home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / tcpip / netkit-a.06 / netkit-a / NetKit-A-0.06 / net-tools-1.1.38 / route.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-17  |  10.7 KB  |  497 lines

  1. /*
  2.  * route        This file contains an implementation of the command
  3.  *              that manages the IP routing table in the kernel.
  4.  *
  5.  * Usage:       route [-nv] [ {add|del} [{-net|-host}] target
  6.  *                    [ gw ] [ netmask ] [ metric ] [ device ]]
  7.  *
  8.  * Version:     @(#)route.c     1.70    01/04/94
  9.  *
  10.  * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  11.  *              Modified for Net-2Debugged by Johannes Stille,
  12.  *                      <johannes@titan.os.open.de>
  13.  *        Changes by Linus Torvalds
  14.  *        Further changes by Alan Cox to add the new mtu/window stuff
  15.  */
  16. #include <sys/types.h>
  17. #include <sys/ioctl.h>
  18. #include <sys/socket.h>
  19. #include <net/if.h>
  20. #include <netinet/in.h>
  21. #include <netdb.h>
  22. #include <arpa/nameser.h>
  23. #include <resolv.h>
  24. #include <stdio.h>
  25. #include <errno.h>
  26. #include <fcntl.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include <ctype.h>
  31.  
  32. char           *Version = "@(#) route 1.70 (01/04/94)";
  33.  
  34. /* Pathnames of the PROCfs files used by NET. */
  35. #define _PATH_PROCNET_ROUTE    "/proc/net/route"
  36.  
  37. #ifdef SIOCADDRTOLD
  38. #define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
  39. #define full_mask(x) (x)
  40. #else
  41. #define mask_in_addr(x) ((x).rt_genmask)
  42. #define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
  43. #endif
  44.  
  45. char * getsock(char *bufp, struct sockaddr * sap)
  46. {
  47.     unsigned char *ptr;
  48.     char *sp = bufp;
  49.     int i, val;
  50.     struct sockaddr_in *sin;
  51.  
  52.     /* Grmpf. -FvK */
  53.     sin = (struct sockaddr_in *) sap;
  54.     sin->sin_family = AF_INET;
  55.     sin->sin_port = 0;
  56.  
  57.     ptr = (unsigned char *) (&(sin->sin_addr.s_addr) + 1);
  58.     for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
  59.         val = 0;
  60.         if (*sp == '\t')
  61.             break;
  62.         if (*sp >= 'A')
  63.             val = (int) (*sp - 'A') + 10;
  64.         else
  65.             val = (int) (*sp - '0');
  66.         val <<= 4;
  67.         sp++;
  68.         if (*sp >= 'A')
  69.             val |= (int) (*sp - 'A') + 10;
  70.         else
  71.             val |= (int) (*sp - '0');
  72.         *--ptr = (unsigned char) (val & 0377);
  73.         sp++;
  74.     }
  75.  
  76.     return (sp);
  77. }
  78.  
  79. int resolve(char *name, struct sockaddr * sap)
  80. {
  81.     struct hostent *hp;
  82.     struct netent  *np;
  83.     struct sockaddr_in *sin;
  84.  
  85.     /* Grmpf. -FvK */
  86.     sin = (struct sockaddr_in *) sap;
  87.     sin->sin_family = AF_INET;
  88.     sin->sin_port = 0;
  89.  
  90.     /* Default is special, meaning 0.0.0.0. */
  91.     if (!strcmp(name, "default")) {
  92.         sin->sin_addr.s_addr = INADDR_ANY;
  93.         return (1);
  94.     }
  95.     /* Try the NETWORKS database to see if this is a known network. */
  96.     if ((np = getnetbyname(name)) != (struct netent *) NULL) {
  97.         sin->sin_addr.s_addr = htonl(np->n_net);
  98.         strcpy(name, np->n_name);
  99.         return (1);
  100.     }
  101. #ifdef DEBUG
  102.     _res.options |= RES_DEBUG;
  103.     res_init();
  104. #endif
  105.  
  106.     if ((hp = gethostbyname(name)) == (struct hostent *) NULL) {
  107.         errno = h_errno;
  108.         return (-1);
  109.     }
  110.     memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
  111.     strcpy(name, hp->h_name);
  112. /*
  113.  * assume it's a network if the least significate byte is 0,
  114.  * as that's not a valid host address.
  115.  */
  116.     return ((ntohl(sin->sin_addr.s_addr) & 0xff) == 0);
  117. }
  118.  
  119.  
  120. int rresolve(char *name, struct sockaddr * sap, int numeric)
  121. {
  122.     struct sockaddr_in *sin;
  123.     struct hostent *ent;
  124.     struct netent  *np;
  125.     unsigned long   ad, host_ad;
  126.  
  127.     /* Grmpf. -FvK */
  128.     sin = (struct sockaddr_in *) sap;
  129.     if (sin->sin_family != AF_INET) {
  130. #ifdef DEBUG
  131.         fprintf(stderr, "rresolve: unsupport address family %d !\n",
  132.             sin->sin_family);
  133. #endif
  134.         errno = EAFNOSUPPORT;
  135.         return (-1);
  136.     }
  137.     if (sin->sin_addr.s_addr == INADDR_ANY) {
  138.         if (numeric & 0x8000)
  139.             strcpy(name, "default");
  140.         else
  141.             strcpy(name, "*");
  142.         return (0);
  143.     }
  144.     ad = (unsigned long) sin->sin_addr.s_addr;
  145.  
  146.     host_ad = ntohl(ad);
  147.     np = NULL;
  148.     ent = NULL;
  149.     if ((numeric & 0x7FFF) == 0) {
  150.         if ((host_ad & 0xFF) != 0)  {
  151.             ent = gethostbyaddr((char *) &ad, 4, AF_INET);
  152.             if (ent != NULL)
  153.                 strcpy(name, ent->h_name);
  154.         } else {
  155.             np = getnetbyaddr(host_ad, AF_INET);
  156.             if (np != NULL) {
  157.                 strcpy(name, np->n_name);
  158.             }
  159.         }
  160.     }
  161.     if ((ent == NULL) && (np == NULL)) {
  162.         sprintf(name, "%d.%d.%d.%d",
  163.             (int) (ad & 0xFF), (int) ((ad >> 8) & 0xFF),
  164.             (int) ((ad >> 16) & 0xFF),
  165.             (int) ((ad >> 24) & 0xFF));
  166.     }
  167.     return (0);
  168. }
  169.  
  170.  
  171. void reserror(char *text)
  172. {
  173.     herror(text);
  174. }
  175.  
  176.  
  177. int             opt_n = 0;    /* numerical output flag     */
  178. int             opt_v = 0;    /* debugging output flag     */
  179. int             skfd = -1;
  180.  
  181.  
  182. static void usage(void)
  183. {
  184.     fprintf(stderr, "Usage: route [-nv]\n");
  185.     fprintf(stderr, "       route [-v] del target\n");
  186.     fprintf(stderr, "       route [-v] add {-net|-host} target [gw gateway]\n");
  187.     fprintf(stderr, "                  [metric NN] [netmask mask] [mss maxsegment] [window maxwindow]\n");
  188.     fprintf(stderr, "                  [[dev] device]\n");
  189.     exit(-1);
  190. }
  191.  
  192.  
  193. static void rt_print(void)
  194. {
  195.     char            buff[1024], iface[16], net_addr[64];
  196.     char            gate_addr[64], mask_addr[64], flags[16];
  197.     struct sockaddr snet, sgate, smask;
  198.     FILE           *fp;
  199.     int             num, iflags, refcnt, use, metric;
  200.     int        mss, window;
  201.  
  202.     printf("Kernel routing table\n");
  203.     printf(
  204.            "Destination     Gateway         Genmask         "
  205.            "Flags MSS    Window Use Iface\n");
  206.     if ((fp = fopen(_PATH_PROCNET_ROUTE, "r")) == NULL) {
  207.         perror(_PATH_PROCNET_ROUTE);
  208.         return;
  209.     }
  210.     while (fgets(buff, 1023, fp)) {
  211.         num = sscanf(buff, "%s %s %s %X %d %d %d %s %d %d\n",
  212.                  iface, net_addr, gate_addr,
  213.                  &iflags, &refcnt, &use, &metric, mask_addr,
  214.                  &mss,&window);
  215.         if (num != 10)
  216.             continue;
  217.  
  218.         /* Fetch and resolve the target address. */
  219.         (void) getsock(net_addr, &snet);
  220.         (void) rresolve(net_addr, &snet, (opt_n | 0x8000));
  221.         net_addr[15] = '\0';
  222.  
  223.         /* Fetch and resolve the gateway address. */
  224.         (void) getsock(gate_addr, &sgate);
  225.         rresolve(gate_addr, &sgate, opt_n);
  226.         gate_addr[15] = '\0';
  227.  
  228.         /* Fetch and resolve the mask. */
  229.         (void) getsock(mask_addr, &smask);
  230.         rresolve(mask_addr, &smask, 1);
  231.         gate_addr[15] = '\0';
  232.  
  233.         /* Decode the flags. */
  234.         flags[0] = '\0';
  235.         if (iflags & RTF_UP)
  236.             strcat(flags, "U");
  237.         if (iflags & RTF_GATEWAY)
  238.             strcat(flags, "G");
  239.         if (iflags & RTF_HOST)
  240.             strcat(flags, "H");
  241.         if (iflags & RTF_REINSTATE)
  242.             strcat(flags, "R");
  243.         if (iflags & RTF_DYNAMIC)
  244.             strcat(flags, "D");
  245.         if (iflags & RTF_MODIFIED)
  246.             strcat(flags, "M");
  247.  
  248.         /* Print the info. */
  249.         printf("%-15s %-15s %-15s %-5s %-6d %-3d %6d %s\n",
  250.                net_addr, gate_addr, mask_addr, flags,
  251.                mss, window, use, iface);
  252.     }
  253.  
  254.     (void) fclose(fp);
  255. }
  256.  
  257. /* Add a routing table entry. */
  258. int rt_add(char **args)
  259. {
  260.     struct rtentry rt;
  261.     char target[128], gateway[128] = "NONE", netmask[128] = "default";
  262.     int xflag, isnet;
  263.  
  264.     xflag = 0;
  265.     if (*args == NULL)
  266.         usage();
  267.     if (!strcmp(*args, "-net")) {
  268.         xflag = 1;
  269.         args++;
  270.     } else if (!strcmp(*args, "-host")) {
  271.         xflag = 2;
  272.         args++;
  273.     }
  274.     if (*args == NULL)
  275.         usage();
  276.     strcpy(target, *args++);
  277.     /* Clean out the RTREQ structure. */
  278.     memset((char *) &rt, 0, sizeof(struct rtentry));
  279.  
  280.     if ((isnet = resolve(target, &rt.rt_dst)) < 0) {
  281.         reserror(target);
  282.         return (-1);
  283.     }
  284.     switch (xflag) {
  285.     case 1:
  286.         isnet = 1;
  287.         break;
  288.  
  289.     case 2:
  290.         isnet = 0;
  291.         break;
  292.  
  293.     default:
  294.         break;
  295.     }
  296.  
  297.     /* Fill in the other fields. */
  298.     rt.rt_flags = (RTF_UP | RTF_HOST);
  299.     if (isnet)
  300.         rt.rt_flags &= ~RTF_HOST;
  301.  
  302.     /* Did we specify a GATEWAY entry? */
  303.     while (*args) {
  304.         if (!strcmp(*args, "metric")) {
  305.             int metric;
  306.  
  307.             args++;
  308.             if (!*args || !isdigit(**args))
  309.                 usage();
  310.             metric = atoi(*args);
  311. #ifdef SIOCADDRTOLD
  312.             rt.rt_metric = metric + 1;
  313. #else
  314.             if (opt_v)
  315.                 fprintf(stderr,"metric %d ignored\n",metric);
  316. #endif
  317.             args++;
  318.             continue;
  319.         }
  320.         if (!strcmp(*args, "netmask")) {
  321.             struct sockaddr mask;
  322.  
  323.             args++;
  324.             if (!*args || mask_in_addr(rt))
  325.                 usage();
  326.             strcpy(netmask, *args);
  327.             if ((isnet = resolve(netmask, &mask)) < 0) {
  328.                 reserror(netmask);
  329.                 return (-1);
  330.             }
  331.             rt.rt_genmask = full_mask(mask);
  332.             args++;
  333.             continue;
  334.         }
  335.         if (!strcmp(*args,"gw") || !strcmp(*args,"gateway")) {
  336.             args++;
  337.             if (!*args)
  338.                 usage();
  339.             if (rt.rt_flags & RTF_GATEWAY)
  340.                 usage();
  341.             strcpy(gateway, *args);
  342.             if ((isnet = resolve(gateway, &rt.rt_gateway)) < 0) {
  343.                 reserror(gateway);
  344.                 return (-1);
  345.             }
  346.             if (isnet) {
  347.                 fprintf(stderr, "%s: cannot use a NETWORK as gateway!\n",
  348.                     gateway);
  349.                 return (-1);
  350.             }
  351.             rt.rt_flags |= RTF_GATEWAY;
  352.             args++;
  353.             continue;
  354.         }
  355.         if (!strcmp(*args,"mss")) {
  356.             args++;
  357.             rt.rt_flags |= RTF_MSS;
  358.             rt.rt_mss = atoi(*args);
  359.             args++;
  360.             if(rt.rt_mss<64||rt.rt_mss>32768)
  361.             {
  362.                 fprintf(stderr,"Invalid MSS.\n");
  363.                 return -1;
  364.             }
  365.             continue;
  366.         }
  367.         if (!strcmp(*args,"window")) {
  368.             args++;
  369.             rt.rt_flags |= RTF_WINDOW;
  370.             rt.rt_window = atoi(*args);
  371.             args++;
  372.             if(rt.rt_window<128||rt.rt_window>32768)
  373.             {
  374.                 fprintf(stderr,"Invalid window.\n");
  375.                 return -1;
  376.             }
  377.             continue;
  378.         }
  379.         if (!strcmp(*args,"device") || !strcmp(*args,"dev")) {
  380.             args++;
  381.             if (!*args)
  382.                 usage();
  383.         } else
  384.             if (args[1])
  385.                 usage();
  386.         if (rt.rt_dev)
  387.             usage();
  388.         rt.rt_dev = *args;
  389.         args++;
  390.     }
  391.     /* sanity checks.. */
  392.     if (mask_in_addr(rt)) {
  393.         unsigned long mask = ~ntohl(mask_in_addr(rt));
  394.         if (rt.rt_flags & RTF_HOST) {
  395.             fprintf(stderr, "route: netmask doesn't make sense with host route\n");
  396.             return -1;
  397.         }
  398.         if (mask & (mask+1)) {
  399.             fprintf(stderr, "route: bogus netmask %s\n", netmask);
  400.             return -1;
  401.         }
  402.         mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
  403.         if (mask & ~mask_in_addr(rt)) {
  404.             fprintf(stderr, "route: netmask doesn't match route address\n");
  405.             return -1;
  406.         }
  407.     }
  408.     /* Tell the kernel to accept this route. */
  409.     if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
  410.         fprintf(stderr, "SIOCADDRT: %s\n", strerror(errno));
  411.         return (-1);
  412.     }
  413.     return (0);
  414. }
  415.  
  416.  
  417. /* Delete a routing table entry. */
  418. int rt_del(char **args)
  419. {
  420.     char target[128];
  421.     struct sockaddr trg;
  422.     struct rtentry rt;
  423.  
  424.     if (!args[0] || args[1])
  425.         usage();
  426.  
  427.     strcpy(target, *args);
  428.  
  429.     if (resolve(target, &trg) < 0) {
  430.         reserror(target);
  431.         return (-1);
  432.     }
  433.     /* Clean out the RTREQ structure. */
  434.     memset((char *) &rt, 0, sizeof(struct rtentry));
  435.     memcpy((char *) &rt.rt_dst, (char *) &trg, sizeof(struct sockaddr));
  436.  
  437.     /* Tell the kernel to delete this route. */
  438.     if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
  439.         fprintf(stderr, "SIOCDELRT: %s\n", strerror(errno));
  440.         return (-1);
  441.     }
  442.     return (0);
  443. }
  444.  
  445.  
  446. int main(int argc, char **argv)
  447. {
  448.     int i;
  449.     char *s;
  450.  
  451.     /* Fetch the command-line arguments. */
  452.     argv++;
  453.     while ((s = *argv) != NULL) {
  454.         if (*s != '-')
  455.             break;
  456.         while (*++s != '\0')
  457.             switch (*s) {
  458.             case 'n':
  459.                 opt_n = 1;
  460.                 break;
  461.  
  462.             case 'v':
  463.                 opt_v = 1;
  464.                 break;
  465.  
  466.             default:
  467.                 usage();
  468.             }
  469.         argv++;
  470.     }
  471.  
  472.     /* Do we have to show the contents of the routing table? */
  473.     if (*argv == NULL) {
  474.         rt_print();
  475.         exit(0);
  476.     }
  477.     /* Fetch the command. */
  478.     if (strcmp(*argv, "add") && strcmp(*argv, "del"))
  479.         usage();
  480.  
  481.     /* Create a socket to the INET kernel. */
  482.     if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  483.         perror("socket");
  484.         exit(-1);
  485.     }
  486.     /* See what we have to do here. */
  487.     if (!strcmp(*argv, "add"))
  488.         i = rt_add(++argv);
  489.     else
  490.         i = rt_del(++argv);
  491.  
  492.     /* Close the socket. */
  493.     (void) close(skfd);
  494.  
  495.     return (i);
  496. }
  497.