Adam Ierymenko 6 years ago
parent
commit
536bc59abb
5 changed files with 390 additions and 55 deletions
  1. 145 0
      go/pkg/zerotier/api.go
  2. 43 24
      go/pkg/zerotier/localconfig.go
  3. 30 0
      go/pkg/zerotier/mac.go
  4. 8 3
      go/pkg/zerotier/network.go
  5. 164 28
      go/pkg/zerotier/node.go

+ 145 - 0
go/pkg/zerotier/api.go

@@ -0,0 +1,145 @@
+/*
+ * Copyright (c)2019 ZeroTier, Inc.
+ *
+ * Use of this software is governed by the Business Source License included
+ * in the LICENSE.TXT file in the project's root directory.
+ *
+ * Change Date: 2023-01-01
+ *
+ * On the date above, in accordance with the Business Source License, use
+ * of this software will be governed by version 2.0 of the Apache License.
+ */
+/****/
+
+package zerotier
+
+import (
+	"encoding/json"
+	"net"
+	"net/http"
+	"path"
+	"time"
+)
+
+type apiStatus struct {
+	Address         Address
+	Clock           int64
+	Config          *LocalConfig
+	Online          bool
+	Identity        *Identity
+	Version         string
+	VersionMajor    int
+	VersionMinor    int
+	VersionRevision int
+	VersionBuild    int
+}
+
+type apiNetwork struct {
+	Config                 *NetworkConfig
+	Settings               *NetworkLocalSettings
+	MulticastSubscriptions []*MulticastGroup
+	TapDeviceType          string
+	TapDeviceName          string
+	TapDeviceEnabled       bool
+}
+
+func apiSetStandardHeaders(out http.ResponseWriter) {
+	now := time.Now().UTC()
+	h := out.Header()
+	h.Set("Cache-Control", "no-cache, no-store, must-revalidate")
+	h.Set("Expires", "0")
+	h.Set("Pragma", "no-cache")
+	h.Set("Date", now.Format(time.RFC1123))
+}
+
+func apiSendObj(out http.ResponseWriter, req *http.Request, httpStatusCode int, obj interface{}) error {
+	h := out.Header()
+	h.Set("Content-Type", "application/json")
+	if req.Method == http.MethodHead {
+		out.WriteHeader(httpStatusCode)
+		return nil
+	}
+	var j []byte
+	var err error
+	if obj != nil {
+		j, err = json.Marshal(obj)
+		if err != nil {
+			return err
+		}
+	}
+	out.WriteHeader(httpStatusCode)
+	_, err = out.Write(j)
+	return err
+}
+
+func apiReadObj(out http.ResponseWriter, req *http.Request, dest interface{}) (err error) {
+	err = json.NewDecoder(req.Body).Decode(&dest)
+	if err != nil {
+		apiSendObj(out, req, http.StatusBadRequest, nil)
+	}
+	return
+}
+
+// createAPIServer creates and starts an HTTP server for a given node
+func createAPIServer(basePath string, node *Node) (*http.Server, error) {
+	smux := http.NewServeMux()
+
+	smux.HandleFunc("/config", func(out http.ResponseWriter, req *http.Request) {
+		apiSetStandardHeaders(out)
+		if req.Method == http.MethodGet || req.Method == http.MethodHead {
+			apiSendObj(out, req, http.StatusOK, nil)
+		} else {
+			out.Header().Set("Allow", "GET, HEAD")
+			apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
+		}
+	})
+
+	smux.HandleFunc("/status", func(out http.ResponseWriter, req *http.Request) {
+		apiSetStandardHeaders(out)
+		if req.Method == http.MethodGet || req.Method == http.MethodHead {
+			var status apiStatus
+			apiSendObj(out, req, http.StatusOK, &status)
+		} else {
+			out.Header().Set("Allow", "GET, HEAD")
+			apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
+		}
+	})
+
+	smux.HandleFunc("/peer/", func(out http.ResponseWriter, req *http.Request) {
+		apiSetStandardHeaders(out)
+		if req.Method == http.MethodGet || req.Method == http.MethodHead {
+			peers := node.Peers()
+			apiSendObj(out, req, http.StatusOK, peers)
+		} else {
+			out.Header().Set("Allow", "GET, HEAD")
+			apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
+		}
+	})
+
+	smux.HandleFunc("/network/", func(out http.ResponseWriter, req *http.Request) {
+		apiSetStandardHeaders(out)
+		if req.Method == http.MethodGet || req.Method == http.MethodHead {
+			networks := node.Networks()
+			apiSendObj(out, req, http.StatusOK, networks)
+		} else {
+			out.Header().Set("Allow", "GET, HEAD")
+			apiSendObj(out, req, http.StatusMethodNotAllowed, nil)
+		}
+	})
+
+	unixListener, err := net.Listen("unix", path.Join(basePath, "apisocket"))
+	if err != nil {
+		return nil, err
+	}
+	httpServer := &http.Server{
+		MaxHeaderBytes: 4096,
+		Handler:        smux,
+		IdleTimeout:    10 * time.Second,
+		ReadTimeout:    10 * time.Second,
+		WriteTimeout:   600 * time.Second,
+	}
+	httpServer.SetKeepAlivesEnabled(true)
+	go httpServer.Serve(unixListener)
+
+	return httpServer, nil
+}

+ 43 - 24
go/pkg/zerotier/localconfig.go

@@ -14,7 +14,11 @@
 package zerotier
 
 import (
+	"encoding/json"
+	"io/ioutil"
+	rand "math/rand"
 	"net"
+	"os"
 	"runtime"
 )
 
@@ -41,33 +45,48 @@ type LocalConfigSettings struct {
 
 // LocalConfig is the local.conf file and stores local settings for the node.
 type LocalConfig struct {
-	Physical map[string]LocalConfigPhysicalPathConfiguration
-	Virtual  map[Address]LocalConfigVirtualAddressConfiguration
+	Physical map[string]*LocalConfigPhysicalPathConfiguration
+	Virtual  map[Address]*LocalConfigVirtualAddressConfiguration
+	Network  map[NetworkID]*NetworkLocalSettings
 	Settings LocalConfigSettings
 }
 
-// NewLocalConfig creates a new local.conf file with defaults
-func NewLocalConfig() *LocalConfig {
-	lc := &LocalConfig{
-		Physical: make(map[string]LocalConfigPhysicalPathConfiguration),
-		Virtual:  make(map[Address]LocalConfigVirtualAddressConfiguration),
-		Settings: LocalConfigSettings{
-			PrimaryPort:        9993,
-			SecondaryPort:      0,
-			TertiaryPort:       0,
-			PortMappingEnabled: true,
-			MuiltipathMode:     0,
-		},
+// Read this local config from a file, initializing to defaults if the file does not exist
+func (lc *LocalConfig) Read(p string) error {
+	if lc.Physical == nil {
+		lc.Physical = make(map[string]*LocalConfigPhysicalPathConfiguration)
+		lc.Virtual = make(map[Address]*LocalConfigVirtualAddressConfiguration)
+		lc.Network = make(map[NetworkID]*NetworkLocalSettings)
+		lc.Settings.PrimaryPort = 9993
+		lc.Settings.SecondaryPort = 16384 + (rand.Int() % 16384)
+		lc.Settings.TertiaryPort = 32768 + (rand.Int() % 16384)
+		lc.Settings.PortMappingEnabled = true
+		lc.Settings.MuiltipathMode = 0
+		switch runtime.GOOS {
+		case "darwin":
+			lc.Settings.InterfacePrefixBlacklist = []string{"utun", "tun", "tap", "feth", "lo", "zt"}
+		case "linux":
+			lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap", "lo", "zt"}
+		case "freebsd", "openbsd", "netbsd", "illumos", "solaris", "dragonfly":
+			lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap", "zt"}
+		case "android":
+			lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap"}
+		}
 	}
-	switch runtime.GOOS {
-	case "darwin":
-		lc.Settings.InterfacePrefixBlacklist = []string{"utun", "tun", "tap", "feth", "lo", "zt"}
-	case "linux":
-		lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap", "lo", "zt"}
-	case "freebsd", "openbsd", "netbsd", "illumos", "solaris", "dragonfly":
-		lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap", "zt"}
-	case "android":
-		lc.Settings.InterfacePrefixBlacklist = []string{"tun", "tap"}
+
+	data, err := ioutil.ReadFile(p)
+	if err != nil && err != os.ErrNotExist {
+		return err
+	}
+
+	return json.Unmarshal(data, lc)
+}
+
+// Write this local config to a file
+func (lc *LocalConfig) Write(p string) error {
+	data, err := json.MarshalIndent(lc, "", "\t")
+	if err != nil {
+		return err
 	}
-	return lc
+	return ioutil.WriteFile(p, data, 0644)
 }

+ 30 - 0
go/pkg/zerotier/mac.go

@@ -41,6 +41,36 @@ func NewMACFromString(s string) (MAC, error) {
 	return MAC(m), nil
 }
 
+// NewMACFromBytes decodes a MAC from a 6-byte array
+func NewMACFromBytes(b []byte) (MAC, error) {
+	if len(b) < 6 {
+		return MAC(0), ErrInvalidMACAddress
+	}
+	var m uint64
+	for i := 0; i < 6; i++ {
+		m <<= 8
+		m |= uint64(b[i])
+	}
+	return MAC(m), nil
+}
+
+// NewMACForNetworkMember computes the static MAC for a given address and network ID
+func NewMACForNetworkMember(addr Address, nwid NetworkID) MAC {
+	// This is the same algorithm as found in MAC::fromAddress() in MAC.hpp
+	firstOctetForNetwork := byte((byte(nwid) & 0xfe) | 0x02)
+	if firstOctetForNetwork == 0x52 {
+		firstOctetForNetwork = 0x32
+	}
+	m := uint64(firstOctetForNetwork) << 40
+	m |= uint64(addr)
+	m ^= ((uint64(nwid) >> 8) & 0xff) << 32
+	m ^= ((uint64(nwid) >> 16) & 0xff) << 24
+	m ^= ((uint64(nwid) >> 24) & 0xff) << 16
+	m ^= ((uint64(nwid) >> 32) & 0xff) << 8
+	m ^= (uint64(nwid) >> 40) & 0xff
+	return MAC(m)
+}
+
 // String returns this MAC address in canonical human-readable form
 func (m MAC) String() string {
 	return fmt.Sprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (uint64(m)>>40)&0xff, (uint64(m)>>32)&0xff, (uint64(m)>>24)&0xff, (uint64(m)>>16)&0xff, (uint64(m)>>8)&0xff, uint64(m)&0xff)

+ 8 - 3
go/pkg/zerotier/network.go

@@ -130,6 +130,7 @@ type NetworkLocalSettings struct {
 type Network struct {
 	node                       *Node
 	id                         NetworkID
+	mac                        MAC
 	tap                        Tap
 	config                     NetworkConfig
 	settings                   NetworkLocalSettings // locked by configLock
@@ -143,6 +144,7 @@ func newNetwork(node *Node, id NetworkID, t Tap) (*Network, error) {
 	n := &Network{
 		node: node,
 		id:   id,
+		mac:  NewMACForNetworkMember(node.Identity().address, id),
 		tap:  t,
 		config: NetworkConfig{
 			ID:     id,
@@ -172,6 +174,12 @@ func newNetwork(node *Node, id NetworkID, t Tap) (*Network, error) {
 // ID gets this network's unique ID
 func (n *Network) ID() NetworkID { return n.id }
 
+// MAC returns the assigned MAC address of this network
+func (n *Network) MAC() MAC { return n.mac }
+
+// Tap gets this network's tap device
+func (n *Network) Tap() Tap { return n.tap }
+
 // Config returns a copy of this network's current configuration
 func (n *Network) Config() NetworkConfig {
 	n.configLock.RLock()
@@ -179,9 +187,6 @@ func (n *Network) Config() NetworkConfig {
 	return n.config
 }
 
-// Tap gets this network's tap device
-func (n *Network) Tap() Tap { return n.tap }
-
 // SetLocalSettings modifies this network's local settings
 func (n *Network) SetLocalSettings(ls *NetworkLocalSettings) { n.updateConfig(nil, ls) }
 

+ 164 - 28
go/pkg/zerotier/node.go

@@ -24,11 +24,13 @@ import (
 	"errors"
 	"fmt"
 	"io/ioutil"
+	rand "math/rand"
 	"net"
 	"os"
 	"path"
 	"sync"
 	"sync/atomic"
+	"time"
 	"unsafe"
 
 	acl "github.com/hectane/go-acl"
@@ -131,31 +133,40 @@ func makeSockaddrStorage(ip net.IP, port int, ss *C.struct_sockaddr_storage) boo
 
 //////////////////////////////////////////////////////////////////////////////
 
-// Node represents an instance of the ZeroTier core node and related C++ I/O code
+// Node is an instance of the ZeroTier core node and related C++ I/O code
 type Node struct {
-	path         string
-	networks     map[uint64]*Network
-	networksLock sync.RWMutex
-
-	gn *C.ZT_GoNode
-	zn *C.ZT_Node
-
-	online  uint32
-	running uint32
+	basePath              string
+	localConfig           LocalConfig
+	networks              map[NetworkID]*Network
+	networksByMAC         map[MAC]*Network // locked by networksLock
+	externalAddresses     map[string]*net.IPNet
+	localConfigLock       sync.RWMutex
+	networksLock          sync.RWMutex
+	externalAddressesLock sync.Mutex
+	gn                    *C.ZT_GoNode
+	zn                    *C.ZT_Node
+	id                    *Identity
+	online                uint32
+	running               uint32
+	runLock               sync.Mutex
 }
 
 // NewNode creates and initializes a new instance of the ZeroTier node service
-func NewNode(path string) (*Node, error) {
-	os.MkdirAll(path, 0755)
-	if _, err := os.Stat(path); err != nil {
+func NewNode(basePath string) (*Node, error) {
+	var err error
+
+	os.MkdirAll(basePath, 0755)
+	if _, err := os.Stat(basePath); err != nil {
 		return nil, err
 	}
 
 	n := new(Node)
-	n.path = path
-	n.networks = make(map[uint64]*Network)
+	n.basePath = basePath
+	n.networks = make(map[NetworkID]*Network)
+	n.networksByMAC = make(map[MAC]*Network)
+	n.externalAddresses = make(map[string]*net.IPNet)
 
-	cpath := C.CString(path)
+	cpath := C.CString(basePath)
 	n.gn = C.ZT_GoNode_new(cpath)
 	C.free(unsafe.Pointer(cpath))
 	if n.gn == nil {
@@ -163,6 +174,14 @@ func NewNode(path string) (*Node, error) {
 	}
 	n.zn = (*C.ZT_Node)(C.ZT_GoNode_getNode(n.gn))
 
+	var ns C.ZT_NodeStatus
+	C.ZT_Node_status(unsafe.Pointer(n.zn), &ns)
+	n.id, err = NewIdentityFromString(C.GoString(ns.secretIdentity))
+	if err != nil {
+		C.ZT_GoNode_delete(n.gn)
+		return nil, err
+	}
+
 	gnRawAddr := uintptr(unsafe.Pointer(n.gn))
 	nodesByUserPtrLock.Lock()
 	nodesByUserPtr[gnRawAddr] = n
@@ -171,6 +190,77 @@ func NewNode(path string) (*Node, error) {
 	n.online = 0
 	n.running = 1
 
+	n.runLock.Lock()
+	go func() {
+		lastScannedInterfaces := int64(0)
+		for atomic.LoadUint32(&n.running) != 0 {
+			time.Sleep(1 * time.Second)
+
+			now := TimeMs()
+			if (now - lastScannedInterfaces) >= 30000 {
+				lastScannedInterfaces = now
+
+				externalAddresses := make(map[string]*net.IPNet)
+				ifs, _ := net.Interfaces()
+				if len(ifs) > 0 {
+					n.networksLock.RLock()
+					for _, i := range ifs {
+						m, _ := NewMACFromBytes(i.HardwareAddr)
+						if _, isZeroTier := n.networksByMAC[m]; !isZeroTier {
+							addrs, _ := i.Addrs()
+							if len(addrs) > 0 {
+								for _, a := range addrs {
+									ipn, _ := a.(*net.IPNet)
+									if ipn != nil {
+										externalAddresses[ipn.String()] = ipn
+									}
+								}
+							}
+						}
+					}
+					n.networksLock.RUnlock()
+				}
+
+				n.localConfigLock.RLock()
+				n.externalAddressesLock.Lock()
+				for astr, ipn := range externalAddresses {
+					if _, alreadyKnown := n.externalAddresses[astr]; !alreadyKnown {
+						ipCstr := C.CString(ipn.IP.String())
+						if n.localConfig.Settings.PrimaryPort > 0 && n.localConfig.Settings.PrimaryPort < 65536 {
+							C.ZT_GoNode_phyStartListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.PrimaryPort))
+						}
+						if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 {
+							C.ZT_GoNode_phyStartListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.SecondaryPort))
+						}
+						if n.localConfig.Settings.TertiaryPort > 0 && n.localConfig.Settings.TertiaryPort < 65536 {
+							C.ZT_GoNode_phyStartListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.TertiaryPort))
+						}
+						C.free(unsafe.Pointer(ipCstr))
+					}
+				}
+				for astr, ipn := range n.externalAddresses {
+					if _, stillPresent := externalAddresses[astr]; !stillPresent {
+						ipCstr := C.CString(ipn.IP.String())
+						if n.localConfig.Settings.PrimaryPort > 0 && n.localConfig.Settings.PrimaryPort < 65536 {
+							C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.PrimaryPort))
+						}
+						if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 {
+							C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.SecondaryPort))
+						}
+						if n.localConfig.Settings.TertiaryPort > 0 && n.localConfig.Settings.TertiaryPort < 65536 {
+							C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(n.localConfig.Settings.TertiaryPort))
+						}
+						C.free(unsafe.Pointer(ipCstr))
+					}
+				}
+				n.externalAddresses = externalAddresses
+				n.externalAddressesLock.Unlock()
+				n.localConfigLock.RUnlock()
+			}
+		}
+		n.runLock.Unlock()
+	}()
+
 	return n, nil
 }
 
@@ -181,14 +271,29 @@ func (n *Node) Close() {
 		nodesByUserPtrLock.Lock()
 		delete(nodesByUserPtr, uintptr(unsafe.Pointer(n.gn)))
 		nodesByUserPtrLock.Unlock()
+		n.runLock.Lock() // wait for gorountine to die
+		n.runLock.Unlock()
 	}
 }
 
+// Address returns this node's address
+func (n *Node) Address() Address { return n.id.address }
+
+// Identity returns this node's identity (including secret portion)
+func (n *Node) Identity() *Identity { return n.id }
+
+// LocalConfig gets this node's local configuration
+func (n *Node) LocalConfig() LocalConfig {
+	n.localConfigLock.RLock()
+	defer n.localConfigLock.RUnlock()
+	return n.localConfig
+}
+
 // Join joins a network
 // If tap is nil, the default system tap for this OS/platform is used (if available).
 func (n *Node) Join(nwid uint64, tap Tap) (*Network, error) {
 	n.networksLock.RLock()
-	if nw, have := n.networks[nwid]; have {
+	if nw, have := n.networks[NetworkID(nwid)]; have {
 		return nw, nil
 	}
 	n.networksLock.RUnlock()
@@ -207,7 +312,7 @@ func (n *Node) Join(nwid uint64, tap Tap) (*Network, error) {
 		return nil, err
 	}
 	n.networksLock.Lock()
-	n.networks[nwid] = nw
+	n.networks[NetworkID(nwid)] = nw
 	n.networksLock.Unlock()
 
 	return nw, nil
@@ -217,11 +322,22 @@ func (n *Node) Join(nwid uint64, tap Tap) (*Network, error) {
 func (n *Node) Leave(nwid uint64) error {
 	C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
 	n.networksLock.Lock()
-	delete(n.networks, nwid)
+	delete(n.networks, NetworkID(nwid))
 	n.networksLock.Unlock()
 	return nil
 }
 
+// Networks returns a list of networks that this node has joined
+func (n *Node) Networks() []*Network {
+	var nws []*Network
+	n.networksLock.RLock()
+	for _, nw := range n.networks {
+		nws = append(nws, nw)
+	}
+	n.networksLock.RUnlock()
+	return nws
+}
+
 // AddStaticRoot adds a statically defined root server to this node.
 // If a static root with the given identity already exists this will update its IP and port information.
 func (n *Node) AddStaticRoot(id *Identity, addrs []net.Addr) {
@@ -351,11 +467,30 @@ func (n *Node) multicastUnsubscribe(nwid uint64, mg *MulticastGroup) {
 	C.ZT_Node_multicastUnsubscribe(unsafe.Pointer(n.zn), C.uint64_t(nwid), C.uint64_t(mg.MAC), C.ulong(mg.ADI))
 }
 
-func (n *Node) pathCheck(ztAddress uint64, af int, ip net.IP, port int) bool {
+func (n *Node) pathCheck(ztAddress Address, af int, ip net.IP, port int) bool {
+	n.localConfigLock.RLock()
+	defer n.localConfigLock.RUnlock()
+	for cidr, phy := range n.localConfig.Physical {
+		if phy.Blacklist {
+			_, ipn, _ := net.ParseCIDR(cidr)
+			if ipn != nil && ipn.Contains(ip) {
+				return false
+			}
+		}
+	}
 	return true
 }
 
-func (n *Node) pathLookup(ztAddress uint64) (net.IP, int) {
+func (n *Node) pathLookup(ztAddress Address) (net.IP, int) {
+	n.localConfigLock.RLock()
+	defer n.localConfigLock.RUnlock()
+	virt := n.localConfig.Virtual[ztAddress]
+	if virt != nil && len(virt.Try) > 0 {
+		udpA, _ := virt.Try[rand.Int()%len(virt.Try)].(*net.UDPAddr)
+		if udpA != nil {
+			return udpA.IP, udpA.Port
+		}
+	}
 	return nil, 0
 }
 
@@ -364,21 +499,21 @@ func (n *Node) makeStateObjectPath(objType int, id [2]uint64) (string, bool) {
 	secret := false
 	switch objType {
 	case C.ZT_STATE_OBJECT_IDENTITY_PUBLIC:
-		fp = path.Join(n.path, "identity.public")
+		fp = path.Join(n.basePath, "identity.public")
 	case C.ZT_STATE_OBJECT_IDENTITY_SECRET:
-		fp = path.Join(n.path, "identity.secret")
+		fp = path.Join(n.basePath, "identity.secret")
 		secret = true
 	case C.ZT_STATE_OBJECT_PEER:
-		fp = path.Join(n.path, "peers.d")
+		fp = path.Join(n.basePath, "peers.d")
 		os.Mkdir(fp, 0700)
 		fp = path.Join(fp, fmt.Sprintf("%.10x.peer", id[0]))
 		secret = true
 	case C.ZT_STATE_OBJECT_NETWORK_CONFIG:
-		fp = path.Join(n.path, "networks.d")
+		fp = path.Join(n.basePath, "networks.d")
 		os.Mkdir(fp, 0755)
 		fp = path.Join(fp, fmt.Sprintf("%.16x.conf", id[0]))
 	case C.ZT_STATE_OBJECT_ROOT_LIST:
-		fp = path.Join(n.path, "roots")
+		fp = path.Join(n.basePath, "roots")
 	}
 	return fp, secret
 }
@@ -436,7 +571,7 @@ func goPathCheckFunc(gn unsafe.Pointer, ztAddress C.uint64_t, af C.int, ip unsaf
 	nodesByUserPtrLock.RLock()
 	node := nodesByUserPtr[uintptr(gn)]
 	nodesByUserPtrLock.RUnlock()
-	if node != nil && node.pathCheck(uint64(ztAddress), int(af), nil, int(port)) {
+	if node != nil && node.pathCheck(Address(ztAddress), int(af), nil, int(port)) {
 		return 1
 	}
 	return 0
@@ -451,7 +586,7 @@ func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, desiredAddressFam
 		return 0
 	}
 
-	ip, port := node.pathLookup(uint64(ztAddress))
+	ip, port := node.pathLookup(Address(ztAddress))
 	if len(ip) > 0 && port > 0 && port <= 65535 {
 		ip4 := ip.To4()
 		if len(ip4) == 4 {
@@ -466,6 +601,7 @@ func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, desiredAddressFam
 			return 1
 		}
 	}
+
 	return 0
 }