📄 icmp6.c
字号:
if (a[0] != b[0])
return 0;
l = a[0];
if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen)
return 0;
if (bcmp(a + 1, b + 1, l) != 0)
return 0;
a += 1 + l;
b += 1 + l;
}
if (a - a0 == alen && b - b0 == blen)
return 1;
else
return 0;
}
/*
* calculate the number of addresses to be returned in the node info reply.
*/
static int
ni6_addrs(ni6, m, ifpp, subj)
struct icmp6_nodeinfo *ni6;
struct mbuf *m;
struct ifnet **ifpp;
char *subj;
{
struct ifnet *ifp;
struct in6_ifaddr *ifa6;
struct ifaddr *ifa;
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);
}
}
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
for (ifp = ifnet; ifp; ifp = ifp->if_next)
#else
for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
#endif
{
addrsofif = 0;
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
#else
for (ifa = ifp->if_addrlist.tqh_first; ifa;
ifa = ifa->ifa_list.tqe_next)
#endif
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ifa6 = (struct in6_ifaddr *)ifa;
if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 &&
IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr,
&ifa6->ia_addr.sin6_addr))
iffound = 1;
/*
* IPv4-mapped addresses can only be returned by a
* Node Information proxy, since they represent
* addresses of IPv4-only nodes, which perforce do
* not implement this protocol.
* [icmp-name-lookups-07, Section 5.4]
* So we don't support NI_NODEADDR_FLAG_COMPAT in
* this function at this moment.
*/
/* What do we have to do about ::1? */
switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
case IPV6_ADDR_SCOPE_LINKLOCAL:
if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
continue;
break;
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;
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 */
if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
(icmp6_nodeinfo & 4) == 0) {
continue;
}
addrsofif++; /* count the address */
}
if (iffound) {
*ifpp = ifp;
return(addrsofif);
}
addrs += addrsofif;
}
return(addrs);
}
static int
ni6_store_addrs(ni6, nni6, ifp0, resid)
struct icmp6_nodeinfo *ni6, *nni6;
struct ifnet *ifp0;
int resid;
{
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
struct ifnet *ifp = ifp0 ? ifp0 : ifnet;
#else
struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet);
#endif
struct in6_ifaddr *ifa6;
struct ifaddr *ifa;
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;
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
long time_second = time.tv_sec;
#endif
if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL))
return(0); /* needless to copy */
again:
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
for (; ifp; ifp = ifp->if_next)
#else
for (; ifp; ifp = TAILQ_NEXT(ifp, if_list))
#endif
{
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
#else
for (ifa = ifp->if_addrlist.tqh_first; ifa;
ifa = ifa->ifa_list.tqe_next)
#endif
{
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ifa6 = (struct in6_ifaddr *)ifa;
if (IFA6_IS_DEPRECATED(ifa6) &&
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_IS_DEPRECATED(ifa6) &&
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 ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
continue;
break;
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;
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;
if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
(icmp6_nodeinfo & 4) == 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.
*
* TTL must be 2^31 > TTL >= 0.
*/
if (ifa6->ia6_lifetime.ia6t_expire == 0)
ltime = ND6_INFINITE_LIFETIME;
else {
if (ifa6->ia6_lifetime.ia6t_expire >
time_second) {
ltime = ifa6->ia6_lifetime.ia6t_expire
- time_second;
} else
ltime = 0;
}
if (ltime > 0x7fffffff)
ltime = 0x7fffffff;
ltime = htonl(ltime);
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);
}
/*
* XXX almost dup'ed code with rip6_input.
*/
static int
icmp6_rip6_input(mp, off)
struct mbuf **mp;
int off;
{
struct mbuf *m = *mp;
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
struct in6pcb *in6p;
struct in6pcb *last = NULL;
struct sockaddr_in6 rip6src;
struct icmp6_hdr *icmp6;
struct ip6_recvpktopts opts;
#ifndef PULLDOWN_TEST
/* this is assumed to be safe. */
icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
#else
IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
if (icmp6 == NULL) {
/* m is already reclaimed */
return IPPROTO_DONE;
}
#endif
bzero(&opts, sizeof(opts));
bzero(&rip6src, sizeof(rip6src));
rip6src.sin6_len = sizeof(struct sockaddr_in6);
rip6src.sin6_family = AF_INET6;
/* KAME hack: recover scopeid */
(void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif);
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
LIST_FOREACH(in6p, &ripcb, inp_list)
#elif defined(__OpenBSD__)
for (in6p = rawin6pcbtable.inpt_queue.cqh_first;
in6p != (struct inpcb *)&rawin6pcbtable.inpt_queue;
in6p = in6p->inp_queue.cqe_next)
#else
for (in6p = rawin6pcb.in6p_next;
in6p != &rawin6pcb; in6p = in6p->in6p_next)
#endif
{
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
if ((in6p->inp_vflag & INP_IPV6) == 0)
continue;
#endif
#ifdef HAVE_NRL_INPCB
if (!(in6p->in6p_flags & INP_IPV6))
continue;
#endif
if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6)
continue;
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
continue;
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
continue;
if (in6p->in6p_icmp6filt
&& ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
in6p->in6p_icmp6filt))
continue;
if (last) {
struct mbuf *n;
if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
if (last->in6p_flags & IN6P_CONTROLOPTS)
ip6_savecontrol(last, ip6, n, &opts,
NULL);
/* strip intermediate headers */
m_adj(n, off);
if (sbappendaddr(&last->in6p_socket->so_rcv,
(struct sockaddr *)&rip6src,
n, opts.head) == 0) {
/* should notify about lost packet */
m_freem(n);
if (opts.head) {
m_freem(opts.head);
}
} else
sorwakeup(last->in6p_socket);
bzero(&opts, sizeof(opts));
}
}
last = in6p;
}
if (last) {
if (last->in6p_flags & IN6P_CONTROLOPTS)
ip6_savecontrol(last, ip6, m, &opts, NULL);
/* strip intermediate headers */
m_adj(m, off);
if (sbappendaddr(&last->in6p_socket->so_rcv,
(struct sockaddr *)&rip6src,
m, opts.head) == 0) {
m_freem(m);
if (opts.head)
m_freem(opts.head);
} else
sorwakeup(last->in6p_socket);
} else {
m_freem(m);
ip6stat.ip6s_delivered--;
}
return IPPROTO_DONE;
}
/*
* Reflect the ip6 packet back to the source.
* OFF points to the icmp6 header, counted from the top of the mbuf.
*
* Note: RFC 1885 required that an echo reply should be truncated if it
* did not fit in with (return) path MTU, and KAME code supported the
* behavior. However, as a clarification after the RFC, this limitation
* was removed in a revised version of the spec, RFC 2463. We had kept the
* old behavior, with a (non-default) ifdef block, while the new version of
* the spec was an internet-draft status, and even after the new RFC was
* published. But it would rather make sense to clean the obsoleted part
* up, and to make the code simpler at this stage.
*/
void
icmp6_reflect(m, off)
struct mbuf *m;
size_t off;
{
struct ip6_hdr *ip6;
struct icmp6_hdr *icmp6;
struct in6_ifaddr *ia;
struct in6_addr t, *src = 0;
int plen;
int type, code;
struct ifnet *outif = NULL;
struct sockaddr_in6 sa6_src, sa6_dst;
/* too short to reflect */
if (off < sizeof(struct ip6_hdr)) {
nd6log((LOG_DEBUG,
"sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n",
(u_long)off, (u_long)sizeof(struct ip6_hdr),
__FILE__, __LINE__));
goto bad;
}
/*
* If there are extra headers between IPv6 and ICMPv6, strip
* off that header first.
*/
#ifdef DIAGNOSTIC
if (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) > MHLEN)
panic("assumption failed in icmp6_reflect");
#endif
if (off > sizeof(struct ip6_hdr)) {
size_t l;
struct ip6_hdr nip6;
l = off - sizeof(struct ip6_hdr);
m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6);
m_adj(m, l);
l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
if (m->m_len < l) {
if ((m = m_pullup(m, l)) == NULL)
return;
}
bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6));
} else /* off == sizeof(struct ip6_hdr) */ {
size_t l;
l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
if (m->m_len < l) {
if ((m = m_pullup(m, l)) == NULL)
return;
}
}
plen = m->m_pkthdr.len - sizeof(struct ip6_hdr);
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_nxt = IPPROTO_ICMPV6;
icmp6 = (struct icmp6_hdr *)(ip6 + 1);
type = icmp6->icmp6_type; /* keep type for statistics */
code = icmp6->icmp6_code; /* ditto. */
t = ip6->ip6_dst;
/*
* ip6_input() drops a packet if i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -