xref: /original-bsd/usr.sbin/arp/arp.c (revision a141c157)
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 
27 #ifndef lint
28 static char sccsid[] = "@(#)arp.c	5.8 (Berkeley) 10/10/88";
29 #endif /* not lint */
30 
31 /*
32  * arp - display, set, and delete arp table entries
33  */
34 
35 #include <machine/pte.h>
36 
37 #include <sys/param.h>
38 #include <sys/vmmac.h>
39 #include <sys/file.h>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 
43 #include <netdb.h>
44 #include <netinet/in.h>
45 #include <net/if.h>
46 #include <netinet/if_ether.h>
47 
48 #include <errno.h>
49 #include <nlist.h>
50 #include <stdio.h>
51 
52 extern int errno;
53 static int kflag;
54 
55 main(argc, argv)
56 	int argc;
57 	char **argv;
58 {
59 	int ch;
60 
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);
98 }
99 
100 /*
101  * Process a file to set standard arp entries
102  */
103 file(name)
104 	char *name;
105 {
106 	FILE *fp;
107 	int i, retval;
108 	char line[100], arg[5][50], *args[5];
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];
118 	args[4] = &arg[4][0];
119 	retval = 0;
120 	while(fgets(line, 100, fp) != NULL) {
121 		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
122 		    arg[3], arg[4]);
123 		if (i < 2) {
124 			fprintf(stderr, "arp: bad line: %s\n", line);
125 			retval = 1;
126 			continue;
127 		}
128 		if (set(i, args))
129 			retval = 1;
130 	}
131 	fclose(fp);
132 	return (retval);
133 }
134 
135 /*
136  * Set an individual arp entry
137  */
138 set(argc, argv)
139 	int argc;
140 	char **argv;
141 {
142 	struct arpreq ar;
143 	struct hostent *hp;
144 	struct sockaddr_in *sin;
145 	u_char *ea;
146 	int s;
147 	char *host = argv[0], *eaddr = argv[1];
148 
149 	argc -= 2;
150 	argv += 2;
151 	bzero((caddr_t)&ar, sizeof ar);
152 	sin = (struct sockaddr_in *)&ar.arp_pa;
153 	sin->sin_family = AF_INET;
154 	sin->sin_addr.s_addr = inet_addr(host);
155 	if (sin->sin_addr.s_addr == -1) {
156 		if (!(hp = gethostbyname(host))) {
157 			fprintf(stderr, "arp: %s: ", host);
158 			herror((char *)NULL);
159 			return (1);
160 		}
161 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
162 		    sizeof sin->sin_addr);
163 	}
164 	ea = (u_char *)ar.arp_ha.sa_data;
165 	if (ether_aton(eaddr, ea))
166 		return (1);
167 	ar.arp_flags = ATF_PERM;
168 	while (argc-- > 0) {
169 		if (strncmp(argv[0], "temp", 4) == 0)
170 			ar.arp_flags &= ~ATF_PERM;
171 		else if (strncmp(argv[0], "pub", 3) == 0)
172 			ar.arp_flags |= ATF_PUBL;
173 		else if (strncmp(argv[0], "trail", 5) == 0)
174 			ar.arp_flags |= ATF_USETRAILERS;
175 		argv++;
176 	}
177 
178 	s = socket(AF_INET, SOCK_DGRAM, 0);
179 	if (s < 0) {
180 		perror("arp: socket");
181 		exit(1);
182 	}
183 	if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) {
184 		perror(host);
185 		exit(1);
186 	}
187 	close(s);
188 	return (0);
189 }
190 
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;
200 	u_char *ea;
201 	int s;
202 	char *inet_ntoa();
203 
204 	bzero((caddr_t)&ar, sizeof ar);
205 	ar.arp_pa.sa_family = AF_INET;
206 	sin = (struct sockaddr_in *)&ar.arp_pa;
207 	sin->sin_family = AF_INET;
208 	sin->sin_addr.s_addr = inet_addr(host);
209 	if (sin->sin_addr.s_addr == -1) {
210 		if (!(hp = gethostbyname(host))) {
211 			fprintf(stderr, "arp: %s: ", host);
212 			herror((char *)NULL);
213 			exit(1);
214 		}
215 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
216 		    sizeof sin->sin_addr);
217 	}
218 	s = socket(AF_INET, SOCK_DGRAM, 0);
219 	if (s < 0) {
220 		perror("arp: socket");
221 		exit(1);
222 	}
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);
232 	ea = (u_char *)ar.arp_ha.sa_data;
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)");
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");
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 
258 	bzero((caddr_t)&ar, sizeof ar);
259 	ar.arp_pa.sa_family = AF_INET;
260 	sin = (struct sockaddr_in *)&ar.arp_pa;
261 	sin->sin_family = AF_INET;
262 	sin->sin_addr.s_addr = inet_addr(host);
263 	if (sin->sin_addr.s_addr == -1) {
264 		if (!(hp = gethostbyname(host))) {
265 			fprintf(stderr, "arp: %s: ", host);
266 			herror((char *)NULL);
267 			exit(1);
268 		}
269 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
270 		    sizeof sin->sin_addr);
271 	}
272 	s = socket(AF_INET, SOCK_DGRAM, 0);
273 	if (s < 0) {
274 		perror("arp: socket");
275 		exit(1);
276 	}
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" },
294 #define	N_SYSMAP	2
295 	{ "_Sysmap" },
296 #define	N_SYSSIZE	3
297 	{ "_Syssize" },
298 	{ "" },
299 };
300 
301 static struct pte *Sysmap;
302 
303 /*
304  * Dump the entire arp table
305  */
306 dump(kernel, mem)
307 	char *kernel, *mem;
308 {
309 	extern int h_errno;
310 	struct arptab *at;
311 	struct hostent *hp;
312 	int bynumber, mf, arptab_size, sz;
313 	char *host, *malloc();
314 	off_t lseek();
315 
316 	if (nlist(kernel, nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) {
317 		fprintf(stderr, "arp: %s: bad namelist\n", kernel);
318 		exit(1);
319 	}
320 	mf = open(mem, O_RDONLY);
321 	if (mf < 0) {
322 		fprintf(stderr, "arp: cannot open %s\n", mem);
323 		exit(1);
324 	}
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);
340 	read(mf, &arptab_size, sizeof arptab_size);
341 	if (arptab_size <= 0 || arptab_size > 1000) {
342 		fprintf(stderr, "arp: %s: namelist wrong\n", kernel);
343 		exit(1);
344 	}
345 	sz = arptab_size * sizeof (struct arptab);
346 	at = (struct arptab *)malloc((u_int)sz);
347 	if (at == NULL) {
348 		fputs("arp: can't get memory for arptab.\n", stderr);
349 		exit(1);
350 	}
351 	klseek(mf, (long)nl[X_ARPTAB].n_value, L_SET);
352 	if (read(mf, (char *)at, sz) != sz) {
353 		perror("arp: error reading arptab");
354 		exit(1);
355 	}
356 	close(mf);
357 	for (bynumber = 0; arptab_size-- > 0; at++) {
358 		if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
359 			continue;
360 		if (bynumber == 0)
361 			hp = gethostbyaddr((caddr_t)&at->at_iaddr,
362 			    sizeof at->at_iaddr, AF_INET);
363 		else
364 			hp = 0;
365 		if (hp)
366 			host = hp->h_name;
367 		else {
368 			host = "?";
369 			if (h_errno == TRY_AGAIN)
370 				bynumber = 1;
371 		}
372 		printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr));
373 		if (at->at_flags & ATF_COM)
374 			ether_print(at->at_enaddr);
375 		else
376 			printf("(incomplete)");
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");
383 		printf("\n");
384 	}
385 }
386 
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 
403 ether_print(cp)
404 	u_char *cp;
405 {
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;
411 	u_char *n;
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++)
422 		n[i] = o[i];
423 	return (0);
424 }
425 
426 usage()
427 {
428 	printf("usage: arp hostname\n");
429 	printf("       arp -a [/vmunix] [/dev/kmem]\n");
430 	printf("       arp -d hostname\n");
431 	printf("       arp -s hostname ether_addr [temp] [pub] [trail]\n");
432 	printf("       arp -f filename\n");
433 	exit(1);
434 }
435