arp.c revision 1.3 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.3 mycroft static char rcsid[] = "$Id: arp.c,v 1.3 1993/08/01 18:00:27 mycroft 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.1 cgd if ((fp = fopen(name, "r")) == NULL) {
124 1.1 cgd fprintf(stderr, "arp: cannot open %s\n", name);
125 1.1 cgd exit(1);
126 1.1 cgd }
127 1.1 cgd args[0] = &arg[0][0];
128 1.1 cgd args[1] = &arg[1][0];
129 1.1 cgd args[2] = &arg[2][0];
130 1.1 cgd args[3] = &arg[3][0];
131 1.1 cgd args[4] = &arg[4][0];
132 1.1 cgd retval = 0;
133 1.1 cgd while(fgets(line, 100, fp) != NULL) {
134 1.1 cgd i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
135 1.1 cgd arg[3], arg[4]);
136 1.1 cgd if (i < 2) {
137 1.1 cgd fprintf(stderr, "arp: bad line: %s\n", line);
138 1.1 cgd retval = 1;
139 1.1 cgd continue;
140 1.1 cgd }
141 1.1 cgd if (set(i, args))
142 1.1 cgd retval = 1;
143 1.1 cgd }
144 1.1 cgd fclose(fp);
145 1.1 cgd return (retval);
146 1.1 cgd }
147 1.1 cgd
148 1.1 cgd /*
149 1.1 cgd * Set an individual arp entry
150 1.1 cgd */
151 1.1 cgd set(argc, argv)
152 1.1 cgd int argc;
153 1.1 cgd char **argv;
154 1.1 cgd {
155 1.1 cgd struct arpreq ar;
156 1.1 cgd struct hostent *hp;
157 1.1 cgd struct sockaddr_in *sin;
158 1.1 cgd u_char *ea;
159 1.1 cgd int s;
160 1.1 cgd char *host = argv[0], *eaddr = argv[1];
161 1.1 cgd
162 1.1 cgd argc -= 2;
163 1.1 cgd argv += 2;
164 1.1 cgd bzero((caddr_t)&ar, sizeof ar);
165 1.1 cgd sin = (struct sockaddr_in *)&ar.arp_pa;
166 1.1 cgd sin->sin_family = AF_INET;
167 1.1 cgd sin->sin_addr.s_addr = inet_addr(host);
168 1.1 cgd if (sin->sin_addr.s_addr == -1) {
169 1.1 cgd if (!(hp = gethostbyname(host))) {
170 1.1 cgd fprintf(stderr, "arp: %s: ", host);
171 1.1 cgd herror((char *)NULL);
172 1.1 cgd return (1);
173 1.1 cgd }
174 1.1 cgd bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
175 1.1 cgd sizeof sin->sin_addr);
176 1.1 cgd }
177 1.1 cgd ea = (u_char *)ar.arp_ha.sa_data;
178 1.1 cgd if (ether_aton(eaddr, ea))
179 1.1 cgd return (1);
180 1.1 cgd ar.arp_flags = ATF_PERM;
181 1.1 cgd while (argc-- > 0) {
182 1.1 cgd if (strncmp(argv[0], "temp", 4) == 0)
183 1.1 cgd ar.arp_flags &= ~ATF_PERM;
184 1.1 cgd else if (strncmp(argv[0], "pub", 3) == 0)
185 1.1 cgd ar.arp_flags |= ATF_PUBL;
186 1.1 cgd else if (strncmp(argv[0], "trail", 5) == 0)
187 1.1 cgd ar.arp_flags |= ATF_USETRAILERS;
188 1.1 cgd argv++;
189 1.1 cgd }
190 1.1 cgd
191 1.1 cgd s = socket(AF_INET, SOCK_DGRAM, 0);
192 1.1 cgd if (s < 0) {
193 1.1 cgd perror("arp: socket");
194 1.1 cgd exit(1);
195 1.1 cgd }
196 1.1 cgd if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) {
197 1.1 cgd perror(host);
198 1.1 cgd exit(1);
199 1.1 cgd }
200 1.1 cgd close(s);
201 1.1 cgd return (0);
202 1.1 cgd }
203 1.1 cgd
204 1.1 cgd /*
205 1.1 cgd * Display an individual arp entry
206 1.1 cgd */
207 1.1 cgd get(host)
208 1.1 cgd char *host;
209 1.1 cgd {
210 1.1 cgd struct arpreq ar;
211 1.1 cgd struct hostent *hp;
212 1.1 cgd struct sockaddr_in *sin;
213 1.1 cgd u_char *ea;
214 1.1 cgd int s;
215 1.1 cgd
216 1.1 cgd bzero((caddr_t)&ar, sizeof ar);
217 1.1 cgd ar.arp_pa.sa_family = AF_INET;
218 1.1 cgd sin = (struct sockaddr_in *)&ar.arp_pa;
219 1.1 cgd sin->sin_family = AF_INET;
220 1.1 cgd sin->sin_addr.s_addr = inet_addr(host);
221 1.1 cgd if (sin->sin_addr.s_addr == -1) {
222 1.1 cgd if (!(hp = gethostbyname(host))) {
223 1.1 cgd fprintf(stderr, "arp: %s: ", host);
224 1.1 cgd herror((char *)NULL);
225 1.1 cgd exit(1);
226 1.1 cgd }
227 1.1 cgd bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
228 1.1 cgd sizeof sin->sin_addr);
229 1.1 cgd }
230 1.1 cgd s = socket(AF_INET, SOCK_DGRAM, 0);
231 1.1 cgd if (s < 0) {
232 1.1 cgd perror("arp: socket");
233 1.1 cgd exit(1);
234 1.1 cgd }
235 1.1 cgd if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
236 1.1 cgd if (errno == ENXIO)
237 1.1 cgd printf("%s (%s) -- no entry\n",
238 1.1 cgd host, inet_ntoa(sin->sin_addr));
239 1.1 cgd else
240 1.1 cgd perror("SIOCGARP");
241 1.1 cgd exit(1);
242 1.1 cgd }
243 1.1 cgd close(s);
244 1.1 cgd ea = (u_char *)ar.arp_ha.sa_data;
245 1.1 cgd printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
246 1.1 cgd if (ar.arp_flags & ATF_COM)
247 1.1 cgd ether_print(ea);
248 1.1 cgd else
249 1.1 cgd printf("(incomplete)");
250 1.1 cgd if (ar.arp_flags & ATF_PERM)
251 1.1 cgd printf(" permanent");
252 1.1 cgd if (ar.arp_flags & ATF_PUBL)
253 1.1 cgd printf(" published");
254 1.1 cgd if (ar.arp_flags & ATF_USETRAILERS)
255 1.1 cgd printf(" trailers");
256 1.1 cgd printf("\n");
257 1.1 cgd }
258 1.1 cgd
259 1.1 cgd /*
260 1.1 cgd * Delete an arp entry
261 1.1 cgd */
262 1.1 cgd delete(host)
263 1.1 cgd char *host;
264 1.1 cgd {
265 1.1 cgd struct arpreq ar;
266 1.1 cgd struct hostent *hp;
267 1.1 cgd struct sockaddr_in *sin;
268 1.1 cgd int s;
269 1.1 cgd
270 1.1 cgd bzero((caddr_t)&ar, sizeof ar);
271 1.1 cgd ar.arp_pa.sa_family = AF_INET;
272 1.1 cgd sin = (struct sockaddr_in *)&ar.arp_pa;
273 1.1 cgd sin->sin_family = AF_INET;
274 1.1 cgd sin->sin_addr.s_addr = inet_addr(host);
275 1.1 cgd if (sin->sin_addr.s_addr == -1) {
276 1.1 cgd if (!(hp = gethostbyname(host))) {
277 1.1 cgd fprintf(stderr, "arp: %s: ", host);
278 1.1 cgd herror((char *)NULL);
279 1.1 cgd exit(1);
280 1.1 cgd }
281 1.1 cgd bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
282 1.1 cgd sizeof sin->sin_addr);
283 1.1 cgd }
284 1.1 cgd s = socket(AF_INET, SOCK_DGRAM, 0);
285 1.1 cgd if (s < 0) {
286 1.1 cgd perror("arp: socket");
287 1.1 cgd exit(1);
288 1.1 cgd }
289 1.1 cgd if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) {
290 1.1 cgd if (errno == ENXIO)
291 1.1 cgd printf("%s (%s) -- no entry\n",
292 1.1 cgd host, inet_ntoa(sin->sin_addr));
293 1.1 cgd else
294 1.1 cgd perror("SIOCDARP");
295 1.1 cgd exit(1);
296 1.1 cgd }
297 1.1 cgd close(s);
298 1.1 cgd printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
299 1.1 cgd }
300 1.1 cgd
301 1.1 cgd struct nlist nl[] = {
302 1.1 cgd #define X_ARPTAB 0
303 1.1 cgd { "_arptab" },
304 1.1 cgd #define X_ARPTAB_SIZE 1
305 1.1 cgd { "_arptab_size" },
306 1.1 cgd { "" },
307 1.1 cgd };
308 1.1 cgd
309 1.1 cgd /*
310 1.1 cgd * Dump the entire arp table
311 1.1 cgd */
312 1.1 cgd dump(kernel, mem)
313 1.1 cgd char *kernel, *mem;
314 1.1 cgd {
315 1.1 cgd extern int h_errno;
316 1.1 cgd struct arptab *at;
317 1.1 cgd struct hostent *hp;
318 1.1 cgd int bynumber, mf, arptab_size, sz;
319 1.1 cgd char *host, *malloc();
320 1.1 cgd off_t lseek();
321 1.1 cgd
322 1.1 cgd if (kvm_openfiles(kernel, mem, NULL) == -1) {
323 1.1 cgd fprintf(stderr, "arp: kvm_openfiles: %s\n", kvm_geterr());
324 1.1 cgd exit(1);
325 1.1 cgd }
326 1.1 cgd if (kvm_nlist(nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) {
327 1.1 cgd fprintf(stderr, "arp: %s: bad namelist\n", kernel);
328 1.1 cgd exit(1);
329 1.1 cgd }
330 1.1 cgd if (kvm_read((void *)(nl[X_ARPTAB_SIZE].n_value),
331 1.1 cgd &arptab_size, sizeof arptab_size) == -1 ||
332 1.1 cgd arptab_size <= 0 || arptab_size > 1000) {
333 1.1 cgd fprintf(stderr, "arp: %s: namelist wrong\n", kernel);
334 1.1 cgd exit(1);
335 1.1 cgd }
336 1.1 cgd sz = arptab_size * sizeof (struct arptab);
337 1.1 cgd at = (struct arptab *)malloc((u_int)sz);
338 1.1 cgd if (at == NULL) {
339 1.1 cgd fputs("arp: can't get memory for arptab.\n", stderr);
340 1.1 cgd exit(1);
341 1.1 cgd }
342 1.1 cgd if (kvm_read((void *)(nl[X_ARPTAB].n_value), (char *)at, sz) == -1) {
343 1.1 cgd perror("arp: error reading arptab");
344 1.1 cgd exit(1);
345 1.1 cgd }
346 1.1 cgd for (bynumber = 0; arptab_size-- > 0; at++) {
347 1.1 cgd if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
348 1.1 cgd continue;
349 1.1 cgd if (bynumber == 0)
350 1.1 cgd hp = gethostbyaddr((caddr_t)&at->at_iaddr,
351 1.1 cgd sizeof at->at_iaddr, AF_INET);
352 1.1 cgd else
353 1.1 cgd hp = 0;
354 1.1 cgd if (hp)
355 1.1 cgd host = hp->h_name;
356 1.1 cgd else {
357 1.1 cgd host = "?";
358 1.1 cgd if (h_errno == TRY_AGAIN)
359 1.1 cgd bynumber = 1;
360 1.1 cgd }
361 1.1 cgd printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr));
362 1.1 cgd if (at->at_flags & ATF_COM)
363 1.1 cgd ether_print(at->at_enaddr);
364 1.1 cgd else
365 1.1 cgd printf("(incomplete)");
366 1.1 cgd if (at->at_flags & ATF_PERM)
367 1.1 cgd printf(" permanent");
368 1.1 cgd if (at->at_flags & ATF_PUBL)
369 1.1 cgd printf(" published");
370 1.1 cgd if (at->at_flags & ATF_USETRAILERS)
371 1.1 cgd printf(" trailers");
372 1.1 cgd printf("\n");
373 1.1 cgd }
374 1.1 cgd }
375 1.1 cgd
376 1.1 cgd ether_print(cp)
377 1.1 cgd u_char *cp;
378 1.1 cgd {
379 1.1 cgd printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
380 1.1 cgd }
381 1.1 cgd
382 1.1 cgd ether_aton(a, n)
383 1.1 cgd char *a;
384 1.1 cgd u_char *n;
385 1.1 cgd {
386 1.1 cgd int i, o[6];
387 1.1 cgd
388 1.1 cgd i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
389 1.1 cgd &o[3], &o[4], &o[5]);
390 1.1 cgd if (i != 6) {
391 1.1 cgd fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
392 1.1 cgd return (1);
393 1.1 cgd }
394 1.1 cgd for (i=0; i<6; i++)
395 1.1 cgd n[i] = o[i];
396 1.1 cgd return (0);
397 1.1 cgd }
398 1.1 cgd
399 1.1 cgd usage()
400 1.1 cgd {
401 1.1 cgd printf("usage: arp hostname\n");
402 1.1 cgd printf(" arp -a [kernel] [kernel_memory]\n");
403 1.1 cgd printf(" arp -d hostname\n");
404 1.1 cgd printf(" arp -s hostname ether_addr [temp] [pub] [trail]\n");
405 1.1 cgd printf(" arp -f filename\n");
406 1.1 cgd exit(1);
407 1.1 cgd }
408