Commit | Line | Data |
---|---|---|
e0dd6298 KB |
1 | /* |
2 | * Copyright (c) 1984 Regents of the University of California. | |
3 | * 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 are permitted | |
9 | * provided that the above copyright notice and this paragraph are | |
10 | * duplicated in all such forms and that any documentation, | |
11 | * advertising materials, and other materials related to such | |
12 | * distribution and use acknowledge that the software was developed | |
13 | * by the University of California, Berkeley. The name of the | |
14 | * University may not be used to endorse or promote products derived | |
15 | * from this software without specific prior written permission. | |
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
18 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
19 | */ | |
20 | ||
21 | #ifndef lint | |
22 | char copyright[] = | |
23 | "@(#) Copyright (c) 1984 Regents of the University of California.\n\ | |
24 | All rights reserved.\n"; | |
25 | #endif /* not lint */ | |
26 | ||
19b8bc00 | 27 | #ifndef lint |
2b2b1758 | 28 | static char sccsid[] = "@(#)arp.c 5.8 (Berkeley) %G%"; |
e0dd6298 | 29 | #endif /* not lint */ |
19b8bc00 MK |
30 | |
31 | /* | |
32 | * arp - display, set, and delete arp table entries | |
33 | */ | |
34 | ||
d2c7d54c KB |
35 | #include <machine/pte.h> |
36 | ||
37 | #include <sys/param.h> | |
38 | #include <sys/vmmac.h> | |
39 | #include <sys/file.h> | |
19b8bc00 | 40 | #include <sys/socket.h> |
19b8bc00 | 41 | #include <sys/ioctl.h> |
d2c7d54c | 42 | |
19b8bc00 | 43 | #include <netdb.h> |
d2c7d54c | 44 | #include <netinet/in.h> |
19b8bc00 MK |
45 | #include <net/if.h> |
46 | #include <netinet/if_ether.h> | |
47 | ||
d2c7d54c KB |
48 | #include <errno.h> |
49 | #include <nlist.h> | |
50 | #include <stdio.h> | |
51 | ||
19b8bc00 | 52 | extern int errno; |
d2c7d54c | 53 | static int kflag; |
19b8bc00 MK |
54 | |
55 | main(argc, argv) | |
d2c7d54c | 56 | int argc; |
19b8bc00 MK |
57 | char **argv; |
58 | { | |
d2c7d54c | 59 | int ch; |
19b8bc00 | 60 | |
d2c7d54c KB |
61 | while ((ch = getopt(argc, argv, "adsf")) != EOF) |
62 | switch((char)ch) { | |
63 | case 'a': { | |
64 | char *mem; | |
65 | ||
66 | if (argc > 4) | |
67 | usage(); | |
68 | if (argc == 4) { | |
69 | kflag = 1; | |
70 | mem = argv[3]; | |
71 | } | |
72 | else | |
73 | mem = "/dev/kmem"; | |
74 | dump((argc >= 3) ? argv[2] : "/vmunix", mem); | |
75 | exit(0); | |
76 | } | |
77 | case 'd': | |
78 | if (argc != 3) | |
79 | usage(); | |
80 | delete(argv[2]); | |
81 | exit(0); | |
82 | case 's': | |
83 | if (argc < 4 || argc > 7) | |
84 | usage(); | |
85 | exit(set(argc-2, &argv[2]) ? 1 : 0); | |
86 | case 'f': | |
87 | if (argc != 3) | |
88 | usage(); | |
89 | exit (file(argv[2]) ? 1 : 0); | |
90 | case '?': | |
91 | default: | |
92 | usage(); | |
93 | } | |
94 | if (argc != 2) | |
95 | usage(); | |
96 | get(argv[1]); | |
97 | exit(0); | |
19b8bc00 MK |
98 | } |
99 | ||
100 | /* | |
101 | * Process a file to set standard arp entries | |
102 | */ | |
103 | file(name) | |
104 | char *name; | |
105 | { | |
106 | FILE *fp; | |
d2c7d54c | 107 | int i, retval; |
9a642f1d | 108 | char line[100], arg[5][50], *args[5]; |
19b8bc00 MK |
109 | |
110 | if ((fp = fopen(name, "r")) == NULL) { | |
111 | fprintf(stderr, "arp: cannot open %s\n", name); | |
112 | exit(1); | |
113 | } | |
114 | args[0] = &arg[0][0]; | |
115 | args[1] = &arg[1][0]; | |
116 | args[2] = &arg[2][0]; | |
117 | args[3] = &arg[3][0]; | |
9a642f1d | 118 | args[4] = &arg[4][0]; |
59ead442 | 119 | retval = 0; |
19b8bc00 | 120 | while(fgets(line, 100, fp) != NULL) { |
59ead442 KM |
121 | i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], |
122 | arg[3], arg[4]); | |
19b8bc00 MK |
123 | if (i < 2) { |
124 | fprintf(stderr, "arp: bad line: %s\n", line); | |
59ead442 | 125 | retval = 1; |
19b8bc00 MK |
126 | continue; |
127 | } | |
59ead442 KM |
128 | if (set(i, args)) |
129 | retval = 1; | |
19b8bc00 MK |
130 | } |
131 | fclose(fp); | |
59ead442 | 132 | return (retval); |
19b8bc00 MK |
133 | } |
134 | ||
135 | /* | |
136 | * Set an individual arp entry | |
137 | */ | |
138 | set(argc, argv) | |
d2c7d54c | 139 | int argc; |
19b8bc00 MK |
140 | char **argv; |
141 | { | |
142 | struct arpreq ar; | |
143 | struct hostent *hp; | |
144 | struct sockaddr_in *sin; | |
b51f832f | 145 | u_char *ea; |
19b8bc00 MK |
146 | int s; |
147 | char *host = argv[0], *eaddr = argv[1]; | |
148 | ||
149 | argc -= 2; | |
150 | argv += 2; | |
19b8bc00 | 151 | bzero((caddr_t)&ar, sizeof ar); |
19b8bc00 | 152 | sin = (struct sockaddr_in *)&ar.arp_pa; |
6faa5fd4 MK |
153 | sin->sin_family = AF_INET; |
154 | sin->sin_addr.s_addr = inet_addr(host); | |
155 | if (sin->sin_addr.s_addr == -1) { | |
2b2b1758 KB |
156 | if (!(hp = gethostbyname(host))) { |
157 | fprintf(stderr, "arp: %s: ", host); | |
158 | herror((char *)NULL); | |
59ead442 | 159 | return (1); |
6faa5fd4 MK |
160 | } |
161 | bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, | |
162 | sizeof sin->sin_addr); | |
163 | } | |
b51f832f | 164 | ea = (u_char *)ar.arp_ha.sa_data; |
19b8bc00 | 165 | if (ether_aton(eaddr, ea)) |
59ead442 | 166 | return (1); |
19b8bc00 | 167 | ar.arp_flags = ATF_PERM; |
6faa5fd4 | 168 | while (argc-- > 0) { |
19b8bc00 MK |
169 | if (strncmp(argv[0], "temp", 4) == 0) |
170 | ar.arp_flags &= ~ATF_PERM; | |
d2c7d54c | 171 | else if (strncmp(argv[0], "pub", 3) == 0) |
19b8bc00 | 172 | ar.arp_flags |= ATF_PUBL; |
d2c7d54c | 173 | else if (strncmp(argv[0], "trail", 5) == 0) |
9a642f1d | 174 | ar.arp_flags |= ATF_USETRAILERS; |
19b8bc00 MK |
175 | argv++; |
176 | } | |
177 | ||
178 | s = socket(AF_INET, SOCK_DGRAM, 0); | |
179 | if (s < 0) { | |
d2c7d54c KB |
180 | perror("arp: socket"); |
181 | exit(1); | |
182 | } | |
19b8bc00 MK |
183 | if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) { |
184 | perror(host); | |
185 | exit(1); | |
186 | } | |
187 | close(s); | |
59ead442 | 188 | return (0); |
19b8bc00 MK |
189 | } |
190 | ||
19b8bc00 MK |
191 | /* |
192 | * Display an individual arp entry | |
193 | */ | |
194 | get(host) | |
195 | char *host; | |
196 | { | |
197 | struct arpreq ar; | |
198 | struct hostent *hp; | |
199 | struct sockaddr_in *sin; | |
b51f832f | 200 | u_char *ea; |
19b8bc00 | 201 | int s; |
d2c7d54c | 202 | char *inet_ntoa(); |
19b8bc00 | 203 | |
19b8bc00 MK |
204 | bzero((caddr_t)&ar, sizeof ar); |
205 | ar.arp_pa.sa_family = AF_INET; | |
206 | sin = (struct sockaddr_in *)&ar.arp_pa; | |
6faa5fd4 MK |
207 | sin->sin_family = AF_INET; |
208 | sin->sin_addr.s_addr = inet_addr(host); | |
209 | if (sin->sin_addr.s_addr == -1) { | |
2b2b1758 KB |
210 | if (!(hp = gethostbyname(host))) { |
211 | fprintf(stderr, "arp: %s: ", host); | |
212 | herror((char *)NULL); | |
6faa5fd4 MK |
213 | exit(1); |
214 | } | |
215 | bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, | |
216 | sizeof sin->sin_addr); | |
217 | } | |
19b8bc00 MK |
218 | s = socket(AF_INET, SOCK_DGRAM, 0); |
219 | if (s < 0) { | |
d2c7d54c KB |
220 | perror("arp: socket"); |
221 | exit(1); | |
222 | } | |
19b8bc00 MK |
223 | if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) { |
224 | if (errno == ENXIO) | |
225 | printf("%s (%s) -- no entry\n", | |
226 | host, inet_ntoa(sin->sin_addr)); | |
227 | else | |
228 | perror("SIOCGARP"); | |
229 | exit(1); | |
230 | } | |
231 | close(s); | |
b51f832f | 232 | ea = (u_char *)ar.arp_ha.sa_data; |
19b8bc00 MK |
233 | printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr)); |
234 | if (ar.arp_flags & ATF_COM) | |
235 | ether_print(ea); | |
236 | else | |
237 | printf("(incomplete)"); | |
d2c7d54c KB |
238 | if (ar.arp_flags & ATF_PERM) |
239 | printf(" permanent"); | |
240 | if (ar.arp_flags & ATF_PUBL) | |
241 | printf(" published"); | |
242 | if (ar.arp_flags & ATF_USETRAILERS) | |
243 | printf(" trailers"); | |
19b8bc00 MK |
244 | printf("\n"); |
245 | } | |
246 | ||
247 | /* | |
248 | * Delete an arp entry | |
249 | */ | |
250 | delete(host) | |
251 | char *host; | |
252 | { | |
253 | struct arpreq ar; | |
254 | struct hostent *hp; | |
255 | struct sockaddr_in *sin; | |
256 | int s; | |
257 | ||
19b8bc00 MK |
258 | bzero((caddr_t)&ar, sizeof ar); |
259 | ar.arp_pa.sa_family = AF_INET; | |
260 | sin = (struct sockaddr_in *)&ar.arp_pa; | |
6faa5fd4 MK |
261 | sin->sin_family = AF_INET; |
262 | sin->sin_addr.s_addr = inet_addr(host); | |
263 | if (sin->sin_addr.s_addr == -1) { | |
2b2b1758 KB |
264 | if (!(hp = gethostbyname(host))) { |
265 | fprintf(stderr, "arp: %s: ", host); | |
266 | herror((char *)NULL); | |
6faa5fd4 MK |
267 | exit(1); |
268 | } | |
269 | bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, | |
270 | sizeof sin->sin_addr); | |
271 | } | |
19b8bc00 MK |
272 | s = socket(AF_INET, SOCK_DGRAM, 0); |
273 | if (s < 0) { | |
d2c7d54c KB |
274 | perror("arp: socket"); |
275 | exit(1); | |
276 | } | |
19b8bc00 MK |
277 | if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) { |
278 | if (errno == ENXIO) | |
279 | printf("%s (%s) -- no entry\n", | |
280 | host, inet_ntoa(sin->sin_addr)); | |
281 | else | |
282 | perror("SIOCDARP"); | |
283 | exit(1); | |
284 | } | |
285 | close(s); | |
286 | printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr)); | |
287 | } | |
288 | ||
289 | struct nlist nl[] = { | |
290 | #define X_ARPTAB 0 | |
291 | { "_arptab" }, | |
292 | #define X_ARPTAB_SIZE 1 | |
293 | { "_arptab_size" }, | |
d2c7d54c KB |
294 | #define N_SYSMAP 2 |
295 | { "_Sysmap" }, | |
296 | #define N_SYSSIZE 3 | |
297 | { "_Syssize" }, | |
19b8bc00 MK |
298 | { "" }, |
299 | }; | |
300 | ||
d2c7d54c KB |
301 | static struct pte *Sysmap; |
302 | ||
19b8bc00 MK |
303 | /* |
304 | * Dump the entire arp table | |
305 | */ | |
306 | dump(kernel, mem) | |
307 | char *kernel, *mem; | |
308 | { | |
d2c7d54c | 309 | extern int h_errno; |
19b8bc00 MK |
310 | struct arptab *at; |
311 | struct hostent *hp; | |
d2c7d54c KB |
312 | int bynumber, mf, arptab_size, sz; |
313 | char *host, *malloc(); | |
314 | off_t lseek(); | |
19b8bc00 | 315 | |
d2c7d54c | 316 | if (nlist(kernel, nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) { |
19b8bc00 MK |
317 | fprintf(stderr, "arp: %s: bad namelist\n", kernel); |
318 | exit(1); | |
319 | } | |
d2c7d54c KB |
320 | mf = open(mem, O_RDONLY); |
321 | if (mf < 0) { | |
7f51d991 | 322 | fprintf(stderr, "arp: cannot open %s\n", mem); |
19b8bc00 MK |
323 | exit(1); |
324 | } | |
d2c7d54c KB |
325 | if (kflag) { |
326 | off_t off; | |
327 | ||
328 | Sysmap = (struct pte *) | |
329 | malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); | |
330 | if (!Sysmap) { | |
331 | fputs("arp: can't get memory for Sysmap.\n", stderr); | |
332 | exit(1); | |
333 | } | |
334 | off = nl[N_SYSMAP].n_value & ~KERNBASE; | |
335 | (void)lseek(mf, off, L_SET); | |
336 | (void)read(mf, (char *)Sysmap, | |
337 | (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); | |
338 | } | |
339 | klseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, L_SET); | |
19b8bc00 | 340 | read(mf, &arptab_size, sizeof arptab_size); |
d2c7d54c | 341 | if (arptab_size <= 0 || arptab_size > 1000) { |
19b8bc00 MK |
342 | fprintf(stderr, "arp: %s: namelist wrong\n", kernel); |
343 | exit(1); | |
344 | } | |
345 | sz = arptab_size * sizeof (struct arptab); | |
d2c7d54c | 346 | at = (struct arptab *)malloc((u_int)sz); |
19b8bc00 | 347 | if (at == NULL) { |
d2c7d54c | 348 | fputs("arp: can't get memory for arptab.\n", stderr); |
19b8bc00 MK |
349 | exit(1); |
350 | } | |
d2c7d54c | 351 | klseek(mf, (long)nl[X_ARPTAB].n_value, L_SET); |
19b8bc00 MK |
352 | if (read(mf, (char *)at, sz) != sz) { |
353 | perror("arp: error reading arptab"); | |
354 | exit(1); | |
355 | } | |
356 | close(mf); | |
d2c7d54c | 357 | for (bynumber = 0; arptab_size-- > 0; at++) { |
19b8bc00 MK |
358 | if (at->at_iaddr.s_addr == 0 || at->at_flags == 0) |
359 | continue; | |
6faa5fd4 MK |
360 | if (bynumber == 0) |
361 | hp = gethostbyaddr((caddr_t)&at->at_iaddr, | |
362 | sizeof at->at_iaddr, AF_INET); | |
363 | else | |
364 | hp = 0; | |
19b8bc00 MK |
365 | if (hp) |
366 | host = hp->h_name; | |
6faa5fd4 | 367 | else { |
19b8bc00 | 368 | host = "?"; |
6faa5fd4 MK |
369 | if (h_errno == TRY_AGAIN) |
370 | bynumber = 1; | |
371 | } | |
19b8bc00 MK |
372 | printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr)); |
373 | if (at->at_flags & ATF_COM) | |
b51f832f | 374 | ether_print(at->at_enaddr); |
19b8bc00 MK |
375 | else |
376 | printf("(incomplete)"); | |
d2c7d54c KB |
377 | if (at->at_flags & ATF_PERM) |
378 | printf(" permanent"); | |
379 | if (at->at_flags & ATF_PUBL) | |
380 | printf(" published"); | |
381 | if (at->at_flags & ATF_USETRAILERS) | |
382 | printf(" trailers"); | |
19b8bc00 MK |
383 | printf("\n"); |
384 | } | |
385 | } | |
386 | ||
d2c7d54c KB |
387 | /* |
388 | * Seek into the kernel for a value. | |
389 | */ | |
390 | klseek(fd, base, off) | |
391 | int fd, off; | |
392 | off_t base; | |
393 | { | |
394 | off_t lseek(); | |
395 | ||
396 | if (kflag) { /* get kernel pte */ | |
397 | base &= ~KERNBASE; | |
398 | base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET); | |
399 | } | |
400 | (void)lseek(fd, base, off); | |
401 | } | |
402 | ||
b51f832f MK |
403 | ether_print(cp) |
404 | u_char *cp; | |
19b8bc00 | 405 | { |
19b8bc00 MK |
406 | printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); |
407 | } | |
408 | ||
409 | ether_aton(a, n) | |
410 | char *a; | |
b51f832f | 411 | u_char *n; |
19b8bc00 MK |
412 | { |
413 | int i, o[6]; | |
414 | ||
415 | i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], | |
416 | &o[3], &o[4], &o[5]); | |
417 | if (i != 6) { | |
418 | fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a); | |
419 | return (1); | |
420 | } | |
421 | for (i=0; i<6; i++) | |
b51f832f | 422 | n[i] = o[i]; |
19b8bc00 MK |
423 | return (0); |
424 | } | |
425 | ||
426 | usage() | |
427 | { | |
d2c7d54c | 428 | printf("usage: arp hostname\n"); |
19b8bc00 MK |
429 | printf(" arp -a [/vmunix] [/dev/kmem]\n"); |
430 | printf(" arp -d hostname\n"); | |
59ead442 | 431 | printf(" arp -s hostname ether_addr [temp] [pub] [trail]\n"); |
19b8bc00 | 432 | printf(" arp -f filename\n"); |
d2c7d54c | 433 | exit(1); |
19b8bc00 | 434 | } |