arp.c revision 1.1.1.3 1 /*
2 * Copyright (c) 1984, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Sun Microsystems, Inc.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #ifndef lint
38 static char copyright[] =
39 "@(#) Copyright (c) 1984, 1993\n\
40 The Regents of the University of California. All rights reserved.\n";
41 #endif /* not lint */
42
43 #ifndef lint
44 static char sccsid[] = "@(#)arp.c 8.3 (Berkeley) 4/28/95";
45 #endif /* not lint */
46
47 /*
48 * arp - display, set, and delete arp table entries
49 */
50
51
52 #include <sys/param.h>
53 #include <sys/file.h>
54 #include <sys/socket.h>
55 #include <sys/sysctl.h>
56
57 #include <net/if.h>
58 #include <net/if_dl.h>
59 #include <net/if_types.h>
60 #include <net/route.h>
61
62 #include <netinet/in.h>
63 #include <netinet/if_ether.h>
64
65 #include <arpa/inet.h>
66
67 #include <err.h>
68 #include <errno.h>
69 #include <netdb.h>
70 #include <nlist.h>
71 #include <paths.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <unistd.h>
76
77 static int pid;
78 static int nflag;
79 static int s = -1;
80
81 int delete __P((char *, char *));
82 void dump __P((u_long));
83 int ether_aton __P((char *, u_char *));
84 void ether_print __P((u_char *));
85 int file __P((char *));
86 void get __P((char *));
87 void getsocket __P((void));
88 int rtmsg __P((int));
89 int set __P((int, char **));
90 void usage __P((void));
91
92 int
93 main(argc, argv)
94 int argc;
95 char **argv;
96 {
97 int ch;
98
99 pid = getpid();
100 while ((ch = getopt(argc, argv, "ands")) != EOF)
101 switch((char)ch) {
102 case 'a':
103 dump(0);
104 exit(0);
105 case 'd':
106 if (argc < 3 || argc > 4)
107 usage();
108 delete(argv[2], argv[3]);
109 exit(0);
110 case 'n':
111 nflag = 1;
112 continue;
113 case 's':
114 if (argc < 4 || argc > 7)
115 usage();
116 exit(set(argc-2, &argv[2]) ? 1 : 0);
117 case '?':
118 default:
119 usage();
120 }
121 if (argc != 2)
122 usage();
123 get(argv[1]);
124 return (0);
125 }
126
127 /*
128 * Process a file to set standard arp entries
129 */
130 int
131 file(name)
132 char *name;
133 {
134 FILE *fp;
135 int i, retval;
136 char line[100], arg[5][50], *args[5];
137
138 if ((fp = fopen(name, "r")) == NULL) {
139 fprintf(stderr, "arp: cannot open %s\n", name);
140 exit(1);
141 }
142 args[0] = &arg[0][0];
143 args[1] = &arg[1][0];
144 args[2] = &arg[2][0];
145 args[3] = &arg[3][0];
146 args[4] = &arg[4][0];
147 retval = 0;
148 while(fgets(line, 100, fp) != NULL) {
149 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
150 arg[3], arg[4]);
151 if (i < 2) {
152 fprintf(stderr, "arp: bad line: %s\n", line);
153 retval = 1;
154 continue;
155 }
156 if (set(i, args))
157 retval = 1;
158 }
159 fclose(fp);
160 return (retval);
161 }
162
163 void
164 getsocket() {
165 if (s < 0) {
166 s = socket(PF_ROUTE, SOCK_RAW, 0);
167 if (s < 0) {
168 perror("arp: socket");
169 exit(1);
170 }
171 }
172 }
173
174 struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
175 struct sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m;
176 struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
177 int expire_time, flags, export_only, doing_proxy, found_entry;
178 struct {
179 struct rt_msghdr m_rtm;
180 char m_space[512];
181 } m_rtmsg;
182
183 /*
184 * Set an individual arp entry
185 */
186 int
187 set(argc, argv)
188 int argc;
189 char **argv;
190 {
191 struct hostent *hp;
192 register struct sockaddr_inarp *sin = &sin_m;
193 register struct sockaddr_dl *sdl;
194 register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
195 u_char *ea;
196 char *host = argv[0], *eaddr = argv[1];
197
198 getsocket();
199 argc -= 2;
200 argv += 2;
201 sdl_m = blank_sdl;
202 sin_m = blank_sin;
203 sin->sin_addr.s_addr = inet_addr(host);
204 if (sin->sin_addr.s_addr == -1) {
205 if (!(hp = gethostbyname(host))) {
206 fprintf(stderr, "arp: %s: ", host);
207 herror((char *)NULL);
208 return (1);
209 }
210 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
211 sizeof sin->sin_addr);
212 }
213 ea = (u_char *)LLADDR(&sdl_m);
214 if (ether_aton(eaddr, ea) == 0)
215 sdl_m.sdl_alen = 6;
216 doing_proxy = flags = export_only = expire_time = 0;
217 while (argc-- > 0) {
218 if (strncmp(argv[0], "temp", 4) == 0) {
219 struct timeval time;
220 gettimeofday(&time, 0);
221 expire_time = time.tv_sec + 20 * 60;
222 }
223 else if (strncmp(argv[0], "pub", 3) == 0) {
224 flags |= RTF_ANNOUNCE;
225 doing_proxy = SIN_PROXY;
226 } else if (strncmp(argv[0], "trail", 5) == 0) {
227 printf("%s: Sending trailers is no longer supported\n",
228 host);
229 }
230 argv++;
231 }
232 tryagain:
233 if (rtmsg(RTM_GET) < 0) {
234 perror(host);
235 return (1);
236 }
237 sin = (struct sockaddr_inarp *)(rtm + 1);
238 sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
239 if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
240 if (sdl->sdl_family == AF_LINK &&
241 (rtm->rtm_flags & RTF_LLINFO) &&
242 !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
243 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
244 case IFT_ISO88024: case IFT_ISO88025:
245 goto overwrite;
246 }
247 if (doing_proxy == 0) {
248 printf("set: can only proxy for %s\n", host);
249 return (1);
250 }
251 if (sin_m.sin_other & SIN_PROXY) {
252 printf("set: proxy entry exists for non 802 device\n");
253 return(1);
254 }
255 sin_m.sin_other = SIN_PROXY;
256 export_only = 1;
257 goto tryagain;
258 }
259 overwrite:
260 if (sdl->sdl_family != AF_LINK) {
261 printf("cannot intuit interface index and type for %s\n", host);
262 return (1);
263 }
264 sdl_m.sdl_type = sdl->sdl_type;
265 sdl_m.sdl_index = sdl->sdl_index;
266 return (rtmsg(RTM_ADD));
267 }
268
269 /*
270 * Display an individual arp entry
271 */
272 void
273 get(host)
274 char *host;
275 {
276 struct hostent *hp;
277 struct sockaddr_inarp *sin = &sin_m;
278
279 sin_m = blank_sin;
280 sin->sin_addr.s_addr = inet_addr(host);
281 if (sin->sin_addr.s_addr == -1) {
282 if (!(hp = gethostbyname(host))) {
283 fprintf(stderr, "arp: %s: ", host);
284 herror((char *)NULL);
285 exit(1);
286 }
287 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
288 sizeof sin->sin_addr);
289 }
290 dump(sin->sin_addr.s_addr);
291 if (found_entry == 0) {
292 printf("%s (%s) -- no entry\n",
293 host, inet_ntoa(sin->sin_addr));
294 exit(1);
295 }
296 }
297
298 /*
299 * Delete an arp entry
300 */
301 int
302 delete(host, info)
303 char *host;
304 char *info;
305 {
306 struct hostent *hp;
307 register struct sockaddr_inarp *sin = &sin_m;
308 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
309 struct sockaddr_dl *sdl;
310
311 if (info && strncmp(info, "pro", 3) )
312 export_only = 1;
313 getsocket();
314 sin_m = blank_sin;
315 sin->sin_addr.s_addr = inet_addr(host);
316 if (sin->sin_addr.s_addr == -1) {
317 if (!(hp = gethostbyname(host))) {
318 fprintf(stderr, "arp: %s: ", host);
319 herror((char *)NULL);
320 return (1);
321 }
322 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
323 sizeof sin->sin_addr);
324 }
325 tryagain:
326 if (rtmsg(RTM_GET) < 0) {
327 perror(host);
328 return (1);
329 }
330 sin = (struct sockaddr_inarp *)(rtm + 1);
331 sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
332 if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
333 if (sdl->sdl_family == AF_LINK &&
334 (rtm->rtm_flags & RTF_LLINFO) &&
335 !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
336 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
337 case IFT_ISO88024: case IFT_ISO88025:
338 goto delete;
339 }
340 }
341 if (sin_m.sin_other & SIN_PROXY) {
342 fprintf(stderr, "delete: can't locate %s\n",host);
343 return (1);
344 } else {
345 sin_m.sin_other = SIN_PROXY;
346 goto tryagain;
347 }
348 delete:
349 if (sdl->sdl_family != AF_LINK) {
350 printf("cannot locate %s\n", host);
351 return (1);
352 }
353 if (rtmsg(RTM_DELETE))
354 return (1);
355 printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
356 return (0);
357 }
358
359 /*
360 * Dump the entire arp table
361 */
362 void
363 dump(addr)
364 u_long addr;
365 {
366 int mib[6];
367 size_t needed;
368 char *host, *lim, *buf, *next;
369 struct rt_msghdr *rtm;
370 struct sockaddr_inarp *sin;
371 struct sockaddr_dl *sdl;
372 extern int h_errno;
373 struct hostent *hp;
374
375 mib[0] = CTL_NET;
376 mib[1] = PF_ROUTE;
377 mib[2] = 0;
378 mib[3] = AF_INET;
379 mib[4] = NET_RT_FLAGS;
380 mib[5] = RTF_LLINFO;
381 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
382 err(1, "route-sysctl-estimate");
383 if ((buf = malloc(needed)) == NULL)
384 err(1, "malloc");
385 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
386 err(1, "actual retrieval of routing table");
387 lim = buf + needed;
388 for (next = buf; next < lim; next += rtm->rtm_msglen) {
389 rtm = (struct rt_msghdr *)next;
390 sin = (struct sockaddr_inarp *)(rtm + 1);
391 sdl = (struct sockaddr_dl *)(sin + 1);
392 if (addr) {
393 if (addr != sin->sin_addr.s_addr)
394 continue;
395 found_entry = 1;
396 }
397 if (nflag == 0)
398 hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
399 sizeof sin->sin_addr, AF_INET);
400 else
401 hp = 0;
402 if (hp)
403 host = hp->h_name;
404 else {
405 host = "?";
406 if (h_errno == TRY_AGAIN)
407 nflag = 1;
408 }
409 printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
410 if (sdl->sdl_alen)
411 ether_print((u_char *)LLADDR(sdl));
412 else
413 printf("(incomplete)");
414 if (rtm->rtm_rmx.rmx_expire == 0)
415 printf(" permanent");
416 if (sin->sin_other & SIN_PROXY)
417 printf(" published (proxy only)");
418 if (rtm->rtm_addrs & RTA_NETMASK) {
419 sin = (struct sockaddr_inarp *)
420 (sdl->sdl_len + (char *)sdl);
421 if (sin->sin_addr.s_addr == 0xffffffff)
422 printf(" published");
423 if (sin->sin_len != 8)
424 printf("(wierd)");
425 }
426 printf("\n");
427 }
428 }
429
430 void
431 ether_print(cp)
432 u_char *cp;
433 {
434 printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
435 }
436
437 int
438 ether_aton(a, n)
439 char *a;
440 u_char *n;
441 {
442 int i, o[6];
443
444 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
445 &o[3], &o[4], &o[5]);
446 if (i != 6) {
447 fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
448 return (1);
449 }
450 for (i=0; i<6; i++)
451 n[i] = o[i];
452 return (0);
453 }
454
455 void
456 usage()
457 {
458 printf("usage: arp hostname\n");
459 printf(" arp -a [kernel] [kernel_memory]\n");
460 printf(" arp -d hostname\n");
461 printf(" arp -s hostname ether_addr [temp] [pub]\n");
462 printf(" arp -f filename\n");
463 exit(1);
464 }
465
466 int
467 rtmsg(cmd)
468 int cmd;
469 {
470 static int seq;
471 int rlen;
472 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
473 register char *cp = m_rtmsg.m_space;
474 register int l;
475
476 errno = 0;
477 if (cmd == RTM_DELETE)
478 goto doit;
479 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
480 rtm->rtm_flags = flags;
481 rtm->rtm_version = RTM_VERSION;
482
483 switch (cmd) {
484 default:
485 fprintf(stderr, "arp: internal wrong cmd\n");
486 exit(1);
487 case RTM_ADD:
488 rtm->rtm_addrs |= RTA_GATEWAY;
489 rtm->rtm_rmx.rmx_expire = expire_time;
490 rtm->rtm_inits = RTV_EXPIRE;
491 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
492 sin_m.sin_other = 0;
493 if (doing_proxy) {
494 if (export_only)
495 sin_m.sin_other = SIN_PROXY;
496 else {
497 rtm->rtm_addrs |= RTA_NETMASK;
498 rtm->rtm_flags &= ~RTF_HOST;
499 }
500 }
501 /* FALLTHROUGH */
502 case RTM_GET:
503 rtm->rtm_addrs |= RTA_DST;
504 }
505 #define NEXTADDR(w, s) \
506 if (rtm->rtm_addrs & (w)) { \
507 bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
508
509 NEXTADDR(RTA_DST, sin_m);
510 NEXTADDR(RTA_GATEWAY, sdl_m);
511 NEXTADDR(RTA_NETMASK, so_mask);
512
513 rtm->rtm_msglen = cp - (char *)&m_rtmsg;
514 doit:
515 l = rtm->rtm_msglen;
516 rtm->rtm_seq = ++seq;
517 rtm->rtm_type = cmd;
518 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
519 if (errno != ESRCH || cmd != RTM_DELETE) {
520 perror("writing to routing socket");
521 return (-1);
522 }
523 }
524 do {
525 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
526 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
527 if (l < 0)
528 (void) fprintf(stderr, "arp: read from routing socket: %s\n",
529 strerror(errno));
530 return (0);
531 }
532