ソースを参照

Implement fingerprint option on join in Go land

Adam Ierymenko 5 年 前
コミット
60fa07bff2

+ 22 - 3
go/cmd/zerotier/cli/join.go

@@ -23,7 +23,7 @@ import (
 
 // Join CLI command
 func Join(basePath, authToken string, args []string) {
-	if len(args) != 1 {
+	if len(args) < 1 || len(args) > 2 {
 		Help()
 		os.Exit(1)
 	}
@@ -39,9 +39,28 @@ func Join(basePath, authToken string, args []string) {
 	}
 	nwids := fmt.Sprintf("%.16x", nwid)
 
+	var fp *zerotier.Fingerprint
+	if len(args) == 2 {
+		fp, err = zerotier.NewFingerprintFromString(args[1])
+		if err != nil {
+			fmt.Printf("ERROR: invalid network controller fingerprint: %s\n", args[1])
+			os.Exit(1)
+		}
+	}
+
 	var network zerotier.APINetwork
 	network.ID = zerotier.NetworkID(nwid)
-	apiPost(basePath, authToken, "/network/"+nwids, &network, nil)
-	fmt.Printf("OK %s", nwids)
+	network.ControllerFingerprint = fp
+
+	if apiPost(basePath, authToken, "/network/"+nwids, &network, nil) <= 0 {
+		fmt.Printf("FAILED\n")
+	} else {
+		if fp == nil {
+			fmt.Printf("OK %s\n", nwids)
+		} else {
+			fmt.Printf("OK %s %s\n", nwids, fp.String())
+		}
+	}
+
 	os.Exit(0)
 }

+ 2 - 2
go/native/GoGlue.cpp

@@ -593,7 +593,7 @@ static void tapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,
 		&(reinterpret_cast<ZT_GoNode *>(uptr)->nextBackgroundTaskDeadline));
 }
 
-extern "C" ZT_GoTap *ZT_GoNode_join(ZT_GoNode *gn,uint64_t nwid)
+extern "C" ZT_GoTap *ZT_GoNode_join(ZT_GoNode *gn,uint64_t nwid,const ZT_Fingerprint *const controllerFingerprint)
 {
 	try {
 		std::lock_guard<std::mutex> l(gn->taps_l);
@@ -606,7 +606,7 @@ extern "C" ZT_GoTap *ZT_GoNode_join(ZT_GoNode *gn,uint64_t nwid)
 		if (!tap)
 			return nullptr;
 		gn->taps[nwid] = tap;
-		gn->node->join(nwid,tap.get(),nullptr);
+		gn->node->join(nwid,controllerFingerprint,tap.get(),nullptr);
 		return (ZT_GoTap *)tap.get();
 	} catch ( ... ) {
 		return nullptr;

+ 1 - 1
go/native/GoGlue.h

@@ -54,7 +54,7 @@ int ZT_GoNode_phyStartListen(ZT_GoNode *gn,const char *dev,const char *ip,int po
 /* Close all listener threads for a given local IP and port */
 int ZT_GoNode_phyStopListen(ZT_GoNode *gn,const char *dev,const char *ip,int port);
 
-ZT_GoTap *ZT_GoNode_join(ZT_GoNode *gn,uint64_t nwid);
+ZT_GoTap *ZT_GoNode_join(ZT_GoNode *gn,uint64_t nwid,const ZT_Fingerprint *controllerFingerprint);
 
 void ZT_GoNode_leave(ZT_GoNode *gn,uint64_t nwid);
 

+ 9 - 0
go/pkg/zerotier/address.go

@@ -39,6 +39,15 @@ func NewAddressFromBytes(b []byte) (Address, error) {
 	return Address((uint64(b[0]) << 32) | (uint64(b[1]) << 24) | (uint64(b[2]) << 16) | (uint64(b[3]) << 8) | uint64(b[4])), nil
 }
 
+// Copy this address to a byte array, which must be 5 bytes in length or this will panic.
+func (a Address) CopyTo(b []byte) {
+	b[0] = byte(a >> 32)
+	b[1] = byte(a >> 24)
+	b[2] = byte(a >> 16)
+	b[3] = byte(a >> 8)
+	b[4] = byte(a)
+}
+
 // IsReserved returns true if this address is reserved and therefore is not valid for a real node.
 func (a Address) IsReserved() bool { return a == 0 || (a>>32) == 0xff }
 

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

@@ -151,6 +151,7 @@ type APINetwork struct {
 	ID                     NetworkID             `json:"id"`
 	Config                 NetworkConfig         `json:"config"`
 	Settings               *NetworkLocalSettings `json:"settings,omitempty"`
+	ControllerFingerprint  *Fingerprint          `json:"controllerFingerprint,omitempty"`
 	MulticastSubscriptions []*MulticastGroup     `json:"multicastSubscriptions,omitempty"`
 	PortType               string                `json:"portType"`
 	PortName               string                `json:"portName"`

+ 60 - 0
go/pkg/zerotier/fingerprint.go

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c)2013-2020 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: 2024-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
+
+//#cgo CFLAGS: -O3
+//#include "../../native/GoGlue.h"
+import "C"
+
+import (
+	"encoding/base32"
+	"errors"
+	"strings"
+	"unsafe"
+)
+
+var ztBase32 = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567").WithPadding(base32.NoPadding)
+
+type Fingerprint struct {
+	Address Address  `json:"address"`
+	Hash    [48]byte `json:"hash"`
+}
+
+func NewFingerprintFromString(fps string) (*Fingerprint, error) {
+	fpb, err := ztBase32.DecodeString(strings.TrimSpace(strings.ToLower(fps)))
+	if err != nil {
+		return nil, err
+	}
+	if len(fpb) != 53 {
+		return nil, errors.New("invalid fingerprint length")
+	}
+	var fp Fingerprint
+	fp.Address, _ = NewAddressFromBytes(fpb[0:5])
+	copy(fp.Hash[:],fpb[5:])
+	return &fp, nil
+}
+
+func (fp *Fingerprint) String() string {
+	var tmp [53]byte
+	fp.Address.CopyTo(tmp[0:5])
+	copy(tmp[5:],fp.Hash[:])
+	return ztBase32.EncodeToString(tmp[:])
+}
+
+func (fp *Fingerprint) apiFingerprint() *C.ZT_Fingerprint {
+	var apifp C.ZT_Fingerprint
+	apifp.address = C.uint64_t(fp.Address)
+	copy((*[48]byte)(unsafe.Pointer(&apifp.hash[0]))[:], fp.Hash[:])
+	return &apifp
+}

+ 6 - 2
go/pkg/zerotier/node.go

@@ -498,7 +498,7 @@ func (n *Node) SetLocalConfig(lc *LocalConfig) (restartRequired bool, err error)
 
 // Join a network.
 // If tap is nil, the default system tap for this OS/platform is used (if available).
-func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*Network, error) {
+func (n *Node) Join(nwid NetworkID, controllerFingerprint *Fingerprint, settings *NetworkLocalSettings, tap Tap) (*Network, error) {
 	n.networksLock.RLock()
 	if nw, have := n.networks[nwid]; have {
 		n.infoLog.Printf("join network %.16x ignored: already a member", nwid)
@@ -512,7 +512,11 @@ func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*N
 	if tap != nil {
 		panic("non-native taps not yet implemented")
 	}
-	ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid))
+	var fp *C.ZT_Fingerprint
+	if controllerFingerprint != nil {
+		fp = controllerFingerprint.apiFingerprint()
+	}
+	ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid), fp)
 	if ntap == nil {
 		n.infoLog.Printf("join network %.16x failed: tap device failed to initialize (check drivers / kernel modules)", uint64(nwid))
 		return nil, ErrTapInitFailed

+ 1 - 1
node/NetworkConfig.hpp

@@ -206,7 +206,7 @@ struct NetworkConfig : TriviallyCopyable
 	ZT_INLINE bool permitsBridging(const Address &fromPeer) const noexcept
 	{
 		for(unsigned int i=0;i<specialistCount;++i) {
-			if ((fromPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0))
+			if ((fromPeer.toInt() == (specialists[i] & ZT_ADDRESS_MASK))&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0))
 				return true;
 		}
 		return false;