diff options
author | 2000-11-11 00:45:38 +0000 | |
---|---|---|
committer | 2000-11-11 00:45:38 +0000 | |
commit | 8479702005f28106ec3dfbb085129e2cffa88135 (patch) | |
tree | 7a5ff3c484872040c3b18781e13e3b6e22a0e8d0 | |
parent | do not panic on "ifconfig lo0 inet6 fe80::1 -alias". KAME PR 295. (diff) | |
download | wireguard-openbsd-8479702005f28106ec3dfbb085129e2cffa88135.tar.xz wireguard-openbsd-8479702005f28106ec3dfbb085129e2cffa88135.zip |
improve spec conformance of node information query (07).
make sure to check scoped address right on PMTUD.
sync with kame.
-rw-r--r-- | sbin/ping6/ping6.8 | 12 | ||||
-rw-r--r-- | sbin/ping6/ping6.c | 186 | ||||
-rw-r--r-- | sys/netinet6/icmp6.c | 331 |
3 files changed, 371 insertions, 158 deletions
diff --git a/sbin/ping6/ping6.8 b/sbin/ping6/ping6.8 index 2ccb33a77c3..89881035271 100644 --- a/sbin/ping6/ping6.8 +++ b/sbin/ping6/ping6.8 @@ -1,5 +1,5 @@ -.\" $OpenBSD: ping6.8,v 1.12 2000/08/13 20:17:00 itojun Exp $ -.\" $KAME: ping6.8,v 1.27 2000/08/11 04:38:35 itojun Exp $ +.\" $OpenBSD: ping6.8,v 1.13 2000/11/11 00:45:38 itojun Exp $ +.\" $KAME: ping6.8,v 1.31 2000/11/11 00:40:56 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -183,7 +183,7 @@ option. If .Ar preload is specified, -.Nm ping +.Nm sends that many packets as fast as possible before falling into its normal mode of behavior. Only the super-user may use this option. @@ -341,7 +341,7 @@ during normal operations or from automated scripts. .\" If less than eight bytes of pad are specified, no round trip times are .\" given. .Sh DUPLICATE AND DAMAGED PACKETS -.Nm Ping6 +.Nm will report duplicate and damaged packets. Duplicate packets should never occur when pinging a unicast address, and seem to be caused by @@ -356,7 +356,7 @@ to the same request. .Pp Damaged packets are obviously serious cause for alarm and often indicate broken hardware somewhere in the -.Nm ping +.Nm packet's path .Pq in the network or in the hosts . .Sh TRYING DIFFERENT DATA PATTERNS @@ -415,7 +415,7 @@ and non-zero if the arguments are incorrect or the host is not responding. .Re .Sh HISTORY The -.Nm ping +.Xr ping 8 command appeared in .Bx 4.3 . The diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c index 893e300344d..2d292dc0ee5 100644 --- a/sbin/ping6/ping6.c +++ b/sbin/ping6/ping6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ping6.c,v 1.16 2000/11/10 18:12:07 itojun Exp $ */ +/* $OpenBSD: ping6.c,v 1.17 2000/11/11 00:45:38 itojun Exp $ */ /* $KAME: ping6.c,v 1.99 2000/11/08 09:55:45 itojun Exp $ */ /* @@ -252,6 +252,7 @@ void pinger __P((void)); const char *pr_addr __P((struct sockaddr_in6 *)); void pr_icmph __P((struct icmp6_hdr *, u_char *)); void pr_iph __P((struct ip6_hdr *)); +void pr_suptypes __P((struct icmp6_nodeinfo *, size_t)); void pr_nodeaddr __P((struct icmp6_nodeinfo *, int)); int myechoreply __P((const struct icmp6_hdr *)); int mynireply __P((const struct icmp6_nodeinfo *)); @@ -261,6 +262,7 @@ void pr_pack __P((u_char *, int, struct msghdr *)); void pr_exthdrs __P((struct msghdr *)); void pr_ip6opt __P((void *)); void pr_rthdr __P((void *)); +int pr_bitrange __P((u_int32_t, int, int)); void pr_retip __P((struct ip6_hdr *, u_char *)); void summary __P((void)); void tvsub __P((struct timeval *, struct timeval *)); @@ -308,15 +310,16 @@ main(argc, argv) preload = 0; datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; #ifndef IPSEC - while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:tvwW")) != EOF) +#define ADDOPTS #else #ifdef IPSEC_POLICY_IPSEC - while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:tvwWP:")) != EOF) +#define ADDOPTS "P:" #else - while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:tvwWAE")) != EOF) +#define ADDOPTS "AE" #endif /*IPSEC_POLICY_IPSEC*/ #endif - { + while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:tvwW" ADDOPTS)) != EOF) { +#undef ADDOPTS switch (ch) { case 'a': { @@ -1082,7 +1085,8 @@ pinger() icp->icmp6_type = ICMP6_NI_QUERY; icp->icmp6_code = ICMP6_NI_SUBJ_FQDN; /*empty*/ nip->ni_qtype = htons(NI_QTYPE_SUPTYPES); - nip->ni_flags = 0; /* do not support compressed bitmap */ + /* we support compressed bitmap */ + nip->ni_flags = NI_SUPTYPE_FLAG_COMPRESS; memcpy(nip->icmp6_ni_nonce, nonce, sizeof(nip->icmp6_ni_nonce)); *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); @@ -1358,27 +1362,7 @@ pr_pack(buf, cc, mhdr) printf("NodeInfo NOOP"); break; case NI_QTYPE_SUPTYPES: - printf("NodeInfo Supported Qtypes"); - if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0) { - printf(", compressed bitmap"); - break; - } else { - size_t clen; - u_int32_t v; - cp = (u_char *)(ni + 1); - clen = (size_t)(end - cp); - if (clen == 0 || clen > 8192 || clen % 4) { - printf(", invalid length(%lu)", - (u_long)clen); - break; - } - printf(", bitmap = 0x"); - for (dp = end - 4; dp >= cp; dp -= 4) { - memcpy(&v, dp, sizeof(v)); - v = (u_int32_t)ntohl(v); - printf("%08x", v); - } - } + pr_suptypes(ni, end - (u_char *)ni); break; case NI_QTYPE_NODEADDR: pr_nodeaddr(ni, end - (u_char *)ni); @@ -1638,14 +1622,120 @@ pr_rthdr(void *extbuf) } #endif /* USE_RFC2292BIS */ +int +pr_bitrange(v, s, ii) + u_int32_t v; + int s; + int ii; +{ + int off; + int i; + + off = 0; + while (off < 32) { + /* shift till we have 0x01 */ + if ((v & 0x01) == 0) { + if (ii > 1) + printf("-%u", s + off - 1); + ii = 0; + switch (v & 0x0f) { + case 0x00: + v >>= 4; off += 4; continue; + case 0x08: + v >>= 3; off += 3; continue; + case 0x04: case 0x0c: + v >>= 2; off += 2; continue; + default: + v >>= 1; off += 1; continue; + } + } + + /* we have 0x01 with us */ + for (i = 0; i < 32 - off; i++) { + if ((v & (0x01 << i)) == 0) + break; + } + if (!ii) + printf(" %u", s + off); + ii += i; + v >>= i; off += i; + } + return ii; +} + +void +pr_suptypes(ni, nilen) + struct icmp6_nodeinfo *ni; /* ni->qtype must be SUPTYPES */ + size_t nilen; +{ + size_t clen; + u_int32_t v; + const u_char *cp, *end; + u_int16_t cur; + struct cbit { + u_int16_t words; /*32bit count*/ + u_int16_t skip; + } cbit; +#define MAXQTYPES (1 << 16) + size_t off; + int b; + + cp = (u_char *)(ni + 1); + end = ((u_char *)ni) + nilen; + cur = 0; + b = 0; + + printf("NodeInfo Supported Qtypes"); + if (options & F_VERBOSE) { + if (ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) + printf(", compressed bitmap"); + else + printf(", raw bitmap"); + } + + while (cp < end) { + clen = (size_t)(end - cp); + if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) == 0) { + if (clen == 0 || clen > MAXQTYPES / 8 || + clen % sizeof(v)) { + printf("???"); + return; + } + } else { + if (clen < sizeof(cbit) || clen % sizeof(v)) + return; + memcpy(&cbit, cp, sizeof(cbit)); + if (sizeof(cbit) + ntohs(cbit.words) * sizeof(v) > clen) + return; + cp += sizeof(cbit); + clen = ntohs(cbit.words) * sizeof(v); + if (cur + clen * 8 + (u_long)ntohs(cbit.skip) * 32 > MAXQTYPES) + return; + } + + for (off = 0; off < clen; off += sizeof(v)) { + memcpy(&v, cp + off, sizeof(v)); + v = (u_int32_t)ntohl(v); + b = pr_bitrange(v, (int)(cur + off * 8), b); + } + /* flush the remaining bits */ + b = pr_bitrange(0, (int)(cur + off * 8), b); + + cp += clen; + cur += clen * 8; + if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0) + cur += ntohs(cbit.skip) * 32; + } +} void pr_nodeaddr(ni, nilen) struct icmp6_nodeinfo *ni; /* ni->qtype must be NODEADDR */ int nilen; { - struct in6_addr *ia6 = (struct in6_addr *)(ni + 1); + u_char *cp = (u_char *)(ni + 1); char ntop_buf[INET6_ADDRSTRLEN]; + int withttl = 0; nilen -= sizeof(struct icmp6_nodeinfo); @@ -1664,9 +1754,43 @@ pr_nodeaddr(ni, nilen) putchar('\n'); if (nilen <= 0) printf(" no address\n"); - for (; nilen > 0; nilen -= sizeof(*ia6), ia6 += 1) { - printf(" %s\n", - inet_ntop(AF_INET6, ia6, ntop_buf, sizeof(ntop_buf))); + + /* + * In icmp-name-lookups 05 and later, TTL of each returned address + * is contained in the resposne. We try to detect the version + * by the length of the data, but note that the detection algorithm + * is incomplete. We assume the latest draft by default. + */ + if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0) + withttl = 1; + while (nilen > 0) { + u_int32_t ttl; + + if (withttl) { + ttl = ntohl(*(u_int32_t *)cp); /* XXX: alignment? */ + cp += sizeof(u_int32_t); + nilen -= sizeof(u_int32_t); + } + + if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) == + NULL) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + printf(" %s", ntop_buf); + if (withttl) { + if (ttl == 0xffffffff) { + /* + * XXX: can this convention be applied to all + * type of TTL (i.e. non-ND TTL)? + */ + printf("(TTL=infty)"); + } + else + printf("(TTL=%u)", ttl); + } + putchar('\n'); + + nilen -= sizeof(struct in6_addr); + cp += sizeof(struct in6_addr); } } diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index d54f195dfdf..52c8fb72b94 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1,5 +1,5 @@ -/* $OpenBSD: icmp6.c,v 1.24 2000/10/10 15:53:08 itojun Exp $ */ -/* $KAME: icmp6.c,v 1.147 2000/10/10 15:35:47 itojun Exp $ */ +/* $OpenBSD: icmp6.c,v 1.25 2000/11/11 00:45:39 itojun Exp $ */ +/* $KAME: icmp6.c,v 1.156 2000/10/19 19:21:07 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -125,7 +125,7 @@ static struct mbuf *ni6_input __P((struct mbuf *, int)); static struct mbuf *ni6_nametodns __P((const char *, int, int)); static int ni6_dnsmatch __P((const char *, int, const char *, int)); static int ni6_addrs __P((struct icmp6_nodeinfo *, struct mbuf *, - struct ifnet **)); + struct ifnet **, char *)); static int ni6_store_addrs __P((struct icmp6_nodeinfo *, struct icmp6_nodeinfo *, struct ifnet *, int)); static struct rtentry *icmp6_mtudisc_clone __P((struct sockaddr *)); @@ -1010,6 +1010,11 @@ icmp6_mtudisc_update(dst, icmp6, m) sin6.sin6_family = PF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_addr = *dst; + /* XXX normally, this won't happen */ + if (IN6_IS_ADDR_LINKLOCAL(dst)) { + sin6.sin6_addr.s6_addr16[1] = + htons(m->m_pkthdr.rcvif->if_index); + } /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */ rt = rtalloc1((struct sockaddr *)&sin6, 1); /*clone*/ if (!rt || (rt->rt_flags & RTF_HOST) == 0) { @@ -1034,7 +1039,7 @@ icmp6_mtudisc_update(dst, icmp6, m) /* * Process a Node Information Query packet, based on - * draft-ietf-ipngwg-icmp-name-lookups-06. + * draft-ietf-ipngwg-icmp-name-lookups-07. * * Spec incompatibilities: * - IPv6 Subject address handling @@ -1059,10 +1064,10 @@ ni6_input(m, off) struct ni_reply_fqdn *fqdn; int addrs; /* for NI_QTYPE_NODEADDR */ struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */ - struct sockaddr_in6 sin6; + struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */ struct ip6_hdr *ip6; int oldfqdn = 0; /* if 1, return pascal string (03 draft) */ - char *subj; + char *subj = NULL; ip6 = mtod(m, struct ip6_hdr *); #ifndef PULLDOWN_TEST @@ -1078,9 +1083,10 @@ ni6_input(m, off) /* * Validate IPv6 destination address. * - * We accept packets with the following IPv6 destination address: - * - Responder's unicast/anycast address, and - * - link-local multicast address (including NI group address) + * The Responder must discard the Query without further processing + * unless it is one of the Responder's unicast or anycast addresses, or + * a link-local scope multicast address which the Responder has joined. + * [icmp-name-lookups-07, Section 4.] */ bzero(&sin6, sizeof(sin6)); sin6.sin6_family = AF_INET6; @@ -1088,52 +1094,19 @@ ni6_input(m, off) bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); /* XXX scopeid */ if (ifa_ifwithaddr((struct sockaddr *)&sin6)) - ; /*unicast/anycast, fine*/ + ; /* unicast/anycast, fine */ else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) - ; /*violates spec slightly, see above*/ + ; /* link-local multicast, fine */ else goto bad; - /* guess reply length */ - qtype = ntohs(ni6->ni_qtype); - switch (qtype) { - case NI_QTYPE_NOOP: - break; /* no reply data */ - case NI_QTYPE_SUPTYPES: - replylen += sizeof(u_int32_t); - break; - case NI_QTYPE_FQDN: - /* XXX will append a mbuf */ - replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); - break; - case NI_QTYPE_NODEADDR: - addrs = ni6_addrs(ni6, m, &ifp); - if ((replylen += addrs * sizeof(struct in6_addr)) > MCLBYTES) - replylen = MCLBYTES; /* XXX: we'll truncate later */ - break; - default: - /* - * XXX: We must return a reply with the ICMP6 code - * `unknown Qtype' in this case. However we regard the case - * as an FQDN query for backward compatibility. - * Older versions set a random value to this field, - * so it rarely varies in the defined qtypes. - * But the mechanism is not reliable... - * maybe we should obsolete older versions. - */ - qtype = NI_QTYPE_FQDN; - /* XXX will append a mbuf */ - replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); - oldfqdn++; - break; - } - /* validate query Subject field. */ + qtype = ntohs(ni6->ni_qtype); subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo); switch (qtype) { case NI_QTYPE_NOOP: case NI_QTYPE_SUPTYPES: - /* 06 draft */ + /* 07 draft */ if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0) break; /*FALLTHROUGH*/ @@ -1193,8 +1166,10 @@ ni6_input(m, off) } #endif } + subj = (char *)&sin6; if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6.sin6_addr)) break; + /* * XXX if we are to allow other cases, we should really * be careful about scope here. @@ -1232,14 +1207,48 @@ ni6_input(m, off) n = NULL; break; - case ICMP6_NI_SUBJ_IPV4: /* xxx: to be implemented? */ + case ICMP6_NI_SUBJ_IPV4: /* XXX: to be implemented? */ default: goto bad; } break; } - /* allocate a mbuf to reply. */ + /* guess reply length */ + switch (qtype) { + case NI_QTYPE_NOOP: + break; /* no reply data */ + case NI_QTYPE_SUPTYPES: + replylen += sizeof(u_int32_t); + break; + case NI_QTYPE_FQDN: + /* XXX will append an mbuf */ + replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); + break; + case NI_QTYPE_NODEADDR: + addrs = ni6_addrs(ni6, m, &ifp, subj); + if ((replylen += addrs * (sizeof(struct in6_addr) + + sizeof(u_int32_t))) > MCLBYTES) + replylen = MCLBYTES; /* XXX: will truncate pkt later */ + break; + default: + /* + * XXX: We must return a reply with the ICMP6 code + * `unknown Qtype' in this case. However we regard the case + * as an FQDN query for backward compatibility. + * Older versions set a random value to this field, + * so it rarely varies in the defined qtypes. + * But the mechanism is not reliable... + * maybe we should obsolete older versions. + */ + qtype = NI_QTYPE_FQDN; + /* XXX will append an mbuf */ + replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen); + oldfqdn++; + break; + } + + /* allocate an mbuf to reply. */ MGETHDR(n, M_DONTWAIT, m->m_type); if (n == NULL) { m_freem(m); @@ -1249,8 +1258,8 @@ ni6_input(m, off) if (replylen > MHLEN) { if (replylen > MCLBYTES) { /* - * XXX: should we try to allocate more? But MCLBYTES is - * probably much larger than IPV6_MMTU... + * XXX: should we try to allocate more? But MCLBYTES + * is probably much larger than IPV6_MMTU... */ goto bad; } @@ -1497,16 +1506,34 @@ ni6_dnsmatch(a, alen, b, blen) * calculate the number of addresses to be returned in the node info reply. */ static int -ni6_addrs(ni6, m, ifpp) +ni6_addrs(ni6, m, ifpp, subj) struct icmp6_nodeinfo *ni6; struct mbuf *m; struct ifnet **ifpp; + char *subj; { register struct ifnet *ifp; register struct in6_ifaddr *ifa6; register struct ifaddr *ifa; - struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */ int addrs = 0, addrsofif, iffound = 0; + int niflags = ni6->ni_flags; + + if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) { + switch(ni6->ni_code) { + case ICMP6_NI_SUBJ_IPV6: + if (subj == NULL) /* must be impossible... */ + return(0); + subj_ip6 = (struct sockaddr_in6 *)subj; + break; + default: + /* + * XXX: we only support IPv6 subject address for + * this Qtype. + */ + return(0); + } + } for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { @@ -1518,8 +1545,8 @@ ni6_addrs(ni6, m, ifpp) continue; ifa6 = (struct in6_ifaddr *)ifa; - if (!(ni6->ni_flags & NI_NODEADDR_FLAG_ALL) && - IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, + if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 && + IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr, &ifa6->ia_addr.sin6_addr)) iffound = 1; @@ -1528,36 +1555,41 @@ ni6_addrs(ni6, m, ifpp) * Node Information proxy, since they represent * addresses of IPv4-only nodes, which perforce do * not implement this protocol. - * [icmp-name-lookups-05] + * [icmp-name-lookups-07, Section 5.4] * So we don't support NI_NODEADDR_FLAG_COMPAT in * this function at this moment. */ - if (ifa6->ia6_flags & IN6_IFF_ANYCAST) - continue; /* we need only unicast addresses */ - - if ((ni6->ni_flags & (NI_NODEADDR_FLAG_LINKLOCAL | - NI_NODEADDR_FLAG_SITELOCAL | - NI_NODEADDR_FLAG_GLOBAL)) == 0) - continue; - /* What do we have to do about ::1? */ switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) { - case IPV6_ADDR_SCOPE_LINKLOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL) - addrsofif++; + case IPV6_ADDR_SCOPE_LINKLOCAL: + if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) + == 0) + continue; break; - case IPV6_ADDR_SCOPE_SITELOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL) - addrsofif++; + case IPV6_ADDR_SCOPE_SITELOCAL: + if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) + == 0) + continue; + break; + case IPV6_ADDR_SCOPE_GLOBAL: + if ((niflags & NI_NODEADDR_FLAG_GLOBAL) + == 0) + continue; break; - case IPV6_ADDR_SCOPE_GLOBAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL) - addrsofif++; - break; - default: - continue; + default: + continue; } + + /* + * check if anycast is okay. + * XXX: just experimental. not in the spec. + */ + if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 && + (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) + continue; /* we need only unicast addresses */ + + addrsofif++; /* count the address */ } if (iffound) { *ifpp = ifp; @@ -1579,79 +1611,136 @@ ni6_store_addrs(ni6, nni6, ifp0, resid) register struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); register struct in6_ifaddr *ifa6; register struct ifaddr *ifa; - int docopy, copied = 0; + struct ifnet *ifp_dep = NULL; + int copied = 0, allow_deprecated = 0; u_char *cp = (u_char *)(nni6 + 1); + int niflags = ni6->ni_flags; + u_int32_t ltime; + long time_second = time.tv_sec; - if (ifp0 == NULL && !(ni6->ni_flags & NI_NODEADDR_FLAG_ALL)) + if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL)) return(0); /* needless to copy */ + again: + for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) { for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { - docopy = 0; - if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifa6 = (struct in6_ifaddr *)ifa; - if (ifa6->ia6_flags & IN6_IFF_ANYCAST) { - /* just experimental. not in the spec. */ - if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST) - docopy = 1; - else - continue; - } - else { /* unicast address */ - if (ni6->ni_flags & NI_NODEADDR_FLAG_ANYCAST) - continue; - else - docopy = 1; + if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) != 0 && + allow_deprecated == 0) { + /* + * prefererred address should be put before + * deprecated addresses. + */ + + /* record the interface for later search */ + if (ifp_dep == NULL) + ifp_dep = ifp; + + continue; } + else if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0 && + allow_deprecated != 0) + continue; /* we now collect deprecated addrs */ /* What do we have to do about ::1? */ switch(in6_addrscope(&ifa6->ia_addr.sin6_addr)) { - case IPV6_ADDR_SCOPE_LINKLOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_LINKLOCAL) - docopy = 1; + case IPV6_ADDR_SCOPE_LINKLOCAL: + if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) + == 0) + continue; break; - case IPV6_ADDR_SCOPE_SITELOCAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_SITELOCAL) - docopy = 1; + case IPV6_ADDR_SCOPE_SITELOCAL: + if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) + == 0) + continue; + break; + case IPV6_ADDR_SCOPE_GLOBAL: + if ((niflags & NI_NODEADDR_FLAG_GLOBAL) + == 0) + continue; break; - case IPV6_ADDR_SCOPE_GLOBAL: - if (ni6->ni_flags & NI_NODEADDR_FLAG_GLOBAL) - docopy = 1; - break; - default: - continue; + default: + continue; } - if (docopy) { - if (resid < sizeof(struct in6_addr)) { - /* - * We give up much more copy. - * Set the truncate flag and return. - */ - nni6->ni_flags |= - NI_NODEADDR_FLAG_TRUNCATE; - return(copied); - } - bcopy(&ifa6->ia_addr.sin6_addr, cp, - sizeof(struct in6_addr)); - /* XXX: KAME link-local hack; remove ifindex */ - if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr)) - ((struct in6_addr *)cp)->s6_addr16[1] = 0; - cp += sizeof(struct in6_addr); - resid -= sizeof(struct in6_addr); - copied += sizeof(struct in6_addr); + /* + * check if anycast is okay. + * XXX: just experimental. not in the spec. + */ + if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 && + (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0) + continue; + + /* now we can copy the address */ + if (resid < sizeof(struct in6_addr) + + sizeof(u_int32_t)) { + /* + * We give up much more copy. + * Set the truncate flag and return. + */ + nni6->ni_flags |= + NI_NODEADDR_FLAG_TRUNCATE; + return(copied); } + + /* + * Set the TTL of the address. + * The TTL value should be one of the following + * according to the specification: + * + * 1. The remaining lifetime of a DHCP lease on the + * address, or + * 2. The remaining Valid Lifetime of a prefix from + * which the address was derived through Stateless + * Autoconfiguration. + * + * Note that we currently do not support stateful + * address configuration by DHCPv6, so the former + * case can't happen. + */ + if (ifa6->ia6_lifetime.ia6t_expire == 0) + ltime = ND6_INFINITE_LIFETIME; + else { + if (ifa6->ia6_lifetime.ia6t_expire > + time_second) + ltime = htonl(ifa6->ia6_lifetime.ia6t_expire - time_second); + else + ltime = 0; + } + + bcopy(<ime, cp, sizeof(u_int32_t)); + cp += sizeof(u_int32_t); + + /* copy the address itself */ + bcopy(&ifa6->ia_addr.sin6_addr, cp, + sizeof(struct in6_addr)); + /* XXX: KAME link-local hack; remove ifindex */ + if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr)) + ((struct in6_addr *)cp)->s6_addr16[1] = 0; + cp += sizeof(struct in6_addr); + + resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t)); + copied += (sizeof(struct in6_addr) + + sizeof(u_int32_t)); } if (ifp0) /* we need search only on the specified IF */ break; } + if (allow_deprecated == 0 && ifp_dep != NULL) { + ifp = ifp_dep; + allow_deprecated = 1; + + goto again; + } + return(copied); } |