diff --git a/api/config.go b/api/config.go index 0bfab47..996bd31 100644 --- a/api/config.go +++ b/api/config.go @@ -7,10 +7,10 @@ import ( "os" "github.com/gin-gonic/gin" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/x/config" "github.com/go-gost/x/registry" "github.com/go-gost/x/service" - "github.com/go-gost/x/stats" ) type serviceStatus interface { diff --git a/config/config.go b/config/config.go index c97dfa8..6bb586f 100644 --- a/config/config.go +++ b/config/config.go @@ -487,6 +487,7 @@ type HopConfig struct { Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"` HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"` Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"` + Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"` } type NodeConfig struct { @@ -500,6 +501,7 @@ type NodeConfig struct { Connector *ConnectorConfig `yaml:",omitempty" json:"connector,omitempty"` Dialer *DialerConfig `yaml:",omitempty" json:"dialer,omitempty"` Interface string `yaml:",omitempty" json:"interface,omitempty"` + Netns string `yaml:",omitempty" json:"netns,omitempty"` SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"` Filter *NodeFilterConfig `yaml:",omitempty" json:"filter,omitempty"` HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"` diff --git a/config/parsing/hop/parse.go b/config/parsing/hop/parse.go index 3fb9dc5..d435479 100644 --- a/config/parsing/hop/parse.go +++ b/config/parsing/hop/parse.go @@ -8,7 +8,9 @@ import ( "github.com/go-gost/core/chain" "github.com/go-gost/core/hop" "github.com/go-gost/core/logger" + mdutil "github.com/go-gost/core/metadata/util" "github.com/go-gost/x/config" + "github.com/go-gost/x/config/parsing" bypass_parser "github.com/go-gost/x/config/parsing/bypass" node_parser "github.com/go-gost/x/config/parsing/node" selector_parser "github.com/go-gost/x/config/parsing/selector" @@ -16,6 +18,7 @@ import ( hop_plugin "github.com/go-gost/x/hop/plugin" "github.com/go-gost/x/internal/loader" "github.com/go-gost/x/internal/plugin" + "github.com/go-gost/x/metadata" ) func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) { @@ -47,6 +50,16 @@ func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) { } } + ifce := cfg.Interface + var netns string + if cfg.Metadata != nil { + md := metadata.NewMetadata(cfg.Metadata) + if v := mdutil.GetString(md, parsing.MDKeyInterface); v != "" { + ifce = v + } + netns = mdutil.GetString(md, "netns") + } + var nodes []*chain.Node for _, v := range cfg.Nodes { if v == nil { @@ -60,8 +73,12 @@ func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) { v.Hosts = cfg.Hosts } if v.Interface == "" { - v.Interface = cfg.Interface + v.Interface = ifce } + if v.Netns == "" { + v.Netns = netns + } + if v.SockOpts == nil { v.SockOpts = cfg.SockOpts } diff --git a/config/parsing/node/parse.go b/config/parsing/node/parse.go index e91df94..af99d07 100644 --- a/config/parsing/node/parse.go +++ b/config/parsing/node/parse.go @@ -5,7 +5,6 @@ import ( "net" "regexp" "strings" - "time" "github.com/go-gost/core/bypass" "github.com/go-gost/core/chain" @@ -143,8 +142,8 @@ func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.No tr := chain.NewTransport(d, cr, chain.AddrTransportOption(cfg.Addr), chain.InterfaceTransportOption(cfg.Interface), + chain.NetnsTransportOption(cfg.Netns), chain.SockOptsTransportOption(sockOpts), - chain.TimeoutTransportOption(10*time.Second), ) opts := []chain.NodeOption{ diff --git a/config/parsing/service/parse.go b/config/parsing/service/parse.go index 3554256..f454a87 100644 --- a/config/parsing/service/parse.go +++ b/config/parsing/service/parse.go @@ -2,6 +2,7 @@ package service import ( "fmt" + "runtime" "strings" "time" @@ -14,6 +15,7 @@ import ( "github.com/go-gost/core/listener" "github.com/go-gost/core/logger" mdutil "github.com/go-gost/core/metadata/util" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/core/recorder" "github.com/go-gost/core/selector" "github.com/go-gost/core/service" @@ -31,7 +33,7 @@ import ( "github.com/go-gost/x/metadata" "github.com/go-gost/x/registry" xservice "github.com/go-gost/x/service" - "github.com/go-gost/x/stats" + "github.com/vishvananda/netns" ) func ParseService(cfg *config.ServiceConfig) (service.Service, error) { @@ -61,17 +63,13 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { "handler": cfg.Handler.Type, }) - listenerLogger := serviceLogger.WithFields(map[string]any{ - "kind": "listener", - }) - tlsCfg := cfg.Listener.TLS if tlsCfg == nil { tlsCfg = &config.TLSConfig{} } tlsConfig, err := tls_util.LoadServerConfig(tlsCfg) if err != nil { - listenerLogger.Error(err) + serviceLogger.Error(err) return nil, err } if tlsConfig == nil { @@ -104,6 +102,8 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { var ignoreChain bool var pStats *stats.Stats var observePeriod time.Duration + var netnsIn, netnsOut string + var dialTimeout time.Duration if cfg.Metadata != nil { md := metadata.NewMetadata(cfg.Metadata) ppv = mdutil.GetInt(md, parsing.MDKeyProxyProtocol) @@ -125,25 +125,65 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { pStats = &stats.Stats{} } observePeriod = mdutil.GetDuration(md, "observePeriod") + netnsIn = mdutil.GetString(md, "netns") + netnsOut = mdutil.GetString(md, "netns.out") + dialTimeout = mdutil.GetDuration(md, "dialTimeout") + } + + listenerLogger := serviceLogger.WithFields(map[string]any{ + "kind": "listener", + }) + + routerOpts := []chain.RouterOption{ + chain.TimeoutRouterOption(dialTimeout), + chain.InterfaceRouterOption(ifce), + chain.NetnsRouterOption(netnsOut), + chain.SockOptsRouterOption(sockOpts), + chain.ResolverRouterOption(registry.ResolverRegistry().Get(cfg.Resolver)), + chain.HostMapperRouterOption(registry.HostsRegistry().Get(cfg.Hosts)), + chain.LoggerRouterOption(listenerLogger), + } + if !ignoreChain { + routerOpts = append(routerOpts, + chain.ChainRouterOption(chainGroup(cfg.Listener.Chain, cfg.Listener.ChainGroup)), + ) } listenOpts := []listener.Option{ listener.AddrOption(cfg.Addr), + listener.RouterOption(chain.NewRouter(routerOpts...)), listener.AutherOption(auther), listener.AuthOption(auth_parser.Info(cfg.Listener.Auth)), listener.TLSConfigOption(tlsConfig), listener.AdmissionOption(admission.AdmissionGroup(admissions...)), listener.TrafficLimiterOption(registry.TrafficLimiterRegistry().Get(cfg.Limiter)), listener.ConnLimiterOption(registry.ConnLimiterRegistry().Get(cfg.CLimiter)), - listener.LoggerOption(listenerLogger), listener.ServiceOption(cfg.Name), listener.ProxyProtocolOption(ppv), listener.StatsOption(pStats), + listener.NetnsOption(netnsIn), + listener.LoggerOption(listenerLogger), } - if !ignoreChain { - listenOpts = append(listenOpts, - listener.ChainOption(chainGroup(cfg.Listener.Chain, cfg.Listener.ChainGroup)), - ) + + if netnsIn != "" { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + originNs, err := netns.Get() + if err != nil { + return nil, fmt.Errorf("netns.Get(): %v", err) + } + defer netns.Set(originNs) + + ns, err := netns.GetFromName(netnsIn) + if err != nil { + return nil, fmt.Errorf("netns.GetFromName(%s): %v", netnsIn, err) + } + defer ns.Close() + + if err := netns.Set(ns); err != nil { + return nil, fmt.Errorf("netns.Set(%s): %v", netnsIn, err) + } } var ln listener.Listener @@ -205,10 +245,11 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { }) } - routerOpts := []chain.RouterOption{ + routerOpts = []chain.RouterOption{ chain.RetriesRouterOption(cfg.Handler.Retries), - // chain.TimeoutRouterOption(10*time.Second), + chain.TimeoutRouterOption(dialTimeout), chain.InterfaceRouterOption(ifce), + chain.NetnsRouterOption(netnsOut), chain.SockOptsRouterOption(sockOpts), chain.ResolverRouterOption(registry.ResolverRegistry().Get(cfg.Resolver)), chain.HostMapperRouterOption(registry.HostsRegistry().Get(cfg.Hosts)), @@ -220,12 +261,11 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { chain.ChainRouterOption(chainGroup(cfg.Handler.Chain, cfg.Handler.ChainGroup)), ) } - router := chain.NewRouter(routerOpts...) var h handler.Handler if rf := registry.HandlerRegistry().Get(cfg.Handler.Type); rf != nil { h = rf( - handler.RouterOption(router), + handler.RouterOption(chain.NewRouter(routerOpts...)), handler.AutherOption(auther), handler.AuthOption(auth_parser.Info(cfg.Handler.Auth)), handler.BypassOption(bypass.BypassGroup(bypass_parser.List(cfg.Bypass, cfg.Bypasses...)...)), @@ -235,6 +275,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) { handler.ObserverOption(registry.ObserverRegistry().Get(cfg.Handler.Observer)), handler.LoggerOption(handlerLogger), handler.ServiceOption(cfg.Name), + handler.NetnsOption(netnsIn), ) } else { return nil, fmt.Errorf("unknown handler: %s", cfg.Handler.Type) diff --git a/connector/direct/connector.go b/connector/direct/connector.go index 4dd0b10..e3ffd41 100644 --- a/connector/direct/connector.go +++ b/connector/direct/connector.go @@ -44,9 +44,17 @@ func (c *directConnector) Connect(ctx context.Context, _ net.Conn, network, addr return nil, err } + var localAddr, remoteAddr string + if addr := conn.LocalAddr(); addr != nil { + localAddr = addr.String() + } + if addr := conn.RemoteAddr(); addr != nil { + remoteAddr = addr.String() + } + log := c.options.Logger.WithFields(map[string]any{ - "remote": conn.RemoteAddr().String(), - "local": conn.LocalAddr().String(), + "remote": remoteAddr, + "local": localAddr, "network": network, "address": address, }) diff --git a/connector/socks/v5/conn.go b/connector/socks/v5/conn.go index da0552f..933a1f2 100644 --- a/connector/socks/v5/conn.go +++ b/connector/socks/v5/conn.go @@ -69,6 +69,10 @@ func (c *udpRelayConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { if err = socksAddr.ParseFrom(addr.String()); err != nil { return } + if socksAddr.Host == "" { + socksAddr.Type = gosocks5.AddrIPv4 + socksAddr.Host = "127.0.0.1" + } header := gosocks5.UDPHeader{ Addr: &socksAddr, diff --git a/connector/socks/v5/connector.go b/connector/socks/v5/connector.go index 0f69650..5844708 100644 --- a/connector/socks/v5/connector.go +++ b/connector/socks/v5/connector.go @@ -130,6 +130,10 @@ func (c *socks5Connector) Connect(ctx context.Context, conn net.Conn, network, a log.Error(err) return nil, err } + if addr.Host == "" { + addr.Type = gosocks5.AddrIPv4 + addr.Host = "127.0.0.1" + } req := gosocks5.NewRequest(gosocks5.CmdConnect, &addr) log.Trace(req) @@ -201,12 +205,12 @@ func (c *socks5Connector) relayUDP(ctx context.Context, conn net.Conn, addr net. } log.Trace(reply) - log.Debugf("bind on: %v", reply.Addr) - if reply.Rep != gosocks5.Succeeded { return nil, errors.New("get socks5 UDP tunnel failure") } + log.Debugf("bind on: %v", reply.Addr) + cc, err := opts.NetDialer.Dial(ctx, "udp", reply.Addr.String()) if err != nil { return nil, err diff --git a/dialer/icmp/dialer.go b/dialer/icmp/dialer.go index dde1d11..85a5385 100644 --- a/dialer/icmp/dialer.go +++ b/dialer/icmp/dialer.go @@ -115,7 +115,7 @@ func (d *icmpDialer) initSession(ctx context.Context, addr net.Addr, conn net.Pa } tlsCfg := d.options.TLSConfig - tlsCfg.NextProtos = []string{"http/3", "quic/v1"} + tlsCfg.NextProtos = []string{"h3", "quic/v1"} session, err := quic.DialEarly(ctx, conn, addr, tlsCfg, quicConfig) if err != nil { diff --git a/dialer/quic/dialer.go b/dialer/quic/dialer.go index 381f5bf..c43f2ef 100644 --- a/dialer/quic/dialer.go +++ b/dialer/quic/dialer.go @@ -114,7 +114,7 @@ func (d *quicDialer) initSession(ctx context.Context, addr net.Addr, conn net.Pa } tlsCfg := d.options.TLSConfig - tlsCfg.NextProtos = []string{"http/3", "quic/v1"} + tlsCfg.NextProtos = []string{"h3", "quic/v1"} session, err := quic.DialEarly(ctx, conn, addr, tlsCfg, quicConfig) if err != nil { diff --git a/dialer/wg/dialer.go b/dialer/wg/dialer.go new file mode 100644 index 0000000..33ac93e --- /dev/null +++ b/dialer/wg/dialer.go @@ -0,0 +1,48 @@ +package wg + +import ( + "context" + "net" + + "github.com/go-gost/core/dialer" + "github.com/go-gost/core/logger" + md "github.com/go-gost/core/metadata" + "github.com/go-gost/x/registry" +) + +func init() { + registry.DialerRegistry().Register("wg", NewDialer) +} + +type wgDialer struct { + md metadata + logger logger.Logger +} + +func NewDialer(opts ...dialer.Option) dialer.Dialer { + options := &dialer.Options{} + for _, opt := range opts { + opt(options) + } + + return &wgDialer{ + logger: options.Logger, + } +} + +func (d *wgDialer) Init(md md.Metadata) (err error) { + return d.parseMetadata(md) +} + +func (d *wgDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) { + var options dialer.DialOptions + for _, opt := range opts { + opt(&options) + } + + conn, err := options.NetDialer.Dial(ctx, "tcp", addr) + if err != nil { + d.logger.Error(err) + } + return conn, err +} diff --git a/dialer/wg/metadata.go b/dialer/wg/metadata.go new file mode 100644 index 0000000..db192db --- /dev/null +++ b/dialer/wg/metadata.go @@ -0,0 +1,23 @@ +package wg + +import ( + "time" + + md "github.com/go-gost/core/metadata" +) + +const ( + dialTimeout = "dialTimeout" +) + +const ( + defaultDialTimeout = 5 * time.Second +) + +type metadata struct { + dialTimeout time.Duration +} + +func (d *wgDialer) parseMetadata(md md.Metadata) (err error) { + return +} diff --git a/go.mod b/go.mod index 5752105..356544b 100644 --- a/go.mod +++ b/go.mod @@ -9,9 +9,9 @@ require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/gin-contrib/cors v1.5.0 github.com/gin-gonic/gin v1.9.1 - github.com/go-gost/core v0.0.0-20240508132029-8d554ddcf77c + github.com/go-gost/core v0.0.0-20240704150322-30cc92870515 github.com/go-gost/gosocks4 v0.0.1 - github.com/go-gost/gosocks5 v0.4.0 + github.com/go-gost/gosocks5 v0.4.2 github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a github.com/go-gost/relay v0.5.0 github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451 @@ -35,6 +35,7 @@ require ( github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 github.com/spf13/viper v1.18.2 github.com/vishvananda/netlink v1.1.0 + github.com/vishvananda/netns v0.0.4 github.com/xtaci/kcp-go/v5 v5.6.5 github.com/xtaci/smux v1.5.24 github.com/xtaci/tcpraw v1.2.25 @@ -106,7 +107,6 @@ require ( github.com/tjfoc/gmsm v1.4.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect - github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.6.0 // indirect diff --git a/go.sum b/go.sum index 23e313b..0191175 100644 --- a/go.sum +++ b/go.sum @@ -53,12 +53,12 @@ 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-20240508132029-8d554ddcf77c h1:1ahtn+3bQB50at5ubWDOrA4yja8vWpWNrGSRaCztNWg= -github.com/go-gost/core v0.0.0-20240508132029-8d554ddcf77c/go.mod h1:j08tDHkFzk7dfOeLhl3RWsASdf9YWWRfWBUQqbQvx3A= +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/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.0 h1:EIrOEkpJez4gwHrMa33frA+hHXJyevjp47thpMQsJzI= -github.com/go-gost/gosocks5 v0.4.0/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4= +github.com/go-gost/gosocks5 v0.4.2 h1:IianxHTkACPqCwiOAT3MHoMdSUl+SEPSRu1ikawC1Pc= +github.com/go-gost/gosocks5 v0.4.2/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4= github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a h1:ME7P1Brcg4C640DSPqlvQr7JuvvQfJ8QpmS3yCFlK3A= github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a/go.mod h1:qXr2Zm9Ex2ATqnWuNUzVZqySPMnuIihvblYZt4MlZLw= github.com/go-gost/relay v0.5.0 h1:JG1tgy/KWiVXS0ukuVXvbM0kbYuJTWxYpJ5JwzsCf/c= @@ -242,8 +242,9 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/xtaci/kcp-go/v5 v5.6.5 h1:oxGZNobj3OddrLzwdJYnR/waNgwrL98u02u0DWNHE3k= github.com/xtaci/kcp-go/v5 v5.6.5/go.mod h1:Qy3Zf2tWTdFdEs0E8JvhrX+39r5UDZoYac8anvud7/Q= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM= diff --git a/handler/http/handler.go b/handler/http/handler.go index 0473e22..30efe32 100644 --- a/handler/http/handler.go +++ b/handler/http/handler.go @@ -23,13 +23,13 @@ import ( traffic "github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" + "github.com/go-gost/core/observer/stats" ctxvalue "github.com/go-gost/x/ctx" netpkg "github.com/go-gost/x/internal/net" stats_util "github.com/go-gost/x/internal/util/stats" traffic_wrapper "github.com/go-gost/x/limiter/traffic/wrapper" + stats_wrapper "github.com/go-gost/x/observer/stats/wrapper" "github.com/go-gost/x/registry" - "github.com/go-gost/x/stats" - stats_wrapper "github.com/go-gost/x/stats/wrapper" ) func init() { @@ -161,14 +161,19 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt log.Debugf("%s >> %s", conn.RemoteAddr(), addr) resp := &http.Response{ - ProtoMajor: 1, - ProtoMinor: 1, - Header: h.md.header, + ProtoMajor: 1, + ProtoMinor: 1, + Header: h.md.header, + ContentLength: -1, } if resp.Header == nil { resp.Header = http.Header{} } + if resp.Header.Get("Proxy-Agent") == "" { + resp.Header.Set("Proxy-Agent", h.md.proxyAgent) + } + clientID, ok := h.authenticate(ctx, conn, req, resp, log) if !ok { return nil diff --git a/handler/http/metadata.go b/handler/http/metadata.go index 4f7b4e1..2ea951f 100644 --- a/handler/http/metadata.go +++ b/handler/http/metadata.go @@ -10,7 +10,8 @@ import ( ) const ( - defaultRealm = "gost" + defaultRealm = "gost" + defaultProxyAgent = "gost/3.0" ) type metadata struct { @@ -20,6 +21,7 @@ type metadata struct { hash string authBasicRealm string observePeriod time.Duration + proxyAgent string } func (h *httpHandler) parseMetadata(md mdata.Metadata) error { @@ -46,6 +48,11 @@ func (h *httpHandler) parseMetadata(md mdata.Metadata) error { h.md.observePeriod = mdutil.GetDuration(md, "observePeriod") + h.md.proxyAgent = mdutil.GetString(md, "http.proxyAgent", "proxyAgent") + if h.md.proxyAgent == "" { + h.md.proxyAgent = defaultProxyAgent + } + return nil } diff --git a/handler/http2/handler.go b/handler/http2/handler.go index b7f94c9..d95b029 100644 --- a/handler/http2/handler.go +++ b/handler/http2/handler.go @@ -23,14 +23,14 @@ import ( "github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" + "github.com/go-gost/core/observer/stats" ctxvalue "github.com/go-gost/x/ctx" xio "github.com/go-gost/x/internal/io" netpkg "github.com/go-gost/x/internal/net" stats_util "github.com/go-gost/x/internal/util/stats" "github.com/go-gost/x/limiter/traffic/wrapper" + stats_wrapper "github.com/go-gost/x/observer/stats/wrapper" "github.com/go-gost/x/registry" - "github.com/go-gost/x/stats" - stats_wrapper "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/handler/relay/bind.go b/handler/relay/bind.go index 459daa1..807655f 100644 --- a/handler/relay/bind.go +++ b/handler/relay/bind.go @@ -10,6 +10,7 @@ import ( "github.com/go-gost/core/listener" "github.com/go-gost/core/logger" "github.com/go-gost/relay" + xnet "github.com/go-gost/x/internal/net" "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" @@ -50,7 +51,10 @@ func (h *relayHandler) bindTCP(ctx context.Context, conn net.Conn, network, addr Status: relay.StatusOK, } - ln, err := net.Listen(network, address) // strict mode: if the port already in use, it will return error + lc := xnet.ListenConfig{ + Netns: h.options.Netns, + } + ln, err := lc.Listen(ctx, network, address) // strict mode: if the port already in use, it will return error if err != nil { log.Error(err) resp.Status = relay.StatusServiceUnavailable @@ -129,10 +133,10 @@ func (h *relayHandler) bindUDP(ctx context.Context, conn net.Conn, network, addr Status: relay.StatusOK, } - var pc net.PacketConn - var err error - bindAddr, _ := net.ResolveUDPAddr(network, address) - pc, err = net.ListenUDP(network, bindAddr) + lc := xnet.ListenConfig{ + Netns: h.options.Netns, + } + pc, err := lc.ListenPacket(ctx, network, address) if err != nil { log.Error(err) return err diff --git a/handler/relay/connect.go b/handler/relay/connect.go index 7b08bca..2fae3be 100644 --- a/handler/relay/connect.go +++ b/handler/relay/connect.go @@ -10,13 +10,13 @@ import ( "github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/logger" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/relay" ctxvalue "github.com/go-gost/x/ctx" xnet "github.com/go-gost/x/internal/net" serial "github.com/go-gost/x/internal/util/serial" "github.com/go-gost/x/limiter/traffic/wrapper" - "github.com/go-gost/x/stats" - stats_wrapper "github.com/go-gost/x/stats/wrapper" + stats_wrapper "github.com/go-gost/x/observer/stats/wrapper" ) func (h *relayHandler) handleConnect(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) (err error) { diff --git a/handler/relay/forward.go b/handler/relay/forward.go index 6d309c7..8074c55 100644 --- a/handler/relay/forward.go +++ b/handler/relay/forward.go @@ -9,12 +9,12 @@ import ( "github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/logger" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/relay" ctxvalue "github.com/go-gost/x/ctx" netpkg "github.com/go-gost/x/internal/net" "github.com/go-gost/x/limiter/traffic/wrapper" - "github.com/go-gost/x/stats" - stats_wrapper "github.com/go-gost/x/stats/wrapper" + stats_wrapper "github.com/go-gost/x/observer/stats/wrapper" ) func (h *relayHandler) handleForward(ctx context.Context, conn net.Conn, network string, log logger.Logger) error { diff --git a/handler/socks/v4/handler.go b/handler/socks/v4/handler.go index 53d274c..ee67332 100644 --- a/handler/socks/v4/handler.go +++ b/handler/socks/v4/handler.go @@ -11,14 +11,14 @@ import ( "github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/gosocks4" ctxvalue "github.com/go-gost/x/ctx" netpkg "github.com/go-gost/x/internal/net" stats_util "github.com/go-gost/x/internal/util/stats" "github.com/go-gost/x/limiter/traffic/wrapper" + stats_wrapper "github.com/go-gost/x/observer/stats/wrapper" "github.com/go-gost/x/registry" - "github.com/go-gost/x/stats" - stats_wrapper "github.com/go-gost/x/stats/wrapper" ) var ( diff --git a/handler/socks/v5/bind.go b/handler/socks/v5/bind.go index ae37b40..6c7a798 100644 --- a/handler/socks/v5/bind.go +++ b/handler/socks/v5/bind.go @@ -9,6 +9,7 @@ import ( "github.com/go-gost/core/logger" "github.com/go-gost/gosocks5" netpkg "github.com/go-gost/x/internal/net" + xnet "github.com/go-gost/x/internal/net" ) func (h *socks5Handler) handleBind(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { @@ -31,7 +32,10 @@ func (h *socks5Handler) handleBind(ctx context.Context, conn net.Conn, network, } func (h *socks5Handler) bindLocal(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { - ln, err := net.Listen(network, address) // strict mode: if the port already in use, it will return error + lc := xnet.ListenConfig{ + Netns: h.options.Netns, + } + ln, err := lc.Listen(ctx, network, address) // strict mode: if the port already in use, it will return error if err != nil { log.Error(err) reply := gosocks5.NewReply(gosocks5.Failure, nil) @@ -95,7 +99,7 @@ func (h *socks5Handler) serveBind(ctx context.Context, conn net.Conn, ln net.Lis defer close(errc) defer pc1.Close() - errc <- netpkg.Transport(conn, pc1) + errc <- xnet.Transport(conn, pc1) }() return errc diff --git a/handler/socks/v5/connect.go b/handler/socks/v5/connect.go index 4384b54..1ba0d03 100644 --- a/handler/socks/v5/connect.go +++ b/handler/socks/v5/connect.go @@ -8,12 +8,12 @@ import ( "github.com/go-gost/core/limiter/traffic" "github.com/go-gost/core/logger" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/gosocks5" ctxvalue "github.com/go-gost/x/ctx" netpkg "github.com/go-gost/x/internal/net" "github.com/go-gost/x/limiter/traffic/wrapper" - "github.com/go-gost/x/stats" - stats_wrapper "github.com/go-gost/x/stats/wrapper" + stats_wrapper "github.com/go-gost/x/observer/stats/wrapper" ) func (h *socks5Handler) handleConnect(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { diff --git a/handler/socks/v5/mbind.go b/handler/socks/v5/mbind.go index 9038780..3c25bd2 100644 --- a/handler/socks/v5/mbind.go +++ b/handler/socks/v5/mbind.go @@ -8,7 +8,7 @@ import ( "github.com/go-gost/core/logger" "github.com/go-gost/gosocks5" - netpkg "github.com/go-gost/x/internal/net" + xnet "github.com/go-gost/x/internal/net" "github.com/go-gost/x/internal/util/mux" ) @@ -31,7 +31,10 @@ func (h *socks5Handler) handleMuxBind(ctx context.Context, conn net.Conn, networ } func (h *socks5Handler) muxBindLocal(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { - ln, err := net.Listen(network, address) // strict mode: if the port already in use, it will return error + lc := xnet.ListenConfig{ + Netns: h.options.Netns, + } + ln, err := lc.Listen(ctx, network, address) // strict mode: if the port already in use, it will return error if err != nil { log.Error(err) reply := gosocks5.NewReply(gosocks5.Failure, nil) @@ -125,7 +128,7 @@ func (h *socks5Handler) serveMuxBind(ctx context.Context, conn net.Conn, ln net. t := time.Now() log.Debugf("%s <-> %s", c.LocalAddr(), c.RemoteAddr()) - netpkg.Transport(sc, c) + xnet.Transport(sc, c) log.WithFields(map[string]any{"duration": time.Since(t)}). Debugf("%s >-< %s", c.LocalAddr(), c.RemoteAddr()) }(rc) diff --git a/handler/socks/v5/udp.go b/handler/socks/v5/udp.go index 709a899..d4405f9 100644 --- a/handler/socks/v5/udp.go +++ b/handler/socks/v5/udp.go @@ -9,12 +9,13 @@ import ( "time" "github.com/go-gost/core/logger" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/gosocks5" ctxvalue "github.com/go-gost/x/ctx" + xnet "github.com/go-gost/x/internal/net" "github.com/go-gost/x/internal/net/udp" "github.com/go-gost/x/internal/util/socks" - "github.com/go-gost/x/stats" - stats_wrapper "github.com/go-gost/x/stats/wrapper" + stats_wrapper "github.com/go-gost/x/observer/stats/wrapper" ) func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, log logger.Logger) error { @@ -29,7 +30,11 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, log logger return reply.Write(conn) } - cc, err := net.ListenUDP("udp", nil) + lc := xnet.ListenConfig{ + Netns: h.options.Netns, + } + laddr := &net.UDPAddr{IP: conn.LocalAddr().(*net.TCPAddr).IP, Port: 0} // use out-going interface's IP + cc, err := lc.ListenPacket(ctx, "udp", laddr.String()) if err != nil { log.Error(err) reply := gosocks5.NewReply(gosocks5.Failure, nil) @@ -41,8 +46,6 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, log logger saddr := gosocks5.Addr{} saddr.ParseFrom(cc.LocalAddr().String()) - saddr.Type = 0 - saddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) // replace the IP to the out-going interface's reply := gosocks5.NewReply(gosocks5.Succeeded, &saddr) log.Trace(reply) if err := reply.Write(conn); err != nil { @@ -70,17 +73,16 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, log logger return err } - var lc net.PacketConn = cc clientID := ctxvalue.ClientIDFromContext(ctx) if h.options.Observer != nil { pstats := h.stats.Stats(string(clientID)) pstats.Add(stats.KindTotalConns, 1) pstats.Add(stats.KindCurrentConns, 1) defer pstats.Add(stats.KindCurrentConns, -1) - lc = stats_wrapper.WrapPacketConn(lc, pstats) + cc = stats_wrapper.WrapPacketConn(cc, pstats) } - r := udp.NewRelay(socks.UDPConn(lc, h.md.udpBufferSize), pc). + r := udp.NewRelay(socks.UDPConn(cc, h.md.udpBufferSize), pc). WithBypass(h.options.Bypass). WithLogger(log) r.SetBufferSize(h.md.udpBufferSize) diff --git a/handler/socks/v5/udp_tun.go b/handler/socks/v5/udp_tun.go index 33242f4..7b99c6b 100644 --- a/handler/socks/v5/udp_tun.go +++ b/handler/socks/v5/udp_tun.go @@ -2,16 +2,18 @@ package v5 import ( "context" + "errors" "net" "time" "github.com/go-gost/core/logger" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/gosocks5" ctxvalue "github.com/go-gost/x/ctx" + xnet "github.com/go-gost/x/internal/net" "github.com/go-gost/x/internal/net/udp" "github.com/go-gost/x/internal/util/socks" - "github.com/go-gost/x/stats" - stats_wrapper "github.com/go-gost/x/stats/wrapper" + stats_wrapper "github.com/go-gost/x/observer/stats/wrapper" ) func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error { @@ -24,28 +26,52 @@ func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network bindAddr = &net.UDPAddr{} } + var pc net.PacketConn + // relay mode if bindAddr.Port == 0 { - // relay mode if !h.md.enableUDP { reply := gosocks5.NewReply(gosocks5.NotAllowed, nil) log.Trace(reply) log.Error("socks5: UDP relay is disabled") return reply.Write(conn) } - } else { - // BIND mode + + // obtain a udp connection + c, err := h.router.Dial(ctx, "udp", "") // UDP association + if err != nil { + log.Error(err) + return err + } + defer c.Close() + + var ok bool + pc, ok = c.(net.PacketConn) + if !ok { + err := errors.New("socks5: wrong connection type") + log.Error(err) + return err + } + + } else { // BIND mode if !h.md.enableBind { reply := gosocks5.NewReply(gosocks5.NotAllowed, nil) log.Trace(reply) log.Error("socks5: BIND is disabled") return reply.Write(conn) } - } - pc, err := net.ListenUDP(network, bindAddr) - if err != nil { - log.Error(err) - return err + lc := xnet.ListenConfig{ + Netns: h.options.Netns, + } + var err error + pc, err = lc.ListenPacket(ctx, "udp", bindAddr.String()) + if err != nil { + log.Error(err) + reply := gosocks5.NewReply(gosocks5.Failure, nil) + log.Trace(reply) + reply.Write(conn) + return err + } } defer pc.Close() diff --git a/internal/net/net.go b/internal/net/net.go index 364dafa..618552e 100644 --- a/internal/net/net.go +++ b/internal/net/net.go @@ -1,8 +1,13 @@ package net import ( + "context" + "fmt" "net" + "runtime" "syscall" + + "github.com/vishvananda/netns" ) type SetBuffer interface { @@ -26,3 +31,57 @@ type SetDSCP interface { func IsIPv4(address string) bool { return address != "" && address[0] != ':' && address[0] != '[' } + +type ListenConfig struct { + Netns string + net.ListenConfig +} + +func (lc *ListenConfig) Listen(ctx context.Context, network, address string) (net.Listener, error) { + if lc.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) + + ns, err := netns.GetFromName(lc.Netns) + if err != nil { + return nil, fmt.Errorf("netns.GetFromName(%s): %v", lc.Netns, err) + } + defer ns.Close() + + if err := netns.Set(ns); err != nil { + return nil, fmt.Errorf("netns.Set(%s): %v", lc.Netns, err) + } + } + + return lc.ListenConfig.Listen(ctx, network, address) +} + +func (lc *ListenConfig) ListenPacket(ctx context.Context, network, address string) (net.PacketConn, error) { + if lc.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) + + ns, err := netns.GetFromName(lc.Netns) + if err != nil { + return nil, fmt.Errorf("netns.GetFromName(%s): %v", lc.Netns, err) + } + defer ns.Close() + + if err := netns.Set(ns); err != nil { + return nil, fmt.Errorf("netns.Set(%s): %v", lc.Netns, err) + } + } + return lc.ListenConfig.ListenPacket(ctx, network, address) +} diff --git a/internal/util/stats/stats.go b/internal/util/stats/stats.go index 81d33c1..2219c1b 100644 --- a/internal/util/stats/stats.go +++ b/internal/util/stats/stats.go @@ -4,7 +4,7 @@ import ( "sync" "github.com/go-gost/core/observer" - "github.com/go-gost/x/stats" + "github.com/go-gost/core/observer/stats" ) type HandlerStats struct { diff --git a/internal/util/tls/tls.go b/internal/util/tls/tls.go index d7301ec..eef4fc8 100644 --- a/internal/util/tls/tls.go +++ b/internal/util/tls/tls.go @@ -3,7 +3,7 @@ package tls import ( "crypto/tls" "crypto/x509" - "errors" + "fmt" "net" "os" "strings" @@ -234,7 +234,7 @@ func loadCA(caFile string) (cp *x509.CertPool, err error) { return nil, err } if !cp.AppendCertsFromPEM(data) { - return nil, errors.New("AppendCertsFromPEM failed") + return nil, fmt.Errorf("loadCA %s: AppendCertsFromPEM failed", caFile) } return } diff --git a/listener/dns/listener.go b/listener/dns/listener.go index 42717b2..8f8ef17 100644 --- a/listener/dns/listener.go +++ b/listener/dns/listener.go @@ -16,8 +16,8 @@ import ( "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" metrics "github.com/go-gost/x/metrics/wrapper" + stats "github.com/go-gost/x/observer/stats/wrapper" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "github.com/miekg/dns" ) diff --git a/listener/dtls/listener.go b/listener/dtls/listener.go index 4675c21..228cf4d 100644 --- a/listener/dtls/listener.go +++ b/listener/dtls/listener.go @@ -16,8 +16,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "github.com/pion/dtls/v2" ) diff --git a/listener/ftcp/listener.go b/listener/ftcp/listener.go index eb25d2f..957d793 100644 --- a/listener/ftcp/listener.go +++ b/listener/ftcp/listener.go @@ -11,8 +11,8 @@ import ( xnet "github.com/go-gost/x/internal/net" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "github.com/xtaci/tcpraw" ) diff --git a/listener/grpc/listener.go b/listener/grpc/listener.go index fd5f7ae..1bf16d6 100644 --- a/listener/grpc/listener.go +++ b/listener/grpc/listener.go @@ -15,8 +15,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" diff --git a/listener/http2/h2/listener.go b/listener/http2/h2/listener.go index e01987f..aa2ad57 100644 --- a/listener/http2/h2/listener.go +++ b/listener/http2/h2/listener.go @@ -18,8 +18,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" ) diff --git a/listener/http2/listener.go b/listener/http2/listener.go index ea115ab..682a367 100644 --- a/listener/http2/listener.go +++ b/listener/http2/listener.go @@ -17,8 +17,8 @@ import ( limiter "github.com/go-gost/x/limiter/traffic/wrapper" mdx "github.com/go-gost/x/metadata" metrics "github.com/go-gost/x/metrics/wrapper" + stats "github.com/go-gost/x/observer/stats/wrapper" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "golang.org/x/net/http2" ) diff --git a/listener/http3/h3/listener.go b/listener/http3/h3/listener.go index fd0aaaa..0ebef93 100644 --- a/listener/http3/h3/listener.go +++ b/listener/http3/h3/listener.go @@ -11,8 +11,8 @@ import ( pht_util "github.com/go-gost/x/internal/util/pht" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "github.com/quic-go/quic-go" ) diff --git a/listener/http3/wt/listener.go b/listener/http3/wt/listener.go index cba4cf9..118b10c 100644 --- a/listener/http3/wt/listener.go +++ b/listener/http3/wt/listener.go @@ -13,8 +13,8 @@ import ( wt_util "github.com/go-gost/x/internal/util/wt" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "github.com/quic-go/quic-go" "github.com/quic-go/quic-go/http3" wt "github.com/quic-go/webtransport-go" diff --git a/listener/icmp/listener.go b/listener/icmp/listener.go index 7347324..86529f6 100644 --- a/listener/icmp/listener.go +++ b/listener/icmp/listener.go @@ -11,8 +11,8 @@ import ( icmp_pkg "github.com/go-gost/x/internal/util/icmp" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "github.com/quic-go/quic-go" "golang.org/x/net/icmp" ) @@ -73,7 +73,7 @@ func (l *icmpListener) Init(md md.Metadata) (err error) { } tlsCfg := l.options.TLSConfig - tlsCfg.NextProtos = []string{"http/3", "quic/v1"} + tlsCfg.NextProtos = []string{"h3", "quic/v1"} ln, err := quic.ListenEarly(conn, tlsCfg, config) if err != nil { diff --git a/listener/kcp/listener.go b/listener/kcp/listener.go index 93ea34d..be2901a 100644 --- a/listener/kcp/listener.go +++ b/listener/kcp/listener.go @@ -12,8 +12,8 @@ import ( kcp_util "github.com/go-gost/x/internal/util/kcp" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "github.com/xtaci/kcp-go/v5" "github.com/xtaci/smux" "github.com/xtaci/tcpraw" diff --git a/listener/mtcp/listener.go b/listener/mtcp/listener.go index 22654e4..3d8d7df 100644 --- a/listener/mtcp/listener.go +++ b/listener/mtcp/listener.go @@ -15,8 +15,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/mtls/listener.go b/listener/mtls/listener.go index 924fff9..5d67a4b 100644 --- a/listener/mtls/listener.go +++ b/listener/mtls/listener.go @@ -16,8 +16,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/mws/listener.go b/listener/mws/listener.go index 6888030..c50d80c 100644 --- a/listener/mws/listener.go +++ b/listener/mws/listener.go @@ -19,8 +19,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "github.com/gorilla/websocket" ) diff --git a/listener/obfs/http/listener.go b/listener/obfs/http/listener.go index a1e0671..ccedafc 100644 --- a/listener/obfs/http/listener.go +++ b/listener/obfs/http/listener.go @@ -14,8 +14,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/obfs/tls/listener.go b/listener/obfs/tls/listener.go index 3aa29f6..a7a6ccd 100644 --- a/listener/obfs/tls/listener.go +++ b/listener/obfs/tls/listener.go @@ -14,8 +14,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/pht/listener.go b/listener/pht/listener.go index 50a7999..1a8ba6f 100644 --- a/listener/pht/listener.go +++ b/listener/pht/listener.go @@ -13,8 +13,8 @@ import ( pht_util "github.com/go-gost/x/internal/util/pht" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/quic/listener.go b/listener/quic/listener.go index 6b3c9ff..3604fef 100644 --- a/listener/quic/listener.go +++ b/listener/quic/listener.go @@ -12,8 +12,8 @@ import ( quic_util "github.com/go-gost/x/internal/util/quic" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "github.com/quic-go/quic-go" ) @@ -82,7 +82,7 @@ func (l *quicListener) Init(md md.Metadata) (err error) { } tlsCfg := l.options.TLSConfig - tlsCfg.NextProtos = []string{"http/3", "quic/v1"} + tlsCfg.NextProtos = []string{"h3", "quic/v1"} ln, err := quic.ListenEarly(conn, tlsCfg, config) if err != nil { diff --git a/listener/redirect/tcp/listener.go b/listener/redirect/tcp/listener.go index bcbfb17..4907698 100644 --- a/listener/redirect/tcp/listener.go +++ b/listener/redirect/tcp/listener.go @@ -14,8 +14,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/redirect/udp/listener.go b/listener/redirect/udp/listener.go index d2b22e3..ff0698a 100644 --- a/listener/redirect/udp/listener.go +++ b/listener/redirect/udp/listener.go @@ -9,8 +9,8 @@ import ( admission "github.com/go-gost/x/admission/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/rtcp/listener.go b/listener/rtcp/listener.go index 263ae15..d553089 100644 --- a/listener/rtcp/listener.go +++ b/listener/rtcp/listener.go @@ -14,8 +14,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { @@ -60,10 +60,10 @@ func (l *rtcpListener) Init(md md.Metadata) (err error) { l.laddr = &bindAddr{addr: l.options.Addr} } - l.router = chain.NewRouter( - chain.ChainRouterOption(l.options.Chain), - chain.LoggerRouterOption(l.logger), - ) + l.router = l.options.Router + if l.router == nil { + l.router = chain.NewRouter(chain.LoggerRouterOption(l.logger)) + } return } diff --git a/listener/rudp/listener.go b/listener/rudp/listener.go index 5b3ca23..8d9e310 100644 --- a/listener/rudp/listener.go +++ b/listener/rudp/listener.go @@ -13,8 +13,8 @@ import ( xnet "github.com/go-gost/x/internal/net" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { @@ -60,10 +60,10 @@ func (l *rudpListener) Init(md md.Metadata) (err error) { l.laddr = &bindAddr{addr: l.options.Addr} } - l.router = chain.NewRouter( - chain.ChainRouterOption(l.options.Chain), - chain.LoggerRouterOption(l.logger), - ) + l.router = l.options.Router + if l.router == nil { + l.router = chain.NewRouter(chain.LoggerRouterOption(l.logger)) + } return } diff --git a/listener/serial/listener.go b/listener/serial/listener.go index 7db6f2e..862dd3c 100644 --- a/listener/serial/listener.go +++ b/listener/serial/listener.go @@ -11,8 +11,8 @@ import ( serial "github.com/go-gost/x/internal/util/serial" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/ssh/listener.go b/listener/ssh/listener.go index 18383a2..2701b09 100644 --- a/listener/ssh/listener.go +++ b/listener/ssh/listener.go @@ -16,8 +16,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "golang.org/x/crypto/ssh" ) diff --git a/listener/sshd/listener.go b/listener/sshd/listener.go index 5f891ec..6c49d5a 100644 --- a/listener/sshd/listener.go +++ b/listener/sshd/listener.go @@ -18,9 +18,9 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" "golang.org/x/crypto/ssh" - stats "github.com/go-gost/x/stats/wrapper" ) // Applicable SSH Request types for Port Forwarding - RFC 4254 7.X diff --git a/listener/tap/listener.go b/listener/tap/listener.go index 02b5803..c01cfbb 100644 --- a/listener/tap/listener.go +++ b/listener/tap/listener.go @@ -12,8 +12,8 @@ import ( limiter "github.com/go-gost/x/limiter/traffic/wrapper" mdx "github.com/go-gost/x/metadata" metrics "github.com/go-gost/x/metrics/wrapper" + stats "github.com/go-gost/x/observer/stats/wrapper" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/tcp/listener.go b/listener/tcp/listener.go index 2ca37b1..9e42ef4 100644 --- a/listener/tcp/listener.go +++ b/listener/tcp/listener.go @@ -14,8 +14,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/tls/listener.go b/listener/tls/listener.go index 0f46624..2e36fb7 100644 --- a/listener/tls/listener.go +++ b/listener/tls/listener.go @@ -15,8 +15,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/tun/listener.go b/listener/tun/listener.go index a6a5058..bf4f96d 100644 --- a/listener/tun/listener.go +++ b/listener/tun/listener.go @@ -13,8 +13,8 @@ import ( limiter "github.com/go-gost/x/limiter/traffic/wrapper" mdx "github.com/go-gost/x/metadata" metrics "github.com/go-gost/x/metrics/wrapper" + stats "github.com/go-gost/x/observer/stats/wrapper" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/udp/listener.go b/listener/udp/listener.go index a33073b..d437a3c 100644 --- a/listener/udp/listener.go +++ b/listener/udp/listener.go @@ -11,8 +11,8 @@ import ( xnet "github.com/go-gost/x/internal/net" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/unix/listener.go b/listener/unix/listener.go index 2c0d94b..11f718a 100644 --- a/listener/unix/listener.go +++ b/listener/unix/listener.go @@ -10,8 +10,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" ) func init() { diff --git a/listener/ws/listener.go b/listener/ws/listener.go index b32146a..2a42a25 100644 --- a/listener/ws/listener.go +++ b/listener/ws/listener.go @@ -18,8 +18,8 @@ import ( climiter "github.com/go-gost/x/limiter/conn/wrapper" 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" "github.com/go-gost/x/registry" - stats "github.com/go-gost/x/stats/wrapper" "github.com/gorilla/websocket" ) diff --git a/observer/plugin/grpc.go b/observer/plugin/grpc.go index 4bdaabf..ea34f53 100644 --- a/observer/plugin/grpc.go +++ b/observer/plugin/grpc.go @@ -6,10 +6,10 @@ import ( "github.com/go-gost/core/logger" "github.com/go-gost/core/observer" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/plugin/observer/proto" "github.com/go-gost/x/internal/plugin" "github.com/go-gost/x/service" - "github.com/go-gost/x/stats" "google.golang.org/grpc" ) diff --git a/observer/plugin/http.go b/observer/plugin/http.go index 01e9a38..1ca082e 100644 --- a/observer/plugin/http.go +++ b/observer/plugin/http.go @@ -10,9 +10,9 @@ import ( "github.com/go-gost/core/logger" "github.com/go-gost/core/observer" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/x/internal/plugin" "github.com/go-gost/x/service" - "github.com/go-gost/x/stats" ) type observeRequest struct { diff --git a/stats/wrapper/conn.go b/observer/stats/wrapper/conn.go similarity index 99% rename from stats/wrapper/conn.go rename to observer/stats/wrapper/conn.go index 5e00f05..55e072a 100644 --- a/stats/wrapper/conn.go +++ b/observer/stats/wrapper/conn.go @@ -7,9 +7,9 @@ import ( "syscall" "github.com/go-gost/core/metadata" + "github.com/go-gost/core/observer/stats" xnet "github.com/go-gost/x/internal/net" "github.com/go-gost/x/internal/net/udp" - "github.com/go-gost/x/stats" ) var ( diff --git a/stats/wrapper/io.go b/observer/stats/wrapper/io.go similarity index 93% rename from stats/wrapper/io.go rename to observer/stats/wrapper/io.go index 365606f..7c165f3 100644 --- a/stats/wrapper/io.go +++ b/observer/stats/wrapper/io.go @@ -3,7 +3,7 @@ package wrapper import ( "io" - "github.com/go-gost/x/stats" + "github.com/go-gost/core/observer/stats" ) // readWriter is an io.ReadWriter with Stats. diff --git a/stats/wrapper/listener.go b/observer/stats/wrapper/listener.go similarity index 90% rename from stats/wrapper/listener.go rename to observer/stats/wrapper/listener.go index 88c272e..595da2d 100644 --- a/stats/wrapper/listener.go +++ b/observer/stats/wrapper/listener.go @@ -3,7 +3,7 @@ package wrapper import ( "net" - "github.com/go-gost/x/stats" + "github.com/go-gost/core/observer/stats" ) type listener struct { diff --git a/service/service.go b/service/service.go index d7ccd44..d3c6491 100644 --- a/service/service.go +++ b/service/service.go @@ -15,11 +15,11 @@ import ( "github.com/go-gost/core/logger" "github.com/go-gost/core/metrics" "github.com/go-gost/core/observer" + "github.com/go-gost/core/observer/stats" "github.com/go-gost/core/recorder" "github.com/go-gost/core/service" ctxvalue "github.com/go-gost/x/ctx" xmetrics "github.com/go-gost/x/metrics" - "github.com/go-gost/x/stats" "github.com/rs/xid" ) diff --git a/service/status.go b/service/status.go index 424a77a..457ef3e 100644 --- a/service/status.go +++ b/service/status.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "github.com/go-gost/x/stats" + "github.com/go-gost/core/observer/stats" ) const ( diff --git a/stats/stats.go b/stats/stats.go deleted file mode 100644 index d00bf75..0000000 --- a/stats/stats.go +++ /dev/null @@ -1,93 +0,0 @@ -package stats - -import ( - "sync/atomic" - - "github.com/go-gost/core/observer" -) - -type Kind int - -const ( - KindTotalConns Kind = 1 - KindCurrentConns Kind = 2 - KindInputBytes Kind = 3 - KindOutputBytes Kind = 4 - KindTotalErrs Kind = 5 -) - -type Stats struct { - updated atomic.Bool - totalConns atomic.Uint64 - currentConns atomic.Int64 - inputBytes atomic.Uint64 - outputBytes atomic.Uint64 - totalErrs atomic.Uint64 -} - -func (s *Stats) Add(kind Kind, n int64) { - if s == nil { - return - } - switch kind { - case KindTotalConns: - if n > 0 { - s.totalConns.Add(uint64(n)) - } - case KindCurrentConns: - s.currentConns.Add(n) - case KindInputBytes: - if n > 0 { - s.inputBytes.Add(uint64(n)) - } - case KindOutputBytes: - if n > 0 { - s.outputBytes.Add(uint64(n)) - } - case KindTotalErrs: - if n > 0 { - s.totalErrs.Add(uint64(n)) - } - } - s.updated.Store(true) -} - -func (s *Stats) Get(kind Kind) uint64 { - if s == nil { - return 0 - } - - switch kind { - case KindTotalConns: - return s.totalConns.Load() - case KindCurrentConns: - return uint64(s.currentConns.Load()) - case KindInputBytes: - return s.inputBytes.Load() - case KindOutputBytes: - return s.outputBytes.Load() - case KindTotalErrs: - return s.totalErrs.Load() - } - return 0 -} - -func (s *Stats) IsUpdated() bool { - return s.updated.Swap(false) -} - -type StatsEvent struct { - Kind string - Service string - Client string - - TotalConns uint64 - CurrentConns uint64 - InputBytes uint64 - OutputBytes uint64 - TotalErrs uint64 -} - -func (StatsEvent) Type() observer.EventType { - return observer.EventStats -}