00001
00002
00003
00004
00005
00006
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
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
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 }