mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 01:11:54 +00:00
Network config stuff in Go
This commit is contained in:
parent
2eef9d22e6
commit
bcb9df9cdf
@ -15,6 +15,7 @@ package zerotier
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
|
"encoding/binary"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@ -27,10 +28,194 @@ func TimeMs() int64 { return int64(time.Now().UnixNano()) / int64(1000000) }
|
|||||||
|
|
||||||
// ipNetToKey creates a key that can be used in a map[] from a net.IPNet
|
// ipNetToKey creates a key that can be used in a map[] from a net.IPNet
|
||||||
func ipNetToKey(ipn *net.IPNet) (k [3]uint64) {
|
func ipNetToKey(ipn *net.IPNet) (k [3]uint64) {
|
||||||
if len(ipn.IP) > 0 {
|
copy(((*[16]byte)(unsafe.Pointer(&k[0])))[:], ipn.IP)
|
||||||
copy(((*[16]byte)(unsafe.Pointer(&k[0])))[:], ipn.IP)
|
|
||||||
}
|
|
||||||
ones, bits := ipn.Mask.Size()
|
ones, bits := ipn.Mask.Size()
|
||||||
k[2] = (uint64(ones) << 32) | uint64(bits)
|
k[2] = (uint64(ones) << 32) | uint64(bits)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allZero(b []byte) bool {
|
||||||
|
for _, bb := range b {
|
||||||
|
if bb != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ipClassify code below is based on and should produce identical results to
|
||||||
|
// 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 (
|
||||||
|
ipClassificationNone = -1
|
||||||
|
ipClassificationLoopback = 0
|
||||||
|
ipClassificationPseudoprivate = 1
|
||||||
|
ipClassificationPrivate = 2
|
||||||
|
ipClassificationLinkLocal = 3
|
||||||
|
ipClassificationMulticast = 4
|
||||||
|
ipClassificationGlobal = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
var ipv4PseudoprivatePrefixes = []byte{
|
||||||
|
0x06, // 6.0.0.0/8 (US Army)
|
||||||
|
0x0b, // 11.0.0.0/8 (US DoD)
|
||||||
|
0x15, // 21.0.0.0/8 (US DDN-RVN)
|
||||||
|
0x16, // 22.0.0.0/8 (US DISA)
|
||||||
|
0x19, // 25.0.0.0/8 (UK Ministry of Defense)
|
||||||
|
0x1a, // 26.0.0.0/8 (US DISA)
|
||||||
|
0x1c, // 28.0.0.0/8 (US DSI-North)
|
||||||
|
0x1d, // 29.0.0.0/8 (US DISA)
|
||||||
|
0x1e, // 30.0.0.0/8 (US DISA)
|
||||||
|
0x33, // 51.0.0.0/8 (UK Department of Social Security)
|
||||||
|
0x37, // 55.0.0.0/8 (US DoD)
|
||||||
|
0x38, // 56.0.0.0/8 (US Postal Service)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ipClassify determines the official or in a few cases unofficial role of an IP address
|
||||||
|
func ipClassify(ip net.IP) int {
|
||||||
|
if len(ip) == 16 {
|
||||||
|
ip4 := ip.To4()
|
||||||
|
if len(ip4) == 4 {
|
||||||
|
ip = ip4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(ip) == 4 {
|
||||||
|
ip4FirstByte := ip[0]
|
||||||
|
for _, b := range ipv4PseudoprivatePrefixes {
|
||||||
|
if ip4FirstByte == b {
|
||||||
|
return ipClassificationPseudoprivate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ip4 := binary.BigEndian.Uint32(ip)
|
||||||
|
switch ip4FirstByte {
|
||||||
|
case 0x0a: // 10.0.0.0/8
|
||||||
|
return ipClassificationPrivate
|
||||||
|
case 0x64: // 100.64.0.0/10
|
||||||
|
if (ip4 & 0xffc00000) == 0x64400000 {
|
||||||
|
return ipClassificationPrivate
|
||||||
|
}
|
||||||
|
case 0x7f: // 127.0.0.1/8
|
||||||
|
return ipClassificationLoopback
|
||||||
|
case 0xa9: // 169.254.0.0/16
|
||||||
|
if (ip4 & 0xffff0000) == 0xa9fe0000 {
|
||||||
|
return ipClassificationLinkLocal
|
||||||
|
}
|
||||||
|
case 0xac: // 172.16.0.0/12
|
||||||
|
if (ip4 & 0xfff00000) == 0xac100000 {
|
||||||
|
return ipClassificationPrivate
|
||||||
|
}
|
||||||
|
case 0xc0: // 192.168.0.0/16
|
||||||
|
if (ip4 & 0xffff0000) == 0xc0a80000 {
|
||||||
|
return ipClassificationPrivate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch ip4 >> 28 {
|
||||||
|
case 0xe: // 224.0.0.0/4
|
||||||
|
return ipClassificationMulticast
|
||||||
|
case 0xf: // 240.0.0.0/4 ("reserved," usually unusable)
|
||||||
|
return ipClassificationNone
|
||||||
|
}
|
||||||
|
return ipClassificationGlobal
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ip) == 16 {
|
||||||
|
if (ip[0] & 0xf0) == 0xf0 {
|
||||||
|
if ip[0] == 0xff { // ff00::/8
|
||||||
|
return ipClassificationMulticast
|
||||||
|
}
|
||||||
|
if ip[0] == 0xfe && (ip[1]&0xc0) == 0x80 {
|
||||||
|
if allZero(ip[2:15]) {
|
||||||
|
if ip[15] == 0x01 { // fe80::1/128
|
||||||
|
return ipClassificationLoopback
|
||||||
|
}
|
||||||
|
return ipClassificationLinkLocal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ip[0] & 0xfe) == 0xfc { // fc00::/7
|
||||||
|
return ipClassificationPrivate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if allZero(ip[0:15]) {
|
||||||
|
if ip[15] == 0x01 { // ::1/128
|
||||||
|
return ipClassificationLoopback
|
||||||
|
}
|
||||||
|
if ip[15] == 0x00 { // ::/128
|
||||||
|
return ipClassificationNone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ipClassificationGlobal
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipClassificationNone
|
||||||
|
}
|
||||||
|
@ -40,7 +40,7 @@ func (n NetworkID) String() string {
|
|||||||
|
|
||||||
// MarshalJSON marshals this NetworkID as a string
|
// MarshalJSON marshals this NetworkID as a string
|
||||||
func (n NetworkID) MarshalJSON() ([]byte, error) {
|
func (n NetworkID) MarshalJSON() ([]byte, error) {
|
||||||
return []byte(n.String()), nil
|
return []byte("\"" + n.String() + "\""), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals this NetworkID from a string
|
// UnmarshalJSON unmarshals this NetworkID from a string
|
||||||
@ -75,13 +75,13 @@ type NetworkConfig struct {
|
|||||||
// MTU is the Ethernet MTU for this network
|
// MTU is the Ethernet MTU for this network
|
||||||
MTU int
|
MTU int
|
||||||
|
|
||||||
// CanBridge is true if this network is allowed to bridge in other devices with different Ethernet addresses
|
// Bridge is true if this network is allowed to bridge in other devices with different Ethernet addresses
|
||||||
Bridge bool
|
Bridge bool
|
||||||
|
|
||||||
// BroadcastEnabled is true if the broadcast (ff:ff:ff:ff:ff:ff) address works (excluding IPv4 ARP which is handled via a special path)
|
// BroadcastEnabled is true if the broadcast (ff:ff:ff:ff:ff:ff) address works (excluding IPv4 ARP which is handled via a special path)
|
||||||
BroadcastEnabled bool
|
BroadcastEnabled bool
|
||||||
|
|
||||||
// Network configuration revision number according to network controller
|
// NetconfRevision is the revision number reported by the controller
|
||||||
NetconfRevision uint64
|
NetconfRevision uint64
|
||||||
|
|
||||||
// AssignedAddresses are static IPs assigned by the network controller to this device
|
// AssignedAddresses are static IPs assigned by the network controller to this device
|
||||||
@ -91,13 +91,50 @@ type NetworkConfig struct {
|
|||||||
Routes []Route
|
Routes []Route
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NetworkLocalSettings is settings for this network that can be changed locally
|
||||||
|
type NetworkLocalSettings struct {
|
||||||
|
// AllowManagedIPs determines whether managed IP assignment is allowed
|
||||||
|
AllowManagedIPs bool
|
||||||
|
|
||||||
|
// AllowGlobalIPs determines if managed IPs that overlap with public Internet addresses are allowed
|
||||||
|
AllowGlobalIPs bool
|
||||||
|
|
||||||
|
// AllowManagedRoutes determines whether managed routes can be set
|
||||||
|
AllowManagedRoutes bool
|
||||||
|
|
||||||
|
// AllowGlobalRoutes determines if managed routes can overlap with public Internet addresses
|
||||||
|
AllowGlobalRoutes bool
|
||||||
|
|
||||||
|
// AllowDefaultRouteOverride determines if the default (0.0.0.0 or ::0) route on the system can be overridden ("full tunnel" mode)
|
||||||
|
AllowDefaultRouteOverride bool
|
||||||
|
}
|
||||||
|
|
||||||
// Network is a currently joined network
|
// Network is a currently joined network
|
||||||
type Network struct {
|
type Network struct {
|
||||||
id NetworkID
|
id NetworkID
|
||||||
config NetworkConfig
|
|
||||||
tap Tap
|
tap Tap
|
||||||
|
config NetworkConfig
|
||||||
|
settings NetworkLocalSettings // locked by configLock
|
||||||
configLock sync.RWMutex
|
configLock sync.RWMutex
|
||||||
tapLock sync.RWMutex
|
}
|
||||||
|
|
||||||
|
// NewNetwork creates a new network with default settings
|
||||||
|
func NewNetwork(id NetworkID, t Tap) (*Network, error) {
|
||||||
|
return &Network{
|
||||||
|
id: id,
|
||||||
|
tap: t,
|
||||||
|
config: NetworkConfig{
|
||||||
|
ID: id,
|
||||||
|
Status: NetworkStatusRequestConfiguration,
|
||||||
|
},
|
||||||
|
settings: NetworkLocalSettings{
|
||||||
|
AllowManagedIPs: true,
|
||||||
|
AllowGlobalIPs: false,
|
||||||
|
AllowManagedRoutes: true,
|
||||||
|
AllowGlobalRoutes: false,
|
||||||
|
AllowDefaultRouteOverride: false,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID gets this network's unique ID
|
// ID gets this network's unique ID
|
||||||
@ -111,36 +148,84 @@ func (n *Network) Config() NetworkConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tap gets this network's tap device
|
// Tap gets this network's tap device
|
||||||
func (n *Network) Tap() Tap {
|
func (n *Network) Tap() Tap { return n.tap }
|
||||||
n.tapLock.RLock()
|
|
||||||
defer n.tapLock.RUnlock()
|
// SetLocalSettings modifies this network's local settings
|
||||||
return n.tap
|
func (n *Network) SetLocalSettings(ls *NetworkLocalSettings) { n.updateConfig(nil, ls) }
|
||||||
|
|
||||||
|
func (n *Network) networkConfigRevision() uint64 {
|
||||||
|
n.configLock.RLock()
|
||||||
|
defer n.configLock.RUnlock()
|
||||||
|
return n.config.NetconfRevision
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Network) handleNetworkConfigUpdate(nc *NetworkConfig) {
|
func networkManagedIPAllowed(ip net.IP, ls *NetworkLocalSettings) bool {
|
||||||
n.tapLock.RLock()
|
if !ls.AllowManagedIPs {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch ipClassify(ip) {
|
||||||
|
case ipClassificationNone, ipClassificationLoopback, ipClassificationLinkLocal, ipClassificationMulticast:
|
||||||
|
return false
|
||||||
|
case ipClassificationGlobal:
|
||||||
|
return ls.AllowGlobalIPs
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func networkManagedRouteAllowed(r *Route, ls *NetworkLocalSettings) bool {
|
||||||
|
if !ls.AllowManagedRoutes {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
bits, _ := r.Target.Mask.Size()
|
||||||
|
if len(r.Target.IP) > 0 && allZero(r.Target.IP) && bits == 0 {
|
||||||
|
return ls.AllowDefaultRouteOverride
|
||||||
|
}
|
||||||
|
switch ipClassify(r.Target.IP) {
|
||||||
|
case ipClassificationNone, ipClassificationLoopback, ipClassificationLinkLocal, ipClassificationMulticast:
|
||||||
|
return false
|
||||||
|
case ipClassificationGlobal:
|
||||||
|
return ls.AllowGlobalRoutes
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) {
|
||||||
n.configLock.Lock()
|
n.configLock.Lock()
|
||||||
defer n.configLock.Unlock()
|
defer n.configLock.Unlock()
|
||||||
defer n.tapLock.RUnlock()
|
|
||||||
|
|
||||||
if n.tap == nil { // sanity check
|
if n.tap == nil { // sanity check, should never happen
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if nc == nil {
|
||||||
|
nc = &n.config
|
||||||
|
}
|
||||||
|
if ls == nil {
|
||||||
|
ls = &n.settings
|
||||||
|
}
|
||||||
|
|
||||||
// Add IPs to tap that are newly assigned in this config update,
|
// Add IPs to tap that are newly assigned in this config update,
|
||||||
// and remove any IPs from the tap that were assigned that are no
|
// and remove any IPs from the tap that were assigned that are no
|
||||||
// longer wanted. IPs assigned to the tap externally (e.g. by an
|
// longer wanted. IPs assigned to the tap externally (e.g. by an
|
||||||
// "ifconfig" command) are left alone.
|
// "ifconfig" command) are left alone.
|
||||||
haveAssignedIPs := make(map[[3]uint64]*net.IPNet)
|
haveAssignedIPs := make(map[[3]uint64]*net.IPNet)
|
||||||
for _, ip := range n.config.AssignedAddresses {
|
|
||||||
haveAssignedIPs[ipNetToKey(&ip)] = &ip
|
|
||||||
}
|
|
||||||
wantAssignedIPs := make(map[[3]uint64]bool)
|
wantAssignedIPs := make(map[[3]uint64]bool)
|
||||||
for _, ip := range nc.AssignedAddresses {
|
if n.settings.AllowManagedIPs {
|
||||||
k := ipNetToKey(&ip)
|
for _, ip := range n.config.AssignedAddresses {
|
||||||
wantAssignedIPs[k] = true
|
if networkManagedIPAllowed(ip.IP, &n.settings) { // was it allowed?
|
||||||
if _, have := haveAssignedIPs[k]; !have {
|
haveAssignedIPs[ipNetToKey(&ip)] = &ip
|
||||||
n.tap.AddIP(&ip)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ls.AllowManagedIPs {
|
||||||
|
for _, ip := range nc.AssignedAddresses {
|
||||||
|
if networkManagedIPAllowed(ip.IP, ls) { // should it be allowed now?
|
||||||
|
k := ipNetToKey(&ip)
|
||||||
|
wantAssignedIPs[k] = true
|
||||||
|
if _, have := haveAssignedIPs[k]; !have {
|
||||||
|
n.tap.AddIP(&ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, ip := range haveAssignedIPs {
|
for k, ip := range haveAssignedIPs {
|
||||||
@ -148,4 +233,38 @@ func (n *Network) handleNetworkConfigUpdate(nc *NetworkConfig) {
|
|||||||
n.tap.RemoveIP(ip)
|
n.tap.RemoveIP(ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do the same for managed routes
|
||||||
|
haveManagedRoutes := make(map[[6]uint64]*Route)
|
||||||
|
wantManagedRoutes := make(map[[6]uint64]bool)
|
||||||
|
if n.settings.AllowManagedRoutes {
|
||||||
|
for _, r := range n.config.Routes {
|
||||||
|
if networkManagedRouteAllowed(&r, &n.settings) { // was it allowed?
|
||||||
|
haveManagedRoutes[r.key()] = &r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ls.AllowManagedRoutes {
|
||||||
|
for _, r := range nc.Routes {
|
||||||
|
if networkManagedRouteAllowed(&r, ls) { // should it be allowed now?
|
||||||
|
k := r.key()
|
||||||
|
wantManagedRoutes[k] = true
|
||||||
|
if _, have := haveManagedRoutes[k]; !have {
|
||||||
|
n.tap.AddRoute(&r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, r := range haveManagedRoutes {
|
||||||
|
if _, want := wantManagedRoutes[k]; !want {
|
||||||
|
n.tap.RemoveRoute(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nc != &n.config {
|
||||||
|
n.config = *nc
|
||||||
|
}
|
||||||
|
if ls != &n.settings {
|
||||||
|
n.settings = *ls
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,9 @@ const (
|
|||||||
NetworkStatusPortError int = C.ZT_NETWORK_STATUS_PORT_ERROR
|
NetworkStatusPortError int = C.ZT_NETWORK_STATUS_PORT_ERROR
|
||||||
NetworkStatusClientTooOld int = C.ZT_NETWORK_STATUS_CLIENT_TOO_OLD
|
NetworkStatusClientTooOld int = C.ZT_NETWORK_STATUS_CLIENT_TOO_OLD
|
||||||
|
|
||||||
|
NetworkTypePrivate int = C.ZT_NETWORK_TYPE_PRIVATE
|
||||||
|
NetworkTypePublic int = C.ZT_NETWORK_TYPE_PUBLIC
|
||||||
|
|
||||||
// CoreVersionMajor is the major version of the ZeroTier core
|
// CoreVersionMajor is the major version of the ZeroTier core
|
||||||
CoreVersionMajor int = C.ZEROTIER_ONE_VERSION_MAJOR
|
CoreVersionMajor int = C.ZEROTIER_ONE_VERSION_MAJOR
|
||||||
|
|
||||||
@ -136,13 +139,10 @@ func (n *Node) Join(nwid uint64, tap Tap) (*Network, error) {
|
|||||||
return nil, ErrTapInitFailed
|
return nil, ErrTapInitFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
nw := &Network{
|
nw, err := NewNetwork(NetworkID(nwid), &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1})
|
||||||
id: NetworkID(nwid),
|
if err != nil {
|
||||||
config: NetworkConfig{
|
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
|
||||||
ID: NetworkID(nwid),
|
return nil, err
|
||||||
Status: NetworkStatusRequestConfiguration,
|
|
||||||
},
|
|
||||||
tap: &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1},
|
|
||||||
}
|
}
|
||||||
n.networksLock.Lock()
|
n.networksLock.Lock()
|
||||||
n.networks[nwid] = nw
|
n.networks[nwid] = nw
|
||||||
@ -368,113 +368,82 @@ func sockaddrStorageToIPNet(ss *C.struct_sockaddr_storage) *net.IPNet {
|
|||||||
|
|
||||||
//export goVirtualNetworkConfigFunc
|
//export goVirtualNetworkConfigFunc
|
||||||
func goVirtualNetworkConfigFunc(gn, tapP unsafe.Pointer, nwid C.uint64_t, op C.int, conf unsafe.Pointer) {
|
func goVirtualNetworkConfigFunc(gn, tapP unsafe.Pointer, nwid C.uint64_t, op C.int, conf unsafe.Pointer) {
|
||||||
nodesByUserPtrLock.RLock()
|
go func() {
|
||||||
node := nodesByUserPtr[uintptr(gn)]
|
nodesByUserPtrLock.RLock()
|
||||||
nodesByUserPtrLock.RUnlock()
|
node := nodesByUserPtr[uintptr(gn)]
|
||||||
if node == nil {
|
nodesByUserPtrLock.RUnlock()
|
||||||
return
|
if node == nil {
|
||||||
}
|
return
|
||||||
node.networksLock.RLock()
|
|
||||||
network := node.networks[uint64(nwid)]
|
|
||||||
node.networksLock.RUnlock()
|
|
||||||
if network != nil {
|
|
||||||
ncc := (*C.ZT_VirtualNetworkConfig)(conf)
|
|
||||||
var nc NetworkConfig
|
|
||||||
nc.ID = uint64(ncc.nwid)
|
|
||||||
nc.MAC = MAC(ncc.mac)
|
|
||||||
nc.Name = C.GoString(ncc.name)
|
|
||||||
nc.Status = int(ncc.status)
|
|
||||||
nc.Type = int(ncc._type)
|
|
||||||
nc.MTU = int(ncc.mtu)
|
|
||||||
nc.Bridge = (ncc.bridge != 0)
|
|
||||||
nc.BroadcastEnabled = (ncc.broadcastEnabled != 0)
|
|
||||||
nc.NetconfRevision = uint64(ncc.netconfRevision)
|
|
||||||
for i := 0; i < int(ncc.assignedAddressCount); i++ {
|
|
||||||
a := sockaddrStorageToIPNet(&ncc.assignedAddresses[i])
|
|
||||||
if a != nil {
|
|
||||||
nc.AssignedAddresses = append(nc.AssignedAddresses, *a)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for i := 0; i < int(ncc.routeCount); i++ {
|
node.networksLock.RLock()
|
||||||
tgt := sockaddrStorageToIPNet(&ncc.routes[i].target)
|
network := node.networks[uint64(nwid)]
|
||||||
viaN := sockaddrStorageToIPNet(&ncc.routes[i].via)
|
node.networksLock.RUnlock()
|
||||||
var via net.IP
|
if network != nil {
|
||||||
if viaN != nil {
|
ncc := (*C.ZT_VirtualNetworkConfig)(conf)
|
||||||
via = viaN.IP
|
if network.networkConfigRevision() > uint64(ncc.netconfRevision) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if tgt != nil {
|
var nc NetworkConfig
|
||||||
nc.Routes = append(nc.Routes, Route{
|
nc.ID = uint64(ncc.nwid)
|
||||||
Target: *tgt,
|
nc.MAC = MAC(ncc.mac)
|
||||||
Via: via,
|
nc.Name = C.GoString(ncc.name)
|
||||||
Flags: uint16(ncc.routes[i].flags),
|
nc.Status = int(ncc.status)
|
||||||
Metric: uint16(ncc.routes[i].metric),
|
nc.Type = int(ncc._type)
|
||||||
})
|
nc.MTU = int(ncc.mtu)
|
||||||
|
nc.Bridge = (ncc.bridge != 0)
|
||||||
|
nc.BroadcastEnabled = (ncc.broadcastEnabled != 0)
|
||||||
|
nc.NetconfRevision = uint64(ncc.netconfRevision)
|
||||||
|
for i := 0; i < int(ncc.assignedAddressCount); i++ {
|
||||||
|
a := sockaddrStorageToIPNet(&ncc.assignedAddresses[i])
|
||||||
|
if a != nil {
|
||||||
|
nc.AssignedAddresses = append(nc.AssignedAddresses, *a)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
for i := 0; i < int(ncc.routeCount); i++ {
|
||||||
|
tgt := sockaddrStorageToIPNet(&ncc.routes[i].target)
|
||||||
|
viaN := sockaddrStorageToIPNet(&ncc.routes[i].via)
|
||||||
|
var via net.IP
|
||||||
|
if viaN != nil {
|
||||||
|
via = viaN.IP
|
||||||
|
}
|
||||||
|
if tgt != nil {
|
||||||
|
nc.Routes = append(nc.Routes, Route{
|
||||||
|
Target: *tgt,
|
||||||
|
Via: via,
|
||||||
|
Flags: uint16(ncc.routes[i].flags),
|
||||||
|
Metric: uint16(ncc.routes[i].metric),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
network.updateConfig(&nc, nil)
|
||||||
}
|
}
|
||||||
network.handleNetworkConfigUpdate(&nc)
|
}()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//export goZtEvent
|
//export goZtEvent
|
||||||
func goZtEvent(gn unsafe.Pointer, eventType C.int, data unsafe.Pointer) {
|
func goZtEvent(gn unsafe.Pointer, eventType C.int, data unsafe.Pointer) {
|
||||||
nodesByUserPtrLock.RLock()
|
go func() {
|
||||||
node := nodesByUserPtr[uintptr(gn)]
|
nodesByUserPtrLock.RLock()
|
||||||
nodesByUserPtrLock.RUnlock()
|
node := nodesByUserPtr[uintptr(gn)]
|
||||||
if node == nil {
|
nodesByUserPtrLock.RUnlock()
|
||||||
return
|
if node == nil {
|
||||||
}
|
return
|
||||||
switch eventType {
|
|
||||||
case C.ZT_EVENT_OFFLINE:
|
|
||||||
atomic.StoreUint32(&node.online, 0)
|
|
||||||
case C.ZT_EVENT_ONLINE:
|
|
||||||
atomic.StoreUint32(&node.online, 1)
|
|
||||||
case C.ZT_EVENT_TRACE:
|
|
||||||
node.handleTrace(C.GoString((*C.char)(data)))
|
|
||||||
case C.ZT_EVENT_USER_MESSAGE:
|
|
||||||
um := (*C.ZT_UserMessage)(data)
|
|
||||||
node.handleUserMessage(uint64(um.origin), uint64(um.typeId), C.GoBytes(um.data, C.int(um.length)))
|
|
||||||
case C.ZT_EVENT_REMOTE_TRACE:
|
|
||||||
rt := (*C.ZT_RemoteTrace)(data)
|
|
||||||
node.handleRemoteTrace(uint64(rt.origin), C.GoBytes(unsafe.Pointer(rt.data), C.int(rt.len)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are really part of nativeTap
|
|
||||||
|
|
||||||
func handleTapMulticastGroupChange(gn unsafe.Pointer, nwid, mac C.uint64_t, adi C.uint32_t, added bool) {
|
|
||||||
nodesByUserPtrLock.RLock()
|
|
||||||
node := nodesByUserPtr[uintptr(gn)]
|
|
||||||
nodesByUserPtrLock.RUnlock()
|
|
||||||
if node == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
node.networksLock.RLock()
|
|
||||||
network := node.networks[uint64(nwid)]
|
|
||||||
node.networksLock.RUnlock()
|
|
||||||
|
|
||||||
network.tapLock.Lock()
|
|
||||||
tap, _ := network.tap.(*nativeTap)
|
|
||||||
network.tapLock.Unlock()
|
|
||||||
|
|
||||||
if tap != nil {
|
|
||||||
mg := &MulticastGroup{MAC: MAC(mac), ADI: uint32(adi)}
|
|
||||||
tap.multicastGroupHandlersLock.Lock()
|
|
||||||
defer tap.multicastGroupHandlersLock.Unlock()
|
|
||||||
for _, h := range tap.multicastGroupHandlers {
|
|
||||||
h(added, mg)
|
|
||||||
}
|
}
|
||||||
}
|
switch eventType {
|
||||||
}
|
case C.ZT_EVENT_OFFLINE:
|
||||||
|
atomic.StoreUint32(&node.online, 0)
|
||||||
//export goHandleTapAddedMulticastGroup
|
case C.ZT_EVENT_ONLINE:
|
||||||
func goHandleTapAddedMulticastGroup(gn, tapP unsafe.Pointer, nwid, mac C.uint64_t, adi C.uint32_t) {
|
atomic.StoreUint32(&node.online, 1)
|
||||||
handleTapMulticastGroupChange(gn, nwid, mac, adi, true)
|
case C.ZT_EVENT_TRACE:
|
||||||
}
|
node.handleTrace(C.GoString((*C.char)(data)))
|
||||||
|
case C.ZT_EVENT_USER_MESSAGE:
|
||||||
//export goHandleTapRemovedMulticastGroup
|
um := (*C.ZT_UserMessage)(data)
|
||||||
func goHandleTapRemovedMulticastGroup(gn, tapP unsafe.Pointer, nwid, mac C.uint64_t, adi C.uint32_t) {
|
node.handleUserMessage(uint64(um.origin), uint64(um.typeId), C.GoBytes(um.data, C.int(um.length)))
|
||||||
handleTapMulticastGroupChange(gn, nwid, mac, adi, false)
|
case C.ZT_EVENT_REMOTE_TRACE:
|
||||||
|
rt := (*C.ZT_RemoteTrace)(data)
|
||||||
|
node.handleRemoteTrace(uint64(rt.origin), C.GoBytes(unsafe.Pointer(rt.data), C.int(rt.len)))
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@ -663,3 +632,40 @@ func (t *nativeTap) SyncRoutes() error {
|
|||||||
C.ZT_GoTap_syncRoutes(t.tap)
|
C.ZT_GoTap_syncRoutes(t.tap)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
func handleTapMulticastGroupChange(gn unsafe.Pointer, nwid, mac C.uint64_t, adi C.uint32_t, added bool) {
|
||||||
|
go func() {
|
||||||
|
nodesByUserPtrLock.RLock()
|
||||||
|
node := nodesByUserPtr[uintptr(gn)]
|
||||||
|
nodesByUserPtrLock.RUnlock()
|
||||||
|
if node == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node.networksLock.RLock()
|
||||||
|
network := node.networks[uint64(nwid)]
|
||||||
|
node.networksLock.RUnlock()
|
||||||
|
if network != nil {
|
||||||
|
tap, _ := network.tap.(*nativeTap)
|
||||||
|
if tap != nil {
|
||||||
|
mg := &MulticastGroup{MAC: MAC(mac), ADI: uint32(adi)}
|
||||||
|
tap.multicastGroupHandlersLock.Lock()
|
||||||
|
defer tap.multicastGroupHandlersLock.Unlock()
|
||||||
|
for _, h := range tap.multicastGroupHandlers {
|
||||||
|
h(added, mg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goHandleTapAddedMulticastGroup
|
||||||
|
func goHandleTapAddedMulticastGroup(gn, tapP unsafe.Pointer, nwid, mac C.uint64_t, adi C.uint32_t) {
|
||||||
|
handleTapMulticastGroupChange(gn, nwid, mac, adi, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export goHandleTapRemovedMulticastGroup
|
||||||
|
func goHandleTapRemovedMulticastGroup(gn, tapP unsafe.Pointer, nwid, mac C.uint64_t, adi C.uint32_t) {
|
||||||
|
handleTapMulticastGroupChange(gn, nwid, mac, adi, false)
|
||||||
|
}
|
||||||
|
@ -13,7 +13,10 @@
|
|||||||
|
|
||||||
package zerotier
|
package zerotier
|
||||||
|
|
||||||
import "net"
|
import (
|
||||||
|
"net"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// Route represents a route in a host's routing table
|
// Route represents a route in a host's routing table
|
||||||
type Route struct {
|
type Route struct {
|
||||||
@ -29,3 +32,13 @@ type Route struct {
|
|||||||
// Metric is an interface metric that can affect route priority (behavior can be OS-specific)
|
// Metric is an interface metric that can affect route priority (behavior can be OS-specific)
|
||||||
Metric uint16
|
Metric uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// key generates a key suitable for a map[] from this route
|
||||||
|
func (r *Route) key() (k [6]uint64) {
|
||||||
|
copy(((*[16]byte)(unsafe.Pointer(&k[0])))[:], r.Target.IP)
|
||||||
|
ones, bits := r.Target.Mask.Size()
|
||||||
|
k[2] = (uint64(ones) << 32) | uint64(bits)
|
||||||
|
copy(((*[16]byte)(unsafe.Pointer(&k[3])))[:], r.Via)
|
||||||
|
k[5] = (uint64(r.Flags) << 32) | uint64(r.Metric)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user