mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 13:03:45 +02:00
Port binding check.
This commit is contained in:
parent
b6175bd408
commit
64c8171e13
2 changed files with 105 additions and 76 deletions
|
@ -43,79 +43,51 @@ func allZero(b []byte) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkPort does trial binding to a port using both UDP and TCP and returns false if any bindings fail.
|
||||||
|
func checkPort(port int) bool {
|
||||||
|
var ua net.UDPAddr
|
||||||
|
ua.IP = net.IPv6zero
|
||||||
|
ua.Port = port
|
||||||
|
uc, err := net.ListenUDP("udp6", &ua)
|
||||||
|
if uc != nil {
|
||||||
|
uc.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ua.IP = net.IPv4zero
|
||||||
|
uc, err = net.ListenUDP("udp4", &ua)
|
||||||
|
if uc != nil {
|
||||||
|
uc.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var ta net.TCPAddr
|
||||||
|
ta.IP = net.IPv6zero
|
||||||
|
ta.Port = port
|
||||||
|
tc, err := net.ListenTCP("tcp6", &ta)
|
||||||
|
if tc != nil {
|
||||||
|
tc.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ta.IP = net.IPv4zero
|
||||||
|
tc, err = net.ListenTCP("tcp4", &ta)
|
||||||
|
if tc != nil {
|
||||||
|
tc.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// The ipClassify code below is based on and should produce identical results to
|
// The ipClassify code below is based on and should produce identical results to
|
||||||
// InetAddress::ipScope() in the C++ code.
|
// InetAddress::ipScope() in the C++ code.
|
||||||
/*
|
|
||||||
InetAddress::IpScope InetAddress::ipScope() const
|
|
||||||
{
|
|
||||||
switch(ss_family) {
|
|
||||||
|
|
||||||
case AF_INET: {
|
|
||||||
const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
|
|
||||||
switch(ip >> 24) {
|
|
||||||
case 0x00: return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used)
|
|
||||||
case 0x06: return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
|
|
||||||
case 0x0a: return IP_SCOPE_PRIVATE; // 10.0.0.0/8
|
|
||||||
case 0x0b: return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
|
|
||||||
case 0x15: return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
|
|
||||||
case 0x16: return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
|
|
||||||
case 0x19: return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense)
|
|
||||||
case 0x1a: return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
|
|
||||||
case 0x1c: return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
|
|
||||||
case 0x1d: return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
|
|
||||||
case 0x1e: return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
|
|
||||||
case 0x33: return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
|
|
||||||
case 0x37: return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
|
|
||||||
case 0x38: return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service)
|
|
||||||
case 0x64:
|
|
||||||
if ((ip & 0xffc00000) == 0x64400000) return IP_SCOPE_PRIVATE; // 100.64.0.0/10
|
|
||||||
break;
|
|
||||||
case 0x7f: return IP_SCOPE_LOOPBACK; // 127.0.0.0/8
|
|
||||||
case 0xa9:
|
|
||||||
if ((ip & 0xffff0000) == 0xa9fe0000) return IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16
|
|
||||||
break;
|
|
||||||
case 0xac:
|
|
||||||
if ((ip & 0xfff00000) == 0xac100000) return IP_SCOPE_PRIVATE; // 172.16.0.0/12
|
|
||||||
break;
|
|
||||||
case 0xc0:
|
|
||||||
if ((ip & 0xffff0000) == 0xc0a80000) return IP_SCOPE_PRIVATE; // 192.168.0.0/16
|
|
||||||
break;
|
|
||||||
case 0xff: return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
|
|
||||||
}
|
|
||||||
switch(ip >> 28) {
|
|
||||||
case 0xe: return IP_SCOPE_MULTICAST; // 224.0.0.0/4
|
|
||||||
case 0xf: return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable)
|
|
||||||
}
|
|
||||||
return IP_SCOPE_GLOBAL;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case AF_INET6: {
|
|
||||||
const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
|
|
||||||
if ((ip[0] & 0xf0) == 0xf0) {
|
|
||||||
if (ip[0] == 0xff) return IP_SCOPE_MULTICAST; // ff00::/8
|
|
||||||
if ((ip[0] == 0xfe)&&((ip[1] & 0xc0) == 0x80)) {
|
|
||||||
unsigned int k = 2;
|
|
||||||
while ((!ip[k])&&(k < 15)) ++k;
|
|
||||||
if ((k == 15)&&(ip[15] == 0x01))
|
|
||||||
return IP_SCOPE_LOOPBACK; // fe80::1/128
|
|
||||||
else return IP_SCOPE_LINK_LOCAL; // fe80::/10
|
|
||||||
}
|
|
||||||
if ((ip[0] & 0xfe) == 0xfc) return IP_SCOPE_PRIVATE; // fc00::/7
|
|
||||||
}
|
|
||||||
unsigned int k = 0;
|
|
||||||
while ((!ip[k])&&(k < 15)) ++k;
|
|
||||||
if (k == 15) { // all 0's except last byte
|
|
||||||
if (ip[15] == 0x01) return IP_SCOPE_LOOPBACK; // ::1/128
|
|
||||||
if (ip[15] == 0x00) return IP_SCOPE_NONE; // ::/128
|
|
||||||
}
|
|
||||||
return IP_SCOPE_GLOBAL;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return IP_SCOPE_NONE;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ipClassificationNone = -1
|
ipClassificationNone = -1
|
||||||
|
|
|
@ -147,12 +147,12 @@ func makeSockaddrStorage(ip net.IP, port int, ss *C.struct_sockaddr_storage) boo
|
||||||
|
|
||||||
// Node is 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 {
|
type Node struct {
|
||||||
basePath string
|
|
||||||
localConfigPath string
|
|
||||||
localConfig LocalConfig
|
|
||||||
networks map[NetworkID]*Network
|
networks map[NetworkID]*Network
|
||||||
networksByMAC map[MAC]*Network // locked by networksLock
|
networksByMAC map[MAC]*Network // locked by networksLock
|
||||||
interfaceAddresses map[string]net.IP // physical external IPs on the machine
|
interfaceAddresses map[string]net.IP // physical external IPs on the machine
|
||||||
|
basePath string
|
||||||
|
localConfigPath string
|
||||||
|
localConfig LocalConfig
|
||||||
localConfigLock sync.RWMutex
|
localConfigLock sync.RWMutex
|
||||||
networksLock sync.RWMutex
|
networksLock sync.RWMutex
|
||||||
interfaceAddressesLock sync.Mutex
|
interfaceAddressesLock sync.Mutex
|
||||||
|
@ -173,15 +173,72 @@ func NewNode(basePath string) (*Node, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
n := new(Node)
|
n := new(Node)
|
||||||
|
n.networks = make(map[NetworkID]*Network)
|
||||||
|
n.networksByMAC = make(map[MAC]*Network)
|
||||||
|
n.interfaceAddresses = make(map[string]net.IP)
|
||||||
|
|
||||||
n.basePath = basePath
|
n.basePath = basePath
|
||||||
n.localConfigPath = path.Join(basePath, "local.conf")
|
n.localConfigPath = path.Join(basePath, "local.conf")
|
||||||
err := n.localConfig.Read(n.localConfigPath, true)
|
err := n.localConfig.Read(n.localConfigPath, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
n.networks = make(map[NetworkID]*Network)
|
|
||||||
n.networksByMAC = make(map[MAC]*Network)
|
if n.localConfig.Settings.PortAutoSearch {
|
||||||
n.interfaceAddresses = make(map[string]net.IP)
|
portsChanged := false
|
||||||
|
|
||||||
|
portCheckCount := 0
|
||||||
|
for portCheckCount < 2048 {
|
||||||
|
portCheckCount++
|
||||||
|
if checkPort(n.localConfig.Settings.PrimaryPort) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n.localConfig.Settings.PrimaryPort++
|
||||||
|
n.localConfig.Settings.PrimaryPort &= 0xffff
|
||||||
|
portsChanged = true
|
||||||
|
}
|
||||||
|
if portCheckCount == 2048 {
|
||||||
|
return nil, errors.New("unable to bind to primary port, tried 2048 later ports")
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.localConfig.Settings.SecondaryPort > 0 {
|
||||||
|
portCheckCount = 0
|
||||||
|
for portCheckCount < 2048 {
|
||||||
|
portCheckCount++
|
||||||
|
if checkPort(n.localConfig.Settings.SecondaryPort) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n.localConfig.Settings.SecondaryPort++
|
||||||
|
n.localConfig.Settings.SecondaryPort &= 0xffff
|
||||||
|
portsChanged = true
|
||||||
|
}
|
||||||
|
if portCheckCount == 2048 {
|
||||||
|
n.localConfig.Settings.SecondaryPort = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.localConfig.Settings.TertiaryPort > 0 {
|
||||||
|
portCheckCount = 0
|
||||||
|
for portCheckCount < 2048 {
|
||||||
|
portCheckCount++
|
||||||
|
if checkPort(n.localConfig.Settings.TertiaryPort) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n.localConfig.Settings.TertiaryPort++
|
||||||
|
n.localConfig.Settings.TertiaryPort &= 0xffff
|
||||||
|
portsChanged = true
|
||||||
|
}
|
||||||
|
if portCheckCount == 2048 {
|
||||||
|
n.localConfig.Settings.TertiaryPort = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if portsChanged {
|
||||||
|
n.localConfig.Write(n.localConfigPath)
|
||||||
|
}
|
||||||
|
} else if !checkPort(n.localConfig.Settings.PrimaryPort) {
|
||||||
|
return nil, errors.New("unable to bind to primary port")
|
||||||
|
}
|
||||||
|
|
||||||
cpath := C.CString(basePath)
|
cpath := C.CString(basePath)
|
||||||
n.gn = C.ZT_GoNode_new(cpath)
|
n.gn = C.ZT_GoNode_new(cpath)
|
||||||
|
|
Loading…
Add table
Reference in a new issue