xref: /csrg-svn/usr.sbin/arp/arp.c (revision 33624)
116255Skarels #ifndef lint
2*33624Sbostic static	char *sccsid = "@(#)arp.c	5.5 (Berkeley) 03/01/88";
316255Skarels #endif
416255Skarels 
516255Skarels /*
616255Skarels  * arp - display, set, and delete arp table entries
716255Skarels  */
816255Skarels 
9*33624Sbostic #include <machine/pte.h>
10*33624Sbostic 
11*33624Sbostic #include <sys/param.h>
12*33624Sbostic #include <sys/vmmac.h>
13*33624Sbostic #include <sys/file.h>
1416255Skarels #include <sys/socket.h>
1516255Skarels #include <sys/ioctl.h>
16*33624Sbostic 
1716255Skarels #include <netdb.h>
18*33624Sbostic #include <netinet/in.h>
1916255Skarels #include <net/if.h>
2016255Skarels #include <netinet/if_ether.h>
2116255Skarels 
22*33624Sbostic #include <errno.h>
23*33624Sbostic #include <nlist.h>
24*33624Sbostic #include <stdio.h>
25*33624Sbostic 
2616255Skarels extern int errno;
27*33624Sbostic static int kflag;
2816255Skarels 
2916255Skarels main(argc, argv)
30*33624Sbostic 	int argc;
3116255Skarels 	char **argv;
3216255Skarels {
33*33624Sbostic 	int ch;
3416255Skarels 
35*33624Sbostic 	while ((ch = getopt(argc, argv, "adsf")) != EOF)
36*33624Sbostic 		switch((char)ch) {
37*33624Sbostic 		case 'a': {
38*33624Sbostic 			char *mem;
39*33624Sbostic 
40*33624Sbostic 			if (argc > 4)
41*33624Sbostic 				usage();
42*33624Sbostic 			if (argc == 4) {
43*33624Sbostic 				kflag = 1;
44*33624Sbostic 				mem = argv[3];
45*33624Sbostic 			}
46*33624Sbostic 			else
47*33624Sbostic 				mem = "/dev/kmem";
48*33624Sbostic 			dump((argc >= 3) ? argv[2] : "/vmunix", mem);
49*33624Sbostic 			exit(0);
50*33624Sbostic 		}
51*33624Sbostic 		case 'd':
52*33624Sbostic 			if (argc != 3)
53*33624Sbostic 				usage();
54*33624Sbostic 			delete(argv[2]);
55*33624Sbostic 			exit(0);
56*33624Sbostic 		case 's':
57*33624Sbostic 			if (argc < 4 || argc > 7)
58*33624Sbostic 				usage();
59*33624Sbostic 			exit(set(argc-2, &argv[2]) ? 1 : 0);
60*33624Sbostic 		case 'f':
61*33624Sbostic 			if (argc != 3)
62*33624Sbostic 				usage();
63*33624Sbostic 			exit (file(argv[2]) ? 1 : 0);
64*33624Sbostic 		case '?':
65*33624Sbostic 		default:
66*33624Sbostic 			usage();
67*33624Sbostic 		}
68*33624Sbostic 	if (argc != 2)
69*33624Sbostic 		usage();
70*33624Sbostic 	get(argv[1]);
71*33624Sbostic 	exit(0);
7216255Skarels }
7316255Skarels 
7416255Skarels /*
7516255Skarels  * Process a file to set standard arp entries
7616255Skarels  */
7716255Skarels file(name)
7816255Skarels 	char *name;
7916255Skarels {
8016255Skarels 	FILE *fp;
81*33624Sbostic 	int i, retval;
8225788Skarels 	char line[100], arg[5][50], *args[5];
8316255Skarels 
8416255Skarels 	if ((fp = fopen(name, "r")) == NULL) {
8516255Skarels 		fprintf(stderr, "arp: cannot open %s\n", name);
8616255Skarels 		exit(1);
8716255Skarels 	}
8816255Skarels 	args[0] = &arg[0][0];
8916255Skarels 	args[1] = &arg[1][0];
9016255Skarels 	args[2] = &arg[2][0];
9116255Skarels 	args[3] = &arg[3][0];
9225788Skarels 	args[4] = &arg[4][0];
9332643Smckusick 	retval = 0;
9416255Skarels 	while(fgets(line, 100, fp) != NULL) {
9532643Smckusick 		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
9632643Smckusick 		    arg[3], arg[4]);
9716255Skarels 		if (i < 2) {
9816255Skarels 			fprintf(stderr, "arp: bad line: %s\n", line);
9932643Smckusick 			retval = 1;
10016255Skarels 			continue;
10116255Skarels 		}
10232643Smckusick 		if (set(i, args))
10332643Smckusick 			retval = 1;
10416255Skarels 	}
10516255Skarels 	fclose(fp);
10632643Smckusick 	return (retval);
10716255Skarels }
10816255Skarels 
10916255Skarels /*
11016255Skarels  * Set an individual arp entry
11116255Skarels  */
11216255Skarels set(argc, argv)
113*33624Sbostic 	int argc;
11416255Skarels 	char **argv;
11516255Skarels {
11616255Skarels 	struct arpreq ar;
11716255Skarels 	struct hostent *hp;
11816255Skarels 	struct sockaddr_in *sin;
11921393Skarels 	u_char *ea;
12016255Skarels 	int s;
12116255Skarels 	char *host = argv[0], *eaddr = argv[1];
12216255Skarels 
12316255Skarels 	argc -= 2;
12416255Skarels 	argv += 2;
12516255Skarels 	bzero((caddr_t)&ar, sizeof ar);
12616255Skarels 	sin = (struct sockaddr_in *)&ar.arp_pa;
12726314Skarels 	sin->sin_family = AF_INET;
12826314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
12926314Skarels 	if (sin->sin_addr.s_addr == -1) {
13026314Skarels 		hp = gethostbyname(host);
13126314Skarels 		if (hp == NULL) {
13226314Skarels 			fprintf(stderr, "arp: %s: unknown host\n", host);
13332643Smckusick 			return (1);
13426314Skarels 		}
13526314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
13626314Skarels 		    sizeof sin->sin_addr);
13726314Skarels 	}
13821393Skarels 	ea = (u_char *)ar.arp_ha.sa_data;
13916255Skarels 	if (ether_aton(eaddr, ea))
14032643Smckusick 		return (1);
14116255Skarels 	ar.arp_flags = ATF_PERM;
14226314Skarels 	while (argc-- > 0) {
14316255Skarels 		if (strncmp(argv[0], "temp", 4) == 0)
14416255Skarels 			ar.arp_flags &= ~ATF_PERM;
145*33624Sbostic 		else if (strncmp(argv[0], "pub", 3) == 0)
14616255Skarels 			ar.arp_flags |= ATF_PUBL;
147*33624Sbostic 		else if (strncmp(argv[0], "trail", 5) == 0)
14825788Skarels 			ar.arp_flags |= ATF_USETRAILERS;
14916255Skarels 		argv++;
15016255Skarels 	}
15116255Skarels 
15216255Skarels 	s = socket(AF_INET, SOCK_DGRAM, 0);
15316255Skarels 	if (s < 0) {
154*33624Sbostic 		perror("arp: socket");
155*33624Sbostic 		exit(1);
156*33624Sbostic 	}
15716255Skarels 	if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) {
15816255Skarels 		perror(host);
15916255Skarels 		exit(1);
16016255Skarels 	}
16116255Skarels 	close(s);
16232643Smckusick 	return (0);
16316255Skarels }
16416255Skarels 
16516255Skarels /*
16616255Skarels  * Display an individual arp entry
16716255Skarels  */
16816255Skarels get(host)
16916255Skarels 	char *host;
17016255Skarels {
17116255Skarels 	struct arpreq ar;
17216255Skarels 	struct hostent *hp;
17316255Skarels 	struct sockaddr_in *sin;
17421393Skarels 	u_char *ea;
17516255Skarels 	int s;
176*33624Sbostic 	char *inet_ntoa();
17716255Skarels 
17816255Skarels 	bzero((caddr_t)&ar, sizeof ar);
17916255Skarels 	ar.arp_pa.sa_family = AF_INET;
18016255Skarels 	sin = (struct sockaddr_in *)&ar.arp_pa;
18126314Skarels 	sin->sin_family = AF_INET;
18226314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
18326314Skarels 	if (sin->sin_addr.s_addr == -1) {
18426314Skarels 		hp = gethostbyname(host);
18526314Skarels 		if (hp == NULL) {
18626314Skarels 			fprintf(stderr, "arp: %s: unknown host\n", host);
18726314Skarels 			exit(1);
18826314Skarels 		}
18926314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
19026314Skarels 		    sizeof sin->sin_addr);
19126314Skarels 	}
19216255Skarels 	s = socket(AF_INET, SOCK_DGRAM, 0);
19316255Skarels 	if (s < 0) {
194*33624Sbostic 		perror("arp: socket");
195*33624Sbostic 		exit(1);
196*33624Sbostic 	}
19716255Skarels 	if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
19816255Skarels 		if (errno == ENXIO)
19916255Skarels 			printf("%s (%s) -- no entry\n",
20016255Skarels 			    host, inet_ntoa(sin->sin_addr));
20116255Skarels 		else
20216255Skarels 			perror("SIOCGARP");
20316255Skarels 		exit(1);
20416255Skarels 	}
20516255Skarels 	close(s);
20621393Skarels 	ea = (u_char *)ar.arp_ha.sa_data;
20716255Skarels 	printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
20816255Skarels 	if (ar.arp_flags & ATF_COM)
20916255Skarels 		ether_print(ea);
21016255Skarels 	else
21116255Skarels 		printf("(incomplete)");
212*33624Sbostic 	if (ar.arp_flags & ATF_PERM)
213*33624Sbostic 		printf(" permanent");
214*33624Sbostic 	if (ar.arp_flags & ATF_PUBL)
215*33624Sbostic 		printf(" published");
216*33624Sbostic 	if (ar.arp_flags & ATF_USETRAILERS)
217*33624Sbostic 		printf(" trailers");
21816255Skarels 	printf("\n");
21916255Skarels }
22016255Skarels 
22116255Skarels /*
22216255Skarels  * Delete an arp entry
22316255Skarels  */
22416255Skarels delete(host)
22516255Skarels 	char *host;
22616255Skarels {
22716255Skarels 	struct arpreq ar;
22816255Skarels 	struct hostent *hp;
22916255Skarels 	struct sockaddr_in *sin;
23016255Skarels 	int s;
23116255Skarels 
23216255Skarels 	bzero((caddr_t)&ar, sizeof ar);
23316255Skarels 	ar.arp_pa.sa_family = AF_INET;
23416255Skarels 	sin = (struct sockaddr_in *)&ar.arp_pa;
23526314Skarels 	sin->sin_family = AF_INET;
23626314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
23726314Skarels 	if (sin->sin_addr.s_addr == -1) {
23826314Skarels 		hp = gethostbyname(host);
23926314Skarels 		if (hp == NULL) {
24026314Skarels 			fprintf(stderr, "arp: %s: unknown host\n", host);
24126314Skarels 			exit(1);
24226314Skarels 		}
24326314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
24426314Skarels 		    sizeof sin->sin_addr);
24526314Skarels 	}
24616255Skarels 	s = socket(AF_INET, SOCK_DGRAM, 0);
24716255Skarels 	if (s < 0) {
248*33624Sbostic 		perror("arp: socket");
249*33624Sbostic 		exit(1);
250*33624Sbostic 	}
25116255Skarels 	if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) {
25216255Skarels 		if (errno == ENXIO)
25316255Skarels 			printf("%s (%s) -- no entry\n",
25416255Skarels 			    host, inet_ntoa(sin->sin_addr));
25516255Skarels 		else
25616255Skarels 			perror("SIOCDARP");
25716255Skarels 		exit(1);
25816255Skarels 	}
25916255Skarels 	close(s);
26016255Skarels 	printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
26116255Skarels }
26216255Skarels 
26316255Skarels struct nlist nl[] = {
26416255Skarels #define	X_ARPTAB	0
26516255Skarels 	{ "_arptab" },
26616255Skarels #define	X_ARPTAB_SIZE	1
26716255Skarels 	{ "_arptab_size" },
268*33624Sbostic #define	N_SYSMAP	2
269*33624Sbostic 	{ "_Sysmap" },
270*33624Sbostic #define	N_SYSSIZE	3
271*33624Sbostic 	{ "_Syssize" },
27216255Skarels 	{ "" },
27316255Skarels };
27416255Skarels 
275*33624Sbostic static struct pte *Sysmap;
276*33624Sbostic 
27716255Skarels /*
27816255Skarels  * Dump the entire arp table
27916255Skarels  */
28016255Skarels dump(kernel, mem)
28116255Skarels 	char *kernel, *mem;
28216255Skarels {
283*33624Sbostic 	extern int h_errno;
28416255Skarels 	struct arptab *at;
28516255Skarels 	struct hostent *hp;
286*33624Sbostic 	int bynumber, mf, arptab_size, sz;
287*33624Sbostic 	char *host, *malloc();
288*33624Sbostic 	off_t lseek();
28916255Skarels 
290*33624Sbostic 	if (nlist(kernel, nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) {
29116255Skarels 		fprintf(stderr, "arp: %s: bad namelist\n", kernel);
29216255Skarels 		exit(1);
29316255Skarels 	}
294*33624Sbostic 	mf = open(mem, O_RDONLY);
295*33624Sbostic 	if (mf < 0) {
29616255Skarels 		fprintf(fprintf, "arp: cannot open %s\n", mem);
29716255Skarels 		exit(1);
29816255Skarels 	}
299*33624Sbostic 	if (kflag) {
300*33624Sbostic 		off_t off;
301*33624Sbostic 
302*33624Sbostic 		Sysmap = (struct pte *)
303*33624Sbostic 		   malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
304*33624Sbostic 		if (!Sysmap) {
305*33624Sbostic 			fputs("arp: can't get memory for Sysmap.\n", stderr);
306*33624Sbostic 			exit(1);
307*33624Sbostic 		}
308*33624Sbostic 		off = nl[N_SYSMAP].n_value & ~KERNBASE;
309*33624Sbostic 		(void)lseek(mf, off, L_SET);
310*33624Sbostic 		(void)read(mf, (char *)Sysmap,
311*33624Sbostic 		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
312*33624Sbostic 	}
313*33624Sbostic 	klseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, L_SET);
31416255Skarels 	read(mf, &arptab_size, sizeof arptab_size);
315*33624Sbostic 	if (arptab_size <= 0 || arptab_size > 1000) {
31616255Skarels 		fprintf(stderr, "arp: %s: namelist wrong\n", kernel);
31716255Skarels 		exit(1);
31816255Skarels 	}
31916255Skarels 	sz = arptab_size * sizeof (struct arptab);
320*33624Sbostic 	at = (struct arptab *)malloc((u_int)sz);
32116255Skarels 	if (at == NULL) {
322*33624Sbostic 		fputs("arp: can't get memory for arptab.\n", stderr);
32316255Skarels 		exit(1);
32416255Skarels 	}
325*33624Sbostic 	klseek(mf, (long)nl[X_ARPTAB].n_value, L_SET);
32616255Skarels 	if (read(mf, (char *)at, sz) != sz) {
32716255Skarels 		perror("arp: error reading arptab");
32816255Skarels 		exit(1);
32916255Skarels 	}
33016255Skarels 	close(mf);
331*33624Sbostic 	for (bynumber = 0; arptab_size-- > 0; at++) {
33216255Skarels 		if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
33316255Skarels 			continue;
33426314Skarels 		if (bynumber == 0)
33526314Skarels 			hp = gethostbyaddr((caddr_t)&at->at_iaddr,
33626314Skarels 			    sizeof at->at_iaddr, AF_INET);
33726314Skarels 		else
33826314Skarels 			hp = 0;
33916255Skarels 		if (hp)
34016255Skarels 			host = hp->h_name;
34126314Skarels 		else {
34216255Skarels 			host = "?";
34326314Skarels 			if (h_errno == TRY_AGAIN)
34426314Skarels 				bynumber = 1;
34526314Skarels 		}
34616255Skarels 		printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr));
34716255Skarels 		if (at->at_flags & ATF_COM)
34821393Skarels 			ether_print(at->at_enaddr);
34916255Skarels 		else
35016255Skarels 			printf("(incomplete)");
351*33624Sbostic 		if (at->at_flags & ATF_PERM)
352*33624Sbostic 			printf(" permanent");
353*33624Sbostic 		if (at->at_flags & ATF_PUBL)
354*33624Sbostic 			printf(" published");
355*33624Sbostic 		if (at->at_flags & ATF_USETRAILERS)
356*33624Sbostic 			printf(" trailers");
35716255Skarels 		printf("\n");
35816255Skarels 	}
35916255Skarels }
36016255Skarels 
361*33624Sbostic /*
362*33624Sbostic  * Seek into the kernel for a value.
363*33624Sbostic  */
364*33624Sbostic klseek(fd, base, off)
365*33624Sbostic 	int fd, off;
366*33624Sbostic 	off_t base;
367*33624Sbostic {
368*33624Sbostic 	off_t lseek();
369*33624Sbostic 
370*33624Sbostic 	if (kflag) {	/* get kernel pte */
371*33624Sbostic 		base &= ~KERNBASE;
372*33624Sbostic 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
373*33624Sbostic 	}
374*33624Sbostic 	(void)lseek(fd, base, off);
375*33624Sbostic }
376*33624Sbostic 
37721393Skarels ether_print(cp)
37821393Skarels 	u_char *cp;
37916255Skarels {
38016255Skarels 	printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
38116255Skarels }
38216255Skarels 
38316255Skarels ether_aton(a, n)
38416255Skarels 	char *a;
38521393Skarels 	u_char *n;
38616255Skarels {
38716255Skarels 	int i, o[6];
38816255Skarels 
38916255Skarels 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
39016255Skarels 					   &o[3], &o[4], &o[5]);
39116255Skarels 	if (i != 6) {
39216255Skarels 		fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
39316255Skarels 		return (1);
39416255Skarels 	}
39516255Skarels 	for (i=0; i<6; i++)
39621393Skarels 		n[i] = o[i];
39716255Skarels 	return (0);
39816255Skarels }
39916255Skarels 
40016255Skarels usage()
40116255Skarels {
402*33624Sbostic 	printf("usage: arp hostname\n");
40316255Skarels 	printf("       arp -a [/vmunix] [/dev/kmem]\n");
40416255Skarels 	printf("       arp -d hostname\n");
40532643Smckusick 	printf("       arp -s hostname ether_addr [temp] [pub] [trail]\n");
40616255Skarels 	printf("       arp -f filename\n");
407*33624Sbostic 	exit(1);
40816255Skarels }
409