Implement fingerprint option on join in Go land

This commit is contained in:
Adam Ierymenko 2020-03-27 17:02:44 -07:00
parent 1df7f21f5f
commit 60fa07bff2
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
8 changed files with 102 additions and 9 deletions

View file

@ -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)
}

View file

@ -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;

View file

@ -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);

View file

@ -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 }

View file

@ -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"`

View file

@ -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
}

View file

@ -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

View file

@ -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;