xref: /csrg-svn/usr.sbin/arp/arp.c (revision 37961)
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  *
834918Sbostic  * Redistribution and use in source and binary forms are permitted
934918Sbostic  * provided that the above copyright notice and this paragraph are
1034918Sbostic  * duplicated in all such forms and that any documentation,
1134918Sbostic  * advertising materials, and other materials related to such
1234918Sbostic  * distribution and use acknowledge that the software was developed
1334918Sbostic  * by the University of California, Berkeley.  The name of the
1434918Sbostic  * University may not be used to endorse or promote products derived
1534918Sbostic  * from this software without specific prior written permission.
1634918Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1734918Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1834918Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1934918Sbostic  */
2034918Sbostic 
2116255Skarels #ifndef lint
2234918Sbostic char copyright[] =
2334918Sbostic "@(#) Copyright (c) 1984 Regents of the University of California.\n\
2434918Sbostic  All rights reserved.\n";
2534918Sbostic #endif /* not lint */
2616255Skarels 
2734918Sbostic #ifndef lint
28*37961Sbostic static char sccsid[] = "@(#)arp.c	5.10 (Berkeley) 05/11/89";
2934918Sbostic #endif /* not lint */
3034918Sbostic 
3116255Skarels /*
3216255Skarels  * arp - display, set, and delete arp table entries
3316255Skarels  */
3416255Skarels 
3533624Sbostic #include <machine/pte.h>
3633624Sbostic 
3733624Sbostic #include <sys/param.h>
3833624Sbostic #include <sys/vmmac.h>
3933624Sbostic #include <sys/file.h>
4016255Skarels #include <sys/socket.h>
4116255Skarels #include <sys/ioctl.h>
4233624Sbostic 
4316255Skarels #include <netdb.h>
4433624Sbostic #include <netinet/in.h>
4516255Skarels #include <net/if.h>
4616255Skarels #include <netinet/if_ether.h>
4716255Skarels 
4833624Sbostic #include <errno.h>
4933624Sbostic #include <nlist.h>
5033624Sbostic #include <stdio.h>
51*37961Sbostic #include <paths.h>
5233624Sbostic 
5316255Skarels extern int errno;
5433624Sbostic static int kflag;
5516255Skarels 
5616255Skarels main(argc, argv)
5733624Sbostic 	int argc;
5816255Skarels 	char **argv;
5916255Skarels {
6033624Sbostic 	int ch;
6116255Skarels 
6233624Sbostic 	while ((ch = getopt(argc, argv, "adsf")) != EOF)
6333624Sbostic 		switch((char)ch) {
6433624Sbostic 		case 'a': {
6533624Sbostic 			char *mem;
6633624Sbostic 
6733624Sbostic 			if (argc > 4)
6833624Sbostic 				usage();
6933624Sbostic 			if (argc == 4) {
7033624Sbostic 				kflag = 1;
7133624Sbostic 				mem = argv[3];
7233624Sbostic 			}
7333624Sbostic 			else
7437255Sbostic 				mem = _PATH_KMEM;
75*37961Sbostic 			dump((argc >= 3) ? argv[2] : _PATH_UNIX, mem);
7633624Sbostic 			exit(0);
7733624Sbostic 		}
7833624Sbostic 		case 'd':
7933624Sbostic 			if (argc != 3)
8033624Sbostic 				usage();
8133624Sbostic 			delete(argv[2]);
8233624Sbostic 			exit(0);
8333624Sbostic 		case 's':
8433624Sbostic 			if (argc < 4 || argc > 7)
8533624Sbostic 				usage();
8633624Sbostic 			exit(set(argc-2, &argv[2]) ? 1 : 0);
8733624Sbostic 		case 'f':
8833624Sbostic 			if (argc != 3)
8933624Sbostic 				usage();
9033624Sbostic 			exit (file(argv[2]) ? 1 : 0);
9133624Sbostic 		case '?':
9233624Sbostic 		default:
9333624Sbostic 			usage();
9433624Sbostic 		}
9533624Sbostic 	if (argc != 2)
9633624Sbostic 		usage();
9733624Sbostic 	get(argv[1]);
9833624Sbostic 	exit(0);
9916255Skarels }
10016255Skarels 
10116255Skarels /*
10216255Skarels  * Process a file to set standard arp entries
10316255Skarels  */
10416255Skarels file(name)
10516255Skarels 	char *name;
10616255Skarels {
10716255Skarels 	FILE *fp;
10833624Sbostic 	int i, retval;
10925788Skarels 	char line[100], arg[5][50], *args[5];
11016255Skarels 
11116255Skarels 	if ((fp = fopen(name, "r")) == NULL) {
11216255Skarels 		fprintf(stderr, "arp: cannot open %s\n", name);
11316255Skarels 		exit(1);
11416255Skarels 	}
11516255Skarels 	args[0] = &arg[0][0];
11616255Skarels 	args[1] = &arg[1][0];
11716255Skarels 	args[2] = &arg[2][0];
11816255Skarels 	args[3] = &arg[3][0];
11925788Skarels 	args[4] = &arg[4][0];
12032643Smckusick 	retval = 0;
12116255Skarels 	while(fgets(line, 100, fp) != NULL) {
12232643Smckusick 		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
12332643Smckusick 		    arg[3], arg[4]);
12416255Skarels 		if (i < 2) {
12516255Skarels 			fprintf(stderr, "arp: bad line: %s\n", line);
12632643Smckusick 			retval = 1;
12716255Skarels 			continue;
12816255Skarels 		}
12932643Smckusick 		if (set(i, args))
13032643Smckusick 			retval = 1;
13116255Skarels 	}
13216255Skarels 	fclose(fp);
13332643Smckusick 	return (retval);
13416255Skarels }
13516255Skarels 
13616255Skarels /*
13716255Skarels  * Set an individual arp entry
13816255Skarels  */
13916255Skarels set(argc, argv)
14033624Sbostic 	int argc;
14116255Skarels 	char **argv;
14216255Skarels {
14316255Skarels 	struct arpreq ar;
14416255Skarels 	struct hostent *hp;
14516255Skarels 	struct sockaddr_in *sin;
14621393Skarels 	u_char *ea;
14716255Skarels 	int s;
14816255Skarels 	char *host = argv[0], *eaddr = argv[1];
14916255Skarels 
15016255Skarels 	argc -= 2;
15116255Skarels 	argv += 2;
15216255Skarels 	bzero((caddr_t)&ar, sizeof ar);
15316255Skarels 	sin = (struct sockaddr_in *)&ar.arp_pa;
15426314Skarels 	sin->sin_family = AF_INET;
15526314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
15626314Skarels 	if (sin->sin_addr.s_addr == -1) {
15735778Sbostic 		if (!(hp = gethostbyname(host))) {
15835778Sbostic 			fprintf(stderr, "arp: %s: ", host);
15935778Sbostic 			herror((char *)NULL);
16032643Smckusick 			return (1);
16126314Skarels 		}
16226314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
16326314Skarels 		    sizeof sin->sin_addr);
16426314Skarels 	}
16521393Skarels 	ea = (u_char *)ar.arp_ha.sa_data;
16616255Skarels 	if (ether_aton(eaddr, ea))
16732643Smckusick 		return (1);
16816255Skarels 	ar.arp_flags = ATF_PERM;
16926314Skarels 	while (argc-- > 0) {
17016255Skarels 		if (strncmp(argv[0], "temp", 4) == 0)
17116255Skarels 			ar.arp_flags &= ~ATF_PERM;
17233624Sbostic 		else if (strncmp(argv[0], "pub", 3) == 0)
17316255Skarels 			ar.arp_flags |= ATF_PUBL;
17433624Sbostic 		else if (strncmp(argv[0], "trail", 5) == 0)
17525788Skarels 			ar.arp_flags |= ATF_USETRAILERS;
17616255Skarels 		argv++;
17716255Skarels 	}
17816255Skarels 
17916255Skarels 	s = socket(AF_INET, SOCK_DGRAM, 0);
18016255Skarels 	if (s < 0) {
18133624Sbostic 		perror("arp: socket");
18233624Sbostic 		exit(1);
18333624Sbostic 	}
18416255Skarels 	if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) {
18516255Skarels 		perror(host);
18616255Skarels 		exit(1);
18716255Skarels 	}
18816255Skarels 	close(s);
18932643Smckusick 	return (0);
19016255Skarels }
19116255Skarels 
19216255Skarels /*
19316255Skarels  * Display an individual arp entry
19416255Skarels  */
19516255Skarels get(host)
19616255Skarels 	char *host;
19716255Skarels {
19816255Skarels 	struct arpreq ar;
19916255Skarels 	struct hostent *hp;
20016255Skarels 	struct sockaddr_in *sin;
20121393Skarels 	u_char *ea;
20216255Skarels 	int s;
20333624Sbostic 	char *inet_ntoa();
20416255Skarels 
20516255Skarels 	bzero((caddr_t)&ar, sizeof ar);
20616255Skarels 	ar.arp_pa.sa_family = AF_INET;
20716255Skarels 	sin = (struct sockaddr_in *)&ar.arp_pa;
20826314Skarels 	sin->sin_family = AF_INET;
20926314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
21026314Skarels 	if (sin->sin_addr.s_addr == -1) {
21135778Sbostic 		if (!(hp = gethostbyname(host))) {
21235778Sbostic 			fprintf(stderr, "arp: %s: ", host);
21335778Sbostic 			herror((char *)NULL);
21426314Skarels 			exit(1);
21526314Skarels 		}
21626314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
21726314Skarels 		    sizeof sin->sin_addr);
21826314Skarels 	}
21916255Skarels 	s = socket(AF_INET, SOCK_DGRAM, 0);
22016255Skarels 	if (s < 0) {
22133624Sbostic 		perror("arp: socket");
22233624Sbostic 		exit(1);
22333624Sbostic 	}
22416255Skarels 	if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
22516255Skarels 		if (errno == ENXIO)
22616255Skarels 			printf("%s (%s) -- no entry\n",
22716255Skarels 			    host, inet_ntoa(sin->sin_addr));
22816255Skarels 		else
22916255Skarels 			perror("SIOCGARP");
23016255Skarels 		exit(1);
23116255Skarels 	}
23216255Skarels 	close(s);
23321393Skarels 	ea = (u_char *)ar.arp_ha.sa_data;
23416255Skarels 	printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
23516255Skarels 	if (ar.arp_flags & ATF_COM)
23616255Skarels 		ether_print(ea);
23716255Skarels 	else
23816255Skarels 		printf("(incomplete)");
23933624Sbostic 	if (ar.arp_flags & ATF_PERM)
24033624Sbostic 		printf(" permanent");
24133624Sbostic 	if (ar.arp_flags & ATF_PUBL)
24233624Sbostic 		printf(" published");
24333624Sbostic 	if (ar.arp_flags & ATF_USETRAILERS)
24433624Sbostic 		printf(" trailers");
24516255Skarels 	printf("\n");
24616255Skarels }
24716255Skarels 
24816255Skarels /*
24916255Skarels  * Delete an arp entry
25016255Skarels  */
25116255Skarels delete(host)
25216255Skarels 	char *host;
25316255Skarels {
25416255Skarels 	struct arpreq ar;
25516255Skarels 	struct hostent *hp;
25616255Skarels 	struct sockaddr_in *sin;
25716255Skarels 	int s;
25816255Skarels 
25916255Skarels 	bzero((caddr_t)&ar, sizeof ar);
26016255Skarels 	ar.arp_pa.sa_family = AF_INET;
26116255Skarels 	sin = (struct sockaddr_in *)&ar.arp_pa;
26226314Skarels 	sin->sin_family = AF_INET;
26326314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
26426314Skarels 	if (sin->sin_addr.s_addr == -1) {
26535778Sbostic 		if (!(hp = gethostbyname(host))) {
26635778Sbostic 			fprintf(stderr, "arp: %s: ", host);
26735778Sbostic 			herror((char *)NULL);
26826314Skarels 			exit(1);
26926314Skarels 		}
27026314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
27126314Skarels 		    sizeof sin->sin_addr);
27226314Skarels 	}
27316255Skarels 	s = socket(AF_INET, SOCK_DGRAM, 0);
27416255Skarels 	if (s < 0) {
27533624Sbostic 		perror("arp: socket");
27633624Sbostic 		exit(1);
27733624Sbostic 	}
27816255Skarels 	if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) {
27916255Skarels 		if (errno == ENXIO)
28016255Skarels 			printf("%s (%s) -- no entry\n",
28116255Skarels 			    host, inet_ntoa(sin->sin_addr));
28216255Skarels 		else
28316255Skarels 			perror("SIOCDARP");
28416255Skarels 		exit(1);
28516255Skarels 	}
28616255Skarels 	close(s);
28716255Skarels 	printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
28816255Skarels }
28916255Skarels 
29016255Skarels struct nlist nl[] = {
29116255Skarels #define	X_ARPTAB	0
29216255Skarels 	{ "_arptab" },
29316255Skarels #define	X_ARPTAB_SIZE	1
29416255Skarels 	{ "_arptab_size" },
29533624Sbostic #define	N_SYSMAP	2
29633624Sbostic 	{ "_Sysmap" },
29733624Sbostic #define	N_SYSSIZE	3
29833624Sbostic 	{ "_Syssize" },
29916255Skarels 	{ "" },
30016255Skarels };
30116255Skarels 
30233624Sbostic static struct pte *Sysmap;
30333624Sbostic 
30416255Skarels /*
30516255Skarels  * Dump the entire arp table
30616255Skarels  */
30716255Skarels dump(kernel, mem)
30816255Skarels 	char *kernel, *mem;
30916255Skarels {
31033624Sbostic 	extern int h_errno;
31116255Skarels 	struct arptab *at;
31216255Skarels 	struct hostent *hp;
31333624Sbostic 	int bynumber, mf, arptab_size, sz;
31433624Sbostic 	char *host, *malloc();
31533624Sbostic 	off_t lseek();
31616255Skarels 
31733624Sbostic 	if (nlist(kernel, nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) {
31816255Skarels 		fprintf(stderr, "arp: %s: bad namelist\n", kernel);
31916255Skarels 		exit(1);
32016255Skarels 	}
32133624Sbostic 	mf = open(mem, O_RDONLY);
32233624Sbostic 	if (mf < 0) {
32335377Sbostic 		fprintf(stderr, "arp: cannot open %s\n", mem);
32416255Skarels 		exit(1);
32516255Skarels 	}
32633624Sbostic 	if (kflag) {
32733624Sbostic 		off_t off;
32833624Sbostic 
32933624Sbostic 		Sysmap = (struct pte *)
33033624Sbostic 		   malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
33133624Sbostic 		if (!Sysmap) {
33233624Sbostic 			fputs("arp: can't get memory for Sysmap.\n", stderr);
33333624Sbostic 			exit(1);
33433624Sbostic 		}
33533624Sbostic 		off = nl[N_SYSMAP].n_value & ~KERNBASE;
33633624Sbostic 		(void)lseek(mf, off, L_SET);
33733624Sbostic 		(void)read(mf, (char *)Sysmap,
33833624Sbostic 		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
33933624Sbostic 	}
34033624Sbostic 	klseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, L_SET);
34116255Skarels 	read(mf, &arptab_size, sizeof arptab_size);
34233624Sbostic 	if (arptab_size <= 0 || arptab_size > 1000) {
34316255Skarels 		fprintf(stderr, "arp: %s: namelist wrong\n", kernel);
34416255Skarels 		exit(1);
34516255Skarels 	}
34616255Skarels 	sz = arptab_size * sizeof (struct arptab);
34733624Sbostic 	at = (struct arptab *)malloc((u_int)sz);
34816255Skarels 	if (at == NULL) {
34933624Sbostic 		fputs("arp: can't get memory for arptab.\n", stderr);
35016255Skarels 		exit(1);
35116255Skarels 	}
35233624Sbostic 	klseek(mf, (long)nl[X_ARPTAB].n_value, L_SET);
35316255Skarels 	if (read(mf, (char *)at, sz) != sz) {
35416255Skarels 		perror("arp: error reading arptab");
35516255Skarels 		exit(1);
35616255Skarels 	}
35716255Skarels 	close(mf);
35833624Sbostic 	for (bynumber = 0; arptab_size-- > 0; at++) {
35916255Skarels 		if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
36016255Skarels 			continue;
36126314Skarels 		if (bynumber == 0)
36226314Skarels 			hp = gethostbyaddr((caddr_t)&at->at_iaddr,
36326314Skarels 			    sizeof at->at_iaddr, AF_INET);
36426314Skarels 		else
36526314Skarels 			hp = 0;
36616255Skarels 		if (hp)
36716255Skarels 			host = hp->h_name;
36826314Skarels 		else {
36916255Skarels 			host = "?";
37026314Skarels 			if (h_errno == TRY_AGAIN)
37126314Skarels 				bynumber = 1;
37226314Skarels 		}
37316255Skarels 		printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr));
37416255Skarels 		if (at->at_flags & ATF_COM)
37521393Skarels 			ether_print(at->at_enaddr);
37616255Skarels 		else
37716255Skarels 			printf("(incomplete)");
37833624Sbostic 		if (at->at_flags & ATF_PERM)
37933624Sbostic 			printf(" permanent");
38033624Sbostic 		if (at->at_flags & ATF_PUBL)
38133624Sbostic 			printf(" published");
38233624Sbostic 		if (at->at_flags & ATF_USETRAILERS)
38333624Sbostic 			printf(" trailers");
38416255Skarels 		printf("\n");
38516255Skarels 	}
38616255Skarels }
38716255Skarels 
38833624Sbostic /*
38933624Sbostic  * Seek into the kernel for a value.
39033624Sbostic  */
39133624Sbostic klseek(fd, base, off)
39233624Sbostic 	int fd, off;
39333624Sbostic 	off_t base;
39433624Sbostic {
39533624Sbostic 	off_t lseek();
39633624Sbostic 
39733624Sbostic 	if (kflag) {	/* get kernel pte */
39833624Sbostic 		base &= ~KERNBASE;
39933624Sbostic 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
40033624Sbostic 	}
40133624Sbostic 	(void)lseek(fd, base, off);
40233624Sbostic }
40333624Sbostic 
40421393Skarels ether_print(cp)
40521393Skarels 	u_char *cp;
40616255Skarels {
40716255Skarels 	printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
40816255Skarels }
40916255Skarels 
41016255Skarels ether_aton(a, n)
41116255Skarels 	char *a;
41221393Skarels 	u_char *n;
41316255Skarels {
41416255Skarels 	int i, o[6];
41516255Skarels 
41616255Skarels 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
41716255Skarels 					   &o[3], &o[4], &o[5]);
41816255Skarels 	if (i != 6) {
41916255Skarels 		fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
42016255Skarels 		return (1);
42116255Skarels 	}
42216255Skarels 	for (i=0; i<6; i++)
42321393Skarels 		n[i] = o[i];
42416255Skarels 	return (0);
42516255Skarels }
42616255Skarels 
42716255Skarels usage()
42816255Skarels {
42933624Sbostic 	printf("usage: arp hostname\n");
430*37961Sbostic 	printf("       arp -a [kernel] [kernel_memory]\n");
43116255Skarels 	printf("       arp -d hostname\n");
43232643Smckusick 	printf("       arp -s hostname ether_addr [temp] [pub] [trail]\n");
43316255Skarels 	printf("       arp -f filename\n");
43433624Sbostic 	exit(1);
43516255Skarels }
436