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 62 static int file(char *); 63 static int set(int, char *[]); 64 static void get(char *); 65 static void delete(char *); 66 static void usage(void); 67 68 int 69 main(int argc, char *argv[]) 70 { 71 int c, nflags = 0, argsleft; 72 int n_flag, a_flag, d_flag, f_flag, s_flag; 73 74 n_flag = a_flag = d_flag = f_flag = s_flag = 0; 75 76 #define CASE(x, y) \ 77 case x: \ 78 if (nflags > 0) { \ 79 usage(); \ 80 exit(1); \ 81 } else { \ 82 y##_flag = 1; \ 83 } \ 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 (void) execl("/usr/bin/netstat", "netstat", 123 (n_flag ? "-np" : "-p"), 124 "-f", "inet", (char *)0); 125 (void) fprintf(stderr, "failed to exec netstat: %s\n", 126 strerror(errno)); 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 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 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 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 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 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