henesyinit from p9f0ed2a895 years agoHistory
707 lines · 11.9 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <bio.h>#include <ip.h> enum{	Version=	1,	Pasize=		4, 	/*	 *  definitions that are innately tied to BSD	 */	AF_INET=	2,	AF_UNSPEC=	0, 	/*	 *  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=	2048,		/* this has to be smaller than what /ip has */	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;	long	time;};struct {	Route	route[Nroute];	Route	*hash[Nhash];	int	nroute;	Route	def;	/* default route (immutable by us) */} ralloc; typedef struct Ifc	Ifc;struct Ifc{	int	bcast;	uchar	addr[Pasize];	/* my address */	uchar	mask[Pasize];	/* subnet mask */	uchar	net[Pasize];	/* subnet */	uchar	*cmask;		/* class mask */	uchar	cnet[Pasize];	/* class net */};struct {	Ifc	ifc[Nifc];	int	nifc;} ialloc; /* *  specific networks to broadcast on */typedef struct Bnet Bnet;struct Bnet{	Bnet	*next;	uchar	addr[Pasize];};Bnet	*bnets; int	ripfd;long	now;int	debug;int	readonly;char	routefile[256];char	netdir[256]; int	openport(void);void	readroutes(void);void	readifcs(void);void	considerroute(Route*);void	installroute(Route*);void	removeroute(Route*);uchar	*getmask(uchar*);void	broadcast(void);void	timeoutroutes(void); voidfatal(int syserr, char *fmt, ...){	char buf[ERRLEN], sysbuf[ERRLEN];	va_list arg; 	va_start(arg, fmt);	doprint(buf, buf+sizeof(buf), fmt, arg);	va_end(arg);	if(syserr) {		errstr(sysbuf);		fprint(2, "routed: %s: %s\n", buf, sysbuf);	}	else		fprint(2, "routed: %s\n", buf);	exits(buf);} ulongv4parseipmask(uchar *ip, char *p){	ulong x;	uchar v6ip[IPaddrlen]; 	x = parseipmask(v6ip, p);	memmove(ip, v6ip+IPv4off, 4);	return x;} uchar*v4defmask(uchar *ip){	uchar v6ip[IPaddrlen]; 	v4tov6(v6ip, ip);	ip = defmask(v6ip);	return ip+IPv4off;} voidv4maskip(uchar *from, uchar *mask, uchar *to){	int i; 	for(i = 0; i < Pasize; i++)		*to++ = *from++ & *mask++;} voidv6tov4mask(uchar *v4, uchar *v6){	memmove(v4, v6+IPv4off, 4);} #define equivip(a, b) (memcmp((a), (b), Pasize) == 0) voidding(void *u, char *msg){	USED(u); 	if(strstr(msg, "alarm"))		noted(NCONT);	noted(NDFLT);} voidusage(void){	fprint(2, "usage: %s [-bnd] [-x netmtpt]\n", argv0);	exits("usage");} voidmain(int argc, char *argv[]){	int i, n;	Udphdr *up;	Ripmsg *m;	Rip *r;	Route route;	Bnet *bn, **l;	int dobroadcast;	char buf[2*1024];	long diff;	char *p;	static long btime;  	setnetmtpt(netdir, sizeof(netdir), nil);	dobroadcast = 0;	ARGBEGIN{	case 'b':		dobroadcast++;		break;	case 'd':		debug++;		break;	case 'n':		readonly++;		break;	case 'x':		p = ARGF();		if(p == nil)			usage();		setnetmtpt(netdir, sizeof(netdir), p);		break;	default:		usage();	}ARGEND 	/* specific broadcast nets */	l = &bnets;	while(argc > 0){		bn = (Bnet*)malloc(sizeof(Bnet));		if(bn == 0)			fatal(1, "out of mem");		v4parseip(bn->addr, *argv);		*l = bn;		l = &bn->next;		argc--;		argv++;		dobroadcast++;	} 	/* command returns */	if(!debug)		switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNOWAIT)) {		case -1:			fatal(1, "fork");		case 0:			break;		default:			exits(0);		}  	fmtinstall('E', eipconv);	fmtinstall('V', eipconv); 	snprint(routefile, sizeof(routefile), "%s/iproute", netdir);	snprint(buf, sizeof(buf), "%s/iproute", netdir); 	now = time(0);	readifcs();	readroutes(); 	notify(ding); 	ripfd = openport();	for(;;) {		diff = btime - time(0);		if(diff <= 0){			if(dobroadcast)				broadcast();			timeoutroutes(); 			btime = time(0) + 2*60;			diff = 2*60;		}		alarm(diff*1000);		n = read(ripfd, buf, sizeof(buf));		alarm(0);		if(n <= 0)			continue; 		n = (n-Udphdrsize-4)/sizeof(Rip);		if(n <= 0)			continue; 		up = (Udphdr*)buf;		m = (Ripmsg*)(buf+Udphdrsize);		if(m->type != Response || m->vers != Version)			continue; 		/* ignore our own messages */		for(i = 0; i < ialloc.nifc; i++)			if(equivip(ialloc.ifc[i].addr, up->raddr))				continue; 		now = time(0);		for(r = m->rip; r < &m->rip[n]; r++){			memmove(route.gate, up->raddr, Pasize);			memmove(route.mask, getmask(r->addr), Pasize);			v4maskip(r->addr, route.mask, route.dest);			route.metric = nhgetl(r->metric) + 1;			if(route.metric < 1)				continue;			considerroute(&route);		}	}	exits(0);} intopenport(void){	char data[128];	char devdir[40];	int ripctl, rip; 	snprint(data, sizeof(data), "%s/udp!*!rip", netdir);	ripctl = announce(data, devdir);	if(ripctl < 0)		fatal(1, "can't announce");	if(write(ripctl, "headers4", sizeof("headers")) < 0)		fatal(1, "can't set header mode"); 	sprint(data, "%s/data", devdir); 	rip = open(data, ORDWR);	if(rip < 0)		fatal(1, "open udp data");	return rip;} Ipifc *ipifcs; voidreadifcs(void){	Ipifc *ipifc;	Ifc *ip;	Bnet *bn;	Route route;	int i; 	ipifcs = readipifc(netdir, ipifcs);	i = 0;	for(ipifc = ipifcs; ipifc && i < Nifc; ipifc = ipifc->next){		// ignore any interfaces that aren't v4		if(memcmp(ipifc->ip, v4prefix, IPaddrlen-IPv4addrlen) != 0)			continue;		ip = &ialloc.ifc[i++];		v6tov4(ip->addr, ipifc->ip);		v6tov4mask(ip->mask, ipifc->mask);		v6tov4(ip->net, ipifc->net);		ip->cmask = v4defmask(ip->net);		v4maskip(ip->net, ip->cmask, ip->cnet);		ip->bcast = 0; 		/* add as a route */		memmove(route.mask, ip->mask, Pasize);		memmove(route.dest, ip->net, Pasize);		memset(route.gate, 0, Pasize);		route.metric = 0;		considerroute(&route); 		/* mark as broadcast */		if(bnets == 0)			ip->bcast = 1;		else for(bn = bnets; bn; bn = bn->next)			if(memcmp(bn->addr, ip->net, Pasize) == 0){				ip->bcast = 1;				break;			}	}	ialloc.nifc = i;} voidreadroutes(void){	int n;	char *p;	Biobuf *b;	char *f[6];	Route route; 	b = Bopen(routefile, OREAD);	if(b == 0)		return;	while(p = Brdline(b, '\n')){		p[Blinelen(b)-1] = 0;		n = getfields(p, f, 6, 1, " \t");		if(n < 5)			continue;		v4parseip(route.dest, f[0]);		v4parseipmask(route.mask, f[1]);		v4parseip(route.gate, f[2]);		route.metric = Infinity;		if(equivip(route.dest, ralloc.def.dest)		&& equivip(route.mask, ralloc.def.mask))			memmove(ralloc.def.gate, route.gate, Pasize);		else if(!equivip(route.dest, route.gate) && strchr(f[3], 'i') == 0)			considerroute(&route);	}	Bterm(b);} /* *  route's hashed by net, not subnet */ulongrhash(uchar *d){	ulong h;	uchar net[Pasize]; 	v4maskip(d, v4defmask(d), net);	h = net[0] + net[1] + net[2];	return h % Nhash;} /* *  consider installing a route.  Do so only if it is better than what *  we have. */voidconsiderroute(Route *r){	ulong h;	Route *hp; 	if(debug)		fprint(2, "consider %16V & %16V -> %16V %d\n", r->dest, r->mask, r->gate, r->metric); 	r->next = 0;	r->time = now;	r->inuse = 1; 	/* don't allow our default route to be highjacked */	if(equivip(r->dest, ralloc.def.dest) || equivip(r->mask, ralloc.def.mask))		return; 	h = rhash(r->dest);	for(hp = ralloc.hash[h]; hp; hp = hp->next){		if(equivip(hp->dest, r->dest)){			/*			 *  found a match, replace if better (or much newer)			 */			if(r->metric < hp->metric || now-hp->time > 5*60){				removeroute(hp);				memmove(hp->mask, r->mask, Pasize);				memmove(hp->gate, r->gate, Pasize);				hp->metric = r->metric;				installroute(hp);			}			if(equivip(hp->gate, r->gate))				hp->time = now;			return;		}	} 	/*	 *  no match, look for space	 */	for(hp = ralloc.route; hp < &ralloc.route[Nroute]; hp++)		if(hp->inuse == 0)			break; 	if(hp == 0)		fatal(0, "no more routes"); 	memmove(hp, r, sizeof(Route));	hp->next = ralloc.hash[h];	ralloc.hash[h] = hp;	installroute(hp);} voidremoveroute(Route *r){	int fd; 	fd = open(routefile, ORDWR);	if(fd < 0){		fprint(2, "can't open oproute\n");		return;	}	if(!readonly)		fprint(fd, "delete %V", r->dest);	if(debug)

Lines 1–500 of 707.