xref: /csrg-svn/usr.sbin/arp/arp.c (revision 34918)
1*34918Sbostic /*
2*34918Sbostic  * Copyright (c) 1984 Regents of the University of California.
3*34918Sbostic  * All rights reserved.
4*34918Sbostic  *
5*34918Sbostic  * This code is derived from software contributed to Berkeley by
6*34918Sbostic  * Sun Microsystems, Inc.
7*34918Sbostic  *
8*34918Sbostic  * Redistribution and use in source and binary forms are permitted
9*34918Sbostic  * provided that the above copyright notice and this paragraph are
10*34918Sbostic  * duplicated in all such forms and that any documentation,
11*34918Sbostic  * advertising materials, and other materials related to such
12*34918Sbostic  * distribution and use acknowledge that the software was developed
13*34918Sbostic  * by the University of California, Berkeley.  The name of the
14*34918Sbostic  * University may not be used to endorse or promote products derived
15*34918Sbostic  * from this software without specific prior written permission.
16*34918Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*34918Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*34918Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19*34918Sbostic  */
20*34918Sbostic 
2116255Skarels #ifndef lint
22*34918Sbostic char copyright[] =
23*34918Sbostic "@(#) Copyright (c) 1984 Regents of the University of California.\n\
24*34918Sbostic  All rights reserved.\n";
25*34918Sbostic #endif /* not lint */
2616255Skarels 
27*34918Sbostic #ifndef lint
28*34918Sbostic static char sccsid[] = "@(#)arp.c	5.6 (Berkeley) 06/30/88";
29*34918Sbostic #endif /* not lint */
30*34918Sbostic 
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>
5133624Sbostic 
5216255Skarels extern int errno;
5333624Sbostic static int kflag;
5416255Skarels 
5516255Skarels main(argc, argv)
5633624Sbostic 	int argc;
5716255Skarels 	char **argv;
5816255Skarels {
5933624Sbostic 	int ch;
6016255Skarels 
6133624Sbostic 	while ((ch = getopt(argc, argv, "adsf")) != EOF)
6233624Sbostic 		switch((char)ch) {
6333624Sbostic 		case 'a': {
6433624Sbostic 			char *mem;
6533624Sbostic 
6633624Sbostic 			if (argc > 4)
6733624Sbostic 				usage();
6833624Sbostic 			if (argc == 4) {
6933624Sbostic 				kflag = 1;
7033624Sbostic 				mem = argv[3];
7133624Sbostic 			}
7233624Sbostic 			else
7333624Sbostic 				mem = "/dev/kmem";
7433624Sbostic 			dump((argc >= 3) ? argv[2] : "/vmunix", mem);
7533624Sbostic 			exit(0);
7633624Sbostic 		}
7733624Sbostic 		case 'd':
7833624Sbostic 			if (argc != 3)
7933624Sbostic 				usage();
8033624Sbostic 			delete(argv[2]);
8133624Sbostic 			exit(0);
8233624Sbostic 		case 's':
8333624Sbostic 			if (argc < 4 || argc > 7)
8433624Sbostic 				usage();
8533624Sbostic 			exit(set(argc-2, &argv[2]) ? 1 : 0);
8633624Sbostic 		case 'f':
8733624Sbostic 			if (argc != 3)
8833624Sbostic 				usage();
8933624Sbostic 			exit (file(argv[2]) ? 1 : 0);
9033624Sbostic 		case '?':
9133624Sbostic 		default:
9233624Sbostic 			usage();
9333624Sbostic 		}
9433624Sbostic 	if (argc != 2)
9533624Sbostic 		usage();
9633624Sbostic 	get(argv[1]);
9733624Sbostic 	exit(0);
9816255Skarels }
9916255Skarels 
10016255Skarels /*
10116255Skarels  * Process a file to set standard arp entries
10216255Skarels  */
10316255Skarels file(name)
10416255Skarels 	char *name;
10516255Skarels {
10616255Skarels 	FILE *fp;
10733624Sbostic 	int i, retval;
10825788Skarels 	char line[100], arg[5][50], *args[5];
10916255Skarels 
11016255Skarels 	if ((fp = fopen(name, "r")) == NULL) {
11116255Skarels 		fprintf(stderr, "arp: cannot open %s\n", name);
11216255Skarels 		exit(1);
11316255Skarels 	}
11416255Skarels 	args[0] = &arg[0][0];
11516255Skarels 	args[1] = &arg[1][0];
11616255Skarels 	args[2] = &arg[2][0];
11716255Skarels 	args[3] = &arg[3][0];
11825788Skarels 	args[4] = &arg[4][0];
11932643Smckusick 	retval = 0;
12016255Skarels 	while(fgets(line, 100, fp) != NULL) {
12132643Smckusick 		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
12232643Smckusick 		    arg[3], arg[4]);
12316255Skarels 		if (i < 2) {
12416255Skarels 			fprintf(stderr, "arp: bad line: %s\n", line);
12532643Smckusick 			retval = 1;
12616255Skarels 			continue;
12716255Skarels 		}
12832643Smckusick 		if (set(i, args))
12932643Smckusick 			retval = 1;
13016255Skarels 	}
13116255Skarels 	fclose(fp);
13232643Smckusick 	return (retval);
13316255Skarels }
13416255Skarels 
13516255Skarels /*
13616255Skarels  * Set an individual arp entry
13716255Skarels  */
13816255Skarels set(argc, argv)
13933624Sbostic 	int argc;
14016255Skarels 	char **argv;
14116255Skarels {
14216255Skarels 	struct arpreq ar;
14316255Skarels 	struct hostent *hp;
14416255Skarels 	struct sockaddr_in *sin;
14521393Skarels 	u_char *ea;
14616255Skarels 	int s;
14716255Skarels 	char *host = argv[0], *eaddr = argv[1];
14816255Skarels 
14916255Skarels 	argc -= 2;
15016255Skarels 	argv += 2;
15116255Skarels 	bzero((caddr_t)&ar, sizeof ar);
15216255Skarels 	sin = (struct sockaddr_in *)&ar.arp_pa;
15326314Skarels 	sin->sin_family = AF_INET;
15426314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
15526314Skarels 	if (sin->sin_addr.s_addr == -1) {
15626314Skarels 		hp = gethostbyname(host);
15726314Skarels 		if (hp == NULL) {
15826314Skarels 			fprintf(stderr, "arp: %s: unknown host\n", host);
15932643Smckusick 			return (1);
16026314Skarels 		}
16126314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
16226314Skarels 		    sizeof sin->sin_addr);
16326314Skarels 	}
16421393Skarels 	ea = (u_char *)ar.arp_ha.sa_data;
16516255Skarels 	if (ether_aton(eaddr, ea))
16632643Smckusick 		return (1);
16716255Skarels 	ar.arp_flags = ATF_PERM;
16826314Skarels 	while (argc-- > 0) {
16916255Skarels 		if (strncmp(argv[0], "temp", 4) == 0)
17016255Skarels 			ar.arp_flags &= ~ATF_PERM;
17133624Sbostic 		else if (strncmp(argv[0], "pub", 3) == 0)
17216255Skarels 			ar.arp_flags |= ATF_PUBL;
17333624Sbostic 		else if (strncmp(argv[0], "trail", 5) == 0)
17425788Skarels 			ar.arp_flags |= ATF_USETRAILERS;
17516255Skarels 		argv++;
17616255Skarels 	}
17716255Skarels 
17816255Skarels 	s = socket(AF_INET, SOCK_DGRAM, 0);
17916255Skarels 	if (s < 0) {
18033624Sbostic 		perror("arp: socket");
18133624Sbostic 		exit(1);
18233624Sbostic 	}
18316255Skarels 	if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) {
18416255Skarels 		perror(host);
18516255Skarels 		exit(1);
18616255Skarels 	}
18716255Skarels 	close(s);
18832643Smckusick 	return (0);
18916255Skarels }
19016255Skarels 
19116255Skarels /*
19216255Skarels  * Display an individual arp entry
19316255Skarels  */
19416255Skarels get(host)
19516255Skarels 	char *host;
19616255Skarels {
19716255Skarels 	struct arpreq ar;
19816255Skarels 	struct hostent *hp;
19916255Skarels 	struct sockaddr_in *sin;
20021393Skarels 	u_char *ea;
20116255Skarels 	int s;
20233624Sbostic 	char *inet_ntoa();
20316255Skarels 
20416255Skarels 	bzero((caddr_t)&ar, sizeof ar);
20516255Skarels 	ar.arp_pa.sa_family = AF_INET;
20616255Skarels 	sin = (struct sockaddr_in *)&ar.arp_pa;
20726314Skarels 	sin->sin_family = AF_INET;
20826314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
20926314Skarels 	if (sin->sin_addr.s_addr == -1) {
21026314Skarels 		hp = gethostbyname(host);
21126314Skarels 		if (hp == NULL) {
21226314Skarels 			fprintf(stderr, "arp: %s: unknown host\n", host);
21326314Skarels 			exit(1);
21426314Skarels 		}
21526314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
21626314Skarels 		    sizeof sin->sin_addr);
21726314Skarels 	}
21816255Skarels 	s = socket(AF_INET, SOCK_DGRAM, 0);
21916255Skarels 	if (s < 0) {
22033624Sbostic 		perror("arp: socket");
22133624Sbostic 		exit(1);
22233624Sbostic 	}
22316255Skarels 	if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
22416255Skarels 		if (errno == ENXIO)
22516255Skarels 			printf("%s (%s) -- no entry\n",
22616255Skarels 			    host, inet_ntoa(sin->sin_addr));
22716255Skarels 		else
22816255Skarels 			perror("SIOCGARP");
22916255Skarels 		exit(1);
23016255Skarels 	}
23116255Skarels 	close(s);
23221393Skarels 	ea = (u_char *)ar.arp_ha.sa_data;
23316255Skarels 	printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
23416255Skarels 	if (ar.arp_flags & ATF_COM)
23516255Skarels 		ether_print(ea);
23616255Skarels 	else
23716255Skarels 		printf("(incomplete)");
23833624Sbostic 	if (ar.arp_flags & ATF_PERM)
23933624Sbostic 		printf(" permanent");
24033624Sbostic 	if (ar.arp_flags & ATF_PUBL)
24133624Sbostic 		printf(" published");
24233624Sbostic 	if (ar.arp_flags & ATF_USETRAILERS)
24333624Sbostic 		printf(" trailers");
24416255Skarels 	printf("\n");
24516255Skarels }
24616255Skarels 
24716255Skarels /*
24816255Skarels  * Delete an arp entry
24916255Skarels  */
25016255Skarels delete(host)
25116255Skarels 	char *host;
25216255Skarels {
25316255Skarels 	struct arpreq ar;
25416255Skarels 	struct hostent *hp;
25516255Skarels 	struct sockaddr_in *sin;
25616255Skarels 	int s;
25716255Skarels 
25816255Skarels 	bzero((caddr_t)&ar, sizeof ar);
25916255Skarels 	ar.arp_pa.sa_family = AF_INET;
26016255Skarels 	sin = (struct sockaddr_in *)&ar.arp_pa;
26126314Skarels 	sin->sin_family = AF_INET;
26226314Skarels 	sin->sin_addr.s_addr = inet_addr(host);
26326314Skarels 	if (sin->sin_addr.s_addr == -1) {
26426314Skarels 		hp = gethostbyname(host);
26526314Skarels 		if (hp == NULL) {
26626314Skarels 			fprintf(stderr, "arp: %s: unknown host\n", host);
26726314Skarels 			exit(1);
26826314Skarels 		}
26926314Skarels 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
27026314Skarels 		    sizeof sin->sin_addr);
27126314Skarels 	}
27216255Skarels 	s = socket(AF_INET, SOCK_DGRAM, 0);
27316255Skarels 	if (s < 0) {
27433624Sbostic 		perror("arp: socket");
27533624Sbostic 		exit(1);
27633624Sbostic 	}
27716255Skarels 	if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) {
27816255Skarels 		if (errno == ENXIO)
27916255Skarels 			printf("%s (%s) -- no entry\n",
28016255Skarels 			    host, inet_ntoa(sin->sin_addr));
28116255Skarels 		else
28216255Skarels 			perror("SIOCDARP");
28316255Skarels 		exit(1);
28416255Skarels 	}
28516255Skarels 	close(s);
28616255Skarels 	printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
28716255Skarels }
28816255Skarels 
28916255Skarels struct nlist nl[] = {
29016255Skarels #define	X_ARPTAB	0
29116255Skarels 	{ "_arptab" },
29216255Skarels #define	X_ARPTAB_SIZE	1
29316255Skarels 	{ "_arptab_size" },
29433624Sbostic #define	N_SYSMAP	2
29533624Sbostic 	{ "_Sysmap" },
29633624Sbostic #define	N_SYSSIZE	3
29733624Sbostic 	{ "_Syssize" },
29816255Skarels 	{ "" },
29916255Skarels };
30016255Skarels 
30133624Sbostic static struct pte *Sysmap;
30233624Sbostic 
30316255Skarels /*
30416255Skarels  * Dump the entire arp table
30516255Skarels  */
30616255Skarels dump(kernel, mem)
30716255Skarels 	char *kernel, *mem;
30816255Skarels {
30933624Sbostic 	extern int h_errno;
31016255Skarels 	struct arptab *at;
31116255Skarels 	struct hostent *hp;
31233624Sbostic 	int bynumber, mf, arptab_size, sz;
31333624Sbostic 	char *host, *malloc();
31433624Sbostic 	off_t lseek();
31516255Skarels 
31633624Sbostic 	if (nlist(kernel, nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) {
31716255Skarels 		fprintf(stderr, "arp: %s: bad namelist\n", kernel);
31816255Skarels 		exit(1);
31916255Skarels 	}
32033624Sbostic 	mf = open(mem, O_RDONLY);
32133624Sbostic 	if (mf < 0) {
32216255Skarels 		fprintf(fprintf, "arp: cannot open %s\n", mem);
32316255Skarels 		exit(1);
32416255Skarels 	}
32533624Sbostic 	if (kflag) {
32633624Sbostic 		off_t off;
32733624Sbostic 
32833624Sbostic 		Sysmap = (struct pte *)
32933624Sbostic 		   malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
33033624Sbostic 		if (!Sysmap) {
33133624Sbostic 			fputs("arp: can't get memory for Sysmap.\n", stderr);
33233624Sbostic 			exit(1);
33333624Sbostic 		}
33433624Sbostic 		off = nl[N_SYSMAP].n_value & ~KERNBASE;
33533624Sbostic 		(void)lseek(mf, off, L_SET);
33633624Sbostic 		(void)read(mf, (char *)Sysmap,
33733624Sbostic 		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
33833624Sbostic 	}
33933624Sbostic 	klseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, L_SET);
34016255Skarels 	read(mf, &arptab_size, sizeof arptab_size);
34133624Sbostic 	if (arptab_size <= 0 || arptab_size > 1000) {
34216255Skarels 		fprintf(stderr, "arp: %s: namelist wrong\n", kernel);
34316255Skarels 		exit(1);
34416255Skarels 	}
34516255Skarels 	sz = arptab_size * sizeof (struct arptab);
34633624Sbostic 	at = (struct arptab *)malloc((u_int)sz);
34716255Skarels 	if (at == NULL) {
34833624Sbostic 		fputs("arp: can't get memory for arptab.\n", stderr);
34916255Skarels 		exit(1);
35016255Skarels 	}
35133624Sbostic 	klseek(mf, (long)nl[X_ARPTAB].n_value, L_SET);
35216255Skarels 	if (read(mf, (char *)at, sz) != sz) {
35316255Skarels 		perror("arp: error reading arptab");
35416255Skarels 		exit(1);
35516255Skarels 	}
35616255Skarels 	close(mf);
35733624Sbostic 	for (bynumber = 0; arptab_size-- > 0; at++) {
35816255Skarels 		if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
35916255Skarels 			continue;
36026314Skarels 		if (bynumber == 0)
36126314Skarels 			hp = gethostbyaddr((caddr_t)&at->at_iaddr,
36226314Skarels 			    sizeof at->at_iaddr, AF_INET);
36326314Skarels 		else
36426314Skarels 			hp = 0;
36516255Skarels 		if (hp)
36616255Skarels 			host = hp->h_name;
36726314Skarels 		else {
36816255Skarels 			host = "?";
36926314Skarels 			if (h_errno == TRY_AGAIN)
37026314Skarels 				bynumber = 1;
37126314Skarels 		}
37216255Skarels 		printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr));
37316255Skarels 		if (at->at_flags & ATF_COM)
37421393Skarels 			ether_print(at->at_enaddr);
37516255Skarels 		else
37616255Skarels 			printf("(incomplete)");
37733624Sbostic 		if (at->at_flags & ATF_PERM)
37833624Sbostic 			printf(" permanent");
37933624Sbostic 		if (at->at_flags & ATF_PUBL)
38033624Sbostic 			printf(" published");
38133624Sbostic 		if (at->at_flags & ATF_USETRAILERS)
38233624Sbostic 			printf(" trailers");
38316255Skarels 		printf("\n");
38416255Skarels 	}
38516255Skarels }
38616255Skarels 
38733624Sbostic /*
38833624Sbostic  * Seek into the kernel for a value.
38933624Sbostic  */
39033624Sbostic klseek(fd, base, off)
39133624Sbostic 	int fd, off;
39233624Sbostic 	off_t base;
39333624Sbostic {
39433624Sbostic 	off_t lseek();
39533624Sbostic 
39633624Sbostic 	if (kflag) {	/* get kernel pte */
39733624Sbostic 		base &= ~KERNBASE;
39833624Sbostic 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
39933624Sbostic 	}
40033624Sbostic 	(void)lseek(fd, base, off);
40133624Sbostic }
40233624Sbostic 
40321393Skarels ether_print(cp)
40421393Skarels 	u_char *cp;
40516255Skarels {
40616255Skarels 	printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
40716255Skarels }
40816255Skarels 
40916255Skarels ether_aton(a, n)
41016255Skarels 	char *a;
41121393Skarels 	u_char *n;
41216255Skarels {
41316255Skarels 	int i, o[6];
41416255Skarels 
41516255Skarels 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
41616255Skarels 					   &o[3], &o[4], &o[5]);
41716255Skarels 	if (i != 6) {
41816255Skarels 		fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
41916255Skarels 		return (1);
42016255Skarels 	}
42116255Skarels 	for (i=0; i<6; i++)
42221393Skarels 		n[i] = o[i];
42316255Skarels 	return (0);
42416255Skarels }
42516255Skarels 
42616255Skarels usage()
42716255Skarels {
42833624Sbostic 	printf("usage: arp hostname\n");
42916255Skarels 	printf("       arp -a [/vmunix] [/dev/kmem]\n");
43016255Skarels 	printf("       arp -d hostname\n");
43132643Smckusick 	printf("       arp -s hostname ether_addr [temp] [pub] [trail]\n");
43216255Skarels 	printf("       arp -f filename\n");
43333624Sbostic 	exit(1);
43416255Skarels }
435