| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206 | /* * Copyright (c)2019 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. * * Change Date: 2026-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. *//****/#include "../node/Constants.hpp"#include <cerrno>//#define ZT_NETLINK_TRACE#ifdef __LINUX__#include "LinuxNetLink.hpp"#include <unistd.h>#include <linux/if_tun.h>#ifndef IFNAMSIZ#define IFNAMSIZ 16#endifconst int ZT_RTE_METRIC = 5000;namespace ZeroTier {struct nl_route_req {	struct nlmsghdr nl;	struct rtmsg rt;	char buf[8192];};struct nl_if_req {	struct nlmsghdr nl;	struct ifinfomsg ifa;	char buf[8192];};struct nl_adr_req {	struct nlmsghdr nl;	struct ifaddrmsg ifa;	char buf[8192];};LinuxNetLink::LinuxNetLink()	: _t()	, _running(false)	, _seq(0)	, _interfaces()	, _if_m()	, _fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE))	, _la({0}){	// set socket timeout to 1 sec so we're not permablocking recv() calls	_setSocketTimeout(_fd, 1);	_la.nl_family = AF_NETLINK;	_la.nl_pid = 0; //getpid()+1;	_la.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR|RTMGRP_IPV4_ROUTE|RTMGRP_IPV6_ROUTE|RTMGRP_NOTIFY;	if (bind(_fd, (struct sockaddr*)&_la, sizeof(_la))) {		fprintf(stderr, "Error connecting to RTNETLINK: %s\n", strerror(errno));		::exit(1);	}	_requestIPv4Routes();	_requestIPv6Routes();	_requestInterfaceList();	_running = true;	_t = Thread::start(this);}LinuxNetLink::~LinuxNetLink(){	_running = false;	Thread::join(_t);	::close(_fd);}void LinuxNetLink::_setSocketTimeout(int fd, int seconds){	struct timeval tv;	tv.tv_sec = seconds;	tv.tv_usec = 0;	if(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) != 0) {#ifdef ZT_NETLINK_TRACE		fprintf(stderr, "setsockopt failed: %s\n", strerror(errno));#endif	}}#define ZT_NL_BUF_SIZE 16384int LinuxNetLink::_doRecv(int fd){	char *buf = nullptr;	if (posix_memalign((void **)&buf,16,ZT_NL_BUF_SIZE) != 0) {		fprintf(stderr,"malloc failed!\n");		::exit(1);	}	if (!buf) {		fprintf(stderr,"malloc failed!\n");		::exit(1);	}	char *p = NULL;	struct nlmsghdr *nlp;	int nll = 0;	int rtn = 0;	p = buf;	for(;;) {		rtn = recv(fd, p, ZT_NL_BUF_SIZE - nll, 0);		if (rtn > 0) {			nlp = (struct nlmsghdr *)p;			if(nlp->nlmsg_type == NLMSG_ERROR && (nlp->nlmsg_flags & NLM_F_ACK) != NLM_F_ACK) {				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlp);				if (err->error != 0) {#ifdef ZT_NETLINK_TRACE					fprintf(stderr, "rtnetlink error: %s\n", strerror(-(err->error)));#endif				}				p = buf;				nll = 0;				break;			}			if (nlp->nlmsg_type == NLMSG_NOOP) {				break;			}			if( (nlp->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI || (nlp->nlmsg_type == NLMSG_DONE))			{				if (nlp->nlmsg_type == NLMSG_DONE) {					_processMessage(nlp, nll);					p = buf;					nll = 0;					break;				}				p += rtn;				nll += rtn;			}			if (nlp->nlmsg_type == NLMSG_OVERRUN) {#ifdef ZT_NETLINK_TRACE				fprintf(stderr, "NLMSG_OVERRUN: Data lost\n");#endif				p = buf;				nll = 0;				break;			}			nll += rtn;			_processMessage(nlp, nll);			p = buf;			nll = 0;			break;		} else {			break;		}	}	free(buf);	return rtn;}void LinuxNetLink::threadMain() throw(){	int rtn = 0;	while(_running) {		rtn = _doRecv(_fd);		if (rtn <= 0) {			Thread::sleep(250);			continue;		}	}}void LinuxNetLink::_processMessage(struct nlmsghdr *nlp, int nll){	for(; NLMSG_OK(nlp, nll); nlp=NLMSG_NEXT(nlp, nll))	{		switch(nlp->nlmsg_type)		{		case RTM_NEWLINK:			_linkAdded(nlp);			break;		case RTM_DELLINK:			_linkDeleted(nlp);			break;		case RTM_NEWADDR:			_ipAddressAdded(nlp);			break;		case RTM_DELADDR:			_ipAddressDeleted(nlp);			break;		case RTM_NEWROUTE:			_routeAdded(nlp);			break;		case RTM_DELROUTE:			_routeDeleted(nlp);			break;		default:			break;		}	}}void LinuxNetLink::_ipAddressAdded(struct nlmsghdr *nlp){#ifdef ZT_NETLINK_TRACE	struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp);	struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap);	int ifal = IFA_PAYLOAD(nlp);	char addr[40] = {0};	char local[40] = {0};	char label[40] = {0};	char bcast[40] = {0};	for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal))	{		switch(rtap->rta_type) {		case IFA_ADDRESS:			inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40);			break;		case IFA_LOCAL:			inet_ntop(ifap->ifa_family, RTA_DATA(rtap), local, 40);			break;		case IFA_LABEL:			memcpy(label, RTA_DATA(rtap), 40);			break;		case IFA_BROADCAST:			inet_ntop(ifap->ifa_family, RTA_DATA(rtap), bcast, 40);			break;		}	}	fprintf(stderr,"Added IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast);#endif}void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr *nlp){#ifdef ZT_NETLINK_TRACE	struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp);	struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap);	int ifal = IFA_PAYLOAD(nlp);	char addr[40] = {0};	char local[40] = {0};	char label[40] = {0};	char bcast[40] = {0};	for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal))	{		switch(rtap->rta_type) {		case IFA_ADDRESS:			inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40);			break;		case IFA_LOCAL:			inet_ntop(ifap->ifa_family, RTA_DATA(rtap), local, 40);			break;		case IFA_LABEL:			memcpy(label, RTA_DATA(rtap), 40);			break;		case IFA_BROADCAST:			inet_ntop(ifap->ifa_family, RTA_DATA(rtap), bcast, 40);			break;		}	}	fprintf(stderr, "Removed IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast);#endif}void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp){	char dsts[40] = {0};	char gws[40] = {0};	char srcs[40] = {0};	char ifs[16] = {0};	char ms[24] = {0};	struct rtmsg *rtp = (struct rtmsg *)NLMSG_DATA(nlp);	struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp);	int rtl = RTM_PAYLOAD(nlp);	Route r;	bool wecare = false;	for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl))	{		switch(rtap->rta_type)		{		case RTA_DST:			switch(rtp->rtm_family) {				case AF_INET:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24);					r.target.set(RTA_DATA(rtap), 4, 0);					wecare = true;					break;				case AF_INET6:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24);					r.target.set(RTA_DATA(rtap), 16, 0);					wecare = true;					break;			}			break;		case RTA_SRC:			switch(rtp->rtm_family) {				case AF_INET:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24);					r.src.set(RTA_DATA(rtap), 4, 0);					wecare = true;					break;				case AF_INET6:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24);					r.src.set(RTA_DATA(rtap), 16, 0);					wecare = true;					break;			}			break;		case RTA_GATEWAY:			switch(rtp->rtm_family) {				case AF_INET:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24);					r.via.set(RTA_DATA(rtap), 4, 0);					wecare = true;					break;				case AF_INET6:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24);					r.via.set(RTA_DATA(rtap), 16, 0);					wecare = true;					break;			}			break;		case RTA_OIF:			switch(rtp->rtm_family) {				case AF_INET:					r.ifidx = *((int*)RTA_DATA(rtap));					wecare = true;					break;				case AF_INET6:					r.ifidx = *((int*)RTA_DATA(rtap));					wecare = true;					break;			}			sprintf(ifs, "%d", *((int*)RTA_DATA(rtap)));			break;		}	}	if (wecare) {		Mutex::Lock rl(_routes_m);		_routes[r.target].insert(r);	}#ifdef ZT_NETLINK_TRACE	sprintf(ms, "%d", rtp->rtm_dst_len);	fprintf(stderr, "Route Added: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs);#endif}void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp){	char dsts[40] = {0};	char gws[40] = {0};	char srcs[40] = {0};	char ifs[16] = {0};	char ms[24] = {0};	struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp);	struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp);	int rtl = RTM_PAYLOAD(nlp);	Route r;	bool wecare = false;	for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl))	{		switch(rtap->rta_type)		{		case RTA_DST:			switch(rtp->rtm_family) {				case AF_INET:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24);					r.target.set(RTA_DATA(rtap), 4, 0);					wecare = true;					break;				case AF_INET6:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24);					r.target.set(RTA_DATA(rtap), 16, 0);					wecare = true;					break;			}			break;		case RTA_SRC:			switch(rtp->rtm_family) {				case AF_INET:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24);					r.src.set(RTA_DATA(rtap), 4, 0);					wecare = true;					break;				case AF_INET6:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24);					r.src.set(RTA_DATA(rtap), 16, 0);					wecare = true;					break;			}			break;		case RTA_GATEWAY:			switch(rtp->rtm_family) {				case AF_INET:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24);					r.via.set(RTA_DATA(rtap), 4, 0);					wecare = true;					break;				case AF_INET6:					inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24);					r.via.set(RTA_DATA(rtap), 16, 0);					wecare = true;					break;			}			break;		case RTA_OIF:			switch(rtp->rtm_family) {				case AF_INET:					r.ifidx = *((int*)RTA_DATA(rtap));					wecare = true;					break;				case AF_INET6:					r.ifidx = *((int*)RTA_DATA(rtap));					wecare = true;					break;			}			sprintf(ifs, "%d", *((int*)RTA_DATA(rtap)));			break;		}	}	if (wecare) {		Mutex::Lock rl(_routes_m);		_routes[r.target].erase(r);	}#ifdef ZT_NETLINK_TRACE	sprintf(ms, "%d", rtp->rtm_dst_len);	fprintf(stderr, "Route Deleted: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs);#endif}void LinuxNetLink::_linkAdded(struct nlmsghdr *nlp){	unsigned char mac_bin[6] = {0};	unsigned int mtu = 0;	char ifname[IFNAMSIZ] = {0};	struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp);	struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);	int ifil = RTM_PAYLOAD(nlp);	const char *ptr = (const char *)0;	for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil))	{		switch(rtap->rta_type) {		case IFLA_ADDRESS:			ptr = (const char *)RTA_DATA(rtap);			memcpy(mac_bin, ptr, 6);			break;		case IFLA_IFNAME:			ptr = (const char *)RTA_DATA(rtap);			memcpy(ifname, ptr, strlen(ptr));			break;		case IFLA_MTU:			memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int));			break;		}	}	{		Mutex::Lock l(_if_m);		struct iface_entry &entry = _interfaces[ifip->ifi_index];		entry.index = ifip->ifi_index;		memcpy(entry.ifacename, ifname, sizeof(ifname));		snprintf(entry.mac,sizeof(entry.mac),"%.02x:%.02x:%.02x:%.02x:%.02x:%.02x",(unsigned int)mac_bin[0],(unsigned int)mac_bin[1],(unsigned int)mac_bin[2],(unsigned int)mac_bin[3],(unsigned int)mac_bin[4],(unsigned int)mac_bin[5]);		memcpy(entry.mac_bin, mac_bin, 6);		entry.mtu = mtu;	}}void LinuxNetLink::_linkDeleted(struct nlmsghdr *nlp){	unsigned int mtu = 0;	char ifname[40] = {0};	struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp);	struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);	int ifil = RTM_PAYLOAD(nlp);	const char *ptr = (const char *)0;	for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil))	{		switch(rtap->rta_type) {		case IFLA_IFNAME:			ptr = (const char*)RTA_DATA(rtap);			memcpy(ifname, ptr, strlen(ptr));			break;		case IFLA_MTU:			memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int));			break;		}	}	{		Mutex::Lock l(_if_m);		if(_interfaces.contains(ifip->ifi_index)) {			_interfaces.erase(ifip->ifi_index);		}	}}void LinuxNetLink::_requestIPv4Routes(){	int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);	if (fd == -1) {		fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno));		return;	}	_setSocketTimeout(fd);	struct sockaddr_nl la;	la.nl_family = AF_NETLINK;	la.nl_pid = 0; //getpid();	la.nl_groups = RTMGRP_IPV4_ROUTE;	if(bind(fd, (struct sockaddr*)&la, sizeof(la))) {		fprintf(stderr, "Error binding RTNETLINK (_requestIPv4Routes #1): %s\n", strerror(errno));		close(fd);		return;	}	struct nl_route_req req;	bzero(&req, sizeof(req));	req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));	req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;	req.nl.nlmsg_type = RTM_GETROUTE;	req.nl.nlmsg_pid = 0;	req.nl.nlmsg_seq = ++_seq;	req.rt.rtm_family = AF_INET;	req.rt.rtm_table = RT_TABLE_MAIN;	struct sockaddr_nl pa;	bzero(&pa, sizeof(pa));	pa.nl_family = AF_NETLINK;	struct msghdr msg;	bzero(&msg, sizeof(msg));	msg.msg_name = (void*)&pa;	msg.msg_namelen = sizeof(pa);	struct iovec iov;	bzero(&iov, sizeof(iov));	iov.iov_base = (void*)&req.nl;	iov.iov_len = req.nl.nlmsg_len;	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	sendmsg(fd, &msg, 0);	_doRecv(fd);	close(fd);}void LinuxNetLink::_requestIPv6Routes(){	int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);	if (fd == -1) {		fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno));		return;	}	_setSocketTimeout(fd);	struct sockaddr_nl la;	la.nl_family = AF_NETLINK;	la.nl_pid = 0; //getpid();	la.nl_groups = RTMGRP_IPV6_ROUTE;	if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {		fprintf(stderr, "Error binding RTNETLINK (_requestIPv6Routes #1): %s\n", strerror(errno));		close(fd);		return;	}	struct nl_route_req req;	bzero(&req, sizeof(req));	req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));	req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;	req.nl.nlmsg_type = RTM_GETROUTE;	req.nl.nlmsg_pid = 0;	req.nl.nlmsg_seq = ++_seq;	req.rt.rtm_family = AF_INET6;	req.rt.rtm_table = RT_TABLE_MAIN;	struct sockaddr_nl pa;	bzero(&pa, sizeof(pa));	pa.nl_family = AF_NETLINK;	struct msghdr msg;	bzero(&msg, sizeof(msg));	msg.msg_name = (void*)&pa;	msg.msg_namelen = sizeof(pa);	struct iovec iov;	bzero(&iov, sizeof(iov));	iov.iov_base = (void*)&req.nl;	iov.iov_len = req.nl.nlmsg_len;	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	sendmsg(fd, &msg, 0);	_doRecv(fd);	close(fd);}void LinuxNetLink::_requestInterfaceList(){	int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);	if (fd == -1) {		fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno));		return;	}	_setSocketTimeout(fd);	struct sockaddr_nl la;	la.nl_family = AF_NETLINK;	la.nl_pid = 0; //getpid();	la.nl_groups = RTMGRP_LINK;	if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {		fprintf(stderr, "Error binding RTNETLINK (_requestInterfaceList #1): %s\n", strerror(errno));		close(fd);		return;	}	struct nl_if_req req;	bzero(&req, sizeof(req));	req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));	req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;	req.nl.nlmsg_type = RTM_GETLINK;	req.nl.nlmsg_pid = 0;	req.nl.nlmsg_seq = ++_seq;	req.ifa.ifi_family = AF_UNSPEC;	struct sockaddr_nl pa;	bzero(&pa, sizeof(pa));	pa.nl_family = AF_NETLINK;	struct msghdr msg;	bzero(&msg, sizeof(msg));	msg.msg_name = (void*)&pa;	msg.msg_namelen = sizeof(pa);	struct iovec iov;	bzero(&iov, sizeof(iov));	iov.iov_base = (void*)&req.nl;	iov.iov_len = req.nl.nlmsg_len;	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	sendmsg(fd, &msg, 0);	_doRecv(fd);	close(fd);}void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName){	if (!target) return;	int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);	if (fd == -1) {		fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno));		return;	}	_setSocketTimeout(fd);	struct sockaddr_nl la;	bzero(&la, sizeof(la));	la.nl_family = AF_NETLINK;	la.nl_pid = 0; //getpid();	if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {		fprintf(stderr, "Error binding RTNETLINK (addRoute #1): %s\n", strerror(errno));		close(fd);		return;	}#ifdef ZT_NETLINK_TRACE	char  tmp[64];	char tmp2[64];	char tmp3[64];	fprintf(stderr, "Adding Route. target: %s via: %s src: %s iface: %s\n", target.toString(tmp), via.toString(tmp2), src.toString(tmp3), ifaceName);#endif	int rtl = sizeof(struct rtmsg);	struct nl_route_req req;	bzero(&req, sizeof(req));	struct rtattr *rtap = (struct rtattr *)req.buf;	rtap->rta_type = RTA_DST;	if (target.isV4()) {		rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));		memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr));	} else {		rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));		memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr));	}	rtl += rtap->rta_len;	if(via) {		/*		 *  Setting a metric keeps zerotier routes from taking priority over physical		 *  At best the computer would use zerotier through the router instead of the LAN.		 *  At worst it stops working at all.		 *		 *  default via 192.168.82.1 dev eth0 proto dhcp src 192.168.82.169 metric 202 		 *  10.147.17.0/24 dev zt5u4uptmb proto kernel scope link src 10.147.17.94 		 *  192.168.82.0/24 dev eth0 proto dhcp scope link src 192.168.82.169 metric 202 		 *  192.168.82.0/24 via 10.147.17.1 dev zt5u4uptmb proto static metric 5000 		 *  		*/		rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);		rtap->rta_type = RTA_PRIORITY;		rtap->rta_len = RTA_LENGTH(sizeof(ZT_RTE_METRIC));		memcpy(RTA_DATA(rtap), &ZT_RTE_METRIC, sizeof(ZT_RTE_METRIC));		rtl += rtap->rta_len;		rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len);		rtap->rta_type = RTA_GATEWAY;		if(via.isV4()) {			rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));			memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr));		} else {			rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));			memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr));		}		rtl += rtap->rta_len;	} else if (src) {		rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len);		rtap->rta_type = RTA_SRC;		if(src.isV4()) {			rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));			memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr));		} else {			rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));			memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr));		}		req.rt.rtm_src_len = src.netmaskBits();	}	if (ifaceName != NULL) {		int interface_index = _indexForInterface(ifaceName);		if (interface_index != -1) {			rtap = (struct rtattr *) (((char*)rtap) + rtap->rta_len);			rtap->rta_type = RTA_OIF;			rtap->rta_len = RTA_LENGTH(sizeof(int));			memcpy(RTA_DATA(rtap), &interface_index, sizeof(int));			rtl += rtap->rta_len;		}	}	req.nl.nlmsg_len = NLMSG_LENGTH(rtl);	req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE | NLM_F_ACK;	req.nl.nlmsg_type = RTM_NEWROUTE;	req.nl.nlmsg_pid = 0;	req.nl.nlmsg_seq = ++_seq;	req.rt.rtm_family = target.ss_family;	req.rt.rtm_table = RT_TABLE_MAIN;	req.rt.rtm_protocol = RTPROT_STATIC;	req.rt.rtm_scope = RT_SCOPE_UNIVERSE;	req.rt.rtm_type = RTN_UNICAST;	req.rt.rtm_dst_len = target.netmaskBits();	req.rt.rtm_flags = 0;	struct sockaddr_nl pa;	bzero(&pa, sizeof(pa));	pa.nl_family = AF_NETLINK;	struct msghdr msg;	bzero(&msg, sizeof(msg));	msg.msg_name = (void*)&pa;	msg.msg_namelen = sizeof(pa);	struct iovec iov;	bzero(&iov, sizeof(iov));	iov.iov_base = (void*)&req.nl;	iov.iov_len = req.nl.nlmsg_len;	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	sendmsg(fd, &msg, 0);	_doRecv(fd);	close(fd);}void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName){	if (!target) return;	int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);	if (fd == -1) {		fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno));		return;	}	_setSocketTimeout(fd);	struct sockaddr_nl la;	la.nl_family = AF_NETLINK;	la.nl_pid = 0; //getpid();	if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {		fprintf(stderr, "Error binding RTNETLINK (delRoute #1): %s\n", strerror(errno));		close(fd);		return;	}#ifdef ZT_NETLINK_TRACE	char  tmp[64];	char tmp2[64];	char tmp3[64];	fprintf(stderr, "Removing Route. target: %s via: %s src: %s iface: %s\n", target.toString(tmp), via.toString(tmp2), src.toString(tmp3), ifaceName);#endif	int rtl = sizeof(struct rtmsg);	struct nl_route_req req;	bzero(&req, sizeof(req));	struct rtattr *rtap = (struct rtattr *)req.buf;	rtap->rta_type = RTA_DST;	if (target.isV4()) {		rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));		memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr));	} else {		rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));		memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr));	}	rtl += rtap->rta_len;	if(via) {		rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len);		rtap->rta_type = RTA_GATEWAY;		if(via.isV4()) {			rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));			memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr));		} else {			rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));			memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr));		}		rtl += rtap->rta_len;	} else if (src) {		rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len);		rtap->rta_type = RTA_SRC;		if(src.isV4()) {			rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));			memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr));		} else {			rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));			memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr));		}		req.rt.rtm_src_len = src.netmaskBits();	}	if (ifaceName != NULL) {		int interface_index = _indexForInterface(ifaceName);		if (interface_index != -1) {			rtap = (struct rtattr *) (((char*)rtap) + rtap->rta_len);			rtap->rta_type = RTA_OIF;			rtap->rta_len = RTA_LENGTH(sizeof(int));			memcpy(RTA_DATA(rtap), &interface_index, sizeof(int));			rtl += rtap->rta_len;		}	}	req.nl.nlmsg_len = NLMSG_LENGTH(rtl);	req.nl.nlmsg_flags = NLM_F_REQUEST;	req.nl.nlmsg_type = RTM_DELROUTE;	req.nl.nlmsg_pid = 0;	req.nl.nlmsg_seq = ++_seq;	req.rt.rtm_family = target.ss_family;	req.rt.rtm_table = RT_TABLE_MAIN;	req.rt.rtm_protocol = RTPROT_STATIC;	req.rt.rtm_scope = RT_SCOPE_UNIVERSE;	req.rt.rtm_type = RTN_UNICAST;	req.rt.rtm_dst_len = target.netmaskBits();	req.rt.rtm_flags = 0;	struct sockaddr_nl pa;	bzero(&pa, sizeof(pa));	pa.nl_family = AF_NETLINK;	struct msghdr msg;	bzero(&msg, sizeof(msg));	msg.msg_name = (void*)&pa;	msg.msg_namelen = sizeof(pa);	struct iovec iov;	bzero(&iov, sizeof(iov));	iov.iov_base = (void*)&req.nl;	iov.iov_len = req.nl.nlmsg_len;	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	sendmsg(fd, &msg, 0);	_doRecv(fd);	close(fd);}void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface){	int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);	if (fd == -1) {		fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno));		return;	}	_setSocketTimeout(fd);	struct sockaddr_nl la;	memset(&la,0,sizeof(la));	la.nl_family = AF_NETLINK;	la.nl_pid = 0; //getpid();	if (addr.isV4()) {		la.nl_groups = RTMGRP_IPV4_IFADDR;	} else {		la.nl_groups = RTMGRP_IPV6_IFADDR;	}	if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {		fprintf(stderr, "Error binding RTNETLINK (addAddress #1): %s\n", strerror(errno));		close(fd);		return;	}#ifdef ZT_NETLINK_TRACE	char tmp[128];	fprintf(stderr, "Adding IP address %s to interface %s\n", addr.toString(tmp), iface);#endif	int interface_index = _indexForInterface(iface);	for (int reps = 0; interface_index == -1 && reps < 10; ++reps) {		Thread::sleep(100);		interface_index = _indexForInterface(iface);	}	if (interface_index == -1) {		fprintf(stderr, "Unable to find index for interface %s\n", iface);		close(fd);		return;	}	int rtl = sizeof(struct ifaddrmsg);	struct nl_adr_req req;	bzero(&req, sizeof(struct nl_adr_req));	struct rtattr *rtap = (struct rtattr *)req.buf;;	if(addr.isV4()) {		struct sockaddr_in *addr_v4 = (struct sockaddr_in*)&addr;		rtap->rta_type = IFA_ADDRESS;		rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));		memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr));		rtl += rtap->rta_len;		rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);		rtap->rta_type = IFA_LOCAL;		rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));		memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr));		rtl += rtap->rta_len;		InetAddress broadcast = addr.broadcast();		if(broadcast) {			rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len);			struct sockaddr_in *bcast = (struct sockaddr_in*)&broadcast;			rtap->rta_type = IFA_BROADCAST;			rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));			memcpy(RTA_DATA(rtap), &bcast->sin_addr, sizeof(struct in_addr));			rtl += rtap->rta_len;		}	} else { //V6		rtap->rta_type = IFA_ADDRESS;		struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6*)&addr;		rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));		memcpy(RTA_DATA(rtap), &addr_v6->sin6_addr, sizeof(struct in6_addr));		rtl += rtap->rta_len;	}	if (iface) {		rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len);		rtap->rta_type = IFA_LABEL;		rtap->rta_len = RTA_LENGTH(strlen(iface));		memcpy(RTA_DATA(rtap), iface, strlen(iface));		rtl += rtap->rta_len;	}	req.nl.nlmsg_len = NLMSG_LENGTH(rtl);	req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;	req.nl.nlmsg_type = RTM_NEWADDR;	req.nl.nlmsg_pid = 0;	req.nl.nlmsg_seq = ++_seq;	req.ifa.ifa_family = addr.ss_family;	req.ifa.ifa_prefixlen = addr.port();	req.ifa.ifa_flags = IFA_F_PERMANENT;	req.ifa.ifa_scope = 0;	req.ifa.ifa_index = interface_index;	struct sockaddr_nl pa;	bzero(&pa, sizeof(sockaddr_nl));	pa.nl_family = AF_NETLINK;	struct msghdr msg;	bzero(&msg, sizeof(msg));	msg.msg_name = (void*)&pa;	msg.msg_namelen = sizeof(pa);	struct iovec iov;	iov.iov_base = (void*)&req.nl;	iov.iov_len = req.nl.nlmsg_len;	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	sendmsg(fd, &msg, 0);	_doRecv(fd);	close(fd);}void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface){	int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);	if (fd == -1) {		fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno));		return;	}	_setSocketTimeout(fd);	struct sockaddr_nl la;	la.nl_family = AF_NETLINK;	la.nl_pid = 0; //getpid();	if (addr.isV4()) {		la.nl_groups = RTMGRP_IPV4_IFADDR;	} else {		la.nl_groups = RTMGRP_IPV6_IFADDR;	}	if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {		fprintf(stderr, "Error binding RTNETLINK (removeAddress #1): %s\n", strerror(errno));		close(fd);		return;	}#ifdef ZT_NETLINK_TRACE	char tmp[128];	fprintf(stderr, "Removing IP address %s from interface %s\n", addr.toString(tmp), iface);#endif	int interface_index = _indexForInterface(iface);	if (interface_index == -1) {		fprintf(stderr, "Unable to find index for interface %s\n", iface);		close(fd);		return;	}	int rtl = sizeof(struct ifaddrmsg);	struct nl_adr_req req;	bzero(&req, sizeof(struct nl_adr_req));	struct rtattr *rtap = (struct rtattr *)req.buf;	if(addr.isV4()) {		struct sockaddr_in *addr_v4 = (struct sockaddr_in*)&addr;		rtap->rta_type = IFA_ADDRESS;		rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));		memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr));		rtl += rtap->rta_len;		rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);		rtap->rta_type = IFA_LOCAL;		rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));		memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr));		rtl += rtap->rta_len;		InetAddress broadcast = addr.broadcast();		if(broadcast) {			rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len);			struct sockaddr_in *bcast = (struct sockaddr_in*)&broadcast;			rtap->rta_type = IFA_BROADCAST;			rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));			memcpy(RTA_DATA(rtap), &bcast->sin_addr, sizeof(struct in_addr));			rtl += rtap->rta_len;		}	} else { //V6		rtap->rta_type = IFA_ADDRESS;		struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6*)&addr;		rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));		memcpy(RTA_DATA(rtap), &addr_v6->sin6_addr, sizeof(struct in6_addr));		rtl += rtap->rta_len;	}	if (iface) {		rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len);		rtap->rta_type = IFA_LABEL;		rtap->rta_len = RTA_LENGTH(strlen(iface));		memcpy(RTA_DATA(rtap), iface, strlen(iface));		rtl += rtap->rta_len;	}	req.nl.nlmsg_len = NLMSG_LENGTH(rtl);	req.nl.nlmsg_flags = NLM_F_REQUEST;	req.nl.nlmsg_type = RTM_DELADDR;	req.nl.nlmsg_pid = 0;	req.nl.nlmsg_seq = ++_seq;	req.ifa.ifa_family = addr.ss_family;	req.ifa.ifa_prefixlen = addr.port();	req.ifa.ifa_flags = IFA_F_PERMANENT;	req.ifa.ifa_scope = 0;	req.ifa.ifa_index = interface_index;	struct sockaddr_nl pa;	bzero(&pa, sizeof(sockaddr_nl));	pa.nl_family = AF_NETLINK;	struct msghdr msg;	bzero(&msg, sizeof(msg));	msg.msg_name = (void*)&pa;	msg.msg_namelen = sizeof(pa);	struct iovec iov;	iov.iov_base = (void*)&req.nl;	iov.iov_len = req.nl.nlmsg_len;	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	sendmsg(fd, &msg, 0);	_doRecv(fd);	close(fd);}bool LinuxNetLink::routeIsSet(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname){	Mutex::Lock rl(_routes_m);	const std::set<LinuxNetLink::Route> &rs = _routes[target];	for(std::set<LinuxNetLink::Route>::const_iterator ri(rs.begin());ri!=rs.end();++ri) {		if ((ri->via == via)&&(ri->src == src)) {			if (ifname) {				Mutex::Lock ifl(_if_m);				const iface_entry *ife = _interfaces.get(ri->ifidx);				if ((ife)&&(!strncmp(ife->ifacename,ifname,IFNAMSIZ)))					return true;			} else {				return true;			}		}	}	return false;}int LinuxNetLink::_indexForInterface(const char *iface){	Mutex::Lock l(_if_m);	int interface_index = -1;	Hashtable<int, iface_entry>::Iterator iter(_interfaces);	int *k = NULL;	iface_entry *v = NULL;	while(iter.next(k,v)) {		if(strcmp(iface, v->ifacename) == 0) {			interface_index = v->index;			break;		}	}	return interface_index;}} // namespace ZeroTier#endif
 |