X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/3cec0c76b6a82a40affe3630b97f94ec413c4d36..74d7f201d24fe264792f7e1837dbb6384f7d87c9:/usr/src/sbin/routed/routed.c diff --git a/usr/src/sbin/routed/routed.c b/usr/src/sbin/routed/routed.c index f10612ad7d..3bb1f0edfe 100644 --- a/usr/src/sbin/routed/routed.c +++ b/usr/src/sbin/routed/routed.c @@ -1,5 +1,5 @@ #ifndef lint -static char sccsid[] = "@(#)routed.c 4.6 %G%"; +static char sccsid[] = "@(#)routed.c 4.13 %G%"; #endif /* @@ -14,6 +14,7 @@ static char sccsid[] = "@(#)routed.c 4.6 %G%"; #include #include #include +#include #include "rip.h" #include "router.h" @@ -34,16 +35,17 @@ struct nlist nl[] = { struct sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER }; int s; +int snoroute; /* socket with no routing */ int kmem = -1; int supplier; /* process should supply updates */ -int initializing; /* stem off broadcast() calls */ -int install = 0; /* if 1 call kernel */ +int install = 1; /* if 1 call kernel */ int lookforinterfaces = 1; int performnlist = 1; int timeval; int timer(); int cleanup(); int trace = 0; +FILE *ftrace; char packet[MAXPACKETSIZE]; @@ -59,18 +61,27 @@ main(argc, argv) int cc; struct sockaddr from; - { int t = open("/dev/tty", 2); - if (t >= 0) { - ioctl(t, TIOCNOTTY, 0); - close(t); - } +#ifndef DEBUG + if (fork()) + exit(0); + for (cc = 0; cc < 10; cc++) + (void) close(cc); + (void) open("/", 0); + (void) dup2(0, 1); + (void) dup2(0, 2); + { int t = open("/dev/tty", 2); + if (t >= 0) { + ioctl(t, TIOCNOTTY, (char *)0); + (void) close(t); + } } +#endif if (trace) { - (void) freopen("/etc/routerlog", "a", stdout); - (void) dup2(fileno(stdout), 2); - setbuf(stdout, NULL); + ftrace = fopen("/etc/routerlog", "w"); + dup2(fileno(ftrace), 1); + dup2(fileno(ftrace), 2); } -#ifdef vax +#ifdef vax || pdp11 myaddr.sin_port = htons(myaddr.sin_port); #endif again: @@ -80,11 +91,15 @@ again: sleep(30); goto again; } +again2: + snoroute = socket(SOCK_DGRAM, 0, 0, SO_DONTROUTE); + if (snoroute < 0) { + perror("socket"); + sleep(30); + goto again2; + } rtinit(); - getothers(); - initializing = 1; getinterfaces(); - initializing = 0; request(); argv++, argc--; @@ -114,45 +129,12 @@ again: } } -/* - * Look in a file for any gateways we should configure - * outside the directly connected ones. This is a kludge, - * but until we can find out about gateways on the "other side" - * of the ARPANET using GGP, it's a must. - * - * We don't really know the distance to the gateway, so we - * assume it's a neighbor. - */ -getothers() -{ - struct sockaddr_in dst, gate; - FILE *fp = fopen("/etc/gateways", "r"); - struct rt_entry *rt; - - if (fp == NULL) - return; - bzero((char *)&dst, sizeof (dst)); - bzero((char *)&gate, sizeof (gate)); - dst.sin_family = AF_INET; - gate.sin_family = AF_INET; - while (fscanf(fp, "%x %x", &dst.sin_addr.s_addr, - &gate.sin_addr.s_addr) != EOF) { - rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1); - rt = rtlookup((struct sockaddr *)&dst); - if (rt) - rt->rt_flags |= RTF_SILENT; - } - fclose(fp); -} - /* * Timer routine: * * o handle timers on table entries, * o invalidate entries which haven't been updated in a while, * o delete entries which are too old, - * o retry ioctl's which weren't successful the first - * time due to the kernel entry being busy * o if we're an internetwork router, supply routing updates * periodically */ @@ -172,11 +154,11 @@ again: /* * If the host is indicated to be - * "silent" (i.e. it's one we got + * "hidden" (i.e. it's one we got * from the initialization file), * don't time out it's entry. */ - if ((rt->rt_flags & RTF_SILENT) == 0) + if ((rt->rt_state & RTS_PASSIVE) == 0) rt->rt_timer += TIMER_RATE; log("", rt); @@ -185,10 +167,9 @@ again: * attempt to do so and reclaim space. */ if (rt->rt_timer >= GARBAGE_TIME || - (rt->rt_flags & RTF_DELRT)) { - rt = rt->rt_forw; - rtdelete(rt->rt_back); + (rt->rt_state & RTS_DELRT)) { rt = rt->rt_back; + rtdelete(rt->rt_forw); continue; } @@ -199,32 +180,32 @@ again: */ if (rt->rt_timer >= EXPIRE_TIME) rt->rt_metric = HOPCNT_INFINITY; - if (rt->rt_flags & RTF_CHGRT) - if (!ioctl(s, SIOCCHGRT,(char *)&rt->rt_rt) || - --rt->rt_retry == 0) - rt->rt_flags &= ~RTF_CHGRT; /* - * Try to add the route to the kernel tables. - * If this fails because the entry already exists - * (perhaps because someone manually added it) - * change the add to a change. If the operation - * fails otherwise (likely because the entry is - * in use), retry the operation a few more times. + * If a change or addition is to be made + * and this isn't time to broadcast an + * update, then broadcast the change. */ - if (rt->rt_flags & RTF_ADDRT) { - if (!ioctl(s, SIOCADDRT,(char *)&rt->rt_rt)) { - if (errno == EEXIST) { - rt->rt_flags &= ~RTF_ADDRT; - rt->rt_flags |= RTF_CHGRT; - rt->rt_retry = - (EXPIRE_TIME/TIMER_RATE); - continue; - } - if (--rt->rt_retry) - continue; - } - rt->rt_flags &= ~RTF_ADDRT; + if ((rt->rt_state & (RTS_CHGRT|RTS_ADDRT)) && + supplier && + (timeval + TIMER_RATE) % SUPPLY_INTERVAL) + broadcast(rt); + + if (rt->rt_state & RTS_CHGRT) { + struct rtentry oldroute; + + oldroute = rt->rt_rt; + rt->rt_router = rt->rt_newrouter; + if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) + perror("SIOCADDRT"); + if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0) + perror("SIOCDELRT"); + rt->rt_state &= ~RTS_CHGRT; + } + if (rt->rt_state & RTS_ADDRT) { + if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) + perror("SIOCADDRT"); + rt->rt_state &= ~RTS_ADDRT; } } } @@ -293,18 +274,19 @@ getinterfaces() } bzero((char *)&net, sizeof (net)); net.sin_family = AF_INET; + lookforinterfaces = 0; nets = 0; while (ifp) { if (lseek(kmem, (long)ifp, 0) == -1 || read(kmem, (char *)&ifstruct, sizeof (ifstruct)) != sizeof (ifstruct)) { perror("read"); - performnlist = 1; + lookforinterfaces = performnlist = 1; break; } ifp = &ifstruct; if ((ifp->if_flags & IFF_UP) == 0) { - lookforinterfaces++; + lookforinterfaces = 1; skip: ifp = ifp->if_next; continue; @@ -345,11 +327,60 @@ getinterfaces() next = ifp->if_next; ifp->if_next = ifnet; ifnet = ifp; - if (rtlookup(dst) == 0) + if (rtlookup(dst) == 0) { + struct rt_entry *rt; + rtadd(dst, &ifp->if_addr, 0); + rt = rtlookup(dst); + if (rt) + rt->rt_state |= RTS_INTERFACE; + } ifp = next; } supplier = nets > 1; + getothers(); +} + +/* + * Look in a file for any gateways we should configure + * outside the directly connected ones. This is a kludge, + * but until we can find out about gateways on the "other side" + * of the ARPANET using GGP, it's a must. + * + * File format is one entry per line, + * destination gateway flags (all hex #'s) + * + * We don't really know the distance to the gateway, so we + * assume it's a neighbor. + */ +getothers() +{ + struct sockaddr_in dst, gate; + FILE *fp; + struct rt_entry *rt; + char flags[132]; + + fp = fopen("/etc/gateways", "r"); + if (fp == NULL) + return; + bzero((char *)&dst, sizeof (dst)); + bzero((char *)&gate, sizeof (gate)); + dst.sin_family = AF_INET; + gate.sin_family = AF_INET; + flags[0] = '\0'; + while (fscanf(fp, "dst %x gateway %x %s\n", &dst.sin_addr.s_addr, + &gate.sin_addr.s_addr, flags) != EOF) { + if (rt = rtlookup((struct sockaddr *)&dst)) { + flags[0] = '\0'; + continue; + } + rtadd((struct sockaddr *)&dst,(struct sockaddr *)&gate,1); + rt = rtlookup(&dst); + if (strcmp(flags, "passive") == 0) + rt->rt_state |= RTS_PASSIVE; + flags[0] = '\0'; + } + fclose(fp); } /* @@ -396,13 +427,14 @@ sendall() again: for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { - if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) + if ((rt->rt_state&RTS_PASSIVE) || rt->rt_metric > 0) continue; if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) dst = &rt->rt_ifp->if_broadaddr; else - dst = &rt->rt_gateway; - (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip)); + dst = &rt->rt_router; + (*afswitch[dst->sa_family].af_output) + (s, dst, sizeof (struct rip)); } if (doinghost) { base = nethash; @@ -426,14 +458,15 @@ supplyall() again: for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { - if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0) + if ((rt->rt_state&RTS_PASSIVE) || + (!(rt->rt_state&RTS_INTERFACE) && rt->rt_metric > 0)) continue; if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST)) dst = &rt->rt_ifp->if_broadaddr; else - dst = &rt->rt_gateway; + dst = &rt->rt_router; log("supply", rt); - supply(dst); + supply(rt->rt_state&RTS_INTERFACE ? snoroute : s, dst); } if (doinghost) { base = nethash; @@ -445,7 +478,8 @@ again: /* * Supply routing information to target "sa". */ -supply(sa) +supply(s, sa) + int s; struct sockaddr *sa; { struct rip *msg = (struct rip *)packet; @@ -467,7 +501,7 @@ again: */ size = (char *)n - packet; if (size > MAXPACKETSIZE - sizeof (struct netinfo)) { - (*output)(sa, size); + (*output)(s, sa, size); n = msg->rip_nets; } n->rip_dst = rt->rt_dst; @@ -480,7 +514,7 @@ again: goto again; } if (n != msg->rip_nets) - (*output)(sa, (char *)n - packet); + (*output)(s, sa, (char *)n - packet); } /* @@ -502,7 +536,7 @@ rip_respond(from, size) size -= sizeof (struct netinfo); if (np->rip_dst.sa_family == AF_UNSPEC && np->rip_metric == HOPCNT_INFINITY && size == 0) { - supply(from); + supply(s, from); return; } rt = rtlookup(&np->rip_dst); @@ -513,7 +547,7 @@ rip_respond(from, size) if (newsize > 0) { msg->rip_cmd = RIPCMD_RESPONSE; newsize += sizeof (int); - (*afswitch[from->sa_family].af_output)(from, newsize); + (*afswitch[from->sa_family].af_output)(s, from, newsize); } } @@ -528,16 +562,28 @@ rip_input(from, size) struct rt_entry *rt; struct netinfo *n; - if (msg->rip_cmd != RIPCMD_RESPONSE && - msg->rip_cmd != RIPCMD_REQUEST) - return; + switch (msg->rip_cmd) { - if (msg->rip_cmd == RIPCMD_RESPONSE && - (*afswitch[from->sa_family].af_portmatch)(from) == 0) + default: return; - if (msg->rip_cmd == RIPCMD_REQUEST) { + + case RIPCMD_REQUEST: rip_respond(from, size); return; + + case RIPCMD_TRACEON: + case RIPCMD_TRACEOFF: + /* verify message came from a priviledged port */ + if ((*afswitch[from->sa_family].af_portcheck)(from) == 0) + return; + tracecmd(msg->rip_cmd, msg, size); + return; + + case RIPCMD_RESPONSE: + /* verify message came from a router */ + if ((*afswitch[from->sa_family].af_portmatch)(from) == 0) + return; + break; } /* @@ -560,7 +606,7 @@ rip_input(from, size) * don't hear their own broadcasts? */ if (if_ifwithaddr(from)) { - rt = rtlookup(from); + rt = rtfind(from); if (rt) rt->rt_timer = 0; return; @@ -590,7 +636,7 @@ rip_input(from, size) if (trace) printf("ours: gate %x hc %d timer %d\n", - ((struct sockaddr_in *)&rt->rt_gateway)->sin_addr, + ((struct sockaddr_in *)&rt->rt_router)->sin_addr, rt->rt_metric, rt->rt_timer); /* * Update the entry if one of the following is true: @@ -601,7 +647,7 @@ rip_input(from, size) * and a path of equivalent cost is offered * (with the cost finite). */ - if (equal(from, &rt->rt_gateway) || + if (equal(from, &rt->rt_router) || rt->rt_metric > n->rip_metric || (rt->rt_timer > (EXPIRE_TIME/2) && rt->rt_metric == n->rip_metric && @@ -612,6 +658,40 @@ rip_input(from, size) } } +/* + * Handle tracing requests. + */ +tracecmd(cmd, msg, size) + int cmd, size; + struct rip *msg; +{ + time_t t; + + if (cmd == RIPCMD_TRACEOFF) { + if (!trace) + return; + t = time(0); + printf("*** Tracing turned off at %.24s ***\n", ctime(&t)); + fflush(stdout), fflush(stderr); + if (ftrace) + fclose(ftrace); + (void) close(1), (void) close(2); + trace = 0; + return; + } + if (trace) + return; + packet[size] = '\0'; + ftrace = fopen(msg->rip_tracefile, "a"); + if (ftrace == NULL) + return; + (void) dup2(fileno(ftrace), 1); + (void) dup2(fileno(ftrace), 2); + trace = 1; + t = time(0); + printf("*** Tracing turned on at %.24s ***\n", ctime(&t)); +} + rtinit() { register struct rthash *rh; @@ -631,9 +711,47 @@ rtlookup(dst) { register struct rt_entry *rt; register struct rthash *rh; - register int hash, (*match)(); + register int hash; struct afhash h; - int af = dst->sa_family, doinghost = 1; + int doinghost = 1; + + if (dst->sa_family >= AF_MAX) + return (0); + (*afswitch[dst->sa_family].af_hash)(dst, &h); + hash = h.afh_hosthash; + rh = &hosthash[hash % ROUTEHASHSIZ]; +again: + for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) { + if (rt->rt_hash != hash) + continue; + if (equal(&rt->rt_dst, dst)) + return (rt); + } + if (doinghost) { + doinghost = 0; + hash = h.afh_nethash; + rh = &nethash[hash % ROUTEHASHSIZ]; + goto again; + } + return (0); +} + +/* + * Find an entry based on address "dst", as the kernel + * does in selecting routes. This means we look first + * for a point to point link, settling for a route to + * the destination network if the former fails. + */ +struct rt_entry * +rtfind(dst) + struct sockaddr *dst; +{ + register struct rt_entry *rt; + register struct rthash *rh; + register int hash; + struct afhash h; + int af = dst->sa_family; + int doinghost = 1, (*match)(); if (af >= AF_MAX) return (0); @@ -657,8 +775,8 @@ again: if (doinghost) { doinghost = 0; hash = h.afh_nethash; - match = afswitch[af].af_netmatch; rh = &nethash[hash % ROUTEHASHSIZ]; + match = afswitch[af].af_netmatch; goto again; } return (0); @@ -692,23 +810,18 @@ rtadd(dst, gate, metric) return; rt->rt_hash = hash; rt->rt_dst = *dst; - rt->rt_gateway = *gate; + rt->rt_router = *gate; rt->rt_metric = metric; rt->rt_timer = 0; rt->rt_flags = RTF_UP | flags; - rt->rt_ifp = if_ifwithnet(&rt->rt_gateway); - if (metric == 0) - rt->rt_flags |= RTF_DIRECT; + rt->rt_state = 0; + rt->rt_ifp = if_ifwithnet(&rt->rt_router); + if (metric) + rt->rt_flags |= RTF_GATEWAY; insque(rt, rh); log("add", rt); - if (initializing) - return; - if (supplier) - broadcast(rt); - if (install) { - rt->rt_flags |= RTF_ADDRT; - rt->rt_retry = EXPIRE_TIME/TIMER_RATE; - } + if (install) + rt->rt_state |= RTS_ADDRT; } /* @@ -722,35 +835,21 @@ rtchange(rt, gate, metric) { int change = 0; - if (!equal(&rt->rt_gateway, gate)) { - rt->rt_gateway = *gate; + if (!equal(&rt->rt_router, gate)) { + rt->rt_newrouter = *gate; change++; } - - /* - * If the hop count has changed, adjust - * the flags in the routing table entry accordingly. - */ if (metric != rt->rt_metric) { - if (rt->rt_metric == 0) - rt->rt_flags &= ~RTF_DIRECT; + if (metric == 0) + rt->rt_flags |= RTF_GATEWAY; rt->rt_metric = metric; - if (metric >= HOPCNT_INFINITY) - rt->rt_flags &= ~RTF_UP; - else - rt->rt_flags |= RTF_UP; change++; } - if (!change) return; - if (supplier) - broadcast(rt); log("change", rt); - if (install) { - rt->rt_flags |= RTF_CHGRT; - rt->rt_retry = EXPIRE_TIME/TIMER_RATE; - } + if (install) + rt->rt_state |= RTS_CHGRT; } /* @@ -760,10 +859,11 @@ rtdelete(rt) struct rt_entry *rt; { log("delete", rt); - if (install) - if (ioctl(s, SIOCDELRT, (char *)&rt->rt_rt) && - errno == EBUSY) - rt->rt_flags |= RTF_DELRT; + if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt)) + perror("SIOCDELRT"); + /* don't delete interface entries so we can poll them later */ + if (rt->rt_state & RTS_INTERFACE) + return; remque(rt); free((char *)rt); } @@ -774,19 +874,22 @@ log(operation, rt) { time_t t = time(0); struct sockaddr_in *dst, *gate; - static struct flagbits { + static struct bits { int t_bits; char *t_name; - } bits[] = { + } flagbits[] = { { RTF_UP, "UP" }, - { RTF_DIRECT, "DIRECT" }, + { RTF_GATEWAY, "GATEWAY" }, { RTF_HOST, "HOST" }, - { RTF_DELRT, "DELETE" }, - { RTF_CHGRT, "CHANGE" }, - { RTF_SILENT, "SILENT" }, + { 0 } + }, statebits[] = { + { RTS_DELRT, "DELETE" }, + { RTS_CHGRT, "CHANGE" }, + { RTS_PASSIVE, "PASSIVE" }, + { RTS_INTERFACE,"INTERFACE" }, { 0 } }; - register struct flagbits *p; + register struct bits *p; register int first; char *cp; @@ -794,11 +897,11 @@ log(operation, rt) return; printf("%s ", operation); dst = (struct sockaddr_in *)&rt->rt_dst; - gate = (struct sockaddr_in *)&rt->rt_gateway; - printf("dst %x, router %x, metric %d, flags ", + gate = (struct sockaddr_in *)&rt->rt_router; + printf("dst %x, router %x, metric %d, flags", dst->sin_addr, gate->sin_addr, rt->rt_metric); - cp = "%s"; - for (first = 1, p = bits; p->t_bits > 0; p++) { + cp = " %s"; + for (first = 1, p = flagbits; p->t_bits > 0; p++) { if ((rt->rt_flags & p->t_bits) == 0) continue; printf(cp, p->t_name); @@ -807,6 +910,17 @@ log(operation, rt) first = 0; } } + printf(" state"); + cp = " %s"; + for (first = 1, p = statebits; p->t_bits > 0; p++) { + if ((rt->rt_state & p->t_bits) == 0) + continue; + printf(cp, p->t_name); + if (first) { + cp = "|%s"; + first = 0; + } + } putchar('\n'); }