diff --git a/config/config.go b/config/config.go index b16f2604..0e2f4608 100644 --- a/config/config.go +++ b/config/config.go @@ -406,11 +406,13 @@ type HTTPNodeConfig struct { // Deprecated: use requestHeader instead Header map[string]string `yaml:",omitempty" json:"header,omitempty"` // additional request header - RequestHeader map[string]string `yaml:",omitempty" json:"requestHeader,omitempty"` + RequestHeader map[string]string `yaml:"requestHeader,omitempty" json:"requestHeader,omitempty"` // additional response header - ResponseHeader map[string]string `yaml:",omitempty" json:"responseHeader,omitempty"` - // rewrite URL + ResponseHeader map[string]string `yaml:"responseHeader,omitempty" json:"responseHeader,omitempty"` + // Deprecated: use rewriteURL instead Rewrite []HTTPURLRewriteConfig `yaml:",omitempty" json:"rewrite,omitempty"` + // rewrite URL + RewriteURL []HTTPURLRewriteConfig `yaml:"rewriteURL,omitempty" json:"rewriteURL,omitempty"` // rewrite response body RewriteBody []HTTPBodyRewriteConfig `yaml:"rewriteBody,omitempty" json:"rewriteBody,omitempty"` // HTTP basic auth diff --git a/config/parsing/node/parse.go b/config/parsing/node/parse.go index dc8d7ea2..bec92493 100644 --- a/config/parsing/node/parse.go +++ b/config/parsing/node/parse.go @@ -215,7 +215,12 @@ func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.No })), ) } - for _, v := range cfg.HTTP.Rewrite { + + rewriteURL := cfg.HTTP.RewriteURL + if rewriteURL == nil { + rewriteURL = cfg.HTTP.Rewrite + } + for _, v := range rewriteURL { if pattern, _ := regexp.Compile(v.Match); pattern != nil { settings.RewriteURL = append(settings.RewriteURL, chain.HTTPURLRewriteSetting{ Pattern: pattern, diff --git a/handler/forward/local/handler.go b/handler/forward/local/handler.go index 2d8946d3..f4defc26 100644 --- a/handler/forward/local/handler.go +++ b/handler/forward/local/handler.go @@ -92,7 +92,10 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand ro.ClientIP = conn.RemoteAddr().String() if clientAddr := ctxvalue.ClientAddrFromContext(ctx); clientAddr != "" { ro.ClientIP = string(clientAddr) + } else { + ctx = ctxvalue.ContextWithClientAddr(ctx, ctxvalue.ClientAddr(conn.RemoteAddr().String())) } + if h, _, _ := net.SplitHostPort(ro.ClientIP); h != "" { ro.ClientIP = h } @@ -100,7 +103,7 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand log := h.options.Logger.WithFields(map[string]any{ "remote": conn.RemoteAddr().String(), "local": conn.LocalAddr().String(), - "sid": ctxvalue.SidFromContext(ctx), + "sid": ro.SID, "client": ro.ClientIP, }) log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr()) diff --git a/handler/forward/remote/handler.go b/handler/forward/remote/handler.go index 3cc6bd4b..da5b7a72 100644 --- a/handler/forward/remote/handler.go +++ b/handler/forward/remote/handler.go @@ -23,6 +23,7 @@ import ( "github.com/go-gost/x/internal/util/sniffing" tls_util "github.com/go-gost/x/internal/util/tls" rate_limiter "github.com/go-gost/x/limiter/rate" + mdutil "github.com/go-gost/x/metadata/util" stats_wrapper "github.com/go-gost/x/observer/stats/wrapper" xrecorder "github.com/go-gost/x/recorder" "github.com/go-gost/x/registry" @@ -93,7 +94,10 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand ro.ClientIP = conn.RemoteAddr().String() if clientAddr := ctxvalue.ClientAddrFromContext(ctx); clientAddr != "" { ro.ClientIP = string(clientAddr) + } else { + ctx = ctxvalue.ContextWithClientAddr(ctx, ctxvalue.ClientAddr(conn.RemoteAddr().String())) } + if h, _, _ := net.SplitHostPort(ro.ClientIP); h != "" { ro.ClientIP = h } @@ -101,7 +105,7 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand log := h.options.Logger.WithFields(map[string]any{ "remote": conn.RemoteAddr().String(), "local": conn.LocalAddr().String(), - "sid": ctxvalue.SidFromContext(ctx), + "sid": ro.SID, "client": ro.ClientIP, }) log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr()) @@ -137,6 +141,13 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand return rate_limiter.ErrRateLimit } + var host string + if md, ok := conn.(mdata.Metadatable); ok { + if v := mdutil.GetString(md.Metadata(), "host"); v != "" { + host = v + } + } + var proto string if network == "tcp" && h.md.sniffing { if h.md.sniffingTimeout > 0 { @@ -193,6 +204,11 @@ func (h *forwardHandler) Handle(ctx context.Context, conn net.Conn, opts ...hand } var target *chain.Node + if host != "" { + target = &chain.Node{ + Addr: host, + } + } if h.hop != nil { target = h.hop.Select(ctx, hop.ProtocolSelectOption(proto), diff --git a/handler/tunnel/connect.go b/handler/tunnel/connect.go index 229d1a23..e0942fbf 100644 --- a/handler/tunnel/connect.go +++ b/handler/tunnel/connect.go @@ -33,18 +33,34 @@ func (h *tunnelHandler) handleConnect(ctx context.Context, req *relay.Request, c host, _, _ := net.SplitHostPort(dstAddr) - // client is a public entrypoint. - if tunnelID.Equal(h.md.entryPointID) { - resp.WriteTo(conn) - return h.ep.Handle(ctx, conn) + var tid relay.TunnelID + if ingress := h.md.ingress; ingress != nil && host != "" { + if rule := ingress.GetRule(ctx, host); rule != nil { + tid = parseTunnelID(rule.Endpoint) + } } - if !h.md.directTunnel { - var tid relay.TunnelID - if ingress := h.md.ingress; ingress != nil && host != "" { - if rule := ingress.GetRule(ctx, host); rule != nil { - tid = parseTunnelID(rule.Endpoint) - } + // visitor is a public entrypoint. + if tunnelID.Equal(h.md.entryPointID) { + if tid.IsZero() { + resp.Status = relay.StatusNetworkUnreachable + resp.WriteTo(conn) + err := fmt.Errorf("no route to host %s", host) + log.Error(err) + return err + } + + if tid.IsPrivate() { + resp.Status = relay.StatusHostUnreachable + resp.WriteTo(conn) + err := fmt.Errorf("tunnel %s is private for host %s", tid, host) + log.Error(err) + return err + } + } else { + // direct routing + if h.md.directTunnel { + tid = tunnelID } if !tid.Equal(tunnelID) { resp.Status = relay.StatusHostUnreachable @@ -63,7 +79,7 @@ func (h *tunnelHandler) handleConnect(ctx context.Context, req *relay.Request, c timeout: 15 * time.Second, log: log, } - cc, node, cid, err := d.Dial(ctx, network, tunnelID.String()) + cc, node, cid, err := d.Dial(ctx, network, tid.String()) if err != nil { log.Error(err) resp.Status = relay.StatusServiceUnavailable @@ -72,7 +88,7 @@ func (h *tunnelHandler) handleConnect(ctx context.Context, req *relay.Request, c } defer cc.Close() - log.Debugf("connected to node=%s tunnel=%s connector=%s", node, tunnelID, cid) + log.Debugf("connect to node=%s tunnel=%s connector=%s OK", node, tid, cid) if node == h.id { if _, err := resp.WriteTo(conn); err != nil { diff --git a/handler/tunnel/tunnel.go b/handler/tunnel/tunnel.go index 70b27569..ae26dc2d 100644 --- a/handler/tunnel/tunnel.go +++ b/handler/tunnel/tunnel.go @@ -260,7 +260,7 @@ func (t *Tunnel) clean() { var connectors []*Connector for _, c := range t.connectors { if c.IsClosed() { - c.log.Debugf("remove connector: %s", t.id, c.id) + c.log.Debugf("remove connector: %s %s", t.id, c.id) continue }