mirror of
https://github.com/ICKelin/gtun.git
synced 2025-09-26 19:11:15 +08:00
feat: remove agent
This commit is contained in:
@@ -1,6 +1,26 @@
|
||||
route_file: "/opt/apps/gtun/etc/route.json"
|
||||
proxy_file: "/opt/apps/gtun/etc/proxy.yaml"
|
||||
|
||||
accelerator:
|
||||
HK:
|
||||
routes:
|
||||
- scheme: "kcp"
|
||||
server: "gtun.alihk.byc.com:3002",
|
||||
trace: "gtun.alihk.byc.com:3003",
|
||||
- scheme: "mux"
|
||||
server: "gtun.alihk.byc.com:3002",
|
||||
trace: "gtun.alihk.byc.com:3003",
|
||||
proxy:
|
||||
tproxy_tcp: |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"listen_addr": ":8524"
|
||||
}
|
||||
tproxy_udp: |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"session_timeout": 30,
|
||||
"listen_addr": ":8524"
|
||||
}
|
||||
log:
|
||||
days: 5
|
||||
level: debug
|
||||
|
@@ -1,14 +0,0 @@
|
||||
"HK":
|
||||
tproxy_tcp: |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"listen_addr": ":8524"
|
||||
}
|
||||
tproxy_udp: |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"session_timeout": 30,
|
||||
"listen_addr": ":8524"
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"gopkg.in/yaml.v3"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
GeoConfig GeoConfig `yaml:"Geo"`
|
||||
Fetcher map[string]json.RawMessage `yaml:"fetcher"`
|
||||
GtunConfig *GtunConfig `yaml:"gtun"`
|
||||
Log Log `yaml:"log"`
|
||||
}
|
||||
|
||||
type GeoConfig struct {
|
||||
GeoIPFile string `yaml:"geo_ip_file"`
|
||||
GeoDomainFile string `yaml:"geo_domain_file"`
|
||||
}
|
||||
|
||||
type GtunConfig struct {
|
||||
FetcherName string `yaml:"fetcher_name"`
|
||||
RouteFile string `yaml:"route_file"`
|
||||
ProxyFile string `yaml:"proxy_file"`
|
||||
RestartCmd []string `yaml:"restart_cmd"`
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
Days int64 `yaml:"days"`
|
||||
Level string `yaml:"level"`
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
|
||||
func ParseConfig(path string) (*Config, error) {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ParseBuffer(content)
|
||||
}
|
||||
|
||||
func ParseBuffer(content []byte) (*Config, error) {
|
||||
conf := Config{}
|
||||
err := yaml.Unmarshal(content, &conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &conf, err
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
log:
|
||||
days: 5
|
||||
level: Debug
|
||||
path: gtun.log
|
||||
|
||||
restart_cmd: ["systemctl", "restart", "gtun.service"]
|
||||
route_file: "/opt/apps/gtun/route.json"
|
||||
proxy_file: "/opt/apps/gtun/proxy.yaml"
|
@@ -1,187 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/src/agent/fetcher"
|
||||
"github.com/beyond-net/golib/logs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"text/template"
|
||||
"time"
|
||||
"v2ray.com/core/app/router"
|
||||
)
|
||||
|
||||
type routeItem struct {
|
||||
ServerAddr string `json:"server_addr"`
|
||||
TraceAddr string `json:"trace_addr"`
|
||||
AuthKey string `json:"auth_key"`
|
||||
Scheme string `json:"scheme"`
|
||||
Rate int `json:"rate"`
|
||||
}
|
||||
|
||||
type proxyObj struct {
|
||||
Region string
|
||||
ListenPort int
|
||||
}
|
||||
|
||||
var proxyTemplate = `
|
||||
"{{.Region}}":
|
||||
tproxy_tcp: |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"listen_addr": ":{{.ListenPort}}"
|
||||
}
|
||||
tproxy_udp: |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"session_timeout": 30,
|
||||
"listen_addr": ":{{.ListenPort}}"
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
type Daemon struct {
|
||||
siteList []router.GeoSite
|
||||
ipList []router.GeoIP
|
||||
gtunConfig *GtunConfig
|
||||
tagManager *TagManager
|
||||
}
|
||||
|
||||
func NewDaemon(cfg *GtunConfig, tagManager *TagManager) *Daemon {
|
||||
return &Daemon{gtunConfig: cfg, tagManager: tagManager}
|
||||
}
|
||||
|
||||
func (daemon *Daemon) WatchGtun() {
|
||||
f := fetcher.GetFetcher(daemon.gtunConfig.FetcherName)
|
||||
if f == nil {
|
||||
logs.Error("invalid fetcher %s", daemon.gtunConfig.FetcherName)
|
||||
return
|
||||
}
|
||||
|
||||
tick := time.NewTicker(time.Second * 10)
|
||||
defer tick.Stop()
|
||||
for range tick.C {
|
||||
rs, err := f.Fetch()
|
||||
if err != nil {
|
||||
logs.Warn("fetcher[%s] fail: %v", f.Name(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
logs.Debug("fetcher[%s] result: %v", f.Name(), rs)
|
||||
err = daemon.reloadGtun(rs)
|
||||
if err != nil {
|
||||
logs.Warn("reload gtun fail: %v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (daemon *Daemon) reloadGtun(newCfg *fetcher.FetchResult) error {
|
||||
routes, proxyContent, err := daemon.render(newCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// generate ip/domains
|
||||
ips, domains, err := daemon.geoInfo(newCfg.GeoIP, newCfg.GeoSite)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logs.Debug(ips, domains)
|
||||
|
||||
// write routes.json
|
||||
routesBytes, err := json.Marshal(routes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
routeFp, err := os.Open(daemon.gtunConfig.RouteFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer routeFp.Close()
|
||||
_, err = routeFp.Write(routesBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// write proxy.yaml
|
||||
fp, err := os.Open(daemon.gtunConfig.ProxyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
_, err = fp.Write([]byte(proxyContent))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return daemon.restartGtun()
|
||||
}
|
||||
|
||||
func (daemon *Daemon) render(newCfg *fetcher.FetchResult) ([]*routeItem, string, error) {
|
||||
routes := make([]*routeItem, 0)
|
||||
proxyContent := ""
|
||||
basePort := 8154
|
||||
for _, node := range routes {
|
||||
// render route file
|
||||
routes = append(routes, &routeItem{
|
||||
Scheme: node.Scheme,
|
||||
TraceAddr: node.TraceAddr,
|
||||
AuthKey: node.AuthKey,
|
||||
ServerAddr: node.ServerAddr,
|
||||
Rate: node.Rate,
|
||||
})
|
||||
|
||||
// render proxy file
|
||||
tpl := template.New("proxy")
|
||||
tpl, err := tpl.Parse(proxyTemplate)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
br := &bytes.Buffer{}
|
||||
err = tpl.Execute(br, &proxyObj{
|
||||
Region: newCfg.Region,
|
||||
ListenPort: basePort,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
proxyContent += string(br.Bytes())
|
||||
basePort += 1
|
||||
}
|
||||
|
||||
return routes, proxyContent, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) geoInfo(geoIP []string, geoDomain []string) ([]string, []string, error) {
|
||||
ips := make([]string, 0)
|
||||
domains := make([]string, 0)
|
||||
|
||||
for _, region := range geoIP {
|
||||
ips = append(ips, daemon.tagManager.GetTagIPList(region)...)
|
||||
}
|
||||
|
||||
for _, site := range geoDomain {
|
||||
domains = append(domains, daemon.tagManager.GetTagIPList(site)...)
|
||||
}
|
||||
return ips, domains, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) restartGtun() error {
|
||||
command := daemon.gtunConfig.RestartCmd
|
||||
if len(command) <= 0 {
|
||||
return fmt.Errorf("invalid cmd")
|
||||
}
|
||||
_, err := exec.Command(command[0], command[1:]...).CombinedOutput()
|
||||
if err != nil {
|
||||
logs.Warn("%v", err)
|
||||
}
|
||||
return err
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
package fetcher
|
||||
|
||||
type DynamicFetcher struct{}
|
@@ -1,45 +0,0 @@
|
||||
package fetcher
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var registerFetcher = map[string]Fetcher{}
|
||||
|
||||
type Fetcher interface {
|
||||
Name() string
|
||||
Setup(cfg json.RawMessage) error
|
||||
Fetch() (*FetchResult, error)
|
||||
}
|
||||
|
||||
type FetchResult struct {
|
||||
Region string `json:"region"`
|
||||
GeoSite []string `json:"geo_site"`
|
||||
GeoIP []string `json:"geo_ip"`
|
||||
Nodes []Node `json:"nodes"`
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
ServerAddr string `json:"server_addr"`
|
||||
TraceAddr string `json:"trace_addr"`
|
||||
AuthKey string `json:"auth_key"`
|
||||
Scheme string `json:"scheme"`
|
||||
Rate int `json:"rate"`
|
||||
}
|
||||
|
||||
func RegisterFetcher(fetcher Fetcher) {
|
||||
registerFetcher[fetcher.Name()] = fetcher
|
||||
}
|
||||
|
||||
func GetFetcher(name string) Fetcher {
|
||||
return registerFetcher[name]
|
||||
}
|
||||
|
||||
func Setup(name string, cfg json.RawMessage) error {
|
||||
f := registerFetcher[name]
|
||||
if f == nil {
|
||||
return fmt.Errorf("fetcher %s not register", name)
|
||||
}
|
||||
return f.Setup(cfg)
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
package fetcher
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type StaticFetcher struct {
|
||||
cfg StaticFetcherConfig
|
||||
}
|
||||
|
||||
type StaticFetcherConfig struct {
|
||||
Filepath string `json:"file_path"`
|
||||
}
|
||||
|
||||
func (fetcher *StaticFetcher) Name() string {
|
||||
return "static"
|
||||
}
|
||||
|
||||
func (fetcher *StaticFetcher) Setup(cfg json.RawMessage) error {
|
||||
var fetcherConfig = StaticFetcherConfig{}
|
||||
err := json.Unmarshal(cfg, &fetcherConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fetcher.cfg = fetcherConfig
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fetcher *StaticFetcher) Fetch() (*FetchResult, error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterFetcher(&StaticFetcher{})
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/ICKelin/gtun/src/agent/fetcher"
|
||||
)
|
||||
|
||||
var (
|
||||
confPath = ""
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&confPath, "c", "", "config file path")
|
||||
flag.Parse()
|
||||
|
||||
conf, err := ParseConfig(confPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for name, cfg := range conf.Fetcher {
|
||||
err := fetcher.Setup(name, cfg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
tagManager, _ := NewTagManager(conf.GeoConfig.GeoIPFile, conf.GeoConfig.GeoDomainFile)
|
||||
daemon := NewDaemon(conf.GtunConfig, tagManager)
|
||||
daemon.WatchGtun()
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"io/ioutil"
|
||||
"v2ray.com/core/app/router"
|
||||
)
|
||||
|
||||
const (
|
||||
tagAll = "all"
|
||||
)
|
||||
|
||||
type TagManager struct {
|
||||
tagIPlist map[string][]string
|
||||
tagSitelist map[string][]string
|
||||
}
|
||||
|
||||
func NewTagManager(geoIPFile, siteFile string) (*TagManager, error) {
|
||||
t := &TagManager{
|
||||
tagSitelist: make(map[string][]string),
|
||||
tagIPlist: make(map[string][]string),
|
||||
}
|
||||
content, err := ioutil.ReadFile(siteFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
protoList := router.GeoSiteList{}
|
||||
err = proto.Unmarshal(content, &protoList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, list := range protoList.Entry {
|
||||
for _, domain := range list.Domain {
|
||||
t.tagSitelist[list.CountryCode] = append(t.tagSitelist[list.CountryCode], domain.String())
|
||||
}
|
||||
}
|
||||
|
||||
content, err = ioutil.ReadFile(geoIPFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
iplist := router.GeoIPList{}
|
||||
err = proto.Unmarshal(content, &iplist)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, entry := range iplist.Entry {
|
||||
for _, cidr := range entry.Cidr {
|
||||
t.tagIPlist[entry.CountryCode] = append(t.tagIPlist[entry.CountryCode], cidr.String())
|
||||
}
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (tm *TagManager) GetTagIPList(tag string) []string {
|
||||
return tm.tagIPlist[tag]
|
||||
}
|
||||
|
||||
func (tm *TagManager) GetTagSiteList(tag string) []string {
|
||||
return tm.tagSitelist[tag]
|
||||
}
|
@@ -11,19 +11,25 @@ var gConfig *Config
|
||||
var signatureKey = os.Getenv("GTUN_SIGNATURE")
|
||||
|
||||
type Config struct {
|
||||
RouteFile string `yaml:"route_file"`
|
||||
ProxyFile string `yaml:"proxy_file"`
|
||||
Log Log `yaml:"log"`
|
||||
Accelerator map[string]Accelerator `yaml:"accelerator"`
|
||||
Log Log `yaml:"log"`
|
||||
}
|
||||
|
||||
type RouteConfig struct {
|
||||
Region string `yaml:"region" json:"region"`
|
||||
Scheme string `yaml:"scheme" json:"scheme"`
|
||||
Server string `yaml:"server" json:"server"`
|
||||
Trace string `yaml:"trace" json:"trace"`
|
||||
AuthKey string `yaml:"auth_key" json:"auth_key"`
|
||||
}
|
||||
|
||||
type Accelerator struct {
|
||||
Region string `json:"region"`
|
||||
GeoSite []string `json:"geo_site"`
|
||||
GeoIP []string `json:"geo_ip"`
|
||||
Routes []*RouteConfig `json:"routes"`
|
||||
Proxy map[string]json.RawMessage `json:"proxy"`
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
Days int64 `yaml:"days"`
|
||||
Level string `yaml:"level"`
|
||||
@@ -72,23 +78,3 @@ func ParseProxy(proxyFile string) (map[string]map[string]string, error) {
|
||||
}
|
||||
return proxies, nil
|
||||
}
|
||||
|
||||
func ParseRoute(routeFile string) ([]*RouteConfig, error) {
|
||||
content, err := os.ReadFile(routeFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configContent, err := signature.UnSign(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var routeConfig = make([]*RouteConfig, 0)
|
||||
err = json.Unmarshal(configContent, &routeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return routeConfig, nil
|
||||
}
|
||||
|
@@ -20,31 +20,19 @@ func main() {
|
||||
}
|
||||
logs.Init(conf.Log.Path, conf.Log.Level, conf.Log.Days)
|
||||
|
||||
routeConfig, err := config.ParseRoute(conf.RouteFile)
|
||||
if err != nil {
|
||||
fmt.Printf("parse node config fail: %v", err)
|
||||
return
|
||||
}
|
||||
for region, cfg := range conf.Accelerator {
|
||||
err := route.Setup(region, cfg.Routes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
proxyConfig, err := config.ParseProxy(conf.ProxyFile)
|
||||
if err != nil {
|
||||
fmt.Printf("parse proxy config fail: %v", err)
|
||||
return
|
||||
err = proxy.Serve(region, cfg.Proxy)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
route.Run()
|
||||
|
||||
// run route
|
||||
err = route.Setup(routeConfig)
|
||||
if err != nil {
|
||||
fmt.Printf("route setup fail: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// run proxy
|
||||
err = proxy.Serve(proxyConfig)
|
||||
if err != nil {
|
||||
fmt.Printf("proxy setup fail: %v", err)
|
||||
return
|
||||
}
|
||||
// TODO: watch for config file changes
|
||||
select {}
|
||||
}
|
||||
|
@@ -26,26 +26,24 @@ func Register(name string, constructor func() Proxy) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Serve(proxyConfig map[string]map[string]string) error {
|
||||
for region, p := range proxyConfig {
|
||||
logs.Debug("region %s proxy config %s", region, p)
|
||||
err := setup(region, p)
|
||||
if err != nil {
|
||||
fmt.Printf("region[%s] setup proxy fail: %v\n", region, err)
|
||||
return err
|
||||
}
|
||||
func Serve(region string, proxyConfig map[string]json.RawMessage) error {
|
||||
logs.Debug("region %s proxy config %s", region, proxyConfig)
|
||||
err := setup(region, proxyConfig)
|
||||
if err != nil {
|
||||
fmt.Printf("region[%s] setup proxy fail: %v\n", region, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setup(region string, proxyConfigs map[string]string) error {
|
||||
func setup(region string, proxyConfigs map[string]json.RawMessage) error {
|
||||
for name, config := range proxyConfigs {
|
||||
constructor := registerProxy[name]
|
||||
if constructor == nil {
|
||||
return errNotRegister
|
||||
}
|
||||
p := constructor()
|
||||
err := p.Setup(region, []byte(config))
|
||||
err := p.Setup(region, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -113,24 +113,24 @@ func (routeManager *Manager) deleteRoute(region string, item *routeItem) {
|
||||
routeManager.routeTable[region] = conns
|
||||
}
|
||||
|
||||
func Setup(routeConfig []*config.RouteConfig) error {
|
||||
for _, cfg := range routeConfig {
|
||||
conn, err := newConn(cfg.Region, cfg.Scheme, cfg.Server, cfg.AuthKey)
|
||||
func Setup(region string, routes []*config.RouteConfig) error {
|
||||
for _, cfg := range routes {
|
||||
conn, err := newConn(region, cfg.Scheme, cfg.Server, cfg.AuthKey)
|
||||
if err != nil {
|
||||
fmt.Printf("region[%s] connect to %s://%s fail: %v",
|
||||
cfg.Region, cfg.Scheme, cfg.Server, cfg.AuthKey)
|
||||
region, cfg.Scheme, cfg.Server, cfg.AuthKey)
|
||||
return err
|
||||
}
|
||||
|
||||
cm.regionConn[cfg.Region] = append(cm.regionConn[cfg.Region], conn)
|
||||
cm.regionConn[region] = append(cm.regionConn[region], conn)
|
||||
|
||||
t, ok := tm.regionTrace[cfg.Region]
|
||||
t, ok := tm.regionTrace[region]
|
||||
if !ok {
|
||||
logs.Debug("add region[%s] trace", cfg.Region)
|
||||
t = newTrace(cfg.Region)
|
||||
tm.regionTrace[cfg.Region] = t
|
||||
logs.Debug("add region[%s] trace", region)
|
||||
t = newTrace(region)
|
||||
tm.regionTrace[region] = t
|
||||
} else {
|
||||
logs.Debug("region[%s] trace exist", cfg.Region)
|
||||
logs.Debug("region[%s] trace exist", region)
|
||||
}
|
||||
|
||||
t.addTarget(traceTarget{
|
||||
@@ -140,7 +140,10 @@ func Setup(routeConfig []*config.RouteConfig) error {
|
||||
})
|
||||
}
|
||||
|
||||
go tm.startTrace()
|
||||
go cm.startConn()
|
||||
return nil
|
||||
}
|
||||
|
||||
func Run() {
|
||||
go tm.startTrace()
|
||||
go cm.startConn()
|
||||
}
|
||||
|
Reference in New Issue
Block a user