Browse Source

Merge branch 'dev' into edge

Adam Ierymenko 7 years ago
parent
commit
0945d6ec0d

+ 131 - 5
controller/DB.cpp

@@ -1,6 +1,6 @@
 /*
 /*
  * ZeroTier One - Network Virtualization Everywhere
  * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015  ZeroTier, Inc.
+ * Copyright (C) 2011-2018  ZeroTier, Inc.
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -41,7 +41,6 @@ void DB::initNetwork(nlohmann::json &network)
 	if (!network.count("tags")) network["tags"] = nlohmann::json::array();
 	if (!network.count("tags")) network["tags"] = nlohmann::json::array();
 	if (!network.count("routes")) network["routes"] = nlohmann::json::array();
 	if (!network.count("routes")) network["routes"] = nlohmann::json::array();
 	if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
 	if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
-	//if (!network.count("anchors")) network["anchors"] = nlohmann::json::array();
 	if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU;
 	if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU;
 	if (!network.count("remoteTraceTarget")) network["remoteTraceTarget"] = nlohmann::json();
 	if (!network.count("remoteTraceTarget")) network["remoteTraceTarget"] = nlohmann::json();
 	if (!network.count("removeTraceLevel")) network["remoteTraceLevel"] = 0;
 	if (!network.count("removeTraceLevel")) network["remoteTraceLevel"] = 0;
@@ -222,7 +221,7 @@ void DB::networks(std::vector<uint64_t> &networks)
 		networks.push_back(n->first);
 		networks.push_back(n->first);
 }
 }
 
 
-void DB::_memberChanged(nlohmann::json &old,nlohmann::json &member,bool push)
+void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool push)
 {
 {
 	uint64_t memberId = 0;
 	uint64_t memberId = 0;
 	uint64_t networkId = 0;
 	uint64_t networkId = 0;
@@ -230,6 +229,102 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &member,bool push)
 	bool wasAuth = false;
 	bool wasAuth = false;
 	std::shared_ptr<_Network> nw;
 	std::shared_ptr<_Network> nw;
 
 
+	if (old.is_object()) {
+		memberId = OSUtils::jsonIntHex(old["id"],0ULL);
+		networkId = OSUtils::jsonIntHex(old["nwid"],0ULL);
+		if ((memberId)&&(networkId)) {
+			{
+				std::lock_guard<std::mutex> l(_networks_l);
+				auto nw2 = _networks.find(networkId);
+				if (nw2 != _networks.end())
+					nw = nw2->second;
+			}
+			if (nw) {
+				std::lock_guard<std::mutex> l(nw->lock);
+				if (OSUtils::jsonBool(old["activeBridge"],false))
+					nw->activeBridgeMembers.erase(memberId);
+				wasAuth = OSUtils::jsonBool(old["authorized"],false);
+				if (wasAuth)
+					nw->authorizedMembers.erase(memberId);
+				json &ips = old["ipAssignments"];
+				if (ips.is_array()) {
+					for(unsigned long i=0;i<ips.size();++i) {
+						json &ipj = ips[i];
+						if (ipj.is_string()) {
+							const std::string ips = ipj;
+							InetAddress ipa(ips.c_str());
+							ipa.setPort(0);
+							nw->allocatedIps.erase(ipa);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (memberConfig.is_object()) {
+		if (!nw) {
+			memberId = OSUtils::jsonIntHex(memberConfig["id"],0ULL);
+			networkId = OSUtils::jsonIntHex(memberConfig["nwid"],0ULL);
+			if ((!memberId)||(!networkId))
+				return;
+			std::lock_guard<std::mutex> l(_networks_l);
+			std::shared_ptr<_Network> &nw2 = _networks[networkId];
+			if (!nw2)
+				nw2.reset(new _Network);
+			nw = nw2;
+		}
+
+		{
+			std::lock_guard<std::mutex> l(nw->lock);
+
+			nw->members[memberId] = memberConfig;
+
+			if (OSUtils::jsonBool(memberConfig["activeBridge"],false))
+				nw->activeBridgeMembers.insert(memberId);
+			isAuth = OSUtils::jsonBool(memberConfig["authorized"],false);
+			if (isAuth)
+				nw->authorizedMembers.insert(memberId);
+			json &ips = memberConfig["ipAssignments"];
+			if (ips.is_array()) {
+				for(unsigned long i=0;i<ips.size();++i) {
+					json &ipj = ips[i];
+					if (ipj.is_string()) {
+						const std::string ips = ipj;
+						InetAddress ipa(ips.c_str());
+						ipa.setPort(0);
+						nw->allocatedIps.insert(ipa);
+					}
+				}
+			}
+
+			if (!isAuth) {
+				const int64_t ldt = (int64_t)OSUtils::jsonInt(memberConfig["lastDeauthorizedTime"],0ULL);
+				if (ldt > nw->mostRecentDeauthTime)
+					nw->mostRecentDeauthTime = ldt;
+			}
+		}
+
+		if (push)
+			_controller->onNetworkMemberUpdate(networkId,memberId);
+	} else if (memberId) {
+		if (nw) {
+			std::lock_guard<std::mutex> l(nw->lock);
+			nw->members.erase(memberId);
+		}
+		if (networkId) {
+			std::lock_guard<std::mutex> l(_networks_l);
+			auto er = _networkByMember.equal_range(memberId);
+			for(auto i=er.first;i!=er.second;++i) {
+				if (i->second == networkId) {
+					_networkByMember.erase(i);
+					break;
+				}
+			}
+		}
+	}
+
+	/*
 	if (old.is_object()) {
 	if (old.is_object()) {
 		json &config = old["config"];
 		json &config = old["config"];
 		if (config.is_object()) {
 		if (config.is_object()) {
@@ -330,16 +425,46 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &member,bool push)
 			}
 			}
 		}
 		}
 	}
 	}
+	*/
 
 
 	if ((push)&&((wasAuth)&&(!isAuth)&&(networkId)&&(memberId)))
 	if ((push)&&((wasAuth)&&(!isAuth)&&(networkId)&&(memberId)))
 		_controller->onNetworkMemberDeauthorize(networkId,memberId);
 		_controller->onNetworkMemberDeauthorize(networkId,memberId);
 }
 }
 
 
-void DB::_networkChanged(nlohmann::json &old,nlohmann::json &network,bool push)
+void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool push)
 {
 {
+	if (networkConfig.is_object()) {
+		const std::string ids = networkConfig["id"];
+		const uint64_t id = Utils::hexStrToU64(ids.c_str());
+		if (id) {
+			std::shared_ptr<_Network> nw;
+			{
+				std::lock_guard<std::mutex> l(_networks_l);
+				std::shared_ptr<_Network> &nw2 = _networks[id];
+				if (!nw2)
+					nw2.reset(new _Network);
+				nw = nw2;
+			}
+			{
+				std::lock_guard<std::mutex> l2(nw->lock);
+				nw->config = networkConfig;
+			}
+			if (push)
+				_controller->onNetworkUpdate(id);
+		}
+	} else if (old.is_object()) {
+		const std::string ids = old["id"];
+		const uint64_t id = Utils::hexStrToU64(ids.c_str());
+		if (id) {
+			std::lock_guard<std::mutex> l(_networks_l);
+			_networks.erase(id);
+		}
+	}
+
+	/*
 	if (network.is_object()) {
 	if (network.is_object()) {
 		json &config = network["config"];
 		json &config = network["config"];
-		if (config.is_object()) {
+		if (networkConfig.is_object()) {
 			const std::string ids = config["id"];
 			const std::string ids = config["id"];
 			const uint64_t id = Utils::hexStrToU64(ids.c_str());
 			const uint64_t id = Utils::hexStrToU64(ids.c_str());
 			if (id) {
 			if (id) {
@@ -367,6 +492,7 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &network,bool push)
 			_networks.erase(id);
 			_networks.erase(id);
 		}
 		}
 	}
 	}
+	*/
 }
 }
 
 
 void DB::_fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info)
 void DB::_fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info)

+ 3 - 3
controller/DB.hpp

@@ -1,6 +1,6 @@
 /*
 /*
  * ZeroTier One - Network Virtualization Everywhere
  * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015  ZeroTier, Inc.
+ * Copyright (C) 2011-2018  ZeroTier, Inc.
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -119,8 +119,8 @@ protected:
 		std::mutex lock;
 		std::mutex lock;
 	};
 	};
 
 
-	void _memberChanged(nlohmann::json &old,nlohmann::json &member,bool push);
-	void _networkChanged(nlohmann::json &old,nlohmann::json &network,bool push);
+	void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool push);
+	void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool push);
 	void _fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info);
 	void _fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info);
 
 
 	EmbeddedNetworkController *const _controller;
 	EmbeddedNetworkController *const _controller;

+ 1 - 1
controller/EmbeddedNetworkController.cpp

@@ -1,6 +1,6 @@
 /*
 /*
  * ZeroTier One - Network Virtualization Everywhere
  * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015  ZeroTier, Inc->
+ * Copyright (C) 2011-2018  ZeroTier, Inc
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by

+ 1 - 1
controller/EmbeddedNetworkController.hpp

@@ -1,6 +1,6 @@
 /*
 /*
  * ZeroTier One - Network Virtualization Everywhere
  * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015  ZeroTier, Inc.
+ * Copyright (C) 2011-2018  ZeroTier, Inc.
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by

+ 1 - 1
controller/FileDB.cpp

@@ -1,6 +1,6 @@
 /*
 /*
  * ZeroTier One - Network Virtualization Everywhere
  * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015  ZeroTier, Inc.
+ * Copyright (C) 2011-2018  ZeroTier, Inc.
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by

+ 1 - 1
controller/FileDB.hpp

@@ -1,6 +1,6 @@
 /*
 /*
  * ZeroTier One - Network Virtualization Everywhere
  * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015  ZeroTier, Inc.
+ * Copyright (C) 2011-2018  ZeroTier, Inc.
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by

+ 11 - 9
controller/RethinkDB.cpp

@@ -1,6 +1,6 @@
 /*
 /*
  * ZeroTier One - Network Virtualization Everywhere
  * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015  ZeroTier, Inc.
+ * Copyright (C) 2011-2018  ZeroTier, Inc.
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -97,10 +97,11 @@ RethinkDB::RethinkDB(EmbeddedNetworkController *const nc,const Identity &myId,co
 								try {
 								try {
 									json &ov = tmp["old_val"];
 									json &ov = tmp["old_val"];
 									json &nv = tmp["new_val"];
 									json &nv = tmp["new_val"];
-									if (ov.is_object()||nv.is_object()) {
-										//if (nv.is_object()) printf("MEMBER: %s" ZT_EOL_S,nv.dump().c_str());
-										this->_memberChanged(ov,nv,(this->_ready <= 0));
-									}
+									json oldConfig,newConfig;
+									if (ov.is_object()) oldConfig = ov["config"];
+									if (nv.is_object()) newConfig = nv["config"];
+									if (oldConfig.is_object()||newConfig.is_object())
+										this->_memberChanged(oldConfig,newConfig,(this->_ready <= 0));
 								} catch ( ... ) {} // ignore bad records
 								} catch ( ... ) {} // ignore bad records
 							}
 							}
 						}
 						}
@@ -138,10 +139,11 @@ RethinkDB::RethinkDB(EmbeddedNetworkController *const nc,const Identity &myId,co
 								try {
 								try {
 									json &ov = tmp["old_val"];
 									json &ov = tmp["old_val"];
 									json &nv = tmp["new_val"];
 									json &nv = tmp["new_val"];
-									if (ov.is_object()||nv.is_object()) {
-										//if (nv.is_object()) printf("NETWORK: %s" ZT_EOL_S,nv.dump().c_str());
-										this->_networkChanged(ov,nv,(this->_ready <= 0));
-									}
+									json oldConfig,newConfig;
+									if (ov.is_object()) oldConfig = ov["config"];
+									if (nv.is_object()) newConfig = nv["config"];
+									if (oldConfig.is_object()||newConfig.is_object())
+										this->_networkChanged(oldConfig,newConfig,(this->_ready <= 0));
 								} catch ( ... ) {} // ignore bad records
 								} catch ( ... ) {} // ignore bad records
 							}
 							}
 						}
 						}

+ 1 - 1
controller/RethinkDB.hpp

@@ -1,6 +1,6 @@
 /*
 /*
  * ZeroTier One - Network Virtualization Everywhere
  * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015  ZeroTier, Inc.
+ * Copyright (C) 2011-2018  ZeroTier, Inc.
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by

+ 0 - 318
controller/migrate-sqlite/migrate.js

@@ -1,318 +0,0 @@
-'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: [],
-				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(),
-				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);
-});

+ 0 - 15
controller/migrate-sqlite/package.json

@@ -1,15 +0,0 @@
-{
-  "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 <[email protected]>",
-  "license": "GPL-3.0",
-  "dependencies": {
-    "async": "^2.1.4",
-    "sqlite3": "^3.1.8"
-  }
-}

+ 114 - 0
include/ZeroTierDebug.h

@@ -0,0 +1,114 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2018  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/>.
+ *
+ * --
+ *
+ * You can be released from the requirements of the license by purchasing
+ * a commercial license. Buying such a license is mandatory as soon as you
+ * develop commercial closed-source software that incorporates or links
+ * directly against ZeroTier software without disclosing the source code
+ * of your own application.
+ */
+
+/**
+ * @file
+ *
+ * Debug macros
+ */
+
+#ifndef ZT_DEBUG_H
+#define ZT_DEBUG_H
+
+#if defined(__linux__) || defined(__APPLE__)
+#include <sys/syscall.h>
+#include <pthread.h>
+#include <unistd.h>
+#endif
+
+#include <string.h>
+
+#define ZT_MSG_INFO        true
+#define ZT_COLOR           true
+
+// Debug output colors
+#if defined(__APPLE__)
+		#include "TargetConditionals.h"
+#endif
+#if defined(ZT_COLOR) && !defined(_WIN32) && !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(__APP_FRAMEWORK__)
+	#define ZT_RED   "\x1B[31m"
+	#define ZT_GRN   "\x1B[32m"
+	#define ZT_YEL   "\x1B[33m"
+	#define ZT_BLU   "\x1B[34m"
+	#define ZT_MAG   "\x1B[35m"
+	#define ZT_CYN   "\x1B[36m"
+	#define ZT_WHT   "\x1B[37m"
+	#define ZT_RESET "\x1B[0m"
+#else
+	#define ZT_RED
+	#define ZT_GRN
+	#define ZT_YEL
+	#define ZT_BLU
+	#define ZT_MAG
+	#define ZT_CYN
+	#define ZT_WHT
+	#define ZT_RESET
+#endif
+
+#define ZT_FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // short
+
+#ifdef __linux__
+  #define ZT_THREAD_ID (long)0 // syscall(SYS_gettid)
+#endif
+#ifdef __APPLE__
+  #define ZT_THREAD_ID (long)0 // (long)gettid()
+#endif
+#ifdef _WIN32
+  #define ZT_THREAD_ID (long)0 // 
+#endif
+#if defined(__JNI_LIB__)
+		#include <jni.h>
+#endif
+#if defined(__ANDROID__)
+		#include <android/log.h>
+		#define ZT_LOG_TAG "ZTSDK"
+#endif
+#if defined(ZT_TRACE)
+	#if ZT_MSG_INFO == true
+		#if defined(__ANDROID__)
+			#define DEBUG_INFO(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \
+				"INFO : %17s:%5d:%20s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
+		#endif
+		#if defined(_WIN32)
+			#define DEBUG_INFO(fmt, ...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" \
+					ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, __VA_ARGS__)
+		#endif
+		#if defined(__linux__) or defined(__APPLE__)
+			#define DEBUG_INFO(fmt, args ...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" \
+					ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
+		#endif
+	#else
+		#define DEBUG_INFO(fmt, args...)
+	#endif
+#else // blank
+	#if defined(_WIN32)
+		#define DEBUG_INFO(...)
+	#else
+		#define DEBUG_INFO(fmt, args...)
+	#endif
+#endif
+
+#endif // _H

+ 98 - 52
node/Network.cpp

@@ -1072,15 +1072,89 @@ void Network::requestConfiguration(void *tPtr)
 	if (_destroyed)
 	if (_destroyed)
 		return;
 		return;
 
 
-	/* ZeroTier addresses can't begin with 0xff, so this is used to mark controllerless
-	 * network IDs. Controllerless network IDs only support unicast IPv6 using the 6plane
-	 * addressing scheme and have the following format: 0xffSSSSEEEE000000 where SSSS
-	 * is the 16-bit starting IP port range allowed and EEEE is the 16-bit ending IP port
-	 * range allowed. Remaining digits are reserved for future use and must be zero. */
 	if ((_id >> 56) == 0xff) {
 	if ((_id >> 56) == 0xff) {
-		const uint16_t startPortRange = (uint16_t)((_id >> 40) & 0xffff);
-		const uint16_t endPortRange = (uint16_t)((_id >> 24) & 0xffff);
-		if (((_id & 0xffffff) == 0)&&(endPortRange >= startPortRange)) {
+		if ((_id & 0xffffff) == 0) {
+			const uint16_t startPortRange = (uint16_t)((_id >> 40) & 0xffff);
+			const uint16_t endPortRange = (uint16_t)((_id >> 24) & 0xffff);
+			if (endPortRange >= startPortRange) {
+				NetworkConfig *const nconf = new NetworkConfig();
+
+				nconf->networkId = _id;
+				nconf->timestamp = RR->node->now();
+				nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA;
+				nconf->revision = 1;
+				nconf->issuedTo = RR->identity.address();
+				nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
+				nconf->mtu = ZT_DEFAULT_MTU;
+				nconf->multicastLimit = 0;
+				nconf->staticIpCount = 1;
+				nconf->ruleCount = 14;
+				nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt());
+
+				// Drop everything but IPv6
+				nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80; // NOT
+				nconf->rules[0].v.etherType = 0x86dd; // IPv6
+				nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP;
+
+				// Allow ICMPv6
+				nconf->rules[2].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL;
+				nconf->rules[2].v.ipProtocol = 0x3a; // ICMPv6
+				nconf->rules[3].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
+
+				// Allow destination ports within range
+				nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL;
+				nconf->rules[4].v.ipProtocol = 0x11; // UDP
+				nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40; // OR
+				nconf->rules[5].v.ipProtocol = 0x06; // TCP
+				nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE;
+				nconf->rules[6].v.port[0] = startPortRange;
+				nconf->rules[6].v.port[1] = endPortRange;
+				nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
+
+				// Allow non-SYN TCP packets to permit non-connection-initiating traffic
+				nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80; // NOT
+				nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN;
+				nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
+
+				// Also allow SYN+ACK which are replies to SYN
+				nconf->rules[10].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS;
+				nconf->rules[10].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN;
+				nconf->rules[11].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS;
+				nconf->rules[11].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK;
+				nconf->rules[12].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
+
+				nconf->rules[13].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP;
+
+				nconf->type = ZT_NETWORK_TYPE_PUBLIC;
+
+				nconf->name[0] = 'a';
+				nconf->name[1] = 'd';
+				nconf->name[2] = 'h';
+				nconf->name[3] = 'o';
+				nconf->name[4] = 'c';
+				nconf->name[5] = '-';
+				Utils::hex((uint16_t)startPortRange,nconf->name + 6);
+				nconf->name[10] = '-';
+				Utils::hex((uint16_t)endPortRange,nconf->name + 11);
+				nconf->name[15] = (char)0;
+
+				this->setConfiguration(tPtr,*nconf,false);
+				delete nconf;
+			} else {
+				this->setNotFound();
+			}
+		} else if ((_id & 0xff) == 0x01) {
+			// ffAA__________01
+			const uint64_t myAddress = RR->identity.address().toInt();
+			uint8_t ipv4[4];
+			ipv4[0] = (uint8_t)((_id >> 48) & 0xff);
+			ipv4[1] = (uint8_t)((myAddress >> 16) & 0xff);
+			ipv4[2] = (uint8_t)((myAddress >> 8) & 0xff);
+			ipv4[3] = (uint8_t)(myAddress & 0xff);
+
+			char v4ascii[24];
+			Utils::decimal(ipv4[0],v4ascii);
+
 			NetworkConfig *const nconf = new NetworkConfig();
 			NetworkConfig *const nconf = new NetworkConfig();
 
 
 			nconf->networkId = _id;
 			nconf->networkId = _id;
@@ -1090,44 +1164,13 @@ void Network::requestConfiguration(void *tPtr)
 			nconf->issuedTo = RR->identity.address();
 			nconf->issuedTo = RR->identity.address();
 			nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
 			nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
 			nconf->mtu = ZT_DEFAULT_MTU;
 			nconf->mtu = ZT_DEFAULT_MTU;
-			nconf->multicastLimit = 0;
-			nconf->staticIpCount = 1;
-			nconf->ruleCount = 14;
-			nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt());
-
-			// Drop everything but IPv6
-			nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80; // NOT
-			nconf->rules[0].v.etherType = 0x86dd; // IPv6
-			nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP;
-
-			// Allow ICMPv6
-			nconf->rules[2].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL;
-			nconf->rules[2].v.ipProtocol = 0x3a; // ICMPv6
-			nconf->rules[3].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
-
-			// Allow destination ports within range
-			nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL;
-			nconf->rules[4].v.ipProtocol = 0x11; // UDP
-			nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40; // OR
-			nconf->rules[5].v.ipProtocol = 0x06; // TCP
-			nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE;
-			nconf->rules[6].v.port[0] = startPortRange;
-			nconf->rules[6].v.port[1] = endPortRange;
-			nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
-
-			// Allow non-SYN TCP packets to permit non-connection-initiating traffic
-			nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80; // NOT
-			nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN;
-			nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
-
-			// Also allow SYN+ACK which are replies to SYN
-			nconf->rules[10].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS;
-			nconf->rules[10].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN;
-			nconf->rules[11].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS;
-			nconf->rules[11].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK;
-			nconf->rules[12].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
-
-			nconf->rules[13].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP;
+			nconf->multicastLimit = 1024;
+			nconf->staticIpCount = 2;
+			nconf->ruleCount = 1;
+			nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,myAddress);
+			nconf->staticIps[1].set(ipv4,4,8);
+
+			nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
 
 
 			nconf->type = ZT_NETWORK_TYPE_PUBLIC;
 			nconf->type = ZT_NETWORK_TYPE_PUBLIC;
 
 
@@ -1137,15 +1180,18 @@ void Network::requestConfiguration(void *tPtr)
 			nconf->name[3] = 'o';
 			nconf->name[3] = 'o';
 			nconf->name[4] = 'c';
 			nconf->name[4] = 'c';
 			nconf->name[5] = '-';
 			nconf->name[5] = '-';
-			Utils::hex((uint16_t)startPortRange,nconf->name + 6);
-			nconf->name[10] = '-';
-			Utils::hex((uint16_t)endPortRange,nconf->name + 11);
-			nconf->name[15] = (char)0;
+			unsigned long nn = 6;
+			while ((nconf->name[nn] = v4ascii[nn - 6])) ++nn;
+			nconf->name[nn++] = '.';
+			nconf->name[nn++] = '0';
+			nconf->name[nn++] = '.';
+			nconf->name[nn++] = '0';
+			nconf->name[nn++] = '.';
+			nconf->name[nn++] = '0';
+			nconf->name[nn++] = (char)0;
 
 
 			this->setConfiguration(tPtr,*nconf,false);
 			this->setConfiguration(tPtr,*nconf,false);
 			delete nconf;
 			delete nconf;
-		} else {
-			this->setNotFound();
 		}
 		}
 		return;
 		return;
 	}
 	}

+ 1 - 1
osdep/WindowsEthernetTap.cpp

@@ -841,7 +841,7 @@ void WindowsEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,
 	// pretty much anything work... IPv4, IPv6, IPX, oldskool Netbios, who knows...
 	// pretty much anything work... IPv4, IPv6, IPX, oldskool Netbios, who knows...
 	unsigned char mcastbuf[TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE];
 	unsigned char mcastbuf[TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE];
 	DWORD bytesReturned = 0;
 	DWORD bytesReturned = 0;
-	if (DeviceIoControl(t,TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS,(LPVOID)0,0,(LPVOID)mcastbuf,sizeof(mcastbuf),&bytesReturned,NULL)) {
+	if (DeviceIoControl(t,TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS,(LPVOID)mcastbuf,sizeof(mcastbuf),(LPVOID)mcastbuf,sizeof(mcastbuf),&bytesReturned,NULL)) {
 		if ((bytesReturned > 0)&&(bytesReturned <= TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE)) { // sanity check
 		if ((bytesReturned > 0)&&(bytesReturned <= TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE)) { // sanity check
 			MAC mac;
 			MAC mac;
 			DWORD i = 0;
 			DWORD i = 0;