diff --git a/contrib/ipfilter/ipsend/44arp.c b/contrib/ipfilter/ipsend/44arp.c index 9033ab9a64ba..9215959395ab 100644 --- a/contrib/ipfilter/ipsend/44arp.c +++ b/contrib/ipfilter/ipsend/44arp.c @@ -1,123 +1,120 @@ /* $FreeBSD$ */ /* * Based upon 4.4BSD's /usr/sbin/arp */ #include #include #include #include #include -#if __FreeBSD_version >= 300000 -# include -#endif #include #include #ifndef __osf__ # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipsend.h" #include "iplang/iplang.h" /* * lookup host and return * its IP address in address * (4 bytes) */ int resolve(host, address) char *host, *address; { struct hostent *hp; u_long add; add = inet_addr(host); if (add == -1) { if (!(hp = gethostbyname(host))) { fprintf(stderr, "unknown host: %s\n", host); return -1; } bcopy((char *)hp->h_addr, (char *)address, 4); return 0; } bcopy((char*)&add, address, 4); return 0; } int arp(addr, eaddr) char *addr, *eaddr; { int mib[6]; size_t needed; char *lim, *buf, *next; struct rt_msghdr *rtm; struct sockaddr_in *sin; struct sockaddr_dl *sdl; #ifdef IPSEND if (arp_getipv4(addr, ether) == 0) return 0; #endif if (!addr) return -1; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; mib[4] = NET_RT_FLAGS; #ifdef RTF_LLINFO mib[5] = RTF_LLINFO; #else mib[5] = 0; #endif if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) { perror("route-sysctl-estimate"); exit(-1); } if ((buf = malloc(needed)) == NULL) { perror("malloc"); exit(-1); } if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) { perror("actual retrieval of routing table"); exit(-1); } lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sin = (struct sockaddr_in *)(rtm + 1); sdl = (struct sockaddr_dl *)(sin + 1); if (!bcmp(addr, (char *)&sin->sin_addr, sizeof(struct in_addr))) { bcopy(LLADDR(sdl), eaddr, sdl->sdl_alen); return 0; } } return -1; } diff --git a/contrib/ipfilter/ipsend/ip.c b/contrib/ipfilter/ipsend/ip.c index 74d164b6ee85..fc7617065ac7 100644 --- a/contrib/ipfilter/ipsend/ip.c +++ b/contrib/ipfilter/ipsend/ip.c @@ -1,367 +1,364 @@ /* $FreeBSD$ */ /* * ip.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. */ #if !defined(lint) static const char sccsid[] = "%W% %G% (C)1995"; static const char rcsid[] = "@(#)$Id$"; #endif #include #include #include #include #include #include #include #include #ifndef linux # include # include # include -# if __FreeBSD_version >= 300000 -# include -# endif #endif #include #include #include #include #include #include "ipsend.h" static char *ipbuf = NULL, *ethbuf = NULL; u_short chksum(buf,len) u_short *buf; int len; { u_long sum = 0; int nwords = len >> 1; for(; nwords > 0; nwords--) sum += *buf++; sum = (sum>>16) + (sum & 0xffff); sum += (sum >>16); return (~sum); } int send_ether(nfd, buf, len, gwip) int nfd, len; char *buf; struct in_addr gwip; { static struct in_addr last_gw; static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; ether_header_t *eh; char *s; int err; if (!ethbuf) ethbuf = (char *)calloc(1, 65536+1024); s = ethbuf; eh = (ether_header_t *)s; bcopy((char *)buf, s + sizeof(*eh), len); if (gwip.s_addr == last_gw.s_addr) { bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); } else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) { perror("arp"); return -2; } eh->ether_type = htons(ETHERTYPE_IP); last_gw.s_addr = gwip.s_addr; err = sendip(nfd, s, sizeof(*eh) + len); return err; } /* */ int send_ip(nfd, mtu, ip, gwip, frag) int nfd, mtu; ip_t *ip; struct in_addr gwip; int frag; { static struct in_addr last_gw, local_ip; static char local_arp[6] = { 0, 0, 0, 0, 0, 0}; static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; static u_short id = 0; ether_header_t *eh; ip_t ipsv; int err, iplen; if (!ipbuf) { ipbuf = (char *)malloc(65536); if (!ipbuf) { perror("malloc failed"); return -2; } } eh = (ether_header_t *)ipbuf; bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) { bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); } else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) { perror("arp"); return -2; } bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp)); eh->ether_type = htons(ETHERTYPE_IP); bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); last_gw.s_addr = gwip.s_addr; iplen = ip->ip_len; ip->ip_len = htons(iplen); if (!(frag & 2)) { if (!IP_V(ip)) IP_V_A(ip, IPVERSION); if (!ip->ip_id) ip->ip_id = htons(id++); if (!ip->ip_ttl) ip->ip_ttl = 60; } if (ip->ip_src.s_addr != local_ip.s_addr) { (void) arp((char *)&ip->ip_src, (char *)A_A local_arp); bcopy(local_arp, (char *)A_A eh->ether_shost,sizeof(last_arp)); local_ip = ip->ip_src; } else bcopy(local_arp, (char *)A_A eh->ether_shost, 6); if (!frag || (sizeof(*eh) + iplen < mtu)) { ip->ip_sum = 0; ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); bcopy((char *)ip, ipbuf + sizeof(*eh), iplen); err = sendip(nfd, ipbuf, sizeof(*eh) + iplen); } else { /* * Actually, this is bogus because we're putting all IP * options in every packet, which isn't always what should be * done. Will do for now. */ ether_header_t eth; char optcpy[48], ol; char *s; int i, sent = 0, ts, hlen, olen; hlen = IP_HL(ip) << 2; if (mtu < (hlen + 8)) { fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", mtu, hlen); fprintf(stderr, "can't fragment data\n"); return -2; } ol = (IP_HL(ip) << 2) - sizeof(*ip); for (i = 0, s = (char*)(ip + 1); ol > 0; ) if (*s == IPOPT_EOL) { optcpy[i++] = *s; break; } else if (*s == IPOPT_NOP) { s++; ol--; } else { olen = (int)(*(u_char *)(s + 1)); ol -= olen; if (IPOPT_COPIED(*s)) { bcopy(s, optcpy + i, olen); i += olen; s += olen; } } if (i) { /* * pad out */ while ((i & 3) && (i & 3) != 3) optcpy[i++] = IPOPT_NOP; if ((i & 3) == 3) optcpy[i++] = IPOPT_EOL; } bcopy((char *)eh, (char *)ð, sizeof(eth)); s = (char *)ip + hlen; iplen = ntohs(ip->ip_len) - hlen; ip->ip_off |= htons(IP_MF); while (1) { if ((sent + (mtu - hlen)) >= iplen) { ip->ip_off ^= htons(IP_MF); ts = iplen - sent; } else ts = (mtu - hlen); ip->ip_off &= htons(0xe000); ip->ip_off |= htons(sent >> 3); ts += hlen; ip->ip_len = htons(ts); ip->ip_sum = 0; ip->ip_sum = chksum((u_short *)ip, hlen); bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); err = sendip(nfd, ipbuf, sizeof(*eh) + ts); bcopy((char *)ð, ipbuf, sizeof(eth)); sent += (ts - hlen); if (!(ntohs(ip->ip_off) & IP_MF)) break; else if (!(ip->ip_off & htons(0x1fff))) { hlen = i + sizeof(*ip); IP_HL_A(ip, (sizeof(*ip) + i) >> 2); bcopy(optcpy, (char *)(ip + 1), i); } } } bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); return err; } /* * send a tcp packet. */ int send_tcp(nfd, mtu, ip, gwip) int nfd, mtu; ip_t *ip; struct in_addr gwip; { static tcp_seq iss = 2; tcphdr_t *t, *t2; int thlen, i, iplen, hlen; u_32_t lbuf[20]; ip_t *ip2; iplen = ip->ip_len; hlen = IP_HL(ip) << 2; t = (tcphdr_t *)((char *)ip + hlen); ip2 = (struct ip *)lbuf; t2 = (tcphdr_t *)((char *)ip2 + hlen); thlen = TCP_OFF(t) << 2; if (!thlen) thlen = sizeof(tcphdr_t); bzero((char *)ip2, sizeof(*ip2) + sizeof(*t2)); ip->ip_p = IPPROTO_TCP; ip2->ip_p = ip->ip_p; ip2->ip_src = ip->ip_src; ip2->ip_dst = ip->ip_dst; bcopy((char *)ip + hlen, (char *)t2, thlen); if (!t2->th_win) t2->th_win = htons(4096); iss += 63; i = sizeof(struct tcpiphdr) / sizeof(long); if ((t2->th_flags == TH_SYN) && !ntohs(ip->ip_off) && (lbuf[i] != htonl(0x020405b4))) { lbuf[i] = htonl(0x020405b4); bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4, iplen - thlen - hlen); thlen += 4; } TCP_OFF_A(t2, thlen >> 2); ip2->ip_len = htons(thlen); ip->ip_len = hlen + thlen; t2->th_sum = 0; t2->th_sum = chksum((u_short *)ip2, thlen + sizeof(ip_t)); bcopy((char *)t2, (char *)ip + hlen, thlen); return send_ip(nfd, mtu, ip, gwip, 1); } /* * send a udp packet. */ int send_udp(nfd, mtu, ip, gwip) int nfd, mtu; ip_t *ip; struct in_addr gwip; { struct tcpiphdr *ti; int thlen; u_long lbuf[20]; ti = (struct tcpiphdr *)lbuf; bzero((char *)ti, sizeof(*ti)); thlen = sizeof(udphdr_t); ti->ti_pr = ip->ip_p; ti->ti_src = ip->ip_src; ti->ti_dst = ip->ip_dst; bcopy((char *)ip + (IP_HL(ip) << 2), (char *)&ti->ti_sport, sizeof(udphdr_t)); ti->ti_len = htons(thlen); ip->ip_len = (IP_HL(ip) << 2) + thlen; ti->ti_sum = 0; ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); bcopy((char *)&ti->ti_sport, (char *)ip + (IP_HL(ip) << 2), sizeof(udphdr_t)); return send_ip(nfd, mtu, ip, gwip, 1); } /* * send an icmp packet. */ int send_icmp(nfd, mtu, ip, gwip) int nfd, mtu; ip_t *ip; struct in_addr gwip; { struct icmp *ic; ic = (struct icmp *)((char *)ip + (IP_HL(ip) << 2)); ic->icmp_cksum = 0; ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); return send_ip(nfd, mtu, ip, gwip, 1); } int send_packet(nfd, mtu, ip, gwip) int nfd, mtu; ip_t *ip; struct in_addr gwip; { switch (ip->ip_p) { case IPPROTO_TCP : return send_tcp(nfd, mtu, ip, gwip); case IPPROTO_UDP : return send_udp(nfd, mtu, ip, gwip); case IPPROTO_ICMP : return send_icmp(nfd, mtu, ip, gwip); default : return send_ip(nfd, mtu, ip, gwip, 1); } } diff --git a/contrib/ipfilter/ipsend/resend.c b/contrib/ipfilter/ipsend/resend.c index d113af38857e..45159bf76455 100644 --- a/contrib/ipfilter/ipsend/resend.c +++ b/contrib/ipfilter/ipsend/resend.c @@ -1,146 +1,143 @@ /* $FreeBSD$ */ /* * resend.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. * */ #if !defined(lint) static const char sccsid[] = "@(#)resend.c 1.3 1/11/96 (C)1995 Darren Reed"; static const char rcsid[] = "@(#)$Id$"; #endif #include #include #include #include #include #include #include #include #include #ifndef linux # include # include -# if __FreeBSD_version >= 300000 -# include -# endif #endif #include #include #include #include #include #include "ipsend.h" extern int opts; void dumppacket __P((ip_t *)); void dumppacket(ip) ip_t *ip; { tcphdr_t *t; int i, j; t = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); if (ip->ip_tos) printf("tos %#x ", ip->ip_tos); if (ip->ip_off & 0x3fff) printf("frag @%#x ", (ip->ip_off & 0x1fff) << 3); printf("len %d id %d ", ip->ip_len, ip->ip_id); printf("ttl %d p %d src %s", ip->ip_ttl, ip->ip_p, inet_ntoa(ip->ip_src)); if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) printf(",%d", t->th_sport); printf(" dst %s", inet_ntoa(ip->ip_dst)); if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) printf(",%d", t->th_dport); if (ip->ip_p == IPPROTO_TCP) { printf(" seq %lu:%lu flags ", (u_long)t->th_seq, (u_long)t->th_ack); for (j = 0, i = 1; i < 256; i *= 2, j++) if (t->th_flags & i) printf("%c", "FSRPAU--"[j]); } putchar('\n'); } int ip_resend(dev, mtu, r, gwip, datain) char *dev; int mtu; struct in_addr gwip; struct ipread *r; char *datain; { ether_header_t *eh; char dhost[6]; ip_t *ip; int fd, wfd = initdevice(dev, 5), len, i; mb_t mb; if (wfd == -1) return -1; if (datain) fd = (*r->r_open)(datain); else fd = (*r->r_open)("-"); if (fd < 0) exit(-1); ip = (struct ip *)mb.mb_buf; eh = (ether_header_t *)malloc(sizeof(*eh)); if(!eh) { perror("malloc failed"); return -2; } bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); if (gwip.s_addr && (arp((char *)&gwip, dhost) == -1)) { perror("arp"); free(eh); return -2; } while ((i = (*r->r_readip)(&mb, NULL, NULL)) > 0) { if (!(opts & OPT_RAW)) { len = ntohs(ip->ip_len); eh = (ether_header_t *)realloc((char *)eh, sizeof(*eh) + len); eh->ether_type = htons((u_short)ETHERTYPE_IP); if (!gwip.s_addr) { if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) { perror("arp"); continue; } } else bcopy(dhost, (char *)A_A eh->ether_dhost, sizeof(dhost)); if (!ip->ip_sum) ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); bcopy(ip, (char *)(eh + 1), len); len += sizeof(*eh); dumppacket(ip); } else { eh = (ether_header_t *)mb.mb_buf; len = i; } if (sendip(wfd, (char *)eh, len) == -1) { perror("send_packet"); break; } } (*r->r_close)(); free(eh); return 0; } diff --git a/contrib/ipfilter/lib/kmem.c b/contrib/ipfilter/lib/kmem.c index 382a51c88c18..d895bafd0540 100644 --- a/contrib/ipfilter/lib/kmem.c +++ b/contrib/ipfilter/lib/kmem.c @@ -1,204 +1,201 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ /* * kmemcpy() - copies n bytes from kernel memory into user buffer. * returns 0 on success, -1 on error. */ #include #include #include #include #include #include #include #include #if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && !defined(linux) && !defined(_AIX51) #include #endif #include #include #include #include #include #include #include #include -#if __FreeBSD_version >= 300000 -# include -#endif #if defined(linux) || defined(__osf__) || defined(__sgi) || defined(__hpux) # include #endif #include "kmem.h" #ifndef __STDC__ # define const #endif #if !defined(lint) static const char sccsid[] = "@(#)kmem.c 1.4 1/12/96 (C) 1992 Darren Reed"; static const char rcsid[] = "@(#)$Id$"; #endif #if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && \ !defined(linux) && !defined(_AIX51) /* * For all platforms where there is a libkvm and a kvm_t, we use that... */ static kvm_t *kvm_f = NULL; #else /* *...and for the others (HP-UX, IRIX, Tru64), we have to provide our own. */ typedef int * kvm_t; static kvm_t kvm_f = NULL; static char *kvm_errstr = NULL; kvm_t kvm_open __P((char *, char *, char *, int, char *)); int kvm_read __P((kvm_t, u_long, char *, size_t)); kvm_t kvm_open(kernel, core, swap, mode, errstr) char *kernel, *core, *swap; int mode; char *errstr; { kvm_t k; int fd; kvm_errstr = errstr; if (core == NULL) core = "/dev/kmem"; fd = open(core, mode); if (fd == -1) return NULL; k = malloc(sizeof(*k)); if (k == NULL) return NULL; *k = fd; return k; } int kvm_read(kvm, pos, buffer, size) kvm_t kvm; u_long pos; char *buffer; size_t size; { int r = 0, left; char *bufp; if (lseek(*kvm, pos, 0) == -1) { if (kvm_errstr != NULL) { fprintf(stderr, "%s", kvm_errstr); perror("lseek"); } return -1; } for (bufp = buffer, left = size; left > 0; bufp += r, left -= r) { r = read(*kvm, bufp, left); #ifdef __osf__ /* * Tru64 returns "0" for successful operation, not the number * of bytes read. */ if (r == 0) r = left; #endif if (r <= 0) return -1; } return r; } #endif /* !defined(__sgi) && !defined(__hpux) && !defined(__osf__) */ int openkmem(kern, core) char *kern, *core; { kvm_f = kvm_open(kern, core, NULL, O_RDONLY, NULL); if (kvm_f == NULL) { perror("openkmem:open"); return -1; } return kvm_f != NULL; } int kmemcpy(buf, pos, n) register char *buf; long pos; register int n; { register int r; if (!n) return 0; if (kvm_f == NULL) if (openkmem(NULL, NULL) == -1) return -1; while ((r = kvm_read(kvm_f, pos, buf, n)) < n) if (r <= 0) { fprintf(stderr, "pos=0x%lx ", (u_long)pos); perror("kmemcpy:read"); return -1; } else { buf += r; pos += r; n -= r; } return 0; } int kstrncpy(buf, pos, n) register char *buf; long pos; register int n; { register int r; if (!n) return 0; if (kvm_f == NULL) if (openkmem(NULL, NULL) == -1) return -1; while (n > 0) { r = kvm_read(kvm_f, pos, buf, 1); if (r <= 0) { fprintf(stderr, "pos=0x%lx ", (u_long)pos); perror("kmemcpy:read"); return -1; } else { if (*buf == '\0') break; buf++; pos++; n--; } } return 0; } diff --git a/contrib/ipfilter/tools/ipfs.c b/contrib/ipfilter/tools/ipfs.c index b5484be2193c..43abd748f59f 100644 --- a/contrib/ipfilter/tools/ipfs.c +++ b/contrib/ipfilter/tools/ipfs.c @@ -1,884 +1,881 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ #ifdef __FreeBSD__ # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif #endif #include #include #include #include #include #if !defined(__SVR4) && !defined(__GNUC__) #include #endif #include #include #include #include #include #include #include #include #include #include #include -#if __FreeBSD_version >= 300000 -# include -#endif #include #include #include #include #include "ipf.h" #include "netinet/ipl.h" #if !defined(lint) static const char rcsid[] = "@(#)$Id$"; #endif #ifndef IPF_SAVEDIR # define IPF_SAVEDIR "/var/db/ipf" #endif #ifndef IPF_NATFILE # define IPF_NATFILE "ipnat.ipf" #endif #ifndef IPF_STATEFILE # define IPF_STATEFILE "ipstate.ipf" #endif #if !defined(__SVR4) && defined(__GNUC__) extern char *index __P((const char *, int)); #endif extern char *optarg; extern int optind; int main __P((int, char *[])); void usage __P((void)); int changestateif __P((char *, char *)); int changenatif __P((char *, char *)); int readstate __P((int, char *)); int readnat __P((int, char *)); int writestate __P((int, char *)); int opendevice __P((char *)); void closedevice __P((int)); int setlock __P((int, int)); int writeall __P((char *)); int readall __P((char *)); int writenat __P((int, char *)); int opts = 0; char *progname; void usage() { fprintf(stderr, "usage: %s [-nv] -l\n", progname); fprintf(stderr, "usage: %s [-nv] -u\n", progname); fprintf(stderr, "usage: %s [-nv] [-d ] -R\n", progname); fprintf(stderr, "usage: %s [-nv] [-d ] -W\n", progname); fprintf(stderr, "usage: %s [-nNSv] [-f ] -r\n", progname); fprintf(stderr, "usage: %s [-nNSv] [-f ] -w\n", progname); fprintf(stderr, "usage: %s [-nNSv] -f -i ,\n", progname); exit(1); } /* * Change interface names in state information saved out to disk. */ int changestateif(ifs, fname) char *ifs, *fname; { int fd, olen, nlen, rw; ipstate_save_t ips; off_t pos; char *s; s = strchr(ifs, ','); if (!s) usage(); *s++ = '\0'; nlen = strlen(s); olen = strlen(ifs); if (nlen >= sizeof(ips.ips_is.is_ifname) || olen >= sizeof(ips.ips_is.is_ifname)) usage(); fd = open(fname, O_RDWR); if (fd == -1) { perror("open"); exit(1); } for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) { rw = 0; if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) { strcpy(ips.ips_is.is_ifname[0], s); rw = 1; } if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) { strcpy(ips.ips_is.is_ifname[1], s); rw = 1; } if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) { strcpy(ips.ips_is.is_ifname[2], s); rw = 1; } if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) { strcpy(ips.ips_is.is_ifname[3], s); rw = 1; } if (rw == 1) { if (lseek(fd, pos, SEEK_SET) != pos) { perror("lseek"); exit(1); } if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) { perror("write"); exit(1); } } pos = lseek(fd, 0, SEEK_CUR); } close(fd); return 0; } /* * Change interface names in NAT information saved out to disk. */ int changenatif(ifs, fname) char *ifs, *fname; { int fd, olen, nlen, rw; nat_save_t ipn; nat_t *nat; off_t pos; char *s; s = strchr(ifs, ','); if (!s) usage(); *s++ = '\0'; nlen = strlen(s); olen = strlen(ifs); nat = &ipn.ipn_nat; if (nlen >= sizeof(nat->nat_ifnames[0]) || olen >= sizeof(nat->nat_ifnames[0])) usage(); fd = open(fname, O_RDWR); if (fd == -1) { perror("open"); exit(1); } for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) { rw = 0; if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) { strcpy(nat->nat_ifnames[0], s); rw = 1; } if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) { strcpy(nat->nat_ifnames[1], s); rw = 1; } if (rw == 1) { if (lseek(fd, pos, SEEK_SET) != pos) { perror("lseek"); exit(1); } if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { perror("write"); exit(1); } } pos = lseek(fd, 0, SEEK_CUR); } close(fd); return 0; } int main(argc,argv) int argc; char *argv[]; { int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; char *dirname = NULL, *filename = NULL, *ifs = NULL; progname = argv[0]; while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1) switch (c) { case 'd' : if ((set == 0) && !dirname && !filename) dirname = optarg; else usage(); break; case 'f' : if ((set != 0) && !dirname && !filename) filename = optarg; else usage(); break; case 'i' : ifs = optarg; set = 1; break; case 'l' : if (filename || dirname || set) usage(); lock = 1; set = 1; break; case 'n' : opts |= OPT_DONOTHING; break; case 'N' : if ((ns >= 0) || dirname || (rw != -1) || set) usage(); ns = 0; set = 1; break; case 'r' : if (dirname || (rw != -1) || (ns == -1)) usage(); rw = 0; set = 1; break; case 'R' : rw = 2; set = 1; break; case 'S' : if ((ns >= 0) || dirname || (rw != -1) || set) usage(); ns = 1; set = 1; break; case 'u' : if (filename || dirname || set) usage(); lock = 0; set = 1; break; case 'v' : opts |= OPT_VERBOSE; break; case 'w' : if (dirname || (rw != -1) || (ns == -1)) usage(); rw = 1; set = 1; break; case 'W' : rw = 3; set = 1; break; case '?' : default : usage(); } if (ifs) { if (!filename || ns < 0) usage(); if (ns == 0) return changenatif(ifs, filename); else return changestateif(ifs, filename); } if ((ns >= 0) || (lock >= 0)) { if (lock >= 0) devfd = opendevice(NULL); else if (ns >= 0) { if (ns == 1) devfd = opendevice(IPSTATE_NAME); else if (ns == 0) devfd = opendevice(IPNAT_NAME); } if (devfd == -1) exit(1); } if (lock >= 0) err = setlock(devfd, lock); else if (rw >= 0) { if (rw & 1) { /* WRITE */ if (rw & 2) err = writeall(dirname); else { if (ns == 0) err = writenat(devfd, filename); else if (ns == 1) err = writestate(devfd, filename); } } else { if (rw & 2) err = readall(dirname); else { if (ns == 0) err = readnat(devfd, filename); else if (ns == 1) err = readstate(devfd, filename); } } } return err; } int opendevice(ipfdev) char *ipfdev; { int fd = -1; if (opts & OPT_DONOTHING) return -2; if (!ipfdev) ipfdev = IPL_NAME; if ((fd = open(ipfdev, O_RDWR)) == -1) if ((fd = open(ipfdev, O_RDONLY)) == -1) perror("open device"); return fd; } void closedevice(fd) int fd; { close(fd); } int setlock(fd, lock) int fd, lock; { if (opts & OPT_VERBOSE) printf("Turn lock %s\n", lock ? "on" : "off"); if (!(opts & OPT_DONOTHING)) { if (ioctl(fd, SIOCSTLCK, &lock) == -1) { perror("SIOCSTLCK"); return 1; } if (opts & OPT_VERBOSE) printf("Lock now %s\n", lock ? "on" : "off"); } return 0; } int writestate(fd, file) int fd; char *file; { ipstate_save_t ips, *ipsp; ipfobj_t obj; int wfd = -1; if (!file) file = IPF_STATEFILE; wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); if (wfd == -1) { fprintf(stderr, "%s ", file); perror("state:open"); return 1; } ipsp = &ips; bzero((char *)&obj, sizeof(obj)); bzero((char *)ipsp, sizeof(ips)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = sizeof(*ipsp); obj.ipfo_type = IPFOBJ_STATESAVE; obj.ipfo_ptr = ipsp; do { if (opts & OPT_VERBOSE) printf("Getting state from addr %p\n", ips.ips_next); if (ioctl(fd, SIOCSTGET, &obj)) { if (errno == ENOENT) break; perror("state:SIOCSTGET"); close(wfd); return 1; } if (opts & OPT_VERBOSE) printf("Got state next %p\n", ips.ips_next); if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { perror("state:write"); close(wfd); return 1; } } while (ips.ips_next != NULL); close(wfd); return 0; } int readstate(fd, file) int fd; char *file; { ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; int sfd = -1, i; ipfobj_t obj; if (!file) file = IPF_STATEFILE; sfd = open(file, O_RDONLY, 0600); if (sfd == -1) { fprintf(stderr, "%s ", file); perror("open"); return 1; } bzero((char *)&ips, sizeof(ips)); /* * 1. Read all state information in. */ do { i = read(sfd, &ips, sizeof(ips)); if (i == -1) { perror("read"); goto freeipshead; } if (i == 0) break; if (i != sizeof(ips)) { fprintf(stderr, "state:incomplete read: %d != %d\n", i, (int)sizeof(ips)); goto freeipshead; } is = (ipstate_save_t *)malloc(sizeof(*is)); if (is == NULL) { fprintf(stderr, "malloc failed\n"); goto freeipshead; } bcopy((char *)&ips, (char *)is, sizeof(ips)); /* * Check to see if this is the first state entry that will * reference a particular rule and if so, flag it as such * else just adjust the rule pointer to become a pointer to * the other. We do this so we have a means later for tracking * who is referencing us when we get back the real pointer * in is_rule after doing the ioctl. */ for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) if (is1->ips_rule == is->ips_rule) break; if (is1 == NULL) is->ips_is.is_flags |= SI_NEWFR; else is->ips_rule = (void *)&is1->ips_rule; /* * Use a tail-queue type list (add things to the end).. */ is->ips_next = NULL; if (!ipshead) ipshead = is; if (ipstail) ipstail->ips_next = is; ipstail = is; } while (1); close(sfd); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = sizeof(*is); obj.ipfo_type = IPFOBJ_STATESAVE; while ((is = ipshead) != NULL) { if (opts & OPT_VERBOSE) printf("Loading new state table entry\n"); if (is->ips_is.is_flags & SI_NEWFR) { if (opts & OPT_VERBOSE) printf("Loading new filter rule\n"); } obj.ipfo_ptr = is; if (!(opts & OPT_DONOTHING)) if (ioctl(fd, SIOCSTPUT, &obj)) { perror("SIOCSTPUT"); goto freeipshead; } if (is->ips_is.is_flags & SI_NEWFR) { if (opts & OPT_VERBOSE) printf("Real rule addr %p\n", is->ips_rule); for (is1 = is->ips_next; is1; is1 = is1->ips_next) if (is1->ips_rule == (frentry_t *)&is->ips_rule) is1->ips_rule = is->ips_rule; } ipshead = is->ips_next; free(is); } return 0; freeipshead: while ((is = ipshead) != NULL) { ipshead = is->ips_next; free(is); } if (sfd != -1) close(sfd); return 1; } int readnat(fd, file) int fd; char *file; { nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL; ipfobj_t obj; int nfd, i; nat_t *nat; char *s; int n; nfd = -1; in = NULL; ipnhead = NULL; ipntail = NULL; if (!file) file = IPF_NATFILE; nfd = open(file, O_RDONLY); if (nfd == -1) { fprintf(stderr, "%s ", file); perror("nat:open"); return 1; } bzero((char *)&ipn, sizeof(ipn)); /* * 1. Read all state information in. */ do { i = read(nfd, &ipn, sizeof(ipn)); if (i == -1) { perror("read"); goto freenathead; } if (i == 0) break; if (i != sizeof(ipn)) { fprintf(stderr, "nat:incomplete read: %d != %d\n", i, (int)sizeof(ipn)); goto freenathead; } in = (nat_save_t *)malloc(ipn.ipn_dsize); if (in == NULL) { fprintf(stderr, "nat:cannot malloc nat save atruct\n"); goto freenathead; } if (ipn.ipn_dsize > sizeof(ipn)) { n = ipn.ipn_dsize - sizeof(ipn); if (n > 0) { s = in->ipn_data + sizeof(in->ipn_data); i = read(nfd, s, n); if (i == 0) break; if (i != n) { fprintf(stderr, "nat:incomplete read: %d != %d\n", i, n); goto freenathead; } } } bcopy((char *)&ipn, (char *)in, sizeof(ipn)); /* * Check to see if this is the first NAT entry that will * reference a particular rule and if so, flag it as such * else just adjust the rule pointer to become a pointer to * the other. We do this so we have a means later for tracking * who is referencing us when we get back the real pointer * in is_rule after doing the ioctl. */ nat = &in->ipn_nat; if (nat->nat_fr != NULL) { for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) if (in1->ipn_rule == nat->nat_fr) break; if (in1 == NULL) nat->nat_flags |= SI_NEWFR; else nat->nat_fr = &in1->ipn_fr; } /* * Use a tail-queue type list (add things to the end).. */ in->ipn_next = NULL; if (!ipnhead) ipnhead = in; if (ipntail) ipntail->ipn_next = in; ipntail = in; } while (1); close(nfd); nfd = -1; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_NATSAVE; while ((in = ipnhead) != NULL) { if (opts & OPT_VERBOSE) printf("Loading new NAT table entry\n"); nat = &in->ipn_nat; if (nat->nat_flags & SI_NEWFR) { if (opts & OPT_VERBOSE) printf("Loading new filter rule\n"); } obj.ipfo_ptr = in; obj.ipfo_size = in->ipn_dsize; if (!(opts & OPT_DONOTHING)) if (ioctl(fd, SIOCSTPUT, &obj)) { fprintf(stderr, "in=%p:", in); perror("SIOCSTPUT"); return 1; } if (nat->nat_flags & SI_NEWFR) { if (opts & OPT_VERBOSE) printf("Real rule addr %p\n", nat->nat_fr); for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) if (in1->ipn_rule == &in->ipn_fr) in1->ipn_rule = nat->nat_fr; } ipnhead = in->ipn_next; free(in); } return 0; freenathead: while ((in = ipnhead) != NULL) { ipnhead = in->ipn_next; free(in); } if (nfd != -1) close(nfd); return 1; } int writenat(fd, file) int fd; char *file; { nat_save_t *ipnp = NULL, *next = NULL; ipfobj_t obj; int nfd = -1; natget_t ng; if (!file) file = IPF_NATFILE; nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); if (nfd == -1) { fprintf(stderr, "%s ", file); perror("nat:open"); return 1; } obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_NATSAVE; do { if (opts & OPT_VERBOSE) printf("Getting nat from addr %p\n", ipnp); ng.ng_ptr = next; ng.ng_sz = 0; if (ioctl(fd, SIOCSTGSZ, &ng)) { perror("nat:SIOCSTGSZ"); close(nfd); if (ipnp != NULL) free(ipnp); return 1; } if (opts & OPT_VERBOSE) printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); if (ng.ng_sz == 0) break; if (!ipnp) ipnp = malloc(ng.ng_sz); else ipnp = realloc((char *)ipnp, ng.ng_sz); if (!ipnp) { fprintf(stderr, "malloc for %d bytes failed\n", ng.ng_sz); break; } bzero((char *)ipnp, ng.ng_sz); obj.ipfo_size = ng.ng_sz; obj.ipfo_ptr = ipnp; ipnp->ipn_dsize = ng.ng_sz; ipnp->ipn_next = next; if (ioctl(fd, SIOCSTGET, &obj)) { if (errno == ENOENT) break; perror("nat:SIOCSTGET"); close(nfd); free(ipnp); return 1; } if (opts & OPT_VERBOSE) printf("Got nat next %p ipn_dsize %d ng_sz %d\n", ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { perror("nat:write"); close(nfd); free(ipnp); return 1; } next = ipnp->ipn_next; } while (ipnp && next); if (ipnp != NULL) free(ipnp); close(nfd); return 0; } int writeall(dirname) char *dirname; { int fd, devfd; if (!dirname) dirname = IPF_SAVEDIR; if (chdir(dirname)) { fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname); perror("chdir(IPF_SAVEDIR)"); return 1; } fd = opendevice(NULL); if (fd == -1) return 1; if (setlock(fd, 1)) { close(fd); return 1; } devfd = opendevice(IPSTATE_NAME); if (devfd == -1) goto bad; if (writestate(devfd, NULL)) goto bad; close(devfd); devfd = opendevice(IPNAT_NAME); if (devfd == -1) goto bad; if (writenat(devfd, NULL)) goto bad; close(devfd); if (setlock(fd, 0)) { close(fd); return 1; } close(fd); return 0; bad: setlock(fd, 0); close(fd); return 1; } int readall(dirname) char *dirname; { int fd, devfd; if (!dirname) dirname = IPF_SAVEDIR; if (chdir(dirname)) { perror("chdir(IPF_SAVEDIR)"); return 1; } fd = opendevice(NULL); if (fd == -1) return 1; if (setlock(fd, 1)) { close(fd); return 1; } devfd = opendevice(IPSTATE_NAME); if (devfd == -1) return 1; if (readstate(devfd, NULL)) return 1; close(devfd); devfd = opendevice(IPNAT_NAME); if (devfd == -1) return 1; if (readnat(devfd, NULL)) return 1; close(devfd); if (setlock(fd, 0)) { close(fd); return 1; } return 0; } diff --git a/contrib/ipfilter/tools/ipnat.c b/contrib/ipfilter/tools/ipnat.c index 448c1c0d2d2a..c3a715698036 100644 --- a/contrib/ipfilter/tools/ipnat.c +++ b/contrib/ipfilter/tools/ipnat.c @@ -1,858 +1,855 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) */ #include #include #include #include #include #if !defined(__SVR4) && !defined(__svr4__) #include #else #include #endif #include #include #include #include #include #include #define _KERNEL #include #undef _KERNEL #include #include #if defined(sun) && (defined(__svr4__) || defined(__SVR4)) # include # include #endif #include #include #include #include #include -#if __FreeBSD_version >= 300000 -# include -#endif #include #include #include #include #include #if defined(linux) # include #else # include #endif #include "ipf.h" #include "netinet/ipl.h" #include "kmem.h" #ifdef __hpux # define nlist nlist64 #endif #if defined(sun) && !SOLARIS2 # define STRERROR(x) sys_errlist[x] extern char *sys_errlist[]; #else # define STRERROR(x) strerror(x) #endif #if !defined(lint) static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; static const char rcsid[] = "@(#)$Id$"; #endif #if SOLARIS #define bzero(a,b) memset(a,0,b) #endif int use_inet6 = 0; char thishost[MAXHOSTNAMELEN]; extern char *optarg; void dostats __P((int, natstat_t *, int, int, int *)); void dotable __P((natstat_t *, int, int, int, char *)); void flushtable __P((int, int, int *)); void usage __P((char *)); int main __P((int, char*[])); void showhostmap __P((natstat_t *nsp)); void natstat_dead __P((natstat_t *, char *)); void dostats_live __P((int, natstat_t *, int, int *)); void showhostmap_dead __P((natstat_t *)); void showhostmap_live __P((int, natstat_t *)); void dostats_dead __P((natstat_t *, int, int *)); int nat_matcharray __P((nat_t *, int *)); int opts; int nohdrfields = 0; wordtab_t *nat_fields = NULL; void usage(name) char *name; { fprintf(stderr, "Usage: %s [-CFhlnrRsv] [-f filename]\n", name); exit(1); } int main(argc, argv) int argc; char *argv[]; { int fd, c, mode, *natfilter; char *file, *core, *kernel; natstat_t ns, *nsp; ipfobj_t obj; fd = -1; opts = 0; nsp = &ns; file = NULL; core = NULL; kernel = NULL; mode = O_RDWR; natfilter = NULL; assigndefined(getenv("IPNAT_PREDEFINED")); while ((c = getopt(argc, argv, "CdFf:hlm:M:N:nO:prRsv")) != -1) switch (c) { case 'C' : opts |= OPT_CLEAR; break; case 'd' : opts |= OPT_DEBUG; break; case 'f' : file = optarg; break; case 'F' : opts |= OPT_FLUSH; break; case 'h' : opts |=OPT_HITS; break; case 'l' : opts |= OPT_LIST; mode = O_RDONLY; break; case 'm' : natfilter = parseipfexpr(optarg, NULL); break; case 'M' : core = optarg; break; case 'N' : kernel = optarg; break; case 'n' : opts |= OPT_DONOTHING|OPT_DONTOPEN; mode = O_RDONLY; break; case 'O' : nat_fields = parsefields(natfields, optarg); break; case 'p' : opts |= OPT_PURGE; break; case 'R' : opts |= OPT_NORESOLVE; break; case 'r' : opts |= OPT_REMOVE; break; case 's' : opts |= OPT_STAT; mode = O_RDONLY; break; case 'v' : opts |= OPT_VERBOSE; break; default : usage(argv[0]); } if (((opts & OPT_PURGE) != 0) && ((opts & OPT_REMOVE) == 0)) { (void) fprintf(stderr, "%s: -p must be used with -r\n", argv[0]); exit(1); } initparse(); if ((kernel != NULL) || (core != NULL)) { (void) setgid(getgid()); (void) setuid(getuid()); } if (!(opts & OPT_DONOTHING)) { if (((fd = open(IPNAT_NAME, mode)) == -1) && ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) { (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME, STRERROR(errno)); exit(1); } } bzero((char *)&ns, sizeof(ns)); if ((opts & OPT_DONOTHING) == 0) { if (checkrev(IPL_NAME) == -1) { fprintf(stderr, "User/kernel version check failed\n"); exit(1); } } if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) { bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_NATSTAT; obj.ipfo_size = sizeof(*nsp); obj.ipfo_ptr = (void *)nsp; if (ioctl(fd, SIOCGNATS, &obj) == -1) { ipferror(fd, "ioctl(SIOCGNATS)"); exit(1); } (void) setgid(getgid()); (void) setuid(getuid()); } else if ((kernel != NULL) || (core != NULL)) { if (openkmem(kernel, core) == -1) exit(1); natstat_dead(nsp, kernel); if (opts & (OPT_LIST|OPT_STAT)) dostats(fd, nsp, opts, 0, natfilter); exit(0); } if (opts & (OPT_FLUSH|OPT_CLEAR)) flushtable(fd, opts, natfilter); if (file) { return ipnat_parsefile(fd, ipnat_addrule, ioctl, file); } if (opts & (OPT_LIST|OPT_STAT)) dostats(fd, nsp, opts, 1, natfilter); return 0; } /* * Read NAT statistic information in using a symbol table and memory file * rather than doing ioctl's. */ void natstat_dead(nsp, kernel) natstat_t *nsp; char *kernel; { struct nlist nat_nlist[10] = { { "nat_table" }, /* 0 */ { "nat_list" }, { "maptable" }, { "ipf_nattable_sz" }, { "ipf_natrules_sz" }, { "ipf_rdrrules_sz" }, /* 5 */ { "ipf_hostmap_sz" }, { "nat_instances" }, { NULL } }; void *tables[2]; if (nlist(kernel, nat_nlist) == -1) { fprintf(stderr, "nlist error\n"); return; } /* * Normally the ioctl copies all of these values into the structure * for us, before returning it to userland, so here we must copy each * one in individually. */ kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables)); nsp->ns_side[0].ns_table = tables[0]; nsp->ns_side[1].ns_table = tables[1]; kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value, sizeof(nsp->ns_list)); kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value, sizeof(nsp->ns_maptable)); kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value, sizeof(nsp->ns_nattab_sz)); kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value, sizeof(nsp->ns_rultab_sz)); kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value, sizeof(nsp->ns_rdrtab_sz)); kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value, sizeof(nsp->ns_hostmap_sz)); kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value, sizeof(nsp->ns_instances)); } /* * Issue an ioctl to flush either the NAT rules table or the active mapping * table or both. */ void flushtable(fd, opts, match) int fd, opts, *match; { int n = 0; if (opts & OPT_FLUSH) { n = 0; if (!(opts & OPT_DONOTHING)) { if (match != NULL) { ipfobj_t obj; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = match[0] * sizeof(int); obj.ipfo_type = IPFOBJ_IPFEXPR; obj.ipfo_ptr = match; if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) { ipferror(fd, "ioctl(SIOCMATCHFLUSH)"); n = -1; } else { n = obj.ipfo_retval; } } else if (ioctl(fd, SIOCIPFFL, &n) == -1) { ipferror(fd, "ioctl(SIOCIPFFL)"); n = -1; } } if (n >= 0) printf("%d entries flushed from NAT table\n", n); } if (opts & OPT_CLEAR) { n = 1; if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) ipferror(fd, "ioctl(SIOCCNATL)"); else printf("%d entries flushed from NAT list\n", n); } } /* * Display NAT statistics. */ void dostats_dead(nsp, opts, filter) natstat_t *nsp; int opts, *filter; { nat_t *np, nat; ipnat_t ipn; int i; if (nat_fields == NULL) { printf("List of active MAP/Redirect filters:\n"); while (nsp->ns_list) { if (kmemcpy((char *)&ipn, (long)nsp->ns_list, sizeof(ipn))) { perror("kmemcpy"); break; } if (opts & OPT_HITS) printf("%lu ", ipn.in_hits); printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); nsp->ns_list = ipn.in_next; } } if (nat_fields == NULL) { printf("\nList of active sessions:\n"); } else if (nohdrfields == 0) { for (i = 0; nat_fields[i].w_value != 0; i++) { printfieldhdr(natfields, nat_fields + i); if (nat_fields[i + 1].w_value != 0) printf("\t"); } printf("\n"); } for (np = nsp->ns_instances; np; np = nat.nat_next) { if (kmemcpy((char *)&nat, (long)np, sizeof(nat))) break; if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0)) continue; if (nat_fields != NULL) { for (i = 0; nat_fields[i].w_value != 0; i++) { printnatfield(&nat, nat_fields[i].w_value); if (nat_fields[i + 1].w_value != 0) printf("\t"); } printf("\n"); } else { printactivenat(&nat, opts, nsp->ns_ticks); if (nat.nat_aps) { int proto; if (nat.nat_dir & NAT_OUTBOUND) proto = nat.nat_pr[1]; else proto = nat.nat_pr[0]; printaps(nat.nat_aps, opts, proto); } } } if (opts & OPT_VERBOSE) showhostmap_dead(nsp); } void dotable(nsp, fd, alive, which, side) natstat_t *nsp; int fd, alive, which; char *side; { int sz, i, used, maxlen, minlen, totallen; ipftable_t table; u_int *buckets; ipfobj_t obj; sz = sizeof(*buckets) * nsp->ns_nattab_sz; buckets = (u_int *)malloc(sz); if (buckets == NULL) { fprintf(stderr, "cannot allocate memory (%d) for buckets\n", sz); return; } obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_GTABLE; obj.ipfo_size = sizeof(table); obj.ipfo_ptr = &table; if (which == 0) { table.ita_type = IPFTABLE_BUCKETS_NATIN; } else if (which == 1) { table.ita_type = IPFTABLE_BUCKETS_NATOUT; } table.ita_table = buckets; if (alive) { if (ioctl(fd, SIOCGTABL, &obj) != 0) { ipferror(fd, "SIOCFTABL"); free(buckets); return; } } else { if (kmemcpy((char *)buckets, (u_long)nsp->ns_nattab_sz, sz)) { free(buckets); return; } } minlen = nsp->ns_side[which].ns_inuse; totallen = 0; maxlen = 0; used = 0; for (i = 0; i < nsp->ns_nattab_sz; i++) { if (buckets[i] > maxlen) maxlen = buckets[i]; if (buckets[i] < minlen) minlen = buckets[i]; if (buckets[i] != 0) used++; totallen += buckets[i]; } printf("%d%%\thash efficiency %s\n", totallen ? used * 100 / totallen : 0, side); printf("%2.2f%%\tbucket usage %s\n", ((float)used / nsp->ns_nattab_sz) * 100.0, side); printf("%d\tminimal length %s\n", minlen, side); printf("%d\tmaximal length %s\n", maxlen, side); printf("%.3f\taverage length %s\n", used ? ((float)totallen / used) : 0.0, side); free(buckets); } void dostats(fd, nsp, opts, alive, filter) natstat_t *nsp; int fd, opts, alive, *filter; { /* * Show statistics ? */ if (opts & OPT_STAT) { printnatside("in", &nsp->ns_side[0]); dotable(nsp, fd, alive, 0, "in"); printnatside("out", &nsp->ns_side[1]); dotable(nsp, fd, alive, 1, "out"); printf("%lu\tlog successes\n", nsp->ns_side[0].ns_log); printf("%lu\tlog failures\n", nsp->ns_side[1].ns_log); printf("%lu\tadded in\n%lu\tadded out\n", nsp->ns_side[0].ns_added, nsp->ns_side[1].ns_added); printf("%u\tactive\n", nsp->ns_active); printf("%lu\ttransparent adds\n", nsp->ns_addtrpnt); printf("%lu\tdivert build\n", nsp->ns_divert_build); printf("%lu\texpired\n", nsp->ns_expire); printf("%lu\tflush all\n", nsp->ns_flush_all); printf("%lu\tflush closing\n", nsp->ns_flush_closing); printf("%lu\tflush queue\n", nsp->ns_flush_queue); printf("%lu\tflush state\n", nsp->ns_flush_state); printf("%lu\tflush timeout\n", nsp->ns_flush_timeout); printf("%lu\thostmap new\n", nsp->ns_hm_new); printf("%lu\thostmap fails\n", nsp->ns_hm_newfail); printf("%lu\thostmap add\n", nsp->ns_hm_addref); printf("%lu\thostmap NULL rule\n", nsp->ns_hm_nullnp); printf("%lu\tlog ok\n", nsp->ns_log_ok); printf("%lu\tlog fail\n", nsp->ns_log_fail); printf("%u\torphan count\n", nsp->ns_orphans); printf("%u\trule count\n", nsp->ns_rules); printf("%u\tmap rules\n", nsp->ns_rules_map); printf("%u\trdr rules\n", nsp->ns_rules_rdr); printf("%u\twilds\n", nsp->ns_wilds); if (opts & OPT_VERBOSE) printf("list %p\n", nsp->ns_list); } if (opts & OPT_LIST) { if (alive) dostats_live(fd, nsp, opts, filter); else dostats_dead(nsp, opts, filter); } } /* * Display NAT statistics. */ void dostats_live(fd, nsp, opts, filter) natstat_t *nsp; int fd, opts, *filter; { ipfgeniter_t iter; char buffer[2000]; ipfobj_t obj; ipnat_t *ipn; nat_t nat; int i; bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_GENITER; obj.ipfo_size = sizeof(iter); obj.ipfo_ptr = &iter; iter.igi_type = IPFGENITER_IPNAT; iter.igi_nitems = 1; iter.igi_data = buffer; ipn = (ipnat_t *)buffer; /* * Show list of NAT rules and NAT sessions ? */ if (nat_fields == NULL) { printf("List of active MAP/Redirect filters:\n"); while (nsp->ns_list) { if (ioctl(fd, SIOCGENITER, &obj) == -1) break; if (opts & OPT_HITS) printf("%lu ", ipn->in_hits); printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); nsp->ns_list = ipn->in_next; } } if (nat_fields == NULL) { printf("\nList of active sessions:\n"); } else if (nohdrfields == 0) { for (i = 0; nat_fields[i].w_value != 0; i++) { printfieldhdr(natfields, nat_fields + i); if (nat_fields[i + 1].w_value != 0) printf("\t"); } printf("\n"); } i = IPFGENITER_IPNAT; (void) ioctl(fd,SIOCIPFDELTOK, &i); iter.igi_type = IPFGENITER_NAT; iter.igi_nitems = 1; iter.igi_data = &nat; while (nsp->ns_instances != NULL) { if (ioctl(fd, SIOCGENITER, &obj) == -1) break; if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0)) continue; if (nat_fields != NULL) { for (i = 0; nat_fields[i].w_value != 0; i++) { printnatfield(&nat, nat_fields[i].w_value); if (nat_fields[i + 1].w_value != 0) printf("\t"); } printf("\n"); } else { printactivenat(&nat, opts, nsp->ns_ticks); if (nat.nat_aps) { int proto; if (nat.nat_dir & NAT_OUTBOUND) proto = nat.nat_pr[1]; else proto = nat.nat_pr[0]; printaps(nat.nat_aps, opts, proto); } } nsp->ns_instances = nat.nat_next; } if (opts & OPT_VERBOSE) showhostmap_live(fd, nsp); i = IPFGENITER_NAT; (void) ioctl(fd,SIOCIPFDELTOK, &i); } /* * Display the active host mapping table. */ void showhostmap_dead(nsp) natstat_t *nsp; { hostmap_t hm, *hmp, **maptable; u_int hv; printf("\nList of active host mappings:\n"); maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) * nsp->ns_hostmap_sz); if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable, sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) { perror("kmemcpy (maptable)"); return; } for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) { hmp = maptable[hv]; while (hmp) { if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) { perror("kmemcpy (hostmap)"); return; } printhostmap(&hm, hv); hmp = hm.hm_next; } } free(maptable); } /* * Display the active host mapping table. */ void showhostmap_live(fd, nsp) int fd; natstat_t *nsp; { ipfgeniter_t iter; hostmap_t hm; ipfobj_t obj; int i; bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_GENITER; obj.ipfo_size = sizeof(iter); obj.ipfo_ptr = &iter; iter.igi_type = IPFGENITER_HOSTMAP; iter.igi_nitems = 1; iter.igi_data = &hm; printf("\nList of active host mappings:\n"); while (nsp->ns_maplist != NULL) { if (ioctl(fd, SIOCGENITER, &obj) == -1) break; printhostmap(&hm, hm.hm_hv); nsp->ns_maplist = hm.hm_next; } i = IPFGENITER_HOSTMAP; (void) ioctl(fd,SIOCIPFDELTOK, &i); } int nat_matcharray(nat, array) nat_t *nat; int *array; { int i, n, *x, rv, p; ipfexp_t *e; rv = 0; n = array[0]; x = array + 1; for (; n > 0; x += 3 + x[3], rv = 0) { e = (ipfexp_t *)x; if (e->ipfe_cmd == IPF_EXP_END) break; n -= e->ipfe_size; p = e->ipfe_cmd >> 16; if ((p != 0) && (p != nat->nat_pr[1])) break; switch (e->ipfe_cmd) { case IPF_EXP_IP_PR : for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= (nat->nat_pr[1] == e->ipfe_arg0[i]); } break; case IPF_EXP_IP_SRCADDR : if (nat->nat_v[0] != 4) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= ((nat->nat_osrcaddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]) || ((nat->nat_nsrcaddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]); } break; case IPF_EXP_IP_DSTADDR : if (nat->nat_v[0] != 4) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= ((nat->nat_odstaddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]) || ((nat->nat_ndstaddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]); } break; case IPF_EXP_IP_ADDR : if (nat->nat_v[0] != 4) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= ((nat->nat_osrcaddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]) || ((nat->nat_nsrcaddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]) || ((nat->nat_odstaddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]) || ((nat->nat_ndstaddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]); } break; #ifdef USE_INET6 case IPF_EXP_IP6_SRCADDR : if (nat->nat_v[0] != 6) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= IP6_MASKEQ(&nat->nat_osrc6, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]) || IP6_MASKEQ(&nat->nat_nsrc6, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]); } break; case IPF_EXP_IP6_DSTADDR : if (nat->nat_v[0] != 6) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= IP6_MASKEQ(&nat->nat_odst6, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]) || IP6_MASKEQ(&nat->nat_ndst6, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]); } break; case IPF_EXP_IP6_ADDR : if (nat->nat_v[0] != 6) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= IP6_MASKEQ(&nat->nat_osrc6, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]) || IP6_MASKEQ(&nat->nat_nsrc6, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]) || IP6_MASKEQ(&nat->nat_odst6, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]) || IP6_MASKEQ(&nat->nat_ndst6, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]); } break; #endif case IPF_EXP_UDP_PORT : case IPF_EXP_TCP_PORT : for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= (nat->nat_osport == e->ipfe_arg0[i]) || (nat->nat_nsport == e->ipfe_arg0[i]) || (nat->nat_odport == e->ipfe_arg0[i]) || (nat->nat_ndport == e->ipfe_arg0[i]); } break; case IPF_EXP_UDP_SPORT : case IPF_EXP_TCP_SPORT : for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= (nat->nat_osport == e->ipfe_arg0[i]) || (nat->nat_nsport == e->ipfe_arg0[i]); } break; case IPF_EXP_UDP_DPORT : case IPF_EXP_TCP_DPORT : for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= (nat->nat_odport == e->ipfe_arg0[i]) || (nat->nat_ndport == e->ipfe_arg0[i]); } break; } rv ^= e->ipfe_not; if (rv == 0) break; } return rv; } diff --git a/contrib/ipfilter/tools/ipnat_y.y b/contrib/ipfilter/tools/ipnat_y.y index 8c23403b3e03..39e6a92bdf67 100644 --- a/contrib/ipfilter/tools/ipnat_y.y +++ b/contrib/ipfilter/tools/ipnat_y.y @@ -1,1785 +1,1782 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ %{ #ifdef __FreeBSD__ # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif #endif #include #include #include #include #include #if !defined(__SVR4) && !defined(__GNUC__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include -#if __FreeBSD_version >= 300000 -# include -#endif #include #include #include #include "ipf.h" #include "netinet/ipl.h" #include "ipnat_l.h" #define YYDEBUG 1 extern void yyerror __P((char *)); extern int yyparse __P((void)); extern int yylex __P((void)); extern int yydebug; extern FILE *yyin; extern int yylineNum; static ipnat_t *nattop = NULL; static ipnat_t *nat = NULL; static int natfd = -1; static ioctlfunc_t natioctlfunc = NULL; static addfunc_t nataddfunc = NULL; static int suggest_port = 0; static proxyrule_t *prules = NULL; static int parser_error = 0; static void newnatrule __P((void)); static void setnatproto __P((int)); static void setmapifnames __P((void)); static void setrdrifnames __P((void)); static void proxy_setconfig __P((int)); static void proxy_unsetconfig __P((void)); static namelist_t *proxy_dns_add_pass __P((char *, char *)); static namelist_t *proxy_dns_add_block __P((char *, char *)); static void proxy_addconfig __P((char *, int, char *, namelist_t *)); static void proxy_loadconfig __P((int, ioctlfunc_t, char *, int, char *, namelist_t *)); static void proxy_loadrules __P((int, ioctlfunc_t, proxyrule_t *)); static void setmapifnames __P((void)); static void setrdrifnames __P((void)); static void setifname __P((ipnat_t **, int, char *)); static int addname __P((ipnat_t **, char *)); %} %union { char *str; u_32_t num; struct { i6addr_t a; int f; } ipa; frentry_t fr; frtuc_t *frt; u_short port; struct { int p1; int p2; int pc; } pc; struct { i6addr_t a; i6addr_t m; int t; /* Address type */ int u; int f; /* Family */ int v; /* IP version */ int s; /* 0 = number, 1 = text */ int n; /* number */ } ipp; union i6addr ip6; namelist_t *names; }; %token YY_NUMBER YY_HEX %token YY_STR %token YY_COMMENT %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT %token YY_RANGE_OUT YY_RANGE_IN %token YY_IPV6 %token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE %token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY %token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY %token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG %token IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO %token IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT %token IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6 %token IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE %type portspec %type hexnumber compare range proto %type saddr daddr sobject dobject mapfrom rdrfrom dip %type hostname ipv4 ipaddr %type addr rhsaddr rhdaddr erhdaddr %type portstuff portpair comaports srcports dstports %type dnslines dnsline %% file: line | assign | file line | file assign | file pconf ';' ; line: xx rule { int err; while ((nat = nattop) != NULL) { if (nat->in_v[0] == 0) nat->in_v[0] = 4; if (nat->in_v[1] == 0) nat->in_v[1] = nat->in_v[0]; nattop = nat->in_next; err = (*nataddfunc)(natfd, natioctlfunc, nat); free(nat); if (err != 0) { parser_error = err; break; } } if (parser_error == 0 && prules != NULL) { proxy_loadrules(natfd, natioctlfunc, prules); prules = NULL; } resetlexer(); } | YY_COMMENT ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); yyvarnext = 0; } ; assigning: '=' { yyvarnext = 1; } ; xx: { newnatrule(); } ; rule: map eol | mapblock eol | redir eol | rewrite ';' | divert ';' ; no: IPNY_NO { nat->in_flags |= IPN_NO; } ; eol: | ';' ; map: mapit ifnames addr tlate rhsaddr proxy mapoptions { if ($3.f != 0 && $3.f != $5.f && $5.f != 0) yyerror("3.address family mismatch"); if (nat->in_v[0] == 0 && $5.v != 0) nat->in_v[0] = $5.v; else if (nat->in_v[0] == 0 && $3.v != 0) nat->in_v[0] = $3.v; if (nat->in_v[1] == 0 && $5.v != 0) nat->in_v[1] = $5.v; else if (nat->in_v[1] == 0 && $3.v != 0) nat->in_v[1] = $3.v; nat->in_osrcatype = $3.t; bcopy(&$3.a, &nat->in_osrc.na_addr[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_osrc.na_addr[1], sizeof($3.a)); nat->in_nsrcatype = $5.t; nat->in_nsrcafunc = $5.u; bcopy(&$5.a, &nat->in_nsrc.na_addr[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_nsrc.na_addr[1], sizeof($5.a)); setmapifnames(); } | mapit ifnames addr tlate rhsaddr mapport mapoptions { if ($3.f != $5.f && $3.f != 0 && $5.f != 0) yyerror("4.address family mismatch"); if (nat->in_v[1] == 0 && $5.v != 0) nat->in_v[1] = $5.v; else if (nat->in_v[0] == 0 && $3.v != 0) nat->in_v[0] = $3.v; if (nat->in_v[0] == 0 && $5.v != 0) nat->in_v[0] = $5.v; else if (nat->in_v[1] == 0 && $3.v != 0) nat->in_v[1] = $3.v; nat->in_osrcatype = $3.t; bcopy(&$3.a, &nat->in_osrc.na_addr[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_osrc.na_addr[1], sizeof($3.a)); nat->in_nsrcatype = $5.t; nat->in_nsrcafunc = $5.u; bcopy(&$5.a, &nat->in_nsrc.na_addr[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_nsrc.na_addr[1], sizeof($5.a)); setmapifnames(); } | no mapit ifnames addr setproto ';' { if (nat->in_v[0] == 0) nat->in_v[0] = $4.v; nat->in_osrcatype = $4.t; bcopy(&$4.a, &nat->in_osrc.na_addr[0], sizeof($4.a)); bcopy(&$4.m, &nat->in_osrc.na_addr[1], sizeof($4.a)); setmapifnames(); } | mapit ifnames mapfrom tlate rhsaddr proxy mapoptions { if ($3 != 0 && $5.f != 0 && $3 != $5.f) yyerror("5.address family mismatch"); if (nat->in_v[0] == 0 && $5.v != 0) nat->in_v[0] = $5.v; else if (nat->in_v[0] == 0 && $3 != 0) nat->in_v[0] = ftov($3); if (nat->in_v[1] == 0 && $5.v != 0) nat->in_v[1] = $5.v; else if (nat->in_v[1] == 0 && $3 != 0) nat->in_v[1] = ftov($3); nat->in_nsrcatype = $5.t; nat->in_nsrcafunc = $5.u; bcopy(&$5.a, &nat->in_nsrc.na_addr[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_nsrc.na_addr[1], sizeof($5.a)); setmapifnames(); } | no mapit ifnames mapfrom setproto ';' { nat->in_v[0] = ftov($4); setmapifnames(); } | mapit ifnames mapfrom tlate rhsaddr mapport mapoptions { if ($3 != 0 && $5.f != 0 && $3 != $5.f) yyerror("6.address family mismatch"); if (nat->in_v[0] == 0 && $5.v != 0) nat->in_v[0] = $5.v; else if (nat->in_v[0] == 0 && $3 != 0) nat->in_v[0] = ftov($3); if (nat->in_v[1] == 0 && $5.v != 0) nat->in_v[1] = $5.v; else if (nat->in_v[1] == 0 && $3 != 0) nat->in_v[1] = ftov($3); nat->in_nsrcatype = $5.t; nat->in_nsrcafunc = $5.u; bcopy(&$5.a, &nat->in_nsrc.na_addr[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_nsrc.na_addr[1], sizeof($5.a)); setmapifnames(); } ; mapblock: mapblockit ifnames addr tlate addr ports mapoptions { if ($3.f != 0 && $5.f != 0 && $3.f != $5.f) yyerror("7.address family mismatch"); if (nat->in_v[0] == 0 && $5.v != 0) nat->in_v[0] = $5.v; else if (nat->in_v[0] == 0 && $3.v != 0) nat->in_v[0] = $3.v; if (nat->in_v[1] == 0 && $5.v != 0) nat->in_v[1] = $5.v; else if (nat->in_v[1] == 0 && $3.v != 0) nat->in_v[1] = $3.v; nat->in_osrcatype = $3.t; bcopy(&$3.a, &nat->in_osrc.na_addr[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_osrc.na_addr[1], sizeof($3.a)); nat->in_nsrcatype = $5.t; nat->in_nsrcafunc = $5.u; bcopy(&$5.a, &nat->in_nsrc.na_addr[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_nsrc.na_addr[1], sizeof($5.a)); setmapifnames(); } | no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';' { if (nat->in_v[0] == 0) nat->in_v[0] = $5.v; if (nat->in_v[1] == 0) nat->in_v[1] = $5.v; nat->in_osrcatype = $5.t; bcopy(&$5.a, &nat->in_osrc.na_addr[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_osrc.na_addr[1], sizeof($5.a)); setmapifnames(); } ; redir: rdrit ifnames addr dport tlate dip nport setproto rdroptions { if ($6 != 0 && $3.f != 0 && $6 != $3.f) yyerror("21.address family mismatch"); if (nat->in_v[0] == 0) { if ($3.v != AF_UNSPEC) nat->in_v[0] = ftov($3.f); else nat->in_v[0] = ftov($6); } nat->in_odstatype = $3.t; bcopy(&$3.a, &nat->in_odst.na_addr[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_odst.na_addr[1], sizeof($3.a)); setrdrifnames(); } | no rdrit ifnames addr dport setproto ';' { if (nat->in_v[0] == 0) nat->in_v[0] = ftov($4.f); nat->in_odstatype = $4.t; bcopy(&$4.a, &nat->in_odst.na_addr[0], sizeof($4.a)); bcopy(&$4.m, &nat->in_odst.na_addr[1], sizeof($4.a)); setrdrifnames(); } | rdrit ifnames rdrfrom tlate dip nport setproto rdroptions { if ($5 != 0 && $3 != 0 && $5 != $3) yyerror("20.address family mismatch"); if (nat->in_v[0] == 0) { if ($3 != AF_UNSPEC) nat->in_v[0] = ftov($3); else nat->in_v[0] = ftov($5); } setrdrifnames(); } | no rdrit ifnames rdrfrom setproto ';' { nat->in_v[0] = ftov($4); setrdrifnames(); } ; rewrite: IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts { if (nat->in_v[0] == 0) nat->in_v[0] = ftov($4); if (nat->in_redir & NAT_MAP) setmapifnames(); else setrdrifnames(); nat->in_redir |= NAT_REWRITE; } ; divert: IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts { if (nat->in_v[0] == 0) nat->in_v[0] = ftov($4); if (nat->in_redir & NAT_MAP) { setmapifnames(); nat->in_pr[0] = IPPROTO_UDP; } else { setrdrifnames(); nat->in_pr[1] = IPPROTO_UDP; } nat->in_flags &= ~IPN_TCP; } ; tlate: IPNY_TLATE { yyexpectaddr = 1; } ; pconf: IPNY_PROXY { yysetdict(proxies); } IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{' { proxy_setconfig(IPNY_DNS); } dnslines ';' '}' { proxy_addconfig("dns", $5, $7, $10); proxy_unsetconfig(); } ; dnslines: dnsline { $$ = $1; } | dnslines ';' dnsline { $$ = $1; $1->na_next = $3; } ; dnsline: IPNY_ALLOW YY_STR { $$ = proxy_dns_add_pass(NULL, $2); } | IPNY_DENY YY_STR { $$ = proxy_dns_add_block(NULL, $2); } | IPNY_ALLOW '.' YY_STR { $$ = proxy_dns_add_pass(".", $3); } | IPNY_DENY '.' YY_STR { $$ = proxy_dns_add_block(".", $3); } ; oninout: inout IPNY_ON ifnames { ; } ; inout: IPNY_IN { nat->in_redir = NAT_REDIRECT; } | IPNY_OUT { nat->in_redir = NAT_MAP; } ; rwrproto: | IPNY_PROTO setproto ; newdst: src rhsaddr srcports dst erhdaddr dstports { nat->in_nsrc.na_addr[0] = $2.a; nat->in_nsrc.na_addr[1] = $2.m; nat->in_nsrc.na_atype = $2.t; if ($2.t == FRI_LOOKUP) { nat->in_nsrc.na_type = $2.u; nat->in_nsrc.na_subtype = $2.s; nat->in_nsrc.na_num = $2.n; } nat->in_nsports[0] = $3.p1; nat->in_nsports[1] = $3.p2; nat->in_ndst.na_addr[0] = $5.a; nat->in_ndst.na_addr[1] = $5.m; nat->in_ndst.na_atype = $5.t; if ($5.t == FRI_LOOKUP) { nat->in_ndst.na_type = $5.u; nat->in_ndst.na_subtype = $5.s; nat->in_ndst.na_num = $5.n; } nat->in_ndports[0] = $6.p1; nat->in_ndports[1] = $6.p2; } ; divdst: src addr ',' portspec dst addr ',' portspec IPNY_UDP { nat->in_nsrc.na_addr[0] = $2.a; if ($2.m.in4.s_addr != 0xffffffff) yyerror("divert must have /32 dest"); nat->in_nsrc.na_addr[1] = $2.m; nat->in_nsports[0] = $4; nat->in_nsports[1] = $4; nat->in_ndst.na_addr[0] = $6.a; nat->in_ndst.na_addr[1] = $6.m; if ($6.m.in4.s_addr != 0xffffffff) yyerror("divert must have /32 dest"); nat->in_ndports[0] = $8; nat->in_ndports[1] = $8; nat->in_redir |= NAT_DIVERTUDP; } ; src: IPNY_SRC { yyexpectaddr = 1; } ; dst: IPNY_DST { yyexpectaddr = 1; } ; srcports: comaports { $$.p1 = $1.p1; $$.p2 = $1.p2; } | IPNY_PORT '=' portspec { $$.p1 = $3; $$.p2 = $3; nat->in_flags |= IPN_FIXEDSPORT; } ; dstports: comaports { $$.p1 = $1.p1; $$.p2 = $1.p2; } | IPNY_PORT '=' portspec { $$.p1 = $3; $$.p2 = $3; nat->in_flags |= IPN_FIXEDDPORT; } ; comaports: { $$.p1 = 0; $$.p2 = 0; } | ',' { if (!(nat->in_flags & IPN_TCPUDP)) yyerror("must be TCP/UDP for ports"); } portpair { $$.p1 = $3.p1; $$.p2 = $3.p2; } ; proxy: | IPNY_PROXY port portspec YY_STR '/' proto { int pos; pos = addname(&nat, $4); nat->in_plabel = pos; if (nat->in_dcmp == 0) { nat->in_odport = $3; } else if ($3 != nat->in_odport) { yyerror("proxy port numbers not consistant"); } nat->in_ndport = $3; setnatproto($6); free($4); } | IPNY_PROXY port YY_STR YY_STR '/' proto { int pnum, pos; pos = addname(&nat, $4); nat->in_plabel = pos; pnum = getportproto($3, $6); if (pnum == -1) yyerror("invalid port number"); nat->in_odport = ntohs(pnum); nat->in_ndport = ntohs(pnum); setnatproto($6); free($3); free($4); } | IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR { int pos; pos = addname(&nat, $4); nat->in_plabel = pos; if (nat->in_dcmp == 0) { nat->in_odport = $3; } else if ($3 != nat->in_odport) { yyerror("proxy port numbers not consistant"); } nat->in_ndport = $3; setnatproto($6); nat->in_pconfig = addname(&nat, $8); free($4); free($8); } | IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR { int pnum, pos; pos = addname(&nat, $4); nat->in_plabel = pos; pnum = getportproto($3, $6); if (pnum == -1) yyerror("invalid port number"); nat->in_odport = ntohs(pnum); nat->in_ndport = ntohs(pnum); setnatproto($6); pos = addname(&nat, $8); nat->in_pconfig = pos; free($3); free($4); free($8); } ; setproto: | proto { if (nat->in_pr[0] != 0 || nat->in_pr[1] != 0 || nat->in_flags & IPN_TCPUDP) yyerror("protocol set twice"); setnatproto($1); } | IPNY_TCPUDP { if (nat->in_pr[0] != 0 || nat->in_pr[1] != 0 || nat->in_flags & IPN_TCPUDP) yyerror("protocol set twice"); nat->in_flags |= IPN_TCPUDP; nat->in_pr[0] = 0; nat->in_pr[1] = 0; } | IPNY_TCP '/' IPNY_UDP { if (nat->in_pr[0] != 0 || nat->in_pr[1] != 0 || nat->in_flags & IPN_TCPUDP) yyerror("protocol set twice"); nat->in_flags |= IPN_TCPUDP; nat->in_pr[0] = 0; nat->in_pr[1] = 0; } ; rhsaddr: addr { $$ = $1; yyexpectaddr = 0; } | hostname '-' { yyexpectaddr = 1; } hostname { $$.t = FRI_RANGE; if ($1.f != $4.f) yyerror("8.address family " "mismatch"); $$.f = $1.f; $$.v = ftov($1.f); $$.a = $1.a; $$.m = $4.a; nat->in_flags |= IPN_SIPRANGE; yyexpectaddr = 0; } | IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname { $$.t = FRI_RANGE; if ($2.f != $5.f) yyerror("9.address family " "mismatch"); $$.f = $2.f; $$.v = ftov($2.f); $$.a = $2.a; $$.m = $5.a; nat->in_flags |= IPN_SIPRANGE; yyexpectaddr = 0; } ; dip: hostname ',' { yyexpectaddr = 1; } hostname { nat->in_flags |= IPN_SPLIT; if ($1.f != $4.f) yyerror("10.address family " "mismatch"); $$ = $1.f; nat->in_ndstip6 = $1.a; nat->in_ndstmsk6 = $4.a; nat->in_ndstatype = FRI_SPLIT; yyexpectaddr = 0; } | rhdaddr { int bits; nat->in_ndstip6 = $1.a; nat->in_ndstmsk6 = $1.m; nat->in_ndst.na_atype = $1.t; yyexpectaddr = 0; if ($1.f == AF_INET) bits = count4bits($1.m.in4.s_addr); else bits = count6bits($1.m.i6); if (($1.f == AF_INET) && (bits != 0) && (bits != 32)) { yyerror("dest ip bitmask not /32"); } else if (($1.f == AF_INET6) && (bits != 0) && (bits != 128)) { yyerror("dest ip bitmask not /128"); } $$ = $1.f; } ; rhdaddr: addr { $$ = $1; yyexpectaddr = 0; } | hostname '-' hostname { bzero(&$$, sizeof($$)); $$.t = FRI_RANGE; if ($1.f != 0 && $3.f != 0 && $1.f != $3.f) yyerror("11.address family " "mismatch"); $$.a = $1.a; $$.m = $3.a; nat->in_flags |= IPN_DIPRANGE; yyexpectaddr = 0; } | IPNY_RANGE hostname '-' hostname { bzero(&$$, sizeof($$)); $$.t = FRI_RANGE; if ($2.f != 0 && $4.f != 0 && $2.f != $4.f) yyerror("12.address family " "mismatch"); $$.a = $2.a; $$.m = $4.a; nat->in_flags |= IPN_DIPRANGE; yyexpectaddr = 0; } ; erhdaddr: rhdaddr { $$ = $1; } | IPNY_DSTLIST '/' YY_NUMBER { $$.t = FRI_LOOKUP; $$.u = IPLT_DSTLIST; $$.s = 0; $$.n = $3; } | IPNY_DSTLIST '/' YY_STR { $$.t = FRI_LOOKUP; $$.u = IPLT_DSTLIST; $$.s = 1; $$.n = addname(&nat, $3); } ; port: IPNY_PORT { suggest_port = 1; } ; portspec: YY_NUMBER { if ($1 > 65535) /* Unsigned */ yyerror("invalid port number"); else $$ = $1; } | YY_STR { if (getport(NULL, $1, &($$), NULL) == -1) yyerror("invalid port number"); $$ = ntohs($$); } ; portpair: portspec { $$.p1 = $1; $$.p2 = $1; } | portspec '-' portspec { $$.p1 = $1; $$.p2 = $3; } | portspec ':' portspec { $$.p1 = $1; $$.p2 = $3; } ; dport: | port portpair { nat->in_odport = $2.p1; if ($2.p2 == 0) nat->in_dtop = $2.p1; else nat->in_dtop = $2.p2; } ; nport: | port portpair { nat->in_dpmin = $2.p1; nat->in_dpnext = $2.p1; nat->in_dpmax = $2.p2; nat->in_ndport = $2.p1; if (nat->in_dtop == 0) nat->in_dtop = $2.p2; } | port '=' portspec { nat->in_dpmin = $3; nat->in_dpnext = $3; nat->in_ndport = $3; if (nat->in_dtop == 0) nat->in_dtop = nat->in_odport; nat->in_flags |= IPN_FIXEDDPORT; } ; ports: | IPNY_PORTS YY_NUMBER { nat->in_spmin = $2; } | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; } ; mapit: IPNY_MAP { nat->in_redir = NAT_MAP; } | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; } ; rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; } ; mapblockit: IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; } ; mapfrom: from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4) yyerror("13.address family " "mismatch"); $$ = $2; } | from sobject '!' to dobject { if ($2 != 0 && $5 != 0 && $2 != $5) yyerror("14.address family " "mismatch"); nat->in_flags |= IPN_NOTDST; $$ = $2; } | from sobject to '!' dobject { if ($2 != 0 && $5 != 0 && $2 != $5) yyerror("15.address family " "mismatch"); nat->in_flags |= IPN_NOTDST; $$ = $2; } ; rdrfrom: from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4) yyerror("16.address family " "mismatch"); $$ = $2; } | '!' from sobject to dobject { if ($3 != 0 && $5 != 0 && $3 != $5) yyerror("17.address family " "mismatch"); nat->in_flags |= IPN_NOTSRC; $$ = $3; } | from '!' sobject to dobject { if ($3 != 0 && $5 != 0 && $3 != $5) yyerror("18.address family " "mismatch"); nat->in_flags |= IPN_NOTSRC; $$ = $3; } ; from: IPNY_FROM { nat->in_flags |= IPN_FILTER; yyexpectaddr = 1; } ; to: IPNY_TO { yyexpectaddr = 1; } ; ifnames: ifname family { yyexpectaddr = 1; } | ifname ',' otherifname family { yyexpectaddr = 1; } ; ifname: YY_STR { setifname(&nat, 0, $1); free($1); } ; family: | IPNY_INET { nat->in_v[0] = 4; nat->in_v[1] = 4; } | IPNY_INET6 { nat->in_v[0] = 6; nat->in_v[1] = 6; } ; otherifname: YY_STR { setifname(&nat, 1, $1); free($1); } ; mapport: IPNY_PORTMAP tcpudp portpair sequential { nat->in_spmin = $3.p1; nat->in_spmax = $3.p2; } | IPNY_PORTMAP portpair tcpudp sequential { nat->in_spmin = $2.p1; nat->in_spmax = $2.p2; } | IPNY_PORTMAP tcpudp IPNY_AUTO sequential { nat->in_flags |= IPN_AUTOPORTMAP; nat->in_spmin = 1024; nat->in_spmax = 65535; } | IPNY_ICMPIDMAP YY_STR portpair sequential { if (strcmp($2, "icmp") != 0 && strcmp($2, "ipv6-icmp") != 0) { yyerror("icmpidmap not followed by icmp"); } free($2); if ($3.p1 < 0 || $3.p1 > 65535) yyerror("invalid 1st ICMP Id number"); if ($3.p2 < 0 || $3.p2 > 65535) yyerror("invalid 2nd ICMP Id number"); if (strcmp($2, "ipv6-icmp") == 0) { nat->in_pr[0] = IPPROTO_ICMPV6; nat->in_pr[1] = IPPROTO_ICMPV6; } else { nat->in_pr[0] = IPPROTO_ICMP; nat->in_pr[1] = IPPROTO_ICMP; } nat->in_flags = IPN_ICMPQUERY; nat->in_spmin = $3.p1; nat->in_spmax = $3.p2; } ; sobject: saddr { $$ = $1; } | saddr port portstuff { nat->in_osport = $3.p1; nat->in_stop = $3.p2; nat->in_scmp = $3.pc; $$ = $1; } ; saddr: addr { nat->in_osrcatype = $1.t; bcopy(&$1.a, &nat->in_osrc.na_addr[0], sizeof($1.a)); bcopy(&$1.m, &nat->in_osrc.na_addr[1], sizeof($1.m)); $$ = $1.f; } ; dobject: daddr { $$ = $1; } | daddr port portstuff { nat->in_odport = $3.p1; nat->in_dtop = $3.p2; nat->in_dcmp = $3.pc; $$ = $1; } ; daddr: addr { nat->in_odstatype = $1.t; bcopy(&$1.a, &nat->in_odst.na_addr[0], sizeof($1.a)); bcopy(&$1.m, &nat->in_odst.na_addr[1], sizeof($1.m)); $$ = $1.f; } ; addr: IPNY_ANY { yyexpectaddr = 0; bzero(&$$, sizeof($$)); $$.t = FRI_NORMAL; } | hostname { bzero(&$$, sizeof($$)); $$.a = $1.a; $$.t = FRI_NORMAL; $$.v = ftov($1.f); $$.f = $1.f; if ($$.f == AF_INET) { $$.m.in4.s_addr = 0xffffffff; } else if ($$.f == AF_INET6) { $$.m.i6[0] = 0xffffffff; $$.m.i6[1] = 0xffffffff; $$.m.i6[2] = 0xffffffff; $$.m.i6[3] = 0xffffffff; } yyexpectaddr = 0; } | hostname slash YY_NUMBER { bzero(&$$, sizeof($$)); $$.a = $1.a; $$.f = $1.f; $$.v = ftov($1.f); $$.t = FRI_NORMAL; ntomask($$.f, $3, (u_32_t *)&$$.m); $$.a.i6[0] &= $$.m.i6[0]; $$.a.i6[1] &= $$.m.i6[1]; $$.a.i6[2] &= $$.m.i6[2]; $$.a.i6[3] &= $$.m.i6[3]; yyexpectaddr = 0; } | hostname slash ipaddr { bzero(&$$, sizeof($$)); if ($1.f != $3.f) { yyerror("1.address family " "mismatch"); } $$.a = $1.a; $$.m = $3.a; $$.t = FRI_NORMAL; $$.a.i6[0] &= $$.m.i6[0]; $$.a.i6[1] &= $$.m.i6[1]; $$.a.i6[2] &= $$.m.i6[2]; $$.a.i6[3] &= $$.m.i6[3]; $$.f = $1.f; $$.v = ftov($1.f); yyexpectaddr = 0; } | hostname slash hexnumber { bzero(&$$, sizeof($$)); $$.a = $1.a; $$.m.in4.s_addr = htonl($3); $$.t = FRI_NORMAL; $$.a.in4.s_addr &= $$.m.in4.s_addr; $$.f = $1.f; $$.v = ftov($1.f); if ($$.f == AF_INET6) yyerror("incorrect inet6 mask"); } | hostname mask ipaddr { bzero(&$$, sizeof($$)); if ($1.f != $3.f) { yyerror("2.address family " "mismatch"); } $$.a = $1.a; $$.m = $3.a; $$.t = FRI_NORMAL; $$.a.i6[0] &= $$.m.i6[0]; $$.a.i6[1] &= $$.m.i6[1]; $$.a.i6[2] &= $$.m.i6[2]; $$.a.i6[3] &= $$.m.i6[3]; $$.f = $1.f; $$.v = ftov($1.f); yyexpectaddr = 0; } | hostname mask hexnumber { bzero(&$$, sizeof($$)); $$.a = $1.a; $$.m.in4.s_addr = htonl($3); $$.t = FRI_NORMAL; $$.a.in4.s_addr &= $$.m.in4.s_addr; $$.f = AF_INET; $$.v = 4; } | pool slash YY_NUMBER { bzero(&$$, sizeof($$)); $$.a.iplookupnum = $3; $$.a.iplookuptype = IPLT_POOL; $$.a.iplookupsubtype = 0; $$.t = FRI_LOOKUP; } | pool slash YY_STR { bzero(&$$, sizeof($$)); $$.a.iplookupname = addname(&nat,$3); $$.a.iplookuptype = IPLT_POOL; $$.a.iplookupsubtype = 1; $$.t = FRI_LOOKUP; } | hash slash YY_NUMBER { bzero(&$$, sizeof($$)); $$.a.iplookupnum = $3; $$.a.iplookuptype = IPLT_HASH; $$.a.iplookupsubtype = 0; $$.t = FRI_LOOKUP; } | hash slash YY_STR { bzero(&$$, sizeof($$)); $$.a.iplookupname = addname(&nat,$3); $$.a.iplookuptype = IPLT_HASH; $$.a.iplookupsubtype = 1; $$.t = FRI_LOOKUP; } ; slash: '/' { yyexpectaddr = 0; } ; mask: IPNY_MASK { yyexpectaddr = 0; } ; pool: IPNY_POOL { if (!(nat->in_flags & IPN_FILTER)) { yyerror("Can only use pool with from/to rules\n"); } yyexpectaddr = 0; yyresetdict(); } ; hash: IPNY_HASH { if (!(nat->in_flags & IPN_FILTER)) { yyerror("Can only use hash with from/to rules\n"); } yyexpectaddr = 0; yyresetdict(); } ; portstuff: compare portspec { $$.pc = $1; $$.p1 = $2; $$.p2 = 0; } | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; } ; mapoptions: rr frag age mssclamp nattag setproto purge ; rdroptions: rr frag age sticky mssclamp rdrproxy nattag purge ; nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2, sizeof(nat->in_tag.ipt_tag)); } rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; } ; frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; } ; age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2; nat->in_age[1] = $2; } | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2; nat->in_age[1] = $4; } ; sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) && !(nat->in_flags & IPN_SPLIT)) { FPRINTF(stderr, "'sticky' for use with round-robin/IP splitting only\n"); } else nat->in_flags |= IPN_STICKY; } ; mssclamp: | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; } ; tcpudp: IPNY_TCP { setnatproto(IPPROTO_TCP); } | IPNY_UDP { setnatproto(IPPROTO_UDP); } | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP; nat->in_pr[0] = 0; nat->in_pr[1] = 0; } | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP; nat->in_pr[0] = 0; nat->in_pr[1] = 0; } ; sequential: | IPNY_SEQUENTIAL { nat->in_flags |= IPN_SEQUENTIAL; } ; purge: | IPNY_PURGE { nat->in_flags |= IPN_PURGE; } ; rdrproxy: IPNY_PROXY YY_STR { int pos; pos = addname(&nat, $2); nat->in_plabel = pos; nat->in_odport = nat->in_dpnext; nat->in_dtop = nat->in_odport; free($2); } | proxy { if (nat->in_plabel != -1) { nat->in_ndport = nat->in_odport; nat->in_dpmin = nat->in_odport; nat->in_dpmax = nat->in_dpmin; nat->in_dtop = nat->in_dpmin; nat->in_dpnext = nat->in_dpmin; } } ; newopts: | IPNY_PURGE { nat->in_flags |= IPN_PURGE; } ; proto: YY_NUMBER { $$ = $1; if ($$ != IPPROTO_TCP && $$ != IPPROTO_UDP) suggest_port = 0; } | IPNY_TCP { $$ = IPPROTO_TCP; } | IPNY_UDP { $$ = IPPROTO_UDP; } | YY_STR { $$ = getproto($1); free($1); if ($$ == -1) yyerror("unknown protocol"); if ($$ != IPPROTO_TCP && $$ != IPPROTO_UDP) suggest_port = 0; } ; hexnumber: YY_HEX { $$ = $1; } ; hostname: YY_STR { i6addr_t addr; int family; #ifdef USE_INET6 if (nat->in_v[0] == 6) family = AF_INET6; else #endif family = AF_INET; memset(&($$), 0, sizeof($$)); memset(&addr, 0, sizeof(addr)); $$.f = family; if (gethost(family, $1, &addr) == 0) { $$.a = addr; } else { FPRINTF(stderr, "Unknown host '%s'\n", $1); } free($1); } | YY_NUMBER { memset(&($$), 0, sizeof($$)); $$.a.in4.s_addr = htonl($1); if ($$.a.in4.s_addr != 0) $$.f = AF_INET; } | ipv4 { $$ = $1; } | YY_IPV6 { memset(&($$), 0, sizeof($$)); $$.a = $1; $$.f = AF_INET6; } | YY_NUMBER YY_IPV6 { memset(&($$), 0, sizeof($$)); $$.a = $2; $$.f = AF_INET6; } ; compare: '=' { $$ = FR_EQUAL; } | YY_CMP_EQ { $$ = FR_EQUAL; } | YY_CMP_NE { $$ = FR_NEQUAL; } | YY_CMP_LT { $$ = FR_LESST; } | YY_CMP_LE { $$ = FR_LESSTE; } | YY_CMP_GT { $$ = FR_GREATERT; } | YY_CMP_GE { $$ = FR_GREATERTE; } range: YY_RANGE_OUT { $$ = FR_OUTRANGE; } | YY_RANGE_IN { $$ = FR_INRANGE; } | ':' { $$ = FR_INCRANGE; } ; ipaddr: ipv4 { $$ = $1; } | YY_IPV6 { $$.a = $1; $$.f = AF_INET6; } ; ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { yyerror("Invalid octet string for IP address"); return 0; } bzero((char *)&$$, sizeof($$)); $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; $$.a.in4.s_addr = htonl($$.a.in4.s_addr); $$.f = AF_INET; } ; %% static wordtab_t proxies[] = { { "dns", IPNY_DNS } }; static wordtab_t dnswords[] = { { "allow", IPNY_ALLOW }, { "block", IPNY_DENY }, { "deny", IPNY_DENY }, { "drop", IPNY_DENY }, { "pass", IPNY_ALLOW }, }; static wordtab_t yywords[] = { { "age", IPNY_AGE }, { "any", IPNY_ANY }, { "auto", IPNY_AUTO }, { "bimap", IPNY_BIMAP }, { "config", IPNY_CONFIG }, { "divert", IPNY_DIVERT }, { "dst", IPNY_DST }, { "dstlist", IPNY_DSTLIST }, { "frag", IPNY_FRAG }, { "from", IPNY_FROM }, { "hash", IPNY_HASH }, { "icmpidmap", IPNY_ICMPIDMAP }, { "in", IPNY_IN }, { "inet", IPNY_INET }, { "inet6", IPNY_INET6 }, { "mask", IPNY_MASK }, { "map", IPNY_MAP }, { "map-block", IPNY_MAPBLOCK }, { "mssclamp", IPNY_MSSCLAMP }, { "netmask", IPNY_MASK }, { "no", IPNY_NO }, { "on", IPNY_ON }, { "out", IPNY_OUT }, { "pool", IPNY_POOL }, { "port", IPNY_PORT }, { "portmap", IPNY_PORTMAP }, { "ports", IPNY_PORTS }, { "proto", IPNY_PROTO }, { "proxy", IPNY_PROXY }, { "purge", IPNY_PURGE }, { "range", IPNY_RANGE }, { "rewrite", IPNY_REWRITE }, { "rdr", IPNY_RDR }, { "round-robin",IPNY_ROUNDROBIN }, { "sequential", IPNY_SEQUENTIAL }, { "src", IPNY_SRC }, { "sticky", IPNY_STICKY }, { "tag", IPNY_TAG }, { "tcp", IPNY_TCP }, { "tcpudp", IPNY_TCPUDP }, { "to", IPNY_TO }, { "udp", IPNY_UDP }, { "-", '-' }, { "->", IPNY_TLATE }, { "eq", YY_CMP_EQ }, { "ne", YY_CMP_NE }, { "lt", YY_CMP_LT }, { "gt", YY_CMP_GT }, { "le", YY_CMP_LE }, { "ge", YY_CMP_GE }, { NULL, 0 } }; int ipnat_parsefile(fd, addfunc, ioctlfunc, filename) int fd; addfunc_t addfunc; ioctlfunc_t ioctlfunc; char *filename; { FILE *fp = NULL; int rval; char *s; yylineNum = 1; (void) yysettab(yywords); s = getenv("YYDEBUG"); if (s) yydebug = atoi(s); else yydebug = 0; if (strcmp(filename, "-")) { fp = fopen(filename, "r"); if (!fp) { FPRINTF(stderr, "fopen(%s) failed: %s\n", filename, STRERROR(errno)); return -1; } } else fp = stdin; while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0) ; if (fp != NULL) fclose(fp); if (rval == -1) rval = 0; else if (rval != 0) rval = 1; return rval; } int ipnat_parsesome(fd, addfunc, ioctlfunc, fp) int fd; addfunc_t addfunc; ioctlfunc_t ioctlfunc; FILE *fp; { char *s; int i; natfd = fd; parser_error = 0; nataddfunc = addfunc; natioctlfunc = ioctlfunc; if (feof(fp)) return -1; i = fgetc(fp); if (i == EOF) return -1; if (ungetc(i, fp) == EOF) return -1; if (feof(fp)) return -1; s = getenv("YYDEBUG"); if (s) yydebug = atoi(s); else yydebug = 0; yyin = fp; yyparse(); return parser_error; } static void newnatrule() { ipnat_t *n; n = calloc(1, sizeof(*n)); if (n == NULL) return; if (nat == NULL) { nattop = nat = n; n->in_pnext = &nattop; } else { nat->in_next = n; n->in_pnext = &nat->in_next; nat = n; } n->in_flineno = yylineNum; n->in_ifnames[0] = -1; n->in_ifnames[1] = -1; n->in_plabel = -1; n->in_pconfig = -1; n->in_size = sizeof(*n); suggest_port = 0; } static void setnatproto(p) int p; { nat->in_pr[0] = p; nat->in_pr[1] = p; switch (p) { case IPPROTO_TCP : nat->in_flags |= IPN_TCP; nat->in_flags &= ~IPN_UDP; break; case IPPROTO_UDP : nat->in_flags |= IPN_UDP; nat->in_flags &= ~IPN_TCP; break; #ifdef USE_INET6 case IPPROTO_ICMPV6 : #endif case IPPROTO_ICMP : nat->in_flags &= ~IPN_TCPUDP; if (!(nat->in_flags & IPN_ICMPQUERY) && !(nat->in_redir & NAT_DIVERTUDP)) { nat->in_dcmp = 0; nat->in_scmp = 0; nat->in_dpmin = 0; nat->in_dpmax = 0; nat->in_dpnext = 0; nat->in_spmin = 0; nat->in_spmax = 0; nat->in_spnext = 0; } break; default : if ((nat->in_redir & NAT_MAPBLK) == 0) { nat->in_flags &= ~IPN_TCPUDP; nat->in_dcmp = 0; nat->in_scmp = 0; nat->in_dpmin = 0; nat->in_dpmax = 0; nat->in_dpnext = 0; nat->in_spmin = 0; nat->in_spmax = 0; nat->in_spnext = 0; } break; } if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) { nat->in_stop = 0; nat->in_dtop = 0; nat->in_osport = 0; nat->in_odport = 0; nat->in_stop = 0; nat->in_osport = 0; nat->in_dtop = 0; nat->in_odport = 0; } if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT) nat->in_flags &= ~IPN_FIXEDDPORT; } int ipnat_addrule(fd, ioctlfunc, ptr) int fd; ioctlfunc_t ioctlfunc; void *ptr; { ioctlcmd_t add, del; ipfobj_t obj; ipnat_t *ipn; ipn = ptr; bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = ipn->in_size; obj.ipfo_type = IPFOBJ_IPNAT; obj.ipfo_ptr = ptr; if ((opts & OPT_DONOTHING) != 0) fd = -1; if (opts & OPT_ZERORULEST) { add = SIOCZRLST; del = 0; } else if (opts & OPT_PURGE) { add = 0; del = SIOCPURGENAT; } else { add = SIOCADNAT; del = SIOCRMNAT; } if ((opts & OPT_VERBOSE) != 0) printnat(ipn, opts); if (opts & OPT_DEBUG) binprint(ipn, ipn->in_size); if ((opts & OPT_ZERORULEST) != 0) { if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { char msg[80]; sprintf(msg, "%d:ioctl(zero nat rule)", ipn->in_flineno); return ipf_perror_fd(fd, ioctlfunc, msg); } } else { PRINTF("hits %lu ", ipn->in_hits); #ifdef USE_QUAD_T PRINTF("bytes %"PRIu64" ", ipn->in_bytes[0] + ipn->in_bytes[1]); #else PRINTF("bytes %lu ", ipn->in_bytes[0] + ipn->in_bytes[1]); #endif printnat(ipn, opts); } } else if ((opts & OPT_REMOVE) != 0) { if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { char msg[80]; sprintf(msg, "%d:ioctl(delete nat rule)", ipn->in_flineno); return ipf_perror_fd(fd, ioctlfunc, msg); } } } else { if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { char msg[80]; sprintf(msg, "%d:ioctl(add/insert nat rule)", ipn->in_flineno); if (errno == EEXIST) { sprintf(msg + strlen(msg), "(line %d)", ipn->in_flineno); } return ipf_perror_fd(fd, ioctlfunc, msg); } } } return 0; } static void setmapifnames() { if (nat->in_ifnames[1] == -1) nat->in_ifnames[1] = nat->in_ifnames[0]; if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0) nat->in_flags |= IPN_TCPUDP; if ((nat->in_flags & IPN_TCPUDP) == 0) setnatproto(nat->in_pr[1]); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } static void setrdrifnames() { if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0) nat->in_flags |= IPN_TCPUDP; if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) && (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0)) setnatproto(IPPROTO_TCP); if (nat->in_ifnames[1] == -1) nat->in_ifnames[1] = nat->in_ifnames[0]; } static void proxy_setconfig(proxy) int proxy; { if (proxy == IPNY_DNS) { yysetfixeddict(dnswords); } } static void proxy_unsetconfig() { yyresetdict(); } static namelist_t * proxy_dns_add_pass(prefix, name) char *prefix, *name; { namelist_t *n; n = calloc(1, sizeof(*n)); if (n != NULL) { if (prefix == NULL || *prefix == '\0') { n->na_name = strdup(name); } else { n->na_name = malloc(strlen(name) + strlen(prefix) + 1); strcpy(n->na_name, prefix); strcat(n->na_name, name); } } return n; } static namelist_t * proxy_dns_add_block(prefix, name) char *prefix, *name; { namelist_t *n; n = calloc(1, sizeof(*n)); if (n != NULL) { if (prefix == NULL || *prefix == '\0') { n->na_name = strdup(name); } else { n->na_name = malloc(strlen(name) + strlen(prefix) + 1); strcpy(n->na_name, prefix); strcat(n->na_name, name); } n->na_value = 1; } return n; } static void proxy_addconfig(proxy, proto, conf, list) char *proxy, *conf; int proto; namelist_t *list; { proxyrule_t *pr; pr = calloc(1, sizeof(*pr)); if (pr != NULL) { pr->pr_proto = proto; pr->pr_proxy = proxy; pr->pr_conf = conf; pr->pr_names = list; pr->pr_next = prules; prules = pr; } } static void proxy_loadrules(fd, ioctlfunc, rules) int fd; ioctlfunc_t ioctlfunc; proxyrule_t *rules; { proxyrule_t *pr; while ((pr = rules) != NULL) { proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto, pr->pr_conf, pr->pr_names); rules = pr->pr_next; free(pr->pr_conf); free(pr); } } static void proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list) int fd; ioctlfunc_t ioctlfunc; char *proxy, *conf; int proto; namelist_t *list; { namelist_t *na; ipfobj_t obj; ap_ctl_t pcmd; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_PROXYCTL; obj.ipfo_size = sizeof(pcmd); obj.ipfo_ptr = &pcmd; while ((na = list) != NULL) { if ((opts & OPT_REMOVE) != 0) pcmd.apc_cmd = APC_CMD_DEL; else pcmd.apc_cmd = APC_CMD_ADD; pcmd.apc_dsize = strlen(na->na_name) + 1; pcmd.apc_data = na->na_name; pcmd.apc_arg = na->na_value; pcmd.apc_p = proto; strncpy(pcmd.apc_label, proxy, APR_LABELLEN); pcmd.apc_label[APR_LABELLEN - 1] = '\0'; strncpy(pcmd.apc_config, conf, APR_LABELLEN); pcmd.apc_config[APR_LABELLEN - 1] = '\0'; if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { char msg[80]; sprintf(msg, "%d:ioctl(add/remove proxy rule)", yylineNum); ipf_perror_fd(fd, ioctlfunc, msg); return; } } list = na->na_next; free(na->na_name); free(na); } } static void setifname(np, idx, name) ipnat_t **np; int idx; char *name; { int pos; pos = addname(np, name); if (pos == -1) return; (*np)->in_ifnames[idx] = pos; } static int addname(np, name) ipnat_t **np; char *name; { ipnat_t *n; int nlen; int pos; nlen = strlen(name) + 1; n = realloc(*np, (*np)->in_size + nlen); if (*np == nattop) nattop = n; *np = n; if (n == NULL) return -1; if (n->in_pnext != NULL) *n->in_pnext = n; n->in_size += nlen; pos = n->in_namelen; n->in_namelen += nlen; strcpy(n->in_names + pos, name); n->in_names[n->in_namelen] = '\0'; return pos; } diff --git a/contrib/ipfilter/tools/ippool.c b/contrib/ipfilter/tools/ippool.c index 49cf7dae63d7..243932c8cc34 100644 --- a/contrib/ipfilter/tools/ippool.c +++ b/contrib/ipfilter/tools/ippool.c @@ -1,1076 +1,1073 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ #include #include #include #include #if defined(BSD) && (BSD >= 199306) # include #endif #include #include -#if __FreeBSD_version >= 300000 -# include -#endif #include #include #include #include #include #include #include #include #include #ifdef linux # include #else # include #endif #include "ipf.h" #include "netinet/ipl.h" #include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" #include "netinet/ip_htable.h" #include "kmem.h" extern int ippool_yyparse __P((void)); extern int ippool_yydebug; extern FILE *ippool_yyin; extern char *optarg; extern int lineNum; void usage __P((char *)); int main __P((int, char **)); int poolcommand __P((int, int, char *[])); int poolnodecommand __P((int, int, char *[])); int loadpoolfile __P((int, char *[], char *)); int poollist __P((int, char *[])); void poollist_dead __P((int, char *, int, char *, char *)); void poollist_live __P((int, char *, int, int)); int poolflush __P((int, char *[])); int poolstats __P((int, char *[])); int gettype __P((char *, u_int *)); int getrole __P((char *)); int setnodeaddr __P((int, int, void *ptr, char *arg)); void showpools_live __P((int, int, ipf_pool_stat_t *, char *)); void showhashs_live __P((int, int, iphtstat_t *, char *)); void showdstls_live __P((int, int, ipf_dstl_stat_t *, char *)); int opts = 0; int fd = -1; int use_inet6 = 0; wordtab_t *pool_fields = NULL; int nohdrfields = 0; void usage(prog) char *prog; { fprintf(stderr, "Usage:\t%s\n", prog); fprintf(stderr, "\t-a [-dnv] [-m ] [-o ] [-t type] [-T ttl] -i [/netmask]\n"); fprintf(stderr, "\t-A [-dnv] [-m ] [-o ] [-S ] [-t ]\n"); fprintf(stderr, "\t-f [-dnuv]\n"); fprintf(stderr, "\t-F [-dv] [-o ] [-t ]\n"); fprintf(stderr, "\t-l [-dv] [-m ] [-t ] [-O ]\n"); fprintf(stderr, "\t-r [-dnv] [-m ] [-o ] [-t type] -i [/netmask]\n"); fprintf(stderr, "\t-R [-dnv] [-m ] [-o ] [-t ]\n"); fprintf(stderr, "\t-s [-dtv] [-M ] [-N ]\n"); exit(1); } int main(argc, argv) int argc; char *argv[]; { int err = 1; if (argc < 2) usage(argv[0]); assigndefined(getenv("IPPOOL_PREDEFINED")); switch (getopt(argc, argv, "aAf:FlnrRsv")) { case 'a' : err = poolnodecommand(0, argc, argv); break; case 'A' : err = poolcommand(0, argc, argv); break; case 'f' : err = loadpoolfile(argc, argv, optarg); break; case 'F' : err = poolflush(argc, argv); break; case 'l' : err = poollist(argc, argv); break; case 'n' : opts |= OPT_DONOTHING|OPT_DONTOPEN; break; case 'r' : err = poolnodecommand(1, argc, argv); break; case 'R' : err = poolcommand(1, argc, argv); break; case 's' : err = poolstats(argc, argv); break; case 'v' : opts |= OPT_VERBOSE; break; default : exit(1); } if (err != 0) exit(1); return 0; } int poolnodecommand(remove, argc, argv) int remove, argc; char *argv[]; { int err = 0, c, ipset, role, type = IPLT_POOL, ttl = 0; char *poolname = NULL; ip_pool_node_t pnode; iphtent_t hnode; void *ptr = &pnode; ipset = 0; role = IPL_LOGIPF; bzero((char *)&pnode, sizeof(pnode)); bzero((char *)&hnode, sizeof(hnode)); while ((c = getopt(argc, argv, "di:m:no:Rt:T:v")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; ippool_yydebug++; break; case 'i' : if (setnodeaddr(type, role, ptr, optarg) == 0) ipset = 1; break; case 'm' : poolname = optarg; break; case 'n' : opts |= OPT_DONOTHING|OPT_DONTOPEN; break; case 'o' : if (ipset == 1) { fprintf(stderr, "cannot set role after ip address\n"); return -1; } role = getrole(optarg); if (role == IPL_LOGNONE) return -1; break; case 'R' : opts |= OPT_NORESOLVE; break; case 't' : if (ipset == 1) { fprintf(stderr, "cannot set type after ip address\n"); return -1; } type = gettype(optarg, NULL); switch (type) { case IPLT_NONE : fprintf(stderr, "unknown type '%s'\n", optarg); return -1; case IPLT_HASH : ptr = &hnode; break; case IPLT_POOL : default : break; } break; case 'T' : ttl = atoi(optarg); if (ttl < 0) { fprintf(stderr, "cannot set negative ttl\n"); return -1; } break; case 'v' : opts |= OPT_VERBOSE; break; } if (argv[optind] != NULL && ipset == 0) { if (setnodeaddr(type, role, ptr, argv[optind]) == 0) ipset = 1; } if (opts & OPT_DEBUG) fprintf(stderr, "poolnodecommand: opts = %#x\n", opts); if (ipset == 0) { fprintf(stderr, "no IP address given with -i\n"); return -1; } if (poolname == NULL) { fprintf(stderr, "poolname not given with add/remove node\n"); return -1; } switch (type) { case IPLT_POOL : if (remove == 0) err = load_poolnode(role, poolname, &pnode, ttl, ioctl); else err = remove_poolnode(role, poolname, &pnode, ioctl); break; case IPLT_HASH : if (remove == 0) err = load_hashnode(role, poolname, &hnode, ttl, ioctl); else err = remove_hashnode(role, poolname, &hnode, ioctl); break; default : break; } return err; } int poolcommand(remove, argc, argv) int remove, argc; char *argv[]; { int type, role, c, err; char *poolname; iphtable_t iph; ip_pool_t pool; err = 1; role = 0; type = 0; poolname = NULL; role = IPL_LOGIPF; bzero((char *)&iph, sizeof(iph)); bzero((char *)&pool, sizeof(pool)); while ((c = getopt(argc, argv, "dm:no:RSv")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; ippool_yydebug++; break; case 'm' : poolname = optarg; break; case 'n' : opts |= OPT_DONOTHING|OPT_DONTOPEN; break; case 'o' : role = getrole(optarg); if (role == IPL_LOGNONE) { fprintf(stderr, "unknown role '%s'\n", optarg); return -1; } break; case 'R' : opts |= OPT_NORESOLVE; break; case 'S' : iph.iph_seed = atoi(optarg); break; case 'v' : opts |= OPT_VERBOSE; break; } if (opts & OPT_DEBUG) fprintf(stderr, "poolcommand: opts = %#x\n", opts); if (poolname == NULL) { fprintf(stderr, "poolname not given with add/remove pool\n"); return -1; } type = gettype(argv[optind], &iph.iph_type); if (type == IPLT_NONE) { fprintf(stderr, "unknown type '%s'\n", argv[optind]); return -1; } if (type == IPLT_HASH) { strncpy(iph.iph_name, poolname, sizeof(iph.iph_name)); iph.iph_name[sizeof(iph.iph_name) - 1] = '\0'; iph.iph_unit = role; } else if (type == IPLT_POOL) { strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name)); pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0'; pool.ipo_unit = role; } if (remove == 0) { switch (type) { case IPLT_HASH : err = load_hash(&iph, NULL, ioctl); break; case IPLT_POOL : err = load_pool(&pool, ioctl); break; } } else { switch (type) { case IPLT_HASH : err = remove_hash(&iph, ioctl); break; case IPLT_POOL : err = remove_pool(&pool, ioctl); break; } } return err; } int loadpoolfile(argc, argv, infile) int argc; char *argv[], *infile; { int c; infile = optarg; while ((c = getopt(argc, argv, "dnRuv")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; ippool_yydebug++; break; case 'n' : opts |= OPT_DONOTHING|OPT_DONTOPEN; break; case 'R' : opts |= OPT_NORESOLVE; break; case 'u' : opts |= OPT_REMOVE; break; case 'v' : opts |= OPT_VERBOSE; break; } if (opts & OPT_DEBUG) fprintf(stderr, "loadpoolfile: opts = %#x\n", opts); if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } } if (ippool_parsefile(fd, infile, ioctl) != 0) return -1; return 0; } int poolstats(argc, argv) int argc; char *argv[]; { int c, type, role, live_kernel; ipf_pool_stat_t plstat; ipf_dstl_stat_t dlstat; char *kernel, *core; iphtstat_t htstat; iplookupop_t op; core = NULL; kernel = NULL; live_kernel = 1; type = IPLT_ALL; role = IPL_LOGALL; bzero((char *)&op, sizeof(op)); while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; break; case 'M' : live_kernel = 0; core = optarg; break; case 'N' : live_kernel = 0; kernel = optarg; break; case 'o' : role = getrole(optarg); if (role == IPL_LOGNONE) { fprintf(stderr, "unknown role '%s'\n", optarg); return -1; } break; case 't' : type = gettype(optarg, NULL); if (type != IPLT_POOL) { fprintf(stderr, "-s not supported for this type yet\n"); return -1; } break; case 'v' : opts |= OPT_VERBOSE; break; } if (opts & OPT_DEBUG) fprintf(stderr, "poolstats: opts = %#x\n", opts); if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } } if (type == IPLT_ALL || type == IPLT_POOL) { op.iplo_type = IPLT_POOL; op.iplo_struct = &plstat; op.iplo_size = sizeof(plstat); if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) { c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)"); return -1; } printf("%lu\taddress pools\n", plstat.ipls_pools); printf("%lu\taddress pool nodes\n", plstat.ipls_nodes); } } if (type == IPLT_ALL || type == IPLT_HASH) { op.iplo_type = IPLT_HASH; op.iplo_struct = &htstat; op.iplo_size = sizeof(htstat); if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) { c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); return -1; } printf("%lu\thash tables\n", htstat.iphs_numtables); printf("%lu\thash table nodes\n", htstat.iphs_numnodes); printf("%lu\thash table no memory \n", htstat.iphs_nomem); } } if (type == IPLT_ALL || type == IPLT_DSTLIST) { op.iplo_type = IPLT_DSTLIST; op.iplo_struct = &dlstat; op.iplo_size = sizeof(dlstat); if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) { c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); return -1; } printf("%u\tdestination lists\n", dlstat.ipls_numlists); printf("%u\tdestination list nodes\n", dlstat.ipls_numnodes); printf("%lu\tdestination list no memory\n", dlstat.ipls_nomem); printf("%u\tdestination list zombies\n", dlstat.ipls_numdereflists); printf("%u\tdesetination list node zombies\n", dlstat.ipls_numderefnodes); } } return 0; } int poolflush(argc, argv) int argc; char *argv[]; { int c, role, type, arg; iplookupflush_t flush; arg = IPLT_ALL; type = IPLT_ALL; role = IPL_LOGALL; while ((c = getopt(argc, argv, "do:t:v")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; break; case 'o' : role = getrole(optarg); if (role == IPL_LOGNONE) { fprintf(stderr, "unknown role '%s'\n", optarg); return -1; } break; case 't' : type = gettype(optarg, NULL); if (type == IPLT_NONE) { fprintf(stderr, "unknown type '%s'\n", optarg); return -1; } break; case 'v' : opts |= OPT_VERBOSE; break; } if (opts & OPT_DEBUG) fprintf(stderr, "poolflush: opts = %#x\n", opts); if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } } bzero((char *)&flush, sizeof(flush)); flush.iplf_type = type; flush.iplf_unit = role; flush.iplf_arg = arg; if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) { if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) { ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)"); exit(1); } } printf("%u object%s flushed\n", flush.iplf_count, (flush.iplf_count == 1) ? "" : "s"); return 0; } int getrole(rolename) char *rolename; { int role; if (!strcasecmp(rolename, "ipf")) { role = IPL_LOGIPF; #if 0 } else if (!strcasecmp(rolename, "nat")) { role = IPL_LOGNAT; } else if (!strcasecmp(rolename, "state")) { role = IPL_LOGSTATE; } else if (!strcasecmp(rolename, "auth")) { role = IPL_LOGAUTH; } else if (!strcasecmp(rolename, "sync")) { role = IPL_LOGSYNC; } else if (!strcasecmp(rolename, "scan")) { role = IPL_LOGSCAN; } else if (!strcasecmp(rolename, "pool")) { role = IPL_LOGLOOKUP; } else if (!strcasecmp(rolename, "count")) { role = IPL_LOGCOUNT; #endif } else { role = IPL_LOGNONE; } return role; } int gettype(typename, minor) char *typename; u_int *minor; { int type; if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) { type = IPLT_POOL; } else if (!strcasecmp(typename, "hash")) { type = IPLT_HASH; if (minor != NULL) *minor = IPHASH_LOOKUP; } else if (!strcasecmp(typename, "group-map")) { type = IPLT_HASH; if (minor != NULL) *minor = IPHASH_GROUPMAP; } else { type = IPLT_NONE; } return type; } int poollist(argc, argv) int argc; char *argv[]; { char *kernel, *core, *poolname; int c, role, type, live_kernel; iplookupop_t op; core = NULL; kernel = NULL; live_kernel = 1; type = IPLT_ALL; poolname = NULL; role = IPL_LOGALL; while ((c = getopt(argc, argv, "dm:M:N:o:Rt:v")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; break; case 'm' : poolname = optarg; break; case 'M' : live_kernel = 0; core = optarg; break; case 'N' : live_kernel = 0; kernel = optarg; break; case 'o' : role = getrole(optarg); if (role == IPL_LOGNONE) { fprintf(stderr, "unknown role '%s'\n", optarg); return -1; } break; case 'O' : pool_fields = parsefields(poolfields, optarg); break; case 'R' : opts |= OPT_NORESOLVE; break; case 't' : type = gettype(optarg, NULL); if (type == IPLT_NONE) { fprintf(stderr, "unknown type '%s'\n", optarg); return -1; } break; case 'v' : opts |= OPT_VERBOSE; break; } if (opts & OPT_DEBUG) fprintf(stderr, "poollist: opts = %#x\n", opts); if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } } bzero((char *)&op, sizeof(op)); if (poolname != NULL) { strncpy(op.iplo_name, poolname, sizeof(op.iplo_name)); op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; } op.iplo_unit = role; if (live_kernel) poollist_live(role, poolname, type, fd); else poollist_dead(role, poolname, type, kernel, core); return 0; } void poollist_dead(role, poolname, type, kernel, core) int role, type; char *poolname, *kernel, *core; { iphtable_t *hptr; ip_pool_t *ptr; if (openkmem(kernel, core) == -1) exit(-1); if (type == IPLT_ALL || type == IPLT_POOL) { ip_pool_t *pools[IPL_LOGSIZE]; struct nlist names[2] = { { "ip_pool_list" } , { "" } }; if (nlist(kernel, names) != 1) return; bzero(&pools, sizeof(pools)); if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools))) return; if (role != IPL_LOGALL) { ptr = pools[role]; while (ptr != NULL) { ptr = printpool(ptr, kmemcpywrap, poolname, opts, pool_fields); } } else { for (role = 0; role <= IPL_LOGMAX; role++) { ptr = pools[role]; while (ptr != NULL) { ptr = printpool(ptr, kmemcpywrap, poolname, opts, pool_fields); } } role = IPL_LOGALL; } } if (type == IPLT_ALL || type == IPLT_HASH) { iphtable_t *tables[IPL_LOGSIZE]; struct nlist names[2] = { { "ipf_htables" } , { "" } }; if (nlist(kernel, names) != 1) return; bzero(&tables, sizeof(tables)); if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables))) return; if (role != IPL_LOGALL) { hptr = tables[role]; while (hptr != NULL) { hptr = printhash(hptr, kmemcpywrap, poolname, opts, pool_fields); } } else { for (role = 0; role <= IPL_LOGMAX; role++) { hptr = tables[role]; while (hptr != NULL) { hptr = printhash(hptr, kmemcpywrap, poolname, opts, pool_fields); } } } } } void poollist_live(role, poolname, type, fd) int role, type, fd; char *poolname; { ipf_pool_stat_t plstat; iplookupop_t op; int c; if (type == IPLT_ALL || type == IPLT_POOL) { op.iplo_type = IPLT_POOL; op.iplo_size = sizeof(plstat); op.iplo_struct = &plstat; op.iplo_name[0] = '\0'; op.iplo_arg = 0; if (role != IPL_LOGALL) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); return; } showpools_live(fd, role, &plstat, poolname); } else { for (role = -1; role <= IPL_LOGMAX; role++) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); return; } showpools_live(fd, role, &plstat, poolname); } role = IPL_LOGALL; } } if (type == IPLT_ALL || type == IPLT_HASH) { iphtstat_t htstat; op.iplo_type = IPLT_HASH; op.iplo_size = sizeof(htstat); op.iplo_struct = &htstat; op.iplo_name[0] = '\0'; op.iplo_arg = 0; if (role != IPL_LOGALL) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); return; } showhashs_live(fd, role, &htstat, poolname); } else { for (role = 0; role <= IPL_LOGMAX; role++) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); return; } showhashs_live(fd, role, &htstat, poolname); } role = IPL_LOGALL; } } if (type == IPLT_ALL || type == IPLT_DSTLIST) { ipf_dstl_stat_t dlstat; op.iplo_type = IPLT_DSTLIST; op.iplo_size = sizeof(dlstat); op.iplo_struct = &dlstat; op.iplo_name[0] = '\0'; op.iplo_arg = 0; if (role != IPL_LOGALL) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); return; } showdstls_live(fd, role, &dlstat, poolname); } else { for (role = 0; role <= IPL_LOGMAX; role++) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); return; } showdstls_live(fd, role, &dlstat, poolname); } role = IPL_LOGALL; } } } void showpools_live(fd, role, plstp, poolname) int fd, role; ipf_pool_stat_t *plstp; char *poolname; { ipflookupiter_t iter; ip_pool_t pool; ipfobj_t obj; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_LOOKUPITER; obj.ipfo_size = sizeof(iter); obj.ipfo_ptr = &iter; iter.ili_type = IPLT_POOL; iter.ili_otype = IPFLOOKUPITER_LIST; iter.ili_ival = IPFGENITER_LOOKUP; iter.ili_nitems = 1; iter.ili_data = &pool; iter.ili_unit = role; *iter.ili_name = '\0'; bzero((char *)&pool, sizeof(pool)); while (plstp->ipls_list[role + 1] != NULL) { if (ioctl(fd, SIOCLOOKUPITER, &obj)) { ipferror(fd, "ioctl(SIOCLOOKUPITER)"); break; } if (((pool.ipo_flags & IPOOL_DELETE) == 0) || ((opts & OPT_DEBUG) != 0)) printpool_live(&pool, fd, poolname, opts, pool_fields); plstp->ipls_list[role + 1] = pool.ipo_next; } } void showhashs_live(fd, role, htstp, poolname) int fd, role; iphtstat_t *htstp; char *poolname; { ipflookupiter_t iter; iphtable_t table; ipfobj_t obj; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_LOOKUPITER; obj.ipfo_size = sizeof(iter); obj.ipfo_ptr = &iter; iter.ili_type = IPLT_HASH; iter.ili_otype = IPFLOOKUPITER_LIST; iter.ili_ival = IPFGENITER_LOOKUP; iter.ili_nitems = 1; iter.ili_data = &table; iter.ili_unit = role; *iter.ili_name = '\0'; while (htstp->iphs_tables != NULL) { if (ioctl(fd, SIOCLOOKUPITER, &obj)) { ipferror(fd, "ioctl(SIOCLOOKUPITER)"); break; } printhash_live(&table, fd, poolname, opts, pool_fields); htstp->iphs_tables = table.iph_next; } } void showdstls_live(fd, role, dlstp, poolname) int fd, role; ipf_dstl_stat_t *dlstp; char *poolname; { ipflookupiter_t iter; ippool_dst_t table; ipfobj_t obj; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_LOOKUPITER; obj.ipfo_size = sizeof(iter); obj.ipfo_ptr = &iter; iter.ili_type = IPLT_DSTLIST; iter.ili_otype = IPFLOOKUPITER_LIST; iter.ili_ival = IPFGENITER_LOOKUP; iter.ili_nitems = 1; iter.ili_data = &table; iter.ili_unit = role; *iter.ili_name = '\0'; while (dlstp->ipls_list[role] != NULL) { if (ioctl(fd, SIOCLOOKUPITER, &obj)) { ipferror(fd, "ioctl(SIOCLOOKUPITER)"); break; } printdstl_live(&table, fd, poolname, opts, pool_fields); dlstp->ipls_list[role] = table.ipld_next; } } int setnodeaddr(int type, int role, void *ptr, char *arg) { struct in_addr mask; char *s; s = strchr(arg, '/'); if (s == NULL) mask.s_addr = 0xffffffff; else if (strchr(s, '.') == NULL) { if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0) return -1; } else { mask.s_addr = inet_addr(s + 1); } if (s != NULL) *s = '\0'; if (type == IPLT_POOL) { ip_pool_node_t *node = ptr; if (node->ipn_addr.adf_family == AF_INET) node->ipn_addr.adf_len = offsetof(addrfamily_t, adf_addr) + sizeof(struct in_addr); #ifdef USE_INET6 else node->ipn_addr.adf_len = offsetof(addrfamily_t, adf_addr) + sizeof(struct in6_addr); #endif node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg); node->ipn_mask.adf_len = node->ipn_addr.adf_len; node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr; } else if (type == IPLT_HASH) { iphtent_t *node = ptr; node->ipe_addr.in4.s_addr = inet_addr(arg); node->ipe_mask.in4.s_addr = mask.s_addr; node->ipe_family = AF_INET; node->ipe_unit = role; } return 0; } diff --git a/contrib/ipfilter/tools/ippool_y.y b/contrib/ipfilter/tools/ippool_y.y index 34987452c65b..93593ce82eca 100644 --- a/contrib/ipfilter/tools/ippool_y.y +++ b/contrib/ipfilter/tools/ippool_y.y @@ -1,821 +1,818 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ %{ #include #include #include #include #if defined(BSD) && (BSD >= 199306) # include #endif #include #include -#if __FreeBSD_version >= 300000 -# include -#endif #include #include #include #include #include #include #include #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" #include "netinet/ip_htable.h" #include "netinet/ip_dstlist.h" #include "ippool_l.h" #include "kmem.h" #define YYDEBUG 1 #define YYSTACKSIZE 0x00ffffff extern int yyparse __P((void)); extern int yydebug; extern FILE *yyin; static iphtable_t ipht; static iphtent_t iphte; static ip_pool_t iplo; static ippool_dst_t ipld; static ioctlfunc_t poolioctl = NULL; static char poolname[FR_GROUPLEN]; static iphtent_t *add_htablehosts __P((char *)); static ip_pool_node_t *add_poolhosts __P((char *)); static ip_pool_node_t *read_whoisfile __P((char *)); static void setadflen __P((addrfamily_t *)); %} %union { char *str; u_32_t num; struct in_addr ip4; struct alist_s *alist; addrfamily_t adrmsk[2]; iphtent_t *ipe; ip_pool_node_t *ipp; ipf_dstnode_t *ipd; addrfamily_t ipa; i6addr_t ip6; } %token YY_NUMBER YY_HEX %token YY_STR %token YY_IPV6 %token YY_COMMENT %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT %token YY_RANGE_OUT YY_RANGE_IN %token IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT IPT_ALL %token IPT_TABLE IPT_GROUPMAP IPT_HASH IPT_SRCHASH IPT_DSTHASH %token IPT_ROLE IPT_TYPE IPT_TREE %token IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME IPT_POLICY %token IPT_POOL IPT_DSTLIST IPT_ROUNDROBIN %token IPT_WEIGHTED IPT_RANDOM IPT_CONNECTION %token IPT_WHOIS IPT_FILE %type role table inout unit dstopts weighting %type ipftree range addrlist %type addrmask %type ipfgroup ipfhash hashlist hashentry %type groupentry setgrouplist grouplist %type ipaddr mask %type ipv4 %type number setgroup name %type dstentry dstentries dstlist %% file: line | assign | file line | file assign ; line: table role ipftree eol { ip_pool_node_t *n; iplo.ipo_unit = $2; iplo.ipo_list = $3; load_pool(&iplo, poolioctl); while ((n = $3) != NULL) { $3 = n->ipn_next; free(n); } resetlexer(); use_inet6 = 0; } | table role ipfhash eol { iphtent_t *h; ipht.iph_unit = $2; ipht.iph_type = IPHASH_LOOKUP; load_hash(&ipht, $3, poolioctl); while ((h = $3) != NULL) { $3 = h->ipe_next; free(h); } resetlexer(); use_inet6 = 0; } | groupmap role number ipfgroup eol { iphtent_t *h; ipht.iph_unit = $2; strncpy(ipht.iph_name, $3, sizeof(ipht.iph_name)); ipht.iph_type = IPHASH_GROUPMAP; load_hash(&ipht, $4, poolioctl); while ((h = $4) != NULL) { $4 = h->ipe_next; free(h); } resetlexer(); use_inet6 = 0; } | YY_COMMENT | poolline eol ; eol: ';' ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); yyvarnext = 0; } ; assigning: '=' { yyvarnext = 1; } ; table: IPT_TABLE { bzero((char *)&ipht, sizeof(ipht)); bzero((char *)&iphte, sizeof(iphte)); bzero((char *)&iplo, sizeof(iplo)); bzero((char *)&ipld, sizeof(ipld)); *ipht.iph_name = '\0'; iplo.ipo_flags = IPHASH_ANON; iplo.ipo_name[0] = '\0'; } ; groupmap: IPT_GROUPMAP inout { bzero((char *)&ipht, sizeof(ipht)); bzero((char *)&iphte, sizeof(iphte)); *ipht.iph_name = '\0'; ipht.iph_unit = IPHASH_GROUPMAP; ipht.iph_flags = $2; } ; inout: IPT_IN { $$ = FR_INQUE; } | IPT_OUT { $$ = FR_OUTQUE; } ; role: IPT_ROLE '=' unit { $$ = $3; } ; unit: IPT_IPF { $$ = IPL_LOGIPF; } | IPT_NAT { $$ = IPL_LOGNAT; } | IPT_AUTH { $$ = IPL_LOGAUTH; } | IPT_COUNT { $$ = IPL_LOGCOUNT; } | IPT_ALL { $$ = IPL_LOGALL; } ; ipftree: IPT_TYPE '=' IPT_TREE number start addrlist end { strncpy(iplo.ipo_name, $4, sizeof(iplo.ipo_name)); $$ = $6; } ; ipfhash: IPT_TYPE '=' IPT_HASH number hashopts start hashlist end { strncpy(ipht.iph_name, $4, sizeof(ipht.iph_name)); $$ = $7; } ; ipfgroup: setgroup hashopts start grouplist end { iphtent_t *e; for (e = $4; e != NULL; e = e->ipe_next) if (e->ipe_group[0] == '\0') strncpy(e->ipe_group, $1, FR_GROUPLEN); $$ = $4; free($1); } | hashopts start setgrouplist end { $$ = $3; } ; number: IPT_NUM '=' YY_NUMBER { sprintf(poolname, "%u", $3); $$ = poolname; } | IPT_NAME '=' YY_STR { strncpy(poolname, $3, FR_GROUPLEN); poolname[FR_GROUPLEN-1]='\0'; free($3); $$ = poolname; } | { $$ = ""; } ; setgroup: IPT_GROUP '=' YY_STR { char tmp[FR_GROUPLEN+1]; strncpy(tmp, $3, FR_GROUPLEN); $$ = strdup(tmp); free($3); } | IPT_GROUP '=' YY_NUMBER { char tmp[FR_GROUPLEN+1]; sprintf(tmp, "%u", $3); $$ = strdup(tmp); } ; hashopts: | size | seed | size seed ; addrlist: ';' { $$ = NULL; } | range next addrlist { $$ = $1; while ($1->ipn_next != NULL) $1 = $1->ipn_next; $1->ipn_next = $3; } | range next { $$ = $1; } ; grouplist: ';' { $$ = NULL; } | groupentry next grouplist { $$ = $1; $1->ipe_next = $3; } | addrmask next grouplist { $$ = calloc(1, sizeof(iphtent_t)); $$->ipe_addr = $1[0].adf_addr; $$->ipe_mask = $1[1].adf_addr; $$->ipe_family = $1[0].adf_family; $$->ipe_next = $3; } | groupentry next { $$ = $1; } | addrmask next { $$ = calloc(1, sizeof(iphtent_t)); $$->ipe_addr = $1[0].adf_addr; $$->ipe_mask = $1[1].adf_addr; #ifdef AF_INET6 if (use_inet6) $$->ipe_family = AF_INET6; else #endif $$->ipe_family = AF_INET; } | YY_STR { $$ = add_htablehosts($1); free($1); } ; setgrouplist: ';' { $$ = NULL; } | groupentry next { $$ = $1; } | groupentry next setgrouplist { $1->ipe_next = $3; $$ = $1; } ; groupentry: addrmask ',' setgroup { $$ = calloc(1, sizeof(iphtent_t)); $$->ipe_addr = $1[0].adf_addr; $$->ipe_mask = $1[1].adf_addr; strncpy($$->ipe_group, $3, FR_GROUPLEN); #ifdef AF_INET6 if (use_inet6) $$->ipe_family = AF_INET6; else #endif $$->ipe_family = AF_INET; free($3); } ; range: addrmask { $$ = calloc(1, sizeof(*$$)); $$->ipn_info = 0; $$->ipn_addr = $1[0]; $$->ipn_mask = $1[1]; } | '!' addrmask { $$ = calloc(1, sizeof(*$$)); $$->ipn_info = 1; $$->ipn_addr = $2[0]; $$->ipn_mask = $2[1]; } | YY_STR { $$ = add_poolhosts($1); free($1); } | IPT_WHOIS IPT_FILE YY_STR { $$ = read_whoisfile($3); free($3); } ; hashlist: ';' { $$ = NULL; } | hashentry next { $$ = $1; } | hashentry next hashlist { $1->ipe_next = $3; $$ = $1; } ; hashentry: addrmask { $$ = calloc(1, sizeof(iphtent_t)); $$->ipe_addr = $1[0].adf_addr; $$->ipe_mask = $1[1].adf_addr; #ifdef USE_INET6 if (use_inet6) $$->ipe_family = AF_INET6; else #endif $$->ipe_family = AF_INET; } | YY_STR { $$ = add_htablehosts($1); free($1); } ; addrmask: ipaddr '/' mask { $$[0] = $1; setadflen(&$$[0]); $$[1] = $3; $$[1].adf_len = $$[0].adf_len; } | ipaddr { $$[0] = $1; setadflen(&$$[1]); $$[1].adf_len = $$[0].adf_len; #ifdef USE_INET6 if (use_inet6) memset(&$$[1].adf_addr, 0xff, sizeof($$[1].adf_addr.in6)); else #endif memset(&$$[1].adf_addr, 0xff, sizeof($$[1].adf_addr.in4)); } ; ipaddr: ipv4 { $$.adf_addr.in4 = $1; $$.adf_family = AF_INET; setadflen(&$$); use_inet6 = 0; } | YY_NUMBER { $$.adf_addr.in4.s_addr = htonl($1); $$.adf_family = AF_INET; setadflen(&$$); use_inet6 = 0; } | YY_IPV6 { $$.adf_addr = $1; $$.adf_family = AF_INET6; setadflen(&$$); use_inet6 = 1; } ; mask: YY_NUMBER { bzero(&$$, sizeof($$)); if (use_inet6) { if (ntomask(AF_INET6, $1, (u_32_t *)&$$.adf_addr) == -1) yyerror("bad bitmask"); } else { if (ntomask(AF_INET, $1, (u_32_t *)&$$.adf_addr.in4) == -1) yyerror("bad bitmask"); } } | ipv4 { bzero(&$$, sizeof($$)); $$.adf_addr.in4 = $1; } | YY_IPV6 { bzero(&$$, sizeof($$)); $$.adf_addr = $1; } ; size: IPT_SIZE '=' YY_NUMBER { ipht.iph_size = $3; } ; seed: IPT_SEED '=' YY_NUMBER { ipht.iph_seed = $3; } ; ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { yyerror("Invalid octet string for IP address"); return 0; } $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; $$.s_addr = htonl($$.s_addr); } ; next: ';' { yyexpectaddr = 1; } ; start: '{' { yyexpectaddr = 1; } ; end: '}' { yyexpectaddr = 0; } ; poolline: IPT_POOL unit '/' IPT_DSTLIST '(' name ';' dstopts ')' start dstlist end { bzero((char *)&ipld, sizeof(ipld)); strncpy(ipld.ipld_name, $6, sizeof(ipld.ipld_name)); ipld.ipld_unit = $2; ipld.ipld_policy = $8; load_dstlist(&ipld, poolioctl, $11); resetlexer(); use_inet6 = 0; free($6); } | IPT_POOL unit '/' IPT_TREE '(' name ';' ')' start addrlist end { bzero((char *)&iplo, sizeof(iplo)); strncpy(iplo.ipo_name, $6, sizeof(iplo.ipo_name)); iplo.ipo_list = $10; iplo.ipo_unit = $2; load_pool(&iplo, poolioctl); resetlexer(); use_inet6 = 0; free($6); } | IPT_POOL '(' name ';' ')' start addrlist end { bzero((char *)&iplo, sizeof(iplo)); strncpy(iplo.ipo_name, $3, sizeof(iplo.ipo_name)); iplo.ipo_list = $7; iplo.ipo_unit = IPL_LOGALL; load_pool(&iplo, poolioctl); resetlexer(); use_inet6 = 0; free($3); } | IPT_POOL unit '/' IPT_HASH '(' name ';' hashoptlist ')' start hashlist end { iphtent_t *h; bzero((char *)&ipht, sizeof(ipht)); strncpy(ipht.iph_name, $6, sizeof(ipht.iph_name)); ipht.iph_unit = $2; load_hash(&ipht, $11, poolioctl); while ((h = ipht.iph_list) != NULL) { ipht.iph_list = h->ipe_next; free(h); } resetlexer(); use_inet6 = 0; free($6); } | IPT_GROUPMAP '(' name ';' inout ';' ')' start setgrouplist end { iphtent_t *h; bzero((char *)&ipht, sizeof(ipht)); strncpy(ipht.iph_name, $3, sizeof(ipht.iph_name)); ipht.iph_type = IPHASH_GROUPMAP; ipht.iph_unit = IPL_LOGIPF; ipht.iph_flags = $5; load_hash(&ipht, $9, poolioctl); while ((h = ipht.iph_list) != NULL) { ipht.iph_list = h->ipe_next; free(h); } resetlexer(); use_inet6 = 0; free($3); } ; name: IPT_NAME YY_STR { $$ = $2; } | IPT_NUM YY_NUMBER { char name[80]; sprintf(name, "%d", $2); $$ = strdup(name); } ; hashoptlist: | hashopt ';' | hashoptlist ';' hashopt ';' ; hashopt: IPT_SIZE YY_NUMBER | IPT_SEED YY_NUMBER ; dstlist: dstentries { $$ = $1; } | ';' { $$ = NULL; } ; dstentries: dstentry next { $$ = $1; } | dstentry next dstentries { $1->ipfd_next = $3; $$ = $1; } ; dstentry: YY_STR ':' ipaddr { int size = sizeof(*$$) + strlen($1) + 1; $$ = calloc(1, size); if ($$ != NULL) { $$->ipfd_dest.fd_name = strlen($1) + 1; bcopy($1, $$->ipfd_names, $$->ipfd_dest.fd_name); $$->ipfd_dest.fd_addr = $3; $$->ipfd_size = size; } free($1); } | ipaddr { $$ = calloc(1, sizeof(*$$)); if ($$ != NULL) { $$->ipfd_dest.fd_name = -1; $$->ipfd_dest.fd_addr = $1; $$->ipfd_size = sizeof(*$$); } } ; dstopts: { $$ = IPLDP_NONE; } | IPT_POLICY IPT_ROUNDROBIN ';' { $$ = IPLDP_ROUNDROBIN; } | IPT_POLICY IPT_WEIGHTED weighting ';' { $$ = $3; } | IPT_POLICY IPT_RANDOM ';' { $$ = IPLDP_RANDOM; } | IPT_POLICY IPT_HASH ';' { $$ = IPLDP_HASHED; } | IPT_POLICY IPT_SRCHASH ';' { $$ = IPLDP_SRCHASH; } | IPT_POLICY IPT_DSTHASH ';' { $$ = IPLDP_DSTHASH; } ; weighting: IPT_CONNECTION { $$ = IPLDP_CONNECTION; } ; %% static wordtab_t yywords[] = { { "all", IPT_ALL }, { "auth", IPT_AUTH }, { "connection", IPT_CONNECTION }, { "count", IPT_COUNT }, { "dst-hash", IPT_DSTHASH }, { "dstlist", IPT_DSTLIST }, { "file", IPT_FILE }, { "group", IPT_GROUP }, { "group-map", IPT_GROUPMAP }, { "hash", IPT_HASH }, { "in", IPT_IN }, { "ipf", IPT_IPF }, { "name", IPT_NAME }, { "nat", IPT_NAT }, { "number", IPT_NUM }, { "out", IPT_OUT }, { "policy", IPT_POLICY }, { "pool", IPT_POOL }, { "random", IPT_RANDOM }, { "round-robin", IPT_ROUNDROBIN }, { "role", IPT_ROLE }, { "seed", IPT_SEED }, { "size", IPT_SIZE }, { "src-hash", IPT_SRCHASH }, { "table", IPT_TABLE }, { "tree", IPT_TREE }, { "type", IPT_TYPE }, { "weighted", IPT_WEIGHTED }, { "whois", IPT_WHOIS }, { NULL, 0 } }; int ippool_parsefile(fd, filename, iocfunc) int fd; char *filename; ioctlfunc_t iocfunc; { FILE *fp = NULL; char *s; yylineNum = 1; (void) yysettab(yywords); s = getenv("YYDEBUG"); if (s) yydebug = atoi(s); else yydebug = 0; if (strcmp(filename, "-")) { fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "fopen(%s) failed: %s\n", filename, STRERROR(errno)); return -1; } } else fp = stdin; while (ippool_parsesome(fd, fp, iocfunc) == 1) ; if (fp != NULL) fclose(fp); return 0; } int ippool_parsesome(fd, fp, iocfunc) int fd; FILE *fp; ioctlfunc_t iocfunc; { char *s; int i; poolioctl = iocfunc; if (feof(fp)) return 0; i = fgetc(fp); if (i == EOF) return 0; if (ungetc(i, fp) == EOF) return 0; if (feof(fp)) return 0; s = getenv("YYDEBUG"); if (s) yydebug = atoi(s); else yydebug = 0; yyin = fp; yyparse(); return 1; } static iphtent_t * add_htablehosts(url) char *url; { iphtent_t *htop, *hbot, *h; alist_t *a, *hlist; if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) { hlist = load_url(url); } else { use_inet6 = 0; hlist = calloc(1, sizeof(*hlist)); if (hlist == NULL) return NULL; if (gethost(hlist->al_family, url, &hlist->al_i6addr) == -1) { yyerror("Unknown hostname"); } } hbot = NULL; htop = NULL; for (a = hlist; a != NULL; a = a->al_next) { h = calloc(1, sizeof(*h)); if (h == NULL) break; h->ipe_family = a->al_family; h->ipe_addr = a->al_i6addr; h->ipe_mask = a->al_i6mask; if (hbot != NULL) hbot->ipe_next = h; else htop = h; hbot = h; } alist_free(hlist); return htop; } static ip_pool_node_t * add_poolhosts(url) char *url; { ip_pool_node_t *ptop, *pbot, *p; alist_t *a, *hlist; if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) { hlist = load_url(url); } else { use_inet6 = 0; hlist = calloc(1, sizeof(*hlist)); if (hlist == NULL) return NULL; if (gethost(hlist->al_family, url, &hlist->al_i6addr) == -1) { yyerror("Unknown hostname"); } } pbot = NULL; ptop = NULL; for (a = hlist; a != NULL; a = a->al_next) { p = calloc(1, sizeof(*p)); if (p == NULL) break; p->ipn_mask.adf_addr = a->al_i6mask; if (a->al_family == AF_INET) { p->ipn_addr.adf_family = AF_INET; #ifdef USE_INET6 } else if (a->al_family == AF_INET6) { p->ipn_addr.adf_family = AF_INET6; #endif } setadflen(&p->ipn_addr); p->ipn_addr.adf_addr = a->al_i6addr; p->ipn_info = a->al_not; p->ipn_mask.adf_len = p->ipn_addr.adf_len; if (pbot != NULL) pbot->ipn_next = p; else ptop = p; pbot = p; } alist_free(hlist); return ptop; } ip_pool_node_t * read_whoisfile(file) char *file; { ip_pool_node_t *ntop, *ipn, node, *last; char line[1024]; FILE *fp; fp = fopen(file, "r"); if (fp == NULL) return NULL; last = NULL; ntop = NULL; while (fgets(line, sizeof(line) - 1, fp) != NULL) { line[sizeof(line) - 1] = '\0'; if (parsewhoisline(line, &node.ipn_addr, &node.ipn_mask)) continue; ipn = calloc(1, sizeof(*ipn)); if (ipn == NULL) continue; ipn->ipn_addr = node.ipn_addr; ipn->ipn_mask = node.ipn_mask; if (last == NULL) ntop = ipn; else last->ipn_next = ipn; last = ipn; } fclose(fp); return ntop; } static void setadflen(afp) addrfamily_t *afp; { afp->adf_len = offsetof(addrfamily_t, adf_addr); switch (afp->adf_family) { case AF_INET : afp->adf_len += sizeof(struct in_addr); break; #ifdef USE_INET6 case AF_INET6 : afp->adf_len += sizeof(struct in6_addr); break; #endif default : break; } } diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c index c50374e7287a..17c9b651c375 100644 --- a/lib/libc/net/getaddrinfo.c +++ b/lib/libc/net/getaddrinfo.c @@ -1,2853 +1,2852 @@ /* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Issues to be discussed: * - Return values. There are nonstandard return values defined and used * in the source code. This is because RFC2553 is silent about which error * code must be returned for which situation. * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is * invalid. current code - SEGV on freeaddrinfo(NULL) * * Note: * - The code filters out AFs that are not supported by the kernel, * when globbing NULL hostname (to loopback, or wildcard). Is it the right * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG * in ai_flags? * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. * (1) what should we do against numeric hostname (2) what should we do * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? * non-loopback address configured? global address configured? * * OS specific notes for freebsd4: * - FreeBSD supported $GAI. The code does not. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include #include #include #include #include #include #ifdef INET6 -#include #include #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "res_config.h" #ifdef DEBUG #include #endif #include #include #include "un-namespace.h" #include "libc_private.h" #ifdef NS_CACHING #include "nscache.h" #endif #define ANY 0 #define YES 1 #define NO 0 static const char in_addrany[] = { 0, 0, 0, 0 }; static const char in_loopback[] = { 127, 0, 0, 1 }; #ifdef INET6 static const char in6_addrany[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char in6_loopback[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; #endif struct policyqueue { TAILQ_ENTRY(policyqueue) pc_entry; #ifdef INET6 struct in6_addrpolicy pc_policy; #endif }; TAILQ_HEAD(policyhead, policyqueue); static const struct afd { int a_af; int a_addrlen; socklen_t a_socklen; int a_off; const char *a_addrany; const char *a_loopback; int a_scoped; } afdl [] = { #ifdef INET6 #define N_INET6 0 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), offsetof(struct sockaddr_in6, sin6_addr), in6_addrany, in6_loopback, 1}, #define N_INET 1 #else #define N_INET 0 #endif {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), offsetof(struct sockaddr_in, sin_addr), in_addrany, in_loopback, 0}, {0, 0, 0, 0, NULL, NULL, 0}, }; struct explore { int e_af; int e_socktype; int e_protocol; int e_wild; #define WILD_AF(ex) ((ex)->e_wild & 0x01) #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) }; static const struct explore explore[] = { #if 0 { PF_LOCAL, ANY, ANY, 0x01 }, #endif #ifdef INET6 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, 0x07 }, { PF_INET6, SOCK_STREAM, IPPROTO_TCP, 0x07 }, { PF_INET6, SOCK_STREAM, IPPROTO_SCTP, 0x03 }, { PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP, 0x07 }, { PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE, 0x03 }, { PF_INET6, SOCK_RAW, ANY, 0x05 }, #endif { PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0x07 }, { PF_INET, SOCK_STREAM, IPPROTO_TCP, 0x07 }, { PF_INET, SOCK_STREAM, IPPROTO_SCTP, 0x03 }, { PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, 0x07 }, { PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE, 0x03 }, { PF_INET, SOCK_RAW, ANY, 0x05 }, { -1, 0, 0, 0 }, }; #ifdef INET6 #define PTON_MAX 16 #else #define PTON_MAX 4 #endif #define AIO_SRCFLAG_DEPRECATED 0x1 struct ai_order { union { struct sockaddr_storage aiou_ss; struct sockaddr aiou_sa; } aio_src_un; #define aio_srcsa aio_src_un.aiou_sa u_int32_t aio_srcflag; int aio_srcscope; int aio_dstscope; struct policyqueue *aio_srcpolicy; struct policyqueue *aio_dstpolicy; struct addrinfo *aio_ai; int aio_matchlen; }; static const ns_src default_dns_files[] = { { NSSRC_FILES, NS_SUCCESS }, { NSSRC_DNS, NS_SUCCESS }, { 0 } }; struct res_target { struct res_target *next; const char *name; /* domain name */ int qclass, qtype; /* class and type of query */ u_char *answer; /* buffer to put answer */ int anslen; /* size of answer buffer */ int n; /* result length */ }; #define MAXPACKET (64*1024) typedef union { HEADER hdr; u_char buf[MAXPACKET]; } querybuf; static int str2number(const char *, int *); static int explore_copy(const struct addrinfo *, const struct addrinfo *, struct addrinfo **); static int explore_null(const struct addrinfo *, const char *, struct addrinfo **); static int explore_numeric(const struct addrinfo *, const char *, const char *, struct addrinfo **, const char *); static int explore_numeric_scope(const struct addrinfo *, const char *, const char *, struct addrinfo **); static int get_canonname(const struct addrinfo *, struct addrinfo *, const char *); static struct addrinfo *get_ai(const struct addrinfo *, const struct afd *, const char *); static struct addrinfo *copy_ai(const struct addrinfo *); static int get_portmatch(const struct addrinfo *, const char *); static int get_port(struct addrinfo *, const char *, int); static const struct afd *find_afd(int); static int addrconfig(struct addrinfo *); #ifdef INET6 static int is_ifdisabled(char *); #endif static void set_source(struct ai_order *, struct policyhead *); static int comp_dst(const void *, const void *); #ifdef INET6 static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); #endif static int gai_addr2scopetype(struct sockaddr *); static int explore_fqdn(const struct addrinfo *, const char *, const char *, struct addrinfo **); static int reorder(struct addrinfo *); static int get_addrselectpolicy(struct policyhead *); static void free_addrselectpolicy(struct policyhead *); static struct policyqueue *match_addrselectpolicy(struct sockaddr *, struct policyhead *); static int matchlen(struct sockaddr *, struct sockaddr *); static struct addrinfo *getanswer(const querybuf *, int, const char *, int, const struct addrinfo *, res_state); #if defined(RESOLVSORT) static int addr4sort(struct addrinfo *, res_state); #endif static int _dns_getaddrinfo(void *, void *, va_list); static void _sethtent(FILE **); static void _endhtent(FILE **); static struct addrinfo *_gethtent(FILE **, const char *, const struct addrinfo *); static int _files_getaddrinfo(void *, void *, va_list); #ifdef YP static struct addrinfo *_yphostent(char *, const struct addrinfo *); static int _yp_getaddrinfo(void *, void *, va_list); #endif #ifdef NS_CACHING static int addrinfo_id_func(char *, size_t *, va_list, void *); static int addrinfo_marshal_func(char *, size_t *, void *, va_list, void *); static int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *); #endif static int res_queryN(const char *, struct res_target *, res_state); static int res_searchN(const char *, struct res_target *, res_state); static int res_querydomainN(const char *, const char *, struct res_target *, res_state); /* XXX macros that make external reference is BAD. */ #define GET_AI(ai, afd, addr) \ do { \ /* external reference: pai, error, and label free */ \ (ai) = get_ai(pai, (afd), (addr)); \ if ((ai) == NULL) { \ error = EAI_MEMORY; \ goto free; \ } \ } while (/*CONSTCOND*/0) #define GET_PORT(ai, serv) \ do { \ /* external reference: error and label free */ \ error = get_port((ai), (serv), 0); \ if (error != 0) \ goto free; \ } while (/*CONSTCOND*/0) #define GET_CANONNAME(ai, str) \ do { \ /* external reference: pai, error and label free */ \ error = get_canonname(pai, (ai), (str)); \ if (error != 0) \ goto free; \ } while (/*CONSTCOND*/0) #define ERR(err) \ do { \ /* external reference: error, and label bad */ \ error = (err); \ goto bad; \ /*NOTREACHED*/ \ } while (/*CONSTCOND*/0) #define MATCH_FAMILY(x, y, w) \ ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) #define MATCH(x, y, w) \ ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) void freeaddrinfo(struct addrinfo *ai) { struct addrinfo *next; do { next = ai->ai_next; if (ai->ai_canonname) free(ai->ai_canonname); /* no need to free(ai->ai_addr) */ free(ai); ai = next; } while (ai); } static int str2number(const char *p, int *portp) { char *ep; unsigned long v; if (*p == '\0') return -1; ep = NULL; errno = 0; v = strtoul(p, &ep, 10); if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) { *portp = v; return 0; } else return -1; } int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { struct addrinfo sentinel; struct addrinfo *cur; int error = 0; struct addrinfo ai, ai0, *afai; struct addrinfo *pai; const struct afd *afd; const struct explore *ex; struct addrinfo *afailist[sizeof(afdl)/sizeof(afdl[0])]; struct addrinfo *afai_unspec; int found; int numeric = 0; /* ensure we return NULL on errors */ *res = NULL; memset(&ai, 0, sizeof(ai)); memset(afailist, 0, sizeof(afailist)); afai_unspec = NULL; memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; pai = &ai; pai->ai_flags = 0; pai->ai_family = PF_UNSPEC; pai->ai_socktype = ANY; pai->ai_protocol = ANY; pai->ai_addrlen = 0; pai->ai_canonname = NULL; pai->ai_addr = NULL; pai->ai_next = NULL; if (hostname == NULL && servname == NULL) return EAI_NONAME; if (hints) { /* error check for hints */ if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) ERR(EAI_BADHINTS); /* xxx */ if (hints->ai_flags & ~AI_MASK) ERR(EAI_BADFLAGS); switch (hints->ai_family) { case PF_UNSPEC: case PF_INET: #ifdef INET6 case PF_INET6: #endif break; default: ERR(EAI_FAMILY); } memcpy(pai, hints, sizeof(*pai)); /* * if both socktype/protocol are specified, check if they * are meaningful combination. */ if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { for (ex = explore; ex->e_af >= 0; ex++) { if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) continue; if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) continue; if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) continue; /* matched */ break; } if (ex->e_af < 0) ERR(EAI_BADHINTS); } } /* * check for special cases. (1) numeric servname is disallowed if * socktype/protocol are left unspecified. (2) servname is disallowed * for raw and other inet{,6} sockets. */ if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) #ifdef PF_INET6 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) #endif ) { ai0 = *pai; /* backup *pai */ if (pai->ai_family == PF_UNSPEC) { #ifdef PF_INET6 pai->ai_family = PF_INET6; #else pai->ai_family = PF_INET; #endif } error = get_portmatch(pai, servname); if (error) goto bad; *pai = ai0; } ai0 = *pai; /* * NULL hostname, or numeric hostname. * If numeric representation of AF1 can be interpreted as FQDN * representation of AF2, we need to think again about the code below. */ found = 0; for (afd = afdl; afd->a_af; afd++) { *pai = ai0; if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) continue; if (pai->ai_family == PF_UNSPEC) pai->ai_family = afd->a_af; if (hostname == NULL) { error = explore_null(pai, servname, &afailist[afd - afdl]); /* * Errors from explore_null should be unexpected and * be caught to avoid returning an incomplete result. */ if (error != 0) goto bad; } else { error = explore_numeric_scope(pai, hostname, servname, &afailist[afd - afdl]); /* * explore_numeric_scope returns an error for address * families that do not match that of hostname. * Thus we should not catch the error at this moment. */ } if (!error && afailist[afd - afdl]) found++; } if (found) { numeric = 1; goto globcopy; } if (hostname == NULL) ERR(EAI_NONAME); /* used to be EAI_NODATA */ if (pai->ai_flags & AI_NUMERICHOST) ERR(EAI_NONAME); if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) ERR(EAI_FAIL); /* * hostname as alphabetical name. */ *pai = ai0; error = explore_fqdn(pai, hostname, servname, &afai_unspec); globcopy: for (ex = explore; ex->e_af >= 0; ex++) { *pai = ai0; if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) continue; if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) continue; if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) continue; if (pai->ai_family == PF_UNSPEC) pai->ai_family = ex->e_af; if (pai->ai_socktype == ANY && ex->e_socktype != ANY) pai->ai_socktype = ex->e_socktype; if (pai->ai_protocol == ANY && ex->e_protocol != ANY) pai->ai_protocol = ex->e_protocol; /* * if the servname does not match socktype/protocol, ignore it. */ if (get_portmatch(pai, servname) != 0) continue; if (afai_unspec) afai = afai_unspec; else { if ((afd = find_afd(pai->ai_family)) == NULL) continue; /* XXX assumes that afd points inside afdl[] */ afai = afailist[afd - afdl]; } if (!afai) continue; error = explore_copy(pai, afai, &cur->ai_next); if (error != 0) goto bad; while (cur && cur->ai_next) cur = cur->ai_next; } /* * ensure we return either: * - error == 0, non-NULL *res * - error != 0, NULL *res */ if (error == 0) { if (sentinel.ai_next) { /* * If the returned entry is for an active connection, * and the given name is not numeric, reorder the * list, so that the application would try the list * in the most efficient order. Since the head entry * of the original list may contain ai_canonname and * that entry may be moved elsewhere in the new list, * we keep the pointer and will restore it in the new * head entry. (Note that RFC3493 requires the head * entry store it when requested by the caller). */ if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) { if (!numeric) { char *canonname; canonname = sentinel.ai_next->ai_canonname; sentinel.ai_next->ai_canonname = NULL; (void)reorder(&sentinel); if (sentinel.ai_next->ai_canonname == NULL) { sentinel.ai_next->ai_canonname = canonname; } else if (canonname != NULL) free(canonname); } } *res = sentinel.ai_next; } else error = EAI_FAIL; } bad: if (afai_unspec) freeaddrinfo(afai_unspec); for (afd = afdl; afd->a_af; afd++) { if (afailist[afd - afdl]) freeaddrinfo(afailist[afd - afdl]); } if (!*res) if (sentinel.ai_next) freeaddrinfo(sentinel.ai_next); return (error); } static int reorder(struct addrinfo *sentinel) { struct addrinfo *ai, **aip; struct ai_order *aio; int i, n; struct policyhead policyhead; /* count the number of addrinfo elements for sorting. */ for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++) ; /* * If the number is small enough, we can skip the reordering process. */ if (n <= 1) return(n); /* allocate a temporary array for sort and initialization of it. */ if ((aio = malloc(sizeof(*aio) * n)) == NULL) return(n); /* give up reordering */ memset(aio, 0, sizeof(*aio) * n); /* retrieve address selection policy from the kernel */ TAILQ_INIT(&policyhead); if (!get_addrselectpolicy(&policyhead)) { /* no policy is installed into kernel, we don't sort. */ free(aio); return (n); } for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) { aio[i].aio_ai = ai; aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr); aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr, &policyhead); set_source(&aio[i], &policyhead); } /* perform sorting. */ qsort(aio, n, sizeof(*aio), comp_dst); /* reorder the addrinfo chain. */ for (i = 0, aip = &sentinel->ai_next; i < n; i++) { *aip = aio[i].aio_ai; aip = &aio[i].aio_ai->ai_next; } *aip = NULL; /* cleanup and return */ free(aio); free_addrselectpolicy(&policyhead); return(n); } static int get_addrselectpolicy(struct policyhead *head) { #ifdef INET6 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; size_t l; char *buf; struct in6_addrpolicy *pol, *ep; if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) return (0); if (l == 0) return (0); if ((buf = malloc(l)) == NULL) return (0); if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { free(buf); return (0); } ep = (struct in6_addrpolicy *)(buf + l); for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { struct policyqueue *new; if ((new = malloc(sizeof(*new))) == NULL) { free_addrselectpolicy(head); /* make the list empty */ break; } new->pc_policy = *pol; TAILQ_INSERT_TAIL(head, new, pc_entry); } free(buf); return (1); #else return (0); #endif } static void free_addrselectpolicy(struct policyhead *head) { struct policyqueue *ent, *nent; for (ent = TAILQ_FIRST(head); ent; ent = nent) { nent = TAILQ_NEXT(ent, pc_entry); TAILQ_REMOVE(head, ent, pc_entry); free(ent); } } static struct policyqueue * match_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) { #ifdef INET6 struct policyqueue *ent, *bestent = NULL; struct in6_addrpolicy *pol; int matchlen, bestmatchlen = -1; u_char *mp, *ep, *k, *p, m; struct sockaddr_in6 key; switch(addr->sa_family) { case AF_INET6: key = *(struct sockaddr_in6 *)addr; break; case AF_INET: /* convert the address into IPv4-mapped IPv6 address. */ memset(&key, 0, sizeof(key)); key.sin6_family = AF_INET6; key.sin6_len = sizeof(key); key.sin6_addr.s6_addr[10] = 0xff; key.sin6_addr.s6_addr[11] = 0xff; memcpy(&key.sin6_addr.s6_addr[12], &((struct sockaddr_in *)addr)->sin_addr, 4); break; default: return(NULL); } for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { pol = &ent->pc_policy; matchlen = 0; mp = (u_char *)&pol->addrmask.sin6_addr; ep = mp + 16; /* XXX: scope field? */ k = (u_char *)&key.sin6_addr; p = (u_char *)&pol->addr.sin6_addr; for (; mp < ep && *mp; mp++, k++, p++) { m = *mp; if ((*k & m) != *p) goto next; /* not match */ if (m == 0xff) /* short cut for a typical case */ matchlen += 8; else { while (m >= 0x80) { matchlen++; m <<= 1; } } } /* matched. check if this is better than the current best. */ if (matchlen > bestmatchlen) { bestent = ent; bestmatchlen = matchlen; } next: continue; } return(bestent); #else return(NULL); #endif } static void set_source(struct ai_order *aio, struct policyhead *ph) { struct addrinfo ai = *aio->aio_ai; struct sockaddr_storage ss; socklen_t srclen; int s; /* set unspec ("no source is available"), just in case */ aio->aio_srcsa.sa_family = AF_UNSPEC; aio->aio_srcscope = -1; switch(ai.ai_family) { case AF_INET: #ifdef INET6 case AF_INET6: #endif break; default: /* ignore unsupported AFs explicitly */ return; } /* XXX: make a dummy addrinfo to call connect() */ ai.ai_socktype = SOCK_DGRAM; ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */ ai.ai_next = NULL; memset(&ss, 0, sizeof(ss)); memcpy(&ss, ai.ai_addr, ai.ai_addrlen); ai.ai_addr = (struct sockaddr *)&ss; get_port(&ai, "1", 0); /* open a socket to get the source address for the given dst */ if ((s = _socket(ai.ai_family, ai.ai_socktype | SOCK_CLOEXEC, ai.ai_protocol)) < 0) return; /* give up */ if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) goto cleanup; srclen = ai.ai_addrlen; if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { aio->aio_srcsa.sa_family = AF_UNSPEC; goto cleanup; } aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr); #ifdef INET6 if (ai.ai_family == AF_INET6) { struct in6_ifreq ifr6; u_int32_t flags6; memset(&ifr6, 0, sizeof(ifr6)); memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen); if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { flags6 = ifr6.ifr_ifru.ifru_flags6; if ((flags6 & IN6_IFF_DEPRECATED)) aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; } } #endif cleanup: _close(s); return; } static int matchlen(struct sockaddr *src, struct sockaddr *dst) { int match = 0; u_char *s, *d; u_char *lim, r; int addrlen; switch (src->sa_family) { #ifdef INET6 case AF_INET6: s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; addrlen = sizeof(struct in6_addr); lim = s + addrlen; break; #endif case AF_INET: s = (u_char *)&((struct sockaddr_in *)src)->sin_addr; d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr; addrlen = sizeof(struct in_addr); lim = s + addrlen; break; default: return(0); } while (s < lim) if ((r = (*d++ ^ *s++)) != 0) { while (r < addrlen * 8) { match++; r <<= 1; } break; } else match += 8; return(match); } static int comp_dst(const void *arg1, const void *arg2) { const struct ai_order *dst1 = arg1, *dst2 = arg2; /* * Rule 1: Avoid unusable destinations. * XXX: we currently do not consider if an appropriate route exists. */ if (dst1->aio_srcsa.sa_family != AF_UNSPEC && dst2->aio_srcsa.sa_family == AF_UNSPEC) { return(-1); } if (dst1->aio_srcsa.sa_family == AF_UNSPEC && dst2->aio_srcsa.sa_family != AF_UNSPEC) { return(1); } /* Rule 2: Prefer matching scope. */ if (dst1->aio_dstscope == dst1->aio_srcscope && dst2->aio_dstscope != dst2->aio_srcscope) { return(-1); } if (dst1->aio_dstscope != dst1->aio_srcscope && dst2->aio_dstscope == dst2->aio_srcscope) { return(1); } /* Rule 3: Avoid deprecated addresses. */ if (dst1->aio_srcsa.sa_family != AF_UNSPEC && dst2->aio_srcsa.sa_family != AF_UNSPEC) { if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { return(-1); } if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { return(1); } } /* Rule 4: Prefer home addresses. */ /* XXX: not implemented yet */ /* Rule 5: Prefer matching label. */ #ifdef INET6 if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && dst1->aio_srcpolicy->pc_policy.label == dst1->aio_dstpolicy->pc_policy.label && (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || dst2->aio_srcpolicy->pc_policy.label != dst2->aio_dstpolicy->pc_policy.label)) { return(-1); } if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && dst2->aio_srcpolicy->pc_policy.label == dst2->aio_dstpolicy->pc_policy.label && (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || dst1->aio_srcpolicy->pc_policy.label != dst1->aio_dstpolicy->pc_policy.label)) { return(1); } #endif /* Rule 6: Prefer higher precedence. */ #ifdef INET6 if (dst1->aio_dstpolicy && (dst2->aio_dstpolicy == NULL || dst1->aio_dstpolicy->pc_policy.preced > dst2->aio_dstpolicy->pc_policy.preced)) { return(-1); } if (dst2->aio_dstpolicy && (dst1->aio_dstpolicy == NULL || dst2->aio_dstpolicy->pc_policy.preced > dst1->aio_dstpolicy->pc_policy.preced)) { return(1); } #endif /* Rule 7: Prefer native transport. */ /* XXX: not implemented yet */ /* Rule 8: Prefer smaller scope. */ if (dst1->aio_dstscope >= 0 && dst1->aio_dstscope < dst2->aio_dstscope) { return(-1); } if (dst2->aio_dstscope >= 0 && dst2->aio_dstscope < dst1->aio_dstscope) { return(1); } /* * Rule 9: Use longest matching prefix. * We compare the match length in a same AF only. */ if (dst1->aio_ai->ai_addr->sa_family == dst2->aio_ai->ai_addr->sa_family && dst1->aio_ai->ai_addr->sa_family != AF_INET) { if (dst1->aio_matchlen > dst2->aio_matchlen) { return(-1); } if (dst1->aio_matchlen < dst2->aio_matchlen) { return(1); } } /* Rule 10: Otherwise, leave the order unchanged. */ return(-1); } /* * Copy from scope.c. * XXX: we should standardize the functions and link them as standard * library. */ static int gai_addr2scopetype(struct sockaddr *sa) { #ifdef INET6 struct sockaddr_in6 *sa6; #endif struct sockaddr_in *sa4; switch(sa->sa_family) { #ifdef INET6 case AF_INET6: sa6 = (struct sockaddr_in6 *)sa; if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { /* just use the scope field of the multicast address */ return(sa6->sin6_addr.s6_addr[2] & 0x0f); } /* * Unicast addresses: map scope type to corresponding scope * value defined for multcast addresses. * XXX: hardcoded scope type values are bad... */ if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) return(1); /* node local scope */ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) return(2); /* link-local scope */ if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) return(5); /* site-local scope */ return(14); /* global scope */ break; #endif case AF_INET: /* * IPv4 pseudo scoping according to RFC 3484. */ sa4 = (struct sockaddr_in *)sa; /* IPv4 autoconfiguration addresses have link-local scope. */ if (((u_char *)&sa4->sin_addr)[0] == 169 && ((u_char *)&sa4->sin_addr)[1] == 254) return(2); /* Private addresses have site-local scope. */ if (((u_char *)&sa4->sin_addr)[0] == 10 || (((u_char *)&sa4->sin_addr)[0] == 172 && (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || (((u_char *)&sa4->sin_addr)[0] == 192 && ((u_char *)&sa4->sin_addr)[1] == 168)) return(14); /* XXX: It should be 5 unless NAT */ /* Loopback addresses have link-local scope. */ if (((u_char *)&sa4->sin_addr)[0] == 127) return(2); return(14); break; default: errno = EAFNOSUPPORT; /* is this a good error? */ return(-1); } } static int explore_copy(const struct addrinfo *pai, const struct addrinfo *src0, struct addrinfo **res) { int error; struct addrinfo sentinel, *cur; const struct addrinfo *src; error = 0; sentinel.ai_next = NULL; cur = &sentinel; for (src = src0; src != NULL; src = src->ai_next) { if (src->ai_family != pai->ai_family) continue; cur->ai_next = copy_ai(src); if (!cur->ai_next) { error = EAI_MEMORY; goto fail; } cur->ai_next->ai_socktype = pai->ai_socktype; cur->ai_next->ai_protocol = pai->ai_protocol; cur = cur->ai_next; } *res = sentinel.ai_next; return 0; fail: freeaddrinfo(sentinel.ai_next); return error; } /* * hostname == NULL. * passive socket -> anyaddr (0.0.0.0 or ::) * non-passive socket -> localhost (127.0.0.1 or ::1) */ static int explore_null(const struct addrinfo *pai, const char *servname, struct addrinfo **res) { int s; const struct afd *afd; struct addrinfo *ai; int error; *res = NULL; ai = NULL; /* * filter out AFs that are not supported by the kernel * XXX errno? */ s = _socket(pai->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (s < 0) { if (errno != EMFILE) return 0; } else _close(s); afd = find_afd(pai->ai_family); if (afd == NULL) return 0; if (pai->ai_flags & AI_PASSIVE) { GET_AI(ai, afd, afd->a_addrany); GET_PORT(ai, servname); } else { GET_AI(ai, afd, afd->a_loopback); GET_PORT(ai, servname); } *res = ai; return 0; free: if (ai != NULL) freeaddrinfo(ai); return error; } /* * numeric hostname */ static int explore_numeric(const struct addrinfo *pai, const char *hostname, const char *servname, struct addrinfo **res, const char *canonname) { const struct afd *afd; struct addrinfo *ai; int error; char pton[PTON_MAX]; *res = NULL; ai = NULL; afd = find_afd(pai->ai_family); if (afd == NULL) return 0; switch (afd->a_af) { case AF_INET: /* * RFC3493 requires getaddrinfo() to accept AF_INET formats * that are accepted by inet_addr() and its family. The * accepted forms includes the "classful" one, which inet_pton * does not accept. So we need to separate the case for * AF_INET. */ if (inet_aton(hostname, (struct in_addr *)pton) != 1) return 0; break; default: if (inet_pton(afd->a_af, hostname, pton) != 1) return 0; break; } if (pai->ai_family == afd->a_af) { GET_AI(ai, afd, pton); GET_PORT(ai, servname); if ((pai->ai_flags & AI_CANONNAME)) { /* * Set the numeric address itself as the canonical * name, based on a clarification in RFC3493. */ GET_CANONNAME(ai, canonname); } } else { /* * XXX: This should not happen since we already matched the AF * by find_afd. */ ERR(EAI_FAMILY); } *res = ai; return 0; free: bad: if (ai != NULL) freeaddrinfo(ai); return error; } /* * numeric hostname with scope */ static int explore_numeric_scope(const struct addrinfo *pai, const char *hostname, const char *servname, struct addrinfo **res) { #if !defined(SCOPE_DELIMITER) || !defined(INET6) return explore_numeric(pai, hostname, servname, res, hostname); #else const struct afd *afd; struct addrinfo *cur; int error; char *cp, *hostname2 = NULL, *scope, *addr; struct sockaddr_in6 *sin6; afd = find_afd(pai->ai_family); if (afd == NULL) return 0; if (!afd->a_scoped) return explore_numeric(pai, hostname, servname, res, hostname); cp = strchr(hostname, SCOPE_DELIMITER); if (cp == NULL) return explore_numeric(pai, hostname, servname, res, hostname); /* * Handle special case of */ hostname2 = strdup(hostname); if (hostname2 == NULL) return EAI_MEMORY; /* terminate at the delimiter */ hostname2[cp - hostname] = '\0'; addr = hostname2; scope = cp + 1; error = explore_numeric(pai, addr, servname, res, hostname); if (error == 0) { u_int32_t scopeid; for (cur = *res; cur; cur = cur->ai_next) { if (cur->ai_family != AF_INET6) continue; sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { free(hostname2); freeaddrinfo(*res); *res = NULL; return(EAI_NONAME); /* XXX: is return OK? */ } sin6->sin6_scope_id = scopeid; } } free(hostname2); if (error && *res) { freeaddrinfo(*res); *res = NULL; } return error; #endif } static int get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) { if ((pai->ai_flags & AI_CANONNAME) != 0) { ai->ai_canonname = strdup(str); if (ai->ai_canonname == NULL) return EAI_MEMORY; } return 0; } static struct addrinfo * get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) { char *p; struct addrinfo *ai; ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + (afd->a_socklen)); if (ai == NULL) return NULL; memcpy(ai, pai, sizeof(struct addrinfo)); ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); memset(ai->ai_addr, 0, (size_t)afd->a_socklen); ai->ai_addr->sa_len = afd->a_socklen; ai->ai_addrlen = afd->a_socklen; ai->ai_addr->sa_family = ai->ai_family = afd->a_af; p = (char *)(void *)(ai->ai_addr); memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); return ai; } /* XXX need to malloc() the same way we do from other functions! */ static struct addrinfo * copy_ai(const struct addrinfo *pai) { struct addrinfo *ai; size_t l; l = sizeof(*ai) + pai->ai_addrlen; if ((ai = (struct addrinfo *)malloc(l)) == NULL) return NULL; memset(ai, 0, l); memcpy(ai, pai, sizeof(*ai)); ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen); if (pai->ai_canonname) { l = strlen(pai->ai_canonname) + 1; if ((ai->ai_canonname = malloc(l)) == NULL) { free(ai); return NULL; } strlcpy(ai->ai_canonname, pai->ai_canonname, l); } else { /* just to make sure */ ai->ai_canonname = NULL; } ai->ai_next = NULL; return ai; } static int get_portmatch(const struct addrinfo *ai, const char *servname) { /* get_port does not touch first argument when matchonly == 1. */ /* LINTED const cast */ return get_port((struct addrinfo *)ai, servname, 1); } static int get_port(struct addrinfo *ai, const char *servname, int matchonly) { const char *proto; struct servent *sp; int port, error; int allownumeric; if (servname == NULL) return 0; switch (ai->ai_family) { case AF_INET: #ifdef AF_INET6 case AF_INET6: #endif break; default: return 0; } switch (ai->ai_socktype) { case SOCK_RAW: return EAI_SERVICE; case SOCK_DGRAM: case SOCK_STREAM: case SOCK_SEQPACKET: allownumeric = 1; break; case ANY: switch (ai->ai_family) { case AF_INET: #ifdef AF_INET6 case AF_INET6: #endif allownumeric = 1; break; default: allownumeric = 0; break; } break; default: return EAI_SOCKTYPE; } error = str2number(servname, &port); if (error == 0) { if (!allownumeric) return EAI_SERVICE; if (port < 0 || port > 65535) return EAI_SERVICE; port = htons(port); } else { if (ai->ai_flags & AI_NUMERICSERV) return EAI_NONAME; switch (ai->ai_protocol) { case IPPROTO_UDP: proto = "udp"; break; case IPPROTO_TCP: proto = "tcp"; break; case IPPROTO_SCTP: proto = "sctp"; break; case IPPROTO_UDPLITE: proto = "udplite"; break; default: proto = NULL; break; } if ((sp = getservbyname(servname, proto)) == NULL) return EAI_SERVICE; port = sp->s_port; } if (!matchonly) { switch (ai->ai_family) { case AF_INET: ((struct sockaddr_in *)(void *) ai->ai_addr)->sin_port = port; break; #ifdef INET6 case AF_INET6: ((struct sockaddr_in6 *)(void *) ai->ai_addr)->sin6_port = port; break; #endif } } return 0; } static const struct afd * find_afd(int af) { const struct afd *afd; if (af == PF_UNSPEC) return NULL; for (afd = afdl; afd->a_af; afd++) { if (afd->a_af == af) return afd; } return NULL; } /* * RFC 3493: AI_ADDRCONFIG check. Determines which address families are * configured on the local system and correlates with pai->ai_family value. * If an address family is not configured on the system, it will not be * queried for. For this purpose, loopback addresses are not considered * configured addresses. * * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with * _dns_getaddrinfo. */ static int addrconfig(struct addrinfo *pai) { struct ifaddrs *ifaddrs, *ifa; struct sockaddr_in *sin; #ifdef INET6 struct sockaddr_in6 *sin6; #endif int seen_inet = 0, seen_inet6 = 0; if (getifaddrs(&ifaddrs) != 0) return (0); for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_UP) == 0) continue; switch (ifa->ifa_addr->sa_family) { case AF_INET: if (seen_inet) continue; sin = (struct sockaddr_in *)(ifa->ifa_addr); if (IN_LOOPBACK(htonl(sin->sin_addr.s_addr))) continue; seen_inet = 1; break; #ifdef INET6 case AF_INET6: if (seen_inet6) continue; sin6 = (struct sockaddr_in6 *)(ifa->ifa_addr); if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) continue; if ((ifa->ifa_flags & IFT_LOOP) != 0 && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) continue; if (is_ifdisabled(ifa->ifa_name)) continue; seen_inet6 = 1; break; #endif } } freeifaddrs(ifaddrs); switch(pai->ai_family) { case AF_INET6: return (seen_inet6); case AF_INET: return (seen_inet); case AF_UNSPEC: if (seen_inet == seen_inet6) return (seen_inet); pai->ai_family = seen_inet ? AF_INET : AF_INET6; return (1); } return (1); } #ifdef INET6 static int is_ifdisabled(char *name) { struct in6_ndireq nd; int fd; if ((fd = _socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) return (-1); memset(&nd, 0, sizeof(nd)); strlcpy(nd.ifname, name, sizeof(nd.ifname)); if (_ioctl(fd, SIOCGIFINFO_IN6, &nd) < 0) { _close(fd); return (-1); } _close(fd); return ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0); } /* convert a string to a scope identifier. XXX: IPv6 specific */ static int ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) { u_long lscopeid; struct in6_addr *a6; char *ep; a6 = &sin6->sin6_addr; /* empty scopeid portion is invalid */ if (*scope == '\0') return -1; if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) || IN6_IS_ADDR_MC_NODELOCAL(a6)) { /* * We currently assume a one-to-one mapping between links * and interfaces, so we simply use interface indices for * like-local scopes. */ *scopeid = if_nametoindex(scope); if (*scopeid == 0) goto trynumeric; return 0; } /* still unclear about literal, allow numeric only - placeholder */ if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) goto trynumeric; if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) goto trynumeric; else goto trynumeric; /* global */ /* try to convert to a numeric id as a last resort */ trynumeric: errno = 0; lscopeid = strtoul(scope, &ep, 10); *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) return 0; else return -1; } #endif #ifdef NS_CACHING static int addrinfo_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) { res_state statp; u_long res_options; const int op_id = 0; /* identifies the getaddrinfo for the cache */ char *hostname; struct addrinfo *hints; char *p; int ai_flags, ai_family, ai_socktype, ai_protocol; size_t desired_size, size; statp = __res_state(); res_options = statp->options & (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH | RES_NOALIASES | RES_USE_INET6); hostname = va_arg(ap, char *); hints = va_arg(ap, struct addrinfo *); desired_size = sizeof(res_options) + sizeof(int) + sizeof(int) * 4; if (hostname != NULL) { size = strlen(hostname); desired_size += size + 1; } else size = 0; if (desired_size > *buffer_size) { *buffer_size = desired_size; return (NS_RETURN); } if (hints == NULL) ai_flags = ai_family = ai_socktype = ai_protocol = 0; else { ai_flags = hints->ai_flags; ai_family = hints->ai_family; ai_socktype = hints->ai_socktype; ai_protocol = hints->ai_protocol; } p = buffer; memcpy(p, &res_options, sizeof(res_options)); p += sizeof(res_options); memcpy(p, &op_id, sizeof(int)); p += sizeof(int); memcpy(p, &ai_flags, sizeof(int)); p += sizeof(int); memcpy(p, &ai_family, sizeof(int)); p += sizeof(int); memcpy(p, &ai_socktype, sizeof(int)); p += sizeof(int); memcpy(p, &ai_protocol, sizeof(int)); p += sizeof(int); if (hostname != NULL) memcpy(p, hostname, size); *buffer_size = desired_size; return (NS_SUCCESS); } static int addrinfo_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, void *cache_mdata) { struct addrinfo *ai, *cai; char *p; size_t desired_size, size, ai_size; ai = *((struct addrinfo **)retval); desired_size = sizeof(size_t); ai_size = 0; for (cai = ai; cai != NULL; cai = cai->ai_next) { desired_size += sizeof(struct addrinfo) + cai->ai_addrlen; if (cai->ai_canonname != NULL) desired_size += sizeof(size_t) + strlen(cai->ai_canonname); ++ai_size; } if (desired_size > *buffer_size) { /* this assignment is here for future use */ errno = ERANGE; *buffer_size = desired_size; return (NS_RETURN); } memset(buffer, 0, desired_size); p = buffer; memcpy(p, &ai_size, sizeof(size_t)); p += sizeof(size_t); for (cai = ai; cai != NULL; cai = cai->ai_next) { memcpy(p, cai, sizeof(struct addrinfo)); p += sizeof(struct addrinfo); memcpy(p, cai->ai_addr, cai->ai_addrlen); p += cai->ai_addrlen; if (cai->ai_canonname != NULL) { size = strlen(cai->ai_canonname); memcpy(p, &size, sizeof(size_t)); p += sizeof(size_t); memcpy(p, cai->ai_canonname, size); p += size; } } return (NS_SUCCESS); } static int addrinfo_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, void *cache_mdata) { struct addrinfo new_ai, *result, *sentinel, *lasts; char *p; size_t ai_size, ai_i, size; p = buffer; memcpy(&ai_size, p, sizeof(size_t)); p += sizeof(size_t); result = NULL; lasts = NULL; for (ai_i = 0; ai_i < ai_size; ++ai_i) { memcpy(&new_ai, p, sizeof(struct addrinfo)); p += sizeof(struct addrinfo); size = new_ai.ai_addrlen + sizeof(struct addrinfo) + _ALIGNBYTES; sentinel = (struct addrinfo *)malloc(size); memset(sentinel, 0, size); memcpy(sentinel, &new_ai, sizeof(struct addrinfo)); sentinel->ai_addr = (struct sockaddr *)_ALIGN((char *)sentinel + sizeof(struct addrinfo)); memcpy(sentinel->ai_addr, p, new_ai.ai_addrlen); p += new_ai.ai_addrlen; if (new_ai.ai_canonname != NULL) { memcpy(&size, p, sizeof(size_t)); p += sizeof(size_t); sentinel->ai_canonname = (char *)malloc(size + 1); memset(sentinel->ai_canonname, 0, size + 1); memcpy(sentinel->ai_canonname, p, size); p += size; } if (result == NULL) { result = sentinel; lasts = sentinel; } else { lasts->ai_next = sentinel; lasts = sentinel; } } *((struct addrinfo **)retval) = result; return (NS_SUCCESS); } #endif /* NS_CACHING */ /* * FQDN hostname, DNS lookup */ static int explore_fqdn(const struct addrinfo *pai, const char *hostname, const char *servname, struct addrinfo **res) { struct addrinfo *result; struct addrinfo *cur; int error = 0; #ifdef NS_CACHING static const nss_cache_info cache_info = NS_COMMON_CACHE_INFO_INITIALIZER( hosts, NULL, addrinfo_id_func, addrinfo_marshal_func, addrinfo_unmarshal_func); #endif static const ns_dtab dtab[] = { NS_FILES_CB(_files_getaddrinfo, NULL) { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ NS_NIS_CB(_yp_getaddrinfo, NULL) #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif { 0 } }; result = NULL; /* * if the servname does not match socktype/protocol, ignore it. */ if (get_portmatch(pai, servname) != 0) return 0; switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", default_dns_files, hostname, pai)) { case NS_TRYAGAIN: error = EAI_AGAIN; goto free; case NS_UNAVAIL: error = EAI_FAIL; goto free; case NS_NOTFOUND: error = EAI_NONAME; goto free; case NS_SUCCESS: error = 0; for (cur = result; cur; cur = cur->ai_next) { GET_PORT(cur, servname); /* canonname should be filled already */ } break; } *res = result; return 0; free: if (result) freeaddrinfo(result); return error; } #ifdef DEBUG static const char AskedForGot[] = "gethostby*.getanswer: asked for \"%s\", got \"%s\""; #endif static struct addrinfo * getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, const struct addrinfo *pai, res_state res) { struct addrinfo sentinel, *cur; struct addrinfo ai; const struct afd *afd; char *canonname; const HEADER *hp; const u_char *cp; int n; const u_char *eom; char *bp, *ep; int type, class, ancount, qdcount; int haveanswer, had_error; char tbuf[MAXDNAME]; int (*name_ok)(const char *); char hostbuf[8*1024]; memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; canonname = NULL; eom = answer->buf + anslen; switch (qtype) { case T_A: case T_AAAA: case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ name_ok = res_hnok; break; default: return (NULL); /* XXX should be abort(); */ } /* * find first satisfactory answer */ hp = &answer->hdr; ancount = ntohs(hp->ancount); qdcount = ntohs(hp->qdcount); bp = hostbuf; ep = hostbuf + sizeof hostbuf; cp = answer->buf + HFIXEDSZ; if (qdcount != 1) { RES_SET_H_ERRNO(res, NO_RECOVERY); return (NULL); } n = dn_expand(answer->buf, eom, cp, bp, ep - bp); if ((n < 0) || !(*name_ok)(bp)) { RES_SET_H_ERRNO(res, NO_RECOVERY); return (NULL); } cp += n + QFIXEDSZ; if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { /* res_send() has already verified that the query name is the * same as the one we sent; this just gets the expanded name * (i.e., with the succeeding search-domain tacked on). */ n = strlen(bp) + 1; /* for the \0 */ if (n >= MAXHOSTNAMELEN) { RES_SET_H_ERRNO(res, NO_RECOVERY); return (NULL); } canonname = bp; bp += n; /* The qname can be abbreviated, but h_name is now absolute. */ qname = canonname; } haveanswer = 0; had_error = 0; while (ancount-- > 0 && cp < eom && !had_error) { n = dn_expand(answer->buf, eom, cp, bp, ep - bp); if ((n < 0) || !(*name_ok)(bp)) { had_error++; continue; } cp += n; /* name */ type = _getshort(cp); cp += INT16SZ; /* type */ class = _getshort(cp); cp += INT16SZ + INT32SZ; /* class, TTL */ n = _getshort(cp); cp += INT16SZ; /* len */ if (class != C_IN) { /* XXX - debug? syslog? */ cp += n; continue; /* XXX - had_error++ ? */ } if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && type == T_CNAME) { n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); if ((n < 0) || !(*name_ok)(tbuf)) { had_error++; continue; } cp += n; /* Get canonical name. */ n = strlen(tbuf) + 1; /* for the \0 */ if (n > ep - bp || n >= MAXHOSTNAMELEN) { had_error++; continue; } strlcpy(bp, tbuf, ep - bp); canonname = bp; bp += n; continue; } if (qtype == T_ANY) { if (!(type == T_A || type == T_AAAA)) { cp += n; continue; } } else if (type != qtype) { #ifdef DEBUG if (type != T_KEY && type != T_SIG && type != ns_t_dname) syslog(LOG_NOTICE|LOG_AUTH, "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", qname, p_class(C_IN), p_type(qtype), p_type(type)); #endif cp += n; continue; /* XXX - had_error++ ? */ } switch (type) { case T_A: case T_AAAA: if (strcasecmp(canonname, bp) != 0) { #ifdef DEBUG syslog(LOG_NOTICE|LOG_AUTH, AskedForGot, canonname, bp); #endif cp += n; continue; /* XXX - had_error++ ? */ } if (type == T_A && n != INADDRSZ) { cp += n; continue; } if (type == T_AAAA && n != IN6ADDRSZ) { cp += n; continue; } #ifdef FILTER_V4MAPPED if (type == T_AAAA) { struct in6_addr in6; memcpy(&in6, cp, sizeof(in6)); if (IN6_IS_ADDR_V4MAPPED(&in6)) { cp += n; continue; } } #endif if (!haveanswer) { int nn; canonname = bp; nn = strlen(bp) + 1; /* for the \0 */ bp += nn; } /* don't overwrite pai */ ai = *pai; ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; afd = find_afd(ai.ai_family); if (afd == NULL) { cp += n; continue; } cur->ai_next = get_ai(&ai, afd, (const char *)cp); if (cur->ai_next == NULL) had_error++; while (cur && cur->ai_next) cur = cur->ai_next; cp += n; break; default: abort(); } if (!had_error) haveanswer++; } if (haveanswer) { #if defined(RESOLVSORT) /* * We support only IPv4 address for backward * compatibility against gethostbyname(3). */ if (res->nsort && qtype == T_A) { if (addr4sort(&sentinel, res) < 0) { freeaddrinfo(sentinel.ai_next); RES_SET_H_ERRNO(res, NO_RECOVERY); return NULL; } } #endif /*RESOLVSORT*/ if (!canonname) (void)get_canonname(pai, sentinel.ai_next, qname); else (void)get_canonname(pai, sentinel.ai_next, canonname); RES_SET_H_ERRNO(res, NETDB_SUCCESS); return sentinel.ai_next; } RES_SET_H_ERRNO(res, NO_RECOVERY); return NULL; } #ifdef RESOLVSORT struct addr_ptr { struct addrinfo *ai; int aval; }; static int addr4sort(struct addrinfo *sentinel, res_state res) { struct addrinfo *ai; struct addr_ptr *addrs, addr; struct sockaddr_in *sin; int naddrs, i, j; int needsort = 0; if (!sentinel) return -1; naddrs = 0; for (ai = sentinel->ai_next; ai; ai = ai->ai_next) naddrs++; if (naddrs < 2) return 0; /* We don't need sorting. */ if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) return -1; i = 0; for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { sin = (struct sockaddr_in *)ai->ai_addr; for (j = 0; (unsigned)j < res->nsort; j++) { if (res->sort_list[j].addr.s_addr == (sin->sin_addr.s_addr & res->sort_list[j].mask)) break; } addrs[i].ai = ai; addrs[i].aval = j; if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) needsort = i; i++; } if (!needsort) { free(addrs); return 0; } while (needsort < naddrs) { for (j = needsort - 1; j >= 0; j--) { if (addrs[j].aval > addrs[j+1].aval) { addr = addrs[j]; addrs[j] = addrs[j + 1]; addrs[j + 1] = addr; } else break; } needsort++; } ai = sentinel; for (i = 0; i < naddrs; ++i) { ai->ai_next = addrs[i].ai; ai = ai->ai_next; } ai->ai_next = NULL; free(addrs); return 0; } #endif /*RESOLVSORT*/ /*ARGSUSED*/ static int _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) { struct addrinfo *ai; querybuf *buf, *buf2; const char *hostname; const struct addrinfo *pai; struct addrinfo sentinel, *cur; struct res_target q, q2; res_state res; hostname = va_arg(ap, char *); pai = va_arg(ap, const struct addrinfo *); memset(&q, 0, sizeof(q)); memset(&q2, 0, sizeof(q2)); memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; buf = malloc(sizeof(*buf)); if (!buf) { RES_SET_H_ERRNO(res, NETDB_INTERNAL); return NS_NOTFOUND; } buf2 = malloc(sizeof(*buf2)); if (!buf2) { free(buf); RES_SET_H_ERRNO(res, NETDB_INTERNAL); return NS_NOTFOUND; } switch (pai->ai_family) { case AF_UNSPEC: q.name = hostname; q.qclass = C_IN; q.qtype = T_A; q.answer = buf->buf; q.anslen = sizeof(buf->buf); q.next = &q2; q2.name = hostname; q2.qclass = C_IN; q2.qtype = T_AAAA; q2.answer = buf2->buf; q2.anslen = sizeof(buf2->buf); break; case AF_INET: q.name = hostname; q.qclass = C_IN; q.qtype = T_A; q.answer = buf->buf; q.anslen = sizeof(buf->buf); break; case AF_INET6: q.name = hostname; q.qclass = C_IN; q.qtype = T_AAAA; q.answer = buf->buf; q.anslen = sizeof(buf->buf); break; default: free(buf); free(buf2); return NS_UNAVAIL; } res = __res_state(); if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) { RES_SET_H_ERRNO(res, NETDB_INTERNAL); free(buf); free(buf2); return NS_NOTFOUND; } if (res_searchN(hostname, &q, res) < 0) { free(buf); free(buf2); return NS_NOTFOUND; } /* prefer IPv6 */ if (q.next) { ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res); if (ai) { cur->ai_next = ai; while (cur && cur->ai_next) cur = cur->ai_next; } } ai = getanswer(buf, q.n, q.name, q.qtype, pai, res); if (ai) cur->ai_next = ai; free(buf); free(buf2); if (sentinel.ai_next == NULL) switch (res->res_h_errno) { case HOST_NOT_FOUND: return NS_NOTFOUND; case TRY_AGAIN: return NS_TRYAGAIN; default: return NS_UNAVAIL; } *((struct addrinfo **)rv) = sentinel.ai_next; return NS_SUCCESS; } static void _sethtent(FILE **hostf) { if (!*hostf) *hostf = fopen(_PATH_HOSTS, "re"); else rewind(*hostf); } static void _endhtent(FILE **hostf) { if (*hostf) { (void) fclose(*hostf); *hostf = NULL; } } static struct addrinfo * _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) { char *p; char *cp, *tname, *cname; struct addrinfo hints, *res0, *res; int error; const char *addr; char hostbuf[8*1024]; if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re"))) return (NULL); again: if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) return (NULL); if (*p == '#') goto again; cp = strpbrk(p, "#\n"); if (cp != NULL) *cp = '\0'; if (!(cp = strpbrk(p, " \t"))) goto again; *cp++ = '\0'; addr = p; cname = NULL; /* if this is not something we're looking for, skip it. */ while (cp && *cp) { if (*cp == ' ' || *cp == '\t') { cp++; continue; } tname = cp; if (cname == NULL) cname = cp; if ((cp = strpbrk(cp, " \t")) != NULL) *cp++ = '\0'; if (strcasecmp(name, tname) == 0) goto found; } goto again; found: /* we should not glob socktype/protocol here */ memset(&hints, 0, sizeof(hints)); hints.ai_family = pai->ai_family; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = 0; hints.ai_flags = AI_NUMERICHOST; error = getaddrinfo(addr, "0", &hints, &res0); if (error) goto again; #ifdef FILTER_V4MAPPED /* XXX should check all items in the chain */ if (res0->ai_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { freeaddrinfo(res0); goto again; } #endif for (res = res0; res; res = res->ai_next) { /* cover it up */ res->ai_flags = pai->ai_flags; res->ai_socktype = pai->ai_socktype; res->ai_protocol = pai->ai_protocol; if (pai->ai_flags & AI_CANONNAME) { if (get_canonname(pai, res, cname) != 0) { freeaddrinfo(res0); goto again; } } } return res0; } /*ARGSUSED*/ static int _files_getaddrinfo(void *rv, void *cb_data, va_list ap) { const char *name; const struct addrinfo *pai; struct addrinfo sentinel, *cur; struct addrinfo *p; FILE *hostf = NULL; name = va_arg(ap, char *); pai = va_arg(ap, struct addrinfo *); memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; _sethtent(&hostf); while ((p = _gethtent(&hostf, name, pai)) != NULL) { cur->ai_next = p; while (cur && cur->ai_next) cur = cur->ai_next; } _endhtent(&hostf); *((struct addrinfo **)rv) = sentinel.ai_next; if (sentinel.ai_next == NULL) return NS_NOTFOUND; return NS_SUCCESS; } #ifdef YP /*ARGSUSED*/ static struct addrinfo * _yphostent(char *line, const struct addrinfo *pai) { struct addrinfo sentinel, *cur; struct addrinfo hints, *res, *res0; int error; char *p = line; const char *addr, *canonname; char *nextline; char *cp; addr = canonname = NULL; memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; nextline: /* terminate line */ cp = strchr(p, '\n'); if (cp) { *cp++ = '\0'; nextline = cp; } else nextline = NULL; cp = strpbrk(p, " \t"); if (cp == NULL) { if (canonname == NULL) return (NULL); else goto done; } *cp++ = '\0'; addr = p; while (cp && *cp) { if (*cp == ' ' || *cp == '\t') { cp++; continue; } if (!canonname) canonname = cp; if ((cp = strpbrk(cp, " \t")) != NULL) *cp++ = '\0'; } hints = *pai; hints.ai_flags = AI_NUMERICHOST; error = getaddrinfo(addr, NULL, &hints, &res0); if (error == 0) { for (res = res0; res; res = res->ai_next) { /* cover it up */ res->ai_flags = pai->ai_flags; if (pai->ai_flags & AI_CANONNAME) (void)get_canonname(pai, res, canonname); } } else res0 = NULL; if (res0) { cur->ai_next = res0; while (cur && cur->ai_next) cur = cur->ai_next; } if (nextline) { p = nextline; goto nextline; } done: return sentinel.ai_next; } /*ARGSUSED*/ static int _yp_getaddrinfo(void *rv, void *cb_data, va_list ap) { struct addrinfo sentinel, *cur; struct addrinfo *ai = NULL; char *ypbuf; int ypbuflen, r; const char *name; const struct addrinfo *pai; char *ypdomain; if (_yp_check(&ypdomain) == 0) return NS_UNAVAIL; name = va_arg(ap, char *); pai = va_arg(ap, const struct addrinfo *); memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; /* hosts.byname is only for IPv4 (Solaris8) */ if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { r = yp_match(ypdomain, "hosts.byname", name, (int)strlen(name), &ypbuf, &ypbuflen); if (r == 0) { struct addrinfo ai4; ai4 = *pai; ai4.ai_family = AF_INET; ai = _yphostent(ypbuf, &ai4); if (ai) { cur->ai_next = ai; while (cur && cur->ai_next) cur = cur->ai_next; } free(ypbuf); } } /* ipnodes.byname can hold both IPv4/v6 */ r = yp_match(ypdomain, "ipnodes.byname", name, (int)strlen(name), &ypbuf, &ypbuflen); if (r == 0) { ai = _yphostent(ypbuf, pai); if (ai) cur->ai_next = ai; free(ypbuf); } if (sentinel.ai_next == NULL) { RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND); return NS_NOTFOUND; } *((struct addrinfo **)rv) = sentinel.ai_next; return NS_SUCCESS; } #endif /* resolver logic */ /* * Formulate a normal query, send, and await answer. * Returned answer is placed in supplied buffer "answer". * Perform preliminary check of answer, returning success only * if no error is indicated and the answer count is nonzero. * Return the size of the response on success, -1 on error. * Error number is left in h_errno. * * Caller must parse answer and determine whether it answers the question. */ static int res_queryN(const char *name, struct res_target *target, res_state res) { u_char *buf; HEADER *hp; int n; u_int oflags; struct res_target *t; int rcode; int ancount; rcode = NOERROR; ancount = 0; buf = malloc(MAXPACKET); if (!buf) { RES_SET_H_ERRNO(res, NETDB_INTERNAL); return -1; } for (t = target; t; t = t->next) { int class, type; u_char *answer; int anslen; hp = (HEADER *)(void *)t->answer; /* make it easier... */ class = t->qclass; type = t->qtype; answer = t->answer; anslen = t->anslen; oflags = res->_flags; again: hp->rcode = NOERROR; /* default */ #ifdef DEBUG if (res->options & RES_DEBUG) printf(";; res_query(%s, %d, %d)\n", name, class, type); #endif n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, buf, MAXPACKET); if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 && (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U) n = res_nopt(res, n, buf, MAXPACKET, anslen); if (n <= 0) { #ifdef DEBUG if (res->options & RES_DEBUG) printf(";; res_query: mkquery failed\n"); #endif free(buf); RES_SET_H_ERRNO(res, NO_RECOVERY); return (n); } n = res_nsend(res, buf, n, answer, anslen); if (n < 0) { /* * if the query choked with EDNS0, retry * without EDNS0 */ if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U && ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) { res->_flags |= RES_F_EDNS0ERR; if (res->options & RES_DEBUG) printf(";; res_nquery: retry without EDNS0\n"); goto again; } rcode = hp->rcode; /* record most recent error */ #ifdef DEBUG if (res->options & RES_DEBUG) printf(";; res_query: send error\n"); #endif continue; } if (n > anslen) hp->rcode = FORMERR; /* XXX not very informative */ if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { rcode = hp->rcode; /* record most recent error */ #ifdef DEBUG if (res->options & RES_DEBUG) printf(";; rcode = %u, ancount=%u\n", hp->rcode, ntohs(hp->ancount)); #endif continue; } ancount += ntohs(hp->ancount); t->n = n; } free(buf); if (ancount == 0) { switch (rcode) { case NXDOMAIN: RES_SET_H_ERRNO(res, HOST_NOT_FOUND); break; case SERVFAIL: RES_SET_H_ERRNO(res, TRY_AGAIN); break; case NOERROR: RES_SET_H_ERRNO(res, NO_DATA); break; case FORMERR: case NOTIMP: case REFUSED: default: RES_SET_H_ERRNO(res, NO_RECOVERY); break; } return (-1); } return (ancount); } /* * Formulate a normal query, send, and retrieve answer in supplied buffer. * Return the size of the response on success, -1 on error. * If enabled, implement search rules until answer or unrecoverable failure * is detected. Error code, if any, is left in h_errno. */ static int res_searchN(const char *name, struct res_target *target, res_state res) { const char *cp, * const *domain; HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ u_int dots; int trailing_dot, ret, saved_herrno; int got_nodata = 0, got_servfail = 0, root_on_list = 0; int tried_as_is = 0; int searched = 0; char abuf[MAXDNAME]; errno = 0; RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */ dots = 0; for (cp = name; *cp; cp++) dots += (*cp == '.'); trailing_dot = 0; if (cp > name && *--cp == '.') trailing_dot++; /* * if there aren't any dots, it could be a user-level alias */ if (!dots && (cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL) return (res_queryN(cp, target, res)); /* * If there are enough dots in the name, let's just give it a * try 'as is'. The threshold can be set with the "ndots" option. * Also, query 'as is', if there is a trailing dot in the name. */ saved_herrno = -1; if (dots >= res->ndots || trailing_dot) { ret = res_querydomainN(name, NULL, target, res); if (ret > 0 || trailing_dot) return (ret); if (errno == ECONNREFUSED) { RES_SET_H_ERRNO(res, TRY_AGAIN); return (-1); } switch (res->res_h_errno) { case NO_DATA: case HOST_NOT_FOUND: break; case TRY_AGAIN: if (hp->rcode == SERVFAIL) break; /* FALLTHROUGH */ default: return (-1); } saved_herrno = res->res_h_errno; tried_as_is++; } /* * We do at least one level of search if * - there is no dot and RES_DEFNAME is set, or * - there is at least one dot, there is no trailing dot, * and RES_DNSRCH is set. */ if ((!dots && (res->options & RES_DEFNAMES)) || (dots && !trailing_dot && (res->options & RES_DNSRCH))) { int done = 0; for (domain = (const char * const *)res->dnsrch; *domain && !done; domain++) { searched = 1; if (domain[0][0] == '\0' || (domain[0][0] == '.' && domain[0][1] == '\0')) root_on_list++; if (root_on_list && tried_as_is) continue; ret = res_querydomainN(name, *domain, target, res); if (ret > 0) return (ret); /* * If no server present, give up. * If name isn't found in this domain, * keep trying higher domains in the search list * (if that's enabled). * On a NO_DATA error, keep trying, otherwise * a wildcard entry of another type could keep us * from finding this entry higher in the domain. * If we get some other error (negative answer or * server failure), then stop searching up, * but try the input name below in case it's * fully-qualified. */ if (errno == ECONNREFUSED) { RES_SET_H_ERRNO(res, TRY_AGAIN); return (-1); } switch (res->res_h_errno) { case NO_DATA: got_nodata++; /* FALLTHROUGH */ case HOST_NOT_FOUND: /* keep trying */ break; case TRY_AGAIN: got_servfail++; if (hp->rcode == SERVFAIL) { /* try next search element, if any */ break; } /* FALLTHROUGH */ default: /* anything else implies that we're done */ done++; } /* * if we got here for some reason other than DNSRCH, * we only wanted one iteration of the loop, so stop. */ if (!(res->options & RES_DNSRCH)) done++; } } switch (res->res_h_errno) { case NO_DATA: case HOST_NOT_FOUND: break; case TRY_AGAIN: if (hp->rcode == SERVFAIL) break; /* FALLTHROUGH */ default: goto giveup; } /* * If the query has not already been tried as is then try it * unless RES_NOTLDQUERY is set and there were no dots. */ if ((dots || !searched || !(res->options & RES_NOTLDQUERY)) && !(tried_as_is || root_on_list)) { ret = res_querydomainN(name, NULL, target, res); if (ret > 0) return (ret); } /* * if we got here, we didn't satisfy the search. * if we did an initial full query, return that query's h_errno * (note that we wouldn't be here if that query had succeeded). * else if we ever got a nodata, send that back as the reason. * else send back meaningless h_errno, that being the one from * the last DNSRCH we did. */ giveup: if (saved_herrno != -1) RES_SET_H_ERRNO(res, saved_herrno); else if (got_nodata) RES_SET_H_ERRNO(res, NO_DATA); else if (got_servfail) RES_SET_H_ERRNO(res, TRY_AGAIN); return (-1); } /* * Perform a call on res_query on the concatenation of name and domain, * removing a trailing dot from name if domain is NULL. */ static int res_querydomainN(const char *name, const char *domain, struct res_target *target, res_state res) { char nbuf[MAXDNAME]; const char *longname = nbuf; size_t n, d; #ifdef DEBUG if (res->options & RES_DEBUG) printf(";; res_querydomain(%s, %s)\n", name, domain?domain:""); #endif if (domain == NULL) { /* * Check for trailing '.'; * copy without '.' if present. */ n = strlen(name); if (n >= MAXDNAME) { RES_SET_H_ERRNO(res, NO_RECOVERY); return (-1); } if (n > 0 && name[--n] == '.') { strncpy(nbuf, name, n); nbuf[n] = '\0'; } else longname = name; } else { n = strlen(name); d = strlen(domain); if (n + d + 1 >= MAXDNAME) { RES_SET_H_ERRNO(res, NO_RECOVERY); return (-1); } snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); } return (res_queryN(longname, target, res)); } diff --git a/lib/libc/net/name6.c b/lib/libc/net/name6.c index 97880a25e7d8..89effe69a354 100644 --- a/lib/libc/net/name6.c +++ b/lib/libc/net/name6.c @@ -1,1114 +1,1113 @@ /* $KAME: name6.c,v 1.25 2000/06/26 16:44:40 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * ++Copyright++ 1985, 1988, 1993 * - * Copyright (c) 1985, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * - * --Copyright-- */ /* * Atsushi Onoe */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include #include #include #ifdef INET6 #include -#include #include #include #include /* XXX */ #endif #include #include #include #include #include #include #include #include #include #include #include #include "un-namespace.h" #include "netdb_private.h" #include "res_private.h" #ifndef MAXALIASES #define MAXALIASES 10 #endif #ifndef MAXADDRS #define MAXADDRS 20 #endif #ifndef MAXDNAME #define MAXDNAME 1025 #endif #ifdef INET6 #define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \ sizeof(struct in_addr)) #else #define ADDRLEN(af) sizeof(struct in_addr) #endif #define MAPADDR(ab, ina) \ do { \ memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \ memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \ memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \ } while (0) #define MAPADDRENABLED(flags) \ (((flags) & AI_V4MAPPED) || \ (((flags) & AI_V4MAPPED_CFG))) union inx_addr { struct in_addr in_addr; #ifdef INET6 struct in6_addr in6_addr; #endif struct { u_char mau_zero[10]; u_char mau_one[2]; struct in_addr mau_inaddr; } map_addr_un; #define map_zero map_addr_un.mau_zero #define map_one map_addr_un.mau_one #define map_inaddr map_addr_un.mau_inaddr }; struct policyqueue { TAILQ_ENTRY(policyqueue) pc_entry; #ifdef INET6 struct in6_addrpolicy pc_policy; #endif }; TAILQ_HEAD(policyhead, policyqueue); #define AIO_SRCFLAG_DEPRECATED 0x1 struct hp_order { union { struct sockaddr_storage aiou_ss; struct sockaddr aiou_sa; } aio_src_un; #define aio_srcsa aio_src_un.aiou_sa u_int32_t aio_srcflag; int aio_srcscope; int aio_dstscope; struct policyqueue *aio_srcpolicy; struct policyqueue *aio_dstpolicy; union { struct sockaddr_storage aiou_ss; struct sockaddr aiou_sa; } aio_un; #define aio_sa aio_un.aiou_sa int aio_matchlen; char *aio_h_addr; }; static struct hostent *_hpcopy(struct hostent *, int *); static struct hostent *_hpaddr(int, const char *, void *, int *); #ifdef INET6 static struct hostent *_hpmerge(struct hostent *, struct hostent *, int *); static struct hostent *_hpmapv6(struct hostent *, int *); #endif static struct hostent *_hpsort(struct hostent *, res_state); #ifdef INET6 static struct hostent *_hpreorder(struct hostent *); static int get_addrselectpolicy(struct policyhead *); static void free_addrselectpolicy(struct policyhead *); static struct policyqueue *match_addrselectpolicy(struct sockaddr *, struct policyhead *); static void set_source(struct hp_order *, struct policyhead *); static int matchlen(struct sockaddr *, struct sockaddr *); static int comp_dst(const void *, const void *); static int gai_addr2scopetype(struct sockaddr *); #endif /* * Functions defined in RFC2553 * getipnodebyname, getipnodebyaddr, freehostent */ struct hostent * getipnodebyname(const char *name, int af, int flags, int *errp) { struct hostent *hp; union inx_addr addrbuf; res_state statp; u_long options; switch (af) { case AF_INET: #ifdef INET6 case AF_INET6: #endif break; default: *errp = NO_RECOVERY; return NULL; } if (flags & AI_ADDRCONFIG) { int s; if ((s = _socket(af, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) return NULL; /* * TODO: * Note that implementation dependent test for address * configuration should be done everytime called * (or apropriate interval), * because addresses will be dynamically assigned or deleted. */ _close(s); } #ifdef INET6 /* special case for literal address */ if (inet_pton(AF_INET6, name, &addrbuf) == 1) { if (af != AF_INET6) { *errp = HOST_NOT_FOUND; return NULL; } return _hpaddr(af, name, &addrbuf, errp); } #endif if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) { if (af != AF_INET) { if (MAPADDRENABLED(flags)) { MAPADDR(&addrbuf, &addrbuf.in_addr); } else { *errp = HOST_NOT_FOUND; return NULL; } } return _hpaddr(af, name, &addrbuf, errp); } statp = __res_state(); if ((statp->options & RES_INIT) == 0) { if (res_ninit(statp) < 0) { *errp = NETDB_INTERNAL; return NULL; } } options = statp->options; statp->options &= ~RES_USE_INET6; hp = gethostbyname2(name, af); hp = _hpcopy(hp, errp); #ifdef INET6 if (af == AF_INET6) hp = _hpreorder(hp); if (af == AF_INET6 && ((flags & AI_ALL) || hp == NULL) && MAPADDRENABLED(flags)) { struct hostent *hp2 = gethostbyname2(name, AF_INET); if (hp == NULL) if (hp2 == NULL) *errp = statp->res_h_errno; else hp = _hpmapv6(hp2, errp); else { if (hp2 && strcmp(hp->h_name, hp2->h_name) == 0) { struct hostent *hpb = hp; hp = _hpmerge(hpb, hp2, errp); freehostent(hpb); } } } #endif if (hp == NULL) *errp = statp->res_h_errno; statp->options = options; return _hpsort(hp, statp); } struct hostent * getipnodebyaddr(const void *src, size_t len, int af, int *errp) { struct hostent *hp; res_state statp; u_long options; #ifdef INET6 struct in6_addr addrbuf; #else struct in_addr addrbuf; #endif switch (af) { case AF_INET: if (len != sizeof(struct in_addr)) { *errp = NO_RECOVERY; return NULL; } if ((long)src & ~(sizeof(struct in_addr) - 1)) { memcpy(&addrbuf, src, len); src = &addrbuf; } if (((struct in_addr *)src)->s_addr == 0) return NULL; break; #ifdef INET6 case AF_INET6: if (len != sizeof(struct in6_addr)) { *errp = NO_RECOVERY; return NULL; } if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*XXX*/ memcpy(&addrbuf, src, len); src = &addrbuf; } if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src)) return NULL; if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src) || IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) { src = (char *)src + (sizeof(struct in6_addr) - sizeof(struct in_addr)); af = AF_INET; len = sizeof(struct in_addr); } break; #endif default: *errp = NO_RECOVERY; return NULL; } statp = __res_state(); if ((statp->options & RES_INIT) == 0) { if (res_ninit(statp) < 0) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); return NULL; } } options = statp->options; statp->options &= ~RES_USE_INET6; hp = gethostbyaddr(src, len, af); if (hp == NULL) *errp = statp->res_h_errno; statp->options = options; return (_hpcopy(hp, errp)); } void freehostent(struct hostent *ptr) { free(ptr); } /* * Private utility functions */ /* * _hpcopy: allocate and copy hostent structure */ static struct hostent * _hpcopy(struct hostent *hp, int *errp) { struct hostent *nhp; char *cp, **pp; int size, addrsize; int nalias = 0, naddr = 0; int al_off; int i; if (hp == NULL) return hp; /* count size to be allocated */ size = sizeof(struct hostent); if (hp->h_name != NULL) size += strlen(hp->h_name) + 1; if ((pp = hp->h_aliases) != NULL) { for (i = 0; *pp != NULL; i++, pp++) { if (**pp != '\0') { size += strlen(*pp) + 1; nalias++; } } } /* adjust alignment */ size = ALIGN(size); al_off = size; size += sizeof(char *) * (nalias + 1); addrsize = ALIGN(hp->h_length); if ((pp = hp->h_addr_list) != NULL) { while (*pp++ != NULL) naddr++; } size += addrsize * naddr; size += sizeof(char *) * (naddr + 1); /* copy */ if ((nhp = (struct hostent *)malloc(size)) == NULL) { *errp = TRY_AGAIN; return NULL; } cp = (char *)&nhp[1]; if (hp->h_name != NULL) { nhp->h_name = cp; strcpy(cp, hp->h_name); cp += strlen(cp) + 1; } else nhp->h_name = NULL; nhp->h_aliases = (char **)((char *)nhp + al_off); if ((pp = hp->h_aliases) != NULL) { for (i = 0; *pp != NULL; pp++) { if (**pp != '\0') { nhp->h_aliases[i++] = cp; strcpy(cp, *pp); cp += strlen(cp) + 1; } } } nhp->h_aliases[nalias] = NULL; cp = (char *)&nhp->h_aliases[nalias + 1]; nhp->h_addrtype = hp->h_addrtype; nhp->h_length = hp->h_length; nhp->h_addr_list = (char **)cp; if ((pp = hp->h_addr_list) != NULL) { cp = (char *)&nhp->h_addr_list[naddr + 1]; for (i = 0; *pp != NULL; pp++) { nhp->h_addr_list[i++] = cp; memcpy(cp, *pp, hp->h_length); cp += addrsize; } } nhp->h_addr_list[naddr] = NULL; return nhp; } /* * _hpaddr: construct hostent structure with one address */ static struct hostent * _hpaddr(int af, const char *name, void *addr, int *errp) { struct hostent *hp, hpbuf; char *addrs[2]; hp = &hpbuf; hp->h_name = (char *)name; hp->h_aliases = NULL; hp->h_addrtype = af; hp->h_length = ADDRLEN(af); hp->h_addr_list = addrs; addrs[0] = (char *)addr; addrs[1] = NULL; return (_hpcopy(hp, errp)); } #ifdef INET6 /* * _hpmerge: merge 2 hostent structure, arguments will be freed */ static struct hostent * _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp) { int i, j; int naddr, nalias; char **pp; struct hostent *hp, hpbuf; char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1]; union inx_addr addrbuf[MAXADDRS]; if (hp1 == NULL) return _hpcopy(hp2, errp); if (hp2 == NULL) return _hpcopy(hp1, errp); #define HP(i) (i == 1 ? hp1 : hp2) hp = &hpbuf; hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name); hp->h_aliases = aliases; nalias = 0; for (i = 1; i <= 2; i++) { if ((pp = HP(i)->h_aliases) == NULL) continue; for (; nalias < MAXALIASES && *pp != NULL; pp++) { /* check duplicates */ for (j = 0; j < nalias; j++) if (strcasecmp(*pp, aliases[j]) == 0) break; if (j == nalias) aliases[nalias++] = *pp; } } aliases[nalias] = NULL; if (hp1->h_length != hp2->h_length) { hp->h_addrtype = AF_INET6; hp->h_length = sizeof(struct in6_addr); } else { hp->h_addrtype = hp1->h_addrtype; hp->h_length = hp1->h_length; } hp->h_addr_list = addrs; naddr = 0; for (i = 1; i <= 2; i++) { if ((pp = HP(i)->h_addr_list) == NULL) continue; if (HP(i)->h_length == hp->h_length) { while (naddr < MAXADDRS && *pp != NULL) addrs[naddr++] = *pp++; } else { /* copy IPv4 addr as mapped IPv6 addr */ while (naddr < MAXADDRS && *pp != NULL) { MAPADDR(&addrbuf[naddr], *pp++); addrs[naddr] = (char *)&addrbuf[naddr]; naddr++; } } } addrs[naddr] = NULL; return (_hpcopy(hp, errp)); } #endif /* * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses */ #ifdef INET6 static struct hostent * _hpmapv6(struct hostent *hp, int *errp) { struct hostent hp6; if (hp == NULL) return NULL; if (hp->h_addrtype == AF_INET6) return _hpcopy(hp, errp); memset(&hp6, 0, sizeof(struct hostent)); hp6.h_addrtype = AF_INET6; hp6.h_length = sizeof(struct in6_addr); return _hpmerge(&hp6, hp, errp); } #endif /* * _hpsort: sort address by sortlist */ static struct hostent * _hpsort(struct hostent *hp, res_state statp) { int i, j, n; u_char *ap, *sp, *mp, **pp; char t; char order[MAXADDRS]; int nsort = statp->nsort; if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0) return hp; for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) { for (j = 0; j < nsort; j++) { #ifdef INET6 if (statp->_u._ext.ext->sort_list[j].af != hp->h_addrtype) continue; sp = (u_char *)&statp->_u._ext.ext->sort_list[j].addr; mp = (u_char *)&statp->_u._ext.ext->sort_list[j].mask; #else sp = (u_char *)&statp->sort_list[j].addr; mp = (u_char *)&statp->sort_list[j].mask; #endif for (n = 0; n < hp->h_length; n++) { if ((ap[n] & mp[n]) != sp[n]) break; } if (n == hp->h_length) break; } order[i] = j; } n = i; pp = (u_char **)hp->h_addr_list; for (i = 0; i < n - 1; i++) { for (j = i + 1; j < n; j++) { if (order[i] > order[j]) { ap = pp[i]; pp[i] = pp[j]; pp[j] = ap; t = order[i]; order[i] = order[j]; order[j] = t; } } } return hp; } #ifdef INET6 /* * _hpreorder: sort address by default address selection */ static struct hostent * _hpreorder(struct hostent *hp) { struct hp_order *aio; int i, n; char *ap; struct sockaddr *sa; struct policyhead policyhead; if (hp == NULL) return hp; switch (hp->h_addrtype) { case AF_INET: #ifdef INET6 case AF_INET6: #endif break; default: free_addrselectpolicy(&policyhead); return hp; } /* count the number of addrinfo elements for sorting. */ for (n = 0; hp->h_addr_list[n] != NULL; n++) ; /* * If the number is small enough, we can skip the reordering process. */ if (n <= 1) return hp; /* allocate a temporary array for sort and initialization of it. */ if ((aio = malloc(sizeof(*aio) * n)) == NULL) return hp; /* give up reordering */ memset(aio, 0, sizeof(*aio) * n); /* retrieve address selection policy from the kernel */ TAILQ_INIT(&policyhead); if (!get_addrselectpolicy(&policyhead)) { /* no policy is installed into kernel, we don't sort. */ free(aio); return hp; } for (i = 0; i < n; i++) { ap = hp->h_addr_list[i]; aio[i].aio_h_addr = ap; sa = &aio[i].aio_sa; switch (hp->h_addrtype) { case AF_INET: sa->sa_family = AF_INET; sa->sa_len = sizeof(struct sockaddr_in); memcpy(&((struct sockaddr_in *)sa)->sin_addr, ap, sizeof(struct in_addr)); break; #ifdef INET6 case AF_INET6: if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { sa->sa_family = AF_INET; sa->sa_len = sizeof(struct sockaddr_in); memcpy(&((struct sockaddr_in *)sa)->sin_addr, &ap[12], sizeof(struct in_addr)); } else { sa->sa_family = AF_INET6; sa->sa_len = sizeof(struct sockaddr_in6); memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, ap, sizeof(struct in6_addr)); } break; #endif } aio[i].aio_dstscope = gai_addr2scopetype(sa); aio[i].aio_dstpolicy = match_addrselectpolicy(sa, &policyhead); set_source(&aio[i], &policyhead); } /* perform sorting. */ qsort(aio, n, sizeof(*aio), comp_dst); /* reorder the h_addr_list. */ for (i = 0; i < n; i++) hp->h_addr_list[i] = aio[i].aio_h_addr; /* cleanup and return */ free(aio); free_addrselectpolicy(&policyhead); return hp; } static int get_addrselectpolicy(struct policyhead *head) { #ifdef INET6 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; size_t l; char *buf; struct in6_addrpolicy *pol, *ep; if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) return (0); if ((buf = malloc(l)) == NULL) return (0); if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { free(buf); return (0); } ep = (struct in6_addrpolicy *)(buf + l); for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { struct policyqueue *new; if ((new = malloc(sizeof(*new))) == NULL) { free_addrselectpolicy(head); /* make the list empty */ break; } new->pc_policy = *pol; TAILQ_INSERT_TAIL(head, new, pc_entry); } free(buf); return (1); #else return (0); #endif } static void free_addrselectpolicy(struct policyhead *head) { struct policyqueue *ent, *nent; for (ent = TAILQ_FIRST(head); ent; ent = nent) { nent = TAILQ_NEXT(ent, pc_entry); TAILQ_REMOVE(head, ent, pc_entry); free(ent); } } static struct policyqueue * match_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) { #ifdef INET6 struct policyqueue *ent, *bestent = NULL; struct in6_addrpolicy *pol; int matchlen, bestmatchlen = -1; u_char *mp, *ep, *k, *p, m; struct sockaddr_in6 key; switch(addr->sa_family) { case AF_INET6: key = *(struct sockaddr_in6 *)addr; break; case AF_INET: /* convert the address into IPv4-mapped IPv6 address. */ memset(&key, 0, sizeof(key)); key.sin6_family = AF_INET6; key.sin6_len = sizeof(key); key.sin6_addr.s6_addr[10] = 0xff; key.sin6_addr.s6_addr[11] = 0xff; memcpy(&key.sin6_addr.s6_addr[12], &((struct sockaddr_in *)addr)->sin_addr, 4); break; default: return(NULL); } for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { pol = &ent->pc_policy; matchlen = 0; mp = (u_char *)&pol->addrmask.sin6_addr; ep = mp + 16; /* XXX: scope field? */ k = (u_char *)&key.sin6_addr; p = (u_char *)&pol->addr.sin6_addr; for (; mp < ep && *mp; mp++, k++, p++) { m = *mp; if ((*k & m) != *p) goto next; /* not match */ if (m == 0xff) /* short cut for a typical case */ matchlen += 8; else { while (m >= 0x80) { matchlen++; m <<= 1; } } } /* matched. check if this is better than the current best. */ if (matchlen > bestmatchlen) { bestent = ent; bestmatchlen = matchlen; } next: continue; } return(bestent); #else return(NULL); #endif } static void set_source(struct hp_order *aio, struct policyhead *ph) { struct sockaddr_storage ss = aio->aio_un.aiou_ss; socklen_t srclen; int s; /* set unspec ("no source is available"), just in case */ aio->aio_srcsa.sa_family = AF_UNSPEC; aio->aio_srcscope = -1; switch(ss.ss_family) { case AF_INET: ((struct sockaddr_in *)&ss)->sin_port = htons(1); break; #ifdef INET6 case AF_INET6: ((struct sockaddr_in6 *)&ss)->sin6_port = htons(1); break; #endif default: /* ignore unsupported AFs explicitly */ return; } /* open a socket to get the source address for the given dst */ if ((s = _socket(ss.ss_family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) < 0) return; /* give up */ if (_connect(s, (struct sockaddr *)&ss, ss.ss_len) < 0) goto cleanup; srclen = ss.ss_len; if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { aio->aio_srcsa.sa_family = AF_UNSPEC; goto cleanup; } aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); aio->aio_matchlen = matchlen(&aio->aio_srcsa, (struct sockaddr *)&ss); #ifdef INET6 if (ss.ss_family == AF_INET6) { struct in6_ifreq ifr6; u_int32_t flags6; memset(&ifr6, 0, sizeof(ifr6)); memcpy(&ifr6.ifr_addr, &ss, ss.ss_len); if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { flags6 = ifr6.ifr_ifru.ifru_flags6; if ((flags6 & IN6_IFF_DEPRECATED)) aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; } } #endif cleanup: _close(s); return; } static int matchlen(struct sockaddr *src, struct sockaddr *dst) { int match = 0; u_char *s, *d; u_char *lim, r; int addrlen; switch (src->sa_family) { #ifdef INET6 case AF_INET6: s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; addrlen = sizeof(struct in6_addr); lim = s + addrlen; break; #endif case AF_INET: s = (u_char *)&((struct sockaddr_in *)src)->sin_addr; d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr; addrlen = sizeof(struct in_addr); lim = s + addrlen; break; default: return(0); } while (s < lim) if ((r = (*d++ ^ *s++)) != 0) { while (r < addrlen * 8) { match++; r <<= 1; } break; } else match += 8; return(match); } static int comp_dst(const void *arg1, const void *arg2) { const struct hp_order *dst1 = arg1, *dst2 = arg2; /* * Rule 1: Avoid unusable destinations. * XXX: we currently do not consider if an appropriate route exists. */ if (dst1->aio_srcsa.sa_family != AF_UNSPEC && dst2->aio_srcsa.sa_family == AF_UNSPEC) { return(-1); } if (dst1->aio_srcsa.sa_family == AF_UNSPEC && dst2->aio_srcsa.sa_family != AF_UNSPEC) { return(1); } /* Rule 2: Prefer matching scope. */ if (dst1->aio_dstscope == dst1->aio_srcscope && dst2->aio_dstscope != dst2->aio_srcscope) { return(-1); } if (dst1->aio_dstscope != dst1->aio_srcscope && dst2->aio_dstscope == dst2->aio_srcscope) { return(1); } /* Rule 3: Avoid deprecated addresses. */ if (dst1->aio_srcsa.sa_family != AF_UNSPEC && dst2->aio_srcsa.sa_family != AF_UNSPEC) { if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { return(-1); } if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { return(1); } } /* Rule 4: Prefer home addresses. */ /* XXX: not implemented yet */ /* Rule 5: Prefer matching label. */ #ifdef INET6 if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && dst1->aio_srcpolicy->pc_policy.label == dst1->aio_dstpolicy->pc_policy.label && (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || dst2->aio_srcpolicy->pc_policy.label != dst2->aio_dstpolicy->pc_policy.label)) { return(-1); } if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && dst2->aio_srcpolicy->pc_policy.label == dst2->aio_dstpolicy->pc_policy.label && (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || dst1->aio_srcpolicy->pc_policy.label != dst1->aio_dstpolicy->pc_policy.label)) { return(1); } #endif /* Rule 6: Prefer higher precedence. */ #ifdef INET6 if (dst1->aio_dstpolicy && (dst2->aio_dstpolicy == NULL || dst1->aio_dstpolicy->pc_policy.preced > dst2->aio_dstpolicy->pc_policy.preced)) { return(-1); } if (dst2->aio_dstpolicy && (dst1->aio_dstpolicy == NULL || dst2->aio_dstpolicy->pc_policy.preced > dst1->aio_dstpolicy->pc_policy.preced)) { return(1); } #endif /* Rule 7: Prefer native transport. */ /* XXX: not implemented yet */ /* Rule 8: Prefer smaller scope. */ if (dst1->aio_dstscope >= 0 && dst1->aio_dstscope < dst2->aio_dstscope) { return(-1); } if (dst2->aio_dstscope >= 0 && dst2->aio_dstscope < dst1->aio_dstscope) { return(1); } /* * Rule 9: Use longest matching prefix. * We compare the match length in a same AF only. */ if (dst1->aio_sa.sa_family == dst2->aio_sa.sa_family) { if (dst1->aio_matchlen > dst2->aio_matchlen) { return(-1); } if (dst1->aio_matchlen < dst2->aio_matchlen) { return(1); } } /* Rule 10: Otherwise, leave the order unchanged. */ return(-1); } /* * Copy from scope.c. * XXX: we should standardize the functions and link them as standard * library. */ static int gai_addr2scopetype(struct sockaddr *sa) { #ifdef INET6 struct sockaddr_in6 *sa6; #endif struct sockaddr_in *sa4; switch(sa->sa_family) { #ifdef INET6 case AF_INET6: sa6 = (struct sockaddr_in6 *)sa; if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { /* just use the scope field of the multicast address */ return(sa6->sin6_addr.s6_addr[2] & 0x0f); } /* * Unicast addresses: map scope type to corresponding scope * value defined for multcast addresses. * XXX: hardcoded scope type values are bad... */ if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) return(1); /* node local scope */ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) return(2); /* link-local scope */ if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) return(5); /* site-local scope */ return(14); /* global scope */ break; #endif case AF_INET: /* * IPv4 pseudo scoping according to RFC 3484. */ sa4 = (struct sockaddr_in *)sa; /* IPv4 autoconfiguration addresses have link-local scope. */ if (((u_char *)&sa4->sin_addr)[0] == 169 && ((u_char *)&sa4->sin_addr)[1] == 254) return(2); /* Private addresses have site-local scope. */ if (((u_char *)&sa4->sin_addr)[0] == 10 || (((u_char *)&sa4->sin_addr)[0] == 172 && (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || (((u_char *)&sa4->sin_addr)[0] == 192 && ((u_char *)&sa4->sin_addr)[1] == 168)) return(14); /* XXX: It should be 5 unless NAT */ /* Loopback addresses have link-local scope. */ if (((u_char *)&sa4->sin_addr)[0] == 127) return(2); return(14); break; default: errno = EAFNOSUPPORT; /* is this a good error? */ return(-1); } } #endif diff --git a/sbin/ifconfig/af_inet.c b/sbin/ifconfig/af_inet.c index c73337374be4..3c3a75742e10 100644 --- a/sbin/ifconfig/af_inet.c +++ b/sbin/ifconfig/af_inet.c @@ -1,212 +1,211 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include -#include /* for struct ifaddr */ #include #include #include #include "ifconfig.h" static struct in_aliasreq in_addreq; static struct ifreq in_ridreq; static void in_status(int s __unused, const struct ifaddrs *ifa) { struct sockaddr_in *sin, null_sin; memset(&null_sin, 0, sizeof(null_sin)); sin = (struct sockaddr_in *)ifa->ifa_addr; if (sin == NULL) return; printf("\tinet %s ", inet_ntoa(sin->sin_addr)); if (ifa->ifa_flags & IFF_POINTOPOINT) { sin = (struct sockaddr_in *)ifa->ifa_dstaddr; if (sin == NULL) sin = &null_sin; printf("--> %s ", inet_ntoa(sin->sin_addr)); } sin = (struct sockaddr_in *)ifa->ifa_netmask; if (sin == NULL) sin = &null_sin; printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); if (ifa->ifa_flags & IFF_BROADCAST) { sin = (struct sockaddr_in *)ifa->ifa_broadaddr; if (sin != NULL && sin->sin_addr.s_addr != 0) printf("broadcast %s ", inet_ntoa(sin->sin_addr)); } print_vhid(ifa, " "); putchar('\n'); } #define SIN(x) ((struct sockaddr_in *) &(x)) static struct sockaddr_in *sintab[] = { SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr), SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr) }; static void in_getaddr(const char *s, int which) { #define MIN(a,b) ((a)<(b)?(a):(b)) struct sockaddr_in *sin = sintab[which]; struct hostent *hp; struct netent *np; sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; if (which == ADDR) { char *p = NULL; if((p = strrchr(s, '/')) != NULL) { const char *errstr; /* address is `name/masklen' */ int masklen; struct sockaddr_in *min = sintab[MASK]; *p = '\0'; if (!isdigit(*(p + 1))) errstr = "invalid"; else masklen = (int)strtonum(p + 1, 0, 32, &errstr); if (errstr != NULL) { *p = '/'; errx(1, "%s: bad value (width %s)", s, errstr); } min->sin_family = AF_INET; min->sin_len = sizeof(*min); min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 0xffffffff); } } if (inet_aton(s, &sin->sin_addr)) return; if ((hp = gethostbyname(s)) != 0) bcopy(hp->h_addr, (char *)&sin->sin_addr, MIN((size_t)hp->h_length, sizeof(sin->sin_addr))); else if ((np = getnetbyname(s)) != 0) sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); else errx(1, "%s: bad value", s); #undef MIN } static void in_status_tunnel(int s) { char src[NI_MAXHOST]; char dst[NI_MAXHOST]; struct ifreq ifr; const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, name, IFNAMSIZ); if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0) return; if (sa->sa_family != AF_INET) return; if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0) src[0] = '\0'; if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0) return; if (sa->sa_family != AF_INET) return; if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0) dst[0] = '\0'; printf("\ttunnel inet %s --> %s\n", src, dst); } static void in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) { struct in_aliasreq addreq; memset(&addreq, 0, sizeof(addreq)); strncpy(addreq.ifra_name, name, IFNAMSIZ); memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len); if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) warn("SIOCSIFPHYADDR"); } static struct afswtch af_inet = { .af_name = "inet", .af_af = AF_INET, .af_status = in_status, .af_getaddr = in_getaddr, .af_status_tunnel = in_status_tunnel, .af_settunnel = in_set_tunnel, .af_difaddr = SIOCDIFADDR, .af_aifaddr = SIOCAIFADDR, .af_ridreq = &in_ridreq, .af_addreq = &in_addreq, }; static __constructor void inet_ctor(void) { #ifndef RESCUE if (!feature_present("inet")) return; #endif af_register(&af_inet); } diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c index bff66e0d1215..8a18401e7e79 100644 --- a/sbin/ifconfig/af_inet6.c +++ b/sbin/ifconfig/af_inet6.c @@ -1,540 +1,539 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include -#include /* for struct ifaddr */ #include #include #include #include /* Define ND6_INFINITE_LIFETIME */ #include "ifconfig.h" static struct in6_ifreq in6_ridreq; static struct in6_aliasreq in6_addreq = { .ifra_flags = 0, .ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } }; static int ip6lifetime; static int prefix(void *, int); static char *sec2str(time_t); static int explicit_prefix = 0; extern void setnd6flags(const char *, int, int, const struct afswtch *); extern void setnd6defif(const char *, int, int, const struct afswtch *); extern void nd6_status(int); static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ static void setifprefixlen(const char *addr, int dummy __unused, int s, const struct afswtch *afp) { if (afp->af_getprefix != NULL) afp->af_getprefix(addr, MASK); explicit_prefix = 1; } static void setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused, const struct afswtch *afp) { if (afp->af_af != AF_INET6) err(1, "address flags can be set only for inet6 addresses"); if (flag < 0) in6_addreq.ifra_flags &= ~(-flag); else in6_addreq.ifra_flags |= flag; } static void setip6lifetime(const char *cmd, const char *val, int s, const struct afswtch *afp) { struct timespec now; time_t newval; char *ep; clock_gettime(CLOCK_MONOTONIC_FAST, &now); newval = (time_t)strtoul(val, &ep, 0); if (val == ep) errx(1, "invalid %s", cmd); if (afp->af_af != AF_INET6) errx(1, "%s not allowed for the AF", cmd); if (strcmp(cmd, "vltime") == 0) { in6_addreq.ifra_lifetime.ia6t_expire = now.tv_sec + newval; in6_addreq.ifra_lifetime.ia6t_vltime = newval; } else if (strcmp(cmd, "pltime") == 0) { in6_addreq.ifra_lifetime.ia6t_preferred = now.tv_sec + newval; in6_addreq.ifra_lifetime.ia6t_pltime = newval; } } static void setip6pltime(const char *seconds, int dummy __unused, int s, const struct afswtch *afp) { setip6lifetime("pltime", seconds, s, afp); } static void setip6vltime(const char *seconds, int dummy __unused, int s, const struct afswtch *afp) { setip6lifetime("vltime", seconds, s, afp); } static void setip6eui64(const char *cmd, int dummy __unused, int s, const struct afswtch *afp) { struct ifaddrs *ifap, *ifa; const struct sockaddr_in6 *sin6 = NULL; const struct in6_addr *lladdr = NULL; struct in6_addr *in6; if (afp->af_af != AF_INET6) errx(EXIT_FAILURE, "%s not allowed for the AF", cmd); in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr; if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0) errx(EXIT_FAILURE, "interface index is already filled"); if (getifaddrs(&ifap) != 0) err(EXIT_FAILURE, "getifaddrs"); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family == AF_INET6 && strcmp(ifa->ifa_name, name) == 0) { sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr; if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { lladdr = &sin6->sin6_addr; break; } } } if (!lladdr) errx(EXIT_FAILURE, "could not determine link local address"); memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8); freeifaddrs(ifap); } static void in6_status(int s __unused, const struct ifaddrs *ifa) { struct sockaddr_in6 *sin, null_sin; struct in6_ifreq ifr6; int s6; u_int32_t flags6; struct in6_addrlifetime lifetime; struct timespec now; int error; clock_gettime(CLOCK_MONOTONIC_FAST, &now); memset(&null_sin, 0, sizeof(null_sin)); sin = (struct sockaddr_in6 *)ifa->ifa_addr; if (sin == NULL) return; strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { warn("socket(AF_INET6,SOCK_DGRAM)"); return; } ifr6.ifr_addr = *sin; if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) { warn("ioctl(SIOCGIFAFLAG_IN6)"); close(s6); return; } flags6 = ifr6.ifr_ifru.ifru_flags6; memset(&lifetime, 0, sizeof(lifetime)); ifr6.ifr_addr = *sin; if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) { warn("ioctl(SIOCGIFALIFETIME_IN6)"); close(s6); return; } lifetime = ifr6.ifr_ifru.ifru_lifetime; close(s6); error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST); if (error != 0) inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, sizeof(addr_buf)); printf("\tinet6 %s ", addr_buf); if (ifa->ifa_flags & IFF_POINTOPOINT) { sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr; /* * some of the interfaces do not have valid destination * address. */ if (sin != NULL && sin->sin6_family == AF_INET6) { int error; error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST); if (error != 0) inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, sizeof(addr_buf)); printf("--> %s ", addr_buf); } } sin = (struct sockaddr_in6 *)ifa->ifa_netmask; if (sin == NULL) sin = &null_sin; printf("prefixlen %d ", prefix(&sin->sin6_addr, sizeof(struct in6_addr))); if ((flags6 & IN6_IFF_ANYCAST) != 0) printf("anycast "); if ((flags6 & IN6_IFF_TENTATIVE) != 0) printf("tentative "); if ((flags6 & IN6_IFF_DUPLICATED) != 0) printf("duplicated "); if ((flags6 & IN6_IFF_DETACHED) != 0) printf("detached "); if ((flags6 & IN6_IFF_DEPRECATED) != 0) printf("deprecated "); if ((flags6 & IN6_IFF_AUTOCONF) != 0) printf("autoconf "); if ((flags6 & IN6_IFF_TEMPORARY) != 0) printf("temporary "); if ((flags6 & IN6_IFF_PREFER_SOURCE) != 0) printf("prefer_source "); if (((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id) printf("scopeid 0x%x ", ((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id); if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) { printf("pltime "); if (lifetime.ia6t_preferred) { printf("%s ", lifetime.ia6t_preferred < now.tv_sec ? "0" : sec2str(lifetime.ia6t_preferred - now.tv_sec)); } else printf("infty "); printf("vltime "); if (lifetime.ia6t_expire) { printf("%s ", lifetime.ia6t_expire < now.tv_sec ? "0" : sec2str(lifetime.ia6t_expire - now.tv_sec)); } else printf("infty "); } print_vhid(ifa, " "); putchar('\n'); } #define SIN6(x) ((struct sockaddr_in6 *) &(x)) static struct sockaddr_in6 *sin6tab[] = { SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr), SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr) }; static void in6_getprefix(const char *plen, int which) { struct sockaddr_in6 *sin = sin6tab[which]; u_char *cp; int len = atoi(plen); if ((len < 0) || (len > 128)) errx(1, "%s: bad value", plen); sin->sin6_len = sizeof(*sin); if (which != MASK) sin->sin6_family = AF_INET6; if ((len == 0) || (len == 128)) { memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr)); return; } memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr)); for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8) *cp++ = 0xff; *cp = 0xff << (8 - len); } static void in6_getaddr(const char *s, int which) { struct sockaddr_in6 *sin = sin6tab[which]; struct addrinfo hints, *res; int error = -1; newaddr &= 1; sin->sin6_len = sizeof(*sin); if (which != MASK) sin->sin6_family = AF_INET6; if (which == ADDR) { char *p = NULL; if((p = strrchr(s, '/')) != NULL) { *p = '\0'; in6_getprefix(p + 1, MASK); explicit_prefix = 1; } } if (sin->sin6_family == AF_INET6) { bzero(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_INET6; error = getaddrinfo(s, NULL, &hints, &res); } if (error != 0) { if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1) errx(1, "%s: bad value", s); } else bcopy(res->ai_addr, sin, res->ai_addrlen); } static int prefix(void *val, int size) { u_char *name = (u_char *)val; int byte, bit, plen = 0; for (byte = 0; byte < size; byte++, plen += 8) if (name[byte] != 0xff) break; if (byte == size) return (plen); for (bit = 7; bit != 0; bit--, plen++) if (!(name[byte] & (1 << bit))) break; for (; bit != 0; bit--) if (name[byte] & (1 << bit)) return(0); byte++; for (; byte < size; byte++) if (name[byte]) return(0); return (plen); } static char * sec2str(time_t total) { static char result[256]; int days, hours, mins, secs; int first = 1; char *p = result; if (0) { days = total / 3600 / 24; hours = (total / 3600) % 24; mins = (total / 60) % 60; secs = total % 60; if (days) { first = 0; p += sprintf(p, "%dd", days); } if (!first || hours) { first = 0; p += sprintf(p, "%dh", hours); } if (!first || mins) { first = 0; p += sprintf(p, "%dm", mins); } sprintf(p, "%ds", secs); } else sprintf(result, "%lu", (unsigned long)total); return(result); } static void in6_postproc(int s, const struct afswtch *afp) { if (explicit_prefix == 0) { /* Aggregatable address architecture defines all prefixes are 64. So, it is convenient to set prefixlen to 64 if it is not specified. */ setifprefixlen("64", 0, s, afp); /* in6_getprefix("64", MASK) if MASK is available here... */ } } static void in6_status_tunnel(int s) { char src[NI_MAXHOST]; char dst[NI_MAXHOST]; struct in6_ifreq in6_ifr; const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr; memset(&in6_ifr, 0, sizeof(in6_ifr)); strncpy(in6_ifr.ifr_name, name, IFNAMSIZ); if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0) return; if (sa->sa_family != AF_INET6) return; if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0) src[0] = '\0'; if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0) return; if (sa->sa_family != AF_INET6) return; if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0) dst[0] = '\0'; printf("\ttunnel inet6 %s --> %s\n", src, dst); } static void in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) { struct in6_aliasreq in6_addreq; memset(&in6_addreq, 0, sizeof(in6_addreq)); strncpy(in6_addreq.ifra_name, name, IFNAMSIZ); memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len); if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0) warn("SIOCSIFPHYADDR_IN6"); } static struct cmd inet6_cmds[] = { DEF_CMD_ARG("prefixlen", setifprefixlen), DEF_CMD("anycast", IN6_IFF_ANYCAST, setip6flags), DEF_CMD("tentative", IN6_IFF_TENTATIVE, setip6flags), DEF_CMD("-tentative", -IN6_IFF_TENTATIVE, setip6flags), DEF_CMD("deprecated", IN6_IFF_DEPRECATED, setip6flags), DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags), DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags), DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags), DEF_CMD("prefer_source",IN6_IFF_PREFER_SOURCE, setip6flags), DEF_CMD("-prefer_source",-IN6_IFF_PREFER_SOURCE,setip6flags), DEF_CMD("accept_rtadv", ND6_IFF_ACCEPT_RTADV, setnd6flags), DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV, setnd6flags), DEF_CMD("no_radr", ND6_IFF_NO_RADR, setnd6flags), DEF_CMD("-no_radr", -ND6_IFF_NO_RADR, setnd6flags), DEF_CMD("defaultif", 1, setnd6defif), DEF_CMD("-defaultif", -1, setnd6defif), DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags), DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags), DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags), DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags), DEF_CMD("auto_linklocal",ND6_IFF_AUTO_LINKLOCAL,setnd6flags), DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags), DEF_CMD("no_prefer_iface",ND6_IFF_NO_PREFER_IFACE,setnd6flags), DEF_CMD("-no_prefer_iface",-ND6_IFF_NO_PREFER_IFACE,setnd6flags), DEF_CMD("no_dad", ND6_IFF_NO_DAD, setnd6flags), DEF_CMD("-no_dad", -ND6_IFF_NO_DAD, setnd6flags), DEF_CMD("ignoreloop", ND6_IFF_IGNORELOOP, setnd6flags), DEF_CMD("-ignoreloop", -ND6_IFF_IGNORELOOP, setnd6flags), DEF_CMD_ARG("pltime", setip6pltime), DEF_CMD_ARG("vltime", setip6vltime), DEF_CMD("eui64", 0, setip6eui64), }; static struct afswtch af_inet6 = { .af_name = "inet6", .af_af = AF_INET6, .af_status = in6_status, .af_getaddr = in6_getaddr, .af_getprefix = in6_getprefix, .af_other_status = nd6_status, .af_postproc = in6_postproc, .af_status_tunnel = in6_status_tunnel, .af_settunnel = in6_set_tunnel, .af_difaddr = SIOCDIFADDR_IN6, .af_aifaddr = SIOCAIFADDR_IN6, .af_ridreq = &in6_addreq, .af_addreq = &in6_addreq, }; static void in6_Lopt_cb(const char *optarg __unused) { ip6lifetime++; /* print IPv6 address lifetime */ } static struct option in6_Lopt = { .opt = "L", .opt_usage = "[-L]", .cb = in6_Lopt_cb }; static __constructor void inet6_ctor(void) { #define N(a) (sizeof(a) / sizeof(a[0])) size_t i; #ifndef RESCUE if (!feature_present("inet6")) return; #endif for (i = 0; i < N(inet6_cmds); i++) cmd_register(&inet6_cmds[i]); af_register(&af_inet6); opt_register(&in6_Lopt); #undef N } diff --git a/sbin/ifconfig/af_nd6.c b/sbin/ifconfig/af_nd6.c index 3a510a5576de..9a1be79710a2 100644 --- a/sbin/ifconfig/af_nd6.c +++ b/sbin/ifconfig/af_nd6.c @@ -1,170 +1,169 @@ /* * Copyright (c) 2009 Hiroki Sato. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include "ifconfig.h" #define MAX_SYSCTL_TRY 5 #define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \ "\004IFDISABLED\005DONT_SET_IFROUTE\006AUTO_LINKLOCAL" \ "\007NO_RADR\010NO_PREFER_IFACE\011IGNORELOOP\012NO_DAD" \ "\020DEFAULTIF" static int isnd6defif(int); void setnd6flags(const char *, int, int, const struct afswtch *); void setnd6defif(const char *, int, int, const struct afswtch *); void nd6_status(int); void setnd6flags(const char *dummyaddr __unused, int d, int s, const struct afswtch *afp) { struct in6_ndireq nd; int error; memset(&nd, 0, sizeof(nd)); strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname)); error = ioctl(s, SIOCGIFINFO_IN6, &nd); if (error) { warn("ioctl(SIOCGIFINFO_IN6)"); return; } if (d < 0) nd.ndi.flags &= ~(-d); else nd.ndi.flags |= d; error = ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd); if (error) warn("ioctl(SIOCSIFINFO_IN6)"); } void setnd6defif(const char *dummyaddr __unused, int d, int s, const struct afswtch *afp) { struct in6_ndifreq ndifreq; int ifindex; int error; memset(&ndifreq, 0, sizeof(ndifreq)); strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname)); if (d < 0) { if (isnd6defif(s)) { /* ifindex = 0 means to remove default if */ ifindex = 0; } else return; } else if ((ifindex = if_nametoindex(ndifreq.ifname)) == 0) { warn("if_nametoindex(%s)", ndifreq.ifname); return; } ndifreq.ifindex = ifindex; error = ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq); if (error) warn("ioctl(SIOCSDEFIFACE_IN6)"); } static int isnd6defif(int s) { struct in6_ndifreq ndifreq; unsigned int ifindex; int error; memset(&ndifreq, 0, sizeof(ndifreq)); strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname)); ifindex = if_nametoindex(ndifreq.ifname); error = ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq); if (error) { warn("ioctl(SIOCGDEFIFACE_IN6)"); return (error); } return (ndifreq.ifindex == ifindex); } void nd6_status(int s) { struct in6_ndireq nd; int s6; int error; int isdefif; memset(&nd, 0, sizeof(nd)); strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname)); if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { if (errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT) warn("socket(AF_INET6, SOCK_DGRAM)"); return; } error = ioctl(s6, SIOCGIFINFO_IN6, &nd); if (error) { if (errno != EPFNOSUPPORT) warn("ioctl(SIOCGIFINFO_IN6)"); close(s6); return; } isdefif = isnd6defif(s6); close(s6); if (nd.ndi.flags == 0 && !isdefif) return; printb("\tnd6 options", (unsigned int)(nd.ndi.flags | (isdefif << 15)), ND6BITS); putchar('\n'); } diff --git a/sbin/ifconfig/carp.c b/sbin/ifconfig/carp.c index 2c58fcb1e931..adff153a42ae 100644 --- a/sbin/ifconfig/carp.c +++ b/sbin/ifconfig/carp.c @@ -1,228 +1,227 @@ /* $FreeBSD$ */ /* from $OpenBSD: ifconfig.c,v 1.82 2003/10/19 05:43:35 mcbride Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff. All rights reserved. * Copyright (c) 2003 Ryan McBride. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include "ifconfig.h" static const char *carp_states[] = { CARP_STATES }; static void carp_status(int s); static void setcarp_vhid(const char *, int, int, const struct afswtch *rafp); static void setcarp_callback(int, void *); static void setcarp_advbase(const char *,int, int, const struct afswtch *rafp); static void setcarp_advskew(const char *, int, int, const struct afswtch *rafp); static void setcarp_passwd(const char *, int, int, const struct afswtch *rafp); static int carpr_vhid = -1; static int carpr_advskew = -1; static int carpr_advbase = -1; static int carpr_state = -1; static unsigned char const *carpr_key; static void carp_status(int s) { struct carpreq carpr[CARP_MAXVHID]; int i; bzero(carpr, sizeof(struct carpreq) * CARP_MAXVHID); carpr[0].carpr_count = CARP_MAXVHID; ifr.ifr_data = (caddr_t)&carpr; if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1) return; for (i = 0; i < carpr[0].carpr_count; i++) { printf("\tcarp: %s vhid %d advbase %d advskew %d", carp_states[carpr[i].carpr_state], carpr[i].carpr_vhid, carpr[i].carpr_advbase, carpr[i].carpr_advskew); if (printkeys && carpr[i].carpr_key[0] != '\0') printf(" key \"%s\"\n", carpr[i].carpr_key); else printf("\n"); } } static void setcarp_vhid(const char *val, int d, int s, const struct afswtch *afp) { carpr_vhid = atoi(val); if (carpr_vhid <= 0 || carpr_vhid > CARP_MAXVHID) errx(1, "vhid must be greater than 0 and less than %u", CARP_MAXVHID); switch (afp->af_af) { #ifdef INET case AF_INET: { struct in_aliasreq *ifra; ifra = (struct in_aliasreq *)afp->af_addreq; ifra->ifra_vhid = carpr_vhid; break; } #endif #ifdef INET6 case AF_INET6: { struct in6_aliasreq *ifra; ifra = (struct in6_aliasreq *)afp->af_addreq; ifra->ifra_vhid = carpr_vhid; break; } #endif default: errx(1, "%s doesn't support carp(4)", afp->af_name); } callback_register(setcarp_callback, NULL); } static void setcarp_callback(int s, void *arg __unused) { struct carpreq carpr; bzero(&carpr, sizeof(struct carpreq)); carpr.carpr_vhid = carpr_vhid; carpr.carpr_count = 1; ifr.ifr_data = (caddr_t)&carpr; if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1 && errno != ENOENT) err(1, "SIOCGVH"); if (carpr_key != NULL) /* XXX Should hash the password into the key here? */ strlcpy(carpr.carpr_key, carpr_key, CARP_KEY_LEN); if (carpr_advskew > -1) carpr.carpr_advskew = carpr_advskew; if (carpr_advbase > -1) carpr.carpr_advbase = carpr_advbase; if (carpr_state > -1) carpr.carpr_state = carpr_state; if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1) err(1, "SIOCSVH"); } static void setcarp_passwd(const char *val, int d, int s, const struct afswtch *afp) { if (carpr_vhid == -1) errx(1, "passwd requires vhid"); carpr_key = val; } static void setcarp_advskew(const char *val, int d, int s, const struct afswtch *afp) { if (carpr_vhid == -1) errx(1, "advskew requires vhid"); carpr_advskew = atoi(val); } static void setcarp_advbase(const char *val, int d, int s, const struct afswtch *afp) { if (carpr_vhid == -1) errx(1, "advbase requires vhid"); carpr_advbase = atoi(val); } static void setcarp_state(const char *val, int d, int s, const struct afswtch *afp) { int i; if (carpr_vhid == -1) errx(1, "state requires vhid"); for (i = 0; i <= CARP_MAXSTATE; i++) if (strcasecmp(carp_states[i], val) == 0) { carpr_state = i; return; } errx(1, "unknown state"); } static struct cmd carp_cmds[] = { DEF_CMD_ARG("advbase", setcarp_advbase), DEF_CMD_ARG("advskew", setcarp_advskew), DEF_CMD_ARG("pass", setcarp_passwd), DEF_CMD_ARG("vhid", setcarp_vhid), DEF_CMD_ARG("state", setcarp_state), }; static struct afswtch af_carp = { .af_name = "af_carp", .af_af = AF_UNSPEC, .af_other_status = carp_status, }; static __constructor void carp_ctor(void) { #define N(a) (sizeof(a) / sizeof(a[0])) int i; for (i = 0; i < N(carp_cmds); i++) cmd_register(&carp_cmds[i]); af_register(&af_carp); #undef N } diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index 9d38a27f5ec0..4a7999232be0 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -1,1400 +1,1399 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include -#include #include #include #include /* IP */ #include #include #include #include #include #include #include #include #include #ifdef JAIL #include #endif #include #include #include #include #include "ifconfig.h" /* * Since "struct ifreq" is composed of various union members, callers * should pay special attention to interpret the value. * (.e.g. little/big endian difference in the structure.) */ struct ifreq ifr; char name[IFNAMSIZ]; char *descr = NULL; size_t descrlen = 64; int setaddr; int setmask; int doalias; int clearaddr; int newaddr = 1; int verbose; int noload; int supmedia = 0; int printkeys = 0; /* Print keying material for interfaces. */ static int ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *afp); static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl, struct ifaddrs *ifa); static void tunnel_status(int s); static void usage(void); static struct afswtch *af_getbyname(const char *name); static struct afswtch *af_getbyfamily(int af); static void af_other_status(int); static struct option *opts = NULL; struct ifa_order_elt { int if_order; int af_orders[255]; struct ifaddrs *ifa; TAILQ_ENTRY(ifa_order_elt) link; }; TAILQ_HEAD(ifa_queue, ifa_order_elt); void opt_register(struct option *p) { p->next = opts; opts = p; } static void usage(void) { char options[1024]; struct option *p; /* XXX not right but close enough for now */ options[0] = '\0'; for (p = opts; p != NULL; p = p->next) { strlcat(options, p->opt_usage, sizeof(options)); strlcat(options, " ", sizeof(options)); } fprintf(stderr, "usage: ifconfig %sinterface address_family [address [dest_address]]\n" " [parameters]\n" " ifconfig interface create\n" " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n" " ifconfig -l [-d] [-u] [address_family]\n" " ifconfig %s[-d] [-m] [-u] [-v]\n", options, options, options); exit(1); } #define ORDERS_SIZE(x) sizeof(x) / sizeof(x[0]) static int calcorders(struct ifaddrs *ifa, struct ifa_queue *q) { struct ifaddrs *prev; struct ifa_order_elt *cur; unsigned int ord, af, ifa_ord; prev = NULL; cur = NULL; ord = 0; ifa_ord = 0; while (ifa != NULL) { if (prev == NULL || strcmp(ifa->ifa_name, prev->ifa_name) != 0) { cur = calloc(1, sizeof(*cur)); if (cur == NULL) return (-1); TAILQ_INSERT_TAIL(q, cur, link); cur->if_order = ifa_ord ++; cur->ifa = ifa; ord = 0; } if (ifa->ifa_addr) { af = ifa->ifa_addr->sa_family; if (af < ORDERS_SIZE(cur->af_orders) && cur->af_orders[af] == 0) cur->af_orders[af] = ++ord; } prev = ifa; ifa = ifa->ifa_next; } return (0); } static int cmpifaddrs(struct ifaddrs *a, struct ifaddrs *b, struct ifa_queue *q) { struct ifa_order_elt *cur, *e1, *e2; unsigned int af1, af2; int ret; e1 = e2 = NULL; ret = strcmp(a->ifa_name, b->ifa_name); if (ret != 0) { TAILQ_FOREACH(cur, q, link) { if (e1 && e2) break; if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) e1 = cur; else if (strcmp(cur->ifa->ifa_name, b->ifa_name) == 0) e2 = cur; } if (!e1 || !e2) return (0); else return (e1->if_order - e2->if_order); } else if (a->ifa_addr != NULL && b->ifa_addr != NULL) { TAILQ_FOREACH(cur, q, link) { if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) { e1 = cur; break; } } if (!e1) return (0); af1 = a->ifa_addr->sa_family; af2 = b->ifa_addr->sa_family; if (af1 < ORDERS_SIZE(e1->af_orders) && af2 < ORDERS_SIZE(e1->af_orders)) return (e1->af_orders[af1] - e1->af_orders[af2]); } return (0); } #undef ORDERS_SIZE static struct ifaddrs * sortifaddrs(struct ifaddrs *list, int (*compare)(struct ifaddrs *, struct ifaddrs *, struct ifa_queue *), struct ifa_queue *q) { struct ifaddrs *right, *temp, *last, *result, *next, *tail; right = list; temp = list; last = list; result = NULL; next = NULL; tail = NULL; if (!list || !list->ifa_next) return (list); while (temp && temp->ifa_next) { last = right; right = right->ifa_next; temp = temp->ifa_next->ifa_next; } last->ifa_next = NULL; list = sortifaddrs(list, compare, q); right = sortifaddrs(right, compare, q); while (list || right) { if (!right) { next = list; list = list->ifa_next; } else if (!list) { next = right; right = right->ifa_next; } else if (compare(list, right, q) <= 0) { next = list; list = list->ifa_next; } else { next = right; right = right->ifa_next; } if (!result) result = next; else tail->ifa_next = next; tail = next; } return (result); } int main(int argc, char *argv[]) { int c, all, namesonly, downonly, uponly; const struct afswtch *afp = NULL; int ifindex; struct ifaddrs *ifap, *sifap, *ifa; struct ifreq paifr; const struct sockaddr_dl *sdl; char options[1024], *cp, *namecp = NULL; struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q); struct ifa_order_elt *cur, *tmp; const char *ifname; struct option *p; size_t iflen; all = downonly = uponly = namesonly = noload = verbose = 0; /* Parse leading line options */ strlcpy(options, "adklmnuv", sizeof(options)); for (p = opts; p != NULL; p = p->next) strlcat(options, p->opt, sizeof(options)); while ((c = getopt(argc, argv, options)) != -1) { switch (c) { case 'a': /* scan all interfaces */ all++; break; case 'd': /* restrict scan to "down" interfaces */ downonly++; break; case 'k': printkeys++; break; case 'l': /* scan interface names only */ namesonly++; break; case 'm': /* show media choices in status */ supmedia = 1; break; case 'n': /* suppress module loading */ noload++; break; case 'u': /* restrict scan to "up" interfaces */ uponly++; break; case 'v': verbose++; break; default: for (p = opts; p != NULL; p = p->next) if (p->opt[0] == c) { p->cb(optarg); break; } if (p == NULL) usage(); break; } } argc -= optind; argv += optind; /* -l cannot be used with -a or -m */ if (namesonly && (all || supmedia)) usage(); /* nonsense.. */ if (uponly && downonly) usage(); /* no arguments is equivalent to '-a' */ if (!namesonly && argc < 1) all = 1; /* -a and -l allow an address family arg to limit the output */ if (all || namesonly) { if (argc > 1) usage(); ifname = NULL; ifindex = 0; if (argc == 1) { afp = af_getbyname(*argv); if (afp == NULL) { warnx("Address family '%s' unknown.", *argv); usage(); } if (afp->af_name != NULL) argc--, argv++; /* leave with afp non-zero */ } } else { /* not listing, need an argument */ if (argc < 1) usage(); ifname = *argv; argc--, argv++; /* check and maybe load support for this interface */ ifmaybeload(ifname); ifindex = if_nametoindex(ifname); if (ifindex == 0) { /* * NOTE: We must special-case the `create' command * right here as we would otherwise fail when trying * to find the interface. */ if (argc > 0 && (strcmp(argv[0], "create") == 0 || strcmp(argv[0], "plumb") == 0)) { iflen = strlcpy(name, ifname, sizeof(name)); if (iflen >= sizeof(name)) errx(1, "%s: cloning name too long", ifname); ifconfig(argc, argv, 1, NULL); exit(0); } #ifdef JAIL /* * NOTE: We have to special-case the `-vnet' command * right here as we would otherwise fail when trying * to find the interface as it lives in another vnet. */ if (argc > 0 && (strcmp(argv[0], "-vnet") == 0)) { iflen = strlcpy(name, ifname, sizeof(name)); if (iflen >= sizeof(name)) errx(1, "%s: interface name too long", ifname); ifconfig(argc, argv, 0, NULL); exit(0); } #endif errx(1, "interface %s does not exist", ifname); } } /* Check for address family */ if (argc > 0) { afp = af_getbyname(*argv); if (afp != NULL) argc--, argv++; } if (getifaddrs(&ifap) != 0) err(EXIT_FAILURE, "getifaddrs"); cp = NULL; if (calcorders(ifap, &q) != 0) err(EXIT_FAILURE, "calcorders"); sifap = sortifaddrs(ifap, cmpifaddrs, &q); TAILQ_FOREACH_SAFE(cur, &q, link, tmp) free(cur); ifindex = 0; for (ifa = sifap; ifa; ifa = ifa->ifa_next) { memset(&paifr, 0, sizeof(paifr)); strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name)); if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) { memcpy(&paifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len); } if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0) continue; if (ifa->ifa_addr->sa_family == AF_LINK) sdl = (const struct sockaddr_dl *) ifa->ifa_addr; else sdl = NULL; if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0 && !namesonly) continue; iflen = strlcpy(name, ifa->ifa_name, sizeof(name)); if (iflen >= sizeof(name)) { warnx("%s: interface name too long, skipping", ifa->ifa_name); continue; } cp = ifa->ifa_name; if ((ifa->ifa_flags & IFF_CANTCONFIG) != 0) continue; if (downonly && (ifa->ifa_flags & IFF_UP) != 0) continue; if (uponly && (ifa->ifa_flags & IFF_UP) == 0) continue; /* * Are we just listing the interfaces? */ if (namesonly) { if (namecp == cp) continue; if (afp != NULL) { /* special case for "ether" address family */ if (!strcmp(afp->af_name, "ether")) { if (sdl == NULL || (sdl->sdl_type != IFT_ETHER && sdl->sdl_type != IFT_L2VLAN && sdl->sdl_type != IFT_BRIDGE) || sdl->sdl_alen != ETHER_ADDR_LEN) continue; } else { if (ifa->ifa_addr->sa_family != afp->af_af) continue; } } namecp = cp; ifindex++; if (ifindex > 1) printf(" "); fputs(name, stdout); continue; } ifindex++; if (argc > 0) ifconfig(argc, argv, 0, afp); else status(afp, sdl, ifa); } if (namesonly) printf("\n"); freeifaddrs(ifap); exit(0); } static struct afswtch *afs = NULL; void af_register(struct afswtch *p) { p->af_next = afs; afs = p; } static struct afswtch * af_getbyname(const char *name) { struct afswtch *afp; for (afp = afs; afp != NULL; afp = afp->af_next) if (strcmp(afp->af_name, name) == 0) return afp; return NULL; } static struct afswtch * af_getbyfamily(int af) { struct afswtch *afp; for (afp = afs; afp != NULL; afp = afp->af_next) if (afp->af_af == af) return afp; return NULL; } static void af_other_status(int s) { struct afswtch *afp; uint8_t afmask[howmany(AF_MAX, NBBY)]; memset(afmask, 0, sizeof(afmask)); for (afp = afs; afp != NULL; afp = afp->af_next) { if (afp->af_other_status == NULL) continue; if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) continue; afp->af_other_status(s); setbit(afmask, afp->af_af); } } static void af_all_tunnel_status(int s) { struct afswtch *afp; uint8_t afmask[howmany(AF_MAX, NBBY)]; memset(afmask, 0, sizeof(afmask)); for (afp = afs; afp != NULL; afp = afp->af_next) { if (afp->af_status_tunnel == NULL) continue; if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) continue; afp->af_status_tunnel(s); setbit(afmask, afp->af_af); } } static struct cmd *cmds = NULL; void cmd_register(struct cmd *p) { p->c_next = cmds; cmds = p; } static const struct cmd * cmd_lookup(const char *name, int iscreate) { #define N(a) (sizeof(a)/sizeof(a[0])) const struct cmd *p; for (p = cmds; p != NULL; p = p->c_next) if (strcmp(name, p->c_name) == 0) { if (iscreate) { if (p->c_iscloneop) return p; } else { if (!p->c_iscloneop) return p; } } return NULL; #undef N } struct callback { callback_func *cb_func; void *cb_arg; struct callback *cb_next; }; static struct callback *callbacks = NULL; void callback_register(callback_func *func, void *arg) { struct callback *cb; cb = malloc(sizeof(struct callback)); if (cb == NULL) errx(1, "unable to allocate memory for callback"); cb->cb_func = func; cb->cb_arg = arg; cb->cb_next = callbacks; callbacks = cb; } /* specially-handled commands */ static void setifaddr(const char *, int, int, const struct afswtch *); static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr); static void setifdstaddr(const char *, int, int, const struct afswtch *); static const struct cmd setifdstaddr_cmd = DEF_CMD("ifdstaddr", 0, setifdstaddr); static int ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp) { const struct afswtch *afp, *nafp; const struct cmd *p; struct callback *cb; int s; strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); afp = NULL; if (uafp != NULL) afp = uafp; /* * This is the historical "accident" allowing users to configure IPv4 * addresses without the "inet" keyword which while a nice feature has * proven to complicate other things. We cannot remove this but only * make sure we will never have a similar implicit default for IPv6 or * any other address familiy. We need a fallback though for * ifconfig IF up/down etc. to work without INET support as people * never used ifconfig IF link up/down, etc. either. */ #ifndef RESCUE #ifdef INET if (afp == NULL && feature_present("inet")) afp = af_getbyname("inet"); #endif #endif if (afp == NULL) afp = af_getbyname("link"); if (afp == NULL) { warnx("Please specify an address_family."); usage(); } top: ifr.ifr_addr.sa_family = afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ? AF_LOCAL : afp->af_af; if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 && (uafp != NULL || errno != EAFNOSUPPORT || (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)) err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family); while (argc > 0) { p = cmd_lookup(*argv, iscreate); if (iscreate && p == NULL) { /* * Push the clone create callback so the new * device is created and can be used for any * remaining arguments. */ cb = callbacks; if (cb == NULL) errx(1, "internal error, no callback"); callbacks = cb->cb_next; cb->cb_func(s, cb->cb_arg); iscreate = 0; /* * Handle any address family spec that * immediately follows and potentially * recreate the socket. */ nafp = af_getbyname(*argv); if (nafp != NULL) { argc--, argv++; if (nafp != afp) { close(s); afp = nafp; goto top; } } /* * Look for a normal parameter. */ continue; } if (p == NULL) { /* * Not a recognized command, choose between setting * the interface address and the dst address. */ p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd); } if (p->c_u.c_func || p->c_u.c_func2) { if (p->c_parameter == NEXTARG) { if (argv[1] == NULL) errx(1, "'%s' requires argument", p->c_name); p->c_u.c_func(argv[1], 0, s, afp); argc--, argv++; } else if (p->c_parameter == OPTARG) { p->c_u.c_func(argv[1], 0, s, afp); if (argv[1] != NULL) argc--, argv++; } else if (p->c_parameter == NEXTARG2) { if (argc < 3) errx(1, "'%s' requires 2 arguments", p->c_name); p->c_u.c_func2(argv[1], argv[2], s, afp); argc -= 2, argv += 2; } else p->c_u.c_func(*argv, p->c_parameter, s, afp); } argc--, argv++; } /* * Do any post argument processing required by the address family. */ if (afp->af_postproc != NULL) afp->af_postproc(s, afp); /* * Do deferred callbacks registered while processing * command-line arguments. */ for (cb = callbacks; cb != NULL; cb = cb->cb_next) cb->cb_func(s, cb->cb_arg); /* * Do deferred operations. */ if (clearaddr) { if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { warnx("interface %s cannot change %s addresses!", name, afp->af_name); clearaddr = 0; } } if (clearaddr) { int ret; strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name); ret = ioctl(s, afp->af_difaddr, afp->af_ridreq); if (ret < 0) { if (errno == EADDRNOTAVAIL && (doalias >= 0)) { /* means no previous address for interface */ } else Perror("ioctl (SIOCDIFADDR)"); } } if (newaddr) { if (afp->af_addreq == NULL || afp->af_aifaddr == 0) { warnx("interface %s cannot change %s addresses!", name, afp->af_name); newaddr = 0; } } if (newaddr && (setaddr || setmask)) { strncpy(afp->af_addreq, name, sizeof ifr.ifr_name); if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) Perror("ioctl (SIOCAIFADDR)"); } close(s); return(0); } /*ARGSUSED*/ static void setifaddr(const char *addr, int param, int s, const struct afswtch *afp) { if (afp->af_getaddr == NULL) return; /* * Delay the ioctl to set the interface addr until flags are all set. * The address interpretation may depend on the flags, * and the flags may change when the address is set. */ setaddr++; if (doalias == 0 && afp->af_af != AF_LINK) clearaddr = 1; afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR)); } static void settunnel(const char *src, const char *dst, int s, const struct afswtch *afp) { struct addrinfo *srcres, *dstres; int ecode; if (afp->af_settunnel == NULL) { warn("address family %s does not support tunnel setup", afp->af_name); return; } if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) errx(1, "error in parsing address string: %s", gai_strerror(ecode)); if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) errx(1, "error in parsing address string: %s", gai_strerror(ecode)); if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) errx(1, "source and destination address families do not match"); afp->af_settunnel(s, srcres, dstres); freeaddrinfo(srcres); freeaddrinfo(dstres); } /* ARGSUSED */ static void deletetunnel(const char *vname, int param, int s, const struct afswtch *afp) { if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) err(1, "SIOCDIFPHYADDR"); } #ifdef JAIL static void setifvnet(const char *jname, int dummy __unused, int s, const struct afswtch *afp) { struct ifreq my_ifr; memcpy(&my_ifr, &ifr, sizeof(my_ifr)); my_ifr.ifr_jid = jail_getid(jname); if (my_ifr.ifr_jid < 0) errx(1, "%s", jail_errmsg); if (ioctl(s, SIOCSIFVNET, &my_ifr) < 0) err(1, "SIOCSIFVNET"); } static void setifrvnet(const char *jname, int dummy __unused, int s, const struct afswtch *afp) { struct ifreq my_ifr; memcpy(&my_ifr, &ifr, sizeof(my_ifr)); my_ifr.ifr_jid = jail_getid(jname); if (my_ifr.ifr_jid < 0) errx(1, "%s", jail_errmsg); if (ioctl(s, SIOCSIFRVNET, &my_ifr) < 0) err(1, "SIOCSIFRVNET(%d, %s)", my_ifr.ifr_jid, my_ifr.ifr_name); } #endif static void setifnetmask(const char *addr, int dummy __unused, int s, const struct afswtch *afp) { if (afp->af_getaddr != NULL) { setmask++; afp->af_getaddr(addr, MASK); } } static void setifbroadaddr(const char *addr, int dummy __unused, int s, const struct afswtch *afp) { if (afp->af_getaddr != NULL) afp->af_getaddr(addr, DSTADDR); } static void notealias(const char *addr, int param, int s, const struct afswtch *afp) { #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) if (setaddr && doalias == 0 && param < 0) if (afp->af_addreq != NULL && afp->af_ridreq != NULL) bcopy((caddr_t)rqtosa(af_addreq), (caddr_t)rqtosa(af_ridreq), rqtosa(af_addreq)->sa_len); doalias = param; if (param < 0) { clearaddr = 1; newaddr = 0; } else clearaddr = 0; #undef rqtosa } /*ARGSUSED*/ static void setifdstaddr(const char *addr, int param __unused, int s, const struct afswtch *afp) { if (afp->af_getaddr != NULL) afp->af_getaddr(addr, DSTADDR); } /* * Note: doing an SIOCIGIFFLAGS scribbles on the union portion * of the ifreq structure, which may confuse other parts of ifconfig. * Make a private copy so we can avoid that. */ static void setifflags(const char *vname, int value, int s, const struct afswtch *afp) { struct ifreq my_ifr; int flags; memset(&my_ifr, 0, sizeof(my_ifr)); (void) strlcpy(my_ifr.ifr_name, name, sizeof(my_ifr.ifr_name)); if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { Perror("ioctl (SIOCGIFFLAGS)"); exit(1); } flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16); if (value < 0) { value = -value; flags &= ~value; } else flags |= value; my_ifr.ifr_flags = flags & 0xffff; my_ifr.ifr_flagshigh = flags >> 16; if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) Perror(vname); } void setifcap(const char *vname, int value, int s, const struct afswtch *afp) { int flags; if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCGIFCAP)"); exit(1); } flags = ifr.ifr_curcap; if (value < 0) { value = -value; flags &= ~value; } else flags |= value; flags &= ifr.ifr_reqcap; ifr.ifr_reqcap = flags; if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0) Perror(vname); } static void setifmetric(const char *val, int dummy __unused, int s, const struct afswtch *afp) { strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_metric = atoi(val); if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) warn("ioctl (set metric)"); } static void setifmtu(const char *val, int dummy __unused, int s, const struct afswtch *afp) { strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_mtu = atoi(val); if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) warn("ioctl (set mtu)"); } static void setifname(const char *val, int dummy __unused, int s, const struct afswtch *afp) { char *newname; newname = strdup(val); if (newname == NULL) { warn("no memory to set ifname"); return; } ifr.ifr_data = newname; if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) { warn("ioctl (set name)"); free(newname); return; } strlcpy(name, newname, sizeof(name)); free(newname); } /* ARGSUSED */ static void setifdescr(const char *val, int dummy __unused, int s, const struct afswtch *afp) { char *newdescr; ifr.ifr_buffer.length = strlen(val) + 1; if (ifr.ifr_buffer.length == 1) { ifr.ifr_buffer.buffer = newdescr = NULL; ifr.ifr_buffer.length = 0; } else { newdescr = strdup(val); ifr.ifr_buffer.buffer = newdescr; if (newdescr == NULL) { warn("no memory to set ifdescr"); return; } } if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) warn("ioctl (set descr)"); free(newdescr); } /* ARGSUSED */ static void unsetifdescr(const char *val, int value, int s, const struct afswtch *afp) { setifdescr("", 0, s, 0); } #define IFFBITS \ "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\7RUNNING" \ "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ "\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP" #define IFCAPBITS \ "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \ "\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \ "\17TOE4\20TOE6\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP" \ "\26RXCSUM_IPV6\27TXCSUM_IPV6" /* * Print the status of the interface. If an address family was * specified, show only it; otherwise, show them all. */ static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl, struct ifaddrs *ifa) { struct ifaddrs *ift; int allfamilies, s; struct ifstat ifs; if (afp == NULL) { allfamilies = 1; ifr.ifr_addr.sa_family = AF_LOCAL; } else { allfamilies = 0; ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af; } strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0); if (s < 0) err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); printf("%s: ", name); printb("flags", ifa->ifa_flags, IFFBITS); if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1) printf(" metric %d", ifr.ifr_metric); if (ioctl(s, SIOCGIFMTU, &ifr) != -1) printf(" mtu %d", ifr.ifr_mtu); putchar('\n'); for (;;) { if ((descr = reallocf(descr, descrlen)) != NULL) { ifr.ifr_buffer.buffer = descr; ifr.ifr_buffer.length = descrlen; if (ioctl(s, SIOCGIFDESCR, &ifr) == 0) { if (ifr.ifr_buffer.buffer == descr) { if (strlen(descr) > 0) printf("\tdescription: %s\n", descr); } else if (ifr.ifr_buffer.length > descrlen) { descrlen = ifr.ifr_buffer.length; continue; } } } else warn("unable to allocate memory for interface" "description"); break; } if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) { if (ifr.ifr_curcap != 0) { printb("\toptions", ifr.ifr_curcap, IFCAPBITS); putchar('\n'); } if (supmedia && ifr.ifr_reqcap != 0) { printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); putchar('\n'); } } tunnel_status(s); for (ift = ifa; ift != NULL; ift = ift->ifa_next) { if (ift->ifa_addr == NULL) continue; if (strcmp(ifa->ifa_name, ift->ifa_name) != 0) continue; if (allfamilies) { const struct afswtch *p; p = af_getbyfamily(ift->ifa_addr->sa_family); if (p != NULL && p->af_status != NULL) p->af_status(s, ift); } else if (afp->af_af == ift->ifa_addr->sa_family) afp->af_status(s, ift); } #if 0 if (allfamilies || afp->af_af == AF_LINK) { const struct afswtch *lafp; /* * Hack; the link level address is received separately * from the routing information so any address is not * handled above. Cobble together an entry and invoke * the status method specially. */ lafp = af_getbyname("lladdr"); if (lafp != NULL) { info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl; lafp->af_status(s, &info); } } #endif if (allfamilies) af_other_status(s); else if (afp->af_other_status != NULL) afp->af_other_status(s); strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name); if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) printf("%s", ifs.ascii); if (verbose > 0) sfp_status(s, &ifr, verbose); close(s); return; } static void tunnel_status(int s) { af_all_tunnel_status(s); } void Perror(const char *cmd) { switch (errno) { case ENXIO: errx(1, "%s: no such interface", cmd); break; case EPERM: errx(1, "%s: permission denied", cmd); break; default: err(1, "%s", cmd); } } /* * Print a value a la the %b format of the kernel's printf */ void printb(const char *s, unsigned v, const char *bits) { int i, any = 0; char c; if (bits && *bits == 8) printf("%s=%o", s, v); else printf("%s=%x", s, v); bits++; if (bits) { putchar('<'); while ((i = *bits++) != '\0') { if (v & (1 << (i-1))) { if (any) putchar(','); any = 1; for (; (c = *bits) > 32; bits++) putchar(c); } else for (; *bits > 32; bits++) ; } putchar('>'); } } void print_vhid(const struct ifaddrs *ifa, const char *s) { struct if_data *ifd; if (ifa->ifa_data == NULL) return; ifd = ifa->ifa_data; if (ifd->ifi_vhid == 0) return; printf("vhid %d ", ifd->ifi_vhid); } void ifmaybeload(const char *name) { #define MOD_PREFIX_LEN 3 /* "if_" */ struct module_stat mstat; int fileid, modid; char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp; const char *cp; /* loading suppressed by the user */ if (noload) return; /* trim the interface number off the end */ strlcpy(ifname, name, sizeof(ifname)); for (dp = ifname; *dp != 0; dp++) if (isdigit(*dp)) { *dp = 0; break; } /* turn interface and unit into module name */ strlcpy(ifkind, "if_", sizeof(ifkind)); strlcat(ifkind, ifname, sizeof(ifkind)); /* scan files in kernel */ mstat.version = sizeof(struct module_stat); for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { /* scan modules in file */ for (modid = kldfirstmod(fileid); modid > 0; modid = modfnext(modid)) { if (modstat(modid, &mstat) < 0) continue; /* strip bus name if present */ if ((cp = strchr(mstat.name, '/')) != NULL) { cp++; } else { cp = mstat.name; } /* already loaded? */ if (strcmp(ifname, cp) == 0 || strcmp(ifkind, cp) == 0) return; } } /* not present, we should try to load it */ kldload(ifkind); } static struct cmd basic_cmds[] = { DEF_CMD("up", IFF_UP, setifflags), DEF_CMD("down", -IFF_UP, setifflags), DEF_CMD("arp", -IFF_NOARP, setifflags), DEF_CMD("-arp", IFF_NOARP, setifflags), DEF_CMD("debug", IFF_DEBUG, setifflags), DEF_CMD("-debug", -IFF_DEBUG, setifflags), DEF_CMD_ARG("description", setifdescr), DEF_CMD_ARG("descr", setifdescr), DEF_CMD("-description", 0, unsetifdescr), DEF_CMD("-descr", 0, unsetifdescr), DEF_CMD("promisc", IFF_PPROMISC, setifflags), DEF_CMD("-promisc", -IFF_PPROMISC, setifflags), DEF_CMD("add", IFF_UP, notealias), DEF_CMD("alias", IFF_UP, notealias), DEF_CMD("-alias", -IFF_UP, notealias), DEF_CMD("delete", -IFF_UP, notealias), DEF_CMD("remove", -IFF_UP, notealias), #ifdef notdef #define EN_SWABIPS 0x1000 DEF_CMD("swabips", EN_SWABIPS, setifflags), DEF_CMD("-swabips", -EN_SWABIPS, setifflags), #endif DEF_CMD_ARG("netmask", setifnetmask), DEF_CMD_ARG("metric", setifmetric), DEF_CMD_ARG("broadcast", setifbroadaddr), DEF_CMD_ARG2("tunnel", settunnel), DEF_CMD("-tunnel", 0, deletetunnel), DEF_CMD("deletetunnel", 0, deletetunnel), #ifdef JAIL DEF_CMD_ARG("vnet", setifvnet), DEF_CMD_ARG("-vnet", setifrvnet), #endif DEF_CMD("link0", IFF_LINK0, setifflags), DEF_CMD("-link0", -IFF_LINK0, setifflags), DEF_CMD("link1", IFF_LINK1, setifflags), DEF_CMD("-link1", -IFF_LINK1, setifflags), DEF_CMD("link2", IFF_LINK2, setifflags), DEF_CMD("-link2", -IFF_LINK2, setifflags), DEF_CMD("monitor", IFF_MONITOR, setifflags), DEF_CMD("-monitor", -IFF_MONITOR, setifflags), DEF_CMD("staticarp", IFF_STATICARP, setifflags), DEF_CMD("-staticarp", -IFF_STATICARP, setifflags), DEF_CMD("rxcsum6", IFCAP_RXCSUM_IPV6, setifcap), DEF_CMD("-rxcsum6", -IFCAP_RXCSUM_IPV6, setifcap), DEF_CMD("txcsum6", IFCAP_TXCSUM_IPV6, setifcap), DEF_CMD("-txcsum6", -IFCAP_TXCSUM_IPV6, setifcap), DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap), DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap), DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap), DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap), DEF_CMD("netcons", IFCAP_NETCONS, setifcap), DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap), DEF_CMD("polling", IFCAP_POLLING, setifcap), DEF_CMD("-polling", -IFCAP_POLLING, setifcap), DEF_CMD("tso6", IFCAP_TSO6, setifcap), DEF_CMD("-tso6", -IFCAP_TSO6, setifcap), DEF_CMD("tso4", IFCAP_TSO4, setifcap), DEF_CMD("-tso4", -IFCAP_TSO4, setifcap), DEF_CMD("tso", IFCAP_TSO, setifcap), DEF_CMD("-tso", -IFCAP_TSO, setifcap), DEF_CMD("toe", IFCAP_TOE, setifcap), DEF_CMD("-toe", -IFCAP_TOE, setifcap), DEF_CMD("lro", IFCAP_LRO, setifcap), DEF_CMD("-lro", -IFCAP_LRO, setifcap), DEF_CMD("wol", IFCAP_WOL, setifcap), DEF_CMD("-wol", -IFCAP_WOL, setifcap), DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap), DEF_CMD("-wol_ucast", -IFCAP_WOL_UCAST, setifcap), DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap), DEF_CMD("-wol_mcast", -IFCAP_WOL_MCAST, setifcap), DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap), DEF_CMD("-wol_magic", -IFCAP_WOL_MAGIC, setifcap), DEF_CMD("normal", -IFF_LINK0, setifflags), DEF_CMD("compress", IFF_LINK0, setifflags), DEF_CMD("noicmp", IFF_LINK1, setifflags), DEF_CMD_ARG("mtu", setifmtu), DEF_CMD_ARG("name", setifname), }; static __constructor void ifconfig_ctor(void) { #define N(a) (sizeof(a) / sizeof(a[0])) size_t i; for (i = 0; i < N(basic_cmds); i++) cmd_register(&basic_cmds[i]); #undef N } diff --git a/sbin/ifconfig/ifvlan.c b/sbin/ifconfig/ifvlan.c index cefcbbceffb4..1a3fbaa5de47 100644 --- a/sbin/ifconfig/ifvlan.c +++ b/sbin/ifconfig/ifvlan.c @@ -1,207 +1,206 @@ /* * Copyright (c) 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include "ifconfig.h" #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif #define NOTAG ((u_short) -1) static struct vlanreq params = { .vlr_tag = NOTAG, }; static int getvlan(int s, struct ifreq *ifr, struct vlanreq *vreq) { bzero((char *)vreq, sizeof(*vreq)); ifr->ifr_data = (caddr_t)vreq; return ioctl(s, SIOCGETVLAN, (caddr_t)ifr); } static void vlan_status(int s) { struct vlanreq vreq; if (getvlan(s, &ifr, &vreq) != -1) printf("\tvlan: %d parent interface: %s\n", vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ? "" : vreq.vlr_parent); } static void vlan_create(int s, struct ifreq *ifr) { if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0') { /* * One or both parameters were specified, make sure both. */ if (params.vlr_tag == NOTAG) errx(1, "must specify a tag for vlan create"); if (params.vlr_parent[0] == '\0') errx(1, "must specify a parent device for vlan create"); ifr->ifr_data = (caddr_t) ¶ms; } if (ioctl(s, SIOCIFCREATE2, ifr) < 0) err(1, "SIOCIFCREATE2"); } static void vlan_cb(int s, void *arg) { if ((params.vlr_tag != NOTAG) ^ (params.vlr_parent[0] != '\0')) errx(1, "both vlan and vlandev must be specified"); } static void vlan_set(int s, struct ifreq *ifr) { if (params.vlr_tag != NOTAG && params.vlr_parent[0] != '\0') { ifr->ifr_data = (caddr_t) ¶ms; if (ioctl(s, SIOCSETVLAN, (caddr_t)ifr) == -1) err(1, "SIOCSETVLAN"); } } static DECL_CMD_FUNC(setvlantag, val, d) { struct vlanreq vreq; u_long ul; char *endp; ul = strtoul(val, &endp, 0); if (*endp != '\0') errx(1, "invalid value for vlan"); params.vlr_tag = ul; /* check if the value can be represented in vlr_tag */ if (params.vlr_tag != ul) errx(1, "value for vlan out of range"); if (getvlan(s, &ifr, &vreq) != -1) vlan_set(s, &ifr); } static DECL_CMD_FUNC(setvlandev, val, d) { struct vlanreq vreq; strlcpy(params.vlr_parent, val, sizeof(params.vlr_parent)); if (getvlan(s, &ifr, &vreq) != -1) vlan_set(s, &ifr); } static DECL_CMD_FUNC(unsetvlandev, val, d) { struct vlanreq vreq; bzero((char *)&vreq, sizeof(struct vlanreq)); ifr.ifr_data = (caddr_t)&vreq; if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) err(1, "SIOCGETVLAN"); bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent)); vreq.vlr_tag = 0; if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1) err(1, "SIOCSETVLAN"); } static struct cmd vlan_cmds[] = { DEF_CLONE_CMD_ARG("vlan", setvlantag), DEF_CLONE_CMD_ARG("vlandev", setvlandev), /* NB: non-clone cmds */ DEF_CMD_ARG("vlan", setvlantag), DEF_CMD_ARG("vlandev", setvlandev), /* XXX For compatibility. Should become DEF_CMD() some day. */ DEF_CMD_OPTARG("-vlandev", unsetvlandev), DEF_CMD("vlanmtu", IFCAP_VLAN_MTU, setifcap), DEF_CMD("-vlanmtu", -IFCAP_VLAN_MTU, setifcap), DEF_CMD("vlanhwtag", IFCAP_VLAN_HWTAGGING, setifcap), DEF_CMD("-vlanhwtag", -IFCAP_VLAN_HWTAGGING, setifcap), DEF_CMD("vlanhwfilter", IFCAP_VLAN_HWFILTER, setifcap), DEF_CMD("-vlanhwfilter", -IFCAP_VLAN_HWFILTER, setifcap), DEF_CMD("-vlanhwtso", -IFCAP_VLAN_HWTSO, setifcap), DEF_CMD("vlanhwtso", IFCAP_VLAN_HWTSO, setifcap), DEF_CMD("vlanhwcsum", IFCAP_VLAN_HWCSUM, setifcap), DEF_CMD("-vlanhwcsum", -IFCAP_VLAN_HWCSUM, setifcap), }; static struct afswtch af_vlan = { .af_name = "af_vlan", .af_af = AF_UNSPEC, .af_other_status = vlan_status, }; static __constructor void vlan_ctor(void) { #define N(a) (sizeof(a) / sizeof(a[0])) size_t i; for (i = 0; i < N(vlan_cmds); i++) cmd_register(&vlan_cmds[i]); af_register(&af_vlan); callback_register(vlan_cb, NULL); clone_setdefcallback("vlan", vlan_create); #undef N } diff --git a/sbin/ifconfig/ifvxlan.c b/sbin/ifconfig/ifvxlan.c index 9aa84a29ff2b..48f5331bf686 100644 --- a/sbin/ifconfig/ifvxlan.c +++ b/sbin/ifconfig/ifvxlan.c @@ -1,648 +1,647 @@ /*- * Copyright (c) 2014, Bryan Venteicher * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include "ifconfig.h" static struct ifvxlanparam params = { .vxlp_vni = VXLAN_VNI_MAX, }; static int get_val(const char *cp, u_long *valp) { char *endptr; u_long val; errno = 0; val = strtoul(cp, &endptr, 0); if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) return (-1); *valp = val; return (0); } static int do_cmd(int sock, u_long op, void *arg, size_t argsize, int set) { struct ifdrv ifd; bzero(&ifd, sizeof(ifd)); strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name)); ifd.ifd_cmd = op; ifd.ifd_len = argsize; ifd.ifd_data = arg; return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd)); } static int vxlan_exists(int sock) { struct ifvxlancfg cfg; bzero(&cfg, sizeof(cfg)); return (do_cmd(sock, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) != -1); } static void vxlan_status(int s) { struct ifvxlancfg cfg; char src[NI_MAXHOST], dst[NI_MAXHOST]; char srcport[NI_MAXSERV], dstport[NI_MAXSERV]; struct sockaddr *lsa, *rsa; int vni, mc, ipv6; bzero(&cfg, sizeof(cfg)); if (do_cmd(s, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) < 0) return; vni = cfg.vxlc_vni; lsa = &cfg.vxlc_local_sa.sa; rsa = &cfg.vxlc_remote_sa.sa; ipv6 = rsa->sa_family == AF_INET6; /* Just report nothing if the network identity isn't set yet. */ if (vni >= VXLAN_VNI_MAX) return; if (getnameinfo(lsa, lsa->sa_len, src, sizeof(src), srcport, sizeof(srcport), NI_NUMERICHOST | NI_NUMERICSERV) != 0) src[0] = srcport[0] = '\0'; if (getnameinfo(rsa, rsa->sa_len, dst, sizeof(dst), dstport, sizeof(dstport), NI_NUMERICHOST | NI_NUMERICSERV) != 0) dst[0] = dstport[0] = '\0'; if (!ipv6) { struct sockaddr_in *sin = (struct sockaddr_in *)rsa; mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr)); } else { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rsa; mc = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr); } printf("\tvxlan vni %d", vni); printf(" local %s%s%s:%s", ipv6 ? "[" : "", src, ipv6 ? "]" : "", srcport); printf(" %s %s%s%s:%s", mc ? "group" : "remote", ipv6 ? "[" : "", dst, ipv6 ? "]" : "", dstport); if (verbose) { printf("\n\t\tconfig: "); printf("%slearning portrange %d-%d ttl %d", cfg.vxlc_learn ? "" : "no", cfg.vxlc_port_min, cfg.vxlc_port_max, cfg.vxlc_ttl); printf("\n\t\tftable: "); printf("cnt %d max %d timeout %d", cfg.vxlc_ftable_cnt, cfg.vxlc_ftable_max, cfg.vxlc_ftable_timeout); } putchar('\n'); } #define _LOCAL_ADDR46 \ (VXLAN_PARAM_WITH_LOCAL_ADDR4 | VXLAN_PARAM_WITH_LOCAL_ADDR6) #define _REMOTE_ADDR46 \ (VXLAN_PARAM_WITH_REMOTE_ADDR4 | VXLAN_PARAM_WITH_REMOTE_ADDR6) static void vxlan_check_params(void) { if ((params.vxlp_with & _LOCAL_ADDR46) == _LOCAL_ADDR46) errx(1, "cannot specify both local IPv4 and IPv6 addresses"); if ((params.vxlp_with & _REMOTE_ADDR46) == _REMOTE_ADDR46) errx(1, "cannot specify both remote IPv4 and IPv6 addresses"); if ((params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR4 && params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR6) || (params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR6 && params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR4)) errx(1, "cannot mix IPv4 and IPv6 addresses"); } #undef _LOCAL_ADDR46 #undef _REMOTE_ADDR46 static void vxlan_cb(int s, void *arg) { } static void vxlan_create(int s, struct ifreq *ifr) { vxlan_check_params(); ifr->ifr_data = (caddr_t) ¶ms; if (ioctl(s, SIOCIFCREATE2, ifr) < 0) err(1, "SIOCIFCREATE2"); } static DECL_CMD_FUNC(setvxlan_vni, arg, d) { struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || val >= VXLAN_VNI_MAX) errx(1, "invalid network identifier: %s", arg); if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_VNI; params.vxlp_vni = val; return; } bzero(&cmd, sizeof(cmd)); cmd.vxlcmd_vni = val; if (do_cmd(s, VXLAN_CMD_SET_VNI, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_VNI"); } static DECL_CMD_FUNC(setvxlan_local, addr, d) { struct ifvxlancmd cmd; struct addrinfo *ai; struct sockaddr *sa; int error; bzero(&cmd, sizeof(cmd)); if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) errx(1, "error in parsing local address string: %s", gai_strerror(error)); sa = ai->ai_addr; switch (ai->ai_family) { #ifdef INET case AF_INET: { struct in_addr addr = ((struct sockaddr_in *) sa)->sin_addr; if (IN_MULTICAST(ntohl(addr.s_addr))) errx(1, "local address cannot be multicast"); cmd.vxlcmd_sa.in4.sin_family = AF_INET; cmd.vxlcmd_sa.in4.sin_addr = addr; break; } #endif #ifdef INET6 case AF_INET6: { struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; if (IN6_IS_ADDR_MULTICAST(addr)) errx(1, "local address cannot be multicast"); cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; cmd.vxlcmd_sa.in6.sin6_addr = *addr; break; } #endif default: errx(1, "local address %s not supported", addr); } freeaddrinfo(ai); if (!vxlan_exists(s)) { if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR4; params.vxlp_local_in4 = cmd.vxlcmd_sa.in4.sin_addr; } else { params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR6; params.vxlp_local_in6 = cmd.vxlcmd_sa.in6.sin6_addr; } return; } if (do_cmd(s, VXLAN_CMD_SET_LOCAL_ADDR, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_LOCAL_ADDR"); } static DECL_CMD_FUNC(setvxlan_remote, addr, d) { struct ifvxlancmd cmd; struct addrinfo *ai; struct sockaddr *sa; int error; bzero(&cmd, sizeof(cmd)); if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) errx(1, "error in parsing remote address string: %s", gai_strerror(error)); sa = ai->ai_addr; switch (ai->ai_family) { #ifdef INET case AF_INET: { struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr; if (IN_MULTICAST(ntohl(addr.s_addr))) errx(1, "remote address cannot be multicast"); cmd.vxlcmd_sa.in4.sin_family = AF_INET; cmd.vxlcmd_sa.in4.sin_addr = addr; break; } #endif #ifdef INET6 case AF_INET6: { struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; if (IN6_IS_ADDR_MULTICAST(addr)) errx(1, "remote address cannot be multicast"); cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; cmd.vxlcmd_sa.in6.sin6_addr = *addr; break; } #endif default: errx(1, "remote address %s not supported", addr); } freeaddrinfo(ai); if (!vxlan_exists(s)) { if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4; params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr; } else { params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6; params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr; } return; } if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_REMOTE_ADDR"); } static DECL_CMD_FUNC(setvxlan_group, addr, d) { struct ifvxlancmd cmd; struct addrinfo *ai; struct sockaddr *sa; int error; bzero(&cmd, sizeof(cmd)); if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0) errx(1, "error in parsing group address string: %s", gai_strerror(error)); sa = ai->ai_addr; switch (ai->ai_family) { #ifdef INET case AF_INET: { struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr; if (!IN_MULTICAST(ntohl(addr.s_addr))) errx(1, "group address must be multicast"); cmd.vxlcmd_sa.in4.sin_family = AF_INET; cmd.vxlcmd_sa.in4.sin_addr = addr; break; } #endif #ifdef INET6 case AF_INET6: { struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr; if (!IN6_IS_ADDR_MULTICAST(addr)) errx(1, "group address must be multicast"); cmd.vxlcmd_sa.in6.sin6_family = AF_INET6; cmd.vxlcmd_sa.in6.sin6_addr = *addr; break; } #endif default: errx(1, "group address %s not supported", addr); } freeaddrinfo(ai); if (!vxlan_exists(s)) { if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) { params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4; params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr; } else { params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6; params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr; } return; } if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_REMOTE_ADDR"); } static DECL_CMD_FUNC(setvxlan_local_port, arg, d) { struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || val >= UINT16_MAX) errx(1, "invalid local port: %s", arg); if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_PORT; params.vxlp_local_port = val; return; } bzero(&cmd, sizeof(cmd)); cmd.vxlcmd_port = val; if (do_cmd(s, VXLAN_CMD_SET_LOCAL_PORT, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_LOCAL_PORT"); } static DECL_CMD_FUNC(setvxlan_remote_port, arg, d) { struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || val >= UINT16_MAX) errx(1, "invalid remote port: %s", arg); if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_PORT; params.vxlp_remote_port = val; return; } bzero(&cmd, sizeof(cmd)); cmd.vxlcmd_port = val; if (do_cmd(s, VXLAN_CMD_SET_REMOTE_PORT, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_REMOTE_PORT"); } static DECL_CMD_FUNC2(setvxlan_port_range, arg1, arg2) { struct ifvxlancmd cmd; u_long min, max; if (get_val(arg1, &min) < 0 || min >= UINT16_MAX) errx(1, "invalid port range minimum: %s", arg1); if (get_val(arg2, &max) < 0 || max >= UINT16_MAX) errx(1, "invalid port range maximum: %s", arg2); if (max < min) errx(1, "invalid port range"); if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_PORT_RANGE; params.vxlp_min_port = min; params.vxlp_max_port = max; return; } bzero(&cmd, sizeof(cmd)); cmd.vxlcmd_port_min = min; cmd.vxlcmd_port_max = max; if (do_cmd(s, VXLAN_CMD_SET_PORT_RANGE, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_PORT_RANGE"); } static DECL_CMD_FUNC(setvxlan_timeout, arg, d) { struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0) errx(1, "invalid timeout value: %s", arg); if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_TIMEOUT; params.vxlp_ftable_timeout = val & 0xFFFFFFFF; return; } bzero(&cmd, sizeof(cmd)); cmd.vxlcmd_ftable_timeout = val & 0xFFFFFFFF; if (do_cmd(s, VXLAN_CMD_SET_FTABLE_TIMEOUT, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_FTABLE_TIMEOUT"); } static DECL_CMD_FUNC(setvxlan_maxaddr, arg, d) { struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0) errx(1, "invalid maxaddr value: %s", arg); if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_MAX; params.vxlp_ftable_max = val & 0xFFFFFFFF; return; } bzero(&cmd, sizeof(cmd)); cmd.vxlcmd_ftable_max = val & 0xFFFFFFFF; if (do_cmd(s, VXLAN_CMD_SET_FTABLE_MAX, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_FTABLE_MAX"); } static DECL_CMD_FUNC(setvxlan_dev, arg, d) { struct ifvxlancmd cmd; if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_MULTICAST_IF; strlcpy(params.vxlp_mc_ifname, arg, sizeof(params.vxlp_mc_ifname)); return; } bzero(&cmd, sizeof(cmd)); strlcpy(cmd.vxlcmd_ifname, arg, sizeof(cmd.vxlcmd_ifname)); if (do_cmd(s, VXLAN_CMD_SET_MULTICAST_IF, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_MULTICAST_IF"); } static DECL_CMD_FUNC(setvxlan_ttl, arg, d) { struct ifvxlancmd cmd; u_long val; if (get_val(arg, &val) < 0 || val > 256) errx(1, "invalid TTL value: %s", arg); if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_TTL; params.vxlp_ttl = val; return; } bzero(&cmd, sizeof(cmd)); cmd.vxlcmd_ttl = val; if (do_cmd(s, VXLAN_CMD_SET_TTL, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_TTL"); } static DECL_CMD_FUNC(setvxlan_learn, arg, d) { struct ifvxlancmd cmd; if (!vxlan_exists(s)) { params.vxlp_with |= VXLAN_PARAM_WITH_LEARN; params.vxlp_learn = d; return; } bzero(&cmd, sizeof(cmd)); if (d != 0) cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_LEARN; if (do_cmd(s, VXLAN_CMD_SET_LEARN, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_SET_LEARN"); } static void setvxlan_flush(const char *val, int d, int s, const struct afswtch *afp) { struct ifvxlancmd cmd; bzero(&cmd, sizeof(cmd)); if (d != 0) cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_FLUSH_ALL; if (do_cmd(s, VXLAN_CMD_FLUSH, &cmd, sizeof(cmd), 1) < 0) err(1, "VXLAN_CMD_FLUSH"); } static struct cmd vxlan_cmds[] = { DEF_CLONE_CMD_ARG("vxlanid", setvxlan_vni), DEF_CLONE_CMD_ARG("vxlanlocal", setvxlan_local), DEF_CLONE_CMD_ARG("vxlanremote", setvxlan_remote), DEF_CLONE_CMD_ARG("vxlangroup", setvxlan_group), DEF_CLONE_CMD_ARG("vxlanlocalport", setvxlan_local_port), DEF_CLONE_CMD_ARG("vxlanremoteport", setvxlan_remote_port), DEF_CLONE_CMD_ARG2("vxlanportrange", setvxlan_port_range), DEF_CLONE_CMD_ARG("vxlantimeout", setvxlan_timeout), DEF_CLONE_CMD_ARG("vxlanmaxaddr", setvxlan_maxaddr), DEF_CLONE_CMD_ARG("vxlandev", setvxlan_dev), DEF_CLONE_CMD_ARG("vxlanttl", setvxlan_ttl), DEF_CLONE_CMD("vxlanlearn", 1, setvxlan_learn), DEF_CLONE_CMD("-vxlanlearn", 0, setvxlan_learn), DEF_CMD_ARG("vxlanvni", setvxlan_vni), DEF_CMD_ARG("vxlanlocal", setvxlan_local), DEF_CMD_ARG("vxlanremote", setvxlan_remote), DEF_CMD_ARG("vxlangroup", setvxlan_group), DEF_CMD_ARG("vxlanlocalport", setvxlan_local_port), DEF_CMD_ARG("vxlanremoteport", setvxlan_remote_port), DEF_CMD_ARG2("vxlanportrange", setvxlan_port_range), DEF_CMD_ARG("vxlantimeout", setvxlan_timeout), DEF_CMD_ARG("vxlanmaxaddr", setvxlan_maxaddr), DEF_CMD_ARG("vxlandev", setvxlan_dev), DEF_CMD_ARG("vxlanttl", setvxlan_ttl), DEF_CMD("vxlanlearn", 1, setvxlan_learn), DEF_CMD("-vxlanlearn", 0, setvxlan_learn), DEF_CMD("vxlanflush", 0, setvxlan_flush), DEF_CMD("vxlanflushall", 1, setvxlan_flush), }; static struct afswtch af_vxlan = { .af_name = "af_vxlan", .af_af = AF_UNSPEC, .af_other_status = vxlan_status, }; static __constructor void vxlan_ctor(void) { #define N(a) (sizeof(a) / sizeof(a[0])) size_t i; for (i = 0; i < N(vxlan_cmds); i++) cmd_register(&vxlan_cmds[i]); af_register(&af_vxlan); callback_register(vxlan_cb, NULL); clone_setdefcallback("vxlan", vxlan_create); #undef N } diff --git a/tools/tools/ath/athratestats/main.c b/tools/tools/ath/athratestats/main.c index 815ed91bd61e..3881e8543be0 100644 --- a/tools/tools/ath/athratestats/main.c +++ b/tools/tools/ath/athratestats/main.c @@ -1,402 +1,401 @@ /*- * Copyright (c) 2012, Adrian Chadd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * * $FreeBSD$ */ #include "opt_ah.h" #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include "ah.h" #include "ah_desc.h" #include "net80211/ieee80211_ioctl.h" #include "net80211/ieee80211_radiotap.h" #include "if_athioctl.h" #include "if_athrate.h" #include "ath_rate/sample/sample.h" static int do_loop = 0; /* * This needs to be big enough to fit the two TLVs, the rate table * and the rate statistics table for a single node. */ #define STATS_BUF_SIZE 8192 #define PRINTMSG(...) do { \ if (do_loop == 0) \ printf(__VA_ARGS__); \ else \ printw(__VA_ARGS__); \ } while (0) #define PRINTATTR_ON(_x) do { \ if (do_loop) \ attron(_x); \ } while(0) #define PRINTATTR_OFF(_x) do { \ if (do_loop) \ attroff(_x); \ } while(0) struct ath_ratestats { int s; struct ath_rateioctl re; }; static inline int dot11rate(struct ath_rateioctl_rt *rt, int rix) { if (rt->ratecode[rix] & IEEE80211_RATE_MCS) return rt->ratecode[rix] & ~(IEEE80211_RATE_MCS); else return (rt->ratecode[rix] / 2); } static const char * dot11str(struct ath_rateioctl_rt *rt, int rix) { if (rix == -1) return ""; else if (rt->ratecode[rix] & IEEE80211_RATE_MCS) return "MCS"; else return " Mb"; } static void ath_sample_stats(struct ath_ratestats *r, struct ath_rateioctl_rt *rt, struct sample_node *sn) { uint64_t mask; int rix, y; PRINTMSG("static_rix (%d) ratemask 0x%llx\n", sn->static_rix, (long long) sn->ratemask); for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { PRINTATTR_ON(COLOR_PAIR(y+4) | A_BOLD); PRINTMSG("[%4u] cur rate %d %s since switch: " "packets %d ticks %u\n", bin_to_size(y), dot11rate(rt, sn->current_rix[y]), dot11str(rt, sn->current_rix[y]), sn->packets_since_switch[y], sn->ticks_since_switch[y]); PRINTMSG("[%4u] last sample (%d %s) cur sample (%d %s) " "packets sent %d\n", bin_to_size(y), dot11rate(rt, sn->last_sample_rix[y]), dot11str(rt, sn->last_sample_rix[y]), dot11rate(rt, sn->current_sample_rix[y]), dot11str(rt, sn->current_sample_rix[y]), sn->packets_sent[y]); PRINTATTR_OFF(COLOR_PAIR(y+4) | A_BOLD); PRINTATTR_ON(COLOR_PAIR(3) | A_BOLD); PRINTMSG("[%4u] packets since sample %d sample tt %u\n", bin_to_size(y), sn->packets_since_sample[y], sn->sample_tt[y]); PRINTATTR_OFF(COLOR_PAIR(3) | A_BOLD); PRINTMSG("\n"); } PRINTMSG(" TX Rate TXTOTAL:TXOK EWMA T/ F" " avg last xmit\n"); for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { if ((mask & 1) == 0) continue; for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { if (sn->stats[y][rix].total_packets == 0) continue; if (rix == sn->current_rix[y]) PRINTATTR_ON(COLOR_PAIR(y+4) | A_BOLD); else if (rix == sn->last_sample_rix[y]) PRINTATTR_ON(COLOR_PAIR(3) | A_BOLD); #if 0 else if (sn->stats[y][rix].ewma_pct / 10 < 50) PRINTATTR_ON(COLOR_PAIR(2) | A_BOLD); else if (sn->stats[y][rix].ewma_pct / 10 < 75) PRINTATTR_ON(COLOR_PAIR(1) | A_BOLD); #endif PRINTMSG("[%2u %s:%4u] %8ju:%-8ju " "(%3d.%1d%%) %8ju/%4d %5uuS %u\n", dot11rate(rt, rix), dot11str(rt, rix), bin_to_size(y), (uintmax_t) sn->stats[y][rix].total_packets, (uintmax_t) sn->stats[y][rix].packets_acked, sn->stats[y][rix].ewma_pct / 10, sn->stats[y][rix].ewma_pct % 10, (uintmax_t) sn->stats[y][rix].tries, sn->stats[y][rix].successive_failures, sn->stats[y][rix].average_tx_time, sn->stats[y][rix].last_tx); if (rix == sn->current_rix[y]) PRINTATTR_OFF(COLOR_PAIR(y+4) | A_BOLD); else if (rix == sn->last_sample_rix[y]) PRINTATTR_OFF(COLOR_PAIR(3) | A_BOLD); #if 0 else if (sn->stats[y][rix].ewma_pct / 10 < 50) PRINTATTR_OFF(COLOR_PAIR(2) | A_BOLD); else if (sn->stats[y][rix].ewma_pct / 10 < 75) PRINTATTR_OFF(COLOR_PAIR(1) | A_BOLD); #endif } } } static void ath_setifname(struct ath_ratestats *r, const char *ifname) { strncpy(r->re.if_name, ifname, sizeof (r->re.if_name)); } static void ath_setsta(struct ath_ratestats *r, uint8_t *mac) { memcpy(&r->re.is_u.macaddr, mac, sizeof(r->re.is_u.macaddr)); } static void ath_rate_ioctl(struct ath_ratestats *r) { if (ioctl(r->s, SIOCGATHNODERATESTATS, &r->re) < 0) err(1, "ioctl"); } static int rate_node_stats(struct ath_ratestats *r, struct ether_addr *e) { struct ath_rateioctl_tlv *av; struct sample_node *sn = NULL; struct ath_rateioctl_rt *rt = NULL; int error = 0; uint8_t *buf = (uint8_t *) r->re.buf; /* * For now, hard-code the TLV order and contents. Ew! */ av = (struct ath_rateioctl_tlv *) buf; if (av->tlv_id != ATH_RATE_TLV_RATETABLE) { fprintf(stderr, "unexpected rate control TLV (got 0x%x, " "expected 0x%x\n", av->tlv_id, ATH_RATE_TLV_RATETABLE); exit(127); } if (av->tlv_len != sizeof(struct ath_rateioctl_rt)) { fprintf(stderr, "unexpected TLV len (got %d bytes, " "expected %d bytes\n", av->tlv_len, (int) sizeof(struct ath_rateioctl_rt)); exit(127); } rt = (void *) (buf + sizeof(struct ath_rateioctl_tlv)); /* Next */ av = (void *) (buf + sizeof(struct ath_rateioctl_tlv) + sizeof(struct ath_rateioctl_rt)); if (av->tlv_id != ATH_RATE_TLV_SAMPLENODE) { fprintf(stderr, "unexpected rate control TLV (got 0x%x, " "expected 0x%x\n", av->tlv_id, ATH_RATE_TLV_SAMPLENODE); exit(127); } if (av->tlv_len != sizeof(struct sample_node)) { fprintf(stderr, "unexpected TLV len (got %d bytes, " "expected %d bytes\n", av->tlv_len, (int) sizeof(struct sample_node)); exit(127); } sn = (void *) (buf + sizeof(struct ath_rateioctl_tlv) + sizeof(struct ath_rateioctl_rt) + sizeof(struct ath_rateioctl_tlv)); ath_sample_stats(r, rt, sn); return (0); } static void fetch_and_print_stats(struct ath_ratestats *r, struct ether_addr *e, uint8_t *buf) { /* Zero the buffer before it's passed in */ memset(buf, '\0', STATS_BUF_SIZE); /* * Set the station address for this lookup. */ ath_setsta(r, e->octet); /* * Fetch the data from the driver. */ ath_rate_ioctl(r); /* * Decode and parse statistics. */ rate_node_stats(r, e); } int main(int argc, char *argv[]) { char const *ifname = NULL, *macaddr = NULL; int c; int do_all = 0; struct ether_addr *e; struct ath_ratestats r; uint8_t *buf; useconds_t sleep_period; float f; short cf, cb; ifname = getenv("ATH"); if (ifname == NULL) ifname = "ath0"; while ((c = getopt(argc, argv, "ahi:m:s:")) != -1) { switch (c) { case 'a': do_all = 1; break; case 'i': ifname = optarg; break; case 'm': macaddr = optarg; break; case 's': sscanf(optarg, "%f", &f); do_loop = 1; sleep_period = (useconds_t) (f * 1000000.0); break; default: errx(1, "usage: %s [-h] [-i ifname] [-a] [-m macaddr] [-s sleep period]\n", argv[0]); /* NOTREACHED */ } } if (macaddr == NULL) { errx(1, "%s: macaddress wasn't supplied and no -a given\n", argv[0]); /* NOTREACHED */ } e = ether_aton(macaddr); if (e == NULL) err(1, "ether_aton"); bzero(&r, sizeof(r)); /* * Persistent buffer for each lookup */ buf = malloc(STATS_BUF_SIZE); if (buf == NULL) err(1, "calloc"); r.re.buf = (char *) buf; r.re.len = STATS_BUF_SIZE; r.s = socket(AF_INET, SOCK_DGRAM, 0); if (r.s < 0) { err(1, "socket"); } /* XXX error check */ ath_setifname(&r, ifname); if (do_loop) { initscr(); start_color(); use_default_colors(); pair_content(0, &cf, &cb); /* Error - medium */ init_pair(1, COLOR_YELLOW, cb); /* Error - high */ init_pair(2, COLOR_RED, cb); /* Sample */ init_pair(3, COLOR_CYAN, cb); /* 250 byte frames */ init_pair(4, COLOR_BLUE, cb); /* 1600 byte frames */ init_pair(5, COLOR_MAGENTA, cb); cbreak(); noecho(); nonl(); nodelay(stdscr, 1); intrflush(stdscr, FALSE); keypad(stdscr, TRUE); while (1) { clear(); move(0, 0); fetch_and_print_stats(&r, e, buf); refresh(); usleep(sleep_period); } } else fetch_and_print_stats(&r, e, buf); exit(0); } diff --git a/tools/tools/cxgbtool/cxgbtool.c b/tools/tools/cxgbtool/cxgbtool.c index f73f1a4d5c47..8eaaf28e34bd 100644 --- a/tools/tools/cxgbtool/cxgbtool.c +++ b/tools/tools/cxgbtool/cxgbtool.c @@ -1,1771 +1,1770 @@ /************************************************************************** Copyright (c) 2007-2010, Chelsio Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the Chelsio Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #define NMTUS 16 #define TCB_SIZE 128 #define TCB_WORDS (TCB_SIZE / 4) #define PROTO_SRAM_LINES 128 #define PROTO_SRAM_LINE_BITS 132 #define PROTO_SRAM_LINE_NIBBLES (132 / 4) #define PROTO_SRAM_SIZE (PROTO_SRAM_LINE_NIBBLES * PROTO_SRAM_LINES / 2) #define PROTO_SRAM_EEPROM_ADDR 4096 #include #include #include "version.h" struct reg_info { const char *name; uint16_t addr; uint16_t len; }; #include "reg_defs.c" #if defined(CONFIG_T3_REGS) # include "reg_defs_t3.c" # include "reg_defs_t3b.c" # include "reg_defs_t3c.c" #endif static const char *progname; static void usage(FILE *fp) { fprintf(fp, "Usage: %s [operation]\n", progname); fprintf(fp, "\tclearstats clear MAC statistics\n" "\tcontext show an SGE context\n" "\tdesc [] dump SGE descriptors\n" "\tfilter [ ] ... set a filter\n" "\tfilter delete|clear delete a filter\n" "\tfilter list list all filters\n" "\tioqs dump uP IOQs\n" "\tla dump uP logic analyzer info\n" "\tloadboot download boot image\n" "\tloadfw download firmware\n" "\tmdio \n" "\t [] read/write MDIO register\n" "\tmemdump cm|tx|rx dump a mem range\n" "\tmeminfo show memory info\n" "\tmtus [...] read/write MTU table\n" "\tpktsched port set TX port scheduler params\n" "\tpktsched tunnelq \n" "\t set TX tunnelq scheduler params\n" "\tpktsched tx \n" "\t [ ] ... set Tx HW scheduler\n" "\tpm [ ] read/write PM config\n" "\tproto read proto SRAM\n" "\tqset read qset parameters\n" "\tqsets read # of qsets\n" "\treg
[=] read/write register\n" "\tregdump [] dump registers\n" "\ttcamdump
show TCAM contents\n" "\ttcb read TCB\n" "\ttrace tx|rx|all on|off [not]\n" "\t [ [:]] ... write trace parameters\n" ); exit(fp == stderr ? 1 : 0); } static int doit(const char *iff_name, unsigned long cmd, void *data) { static int fd = 0; if (fd == 0) { char buf[64]; snprintf(buf, 64, "/dev/%s", iff_name); if ((fd = open(buf, O_RDWR)) < 0) return -1; } return ioctl(fd, cmd, data) < 0 ? -1 : 0; } static int get_int_arg(const char *s, uint32_t *valp) { char *p; *valp = strtoul(s, &p, 0); if (*p) { warnx("bad parameter \"%s\"", s); return -1; } return 0; } static uint32_t read_reg(const char *iff_name, uint32_t addr) { struct ch_reg reg; reg.addr = addr; if (doit(iff_name, CHELSIO_GETREG, ®) < 0) err(1, "register read"); return reg.val; } static void write_reg(const char *iff_name, uint32_t addr, uint32_t val) { struct ch_reg ch_reg; ch_reg.addr = addr; ch_reg.val = val; if (doit(iff_name, CHELSIO_SETREG, &ch_reg) < 0) err(1, "register write"); } static int register_io(int argc, char *argv[], int start_arg, const char *iff_name) { char *p; uint32_t addr, val = 0, w = 0; if (argc != start_arg + 1) return -1; addr = strtoul(argv[start_arg], &p, 0); if (p == argv[start_arg]) return -1; if (*p == '=' && p[1]) { val = strtoul(p + 1, &p, 0); w = 1; } if (*p) { warnx("bad parameter \"%s\"", argv[start_arg]); return -1; } if (w) write_reg(iff_name, addr, val); else { val = read_reg(iff_name, addr); printf("%#x [%u]\n", val, val); } return 0; } static int mdio_io(int argc, char *argv[], int start_arg, const char *iff_name) { struct ch_mii_data p; unsigned int cmd, phy_addr, reg, mmd, val; if (argc == start_arg + 3) cmd = CHELSIO_GET_MIIREG; else if (argc == start_arg + 4) cmd = CHELSIO_SET_MIIREG; else return -1; if (get_int_arg(argv[start_arg], &phy_addr) || get_int_arg(argv[start_arg + 1], &mmd) || get_int_arg(argv[start_arg + 2], ®) || (cmd == CHELSIO_SET_MIIREG && get_int_arg(argv[start_arg + 3], &val))) return -1; p.phy_id = phy_addr | (mmd << 8); p.reg_num = reg; p.val_in = val; if (doit(iff_name, cmd, &p) < 0) err(1, "MDIO %s", cmd == CHELSIO_GET_MIIREG ? "read" : "write"); if (cmd == CHELSIO_GET_MIIREG) printf("%#x [%u]\n", p.val_out, p.val_out); return 0; } static inline uint32_t xtract(uint32_t val, int shift, int len) { return (val >> shift) & ((1 << len) - 1); } static int dump_block_regs(const struct reg_info *reg_array, uint32_t *regs) { uint32_t reg_val = 0; // silence compiler warning for ( ; reg_array->name; ++reg_array) if (!reg_array->len) { reg_val = regs[reg_array->addr / 4]; printf("[%#5x] %-40s %#-10x [%u]\n", reg_array->addr, reg_array->name, reg_val, reg_val); } else { uint32_t v = xtract(reg_val, reg_array->addr, reg_array->len); printf(" %-40s %#-10x [%u]\n", reg_array->name, v, v); } return 1; } static int dump_regs_t2(int argc, char *argv[], int start_arg, uint32_t *regs) { int match = 0; char *block_name = NULL; if (argc == start_arg + 1) block_name = argv[start_arg]; else if (argc != start_arg) return -1; if (!block_name || !strcmp(block_name, "sge")) match += dump_block_regs(sge_regs, regs); if (!block_name || !strcmp(block_name, "mc3")) match += dump_block_regs(mc3_regs, regs); if (!block_name || !strcmp(block_name, "mc4")) match += dump_block_regs(mc4_regs, regs); if (!block_name || !strcmp(block_name, "tpi")) match += dump_block_regs(tpi_regs, regs); if (!block_name || !strcmp(block_name, "tp")) match += dump_block_regs(tp_regs, regs); if (!block_name || !strcmp(block_name, "rat")) match += dump_block_regs(rat_regs, regs); if (!block_name || !strcmp(block_name, "cspi")) match += dump_block_regs(cspi_regs, regs); if (!block_name || !strcmp(block_name, "espi")) match += dump_block_regs(espi_regs, regs); if (!block_name || !strcmp(block_name, "ulp")) match += dump_block_regs(ulp_regs, regs); if (!block_name || !strcmp(block_name, "pl")) match += dump_block_regs(pl_regs, regs); if (!block_name || !strcmp(block_name, "mc5")) match += dump_block_regs(mc5_regs, regs); if (!match) errx(1, "unknown block \"%s\"", block_name); return 0; } #if defined(CONFIG_T3_REGS) static int dump_regs_t3(int argc, char *argv[], int start_arg, uint32_t *regs, int is_pcie) { int match = 0; char *block_name = NULL; if (argc == start_arg + 1) block_name = argv[start_arg]; else if (argc != start_arg) return -1; if (!block_name || !strcmp(block_name, "sge")) match += dump_block_regs(sge3_regs, regs); if (!block_name || !strcmp(block_name, "pci")) match += dump_block_regs(is_pcie ? pcie0_regs : pcix1_regs, regs); if (!block_name || !strcmp(block_name, "t3dbg")) match += dump_block_regs(t3dbg_regs, regs); if (!block_name || !strcmp(block_name, "pmrx")) match += dump_block_regs(mc7_pmrx_regs, regs); if (!block_name || !strcmp(block_name, "pmtx")) match += dump_block_regs(mc7_pmtx_regs, regs); if (!block_name || !strcmp(block_name, "cm")) match += dump_block_regs(mc7_cm_regs, regs); if (!block_name || !strcmp(block_name, "cim")) match += dump_block_regs(cim_regs, regs); if (!block_name || !strcmp(block_name, "tp")) match += dump_block_regs(tp1_regs, regs); if (!block_name || !strcmp(block_name, "ulp_rx")) match += dump_block_regs(ulp2_rx_regs, regs); if (!block_name || !strcmp(block_name, "ulp_tx")) match += dump_block_regs(ulp2_tx_regs, regs); if (!block_name || !strcmp(block_name, "pmrx")) match += dump_block_regs(pm1_rx_regs, regs); if (!block_name || !strcmp(block_name, "pmtx")) match += dump_block_regs(pm1_tx_regs, regs); if (!block_name || !strcmp(block_name, "mps")) match += dump_block_regs(mps0_regs, regs); if (!block_name || !strcmp(block_name, "cplsw")) match += dump_block_regs(cpl_switch_regs, regs); if (!block_name || !strcmp(block_name, "smb")) match += dump_block_regs(smb0_regs, regs); if (!block_name || !strcmp(block_name, "i2c")) match += dump_block_regs(i2cm0_regs, regs); if (!block_name || !strcmp(block_name, "mi1")) match += dump_block_regs(mi1_regs, regs); if (!block_name || !strcmp(block_name, "sf")) match += dump_block_regs(sf1_regs, regs); if (!block_name || !strcmp(block_name, "pl")) match += dump_block_regs(pl3_regs, regs); if (!block_name || !strcmp(block_name, "mc5")) match += dump_block_regs(mc5a_regs, regs); if (!block_name || !strcmp(block_name, "xgmac0")) match += dump_block_regs(xgmac0_0_regs, regs); if (!block_name || !strcmp(block_name, "xgmac1")) match += dump_block_regs(xgmac0_1_regs, regs); if (!match) errx(1, "unknown block \"%s\"", block_name); return 0; } static int dump_regs_t3b(int argc, char *argv[], int start_arg, uint32_t *regs, int is_pcie) { int match = 0; char *block_name = NULL; if (argc == start_arg + 1) block_name = argv[start_arg]; else if (argc != start_arg) return -1; if (!block_name || !strcmp(block_name, "sge")) match += dump_block_regs(t3b_sge3_regs, regs); if (!block_name || !strcmp(block_name, "pci")) match += dump_block_regs(is_pcie ? t3b_pcie0_regs : t3b_pcix1_regs, regs); if (!block_name || !strcmp(block_name, "t3dbg")) match += dump_block_regs(t3b_t3dbg_regs, regs); if (!block_name || !strcmp(block_name, "pmrx")) match += dump_block_regs(t3b_mc7_pmrx_regs, regs); if (!block_name || !strcmp(block_name, "pmtx")) match += dump_block_regs(t3b_mc7_pmtx_regs, regs); if (!block_name || !strcmp(block_name, "cm")) match += dump_block_regs(t3b_mc7_cm_regs, regs); if (!block_name || !strcmp(block_name, "cim")) match += dump_block_regs(t3b_cim_regs, regs); if (!block_name || !strcmp(block_name, "tp")) match += dump_block_regs(t3b_tp1_regs, regs); if (!block_name || !strcmp(block_name, "ulp_rx")) match += dump_block_regs(t3b_ulp2_rx_regs, regs); if (!block_name || !strcmp(block_name, "ulp_tx")) match += dump_block_regs(t3b_ulp2_tx_regs, regs); if (!block_name || !strcmp(block_name, "pmrx")) match += dump_block_regs(t3b_pm1_rx_regs, regs); if (!block_name || !strcmp(block_name, "pmtx")) match += dump_block_regs(t3b_pm1_tx_regs, regs); if (!block_name || !strcmp(block_name, "mps")) match += dump_block_regs(t3b_mps0_regs, regs); if (!block_name || !strcmp(block_name, "cplsw")) match += dump_block_regs(t3b_cpl_switch_regs, regs); if (!block_name || !strcmp(block_name, "smb")) match += dump_block_regs(t3b_smb0_regs, regs); if (!block_name || !strcmp(block_name, "i2c")) match += dump_block_regs(t3b_i2cm0_regs, regs); if (!block_name || !strcmp(block_name, "mi1")) match += dump_block_regs(t3b_mi1_regs, regs); if (!block_name || !strcmp(block_name, "sf")) match += dump_block_regs(t3b_sf1_regs, regs); if (!block_name || !strcmp(block_name, "pl")) match += dump_block_regs(t3b_pl3_regs, regs); if (!block_name || !strcmp(block_name, "mc5")) match += dump_block_regs(t3b_mc5a_regs, regs); if (!block_name || !strcmp(block_name, "xgmac0")) match += dump_block_regs(t3b_xgmac0_0_regs, regs); if (!block_name || !strcmp(block_name, "xgmac1")) match += dump_block_regs(t3b_xgmac0_1_regs, regs); if (!match) errx(1, "unknown block \"%s\"", block_name); return 0; } static int dump_regs_t3c(int argc, char *argv[], int start_arg, uint32_t *regs, int is_pcie) { int match = 0; char *block_name = NULL; if (argc == start_arg + 1) block_name = argv[start_arg]; else if (argc != start_arg) return -1; if (!block_name || !strcmp(block_name, "sge")) match += dump_block_regs(t3c_sge3_regs, regs); if (!block_name || !strcmp(block_name, "pci")) match += dump_block_regs(is_pcie ? t3c_pcie0_regs : t3c_pcix1_regs, regs); if (!block_name || !strcmp(block_name, "t3dbg")) match += dump_block_regs(t3c_t3dbg_regs, regs); if (!block_name || !strcmp(block_name, "pmrx")) match += dump_block_regs(t3c_mc7_pmrx_regs, regs); if (!block_name || !strcmp(block_name, "pmtx")) match += dump_block_regs(t3c_mc7_pmtx_regs, regs); if (!block_name || !strcmp(block_name, "cm")) match += dump_block_regs(t3c_mc7_cm_regs, regs); if (!block_name || !strcmp(block_name, "cim")) match += dump_block_regs(t3c_cim_regs, regs); if (!block_name || !strcmp(block_name, "tp")) match += dump_block_regs(t3c_tp1_regs, regs); if (!block_name || !strcmp(block_name, "ulp_rx")) match += dump_block_regs(t3c_ulp2_rx_regs, regs); if (!block_name || !strcmp(block_name, "ulp_tx")) match += dump_block_regs(t3c_ulp2_tx_regs, regs); if (!block_name || !strcmp(block_name, "pmrx")) match += dump_block_regs(t3c_pm1_rx_regs, regs); if (!block_name || !strcmp(block_name, "pmtx")) match += dump_block_regs(t3c_pm1_tx_regs, regs); if (!block_name || !strcmp(block_name, "mps")) match += dump_block_regs(t3c_mps0_regs, regs); if (!block_name || !strcmp(block_name, "cplsw")) match += dump_block_regs(t3c_cpl_switch_regs, regs); if (!block_name || !strcmp(block_name, "smb")) match += dump_block_regs(t3c_smb0_regs, regs); if (!block_name || !strcmp(block_name, "i2c")) match += dump_block_regs(t3c_i2cm0_regs, regs); if (!block_name || !strcmp(block_name, "mi1")) match += dump_block_regs(t3c_mi1_regs, regs); if (!block_name || !strcmp(block_name, "sf")) match += dump_block_regs(t3c_sf1_regs, regs); if (!block_name || !strcmp(block_name, "pl")) match += dump_block_regs(t3c_pl3_regs, regs); if (!block_name || !strcmp(block_name, "mc5")) match += dump_block_regs(t3c_mc5a_regs, regs); if (!block_name || !strcmp(block_name, "xgmac0")) match += dump_block_regs(t3c_xgmac0_0_regs, regs); if (!block_name || !strcmp(block_name, "xgmac1")) match += dump_block_regs(t3c_xgmac0_1_regs, regs); if (!match) errx(1, "unknown block \"%s\"", block_name); return 0; } #endif static int dump_regs(int argc, char *argv[], int start_arg, const char *iff_name) { int vers, revision, is_pcie; struct ch_ifconf_regs regs; regs.len = REGDUMP_SIZE; /* XXX: This is never freed. Looks like we don't care. */ if ((regs.data = malloc(regs.len)) == NULL) err(1, "can't malloc"); if (doit(iff_name, CHELSIO_IFCONF_GETREGS, ®s)) err(1, "can't read registers"); vers = regs.version & 0x3ff; revision = (regs.version >> 10) & 0x3f; is_pcie = (regs.version & 0x80000000) != 0; if (vers <= 2) return dump_regs_t2(argc, argv, start_arg, (uint32_t *)regs.data); #if defined(CONFIG_T3_REGS) if (vers == 3) { if (revision == 0) return dump_regs_t3(argc, argv, start_arg, (uint32_t *)regs.data, is_pcie); if (revision == 2 || revision == 3) return dump_regs_t3b(argc, argv, start_arg, (uint32_t *)regs.data, is_pcie); if (revision == 4) return dump_regs_t3c(argc, argv, start_arg, (uint32_t *)regs.data, is_pcie); } #endif errx(1, "unknown card type %d.%d", vers, revision); return 0; } static int t3_meminfo(const uint32_t *regs) { enum { SG_EGR_CNTX_BADDR = 0x58, SG_CQ_CONTEXT_BADDR = 0x6c, CIM_SDRAM_BASE_ADDR = 0x28c, CIM_SDRAM_ADDR_SIZE = 0x290, TP_CMM_MM_BASE = 0x314, TP_CMM_TIMER_BASE = 0x318, TP_CMM_MM_RX_FLST_BASE = 0x460, TP_CMM_MM_TX_FLST_BASE = 0x464, TP_CMM_MM_PS_FLST_BASE = 0x468, ULPRX_ISCSI_LLIMIT = 0x50c, ULPRX_ISCSI_ULIMIT = 0x510, ULPRX_TDDP_LLIMIT = 0x51c, ULPRX_TDDP_ULIMIT = 0x520, ULPRX_STAG_LLIMIT = 0x52c, ULPRX_STAG_ULIMIT = 0x530, ULPRX_RQ_LLIMIT = 0x534, ULPRX_RQ_ULIMIT = 0x538, ULPRX_PBL_LLIMIT = 0x53c, ULPRX_PBL_ULIMIT = 0x540, }; unsigned int egr_cntxt = regs[SG_EGR_CNTX_BADDR / 4], cq_cntxt = regs[SG_CQ_CONTEXT_BADDR / 4], timers = regs[TP_CMM_TIMER_BASE / 4] & 0xfffffff, pstructs = regs[TP_CMM_MM_BASE / 4], pstruct_fl = regs[TP_CMM_MM_PS_FLST_BASE / 4], rx_fl = regs[TP_CMM_MM_RX_FLST_BASE / 4], tx_fl = regs[TP_CMM_MM_TX_FLST_BASE / 4], cim_base = regs[CIM_SDRAM_BASE_ADDR / 4], cim_size = regs[CIM_SDRAM_ADDR_SIZE / 4]; unsigned int iscsi_ll = regs[ULPRX_ISCSI_LLIMIT / 4], iscsi_ul = regs[ULPRX_ISCSI_ULIMIT / 4], tddp_ll = regs[ULPRX_TDDP_LLIMIT / 4], tddp_ul = regs[ULPRX_TDDP_ULIMIT / 4], stag_ll = regs[ULPRX_STAG_LLIMIT / 4], stag_ul = regs[ULPRX_STAG_ULIMIT / 4], rq_ll = regs[ULPRX_RQ_LLIMIT / 4], rq_ul = regs[ULPRX_RQ_ULIMIT / 4], pbl_ll = regs[ULPRX_PBL_LLIMIT / 4], pbl_ul = regs[ULPRX_PBL_ULIMIT / 4]; printf("CM memory map:\n"); printf(" TCB region: 0x%08x - 0x%08x [%u]\n", 0, egr_cntxt - 1, egr_cntxt); printf(" Egress contexts: 0x%08x - 0x%08x [%u]\n", egr_cntxt, cq_cntxt - 1, cq_cntxt - egr_cntxt); printf(" CQ contexts: 0x%08x - 0x%08x [%u]\n", cq_cntxt, timers - 1, timers - cq_cntxt); printf(" Timers: 0x%08x - 0x%08x [%u]\n", timers, pstructs - 1, pstructs - timers); printf(" Pstructs: 0x%08x - 0x%08x [%u]\n", pstructs, pstruct_fl - 1, pstruct_fl - pstructs); printf(" Pstruct FL: 0x%08x - 0x%08x [%u]\n", pstruct_fl, rx_fl - 1, rx_fl - pstruct_fl); printf(" Rx FL: 0x%08x - 0x%08x [%u]\n", rx_fl, tx_fl - 1, tx_fl - rx_fl); printf(" Tx FL: 0x%08x - 0x%08x [%u]\n", tx_fl, cim_base - 1, cim_base - tx_fl); printf(" uP RAM: 0x%08x - 0x%08x [%u]\n", cim_base, cim_base + cim_size - 1, cim_size); printf("\nPMRX memory map:\n"); printf(" iSCSI region: 0x%08x - 0x%08x [%u]\n", iscsi_ll, iscsi_ul, iscsi_ul - iscsi_ll + 1); printf(" TCP DDP region: 0x%08x - 0x%08x [%u]\n", tddp_ll, tddp_ul, tddp_ul - tddp_ll + 1); printf(" TPT region: 0x%08x - 0x%08x [%u]\n", stag_ll, stag_ul, stag_ul - stag_ll + 1); printf(" RQ region: 0x%08x - 0x%08x [%u]\n", rq_ll, rq_ul, rq_ul - rq_ll + 1); printf(" PBL region: 0x%08x - 0x%08x [%u]\n", pbl_ll, pbl_ul, pbl_ul - pbl_ll + 1); return 0; } static int meminfo(int argc, char *argv[], int start_arg, const char *iff_name) { int vers; struct ch_ifconf_regs regs; (void) argc; (void) argv; (void) start_arg; regs.len = REGDUMP_SIZE; if ((regs.data = malloc(regs.len)) == NULL) err(1, "can't malloc"); if (doit(iff_name, CHELSIO_IFCONF_GETREGS, ®s)) err(1, "can't read registers"); vers = regs.version & 0x3ff; if (vers == 3) return t3_meminfo((uint32_t *)regs.data); errx(1, "unknown card type %d", vers); return 0; } static int mtu_tab_op(int argc, char *argv[], int start_arg, const char *iff_name) { struct ch_mtus m; unsigned int i; if (argc == start_arg) { if (doit(iff_name, CHELSIO_GETMTUTAB, &m) < 0) err(1, "get MTU table"); for (i = 0; i < m.nmtus; ++i) printf("%u ", m.mtus[i]); printf("\n"); } else if (argc <= start_arg + NMTUS) { m.nmtus = argc - start_arg; for (i = 0; i < m.nmtus; ++i) { char *p; unsigned long mt = strtoul(argv[start_arg + i], &p, 0); if (*p || mt > 9600) { warnx("bad parameter \"%s\"", argv[start_arg + i]); return -1; } if (i && mt < m.mtus[i - 1]) errx(1, "MTUs must be in ascending order"); m.mtus[i] = mt; } if (doit(iff_name, CHELSIO_SETMTUTAB, &m) < 0) err(1, "set MTU table"); } else return -1; return 0; } #ifdef CHELSIO_INTERNAL static void show_egress_cntxt(uint32_t data[]) { printf("credits: %u\n", data[0] & 0x7fff); printf("GTS: %u\n", (data[0] >> 15) & 1); printf("index: %u\n", data[0] >> 16); printf("queue size: %u\n", data[1] & 0xffff); printf("base address: 0x%" PRIx64 "\n", ((data[1] >> 16) | ((uint64_t)data[2] << 16) | (((uint64_t)data[3] & 0xf) << 48)) << 12); printf("rsp queue #: %u\n", (data[3] >> 4) & 7); printf("cmd queue #: %u\n", (data[3] >> 7) & 1); printf("TUN: %u\n", (data[3] >> 8) & 1); printf("TOE: %u\n", (data[3] >> 9) & 1); printf("generation: %u\n", (data[3] >> 10) & 1); printf("uP token: %u\n", (data[3] >> 11) & 0xfffff); printf("valid: %u\n", (data[3] >> 31) & 1); } static void show_fl_cntxt(uint32_t data[]) { printf("base address: 0x%" PRIx64 "\n", ((uint64_t)data[0] | ((uint64_t)data[1] & 0xfffff) << 32) << 12); printf("index: %u\n", (data[1] >> 20) | ((data[2] & 0xf) << 12)); printf("queue size: %u\n", (data[2] >> 4) & 0xffff); printf("generation: %u\n", (data[2] >> 20) & 1); printf("entry size: %u\n", (data[2] >> 21) | (data[3] & 0x1fffff) << 11); printf("congest thr: %u\n", (data[3] >> 21) & 0x3ff); printf("GTS: %u\n", (data[3] >> 31) & 1); } static void show_response_cntxt(uint32_t data[]) { printf("index: %u\n", data[0] & 0xffff); printf("size: %u\n", data[0] >> 16); printf("base address: 0x%" PRIx64 "\n", ((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12); printf("MSI-X/RspQ: %u\n", (data[2] >> 20) & 0x3f); printf("intr enable: %u\n", (data[2] >> 26) & 1); printf("intr armed: %u\n", (data[2] >> 27) & 1); printf("generation: %u\n", (data[2] >> 28) & 1); printf("CQ mode: %u\n", (data[2] >> 31) & 1); printf("FL threshold: %u\n", data[3]); } static void show_cq_cntxt(uint32_t data[]) { printf("index: %u\n", data[0] & 0xffff); printf("size: %u\n", data[0] >> 16); printf("base address: 0x%" PRIx64 "\n", ((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12); printf("rsp queue #: %u\n", (data[2] >> 20) & 0x3f); printf("AN: %u\n", (data[2] >> 26) & 1); printf("armed: %u\n", (data[2] >> 27) & 1); printf("ANS: %u\n", (data[2] >> 28) & 1); printf("generation: %u\n", (data[2] >> 29) & 1); printf("overflow mode: %u\n", (data[2] >> 31) & 1); printf("credits: %u\n", data[3] & 0xffff); printf("credit threshold: %u\n", data[3] >> 16); } static int get_sge_context(int argc, char *argv[], int start_arg, const char *iff_name) { struct ch_cntxt ctx; if (argc != start_arg + 2) return -1; if (!strcmp(argv[start_arg], "egress")) ctx.cntxt_type = CNTXT_TYPE_EGRESS; else if (!strcmp(argv[start_arg], "fl")) ctx.cntxt_type = CNTXT_TYPE_FL; else if (!strcmp(argv[start_arg], "response")) ctx.cntxt_type = CNTXT_TYPE_RSP; else if (!strcmp(argv[start_arg], "cq")) ctx.cntxt_type = CNTXT_TYPE_CQ; else { warnx("unknown context type \"%s\"; known types are egress, " "fl, cq, and response", argv[start_arg]); return -1; } if (get_int_arg(argv[start_arg + 1], &ctx.cntxt_id)) return -1; if (doit(iff_name, CHELSIO_GET_SGE_CONTEXT, &ctx) < 0) err(1, "get SGE context"); if (!strcmp(argv[start_arg], "egress")) show_egress_cntxt(ctx.data); else if (!strcmp(argv[start_arg], "fl")) show_fl_cntxt(ctx.data); else if (!strcmp(argv[start_arg], "response")) show_response_cntxt(ctx.data); else if (!strcmp(argv[start_arg], "cq")) show_cq_cntxt(ctx.data); return 0; } #define ntohll(x) be64toh((x)) static int get_sge_desc(int argc, char *argv[], int start_arg, const char *iff_name) { uint64_t *p, wr_hdr; unsigned int n = 1, qset, qnum; struct ch_desc desc; if (argc != start_arg + 3 && argc != start_arg + 4) return -1; if (get_int_arg(argv[start_arg], &qset) || get_int_arg(argv[start_arg + 1], &qnum) || get_int_arg(argv[start_arg + 2], &desc.idx)) return -1; if (argc == start_arg + 4 && get_int_arg(argv[start_arg + 3], &n)) return -1; if (qnum > 5) errx(1, "invalid queue number %d, range is 0..5", qnum); desc.queue_num = qset * 6 + qnum; for (; n--; desc.idx++) { if (doit(iff_name, CHELSIO_GET_SGE_DESC, &desc) < 0) err(1, "get SGE descriptor"); p = (uint64_t *)desc.data; wr_hdr = ntohll(*p); printf("Descriptor %u: cmd %u, TID %u, %s%s%s%s%u flits\n", desc.idx, (unsigned int)(wr_hdr >> 56), ((unsigned int)wr_hdr >> 8) & 0xfffff, ((wr_hdr >> 55) & 1) ? "SOP, " : "", ((wr_hdr >> 54) & 1) ? "EOP, " : "", ((wr_hdr >> 53) & 1) ? "COMPL, " : "", ((wr_hdr >> 52) & 1) ? "SGL, " : "", (unsigned int)wr_hdr & 0xff); for (; desc.size; p++, desc.size -= sizeof(uint64_t)) printf("%016" PRIx64 "%c", ntohll(*p), desc.size % 32 == 8 ? '\n' : ' '); } return 0; } #endif static int get_tcb2(int argc, char *argv[], int start_arg, const char *iff_name) { uint64_t *d; unsigned int i; unsigned int tcb_idx; struct ch_mem_range mr; if (argc != start_arg + 1) return -1; if (get_int_arg(argv[start_arg], &tcb_idx)) return -1; mr.buf = calloc(1, TCB_SIZE); if (!mr.buf) err(1, "get TCB"); mr.mem_id = MEM_CM; mr.addr = tcb_idx * TCB_SIZE; mr.len = TCB_SIZE; if (doit(iff_name, CHELSIO_GET_MEM, &mr) < 0) err(1, "get TCB"); for (d = (uint64_t *)mr.buf, i = 0; i < TCB_SIZE / 32; i++) { printf("%2u:", i); printf(" %08x %08x %08x %08x", (uint32_t)d[1], (uint32_t)(d[1] >> 32), (uint32_t)d[0], (uint32_t)(d[0] >> 32)); d += 2; printf(" %08x %08x %08x %08x\n", (uint32_t)d[1], (uint32_t)(d[1] >> 32), (uint32_t)d[0], (uint32_t)(d[0] >> 32)); d += 2; } free(mr.buf); return 0; } static int get_pm_page_spec(const char *s, unsigned int *page_size, unsigned int *num_pages) { char *p; unsigned long val; val = strtoul(s, &p, 0); if (p == s) return -1; if (*p == 'x' && p[1]) { *num_pages = val; *page_size = strtoul(p + 1, &p, 0); } else { *num_pages = -1; *page_size = val; } *page_size <<= 10; // KB -> bytes return *p; } static int conf_pm(int argc, char *argv[], int start_arg, const char *iff_name) { struct ch_pm pm; if (argc == start_arg) { if (doit(iff_name, CHELSIO_GET_PM, &pm) < 0) err(1, "read pm config"); printf("%ux%uKB TX pages, %ux%uKB RX pages, %uKB total memory\n", pm.tx_num_pg, pm.tx_pg_sz >> 10, pm.rx_num_pg, pm.rx_pg_sz >> 10, pm.pm_total >> 10); return 0; } if (argc != start_arg + 2) return -1; if (get_pm_page_spec(argv[start_arg], &pm.tx_pg_sz, &pm.tx_num_pg)) { warnx("bad parameter \"%s\"", argv[start_arg]); return -1; } if (get_pm_page_spec(argv[start_arg + 1], &pm.rx_pg_sz, &pm.rx_num_pg)) { warnx("bad parameter \"%s\"", argv[start_arg + 1]); return -1; } if (doit(iff_name, CHELSIO_SET_PM, &pm) < 0) err(1, "pm config"); return 0; } #ifdef CHELSIO_INTERNAL static int dump_tcam(int argc, char *argv[], int start_arg, const char *iff_name) { unsigned int nwords; struct ch_tcam_word op; if (argc != start_arg + 2) return -1; if (get_int_arg(argv[start_arg], &op.addr) || get_int_arg(argv[start_arg + 1], &nwords)) return -1; while (nwords--) { if (doit(iff_name, CHELSIO_READ_TCAM_WORD, &op) < 0) err(1, "tcam dump"); printf("0x%08x: 0x%02x 0x%08x 0x%08x\n", op.addr, op.buf[0] & 0xff, op.buf[1], op.buf[2]); op.addr++; } return 0; } static void hexdump_8b(unsigned int start, uint64_t *data, unsigned int len) { int i; while (len) { printf("0x%08x:", start); for (i = 0; i < 4 && len; ++i, --len) printf(" %016llx", (unsigned long long)*data++); printf("\n"); start += 32; } } static int dump_mc7(int argc, char *argv[], int start_arg, const char *iff_name) { struct ch_mem_range mem; unsigned int mem_id, addr, len; if (argc != start_arg + 3) return -1; if (!strcmp(argv[start_arg], "cm")) mem_id = MEM_CM; else if (!strcmp(argv[start_arg], "rx")) mem_id = MEM_PMRX; else if (!strcmp(argv[start_arg], "tx")) mem_id = MEM_PMTX; else errx(1, "unknown memory \"%s\"; must be one of \"cm\", \"tx\"," " or \"rx\"", argv[start_arg]); if (get_int_arg(argv[start_arg + 1], &addr) || get_int_arg(argv[start_arg + 2], &len)) return -1; mem.buf = malloc(len); if (!mem.buf) err(1, "memory dump"); mem.mem_id = mem_id; mem.addr = addr; mem.len = len; if (doit(iff_name, CHELSIO_GET_MEM, &mem) < 0) err(1, "memory dump"); hexdump_8b(mem.addr, (uint64_t *)mem.buf, mem.len >> 3); free(mem.buf); return 0; } #endif /* Max FW size is 64K including version, +4 bytes for the checksum. */ #define MAX_FW_IMAGE_SIZE (64 * 1024) static int load_fw(int argc, char *argv[], int start_arg, const char *iff_name) { int fd, len; struct ch_mem_range op; const char *fname = argv[start_arg]; if (argc != start_arg + 1) return -1; fd = open(fname, O_RDONLY); if (fd < 0) err(1, "load firmware"); bzero(&op, sizeof(op)); op.buf = malloc(MAX_FW_IMAGE_SIZE + 1); if (!op.buf) err(1, "load firmware"); len = read(fd, op.buf, MAX_FW_IMAGE_SIZE + 1); if (len < 0) err(1, "load firmware"); if (len > MAX_FW_IMAGE_SIZE) errx(1, "FW image too large"); op.len = len; if (doit(iff_name, CHELSIO_LOAD_FW, &op) < 0) err(1, "load firmware"); close(fd); return 0; } /* Max BOOT size is 255*512 bytes including the BIOS boot ROM basic header */ #define MAX_BOOT_IMAGE_SIZE (0xff * 512) static int load_boot(int argc, char *argv[], int start_arg, const char *iff_name) { int fd, len; struct ch_mem_range op; const char *fname = argv[start_arg]; if (argc != start_arg + 1) return -1; fd = open(fname, O_RDONLY); if (fd < 0) err(1, "load boot image"); op.buf = malloc(MAX_BOOT_IMAGE_SIZE + 1); if (!op.buf) err(1, "load boot image"); len = read(fd, op.buf, MAX_BOOT_IMAGE_SIZE + 1); if (len < 0) err(1, "load boot image"); if (len > MAX_BOOT_IMAGE_SIZE) errx(1, "boot image too large"); op.len = len; if (doit(iff_name, CHELSIO_LOAD_BOOT, &op) < 0) err(1, "load boot image"); close(fd); return 0; } static int dump_proto_sram(const char *iff_name) { int i, j; uint8_t buf[PROTO_SRAM_SIZE]; struct ch_eeprom ee; uint8_t *p = buf; bzero(buf, sizeof(buf)); ee.offset = PROTO_SRAM_EEPROM_ADDR; ee.data = p; ee.len = sizeof(buf); if (doit(iff_name, CHELSIO_GET_EEPROM, &ee)) err(1, "show protocol sram"); for (i = 0; i < PROTO_SRAM_LINES; i++) { for (j = PROTO_SRAM_LINE_NIBBLES - 1; j >= 0; j--) { int nibble_idx = i * PROTO_SRAM_LINE_NIBBLES + j; uint8_t nibble = p[nibble_idx / 2]; if (nibble_idx & 1) nibble >>= 4; else nibble &= 0xf; printf("%x", nibble); } putchar('\n'); } return 0; } static int proto_sram_op(int argc, char *argv[], int start_arg, const char *iff_name) { (void) argv; (void) start_arg; if (argc == start_arg) return dump_proto_sram(iff_name); return -1; } static int dump_qset_params(const char *iff_name) { struct ch_qset_params qp; qp.qset_idx = 0; while (doit(iff_name, CHELSIO_GET_QSET_PARAMS, &qp) == 0) { if (!qp.qset_idx) printf("Qset TxQ0 TxQ1 TxQ2 RspQ RxQ0 RxQ1" " Cong Lat IRQ\n"); printf("%4u %6u %6u %6u %6u %6u %6u %5u %4u %5d\n", qp.qnum, qp.txq_size[0], qp.txq_size[1], qp.txq_size[2], qp.rspq_size, qp.fl_size[0], qp.fl_size[1], qp.cong_thres, qp.intr_lat, qp.vector); qp.qset_idx++; } if (!qp.qset_idx || (errno && errno != EINVAL)) err(1, "get qset parameters"); return 0; } static int qset_config(int argc, char *argv[], int start_arg, const char *iff_name) { (void) argv; if (argc == start_arg) return dump_qset_params(iff_name); return -1; } static int qset_num_config(int argc, char *argv[], int start_arg, const char *iff_name) { struct ch_reg reg; (void) argv; if (argc == start_arg) { if (doit(iff_name, CHELSIO_GET_QSET_NUM, ®) < 0) err(1, "get qsets"); printf("%u\n", reg.val); return 0; } return -1; } /* * Parse a string containing an IP address with an optional network prefix. */ static int parse_ipaddr(const char *s, uint32_t *addr, uint32_t *mask) { char *p, *slash; struct in_addr ia; *mask = 0xffffffffU; slash = strchr(s, '/'); if (slash) *slash = 0; if (!inet_aton(s, &ia)) { if (slash) *slash = '/'; *addr = 0; return -1; } *addr = ntohl(ia.s_addr); if (slash) { unsigned int prefix = strtoul(slash + 1, &p, 10); *slash = '/'; if (p == slash + 1 || *p || prefix > 32) return -1; *mask <<= (32 - prefix); } return 0; } /* * Parse a string containing a value and an optional colon separated mask. */ static int parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask, uint32_t default_mask) { char *p; *mask = default_mask; *val = strtoul(s, &p, 0); if (p == s || *val > default_mask) return -1; if (*p == ':' && p[1]) *mask = strtoul(p + 1, &p, 0); return *p || *mask > default_mask ? -1 : 0; } static int parse_trace_param(const char *s, uint32_t *val, uint32_t *mask) { return strchr(s, '.') ? parse_ipaddr(s, val, mask) : parse_val_mask_param(s, val, mask, 0xffffffffU); } static int trace_config(int argc, char *argv[], int start_arg, const char *iff_name) { uint32_t val, mask; struct ch_trace trace; if (argc == start_arg) return -1; memset(&trace, 0, sizeof(trace)); if (!strcmp(argv[start_arg], "tx")) trace.config_tx = 1; else if (!strcmp(argv[start_arg], "rx")) trace.config_rx = 1; else if (!strcmp(argv[start_arg], "all")) trace.config_tx = trace.config_rx = 1; else errx(1, "bad trace filter \"%s\"; must be one of \"rx\", " "\"tx\" or \"all\"", argv[start_arg]); if (argc == ++start_arg) return -1; if (!strcmp(argv[start_arg], "on")) { trace.trace_tx = trace.config_tx; trace.trace_rx = trace.config_rx; } else if (strcmp(argv[start_arg], "off")) errx(1, "bad argument \"%s\"; must be \"on\" or \"off\"", argv[start_arg]); start_arg++; if (start_arg < argc && !strcmp(argv[start_arg], "not")) { trace.invert_match = 1; start_arg++; } while (start_arg + 2 <= argc) { int ret = parse_trace_param(argv[start_arg + 1], &val, &mask); if (!strcmp(argv[start_arg], "interface")) { trace.intf = val; trace.intf_mask = mask; } else if (!strcmp(argv[start_arg], "sip")) { trace.sip = val; trace.sip_mask = mask; } else if (!strcmp(argv[start_arg], "dip")) { trace.dip = val; trace.dip_mask = mask; } else if (!strcmp(argv[start_arg], "sport")) { trace.sport = val; trace.sport_mask = mask; } else if (!strcmp(argv[start_arg], "dport")) { trace.dport = val; trace.dport_mask = mask; } else if (!strcmp(argv[start_arg], "vlan")) { trace.vlan = val; trace.vlan_mask = mask; } else if (!strcmp(argv[start_arg], "proto")) { trace.proto = val; trace.proto_mask = mask; } else errx(1, "unknown trace parameter \"%s\"\n" "known parameters are \"interface\", \"sip\", " "\"dip\", \"sport\", \"dport\", \"vlan\", " "\"proto\"", argv[start_arg]); if (ret < 0) errx(1, "bad parameter \"%s\"", argv[start_arg + 1]); start_arg += 2; } if (start_arg != argc) errx(1, "unknown parameter \"%s\"", argv[start_arg]); if (doit(iff_name, CHELSIO_SET_TRACE_FILTER, &trace) < 0) err(1, "trace"); return 0; } static void show_filters(const char *iff_name) { static const char *pkt_type[] = { "*", "tcp", "udp", "frag" }; struct ch_filter op; union { uint32_t nip; uint8_t octet[4]; } nsip, ndip; char sip[20], dip[20]; int header = 0; bzero(&op, sizeof(op)); op.filter_id = 0xffffffff; do { if (doit(iff_name, CHELSIO_GET_FILTER, &op) < 0) err(1, "list filters"); if (op.filter_id == 0xffffffff) break; if (!header) { printf("index SIP DIP sport " "dport VLAN PRI P/MAC type Q\n"); header = 1; } nsip.nip = htonl(op.val.sip); ndip.nip = htonl(op.val.dip); sprintf(sip, "%u.%u.%u.%u/%-2u", nsip.octet[0], nsip.octet[1], nsip.octet[2], nsip.octet[3], op.mask.sip ? 33 - ffs(op.mask.sip) : 0); sprintf(dip, "%u.%u.%u.%u", ndip.octet[0], ndip.octet[1], ndip.octet[2], ndip.octet[3]); printf("%5zu %18s %15s ", (size_t)op.filter_id, sip, dip); printf(op.val.sport ? "%5u " : " * ", op.val.sport); printf(op.val.dport ? "%5u " : " * ", op.val.dport); printf(op.val.vlan != 0xfff ? "%4u " : " * ", op.val.vlan); printf(op.val.vlan_prio == 7 ? " * " : "%1u/%1u ", op.val.vlan_prio, op.val.vlan_prio | 1); if (op.mac_addr_idx == 0xffff) printf("*/* "); else if (op.mac_hit) printf("%1u/%3u ", (op.mac_addr_idx >> 3) & 0x1, (op.mac_addr_idx) & 0x7); else printf("%1u/ * ", (op.mac_addr_idx >> 3) & 0x1); printf("%4s ", pkt_type[op.proto]); if (!op.pass) printf("-\n"); else if (op.rss) printf("*\n"); else printf("%1u\n", op.qset); } while (1); } static int filter_config(int argc, char *argv[], int start_arg, const char *iff_name) { int ret = 0; uint32_t val, mask; struct ch_filter op; if (argc < start_arg + 1) return -1; memset(&op, 0, sizeof(op)); op.mac_addr_idx = 0xffff; op.rss = 1; if (argc == start_arg + 1 && !strcmp(argv[start_arg], "list")) { show_filters(iff_name); return 0; } if (get_int_arg(argv[start_arg++], &op.filter_id)) return -1; if (argc == start_arg + 1 && (!strcmp(argv[start_arg], "delete") || !strcmp(argv[start_arg], "clear"))) { if (doit(iff_name, CHELSIO_DEL_FILTER, &op) < 0) { if (errno == EBUSY) err(1, "no filter support when offload in use"); err(1, "delete filter"); } return 0; } while (start_arg + 2 <= argc) { if (!strcmp(argv[start_arg], "sip")) { ret = parse_ipaddr(argv[start_arg + 1], &op.val.sip, &op.mask.sip); } else if (!strcmp(argv[start_arg], "dip")) { ret = parse_ipaddr(argv[start_arg + 1], &op.val.dip, &op.mask.dip); } else if (!strcmp(argv[start_arg], "sport")) { ret = parse_val_mask_param(argv[start_arg + 1], &val, &mask, 0xffff); op.val.sport = val; op.mask.sport = mask; } else if (!strcmp(argv[start_arg], "dport")) { ret = parse_val_mask_param(argv[start_arg + 1], &val, &mask, 0xffff); op.val.dport = val; op.mask.dport = mask; } else if (!strcmp(argv[start_arg], "vlan")) { ret = parse_val_mask_param(argv[start_arg + 1], &val, &mask, 0xfff); op.val.vlan = val; op.mask.vlan = mask; } else if (!strcmp(argv[start_arg], "prio")) { ret = parse_val_mask_param(argv[start_arg + 1], &val, &mask, 7); op.val.vlan_prio = val; op.mask.vlan_prio = mask; } else if (!strcmp(argv[start_arg], "mac")) { if (!strcmp(argv[start_arg + 1], "none")) val = -1; else ret = get_int_arg(argv[start_arg + 1], &val); op.mac_hit = val != (uint32_t)-1; op.mac_addr_idx = op.mac_hit ? val : 0; } else if (!strcmp(argv[start_arg], "type")) { if (!strcmp(argv[start_arg + 1], "tcp")) op.proto = 1; else if (!strcmp(argv[start_arg + 1], "udp")) op.proto = 2; else if (!strcmp(argv[start_arg + 1], "frag")) op.proto = 3; else errx(1, "unknown type \"%s\"; must be one of " "\"tcp\", \"udp\", or \"frag\"", argv[start_arg + 1]); } else if (!strcmp(argv[start_arg], "queue")) { ret = get_int_arg(argv[start_arg + 1], &val); op.qset = val; op.rss = 0; } else if (!strcmp(argv[start_arg], "action")) { if (!strcmp(argv[start_arg + 1], "pass")) op.pass = 1; else if (strcmp(argv[start_arg + 1], "drop")) errx(1, "unknown action \"%s\"; must be one of " "\"pass\" or \"drop\"", argv[start_arg + 1]); } else errx(1, "unknown filter parameter \"%s\"\n" "known parameters are \"mac\", \"sip\", " "\"dip\", \"sport\", \"dport\", \"vlan\", " "\"prio\", \"type\", \"queue\", and \"action\"", argv[start_arg]); if (ret < 0) errx(1, "bad value \"%s\" for parameter \"%s\"", argv[start_arg + 1], argv[start_arg]); start_arg += 2; } if (start_arg != argc) errx(1, "no value for \"%s\"", argv[start_arg]); if (doit(iff_name, CHELSIO_SET_FILTER, &op) < 0) { if (errno == EBUSY) err(1, "no filter support when offload in use"); err(1, "set filter"); } return 0; } static int get_sched_param(int argc, char *argv[], int pos, unsigned int *valp) { if (pos + 1 >= argc) errx(1, "missing value for %s", argv[pos]); if (get_int_arg(argv[pos + 1], valp)) exit(1); return 0; } static int tx_sched(int argc, char *argv[], int start_arg, const char *iff_name) { struct ch_hw_sched op; unsigned int idx, val; if (argc < 5 || get_int_arg(argv[start_arg++], &idx)) return -1; op.sched = idx; op.mode = op.channel = -1; op.kbps = op.class_ipg = op.flow_ipg = -1; while (argc > start_arg) { if (!strcmp(argv[start_arg], "mode")) { if (start_arg + 1 >= argc) errx(1, "missing value for mode"); if (!strcmp(argv[start_arg + 1], "class")) op.mode = 0; else if (!strcmp(argv[start_arg + 1], "flow")) op.mode = 1; else errx(1, "bad mode \"%s\"", argv[start_arg + 1]); } else if (!strcmp(argv[start_arg], "channel") && !get_sched_param(argc, argv, start_arg, &val)) op.channel = val; else if (!strcmp(argv[start_arg], "rate") && !get_sched_param(argc, argv, start_arg, &val)) op.kbps = val; else if (!strcmp(argv[start_arg], "ipg") && !get_sched_param(argc, argv, start_arg, &val)) op.class_ipg = val; else if (!strcmp(argv[start_arg], "flowipg") && !get_sched_param(argc, argv, start_arg, &val)) op.flow_ipg = val; else errx(1, "unknown scheduler parameter \"%s\"", argv[start_arg]); start_arg += 2; } if (doit(iff_name, CHELSIO_SET_HW_SCHED, &op) < 0) err(1, "pktsched"); return 0; } static int pktsched(int argc, char *argv[], int start_arg, const char *iff_name) { struct ch_pktsched_params op; unsigned int idx, min = -1, max, binding = -1; if (argc < 4) errx(1, "no scheduler specified"); if (!strcmp(argv[start_arg], "port")) { if (argc != start_arg + 4) return -1; if (get_int_arg(argv[start_arg + 1], &idx) || get_int_arg(argv[start_arg + 2], &min) || get_int_arg(argv[start_arg + 3], &max)) return -1; op.sched = 0; } else if (!strcmp(argv[start_arg], "tunnelq")) { if (argc != start_arg + 4) return -1; if (get_int_arg(argv[start_arg + 1], &idx) || get_int_arg(argv[start_arg + 2], &max) || get_int_arg(argv[start_arg + 3], &binding)) return -1; op.sched = 1; } else if (!strcmp(argv[start_arg], "tx")) return tx_sched(argc, argv, start_arg + 1, iff_name); else errx(1, "unknown scheduler \"%s\"; must be one of \"port\", " "\"tunnelq\" or \"tx\"", argv[start_arg]); op.idx = idx; op.min = min; op.max = max; op.binding = binding; if (doit(iff_name, CHELSIO_SET_PKTSCHED, &op) < 0) err(1, "pktsched"); return 0; } static int clear_stats(int argc, char *argv[], int start_arg, const char *iff_name) { (void) argc; (void) argv; (void) start_arg; if (doit(iff_name, CHELSIO_CLEAR_STATS, NULL) < 0) err(1, "clearstats"); return 0; } static int get_up_la(int argc, char *argv[], int start_arg, const char *iff_name) { struct ch_up_la la; int i, idx, max_idx, entries; (void) argc; (void) argv; (void) start_arg; la.stopped = 0; la.idx = -1; la.bufsize = LA_BUFSIZE; la.data = malloc(la.bufsize); if (!la.data) err(1, "uP_LA malloc"); if (doit(iff_name, CHELSIO_GET_UP_LA, &la) < 0) err(1, "uP_LA"); if (la.stopped) printf("LA is not running\n"); entries = la.bufsize / 4; idx = (int)la.idx; max_idx = (entries / 4) - 1; for (i = 0; i < max_idx; i++) { printf("%04x %08x %08x\n", la.data[idx], la.data[idx+2], la.data[idx+1]); idx = (idx + 4) & (entries - 1); } return 0; } static int get_up_ioqs(int argc, char *argv[], int start_arg, const char *iff_name) { struct ch_up_ioqs ioqs; int i, entries; (void) argc; (void) argv; (void) start_arg; bzero(&ioqs, sizeof(ioqs)); ioqs.bufsize = IOQS_BUFSIZE; ioqs.data = malloc(IOQS_BUFSIZE); if (!ioqs.data) err(1, "uP_IOQs malloc"); if (doit(iff_name, CHELSIO_GET_UP_IOQS, &ioqs) < 0) err(1, "uP_IOQs"); printf("ioq_rx_enable : 0x%08x\n", ioqs.ioq_rx_enable); printf("ioq_tx_enable : 0x%08x\n", ioqs.ioq_tx_enable); printf("ioq_rx_status : 0x%08x\n", ioqs.ioq_rx_status); printf("ioq_tx_status : 0x%08x\n", ioqs.ioq_tx_status); entries = ioqs.bufsize / sizeof(struct t3_ioq_entry); for (i = 0; i < entries; i++) { printf("\nioq[%d].cp : 0x%08x\n", i, ioqs.data[i].ioq_cp); printf("ioq[%d].pp : 0x%08x\n", i, ioqs.data[i].ioq_pp); printf("ioq[%d].alen : 0x%08x\n", i, ioqs.data[i].ioq_alen); printf("ioq[%d].stats : 0x%08x\n", i, ioqs.data[i].ioq_stats); printf(" sop %u\n", ioqs.data[i].ioq_stats >> 16); printf(" eop %u\n", ioqs.data[i].ioq_stats & 0xFFFF); } return 0; } static int run_cmd(int argc, char *argv[], const char *iff_name) { int r = -1; if (!strcmp(argv[2], "reg")) r = register_io(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "mdio")) r = mdio_io(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "mtus")) r = mtu_tab_op(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "pm")) r = conf_pm(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "regdump")) r = dump_regs(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "tcamdump")) r = dump_tcam(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "memdump")) r = dump_mc7(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "meminfo")) r = meminfo(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "context")) r = get_sge_context(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "desc")) r = get_sge_desc(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "loadfw")) r = load_fw(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "loadboot")) r = load_boot(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "proto")) r = proto_sram_op(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "qset")) r = qset_config(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "qsets")) r = qset_num_config(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "trace")) r = trace_config(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "pktsched")) r = pktsched(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "tcb")) r = get_tcb2(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "filter")) r = filter_config(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "clearstats")) r = clear_stats(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "la")) r = get_up_la(argc, argv, 3, iff_name); else if (!strcmp(argv[2], "ioqs")) r = get_up_ioqs(argc, argv, 3, iff_name); if (r == -1) usage(stderr); return (0); } static int run_cmd_loop(int argc, char *argv[], const char *iff_name) { int n; unsigned int i; char buf[64]; char *args[8], *s; (void) argc; args[0] = argv[0]; args[1] = argv[1]; /* * Fairly simplistic loop. Displays a "> " prompt and processes any * input as a cxgbtool command. You're supposed to enter only the part * after "cxgbtool cxgbX". Use "quit" or "exit" to exit. Any error in * the command will also terminate cxgbtool. */ for (;;) { fprintf(stdout, "> "); fflush(stdout); n = read(STDIN_FILENO, buf, sizeof(buf) - 1); if (n <= 0) return (0); if (buf[--n] != '\n') continue; else buf[n] = 0; s = &buf[0]; for (i = 2; i < sizeof(args)/sizeof(args[0]) - 1; i++) { while (s && (*s == ' ' || *s == '\t')) s++; if ((args[i] = strsep(&s, " \t")) == NULL) break; } args[sizeof(args)/sizeof(args[0]) - 1] = 0; if (!strcmp(args[2], "quit") || !strcmp(args[2], "exit")) return (0); (void) run_cmd(i, args, iff_name); } /* Can't really get here */ return (0); } int main(int argc, char *argv[]) { int r = -1; const char *iff_name; progname = argv[0]; if (argc == 2) { if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) usage(stdout); if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) { printf("%s version %s\n", PROGNAME, VERSION); printf("%s\n", COPYRIGHT); exit(0); } } if (argc < 3) usage(stderr); iff_name = argv[1]; if (argc == 3 && !strcmp(argv[2], "stdio")) r = run_cmd_loop(argc, argv, iff_name); else r = run_cmd(argc, argv, iff_name); return (r); } diff --git a/tools/tools/iwn/iwnstats/iwn_ioctl.c b/tools/tools/iwn/iwnstats/iwn_ioctl.c index 13c615397a0c..97b2a918d9ec 100644 --- a/tools/tools/iwn/iwnstats/iwn_ioctl.c +++ b/tools/tools/iwn/iwnstats/iwn_ioctl.c @@ -1,91 +1,90 @@ /*- * Copyright (c) 2014 Adrian Chadd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * * $FreeBSD$ */ /* * iwn ioctl API. */ #include #include #include #include #include #include -#include #include #include #include #include #include #include #include "net80211/ieee80211_ioctl.h" #include "net80211/ieee80211_radiotap.h" #include "if_iwn_ioctl.h" /* * This contains the register definitions for iwn; including * the statistics definitions. */ #include "if_iwnreg.h" #include "iwnstats.h" #include "iwn_ioctl.h" void iwn_setifname(struct iwnstats *is, const char *ifname) { strncpy(is->ifr.ifr_name, ifname, sizeof (is->ifr.ifr_name)); } void iwn_zerostats(struct iwnstats *is) { if (ioctl(is->s, SIOCZIWNSTATS, &is->ifr) < 0) err(-1, "ioctl: %s", is->ifr.ifr_name); } int iwn_collect(struct iwnstats *is) { int err; is->ifr.ifr_data = (caddr_t) &is->st; err = ioctl(is->s, SIOCGIWNSTATS, &is->ifr); if (err < 0) warn("ioctl: %s", is->ifr.ifr_name); return (err); } diff --git a/usr.bin/bluetooth/btsockstat/btsockstat.c b/usr.bin/bluetooth/btsockstat/btsockstat.c index 20f4de8076c8..a9c93542cfb8 100644 --- a/usr.bin/bluetooth/btsockstat/btsockstat.c +++ b/usr.bin/bluetooth/btsockstat/btsockstat.c @@ -1,645 +1,644 @@ /* * btsockstat.c * * Copyright (c) 2001-2002 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: btsockstat.c,v 1.8 2003/05/21 22:40:25 max Exp $ * $FreeBSD$ */ #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void hcirawpr (kvm_t *kvmd, u_long addr); static void l2caprawpr (kvm_t *kvmd, u_long addr); static void l2cappr (kvm_t *kvmd, u_long addr); static void l2caprtpr (kvm_t *kvmd, u_long addr); static void rfcommpr (kvm_t *kvmd, u_long addr); static void rfcommpr_s (kvm_t *kvmd, u_long addr); static char * bdaddrpr (bdaddr_p const ba, char *str, int len); static kvm_t * kopen (char const *memf); static int kread (kvm_t *kvmd, u_long addr, char *buffer, int size); static void usage (void); /* * List of symbols */ static struct nlist nl[] = { #define N_HCI_RAW 0 { "_ng_btsocket_hci_raw_sockets" }, #define N_L2CAP_RAW 1 { "_ng_btsocket_l2cap_raw_sockets" }, #define N_L2CAP 2 { "_ng_btsocket_l2cap_sockets" }, #define N_L2CAP_RAW_RT 3 { "_ng_btsocket_l2cap_raw_rt" }, #define N_L2CAP_RT 4 { "_ng_btsocket_l2cap_rt" }, #define N_RFCOMM 5 { "_ng_btsocket_rfcomm_sockets" }, #define N_RFCOMM_S 6 { "_ng_btsocket_rfcomm_sessions" }, { "" }, }; #define state2str(x) \ (((x) >= sizeof(states)/sizeof(states[0]))? "UNKNOWN" : states[(x)]) /* * Main */ static int numeric_bdaddr = 0; int main(int argc, char *argv[]) { int opt, proto = -1, route = 0; kvm_t *kvmd = NULL; char *memf = NULL; while ((opt = getopt(argc, argv, "hnM:p:r")) != -1) { switch (opt) { case 'n': numeric_bdaddr = 1; break; case 'M': memf = optarg; break; case 'p': if (strcasecmp(optarg, "hci_raw") == 0) proto = N_HCI_RAW; else if (strcasecmp(optarg, "l2cap_raw") == 0) proto = N_L2CAP_RAW; else if (strcasecmp(optarg, "l2cap") == 0) proto = N_L2CAP; else if (strcasecmp(optarg, "rfcomm") == 0) proto = N_RFCOMM; else if (strcasecmp(optarg, "rfcomm_s") == 0) proto = N_RFCOMM_S; else usage(); /* NOT REACHED */ break; case 'r': route = 1; break; case 'h': default: usage(); /* NOT REACHED */ } } if ((proto == N_HCI_RAW || proto == N_RFCOMM || proto == N_RFCOMM_S) && route) usage(); /* NOT REACHED */ /* * Discard setgid privileges if not the running kernel so that * bad guys can't print interesting stuff from kernel memory. */ if (memf != NULL) setgid(getgid()); kvmd = kopen(memf); if (kvmd == NULL) return (1); switch (proto) { case N_HCI_RAW: hcirawpr(kvmd, nl[N_HCI_RAW].n_value); break; case N_L2CAP_RAW: if (route) l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value); else l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value); break; case N_L2CAP: if (route) l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value); else l2cappr(kvmd, nl[N_L2CAP].n_value); break; case N_RFCOMM: rfcommpr(kvmd, nl[N_RFCOMM].n_value); break; case N_RFCOMM_S: rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value); break; default: if (route) { l2caprtpr(kvmd, nl[N_L2CAP_RAW_RT].n_value); l2caprtpr(kvmd, nl[N_L2CAP_RT].n_value); } else { hcirawpr(kvmd, nl[N_HCI_RAW].n_value); l2caprawpr(kvmd, nl[N_L2CAP_RAW].n_value); l2cappr(kvmd, nl[N_L2CAP].n_value); rfcommpr_s(kvmd, nl[N_RFCOMM_S].n_value); rfcommpr(kvmd, nl[N_RFCOMM].n_value); } break; } return (kvm_close(kvmd)); } /* main */ /* * Print raw HCI sockets */ static void hcirawpr(kvm_t *kvmd, u_long addr) { ng_btsocket_hci_raw_pcb_p this = NULL, next = NULL; ng_btsocket_hci_raw_pcb_t pcb; struct socket so; int first = 1; if (addr == 0) return; if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0) return; for ( ; this != NULL; this = next) { if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0) return; if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0) return; next = LIST_NEXT(&pcb, next); if (first) { first = 0; fprintf(stdout, "Active raw HCI sockets\n" \ "%-8.8s %-8.8s %-6.6s %-6.6s %-6.6s %-16.16s\n", "Socket", "PCB", "Flags", "Recv-Q", "Send-Q", "Local address"); } if (pcb.addr.hci_node[0] == 0) { pcb.addr.hci_node[0] = '*'; pcb.addr.hci_node[1] = 0; } fprintf(stdout, "%-8lx %-8lx %-6.6x %6d %6d %-16.16s\n", (unsigned long) pcb.so, (unsigned long) this, pcb.flags, so.so_rcv.sb_ccc, so.so_snd.sb_ccc, pcb.addr.hci_node); } } /* hcirawpr */ /* * Print raw L2CAP sockets */ static void l2caprawpr(kvm_t *kvmd, u_long addr) { ng_btsocket_l2cap_raw_pcb_p this = NULL, next = NULL; ng_btsocket_l2cap_raw_pcb_t pcb; struct socket so; int first = 1; if (addr == 0) return; if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0) return; for ( ; this != NULL; this = next) { if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0) return; if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0) return; next = LIST_NEXT(&pcb, next); if (first) { first = 0; fprintf(stdout, "Active raw L2CAP sockets\n" \ "%-8.8s %-8.8s %-6.6s %-6.6s %-17.17s\n", "Socket", "PCB", "Recv-Q", "Send-Q", "Local address"); } fprintf(stdout, "%-8lx %-8lx %6d %6d %-17.17s\n", (unsigned long) pcb.so, (unsigned long) this, so.so_rcv.sb_ccc, so.so_snd.sb_ccc, bdaddrpr(&pcb.src, NULL, 0)); } } /* l2caprawpr */ /* * Print L2CAP sockets */ static void l2cappr(kvm_t *kvmd, u_long addr) { static char const * const states[] = { /* NG_BTSOCKET_L2CAP_CLOSED */ "CLOSED", /* NG_BTSOCKET_L2CAP_CONNECTING */ "CON", /* NG_BTSOCKET_L2CAP_CONFIGURING */ "CONFIG", /* NG_BTSOCKET_L2CAP_OPEN */ "OPEN", /* NG_BTSOCKET_L2CAP_DISCONNECTING */ "DISCON" }; ng_btsocket_l2cap_pcb_p this = NULL, next = NULL; ng_btsocket_l2cap_pcb_t pcb; struct socket so; int first = 1; char local[24], remote[24]; if (addr == 0) return; if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0) return; for ( ; this != NULL; this = next) { if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0) return; if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0) return; next = LIST_NEXT(&pcb, next); if (first) { first = 0; fprintf(stdout, "Active L2CAP sockets\n" \ "%-8.8s %-6.6s %-6.6s %-23.23s %-17.17s %-5.5s %s\n", "PCB", "Recv-Q", "Send-Q", "Local address/PSM", "Foreign address", "CID", "State"); } fprintf(stdout, "%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n", (unsigned long) this, so.so_rcv.sb_ccc, so.so_snd.sb_ccc, bdaddrpr(&pcb.src, local, sizeof(local)), pcb.psm, bdaddrpr(&pcb.dst, remote, sizeof(remote)), pcb.cid, (so.so_options & SO_ACCEPTCONN)? "LISTEN" : state2str(pcb.state)); } } /* l2cappr */ /* * Print L2CAP routing table */ static void l2caprtpr(kvm_t *kvmd, u_long addr) { ng_btsocket_l2cap_rtentry_p this = NULL, next = NULL; ng_btsocket_l2cap_rtentry_t rt; int first = 1; if (addr == 0) return; if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0) return; for ( ; this != NULL; this = next) { if (kread(kvmd, (u_long) this, (char *) &rt, sizeof(rt)) < 0) return; next = LIST_NEXT(&rt, next); if (first) { first = 0; fprintf(stdout, "Known %sL2CAP routes\n", (addr == nl[N_L2CAP_RAW_RT].n_value)? "raw " : ""); fprintf(stdout, "%-8.8s %-8.8s %-17.17s\n", "RTentry", "Hook", "BD_ADDR"); } fprintf(stdout, "%-8lx %-8lx %-17.17s\n", (unsigned long) this, (unsigned long) rt.hook, bdaddrpr(&rt.src, NULL, 0)); } } /* l2caprtpr */ /* * Print RFCOMM sockets */ static void rfcommpr(kvm_t *kvmd, u_long addr) { static char const * const states[] = { /* NG_BTSOCKET_RFCOMM_DLC_CLOSED */ "CLOSED", /* NG_BTSOCKET_RFCOMM_DLC_W4_CONNECT */ "W4CON", /* NG_BTSOCKET_RFCOMM_DLC_CONFIGURING */ "CONFIG", /* NG_BTSOCKET_RFCOMM_DLC_CONNECTING */ "CONN", /* NG_BTSOCKET_RFCOMM_DLC_CONNECTED */ "OPEN", /* NG_BTSOCKET_RFCOMM_DLC_DISCONNECTING */ "DISCON" }; ng_btsocket_rfcomm_pcb_p this = NULL, next = NULL; ng_btsocket_rfcomm_pcb_t pcb; struct socket so; int first = 1; char local[24], remote[24]; if (addr == 0) return; if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0) return; for ( ; this != NULL; this = next) { if (kread(kvmd, (u_long) this, (char *) &pcb, sizeof(pcb)) < 0) return; if (kread(kvmd, (u_long) pcb.so, (char *) &so, sizeof(so)) < 0) return; next = LIST_NEXT(&pcb, next); if (first) { first = 0; fprintf(stdout, "Active RFCOMM sockets\n" \ "%-8.8s %-6.6s %-6.6s %-17.17s %-17.17s %-4.4s %-4.4s %s\n", "PCB", "Recv-Q", "Send-Q", "Local address", "Foreign address", "Chan", "DLCI", "State"); } fprintf(stdout, "%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n", (unsigned long) this, so.so_rcv.sb_ccc, so.so_snd.sb_ccc, bdaddrpr(&pcb.src, local, sizeof(local)), bdaddrpr(&pcb.dst, remote, sizeof(remote)), pcb.channel, pcb.dlci, (so.so_options & SO_ACCEPTCONN)? "LISTEN" : state2str(pcb.state)); } } /* rfcommpr */ /* * Print RFCOMM sessions */ static void rfcommpr_s(kvm_t *kvmd, u_long addr) { static char const * const states[] = { /* NG_BTSOCKET_RFCOMM_SESSION_CLOSED */ "CLOSED", /* NG_BTSOCKET_RFCOMM_SESSION_LISTENING */ "LISTEN", /* NG_BTSOCKET_RFCOMM_SESSION_CONNECTING */ "CONNECTING", /* NG_BTSOCKET_RFCOMM_SESSION_CONNECTED */ "CONNECTED", /* NG_BTSOCKET_RFCOMM_SESSION_OPEN */ "OPEN", /* NG_BTSOCKET_RFCOMM_SESSION_DISCONNECTING */ "DISCONNECTING" }; ng_btsocket_rfcomm_session_p this = NULL, next = NULL; ng_btsocket_rfcomm_session_t s; struct socket so; int first = 1; if (addr == 0) return; if (kread(kvmd, addr, (char *) &this, sizeof(this)) < 0) return; for ( ; this != NULL; this = next) { if (kread(kvmd, (u_long) this, (char *) &s, sizeof(s)) < 0) return; if (kread(kvmd, (u_long) s.l2so, (char *) &so, sizeof(so)) < 0) return; next = LIST_NEXT(&s, next); if (first) { first = 0; fprintf(stdout, "Active RFCOMM sessions\n" \ "%-8.8s %-8.8s %-4.4s %-5.5s %-5.5s %-4.4s %s\n", "L2PCB", "PCB", "Flags", "MTU", "Out-Q", "DLCs", "State"); } fprintf(stdout, "%-8lx %-8lx %-4x %-5d %-5d %-4s %s\n", (unsigned long) so.so_pcb, (unsigned long) this, s.flags, s.mtu, s.outq.len, LIST_EMPTY(&s.dlcs)? "No" : "Yes", state2str(s.state)); } } /* rfcommpr_s */ /* * Return BD_ADDR as string */ static char * bdaddrpr(bdaddr_p const ba, char *str, int len) { static char buffer[MAXHOSTNAMELEN]; struct hostent *he = NULL; if (str == NULL) { str = buffer; len = sizeof(buffer); } if (memcmp(ba, NG_HCI_BDADDR_ANY, sizeof(*ba)) == 0) { str[0] = '*'; str[1] = 0; return (str); } if (!numeric_bdaddr && (he = bt_gethostbyaddr((char *)ba, sizeof(*ba), AF_BLUETOOTH)) != NULL) { strlcpy(str, he->h_name, len); return (str); } bt_ntoa(ba, str); return (str); } /* bdaddrpr */ /* * Open kvm */ static kvm_t * kopen(char const *memf) { kvm_t *kvmd = NULL; char errbuf[_POSIX2_LINE_MAX]; /* * Discard setgid privileges if not the running kernel so that * bad guys can't print interesting stuff from kernel memory. */ if (memf != NULL) setgid(getgid()); kvmd = kvm_openfiles(NULL, memf, NULL, O_RDONLY, errbuf); if (kvmd == NULL) { warnx("kvm_openfiles: %s", errbuf); return (NULL); } if (kvm_nlist(kvmd, nl) < 0) { warnx("kvm_nlist: %s", kvm_geterr(kvmd)); goto fail; } if (nl[0].n_type == 0) { warnx("kvm_nlist: no namelist"); goto fail; } return (kvmd); fail: kvm_close(kvmd); return (NULL); } /* kopen */ /* * Read kvm */ static int kread(kvm_t *kvmd, u_long addr, char *buffer, int size) { if (kvmd == NULL || buffer == NULL) return (-1); if (kvm_read(kvmd, addr, buffer, size) != size) { warnx("kvm_read: %s", kvm_geterr(kvmd)); return (-1); } return (0); } /* kread */ /* * Print usage and exit */ static void usage(void) { fprintf(stdout, "Usage: btsockstat [-M core ] [-n] [-p proto] [-r]\n"); exit(255); } /* usage */ diff --git a/usr.bin/kdump/mkioctls b/usr.bin/kdump/mkioctls index a9ba860682af..525e143aa442 100644 --- a/usr.bin/kdump/mkioctls +++ b/usr.bin/kdump/mkioctls @@ -1,119 +1,118 @@ #!/bin/sh # # $FreeBSD$ # # When editing this script, keep in mind that truss also uses it. # set -e if [ $# -ne 2 -o \( $1 != "print" -a $1 != "return" \) ]; then echo "usage: sh $0 print|return include-dir" exit 1 fi style="$1" includedir="$2" LC_ALL=C; export LC_ALL # Build a list of headers that have ioctls in them. # XXX should we use an ANSI cpp? ioctl_includes=$( cd $includedir find -H -s * -name '*.h' | \ egrep -v '(.*disk.*|net/pfvar|net/if_pfsync)\.h' | \ xargs egrep -l \ '^#[ ]*define[ ]+[A-Za-z_][A-Za-z0-9_]*[ ]+_IO[^a-z0-9_]' | awk '{printf("#include <%s>\\n", $1)}' ) : ${MACHINE=$(uname -m)} case "${MACHINE}" in *pc98*) ioctl_includes="$ioctl_includes#include \\n" ;; *) ioctl_includes="$ioctl_includes#include \\n" ;; esac awk -v x="$ioctl_includes" 'BEGIN {print x}' | $CPP -I$1 -dM -DCOMPAT_43TTY - | awk -v ioctl_includes="$ioctl_includes" -v style="$style" ' BEGIN { print "/* XXX obnoxious prerequisites. */" print "#define COMPAT_43" print "#define COMPAT_43TTY" print "#include " print "#include " print "#include " print "#include " print "#include " print "#include " print "#include " print "#include " print "#include " - print "#include " print "#ifdef PF" print "#include " print "#include " print "#endif" print "#include " print "#include " print "#include " print "#include " print "#include " print "#include " print "#include " print "#include " print "#include " print "#include " print "" print ioctl_includes print "" if (style == "print") { print "void ioctlname(unsigned long val, int decimal);" print "" print "void" print "ioctlname(unsigned long val, int decimal)" } else { print "const char *ioctlname(unsigned long val);" print "" print "const char *" print "ioctlname(unsigned long val)" } print "{" print "\tconst char *str = NULL;" print "" } /^#[ ]*define[ ]+[A-Za-z_][A-Za-z0-9_]*[ ]+_IO/ { # find where the name starts for (i = 1; i <= NF; i++) if ($i ~ /define/) break; ++i; # printf("\t"); if (n++ > 0) printf("else "); printf("if (val == %s)\n", $i); printf("\t\tstr = \"%s\";\n", $i); } END { print "" if (style == "print") { print "\tif (str != NULL)" print "\t\tprintf(\"%s\", str);" print "\telse if (decimal)" print "\t\tprintf(\"%lu\", val);" print "\telse" print "\t\tprintf(\"%#lx\", val);" } else { print "\treturn (str);" } print "}" } ' diff --git a/usr.bin/netstat/bpf.c b/usr.bin/netstat/bpf.c index b48f9a103b1a..60546e38be14 100644 --- a/usr.bin/netstat/bpf.c +++ b/usr.bin/netstat/bpf.c @@ -1,170 +1,169 @@ /*- * Copyright (c) 2005 Christian S.J. Peron * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" /* print bpf stats */ static char * bpf_pidname(pid_t pid) { struct kinfo_proc newkp; int error, mib[4]; size_t size; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = pid; size = sizeof(newkp); error = sysctl(mib, 4, &newkp, &size, NULL, 0); if (error < 0) { xo_warn("kern.proc.pid failed"); return (strdup("??????")); } return (strdup(newkp.ki_comm)); } static void bpf_flags(struct xbpf_d *bd, char *flagbuf) { *flagbuf++ = bd->bd_promisc ? 'p' : '-'; *flagbuf++ = bd->bd_immediate ? 'i' : '-'; *flagbuf++ = bd->bd_hdrcmplt ? '-' : 'f'; *flagbuf++ = (bd->bd_direction == BPF_D_IN) ? '-' : ((bd->bd_direction == BPF_D_OUT) ? 'o' : 's'); *flagbuf++ = bd->bd_feedback ? 'b' : '-'; *flagbuf++ = bd->bd_async ? 'a' : '-'; *flagbuf++ = bd->bd_locked ? 'l' : '-'; *flagbuf++ = '\0'; if (bd->bd_promisc) xo_emit("{e:promiscuous/}"); if (bd->bd_immediate) xo_emit("{e:immediate/}"); if (bd->bd_hdrcmplt) xo_emit("{e:header-complete/}"); xo_emit("{e:direction}", (bd->bd_direction == BPF_D_IN) ? "input" : (bd->bd_direction == BPF_D_OUT) ? "output" : "bidirectional"); if (bd->bd_feedback) xo_emit("{e:feedback/}"); if (bd->bd_async) xo_emit("{e:async/}"); if (bd->bd_locked) xo_emit("{e:locked/}"); } void bpf_stats(char *ifname) { struct xbpf_d *d, *bd, zerostat; char *pname, flagbuf[12]; size_t size; if (zflag) { bzero(&zerostat, sizeof(zerostat)); if (sysctlbyname("net.bpf.stats", NULL, NULL, &zerostat, sizeof(zerostat)) < 0) xo_warn("failed to zero bpf counters"); return; } if (sysctlbyname("net.bpf.stats", NULL, &size, NULL, 0) < 0) { xo_warn("net.bpf.stats"); return; } if (size == 0) return; bd = malloc(size); if (bd == NULL) { xo_warn("malloc failed"); return; } if (sysctlbyname("net.bpf.stats", bd, &size, NULL, 0) < 0) { xo_warn("net.bpf.stats"); free(bd); return; } xo_emit("{T:/%5s} {T:/%6s} {T:/%7s} {T:/%9s} {T:/%9s} {T:/%9s} " "{T:/%5s} {T:/%5s} {T:/%s}\n", "Pid", "Netif", "Flags", "Recv", "Drop", "Match", "Sblen", "Hblen", "Command"); xo_open_container("bpf-statistics"); xo_open_list("bpf-entry"); for (d = &bd[0]; d < &bd[size / sizeof(*d)]; d++) { if (d->bd_structsize != sizeof(*d)) { xo_warnx("bpf_stats_extended: version mismatch"); return; } if (ifname && strcmp(ifname, d->bd_ifname) != 0) continue; xo_open_instance("bpf-entry"); pname = bpf_pidname(d->bd_pid); xo_emit("{k:pid/%5d} {k:interface-name/%6s} ", d->bd_pid, d->bd_ifname); bpf_flags(d, flagbuf); xo_emit("{d:flags/%7s} {:received-packets/%9ju} " "{:dropped-packets/%9ju} {:filter-packets/%9ju} " "{:store-buffer-length/%5d} {:hold-buffer-length/%5d} " "{:process/%s}\n", flagbuf, (uintmax_t)d->bd_rcount, (uintmax_t)d->bd_dcount, (uintmax_t)d->bd_fcount, d->bd_slen, d->bd_hlen, pname); free(pname); xo_close_instance("bpf-entry"); } xo_close_list("bpf-entry"); xo_close_container("bpf-statistics"); free(bd); } diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c index cc8405e602b9..f04c5310dd86 100644 --- a/usr.bin/netstat/if.c +++ b/usr.bin/netstat/if.c @@ -1,673 +1,672 @@ /*- * Copyright (c) 2013 Gleb Smirnoff * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)if.c 8.3 (Berkeley) 4/28/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #ifdef PF #include #include #endif #include #include #include #include #ifdef INET6 #include #endif #include #include #include #include #include #include #include #include #include #include "netstat.h" static void sidewaysintpr(int); #ifdef INET6 static char addr_buf[NI_MAXHOST]; /* for getnameinfo() */ #endif #ifdef PF static const char* pfsyncacts[] = { /* PFSYNC_ACT_CLR */ "clear all request", /* PFSYNC_ACT_INS */ "state insert", /* PFSYNC_ACT_INS_ACK */ "state inserted ack", /* PFSYNC_ACT_UPD */ "state update", /* PFSYNC_ACT_UPD_C */ "compressed state update", /* PFSYNC_ACT_UPD_REQ */ "uncompressed state request", /* PFSYNC_ACT_DEL */ "state delete", /* PFSYNC_ACT_DEL_C */ "compressed state delete", /* PFSYNC_ACT_INS_F */ "fragment insert", /* PFSYNC_ACT_DEL_F */ "fragment delete", /* PFSYNC_ACT_BUS */ "bulk update mark", /* PFSYNC_ACT_TDB */ "TDB replay counter update", /* PFSYNC_ACT_EOF */ "end of frame mark", }; static const char* pfsyncacts_name[] = { /* PFSYNC_ACT_CLR */ "clear-all-request", /* PFSYNC_ACT_INS */ "state-insert", /* PFSYNC_ACT_INS_ACK */ "state-inserted-ack", /* PFSYNC_ACT_UPD */ "state-update", /* PFSYNC_ACT_UPD_C */ "compressed-state-update", /* PFSYNC_ACT_UPD_REQ */ "uncompressed-state-request", /* PFSYNC_ACT_DEL */ "state-delete", /* PFSYNC_ACT_DEL_C */ "compressed-state-delete", /* PFSYNC_ACT_INS_F */ "fragment-insert", /* PFSYNC_ACT_DEL_F */ "fragment-delete", /* PFSYNC_ACT_BUS */ "bulk-update-mark", /* PFSYNC_ACT_TDB */ "TDB-replay-counter-update", /* PFSYNC_ACT_EOF */ "end-of-frame-mark", }; static void pfsync_acts_stats(const char *list, const char *desc, uint64_t *a) { int i; xo_open_list(list); for (i = 0; i < PFSYNC_ACT_MAX; i++, a++) { if (*a || sflag <= 1) { xo_open_instance(list); xo_emit("\t\t{e:name}{:count/%ju} {N:/%s%s %s}\n", pfsyncacts_name[i], (uintmax_t)(*a), pfsyncacts[i], plural(*a), desc); xo_close_instance(list); } } xo_close_list(list); } /* * Dump pfsync statistics structure. */ void pfsync_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct pfsyncstats pfsyncstat, zerostat; size_t len = sizeof(struct pfsyncstats); if (live) { if (zflag) memset(&zerostat, 0, len); if (sysctlbyname("net.pfsync.stats", &pfsyncstat, &len, zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { if (errno != ENOENT) warn("sysctl: net.pfsync.stats"); return; } } else kread(off, &pfsyncstat, len); xo_emit("{T:/%s}:\n", name); xo_open_container(name); #define p(f, m) if (pfsyncstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)pfsyncstat.f, plural(pfsyncstat.f)) p(pfsyncs_ipackets, "\t{:received-inet-packets/%ju} " "{N:/packet%s received (IPv4)}\n"); p(pfsyncs_ipackets6, "\t{:received-inet6-packets/%ju} " "{N:/packet%s received (IPv6)}\n"); pfsync_acts_stats("input-histogram", "received", &pfsyncstat.pfsyncs_iacts[0]); p(pfsyncs_badif, "\t\t/{:dropped-bad-interface/%ju} " "{N:/packet%s discarded for bad interface}\n"); p(pfsyncs_badttl, "\t\t{:dropped-bad-ttl/%ju} " "{N:/packet%s discarded for bad ttl}\n"); p(pfsyncs_hdrops, "\t\t{:dropped-short-header/%ju} " "{N:/packet%s shorter than header}\n"); p(pfsyncs_badver, "\t\t{:dropped-bad-version/%ju} " "{N:/packet%s discarded for bad version}\n"); p(pfsyncs_badauth, "\t\t{:dropped-bad-auth/%ju} " "{N:/packet%s discarded for bad HMAC}\n"); p(pfsyncs_badact,"\t\t{:dropped-bad-action/%ju} " "{N:/packet%s discarded for bad action}\n"); p(pfsyncs_badlen, "\t\t{:dropped-short/%ju} " "{N:/packet%s discarded for short packet}\n"); p(pfsyncs_badval, "\t\t{:dropped-bad-values/%ju} " "{N:/state%s discarded for bad values}\n"); p(pfsyncs_stale, "\t\t{:dropped-stale-state/%ju} " "{N:/stale state%s}\n"); p(pfsyncs_badstate, "\t\t{:dropped-failed-lookup/%ju} " "{N:/failed state lookup\\/insert%s}\n"); p(pfsyncs_opackets, "\t{:sent-inet-packets/%ju} " "{N:/packet%s sent (IPv4})\n"); p(pfsyncs_opackets6, "\t{:send-inet6-packets/%ju} " "{N:/packet%s sent (IPv6})\n"); pfsync_acts_stats("output-histogram", "sent", &pfsyncstat.pfsyncs_oacts[0]); p(pfsyncs_onomem, "\t\t{:discarded-no-memory/%ju} " "{N:/failure%s due to mbuf memory error}\n"); p(pfsyncs_oerrors, "\t\t{:send-errors/%ju} " "{N:/send error%s}\n"); #undef p xo_close_container(name); } #endif /* PF */ /* * Display a formatted value, or a '-' in the same space. */ static void show_stat(const char *fmt, int width, const char *name, u_long value, short showvalue) { const char *lsep, *rsep; char newfmt[64]; lsep = ""; if (strncmp(fmt, "LS", 2) == 0) { lsep = " "; fmt += 2; } rsep = " "; if (strncmp(fmt, "NRS", 3) == 0) { rsep = ""; fmt += 3; } if (showvalue == 0) { /* Print just dash. */ xo_emit("{P:/%s}{D:/%*s}{P:/%s}", lsep, width, "-", rsep); return; } /* * XXX: workaround {P:} modifier can't be empty and doesn't seem to * take args... so we need to conditionally include it in the format. */ #define maybe_pad(pad) do { \ if (strlen(pad)) { \ snprintf(newfmt, sizeof(newfmt), "{P:%s}", pad); \ xo_emit(newfmt); \ } \ } while (0) if (hflag) { char buf[5]; /* Format in human readable form. */ humanize_number(buf, sizeof(buf), (int64_t)value, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); maybe_pad(lsep); snprintf(newfmt, sizeof(newfmt), "{:%s/%%%ds}", name, width); xo_emit(newfmt, buf); maybe_pad(rsep); } else { /* Construct the format string. */ maybe_pad(lsep); snprintf(newfmt, sizeof(newfmt), "{:%s/%%%d%s}", name, width, fmt); xo_emit(newfmt, value); maybe_pad(rsep); } } /* * Find next multiaddr for a given interface name. */ static struct ifmaddrs * next_ifma(struct ifmaddrs *ifma, const char *name, const sa_family_t family) { for(; ifma != NULL; ifma = ifma->ifma_next) { struct sockaddr_dl *sdl; sdl = (struct sockaddr_dl *)ifma->ifma_name; if (ifma->ifma_addr->sa_family == family && strcmp(sdl->sdl_data, name) == 0) break; } return (ifma); } /* * Print a description of the network interfaces. */ void intpr(int interval, void (*pfunc)(char *), int af) { struct ifaddrs *ifap, *ifa; struct ifmaddrs *ifmap, *ifma; if (interval) return sidewaysintpr(interval); if (getifaddrs(&ifap) != 0) err(EX_OSERR, "getifaddrs"); if (aflag && getifmaddrs(&ifmap) != 0) err(EX_OSERR, "getifmaddrs"); xo_open_list("interface"); if (!pfunc) { if (Wflag) xo_emit("{T:/%-7.7s}", "Name"); else xo_emit("{T:/%-5.5s}", "Name"); xo_emit(" {T:/%5.5s} {T:/%-13.13s} {T:/%-17.17s} {T:/%8.8s} " "{T:/%5.5s} {T:/%5.5s}", "Mtu", "Network", "Address", "Ipkts", "Ierrs", "Idrop"); if (bflag) xo_emit(" {T:/%10.10s}","Ibytes"); xo_emit(" {T:/%8.8s} {T:/%5.5s}", "Opkts", "Oerrs"); if (bflag) xo_emit(" {T:/%10.10s}","Obytes"); xo_emit(" {T:/%5s}", "Coll"); if (dflag) xo_emit(" {T:/%s}", "Drop"); xo_emit("\n"); } for (ifa = ifap; ifa; ifa = ifa->ifa_next) { bool network = false, link = false; char *name; if (interface != NULL && strcmp(ifa->ifa_name, interface) != 0) continue; name = ifa->ifa_name; if (pfunc) { (*pfunc)(name); /* * Skip all ifaddrs belonging to same interface. */ while(ifa->ifa_next != NULL && (strcmp(ifa->ifa_next->ifa_name, name) == 0)) { ifa = ifa->ifa_next; } continue; } if (af != AF_UNSPEC && ifa->ifa_addr->sa_family != af) continue; xo_open_instance("interface"); if (Wflag) xo_emit("{tk:name/%-7.7s}", name); else xo_emit("{tk:name/%-5.5s}", name); #define IFA_MTU(ifa) (((struct if_data *)(ifa)->ifa_data)->ifi_mtu) show_stat("lu", 6, "mtu", IFA_MTU(ifa), IFA_MTU(ifa)); #undef IFA_MTU switch (ifa->ifa_addr->sa_family) { case AF_UNSPEC: xo_emit("{:network/%-13.13s} ", "none"); xo_emit("{:address/%-15.15s} ", "none"); break; case AF_INET: { struct sockaddr_in *sin, *mask; sin = (struct sockaddr_in *)ifa->ifa_addr; mask = (struct sockaddr_in *)ifa->ifa_netmask; xo_emit("{t:network/%-13.13s} ", netname(sin->sin_addr.s_addr, mask->sin_addr.s_addr)); xo_emit("{t:address/%-17.17s} ", routename(sin->sin_addr.s_addr)); network = true; break; } #ifdef INET6 case AF_INET6: { struct sockaddr_in6 *sin6, *mask; sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; mask = (struct sockaddr_in6 *)ifa->ifa_netmask; xo_emit("{t:network/%-13.13s} ", netname6(sin6, &mask->sin6_addr)); getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len, addr_buf, sizeof(addr_buf), 0, 0, NI_NUMERICHOST); xo_emit("{t:address/%-17.17s} ", addr_buf); network = 1; break; } #endif /* INET6 */ case AF_LINK: { struct sockaddr_dl *sdl; char *cp, linknum[10]; int len = 32; char buf[len]; int n, z; sdl = (struct sockaddr_dl *)ifa->ifa_addr; cp = (char *)LLADDR(sdl); n = sdl->sdl_alen; sprintf(linknum, "", sdl->sdl_index); xo_emit("{t:network/%-13.13s} ", linknum); buf[0] = '\0'; z = 0; while ((--n >= 0) && (z < len)) { snprintf(buf + z, len - z, "%02x%c", *cp++ & 0xff, n > 0 ? ':' : ' '); z += 3; } if (z > 0) xo_emit("{:address/%*s}", 32 - z, buf); else xo_emit("{P: }"); link = 1; break; } } #define IFA_STAT(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s) show_stat("lu", 8, "received-packets", IFA_STAT(ipackets), link|network); show_stat("lu", 5, "received-errors", IFA_STAT(ierrors), link); show_stat("lu", 5, "dropped-packets", IFA_STAT(iqdrops), link); if (bflag) show_stat("lu", 10, "received-bytes", IFA_STAT(ibytes), link|network); show_stat("lu", 8, "sent-packets", IFA_STAT(opackets), link|network); show_stat("lu", 5, "send-errors", IFA_STAT(oerrors), link); if (bflag) show_stat("lu", 10, "sent-bytes", IFA_STAT(obytes), link|network); show_stat("NRSlu", 5, "collisions", IFA_STAT(collisions), link); if (dflag) show_stat("LSlu", 5, "dropped-packets", IFA_STAT(oqdrops), link); xo_emit("\n"); if (!aflag) { xo_close_instance("interface"); continue; } /* * Print family's multicast addresses. */ xo_open_list("multicast-address"); for (ifma = next_ifma(ifmap, ifa->ifa_name, ifa->ifa_addr->sa_family); ifma != NULL; ifma = next_ifma(ifma, ifa->ifa_name, ifa->ifa_addr->sa_family)) { const char *fmt = NULL; xo_open_instance("multicast-address"); switch (ifma->ifma_addr->sa_family) { case AF_INET: { struct sockaddr_in *sin; sin = (struct sockaddr_in *)ifma->ifma_addr; fmt = routename(sin->sin_addr.s_addr); break; } #ifdef INET6 case AF_INET6: /* in6_fillscopeid(&msa.in6); */ getnameinfo(ifma->ifma_addr, ifma->ifma_addr->sa_len, addr_buf, sizeof(addr_buf), 0, 0, NI_NUMERICHOST); xo_emit("{P:/%*s }{t:address/%-19.19s}", Wflag ? 27 : 25, "", addr_buf); break; #endif /* INET6 */ case AF_LINK: { struct sockaddr_dl *sdl; sdl = (struct sockaddr_dl *)ifma->ifma_addr; switch (sdl->sdl_type) { case IFT_ETHER: case IFT_FDDI: fmt = ether_ntoa( (struct ether_addr *)LLADDR(sdl)); break; } break; } } if (fmt) { xo_emit("{P:/%*s }{t:address/%-17.17s/}", Wflag ? 27 : 25, "", fmt); if (ifma->ifma_addr->sa_family == AF_LINK) { xo_emit(" {:received-packets/%8lu}", IFA_STAT(imcasts)); xo_emit("{P:/%*s}", bflag? 17 : 6, ""); xo_emit(" {:sent-packets/%8lu}", IFA_STAT(omcasts)); } xo_emit("\n"); } xo_close_instance("multicast-address"); ifma = ifma->ifma_next; } xo_close_list("multicast-address"); xo_close_instance("interface"); } xo_close_list("interface"); freeifaddrs(ifap); if (aflag) freeifmaddrs(ifmap); } struct iftot { u_long ift_ip; /* input packets */ u_long ift_ie; /* input errors */ u_long ift_id; /* input drops */ u_long ift_op; /* output packets */ u_long ift_oe; /* output errors */ u_long ift_od; /* output drops */ u_long ift_co; /* collisions */ u_long ift_ib; /* input bytes */ u_long ift_ob; /* output bytes */ }; /* * Obtain stats for interface(s). */ static void fill_iftot(struct iftot *st) { struct ifaddrs *ifap, *ifa; bool found = false; if (getifaddrs(&ifap) != 0) xo_err(EX_OSERR, "getifaddrs"); bzero(st, sizeof(*st)); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; if (interface) { if (strcmp(ifa->ifa_name, interface) == 0) found = true; else continue; } st->ift_ip += IFA_STAT(ipackets); st->ift_ie += IFA_STAT(ierrors); st->ift_id += IFA_STAT(iqdrops); st->ift_ib += IFA_STAT(ibytes); st->ift_op += IFA_STAT(opackets); st->ift_oe += IFA_STAT(oerrors); st->ift_od += IFA_STAT(oqdrops); st->ift_ob += IFA_STAT(obytes); st->ift_co += IFA_STAT(collisions); } if (interface && found == false) xo_err(EX_DATAERR, "interface %s not found", interface); freeifaddrs(ifap); } /* * Set a flag to indicate that a signal from the periodic itimer has been * caught. */ static sig_atomic_t signalled; static void catchalarm(int signo __unused) { signalled = true; } /* * Print a running summary of interface statistics. * Repeat display every interval seconds, showing statistics * collected over that interval. Assumes that interval is non-zero. * First line printed at top of screen is always cumulative. */ static void sidewaysintpr(int interval) { struct iftot ift[2], *new, *old; struct itimerval interval_it; int oldmask, line; new = &ift[0]; old = &ift[1]; fill_iftot(old); (void)signal(SIGALRM, catchalarm); signalled = false; interval_it.it_interval.tv_sec = interval; interval_it.it_interval.tv_usec = 0; interval_it.it_value = interval_it.it_interval; setitimer(ITIMER_REAL, &interval_it, NULL); xo_open_list("interface-statistics"); banner: xo_emit("{T:/%17s} {T:/%14s} {T:/%16s}\n", "input", interface != NULL ? interface : "(Total)", "output"); xo_emit("{T:/%10s} {T:/%5s} {T:/%5s} {T:/%10s} {T:/%10s} {T:/%5s} " "{T:/%10s} {T:/%5s}", "packets", "errs", "idrops", "bytes", "packets", "errs", "bytes", "colls"); if (dflag) xo_emit(" {T:/%5.5s}", "drops"); xo_emit("\n"); xo_flush(); line = 0; loop: if ((noutputs != 0) && (--noutputs == 0)) { xo_close_list("interface-statistics"); return; } oldmask = sigblock(sigmask(SIGALRM)); while (!signalled) sigpause(0); signalled = false; sigsetmask(oldmask); line++; fill_iftot(new); xo_open_instance("stats"); show_stat("lu", 10, "received-packets", new->ift_ip - old->ift_ip, 1); show_stat("lu", 5, "received-errors", new->ift_ie - old->ift_ie, 1); show_stat("lu", 5, "dropped-packets", new->ift_id - old->ift_id, 1); show_stat("lu", 10, "received-bytes", new->ift_ib - old->ift_ib, 1); show_stat("lu", 10, "sent-packets", new->ift_op - old->ift_op, 1); show_stat("lu", 5, "send-errors", new->ift_oe - old->ift_oe, 1); show_stat("lu", 10, "sent-bytes", new->ift_ob - old->ift_ob, 1); show_stat("NRSlu", 5, "collisions", new->ift_co - old->ift_co, 1); if (dflag) show_stat("LSlu", 5, "dropped-packets", new->ift_od - old->ift_od, 1); xo_close_instance("stats"); xo_emit("\n"); xo_flush(); if (new == &ift[0]) { new = &ift[1]; old = &ift[0]; } else { new = &ift[0]; old = &ift[1]; } if (line == 21) goto banner; else goto loop; /* NOTREACHED */ } diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c index 0d2006afe28b..3535f4533ae5 100644 --- a/usr.bin/netstat/inet6.c +++ b/usr.bin/netstat/inet6.c @@ -1,1395 +1,1394 @@ /* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */ /*- * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #ifdef INET6 #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" struct socket sockb; char *inet6name(struct in6_addr *); static char ntop_buf[INET6_ADDRSTRLEN]; static const char *ip6nh[] = { "hop by hop", "ICMP", "IGMP", "#3", "IP", "#5", "TCP", "#7", "#8", "#9", "#10", "#11", "#12", "#13", "#14", "#15", "#16", "UDP", "#18", "#19", "#20", "#21", "IDP", "#23", "#24", "#25", "#26", "#27", "#28", "TP", "#30", "#31", "#32", "#33", "#34", "#35", "#36", "#37", "#38", "#39", "#40", "IP6", "#42", "routing", "fragment", "#45", "#46", "#47", "#48", "#49", "ESP", "AH", "#52", "#53", "#54", "#55", "#56", "#57", "ICMP6", "no next header", "destination option", "#61", "mobility", "#63", "#64", "#65", "#66", "#67", "#68", "#69", "#70", "#71", "#72", "#73", "#74", "#75", "#76", "#77", "#78", "#79", "ISOIP", "#81", "#82", "#83", "#84", "#85", "#86", "#87", "#88", "OSPF", "#80", "#91", "#92", "#93", "#94", "#95", "#96", "Ethernet", "#98", "#99", "#100", "#101", "#102", "PIM", "#104", "#105", "#106", "#107", "#108", "#109", "#110", "#111", "#112", "#113", "#114", "#115", "#116", "#117", "#118", "#119", "#120", "#121", "#122", "#123", "#124", "#125", "#126", "#127", "#128", "#129", "#130", "#131", "#132", "#133", "#134", "#135", "#136", "#137", "#138", "#139", "#140", "#141", "#142", "#143", "#144", "#145", "#146", "#147", "#148", "#149", "#150", "#151", "#152", "#153", "#154", "#155", "#156", "#157", "#158", "#159", "#160", "#161", "#162", "#163", "#164", "#165", "#166", "#167", "#168", "#169", "#170", "#171", "#172", "#173", "#174", "#175", "#176", "#177", "#178", "#179", "#180", "#181", "#182", "#183", "#184", "#185", "#186", "#187", "#188", "#189", "#180", "#191", "#192", "#193", "#194", "#195", "#196", "#197", "#198", "#199", "#200", "#201", "#202", "#203", "#204", "#205", "#206", "#207", "#208", "#209", "#210", "#211", "#212", "#213", "#214", "#215", "#216", "#217", "#218", "#219", "#220", "#221", "#222", "#223", "#224", "#225", "#226", "#227", "#228", "#229", "#230", "#231", "#232", "#233", "#234", "#235", "#236", "#237", "#238", "#239", "#240", "#241", "#242", "#243", "#244", "#245", "#246", "#247", "#248", "#249", "#250", "#251", "#252", "#253", "#254", "#255", }; static const char *srcrule_str[] = { "first candidate", "same address", "appropriate scope", "deprecated address", "home address", "outgoing interface", "matching label", "public/temporary address", "alive interface", "better virtual status", "preferred source", "rule #11", "rule #12", "rule #13", "longest match", "rule #15", }; /* * Dump IP6 statistics structure. */ void ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ip6stat ip6stat, zerostat; int first, i; size_t len; len = sizeof ip6stat; if (live) { memset(&ip6stat, 0, len); if (zflag) memset(&zerostat, 0, len); if (sysctlbyname("net.inet6.ip6.stats", &ip6stat, &len, zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { if (errno != ENOENT) xo_warn("sysctl: net.inet6.ip6.stats"); return; } } else kread_counters(off, &ip6stat, len); xo_open_container(name); xo_emit("{T:/%s}:\n", name); #define p(f, m) if (ip6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)ip6stat.f, plural(ip6stat.f)) #define p1a(f, m) if (ip6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)ip6stat.f) p(ip6s_total, "\t{:received-packets/%ju} " "{N:/total packet%s received}\n"); p1a(ip6s_toosmall, "\t{:dropped-below-minimum-size/%ju} " "{N:/with size smaller than minimum}\n"); p1a(ip6s_tooshort, "\t{:dropped-short-packets/%ju} " "{N:/with data size < data length}\n"); p1a(ip6s_badoptions, "\t{:dropped-bad-options/%ju} " "{N:/with bad options}\n"); p1a(ip6s_badvers, "\t{:dropped-bad-version/%ju} " "{N:/with incorrect version number}\n"); p(ip6s_fragments, "\t{:received-fragments/%ju} " "{N:/fragment%s received}\n"); p(ip6s_fragdropped, "\t{:dropped-fragment/%ju} " "{N:/fragment%s dropped (dup or out of space)}\n"); p(ip6s_fragtimeout, "\t{:dropped-fragment-after-timeout/%ju} " "{N:/fragment%s dropped after timeout}\n"); p(ip6s_fragoverflow, "\t{:dropped-fragments-overflow/%ju} " "{N:/fragment%s that exceeded limit}\n"); p(ip6s_reassembled, "\t{:reassembled-packets/%ju} " "{N:/packet%s reassembled ok}\n"); p(ip6s_delivered, "\t{:received-local-packets/%ju} " "{N:/packet%s for this host}\n"); p(ip6s_forward, "\t{:forwarded-packets/%ju} " "{N:/packet%s forwarded}\n"); p(ip6s_cantforward, "\t{:packets-not-forwardable/%ju} " "{N:/packet%s not forwardable}\n"); p(ip6s_redirectsent, "\t{:sent-redirects/%ju} " "{N:/redirect%s sent}\n"); p(ip6s_localout, "\t{:sent-packets/%ju} " "{N:/packet%s sent from this host}\n"); p(ip6s_rawout, "\t{:send-packets-fabricated-header/%ju} " "{N:/packet%s sent with fabricated ip header}\n"); p(ip6s_odropped, "\t{:discard-no-mbufs/%ju} " "{N:/output packet%s dropped due to no bufs, etc.}\n"); p(ip6s_noroute, "\t{:discard-no-route/%ju} " "{N:/output packet%s discarded due to no route}\n"); p(ip6s_fragmented, "\t{:sent-fragments/%ju} " "{N:/output datagram%s fragmented}\n"); p(ip6s_ofragments, "\t{:fragments-created/%ju} " "{N:/fragment%s created}\n"); p(ip6s_cantfrag, "\t{:discard-cannot-fragment/%ju} " "{N:/datagram%s that can't be fragmented}\n"); p(ip6s_badscope, "\t{:discard-scope-violations/%ju} " "{N:/packet%s that violated scope rules}\n"); p(ip6s_notmember, "\t{:multicast-no-join-packets/%ju} " "{N:/multicast packet%s which we don't join}\n"); for (first = 1, i = 0; i < IP6S_HDRCNT; i++) if (ip6stat.ip6s_nxthist[i] != 0) { if (first) { xo_emit("\t{T:Input histogram}:\n"); xo_open_list("input-histogram"); first = 0; } xo_open_instance("input-histogram"); xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", ip6nh[i], (uintmax_t)ip6stat.ip6s_nxthist[i]); xo_close_instance("input-histogram"); } if (!first) xo_close_list("input-histogram"); xo_open_container("mbuf-statistics"); xo_emit("\t{T:Mbuf statistics}:\n"); xo_emit("\t\t{:one-mbuf/%ju} {N:/one mbuf}\n", (uintmax_t)ip6stat.ip6s_m1); for (first = 1, i = 0; i < IP6S_M2MMAX; i++) { char ifbuf[IFNAMSIZ]; if (ip6stat.ip6s_m2m[i] != 0) { if (first) { xo_emit("\t\t{N:two or more mbuf}:\n"); xo_open_list("mbuf-data"); first = 0; } xo_open_instance("mbuf-data"); xo_emit("\t\t\t{k:name/%s}= {:count/%ju}\n", if_indextoname(i, ifbuf), (uintmax_t)ip6stat.ip6s_m2m[i]); xo_close_instance("mbuf-data"); } } if (!first) xo_close_list("mbuf-data"); xo_emit("\t\t{:one-extra-mbuf/%ju} {N:one ext mbuf}\n", (uintmax_t)ip6stat.ip6s_mext1); xo_emit("\t\t{:two-or-more-extra-mbufs/%ju} " "{N:/two or more ext mbuf}\n", (uintmax_t)ip6stat.ip6s_mext2m); xo_close_container("mbuf-statistics"); p(ip6s_exthdrtoolong, "\t{:dropped-header-too-long/%ju} " "{N:/packet%s whose headers are not contiguous}\n"); p(ip6s_nogif, "\t{:discard-tunnel-no-gif/%ju} " "{N:/tunneling packet%s that can't find gif}\n"); p(ip6s_toomanyhdr, "\t{:dropped-too-many-headers/%ju} " "{N:/packet%s discarded because of too many headers}\n"); /* for debugging source address selection */ #define PRINT_SCOPESTAT(s,i) do {\ switch(i) { /* XXX hardcoding in each case */\ case 1:\ p(s, "\t\t{ke:name/interface-locals}{:count/%ju} " \ "{N:/interface-local%s}\n"); \ break;\ case 2:\ p(s,"\t\t{ke:name/link-locals}{:count/%ju} " \ "{N:/link-local%s}\n"); \ break;\ case 5:\ p(s,"\t\t{ke:name/site-locals}{:count/%ju} " \ "{N:/site-local%s}\n");\ break;\ case 14:\ p(s,"\t\t{ke:name/globals}{:count/%ju} " \ "{N:/global%s}\n");\ break;\ default:\ xo_emit("\t\t{qke:name/%x}{:count/%ju} " \ "addresses scope=%x\n",\ i, (uintmax_t)ip6stat.s, i); \ }\ } while (0); xo_open_container("source-address-selection"); p(ip6s_sources_none, "\t{:address-selection-failures/%ju} " "{N:/failure%s of source address selection}\n"); for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { if (ip6stat.ip6s_sources_sameif[i]) { if (first) { xo_open_list("outgoing-interface"); xo_emit("\tsource addresses on an outgoing " "I/F\n"); first = 0; } xo_open_instance("outgoing-interface"); PRINT_SCOPESTAT(ip6s_sources_sameif[i], i); xo_close_instance("outgoing-interface"); } } if (!first) xo_close_list("outgoing-interface"); for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { if (ip6stat.ip6s_sources_otherif[i]) { if (first) { xo_open_list("non-outgoing-interface"); xo_emit("\tsource addresses on a non-outgoing " "I/F\n"); first = 0; } xo_open_instance("non-outgoing-interface"); PRINT_SCOPESTAT(ip6s_sources_otherif[i], i); xo_close_instance("non-outgoing-interface"); } } if (!first) xo_close_list("non-outgoing-interface"); for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { if (ip6stat.ip6s_sources_samescope[i]) { if (first) { xo_open_list("same-source"); xo_emit("\tsource addresses of same scope\n"); first = 0; } xo_open_instance("same-source"); PRINT_SCOPESTAT(ip6s_sources_samescope[i], i); xo_close_instance("same-source"); } } if (!first) xo_close_list("same-source"); for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { if (ip6stat.ip6s_sources_otherscope[i]) { if (first) { xo_open_list("different-scope"); xo_emit("\tsource addresses of a different " "scope\n"); first = 0; } xo_open_instance("different-scope"); PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i); xo_close_instance("different-scope"); } } if (!first) xo_close_list("different-scope"); for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { if (ip6stat.ip6s_sources_deprecated[i]) { if (first) { xo_open_list("deprecated-source"); xo_emit("\tdeprecated source addresses\n"); first = 0; } xo_open_instance("deprecated-source"); PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i); xo_close_instance("deprecated-source"); } } if (!first) xo_close_list("deprecated-source"); for (first = 1, i = 0; i < IP6S_RULESMAX; i++) { if (ip6stat.ip6s_sources_rule[i]) { if (first) { xo_open_list("rules-applied"); xo_emit("\t{T:Source addresses selection " "rule applied}:\n"); first = 0; } xo_open_instance("rules-applied"); xo_emit("\t\t{ke:name/%s}{:count/%ju} {d:name/%s}\n", srcrule_str[i], (uintmax_t)ip6stat.ip6s_sources_rule[i], srcrule_str[i]); xo_close_instance("rules-applied"); } } if (!first) xo_close_list("rules-applied"); xo_close_container("source-address-selection"); #undef p #undef p1a xo_close_container(name); } /* * Dump IPv6 per-interface statistics based on RFC 2465. */ void ip6_ifstats(char *ifname) { struct in6_ifreq ifr; int s; #define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f, \ plural(ifr.ifr_ifru.ifru_stat.f)) if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { xo_warn("Warning: socket(AF_INET6)"); return; } strcpy(ifr.ifr_name, ifname); if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) { if (errno != EPFNOSUPPORT) xo_warn("Warning: ioctl(SIOCGIFSTAT_IN6)"); goto end; } xo_emit("{T:/ip6 on %s}:\n", ifr.ifr_name); xo_open_instance("ip6-interface-statistics"); xo_emit("{ke:name/%s}", ifr.ifr_name); p(ifs6_in_receive, "\t{:received-packets/%ju} " "{N:/total input datagram%s}\n"); p(ifs6_in_hdrerr, "\t{:dropped-invalid-header/%ju} " "{N:/datagram%s with invalid header received}\n"); p(ifs6_in_toobig, "\t{:dropped-mtu-exceeded/%ju} " "{N:/datagram%s exceeded MTU received}\n"); p(ifs6_in_noroute, "\t{:dropped-no-route/%ju} " "{N:/datagram%s with no route received}\n"); p(ifs6_in_addrerr, "\t{:dropped-invalid-destination/%ju} " "{N:/datagram%s with invalid dst received}\n"); p(ifs6_in_protounknown, "\t{:dropped-unknown-protocol/%ju} " "{N:/datagram%s with unknown proto received}\n"); p(ifs6_in_truncated, "\t{:dropped-truncated/%ju} " "{N:/truncated datagram%s received}\n"); p(ifs6_in_discard, "\t{:dropped-discarded/%ju} " "{N:/input datagram%s discarded}\n"); p(ifs6_in_deliver, "\t{:received-valid-packets/%ju} " "{N:/datagram%s delivered to an upper layer protocol}\n"); p(ifs6_out_forward, "\t{:sent-forwarded/%ju} " "{N:/datagram%s forwarded to this interface}\n"); p(ifs6_out_request, "\t{:sent-packets/%ju} " "{N:/datagram%s sent from an upper layer protocol}\n"); p(ifs6_out_discard, "\t{:discard-packets/%ju} " "{N:/total discarded output datagram%s}\n"); p(ifs6_out_fragok, "\t{:discard-fragments/%ju} " "{N:/output datagram%s fragmented}\n"); p(ifs6_out_fragfail, "\t{:fragments-failed/%ju} " "{N:/output datagram%s failed on fragment}\n"); p(ifs6_out_fragcreat, "\t{:fragments-created/%ju} " "{N:/output datagram%s succeeded on fragment}\n"); p(ifs6_reass_reqd, "\t{:reassembly-required/%ju} " "{N:/incoming datagram%s fragmented}\n"); p(ifs6_reass_ok, "\t{:reassembled-packets/%ju} " "{N:/datagram%s reassembled}\n"); p(ifs6_reass_fail, "\t{:reassembly-failed/%ju} " "{N:/datagram%s failed on reassembly}\n"); p(ifs6_in_mcast, "\t{:received-multicast/%ju} " "{N:/multicast datagram%s received}\n"); p(ifs6_out_mcast, "\t{:sent-multicast/%ju} " "{N:/multicast datagram%s sent}\n"); end: xo_close_instance("ip6-interface-statistics"); close(s); #undef p } static const char *icmp6names[] = { "#0", "unreach", "packet too big", "time exceed", "parameter problem", "#5", "#6", "#7", "#8", "#9", "#10", "#11", "#12", "#13", "#14", "#15", "#16", "#17", "#18", "#19", "#20", "#21", "#22", "#23", "#24", "#25", "#26", "#27", "#28", "#29", "#30", "#31", "#32", "#33", "#34", "#35", "#36", "#37", "#38", "#39", "#40", "#41", "#42", "#43", "#44", "#45", "#46", "#47", "#48", "#49", "#50", "#51", "#52", "#53", "#54", "#55", "#56", "#57", "#58", "#59", "#60", "#61", "#62", "#63", "#64", "#65", "#66", "#67", "#68", "#69", "#70", "#71", "#72", "#73", "#74", "#75", "#76", "#77", "#78", "#79", "#80", "#81", "#82", "#83", "#84", "#85", "#86", "#87", "#88", "#89", "#80", "#91", "#92", "#93", "#94", "#95", "#96", "#97", "#98", "#99", "#100", "#101", "#102", "#103", "#104", "#105", "#106", "#107", "#108", "#109", "#110", "#111", "#112", "#113", "#114", "#115", "#116", "#117", "#118", "#119", "#120", "#121", "#122", "#123", "#124", "#125", "#126", "#127", "echo", "echo reply", "multicast listener query", "MLDv1 listener report", "MLDv1 listener done", "router solicitation", "router advertisement", "neighbor solicitation", "neighbor advertisement", "redirect", "router renumbering", "node information request", "node information reply", "inverse neighbor solicitation", "inverse neighbor advertisement", "MLDv2 listener report", "#144", "#145", "#146", "#147", "#148", "#149", "#150", "#151", "#152", "#153", "#154", "#155", "#156", "#157", "#158", "#159", "#160", "#161", "#162", "#163", "#164", "#165", "#166", "#167", "#168", "#169", "#170", "#171", "#172", "#173", "#174", "#175", "#176", "#177", "#178", "#179", "#180", "#181", "#182", "#183", "#184", "#185", "#186", "#187", "#188", "#189", "#180", "#191", "#192", "#193", "#194", "#195", "#196", "#197", "#198", "#199", "#200", "#201", "#202", "#203", "#204", "#205", "#206", "#207", "#208", "#209", "#210", "#211", "#212", "#213", "#214", "#215", "#216", "#217", "#218", "#219", "#220", "#221", "#222", "#223", "#224", "#225", "#226", "#227", "#228", "#229", "#230", "#231", "#232", "#233", "#234", "#235", "#236", "#237", "#238", "#239", "#240", "#241", "#242", "#243", "#244", "#245", "#246", "#247", "#248", "#249", "#250", "#251", "#252", "#253", "#254", "#255", }; /* * Dump ICMP6 statistics. */ void icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct icmp6stat icmp6stat, zerostat; int i, first; size_t len; len = sizeof icmp6stat; if (live) { memset(&icmp6stat, 0, len); if (zflag) memset(&zerostat, 0, len); if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len, zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { if (errno != ENOENT) xo_warn("sysctl: net.inet6.icmp6.stats"); return; } } else kread_counters(off, &icmp6stat, len); xo_emit("{T:/%s}:\n", name); xo_open_container(name); #define p(f, m) if (icmp6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f)) #define p_5(f, m) if (icmp6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)icmp6stat.f) p(icp6s_error, "\t{:icmp6-calls/%ju} " "{N:/call%s to icmp6_error}\n"); p(icp6s_canterror, "\t{:errors-not-generated-from-message/%ju} " "{N:/error%s not generated in response to an icmp6 message}\n"); p(icp6s_toofreq, "\t{:errors-discarded-by-rate-limitation/%ju} " "{N:/error%s not generated because of rate limitation}\n"); #define NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0])) for (first = 1, i = 0; i < NELEM; i++) if (icmp6stat.icp6s_outhist[i] != 0) { if (first) { xo_open_list("output-histogram"); xo_emit("\t{T:Output histogram}:\n"); first = 0; } xo_open_instance("output-histogram"); xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", icmp6names[i], (uintmax_t)icmp6stat.icp6s_outhist[i]); xo_close_instance("output-histogram"); } if (!first) xo_close_list("output-histogram"); #undef NELEM p(icp6s_badcode, "\t{:dropped-bad-code/%ju} " "{N:/message%s with bad code fields}\n"); p(icp6s_tooshort, "\t{:dropped-too-short/%ju} " "{N:/message%s < minimum length}\n"); p(icp6s_checksum, "\t{:dropped-bad-checksum/%ju} " "{N:/bad checksum%s}\n"); p(icp6s_badlen, "\t{:dropped-bad-length/%ju} " "{N:/message%s with bad length}\n"); #define NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0])) for (first = 1, i = 0; i < NELEM; i++) if (icmp6stat.icp6s_inhist[i] != 0) { if (first) { xo_open_list("input-histogram"); xo_emit("\t{T:Input histogram}:\n"); first = 0; } xo_open_instance("input-histogram"); xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", icmp6names[i], (uintmax_t)icmp6stat.icp6s_inhist[i]); xo_close_instance("input-histogram"); } if (!first) xo_close_list("input-histogram"); #undef NELEM xo_emit("\t{T:Histogram of error messages to be generated}:\n"); xo_open_container("errors"); p_5(icp6s_odst_unreach_noroute, "\t\t{:no-route/%ju} " "{N:/no route}\n"); p_5(icp6s_odst_unreach_admin, "\t\t{:admin-prohibited/%ju} " "{N:/administratively prohibited}\n"); p_5(icp6s_odst_unreach_beyondscope, "\t\t{:beyond-scope/%ju} " "{N:/beyond scope}\n"); p_5(icp6s_odst_unreach_addr, "\t\t{:address-unreachable/%ju} " "{N:/address unreachable}\n"); p_5(icp6s_odst_unreach_noport, "\t\t{:port-unreachable/%ju} " "{N:/port unreachable}\n"); p_5(icp6s_opacket_too_big, "\t\t{:packet-too-big/%ju} " "{N:/packet too big}\n"); p_5(icp6s_otime_exceed_transit, "\t\t{:time-exceed-transmit/%ju} " "{N:/time exceed transit}\n"); p_5(icp6s_otime_exceed_reassembly, "\t\t{:time-exceed-reassembly/%ju} " "{N:/time exceed reassembly}\n"); p_5(icp6s_oparamprob_header, "\t\t{:bad-header/%ju} " "{N:/erroneous header field}\n"); p_5(icp6s_oparamprob_nextheader, "\t\t{:bad-next-header/%ju} " "{N:/unrecognized next header}\n"); p_5(icp6s_oparamprob_option, "\t\t{:bad-option/%ju} " "{N:/unrecognized option}\n"); p_5(icp6s_oredirect, "\t\t{:redirects/%ju} " "{N:/redirect}\n"); p_5(icp6s_ounknown, "\t\t{:unknown/%ju} {N:unknown}\n"); p(icp6s_reflect, "\t{:reflect/%ju} " "{N:/message response%s generated}\n"); p(icp6s_nd_toomanyopt, "\t{:too-many-nd-options/%ju} " "{N:/message%s with too many ND options}\n"); p(icp6s_nd_badopt, "\t{:bad-nd-options/%ju} " "{N:/message%s with bad ND options}\n"); p(icp6s_badns, "\t{:bad-neighbor-solicitation/%ju} " "{N:/bad neighbor solicitation message%s}\n"); p(icp6s_badna, "\t{:bad-neighbor-advertisement/%ju} " "{N:/bad neighbor advertisement message%s}\n"); p(icp6s_badrs, "\t{:bad-router-solicitation/%ju} " "{N:/bad router solicitation message%s}\n"); p(icp6s_badra, "\t{:bad-router-advertisement/%ju} " "{N:/bad router advertisement message%s}\n"); p(icp6s_badredirect, "\t{:bad-redirect/%ju} " "{N:/bad redirect message%s}\n"); xo_close_container("errors"); p(icp6s_pmtuchg, "\t{:path-mtu-changes/%ju} {N:/path MTU change%s}\n"); #undef p #undef p_5 xo_close_container(name); } /* * Dump ICMPv6 per-interface statistics based on RFC 2466. */ void icmp6_ifstats(char *ifname) { struct in6_ifreq ifr; int s; #define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, \ plural(ifr.ifr_ifru.ifru_icmp6stat.f)) #define p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, \ pluralies(ifr.ifr_ifru.ifru_icmp6stat.f)) if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { xo_warn("Warning: socket(AF_INET6)"); return; } strcpy(ifr.ifr_name, ifname); if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) { if (errno != EPFNOSUPPORT) xo_warn("Warning: ioctl(SIOCGIFSTAT_ICMP6)"); goto end; } xo_emit("{T:/icmp6 on %s}:\n", ifr.ifr_name); xo_open_instance("icmp6-interface-statistics"); xo_emit("{ke:name/%s}", ifr.ifr_name); p(ifs6_in_msg, "\t{:received-packets/%ju} " "{N:/total input message%s}\n"); p(ifs6_in_error, "\t{:received-errors/%ju} " "{N:/total input error message%s}\n"); p(ifs6_in_dstunreach, "\t{:received-destination-unreachable/%ju} " "{N:/input destination unreachable error%s}\n"); p(ifs6_in_adminprohib, "\t{:received-admin-prohibited/%ju} " "{N:/input administratively prohibited error%s}\n"); p(ifs6_in_timeexceed, "\t{:received-time-exceeded/%ju} " "{N:/input time exceeded error%s}\n"); p(ifs6_in_paramprob, "\t{:received-bad-parameter/%ju} " "{N:/input parameter problem error%s}\n"); p(ifs6_in_pkttoobig, "\t{:received-packet-too-big/%ju} " "{N:/input packet too big error%s}\n"); p(ifs6_in_echo, "\t{:received-echo-requests/%ju} " "{N:/input echo request%s}\n"); p2(ifs6_in_echoreply, "\t{:received-echo-replies/%ju} " "{N:/input echo repl%s}\n"); p(ifs6_in_routersolicit, "\t{:received-router-solicitation/%ju} " "{N:/input router solicitation%s}\n"); p(ifs6_in_routeradvert, "\t{:received-router-advertisement/%ju} " "{N:/input router advertisement%s}\n"); p(ifs6_in_neighborsolicit, "\t{:received-neighbor-solicitation/%ju} " "{N:/input neighbor solicitation%s}\n"); p(ifs6_in_neighboradvert, "\t{:received-neighbor-advertisement/%ju} " "{N:/input neighbor advertisement%s}\n"); p(ifs6_in_redirect, "\t{received-redirects/%ju} " "{N:/input redirect%s}\n"); p2(ifs6_in_mldquery, "\t{:received-mld-queries/%ju} " "{N:/input MLD quer%s}\n"); p(ifs6_in_mldreport, "\t{:received-mld-reports/%ju} " "{N:/input MLD report%s}\n"); p(ifs6_in_mlddone, "\t{:received-mld-done/%ju} " "{N:/input MLD done%s}\n"); p(ifs6_out_msg, "\t{:sent-packets/%ju} " "{N:/total output message%s}\n"); p(ifs6_out_error, "\t{:sent-errors/%ju} " "{N:/total output error message%s}\n"); p(ifs6_out_dstunreach, "\t{:sent-destination-unreachable/%ju} " "{N:/output destination unreachable error%s}\n"); p(ifs6_out_adminprohib, "\t{:sent-admin-prohibited/%ju} " "{N:/output administratively prohibited error%s}\n"); p(ifs6_out_timeexceed, "\t{:sent-time-exceeded/%ju} " "{N:/output time exceeded error%s}\n"); p(ifs6_out_paramprob, "\t{:sent-bad-parameter/%ju} " "{N:/output parameter problem error%s}\n"); p(ifs6_out_pkttoobig, "\t{:sent-packet-too-big/%ju} " "{N:/output packet too big error%s}\n"); p(ifs6_out_echo, "\t{:sent-echo-requests/%ju} " "{N:/output echo request%s}\n"); p2(ifs6_out_echoreply, "\t{:sent-echo-replies/%ju} " "{N:/output echo repl%s}\n"); p(ifs6_out_routersolicit, "\t{:sent-router-solicitation/%ju} " "{N:/output router solicitation%s}\n"); p(ifs6_out_routeradvert, "\t{:sent-router-advertisement/%ju} " "{N:/output router advertisement%s}\n"); p(ifs6_out_neighborsolicit, "\t{:sent-neighbor-solicitation/%ju} " "{N:/output neighbor solicitation%s}\n"); p(ifs6_out_neighboradvert, "\t{:sent-neighbor-advertisement/%ju} " "{N:/output neighbor advertisement%s}\n"); p(ifs6_out_redirect, "\t{:sent-redirects/%ju} " "{N:/output redirect%s}\n"); p2(ifs6_out_mldquery, "\t{:sent-mld-queries/%ju} " "{N:/output MLD quer%s}\n"); p(ifs6_out_mldreport, "\t{:sent-mld-reports/%ju} " "{N:/output MLD report%s}\n"); p(ifs6_out_mlddone, "\t{:sent-mld-dones/%ju} " "{N:/output MLD done%s}\n"); end: xo_close_instance("icmp6-interface-statistics"); close(s); #undef p } /* * Dump PIM statistics structure. */ void pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct pim6stat pim6stat, zerostat; size_t len = sizeof pim6stat; if (live) { if (zflag) memset(&zerostat, 0, len); if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len, zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { if (errno != ENOENT) xo_warn("sysctl: net.inet6.pim.stats"); return; } } else { if (off == 0) return; kread(off, &pim6stat, len); } xo_emit("{T:/%s}:\n", name); xo_open_container(name); #define p(f, m) if (pim6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)pim6stat.f, plural(pim6stat.f)) p(pim6s_rcv_total, "\t{:received-packets/%ju} " "{N:/message%s received}\n"); p(pim6s_rcv_tooshort, "\t{:dropped-too-short/%ju} " "{N:/message%s received with too few bytes}\n"); p(pim6s_rcv_badsum, "\t{:dropped-bad-checksum/%ju} " "{N:/message%s received with bad checksum}\n"); p(pim6s_rcv_badversion, "\t{:dropped-bad-version/%ju} " "{N:/message%s received with bad version}\n"); p(pim6s_rcv_registers, "\t{:received-registers/%ju} " "{N:/register%s received}\n"); p(pim6s_rcv_badregisters, "\t{:received-bad-registers/%ju} " "{N:/bad register%s received}\n"); p(pim6s_snd_registers, "\t{:sent-registers/%ju} " "{N:/register%s sent}\n"); #undef p xo_close_container(name); } /* * Dump raw ip6 statistics structure. */ void rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct rip6stat rip6stat, zerostat; u_quad_t delivered; size_t len; len = sizeof(rip6stat); if (live) { if (zflag) memset(&zerostat, 0, len); if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len, zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { if (errno != ENOENT) xo_warn("sysctl: net.inet6.ip6.rip6stats"); return; } } else kread_counters(off, &rip6stat, len); xo_emit("{T:/%s}:\n", name); xo_open_container(name); #define p(f, m) if (rip6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)rip6stat.f, plural(rip6stat.f)) p(rip6s_ipackets, "\t{:received-packets/%ju} " "{N:/message%s received}\n"); p(rip6s_isum, "\t{:input-checksum-computation/%ju} " "{N:/checksum calculation%s on inbound}\n"); p(rip6s_badsum, "\t{:received-bad-checksum/%ju} " "{N:/message%s with bad checksum}\n"); p(rip6s_nosock, "\t{:dropped-no-socket/%ju} " "{N:/message%s dropped due to no socket}\n"); p(rip6s_nosockmcast, "\t{:dropped-multicast-no-socket/%ju} " "{N:/multicast message%s dropped due to no socket}\n"); p(rip6s_fullsock, "\t{:dropped-full-socket-buffer/%ju} " "{N:/message%s dropped due to full socket buffers}\n"); delivered = rip6stat.rip6s_ipackets - rip6stat.rip6s_badsum - rip6stat.rip6s_nosock - rip6stat.rip6s_nosockmcast - rip6stat.rip6s_fullsock; if (delivered || sflag <= 1) xo_emit("\t{:delivered-packets/%ju} {N:/delivered}\n", (uintmax_t)delivered); p(rip6s_opackets, "\t{:sent-packets/%ju} " "{N:/datagram%s output}\n"); #undef p xo_close_container(name); } /* * Pretty print an Internet address (net address + port). * Take numeric_addr and numeric_port into consideration. */ #define GETSERVBYPORT6(port, proto, ret)\ {\ if (strcmp((proto), "tcp6") == 0)\ (ret) = getservbyport((int)(port), "tcp");\ else if (strcmp((proto), "udp6") == 0)\ (ret) = getservbyport((int)(port), "udp");\ else\ (ret) = getservbyport((int)(port), (proto));\ }; void inet6print(const char *container, struct in6_addr *in6, int port, const char *proto, int numeric) { struct servent *sp = 0; char line[80], *cp; int width; if (container) xo_open_container(container); sprintf(line, "%.*s.", Wflag ? 39 : (Aflag && !numeric) ? 12 : 16, inet6name(in6)); cp = strchr(line, '\0'); if (!numeric && port) GETSERVBYPORT6(port, proto, sp); if (sp || port == 0) sprintf(cp, "%.15s", sp ? sp->s_name : "*"); else sprintf(cp, "%d", ntohs((u_short)port)); width = Wflag ? 45 : Aflag ? 18 : 22; xo_emit("{d:target/%-*.*s} ", width, width, line); int alen = cp - line - 1, plen = strlen(cp) - 1; xo_emit("{e:address/%*.*s}{e:port/%*.*s}", alen, alen, line, plen, plen, cp); if (container) xo_close_container(container); } /* * Construct an Internet address representation. * If the numeric_addr has been supplied, give * numeric value, otherwise try for symbolic name. */ char * inet6name(struct in6_addr *in6p) { struct sockaddr_in6 sin6; char hbuf[NI_MAXHOST], *cp; static char line[50]; static char domain[MAXHOSTNAMELEN]; static int first = 1; int flags, error; if (IN6_IS_ADDR_UNSPECIFIED(in6p)) { strcpy(line, "*"); return (line); } if (first && !numeric_addr) { first = 0; if (gethostname(domain, MAXHOSTNAMELEN) == 0 && (cp = strchr(domain, '.'))) (void) strcpy(domain, cp + 1); else domain[0] = 0; } memset(&sin6, 0, sizeof(sin6)); memcpy(&sin6.sin6_addr, in6p, sizeof(*in6p)); sin6.sin6_family = AF_INET6; /* XXX: in6p.s6_addr[2] can contain scopeid. */ in6_fillscopeid(&sin6); flags = (numeric_addr) ? NI_NUMERICHOST : 0; error = getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), hbuf, sizeof(hbuf), NULL, 0, flags); if (error == 0) { if ((flags & NI_NUMERICHOST) == 0 && (cp = strchr(hbuf, '.')) && !strcmp(cp + 1, domain)) *cp = 0; strcpy(line, hbuf); } else { /* XXX: this should not happen. */ sprintf(line, "%s", inet_ntop(AF_INET6, (void *)&sin6.sin6_addr, ntop_buf, sizeof(ntop_buf))); } return (line); } #endif /*INET6*/ diff --git a/usr.sbin/amd/include/config.h b/usr.sbin/amd/include/config.h index 5817a460a8fb..cffb82ad71f3 100644 --- a/usr.sbin/amd/include/config.h +++ b/usr.sbin/amd/include/config.h @@ -1,2205 +1,2202 @@ /* * $FreeBSD$ * * portions derived from * $NetBSD: config.h,v 1.11 1998/08/08 22:33:37 christos Exp $ */ #ifndef _CONFIG_H #define _CONFIG_H /* We [FREEBSD-NATIVE] pick some parameters from our local config file */ #include "config_local.h" /* define name of am-utils' NFS protocol header */ #define AMU_NFS_PROTOCOL_HEADER "./conf/nfs_prot/nfs_prot_freebsd3.h" /* Type of the 5rd argument to authunix_create() */ #define AUTH_CREATE_GIDLIST_TYPE gid_t /* Define configuration date */ /* #define CONFIG_DATE "Tue Dec 4 21:39:00 PST 2007" */ /* Turn off general debugging by default */ /* #undef DEBUG */ /* Turn off memory debugging by default */ /* #undef DEBUG_MEM */ /* Define name of host OS's distribution name (eg. debian, redhat, suse, etc.) */ #define DISTRO_NAME "The FreeBSD Project" /* Define to the type of elements in the array set by `getgroups'. Usually this is either `int' or `gid_t'. */ #define GETGROUPS_T gid_t /* Define to 1 if the `getpgrp' function requires zero arguments. */ #define GETPGRP_VOID 1 /* Define if have automount filesystem */ #define HAVE_AMU_FS_AUTO 1 /* Define if have direct automount filesystem */ #define HAVE_AMU_FS_DIRECT 1 /* Define if have error filesystem */ #define HAVE_AMU_FS_ERROR 1 /* Define if have NFS host-tree filesystem */ #define HAVE_AMU_FS_HOST 1 /* Define if have symbolic-link filesystem */ #define HAVE_AMU_FS_LINK 1 /* Define if have symlink with existence check filesystem */ #define HAVE_AMU_FS_LINKX 1 /* Define if have nfsl (NFS with local link check) filesystem */ #define HAVE_AMU_FS_NFSL 1 /* Define if have multi-NFS filesystem */ #define HAVE_AMU_FS_NFSX 1 /* Define if have program filesystem */ #define HAVE_AMU_FS_PROGRAM 1 /* Define if have "top-level" filesystem */ #define HAVE_AMU_FS_TOPLVL 1 /* Define if have union filesystem */ #define HAVE_AMU_FS_UNION 1 /* Define to 1 if you have the header file. */ #define HAVE_ARPA_INET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ARPA_NAMESER_H 1 /* Define to 1 if you have the header file. */ #define HAVE_ASSERT_H 1 /* Define to 1 if `addr' is member of `autofs_args_t'. */ /* #undef HAVE_AUTOFS_ARGS_T_ADDR */ /* define if have a bad version of hasmntopt() */ /* #undef HAVE_BAD_HASMNTOPT */ /* define if have a bad version of memcmp() */ /* #undef HAVE_BAD_MEMCMP */ /* define if have a bad version of yp_all() */ /* #undef HAVE_BAD_YP_ALL */ /* Define to 1 if you have the `bcmp' function. */ #define HAVE_BCMP 1 /* Define to 1 if you have the `bcopy' function. */ #define HAVE_BCOPY 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_BSD_RPC_RPC_H */ /* Define to 1 if you have the `bzero' function. */ #define HAVE_BZERO 1 /* System supports C99-style variable-length argument macros */ #define HAVE_C99_VARARGS_MACROS 1 /* Define to 1 if `flags' is member of `cdfs_args_t'. */ #define HAVE_CDFS_ARGS_T_FLAGS 1 /* Define to 1 if `fspec' is member of `cdfs_args_t'. */ #define HAVE_CDFS_ARGS_T_FSPEC 1 /* Define to 1 if `iso_flags' is member of `cdfs_args_t'. */ /* #undef HAVE_CDFS_ARGS_T_ISO_FLAGS */ /* Define to 1 if `iso_pgthresh' is member of `cdfs_args_t'. */ /* #undef HAVE_CDFS_ARGS_T_ISO_PGTHRESH */ /* Define to 1 if `norrip' is member of `cdfs_args_t'. */ /* #undef HAVE_CDFS_ARGS_T_NORRIP */ /* Define to 1 if `ssector' is member of `cdfs_args_t'. */ #define HAVE_CDFS_ARGS_T_SSECTOR 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_CDFS_CDFSMOUNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_CDFS_CDFS_MOUNT_H */ /* Define to 1 if you have the `clnt_create' function. */ #define HAVE_CLNT_CREATE 1 /* Define to 1 if you have the `clnt_create_vers' function. */ #define HAVE_CLNT_CREATE_VERS 1 /* Define to 1 if you have the `clnt_create_vers_timed' function. */ #define HAVE_CLNT_CREATE_VERS_TIMED 1 /* Define to 1 if you have the `clnt_spcreateerror' function. */ #define HAVE_CLNT_SPCREATEERROR 1 /* Define to 1 if you have the `clnt_sperrno' function. */ #define HAVE_CLNT_SPERRNO 1 /* Define to 1 if you have the `clock_gettime' function. */ #define HAVE_CLOCK_GETTIME 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_CLUSTER_H */ /* Define to 1 if you have the `cnodeid' function. */ /* #undef HAVE_CNODEID */ /* Define to 1 if you have the header file. */ #define HAVE_CTYPE_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_DB1_NDBM_H */ /* Define to 1 if you have the `dbm_open' function. */ #define HAVE_DBM_OPEN 1 /* Define to 1 if you have the `dg_mount' function. */ /* #undef HAVE_DG_MOUNT */ /* Define to 1 if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if `flags' is member of `efs_args_t'. */ /* #undef HAVE_EFS_ARGS_T_FLAGS */ /* Define to 1 if `fspec' is member of `efs_args_t'. */ /* #undef HAVE_EFS_ARGS_T_FSPEC */ /* Define to 1 if you have the header file. */ #define HAVE_ERRNO_H 1 /* does extern definition for clnt_spcreateerror() exist? */ #define HAVE_EXTERN_CLNT_SPCREATEERROR 1 /* does extern definition for clnt_sperrno() exist? */ #define HAVE_EXTERN_CLNT_SPERRNO 1 /* does extern definition for free() exist? */ #define HAVE_EXTERN_FREE 1 /* does extern definition for getccent() (hpux) exist? */ /* #undef HAVE_EXTERN_GETCCENT */ /* does extern definition for getdomainname() exist? */ #define HAVE_EXTERN_GETDOMAINNAME 1 /* does extern definition for getdtablesize() exist? */ #define HAVE_EXTERN_GETDTABLESIZE 1 /* does extern definition for gethostname() exist? */ #define HAVE_EXTERN_GETHOSTNAME 1 /* does extern definition for getlogin() exist? */ #define HAVE_EXTERN_GETLOGIN 1 /* does extern definition for getpagesize() exist? */ #define HAVE_EXTERN_GETPAGESIZE 1 /* does extern definition for gettablesize() exist? */ /* #undef HAVE_EXTERN_GETTABLESIZE */ /* does extern definition for getwd() exist? */ #define HAVE_EXTERN_GETWD 1 /* does extern definition for get_myaddress() exist? */ #define HAVE_EXTERN_GET_MYADDRESS 1 /* does extern definition for hosts_ctl() exist? */ /* #undef HAVE_EXTERN_HOSTS_CTL */ /* does extern definition for innetgr() exist? */ #define HAVE_EXTERN_INNETGR 1 /* does extern definition for ldap_enable_cache() exist? */ /* #undef HAVE_EXTERN_LDAP_ENABLE_CACHE */ /* does extern definition for mkstemp() exist? */ #define HAVE_EXTERN_MKSTEMP 1 /* does extern definition for mntctl() exist? */ /* #undef HAVE_EXTERN_MNTCTL */ /* does extern definition for optarg exist? */ #define HAVE_EXTERN_OPTARG 1 /* does extern definition for sbrk() exist? */ #define HAVE_EXTERN_SBRK 1 /* does extern definition for seteuid() exist? */ #define HAVE_EXTERN_SETEUID 1 /* does extern definition for setitimer() exist? */ #define HAVE_EXTERN_SETITIMER 1 /* does extern definition for sleep() exist? */ #define HAVE_EXTERN_SLEEP 1 /* does extern definition for strcasecmp() exist? */ #define HAVE_EXTERN_STRCASECMP 1 /* does extern definition for strdup() exist? */ #define HAVE_EXTERN_STRDUP 1 /* does extern definition for strlcat() exist? */ #define HAVE_EXTERN_STRLCAT 1 /* does extern definition for strlcpy() exist? */ #define HAVE_EXTERN_STRLCPY 1 /* does extern definition for strstr() exist? */ #define HAVE_EXTERN_STRSTR 1 /* does extern definition for sys_errlist[] exist? */ #define HAVE_EXTERN_SYS_ERRLIST 1 /* does extern definition for ualarm() exist? */ #define HAVE_EXTERN_UALARM 1 /* does extern definition for usleep() exist? */ #define HAVE_EXTERN_USLEEP 1 /* does extern definition for vsnprintf() exist? */ #define HAVE_EXTERN_VSNPRINTF 1 /* does extern definition for wait3() exist? */ #define HAVE_EXTERN_WAIT3 1 /* does extern definition for xdr_callmsg() exist? */ #define HAVE_EXTERN_XDR_CALLMSG 1 /* does extern definition for xdr_opaque_auth() exist? */ #define HAVE_EXTERN_XDR_OPAQUE_AUTH 1 /* Define to 1 if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define to 1 if `fds_bits' is member of `fd_set'. */ #define HAVE_FD_SET_FDS_BITS 1 /* Define to 1 if you have the `fgets' function. */ #define HAVE_FGETS 1 /* Define if plain fhandle type exists */ #define HAVE_FHANDLE 1 /* Define to 1 if you have the `flock' function. */ #define HAVE_FLOCK 1 /* Define to 1 if you have the `fork' function. */ #define HAVE_FORK 1 /* Define to 1 if you have the `fsmount' function. */ /* #undef HAVE_FSMOUNT */ /* Define if have AUTOFS filesystem */ /* #undef HAVE_FS_AUTOFS */ /* Define if have CACHEFS filesystem */ /* #undef HAVE_FS_CACHEFS */ /* Define if have CDFS filesystem */ #define HAVE_FS_CDFS 1 /* Define if have CFS (crypto) filesystem */ /* #undef HAVE_FS_CFS */ /* Define if have EFS filesystem (irix) */ /* #undef HAVE_FS_EFS */ /* Define if have FFS filesystem */ /* #undef HAVE_FS_FFS */ /* Define if have HSFS filesystem */ /* #undef HAVE_FS_HSFS */ /* Define if have LOFS filesystem */ /* #undef HAVE_FS_LOFS */ /* Define if have MFS filesystem */ /* #undef HAVE_FS_MFS */ /* Define if have NFS filesystem */ #define HAVE_FS_NFS 1 /* Define if have NFS3 filesystem */ #define HAVE_FS_NFS3 1 /* Define if have NULLFS (loopback on bsd44) filesystem */ #define HAVE_FS_NULLFS 1 /* Define if have PCFS filesystem */ #define HAVE_FS_PCFS 1 /* Define if have TFS filesystem */ /* #undef HAVE_FS_TFS */ /* Define if have TMPFS filesystem */ /* #undef HAVE_FS_TMPFS */ /* Define if have UFS filesystem */ #define HAVE_FS_UFS 1 /* Define if have UMAPFS (uid/gid mapping) filesystem */ /* #undef HAVE_FS_UMAPFS */ /* Define if have UNIONFS filesystem */ #define HAVE_FS_UNIONFS 1 /* Define if have XFS filesystem (irix) */ /* #undef HAVE_FS_XFS */ /* System supports GCC-style variable-length argument macros */ /* #undef HAVE_GCC_VARARGS_MACROS */ /* Define to 1 if you have the header file. */ /* #undef HAVE_GDBM_NDBM_H */ /* Define to 1 if you have the `getccent' function. */ /* #undef HAVE_GETCCENT */ /* Define to 1 if you have the `getcwd' function. */ #define HAVE_GETCWD 1 /* Define to 1 if you have the `getdomainname' function. */ #define HAVE_GETDOMAINNAME 1 /* Define to 1 if you have the `getdtablesize' function. */ #define HAVE_GETDTABLESIZE 1 /* Define to 1 if you have the `gethostname' function. */ #define HAVE_GETHOSTNAME 1 /* Define to 1 if you have the `getifaddrs' function. */ #define HAVE_GETIFADDRS 1 /* Define to 1 if you have the `getmntinfo' function. */ #define HAVE_GETMNTINFO 1 /* Define to 1 if you have the `getmountent' function. */ /* #undef HAVE_GETMOUNTENT */ /* Define to 1 if you have the `getpagesize' function. */ #define HAVE_GETPAGESIZE 1 /* Define to 1 if you have the `getpwnam' function. */ #define HAVE_GETPWNAM 1 /* Define to 1 if you have the `gettimeofday' function. */ #define HAVE_GETTIMEOFDAY 1 /* Define to 1 if you have the `get_myaddress' function. */ #define HAVE_GET_MYADDRESS 1 /* define if your system's getopt() is GNU getopt() (are you using glibc) */ /* #undef HAVE_GNU_GETOPT */ /* Define to 1 if you have the header file. */ #define HAVE_GRP_H 1 /* Define to 1 if you have the `hasmntopt' function. */ /* #undef HAVE_HASMNTOPT */ #ifdef YES_HESIOD /* Define to 1 if you have the header file. */ #define HAVE_HESIOD_H 1 /* Define to 1 if you have the `hesiod_init' function. */ #define HAVE_HESIOD_INIT 1 /* Define to 1 if you have the `hesiod_reload' function. */ /* #undef HAVE_HESIOD_RELOAD */ /* Define to 1 if you have the `hesiod_to_bind' function. */ #define HAVE_HESIOD_TO_BIND 1 /* Define to 1 if you have the `hes_init' function. */ #define HAVE_HES_INIT 1 #else #undef HAVE_HESIOD_H #undef HAVE_HESIOD_INIT #undef HAVE_HESIOD_RELOAD #undef HAVE_HESIOD_TO_BIND #undef HAVE_HES_INIT #endif /* Define to 1 if you have the header file. */ /* #undef HAVE_HSFS_HSFS_H */ /* Define to 1 if you have the `hstrerror' function. */ #define HAVE_HSTRERROR 1 /* Define to 1 if you have the header file. */ #define HAVE_IFADDRS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_IRS_H */ /* Define to 1 if you have the header file. */ #define HAVE_ISOFS_CD9660_CD9660_MOUNT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_LBER_H */ /* Define to 1 if you have the `ldap_enable_cache' function. */ /* #undef HAVE_LDAP_ENABLE_CACHE */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LDAP_H */ /* Define to 1 if you have the `ldap_open' function. */ /* #undef HAVE_LDAP_OPEN */ /* Define to 1 if you have the header file. */ #define HAVE_LIBGEN_H 1 /* Define to 1 if you have the `malloc' library (-lmalloc). */ /* #undef HAVE_LIBMALLOC */ /* Define to 1 if you have the `mapmalloc' library (-lmapmalloc). */ /* #undef HAVE_LIBMAPMALLOC */ /* Define to 1 if you have the `nsl' library (-lnsl). */ /* #undef HAVE_LIBNSL */ /* Define to 1 if you have the `posix4' library (-lposix4). */ /* #undef HAVE_LIBPOSIX4 */ /* Define to 1 if you have the `resolv' library (-lresolv). */ /* #undef HAVE_LIBRESOLV */ /* Define to 1 if you have the `rpc' library (-lrpc). */ /* #undef HAVE_LIBRPC */ /* Define to 1 if you have the `rpcsvc' library (-lrpcsvc). */ #define HAVE_LIBRPCSVC 1 /* Define to 1 if you have the `rt' library (-lrt). */ /* #undef HAVE_LIBRT */ /* does libwrap exist? */ #define HAVE_LIBWRAP 1 /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_AUTO_FS4_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_AUTO_FS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_FS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_KDEV_T_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_LIST_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_LOOP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_NFS2_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_NFS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_NFS_MOUNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_POSIX_TYPES_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LINUX_SOCKET_H */ /* Define to 1 if you support file names longer than 14 characters. */ #define HAVE_LONG_FILE_NAMES 1 /* Define to 1 if you have the header file. */ #define HAVE_MACHINE_ENDIAN_H 1 /* Define to 1 if you have the `madvise' function. */ #define HAVE_MADVISE 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MALLOC_H */ /* Define if have DBM maps */ /* #undef HAVE_MAP_DBM */ /* Define if have executable maps */ #define HAVE_MAP_EXEC 1 /* Define if have file maps (everyone should have it!) */ #define HAVE_MAP_FILE 1 #ifdef YES_HESIOD /* Define if have HESIOD maps */ #define HAVE_MAP_HESIOD 1 #else #undef HAVE_MAP_HESIOD #endif /* Define if have LDAP maps */ /* #undef HAVE_MAP_LDAP */ /* Define if have NDBM maps */ #define HAVE_MAP_NDBM 1 /* Define if have NIS maps */ #define HAVE_MAP_NIS 1 /* Define if have NIS+ maps */ /* #undef HAVE_MAP_NISPLUS */ /* Define if have PASSWD maps */ #define HAVE_MAP_PASSWD 1 /* Define if have UNION maps */ #define HAVE_MAP_UNION 1 /* Define to 1 if you have the `memcmp' function. */ #define HAVE_MEMCMP 1 /* Define to 1 if you have the `memcpy' function. */ #define HAVE_MEMCPY 1 /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `memset' function. */ #define HAVE_MEMSET 1 /* Define to 1 if you have the `mkdir' function. */ #define HAVE_MKDIR 1 /* Define to 1 if you have the `mkstemp' function. */ #define HAVE_MKSTEMP 1 /* Define to 1 if you have the `mlockall' function. */ #define HAVE_MLOCKALL 1 /* Define to 1 if you have the `mntctl' function. */ /* #undef HAVE_MNTCTL */ /* Define to 1 if you have the header file. */ /* #undef HAVE_MNTENT_H */ /* Define to 1 if `mnt_cnode' is member of `mntent_t'. */ /* #undef HAVE_MNTENT_T_MNT_CNODE */ /* Define to 1 if `mnt_ro' is member of `mntent_t'. */ /* #undef HAVE_MNTENT_T_MNT_RO */ /* Define to 1 if `mnt_time' is member of `mntent_t'. */ /* #undef HAVE_MNTENT_T_MNT_TIME */ /* does mntent_t have mnt_time field and is of type "char *" ? */ /* #undef HAVE_MNTENT_T_MNT_TIME_STRING */ /* Define to 1 if you have the header file. */ /* #undef HAVE_MNTTAB_H */ /* Define to 1 if you have the `mount' function. */ #define HAVE_MOUNT 1 /* Define to 1 if `optptr' is member of `mounta'. */ /* #undef HAVE_MOUNTA_OPTPTR */ /* Define to 1 if you have the `mountsyscall' function. */ /* #undef HAVE_MOUNTSYSCALL */ /* Define to 1 if you have the header file. */ /* #undef HAVE_MOUNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_MSDOSFS_MSDOSFSMOUNT_H */ /* Define to 1 if you have the header file. */ #define HAVE_FS_MSDOSFS_MSDOSFSMOUNT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NDBM_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_NETCONFIG_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETDIR_H */ /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IF_ETHER_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NET_ERRNO_H */ /* Define to 1 if you have the header file. */ #define HAVE_NET_IF_H 1 -/* Define to 1 if you have the header file. */ -#define HAVE_NET_IF_VAR_H 1 - /* Define to 1 if you have the header file. */ #define HAVE_NET_ROUTE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NFSCLIENT_NFSARGS_H 1 /* Define to 1 if `acdirmax' is member of `nfs_args_t'. */ #define HAVE_NFS_ARGS_T_ACDIRMAX 1 /* Define to 1 if `acdirmin' is member of `nfs_args_t'. */ #define HAVE_NFS_ARGS_T_ACDIRMIN 1 /* Define to 1 if `acregmax' is member of `nfs_args_t'. */ #define HAVE_NFS_ARGS_T_ACREGMAX 1 /* Define to 1 if `acregmin' is member of `nfs_args_t'. */ #define HAVE_NFS_ARGS_T_ACREGMIN 1 /* Define to 1 if `addrlen' is member of `nfs_args_t'. */ #define HAVE_NFS_ARGS_T_ADDRLEN 1 /* Define to 1 if `bsize' is member of `nfs_args_t'. */ /* #undef HAVE_NFS_ARGS_T_BSIZE */ /* Define to 1 if `fhsize' is member of `nfs_args_t'. */ #define HAVE_NFS_ARGS_T_FHSIZE 1 /* Define to 1 if `fh_len' is member of `nfs_args_t'. */ /* #undef HAVE_NFS_ARGS_T_FH_LEN */ /* Define to 1 if `gfs_flags' is member of `nfs_args_t'. */ /* #undef HAVE_NFS_ARGS_T_GFS_FLAGS */ /* Define to 1 if `namlen' is member of `nfs_args_t'. */ /* #undef HAVE_NFS_ARGS_T_NAMLEN */ /* Define to 1 if `optstr' is member of `nfs_args_t'. */ /* #undef HAVE_NFS_ARGS_T_OPTSTR */ /* Define to 1 if `proto' is member of `nfs_args_t'. */ #define HAVE_NFS_ARGS_T_PROTO 1 /* Define to 1 if `sotype' is member of `nfs_args_t'. */ #define HAVE_NFS_ARGS_T_SOTYPE 1 /* Define to 1 if `version' is member of `nfs_args_t'. */ #define HAVE_NFS_ARGS_T_VERSION 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NFS_EXPORT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NFS_MOUNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NFS_NFSMOUNT_H */ /* Define to 1 if you have the header file. */ #define HAVE_NFS_NFSPROTO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NFS_NFSV2_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NFS_NFS_CLNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NFS_NFS_GFS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NFS_NFS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NFS_NFS_MOUNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NFS_PATHCONF_H */ /* define if the host has NFS protocol headers in system headers */ /* #undef HAVE_NFS_PROT_HEADERS */ /* Define to 1 if you have the header file. */ /* #define HAVE_NFS_RPCV2_H 1 */ /* Define to 1 if you have the `nis_domain_of' function. */ /* #undef HAVE_NIS_DOMAIN_OF */ /* Define to 1 if you have the header file. */ #define HAVE_NSSWITCH_H 1 /* Define to 1 if you have the `opendir' function. */ #define HAVE_OPENDIR 1 /* Define to 1 if `dsttime' is member of `pcfs_args_t'. */ /* #undef HAVE_PCFS_ARGS_T_DSTTIME */ /* Define to 1 if `fspec' is member of `pcfs_args_t'. */ #define HAVE_PCFS_ARGS_T_FSPEC 1 /* Define to 1 if `gid' is member of `pcfs_args_t'. */ #define HAVE_PCFS_ARGS_T_GID 1 /* Define to 1 if `mask' is member of `pcfs_args_t'. */ #define HAVE_PCFS_ARGS_T_MASK 1 /* Define to 1 if `dirmask' is member of `pcfs_args_t'. */ #define HAVE_PCFS_ARGS_T_DIRMASK 1 /* Define to 1 if `secondswest' is member of `pcfs_args_t'. */ /* #undef HAVE_PCFS_ARGS_T_SECONDSWEST */ /* Define to 1 if `uid' is member of `pcfs_args_t'. */ #define HAVE_PCFS_ARGS_T_UID 1 /* Define to 1 if you have the `plock' function. */ /* #undef HAVE_PLOCK */ /* Define to 1 if you have the header file. */ #define HAVE_PWD_H 1 /* Define to 1 if you have the `regcomp' function. */ #define HAVE_REGCOMP 1 /* Define to 1 if you have the `regexec' function. */ #define HAVE_REGEXEC 1 /* Define to 1 if you have the header file. */ #define HAVE_REGEX_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RESOLV_H 1 /* Define to 1 if system calls automatically restart after interruption by a signal. */ #define HAVE_RESTARTABLE_SYSCALLS 1 /* Define to 1 if you have the `rmdir' function. */ #define HAVE_RMDIR 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_RPCSVC_AUTOFS_PROT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_RPCSVC_MOUNTV3_H */ /* Define to 1 if you have the header file. */ #define HAVE_RPCSVC_MOUNT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RPCSVC_NFS_PROT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RPCSVC_NIS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RPCSVC_YPCLNT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RPCSVC_YP_PROT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RPC_AUTH_DES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RPC_PMAP_CLNT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RPC_PMAP_PROT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RPC_RPC_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RPC_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_RPC_XDR_H 1 /* Define to 1 if you have the `select' function. */ #define HAVE_SELECT 1 /* Define to 1 if you have the `seteuid' function. */ #define HAVE_SETEUID 1 /* Define to 1 if you have the `setitimer' function. */ #define HAVE_SETITIMER 1 /* Define to 1 if you have the header file. */ #define HAVE_SETJMP_H 1 /* Define to 1 if you have the `setresuid' function. */ #define HAVE_SETRESUID 1 /* Define to 1 if you have the `setsid' function. */ #define HAVE_SETSID 1 /* Define to 1 if you have the `sigaction' function. */ #define HAVE_SIGACTION 1 /* Define to 1 if you have the `signal' function. */ #define HAVE_SIGNAL 1 /* Define to 1 if you have the header file. */ #define HAVE_SIGNAL_H 1 /* Define to 1 if you have the `sigsuspend' function. */ #define HAVE_SIGSUSPEND 1 /* Define to 1 if you have the `socket' function. */ #define HAVE_SOCKET 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SOCKETBITS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_STATBUF_H */ /* Define to 1 if you have the `statfs' function. */ #define HAVE_STATFS 1 /* Define to 1 if you have the `statvfs' function. */ #define HAVE_STATVFS 1 /* Define to 1 if you have the header file. */ #define HAVE_STDARG_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the `strcasecmp' function. */ #define HAVE_STRCASECMP 1 /* Define to 1 if you have the `strchr' function. */ #define HAVE_STRCHR 1 /* Define to 1 if you have the `strcspn' function. */ #define HAVE_STRCSPN 1 /* Define to 1 if you have the `strdup' function. */ #define HAVE_STRDUP 1 /* Define to 1 if you have the `strerror' function. */ #define HAVE_STRERROR 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the `strlcat' function. */ #define HAVE_STRLCAT 1 /* Define to 1 if you have the `strlcpy' function. */ #define HAVE_STRLCPY 1 /* Define to 1 if you have the `strspn' function. */ #define HAVE_STRSPN 1 /* Define to 1 if you have the `strstr' function. */ #define HAVE_STRSTR 1 /* Define to 1 if `fhs_fh' is member of `struct fhstatus'. */ /* #undef HAVE_STRUCT_FHSTATUS_FHS_FH */ /* Define to 1 if `ifa_next' is member of `struct ifaddrs'. */ #define HAVE_STRUCT_IFADDRS_IFA_NEXT 1 /* Define to 1 if `ifr_addr' is member of `struct ifreq'. */ #define HAVE_STRUCT_IFREQ_IFR_ADDR 1 /* Define if have struct mntent in one of the standard headers */ /* #undef HAVE_STRUCT_MNTENT */ /* Define if have struct mnttab in one of the standard headers */ /* #undef HAVE_STRUCT_MNTTAB */ /* Define if have struct nfs_args in one of the standard nfs headers */ #define HAVE_STRUCT_NFS_ARGS 1 /* Define if have struct nfs_gfs_mount in one of the standard nfs headers */ /* #undef HAVE_STRUCT_NFS_GFS_MOUNT */ /* Define to 1 if `sa_len' is member of `struct sockaddr'. */ #define HAVE_STRUCT_SOCKADDR_SA_LEN 1 /* Define to 1 if `f_fstypename' is member of `struct statfs'. */ #define HAVE_STRUCT_STATFS_F_FSTYPENAME 1 /* Define to 1 if `devid' is member of `struct umntrequest'. */ /* #undef HAVE_STRUCT_UMNTREQUEST_DEVID */ /* Define to 1 if you have the `svc_getreq' function. */ #define HAVE_SVC_GETREQ 1 /* Define to 1 if you have the `svc_getreqset' function. */ #define HAVE_SVC_GETREQSET 1 /* Define to 1 if you have the `sysfs' function. */ /* #undef HAVE_SYSFS */ /* Define to 1 if you have the `syslog' function. */ #define HAVE_SYSLOG 1 /* Define to 1 if you have the header file. */ #define HAVE_SYSLOG_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_CONFIG_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_DG_MOUNT_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_DIR_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_ERRNO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_FILE_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FSID_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FSTYP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_AUTOFS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_AUTOFS_PROT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_CACHEFS_FS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_EFS_CLNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_NFS_CLNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_NFS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_NFS_MOUNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_NFS_NFS_CLNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_PC_FS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_TMP_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_TYPES_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_UFS_MOUNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_FS_XFS_CLNT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_IMMU_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_IOCTL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_LOCK_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_MACHINE_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_MBUF_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_MMAN_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_MNTCTL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_MNTENT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_MNTTAB_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_MOUNT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_NETCONFIG_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PARAM_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_PATHCONF_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_PROC_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SEMA_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SIGNAL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKIO_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_STATFS_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_STATVFS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SYSCALL_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SYSLIMITS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SYSLOG_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_TIUSER_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UCRED_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_UTSNAME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_VFS_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_VMOUNT_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_VNODE_H 1 /* Define to 1 if you have that is POSIX.1 compatible. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_TCPD_H 1 /* Define to 1 if you have the header file. */ #define HAVE_TIME_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_TIUSER_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_TMPFS_TMP_H */ /* what type of network transport type is in use? TLI or sockets? */ /* #undef HAVE_TRANSPORT_TYPE_TLI */ /* Define to 1 if you have the `ualarm' function. */ #define HAVE_UALARM 1 /* Define to 1 if `flags' is member of `ufs_args_t'. */ /* #undef HAVE_UFS_ARGS_T_FLAGS */ /* Define to 1 if `fspec' is member of `ufs_args_t'. */ #define HAVE_UFS_ARGS_T_FSPEC 1 /* Define to 1 if `ufs_flags' is member of `ufs_args_t'. */ /* #undef HAVE_UFS_ARGS_T_UFS_FLAGS */ /* Define to 1 if `ufs_pgthresh' is member of `ufs_args_t'. */ /* #undef HAVE_UFS_ARGS_T_UFS_PGTHRESH */ /* Define to 1 if you have the header file. */ #define HAVE_UFS_UFS_EXTATTR_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_UFS_UFS_MOUNT_H */ /* Define to 1 if you have the header file. */ #define HAVE_UFS_UFS_UFSMOUNT_H 1 /* Define to 1 if you have the `umount' function. */ /* #undef HAVE_UMOUNT */ /* Define to 1 if you have the `umount2' function. */ /* #undef HAVE_UMOUNT2 */ /* Define to 1 if you have the `uname' function. */ #define HAVE_UNAME 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the `unmount' function. */ #define HAVE_UNMOUNT 1 /* Define to 1 if you have the `uvmount' function. */ /* #undef HAVE_UVMOUNT */ /* Define to 1 if you have the header file. */ /* #undef HAVE_VARARGS_H */ /* Define to 1 if you have the `vfork' function. */ #define HAVE_VFORK 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_VFORK_H */ /* Define to 1 if you have the `vfsmount' function. */ /* #undef HAVE_VFSMOUNT */ /* Define to 1 if you have the `vmount' function. */ /* #undef HAVE_VMOUNT */ /* Define to 1 if you have the `vsnprintf' function. */ #define HAVE_VSNPRINTF 1 /* Define to 1 if you have the `wait3' function. */ #define HAVE_WAIT3 1 /* Define to 1 if you have the `waitpid' function. */ #define HAVE_WAITPID 1 /* Define to 1 if `fork' works. */ #define HAVE_WORKING_FORK 1 /* Define to 1 if `vfork' works. */ #define HAVE_WORKING_VFORK 1 /* Define to 1 if you have the `xdr_attrstat' function. */ #define HAVE_XDR_ATTRSTAT 1 /* Define to 1 if you have the `xdr_createargs' function. */ #define HAVE_XDR_CREATEARGS 1 /* Define to 1 if you have the `xdr_dirlist' function. */ #define HAVE_XDR_DIRLIST 1 /* Define to 1 if you have the `xdr_diropargs' function. */ #define HAVE_XDR_DIROPARGS 1 /* Define to 1 if you have the `xdr_diropokres' function. */ #define HAVE_XDR_DIROPOKRES 1 /* Define to 1 if you have the `xdr_diropres' function. */ #define HAVE_XDR_DIROPRES 1 /* Define to 1 if you have the `xdr_dirpath' function. */ #define HAVE_XDR_DIRPATH 1 /* Define to 1 if you have the `xdr_entry' function. */ #define HAVE_XDR_ENTRY 1 /* Define to 1 if you have the `xdr_exportnode' function. */ #define HAVE_XDR_EXPORTNODE 1 /* Define to 1 if you have the `xdr_exports' function. */ #define HAVE_XDR_EXPORTS 1 /* Define to 1 if you have the `xdr_fattr' function. */ #define HAVE_XDR_FATTR 1 /* Define to 1 if you have the `xdr_fhandle' function. */ #define HAVE_XDR_FHANDLE 1 /* Define to 1 if you have the `xdr_fhstatus' function. */ #define HAVE_XDR_FHSTATUS 1 /* Define to 1 if you have the `xdr_filename' function. */ #define HAVE_XDR_FILENAME 1 /* Define to 1 if you have the `xdr_ftype' function. */ #define HAVE_XDR_FTYPE 1 /* Define to 1 if you have the `xdr_groupnode' function. */ #define HAVE_XDR_GROUPNODE 1 /* Define to 1 if you have the `xdr_groups' function. */ #define HAVE_XDR_GROUPS 1 /* Define to 1 if you have the `xdr_linkargs' function. */ #define HAVE_XDR_LINKARGS 1 /* Define to 1 if you have the `xdr_mountbody' function. */ #define HAVE_XDR_MOUNTBODY 1 /* Define to 1 if you have the `xdr_mountlist' function. */ #define HAVE_XDR_MOUNTLIST 1 /* Define to 1 if you have the `xdr_name' function. */ #define HAVE_XDR_NAME 1 /* Define to 1 if you have the `xdr_nfscookie' function. */ #define HAVE_XDR_NFSCOOKIE 1 /* Define to 1 if you have the `xdr_nfspath' function. */ #define HAVE_XDR_NFSPATH 1 /* Define to 1 if you have the `xdr_nfsstat' function. */ #define HAVE_XDR_NFSSTAT 1 /* Define to 1 if you have the `xdr_nfstime' function. */ #define HAVE_XDR_NFSTIME 1 /* Define to 1 if you have the `xdr_nfs_fh' function. */ #define HAVE_XDR_NFS_FH 1 /* Define to 1 if you have the `xdr_pointer' function. */ #define HAVE_XDR_POINTER 1 /* Define to 1 if you have the `xdr_readargs' function. */ #define HAVE_XDR_READARGS 1 /* Define to 1 if you have the `xdr_readdirargs' function. */ #define HAVE_XDR_READDIRARGS 1 /* Define to 1 if you have the `xdr_readdirres' function. */ #define HAVE_XDR_READDIRRES 1 /* Define to 1 if you have the `xdr_readlinkres' function. */ #define HAVE_XDR_READLINKRES 1 /* Define to 1 if you have the `xdr_readokres' function. */ #define HAVE_XDR_READOKRES 1 /* Define to 1 if you have the `xdr_readres' function. */ #define HAVE_XDR_READRES 1 /* Define to 1 if you have the `xdr_renameargs' function. */ #define HAVE_XDR_RENAMEARGS 1 /* Define to 1 if you have the `xdr_sattr' function. */ #define HAVE_XDR_SATTR 1 /* Define to 1 if you have the `xdr_sattrargs' function. */ #define HAVE_XDR_SATTRARGS 1 /* Define to 1 if you have the `xdr_statfsokres' function. */ #define HAVE_XDR_STATFSOKRES 1 /* Define to 1 if you have the `xdr_statfsres' function. */ #define HAVE_XDR_STATFSRES 1 /* Define to 1 if you have the `xdr_symlinkargs' function. */ #define HAVE_XDR_SYMLINKARGS 1 /* Define to 1 if you have the `xdr_writeargs' function. */ #define HAVE_XDR_WRITEARGS 1 /* Define to 1 if `flags' is member of `xfs_args_t'. */ /* #undef HAVE_XFS_ARGS_T_FLAGS */ /* Define to 1 if `fspec' is member of `xfs_args_t'. */ /* #undef HAVE_XFS_ARGS_T_FSPEC */ /* Define to 1 if you have the `yp_all' function. */ /* #undef HAVE_YP_ALL */ /* Define to 1 if you have the `yp_get_default_domain' function. */ #define HAVE_YP_GET_DEFAULT_DOMAIN 1 /* Define to 1 if you have the `_seterr_reply' function. */ #define HAVE__SETERR_REPLY 1 /* Define to 1 if you have the `__rpc_get_local_uid' function. */ #define HAVE___RPC_GET_LOCAL_UID 1 /* Define to 1 if you have the `__seterr_reply' function. */ /* #undef HAVE___SETERR_REPLY */ /* Name of mount type to hide amd mount from df(1) */ #define HIDE_MOUNT_TYPE "nfs" /* Define name of host machine's architecture (eg. sun4) */ /* #define HOST_ARCH "i386" */ /* Define name of host machine's cpu (eg. sparc) */ /* #define HOST_CPU "i386" */ /* Define the header version of (linux) hosts (eg. 2.2.10) */ // #undef define HOST_HEADER_VERSION */ /* Define name of host */ /* #define HOST_NAME "trang.nuxi.org" */ /* Define name and version of host machine (eg. solaris2.5.1) */ /* #define HOST_OS "freebsd8.0" */ /* Define only name of host machine OS (eg. solaris2) */ /* #define HOST_OS_NAME "freebsd8" */ /* Define only version of host machine (eg. 2.5.1) */ /* #define HOST_OS_VERSION "8.0" */ /* Define name of host machine's vendor (eg. sun) */ #define HOST_VENDOR "undermydesk" /* Ignore permission bits */ /* #undef MNT2_CDFS_OPT_DEFPERM */ /* Use on-disk permission bits */ /* #undef MNT2_CDFS_OPT_NODEFPERM */ /* Strip off extension from version string */ /* #undef MNT2_CDFS_OPT_NOVERSION */ /* Use Rock Ridge Interchange Protocol (RRIP) extensions */ /* #undef MNT2_CDFS_OPT_RRIP */ /* asynchronous filesystem access */ #define MNT2_GEN_OPT_ASYNC 0x40 /* automounter filesystem (ignore) flag, used in bsdi-4.1 */ /* #undef MNT2_GEN_OPT_AUTOMNTFS */ /* automounter filesystem flag, used in Mac OS X / Darwin */ /* #undef MNT2_GEN_OPT_AUTOMOUNTED */ /* directory hardlink */ /* #undef MNT2_GEN_OPT_BIND */ /* cache (what?) */ /* #undef MNT2_GEN_OPT_CACHE */ /* 6-argument mount */ /* #undef MNT2_GEN_OPT_DATA */ /* Use a lazy unmount (detach) */ /* #undef MNT2_GEN_OPT_DETACH */ /* Use a forced unmount */ #define MNT2_GEN_OPT_FORCE 0x80000 /* old (4-argument) mount (compatibility) */ /* #undef MNT2_GEN_OPT_FSS */ /* old BSD group-id on create */ /* #undef MNT2_GEN_OPT_GRPID */ /* ignore mount entry in df output */ #define MNT2_GEN_OPT_IGNORE 0x800000 /* journaling filesystem (AIX's UFS/FFS) */ /* #undef MNT2_GEN_OPT_JFS */ /* do multi-component lookup on files */ /* #undef MNT2_GEN_OPT_MULTI */ /* use type string instead of int */ /* #undef MNT2_GEN_OPT_NEWTYPE */ /* NFS mount */ /* #undef MNT2_GEN_OPT_NFS */ /* nocache (what?) */ /* #undef MNT2_GEN_OPT_NOCACHE */ /* do not interpret special device files */ #define MNT2_GEN_OPT_NODEV 0x0 /* no exec calls allowed */ #define MNT2_GEN_OPT_NOEXEC 0x4 /* do not interpret special device files */ /* #undef MNT2_GEN_OPT_NONDEV */ /* Disallow mounts beneath this mount */ /* #undef MNT2_GEN_OPT_NOSUB */ /* Setuid programs disallowed */ #define MNT2_GEN_OPT_NOSUID 0x8 /* Return ENAMETOOLONG for long filenames */ /* #undef MNT2_GEN_OPT_NOTRUNC */ /* Pass mount option string to kernel */ /* #undef MNT2_GEN_OPT_OPTIONSTR */ /* allow overlay mounts */ /* #undef MNT2_GEN_OPT_OVERLAY */ /* check quotas */ #define MNT2_GEN_OPT_QUOTA 0x2000 /* Read-only */ #define MNT2_GEN_OPT_RDONLY 0x1 /* change options on an existing mount */ /* #undef MNT2_GEN_OPT_REMOUNT */ /* read only */ /* #undef MNT2_GEN_OPT_RONLY */ /* synchronize data immediately to filesystem */ /* #undef MNT2_GEN_OPT_SYNC */ /* synchronous filesystem access (same as SYNC) */ #define MNT2_GEN_OPT_SYNCHRONOUS 0x2 /* Mount with Sys 5-specific semantics */ /* #undef MNT2_GEN_OPT_SYS5 */ /* Union mount */ /* #undef MNT2_GEN_OPT_UNION */ /* set max secs for dir attr cache */ #define MNT2_NFS_OPT_ACDIRMAX 0x200000 /* set min secs for dir attr cache */ #define MNT2_NFS_OPT_ACDIRMIN 0x100000 /* set max secs for file attr cache */ #define MNT2_NFS_OPT_ACREGMAX 0x80000 /* set min secs for file attr cache */ #define MNT2_NFS_OPT_ACREGMIN 0x40000 /* Authentication error */ /* #undef MNT2_NFS_OPT_AUTHERR */ /* hide mount type from df(1) */ /* #undef MNT2_NFS_OPT_AUTO */ /* set dead server retry thresh */ #define MNT2_NFS_OPT_DEADTHRESH 0x4000 /* Dismount in progress */ /* #undef MNT2_NFS_OPT_DISMINPROG */ /* Dismounted */ /* #undef MNT2_NFS_OPT_DISMNT */ /* Don't estimate rtt dynamically */ #define MNT2_NFS_OPT_DUMBTIMR 0x800 /* provide name of server's fs to system */ /* #undef MNT2_NFS_OPT_FSNAME */ /* System V-style gid inheritance */ /* #undef MNT2_NFS_OPT_GRPID */ /* Has authenticator */ /* #undef MNT2_NFS_OPT_HASAUTH */ /* set hostname for error printf */ /* #undef MNT2_NFS_OPT_HOSTNAME */ /* ignore mount point */ /* #undef MNT2_NFS_OPT_IGNORE */ /* allow interrupts on hard mount */ #define MNT2_NFS_OPT_INT 0x40 /* Bits set internally */ /* #undef MNT2_NFS_OPT_INTERNAL */ /* allow interrupts on hard mount */ /* #undef MNT2_NFS_OPT_INTR */ /* Use Kerberos authentication */ /* #undef MNT2_NFS_OPT_KERB */ /* use kerberos credentials */ /* #undef MNT2_NFS_OPT_KERBEROS */ /* transport's knetconfig structure */ /* #undef MNT2_NFS_OPT_KNCONF */ /* set lease term (nqnfs) */ /* #undef MNT2_NFS_OPT_LEASETERM */ /* Local locking (no lock manager) */ /* #undef MNT2_NFS_OPT_LLOCK */ /* set maximum grouplist size */ #define MNT2_NFS_OPT_MAXGRPS 0x20 /* Mnt server for mnt point */ /* #undef MNT2_NFS_OPT_MNTD */ /* Assume writes were mine */ /* #undef MNT2_NFS_OPT_MYWRITE */ /* mount NFS Version 3 */ #define MNT2_NFS_OPT_NFSV3 0x200 /* don't cache attributes */ /* #undef MNT2_NFS_OPT_NOAC */ /* Don't Connect the socket */ #define MNT2_NFS_OPT_NOCONN 0x80 /* no close-to-open consistency */ /* #undef MNT2_NFS_OPT_NOCTO */ /* disallow interrupts on hard mounts */ /* #undef MNT2_NFS_OPT_NOINT */ /* Don't use locking */ /* #undef MNT2_NFS_OPT_NONLM */ /* Get lease for lookup */ /* #undef MNT2_NFS_OPT_NQLOOKLEASE */ /* Use Nqnfs protocol */ /* #undef MNT2_NFS_OPT_NQNFS */ /* paging threshold */ /* #undef MNT2_NFS_OPT_PGTHRESH */ /* static pathconf kludge info */ /* #undef MNT2_NFS_OPT_POSIX */ /* Use local locking */ /* #undef MNT2_NFS_OPT_PRIVATE */ /* allow property list operations (ACLs over NFS) */ /* #undef MNT2_NFS_OPT_PROPLIST */ /* Rcv socket lock */ /* #undef MNT2_NFS_OPT_RCVLOCK */ /* Do lookup with readdir (nqnfs) */ /* #undef MNT2_NFS_OPT_RDIRALOOK */ /* Use Readdirplus for NFSv3 */ #define MNT2_NFS_OPT_RDIRPLUS 0x10000 /* set read ahead */ #define MNT2_NFS_OPT_READAHEAD 0x2000 /* Set readdir size */ #define MNT2_NFS_OPT_READDIRSIZE 0x20000 /* Allocate a reserved port */ #define MNT2_NFS_OPT_RESVPORT 0x8000 /* set number of request retries */ #define MNT2_NFS_OPT_RETRANS 0x10 /* read only */ /* #undef MNT2_NFS_OPT_RONLY */ /* use RPC to do secure NFS time sync */ /* #undef MNT2_NFS_OPT_RPCTIMESYNC */ /* set read size */ #define MNT2_NFS_OPT_RSIZE 0x4 /* secure mount */ /* #undef MNT2_NFS_OPT_SECURE */ /* Send socket lock */ /* #undef MNT2_NFS_OPT_SNDLOCK */ /* soft mount (hard is default) */ #define MNT2_NFS_OPT_SOFT 0x1 /* spongy mount */ /* #undef MNT2_NFS_OPT_SPONGY */ /* set symlink cache time-to-live */ /* #undef MNT2_NFS_OPT_SYMTTL */ /* use TCP for mounts */ /* #undef MNT2_NFS_OPT_TCP */ /* set initial timeout */ #define MNT2_NFS_OPT_TIMEO 0x8 /* linux NFSv3 */ /* #undef MNT2_NFS_OPT_VER3 */ /* Wait for authentication */ /* #undef MNT2_NFS_OPT_WAITAUTH */ /* Wants an authenticator */ /* #undef MNT2_NFS_OPT_WANTAUTH */ /* Want receive socket lock */ /* #undef MNT2_NFS_OPT_WANTRCV */ /* Want send socket lock */ /* #undef MNT2_NFS_OPT_WANTSND */ /* set write size */ #define MNT2_NFS_OPT_WSIZE 0x2 /* 32<->64 dir cookie translation */ /* #undef MNT2_NFS_OPT_XLATECOOKIE */ /* Force Win95 long names */ #define MNT2_PCFS_OPT_LONGNAME 0x2 /* Completely ignore Win95 entries */ #define MNT2_PCFS_OPT_NOWIN95 0x4 /* Force old DOS short names only */ #define MNT2_PCFS_OPT_SHORTNAME 0x1 /* Name of mount table file name */ /* #undef MNTTAB_FILE_NAME */ /* Mount Table option string: Max attr cache timeout (dirs) */ /* #undef MNTTAB_OPT_ACDIRMAX */ /* Mount Table option string: Min attr cache timeout (dirs) */ /* #undef MNTTAB_OPT_ACDIRMIN */ /* Mount Table option string: Max attr cache timeout (files) */ /* #undef MNTTAB_OPT_ACREGMAX */ /* Mount Table option string: Min attr cache timeout (files) */ /* #undef MNTTAB_OPT_ACREGMIN */ /* Mount Table option string: Attr cache timeout (sec) */ /* #undef MNTTAB_OPT_ACTIMEO */ /* Mount Table option string: Do mount retries in background */ /* #undef MNTTAB_OPT_BG */ /* Mount Table option string: compress */ /* #undef MNTTAB_OPT_COMPRESS */ /* Mount Table option string: Device id of mounted fs */ /* #undef MNTTAB_OPT_DEV */ /* Mount Table option string: Automount direct map mount */ /* #undef MNTTAB_OPT_DIRECT */ /* Mount Table option string: Do mount retries in foreground */ /* #undef MNTTAB_OPT_FG */ /* Mount Table option string: Filesystem id of mounted fs */ /* #undef MNTTAB_OPT_FSID */ /* Mount Table option string: SysV-compatible gid on create */ /* #undef MNTTAB_OPT_GRPID */ /* Mount Table option string: Hard mount */ /* #undef MNTTAB_OPT_HARD */ /* Mount Table option string: Ignore this entry */ /* #undef MNTTAB_OPT_IGNORE */ /* Mount Table option string: Automount indirect map mount */ /* #undef MNTTAB_OPT_INDIRECT */ /* Mount Table option string: Allow NFS ops to be interrupted */ /* #undef MNTTAB_OPT_INTR */ /* Mount Table option string: Secure (AUTH_Kerb) mounting */ /* #undef MNTTAB_OPT_KERB */ /* Mount Table option string: Local locking (no lock manager) */ /* #undef MNTTAB_OPT_LLOCK */ /* Force Win95 long names */ /* #undef MNTTAB_OPT_LONGNAME */ /* Mount Table option string: Automount map */ /* #undef MNTTAB_OPT_MAP */ /* Mount Table option string: max groups */ /* #undef MNTTAB_OPT_MAXGROUPS */ /* Mount Table option string: Do multi-component lookup */ /* #undef MNTTAB_OPT_MULTI */ /* Mount Table option string: Don't cache attributes at all */ /* #undef MNTTAB_OPT_NOAC */ /* Mount Table option string: No auto (what?) */ /* #undef MNTTAB_OPT_NOAUTO */ /* Mount Table option string: No connection */ /* #undef MNTTAB_OPT_NOCONN */ /* Mount Table option string: No close-to-open consistency */ /* #undef MNTTAB_OPT_NOCTO */ /* Mount Table option string: Don't allow interrupted ops */ /* #undef MNTTAB_OPT_NOINTR */ /* Mount Table option string: Don't check quotas */ /* #undef MNTTAB_OPT_NOQUOTA */ /* Mount Table option string: Do no allow setting sec attrs */ /* #undef MNTTAB_OPT_NOSETSEC */ /* Mount Table option string: Disallow mounts on subdirs */ /* #undef MNTTAB_OPT_NOSUB */ /* Mount Table option string: Set uid not allowed */ /* #undef MNTTAB_OPT_NOSUID */ /* Completely ignore Win95 entries */ /* #undef MNTTAB_OPT_NOWIN95 */ /* Mount Table option string: action to taken on error */ /* #undef MNTTAB_OPT_ONERROR */ /* Mount Table option string: paging threshold */ /* #undef MNTTAB_OPT_PGTHRESH */ /* Mount Table option string: NFS server IP port number */ /* #undef MNTTAB_OPT_PORT */ /* Mount Table option string: Get static pathconf for mount */ /* #undef MNTTAB_OPT_POSIX */ /* Mount Table option string: Use local locking */ /* #undef MNTTAB_OPT_PRIVATE */ /* Mount Table option string: support property lists (ACLs) */ /* #undef MNTTAB_OPT_PROPLIST */ /* Mount Table option string: protocol network_id indicator */ /* #undef MNTTAB_OPT_PROTO */ /* Mount Table option string: Check quotas */ /* #undef MNTTAB_OPT_QUOTA */ /* Mount Table option string: Change mount options */ /* #undef MNTTAB_OPT_REMOUNT */ /* Mount Table option string: Max retransmissions (soft mnts) */ /* #undef MNTTAB_OPT_RETRANS */ /* Mount Table option string: Number of mount retries */ /* #undef MNTTAB_OPT_RETRY */ /* Mount Table option string: Read only */ /* #undef MNTTAB_OPT_RO */ /* Mount Table option string: Read/write with quotas */ /* #undef MNTTAB_OPT_RQ */ /* Mount Table option string: Max NFS read size (bytes) */ /* #undef MNTTAB_OPT_RSIZE */ /* Mount Table option string: Read/write */ /* #undef MNTTAB_OPT_RW */ /* Mount Table option string: Secure (AUTH_DES) mounting */ /* #undef MNTTAB_OPT_SECURE */ /* Force old DOS short names only */ /* #undef MNTTAB_OPT_SHORTNAME */ /* Mount Table option string: Soft mount */ /* #undef MNTTAB_OPT_SOFT */ /* Mount Table option string: spongy mount */ /* #undef MNTTAB_OPT_SPONGY */ /* Mount Table option string: Set uid allowed */ /* #undef MNTTAB_OPT_SUID */ /* Mount Table option string: set symlink cache time-to-live */ /* #undef MNTTAB_OPT_SYMTTL */ /* Mount Table option string: Synchronous local directory ops */ /* #undef MNTTAB_OPT_SYNCDIR */ /* Mount Table option string: NFS timeout (1/10 sec) */ /* #undef MNTTAB_OPT_TIMEO */ /* Mount Table option string: min. time between inconsistencies */ /* #undef MNTTAB_OPT_TOOSOON */ /* Mount Table option string: protocol version number indicator */ /* #undef MNTTAB_OPT_VERS */ /* Mount Table option string: Max NFS write size (bytes) */ /* #undef MNTTAB_OPT_WSIZE */ /* Mount-table entry name for AUTOFS filesystem */ /* #undef MNTTAB_TYPE_AUTOFS */ /* Mount-table entry name for CACHEFS filesystem */ /* #undef MNTTAB_TYPE_CACHEFS */ /* Mount-table entry name for CDFS filesystem */ #define MNTTAB_TYPE_CDFS "cd9660" /* Mount-table entry name for CFS (crypto) filesystem */ /* #undef MNTTAB_TYPE_CFS */ /* Mount-table entry name for EFS filesystem (irix) */ /* #undef MNTTAB_TYPE_EFS */ /* Mount-table entry name for FFS filesystem */ /* #undef MNTTAB_TYPE_FFS */ /* Mount-table entry name for LOFS filesystem */ /* #undef MNTTAB_TYPE_LOFS */ /* Mount-table entry name for MFS filesystem */ /* #undef MNTTAB_TYPE_MFS */ /* Mount-table entry name for NFS filesystem */ #define MNTTAB_TYPE_NFS "nfs" /* Mount-table entry name for NFS3 filesystem */ #define MNTTAB_TYPE_NFS3 "nfs3" /* Mount-table entry name for NULLFS (loopback on bsd44) filesystem */ #define MNTTAB_TYPE_NULLFS "nullfs" /* Mount-table entry name for PCFS filesystem */ #define MNTTAB_TYPE_PCFS "msdosfs" /* Mount-table entry name for TFS filesystem */ /* #undef MNTTAB_TYPE_TFS */ /* Mount-table entry name for TMPFS filesystem */ /* #undef MNTTAB_TYPE_TMPFS */ /* Mount-table entry name for UFS filesystem */ #define MNTTAB_TYPE_UFS "ufs" /* Mount-table entry name for UMAPFS (uid/gid mapping) filesystem */ /* #undef MNTTAB_TYPE_UMAPFS */ /* Mount-table entry name for UNIONFS filesystem */ #define MNTTAB_TYPE_UNIONFS "unionfs" /* Mount-table entry name for XFS filesystem (irix) */ /* #undef MNTTAB_TYPE_XFS */ /* Define if mount table is on file, undefine if in kernel */ /* #undef MOUNT_TABLE_ON_FILE */ /* Mount(2) type/name for AUTOFS filesystem */ /* #undef MOUNT_TYPE_AUTOFS */ /* Mount(2) type/name for CACHEFS filesystem */ /* #undef MOUNT_TYPE_CACHEFS */ /* Mount(2) type/name for CDFS filesystem */ #define MOUNT_TYPE_CDFS "cd9660" /* Mount(2) type/name for CFS (crypto) filesystem */ /* #undef MOUNT_TYPE_CFS */ /* Mount(2) type/name for EFS filesystem (irix) */ /* #undef MOUNT_TYPE_EFS */ /* Mount(2) type/name for FFS filesystem */ /* #undef MOUNT_TYPE_FFS */ /* Mount(2) type/name for IGNORE filesystem (not real just ignore for df) */ #define MOUNT_TYPE_IGNORE MNT_IGNORE /* Mount(2) type/name for LOFS filesystem */ /* #undef MOUNT_TYPE_LOFS */ /* Mount(2) type/name for MFS filesystem */ /* #undef MOUNT_TYPE_MFS */ /* Mount(2) type/name for NFS filesystem */ #define MOUNT_TYPE_NFS "nfs" /* Mount(2) type/name for NFS3 filesystem */ #define MOUNT_TYPE_NFS3 MOUNT_NFS3 /* Mount(2) type/name for NULLFS (loopback on bsd44) filesystem */ #define MOUNT_TYPE_NULLFS "nullfs" /* Mount(2) type/name for PCFS filesystem. XXX: conf/trap/trap_hpux.h may override this definition for HPUX 9.0 */ #define MOUNT_TYPE_PCFS "msdosfs" /* Mount(2) type/name for TFS filesystem */ /* #undef MOUNT_TYPE_TFS */ /* Mount(2) type/name for TMPFS filesystem */ /* #undef MOUNT_TYPE_TMPFS */ /* Mount(2) type/name for UFS filesystem */ #define MOUNT_TYPE_UFS "ufs" /* Mount(2) type/name for UMAPFS (uid/gid mapping) filesystem */ /* #undef MOUNT_TYPE_UMAPFS */ /* Mount(2) type/name for UNIONFS filesystem */ #define MOUNT_TYPE_UNIONFS MNT_UNION /* Mount(2) type/name for XFS filesystem (irix) */ /* #undef MOUNT_TYPE_XFS */ /* The string used in printf to print the mount-type field of mount(2) */ #define MTYPE_PRINTF_TYPE "%s" /* Type of the mount-type field in the mount() system call */ #define MTYPE_TYPE char * /* does libwrap expect caller to define the variables allow_severity and deny_severity */ /* #undef NEED_LIBWRAP_SEVERITY_VARIABLES */ /* Defined to the header file containing ndbm-compatible definitions */ #define NEW_DBM_H /* Define the field name for the filehandle within nfs_args_t */ #define NFS_FH_FIELD fh /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "am-utils" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "https://bugzilla.am-utils.org/ or am-utils@am-utils.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "am-utils" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "am-utils 6.1.5" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "am-utils" /* Define to the version of this package. */ #define PACKAGE_VERSION "6.1.5" /* Type of the 6th argument to recvfrom() */ #define RECVFROM_FROMLEN_TYPE int /* should signal handlers be reinstalled? */ /* #undef REINSTALL_SIGNAL_HANDLER */ /* Define as the return type of signal handlers (`int' or `void'). */ #define RETSIGTYPE void /* Define to 1 if the `setpgrp' function takes no argument. */ /* #undef SETPGRP_VOID */ /* Define to 1 if the `S_IS*' macros in do not work properly. */ /* #undef STAT_MACROS_BROKEN */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define the type of the 3rd argument ('in') to svc_getargs() */ #define SVC_IN_ARG_TYPE caddr_t /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define to 1 if your declares `struct tm'. */ /* #undef TM_IN_SYS_TIME */ /* Define user name */ /* #define USER_NAME "obrien" */ /* define if must NOT use NFS "noconn" option */ #define USE_CONNECTED_NFS_SOCKETS 1 /* define if must use NFS "noconn" option */ /* #undef USE_UNCONNECTED_NFS_SOCKETS */ /* Version number of package */ #define VERSION "6.1.5" /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ /* #undef WORDS_BIGENDIAN */ /* Define to the type of xdr procedure type */ #define XDRPROC_T_TYPE xdrproc_t /* Type of the 3rd argument to yp_order() */ #define YP_ORDER_OUTORDER_TYPE int /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #define YYTEXT_POINTER 1 /* Define to 1 if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE /* # undef _ALL_SOURCE */ #endif /* Define a type/structure for an NFS V2 filehandle */ #define am_nfs_fh nfs_fh /* Define a type/structure for an NFS V3 filehandle */ #define am_nfs_fh3 nfs_fh3_freebsd3 /* Define a type for the autofs_args structure */ /* #undef autofs_args_t */ /* Define a type for the cachefs_args structure */ /* #undef cachefs_args_t */ /* Define a type for the cdfs_args structure */ #define cdfs_args_t struct iso_args /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define a type for the efs_args structure */ /* #undef efs_args_t */ /* Define to `int' if doesn't define. */ /* #undef gid_t */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif /* Define a type for the lofs_args structure */ /* #undef lofs_args_t */ /* Define a type for the mfs_args structure */ /* #undef mfs_args_t */ /* Define to `int' if does not define. */ /* #undef mode_t */ /* Define a type for the nfs_args structure */ #define nfs_args_t struct nfs_args /* Define a type for the pcfs_args structure */ #define pcfs_args_t struct msdosfs_args /* Define to `int' if does not define. */ /* #undef pid_t */ /* Check if pte_t is defined in */ /* #undef pte_t */ /* Define a type for the rfs_args structure */ /* #undef rfs_args_t */ /* Check if rpcvers_t is defined in */ /* #undef rpcvers_t */ /* Define to `unsigned' if does not define. */ /* #undef size_t */ /* Define to `long' if does not define. */ /* #undef time_t */ /* Define a type for the tmpfs_args structure */ /* #undef tmpfs_args_t */ /* Define a type for the ufs_args structure */ #define ufs_args_t struct ufs_args /* Define to `int' if doesn't define. */ /* #undef uid_t */ /* Define as `fork' if `vfork' does not work. */ /* #undef vfork */ /* Define to "void *" if compiler can handle, otherwise "char *" */ #define voidp void * /* Define to empty if the keyword `volatile' does not work. Warning: valid code using `volatile' can become incorrect without. Disable with care. */ /* #undef volatile */ /* Define a type for the xfs_args structure */ /* #undef xfs_args_t */ /****************************************************************************/ /*** INCLUDE localconfig.h if it exists, to allow users to make some ***/ /*** compile time configuration changes. ***/ /****************************************************************************/ /* does a local configuration file exist? */ /* #undef HAVE_LOCALCONFIG_H */ #ifdef HAVE_LOCALCONFIG_H # include #endif /* HAVE_LOCALCONFIG_H */ #endif /* not _CONFIG_H */ /* * Local Variables: * mode: c * End: */ /* End of am-utils-6.x config.h file */ diff --git a/usr.sbin/ancontrol/ancontrol.c b/usr.sbin/ancontrol/ancontrol.c index 839cdcb311ea..4ff32ff19098 100644 --- a/usr.sbin/ancontrol/ancontrol.c +++ b/usr.sbin/ancontrol/ancontrol.c @@ -1,1780 +1,1779 @@ /* * Copyright 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1997, 1998, 1999\ Bill Paul. All rights reserved."; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include static int an_getval(const char *, struct an_req *); static void an_setval(const char *, struct an_req *); static void an_printwords(const u_int16_t *, int); static void an_printspeeds(const u_int8_t *, int); static void an_printbool(int); static void an_printhex(const char *, int); static void an_printstr(char *, int); static void an_dumpstatus(const char *); static void an_dumpstats(const char *); static void an_dumpconfig(const char *); static void an_dumpcaps(const char *); static void an_dumpssid(const char *); static void an_dumpap(const char *); static void an_setconfig(const char *, int, void *); static void an_setssid(const char *, int, void *); static void an_setap(const char *, int, void *); static void an_setspeed(const char *, int, void *); static void an_readkeyinfo(const char *); #ifdef ANCACHE static void an_zerocache(const char *); static void an_readcache(const char *); #endif static int an_hex2int(char); static void an_str2key(const char *, struct an_ltv_key *); static void an_setkeys(const char *, const char *, int); static void an_enable_tx_key(const char *, const char *); static void an_enable_leap_mode(const char *, const char *); static void an_dumprssimap(const char *); static void usage(const char *); #define ACT_DUMPSTATS 1 #define ACT_DUMPCONFIG 2 #define ACT_DUMPSTATUS 3 #define ACT_DUMPCAPS 4 #define ACT_DUMPSSID 5 #define ACT_DUMPAP 6 #define ACT_SET_OPMODE 7 #define ACT_SET_SSID 8 #define ACT_SET_FREQ 11 #define ACT_SET_AP1 12 #define ACT_SET_AP2 13 #define ACT_SET_AP3 14 #define ACT_SET_AP4 15 #define ACT_SET_DRIVERNAME 16 #define ACT_SET_SCANMODE 17 #define ACT_SET_TXRATE 18 #define ACT_SET_RTS_THRESH 19 #define ACT_SET_PWRSAVE 20 #define ACT_SET_DIVERSITY_RX 21 #define ACT_SET_DIVERSITY_TX 22 #define ACT_SET_RTS_RETRYLIM 23 #define ACT_SET_WAKE_DURATION 24 #define ACT_SET_BEACON_PERIOD 25 #define ACT_SET_TXPWR 26 #define ACT_SET_FRAG_THRESH 27 #define ACT_SET_NETJOIN 28 #define ACT_SET_MYNAME 29 #define ACT_SET_MAC 30 #define ACT_DUMPCACHE 31 #define ACT_ZEROCACHE 32 #define ACT_ENABLE_WEP 33 #define ACT_SET_KEY_TYPE 34 #define ACT_SET_KEYS 35 #define ACT_ENABLE_TX_KEY 36 #define ACT_SET_MONITOR_MODE 37 #define ACT_SET_LEAP_MODE 38 #define ACT_DUMPRSSIMAP 39 static int an_getval(const char *iface, struct an_req *areq) { struct ifreq ifr; int s, okay = 1; bzero(&ifr, sizeof(ifr)); strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)areq; s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) err(1, "socket"); if (ioctl(s, SIOCGAIRONET, &ifr) == -1) { okay = 0; err(1, "SIOCGAIRONET"); } close(s); return (okay); } static void an_setval(const char *iface, struct an_req *areq) { struct ifreq ifr; int s; bzero(&ifr, sizeof(ifr)); strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)areq; s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) err(1, "socket"); if (ioctl(s, SIOCSAIRONET, &ifr) == -1) err(1, "SIOCSAIRONET"); close(s); return; } static void an_printstr(char *str, int len) { int i; for (i = 0; i < len - 1; i++) { if (str[i] == '\0') str[i] = ' '; } printf("[ %.*s ]", len, str); } static void an_printwords(const u_int16_t *w, int len) { int i; printf("[ "); for (i = 0; i < len; i++) printf("%u ", w[i]); printf("]"); } static void an_printspeeds(const u_int8_t *w, int len) { int i; printf("[ "); for (i = 0; i < len && w[i]; i++) printf("%2.1fMbps ", w[i] * 0.500); printf("]"); } static void an_printbool(int val) { if (val) printf("[ On ]"); else printf("[ Off ]"); } static void an_printhex(const char *ptr, int len) { int i; printf("[ "); for (i = 0; i < len; i++) { printf("%02x", ptr[i] & 0xFF); if (i < (len - 1)) printf(":"); } printf(" ]"); } static void an_dumpstatus(const char *iface) { struct an_ltv_status *sts; struct an_req areq; struct an_ltv_rssi_map an_rssimap; int rssimap_valid = 0; /* * Try to get RSSI to percent and dBM table */ an_rssimap.an_len = sizeof(an_rssimap); an_rssimap.an_type = AN_RID_RSSI_MAP; rssimap_valid = an_getval(iface, (struct an_req*)&an_rssimap); if (rssimap_valid) printf("RSSI table:\t\t[ present ]\n"); else printf("RSSI table:\t\t[ not available ]\n"); areq.an_len = sizeof(areq); areq.an_type = AN_RID_STATUS; an_getval(iface, &areq); sts = (struct an_ltv_status *)&areq; printf("MAC address:\t\t"); an_printhex((char *)&sts->an_macaddr, ETHER_ADDR_LEN); printf("\nOperating mode:\t\t[ "); if (sts->an_opmode & AN_STATUS_OPMODE_CONFIGURED) printf("configured "); if (sts->an_opmode & AN_STATUS_OPMODE_MAC_ENABLED) printf("MAC ON "); if (sts->an_opmode & AN_STATUS_OPMODE_RX_ENABLED) printf("RX ON "); if (sts->an_opmode & AN_STATUS_OPMODE_IN_SYNC) printf("synced "); if (sts->an_opmode & AN_STATUS_OPMODE_ASSOCIATED) printf("associated "); if (sts->an_opmode & AN_STATUS_OPMODE_LEAP) printf("LEAP "); if (sts->an_opmode & AN_STATUS_OPMODE_ERROR) printf("error "); printf("]\n"); printf("Error code:\t\t"); an_printhex((char *)&sts->an_errcode, 1); if (rssimap_valid) printf("\nSignal strength:\t[ %u%% ]", an_rssimap.an_entries[ sts->an_normalized_strength].an_rss_pct); else printf("\nSignal strength:\t[ %u%% ]", sts->an_normalized_strength); printf("\nAverage Noise:\t\t[ %u%% ]", sts->an_avg_noise_prev_min_pc); if (rssimap_valid) printf("\nSignal quality:\t\t[ %u%% ]", an_rssimap.an_entries[ sts->an_cur_signal_quality].an_rss_pct); else printf("\nSignal quality:\t\t[ %u ]", sts->an_cur_signal_quality); printf("\nMax Noise:\t\t[ %u%% ]", sts->an_max_noise_prev_min_pc); /* * XXX: This uses the old definition of the rate field (units of * 500kbps). Technically the new definition is that this field * contains arbitrary values, but no devices which need this * support exist and the IEEE seems to intend to use the old * definition until they get something big so we'll keep using * it as well because this will work with new cards with * rate <= 63.5Mbps. */ printf("\nCurrent TX rate:\t[ %u%s ]", sts->an_current_tx_rate / 2, (sts->an_current_tx_rate % 2) ? ".5" : ""); printf("\nCurrent SSID:\t\t"); an_printstr((char *)&sts->an_ssid, sts->an_ssidlen); printf("\nCurrent AP name:\t"); an_printstr((char *)&sts->an_ap_name, 16); printf("\nCurrent BSSID:\t\t"); an_printhex((char *)&sts->an_cur_bssid, ETHER_ADDR_LEN); printf("\nBeacon period:\t\t"); an_printwords(&sts->an_beacon_period, 1); printf("\nDTIM period:\t\t"); an_printwords(&sts->an_dtim_period, 1); printf("\nATIM duration:\t\t"); an_printwords(&sts->an_atim_duration, 1); printf("\nHOP period:\t\t"); an_printwords(&sts->an_hop_period, 1); printf("\nChannel set:\t\t"); an_printwords(&sts->an_channel_set, 1); printf("\nCurrent channel:\t"); an_printwords(&sts->an_cur_channel, 1); printf("\nHops to backbone:\t"); an_printwords(&sts->an_hops_to_backbone, 1); printf("\nTotal AP load:\t\t"); an_printwords(&sts->an_ap_total_load, 1); printf("\nOur generated load:\t"); an_printwords(&sts->an_our_generated_load, 1); printf("\nAccumulated ARL:\t"); an_printwords(&sts->an_accumulated_arl, 1); printf("\n"); return; } static void an_dumpcaps(const char *iface) { struct an_ltv_caps *caps; struct an_req areq; u_int16_t tmp; areq.an_len = sizeof(areq); areq.an_type = AN_RID_CAPABILITIES; an_getval(iface, &areq); caps = (struct an_ltv_caps *)&areq; printf("OUI:\t\t\t"); an_printhex((char *)&caps->an_oui, 3); printf("\nProduct number:\t\t"); an_printwords(&caps->an_prodnum, 1); printf("\nManufacturer name:\t"); an_printstr((char *)&caps->an_manufname, 32); printf("\nProduce name:\t\t"); an_printstr((char *)&caps->an_prodname, 16); printf("\nFirmware version:\t"); an_printstr((char *)&caps->an_prodvers, 1); printf("\nOEM MAC address:\t"); an_printhex((char *)&caps->an_oemaddr, ETHER_ADDR_LEN); printf("\nAironet MAC address:\t"); an_printhex((char *)&caps->an_aironetaddr, ETHER_ADDR_LEN); printf("\nRadio type:\t\t[ "); if (caps->an_radiotype & AN_RADIOTYPE_80211_FH) printf("802.11 FH"); else if (caps->an_radiotype & AN_RADIOTYPE_80211_DS) printf("802.11 DS"); else if (caps->an_radiotype & AN_RADIOTYPE_LM2000_DS) printf("LM2000 DS"); else printf("unknown (%x)", caps->an_radiotype); printf(" ]"); printf("\nRegulatory domain:\t"); an_printwords(&caps->an_regdomain, 1); printf("\nAssigned CallID:\t"); an_printhex((char *)&caps->an_callid, 6); printf("\nSupported speeds:\t"); an_printspeeds(caps->an_rates, 8); printf("\nRX Diversity:\t\t[ "); if (caps->an_rx_diversity == AN_DIVERSITY_FACTORY_DEFAULT) printf("factory default"); else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_1_ONLY) printf("antenna 1 only"); else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_2_ONLY) printf("antenna 2 only"); else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_1_AND_2) printf("antenna 1 and 2"); printf(" ]"); printf("\nTX Diversity:\t\t[ "); if (caps->an_tx_diversity == AN_DIVERSITY_FACTORY_DEFAULT) printf("factory default"); else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_1_ONLY) printf("antenna 1 only"); else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_2_ONLY) printf("antenna 2 only"); else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_1_AND_2) printf("antenna 1 and 2"); printf(" ]"); printf("\nSupported power levels:\t"); an_printwords(caps->an_tx_powerlevels, 8); printf("\nHardware revision:\t"); tmp = ntohs(caps->an_hwrev); an_printhex((char *)&tmp, 2); printf("\nSoftware revision:\t"); tmp = ntohs(caps->an_fwrev); an_printhex((char *)&tmp, 2); printf("\nSoftware subrevision:\t"); tmp = ntohs(caps->an_fwsubrev); an_printhex((char *)&tmp, 2); printf("\nInterface revision:\t"); tmp = ntohs(caps->an_ifacerev); an_printhex((char *)&tmp, 2); printf("\nBootblock revision:\t"); tmp = ntohs(caps->an_bootblockrev); an_printhex((char *)&tmp, 2); printf("\n"); return; } static void an_dumpstats(const char *iface) { struct an_ltv_stats *stats; struct an_req areq; areq.an_len = sizeof(areq); areq.an_type = AN_RID_32BITS_CUM; an_getval(iface, &areq); stats = (struct an_ltv_stats *)((uint16_t *)&areq - 1); printf("RX overruns:\t\t\t\t\t[ %u ]\n", stats->an_rx_overruns); printf("RX PLCP CSUM errors:\t\t\t\t[ %u ]\n", stats->an_rx_plcp_csum_errs); printf("RX PLCP format errors:\t\t\t\t[ %u ]\n", stats->an_rx_plcp_format_errs); printf("RX PLCP length errors:\t\t\t\t[ %u ]\n", stats->an_rx_plcp_len_errs); printf("RX MAC CRC errors:\t\t\t\t[ %u ]\n", stats->an_rx_mac_crc_errs); printf("RX MAC CRC OK:\t\t\t\t\t[ %u ]\n", stats->an_rx_mac_crc_ok); printf("RX WEP errors:\t\t\t\t\t[ %u ]\n", stats->an_rx_wep_errs); printf("RX WEP OK:\t\t\t\t\t[ %u ]\n", stats->an_rx_wep_ok); printf("Long retries:\t\t\t\t\t[ %u ]\n", stats->an_retry_long); printf("Short retries:\t\t\t\t\t[ %u ]\n", stats->an_retry_short); printf("Retries exhausted:\t\t\t\t[ %u ]\n", stats->an_retry_max); printf("Bad ACK:\t\t\t\t\t[ %u ]\n", stats->an_no_ack); printf("Bad CTS:\t\t\t\t\t[ %u ]\n", stats->an_no_cts); printf("RX good ACKs:\t\t\t\t\t[ %u ]\n", stats->an_rx_ack_ok); printf("RX good CTSs:\t\t\t\t\t[ %u ]\n", stats->an_rx_cts_ok); printf("TX good ACKs:\t\t\t\t\t[ %u ]\n", stats->an_tx_ack_ok); printf("TX good RTSs:\t\t\t\t\t[ %u ]\n", stats->an_tx_rts_ok); printf("TX good CTSs:\t\t\t\t\t[ %u ]\n", stats->an_tx_cts_ok); printf("LMAC multicasts transmitted:\t\t\t[ %u ]\n", stats->an_tx_lmac_mcasts); printf("LMAC broadcasts transmitted:\t\t\t[ %u ]\n", stats->an_tx_lmac_bcasts); printf("LMAC unicast frags transmitted:\t\t\t[ %u ]\n", stats->an_tx_lmac_ucast_frags); printf("LMAC unicasts transmitted:\t\t\t[ %u ]\n", stats->an_tx_lmac_ucasts); printf("Beacons transmitted:\t\t\t\t[ %u ]\n", stats->an_tx_beacons); printf("Beacons received:\t\t\t\t[ %u ]\n", stats->an_rx_beacons); printf("Single transmit collisions:\t\t\t[ %u ]\n", stats->an_tx_single_cols); printf("Multiple transmit collisions:\t\t\t[ %u ]\n", stats->an_tx_multi_cols); printf("Transmits without deferrals:\t\t\t[ %u ]\n", stats->an_tx_defers_no); printf("Transmits deferred due to protocol:\t\t[ %u ]\n", stats->an_tx_defers_prot); printf("Transmits deferred due to energy detect:\t\t[ %u ]\n", stats->an_tx_defers_energy); printf("RX duplicate frames/frags:\t\t\t[ %u ]\n", stats->an_rx_dups); printf("RX partial frames:\t\t\t\t[ %u ]\n", stats->an_rx_partial); printf("TX max lifetime exceeded:\t\t\t[ %u ]\n", stats->an_tx_too_old); printf("RX max lifetime exceeded:\t\t\t[ %u ]\n", stats->an_tx_too_old); printf("Sync lost due to too many missed beacons:\t[ %u ]\n", stats->an_lostsync_missed_beacons); printf("Sync lost due to ARL exceeded:\t\t\t[ %u ]\n", stats->an_lostsync_arl_exceeded); printf("Sync lost due to deauthentication:\t\t[ %u ]\n", stats->an_lostsync_deauthed); printf("Sync lost due to disassociation:\t\t[ %u ]\n", stats->an_lostsync_disassociated); printf("Sync lost due to excess change in TSF timing:\t[ %u ]\n", stats->an_lostsync_tsf_timing); printf("Host transmitted multicasts:\t\t\t[ %u ]\n", stats->an_tx_host_mcasts); printf("Host transmitted broadcasts:\t\t\t[ %u ]\n", stats->an_tx_host_bcasts); printf("Host transmitted unicasts:\t\t\t[ %u ]\n", stats->an_tx_host_ucasts); printf("Host transmission failures:\t\t\t[ %u ]\n", stats->an_tx_host_failed); printf("Host received multicasts:\t\t\t[ %u ]\n", stats->an_rx_host_mcasts); printf("Host received broadcasts:\t\t\t[ %u ]\n", stats->an_rx_host_bcasts); printf("Host received unicasts:\t\t\t\t[ %u ]\n", stats->an_rx_host_ucasts); printf("Host receive discards:\t\t\t\t[ %u ]\n", stats->an_rx_host_discarded); printf("HMAC transmitted multicasts:\t\t\t[ %u ]\n", stats->an_tx_hmac_mcasts); printf("HMAC transmitted broadcasts:\t\t\t[ %u ]\n", stats->an_tx_hmac_bcasts); printf("HMAC transmitted unicasts:\t\t\t[ %u ]\n", stats->an_tx_hmac_ucasts); printf("HMAC transmissions failed:\t\t\t[ %u ]\n", stats->an_tx_hmac_failed); printf("HMAC received multicasts:\t\t\t[ %u ]\n", stats->an_rx_hmac_mcasts); printf("HMAC received broadcasts:\t\t\t[ %u ]\n", stats->an_rx_hmac_bcasts); printf("HMAC received unicasts:\t\t\t\t[ %u ]\n", stats->an_rx_hmac_ucasts); printf("HMAC receive discards:\t\t\t\t[ %u ]\n", stats->an_rx_hmac_discarded); printf("HMAC transmits accepted:\t\t\t[ %u ]\n", stats->an_tx_hmac_accepted); printf("SSID mismatches:\t\t\t\t[ %u ]\n", stats->an_ssid_mismatches); printf("Access point mismatches:\t\t\t[ %u ]\n", stats->an_ap_mismatches); printf("Speed mismatches:\t\t\t\t[ %u ]\n", stats->an_rates_mismatches); printf("Authentication rejects:\t\t\t\t[ %u ]\n", stats->an_auth_rejects); printf("Authentication timeouts:\t\t\t[ %u ]\n", stats->an_auth_timeouts); printf("Association rejects:\t\t\t\t[ %u ]\n", stats->an_assoc_rejects); printf("Association timeouts:\t\t\t\t[ %u ]\n", stats->an_assoc_timeouts); printf("Management frames received:\t\t\t[ %u ]\n", stats->an_rx_mgmt_pkts); printf("Management frames transmitted:\t\t\t[ %u ]\n", stats->an_tx_mgmt_pkts); printf("Refresh frames received:\t\t\t[ %u ]\n", stats->an_rx_refresh_pkts), printf("Refresh frames transmitted:\t\t\t[ %u ]\n", stats->an_tx_refresh_pkts), printf("Poll frames received:\t\t\t\t[ %u ]\n", stats->an_rx_poll_pkts); printf("Poll frames transmitted:\t\t\t[ %u ]\n", stats->an_tx_poll_pkts); printf("Host requested sync losses:\t\t\t[ %u ]\n", stats->an_lostsync_hostreq); printf("Host transmitted bytes:\t\t\t\t[ %u ]\n", stats->an_host_tx_bytes); printf("Host received bytes:\t\t\t\t[ %u ]\n", stats->an_host_rx_bytes); printf("Uptime in microseconds:\t\t\t\t[ %u ]\n", stats->an_uptime_usecs); printf("Uptime in seconds:\t\t\t\t[ %u ]\n", stats->an_uptime_secs); printf("Sync lost due to better AP:\t\t\t[ %u ]\n", stats->an_lostsync_better_ap); } static void an_dumpap(const char *iface) { struct an_ltv_aplist *ap; struct an_req areq; areq.an_len = sizeof(areq); areq.an_type = AN_RID_APLIST; an_getval(iface, &areq); ap = (struct an_ltv_aplist *)&areq; printf("Access point 1:\t\t\t"); an_printhex((char *)&ap->an_ap1, ETHER_ADDR_LEN); printf("\nAccess point 2:\t\t\t"); an_printhex((char *)&ap->an_ap2, ETHER_ADDR_LEN); printf("\nAccess point 3:\t\t\t"); an_printhex((char *)&ap->an_ap3, ETHER_ADDR_LEN); printf("\nAccess point 4:\t\t\t"); an_printhex((char *)&ap->an_ap4, ETHER_ADDR_LEN); printf("\n"); return; } static void an_dumpssid(const char *iface) { struct an_ltv_ssidlist_new *ssid; struct an_req areq; int i, max; areq.an_len = sizeof(areq); areq.an_type = AN_RID_SSIDLIST; an_getval(iface, &areq); max = (areq.an_len - 4) / sizeof(struct an_ltv_ssid_entry); if ( max > MAX_SSIDS ) { printf("Too many SSIDs only printing %d of %d\n", MAX_SSIDS, max); max = MAX_SSIDS; } ssid = (struct an_ltv_ssidlist_new *)&areq; for (i = 0; i < max; i++) printf("SSID %2d:\t\t\t[ %.*s ]\n", i + 1, ssid->an_entry[i].an_len, ssid->an_entry[i].an_ssid); return; } static void an_dumpconfig(const char *iface) { struct an_ltv_genconfig *cfg; struct an_req areq; unsigned char diversity; areq.an_len = sizeof(areq); areq.an_type = AN_RID_ACTUALCFG; an_getval(iface, &areq); cfg = (struct an_ltv_genconfig *)&areq; printf("Operating mode:\t\t\t\t[ "); if ((cfg->an_opmode & 0x7) == AN_OPMODE_IBSS_ADHOC) printf("ad-hoc"); if ((cfg->an_opmode & 0x7) == AN_OPMODE_INFRASTRUCTURE_STATION) printf("infrastructure"); if ((cfg->an_opmode & 0x7) == AN_OPMODE_AP) printf("access point"); if ((cfg->an_opmode & 0x7) == AN_OPMODE_AP_REPEATER) printf("access point repeater"); printf(" ]"); printf("\nReceive mode:\t\t\t\t[ "); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_BC_MC_ADDR) printf("broadcast/multicast/unicast"); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_BC_ADDR) printf("broadcast/unicast"); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_ADDR) printf("unicast"); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_80211_MONITOR_CURBSS) printf("802.11 monitor, current BSSID"); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_80211_MONITOR_ANYBSS) printf("802.11 monitor, any BSSID"); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_LAN_MONITOR_CURBSS) printf("LAN monitor, current BSSID"); printf(" ]"); printf("\nFragment threshold:\t\t\t"); an_printwords(&cfg->an_fragthresh, 1); printf("\nRTS threshold:\t\t\t\t"); an_printwords(&cfg->an_rtsthresh, 1); printf("\nMAC address:\t\t\t\t"); an_printhex((char *)&cfg->an_macaddr, ETHER_ADDR_LEN); printf("\nSupported rates:\t\t\t"); an_printspeeds(cfg->an_rates, 8); printf("\nShort retry limit:\t\t\t"); an_printwords(&cfg->an_shortretry_limit, 1); printf("\nLong retry limit:\t\t\t"); an_printwords(&cfg->an_longretry_limit, 1); printf("\nTX MSDU lifetime:\t\t\t"); an_printwords(&cfg->an_tx_msdu_lifetime, 1); printf("\nRX MSDU lifetime:\t\t\t"); an_printwords(&cfg->an_rx_msdu_lifetime, 1); printf("\nStationary:\t\t\t\t"); an_printbool(cfg->an_stationary); printf("\nOrdering:\t\t\t\t"); an_printbool(cfg->an_ordering); printf("\nDevice type:\t\t\t\t[ "); if (cfg->an_devtype == AN_DEVTYPE_PC4500) printf("PC4500"); else if (cfg->an_devtype == AN_DEVTYPE_PC4800) printf("PC4800"); else printf("unknown (%x)", cfg->an_devtype); printf(" ]"); printf("\nScanning mode:\t\t\t\t[ "); if (cfg->an_scanmode == AN_SCANMODE_ACTIVE) printf("active"); if (cfg->an_scanmode == AN_SCANMODE_PASSIVE) printf("passive"); if (cfg->an_scanmode == AN_SCANMODE_AIRONET_ACTIVE) printf("Aironet active"); printf(" ]"); printf("\nProbe delay:\t\t\t\t"); an_printwords(&cfg->an_probedelay, 1); printf("\nProbe energy timeout:\t\t\t"); an_printwords(&cfg->an_probe_energy_timeout, 1); printf("\nProbe response timeout:\t\t\t"); an_printwords(&cfg->an_probe_response_timeout, 1); printf("\nBeacon listen timeout:\t\t\t"); an_printwords(&cfg->an_beacon_listen_timeout, 1); printf("\nIBSS join network timeout:\t\t"); an_printwords(&cfg->an_ibss_join_net_timeout, 1); printf("\nAuthentication timeout:\t\t\t"); an_printwords(&cfg->an_auth_timeout, 1); printf("\nWEP enabled:\t\t\t\t[ "); if (cfg->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) { if (cfg->an_authtype & AN_AUTHTYPE_LEAP) printf("LEAP"); else if (cfg->an_authtype & AN_AUTHTYPE_ALLOW_UNENCRYPTED) printf("mixed cell"); else printf("full"); } else printf("no"); printf(" ]"); printf("\nAuthentication type:\t\t\t[ "); if ((cfg->an_authtype & AN_AUTHTYPE_MASK) == AN_AUTHTYPE_NONE) printf("none"); if ((cfg->an_authtype & AN_AUTHTYPE_MASK) == AN_AUTHTYPE_OPEN) printf("open"); if ((cfg->an_authtype & AN_AUTHTYPE_MASK) == AN_AUTHTYPE_SHAREDKEY) printf("shared key"); printf(" ]"); printf("\nAssociation timeout:\t\t\t"); an_printwords(&cfg->an_assoc_timeout, 1); printf("\nSpecified AP association timeout:\t"); an_printwords(&cfg->an_specified_ap_timeout, 1); printf("\nOffline scan interval:\t\t\t"); an_printwords(&cfg->an_offline_scan_interval, 1); printf("\nOffline scan duration:\t\t\t"); an_printwords(&cfg->an_offline_scan_duration, 1); printf("\nLink loss delay:\t\t\t"); an_printwords(&cfg->an_link_loss_delay, 1); printf("\nMax beacon loss time:\t\t\t"); an_printwords(&cfg->an_max_beacon_lost_time, 1); printf("\nRefresh interval:\t\t\t"); an_printwords(&cfg->an_refresh_interval, 1); printf("\nPower save mode:\t\t\t[ "); if (cfg->an_psave_mode == AN_PSAVE_NONE) printf("none"); if (cfg->an_psave_mode == AN_PSAVE_CAM) printf("constantly awake mode"); if (cfg->an_psave_mode == AN_PSAVE_PSP) printf("PSP"); if (cfg->an_psave_mode == AN_PSAVE_PSP_CAM) printf("PSP-CAM (fast PSP)"); printf(" ]"); printf("\nSleep through DTIMs:\t\t\t"); an_printbool(cfg->an_sleep_for_dtims); printf("\nPower save listen interval:\t\t"); an_printwords(&cfg->an_listen_interval, 1); printf("\nPower save fast listen interval:\t"); an_printwords(&cfg->an_fast_listen_interval, 1); printf("\nPower save listen decay:\t\t"); an_printwords(&cfg->an_listen_decay, 1); printf("\nPower save fast listen decay:\t\t"); an_printwords(&cfg->an_fast_listen_decay, 1); printf("\nAP/ad-hoc Beacon period:\t\t"); an_printwords(&cfg->an_beacon_period, 1); printf("\nAP/ad-hoc ATIM duration:\t\t"); an_printwords(&cfg->an_atim_duration, 1); printf("\nAP/ad-hoc current channel:\t\t"); an_printwords(&cfg->an_ds_channel, 1); printf("\nAP/ad-hoc DTIM period:\t\t\t"); an_printwords(&cfg->an_dtim_period, 1); printf("\nRadio type:\t\t\t\t[ "); if (cfg->an_radiotype & AN_RADIOTYPE_80211_FH) printf("802.11 FH"); else if (cfg->an_radiotype & AN_RADIOTYPE_80211_DS) printf("802.11 DS"); else if (cfg->an_radiotype & AN_RADIOTYPE_LM2000_DS) printf("LM2000 DS"); else printf("unknown (%x)", cfg->an_radiotype); printf(" ]"); printf("\nRX Diversity:\t\t\t\t[ "); diversity = cfg->an_diversity & 0xFF; if (diversity == AN_DIVERSITY_FACTORY_DEFAULT) printf("factory default"); else if (diversity == AN_DIVERSITY_ANTENNA_1_ONLY) printf("antenna 1 only"); else if (diversity == AN_DIVERSITY_ANTENNA_2_ONLY) printf("antenna 2 only"); else if (diversity == AN_DIVERSITY_ANTENNA_1_AND_2) printf("antenna 1 and 2"); printf(" ]"); printf("\nTX Diversity:\t\t\t\t[ "); diversity = (cfg->an_diversity >> 8) & 0xFF; if (diversity == AN_DIVERSITY_FACTORY_DEFAULT) printf("factory default"); else if (diversity == AN_DIVERSITY_ANTENNA_1_ONLY) printf("antenna 1 only"); else if (diversity == AN_DIVERSITY_ANTENNA_2_ONLY) printf("antenna 2 only"); else if (diversity == AN_DIVERSITY_ANTENNA_1_AND_2) printf("antenna 1 and 2"); printf(" ]"); printf("\nTransmit power level:\t\t\t"); an_printwords(&cfg->an_tx_power, 1); printf("\nRSS threshold:\t\t\t\t"); an_printwords(&cfg->an_rss_thresh, 1); printf("\nNode name:\t\t\t\t"); an_printstr((char *)&cfg->an_nodename, 16); printf("\nARL threshold:\t\t\t\t"); an_printwords(&cfg->an_arl_thresh, 1); printf("\nARL decay:\t\t\t\t"); an_printwords(&cfg->an_arl_decay, 1); printf("\nARL delay:\t\t\t\t"); an_printwords(&cfg->an_arl_delay, 1); printf("\nConfiguration:\t\t\t\t[ "); if (cfg->an_home_product & AN_HOME_NETWORK) printf("Home Configuration"); else printf("Enterprise Configuration"); printf(" ]"); printf("\n"); printf("\n"); an_readkeyinfo(iface); } static void an_dumprssimap(const char *iface) { struct an_ltv_rssi_map *rssi; struct an_req areq; int i; areq.an_len = sizeof(areq); areq.an_type = AN_RID_RSSI_MAP; an_getval(iface, &areq); rssi = (struct an_ltv_rssi_map *)&areq; printf("idx\tpct\t dBm\n"); for (i = 0; i < 0xFF; i++) { /* * negate the dBm value: it's the only way the power * level makes sense */ printf("%3d\t%3d\t%4d\n", i, rssi->an_entries[i].an_rss_pct, - rssi->an_entries[i].an_rss_dbm); } } static void usage(const char *p) { fprintf(stderr, "usage: %s -i iface -A (show specified APs)\n", p); fprintf(stderr, "\t%s -i iface -N (show specified SSIDss)\n", p); fprintf(stderr, "\t%s -i iface -S (show NIC status)\n", p); fprintf(stderr, "\t%s -i iface -I (show NIC capabilities)\n", p); fprintf(stderr, "\t%s -i iface -T (show stats counters)\n", p); fprintf(stderr, "\t%s -i iface -C (show current config)\n", p); fprintf(stderr, "\t%s -i iface -R (show RSSI map)\n", p); fprintf(stderr, "\t%s -i iface -t 0-4 (set TX speed)\n", p); fprintf(stderr, "\t%s -i iface -s 0-3 (set power save mode)\n", p); fprintf(stderr, "\t%s -i iface [-v 1-4] -a AP (specify AP)\n", p); fprintf(stderr, "\t%s -i iface -b val (set beacon period)\n", p); fprintf(stderr, "\t%s -i iface [-v 0|1] -d val (set diversity)\n", p); fprintf(stderr, "\t%s -i iface -j val (set netjoin timeout)\n", p); fprintf(stderr, "\t%s -i iface -e 0-4 (enable transmit key)\n", p); fprintf(stderr, "\t%s -i iface [-v 0-8] -k key (set key)\n", p); fprintf(stderr, "\t%s -i iface -K 0-2 (no auth/open/shared secret)\n", p); fprintf(stderr, "\t%s -i iface -W 0-2 (no WEP/full WEP/mixed cell)\n", p); fprintf(stderr, "\t%s -i iface -l val (set station name)\n", p); fprintf(stderr, "\t%s -i iface -m val (set MAC address)\n", p); fprintf(stderr, "\t%s -i iface [-v 1-3] -n SSID " "(specify SSID)\n", p); fprintf(stderr, "\t%s -i iface -o 0|1 (set operating mode)\n", p); fprintf(stderr, "\t%s -i iface -c val (set ad-hoc channel)\n", p); fprintf(stderr, "\t%s -i iface -f val (set frag threshold)\n", p); fprintf(stderr, "\t%s -i iface -r val (set RTS threshold)\n", p); fprintf(stderr, "\t%s -i iface -M 0-15 (set monitor mode)\n", p); fprintf(stderr, "\t%s -i iface -L user (enter LEAP authentication mode)\n", p); #ifdef ANCACHE fprintf(stderr, "\t%s -i iface -Q print signal quality cache\n", p); fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p); #endif fprintf(stderr, "\t%s -h (display this message)\n", p); exit(1); } static void an_setconfig(const char *iface, int act, void *arg) { struct an_ltv_genconfig *cfg; struct an_ltv_caps *caps; struct an_req areq; struct an_req areq_caps; u_int16_t diversity = 0; struct ether_addr *addr; int i; areq.an_len = sizeof(areq); areq.an_type = AN_RID_GENCONFIG; an_getval(iface, &areq); cfg = (struct an_ltv_genconfig *)&areq; areq_caps.an_len = sizeof(areq); areq_caps.an_type = AN_RID_CAPABILITIES; an_getval(iface, &areq_caps); caps = (struct an_ltv_caps *)&areq_caps; switch(act) { case ACT_SET_OPMODE: cfg->an_opmode = atoi(arg); break; case ACT_SET_FREQ: cfg->an_ds_channel = atoi(arg); break; case ACT_SET_PWRSAVE: cfg->an_psave_mode = atoi(arg); break; case ACT_SET_SCANMODE: cfg->an_scanmode = atoi(arg); break; case ACT_SET_DIVERSITY_RX: case ACT_SET_DIVERSITY_TX: switch(atoi(arg)) { case 0: diversity = AN_DIVERSITY_FACTORY_DEFAULT; break; case 1: diversity = AN_DIVERSITY_ANTENNA_1_ONLY; break; case 2: diversity = AN_DIVERSITY_ANTENNA_2_ONLY; break; case 3: diversity = AN_DIVERSITY_ANTENNA_1_AND_2; break; default: errx(1, "bad diversity setting: %u", diversity); break; } if (act == ACT_SET_DIVERSITY_RX) { cfg->an_diversity &= 0xFF00; cfg->an_diversity |= diversity; } else { cfg->an_diversity &= 0x00FF; cfg->an_diversity |= (diversity << 8); } break; case ACT_SET_TXPWR: for (i = 0; i < 8; i++) { if (caps->an_tx_powerlevels[i] == atoi(arg)) break; } if (i == 8) errx(1, "unsupported power level: %dmW", atoi(arg)); cfg->an_tx_power = atoi(arg); break; case ACT_SET_RTS_THRESH: cfg->an_rtsthresh = atoi(arg); break; case ACT_SET_RTS_RETRYLIM: cfg->an_shortretry_limit = cfg->an_longretry_limit = atoi(arg); break; case ACT_SET_BEACON_PERIOD: cfg->an_beacon_period = atoi(arg); break; case ACT_SET_WAKE_DURATION: cfg->an_atim_duration = atoi(arg); break; case ACT_SET_FRAG_THRESH: cfg->an_fragthresh = atoi(arg); break; case ACT_SET_NETJOIN: cfg->an_ibss_join_net_timeout = atoi(arg); break; case ACT_SET_MYNAME: bzero(cfg->an_nodename, 16); strncpy((char *)&cfg->an_nodename, optarg, 16); break; case ACT_SET_MAC: addr = ether_aton((char *)arg); if (addr == NULL) errx(1, "badly formatted address"); bzero(cfg->an_macaddr, ETHER_ADDR_LEN); bcopy(addr, &cfg->an_macaddr, ETHER_ADDR_LEN); break; case ACT_ENABLE_WEP: switch (atoi (arg)) { case 0: /* no WEP */ cfg->an_authtype &= ~(AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_ALLOW_UNENCRYPTED | AN_AUTHTYPE_LEAP); break; case 1: /* full WEP */ cfg->an_authtype |= AN_AUTHTYPE_PRIVACY_IN_USE; cfg->an_authtype &= ~AN_AUTHTYPE_ALLOW_UNENCRYPTED; cfg->an_authtype &= ~AN_AUTHTYPE_LEAP; break; case 2: /* mixed cell */ cfg->an_authtype = AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_ALLOW_UNENCRYPTED; break; } break; case ACT_SET_KEY_TYPE: cfg->an_authtype = (cfg->an_authtype & ~AN_AUTHTYPE_MASK) | atoi(arg); break; case ACT_SET_MONITOR_MODE: areq.an_type = AN_RID_MONITOR_MODE; cfg->an_len = atoi(arg); /* mode is put in length */ break; default: errx(1, "unknown action"); break; } an_setval(iface, &areq); exit(0); } static void an_setspeed(const char *iface, int act __unused, void *arg) { struct an_req areq; struct an_ltv_caps *caps; u_int16_t speed; areq.an_len = sizeof(areq); areq.an_type = AN_RID_CAPABILITIES; an_getval(iface, &areq); caps = (struct an_ltv_caps *)&areq; switch(atoi(arg)) { case 0: speed = 0; break; case 1: speed = AN_RATE_1MBPS; break; case 2: speed = AN_RATE_2MBPS; break; case 3: if (caps->an_rates[2] != AN_RATE_5_5MBPS) errx(1, "5.5Mbps not supported on this card"); speed = AN_RATE_5_5MBPS; break; case 4: if (caps->an_rates[3] != AN_RATE_11MBPS) errx(1, "11Mbps not supported on this card"); speed = AN_RATE_11MBPS; break; default: errx(1, "unsupported speed"); break; } areq.an_len = 6; areq.an_type = AN_RID_TX_SPEED; areq.an_val[0] = speed; an_setval(iface, &areq); exit(0); } static void an_setap(const char *iface, int act, void *arg) { struct an_ltv_aplist *ap; struct an_req areq; struct ether_addr *addr; areq.an_len = sizeof(areq); areq.an_type = AN_RID_APLIST; an_getval(iface, &areq); ap = (struct an_ltv_aplist *)&areq; addr = ether_aton((char *)arg); if (addr == NULL) errx(1, "badly formatted address"); switch(act) { case ACT_SET_AP1: bzero(ap->an_ap1, ETHER_ADDR_LEN); bcopy(addr, &ap->an_ap1, ETHER_ADDR_LEN); break; case ACT_SET_AP2: bzero(ap->an_ap2, ETHER_ADDR_LEN); bcopy(addr, &ap->an_ap2, ETHER_ADDR_LEN); break; case ACT_SET_AP3: bzero(ap->an_ap3, ETHER_ADDR_LEN); bcopy(addr, &ap->an_ap3, ETHER_ADDR_LEN); break; case ACT_SET_AP4: bzero(ap->an_ap4, ETHER_ADDR_LEN); bcopy(addr, &ap->an_ap4, ETHER_ADDR_LEN); break; default: errx(1, "unknown action"); break; } an_setval(iface, &areq); exit(0); } static void an_setssid(const char *iface, int act, void *arg) { struct an_ltv_ssidlist_new *ssid; struct an_req areq; int max; areq.an_len = sizeof(areq); areq.an_type = AN_RID_SSIDLIST; an_getval(iface, &areq); ssid = (struct an_ltv_ssidlist_new *)&areq; max = (areq.an_len - 4) / sizeof(struct an_ltv_ssid_entry); if ( max > MAX_SSIDS ) { printf("Too many SSIDs only printing %d of %d\n", MAX_SSIDS, max); max = MAX_SSIDS; } if ( act > max ) { errx(1, "bad modifier %d: there " "are only %d SSID settings", act, max); exit(1); } bzero(ssid->an_entry[act-1].an_ssid, sizeof(ssid->an_entry[act-1].an_ssid)); strlcpy(ssid->an_entry[act-1].an_ssid, (char *)arg, sizeof(ssid->an_entry[act-1].an_ssid)); ssid->an_entry[act-1].an_len = strlen(ssid->an_entry[act-1].an_ssid); an_setval(iface, &areq); exit(0); } #ifdef ANCACHE static void an_zerocache(const char *iface) { struct an_req areq; bzero(&areq, sizeof(areq)); areq.an_len = 0; areq.an_type = AN_RID_ZERO_CACHE; an_getval(iface, &areq); } static void an_readcache(const char *iface) { struct an_req areq; uint16_t *an_sigitems; struct an_sigcache *sc; int i; if (iface == NULL) errx(1, "must specify interface name"); bzero(&areq, sizeof(areq)); areq.an_len = AN_MAX_DATALEN; areq.an_type = AN_RID_READ_CACHE; an_getval(iface, &areq); an_sigitems = areq.an_val; sc = (struct an_sigcache *)((int32_t *)areq.an_val + 1); for (i = 0; i < *an_sigitems; i++) { printf("[%d/%d]:", i+1, *an_sigitems); printf(" %02x:%02x:%02x:%02x:%02x:%02x,", sc->macsrc[0]&0xff, sc->macsrc[1]&0xff, sc->macsrc[2]&0xff, sc->macsrc[3]&0xff, sc->macsrc[4]&0xff, sc->macsrc[5]&0xff); printf(" %d.%d.%d.%d,",((sc->ipsrc >> 0) & 0xff), ((sc->ipsrc >> 8) & 0xff), ((sc->ipsrc >> 16) & 0xff), ((sc->ipsrc >> 24) & 0xff)); printf(" sig: %d, noise: %d, qual: %d\n", sc->signal, sc->noise, sc->quality); sc++; } } #endif static int an_hex2int(char c) { if (c >= '0' && c <= '9') return (c - '0'); if (c >= 'A' && c <= 'F') return (c - 'A' + 10); if (c >= 'a' && c <= 'f') return (c - 'a' + 10); return (0); } static void an_str2key(const char *s, struct an_ltv_key *k) { int n, i; char *p; /* Is this a hex string? */ if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { /* Yes, convert to int. */ n = 0; p = (char *)&k->key[0]; for (i = 2; s[i] != '\0' && s[i + 1] != '\0'; i+= 2) { *p++ = (an_hex2int(s[i]) << 4) + an_hex2int(s[i + 1]); n++; } if (s[i] != '\0') errx(1, "hex strings must be of even length"); k->klen = n; } else { /* No, just copy it in. */ bcopy(s, k->key, strlen(s)); k->klen = strlen(s); } return; } static void an_setkeys(const char *iface, const char *key, int keytype) { struct an_req areq; struct an_ltv_key *k; bzero(&areq, sizeof(areq)); k = (struct an_ltv_key *)&areq; if (strlen(key) > 28) { err(1, "encryption key must be no " "more than 18 characters long"); } an_str2key(key, k); k->kindex=keytype/2; if (!(k->klen==0 || k->klen==5 || k->klen==13)) { err(1, "encryption key must be 0, 5 or 13 bytes long"); } /* default mac and only valid one (from manual) 1.0.0.0.0.0 */ k->mac[0]=1; k->mac[1]=0; k->mac[2]=0; k->mac[3]=0; k->mac[4]=0; k->mac[5]=0; switch(keytype & 1) { case 0: areq.an_len = sizeof(struct an_ltv_key); areq.an_type = AN_RID_WEP_PERM; an_setval(iface, &areq); break; case 1: areq.an_len = sizeof(struct an_ltv_key); areq.an_type = AN_RID_WEP_TEMP; an_setval(iface, &areq); break; } } static void an_readkeyinfo(const char *iface) { struct an_req areq; struct an_ltv_genconfig *cfg; struct an_ltv_key *k; int i; int home; areq.an_len = sizeof(areq); areq.an_type = AN_RID_ACTUALCFG; an_getval(iface, &areq); cfg = (struct an_ltv_genconfig *)&areq; if (cfg->an_home_product & AN_HOME_NETWORK) home = 1; else home = 0; bzero(&areq, sizeof(areq)); k = (struct an_ltv_key *)&areq; printf("WEP Key status:\n"); areq.an_type = AN_RID_WEP_TEMP; /* read first key */ for(i=0; i<5; i++) { areq.an_len = sizeof(struct an_ltv_key); an_getval(iface, &areq); if (k->kindex == 0xffff) break; switch (k->klen) { case 0: printf("\tKey %u is unset\n", k->kindex); break; case 5: printf("\tKey %u is set 40 bits\n", k->kindex); break; case 13: printf("\tKey %u is set 128 bits\n", k->kindex); break; default: printf("\tWEP Key %d has an unknown size %u\n", i, k->klen); } areq.an_type = AN_RID_WEP_PERM; /* read next key */ } k->kindex = 0xffff; areq.an_len = sizeof(struct an_ltv_key); an_getval(iface, &areq); printf("\tThe active transmit key is %d\n", 4 * home + k->mac[0]); return; } static void an_enable_tx_key(const char *iface, const char *arg) { struct an_req areq; struct an_ltv_key *k; struct an_ltv_genconfig *config; bzero(&areq, sizeof(areq)); /* set home or not home mode */ areq.an_len = sizeof(struct an_ltv_genconfig); areq.an_type = AN_RID_GENCONFIG; an_getval(iface, &areq); config = (struct an_ltv_genconfig *)&areq; if (atoi(arg) == 4) { config->an_home_product |= AN_HOME_NETWORK; }else{ config->an_home_product &= ~AN_HOME_NETWORK; } an_setval(iface, &areq); bzero(&areq, sizeof(areq)); k = (struct an_ltv_key *)&areq; /* From a Cisco engineer write the transmit key to use in the first MAC, index is FFFF*/ k->kindex=0xffff; k->klen=0; k->mac[0]=atoi(arg); k->mac[1]=0; k->mac[2]=0; k->mac[3]=0; k->mac[4]=0; k->mac[5]=0; areq.an_len = sizeof(struct an_ltv_key); areq.an_type = AN_RID_WEP_PERM; an_setval(iface, &areq); } static void an_enable_leap_mode(const char *iface, const char *username) { struct an_req areq; struct an_ltv_status *sts; struct an_ltv_genconfig *cfg; struct an_ltv_caps *caps; struct an_ltv_leap_username an_username; struct an_ltv_leap_password an_password; char *password; MD4_CTX context; int len; int i; char unicode_password[LEAP_PASSWORD_MAX * 2]; areq.an_len = sizeof(areq); areq.an_type = AN_RID_CAPABILITIES; an_getval(iface, &areq); caps = (struct an_ltv_caps *)&areq; if (!(caps->an_softcaps & AN_AUTHTYPE_LEAP)) { fprintf(stderr, "Firmware does not support LEAP\n"); exit(1); } bzero(&an_username, sizeof(an_username)); bzero(&an_password, sizeof(an_password)); len = strlen(username); if (len > LEAP_USERNAME_MAX) { printf("Username too long (max %d)\n", LEAP_USERNAME_MAX); exit(1); } strncpy(an_username.an_username, username, len); an_username.an_username_len = len; an_username.an_len = sizeof(an_username); an_username.an_type = AN_RID_LEAPUSERNAME; password = getpass("Enter LEAP password:"); len = strlen(password); if (len > LEAP_PASSWORD_MAX) { printf("Password too long (max %d)\n", LEAP_PASSWORD_MAX); exit(1); } bzero(&unicode_password, sizeof(unicode_password)); for(i = 0; i < len; i++) { unicode_password[i * 2] = *password++; } /* First half */ MD4Init(&context); MD4Update(&context, unicode_password, len * 2); MD4Final(&an_password.an_password[0], &context); /* Second half */ MD4Init (&context); MD4Update (&context, &an_password.an_password[0], 16); MD4Final (&an_password.an_password[16], &context); an_password.an_password_len = 32; an_password.an_len = sizeof(an_password); an_password.an_type = AN_RID_LEAPPASSWORD; an_setval(iface, (struct an_req *)&an_username); an_setval(iface, (struct an_req *)&an_password); areq.an_len = sizeof(areq); areq.an_type = AN_RID_GENCONFIG; an_getval(iface, &areq); cfg = (struct an_ltv_genconfig *)&areq; cfg->an_authtype = (AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_LEAP); an_setval(iface, &areq); sts = (struct an_ltv_status *)&areq; areq.an_type = AN_RID_STATUS; for (i = 60; i > 0; i--) { an_getval(iface, &areq); if (sts->an_opmode & AN_STATUS_OPMODE_LEAP) { printf("Authenticated\n"); break; } sleep(1); } if (i == 0) { fprintf(stderr, "Failed LEAP authentication\n"); exit(1); } } int main(int argc, char *argv[]) { int ch; int act = 0; const char *iface = NULL; int modifier = 0; char *key = NULL; void *arg = NULL; char *p = argv[0]; /* Get the interface name */ opterr = 0; ch = getopt(argc, argv, "i:"); if (ch == 'i') { iface = optarg; } else { if (argc > 1 && *argv[1] != '-') { iface = argv[1]; optind = 2; } else { iface = "an0"; optind = 1; } optreset = 1; } opterr = 1; while ((ch = getopt(argc, argv, "ANISCTRht:a:e:o:s:n:v:d:j:b:c:f:r:p:w:m:l:k:K:W:QZM:L:")) != -1) { switch(ch) { case 'Z': #ifdef ANCACHE act = ACT_ZEROCACHE; #else errx(1, "ANCACHE not available"); #endif break; case 'Q': #ifdef ANCACHE act = ACT_DUMPCACHE; #else errx(1, "ANCACHE not available"); #endif break; case 'A': act = ACT_DUMPAP; break; case 'N': act = ACT_DUMPSSID; break; case 'S': act = ACT_DUMPSTATUS; break; case 'I': act = ACT_DUMPCAPS; break; case 'T': act = ACT_DUMPSTATS; break; case 'C': act = ACT_DUMPCONFIG; break; case 'R': act = ACT_DUMPRSSIMAP; break; case 't': act = ACT_SET_TXRATE; arg = optarg; break; case 's': act = ACT_SET_PWRSAVE; arg = optarg; break; case 'p': act = ACT_SET_TXPWR; arg = optarg; break; case 'v': modifier = atoi(optarg); break; case 'a': switch(modifier) { case 0: case 1: act = ACT_SET_AP1; break; case 2: act = ACT_SET_AP2; break; case 3: act = ACT_SET_AP3; break; case 4: act = ACT_SET_AP4; break; default: errx(1, "bad modifier %d: there " "are only 4 access point settings", modifier); usage(p); break; } arg = optarg; break; case 'b': act = ACT_SET_BEACON_PERIOD; arg = optarg; break; case 'd': switch(modifier) { case 0: act = ACT_SET_DIVERSITY_RX; break; case 1: act = ACT_SET_DIVERSITY_TX; break; default: errx(1, "must specify RX or TX diversity"); break; } if (!isdigit(*optarg)) { errx(1, "%s is not numeric", optarg); exit(1); } arg = optarg; break; case 'j': act = ACT_SET_NETJOIN; arg = optarg; break; case 'l': act = ACT_SET_MYNAME; arg = optarg; break; case 'm': act = ACT_SET_MAC; arg = optarg; break; case 'n': if (modifier == 0) modifier = 1; act = ACT_SET_SSID; arg = optarg; break; case 'o': act = ACT_SET_OPMODE; arg = optarg; break; case 'c': act = ACT_SET_FREQ; arg = optarg; break; case 'f': act = ACT_SET_FRAG_THRESH; arg = optarg; break; case 'W': act = ACT_ENABLE_WEP; arg = optarg; break; case 'K': act = ACT_SET_KEY_TYPE; arg = optarg; break; case 'k': act = ACT_SET_KEYS; key = optarg; break; case 'e': act = ACT_ENABLE_TX_KEY; arg = optarg; break; case 'q': act = ACT_SET_RTS_RETRYLIM; arg = optarg; break; case 'r': act = ACT_SET_RTS_THRESH; arg = optarg; break; case 'w': act = ACT_SET_WAKE_DURATION; arg = optarg; break; case 'M': act = ACT_SET_MONITOR_MODE; arg = optarg; break; case 'L': act = ACT_SET_LEAP_MODE; arg = optarg; break; case 'h': default: usage(p); } } if (iface == NULL || (!act && !key)) usage(p); switch(act) { case ACT_DUMPSTATUS: an_dumpstatus(iface); break; case ACT_DUMPCAPS: an_dumpcaps(iface); break; case ACT_DUMPSTATS: an_dumpstats(iface); break; case ACT_DUMPCONFIG: an_dumpconfig(iface); break; case ACT_DUMPSSID: an_dumpssid(iface); break; case ACT_DUMPAP: an_dumpap(iface); break; case ACT_DUMPRSSIMAP: an_dumprssimap(iface); break; case ACT_SET_SSID: an_setssid(iface, modifier, arg); break; case ACT_SET_AP1: case ACT_SET_AP2: case ACT_SET_AP3: case ACT_SET_AP4: an_setap(iface, act, arg); break; case ACT_SET_TXRATE: an_setspeed(iface, act, arg); break; #ifdef ANCACHE case ACT_ZEROCACHE: an_zerocache(iface); break; case ACT_DUMPCACHE: an_readcache(iface); break; #endif case ACT_SET_KEYS: an_setkeys(iface, key, modifier); break; case ACT_ENABLE_TX_KEY: an_enable_tx_key(iface, arg); break; case ACT_SET_LEAP_MODE: an_enable_leap_mode(iface, arg); break; default: an_setconfig(iface, act, arg); break; } exit(0); } diff --git a/usr.sbin/ifmcstat/ifmcstat.c b/usr.sbin/ifmcstat/ifmcstat.c index d3798e39fab9..4f3f444c276d 100644 --- a/usr.sbin/ifmcstat/ifmcstat.c +++ b/usr.sbin/ifmcstat/ifmcstat.c @@ -1,1247 +1,1246 @@ /* $KAME: ifmcstat.c,v 1.48 2006/11/15 05:13:59 itojun Exp $ */ /* * Copyright (c) 2007-2009 Bruce Simpson. * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #ifdef INET6 #include #include #endif /* INET6 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KVM /* * Currently the KVM build is broken. To be fixed it requires uncovering * large amount of _KERNEL code in include files, and it is also very * tentative to internal kernel ABI changes. If anyone wishes to restore * it, please move it out of src/usr.sbin to src/tools/tools. */ #include #include #endif /* XXX: This file currently assumes INET support in the base system. */ #ifndef INET #define INET #endif extern void printb(const char *, unsigned int, const char *); union sockunion { struct sockaddr_storage ss; struct sockaddr sa; struct sockaddr_dl sdl; #ifdef INET struct sockaddr_in sin; #endif #ifdef INET6 struct sockaddr_in6 sin6; #endif }; typedef union sockunion sockunion_t; uint32_t ifindex = 0; int af = AF_UNSPEC; #ifdef WITH_KVM int Kflag = 0; #endif int vflag = 0; #define sa_dl_equal(a1, a2) \ ((((struct sockaddr_dl *)(a1))->sdl_len == \ ((struct sockaddr_dl *)(a2))->sdl_len) && \ (bcmp(LLADDR((struct sockaddr_dl *)(a1)), \ LLADDR((struct sockaddr_dl *)(a2)), \ ((struct sockaddr_dl *)(a1))->sdl_alen) == 0)) /* * Most of the code in this utility is to support the use of KVM for * post-mortem debugging of the multicast code. */ #ifdef WITH_KVM #ifdef INET static void if_addrlist(struct ifaddr *); static struct in_multi * in_multientry(struct in_multi *); #endif /* INET */ #ifdef INET6 static void if6_addrlist(struct ifaddr *); static struct in6_multi * in6_multientry(struct in6_multi *); #endif /* INET6 */ static void kread(u_long, void *, int); static void ll_addrlist(struct ifaddr *); static int ifmcstat_kvm(const char *kernel, const char *core); #define KREAD(addr, buf, type) \ kread((u_long)addr, (void *)buf, sizeof(type)) kvm_t *kvmd; struct nlist nl[] = { { "_ifnet", 0, 0, 0, 0, }, { "", 0, 0, 0, 0, }, }; #define N_IFNET 0 #endif /* WITH_KVM */ static int ifmcstat_getifmaddrs(void); #ifdef INET static void in_ifinfo(struct igmp_ifinfo *); static const char * inm_mode(u_int mode); #endif #ifdef INET6 static void in6_ifinfo(struct mld_ifinfo *); static const char * inet6_n2a(struct in6_addr *, uint32_t); #endif int main(int, char **); static void usage() { fprintf(stderr, "usage: ifmcstat [-i interface] [-f address family]" " [-v]" #ifdef WITH_KVM " [-K] [-M core] [-N system]" #endif "\n"); exit(EX_USAGE); } static const char *options = "i:f:vM:N:" #ifdef WITH_KVM "K" #endif ; int main(int argc, char **argv) { int c, error; #ifdef WITH_KVM const char *kernel = NULL; const char *core = NULL; #endif while ((c = getopt(argc, argv, options)) != -1) { switch (c) { case 'i': if ((ifindex = if_nametoindex(optarg)) == 0) { fprintf(stderr, "%s: unknown interface\n", optarg); exit(EX_NOHOST); } break; case 'f': #ifdef INET if (strcmp(optarg, "inet") == 0) { af = AF_INET; break; } #endif #ifdef INET6 if (strcmp(optarg, "inet6") == 0) { af = AF_INET6; break; } #endif if (strcmp(optarg, "link") == 0) { af = AF_LINK; break; } fprintf(stderr, "%s: unknown address family\n", optarg); exit(EX_USAGE); /*NOTREACHED*/ break; #ifdef WITH_KVM case 'K': ++Kflag; break; #endif case 'v': ++vflag; break; #ifdef WITH_KVM case 'M': core = strdup(optarg); break; case 'N': kernel = strdup(optarg); break; #endif default: usage(); break; /*NOTREACHED*/ } } if (af == AF_LINK && vflag) usage(); #ifdef WITH_KVM if (Kflag) error = ifmcstat_kvm(kernel, core); /* * If KVM failed, and user did not explicitly specify a core file, * or force KVM backend to be disabled, try the sysctl backend. */ if (!Kflag || (error != 0 && (core == NULL && kernel == NULL))) #endif error = ifmcstat_getifmaddrs(); if (error != 0) exit(EX_OSERR); exit(EX_OK); /*NOTREACHED*/ } #ifdef INET static void in_ifinfo(struct igmp_ifinfo *igi) { printf("\t"); switch (igi->igi_version) { case IGMP_VERSION_1: case IGMP_VERSION_2: case IGMP_VERSION_3: printf("igmpv%d", igi->igi_version); break; default: printf("igmpv?(%d)", igi->igi_version); break; } if (igi->igi_flags) printb(" flags", igi->igi_flags, "\020\1SILENT\2LOOPBACK"); if (igi->igi_version == IGMP_VERSION_3) { printf(" rv %u qi %u qri %u uri %u", igi->igi_rv, igi->igi_qi, igi->igi_qri, igi->igi_uri); } if (vflag >= 2) { printf(" v1timer %u v2timer %u v3timer %u", igi->igi_v1_timer, igi->igi_v2_timer, igi->igi_v3_timer); } printf("\n"); } static const char *inm_modes[] = { "undefined", "include", "exclude", }; static const char * inm_mode(u_int mode) { if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE) return (inm_modes[mode]); return (NULL); } #endif /* INET */ #ifdef WITH_KVM static int ifmcstat_kvm(const char *kernel, const char *core) { char buf[_POSIX2_LINE_MAX], ifname[IFNAMSIZ]; struct ifnet *ifp, *nifp, ifnet; if ((kvmd = kvm_openfiles(kernel, core, NULL, O_RDONLY, buf)) == NULL) { perror("kvm_openfiles"); return (-1); } if (kvm_nlist(kvmd, nl) < 0) { perror("kvm_nlist"); return (-1); } if (nl[N_IFNET].n_value == 0) { printf("symbol %s not found\n", nl[N_IFNET].n_name); return (-1); } KREAD(nl[N_IFNET].n_value, &ifp, struct ifnet *); while (ifp) { KREAD(ifp, &ifnet, struct ifnet); nifp = ifnet.if_link.tqe_next; if (ifindex && ifindex != ifnet.if_index) goto next; printf("%s:\n", if_indextoname(ifnet.if_index, ifname)); #ifdef INET if_addrlist(TAILQ_FIRST(&ifnet.if_addrhead)); #endif #ifdef INET6 if6_addrlist(TAILQ_FIRST(&ifnet.if_addrhead)); #endif if (vflag) ll_addrlist(TAILQ_FIRST(&ifnet.if_addrhead)); next: ifp = nifp; } return (0); } static void kread(u_long addr, void *buf, int len) { if (kvm_read(kvmd, addr, buf, len) != len) { perror("kvm_read"); exit(EX_OSERR); } } static void ll_addrlist(struct ifaddr *ifap) { char addrbuf[NI_MAXHOST]; struct ifaddr ifa; struct sockaddr sa; struct sockaddr_dl sdl; struct ifaddr *ifap0; if (af && af != AF_LINK) return; ifap0 = ifap; while (ifap) { KREAD(ifap, &ifa, struct ifaddr); if (ifa.ifa_addr == NULL) goto nextifap; KREAD(ifa.ifa_addr, &sa, struct sockaddr); if (sa.sa_family != PF_LINK) goto nextifap; KREAD(ifa.ifa_addr, &sdl, struct sockaddr_dl); if (sdl.sdl_alen == 0) goto nextifap; addrbuf[0] = '\0'; getnameinfo((struct sockaddr *)&sdl, sdl.sdl_len, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); printf("\tlink %s\n", addrbuf); nextifap: ifap = ifa.ifa_link.tqe_next; } if (ifap0) { struct ifnet ifnet; struct ifmultiaddr ifm, *ifmp = 0; KREAD(ifap0, &ifa, struct ifaddr); KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); if (TAILQ_FIRST(&ifnet.if_multiaddrs)) ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs); while (ifmp) { KREAD(ifmp, &ifm, struct ifmultiaddr); if (ifm.ifma_addr == NULL) goto nextmulti; KREAD(ifm.ifma_addr, &sa, struct sockaddr); if (sa.sa_family != AF_LINK) goto nextmulti; KREAD(ifm.ifma_addr, &sdl, struct sockaddr_dl); addrbuf[0] = '\0'; getnameinfo((struct sockaddr *)&sdl, sdl.sdl_len, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); printf("\t\tgroup %s refcnt %d\n", addrbuf, ifm.ifma_refcount); nextmulti: ifmp = TAILQ_NEXT(&ifm, ifma_link); } } } #ifdef INET6 static void if6_addrlist(struct ifaddr *ifap) { struct ifnet ifnet; struct ifaddr ifa; struct sockaddr sa; struct in6_ifaddr if6a; struct ifaddr *ifap0; if (af && af != AF_INET6) return; ifap0 = ifap; while (ifap) { KREAD(ifap, &ifa, struct ifaddr); if (ifa.ifa_addr == NULL) goto nextifap; KREAD(ifa.ifa_addr, &sa, struct sockaddr); if (sa.sa_family != PF_INET6) goto nextifap; KREAD(ifap, &if6a, struct in6_ifaddr); printf("\tinet6 %s\n", inet6_n2a(&if6a.ia_addr.sin6_addr, if6a.ia_addr.sin6_scope_id)); /* * Print per-link MLD information, if available. */ if (ifa.ifa_ifp != NULL) { struct in6_ifextra ie; struct mld_ifinfo mli; KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); KREAD(ifnet.if_afdata[AF_INET6], &ie, struct in6_ifextra); if (ie.mld_ifinfo != NULL) { KREAD(ie.mld_ifinfo, &mli, struct mld_ifinfo); in6_ifinfo(&mli); } } nextifap: ifap = ifa.ifa_link.tqe_next; } if (ifap0) { struct ifnet ifnet; struct ifmultiaddr ifm, *ifmp = 0; struct sockaddr_dl sdl; KREAD(ifap0, &ifa, struct ifaddr); KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); if (TAILQ_FIRST(&ifnet.if_multiaddrs)) ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs); while (ifmp) { KREAD(ifmp, &ifm, struct ifmultiaddr); if (ifm.ifma_addr == NULL) goto nextmulti; KREAD(ifm.ifma_addr, &sa, struct sockaddr); if (sa.sa_family != AF_INET6) goto nextmulti; (void)in6_multientry((struct in6_multi *) ifm.ifma_protospec); if (ifm.ifma_lladdr == 0) goto nextmulti; KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl); printf("\t\t\tmcast-macaddr %s refcnt %d\n", ether_ntoa((struct ether_addr *)LLADDR(&sdl)), ifm.ifma_refcount); nextmulti: ifmp = TAILQ_NEXT(&ifm, ifma_link); } } } static struct in6_multi * in6_multientry(struct in6_multi *mc) { struct in6_multi multi; KREAD(mc, &multi, struct in6_multi); printf("\t\tgroup %s", inet6_n2a(&multi.in6m_addr, 0)); printf(" refcnt %u\n", multi.in6m_refcount); return (multi.in6m_entry.le_next); } #endif /* INET6 */ #ifdef INET static void if_addrlist(struct ifaddr *ifap) { struct ifaddr ifa; struct ifnet ifnet; struct sockaddr sa; struct in_ifaddr ia; struct ifaddr *ifap0; if (af && af != AF_INET) return; ifap0 = ifap; while (ifap) { KREAD(ifap, &ifa, struct ifaddr); if (ifa.ifa_addr == NULL) goto nextifap; KREAD(ifa.ifa_addr, &sa, struct sockaddr); if (sa.sa_family != PF_INET) goto nextifap; KREAD(ifap, &ia, struct in_ifaddr); printf("\tinet %s\n", inet_ntoa(ia.ia_addr.sin_addr)); /* * Print per-link IGMP information, if available. */ if (ifa.ifa_ifp != NULL) { struct in_ifinfo ii; struct igmp_ifinfo igi; KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); KREAD(ifnet.if_afdata[AF_INET], &ii, struct in_ifinfo); if (ii.ii_igmp != NULL) { KREAD(ii.ii_igmp, &igi, struct igmp_ifinfo); in_ifinfo(&igi); } } nextifap: ifap = ifa.ifa_link.tqe_next; } if (ifap0) { struct ifmultiaddr ifm, *ifmp = 0; struct sockaddr_dl sdl; KREAD(ifap0, &ifa, struct ifaddr); KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); if (TAILQ_FIRST(&ifnet.if_multiaddrs)) ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs); while (ifmp) { KREAD(ifmp, &ifm, struct ifmultiaddr); if (ifm.ifma_addr == NULL) goto nextmulti; KREAD(ifm.ifma_addr, &sa, struct sockaddr); if (sa.sa_family != AF_INET) goto nextmulti; (void)in_multientry((struct in_multi *) ifm.ifma_protospec); if (ifm.ifma_lladdr == 0) goto nextmulti; KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl); printf("\t\t\tmcast-macaddr %s refcnt %d\n", ether_ntoa((struct ether_addr *)LLADDR(&sdl)), ifm.ifma_refcount); nextmulti: ifmp = TAILQ_NEXT(&ifm, ifma_link); } } } static const char *inm_states[] = { "not-member", "silent", "idle", "lazy", "sleeping", "awakening", "query-pending", "sg-query-pending", "leaving" }; static const char * inm_state(u_int state) { if (state >= IGMP_NOT_MEMBER && state <= IGMP_LEAVING_MEMBER) return (inm_states[state]); return (NULL); } #if 0 static struct ip_msource * ims_min_kvm(struct in_multi *pinm) { struct ip_msource ims0; struct ip_msource *tmp, *parent; parent = NULL; tmp = RB_ROOT(&pinm->inm_srcs); while (tmp) { parent = tmp; KREAD(tmp, &ims0, struct ip_msource); tmp = RB_LEFT(&ims0, ims_link); } return (parent); /* kva */ } /* XXX This routine is buggy. See RB_NEXT in sys/tree.h. */ static struct ip_msource * ims_next_kvm(struct ip_msource *ims) { struct ip_msource ims0, ims1; struct ip_msource *tmp; KREAD(ims, &ims0, struct ip_msource); if (RB_RIGHT(&ims0, ims_link)) { ims = RB_RIGHT(&ims0, ims_link); KREAD(ims, &ims1, struct ip_msource); while ((tmp = RB_LEFT(&ims1, ims_link))) { KREAD(tmp, &ims0, struct ip_msource); ims = RB_LEFT(&ims0, ims_link); } } else { tmp = RB_PARENT(&ims0, ims_link); if (tmp) { KREAD(tmp, &ims1, struct ip_msource); if (ims == RB_LEFT(&ims1, ims_link)) ims = tmp; } else { while ((tmp = RB_PARENT(&ims0, ims_link))) { KREAD(tmp, &ims1, struct ip_msource); if (ims == RB_RIGHT(&ims1, ims_link)) { ims = tmp; KREAD(ims, &ims0, struct ip_msource); } else break; } ims = RB_PARENT(&ims0, ims_link); } } return (ims); /* kva */ } static void inm_print_sources_kvm(struct in_multi *pinm) { struct ip_msource ims0; struct ip_msource *ims; struct in_addr src; int cnt; uint8_t fmode; cnt = 0; fmode = pinm->inm_st[1].iss_fmode; if (fmode == MCAST_UNDEFINED) return; for (ims = ims_min_kvm(pinm); ims != NULL; ims = ims_next_kvm(ims)) { if (cnt == 0) printf(" srcs "); KREAD(ims, &ims0, struct ip_msource); /* Only print sources in-mode at t1. */ if (fmode != ims_get_mode(pinm, ims, 1)) continue; src.s_addr = htonl(ims0.ims_haddr); printf("%s%s", (cnt++ == 0 ? "" : ","), inet_ntoa(src)); } } #endif static struct in_multi * in_multientry(struct in_multi *pinm) { struct in_multi inm; const char *state, *mode; KREAD(pinm, &inm, struct in_multi); printf("\t\tgroup %s", inet_ntoa(inm.inm_addr)); printf(" refcnt %u", inm.inm_refcount); state = inm_state(inm.inm_state); if (state) printf(" state %s", state); else printf(" state (%d)", inm.inm_state); mode = inm_mode(inm.inm_st[1].iss_fmode); if (mode) printf(" mode %s", mode); else printf(" mode (%d)", inm.inm_st[1].iss_fmode); if (vflag >= 2) { printf(" asm %u ex %u in %u rec %u", (u_int)inm.inm_st[1].iss_asm, (u_int)inm.inm_st[1].iss_ex, (u_int)inm.inm_st[1].iss_in, (u_int)inm.inm_st[1].iss_rec); } #if 0 /* Buggy. */ if (vflag) inm_print_sources_kvm(&inm); #endif printf("\n"); return (NULL); } #endif /* INET */ #endif /* WITH_KVM */ #ifdef INET6 static void in6_ifinfo(struct mld_ifinfo *mli) { printf("\t"); switch (mli->mli_version) { case MLD_VERSION_1: case MLD_VERSION_2: printf("mldv%d", mli->mli_version); break; default: printf("mldv?(%d)", mli->mli_version); break; } if (mli->mli_flags) printb(" flags", mli->mli_flags, "\020\1SILENT\2USEALLOW"); if (mli->mli_version == MLD_VERSION_2) { printf(" rv %u qi %u qri %u uri %u", mli->mli_rv, mli->mli_qi, mli->mli_qri, mli->mli_uri); } if (vflag >= 2) { printf(" v1timer %u v2timer %u", mli->mli_v1_timer, mli->mli_v2_timer); } printf("\n"); } static const char * inet6_n2a(struct in6_addr *p, uint32_t scope_id) { static char buf[NI_MAXHOST]; struct sockaddr_in6 sin6; const int niflags = NI_NUMERICHOST; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_addr = *p; sin6.sin6_scope_id = scope_id; if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, buf, sizeof(buf), NULL, 0, niflags) == 0) { return (buf); } else { return ("(invalid)"); } } #endif /* INET6 */ #ifdef INET /* * Retrieve per-group source filter mode and lists via sysctl. */ static void inm_print_sources_sysctl(uint32_t ifindex, struct in_addr gina) { #define MAX_SYSCTL_TRY 5 int mib[7]; int ntry = 0; size_t mibsize; size_t len; size_t needed; size_t cnt; int i; char *buf; struct in_addr *pina; uint32_t *p; uint32_t fmode; const char *modestr; mibsize = sizeof(mib) / sizeof(mib[0]); if (sysctlnametomib("net.inet.ip.mcast.filters", mib, &mibsize) == -1) { perror("sysctlnametomib"); return; } needed = 0; mib[5] = ifindex; mib[6] = gina.s_addr; /* 32 bits wide */ mibsize = sizeof(mib) / sizeof(mib[0]); do { if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) { perror("sysctl net.inet.ip.mcast.filters"); return; } if ((buf = malloc(needed)) == NULL) { perror("malloc"); return; } if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) { if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { perror("sysctl"); goto out_free; } free(buf); buf = NULL; } } while (buf == NULL); len = needed; if (len < sizeof(uint32_t)) { perror("sysctl"); goto out_free; } p = (uint32_t *)buf; fmode = *p++; len -= sizeof(uint32_t); modestr = inm_mode(fmode); if (modestr) printf(" mode %s", modestr); else printf(" mode (%u)", fmode); if (vflag == 0) goto out_free; cnt = len / sizeof(struct in_addr); pina = (struct in_addr *)p; for (i = 0; i < cnt; i++) { if (i == 0) printf(" srcs "); fprintf(stdout, "%s%s", (i == 0 ? "" : ","), inet_ntoa(*pina++)); len -= sizeof(struct in_addr); } if (len > 0) { fprintf(stderr, "warning: %u trailing bytes from %s\n", (unsigned int)len, "net.inet.ip.mcast.filters"); } out_free: free(buf); #undef MAX_SYSCTL_TRY } #endif /* INET */ #ifdef INET6 /* * Retrieve MLD per-group source filter mode and lists via sysctl. * * Note: The 128-bit IPv6 group address needs to be segmented into * 32-bit pieces for marshaling to sysctl. So the MIB name ends * up looking like this: * a.b.c.d.e.ifindex.g[0].g[1].g[2].g[3] * Assumes that pgroup originated from the kernel, so its components * are already in network-byte order. */ static void in6m_print_sources_sysctl(uint32_t ifindex, struct in6_addr *pgroup) { #define MAX_SYSCTL_TRY 5 char addrbuf[INET6_ADDRSTRLEN]; int mib[10]; int ntry = 0; int *pi; size_t mibsize; size_t len; size_t needed; size_t cnt; int i; char *buf; struct in6_addr *pina; uint32_t *p; uint32_t fmode; const char *modestr; mibsize = sizeof(mib) / sizeof(mib[0]); if (sysctlnametomib("net.inet6.ip6.mcast.filters", mib, &mibsize) == -1) { perror("sysctlnametomib"); return; } needed = 0; mib[5] = ifindex; pi = (int *)pgroup; for (i = 0; i < 4; i++) mib[6 + i] = *pi++; mibsize = sizeof(mib) / sizeof(mib[0]); do { if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) { perror("sysctl net.inet6.ip6.mcast.filters"); return; } if ((buf = malloc(needed)) == NULL) { perror("malloc"); return; } if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) { if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { perror("sysctl"); goto out_free; } free(buf); buf = NULL; } } while (buf == NULL); len = needed; if (len < sizeof(uint32_t)) { perror("sysctl"); goto out_free; } p = (uint32_t *)buf; fmode = *p++; len -= sizeof(uint32_t); modestr = inm_mode(fmode); if (modestr) printf(" mode %s", modestr); else printf(" mode (%u)", fmode); if (vflag == 0) goto out_free; cnt = len / sizeof(struct in6_addr); pina = (struct in6_addr *)p; for (i = 0; i < cnt; i++) { if (i == 0) printf(" srcs "); inet_ntop(AF_INET6, (const char *)pina++, addrbuf, INET6_ADDRSTRLEN); fprintf(stdout, "%s%s", (i == 0 ? "" : ","), addrbuf); len -= sizeof(struct in6_addr); } if (len > 0) { fprintf(stderr, "warning: %u trailing bytes from %s\n", (unsigned int)len, "net.inet6.ip6.mcast.filters"); } out_free: free(buf); #undef MAX_SYSCTL_TRY } #endif /* INET6 */ static int ifmcstat_getifmaddrs(void) { char thisifname[IFNAMSIZ]; char addrbuf[NI_MAXHOST]; struct ifaddrs *ifap, *ifa; struct ifmaddrs *ifmap, *ifma; sockunion_t lastifasa; sockunion_t *psa, *pgsa, *pllsa, *pifasa; char *pcolon; char *pafname; uint32_t lastifindex, thisifindex; int error; error = 0; ifap = NULL; ifmap = NULL; lastifindex = 0; thisifindex = 0; lastifasa.ss.ss_family = AF_UNSPEC; if (getifaddrs(&ifap) != 0) { warn("getifmaddrs"); return (-1); } if (getifmaddrs(&ifmap) != 0) { warn("getifmaddrs"); error = -1; goto out; } for (ifma = ifmap; ifma; ifma = ifma->ifma_next) { error = 0; if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL) continue; psa = (sockunion_t *)ifma->ifma_name; if (psa->sa.sa_family != AF_LINK) { fprintf(stderr, "WARNING: Kernel returned invalid data.\n"); error = -1; break; } /* Filter on interface name. */ thisifindex = psa->sdl.sdl_index; if (ifindex != 0 && thisifindex != ifindex) continue; /* Filter on address family. */ pgsa = (sockunion_t *)ifma->ifma_addr; if (af != 0 && pgsa->sa.sa_family != af) continue; strlcpy(thisifname, link_ntoa(&psa->sdl), IFNAMSIZ); pcolon = strchr(thisifname, ':'); if (pcolon) *pcolon = '\0'; /* Only print the banner for the first ifmaddrs entry. */ if (lastifindex == 0 || lastifindex != thisifindex) { lastifindex = thisifindex; fprintf(stdout, "%s:\n", thisifname); } /* * Currently, multicast joins only take place on the * primary IPv4 address, and only on the link-local IPv6 * address, as per IGMPv2/3 and MLDv1/2 semantics. * Therefore, we only look up the primary address on * the first pass. */ pifasa = NULL; for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if ((strcmp(ifa->ifa_name, thisifname) != 0) || (ifa->ifa_addr == NULL) || (ifa->ifa_addr->sa_family != pgsa->sa.sa_family)) continue; /* * For AF_INET6 only the link-local address should * be returned. If built without IPv6 support, * skip this address entirely. */ pifasa = (sockunion_t *)ifa->ifa_addr; if (pifasa->sa.sa_family == AF_INET6 #ifdef INET6 && !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr) #endif ) { pifasa = NULL; continue; } break; } if (pifasa == NULL) continue; /* primary address not found */ if (!vflag && pifasa->sa.sa_family == AF_LINK) continue; /* Parse and print primary address, if not already printed. */ if (lastifasa.ss.ss_family == AF_UNSPEC || ((lastifasa.ss.ss_family == AF_LINK && !sa_dl_equal(&lastifasa.sa, &pifasa->sa)) || !sa_equal(&lastifasa.sa, &pifasa->sa))) { switch (pifasa->sa.sa_family) { case AF_INET: pafname = "inet"; break; case AF_INET6: pafname = "inet6"; break; case AF_LINK: pafname = "link"; break; default: pafname = "unknown"; break; } switch (pifasa->sa.sa_family) { case AF_INET6: #ifdef INET6 { const char *p = inet6_n2a(&pifasa->sin6.sin6_addr, pifasa->sin6.sin6_scope_id); strlcpy(addrbuf, p, sizeof(addrbuf)); break; } #else /* FALLTHROUGH */ #endif case AF_INET: case AF_LINK: error = getnameinfo(&pifasa->sa, pifasa->sa.sa_len, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); if (error) perror("getnameinfo"); break; default: addrbuf[0] = '\0'; break; } fprintf(stdout, "\t%s %s", pafname, addrbuf); #ifdef INET6 if (pifasa->sa.sa_family == AF_INET6 && pifasa->sin6.sin6_scope_id) fprintf(stdout, " scopeid 0x%x", pifasa->sin6.sin6_scope_id); #endif fprintf(stdout, "\n"); #ifdef INET /* * Print per-link IGMP information, if available. */ if (pifasa->sa.sa_family == AF_INET) { struct igmp_ifinfo igi; size_t mibsize, len; int mib[5]; mibsize = sizeof(mib) / sizeof(mib[0]); if (sysctlnametomib("net.inet.igmp.ifinfo", mib, &mibsize) == -1) { perror("sysctlnametomib"); goto next_ifnet; } mib[mibsize] = thisifindex; len = sizeof(struct igmp_ifinfo); if (sysctl(mib, mibsize + 1, &igi, &len, NULL, 0) == -1) { perror("sysctl net.inet.igmp.ifinfo"); goto next_ifnet; } in_ifinfo(&igi); } #endif /* INET */ #ifdef INET6 /* * Print per-link MLD information, if available. */ if (pifasa->sa.sa_family == AF_INET6) { struct mld_ifinfo mli; size_t mibsize, len; int mib[5]; mibsize = sizeof(mib) / sizeof(mib[0]); if (sysctlnametomib("net.inet6.mld.ifinfo", mib, &mibsize) == -1) { perror("sysctlnametomib"); goto next_ifnet; } mib[mibsize] = thisifindex; len = sizeof(struct mld_ifinfo); if (sysctl(mib, mibsize + 1, &mli, &len, NULL, 0) == -1) { perror("sysctl net.inet6.mld.ifinfo"); goto next_ifnet; } in6_ifinfo(&mli); } #endif /* INET6 */ #if defined(INET) || defined(INET6) next_ifnet: #endif lastifasa = *pifasa; } /* Print this group address. */ #ifdef INET6 if (pgsa->sa.sa_family == AF_INET6) { const char *p = inet6_n2a(&pgsa->sin6.sin6_addr, pgsa->sin6.sin6_scope_id); strlcpy(addrbuf, p, sizeof(addrbuf)); } else #endif { error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); if (error) perror("getnameinfo"); } fprintf(stdout, "\t\tgroup %s", addrbuf); #ifdef INET6 if (pgsa->sa.sa_family == AF_INET6 && pgsa->sin6.sin6_scope_id) fprintf(stdout, " scopeid 0x%x", pgsa->sin6.sin6_scope_id); #endif #ifdef INET if (pgsa->sa.sa_family == AF_INET) { inm_print_sources_sysctl(thisifindex, pgsa->sin.sin_addr); } #endif #ifdef INET6 if (pgsa->sa.sa_family == AF_INET6) { in6m_print_sources_sysctl(thisifindex, &pgsa->sin6.sin6_addr); } #endif fprintf(stdout, "\n"); /* Link-layer mapping, if present. */ pllsa = (sockunion_t *)ifma->ifma_lladdr; if (pllsa != NULL) { error = getnameinfo(&pllsa->sa, pllsa->sa.sa_len, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); fprintf(stdout, "\t\t\tmcast-macaddr %s\n", addrbuf); } } out: if (ifmap != NULL) freeifmaddrs(ifmap); if (ifap != NULL) freeifaddrs(ifap); return (error); } diff --git a/usr.sbin/ip6addrctl/ip6addrctl.c b/usr.sbin/ip6addrctl/ip6addrctl.c index 6a730ff1fc30..d9bf89de68b7 100644 --- a/usr.sbin/ip6addrctl/ip6addrctl.c +++ b/usr.sbin/ip6addrctl/ip6addrctl.c @@ -1,457 +1,456 @@ /* $KAME: ip6addrctl.c,v 1.3 2003/12/16 08:14:28 suz Exp $ */ /* * Copyright (C) 2001 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include static char *configfile; struct policyqueue { TAILQ_ENTRY(policyqueue) pc_entry; struct in6_addrpolicy pc_policy; }; TAILQ_HEAD(policyhead, policyqueue); static struct policyhead policyhead; static void usage(void); static void get_policy(void); static void dump_policy(void); static int mask2plen(struct sockaddr_in6 *); static int parse_prefix(const char *, struct in6_addrpolicy *); static void make_policy_fromfile(char *); static void plen2mask(struct sockaddr_in6 *, int); static void set_policy(void); static void add_policy(char *, char *, char *); static void delete_policy(char *); static void flush_policy(void); int main(int argc, char *argv[]) { TAILQ_INIT(&policyhead); if (argc == 1 || strcasecmp(argv[1], "show") == 0) { get_policy(); dump_policy(); } else if (strcasecmp(argv[1], "add") == 0) { if (argc < 5) usage(); add_policy(argv[2], argv[3], argv[4]); } else if (strcasecmp(argv[1], "delete") == 0) { if (argc < 3) usage(); delete_policy(argv[2]); } else if (strcasecmp(argv[1], "flush") == 0) { get_policy(); flush_policy(); } else if (strcasecmp(argv[1], "install") == 0) { if (argc < 3) usage(); configfile = argv[2]; make_policy_fromfile(configfile); set_policy(); } else usage(); exit(0); } static void get_policy(void) { int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; size_t l; struct in6_addrpolicy *buf; struct in6_addrpolicy *pol, *ep; if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { err(1, "sysctl(IPV6CTL_ADDRCTLPOLICY)"); /* NOTREACHED */ } if (l == 0) { printf("no source-address-selection policy is installed\n"); return; } if ((buf = malloc(l)) == NULL) { errx(1, "malloc failed"); /* NOTREACHED */ } if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { err(1, "sysctl(IPV6CTL_ADDRCTLPOLICY)"); /* NOTREACHED */ } ep = buf + l/sizeof(*buf); for (pol = buf; pol + 1 <= ep; pol++) { struct policyqueue *new; if ((new = malloc(sizeof(*new))) == NULL) errx(1, "malloc failed\n"); new->pc_policy = *pol; TAILQ_INSERT_TAIL(&policyhead, new, pc_entry); } free(buf); } static void dump_policy(void) { size_t addrlen; char addrbuf[NI_MAXHOST]; struct in6_addrpolicy *pol; struct policyqueue *ent; int plen, first = 1; for (ent = TAILQ_FIRST(&policyhead); ent; ent = TAILQ_NEXT(ent, pc_entry)) { pol = &ent->pc_policy; if (first) { printf("%-30s %5s %5s %8s\n", "Prefix", "Prec", "Label", "Use"); first = 0; } if ((getnameinfo((struct sockaddr *)&pol->addr, sizeof(pol->addr), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST))) { warnx("getnameinfo for prefix address failed"); continue; } if ((plen = mask2plen(&pol->addrmask)) < 0) { warnx("invalid address mask"); continue; } addrlen = strlen(addrbuf); if (addrlen + sizeof("/128") < sizeof(addrbuf)) { snprintf(&addrbuf[addrlen], sizeof(addrbuf) - addrlen - 1, "/%d", plen); printf("%-30s", addrbuf); } else /* XXX */ printf("%s/%d", addrbuf, plen); printf(" %5d %5d %8llu\n", pol->preced, pol->label, (unsigned long long)pol->use); } } #define SKIP_WHITE(p, emptyok) \ do { \ while((*(p) == ' ' || *(p) == '\t')) \ (p)++; \ if ((*(p) == '\0' || (*(p) == '\n')) && !(emptyok)) \ goto bad; \ } while (0); #define SKIP_WORD(p) \ do { \ while(*(p) != ' ' && *(p) != '\t') \ (p)++; \ if (*(p) == '\0' || *(p) == '\n') \ goto bad; \ } while (0); static void make_policy_fromfile(char *conf) { char line[_POSIX2_LINE_MAX], *cp; char *addrstr; FILE *fp; int count = 0; struct in6_addrpolicy pol0; struct policyqueue *new; if ((fp = fopen(conf, "r")) == NULL) err(1, "fopen: %s", conf); while(fgets(line, sizeof(line), fp)) { count++; cp = line; memset(&pol0, 0, sizeof(pol0)); /* get prefix */ SKIP_WHITE(cp, 1); if (*cp == '\n') /* empty line */ continue; if (*cp == '#') continue; addrstr = cp; if (parse_prefix((const char *)addrstr, &pol0)) goto bad; /* get precedence value */ SKIP_WORD(cp); SKIP_WHITE(cp, 0); pol0.preced = atoi(cp); /* get label */ SKIP_WORD(cp); SKIP_WHITE(cp, 0); pol0.label = atoi(cp); /* parse succeeded. make a control buffer entry. */ if ((new = malloc(sizeof(*new))) == NULL) errx(1, "malloc failed\n"); memset(new, 0, sizeof(*new)); new->pc_policy = pol0; TAILQ_INSERT_TAIL(&policyhead, new, pc_entry); } fclose(fp); return; bad: errx(1, "parse failed at line %d", count); /* NOTREACHED */ } static int parse_prefix(const char *prefix0, struct in6_addrpolicy *pol) { int e = 0, plen; char *prefix, *plenstr; struct addrinfo hints, *res; if ((prefix = strdup(prefix0)) == NULL) errx(1, "strdup failed"); if ((plenstr = strchr(prefix, '/')) == NULL) { e = -1; goto end; } *plenstr = '\0'; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; hints.ai_family = AF_INET6; if ((e = getaddrinfo(prefix, NULL, &hints, &res)) != 0) { warnx("getaddrinfo failed for %s: %s", prefix, gai_strerror(e)); goto end; } memcpy(&pol->addr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); plen = atoi(plenstr + 1); if (plen < 0 || plen > 128) { warnx("invalid prefix length: %d", plen); e = -1; goto end; } plen2mask(&pol->addrmask, plen); end: free(prefix); return(e); } static void plen2mask(struct sockaddr_in6 *mask, int plen) { u_char *cp = (unsigned char *)&mask->sin6_addr; memset(mask, 0, sizeof(*mask)); mask->sin6_family = AF_INET6; /* just in case */ mask->sin6_len = sizeof(*mask); for(; plen >= 8; plen -= 8) *cp++ = 0xff; if (plen > 0) *cp = (0xff << (8 - plen)); } static void set_policy(void) { struct policyqueue *ent; int s; if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) err(1, "socket(UDP)"); for (ent = TAILQ_FIRST(&policyhead); ent; ent = TAILQ_NEXT(ent, pc_entry)) { if (ioctl(s, SIOCAADDRCTL_POLICY, &ent->pc_policy)) warn("ioctl(SIOCAADDRCTL_POLICY)"); } close(s); } static int mask2plen(struct sockaddr_in6 *mask) { int masklen, final = 0; u_char *p, *lim; masklen = 0; lim = (u_char *)(mask + 1); for (p = (u_char *)(&mask->sin6_addr); p < lim; p++) { if (final && *p) { goto bad; } switch (*p & 0xff) { case 0xff: masklen += 8; break; case 0xfe: masklen += 7; final++; break; case 0xfc: masklen += 6; final++; break; case 0xf8: masklen += 5; final++; break; case 0xf0: masklen += 4; final++; break; case 0xe0: masklen += 3; final++; break; case 0xc0: masklen += 2; final++; break; case 0x80: masklen += 1; final++; break; case 0x00: final++; break; default: goto bad; break; } } return(masklen); bad: return(-1); } static void add_policy(char *prefix, char *prec, char *label) { struct in6_addrpolicy p; int s; memset(&p, 0, sizeof(p)); if (parse_prefix((const char *)prefix, &p)) errx(1, "bad prefix: %s", prefix); p.preced = atoi(prec); p.label = atoi(label); if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) err(1, "socket(UDP)"); if (ioctl(s, SIOCAADDRCTL_POLICY, &p)) err(1, "ioctl(SIOCAADDRCTL_POLICY)"); close(s); } static void delete_policy(char *prefix) { struct in6_addrpolicy p; int s; memset(&p, 0, sizeof(p)); if (parse_prefix((const char *)prefix, &p)) errx(1, "bad prefix: %s", prefix); if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) err(1, "socket(UDP)"); if (ioctl(s, SIOCDADDRCTL_POLICY, &p)) err(1, "ioctl(SIOCDADDRCTL_POLICY)"); close(s); } static void flush_policy(void) { struct policyqueue *ent; int s; if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) err(1, "socket(UDP)"); for (ent = TAILQ_FIRST(&policyhead); ent; ent = TAILQ_NEXT(ent, pc_entry)) { if (ioctl(s, SIOCDADDRCTL_POLICY, &ent->pc_policy)) warn("ioctl(SIOCDADDRCTL_POLICY)"); } close(s); } static void usage(void) { fprintf(stderr, "usage: ip6addrctl [show]\n"); fprintf(stderr, " ip6addrctl add " "