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