feat(router): add 'auto' interface for source-in source-out on multi-homed hosts
When a router is configured with interface: "auto", the outbound socket is bound to the same IP that received the incoming connection (read from DstAddr in context, which is conn.LocalAddr() from the service accept loop). This enables the 源进源出 (source-in source-out) pattern without requiring a hardcoded interface name. Supports comma-separated interface lists (e.g. "auto,eth1") where only the "auto" token is replaced with the detected ingress IP. Falls back to the original string when the ingress address is INADDR_ANY, loopback, or unavailable, so the remaining entries still take effect. Closes go-gost/gost#341
This commit is contained in:
+27
-1
@@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/core/chain"
|
"github.com/go-gost/core/chain"
|
||||||
@@ -141,9 +142,34 @@ func (r *Router) dial(ctx context.Context, network, address string, log logger.L
|
|||||||
if route == nil {
|
if route == nil {
|
||||||
route = DefaultRoute
|
route = DefaultRoute
|
||||||
}
|
}
|
||||||
|
ifceName := r.options.IfceName
|
||||||
|
if strings.Contains(ifceName, "auto") {
|
||||||
|
// "auto" triggers per-connection interface detection: the
|
||||||
|
// ingress IP (conn.LocalAddr()) is used as the bind address,
|
||||||
|
// ensuring egress traffic leaves via the same interface that
|
||||||
|
// received the connection — the "source-in source-out"
|
||||||
|
// pattern for multi-homed hosts.
|
||||||
|
if dstAddr := xctx.DstAddrFromContext(ctx); dstAddr != nil {
|
||||||
|
if host, _, _ := net.SplitHostPort(dstAddr.String()); host != "" &&
|
||||||
|
host != "0.0.0.0" && host != "::" {
|
||||||
|
// Replace only exact "auto" tokens in the
|
||||||
|
// comma-separated interface list.
|
||||||
|
parts := strings.Split(ifceName, ",")
|
||||||
|
for i, p := range parts {
|
||||||
|
if p == "auto" {
|
||||||
|
parts[i] = host
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ifceName = strings.Join(parts, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.Contains(ifceName, "auto") {
|
||||||
|
log.Debugf("auto interface: no suitable ingress address, keeping literal %q", ifceName)
|
||||||
|
}
|
||||||
|
}
|
||||||
conn, err = route.Dial(ctx, network, ipAddr,
|
conn, err = route.Dial(ctx, network, ipAddr,
|
||||||
append([]chain.DialOption{
|
append([]chain.DialOption{
|
||||||
chain.InterfaceDialOption(r.options.IfceName),
|
chain.InterfaceDialOption(ifceName),
|
||||||
chain.NetnsDialOption(r.options.Netns),
|
chain.NetnsDialOption(r.options.Netns),
|
||||||
chain.SockOptsDialOption(r.options.SockOpts),
|
chain.SockOptsDialOption(r.options.SockOpts),
|
||||||
chain.LoggerDialOption(log),
|
chain.LoggerDialOption(log),
|
||||||
|
|||||||
Reference in New Issue
Block a user