henesyinit from p9fce6d0435 years agoHistory
661 lines · 11.0 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <bio.h>#include <ip.h> #define LOG if(debug)syslog 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=	1000,		/* 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; char	*logname = "rip";int	ripfd;long	now;int	debug; int	nhgets(uchar*);long	nhgetl(uchar*);void	hnputs(uchar*, int);void	hnputl(uchar*, long);int	openport(void);void	readroutes(void);void	readifcs(void);void	considerroute(Route*);void	installroute(Route*);void	removeroute(Route*);uchar	*getmask(uchar*);void	broadcast(void); voidfatal(int syserr, char *fmt, ...){	char buf[ERRLEN], sysbuf[ERRLEN]; 	doprint(buf, buf+sizeof(buf), fmt, (&fmt+1));	if(syserr) {		errstr(sysbuf);		fprint(2, "rip: %s: %s\n", buf, sysbuf);	}	else		fprint(2, "rip: %s\n", buf);	exits(buf);} voidding(void *u, char *msg){	USED(u); 	if(strstr(msg, "alarm"))		noted(NCONT);	noted(NDFLT);} 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]; 	dobroadcast = 0;	ARGBEGIN{	case 'b':		dobroadcast++;		break;	case 'd':		debug++;		break;	default:		fprint(2, "usage: rip [-b]\n");		exits("usage");	}ARGEND 	/* specific broadcast nets */	l = &bnets;	while(argc > 0){		bn = (Bnet*)malloc(sizeof(Bnet));		if(bn == 0)			fatal(1, "out of mem");		parseip(bn->addr, *argv);		*l = bn;		l = &bn->next;		argc--;		argv++;		dobroadcast++;	} 	/* command returns */	switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNOWAIT)) {	case -1:		fatal(1, "fork");	case 0:		break;	default:		exits(0);	}  	fmtinstall('E', eipconv);	fmtinstall('I', eipconv); 	if(stat("/net/iproute", buf) < 0)		bind("#P", "/net", MAFTER); 	readifcs();	readroutes(); 	if(dobroadcast)		notify(ding); 	ripfd = openport();	for(;;) {		if(dobroadcast){			long diff;			static long btime; 			diff = btime - time(0);			if(diff <= 0){				broadcast();				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->ipaddr))				continue; 		now = time(0);		for(r = m->rip; r < &m->rip[n]; r++){			memmove(route.gate, up->ipaddr, Pasize);			memmove(route.mask, getmask(r->addr), Pasize);			maskip(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; 	ripctl = announce("udp!*!rip", devdir);	if(ripctl < 0)		fatal(1, "can't announce");	if(write(ripctl, "headers", 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;} voidreadifcs(void){	int i, n;	char *p;	Biobuf *b;	char *f[6];	Ifc *ip;	Bnet *bn;	Route route; 	b = Bopen("/net/ipifc", OREAD);	if(b == 0)		return;	setfields(" ");	i = 0;	while(p = Brdline(b, '\n')){		if(i >= Nifc)			break;		p[Blinelen(b)-1] = 0;		if(strchr(p, ':'))			break;			/* error summaries in brazil */		n = getmfields(p, f, 6);		if(n < 5)			continue;		ip = &ialloc.ifc[i++];		parseip(ip->addr, f[2]);		parseip(ip->mask, f[3]);		parseip(ip->net, f[4]);		ip->cmask = classmask[CLASS(ip->net)];		maskip(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;	Bterm(b);} voidreadroutes(void){	int n;	char *p;	Biobuf *b;	char *f[6];	Route route; 	b = Bopen("/net/iproute", OREAD);	if(b == 0)		return;	while(p = Brdline(b, '\n')){		p[Blinelen(b)-1] = 0;		n = getmfields(p, f, 6);		if(n < 5)			continue;		parseip(route.dest, f[0]);		parseip(route.mask, f[2]);		parseip(route.gate, f[4]);		route.metric = Infinity;		if(equivip(route.dest, ralloc.def.dest)		&& equivip(route.mask, ralloc.def.mask))			memmove(ralloc.def.gate, route.gate, Pasize);		else			considerroute(&route);	}	Bterm(b);} /* *  route's hashed by net, not subnet */ulongrhash(uchar *d){	ulong h;	uchar net[Pasize]; 	maskip(d, classmask[CLASS(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, i;	Route *hp, **l; 	if(debug)		fprint(2, "consider %16I & %16I -> %16I %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; 	/*	 *  look for an old entry	 */	if(hp == &ralloc.route[Nroute])		for(i = 0; hp == 0 && i < Nhash; i++){			l = &ralloc.hash[i];			for(hp = *l; hp; hp = *l){				if(now - hp->time > 10*60){					removeroute(hp);					*l = hp->next;					break;				}				l = &hp->next;			}		} 	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("/net/iproute", ORDWR);	if(fd < 0){		fprint(2, "rip: can't open iproute: %r\n");		return;	}	fprint(fd, "delete %I", r->dest);	if(debug)		LOG(0, logname, "delete %I", r->dest);	close(fd);} /* *  pass a route to the kernel or /ip.  Don't bother if it is just the default *  gateway. */voidinstallroute(Route *r){	int fd;	ulong h;	Route *hp;	uchar net[Pasize]; 	/* don't install routes that already go through the default */	if(equivip(r->gate, ralloc.def.dest))		return; 	fd = open("/net/iproute", ORDWR);	if(fd < 0){		fprint(2, "rip: can't open iproute: %r\n");		return;	}	h = rhash(r->dest);	if(equivip(r->gate, ralloc.def.gate)){		for(hp = ralloc.hash[h]; hp; hp = hp->next){			maskip(hp->mask, r->dest, net);			if(equivip(net, hp->dest) && !equivip(hp->gate, ralloc.def.gate))				break;		}		if(hp == 0){

Lines 1–500 of 661.