| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 | 
							- /*
 
-  * 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/>.
 
-  */
 
- #ifdef ZT_ENABLE_CLUSTER
 
- #include <math.h>
 
- #include <cmath>
 
- #include "ClusterGeoIpService.hpp"
 
- #include "../node/Utils.hpp"
 
- #include "../osdep/OSUtils.hpp"
 
- #define ZT_CLUSTERGEOIPSERVICE_FILE_MODIFICATION_CHECK_EVERY 10000
 
- namespace ZeroTier {
 
- ClusterGeoIpService::ClusterGeoIpService() :
 
- 	_pathToCsv(),
 
- 	_ipStartColumn(-1),
 
- 	_ipEndColumn(-1),
 
- 	_latitudeColumn(-1),
 
- 	_longitudeColumn(-1),
 
- 	_lastFileCheckTime(0),
 
- 	_csvModificationTime(0),
 
- 	_csvFileSize(0)
 
- {
 
- }
 
- ClusterGeoIpService::~ClusterGeoIpService()
 
- {
 
- }
 
- bool ClusterGeoIpService::locate(const InetAddress &ip,int &x,int &y,int &z)
 
- {
 
- 	Mutex::Lock _l(_lock);
 
- 	if ((_pathToCsv.length() > 0)&&((OSUtils::now() - _lastFileCheckTime) > ZT_CLUSTERGEOIPSERVICE_FILE_MODIFICATION_CHECK_EVERY)) {
 
- 		_lastFileCheckTime = OSUtils::now();
 
- 		if ((_csvFileSize != OSUtils::getFileSize(_pathToCsv.c_str()))||(_csvModificationTime != OSUtils::getLastModified(_pathToCsv.c_str())))
 
- 			_load(_pathToCsv.c_str(),_ipStartColumn,_ipEndColumn,_latitudeColumn,_longitudeColumn);
 
- 	}
 
- 	/* We search by looking up the upper bound of the sorted vXdb vectors
 
- 	 * and then iterating down for a matching IP range. We stop when we hit
 
- 	 * the beginning or an entry whose start and end are before the IP we
 
- 	 * are searching. */
 
- 	if ((ip.ss_family == AF_INET)&&(_v4db.size() > 0)) {
 
- 		_V4E key;
 
- 		key.start = Utils::ntoh((uint32_t)(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr));
 
- 		std::vector<_V4E>::const_iterator i(std::upper_bound(_v4db.begin(),_v4db.end(),key));
 
- 		while (i != _v4db.begin()) {
 
- 			--i;
 
- 			if ((key.start >= i->start)&&(key.start <= i->end)) {
 
- 				x = i->x;
 
- 				y = i->y;
 
- 				z = i->z;
 
- 				//printf("%s : %f,%f %d,%d,%d\n",ip.toIpString().c_str(),i->lat,i->lon,x,y,z);
 
- 				return true;
 
- 			} else if ((key.start > i->start)&&(key.start > i->end))
 
- 				break;
 
- 		}
 
- 	} else if ((ip.ss_family == AF_INET6)&&(_v6db.size() > 0)) {
 
- 		_V6E key;
 
- 		memcpy(key.start,reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
 
- 		std::vector<_V6E>::const_iterator i(std::upper_bound(_v6db.begin(),_v6db.end(),key));
 
- 		while (i != _v6db.begin()) {
 
- 			--i;
 
- 			const int s_vs_s = memcmp(key.start,i->start,16);
 
- 			const int s_vs_e = memcmp(key.start,i->end,16);
 
- 			if ((s_vs_s >= 0)&&(s_vs_e <= 0)) {
 
- 				x = i->x;
 
- 				y = i->y;
 
- 				z = i->z;
 
- 				//printf("%s : %f,%f %d,%d,%d\n",ip.toIpString().c_str(),i->lat,i->lon,x,y,z);
 
- 				return true;
 
- 			} else if ((s_vs_s > 0)&&(s_vs_e > 0))
 
- 				break;
 
- 		}
 
- 	}
 
- 	return false;
 
- }
 
- void ClusterGeoIpService::_parseLine(const char *line,std::vector<_V4E> &v4db,std::vector<_V6E> &v6db,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn)
 
- {
 
- 	std::vector<std::string> ls(Utils::split(line,",\t","\\","\"'"));
 
- 	if ( ((ipStartColumn >= 0)&&(ipStartColumn < (int)ls.size()))&&
 
- 	     ((ipEndColumn >= 0)&&(ipEndColumn < (int)ls.size()))&&
 
- 	     ((latitudeColumn >= 0)&&(latitudeColumn < (int)ls.size()))&&
 
- 	     ((longitudeColumn >= 0)&&(longitudeColumn < (int)ls.size())) ) {
 
- 		InetAddress ipStart(ls[ipStartColumn].c_str(),0);
 
- 		InetAddress ipEnd(ls[ipEndColumn].c_str(),0);
 
- 		const double lat = strtod(ls[latitudeColumn].c_str(),(char **)0);
 
- 		const double lon = strtod(ls[longitudeColumn].c_str(),(char **)0);
 
- 		if ((ipStart.ss_family == ipEnd.ss_family)&&(ipStart)&&(ipEnd)&&(std::isfinite(lat))&&(std::isfinite(lon))) {
 
- 			const double latRadians = lat * 0.01745329251994; // PI / 180
 
- 			const double lonRadians = lon * 0.01745329251994; // PI / 180
 
- 			const double cosLat = cos(latRadians);
 
- 			const int x = (int)round((-6371.0) * cosLat * cos(lonRadians)); // 6371 == Earth's approximate radius in kilometers
 
- 			const int y = (int)round(6371.0 * sin(latRadians));
 
- 			const int z = (int)round(6371.0 * cosLat * sin(lonRadians));
 
- 			if (ipStart.ss_family == AF_INET) {
 
- 				v4db.push_back(_V4E());
 
- 				v4db.back().start = Utils::ntoh((uint32_t)(reinterpret_cast<const struct sockaddr_in *>(&ipStart)->sin_addr.s_addr));
 
- 				v4db.back().end = Utils::ntoh((uint32_t)(reinterpret_cast<const struct sockaddr_in *>(&ipEnd)->sin_addr.s_addr));
 
- 				v4db.back().lat = (float)lat;
 
- 				v4db.back().lon = (float)lon;
 
- 				v4db.back().x = x;
 
- 				v4db.back().y = y;
 
- 				v4db.back().z = z;
 
- 				//printf("%s - %s : %d,%d,%d\n",ipStart.toIpString().c_str(),ipEnd.toIpString().c_str(),x,y,z);
 
- 			} else if (ipStart.ss_family == AF_INET6) {
 
- 				v6db.push_back(_V6E());
 
- 				memcpy(v6db.back().start,reinterpret_cast<const struct sockaddr_in6 *>(&ipStart)->sin6_addr.s6_addr,16);
 
- 				memcpy(v6db.back().end,reinterpret_cast<const struct sockaddr_in6 *>(&ipEnd)->sin6_addr.s6_addr,16);
 
- 				v6db.back().lat = (float)lat;
 
- 				v6db.back().lon = (float)lon;
 
- 				v6db.back().x = x;
 
- 				v6db.back().y = y;
 
- 				v6db.back().z = z;
 
- 				//printf("%s - %s : %d,%d,%d\n",ipStart.toIpString().c_str(),ipEnd.toIpString().c_str(),x,y,z);
 
- 			}
 
- 		}
 
- 	}
 
- }
 
- long ClusterGeoIpService::_load(const char *pathToCsv,int ipStartColumn,int ipEndColumn,int latitudeColumn,int longitudeColumn)
 
- {
 
- 	// assumes _lock is locked
 
- 	FILE *f = fopen(pathToCsv,"rb");
 
- 	if (!f)
 
- 		return -1;
 
- 	std::vector<_V4E> v4db;
 
- 	std::vector<_V6E> v6db;
 
- 	v4db.reserve(16777216);
 
- 	v6db.reserve(16777216);
 
- 	char buf[4096];
 
- 	char linebuf[1024];
 
- 	unsigned int lineptr = 0;
 
- 	for(;;) {
 
- 		int n = (int)fread(buf,1,sizeof(buf),f);
 
- 		if (n <= 0)
 
- 			break;
 
- 		for(int i=0;i<n;++i) {
 
- 			if ((buf[i] == '\r')||(buf[i] == '\n')||(buf[i] == (char)0)) {
 
- 				if (lineptr) {
 
- 					linebuf[lineptr] = (char)0;
 
- 					_parseLine(linebuf,v4db,v6db,ipStartColumn,ipEndColumn,latitudeColumn,longitudeColumn);
 
- 				}
 
- 				lineptr = 0;
 
- 			} else if (lineptr < (unsigned int)sizeof(linebuf))
 
- 				linebuf[lineptr++] = buf[i];
 
- 		}
 
- 	}
 
- 	if (lineptr) {
 
- 		linebuf[lineptr] = (char)0;
 
- 		_parseLine(linebuf,v4db,v6db,ipStartColumn,ipEndColumn,latitudeColumn,longitudeColumn);
 
- 	}
 
- 	fclose(f);
 
- 	if ((v4db.size() > 0)||(v6db.size() > 0)) {
 
- 		std::sort(v4db.begin(),v4db.end());
 
- 		std::sort(v6db.begin(),v6db.end());
 
- 		_pathToCsv = pathToCsv;
 
- 		_ipStartColumn = ipStartColumn;
 
- 		_ipEndColumn = ipEndColumn;
 
- 		_latitudeColumn = latitudeColumn;
 
- 		_longitudeColumn = longitudeColumn;
 
- 		_lastFileCheckTime = OSUtils::now();
 
- 		_csvModificationTime = OSUtils::getLastModified(pathToCsv);
 
- 		_csvFileSize = OSUtils::getFileSize(pathToCsv);
 
- 		_v4db.swap(v4db);
 
- 		_v6db.swap(v6db);
 
- 		return (long)(_v4db.size() + _v6db.size());
 
- 	} else {
 
- 		return 0;
 
- 	}
 
- }
 
- } // namespace ZeroTier
 
- #endif // ZT_ENABLE_CLUSTER
 
- /*
 
- int main(int argc,char **argv)
 
- {
 
- 	char buf[1024];
 
- 	ZeroTier::ClusterGeoIpService gip;
 
- 	printf("loading...\n");
 
- 	gip.load("/Users/api/Code/ZeroTier/Infrastructure/root-servers/zerotier-one/cluster-geoip.csv",0,1,5,6);
 
- 	printf("... done!\n"); fflush(stdout);
 
- 	while (gets(buf)) { // unsafe, testing only
 
- 		ZeroTier::InetAddress addr(buf,0);
 
- 		printf("looking up: %s\n",addr.toString().c_str()); fflush(stdout);
 
- 		int x = 0,y = 0,z = 0;
 
- 		if (gip.locate(addr,x,y,z)) {
 
- 			//printf("%s: %d,%d,%d\n",addr.toString().c_str(),x,y,z); fflush(stdout);
 
- 		} else {
 
- 			printf("%s: not found!\n",addr.toString().c_str()); fflush(stdout);
 
- 		}
 
- 	}
 
- 	return 0;
 
- }
 
- */
 
 
  |