diff --git a/controllers/ipservice.go b/controllers/ipservice.go index 56d0f8cc..6ca80e39 100644 --- a/controllers/ipservice.go +++ b/controllers/ipservice.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/gorilla/mux" + "github.com/gravitl/netmaker/netclient/ncutils" ) func ipHandlers(r *mux.Router) { @@ -38,7 +39,7 @@ func parseIP(r *http.Request) (string, error) { // Get Public IP from header ip := r.Header.Get("X-REAL-IP") ipnet := net.ParseIP(ip) - if ipnet != nil && !ipIsPrivate(ipnet) { + if ipnet != nil && !ncutils.IpIsPrivate(ipnet) { return ip, nil } @@ -47,7 +48,7 @@ func parseIP(r *http.Request) (string, error) { iplist := strings.Split(forwardips, ",") for _, ip := range iplist { ipnet := net.ParseIP(ip) - if ipnet != nil && !ipIsPrivate(ipnet) { + if ipnet != nil && !ncutils.IpIsPrivate(ipnet) { return ip, nil } } @@ -59,14 +60,10 @@ func parseIP(r *http.Request) (string, error) { } ipnet = net.ParseIP(ip) if ipnet != nil { - if ipIsPrivate(ipnet) { + if ncutils.IpIsPrivate(ipnet) { return ip, fmt.Errorf("ip is a private address") } return ip, nil } return "", fmt.Errorf("no ip found") } - -func ipIsPrivate(ipnet net.IP) bool { - return ipnet.IsPrivate() || ipnet.IsLoopback() -} diff --git a/netclient/local/routes.go b/netclient/local/routes.go index 104265b2..aa4fdb96 100644 --- a/netclient/local/routes.go +++ b/netclient/local/routes.go @@ -12,6 +12,17 @@ import ( // SetPeerRoutes - sets/removes ip routes for each peer on a network func SetPeerRoutes(iface string, oldPeers map[string]bool, newPeers []wgtypes.PeerConfig) { + + // get the default route + var hasRoute bool + gwIP, gwIface, err := GetDefaultRoute() + if err != nil { + logger.Log(0, "error getting default route:", err.Error()) + } + if gwIP != "" && gwIface != "" && err == nil { + hasRoute = true + } + // traverse through all recieved peers for _, peer := range newPeers { for _, allowedIP := range peer.AllowedIPs { @@ -23,6 +34,13 @@ func SetPeerRoutes(iface string, oldPeers map[string]bool, newPeers []wgtypes.Pe delete(oldPeers, allowedIP.String()) } } + if hasRoute && !ncutils.IpIsPrivate(peer.Endpoint.IP) { + ipNet, err := ncutils.GetIPNetFromString(peer.Endpoint.IP.String()) + if err != nil { + logger.Log(0, "error parsing ip:", err.Error()) + } + setRoute(gwIface, &ipNet, gwIP) + } } // traverse through all remaining existing peers for i := range oldPeers { @@ -37,19 +55,55 @@ func SetPeerRoutes(iface string, oldPeers map[string]bool, newPeers []wgtypes.Pe // SetCurrentPeerRoutes - sets all the current peers func SetCurrentPeerRoutes(iface, currentAddr string, peers []wgtypes.PeerConfig) { + + // get the default route + var hasRoute bool + gwIP, gwIface, err := GetDefaultRoute() + if err != nil { + logger.Log(0, "error getting default route:", err.Error()) + } + if gwIP != "" && gwIface != "" && err == nil { + hasRoute = true + } + + // traverse through all recieved peers for _, peer := range peers { for _, allowedIP := range peer.AllowedIPs { setRoute(iface, &allowedIP, currentAddr) } + if hasRoute && !ncutils.IpIsPrivate(peer.Endpoint.IP) { + ipNet, err := ncutils.GetIPNetFromString(peer.Endpoint.IP.String()) + if err != nil { + logger.Log(0, "error parsing ip:", err.Error()) + } + setRoute(gwIface, &ipNet, gwIP) + } } } // FlushPeerRoutes - removes all current peer routes func FlushPeerRoutes(iface, currentAddr string, peers []wgtypes.Peer) { + // get the default route + var hasRoute bool + gwIP, gwIface, err := GetDefaultRoute() + if err != nil { + logger.Log(0, "error getting default route:", err.Error()) + } + if gwIP != "" && gwIface != "" && err == nil { + hasRoute = true + } + for _, peer := range peers { for _, allowedIP := range peer.AllowedIPs { deleteRoute(iface, &allowedIP, currentAddr) } + if hasRoute && !ncutils.IpIsPrivate(peer.Endpoint.IP) { + ipNet, err := ncutils.GetIPNetFromString(peer.Endpoint.IP.String()) + if err != nil { + logger.Log(0, "error parsing ip:", err.Error()) + } + deleteRoute(gwIface, &ipNet, gwIP) + } } } diff --git a/netclient/local/routes_darwin.go b/netclient/local/routes_darwin.go index d6886c51..0d33fb70 100644 --- a/netclient/local/routes_darwin.go +++ b/netclient/local/routes_darwin.go @@ -9,6 +9,44 @@ import ( "github.com/gravitl/netmaker/netclient/ncutils" ) +// GetDefaultRoute - Gets the default route (ip and interface) on a mac machine +func GetDefaultRoute() (string, string, error) { + var ipaddr string + var iface string + var err error + var outLine string + output, err := ncutils.RunCmd("netstat -nr", false) + for _, line := range strings.Split(strings.TrimSuffix(output, "\n"), "\n") { + if strings.Contains(line, "default") { + outLine = line + break + } + } + space := regexp.MustCompile(`\s+`) + outFormatted := space.ReplaceAllString(outLine, " ") + if err != nil { + return ipaddr, iface, err + } + outputSlice := strings.Split(string(outFormatted), " ") + if !strings.Contains(outputSlice[0], "default") { + return ipaddr, iface, fmt.Errorf("could not find default gateway") + } + ipaddr = outputSlice[1] + if err = checkIPAddress(ipaddr); err != nil { + return ipaddr, iface, err + } + iface = outputSlice[3] + + return ipaddr, iface, err +} + +func checkIPAddress(ip string) error { + if net.ParseIP(ip) == nil { + return fmt.Errorf("IP Address: %s - Invalid", ip) + } + return nil +} + // route -n add -net 10.0.0.0/8 192.168.0.254 // networksetup -setadditionalroutes Ethernet 192.168.1.0 255.255.255.0 10.0.0.2 persistent func setRoute(iface string, addr *net.IPNet, address string) error { diff --git a/netclient/local/routes_freebsd.go b/netclient/local/routes_freebsd.go index 0e71e714..a63b1cc5 100644 --- a/netclient/local/routes_freebsd.go +++ b/netclient/local/routes_freebsd.go @@ -8,6 +8,32 @@ import ( "github.com/gravitl/netmaker/netclient/ncutils" ) +// GetDefaultRoute - Gets the default route (ip and interface) on a freebsd machine +func GetDefaultRoute() (string, string, error) { + var ipaddr string + var iface string + var err error + + output, err := ncutils.RunCmd("route show default", true) + if err != nil { + return ipaddr, iface, err + } + outFormatted := strings.ReplaceAll(output, "\n", "") + if !strings.Contains(outFormatted, "default") && !strings.Contains(outFormatted, "interface:") { + return ipaddr, iface, fmt.Errorf("could not find default gateway") + } + outputSlice := strings.Split(string(outFormatted), " ") + for i, outString := range outputSlice { + if outString == "gateway:" { + ipaddr = outputSlice[i+1] + } + if outString == "interface:" { + iface = outputSlice[i+1] + } + } + return ipaddr, iface, err +} + func setRoute(iface string, addr *net.IPNet, address string) error { var err error _, _ = ncutils.RunCmd("route add -net "+addr.String()+" -interface "+iface, false) diff --git a/netclient/local/routes_linux.go b/netclient/local/routes_linux.go index d6854f68..c7decf75 100644 --- a/netclient/local/routes_linux.go +++ b/netclient/local/routes_linux.go @@ -12,6 +12,30 @@ import ( "github.com/gravitl/netmaker/netclient/ncutils" ) +// GetDefaultRoute - Gets the default route (ip and interface) on a linux machine +func GetDefaultRoute() (string, string, error) { + var ipaddr string + var iface string + var err error + output, err := ncutils.RunCmd("ip route show default", false) + if err != nil { + return ipaddr, iface, err + } + outputSlice := strings.Split(output, " ") + if !strings.Contains(outputSlice[0], "default") { + return ipaddr, iface, fmt.Errorf("could not find default gateway") + } + for i, outString := range outputSlice { + if outString == "via" { + ipaddr = outputSlice[i+1] + } + if outString == "dev" { + iface = outputSlice[i+1] + } + } + return ipaddr, iface, err +} + func setRoute(iface string, addr *net.IPNet, address string) error { out, err := ncutils.RunCmd(fmt.Sprintf("ip route get %s", addr.IP.String()), false) if err != nil || !strings.Contains(out, iface) { diff --git a/netclient/local/routes_windows.go b/netclient/local/routes_windows.go index 9c635ad6..70e7b0d4 100644 --- a/netclient/local/routes_windows.go +++ b/netclient/local/routes_windows.go @@ -7,6 +7,15 @@ import ( "github.com/gravitl/netmaker/netclient/ncutils" ) +// GetDefaultRoute - Gets the default route (ip and interface) on a linux machine +func GetDefaultRoute() (string, string, error) { + var ipaddr string + var iface string + var err error + + return ipaddr, iface, fmt.Errorf("not written yet on windows") +} + func setRoute(iface string, addr *net.IPNet, address string) error { var err error _, err = ncutils.RunCmd("route ADD "+addr.String()+" "+address, false) diff --git a/netclient/ncutils/iface.go b/netclient/ncutils/iface.go index 6cc10265..6ea08c15 100644 --- a/netclient/ncutils/iface.go +++ b/netclient/ncutils/iface.go @@ -90,3 +90,7 @@ func IfaceExists(ifacename string) bool { } return false } + +func IpIsPrivate(ipnet net.IP) bool { + return ipnet.IsPrivate() || ipnet.IsLoopback() +}