install correct aliases file
[unix-history] / usr / src / usr.sbin / arp / arp.c
CommitLineData
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
22char 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 28static 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 52extern int errno;
d2c7d54c 53static int kflag;
19b8bc00
MK
54
55main(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 */
103file(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 */
138set(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 */
194get(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 */
250delete(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
289struct 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
301static struct pte *Sysmap;
302
19b8bc00
MK
303/*
304 * Dump the entire arp table
305 */
306dump(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 */
390klseek(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
403ether_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
409ether_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
426usage()
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}