Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NET-748: Handle Peer with nil IP, fallback to ip service if stun fails #631

Merged
merged 9 commits into from
Nov 16, 2023
14 changes: 14 additions & 0 deletions functions/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
4 changes: 1 addition & 3 deletions functions/mqhandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -347,7 +346,6 @@ func handleEndpointDetection(peers []wgtypes.PeerConfig, peerInfo models.HostInf
peerInfo.ListenPort,
)
}

}
}
}
Expand Down
8 changes: 0 additions & 8 deletions functions/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
37 changes: 37 additions & 0 deletions ncutils/netclientutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"io"
"log"
"net"
"net/http"
"os"
"os/exec"
"regexp"
Expand Down Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion nmproxy/stun/stun.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
4 changes: 2 additions & 2 deletions nmproxy/wg/wg.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
}
Expand Down
11 changes: 10 additions & 1 deletion wireguard/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions wireguard/wireguard.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
Expand Down