Merge branch 'master' into dev
This commit is contained in:
commit
5cc2c3de82
@ -54,7 +54,7 @@ func getConfig(ctx *gin.Context) {
|
|||||||
if ok && ss != nil {
|
if ok && ss != nil {
|
||||||
status := ss.Status()
|
status := ss.Status()
|
||||||
svc.Status = &config.ServiceStatus{
|
svc.Status = &config.ServiceStatus{
|
||||||
CreateTime: status.CreateTime().UnixNano(),
|
CreateTime: status.CreateTime().Unix(),
|
||||||
State: string(status.State()),
|
State: string(status.State()),
|
||||||
}
|
}
|
||||||
if st := status.Stats(); st != nil {
|
if st := status.Stats(); st != nil {
|
||||||
@ -69,7 +69,7 @@ func getConfig(ctx *gin.Context) {
|
|||||||
for _, ev := range status.Events() {
|
for _, ev := range status.Events() {
|
||||||
if !ev.Time.IsZero() {
|
if !ev.Time.IsZero() {
|
||||||
svc.Status.Events = append(svc.Status.Events, config.ServiceEvent{
|
svc.Status.Events = append(svc.Status.Events, config.ServiceEvent{
|
||||||
Time: ev.Time.UnixNano(),
|
Time: ev.Time.Unix(),
|
||||||
Msg: ev.Message,
|
Msg: ev.Message,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -359,13 +359,15 @@ type ForwardNodeConfig struct {
|
|||||||
Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"`
|
Bypasses []string `yaml:",omitempty" json:"bypasses,omitempty"`
|
||||||
HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"`
|
HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"`
|
||||||
TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"`
|
TLS *TLSNodeConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||||
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
// DEPRECATED by HTTP.Auth
|
||||||
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||||
|
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPNodeConfig struct {
|
type HTTPNodeConfig struct {
|
||||||
Host string `yaml:",omitempty" json:"host,omitempty"`
|
Host string `yaml:",omitempty" json:"host,omitempty"`
|
||||||
Header map[string]string `yaml:",omitempty" json:"header,omitempty"`
|
Header map[string]string `yaml:",omitempty" json:"header,omitempty"`
|
||||||
|
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TLSNodeConfig struct {
|
type TLSNodeConfig struct {
|
||||||
|
@ -168,10 +168,28 @@ func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.No
|
|||||||
chain.NetworkNodeOption(cfg.Network),
|
chain.NetworkNodeOption(cfg.Network),
|
||||||
}
|
}
|
||||||
if cfg.HTTP != nil {
|
if cfg.HTTP != nil {
|
||||||
opts = append(opts, chain.HTTPNodeOption(&chain.HTTPNodeSettings{
|
settings := &chain.HTTPNodeSettings{
|
||||||
Host: cfg.HTTP.Host,
|
Host: cfg.HTTP.Host,
|
||||||
Header: cfg.HTTP.Header,
|
Header: cfg.HTTP.Header,
|
||||||
}))
|
}
|
||||||
|
|
||||||
|
auth := cfg.HTTP.Auth
|
||||||
|
if auth == nil {
|
||||||
|
auth = cfg.Auth
|
||||||
|
}
|
||||||
|
if auth != nil {
|
||||||
|
settings.Auther = xauth.NewAuthenticator(
|
||||||
|
xauth.AuthsOption(map[string]string{auth.Username: auth.Password}),
|
||||||
|
xauth.LoggerOption(log.WithFields(map[string]any{
|
||||||
|
"kind": "node",
|
||||||
|
"node": cfg.Name,
|
||||||
|
"addr": cfg.Addr,
|
||||||
|
"host": cfg.Host,
|
||||||
|
"protocol": cfg.Protocol,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
opts = append(opts, chain.HTTPNodeOption(settings))
|
||||||
}
|
}
|
||||||
if cfg.TLS != nil {
|
if cfg.TLS != nil {
|
||||||
tlsCfg := &chain.TLSNodeSettings{
|
tlsCfg := &chain.TLSNodeSettings{
|
||||||
@ -185,18 +203,5 @@ func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.No
|
|||||||
}
|
}
|
||||||
opts = append(opts, chain.TLSNodeOption(tlsCfg))
|
opts = append(opts, chain.TLSNodeOption(tlsCfg))
|
||||||
}
|
}
|
||||||
if cfg.Auth != nil {
|
|
||||||
opts = append(opts, chain.AutherNodeOption(
|
|
||||||
xauth.NewAuthenticator(
|
|
||||||
xauth.AuthsOption(map[string]string{cfg.Auth.Username: cfg.Auth.Password}),
|
|
||||||
xauth.LoggerOption(logger.Default().WithFields(map[string]any{
|
|
||||||
"kind": "node",
|
|
||||||
"node": cfg.Name,
|
|
||||||
"addr": cfg.Addr,
|
|
||||||
"host": cfg.Host,
|
|
||||||
"protocol": cfg.Protocol,
|
|
||||||
})),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
return chain.NewNode(cfg.Name, cfg.Addr, opts...), nil
|
return chain.NewNode(cfg.Name, cfg.Addr, opts...), nil
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,8 @@ func (c *tunnelConnector) Bind(ctx context.Context, conn net.Conn, network, addr
|
|||||||
"endpoint": endpoint,
|
"endpoint": endpoint,
|
||||||
"tunnel": c.md.tunnelID.String(),
|
"tunnel": c.md.tunnelID.String(),
|
||||||
})
|
})
|
||||||
log.Infof("create tunnel on %s/%s OK, tunnel=%s, connector=%s", addr, network, c.md.tunnelID.String(), cid)
|
log.Infof("create tunnel on %s/%s OK, tunnel=%s, connector=%s, weight=%d",
|
||||||
|
addr, network, c.md.tunnelID.String(), cid, cid.Weight())
|
||||||
|
|
||||||
session, err := mux.ServerSession(conn, c.md.muxCfg)
|
session, err := mux.ServerSession(conn, c.md.muxCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -72,7 +73,7 @@ func (c *tunnelConnector) initTunnel(conn net.Conn, network, address string) (ad
|
|||||||
req.Features = append(req.Features, af) // dst address
|
req.Features = append(req.Features, af) // dst address
|
||||||
|
|
||||||
req.Features = append(req.Features, &relay.TunnelFeature{
|
req.Features = append(req.Features, &relay.TunnelFeature{
|
||||||
ID: c.md.tunnelID.ID(),
|
ID: c.md.tunnelID,
|
||||||
})
|
})
|
||||||
if _, err = req.WriteTo(conn); err != nil {
|
if _, err = req.WriteTo(conn); err != nil {
|
||||||
return
|
return
|
||||||
@ -100,7 +101,7 @@ func (c *tunnelConnector) initTunnel(conn net.Conn, network, address string) (ad
|
|||||||
}
|
}
|
||||||
case relay.FeatureTunnel:
|
case relay.FeatureTunnel:
|
||||||
if feature, _ := f.(*relay.TunnelFeature); feature != nil {
|
if feature, _ := f.(*relay.TunnelFeature); feature != nil {
|
||||||
cid = relay.NewConnectorID(feature.ID[:])
|
cid = feature.ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ func (c *tunnelConnector) Connect(ctx context.Context, conn net.Conn, network, a
|
|||||||
req.Features = append(req.Features, af) // dst address
|
req.Features = append(req.Features, af) // dst address
|
||||||
|
|
||||||
req.Features = append(req.Features, &relay.TunnelFeature{
|
req.Features = append(req.Features, &relay.TunnelFeature{
|
||||||
ID: c.md.tunnelID.ID(),
|
ID: c.md.tunnelID,
|
||||||
})
|
})
|
||||||
|
|
||||||
if _, err := req.WriteTo(conn); err != nil {
|
if _, err := req.WriteTo(conn); err != nil {
|
||||||
|
@ -40,6 +40,10 @@ func (c *tunnelConnector) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
c.md.tunnelID = relay.NewTunnelID(uuid[:])
|
c.md.tunnelID = relay.NewTunnelID(uuid[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if weight := mdutil.GetInt(md, "tunnel.weight"); weight > 0 {
|
||||||
|
c.md.tunnelID = c.md.tunnelID.SetWeight(uint8(weight))
|
||||||
|
}
|
||||||
|
|
||||||
c.md.muxCfg = &mux.Config{
|
c.md.muxCfg = &mux.Config{
|
||||||
Version: mdutil.GetInt(md, "mux.version"),
|
Version: mdutil.GetInt(md, "mux.version"),
|
||||||
KeepAliveInterval: mdutil.GetDuration(md, "mux.keepaliveInterval"),
|
KeepAliveInterval: mdutil.GetDuration(md, "mux.keepaliveInterval"),
|
||||||
|
6
go.mod
6
go.mod
@ -7,11 +7,11 @@ require (
|
|||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
||||||
github.com/gin-contrib/cors v1.5.0
|
github.com/gin-contrib/cors v1.5.0
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/go-gost/core v0.0.0-20240103125300-5a427b4eaf99
|
github.com/go-gost/core v0.0.0-20240127130604-04314fa08476
|
||||||
github.com/go-gost/gosocks4 v0.0.1
|
github.com/go-gost/gosocks4 v0.0.1
|
||||||
github.com/go-gost/gosocks5 v0.4.0
|
github.com/go-gost/gosocks5 v0.4.0
|
||||||
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a
|
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a
|
||||||
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7
|
github.com/go-gost/relay v0.4.1-0.20240128081525-e36d5f4a8322
|
||||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451
|
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
@ -23,7 +23,7 @@ require (
|
|||||||
github.com/pion/dtls/v2 v2.2.6
|
github.com/pion/dtls/v2 v2.2.6
|
||||||
github.com/pires/go-proxyproto v0.7.0
|
github.com/pires/go-proxyproto v0.7.0
|
||||||
github.com/prometheus/client_golang v1.17.0
|
github.com/prometheus/client_golang v1.17.0
|
||||||
github.com/quic-go/quic-go v0.40.0
|
github.com/quic-go/quic-go v0.40.1
|
||||||
github.com/quic-go/webtransport-go v0.6.0
|
github.com/quic-go/webtransport-go v0.6.0
|
||||||
github.com/refraction-networking/utls v1.5.4
|
github.com/refraction-networking/utls v1.5.4
|
||||||
github.com/rs/xid v1.3.0
|
github.com/rs/xid v1.3.0
|
||||||
|
12
go.sum
12
go.sum
@ -49,16 +49,16 @@ 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-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 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||||
github.com/go-gost/core v0.0.0-20240103125300-5a427b4eaf99 h1:/0hmilnQBEDlOaRcO+TlwaHH8a5ig6nc2aAsU4FGZcw=
|
github.com/go-gost/core v0.0.0-20240127130604-04314fa08476 h1:4TA4ErfFw2CsVv5K5oqqYpUn68aZFrV+ONb4aGPJ1QQ=
|
||||||
github.com/go-gost/core v0.0.0-20240103125300-5a427b4eaf99/go.mod h1:ndkgWVYRLwupVaFFWv8ML1Nr8tD3xhHK245PLpUDg4E=
|
github.com/go-gost/core v0.0.0-20240127130604-04314fa08476/go.mod h1:ndkgWVYRLwupVaFFWv8ML1Nr8tD3xhHK245PLpUDg4E=
|
||||||
github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s=
|
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/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 h1:EIrOEkpJez4gwHrMa33frA+hHXJyevjp47thpMQsJzI=
|
||||||
github.com/go-gost/gosocks5 v0.4.0/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4=
|
github.com/go-gost/gosocks5 v0.4.0/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 h1:ME7P1Brcg4C640DSPqlvQr7JuvvQfJ8QpmS3yCFlK3A=
|
||||||
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a/go.mod h1:qXr2Zm9Ex2ATqnWuNUzVZqySPMnuIihvblYZt4MlZLw=
|
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a/go.mod h1:qXr2Zm9Ex2ATqnWuNUzVZqySPMnuIihvblYZt4MlZLw=
|
||||||
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7 h1:qAG1OyjvdA5h221CfFSS3J359V3d2E7dJWyP29QoDSI=
|
github.com/go-gost/relay v0.4.1-0.20240128081525-e36d5f4a8322 h1:R2a+Lx6XVvWdskGUUjteJ62WYBAskDHySgqNC6y8dI8=
|
||||||
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
|
github.com/go-gost/relay v0.4.1-0.20240128081525-e36d5f4a8322/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
|
||||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451 h1:xj8gUZGYO3nb5+6Bjw9+tsFkA9sYynrOvDvvC4uDV2I=
|
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451 h1:xj8gUZGYO3nb5+6Bjw9+tsFkA9sYynrOvDvvC4uDV2I=
|
||||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs=
|
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs=
|
||||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||||
@ -182,8 +182,8 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
|||||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||||
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
|
||||||
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||||
github.com/quic-go/quic-go v0.40.0 h1:GYd1iznlKm7dpHD7pOVpUvItgMPo/jrMgDWZhMCecqw=
|
github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q=
|
||||||
github.com/quic-go/quic-go v0.40.0/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
|
github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
|
||||||
github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY=
|
github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY=
|
||||||
github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc=
|
github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc=
|
||||||
github.com/refraction-networking/utls v1.5.4/go.mod h1:SPuDbBmgLGp8s+HLNc83FuavwZCFoMmExj+ltUHiHUw=
|
github.com/refraction-networking/utls v1.5.4/go.mod h1:SPuDbBmgLGp8s+HLNc83FuavwZCFoMmExj+ltUHiHUw=
|
||||||
|
@ -247,18 +247,19 @@ func (h *forwardHandler) handleHTTP(ctx context.Context, rw io.ReadWriter, remot
|
|||||||
})
|
})
|
||||||
log.Debugf("find node for host %s -> %s(%s)", req.Host, target.Name, target.Addr)
|
log.Debugf("find node for host %s -> %s(%s)", req.Host, target.Name, target.Addr)
|
||||||
|
|
||||||
if auther := target.Options().Auther; auther != nil {
|
|
||||||
username, password, _ := req.BasicAuth()
|
|
||||||
id, ok := auther.Authenticate(ctx, username, password)
|
|
||||||
if !ok {
|
|
||||||
resp.StatusCode = http.StatusUnauthorized
|
|
||||||
resp.Header.Set("WWW-Authenticate", "Basic")
|
|
||||||
log.Warnf("node %s(%s) 401 unauthorized", target.Name, target.Addr)
|
|
||||||
return resp.Write(rw)
|
|
||||||
}
|
|
||||||
ctx = ctxvalue.ContextWithClientID(ctx, ctxvalue.ClientID(id))
|
|
||||||
}
|
|
||||||
if httpSettings := target.Options().HTTP; httpSettings != nil {
|
if httpSettings := target.Options().HTTP; httpSettings != nil {
|
||||||
|
if auther := httpSettings.Auther; auther != nil {
|
||||||
|
username, password, _ := req.BasicAuth()
|
||||||
|
id, ok := auther.Authenticate(ctx, username, password)
|
||||||
|
if !ok {
|
||||||
|
resp.StatusCode = http.StatusUnauthorized
|
||||||
|
resp.Header.Set("WWW-Authenticate", "Basic")
|
||||||
|
log.Warnf("node %s(%s) 401 unauthorized", target.Name, target.Addr)
|
||||||
|
return resp.Write(rw)
|
||||||
|
}
|
||||||
|
ctx = ctxvalue.ContextWithClientID(ctx, ctxvalue.ClientID(id))
|
||||||
|
}
|
||||||
|
|
||||||
if httpSettings.Host != "" {
|
if httpSettings.Host != "" {
|
||||||
req.Host = httpSettings.Host
|
req.Host = httpSettings.Host
|
||||||
}
|
}
|
||||||
|
@ -248,18 +248,18 @@ func (h *forwardHandler) handleHTTP(ctx context.Context, rw io.ReadWriter, remot
|
|||||||
})
|
})
|
||||||
log.Debugf("find node for host %s -> %s(%s)", req.Host, target.Name, target.Addr)
|
log.Debugf("find node for host %s -> %s(%s)", req.Host, target.Name, target.Addr)
|
||||||
|
|
||||||
if auther := target.Options().Auther; auther != nil {
|
|
||||||
username, password, _ := req.BasicAuth()
|
|
||||||
id, ok := auther.Authenticate(ctx, username, password)
|
|
||||||
if !ok {
|
|
||||||
resp.StatusCode = http.StatusUnauthorized
|
|
||||||
resp.Header.Set("WWW-Authenticate", "Basic")
|
|
||||||
log.Warnf("node %s(%s) 401 unauthorized", target.Name, target.Addr)
|
|
||||||
return resp.Write(rw)
|
|
||||||
}
|
|
||||||
ctx = ctxvalue.ContextWithClientID(ctx, ctxvalue.ClientID(id))
|
|
||||||
}
|
|
||||||
if httpSettings := target.Options().HTTP; httpSettings != nil {
|
if httpSettings := target.Options().HTTP; httpSettings != nil {
|
||||||
|
if auther := httpSettings.Auther; auther != nil {
|
||||||
|
username, password, _ := req.BasicAuth()
|
||||||
|
id, ok := auther.Authenticate(ctx, username, password)
|
||||||
|
if !ok {
|
||||||
|
resp.StatusCode = http.StatusUnauthorized
|
||||||
|
resp.Header.Set("WWW-Authenticate", "Basic")
|
||||||
|
log.Warnf("node %s(%s) 401 unauthorized", target.Name, target.Addr)
|
||||||
|
return resp.Write(rw)
|
||||||
|
}
|
||||||
|
ctx = ctxvalue.ContextWithClientID(ctx, ctxvalue.ClientID(id))
|
||||||
|
}
|
||||||
if httpSettings.Host != "" {
|
if httpSettings.Host != "" {
|
||||||
req.Host = httpSettings.Host
|
req.Host = httpSettings.Host
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,8 @@ func (h *tunnelHandler) handleBind(ctx context.Context, conn net.Conn, network,
|
|||||||
if network == "udp" {
|
if network == "udp" {
|
||||||
connectorID = relay.NewUDPConnectorID(uuid[:])
|
connectorID = relay.NewUDPConnectorID(uuid[:])
|
||||||
}
|
}
|
||||||
|
// copy weight from tunnelID
|
||||||
|
connectorID = connectorID.SetWeight(tunnelID.Weight())
|
||||||
|
|
||||||
v := md5.Sum([]byte(tunnelID.String()))
|
v := md5.Sum([]byte(tunnelID.String()))
|
||||||
endpoint := hex.EncodeToString(v[:8])
|
endpoint := hex.EncodeToString(v[:8])
|
||||||
@ -47,7 +49,7 @@ func (h *tunnelHandler) handleBind(ctx context.Context, conn net.Conn, network,
|
|||||||
}
|
}
|
||||||
resp.Features = append(resp.Features, af,
|
resp.Features = append(resp.Features, af,
|
||||||
&relay.TunnelFeature{
|
&relay.TunnelFeature{
|
||||||
ID: connectorID.ID(),
|
ID: connectorID,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
resp.WriteTo(conn)
|
resp.WriteTo(conn)
|
||||||
@ -84,7 +86,7 @@ func (h *tunnelHandler) handleBind(ctx context.Context, conn net.Conn, network,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("%s/%s: tunnel=%s, connector=%s established", addr, network, tunnelID, connectorID)
|
log.Debugf("%s/%s: tunnel=%s, connector=%s, weight=%d established", addr, network, tunnelID, connectorID, connectorID.Weight())
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ func (h *tunnelHandler) Handle(ctx context.Context, conn net.Conn, opts ...handl
|
|||||||
}
|
}
|
||||||
case relay.FeatureTunnel:
|
case relay.FeatureTunnel:
|
||||||
if feature, _ := f.(*relay.TunnelFeature); feature != nil {
|
if feature, _ := f.(*relay.TunnelFeature); feature != nil {
|
||||||
tunnelID = relay.NewTunnelID(feature.ID[:])
|
tunnelID = feature.ID
|
||||||
}
|
}
|
||||||
case relay.FeatureNetwork:
|
case relay.FeatureNetwork:
|
||||||
if feature, _ := f.(*relay.NetworkFeature); feature != nil {
|
if feature, _ := f.(*relay.NetworkFeature); feature != nil {
|
||||||
|
@ -3,16 +3,20 @@ package tunnel
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/core/sd"
|
"github.com/go-gost/core/sd"
|
||||||
"github.com/go-gost/relay"
|
"github.com/go-gost/relay"
|
||||||
"github.com/go-gost/x/internal/util/mux"
|
"github.com/go-gost/x/internal/util/mux"
|
||||||
|
"github.com/go-gost/x/selector"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MaxWeight uint8 = 0xff
|
||||||
|
)
|
||||||
|
|
||||||
type Connector struct {
|
type Connector struct {
|
||||||
id relay.ConnectorID
|
id relay.ConnectorID
|
||||||
tid relay.TunnelID
|
tid relay.TunnelID
|
||||||
@ -67,11 +71,11 @@ type Tunnel struct {
|
|||||||
id relay.TunnelID
|
id relay.TunnelID
|
||||||
connectors []*Connector
|
connectors []*Connector
|
||||||
t time.Time
|
t time.Time
|
||||||
n uint64
|
|
||||||
close chan struct{}
|
close chan struct{}
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
sd sd.SD
|
sd sd.SD
|
||||||
ttl time.Duration
|
ttl time.Duration
|
||||||
|
rw *selector.RandomWeighted[*Connector]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunnel(node string, tid relay.TunnelID, ttl time.Duration) *Tunnel {
|
func NewTunnel(node string, tid relay.TunnelID, ttl time.Duration) *Tunnel {
|
||||||
@ -81,6 +85,7 @@ func NewTunnel(node string, tid relay.TunnelID, ttl time.Duration) *Tunnel {
|
|||||||
t: time.Now(),
|
t: time.Now(),
|
||||||
close: make(chan struct{}),
|
close: make(chan struct{}),
|
||||||
ttl: ttl,
|
ttl: ttl,
|
||||||
|
rw: selector.NewRandomWeighted[*Connector](),
|
||||||
}
|
}
|
||||||
if t.ttl <= 0 {
|
if t.ttl <= 0 {
|
||||||
t.ttl = defaultTTL
|
t.ttl = defaultTTL
|
||||||
@ -112,21 +117,34 @@ func (t *Tunnel) GetConnector(network string) *Connector {
|
|||||||
t.mu.RLock()
|
t.mu.RLock()
|
||||||
defer t.mu.RUnlock()
|
defer t.mu.RUnlock()
|
||||||
|
|
||||||
var connectors []*Connector
|
rw := t.rw
|
||||||
|
rw.Reset()
|
||||||
|
|
||||||
|
found := false
|
||||||
for _, c := range t.connectors {
|
for _, c := range t.connectors {
|
||||||
if c.Session().IsClosed() {
|
if c.Session().IsClosed() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
weight := c.ID().Weight()
|
||||||
|
if weight == 0 {
|
||||||
|
weight = 1
|
||||||
|
}
|
||||||
|
|
||||||
if network == "udp" && c.id.IsUDP() ||
|
if network == "udp" && c.id.IsUDP() ||
|
||||||
network != "udp" && !c.id.IsUDP() {
|
network != "udp" && !c.id.IsUDP() {
|
||||||
connectors = append(connectors, c)
|
if weight == MaxWeight && !found {
|
||||||
|
rw.Reset()
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if weight == MaxWeight || !found {
|
||||||
|
rw.Add(c, int(weight))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(connectors) == 0 {
|
|
||||||
return nil
|
return rw.Next()
|
||||||
}
|
|
||||||
n := atomic.AddUint64(&t.n, 1) - 1
|
|
||||||
return connectors[n%uint64(len(connectors))]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tunnel) CloseOnIdle() bool {
|
func (t *Tunnel) CloseOnIdle() bool {
|
||||||
|
@ -24,10 +24,6 @@ type httpPluginRequest struct {
|
|||||||
Src string `json:"src"`
|
Src string `json:"src"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type httpPluginResponse struct {
|
|
||||||
Node string `json:"node"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type httpPlugin struct {
|
type httpPlugin struct {
|
||||||
name string
|
name string
|
||||||
url string
|
url string
|
||||||
@ -101,18 +97,8 @@ func (p *httpPlugin) Select(ctx context.Context, opts ...hop.SelectOption) *chai
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
res := httpPluginResponse{}
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
|
||||||
p.log.Error(resp.Status)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.Node == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var cfg config.NodeConfig
|
var cfg config.NodeConfig
|
||||||
if err := json.NewDecoder(bytes.NewReader([]byte(res.Node))).Decode(&cfg); err != nil {
|
if err := json.NewDecoder(resp.Body).Decode(&cfg); err != nil {
|
||||||
p.log.Error(err)
|
p.log.Error(err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ func (l *udpListener) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
readBufferSize = "readBufferSize"
|
readBufferSize = "readBufferSize"
|
||||||
readQueueSize = "readQueueSize"
|
readQueueSize = "readQueueSize"
|
||||||
backlog = "backlog"
|
backlog = "backlog"
|
||||||
keepAlive = "keepAlive"
|
keepalive = "keepalive"
|
||||||
ttl = "ttl"
|
ttl = "ttl"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ func (l *udpListener) parseMetadata(md mdata.Metadata) (err error) {
|
|||||||
if l.md.backlog <= 0 {
|
if l.md.backlog <= 0 {
|
||||||
l.md.backlog = defaultBacklog
|
l.md.backlog = defaultBacklog
|
||||||
}
|
}
|
||||||
l.md.keepalive = mdutil.GetBool(md, keepAlive)
|
l.md.keepalive = mdutil.GetBool(md, keepalive)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ func (s *roundRobinStrategy[T]) Apply(ctx context.Context, vs ...T) (v T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type randomStrategy[T any] struct {
|
type randomStrategy[T any] struct {
|
||||||
rw *randomWeighted[T]
|
rw *RandomWeighted[T]
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ type randomStrategy[T any] struct {
|
|||||||
// The node will be selected randomly.
|
// The node will be selected randomly.
|
||||||
func RandomStrategy[T any]() selector.Strategy[T] {
|
func RandomStrategy[T any]() selector.Strategy[T] {
|
||||||
return &randomStrategy[T]{
|
return &randomStrategy[T]{
|
||||||
rw: newRandomWeighted[T](),
|
rw: NewRandomWeighted[T](),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,25 +10,25 @@ type randomWeightedItem[T any] struct {
|
|||||||
weight int
|
weight int
|
||||||
}
|
}
|
||||||
|
|
||||||
type randomWeighted[T any] struct {
|
type RandomWeighted[T any] struct {
|
||||||
items []*randomWeightedItem[T]
|
items []*randomWeightedItem[T]
|
||||||
sum int
|
sum int
|
||||||
r *rand.Rand
|
r *rand.Rand
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRandomWeighted[T any]() *randomWeighted[T] {
|
func NewRandomWeighted[T any]() *RandomWeighted[T] {
|
||||||
return &randomWeighted[T]{
|
return &RandomWeighted[T]{
|
||||||
r: rand.New(rand.NewSource(time.Now().UnixNano())),
|
r: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *randomWeighted[T]) Add(item T, weight int) {
|
func (rw *RandomWeighted[T]) Add(item T, weight int) {
|
||||||
ri := &randomWeightedItem[T]{item: item, weight: weight}
|
ri := &randomWeightedItem[T]{item: item, weight: weight}
|
||||||
rw.items = append(rw.items, ri)
|
rw.items = append(rw.items, ri)
|
||||||
rw.sum += weight
|
rw.sum += weight
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *randomWeighted[T]) Next() (v T) {
|
func (rw *RandomWeighted[T]) Next() (v T) {
|
||||||
if len(rw.items) == 0 {
|
if len(rw.items) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ func (rw *randomWeighted[T]) Next() (v T) {
|
|||||||
return rw.items[len(rw.items)-1].item
|
return rw.items[len(rw.items)-1].item
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rw *randomWeighted[T]) Reset() {
|
func (rw *RandomWeighted[T]) Reset() {
|
||||||
rw.items = nil
|
rw.items = nil
|
||||||
rw.sum = 0
|
rw.sum = 0
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user