xref: /csrg-svn/usr.sbin/arp/arp.c (revision 50476)
134918Sbostic /*
234918Sbostic  * Copyright (c) 1984 Regents of the University of California.
334918Sbostic  * All rights reserved.
434918Sbostic  *
534918Sbostic  * This code is derived from software contributed to Berkeley by
634918Sbostic  * Sun Microsystems, Inc.
734918Sbostic  *
842791Sbostic  * %sccs.include.redist.c%
934918Sbostic  */
1034918Sbostic 
1116255Skarels #ifndef lint
1234918Sbostic char copyright[] =
1334918Sbostic "@(#) Copyright (c) 1984 Regents of the University of California.\n\
1434918Sbostic  All rights reserved.\n";
1534918Sbostic #endif /* not lint */
1616255Skarels 
1734918Sbostic #ifndef lint
18*50476Sbostic static char sccsid[] = "@(#)arp.c	5.11.1.1 (Berkeley) 07/22/91";
1934918Sbostic #endif /* not lint */
2034918Sbostic 
2116255Skarels /*
2216255Skarels  * arp - display, set, and delete arp table entries
2316255Skarels  */
2416255Skarels 
2533624Sbostic #include <sys/param.h>
2633624Sbostic #include <sys/file.h>
2716255Skarels #include <sys/socket.h>
28*50476Sbostic #include <sys/ioctl.h>
2933624Sbostic 
30*50476Sbostic #include <netdb.h>
31*50476Sbostic #include <netinet/in.h>
3250132Ssklower #include <net/if.h>
3316255Skarels #include <netinet/if_ether.h>
3416255Skarels 
3533624Sbostic #include <errno.h>
3633624Sbostic #include <nlist.h>
37*50476Sbostic #include <kvm.h>
3833624Sbostic #include <stdio.h>
3937961Sbostic #include <paths.h>
4033624Sbostic 
4116255Skarels extern int errno;
4216255Skarels 
4316255Skarels main(argc, argv)
4433624Sbostic 	int argc;
4516255Skarels 	char **argv;
4616255Skarels {
4733624Sbostic 	int ch;
4816255Skarels 
49*50476Sbostic 	while ((ch = getopt(argc, argv, "adsf")) != EOF)
5033624Sbostic 		switch((char)ch) {
51*50476Sbostic 		case 'a': {
52*50476Sbostic 			char *mem = 0;
53*50476Sbostic 
54*50476Sbostic 			if (argc > 4)
55*50476Sbostic 				usage();
56*50476Sbostic 			if (argc == 4) {
57*50476Sbostic 				mem = argv[3];
58*50476Sbostic 			}
59*50476Sbostic 			dump((argc >= 3) ? argv[2] : _PATH_UNIX, mem);
6033624Sbostic 			exit(0);
61*50476Sbostic 		}
6233624Sbostic 		case 'd':
63*50476Sbostic 			if (argc != 3)
6433624Sbostic 				usage();
65*50476Sbostic 			delete(argv[2]);
6633624Sbostic 			exit(0);
6733624Sbostic 		case 's':
6833624Sbostic 			if (argc < 4 || argc > 7)
6933624Sbostic 				usage();
7033624Sbostic 			exit(set(argc-2, &argv[2]) ? 1 : 0);
71*50476Sbostic 		case 'f':
72*50476Sbostic 			if (argc != 3)
73*50476Sbostic 				usage();
74*50476Sbostic 			exit (file(argv[2]) ? 1 : 0);
7533624Sbostic 		case '?':
7633624Sbostic 		default:
7733624Sbostic 			usage();
7833624Sbostic 		}
7933624Sbostic 	if (argc != 2)
8033624Sbostic 		usage();
8133624Sbostic 	get(argv[1]);
8233624Sbostic 	exit(0);
8316255Skarels }
8416255Skarels 
8516255Skarels /*
8616255Skarels  * Process a file to set standard arp entries
8716255Skarels  */
8816255Skarels file(name)
8916255Skarels 	char *name;
9016255Skarels {
9116255Skarels 	FILE *fp;
9233624Sbostic 	int i, retval;
9325788Skarels 	char line[100], arg[5][50], *args[5];
9416255Skarels 
9516255Skarels 	if ((fp = fopen(name, "r")) == NULL) {
9616255Skarels 		fprintf(stderr, "arp: cannot open %s\n", name);
9716255Skarels 		exit(1);
9816255Skarels 	}
9916255Skarels 	args[0] = &arg[0][0];
10016255Skarels 	args[1] = &arg[1][0];
10116255Skarels 	args[2] = &arg[2][0];
10216255Skarels 	args[3] = &arg[3][0];
10325788Skarels 	args[4] = &arg[4][0];
10432643Smckusick 	retval = 0;
10516255Skarels 	while(fgets(line, 100, fp) != NULL) {
10632643Smckusick 		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
10732643Smckusick 		    arg[3], arg[4]);
10816255Skarels 		if (i < 2) {
10916255Skarels 			fprintf(stderr, "arp: bad line: %s\n", line);
11032643Smckusick 			retval = 1;
11116255Skarels 			continue;
11216255Skarels 		}
11332643Smckusick 		if (set(i, args))
11432643Smckusick 			retval = 1;
11516255Skarels 	}
11616255Skarels 	fclose(fp);
11732643Smckusick 	return (retval);
11816255Skarels }
11916255Skarels 
12016255Skarels /*
12116255Skarels  * Set an individual arp entry
12216255Skarels  */
12316255Skarels set(argc, argv)
12433624Sbostic 	int argc;
12516255Skarels 	char **argv;
12616255Skarels {
127*50476Sbostic 	struct arpreq ar;
12816255Skarels 	struct hostent *hp;
129*50476Sbostic 	struct sockaddr_in *sin;
13021393Skarels 	u_char *ea;
131*50476Sbostic 	int s;
13216255Skarels 	char *host = argv[0], *eaddr = argv[1];
13316255Skarels 
13416255Skarels 	argc -= 2;
13516255Skarels 	argv += 2;
136*50476Sbostic 	bzero((caddr_t)&ar, sizeof ar);
137*50476Sbostic 	sin = (struct sockaddr_in *)&ar.arp_pa;
138*50476Sbostic 	sin->sin_family = AF_INET;
13926314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
14026314Skarels 	if (sin->sin_addr.s_addr == -1) {
14135778Sbostic 		if (!(hp = gethostbyname(host))) {
14235778Sbostic 			fprintf(stderr, "arp: %s: ", host);
14335778Sbostic 			herror((char *)NULL);
14432643Smckusick 			return (1);
14526314Skarels 		}
14626314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
14726314Skarels 		    sizeof sin->sin_addr);
14826314Skarels 	}
149*50476Sbostic 	ea = (u_char *)ar.arp_ha.sa_data;
150*50476Sbostic 	if (ether_aton(eaddr, ea))
151*50476Sbostic 		return (1);
152*50476Sbostic 	ar.arp_flags = ATF_PERM;
15326314Skarels 	while (argc-- > 0) {
154*50476Sbostic 		if (strncmp(argv[0], "temp", 4) == 0)
155*50476Sbostic 			ar.arp_flags &= ~ATF_PERM;
15633624Sbostic 		else if (strncmp(argv[0], "pub", 3) == 0)
157*50476Sbostic 			ar.arp_flags |= ATF_PUBL;
15833624Sbostic 		else if (strncmp(argv[0], "trail", 5) == 0)
159*50476Sbostic 			ar.arp_flags |= ATF_USETRAILERS;
16016255Skarels 		argv++;
16116255Skarels 	}
162*50476Sbostic 
163*50476Sbostic 	s = socket(AF_INET, SOCK_DGRAM, 0);
164*50476Sbostic 	if (s < 0) {
165*50476Sbostic 		perror("arp: socket");
166*50476Sbostic 		exit(1);
167*50476Sbostic 	}
168*50476Sbostic 	if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) {
16916255Skarels 		perror(host);
170*50476Sbostic 		exit(1);
17116255Skarels 	}
172*50476Sbostic 	close(s);
173*50476Sbostic 	return (0);
17416255Skarels }
17516255Skarels 
17616255Skarels /*
17716255Skarels  * Display an individual arp entry
17816255Skarels  */
17916255Skarels get(host)
18016255Skarels 	char *host;
18116255Skarels {
182*50476Sbostic 	struct arpreq ar;
18316255Skarels 	struct hostent *hp;
184*50476Sbostic 	struct sockaddr_in *sin;
18521393Skarels 	u_char *ea;
186*50476Sbostic 	int s;
18733624Sbostic 	char *inet_ntoa();
18816255Skarels 
189*50476Sbostic 	bzero((caddr_t)&ar, sizeof ar);
190*50476Sbostic 	ar.arp_pa.sa_family = AF_INET;
191*50476Sbostic 	sin = (struct sockaddr_in *)&ar.arp_pa;
192*50476Sbostic 	sin->sin_family = AF_INET;
19326314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
19426314Skarels 	if (sin->sin_addr.s_addr == -1) {
19535778Sbostic 		if (!(hp = gethostbyname(host))) {
19635778Sbostic 			fprintf(stderr, "arp: %s: ", host);
19735778Sbostic 			herror((char *)NULL);
19826314Skarels 			exit(1);
19926314Skarels 		}
20026314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
20126314Skarels 		    sizeof sin->sin_addr);
20226314Skarels 	}
203*50476Sbostic 	s = socket(AF_INET, SOCK_DGRAM, 0);
204*50476Sbostic 	if (s < 0) {
205*50476Sbostic 		perror("arp: socket");
20633624Sbostic 		exit(1);
20733624Sbostic 	}
208*50476Sbostic 	if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
209*50476Sbostic 		if (errno == ENXIO)
210*50476Sbostic 			printf("%s (%s) -- no entry\n",
211*50476Sbostic 			    host, inet_ntoa(sin->sin_addr));
212*50476Sbostic 		else
213*50476Sbostic 			perror("SIOCGARP");
214*50476Sbostic 		exit(1);
215*50476Sbostic 	}
216*50476Sbostic 	close(s);
217*50476Sbostic 	ea = (u_char *)ar.arp_ha.sa_data;
218*50476Sbostic 	printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
219*50476Sbostic 	if (ar.arp_flags & ATF_COM)
220*50476Sbostic 		ether_print(ea);
221*50476Sbostic 	else
222*50476Sbostic 		printf("(incomplete)");
223*50476Sbostic 	if (ar.arp_flags & ATF_PERM)
224*50476Sbostic 		printf(" permanent");
225*50476Sbostic 	if (ar.arp_flags & ATF_PUBL)
226*50476Sbostic 		printf(" published");
227*50476Sbostic 	if (ar.arp_flags & ATF_USETRAILERS)
228*50476Sbostic 		printf(" trailers");
229*50476Sbostic 	printf("\n");
23016255Skarels }
23116255Skarels 
23216255Skarels /*
23316255Skarels  * Delete an arp entry
23416255Skarels  */
235*50476Sbostic delete(host)
23616255Skarels 	char *host;
23716255Skarels {
238*50476Sbostic 	struct arpreq ar;
23916255Skarels 	struct hostent *hp;
240*50476Sbostic 	struct sockaddr_in *sin;
241*50476Sbostic 	int s;
24216255Skarels 
243*50476Sbostic 	bzero((caddr_t)&ar, sizeof ar);
244*50476Sbostic 	ar.arp_pa.sa_family = AF_INET;
245*50476Sbostic 	sin = (struct sockaddr_in *)&ar.arp_pa;
246*50476Sbostic 	sin->sin_family = AF_INET;
24726314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
24826314Skarels 	if (sin->sin_addr.s_addr == -1) {
24935778Sbostic 		if (!(hp = gethostbyname(host))) {
25035778Sbostic 			fprintf(stderr, "arp: %s: ", host);
25135778Sbostic 			herror((char *)NULL);
252*50476Sbostic 			exit(1);
25326314Skarels 		}
25426314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
25526314Skarels 		    sizeof sin->sin_addr);
25626314Skarels 	}
257*50476Sbostic 	s = socket(AF_INET, SOCK_DGRAM, 0);
258*50476Sbostic 	if (s < 0) {
259*50476Sbostic 		perror("arp: socket");
260*50476Sbostic 		exit(1);
26133624Sbostic 	}
262*50476Sbostic 	if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) {
263*50476Sbostic 		if (errno == ENXIO)
264*50476Sbostic 			printf("%s (%s) -- no entry\n",
265*50476Sbostic 			    host, inet_ntoa(sin->sin_addr));
266*50476Sbostic 		else
267*50476Sbostic 			perror("SIOCDARP");
268*50476Sbostic 		exit(1);
26916255Skarels 	}
270*50476Sbostic 	close(s);
271*50476Sbostic 	printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
27216255Skarels }
27316255Skarels 
274*50476Sbostic struct nlist nl[] = {
275*50476Sbostic #define	X_ARPTAB	0
276*50476Sbostic 	{ "_arptab" },
277*50476Sbostic #define	X_ARPTAB_SIZE	1
278*50476Sbostic 	{ "_arptab_size" },
279*50476Sbostic 	{ "" },
280*50476Sbostic };
281*50476Sbostic 
28216255Skarels /*
28316255Skarels  * Dump the entire arp table
28416255Skarels  */
285*50476Sbostic dump(kernel, mem)
286*50476Sbostic 	char *kernel, *mem;
28716255Skarels {
28833624Sbostic 	extern int h_errno;
289*50476Sbostic 	struct arptab *at;
29016255Skarels 	struct hostent *hp;
291*50476Sbostic 	int bynumber, mf, arptab_size, sz;
292*50476Sbostic 	char *host, *malloc();
293*50476Sbostic 	off_t lseek();
29416255Skarels 
295*50476Sbostic 	if (kvm_openfiles(kernel, mem, NULL) == -1) {
296*50476Sbostic 		fprintf(stderr, "arp: kvm_openfiles: %s\n", kvm_geterr());
297*50476Sbostic 		exit(1);
298*50476Sbostic 	}
299*50476Sbostic 	if (kvm_nlist(nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) {
300*50476Sbostic 		fprintf(stderr, "arp: %s: bad namelist\n", kernel);
301*50476Sbostic 		exit(1);
302*50476Sbostic 	}
303*50476Sbostic 	if (kvm_read((void *)(nl[X_ARPTAB_SIZE].n_value),
304*50476Sbostic 		     &arptab_size, sizeof arptab_size) == -1 ||
305*50476Sbostic 	    arptab_size <= 0 || arptab_size > 1000) {
306*50476Sbostic 		fprintf(stderr, "arp: %s: namelist wrong\n", kernel);
307*50476Sbostic 		exit(1);
308*50476Sbostic 	}
309*50476Sbostic 	sz = arptab_size * sizeof (struct arptab);
310*50476Sbostic 	at = (struct arptab *)malloc((u_int)sz);
311*50476Sbostic 	if (at == NULL) {
312*50476Sbostic 		fputs("arp: can't get memory for arptab.\n", stderr);
313*50476Sbostic 		exit(1);
314*50476Sbostic 	}
315*50476Sbostic 	if (kvm_read((void *)(nl[X_ARPTAB].n_value), (char *)at, sz) == -1) {
316*50476Sbostic 		perror("arp: error reading arptab");
317*50476Sbostic 		exit(1);
318*50476Sbostic 	}
319*50476Sbostic 	for (bynumber = 0; arptab_size-- > 0; at++) {
320*50476Sbostic 		if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
321*50476Sbostic 			continue;
322*50476Sbostic 		if (bynumber == 0)
323*50476Sbostic 			hp = gethostbyaddr((caddr_t)&at->at_iaddr,
324*50476Sbostic 			    sizeof at->at_iaddr, AF_INET);
32526314Skarels 		else
32626314Skarels 			hp = 0;
32716255Skarels 		if (hp)
32816255Skarels 			host = hp->h_name;
32926314Skarels 		else {
33016255Skarels 			host = "?";
33126314Skarels 			if (h_errno == TRY_AGAIN)
332*50476Sbostic 				bynumber = 1;
33326314Skarels 		}
334*50476Sbostic 		printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr));
335*50476Sbostic 		if (at->at_flags & ATF_COM)
336*50476Sbostic 			ether_print(at->at_enaddr);
33716255Skarels 		else
33816255Skarels 			printf("(incomplete)");
339*50476Sbostic 		if (at->at_flags & ATF_PERM)
34033624Sbostic 			printf(" permanent");
341*50476Sbostic 		if (at->at_flags & ATF_PUBL)
342*50476Sbostic 			printf(" published");
343*50476Sbostic 		if (at->at_flags & ATF_USETRAILERS)
34433624Sbostic 			printf(" trailers");
34516255Skarels 		printf("\n");
34616255Skarels 	}
34716255Skarels }
34816255Skarels 
34921393Skarels ether_print(cp)
35021393Skarels 	u_char *cp;
35116255Skarels {
35216255Skarels 	printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
35316255Skarels }
35416255Skarels 
35516255Skarels ether_aton(a, n)
35616255Skarels 	char *a;
35721393Skarels 	u_char *n;
35816255Skarels {
35916255Skarels 	int i, o[6];
36016255Skarels 
36116255Skarels 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
36216255Skarels 					   &o[3], &o[4], &o[5]);
36316255Skarels 	if (i != 6) {
36416255Skarels 		fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
36516255Skarels 		return (1);
36616255Skarels 	}
36716255Skarels 	for (i=0; i<6; i++)
36821393Skarels 		n[i] = o[i];
36916255Skarels 	return (0);
37016255Skarels }
37116255Skarels 
37216255Skarels usage()
37316255Skarels {
37433624Sbostic 	printf("usage: arp hostname\n");
37537961Sbostic 	printf("       arp -a [kernel] [kernel_memory]\n");
37616255Skarels 	printf("       arp -d hostname\n");
37732643Smckusick 	printf("       arp -s hostname ether_addr [temp] [pub] [trail]\n");
37816255Skarels 	printf("       arp -f filename\n");
37933624Sbostic 	exit(1);
38016255Skarels }
381