Imported Upstream version 1.2.4
This commit is contained in:
parent
bb232b9d52
commit
4722a0b75a
398 changed files with 38633 additions and 24919 deletions
36
.gitignore
vendored
36
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
<<<<<<< HEAD
|
||||
# Main binaries created in *nix builds
|
||||
/zerotier-one
|
||||
/zerotier-idtool
|
||||
|
@ -9,6 +10,7 @@
|
|||
.DS_Store
|
||||
.Apple*
|
||||
Thumbs.db
|
||||
@eaDir
|
||||
|
||||
# Windows build droppings
|
||||
/windows/ZeroTierOne.sdf
|
||||
|
@ -29,6 +31,15 @@ Thumbs.db
|
|||
/ext/installfiles/windows/Prerequisites
|
||||
/ext/installfiles/windows/*-cache
|
||||
/ZeroTier One.msi
|
||||
/windows/.vs
|
||||
*.vcxproj.backup
|
||||
/windows/TapDriver6/Win7Debug
|
||||
/windows/TapDriver6/win7Release
|
||||
/windows/*.db
|
||||
/windows/*.opendb
|
||||
enc_temp_folder
|
||||
/windows/copyutil/bin
|
||||
/windows/copyutil/obj
|
||||
|
||||
# *nix/Mac build droppings
|
||||
/build-*
|
||||
|
@ -49,7 +60,7 @@ zt1-src.tar.gz
|
|||
*.pid
|
||||
*.pkg
|
||||
*.o
|
||||
*.a
|
||||
/*.a
|
||||
*.dylib
|
||||
*.so
|
||||
*.so.*
|
||||
|
@ -59,16 +70,15 @@ zt1-src.tar.gz
|
|||
*.rpm
|
||||
*.autosave
|
||||
*.tmp
|
||||
doc/*.1
|
||||
doc/*.2
|
||||
doc/*.8
|
||||
.depend
|
||||
node_modules
|
||||
zt1_update_*
|
||||
debian/files
|
||||
debian/zerotier-one
|
||||
debian/zerotier-one*.debhelper
|
||||
debian/*.log
|
||||
debian/zerotier-one.substvars
|
||||
root-watcher/config.json
|
||||
|
||||
# Java/Android/JNI build droppings
|
||||
java/obj/
|
||||
|
@ -83,3 +93,21 @@ windows/WinUI/obj/
|
|||
windows/WinUI/bin/
|
||||
windows/ZeroTierOne/Debug/
|
||||
/ext/installfiles/windows/chocolatey/zerotier-one/*.nupkg
|
||||
|
||||
# Miscellaneous mac/Xcode droppings
|
||||
.DS_Store
|
||||
.Trashes
|
||||
*.swp
|
||||
*~.nib
|
||||
DerivedData/
|
||||
build/
|
||||
*.pbxuser
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.perspectivev3
|
||||
!default.pbxuser
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.perspectivev3
|
||||
*.xccheckout
|
||||
xcuserdata/
|
||||
|
|
31
AUTHORS.md
31
AUTHORS.md
|
@ -25,13 +25,13 @@
|
|||
|
||||
## Third-Party Code
|
||||
|
||||
These are included in ext/ for platforms that do not have them available in common repositories. Otherwise they may be linked and the package may ship with them as dependencies.
|
||||
ZeroTier includes the following third party code, either in ext/ or incorporated into the ZeroTier core.
|
||||
|
||||
* LZ4 compression algorithm by Yann Collet
|
||||
|
||||
* Files: ext/lz4/*
|
||||
* Files: node/Packet.cpp (bundled within anonymous namespace)
|
||||
* Home page: http://code.google.com/p/lz4/
|
||||
* License grant: BSD attribution
|
||||
* License grant: BSD 2-clause
|
||||
|
||||
* http-parser by Joyent, Inc. (many authors)
|
||||
|
||||
|
@ -39,11 +39,11 @@ These are included in ext/ for platforms that do not have them available in comm
|
|||
* Home page: https://github.com/joyent/http-parser/
|
||||
* License grant: MIT/Expat
|
||||
|
||||
* json-parser by James McLaughlin
|
||||
* C++11 json (nlohmann/json) by Niels Lohmann
|
||||
|
||||
* Files: ext/json-parser/*
|
||||
* Home page: https://github.com/udp/json-parser/
|
||||
* License grant: BSD attribution
|
||||
* Files: ext/json/*
|
||||
* Home page: https://github.com/nlohmann/json
|
||||
* License grant: MIT
|
||||
|
||||
* TunTapOSX by Mattias Nissler
|
||||
|
||||
|
@ -55,26 +55,19 @@ These are included in ext/ for platforms that do not have them available in comm
|
|||
* tap-windows6 by the OpenVPN project
|
||||
|
||||
* Files: windows/TapDriver6/*
|
||||
* Home page:
|
||||
https://github.com/OpenVPN/tap-windows6/
|
||||
* Home page: https://github.com/OpenVPN/tap-windows6/
|
||||
* License grant: GNU GPL v2
|
||||
* ZeroTier Modifications: change name of driver to ZeroTier, add ioctl() to get L2 multicast memberships (source is in ext/ and modifications inherit GPL)
|
||||
|
||||
* Salsa20 stream cipher, Curve25519 elliptic curve cipher, Ed25519
|
||||
digital signature algorithm, and Poly1305 MAC algorithm, all by
|
||||
Daniel J. Bernstein
|
||||
* Salsa20 stream cipher, Curve25519 elliptic curve cipher, Ed25519 digital signature algorithm, and Poly1305 MAC algorithm, all by Daniel J. Bernstein
|
||||
|
||||
* Files:
|
||||
node/Salsa20.hpp
|
||||
node/C25519.hpp
|
||||
node/Poly1305.hpp
|
||||
* Files: node/Salsa20.* node/C25519.* node/Poly1305.*
|
||||
* Home page: http://cr.yp.to/
|
||||
* License grant: public domain
|
||||
* ZeroTier Modifications: slight cryptographically-irrelevant modifications for inclusion into ZeroTier core
|
||||
|
||||
* MiniUPNPC and libnatpmp by Thomas Bernard
|
||||
|
||||
* Files:
|
||||
ext/libnatpmp/*
|
||||
ext/miniupnpc/*
|
||||
* Files: ext/libnatpmp/* ext/miniupnpc/*
|
||||
* Home page: http://miniupnp.free.fr/
|
||||
* License grant: BSD attribution no-endorsement
|
||||
|
|
82
Jenkinsfile
vendored
Normal file
82
Jenkinsfile
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/env groovy
|
||||
|
||||
node('master') {
|
||||
def changelog = getChangeLog currentBuild
|
||||
|
||||
slackSend "Building ${env.JOB_NAME} #${env.BUILD_NUMBER} \n Change Log: \n ${changelog}"
|
||||
}
|
||||
|
||||
parallel 'centos7': {
|
||||
node('centos7') {
|
||||
try {
|
||||
checkout scm
|
||||
|
||||
stage('Build Centos 7') {
|
||||
sh 'make -f make-linux.mk'
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
currentBuild.result = "FAILURE"
|
||||
slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on Centos 7 (<${env.BUILD_URL}|Open>)"
|
||||
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}, 'android-ndk': {
|
||||
node('android-ndk') {
|
||||
try {
|
||||
checkout scm
|
||||
|
||||
stage('Build Android NDK') {
|
||||
sh "/android/android-ndk-r13b/ndk-build -C $WORKSPACE/java ZT1=${WORKSPACE}"
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
currentBuild.result = "FAILURE"
|
||||
slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on Android NDK (<${env.BUILD_URL}|Open>)"
|
||||
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}, 'macOS': {
|
||||
node('macOS') {
|
||||
try {
|
||||
checkout scm
|
||||
|
||||
stage('Build macOS') {
|
||||
sh 'make -f make-mac.mk'
|
||||
}
|
||||
|
||||
stage('Build macOS UI') {
|
||||
sh 'cd macui && xcodebuild -target "ZeroTier One" -configuration Debug'
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
currentBuild.result = "FAILURE"
|
||||
slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)"
|
||||
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}, 'windows': {
|
||||
node('windows') {
|
||||
try {
|
||||
checkout scm
|
||||
|
||||
stage('Build Windows') {
|
||||
bat '''CALL "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat" amd64
|
||||
git clean -dfx
|
||||
msbuild windows\\ZeroTierOne.sln
|
||||
'''
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
currentBuild.result = "FAILURE"
|
||||
slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on Windows (<${env.BUILD_URL}|Open>)"
|
||||
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slackSend color: "#00ff00", message: "${env.JOB_NAME} #${env.BUILD_NUMBER} Complete (<${env.BUILD_URL}|Show More...>)"
|
10
Makefile
10
Makefile
|
@ -11,8 +11,14 @@ ifeq ($(OSTYPE),Linux)
|
|||
endif
|
||||
|
||||
ifeq ($(OSTYPE),FreeBSD)
|
||||
include make-freebsd.mk
|
||||
CC=clang
|
||||
CXX=clang++
|
||||
ZT_BUILD_PLATFORM=7
|
||||
include make-bsd.mk
|
||||
endif
|
||||
ifeq ($(OSTYPE),OpenBSD)
|
||||
include make-freebsd.mk
|
||||
CC=egcc
|
||||
CXX=eg++
|
||||
ZT_BUILD_PLATFORM=9
|
||||
include make-bsd.mk
|
||||
endif
|
||||
|
|
|
@ -15,6 +15,7 @@ The version must be incremented in all of the following files:
|
|||
/ext/installfiles/mac/ZeroTier One.pkgproj
|
||||
/ext/installfiles/windows/chocolatey/zerotier-one.nuspec
|
||||
/ext/installfiles/windows/ZeroTier One.aip
|
||||
/windows/WinUI/AboutView.xaml
|
||||
|
||||
The final .AIP file can only be edited on Windows with [Advanced Installer Enterprise](http://www.advancedinstaller.com/). In addition to incrementing the version be sure that a new product code is generated. (The "upgrade code" GUID on the other hand must never change.)
|
||||
|
||||
|
|
68
README.md
68
README.md
|
@ -1,52 +1,76 @@
|
|||
ZeroTier - A Planetary Ethernet Switch
|
||||
======
|
||||
|
||||
ZeroTier is a software-based managed Ethernet switch for planet Earth.
|
||||
ZeroTier is an enterprise Ethernet switch for planet Earth.
|
||||
|
||||
It erases the LAN/WAN distinction and makes VPNs, tunnels, proxies, and other kludges arising from the inflexible nature of physical networks obsolete. Everything is encrypted end-to-end and traffic takes the most direct (peer to peer) path available.
|
||||
|
||||
This repository contains ZeroTier One, a service that provides ZeroTier network connectivity to devices running Windows, Mac, Linux, iOS, Android, and FreeBSD and makes joining virtual networks as easy as joining IRC or Slack channels. It also contains the OS-independent core ZeroTier protocol implementation in [node/](node/).
|
||||
|
||||
Visit [ZeroTier's site](https://www.zerotier.com/) for more information and [pre-built binary packages](https://www.zerotier.com/download.shtml). Apps for Android and iOS are available for free in the Google Play and Apple app stores.
|
||||
|
||||
### Getting Started
|
||||
|
||||
ZeroTier's basic operation is easy to understand. Devices have 10-digit *ZeroTier addresses* like `89e92ceee5` and networks have 16-digit network IDs like `8056c2e21c000001`. All it takes for a device to join a network is its 16-digit ID, and all it takes for a network to authorize a device is its 10-digit address. Everything else is automatic.
|
||||
|
||||
A "device" can be anything really: desktops, laptops, phones, servers, VMs/VPSes, containers, and even (soon) apps.
|
||||
A "device" in our terminology is any "unit of compute" capable of talking to a network: desktops, laptops, phones, servers, VMs/VPSes, containers, and even user-space applications via our [SDK](https://github.com/zerotier/ZeroTierSDK).
|
||||
|
||||
For testing we provide a public virtual network called *Earth* with network ID `8056c2e21c000001`. On Linux and Mac you can do this with:
|
||||
For testing purposes we provide a public virtual network called *Earth* with network ID `8056c2e21c000001`. You can join it with:
|
||||
|
||||
sudo zerotier-cli join 8056c2e21c000001
|
||||
|
||||
Now wait about 30 seconds and check your system with `ip addr list` or `ifconfig`. You'll see a new interface whose name starts with *zt* and it should quickly get an IPv4 and an IPv6 address. Once you see it get an IP, try pinging `earth.zerotier.net` at `29.209.112.93`. If you've joined Earth from more than one system, try pinging your other machine.
|
||||
|
||||
*(IPv4 addresses for Earth are assigned from the block 28.0.0.0/7, which is not a part of the public Internet but is non-standard for private networks. It's used to avoid IP conflicts during testing. Your networks can run any IP addressing scheme you want.)*
|
||||
|
||||
If you don't want to belong to a giant Ethernet party line anymore, just type:
|
||||
Now wait about 30 seconds and check your system with `ip addr list` or `ifconfig`. You'll see a new interface whose name starts with *zt* and it should quickly get an IPv4 and an IPv6 address. Once you see it get an IP, try pinging `earth.zerotier.net` at `29.209.112.93`. If you've joined Earth from more than one system, try pinging your other machine. If you don't want to belong to a giant Ethernet party line anymore, just type:
|
||||
|
||||
sudo zerotier-cli leave 8056c2e21c000001
|
||||
|
||||
The *zt* interface will disappear. You're no longer on the network.
|
||||
|
||||
To create networks of your own you'll need a network controller. You can use [our hosted controller at my.zerotier.com](https://my.zerotier.com) which is free for up to 100 devices on an unlimited number of networks, or you can build your own controller and run it through its local JSON API. See [README.md in controller/](controller/) for more information.
|
||||
To create networks of your own, you'll need a network controller. ZeroTier One (for desktops and servers) includes controller functionality in its default build that can be configured via its JSON API (see [README.md in controller/](controller/)). ZeroTier provides a hosted solution with a nice web UI and SaaS add-ons at [my.zerotier.com](https://my.zerotier.com/). Basic controller functionality is free for up to 100 devices.
|
||||
|
||||
### Building from Source
|
||||
### Project Layout
|
||||
|
||||
For Mac, Linux, and BSD, just type "make" (or "gmake" on BSD). You won't need much installed; here are the requirements for various platforms:
|
||||
- `artwork/`: icons, logos, etc.
|
||||
- `attic/`: old stuff and experimental code that we want to keep around for reference.
|
||||
- `controller/`: the reference network controller implementation, which is built and included by default on desktop and server build targets.
|
||||
- `debian/`: files for building Debian packages on Linux.
|
||||
- `doc/`: manual pages and other documentation.
|
||||
- `ext/`: third party libraries, binaries that we ship for convenience on some platforms (Mac and Windows), and installation support files.
|
||||
- `include/`: include files for the ZeroTier core.
|
||||
- `java/`: a JNI wrapper used with our Android mobile app. (The whole Android app is not open source but may be made so in the future.)
|
||||
- `macui/`: a Macintosh menu-bar app for controlling ZeroTier One, written in Objective C.
|
||||
- `node/`: the ZeroTier virtual Ethernet switch core, which is designed to be entirely separate from the rest of the code and able to be built as a stand-alone OS-independent library. Note to developers: do not use C++11 features in here, since we want this to build on old embedded platforms that lack C++11 support. C++11 can be used elsewhere.
|
||||
- `osdep/`: code to support and integrate with OSes, including platform-specific stuff only built for certain targets.
|
||||
- `service/`: the ZeroTier One service, which wraps the ZeroTier core and provides VPN-like connectivity to virtual networks for desktops, laptops, servers, VMs, and containers.
|
||||
- `tcp-proxy/`: TCP proxy code run by ZeroTier, Inc. to provide TCP fallback (this will die soon!).
|
||||
- `windows/`: Visual Studio solution files, Windows service code for ZeroTier One, and the Windows task bar app UI.
|
||||
|
||||
* **Mac**: Xcode command line tools. It should build on OSX 10.7 or newer.
|
||||
* **Linux**: gcc/g++ (4.9 or newer recommended) or clang/clang++ (3.4 or newer recommended) Makefile will use clang by default if available. The Linux build will auto-detect the presence of development headers for *json-parser*, *http-parser*, *li8bnatpmp*, and *libminiupnpc* and will link against the system libraries for these if they are present and recent enough. Otherwise the bundled versions in [ext/](ext/) will be used. Type `make install` to install the binaries and other files on the system, though this will not create init.d or systemd links.
|
||||
* **FreeBSD**: C++ compiler (G++ usually) and GNU make (gmake).
|
||||
The base path contains the ZeroTier One service main entry point (`one.cpp`), self test code, makefiles, etc.
|
||||
|
||||
Each supported platform has its own *make-XXX.mk* file that contains the actual make rules for the platform. The right .mk file is included by the main Makefile based on the GNU make *OSTYPE* variable. Take a look at the .mk file for your platform for other targets, debug build rules, etc.
|
||||
### Build and Platform Notes
|
||||
|
||||
To build on Mac and Linux just type `make`. On FreeBSD and OpenBSD `gmake` (GNU make) is required and can be installed from packages or ports. For Windows there is a Visual Studio solution in `windows/'.
|
||||
|
||||
- **Mac**
|
||||
- Xcode command line tools for OSX 10.7 or newer are required.
|
||||
- Tap device driver kext source is in `ext/tap-mac` and a signed pre-built binary can be found in `ext/bin/tap-mac`. You should not need to build it yourself. It's a fork of [tuntaposx](http://tuntaposx.sourceforge.net) with device names changed to `zt#`, support for a larger MTU, and tun functionality removed.
|
||||
- **Linux**
|
||||
- The minimum compiler versions required are GCC/G++ 4.9.3 or CLANG/CLANG++ 3.4.2.
|
||||
- Linux makefiles automatically detect and prefer clang/clang++ if present as it produces smaller and slightly faster binaries in most cases. You can override by supplying CC and CXX variables on the make command line.
|
||||
- CentOS 7 ships with a version of GCC/G++ that is too old, but a new enough version of CLANG can be found in the *epel* repositories. Type `yum install epel-release` and then `yum install clang` to build there.
|
||||
- **Windows**
|
||||
- Windows 7 or newer (and equivalent server versions) are supported. This *may* work on Vista but you're on your own there. Windows XP is not supported since it lacks many important network API functions.
|
||||
- We build with Visual Studio 2015. Older versions may not work with the solution file and project files we ship and may not have new enough C++11 support.
|
||||
- Pre-built signed Windows drivers are included in `ext/bin/tap-windows-ndis6`. The MSI files found there will install them on 32-bit and 64-bit systems. (These are included in our multi-architecture installer as chained MSIs.)
|
||||
- Windows builds are more painful in general than other platforms and are for the adventurous.
|
||||
- **FreeBSD**
|
||||
- Tested most recently on FreeBSD-11. Older versions may work but we're not sure.
|
||||
- GCC/G++ 4.9 and gmake are required. These can be installed from packages or ports. Type `gmake` to build.
|
||||
- **OpenBSD**
|
||||
- There is a limit of four network memberships on OpenBSD as there are only four tap devices (`/dev/tap0` through `/dev/tap3`). We're not sure if this can be increased.
|
||||
- OpenBSD lacks `getifmaddrs` (or any equivalent method) to get interface multicast memberships. As a result multicast will only work on OpenBSD for ARP and NDP (IP/MAC lookup) and not for other purposes.
|
||||
- Only tested on OpenBSD 6.0. Older versions may not work.
|
||||
- GCC/G++ 4.9 and gmake are required and can be installed using `pkg_add` or from ports. They get installed in `/usr/local/bin` as `egcc` and `eg++` and our makefile is pre-configured to use them on OpenBSD.
|
||||
|
||||
Typing `make selftest` will build a *zerotier-selftest* binary which unit tests various internals and reports on a few aspects of the build environment. It's a good idea to try this on novel platforms or architectures.
|
||||
|
||||
Windows, of course, is special. We build for Windows with Microsoft Visual Studio 2012 on Windows 7. A solution file is located in the *windows/* subfolder. Newer versions of Visual Studio (and Windows) may work but haven't been tested. Older versions almost certainly will not, since they lack things like *stdint.h* and certain STL features. MinGW or other ports of gcc/clang to Windows should also work but haven't been tested.
|
||||
|
||||
32 and 64 bit X86 and ARM (e.g. Raspberry Pi, Android) are officially supported. Community members have built for MIPS and Sparc without issues.
|
||||
|
||||
### Running
|
||||
|
||||
Running *zerotier-one* with -h will show help.
|
||||
|
@ -62,7 +86,7 @@ The service is controlled via the JSON API, which by default is available at 127
|
|||
Here's where home folders live (by default) on each OS:
|
||||
|
||||
* **Linux**: `/var/lib/zerotier-one`
|
||||
* **FreeBSD**: `/var/db/zerotier-one`
|
||||
* **FreeBSD** / **OpenBSD**: `/var/db/zerotier-one`
|
||||
* **Mac**: `/Library/Application Support/ZeroTier/One`
|
||||
* **Windows**: `\ProgramData\ZeroTier\One` (That's for Windows 7. The base 'shared app data' folder might be different on different Windows versions.)
|
||||
|
||||
|
|
138
RELEASE-NOTES.md
Normal file
138
RELEASE-NOTES.md
Normal file
|
@ -0,0 +1,138 @@
|
|||
ZeroTier Release Notes
|
||||
======
|
||||
|
||||
# 2017-04-20 -- Version 1.2.4
|
||||
|
||||
* Managed routes are now only bifurcated for the default route. This is a change in behavior, though few people will probably notice. Bifurcating all managed routes was causing more trouble than it was worth for most users.
|
||||
* Up to 2X crypto speedup on x86-64 (except Windows, which will take some porting) and 32-bit ARM platforms due to integration of fast assembly language implementations of Salsa20/12 from the [supercop](http://bench.cr.yp.to/supercop.html) code base. These were written by Daniel J. Bernstein and are in the public domain. My Macbook Pro (Core i5 2.8ghz) now does almost 1.5GiB/sec Salsa20/12 per core and a Raspberry Pi got a 2X boost. 64-bit ARM support and Windows support will take some work but should not be too hard.
|
||||
* Refactored code that manages credentials to greatly reduce memory use in most cases. This may also result in a small performance improvement.
|
||||
* Reworked and simplified path selection and priority logic to fix path instability and dead path persistence edge cases. There have been some sporadic reports of persistent path instabilities and dead paths hanging around that take minutes to resolve. These have proven difficult to reproduce in house, but hopefully this will fix them. In any case it seems to speed up path establishment in our tests and it makes the code simpler and more readable.
|
||||
* Eliminated some unused cruft from the code around path management and in the peer class.
|
||||
* Fixed an issue causing build problems on some MIPS architecture systems.
|
||||
* Fixed Windows forgetting routes on sleep/wake or in some other circumstances. (GitHub issue #465)
|
||||
|
||||
# 2017-03-17 -- Version 1.2.2
|
||||
|
||||
* A bug causing unreliable multicast propagation (GitHub issue #461).
|
||||
* A crash in ARM binaries due to a build chain and flags problem.
|
||||
* A bug in the network controller preventing members from being listed (GitHub issue #460).
|
||||
|
||||
# 2017-03-14 -- Version 1.2.0
|
||||
|
||||
Version 1.2.0 is a major milestone release representing almost nine months of work. It includes our rules engine for distributed network packet filtering and security monitoring, federated roots, and many other architectural and UI improvements and bug fixes.
|
||||
|
||||
## New Features in 1.2.0
|
||||
|
||||
### The ZeroTier Rules Engine
|
||||
|
||||
The largest new feature in 1.2.0, and the product of many months of work, is our advanced network rules engine. With this release we achieve traffic control, security monitoring, and micro-segmentation capability on par with many enterprise SDN solutions designed for use in advanced data centers and corporate networks.
|
||||
|
||||
Rules allow you to filter packets on your network and vector traffic to security observers. Security observation can be performed in-band using REDIRECT or out of band using TEE.
|
||||
|
||||
Tags and capabilites provide advanced methods for implementing fine grained permission structures and micro-segmentation schemes without bloating the size and complexity of your rules table.
|
||||
|
||||
See the [rules engine announcement blog post](https://www.zerotier.com/blog/?p=927) for an in-depth discussion of theory and implementation. The [manual](https://www.zerotier.com/manual.shtml) contains detailed information on rule, tag, and capability use, and the `rule-compiler/` subfolder of the ZeroTier source tree contains a JavaScript function to compile rules in our human-readable rule definition language into rules suitable for import into a network controller. (ZeroTier Central uses this same script to compile rules on [my.zerotier.com](https://my.zerotier.com/).)
|
||||
|
||||
### Root Server Federation
|
||||
|
||||
It's now possible to create your own root servers and add them to the root server pool on your nodes. This is done by creating what's called a "moon," which is a signed enumeration of root servers and their stable points on the network. Refer to the [manual](https://www.zerotier.com/manual.shtml) for instructions.
|
||||
|
||||
Federated roots achieve a number of things:
|
||||
|
||||
* You can deploy your own infrastructure to reduce dependency on ours.
|
||||
* You can deploy roots *inside your LAN* to ensure that network connectivity inside your facility still works if the Internet goes down. This is the first step toward making ZeroTier viable as an in-house SDN solution.
|
||||
* Roots can be deployed inside national boundaries for countries with data residency laws or "great firewalls." (As of 1.2.0 there is still no way to force all traffic to use these roots, but that will be easy to do in a later version.)
|
||||
* Last but not least this makes ZeroTier somewhat less centralized by eliminating any hard dependency on ZeroTier, Inc.'s infrastructure.
|
||||
|
||||
Our roots will of course remain and continue to provide zero-configuration instant-on deployment, a secure global authority for identities, and free traffic relaying for those who can't establish peer to peer connections.
|
||||
|
||||
### Local Configuration
|
||||
|
||||
An element of our design philosophy is "features are bugs." This isn't an absolute dogma but more of a guiding principle. We try as hard as we can to avoid adding features, especially "knobs" that must be tweaked by a user.
|
||||
|
||||
As of 1.2.0 we've decided that certain knobs are unavoidable, and so there is now a `local.conf` file that can be used to configure them. See the ZeroTier One documentation for these. They include:
|
||||
|
||||
* Blacklisting interfaces you want to make sure ZeroTier doesn't use for network traffic, such as VPNs, slow links, or backplanes designated for only certain kinds of traffic.
|
||||
* Turning uPnP/NAT-PMP on or off.
|
||||
* Configuring software updates on Windows and Mac platforms.
|
||||
* Defining trusted paths (the old trusted paths file is now deprecated)
|
||||
* Setting the ZeroTier main port so it doesn't have to be changed on the command line, which is very inconvenient in many cases.
|
||||
|
||||
### Improved In-Band Software Updates
|
||||
|
||||
A good software update system for Windows and Mac clients has been a missing feature in previous versions. It does exist but we've been shy about using it so far due to its fragility in some environments.
|
||||
|
||||
We've greatly improved this mechanism in 1.2.0. Not only does it now do a better job of actually invoking the update, but it also transfers updates in-band using the ZeroTier protocol. This means it can work in environments that do not allows http/https traffic or that force it through proxies. There's also now an update channel setting: `beta` or `release` (the default).
|
||||
|
||||
Software updates are authenticated three ways:
|
||||
|
||||
1. ZeroTier's own signing key is used to sign all updates and this signature is checked prior to installation. ZeroTier, Inc.'s signatures are performed on an air-gapped machine.
|
||||
|
||||
2. Updates for Mac and Windows are signed using Apple and Microsoft (DigiCert EV) keys and will not install unless these signatures are also valid.
|
||||
|
||||
3. The new in-band update mechanism also authenticates the source of the update via ZeroTier's built-in security features. This provides transport security, while 1 and 2 provide security of the update at rest.
|
||||
|
||||
Updates are now configurable via `local.conf`. There are three options: `disable`, `download`, and `apply`. The third (apply) is the default for official builds on Windows and Mac, making updates happen silently and automatically as they do for popular browsers like Chrome and Firefox. Updates are disabled by default on Linux and other Unix-type systems as these are typically updated through package managers.
|
||||
|
||||
### Path Link Quality Awareness
|
||||
|
||||
Version 1.2.0 is now aware of the link quality of direct paths with other 1.2.0 nodes. This information isn't used yet but is visible through the JSON API. (Quality always shows as 100% with pre-1.2.0 nodes.) Quality is measured passively with no additional overhead using a counter based packet loss detection algorithm.
|
||||
|
||||
This information is visible from the command line via `listpeers`:
|
||||
|
||||
200 listpeers XXXXXXXXXX 199.XXX.XXX.XXX/9993;10574;15250;1.00 48 1.2.0 LEAF
|
||||
200 listpeers XXXXXXXXXX 195.XXX.XXX.XXX/45584;467;7608;0.44 290 1.2.0 LEAF
|
||||
|
||||
The first peer's path is at 100% (1.00), while the second peer's path is suffering quite a bit of packet loss (0.44).
|
||||
|
||||
Link quality awareness is a precursor to intelligent multi-path and QoS support, which will in future versions bring us to feature parity with SD-WAN products like Cisco iWAN.
|
||||
|
||||
### Security Improvements
|
||||
|
||||
Version 1.2.0 adds anti-DOS (denial of service) rate limits and other hardening for improved resiliency against a number of denial of service attack scenarios.
|
||||
|
||||
It also adds a mechanism for instantaneous credential revocation. This can be used to revoke certificates of membership instantly to kick a node off a network (for private networks) and also to revoke capabilities and tags. The new controller sends revocations by default when a peer is de-authorized.
|
||||
|
||||
Revocations propagate using a "rumor mill" peer to peer algorithm. This means that a controller need only successfully send a revocation to at least one member of a network with connections to other active members. At this point the revocation will flood through the network peer to peer very quickly. This helps make revocations more robust in the face of poor connectivity with the controller or attempts to incapacitate the controller with denial of service attacks, as well as making revocations faster on huge networks.
|
||||
|
||||
### Windows and Macintosh UI Improvements (ZeroTier One)
|
||||
|
||||
The Mac has a whole new UI built natively in Objective-C. It provides a pulldown similar in appearance and operation to the Mac WiFi task bar menu.
|
||||
|
||||
The Windows UI has also been improved and now provides a task bar icon that can be right-clicked to manage networks. Both now expose managed route and IP permissions, allowing nodes to easily opt in to full tunnel operation if you have a router configured on your network.
|
||||
|
||||
### Ad-Hoc Networks
|
||||
|
||||
A special kind of public network called an ad-hoc network may be accessed by joining a network ID with the format:
|
||||
|
||||
ffSSSSEEEE000000
|
||||
| | | |
|
||||
| | | Reserved for future use, must be 0
|
||||
| | End of port range (hex)
|
||||
| Start of port range (hex)
|
||||
Reserved ZeroTier address prefix indicating a controller-less network
|
||||
|
||||
Ad-hoc networks are public (no access control) networks that have no network controller. Instead their configuration and other credentials are generated locally. Ad-hoc networks permit only IPv6 UDP and TCP unicast traffic (no multicast or broadcast) using 6plane format NDP-emulated IPv6 addresses. In addition an ad-hoc network ID encodes an IP port range. UDP packets and TCP SYN (connection open) packets are only allowed to desintation ports within the encoded range.
|
||||
|
||||
For example `ff00160016000000` is an ad-hoc network allowing only SSH, while `ff0000ffff000000` is an ad-hoc network allowing any UDP or TCP port.
|
||||
|
||||
Keep in mind that these networks are public and anyone in the entire world can join them. Care must be taken to avoid exposing vulnerable services or sharing unwanted files or other resources.
|
||||
|
||||
### Network Controller (Partial) Rewrite
|
||||
|
||||
The network controller has been largely rewritten to use a simple in-filesystem JSON data store in place of SQLite, and it is now included by default in all Windows, Mac, Linux, and BSD builds. This means any desktop or server node running ZeroTier One can now be a controller with no recompilation needed.
|
||||
|
||||
If you have data in an old SQLite3 controller we've included a NodeJS script in `controller/migrate-sqlite` to migrate data to the new format. If you don't migrate, members will start getting `NOT_FOUND` when they attempt to query for updates.
|
||||
|
||||
## Major Bug Fixes in 1.2.0
|
||||
|
||||
* **The Windows HyperV 100% CPU bug is FINALLY DEAD**: This long-running problem turns out to have been an issue with Windows itself, but one we were triggering by placing invalid data into the Windows registry. Microsoft is aware of the issue but we've also fixed the triggering problem on our side. ZeroTier should now co-exist quite well with HyperV and should now be able to be bridged with a HyperV virtual switch.
|
||||
* **Segmenation faults on musl-libc based Linux systems**: Alpine Linux and some embedded Linux systems that use musl libc (a minimal libc) experienced segmentation faults. These were due to a smaller default stack size. A work-around that sets the stack size for new threads has been added.
|
||||
* **Windows firewall blocks local JSON API**: On some Windows systems the firewall likes to block 127.0.0.1:9993 for mysterious reasons. This is now fixed in the installer via the addition of another firewall exemption rule.
|
||||
* **UI crash on embedded Windows due to missing fonts**: The MSI installer now ships fonts and will install them if they are not present, so this should be fixed.
|
||||
|
||||
## Other Improvements in 1.2.0
|
||||
|
||||
* **Improved dead path detection**: ZeroTier is now more aggressive about expiring paths that do not seem to be active. If a path seems marginal it is re-confirmed before re-use.
|
||||
* **Minor performance improvements**: We've reduced unnecessary memcpy's and made a few other performance improvements in the core.
|
||||
* **Linux static binaries**: For our official packages (the ones in the download.zerotier.com apt and yum repositories) we now build Linux binaries with static linking. Hopefully this will stop all the bug reports relating to library inconsistencies, as well as allowing our deb packages to run on a wider variety of Debian-based distributions. (There are far too many of these to support officially!) The overhead for this is very small, especially since we built our static versions against musl-libc. Distribution maintainers are of course free to build dynamically linked versions for inclusion into distributions; this only affects our official binaries.
|
408
attic/Filter.cpp
408
attic/Filter.cpp
|
@ -1,408 +0,0 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "Filter.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
const char *const Filter::UNKNOWN_NAME = "(unknown)";
|
||||
const Range<unsigned int> Filter::ANY;
|
||||
|
||||
static inline Range<unsigned int> __parseRange(char *r)
|
||||
throw(std::invalid_argument)
|
||||
{
|
||||
char *saveptr = (char *)0;
|
||||
unsigned int a = 0;
|
||||
unsigned int b = 0;
|
||||
unsigned int fn = 0;
|
||||
for(char *f=Utils::stok(r,"-",&saveptr);(f);f=Utils::stok((char *)0,"-",&saveptr)) {
|
||||
if (*f) {
|
||||
switch(fn++) {
|
||||
case 0:
|
||||
if (*f != '*')
|
||||
a = b = (unsigned int)strtoul(f,(char **)0,10);
|
||||
break;
|
||||
case 1:
|
||||
if (*f != '*')
|
||||
b = (unsigned int)strtoul(f,(char **)0,10);
|
||||
break;
|
||||
default:
|
||||
throw std::invalid_argument("rule range must be <int>, <int>-<int>, or *");
|
||||
}
|
||||
}
|
||||
}
|
||||
return Range<unsigned int>(a,b);
|
||||
}
|
||||
|
||||
Filter::Rule::Rule(const char *s)
|
||||
throw(std::invalid_argument)
|
||||
{
|
||||
char *saveptr = (char *)0;
|
||||
char tmp[256];
|
||||
if (!Utils::scopy(tmp,sizeof(tmp),s))
|
||||
throw std::invalid_argument("rule string too long");
|
||||
unsigned int fn = 0;
|
||||
for(char *f=Utils::stok(tmp,";",&saveptr);(f);f=Utils::stok((char *)0,";",&saveptr)) {
|
||||
if (*f) {
|
||||
switch(fn++) {
|
||||
case 0:
|
||||
_etherType = __parseRange(f);
|
||||
break;
|
||||
case 1:
|
||||
_protocol = __parseRange(f);
|
||||
break;
|
||||
case 2:
|
||||
_port = __parseRange(f);
|
||||
break;
|
||||
default:
|
||||
throw std::invalid_argument("rule string has unknown extra fields");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fn != 3)
|
||||
throw std::invalid_argument("rule string must contain 3 fields");
|
||||
}
|
||||
|
||||
bool Filter::Rule::operator()(unsigned int etype,const void *data,unsigned int len) const
|
||||
throw(std::invalid_argument)
|
||||
{
|
||||
if ((!_etherType)||(_etherType(etype))) { // ethertype is ANY, or matches
|
||||
// Ethertype determines meaning of protocol and port
|
||||
switch(etype) {
|
||||
case ZT_ETHERTYPE_IPV4:
|
||||
if (len > 20) {
|
||||
if ((!_protocol)||(_protocol(((const uint8_t *)data)[9]))) { // protocol is ANY or match
|
||||
if (!_port) // port is ANY
|
||||
return true;
|
||||
|
||||
// Don't match on fragments beyond fragment 0. If we've blocked
|
||||
// fragment 0, further fragments will fall on deaf ears anyway.
|
||||
if ((Utils::ntoh(((const uint16_t *)data)[3]) & 0x1fff))
|
||||
return false;
|
||||
|
||||
// Internet header length determines where data begins, in multiples of 32 bits
|
||||
unsigned int ihl = 4 * (((const uint8_t *)data)[0] & 0x0f);
|
||||
|
||||
switch(((const uint8_t *)data)[9]) { // port's meaning depends on IP protocol
|
||||
case ZT_IPPROTO_ICMP:
|
||||
// For ICMP, port is ICMP type
|
||||
return _port(((const uint8_t *)data)[ihl]);
|
||||
case ZT_IPPROTO_TCP:
|
||||
case ZT_IPPROTO_UDP:
|
||||
case ZT_IPPROTO_SCTP:
|
||||
case ZT_IPPROTO_UDPLITE:
|
||||
// For these, port is destination port. Protocol designers were
|
||||
// nice enough to put the field in the same place.
|
||||
return _port(((const uint16_t *)data)[(ihl / 2) + 1]);
|
||||
default:
|
||||
// port has no meaning for other IP types, so ignore it
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // no match on port
|
||||
}
|
||||
} else throw std::invalid_argument("undersized IPv4 packet");
|
||||
break;
|
||||
|
||||
case ZT_ETHERTYPE_IPV6:
|
||||
if (len > 40) {
|
||||
int nextHeader = ((const uint8_t *)data)[6];
|
||||
unsigned int pos = 40;
|
||||
while ((pos < len)&&(nextHeader >= 0)&&(nextHeader != 59)) { // 59 == no next header
|
||||
fprintf(stderr,"[rule] V6: start header parse, header %.2x pos %d\n",nextHeader,pos);
|
||||
|
||||
switch(nextHeader) {
|
||||
case 0: // hop-by-hop options
|
||||
case 60: // destination options
|
||||
case 43: // routing
|
||||
case 135: // mobility (mobile IPv6 options)
|
||||
if (_protocol((unsigned int)nextHeader))
|
||||
return true; // match if our goal was to match any of these
|
||||
nextHeader = ((const uint8_t *)data)[pos];
|
||||
pos += 8 + (8 * ((const uint8_t *)data)[pos + 1]);
|
||||
break;
|
||||
case 44: // fragment
|
||||
if (_protocol(44))
|
||||
return true; // match if our goal was to match fragments
|
||||
nextHeader = ((const uint8_t *)data)[pos];
|
||||
pos += 8;
|
||||
break;
|
||||
case ZT_IPPROTO_AH: // AH
|
||||
return _protocol(ZT_IPPROTO_AH); // true if AH is matched protocol, otherwise false since packet will be IPsec
|
||||
case ZT_IPPROTO_ESP: // ESP
|
||||
return _protocol(ZT_IPPROTO_ESP); // true if ESP is matched protocol, otherwise false since packet will be IPsec
|
||||
case ZT_IPPROTO_ICMPV6:
|
||||
// Only match ICMPv6 if we've selected it specifically
|
||||
if (_protocol(ZT_IPPROTO_ICMPV6)) {
|
||||
// Port is interpreted as ICMPv6 type
|
||||
if ((!_port)||(_port(((const uint8_t *)data)[pos])))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case ZT_IPPROTO_TCP:
|
||||
case ZT_IPPROTO_UDP:
|
||||
case ZT_IPPROTO_SCTP:
|
||||
case ZT_IPPROTO_UDPLITE:
|
||||
// If we encounter any of these, match if protocol matches or is wildcard as
|
||||
// we'll consider these the "real payload" if present.
|
||||
if ((!_protocol)||(_protocol(nextHeader))) {
|
||||
if ((!_port)||(_port(((const uint16_t *)data)[(pos / 2) + 1])))
|
||||
return true; // protocol matches or is ANY, port is ANY or matches
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
char foo[128];
|
||||
Utils::snprintf(foo,sizeof(foo),"unrecognized IPv6 header type %d",(int)nextHeader);
|
||||
throw std::invalid_argument(foo);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr,"[rule] V6: end header parse, next header %.2x, new pos %d\n",nextHeader,pos);
|
||||
}
|
||||
} else throw std::invalid_argument("undersized IPv6 packet");
|
||||
break;
|
||||
|
||||
default:
|
||||
// For other ethertypes, protocol and port are ignored. What would they mean?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Filter::Rule::toString() const
|
||||
{
|
||||
char buf[128];
|
||||
std::string s;
|
||||
|
||||
switch(_etherType.magnitude()) {
|
||||
case 0:
|
||||
s.push_back('*');
|
||||
break;
|
||||
case 1:
|
||||
Utils::snprintf(buf,sizeof(buf),"%u",_etherType.start);
|
||||
s.append(buf);
|
||||
break;
|
||||
default:
|
||||
Utils::snprintf(buf,sizeof(buf),"%u-%u",_etherType.start,_etherType.end);
|
||||
s.append(buf);
|
||||
break;
|
||||
}
|
||||
s.push_back(';');
|
||||
switch(_protocol.magnitude()) {
|
||||
case 0:
|
||||
s.push_back('*');
|
||||
break;
|
||||
case 1:
|
||||
Utils::snprintf(buf,sizeof(buf),"%u",_protocol.start);
|
||||
s.append(buf);
|
||||
break;
|
||||
default:
|
||||
Utils::snprintf(buf,sizeof(buf),"%u-%u",_protocol.start,_protocol.end);
|
||||
s.append(buf);
|
||||
break;
|
||||
}
|
||||
s.push_back(';');
|
||||
switch(_port.magnitude()) {
|
||||
case 0:
|
||||
s.push_back('*');
|
||||
break;
|
||||
case 1:
|
||||
Utils::snprintf(buf,sizeof(buf),"%u",_port.start);
|
||||
s.append(buf);
|
||||
break;
|
||||
default:
|
||||
Utils::snprintf(buf,sizeof(buf),"%u-%u",_port.start,_port.end);
|
||||
s.append(buf);
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
Filter::Filter(const char *s)
|
||||
throw(std::invalid_argument)
|
||||
{
|
||||
char tmp[16384];
|
||||
if (!Utils::scopy(tmp,sizeof(tmp),s))
|
||||
throw std::invalid_argument("filter string too long");
|
||||
char *saveptr = (char *)0;
|
||||
unsigned int fn = 0;
|
||||
for(char *f=Utils::stok(tmp,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
|
||||
try {
|
||||
_rules.push_back(Rule(f));
|
||||
++fn;
|
||||
} catch (std::invalid_argument &exc) {
|
||||
char tmp[256];
|
||||
Utils::snprintf(tmp,sizeof(tmp),"invalid rule at index %u: %s",fn,exc.what());
|
||||
throw std::invalid_argument(tmp);
|
||||
}
|
||||
}
|
||||
std::sort(_rules.begin(),_rules.end());
|
||||
}
|
||||
|
||||
std::string Filter::toString() const
|
||||
{
|
||||
std::string s;
|
||||
|
||||
for(std::vector<Rule>::const_iterator r(_rules.begin());r!=_rules.end();++r) {
|
||||
if (s.length() > 0)
|
||||
s.push_back(',');
|
||||
s.append(r->toString());
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void Filter::add(const Rule &r)
|
||||
{
|
||||
for(std::vector<Rule>::iterator rr(_rules.begin());rr!=_rules.end();++rr) {
|
||||
if (r == *rr)
|
||||
return;
|
||||
}
|
||||
_rules.push_back(r);
|
||||
std::sort(_rules.begin(),_rules.end());
|
||||
}
|
||||
|
||||
const char *Filter::etherTypeName(const unsigned int etherType)
|
||||
throw()
|
||||
{
|
||||
switch(etherType) {
|
||||
case ZT_ETHERTYPE_IPV4: return "ETHERTYPE_IPV4";
|
||||
case ZT_ETHERTYPE_ARP: return "ETHERTYPE_ARP";
|
||||
case ZT_ETHERTYPE_RARP: return "ETHERTYPE_RARP";
|
||||
case ZT_ETHERTYPE_ATALK: return "ETHERTYPE_ATALK";
|
||||
case ZT_ETHERTYPE_AARP: return "ETHERTYPE_AARP";
|
||||
case ZT_ETHERTYPE_IPX_A: return "ETHERTYPE_IPX_A";
|
||||
case ZT_ETHERTYPE_IPX_B: return "ETHERTYPE_IPX_B";
|
||||
case ZT_ETHERTYPE_IPV6: return "ETHERTYPE_IPV6";
|
||||
}
|
||||
return UNKNOWN_NAME;
|
||||
}
|
||||
|
||||
const char *Filter::ipProtocolName(const unsigned int ipp)
|
||||
throw()
|
||||
{
|
||||
switch(ipp) {
|
||||
case ZT_IPPROTO_ICMP: return "IPPROTO_ICMP";
|
||||
case ZT_IPPROTO_IGMP: return "IPPROTO_IGMP";
|
||||
case ZT_IPPROTO_TCP: return "IPPROTO_TCP";
|
||||
case ZT_IPPROTO_UDP: return "IPPROTO_UDP";
|
||||
case ZT_IPPROTO_GRE: return "IPPROTO_GRE";
|
||||
case ZT_IPPROTO_ESP: return "IPPROTO_ESP";
|
||||
case ZT_IPPROTO_AH: return "IPPROTO_AH";
|
||||
case ZT_IPPROTO_ICMPV6: return "IPPROTO_ICMPV6";
|
||||
case ZT_IPPROTO_OSPF: return "IPPROTO_OSPF";
|
||||
case ZT_IPPROTO_IPIP: return "IPPROTO_IPIP";
|
||||
case ZT_IPPROTO_IPCOMP: return "IPPROTO_IPCOMP";
|
||||
case ZT_IPPROTO_L2TP: return "IPPROTO_L2TP";
|
||||
case ZT_IPPROTO_SCTP: return "IPPROTO_SCTP";
|
||||
case ZT_IPPROTO_FC: return "IPPROTO_FC";
|
||||
case ZT_IPPROTO_UDPLITE: return "IPPROTO_UDPLITE";
|
||||
case ZT_IPPROTO_HIP: return "IPPROTO_HIP";
|
||||
}
|
||||
return UNKNOWN_NAME;
|
||||
}
|
||||
|
||||
const char *Filter::icmpTypeName(const unsigned int icmpType)
|
||||
throw()
|
||||
{
|
||||
switch(icmpType) {
|
||||
case ZT_ICMP_ECHO_REPLY: return "ICMP_ECHO_REPLY";
|
||||
case ZT_ICMP_DESTINATION_UNREACHABLE: return "ICMP_DESTINATION_UNREACHABLE";
|
||||
case ZT_ICMP_SOURCE_QUENCH: return "ICMP_SOURCE_QUENCH";
|
||||
case ZT_ICMP_REDIRECT: return "ICMP_REDIRECT";
|
||||
case ZT_ICMP_ALTERNATE_HOST_ADDRESS: return "ICMP_ALTERNATE_HOST_ADDRESS";
|
||||
case ZT_ICMP_ECHO_REQUEST: return "ICMP_ECHO_REQUEST";
|
||||
case ZT_ICMP_ROUTER_ADVERTISEMENT: return "ICMP_ROUTER_ADVERTISEMENT";
|
||||
case ZT_ICMP_ROUTER_SOLICITATION: return "ICMP_ROUTER_SOLICITATION";
|
||||
case ZT_ICMP_TIME_EXCEEDED: return "ICMP_TIME_EXCEEDED";
|
||||
case ZT_ICMP_BAD_IP_HEADER: return "ICMP_BAD_IP_HEADER";
|
||||
case ZT_ICMP_TIMESTAMP: return "ICMP_TIMESTAMP";
|
||||
case ZT_ICMP_TIMESTAMP_REPLY: return "ICMP_TIMESTAMP_REPLY";
|
||||
case ZT_ICMP_INFORMATION_REQUEST: return "ICMP_INFORMATION_REQUEST";
|
||||
case ZT_ICMP_INFORMATION_REPLY: return "ICMP_INFORMATION_REPLY";
|
||||
case ZT_ICMP_ADDRESS_MASK_REQUEST: return "ICMP_ADDRESS_MASK_REQUEST";
|
||||
case ZT_ICMP_ADDRESS_MASK_REPLY: return "ICMP_ADDRESS_MASK_REPLY";
|
||||
case ZT_ICMP_TRACEROUTE: return "ICMP_TRACEROUTE";
|
||||
case ZT_ICMP_MOBILE_HOST_REDIRECT: return "ICMP_MOBILE_HOST_REDIRECT";
|
||||
case ZT_ICMP_MOBILE_REGISTRATION_REQUEST: return "ICMP_MOBILE_REGISTRATION_REQUEST";
|
||||
case ZT_ICMP_MOBILE_REGISTRATION_REPLY: return "ICMP_MOBILE_REGISTRATION_REPLY";
|
||||
}
|
||||
return UNKNOWN_NAME;
|
||||
}
|
||||
|
||||
const char *Filter::icmp6TypeName(const unsigned int icmp6Type)
|
||||
throw()
|
||||
{
|
||||
switch(icmp6Type) {
|
||||
case ZT_ICMP6_DESTINATION_UNREACHABLE: return "ICMP6_DESTINATION_UNREACHABLE";
|
||||
case ZT_ICMP6_PACKET_TOO_BIG: return "ICMP6_PACKET_TOO_BIG";
|
||||
case ZT_ICMP6_TIME_EXCEEDED: return "ICMP6_TIME_EXCEEDED";
|
||||
case ZT_ICMP6_PARAMETER_PROBLEM: return "ICMP6_PARAMETER_PROBLEM";
|
||||
case ZT_ICMP6_ECHO_REQUEST: return "ICMP6_ECHO_REQUEST";
|
||||
case ZT_ICMP6_ECHO_REPLY: return "ICMP6_ECHO_REPLY";
|
||||
case ZT_ICMP6_MULTICAST_LISTENER_QUERY: return "ICMP6_MULTICAST_LISTENER_QUERY";
|
||||
case ZT_ICMP6_MULTICAST_LISTENER_REPORT: return "ICMP6_MULTICAST_LISTENER_REPORT";
|
||||
case ZT_ICMP6_MULTICAST_LISTENER_DONE: return "ICMP6_MULTICAST_LISTENER_DONE";
|
||||
case ZT_ICMP6_ROUTER_SOLICITATION: return "ICMP6_ROUTER_SOLICITATION";
|
||||
case ZT_ICMP6_ROUTER_ADVERTISEMENT: return "ICMP6_ROUTER_ADVERTISEMENT";
|
||||
case ZT_ICMP6_NEIGHBOR_SOLICITATION: return "ICMP6_NEIGHBOR_SOLICITATION";
|
||||
case ZT_ICMP6_NEIGHBOR_ADVERTISEMENT: return "ICMP6_NEIGHBOR_ADVERTISEMENT";
|
||||
case ZT_ICMP6_REDIRECT_MESSAGE: return "ICMP6_REDIRECT_MESSAGE";
|
||||
case ZT_ICMP6_ROUTER_RENUMBERING: return "ICMP6_ROUTER_RENUMBERING";
|
||||
case ZT_ICMP6_NODE_INFORMATION_QUERY: return "ICMP6_NODE_INFORMATION_QUERY";
|
||||
case ZT_ICMP6_NODE_INFORMATION_RESPONSE: return "ICMP6_NODE_INFORMATION_RESPONSE";
|
||||
case ZT_ICMP6_INV_NEIGHBOR_SOLICITATION: return "ICMP6_INV_NEIGHBOR_SOLICITATION";
|
||||
case ZT_ICMP6_INV_NEIGHBOR_ADVERTISEMENT: return "ICMP6_INV_NEIGHBOR_ADVERTISEMENT";
|
||||
case ZT_ICMP6_MLDV2: return "ICMP6_MLDV2";
|
||||
case ZT_ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REQUEST: return "ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REQUEST";
|
||||
case ZT_ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REPLY: return "ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REPLY";
|
||||
case ZT_ICMP6_MOBILE_PREFIX_SOLICITATION: return "ICMP6_MOBILE_PREFIX_SOLICITATION";
|
||||
case ZT_ICMP6_MOBILE_PREFIX_ADVERTISEMENT: return "ICMP6_MOBILE_PREFIX_ADVERTISEMENT";
|
||||
case ZT_ICMP6_CERTIFICATION_PATH_SOLICITATION: return "ICMP6_CERTIFICATION_PATH_SOLICITATION";
|
||||
case ZT_ICMP6_CERTIFICATION_PATH_ADVERTISEMENT: return "ICMP6_CERTIFICATION_PATH_ADVERTISEMENT";
|
||||
case ZT_ICMP6_MULTICAST_ROUTER_ADVERTISEMENT: return "ICMP6_MULTICAST_ROUTER_ADVERTISEMENT";
|
||||
case ZT_ICMP6_MULTICAST_ROUTER_SOLICITATION: return "ICMP6_MULTICAST_ROUTER_SOLICITATION";
|
||||
case ZT_ICMP6_MULTICAST_ROUTER_TERMINATION: return "ICMP6_MULTICAST_ROUTER_TERMINATION";
|
||||
case ZT_ICMP6_RPL_CONTROL_MESSAGE: return "ICMP6_RPL_CONTROL_MESSAGE";
|
||||
}
|
||||
return UNKNOWN_NAME;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
284
attic/Filter.hpp
284
attic/Filter.hpp
|
@ -1,284 +0,0 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef _ZT_FILTER_HPP
|
||||
#define _ZT_FILTER_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "Range.hpp"
|
||||
|
||||
/* Ethernet frame types that might be relevant to us */
|
||||
#define ZT_ETHERTYPE_IPV4 0x0800
|
||||
#define ZT_ETHERTYPE_ARP 0x0806
|
||||
#define ZT_ETHERTYPE_RARP 0x8035
|
||||
#define ZT_ETHERTYPE_ATALK 0x809b
|
||||
#define ZT_ETHERTYPE_AARP 0x80f3
|
||||
#define ZT_ETHERTYPE_IPX_A 0x8137
|
||||
#define ZT_ETHERTYPE_IPX_B 0x8138
|
||||
#define ZT_ETHERTYPE_IPV6 0x86dd
|
||||
|
||||
/* IP protocols we might care about */
|
||||
#define ZT_IPPROTO_ICMP 0x01
|
||||
#define ZT_IPPROTO_IGMP 0x02
|
||||
#define ZT_IPPROTO_TCP 0x06
|
||||
#define ZT_IPPROTO_UDP 0x11
|
||||
#define ZT_IPPROTO_GRE 0x2f
|
||||
#define ZT_IPPROTO_ESP 0x32
|
||||
#define ZT_IPPROTO_AH 0x33
|
||||
#define ZT_IPPROTO_ICMPV6 0x3a
|
||||
#define ZT_IPPROTO_OSPF 0x59
|
||||
#define ZT_IPPROTO_IPIP 0x5e
|
||||
#define ZT_IPPROTO_IPCOMP 0x6c
|
||||
#define ZT_IPPROTO_L2TP 0x73
|
||||
#define ZT_IPPROTO_SCTP 0x84
|
||||
#define ZT_IPPROTO_FC 0x85
|
||||
#define ZT_IPPROTO_UDPLITE 0x88
|
||||
#define ZT_IPPROTO_HIP 0x8b
|
||||
|
||||
/* IPv4 ICMP types */
|
||||
#define ZT_ICMP_ECHO_REPLY 0
|
||||
#define ZT_ICMP_DESTINATION_UNREACHABLE 3
|
||||
#define ZT_ICMP_SOURCE_QUENCH 4
|
||||
#define ZT_ICMP_REDIRECT 5
|
||||
#define ZT_ICMP_ALTERNATE_HOST_ADDRESS 6
|
||||
#define ZT_ICMP_ECHO_REQUEST 8
|
||||
#define ZT_ICMP_ROUTER_ADVERTISEMENT 9
|
||||
#define ZT_ICMP_ROUTER_SOLICITATION 10
|
||||
#define ZT_ICMP_TIME_EXCEEDED 11
|
||||
#define ZT_ICMP_BAD_IP_HEADER 12
|
||||
#define ZT_ICMP_TIMESTAMP 13
|
||||
#define ZT_ICMP_TIMESTAMP_REPLY 14
|
||||
#define ZT_ICMP_INFORMATION_REQUEST 15
|
||||
#define ZT_ICMP_INFORMATION_REPLY 16
|
||||
#define ZT_ICMP_ADDRESS_MASK_REQUEST 17
|
||||
#define ZT_ICMP_ADDRESS_MASK_REPLY 18
|
||||
#define ZT_ICMP_TRACEROUTE 30
|
||||
#define ZT_ICMP_MOBILE_HOST_REDIRECT 32
|
||||
#define ZT_ICMP_MOBILE_REGISTRATION_REQUEST 35
|
||||
#define ZT_ICMP_MOBILE_REGISTRATION_REPLY 36
|
||||
|
||||
/* IPv6 ICMP types */
|
||||
#define ZT_ICMP6_DESTINATION_UNREACHABLE 1
|
||||
#define ZT_ICMP6_PACKET_TOO_BIG 2
|
||||
#define ZT_ICMP6_TIME_EXCEEDED 3
|
||||
#define ZT_ICMP6_PARAMETER_PROBLEM 4
|
||||
#define ZT_ICMP6_ECHO_REQUEST 128
|
||||
#define ZT_ICMP6_ECHO_REPLY 129
|
||||
#define ZT_ICMP6_MULTICAST_LISTENER_QUERY 130
|
||||
#define ZT_ICMP6_MULTICAST_LISTENER_REPORT 131
|
||||
#define ZT_ICMP6_MULTICAST_LISTENER_DONE 132
|
||||
#define ZT_ICMP6_ROUTER_SOLICITATION 133
|
||||
#define ZT_ICMP6_ROUTER_ADVERTISEMENT 134
|
||||
#define ZT_ICMP6_NEIGHBOR_SOLICITATION 135
|
||||
#define ZT_ICMP6_NEIGHBOR_ADVERTISEMENT 136
|
||||
#define ZT_ICMP6_REDIRECT_MESSAGE 137
|
||||
#define ZT_ICMP6_ROUTER_RENUMBERING 138
|
||||
#define ZT_ICMP6_NODE_INFORMATION_QUERY 139
|
||||
#define ZT_ICMP6_NODE_INFORMATION_RESPONSE 140
|
||||
#define ZT_ICMP6_INV_NEIGHBOR_SOLICITATION 141
|
||||
#define ZT_ICMP6_INV_NEIGHBOR_ADVERTISEMENT 142
|
||||
#define ZT_ICMP6_MLDV2 143
|
||||
#define ZT_ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REQUEST 144
|
||||
#define ZT_ICMP6_HOME_AGENT_ADDRESS_DISCOVERY_REPLY 145
|
||||
#define ZT_ICMP6_MOBILE_PREFIX_SOLICITATION 146
|
||||
#define ZT_ICMP6_MOBILE_PREFIX_ADVERTISEMENT 147
|
||||
#define ZT_ICMP6_CERTIFICATION_PATH_SOLICITATION 148
|
||||
#define ZT_ICMP6_CERTIFICATION_PATH_ADVERTISEMENT 149
|
||||
#define ZT_ICMP6_MULTICAST_ROUTER_ADVERTISEMENT 151
|
||||
#define ZT_ICMP6_MULTICAST_ROUTER_SOLICITATION 152
|
||||
#define ZT_ICMP6_MULTICAST_ROUTER_TERMINATION 153
|
||||
#define ZT_ICMP6_RPL_CONTROL_MESSAGE 155
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
|
||||
/**
|
||||
* A simple Ethernet frame level filter
|
||||
*
|
||||
* This doesn't specify actions, since it's used as a deny filter. The rule
|
||||
* in ZT1 is "that which is not explicitly prohibited is allowed." (Except for
|
||||
* ethertypes, which are handled by a whitelist.)
|
||||
*/
|
||||
class Filter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Value returned by etherTypeName, etc. on unknown
|
||||
*
|
||||
* These static methods return precisely this, so a pointer equality
|
||||
* check will work.
|
||||
*/
|
||||
static const char *const UNKNOWN_NAME;
|
||||
|
||||
/**
|
||||
* An empty range as a more idiomatic way of specifying a wildcard match
|
||||
*/
|
||||
static const Range<unsigned int> ANY;
|
||||
|
||||
/**
|
||||
* A filter rule
|
||||
*/
|
||||
class Rule
|
||||
{
|
||||
public:
|
||||
Rule()
|
||||
throw() :
|
||||
_etherType(),
|
||||
_protocol(),
|
||||
_port()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a rule from a string-serialized value
|
||||
*
|
||||
* @param s String formatted rule, such as returned by toString()
|
||||
* @throws std::invalid_argument String formatted rule is not valid
|
||||
*/
|
||||
Rule(const char *s)
|
||||
throw(std::invalid_argument);
|
||||
|
||||
/**
|
||||
* Construct a new rule
|
||||
*
|
||||
* @param etype Ethernet type or empty range for ANY
|
||||
* @param prot Protocol or empty range for ANY (meaning depends on ethertype, e.g. IP protocol numbers)
|
||||
* @param prt Port or empty range for ANY (only applies to some protocols)
|
||||
*/
|
||||
Rule(const Range<unsigned int> &etype,const Range<unsigned int> &prot,const Range<unsigned int> &prt)
|
||||
throw() :
|
||||
_etherType(etype),
|
||||
_protocol(prot),
|
||||
_port(prt)
|
||||
{
|
||||
}
|
||||
|
||||
inline const Range<unsigned int> ðerType() const throw() { return _etherType; }
|
||||
inline const Range<unsigned int> &protocol() const throw() { return _protocol; }
|
||||
inline const Range<unsigned int> &port() const throw() { return _port; }
|
||||
|
||||
/**
|
||||
* Test this rule against a frame
|
||||
*
|
||||
* @param etype Type of ethernet frame
|
||||
* @param data Ethernet frame data
|
||||
* @param len Length of ethernet frame
|
||||
* @return True if rule matches
|
||||
* @throws std::invalid_argument Frame invalid or not parseable
|
||||
*/
|
||||
bool operator()(unsigned int etype,const void *data,unsigned int len) const
|
||||
throw(std::invalid_argument);
|
||||
|
||||
/**
|
||||
* Serialize rule as string
|
||||
*
|
||||
* @return Human readable representation of rule
|
||||
*/
|
||||
std::string toString() const;
|
||||
|
||||
inline bool operator==(const Rule &r) const throw() { return ((_etherType == r._etherType)&&(_protocol == r._protocol)&&(_port == r._port)); }
|
||||
inline bool operator!=(const Rule &r) const throw() { return !(*this == r); }
|
||||
inline bool operator<(const Rule &r) const
|
||||
throw()
|
||||
{
|
||||
if (_etherType < r._etherType)
|
||||
return true;
|
||||
else if (_etherType == r._etherType) {
|
||||
if (_protocol < r._protocol)
|
||||
return true;
|
||||
else if (_protocol == r._protocol) {
|
||||
if (_port < r._port)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline bool operator>(const Rule &r) const throw() { return (r < *this); }
|
||||
inline bool operator<=(const Rule &r) const throw() { return !(r < *this); }
|
||||
inline bool operator>=(const Rule &r) const throw() { return !(*this < r); }
|
||||
|
||||
private:
|
||||
Range<unsigned int> _etherType;
|
||||
Range<unsigned int> _protocol;
|
||||
Range<unsigned int> _port;
|
||||
};
|
||||
|
||||
Filter() {}
|
||||
|
||||
/**
|
||||
* @param s String-serialized filter representation
|
||||
*/
|
||||
Filter(const char *s)
|
||||
throw(std::invalid_argument);
|
||||
|
||||
/**
|
||||
* @return Comma-delimited list of string-format rules
|
||||
*/
|
||||
std::string toString() const;
|
||||
|
||||
/**
|
||||
* Add a rule to this filter
|
||||
*
|
||||
* @param r Rule to add to filter
|
||||
*/
|
||||
void add(const Rule &r);
|
||||
|
||||
inline bool operator()(unsigned int etype,const void *data,unsigned int len) const
|
||||
throw(std::invalid_argument)
|
||||
{
|
||||
for(std::vector<Rule>::const_iterator r(_rules.begin());r!=_rules.end();++r) {
|
||||
if ((*r)(etype,data,len))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char *etherTypeName(const unsigned int etherType)
|
||||
throw();
|
||||
static const char *ipProtocolName(const unsigned int ipp)
|
||||
throw();
|
||||
static const char *icmpTypeName(const unsigned int icmpType)
|
||||
throw();
|
||||
static const char *icmp6TypeName(const unsigned int icmp6Type)
|
||||
throw();
|
||||
|
||||
private:
|
||||
std::vector<Rule> _rules;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
|
@ -1,84 +0,0 @@
|
|||
ZeroTier Security
|
||||
======
|
||||
|
||||
## Summary
|
||||
|
||||
|
||||
## Using ZeroTier Securely
|
||||
|
||||
### Overall Recommendations
|
||||
|
||||
*TL;DR: same as anything else: defense in depth defense in depth defense in depth.*
|
||||
|
||||
We encourage our users to treat private ZeroTier networks as being rougly equivalent in security to WPA2-enterprise securied WiFi or on-premise wired Ethernet. (Public networks on the other hand are open by design.) That means they're networks with perimeters, but like all networks the compromise of any participating device or network controller allows an attacker to breach this perimeter.
|
||||
|
||||
**Never trust the network.** Many modern security professionals discourage reliance on network perimeters as major components in any security strategy, and we strongly agree regardless of whether your network is physical or virtual.
|
||||
|
||||
As part of a defense in depth approach **we specifically encourage the use of other secure protocols and authentication systems over ZeroTier networks**. While the use of secure encrypted protocols like SSH and SSL over ZeroTier adds a bit more overhead, it greatly reduces the chance of total compromise.
|
||||
|
||||
Imagine that the per-day probability of a major "0-day" security flaw in ZeroTier and OpenSSH are both roughly 0.001 or one per thousand days. Using both at the same time gives you a cumulative 0-day risk of roughly 0.000001 or one per one million days.
|
||||
|
||||
Those are made-up numbers. In reality these probabilities can't be known ahead of time. History shows that a 0-day could be found in anything tomorrow, next week, or never. But layers of security give you an overall posture that is the product -- more than the sum -- of its parts. That's how defense in depth works.
|
||||
|
||||
### ZeroTier Specifics
|
||||
|
||||
#### Protect Your Identity
|
||||
|
||||
Each ZeroTier device has an identity. The secret portion of this identity is stored in a file called "identity.secret." *Protect this file.* If it's stolen your device's identity (as represented by its 10-digit ZeroTier address) can easily be stolen or impersonated and your traffic can be decrypted or man-in-the-middle'd.
|
||||
|
||||
#### Protect Your Controller
|
||||
|
||||
The second major component of ZeroTier network security is the network controller. It's responsible for issuing certificates and configuration information to all network members. That makes it a certificate authority. Compromise of the controller allows an attacker to join or disrupt any network the controller controls. It does *not*, however, allow an attacker to decrypt peer to peer unicast traffic.
|
||||
|
||||
If you are using our controller-as-a-service at [my.zerotier.com](https://my.zerotier.com), you are delegating this responsibility to us.
|
||||
|
||||
## Security Priorities
|
||||
|
||||
These are our security "must-haves." If the system fails in any of these objectives it is broken.
|
||||
|
||||
* ZeroTier must be secure against remote vulnerabilities. This includes things like unauthorized remote control, remote penetration of the device using ZeroTier as a vector, or remote injection of malware.
|
||||
|
||||
* The content (but not meta-data) of communication must be secure against eavesdropping on the wire by any known means. (We can't warrant against secret vulnerabilities against ciphers, etc., or anything else we don't know about.)
|
||||
|
||||
* Communication must be secure against man-in-the-middle attacks and remote device impersonation.
|
||||
|
||||
## Security Non-Priorities
|
||||
|
||||
There are a few aspects of security we knowingly do not address, since doing so would be beyond scope or would conflict too greatly with other priorities.
|
||||
|
||||
* ZeroTier makes no effort to conceal communication meta-data such as source and destination addresses and the amount of information transferred between peers. To do this more or less requires onion routing or other "heavy" approaches to anonymity, and this is beyond scope.
|
||||
|
||||
* ZeroTier does not implement complex certificate chains, X.509, or other feature-rich (some would say feature-laden) cryptographic stuff. We only implement the crypto we need to get the job done.
|
||||
|
||||
* We don't take extraordinary measures to preserve security under conditions in which an endpoint device has been penetrated by other means (e.g. "rooted" by third party malware) or physicall compromised. If someone steals your keys they've stolen your keys, and if they've "pwned" your device they can easily eavesdrop on everything directly.
|
||||
|
||||
## Insecurities and Areas for Improvement
|
||||
|
||||
The only perfectly secure system is one that is off. All real world systems have potential security weaknesses. If possible, we like to know what these are and acknowledge their existence.
|
||||
|
||||
In some cases we plan to improve these. In other cases we have deliberately decided to "punt" on them in favor of some other priority (see philosophy). We may or may not revisit this decision in the future.
|
||||
|
||||
* We don't implement forward secrecy / ephemeral keys. A [discussion of this can be found at the closed GitHub issue for this feature](https://github.com/zerotier/ZeroTierOne/issues/204). In short: we've decided to "punt" on this feature because it introduces complexity and state negotiation. One of the design goals of ZeroTier is "reliability convergence" -- the reliability of ZeroTier virtual networks should rapidly converge with that of the underlying physical wire. Any state that must be negotiated prior to communication multiplies the probability of delay or failure due to packet loss. We *may* revisit this decision at a later date.
|
||||
|
||||
## Secure Coding Practices
|
||||
|
||||
The first line of defense employed against remote vulnerabilities and other major security flaws is the use of secure coding practices. These are, in no particular order:
|
||||
|
||||
* All parsing of remote messages is performed via higher level safe bounds-checked data structures and interfaces. See node/Buffer.hpp for one of the core elements of this.
|
||||
|
||||
* C++ exceptions are used to ensure that any unhandled failure or error condition (such as a bounds checking violation) results in the safe and complete termination of message processing. Invalid messages are dropped and ignored.
|
||||
|
||||
* Minimalism is a secure coding practice. There is an exponential relationship between complexity and the probability of bugs, and complex designs are much harder to audit and reason about.
|
||||
|
||||
* Our build scripts try to enable any OS and compiler level security features such as ASLR and "stack canaries" on non-debug builds.
|
||||
|
||||
## Cryptographic Security Practices
|
||||
|
||||
* We use [boring crypto](https://cr.yp.to/talks/2015.10.05/slides-djb-20151005-a4.pdf). A single symmetric algorithm (Salsa20/12), a single asymmetric algorithm (Curve25519 ECDH-256), and a single MAC (Poly1305). The way these algorithms are used is identical to how they're used in the NaCl reference implementation. The protocol supports selection of alternative algorithms but only for "future proofing" in the case that a serious flaw is discovered in any of these. Avoding algorithm bloat and cryptographic state negotiation helps guard against down-grade, "oracle," and other protocol level attacks.
|
||||
|
||||
* Authenticated encryption is employed with authentication being performed prior to any other operations on received messages. See also: [the cryptographic doom principle](https://moxie.org/blog/the-cryptographic-doom-principle/).
|
||||
|
||||
* "Never branch on anything secret" -- deterministic-time comparisons and other operations are used in cryptographic operations. See Utils::secureEq() in node/Utils.hpp.
|
||||
|
||||
* OS-derived crypographic random numbers (/dev/urandom or Windows CryptGenRandom) are further randomized using encryption by a secondary key with a secondary source of entropy to guard against CSPRNG bugs. Such OS-level CSPRNG bugs have been found in the past. See Utils::getSecureRandom() in node/Utils.hpp.
|
||||
|
57
attic/cli/README.md
Normal file
57
attic/cli/README.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
The new ZeroTier CLI!
|
||||
====
|
||||
|
||||
With this update we've expanded upon the previous CLI's functionality, so things should seem pretty familiar. Here are some of the new features we've introduced:
|
||||
|
||||
- Create and administer networks on ZeroTier Central directly from the console.
|
||||
- Service configurations, allows you to control local/remote instances of ZeroTier One
|
||||
- Identity generation and management is now part of the same CLI tool
|
||||
|
||||
***
|
||||
## Configurations
|
||||
|
||||
Configurations are a way for you to nickname and logically organize the control of ZeroTier services running locally or remotely (this includes ZeroTier Central!). They're merely groupings of service API url's and auth tokens. The CLI's settings data is contained within `.zerotierCliSettings`.
|
||||
|
||||
For instance, you can control your local instance of ZeroTier One via the `@local` config. By default it is represented as follows:
|
||||
|
||||
```
|
||||
"local": {
|
||||
"auth": "7tyqRoFytajf21j2l2t9QPm5",
|
||||
"type": "one",
|
||||
"url": "http://127.0.0.1:9993/"
|
||||
}
|
||||
```
|
||||
|
||||
As an example, if you issue the command `zerotier ls` is it implicitly stating `zerotier @local ls`.
|
||||
|
||||
With the same line of thinking, you could create a `@my.zerotier.com` which would allow for something like `zerotier @my.zerotier.com net-create` which talks to our hosted ZeroTier Central to create a new network.
|
||||
|
||||
|
||||
|
||||
## Command families
|
||||
|
||||
- `cli-` is for configuring the settings data for the CLI itself, such as adding/removing `@thing` configurations, variables, etc.
|
||||
- `net-` is for operating on a *ZeroTier Central* service such as `https://my.zerotier.com`
|
||||
- `id-` is for handling ZeroTier identities.
|
||||
|
||||
And those commands with no prefix are there to allow you to operate ZeroTier One instances either local or remote.
|
||||
|
||||
***
|
||||
## Useful command examples
|
||||
|
||||
*Add a ZeroTier One configuration:*
|
||||
|
||||
- `zerotier cli-add-zt MyLocalConfigName https://127.0.0.1:9993/ <authtoken>`
|
||||
|
||||
*Add a ZeroTier Central configuration:*
|
||||
|
||||
- `zerotier cli-add-central MyZTCentralConfigName https://my.zerotier.com/ <centralAPIAuthtoken>`
|
||||
|
||||
*Set a default ZeroTier One instance:*
|
||||
|
||||
- `zerotier cli-set defaultOne MyLocalConfigName`
|
||||
|
||||
*Set a default ZeroTier Central:*
|
||||
|
||||
- `zerotier cli-set defaultCentral MyZTCentralConfigName`
|
||||
|
957
attic/cli/zerotier.cpp
Normal file
957
attic/cli/zerotier.cpp
Normal file
|
@ -0,0 +1,957 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Note: unlike the rest of ZT's code base, this requires C++11 due to
|
||||
// the JSON library it uses and other things.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/Identity.hpp"
|
||||
#include "../version.h"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
#include "../ext/offbase/json/json.hpp"
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <wchar.h>
|
||||
#else
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <regex>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
using namespace ZeroTier;
|
||||
|
||||
#define ZT_CLI_FLAG_VERBOSE 'v'
|
||||
#define ZT_CLI_FLAG_UNSAFE_SSL 'X'
|
||||
|
||||
#define REQ_GET 0
|
||||
#define REQ_POST 1
|
||||
#define REQ_DEL 2
|
||||
|
||||
#define OK_STR "[OK ]: "
|
||||
#define FAIL_STR "[FAIL]: "
|
||||
#define WARN_STR "[WARN]: "
|
||||
#define INVALID_ARGS_STR "Invalid args. Usage: "
|
||||
|
||||
struct CLIState
|
||||
{
|
||||
std::string atname;
|
||||
std::string command;
|
||||
std::string url;
|
||||
std::map<std::string,std::string> reqHeaders;
|
||||
std::vector<std::string> args;
|
||||
std::map<char,std::string> opts;
|
||||
json settings;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
static Identity getIdFromArg(char *arg)
|
||||
{
|
||||
Identity id;
|
||||
if ((strlen(arg) > 32)&&(arg[10] == ':')) { // identity is a literal on the command line
|
||||
if (id.fromString(arg))
|
||||
return id;
|
||||
} else { // identity is to be read from a file
|
||||
std::string idser;
|
||||
if (OSUtils::readFile(arg,idser)) {
|
||||
if (id.fromString(idser))
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return Identity();
|
||||
}
|
||||
|
||||
static std::string trimString(const std::string &s)
|
||||
{
|
||||
unsigned long end = (unsigned long)s.length();
|
||||
while (end) {
|
||||
char c = s[end - 1];
|
||||
if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t'))
|
||||
--end;
|
||||
else break;
|
||||
}
|
||||
unsigned long start = 0;
|
||||
while (start < end) {
|
||||
char c = s[start];
|
||||
if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t'))
|
||||
++start;
|
||||
else break;
|
||||
}
|
||||
return s.substr(start,end - start);
|
||||
}
|
||||
|
||||
static inline std::string getSettingsFilePath()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
#else
|
||||
const char *home = getenv("HOME");
|
||||
if (!home)
|
||||
home = "/";
|
||||
return (std::string(home) + "/.zerotierCliSettings");
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool saveSettingsBackup(CLIState &state)
|
||||
{
|
||||
std::string sfp(getSettingsFilePath().c_str());
|
||||
if(state.settings.find("generateBackupConfig") != state.settings.end()
|
||||
&& state.settings["generateBackupConfig"].get<std::string>() == "true") {
|
||||
std::string backup_file = getSettingsFilePath() + ".bak";
|
||||
if(!OSUtils::writeFile(sfp.c_str(), state.settings.dump(2))) {
|
||||
OSUtils::lockDownFile(sfp.c_str(),false);
|
||||
std::cout << WARN_STR << "unable to write backup config file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool saveSettings(CLIState &state)
|
||||
{
|
||||
std::string sfp(getSettingsFilePath().c_str());
|
||||
if(OSUtils::writeFile(sfp.c_str(), state.settings.dump(2))) {
|
||||
OSUtils::lockDownFile(sfp.c_str(),false);
|
||||
std::cout << OK_STR << "changes saved." << std::endl;
|
||||
return true;
|
||||
}
|
||||
std::cout << FAIL_STR << "unable to write to " << sfp << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void dumpHelp()
|
||||
{
|
||||
std::cout << "ZeroTier Newer-Spiffier CLI " << ZEROTIER_ONE_VERSION_MAJOR << "." << ZEROTIER_ONE_VERSION_MINOR << "." << ZEROTIER_ONE_VERSION_REVISION << std::endl;
|
||||
std::cout << "(c)2016 ZeroTier, Inc. / Licensed under the GNU GPL v3" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Configuration path: " << getSettingsFilePath() << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Usage: zerotier [-option] [@name] <command> [<command options>]" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Options:" << std::endl;
|
||||
std::cout << " -verbose - Verbose JSON output" << std::endl;
|
||||
std::cout << " -X - Do not check SSL certs (CAUTION!)" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "CLI Configuration Commands:" << std::endl;
|
||||
std::cout << " cli-set <setting> <value> - Set a CLI option ('cli-set help')" << std::endl;
|
||||
std::cout << " cli-unset <setting> <value> - Un-sets a CLI option ('cli-unset help')" << std::endl;
|
||||
std::cout << " cli-ls - List configured @things" << std::endl;
|
||||
std::cout << " cli-rm @name - Remove a configured @thing" << std::endl;
|
||||
std::cout << " cli-add-zt @name <url> <auth> - Add a ZeroTier service" << std::endl;
|
||||
std::cout << " cli-add-central @name <url> <auth> - Add ZeroTier Central instance" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "ZeroTier One Service Commands:" << std::endl;
|
||||
std::cout << " -v / -version - Displays default local instance's version'" << std::endl;
|
||||
std::cout << " ls - List currently joined networks" << std::endl;
|
||||
std::cout << " join <network> [opt=value ...] - Join a network" << std::endl;
|
||||
std::cout << " leave <network> - Leave a network" << std::endl;
|
||||
std::cout << " peers - List ZeroTier VL1 peers" << std::endl;
|
||||
std::cout << " show [<network/peer address>] - Get info about self or object" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Network Controller Commands:" << std::endl;
|
||||
std::cout << " net-create - Create a new network" << std::endl;
|
||||
std::cout << " net-rm <network> - Delete a network (CAUTION!)" << std::endl;
|
||||
std::cout << " net-ls - List administered networks" << std::endl;
|
||||
std::cout << " net-members <network> - List members of a network" << std::endl;
|
||||
std::cout << " net-show <network> [<address>] - Get network or member info" << std::endl;
|
||||
std::cout << " net-auth <network> <address> - Authorize a member" << std::endl;
|
||||
std::cout << " net-unauth <network> <address> - De-authorize a member" << std::endl;
|
||||
std::cout << " net-set <path> <value> - See 'net-set help'" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Identity Commands:" << std::endl;
|
||||
std::cout << " id-generate [<vanity prefix>] - Generate a ZeroTier identity" << std::endl;
|
||||
std::cout << " id-validate <identity> - Locally validate an identity" << std::endl;
|
||||
std::cout << " id-sign <identity> <file> - Sign a file" << std::endl;
|
||||
std::cout << " id-verify <secret> <file> <sig> - Verify a file's signature" << std::endl;
|
||||
std::cout << " id-getpublic <secret> - Get full identity's public portion" << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
static size_t _curlStringAppendCallback(void *contents,size_t size,size_t nmemb,void *stdstring)
|
||||
{
|
||||
size_t totalSize = size * nmemb;
|
||||
reinterpret_cast<std::string *>(stdstring)->append((const char *)contents,totalSize);
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
static std::tuple<int,std::string> REQUEST(int requestType, CLIState &state, const std::map<std::string,std::string> &headers, const std::string &postfield, const std::string &url)
|
||||
{
|
||||
std::string body;
|
||||
char errbuf[CURL_ERROR_SIZE];
|
||||
char urlbuf[4096];
|
||||
|
||||
CURL *curl;
|
||||
curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
std::cerr << "FATAL: curl_easy_init() failed" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
Utils::scopy(urlbuf,sizeof(urlbuf),url.c_str());
|
||||
curl_easy_setopt(curl,CURLOPT_URL,urlbuf);
|
||||
|
||||
struct curl_slist *hdrs = (struct curl_slist *)0;
|
||||
for(std::map<std::string,std::string>::const_iterator i(headers.begin());i!=headers.end();++i) {
|
||||
std::string htmp(i->first);
|
||||
htmp.append(": ");
|
||||
htmp.append(i->second);
|
||||
hdrs = curl_slist_append(hdrs,htmp.c_str());
|
||||
}
|
||||
if (hdrs)
|
||||
curl_easy_setopt(curl,CURLOPT_HTTPHEADER,hdrs);
|
||||
|
||||
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
||||
curl_easy_setopt(curl,CURLOPT_WRITEDATA,(void *)&body);
|
||||
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curlStringAppendCallback);
|
||||
|
||||
if(std::find(state.args.begin(), state.args.end(), "-X") == state.args.end())
|
||||
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(state.opts.count(ZT_CLI_FLAG_UNSAFE_SSL) > 0) ? 0L : 1L);
|
||||
|
||||
if(requestType == REQ_POST) {
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfield.c_str());
|
||||
}
|
||||
if(requestType == REQ_DEL)
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
if(requestType == REQ_GET) {
|
||||
curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errbuf);
|
||||
curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,0L);
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl,CURLOPT_USERAGENT,"ZeroTier-CLI");
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
|
||||
errbuf[CURL_ERROR_SIZE-1] = (char)0; // sanity check
|
||||
|
||||
if (res != CURLE_OK)
|
||||
return std::make_tuple(-1,std::string(errbuf));
|
||||
|
||||
long response_code;
|
||||
int rc = (int)curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE, &response_code);
|
||||
|
||||
if(response_code == 401) { std::cout << FAIL_STR << response_code << "Unauthorized." << std::endl; exit(0); }
|
||||
else if(response_code == 403) { std::cout << FAIL_STR << response_code << "Forbidden." << std::endl; exit(0); }
|
||||
else if(response_code == 404) { std::cout << FAIL_STR << response_code << "Not found." << std::endl; exit(0); }
|
||||
else if(response_code == 408) { std::cout << FAIL_STR << response_code << "Request timed out." << std::endl; exit(0); }
|
||||
else if(response_code != 200) { std::cout << FAIL_STR << response_code << "Unable to process request." << std::endl; exit(0); }
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
if (hdrs)
|
||||
curl_slist_free_all(hdrs);
|
||||
return std::make_tuple(response_code,body);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Check for user-specified @thing config
|
||||
// Make sure it @thing makes sense
|
||||
// Apply appropriate request headers
|
||||
static void checkForThing(CLIState &state, std::string thingType, bool warnNoThingProvided)
|
||||
{
|
||||
std::string configName;
|
||||
if(state.atname.length()) {
|
||||
configName = state.atname.erase(0,1);
|
||||
// make sure specified @thing makes sense in the context of the command
|
||||
if(thingType == "one" && state.settings["things"][configName]["type"].get<std::string>() != "one") {
|
||||
std::cout << FAIL_STR << "A ZeroTier Central config was specified for a ZeroTier One command." << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
if(thingType == "central" && state.settings["things"][configName]["type"].get<std::string>() != "central") {
|
||||
std::cout << FAIL_STR << "A ZeroTier One config was specified for a ZeroTier Central command." << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else { // no @thing specified, check for defaults depending on type
|
||||
if(thingType == "one") {
|
||||
if(state.settings.find("defaultOne") != state.settings.end()) {
|
||||
if(warnNoThingProvided)
|
||||
std::cout << WARN_STR << "No @thing specified, assuming default for ZeroTier One command: " << state.settings["defaultOne"].get<std::string>().c_str() << std::endl;
|
||||
configName = state.settings["defaultOne"].get<std::string>().erase(0,1); // get default
|
||||
}
|
||||
else {
|
||||
std::cout << WARN_STR << "No @thing specified, and no default is known." << std::endl;
|
||||
std::cout << "HELP: To set a default: zerotier cli-set defaultOne @my_default_thing" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
if(thingType == "central") {
|
||||
if(state.settings.find("defaultCentral") != state.settings.end()) {
|
||||
if(warnNoThingProvided)
|
||||
std::cout << WARN_STR << "No @thing specified, assuming default for ZeroTier Central command: " << state.settings["defaultCentral"].get<std::string>().c_str() << std::endl;
|
||||
configName = state.settings["defaultCentral"].get<std::string>().erase(0,1); // get default
|
||||
}
|
||||
else {
|
||||
std::cout << WARN_STR << "No @thing specified, and no default is known." << std::endl;
|
||||
std::cout << "HELP: To set a default: zerotier cli-set defaultCentral @my_default_thing" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Apply headers
|
||||
if(thingType == "one") {
|
||||
state.reqHeaders["X-ZT1-Auth"] = state.settings["things"][configName]["auth"];
|
||||
}
|
||||
if(thingType == "central"){
|
||||
state.reqHeaders["Content-Type"] = "application/json";
|
||||
state.reqHeaders["Authorization"] = "Bearer " + state.settings["things"][configName]["auth"].get<std::string>();
|
||||
state.reqHeaders["Accept"] = "application/json";
|
||||
}
|
||||
state.url = state.settings["things"][configName]["url"];
|
||||
}
|
||||
|
||||
static bool checkURL(std::string url)
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string getLocalVersion(CLIState &state)
|
||||
{
|
||||
json result;
|
||||
std::tuple<int,std::string> res;
|
||||
checkForThing(state,"one",false);
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "/status");
|
||||
if(std::get<0>(res) == 200) {
|
||||
result = json::parse(std::get<1>(res));
|
||||
return result["version"].get<std::string>();
|
||||
}
|
||||
return "---";
|
||||
}
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
int _tmain(int argc, _TCHAR* argv[])
|
||||
#else
|
||||
int main(int argc,char **argv)
|
||||
#endif
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
{
|
||||
WSADATA wsaData;
|
||||
WSAStartup(MAKEWORD(2,2),&wsaData);
|
||||
}
|
||||
#endif
|
||||
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
CLIState state;
|
||||
std::string arg1, arg2, authToken;
|
||||
|
||||
for(int i=1;i<argc;++i) {
|
||||
if (argv[i][0] == '@') {
|
||||
state.atname = argv[i];
|
||||
}
|
||||
else if (state.command.length() == 0) {
|
||||
if (argv[i][0] == '-') {
|
||||
if (!argv[i][1]) {
|
||||
dumpHelp();
|
||||
return -1;
|
||||
} else if (argv[i][2]) {
|
||||
state.opts[argv[i][1]] = argv[i] + 2;
|
||||
} else {
|
||||
state.opts[argv[i][1]] = "";
|
||||
}
|
||||
} else {
|
||||
state.command = argv[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
state.args.push_back(std::string(argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::string buf;
|
||||
if (OSUtils::readFile(getSettingsFilePath().c_str(),buf))
|
||||
state.settings = json::parse(buf);
|
||||
|
||||
if (state.settings.empty()) {
|
||||
// Default settings
|
||||
state.settings = {
|
||||
{ "configVersion", 1 },
|
||||
{ "things", {
|
||||
{ "my.zerotier.com", {
|
||||
{ "type", "central" },
|
||||
{ "url", "https://my.zerotier.com/" },
|
||||
{ "auth", "" }
|
||||
}},
|
||||
{ "local", {
|
||||
{ "type", "one" },
|
||||
{ "url", "" },
|
||||
{ "auth", "" }
|
||||
}}
|
||||
}},
|
||||
{ "defaultController", "@my.zerotier.com" },
|
||||
{ "defaultOne", "@local" }
|
||||
};
|
||||
|
||||
std::string oneHome(OSUtils::platformDefaultHomePath());
|
||||
std::string portStr;
|
||||
bool initSuccess = false;
|
||||
std::string path = oneHome + ZT_PATH_SEPARATOR_S ;
|
||||
if (OSUtils::readFile((oneHome + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),authToken)&&OSUtils::readFile((oneHome + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),portStr)) {
|
||||
portStr = trimString(portStr);
|
||||
authToken = trimString(authToken);
|
||||
int port = Utils::strToInt(portStr.c_str());
|
||||
if (((port > 0)&&(port < 65536))&&(authToken.length() > 0)) {
|
||||
state.settings["things"]["local"]["url"] = (std::string("http://127.0.0.1:") + portStr + "/");
|
||||
state.settings["things"]["local"]["auth"] = authToken;
|
||||
initSuccess = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!saveSettings(state)) {
|
||||
std::cerr << "FATAL: unable to write " << getSettingsFilePath() << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (initSuccess) {
|
||||
std::cerr << "INFO: initialized new config at " << getSettingsFilePath() << std::endl;
|
||||
} else {
|
||||
std::cerr << "INFO: initialized new config at " << getSettingsFilePath() << " but could not auto-init local ZeroTier One service config from " << oneHome << " -- you will need to set local service URL and port manually if you want to control a local instance of ZeroTier One. (This happens if you are not root/administrator.)" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PRE-REQUEST SETUP
|
||||
|
||||
json result;
|
||||
std::tuple<int,std::string> res;
|
||||
std::string url = "";
|
||||
|
||||
// META
|
||||
|
||||
if ((state.command.length() == 0)||(state.command == "help")) {
|
||||
dumpHelp();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// zerotier version
|
||||
else if (state.command == "v" || state.command == "version") {
|
||||
std::cout << getLocalVersion(state) << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// zerotier cli-set <setting> <value>
|
||||
else if (state.command == "cli-set") {
|
||||
if(argc != 4) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier cli-set <setting> <value>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string settingName, settingValue;
|
||||
if(state.atname.length()) { // User provided @thing erroneously, we will ignore it and adjust argument indices
|
||||
settingName = argv[3];
|
||||
settingValue = argv[4];
|
||||
}
|
||||
else {
|
||||
settingName = argv[2];
|
||||
settingValue = argv[3];
|
||||
}
|
||||
saveSettingsBackup(state);
|
||||
state.settings[settingName] = settingValue; // changes
|
||||
saveSettings(state);
|
||||
}
|
||||
|
||||
// zerotier cli-unset <setting>
|
||||
else if (state.command == "cli-unset") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier cli-unset <setting>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string settingName;
|
||||
if(state.atname.length()) // User provided @thing erroneously, we will ignore it and adjust argument indices
|
||||
settingName = argv[3];
|
||||
else
|
||||
settingName = argv[2];
|
||||
saveSettingsBackup(state);
|
||||
state.settings.erase(settingName); // changes
|
||||
saveSettings(state);
|
||||
}
|
||||
|
||||
// zerotier @thing_to_remove cli-rm --- removes the configuration
|
||||
else if (state.command == "cli-rm") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier cli-rm <@thing>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if(state.settings["things"].find(state.atname) != state.settings["things"].end()) {
|
||||
if(state.settings["defaultOne"] == state.atname) {
|
||||
std::cout << "WARNING: The config you're trying to remove is currently set as your default. Set a new default first!" << std::endl;
|
||||
std::cout << " | Usage: zerotier set defaultOne @your_other_thing" << std::endl;
|
||||
}
|
||||
else {
|
||||
state.settings["things"].erase(state.atname.c_str());
|
||||
saveSettings(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier cli-add-zt <shortname> <url> <auth>
|
||||
// TODO: Check for malformed urls/auth
|
||||
else if (state.command == "cli-add-zt") {
|
||||
if(argc != 5) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier cli-add-zt <shortname> <url> <authToken>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string thing_name = argv[2], url = argv[3], auth = argv[4];
|
||||
if(!checkURL(url)) {
|
||||
std::cout << FAIL_STR << "Malformed URL" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if(state.settings.find(thing_name) != state.settings.end()) {
|
||||
std::cout << "WARNING: A @thing with the shortname " << thing_name.c_str()
|
||||
<< " already exists. Choose another name or rename the old @thing" << std::endl;
|
||||
std::cout << " | Usage: To rename a @thing: zerotier cli-rename @old_thing_name @new_thing_name" << std::endl;
|
||||
}
|
||||
else {
|
||||
result = json::parse("{ \"auth\": \"" + auth + "\", \"type\": \"" + "one" + "\", \"url\": \"" + url + "\" }");
|
||||
saveSettingsBackup(state);
|
||||
// TODO: Handle cases where user may or may not prepend an @
|
||||
state.settings["things"][thing_name] = result; // changes
|
||||
saveSettings(state);
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier cli-add-central <shortname> <url> <auth>
|
||||
// TODO: Check for malformed urls/auth
|
||||
else if (state.command == "cli-add-central") {
|
||||
if(argc != 5) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier cli-add-central <shortname> <url> <authToken>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string thing_name = argv[2], url = argv[3], auth = argv[4];
|
||||
if(!checkURL(url)) {
|
||||
std::cout << FAIL_STR << "Malformed URL" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if(state.settings.find(thing_name) != state.settings.end()) {
|
||||
std::cout << "WARNING: A @thing with the shortname " << thing_name.c_str()
|
||||
<< " already exists. Choose another name or rename the old @thing" << std::endl;
|
||||
std::cout << " | Usage: To rename a @thing: zerotier cli-rename @old_thing_name @new_thing_name" << std::endl;
|
||||
}
|
||||
else {
|
||||
result = json::parse("{ \"auth\": \"" + auth + "\", \"type\": \"" + "central" + "\", \"url\": \"" + url + "\" }");
|
||||
saveSettingsBackup(state);
|
||||
// TODO: Handle cases where user may or may not prepend an @
|
||||
state.settings["things"]["@" + thing_name] = result; // changes
|
||||
saveSettings(state);
|
||||
}
|
||||
}
|
||||
|
||||
// ONE SERVICE
|
||||
|
||||
// zerotier ls --- display all networks currently joined
|
||||
else if (state.command == "ls" || state.command == "listnetworks") {
|
||||
if(argc != 2) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier ls" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"one",true);
|
||||
url = state.url + "network";
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",(const std::string)url);
|
||||
if(std::get<0>(res) == 200) {
|
||||
std::cout << "listnetworks <nwid> <name> <mac> <status> <type> <dev> <ZT assigned ips>" << std::endl;
|
||||
auto j = json::parse(std::get<1>(res).c_str());
|
||||
if (j.type() == json::value_t::array) {
|
||||
for(int i=0;i<j.size();i++){
|
||||
std::string nwid = j[i]["nwid"].get<std::string>();
|
||||
std::string name = j[i]["name"].get<std::string>();
|
||||
std::string mac = j[i]["mac"].get<std::string>();
|
||||
std::string status = j[i]["status"].get<std::string>();
|
||||
std::string type = j[i]["type"].get<std::string>();
|
||||
std::string addrs;
|
||||
for(int m=0; m<j[i]["assignedAddresses"].size(); m++) {
|
||||
addrs += j[i]["assignedAddresses"][m].get<std::string>() + " ";
|
||||
}
|
||||
std::string dev = j[i]["portDeviceName"].get<std::string>();
|
||||
std::cout << "listnetworks " << nwid << " " << name << " " << mac << " " << status << " " << type << " " << dev << " " << addrs << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier join <nwid> --- joins a network
|
||||
else if (state.command == "join") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier join <nwid>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"one",true);
|
||||
res = REQUEST(REQ_POST,state,state.reqHeaders,"{}",state.url + "/network/" + state.args[0]);
|
||||
if(std::get<0>(res) == 200) {
|
||||
std::cout << OK_STR << "connected to " << state.args[0] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier leave <nwid> --- leaves a network
|
||||
else if (state.command == "leave") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier leave <nwid>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"one",true);
|
||||
res = REQUEST(REQ_DEL,state,state.reqHeaders,"{}",state.url + "/network/" + state.args[0]);
|
||||
if(std::get<0>(res) == 200) {
|
||||
std::cout << OK_STR << "disconnected from " << state.args[0] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier peers --- display address and role of all peers
|
||||
else if (state.command == "peers") {
|
||||
if(argc != 2) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier peers" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"one",true);
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "/peer");
|
||||
if(std::get<0>(res) == 200) {
|
||||
json result = json::parse(std::get<1>(res));
|
||||
for(int i=0; i<result.size(); i++) {
|
||||
std::cout << result[i]["address"] << " " << result[i]["role"] << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier show --- display status of local instance
|
||||
else if (state.command == "show" || state.command == "status") {
|
||||
if(argc != 2) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier show" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"one",true);
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "/status");
|
||||
if(std::get<0>(res) == 200) {
|
||||
result = json::parse(std::get<1>(res));
|
||||
std::string status_str = result["online"].get<bool>() ? "ONLINE" : "OFFLINE";
|
||||
std::cout << "info " << result["address"].get<std::string>()
|
||||
<< " " << status_str << " " << result["version"].get<std::string>() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// REMOTE
|
||||
|
||||
// zerotier @thing net-create --- creates a new network
|
||||
else if (state.command == "net-create") {
|
||||
if(argc > 3 || (argc == 3 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-create" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
res = REQUEST(REQ_POST,state,state.reqHeaders,"",state.url + "api/network");
|
||||
if(std::get<0>(res) == 200) {
|
||||
json result = json::parse(std::get<1>(res));
|
||||
std::cout << OK_STR << "created network " << result["config"]["nwid"].get<std::string>() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-rm <nwid> --- deletes a network
|
||||
else if (state.command == "net-rm") {
|
||||
if(argc > 4 || (argc == 4 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-rm <nwid>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
if(!state.args.size()) {
|
||||
std::cout << "Argument error: No network specified." << std::endl;
|
||||
std::cout << " | Usage: zerotier net-rm <nwid>" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::string nwid = state.args[0];
|
||||
res = REQUEST(REQ_DEL,state,state.reqHeaders,"",state.url + "api/network/" + nwid);
|
||||
if(std::get<0>(res) == 200) {
|
||||
std::cout << "deleted network " << nwid << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-ls --- lists all networks
|
||||
else if (state.command == "net-ls") {
|
||||
if(argc > 3 || (argc == 3 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-ls" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network");
|
||||
if(std::get<0>(res) == 200) {
|
||||
json result = json::parse(std::get<1>(res));
|
||||
for(int m=0;m<result.size(); m++) {
|
||||
std::cout << "network " << result[m]["id"].get<std::string>() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-members <nwid> --- show all members of a network
|
||||
else if (state.command == "net-members") {
|
||||
if(argc > 4 || (argc == 4 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-members <nwid>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
if(!state.args.size()) {
|
||||
std::cout << FAIL_STR << "Argument error: No network specified." << std::endl;
|
||||
std::cout << " | Usage: zerotier net-members <nwid>" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::string nwid = state.args[0];
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network/" + nwid + "/member");
|
||||
json result = json::parse(std::get<1>(res));
|
||||
std::cout << "Members of " << nwid << ":" << std::endl;
|
||||
for (json::iterator it = result.begin(); it != result.end(); ++it) {
|
||||
std::cout << it.key() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-show <nwid> <devID> --- show info about a device on a specific network
|
||||
else if (state.command == "net-show") {
|
||||
if(argc > 5 || (argc == 5 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-show <nwid> <devID>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
if(state.args.size() < 2) {
|
||||
std::cout << FAIL_STR << "Argument error: Too few arguments." << std::endl;
|
||||
std::cout << " | Usage: zerotier net-show <nwid> <devID>" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::string nwid = state.args[0];
|
||||
std::string devid = state.args[1];
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network/" + nwid + "/member/" + devid);
|
||||
// TODO: More info, what would we like to show exactly?
|
||||
if(std::get<0>(res) == 200) {
|
||||
json result = json::parse(std::get<1>(res));
|
||||
std::cout << "Assigned IP: " << std::endl;
|
||||
for(int m=0; m<result["config"]["ipAssignments"].size();m++) {
|
||||
std::cout << "\t" << result["config"]["ipAssignments"][m].get<std::string>() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-auth <nwid> <devID> --- authorize a device on a network
|
||||
else if (state.command == "net-auth") {
|
||||
if(argc > 5 || (argc == 5 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-auth <nwid> <devID>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
if(state.args.size() != 2) {
|
||||
std::cout << FAIL_STR << "Argument error: Network and/or device ID not specified." << std::endl;
|
||||
std::cout << " | Usage: zerotier net-auth <nwid> <devID>" << std::endl;
|
||||
}
|
||||
std::string nwid = state.args[0];
|
||||
std::string devid = state.args[1];
|
||||
url = state.url + "api/network/" + nwid + "/member/" + devid;
|
||||
// Add device to network
|
||||
res = REQUEST(REQ_POST,state,state.reqHeaders,"",(const std::string)url);
|
||||
if(std::get<0>(res) == 200) {
|
||||
result = json::parse(std::get<1>(res));
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",(const std::string)url);
|
||||
result = json::parse(std::get<1>(res));
|
||||
result["config"]["authorized"] = "true";
|
||||
std::string newconfig = result.dump();
|
||||
res = REQUEST(REQ_POST,state,state.reqHeaders,newconfig,(const std::string)url);
|
||||
if(std::get<0>(res) == 200)
|
||||
std::cout << OK_STR << devid << " authorized on " << nwid << std::endl;
|
||||
else
|
||||
std::cout << FAIL_STR << "There was a problem authorizing that device." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-unauth <nwid> <devID>
|
||||
else if (state.command == "net-unauth") {
|
||||
if(argc > 5 || (argc == 5 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-unauth <nwid> <devID>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
if(state.args.size() != 2) {
|
||||
std::cout << FAIL_STR << "Bad argument. No network and/or device ID specified." << std::endl;
|
||||
std::cout << " | Usage: zerotier net-unauth <nwid> <devID>" << std::endl;
|
||||
}
|
||||
std::string nwid = state.args[0];
|
||||
std::string devid = state.args[1];
|
||||
// If successful, get member config
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network/" + nwid + "/member/" + devid);
|
||||
result = json::parse(std::get<1>(res));
|
||||
// modify auth field and re-POST
|
||||
result["config"]["authorized"] = "false";
|
||||
std::string newconfig = result.dump();
|
||||
res = REQUEST(REQ_POST,state,state.reqHeaders,newconfig,state.url + "api/network/" + nwid + "/member/" + devid);
|
||||
if(std::get<0>(res) == 200)
|
||||
std::cout << OK_STR << devid << " de-authorized from " << nwid << std::endl;
|
||||
else
|
||||
std::cout << FAIL_STR << "There was a problem de-authorizing that device." << std::endl;
|
||||
}
|
||||
|
||||
// zerotier @thing net-set
|
||||
else if (state.command == "net-set") {
|
||||
}
|
||||
|
||||
// ID
|
||||
|
||||
// zerotier id-generate [<vanity prefix>]
|
||||
else if (state.command == "id-generate") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier id-generate [<vanity prefix>]" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
uint64_t vanity = 0;
|
||||
int vanityBits = 0;
|
||||
if (argc >= 5) {
|
||||
vanity = Utils::hexStrToU64(argv[4]) & 0xffffffffffULL;
|
||||
vanityBits = 4 * strlen(argv[4]);
|
||||
if (vanityBits > 40)
|
||||
vanityBits = 40;
|
||||
}
|
||||
|
||||
ZeroTier::Identity id;
|
||||
for(;;) {
|
||||
id.generate();
|
||||
if ((id.address().toInt() >> (40 - vanityBits)) == vanity) {
|
||||
if (vanityBits > 0) {
|
||||
fprintf(stderr,"vanity address: found %.10llx !\n",(unsigned long long)id.address().toInt());
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
fprintf(stderr,"vanity address: tried %.10llx looking for first %d bits of %.10llx\n",(unsigned long long)id.address().toInt(),vanityBits,(unsigned long long)(vanity << (40 - vanityBits)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string idser = id.toString(true);
|
||||
if (argc >= 3) {
|
||||
if (!OSUtils::writeFile(argv[2],idser)) {
|
||||
std::cerr << "Error writing to " << argv[2] << std::endl;
|
||||
return 1;
|
||||
} else std::cout << argv[2] << " written" << std::endl;
|
||||
if (argc >= 4) {
|
||||
idser = id.toString(false);
|
||||
if (!OSUtils::writeFile(argv[3],idser)) {
|
||||
std::cerr << "Error writing to " << argv[3] << std::endl;
|
||||
return 1;
|
||||
} else std::cout << argv[3] << " written" << std::endl;
|
||||
}
|
||||
} else std::cout << idser << std::endl;
|
||||
}
|
||||
|
||||
// zerotier id-validate <identity>
|
||||
else if (state.command == "id-validate") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier id-validate <identity>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
Identity id = getIdFromArg(argv[2]);
|
||||
if (!id) {
|
||||
std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (!id.locallyValidate()) {
|
||||
std::cerr << argv[2] << " FAILED validation." << std::endl;
|
||||
return 1;
|
||||
} else std::cout << argv[2] << "is a valid identity" << std::endl;
|
||||
}
|
||||
|
||||
// zerotier id-sign <identity> <file>
|
||||
else if (state.command == "id-sign") {
|
||||
if(argc != 4) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier id-sign <identity> <file>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
Identity id = getIdFromArg(argv[2]);
|
||||
if (!id) {
|
||||
std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (!id.hasPrivate()) {
|
||||
std::cerr << argv[2] << " does not contain a private key (must use private to sign)" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string inf;
|
||||
if (!OSUtils::readFile(argv[3],inf)) {
|
||||
std::cerr << argv[3] << " is not readable" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length());
|
||||
std::cout << Utils::hex(signature.data,(unsigned int)signature.size()) << std::endl;
|
||||
}
|
||||
|
||||
// zerotier id-verify <secret> <file> <sig>
|
||||
else if (state.command == "id-verify") {
|
||||
if(argc != 4) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier id-verify <secret> <file> <sig>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
Identity id = getIdFromArg(argv[2]);
|
||||
if (!id) {
|
||||
std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string inf;
|
||||
if (!OSUtils::readFile(argv[3],inf)) {
|
||||
std::cerr << argv[3] << " is not readable" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string signature(Utils::unhex(argv[4]));
|
||||
if ((signature.length() > ZT_ADDRESS_LENGTH)&&(id.verify(inf.data(),(unsigned int)inf.length(),signature.data(),(unsigned int)signature.length()))) {
|
||||
std::cout << argv[3] << " signature valid" << std::endl;
|
||||
} else {
|
||||
std::cerr << argv[3] << " signature check FAILED" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier id-getpublic <secret>
|
||||
else if (state.command == "id-getpublic") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier id-getpublic <secret>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
Identity id = getIdFromArg(argv[2]);
|
||||
if (!id) {
|
||||
std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cerr << id.toString(false) << std::endl;
|
||||
}
|
||||
//
|
||||
else {
|
||||
dumpHelp();
|
||||
return -1;
|
||||
}
|
||||
if(std::find(state.args.begin(), state.args.end(), "-verbose") != state.args.end())
|
||||
std::cout << "\n\nAPI response = " << std::get<1>(res) << std::endl;
|
||||
curl_global_cleanup();
|
||||
return 0;
|
||||
}
|
|
@ -86,34 +86,27 @@ CREATE TABLE Route (
|
|||
|
||||
CREATE INDEX Route_networkId ON Route (networkId);
|
||||
|
||||
CREATE TABLE Relay (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
address char(10) NOT NULL,
|
||||
phyAddress varchar(64) NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX Relay_networkId_address ON Relay (networkId,address);
|
||||
|
||||
CREATE TABLE Rule (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
capId integer,
|
||||
ruleNo integer NOT NULL,
|
||||
nodeId char(10) REFERENCES Node(id),
|
||||
sourcePort char(10),
|
||||
destPort char(10),
|
||||
vlanId integer,
|
||||
vlanPcp integer,
|
||||
etherType integer,
|
||||
macSource char(12),
|
||||
macDest char(12),
|
||||
ipSource varchar(64),
|
||||
ipDest varchar(64),
|
||||
ipTos integer,
|
||||
ipProtocol integer,
|
||||
ipSourcePort integer,
|
||||
ipDestPort integer,
|
||||
flags integer,
|
||||
invFlags integer,
|
||||
"action" varchar(4096) NOT NULL DEFAULT('accept')
|
||||
ruleType integer NOT NULL DEFAULT(0),
|
||||
"addr" blob(16),
|
||||
"int1" integer,
|
||||
"int2" integer,
|
||||
"int3" integer,
|
||||
"int4" integer
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);
|
||||
CREATE INDEX Rule_networkId_capId ON Rule (networkId,capId);
|
||||
|
||||
CREATE TABLE MemberTC (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,
|
||||
tagId integer,
|
||||
tagValue integer,
|
||||
capId integer,
|
||||
capMaxCustodyChainLength integer NOT NULL DEFAULT(1)
|
||||
);
|
||||
|
||||
CREATE INDEX MemberTC_networkId_nodeId ON MemberTC (networkId,nodeId);
|
|
@ -50,25 +50,6 @@
|
|||
|
||||
using namespace ZeroTier;
|
||||
|
||||
class WorldMaker : public World
|
||||
{
|
||||
public:
|
||||
static inline World make(uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector<World::Root> &roots,const C25519::Pair &signWith)
|
||||
{
|
||||
WorldMaker w;
|
||||
w._id = id;
|
||||
w._ts = ts;
|
||||
w._updateSigningKey = sk;
|
||||
w._roots = roots;
|
||||
|
||||
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
|
||||
w.serialize(tmp,true);
|
||||
w._signature = C25519::sign(signWith,tmp.data(),tmp.size());
|
||||
|
||||
return w;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
std::string previous,current;
|
||||
|
@ -139,7 +120,7 @@ int main(int argc,char **argv)
|
|||
|
||||
fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu"ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts);
|
||||
|
||||
World nw = WorldMaker::make(id,ts,currentKP.pub,roots,previousKP);
|
||||
World nw = World::make(World::TYPE_PLANET,id,ts,currentKP.pub,roots,previousKP);
|
||||
|
||||
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> outtmp;
|
||||
nw.serialize(outtmp,false);
|
|
@ -1,6 +0,0 @@
|
|||
ZeroTier Newer-Spiffier Command Line Interface
|
||||
======
|
||||
|
||||
This will be the future home of our new unified CLI for ZeroTier One, controllers, and Central (my.zerotier.com etc.).
|
||||
|
||||
IT IS NOT DONE AND DOES NOT WORK EVEN A LITTLE BIT. GO AWAY.
|
335
cli/zerotier.cpp
335
cli/zerotier.cpp
|
@ -1,335 +0,0 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Note: unlike the rest of ZT's code base, this requires C++11 due to
|
||||
// the JSON library it uses and other things.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../version.h"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
#include "../ext/json/json.hpp"
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <wchar.h>
|
||||
#else
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
using namespace ZeroTier;
|
||||
|
||||
#define ZT_CLI_FLAG_VERBOSE 'v'
|
||||
#define ZT_CLI_FLAG_UNSAFE_SSL 'X'
|
||||
|
||||
struct CLIState
|
||||
{
|
||||
std::string atname;
|
||||
std::string command;
|
||||
std::vector<std::string> args;
|
||||
std::map<char,std::string> opts;
|
||||
json settings;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
static std::string trimString(const std::string &s)
|
||||
{
|
||||
unsigned long end = (unsigned long)s.length();
|
||||
while (end) {
|
||||
char c = s[end - 1];
|
||||
if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t'))
|
||||
--end;
|
||||
else break;
|
||||
}
|
||||
unsigned long start = 0;
|
||||
while (start < end) {
|
||||
char c = s[start];
|
||||
if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t'))
|
||||
++start;
|
||||
else break;
|
||||
}
|
||||
return s.substr(start,end - start);
|
||||
}
|
||||
|
||||
static inline std::string getSettingsFilePath()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
#else
|
||||
const char *home = getenv("HOME");
|
||||
if (!home)
|
||||
home = "/";
|
||||
return (std::string(home) + "/.zerotierCliSettings");
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool saveSettings(const json &settings)
|
||||
{
|
||||
std::string sfp(getSettingsFilePath().c_str());
|
||||
std::string buf(settings.dump(2));
|
||||
if (OSUtils::writeFile(sfp.c_str(),buf)) {
|
||||
OSUtils::lockDownFile(sfp.c_str(),false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void dumpHelp()
|
||||
{
|
||||
std::cout << "ZeroTier Newer-Spiffier CLI " << ZEROTIER_ONE_VERSION_MAJOR << "." << ZEROTIER_ONE_VERSION_MINOR << "." << ZEROTIER_ONE_VERSION_REVISION << std::endl;
|
||||
std::cout << "(c)2016 ZeroTier, Inc. / Licensed under the GNU GPL v3" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Configuration path: " << getSettingsFilePath() << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Usage: zerotier [-option] [@name] <command> [<command options>]" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Options:" << std::endl;
|
||||
std::cout << " -v - Verbose JSON output" << std::endl;
|
||||
std::cout << " -X - Do not check SSL certs (CAUTION!)" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "CLI Configuration Commands:" << std::endl;
|
||||
std::cout << " cli-set <setting> <value> - Set a CLI option ('cli-set help')" << std::endl;
|
||||
std::cout << " cli-ls - List configured @things" << std::endl;
|
||||
std::cout << " cli-rm @name - Remove a configured @thing" << std::endl;
|
||||
std::cout << " cli-add-zt @name <url> <auth> - Add a ZeroTier service" << std::endl;
|
||||
std::cout << " cli-add-central @name <url> <auth> - Add ZeroTier Central instance" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "ZeroTier One Service Commands:" << std::endl;
|
||||
std::cout << " ls - List currently joined networks" << std::endl;
|
||||
std::cout << " join <network> [opt=value ...] - Join a network" << std::endl;
|
||||
std::cout << " leave <network> - Leave a network" << std::endl;
|
||||
std::cout << " peers - List ZeroTier VL1 peers" << std::endl;
|
||||
std::cout << " show [<network/peer address>] - Get info about self or object" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Network Controller Commands:" << std::endl;
|
||||
std::cout << " net-create - Create a new network" << std::endl;
|
||||
std::cout << " net-rm <network> - Delete a network (CAUTION!)" << std::endl;
|
||||
std::cout << " net-ls - List administered networks" << std::endl;
|
||||
std::cout << " net-members <network> - List members of a network" << std::endl;
|
||||
std::cout << " net-show <network> [<address>] - Get network or member info" << std::endl;
|
||||
std::cout << " net-auth <network> <address> - Authorize a member" << std::endl;
|
||||
std::cout << " net-set <path> <value> - See 'net-set help'" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Identity Commands:" << std::endl;
|
||||
std::cout << " id-generate [<vanity prefix>] - Generate a ZeroTier identity" << std::endl;
|
||||
std::cout << " id-validate <identity> - Locally validate an identity" << std::endl;
|
||||
std::cout << " id-sign <identity> <file> - Sign a file" << std::endl;
|
||||
std::cout << " id-verify <secret> <file> <sig> - Verify a file's signature" << std::endl;
|
||||
std::cout << " id-getpublic <secret> - Get full identity's public portion" << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
static size_t _curlStringAppendCallback(void *contents,size_t size,size_t nmemb,void *stdstring)
|
||||
{
|
||||
size_t totalSize = size * nmemb;
|
||||
reinterpret_cast<std::string *>(stdstring)->append((const char *)contents,totalSize);
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
static std::tuple<int,std::string> GET(const CLIState &state,const std::map<std::string,std::string> &headers,const std::string &url)
|
||||
{
|
||||
std::string body;
|
||||
char errbuf[CURL_ERROR_SIZE];
|
||||
char urlbuf[4096];
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
std::cerr << "FATAL: curl_easy_init() failed" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curlStringAppendCallback);
|
||||
curl_easy_setopt(curl,CURLOPT_WRITEDATA,(void *)&body);
|
||||
curl_easy_setopt(curl,CURLOPT_USERAGENT,"ZeroTier-CLI");
|
||||
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(state.opts.count(ZT_CLI_FLAG_UNSAFE_SSL) > 0) ? 0L : 1L);
|
||||
curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errbuf);
|
||||
curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,0L);
|
||||
|
||||
Utils::scopy(urlbuf,sizeof(urlbuf),url.c_str());
|
||||
curl_easy_setopt(curl,CURLOPT_URL,urlbuf);
|
||||
|
||||
struct curl_slist *hdrs = (struct curl_slist *)0;
|
||||
for(std::map<std::string,std::string>::const_iterator i(headers.begin());i!=headers.end();++i) {
|
||||
std::string htmp(i->first);
|
||||
htmp.append(": ");
|
||||
htmp.append(i->second);
|
||||
hdrs = curl_slist_append(hdrs,htmp.c_str());
|
||||
}
|
||||
if (hdrs)
|
||||
curl_easy_setopt(curl,CURLOPT_HTTPHEADER,hdrs);
|
||||
|
||||
memset(errbuf,0,sizeof(errbuf));
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
errbuf[CURL_ERROR_SIZE-1] = (char)0; // sanity check
|
||||
|
||||
if (res != CURLE_OK)
|
||||
return std::make_tuple(-1,std::string(errbuf));
|
||||
|
||||
int rc = (int)curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE);
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
if (hdrs)
|
||||
curl_slist_free_all(hdrs);
|
||||
|
||||
return std::make_tuple(rc,body);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
int _tmain(int argc, _TCHAR* argv[])
|
||||
#else
|
||||
int main(int argc,char **argv)
|
||||
#endif
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
{
|
||||
WSADATA wsaData;
|
||||
WSAStartup(MAKEWORD(2,2),&wsaData);
|
||||
}
|
||||
#endif
|
||||
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
|
||||
CLIState state;
|
||||
|
||||
for(int i=1;i<argc;++i) {
|
||||
if ((i == 1)&&(argv[i][0] == '@')) {
|
||||
state.atname = argv[i];
|
||||
} else if (state.command.length() == 0) {
|
||||
if (argv[i][0] == '-') {
|
||||
if (!argv[i][1]) {
|
||||
dumpHelp();
|
||||
return -1;
|
||||
} else if (argv[i][2]) {
|
||||
state.opts[argv[i][1]] = argv[i] + 2;
|
||||
} else {
|
||||
state.opts[argv[i][1]] = "";
|
||||
}
|
||||
} else {
|
||||
state.command = argv[i];
|
||||
}
|
||||
} else {
|
||||
state.args.push_back(std::string(argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::string buf;
|
||||
if (OSUtils::readFile(getSettingsFilePath().c_str(),buf))
|
||||
state.settings = json::parse(buf);
|
||||
|
||||
if (state.settings.empty()) {
|
||||
// Default settings
|
||||
state.settings = {
|
||||
{ "configVersion", 1 },
|
||||
{ "things", {
|
||||
{ "my.zerotier.com", {
|
||||
{ "type", "central" },
|
||||
{ "url", "https://my.zerotier.com/" },
|
||||
{ "auth", "" }
|
||||
}},
|
||||
{ "local", {
|
||||
{ "type", "one" },
|
||||
{ "url", "" },
|
||||
{ "auth", "" }
|
||||
}}
|
||||
}},
|
||||
{ "defaultController", "@my.zerotier.com" },
|
||||
{ "defaultOne", "@local" }
|
||||
};
|
||||
|
||||
std::string oneHome(OSUtils::platformDefaultHomePath());
|
||||
std::string authToken,portStr;
|
||||
bool initSuccess = false;
|
||||
if (OSUtils::readFile((oneHome + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),authToken)&&OSUtils::readFile((oneHome + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),portStr)) {
|
||||
portStr = trimString(portStr);
|
||||
authToken = trimString(authToken);
|
||||
int port = Utils::strToInt(portStr.c_str());
|
||||
if (((port > 0)&&(port < 65536))&&(authToken.length() > 0)) {
|
||||
state.settings["things"]["local"]["url"] = (std::string("http://127.0.0.1:") + portStr + "/");
|
||||
state.settings["things"]["local"]["auth"] = authToken;
|
||||
initSuccess = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!saveSettings(state.settings)) {
|
||||
std::cerr << "FATAL: unable to write " << getSettingsFilePath() << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (initSuccess) {
|
||||
std::cerr << "INFO: initialized new config at " << getSettingsFilePath() << std::endl;
|
||||
} else {
|
||||
std::cerr << "INFO: initialized new config at " << getSettingsFilePath() << " but could not auto-init local ZeroTier One service config from " << oneHome << " -- you will need to set local service URL and port manually if you want to control a local instance of ZeroTier One. (This happens if you are not root/administrator.)" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((state.command.length() == 0)||(state.command == "help")) {
|
||||
dumpHelp();
|
||||
return -1;
|
||||
} else if (state.command == "cli-set") {
|
||||
} else if (state.command == "cli-ls") {
|
||||
} else if (state.command == "cli-rm") {
|
||||
} else if (state.command == "cli-add-zt") {
|
||||
} else if (state.command == "cli-add-central") {
|
||||
} else if (state.command == "ls") {
|
||||
} else if (state.command == "join") {
|
||||
} else if (state.command == "leave") {
|
||||
} else if (state.command == "peers") {
|
||||
} else if (state.command == "show") {
|
||||
} else if (state.command == "net-create") {
|
||||
} else if (state.command == "net-rm") {
|
||||
} else if (state.command == "net-ls") {
|
||||
} else if (state.command == "net-members") {
|
||||
} else if (state.command == "net-show") {
|
||||
} else if (state.command == "net-auth") {
|
||||
} else if (state.command == "net-set") {
|
||||
} else if (state.command == "id-generate") {
|
||||
} else if (state.command == "id-validate") {
|
||||
} else if (state.command == "id-sign") {
|
||||
} else if (state.command == "id-verify") {
|
||||
} else if (state.command == "id-getpublic") {
|
||||
} else {
|
||||
dumpHelp();
|
||||
return -1;
|
||||
}
|
||||
|
||||
curl_global_cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
1854
controller/EmbeddedNetworkController.cpp
Normal file
1854
controller/EmbeddedNetworkController.cpp
Normal file
File diff suppressed because it is too large
Load diff
210
controller/EmbeddedNetworkController.hpp
Normal file
210
controller/EmbeddedNetworkController.hpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_SQLITENETWORKCONTROLLER_HPP
|
||||
#define ZT_SQLITENETWORKCONTROLLER_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <list>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
|
||||
#include "../node/NetworkController.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/Address.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
#include "../osdep/Thread.hpp"
|
||||
#include "../osdep/BlockingQueue.hpp"
|
||||
|
||||
#include "../ext/json/json.hpp"
|
||||
|
||||
#include "JSONDB.hpp"
|
||||
|
||||
// Number of background threads to start -- not actually started until needed
|
||||
#define ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT 4
|
||||
|
||||
// TTL for circuit tests
|
||||
#define ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION 120000
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class Node;
|
||||
|
||||
class EmbeddedNetworkController : public NetworkController
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param node Parent node
|
||||
* @param dbPath Path to store data
|
||||
*/
|
||||
EmbeddedNetworkController(Node *node,const char *dbPath);
|
||||
virtual ~EmbeddedNetworkController();
|
||||
|
||||
virtual void init(const Identity &signingId,Sender *sender);
|
||||
|
||||
virtual void request(
|
||||
uint64_t nwid,
|
||||
const InetAddress &fromAddr,
|
||||
uint64_t requestPacketId,
|
||||
const Identity &identity,
|
||||
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
|
||||
|
||||
unsigned int handleControlPlaneHttpGET(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
unsigned int handleControlPlaneHttpPOST(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
unsigned int handleControlPlaneHttpDELETE(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
|
||||
void threadMain()
|
||||
throw();
|
||||
|
||||
private:
|
||||
struct _RQEntry
|
||||
{
|
||||
uint64_t nwid;
|
||||
uint64_t requestPacketId;
|
||||
InetAddress fromAddr;
|
||||
Identity identity;
|
||||
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData;
|
||||
};
|
||||
|
||||
// Gathers a bunch of statistics about members of a network, IP assignments, etc. that we need in various places
|
||||
struct _NetworkMemberInfo
|
||||
{
|
||||
_NetworkMemberInfo() : authorizedMemberCount(0),activeMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {}
|
||||
std::set<Address> activeBridges;
|
||||
std::set<InetAddress> allocatedIps;
|
||||
unsigned long authorizedMemberCount;
|
||||
unsigned long activeMemberCount;
|
||||
unsigned long totalMemberCount;
|
||||
uint64_t mostRecentDeauthTime;
|
||||
uint64_t nmiTimestamp; // time this NMI structure was computed
|
||||
};
|
||||
|
||||
static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report);
|
||||
void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
|
||||
void _getNetworkMemberInfo(uint64_t now,uint64_t nwid,_NetworkMemberInfo &nmi);
|
||||
inline void _clearNetworkMemberInfoCache(const uint64_t nwid) { Mutex::Lock _l(_nmiCache_m); _nmiCache.erase(nwid); }
|
||||
void _pushMemberUpdate(uint64_t now,uint64_t nwid,const nlohmann::json &member);
|
||||
|
||||
// These init objects with default and static/informational fields
|
||||
inline void _initMember(nlohmann::json &member)
|
||||
{
|
||||
if (!member.count("authorized")) member["authorized"] = false;
|
||||
if (!member.count("authHistory")) member["authHistory"] = nlohmann::json::array();
|
||||
if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array();
|
||||
if (!member.count("recentLog")) member["recentLog"] = nlohmann::json::array();
|
||||
if (!member.count("activeBridge")) member["activeBridge"] = false;
|
||||
if (!member.count("tags")) member["tags"] = nlohmann::json::array();
|
||||
if (!member.count("capabilities")) member["capabilities"] = nlohmann::json::array();
|
||||
if (!member.count("creationTime")) member["creationTime"] = OSUtils::now();
|
||||
if (!member.count("noAutoAssignIps")) member["noAutoAssignIps"] = false;
|
||||
if (!member.count("revision")) member["revision"] = 0ULL;
|
||||
if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL;
|
||||
if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL;
|
||||
member["objtype"] = "member";
|
||||
}
|
||||
inline void _initNetwork(nlohmann::json &network)
|
||||
{
|
||||
if (!network.count("private")) network["private"] = true;
|
||||
if (!network.count("creationTime")) network["creationTime"] = OSUtils::now();
|
||||
if (!network.count("name")) network["name"] = "";
|
||||
if (!network.count("multicastLimit")) network["multicastLimit"] = (uint64_t)32;
|
||||
if (!network.count("enableBroadcast")) network["enableBroadcast"] = true;
|
||||
if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}};
|
||||
if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}};
|
||||
if (!network.count("authTokens")) network["authTokens"] = nlohmann::json::array();
|
||||
if (!network.count("capabilities")) network["capabilities"] = nlohmann::json::array();
|
||||
if (!network.count("tags")) network["tags"] = nlohmann::json::array();
|
||||
if (!network.count("routes")) network["routes"] = nlohmann::json::array();
|
||||
if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
|
||||
if (!network.count("rules")) {
|
||||
// If unspecified, rules are set to allow anything and behave like a flat L2 segment
|
||||
network["rules"] = {{
|
||||
{ "not",false },
|
||||
{ "or", false },
|
||||
{ "type","ACTION_ACCEPT" }
|
||||
}};
|
||||
}
|
||||
network["objtype"] = "network";
|
||||
}
|
||||
inline void _addNetworkNonPersistedFields(nlohmann::json &network,uint64_t now,const _NetworkMemberInfo &nmi)
|
||||
{
|
||||
network["clock"] = now;
|
||||
network["authorizedMemberCount"] = nmi.authorizedMemberCount;
|
||||
network["activeMemberCount"] = nmi.activeMemberCount;
|
||||
network["totalMemberCount"] = nmi.totalMemberCount;
|
||||
}
|
||||
inline void _addMemberNonPersistedFields(nlohmann::json &member,uint64_t now)
|
||||
{
|
||||
member["clock"] = now;
|
||||
}
|
||||
|
||||
const uint64_t _startTime;
|
||||
|
||||
BlockingQueue<_RQEntry *> _queue;
|
||||
Thread _threads[ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT];
|
||||
bool _threadsStarted;
|
||||
Mutex _threads_m;
|
||||
|
||||
std::map<uint64_t,_NetworkMemberInfo> _nmiCache;
|
||||
Mutex _nmiCache_m;
|
||||
|
||||
JSONDB _db;
|
||||
Mutex _db_m;
|
||||
|
||||
Node *const _node;
|
||||
std::string _path;
|
||||
|
||||
NetworkController::Sender *_sender;
|
||||
Identity _signingId;
|
||||
|
||||
std::list< ZT_CircuitTest > _tests;
|
||||
Mutex _tests_m;
|
||||
|
||||
std::map< std::pair<uint64_t,uint64_t>,uint64_t > _lastRequestTime; // last request time by <address,networkId>
|
||||
Mutex _lastRequestTime_m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
219
controller/JSONDB.cpp
Normal file
219
controller/JSONDB.cpp
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "JSONDB.hpp"
|
||||
|
||||
#define ZT_JSONDB_HTTP_TIMEOUT 60000
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
static const nlohmann::json _EMPTY_JSON(nlohmann::json::object());
|
||||
static const std::map<std::string,std::string> _ZT_JSONDB_GET_HEADERS;
|
||||
|
||||
JSONDB::JSONDB(const std::string &basePath) :
|
||||
_basePath(basePath),
|
||||
_ready(false)
|
||||
{
|
||||
if ((_basePath.length() > 7)&&(_basePath.substr(0,7) == "http://")) {
|
||||
// TODO: this doesn't yet support IPv6 since bracketed address notiation isn't supported.
|
||||
// Typically it's used with 127.0.0.1 anyway.
|
||||
std::string hn = _basePath.substr(7);
|
||||
std::size_t hnend = hn.find_first_of('/');
|
||||
if (hnend != std::string::npos)
|
||||
hn = hn.substr(0,hnend);
|
||||
std::size_t hnsep = hn.find_last_of(':');
|
||||
if (hnsep != std::string::npos)
|
||||
hn[hnsep] = '/';
|
||||
_httpAddr.fromString(hn);
|
||||
if (hnend != std::string::npos)
|
||||
_basePath = _basePath.substr(7 + hnend);
|
||||
if (_basePath.length() == 0)
|
||||
_basePath = "/";
|
||||
if (_basePath[0] != '/')
|
||||
_basePath = std::string("/") + _basePath;
|
||||
} else {
|
||||
OSUtils::mkdir(_basePath.c_str());
|
||||
OSUtils::lockDownFile(_basePath.c_str(),true); // networks might contain auth tokens, etc., so restrict directory permissions
|
||||
}
|
||||
_ready = _reload(_basePath,std::string());
|
||||
}
|
||||
|
||||
bool JSONDB::writeRaw(const std::string &n,const std::string &obj)
|
||||
{
|
||||
if (!_isValidObjectName(n))
|
||||
return false;
|
||||
if (_httpAddr) {
|
||||
std::map<std::string,std::string> headers;
|
||||
std::string body;
|
||||
std::map<std::string,std::string> reqHeaders;
|
||||
char tmp[64];
|
||||
Utils::snprintf(tmp,sizeof(tmp),"%lu",(unsigned long)obj.length());
|
||||
reqHeaders["Content-Length"] = tmp;
|
||||
reqHeaders["Content-Type"] = "application/json";
|
||||
const unsigned int sc = Http::PUT(1048576,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),(_basePath+"/"+n).c_str(),reqHeaders,obj.data(),(unsigned long)obj.length(),headers,body);
|
||||
return (sc == 200);
|
||||
} else {
|
||||
const std::string path(_genPath(n,true));
|
||||
if (!path.length())
|
||||
return false;
|
||||
return OSUtils::writeFile(path.c_str(),obj);
|
||||
}
|
||||
}
|
||||
|
||||
bool JSONDB::put(const std::string &n,const nlohmann::json &obj)
|
||||
{
|
||||
const bool r = writeRaw(n,OSUtils::jsonDump(obj));
|
||||
_db[n].obj = obj;
|
||||
return r;
|
||||
}
|
||||
|
||||
const nlohmann::json &JSONDB::get(const std::string &n)
|
||||
{
|
||||
while (!_ready) {
|
||||
Thread::sleep(250);
|
||||
_ready = _reload(_basePath,std::string());
|
||||
}
|
||||
|
||||
if (!_isValidObjectName(n))
|
||||
return _EMPTY_JSON;
|
||||
std::map<std::string,_E>::iterator e(_db.find(n));
|
||||
if (e != _db.end())
|
||||
return e->second.obj;
|
||||
|
||||
std::string buf;
|
||||
if (_httpAddr) {
|
||||
std::map<std::string,std::string> headers;
|
||||
const unsigned int sc = Http::GET(1048576,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,buf);
|
||||
if (sc != 200)
|
||||
return _EMPTY_JSON;
|
||||
} else {
|
||||
const std::string path(_genPath(n,false));
|
||||
if (!path.length())
|
||||
return _EMPTY_JSON;
|
||||
if (!OSUtils::readFile(path.c_str(),buf))
|
||||
return _EMPTY_JSON;
|
||||
}
|
||||
|
||||
try {
|
||||
_E &e2 = _db[n];
|
||||
e2.obj = OSUtils::jsonParse(buf);
|
||||
return e2.obj;
|
||||
} catch ( ... ) {
|
||||
_db.erase(n);
|
||||
return _EMPTY_JSON;
|
||||
}
|
||||
}
|
||||
|
||||
void JSONDB::erase(const std::string &n)
|
||||
{
|
||||
if (!_isValidObjectName(n))
|
||||
return;
|
||||
|
||||
if (_httpAddr) {
|
||||
std::string body;
|
||||
std::map<std::string,std::string> headers;
|
||||
Http::DEL(1048576,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body);
|
||||
} else {
|
||||
std::string path(_genPath(n,true));
|
||||
if (!path.length())
|
||||
return;
|
||||
OSUtils::rm(path.c_str());
|
||||
}
|
||||
|
||||
_db.erase(n);
|
||||
}
|
||||
|
||||
bool JSONDB::_reload(const std::string &p,const std::string &b)
|
||||
{
|
||||
if (_httpAddr) {
|
||||
std::string body;
|
||||
std::map<std::string,std::string> headers;
|
||||
const unsigned int sc = Http::GET(2147483647,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),_basePath.c_str(),_ZT_JSONDB_GET_HEADERS,headers,body);
|
||||
if (sc == 200) {
|
||||
try {
|
||||
nlohmann::json dbImg(OSUtils::jsonParse(body));
|
||||
std::string tmp;
|
||||
if (dbImg.is_object()) {
|
||||
for(nlohmann::json::iterator i(dbImg.begin());i!=dbImg.end();++i) {
|
||||
if (i.value().is_object()) {
|
||||
tmp = i.key();
|
||||
_db[tmp].obj = i.value();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch ( ... ) {} // invalid JSON, so maybe incomplete request
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
std::vector<std::string> dl(OSUtils::listDirectory(p.c_str(),true));
|
||||
for(std::vector<std::string>::const_iterator di(dl.begin());di!=dl.end();++di) {
|
||||
if ((di->length() > 5)&&(di->substr(di->length() - 5) == ".json")) {
|
||||
this->get(b + di->substr(0,di->length() - 5));
|
||||
} else {
|
||||
this->_reload((p + ZT_PATH_SEPARATOR + *di),(b + *di + ZT_PATH_SEPARATOR));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool JSONDB::_isValidObjectName(const std::string &n)
|
||||
{
|
||||
if (n.length() == 0)
|
||||
return false;
|
||||
const char *p = n.c_str();
|
||||
char c;
|
||||
// For security reasons we should not allow dots, backslashes, or other path characters or potential path characters.
|
||||
while ((c = *(p++))) {
|
||||
if (!( ((c >= 'a')&&(c <= 'z')) || ((c >= 'A')&&(c <= 'Z')) || ((c >= '0')&&(c <= '9')) || (c == '/') || (c == '_') || (c == '~') || (c == '-') ))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string JSONDB::_genPath(const std::string &n,bool create)
|
||||
{
|
||||
std::vector<std::string> pt(OSUtils::split(n.c_str(),"/","",""));
|
||||
if (pt.size() == 0)
|
||||
return std::string();
|
||||
|
||||
char sep;
|
||||
if (_httpAddr) {
|
||||
sep = '/';
|
||||
create = false;
|
||||
} else {
|
||||
sep = ZT_PATH_SEPARATOR;
|
||||
}
|
||||
|
||||
std::string p(_basePath);
|
||||
if (create) OSUtils::mkdir(p.c_str());
|
||||
for(unsigned long i=0,j=(unsigned long)(pt.size()-1);i<j;++i) {
|
||||
p.push_back(sep);
|
||||
p.append(pt[i]);
|
||||
if (create) OSUtils::mkdir(p.c_str());
|
||||
}
|
||||
|
||||
p.push_back(sep);
|
||||
p.append(pt[pt.size()-1]);
|
||||
p.append(".json");
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
116
controller/JSONDB.hpp
Normal file
116
controller/JSONDB.hpp
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_JSONDB_HPP
|
||||
#define ZT_JSONDB_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "../ext/json/json.hpp"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
#include "../osdep/Http.hpp"
|
||||
#include "../osdep/Thread.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Hierarchical JSON store that persists into the filesystem or via HTTP
|
||||
*/
|
||||
class JSONDB
|
||||
{
|
||||
public:
|
||||
JSONDB(const std::string &basePath);
|
||||
|
||||
bool writeRaw(const std::string &n,const std::string &obj);
|
||||
|
||||
bool put(const std::string &n,const nlohmann::json &obj);
|
||||
|
||||
inline bool put(const std::string &n1,const std::string &n2,const nlohmann::json &obj) { return this->put((n1 + "/" + n2),obj); }
|
||||
inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3),obj); }
|
||||
inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3 + "/" + n4),obj); }
|
||||
inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5),obj); }
|
||||
|
||||
const nlohmann::json &get(const std::string &n);
|
||||
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2) { return this->get((n1 + "/" + n2)); }
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3) { return this->get((n1 + "/" + n2 + "/" + n3)); }
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4) { return this->get((n1 + "/" + n2 + "/" + n3 + "/" + n4)); }
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5) { return this->get((n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5)); }
|
||||
|
||||
void erase(const std::string &n);
|
||||
|
||||
inline void erase(const std::string &n1,const std::string &n2) { this->erase(n1 + "/" + n2); }
|
||||
inline void erase(const std::string &n1,const std::string &n2,const std::string &n3) { this->erase(n1 + "/" + n2 + "/" + n3); }
|
||||
inline void erase(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4) { this->erase(n1 + "/" + n2 + "/" + n3 + "/" + n4); }
|
||||
inline void erase(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5) { this->erase(n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5); }
|
||||
|
||||
template<typename F>
|
||||
inline void filter(const std::string &prefix,F func)
|
||||
{
|
||||
while (!_ready) {
|
||||
Thread::sleep(250);
|
||||
_ready = _reload(_basePath,std::string());
|
||||
}
|
||||
|
||||
for(std::map<std::string,_E>::iterator i(_db.lower_bound(prefix));i!=_db.end();) {
|
||||
if ((i->first.length() >= prefix.length())&&(!memcmp(i->first.data(),prefix.data(),prefix.length()))) {
|
||||
if (!func(i->first,get(i->first))) {
|
||||
std::map<std::string,_E>::iterator i2(i); ++i2;
|
||||
this->erase(i->first);
|
||||
i = i2;
|
||||
} else ++i;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator==(const JSONDB &db) const { return ((_basePath == db._basePath)&&(_db == db._db)); }
|
||||
inline bool operator!=(const JSONDB &db) const { return (!(*this == db)); }
|
||||
|
||||
private:
|
||||
bool _reload(const std::string &p,const std::string &b);
|
||||
bool _isValidObjectName(const std::string &n);
|
||||
std::string _genPath(const std::string &n,bool create);
|
||||
|
||||
struct _E
|
||||
{
|
||||
nlohmann::json obj;
|
||||
inline bool operator==(const _E &e) const { return (obj == e.obj); }
|
||||
inline bool operator!=(const _E &e) const { return (obj != e.obj); }
|
||||
};
|
||||
|
||||
InetAddress _httpAddr;
|
||||
std::string _basePath;
|
||||
std::map<std::string,_E> _db;
|
||||
volatile bool _ready;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
|
@ -1,66 +1,43 @@
|
|||
Network Controller Microservice
|
||||
======
|
||||
|
||||
ZeroTier's 16-digit network IDs are really just a concatenation of the 10-digit ZeroTier address of a network controller followed by a 6-digit (24-bit) network number on that controller. Fans of software defined networking will recognize this as a variation of the familiar [separation of data plane and control plane](http://sdntutorials.com/difference-between-control-plane-and-data-plane/) SDN design pattern.
|
||||
Every ZeroTier virtual network has a *network controller*. This is our reference implementation and is the same one we use to power our own hosted services at [my.zerotier.com](https://my.zerotier.com/). Network controllers act as configuration servers and certificate authorities for the members of networks. Controllers are located on the network by simply parsing out the first 10 digits of a network's 16-digit network ID: these are the address of the controller.
|
||||
|
||||
This code implements the *node/NetworkController.hpp* interface and provides a SQLite3-backed network controller microservice. Including it in the build allows ZeroTier One to act as a controller and create/manage networks.
|
||||
As of ZeroTier One version 1.2.0 this code is included in normal builds for desktop, laptop, and server (Linux, etc.) targets, allowing any device to create virtual networks without having to be rebuilt from source with special flags to enable this feature. While this does offer a convenient way to create ad-hoc networks or experiment, we recommend running a dedicated controller somewhere secure and stable for any "serious" use case.
|
||||
|
||||
This is the same code we use to run [my.zerotier.com](https://my.zerotier.com/), which is a web UI and API that runs in front of a pool of controllers.
|
||||
Controller data is stored in JSON format under `controller.d` in the ZeroTier working directory. It can be copied, rsync'd, placed in `git`, etc. The files under `controller.d` should not be modified in place while the controller is running or data loss may result, and if they are edited directly take care not to save corrupt JSON since that can also lead to data loss when the controller is restarted. Going through the API is strongly preferred to directly modifying these files.
|
||||
|
||||
### Building
|
||||
### Upgrading from Older (1.1.14 or earlier) Versions
|
||||
|
||||
On Linux, Mac, or BSD you can create a controller-enabled build with:
|
||||
Older versions of this code used a SQLite database instead of in-filesystem JSON. A migration utility called `migrate-sqlite` is included here and *must* be used to migrate this data to the new format. If the controller is started with an old `controller.db` in its working directory it will terminate after printing an error to *stderr*. This is done to prevent "surprises" for those running DIY controllers using the old code.
|
||||
|
||||
make ZT_ENABLE_NETWORK_CONTROLLER=1
|
||||
The migration tool is written in nodeJS and can be used like this:
|
||||
|
||||
You will need the development headers and libraries for SQLite3 installed.
|
||||
cd migrate-sqlite
|
||||
npm install
|
||||
node migrate.js </path/to/controller.db> </path/to/controller.d>
|
||||
|
||||
### Running
|
||||
Very old versions of nodeJS may have issues. We tested it with version 7.
|
||||
|
||||
After building and installing (`make install`) a controller-enabled build of ZeroTier One, start it and try:
|
||||
### Scalability and Reliability
|
||||
|
||||
sudo zerotier-cli /controller
|
||||
Controllers can in theory host up to 2^24 networks and serve many millions of devices (or more), but we recommend spreading large numbers of networks across many controllers for load balancing and fault tolerance reasons. Since the controller uses the filesystem as its data store we recommend fast filesystems and fast SSD drives for heavily loaded controllers.
|
||||
|
||||
You should see something like:
|
||||
|
||||
{
|
||||
"controller": true,
|
||||
"apiVersion": 2,
|
||||
"clock": 1468002975497,
|
||||
"instanceId": "8ab354604debe1da27ee627c9ef94a48"
|
||||
}
|
||||
|
||||
When started, a controller-enabled build of ZeroTier One will automatically create and initialize a `controller.db` file in its home folder. This is where all the controller's data and persistent state lives. If you're upgrading an old controller it will upgrade its database schema automatically on first launch. Make a backup of the old controller's database first since you can't go backward.
|
||||
|
||||
Controllers periodically make backups of their database as `controller.db.backup`. This is done so that this file can be more easily copied/rsync'ed to other systems without worrying about corruption. SQLite3 supports multiple processes accessing the same database file, so `sqlite3 /path/to/controller.db .dump` also works but can be slow on a busy controller.
|
||||
|
||||
Controllers can in theory host up to 2^24 networks and serve many millions of devices (or more), but we recommend running multiple controllers for a lot of networks to spread load and be more fault tolerant.
|
||||
Since ZeroTier nodes are mobile and do not need static IPs, implementing high availability fail-over for controllers is easy. Just replicate their working directories from master to backup and have something automatically fire up the backup if the master goes down. Many modern orchestration tools have built-in support for this. It would also be possible in theory to run controllers on a replicated or distributed filesystem, but we haven't tested this yet.
|
||||
|
||||
### Dockerizing Controllers
|
||||
|
||||
ZeroTier network controllers can easily be run in Docker or other container systems. Since containers do not need to actually join networks, extra privilege options like "--device=/dev/net/tun --privileged" are not needed. You'll just need to map the local JSON API port of the running controller and allow it to access the Internet (over UDP/9993 at a minimum) so things can reach and query it.
|
||||
|
||||
### Implementing High Availability Fail-Over
|
||||
|
||||
ZeroTier network controllers are not single points of failure for networks-- in the sense that if a controller goes down *existing* members of a network can continue to communicate. But new members (or those that have been offline for a while) can't join, existing members can't be de-authorized, and other changes to the network's configuration can't be made. This means that short "glitches" in controller availability are not a major problem but long periods of unavailability can be.
|
||||
|
||||
Because controllers are just regular ZeroTier nodes and controller queries are in-band, controllers can trivially be moved without worrying about changes to underlying physical IPs. This makes high-availability fail-over very easy to implement.
|
||||
|
||||
Just set up two cloud hosts, preferably in different data centers (e.g. two different AWS regions or Digital Ocean SF and NYC). Now set up the hot spare controller to constantly mirror `controller.db.backup` from its active sibling.
|
||||
|
||||
If the active controller goes down, rename `controller.db.backup` to `controller.db` on the hot spare and start the ZeroTier One service there. The spare will take over and has now become the active controller. If the original active node comes back, it should take on the role of spare and should not start its service. Instead it should start mirroring the active controller's backup and wait until it is needed.
|
||||
|
||||
The details of actually implementing this kind of HA fail-over on Linux or other OSes are beyond the scope of these docs and there are many ways to do it. Docker orchestration tools like Kubernetes can also be used to accomplish this if you've dockerized your controller.
|
||||
|
||||
### Network Controller API
|
||||
|
||||
The controller API is hosted via the same JSON API endpoint that ZeroTier One uses for local control (usually at 127.0.0.1 port 9993). All controller options are routed under the `/controller` base path.
|
||||
|
||||
The controller microservice does not implement any fine-grained access control (authentication is via authtoken.secret just like the regular JSON API) or other complex mangement features. It just takes network and network member configurations and reponds to controller queries. We have an enterprise product called [ZeroTier Central](https://my.zerotier.com/) that we host as a service (and that companies can license to self-host) that does this.
|
||||
|
||||
All working network IDs on a controller must begin with the controller's ZeroTier address. The API will *allow* "foreign" networks to be added but the controller will have no way of doing anything with them.
|
||||
All working network IDs on a controller must begin with the controller's ZeroTier address. The API will *allow* "foreign" networks to be added but the controller will have no way of doing anything with them since nobody will know to query it. (In the future we might support secondaries, which would make this relevant.)
|
||||
|
||||
Also note that the API is *very* sensitive about types. Integers must be integers and strings strings, etc. Incorrectly typed and unrecognized fields are just ignored.
|
||||
The JSON API is *very* sensitive about types. Integers must be integers and strings strings, etc. Incorrectly typed and unrecognized fields may result in ignored fields or a 400 (bad request) error.
|
||||
|
||||
#### `/controller`
|
||||
|
||||
|
@ -71,11 +48,8 @@ Also note that the API is *very* sensitive about types. Integers must be integer
|
|||
| Field | Type | Description | Writable |
|
||||
| ------------------ | ----------- | ------------------------------------------------- | -------- |
|
||||
| controller | boolean | Always 'true' | no |
|
||||
| apiVersion | integer | Controller API version, currently 2 | no |
|
||||
| apiVersion | integer | Controller API version, currently 3 | no |
|
||||
| clock | integer | Current clock on controller, ms since epoch | no |
|
||||
| instanceId | string | A random ID generated on first controller DB init | no |
|
||||
|
||||
The instance ID can be used to check whether a controller's database has been reset or otherwise switched.
|
||||
|
||||
#### `/controller/network`
|
||||
|
||||
|
@ -97,52 +71,50 @@ When POSTing new networks take care that their IDs are not in use, otherwise you
|
|||
|
||||
| Field | Type | Description | Writable |
|
||||
| --------------------- | ------------- | ------------------------------------------------- | -------- |
|
||||
| nwid | string | 16-digit network ID | no |
|
||||
| controllerInstanceId | string | Controller database instance ID | no |
|
||||
| id | string | 16-digit network ID | no |
|
||||
| nwid | string | 16-digit network ID (old, but still around) | no |
|
||||
| clock | integer | Current clock, ms since epoch | no |
|
||||
| name | string | A short name for this network | YES |
|
||||
| private | boolean | Is access control enabled? | YES |
|
||||
| enableBroadcast | boolean | Ethernet ff:ff:ff:ff:ff:ff allowed? | YES |
|
||||
| allowPassiveBridging | boolean | Allow any member to bridge (very experimental) | YES |
|
||||
| v4AssignMode | string | If 'zt', auto-assign IPv4 from pool(s) | YES |
|
||||
| v6AssignMode | string | IPv6 address auto-assign modes; see below | YES |
|
||||
| v4AssignMode | object | IPv4 management and assign options (see below) | YES |
|
||||
| v6AssignMode | object | IPv6 management and assign options (see below) | YES |
|
||||
| multicastLimit | integer | Maximum recipients for a multicast packet | YES |
|
||||
| creationTime | integer | Time network was first created | no |
|
||||
| revision | integer | Network config revision counter | no |
|
||||
| memberRevisionCounter | integer | Network member revision counter | no |
|
||||
| authorizedMemberCount | integer | Number of authorized members (for private nets) | no |
|
||||
| relays | array[object] | Alternative relays; see below | YES |
|
||||
| activeMemberCount | integer | Number of members that appear to be online | no |
|
||||
| totalMemberCount | integer | Total known members of this network | no |
|
||||
| routes | array[object] | Managed IPv4 and IPv6 routes; see below | YES |
|
||||
| ipAssignmentPools | array[object] | IP auto-assign ranges; see below | YES |
|
||||
| rules | array[object] | Traffic rules; see below | YES |
|
||||
|
||||
(The `ipLocalRoutes` field appeared in older versions but is no longer present. Routes will now show up in `routes`.)
|
||||
Recent changes:
|
||||
|
||||
Two important things to know about networks:
|
||||
* The `ipLocalRoutes` field appeared in older versions but is no longer present. Routes will now show up in `routes`.
|
||||
* The `relays` field is gone since network preferred relays are gone. This capability is replaced by VL1 level federation ("federated roots").
|
||||
|
||||
- Networks without rules won't carry any traffic. See below for an example with rules to permit IPv4 and IPv6.
|
||||
- Managed IP address assignments and IP assignment pools that do not fall within a route configured in `routes` are ignored and won't be used or sent to members.
|
||||
- The default for `private` is `true` and this is probably what you want. Turning `private` off means *anyone* can join your network with only its 16-digit network ID. It's also impossible to de-authorize a member as these networks don't issue or enforce certificates. Such "party line" networks are used for decentralized app backplanes, gaming, and testing but are not common in ordinary use.
|
||||
Other important points:
|
||||
|
||||
**IPv6 Auto-Assign Modes:**
|
||||
* Networks without rules won't carry any traffic. If you don't specify any on network creation an "accept anything" rule set will automatically be added.
|
||||
* Managed IP address assignments and IP assignment pools that do not fall within a route configured in `routes` are ignored and won't be used or sent to members.
|
||||
* The default for `private` is `true` and this is probably what you want. Turning `private` off means *anyone* can join your network with only its 16-digit network ID. It's also impossible to de-authorize a member as these networks don't issue or enforce certificates. Such "party line" networks are used for decentralized app backplanes, gaming, and testing but are otherwise not common.
|
||||
|
||||
This field is (for legacy reasons) a comma-delimited list of strings. These can be `rfc4193`, `6plane`, and `zt`. RFC4193 and 6PLANE are special addressing modes that deterministically assign IPv6 addresses based on the network ID and the ZeroTier address of each member. The `zt` mode enables IPv6 auto-assignment from arbitrary IPv6 IP ranges configured in `ipAssignmentPools`.
|
||||
**Auto-Assign Modes:**
|
||||
|
||||
**Relay object format:**
|
||||
Auto assign modes (`v4AssignMode` and `v6AssignMode`) contain objects that map assignment modes to booleans.
|
||||
|
||||
Relay objects define network-specific preferred relay nodes. Traffic to peers on this network will preferentially use these relays if they are available, and otherwise will fall back to the global rootserver infrastructure.
|
||||
For IPv4 the only valid setting is `zt` which, if true, causes IPv4 addresses to be auto-assigned from `ipAssignmentPools` to members that do not have an IPv4 assignment. Note that active bridges are exempt and will not get auto-assigned IPs since this can interfere with bridging. (You can still manually assign one if you want.)
|
||||
|
||||
| Field | Type | Description | Writable |
|
||||
| --------------------- | ------------- | ------------------------------------------------- | -------- |
|
||||
| address | string | 10-digit ZeroTier address of relay | YES |
|
||||
| phyAddress | string | Optional IP/port suggestion for finding relay | YES |
|
||||
IPv6 includes this option and two others: `6plane` and `rfc4193`. These assign private IPv6 addresses to each member based on a deterministic assignment scheme that allows members to emulate IPv6 NDP to skip multicast for better performance and scalability. The `rfc4193` mode gives every member a /128 on a /88 network, while `6plane` gives every member a /80 within a /40 network but uses NDP emulation to route *all* IPs under that /80 to its owner. The `6plane` mode is great for use cases like Docker since it allows every member to assign IPv6 addresses within its /80 that just work instantly and globally across the network.
|
||||
|
||||
**IP assignment pool object format:**
|
||||
|
||||
| Field | Type | Description | Writable |
|
||||
| --------------------- | ------------- | ------------------------------------------------- | -------- |
|
||||
| ipRangeStart | string | Starting IP address in range | YES |
|
||||
| ipRangeEnd | string | Ending IP address in range (inclusive) | YES |
|
||||
| Field | Type | Description |
|
||||
| --------------------- | ------------- | ------------------------------------------------- |
|
||||
| ipRangeStart | string | Starting IP address in range |
|
||||
| ipRangeEnd | string | Ending IP address in range (inclusive) |
|
||||
|
||||
Pools are only used if auto-assignment is on for the given address type (IPv4 or IPv6) and if the entire range falls within a managed route.
|
||||
|
||||
|
@ -159,57 +131,68 @@ That defines a range within network `fd00:feed:feed:beef::/64` that contains up
|
|||
|
||||
**Rule object format:**
|
||||
|
||||
Rules are matched in order of ruleNo. If no rules match, the default action is `drop`. To allow all traffic, create a single rule with all *null* fields and an action of `accept`.
|
||||
Each rule is actually a sequence of zero or more `MATCH_` entries in the rule array followed by an `ACTION_` entry that describes what to do if all the preceding entries match. An `ACTION_` without any preceding `MATCH_` entries is always taken, so setting a single `ACTION_ACCEPT` rule yields a network that allows all traffic. If no rules are present the default action is `ACTION_DROP`.
|
||||
|
||||
In the future there will be many, many more types of rules. As of today only filtering by Ethernet packet type is supported.
|
||||
Rules are evaluated in the order in which they appear in the array. There is currently a limit of 256 entries per network. Capabilities should be used if a larger and more complex rule set is needed since they allow rules to be grouped by purpose and only shipped to members that need them.
|
||||
|
||||
| Field | Type | Description | Writable |
|
||||
| --------------------- | ------------- | ------------------------------------------------- | -------- |
|
||||
| ruleNo | integer | Rule sorting key | YES |
|
||||
| etherType | integer | Ethernet frame type (e.g. 34525 for IPv6) | YES |
|
||||
| action | string | Currently either `allow` or `drop` | YES |
|
||||
Each rule table entry has two common fields.
|
||||
|
||||
**An Example: The Configuration for Earth**
|
||||
| Field | Type | Description |
|
||||
| --------------------- | ------------- | ------------------------------------------------- |
|
||||
| type | string | Entry type (all caps, case sensitive) |
|
||||
| not | boolean | If true, MATCHes match if they don't match |
|
||||
|
||||
Here is an example of a correctly configured ZeroTier network with IPv4 auto-assigned addresses from 28.0.0.0/7 (a "de-facto private" space) and RFC4193 IPv6 addressing. Users might recognize this as *Earth*, our public "global LAN party" that's used for demos and testing and occasionally gaming.
|
||||
The following fields may or may not be present depending on rule type:
|
||||
|
||||
For your own networks you'll probably want to change `private` to `true` unless you like company. These rules on the other hand probably are what you want. These allow IPv4, IPv4 ARP, and IPv6 Ethernet frames. To allow only IPv4 omit the one for Ethernet type 34525 (IPv6).
|
||||
| Field | Type | Description |
|
||||
| --------------------- | ------------- | ------------------------------------------------- |
|
||||
| zt | string | 10-digit hex ZeroTier address |
|
||||
| etherType | integer | Ethernet frame type |
|
||||
| mac | string | Hex MAC address (with or without :'s) |
|
||||
| ip | string | IPv4 or IPv6 address |
|
||||
| ipTos | integer | IP type of service |
|
||||
| ipProtocol | integer | IP protocol (e.g. TCP) |
|
||||
| start | integer | Start of an integer range (e.g. port range) |
|
||||
| end | integer | End of an integer range (inclusive) |
|
||||
| id | integer | Tag ID |
|
||||
| value | integer | Tag value or comparison value |
|
||||
| mask | integer | Bit mask (for characteristics flags) |
|
||||
|
||||
{
|
||||
"nwid": "8056c2e21c000001",
|
||||
"controllerInstanceId": "8ab354604debe1da27ee627c9ef94a48",
|
||||
"clock": 1468004857100,
|
||||
"name": "earth.zerotier.net",
|
||||
"private": false,
|
||||
"enableBroadcast": false,
|
||||
"allowPassiveBridging": false,
|
||||
"v4AssignMode": "zt",
|
||||
"v6AssignMode": "rfc4193",
|
||||
"multicastLimit": 64,
|
||||
"creationTime": 1442292573165,
|
||||
"revision": 234,
|
||||
"memberRevisionCounter": 3326,
|
||||
"authorizedMemberCount": 2873,
|
||||
"relays": [],
|
||||
"routes": [
|
||||
{"target":"28.0.0.0/7","via":null,"flags":0,"metric":0}],
|
||||
"ipAssignmentPools": [
|
||||
{"ipRangeStart":"28.0.0.1","ipRangeEnd":"29.255.255.254"}],
|
||||
"rules": [
|
||||
{
|
||||
"ruleNo": 20,
|
||||
"etherType": 2048,
|
||||
"action": "accept"
|
||||
},{
|
||||
"ruleNo": 21,
|
||||
"etherType": 2054,
|
||||
"action": "accept"
|
||||
},{
|
||||
"ruleNo": 30,
|
||||
"etherType": 34525,
|
||||
"action": "accept"
|
||||
}]
|
||||
}
|
||||
The entry types and their additional fields are:
|
||||
|
||||
| Entry type | Description | Fields |
|
||||
| ------------------------------- | ----------------------------------------------------------------- | -------------- |
|
||||
| `ACTION_DROP` | Drop any packets matching this rule | (none) |
|
||||
| `ACTION_ACCEPT` | Accept any packets matching this rule | (none) |
|
||||
| `ACTION_TEE` | Send a copy of this packet to a node (rule parsing continues) | `zt` |
|
||||
| `ACTION_REDIRECT` | Redirect this packet to another node | `zt` |
|
||||
| `ACTION_DEBUG_LOG` | Output debug info on match (if built with rules engine debug) | (none) |
|
||||
| `MATCH_SOURCE_ZEROTIER_ADDRESS` | Match VL1 ZeroTier address of packet sender. | `zt` |
|
||||
| `MATCH_DEST_ZEROTIER_ADDRESS` | Match VL1 ZeroTier address of recipient | `zt` |
|
||||
| `MATCH_ETHERTYPE` | Match Ethernet frame type | `etherType` |
|
||||
| `MATCH_MAC_SOURCE` | Match source Ethernet MAC address | `mac` |
|
||||
| `MATCH_MAC_DEST` | Match destination Ethernet MAC address | `mac` |
|
||||
| `MATCH_IPV4_SOURCE` | Match source IPv4 address | `ip` |
|
||||
| `MATCH_IPV4_DEST` | Match destination IPv4 address | `ip` |
|
||||
| `MATCH_IPV6_SOURCE` | Match source IPv6 address | `ip` |
|
||||
| `MATCH_IPV6_DEST` | Match destination IPv6 address | `ip` |
|
||||
| `MATCH_IP_TOS` | Match IP TOS field | `ipTos` |
|
||||
| `MATCH_IP_PROTOCOL` | Match IP protocol field | `ipProtocol` |
|
||||
| `MATCH_IP_SOURCE_PORT_RANGE` | Match a source IP port range | `start`,`end` |
|
||||
| `MATCH_IP_DEST_PORT_RANGE` | Match a destination IP port range | `start`,`end` |
|
||||
| `MATCH_CHARACTERISTICS` | Match on characteristics flags | `mask`,`value` |
|
||||
| `MATCH_FRAME_SIZE_RANGE` | Match a range of Ethernet frame sizes | `start`,`end` |
|
||||
| `MATCH_TAGS_SAMENESS` | Match if both sides' tags differ by no more than value | `id`,`value` |
|
||||
| `MATCH_TAGS_BITWISE_AND` | Match if both sides' tags AND to value | `id`,`value` |
|
||||
| `MATCH_TAGS_BITWISE_OR` | Match if both sides' tags OR to value | `id`,`value` |
|
||||
| `MATCH_TAGS_BITWISE_XOR` | Match if both sides` tags XOR to value | `id`,`value` |
|
||||
|
||||
Important notes about rules engine behavior:
|
||||
|
||||
* IPv4 and IPv6 IP address rules do not match for frames that are not IPv4 or IPv6 respectively.
|
||||
* `ACTION_DEBUG_LOG` is a no-op on nodes not built with `ZT_RULES_ENGINE_DEBUGGING` enabled (see Network.cpp). If that is enabled nodes will dump a trace of rule evaluation results to *stdout* when this action is encountered but will otherwise keep evaluating rules. This is used for basic "smoke testing" of the rules engine.
|
||||
* Multicast packets and packets destined for bridged devices treated a little differently. They are matched more than once. They are matched at the point of send with a NULL ZeroTier destination address, meaning that `MATCH_DEST_ZEROTIER_ADDRESS` is useless. That's because the true VL1 destination is not yet known. Then they are matched again for each true VL1 destination. On these later subsequent matches TEE actions are ignored and REDIRECT rules are interpreted as DROPs. This prevents multiple TEE or REDIRECT packets from being sent to third party devices.
|
||||
* Rules in capabilities are always matched as if the current device is the sender (inbound == false). A capability specifies sender side rules that can be enforced on both sides.
|
||||
|
||||
#### `/controller/network/<network ID>/member`
|
||||
|
||||
|
@ -235,10 +218,12 @@ This returns an object containing all currently online members and the most rece
|
|||
|
||||
| Field | Type | Description | Writable |
|
||||
| --------------------- | ------------- | ------------------------------------------------- | -------- |
|
||||
| id | string | Member's 10-digit ZeroTier address | no |
|
||||
| address | string | Member's 10-digit ZeroTier address | no |
|
||||
| nwid | string | 16-digit network ID | no |
|
||||
| clock | integer | Current clock, ms since epoch | no |
|
||||
| address | string | Member's 10-digit ZeroTier address | no |
|
||||
| authorized | boolean | Is member authorized? (for private networks) | YES |
|
||||
| authHistory | array[object] | History of auth changes, latest at end | no |
|
||||
| activeBridge | boolean | Member is able to bridge to other Ethernet nets | YES |
|
||||
| identity | string | Member's public ZeroTier identity (if known) | no |
|
||||
| ipAssignments | array[string] | Managed IP address assignments | YES |
|
||||
|
@ -252,10 +237,12 @@ Note that managed IP assignments are only used if they fall within a managed rou
|
|||
| Field | Type | Description |
|
||||
| --------------------- | ------------- | ------------------------------------------------- |
|
||||
| ts | integer | Time of request, ms since epoch |
|
||||
| authorized | boolean | Was member authorized? |
|
||||
| clientMajorVersion | integer | Client major version or -1 if unknown |
|
||||
| clientMinorVersion | integer | Client minor version or -1 if unknown |
|
||||
| clientRevision | integer | Client revision or -1 if unknown |
|
||||
| auth | boolean | Was member authorized? |
|
||||
| authBy | string | How was member authorized? |
|
||||
| vMajor | integer | Client major version or -1 if unknown |
|
||||
| vMinor | integer | Client minor version or -1 if unknown |
|
||||
| vRev | integer | Client revision or -1 if unknown |
|
||||
| vProto | integer | ZeroTier protocol version reported by client |
|
||||
| fromAddr | string | Physical address if known |
|
||||
|
||||
The controller can only know a member's `fromAddr` if it's able to establish a direct path to it. Members behind very restrictive firewalls may not have this information since the controller will be receiving the member's requests by way of a relay. ZeroTier does not back-trace IP paths as packets are relayed since this would add a lot of protocol overhead.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef ZT_SQLITENETWORKCONTROLLER_HPP
|
||||
#define ZT_SQLITENETWORKCONTROLLER_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/NetworkController.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "../osdep/Thread.hpp"
|
||||
|
||||
// Number of in-memory last log entries to maintain per user
|
||||
#define ZT_SQLITENETWORKCONTROLLER_IN_MEMORY_LOG_SIZE 32
|
||||
|
||||
// How long do circuit tests last before they're forgotten?
|
||||
#define ZT_SQLITENETWORKCONTROLLER_CIRCUIT_TEST_TIMEOUT 60000
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class Node;
|
||||
|
||||
class SqliteNetworkController : public NetworkController
|
||||
{
|
||||
public:
|
||||
SqliteNetworkController(Node *node,const char *dbPath,const char *circuitTestPath);
|
||||
virtual ~SqliteNetworkController();
|
||||
|
||||
virtual NetworkController::ResultCode doNetworkConfigRequest(
|
||||
const InetAddress &fromAddr,
|
||||
const Identity &signingId,
|
||||
const Identity &identity,
|
||||
uint64_t nwid,
|
||||
const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &metaData,
|
||||
NetworkConfig &nc);
|
||||
|
||||
unsigned int handleControlPlaneHttpGET(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
unsigned int handleControlPlaneHttpPOST(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
unsigned int handleControlPlaneHttpDELETE(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
|
||||
// threadMain() for backup thread -- do not call directly
|
||||
void threadMain()
|
||||
throw();
|
||||
|
||||
private:
|
||||
/* deprecated
|
||||
enum IpAssignmentType {
|
||||
// IP assignment is a static IP address
|
||||
ZT_IP_ASSIGNMENT_TYPE_ADDRESS = 0,
|
||||
// IP assignment is a network -- a route via this interface, not an address
|
||||
ZT_IP_ASSIGNMENT_TYPE_NETWORK = 1
|
||||
};
|
||||
*/
|
||||
|
||||
unsigned int _doCPGet(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
|
||||
static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report);
|
||||
|
||||
Node *_node;
|
||||
Thread _backupThread;
|
||||
volatile bool _backupThreadRun;
|
||||
volatile bool _backupNeeded;
|
||||
std::string _dbPath;
|
||||
std::string _circuitTestPath;
|
||||
std::string _instanceId;
|
||||
|
||||
// Circuit tests outstanding
|
||||
struct _CircuitTestEntry
|
||||
{
|
||||
ZT_CircuitTest *test;
|
||||
std::string jsonResults;
|
||||
};
|
||||
std::map< uint64_t,_CircuitTestEntry > _circuitTests;
|
||||
|
||||
// Last request time by address, for rate limitation
|
||||
std::map< std::pair<uint64_t,uint64_t>,uint64_t > _lastRequestTime;
|
||||
|
||||
sqlite3 *_db;
|
||||
|
||||
sqlite3_stmt *_sGetNetworkById;
|
||||
sqlite3_stmt *_sGetMember;
|
||||
sqlite3_stmt *_sCreateMember;
|
||||
sqlite3_stmt *_sGetNodeIdentity;
|
||||
sqlite3_stmt *_sCreateOrReplaceNode;
|
||||
sqlite3_stmt *_sGetEtherTypesFromRuleTable;
|
||||
sqlite3_stmt *_sGetActiveBridges;
|
||||
sqlite3_stmt *_sGetIpAssignmentsForNode;
|
||||
sqlite3_stmt *_sGetIpAssignmentPools;
|
||||
sqlite3_stmt *_sCheckIfIpIsAllocated;
|
||||
sqlite3_stmt *_sAllocateIp;
|
||||
sqlite3_stmt *_sDeleteIpAllocations;
|
||||
sqlite3_stmt *_sGetRelays;
|
||||
sqlite3_stmt *_sListNetworks;
|
||||
sqlite3_stmt *_sListNetworkMembers;
|
||||
sqlite3_stmt *_sGetMember2;
|
||||
sqlite3_stmt *_sGetIpAssignmentPools2;
|
||||
sqlite3_stmt *_sListRules;
|
||||
sqlite3_stmt *_sCreateRule;
|
||||
sqlite3_stmt *_sCreateNetwork;
|
||||
sqlite3_stmt *_sGetNetworkRevision;
|
||||
sqlite3_stmt *_sSetNetworkRevision;
|
||||
sqlite3_stmt *_sDeleteRelaysForNetwork;
|
||||
sqlite3_stmt *_sCreateRelay;
|
||||
sqlite3_stmt *_sDeleteIpAssignmentPoolsForNetwork;
|
||||
sqlite3_stmt *_sDeleteRulesForNetwork;
|
||||
sqlite3_stmt *_sCreateIpAssignmentPool;
|
||||
sqlite3_stmt *_sUpdateMemberAuthorized;
|
||||
sqlite3_stmt *_sUpdateMemberActiveBridge;
|
||||
sqlite3_stmt *_sUpdateMemberHistory;
|
||||
sqlite3_stmt *_sDeleteMember;
|
||||
sqlite3_stmt *_sDeleteAllNetworkMembers;
|
||||
sqlite3_stmt *_sGetActiveNodesOnNetwork;
|
||||
sqlite3_stmt *_sDeleteNetwork;
|
||||
sqlite3_stmt *_sCreateRoute;
|
||||
sqlite3_stmt *_sGetRoutes;
|
||||
sqlite3_stmt *_sDeleteRoutes;
|
||||
sqlite3_stmt *_sIncrementMemberRevisionCounter;
|
||||
sqlite3_stmt *_sGetConfig;
|
||||
sqlite3_stmt *_sSetConfig;
|
||||
|
||||
Mutex _lock;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
320
controller/migrate-sqlite/migrate.js
Normal file
320
controller/migrate-sqlite/migrate.js
Normal file
|
@ -0,0 +1,320 @@
|
|||
'use strict';
|
||||
|
||||
var sqlite3 = require('sqlite3').verbose();
|
||||
var fs = require('fs');
|
||||
var async = require('async');
|
||||
|
||||
function blobToIPv4(b)
|
||||
{
|
||||
if (!b)
|
||||
return null;
|
||||
if (b.length !== 16)
|
||||
return null;
|
||||
return b.readUInt8(12).toString()+'.'+b.readUInt8(13).toString()+'.'+b.readUInt8(14).toString()+'.'+b.readUInt8(15).toString();
|
||||
}
|
||||
function blobToIPv6(b)
|
||||
{
|
||||
if (!b)
|
||||
return null;
|
||||
if (b.length !== 16)
|
||||
return null;
|
||||
var s = '';
|
||||
for(var i=0;i<16;++i) {
|
||||
var x = b.readUInt8(i).toString(16);
|
||||
if (x.length === 1)
|
||||
s += '0';
|
||||
s += x;
|
||||
if ((((i+1) & 1) === 0)&&(i !== 15))
|
||||
s += ':';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
if (process.argv.length !== 4) {
|
||||
console.log('ZeroTier Old Sqlite3 Controller DB Migration Utility');
|
||||
console.log('(c)2017 ZeroTier, Inc. [GPL3]');
|
||||
console.log('');
|
||||
console.log('Usage: node migrate.js </path/to/controller.db> </path/to/controller.d>');
|
||||
console.log('');
|
||||
console.log('The first argument must be the path to the old Sqlite3 controller.db');
|
||||
console.log('file. The second must be the path to the EMPTY controller.d database');
|
||||
console.log('directory for a new (1.1.17 or newer) controller. If this path does');
|
||||
console.log('not exist it will be created.');
|
||||
console.log('');
|
||||
console.log('WARNING: this will ONLY work correctly on a 1.1.14 controller database.');
|
||||
console.log('If your controller is old you should first upgrade to 1.1.14 and run the');
|
||||
console.log('controller so that it will brings its Sqlite3 database up to the latest');
|
||||
console.log('version before running this migration.');
|
||||
console.log('');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var oldDbPath = process.argv[2];
|
||||
var newDbPath = process.argv[3];
|
||||
|
||||
console.log('Starting migrate of "'+oldDbPath+'" to "'+newDbPath+'"...');
|
||||
console.log('');
|
||||
|
||||
var old = new sqlite3.Database(oldDbPath);
|
||||
|
||||
var networks = {};
|
||||
|
||||
var nodeIdentities = {};
|
||||
var networkCount = 0;
|
||||
var memberCount = 0;
|
||||
var routeCount = 0;
|
||||
var ipAssignmentPoolCount = 0;
|
||||
var ipAssignmentCount = 0;
|
||||
var ruleCount = 0;
|
||||
var oldSchemaVersion = -1;
|
||||
|
||||
async.series([function(nextStep) {
|
||||
|
||||
old.each('SELECT v from Config WHERE k = \'schemaVersion\'',function(err,row) {
|
||||
oldSchemaVersion = parseInt(row.v)||-1;
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
if (oldSchemaVersion !== 4) {
|
||||
console.log('FATAL: this MUST be run on a 1.1.14 controller.db! Upgrade your old');
|
||||
console.log('controller to 1.1.14 first and run it once to bring its DB up to date.');
|
||||
return process.exit(1);
|
||||
}
|
||||
|
||||
console.log('Reading networks...');
|
||||
old.each('SELECT * FROM Network',function(err,row) {
|
||||
if ((typeof row.id === 'string')&&(row.id.length === 16)) {
|
||||
var flags = parseInt(row.flags)||0;
|
||||
networks[row.id] = {
|
||||
id: row.id,
|
||||
nwid: row.id,
|
||||
objtype: 'network',
|
||||
authTokens: [],
|
||||
capabilities: [],
|
||||
creationTime: parseInt(row.creationTime)||0,
|
||||
enableBroadcast: !!row.enableBroadcast,
|
||||
ipAssignmentPools: [],
|
||||
lastModified: Date.now(),
|
||||
multicastLimit: row.multicastLimit||32,
|
||||
name: row.name||'',
|
||||
private: !!row.private,
|
||||
revision: parseInt(row.revision)||1,
|
||||
rules: [{ 'type': 'ACTION_ACCEPT' }], // populated later if there are defined rules, otherwise default is allow all
|
||||
routes: [],
|
||||
v4AssignMode: {
|
||||
'zt': ((flags & 1) !== 0)
|
||||
},
|
||||
v6AssignMode: {
|
||||
'6plane': ((flags & 4) !== 0),
|
||||
'rfc4193': ((flags & 2) !== 0),
|
||||
'zt': ((flags & 8) !== 0)
|
||||
},
|
||||
_members: {} // temporary
|
||||
};
|
||||
++networkCount;
|
||||
//console.log(networks[row.id]);
|
||||
}
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
console.log(' '+networkCount+' networks.');
|
||||
console.log('Reading network route definitions...');
|
||||
old.each('SELECT * from Route WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) {
|
||||
var network = networks[row.networkId];
|
||||
if (network) {
|
||||
var rt = {
|
||||
target: (((row.ipVersion == 4) ? blobToIPv4(row.target) : blobToIPv6(row.target))+'/'+row.targetNetmaskBits),
|
||||
via: ((row.via) ? ((row.ipVersion == 4) ? blobToIPv4(row.via) : blobToIPv6(row.via)) : null)
|
||||
};
|
||||
network.routes.push(rt);
|
||||
++routeCount;
|
||||
}
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
console.log(' '+routeCount+' routes in '+networkCount+' networks.');
|
||||
console.log('Reading IP assignment pools...');
|
||||
old.each('SELECT * FROM IpAssignmentPool WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) {
|
||||
var network = networks[row.networkId];
|
||||
if (network) {
|
||||
var p = {
|
||||
ipRangeStart: ((row.ipVersion == 4) ? blobToIPv4(row.ipRangeStart) : blobToIPv6(row.ipRangeStart)),
|
||||
ipRangeEnd: ((row.ipVersion == 4) ? blobToIPv4(row.ipRangeEnd) : blobToIPv6(row.ipRangeEnd))
|
||||
};
|
||||
network.ipAssignmentPools.push(p);
|
||||
++ipAssignmentPoolCount;
|
||||
}
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
console.log(' '+ipAssignmentPoolCount+' IP assignment pools in '+networkCount+' networks.');
|
||||
console.log('Reading known node identities...');
|
||||
old.each('SELECT * FROM Node',function(err,row) {
|
||||
nodeIdentities[row.id] = row.identity;
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
console.log(' '+Object.keys(nodeIdentities).length+' known identities.');
|
||||
console.log('Reading network members...');
|
||||
old.each('SELECT * FROM Member',function(err,row) {
|
||||
var network = networks[row.networkId];
|
||||
if (network) {
|
||||
network._members[row.nodeId] = {
|
||||
id: row.nodeId,
|
||||
address: row.nodeId,
|
||||
objtype: 'member',
|
||||
authorized: !!row.authorized,
|
||||
activeBridge: !!row.activeBridge,
|
||||
authHistory: [],
|
||||
capabilities: [],
|
||||
creationTime: 0,
|
||||
identity: nodeIdentities[row.nodeId]||null,
|
||||
ipAssignments: [],
|
||||
lastAuthorizedTime: (row.authorized) ? Date.now() : 0,
|
||||
lastDeauthorizedTime: (row.authorized) ? 0 : Date.now(),
|
||||
lastModified: Date.now(),
|
||||
lastRequestMetaData: '',
|
||||
noAutoAssignIps: false,
|
||||
nwid: row.networkId,
|
||||
revision: parseInt(row.memberRevision)||1,
|
||||
tags: [],
|
||||
recentLog: []
|
||||
};
|
||||
++memberCount;
|
||||
//console.log(network._members[row.nodeId]);
|
||||
}
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
console.log(' '+memberCount+' members of '+networkCount+' networks.');
|
||||
console.log('Reading static IP assignments...');
|
||||
old.each('SELECT * FROM IpAssignment WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) {
|
||||
var network = networks[row.networkId];
|
||||
if (network) {
|
||||
var member = network._members[row.nodeId];
|
||||
if ((member)&&((member.authorized)||(!network['private']))) { // don't mirror assignments to unauthorized members to avoid conflicts
|
||||
if (row.ipVersion == 4) {
|
||||
member.ipAssignments.push(blobToIPv4(row.ip));
|
||||
++ipAssignmentCount;
|
||||
} else if (row.ipVersion == 6) {
|
||||
member.ipAssignments.push(blobToIPv6(row.ip));
|
||||
++ipAssignmentCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
// Old versions only supported Ethertype whitelisting, so that's
|
||||
// all we mirror forward. The other fields were always unused.
|
||||
|
||||
console.log(' '+ipAssignmentCount+' IP assignments for '+memberCount+' authorized members of '+networkCount+' networks.');
|
||||
console.log('Reading allowed Ethernet types (old basic rules)...');
|
||||
var etherTypesByNetwork = {};
|
||||
old.each('SELECT DISTINCT networkId,ruleNo,etherType FROM Rule WHERE "action" = \'accept\'',function(err,row) {
|
||||
if (row.networkId in networks) {
|
||||
var et = parseInt(row.etherType)||0;
|
||||
var ets = etherTypesByNetwork[row.networkId];
|
||||
if (!ets)
|
||||
etherTypesByNetwork[row.networkId] = [ et ];
|
||||
else ets.push(et);
|
||||
}
|
||||
},function(err) {
|
||||
if (err) return nextStep(err);
|
||||
for(var nwid in etherTypesByNetwork) {
|
||||
var ets = etherTypesByNetwork[nwid].sort();
|
||||
var network = networks[nwid];
|
||||
if (network) {
|
||||
var rules = [];
|
||||
if (ets.indexOf(0) >= 0) {
|
||||
// If 0 is in the list, all Ethernet types are allowed so we accept all.
|
||||
rules.push({ 'type': 'ACTION_ACCEPT' });
|
||||
} else {
|
||||
// Otherwise we whitelist.
|
||||
for(var i=0;i<ets.length;++i) {
|
||||
rules.push({
|
||||
'etherType': ets[i],
|
||||
'not': true,
|
||||
'or': false,
|
||||
'type': 'MATCH_ETHERTYPE'
|
||||
});
|
||||
}
|
||||
rules.push({ 'type': 'ACTION_DROP' });
|
||||
rules.push({ 'type': 'ACTION_ACCEPT' });
|
||||
}
|
||||
network.rules = rules;
|
||||
++ruleCount;
|
||||
}
|
||||
}
|
||||
return nextStep(null);
|
||||
});
|
||||
|
||||
}],function(err) {
|
||||
|
||||
if (err) {
|
||||
console.log('FATAL: '+err.toString());
|
||||
return process.exit(1);
|
||||
}
|
||||
|
||||
console.log(' '+ruleCount+' ethernet type whitelists converted to new format rules.');
|
||||
old.close();
|
||||
console.log('Done reading and converting Sqlite3 database! Writing JSONDB files...');
|
||||
|
||||
try {
|
||||
fs.mkdirSync(newDbPath,0o700);
|
||||
} catch (e) {}
|
||||
var nwBase = newDbPath+'/network';
|
||||
try {
|
||||
fs.mkdirSync(nwBase,0o700);
|
||||
} catch (e) {}
|
||||
nwBase = nwBase + '/';
|
||||
var nwids = Object.keys(networks).sort();
|
||||
var fileCount = 0;
|
||||
for(var ni=0;ni<nwids.length;++ni) {
|
||||
var network = networks[nwids[ni]];
|
||||
|
||||
var mids = Object.keys(network._members).sort();
|
||||
if (mids.length > 0) {
|
||||
try {
|
||||
fs.mkdirSync(nwBase+network.id);
|
||||
} catch (e) {}
|
||||
var mbase = nwBase+network.id+'/member';
|
||||
try {
|
||||
fs.mkdirSync(mbase,0o700);
|
||||
} catch (e) {}
|
||||
mbase = mbase + '/';
|
||||
|
||||
for(var mi=0;mi<mids.length;++mi) {
|
||||
var member = network._members[mids[mi]];
|
||||
fs.writeFileSync(mbase+member.id+'.json',JSON.stringify(member,null,1),{ mode: 0o600 });
|
||||
++fileCount;
|
||||
//console.log(mbase+member.id+'.json');
|
||||
}
|
||||
}
|
||||
|
||||
delete network._members; // temporary field, not part of actual JSONDB, so don't write
|
||||
fs.writeFileSync(nwBase+network.id+'.json',JSON.stringify(network,null,1),{ mode: 0o600 });
|
||||
++fileCount;
|
||||
//console.log(nwBase+network.id+'.json');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('SUCCESS! Wrote '+fileCount+' JSONDB files.');
|
||||
|
||||
console.log('');
|
||||
console.log('You should still inspect the new DB before going live. Also be sure');
|
||||
console.log('to "chown -R" and "chgrp -R" the new DB to the user and group under');
|
||||
console.log('which the ZeroTier One instance acting as controller will be running.');
|
||||
console.log('The controller must be able to read and write the DB, of course.');
|
||||
console.log('');
|
||||
console.log('Have fun!');
|
||||
|
||||
return process.exit(0);
|
||||
});
|
15
controller/migrate-sqlite/package.json
Normal file
15
controller/migrate-sqlite/package.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "migrate-sqlite",
|
||||
"version": "1.0.0",
|
||||
"description": "Migrate old SQLite to new JSON filesystem DB for ZeroTier network controller",
|
||||
"main": "migrate.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Adam Ierymenko <adam.ierymenko@zerotier.com>",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"async": "^2.1.4",
|
||||
"sqlite3": "^3.1.8"
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
#define ZT_NETCONF_SCHEMA_SQL \
|
||||
"CREATE TABLE Config (\n"\
|
||||
" k varchar(16) PRIMARY KEY NOT NULL,\n"\
|
||||
" v varchar(1024) NOT NULL\n"\
|
||||
");\n"\
|
||||
"\n"\
|
||||
"CREATE TABLE Network (\n"\
|
||||
" id char(16) PRIMARY KEY NOT NULL,\n"\
|
||||
" name varchar(128) NOT NULL,\n"\
|
||||
" private integer NOT NULL DEFAULT(1),\n"\
|
||||
" enableBroadcast integer NOT NULL DEFAULT(1),\n"\
|
||||
" allowPassiveBridging integer NOT NULL DEFAULT(0),\n"\
|
||||
" multicastLimit integer NOT NULL DEFAULT(32),\n"\
|
||||
" creationTime integer NOT NULL DEFAULT(0),\n"\
|
||||
" revision integer NOT NULL DEFAULT(1),\n"\
|
||||
" memberRevisionCounter integer NOT NULL DEFAULT(1),\n"\
|
||||
" flags integer NOT NULL DEFAULT(0)\n"\
|
||||
");\n"\
|
||||
"\n"\
|
||||
"CREATE TABLE AuthToken (\n"\
|
||||
" id integer PRIMARY KEY NOT NULL,\n"\
|
||||
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
|
||||
" authMode integer NOT NULL DEFAULT(1),\n"\
|
||||
" useCount integer NOT NULL DEFAULT(0),\n"\
|
||||
" maxUses integer NOT NULL DEFAULT(0),\n"\
|
||||
" expiresAt integer NOT NULL DEFAULT(0),\n"\
|
||||
" token varchar(256) NOT NULL\n"\
|
||||
");\n"\
|
||||
"\n"\
|
||||
"CREATE INDEX AuthToken_networkId_token ON AuthToken(networkId,token);\n"\
|
||||
"\n"\
|
||||
"CREATE TABLE Node (\n"\
|
||||
" id char(10) PRIMARY KEY NOT NULL,\n"\
|
||||
" identity varchar(4096) NOT NULL\n"\
|
||||
");\n"\
|
||||
"\n"\
|
||||
"CREATE TABLE IpAssignment (\n"\
|
||||
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
|
||||
" nodeId char(10) REFERENCES Node(id) ON DELETE CASCADE,\n"\
|
||||
" type integer NOT NULL DEFAULT(0),\n"\
|
||||
" ip blob(16) NOT NULL,\n"\
|
||||
" ipNetmaskBits integer NOT NULL DEFAULT(0),\n"\
|
||||
" ipVersion integer NOT NULL DEFAULT(4)\n"\
|
||||
");\n"\
|
||||
"\n"\
|
||||
"CREATE UNIQUE INDEX IpAssignment_networkId_ip ON IpAssignment (networkId, ip);\n"\
|
||||
"\n"\
|
||||
"CREATE INDEX IpAssignment_networkId_nodeId ON IpAssignment (networkId, nodeId);\n"\
|
||||
"\n"\
|
||||
"CREATE TABLE IpAssignmentPool (\n"\
|
||||
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
|
||||
" ipRangeStart blob(16) NOT NULL,\n"\
|
||||
" ipRangeEnd blob(16) NOT NULL,\n"\
|
||||
" ipVersion integer NOT NULL DEFAULT(4)\n"\
|
||||
");\n"\
|
||||
"\n"\
|
||||
"CREATE UNIQUE INDEX IpAssignmentPool_networkId_ipRangeStart ON IpAssignmentPool (networkId,ipRangeStart);\n"\
|
||||
"\n"\
|
||||
"CREATE TABLE Member (\n"\
|
||||
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
|
||||
" nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,\n"\
|
||||
" authorized integer NOT NULL DEFAULT(0),\n"\
|
||||
" activeBridge integer NOT NULL DEFAULT(0),\n"\
|
||||
" memberRevision integer NOT NULL DEFAULT(0),\n"\
|
||||
" flags integer NOT NULL DEFAULT(0),\n"\
|
||||
" lastRequestTime integer NOT NULL DEFAULT(0),\n"\
|
||||
" lastPowDifficulty integer NOT NULL DEFAULT(0),\n"\
|
||||
" lastPowTime integer NOT NULL DEFAULT(0),\n"\
|
||||
" recentHistory blob,\n"\
|
||||
" PRIMARY KEY (networkId, nodeId)\n"\
|
||||
");\n"\
|
||||
"\n"\
|
||||
"CREATE INDEX Member_networkId_nodeId ON Member(networkId,nodeId);\n"\
|
||||
"CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);\n"\
|
||||
"CREATE INDEX Member_networkId_memberRevision ON Member(networkId, memberRevision);\n"\
|
||||
"CREATE INDEX Member_networkId_lastRequestTime ON Member(networkId, lastRequestTime);\n"\
|
||||
"\n"\
|
||||
"CREATE TABLE Route (\n"\
|
||||
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
|
||||
" target blob(16) NOT NULL,\n"\
|
||||
" via blob(16),\n"\
|
||||
" targetNetmaskBits integer NOT NULL,\n"\
|
||||
" ipVersion integer NOT NULL,\n"\
|
||||
" flags integer NOT NULL,\n"\
|
||||
" metric integer NOT NULL\n"\
|
||||
");\n"\
|
||||
"\n"\
|
||||
"CREATE INDEX Route_networkId ON Route (networkId);\n"\
|
||||
"\n"\
|
||||
"CREATE TABLE Relay (\n"\
|
||||
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
|
||||
" address char(10) NOT NULL,\n"\
|
||||
" phyAddress varchar(64) NOT NULL\n"\
|
||||
");\n"\
|
||||
"\n"\
|
||||
"CREATE UNIQUE INDEX Relay_networkId_address ON Relay (networkId,address);\n"\
|
||||
"\n"\
|
||||
"CREATE TABLE Rule (\n"\
|
||||
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
|
||||
" ruleNo integer NOT NULL,\n"\
|
||||
" nodeId char(10) REFERENCES Node(id),\n"\
|
||||
" sourcePort char(10),\n"\
|
||||
" destPort char(10),\n"\
|
||||
" vlanId integer,\n"\
|
||||
" vlanPcp integer,\n"\
|
||||
" etherType integer,\n"\
|
||||
" macSource char(12),\n"\
|
||||
" macDest char(12),\n"\
|
||||
" ipSource varchar(64),\n"\
|
||||
" ipDest varchar(64),\n"\
|
||||
" ipTos integer,\n"\
|
||||
" ipProtocol integer,\n"\
|
||||
" ipSourcePort integer,\n"\
|
||||
" ipDestPort integer,\n"\
|
||||
" flags integer,\n"\
|
||||
" invFlags integer,\n"\
|
||||
" \"action\" varchar(4096) NOT NULL DEFAULT('accept')\n"\
|
||||
");\n"\
|
||||
"\n"\
|
||||
"CREATE UNIQUE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);\n"\
|
||||
""
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Run this file to package the .sql file into a .c file whenever the SQL changes.
|
||||
|
||||
rm -f schema.sql.c
|
||||
echo '#define ZT_NETCONF_SCHEMA_SQL \' >schema.sql.c
|
||||
cat schema.sql | sed 's/"/\\"/g' | sed 's/^/"/' | sed 's/$/\\n"\\/' >>schema.sql.c
|
||||
echo '""' >>schema.sql.c
|
18
debian/changelog
vendored
18
debian/changelog
vendored
|
@ -1,3 +1,21 @@
|
|||
zerotier-one (1.2.4) unstable; urgency=medium
|
||||
|
||||
* See https://github.com/zerotier/ZeroTierOne for release notes.
|
||||
|
||||
-- Adam Ierymenko <adam.ierymenko@zerotier.com> Mon, 24 Mar 2017 01:00:00 -0700
|
||||
|
||||
zerotier-one (1.2.2) unstable; urgency=medium
|
||||
|
||||
* See https://github.com/zerotier/ZeroTierOne for release notes.
|
||||
|
||||
-- Adam Ierymenko <adam.ierymenko@zerotier.com> Fri, 17 Mar 2017 01:00:00 -0700
|
||||
|
||||
zerotier-one (1.2.0) unstable; urgency=medium
|
||||
|
||||
* See https://github.com/zerotier/ZeroTierOne for release notes.
|
||||
|
||||
-- Adam Ierymenko <adam.ierymenko@zerotier.com> Tue, 14 Mar 2017 09:08:00 -0700
|
||||
|
||||
zerotier-one (1.1.14) unstable; urgency=medium
|
||||
|
||||
* See https://github.com/zerotier/ZeroTierOne for release notes.
|
||||
|
|
4
debian/control
vendored
4
debian/control
vendored
|
@ -3,14 +3,14 @@ Maintainer: Adam Ierymenko <adam.ierymenko@zerotier.com>
|
|||
Section: net
|
||||
Priority: optional
|
||||
Standards-Version: 3.9.6
|
||||
Build-Depends: debhelper (>= 9), liblz4-dev, libnatpmp-dev, dh-systemd, ruby-ronn
|
||||
Build-Depends: debhelper (>= 9), dh-systemd
|
||||
Vcs-Git: git://github.com/zerotier/ZeroTierOne
|
||||
Vcs-Browser: https://github.com/zerotier/ZeroTierOne
|
||||
Homepage: https://www.zerotier.com/
|
||||
|
||||
Package: zerotier-one
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, liblz4-1, libnatpmp1, iproute2
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, iproute2, adduser, libstdc++6
|
||||
Homepage: https://www.zerotier.com/
|
||||
Description: ZeroTier network virtualization service
|
||||
ZeroTier One lets you join ZeroTier virtual networks and
|
||||
|
|
4
debian/control.wheezy
vendored
4
debian/control.wheezy
vendored
|
@ -3,14 +3,14 @@ Maintainer: Adam Ierymenko <adam.ierymenko@zerotier.com>
|
|||
Section: net
|
||||
Priority: optional
|
||||
Standards-Version: 3.9.4
|
||||
Build-Depends: debhelper (>= 9), ruby-ronn
|
||||
Build-Depends: debhelper (>= 9)
|
||||
Vcs-Git: git://github.com/zerotier/ZeroTierOne
|
||||
Vcs-Browser: https://github.com/zerotier/ZeroTierOne
|
||||
Homepage: https://www.zerotier.com/
|
||||
|
||||
Package: zerotier-one
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, iproute
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, iproute, libstdc++6
|
||||
Homepage: https://www.zerotier.com/
|
||||
Description: ZeroTier network virtualization service
|
||||
ZeroTier One lets you join ZeroTier virtual networks and
|
||||
|
|
9
debian/postinst
vendored
Normal file
9
debian/postinst
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
adduser --system --group --home /var/lib/zerotier-one --no-create-home zerotier-one
|
||||
;;
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
2
debian/rules
vendored
2
debian/rules
vendored
|
@ -7,7 +7,7 @@ CXXFLAGS=-O3 -fstack-protector-strong
|
|||
dh $@ --with systemd
|
||||
|
||||
override_dh_auto_build:
|
||||
make ZT_USE_MINIUPNPC=1 -j 2
|
||||
make -j 2
|
||||
|
||||
override_dh_systemd_start:
|
||||
dh_systemd_start --restart-after-upgrade
|
||||
|
|
16
debian/rules.static
vendored
Normal file
16
debian/rules.static
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
CFLAGS=-O3 -fstack-protector-strong
|
||||
CXXFLAGS=-O3 -fstack-protector-strong
|
||||
|
||||
%:
|
||||
dh $@ --with systemd
|
||||
|
||||
override_dh_auto_build:
|
||||
# make -j 2
|
||||
|
||||
override_dh_systemd_start:
|
||||
dh_systemd_start --restart-after-upgrade
|
||||
|
||||
override_dh_installinit:
|
||||
dh_installinit --name=zerotier-one -- defaults
|
2
debian/rules.wheezy
vendored
2
debian/rules.wheezy
vendored
|
@ -7,5 +7,5 @@ CXXFLAGS=-O3 -fstack-protector
|
|||
dh $@
|
||||
|
||||
override_dh_auto_build:
|
||||
make ZT_USE_MINIUPNPC=1 -j 2
|
||||
make -j 2
|
||||
|
||||
|
|
11
debian/rules.wheezy.static
vendored
Normal file
11
debian/rules.wheezy.static
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
CFLAGS=-O3 -fstack-protector
|
||||
CXXFLAGS=-O3 -fstack-protector
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_auto_build:
|
||||
# make -j 2
|
||||
|
0
debian/format → debian/source/format
vendored
0
debian/format → debian/source/format
vendored
18
doc/ext/kubernetes/.zerotierCliSettings
Normal file
18
doc/ext/kubernetes/.zerotierCliSettings
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"configVersion": 1,
|
||||
"defaultCentral": "@my.zerotier.com",
|
||||
"defaultController": "@my.zerotier.com",
|
||||
"defaultOne": "@local",
|
||||
"things": {
|
||||
"local": {
|
||||
"auth": "local_service_auth_token_replaced_automatically",
|
||||
"type": "one",
|
||||
"url": "http://127.0.0.1:9993/"
|
||||
},
|
||||
"my.zerotier.com": {
|
||||
"auth": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"type": "central",
|
||||
"url": "https://my.zerotier.com/"
|
||||
}
|
||||
}
|
||||
}
|
19
doc/ext/kubernetes/Dockerfile
Normal file
19
doc/ext/kubernetes/Dockerfile
Normal file
|
@ -0,0 +1,19 @@
|
|||
FROM node:4.4
|
||||
EXPOSE 8080/tcp 9993/udp
|
||||
|
||||
# Install ZT network conf files
|
||||
RUN mkdir -p /var/lib/zerotier-one/networks.d
|
||||
ADD *.conf /var/lib/zerotier-one/networks.d/
|
||||
ADD *.conf /
|
||||
ADD zerotier-one /
|
||||
ADD zerotier-cli /
|
||||
ADD .zerotierCliSettings /
|
||||
|
||||
# Install App
|
||||
ADD server.js /
|
||||
|
||||
# script which will start/auth VM on ZT network
|
||||
ADD entrypoint.sh /
|
||||
RUN chmod -v +x /entrypoint.sh
|
||||
|
||||
CMD ["./entrypoint.sh"]
|
150
doc/ext/kubernetes/README.md
Normal file
150
doc/ext/kubernetes/README.md
Normal file
|
@ -0,0 +1,150 @@
|
|||
Kubernetes + ZeroTier
|
||||
====
|
||||
|
||||
A self-authorizing Kubernetes cluster deployment over a private ZeroTier network.
|
||||
|
||||
This is a quick tutorial for setting up a Kubernetes deployment which can self-authorize each new replica onto your private ZeroTier network with no additional configuration needed when you scale. The Kubernetes-specific instructions and content is based on the [hellonode](http://kubernetes.io/docs/hellonode/) tutorial. All of the files discussed below can be found [here]();
|
||||
|
||||
|
||||
|
||||
## Preliminary tasks
|
||||
|
||||
**Step 1: Go to [my.zerotier.com](https://my.zerotier.com) and generate a network controller API key. This key will be used by ZeroTier to automatically authorize new instances of your VMs to join your secure deployment network during replication.**
|
||||
|
||||
**Step 2: Create a new `private` network. Take note of the network ID, henceforth: `nwid`**
|
||||
|
||||
**Step 3: Follow the instructions from the [hellonode](ttp://kubernetes.io/docs/hellonode/) tutorial to set up your development system.**
|
||||
|
||||
***
|
||||
## Construct docker image
|
||||
|
||||
**Step 4: Create necessary files for inclusion into image, your resultant directory should contain:**
|
||||
|
||||
- `ztkube/<nwid>.conf`
|
||||
- `ztkube/Dockerfile`
|
||||
- `ztkube/entrypoint.sh`
|
||||
- `ztkube/server.js`
|
||||
- `ztkube/zerotier-cli`
|
||||
- `ztkube/zerotier-one`
|
||||
|
||||
Start by creating a build directory to copy all required files into `mkdir ztkube`. Then build the following:
|
||||
- `make one`
|
||||
- `make cli`
|
||||
|
||||
Add the following files to the `ztkube` directory. These files will be compiled into the Docker image.
|
||||
|
||||
- Create an empty `<nwid>.conf` file to specify the private deployment network you created in *Step 2*:
|
||||
|
||||
- Create a CLI tool config file `.zerotierCliSettings` which should only contain your network controller API key to authorize new devices on your network (the local service API key will be filled in automatically). In this example the default controller is hosted by us at [my.zerotier.com](https://my.zerotier.com). Alternatively, you can host your own network controller but you'll need to modify the CLI config file accordingly.
|
||||
|
||||
```
|
||||
{
|
||||
"configVersion": 1,
|
||||
"defaultCentral": "@my.zerotier.com",
|
||||
"defaultController": "@my.zerotier.com",
|
||||
"defaultOne": "@local",
|
||||
"things": {
|
||||
"local": {
|
||||
"auth": "local_service_auth_token_replaced_automatically",
|
||||
"type": "one",
|
||||
"url": "http://127.0.0.1:9993/"
|
||||
},
|
||||
"my.zerotier.com": {
|
||||
"auth": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"type": "central",
|
||||
"url": "https://my.zerotier.com/"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
- Create a `Dockerfile` which will copy the ZeroTier service as well as the ZeroTier CLI to the image:
|
||||
|
||||
```
|
||||
FROM node:4.4
|
||||
EXPOSE 8080/tcp 9993/udp
|
||||
|
||||
# Install ZT network conf files
|
||||
RUN mkdir -p /var/lib/zerotier-one/networks.d
|
||||
ADD *.conf /var/lib/zerotier-one/networks.d/
|
||||
ADD *.conf /
|
||||
ADD zerotier-one /
|
||||
ADD zerotier-cli /
|
||||
ADD .zerotierCliSettings /
|
||||
|
||||
# Install App
|
||||
ADD server.js /
|
||||
|
||||
# script which will start/auth VM on ZT network
|
||||
ADD entrypoint.sh /
|
||||
RUN chmod -v +x /entrypoint.sh
|
||||
|
||||
CMD ["./entrypoint.sh"]
|
||||
```
|
||||
|
||||
- Create the `entrypoint.sh` script which will start the ZeroTier service in the VM, attempt to join your deployment network and automatically authorize the new VM if your network is set to private:
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
|
||||
echo '*** ZeroTier-Kubernetes self-auth test script'
|
||||
chown -R daemon /var/lib/zerotier-one
|
||||
chgrp -R daemon /var/lib/zerotier-one
|
||||
su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1'
|
||||
dev=""
|
||||
nwconf=$(ls *.conf)
|
||||
nwid="${nwconf%.*}"
|
||||
|
||||
sleep 10
|
||||
dev=$(cat /var/lib/zerotier-one/identity.public| cut -d ':' -f 1)
|
||||
|
||||
echo '*** Joining'
|
||||
./zerotier-cli join "$nwid".conf
|
||||
# Fill out local service auth token
|
||||
AUTHTOKEN=$(cat /var/lib/zerotier-one/authtoken.secret)
|
||||
sed "s|\local_service_auth_token_replaced_automatically|${AUTHTOKEN}|" .zerotierCliSettings > /root/.zerotierCliSettings
|
||||
echo '*** Authorizing'
|
||||
./zerotier-cli net-auth @my.zerotier.com "$nwid" "$dev"
|
||||
echo '*** Cleaning up' # Remove controller auth token
|
||||
rm -rf .zerotierCliSettings /root/.zerotierCliSettings
|
||||
node server.js
|
||||
```
|
||||
|
||||
**Step 5: Build the image:**
|
||||
|
||||
- `docker build -t gcr.io/$PROJECT_ID/hello-node .`
|
||||
|
||||
|
||||
|
||||
**Step 6: Push the docker image to your *Container Registry***
|
||||
|
||||
- `gcloud docker push gcr.io/$PROJECT_ID/hello-node:v1`
|
||||
|
||||
***
|
||||
## Deploy!
|
||||
|
||||
**Step 7: Create Kubernetes Cluster**
|
||||
|
||||
- `gcloud config set compute/zone us-central1-a`
|
||||
|
||||
- `gcloud container clusters create hello-world`
|
||||
|
||||
- `gcloud container clusters get-credentials hello-world`
|
||||
|
||||
|
||||
|
||||
**Step 8: Create your pod**
|
||||
|
||||
- `kubectl run hello-node --image=gcr.io/$PROJECT_ID/hello-node:v1 --port=8080`
|
||||
|
||||
|
||||
|
||||
**Step 9: Scale**
|
||||
|
||||
- `kubectl scale deployment hello-node --replicas=4`
|
||||
|
||||
***
|
||||
## Verify
|
||||
|
||||
Now, after a minute or so you can use `zerotier-cli net-members <nwid>` to show all of your VM instances on your ZeroTier deployment network. If you haven't [configured your local CLI](https://github.com/zerotier/ZeroTierOne/tree/dev/cli), you can simply log into [my.zerotier.com](https://my.zerotier.com), go to *Networks -> nwid* to check that your VMs are indeed members of your private network. You should also note that the `entrypoint.sh` script will automatically delete your network controller API key once it has authorized your VM. This is merely a security measure and can be removed if needed.
|
23
doc/ext/kubernetes/entrypoint.sh
Normal file
23
doc/ext/kubernetes/entrypoint.sh
Normal file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo '*** ZeroTier-Kubernetes self-auth test script'
|
||||
chown -R daemon /var/lib/zerotier-one
|
||||
chgrp -R daemon /var/lib/zerotier-one
|
||||
su daemon -s /bin/bash -c '/zerotier-one -d -U -p9993 >>/tmp/zerotier-one.out 2>&1'
|
||||
dev=""
|
||||
nwconf=$(ls *.conf)
|
||||
nwid="${nwconf%.*}"
|
||||
|
||||
sleep 10
|
||||
dev=$(cat /var/lib/zerotier-one/identity.public| cut -d ':' -f 1)
|
||||
|
||||
echo '*** Joining'
|
||||
./zerotier-cli join "$nwid".conf
|
||||
# Fill out local service auth token
|
||||
AUTHTOKEN=$(cat /var/lib/zerotier-one/authtoken.secret)
|
||||
sed "s|\local_service_auth_token_replaced_automatically|${AUTHTOKEN}|" .zerotierCliSettings > /root/.zerotierCliSettings
|
||||
echo '*** Authorizing'
|
||||
./zerotier-cli net-auth @my.zerotier.com "$nwid" "$dev"
|
||||
echo '*** Cleaning up' # Remove controller auth token
|
||||
rm -rf .zerotierCliSettings /root/.zerotierCliSettings
|
||||
node server.js
|
8
doc/ext/kubernetes/server.js
Normal file
8
doc/ext/kubernetes/server.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
var http = require('http');
|
||||
var handleRequest = function(request, response) {
|
||||
console.log('Received request for URL: ' + request.url);
|
||||
response.writeHead(200);
|
||||
response.end('Hello World!');
|
||||
};
|
||||
var www = http.createServer(handleRequest);
|
||||
www.listen(8080);
|
83
doc/zerotier-cli.1
Normal file
83
doc/zerotier-cli.1
Normal file
|
@ -0,0 +1,83 @@
|
|||
.TH "ZEROTIER\-CLI" "1" "December 2016" "" ""
|
||||
.SH "NAME"
|
||||
\fBzerotier-cli\fR \- control local ZeroTier virtual network service
|
||||
.SH SYNOPSIS
|
||||
.P
|
||||
\fBzerotier\-cli\fP [\-switches] <command> [arguments]
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
\fBzerotier\-cli\fR provides a simple command line interface to the local JSON API of the ZeroTier virtual network endpoint service zerotier\-one(8)\.
|
||||
.P
|
||||
By default \fBzerotier\-cli\fR must be run as root or with \fBsudo\fP\|\. If you want to allow an unprivileged user to use \fBzerotier\-cli\fR to control the system ZeroTier service, you can create a local copy of the ZeroTier service authorization token in the user's home directory:
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
sudo cp /var/lib/zerotier\-one/authtoken\.secret /home/user/\.zeroTierOneAuthToken
|
||||
chown user /home/user/\.zeroTierOneAuthToken
|
||||
chmod 0600 /home/user/\.zeroTierOneAuthToken
|
||||
.fi
|
||||
.RE
|
||||
.P
|
||||
(The location of ZeroTier's service home may differ by platform\. See zerotier\-one(8)\.)
|
||||
.P
|
||||
Note that this gives the user the power to connect or disconnect the system to or from any virtual network, which is a significant permission\.
|
||||
.P
|
||||
\fBzerotier\-cli\fR has several command line arguments that are visible in \fBhelp\fP output\. The two most commonly used are \fB\-j\fP for raw JSON output and \fB\-D<path>\fP to specify an alternative ZeroTier service working directory\. Raw JSON output is easier to parse in scripts and also contains verbose details not present in the tabular output\. The \fB\-D<path>\fP option specifies where the service's zerotier\-one\.port and authtoken\.secret files are located if the service is not running at the default location for your system\.
|
||||
.SH COMMANDS
|
||||
.RS 0
|
||||
.IP \(bu 2
|
||||
\fBhelp\fP:
|
||||
Displays \fBzerotier\-cli\fR help\.
|
||||
.IP \(bu 2
|
||||
\fBinfo\fP:
|
||||
Shows information about this device including its 10\-digit ZeroTier address and apparent connection status\. Use \fB\-j\fP for more verbose output\.
|
||||
.IP \(bu 2
|
||||
\fBlistpeers\fP:
|
||||
This command lists the ZeroTier VL1 (virtual layer 1, the peer to peer network) peers this service knows about and has recently (within the past 30 minutes or so) communicated with\. These are not necessarily all the devices on your virtual network(s), and may also include a few devices not on any virtual network you've joined\. These are typically either root servers or network controllers\.
|
||||
.IP \(bu 2
|
||||
\fBlistnetworks\fP:
|
||||
This lists the networks your system belongs to and some information about them, such as any ZeroTier\-managed IP addresses you have been assigned\. (IP addresses assigned manually to ZeroTier interfaces will not be listed here\. Use the standard network interface commands to see these\.)
|
||||
.IP \(bu 2
|
||||
\fBjoin\fP:
|
||||
To join a network just use \fBjoin\fP and its 16\-digit hex network ID\. That's it\. Then use \fBlistnetworks\fP to see the status\. You'll either get a reply from the network controller with a certificate and other info such as IP assignments, or you'll get "access denied\." In this case you'll need the administrator of this network to authorize your device by its 10\-digit device ID (visible with \fBinfo\fP) on the network's controller\.
|
||||
.IP \(bu 2
|
||||
\fBleave\fP:
|
||||
Leaving a network is as easy as joining it\. This disconnects from the network and deletes its interface from the system\. Note that peers on the network may hang around in \fBlistpeers\fP for up to 30 minutes until they time out due to lack of traffic\. But if they no longer share a network with you, they can't actually communicate with you in any meaningful way\.
|
||||
|
||||
.RE
|
||||
.SH EXAMPLES
|
||||
.P
|
||||
Join "Earth," ZeroTier's big public party line network:
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
$ sudo zerotier\-cli join 8056c2e21c000001
|
||||
$ sudo zerotier\-cli listnetworks
|
||||
( wait until you get an Earth IP )
|
||||
$ ping earth\.zerotier\.net
|
||||
( you should now be able to ping our Earth test IP )
|
||||
.fi
|
||||
.RE
|
||||
.P
|
||||
Leave "Earth":
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
$ sudo zerotier\-cli leave 8056c2e21c000001
|
||||
.fi
|
||||
.RE
|
||||
.P
|
||||
List VL1 peers:
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
$ sudo zerotier\-cli listpeers
|
||||
.fi
|
||||
.RE
|
||||
.SH COPYRIGHT
|
||||
.P
|
||||
(c)2011\-2016 ZeroTier, Inc\. \-\- https://www\.zerotier\.com/ \-\- https://github\.com/zerotier
|
||||
.SH SEE ALSO
|
||||
.P
|
||||
zerotier\-one(8), zerotier\-idtool(1)
|
||||
|
84
doc/zerotier-idtool.1
Normal file
84
doc/zerotier-idtool.1
Normal file
|
@ -0,0 +1,84 @@
|
|||
.TH "ZEROTIER\-IDTOOL" "1" "December 2016" "" ""
|
||||
.SH "NAME"
|
||||
\fBzerotier-idtool\fR \- tool for creating and manipulating ZeroTier identities
|
||||
.SH SYNOPSIS
|
||||
.P
|
||||
\fBzerotier\-idtool\fP <command> [args]
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
\fBzerotier\-idtool\fR is a command line utility for doing things with ZeroTier identities\. A ZeroTier identity consists of a public/private key pair (or just the public if it's only an identity\.public) and a 10\-digit hexadecimal ZeroTier address derived from the public key by way of a proof of work based hash function\.
|
||||
.SH COMMANDS
|
||||
.P
|
||||
When command arguments call for a public or secret (full) identity, the identity can be specified as a path to a file or directly on the command line\.
|
||||
.RS 0
|
||||
.IP \(bu 2
|
||||
\fBhelp\fP:
|
||||
Display help\. (Also running with no command does this\.)
|
||||
.IP \(bu 2
|
||||
\fBgenerate\fP [secret file] [public file] [vanity]:
|
||||
Generate a new ZeroTier identity\. If a secret file is specified, the full identity including the private key will be written to this file\. If the public file is specified, the public portion will be written there\. If no file paths are specified the full secret identity is output to STDOUT\. The vanity prefix is a series of hexadecimal digits that the generated identity's address should start with\. Typically this isn't used, and if it's specified generation can take a very long time due to the intrinsic cost of generating identities with their proof of work function\. Generating an identity with a known 16\-bit (4 digit) prefix on a 2\.8ghz Core i5 (using one core) takes an average of two hours\.
|
||||
.IP \(bu 2
|
||||
\fBvalidate\fP <identity, only public part required>:
|
||||
Locally validate an identity's key and proof of work function correspondence\.
|
||||
.IP \(bu 2
|
||||
\fBgetpublic\fP <full identity with secret>:
|
||||
Extract the public portion of an identity\.secret and print to STDOUT\.
|
||||
.IP \(bu 2
|
||||
\fBsign\fP <full identity with secret> <file to sign>:
|
||||
Sign a file's contents with SHA512+ECC\-256 (ed25519)\. The signature is output in hex to STDOUT\.
|
||||
.IP \(bu 2
|
||||
\fBverify\fP <identity, only public part required> <file to check> <signature in hex>:
|
||||
Verify a signature created with \fBsign\fP\|\.
|
||||
.IP \(bu 2
|
||||
\fBmkcom\fP <full identity with secret> [id,value,maxdelta] [\|\.\.\.]:
|
||||
Create and sign a network membership certificate\. This is not generally useful since network controllers do this automatically and is included mostly for testing purposes\.
|
||||
|
||||
.RE
|
||||
.SH EXAMPLES
|
||||
.P
|
||||
Generate and dump a new identity:
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
$ zerotier\-idtool generate
|
||||
.fi
|
||||
.RE
|
||||
.P
|
||||
Generate and write a new identity, both secret and public parts:
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
$ zerotier\-idtool generate identity\.secret identity\.public
|
||||
.fi
|
||||
.RE
|
||||
.P
|
||||
Generate a vanity address that begins with the hex digits "beef" (this will take a while!):
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
$ zerotier\-idtool generate beef\.secret beef\.public beef
|
||||
.fi
|
||||
.RE
|
||||
.P
|
||||
Sign a file with an identity's secret key:
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
$ zerotier\-idtool sign identity\.secret last_will_and_testament\.txt
|
||||
.fi
|
||||
.RE
|
||||
.P
|
||||
Verify a file's signature with a public key:
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
$ zerotier\-idtool verify identity\.public last_will_and_testament\.txt
|
||||
.fi
|
||||
.RE
|
||||
.SH COPYRIGHT
|
||||
.P
|
||||
(c)2011\-2016 ZeroTier, Inc\. \-\- https://www\.zerotier\.com/ \-\- https://github\.com/zerotier
|
||||
.SH SEE ALSO
|
||||
.P
|
||||
zerotier\-one(8), zerotier\-cli(1)
|
||||
|
104
doc/zerotier-one.8
Normal file
104
doc/zerotier-one.8
Normal file
|
@ -0,0 +1,104 @@
|
|||
.TH "ZEROTIER\-ONE" "8" "December 2016" "" ""
|
||||
.SH "NAME"
|
||||
\fBzerotier-one\fR \- ZeroTier virtual network endpoint service
|
||||
.SH SYNOPSIS
|
||||
.P
|
||||
\fBzerotier\-one\fP [\-switches] [working directory]
|
||||
.SH DESCRIPTION
|
||||
.P
|
||||
\fBzerotier\-one\fR is the service/daemon responsible for connecting a Unix (Linux/BSD/OSX) system to one or more ZeroTier virtual networks and presenting those networks to the system as virtual network ports\. You can think of it as a peer to peer VPN client\.
|
||||
.P
|
||||
It's typically run by init systems like systemd (Linux) or launchd (Mac) rather than directly by the user, and it must be run as root unless you give it the \fB\-U\fP switch and don't plan on actually joining networks (e\.g\. to run a network controller microservice only)\.
|
||||
.P
|
||||
The \fBzerotier\-one\fR service keeps its state and other files in a working directory\. If this directory is not specified at launch it defaults to "/var/lib/zerotier\-one" on Linux, "/Library/Application Support/ZeroTier/One" on Mac, and "/var/db/zerotier\-one" on FreeBSD and other similar BSDs\. The working directory should persist\. It shouldn't be automatically cleaned by system cleanup daemons or stored in a volatile location\. Loss of its identity\.secret file results in loss of this system's unique 10\-digit ZeroTier address and key\.
|
||||
.P
|
||||
Multiple instances of \fBzerotier\-one\fR can be run on the same system as long as they are run with different primary ports (see switches) and a different working directory\. But since a single service can join any number of networks, typically there's no point in doing this\.
|
||||
.P
|
||||
The \fBzerotier\-one\fR service is controlled via a JSON API available at 127\.0\.0\.1:<primary port> with the default primary port being 9993\. Access to this API requires an authorization token normally found in the authtoken\.secret file in the service's working directory\. On some platforms access may be guarded by other measures such as socket peer UID/GID lookup if additional security options are enabled (this is not the default)\.
|
||||
.P
|
||||
The first time the service is started in a fresh working directory, it generates a ZeroTier identity\. On slow systems this process can take ten seconds or more due to an anti\-DDOS/anti\-counterfeit proof of work function used by ZeroTier in address generation\. This only happens once, and once generated the result is saved in identity\.secret in the working directory\. This file represents and defines/claims your ZeroTier address and associated ECC\-256 key pair\.
|
||||
.SH SWITCHES
|
||||
.RS 0
|
||||
.IP \(bu 2
|
||||
\fB\-h\fP:
|
||||
Display help\.
|
||||
.IP \(bu 2
|
||||
\fB\-v\fP:
|
||||
Display ZeroTier One version\.
|
||||
.IP \(bu 2
|
||||
\fB\-U\fP:
|
||||
Skip privilege check and allow to be run by non\-privileged user\. This is typically used when \fBzerotier\-one\fR is built with the network controller option included\. In this case the ZeroTier service might only be acting as a network controller and might never actually join networks, in which case it does not require elevated system permissions\.
|
||||
.IP \(bu 2
|
||||
\fB\-p<port>\fP:
|
||||
Specify a different primary port\. If this is not given the default is 9993\. If zero is given a random port is chosen each time\.
|
||||
.IP \(bu 2
|
||||
\fB\-d\fP:
|
||||
Fork and run as a daemon\.
|
||||
.IP \(bu 2
|
||||
\fB\-i\fP:
|
||||
Invoke the \fBzerotier\-idtool\fR personality, in which case the binary behaves like zerotier\-idtool(1)\. This happens automatically if the name of the binary (or a symlink to it) is zerotier\-idtool\.
|
||||
.IP \(bu 2
|
||||
\fB\-q\fP:
|
||||
Invoke the \fBzerotier\-cli\fR personality, in which case the binary behaves like zerotier\-cli(1)\. This happens automatically if the name of the binary (or a symlink to it) is zerotier\-cli\.
|
||||
|
||||
.RE
|
||||
.SH EXAMPLES
|
||||
.P
|
||||
Run as daemon with OS default working directory and default port:
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
$ sudo zerotier\-one \-d
|
||||
.fi
|
||||
.RE
|
||||
.P
|
||||
Run as daemon with a different working directory and port:
|
||||
.P
|
||||
.RS 2
|
||||
.nf
|
||||
$ sudo zerotier\-one \-d \-p12345 /tmp/zerotier\-working\-directory\-test
|
||||
.fi
|
||||
.RE
|
||||
.SH FILES
|
||||
.P
|
||||
These are found in the service's working directory\.
|
||||
.RS 0
|
||||
.IP \(bu 2
|
||||
\fBidentity\.public\fP:
|
||||
The public portion of your ZeroTier identity, which is your 10\-digit hex address and the associated public key\.
|
||||
.IP \(bu 2
|
||||
\fBidentity\.secret\fP:
|
||||
Your full ZeroTier identity including its private key\. This file identifies the system on the network, which means you can move a ZeroTier address around by copying this file and you should back up this file if you want to save your system's static ZeroTier address\. This file must be protected, since theft of its secret key will allow anyone to impersonate your device on any network and decrypt traffic\. For network controllers this file is particularly sensitive since it constitutes the private key for a certificate authority for the controller's networks\.
|
||||
.IP \(bu 2
|
||||
\fBauthtoken\.secret\fP:
|
||||
The secret token used to authenticate requests to the service's local JSON API\. If it does not exist it is generated from a secure random source on service start\. To use, send it in the "X\-ZT1\-Auth" header with HTTP requests to 127\.0\.0\.1:<primary port>\|\.
|
||||
.IP \(bu 2
|
||||
\fBdevicemap\fP:
|
||||
Remembers mappings of zt# interface numbers to ZeroTier networks so they'll persist across restarts\. On some systems that support longer interface names that can encode the network ID (such as FreeBSD) this file may not be present\.
|
||||
.IP \(bu 2
|
||||
\fBzerotier\-one\.pid\fP:
|
||||
ZeroTier's PID\. This file is deleted on normal shutdown\.
|
||||
.IP \(bu 2
|
||||
\fBzerotier\-one\.port\fP:
|
||||
ZeroTier's primary port, which is also where its JSON API is found at 127\.0\.0\.1:<this port>\|\. This file is created on startup and is read by zerotier\-cli(1) to determine where it should find the control API\.
|
||||
.IP \(bu 2
|
||||
\fBcontroller\.db\fP:
|
||||
If the ZeroTier One service is built with the network controller enabled, this file contains the controller's SQLite3 database\.
|
||||
.IP \(bu 2
|
||||
\fBcontroller\.db\.backup\fP:
|
||||
If the ZeroTier One service is built with the network controller enabled, it periodically backs up its controller\.db database in this file (currently every 5 minutes if there have been changes)\. Since this file is not a currently in use SQLite3 database it's safer to back up without corruption\. On new backups the file is rotated out rather than being rewritten in place\.
|
||||
.IP \(bu 2
|
||||
\fBiddb\.d/\fP (directory):
|
||||
Caches the public identity of every peer ZeroTier has spoken with in the last 60 days\. This directory and its contents can be deleted, but this may result in slower connection initations since it will require that we go out and re\-fetch full identities for peers we're speaking to\.
|
||||
.IP \(bu 2
|
||||
\fBnetworks\.d\fP (directory):
|
||||
This caches network configurations and certificate information for networks you belong to\. ZeroTier scans this directory for <network ID>\|\.conf files on startup to recall its networks, so "touch"ing an empty <network ID>\|\.conf file in this directory is a way of pre\-configuring ZeroTier to join a specific network on startup without using the API\. If the config file is empty ZeroTIer will just fetch it from the network's controller\.
|
||||
|
||||
.RE
|
||||
.SH COPYRIGHT
|
||||
.P
|
||||
(c)2011\-2016 ZeroTier, Inc\. \-\- https://www\.zerotier\.com/ \-\- https://github\.com/zerotier
|
||||
.SH SEE ALSO
|
||||
.P
|
||||
zerotier\-cli(1), zerotier\-idtool(1)
|
||||
|
6
ext/arm32-neon-salsa2012-asm/README.md
Normal file
6
ext/arm32-neon-salsa2012-asm/README.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
ARM NEON (32-bit) ASM implementation of Salsa20/12
|
||||
======
|
||||
|
||||
This is from [supercop](http://bench.cr.yp.to/supercop.html) and was originally written by Daniel J. Bernstein. Code is in the public domain like the rest of Salsa20. It's much faster than the naive implementation.
|
||||
|
||||
It's included automatically in 32-bit Linux ARM builds. It likely will not work on 64-bit ARM, so it'll need to be ported at least. That will unfortunately keep it out of mobile versions for now since those are all going 64-bit.
|
23
ext/arm32-neon-salsa2012-asm/salsa2012.h
Normal file
23
ext/arm32-neon-salsa2012-asm/salsa2012.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef ZT_SALSA2012_ARM32NEON_ASM
|
||||
#define ZT_SALSA2012_ARM32NEON_ASM
|
||||
|
||||
#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
|
||||
#include <sys/auxv.h>
|
||||
#include <asm/hwcap.h>
|
||||
#define zt_arm_has_neon() ((getauxval(AT_HWCAP) & HWCAP_NEON) != 0)
|
||||
#else
|
||||
#define zt_arm_has_neon() (true)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// ciphertext buffer, message/NULL, length, nonce (8 bytes), key (32 bytes)
|
||||
extern int zt_salsa2012_armneon3_xor(unsigned char *c,const unsigned char *m,unsigned long long len,const unsigned char *n,const unsigned char *k);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
2231
ext/arm32-neon-salsa2012-asm/salsa2012.s
Normal file
2231
ext/arm32-neon-salsa2012-asm/salsa2012.s
Normal file
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
|
@ -1,79 +0,0 @@
|
|||
[Version]
|
||||
Signature="$WINDOWS NT$"
|
||||
Class=Net
|
||||
ClassGuid={4d36e972-e325-11ce-bfc1-08002be10318}
|
||||
Provider=%Provider%
|
||||
CatalogFile=zttap200.cat
|
||||
DriverVer=01/23/2014,15.19.17.816
|
||||
|
||||
[Strings]
|
||||
DeviceDescription = "ZeroTier One Virtual Network Port"
|
||||
Provider = "ZeroTier Networks LLC"
|
||||
|
||||
; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back!
|
||||
[Manufacturer]
|
||||
%Provider%=zttap200,NTamd64
|
||||
|
||||
[zttap200]
|
||||
%DeviceDescription%=zttap200.ndi,zttap200
|
||||
|
||||
[ztTap200.NTamd64]
|
||||
%DeviceDescription%=zttap200.ndi,zttap200
|
||||
|
||||
[zttap200.ndi]
|
||||
CopyFiles = zttap200.driver,zttap200.files
|
||||
AddReg = zttap200.reg
|
||||
AddReg = zttap200.params.reg
|
||||
Characteristics = 0x81
|
||||
|
||||
[zttap200.ndi.Services]
|
||||
AddService = zttap200, 2, zttap200.service
|
||||
|
||||
[zttap200.reg]
|
||||
HKR, Ndi, Service, 0, "zttap200"
|
||||
HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
|
||||
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
|
||||
HKR, , Manufacturer, 0, "%Provider%"
|
||||
HKR, , ProductName, 0, "%DeviceDescription%"
|
||||
|
||||
[zttap200.params.reg]
|
||||
HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
|
||||
HKR, Ndi\params\MTU, Type, 0, "int"
|
||||
HKR, Ndi\params\MTU, Default, 0, "2800"
|
||||
HKR, Ndi\params\MTU, Optional, 0, "0"
|
||||
HKR, Ndi\params\MTU, Min, 0, "100"
|
||||
HKR, Ndi\params\MTU, Max, 0, "2800"
|
||||
HKR, Ndi\params\MTU, Step, 0, "1"
|
||||
HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status"
|
||||
HKR, Ndi\params\MediaStatus, Type, 0, "enum"
|
||||
HKR, Ndi\params\MediaStatus, Default, 0, "0"
|
||||
HKR, Ndi\params\MediaStatus, Optional, 0, "0"
|
||||
HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled"
|
||||
HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected"
|
||||
HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address"
|
||||
HKR, Ndi\params\MAC, Type, 0, "edit"
|
||||
HKR, Ndi\params\MAC, Optional, 0, "1"
|
||||
|
||||
[zttap200.service]
|
||||
DisplayName = %DeviceDescription%
|
||||
ServiceType = 1
|
||||
StartType = 3
|
||||
ErrorControl = 1
|
||||
LoadOrderGroup = NDIS
|
||||
ServiceBinary = %12%\zttap200.sys
|
||||
|
||||
[SourceDisksNames]
|
||||
1 = %DeviceDescription%, zttap200.sys
|
||||
|
||||
[SourceDisksFiles]
|
||||
zttap200.sys = 1
|
||||
|
||||
[DestinationDirs]
|
||||
zttap200.files = 11
|
||||
zttap200.driver = 12
|
||||
|
||||
[zttap200.files]
|
||||
;
|
||||
|
||||
[zttap200.driver]
|
||||
zttap200.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,76 +0,0 @@
|
|||
[Version]
|
||||
Signature="$WINDOWS NT$"
|
||||
Class=Net
|
||||
ClassGuid={4d36e972-e325-11ce-bfc1-08002be10318}
|
||||
Provider=%Provider%
|
||||
CatalogFile=zttap200.cat
|
||||
DriverVer=01/24/2014,17.25.51.226
|
||||
|
||||
[Strings]
|
||||
DeviceDescription = "ZeroTier One Virtual Network Port"
|
||||
Provider = "ZeroTier Networks LLC"
|
||||
|
||||
; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back!
|
||||
[Manufacturer]
|
||||
%Provider%=zttap200
|
||||
|
||||
[zttap200]
|
||||
%DeviceDescription%=zttap200.ndi,zttap200
|
||||
|
||||
[zttap200.ndi]
|
||||
CopyFiles = zttap200.driver,zttap200.files
|
||||
AddReg = zttap200.reg
|
||||
AddReg = zttap200.params.reg
|
||||
Characteristics = 0x81
|
||||
|
||||
[zttap200.ndi.Services]
|
||||
AddService = zttap200, 2, zttap200.service
|
||||
|
||||
[zttap200.reg]
|
||||
HKR, Ndi, Service, 0, "zttap200"
|
||||
HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
|
||||
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
|
||||
HKR, , Manufacturer, 0, "%Provider%"
|
||||
HKR, , ProductName, 0, "%DeviceDescription%"
|
||||
|
||||
[zttap200.params.reg]
|
||||
HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
|
||||
HKR, Ndi\params\MTU, Type, 0, "int"
|
||||
HKR, Ndi\params\MTU, Default, 0, "2800"
|
||||
HKR, Ndi\params\MTU, Optional, 0, "0"
|
||||
HKR, Ndi\params\MTU, Min, 0, "100"
|
||||
HKR, Ndi\params\MTU, Max, 0, "2800"
|
||||
HKR, Ndi\params\MTU, Step, 0, "1"
|
||||
HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status"
|
||||
HKR, Ndi\params\MediaStatus, Type, 0, "enum"
|
||||
HKR, Ndi\params\MediaStatus, Default, 0, "0"
|
||||
HKR, Ndi\params\MediaStatus, Optional, 0, "0"
|
||||
HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled"
|
||||
HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected"
|
||||
HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address"
|
||||
HKR, Ndi\params\MAC, Type, 0, "edit"
|
||||
HKR, Ndi\params\MAC, Optional, 0, "1"
|
||||
|
||||
[zttap200.service]
|
||||
DisplayName = %DeviceDescription%
|
||||
ServiceType = 1
|
||||
StartType = 3
|
||||
ErrorControl = 1
|
||||
LoadOrderGroup = NDIS
|
||||
ServiceBinary = %12%\zttap200.sys
|
||||
|
||||
[SourceDisksNames]
|
||||
1 = %DeviceDescription%, zttap200.sys
|
||||
|
||||
[SourceDisksFiles]
|
||||
zttap200.sys = 1
|
||||
|
||||
[DestinationDirs]
|
||||
zttap200.files = 11
|
||||
zttap200.driver = 12
|
||||
|
||||
[zttap200.files]
|
||||
;
|
||||
|
||||
[zttap200.driver]
|
||||
zttap200.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1366,12 +1366,7 @@ reexecute:
|
|||
|| c != CONTENT_LENGTH[parser->index]) {
|
||||
parser->header_state = h_general;
|
||||
} else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
|
||||
if (parser->flags & F_CONTENTLENGTH) {
|
||||
SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
|
||||
goto error;
|
||||
}
|
||||
parser->header_state = h_content_length;
|
||||
parser->flags |= F_CONTENTLENGTH;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1474,6 +1469,12 @@ reexecute:
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (parser->flags & F_CONTENTLENGTH) {
|
||||
SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
|
||||
goto error;
|
||||
}
|
||||
|
||||
parser->flags |= F_CONTENTLENGTH;
|
||||
parser->content_length = ch - '0';
|
||||
break;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ extern "C" {
|
|||
/* Also update SONAME in the Makefile whenever you change these. */
|
||||
#define HTTP_PARSER_VERSION_MAJOR 2
|
||||
#define HTTP_PARSER_VERSION_MINOR 7
|
||||
#define HTTP_PARSER_VERSION_PATCH 0
|
||||
#define HTTP_PARSER_VERSION_PATCH 1
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && \
|
||||
|
@ -90,6 +90,76 @@ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
|
|||
typedef int (*http_cb) (http_parser*);
|
||||
|
||||
|
||||
/* Status Codes */
|
||||
#define HTTP_STATUS_MAP(XX) \
|
||||
XX(100, CONTINUE, Continue) \
|
||||
XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \
|
||||
XX(102, PROCESSING, Processing) \
|
||||
XX(200, OK, OK) \
|
||||
XX(201, CREATED, Created) \
|
||||
XX(202, ACCEPTED, Accepted) \
|
||||
XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \
|
||||
XX(204, NO_CONTENT, No Content) \
|
||||
XX(205, RESET_CONTENT, Reset Content) \
|
||||
XX(206, PARTIAL_CONTENT, Partial Content) \
|
||||
XX(207, MULTI_STATUS, Multi-Status) \
|
||||
XX(208, ALREADY_REPORTED, Already Reported) \
|
||||
XX(226, IM_USED, IM Used) \
|
||||
XX(300, MULTIPLE_CHOICES, Multiple Choices) \
|
||||
XX(301, MOVED_PERMANENTLY, Moved Permanently) \
|
||||
XX(302, FOUND, Found) \
|
||||
XX(303, SEE_OTHER, See Other) \
|
||||
XX(304, NOT_MODIFIED, Not Modified) \
|
||||
XX(305, USE_PROXY, Use Proxy) \
|
||||
XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \
|
||||
XX(308, PERMANENT_REDIRECT, Permanent Redirect) \
|
||||
XX(400, BAD_REQUEST, Bad Request) \
|
||||
XX(401, UNAUTHORIZED, Unauthorized) \
|
||||
XX(402, PAYMENT_REQUIRED, Payment Required) \
|
||||
XX(403, FORBIDDEN, Forbidden) \
|
||||
XX(404, NOT_FOUND, Not Found) \
|
||||
XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \
|
||||
XX(406, NOT_ACCEPTABLE, Not Acceptable) \
|
||||
XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \
|
||||
XX(408, REQUEST_TIMEOUT, Request Timeout) \
|
||||
XX(409, CONFLICT, Conflict) \
|
||||
XX(410, GONE, Gone) \
|
||||
XX(411, LENGTH_REQUIRED, Length Required) \
|
||||
XX(412, PRECONDITION_FAILED, Precondition Failed) \
|
||||
XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \
|
||||
XX(414, URI_TOO_LONG, URI Too Long) \
|
||||
XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \
|
||||
XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \
|
||||
XX(417, EXPECTATION_FAILED, Expectation Failed) \
|
||||
XX(421, MISDIRECTED_REQUEST, Misdirected Request) \
|
||||
XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \
|
||||
XX(423, LOCKED, Locked) \
|
||||
XX(424, FAILED_DEPENDENCY, Failed Dependency) \
|
||||
XX(426, UPGRADE_REQUIRED, Upgrade Required) \
|
||||
XX(428, PRECONDITION_REQUIRED, Precondition Required) \
|
||||
XX(429, TOO_MANY_REQUESTS, Too Many Requests) \
|
||||
XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
|
||||
XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \
|
||||
XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \
|
||||
XX(501, NOT_IMPLEMENTED, Not Implemented) \
|
||||
XX(502, BAD_GATEWAY, Bad Gateway) \
|
||||
XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \
|
||||
XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \
|
||||
XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \
|
||||
XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \
|
||||
XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \
|
||||
XX(508, LOOP_DETECTED, Loop Detected) \
|
||||
XX(510, NOT_EXTENDED, Not Extended) \
|
||||
XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
|
||||
|
||||
enum http_status
|
||||
{
|
||||
#define XX(num, name, string) HTTP_STATUS_##name = num,
|
||||
HTTP_STATUS_MAP(XX)
|
||||
#undef XX
|
||||
};
|
||||
|
||||
|
||||
/* Request Methods */
|
||||
#define HTTP_METHOD_MAP(XX) \
|
||||
XX(0, DELETE, DELETE) \
|
||||
|
|
20
ext/installfiles/linux/zerotier-containerized/Dockerfile
Normal file
20
ext/installfiles/linux/zerotier-containerized/Dockerfile
Normal file
|
@ -0,0 +1,20 @@
|
|||
FROM alpine:latest
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
LABEL version="1.1.14"
|
||||
LABEL description="Containerized ZeroTier One for use on CoreOS or other Docker-only Linux hosts."
|
||||
|
||||
# Uncomment to build in container
|
||||
#RUN apk add --update alpine-sdk linux-headers
|
||||
|
||||
RUN apk add --update libgcc libstdc++
|
||||
|
||||
ADD zerotier-one /
|
||||
RUN chmod 0755 /zerotier-one
|
||||
RUN ln -sf /zerotier-one /zerotier-cli
|
||||
RUN mkdir -p /var/lib/zerotier-one
|
||||
|
||||
ADD main.sh /
|
||||
RUN chmod 0755 /main.sh
|
||||
|
||||
ENTRYPOINT /main.sh
|
10
ext/installfiles/linux/zerotier-containerized/main.sh
Executable file
10
ext/installfiles/linux/zerotier-containerized/main.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin
|
||||
|
||||
if [ ! -e /dev/net/tun ]; then
|
||||
echo 'FATAL: cannot start ZeroTier One in container: /dev/net/tun not present.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec /zerotier-one
|
49
ext/installfiles/mac-update/updater.tmpl.sh
Normal file
49
ext/installfiles/mac-update/updater.tmpl.sh
Normal file
|
@ -0,0 +1,49 @@
|
|||
#!/bin/bash
|
||||
|
||||
export PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
||||
shopt -s expand_aliases
|
||||
|
||||
if [ "$UID" -ne 0 ]; then
|
||||
echo '*** Auto-updater must be run as root.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
scriptPath="`dirname "$0"`/`basename "$0"`"
|
||||
if [ ! -s "$scriptPath" ]; then
|
||||
scriptPath="$0"
|
||||
if [ ! -s "$scriptPath" ]; then
|
||||
echo "*** Auto-updater cannot determine its own path; $scriptPath is not readable."
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
endMarkerIndex=`grep -a -b -E '^################' "$scriptPath" | head -c 16 | cut -d : -f 1`
|
||||
if [ "$endMarkerIndex" -le 100 ]; then
|
||||
echo 'Internal error: unable to find end of script / start of binary data marker.'
|
||||
exit 2
|
||||
fi
|
||||
blobStart=`expr $endMarkerIndex + 17`
|
||||
if [ "$blobStart" -le "$endMarkerIndex" ]; then
|
||||
echo 'Internal error: unable to find end of script / start of binary data marker.'
|
||||
exit 2
|
||||
fi
|
||||
|
||||
rm -f /tmp/ZeroTierOne-update.pkg
|
||||
tail -c +$blobStart "$scriptPath" >/tmp/ZeroTierOne-update.pkg
|
||||
chmod 0600 /tmp/ZeroTierOne-update.pkg
|
||||
|
||||
if [ -s /tmp/ZeroTierOne-update.pkg ]; then
|
||||
rm -f '/Library/Application Support/ZeroTier/One/latest-update.exe' '/Library/Application Support/ZeroTier/One/latest-update.json' /tmp/ZeroTierOne-update.log
|
||||
installer -verbose -pkg /tmp/ZeroTierOne-update.pkg -target / >/tmp/ZeroTierOne-update.log 2>&1
|
||||
rm -f /tmp/ZeroTierOne-update.pkg
|
||||
exit 0
|
||||
else
|
||||
echo '*** Error self-unpacking update!'
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# Do not remove the last line or add a carriage return to it! The installer
|
||||
# looks for an unterminated line beginning with 16 #'s in itself to find
|
||||
# the binary blob data, which is appended after it.
|
||||
|
||||
################
|
|
@ -37,7 +37,7 @@
|
|||
<key>GID</key>
|
||||
<integer>80</integer>
|
||||
<key>PATH</key>
|
||||
<string>mac-ui-macgap1-wrapper/bin/ZeroTier One.app</string>
|
||||
<string>../../../macui/build/Release/ZeroTier One.app</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
|
@ -121,119 +121,6 @@
|
|||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>ui/index.html</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>420</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>3</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>ui/main.js</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>420</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>3</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>ui/react.min.js</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>420</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>3</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>ui/simpleajax.min.js</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>420</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>3</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>ui/zerotier.css</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>420</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>3</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>ui/ztui.min.js</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>1</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>420</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>3</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GID</key>
|
||||
<integer>0</integer>
|
||||
<key>PATH</key>
|
||||
<string>ui</string>
|
||||
<key>PATH_TYPE</key>
|
||||
<integer>0</integer>
|
||||
<key>PERMISSIONS</key>
|
||||
<integer>493</integer>
|
||||
<key>TYPE</key>
|
||||
<integer>2</integer>
|
||||
<key>UID</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CHILDREN</key>
|
||||
<array/>
|
||||
|
@ -759,7 +646,7 @@
|
|||
<key>OVERWRITE_PERMISSIONS</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>1.1.14</string>
|
||||
<string>1.2.4</string>
|
||||
</dict>
|
||||
<key>PROJECT_COMMENTS</key>
|
||||
<dict>
|
||||
|
@ -773,7 +660,7 @@
|
|||
ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KPHRp
|
||||
dGxlPjwvdGl0bGU+CjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29u
|
||||
dGVudD0iQ29jb2EgSFRNTCBXcml0ZXIiPgo8bWV0YSBuYW1lPSJD
|
||||
b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjE0MDQuNDciPgo8c3R5bGUg
|
||||
b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjE1MDQuNzYiPgo8c3R5bGUg
|
||||
dHlwZT0idGV4dC9jc3MiPgpwLnAxIHttYXJnaW46IDAuMHB4IDAu
|
||||
MHB4IDAuMHB4IDAuMHB4OyBsaW5lLWhlaWdodDogMTQuMHB4OyBm
|
||||
b250OiAxMi4wcHggSGVsdmV0aWNhOyBjb2xvcjogIzAwMDAwMDsg
|
||||
|
@ -782,7 +669,7 @@
|
|||
b2R5Pgo8cCBjbGFzcz0icDEiPjxzcGFuIGNsYXNzPSJzMSI+WmVy
|
||||
b1RpZXIgT25lIC0gTmV0d29yayBWaXJ0dWFsaXphdGlvbiBFdmVy
|
||||
eXdoZXJlPC9zcGFuPjwvcD4KPHAgY2xhc3M9InAxIj48c3BhbiBj
|
||||
bGFzcz0iczEiPihjKTIwMTEtMjAxNiBaZXJvVGllciwgSW5jLjwv
|
||||
bGFzcz0iczEiPihjKTIwMTEtMjAxNyBaZXJvVGllciwgSW5jLjwv
|
||||
c3Bhbj48L3A+CjxwIGNsYXNzPSJwMSI+PHNwYW4gY2xhc3M9InMx
|
||||
Ij5jb250YWN0QHplcm90aWVyLmNvbTwvc3Bhbj48L3A+CjxwIGNs
|
||||
YXNzPSJwMSI+PHNwYW4gY2xhc3M9InMxIj48YnI+Cjwvc3Bhbj48
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildMachineOSBuild</key>
|
||||
<string>15B42</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>ZeroTier One</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>ZeroTierIcon</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.zerotier.ZeroTier-One</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>ZeroTier One</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>DTCompiler</key>
|
||||
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||
<key>DTPlatformBuild</key>
|
||||
<string>7B1005</string>
|
||||
<key>DTPlatformVersion</key>
|
||||
<string>GM</string>
|
||||
<key>DTSDKBuild</key>
|
||||
<string>15A278</string>
|
||||
<key>DTSDKName</key>
|
||||
<string>macosx10.11</string>
|
||||
<key>DTXcode</key>
|
||||
<string>0711</string>
|
||||
<key>DTXcodeBuild</key>
|
||||
<string>7B1005</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.7</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
APPL????
|
|
@ -1,13 +0,0 @@
|
|||
{\rtf1\ansi\ansicpg1252\cocoartf1347\cocoasubrtf570
|
||||
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
\vieww9600\viewh8400\viewkind0
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
|
||||
|
||||
\f0\b\fs24 \cf0 (c)2011-2015 ZeroTier, Inc.\
|
||||
Licensed under the GNU GPLv3\
|
||||
\
|
||||
UI Wrapper MacGap (c) Twitter, Inc.\
|
||||
Licensed under the MIT License\
|
||||
http://macgap.com/\
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,187 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>files</key>
|
||||
<dict>
|
||||
<key>Resources/ZeroTierIcon.icns</key>
|
||||
<data>
|
||||
430Gd+4+jnim7WxXEEugp6G+Tgk=
|
||||
</data>
|
||||
<key>Resources/en.lproj/Credits.rtf</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
ePttkAH2X1GJ6OL0UhDBAktxB3Y=
|
||||
</data>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Resources/en.lproj/InfoPlist.strings</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
MiLKDDnrUKr4EmuvhS5VQwxHGK8=
|
||||
</data>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Resources/en.lproj/MainMenu.nib</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
8JZXf4/3df3LD+o74Y8WM0dV8io=
|
||||
</data>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Resources/en.lproj/Window.nib</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
aP0mIANPPnnTMmxYlELioz9ZO1I=
|
||||
</data>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>files2</key>
|
||||
<dict>
|
||||
<key>Resources/ZeroTierIcon.icns</key>
|
||||
<data>
|
||||
430Gd+4+jnim7WxXEEugp6G+Tgk=
|
||||
</data>
|
||||
<key>Resources/en.lproj/Credits.rtf</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
ePttkAH2X1GJ6OL0UhDBAktxB3Y=
|
||||
</data>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Resources/en.lproj/InfoPlist.strings</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
MiLKDDnrUKr4EmuvhS5VQwxHGK8=
|
||||
</data>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Resources/en.lproj/MainMenu.nib</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
8JZXf4/3df3LD+o74Y8WM0dV8io=
|
||||
</data>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Resources/en.lproj/Window.nib</key>
|
||||
<dict>
|
||||
<key>hash</key>
|
||||
<data>
|
||||
aP0mIANPPnnTMmxYlELioz9ZO1I=
|
||||
</data>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>rules</key>
|
||||
<dict>
|
||||
<key>^Resources/</key>
|
||||
<true/>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^version.plist$</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>rules2</key>
|
||||
<dict>
|
||||
<key>.*\.dSYM($|/)</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>11</real>
|
||||
</dict>
|
||||
<key>^(.*/)?\.DS_Store$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>2000</real>
|
||||
</dict>
|
||||
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^Info\.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^PkgInfo$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^[^/]+$</key>
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>10</real>
|
||||
</dict>
|
||||
<key>^embedded\.provisionprofile$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^version\.plist$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue