Annotation of embedaddon/libpdel/net/if_arp.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/types.h>
42: #include <sys/param.h>
43: #include <sys/socket.h>
44: #include <sys/sysctl.h>
45: #include <sys/sockio.h>
46: #include <sys/ioctl.h>
47:
48: #include <net/if.h>
49: #include <net/if_dl.h>
50: #include <net/if_types.h>
51: #include <net/route.h>
52:
53: #include <netinet/in.h>
54: #include <netinet/if_ether.h>
55: #include <arpa/inet.h>
56:
57: #include <stdio.h>
58: #include <stdlib.h>
59: #include <stdarg.h>
60: #include <unistd.h>
61: #include <syslog.h>
62: #include <string.h>
63: #include <assert.h>
64: #include <errno.h>
65: #include <time.h>
66:
67: #include "structs/structs.h"
68: #include "structs/type/array.h"
69:
70: #include "net/if_util.h"
71: #include "util/typed_mem.h"
72:
73: #define ROUNDUP(a) \
74: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
75: #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
76:
77: #define ADDADDR(cp, s) \
78: do { \
79: memcpy(cp, &s, sizeof(s)); \
80: cp += ROUNDUP(sizeof(s)); \
81: } while (0)
82:
83: #define TEMP_EXPIRE (20 * 60)
84:
85: struct rt {
86: struct rt_msghdr m_rtm;
87: char m_space[512];
88: };
89:
90: /*
91: * Internal functions
92: */
93: static int arp_set(int sock, struct in_addr ip,
94: const u_char *ether, int temp, int publish);
95: static int arp_delete(int sock, struct in_addr ip);
96: static int arp_rtmsg(int sock, struct rt *rt, struct sockaddr_inarp *sin,
97: struct sockaddr_dl *sdl, int cmd, int flags,
98: int export_only, int doing_proxy, u_long expiry);
99:
100: /*
101: * Internal variables
102: */
103: static const struct sockaddr_in so_mask = { 8, 0, 0, { 0xffffffff} };
104: static const struct sockaddr_inarp zero_sin = { sizeof(zero_sin), AF_INET };
105: static const struct sockaddr_dl zero_sdl = { sizeof(zero_sdl), AF_LINK };
106:
107: /*
108: * Get an ARP entry.
109: */
110: int
111: if_get_arp(struct in_addr ip, u_char *ether)
112: {
113: int mib[6];
114: size_t needed;
115: char *lim, *buf, *next;
116: struct rt_msghdr *rtm;
117: struct sockaddr_inarp *sin;
118: struct sockaddr_dl *sdl;
119:
120: /* Get ARP table */
121: mib[0] = CTL_NET;
122: mib[1] = PF_ROUTE;
123: mib[2] = 0;
124: mib[3] = AF_INET;
125: mib[4] = NET_RT_FLAGS;
126: #ifdef RTF_LLINFO
127: mib[5] = RTF_LLINFO;
128: #else
129: mib[5] = 0;
130: #endif
131: if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
132: return (-1);
133: needed += 128;
134: if ((buf = MALLOC(TYPED_MEM_TEMP, needed)) == NULL)
135: return (-1);
136: if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
137: FREE(TYPED_MEM_TEMP, buf);
138: return (-1);
139: }
140:
141: /* Find desired entry */
142: lim = buf + needed;
143: for (next = buf; next < lim; next += rtm->rtm_msglen) {
144: rtm = (struct rt_msghdr *)(void *)next;
145: sin = (struct sockaddr_inarp *)(rtm + 1);
146: sdl = (struct sockaddr_dl *)(void *)
147: ((char *)sin + ROUNDUP(sin->sin_len));
148: if (sin->sin_addr.s_addr != ip.s_addr)
149: continue;
150: if (sdl->sdl_alen == 0)
151: break;
152: memcpy(ether, LLADDR(sdl), ETHER_ADDR_LEN);
153: FREE(TYPED_MEM_TEMP, buf);
154: return (0);
155: }
156:
157: /* Not found */
158: FREE(TYPED_MEM_TEMP, buf);
159: errno = ENOENT;
160: return (-1);
161: }
162:
163: /*
164: * Set or remove an ARP entry.
165: */
166: int
167: if_set_arp(struct in_addr ip, const u_char *ether, int temp, int publish)
168: {
169: int ret = -1;
170: int sock;
171:
172: /* Get socket */
173: if ((sock = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
174: return (-1);
175:
176: /* Delete any existing entries */
177: while ((ret = arp_delete(sock, ip)) != -1);
178: if (errno != ENOENT)
179: goto done;
180:
181: /* If not setting a new one, done */
182: if (ether == NULL) {
183: ret = 0;
184: goto done;
185: }
186:
187: /* Set a new one */
188: ret = arp_set(sock, ip, ether, temp, publish);
189:
190: done:
191: /* Done */
192: (void)close(sock);
193: return (ret);
194: }
195:
196: /*
197: * Set an individual arp entry
198: */
199: static int
200: arp_set(int sock, struct in_addr ip, const u_char *ether, int temp, int publish)
201: {
202: struct rt m_rtmsg;
203: struct sockaddr_inarp sin_m;
204: struct sockaddr_dl sdl_m;
205: struct sockaddr_inarp *sin = &sin_m;
206: struct rt_msghdr *const rtm = &m_rtmsg.m_rtm;
207: struct sockaddr_dl *sdl;
208: int doing_proxy;
209: int export_only;
210: int expiry;
211: int flags;
212:
213: sdl_m = zero_sdl;
214: sin_m = zero_sin;
215: sin->sin_addr = ip;
216: doing_proxy = flags = export_only = expiry = 0;
217: if (temp)
218: expiry = time(NULL) + TEMP_EXPIRE;
219: if (publish) {
220: flags |= RTF_ANNOUNCE;
221: doing_proxy = SIN_PROXY;
222: }
223: memcpy(LLADDR(&sdl_m), ether, ETHER_ADDR_LEN);
224: sdl_m.sdl_alen = 6;
225: tryagain:
226: if (arp_rtmsg(sock, &m_rtmsg, &sin_m, &sdl_m,
227: RTM_GET, flags, export_only, doing_proxy, expiry) < 0)
228: return (-1);
229: sin = (struct sockaddr_inarp *)(rtm + 1);
230: sdl = (struct sockaddr_dl *)(void *)
231: (ROUNDUP(sin->sin_len) + (char *)sin);
232: if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
233: if (sdl->sdl_family == AF_LINK &&
234: #ifdef RTF_LLINFO
235: (rtm->rtm_flags & RTF_LLINFO) != 0 &&
236: #endif
237: (rtm->rtm_flags & RTF_GATEWAY) == 0) {
238: switch (sdl->sdl_type) {
239: case IFT_ETHER:
240: case IFT_FDDI:
241: case IFT_ISO88023:
242: case IFT_ISO88024:
243: case IFT_ISO88025:
244: case IFT_L2VLAN:
245: goto overwrite;
246: default:
247: break;
248: }
249: }
250: if (doing_proxy == 0) {
251: errno = EINVAL;
252: return (-1);
253: }
254: if (sin_m.sin_other & SIN_PROXY) {
255: errno = EINVAL;
256: return (-1);
257: }
258: sin_m.sin_other = SIN_PROXY;
259: export_only = 1;
260: goto tryagain;
261: }
262: overwrite:
263: if (sdl->sdl_family != AF_LINK) {
264: errno = ENOENT;
265: return (-1);
266: }
267: sdl_m.sdl_type = sdl->sdl_type;
268: sdl_m.sdl_index = sdl->sdl_index;
269: return (arp_rtmsg(sock, &m_rtmsg, &sin_m, &sdl_m,
270: RTM_ADD, flags, export_only, doing_proxy, expiry));
271: }
272:
273: /*
274: * Delete an arp entry
275: */
276: static int
277: arp_delete(int sock, struct in_addr ip)
278: {
279: struct rt m_rtmsg;
280: struct sockaddr_inarp sin_m;
281: struct sockaddr_dl sdl_m;
282: struct sockaddr_inarp *sin = &sin_m;
283: struct rt_msghdr *const rtm = &m_rtmsg.m_rtm;
284: struct sockaddr_dl *sdl;
285:
286: sdl_m = zero_sdl;
287: sin_m = zero_sin;
288: sin->sin_addr = ip;
289: tryagain:
290: if (arp_rtmsg(sock, &m_rtmsg, &sin_m, &sdl_m, RTM_GET, 0, 0, 0, 0) < 0)
291: return (-1);
292: sin = (struct sockaddr_inarp *)(rtm + 1);
293: sdl = (struct sockaddr_dl *)(void *)
294: (ROUNDUP(sin->sin_len) + (char *)sin);
295: if (sdl->sdl_family == AF_LINK &&
296: #ifdef RTF_LLINFO
297: (rtm->rtm_flags & RTF_LLINFO) &&
298: #endif
299: !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
300: case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
301: case IFT_ISO88024: case IFT_ISO88025:
302: sin->sin_addr.s_addr = sin_m.sin_addr.s_addr;
303: goto delete;
304: }
305: if (sin_m.sin_other & SIN_PROXY) {
306: errno = ENOENT;
307: return (-1);
308: }
309: sin_m.sin_other = SIN_PROXY;
310: goto tryagain;
311: delete:
312: if (sdl->sdl_family != AF_LINK) {
313: errno = ENOENT;
314: return (-1);
315: }
316: if (arp_rtmsg(sock, &m_rtmsg, &sin_m, &sdl_m,
317: RTM_DELETE, 0, 0, 0, 0) == -1)
318: return (-1);
319: return (0);
320: }
321:
322: static int
323: arp_rtmsg(int sock, struct rt *rt, struct sockaddr_inarp *sin,
324: struct sockaddr_dl *sdl, int cmd, int flags,
325: int export_only, int doing_proxy, u_long expiry)
326: {
327: struct rt_msghdr *const rtm = &rt->m_rtm;
328: const pid_t pid = getpid();
329: u_char *cp = (u_char *)rt->m_space;
330: static int seq;
331: int l;
332: int rlen;
333:
334: if (cmd == RTM_DELETE)
335: goto doit;
336: memset(rtm, 0, sizeof(*rtm));
337: rtm->rtm_flags = flags;
338: rtm->rtm_version = RTM_VERSION;
339:
340: switch (cmd) {
341: case RTM_ADD:
342: rtm->rtm_addrs |= RTA_GATEWAY;
343: rtm->rtm_rmx.rmx_expire = expiry;
344: rtm->rtm_inits = RTV_EXPIRE;
345: rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
346: sin->sin_other = 0;
347: if (doing_proxy) {
348: if (export_only)
349: sin->sin_other = SIN_PROXY;
350: else {
351: rtm->rtm_addrs |= RTA_NETMASK;
352: rtm->rtm_flags &= ~RTF_HOST;
353: }
354: }
355: /* FALLTHROUGH */
356: case RTM_GET:
357: rtm->rtm_addrs |= RTA_DST;
358: break;
359: default:
360: assert(0);
361: }
362: #define NEXTADDR(w, s) \
363: if (rtm->rtm_addrs & (w)) { \
364: memcpy(cp, s, sizeof(*s)); cp += ROUNDUP(sizeof(*s));}
365:
366: NEXTADDR(RTA_DST, sin);
367: NEXTADDR(RTA_GATEWAY, sdl);
368: NEXTADDR(RTA_NETMASK, &so_mask);
369:
370: rtm->rtm_msglen = cp - (u_char *)rtm;
371: doit:
372: l = rtm->rtm_msglen;
373: rtm->rtm_seq = ++seq;
374: rtm->rtm_type = cmd;
375: if ((rlen = write(sock, (char *)rt, l)) < 0) {
376: if (errno != ESRCH || cmd != RTM_DELETE)
377: return (-1);
378: }
379: do {
380: l = read(sock, (char *)rt, sizeof(*rt));
381: } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
382: if (l < 0)
383: return (-1);
384: return (0);
385: }
386:
387: /*
388: * Flush all ARP entries.
389: */
390: int
391: if_flush_arp(void)
392: {
393: int errno_save = errno;
394: int mib[6];
395: size_t needed;
396: char *lim, *buf, *next;
397: struct rt_msghdr *rtm;
398: struct sockaddr_inarp *sin;
399: struct sockaddr_dl *sdl;
400: int sock, rtn = -1;
401:
402: /* Get socket */
403: if ((sock = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
404: return (-1);
405:
406: /* Get ARP table */
407: mib[0] = CTL_NET;
408: mib[1] = PF_ROUTE;
409: mib[2] = 0;
410: mib[3] = AF_INET;
411: mib[4] = NET_RT_FLAGS;
412: #ifdef RTF_LLINFO
413: mib[5] = RTF_LLINFO;
414: #else
415: mib[5] = 0;
416: #endif
417: if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
418: goto done;
419: needed += 128;
420: if ((buf = MALLOC(TYPED_MEM_TEMP, needed)) == NULL)
421: goto done;
422: if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
423: goto done2;
424: }
425:
426: /* Find desired entry */
427: lim = buf + needed;
428: for (next = buf; next < lim; next += rtm->rtm_msglen) {
429: rtm = (struct rt_msghdr *)(void *)next;
430: sin = (struct sockaddr_inarp *)(rtm + 1);
431: sdl = (struct sockaddr_dl *)(void *)
432: ((char *)sin + ROUNDUP(sin->sin_len));
433: if (sdl->sdl_alen == 0)
434: break;
435: arp_delete(sock, sin->sin_addr);
436: }
437:
438: rtn = 0;
439: done2:
440: FREE(TYPED_MEM_TEMP, buf);
441: done:
442: (void)close(sock);
443: errno = errno_save;
444: return (rtn);
445: }
446:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>