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 are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 */ 20 21 #ifndef lint 22 char copyright[] = 23 "@(#) Copyright (c) 1984 Regents of the University of California.\n\ 24 All rights reserved.\n"; 25 #endif /* not lint */ 26 27 #ifndef lint 28 static char sccsid[] = "@(#)arp.c 5.10 (Berkeley) 05/11/89"; 29 #endif /* not lint */ 30 31 /* 32 * arp - display, set, and delete arp table entries 33 */ 34 35 #include <machine/pte.h> 36 37 #include <sys/param.h> 38 #include <sys/vmmac.h> 39 #include <sys/file.h> 40 #include <sys/socket.h> 41 #include <sys/ioctl.h> 42 43 #include <netdb.h> 44 #include <netinet/in.h> 45 #include <net/if.h> 46 #include <netinet/if_ether.h> 47 48 #include <errno.h> 49 #include <nlist.h> 50 #include <stdio.h> 51 #include <paths.h> 52 53 extern int errno; 54 static int kflag; 55 56 main(argc, argv) 57 int argc; 58 char **argv; 59 { 60 int ch; 61 62 while ((ch = getopt(argc, argv, "adsf")) != EOF) 63 switch((char)ch) { 64 case 'a': { 65 char *mem; 66 67 if (argc > 4) 68 usage(); 69 if (argc == 4) { 70 kflag = 1; 71 mem = argv[3]; 72 } 73 else 74 mem = _PATH_KMEM; 75 dump((argc >= 3) ? argv[2] : _PATH_UNIX, mem); 76 exit(0); 77 } 78 case 'd': 79 if (argc != 3) 80 usage(); 81 delete(argv[2]); 82 exit(0); 83 case 's': 84 if (argc < 4 || argc > 7) 85 usage(); 86 exit(set(argc-2, &argv[2]) ? 1 : 0); 87 case 'f': 88 if (argc != 3) 89 usage(); 90 exit (file(argv[2]) ? 1 : 0); 91 case '?': 92 default: 93 usage(); 94 } 95 if (argc != 2) 96 usage(); 97 get(argv[1]); 98 exit(0); 99 } 100 101 /* 102 * Process a file to set standard arp entries 103 */ 104 file(name) 105 char *name; 106 { 107 FILE *fp; 108 int i, retval; 109 char line[100], arg[5][50], *args[5]; 110 111 if ((fp = fopen(name, "r")) == NULL) { 112 fprintf(stderr, "arp: cannot open %s\n", name); 113 exit(1); 114 } 115 args[0] = &arg[0][0]; 116 args[1] = &arg[1][0]; 117 args[2] = &arg[2][0]; 118 args[3] = &arg[3][0]; 119 args[4] = &arg[4][0]; 120 retval = 0; 121 while(fgets(line, 100, fp) != NULL) { 122 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], 123 arg[3], arg[4]); 124 if (i < 2) { 125 fprintf(stderr, "arp: bad line: %s\n", line); 126 retval = 1; 127 continue; 128 } 129 if (set(i, args)) 130 retval = 1; 131 } 132 fclose(fp); 133 return (retval); 134 } 135 136 /* 137 * Set an individual arp entry 138 */ 139 set(argc, argv) 140 int argc; 141 char **argv; 142 { 143 struct arpreq ar; 144 struct hostent *hp; 145 struct sockaddr_in *sin; 146 u_char *ea; 147 int s; 148 char *host = argv[0], *eaddr = argv[1]; 149 150 argc -= 2; 151 argv += 2; 152 bzero((caddr_t)&ar, sizeof ar); 153 sin = (struct sockaddr_in *)&ar.arp_pa; 154 sin->sin_family = AF_INET; 155 sin->sin_addr.s_addr = inet_addr(host); 156 if (sin->sin_addr.s_addr == -1) { 157 if (!(hp = gethostbyname(host))) { 158 fprintf(stderr, "arp: %s: ", host); 159 herror((char *)NULL); 160 return (1); 161 } 162 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 163 sizeof sin->sin_addr); 164 } 165 ea = (u_char *)ar.arp_ha.sa_data; 166 if (ether_aton(eaddr, ea)) 167 return (1); 168 ar.arp_flags = ATF_PERM; 169 while (argc-- > 0) { 170 if (strncmp(argv[0], "temp", 4) == 0) 171 ar.arp_flags &= ~ATF_PERM; 172 else if (strncmp(argv[0], "pub", 3) == 0) 173 ar.arp_flags |= ATF_PUBL; 174 else if (strncmp(argv[0], "trail", 5) == 0) 175 ar.arp_flags |= ATF_USETRAILERS; 176 argv++; 177 } 178 179 s = socket(AF_INET, SOCK_DGRAM, 0); 180 if (s < 0) { 181 perror("arp: socket"); 182 exit(1); 183 } 184 if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) { 185 perror(host); 186 exit(1); 187 } 188 close(s); 189 return (0); 190 } 191 192 /* 193 * Display an individual arp entry 194 */ 195 get(host) 196 char *host; 197 { 198 struct arpreq ar; 199 struct hostent *hp; 200 struct sockaddr_in *sin; 201 u_char *ea; 202 int s; 203 char *inet_ntoa(); 204 205 bzero((caddr_t)&ar, sizeof ar); 206 ar.arp_pa.sa_family = AF_INET; 207 sin = (struct sockaddr_in *)&ar.arp_pa; 208 sin->sin_family = AF_INET; 209 sin->sin_addr.s_addr = inet_addr(host); 210 if (sin->sin_addr.s_addr == -1) { 211 if (!(hp = gethostbyname(host))) { 212 fprintf(stderr, "arp: %s: ", host); 213 herror((char *)NULL); 214 exit(1); 215 } 216 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 217 sizeof sin->sin_addr); 218 } 219 s = socket(AF_INET, SOCK_DGRAM, 0); 220 if (s < 0) { 221 perror("arp: socket"); 222 exit(1); 223 } 224 if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) { 225 if (errno == ENXIO) 226 printf("%s (%s) -- no entry\n", 227 host, inet_ntoa(sin->sin_addr)); 228 else 229 perror("SIOCGARP"); 230 exit(1); 231 } 232 close(s); 233 ea = (u_char *)ar.arp_ha.sa_data; 234 printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr)); 235 if (ar.arp_flags & ATF_COM) 236 ether_print(ea); 237 else 238 printf("(incomplete)"); 239 if (ar.arp_flags & ATF_PERM) 240 printf(" permanent"); 241 if (ar.arp_flags & ATF_PUBL) 242 printf(" published"); 243 if (ar.arp_flags & ATF_USETRAILERS) 244 printf(" trailers"); 245 printf("\n"); 246 } 247 248 /* 249 * Delete an arp entry 250 */ 251 delete(host) 252 char *host; 253 { 254 struct arpreq ar; 255 struct hostent *hp; 256 struct sockaddr_in *sin; 257 int s; 258 259 bzero((caddr_t)&ar, sizeof ar); 260 ar.arp_pa.sa_family = AF_INET; 261 sin = (struct sockaddr_in *)&ar.arp_pa; 262 sin->sin_family = AF_INET; 263 sin->sin_addr.s_addr = inet_addr(host); 264 if (sin->sin_addr.s_addr == -1) { 265 if (!(hp = gethostbyname(host))) { 266 fprintf(stderr, "arp: %s: ", host); 267 herror((char *)NULL); 268 exit(1); 269 } 270 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 271 sizeof sin->sin_addr); 272 } 273 s = socket(AF_INET, SOCK_DGRAM, 0); 274 if (s < 0) { 275 perror("arp: socket"); 276 exit(1); 277 } 278 if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) { 279 if (errno == ENXIO) 280 printf("%s (%s) -- no entry\n", 281 host, inet_ntoa(sin->sin_addr)); 282 else 283 perror("SIOCDARP"); 284 exit(1); 285 } 286 close(s); 287 printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr)); 288 } 289 290 struct nlist nl[] = { 291 #define X_ARPTAB 0 292 { "_arptab" }, 293 #define X_ARPTAB_SIZE 1 294 { "_arptab_size" }, 295 #define N_SYSMAP 2 296 { "_Sysmap" }, 297 #define N_SYSSIZE 3 298 { "_Syssize" }, 299 { "" }, 300 }; 301 302 static struct pte *Sysmap; 303 304 /* 305 * Dump the entire arp table 306 */ 307 dump(kernel, mem) 308 char *kernel, *mem; 309 { 310 extern int h_errno; 311 struct arptab *at; 312 struct hostent *hp; 313 int bynumber, mf, arptab_size, sz; 314 char *host, *malloc(); 315 off_t lseek(); 316 317 if (nlist(kernel, nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) { 318 fprintf(stderr, "arp: %s: bad namelist\n", kernel); 319 exit(1); 320 } 321 mf = open(mem, O_RDONLY); 322 if (mf < 0) { 323 fprintf(stderr, "arp: cannot open %s\n", mem); 324 exit(1); 325 } 326 if (kflag) { 327 off_t off; 328 329 Sysmap = (struct pte *) 330 malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 331 if (!Sysmap) { 332 fputs("arp: can't get memory for Sysmap.\n", stderr); 333 exit(1); 334 } 335 off = nl[N_SYSMAP].n_value & ~KERNBASE; 336 (void)lseek(mf, off, L_SET); 337 (void)read(mf, (char *)Sysmap, 338 (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 339 } 340 klseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, L_SET); 341 read(mf, &arptab_size, sizeof arptab_size); 342 if (arptab_size <= 0 || arptab_size > 1000) { 343 fprintf(stderr, "arp: %s: namelist wrong\n", kernel); 344 exit(1); 345 } 346 sz = arptab_size * sizeof (struct arptab); 347 at = (struct arptab *)malloc((u_int)sz); 348 if (at == NULL) { 349 fputs("arp: can't get memory for arptab.\n", stderr); 350 exit(1); 351 } 352 klseek(mf, (long)nl[X_ARPTAB].n_value, L_SET); 353 if (read(mf, (char *)at, sz) != sz) { 354 perror("arp: error reading arptab"); 355 exit(1); 356 } 357 close(mf); 358 for (bynumber = 0; arptab_size-- > 0; at++) { 359 if (at->at_iaddr.s_addr == 0 || at->at_flags == 0) 360 continue; 361 if (bynumber == 0) 362 hp = gethostbyaddr((caddr_t)&at->at_iaddr, 363 sizeof at->at_iaddr, AF_INET); 364 else 365 hp = 0; 366 if (hp) 367 host = hp->h_name; 368 else { 369 host = "?"; 370 if (h_errno == TRY_AGAIN) 371 bynumber = 1; 372 } 373 printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr)); 374 if (at->at_flags & ATF_COM) 375 ether_print(at->at_enaddr); 376 else 377 printf("(incomplete)"); 378 if (at->at_flags & ATF_PERM) 379 printf(" permanent"); 380 if (at->at_flags & ATF_PUBL) 381 printf(" published"); 382 if (at->at_flags & ATF_USETRAILERS) 383 printf(" trailers"); 384 printf("\n"); 385 } 386 } 387 388 /* 389 * Seek into the kernel for a value. 390 */ 391 klseek(fd, base, off) 392 int fd, off; 393 off_t base; 394 { 395 off_t lseek(); 396 397 if (kflag) { /* get kernel pte */ 398 base &= ~KERNBASE; 399 base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET); 400 } 401 (void)lseek(fd, base, off); 402 } 403 404 ether_print(cp) 405 u_char *cp; 406 { 407 printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 408 } 409 410 ether_aton(a, n) 411 char *a; 412 u_char *n; 413 { 414 int i, o[6]; 415 416 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 417 &o[3], &o[4], &o[5]); 418 if (i != 6) { 419 fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a); 420 return (1); 421 } 422 for (i=0; i<6; i++) 423 n[i] = o[i]; 424 return (0); 425 } 426 427 usage() 428 { 429 printf("usage: arp hostname\n"); 430 printf(" arp -a [kernel] [kernel_memory]\n"); 431 printf(" arp -d hostname\n"); 432 printf(" arp -s hostname ether_addr [temp] [pub] [trail]\n"); 433 printf(" arp -f filename\n"); 434 exit(1); 435 } 436