1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier #include <ip.h>
5219b2ee8SDavid du Colombier
6219b2ee8SDavid du Colombier enum
7219b2ee8SDavid du Colombier {
8219b2ee8SDavid du Colombier Version= 1,
9219b2ee8SDavid du Colombier Pasize= 4,
10219b2ee8SDavid du Colombier
11219b2ee8SDavid du Colombier /*
12219b2ee8SDavid du Colombier * definitions that are innately tied to BSD
13219b2ee8SDavid du Colombier */
14219b2ee8SDavid du Colombier AF_INET= 2,
15219b2ee8SDavid du Colombier AF_UNSPEC= 0,
16219b2ee8SDavid du Colombier
17219b2ee8SDavid du Colombier /*
18219b2ee8SDavid du Colombier * Packet types.
19219b2ee8SDavid du Colombier */
20219b2ee8SDavid du Colombier Request= 1,
21219b2ee8SDavid du Colombier Response= 2,
22219b2ee8SDavid du Colombier Traceon= 3,
23219b2ee8SDavid du Colombier Traceoff= 4,
24219b2ee8SDavid du Colombier
25219b2ee8SDavid du Colombier Infinity= 16, /* infinite hop count */
26219b2ee8SDavid du Colombier Maxpacket= 488, /* largest packet body */
27219b2ee8SDavid du Colombier };
28219b2ee8SDavid du Colombier
29219b2ee8SDavid du Colombier
30219b2ee8SDavid du Colombier /*
31219b2ee8SDavid du Colombier * network info
32219b2ee8SDavid du Colombier */
33219b2ee8SDavid du Colombier typedef struct Rip Rip;
34219b2ee8SDavid du Colombier struct Rip
35219b2ee8SDavid du Colombier {
36219b2ee8SDavid du Colombier uchar family[2];
37219b2ee8SDavid du Colombier uchar port[2];
38219b2ee8SDavid du Colombier uchar addr[Pasize];
39219b2ee8SDavid du Colombier uchar pad[8];
40219b2ee8SDavid du Colombier uchar metric[4];
41219b2ee8SDavid du Colombier };
42219b2ee8SDavid du Colombier typedef struct Ripmsg Ripmsg;
43219b2ee8SDavid du Colombier struct Ripmsg
44219b2ee8SDavid du Colombier {
45219b2ee8SDavid du Colombier uchar type;
46219b2ee8SDavid du Colombier uchar vers;
47219b2ee8SDavid du Colombier uchar pad[2];
48219b2ee8SDavid du Colombier Rip rip[1]; /* the rest of the packet consists of routes */
49219b2ee8SDavid du Colombier };
50219b2ee8SDavid du Colombier
51219b2ee8SDavid du Colombier enum
52219b2ee8SDavid du Colombier {
53219b2ee8SDavid du Colombier Maxroutes= (Maxpacket-4)/sizeof(Ripmsg),
54219b2ee8SDavid du Colombier };
55219b2ee8SDavid du Colombier
56219b2ee8SDavid du Colombier /*
57219b2ee8SDavid du Colombier * internal route info
58219b2ee8SDavid du Colombier */
59219b2ee8SDavid du Colombier enum
60219b2ee8SDavid du Colombier {
617dd7cddfSDavid du Colombier Nroute= 2048, /* this has to be smaller than what /ip has */
62219b2ee8SDavid du Colombier Nhash= 256, /* routing hash buckets */
63219b2ee8SDavid du Colombier Nifc= 16,
64219b2ee8SDavid du Colombier };
65219b2ee8SDavid du Colombier
66219b2ee8SDavid du Colombier typedef struct Route Route;
67219b2ee8SDavid du Colombier struct Route
68219b2ee8SDavid du Colombier {
69219b2ee8SDavid du Colombier Route *next;
70219b2ee8SDavid du Colombier
71219b2ee8SDavid du Colombier uchar dest[Pasize];
72219b2ee8SDavid du Colombier uchar mask[Pasize];
73219b2ee8SDavid du Colombier uchar gate[Pasize];
74219b2ee8SDavid du Colombier int metric;
75219b2ee8SDavid du Colombier int inuse;
76219b2ee8SDavid du Colombier long time;
77219b2ee8SDavid du Colombier };
78219b2ee8SDavid du Colombier struct {
79219b2ee8SDavid du Colombier Route route[Nroute];
80219b2ee8SDavid du Colombier Route *hash[Nhash];
81219b2ee8SDavid du Colombier int nroute;
82219b2ee8SDavid du Colombier Route def; /* default route (immutable by us) */
83219b2ee8SDavid du Colombier } ralloc;
84219b2ee8SDavid du Colombier
85219b2ee8SDavid du Colombier typedef struct Ifc Ifc;
86219b2ee8SDavid du Colombier struct Ifc
87219b2ee8SDavid du Colombier {
88219b2ee8SDavid du Colombier int bcast;
89219b2ee8SDavid du Colombier uchar addr[Pasize]; /* my address */
90219b2ee8SDavid du Colombier uchar mask[Pasize]; /* subnet mask */
91219b2ee8SDavid du Colombier uchar net[Pasize]; /* subnet */
92219b2ee8SDavid du Colombier uchar *cmask; /* class mask */
93219b2ee8SDavid du Colombier uchar cnet[Pasize]; /* class net */
94219b2ee8SDavid du Colombier };
95219b2ee8SDavid du Colombier struct {
96219b2ee8SDavid du Colombier Ifc ifc[Nifc];
97219b2ee8SDavid du Colombier int nifc;
98219b2ee8SDavid du Colombier } ialloc;
99219b2ee8SDavid du Colombier
100219b2ee8SDavid du Colombier /*
101219b2ee8SDavid du Colombier * specific networks to broadcast on
102219b2ee8SDavid du Colombier */
103219b2ee8SDavid du Colombier typedef struct Bnet Bnet;
104219b2ee8SDavid du Colombier struct Bnet
105219b2ee8SDavid du Colombier {
106219b2ee8SDavid du Colombier Bnet *next;
107219b2ee8SDavid du Colombier uchar addr[Pasize];
108219b2ee8SDavid du Colombier };
109219b2ee8SDavid du Colombier Bnet *bnets;
110219b2ee8SDavid du Colombier
111219b2ee8SDavid du Colombier int ripfd;
112219b2ee8SDavid du Colombier long now;
113219b2ee8SDavid du Colombier int debug;
1147dd7cddfSDavid du Colombier int readonly;
1157dd7cddfSDavid du Colombier char routefile[256];
1167dd7cddfSDavid du Colombier char netdir[256];
117219b2ee8SDavid du Colombier
118219b2ee8SDavid du Colombier int openport(void);
119219b2ee8SDavid du Colombier void readroutes(void);
120219b2ee8SDavid du Colombier void readifcs(void);
121219b2ee8SDavid du Colombier void considerroute(Route*);
122219b2ee8SDavid du Colombier void installroute(Route*);
123219b2ee8SDavid du Colombier void removeroute(Route*);
124219b2ee8SDavid du Colombier uchar *getmask(uchar*);
125219b2ee8SDavid du Colombier void broadcast(void);
1267dd7cddfSDavid du Colombier void timeoutroutes(void);
127219b2ee8SDavid du Colombier
128219b2ee8SDavid du Colombier void
fatal(int syserr,char * fmt,...)129219b2ee8SDavid du Colombier fatal(int syserr, char *fmt, ...)
130219b2ee8SDavid du Colombier {
1319a747e4fSDavid du Colombier char buf[ERRMAX], sysbuf[ERRMAX];
1327dd7cddfSDavid du Colombier va_list arg;
133219b2ee8SDavid du Colombier
1347dd7cddfSDavid du Colombier va_start(arg, fmt);
1359a747e4fSDavid du Colombier vseprint(buf, buf+sizeof(buf), fmt, arg);
1367dd7cddfSDavid du Colombier va_end(arg);
137219b2ee8SDavid du Colombier if(syserr) {
1389a747e4fSDavid du Colombier errstr(sysbuf, sizeof sysbuf);
1397dd7cddfSDavid du Colombier fprint(2, "routed: %s: %s\n", buf, sysbuf);
140219b2ee8SDavid du Colombier }
141219b2ee8SDavid du Colombier else
1427dd7cddfSDavid du Colombier fprint(2, "routed: %s\n", buf);
143219b2ee8SDavid du Colombier exits(buf);
144219b2ee8SDavid du Colombier }
145219b2ee8SDavid du Colombier
1467dd7cddfSDavid du Colombier ulong
v4parseipmask(uchar * ip,char * p)1477dd7cddfSDavid du Colombier v4parseipmask(uchar *ip, char *p)
1487dd7cddfSDavid du Colombier {
1497dd7cddfSDavid du Colombier ulong x;
1507dd7cddfSDavid du Colombier uchar v6ip[IPaddrlen];
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier x = parseipmask(v6ip, p);
1537dd7cddfSDavid du Colombier memmove(ip, v6ip+IPv4off, 4);
1547dd7cddfSDavid du Colombier return x;
1557dd7cddfSDavid du Colombier }
1567dd7cddfSDavid du Colombier
1577dd7cddfSDavid du Colombier uchar*
v4defmask(uchar * ip)1587dd7cddfSDavid du Colombier v4defmask(uchar *ip)
1597dd7cddfSDavid du Colombier {
1607dd7cddfSDavid du Colombier uchar v6ip[IPaddrlen];
1617dd7cddfSDavid du Colombier
1627dd7cddfSDavid du Colombier v4tov6(v6ip, ip);
1637dd7cddfSDavid du Colombier ip = defmask(v6ip);
1647dd7cddfSDavid du Colombier return ip+IPv4off;
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier
1677dd7cddfSDavid du Colombier void
v4maskip(uchar * from,uchar * mask,uchar * to)1687dd7cddfSDavid du Colombier v4maskip(uchar *from, uchar *mask, uchar *to)
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier int i;
1717dd7cddfSDavid du Colombier
1727dd7cddfSDavid du Colombier for(i = 0; i < Pasize; i++)
1737dd7cddfSDavid du Colombier *to++ = *from++ & *mask++;
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier
1767dd7cddfSDavid du Colombier void
v6tov4mask(uchar * v4,uchar * v6)1777dd7cddfSDavid du Colombier v6tov4mask(uchar *v4, uchar *v6)
1787dd7cddfSDavid du Colombier {
1797dd7cddfSDavid du Colombier memmove(v4, v6+IPv4off, 4);
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier
1827dd7cddfSDavid du Colombier #define equivip(a, b) (memcmp((a), (b), Pasize) == 0)
1837dd7cddfSDavid du Colombier
184219b2ee8SDavid du Colombier void
ding(void * u,char * msg)185219b2ee8SDavid du Colombier ding(void *u, char *msg)
186219b2ee8SDavid du Colombier {
187219b2ee8SDavid du Colombier USED(u);
188219b2ee8SDavid du Colombier
189219b2ee8SDavid du Colombier if(strstr(msg, "alarm"))
190219b2ee8SDavid du Colombier noted(NCONT);
191219b2ee8SDavid du Colombier noted(NDFLT);
192219b2ee8SDavid du Colombier }
193219b2ee8SDavid du Colombier
194219b2ee8SDavid du Colombier void
usage(void)1957dd7cddfSDavid du Colombier usage(void)
1967dd7cddfSDavid du Colombier {
1977dd7cddfSDavid du Colombier fprint(2, "usage: %s [-bnd] [-x netmtpt]\n", argv0);
1987dd7cddfSDavid du Colombier exits("usage");
1997dd7cddfSDavid du Colombier }
2007dd7cddfSDavid du Colombier
2017dd7cddfSDavid du Colombier void
main(int argc,char * argv[])202219b2ee8SDavid du Colombier main(int argc, char *argv[])
203219b2ee8SDavid du Colombier {
204*f27a9a5aSDavid du Colombier int dobroadcast, i, n;
2057dd7cddfSDavid du Colombier long diff;
2067dd7cddfSDavid du Colombier char *p;
207*f27a9a5aSDavid du Colombier char buf[2*1024];
2081e8349ebSDavid du Colombier uchar raddr[Pasize];
209*f27a9a5aSDavid du Colombier Bnet *bn, **l;
210*f27a9a5aSDavid du Colombier Udphdr *up;
211*f27a9a5aSDavid du Colombier Rip *r;
212*f27a9a5aSDavid du Colombier Ripmsg *m;
213*f27a9a5aSDavid du Colombier Route route;
214*f27a9a5aSDavid du Colombier static long btime;
2157dd7cddfSDavid du Colombier
2167dd7cddfSDavid du Colombier setnetmtpt(netdir, sizeof(netdir), nil);
217219b2ee8SDavid du Colombier dobroadcast = 0;
218219b2ee8SDavid du Colombier ARGBEGIN{
219219b2ee8SDavid du Colombier case 'b':
220219b2ee8SDavid du Colombier dobroadcast++;
221219b2ee8SDavid du Colombier break;
222219b2ee8SDavid du Colombier case 'd':
223219b2ee8SDavid du Colombier debug++;
224219b2ee8SDavid du Colombier break;
2257dd7cddfSDavid du Colombier case 'n':
2267dd7cddfSDavid du Colombier readonly++;
2277dd7cddfSDavid du Colombier break;
2287dd7cddfSDavid du Colombier case 'x':
2297dd7cddfSDavid du Colombier p = ARGF();
2307dd7cddfSDavid du Colombier if(p == nil)
2317dd7cddfSDavid du Colombier usage();
2327dd7cddfSDavid du Colombier setnetmtpt(netdir, sizeof(netdir), p);
2337dd7cddfSDavid du Colombier break;
234219b2ee8SDavid du Colombier default:
2357dd7cddfSDavid du Colombier usage();
236219b2ee8SDavid du Colombier }ARGEND
237219b2ee8SDavid du Colombier
238219b2ee8SDavid du Colombier /* specific broadcast nets */
239219b2ee8SDavid du Colombier l = &bnets;
240219b2ee8SDavid du Colombier while(argc > 0){
241219b2ee8SDavid du Colombier bn = (Bnet*)malloc(sizeof(Bnet));
242219b2ee8SDavid du Colombier if(bn == 0)
243219b2ee8SDavid du Colombier fatal(1, "out of mem");
2447dd7cddfSDavid du Colombier v4parseip(bn->addr, *argv);
245219b2ee8SDavid du Colombier *l = bn;
246219b2ee8SDavid du Colombier l = &bn->next;
247219b2ee8SDavid du Colombier argc--;
248219b2ee8SDavid du Colombier argv++;
249219b2ee8SDavid du Colombier dobroadcast++;
250219b2ee8SDavid du Colombier }
251219b2ee8SDavid du Colombier
252219b2ee8SDavid du Colombier /* command returns */
2537dd7cddfSDavid du Colombier if(!debug)
254219b2ee8SDavid du Colombier switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNOWAIT)) {
255219b2ee8SDavid du Colombier case -1:
256219b2ee8SDavid du Colombier fatal(1, "fork");
257219b2ee8SDavid du Colombier case 0:
258219b2ee8SDavid du Colombier break;
259219b2ee8SDavid du Colombier default:
260219b2ee8SDavid du Colombier exits(0);
261219b2ee8SDavid du Colombier }
262219b2ee8SDavid du Colombier
263219b2ee8SDavid du Colombier
2649a747e4fSDavid du Colombier fmtinstall('E', eipfmt);
2659a747e4fSDavid du Colombier fmtinstall('V', eipfmt);
266219b2ee8SDavid du Colombier
2677dd7cddfSDavid du Colombier snprint(routefile, sizeof(routefile), "%s/iproute", netdir);
2687dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "%s/iproute", netdir);
269219b2ee8SDavid du Colombier
2707dd7cddfSDavid du Colombier now = time(0);
271219b2ee8SDavid du Colombier readifcs();
272219b2ee8SDavid du Colombier readroutes();
273219b2ee8SDavid du Colombier
274219b2ee8SDavid du Colombier notify(ding);
275219b2ee8SDavid du Colombier
276219b2ee8SDavid du Colombier ripfd = openport();
277219b2ee8SDavid du Colombier for(;;) {
278219b2ee8SDavid du Colombier diff = btime - time(0);
279219b2ee8SDavid du Colombier if(diff <= 0){
2807dd7cddfSDavid du Colombier if(dobroadcast)
281219b2ee8SDavid du Colombier broadcast();
2827dd7cddfSDavid du Colombier timeoutroutes();
2837dd7cddfSDavid du Colombier
284219b2ee8SDavid du Colombier btime = time(0) + 2*60;
285219b2ee8SDavid du Colombier diff = 2*60;
286219b2ee8SDavid du Colombier }
287219b2ee8SDavid du Colombier alarm(diff*1000);
288219b2ee8SDavid du Colombier n = read(ripfd, buf, sizeof(buf));
289219b2ee8SDavid du Colombier alarm(0);
290219b2ee8SDavid du Colombier if(n <= 0)
291219b2ee8SDavid du Colombier continue;
292219b2ee8SDavid du Colombier
293*f27a9a5aSDavid du Colombier n = (n - Udphdrsize - 4) / sizeof(Rip);
294219b2ee8SDavid du Colombier if(n <= 0)
295219b2ee8SDavid du Colombier continue;
296219b2ee8SDavid du Colombier
297*f27a9a5aSDavid du Colombier up = (Udphdr*)buf;
298*f27a9a5aSDavid du Colombier m = (Ripmsg*)(buf+Udphdrsize);
299219b2ee8SDavid du Colombier if(m->type != Response || m->vers != Version)
300219b2ee8SDavid du Colombier continue;
3011e8349ebSDavid du Colombier v6tov4(raddr, up->raddr);
302219b2ee8SDavid du Colombier
303219b2ee8SDavid du Colombier /* ignore our own messages */
304219b2ee8SDavid du Colombier for(i = 0; i < ialloc.nifc; i++)
3051e8349ebSDavid du Colombier if(equivip(ialloc.ifc[i].addr, raddr))
306219b2ee8SDavid du Colombier continue;
307219b2ee8SDavid du Colombier
308219b2ee8SDavid du Colombier now = time(0);
309219b2ee8SDavid du Colombier for(r = m->rip; r < &m->rip[n]; r++){
3101e8349ebSDavid du Colombier memmove(route.gate, raddr, Pasize);
311219b2ee8SDavid du Colombier memmove(route.mask, getmask(r->addr), Pasize);
3127dd7cddfSDavid du Colombier v4maskip(r->addr, route.mask, route.dest);
313219b2ee8SDavid du Colombier route.metric = nhgetl(r->metric) + 1;
314219b2ee8SDavid du Colombier if(route.metric < 1)
315219b2ee8SDavid du Colombier continue;
316219b2ee8SDavid du Colombier considerroute(&route);
317219b2ee8SDavid du Colombier }
318219b2ee8SDavid du Colombier }
319b85a8364SDavid du Colombier /* not reached */
320219b2ee8SDavid du Colombier }
321219b2ee8SDavid du Colombier
322219b2ee8SDavid du Colombier int
openport(void)323219b2ee8SDavid du Colombier openport(void)
324219b2ee8SDavid du Colombier {
325219b2ee8SDavid du Colombier int ripctl, rip;
326*f27a9a5aSDavid du Colombier char data[128], devdir[40];
327219b2ee8SDavid du Colombier
3287dd7cddfSDavid du Colombier snprint(data, sizeof(data), "%s/udp!*!rip", netdir);
3297dd7cddfSDavid du Colombier ripctl = announce(data, devdir);
330219b2ee8SDavid du Colombier if(ripctl < 0)
331219b2ee8SDavid du Colombier fatal(1, "can't announce");
3321e8349ebSDavid du Colombier if(fprint(ripctl, "headers") < 0)
333219b2ee8SDavid du Colombier fatal(1, "can't set header mode");
334219b2ee8SDavid du Colombier
335219b2ee8SDavid du Colombier sprint(data, "%s/data", devdir);
336219b2ee8SDavid du Colombier rip = open(data, ORDWR);
337219b2ee8SDavid du Colombier if(rip < 0)
338219b2ee8SDavid du Colombier fatal(1, "open udp data");
339219b2ee8SDavid du Colombier return rip;
340219b2ee8SDavid du Colombier }
341219b2ee8SDavid du Colombier
3429a747e4fSDavid du Colombier Ipifc *ifcs;
3437dd7cddfSDavid du Colombier
344219b2ee8SDavid du Colombier void
readifcs(void)345219b2ee8SDavid du Colombier readifcs(void)
346219b2ee8SDavid du Colombier {
3479a747e4fSDavid du Colombier Ipifc *ifc;
3489a747e4fSDavid du Colombier Iplifc *lifc;
349219b2ee8SDavid du Colombier Ifc *ip;
350219b2ee8SDavid du Colombier Bnet *bn;
351219b2ee8SDavid du Colombier Route route;
3527dd7cddfSDavid du Colombier int i;
353219b2ee8SDavid du Colombier
3549a747e4fSDavid du Colombier ifcs = readipifc(netdir, ifcs, -1);
355219b2ee8SDavid du Colombier i = 0;
3569a747e4fSDavid du Colombier for(ifc = ifcs; ifc != nil; ifc = ifc->next){
3579a747e4fSDavid du Colombier for(lifc = ifc->lifc; lifc != nil && i < Nifc; lifc = lifc->next){
3587dd7cddfSDavid du Colombier // ignore any interfaces that aren't v4
3599a747e4fSDavid du Colombier if(memcmp(lifc->ip, v4prefix, IPaddrlen-IPv4addrlen) != 0)
360219b2ee8SDavid du Colombier continue;
361219b2ee8SDavid du Colombier ip = &ialloc.ifc[i++];
3629a747e4fSDavid du Colombier v6tov4(ip->addr, lifc->ip);
3639a747e4fSDavid du Colombier v6tov4mask(ip->mask, lifc->mask);
3649a747e4fSDavid du Colombier v6tov4(ip->net, lifc->net);
3657dd7cddfSDavid du Colombier ip->cmask = v4defmask(ip->net);
3667dd7cddfSDavid du Colombier v4maskip(ip->net, ip->cmask, ip->cnet);
367219b2ee8SDavid du Colombier ip->bcast = 0;
368219b2ee8SDavid du Colombier
369219b2ee8SDavid du Colombier /* add as a route */
370219b2ee8SDavid du Colombier memmove(route.mask, ip->mask, Pasize);
371219b2ee8SDavid du Colombier memmove(route.dest, ip->net, Pasize);
372219b2ee8SDavid du Colombier memset(route.gate, 0, Pasize);
373219b2ee8SDavid du Colombier route.metric = 0;
374219b2ee8SDavid du Colombier considerroute(&route);
375219b2ee8SDavid du Colombier
376219b2ee8SDavid du Colombier /* mark as broadcast */
377219b2ee8SDavid du Colombier if(bnets == 0)
378219b2ee8SDavid du Colombier ip->bcast = 1;
379219b2ee8SDavid du Colombier else for(bn = bnets; bn; bn = bn->next)
380219b2ee8SDavid du Colombier if(memcmp(bn->addr, ip->net, Pasize) == 0){
381219b2ee8SDavid du Colombier ip->bcast = 1;
382219b2ee8SDavid du Colombier break;
383219b2ee8SDavid du Colombier }
384219b2ee8SDavid du Colombier }
3859a747e4fSDavid du Colombier }
386219b2ee8SDavid du Colombier ialloc.nifc = i;
387219b2ee8SDavid du Colombier }
388219b2ee8SDavid du Colombier
389219b2ee8SDavid du Colombier void
readroutes(void)390219b2ee8SDavid du Colombier readroutes(void)
391219b2ee8SDavid du Colombier {
392219b2ee8SDavid du Colombier int n;
393219b2ee8SDavid du Colombier char *p;
394219b2ee8SDavid du Colombier Biobuf *b;
395219b2ee8SDavid du Colombier char *f[6];
396219b2ee8SDavid du Colombier Route route;
397219b2ee8SDavid du Colombier
3987dd7cddfSDavid du Colombier b = Bopen(routefile, OREAD);
399219b2ee8SDavid du Colombier if(b == 0)
400219b2ee8SDavid du Colombier return;
401219b2ee8SDavid du Colombier while(p = Brdline(b, '\n')){
402219b2ee8SDavid du Colombier p[Blinelen(b)-1] = 0;
4037dd7cddfSDavid du Colombier n = getfields(p, f, 6, 1, " \t");
404219b2ee8SDavid du Colombier if(n < 5)
405219b2ee8SDavid du Colombier continue;
4067dd7cddfSDavid du Colombier v4parseip(route.dest, f[0]);
4077dd7cddfSDavid du Colombier v4parseipmask(route.mask, f[1]);
4087dd7cddfSDavid du Colombier v4parseip(route.gate, f[2]);
409219b2ee8SDavid du Colombier route.metric = Infinity;
410219b2ee8SDavid du Colombier if(equivip(route.dest, ralloc.def.dest)
411219b2ee8SDavid du Colombier && equivip(route.mask, ralloc.def.mask))
412219b2ee8SDavid du Colombier memmove(ralloc.def.gate, route.gate, Pasize);
4137dd7cddfSDavid du Colombier else if(!equivip(route.dest, route.gate) && strchr(f[3], 'i') == 0)
414219b2ee8SDavid du Colombier considerroute(&route);
415219b2ee8SDavid du Colombier }
416219b2ee8SDavid du Colombier Bterm(b);
417219b2ee8SDavid du Colombier }
418219b2ee8SDavid du Colombier
419219b2ee8SDavid du Colombier /*
420219b2ee8SDavid du Colombier * route's hashed by net, not subnet
421219b2ee8SDavid du Colombier */
422219b2ee8SDavid du Colombier ulong
rhash(uchar * d)423219b2ee8SDavid du Colombier rhash(uchar *d)
424219b2ee8SDavid du Colombier {
425219b2ee8SDavid du Colombier ulong h;
426219b2ee8SDavid du Colombier uchar net[Pasize];
427219b2ee8SDavid du Colombier
4287dd7cddfSDavid du Colombier v4maskip(d, v4defmask(d), net);
429219b2ee8SDavid du Colombier h = net[0] + net[1] + net[2];
430219b2ee8SDavid du Colombier return h % Nhash;
431219b2ee8SDavid du Colombier }
432219b2ee8SDavid du Colombier
433219b2ee8SDavid du Colombier /*
434219b2ee8SDavid du Colombier * consider installing a route. Do so only if it is better than what
435219b2ee8SDavid du Colombier * we have.
436219b2ee8SDavid du Colombier */
437219b2ee8SDavid du Colombier void
considerroute(Route * r)438219b2ee8SDavid du Colombier considerroute(Route *r)
439219b2ee8SDavid du Colombier {
4407dd7cddfSDavid du Colombier ulong h;
4417dd7cddfSDavid du Colombier Route *hp;
442219b2ee8SDavid du Colombier
443219b2ee8SDavid du Colombier if(debug)
4447dd7cddfSDavid du Colombier fprint(2, "consider %16V & %16V -> %16V %d\n", r->dest, r->mask, r->gate, r->metric);
445219b2ee8SDavid du Colombier
446219b2ee8SDavid du Colombier r->next = 0;
447219b2ee8SDavid du Colombier r->time = now;
448219b2ee8SDavid du Colombier r->inuse = 1;
449219b2ee8SDavid du Colombier
450219b2ee8SDavid du Colombier /* don't allow our default route to be highjacked */
451219b2ee8SDavid du Colombier if(equivip(r->dest, ralloc.def.dest) || equivip(r->mask, ralloc.def.mask))
452219b2ee8SDavid du Colombier return;
453219b2ee8SDavid du Colombier
454219b2ee8SDavid du Colombier h = rhash(r->dest);
455219b2ee8SDavid du Colombier for(hp = ralloc.hash[h]; hp; hp = hp->next){
456219b2ee8SDavid du Colombier if(equivip(hp->dest, r->dest)){
457219b2ee8SDavid du Colombier /*
458219b2ee8SDavid du Colombier * found a match, replace if better (or much newer)
459219b2ee8SDavid du Colombier */
460219b2ee8SDavid du Colombier if(r->metric < hp->metric || now-hp->time > 5*60){
461219b2ee8SDavid du Colombier removeroute(hp);
462219b2ee8SDavid du Colombier memmove(hp->mask, r->mask, Pasize);
463219b2ee8SDavid du Colombier memmove(hp->gate, r->gate, Pasize);
464219b2ee8SDavid du Colombier hp->metric = r->metric;
465219b2ee8SDavid du Colombier installroute(hp);
466219b2ee8SDavid du Colombier }
467219b2ee8SDavid du Colombier if(equivip(hp->gate, r->gate))
468219b2ee8SDavid du Colombier hp->time = now;
469219b2ee8SDavid du Colombier return;
470219b2ee8SDavid du Colombier }
471219b2ee8SDavid du Colombier }
472219b2ee8SDavid du Colombier
473219b2ee8SDavid du Colombier /*
474219b2ee8SDavid du Colombier * no match, look for space
475219b2ee8SDavid du Colombier */
476219b2ee8SDavid du Colombier for(hp = ralloc.route; hp < &ralloc.route[Nroute]; hp++)
477219b2ee8SDavid du Colombier if(hp->inuse == 0)
478219b2ee8SDavid du Colombier break;
479219b2ee8SDavid du Colombier
480219b2ee8SDavid du Colombier if(hp == 0)
481219b2ee8SDavid du Colombier fatal(0, "no more routes");
482219b2ee8SDavid du Colombier
483219b2ee8SDavid du Colombier memmove(hp, r, sizeof(Route));
484219b2ee8SDavid du Colombier hp->next = ralloc.hash[h];
485219b2ee8SDavid du Colombier ralloc.hash[h] = hp;
486219b2ee8SDavid du Colombier installroute(hp);
487219b2ee8SDavid du Colombier }
488219b2ee8SDavid du Colombier
489219b2ee8SDavid du Colombier void
removeroute(Route * r)490219b2ee8SDavid du Colombier removeroute(Route *r)
491219b2ee8SDavid du Colombier {
492219b2ee8SDavid du Colombier int fd;
493219b2ee8SDavid du Colombier
4947dd7cddfSDavid du Colombier fd = open(routefile, ORDWR);
495219b2ee8SDavid du Colombier if(fd < 0){
4967dd7cddfSDavid du Colombier fprint(2, "can't open oproute\n");
497219b2ee8SDavid du Colombier return;
498219b2ee8SDavid du Colombier }
4997dd7cddfSDavid du Colombier if(!readonly)
5007dd7cddfSDavid du Colombier fprint(fd, "delete %V", r->dest);
501219b2ee8SDavid du Colombier if(debug)
5027dd7cddfSDavid du Colombier fprint(2, "removeroute %V\n", r->dest);
503219b2ee8SDavid du Colombier close(fd);
504219b2ee8SDavid du Colombier }
505219b2ee8SDavid du Colombier
506219b2ee8SDavid du Colombier /*
507219b2ee8SDavid du Colombier * pass a route to the kernel or /ip. Don't bother if it is just the default
508219b2ee8SDavid du Colombier * gateway.
509219b2ee8SDavid du Colombier */
510219b2ee8SDavid du Colombier void
installroute(Route * r)511219b2ee8SDavid du Colombier installroute(Route *r)
512219b2ee8SDavid du Colombier {
513219b2ee8SDavid du Colombier int fd;
514219b2ee8SDavid du Colombier ulong h;
515219b2ee8SDavid du Colombier Route *hp;
516219b2ee8SDavid du Colombier uchar net[Pasize];
517219b2ee8SDavid du Colombier
5187dd7cddfSDavid du Colombier /*
5197dd7cddfSDavid du Colombier * don't install routes whose gateway is 00000000
5207dd7cddfSDavid du Colombier */
521219b2ee8SDavid du Colombier if(equivip(r->gate, ralloc.def.dest))
522219b2ee8SDavid du Colombier return;
523219b2ee8SDavid du Colombier
5247dd7cddfSDavid du Colombier fd = open(routefile, ORDWR);
525219b2ee8SDavid du Colombier if(fd < 0){
5267dd7cddfSDavid du Colombier fprint(2, "can't open oproute\n");
527219b2ee8SDavid du Colombier return;
528219b2ee8SDavid du Colombier }
529219b2ee8SDavid du Colombier h = rhash(r->dest);
5307dd7cddfSDavid du Colombier
5317dd7cddfSDavid du Colombier /*
5327dd7cddfSDavid du Colombier * if the gateway is the same as the default gateway
5337dd7cddfSDavid du Colombier * we may be able to avoid a entry in the kernel
5347dd7cddfSDavid du Colombier */
535219b2ee8SDavid du Colombier if(equivip(r->gate, ralloc.def.gate)){
5367dd7cddfSDavid du Colombier /*
5377dd7cddfSDavid du Colombier * look for a less specific match
5387dd7cddfSDavid du Colombier */
539219b2ee8SDavid du Colombier for(hp = ralloc.hash[h]; hp; hp = hp->next){
5407dd7cddfSDavid du Colombier v4maskip(hp->mask, r->dest, net);
541219b2ee8SDavid du Colombier if(equivip(net, hp->dest) && !equivip(hp->gate, ralloc.def.gate))
542219b2ee8SDavid du Colombier break;
543219b2ee8SDavid du Colombier }
5447dd7cddfSDavid du Colombier /*
5457dd7cddfSDavid du Colombier * if no less specific match, just use the default
5467dd7cddfSDavid du Colombier */
547219b2ee8SDavid du Colombier if(hp == 0){
5487dd7cddfSDavid du Colombier if(!readonly)
5497dd7cddfSDavid du Colombier fprint(fd, "delete %V", r->dest);
550219b2ee8SDavid du Colombier if(debug)
5517dd7cddfSDavid du Colombier fprint(2, "delete %V\n", r->dest);
552219b2ee8SDavid du Colombier close(fd);
553219b2ee8SDavid du Colombier return;
554219b2ee8SDavid du Colombier }
555219b2ee8SDavid du Colombier }
5567dd7cddfSDavid du Colombier if(!readonly)
5577dd7cddfSDavid du Colombier fprint(fd, "add %V %V %V", r->dest, r->mask, r->gate);
558219b2ee8SDavid du Colombier if(debug)
5597dd7cddfSDavid du Colombier fprint(2, "add %V & %V -> %V\n", r->dest, r->mask, r->gate);
560219b2ee8SDavid du Colombier close(fd);
561219b2ee8SDavid du Colombier }
562219b2ee8SDavid du Colombier
563219b2ee8SDavid du Colombier /*
564219b2ee8SDavid du Colombier * return true of dest is on net
565219b2ee8SDavid du Colombier */
566219b2ee8SDavid du Colombier int
onnet(uchar * dest,uchar * net,uchar * netmask)567219b2ee8SDavid du Colombier onnet(uchar *dest, uchar *net, uchar *netmask)
568219b2ee8SDavid du Colombier {
569219b2ee8SDavid du Colombier uchar dnet[Pasize];
570219b2ee8SDavid du Colombier
5717dd7cddfSDavid du Colombier v4maskip(dest, netmask, dnet);
572219b2ee8SDavid du Colombier return equivip(dnet, net);
573219b2ee8SDavid du Colombier }
574219b2ee8SDavid du Colombier
575219b2ee8SDavid du Colombier /*
576219b2ee8SDavid du Colombier * figure out what mask to use, if we have a direct connected network
577219b2ee8SDavid du Colombier * with the same class net use its subnet mask.
578219b2ee8SDavid du Colombier */
579219b2ee8SDavid du Colombier uchar*
getmask(uchar * dest)580219b2ee8SDavid du Colombier getmask(uchar *dest)
581219b2ee8SDavid du Colombier {
582219b2ee8SDavid du Colombier int i;
583219b2ee8SDavid du Colombier Ifc *ip;
584219b2ee8SDavid du Colombier ulong mask, nmask;
585219b2ee8SDavid du Colombier uchar *m;
586219b2ee8SDavid du Colombier
587219b2ee8SDavid du Colombier m = 0;
588219b2ee8SDavid du Colombier mask = 0xffffffff;
589219b2ee8SDavid du Colombier for(i = 0; i < ialloc.nifc; i++){
590219b2ee8SDavid du Colombier ip = &ialloc.ifc[i];
591219b2ee8SDavid du Colombier if(onnet(dest, ip->cnet, ip->cmask)){
592219b2ee8SDavid du Colombier nmask = nhgetl(ip->mask);
593219b2ee8SDavid du Colombier if(nmask < mask){
594219b2ee8SDavid du Colombier mask = nmask;
595219b2ee8SDavid du Colombier m = ip->mask;
596219b2ee8SDavid du Colombier }
597219b2ee8SDavid du Colombier }
598219b2ee8SDavid du Colombier }
599219b2ee8SDavid du Colombier
600219b2ee8SDavid du Colombier if(m == 0)
6017dd7cddfSDavid du Colombier m = v4defmask(dest);
602219b2ee8SDavid du Colombier return m;
603219b2ee8SDavid du Colombier }
604219b2ee8SDavid du Colombier
605219b2ee8SDavid du Colombier /*
606219b2ee8SDavid du Colombier * broadcast routes onto all networks
607219b2ee8SDavid du Colombier */
608219b2ee8SDavid du Colombier void
sendto(Ifc * ip)609219b2ee8SDavid du Colombier sendto(Ifc *ip)
610219b2ee8SDavid du Colombier {
611219b2ee8SDavid du Colombier int h, n;
612*f27a9a5aSDavid du Colombier uchar raddr[Pasize], mbuf[Udphdrsize+512];
613219b2ee8SDavid du Colombier Ripmsg *m;
614*f27a9a5aSDavid du Colombier Route *r;
615*f27a9a5aSDavid du Colombier Udphdr *u;
616219b2ee8SDavid du Colombier
617*f27a9a5aSDavid du Colombier u = (Udphdr*)mbuf;
618219b2ee8SDavid du Colombier for(n = 0; n < Pasize; n++)
6191e8349ebSDavid du Colombier raddr[n] = ip->net[n] | ~(ip->mask[n]);
6201e8349ebSDavid du Colombier v4tov6(u->raddr, raddr);
6217dd7cddfSDavid du Colombier hnputs(u->rport, 520);
622*f27a9a5aSDavid du Colombier m = (Ripmsg*)(mbuf+Udphdrsize);
623219b2ee8SDavid du Colombier m->type = Response;
624219b2ee8SDavid du Colombier m->vers = Version;
625219b2ee8SDavid du Colombier if(debug)
6267dd7cddfSDavid du Colombier fprint(2, "to %V\n", u->raddr);
627219b2ee8SDavid du Colombier
628219b2ee8SDavid du Colombier n = 0;
629219b2ee8SDavid du Colombier for(h = 0; h < Nhash; h++){
630219b2ee8SDavid du Colombier for(r = ralloc.hash[h]; r; r = r->next){
631219b2ee8SDavid du Colombier /*
632219b2ee8SDavid du Colombier * don't send any route back to the net
633219b2ee8SDavid du Colombier * it came from
634219b2ee8SDavid du Colombier */
635219b2ee8SDavid du Colombier if(onnet(r->gate, ip->net, ip->mask))
636219b2ee8SDavid du Colombier continue;
637219b2ee8SDavid du Colombier
638219b2ee8SDavid du Colombier /*
639219b2ee8SDavid du Colombier * don't tell a network about itself
640219b2ee8SDavid du Colombier */
641219b2ee8SDavid du Colombier if(equivip(r->dest, ip->net))
642219b2ee8SDavid du Colombier continue;
643219b2ee8SDavid du Colombier
644219b2ee8SDavid du Colombier /*
645219b2ee8SDavid du Colombier * don't tell nets about other net's subnets
646219b2ee8SDavid du Colombier */
6477dd7cddfSDavid du Colombier if(!equivip(r->mask, v4defmask(r->dest))
6487dd7cddfSDavid du Colombier && !equivip(ip->cmask, v4defmask(r->dest)))
649219b2ee8SDavid du Colombier continue;
650219b2ee8SDavid du Colombier
651219b2ee8SDavid du Colombier memset(&m->rip[n], 0, sizeof(m->rip[n]));
652219b2ee8SDavid du Colombier memmove(m->rip[n].addr, r->dest, Pasize);
653219b2ee8SDavid du Colombier if(r->metric < 1)
654219b2ee8SDavid du Colombier hnputl(m->rip[n].metric, 1);
655219b2ee8SDavid du Colombier else
656219b2ee8SDavid du Colombier hnputl(m->rip[n].metric, r->metric);
657219b2ee8SDavid du Colombier hnputs(m->rip[n].family, AF_INET);
658219b2ee8SDavid du Colombier
659219b2ee8SDavid du Colombier if(debug)
660*f27a9a5aSDavid du Colombier fprint(2, " %16V & %16V -> %16V %2d\n",
661*f27a9a5aSDavid du Colombier r->dest, r->mask, r->gate, r->metric);
662219b2ee8SDavid du Colombier
6637dd7cddfSDavid du Colombier if(++n == Maxroutes && !readonly){
664*f27a9a5aSDavid du Colombier write(ripfd, mbuf, Udphdrsize + 4 + n*20);
665219b2ee8SDavid du Colombier n = 0;
666219b2ee8SDavid du Colombier }
667219b2ee8SDavid du Colombier }
668219b2ee8SDavid du Colombier }
669219b2ee8SDavid du Colombier
6707dd7cddfSDavid du Colombier if(n && !readonly)
671*f27a9a5aSDavid du Colombier write(ripfd, mbuf, Udphdrsize+4+n*20);
672219b2ee8SDavid du Colombier }
673219b2ee8SDavid du Colombier void
broadcast(void)674219b2ee8SDavid du Colombier broadcast(void)
675219b2ee8SDavid du Colombier {
676219b2ee8SDavid du Colombier int i;
677219b2ee8SDavid du Colombier
678219b2ee8SDavid du Colombier readifcs();
679219b2ee8SDavid du Colombier for(i = 0; i < ialloc.nifc; i++){
680219b2ee8SDavid du Colombier if(ialloc.ifc[i].bcast)
681219b2ee8SDavid du Colombier sendto(&ialloc.ifc[i]);
682219b2ee8SDavid du Colombier }
683219b2ee8SDavid du Colombier }
684219b2ee8SDavid du Colombier
6857dd7cddfSDavid du Colombier /*
6867dd7cddfSDavid du Colombier * timeout any routes that haven't been refreshed and aren't wired
6877dd7cddfSDavid du Colombier */
688219b2ee8SDavid du Colombier void
timeoutroutes(void)6897dd7cddfSDavid du Colombier timeoutroutes(void)
690219b2ee8SDavid du Colombier {
6917dd7cddfSDavid du Colombier int h;
6927dd7cddfSDavid du Colombier long now;
6937dd7cddfSDavid du Colombier Route *r, **l;
694219b2ee8SDavid du Colombier
6957dd7cddfSDavid du Colombier now = time(0);
6967dd7cddfSDavid du Colombier
6977dd7cddfSDavid du Colombier for(h = 0; h < Nhash; h++){
6987dd7cddfSDavid du Colombier l = &ralloc.hash[h];
6997dd7cddfSDavid du Colombier for(r = *l; r; r = *l){
7007dd7cddfSDavid du Colombier if(r->metric < Infinity && now - r->time > 10*60){
7017dd7cddfSDavid du Colombier removeroute(r);
7027dd7cddfSDavid du Colombier r->inuse = 0;
7037dd7cddfSDavid du Colombier *l = r->next;
7047dd7cddfSDavid du Colombier continue;
7057dd7cddfSDavid du Colombier }
7067dd7cddfSDavid du Colombier l = &r->next;
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier }
709219b2ee8SDavid du Colombier }
710