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-08-24 11:13:41 +00:00
committed by Cuong Manh Le
parent 073af0f89c
commit 94a0530991

View File

@@ -1,10 +1,12 @@
package cli
import (
"bytes"
"errors"
"fmt"
"math/rand"
"net"
"net/netip"
"net/url"
"os"
"runtime"
@@ -364,29 +366,58 @@ func errUrlNetworkError(err error) bool {
return false
}
// defaultRouteIP returns IP string of the default route if present, prefer IPv4 over IPv6.
func defaultRouteIP() string {
if dr, err := interfaces.DefaultRoute(); err == nil {
if netIface, err := netInterface(dr.InterfaceName); err == nil {
addrs, _ := netIface.Addrs()
do := func(v4 bool) net.IP {
for _, addr := range addrs {
if netIP, ok := addr.(*net.IPNet); ok && netIP.IP.IsPrivate() {
if v4 {
return netIP.IP.To4()
}
return netIP.IP
}
func ifaceFirstPrivateIP(iface *net.Interface) string {
if iface == nil {
return ""
}
do := func(addrs []net.Addr, v4 bool) net.IP {
for _, addr := range addrs {
if netIP, ok := addr.(*net.IPNet); ok && netIP.IP.IsPrivate() {
if v4 {
return netIP.IP.To4()
}
return nil
}
if ip := do(true); ip != nil {
return ip.String()
}
if ip := do(false); ip != nil {
return ip.String()
return netIP.IP
}
}
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 ""
}