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