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