1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5 /*
6 * Copyright (c) 1984 Regents of the University of California.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Sun Microsystems, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41
42 /*
43 * arp - display, set, and delete arp table entries
44 */
45
46 #include <stdio.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <sys/ioctl.h>
51 #include <errno.h>
52 #include <netdb.h>
53 #include <net/if.h>
54 #include <net/if_arp.h>
55 #include <stdlib.h>
56 #include <unistd.h>
57 #include <string.h>
58 #include <arpa/inet.h>
59 #include <net/if_types.h>
60 #include <net/if_dl.h>
61 #include <zone.h>
62
63 static int file(char *);
64 static int set(int, char *[]);
65 static void get(char *);
66 static void delete(char *);
67 static void usage(void);
68
69 int
70 main(int argc, char *argv[])
71 {
72 int c, nflags = 0, argsleft;
73 int n_flag, a_flag, d_flag, f_flag, s_flag;
74
75 n_flag = a_flag = d_flag = f_flag = s_flag = 0;
76
77 #define CASE(x, y) \
78 case x: \
79 if (nflags > 0) { \
80 usage(); \
81 exit(1); \
82 } else \
83 y##_flag = 1; \
84 nflags++; \
85 break
86
87 while ((c = getopt(argc, argv, "nadfs")) != EOF) {
88 switch (c) {
89 case '?':
90 usage();
91 exit(1);
92 /* NOTREACHED */
93 break;
94 case 'n':
95 n_flag = 1;
96 break;
97 CASE('a', a);
98 CASE('d', d);
99 CASE('f', f);
100 CASE('s', s);
101 }
102 }
103
104 #undef CASE
105
106 /*
107 * -n only allowed with -a
108 */
109 if (n_flag && !a_flag) {
110 usage();
111 exit(1);
112 }
113
114 argsleft = argc - optind;
115
116 if (a_flag && (argsleft == 0)) {
117 /*
118 * the easiest way to get the complete arp table
119 * is to let netstat, which prints it as part of
120 * the MIB statistics, do it.
121 */
122 char netstat_path[MAXPATHLEN];
123 const char *zroot = zone_get_nroot();
124 (void) snprintf(netstat_path, sizeof (netstat_path), "%s%s", zroot != NULL ?
125 zroot : "", "/usr/bin/netstat");
126 (void) execl(netstat_path, "netstat",
127 (n_flag ? "-np" : "-p"),
128 "-f", "inet", (char *)0);
129 (void) fprintf(stderr, "failed to exec %s: %s\n",
130 netstat_path, strerror(errno));
131 exit(1);
132
133 } else if (s_flag && (argsleft >= 2)) {
134 if (set(argsleft, &argv[optind]) != 0)
135 exit(1);
136
137 } else if (d_flag && (argsleft == 1)) {
138 delete(argv[optind]);
139
140 } else if (f_flag && (argsleft == 1)) {
141 if (file(argv[optind]) != 0)
142 exit(1);
143
144 } else if ((nflags == 0) && (argsleft == 1)) {
145 get(argv[optind]);
146
147 } else {
148 usage();
149 exit(1);
150 }
151 return (0);
152 }
153
154 /*
155 * Process a file to set standard arp entries
156 */
157 static int
158 file(char *name)
159 {
160 /*
161 * A line of input can be:
162 * <hostname> <macaddr> ["temp"] ["pub"] ["trail"] ["permanent"]
163 */
164 #define MAX_LINE_LEN (MAXHOSTNAMELEN + \
165 sizeof (" xx:xx:xx:xx:xx:xx temp pub trail permanent\n"))
166 #define MIN_ARGS 2
167 #define MAX_ARGS 5
168
169 FILE *fp;
170 char line[MAX_LINE_LEN];
171 int retval;
172
173 if ((fp = fopen(name, "r")) == NULL) {
174 (void) fprintf(stderr, "arp: cannot open %s\n", name);
175 exit(1);
176 }
177
178 retval = 0;
179 while (fgets(line, MAX_LINE_LEN, fp) != NULL) {
180 char line_copy[MAX_LINE_LEN];
181 char *args[MAX_ARGS];
182 char *start;
183 int i;
184
185 /*
186 * Keep a copy of the un-altered line for error
187 * reporting.
188 */
189 (void) strlcpy(line_copy, line, MAX_LINE_LEN);
190
191 start = line_copy;
192 for (i = 0; i < MAX_ARGS; i++) {
193 if ((args[i] = strtok(start, " \t\n")) == NULL)
194 break;
195
196 start = NULL;
197 }
198
199 if (i < MIN_ARGS) {
200 (void) fprintf(stderr, "arp: bad line: %s\n",
201 line);
202 retval = 1;
203 continue;
204 }
205
206 if (set(i, args) != 0)
207 retval = 1;
208 }
209
210 #undef MAX_LINE_LEN
211 #undef MIN_ARGS
212 #undef MAX_ARGS
213
214 (void) fclose(fp);
215 return (retval);
216 }
217
218 /*
219 * Set an individual arp entry
220 */
221 static int
222 set(int argc, char *argv[])
223 {
224 struct xarpreq ar;
225 struct hostent *hp;
226 struct sockaddr_in *sin;
227 uchar_t *ea;
228 int s;
229 char *host = argv[0], *eaddr = argv[1];
230
231 argc -= 2;
232 argv += 2;
233 (void) memset(&ar, 0, sizeof (ar));
234 sin = (struct sockaddr_in *)&ar.xarp_pa;
235 sin->sin_family = AF_INET;
236 sin->sin_addr.s_addr = inet_addr(host);
237 if (sin->sin_addr.s_addr == (in_addr_t)-1) {
238 hp = gethostbyname(host);
239 if (hp == NULL) {
240 (void) fprintf(stderr, "arp: %s: unknown host\n",
241 host);
242 return (1);
243 }
244 (void) memcpy(&sin->sin_addr, hp->h_addr,
245 sizeof (sin->sin_addr));
246 }
247 ea = _link_aton(eaddr, &s);
248 if (ea == NULL) {
249 if (s == -1) {
250 (void) fprintf(stderr,
251 "arp: invalid link layer address '%s'\n", eaddr);
252 return (1);
253 }
254 perror("arp: nomem");
255 exit(1);
256 }
257 ar.xarp_ha.sdl_alen = s;
258 (void) memcpy(LLADDR(&ar.xarp_ha), ea, ar.xarp_ha.sdl_alen);
259 free(ea);
260 ar.xarp_ha.sdl_family = AF_LINK;
261 ar.xarp_flags = ATF_PERM;
262 while (argc-- > 0) {
263 if (strncmp(argv[0], "temp", 4) == 0) {
264 ar.xarp_flags &= ~ATF_PERM;
265 } else if (strncmp(argv[0], "pub", 3) == 0) {
266 ar.xarp_flags |= ATF_PUBL;
267 } else if (strncmp(argv[0], "trail", 5) == 0) {
268 ar.xarp_flags |= ATF_USETRAILERS;
269 } else if (strcmp(argv[0], "permanent") == 0) {
270 ar.xarp_flags |= ATF_AUTHORITY;
271 } else {
272 (void) fprintf(stderr,
273 "arp: unknown keyword '%s'\n", argv[0]);
274 return (1);
275 }
276 argv++;
277 }
278
279 if ((ar.xarp_flags & (ATF_PERM|ATF_AUTHORITY)) == ATF_AUTHORITY) {
280 (void) fprintf(stderr, "arp: 'temp' and 'permanent' flags are "
281 "not usable together.\n");
282 return (1);
283 }
284
285 s = socket(AF_INET, SOCK_DGRAM, 0);
286 if (s < 0) {
287 perror("arp: socket");
288 exit(1);
289 }
290 if (ioctl(s, SIOCSXARP, (caddr_t)&ar) < 0) {
291 perror(host);
292 exit(1);
293 }
294 (void) close(s);
295 return (0);
296 }
297
298 /*
299 * Display an individual arp entry
300 */
301 static void
302 get(char *host)
303 {
304 struct xarpreq ar;
305 struct hostent *hp;
306 struct sockaddr_in *sin;
307 uchar_t *ea;
308 int s;
309 char *str = NULL;
310
311 (void) memset(&ar, 0, sizeof (ar));
312 sin = (struct sockaddr_in *)&ar.xarp_pa;
313 sin->sin_family = AF_INET;
314 sin->sin_addr.s_addr = inet_addr(host);
315 if (sin->sin_addr.s_addr == (in_addr_t)-1) {
316 hp = gethostbyname(host);
317 if (hp == NULL) {
318 (void) fprintf(stderr, "arp: %s: unknown host\n",
319 host);
320 exit(1);
321 }
322 (void) memcpy(&sin->sin_addr, hp->h_addr,
323 sizeof (sin->sin_addr));
324 }
325 s = socket(AF_INET, SOCK_DGRAM, 0);
326 if (s < 0) {
327 perror("arp: socket");
328 exit(1);
329 }
330 ar.xarp_ha.sdl_family = AF_LINK;
331 if (ioctl(s, SIOCGXARP, (caddr_t)&ar) < 0) {
332 if (errno == ENXIO)
333 (void) printf("%s (%s) -- no entry\n",
334 host, inet_ntoa(sin->sin_addr));
335 else
336 perror("SIOCGXARP");
337 exit(1);
338 }
339 (void) close(s);
340 ea = (uchar_t *)LLADDR(&ar.xarp_ha);
341 if (ar.xarp_flags & ATF_COM) {
342 str = _link_ntoa(ea, str, ar.xarp_ha.sdl_alen, IFT_OTHER);
343 if (str != NULL) {
344 (void) printf("%s (%s) at %s", host,
345 inet_ntoa(sin->sin_addr), str);
346 free(str);
347 } else {
348 perror("arp: nomem");
349 exit(1);
350 }
351 } else {
352 (void) printf("%s (%s) at (incomplete)", host,
353 inet_ntoa(sin->sin_addr));
354 }
355 if (!(ar.xarp_flags & ATF_PERM))
356 (void) printf(" temp");
357 if (ar.xarp_flags & ATF_PUBL)
358 (void) printf(" pub");
359 if (ar.xarp_flags & ATF_USETRAILERS)
360 (void) printf(" trail");
361 if (ar.xarp_flags & ATF_AUTHORITY)
362 (void) printf(" permanent");
363 (void) printf("\n");
364 }
365
366 /*
367 * Delete an arp entry
368 */
369 static void
370 delete(char *host)
371 {
372 struct xarpreq ar;
373 struct hostent *hp;
374 struct sockaddr_in *sin;
375 int s;
376
377 (void) memset(&ar, 0, sizeof (ar));
378 sin = (struct sockaddr_in *)&ar.xarp_pa;
379 sin->sin_family = AF_INET;
380 sin->sin_addr.s_addr = inet_addr(host);
381 if (sin->sin_addr.s_addr == (in_addr_t)-1) {
382 hp = gethostbyname(host);
383 if (hp == NULL) {
384 (void) fprintf(stderr, "arp: %s: unknown host\n",
385 host);
386 exit(1);
387 }
388 (void) memcpy(&sin->sin_addr, hp->h_addr,
389 sizeof (sin->sin_addr));
390 }
391 s = socket(AF_INET, SOCK_DGRAM, 0);
392 if (s < 0) {
393 perror("arp: socket");
394 exit(1);
395 }
396 ar.xarp_ha.sdl_family = AF_LINK;
397 if (ioctl(s, SIOCDXARP, (caddr_t)&ar) < 0) {
398 if (errno == ENXIO)
399 (void) printf("%s (%s) -- no entry\n",
400 host, inet_ntoa(sin->sin_addr));
401 else
402 perror("SIOCDXARP");
403 exit(1);
404 }
405 (void) close(s);
406 (void) printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
407 }
408
409 static void
410 usage(void)
411 {
412 (void) printf("Usage: arp hostname\n");
413 (void) printf(" arp -a [-n]\n");
414 (void) printf(" arp -d hostname\n");
415 (void) printf(" arp -s hostname ether_addr "
416 "[temp] [pub] [trail] [permanent]\n");
417 (void) printf(" arp -f filename\n");
418 }