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 #pragma ident "%Z%%M% %I% %E% SMI"
44
45 /*
46 * arp - display, set, and delete arp table entries
47 */
48
49 #include <stdio.h>
50 #include <sys/types.h>
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <sys/ioctl.h>
54 #include <errno.h>
55 #include <netdb.h>
56 #include <net/if.h>
57 #include <net/if_arp.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <string.h>
61 #include <arpa/inet.h>
62 #include <net/if_types.h>
63 #include <net/if_dl.h>
64
65 static int file(char *);
66 static int set(int, char *[]);
67 static void get(char *);
68 static void delete(char *);
69 static void usage(void);
70
71 int
main(int argc,char * argv[])72 main(int argc, char *argv[])
73 {
74 int c, nflags = 0, argsleft;
75 int n_flag, a_flag, d_flag, f_flag, s_flag;
76
77 n_flag = a_flag = d_flag = f_flag = s_flag = 0;
78
79 #define CASE(x, y) \
80 case x: \
81 if (nflags > 0) { \
82 usage(); \
83 exit(1); \
84 } else \
85 y##_flag = 1; \
86 nflags++; \
87 break
88
89 while ((c = getopt(argc, argv, "nadfs")) != EOF) {
90 switch (c) {
91 case '?':
92 usage();
93 exit(1);
94 /* NOTREACHED */
95 break;
96 case 'n':
97 n_flag = 1;
98 break;
99 CASE('a', a);
100 CASE('d', d);
101 CASE('f', f);
102 CASE('s', s);
103 }
104 }
105
106 #undef CASE
107
108 /*
109 * -n only allowed with -a
110 */
111 if (n_flag && !a_flag) {
112 usage();
113 exit(1);
114 }
115
116 argsleft = argc - optind;
117
118 if (a_flag && (argsleft == 0)) {
119 /*
120 * the easiest way to get the complete arp table
121 * is to let netstat, which prints it as part of
122 * the MIB statistics, do it.
123 */
124 (void) execl("/usr/bin/netstat", "netstat",
125 (n_flag ? "-np" : "-p"),
126 "-f", "inet", (char *)0);
127 exit(1);
128
129 } else if (s_flag && (argsleft >= 2)) {
130 if (set(argsleft, &argv[optind]) != 0)
131 exit(1);
132
133 } else if (d_flag && (argsleft == 1)) {
134 delete(argv[optind]);
135
136 } else if (f_flag && (argsleft == 1)) {
137 if (file(argv[optind]) != 0)
138 exit(1);
139
140 } else if ((nflags == 0) && (argsleft == 1)) {
141 get(argv[optind]);
142
143 } else {
144 usage();
145 exit(1);
146 }
147 return (0);
148 }
149
150 /*
151 * Process a file to set standard arp entries
152 */
153 static int
file(char * name)154 file(char *name)
155 {
156 /*
157 * A line of input can be:
158 * <hostname> <macaddr> ["temp"] ["pub"] ["trail"] ["permanent"]
159 */
160 #define MAX_LINE_LEN (MAXHOSTNAMELEN + \
161 sizeof (" xx:xx:xx:xx:xx:xx temp pub trail permanent\n"))
162 #define MIN_ARGS 2
163 #define MAX_ARGS 5
164
165 FILE *fp;
166 char line[MAX_LINE_LEN];
167 int retval;
168
169 if ((fp = fopen(name, "r")) == NULL) {
170 (void) fprintf(stderr, "arp: cannot open %s\n", name);
171 exit(1);
172 }
173
174 retval = 0;
175 while (fgets(line, MAX_LINE_LEN, fp) != NULL) {
176 char line_copy[MAX_LINE_LEN];
177 char *args[MAX_ARGS];
178 char *start;
179 int i;
180
181 /*
182 * Keep a copy of the un-altered line for error
183 * reporting.
184 */
185 (void) strlcpy(line_copy, line, MAX_LINE_LEN);
186
187 start = line_copy;
188 for (i = 0; i < MAX_ARGS; i++) {
189 if ((args[i] = strtok(start, " \t\n")) == NULL)
190 break;
191
192 start = NULL;
193 }
194
195 if (i < MIN_ARGS) {
196 (void) fprintf(stderr, "arp: bad line: %s\n",
197 line);
198 retval = 1;
199 continue;
200 }
201
202 if (set(i, args) != 0)
203 retval = 1;
204 }
205
206 #undef MAX_LINE_LEN
207 #undef MIN_ARGS
208 #undef MAX_ARGS
209
210 (void) fclose(fp);
211 return (retval);
212 }
213
214 /*
215 * Set an individual arp entry
216 */
217 static int
set(int argc,char * argv[])218 set(int argc, char *argv[])
219 {
220 struct xarpreq ar;
221 struct hostent *hp;
222 struct sockaddr_in *sin;
223 uchar_t *ea;
224 int s;
225 char *host = argv[0], *eaddr = argv[1];
226
227 argc -= 2;
228 argv += 2;
229 (void) memset(&ar, 0, sizeof (ar));
230 sin = (struct sockaddr_in *)&ar.xarp_pa;
231 sin->sin_family = AF_INET;
232 sin->sin_addr.s_addr = inet_addr(host);
233 if (sin->sin_addr.s_addr == (in_addr_t)-1) {
234 hp = gethostbyname(host);
235 if (hp == NULL) {
236 (void) fprintf(stderr, "arp: %s: unknown host\n",
237 host);
238 return (1);
239 }
240 (void) memcpy(&sin->sin_addr, hp->h_addr,
241 sizeof (sin->sin_addr));
242 }
243 ea = _link_aton(eaddr, &s);
244 if (ea == NULL) {
245 if (s == -1) {
246 (void) fprintf(stderr,
247 "arp: invalid link layer address '%s'\n", eaddr);
248 return (1);
249 }
250 perror("arp: nomem");
251 exit(1);
252 }
253 ar.xarp_ha.sdl_alen = s;
254 (void) memcpy(LLADDR(&ar.xarp_ha), ea, ar.xarp_ha.sdl_alen);
255 free(ea);
256 ar.xarp_ha.sdl_family = AF_LINK;
257 ar.xarp_flags = ATF_PERM;
258 while (argc-- > 0) {
259 if (strncmp(argv[0], "temp", 4) == 0) {
260 ar.xarp_flags &= ~ATF_PERM;
261 } else if (strncmp(argv[0], "pub", 3) == 0) {
262 ar.xarp_flags |= ATF_PUBL;
263 } else if (strncmp(argv[0], "trail", 5) == 0) {
264 ar.xarp_flags |= ATF_USETRAILERS;
265 } else if (strcmp(argv[0], "permanent") == 0) {
266 ar.xarp_flags |= ATF_AUTHORITY;
267 } else {
268 (void) fprintf(stderr,
269 "arp: unknown keyword '%s'\n", argv[0]);
270 return (1);
271 }
272 argv++;
273 }
274
275 if ((ar.xarp_flags & (ATF_PERM|ATF_AUTHORITY)) == ATF_AUTHORITY) {
276 (void) fprintf(stderr, "arp: 'temp' and 'permanent' flags are "
277 "not usable together.\n");
278 return (1);
279 }
280
281 s = socket(AF_INET, SOCK_DGRAM, 0);
282 if (s < 0) {
283 perror("arp: socket");
284 exit(1);
285 }
286 if (ioctl(s, SIOCSXARP, (caddr_t)&ar) < 0) {
287 perror(host);
288 exit(1);
289 }
290 (void) close(s);
291 return (0);
292 }
293
294 /*
295 * Display an individual arp entry
296 */
297 static void
get(char * host)298 get(char *host)
299 {
300 struct xarpreq ar;
301 struct hostent *hp;
302 struct sockaddr_in *sin;
303 uchar_t *ea;
304 int s;
305 char *str = NULL;
306
307 (void) memset(&ar, 0, sizeof (ar));
308 sin = (struct sockaddr_in *)&ar.xarp_pa;
309 sin->sin_family = AF_INET;
310 sin->sin_addr.s_addr = inet_addr(host);
311 if (sin->sin_addr.s_addr == (in_addr_t)-1) {
312 hp = gethostbyname(host);
313 if (hp == NULL) {
314 (void) fprintf(stderr, "arp: %s: unknown host\n",
315 host);
316 exit(1);
317 }
318 (void) memcpy(&sin->sin_addr, hp->h_addr,
319 sizeof (sin->sin_addr));
320 }
321 s = socket(AF_INET, SOCK_DGRAM, 0);
322 if (s < 0) {
323 perror("arp: socket");
324 exit(1);
325 }
326 ar.xarp_ha.sdl_family = AF_LINK;
327 if (ioctl(s, SIOCGXARP, (caddr_t)&ar) < 0) {
328 if (errno == ENXIO)
329 (void) printf("%s (%s) -- no entry\n",
330 host, inet_ntoa(sin->sin_addr));
331 else
332 perror("SIOCGXARP");
333 exit(1);
334 }
335 (void) close(s);
336 ea = (uchar_t *)LLADDR(&ar.xarp_ha);
337 if (ar.xarp_flags & ATF_COM) {
338 str = _link_ntoa(ea, str, ar.xarp_ha.sdl_alen, IFT_OTHER);
339 if (str != NULL) {
340 (void) printf("%s (%s) at %s", host,
341 inet_ntoa(sin->sin_addr), str);
342 free(str);
343 } else {
344 perror("arp: nomem");
345 exit(1);
346 }
347 } else {
348 (void) printf("%s (%s) at (incomplete)", host,
349 inet_ntoa(sin->sin_addr));
350 }
351 if (!(ar.xarp_flags & ATF_PERM))
352 (void) printf(" temp");
353 if (ar.xarp_flags & ATF_PUBL)
354 (void) printf(" pub");
355 if (ar.xarp_flags & ATF_USETRAILERS)
356 (void) printf(" trail");
357 if (ar.xarp_flags & ATF_AUTHORITY)
358 (void) printf(" permanent");
359 (void) printf("\n");
360 }
361
362 /*
363 * Delete an arp entry
364 */
365 static void
delete(char * host)366 delete(char *host)
367 {
368 struct xarpreq ar;
369 struct hostent *hp;
370 struct sockaddr_in *sin;
371 int s;
372
373 (void) memset(&ar, 0, sizeof (ar));
374 sin = (struct sockaddr_in *)&ar.xarp_pa;
375 sin->sin_family = AF_INET;
376 sin->sin_addr.s_addr = inet_addr(host);
377 if (sin->sin_addr.s_addr == (in_addr_t)-1) {
378 hp = gethostbyname(host);
379 if (hp == NULL) {
380 (void) fprintf(stderr, "arp: %s: unknown host\n",
381 host);
382 exit(1);
383 }
384 (void) memcpy(&sin->sin_addr, hp->h_addr,
385 sizeof (sin->sin_addr));
386 }
387 s = socket(AF_INET, SOCK_DGRAM, 0);
388 if (s < 0) {
389 perror("arp: socket");
390 exit(1);
391 }
392 ar.xarp_ha.sdl_family = AF_LINK;
393 if (ioctl(s, SIOCDXARP, (caddr_t)&ar) < 0) {
394 if (errno == ENXIO)
395 (void) printf("%s (%s) -- no entry\n",
396 host, inet_ntoa(sin->sin_addr));
397 else
398 perror("SIOCDXARP");
399 exit(1);
400 }
401 (void) close(s);
402 (void) printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
403 }
404
405 static void
usage(void)406 usage(void)
407 {
408 (void) printf("Usage: arp hostname\n");
409 (void) printf(" arp -a [-n]\n");
410 (void) printf(" arp -d hostname\n");
411 (void) printf(" arp -s hostname ether_addr "
412 "[temp] [pub] [trail] [permanent]\n");
413 (void) printf(" arp -f filename\n");
414 }
415