arp.c revision 93952
160484Sobrien/* 2130561Sobrien * Copyright (c) 1984, 1993 378828Sobrien * The Regents of the University of California. All rights reserved. 460484Sobrien * 560484Sobrien * This code is derived from software contributed to Berkeley by 660484Sobrien * Sun Microsystems, Inc. 7130561Sobrien * 860484Sobrien * Redistribution and use in source and binary forms, with or without 9130561Sobrien * modification, are permitted provided that the following conditions 10130561Sobrien * are met: 11130561Sobrien * 1. Redistributions of source code must retain the above copyright 12130561Sobrien * notice, this list of conditions and the following disclaimer. 1360484Sobrien * 2. Redistributions in binary form must reproduce the above copyright 14130561Sobrien * notice, this list of conditions and the following disclaimer in the 15130561Sobrien * documentation and/or other materials provided with the distribution. 16130561Sobrien * 3. All advertising materials mentioning features or use of this software 17130561Sobrien * must display the following acknowledgement: 1860484Sobrien * This product includes software developed by the University of 19130561Sobrien * California, Berkeley and its contributors. 20130561Sobrien * 4. Neither the name of the University nor the names of its contributors 21130561Sobrien * may be used to endorse or promote products derived from this software 2260484Sobrien * without specific prior written permission. 2360484Sobrien * 2460484Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2560484Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2660484Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2760484Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2860484Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2960484Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30130561Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3160484Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32104834Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3360484Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3460484Sobrien * SUCH DAMAGE. 3560484Sobrien */ 3660484Sobrien 3760484Sobrien#ifndef lint 3860484Sobrienstatic char const copyright[] = 3960484Sobrien"@(#) Copyright (c) 1984, 1993\n\ 4060484Sobrien The Regents of the University of California. All rights reserved.\n"; 4160484Sobrien#endif /* not lint */ 4260484Sobrien 4360484Sobrien#ifndef lint 4460484Sobrien#if 0 4560484Sobrienstatic char const sccsid[] = "@(#)from: arp.c 8.2 (Berkeley) 1/2/94"; 4660484Sobrien#endif 4760484Sobrienstatic const char rcsid[] = 4860484Sobrien "$FreeBSD: head/usr.sbin/arp/arp.c 93952 2002-04-06 09:01:44Z ru $"; 4960484Sobrien#endif /* not lint */ 5060484Sobrien 5160484Sobrien/* 5260484Sobrien * arp - display, set, and delete arp table entries 5360484Sobrien */ 5460484Sobrien 5560484Sobrien 5660484Sobrien#include <sys/param.h> 5760484Sobrien#include <sys/file.h> 5860484Sobrien#include <sys/socket.h> 5960484Sobrien#include <sys/sockio.h> 6060484Sobrien#include <sys/sysctl.h> 6160484Sobrien#include <sys/ioctl.h> 6260484Sobrien#include <sys/time.h> 6360484Sobrien 6460484Sobrien#include <net/if.h> 6577298Sobrien#include <net/if_dl.h> 6677298Sobrien#include <net/if_types.h> 6760484Sobrien#include <net/route.h> 6860484Sobrien 6960484Sobrien#include <netinet/in.h> 7060484Sobrien#include <netinet/if_ether.h> 7160484Sobrien 7260484Sobrien#include <arpa/inet.h> 7360484Sobrien 74130561Sobrien#include <err.h> 75130561Sobrien#include <errno.h> 76130561Sobrien#include <netdb.h> 77130561Sobrien#include <nlist.h> 78130561Sobrien#include <paths.h> 7960484Sobrien#include <stdio.h> 8060484Sobrien#include <stdlib.h> 81130561Sobrien#include <string.h> 82130561Sobrien#include <strings.h> 83130561Sobrien#include <unistd.h> 84130561Sobrien 85130561Sobrienvoid search(u_long addr, void (*action)(struct sockaddr_dl *sdl, 86130561Sobrien struct sockaddr_inarp *sin, struct rt_msghdr *rtm)); 87130561Sobrienvoid print_entry(struct sockaddr_dl *sdl, 88130561Sobrien struct sockaddr_inarp *addr, struct rt_msghdr *rtm); 89130561Sobrienvoid nuke_entry(struct sockaddr_dl *sdl, 90130561Sobrien struct sockaddr_inarp *addr, struct rt_msghdr *rtm); 9177298Sobrienint delete(char *host, char *info); 9260484Sobrienvoid usage(void); 9360484Sobrienint set(int argc, char **argv); 9460484Sobrienint get(char *host); 9560484Sobrienint file(char *name); 9660484Sobrienvoid getsocket(void); 97130561Sobrienint my_ether_aton(char *a, struct ether_addr *n); 9860484Sobrienint rtmsg(int cmd); 9960484Sobrienint get_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr); 10060484Sobrien 10160484Sobrienstatic int pid; 102130561Sobrienstatic int nflag; /* no reverse dns lookups */ 10360484Sobrienstatic int aflag; /* do it for all entries */ 10460484Sobrienstatic int s = -1; 10560484Sobrien 106130561Sobrienstruct sockaddr_in so_mask; 107130561Sobrienstruct sockaddr_inarp blank_sin, sin_m; 108130561Sobrienstruct sockaddr_dl blank_sdl, sdl_m; 109130561Sobrienint expire_time, flags, doing_proxy, proxy_only, found_entry; 110130561Sobrienstruct { 111130561Sobrien struct rt_msghdr m_rtm; 112130561Sobrien char m_space[512]; 113130561Sobrien} m_rtmsg; 114130561Sobrien 115130561Sobrien/* which function we're supposed to do */ 116130561Sobrien#define F_GET 1 117130561Sobrien#define F_SET 2 118130561Sobrien#define F_FILESET 3 119130561Sobrien#define F_REPLACE 4 120130561Sobrien#define F_DELETE 5 121130561Sobrien 122130561Sobrien#define ROUNDUP(a) \ 123130561Sobrien ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 124130561Sobrien#define SETFUNC(f) { if (func) usage(); func = (f); } 12560484Sobrien 126104834Sobrienint 12760484Sobrienmain(int argc, char *argv[]) 128104834Sobrien{ 12960484Sobrien int ch, func = 0; 13060484Sobrien int rtn = 0; 13160484Sobrien 13260484Sobrien pid = getpid(); 13360484Sobrien while ((ch = getopt(argc, argv, "andfsS")) != -1) 134104834Sobrien switch((char)ch) { 135104834Sobrien case 'a': 13660484Sobrien aflag = 1; 13760484Sobrien break; 13860484Sobrien case 'd': 13960484Sobrien SETFUNC(F_DELETE); 14060484Sobrien break; 14160484Sobrien case 'n': 14260484Sobrien nflag = 1; 143104834Sobrien break; 144104834Sobrien case 'S': 145104834Sobrien SETFUNC(F_REPLACE); 146104834Sobrien break; 147104834Sobrien case 's': 14860484Sobrien SETFUNC(F_SET); 14960484Sobrien break; 15060484Sobrien case 'f' : 15160484Sobrien SETFUNC(F_FILESET); 15260484Sobrien break; 15360484Sobrien case '?': 15460484Sobrien default: 15560484Sobrien usage(); 15660484Sobrien } 15760484Sobrien argc -= optind; 15860484Sobrien argv += optind; 15960484Sobrien 16060484Sobrien bzero(&so_mask, sizeof(so_mask)); 16160484Sobrien so_mask.sin_len = 8; 162130561Sobrien so_mask.sin_addr.s_addr = 0xffffffff; 16360484Sobrien bzero(&blank_sin, sizeof(blank_sin)); 16460484Sobrien blank_sin.sin_len = sizeof(blank_sin); 16560484Sobrien blank_sin.sin_family = AF_INET; 16660484Sobrien bzero(&blank_sdl, sizeof(blank_sdl)); 16760484Sobrien blank_sdl.sdl_len = sizeof(blank_sdl); 16860484Sobrien blank_sdl.sdl_family = AF_LINK; 169130561Sobrien 17060484Sobrien if (!func) 17160484Sobrien func = F_GET; 17260484Sobrien switch (func) { 17360484Sobrien case F_GET: 17460484Sobrien if (aflag) { 17560484Sobrien if (argc != 0) 17660484Sobrien usage(); 177130561Sobrien search(0, print_entry); 17860484Sobrien } else { 17960484Sobrien if (argc != 1) 180130561Sobrien usage(); 18160484Sobrien get(argv[0]); 18260484Sobrien } 18360484Sobrien break; 18460484Sobrien case F_SET: 18560484Sobrien case F_REPLACE: 18660484Sobrien if (argc < 2 || argc > 6) 18760484Sobrien usage(); 18860484Sobrien if (func == F_REPLACE) 189130561Sobrien (void) delete(argv[0], NULL); 190130561Sobrien rtn = set(argc, argv) ? 1 : 0; 191130561Sobrien break; 192130561Sobrien case F_DELETE: 193130561Sobrien if (aflag) { 194130561Sobrien if (argc != 0) 195130561Sobrien usage(); 196130561Sobrien search(0, nuke_entry); 197130561Sobrien } else { 198130561Sobrien if (argc < 1 || argc > 2) 199130561Sobrien usage(); 200130561Sobrien rtn = delete(argv[0], argv[1]); 201130561Sobrien } 202130561Sobrien break; 203130561Sobrien case F_FILESET: 204130561Sobrien if (argc != 1) 205130561Sobrien usage(); 206130561Sobrien rtn = file(argv[0]); 20760484Sobrien break; 20860484Sobrien } 209104834Sobrien 21060484Sobrien return(rtn); 21160484Sobrien} 212130561Sobrien 213130561Sobrien/* 214130561Sobrien * Process a file to set standard arp entries 21560484Sobrien */ 216130561Sobrienint 217130561Sobrienfile(char *name) 218130561Sobrien{ 219130561Sobrien FILE *fp; 22060484Sobrien int i, retval; 22160484Sobrien char line[100], arg[5][50], *args[5]; 22260484Sobrien 223130561Sobrien if ((fp = fopen(name, "r")) == NULL) 224130561Sobrien errx(1, "cannot open %s", name); 225130561Sobrien args[0] = &arg[0][0]; 226130561Sobrien args[1] = &arg[1][0]; 227130561Sobrien args[2] = &arg[2][0]; 22860484Sobrien args[3] = &arg[3][0]; 22960484Sobrien args[4] = &arg[4][0]; 23060484Sobrien retval = 0; 231130561Sobrien while(fgets(line, 100, fp) != NULL) { 23260484Sobrien i = sscanf(line, "%49s %49s %49s %49s %49s", arg[0], arg[1], 23360484Sobrien arg[2], arg[3], arg[4]); 23460484Sobrien if (i < 2) { 23560484Sobrien warnx("bad line: %s", line); 23660484Sobrien retval = 1; 23760484Sobrien continue; 23860484Sobrien } 23960484Sobrien if (set(i, args)) 24060484Sobrien retval = 1; 24160484Sobrien } 24260484Sobrien fclose(fp); 24360484Sobrien return (retval); 24460484Sobrien} 24560484Sobrien 24660484Sobrienvoid 247130561Sobriengetsocket(void) 24860484Sobrien{ 249130561Sobrien if (s < 0) { 25060484Sobrien s = socket(PF_ROUTE, SOCK_RAW, 0); 25160484Sobrien if (s < 0) 25260484Sobrien err(1, "socket"); 25360484Sobrien } 254130561Sobrien} 255104834Sobrien 25680016Sobrien/* 25760484Sobrien * Set an individual arp entry 25860484Sobrien */ 25960484Sobrienint 26060484Sobrienset(int argc, char **argv) 26160484Sobrien{ 26260484Sobrien struct hostent *hp; 26360484Sobrien register struct sockaddr_inarp *addr = &sin_m; 26460484Sobrien register struct sockaddr_dl *sdl; 26560484Sobrien register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 26660484Sobrien struct ether_addr *ea; 26760484Sobrien char *host = argv[0], *eaddr = argv[1]; 26860484Sobrien 26960484Sobrien getsocket(); 27080016Sobrien argc -= 2; 27160484Sobrien argv += 2; 272104834Sobrien sdl_m = blank_sdl; 273104834Sobrien sin_m = blank_sin; 27460484Sobrien addr->sin_addr.s_addr = inet_addr(host); 275130561Sobrien if (addr->sin_addr.s_addr == INADDR_NONE) { 27660484Sobrien if (!(hp = gethostbyname(host))) { 27760484Sobrien warnx("%s: %s", host, hstrerror(h_errno)); 27860484Sobrien return (1); 27960484Sobrien } 28060484Sobrien bcopy((char *)hp->h_addr, (char *)&addr->sin_addr, 281130561Sobrien sizeof addr->sin_addr); 28260484Sobrien } 28360484Sobrien doing_proxy = flags = proxy_only = expire_time = 0; 28460484Sobrien while (argc-- > 0) { 28560484Sobrien if (strncmp(argv[0], "temp", 4) == 0) { 28660484Sobrien struct timeval tv; 28760484Sobrien gettimeofday(&tv, 0); 28860484Sobrien expire_time = tv.tv_sec + 20 * 60; 289130561Sobrien } 29060484Sobrien else if (strncmp(argv[0], "pub", 3) == 0) { 29160484Sobrien flags |= RTF_ANNOUNCE; 29260484Sobrien doing_proxy = 1; 29360484Sobrien if (argc && strncmp(argv[1], "only", 3) == 0) { 29460484Sobrien proxy_only = 1; 29560484Sobrien sin_m.sin_other = SIN_PROXY; 29660484Sobrien argc--; argv++; 29760484Sobrien } 29860484Sobrien } else if (strncmp(argv[0], "trail", 5) == 0) { 29960484Sobrien printf("%s: Sending trailers is no longer supported\n", 30060484Sobrien host); 301130561Sobrien } 30260484Sobrien argv++; 30360484Sobrien } 30460484Sobrien ea = (struct ether_addr *)LLADDR(&sdl_m); 30560484Sobrien if (doing_proxy && !strcmp(eaddr, "auto")) { 30660484Sobrien if (!get_ether_addr(addr->sin_addr.s_addr, ea)) { 30760484Sobrien printf("no interface found for %s\n", 30860484Sobrien inet_ntoa(addr->sin_addr)); 30960484Sobrien return (1); 310130561Sobrien } 31160484Sobrien sdl_m.sdl_alen = ETHER_ADDR_LEN; 31260484Sobrien } else { 313130561Sobrien if (my_ether_aton(eaddr, ea) == 0) 31460484Sobrien sdl_m.sdl_alen = ETHER_ADDR_LEN; 31560484Sobrien } 31660484Sobrientryagain: 31760484Sobrien if (rtmsg(RTM_GET) < 0) { 31860484Sobrien warn("%s", host); 319130561Sobrien return (1); 32060484Sobrien } 32160484Sobrien addr = (struct sockaddr_inarp *)(rtm + 1); 32260484Sobrien sdl = (struct sockaddr_dl *)(ROUNDUP(addr->sin_len) + (char *)addr); 32360484Sobrien if (addr->sin_addr.s_addr == sin_m.sin_addr.s_addr) { 32460484Sobrien if (sdl->sdl_family == AF_LINK && 32560484Sobrien (rtm->rtm_flags & RTF_LLINFO) && 32660484Sobrien !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { 32760484Sobrien case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 32860484Sobrien case IFT_ISO88024: case IFT_ISO88025: case IFT_L2VLAN: 32960484Sobrien goto overwrite; 33060484Sobrien } 33160484Sobrien if (doing_proxy == 0) { 332130561Sobrien printf("set: can only proxy for %s\n", host); 33360484Sobrien return (1); 33460484Sobrien } 335130561Sobrien if (sin_m.sin_other & SIN_PROXY) { 33680016Sobrien printf("set: proxy entry exists for non 802 device\n"); 337130561Sobrien return(1); 33860484Sobrien } 33960484Sobrien sin_m.sin_other = SIN_PROXY; 34060484Sobrien proxy_only = 1; 34160484Sobrien goto tryagain; 34260484Sobrien } 343130561Sobrienoverwrite: 34460484Sobrien if (sdl->sdl_family != AF_LINK) { 34560484Sobrien printf("cannot intuit interface index and type for %s\n", host); 34660484Sobrien return (1); 34760484Sobrien } 34860484Sobrien sdl_m.sdl_type = sdl->sdl_type; 34960484Sobrien sdl_m.sdl_index = sdl->sdl_index; 35060484Sobrien return (rtmsg(RTM_ADD)); 35160484Sobrien} 35260484Sobrien 353130561Sobrien/* 35460484Sobrien * Display an individual arp entry 35560484Sobrien */ 35660484Sobrienint 35760484Sobrienget(char *host) 35860484Sobrien{ 35960484Sobrien struct hostent *hp; 36060484Sobrien struct sockaddr_inarp *addr = &sin_m; 36160484Sobrien 36260484Sobrien sin_m = blank_sin; 36360484Sobrien addr->sin_addr.s_addr = inet_addr(host); 36460484Sobrien if (addr->sin_addr.s_addr == INADDR_NONE) { 36560484Sobrien if (!(hp = gethostbyname(host))) 366130561Sobrien errx(1, "%s: %s", host, hstrerror(h_errno)); 36760484Sobrien bcopy((char *)hp->h_addr, (char *)&addr->sin_addr, 36860484Sobrien sizeof addr->sin_addr); 36960484Sobrien } 37060484Sobrien search(addr->sin_addr.s_addr, print_entry); 37160484Sobrien if (found_entry == 0) { 37260484Sobrien printf("%s (%s) -- no entry\n", 37360484Sobrien host, inet_ntoa(addr->sin_addr)); 37460484Sobrien return(1); 37560484Sobrien } 37660484Sobrien return(0); 377130561Sobrien} 37860484Sobrien 37960484Sobrien/* 380130561Sobrien * Delete an arp entry 38160484Sobrien */ 38260484Sobrienint 38360484Sobriendelete(char *host, char *info) 38460484Sobrien{ 38560484Sobrien struct hostent *hp; 38660484Sobrien register struct sockaddr_inarp *addr = &sin_m; 38760484Sobrien register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 38860484Sobrien struct sockaddr_dl *sdl; 38960484Sobrien 39060484Sobrien getsocket(); 39160484Sobrien sin_m = blank_sin; 39260484Sobrien if (info) { 39360484Sobrien if (strncmp(info, "pub", 3) == 0) 394130561Sobrien sin_m.sin_other = SIN_PROXY; 39560484Sobrien else 39660484Sobrien usage(); 39760484Sobrien } 39860484Sobrien addr->sin_addr.s_addr = inet_addr(host); 39960484Sobrien if (addr->sin_addr.s_addr == INADDR_NONE) { 40060484Sobrien if (!(hp = gethostbyname(host))) { 40160484Sobrien warnx("%s: %s", host, hstrerror(h_errno)); 40260484Sobrien return (1); 40360484Sobrien } 40460484Sobrien bcopy((char *)hp->h_addr, (char *)&addr->sin_addr, 40560484Sobrien sizeof addr->sin_addr); 40660484Sobrien } 40760484Sobrientryagain: 40860484Sobrien if (rtmsg(RTM_GET) < 0) { 40960484Sobrien warn("%s", host); 41060484Sobrien return (1); 41160484Sobrien } 41260484Sobrien addr = (struct sockaddr_inarp *)(rtm + 1); 41360484Sobrien sdl = (struct sockaddr_dl *)(ROUNDUP(addr->sin_len) + (char *)addr); 41460484Sobrien if (addr->sin_addr.s_addr == sin_m.sin_addr.s_addr) { 41560484Sobrien if (sdl->sdl_family == AF_LINK && 41660484Sobrien (rtm->rtm_flags & RTF_LLINFO) && 41760484Sobrien !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { 41860484Sobrien case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 41960484Sobrien case IFT_ISO88024: case IFT_ISO88025: case IFT_L2VLAN: 42060484Sobrien goto delete; 42160484Sobrien } 42260484Sobrien } 42360484Sobrien if (sin_m.sin_other & SIN_PROXY) { 42460484Sobrien fprintf(stderr, "delete: can't locate %s\n",host); 42560484Sobrien return (1); 42660484Sobrien } else { 42760484Sobrien sin_m.sin_other = SIN_PROXY; 42860484Sobrien goto tryagain; 42960484Sobrien } 43060484Sobriendelete: 43160484Sobrien if (sdl->sdl_family != AF_LINK) { 43260484Sobrien printf("cannot locate %s\n", host); 43360484Sobrien return (1); 43460484Sobrien } 43560484Sobrien if (rtmsg(RTM_DELETE) == 0) { 43660484Sobrien printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr)); 43760484Sobrien return (0); 43860484Sobrien } 43960484Sobrien return (1); 44060484Sobrien} 44160484Sobrien 44260484Sobrien/* 44360484Sobrien * Search the arp table and do some action on matching entries 44460484Sobrien */ 44560484Sobrienvoid 44660484Sobriensearch(u_long addr, void (*action)(struct sockaddr_dl *sdl, 44760484Sobrien struct sockaddr_inarp *sin, struct rt_msghdr *rtm)) 448130561Sobrien{ 449130561Sobrien int mib[6]; 45060484Sobrien size_t needed; 45160484Sobrien char *lim, *buf, *next; 452130561Sobrien struct rt_msghdr *rtm; 45360484Sobrien struct sockaddr_inarp *sin2; 454130561Sobrien struct sockaddr_dl *sdl; 45560484Sobrien 45660484Sobrien mib[0] = CTL_NET; 45760484Sobrien mib[1] = PF_ROUTE; 45860484Sobrien mib[2] = 0; 45960484Sobrien mib[3] = AF_INET; 46060484Sobrien mib[4] = NET_RT_FLAGS; 46160484Sobrien mib[5] = RTF_LLINFO; 46260484Sobrien if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 46360484Sobrien errx(1, "route-sysctl-estimate"); 464130561Sobrien if ((buf = malloc(needed)) == NULL) 465130561Sobrien errx(1, "malloc"); 466130561Sobrien if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 467130561Sobrien errx(1, "actual retrieval of routing table"); 468130561Sobrien lim = buf + needed; 469130561Sobrien for (next = buf; next < lim; next += rtm->rtm_msglen) { 470130561Sobrien rtm = (struct rt_msghdr *)next; 471130561Sobrien sin2 = (struct sockaddr_inarp *)(rtm + 1); 472130561Sobrien (char *)sdl = (char *)sin2 + ROUNDUP(sin2->sin_len); 473130561Sobrien if (addr) { 47460484Sobrien if (addr != sin2->sin_addr.s_addr) 475130561Sobrien continue; 47660484Sobrien found_entry = 1; 47760484Sobrien } 47860484Sobrien (*action)(sdl, sin2, rtm); 47977298Sobrien } 48077298Sobrien free(buf); 48177298Sobrien} 48277298Sobrien 48377298Sobrien/* 484130561Sobrien * Display an arp entry 48577298Sobrien */ 48677298Sobrienvoid 48777298Sobrienprint_entry(struct sockaddr_dl *sdl, 48877298Sobrien struct sockaddr_inarp *addr, struct rt_msghdr *rtm) 48977298Sobrien{ 49077298Sobrien const char *host; 49177298Sobrien struct hostent *hp; 49277298Sobrien char ifname[IF_NAMESIZE]; 493130561Sobrien int seg; 49477298Sobrien 49577298Sobrien if (nflag == 0) 49677298Sobrien hp = gethostbyaddr((caddr_t)&(addr->sin_addr), 49777298Sobrien sizeof addr->sin_addr, AF_INET); 49877298Sobrien else 49977298Sobrien hp = 0; 50077298Sobrien if (hp) 50177298Sobrien host = hp->h_name; 50289857Sobrien else { 50389857Sobrien host = "?"; 50489857Sobrien if (h_errno == TRY_AGAIN) 50589857Sobrien nflag = 1; 50689857Sobrien } 50789857Sobrien printf("%s (%s) at ", host, inet_ntoa(addr->sin_addr)); 50889857Sobrien if (sdl->sdl_alen) 50989857Sobrien printf("%s", ether_ntoa((struct ether_addr *)LLADDR(sdl))); 51089857Sobrien else 51189857Sobrien printf("(incomplete)"); 51289857Sobrien if (if_indextoname(sdl->sdl_index, ifname) != NULL) 51389857Sobrien printf(" on %s", ifname); 51489857Sobrien if (rtm->rtm_rmx.rmx_expire == 0) 51589857Sobrien printf(" permanent"); 51689857Sobrien if (addr->sin_other & SIN_PROXY) 51789857Sobrien printf(" published (proxy only)"); 51889857Sobrien if (rtm->rtm_addrs & RTA_NETMASK) { 51989857Sobrien addr = (struct sockaddr_inarp *) 52089857Sobrien (ROUNDUP(sdl->sdl_len) + (char *)sdl); 52160484Sobrien if (addr->sin_addr.s_addr == 0xffffffff) 52277298Sobrien printf(" published"); 52377298Sobrien if (addr->sin_len != 8) 52477298Sobrien printf("(weird)"); 52577298Sobrien } 52677298Sobrien switch(sdl->sdl_type) { 52777298Sobrien case IFT_ETHER: 52877298Sobrien printf(" [ethernet]"); 52977298Sobrien break; 53077298Sobrien case IFT_ISO88025: 53160484Sobrien printf(" [token-ring]"); 53260484Sobrien break; 53360484Sobrien case IFT_FDDI: 53460484Sobrien printf(" [fddi]"); 53560484Sobrien break; 53660484Sobrien case IFT_ATM: 53760484Sobrien printf(" [atm]"); 53860484Sobrien break; 53960484Sobrien case IFT_L2VLAN: 54060484Sobrien printf(" [vlan]"); 54160484Sobrien break; 54260484Sobrien default: 54360484Sobrien } 54460484Sobrien if (sdl->sdl_rcf != NULL) { 54560484Sobrien printf(" rt=%x", ntohs(sdl->sdl_rcf)); 54660484Sobrien for (seg = 0; seg < ((((ntohs(sdl->sdl_rcf) & 0x1f00) >> 8) - 2 ) / 2); seg++) 54760484Sobrien printf(":%x", ntohs(sdl->sdl_route[seg])); 54860484Sobrien } 549130561Sobrien 55060484Sobrien printf("\n"); 55160484Sobrien 55260484Sobrien} 55360484Sobrien 55460484Sobrien/* 55560484Sobrien * Nuke an arp entry 55660484Sobrien */ 55760484Sobrienvoid 55860484Sobriennuke_entry(struct sockaddr_dl *sdl __unused, 55960484Sobrien struct sockaddr_inarp *addr, struct rt_msghdr *rtm __unused) 56060484Sobrien{ 56160484Sobrien char ip[20]; 56260484Sobrien 56360484Sobrien snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr)); 56460484Sobrien delete(ip, NULL); 56560484Sobrien} 56660484Sobrien 56760484Sobrienint 56860484Sobrienmy_ether_aton(char *a, struct ether_addr *n) 56960484Sobrien{ 57060484Sobrien struct ether_addr *ea; 57160484Sobrien 57260484Sobrien if ((ea = ether_aton(a)) == NULL) { 57360484Sobrien warnx("invalid Ethernet address '%s'", a); 57460484Sobrien return (1); 57560484Sobrien } 57660484Sobrien *n = *ea; 57760484Sobrien return (0); 57860484Sobrien} 57960484Sobrien 58060484Sobrienvoid 58160484Sobrienusage(void) 58260484Sobrien{ 58360484Sobrien fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 58460484Sobrien "usage: arp [-n] hostname", 58560484Sobrien " arp [-n] -a", 58660484Sobrien " arp -d hostname [pub]", 58760484Sobrien " arp -d -a", 58860484Sobrien " arp -s hostname ether_addr [temp] [pub]", 58960484Sobrien " arp -S hostname ether_addr [temp] [pub]", 59060484Sobrien " arp -f filename"); 59160484Sobrien exit(1); 59260484Sobrien} 59360484Sobrien 59460484Sobrienint 59560484Sobrienrtmsg(int cmd) 59660484Sobrien{ 59760484Sobrien static int seq; 59860484Sobrien int rlen; 59960484Sobrien register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 60060484Sobrien register char *cp = m_rtmsg.m_space; 601130561Sobrien register int l; 60260484Sobrien 60360484Sobrien errno = 0; 60460484Sobrien if (cmd == RTM_DELETE) 60560484Sobrien goto doit; 60660484Sobrien bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 60760484Sobrien rtm->rtm_flags = flags; 60860484Sobrien rtm->rtm_version = RTM_VERSION; 60960484Sobrien 61060484Sobrien switch (cmd) { 61160484Sobrien default: 61260484Sobrien errx(1, "internal wrong cmd"); 613130561Sobrien case RTM_ADD: 61460484Sobrien rtm->rtm_addrs |= RTA_GATEWAY; 61560484Sobrien rtm->rtm_rmx.rmx_expire = expire_time; 616130561Sobrien rtm->rtm_inits = RTV_EXPIRE; 61760484Sobrien rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); 61860484Sobrien sin_m.sin_other = 0; 619130561Sobrien if (doing_proxy) { 62060484Sobrien if (proxy_only) 62160484Sobrien sin_m.sin_other = SIN_PROXY; 62260484Sobrien else { 62360484Sobrien rtm->rtm_addrs |= RTA_NETMASK; 62460484Sobrien rtm->rtm_flags &= ~RTF_HOST; 625130561Sobrien } 62660484Sobrien } 62760484Sobrien /* FALLTHROUGH */ 628130561Sobrien case RTM_GET: 62960484Sobrien rtm->rtm_addrs |= RTA_DST; 63060484Sobrien } 63160484Sobrien#define NEXTADDR(w, s) \ 63260484Sobrien if (rtm->rtm_addrs & (w)) { \ 63360484Sobrien bcopy((char *)&s, cp, sizeof(s)); cp += ROUNDUP(sizeof(s));} 63460484Sobrien 635130561Sobrien NEXTADDR(RTA_DST, sin_m); 636130561Sobrien NEXTADDR(RTA_GATEWAY, sdl_m); 637130561Sobrien NEXTADDR(RTA_NETMASK, so_mask); 638130561Sobrien 639130561Sobrien rtm->rtm_msglen = cp - (char *)&m_rtmsg; 640130561Sobriendoit: 641130561Sobrien l = rtm->rtm_msglen; 642130561Sobrien rtm->rtm_seq = ++seq; 643130561Sobrien rtm->rtm_type = cmd; 644130561Sobrien if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 64560484Sobrien if (errno != ESRCH || cmd != RTM_DELETE) { 64660484Sobrien warn("writing to routing socket"); 64760484Sobrien return (-1); 64860484Sobrien } 649130561Sobrien } 65060484Sobrien do { 65160484Sobrien l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 65260484Sobrien } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 65360484Sobrien if (l < 0) 65460484Sobrien warn("read from routing socket"); 655130561Sobrien return (0); 65660484Sobrien} 65760484Sobrien 658130561Sobrien/* 65960484Sobrien * get_ether_addr - get the hardware address of an interface on the 660130561Sobrien * the same subnet as ipaddr. 66160484Sobrien */ 66260484Sobrien#define MAX_IFS 32 66360484Sobrien 66460484Sobrienint 66560484Sobrienget_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr) 66660484Sobrien{ 66760484Sobrien struct ifreq *ifr, *ifend, *ifp; 66860484Sobrien u_int32_t ina, mask; 66960484Sobrien struct sockaddr_dl *dla; 67060484Sobrien struct ifreq ifreq; 67160484Sobrien struct ifconf ifc; 672130561Sobrien struct ifreq ifs[MAX_IFS]; 67360484Sobrien int sock; 67460484Sobrien 675130561Sobrien sock = socket(AF_INET, SOCK_DGRAM, 0); 67660484Sobrien if (sock < 0) 67760484Sobrien err(1, "socket"); 67860484Sobrien 67960484Sobrien ifc.ifc_len = sizeof(ifs); 68060484Sobrien ifc.ifc_req = ifs; 68160484Sobrien if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { 682130561Sobrien warnx("ioctl(SIOCGIFCONF)"); 68360484Sobrien close(sock); 68460484Sobrien return 0; 685130561Sobrien } 68660484Sobrien 68760484Sobrien /* 68860484Sobrien * Scan through looking for an interface with an Internet 68960484Sobrien * address on the same subnet as `ipaddr'. 69060484Sobrien */ 69160484Sobrien ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); 69260484Sobrien for (ifr = ifc.ifc_req; ifr < ifend; ) { 693130561Sobrien if (ifr->ifr_addr.sa_family == AF_INET) { 694130561Sobrien ina = ((struct sockaddr_in *) 695130561Sobrien &ifr->ifr_addr)->sin_addr.s_addr; 696130561Sobrien strncpy(ifreq.ifr_name, ifr->ifr_name, 697130561Sobrien sizeof(ifreq.ifr_name)); 698130561Sobrien /* 699130561Sobrien * Check that the interface is up, 700130561Sobrien * and not point-to-point or loopback. 701130561Sobrien */ 702130561Sobrien if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) 703130561Sobrien continue; 704130561Sobrien if ((ifreq.ifr_flags & 705130561Sobrien (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT| 706130561Sobrien IFF_LOOPBACK|IFF_NOARP)) 707130561Sobrien != (IFF_UP|IFF_BROADCAST)) 708130561Sobrien goto nextif; 709130561Sobrien /* 710130561Sobrien * Get its netmask and check that it's on 711130561Sobrien * the right subnet. 712130561Sobrien */ 713130561Sobrien if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0) 714130561Sobrien continue; 715130561Sobrien mask = ((struct sockaddr_in *) 716130561Sobrien &ifreq.ifr_addr)->sin_addr.s_addr; 717130561Sobrien if ((ipaddr & mask) != (ina & mask)) 718130561Sobrien goto nextif; 719130561Sobrien break; 720130561Sobrien } 721130561Sobriennextif: 722130561Sobrien ifr = (struct ifreq *) ((char *)&ifr->ifr_addr 723130561Sobrien + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr))); 724130561Sobrien } 725130561Sobrien 726130561Sobrien if (ifr >= ifend) { 727130561Sobrien close(sock); 728130561Sobrien return 0; 729130561Sobrien } 730130561Sobrien 731130561Sobrien /* 732130561Sobrien * Now scan through again looking for a link-level address 733130561Sobrien * for this interface. 734130561Sobrien */ 735130561Sobrien ifp = ifr; 736130561Sobrien for (ifr = ifc.ifc_req; ifr < ifend; ) { 737130561Sobrien if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 738130561Sobrien && ifr->ifr_addr.sa_family == AF_LINK) { 739130561Sobrien /* 740130561Sobrien * Found the link-level address - copy it out 741130561Sobrien */ 742130561Sobrien dla = (struct sockaddr_dl *) &ifr->ifr_addr; 743130561Sobrien memcpy(hwaddr, LLADDR(dla), dla->sdl_alen); 744130561Sobrien close (sock); 745130561Sobrien printf("using interface %s for proxy with address ", 746130561Sobrien ifp->ifr_name); 747130561Sobrien printf("%s\n", ether_ntoa(hwaddr)); 748130561Sobrien return dla->sdl_alen; 749130561Sobrien } 75060484Sobrien ifr = (struct ifreq *) ((char *)&ifr->ifr_addr 75160484Sobrien + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr))); 75260484Sobrien } 75360484Sobrien return 0; 75489857Sobrien} 75589857Sobrien