]>
Commit | Line | Data |
---|---|---|
fdfd5971 A |
1 | /* |
2 | * Copyright (c) 2003-2011 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
b7080c8e A |
29 | /* |
30 | * Copyright (c) 1984, 1993 | |
31 | * The Regents of the University of California. All rights reserved. | |
32 | * | |
33 | * This code is derived from software contributed to Berkeley by | |
34 | * Sun Microsystems, Inc. | |
35 | * | |
36 | * Redistribution and use in source and binary forms, with or without | |
37 | * modification, are permitted provided that the following conditions | |
38 | * are met: | |
39 | * 1. Redistributions of source code must retain the above copyright | |
40 | * notice, this list of conditions and the following disclaimer. | |
41 | * 2. Redistributions in binary form must reproduce the above copyright | |
42 | * notice, this list of conditions and the following disclaimer in the | |
43 | * documentation and/or other materials provided with the distribution. | |
b7080c8e A |
44 | * 4. Neither the name of the University nor the names of its contributors |
45 | * may be used to endorse or promote products derived from this software | |
46 | * without specific prior written permission. | |
47 | * | |
48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
58 | * SUCH DAMAGE. | |
59 | */ | |
60 | ||
9c859447 | 61 | #if 0 |
b7080c8e | 62 | #ifndef lint |
ac2f15b3 | 63 | static char const copyright[] = |
b7080c8e A |
64 | "@(#) Copyright (c) 1984, 1993\n\ |
65 | The Regents of the University of California. All rights reserved.\n"; | |
66 | #endif /* not lint */ | |
67 | ||
68 | #ifndef lint | |
ac2f15b3 | 69 | static char const sccsid[] = "@(#)from: arp.c 8.2 (Berkeley) 1/2/94"; |
b7080c8e | 70 | #endif /* not lint */ |
9c859447 A |
71 | #include <sys/cdefs.h> |
72 | __FBSDID("$FreeBSD: src/usr.sbin/arp/arp.c,v 1.65.2.1 2008/04/25 16:38:14 sam Exp $"); | |
73 | #endif | |
b7080c8e A |
74 | |
75 | /* | |
76 | * arp - display, set, and delete arp table entries | |
77 | */ | |
78 | ||
79 | ||
80 | #include <sys/param.h> | |
81 | #include <sys/file.h> | |
82 | #include <sys/socket.h> | |
ac2f15b3 | 83 | #include <sys/sockio.h> |
b7080c8e | 84 | #include <sys/sysctl.h> |
ac2f15b3 A |
85 | #include <sys/ioctl.h> |
86 | #include <sys/time.h> | |
b7080c8e A |
87 | |
88 | #include <net/if.h> | |
89 | #include <net/if_dl.h> | |
90 | #include <net/if_types.h> | |
91 | #include <net/route.h> | |
9c859447 A |
92 | #if 0 |
93 | #include <net/iso88025.h> | |
94 | #endif | |
b7080c8e A |
95 | |
96 | #include <netinet/in.h> | |
97 | #include <netinet/if_ether.h> | |
98 | ||
99 | #include <arpa/inet.h> | |
100 | ||
9c859447 | 101 | #include <ctype.h> |
b7080c8e A |
102 | #include <err.h> |
103 | #include <errno.h> | |
104 | #include <netdb.h> | |
105 | #include <nlist.h> | |
106 | #include <paths.h> | |
107 | #include <stdio.h> | |
108 | #include <stdlib.h> | |
9c859447 | 109 | #include <string.h> |
ac2f15b3 | 110 | #include <strings.h> |
b7080c8e A |
111 | #include <unistd.h> |
112 | ||
9c859447 A |
113 | typedef void (action_fn)(struct sockaddr_dl *sdl, |
114 | struct sockaddr_inarp *s_in, struct rt_msghdr *rtm); | |
fdfd5971 A |
115 | typedef void (action_ext_fn)(struct sockaddr_dl *sdl, |
116 | struct sockaddr_inarp *s_in, struct rt_msghdr_ext *rtm); | |
9c859447 A |
117 | |
118 | static int search(in_addr_t addr, action_fn *action); | |
fdfd5971 | 119 | static int search_ext(in_addr_t addr, action_ext_fn *action); |
9c859447 A |
120 | static action_fn print_entry; |
121 | static action_fn nuke_entry; | |
fdfd5971 | 122 | static action_ext_fn print_entry_ext; |
9c859447 | 123 | |
fdfd5971 | 124 | static char *print_lladdr(struct sockaddr_dl *); |
9c859447 A |
125 | static int delete(char *host, int do_proxy); |
126 | static void usage(void); | |
127 | static int set(int argc, char **argv); | |
128 | static int get(char *host); | |
129 | static int file(char *name); | |
130 | static struct rt_msghdr *rtmsg(int cmd, | |
131 | struct sockaddr_inarp *dst, struct sockaddr_dl *sdl); | |
132 | static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr); | |
133 | static struct sockaddr_inarp *getaddr(char *host); | |
134 | static int valid_type(int type); | |
fdfd5971 | 135 | static char *sec2str(time_t); |
9c859447 | 136 | |
ac2f15b3 | 137 | static int nflag; /* no reverse dns lookups */ |
9c859447 A |
138 | static char *rifname; |
139 | ||
140 | static int expire_time, flags, doing_proxy, proxy_only; | |
141 | ||
142 | static char *boundif = NULL; | |
143 | static unsigned int ifscope = 0; | |
ac2f15b3 A |
144 | |
145 | /* which function we're supposed to do */ | |
146 | #define F_GET 1 | |
147 | #define F_SET 2 | |
148 | #define F_FILESET 3 | |
149 | #define F_REPLACE 4 | |
150 | #define F_DELETE 5 | |
151 | ||
9c859447 A |
152 | #ifndef SA_SIZE |
153 | #define SA_SIZE(sa) \ | |
154 | ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ | |
155 | sizeof(uint32_t) : \ | |
156 | 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) ) | |
157 | #endif | |
158 | ||
ac2f15b3 | 159 | #define SETFUNC(f) { if (func) usage(); func = (f); } |
b7080c8e | 160 | |
9c859447 | 161 | |
b7080c8e | 162 | int |
ac2f15b3 | 163 | main(int argc, char *argv[]) |
b7080c8e | 164 | { |
ac2f15b3 A |
165 | int ch, func = 0; |
166 | int rtn = 0; | |
9c859447 | 167 | int aflag = 0; /* do it for all entries */ |
fdfd5971 A |
168 | int lflag = 0; |
169 | uint32_t ifindex = 0; | |
b7080c8e | 170 | |
fdfd5971 | 171 | while ((ch = getopt(argc, argv, "andflsSi:")) != -1) |
b7080c8e A |
172 | switch((char)ch) { |
173 | case 'a': | |
8052502f A |
174 | aflag = 1; |
175 | break; | |
b7080c8e | 176 | case 'd': |
ac2f15b3 A |
177 | SETFUNC(F_DELETE); |
178 | break; | |
b7080c8e A |
179 | case 'n': |
180 | nflag = 1; | |
8052502f | 181 | break; |
fdfd5971 A |
182 | case 'l': |
183 | lflag = 1; | |
184 | break; | |
ac2f15b3 A |
185 | case 'S': |
186 | SETFUNC(F_REPLACE); | |
187 | break; | |
b7080c8e | 188 | case 's': |
ac2f15b3 A |
189 | SETFUNC(F_SET); |
190 | break; | |
191 | case 'f' : | |
192 | SETFUNC(F_FILESET); | |
193 | break; | |
9c859447 A |
194 | case 'i': |
195 | rifname = optarg; | |
196 | break; | |
b7080c8e A |
197 | case '?': |
198 | default: | |
199 | usage(); | |
200 | } | |
ac2f15b3 A |
201 | argc -= optind; |
202 | argv += optind; | |
203 | ||
ac2f15b3 A |
204 | if (!func) |
205 | func = F_GET; | |
9c859447 A |
206 | if (rifname) { |
207 | if (func != F_GET && !(func == F_DELETE && aflag)) | |
208 | errx(1, "-i not applicable to this operation"); | |
fdfd5971 | 209 | if ((ifindex = if_nametoindex(rifname)) == 0) { |
9c859447 A |
210 | if (errno == ENXIO) |
211 | errx(1, "interface %s does not exist", rifname); | |
212 | else | |
213 | err(1, "if_nametoindex(%s)", rifname); | |
214 | } | |
215 | } | |
ac2f15b3 A |
216 | switch (func) { |
217 | case F_GET: | |
218 | if (aflag) { | |
219 | if (argc != 0) | |
220 | usage(); | |
fdfd5971 A |
221 | if (lflag) { |
222 | printf("%-23s %-17s %-9.9s %-9.9s %8.8s %4s " | |
223 | "%4s\n", "Neighbor", "Linklayer Address", | |
224 | "Expire(O)", "Expire(I)", "Netif", "Refs", | |
225 | "Prbs"); | |
226 | search_ext(0, print_entry_ext); | |
227 | } else { | |
228 | search(0, print_entry); | |
229 | } | |
ac2f15b3 A |
230 | } else { |
231 | if (argc != 1) | |
232 | usage(); | |
9c859447 | 233 | rtn = get(argv[0]); |
ac2f15b3 A |
234 | } |
235 | break; | |
236 | case F_SET: | |
237 | case F_REPLACE: | |
238 | if (argc < 2 || argc > 6) | |
239 | usage(); | |
240 | if (func == F_REPLACE) | |
9c859447 | 241 | (void)delete(argv[0], 0); |
ac2f15b3 A |
242 | rtn = set(argc, argv) ? 1 : 0; |
243 | break; | |
244 | case F_DELETE: | |
245 | if (aflag) { | |
246 | if (argc != 0) | |
247 | usage(); | |
248 | search(0, nuke_entry); | |
249 | } else { | |
9c859447 A |
250 | int do_proxy = 0; |
251 | int i; | |
252 | ||
253 | for (i = 1; i < argc; i++) { | |
254 | if (strncmp(argv[i], "pub", sizeof("pub")) == 0) { | |
255 | do_proxy = SIN_PROXY; | |
256 | } else if (strncmp(argv[i], "ifscope", sizeof("ifscope")) == 0) { | |
257 | if (i + 1 >= argc) { | |
258 | printf("ifscope needs an interface parameter\n"); | |
259 | return (1); | |
260 | } | |
261 | boundif = argv[++i]; | |
262 | if ((ifscope = if_nametoindex(boundif)) == 0) | |
263 | errx(1, "ifscope has bad interface name: %s", boundif); | |
264 | } else { | |
265 | usage(); | |
266 | } | |
267 | } | |
fdfd5971 A |
268 | if (i > argc) |
269 | usage(); | |
9c859447 | 270 | rtn = delete(argv[0], do_proxy); |
ac2f15b3 A |
271 | } |
272 | break; | |
273 | case F_FILESET: | |
274 | if (argc != 1) | |
275 | usage(); | |
276 | rtn = file(argv[0]); | |
277 | break; | |
8052502f | 278 | } |
ac2f15b3 | 279 | |
9c859447 | 280 | return (rtn); |
b7080c8e A |
281 | } |
282 | ||
283 | /* | |
284 | * Process a file to set standard arp entries | |
285 | */ | |
9c859447 | 286 | static int |
ac2f15b3 | 287 | file(char *name) |
b7080c8e A |
288 | { |
289 | FILE *fp; | |
290 | int i, retval; | |
9c859447 | 291 | char line[128], arg[7][50], *args[7], *p; |
b7080c8e | 292 | |
ac2f15b3 | 293 | if ((fp = fopen(name, "r")) == NULL) |
9c859447 | 294 | err(1, "cannot open %s", name); |
b7080c8e A |
295 | args[0] = &arg[0][0]; |
296 | args[1] = &arg[1][0]; | |
297 | args[2] = &arg[2][0]; | |
298 | args[3] = &arg[3][0]; | |
299 | args[4] = &arg[4][0]; | |
9c859447 A |
300 | args[5] = &arg[5][0]; |
301 | args[6] = &arg[6][0]; | |
b7080c8e | 302 | retval = 0; |
9c859447 A |
303 | while(fgets(line, sizeof(line), fp) != NULL) { |
304 | if ((p = strchr(line, '#')) != NULL) | |
305 | *p = '\0'; | |
306 | for (p = line; isblank(*p); p++); | |
307 | if (*p == '\n' || *p == '\0') | |
308 | continue; | |
309 | i = sscanf(p, "%49s %49s %49s %49s %49s %49s %49s", arg[0], arg[1], | |
310 | arg[2], arg[3], arg[4], arg[5], arg[6]); | |
b7080c8e | 311 | if (i < 2) { |
ac2f15b3 | 312 | warnx("bad line: %s", line); |
b7080c8e A |
313 | retval = 1; |
314 | continue; | |
315 | } | |
316 | if (set(i, args)) | |
317 | retval = 1; | |
318 | } | |
319 | fclose(fp); | |
320 | return (retval); | |
321 | } | |
322 | ||
9c859447 A |
323 | /* |
324 | * Given a hostname, fills up a (static) struct sockaddr_inarp with | |
325 | * the address of the host and returns a pointer to the | |
326 | * structure. | |
327 | */ | |
328 | static struct sockaddr_inarp * | |
329 | getaddr(char *host) | |
ac2f15b3 | 330 | { |
9c859447 A |
331 | struct hostent *hp; |
332 | static struct sockaddr_inarp reply; | |
333 | ||
334 | bzero(&reply, sizeof(reply)); | |
335 | reply.sin_len = sizeof(reply); | |
336 | reply.sin_family = AF_INET; | |
337 | reply.sin_addr.s_addr = inet_addr(host); | |
338 | if (reply.sin_addr.s_addr == INADDR_NONE) { | |
339 | if (!(hp = gethostbyname(host))) { | |
340 | warnx("%s: %s", host, hstrerror(h_errno)); | |
341 | return (NULL); | |
342 | } | |
343 | bcopy((char *)hp->h_addr, (char *)&reply.sin_addr, | |
344 | sizeof reply.sin_addr); | |
345 | } | |
346 | return (&reply); | |
347 | } | |
348 | ||
349 | /* | |
350 | * Returns true if the type is a valid one for ARP. | |
351 | */ | |
352 | static int | |
353 | valid_type(int type) | |
354 | { | |
355 | ||
356 | switch (type) { | |
357 | case IFT_ETHER: | |
358 | case IFT_FDDI: | |
359 | case IFT_ISO88023: | |
360 | case IFT_ISO88024: | |
361 | #if 0 | |
362 | case IFT_ISO88025: | |
363 | #endif | |
364 | case IFT_L2VLAN: | |
365 | #ifdef IFT_BRIDGE | |
366 | case IFT_BRIDGE: | |
367 | #endif | |
368 | return (1); | |
369 | default: | |
370 | return (0); | |
b7080c8e A |
371 | } |
372 | } | |
373 | ||
b7080c8e | 374 | /* |
ac2f15b3 | 375 | * Set an individual arp entry |
b7080c8e | 376 | */ |
9c859447 | 377 | static int |
ac2f15b3 | 378 | set(int argc, char **argv) |
b7080c8e | 379 | { |
9c859447 A |
380 | struct sockaddr_inarp *addr; |
381 | struct sockaddr_inarp *dst; /* what are we looking for */ | |
382 | struct sockaddr_dl *sdl; | |
383 | struct rt_msghdr *rtm; | |
ac2f15b3 | 384 | struct ether_addr *ea; |
b7080c8e | 385 | char *host = argv[0], *eaddr = argv[1]; |
9c859447 | 386 | struct sockaddr_dl sdl_m; |
b7080c8e | 387 | |
b7080c8e A |
388 | argc -= 2; |
389 | argv += 2; | |
9c859447 A |
390 | |
391 | bzero(&sdl_m, sizeof(sdl_m)); | |
392 | sdl_m.sdl_len = sizeof(sdl_m); | |
393 | sdl_m.sdl_family = AF_LINK; | |
394 | ||
395 | dst = getaddr(host); | |
396 | if (dst == NULL) | |
397 | return (1); | |
ac2f15b3 | 398 | doing_proxy = flags = proxy_only = expire_time = 0; |
9c859447 A |
399 | boundif = NULL; |
400 | ifscope = 0; | |
b7080c8e | 401 | while (argc-- > 0) { |
9c859447 | 402 | if (strncmp(argv[0], "temp", sizeof("temp")) == 0) { |
ac2f15b3 A |
403 | struct timeval tv; |
404 | gettimeofday(&tv, 0); | |
405 | expire_time = tv.tv_sec + 20 * 60; | |
9c859447 | 406 | } else if (strncmp(argv[0], "pub", sizeof("pub")) == 0) { |
b7080c8e | 407 | flags |= RTF_ANNOUNCE; |
ac2f15b3 | 408 | doing_proxy = 1; |
9c859447 | 409 | if (argc && strncmp(argv[1], "only", sizeof("only")) == 0) { |
ac2f15b3 | 410 | proxy_only = 1; |
9c859447 | 411 | dst->sin_other = SIN_PROXY; |
ac2f15b3 A |
412 | argc--; argv++; |
413 | } | |
9c859447 A |
414 | } else if (strncmp(argv[0], "blackhole", sizeof("blackhole")) == 0) { |
415 | flags |= RTF_BLACKHOLE; | |
416 | } else if (strncmp(argv[0], "reject", sizeof("reject")) == 0) { | |
417 | flags |= RTF_REJECT; | |
418 | } else if (strncmp(argv[0], "trail", sizeof("trail")) == 0) { | |
419 | /* XXX deprecated and undocumented feature */ | |
b7080c8e A |
420 | printf("%s: Sending trailers is no longer supported\n", |
421 | host); | |
9c859447 A |
422 | } else if (strncmp(argv[0], "ifscope", sizeof("ifscope")) == 0) { |
423 | if (argc < 1) { | |
424 | printf("ifscope needs an interface parameter\n"); | |
425 | return (1); | |
426 | } | |
427 | boundif = argv[1]; | |
428 | if ((ifscope = if_nametoindex(boundif)) == 0) | |
429 | errx(1, "ifscope has bad interface name: %s", boundif); | |
430 | argc--; argv++; | |
b7080c8e A |
431 | } |
432 | argv++; | |
433 | } | |
ac2f15b3 A |
434 | ea = (struct ether_addr *)LLADDR(&sdl_m); |
435 | if (doing_proxy && !strcmp(eaddr, "auto")) { | |
9c859447 | 436 | if (!get_ether_addr(dst->sin_addr.s_addr, ea)) { |
ac2f15b3 | 437 | printf("no interface found for %s\n", |
9c859447 | 438 | inet_ntoa(dst->sin_addr)); |
ac2f15b3 A |
439 | return (1); |
440 | } | |
441 | sdl_m.sdl_alen = ETHER_ADDR_LEN; | |
442 | } else { | |
9c859447 A |
443 | struct ether_addr *ea1 = ether_aton(eaddr); |
444 | ||
445 | if (ea1 == NULL) { | |
446 | warnx("invalid Ethernet address '%s'", eaddr); | |
447 | return (1); | |
448 | } else { | |
449 | *ea = *ea1; | |
ac2f15b3 | 450 | sdl_m.sdl_alen = ETHER_ADDR_LEN; |
9c859447 | 451 | } |
ac2f15b3 | 452 | } |
9c859447 A |
453 | for (;;) { /* try at most twice */ |
454 | rtm = rtmsg(RTM_GET, dst, &sdl_m); | |
455 | if (rtm == NULL) { | |
456 | warn("%s", host); | |
457 | return (1); | |
458 | } | |
459 | addr = (struct sockaddr_inarp *)(rtm + 1); | |
460 | sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr); | |
461 | if (addr->sin_addr.s_addr != dst->sin_addr.s_addr) | |
462 | break; | |
b7080c8e A |
463 | if (sdl->sdl_family == AF_LINK && |
464 | (rtm->rtm_flags & RTF_LLINFO) && | |
9c859447 A |
465 | !(rtm->rtm_flags & RTF_GATEWAY) && |
466 | valid_type(sdl->sdl_type) ) | |
467 | break; | |
468 | /* | |
469 | * If we asked for a scope entry and did not get one or | |
470 | * did not asked for a scope entry and got one, we can | |
471 | * proceed. | |
472 | */ | |
473 | if ((ifscope != 0) != (rtm->rtm_flags & RTF_IFSCOPE)) | |
474 | break; | |
b7080c8e A |
475 | if (doing_proxy == 0) { |
476 | printf("set: can only proxy for %s\n", host); | |
477 | return (1); | |
478 | } | |
9c859447 | 479 | if (dst->sin_other & SIN_PROXY) { |
b7080c8e | 480 | printf("set: proxy entry exists for non 802 device\n"); |
9c859447 | 481 | return (1); |
b7080c8e | 482 | } |
9c859447 | 483 | dst->sin_other = SIN_PROXY; |
ac2f15b3 | 484 | proxy_only = 1; |
b7080c8e | 485 | } |
9c859447 | 486 | |
b7080c8e A |
487 | if (sdl->sdl_family != AF_LINK) { |
488 | printf("cannot intuit interface index and type for %s\n", host); | |
489 | return (1); | |
490 | } | |
491 | sdl_m.sdl_type = sdl->sdl_type; | |
492 | sdl_m.sdl_index = sdl->sdl_index; | |
9c859447 | 493 | return (rtmsg(RTM_ADD, dst, &sdl_m) == NULL); |
b7080c8e A |
494 | } |
495 | ||
496 | /* | |
497 | * Display an individual arp entry | |
498 | */ | |
9c859447 | 499 | static int |
ac2f15b3 | 500 | get(char *host) |
b7080c8e | 501 | { |
9c859447 A |
502 | struct sockaddr_inarp *addr; |
503 | ||
504 | addr = getaddr(host); | |
505 | if (addr == NULL) | |
506 | return (1); | |
507 | if (0 == search(addr->sin_addr.s_addr, print_entry)) { | |
508 | printf("%s (%s) -- no entry", | |
ac2f15b3 | 509 | host, inet_ntoa(addr->sin_addr)); |
9c859447 A |
510 | if (rifname) |
511 | printf(" on %s", rifname); | |
512 | printf("\n"); | |
513 | return (1); | |
b7080c8e | 514 | } |
9c859447 | 515 | return (0); |
b7080c8e A |
516 | } |
517 | ||
518 | /* | |
ac2f15b3 | 519 | * Delete an arp entry |
b7080c8e | 520 | */ |
9c859447 A |
521 | static int |
522 | delete(char *host, int do_proxy) | |
b7080c8e | 523 | { |
9c859447 A |
524 | struct sockaddr_inarp *addr, *dst; |
525 | struct rt_msghdr *rtm; | |
b7080c8e A |
526 | struct sockaddr_dl *sdl; |
527 | ||
9c859447 A |
528 | dst = getaddr(host); |
529 | if (dst == NULL) | |
530 | return (1); | |
531 | dst->sin_other = do_proxy; | |
532 | for (;;) { /* try twice */ | |
533 | rtm = rtmsg(RTM_GET, dst, NULL); | |
534 | if (rtm == NULL) { | |
535 | warn("%s", host); | |
b7080c8e A |
536 | return (1); |
537 | } | |
9c859447 A |
538 | addr = (struct sockaddr_inarp *)(rtm + 1); |
539 | sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr); | |
540 | if (addr->sin_addr.s_addr == dst->sin_addr.s_addr && | |
541 | sdl->sdl_family == AF_LINK && | |
b7080c8e | 542 | (rtm->rtm_flags & RTF_LLINFO) && |
9c859447 A |
543 | !(rtm->rtm_flags & RTF_GATEWAY) && |
544 | valid_type(sdl->sdl_type) ) | |
545 | break; /* found it */ | |
546 | if (dst->sin_other & SIN_PROXY) { | |
547 | fprintf(stderr, "delete: cannot locate %s\n",host); | |
548 | return (1); | |
b7080c8e | 549 | } |
9c859447 | 550 | dst->sin_other = SIN_PROXY; |
b7080c8e | 551 | } |
9c859447 | 552 | if (rtmsg(RTM_DELETE, dst, NULL) != NULL) { |
ac2f15b3 A |
553 | printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr)); |
554 | return (0); | |
555 | } | |
556 | return (1); | |
b7080c8e A |
557 | } |
558 | ||
559 | /* | |
ac2f15b3 | 560 | * Search the arp table and do some action on matching entries |
b7080c8e | 561 | */ |
9c859447 A |
562 | static int |
563 | search(in_addr_t addr, action_fn *action) | |
b7080c8e A |
564 | { |
565 | int mib[6]; | |
566 | size_t needed; | |
9c859447 | 567 | char *lim, *buf, *newbuf, *next; |
b7080c8e | 568 | struct rt_msghdr *rtm; |
ac2f15b3 | 569 | struct sockaddr_inarp *sin2; |
b7080c8e | 570 | struct sockaddr_dl *sdl; |
9c859447 A |
571 | char ifname[IF_NAMESIZE]; |
572 | int st, found_entry = 0; | |
b7080c8e A |
573 | |
574 | mib[0] = CTL_NET; | |
575 | mib[1] = PF_ROUTE; | |
576 | mib[2] = 0; | |
577 | mib[3] = AF_INET; | |
578 | mib[4] = NET_RT_FLAGS; | |
579 | mib[5] = RTF_LLINFO; | |
580 | if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) | |
9c859447 A |
581 | err(1, "route-sysctl-estimate"); |
582 | if (needed == 0) /* empty table */ | |
583 | return 0; | |
584 | buf = NULL; | |
585 | for (;;) { | |
586 | newbuf = realloc(buf, needed); | |
587 | if (newbuf == NULL) { | |
588 | if (buf != NULL) | |
589 | free(buf); | |
590 | errx(1, "could not reallocate memory"); | |
591 | } | |
592 | buf = newbuf; | |
593 | st = sysctl(mib, 6, buf, &needed, NULL, 0); | |
594 | if (st == 0 || errno != ENOMEM) | |
595 | break; | |
596 | needed += needed / 8; | |
597 | } | |
598 | if (st == -1) | |
599 | err(1, "actual retrieval of routing table"); | |
b7080c8e A |
600 | lim = buf + needed; |
601 | for (next = buf; next < lim; next += rtm->rtm_msglen) { | |
602 | rtm = (struct rt_msghdr *)next; | |
ac2f15b3 | 603 | sin2 = (struct sockaddr_inarp *)(rtm + 1); |
9c859447 A |
604 | sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2)); |
605 | if (rifname && if_indextoname(sdl->sdl_index, ifname) && | |
606 | strcmp(ifname, rifname)) | |
607 | continue; | |
b7080c8e | 608 | if (addr) { |
ac2f15b3 | 609 | if (addr != sin2->sin_addr.s_addr) |
b7080c8e A |
610 | continue; |
611 | found_entry = 1; | |
612 | } | |
ac2f15b3 | 613 | (*action)(sdl, sin2, rtm); |
b7080c8e | 614 | } |
ac2f15b3 | 615 | free(buf); |
9c859447 | 616 | return (found_entry); |
b7080c8e A |
617 | } |
618 | ||
ac2f15b3 A |
619 | /* |
620 | * Stolen and adapted from ifconfig | |
621 | */ | |
fdfd5971 | 622 | static char * |
ac2f15b3 A |
623 | print_lladdr(struct sockaddr_dl *sdl) |
624 | { | |
fdfd5971 | 625 | static char buf[256]; |
ac2f15b3 | 626 | char *cp; |
fdfd5971 | 627 | int n, bufsize = sizeof (buf), p = 0; |
ac2f15b3 | 628 | |
fdfd5971 | 629 | bzero(buf, sizeof (buf)); |
ac2f15b3 A |
630 | cp = (char *)LLADDR(sdl); |
631 | if ((n = sdl->sdl_alen) > 0) { | |
632 | while (--n >= 0) | |
fdfd5971 A |
633 | p += snprintf(buf + p, bufsize - p, "%x%s", |
634 | *cp++ & 0xff, n > 0 ? ":" : ""); | |
ac2f15b3 | 635 | } |
fdfd5971 | 636 | return (buf); |
ac2f15b3 A |
637 | } |
638 | ||
ac2f15b3 A |
639 | /* |
640 | * Display an arp entry | |
641 | */ | |
9c859447 | 642 | static void |
ac2f15b3 A |
643 | print_entry(struct sockaddr_dl *sdl, |
644 | struct sockaddr_inarp *addr, struct rt_msghdr *rtm) | |
b7080c8e | 645 | { |
ac2f15b3 A |
646 | const char *host; |
647 | struct hostent *hp; | |
ac2f15b3 | 648 | char ifname[IF_NAMESIZE]; |
9c859447 A |
649 | #if 0 |
650 | struct iso88025_sockaddr_dl_data *trld; | |
651 | int seg; | |
652 | #endif | |
ac2f15b3 A |
653 | |
654 | if (nflag == 0) | |
655 | hp = gethostbyaddr((caddr_t)&(addr->sin_addr), | |
656 | sizeof addr->sin_addr, AF_INET); | |
657 | else | |
658 | hp = 0; | |
659 | if (hp) | |
660 | host = hp->h_name; | |
661 | else { | |
662 | host = "?"; | |
663 | if (h_errno == TRY_AGAIN) | |
664 | nflag = 1; | |
665 | } | |
666 | printf("%s (%s) at ", host, inet_ntoa(addr->sin_addr)); | |
667 | if (sdl->sdl_alen) { | |
9c859447 | 668 | #if 1 |
fdfd5971 | 669 | printf("%s", print_lladdr(sdl)); |
9c859447 A |
670 | #else |
671 | if ((sdl->sdl_type == IFT_ETHER || | |
672 | sdl->sdl_type == IFT_L2VLAN || | |
673 | sdl->sdl_type == IFT_BRIDGE) && | |
674 | sdl->sdl_alen == ETHER_ADDR_LEN) | |
675 | printf("%s", ether_ntoa((struct ether_addr *)LLADDR(sdl))); | |
676 | else { | |
677 | int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; | |
678 | ||
679 | printf("%s", link_ntoa(sdl) + n); | |
680 | } | |
681 | #endif | |
682 | } else | |
ac2f15b3 A |
683 | printf("(incomplete)"); |
684 | if (if_indextoname(sdl->sdl_index, ifname) != NULL) | |
685 | printf(" on %s", ifname); | |
9c859447 A |
686 | if ((rtm->rtm_flags & RTF_IFSCOPE)) |
687 | printf(" ifscope"); | |
ac2f15b3 A |
688 | if (rtm->rtm_rmx.rmx_expire == 0) |
689 | printf(" permanent"); | |
690 | if (addr->sin_other & SIN_PROXY) | |
691 | printf(" published (proxy only)"); | |
692 | if (rtm->rtm_addrs & RTA_NETMASK) { | |
693 | addr = (struct sockaddr_inarp *) | |
9c859447 | 694 | (SA_SIZE(sdl) + (char *)sdl); |
ac2f15b3 A |
695 | if (addr->sin_addr.s_addr == 0xffffffff) |
696 | printf(" published"); | |
697 | if (addr->sin_len != 8) | |
698 | printf("(weird)"); | |
699 | } | |
700 | switch(sdl->sdl_type) { | |
9c859447 | 701 | case IFT_ETHER: |
ac2f15b3 A |
702 | printf(" [ethernet]"); |
703 | break; | |
9c859447 A |
704 | #if 0 |
705 | case IFT_ISO88025: | |
ac2f15b3 A |
706 | printf(" [token-ring]"); |
707 | trld = SDL_ISO88025(sdl); | |
708 | if (trld->trld_rcf != 0) { | |
709 | printf(" rt=%x", ntohs(trld->trld_rcf)); | |
710 | for (seg = 0; | |
711 | seg < ((TR_RCF_RIFLEN(trld->trld_rcf) - 2 ) / 2); | |
712 | seg++) | |
713 | printf(":%x", ntohs(*(trld->trld_route[seg]))); | |
714 | } | |
9c859447 | 715 | break; |
ac2f15b3 | 716 | #endif |
9c859447 A |
717 | case IFT_FDDI: |
718 | printf(" [fddi]"); | |
ac2f15b3 | 719 | break; |
9c859447 A |
720 | case IFT_ATM: |
721 | printf(" [atm]"); | |
722 | break; | |
723 | case IFT_L2VLAN: | |
ac2f15b3 A |
724 | printf(" [vlan]"); |
725 | break; | |
9c859447 A |
726 | case IFT_IEEE1394: |
727 | printf(" [firewire]"); | |
728 | break; | |
729 | #ifdef IFT_BRIDGE | |
730 | case IFT_BRIDGE: | |
731 | printf(" [bridge]"); | |
ac2f15b3 | 732 | break; |
9c859447 A |
733 | #endif |
734 | default: | |
2b484d24 | 735 | break; |
ac2f15b3 A |
736 | } |
737 | ||
738 | printf("\n"); | |
739 | ||
740 | } | |
741 | ||
742 | /* | |
743 | * Nuke an arp entry | |
744 | */ | |
9c859447 A |
745 | static void |
746 | nuke_entry(struct sockaddr_dl *sdl __unused, | |
fdfd5971 | 747 | struct sockaddr_inarp *addr, struct rt_msghdr *rtm) |
ac2f15b3 A |
748 | { |
749 | char ip[20]; | |
750 | ||
751 | snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr)); | |
fdfd5971 A |
752 | /* |
753 | * When deleting all entries, specify the interface scope of each entry | |
754 | */ | |
755 | if ((rtm->rtm_flags & RTF_IFSCOPE)) | |
756 | ifscope = rtm->rtm_index; | |
9c859447 | 757 | (void)delete(ip, 0); |
fdfd5971 | 758 | ifscope = 0; |
b7080c8e A |
759 | } |
760 | ||
9c859447 | 761 | static void |
ac2f15b3 | 762 | usage(void) |
b7080c8e | 763 | { |
ac2f15b3 | 764 | fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", |
9c859447 | 765 | "usage: arp [-n] [-i interface] hostname", |
fdfd5971 | 766 | " arp [-n] [-i interface] [-l] -a", |
9c859447 A |
767 | " arp -d hostname [pub] [ifscope interface]", |
768 | " arp -d [-i interface] -a", | |
769 | " arp -s hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]", | |
770 | " arp -S hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]", | |
ac2f15b3 | 771 | " arp -f filename"); |
b7080c8e A |
772 | exit(1); |
773 | } | |
774 | ||
9c859447 A |
775 | static struct rt_msghdr * |
776 | rtmsg(int cmd, struct sockaddr_inarp *dst, struct sockaddr_dl *sdl) | |
b7080c8e A |
777 | { |
778 | static int seq; | |
779 | int rlen; | |
9c859447 A |
780 | int l; |
781 | struct sockaddr_in so_mask, *so_mask_ptr = &so_mask; | |
782 | static int s = -1; | |
783 | static pid_t pid; | |
784 | ||
785 | static struct { | |
786 | struct rt_msghdr m_rtm; | |
787 | char m_space[512]; | |
788 | } m_rtmsg; | |
789 | ||
790 | struct rt_msghdr *rtm = &m_rtmsg.m_rtm; | |
791 | char *cp = m_rtmsg.m_space; | |
792 | ||
793 | if (s < 0) { /* first time: open socket, get pid */ | |
794 | s = socket(PF_ROUTE, SOCK_RAW, 0); | |
795 | if (s < 0) | |
796 | err(1, "socket"); | |
797 | pid = getpid(); | |
798 | } | |
799 | bzero(&so_mask, sizeof(so_mask)); | |
800 | so_mask.sin_len = 8; | |
801 | so_mask.sin_addr.s_addr = 0xffffffff; | |
b7080c8e A |
802 | |
803 | errno = 0; | |
9c859447 A |
804 | /* |
805 | * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer | |
806 | * appropriately (except for the mask set just above). | |
807 | */ | |
b7080c8e A |
808 | if (cmd == RTM_DELETE) |
809 | goto doit; | |
810 | bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); | |
811 | rtm->rtm_flags = flags; | |
812 | rtm->rtm_version = RTM_VERSION; | |
813 | ||
9c859447 A |
814 | /* |
815 | * Note: On RTM_GET the kernel will return a scoped route when both a scoped route and | |
816 | * a unscoped route exist. That means we cannot delete a unscoped route if there is | |
817 | * also a matching scope route | |
818 | */ | |
819 | if (ifscope) { | |
820 | rtm->rtm_index = ifscope; | |
821 | rtm->rtm_flags |= RTF_IFSCOPE; | |
822 | } | |
823 | ||
b7080c8e A |
824 | switch (cmd) { |
825 | default: | |
ac2f15b3 | 826 | errx(1, "internal wrong cmd"); |
b7080c8e A |
827 | case RTM_ADD: |
828 | rtm->rtm_addrs |= RTA_GATEWAY; | |
829 | rtm->rtm_rmx.rmx_expire = expire_time; | |
830 | rtm->rtm_inits = RTV_EXPIRE; | |
831 | rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); | |
9c859447 | 832 | dst->sin_other = 0; |
b7080c8e | 833 | if (doing_proxy) { |
ac2f15b3 | 834 | if (proxy_only) |
9c859447 | 835 | dst->sin_other = SIN_PROXY; |
b7080c8e A |
836 | else { |
837 | rtm->rtm_addrs |= RTA_NETMASK; | |
838 | rtm->rtm_flags &= ~RTF_HOST; | |
839 | } | |
840 | } | |
841 | /* FALLTHROUGH */ | |
842 | case RTM_GET: | |
843 | rtm->rtm_addrs |= RTA_DST; | |
844 | } | |
845 | #define NEXTADDR(w, s) \ | |
9c859447 A |
846 | if ((s) != NULL && rtm->rtm_addrs & (w)) { \ |
847 | bcopy((s), cp, sizeof(*(s))); cp += SA_SIZE(s);} | |
b7080c8e | 848 | |
9c859447 A |
849 | NEXTADDR(RTA_DST, dst); |
850 | NEXTADDR(RTA_GATEWAY, sdl); | |
851 | NEXTADDR(RTA_NETMASK, so_mask_ptr); | |
b7080c8e A |
852 | |
853 | rtm->rtm_msglen = cp - (char *)&m_rtmsg; | |
854 | doit: | |
855 | l = rtm->rtm_msglen; | |
856 | rtm->rtm_seq = ++seq; | |
857 | rtm->rtm_type = cmd; | |
858 | if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { | |
859 | if (errno != ESRCH || cmd != RTM_DELETE) { | |
ac2f15b3 | 860 | warn("writing to routing socket"); |
9c859447 | 861 | return (NULL); |
b7080c8e A |
862 | } |
863 | } | |
864 | do { | |
865 | l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); | |
866 | } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); | |
867 | if (l < 0) | |
ac2f15b3 | 868 | warn("read from routing socket"); |
9c859447 | 869 | return (rtm); |
b7080c8e | 870 | } |
ac2f15b3 A |
871 | |
872 | /* | |
873 | * get_ether_addr - get the hardware address of an interface on the | |
874 | * the same subnet as ipaddr. | |
875 | */ | |
876 | #define MAX_IFS 32 | |
877 | ||
9c859447 A |
878 | static int |
879 | get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr) | |
ac2f15b3 A |
880 | { |
881 | struct ifreq *ifr, *ifend, *ifp; | |
9c859447 | 882 | in_addr_t ina, mask; |
ac2f15b3 A |
883 | struct sockaddr_dl *dla; |
884 | struct ifreq ifreq; | |
885 | struct ifconf ifc; | |
886 | struct ifreq ifs[MAX_IFS]; | |
887 | int sock; | |
9c859447 | 888 | int retval = 0; |
ac2f15b3 A |
889 | |
890 | sock = socket(AF_INET, SOCK_DGRAM, 0); | |
891 | if (sock < 0) | |
892 | err(1, "socket"); | |
893 | ||
894 | ifc.ifc_len = sizeof(ifs); | |
895 | ifc.ifc_req = ifs; | |
896 | if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { | |
897 | warnx("ioctl(SIOCGIFCONF)"); | |
9c859447 | 898 | goto done; |
ac2f15b3 A |
899 | } |
900 | ||
9c859447 A |
901 | #define NEXTIFR(i) \ |
902 | ((struct ifreq *)((char *)&(i)->ifr_addr \ | |
903 | + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) ) | |
904 | ||
ac2f15b3 | 905 | /* |
9c859447 A |
906 | * Scan through looking for an interface with an Internet |
907 | * address on the same subnet as `ipaddr'. | |
908 | */ | |
909 | ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len); | |
910 | for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr) ) { | |
911 | if (ifr->ifr_addr.sa_family != AF_INET) | |
912 | continue; | |
913 | strncpy(ifreq.ifr_name, ifr->ifr_name, | |
914 | sizeof(ifreq.ifr_name)); | |
915 | ifreq.ifr_addr = ifr->ifr_addr; | |
916 | /* | |
917 | * Check that the interface is up, | |
918 | * and not point-to-point or loopback. | |
919 | */ | |
920 | if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) | |
921 | continue; | |
922 | if ((ifreq.ifr_flags & | |
923 | (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT| | |
924 | IFF_LOOPBACK|IFF_NOARP)) | |
925 | != (IFF_UP|IFF_BROADCAST)) | |
926 | continue; | |
927 | /* | |
928 | * Get its netmask and check that it's on | |
929 | * the right subnet. | |
930 | */ | |
931 | if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0) | |
932 | continue; | |
933 | mask = ((struct sockaddr_in *) | |
934 | &ifreq.ifr_addr)->sin_addr.s_addr; | |
935 | ina = ((struct sockaddr_in *) | |
936 | &ifr->ifr_addr)->sin_addr.s_addr; | |
937 | if ((ipaddr & mask) == (ina & mask)) | |
938 | break; /* ok, we got it! */ | |
ac2f15b3 A |
939 | } |
940 | ||
9c859447 A |
941 | if (ifr >= ifend) |
942 | goto done; | |
ac2f15b3 A |
943 | |
944 | /* | |
9c859447 A |
945 | * Now scan through again looking for a link-level address |
946 | * for this interface. | |
947 | */ | |
ac2f15b3 | 948 | ifp = ifr; |
9c859447 A |
949 | for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr)) |
950 | if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 && | |
951 | ifr->ifr_addr.sa_family == AF_LINK) | |
952 | break; | |
953 | if (ifr >= ifend) | |
954 | goto done; | |
955 | /* | |
956 | * Found the link-level address - copy it out | |
957 | */ | |
958 | dla = (struct sockaddr_dl *) &ifr->ifr_addr; | |
959 | memcpy(hwaddr, LLADDR(dla), dla->sdl_alen); | |
960 | printf("using interface %s for proxy with address ", | |
961 | ifp->ifr_name); | |
962 | printf("%s\n", ether_ntoa(hwaddr)); | |
963 | retval = dla->sdl_alen; | |
964 | done: | |
965 | close(sock); | |
966 | return (retval); | |
ac2f15b3 | 967 | } |
fdfd5971 A |
968 | |
969 | static char * | |
970 | sec2str(total) | |
971 | time_t total; | |
972 | { | |
973 | static char result[256]; | |
974 | int days, hours, mins, secs; | |
975 | int first = 1; | |
976 | char *p = result; | |
977 | ||
978 | days = total / 3600 / 24; | |
979 | hours = (total / 3600) % 24; | |
980 | mins = (total / 60) % 60; | |
981 | secs = total % 60; | |
982 | ||
983 | if (days) { | |
984 | first = 0; | |
985 | p += snprintf(p, sizeof(result) - (p - result), "%dd", days); | |
986 | } | |
987 | if (!first || hours) { | |
988 | first = 0; | |
989 | p += snprintf(p, sizeof(result) - (p - result), "%dh", hours); | |
990 | } | |
991 | if (!first || mins) { | |
992 | first = 0; | |
993 | p += snprintf(p, sizeof(result) - (p - result), "%dm", mins); | |
994 | } | |
995 | snprintf(p, sizeof(result) - (p - result), "%ds", secs); | |
996 | ||
997 | return(result); | |
998 | } | |
999 | ||
1000 | static int | |
1001 | search_ext(in_addr_t addr, action_ext_fn *action) | |
1002 | { | |
1003 | int mib[6]; | |
1004 | size_t needed; | |
1005 | char *lim, *buf, *newbuf, *next; | |
1006 | struct rt_msghdr_ext *ertm; | |
1007 | struct sockaddr_inarp *sin2; | |
1008 | struct sockaddr_dl *sdl; | |
1009 | char ifname[IF_NAMESIZE]; | |
1010 | int st, found_entry = 0; | |
1011 | ||
1012 | mib[0] = CTL_NET; | |
1013 | mib[1] = PF_ROUTE; | |
1014 | mib[2] = 0; | |
1015 | mib[3] = AF_INET; | |
1016 | mib[4] = NET_RT_DUMPX_FLAGS; | |
1017 | mib[5] = RTF_LLINFO; | |
1018 | if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) | |
1019 | err(1, "route-sysctl-estimate"); | |
1020 | if (needed == 0) /* empty table */ | |
1021 | return 0; | |
1022 | buf = NULL; | |
1023 | for (;;) { | |
1024 | newbuf = realloc(buf, needed); | |
1025 | if (newbuf == NULL) { | |
1026 | if (buf != NULL) | |
1027 | free(buf); | |
1028 | errx(1, "could not reallocate memory"); | |
1029 | } | |
1030 | buf = newbuf; | |
1031 | st = sysctl(mib, 6, buf, &needed, NULL, 0); | |
1032 | if (st == 0 || errno != ENOMEM) | |
1033 | break; | |
1034 | needed += needed / 8; | |
1035 | } | |
1036 | if (st == -1) | |
1037 | err(1, "actual retrieval of routing table"); | |
1038 | lim = buf + needed; | |
1039 | for (next = buf; next < lim; next += ertm->rtm_msglen) { | |
1040 | ertm = (struct rt_msghdr_ext *)next; | |
1041 | sin2 = (struct sockaddr_inarp *)(ertm + 1); | |
1042 | sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2)); | |
1043 | if (rifname && if_indextoname(sdl->sdl_index, ifname) && | |
1044 | strcmp(ifname, rifname)) | |
1045 | continue; | |
1046 | if (addr) { | |
1047 | if (addr != sin2->sin_addr.s_addr) | |
1048 | continue; | |
1049 | found_entry = 1; | |
1050 | } | |
1051 | (*action)(sdl, sin2, ertm); | |
1052 | } | |
1053 | free(buf); | |
1054 | return (found_entry); | |
1055 | } | |
1056 | ||
1057 | static void | |
1058 | print_entry_ext(struct sockaddr_dl *sdl, struct sockaddr_inarp *addr, | |
1059 | struct rt_msghdr_ext *ertm) | |
1060 | { | |
1061 | const char *host; | |
1062 | struct hostent *hp; | |
1063 | char ifname[IF_NAMESIZE]; | |
1064 | struct timeval time; | |
1065 | ||
1066 | if (nflag == 0) | |
1067 | hp = gethostbyaddr((caddr_t)&(addr->sin_addr), | |
1068 | sizeof (addr->sin_addr), AF_INET); | |
1069 | else | |
1070 | hp = 0; | |
1071 | ||
1072 | if (hp) | |
1073 | host = hp->h_name; | |
1074 | else | |
1075 | host = inet_ntoa(addr->sin_addr); | |
1076 | ||
1077 | printf("%-23s ", host); | |
1078 | ||
1079 | if (sdl->sdl_alen) | |
1080 | printf("%-17s ", print_lladdr(sdl)); | |
1081 | else | |
1082 | printf("%-17s ", "(incomplete)"); | |
1083 | ||
1084 | gettimeofday(&time, 0); | |
1085 | ||
1086 | if (ertm->rtm_ri.ri_refcnt == 0 || ertm->rtm_ri.ri_snd_expire == 0) | |
1087 | printf("%-9.9s ", "(none)"); | |
1088 | else if (ertm->rtm_ri.ri_snd_expire > time.tv_sec) | |
1089 | printf("%-9.9s ", | |
1090 | sec2str(ertm->rtm_ri.ri_snd_expire - time.tv_sec)); | |
1091 | else | |
1092 | printf("%-9.9s ", "expired"); | |
1093 | ||
1094 | if (ertm->rtm_ri.ri_refcnt == 0 || ertm->rtm_ri.ri_rcv_expire == 0) | |
1095 | printf("%-9.9s", "(none)"); | |
1096 | else if (ertm->rtm_ri.ri_rcv_expire > time.tv_sec) | |
1097 | printf("%-9.9s", | |
1098 | sec2str(ertm->rtm_ri.ri_rcv_expire - time.tv_sec)); | |
1099 | else | |
1100 | printf("%-9.9s", "expired"); | |
1101 | ||
1102 | if (if_indextoname(sdl->sdl_index, ifname) == NULL) | |
1103 | snprintf(ifname, sizeof (ifname), "%s", "?"); | |
1104 | printf(" %8.8s", ifname); | |
1105 | ||
1106 | if (ertm->rtm_ri.ri_refcnt) { | |
1107 | printf(" %4d", ertm->rtm_ri.ri_refcnt); | |
1108 | if (ertm->rtm_ri.ri_probes) | |
1109 | printf(" %4d", ertm->rtm_ri.ri_probes); | |
1110 | } | |
1111 | printf("\n"); | |
1112 | } |