diff --git a/config/parsing/parse.go b/config/parsing/parse.go index a19ef0f..a3e07d2 100644 --- a/config/parsing/parse.go +++ b/config/parsing/parse.go @@ -333,7 +333,7 @@ func ParseIngress(cfg *config.IngressConfig) ingress.Ingress { } rules = append(rules, xingress.Rule{ - Host: rule.Hostname, + Hostname: rule.Hostname, Endpoint: rule.Endpoint, }) } diff --git a/connector/relay/metadata.go b/connector/relay/metadata.go index 29fc927..78fc681 100644 --- a/connector/relay/metadata.go +++ b/connector/relay/metadata.go @@ -19,13 +19,12 @@ func (c *relayConnector) parseMetadata(md mdata.Metadata) (err error) { const ( connectTimeout = "connectTimeout" noDelay = "nodelay" - tunnelID = "tunnelID" ) c.md.connectTimeout = mdutil.GetDuration(md, connectTimeout) c.md.noDelay = mdutil.GetBool(md, noDelay) - if s := mdutil.GetString(md, tunnelID); s != "" { + if s := mdutil.GetString(md, "tunnelID", "tunnel.id"); s != "" { uuid, err := uuid.Parse(s) if err != nil { return err diff --git a/handler/forward/local/handler.go b/handler/forward/local/handler.go index 4958e42..e2d1b71 100644 --- a/handler/forward/local/handler.go +++ b/handler/forward/local/handler.go @@ -132,7 +132,11 @@ 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) + addr := target.Addr + if _, _, err := net.SplitHostPort(addr); err != nil { + addr += ":0" + } + cc, err := h.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, diff --git a/handler/relay/bind.go b/handler/relay/bind.go index f137e6f..8ccdd62 100644 --- a/handler/relay/bind.go +++ b/handler/relay/bind.go @@ -13,6 +13,7 @@ import ( "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" + metrics "github.com/go-gost/x/metrics/wrapper" xservice "github.com/go-gost/x/service" "github.com/google/uuid" ) @@ -129,23 +130,32 @@ 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) + pc, err = net.ListenUDP(network, bindAddr) if err != nil { log.Error(err) return err } + + serviceName := fmt.Sprintf("%s-ep-%s", h.options.Service, pc.LocalAddr()) + log = log.WithFields(map[string]any{ + "service": serviceName, + "listener": "udp", + "handler": "ep-udp", + "bind": fmt.Sprintf("%s/%s", pc.LocalAddr(), pc.LocalAddr().Network()), + }) + pc = metrics.WrapPacketConn(serviceName, pc) + // pc = admission.WrapPacketConn(l.options.Admission, pc) + // pc = limiter.WrapPacketConn(l.options.TrafficLimiter, pc) + defer pc.Close() af := &relay.AddrFeature{} - err = af.ParseFrom(pc.LocalAddr().String()) - if err != nil { + if err := af.ParseFrom(pc.LocalAddr().String()); err != nil { log.Warn(err) } - - // Issue: may not reachable when host has multi-interface - af.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) - af.AType = relay.AddrIPv4 resp.Features = append(resp.Features, af) if _, err := resp.WriteTo(conn); err != nil { log.Error(err) @@ -183,7 +193,6 @@ func (h *relayHandler) handleBindTunnel(ctx context.Context, conn net.Conn, netw resp.WriteTo(conn) return } - connectorID := relay.NewConnectorID(uuid[:]) if network == "udp" { connectorID = relay.NewUDPConnectorID(uuid[:]) diff --git a/handler/relay/connect.go b/handler/relay/connect.go index 062f89a..2598771 100644 --- a/handler/relay/connect.go +++ b/handler/relay/connect.go @@ -123,11 +123,10 @@ func (h *relayHandler) handleConnectTunnel(ctx context.Context, conn net.Conn, n if ingress := h.md.ingress; ingress != nil { tid = parseTunnelID(ingress.Get(host)) } - - if !tid.Equal(tunnelID) { + if !tid.Equal(tunnelID) && !h.md.directTunnel { resp.Status = relay.StatusBadRequest resp.WriteTo(conn) - err := fmt.Errorf("tunnel %s not found", tunnelID.String()) + err := fmt.Errorf("not route to host %s", host) log.Error(err) return err } diff --git a/handler/relay/entrypoint.go b/handler/relay/entrypoint.go index 8975621..7c7701d 100644 --- a/handler/relay/entrypoint.go +++ b/handler/relay/entrypoint.go @@ -177,8 +177,13 @@ func (h *tunnelHandler) Handle(ctx context.Context, conn net.Conn, opts ...handl if h.ingress != nil { tunnelID = parseTunnelID(h.ingress.Get(host)) } + if tunnelID.IsZero() { + err := fmt.Errorf("no route to host %s", host) + log.Error(err) + return err + } if tunnelID.IsPrivate() { - err := fmt.Errorf("access denied: tunnel %s is private", tunnelID) + err := fmt.Errorf("access denied: tunnel %s is private for host %s", tunnelID, host) log.Error(err) return err } diff --git a/handler/relay/metadata.go b/handler/relay/metadata.go index 50ab5c3..6f40c2b 100644 --- a/handler/relay/metadata.go +++ b/handler/relay/metadata.go @@ -21,6 +21,7 @@ type metadata struct { hash string entryPoint string ingress ingress.Ingress + directTunnel bool } func (h *relayHandler) parseMetadata(md mdata.Metadata) (err error) { @@ -47,13 +48,23 @@ func (h *relayHandler) parseMetadata(md mdata.Metadata) (err error) { h.md.entryPoint = mdutil.GetString(md, entryPoint) h.md.ingress = registry.IngressRegistry().Get(mdutil.GetString(md, "ingress")) + h.md.directTunnel = mdutil.GetBool(md, "tunnel.direct") if h.md.ingress == nil { - if ss := strings.Split(mdutil.GetString(md, "tunnel"), ":"); len(ss) == 2 { + var rules []xingress.Rule + for _, s := range strings.Split(mdutil.GetString(md, "tunnel"), ",") { + ss := strings.SplitN(s, ":", 2) + if len(ss) != 2 { + continue + } + rules = append(rules, xingress.Rule{ + Hostname: ss[0], + Endpoint: ss[1], + }) + } + if len(rules) > 0 { h.md.ingress = xingress.NewIngress( - xingress.RulesOption([]xingress.Rule{ - {Host: ss[0], Endpoint: ss[1]}, - }), + xingress.RulesOption(rules), xingress.LoggerOption(logger.Default().WithFields(map[string]any{ "kind": "ingress", })), diff --git a/handler/relay/tunnel.go b/handler/relay/tunnel.go index b4849ec..1cc9ada 100644 --- a/handler/relay/tunnel.go +++ b/handler/relay/tunnel.go @@ -87,14 +87,9 @@ func (t *Tunnel) GetConnector(network string) *Connector { var connectors []*Connector for _, c := range t.connectors { - if network == "udp" { - if c.id.IsUDP() { - connectors = append(connectors, c) - } - } else { - if !c.id.IsUDP() { - connectors = append(connectors, c) - } + if network == "udp" && c.id.IsUDP() || + network != "udp" && !c.id.IsUDP() { + connectors = append(connectors, c) } } if len(connectors) == 0 { @@ -181,14 +176,14 @@ func parseTunnelID(s string) (tid relay.TunnelID) { return relay.NewTunnelID(uuid[:]) } -func getTunnelConn(network string, pool *ConnectorPool, tunnelID relay.TunnelID, retry int, log logger.Logger) (conn net.Conn, err error) { +func getTunnelConn(network string, pool *ConnectorPool, tid relay.TunnelID, retry int, log logger.Logger) (conn net.Conn, err error) { if retry <= 0 { retry = 1 } for i := 0; i < retry; i++ { - c := pool.Get(network, tunnelID) + c := pool.Get(network, tid) if c == nil { - err = fmt.Errorf("tunnel %s not available", tunnelID.String()) + err = fmt.Errorf("tunnel %s not available", tid.String()) break } diff --git a/ingress/ingress.go b/ingress/ingress.go index 238796a..aa656dc 100644 --- a/ingress/ingress.go +++ b/ingress/ingress.go @@ -15,7 +15,7 @@ import ( ) type Rule struct { - Host string + Hostname string Endpoint string } @@ -122,10 +122,10 @@ func (ing *ingress) reload(ctx context.Context) error { rules := make(map[string]Rule) fn := func(rule Rule) { - if rule.Host == "" || rule.Endpoint == "" { + if rule.Hostname == "" || rule.Endpoint == "" { return } - host := rule.Host + host := rule.Hostname if host[0] == '*' { host = host[1:] } @@ -210,7 +210,7 @@ func (ing *ingress) parseRules(r io.Reader) (rules []Rule, err error) { scanner := bufio.NewScanner(r) for scanner.Scan() { - if rule := ing.parseLine(scanner.Text()); rule.Host != "" { + if rule := ing.parseLine(scanner.Text()); rule.Hostname != "" { rules = append(rules, rule) } } @@ -287,7 +287,7 @@ func (ing *ingress) parseLine(s string) (rule Rule) { } return Rule{ - Host: sp[0], + Hostname: sp[0], Endpoint: sp[1], } }