try to make sure that path-addrs always have <angle brackets>
[unix-history] / usr / src / usr.sbin / arp / arp.c
CommitLineData
e0dd6298 1/*
726d166d
KB
2 * Copyright (c) 1984, 1993
3 * The Regents of the University of California. All rights reserved.
e0dd6298
KB
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Sun Microsystems, Inc.
7 *
32ce521f 8 * %sccs.include.redist.c%
e0dd6298
KB
9 */
10
11#ifndef lint
726d166d
KB
12static char copyright[] =
13"@(#) Copyright (c) 1984, 1993\n\
14 The Regents of the University of California. All rights reserved.\n";
e0dd6298
KB
15#endif /* not lint */
16
19b8bc00 17#ifndef lint
b8d2f62b 18static char sccsid[] = "@(#)arp.c 8.2 (Berkeley) %G%";
e0dd6298 19#endif /* not lint */
19b8bc00
MK
20
21/*
22 * arp - display, set, and delete arp table entries
23 */
24
d2c7d54c 25#include <sys/param.h>
d2c7d54c 26#include <sys/file.h>
19b8bc00 27#include <sys/socket.h>
e5eeeda9 28#include <sys/sysctl.h>
d2c7d54c 29
19b8bc00 30#include <net/if.h>
3d364b34
KS
31#include <net/if_dl.h>
32#include <net/if_types.h>
33#include <net/route.h>
34
35#include <netinet/in.h>
19b8bc00
MK
36#include <netinet/if_ether.h>
37
80c4d34b
RC
38#include <arpa/inet.h>
39
3d364b34 40#include <netdb.h>
d2c7d54c
KB
41#include <errno.h>
42#include <nlist.h>
bbf1e72a 43#include <kvm.h>
d2c7d54c 44#include <stdio.h>
7abf8d65 45#include <paths.h>
0f62a41e 46
19b8bc00 47extern int errno;
3d364b34 48static int pid;
3d364b34
KS
49static int nflag;
50static int s = -1;
19b8bc00
MK
51
52main(argc, argv)
d2c7d54c 53 int argc;
19b8bc00
MK
54 char **argv;
55{
d2c7d54c 56 int ch;
19b8bc00 57
3d364b34
KS
58 pid = getpid();
59 while ((ch = getopt(argc, argv, "ands")) != EOF)
d2c7d54c 60 switch((char)ch) {
3d364b34
KS
61 case 'a':
62 dump(0);
d2c7d54c 63 exit(0);
d2c7d54c 64 case 'd':
3d364b34 65 if (argc < 3 || argc > 4)
d2c7d54c 66 usage();
3d364b34 67 delete(argv[2], argv[3]);
d2c7d54c 68 exit(0);
3d364b34
KS
69 case 'n':
70 nflag = 1;
71 continue;
d2c7d54c
KB
72 case 's':
73 if (argc < 4 || argc > 7)
74 usage();
75 exit(set(argc-2, &argv[2]) ? 1 : 0);
d2c7d54c
KB
76 case '?':
77 default:
78 usage();
79 }
80 if (argc != 2)
81 usage();
82 get(argv[1]);
83 exit(0);
19b8bc00
MK
84}
85
86/*
87 * Process a file to set standard arp entries
88 */
89file(name)
90 char *name;
91{
92 FILE *fp;
d2c7d54c 93 int i, retval;
9a642f1d 94 char line[100], arg[5][50], *args[5];
19b8bc00
MK
95
96 if ((fp = fopen(name, "r")) == NULL) {
97 fprintf(stderr, "arp: cannot open %s\n", name);
98 exit(1);
99 }
100 args[0] = &arg[0][0];
101 args[1] = &arg[1][0];
102 args[2] = &arg[2][0];
103 args[3] = &arg[3][0];
9a642f1d 104 args[4] = &arg[4][0];
59ead442 105 retval = 0;
19b8bc00 106 while(fgets(line, 100, fp) != NULL) {
59ead442
KM
107 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
108 arg[3], arg[4]);
19b8bc00
MK
109 if (i < 2) {
110 fprintf(stderr, "arp: bad line: %s\n", line);
59ead442 111 retval = 1;
19b8bc00
MK
112 continue;
113 }
59ead442
KM
114 if (set(i, args))
115 retval = 1;
19b8bc00
MK
116 }
117 fclose(fp);
59ead442 118 return (retval);
19b8bc00
MK
119}
120
3d364b34
KS
121getsocket() {
122 if (s < 0) {
123 s = socket(PF_ROUTE, SOCK_RAW, 0);
124 if (s < 0) {
125 perror("arp: socket");
126 exit(1);
127 }
128 }
129}
130
131struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
132struct sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m;
133struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
134int expire_time, flags, export_only, doing_proxy, found_entry;
135struct {
136 struct rt_msghdr m_rtm;
137 char m_space[512];
138} m_rtmsg;
139
19b8bc00
MK
140/*
141 * Set an individual arp entry
142 */
143set(argc, argv)
d2c7d54c 144 int argc;
19b8bc00
MK
145 char **argv;
146{
19b8bc00 147 struct hostent *hp;
3d364b34
KS
148 register struct sockaddr_inarp *sin = &sin_m;
149 register struct sockaddr_dl *sdl;
150 register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
b51f832f 151 u_char *ea;
19b8bc00
MK
152 char *host = argv[0], *eaddr = argv[1];
153
3d364b34 154 getsocket();
19b8bc00
MK
155 argc -= 2;
156 argv += 2;
3d364b34
KS
157 sdl_m = blank_sdl;
158 sin_m = blank_sin;
6faa5fd4
MK
159 sin->sin_addr.s_addr = inet_addr(host);
160 if (sin->sin_addr.s_addr == -1) {
2b2b1758
KB
161 if (!(hp = gethostbyname(host))) {
162 fprintf(stderr, "arp: %s: ", host);
163 herror((char *)NULL);
59ead442 164 return (1);
6faa5fd4
MK
165 }
166 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
167 sizeof sin->sin_addr);
168 }
3d364b34
KS
169 ea = (u_char *)LLADDR(&sdl_m);
170 if (ether_aton(eaddr, ea) == 0)
171 sdl_m.sdl_alen = 6;
172 doing_proxy = flags = export_only = expire_time = 0;
6faa5fd4 173 while (argc-- > 0) {
3d364b34
KS
174 if (strncmp(argv[0], "temp", 4) == 0) {
175 struct timeval time;
176 gettimeofday(&time, 0);
177 expire_time = time.tv_sec + 20 * 60;
178 }
3ad154fa
KB
179 else if (strncmp(argv[0], "pub", 3) == 0) {
180 flags |= RTF_ANNOUNCE;
3d364b34 181 doing_proxy = SIN_PROXY;
3ad154fa 182 } else if (strncmp(argv[0], "trail", 5) == 0) {
e270ebe8
KS
183 printf("%s: Sending trailers is no longer supported\n",
184 host);
185 }
19b8bc00
MK
186 argv++;
187 }
3d364b34
KS
188tryagain:
189 if (rtmsg(RTM_GET) < 0) {
19b8bc00 190 perror(host);
3d364b34 191 return (1);
19b8bc00 192 }
3d364b34
KS
193 sin = (struct sockaddr_inarp *)(rtm + 1);
194 sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
195 if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
196 if (sdl->sdl_family == AF_LINK &&
197 (rtm->rtm_flags & RTF_LLINFO) &&
198 !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
199 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
200 case IFT_ISO88024: case IFT_ISO88025:
201 goto overwrite;
202 }
203 if (doing_proxy == 0) {
204 printf("set: can only proxy for %s\n", host);
205 return (1);
206 }
207 if (sin_m.sin_other & SIN_PROXY) {
208 printf("set: proxy entry exists for non 802 device\n");
209 return(1);
210 }
211 sin_m.sin_other = SIN_PROXY;
212 export_only = 1;
213 goto tryagain;
214 }
215overwrite:
216 if (sdl->sdl_family != AF_LINK) {
217 printf("cannot intuit interface index and type for %s\n", host);
218 return (1);
219 }
220 sdl_m.sdl_type = sdl->sdl_type;
221 sdl_m.sdl_index = sdl->sdl_index;
222 return (rtmsg(RTM_ADD));
19b8bc00
MK
223}
224
19b8bc00
MK
225/*
226 * Display an individual arp entry
227 */
228get(host)
229 char *host;
230{
19b8bc00 231 struct hostent *hp;
3d364b34 232 struct sockaddr_inarp *sin = &sin_m;
b51f832f 233 u_char *ea;
19b8bc00 234
3d364b34 235 sin_m = blank_sin;
6faa5fd4
MK
236 sin->sin_addr.s_addr = inet_addr(host);
237 if (sin->sin_addr.s_addr == -1) {
2b2b1758
KB
238 if (!(hp = gethostbyname(host))) {
239 fprintf(stderr, "arp: %s: ", host);
240 herror((char *)NULL);
6faa5fd4
MK
241 exit(1);
242 }
243 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
244 sizeof sin->sin_addr);
245 }
3d364b34
KS
246 dump(sin->sin_addr.s_addr);
247 if (found_entry == 0) {
248 printf("%s (%s) -- no entry\n",
249 host, inet_ntoa(sin->sin_addr));
d2c7d54c
KB
250 exit(1);
251 }
19b8bc00
MK
252}
253
254/*
255 * Delete an arp entry
256 */
3d364b34 257delete(host, info)
19b8bc00 258 char *host;
3d364b34 259 char *info;
19b8bc00 260{
19b8bc00 261 struct hostent *hp;
3d364b34
KS
262 register struct sockaddr_inarp *sin = &sin_m;
263 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
264 struct sockaddr_dl *sdl;
265 u_char *ea;
266 char *eaddr;
19b8bc00 267
3d364b34
KS
268 if (info && strncmp(info, "pro", 3) )
269 export_only = 1;
270 getsocket();
271 sin_m = blank_sin;
6faa5fd4
MK
272 sin->sin_addr.s_addr = inet_addr(host);
273 if (sin->sin_addr.s_addr == -1) {
2b2b1758
KB
274 if (!(hp = gethostbyname(host))) {
275 fprintf(stderr, "arp: %s: ", host);
276 herror((char *)NULL);
3d364b34 277 return (1);
6faa5fd4
MK
278 }
279 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
280 sizeof sin->sin_addr);
281 }
3d364b34
KS
282tryagain:
283 if (rtmsg(RTM_GET) < 0) {
284 perror(host);
285 return (1);
d2c7d54c 286 }
3d364b34
KS
287 sin = (struct sockaddr_inarp *)(rtm + 1);
288 sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
289 if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
290 if (sdl->sdl_family == AF_LINK &&
291 (rtm->rtm_flags & RTF_LLINFO) &&
292 !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
293 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
294 case IFT_ISO88024: case IFT_ISO88025:
295 goto delete;
296 }
19b8bc00 297 }
3d364b34
KS
298 if (sin_m.sin_other & SIN_PROXY) {
299 fprintf(stderr, "delete: can't locate %s\n",host);
300 return (1);
301 } else {
302 sin_m.sin_other = SIN_PROXY;
303 goto tryagain;
304 }
305delete:
306 if (sdl->sdl_family != AF_LINK) {
307 printf("cannot locate %s\n", host);
308 return (1);
309 }
310 if (rtmsg(RTM_DELETE) == 0)
311 printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
19b8bc00
MK
312}
313
19b8bc00
MK
314/*
315 * Dump the entire arp table
316 */
3d364b34
KS
317dump(addr)
318u_long addr;
19b8bc00 319{
e5eeeda9
KM
320 int mib[6];
321 size_t needed;
3d364b34
KS
322 char *host, *malloc(), *lim, *buf, *next;
323 struct rt_msghdr *rtm;
324 struct sockaddr_inarp *sin;
325 struct sockaddr_dl *sdl;
d2c7d54c 326 extern int h_errno;
19b8bc00 327 struct hostent *hp;
19b8bc00 328
3d364b34
KS
329 if (nflag == 0)
330 hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
331 sizeof sin->sin_addr, AF_INET);
6faa5fd4
MK
332 else
333 hp = 0;
19b8bc00
MK
334 if (hp)
335 host = hp->h_name;
6faa5fd4 336 else {
19b8bc00 337 host = "?";
6faa5fd4 338 if (h_errno == TRY_AGAIN)
3d364b34 339 nflag = 1;
6faa5fd4 340 }
3d364b34
KS
341 printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
342 if (sdl->sdl_alen)
343 ether_print(LLADDR(sdl));
19b8bc00
MK
344 else
345 printf("(incomplete)");
3d364b34 346 if (rtm->rtm_rmx.rmx_expire == 0)
d2c7d54c 347 printf(" permanent");
3d364b34
KS
348 if (sin->sin_other & SIN_PROXY)
349 printf(" published (proxy only)");
3d364b34
KS
350 if (rtm->rtm_addrs & RTA_NETMASK) {
351 sin = (struct sockaddr_inarp *)
352 (sdl->sdl_len + (char *)sdl);
353 if (sin->sin_addr.s_addr == 0xffffffff)
354 printf(" published");
355 if (sin->sin_len != 8)
356 printf("(wierd)");
357 }
19b8bc00
MK
358 printf("\n");
359 }
b51f832f
MK
360ether_print(cp)
361 u_char *cp;
19b8bc00 362{
19b8bc00
MK
363 printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
364}
365
366ether_aton(a, n)
367 char *a;
b51f832f 368 u_char *n;
19b8bc00
MK
369{
370 int i, o[6];
371
372 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
373 &o[3], &o[4], &o[5]);
374 if (i != 6) {
375 fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
376 return (1);
377 }
378 for (i=0; i<6; i++)
b51f832f 379 n[i] = o[i];
19b8bc00
MK
380 return (0);
381}
382
383usage()
384{
d2c7d54c 385 printf("usage: arp hostname\n");
7abf8d65 386 printf(" arp -a [kernel] [kernel_memory]\n");
19b8bc00 387 printf(" arp -d hostname\n");
e270ebe8 388 printf(" arp -s hostname ether_addr [temp] [pub]\n");
19b8bc00 389 printf(" arp -f filename\n");
d2c7d54c 390 exit(1);
19b8bc00 391}
3d364b34
KS
392
393rtmsg(cmd)
394{
395 static int seq;
396 int rlen;
397 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
398 register char *cp = m_rtmsg.m_space;
399 register int l;
400
401 errno = 0;
402 if (cmd == RTM_DELETE)
403 goto doit;
404 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
405 rtm->rtm_flags = flags;
406 rtm->rtm_version = RTM_VERSION;
407
408 switch (cmd) {
409 default:
410 fprintf(stderr, "arp: internal wrong cmd\n");
411 exit(1);
412 case RTM_ADD:
413 rtm->rtm_addrs |= RTA_GATEWAY;
414 rtm->rtm_rmx.rmx_expire = expire_time;
415 rtm->rtm_inits = RTV_EXPIRE;
4937f90f 416 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
3d364b34
KS
417 sin_m.sin_other = 0;
418 if (doing_proxy) {
419 if (export_only)
420 sin_m.sin_other = SIN_PROXY;
421 else {
422 rtm->rtm_addrs |= RTA_NETMASK;
423 rtm->rtm_flags &= ~RTF_HOST;
424 }
425 }
b8d2f62b 426 /* FALLTHROUGH */
3d364b34
KS
427 case RTM_GET:
428 rtm->rtm_addrs |= RTA_DST;
429 }
430#define NEXTADDR(w, s) \
431 if (rtm->rtm_addrs & (w)) { \
432 bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
433
434 NEXTADDR(RTA_DST, sin_m);
435 NEXTADDR(RTA_GATEWAY, sdl_m);
436 NEXTADDR(RTA_NETMASK, so_mask);
437
438 rtm->rtm_msglen = cp - (char *)&m_rtmsg;
439doit:
440 l = rtm->rtm_msglen;
441 rtm->rtm_seq = ++seq;
442 rtm->rtm_type = cmd;
443 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
444 if (errno != ESRCH || cmd != RTM_DELETE) {
445 perror("writing to routing socket");
446 return (-1);
447 }
448 }
449 do {
450 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
451 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
452 if (l < 0)
453 (void) fprintf(stderr, "arp: read from routing socket: %s\n",
454 strerror(errno));
455 return (0);
456}
457
458quit(msg)
459char *msg;
460{
461 fprintf(stderr, "%s\n", msg);
462 exit(1);
463}