415 lines · 7.1 KB · C
RawDownload
#include "all.h" #include "../ip/ip.h" #define	dprint(...)	if(cons.flags&ralloc.flag)print(__VA_ARGS__) enum{	Version=	1, 	/*	 *  Packet types.	 */	Request=	1,	Response=	2,	Traceon=	3,	Traceoff=	4, 	Infinity=	16,	/* infinite hop count */	Maxpacket=	488,	/* largest packet body */};  /* *  network info */typedef struct Rip	Rip;struct Rip{	uchar	family[2];	uchar	port[2];	uchar	addr[Pasize];	uchar	pad[8];	uchar	metric[4];};typedef struct Ripmsg	Ripmsg;struct Ripmsg{	uchar	type;	uchar	vers;	uchar	pad[2];	Rip	rip[1];		/* the rest of the packet consists of routes */}; enum{	Maxroutes=	(Maxpacket-4)/sizeof(Ripmsg),}; /* *  internal route info */enum{	Nroute	= 2*1024,	Nhash	= 256,		/* routing hash buckets */	Nifc	= 16,}; typedef struct Route	Route;struct Route{	Route	*next; 	uchar	dest[Pasize];	uchar	mask[Pasize];	uchar	gate[Pasize];	int	metric;	int	inuse;	Timet	time;};struct{	Lock;	Route	route[Nroute];	Route	*hash[Nhash];	int	nroute;	ulong	flag;	int 	dorip;} ralloc; uchar classmask[4][4] ={	0xff, 0x00, 0x00, 0x00,	0xff, 0x00, 0x00, 0x00,	0xff, 0xff, 0x00, 0x00,	0xff, 0xff, 0xff, 0x00,}; #define CLASS(p) ((*(uchar*)(p))>>6) static void	considerroute(Route*);static void	deleteroute(Route*);static void	printroute(Route*);static void	printroutes(void);static void	installroute(Route*);static void	getmask(uchar*, uchar*);static void	maskip(uchar*, uchar*, uchar*);static int	equivip(uchar*, uchar*);static void	cmd_route(int, char*[]);static ulong	rhash(uchar*); voidiprouteinit(void){	cmd_install("route", "subcommand -- ip routes", cmd_route);	ralloc.flag = flag_install("route", "-- verbose");	if(!conf.ripoff)		ralloc.dorip = 1;} static voidcmd_route(int argc, char *argv[]){	Route r; 	if(argc < 2) {usage:		print("route add dest gate [mask] -- add a route\n");		print("route delete dest -- remote a route\n");		print("route print [dest] -- print routes\n");		print("route ripon -- listen to RIP packets\n");		print("route ripoff -- ignore RIP packets\n");		return;	}	if(strcmp(argv[1], "ripoff") == 0)		ralloc.dorip = 0;	else if(strcmp(argv[1], "ripon") == 0)		ralloc.dorip = 1;	else if(strcmp(argv[1], "add") == 0) {		switch(argc){		default:			goto usage;		case 4:			memmove(r.mask, classmask[CLASS(r.dest)], Pasize);			break;		case 5:			if(chartoip(r.mask, argv[4]))				goto usage;			break;		}		if(chartoip(r.dest, argv[2]) || chartoip(r.gate, argv[3]))			goto usage;		r.metric = 0;			/* rip can't nuke these */		deleteroute(&r);		considerroute(&r);	} else if(strcmp(argv[1], "delete") == 0) {		if(argc != 3 || chartoip(r.dest, argv[2]))			goto usage;		deleteroute(&r);	} else if(strcmp(argv[1], "print") == 0) {		if(argc == 3) {			if(chartoip(r.dest, argv[2]))				goto usage;			printroute(&r);		} else			printroutes();	}} /* *  consider installing a route.  Do so only if it is better than what *  we have. */static voidconsiderroute(Route *r){	ulong h, i;	ulong m, nm;	Route *hp, **l; 	r->next = 0;	r->time = time();	r->inuse = 1; 	lock(&ralloc);	h = rhash(r->dest);	for(hp = ralloc.hash[h]; hp; hp = hp->next) {		if(equivip(hp->dest, r->dest) && equivip(hp->mask, r->mask)) {			/*			 *  found a match, replace if better (or much newer)			 */			if(r->metric < hp->metric || time()-hp->time > 10*60) {				memmove(hp->gate, r->gate, Pasize);				hp->metric = r->metric;				dprint("route: replacement %I & %I -> %I (%d)\n",					hp->dest, hp->mask, hp->dest, hp->metric);			}			if(equivip(r->gate, hp->gate))				hp->time = time();			goto done;		}	} 	/*	 *  no match, look for space	 */	for(hp = ralloc.route; hp < &ralloc.route[Nroute]; hp++)		if(hp->inuse == 0)			break;	if(hp == &ralloc.route[Nroute])		hp = 0; 	/*	 *  look for an old entry	 */	for(i = 0; hp == 0 && i < Nhash; i++) {		l = &ralloc.hash[i];		for(hp = *l; hp; hp = *l) {			if(time() - hp->time > 10*60 && hp->metric > 0){				*l = hp->next;				break;			}			l = &hp->next;		}	} 	if(hp == 0) {		print("no more routes");		goto done;	} 	memmove(hp, r, sizeof(Route)); 	/*	 *  insert largest mask first	 */	m = nhgetl(hp->mask);	for(l = &ralloc.hash[h]; *l; l = &(*l)->next){		nm = nhgetl((*l)->mask);		if(nm < m)			break;	}	hp->next = *l;	*l = hp;	dprint("route: new %I & %I -> %I (%d)\n", hp->dest, hp->mask,		hp->dest, hp->metric);done:	unlock(&ralloc);} static voiddeleteroute(Route *r){	int h;	Route *hp, **l; 	lock(&ralloc);	for(h = 0; h < Nhash; h++) {		l = &ralloc.hash[h];		for(hp = *l; hp; hp = *l){			if(equivip(r->dest, hp->dest)) {				*l = hp->next;				hp->next = 0;				hp->inuse = 0;				break;			}			l = &hp->next;		}	}	unlock(&ralloc);} static voidprintroutes(void){	Ifc *i;	int h;	Route *hp;	uchar mask[Pasize]; 	lock(&ralloc);	for(h = 0; h < Nhash; h++)		for(hp = ralloc.hash[h]; hp; hp = hp->next)			print("%I & %I -> %I\n", hp->dest, hp->mask, hp->gate);	unlock(&ralloc); 	print("\nifc's\n");	for(i = enets; i; i = i->next) {		hnputl(mask, i->mask);		print("addr %I mask %I defgate %I\n", i->ipa, mask, i->netgate);	}} static voidprintroute(Route *r){	int h;	Route *hp;	uchar net[Pasize]; 	h = rhash(r->dest);	for(hp = ralloc.hash[h]; hp; hp = hp->next){		maskip(r->dest, hp->mask, net);		if(equivip(hp->dest, net)){			print("%I & %I -> %I\n", hp->dest, hp->mask, hp->gate);			return;		}	}	print("default * -> %I\n", enets[0].netgate);} voidiproute(uchar *to, uchar *dst, uchar *def){	int h;	Route *hp;	uchar net[Pasize]; 	h = rhash(dst);	for(hp = ralloc.hash[h]; hp; hp = hp->next) {		maskip(dst, hp->mask, net);		if(equivip(hp->dest, net)) {			def = hp->gate;			break;		}	}	memmove(to, def, Pasize);} voidriprecv(Msgbuf *mb, Ifc*){	int n;	Rip *r;	Ripmsg *m;	Udppkt *uh;	Route route; 	if(ralloc.dorip == 0)		goto drop; 	uh = (Udppkt*)mb->data;	m = (Ripmsg*)(mb->data + Ensize + Ipsize + Udpsize);	if(m->type != Response || m->vers != Version)		goto drop; 	n = nhgets(uh->udplen);	n -= Udpsize;	n = n/sizeof(Rip); 	dprint("%d routes from %I\n", n, uh->src); 	memmove(route.gate, uh->src, Pasize);	for(r = m->rip; r < &m->rip[n]; r++){		getmask(route.mask, r->addr);		maskip(r->addr, route.mask, route.dest);		route.metric = nhgetl(r->metric) + 1;		if(route.metric < 1)			continue;		considerroute(&route);	}drop:	mbfree(mb);} /* *  route's hashed by net, not subnet */static ulongrhash(uchar *d){	ulong h;	uchar net[Pasize]; 	maskip(d, classmask[CLASS(d)], net);	h = net[0] + net[1] + net[2];	return h % Nhash;} /* *  figure out what mask to use, if we have a direct connected network *  with the same class net use its subnet mask. */static voidgetmask(uchar *mask, uchar *dest){	Ifc *i;	long ip; 	ip = nhgetl(dest);	for(i = enets; i; i = i->next)		if((i->ipaddr & i->cmask) == (ip & i->cmask)) {			hnputl(mask, i->mask);			return;		} 	memmove(mask, classmask[CLASS(dest)], Pasize);} static voidmaskip(uchar *a, uchar *m, uchar *n){	int i; 	for(i = 0; i < 4; i++)		n[i] = a[i] & m[i];} static intequivip(uchar *a, uchar *b){	int i; 	for(i = 0; i < 4; i++)		if(a[i] != b[i])			return 0;	return 1;} longipclassmask(uchar *ip){	return nhgetl(classmask[CLASS(ip)]);}