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