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

arp-bsd.c

Go to the documentation of this file.
00001 /*
00002  * arp-bsd.c
00003  * 
00004  * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
00005  *
00006  * $Id: arp-bsd.c,v 1.14 2005/01/23 07:36:54 dugsong Exp $
00007  */
00008 
00009 #include "config.h"
00010 
00011 #include <sys/param.h>
00012 #include <sys/types.h>
00013 #include <sys/socket.h>
00014 #ifdef HAVE_SYS_SYSCTL_H
00015 #include <sys/sysctl.h>
00016 #endif
00017 #ifdef HAVE_STREAMS_ROUTE
00018 #include <sys/stream.h>
00019 #include <sys/stropts.h>
00020 #endif
00021 
00022 #include <net/if.h>
00023 #include <net/if_dl.h>
00024 #include <net/route.h>
00025 #include <netinet/in.h>
00026 #include <netinet/if_ether.h>
00027 
00028 #include <assert.h>
00029 #include <errno.h>
00030 #include <fcntl.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <unistd.h>
00035 
00036 #include "dnet.h"
00037 
00038 struct arp_handle {
00039         int     fd;
00040         int     seq;
00041 };
00042 
00043 struct arpmsg {
00044         struct rt_msghdr        rtm;
00045         u_char                  addrs[256];
00046 };
00047 
00048 arp_t *
00049 arp_open(void)
00050 {
00051         arp_t *arp;
00052 
00053         if ((arp = calloc(1, sizeof(*arp))) != NULL) {
00054 #ifdef HAVE_STREAMS_ROUTE
00055                 if ((arp->fd = open("/dev/route", O_RDWR, 0)) < 0)
00056 #else
00057                 if ((arp->fd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0)
00058 #endif
00059                         return (arp_close(arp));
00060         }
00061         return (arp);
00062 }
00063 
00064 static int
00065 arp_msg(arp_t *arp, struct arpmsg *msg)
00066 {
00067         struct arpmsg smsg;
00068         int len, i = 0;
00069         pid_t pid;
00070         
00071         msg->rtm.rtm_version = RTM_VERSION;
00072         msg->rtm.rtm_seq = ++arp->seq; 
00073         memcpy(&smsg, msg, sizeof(smsg));
00074         
00075 #ifdef HAVE_STREAMS_ROUTE
00076         return (ioctl(arp->fd, RTSTR_SEND, &msg->rtm));
00077 #else
00078         if (write(arp->fd, &smsg, smsg.rtm.rtm_msglen) < 0) {
00079                 if (errno != ESRCH || msg->rtm.rtm_type != RTM_DELETE)
00080                         return (-1);
00081         }
00082         pid = getpid();
00083         
00084         /* XXX - should we only read RTM_GET responses here? */
00085         while ((len = read(arp->fd, msg, sizeof(*msg))) > 0) {
00086                 if (len < (int)sizeof(msg->rtm))
00087                         return (-1);
00088 
00089                 if (msg->rtm.rtm_pid == pid) {
00090                         if (msg->rtm.rtm_seq == arp->seq)
00091                                 break;
00092                         continue;
00093                 } else if ((i++ % 2) == 0)
00094                         continue;
00095                 
00096                 /* Repeat request. */
00097                 if (write(arp->fd, &smsg, smsg.rtm.rtm_msglen) < 0) {
00098                         if (errno != ESRCH || msg->rtm.rtm_type != RTM_DELETE)
00099                                 return (-1);
00100                 }
00101         }
00102         if (len < 0)
00103                 return (-1);
00104         
00105         return (0);
00106 #endif
00107 }
00108 
00109 int
00110 arp_add(arp_t *arp, const struct arp_entry *entry)
00111 {
00112         struct arpmsg msg;
00113         struct sockaddr_in *sin;
00114         struct sockaddr *sa;
00115         int index, type;
00116         
00117         if (entry->arp_pa.addr_type != ADDR_TYPE_IP ||
00118             entry->arp_ha.addr_type != ADDR_TYPE_ETH) {
00119                 errno = EAFNOSUPPORT;
00120                 return (-1);
00121         }
00122         sin = (struct sockaddr_in *)msg.addrs;
00123         sa = (struct sockaddr *)(sin + 1);
00124         
00125         if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0)
00126                 return (-1);
00127         
00128         memset(&msg.rtm, 0, sizeof(msg.rtm));
00129         msg.rtm.rtm_type = RTM_GET;
00130         msg.rtm.rtm_addrs = RTA_DST;
00131         msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin);
00132         
00133         if (arp_msg(arp, &msg) < 0)
00134                 return (-1);
00135         
00136         if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) +
00137             sizeof(*sin) + sizeof(*sa)) {
00138                 errno = EADDRNOTAVAIL;
00139                 return (-1);
00140         }
00141         if (sin->sin_addr.s_addr == entry->arp_pa.addr_ip) {
00142                 if ((msg.rtm.rtm_flags & RTF_LLINFO) == 0 ||
00143                     (msg.rtm.rtm_flags & RTF_GATEWAY) != 0) {
00144                         errno = EADDRINUSE;
00145                         return (-1);
00146                 }
00147         }
00148         if (sa->sa_family != AF_LINK) {
00149                 errno = EADDRNOTAVAIL;
00150                 return (-1);
00151         } else {
00152                 index = ((struct sockaddr_dl *)sa)->sdl_index;
00153                 type = ((struct sockaddr_dl *)sa)->sdl_type;
00154         }
00155         if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0 ||
00156             addr_ntos(&entry->arp_ha, sa) < 0)
00157                 return (-1);
00158 
00159         ((struct sockaddr_dl *)sa)->sdl_index = index;
00160         ((struct sockaddr_dl *)sa)->sdl_type = type;
00161         
00162         memset(&msg.rtm, 0, sizeof(msg.rtm));
00163         msg.rtm.rtm_type = RTM_ADD;
00164         msg.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
00165         msg.rtm.rtm_inits = RTV_EXPIRE;
00166         msg.rtm.rtm_flags = RTF_HOST | RTF_STATIC;
00167 #ifdef HAVE_SOCKADDR_SA_LEN
00168         msg.rtm.rtm_msglen = sizeof(msg.rtm) + sin->sin_len + sa->sa_len;
00169 #else
00170         msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin) + sizeof(*sa);
00171 #endif
00172         return (arp_msg(arp, &msg));
00173 }
00174 
00175 int
00176 arp_delete(arp_t *arp, const struct arp_entry *entry)
00177 {
00178         struct arpmsg msg;
00179         struct sockaddr_in *sin;
00180         struct sockaddr *sa;
00181 
00182         if (entry->arp_pa.addr_type != ADDR_TYPE_IP) {
00183                 errno = EAFNOSUPPORT;
00184                 return (-1);
00185         }
00186         sin = (struct sockaddr_in *)msg.addrs;
00187         sa = (struct sockaddr *)(sin + 1);
00188 
00189         if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0)
00190                 return (-1);
00191 
00192         memset(&msg.rtm, 0, sizeof(msg.rtm));
00193         msg.rtm.rtm_type = RTM_GET;
00194         msg.rtm.rtm_addrs = RTA_DST;
00195         msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin);
00196         
00197         if (arp_msg(arp, &msg) < 0)
00198                 return (-1);
00199         
00200         if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) +
00201             sizeof(*sin) + sizeof(*sa)) {
00202                 errno = ESRCH;
00203                 return (-1);
00204         }
00205         if (sin->sin_addr.s_addr == entry->arp_pa.addr_ip) {
00206                 if ((msg.rtm.rtm_flags & RTF_LLINFO) == 0 ||
00207                     (msg.rtm.rtm_flags & RTF_GATEWAY) != 0) {
00208                         errno = EADDRINUSE;
00209                         return (-1);
00210                 }
00211         }
00212         if (sa->sa_family != AF_LINK) {
00213                 errno = ESRCH;
00214                 return (-1);
00215         }
00216         msg.rtm.rtm_type = RTM_DELETE;
00217         
00218         return (arp_msg(arp, &msg));
00219 }
00220 
00221 int
00222 arp_get(arp_t *arp, struct arp_entry *entry)
00223 {
00224         struct arpmsg msg;
00225         struct sockaddr_in *sin;
00226         struct sockaddr *sa;
00227         
00228         if (entry->arp_pa.addr_type != ADDR_TYPE_IP) {
00229                 errno = EAFNOSUPPORT;
00230                 return (-1);
00231         }
00232         sin = (struct sockaddr_in *)msg.addrs;
00233         sa = (struct sockaddr *)(sin + 1);
00234         
00235         if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0)
00236                 return (-1);
00237         
00238         memset(&msg.rtm, 0, sizeof(msg.rtm));
00239         msg.rtm.rtm_type = RTM_GET;
00240         msg.rtm.rtm_addrs = RTA_DST;
00241         msg.rtm.rtm_flags = RTF_LLINFO;
00242         msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin);
00243         
00244         if (arp_msg(arp, &msg) < 0)
00245                 return (-1);
00246         
00247         if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) +
00248             sizeof(*sin) + sizeof(*sa) ||
00249             sin->sin_addr.s_addr != entry->arp_pa.addr_ip ||
00250             sa->sa_family != AF_LINK) {
00251                 errno = ESRCH;
00252                 return (-1);
00253         }
00254         if (addr_ston(sa, &entry->arp_ha) < 0)
00255                 return (-1);
00256         
00257         return (0);
00258 }
00259 
00260 #ifdef HAVE_SYS_SYSCTL_H
00261 int
00262 arp_loop(arp_t *arp, arp_handler callback, void *arg)
00263 {
00264         struct arp_entry entry;
00265         struct rt_msghdr *rtm;
00266         struct sockaddr_in *sin;
00267         struct sockaddr *sa;
00268         char *buf, *lim, *next;
00269         size_t len;
00270         int ret, mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET,
00271                             NET_RT_FLAGS, RTF_LLINFO };
00272 
00273         if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
00274                 return (-1);
00275 
00276         if (len == 0)
00277                 return (0);
00278 
00279         if ((buf = malloc(len)) == NULL)
00280                 return (-1);
00281         
00282         if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
00283                 free(buf);
00284                 return (-1);
00285         }
00286         lim = buf + len;
00287         ret = 0;
00288         
00289         for (next = buf; next < lim; next += rtm->rtm_msglen) {
00290                 rtm = (struct rt_msghdr *)next;
00291                 sin = (struct sockaddr_in *)(rtm + 1);
00292                 sa = (struct sockaddr *)(sin + 1);
00293                 
00294                 if (addr_ston((struct sockaddr *)sin, &entry.arp_pa) < 0 ||
00295                     addr_ston(sa, &entry.arp_ha) < 0)
00296                         continue;
00297                 
00298                 if ((ret = callback(&entry, arg)) != 0)
00299                         break;
00300         }
00301         free(buf);
00302         
00303         return (ret);
00304 }
00305 #else
00306 int
00307 arp_loop(arp_t *arp, arp_handler callback, void *arg)
00308 {
00309         errno = ENOSYS;
00310         return (-1);
00311 }
00312 #endif
00313 
00314 arp_t *
00315 arp_close(arp_t *arp)
00316 {
00317         if (arp != NULL) {
00318                 if (arp->fd >= 0)
00319                         close(arp->fd);
00320                 free(arp);
00321         }
00322         return (NULL);
00323 }

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