+ if (argc > 0) switch (keyword(*argv)) {
+ case K_ADD:
+ case K_CHANGE:
+ case K_DELETE:
+ newroute(argc, argv);
+ case K_MONITOR:
+ monitor();
+ case K_FLUSH:
+ flushroutes(argc, argv);
+ }
+ usage(*argv);
+}
+
+/*
+ * Purge all entries in the routing tables not
+ * associated with network interfaces.
+ */
+flushroutes(argc, argv)
+char *argv[];
+{
+ int bufsize, needed, seqno, rlen;
+ char *buf, *next, *lim;
+ register struct rt_msghdr *rtm;
+ struct {
+ struct rt_msghdr m_rtm;
+ union {
+ char u_saddrs[200];
+ struct sockaddr u_sa;
+ } m_u;
+ } m;
+
+ if (argc > 1) {
+ argv++;
+ if (argc == 2 && **argv == '-') switch (keyword(1 + *argv)) {
+ case K_INET: af = AF_INET; break;
+ case K_XNS: af = AF_NS; break;
+ case K_LINK: af = AF_LINK; break;
+ case K_ISO: case K_OSI: af = AF_ISO; break;
+ default: goto bad;
+ } else
+ bad: usage(*argv);
+ }
+ if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0)
+ { perror("route-getkerninfo-estimate"); exit(1);}
+ if ((buf = malloc(needed)) == 0)
+ { printf("out of space\n");; exit(1);}
+ if ((rlen = getkerninfo(KINFO_RT_DUMP, buf, &needed, 0)) < 0)
+ { perror("actual retrieval of routing table"); exit(1);}
+ lim = buf + rlen;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
+ continue;
+ if (af) {
+ struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+ if (sa->sa_family != af)
+ continue;
+ }
+ rtm->rtm_type = RTM_DELETE;
+ rtm->rtm_seq = seqno;
+ if ((rlen = write(s, next, rtm->rtm_msglen)) < 0) {
+ perror("writing to routing socket");
+ printf("got only %d for rlen\n", rlen);
+ break;
+ }
+ again:
+ if ((rlen = read(s, (char *)&m, sizeof (m))) < 0) {
+ perror("reading from routing socket");
+ printf("got only %d for rlen\n", rlen);
+ break;
+ }
+ if ((m.m_rtm.rtm_pid != pid) || (m.m_rtm.rtm_seq != seqno)) {
+ printf("Got response for somebody else's request");
+ goto again;
+ }
+ seqno++;
+ if (qflag)
+ continue;
+ if (verbose) {
+ print_rtmsg(rtm, rlen);
+ } else {
+ struct sockaddr *sa = &m.m_u.u_sa;
+ printf("%-20.20s ", (rtm->rtm_flags & RTF_HOST) ?
+ routename(sa) : netname(sa));
+ sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
+ printf("%-20.20s ", routename(sa));
+ printf("done\n");
+ }
+ }
+ exit(0);
+}
+
+char *
+routename(sa)
+ struct sockaddr *sa;
+{
+ register char *cp;
+ static char line[50];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+ char *index();
+ char *ns_print();
+
+ if (first) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) strcpy(domain, cp + 1);
+ else
+ domain[0] = 0;
+ }
+ switch (sa->sa_family) {
+
+ case AF_INET:
+ { struct in_addr in;
+ in = ((struct sockaddr_in *)sa)->sin_addr;
+
+ cp = 0;
+ if (in.s_addr == INADDR_ANY)
+ cp = "default";
+ if (cp == 0 && !nflag) {
+ hp = gethostbyaddr(&in, sizeof (struct in_addr),
+ AF_INET);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (cp)
+ strcpy(line, cp);
+ else {
+#define C(x) ((x) & 0xff)
+ in.s_addr = ntohl(in.s_addr);
+ (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
+ }
+ break;
+ }
+
+ case AF_NS:
+ return (ns_print((struct sockaddr_ns *)sa));
+
+ case AF_LINK:
+ return (link_ntoa((struct sockaddr_dl *)sa));
+
+ case AF_ISO:
+ (void) sprintf(line, "iso %s",
+ iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
+ break;
+
+ default:
+ { u_short *s = (u_short *)sa->sa_data;
+ u_short *slim = s + ((sa->sa_len + 1)>>1);
+ char *cp = line + sprintf(line, "(%d)", sa->sa_family);
+ int n;
+
+ while (s < slim) {
+ n = sprintf(cp, " %x", *s);
+ s++; cp += n;
+ }
+ break;
+ }
+ }
+ return (line);
+}
+
+/*
+ * Return the name of the network whose address is given.
+ * The address is assumed to be that of a net or subnet, not a host.
+ */
+char *
+netname(sa)
+ struct sockaddr *sa;
+{
+ char *cp = 0;
+ static char line[50];
+ struct netent *np = 0;
+ u_long net, mask;
+ register u_long i;
+ int subnetshift;
+ char *ns_print();
+
+ switch (sa->sa_family) {
+
+ case AF_INET:
+ { struct in_addr in;
+ in = ((struct sockaddr_in *)sa)->sin_addr;
+
+ i = in.s_addr = ntohl(in.s_addr);
+ if (in.s_addr == 0)
+ cp = "default";
+ else if (!nflag) {
+ if (IN_CLASSA(i)) {
+ mask = IN_CLASSA_NET;
+ subnetshift = 8;
+ } else if (IN_CLASSB(i)) {
+ mask = IN_CLASSB_NET;
+ subnetshift = 8;
+ } else {
+ mask = IN_CLASSC_NET;
+ subnetshift = 4;
+ }
+ /*
+ * If there are more bits than the standard mask
+ * would suggest, subnets must be in use.
+ * Guess at the subnet mask, assuming reasonable
+ * width subnet fields.
+ */
+ while (in.s_addr &~ mask)
+ mask = (long)mask >> subnetshift;
+ net = in.s_addr & mask;
+ while ((mask & 1) == 0)
+ mask >>= 1, net >>= 1;
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ cp = np->n_name;
+ }
+ if (cp)
+ strcpy(line, cp);
+ else if ((in.s_addr & 0xffffff) == 0)
+ (void)sprintf(line, "%u", C(in.s_addr >> 24));
+ else if ((in.s_addr & 0xffff) == 0)
+ (void)sprintf(line, "%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16));
+ else if ((in.s_addr & 0xff) == 0)
+ (void)sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8));
+ else
+ (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8),
+ C(in.s_addr));
+ break;
+ }
+
+ case AF_NS:
+ return (ns_print((struct sockaddr_ns *)sa));
+ break;
+
+ case AF_LINK:
+ return (link_ntoa((struct sockaddr_dl *)sa));
+
+ case AF_ISO:
+ (void) sprintf(line, "iso %s",
+ iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
+ break;
+
+ default:
+ { u_short *s = (u_short *)sa->sa_data;
+ u_short *slim = s + ((sa->sa_len + 1)>>1);
+ char *cp = line + sprintf(line, "af %d:", sa->sa_family);
+ int n;
+
+ while (s < slim) {
+ n = sprintf(cp, " %x", *s);
+ s++; cp += n;
+ }
+ break;
+ }
+ }
+ return (line);
+}
+
+set_metric(value, key)
+char *value;
+{
+ int flag = 0;
+ u_long noval, *valp = &noval;
+
+ switch (key) {
+#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
+ caseof(K_MTU, RTV_MTU, rmx_mtu);
+ caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
+ caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
+ caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
+ caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
+ caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
+ caseof(K_RTT, RTV_RTT, rmx_rtt);
+ caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
+ }
+ rtm_inits |= flag;
+ if (lockrest || locking)
+ rt_metrics.rmx_locks |= flag;
+ if (locking)
+ locking = 0;
+ *valp = atoi(value);