mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-03-10 22:44:21 +00:00
Network config stuff in Go
This commit is contained in:
parent
2eef9d22e6
commit
bcb9df9cdf
@ -15,6 +15,7 @@ package zerotier
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"time"
|
||||
"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
|
||||
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()
|
||||
k[2] = (uint64(ones) << 32) | uint64(bits)
|
||||
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
|
||||
func (n NetworkID) MarshalJSON() ([]byte, error) {
|
||||
return []byte(n.String()), nil
|
||||
return []byte("\"" + n.String() + "\""), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals this NetworkID from a string
|
||||
@ -75,13 +75,13 @@ type NetworkConfig struct {
|
||||
// MTU is the Ethernet MTU for this network
|
||||
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
|
||||
|
||||
// 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
|
||||
|
||||
// Network configuration revision number according to network controller
|
||||
// NetconfRevision is the revision number reported by the controller
|
||||
NetconfRevision uint64
|
||||
|
||||
// AssignedAddresses are static IPs assigned by the network controller to this device
|
||||
@ -91,13 +91,50 @@ type NetworkConfig struct {
|
||||
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
|
||||
type Network struct {
|
||||
id NetworkID
|
||||
config NetworkConfig
|
||||
tap Tap
|
||||
config NetworkConfig
|
||||
settings NetworkLocalSettings // locked by configLock
|
||||
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
|
||||
@ -111,36 +148,84 @@ func (n *Network) Config() NetworkConfig {
|
||||
}
|
||||
|
||||
// Tap gets this network's tap device
|
||||
func (n *Network) Tap() Tap {
|
||||
n.tapLock.RLock()
|
||||
defer n.tapLock.RUnlock()
|
||||
return n.tap
|
||||
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) }
|
||||
|
||||
func (n *Network) networkConfigRevision() uint64 {
|
||||
n.configLock.RLock()
|
||||
defer n.configLock.RUnlock()
|
||||
return n.config.NetconfRevision
|
||||
}
|
||||
|
||||
func (n *Network) handleNetworkConfigUpdate(nc *NetworkConfig) {
|
||||
n.tapLock.RLock()
|
||||
func networkManagedIPAllowed(ip net.IP, ls *NetworkLocalSettings) bool {
|
||||
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()
|
||||
defer n.configLock.Unlock()
|
||||
defer n.tapLock.RUnlock()
|
||||
|
||||
if n.tap == nil { // sanity check
|
||||
if n.tap == nil { // sanity check, should never happen
|
||||
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,
|
||||
// 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
|
||||
// "ifconfig" command) are left alone.
|
||||
haveAssignedIPs := make(map[[3]uint64]*net.IPNet)
|
||||
for _, ip := range n.config.AssignedAddresses {
|
||||
haveAssignedIPs[ipNetToKey(&ip)] = &ip
|
||||
}
|
||||
wantAssignedIPs := make(map[[3]uint64]bool)
|
||||
for _, ip := range nc.AssignedAddresses {
|
||||
k := ipNetToKey(&ip)
|
||||
wantAssignedIPs[k] = true
|
||||
if _, have := haveAssignedIPs[k]; !have {
|
||||
n.tap.AddIP(&ip)
|
||||
if n.settings.AllowManagedIPs {
|
||||
for _, ip := range n.config.AssignedAddresses {
|
||||
if networkManagedIPAllowed(ip.IP, &n.settings) { // was it allowed?
|
||||
haveAssignedIPs[ipNetToKey(&ip)] = &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 {
|
||||
@ -148,4 +233,38 @@ func (n *Network) handleNetworkConfigUpdate(nc *NetworkConfig) {
|
||||
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
|
||||
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 int = C.ZEROTIER_ONE_VERSION_MAJOR
|
||||
|
||||
@ -136,13 +139,10 @@ func (n *Node) Join(nwid uint64, tap Tap) (*Network, error) {
|
||||
return nil, ErrTapInitFailed
|
||||
}
|
||||
|
||||
nw := &Network{
|
||||
id: NetworkID(nwid),
|
||||
config: NetworkConfig{
|
||||
ID: NetworkID(nwid),
|
||||
Status: NetworkStatusRequestConfiguration,
|
||||
},
|
||||
tap: &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1},
|
||||
nw, err := NewNetwork(NetworkID(nwid), &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1})
|
||||
if err != nil {
|
||||
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
|
||||
return nil, err
|
||||
}
|
||||
n.networksLock.Lock()
|
||||
n.networks[nwid] = nw
|
||||
@ -368,113 +368,82 @@ func sockaddrStorageToIPNet(ss *C.struct_sockaddr_storage) *net.IPNet {
|
||||
|
||||
//export goVirtualNetworkConfigFunc
|
||||
func goVirtualNetworkConfigFunc(gn, tapP unsafe.Pointer, nwid C.uint64_t, op C.int, conf unsafe.Pointer) {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
go func() {
|
||||
nodesByUserPtrLock.RLock()
|
||||
node := nodesByUserPtr[uintptr(gn)]
|
||||
nodesByUserPtrLock.RUnlock()
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
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
|
||||
node.networksLock.RLock()
|
||||
network := node.networks[uint64(nwid)]
|
||||
node.networksLock.RUnlock()
|
||||
if network != nil {
|
||||
ncc := (*C.ZT_VirtualNetworkConfig)(conf)
|
||||
if network.networkConfigRevision() > uint64(ncc.netconfRevision) {
|
||||
return
|
||||
}
|
||||
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),
|
||||
})
|
||||
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++ {
|
||||
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
|
||||
func goZtEvent(gn unsafe.Pointer, eventType C.int, data unsafe.Pointer) {
|
||||
nodesByUserPtrLock.RLock()
|
||||
node := nodesByUserPtr[uintptr(gn)]
|
||||
nodesByUserPtrLock.RUnlock()
|
||||
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)
|
||||
go func() {
|
||||
nodesByUserPtrLock.RLock()
|
||||
node := nodesByUserPtr[uintptr(gn)]
|
||||
nodesByUserPtrLock.RUnlock()
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//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)
|
||||
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)))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -663,3 +632,40 @@ func (t *nativeTap) SyncRoutes() error {
|
||||
C.ZT_GoTap_syncRoutes(t.tap)
|
||||
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
|
||||
|
||||
import "net"
|
||||
import (
|
||||
"net"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Route represents a route in a host's routing table
|
||||
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 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