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