diff --git a/common/utils.go b/common/utils.go index 42bba2a..2f0ab22 100644 --- a/common/utils.go +++ b/common/utils.go @@ -13,7 +13,9 @@ import ( "encoding/hex" "fmt" internal "github.com/daeuniverse/dae/pkg/ebpf_internal" + "github.com/vishvananda/netlink" "golang.org/x/net/dns/dnsmessage" + "golang.org/x/sys/unix" "net/netip" "net/url" "path/filepath" @@ -68,6 +70,9 @@ func Ipv6Uint32ArrayToByteSlice(_ip [4]uint32) (ip []byte) { } func Deduplicate(list []string) []string { + if list == nil { + return nil + } res := make([]string, 0, len(list)) m := make(map[string]struct{}) for _, v := range list { @@ -415,3 +420,32 @@ func Ntohs(i uint16) uint16 { bytes := *(*[2]byte)(unsafe.Pointer(&i)) return binary.BigEndian.Uint16(bytes[:]) } + +func GetDefaultIfnames() (defaultIfs []string, err error) { + linkList, err := netlink.LinkList() + if err != nil { + return nil, err + } +nextLink: + for _, link := range linkList { + if link.Attrs().Flags&unix.RTF_UP != unix.RTF_UP { + // Interface is down. + continue + } + for _, family := range []int{unix.AF_INET, unix.AF_INET6} { + rs, err := netlink.RouteList(link, family) + if err != nil { + return nil, err + } + for _, route := range rs { + if route.Dst != nil { + continue + } + // Have no dst, it is a default route. + defaultIfs = append(defaultIfs, link.Attrs().Name) + continue nextLink + } + } + } + return Deduplicate(defaultIfs), nil +} diff --git a/config/desc.go b/config/desc.go index 77366f3..2679129 100644 --- a/config/desc.go +++ b/config/desc.go @@ -42,7 +42,7 @@ var GlobalDesc = Desc{ "check_interval": "Interval of connectivity check for TCP and UDP", "check_tolerance": "Group will switch node only when new_latency <= old_latency - tolerance.", "lan_interface": "The LAN interface to bind. Use it if you only want to proxy LAN instead of localhost.", - "wan_interface": "The WAN interface to bind. Use it if you want to proxy localhost.", + "wan_interface": "The WAN interface to bind. Use it if you want to proxy localhost. Use \"auto\" to auto detect.", "allow_insecure": "Allow insecure TLS certificates. It is not recommended to turn it on unless you have to.", "dial_mode": `Optional values of dial_mode are: 1. "ip". Dial proxy using the IP from DNS directly. This allows your ipv4, ipv6 to choose the optimal path respectively, and makes the IP version requested by the application meet expectations. For example, if you use curl -4 ip.sb, you will request IPv4 via proxy and get a IPv4 echo. And curl -6 ip.sb will request IPv6. This may solve some wierd full-cone problem if your are be your node support that. diff --git a/control/control_plane.go b/control/control_plane.go index ddd93ad..d9cc2c0 100644 --- a/control/control_plane.go +++ b/control/control_plane.go @@ -186,6 +186,7 @@ func NewControlPlane( if err = core.setupRoutingPolicy(); err != nil { return nil, err } + global.LanInterface = common.Deduplicate(global.LanInterface) for _, ifname := range global.LanInterface { if err = core.bindLan(ifname); err != nil { return nil, fmt.Errorf("bindLan: %v: %w", ifname, err) @@ -193,6 +194,20 @@ func NewControlPlane( } } // Bind to WAN + // preprocess "auto". + ifs := make([]string, 0, len(global.WanInterface)+2) + for _, ifname := range global.WanInterface { + if ifname == "auto" { + defaultIfs, err := common.GetDefaultIfnames() + if err != nil { + return nil, fmt.Errorf("failed to convert 'auto': %w", err) + } + ifs = append(ifs, defaultIfs...) + } else { + ifs = append(ifs, ifname) + } + } + global.WanInterface = common.Deduplicate(ifs) if len(global.WanInterface) > 0 { if err = core.setupSkPidMonitor(); err != nil { return nil, err diff --git a/docs/getting-started/README.md b/docs/getting-started/README.md index 396c89d..ff926c0 100644 --- a/docs/getting-started/README.md +++ b/docs/getting-started/README.md @@ -133,7 +133,7 @@ However, this config leaves dae no-load state. If you want dae to be in working global { # Bind to LAN and/or WAN as you want. Replace the interface name to your own. #lan_interface: docker0 - wan_interface: wlp5s0 + wan_interface: auto # Use "auto" to auto detect WAN interface. log_level: info allow_insecure: false diff --git a/example.dae b/example.dae index cc3ee05..55561b3 100644 --- a/example.dae +++ b/example.dae @@ -26,8 +26,8 @@ global { #lan_interface: docker0 # The WAN interface to bind. Use it if you want to proxy localhost. - # Multiple interfaces split by ",". - wan_interface: wlp5s0 + # Multiple interfaces split by ",". Use "auto" to auto detect. + wan_interface: auto # Allow insecure TLS certificates. It is not recommended to turn it on unless you have to. allow_insecure: false