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