134918Sbostic /* 234918Sbostic * Copyright (c) 1984 Regents of the University of California. 334918Sbostic * All rights reserved. 434918Sbostic * 534918Sbostic * This code is derived from software contributed to Berkeley by 634918Sbostic * Sun Microsystems, Inc. 734918Sbostic * 834918Sbostic * Redistribution and use in source and binary forms are permitted 934918Sbostic * provided that the above copyright notice and this paragraph are 1034918Sbostic * duplicated in all such forms and that any documentation, 1134918Sbostic * advertising materials, and other materials related to such 1234918Sbostic * distribution and use acknowledge that the software was developed 1334918Sbostic * by the University of California, Berkeley. The name of the 1434918Sbostic * University may not be used to endorse or promote products derived 1534918Sbostic * from this software without specific prior written permission. 1634918Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1734918Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1834918Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1934918Sbostic */ 2034918Sbostic 2116255Skarels #ifndef lint 2234918Sbostic char copyright[] = 2334918Sbostic "@(#) Copyright (c) 1984 Regents of the University of California.\n\ 2434918Sbostic All rights reserved.\n"; 2534918Sbostic #endif /* not lint */ 2616255Skarels 2734918Sbostic #ifndef lint 28*37961Sbostic static char sccsid[] = "@(#)arp.c 5.10 (Berkeley) 05/11/89"; 2934918Sbostic #endif /* not lint */ 3034918Sbostic 3116255Skarels /* 3216255Skarels * arp - display, set, and delete arp table entries 3316255Skarels */ 3416255Skarels 3533624Sbostic #include <machine/pte.h> 3633624Sbostic 3733624Sbostic #include <sys/param.h> 3833624Sbostic #include <sys/vmmac.h> 3933624Sbostic #include <sys/file.h> 4016255Skarels #include <sys/socket.h> 4116255Skarels #include <sys/ioctl.h> 4233624Sbostic 4316255Skarels #include <netdb.h> 4433624Sbostic #include <netinet/in.h> 4516255Skarels #include <net/if.h> 4616255Skarels #include <netinet/if_ether.h> 4716255Skarels 4833624Sbostic #include <errno.h> 4933624Sbostic #include <nlist.h> 5033624Sbostic #include <stdio.h> 51*37961Sbostic #include <paths.h> 5233624Sbostic 5316255Skarels extern int errno; 5433624Sbostic static int kflag; 5516255Skarels 5616255Skarels main(argc, argv) 5733624Sbostic int argc; 5816255Skarels char **argv; 5916255Skarels { 6033624Sbostic int ch; 6116255Skarels 6233624Sbostic while ((ch = getopt(argc, argv, "adsf")) != EOF) 6333624Sbostic switch((char)ch) { 6433624Sbostic case 'a': { 6533624Sbostic char *mem; 6633624Sbostic 6733624Sbostic if (argc > 4) 6833624Sbostic usage(); 6933624Sbostic if (argc == 4) { 7033624Sbostic kflag = 1; 7133624Sbostic mem = argv[3]; 7233624Sbostic } 7333624Sbostic else 7437255Sbostic mem = _PATH_KMEM; 75*37961Sbostic dump((argc >= 3) ? argv[2] : _PATH_UNIX, mem); 7633624Sbostic exit(0); 7733624Sbostic } 7833624Sbostic case 'd': 7933624Sbostic if (argc != 3) 8033624Sbostic usage(); 8133624Sbostic delete(argv[2]); 8233624Sbostic exit(0); 8333624Sbostic case 's': 8433624Sbostic if (argc < 4 || argc > 7) 8533624Sbostic usage(); 8633624Sbostic exit(set(argc-2, &argv[2]) ? 1 : 0); 8733624Sbostic case 'f': 8833624Sbostic if (argc != 3) 8933624Sbostic usage(); 9033624Sbostic exit (file(argv[2]) ? 1 : 0); 9133624Sbostic case '?': 9233624Sbostic default: 9333624Sbostic usage(); 9433624Sbostic } 9533624Sbostic if (argc != 2) 9633624Sbostic usage(); 9733624Sbostic get(argv[1]); 9833624Sbostic exit(0); 9916255Skarels } 10016255Skarels 10116255Skarels /* 10216255Skarels * Process a file to set standard arp entries 10316255Skarels */ 10416255Skarels file(name) 10516255Skarels char *name; 10616255Skarels { 10716255Skarels FILE *fp; 10833624Sbostic int i, retval; 10925788Skarels char line[100], arg[5][50], *args[5]; 11016255Skarels 11116255Skarels if ((fp = fopen(name, "r")) == NULL) { 11216255Skarels fprintf(stderr, "arp: cannot open %s\n", name); 11316255Skarels exit(1); 11416255Skarels } 11516255Skarels args[0] = &arg[0][0]; 11616255Skarels args[1] = &arg[1][0]; 11716255Skarels args[2] = &arg[2][0]; 11816255Skarels args[3] = &arg[3][0]; 11925788Skarels args[4] = &arg[4][0]; 12032643Smckusick retval = 0; 12116255Skarels while(fgets(line, 100, fp) != NULL) { 12232643Smckusick i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], 12332643Smckusick arg[3], arg[4]); 12416255Skarels if (i < 2) { 12516255Skarels fprintf(stderr, "arp: bad line: %s\n", line); 12632643Smckusick retval = 1; 12716255Skarels continue; 12816255Skarels } 12932643Smckusick if (set(i, args)) 13032643Smckusick retval = 1; 13116255Skarels } 13216255Skarels fclose(fp); 13332643Smckusick return (retval); 13416255Skarels } 13516255Skarels 13616255Skarels /* 13716255Skarels * Set an individual arp entry 13816255Skarels */ 13916255Skarels set(argc, argv) 14033624Sbostic int argc; 14116255Skarels char **argv; 14216255Skarels { 14316255Skarels struct arpreq ar; 14416255Skarels struct hostent *hp; 14516255Skarels struct sockaddr_in *sin; 14621393Skarels u_char *ea; 14716255Skarels int s; 14816255Skarels char *host = argv[0], *eaddr = argv[1]; 14916255Skarels 15016255Skarels argc -= 2; 15116255Skarels argv += 2; 15216255Skarels bzero((caddr_t)&ar, sizeof ar); 15316255Skarels sin = (struct sockaddr_in *)&ar.arp_pa; 15426314Skarels sin->sin_family = AF_INET; 15526314Skarels sin->sin_addr.s_addr = inet_addr(host); 15626314Skarels if (sin->sin_addr.s_addr == -1) { 15735778Sbostic if (!(hp = gethostbyname(host))) { 15835778Sbostic fprintf(stderr, "arp: %s: ", host); 15935778Sbostic herror((char *)NULL); 16032643Smckusick return (1); 16126314Skarels } 16226314Skarels bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 16326314Skarels sizeof sin->sin_addr); 16426314Skarels } 16521393Skarels ea = (u_char *)ar.arp_ha.sa_data; 16616255Skarels if (ether_aton(eaddr, ea)) 16732643Smckusick return (1); 16816255Skarels ar.arp_flags = ATF_PERM; 16926314Skarels while (argc-- > 0) { 17016255Skarels if (strncmp(argv[0], "temp", 4) == 0) 17116255Skarels ar.arp_flags &= ~ATF_PERM; 17233624Sbostic else if (strncmp(argv[0], "pub", 3) == 0) 17316255Skarels ar.arp_flags |= ATF_PUBL; 17433624Sbostic else if (strncmp(argv[0], "trail", 5) == 0) 17525788Skarels ar.arp_flags |= ATF_USETRAILERS; 17616255Skarels argv++; 17716255Skarels } 17816255Skarels 17916255Skarels s = socket(AF_INET, SOCK_DGRAM, 0); 18016255Skarels if (s < 0) { 18133624Sbostic perror("arp: socket"); 18233624Sbostic exit(1); 18333624Sbostic } 18416255Skarels if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) { 18516255Skarels perror(host); 18616255Skarels exit(1); 18716255Skarels } 18816255Skarels close(s); 18932643Smckusick return (0); 19016255Skarels } 19116255Skarels 19216255Skarels /* 19316255Skarels * Display an individual arp entry 19416255Skarels */ 19516255Skarels get(host) 19616255Skarels char *host; 19716255Skarels { 19816255Skarels struct arpreq ar; 19916255Skarels struct hostent *hp; 20016255Skarels struct sockaddr_in *sin; 20121393Skarels u_char *ea; 20216255Skarels int s; 20333624Sbostic char *inet_ntoa(); 20416255Skarels 20516255Skarels bzero((caddr_t)&ar, sizeof ar); 20616255Skarels ar.arp_pa.sa_family = AF_INET; 20716255Skarels sin = (struct sockaddr_in *)&ar.arp_pa; 20826314Skarels sin->sin_family = AF_INET; 20926314Skarels sin->sin_addr.s_addr = inet_addr(host); 21026314Skarels if (sin->sin_addr.s_addr == -1) { 21135778Sbostic if (!(hp = gethostbyname(host))) { 21235778Sbostic fprintf(stderr, "arp: %s: ", host); 21335778Sbostic herror((char *)NULL); 21426314Skarels exit(1); 21526314Skarels } 21626314Skarels bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 21726314Skarels sizeof sin->sin_addr); 21826314Skarels } 21916255Skarels s = socket(AF_INET, SOCK_DGRAM, 0); 22016255Skarels if (s < 0) { 22133624Sbostic perror("arp: socket"); 22233624Sbostic exit(1); 22333624Sbostic } 22416255Skarels if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) { 22516255Skarels if (errno == ENXIO) 22616255Skarels printf("%s (%s) -- no entry\n", 22716255Skarels host, inet_ntoa(sin->sin_addr)); 22816255Skarels else 22916255Skarels perror("SIOCGARP"); 23016255Skarels exit(1); 23116255Skarels } 23216255Skarels close(s); 23321393Skarels ea = (u_char *)ar.arp_ha.sa_data; 23416255Skarels printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr)); 23516255Skarels if (ar.arp_flags & ATF_COM) 23616255Skarels ether_print(ea); 23716255Skarels else 23816255Skarels printf("(incomplete)"); 23933624Sbostic if (ar.arp_flags & ATF_PERM) 24033624Sbostic printf(" permanent"); 24133624Sbostic if (ar.arp_flags & ATF_PUBL) 24233624Sbostic printf(" published"); 24333624Sbostic if (ar.arp_flags & ATF_USETRAILERS) 24433624Sbostic printf(" trailers"); 24516255Skarels printf("\n"); 24616255Skarels } 24716255Skarels 24816255Skarels /* 24916255Skarels * Delete an arp entry 25016255Skarels */ 25116255Skarels delete(host) 25216255Skarels char *host; 25316255Skarels { 25416255Skarels struct arpreq ar; 25516255Skarels struct hostent *hp; 25616255Skarels struct sockaddr_in *sin; 25716255Skarels int s; 25816255Skarels 25916255Skarels bzero((caddr_t)&ar, sizeof ar); 26016255Skarels ar.arp_pa.sa_family = AF_INET; 26116255Skarels sin = (struct sockaddr_in *)&ar.arp_pa; 26226314Skarels sin->sin_family = AF_INET; 26326314Skarels sin->sin_addr.s_addr = inet_addr(host); 26426314Skarels if (sin->sin_addr.s_addr == -1) { 26535778Sbostic if (!(hp = gethostbyname(host))) { 26635778Sbostic fprintf(stderr, "arp: %s: ", host); 26735778Sbostic herror((char *)NULL); 26826314Skarels exit(1); 26926314Skarels } 27026314Skarels bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 27126314Skarels sizeof sin->sin_addr); 27226314Skarels } 27316255Skarels s = socket(AF_INET, SOCK_DGRAM, 0); 27416255Skarels if (s < 0) { 27533624Sbostic perror("arp: socket"); 27633624Sbostic exit(1); 27733624Sbostic } 27816255Skarels if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) { 27916255Skarels if (errno == ENXIO) 28016255Skarels printf("%s (%s) -- no entry\n", 28116255Skarels host, inet_ntoa(sin->sin_addr)); 28216255Skarels else 28316255Skarels perror("SIOCDARP"); 28416255Skarels exit(1); 28516255Skarels } 28616255Skarels close(s); 28716255Skarels printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr)); 28816255Skarels } 28916255Skarels 29016255Skarels struct nlist nl[] = { 29116255Skarels #define X_ARPTAB 0 29216255Skarels { "_arptab" }, 29316255Skarels #define X_ARPTAB_SIZE 1 29416255Skarels { "_arptab_size" }, 29533624Sbostic #define N_SYSMAP 2 29633624Sbostic { "_Sysmap" }, 29733624Sbostic #define N_SYSSIZE 3 29833624Sbostic { "_Syssize" }, 29916255Skarels { "" }, 30016255Skarels }; 30116255Skarels 30233624Sbostic static struct pte *Sysmap; 30333624Sbostic 30416255Skarels /* 30516255Skarels * Dump the entire arp table 30616255Skarels */ 30716255Skarels dump(kernel, mem) 30816255Skarels char *kernel, *mem; 30916255Skarels { 31033624Sbostic extern int h_errno; 31116255Skarels struct arptab *at; 31216255Skarels struct hostent *hp; 31333624Sbostic int bynumber, mf, arptab_size, sz; 31433624Sbostic char *host, *malloc(); 31533624Sbostic off_t lseek(); 31616255Skarels 31733624Sbostic if (nlist(kernel, nl) < 0 || nl[X_ARPTAB_SIZE].n_type == 0) { 31816255Skarels fprintf(stderr, "arp: %s: bad namelist\n", kernel); 31916255Skarels exit(1); 32016255Skarels } 32133624Sbostic mf = open(mem, O_RDONLY); 32233624Sbostic if (mf < 0) { 32335377Sbostic fprintf(stderr, "arp: cannot open %s\n", mem); 32416255Skarels exit(1); 32516255Skarels } 32633624Sbostic if (kflag) { 32733624Sbostic off_t off; 32833624Sbostic 32933624Sbostic Sysmap = (struct pte *) 33033624Sbostic malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 33133624Sbostic if (!Sysmap) { 33233624Sbostic fputs("arp: can't get memory for Sysmap.\n", stderr); 33333624Sbostic exit(1); 33433624Sbostic } 33533624Sbostic off = nl[N_SYSMAP].n_value & ~KERNBASE; 33633624Sbostic (void)lseek(mf, off, L_SET); 33733624Sbostic (void)read(mf, (char *)Sysmap, 33833624Sbostic (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 33933624Sbostic } 34033624Sbostic klseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, L_SET); 34116255Skarels read(mf, &arptab_size, sizeof arptab_size); 34233624Sbostic if (arptab_size <= 0 || arptab_size > 1000) { 34316255Skarels fprintf(stderr, "arp: %s: namelist wrong\n", kernel); 34416255Skarels exit(1); 34516255Skarels } 34616255Skarels sz = arptab_size * sizeof (struct arptab); 34733624Sbostic at = (struct arptab *)malloc((u_int)sz); 34816255Skarels if (at == NULL) { 34933624Sbostic fputs("arp: can't get memory for arptab.\n", stderr); 35016255Skarels exit(1); 35116255Skarels } 35233624Sbostic klseek(mf, (long)nl[X_ARPTAB].n_value, L_SET); 35316255Skarels if (read(mf, (char *)at, sz) != sz) { 35416255Skarels perror("arp: error reading arptab"); 35516255Skarels exit(1); 35616255Skarels } 35716255Skarels close(mf); 35833624Sbostic for (bynumber = 0; arptab_size-- > 0; at++) { 35916255Skarels if (at->at_iaddr.s_addr == 0 || at->at_flags == 0) 36016255Skarels continue; 36126314Skarels if (bynumber == 0) 36226314Skarels hp = gethostbyaddr((caddr_t)&at->at_iaddr, 36326314Skarels sizeof at->at_iaddr, AF_INET); 36426314Skarels else 36526314Skarels hp = 0; 36616255Skarels if (hp) 36716255Skarels host = hp->h_name; 36826314Skarels else { 36916255Skarels host = "?"; 37026314Skarels if (h_errno == TRY_AGAIN) 37126314Skarels bynumber = 1; 37226314Skarels } 37316255Skarels printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr)); 37416255Skarels if (at->at_flags & ATF_COM) 37521393Skarels ether_print(at->at_enaddr); 37616255Skarels else 37716255Skarels printf("(incomplete)"); 37833624Sbostic if (at->at_flags & ATF_PERM) 37933624Sbostic printf(" permanent"); 38033624Sbostic if (at->at_flags & ATF_PUBL) 38133624Sbostic printf(" published"); 38233624Sbostic if (at->at_flags & ATF_USETRAILERS) 38333624Sbostic printf(" trailers"); 38416255Skarels printf("\n"); 38516255Skarels } 38616255Skarels } 38716255Skarels 38833624Sbostic /* 38933624Sbostic * Seek into the kernel for a value. 39033624Sbostic */ 39133624Sbostic klseek(fd, base, off) 39233624Sbostic int fd, off; 39333624Sbostic off_t base; 39433624Sbostic { 39533624Sbostic off_t lseek(); 39633624Sbostic 39733624Sbostic if (kflag) { /* get kernel pte */ 39833624Sbostic base &= ~KERNBASE; 39933624Sbostic base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET); 40033624Sbostic } 40133624Sbostic (void)lseek(fd, base, off); 40233624Sbostic } 40333624Sbostic 40421393Skarels ether_print(cp) 40521393Skarels u_char *cp; 40616255Skarels { 40716255Skarels printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 40816255Skarels } 40916255Skarels 41016255Skarels ether_aton(a, n) 41116255Skarels char *a; 41221393Skarels u_char *n; 41316255Skarels { 41416255Skarels int i, o[6]; 41516255Skarels 41616255Skarels i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 41716255Skarels &o[3], &o[4], &o[5]); 41816255Skarels if (i != 6) { 41916255Skarels fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a); 42016255Skarels return (1); 42116255Skarels } 42216255Skarels for (i=0; i<6; i++) 42321393Skarels n[i] = o[i]; 42416255Skarels return (0); 42516255Skarels } 42616255Skarels 42716255Skarels usage() 42816255Skarels { 42933624Sbostic printf("usage: arp hostname\n"); 430*37961Sbostic printf(" arp -a [kernel] [kernel_memory]\n"); 43116255Skarels printf(" arp -d hostname\n"); 43232643Smckusick printf(" arp -s hostname ether_addr [temp] [pub] [trail]\n"); 43316255Skarels printf(" arp -f filename\n"); 43433624Sbostic exit(1); 43516255Skarels } 436