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