home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / route / route.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-27  |  26.9 KB  |  1,218 lines

  1. /*
  2.  * Copyright (c) 1983, 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)route.c    5.35 (Berkeley) 6/27/91";
  42. #endif /* not lint */
  43.  
  44. #include <sys/param.h>
  45. #include <sys/file.h>
  46. #include <sys/socket.h>
  47. #include <sys/ioctl.h>
  48. #include <sys/mbuf.h>
  49. #include <sys/kinfo.h>
  50.  
  51. #include <net/route.h>
  52. #include <net/if_dl.h>
  53. #include <netinet/in.h>
  54. #include <netns/ns.h>
  55. #include <netiso/iso.h>
  56. #include <netccitt/x25.h>
  57. #include <arpa/inet.h>
  58. #include <netdb.h>
  59.  
  60. #include <errno.h>
  61. #include <unistd.h>
  62. #include <stdio.h>
  63. #include <ctype.h>
  64. #include <stdlib.h>
  65. #include <string.h>
  66. #include <paths.h>
  67.  
  68. struct keytab {
  69.     char    *kt_cp;
  70.     int    kt_i;
  71. } keywords[] = {
  72. #include "keywords.h"
  73. {0, 0}
  74. };
  75.  
  76. struct    ortentry route;
  77. union    sockunion {
  78.     struct    sockaddr sa;
  79.     struct    sockaddr_in sin;
  80.     struct    sockaddr_ns sns;
  81.     struct    sockaddr_iso siso;
  82.     struct    sockaddr_dl sdl;
  83.     struct    sockaddr_x25 sx25;
  84. } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
  85.  
  86. union sockunion *so_addrs[] =
  87.     { &so_dst, &so_gate, &so_mask, &so_genmask, &so_ifp, &so_ifa, 0}; 
  88.  
  89. typedef union sockunion *sup;
  90. int    pid, rtm_addrs, uid;
  91. int    s;
  92. int    forcehost, forcenet, doflush, nflag, af, qflag, tflag, Cflag, keyword();
  93. int    iflag, verbose, aflen = sizeof (struct sockaddr_in);
  94. int    locking, lockrest, debugonly;
  95. struct    sockaddr_in sin = { sizeof(sin), AF_INET };
  96. struct    rt_metrics rt_metrics;
  97. u_long  rtm_inits;
  98. struct    in_addr inet_makeaddr();
  99. char    *routename(), *netname();
  100. void    flushroutes(), newroute(), monitor(), sockaddr();
  101. void    print_getmsg(), print_rtmsg(), pmsg_common(), sodump(), bprintf();
  102. int    getaddr(), rtmsg();
  103. extern    char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
  104.  
  105. void
  106. usage(cp)
  107.     char *cp;
  108. {
  109.     if (cp)
  110.         (void) fprintf(stderr, "route: botched keyword: %s\n", cp);
  111.     (void) fprintf(stderr,
  112.         "usage: route [ -Cnqv ] cmd [[ -<qualifers> ] args ]\n");
  113.     exit(1);
  114.     /* NOTREACHED */
  115. }
  116.  
  117. void
  118. quit(s)
  119.     char *s;
  120. {
  121.     int sverrno = errno;
  122.  
  123.     (void) fprintf(stderr, "route: ");
  124.     if (s)
  125.         (void) fprintf(stderr, "%s: ", s);
  126.     (void) fprintf(stderr, "%s\n", strerror(sverrno));
  127.     exit(1);
  128.     /* NOTREACHED */
  129. }
  130.  
  131. #define ROUNDUP(a) \
  132.     ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  133. #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
  134.  
  135. main(argc, argv)
  136.     int argc;
  137.     char **argv;
  138. {
  139.     extern int optind;
  140.     int ch;
  141.     char *argvp;
  142.  
  143.     if (argc < 2)
  144.         usage((char *)NULL);
  145.  
  146.     while ((ch = getopt(argc, argv, "Cnqtv")) != EOF)
  147.         switch(ch) {
  148.         case 'C':
  149.             Cflag = 1;    /* Use old ioctls. */
  150.             break;
  151.         case 'n':
  152.             nflag = 1;
  153.             break;
  154.         case 'q':
  155.             qflag = 1;
  156.             break;
  157.         case 'v':
  158.             verbose = 1;
  159.             break;
  160.         case 't':
  161.             tflag = 1;
  162.             break;
  163.         case '?':
  164.         default:
  165.             usage();
  166.         }
  167.     argc -= optind;
  168.     argv += optind;
  169.  
  170.     pid = getpid();
  171.     uid = getuid();
  172.     if (tflag)
  173.         s = open("/dev/null", O_WRONLY, 0);
  174.     else if (Cflag)
  175.         s = socket(AF_INET, SOCK_RAW, 0);
  176.     else
  177.         s = socket(PF_ROUTE, SOCK_RAW, 0);
  178.     if (s < 0)
  179.         quit("socket");
  180.     if (*argv)
  181.         switch (keyword(*argv)) {
  182.         case K_GET:
  183.             uid = 0;
  184.             /* FALLTHROUGH */
  185.  
  186.         case K_CHANGE:
  187.             if (Cflag)
  188.                 usage("change or get with -C");
  189.             /* FALLTHROUGH */
  190.  
  191.         case K_ADD:
  192.         case K_DELETE:
  193.             newroute(argc, argv);
  194.             exit(0);
  195.             /* NOTREACHED */
  196.  
  197.         case K_MONITOR:
  198.             monitor();
  199.             /* NOTREACHED */
  200.  
  201.         case K_FLUSH:
  202.             flushroutes(argc, argv);
  203.             exit(0);
  204.             /* NOTREACHED */
  205.         }
  206.     usage(*argv);
  207.     /* NOTREACHED */
  208. }
  209.  
  210. /*
  211.  * Purge all entries in the routing tables not
  212.  * associated with network interfaces.
  213.  */
  214. void
  215. flushroutes(argc, argv)
  216.     int argc;
  217.     char *argv[];
  218. {
  219.     int needed, seqno, rlen;
  220.     char *buf, *next, *lim;
  221.     register struct rt_msghdr *rtm;
  222.  
  223.     if (uid)
  224.         quit("must be root to alter routing table");
  225.     shutdown(s, 0); /* Don't want to read back our messages */
  226.     if (argc > 1) {
  227.         argv++;
  228.         if (argc == 2 && **argv == '-')
  229.             switch (keyword(*argv + 1)) {
  230.             case K_INET:
  231.                 af = AF_INET;
  232.                 break;
  233.             case K_XNS:
  234.                 af = AF_NS;
  235.                 break;
  236.             case K_LINK:
  237.                 af = AF_LINK;
  238.                 break;
  239.             case K_ISO:
  240.             case K_OSI:
  241.                 af = AF_ISO;
  242.                 break;
  243.             case K_X25:
  244.                 af = AF_CCITT;
  245.             default:
  246.                 goto bad;
  247.         } else
  248. bad:            usage(*argv);
  249.     }
  250.     if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0)
  251.         quit("route-getkerninfo-estimate");
  252.     if ((buf = malloc(needed)) == NULL)
  253.         quit("malloc");
  254.     if ((rlen = getkerninfo(KINFO_RT_DUMP, buf, &needed, 0)) < 0)
  255.         quit("actual retrieval of routing table");
  256.     lim = buf + rlen;
  257.     seqno = 0;        /* ??? */
  258.     for (next = buf; next < lim; next += rtm->rtm_msglen) {
  259.         rtm = (struct rt_msghdr *)next;
  260.         if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
  261.             continue;
  262.         if (af) {
  263.             struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
  264.  
  265.             if (sa->sa_family != af)
  266.                 continue;
  267.         }
  268.         rtm->rtm_type = RTM_DELETE;
  269.         rtm->rtm_seq = seqno;
  270.         rlen = write(s, next, rtm->rtm_msglen);
  271.         if (rlen < (int)rtm->rtm_msglen) {
  272.             (void) fprintf(stderr,
  273.                 "route: write to routing socket: %s\n",
  274.                 strerror(errno));
  275.             (void) printf("got only %d for rlen\n", rlen);
  276.             break;
  277.         }
  278.         seqno++;
  279.         if (qflag)
  280.             continue;
  281.         if (verbose)
  282.             print_rtmsg(rtm, rlen);
  283.         else {
  284.             struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
  285.             (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
  286.                 routename(sa) : netname(sa));
  287.             sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
  288.             (void) printf("%-20.20s ", routename(sa));
  289.             (void) printf("done\n");
  290.         }
  291.     }
  292. }
  293.     
  294. char *
  295. routename(sa)
  296.     struct sockaddr *sa;
  297. {
  298.     register char *cp;
  299.     static char line[50];
  300.     struct hostent *hp;
  301.     static char domain[MAXHOSTNAMELEN + 1];
  302.     static int first = 1;
  303.     char *ns_print();
  304.  
  305.     if (first) {
  306.         first = 0;
  307.         if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
  308.             (cp = index(domain, '.')))
  309.             (void) strcpy(domain, cp + 1);
  310.         else
  311.             domain[0] = 0;
  312.     }
  313.     switch (sa->sa_family) {
  314.  
  315.     case AF_INET:
  316.         {    struct in_addr in;
  317.         in = ((struct sockaddr_in *)sa)->sin_addr;
  318.  
  319.         cp = 0;
  320.         if (in.s_addr == INADDR_ANY)
  321.             cp = "default";
  322.         if (cp == 0 && !nflag) {
  323.             hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
  324.                 AF_INET);
  325.             if (hp) {
  326.                 if ((cp = index(hp->h_name, '.')) &&
  327.                     !strcmp(cp + 1, domain))
  328.                     *cp = 0;
  329.                 cp = hp->h_name;
  330.             }
  331.         }
  332.         if (cp)
  333.             strcpy(line, cp);
  334.         else {
  335. #define C(x)    ((x) & 0xff)
  336.             in.s_addr = ntohl(in.s_addr);
  337.             (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
  338.                C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
  339.         }
  340.         break;
  341.         }
  342.  
  343.     case AF_NS:
  344.         return (ns_print((struct sockaddr_ns *)sa));
  345.  
  346.     case AF_LINK:
  347.         return (link_ntoa((struct sockaddr_dl *)sa));
  348.  
  349.     case AF_ISO:
  350.         (void) sprintf(line, "iso %s",
  351.             iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
  352.         break;
  353.  
  354.     default:
  355.         {    u_short *s = (u_short *)sa->sa_data;
  356.         u_short *slim = s + ((sa->sa_len + 1) >> 1);
  357.         char *cp = line + sprintf(line, "(%d)", sa->sa_family);
  358.  
  359.         while (s < slim)
  360.             cp += sprintf(cp, " %x", *s++);
  361.         break;
  362.         }
  363.     }
  364.     return (line);
  365. }
  366.  
  367. /*
  368.  * Return the name of the network whose address is given.
  369.  * The address is assumed to be that of a net or subnet, not a host.
  370.  */
  371. char *
  372. netname(sa)
  373.     struct sockaddr *sa;
  374. {
  375.     char *cp = 0;
  376.     static char line[50];
  377.     struct netent *np = 0;
  378.     u_long net, mask;
  379.     register u_long i;
  380.     int subnetshift;
  381.     char *ns_print();
  382.  
  383.     switch (sa->sa_family) {
  384.  
  385.     case AF_INET:
  386.         {    struct in_addr in;
  387.         in = ((struct sockaddr_in *)sa)->sin_addr;
  388.  
  389.         i = in.s_addr = ntohl(in.s_addr);
  390.         if (in.s_addr == 0)
  391.             cp = "default";
  392.         else if (!nflag) {
  393.             if (IN_CLASSA(i)) {
  394.                 mask = IN_CLASSA_NET;
  395.                 subnetshift = 8;
  396.             } else if (IN_CLASSB(i)) {
  397.                 mask = IN_CLASSB_NET;
  398.                 subnetshift = 8;
  399.             } else {
  400.                 mask = IN_CLASSC_NET;
  401.                 subnetshift = 4;
  402.             }
  403.             /*
  404.              * If there are more bits than the standard mask
  405.              * would suggest, subnets must be in use.
  406.              * Guess at the subnet mask, assuming reasonable
  407.              * width subnet fields.
  408.              */
  409.             while (in.s_addr &~ mask)
  410.                 mask = (long)mask >> subnetshift;
  411.             net = in.s_addr & mask;
  412.             while ((mask & 1) == 0)
  413.                 mask >>= 1, net >>= 1;
  414.             np = getnetbyaddr(net, AF_INET);
  415.             if (np)
  416.                 cp = np->n_name;
  417.         }
  418.         if (cp)
  419.             strcpy(line, cp);
  420.         else if ((in.s_addr & 0xffffff) == 0)
  421.             (void) sprintf(line, "%u", C(in.s_addr >> 24));
  422.         else if ((in.s_addr & 0xffff) == 0)
  423.             (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
  424.                 C(in.s_addr >> 16));
  425.         else if ((in.s_addr & 0xff) == 0)
  426.             (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
  427.                 C(in.s_addr >> 16), C(in.s_addr >> 8));
  428.         else
  429.             (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
  430.                 C(in.s_addr >> 16), C(in.s_addr >> 8),
  431.                 C(in.s_addr));
  432.         break;
  433.         }
  434.  
  435.     case AF_NS:
  436.         return (ns_print((struct sockaddr_ns *)sa));
  437.         break;
  438.  
  439.     case AF_LINK:
  440.         return (link_ntoa((struct sockaddr_dl *)sa));
  441.  
  442.     case AF_ISO:
  443.         (void) sprintf(line, "iso %s",
  444.             iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
  445.         break;
  446.  
  447.     default:
  448.         {    u_short *s = (u_short *)sa->sa_data;
  449.         u_short *slim = s + ((sa->sa_len + 1)>>1);
  450.         char *cp = line + sprintf(line, "af %d:", sa->sa_family);
  451.  
  452.         while (s < slim)
  453.             cp += sprintf(cp, " %x", *s++);
  454.         break;
  455.         }
  456.     }
  457.     return (line);
  458. }
  459.  
  460. void
  461. set_metric(value, key)
  462.     char *value;
  463.     int key;
  464. {
  465.     int flag = 0; 
  466.     u_long noval, *valp = &noval;
  467.  
  468.     switch (key) {
  469. #define caseof(x, y, z)    case x: valp = &rt_metrics.z; flag = y; break
  470.     caseof(K_MTU, RTV_MTU, rmx_mtu);
  471.     caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
  472.     caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
  473.     caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
  474.     caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
  475.     caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
  476.     caseof(K_RTT, RTV_RTT, rmx_rtt);
  477.     caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
  478.     }
  479.     rtm_inits |= flag;
  480.     if (lockrest || locking)
  481.         rt_metrics.rmx_locks |= flag;
  482.     if (locking)
  483.         locking = 0;
  484.     *valp = atoi(value);
  485. }
  486.  
  487. void
  488. newroute(argc, argv)
  489.     int argc;
  490.     register char **argv;
  491. {
  492.     char *cmd, *dest = "", *gateway = "", *err;
  493.     int ishost = 0, ret, attempts, oerrno, flags = 0;
  494.     int key;
  495.     struct hostent *hp = 0;
  496.  
  497.     if (uid)
  498.         quit("must be root to alter routing table");
  499.     cmd = argv[0];
  500.     if (*cmd != 'g')
  501.         shutdown(s, 0); /* Don't want to read back our messages */
  502.     while (--argc > 0) {
  503.         if (**(++argv)== '-') {
  504.             switch (key = keyword(1 + *argv)) {
  505.             case K_LINK:
  506.                 af = AF_LINK;
  507.                 aflen = sizeof(struct sockaddr_dl);
  508.                 break;
  509.             case K_OSI:
  510.             case K_ISO:
  511.                 af = AF_ISO;
  512.                 aflen = sizeof(struct sockaddr_iso);
  513.                 break;
  514.             case K_INET:
  515.                 af = AF_INET;
  516.                 aflen = sizeof(struct sockaddr_in);
  517.                 break;
  518.             case K_X25:
  519.                 af = AF_CCITT;
  520.                 aflen = sizeof(struct sockaddr_x25);
  521.                 break;
  522.             case K_SA:
  523.                 af = 0;
  524.                 aflen = sizeof(union sockunion);
  525.                 break;
  526.             case K_XNS:
  527.                 af = AF_NS;
  528.                 aflen = sizeof(struct sockaddr_ns);
  529.                 break;
  530.             case K_IFACE:
  531.             case K_INTERFACE:
  532.                 iflag++;
  533.                 break;
  534.             case K_LOCK:
  535.                 locking = 1;
  536.                 break;
  537.             case K_LOCKREST:
  538.                 lockrest = 1;
  539.                 break;
  540.             case K_HOST:
  541.                 forcehost++;
  542.                 break;
  543.             case K_REJECT:
  544.                 flags |= RTF_REJECT;
  545.                 break;
  546.             case K_PROTO1:
  547.                 flags |= RTF_PROTO1;
  548.                 break;
  549.             case K_PROTO2:
  550.                 flags |= RTF_PROTO2;
  551.                 break;
  552.             case K_CLONING:
  553.                 flags |= RTF_CLONING;
  554.                 break;
  555.             case K_XRESOLVE:
  556.                 flags |= RTF_XRESOLVE;
  557.                 break;
  558.             case K_IFA:
  559.                 argc--;
  560.                 (void) getaddr(RTA_IFA, *++argv, 0);
  561.                 break;
  562.             case K_IFP:
  563.                 argc--;
  564.                 (void) getaddr(RTA_IFP, *++argv, 0);
  565.                 break;
  566.             case K_GENMASK:
  567.                 argc--;
  568.                 (void) getaddr(RTA_GENMASK, *++argv, 0);
  569.                 break;
  570.             case K_GATEWAY:
  571.                 argc--;
  572.                 (void) getaddr(RTA_GATEWAY, *++argv, 0);
  573.                 break;
  574.             case K_DST:
  575.                 argc--;
  576.                 ishost = getaddr(RTA_DST, *++argv, &hp);
  577.                 dest = *argv;
  578.                 break;
  579.             case K_NETMASK:
  580.                 argc--;
  581.                 (void) getaddr(RTA_NETMASK, *++argv, 0);
  582.                 /* FALLTHROUGH */
  583.             case K_NET:
  584.                 forcenet++;
  585.                 break;
  586.             case K_MTU:
  587.             case K_HOPCOUNT:
  588.             case K_EXPIRE:
  589.             case K_RECVPIPE:
  590.             case K_SENDPIPE:
  591.             case K_SSTHRESH:
  592.             case K_RTT:
  593.             case K_RTTVAR:
  594.                 argc--;
  595.                 set_metric(*++argv, key);
  596.                 break;
  597.             default:
  598.                 usage(1+*argv);
  599.             }
  600.         } else {
  601.             if ((rtm_addrs & RTA_DST) == 0) {
  602.                 dest = *argv;
  603.                 ishost = getaddr(RTA_DST, *argv, &hp);
  604.             } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
  605.                 gateway = *argv;
  606.                 (void) getaddr(RTA_GATEWAY, *argv, &hp);
  607.             } else {
  608.                 int ret = atoi(*argv);
  609.                 if (ret == 0) {
  610.                     printf("%s,%s", "old usage of trailing 0",
  611.                        "assuming route to if\n");
  612.                     iflag = 1;
  613.                     continue;
  614.                 } else if (ret > 0 && ret < 10) {
  615.                     printf("old usage of trailing digit, ");
  616.                     printf("assuming route via gateway\n");
  617.                     iflag = 0;
  618.                     continue;
  619.                 }
  620.                 (void) getaddr(RTA_NETMASK, *argv, 0);
  621.             }
  622.         }
  623.     }
  624.     if (forcehost)
  625.         ishost = 1;
  626.     if (forcenet)
  627.         ishost = 0;
  628.     flags |= RTF_UP;
  629.     if (ishost)
  630.         flags |= RTF_HOST;
  631.     if (iflag == 0)
  632.         flags |= RTF_GATEWAY;
  633.     for (attempts = 1; ; attempts++) {
  634.         errno = 0;
  635.         if (Cflag && (af == AF_INET || af == AF_NS)) {
  636.             route.rt_flags = flags;
  637.             route.rt_dst = so_dst.sa;
  638.             route.rt_gateway = so_gate.sa;
  639.             if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT,
  640.                  (caddr_t)&route)) == 0)
  641.                 break;
  642.         } else {
  643.             if ((ret = rtmsg(*cmd, flags)) == 0)
  644.                 break;
  645.         }
  646.         if (errno != ENETUNREACH && errno != ESRCH)
  647.             break;
  648.         if (af == AF_INET && hp && hp->h_addr_list[1]) {
  649.             hp->h_addr_list++;
  650.             bcopy(hp->h_addr_list[0], (caddr_t)&so_dst.sin.sin_addr,
  651.                 hp->h_length);
  652.         } else
  653.             break;
  654.     }
  655.     if (*cmd == 'g')
  656.         exit(0);
  657.     oerrno = errno;
  658.     (void) printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net",
  659.         dest, gateway);
  660.     if (attempts > 1 && ret == 0)
  661.         (void) printf(" (%s)",
  662.         inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
  663.     if (ret == 0)
  664.         (void) printf("\n");
  665.     else {
  666.         switch (oerrno) {
  667.         case ESRCH:
  668.             err = "not in table";
  669.             break;
  670.         case EBUSY:
  671.             err = "entry in use";
  672.             break;
  673.         case ENOBUFS:
  674.             err = "routing table overflow";
  675.             break;
  676.         default:
  677.             err = strerror(oerrno);
  678.             break;
  679.         }
  680.         (void) printf(": %s\n", err);
  681.     }
  682. }
  683.  
  684. void
  685. inet_makenetandmask(net, sin)
  686.     u_long net;
  687.     register struct sockaddr_in *sin;
  688. {
  689.     u_long addr, mask = 0;
  690.     register char *cp;
  691.  
  692.     rtm_addrs |= RTA_NETMASK;
  693.     if (net == 0)
  694.         mask = addr = 0;
  695.     else if (net < 128) {
  696.         addr = net << IN_CLASSA_NSHIFT;
  697.         mask = IN_CLASSA_NET;
  698.     } else if (net < 65536) {
  699.         addr = net << IN_CLASSB_NSHIFT;
  700.         mask = IN_CLASSB_NET;
  701.     } else if (net < 16777216L) {
  702.         addr = net << IN_CLASSC_NSHIFT;
  703.         mask = IN_CLASSC_NET;
  704.     } else {
  705.         addr = net;
  706.         if ((addr & IN_CLASSA_HOST) == 0)
  707.             mask =  IN_CLASSA_NET;
  708.         else if ((addr & IN_CLASSB_HOST) == 0)
  709.             mask =  IN_CLASSB_NET;
  710.         else if ((addr & IN_CLASSC_HOST) == 0)
  711.             mask =  IN_CLASSC_NET;
  712.         else
  713.             mask = -1;
  714.     }
  715.     sin->sin_addr.s_addr = htonl(addr);
  716.     sin = &so_mask.sin;
  717.     sin->sin_addr.s_addr = htonl(mask);
  718.     sin->sin_len = 0;
  719.     sin->sin_family = 0;
  720.     cp = (char *)(&sin->sin_addr + 1);
  721.     while (*--cp == 0 && cp > (char *)sin)
  722.         ;
  723.     sin->sin_len = 1 + cp - (char *)sin;
  724. }
  725.  
  726. /*
  727.  * Interpret an argument as a network address of some kind,
  728.  * returning 1 if a host address, 0 if a network address.
  729.  */
  730. int
  731. getaddr(which, s, hpp)
  732.     int which;
  733.     char *s;
  734.     struct hostent **hpp;
  735. {
  736.     register sup su;
  737.     struct ns_addr ns_addr();
  738.     struct iso_addr *iso_addr();
  739.     struct hostent *hp;
  740.     struct netent *np;
  741.     u_long val;
  742.  
  743.     if (af == 0) {
  744.         af = AF_INET;
  745.         aflen = sizeof(struct sockaddr_in);
  746.     }
  747.     rtm_addrs |= which;
  748.     switch (which) {
  749.     case RTA_DST:        su = so_addrs[0]; su->sa.sa_family = af; break;
  750.     case RTA_GATEWAY:    su = so_addrs[1]; su->sa.sa_family = af; break;
  751.     case RTA_NETMASK:    su = so_addrs[2]; break;
  752.     case RTA_GENMASK:    su = so_addrs[3]; break;
  753.     case RTA_IFP:        su = so_addrs[4]; su->sa.sa_family = af; break;
  754.     case RTA_IFA:        su = so_addrs[5]; su->sa.sa_family = af; break;
  755.     default:        usage("Internal Error"); /*NOTREACHED*/
  756.     }
  757.     su->sa.sa_len = aflen;
  758.     if (strcmp(s, "default") == 0) {
  759.         switch (which) {
  760.         case RTA_DST:
  761.             forcenet++;
  762.             (void) getaddr(RTA_NETMASK, s, 0);
  763.             break;
  764.         case RTA_NETMASK:
  765.         case RTA_GENMASK:
  766.             su->sa.sa_len = 0;
  767.         }
  768.         return 0;
  769.     }
  770.     if (af == AF_NS)
  771.         goto do_xns;
  772.     if (af == AF_OSI)
  773.         goto do_osi;
  774.     if (af == AF_LINK)
  775.         goto do_link;
  776.     if (af == AF_CCITT)
  777.         goto do_ccitt;
  778.     if (af == 0)
  779.         goto do_sa;
  780.     if (hpp == NULL)
  781.         hpp = &hp;
  782.     *hpp = NULL;
  783.     if (((val = inet_addr(s)) != -1) &&
  784.         (which != RTA_DST || forcenet == 0)) {
  785.         su->sin.sin_addr.s_addr = val;
  786.         if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
  787.             return (1);
  788.         else {
  789.             val = ntohl(val);
  790.         out:    if (which == RTA_DST)
  791.                 inet_makenetandmask(val, &su->sin);
  792.             return (0);
  793.         }
  794.     }
  795.     val = inet_network(s);
  796.     if (val != -1) {
  797.         goto out;
  798.     }
  799.     np = getnetbyname(s);
  800.     if (np) {
  801.         val = np->n_net;
  802.         goto out;
  803.     }
  804.     hp = gethostbyname(s);
  805.     if (hp) {
  806.         *hpp = hp;
  807.         su->sin.sin_family = hp->h_addrtype;
  808.         bcopy(hp->h_addr, (char *)&su->sin.sin_addr, hp->h_length);
  809.         return (1);
  810.     }
  811.     (void) fprintf(stderr, "%s: bad value\n", s);
  812.     exit(1);
  813. do_xns:
  814.     if (which == RTA_DST) {
  815.         extern short ns_bh[3];
  816.         struct sockaddr_ns *sms = &(so_mask.sns);
  817.         bzero((char *)sms, sizeof(*sms));
  818.         sms->sns_family = 0;
  819.         sms->sns_len = 6;
  820.         sms->sns_addr.x_net = *(union ns_net *)ns_bh;
  821.         rtm_addrs |= RTA_NETMASK;
  822.     }
  823.     su->sns.sns_addr = ns_addr(s);
  824.     return (!ns_nullhost(su->sns.sns_addr));
  825. do_osi:
  826.     su->siso.siso_addr = *iso_addr(s);
  827.     if (which == RTA_NETMASK || which == RTA_GENMASK) {
  828.         register char *cp = (char *)TSEL(&su->siso);
  829.         su->siso.siso_nlen = 0;
  830.         do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
  831.         su->siso.siso_len = 1 + cp - (char *)su;
  832.     }
  833.     return (1);
  834. do_ccitt:
  835.     ccitt_addr(s, &su->sx25);
  836.     return (1);
  837. do_link:
  838.     link_addr(s, &su->sdl);
  839.     return (1);
  840. do_sa:
  841.     su->sa.sa_len = sizeof(*su);
  842.     sockaddr(s, &su->sa);
  843.     return (1);
  844. }
  845.  
  846. short ns_nullh[] = {0,0,0};
  847. short ns_bh[] = {-1,-1,-1};
  848.  
  849. char *
  850. ns_print(sns)
  851.     struct sockaddr_ns *sns;
  852. {
  853.     struct ns_addr work;
  854.     union { union ns_net net_e; u_long long_e; } net;
  855.     u_short port;
  856.     static char mybuf[50], cport[10], chost[25];
  857.     char *host = "";
  858.     register char *p;
  859.     register u_char *q;
  860.  
  861.     work = sns->sns_addr;
  862.     port = ntohs(work.x_port);
  863.     work.x_port = 0;
  864.     net.net_e  = work.x_net;
  865.     if (ns_nullhost(work) && net.long_e == 0) {
  866.         if (!port)
  867.             return ("*.*");
  868.         (void) sprintf(mybuf, "*.%XH", port);
  869.         return (mybuf);
  870.     }
  871.  
  872.     if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0) 
  873.         host = "any";
  874.     else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
  875.         host = "*";
  876.     else {
  877.         q = work.x_host.c_host;
  878.         (void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
  879.             q[0], q[1], q[2], q[3], q[4], q[5]);
  880.         for (p = chost; *p == '0' && p < chost + 12; p++)
  881.             /* void */;
  882.         host = p;
  883.     }
  884.     if (port)
  885.         (void) sprintf(cport, ".%XH", htons(port));
  886.     else
  887.         *cport = 0;
  888.  
  889.     (void) sprintf(mybuf,"%XH.%s%s", ntohl(net.long_e), host, cport);
  890.     return (mybuf);
  891. }
  892.  
  893. void
  894. monitor()
  895. {
  896.     int n;
  897.     char msg[2048];
  898.  
  899.     verbose = 1;
  900.     for(;;) {
  901.         n = read(s, msg, 2048);
  902.         (void) printf("got message of size %d\n", n);
  903.         print_rtmsg((struct rt_msghdr *)msg);
  904.     }
  905. }
  906.  
  907. struct {
  908.     struct    rt_msghdr m_rtm;
  909.     char    m_space[512];
  910. } m_rtmsg;
  911.  
  912. int
  913. rtmsg(cmd, flags)
  914.     int cmd, flags;
  915. {
  916.     static int seq;
  917.     int rlen;
  918.     register char *cp = m_rtmsg.m_space;
  919.     register int l;
  920.  
  921. #define NEXTADDR(w, u) \
  922.     if (rtm_addrs & (w)) {\
  923.         l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
  924.         if (verbose) sodump(&(u),"u");\
  925.     }
  926.  
  927.     errno = 0;
  928.     bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
  929.     if (cmd == 'a')
  930.         cmd = RTM_ADD;
  931.     else if (cmd == 'c')
  932.         cmd = RTM_CHANGE;
  933.     else if (cmd == 'g')
  934.         cmd = RTM_GET;
  935.     else
  936.         cmd = RTM_DELETE;
  937. #define rtm m_rtmsg.m_rtm
  938.     rtm.rtm_type = cmd;
  939.     rtm.rtm_flags = flags;
  940.     rtm.rtm_version = RTM_VERSION;
  941.     rtm.rtm_seq = ++seq;
  942.     rtm.rtm_addrs = rtm_addrs;
  943.     rtm.rtm_rmx = rt_metrics;
  944.     rtm.rtm_inits = rtm_inits;
  945.  
  946.     if (rtm_addrs & RTA_NETMASK)
  947.         mask_addr();
  948.     NEXTADDR(RTA_DST, so_dst);
  949.     NEXTADDR(RTA_GATEWAY, so_gate);
  950.     NEXTADDR(RTA_NETMASK, so_mask);
  951.     NEXTADDR(RTA_GENMASK, so_genmask);
  952.     NEXTADDR(RTA_IFP, so_ifp);
  953.     NEXTADDR(RTA_IFA, so_ifa);
  954.     rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
  955.     if (verbose)
  956.         print_rtmsg(&rtm, l);
  957.     if (debugonly)
  958.         return 0;
  959.     if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
  960.         perror("writing to routing socket");
  961.         return (-1);
  962.     }
  963.     if (cmd == RTM_GET) {
  964.         do {
  965.             l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
  966.         } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
  967.         if (l < 0)
  968.             (void) fprintf(stderr,
  969.                 "route: read from routing socket: %s\n",
  970.                 strerror(errno));
  971.         else
  972.             print_getmsg(&rtm, l);
  973.     }
  974. #undef rtm
  975.     return (0);
  976. }
  977.  
  978. mask_addr() {
  979.     register char *cp1, *cp2;
  980.     int olen;
  981.  
  982.     if ((rtm_addrs & RTA_DST) == 0)
  983.         return;
  984.     switch(so_dst.sa.sa_family) {
  985.     case AF_NS: case AF_INET: case 0:
  986.         return;
  987.     case AF_ISO:
  988.         olen = MIN(so_dst.siso.siso_nlen, so_mask.sa.sa_len - 6);
  989.     }
  990.     cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
  991.     cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
  992.     while (cp2 > cp1)
  993.         *--cp2 = 0;
  994.     cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
  995.     while (cp1 > so_dst.sa.sa_data)
  996.         *--cp1 &= *--cp2;
  997.     switch(so_dst.sa.sa_family) {
  998.     case AF_ISO:
  999.         so_dst.siso.siso_nlen = olen;
  1000.     }
  1001. }
  1002.  
  1003. char *msgtypes[] = {
  1004.     "",
  1005.     "RTM_ADD: Add Route",
  1006.     "RTM_DELETE: Delete Route",
  1007.     "RTM_CHANGE: Change Metrics or flags",
  1008.     "RTM_GET: Report Metrics",
  1009.     "RTM_LOSING: Kernel Suspects Partitioning",
  1010.     "RTM_REDIRECT: Told to use different route",
  1011.     "RTM_MISS: Lookup failed on this address",
  1012.     "RTM_LOCK: fix specified metrics",
  1013.     "RTM_OLDADD: caused by SIOCADDRT",
  1014.     "RTM_OLDDEL: caused by SIOCDELRT",
  1015.     0,
  1016. };
  1017.  
  1018. char metricnames[] =
  1019. "\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
  1020. char routeflags[] = 
  1021. "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\017PROTO2\020PROTO1";
  1022.  
  1023.  
  1024. void
  1025. print_rtmsg(rtm, msglen)
  1026.     register struct rt_msghdr *rtm;
  1027.     int msglen;
  1028. {
  1029.     if (verbose == 0)
  1030.         return;
  1031.     if (rtm->rtm_version != RTM_VERSION) {
  1032.         (void) printf("routing message version %d not understood\n",
  1033.             rtm->rtm_version);
  1034.         return;
  1035.     }
  1036.     (void) printf("%s\npid: %d, len %d, seq %d, errno %d, flags:",
  1037.         msgtypes[rtm->rtm_type], rtm->rtm_pid, rtm->rtm_msglen,
  1038.         rtm->rtm_seq, rtm->rtm_errno); 
  1039.     bprintf(stdout, rtm->rtm_flags, routeflags);
  1040.     pmsg_common(rtm);
  1041. }
  1042.  
  1043. void
  1044. print_getmsg(rtm, msglen)
  1045.     register struct rt_msghdr *rtm;
  1046.     int msglen;
  1047. {
  1048.     if (rtm->rtm_version != RTM_VERSION) {
  1049.         (void)printf("routing message version %d not understood\n",
  1050.             rtm->rtm_version);
  1051.         return;
  1052.     }
  1053.     if (rtm->rtm_msglen > msglen) {
  1054.         (void)printf("get length mismatch, in packet %d, returned %d\n",
  1055.             rtm->rtm_msglen, msglen);
  1056.     }
  1057.     (void) printf("RTM_GET: errno %d, flags:", rtm->rtm_errno); 
  1058.     bprintf(stdout, rtm->rtm_flags, routeflags);
  1059.     (void) printf("\nmetric values:\n  ");
  1060. #define metric(f, e)\
  1061.     printf("%s: %d%s", __STRING(f), rtm->rtm_rmx.__CONCAT(rmx_,f), e)
  1062.     metric(recvpipe, ", ");
  1063.     metric(sendpipe, ", ");
  1064.     metric(ssthresh, ", ");
  1065.     metric(rtt, "\n  ");
  1066.     metric(rttvar, ", ");
  1067.     metric(hopcount, ", ");
  1068.     metric(mtu, ", ");
  1069.     metric(expire, "\n");
  1070. #undef metric
  1071.     pmsg_common(rtm);
  1072. }
  1073.  
  1074. void
  1075. pmsg_common(rtm)
  1076.     register struct rt_msghdr *rtm;
  1077. {
  1078.     char *cp;
  1079.     register struct sockaddr *sa;
  1080.     int i;
  1081.  
  1082.     (void) printf("\nlocks: ");
  1083.     bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
  1084.     (void) printf(" inits: ");
  1085.     bprintf(stdout, rtm->rtm_inits, metricnames);
  1086.     (void) printf("\nsockaddrs: ");
  1087.     bprintf(stdout, rtm->rtm_addrs,
  1088.         "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR");
  1089.     (void) putchar('\n');
  1090.     cp = ((char *)(rtm + 1));
  1091.     if (rtm->rtm_addrs)
  1092.         for (i = 1; i; i <<= 1)
  1093.             if (i & rtm->rtm_addrs) {
  1094.                 sa = (struct sockaddr *)cp;
  1095.                 (void) printf(" %s", routename(sa));
  1096.                 ADVANCE(cp, sa);
  1097.             }
  1098.     (void) putchar('\n');
  1099.     (void) fflush(stdout);
  1100. }
  1101.  
  1102. void
  1103. bprintf(fp, b, s)
  1104.     register FILE *fp;
  1105.     register int b;
  1106.     register u_char *s;
  1107. {
  1108.     register int i;
  1109.     int gotsome = 0;
  1110.  
  1111.     if (b == 0)
  1112.         return;
  1113.     while (i = *s++) {
  1114.         if (b & (1 << (i-1))) {
  1115.             if (gotsome == 0)
  1116.                 i = '<';
  1117.             else
  1118.                 i = ',';
  1119.             (void) putc(i, fp);
  1120.             gotsome = 1;
  1121.             for (; (i = *s) > 32; s++)
  1122.                 (void) putc(i, fp);
  1123.         } else
  1124.             while (*s > 32)
  1125.                 s++;
  1126.     }
  1127.     if (gotsome)
  1128.         (void) putc('>', fp);
  1129. }
  1130.  
  1131. int
  1132. keyword(cp)
  1133.     char *cp;
  1134. {
  1135.     register struct keytab *kt = keywords;
  1136.  
  1137.     while (kt->kt_cp && strcmp(kt->kt_cp, cp))
  1138.         kt++;
  1139.     return kt->kt_i;
  1140. }
  1141.  
  1142. void
  1143. sodump(su, which)
  1144.     register sup su;
  1145.     char *which;
  1146. {
  1147.     switch (su->sa.sa_family) {
  1148.     case AF_LINK:
  1149.         (void) printf("%s: link %s; ",
  1150.             which, link_ntoa(&su->sdl));
  1151.         break;
  1152.     case AF_ISO:
  1153.         (void) printf("%s: iso %s; ",
  1154.             which, iso_ntoa(&su->siso.siso_addr));
  1155.         break;
  1156.     case AF_INET:
  1157.         (void) printf("%s: inet %s; ",
  1158.             which, inet_ntoa(su->sin.sin_addr));
  1159.         break;
  1160.     case AF_NS:
  1161.         (void) printf("%s: xns %s; ",
  1162.             which, ns_ntoa(su->sns.sns_addr));
  1163.         break;
  1164.     }
  1165.     (void) fflush(stdout);
  1166. }
  1167. /* States*/
  1168. #define VIRGIN    0
  1169. #define GOTONE    1
  1170. #define GOTTWO    2
  1171. /* Inputs */
  1172. #define    DIGIT    (4*0)
  1173. #define    END    (4*1)
  1174. #define DELIM    (4*2)
  1175.  
  1176. void
  1177. sockaddr(addr, sa)
  1178. register char *addr;
  1179. register struct sockaddr *sa;
  1180. {
  1181.     register char *cp = (char *)sa;
  1182.     int size = sa->sa_len;
  1183.     char *cplim = cp + size;
  1184.     register int byte = 0, state = VIRGIN, new;
  1185.  
  1186.     bzero(cp, size);
  1187.     do {
  1188.         if ((*addr >= '0') && (*addr <= '9')) {
  1189.             new = *addr - '0';
  1190.         } else if ((*addr >= 'a') && (*addr <= 'f')) {
  1191.             new = *addr - 'a' + 10;
  1192.         } else if ((*addr >= 'A') && (*addr <= 'F')) {
  1193.             new = *addr - 'A' + 10;
  1194.         } else if (*addr == 0) 
  1195.             state |= END;
  1196.         else
  1197.             state |= DELIM;
  1198.         addr++;
  1199.         switch (state /* | INPUT */) {
  1200.         case GOTTWO | DIGIT:
  1201.             *cp++ = byte; /*FALLTHROUGH*/
  1202.         case VIRGIN | DIGIT:
  1203.             state = GOTONE; byte = new; continue;
  1204.         case GOTONE | DIGIT:
  1205.             state = GOTTWO; byte = new + (byte << 4); continue;
  1206.         default: /* | DELIM */
  1207.             state = VIRGIN; *cp++ = byte; byte = 0; continue;
  1208.         case GOTONE | END:
  1209.         case GOTTWO | END:
  1210.             *cp++ = byte; /* FALLTHROUGH */
  1211.         case VIRGIN | END:
  1212.             break;
  1213.         }
  1214.         break;
  1215.     } while (cp < cplim); 
  1216.     sa->sa_len = cp - (char *)sa;
  1217. }
  1218.