Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

arp-ioctl.c

Go to the documentation of this file.
00001 /*
00002  * arp-ioctl.c
00003  *
00004  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
00005  *
00006  * $Id: arp-ioctl.c,v 1.25 2005/02/09 22:31:00 dugsong Exp $
00007  */
00008 
00009 #include "config.h"
00010 
00011 #include <sys/param.h>
00012 #include <sys/types.h>
00013 #include <sys/ioctl.h>
00014 #include <sys/socket.h>
00015 #ifdef HAVE_STREAMS_MIB2
00016 # include <sys/sockio.h>
00017 # include <sys/stream.h>
00018 # include <sys/tihdr.h>
00019 # include <sys/tiuser.h>
00020 # include <inet/common.h>
00021 # include <inet/mib2.h>
00022 # include <inet/ip.h>
00023 # undef IP_ADDR_LEN
00024 #elif defined(HAVE_SYS_MIB_H)
00025 # include <sys/mib.h>
00026 #endif
00027 
00028 #include <net/if.h>
00029 #include <net/if_arp.h>
00030 #ifdef HAVE_STREAMS_MIB2
00031 # include <netinet/in.h>
00032 # include <stropts.h>
00033 #endif
00034 #include <errno.h>
00035 #include <fcntl.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <unistd.h>
00040 
00041 #include "dnet.h"
00042 
00043 #ifdef HAVE_LINUX_PROCFS
00044 #define PROC_ARP_FILE   "/proc/net/arp"
00045 #endif
00046 
00047 struct arp_handle {
00048         int      fd;
00049 #ifdef HAVE_ARPREQ_ARP_DEV
00050         intf_t  *intf;
00051 #endif
00052 };
00053 
00054 arp_t *
00055 arp_open(void)
00056 {
00057         arp_t *a;
00058         
00059         if ((a = calloc(1, sizeof(*a))) != NULL) {
00060 #ifdef HAVE_STREAMS_MIB2
00061                 if ((a->fd = open(IP_DEV_NAME, O_RDWR)) < 0)
00062 #elif defined(HAVE_STREAMS_ROUTE)
00063                 if ((a->fd = open("/dev/route", O_WRONLY, 0)) < 0)
00064 #else
00065                 if ((a->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00066 #endif
00067                         return (arp_close(a));
00068 #ifdef HAVE_ARPREQ_ARP_DEV
00069                 if ((a->intf = intf_open()) == NULL)
00070                         return (arp_close(a));
00071 #endif
00072         }
00073         return (a);
00074 }
00075 
00076 #ifdef HAVE_ARPREQ_ARP_DEV
00077 static int
00078 _arp_set_dev(const struct intf_entry *entry, void *arg)
00079 {
00080         struct arpreq *ar = (struct arpreq *)arg;
00081         struct addr dst;
00082         uint32_t mask;
00083 
00084         if (entry->intf_type == INTF_TYPE_ETH &&
00085             entry->intf_addr.addr_type == ADDR_TYPE_IP) {
00086                 addr_btom(entry->intf_addr.addr_bits, &mask, IP_ADDR_LEN);
00087                 addr_ston((struct sockaddr *)&ar->arp_pa, &dst);
00088         
00089                 if ((entry->intf_addr.addr_ip & mask) ==
00090                     (dst.addr_ip & mask)) {
00091                         strlcpy(ar->arp_dev, entry->intf_name,
00092                             sizeof(ar->arp_dev));
00093                         return (1);
00094                 }
00095         }
00096         return (0);
00097 }
00098 #endif
00099 
00100 int
00101 arp_add(arp_t *a, const struct arp_entry *entry)
00102 {
00103         struct arpreq ar;
00104 
00105         memset(&ar, 0, sizeof(ar));
00106 
00107         if (addr_ntos(&entry->arp_pa, &ar.arp_pa) < 0)
00108                 return (-1);
00109 
00110         /* XXX - see arp(7) for details... */
00111 #ifdef __linux__
00112         if (addr_ntos(&entry->arp_ha, &ar.arp_ha) < 0)
00113                 return (-1);
00114         ar.arp_ha.sa_family = ARP_HRD_ETH;
00115 #else
00116         /* XXX - Solaris, HP-UX, IRIX, other Mentat stacks? */
00117         ar.arp_ha.sa_family = AF_UNSPEC;
00118         memcpy(ar.arp_ha.sa_data, &entry->arp_ha.addr_eth, ETH_ADDR_LEN);
00119 #endif
00120 
00121 #ifdef HAVE_ARPREQ_ARP_DEV
00122         if (intf_loop(a->intf, _arp_set_dev, &ar) != 1) {
00123                 errno = ESRCH;
00124                 return (-1);
00125         }
00126 #endif
00127         ar.arp_flags = ATF_PERM | ATF_COM;
00128 #ifdef hpux
00129         /* XXX - screwy extended arpreq struct */
00130         {
00131                 struct sockaddr_in *sin;
00132 
00133                 ar.arp_hw_addr_len = ETH_ADDR_LEN;
00134                 sin = (struct sockaddr_in *)&ar.arp_pa_mask;
00135                 sin->sin_family = AF_INET;
00136                 sin->sin_addr.s_addr = IP_ADDR_BROADCAST;
00137         }
00138 #endif
00139         if (ioctl(a->fd, SIOCSARP, &ar) < 0)
00140                 return (-1);
00141 
00142 #ifdef HAVE_STREAMS_MIB2
00143         /* XXX - force entry into ipNetToMediaTable. */
00144         {
00145                 struct sockaddr_in sin;
00146                 int fd;
00147                 
00148                 addr_ntos(&entry->arp_pa, (struct sockaddr *)&sin);
00149                 sin.sin_port = htons(666);
00150                 
00151                 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00152                         return (-1);
00153                 
00154                 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
00155                         close(fd);
00156                         return (-1);
00157                 }
00158                 write(fd, NULL, 0);
00159                 close(fd);
00160         }
00161 #endif
00162         return (0);
00163 }
00164 
00165 int
00166 arp_delete(arp_t *a, const struct arp_entry *entry)
00167 {
00168         struct arpreq ar;
00169 
00170         memset(&ar, 0, sizeof(ar));
00171         
00172         if (addr_ntos(&entry->arp_pa, &ar.arp_pa) < 0)
00173                 return (-1);
00174         
00175         if (ioctl(a->fd, SIOCDARP, &ar) < 0)
00176                 return (-1);
00177 
00178         return (0);
00179 }
00180 
00181 int
00182 arp_get(arp_t *a, struct arp_entry *entry)
00183 {
00184         struct arpreq ar;
00185 
00186         memset(&ar, 0, sizeof(ar));
00187         
00188         if (addr_ntos(&entry->arp_pa, &ar.arp_pa) < 0)
00189                 return (-1);
00190         
00191 #ifdef HAVE_ARPREQ_ARP_DEV
00192         if (intf_loop(a->intf, _arp_set_dev, &ar) != 1) {
00193                 errno = ESRCH;
00194                 return (-1);
00195         }
00196 #endif
00197         if (ioctl(a->fd, SIOCGARP, &ar) < 0)
00198                 return (-1);
00199 
00200         if ((ar.arp_flags & ATF_COM) == 0) {
00201                 errno = ESRCH;
00202                 return (-1);
00203         }
00204         return (addr_ston(&ar.arp_ha, &entry->arp_ha));
00205 }
00206 
00207 #ifdef HAVE_LINUX_PROCFS
00208 int
00209 arp_loop(arp_t *a, arp_handler callback, void *arg)
00210 {
00211         FILE *fp;
00212         struct arp_entry entry;
00213         char buf[BUFSIZ], ipbuf[100], macbuf[100], maskbuf[100], devbuf[100];
00214         int i, type, flags, ret;
00215 
00216         if ((fp = fopen(PROC_ARP_FILE, "r")) == NULL)
00217                 return (-1);
00218 
00219         ret = 0;
00220         while (fgets(buf, sizeof(buf), fp) != NULL) {
00221                 i = sscanf(buf, "%s 0x%x 0x%x %100s %100s %100s\n",
00222                     ipbuf, &type, &flags, macbuf, maskbuf, devbuf);
00223                 
00224                 if (i < 4 || (flags & ATF_COM) == 0)
00225                         continue;
00226                 
00227                 if (addr_aton(ipbuf, &entry.arp_pa) == 0 &&
00228                     addr_aton(macbuf, &entry.arp_ha) == 0) {
00229                         if ((ret = callback(&entry, arg)) != 0)
00230                                 break;
00231                 }
00232         }
00233         if (ferror(fp)) {
00234                 fclose(fp);
00235                 return (-1);
00236         }
00237         fclose(fp);
00238         
00239         return (ret);
00240 }
00241 #elif defined (HAVE_STREAMS_MIB2)
00242 int
00243 arp_loop(arp_t *r, arp_handler callback, void *arg)
00244 {
00245         struct arp_entry entry;
00246         struct strbuf msg;
00247         struct T_optmgmt_req *tor;
00248         struct T_optmgmt_ack *toa;
00249         struct T_error_ack *tea;
00250         struct opthdr *opt;
00251         mib2_ipNetToMediaEntry_t *arp, *arpend;
00252         u_char buf[8192];
00253         int flags, rc, atable, ret;
00254 
00255         tor = (struct T_optmgmt_req *)buf;
00256         toa = (struct T_optmgmt_ack *)buf;
00257         tea = (struct T_error_ack *)buf;
00258 
00259         tor->PRIM_type = T_OPTMGMT_REQ;
00260         tor->OPT_offset = sizeof(*tor);
00261         tor->OPT_length = sizeof(*opt);
00262         tor->MGMT_flags = T_CURRENT;
00263         
00264         opt = (struct opthdr *)(tor + 1);
00265         opt->level = MIB2_IP;
00266         opt->name = opt->len = 0;
00267         
00268         msg.maxlen = sizeof(buf);
00269         msg.len = sizeof(*tor) + sizeof(*opt);
00270         msg.buf = buf;
00271         
00272         if (putmsg(r->fd, &msg, NULL, 0) < 0)
00273                 return (-1);
00274         
00275         opt = (struct opthdr *)(toa + 1);
00276         msg.maxlen = sizeof(buf);
00277         
00278         for (;;) {
00279                 flags = 0;
00280                 if ((rc = getmsg(r->fd, &msg, NULL, &flags)) < 0)
00281                         return (-1);
00282 
00283                 /* See if we're finished. */
00284                 if (rc == 0 &&
00285                     msg.len >= sizeof(*toa) &&
00286                     toa->PRIM_type == T_OPTMGMT_ACK &&
00287                     toa->MGMT_flags == T_SUCCESS && opt->len == 0)
00288                         break;
00289 
00290                 if (msg.len >= sizeof(*tea) && tea->PRIM_type == T_ERROR_ACK)
00291                         return (-1);
00292                 
00293                 if (rc != MOREDATA || msg.len < (int)sizeof(*toa) ||
00294                     toa->PRIM_type != T_OPTMGMT_ACK ||
00295                     toa->MGMT_flags != T_SUCCESS)
00296                         return (-1);
00297                 
00298                 atable = (opt->level == MIB2_IP && opt->name == MIB2_IP_22);
00299                 
00300                 msg.maxlen = sizeof(buf) - (sizeof(buf) % sizeof(*arp));
00301                 msg.len = 0;
00302                 flags = 0;
00303                 
00304                 do {
00305                         rc = getmsg(r->fd, NULL, &msg, &flags);
00306                         
00307                         if (rc != 0 && rc != MOREDATA)
00308                                 return (-1);
00309                         
00310                         if (!atable)
00311                                 continue;
00312                         
00313                         arp = (mib2_ipNetToMediaEntry_t *)msg.buf;
00314                         arpend = (mib2_ipNetToMediaEntry_t *)
00315                             (msg.buf + msg.len);
00316 
00317                         entry.arp_pa.addr_type = ADDR_TYPE_IP;
00318                         entry.arp_pa.addr_bits = IP_ADDR_BITS;
00319                         
00320                         entry.arp_ha.addr_type = ADDR_TYPE_ETH;
00321                         entry.arp_ha.addr_bits = ETH_ADDR_BITS;
00322 
00323                         for ( ; arp < arpend; arp++) {
00324                                 entry.arp_pa.addr_ip =
00325                                     arp->ipNetToMediaNetAddress;
00326                                 
00327                                 memcpy(&entry.arp_ha.addr_eth,
00328                                     arp->ipNetToMediaPhysAddress.o_bytes,
00329                                     ETH_ADDR_LEN);
00330                                 
00331                                 if ((ret = callback(&entry, arg)) != 0)
00332                                         return (ret);
00333                         }
00334                 } while (rc == MOREDATA);
00335         }
00336         return (0);
00337 }
00338 #elif defined(HAVE_SYS_MIB_H)
00339 #define MAX_ARPENTRIES  512     /* XXX */
00340 
00341 int
00342 arp_loop(arp_t *r, arp_handler callback, void *arg)
00343 {
00344         struct nmparms nm;
00345         struct arp_entry entry;
00346         mib_ipNetToMediaEnt arpentries[MAX_ARPENTRIES];
00347         int fd, i, n, ret;
00348         
00349         if ((fd = open_mib("/dev/ip", O_RDWR, 0 /* XXX */, 0)) < 0)
00350                 return (-1);
00351         
00352         nm.objid = ID_ipNetToMediaTable;
00353         nm.buffer = arpentries;
00354         n = sizeof(arpentries);
00355         nm.len = &n;
00356         
00357         if (get_mib_info(fd, &nm) < 0) {
00358                 close_mib(fd);
00359                 return (-1);
00360         }
00361         close_mib(fd);
00362 
00363         entry.arp_pa.addr_type = ADDR_TYPE_IP;
00364         entry.arp_pa.addr_bits = IP_ADDR_BITS;
00365 
00366         entry.arp_ha.addr_type = ADDR_TYPE_ETH;
00367         entry.arp_ha.addr_bits = ETH_ADDR_BITS;
00368         
00369         n /= sizeof(*arpentries);
00370         ret = 0;
00371         
00372         for (i = 0; i < n; i++) {
00373                 if (arpentries[i].Type == INTM_INVALID ||
00374                     arpentries[i].PhysAddr.o_length != ETH_ADDR_LEN)
00375                         continue;
00376                 
00377                 entry.arp_pa.addr_ip = arpentries[i].NetAddr;
00378                 memcpy(&entry.arp_ha.addr_eth, arpentries[i].PhysAddr.o_bytes,
00379                     ETH_ADDR_LEN);
00380                 
00381                 if ((ret = callback(&entry, arg)) != 0)
00382                         break;
00383         }
00384         return (ret);
00385 }
00386 #elif defined(HAVE_NET_RADIX_H)
00387 /* XXX - Tru64, others? */
00388 #include <netinet/if_ether.h>
00389 #include <nlist.h>
00390 
00391 static int
00392 _kread(int fd, void *addr, void *buf, int len)
00393 {
00394         if (lseek(fd, (off_t)addr, SEEK_SET) == (off_t)-1L)
00395                 return (-1);
00396         return (read(fd, buf, len) == len ? 0 : -1);
00397 }
00398 
00399 static int
00400 _radix_walk(int fd, struct radix_node *rn, arp_handler callback, void *arg)
00401 {
00402         struct radix_node rnode;
00403         struct rtentry rt;
00404         struct sockaddr_in sin;
00405         struct arptab at;
00406         struct arp_entry entry;
00407         int ret = 0;
00408  again:
00409         _kread(fd, rn, &rnode, sizeof(rnode));
00410         if (rnode.rn_b < 0) {
00411                 if (!(rnode.rn_flags & RNF_ROOT)) {
00412                         _kread(fd, rn, &rt, sizeof(rt));
00413                         _kread(fd, rt_key(&rt), &sin, sizeof(sin));
00414                         addr_ston((struct sockaddr *)&sin, &entry.arp_pa);
00415                         _kread(fd, rt.rt_llinfo, &at, sizeof(at));
00416                         if (at.at_flags & ATF_COM) {
00417                                 addr_pack(&entry.arp_ha, ADDR_TYPE_ETH,
00418                                     ETH_ADDR_BITS, at.at_hwaddr, ETH_ADDR_LEN);
00419                                 if ((ret = callback(&entry, arg)) != 0)
00420                                         return (ret);
00421                         }
00422                 }
00423                 if ((rn = rnode.rn_dupedkey))
00424                         goto again;
00425         } else {
00426                 rn = rnode.rn_r;
00427                 if ((ret = _radix_walk(fd, rnode.rn_l, callback, arg)) != 0)
00428                         return (ret);
00429                 if ((ret = _radix_walk(fd, rn, callback, arg)) != 0)
00430                         return (ret);
00431         }
00432         return (ret);
00433 }
00434 
00435 int
00436 arp_loop(arp_t *r, arp_handler callback, void *arg)
00437 {
00438         struct ifnet *ifp, ifnet;
00439         struct ifnet_arp_cache_head ifarp;
00440         struct radix_node_head *head;
00441         
00442         struct nlist nl[2];
00443         int fd, ret = 0;
00444 
00445         memset(nl, 0, sizeof(nl));
00446         nl[0].n_name = "ifnet";
00447         
00448         if (knlist(nl) < 0 || nl[0].n_type == 0 ||
00449             (fd = open("/dev/kmem", O_RDONLY, 0)) < 0)
00450                 return (-1);
00451 
00452         for (ifp = (struct ifnet *)nl[0].n_value;
00453             ifp != NULL; ifp = ifnet.if_next) {
00454                 _kread(fd, ifp, &ifnet, sizeof(ifnet));
00455                 if (ifnet.if_arp_cache_head != NULL) {
00456                         _kread(fd, ifnet.if_arp_cache_head,
00457                             &ifarp, sizeof(ifarp));
00458                         /* XXX - only ever one rnh, only ever AF_INET. */
00459                         if ((ret = _radix_walk(fd, ifarp.arp_cache_head.rnh_treetop,
00460                                  callback, arg)) != 0)
00461                                 break;
00462                 }
00463         }
00464         close(fd);
00465         return (ret);
00466 }
00467 #else
00468 int
00469 arp_loop(arp_t *a, arp_handler callback, void *arg)
00470 {
00471         errno = ENOSYS;
00472         return (-1);
00473 }
00474 #endif
00475 
00476 arp_t *
00477 arp_close(arp_t *a)
00478 {
00479         if (a != NULL) {
00480                 if (a->fd >= 0)
00481                         close(a->fd);
00482 #ifdef HAVE_ARPREQ_ARP_DEV
00483                 if (a->intf != NULL)
00484                         intf_close(a->intf);
00485 #endif
00486                 free(a);
00487         }
00488         return (NULL);
00489 }

Generated on Sun May 14 14:51:11 2006 by  doxygen 1.4.2