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