diff --git a/functions/daemon.go b/functions/daemon.go index df141ee5..a1439741 100644 --- a/functions/daemon.go +++ b/functions/daemon.go @@ -477,6 +477,20 @@ func holePunchWgPort() (pubIP net.IP, pubPort int, natType string) { portToStun := config.Netclient().ListenPort pubIP, pubPort, natType = stun.HolePunch(portToStun) + if pubIP == nil { // if stun has failed fallback to ip service to get publicIP + var api string + server := config.GetServer(config.CurrServer) + if server != nil { + api = server.API + } + publicIP, err := ncutils.GetPublicIP(api) + if err != nil { + slog.Error("failed to get publicIP", "error", err) + return + } + pubIP = publicIP + pubPort = portToStun + } return } diff --git a/functions/mqhandlers.go b/functions/mqhandlers.go index a8fca7cf..ef8d35ef 100644 --- a/functions/mqhandlers.go +++ b/functions/mqhandlers.go @@ -326,7 +326,7 @@ func handleEndpointDetection(peers []wgtypes.PeerConfig, peerInfo models.HostInf for i := range peerInfo.Interfaces { peerIface := peerInfo.Interfaces[i] peerIP := peerIface.Address.IP - if peers[idx].Endpoint == nil || peerIP == nil { + if peerIP == nil { continue } // check to skip bridge network @@ -336,7 +336,6 @@ func handleEndpointDetection(peers []wgtypes.PeerConfig, peerInfo models.HostInf if strings.Contains(peerIP.String(), "127.0.0.") || peerIP.IsMulticast() || (peerIP.IsLinkLocalUnicast() && strings.Count(peerIP.String(), ":") >= 2) || - peers[idx].Endpoint.IP.Equal(peerIP) || isAddressInPeers(peerIP, currentCidrs) { continue } @@ -347,7 +346,6 @@ func handleEndpointDetection(peers []wgtypes.PeerConfig, peerInfo models.HostInf peerInfo.ListenPort, ) } - } } } diff --git a/functions/register.go b/functions/register.go index ed247025..76062d1f 100644 --- a/functions/register.go +++ b/functions/register.go @@ -101,14 +101,6 @@ func doubleCheck(host *config.Config, apiServer string) (shouldUpdate bool, err } } - if host.EndpointIP == nil || host.WgPublicListenPort == 0 || host.NatType == "" { - publicIp, publicPort, natType := holePunchWgPort() - host.EndpointIP = publicIp - host.WgPublicListenPort = publicPort - host.NatType = natType - shouldUpdateHost = true - } - if shouldUpdateHost { config.UpdateNetclient(*host) config.WriteNetclientConfig() diff --git a/ncutils/netclientutils.go b/ncutils/netclientutils.go index 328e4723..0689d30e 100644 --- a/ncutils/netclientutils.go +++ b/ncutils/netclientutils.go @@ -12,6 +12,7 @@ import ( "io" "log" "net" + "net/http" "os" "os/exec" "regexp" @@ -119,6 +120,42 @@ func IsEmptyRecord(err error) bool { return strings.Contains(err.Error(), NoDBRecord) || strings.Contains(err.Error(), NoDBRecords) } +// GetPublicIP - gets public ip +func GetPublicIP(api string) (net.IP, error) { + + iplist := []string{"https://ip.client.gravitl.com", "https://ifconfig.me", "https://api.ipify.org", "https://ipinfo.io/ip"} + + if api != "" { + api = "https://" + api + "/api/getip" + iplist = append([]string{api}, iplist...) + } + + endpoint := "" + var err error + for _, ipserver := range iplist { + client := &http.Client{ + Timeout: time.Second * 10, + } + resp, err := client.Get(ipserver) + if err != nil { + continue + } + defer resp.Body.Close() + if resp.StatusCode == http.StatusOK { + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + continue + } + endpoint = string(bodyBytes) + break + } + } + if err == nil && endpoint == "" { + err = errors.New("public address not found") + } + return net.ParseIP(endpoint), err +} + // GetMacAddr - get's mac address func GetMacAddr() ([]net.HardwareAddr, error) { ifas, err := net.Interfaces() diff --git a/nmproxy/stun/stun.go b/nmproxy/stun/stun.go index 0dde78a4..c28a9401 100644 --- a/nmproxy/stun/stun.go +++ b/nmproxy/stun/stun.go @@ -73,7 +73,7 @@ func HolePunch(portToStun int) (publicIP net.IP, publicPort int, natType string) slog.Debug(fmt.Sprintf("hole punching port %d via stun server %s:%d", portToStun, stunServer.Domain, stunServer.Port)) publicIP, publicPort, natType, err = doStunTransaction(l, s) if err != nil { - logger.Log(0, "stun transaction failed: ", stunServer.Domain, err.Error()) + logger.Log(3, "stun transaction failed: ", stunServer.Domain, err.Error()) continue } if publicPort == 0 || publicIP == nil || publicIP.IsUnspecified() { diff --git a/nmproxy/wg/wg.go b/nmproxy/wg/wg.go index 7bed6596..de17ba7e 100644 --- a/nmproxy/wg/wg.go +++ b/nmproxy/wg/wg.go @@ -38,7 +38,7 @@ func (w *WGIface) UpdatePeerEndpoint(peer wgtypes.PeerConfig) error { w.mu.Lock() defer w.mu.Unlock() - logger.Log(0, fmt.Sprintf("updating interface %s peer %s: endpoint %s ", w.Name, peer.PublicKey.String(), peer.Endpoint.String())) + logger.Log(0, fmt.Sprintf("updating interface %s peer %s: endpoint %s ", w.Name, peer.PublicKey.String(), peer.Endpoint)) // //parse allowed ips // _, ipNet, err := net.ParseCIDR(allowedIps) @@ -57,7 +57,7 @@ func (w *WGIface) UpdatePeerEndpoint(peer wgtypes.PeerConfig) error { } err := w.configureDevice(config) if err != nil { - return fmt.Errorf("received error \"%v\" while updating peer on interface %s with settings: endpoint %s", err, w.Name, peer.Endpoint.String()) + return fmt.Errorf("received error \"%v\" while updating peer on interface %s with settings: endpoint %s", err, w.Name, peer.Endpoint) } return nil } diff --git a/wireguard/types.go b/wireguard/types.go index 6c7c9471..741e8018 100644 --- a/wireguard/types.go +++ b/wireguard/types.go @@ -59,12 +59,21 @@ func NewNCIface(host *config.Config, nodes config.NodeMap) *NCIface { FirewallMark: &firewallMark, ListenPort: &host.ListenPort, ReplacePeers: true, - Peers: peers, + Peers: cleanUpPeers(peers), }, } return &netmaker } +func cleanUpPeers(peers []wgtypes.PeerConfig) []wgtypes.PeerConfig { + for i, peer := range peers { + if peer.Endpoint != nil && peer.Endpoint.IP == nil { + peers[i].Endpoint = nil + } + } + return peers +} + // ifaceAddress - interface parsed address type ifaceAddress struct { IP net.IP diff --git a/wireguard/wireguard.go b/wireguard/wireguard.go index 7364aca6..65c6a430 100644 --- a/wireguard/wireguard.go +++ b/wireguard/wireguard.go @@ -18,6 +18,9 @@ func SetPeers(replace bool) error { peers := config.Netclient().HostPeers for i := range peers { peer := peers[i] + if peer.Endpoint != nil && peer.Endpoint.IP == nil { + peers[i].Endpoint = nil + } if !peer.Remove && checkForBetterEndpoint(&peer) { peers[i] = peer } @@ -62,9 +65,6 @@ func apply(c *wgtypes.Config) error { // returns if better endpoint has been calculated for this peer already // if so sets it and returns true func checkForBetterEndpoint(peer *wgtypes.PeerConfig) bool { - if peer.Endpoint == nil { - return false - } if endpoint, ok := cache.EndpointCache.Load(peer.PublicKey.String()); ok && endpoint != nil { var cacheEndpoint cache.EndpointCacheValue cacheEndpoint, ok = endpoint.(cache.EndpointCacheValue)