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