Przeglądaj źródła

Build fix, add Go unit tests for CGo Locator interface.

Adam Ierymenko 4 lat temu
rodzic
commit
1bb43476e8

+ 43 - 27
cmd/zerotier/cli/cert.go

@@ -48,20 +48,27 @@ func Cert(basePath string, authTokenGenerator func() string, args []string, json
 			Help()
 			return 1
 		}
+
 		uniqueId, uniqueIdPrivate, err := zerotier.NewCertificateSubjectUniqueId(zerotier.CertificateUniqueIdTypeNistP384)
 		if err != nil {
-			fmt.Printf("ERROR: unable to create unique ID and private key: %s\n", err.Error())
+			pErr("unable to create unique ID and private key: %s", err.Error())
 			return 1
 		}
-		sec, err := json.MarshalIndent(&zerotier.CertificateSubjectUniqueIDSecret{UniqueID: uniqueId, UniqueIDSecret: uniqueIdPrivate}, "", "  ")
+
+		sec, err := json.MarshalIndent(&zerotier.CertificateSubjectUniqueIDSecret{
+			UniqueID: uniqueId,
+			UniqueIDSecret: uniqueIdPrivate,
+		}, "", "  ")
 		if err != nil {
-			fmt.Printf("ERROR: unable to create unique ID and private key: %s\n", err.Error())
+			pErr("unable to create unique ID and private key: %s", err.Error())
 			return 1
 		}
+
 		if len(args) == 1 {
 			fmt.Println(string(sec))
 		} else {
 			_ = ioutil.WriteFile(args[1], sec, 0600)
+			pResult("%s", args[1])
 		}
 
 	case "newcsr":
@@ -69,28 +76,32 @@ func Cert(basePath string, authTokenGenerator func() string, args []string, json
 			Help()
 			return 1
 		}
-		var cs zerotier.CertificateSubject
-		err := readJSONFile(args[1], &cs)
+
+		var subject zerotier.CertificateSubject
+		err := readJSONFile(args[1], &subject)
 		if err != nil {
-			fmt.Printf("ERROR: unable to read subject from %s: %s\n", args[1], err.Error())
+			pErr("unable to read subject from %s: %s", args[1], err.Error())
 			return 1
 		}
-		var subj zerotier.CertificateSubjectUniqueIDSecret
-		err = readJSONFile(args[2], &subj)
+
+		var uniqueIdSecret zerotier.CertificateSubjectUniqueIDSecret
+		err = readJSONFile(args[2], &uniqueIdSecret)
 		if err != nil {
-			fmt.Printf("ERROR: unable to read unique ID secret from %s: %s\n", args[2], err.Error())
+			pErr("unable to read unique ID secret from %s: %s", args[2], err.Error())
 			return 1
 		}
-		csr, err := zerotier.NewCertificateCSR(&cs, subj.UniqueID, subj.UniqueIDSecret)
+
+		csr, err := zerotier.NewCertificateCSR(&subject, uniqueIdSecret.UniqueID, uniqueIdSecret.UniqueIDSecret)
 		if err != nil {
-			fmt.Printf("ERROR: problem creating CSR: %s\n", err.Error())
+			pErr("problem creating CSR: %s", err.Error())
 			return 1
 		}
+
 		err = ioutil.WriteFile(args[3], csr, 0644)
 		if err == nil {
-			fmt.Printf("Wrote CSR to %s\n", args[3])
+			pResult("%s", args[3])
 		} else {
-			fmt.Printf("ERROR: unable to write CSR to %s: %s\n", args[3], err.Error())
+			pErr("unable to write CSR to %s: %s", args[3], err.Error())
 			return 1
 		}
 
@@ -102,40 +113,42 @@ func Cert(basePath string, authTokenGenerator func() string, args []string, json
 
 		csrBytes, err := ioutil.ReadFile(args[1])
 		if err != nil {
-			fmt.Printf("ERROR: unable to read CSR from %s: %s\n", args[1], err.Error())
+			pErr("unable to read CSR from %s: %s", args[1], err.Error())
 			return 1
 		}
 		csr, err := zerotier.NewCertificateFromBytes(csrBytes, false)
 		if err != nil {
-			fmt.Printf("ERROR: CSR in %s is invalid: %s\n", args[1], err.Error())
+			pErr("CSR in %s is invalid: %s", args[1], err.Error())
 			return 1
 		}
 
-		id := readIdentity(args[2])
-		if id == nil {
-			fmt.Printf("ERROR: unable to read identity from %s\n", args[2])
+		signingIdentity := readIdentity(args[2])
+		if signingIdentity == nil {
+			pErr("unable to read identity from %s", args[2])
 			return 1
 		}
-		if !id.HasPrivate() {
-			fmt.Printf("ERROR: signing identity in %s lacks private key\n", args[2])
+		if !signingIdentity.HasPrivate() {
+			pErr("signing identity in %s lacks private key", args[2])
 			return 1
 		}
 
-		cert, err := csr.Sign(id)
+		cert, err := csr.Sign(signingIdentity)
 		if err != nil {
-			fmt.Printf("ERROR: error signing CSR or generating certificate: %s\n", err.Error())
+			pErr("error signing CSR or generating certificate: %s", err.Error())
 			return 1
 		}
+
 		cb, err := cert.Marshal()
 		if err != nil {
-			fmt.Printf("ERROR: error marshaling signed certificate: %s\n", err.Error())
+			pErr("error marshaling signed certificate: %s", err.Error())
 			return 1
 		}
+
 		err = ioutil.WriteFile(args[3], cb, 0644)
 		if err == nil {
-			fmt.Printf("Wrote signed certificate to %s\n", args[3])
+			pResult("%s", args[3])
 		} else {
-			fmt.Printf("ERROR: unable to write signed certificate to %s: %s\n", args[3], err.Error())
+			pErr("unable to write signed certificate to %s: %s", args[3], err.Error())
 			return 1
 		}
 
@@ -144,16 +157,19 @@ func Cert(basePath string, authTokenGenerator func() string, args []string, json
 			Help()
 			return 1
 		}
+
 		certBytes, err := ioutil.ReadFile(args[1])
 		if err != nil {
-			fmt.Printf("ERROR: unable to read certificate from %s: %s\n", args[1], err.Error())
+			pErr("unable to read certificate from %s: %s", args[1], err.Error())
 			return 1
 		}
+
 		cert, err := zerotier.NewCertificateFromBytes(certBytes, true)
 		if err != nil {
-			fmt.Printf("FAILED: certificate in %s invalid: %s\n", args[1], err.Error())
+			pErr("certificate in %s invalid: %s", args[1], err.Error())
 			return 1
 		}
+
 		if args[0] == "dump" {
 			fmt.Println(cert.JSON())
 		} else {

+ 0 - 1
cmd/zerotier/cli/help.go

@@ -97,7 +97,6 @@ Advanced Operations:
   cert <command> [args]
 ·   list                                  List certificates at local node
 ·   show <serial>                         Show certificate details
-    newsubject <subject out>              Interactive subject creation
     newsid <secret out>                   Create a new subject unique ID
     newcsr <subject|-> <secret> <csr out> Create a subject CSR
     sign <csr> <identity> <cert out>      Sign a CSR to create a certificate

+ 11 - 5
cmd/zerotier/cli/identity.go

@@ -43,11 +43,13 @@ func Identity(args []string) int {
 					return 1
 				}
 			}
+
 			id, err := zerotier.NewIdentity(idType)
 			if err != nil {
-				fmt.Printf("ERROR: internal error generating identity: %s\n", err.Error())
+				pErr("internal error generating identity: %s", err.Error())
 				return 1
 			}
+
 			fmt.Println(id.PrivateKeyString())
 			return 0
 
@@ -56,20 +58,24 @@ func Identity(args []string) int {
 				fmt.Println(readIdentity(args[1]).String())
 				return 0
 			}
+			pErr("no identity specified")
+			return 1
 
 		case "fingerprint":
 			if len(args) == 2 {
 				fmt.Println(readIdentity(args[1]).Fingerprint().String())
 				return 0
 			}
+			pErr("no identity specified")
+			return 1
 
 		case "validate":
 			if len(args) == 2 {
 				if readIdentity(args[1]).LocallyValidate() {
-					fmt.Println("OK")
+					fmt.Println("VALID")
 					return 0
 				}
-				fmt.Println("FAILED")
+				fmt.Println("INVALID")
 				return 1
 			}
 
@@ -78,7 +84,7 @@ func Identity(args []string) int {
 				id := readIdentity(args[1])
 				msg, err := ioutil.ReadFile(args[2])
 				if err != nil {
-					fmt.Printf("ERROR: unable to read input file: %s\n", err.Error())
+					pErr("unable to read input file: %s", err.Error())
 					return 1
 				}
 
@@ -99,7 +105,7 @@ func Identity(args []string) int {
 				} else {
 					sig, err := id.Sign(msg)
 					if err != nil {
-						fmt.Printf("ERROR: internal error signing message: %s\n", err.Error())
+						pErr("internal error signing message: %s", err.Error())
 						return 1
 					}
 					fmt.Println(hex.EncodeToString(sig))

+ 12 - 12
cmd/zerotier/cli/join.go

@@ -39,10 +39,17 @@ func Join(basePath string, authTokenGenerator func() string, args []string) int
 		Help()
 		return 1
 	}
-	if len(args[0]) != zerotier.NetworkIDStringLength {
-		fmt.Printf("ERROR: invalid network ID: %s\n", args[0])
+
+	if !isValidNetworkID(args[0]) {
+		pErr("invalid network ID: %s", args[0])
+		return 1
+	}
+	nwid, err := strconv.ParseUint(args[0], 16, 64)
+	if err != nil {
+		pErr("ERROR: invalid network ID: %s", args[0])
 		return 1
 	}
+	nwids := fmt.Sprintf("%.16x", nwid)
 
 	_ = *controllerAuthToken // TODO: not implemented yet
 
@@ -51,32 +58,25 @@ func Join(basePath string, authTokenGenerator func() string, args []string) int
 		if strings.ContainsRune(*controllerFingerprint, '-') {
 			fp, err = zerotier.NewFingerprintFromString(*controllerFingerprint)
 			if err != nil {
-				fmt.Printf("ERROR: invalid network controller fingerprint: %s\n", *controllerFingerprint)
+				pErr("invalid network controller fingerprint: %s", *controllerFingerprint)
 				return 1
 			}
 		} else {
 			id, err := zerotier.NewIdentityFromString(*controllerFingerprint)
 			if err != nil {
-				fmt.Printf("ERROR: invalid network controller identity: %s\n", *controllerFingerprint)
+				pErr("invalid network controller identity: %s", *controllerFingerprint)
 				return 1
 			}
 			fp = id.Fingerprint()
 		}
 	}
 
-	nwid, err := strconv.ParseUint(args[0], 16, 64)
-	if err != nil {
-		fmt.Printf("ERROR: invalid network ID: %s\n", args[0])
-		return 1
-	}
-	nwids := fmt.Sprintf("%.16x", nwid)
-
 	var network zerotier.APINetwork
 	network.ID = zerotier.NetworkID(nwid)
 	network.ControllerFingerprint = fp
 
 	if apiPost(basePath, authToken, "/network/"+nwids, &network, nil) <= 0 {
-		fmt.Printf("FAILED\n")
+		fmt.Println("FAILED")
 	} else {
 		if fp == nil {
 			fmt.Printf("OK %s\n", nwids)

+ 12 - 2
cmd/zerotier/cli/misc.go

@@ -14,18 +14,26 @@
 package cli
 
 import (
-	"bufio"
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
 	"net/http"
 	"os"
-	"strconv"
 	"strings"
 
 	"zerotier/pkg/zerotier"
 )
 
+func pErr(format string, args ...interface{}) {
+	_, _ = fmt.Fprintf(os.Stdout, "ERROR: "+format, args...)
+	fmt.Println()
+}
+
+func pResult(format string, args ...interface{}) {
+	_, _ = fmt.Printf(format, args...)
+	fmt.Println()
+}
+
 func apiGet(basePath, authToken, urlPath string, result interface{}) int64 {
 	statusCode, clock, err := zerotier.APIGet(basePath, zerotier.APISocketName, authToken, urlPath, result)
 	if err != nil {
@@ -238,6 +246,7 @@ func isValidNetworkID(a string) bool {
 	return false
 }
 
+/*
 func prompt(str string, dfl string) string {
 	if len(dfl) > 0 {
 		fmt.Printf("%s [%s]: ", str, dfl)
@@ -274,3 +283,4 @@ func promptFile(str string) []byte {
 	}
 	return nil
 }
+*/

+ 2 - 2
cmd/zerotier/cli/network.go

@@ -124,12 +124,12 @@ func Network(basePath string, authTokenGenerator func() string, args []string, j
 	}
 
 	if len(args[0]) != zerotier.NetworkIDStringLength {
-		fmt.Printf("ERROR: invalid network ID: %s\n", args[0])
+		pErr("ERROR: invalid network ID: %s", args[0])
 		return 1
 	}
 	nwid, err := strconv.ParseUint(args[0], 16, 64)
 	if err != nil {
-		fmt.Printf("ERROR: invalid network ID: %s\n", args[0])
+		pErr("ERROR: invalid network ID: %s", args[0])
 		return 1
 	}
 	nwids := fmt.Sprintf("%.16x", nwid)

+ 53 - 0
cmd/zt_service_tests/locator.go

@@ -0,0 +1,53 @@
+/*
+ * 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: 2025-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 main
+
+import (
+	"fmt"
+	"zerotier/pkg/zerotier"
+)
+
+func TestLocator() bool {
+	fmt.Printf("Creating Endpoint instances... ")
+	ep0, err := zerotier.NewEndpointFromString("1.1.1.1/1")
+	if err != nil {
+		fmt.Printf("IPv4 FAILED (%s)\n",err.Error())
+		return false
+	}
+	ep1, err := zerotier.NewEndpointFromString("2600:1901:0:4006::1234/2")
+	if err != nil {
+		fmt.Printf("IPv6 FAILED (%s)\n",err.Error())
+		return false
+	}
+	eps := []*zerotier.Endpoint{ep0, ep1}
+	fmt.Printf("OK\n")
+
+	fmt.Printf("Creating signing Identity... ")
+	signer, err := zerotier.NewIdentity(zerotier.IdentityTypeP384)
+	if err != nil {
+		fmt.Printf("FAILED (%s)\n", err.Error())
+		return false
+	}
+	fmt.Printf("OK %s\n",signer.String())
+
+	fmt.Printf("Creating Locator instance... ")
+	loc, err := zerotier.NewLocator(zerotier.TimeMs(), eps, signer)
+	if err != nil {
+		fmt.Printf("FAILED (%s)\n",err.Error())
+		return false
+	}
+	fmt.Printf("OK %s\n",loc.String())
+
+	return true
+}

+ 3 - 0
cmd/zt_service_tests/zt_service_tests.go

@@ -13,4 +13,7 @@ func main() {
 	if !TestCertificate() {
 		os.Exit(1)
 	}
+	if !TestLocator() {
+		os.Exit(1)
+	}
 }

+ 4 - 4
pkg/zerotier/identity.go

@@ -111,7 +111,7 @@ func NewIdentityFromString(s string) (*Identity, error) {
 		}
 
 	case 1:
-		id.publicKey, err = Base32StdLowerCase.DecodeString(ss[2])
+		id.publicKey, err = Base32.DecodeString(ss[2])
 		if err != nil {
 			return nil, err
 		}
@@ -119,7 +119,7 @@ func NewIdentityFromString(s string) (*Identity, error) {
 			return nil, ErrInvalidKey
 		}
 		if len(ss) >= 4 {
-			id.privateKey, err = Base32StdLowerCase.DecodeString(ss[3])
+			id.privateKey, err = Base32.DecodeString(ss[3])
 			if err != nil {
 				return nil, err
 			}
@@ -190,7 +190,7 @@ func (id *Identity) PrivateKeyString() string {
 		}
 	case IdentityTypeP384:
 		if len(id.publicKey) == IdentityTypeP384PublicKeySize && len(id.privateKey) == IdentityTypeP384PrivateKeySize {
-			return fmt.Sprintf("%.10x:1:%s:%s", uint64(id.address), Base32StdLowerCase.EncodeToString(id.publicKey), Base32StdLowerCase.EncodeToString(id.privateKey))
+			return fmt.Sprintf("%.10x:1:%s:%s", uint64(id.address), Base32.EncodeToString(id.publicKey), Base32.EncodeToString(id.privateKey))
 		}
 	}
 	return ""
@@ -206,7 +206,7 @@ func (id *Identity) String() string {
 		}
 	case IdentityTypeP384:
 		if len(id.publicKey) == IdentityTypeP384PublicKeySize {
-			return fmt.Sprintf("%.10x:1:%s", uint64(id.address), Base32StdLowerCase.EncodeToString(id.publicKey))
+			return fmt.Sprintf("%.10x:1:%s", uint64(id.address), Base32.EncodeToString(id.publicKey))
 		}
 	}
 	return ""

+ 3 - 3
pkg/zerotier/locator.go

@@ -39,7 +39,7 @@ func newLocatorFromCLocator(cl unsafe.Pointer, needFinalizer bool) (*Locator, er
 	return loc, nil
 }
 
-func NewLocator(ts int64, endpoints []Endpoint, signer *Identity) (*Locator, error) {
+func NewLocator(ts int64, endpoints []*Endpoint, signer *Identity) (*Locator, error) {
 	if ts <= 0 || len(endpoints) == 0 || signer == nil {
 		return nil, ErrInvalidParameter
 	}
@@ -110,8 +110,8 @@ func (loc *Locator) String() string {
 	if loc.cl == nil {
 		return ""
 	}
-	var buf [4096]C.char
-	return C.GoString(C.ZT_Locator_toString(loc.cl, &buf[0], 4096))
+	var buf [16384]C.char // 16384 == ZT_LOCATOR_STRING_SIZE_MAX
+	return C.GoString(C.ZT_Locator_toString(loc.cl, &buf[0], 16384))
 }
 
 func (loc *Locator) MarshalJSON() ([]byte, error) {

+ 2 - 2
pkg/zerotier/misc.go

@@ -35,8 +35,8 @@ const pointerSize = unsafe.Sizeof(uintptr(0))
 // Base32Alphabet is the Base32 alphabet used in ZeroTier.
 const Base32Alphabet = "abcdefghijklmnopqrstuvwxyz234567"
 
-// Base32 is an encoder using the ZeroTier base32 encoding.
-var Base32 = base32.NewEncoding(Base32Alphabet)
+// Base32 is an encoder using the ZeroTier base32 encoding and no padding (same as core).
+var Base32 = base32.NewEncoding(Base32Alphabet).WithPadding(base32.NoPadding)
 
 // unassignedPrivilegedPorts are ports below 1024 that do not appear to be assigned by IANA.
 // The new 2.0+ ZeroTier default is 793, which we will eventually seek to have assigned. These