arp.c revision 1.4 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, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #ifndef lint
38 char copyright[] =
39 "@(#) Copyright (c) 1984 Regents of the University of California.\n\
40 All rights reserved.\n";
41 #endif /* not lint */
42
43 #ifndef lint
44 /*static char sccsid[] = "from: @(#)arp.c 5.11.1.1 (Berkeley) 7/22/91";*/
45 static char rcsid[] = "$Id: arp.c,v 1.4 1993/12/25 02:28:46 deraadt Exp $";
46 #endif /* not lint */
47
48 /*
49 * arp - display, set, and delete arp table entries
50 */
51
52 #include <sys/param.h>
53 #include <sys/file.h>
54 #include <sys/socket.h>
55 #include <sys/ioctl.h>
56
57 #include <netdb.h>
58 #include <netinet/in.h>
59 #include <net/if.h>
60 #include <netinet/if_ether.h>
61 #include <arpa/inet.h>
62
63 #include <errno.h>
64 #include <nlist.h>
65 #include <kvm.h>
66 #include <stdio.h>
67 #include <paths.h>
68
69 extern int errno;
70
71 main(argc, argv)
72 int argc;
73 char **argv;
74 {
75 int ch;
76
77 while ((ch = getopt(argc, argv, "adsf")) != EOF)
78 switch((char)ch) {
79 case 'a': {
80 char *mem = 0;
81
82 if (argc > 4)
83 usage();
84 if (argc == 4) {
85 mem = argv[3];
86 }
87 dump((argc >= 3) ? argv[2] : _PATH_UNIX, mem);
88 exit(0);
89 }
90 case 'd':
91 if (argc != 3)
92 usage();
93 delete(argv[2]);
94 exit(0);
95 case 's':
96 if (argc < 4 || argc > 7)
97 usage();
98 exit(set(argc-2, &argv[2]) ? 1 : 0);
99 case 'f':
100 if (argc != 3)
101 usage();
102 exit (file(argv[2]) ? 1 : 0);
103 case '?':
104 default:
105 usage();
106 }
107 if (argc != 2)
108 usage();
109 get(argv[1]);
110 exit(0);
111 }
112
113 /*
114 * Process a file to set standard arp entries
115 */
116 file(name)
117 char *name;
118 {
119 FILE *fp;
120 int i, retval;
121 char line[100], arg[5][50], *args[5];
122
123 setregid(getegid(), getgid());
124 if ((fp = fopen(name, "r")) == NULL) {
125 fprintf(stderr, "arp: cannot open %s\n", name);
126 exit(1);
127 }
128 setregid(getegid(), getgid());
129 args[0] = &arg[0][0];
130 args[1] = &arg[1][0];
131 args[2] = &arg[2][0];
132 args[3] = &arg[3][0];
133 args[4] = &arg[4][0];
134 retval = 0;
135 while(fgets(line, 100, fp) != NULL) {
136 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
137 arg[3], arg[4]);
138 if (i < 2) {
139 fprintf(stderr, "arp: bad line: %s\n", line);
140 retval = 1;
141 continue;
142 }
143 if (set(i, args))
144 retval = 1;
145 }
146 fclose(fp);
147 return (retval);
148 }
149
150 /*
151 * Set an individual arp entry
152 */
153 set(argc, argv)
154 int argc;
155 char **argv;
156 {
157 struct arpreq ar;
158 struct hostent *hp;
159 struct sockaddr_in *sin;
160 u_char *ea;
161 int s;
162 char *host = argv[0], *eaddr = argv[1];
163
164 argc -= 2;
165 argv += 2;
166 bzero((caddr_t)&ar, sizeof ar);
167 sin = (struct sockaddr_in *)&ar.arp_pa;
168 sin->sin_family = AF_INET;
169 sin->sin_addr.s_addr = inet_addr(host);
170 if (sin->sin_addr.s_addr == -1) {
171 if (!(hp = gethostbyname(host))) {
172 fprintf(stderr, "arp: %s: ", host);
173 herror((char *)NULL);
174 return (1);
175 }
176 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
177 sizeof sin->sin_addr);
178 }
179 ea = (u_char *)ar.arp_ha.sa_data;
180 if (ether_aton(eaddr, ea))
181 return (1);
182 ar.arp_flags = ATF_PERM;
183 while (argc-- > 0) {
184 if (strncmp(argv[0], "temp", 4) == 0)
185 ar.arp_flags &= ~ATF_PERM;
186 else if (strncmp(argv[0], "pub", 3) == 0)
187 ar.arp_flags |= ATF_PUBL;
188 else if (strncmp(argv[0], "trail", 5) == 0)
189 ar.arp_flags |= ATF_USETRAILERS;
190 argv++;
191 }
192
193 s = socket(AF_INET, SOCK_DGRAM, 0);
194 if (s < 0) {
195 perror("arp: socket");
196 exit(1);
197 }
198 if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) {
199 perror(host);
200 exit(1);
201 }
202 close(s);
203 return (0);
204 }
205
206 /*
207 * Display an individual arp entry
208 */
209 get(host)
210 char *host;
211 {
212 struct arpreq ar;
213 struct hostent *hp;
214 struct sockaddr_in *sin;
215 u_char *ea;
216 int s;
217
218 bzero((caddr_t)&ar, sizeof ar);
219 ar.arp_pa.sa_family = AF_INET;
220 sin = (struct sockaddr_in *)&ar.arp_pa;
221 sin->sin_family = AF_INET;
222 sin->sin_addr.s_addr = inet_addr(host);
223 if (sin->sin_addr.s_addr == -1) {
224 if (!(hp = gethostbyname(host))) {
225 fprintf(stderr, "arp: %s: ", host);
226 herror((char *)NULL);
227 exit(1);
228 }
229 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
230 sizeof sin->sin_addr);
231 }
232 s = socket(AF_INET, SOCK_DGRAM, 0);
233 if (s < 0) {
234 perror("arp: socket");
235 exit(1);
236 }
237 if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
238 if (errno == ENXIO)
239 printf("%s (%s) -- no entry\n",
240 host, inet_ntoa(sin->sin_addr));
241 else
242 perror("SIOCGARP");
243 exit(1);
244 }
245 close(s);
246 ea = (u_char *)ar.arp_ha.sa_data;
247 printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
248 if (ar.arp_flags & ATF_COM)
249 ether_print(ea);
250 else
251 printf("(incomplete)");
252 if (ar.arp_flags & ATF_PERM)
253 printf(" permanent");
254 if (ar.arp_flags & ATF_PUBL)
255 printf(" published");
256 if (ar.arp_flags & ATF_USETRAILERS)
257 printf(" trailers");
258 printf("\n");
259 }
260
261 /*
262 * Delete an arp entry
263 */
264 delete(host)
265 char *host;
266 {
267 struct arpreq ar;
268 struct hostent *hp;
269 struct sockaddr_in *sin;
270 int s;
271
272 bzero((caddr_t)&ar, sizeof ar);
273 ar.arp_pa.sa_family = AF_INET;
274 sin = (struct sockaddr_in *)&ar.arp_pa;
275 sin->sin_family = AF_INET;
276 sin->sin_addr.s_addr = inet_addr(host);
277 if (sin->sin_addr.s_addr == -1) {
278 if (!(hp = gethostbyname(host))) {
279 fprintf(stderr, "arp: %s: ", host);
280 herror((char *)NULL);
281 exit(1);
282 }
283 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
284 sizeof sin->sin_addr);
285 }
286 s = socket(AF_INET, SOCK_DGRAM, 0);
287 if (s < 0) {
288 perror("arp: socket");
289 exit(1);
290 }
291 if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) {
292 if (errno == ENXIO)
293 printf("%s (%s) -- no entry\n",
294 host, inet_ntoa(sin->sin_addr));
295 else
296 perror("SIOCDARP");
297 exit(1);
298 }
299 close(s);
300 printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
301 }
302
303 struct nlist nl[] = {
304 #define X_ARPTAB 0
305 { "_arptab" },
306 #define X_ARPTAB_SIZE 1
307 { "_arptab_size" },
308 { "" },
309 };
310
311 /*
312 * Dump the entire arp table
313 */
314 dump(kernel, mem)
315 char *kernel, *mem;
316 {
317 extern int h_errno;
318 struct arptab *at;
319 struct hostent *hp;
320 int bynumber, mf, arptab_size, sz;
321 char *host, *malloc();
322 off_t lseek();
323
324 if (kvm_openfiles(kernel, mem, NULL) == -1) {
325 fprintf(stderr, "arp: kvm_openfiles: %s\n", kvm_geterr());
326 exit(1);
327 }
328 if (kvm_nlist(nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) {
329 fprintf(stderr, "arp: %s: bad namelist\n", kernel);
330 exit(1);
331 }
332 if (kvm_read((void *)(nl[X_ARPTAB_SIZE].n_value),
333 &arptab_size, sizeof arptab_size) == -1 ||
334 arptab_size <= 0 || arptab_size > 1000) {
335 fprintf(stderr, "arp: %s: namelist wrong\n", kernel);
336 exit(1);
337 }
338 sz = arptab_size * sizeof (struct arptab);
339 at = (struct arptab *)malloc((u_int)sz);
340 if (at == NULL) {
341 fputs("arp: can't get memory for arptab.\n", stderr);
342 exit(1);
343 }
344 if (kvm_read((void *)(nl[X_ARPTAB].n_value), (char *)at, sz) == -1) {
345 perror("arp: error reading arptab");
346 exit(1);
347 }
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 ether_print(cp)
379 u_char *cp;
380 {
381 printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
382 }
383
384 ether_aton(a, n)
385 char *a;
386 u_char *n;
387 {
388 int i, o[6];
389
390 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
391 &o[3], &o[4], &o[5]);
392 if (i != 6) {
393 fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
394 return (1);
395 }
396 for (i=0; i<6; i++)
397 n[i] = o[i];
398 return (0);
399 }
400
401 usage()
402 {
403 printf("usage: arp hostname\n");
404 printf(" arp -a [kernel] [kernel_memory]\n");
405 printf(" arp -d hostname\n");
406 printf(" arp -s hostname ether_addr [temp] [pub] [trail]\n");
407 printf(" arp -f filename\n");
408 exit(1);
409 }
410