1 /* 2 * Copyright (c) 1984 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Sun Microsystems, Inc. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 char copyright[] = 39 "@(#) Copyright (c) 1984 Regents of the University of California.\n\ 40 All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 /*static char sccsid[] = "from: @(#)arp.c 5.11.1.1 (Berkeley) 7/22/91";*/ 45 static char rcsid[] = "$Id: arp.c,v 1.3 1993/08/01 18:00:27 mycroft Exp $"; 46 #endif /* not lint */ 47 48 /* 49 * arp - display, set, and delete arp table entries 50 */ 51 52 #include <sys/param.h> 53 #include <sys/file.h> 54 #include <sys/socket.h> 55 #include <sys/ioctl.h> 56 57 #include <netdb.h> 58 #include <netinet/in.h> 59 #include <net/if.h> 60 #include <netinet/if_ether.h> 61 #include <arpa/inet.h> 62 63 #include <errno.h> 64 #include <nlist.h> 65 #include <kvm.h> 66 #include <stdio.h> 67 #include <paths.h> 68 69 extern int errno; 70 71 main(argc, argv) 72 int argc; 73 char **argv; 74 { 75 int ch; 76 77 while ((ch = getopt(argc, argv, "adsf")) != EOF) 78 switch((char)ch) { 79 case 'a': { 80 char *mem = 0; 81 82 if (argc > 4) 83 usage(); 84 if (argc == 4) { 85 mem = argv[3]; 86 } 87 dump((argc >= 3) ? argv[2] : _PATH_UNIX, mem); 88 exit(0); 89 } 90 case 'd': 91 if (argc != 3) 92 usage(); 93 delete(argv[2]); 94 exit(0); 95 case 's': 96 if (argc < 4 || argc > 7) 97 usage(); 98 exit(set(argc-2, &argv[2]) ? 1 : 0); 99 case 'f': 100 if (argc != 3) 101 usage(); 102 exit (file(argv[2]) ? 1 : 0); 103 case '?': 104 default: 105 usage(); 106 } 107 if (argc != 2) 108 usage(); 109 get(argv[1]); 110 exit(0); 111 } 112 113 /* 114 * Process a file to set standard arp entries 115 */ 116 file(name) 117 char *name; 118 { 119 FILE *fp; 120 int i, retval; 121 char line[100], arg[5][50], *args[5]; 122 123 if ((fp = fopen(name, "r")) == NULL) { 124 fprintf(stderr, "arp: cannot open %s\n", name); 125 exit(1); 126 } 127 args[0] = &arg[0][0]; 128 args[1] = &arg[1][0]; 129 args[2] = &arg[2][0]; 130 args[3] = &arg[3][0]; 131 args[4] = &arg[4][0]; 132 retval = 0; 133 while(fgets(line, 100, fp) != NULL) { 134 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], 135 arg[3], arg[4]); 136 if (i < 2) { 137 fprintf(stderr, "arp: bad line: %s\n", line); 138 retval = 1; 139 continue; 140 } 141 if (set(i, args)) 142 retval = 1; 143 } 144 fclose(fp); 145 return (retval); 146 } 147 148 /* 149 * Set an individual arp entry 150 */ 151 set(argc, argv) 152 int argc; 153 char **argv; 154 { 155 struct arpreq ar; 156 struct hostent *hp; 157 struct sockaddr_in *sin; 158 u_char *ea; 159 int s; 160 char *host = argv[0], *eaddr = argv[1]; 161 162 argc -= 2; 163 argv += 2; 164 bzero((caddr_t)&ar, sizeof ar); 165 sin = (struct sockaddr_in *)&ar.arp_pa; 166 sin->sin_family = AF_INET; 167 sin->sin_addr.s_addr = inet_addr(host); 168 if (sin->sin_addr.s_addr == -1) { 169 if (!(hp = gethostbyname(host))) { 170 fprintf(stderr, "arp: %s: ", host); 171 herror((char *)NULL); 172 return (1); 173 } 174 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 175 sizeof sin->sin_addr); 176 } 177 ea = (u_char *)ar.arp_ha.sa_data; 178 if (ether_aton(eaddr, ea)) 179 return (1); 180 ar.arp_flags = ATF_PERM; 181 while (argc-- > 0) { 182 if (strncmp(argv[0], "temp", 4) == 0) 183 ar.arp_flags &= ~ATF_PERM; 184 else if (strncmp(argv[0], "pub", 3) == 0) 185 ar.arp_flags |= ATF_PUBL; 186 else if (strncmp(argv[0], "trail", 5) == 0) 187 ar.arp_flags |= ATF_USETRAILERS; 188 argv++; 189 } 190 191 s = socket(AF_INET, SOCK_DGRAM, 0); 192 if (s < 0) { 193 perror("arp: socket"); 194 exit(1); 195 } 196 if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) { 197 perror(host); 198 exit(1); 199 } 200 close(s); 201 return (0); 202 } 203 204 /* 205 * Display an individual arp entry 206 */ 207 get(host) 208 char *host; 209 { 210 struct arpreq ar; 211 struct hostent *hp; 212 struct sockaddr_in *sin; 213 u_char *ea; 214 int s; 215 216 bzero((caddr_t)&ar, sizeof ar); 217 ar.arp_pa.sa_family = AF_INET; 218 sin = (struct sockaddr_in *)&ar.arp_pa; 219 sin->sin_family = AF_INET; 220 sin->sin_addr.s_addr = inet_addr(host); 221 if (sin->sin_addr.s_addr == -1) { 222 if (!(hp = gethostbyname(host))) { 223 fprintf(stderr, "arp: %s: ", host); 224 herror((char *)NULL); 225 exit(1); 226 } 227 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 228 sizeof sin->sin_addr); 229 } 230 s = socket(AF_INET, SOCK_DGRAM, 0); 231 if (s < 0) { 232 perror("arp: socket"); 233 exit(1); 234 } 235 if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) { 236 if (errno == ENXIO) 237 printf("%s (%s) -- no entry\n", 238 host, inet_ntoa(sin->sin_addr)); 239 else 240 perror("SIOCGARP"); 241 exit(1); 242 } 243 close(s); 244 ea = (u_char *)ar.arp_ha.sa_data; 245 printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr)); 246 if (ar.arp_flags & ATF_COM) 247 ether_print(ea); 248 else 249 printf("(incomplete)"); 250 if (ar.arp_flags & ATF_PERM) 251 printf(" permanent"); 252 if (ar.arp_flags & ATF_PUBL) 253 printf(" published"); 254 if (ar.arp_flags & ATF_USETRAILERS) 255 printf(" trailers"); 256 printf("\n"); 257 } 258 259 /* 260 * Delete an arp entry 261 */ 262 delete(host) 263 char *host; 264 { 265 struct arpreq ar; 266 struct hostent *hp; 267 struct sockaddr_in *sin; 268 int s; 269 270 bzero((caddr_t)&ar, sizeof ar); 271 ar.arp_pa.sa_family = AF_INET; 272 sin = (struct sockaddr_in *)&ar.arp_pa; 273 sin->sin_family = AF_INET; 274 sin->sin_addr.s_addr = inet_addr(host); 275 if (sin->sin_addr.s_addr == -1) { 276 if (!(hp = gethostbyname(host))) { 277 fprintf(stderr, "arp: %s: ", host); 278 herror((char *)NULL); 279 exit(1); 280 } 281 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 282 sizeof sin->sin_addr); 283 } 284 s = socket(AF_INET, SOCK_DGRAM, 0); 285 if (s < 0) { 286 perror("arp: socket"); 287 exit(1); 288 } 289 if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) { 290 if (errno == ENXIO) 291 printf("%s (%s) -- no entry\n", 292 host, inet_ntoa(sin->sin_addr)); 293 else 294 perror("SIOCDARP"); 295 exit(1); 296 } 297 close(s); 298 printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr)); 299 } 300 301 struct nlist nl[] = { 302 #define X_ARPTAB 0 303 { "_arptab" }, 304 #define X_ARPTAB_SIZE 1 305 { "_arptab_size" }, 306 { "" }, 307 }; 308 309 /* 310 * Dump the entire arp table 311 */ 312 dump(kernel, mem) 313 char *kernel, *mem; 314 { 315 extern int h_errno; 316 struct arptab *at; 317 struct hostent *hp; 318 int bynumber, mf, arptab_size, sz; 319 char *host, *malloc(); 320 off_t lseek(); 321 322 if (kvm_openfiles(kernel, mem, NULL) == -1) { 323 fprintf(stderr, "arp: kvm_openfiles: %s\n", kvm_geterr()); 324 exit(1); 325 } 326 if (kvm_nlist(nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) { 327 fprintf(stderr, "arp: %s: bad namelist\n", kernel); 328 exit(1); 329 } 330 if (kvm_read((void *)(nl[X_ARPTAB_SIZE].n_value), 331 &arptab_size, sizeof arptab_size) == -1 || 332 arptab_size <= 0 || arptab_size > 1000) { 333 fprintf(stderr, "arp: %s: namelist wrong\n", kernel); 334 exit(1); 335 } 336 sz = arptab_size * sizeof (struct arptab); 337 at = (struct arptab *)malloc((u_int)sz); 338 if (at == NULL) { 339 fputs("arp: can't get memory for arptab.\n", stderr); 340 exit(1); 341 } 342 if (kvm_read((void *)(nl[X_ARPTAB].n_value), (char *)at, sz) == -1) { 343 perror("arp: error reading arptab"); 344 exit(1); 345 } 346 for (bynumber = 0; arptab_size-- > 0; at++) { 347 if (at->at_iaddr.s_addr == 0 || at->at_flags == 0) 348 continue; 349 if (bynumber == 0) 350 hp = gethostbyaddr((caddr_t)&at->at_iaddr, 351 sizeof at->at_iaddr, AF_INET); 352 else 353 hp = 0; 354 if (hp) 355 host = hp->h_name; 356 else { 357 host = "?"; 358 if (h_errno == TRY_AGAIN) 359 bynumber = 1; 360 } 361 printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr)); 362 if (at->at_flags & ATF_COM) 363 ether_print(at->at_enaddr); 364 else 365 printf("(incomplete)"); 366 if (at->at_flags & ATF_PERM) 367 printf(" permanent"); 368 if (at->at_flags & ATF_PUBL) 369 printf(" published"); 370 if (at->at_flags & ATF_USETRAILERS) 371 printf(" trailers"); 372 printf("\n"); 373 } 374 } 375 376 ether_print(cp) 377 u_char *cp; 378 { 379 printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 380 } 381 382 ether_aton(a, n) 383 char *a; 384 u_char *n; 385 { 386 int i, o[6]; 387 388 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 389 &o[3], &o[4], &o[5]); 390 if (i != 6) { 391 fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a); 392 return (1); 393 } 394 for (i=0; i<6; i++) 395 n[i] = o[i]; 396 return (0); 397 } 398 399 usage() 400 { 401 printf("usage: arp hostname\n"); 402 printf(" arp -a [kernel] [kernel_memory]\n"); 403 printf(" arp -d hostname\n"); 404 printf(" arp -s hostname ether_addr [temp] [pub] [trail]\n"); 405 printf(" arp -f filename\n"); 406 exit(1); 407 } 408