diff --git a/chain/route.go b/chain/route.go index c915a9b..8e1de36 100644 --- a/chain/route.go +++ b/chain/route.go @@ -2,6 +2,8 @@ package chain import ( "context" + "errors" + "fmt" "net" "time" @@ -10,9 +12,86 @@ import ( "github.com/go-gost/core/logger" "github.com/go-gost/core/metrics" "github.com/go-gost/core/selector" + xnet "github.com/go-gost/x/internal/net" + "github.com/go-gost/x/internal/net/dialer" + "github.com/go-gost/x/internal/net/udp" xmetrics "github.com/go-gost/x/metrics" ) +var ( + ErrEmptyRoute = errors.New("empty route") +) + +var ( + DefaultRoute chain.Route = &defaultRoute{} +) + +// defaultRoute is a Route without nodes. +type defaultRoute struct{} + +func (*defaultRoute) Dial(ctx context.Context, network, address string, opts ...chain.DialOption) (net.Conn, error) { + var options chain.DialOptions + for _, opt := range opts { + opt(&options) + } + + netd := dialer.Dialer{ + Interface: options.Interface, + Netns: options.Netns, + Logger: options.Logger, + } + if options.SockOpts != nil { + netd.Mark = options.SockOpts.Mark + } + + return netd.Dial(ctx, network, address) +} + +func (*defaultRoute) Bind(ctx context.Context, network, address string, opts ...chain.BindOption) (net.Listener, error) { + var options chain.BindOptions + for _, opt := range opts { + opt(&options) + } + + switch network { + case "tcp", "tcp4", "tcp6": + addr, err := net.ResolveTCPAddr(network, address) + if err != nil { + return nil, err + } + return net.ListenTCP(network, addr) + case "udp", "udp4", "udp6": + addr, err := net.ResolveUDPAddr(network, address) + if err != nil { + return nil, err + } + conn, err := net.ListenUDP(network, addr) + if err != nil { + return nil, err + } + logger := logger.Default().WithFields(map[string]any{ + "network": network, + "address": address, + }) + ln := udp.NewListener(conn, &udp.ListenConfig{ + Backlog: options.Backlog, + ReadQueueSize: options.UDPDataQueueSize, + ReadBufferSize: options.UDPDataBufferSize, + TTL: options.UDPConnTTL, + KeepAlive: true, + Logger: logger, + }) + return ln, err + default: + err := fmt.Errorf("network %s unsupported", network) + return nil, err + } +} + +func (r *defaultRoute) Nodes() []*chain.Node { + return nil +} + type RouteOptions struct { Chain chain.Chainer } @@ -25,12 +104,12 @@ func ChainRouteOption(c chain.Chainer) RouteOption { } } -type route struct { +type chainRoute struct { nodes []*chain.Node options RouteOptions } -func NewRoute(opts ...RouteOption) *route { +func NewRoute(opts ...RouteOption) *chainRoute { var options RouteOptions for _, opt := range opts { if opt != nil { @@ -38,18 +117,18 @@ func NewRoute(opts ...RouteOption) *route { } } - return &route{ + return &chainRoute{ options: options, } } -func (r *route) addNode(nodes ...*chain.Node) { +func (r *chainRoute) addNode(nodes ...*chain.Node) { r.nodes = append(r.nodes, nodes...) } -func (r *route) Dial(ctx context.Context, network, address string, opts ...chain.DialOption) (net.Conn, error) { +func (r *chainRoute) Dial(ctx context.Context, network, address string, opts ...chain.DialOption) (net.Conn, error) { if len(r.Nodes()) == 0 { - return chain.DefaultRoute.Dial(ctx, network, address, opts...) + return DefaultRoute.Dial(ctx, network, address, opts...) } var options chain.DialOptions @@ -73,9 +152,9 @@ func (r *route) Dial(ctx context.Context, network, address string, opts ...chain return cc, nil } -func (r *route) Bind(ctx context.Context, network, address string, opts ...chain.BindOption) (net.Listener, error) { +func (r *chainRoute) Bind(ctx context.Context, network, address string, opts ...chain.BindOption) (net.Listener, error) { if len(r.Nodes()) == 0 { - return chain.DefaultRoute.Bind(ctx, network, address, opts...) + return DefaultRoute.Bind(ctx, network, address, opts...) } var options chain.BindOptions @@ -106,7 +185,7 @@ func (r *route) Bind(ctx context.Context, network, address string, opts ...chain return ln, nil } -func (r *route) connect(ctx context.Context, logger logger.Logger) (conn net.Conn, err error) { +func (r *chainRoute) connect(ctx context.Context, logger logger.Logger) (conn net.Conn, err error) { network := "ip" node := r.nodes[0] @@ -138,7 +217,7 @@ func (r *route) connect(ctx context.Context, logger logger.Logger) (conn net.Con } }() - addr, err := chain.Resolve(ctx, network, node.Addr, node.Options().Resolver, node.Options().HostMapper, logger) + addr, err := xnet.Resolve(ctx, network, node.Addr, node.Options().Resolver, node.Options().HostMapper, logger) marker := node.Marker() if err != nil { if marker != nil { @@ -182,7 +261,7 @@ func (r *route) connect(ctx context.Context, logger logger.Logger) (conn net.Con preNode := node for _, node := range r.nodes[1:] { marker := node.Marker() - addr, err = chain.Resolve(ctx, network, node.Addr, node.Options().Resolver, node.Options().HostMapper, logger) + addr, err = xnet.Resolve(ctx, network, node.Addr, node.Options().Resolver, node.Options().HostMapper, logger) if err != nil { cn.Close() if marker != nil { @@ -218,14 +297,14 @@ func (r *route) connect(ctx context.Context, logger logger.Logger) (conn net.Con return } -func (r *route) getNode(index int) *chain.Node { +func (r *chainRoute) getNode(index int) *chain.Node { if r == nil || len(r.Nodes()) == 0 || index < 0 || index >= len(r.Nodes()) { return nil } return r.nodes[index] } -func (r *route) Nodes() []*chain.Node { +func (r *chainRoute) Nodes() []*chain.Node { if r != nil { return r.nodes } diff --git a/chain/router.go b/chain/router.go new file mode 100644 index 0000000..1c166f3 --- /dev/null +++ b/chain/router.go @@ -0,0 +1,205 @@ +package chain + +import ( + "bytes" + "context" + "fmt" + "net" + "time" + + "github.com/go-gost/core/chain" + "github.com/go-gost/core/logger" + "github.com/go-gost/core/recorder" + xnet "github.com/go-gost/x/internal/net" +) + +type Router struct { + options chain.RouterOptions +} + +func NewRouter(opts ...chain.RouterOption) *Router { + r := &Router{} + for _, opt := range opts { + if opt != nil { + opt(&r.options) + } + } + if r.options.Timeout == 0 { + r.options.Timeout = 15 * time.Second + } + + if r.options.Logger == nil { + r.options.Logger = logger.Default().WithFields(map[string]any{"kind": "router"}) + } + return r +} + +func (r *Router) Options() *chain.RouterOptions { + if r == nil { + return nil + } + return &r.options +} + +func (r *Router) Dial(ctx context.Context, network, address string) (conn net.Conn, err error) { + if r.options.Timeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, r.options.Timeout) + defer cancel() + } + + host := address + if h, _, _ := net.SplitHostPort(address); h != "" { + host = h + } + r.record(ctx, recorder.RecorderServiceRouterDialAddress, []byte(host)) + + conn, err = r.dial(ctx, network, address) + if err != nil { + r.record(ctx, recorder.RecorderServiceRouterDialAddressError, []byte(host)) + return + } + + if network == "udp" || network == "udp4" || network == "udp6" { + if _, ok := conn.(net.PacketConn); !ok { + return &packetConn{conn}, nil + } + } + return +} + +func (r *Router) record(ctx context.Context, name string, data []byte) error { + if len(data) == 0 { + return nil + } + + for _, rec := range r.options.Recorders { + if rec.Record == name { + err := rec.Recorder.Record(ctx, data) + if err != nil { + r.options.Logger.Errorf("record %s: %v", name, err) + } + return err + } + } + return nil +} + +func (r *Router) dial(ctx context.Context, network, address string) (conn net.Conn, err error) { + count := r.options.Retries + 1 + if count <= 0 { + count = 1 + } + r.options.Logger.Debugf("dial %s/%s", address, network) + + for i := 0; i < count; i++ { + var ipAddr string + ipAddr, err = xnet.Resolve(ctx, "ip", address, r.options.Resolver, r.options.HostMapper, r.options.Logger) + if err != nil { + r.options.Logger.Error(err) + break + } + + var route chain.Route + if r.options.Chain != nil { + route = r.options.Chain.Route(ctx, network, ipAddr, chain.WithHostRouteOption(address)) + } + + if r.options.Logger.IsLevelEnabled(logger.DebugLevel) { + buf := bytes.Buffer{} + for _, node := range routePath(route) { + fmt.Fprintf(&buf, "%s@%s > ", node.Name, node.Addr) + } + fmt.Fprintf(&buf, "%s", ipAddr) + r.options.Logger.Debugf("route(retry=%d) %s", i, buf.String()) + } + + if route == nil { + route = DefaultRoute + } + conn, err = route.Dial(ctx, network, ipAddr, + chain.InterfaceDialOption(r.options.IfceName), + chain.NetnsDialOption(r.options.Netns), + chain.SockOptsDialOption(r.options.SockOpts), + chain.LoggerDialOption(r.options.Logger), + ) + if err == nil { + break + } + r.options.Logger.Errorf("route(retry=%d) %s", i, err) + } + + return +} + +func (r *Router) Bind(ctx context.Context, network, address string, opts ...chain.BindOption) (ln net.Listener, err error) { + if r.options.Timeout > 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, r.options.Timeout) + defer cancel() + } + + count := r.options.Retries + 1 + if count <= 0 { + count = 1 + } + r.options.Logger.Debugf("bind on %s/%s", address, network) + + for i := 0; i < count; i++ { + var route chain.Route + if r.options.Chain != nil { + route = r.options.Chain.Route(ctx, network, address) + if route == nil || len(route.Nodes()) == 0 { + err = ErrEmptyRoute + return + } + } + + if r.options.Logger.IsLevelEnabled(logger.DebugLevel) { + buf := bytes.Buffer{} + for _, node := range routePath(route) { + fmt.Fprintf(&buf, "%s@%s > ", node.Name, node.Addr) + } + fmt.Fprintf(&buf, "%s", address) + r.options.Logger.Debugf("route(retry=%d) %s", i, buf.String()) + } + + if route == nil { + route = DefaultRoute + } + ln, err = route.Bind(ctx, network, address, opts...) + if err == nil { + break + } + r.options.Logger.Errorf("route(retry=%d) %s", i, err) + } + + return +} + +func routePath(route chain.Route) (path []*chain.Node) { + if route == nil { + return + } + for _, node := range route.Nodes() { + if tr := node.Options().Transport; tr != nil { + path = append(path, routePath(tr.Options().Route)...) + } + path = append(path, node) + } + return +} + +type packetConn struct { + net.Conn +} + +func (c *packetConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { + n, err = c.Read(b) + addr = c.Conn.RemoteAddr() + return +} + +func (c *packetConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { + return c.Write(b) +} diff --git a/chain/transport.go b/chain/transport.go new file mode 100644 index 0000000..ed999f4 --- /dev/null +++ b/chain/transport.go @@ -0,0 +1,106 @@ +package chain + +import ( + "context" + "net" + + "github.com/go-gost/core/chain" + "github.com/go-gost/core/connector" + "github.com/go-gost/core/dialer" + net_dialer "github.com/go-gost/x/internal/net/dialer" +) + +type Transport struct { + dialer dialer.Dialer + connector connector.Connector + options chain.TransportOptions +} + +func NewTransport(d dialer.Dialer, c connector.Connector, opts ...chain.TransportOption) *Transport { + tr := &Transport{ + dialer: d, + connector: c, + } + for _, opt := range opts { + if opt != nil { + opt(&tr.options) + } + } + + return tr +} + +func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) { + netd := &net_dialer.Dialer{ + Interface: tr.options.IfceName, + Netns: tr.options.Netns, + } + if tr.options.SockOpts != nil { + netd.Mark = tr.options.SockOpts.Mark + } + if tr.options.Route != nil && len(tr.options.Route.Nodes()) > 0 { + netd.DialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) { + return tr.options.Route.Dial(ctx, network, addr) + } + } + opts := []dialer.DialOption{ + dialer.HostDialOption(tr.options.Addr), + dialer.NetDialerDialOption(netd), + } + return tr.dialer.Dial(ctx, addr, opts...) +} + +func (tr *Transport) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) { + var err error + if hs, ok := tr.dialer.(dialer.Handshaker); ok { + conn, err = hs.Handshake(ctx, conn, + dialer.AddrHandshakeOption(tr.options.Addr)) + if err != nil { + return nil, err + } + } + if hs, ok := tr.connector.(connector.Handshaker); ok { + return hs.Handshake(ctx, conn) + } + return conn, nil +} + +func (tr *Transport) Connect(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) { + netd := &net_dialer.Dialer{ + Interface: tr.options.IfceName, + Netns: tr.options.Netns, + } + if tr.options.SockOpts != nil { + netd.Mark = tr.options.SockOpts.Mark + } + return tr.connector.Connect(ctx, conn, network, address, + connector.DialerConnectOption(netd), + ) +} + +func (tr *Transport) Bind(ctx context.Context, conn net.Conn, network, address string, opts ...connector.BindOption) (net.Listener, error) { + if binder, ok := tr.connector.(connector.Binder); ok { + return binder.Bind(ctx, conn, network, address, opts...) + } + return nil, connector.ErrBindUnsupported +} + +func (tr *Transport) Multiplex() bool { + if mux, ok := tr.dialer.(dialer.Multiplexer); ok { + return mux.Multiplex() + } + return false +} + +func (tr *Transport) Options() *chain.TransportOptions { + if tr != nil { + return &tr.options + } + return nil +} + +func (tr *Transport) Copy() chain.Transporter { + tr2 := &Transport{} + *tr2 = *tr + return tr +} diff --git a/config/cmd/cmd.go b/config/cmd/cmd.go new file mode 100644 index 0000000..1ae66be --- /dev/null +++ b/config/cmd/cmd.go @@ -0,0 +1,677 @@ +package cmd + +import ( + "encoding/base64" + "errors" + "fmt" + "net/url" + "os" + "strconv" + "strings" + "time" + + mdutil "github.com/go-gost/core/metadata/util" + "github.com/go-gost/x/config" + xnet "github.com/go-gost/x/internal/net" + "github.com/go-gost/x/limiter/conn" + "github.com/go-gost/x/limiter/traffic" + mdx "github.com/go-gost/x/metadata" + "github.com/go-gost/x/registry" +) + +var ( + ErrInvalidCmd = errors.New("invalid cmd") + ErrInvalidNode = errors.New("invalid node") +) + +func BuildConfigFromCmd(serviceList, nodeList []string) (*config.Config, error) { + namePrefix := "" + cfg := &config.Config{} + + var chain *config.ChainConfig + if len(nodeList) > 0 { + chain = &config.ChainConfig{ + Name: fmt.Sprintf("%schain-0", namePrefix), + } + cfg.Chains = append(cfg.Chains, chain) + } + + for i, node := range nodeList { + url, err := Norm(node) + if err != nil { + return nil, err + } + + nodeConfig, err := buildNodeConfig(url) + if err != nil { + return nil, err + } + nodeConfig.Name = fmt.Sprintf("%snode-0", namePrefix) + + var nodes []*config.NodeConfig + for _, host := range strings.Split(nodeConfig.Addr, ",") { + if host == "" { + continue + } + nodeCfg := &config.NodeConfig{} + *nodeCfg = *nodeConfig + nodeCfg.Name = fmt.Sprintf("%snode-%d", namePrefix, len(nodes)) + nodeCfg.Addr = host + nodes = append(nodes, nodeCfg) + } + + m := map[string]any{} + for k, v := range url.Query() { + if len(v) > 0 { + m[k] = v[0] + } + } + md := mdx.NewMetadata(m) + + hopConfig := &config.HopConfig{ + Name: fmt.Sprintf("%shop-%d", namePrefix, i), + Selector: parseSelector(m), + Nodes: nodes, + Metadata: m, + } + + if v := mdutil.GetString(md, "bypass"); v != "" { + bypassCfg := &config.BypassConfig{ + Name: fmt.Sprintf("%sbypass-%d", namePrefix, len(cfg.Bypasses)), + } + if v[0] == '~' { + bypassCfg.Whitelist = true + v = v[1:] + } + for _, s := range strings.Split(v, ",") { + if s == "" { + continue + } + bypassCfg.Matchers = append(bypassCfg.Matchers, s) + } + hopConfig.Bypass = bypassCfg.Name + cfg.Bypasses = append(cfg.Bypasses, bypassCfg) + delete(m, "bypass") + } + if v := mdutil.GetString(md, "resolver"); v != "" { + resolverCfg := &config.ResolverConfig{ + Name: fmt.Sprintf("%sresolver-%d", namePrefix, len(cfg.Resolvers)), + } + for _, rs := range strings.Split(v, ",") { + if rs == "" { + continue + } + resolverCfg.Nameservers = append( + resolverCfg.Nameservers, + &config.NameserverConfig{ + Addr: rs, + }, + ) + } + hopConfig.Resolver = resolverCfg.Name + cfg.Resolvers = append(cfg.Resolvers, resolverCfg) + delete(m, "resolver") + } + if v := mdutil.GetString(md, "hosts"); v != "" { + hostsCfg := &config.HostsConfig{ + Name: fmt.Sprintf("%shosts-%d", namePrefix, len(cfg.Hosts)), + } + for _, s := range strings.Split(v, ",") { + ss := strings.SplitN(s, ":", 2) + if len(ss) != 2 { + continue + } + hostsCfg.Mappings = append( + hostsCfg.Mappings, + &config.HostMappingConfig{ + Hostname: ss[0], + IP: ss[1], + }, + ) + } + hopConfig.Hosts = hostsCfg.Name + cfg.Hosts = append(cfg.Hosts, hostsCfg) + delete(m, "hosts") + } + + if v := mdutil.GetString(md, "interface"); v != "" { + hopConfig.Interface = v + delete(m, "interface") + } + if v := mdutil.GetInt(md, "so_mark"); v > 0 { + hopConfig.SockOpts = &config.SockOptsConfig{ + Mark: v, + } + delete(m, "so_mark") + } + + chain.Hops = append(chain.Hops, hopConfig) + } + + var services []*config.ServiceConfig + for _, svc := range serviceList { + svc = strings.TrimSpace(svc) + if svc == "" { + continue + } + + if svc[0] == ':' || !strings.Contains(svc, "://") { + svc = "auto://" + svc + } + + host, svc := cutHost(svc) + + url, err := Norm(svc) + if err != nil { + return nil, err + } + url.Host = host + + svcs, err := buildServiceConfig(url) + if err != nil { + return nil, err + } + services = append(services, svcs...) + } + + for i, service := range services { + service.Name = fmt.Sprintf("%sservice-%d", namePrefix, i) + if chain != nil { + if service.Listener.Type == "rtcp" || service.Listener.Type == "rudp" { + service.Listener.Chain = chain.Name + } else { + service.Handler.Chain = chain.Name + } + } + cfg.Services = append(cfg.Services, service) + + mh := service.Handler.Metadata + md := mdx.NewMetadata(mh) + if v := mdutil.GetInt(md, "retries"); v > 0 { + service.Handler.Retries = v + delete(mh, "retries") + } + if v := mdutil.GetString(md, "admission"); v != "" { + admCfg := &config.AdmissionConfig{ + Name: fmt.Sprintf("%sadmission-%d", namePrefix, len(cfg.Admissions)), + } + if v[0] == '~' { + admCfg.Whitelist = true + v = v[1:] + } + for _, s := range strings.Split(v, ",") { + if s == "" { + continue + } + admCfg.Matchers = append(admCfg.Matchers, s) + } + service.Admission = admCfg.Name + cfg.Admissions = append(cfg.Admissions, admCfg) + delete(mh, "admission") + } + if v := mdutil.GetString(md, "bypass"); v != "" { + bypassCfg := &config.BypassConfig{ + Name: fmt.Sprintf("%sbypass-%d", namePrefix, len(cfg.Bypasses)), + } + if v[0] == '~' { + bypassCfg.Whitelist = true + v = v[1:] + } + for _, s := range strings.Split(v, ",") { + if s == "" { + continue + } + bypassCfg.Matchers = append(bypassCfg.Matchers, s) + } + service.Bypass = bypassCfg.Name + cfg.Bypasses = append(cfg.Bypasses, bypassCfg) + delete(mh, "bypass") + } + if v := mdutil.GetString(md, "resolver"); v != "" { + resolverCfg := &config.ResolverConfig{ + Name: fmt.Sprintf("%sresolver-%d", namePrefix, len(cfg.Resolvers)), + } + for _, rs := range strings.Split(v, ",") { + if rs == "" { + continue + } + resolverCfg.Nameservers = append( + resolverCfg.Nameservers, + &config.NameserverConfig{ + Addr: rs, + Prefer: mdutil.GetString(md, "prefer"), + }, + ) + } + service.Resolver = resolverCfg.Name + cfg.Resolvers = append(cfg.Resolvers, resolverCfg) + delete(mh, "resolver") + } + if v := mdutil.GetString(md, "hosts"); v != "" { + hostsCfg := &config.HostsConfig{ + Name: fmt.Sprintf("%shosts-%d", namePrefix, len(cfg.Hosts)), + } + for _, s := range strings.Split(v, ",") { + ss := strings.SplitN(s, ":", 2) + if len(ss) != 2 { + continue + } + hostsCfg.Mappings = append( + hostsCfg.Mappings, + &config.HostMappingConfig{ + Hostname: ss[0], + IP: ss[1], + }, + ) + } + service.Hosts = hostsCfg.Name + cfg.Hosts = append(cfg.Hosts, hostsCfg) + delete(mh, "hosts") + } + + in := mdutil.GetString(md, "limiter.in") + out := mdutil.GetString(md, "limiter.out") + cin := mdutil.GetString(md, "limiter.conn.in") + cout := mdutil.GetString(md, "limiter.conn.out") + if in != "" || cin != "" || out != "" || cout != "" { + limiter := &config.LimiterConfig{ + Name: fmt.Sprintf("%slimiter-%d", namePrefix, len(cfg.Limiters)), + } + if in != "" || out != "" { + limiter.Limits = append(limiter.Limits, + fmt.Sprintf("%s %s %s", traffic.GlobalLimitKey, in, out)) + } + if cin != "" || cout != "" { + limiter.Limits = append(limiter.Limits, + fmt.Sprintf("%s %s %s", traffic.ConnLimitKey, cin, cout)) + } + service.Limiter = limiter.Name + cfg.Limiters = append(cfg.Limiters, limiter) + delete(mh, "limiter.in") + delete(mh, "limiter.out") + delete(mh, "limiter.conn.in") + delete(mh, "limiter.conn.out") + } + + if climit := mdutil.GetInt(md, "climiter"); climit > 0 { + limiter := &config.LimiterConfig{ + Name: fmt.Sprintf("%sclimiter-%d", namePrefix, len(cfg.CLimiters)), + Limits: []string{fmt.Sprintf("%s %d", conn.GlobalLimitKey, climit)}, + } + service.CLimiter = limiter.Name + cfg.CLimiters = append(cfg.CLimiters, limiter) + delete(mh, "climiter") + } + + if rlimit := mdutil.GetFloat(md, "rlimiter"); rlimit > 0 { + limiter := &config.LimiterConfig{ + Name: fmt.Sprintf("%srlimiter-%d", namePrefix, len(cfg.RLimiters)), + Limits: []string{fmt.Sprintf("%s %s", conn.GlobalLimitKey, strconv.FormatFloat(rlimit, 'f', -1, 64))}, + } + service.RLimiter = limiter.Name + cfg.RLimiters = append(cfg.RLimiters, limiter) + delete(mh, "rlimiter") + } + } + + return cfg, nil +} + +func cutHost(s string) (host, remain string) { + if s == "" { + return + } + + n := strings.IndexByte(s, ':') + start := n + 3 + end := strings.IndexAny(s[start:], "/?") + if end < 0 { + end = len(s) + } else { + end += start + } + host = s[start:end] + remain = s[:start] + s[end:] + + return +} + +func buildServiceConfig(url *url.URL) ([]*config.ServiceConfig, error) { + namePrefix := "" + if v := os.Getenv("_GOST_ID"); v != "" { + namePrefix = fmt.Sprintf("go-%s@", v) + } + + var handler, listener string + schemes := strings.Split(url.Scheme, "+") + if len(schemes) == 1 { + handler = schemes[0] + listener = schemes[0] + } + if len(schemes) == 2 { + handler = schemes[0] + listener = schemes[1] + } + + addrs := xnet.AddrPortRange(url.Host).Addrs() + if len(addrs) == 0 { + addrs = append(addrs, url.Host) + } + + var services []*config.ServiceConfig + for _, addr := range addrs { + services = append(services, &config.ServiceConfig{ + Addr: addr, + }) + } + + if h := registry.HandlerRegistry().Get(handler); h == nil { + handler = "auto" + } + if ln := registry.ListenerRegistry().Get(listener); ln == nil { + listener = "tcp" + if handler == "ssu" { + listener = "udp" + } + } + + var nodes []*config.ForwardNodeConfig + // forward mode + if remotes := strings.Trim(url.EscapedPath(), "/"); remotes != "" { + i := 0 + for _, addr := range strings.Split(remotes, ",") { + addrs := xnet.AddrPortRange(addr).Addrs() + if len(addrs) == 0 { + addrs = append(addrs, addr) + } + for _, adr := range addrs { + nodes = append(nodes, &config.ForwardNodeConfig{ + Name: fmt.Sprintf("%starget-%d", namePrefix, i), + Addr: adr, + }) + i++ + } + } + + if handler != "relay" { + if listener == "tcp" || listener == "udp" || + listener == "rtcp" || listener == "rudp" || + listener == "tun" || listener == "tap" || + listener == "dns" || listener == "unix" || + listener == "serial" { + handler = listener + } else { + handler = "forward" + } + } + } + + if len(nodes) > 0 { + if len(services) == 1 { + services[0].Forwarder = &config.ForwarderConfig{ + Nodes: nodes, + } + } else { + for i, svc := range services { + if len(nodes) == 1 { + svc.Forwarder = &config.ForwarderConfig{ + Nodes: nodes, + } + } else { + if i < len(nodes) { + svc.Forwarder = &config.ForwarderConfig{ + Nodes: []*config.ForwardNodeConfig{nodes[i]}, + } + } + } + } + } + } + + var auth *config.AuthConfig + if url.User != nil { + auth = &config.AuthConfig{ + Username: url.User.Username(), + } + auth.Password, _ = url.User.Password() + } + + m := map[string]any{} + for k, v := range url.Query() { + if len(v) > 0 { + m[k] = v[0] + } + } + md := mdx.NewMetadata(m) + + if sa := mdutil.GetString(md, "auth"); sa != "" { + au, err := parseAuthFromCmd(sa) + if err != nil { + return nil, err + } + auth = au + } + delete(m, "auth") + + tlsConfig := &config.TLSConfig{ + CertFile: mdutil.GetString(md, "tls.certFile", "certFile", "cert"), + KeyFile: mdutil.GetString(md, "tls.keyFile", "keyFile", "key"), + CAFile: mdutil.GetString(md, "tls.caFile", "caFile", "ca"), + } + + delete(m, "tls.certFile") + delete(m, "certFile") + delete(m, "cert") + delete(m, "tls.keyFile") + delete(m, "keyFile") + delete(m, "key") + delete(m, "tls.caFile") + delete(m, "caFile") + delete(m, "ca") + + if tlsConfig.CertFile == "" { + tlsConfig = nil + } + + if v := mdutil.GetString(md, "dns"); v != "" { + md.Set("dns", strings.Split(v, ",")) + } + + selector := parseSelector(m) + handlerCfg := &config.HandlerConfig{ + Type: handler, + Auth: auth, + Metadata: m, + } + listenerCfg := &config.ListenerConfig{ + Type: listener, + TLS: tlsConfig, + Metadata: m, + } + if listenerCfg.Type == "ssh" || listenerCfg.Type == "sshd" { + handlerCfg.Auth = nil + listenerCfg.Auth = auth + } + + for _, svc := range services { + if svc.Forwarder != nil { + svc.Forwarder.Selector = selector + } + svc.Handler = handlerCfg + svc.Listener = listenerCfg + svc.Metadata = m + } + + return services, nil +} + +func buildNodeConfig(url *url.URL) (*config.NodeConfig, error) { + var connector, dialer string + schemes := strings.Split(url.Scheme, "+") + if len(schemes) == 1 { + connector = schemes[0] + dialer = schemes[0] + } + if len(schemes) == 2 { + connector = schemes[0] + dialer = schemes[1] + } + + m := map[string]any{} + for k, v := range url.Query() { + if len(v) > 0 { + m[k] = v[0] + } + } + md := mdx.NewMetadata(m) + + node := &config.NodeConfig{ + Addr: url.Host, + Metadata: m, + } + + if c := registry.ConnectorRegistry().Get(connector); c == nil { + connector = "http" + } + if d := registry.DialerRegistry().Get(dialer); d == nil { + dialer = "tcp" + if connector == "ssu" { + dialer = "udp" + } + } + + var auth *config.AuthConfig + if url.User != nil { + auth = &config.AuthConfig{ + Username: url.User.Username(), + } + auth.Password, _ = url.User.Password() + } + + if sauth := mdutil.GetString(md, "auth"); sauth != "" && auth == nil { + au, err := parseAuthFromCmd(sauth) + if err != nil { + return nil, err + } + auth = au + } + delete(m, "auth") + + tlsConfig := &config.TLSConfig{ + CertFile: mdutil.GetString(md, "tls.certFile", "certFile", "cert"), + KeyFile: mdutil.GetString(md, "tls.keyFile", "keyFile", "key"), + CAFile: mdutil.GetString(md, "tls.caFile", "caFile", "ca"), + Secure: mdutil.GetBool(md, "tls.secure", "secure"), + ServerName: mdutil.GetString(md, "tls.servername", "servername"), + } + if tlsConfig.ServerName == "" { + tlsConfig.ServerName = url.Hostname() + } + + delete(m, "tls.certFile") + delete(m, "certFile") + delete(m, "cert") + delete(m, "tls.keyFile") + delete(m, "keyFile") + delete(m, "key") + delete(m, "tls.caFile") + delete(m, "caFile") + delete(m, "ca") + delete(m, "tls.secure") + delete(m, "secure") + delete(m, "tls.servername") + delete(m, "serverName") + + if !tlsConfig.Secure && tlsConfig.CertFile == "" && tlsConfig.CAFile == "" && tlsConfig.ServerName == "" { + tlsConfig = nil + } + + node.Connector = &config.ConnectorConfig{ + Type: connector, + Auth: auth, + Metadata: m, + } + node.Dialer = &config.DialerConfig{ + Type: dialer, + TLS: tlsConfig, + Metadata: m, + } + + if node.Dialer.Type == "ssh" || node.Dialer.Type == "sshd" { + node.Connector.Auth = nil + node.Dialer.Auth = auth + } + + return node, nil +} + +func Norm(s string) (*url.URL, error) { + s = strings.TrimSpace(s) + if s == "" { + return nil, ErrInvalidCmd + } + + if s[0] == ':' || !strings.Contains(s, "://") { + s = "auto://" + s + } + + url, err := url.Parse(s) + if err != nil { + return nil, err + } + if url.Scheme == "https" { + url.Scheme = "http+tls" + } + + return url, nil +} + +func parseAuthFromCmd(sa string) (*config.AuthConfig, error) { + v, err := base64.StdEncoding.DecodeString(sa) + if err != nil { + return nil, err + } + cs := string(v) + n := strings.IndexByte(cs, ':') + if n < 0 { + return &config.AuthConfig{ + Username: cs, + }, nil + } + + return &config.AuthConfig{ + Username: cs[:n], + Password: cs[n+1:], + }, nil +} + +func parseSelector(m map[string]any) *config.SelectorConfig { + md := mdx.NewMetadata(m) + strategy := mdutil.GetString(md, "strategy") + maxFails := mdutil.GetInt(md, "maxFails", "max_fails") + failTimeout := mdutil.GetDuration(md, "failTimeout", "fail_timeout") + if strategy == "" && maxFails <= 0 && failTimeout <= 0 { + return nil + } + if strategy == "" { + strategy = "round" + } + if maxFails <= 0 { + maxFails = 1 + } + if failTimeout <= 0 { + failTimeout = 30 * time.Second + } + + delete(m, "strategy") + delete(m, "maxFails") + delete(m, "max_fails") + delete(m, "failTimeout") + delete(m, "fail_timeout") + + return &config.SelectorConfig{ + Strategy: strategy, + MaxFails: maxFails, + FailTimeout: failTimeout, + } +} diff --git a/config/parsing/node/parse.go b/config/parsing/node/parse.go index af99d07..41fd58a 100644 --- a/config/parsing/node/parse.go +++ b/config/parsing/node/parse.go @@ -14,6 +14,7 @@ import ( "github.com/go-gost/core/metadata" mdutil "github.com/go-gost/core/metadata/util" xauth "github.com/go-gost/x/auth" + xchain "github.com/go-gost/x/chain" "github.com/go-gost/x/config" "github.com/go-gost/x/config/parsing" auth_parser "github.com/go-gost/x/config/parsing/auth" @@ -139,7 +140,7 @@ func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.No } } - tr := chain.NewTransport(d, cr, + tr := xchain.NewTransport(d, cr, chain.AddrTransportOption(cfg.Addr), chain.InterfaceTransportOption(cfg.Interface), chain.NetnsTransportOption(cfg.Netns), diff --git a/config/parsing/service/parse.go b/config/parsing/service/parse.go index 599b545..79ad47f 100644 --- a/config/parsing/service/parse.go +++ b/config/parsing/service/parse.go @@ -28,7 +28,6 @@ import ( hop_parser "github.com/go-gost/x/config/parsing/hop" logger_parser "github.com/go-gost/x/config/parsing/logger" selector_parser "github.com/go-gost/x/config/parsing/selector" - xnet "github.com/go-gost/x/internal/net" tls_util "github.com/go-gost/x/internal/util/tls" "github.com/go-gost/x/metadata" "github.com/go-gost/x/registry" @@ -151,7 +150,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { listenOpts := []listener.Option{ listener.AddrOption(cfg.Addr), - listener.RouterOption(chain.NewRouter(routerOpts...)), + listener.RouterOption(xchain.NewRouter(routerOpts...)), listener.AutherOption(auther), listener.AuthOption(auth_parser.Info(cfg.Listener.Auth)), listener.TLSConfigOption(tlsConfig), @@ -271,7 +270,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { var h handler.Handler if rf := registry.HandlerRegistry().Get(cfg.Handler.Type); rf != nil { h = rf( - handler.RouterOption(chain.NewRouter(routerOpts...)), + handler.RouterOption(xchain.NewRouter(routerOpts...)), handler.AutherOption(auther), handler.AuthOption(auth_parser.Info(cfg.Handler.Auth)), handler.BypassOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)), @@ -339,50 +338,41 @@ func parseForwarder(cfg *config.ForwarderConfig, log logger.Logger) (hop.Hop, er Selector: cfg.Selector, } for _, node := range cfg.Nodes { - if node != nil { - addrs := xnet.AddrPortRange(node.Addr).Addrs() - if len(addrs) == 0 { - addrs = append(addrs, node.Addr) - } - for i, addr := range addrs { - name := node.Name - if i > 0 { - name = fmt.Sprintf("%s-%d", node.Name, i) - } + if node == nil { + continue + } - filter := node.Filter - if filter == nil { - if node.Protocol != "" || node.Host != "" || node.Path != "" { - filter = &config.NodeFilterConfig{ - Protocol: node.Protocol, - Host: node.Host, - Path: node.Path, - } - } + filter := node.Filter + if filter == nil { + if node.Protocol != "" || node.Host != "" || node.Path != "" { + filter = &config.NodeFilterConfig{ + Protocol: node.Protocol, + Host: node.Host, + Path: node.Path, } - - httpCfg := node.HTTP - if node.Auth != nil { - if httpCfg == nil { - httpCfg = &config.HTTPNodeConfig{} - } - if httpCfg.Auth == nil { - httpCfg.Auth = node.Auth - } - } - hc.Nodes = append(hc.Nodes, &config.NodeConfig{ - Name: name, - Addr: addr, - Network: node.Network, - Bypass: node.Bypass, - Bypasses: node.Bypasses, - Filter: filter, - HTTP: httpCfg, - TLS: node.TLS, - Metadata: node.Metadata, - }) } } + + httpCfg := node.HTTP + if node.Auth != nil { + if httpCfg == nil { + httpCfg = &config.HTTPNodeConfig{} + } + if httpCfg.Auth == nil { + httpCfg.Auth = node.Auth + } + } + hc.Nodes = append(hc.Nodes, &config.NodeConfig{ + Name: node.Name, + Addr: node.Addr, + Network: node.Network, + Bypass: node.Bypass, + Bypasses: node.Bypasses, + Filter: filter, + HTTP: httpCfg, + TLS: node.TLS, + Metadata: node.Metadata, + }) } return hop_parser.ParseHop(&hc, log) } diff --git a/connector/direct/connector.go b/connector/direct/connector.go index e3ffd41..bba2052 100644 --- a/connector/direct/connector.go +++ b/connector/direct/connector.go @@ -39,7 +39,7 @@ func (c *directConnector) Connect(ctx context.Context, _ net.Conn, network, addr opt(&cOpts) } - conn, err := cOpts.NetDialer.Dial(ctx, network, address) + conn, err := cOpts.Dialer.Dial(ctx, network, address) if err != nil { return nil, err } diff --git a/connector/relay/bind.go b/connector/relay/bind.go index 08f279d..09a7513 100644 --- a/connector/relay/bind.go +++ b/connector/relay/bind.go @@ -6,10 +6,10 @@ import ( "net" "strconv" - "github.com/go-gost/core/common/net/udp" "github.com/go-gost/core/connector" "github.com/go-gost/core/logger" "github.com/go-gost/relay" + "github.com/go-gost/x/internal/net/udp" "github.com/go-gost/x/internal/util/mux" relay_util "github.com/go-gost/x/internal/util/relay" ) diff --git a/connector/socks/v5/bind.go b/connector/socks/v5/bind.go index 31f0ea8..b2e6d39 100644 --- a/connector/socks/v5/bind.go +++ b/connector/socks/v5/bind.go @@ -5,10 +5,10 @@ import ( "fmt" "net" - "github.com/go-gost/core/common/net/udp" "github.com/go-gost/core/connector" "github.com/go-gost/core/logger" "github.com/go-gost/gosocks5" + "github.com/go-gost/x/internal/net/udp" "github.com/go-gost/x/internal/util/mux" "github.com/go-gost/x/internal/util/socks" ) diff --git a/connector/socks/v5/connector.go b/connector/socks/v5/connector.go index d52e795..2d8ef17 100644 --- a/connector/socks/v5/connector.go +++ b/connector/socks/v5/connector.go @@ -211,7 +211,7 @@ func (c *socks5Connector) relayUDP(ctx context.Context, conn net.Conn, addr net. log.Debugf("bind on: %v", reply.Addr) - cc, err := opts.NetDialer.Dial(ctx, "udp", reply.Addr.String()) + cc, err := opts.Dialer.Dial(ctx, "udp", reply.Addr.String()) if err != nil { c.options.Logger.Error(err) return nil, err diff --git a/dialer/dtls/dialer.go b/dialer/dtls/dialer.go index 6286092..7ac9a04 100644 --- a/dialer/dtls/dialer.go +++ b/dialer/dtls/dialer.go @@ -45,7 +45,7 @@ func (d *dtlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO opt(&options) } - conn, err := options.NetDialer.Dial(ctx, "udp", addr) + conn, err := options.Dialer.Dial(ctx, "udp", addr) if err != nil { return nil, err } diff --git a/dialer/grpc/dialer.go b/dialer/grpc/dialer.go index ea12072..7a608c4 100644 --- a/dialer/grpc/dialer.go +++ b/dialer/grpc/dialer.go @@ -71,14 +71,13 @@ func (d *grpcDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO grpcOpts := []grpc.DialOption{ // grpc.WithBlock(), grpc.WithContextDialer(func(c context.Context, s string) (net.Conn, error) { - return options.NetDialer.Dial(c, "tcp", s) + return options.Dialer.Dial(c, "tcp", s) }), grpc.WithAuthority(host), grpc.WithConnectParams(grpc.ConnectParams{ Backoff: backoff.DefaultConfig, MinConnectTimeout: d.md.minConnectTimeout, }), - grpc.FailOnNonTempDialError(true), } if !d.md.insecure { grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(d.options.TLSConfig))) @@ -94,7 +93,7 @@ func (d *grpcDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO })) } - cc, err := grpc.DialContext(ctx, addr, grpcOpts...) + cc, err := grpc.NewClient(addr, grpcOpts...) if err != nil { d.options.Logger.Error(err) return nil, err diff --git a/dialer/http2/dialer.go b/dialer/http2/dialer.go index 369640e..0207345 100644 --- a/dialer/http2/dialer.go +++ b/dialer/http2/dialer.go @@ -7,10 +7,10 @@ import ( "sync" "time" - net_dialer "github.com/go-gost/core/common/net/dialer" "github.com/go-gost/core/dialer" "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" + net_dialer "github.com/go-gost/x/internal/net/dialer" mdx "github.com/go-gost/x/metadata" "github.com/go-gost/x/registry" ) @@ -72,7 +72,7 @@ func (d *http2Dialer) Dial(ctx context.Context, address string, opts ...dialer.D { // Check whether the connection is established properly - netd := options.NetDialer + netd := options.Dialer if netd == nil { netd = net_dialer.DefaultNetDialer } @@ -87,7 +87,7 @@ func (d *http2Dialer) Dial(ctx context.Context, address string, opts ...dialer.D Transport: &http.Transport{ TLSClientConfig: d.options.TLSConfig, DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - netd := options.NetDialer + netd := options.Dialer if netd == nil { netd = net_dialer.DefaultNetDialer } diff --git a/dialer/http2/h2/dialer.go b/dialer/http2/h2/dialer.go index 027eeb9..63d1420 100644 --- a/dialer/http2/h2/dialer.go +++ b/dialer/http2/h2/dialer.go @@ -94,14 +94,14 @@ func (d *h2Dialer) Dial(ctx context.Context, address string, opts ...dialer.Dial client.Transport = &http2.Transport{ AllowHTTP: true, DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { - return options.NetDialer.Dial(ctx, network, addr) + return options.Dialer.Dial(ctx, network, addr) }, } } else { client.Transport = &http.Transport{ TLSClientConfig: d.options.TLSConfig, DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - return options.NetDialer.Dial(ctx, network, addr) + return options.Dialer.Dial(ctx, network, addr) }, ForceAttemptHTTP2: true, MaxIdleConns: 100, diff --git a/dialer/http3/dialer.go b/dialer/http3/dialer.go index 6ec0deb..1b406bd 100644 --- a/dialer/http3/dialer.go +++ b/dialer/http3/dialer.go @@ -79,7 +79,7 @@ func (d *http3Dialer) Dial(ctx context.Context, addr string, opts ...dialer.Dial return nil, err } - udpConn, err := options.NetDialer.Dial(ctx, "udp", "") + udpConn, err := options.Dialer.Dial(ctx, "udp", "") if err != nil { return nil, err } diff --git a/dialer/http3/wt/dialer.go b/dialer/http3/wt/dialer.go index 696053b..3c7cd2a 100644 --- a/dialer/http3/wt/dialer.go +++ b/dialer/http3/wt/dialer.go @@ -81,7 +81,7 @@ func (d *wtDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOpt return nil, err } - udpConn, err := options.NetDialer.Dial(ctx, "udp", "") + udpConn, err := options.Dialer.Dial(ctx, "udp", "") if err != nil { return nil, err } diff --git a/dialer/kcp/dialer.go b/dialer/kcp/dialer.go index 20b993c..a73df73 100644 --- a/dialer/kcp/dialer.go +++ b/dialer/kcp/dialer.go @@ -83,7 +83,7 @@ func (d *kcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp PacketConn: pc, } } else { - c, err := options.NetDialer.Dial(ctx, "udp", "") + c, err := options.Dialer.Dial(ctx, "udp", "") if err != nil { return nil, err } diff --git a/dialer/mtcp/dialer.go b/dialer/mtcp/dialer.go index a9d1831..7a1c5eb 100644 --- a/dialer/mtcp/dialer.go +++ b/dialer/mtcp/dialer.go @@ -67,7 +67,7 @@ func (d *mtcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO opt(&options) } - conn, err = options.NetDialer.Dial(ctx, "tcp", addr) + conn, err = options.Dialer.Dial(ctx, "tcp", addr) if err != nil { return } diff --git a/dialer/mtls/dialer.go b/dialer/mtls/dialer.go index f7052a6..2c7b902 100644 --- a/dialer/mtls/dialer.go +++ b/dialer/mtls/dialer.go @@ -68,7 +68,7 @@ func (d *mtlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO opt(&options) } - conn, err = options.NetDialer.Dial(ctx, "tcp", addr) + conn, err = options.Dialer.Dial(ctx, "tcp", addr) if err != nil { return } diff --git a/dialer/mws/dialer.go b/dialer/mws/dialer.go index cdd1105..9ffe7a7 100644 --- a/dialer/mws/dialer.go +++ b/dialer/mws/dialer.go @@ -82,7 +82,7 @@ func (d *mwsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp opt(&options) } - conn, err = options.NetDialer.Dial(ctx, "tcp", addr) + conn, err = options.Dialer.Dial(ctx, "tcp", addr) if err != nil { return } diff --git a/dialer/obfs/http/dialer.go b/dialer/obfs/http/dialer.go index d8b4a22..e69d148 100644 --- a/dialer/obfs/http/dialer.go +++ b/dialer/obfs/http/dialer.go @@ -55,7 +55,7 @@ func (d *obfsHTTPDialer) Dial(ctx context.Context, addr string, opts ...dialer.D opt(options) } - conn, err := options.NetDialer.Dial(ctx, "tcp", addr) + conn, err := options.Dialer.Dial(ctx, "tcp", addr) if err != nil { d.logger.Error(err) } diff --git a/dialer/obfs/tls/dialer.go b/dialer/obfs/tls/dialer.go index d7b5b1a..d3ba740 100644 --- a/dialer/obfs/tls/dialer.go +++ b/dialer/obfs/tls/dialer.go @@ -40,7 +40,7 @@ func (d *obfsTLSDialer) Dial(ctx context.Context, addr string, opts ...dialer.Di opt(options) } - conn, err := options.NetDialer.Dial(ctx, "tcp", addr) + conn, err := options.Dialer.Dial(ctx, "tcp", addr) if err != nil { d.logger.Error(err) } diff --git a/dialer/pht/dialer.go b/dialer/pht/dialer.go index 0398b2f..de69aff 100644 --- a/dialer/pht/dialer.go +++ b/dialer/pht/dialer.go @@ -87,7 +87,7 @@ func (d *phtDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp tr := &http.Transport{ // Proxy: http.ProxyFromEnvironment, DialContext: func(ctx context.Context, network, adr string) (net.Conn, error) { - return options.NetDialer.Dial(ctx, network, addr) + return options.Dialer.Dial(ctx, network, addr) }, ForceAttemptHTTP2: true, MaxIdleConns: 100, diff --git a/dialer/quic/dialer.go b/dialer/quic/dialer.go index c43f2ef..618e1b8 100644 --- a/dialer/quic/dialer.go +++ b/dialer/quic/dialer.go @@ -67,7 +67,7 @@ func (d *quicDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO opt(options) } - c, err := options.NetDialer.Dial(ctx, "udp", "") + c, err := options.Dialer.Dial(ctx, "udp", "") if err != nil { return nil, err } diff --git a/dialer/ssh/dialer.go b/dialer/ssh/dialer.go index 509c3cb..d97f000 100644 --- a/dialer/ssh/dialer.go +++ b/dialer/ssh/dialer.go @@ -64,7 +64,7 @@ func (d *sshDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp opt(&options) } - conn, err = options.NetDialer.Dial(ctx, "tcp", addr) + conn, err = options.Dialer.Dial(ctx, "tcp", addr) if err != nil { return } diff --git a/dialer/sshd/dialer.go b/dialer/sshd/dialer.go index c09c36b..1ec7760 100644 --- a/dialer/sshd/dialer.go +++ b/dialer/sshd/dialer.go @@ -64,7 +64,7 @@ func (d *sshdDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialO opt(&options) } - conn, err = options.NetDialer.Dial(ctx, "tcp", addr) + conn, err = options.Dialer.Dial(ctx, "tcp", addr) if err != nil { return } diff --git a/dialer/tcp/dialer.go b/dialer/tcp/dialer.go index 16f19f3..91c9e60 100644 --- a/dialer/tcp/dialer.go +++ b/dialer/tcp/dialer.go @@ -40,7 +40,7 @@ func (d *tcpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp opt(&options) } - conn, err := options.NetDialer.Dial(ctx, "tcp", addr) + conn, err := options.Dialer.Dial(ctx, "tcp", addr) if err != nil { d.logger.Error(err) } diff --git a/dialer/tls/dialer.go b/dialer/tls/dialer.go index fd9967c..a5f68d3 100644 --- a/dialer/tls/dialer.go +++ b/dialer/tls/dialer.go @@ -44,7 +44,7 @@ func (d *tlsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp opt(&options) } - conn, err := options.NetDialer.Dial(ctx, "tcp", addr) + conn, err := options.Dialer.Dial(ctx, "tcp", addr) if err != nil { d.logger.Error(err) } diff --git a/dialer/udp/dialer.go b/dialer/udp/dialer.go index 42a8261..cc57d1e 100644 --- a/dialer/udp/dialer.go +++ b/dialer/udp/dialer.go @@ -40,7 +40,7 @@ func (d *udpDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOp opt(&options) } - c, err := options.NetDialer.Dial(ctx, "udp", addr) + c, err := options.Dialer.Dial(ctx, "udp", addr) if err != nil { return nil, err } diff --git a/dialer/wg/dialer.go b/dialer/wg/dialer.go index 33ac93e..83e1335 100644 --- a/dialer/wg/dialer.go +++ b/dialer/wg/dialer.go @@ -40,7 +40,7 @@ func (d *wgDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOpt opt(&options) } - conn, err := options.NetDialer.Dial(ctx, "tcp", addr) + conn, err := options.Dialer.Dial(ctx, "tcp", addr) if err != nil { d.logger.Error(err) } diff --git a/dialer/ws/dialer.go b/dialer/ws/dialer.go index ccc5bc5..1d6e90f 100644 --- a/dialer/ws/dialer.go +++ b/dialer/ws/dialer.go @@ -57,7 +57,7 @@ func (d *wsDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOpt opt(&options) } - conn, err := options.NetDialer.Dial(ctx, "tcp", addr) + conn, err := options.Dialer.Dial(ctx, "tcp", addr) if err != nil { d.options.Logger.Error(err) } diff --git a/go.mod b/go.mod index b50a1a3..fbd0250 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/gin-contrib/cors v1.6.0 github.com/gin-gonic/gin v1.9.1 - github.com/go-gost/core v0.0.0-20240704150322-30cc92870515 + github.com/go-gost/core v0.0.0-20240708142821-48d070d34568 github.com/go-gost/gosocks4 v0.0.1 github.com/go-gost/gosocks5 v0.4.2 github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a @@ -20,7 +20,7 @@ require ( github.com/golang/snappy v0.0.4 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.1 - github.com/miekg/dns v1.1.57 + github.com/miekg/dns v1.1.61 github.com/mitchellh/go-homedir v1.1.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pion/dtls/v2 v2.2.6 @@ -41,12 +41,12 @@ require ( github.com/xtaci/tcpraw v1.2.25 github.com/yl2chen/cidranger v1.0.2 github.com/zalando/go-keyring v0.2.4 - golang.org/x/crypto v0.24.0 - golang.org/x/net v0.26.0 - golang.org/x/sys v0.21.0 + golang.org/x/crypto v0.25.0 + golang.org/x/net v0.27.0 + golang.org/x/sys v0.22.0 golang.org/x/time v0.5.0 golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 - google.golang.org/grpc v1.64.0 + google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 @@ -57,7 +57,7 @@ require ( github.com/alessio/shellescape v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.11.2 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/coreos/go-iptables v0.5.0 // indirect @@ -111,11 +111,11 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.7.0 // indirect golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect - golang.org/x/mod v0.18.0 // indirect + golang.org/x/mod v0.19.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/text v0.16.0 // indirect - golang.org/x/tools v0.22.0 // indirect + golang.org/x/tools v0.23.0 // indirect golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/go.sum b/go.sum index a175c88..84f356f 100644 --- a/go.sum +++ b/go.sum @@ -15,8 +15,8 @@ github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ github.com/bytedance/sonic v1.11.2 h1:ywfwo0a/3j9HR8wsYGWsIWl2mvRsI950HyoxiBERw5A= github.com/bytedance/sonic v1.11.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= @@ -53,8 +53,8 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-gost/core v0.0.0-20240704150322-30cc92870515 h1:i/zcDZtz00hcmRosvJgXmgJsdc4bC32PAvt2+8MUOEg= -github.com/go-gost/core v0.0.0-20240704150322-30cc92870515/go.mod h1:QmVAZIXIYBsX44Vehwug5RFnG2K3/Hz/uu/Y4QVhAY0= +github.com/go-gost/core v0.0.0-20240708142821-48d070d34568 h1:OJ+FzmBMy9RnWdECxGw6FKHRmN346Q/iVmDUSCBIthk= +github.com/go-gost/core v0.0.0-20240708142821-48d070d34568/go.mod h1:WGI43jOka7FAsSAwi/fSMaqxdR+E339ycb4NBGlFr6A= github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s= github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc= github.com/go-gost/gosocks5 v0.4.2 h1:IianxHTkACPqCwiOAT3MHoMdSUl+SEPSRu1ikawC1Pc= @@ -133,8 +133,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= -github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -271,8 +271,8 @@ golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM= golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= @@ -282,8 +282,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= -golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -295,8 +295,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -317,15 +317,15 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -343,8 +343,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -356,14 +356,14 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3 h1:9Xyg6I9IWQZhRVfCWjKK+l6kI0jHcPesVlMnT//aHNo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240610135401-a8a62080eff3/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/handler/dns/handler.go b/handler/dns/handler.go index e7c71fb..2cd4534 100644 --- a/handler/dns/handler.go +++ b/handler/dns/handler.go @@ -34,7 +34,6 @@ type dnsHandler struct { hop hop.Hop exchangers map[string]exchanger.Exchanger cache *resolver_util.Cache - router *chain.Router hostMapper hosts.HostMapper md metadata options handler.Options @@ -60,11 +59,7 @@ func (h *dnsHandler) Init(md md.Metadata) (err error) { h.cache = resolver_util.NewCache().WithLogger(log) - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(log)) - } - h.hostMapper = h.router.Options().HostMapper + h.hostMapper = h.options.Router.Options().HostMapper if h.hop == nil { var nodes []*chain.Node @@ -88,7 +83,7 @@ func (h *dnsHandler) Init(md md.Metadata) (err error) { } ex, err := exchanger.NewExchanger( addr, - exchanger.RouterOption(h.router), + exchanger.RouterOption(h.options.Router), exchanger.TimeoutOption(h.md.timeout), exchanger.LoggerOption(log), ) @@ -102,7 +97,7 @@ func (h *dnsHandler) Init(md md.Metadata) (err error) { if len(h.exchangers) == 0 { ex, err := exchanger.NewExchanger( defaultNameserver, - exchanger.RouterOption(h.router), + exchanger.RouterOption(h.options.Router), exchanger.TimeoutOption(h.md.timeout), exchanger.LoggerOption(log), ) diff --git a/handler/forward/local/handler.go b/handler/forward/local/handler.go index 0d8f9cb..957d55a 100644 --- a/handler/forward/local/handler.go +++ b/handler/forward/local/handler.go @@ -37,7 +37,6 @@ func init() { type forwardHandler struct { hop hop.Hop - router *chain.Router md metadata options handler.Options } @@ -58,11 +57,6 @@ func (h *forwardHandler) Init(md md.Metadata) (err error) { return } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return } @@ -157,7 +151,7 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand log.Debugf("%s >> %s", conn.RemoteAddr(), addr) - cc, err := h.router.Dial(ctx, network, addr) + cc, err := h.options.Router.Dial(ctx, network, addr) if err != nil { log.Error(err) // TODO: the router itself may be failed due to the failed node in the router, @@ -277,7 +271,7 @@ func (h *forwardHandler) handleHTTP(ctx context.Context, rw io.ReadWriter, remot } } - cc, err = h.router.Dial(ctx, "tcp", target.Addr) + cc, err = h.options.Router.Dial(ctx, "tcp", target.Addr) if err != nil { // TODO: the router itself may be failed due to the failed node in the router, // the dead marker may be a wrong operation. diff --git a/handler/forward/remote/handler.go b/handler/forward/remote/handler.go index c00da9f..dfd2ba2 100644 --- a/handler/forward/remote/handler.go +++ b/handler/forward/remote/handler.go @@ -38,7 +38,6 @@ func init() { type forwardHandler struct { hop hop.Hop - router *chain.Router md metadata options handler.Options } @@ -59,11 +58,6 @@ func (h *forwardHandler) Init(md mdata.Metadata) (err error) { return } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return } @@ -156,7 +150,7 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand log.Debugf("%s >> %s", conn.RemoteAddr(), target.Addr) - cc, err := h.router.Dial(ctx, network, target.Addr) + cc, err := h.options.Router.Dial(ctx, network, target.Addr) if err != nil { log.Error(err) // TODO: the router itself may be failed due to the failed node in the router, @@ -277,7 +271,7 @@ func (h *forwardHandler) handleHTTP(ctx context.Context, rw io.ReadWriter, remot } } - cc, err = h.router.Dial(ctx, "tcp", target.Addr) + cc, err = h.options.Router.Dial(ctx, "tcp", target.Addr) if err != nil { // TODO: the router itself may be failed due to the failed node in the router, // the dead marker may be a wrong operation. diff --git a/handler/http/handler.go b/handler/http/handler.go index 30efe32..392544f 100644 --- a/handler/http/handler.go +++ b/handler/http/handler.go @@ -18,7 +18,6 @@ import ( "time" "github.com/asaskevich/govalidator" - "github.com/go-gost/core/chain" "github.com/go-gost/core/handler" traffic "github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/logger" @@ -37,7 +36,6 @@ func init() { } type httpHandler struct { - router *chain.Router md metadata options handler.Options stats *stats_util.HandlerStats @@ -61,11 +59,6 @@ func (h *httpHandler) Init(md md.Metadata) error { return err } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - ctx, cancel := context.WithCancel(context.Background()) h.cancel = cancel @@ -215,7 +208,7 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt ctx = ctxvalue.ContextWithHash(ctx, &ctxvalue.Hash{Source: addr}) } - cc, err := h.router.Dial(ctx, network, addr) + cc, err := h.options.Router.Dial(ctx, network, addr) if err != nil { resp.StatusCode = http.StatusServiceUnavailable diff --git a/handler/http/udp.go b/handler/http/udp.go index 52db1ca..5e6edf6 100644 --- a/handler/http/udp.go +++ b/handler/http/udp.go @@ -51,7 +51,7 @@ func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, log logger.L } // obtain a udp connection - c, err := h.router.Dial(ctx, "udp", "") // UDP association + c, err := h.options.Router.Dial(ctx, "udp", "") // UDP association if err != nil { log.Error(err) return err diff --git a/handler/http2/handler.go b/handler/http2/handler.go index d95b029..5aa6e46 100644 --- a/handler/http2/handler.go +++ b/handler/http2/handler.go @@ -18,7 +18,6 @@ import ( "strings" "time" - "github.com/go-gost/core/chain" "github.com/go-gost/core/handler" "github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/logger" @@ -38,7 +37,6 @@ func init() { } type http2Handler struct { - router *chain.Router md metadata options handler.Options stats *stats_util.HandlerStats @@ -62,11 +60,6 @@ func (h *http2Handler) Init(md md.Metadata) error { return err } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - ctx, cancel := context.WithCancel(context.Background()) h.cancel = cancel @@ -188,7 +181,7 @@ func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req ctx = ctxvalue.ContextWithHash(ctx, &ctxvalue.Hash{Source: addr}) } - cc, err := h.router.Dial(ctx, "tcp", addr) + cc, err := h.options.Router.Dial(ctx, "tcp", addr) if err != nil { log.Error(err) w.WriteHeader(http.StatusServiceUnavailable) diff --git a/handler/http3/handler.go b/handler/http3/handler.go index abee3b9..933b12a 100644 --- a/handler/http3/handler.go +++ b/handler/http3/handler.go @@ -24,7 +24,6 @@ func init() { type http3Handler struct { hop hop.Hop - router *chain.Router md metadata options handler.Options } @@ -45,11 +44,6 @@ func (h *http3Handler) Init(md md.Metadata) error { return err } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return nil } @@ -147,7 +141,7 @@ func (h *http3Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - conn, err := h.router.Dial(ctx, network, target.Addr) + conn, err := h.options.Router.Dial(ctx, network, target.Addr) if err != nil { log.Error(err) // TODO: the router itself may be failed due to the failed node in the router, diff --git a/handler/redirect/tcp/handler.go b/handler/redirect/tcp/handler.go index a81a8a2..56d5e9b 100644 --- a/handler/redirect/tcp/handler.go +++ b/handler/redirect/tcp/handler.go @@ -15,7 +15,6 @@ import ( "time" "github.com/go-gost/core/bypass" - "github.com/go-gost/core/chain" "github.com/go-gost/core/handler" "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" @@ -32,7 +31,6 @@ func init() { } type redirectHandler struct { - router *chain.Router md metadata options handler.Options } @@ -53,11 +51,6 @@ func (h *redirectHandler) Init(md md.Metadata) (err error) { return } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return } @@ -129,7 +122,7 @@ func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn, opts ...han return nil } - cc, err := h.router.Dial(ctx, dstAddr.Network(), dstAddr.String()) + cc, err := h.options.Router.Dial(ctx, dstAddr.Network(), dstAddr.String()) if err != nil { log.Error(err) return err @@ -170,13 +163,13 @@ func (h *redirectHandler) handleHTTP(ctx context.Context, rw io.ReadWriter, radd return nil } - cc, err := h.router.Dial(ctx, "tcp", host) + cc, err := h.options.Router.Dial(ctx, "tcp", host) if err != nil { log.Error(err) } if cc == nil { - cc, err = h.router.Dial(ctx, "tcp", dstAddr.String()) + cc, err = h.options.Router.Dial(ctx, "tcp", dstAddr.String()) if err != nil { log.Error(err) return err @@ -245,14 +238,14 @@ func (h *redirectHandler) handleHTTPS(ctx context.Context, rw io.ReadWriter, rad return nil } - cc, err = h.router.Dial(ctx, "tcp", host) + cc, err = h.options.Router.Dial(ctx, "tcp", host) if err != nil { log.Error(err) } } if cc == nil { - cc, err = h.router.Dial(ctx, "tcp", dstAddr.String()) + cc, err = h.options.Router.Dial(ctx, "tcp", dstAddr.String()) if err != nil { log.Error(err) return err diff --git a/handler/redirect/udp/handler.go b/handler/redirect/udp/handler.go index d340266..3fe6692 100644 --- a/handler/redirect/udp/handler.go +++ b/handler/redirect/udp/handler.go @@ -6,7 +6,6 @@ import ( "net" "time" - "github.com/go-gost/core/chain" "github.com/go-gost/core/handler" md "github.com/go-gost/core/metadata" netpkg "github.com/go-gost/x/internal/net" @@ -18,7 +17,6 @@ func init() { } type redirectHandler struct { - router *chain.Router md metadata options handler.Options } @@ -39,11 +37,6 @@ func (h *redirectHandler) Init(md md.Metadata) (err error) { return } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return } @@ -80,7 +73,7 @@ func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn, opts ...han return nil } - cc, err := h.router.Dial(ctx, dstAddr.Network(), dstAddr.String()) + cc, err := h.options.Router.Dial(ctx, dstAddr.Network(), dstAddr.String()) if err != nil { log.Error(err) return err diff --git a/handler/relay/connect.go b/handler/relay/connect.go index 2fae3be..f956717 100644 --- a/handler/relay/connect.go +++ b/handler/relay/connect.go @@ -66,7 +66,7 @@ func (h *relayHandler) handleConnect(ctx context.Context, conn net.Conn, network case "serial": cc, err = serial.OpenPort(serial.ParseConfigFromAddr(address)) default: - cc, err = h.router.Dial(ctx, network, address) + cc, err = h.options.Router.Dial(ctx, network, address) } if err != nil { resp.Status = relay.StatusNetworkUnreachable diff --git a/handler/relay/forward.go b/handler/relay/forward.go index 8074c55..9f4f08f 100644 --- a/handler/relay/forward.go +++ b/handler/relay/forward.go @@ -38,7 +38,7 @@ func (h *relayHandler) handleForward(ctx context.Context, conn net.Conn, network log.Debugf("%s >> %s", conn.RemoteAddr(), target.Addr) - cc, err := h.router.Dial(ctx, network, target.Addr) + cc, err := h.options.Router.Dial(ctx, network, target.Addr) if err != nil { // TODO: the router itself may be failed due to the failed node in the router, // the dead marker may be a wrong operation. diff --git a/handler/relay/handler.go b/handler/relay/handler.go index 4b368ae..c86c02c 100644 --- a/handler/relay/handler.go +++ b/handler/relay/handler.go @@ -7,7 +7,6 @@ import ( "strconv" "time" - "github.com/go-gost/core/chain" "github.com/go-gost/core/handler" "github.com/go-gost/core/hop" md "github.com/go-gost/core/metadata" @@ -30,7 +29,6 @@ func init() { type relayHandler struct { hop hop.Hop - router *chain.Router md metadata options handler.Options stats *stats_util.HandlerStats @@ -54,11 +52,6 @@ func (h *relayHandler) Init(md md.Metadata) (err error) { return err } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - ctx, cancel := context.WithCancel(context.Background()) h.cancel = cancel diff --git a/handler/serial/handler.go b/handler/serial/handler.go index 59853b4..313e430 100644 --- a/handler/serial/handler.go +++ b/handler/serial/handler.go @@ -25,7 +25,6 @@ func init() { type serialHandler struct { hop hop.Hop - router *chain.Router md metadata options handler.Options recorder recorder.RecorderObject @@ -47,11 +46,7 @@ func (h *serialHandler) Init(md md.Metadata) (err error) { return } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - if opts := h.router.Options(); opts != nil { + if opts := h.options.Router.Options(); opts != nil { for _, ro := range opts.Recorders { if ro.Record == xrecorder.RecorderServiceHandlerSerial { h.recorder = ro @@ -97,7 +92,7 @@ func (h *serialHandler) Handle(ctx context.Context, conn net.Conn, opts ...handl return h.forwardSerial(ctx, conn, target, log) } - cc, err := h.router.Dial(ctx, "tcp", "@") + cc, err := h.options.Router.Dial(ctx, "tcp", "@") if err != nil { log.Error(err) return err @@ -121,8 +116,8 @@ func (h *serialHandler) forwardSerial(ctx context.Context, conn net.Conn, target cfg := serial.ParseConfigFromAddr(conn.LocalAddr().String()) cfg.Name = target.Addr - if opts := h.router.Options(); opts != nil && opts.Chain != nil { - port, err = h.router.Dial(ctx, "serial", serial.AddrFromConfig(cfg)) + if opts := h.options.Router.Options(); opts != nil && opts.Chain != nil { + port, err = h.options.Router.Dial(ctx, "serial", serial.AddrFromConfig(cfg)) } else { cfg.ReadTimeout = h.md.timeout port, err = serial.OpenPort(cfg) diff --git a/handler/sni/handler.go b/handler/sni/handler.go index 4cbb712..d70bf2d 100644 --- a/handler/sni/handler.go +++ b/handler/sni/handler.go @@ -16,7 +16,6 @@ import ( "time" "github.com/go-gost/core/bypass" - "github.com/go-gost/core/chain" "github.com/go-gost/core/handler" "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" @@ -32,7 +31,6 @@ func init() { } type sniHandler struct { - router *chain.Router md metadata options handler.Options } @@ -55,11 +53,6 @@ func (h *sniHandler) Init(md md.Metadata) (err error) { return } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return nil } @@ -128,7 +121,7 @@ func (h *sniHandler) handleHTTP(ctx context.Context, rw io.ReadWriter, raddr net ctx = ctxvalue.ContextWithHash(ctx, &ctxvalue.Hash{Source: host}) } - cc, err := h.router.Dial(ctx, "tcp", host) + cc, err := h.options.Router.Dial(ctx, "tcp", host) if err != nil { log.Error(err) return err @@ -196,7 +189,7 @@ func (h *sniHandler) handleHTTPS(ctx context.Context, rw io.ReadWriter, raddr ne ctx = ctxvalue.ContextWithHash(ctx, &ctxvalue.Hash{Source: host}) } - cc, err := h.router.Dial(ctx, "tcp", host) + cc, err := h.options.Router.Dial(ctx, "tcp", host) if err != nil { log.Error(err) return err diff --git a/handler/socks/v4/handler.go b/handler/socks/v4/handler.go index ee67332..2637b92 100644 --- a/handler/socks/v4/handler.go +++ b/handler/socks/v4/handler.go @@ -6,7 +6,6 @@ import ( "net" "time" - "github.com/go-gost/core/chain" "github.com/go-gost/core/handler" "github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/logger" @@ -32,7 +31,6 @@ func init() { } type socks4Handler struct { - router *chain.Router md metadata options handler.Options stats *stats_util.HandlerStats @@ -56,11 +54,6 @@ func (h *socks4Handler) Init(md md.Metadata) (err error) { return err } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - ctx, cancel := context.WithCancel(context.Background()) h.cancel = cancel @@ -154,7 +147,7 @@ func (h *socks4Handler) handleConnect(ctx context.Context, conn net.Conn, req *g ctx = ctxvalue.ContextWithHash(ctx, &ctxvalue.Hash{Source: addr}) } - cc, err := h.router.Dial(ctx, "tcp", addr) + cc, err := h.options.Router.Dial(ctx, "tcp", addr) if err != nil { resp := gosocks4.NewReply(gosocks4.Failed, nil) log.Trace(resp) diff --git a/handler/socks/v5/connect.go b/handler/socks/v5/connect.go index 1ba0d03..6c2a266 100644 --- a/handler/socks/v5/connect.go +++ b/handler/socks/v5/connect.go @@ -35,7 +35,7 @@ func (h *socks5Handler) handleConnect(ctx context.Context, conn net.Conn, networ ctx = ctxvalue.ContextWithHash(ctx, &ctxvalue.Hash{Source: address}) } - cc, err := h.router.Dial(ctx, network, address) + cc, err := h.options.Router.Dial(ctx, network, address) if err != nil { resp := gosocks5.NewReply(gosocks5.NetUnreachable, nil) log.Trace(resp) diff --git a/handler/socks/v5/handler.go b/handler/socks/v5/handler.go index 3d14482..ece0b83 100644 --- a/handler/socks/v5/handler.go +++ b/handler/socks/v5/handler.go @@ -6,7 +6,6 @@ import ( "net" "time" - "github.com/go-gost/core/chain" "github.com/go-gost/core/handler" md "github.com/go-gost/core/metadata" "github.com/go-gost/gosocks5" @@ -27,7 +26,6 @@ func init() { type socks5Handler struct { selector gosocks5.Selector - router *chain.Router md metadata options handler.Options stats *stats_util.HandlerStats @@ -51,11 +49,6 @@ func (h *socks5Handler) Init(md md.Metadata) (err error) { return } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - h.selector = &serverSelector{ Authenticator: h.options.Auther, TLSConfig: h.options.TLSConfig, diff --git a/handler/socks/v5/udp.go b/handler/socks/v5/udp.go index d4405f9..95f2669 100644 --- a/handler/socks/v5/udp.go +++ b/handler/socks/v5/udp.go @@ -59,7 +59,7 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, log logger log.Debugf("bind on %s OK", cc.LocalAddr()) // obtain a udp connection - c, err := h.router.Dial(ctx, "udp", "") // UDP association + c, err := h.options.Router.Dial(ctx, "udp", "") // UDP association if err != nil { log.Error(err) return err diff --git a/handler/socks/v5/udp_tun.go b/handler/socks/v5/udp_tun.go index 7b99c6b..b9d1ccb 100644 --- a/handler/socks/v5/udp_tun.go +++ b/handler/socks/v5/udp_tun.go @@ -37,7 +37,7 @@ func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network } // obtain a udp connection - c, err := h.router.Dial(ctx, "udp", "") // UDP association + c, err := h.options.Router.Dial(ctx, "udp", "") // UDP association if err != nil { log.Error(err) return err diff --git a/handler/ss/handler.go b/handler/ss/handler.go index 3b58609..c6315cb 100644 --- a/handler/ss/handler.go +++ b/handler/ss/handler.go @@ -6,7 +6,6 @@ import ( "net" "time" - "github.com/go-gost/core/chain" "github.com/go-gost/core/handler" md "github.com/go-gost/core/metadata" "github.com/go-gost/gosocks5" @@ -23,7 +22,6 @@ func init() { type ssHandler struct { cipher core.Cipher - router *chain.Router md metadata options handler.Options } @@ -52,11 +50,6 @@ func (h *ssHandler) Init(md md.Metadata) (err error) { } } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return } @@ -111,7 +104,7 @@ func (h *ssHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.H ctx = ctxvalue.ContextWithHash(ctx, &ctxvalue.Hash{Source: addr.String()}) } - cc, err := h.router.Dial(ctx, "tcp", addr.String()) + cc, err := h.options.Router.Dial(ctx, "tcp", addr.String()) if err != nil { return err } diff --git a/handler/ss/udp/handler.go b/handler/ss/udp/handler.go index 4f31422..ef8cfed 100644 --- a/handler/ss/udp/handler.go +++ b/handler/ss/udp/handler.go @@ -6,7 +6,6 @@ import ( "net" "time" - "github.com/go-gost/core/chain" "github.com/go-gost/core/common/bufpool" "github.com/go-gost/core/handler" "github.com/go-gost/core/logger" @@ -23,7 +22,6 @@ func init() { type ssuHandler struct { cipher core.Cipher - router *chain.Router md metadata options handler.Options } @@ -53,11 +51,6 @@ func (h *ssuHandler) Init(md md.Metadata) (err error) { } } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return } @@ -97,7 +90,7 @@ func (h *ssuHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler. } // obtain a udp connection - c, err := h.router.Dial(ctx, "udp", "") // UDP association + c, err := h.options.Router.Dial(ctx, "udp", "") // UDP association if err != nil { log.Error(err) return err diff --git a/handler/sshd/handler.go b/handler/sshd/handler.go index e22fb98..884f629 100644 --- a/handler/sshd/handler.go +++ b/handler/sshd/handler.go @@ -9,7 +9,6 @@ import ( "strconv" "time" - "github.com/go-gost/core/chain" "github.com/go-gost/core/handler" "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" @@ -29,7 +28,6 @@ func init() { } type forwardHandler struct { - router *chain.Router md metadata options handler.Options } @@ -50,11 +48,6 @@ func (h *forwardHandler) Init(md md.Metadata) (err error) { return } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return nil } @@ -97,7 +90,7 @@ func (h *forwardHandler) handleDirectForward(ctx context.Context, conn *sshd_uti return nil } - cc, err := h.router.Dial(ctx, "tcp", targetAddr) + cc, err := h.options.Router.Dial(ctx, "tcp", targetAddr) if err != nil { return err } diff --git a/handler/tap/handler.go b/handler/tap/handler.go index ccd1dc2..66be14e 100644 --- a/handler/tap/handler.go +++ b/handler/tap/handler.go @@ -33,7 +33,6 @@ type tapHandler struct { routes sync.Map exit chan struct{} cipher core.Cipher - router *chain.Router md metadata options handler.Options } @@ -64,11 +63,6 @@ func (h *tapHandler) Init(md md.Metadata) (err error) { } } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return } @@ -135,7 +129,7 @@ func (h *tapHandler) handleLoop(ctx context.Context, conn net.Conn, addr net.Add var pc net.PacketConn if addr != nil { - cc, err := h.router.Dial(ctx, addr.Network(), "") + cc, err := h.options.Router.Dial(ctx, addr.Network(), "") if err != nil { return err } diff --git a/handler/tun/client.go b/handler/tun/client.go index a02bb7c..926ab4c 100644 --- a/handler/tun/client.go +++ b/handler/tun/client.go @@ -35,7 +35,7 @@ func (h *tunHandler) handleClient(ctx context.Context, conn net.Conn, raddr stri for { err := func() error { - cc, err := h.router.Dial(ctx, "udp", raddr) + cc, err := h.options.Router.Dial(ctx, "udp", raddr) if err != nil { return err } diff --git a/handler/tun/handler.go b/handler/tun/handler.go index 2f87ffb..94aa93f 100644 --- a/handler/tun/handler.go +++ b/handler/tun/handler.go @@ -29,7 +29,6 @@ func init() { type tunHandler struct { hop hop.Hop routes sync.Map - router *chain.Router md metadata options handler.Options } @@ -50,11 +49,6 @@ func (h *tunHandler) Init(md md.Metadata) (err error) { return } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return } diff --git a/handler/unix/handler.go b/handler/unix/handler.go index d03cf56..f819493 100644 --- a/handler/unix/handler.go +++ b/handler/unix/handler.go @@ -8,8 +8,8 @@ import ( "time" "github.com/go-gost/core/chain" - "github.com/go-gost/core/hop" "github.com/go-gost/core/handler" + "github.com/go-gost/core/hop" "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" xnet "github.com/go-gost/x/internal/net" @@ -22,7 +22,6 @@ func init() { type unixHandler struct { hop hop.Hop - router *chain.Router md metadata options handler.Options } @@ -43,11 +42,6 @@ func (h *unixHandler) Init(md md.Metadata) (err error) { return } - h.router = h.options.Router - if h.router == nil { - h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger)) - } - return } @@ -80,7 +74,7 @@ func (h *unixHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler return h.forwardUnix(ctx, conn, target, log) } - cc, err := h.router.Dial(ctx, "tcp", "@") + cc, err := h.options.Router.Dial(ctx, "tcp", "@") if err != nil { log.Error(err) return err @@ -101,8 +95,8 @@ func (h *unixHandler) forwardUnix(ctx context.Context, conn net.Conn, target *ch log.Debugf("%s >> %s", conn.LocalAddr(), target.Addr) var cc io.ReadWriteCloser - if opts := h.router.Options(); opts != nil && opts.Chain != nil { - cc, err = h.router.Dial(ctx, "unix", target.Addr) + if opts := h.options.Router.Options(); opts != nil && opts.Chain != nil { + cc, err = h.options.Router.Dial(ctx, "unix", target.Addr) } else { cc, err = (&net.Dialer{}).DialContext(ctx, "unix", target.Addr) } diff --git a/internal/net/addr.go b/internal/net/addr.go index 8b24a0b..9675946 100644 --- a/internal/net/addr.go +++ b/internal/net/addr.go @@ -7,6 +7,84 @@ import ( "strings" ) +func ParseInterfaceAddr(ifceName, network string) (ifce string, addr []net.Addr, err error) { + if ifceName == "" { + addr = append(addr, nil) + return + } + + ip := net.ParseIP(ifceName) + if ip == nil { + var ife *net.Interface + ife, err = net.InterfaceByName(ifceName) + if err != nil { + return + } + var addrs []net.Addr + addrs, err = ife.Addrs() + if err != nil { + return + } + if len(addrs) == 0 { + err = fmt.Errorf("addr not found for interface %s", ifceName) + return + } + ifce = ifceName + for _, addr_ := range addrs { + if ipNet, ok := addr_.(*net.IPNet); ok { + addr = append(addr, ipToAddr(ipNet.IP, network)) + } + } + } else { + ifce, err = findInterfaceByIP(ip) + if err != nil { + return + } + addr = []net.Addr{ipToAddr(ip, network)} + } + + return +} + +func ipToAddr(ip net.IP, network string) (addr net.Addr) { + port := 0 + switch network { + case "tcp", "tcp4", "tcp6": + addr = &net.TCPAddr{IP: ip, Port: port} + return + case "udp", "udp4", "udp6": + addr = &net.UDPAddr{IP: ip, Port: port} + return + default: + addr = &net.IPAddr{IP: ip} + return + } +} + +func findInterfaceByIP(ip net.IP) (string, error) { + ifces, err := net.Interfaces() + if err != nil { + return "", err + } + for _, ifce := range ifces { + addrs, _ := ifce.Addrs() + if len(addrs) == 0 { + continue + } + for _, addr := range addrs { + ipAddr, _ := addr.(*net.IPNet) + if ipAddr == nil { + continue + } + // logger.Default().Infof("%s-%s", ipAddr, ip) + if ipAddr.IP.Equal(ip) { + return ifce.Name, nil + } + } + } + return "", nil +} + // AddrPortRange is the network address with port range supported. // e.g. 192.168.1.1:0-65535 type AddrPortRange string diff --git a/internal/net/dialer/dialer.go b/internal/net/dialer/dialer.go new file mode 100644 index 0000000..f1b10a8 --- /dev/null +++ b/internal/net/dialer/dialer.go @@ -0,0 +1,176 @@ +package dialer + +import ( + "context" + "fmt" + "net" + "runtime" + "strings" + "syscall" + "time" + + "github.com/go-gost/core/logger" + xnet "github.com/go-gost/x/internal/net" + "github.com/vishvananda/netns" +) + +const ( + DefaultTimeout = 10 * time.Second +) + +var ( + DefaultNetDialer = &Dialer{} +) + +type Dialer struct { + Interface string + Netns string + Mark int + DialFunc func(ctx context.Context, network, addr string) (net.Conn, error) + Logger logger.Logger +} + +func (d *Dialer) Dial(ctx context.Context, network, addr string) (conn net.Conn, err error) { + if d == nil { + d = DefaultNetDialer + } + + log := d.Logger + if log == nil { + log = logger.Default() + } + + if d.Netns != "" { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + originNs, err := netns.Get() + if err != nil { + return nil, fmt.Errorf("netns.Get(): %v", err) + } + defer netns.Set(originNs) + + var ns netns.NsHandle + if strings.HasPrefix(d.Netns, "/") { + ns, err = netns.GetFromPath(d.Netns) + } else { + ns, err = netns.GetFromName(d.Netns) + } + if err != nil { + return nil, fmt.Errorf("netns.Get(%s): %v", d.Netns, err) + } + defer ns.Close() + + if err := netns.Set(ns); err != nil { + return nil, fmt.Errorf("netns.Set(%s): %v", d.Netns, err) + } + } + + if d.DialFunc != nil { + return d.DialFunc(ctx, network, addr) + } + + switch network { + case "unix": + netd := net.Dialer{} + return netd.DialContext(ctx, network, addr) + default: + } + + ifces := strings.Split(d.Interface, ",") + for _, ifce := range ifces { + strict := strings.HasSuffix(ifce, "!") + ifce = strings.TrimSuffix(ifce, "!") + var ifceName string + var ifAddrs []net.Addr + ifceName, ifAddrs, err = xnet.ParseInterfaceAddr(ifce, network) + if err != nil && strict { + return + } + + for _, ifAddr := range ifAddrs { + conn, err = d.dialOnce(ctx, network, addr, ifceName, ifAddr, log) + if err == nil { + return + } + + log.Debugf("dial %s %v@%s failed: %s", network, ifAddr, ifceName, err) + + if strict && + !strings.Contains(err.Error(), "no suitable address found") && + !strings.Contains(err.Error(), "mismatched local address type") { + return + } + } + } + + return +} + +func (d *Dialer) dialOnce(ctx context.Context, network, addr, ifceName string, ifAddr net.Addr, log logger.Logger) (net.Conn, error) { + if ifceName != "" { + log.Debugf("interface: %s %v/%s", ifceName, ifAddr, network) + } + + switch network { + case "udp", "udp4", "udp6": + if addr == "" { + var laddr *net.UDPAddr + if ifAddr != nil { + laddr, _ = ifAddr.(*net.UDPAddr) + } + + c, err := net.ListenUDP(network, laddr) + if err != nil { + return nil, err + } + sc, err := c.SyscallConn() + if err != nil { + log.Error(err) + return nil, err + } + err = sc.Control(func(fd uintptr) { + if ifceName != "" { + if err := bindDevice(fd, ifceName); err != nil { + log.Warnf("bind device: %v", err) + } + } + if d.Mark != 0 { + if err := setMark(fd, d.Mark); err != nil { + log.Warnf("set mark: %v", err) + } + } + }) + if err != nil { + log.Error(err) + } + return c, nil + } + case "tcp", "tcp4", "tcp6": + default: + return nil, fmt.Errorf("dial: unsupported network %s", network) + } + netd := net.Dialer{ + LocalAddr: ifAddr, + Control: func(network, address string, c syscall.RawConn) error { + return c.Control(func(fd uintptr) { + if ifceName != "" { + if err := bindDevice(fd, ifceName); err != nil { + log.Warnf("bind device: %v", err) + } + } + if d.Mark != 0 { + if err := setMark(fd, d.Mark); err != nil { + log.Warnf("set mark: %v", err) + } + } + }) + }, + } + if d.Netns != "" { + // https://github.com/golang/go/issues/44922#issuecomment-796645858 + netd.FallbackDelay = -1 + } + + return netd.DialContext(ctx, network, addr) +} diff --git a/internal/net/dialer/dialer_linux.go b/internal/net/dialer/dialer_linux.go new file mode 100644 index 0000000..730af75 --- /dev/null +++ b/internal/net/dialer/dialer_linux.go @@ -0,0 +1,19 @@ +package dialer + +import ( + "golang.org/x/sys/unix" +) + +func bindDevice(fd uintptr, ifceName string) error { + if ifceName == "" { + return nil + } + return unix.BindToDevice(int(fd), ifceName) +} + +func setMark(fd uintptr, mark int) error { + if mark == 0 { + return nil + } + return unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_MARK, mark) +} diff --git a/internal/net/dialer/dialer_other.go b/internal/net/dialer/dialer_other.go new file mode 100644 index 0000000..fff35b4 --- /dev/null +++ b/internal/net/dialer/dialer_other.go @@ -0,0 +1,11 @@ +//go:build !linux + +package dialer + +func bindDevice(fd uintptr, ifceName string) error { + return nil +} + +func setMark(fd uintptr, mark int) error { + return nil +} diff --git a/internal/net/resovle.go b/internal/net/resovle.go new file mode 100644 index 0000000..fb5b8eb --- /dev/null +++ b/internal/net/resovle.go @@ -0,0 +1,44 @@ +package net + +import ( + "context" + "fmt" + "net" + + "github.com/go-gost/core/hosts" + "github.com/go-gost/core/logger" + "github.com/go-gost/core/resolver" +) + +func Resolve(ctx context.Context, network, addr string, r resolver.Resolver, hosts hosts.HostMapper, log logger.Logger) (string, error) { + if addr == "" { + return addr, nil + } + + host, port, _ := net.SplitHostPort(addr) + if host == "" { + return addr, nil + } + + if hosts != nil { + if ips, _ := hosts.Lookup(ctx, network, host); len(ips) > 0 { + log.Debugf("hit host mapper: %s -> %s", host, ips) + return net.JoinHostPort(ips[0].String(), port), nil + } + } + + if r != nil { + ips, err := r.Resolve(ctx, network, host) + if err != nil { + if err == resolver.ErrInvalid { + return addr, nil + } + log.Error(err) + } + if len(ips) == 0 { + return "", fmt.Errorf("resolver: domain %s does not exist", host) + } + return net.JoinHostPort(ips[0].String(), port), nil + } + return addr, nil +} diff --git a/internal/net/udp/listener.go b/internal/net/udp/listener.go new file mode 100644 index 0000000..b88b7ce --- /dev/null +++ b/internal/net/udp/listener.go @@ -0,0 +1,232 @@ +package udp + +import ( + "errors" + "net" + "sync" + "sync/atomic" + "time" + + "github.com/go-gost/core/common/bufpool" + "github.com/go-gost/core/logger" +) + +type ListenConfig struct { + Addr net.Addr + Backlog int + ReadQueueSize int + ReadBufferSize int + TTL time.Duration + KeepAlive bool + Logger logger.Logger +} +type listener struct { + conn net.PacketConn + cqueue chan net.Conn + connPool *connPool + // mux sync.Mutex + closed chan struct{} + errChan chan error + config *ListenConfig +} + +func NewListener(conn net.PacketConn, cfg *ListenConfig) net.Listener { + if cfg == nil { + cfg = &ListenConfig{} + } + + ln := &listener{ + conn: conn, + cqueue: make(chan net.Conn, cfg.Backlog), + closed: make(chan struct{}), + errChan: make(chan error, 1), + config: cfg, + } + if cfg.KeepAlive { + ln.connPool = newConnPool(cfg.TTL).WithLogger(cfg.Logger) + } + go ln.listenLoop() + + return ln +} + +func (ln *listener) Accept() (conn net.Conn, err error) { + select { + case conn = <-ln.cqueue: + return + case <-ln.closed: + return nil, net.ErrClosed + case err = <-ln.errChan: + if err == nil { + err = net.ErrClosed + } + return + } +} + +func (ln *listener) listenLoop() { + for { + select { + case <-ln.closed: + return + default: + } + + b := bufpool.Get(ln.config.ReadBufferSize) + + n, raddr, err := ln.conn.ReadFrom(b) + if err != nil { + ln.errChan <- err + close(ln.errChan) + return + } + + c := ln.getConn(raddr) + if c == nil { + bufpool.Put(b) + continue + } + + if err := c.WriteQueue(b[:n]); err != nil { + ln.config.Logger.Warn("data discarded: ", err) + } + } +} + +func (ln *listener) Addr() net.Addr { + if ln.config.Addr != nil { + return ln.config.Addr + } + return ln.conn.LocalAddr() +} + +func (ln *listener) Close() error { + select { + case <-ln.closed: + default: + close(ln.closed) + ln.conn.Close() + ln.connPool.Close() + } + + return nil +} + +func (ln *listener) getConn(raddr net.Addr) *conn { + // ln.mux.Lock() + // defer ln.mux.Unlock() + + c, ok := ln.connPool.Get(raddr.String()) + if ok { + return c + } + + c = newConn(ln.conn, ln.Addr(), raddr, ln.config.ReadQueueSize, ln.config.KeepAlive) + select { + case ln.cqueue <- c: + ln.connPool.Set(raddr.String(), c) + return c + default: + c.Close() + ln.config.Logger.Warnf("connection queue is full, client %s discarded", raddr) + return nil + } +} + +// conn is a server side connection for UDP client peer, it implements net.Conn and net.PacketConn. +type conn struct { + net.PacketConn + localAddr net.Addr + remoteAddr net.Addr + rc chan []byte // data receive queue + idle int32 // indicate the connection is idle + closed chan struct{} + closeMutex sync.Mutex + keepAlive bool +} + +func newConn(c net.PacketConn, laddr, remoteAddr net.Addr, queueSize int, keepAlive bool) *conn { + return &conn{ + PacketConn: c, + localAddr: laddr, + remoteAddr: remoteAddr, + rc: make(chan []byte, queueSize), + closed: make(chan struct{}), + keepAlive: keepAlive, + } +} + +func (c *conn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { + select { + case bb := <-c.rc: + n = copy(b, bb) + c.SetIdle(false) + bufpool.Put(bb) + + case <-c.closed: + err = net.ErrClosed + return + } + + addr = c.remoteAddr + + return +} + +func (c *conn) Read(b []byte) (n int, err error) { + n, _, err = c.ReadFrom(b) + return +} + +func (c *conn) Write(b []byte) (n int, err error) { + n, err = c.WriteTo(b, c.remoteAddr) + if !c.keepAlive { + c.Close() + } + return +} + +func (c *conn) Close() error { + c.closeMutex.Lock() + defer c.closeMutex.Unlock() + + select { + case <-c.closed: + default: + close(c.closed) + } + return nil +} + +func (c *conn) LocalAddr() net.Addr { + return c.localAddr +} + +func (c *conn) RemoteAddr() net.Addr { + return c.remoteAddr +} + +func (c *conn) IsIdle() bool { + return atomic.LoadInt32(&c.idle) > 0 +} + +func (c *conn) SetIdle(idle bool) { + v := int32(0) + if idle { + v = 1 + } + atomic.StoreInt32(&c.idle, v) +} + +func (c *conn) WriteQueue(b []byte) error { + select { + case c.rc <- b: + return nil + + case <-c.closed: + return net.ErrClosed + + default: + return errors.New("recv queue is full") + } +} diff --git a/internal/net/udp/pool.go b/internal/net/udp/pool.go new file mode 100644 index 0000000..232d03d --- /dev/null +++ b/internal/net/udp/pool.go @@ -0,0 +1,115 @@ +package udp + +import ( + "sync" + "time" + + "github.com/go-gost/core/logger" +) + +type connPool struct { + m sync.Map + ttl time.Duration + closed chan struct{} + logger logger.Logger +} + +func newConnPool(ttl time.Duration) *connPool { + p := &connPool{ + ttl: ttl, + closed: make(chan struct{}), + } + go p.idleCheck() + return p +} + +func (p *connPool) WithLogger(logger logger.Logger) *connPool { + p.logger = logger + return p +} + +func (p *connPool) Get(key any) (c *conn, ok bool) { + if p == nil { + return + } + + v, ok := p.m.Load(key) + if ok { + c, ok = v.(*conn) + } + return +} + +func (p *connPool) Set(key any, c *conn) { + if p == nil { + return + } + + p.m.Store(key, c) +} + +func (p *connPool) Delete(key any) { + if p == nil { + return + } + p.m.Delete(key) +} + +func (p *connPool) Close() { + if p == nil { + return + } + + select { + case <-p.closed: + return + default: + } + + close(p.closed) + + p.m.Range(func(k, v any) bool { + if c, ok := v.(*conn); ok && c != nil { + c.Close() + } + return true + }) +} + +func (p *connPool) idleCheck() { + ticker := time.NewTicker(p.ttl) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + size := 0 + idles := 0 + p.m.Range(func(key, value any) bool { + c, ok := value.(*conn) + if !ok || c == nil { + p.Delete(key) + return true + } + size++ + + if c.IsIdle() { + idles++ + p.Delete(key) + c.Close() + return true + } + + c.SetIdle(true) + + return true + }) + + if idles > 0 { + p.logger.Debugf("connection pool: size=%d, idle=%d", size, idles) + } + case <-p.closed: + return + } + } +} diff --git a/listener/ftcp/listener.go b/listener/ftcp/listener.go index 957d793..58dc3c4 100644 --- a/listener/ftcp/listener.go +++ b/listener/ftcp/listener.go @@ -3,12 +3,12 @@ package ftcp import ( "net" - "github.com/go-gost/core/common/net/udp" "github.com/go-gost/core/listener" "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" admission "github.com/go-gost/x/admission/wrapper" xnet "github.com/go-gost/x/internal/net" + "github.com/go-gost/x/internal/net/udp" limiter "github.com/go-gost/x/limiter/traffic/wrapper" metrics "github.com/go-gost/x/metrics/wrapper" stats "github.com/go-gost/x/observer/stats/wrapper" diff --git a/listener/redirect/udp/listener_linux.go b/listener/redirect/udp/listener_linux.go index ba2b779..3b0cfce 100644 --- a/listener/redirect/udp/listener_linux.go +++ b/listener/redirect/udp/listener_linux.go @@ -108,7 +108,7 @@ func (l *redirectListener) accept() (conn net.Conn, err error) { // Out-of-band data is also read in so that the original destination // address can be identified and parsed. func readFromUDP(conn *net.UDPConn, b []byte) (n int, remoteAddr *net.UDPAddr, dstAddr *net.UDPAddr, err error) { - oob := bufpool.Get(1024) + oob := bufpool.Get(8192) defer bufpool.Put(oob) n, oobn, _, remoteAddr, err := conn.ReadMsgUDP(b, oob) @@ -118,14 +118,14 @@ func readFromUDP(conn *net.UDPConn, b []byte) (n int, remoteAddr *net.UDPAddr, d msgs, err := unix.ParseSocketControlMessage(oob[:oobn]) if err != nil { - return 0, nil, nil, fmt.Errorf("parsing socket control message: %s", err) + return 0, nil, nil, fmt.Errorf("parsing socket control message: %v", err) } for _, msg := range msgs { if msg.Header.Level == unix.SOL_IP && msg.Header.Type == unix.IP_RECVORIGDSTADDR { originalDstRaw := &unix.RawSockaddrInet4{} if err = binary.Read(bytes.NewReader(msg.Data), binary.LittleEndian, originalDstRaw); err != nil { - return 0, nil, nil, fmt.Errorf("reading original destination address: %s", err) + return 0, nil, nil, fmt.Errorf("reading original destination address: %v", err) } switch originalDstRaw.Family { @@ -154,7 +154,7 @@ func readFromUDP(conn *net.UDPConn, b []byte) (n int, remoteAddr *net.UDPAddr, d } if dstAddr == nil { - return 0, nil, nil, fmt.Errorf("unable to obtain original destination: %s", err) + return 0, nil, nil, fmt.Errorf("unable to obtain original destination: %v", err) } return @@ -166,50 +166,50 @@ func readFromUDP(conn *net.UDPConn, b []byte) (n int, remoteAddr *net.UDPAddr, d func dialUDP(network string, laddr *net.UDPAddr, raddr *net.UDPAddr) (net.Conn, error) { remoteSocketAddress, err := udpAddrToSocketAddr(raddr) if err != nil { - return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("build destination socket address: %s", err)} + return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("build destination socket address: %v", err)} } localSocketAddress, err := udpAddrToSocketAddr(laddr) if err != nil { - return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("build local socket address: %s", err)} + return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("build local socket address: %v", err)} } fileDescriptor, err := unix.Socket(udpAddrFamily(network, laddr, raddr), unix.SOCK_DGRAM, 0) if err != nil { - return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("socket open: %s", err)} + return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("socket open: %v", err)} } if err = unix.SetsockoptInt(fileDescriptor, unix.SOL_IP, unix.IP_TRANSPARENT, 1); err != nil { unix.Close(fileDescriptor) - return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("set socket option: IP_TRANSPARENT: %s", err)} + return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("set socket option: IP_TRANSPARENT: %v", err)} } if err = unix.SetsockoptInt(fileDescriptor, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil { unix.Close(fileDescriptor) - return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("set socket option: SO_REUSEADDR: %s", err)} + return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("set socket option: SO_REUSEADDR: %v", err)} } if err = unix.SetsockoptInt(fileDescriptor, unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil { unix.Close(fileDescriptor) - return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("set socket option: SO_REUSEPORT: %s", err)} + return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("set socket option: SO_REUSEPORT: %v", err)} } if err = unix.Bind(fileDescriptor, localSocketAddress); err != nil { unix.Close(fileDescriptor) - return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("socket bind %v: %s", laddr, err)} + return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("socket bind %v: %v", laddr, err)} } if err = unix.Connect(fileDescriptor, remoteSocketAddress); err != nil { unix.Close(fileDescriptor) - return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("socket connect: %s", err)} + return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("socket connect: %v", err)} } - fdFile := os.NewFile(uintptr(fileDescriptor), fmt.Sprintf("net-udp-dial-%s", raddr.String())) + fdFile := os.NewFile(uintptr(fileDescriptor), fmt.Sprintf("net-udp-dial-%v", raddr.String())) defer fdFile.Close() remoteConn, err := net.FileConn(fdFile) if err != nil { unix.Close(fileDescriptor) - return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("convert file descriptor to connection: %s", err)} + return nil, &net.OpError{Op: "dial", Err: fmt.Errorf("convert file descriptor to connection: %v", err)} } return remoteConn, nil diff --git a/listener/rtcp/listener.go b/listener/rtcp/listener.go index d553089..564c267 100644 --- a/listener/rtcp/listener.go +++ b/listener/rtcp/listener.go @@ -25,7 +25,6 @@ func init() { type rtcpListener struct { laddr net.Addr ln net.Listener - router *chain.Router logger logger.Logger closed chan struct{} options listener.Options @@ -60,11 +59,6 @@ func (l *rtcpListener) Init(md md.Metadata) (err error) { l.laddr = &bindAddr{addr: l.options.Addr} } - l.router = l.options.Router - if l.router == nil { - l.router = chain.NewRouter(chain.LoggerRouterOption(l.logger)) - } - return } @@ -77,7 +71,7 @@ func (l *rtcpListener) Accept() (conn net.Conn, err error) { ln := l.getListener() if ln == nil { - ln, err = l.router.Bind( + ln, err = l.options.Router.Bind( context.Background(), "tcp", l.laddr.String(), chain.MuxBindOption(true), ) diff --git a/listener/rudp/listener.go b/listener/rudp/listener.go index 8d9e310..b98bb64 100644 --- a/listener/rudp/listener.go +++ b/listener/rudp/listener.go @@ -24,7 +24,6 @@ func init() { type rudpListener struct { laddr net.Addr ln net.Listener - router *chain.Router closed chan struct{} logger logger.Logger md metadata @@ -60,11 +59,6 @@ func (l *rudpListener) Init(md md.Metadata) (err error) { l.laddr = &bindAddr{addr: l.options.Addr} } - l.router = l.options.Router - if l.router == nil { - l.router = chain.NewRouter(chain.LoggerRouterOption(l.logger)) - } - return } @@ -77,7 +71,7 @@ func (l *rudpListener) Accept() (conn net.Conn, err error) { ln := l.getListener() if ln == nil { - ln, err = l.router.Bind( + ln, err = l.options.Router.Bind( context.Background(), "udp", l.laddr.String(), chain.BacklogBindOption(l.md.backlog), chain.UDPConnTTLBindOption(l.md.ttl), diff --git a/listener/udp/listener.go b/listener/udp/listener.go index d437a3c..d74c7a1 100644 --- a/listener/udp/listener.go +++ b/listener/udp/listener.go @@ -3,12 +3,12 @@ package udp import ( "net" - "github.com/go-gost/core/common/net/udp" "github.com/go-gost/core/listener" "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" admission "github.com/go-gost/x/admission/wrapper" xnet "github.com/go-gost/x/internal/net" + "github.com/go-gost/x/internal/net/udp" limiter "github.com/go-gost/x/limiter/traffic/wrapper" metrics "github.com/go-gost/x/metrics/wrapper" stats "github.com/go-gost/x/observer/stats/wrapper" diff --git a/resolver/exchanger/exchanger.go b/resolver/exchanger/exchanger.go index 105fc7c..ce9ccf0 100644 --- a/resolver/exchanger/exchanger.go +++ b/resolver/exchanger/exchanger.go @@ -14,11 +14,12 @@ import ( "github.com/go-gost/core/chain" "github.com/go-gost/core/logger" + xchain "github.com/go-gost/x/chain" "github.com/miekg/dns" ) type Options struct { - router *chain.Router + router chain.Router tlsConfig *tls.Config timeout time.Duration logger logger.Logger @@ -28,7 +29,7 @@ type Options struct { type Option func(opts *Options) // RouterOption sets the router for Exchanger. -func RouterOption(router *chain.Router) Option { +func RouterOption(router chain.Router) Option { return func(opts *Options) { opts.router = router } @@ -65,7 +66,7 @@ type exchanger struct { network string addr string rawAddr string - router *chain.Router + router chain.Router client *http.Client options Options } @@ -102,7 +103,7 @@ func NewExchanger(addr string, opts ...Option) (Exchanger, error) { ex.addr = net.JoinHostPort(ex.addr, "53") } if ex.router == nil { - ex.router = chain.NewRouter(chain.LoggerRouterOption(options.logger)) + ex.router = xchain.NewRouter(chain.LoggerRouterOption(options.logger)) } switch ex.network { diff --git a/resolver/resolver.go b/resolver/resolver.go index 6319149..5e2b658 100644 --- a/resolver/resolver.go +++ b/resolver/resolver.go @@ -9,6 +9,7 @@ import ( "github.com/go-gost/core/chain" "github.com/go-gost/core/logger" "github.com/go-gost/core/resolver" + xchain "github.com/go-gost/x/chain" resolver_util "github.com/go-gost/x/internal/util/resolver" "github.com/go-gost/x/resolver/exchanger" "github.com/miekg/dns" @@ -67,7 +68,7 @@ func NewResolver(nameservers []NameServer, opts ...Option) (resolver.Resolver, e ex, err := exchanger.NewExchanger( addr, exchanger.RouterOption( - chain.NewRouter( + xchain.NewRouter( chain.ChainRouterOption(server.Chain), chain.LoggerRouterOption(options.logger), ), @@ -165,7 +166,7 @@ func (r *localResolver) resolveAsync(ctx context.Context, server *NameServer, ho return } -func (r *localResolver) lookupCache(ctx context.Context, server *NameServer, host string) (ips []net.IP, ttl time.Duration, ok bool) { +func (r *localResolver) lookupCache(_ context.Context, server *NameServer, host string) (ips []net.IP, ttl time.Duration, ok bool) { lookup := func(t uint16, host string) (ips []net.IP, ttl time.Duration, ok bool) { mq := dns.Msg{} mq.SetQuestion(dns.Fqdn(host), t)