relay: add direct routing for tunnel

This commit is contained in:
ginuerzh 2023-02-06 21:16:56 +08:00
parent 02a5f4dde4
commit 6f9f5ce6ab
9 changed files with 58 additions and 36 deletions

View File

@ -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,
})
}

View File

@ -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

View File

@ -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,

View File

@ -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[:])

View File

@ -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
}

View File

@ -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
}

View File

@ -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",
})),

View File

@ -87,15 +87,10 @@ func (t *Tunnel) GetConnector(network string) *Connector {
var connectors []*Connector
for _, c := range t.connectors {
if network == "udp" {
if c.id.IsUDP() {
if network == "udp" && c.id.IsUDP() ||
network != "udp" && !c.id.IsUDP() {
connectors = append(connectors, c)
}
} else {
if !c.id.IsUDP() {
connectors = append(connectors, c)
}
}
}
if len(connectors) == 0 {
return nil
@ -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
}

View File

@ -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],
}
}