cmd/cli: fix default route IP with public interface

For reporting router queries, ctrld uses private IP of the default route
interface. However, when the default route is conntected directly to
ISP, the interface will have a public IP, and another interface with the
same MAC address will be created for LAN ip. So when no private IP found
for default route interface, ctrld must look at the other interface to
find the corret LAN ip.
This commit is contained in:
Cuong Manh Le
2023-09-22 18:38:40 +07:00
committed by Cuong Manh Le
parent 073af0f89c
commit 94a0530991
+51 -20
View File
@@ -1,10 +1,12 @@
package cli package cli
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"math/rand" "math/rand"
"net" "net"
"net/netip"
"net/url" "net/url"
"os" "os"
"runtime" "runtime"
@@ -364,29 +366,58 @@ func errUrlNetworkError(err error) bool {
return false return false
} }
// defaultRouteIP returns IP string of the default route if present, prefer IPv4 over IPv6. func ifaceFirstPrivateIP(iface *net.Interface) string {
func defaultRouteIP() string { if iface == nil {
if dr, err := interfaces.DefaultRoute(); err == nil { return ""
if netIface, err := netInterface(dr.InterfaceName); err == nil { }
addrs, _ := netIface.Addrs() do := func(addrs []net.Addr, v4 bool) net.IP {
do := func(v4 bool) net.IP { for _, addr := range addrs {
for _, addr := range addrs { if netIP, ok := addr.(*net.IPNet); ok && netIP.IP.IsPrivate() {
if netIP, ok := addr.(*net.IPNet); ok && netIP.IP.IsPrivate() { if v4 {
if v4 { return netIP.IP.To4()
return netIP.IP.To4()
}
return netIP.IP
}
} }
return nil return netIP.IP
}
if ip := do(true); ip != nil {
return ip.String()
}
if ip := do(false); ip != nil {
return ip.String()
} }
} }
return nil
}
addrs, _ := iface.Addrs()
if ip := do(addrs, true); ip != nil {
return ip.String()
}
if ip := do(addrs, false); ip != nil {
return ip.String()
}
return ""
}
// defaultRouteIP returns private IP string of the default route if present, prefer IPv4 over IPv6.
func defaultRouteIP() string {
dr, err := interfaces.DefaultRoute()
if err != nil {
return ""
}
drNetIface, err := netInterface(dr.InterfaceName)
if err != nil {
return ""
}
if ip := ifaceFirstPrivateIP(drNetIface); ip != "" {
return ip
}
// If we reach here, it means the default route interface is connected directly to ISP.
// We need to find the LAN interface with the same Mac address with drNetIface.
var drLanNetIface *net.Interface
interfaces.ForeachInterface(func(i interfaces.Interface, prefixes []netip.Prefix) {
if i.Name == drNetIface.Name {
return
}
if bytes.Equal(i.HardwareAddr, drNetIface.HardwareAddr) {
drLanNetIface = i.Interface
}
})
if ip := ifaceFirstPrivateIP(drLanNetIface); ip != "" {
return ip
} }
return "" return ""
} }