1 /* 2 * Copyright 2004 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 <netinet/if_ether.h> 59 #include <stdlib.h> 60 #include <unistd.h> 61 #include <string.h> 62 #include <arpa/inet.h> 63 #include <net/if_types.h> 64 #include <net/if_dl.h> 65 66 static int file(char *); 67 static int set(int, char *[]); 68 static void get(char *); 69 static void delete(char *); 70 static void usage(void); 71 72 int 73 main(int argc, char *argv[]) 74 { 75 int c, nflags = 0, argsleft; 76 int n_flag, a_flag, d_flag, f_flag, s_flag; 77 78 n_flag = a_flag = d_flag = f_flag = s_flag = 0; 79 80 #define CASE(x, y) \ 81 case x: \ 82 if (nflags > 0) { \ 83 usage(); \ 84 exit(1); \ 85 } else \ 86 y##_flag = 1; \ 87 nflags++; \ 88 break 89 90 while ((c = getopt(argc, argv, "nadfs")) != EOF) { 91 switch (c) { 92 case '?': 93 usage(); 94 exit(1); 95 /* NOTREACHED */ 96 break; 97 case 'n': 98 n_flag = 1; 99 break; 100 CASE('a', a); 101 CASE('d', d); 102 CASE('f', f); 103 CASE('s', s); 104 } 105 } 106 107 #undef CASE 108 109 /* 110 * -n only allowed with -a 111 */ 112 if (n_flag && !a_flag) { 113 usage(); 114 exit(1); 115 } 116 117 argsleft = argc - optind; 118 119 if (a_flag && (argsleft == 0)) { 120 /* 121 * the easiest way to get the complete arp table 122 * is to let netstat, which prints it as part of 123 * the MIB statistics, do it. 124 */ 125 (void) execl("/usr/bin/netstat", "netstat", 126 (n_flag ? "-np" : "-p"), 127 "-f", "inet", (char *)0); 128 exit(1); 129 130 } else if (s_flag && (argsleft >= 2)) { 131 if (set(argsleft, &argv[optind]) != 0) 132 exit(1); 133 134 } else if (d_flag && (argsleft == 1)) { 135 delete(argv[optind]); 136 137 } else if (f_flag && (argsleft == 1)) { 138 if (file(argv[optind]) != 0) 139 exit(1); 140 141 } else if ((nflags == 0) && (argsleft == 1)) { 142 get(argv[optind]); 143 144 } else { 145 usage(); 146 exit(1); 147 } 148 return (0); 149 } 150 151 /* 152 * Process a file to set standard arp entries 153 */ 154 static int file(char *name) 155 { 156 /* 157 * A line of input can be: 158 * <hostname> <macaddr> ["temp"] ["pub"] ["trail"] 159 */ 160 #define MAX_LINE_LEN (MAXHOSTNAMELEN + \ 161 sizeof (" xx:xx:xx:xx:xx:xx temp pub trail\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 { 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 if (strncmp(argv[0], "pub", 3) == 0) 261 ar.xarp_flags |= ATF_PUBL; 262 if (strncmp(argv[0], "trail", 5) == 0) 263 ar.xarp_flags |= ATF_USETRAILERS; 264 argv++; 265 } 266 267 s = socket(AF_INET, SOCK_DGRAM, 0); 268 if (s < 0) { 269 perror("arp: socket"); 270 exit(1); 271 } 272 if (ioctl(s, SIOCSXARP, (caddr_t)&ar) < 0) { 273 perror(host); 274 exit(1); 275 } 276 (void) close(s); 277 return (0); 278 } 279 280 281 /* 282 * Display an individual arp entry 283 */ 284 static void get(char *host) 285 { 286 struct xarpreq ar; 287 struct hostent *hp; 288 struct sockaddr_in *sin; 289 uchar_t *ea; 290 int s; 291 char *str = NULL; 292 293 (void) memset(&ar, 0, sizeof (ar)); 294 sin = (struct sockaddr_in *)&ar.xarp_pa; 295 sin->sin_family = AF_INET; 296 sin->sin_addr.s_addr = inet_addr(host); 297 if (sin->sin_addr.s_addr == (in_addr_t)-1) { 298 hp = gethostbyname(host); 299 if (hp == NULL) { 300 (void) fprintf(stderr, "arp: %s: unknown host\n", 301 host); 302 exit(1); 303 } 304 (void) memcpy(&sin->sin_addr, hp->h_addr, 305 sizeof (sin->sin_addr)); 306 } 307 s = socket(AF_INET, SOCK_DGRAM, 0); 308 if (s < 0) { 309 perror("arp: socket"); 310 exit(1); 311 } 312 ar.xarp_ha.sdl_family = AF_LINK; 313 if (ioctl(s, SIOCGXARP, (caddr_t)&ar) < 0) { 314 if (errno == ENXIO) 315 (void) printf("%s (%s) -- no entry\n", 316 host, inet_ntoa(sin->sin_addr)); 317 else 318 perror("SIOCGXARP"); 319 exit(1); 320 } 321 (void) close(s); 322 ea = (uchar_t *)LLADDR(&ar.xarp_ha); 323 if (ar.xarp_flags & ATF_COM) { 324 str = _link_ntoa(ea, str, ar.xarp_ha.sdl_alen, IFT_OTHER); 325 if (str != NULL) { 326 (void) printf("%s (%s) at %s", host, 327 inet_ntoa(sin->sin_addr), str); 328 free(str); 329 } else { 330 perror("arp: nomem"); 331 exit(1); 332 } 333 } else { 334 (void) printf("%s (%s) at (incomplete)", host, 335 inet_ntoa(sin->sin_addr)); 336 } 337 if (ar.xarp_flags & ATF_PERM) 338 (void) printf(" permanent"); 339 if (ar.xarp_flags & ATF_PUBL) 340 (void) printf(" published"); 341 if (ar.xarp_flags & ATF_USETRAILERS) 342 (void) printf(" trailers"); 343 (void) printf("\n"); 344 } 345 346 /* 347 * Delete an arp entry 348 */ 349 static void delete(char *host) 350 { 351 struct xarpreq ar; 352 struct hostent *hp; 353 struct sockaddr_in *sin; 354 int s; 355 356 (void) memset(&ar, 0, sizeof (ar)); 357 sin = (struct sockaddr_in *)&ar.xarp_pa; 358 sin->sin_family = AF_INET; 359 sin->sin_addr.s_addr = inet_addr(host); 360 if (sin->sin_addr.s_addr == (in_addr_t)-1) { 361 hp = gethostbyname(host); 362 if (hp == NULL) { 363 (void) fprintf(stderr, "arp: %s: unknown host\n", 364 host); 365 exit(1); 366 } 367 (void) memcpy(&sin->sin_addr, hp->h_addr, 368 sizeof (sin->sin_addr)); 369 } 370 s = socket(AF_INET, SOCK_DGRAM, 0); 371 if (s < 0) { 372 perror("arp: socket"); 373 exit(1); 374 } 375 ar.xarp_ha.sdl_family = AF_LINK; 376 if (ioctl(s, SIOCDXARP, (caddr_t)&ar) < 0) { 377 if (errno == ENXIO) 378 (void) printf("%s (%s) -- no entry\n", 379 host, inet_ntoa(sin->sin_addr)); 380 else 381 perror("SIOCDXARP"); 382 exit(1); 383 } 384 (void) close(s); 385 (void) printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr)); 386 } 387 388 static void usage(void) 389 { 390 (void) printf("Usage: arp hostname\n"); 391 (void) printf(" arp -a [-n]\n"); 392 (void) printf(" arp -d hostname\n"); 393 (void) printf(" arp -s hostname ether_addr " 394 "[temp] [pub] [trail]\n"); 395 (void) printf(" arp -f filename\n"); 396 } 397