home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NET-TOOL.1 / NET-TOOL / net-tools / arp.c next >
Encoding:
C/C++ Source or Header  |  1994-10-24  |  10.3 KB  |  475 lines

  1.  
  2. /*
  3.  * arp        This file contains an implementation of the command
  4.  *        that maintains the kernel's ARP cache.  It is derived
  5.  *        from Berkeley UNIX arp(8), but cleaner and with sup-
  6.  *        port for devices other than Ethernet.
  7.  *
  8.  * Usage:    arp [-vn] [-p proto] [-t type] -a [hostname]
  9.  *        arp [-v] [-p proto] -d hostname ...
  10.  *        arp [-v] [-p proto] [-t type] -s hostname hw_addr
  11.  *                        [temp|pub|rarp|trail]
  12.  *        arp [-vn] -f filename
  13.  *
  14.  * Version:    @(#)arp.c    1.50    01/20/94
  15.  *
  16.  * Author:     Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  17.  *
  18.  * Modified for NET3 by Alan Cox.
  19.  * Modified for proxy arp netmasks by Andrew Tridgell
  20.  */
  21. #include <sys/types.h>
  22. #include <sys/socket.h>
  23. #include <sys/ioctl.h>
  24. #include <net/if.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <errno.h>
  28. #include <ctype.h>
  29. #include <fcntl.h>
  30. #include <string.h>
  31. #include <unistd.h>
  32. #include "support.h"
  33. #include "pathnames.h"
  34. #include "version.h"
  35.  
  36.  
  37. #define DFLT_AF    "inet"
  38. #define DFLT_HW    "ether"
  39.  
  40.  
  41. char *Release = RELEASE,
  42.      *Version = "@(#) arp 1.50 (01/20/94)";
  43.  
  44.  
  45. int opt_n = 0;                /* do not resolve addresses    */
  46. int opt_v = 0;                /* debugging output flag    */
  47. struct aftype *ap;            /* current address family    */
  48. struct hwtype *hw;            /* current hardware type    */
  49. int skfd;                /* active /proc  descriptor    */
  50. int sockfd;                /* active socket descriptor     */
  51.  
  52.  
  53. static void usage(void);
  54.  
  55.  
  56. /* Delete an entry from the ARP cache. */
  57. static int
  58. arp_del(char **args)
  59. {
  60.   char host[128];
  61.   struct arpreq req;
  62.   struct sockaddr sa;
  63.  
  64.   /* Resolve the host name. */
  65.   if (*args == NULL) {
  66.     fprintf(stderr, "arp: need host name\n");
  67.     return(-1);
  68.   }
  69.   strcpy(host, *args);
  70.   if (ap->input(host, &sa) < 0) {
  71.     ap->herror(host);
  72.     return(-1);
  73.   }
  74.  
  75.   /* If a host has more than one address, use the correct one! */
  76.   memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
  77.  
  78.   /* Call the kernel. */
  79.   if (ioctl(sockfd, SIOCDARP, &req) < 0) {
  80.     if (errno != ENXIO) {
  81.         perror("SIOCDARP");
  82.         return(-1);
  83.     } else printf("No ARP entry for %s\n", host);
  84.   }
  85.  
  86.   return(0);
  87. }
  88.  
  89.  
  90. /* Set an entry in the ARP cache. */
  91. static int
  92. arp_set(char **args)
  93. {
  94.   char host[128];
  95.   struct arpreq req;
  96.   struct sockaddr sa;
  97.   int flags;
  98.  
  99.   /* Resolve the host name. */
  100.   if (*args == NULL) {
  101.     fprintf(stderr, "arp: need host name\n");
  102.     return(-1);
  103.   }
  104.   strcpy(host, *args++);
  105.   if (ap->input(host, &sa) < 0) {
  106.     ap->herror(host);
  107.     return(-1);
  108.   }
  109.  
  110.   /* If a host has more than one address, use the correct one! */
  111.   memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
  112.  
  113.   /* Fetch the hardware address. */
  114.   if (*args == NULL) {
  115.     fprintf(stderr, "arp: need hardware address\n");
  116.     return(-1);
  117.   }
  118.   if (hw->input(*args++, &req.arp_ha) < 0) {
  119.     fprintf(stderr, "arp: invalid hardware address\n");
  120.     return(-1);
  121.   }
  122.  
  123.   /* Check out any modifiers. */
  124.   flags = ATF_PERM;
  125.   while (*args != NULL) {
  126.     if (! strcmp(*args, "temp")) flags &= ~ATF_PERM;
  127.     if (! strcmp(*args, "pub")) flags |= ATF_PUBL;
  128. /*    if (! strcmp(*args, "rarp")) flags |= ATF_RARP;*/
  129.     if (! strcmp(*args, "trail")) flags |= ATF_USETRAILERS;
  130.     if (! strcmp(*args, "netmask")) 
  131.       {
  132.         if (*++args == NULL) usage();
  133.         if (strcmp(*args,"255.255.255.255") != 0)
  134.           {
  135.         strcpy(host, *args);
  136.         if (ap->input(host, &sa) < 0) {
  137.           ap->herror(host);
  138.           return(-1);
  139.         }
  140.         memcpy((char *) &req.arp_netmask, (char *) &sa,
  141.                sizeof(struct sockaddr));
  142.         flags |= ATF_NETMASK;
  143.           }
  144.       }
  145.     args++;
  146.   }
  147.  
  148.   if ((flags & ATF_NETMASK) && !(flags & ATF_PUBL))
  149.     usage();
  150.  
  151.   /* Fill in the remainder of the request. */
  152.   req.arp_flags = flags;
  153.  
  154.   /* Call the kernel. */
  155.   if (ioctl(sockfd, SIOCSARP, &req) < 0) {
  156.     perror("SIOCSARP");
  157.     return(-1);
  158.   }
  159.   return(0);
  160. }
  161.  
  162.  
  163. /* Process an EtherFile */
  164. static int
  165. arp_file(char *name)
  166. {
  167.   char buff[1024];
  168.   char *sp, *args[32];
  169.   int linenr, argc;
  170.   FILE *fp;
  171.  
  172.   if ((fp = fopen(name, "r")) == NULL) {
  173.     fprintf(stderr, "arp: cannot open etherfile %s !\n", name);
  174.     return(-1);
  175.   }
  176.  
  177.   /* Read the lines in the file. */
  178.   linenr = 0;
  179.   while (fgets(buff, sizeof(buff), fp) != (char *)NULL) {
  180.     linenr++;
  181.     if (opt_v == 1) fprintf(stderr, ">> %s", buff);
  182.     if ((sp = strchr(buff, '\n')) != (char *)NULL) *sp = '\0';
  183.     if (buff[0] == '#' || buff[0] == '\0') continue;
  184.  
  185.     argc = getargs(buff, args);
  186.     if (argc < 2) {
  187.         fprintf(stderr,
  188.             "arp: format error on line %u of etherfile %s !\n",
  189.                             linenr, name);
  190.         continue;
  191.     }
  192.  
  193.     if (arp_set(args) != 0) {
  194.         fprintf(stderr,
  195.             "arp: cannot set entry on line %u of etherfile %s !\n",
  196.                             linenr, name);
  197.     }
  198.   }
  199.  
  200.   (void) fclose(fp);
  201.   return(0);
  202. }
  203.  
  204.  
  205. /* Print the contents of an ARP request block. */
  206. static void
  207. arp_disp(struct arpreq *req)
  208. {
  209.   static int title = 0;
  210.   struct hwtype *xhw;
  211.   struct aftype *xap;
  212.   char *sp, flags[6];
  213.  
  214.   /* Fetch the hardware type, which was given by the kernel. */
  215.   if(req->arp_ha.sa_family==0)
  216.       req->arp_ha.sa_family=ARPHRD_ETHER;
  217.   xhw = get_hwntype(req->arp_ha.sa_family);
  218.   if (xhw == NULL) xhw = get_hwtype("ether");
  219.   xap = get_afntype(req->arp_pa.sa_family);
  220.   if (xap == NULL) xap = get_aftype("inet");
  221.   
  222.   if (title++ == 0) printf("Address\t\t\tHW type\t\tHW address\t\tFlags\n");
  223.  
  224.   /* Setup the flags. */
  225.   flags[0] = '\0';
  226.   if (req->arp_flags & ATF_COM) strcat(flags, "C");
  227.   if (req->arp_flags & ATF_PERM) strcat(flags, "M");
  228.   if (req->arp_flags & ATF_PUBL) strcat(flags, "P");
  229. /*  if (req->arp_flags & ATF_RARP) strcat(flags, "R");*/
  230.   if (req->arp_flags & ATF_USETRAILERS) strcat(flags, "T");
  231.  
  232.   sp = xap->print(req->arp_pa.sa_data/*, opt_n*/);
  233.   printf("%-23.23s\t%-16.16s", sp, xhw->title);
  234.   printf("%-21.21s\t%-6s\n", xhw->sprint(&req->arp_ha), flags);
  235. }
  236.  
  237.  
  238. /* Print the contents of an ARP request block. */
  239. static void
  240. arp_disp_2(char *ip,int type,int arp_flags,char *hw,char *mask)
  241. {
  242.   static int title = 0;
  243.   struct hwtype *xhw;
  244.   struct aftype *xap;
  245. /*  char *sp; */ 
  246.   char flags[6];
  247.  
  248.   xhw = get_hwntype(type);
  249.   if (xhw == NULL) 
  250.     xhw = get_hwtype("ether");
  251. /*
  252.  * xap = get_afntype(req->arp_pa.sa_family);
  253.  * if (xap == NULL) 
  254.  */
  255.   xap = get_aftype("inet");
  256.   
  257.   if (title++ == 0) 
  258.     printf("Address\t\t\tHW type\t\tHW address\t\tFlags\tMask\n");
  259.  
  260.   /* Setup the flags. */
  261.   flags[0] = '\0';
  262.   if (arp_flags & ATF_COM) strcat(flags, "C");
  263.   if (arp_flags & ATF_PERM) strcat(flags, "M");
  264.   if (arp_flags & ATF_PUBL) strcat(flags, "P");
  265. /*  if (arp_flags & ATF_RARP) strcat(flags, "R");*/
  266.   if (arp_flags & ATF_USETRAILERS) strcat(flags, "T");
  267.  
  268. #ifdef NOTDEF
  269.   sp = xap->print(req->arp_pa.sa_data/*, opt_n*/);
  270. #endif
  271.   printf("%-23.23s\t%-16.16s", ip /* sp */, xhw->title);
  272.   printf("%-21.21s\t%-6s\t%s\n", hw /* xhw->sprint(&req->arp_ha) */, flags,mask);
  273. }
  274.  
  275.  
  276. /* Display the contents of the ARP cache in the kernel. */
  277. static int
  278. pr_arps(void)
  279. {
  280.   char ip[100];
  281.   char hw[100];
  282.   char mask[100];
  283.   char line[200];
  284.   int type,flags;
  285.   FILE *fp;
  286.   int num;
  287.  
  288.   /* Open the PROCps kernel table. */
  289.   if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL) {
  290.     perror(_PATH_PROCNET_ARP);
  291.     return(-1);
  292.   }
  293.  
  294.   /* Bypass header -- read until newline */
  295.   if (fgets(line, sizeof(line), fp) != (char *)NULL)
  296.     {
  297.       /* check to see if this kernel has an arp netmask */
  298.       int has_mask = (strstr(line,"Mask") != NULL);
  299.  
  300.       /* Read the ARP cache entries. */
  301.       for(;;)
  302.     {
  303.       *mask = 0;
  304.       if (has_mask)
  305.         num=fscanf(fp,"%s 0x%x 0x%x %s %s",ip,&type,&flags,hw,mask);
  306.       else
  307.         num=fscanf(fp,"%s 0x%x 0x%x %s",ip,&type,&flags,hw);
  308.       if(num<4)
  309.         break;
  310.  
  311.       arp_disp_2(ip,type,flags,hw,mask);
  312.     }
  313.     }
  314.  
  315.   (void) fclose(fp);
  316.   return(0);
  317. }
  318.  
  319.  
  320. /* Show one or more entries from the ARP cache. */
  321. static int
  322. arp_show(char *name)
  323. {
  324.   char host[128];
  325.   struct sockaddr sa;
  326.   struct arpreq req;
  327.  
  328.   /* Do we have to show the whole table? */
  329.   if (name == NULL) return(pr_arps());
  330.  
  331.   /* Nope.  Resolve the host name. */
  332.   strcpy(host, name);
  333.   if (ap->input(host, &sa) < 0) {
  334.     fprintf(stderr, "arp: %s: %s\n", host, strerror(errno));
  335.     return(-1);
  336.   }
  337.  
  338.   /* If a host has more than one address, use the correct one! */
  339.   memcpy((char *) &req.arp_pa, &sa, sizeof(struct sockaddr));
  340.   req.arp_ha.sa_family = AF_UNSPEC;    /* any type */
  341.  
  342.   /* Call the kernel. */
  343.   if (ioctl(sockfd, SIOCGARP, &req) < 0) {
  344.     if (errno != ENXIO) perror("SIOCGARP");
  345.       else printf("No ARP entry for %s\n", host);
  346.         return(-1);
  347.   }
  348.  
  349.   /* We found it.  Display the results. */
  350.   arp_disp(&req);
  351.  
  352.   return(0);
  353. }
  354.  
  355.  
  356. static void
  357. usage(void)
  358. {
  359.   fprintf(stderr,
  360.     "Usage: arp [-vn] [-p proto] [-t type] -a [hostname]\n");
  361.   fprintf(stderr,
  362.     "       arp [-v] [-p proto] -d hostname ...\n");
  363.   fprintf(stderr,
  364.     "       arp [-v] [-p proto] [-t type] -s hostname hw_addr [netmask aa.bb.cc.dd] [temp|pub|trail]\n");
  365.   fprintf(stderr,
  366.     "       arp [-vn] -f filename\n");
  367.   fprintf(stderr,
  368.     "       Note: netmask may only be used with the pub option\n");
  369.   exit(-1);
  370. }
  371.  
  372.  
  373. int
  374. main(int argc, char **argv)
  375. {
  376.   int c, what;
  377.  
  378.   /* Initialize variables... */
  379.   if ((hw = get_hwtype(DFLT_HW)) == NULL) {
  380.     fprintf(stderr, "%s: hardware type not supported!\n", DFLT_HW);
  381.     return(-1);
  382.   }
  383.   if ((ap = get_aftype(DFLT_AF)) == NULL) {
  384.     fprintf(stderr, "%s: address family not supported!\n", DFLT_AF);
  385.     return(-1);
  386.   }
  387.   what = -1;
  388.  
  389.   /* Fetch the command-line arguments. */
  390.   opterr = 0;
  391.   while ((c = getopt(argc, argv, "adfp:nst:v")) != EOF) switch(c) {
  392.     case 'a':
  393.         what = 1;
  394.         break;
  395.  
  396.     case 'd':
  397.         what = 3;
  398.         break;
  399.  
  400.     case 'f':
  401.         what = 2;
  402.         break;
  403.  
  404.     case 'n':
  405.         opt_n = 1;
  406.         break;
  407.  
  408.     case 'p':
  409.         ap = get_aftype(optarg);
  410.         if (ap == NULL) {
  411.             fprintf(stderr, "arp: %s: unknown address family.\n",
  412.                                 optarg);
  413.             exit(-1);
  414.         }
  415.         break;
  416.  
  417.     case 's':
  418.         what = 4;
  419.         break;
  420.  
  421.     case 't':
  422.         hw = get_hwtype(optarg);
  423.         if (hw == NULL) {
  424.             fprintf(stderr, "arp: %s: unknown hardware type.\n",
  425.                                 optarg);
  426.             exit(-1);
  427.         }
  428.         break;
  429.  
  430.     case 'v':
  431.         opt_v = 1;
  432.         break;
  433.  
  434.     default:
  435.         usage();
  436.   }
  437.  
  438.   /* Create an entry point into the ARP protocol. */
  439.   if ((skfd = open(_PATH_PROCNET_ARP, O_RDONLY)) < 0) {
  440.     perror(_PATH_PROCNET_ARP);
  441.     exit(-1);
  442.   }
  443.   if ((sockfd = socket(AF_INET,SOCK_DGRAM,0)) <0)
  444.   {
  445.       perror("socket");
  446.       exit(-1);
  447.   }
  448.  
  449.   /* Now see what we have to do here... */
  450.   switch(what) {
  451.     case 1:        /* show an ARP entry in the cache */
  452.         what = arp_show(argv[optind]);
  453.         break;
  454.  
  455.     case 2:        /* process an EtherFile */
  456.         what = arp_file(argv[optind]);
  457.         break;
  458.  
  459.     case 3:        /* delete an ARP entry from the cache */
  460.         what = arp_del(&argv[optind]);
  461.         break;
  462.  
  463.     case 4:        /* set an ARP entry in the cache */
  464.         what = arp_set(&argv[optind]);
  465.         break;
  466.  
  467.     default:
  468.         usage();
  469.   }
  470.  
  471.   (void) close(skfd);
  472.   exit(what);
  473. }
  474.  
  475.