feat: remove agent

This commit is contained in:
ICKelin
2024-04-22 14:42:01 +08:00
parent 1dd60f37da
commit 467cf95eff
14 changed files with 66 additions and 509 deletions

View File

@@ -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

View File

@@ -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"
}

View File

@@ -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
}

View File

@@ -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"

View File

@@ -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
}

View File

@@ -1,3 +0,0 @@
package fetcher
type DynamicFetcher struct{}

View File

@@ -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)
}

View File

@@ -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{})
}

View File

@@ -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()
}

View File

@@ -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]
}

View File

@@ -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
}

View File

@@ -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 {}
}

View File

@@ -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
}

View File

@@ -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()
}