xref: /original-bsd/usr.sbin/arp/arp.c (revision 5e36add1)
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  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1984 Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)arp.c	5.11 (Berkeley) 06/01/90";
19 #endif /* not lint */
20 
21 /*
22  * arp - display, set, and delete arp table entries
23  */
24 
25 #include <machine/pte.h>
26 
27 #include <sys/param.h>
28 #include <sys/vmmac.h>
29 #include <sys/file.h>
30 #include <sys/socket.h>
31 #include <sys/ioctl.h>
32 
33 #include <netdb.h>
34 #include <netinet/in.h>
35 #include <net/if.h>
36 #include <netinet/if_ether.h>
37 
38 #include <errno.h>
39 #include <nlist.h>
40 #include <stdio.h>
41 #include <paths.h>
42 
43 extern int errno;
44 static int kflag;
45 
46 main(argc, argv)
47 	int argc;
48 	char **argv;
49 {
50 	int ch;
51 
52 	while ((ch = getopt(argc, argv, "adsf")) != EOF)
53 		switch((char)ch) {
54 		case 'a': {
55 			char *mem;
56 
57 			if (argc > 4)
58 				usage();
59 			if (argc == 4) {
60 				kflag = 1;
61 				mem = argv[3];
62 			}
63 			else
64 				mem = _PATH_KMEM;
65 			dump((argc >= 3) ? argv[2] : _PATH_UNIX, mem);
66 			exit(0);
67 		}
68 		case 'd':
69 			if (argc != 3)
70 				usage();
71 			delete(argv[2]);
72 			exit(0);
73 		case 's':
74 			if (argc < 4 || argc > 7)
75 				usage();
76 			exit(set(argc-2, &argv[2]) ? 1 : 0);
77 		case 'f':
78 			if (argc != 3)
79 				usage();
80 			exit (file(argv[2]) ? 1 : 0);
81 		case '?':
82 		default:
83 			usage();
84 		}
85 	if (argc != 2)
86 		usage();
87 	get(argv[1]);
88 	exit(0);
89 }
90 
91 /*
92  * Process a file to set standard arp entries
93  */
94 file(name)
95 	char *name;
96 {
97 	FILE *fp;
98 	int i, retval;
99 	char line[100], arg[5][50], *args[5];
100 
101 	if ((fp = fopen(name, "r")) == NULL) {
102 		fprintf(stderr, "arp: cannot open %s\n", name);
103 		exit(1);
104 	}
105 	args[0] = &arg[0][0];
106 	args[1] = &arg[1][0];
107 	args[2] = &arg[2][0];
108 	args[3] = &arg[3][0];
109 	args[4] = &arg[4][0];
110 	retval = 0;
111 	while(fgets(line, 100, fp) != NULL) {
112 		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
113 		    arg[3], arg[4]);
114 		if (i < 2) {
115 			fprintf(stderr, "arp: bad line: %s\n", line);
116 			retval = 1;
117 			continue;
118 		}
119 		if (set(i, args))
120 			retval = 1;
121 	}
122 	fclose(fp);
123 	return (retval);
124 }
125 
126 /*
127  * Set an individual arp entry
128  */
129 set(argc, argv)
130 	int argc;
131 	char **argv;
132 {
133 	struct arpreq ar;
134 	struct hostent *hp;
135 	struct sockaddr_in *sin;
136 	u_char *ea;
137 	int s;
138 	char *host = argv[0], *eaddr = argv[1];
139 
140 	argc -= 2;
141 	argv += 2;
142 	bzero((caddr_t)&ar, sizeof ar);
143 	sin = (struct sockaddr_in *)&ar.arp_pa;
144 	sin->sin_family = AF_INET;
145 	sin->sin_addr.s_addr = inet_addr(host);
146 	if (sin->sin_addr.s_addr == -1) {
147 		if (!(hp = gethostbyname(host))) {
148 			fprintf(stderr, "arp: %s: ", host);
149 			herror((char *)NULL);
150 			return (1);
151 		}
152 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
153 		    sizeof sin->sin_addr);
154 	}
155 	ea = (u_char *)ar.arp_ha.sa_data;
156 	if (ether_aton(eaddr, ea))
157 		return (1);
158 	ar.arp_flags = ATF_PERM;
159 	while (argc-- > 0) {
160 		if (strncmp(argv[0], "temp", 4) == 0)
161 			ar.arp_flags &= ~ATF_PERM;
162 		else if (strncmp(argv[0], "pub", 3) == 0)
163 			ar.arp_flags |= ATF_PUBL;
164 		else if (strncmp(argv[0], "trail", 5) == 0)
165 			ar.arp_flags |= ATF_USETRAILERS;
166 		argv++;
167 	}
168 
169 	s = socket(AF_INET, SOCK_DGRAM, 0);
170 	if (s < 0) {
171 		perror("arp: socket");
172 		exit(1);
173 	}
174 	if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) {
175 		perror(host);
176 		exit(1);
177 	}
178 	close(s);
179 	return (0);
180 }
181 
182 /*
183  * Display an individual arp entry
184  */
185 get(host)
186 	char *host;
187 {
188 	struct arpreq ar;
189 	struct hostent *hp;
190 	struct sockaddr_in *sin;
191 	u_char *ea;
192 	int s;
193 	char *inet_ntoa();
194 
195 	bzero((caddr_t)&ar, sizeof ar);
196 	ar.arp_pa.sa_family = AF_INET;
197 	sin = (struct sockaddr_in *)&ar.arp_pa;
198 	sin->sin_family = AF_INET;
199 	sin->sin_addr.s_addr = inet_addr(host);
200 	if (sin->sin_addr.s_addr == -1) {
201 		if (!(hp = gethostbyname(host))) {
202 			fprintf(stderr, "arp: %s: ", host);
203 			herror((char *)NULL);
204 			exit(1);
205 		}
206 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
207 		    sizeof sin->sin_addr);
208 	}
209 	s = socket(AF_INET, SOCK_DGRAM, 0);
210 	if (s < 0) {
211 		perror("arp: socket");
212 		exit(1);
213 	}
214 	if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
215 		if (errno == ENXIO)
216 			printf("%s (%s) -- no entry\n",
217 			    host, inet_ntoa(sin->sin_addr));
218 		else
219 			perror("SIOCGARP");
220 		exit(1);
221 	}
222 	close(s);
223 	ea = (u_char *)ar.arp_ha.sa_data;
224 	printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
225 	if (ar.arp_flags & ATF_COM)
226 		ether_print(ea);
227 	else
228 		printf("(incomplete)");
229 	if (ar.arp_flags & ATF_PERM)
230 		printf(" permanent");
231 	if (ar.arp_flags & ATF_PUBL)
232 		printf(" published");
233 	if (ar.arp_flags & ATF_USETRAILERS)
234 		printf(" trailers");
235 	printf("\n");
236 }
237 
238 /*
239  * Delete an arp entry
240  */
241 delete(host)
242 	char *host;
243 {
244 	struct arpreq ar;
245 	struct hostent *hp;
246 	struct sockaddr_in *sin;
247 	int s;
248 
249 	bzero((caddr_t)&ar, sizeof ar);
250 	ar.arp_pa.sa_family = AF_INET;
251 	sin = (struct sockaddr_in *)&ar.arp_pa;
252 	sin->sin_family = AF_INET;
253 	sin->sin_addr.s_addr = inet_addr(host);
254 	if (sin->sin_addr.s_addr == -1) {
255 		if (!(hp = gethostbyname(host))) {
256 			fprintf(stderr, "arp: %s: ", host);
257 			herror((char *)NULL);
258 			exit(1);
259 		}
260 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
261 		    sizeof sin->sin_addr);
262 	}
263 	s = socket(AF_INET, SOCK_DGRAM, 0);
264 	if (s < 0) {
265 		perror("arp: socket");
266 		exit(1);
267 	}
268 	if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) {
269 		if (errno == ENXIO)
270 			printf("%s (%s) -- no entry\n",
271 			    host, inet_ntoa(sin->sin_addr));
272 		else
273 			perror("SIOCDARP");
274 		exit(1);
275 	}
276 	close(s);
277 	printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
278 }
279 
280 struct nlist nl[] = {
281 #define	X_ARPTAB	0
282 	{ "_arptab" },
283 #define	X_ARPTAB_SIZE	1
284 	{ "_arptab_size" },
285 #define	N_SYSMAP	2
286 	{ "_Sysmap" },
287 #define	N_SYSSIZE	3
288 	{ "_Syssize" },
289 	{ "" },
290 };
291 
292 static struct pte *Sysmap;
293 
294 /*
295  * Dump the entire arp table
296  */
297 dump(kernel, mem)
298 	char *kernel, *mem;
299 {
300 	extern int h_errno;
301 	struct arptab *at;
302 	struct hostent *hp;
303 	int bynumber, mf, arptab_size, sz;
304 	char *host, *malloc();
305 	off_t lseek();
306 
307 	if (nlist(kernel, nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) {
308 		fprintf(stderr, "arp: %s: bad namelist\n", kernel);
309 		exit(1);
310 	}
311 	mf = open(mem, O_RDONLY);
312 	if (mf < 0) {
313 		fprintf(stderr, "arp: cannot open %s\n", mem);
314 		exit(1);
315 	}
316 	if (kflag) {
317 		off_t off;
318 
319 		Sysmap = (struct pte *)
320 		   malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
321 		if (!Sysmap) {
322 			fputs("arp: can't get memory for Sysmap.\n", stderr);
323 			exit(1);
324 		}
325 		off = nl[N_SYSMAP].n_value & ~KERNBASE;
326 		(void)lseek(mf, off, L_SET);
327 		(void)read(mf, (char *)Sysmap,
328 		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
329 	}
330 	klseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, L_SET);
331 	read(mf, &arptab_size, sizeof arptab_size);
332 	if (arptab_size <= 0 || arptab_size > 1000) {
333 		fprintf(stderr, "arp: %s: namelist wrong\n", kernel);
334 		exit(1);
335 	}
336 	sz = arptab_size * sizeof (struct arptab);
337 	at = (struct arptab *)malloc((u_int)sz);
338 	if (at == NULL) {
339 		fputs("arp: can't get memory for arptab.\n", stderr);
340 		exit(1);
341 	}
342 	klseek(mf, (long)nl[X_ARPTAB].n_value, L_SET);
343 	if (read(mf, (char *)at, sz) != sz) {
344 		perror("arp: error reading arptab");
345 		exit(1);
346 	}
347 	close(mf);
348 	for (bynumber = 0; arptab_size-- > 0; at++) {
349 		if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
350 			continue;
351 		if (bynumber == 0)
352 			hp = gethostbyaddr((caddr_t)&at->at_iaddr,
353 			    sizeof at->at_iaddr, AF_INET);
354 		else
355 			hp = 0;
356 		if (hp)
357 			host = hp->h_name;
358 		else {
359 			host = "?";
360 			if (h_errno == TRY_AGAIN)
361 				bynumber = 1;
362 		}
363 		printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr));
364 		if (at->at_flags & ATF_COM)
365 			ether_print(at->at_enaddr);
366 		else
367 			printf("(incomplete)");
368 		if (at->at_flags & ATF_PERM)
369 			printf(" permanent");
370 		if (at->at_flags & ATF_PUBL)
371 			printf(" published");
372 		if (at->at_flags & ATF_USETRAILERS)
373 			printf(" trailers");
374 		printf("\n");
375 	}
376 }
377 
378 /*
379  * Seek into the kernel for a value.
380  */
381 klseek(fd, base, off)
382 	int fd, off;
383 	off_t base;
384 {
385 	off_t lseek();
386 
387 	if (kflag) {	/* get kernel pte */
388 		base &= ~KERNBASE;
389 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
390 	}
391 	(void)lseek(fd, base, off);
392 }
393 
394 ether_print(cp)
395 	u_char *cp;
396 {
397 	printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
398 }
399 
400 ether_aton(a, n)
401 	char *a;
402 	u_char *n;
403 {
404 	int i, o[6];
405 
406 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
407 					   &o[3], &o[4], &o[5]);
408 	if (i != 6) {
409 		fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
410 		return (1);
411 	}
412 	for (i=0; i<6; i++)
413 		n[i] = o[i];
414 	return (0);
415 }
416 
417 usage()
418 {
419 	printf("usage: arp hostname\n");
420 	printf("       arp -a [kernel] [kernel_memory]\n");
421 	printf("       arp -d hostname\n");
422 	printf("       arp -s hostname ether_addr [temp] [pub] [trail]\n");
423 	printf("       arp -f filename\n");
424 	exit(1);
425 }
426