/* arp.c Created: Jan 2001 by Philip Homburg Manipulate ARP table */ #define _POSIX_C_SOURCE 2 #define _MINIX_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include char *progname; static int ipfd= -1; static int do_setuid= 0; static void do_open(char *devname); static void show_one(char *hostname, int do_num); static void show_all(int do_num); static void print_one(ipaddr_t ipaddr, nwio_arp_t *arpp, int do_num); static void delete_all(void); static void delete(char *hostname); static void do_set(char *hostname, char *ethername, int temp, int pub, int optdelete); static ipaddr_t nametoipaddr(char *hostname); static void fatal(char *fmt, ...); static void usage(void); int main(int argc, char *argv[]) { int c; char *hostname, *ethername; int do_temp, do_pub; int a_flag, d_flag, n_flag, s_flag, S_flag; char *I_arg; (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]); a_flag= d_flag= n_flag= s_flag= S_flag= 0; I_arg= NULL; while(c= getopt(argc, argv, "adnsS?I:"), c != -1) { switch(c) { case '?': usage(); case 'a': a_flag= 1; break; case 'd': d_flag= 1; break; case 'n': n_flag= 1; break; case 's': s_flag= 1; break; case 'S': S_flag= 1; break; case 'I': I_arg= optarg; break; default: fatal("getopt failed: '%c'", c); } } hostname= NULL; /* lint */ ethername= NULL; /* lint */ do_temp= do_pub= 0; /* lint */ if (n_flag + d_flag + s_flag + S_flag > 1) usage(); if (s_flag || S_flag) { if (optind >= argc) usage(); hostname= argv[optind++]; if (optind >= argc) usage(); ethername= argv[optind++]; do_temp= do_pub= 0; while (optind < argc) { if (strcasecmp(argv[optind], "temp") == 0) { do_temp= 1; optind++; continue; } if (strcasecmp(argv[optind], "pub") == 0) { do_pub= 1; optind++; continue; } usage(); } } else if (d_flag) { if (!a_flag) { if (optind >= argc) usage(); hostname= argv[optind++]; if (optind != argc) usage(); } } else if (a_flag) { if (optind != argc) usage(); do_setuid= 1; } else { if (optind >= argc) usage(); hostname= argv[optind++]; if (optind != argc) usage(); do_setuid= 1; } do_open(I_arg); if (d_flag) { if (a_flag) delete_all(); else delete(hostname); } else if (s_flag || S_flag) do_set(hostname, ethername, do_temp, do_pub, S_flag); else if (a_flag) show_all(n_flag); else show_one(hostname, n_flag); exit(0); } static void do_open(char *devname) { size_t l; char *check; if (do_setuid && devname) { /* Only strings that consist of IP_DEVICE optionally * followed by a number are allowed. */ l= strlen(IP_DEVICE); if (strncmp(devname, IP_DEVICE, l) != 0) do_setuid= 0; else if (strlen(devname) == l) ; /* OK */ else { strtoul(devname+l, &check, 10); if (check[0] != '\0') do_setuid= 0; } } if (!devname) devname= IP_DEVICE; if (!do_setuid) { setuid(getuid()); setgid(getgid()); } ipfd= open(devname, O_RDWR); if (ipfd == -1) fatal("unable to open '%s': %s", devname, strerror(errno)); } static void show_one(char *hostname, int do_num) { int r; ipaddr_t ipaddr; nwio_arp_t arp; ipaddr= nametoipaddr(hostname); arp.nwa_ipaddr= ipaddr; r= ioctl(ipfd, NWIOARPGIP, &arp); if (r == -1 && errno == ENOENT) { print_one(ipaddr, NULL, do_num); exit(1); } if (r == -1) fatal("NWIOARPGIP failed: %s", strerror(errno)); print_one(ipaddr, &arp, do_num); } static void show_all(int do_num) { int ind, max, i, r; nwio_arp_t *arptab; nwio_arp_t arp; /* First get all entries */ max= 10; ind= 0; arptab= malloc(max * sizeof(*arptab)); if (arptab == NULL) { fatal("out of memory, can't get %d bytes", max*sizeof(*arptab)); } arp.nwa_entno= 0; for (;;) { if (ind == max) { max *= 2; arptab= realloc(arptab, max * sizeof(*arptab)); if (!arptab) { fatal("out of memory, can't get %d bytes", max*sizeof(*arptab)); } } r= ioctl(ipfd, NWIOARPGNEXT, &arp); if (r == -1 && errno == ENOENT) break; if (r == -1) fatal("NWIOARPGNEXT failed: %s", strerror(errno)); arptab[ind]= arp; ind++; } for (i= 0; inwa_ipaddr; if (!do_num) he= gethostbyaddr((char *)&ipaddr, sizeof(ipaddr), AF_INET); else he= NULL; if (he) printf("%s (%s)", he->h_name, inet_ntoa(ipaddr)); else printf("%s", inet_ntoa(ipaddr)); if (!arpp) { printf(" -- no entry\n"); return; } flags= arpp->nwa_flags; if (flags & NWAF_INCOMPLETE) printf(" is incomplete"); else if (flags & NWAF_DEAD) printf(" is dead"); else { printf(" is at %s", ether_ntoa(&arpp->nwa_ethaddr)); if (flags & NWAF_PERM) printf(" permanent"); if (flags & NWAF_PUB) printf(" published"); } printf("\n"); } static void delete_all(void) { int ind, max, i, r; nwio_arp_t *arptab; nwio_arp_t arp; /* First get all entries */ max= 10; ind= 0; arptab= malloc(max * sizeof(*arptab)); if (arptab == NULL) { fatal("out of memory, can't get %d bytes", max*sizeof(*arptab)); } arp.nwa_entno= 0; for (;;) { if (ind == max) { max *= 2; arptab= realloc(arptab, max * sizeof(*arptab)); if (arptab == NULL) { fatal("out of memory, can't get %d bytes", max*sizeof(*arptab)); } } r= ioctl(ipfd, NWIOARPGNEXT, &arp); if (r == -1 && errno == ENOENT) break; if (r == -1) fatal("NWIOARPGNEXT failed: %s", strerror(errno)); arptab[ind]= arp; ind++; } for (i= 0; ih_addrtype != AF_INET || he->h_length != sizeof(ipaddr)) { fatal("strange host '%s': addrtype %d, length %d", he->h_addrtype, he->h_length); } memcpy(&ipaddr, he->h_addr, sizeof(ipaddr)); } return ipaddr; } #if 0 static char *ether_ntoa(struct ether_addr *eap) { static char buf[]= "xx:xx:xx:xx:xx:xx"; sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", eap->ea_addr[0], eap->ea_addr[1], eap->ea_addr[2], eap->ea_addr[3], eap->ea_addr[4], eap->ea_addr[5]); return buf; } #endif static void fatal(char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "%s: ", progname); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); exit(1); } static void usage(void) { fprintf(stderr, "Usage:\tarp [-I ip-dev] [-n] hostname\n" "\tarp [-I ip-dev] [-n] -a\n" "\tarp [-I ip-dev] -d hostname\n" "\tarp [-I ip-dev] -d -a\n" "\tarp [-I ip-dev] -s hostname ether-addr [temp] [pub]\n" "\tarp [-I ip-dev] -S hostname ether-addr [temp] [pub]\n"); exit(1); } /* * $PchId: arp.c,v 1.3 2005/01/31 22:31:45 philip Exp $ */