📄 ip6_input.c
字号:
ip6stat.ip6s_m2m[loif[0].if_index]++; /* XXX */
#endif
} else if (m->m_pkthdr.rcvif->if_index < M2MMAX)
ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++;
else
ip6stat.ip6s_m2m[0]++;
} else
ip6stat.ip6s_m1++;
#undef M2MMAX
}
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive);
ip6stat.ip6s_total++;
#ifndef PULLDOWN_TEST
/*
* L2 bridge code and some other code can return mbuf chain
* that does not conform to KAME requirement. too bad.
* XXX: fails to join if interface MTU > MCLBYTES. jumbogram?
*/
if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) {
struct mbuf *n;
MGETHDR(n, M_DONTWAIT, MT_HEADER);
if (n != NULL) {
#ifdef __OpenBSD__
M_MOVE_PKTHDR(n, m);
#else
M_COPY_PKTHDR(n, m);
#endif
}
if (n != NULL && m->m_pkthdr.len > MHLEN) {
MCLGET(n, M_DONTWAIT);
if ((n->m_flags & M_EXT) == 0) {
m_freem(n);
n = NULL;
}
}
if (n == NULL) {
m_freem(m);
return; /* ENOBUFS */
}
m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));
n->m_len = m->m_pkthdr.len;
m_freem(m);
m = n;
}
IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /* nothing */);
#endif
#if defined(__OpenBSD__) && NPF > 0
/*
* Packet filter
*/
if (pf_test6(PF_IN, m->m_pkthdr.rcvif, &m) != PF_PASS)
goto bad;
#endif
if (m->m_len < sizeof(struct ip6_hdr)) {
struct ifnet *inifp;
inifp = m->m_pkthdr.rcvif;
if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) {
ip6stat.ip6s_toosmall++;
in6_ifstat_inc(inifp, ifs6_in_hdrerr);
return;
}
}
ip6 = mtod(m, struct ip6_hdr *);
if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
ip6stat.ip6s_badvers++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr);
goto bad;
}
#if defined(__NetBSD__) && defined(PFIL_HOOKS)
/*
* Run through list of hooks for input packets. If there are any
* filters which require that additional packets in the flow are
* not fast-forwarded, they must clear the M_CANFASTFWD flag.
* Note that filters must _never_ set this flag, as another filter
* in the list may have previously cleared it.
*/
/*
* let ipfilter look at packet on the wire,
* not the decapsulated packet.
*/
#ifdef IPSEC
if (!ipsec_getnhist(m))
#else
if (1 /* CONSTCOND */)
#endif
{
m0 = m;
pfh = pfil_hook_get(PFIL_IN,
&inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh);
} else
pfh = NULL;
for (; pfh; pfh = pfh->pfil_link.tqe_next)
if (pfh->pfil_func) {
rv = pfh->pfil_func(ip6, sizeof(*ip6),
m->m_pkthdr.rcvif, 0, &m0);
if (rv)
return;
m = m0;
if (m == NULL)
return;
ip6 = mtod(m, struct ip6_hdr *);
}
#endif /* PFIL_HOOKS */
ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
/*
* Check with the firewall...
*/
#if defined(__FreeBSD__) && __FreeBSD__ >= 4
if (ip6_fw_enable && ip6_fw_chk_ptr)
#else
if (ip6_fw_chk_ptr)
#endif
{
/* If ipfw says divert, we have to just drop packet */
/* use port as a dummy argument */
if ((*ip6_fw_chk_ptr)(&ip6, NULL, &m)) {
m_freem(m);
m = NULL;
}
if (!m)
return;
}
#endif
#ifdef ALTQ
if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) {
/* packet is dropped by traffic conditioner */
return;
}
#endif
/*
* Check against address spoofing/corruption.
*/
#if 0
diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
diag_dump_buf(&ip6->ip6_src, 16);
diag_dump_buf(&ip6->ip6_dst, 16);
#endif
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) ||
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) {
/*
* XXX: "badscope" is not very suitable for a multicast source.
*/
ip6stat.ip6s_badscope++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);
goto bad;
}
if ((IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) ||
IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) &&
(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
ip6stat.ip6s_badscope++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);
goto bad;
}
if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) &&
!(m->m_flags & M_LOOP)) {
/*
* In this case, the packet should come from the loopback
* interface. However, we cannot just check the if_flags,
* because ip6_mloopback() passes the "actual" interface
* as the outgoing/incoming interface.
*/
ip6stat.ip6s_badscope++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);
goto bad;
}
/*
* The following check is not documented in specs. A malicious
* party may be able to use IPv4 mapped addr to confuse tcp/udp stack
* and bypass security checks (act as if it was from 127.0.0.1 by using
* IPv6 src ::ffff:127.0.0.1). Be cautious.
*
* This check chokes if we are in an SIIT cloud. As none of BSDs
* support IPv4-less kernel compilation, we cannot support SIIT
* environment at all. So, it makes more sense for us to reject any
* malicious packets for non-SIIT environment, than try to do a
* partical support for SIIT environment.
*/
if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
ip6stat.ip6s_badscope++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);
goto bad;
}
#if 0
/*
* Reject packets with IPv4 compatible addresses (auto tunnel).
*
* The code forbids auto tunnel relay case in RFC1933 (the check is
* stronger than RFC1933). We may want to re-enable it if mech-xx
* is revised to forbid relaying case.
*/
if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) ||
IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) {
ip6stat.ip6s_badscope++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
}
#endif
/* drop packets if interface ID portion is already filled */
if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src) &&
ip6->ip6_src.s6_addr16[1]) {
ip6stat.ip6s_badscope++;
log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);
goto bad;
}
if ((IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) &&
ip6->ip6_dst.s6_addr16[1]) {
ip6stat.ip6s_badscope++;
log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);
goto bad;
}
}
/*
* Embed interface ID as the zone ID for interface-local and
* link-local addresses.
* XXX: KAME assumes one-to-one mapping between interfaces and
* links.
*/
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
ip6->ip6_src.s6_addr16[1]
= htons(m->m_pkthdr.rcvif->if_index);
if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
ip6->ip6_dst.s6_addr16[1]
= htons(m->m_pkthdr.rcvif->if_index);
#if 0 /* this case seems to be unnecessary. (jinmei, 20010401) */
/*
* We use rt->rt_ifp to determine if the address is ours or not.
* If rt_ifp is lo0, the address is ours.
* The problem here is, rt->rt_ifp for fe80::%lo0/64 is set to lo0,
* so any address under fe80::%lo0/64 will be mistakenly considered
* local. The special case is supplied to handle the case properly
* by actually looking at interface addresses
* (using in6ifa_ifpwithaddr).
*/
if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) != 0 &&
IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) {
if (!in6ifa_ifpwithaddr(m->m_pkthdr.rcvif, &ip6->ip6_dst)) {
icmp6_error(m, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_ADDR, 0);
/* m is already freed */
return;
}
ours = 1;
deliverifp = m->m_pkthdr.rcvif;
goto hbhcheck;
}
#endif
/*
* Multicast check
*/
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
struct in6_multi *in6m = 0;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast);
/*
* See if we belong to the destination multicast group on the
* arrival interface.
*/
IN6_LOOKUP_MULTI(ip6->ip6_dst, m->m_pkthdr.rcvif, in6m);
// TEMP
if (0) {
struct in6_addr *_addr = &ip6->ip6_dst;
struct ifnet *_ifp = m->m_pkthdr.rcvif;
struct ifmultiaddr *_ifma;
diag_printf("Lookup Multi = %p\n", in6m);
diag_dump_buf(_addr, 16);
diag_printf("=====================================================================\n");
for (_ifma = (_ifp)->if_multiaddrs.lh_first; _ifma;
_ifma = _ifma->ifma_link.le_next) {
diag_dump_buf(&((struct sockaddr_in6 *)_ifma->ifma_addr)->sin6_addr, 16);
diag_printf("---------------------------------------------------------------------\n");
}
}
// TEMP
if (in6m)
ours = 1;
else if (!ip6_mrouter) {
ip6stat.ip6s_notmember++;
ip6stat.ip6s_cantforward++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
log(LOG_FAIL, "%s.%d - wrong multi group\n",
__FUNCTION__, __LINE__);
log_dump(LOG_FAIL, &ip6->ip6_dst, 16);
goto bad;
}
deliverifp = m->m_pkthdr.rcvif;
goto hbhcheck;
}
/*
* Unicast check
*/
#ifdef MEASURE_PERFORMANCE
ctr_beg = read_tsc();
#endif
switch (ip6_ours_check_algorithm) {
#ifdef MEASURE_PERFORMANCE
case OURS_CHECK_ALG_LINEAR:
/* traditional linear search: just for measurement */
{
struct in6_ifaddr *ia;
for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
if ((ia->ia6_flags & IN6_IFF_NOTREADY) == 0 &&
IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
&ip6->ip6_dst)) {
#ifdef MEASURE_PERFORMANCE
ctr_end = read_tsc();
#ifdef MEASURE_PERFORMANCE_UDPONLY
if (ip6->ip6_nxt == IPPROTO_UDP)
#else
if (1)
#endif
add_performance_log(ctr_end - ctr_beg,
&ip6->ip6_dst);
#endif
/* record address information into m_aux. */
(void)ip6_setdstifaddr(m, ia);
ours = 1;
deliverifp = ia->ia_ifp;
goto hbhcheck;
}
}
}
break;
case OURS_CHECK_ALG_HASH:
case OURS_CHECK_ALG_LARGEHASH:
{
struct in6_ifaddr *ia;
struct in6hash *ih = NULL;
if ((ih = in6h_lookup(&ip6->ip6_dst, m->m_pkthdr.rcvif)) !=
NULL && (ia = ih->in6h_ifa) != NULL) {
#ifdef MEASURE_PERFORMANCE
ctr_end = read_tsc();
#ifdef MEASURE_PERFORMANCE_UDPONLY
if (ip6->ip6_nxt == IPPROTO_UDP)
#else
if (1)
#endif
add_performance_log(ctr_end - ctr_beg,
&ip6->ip6_dst);
#endif
/* record address information into m_aux. */
(void)ip6_setdstifaddr(m, ia);
ours = 1;
deliverifp = m->m_pkthdr.rcvif;
goto hbhcheck;
}
}
break;
#endif /* MEASURE_PERFORMANCE */
default:
/*
* XXX: I intentionally broke our indentation rule here,
* since this switch-case is just for measurement and
* therefore should soon be removed.
*/
if (ip6_forward_rt.ro_rt != NULL &&
(ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 &&
IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
&((struct sockaddr_in6 *)(&ip6_forward_rt.ro_dst))->sin6_addr))
ip6stat.ip6s_forward_cachehit++;
else {
struct sockaddr_in6 *dst6;
#ifdef SCOPEDROUTING
int64_t dstzone;
#endif
if (ip6_forward_rt.ro_rt) {
/* route is down or destination is different */
ip6stat.ip6s_forward_cachemiss++;
RTFREE(ip6_forward_rt.ro_rt);
ip6_forward_rt.ro_rt = 0;
}
bzero(&ip6_forward_rt.ro_dst, sizeof(struct sockaddr_in6));
dst6 = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst;
dst6->sin6_len = sizeof(struct sockaddr_in6);
dst6->sin6_family = AF_INET6;
dst6->sin6_addr = ip6->ip6_dst;
#ifdef SCOPEDROUTING
if ((dstzone = in6_addr2zoneid(m->m_pkthdr.rcvif,
&ip6->ip6_dst)) < 0) {
ip6stat.ip6s_badscope++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
log(LOG_FAIL, "%s.%d\n", __FUNCTION__, __LINE__);
goto bad;
}
ip6_forward_rt.ro_dst.sin6_scope_id = dstzone;
#endif
#ifdef __FreeBSD__
rtalloc_ign((struct route *)&ip6_forward_rt, RTF_PRCLONING);
#else
rtalloc((struct route *)&ip6_forward_rt);
#endif
}
#define rt6_key(r) ((struct sockaddr_in6 *)((r)->rt_nodes->rn_key))
/*
* Accept the packet if the forwarding interface to the destination
* according to the routing table is the loopback interface,
* unless the associated route has a gateway.
* Note that this approach causes to accept a packet if there is a
* route to the loopback interface for the destination of the packet.
* But we think it's even useful in some situations, e.g. when using
* a special daemon which wants to intercept the packet.
*
* XXX: some OSes automatically make a cloned route for the destination
* of an outgoing packet. If the outgoing interface of the packet
* is a loopback one, the kernel would consider the packet to be
* accepted, even if we have no such address assinged on the interface.
* We check the cloned flag of the route entry to reject such cases,
* assuming that route entries for our own addresses are not made by
* cloning (it should be true because in6_addloop explicitly installs
* the host route). However, we might have to do an explicit check
* while it would be less efficient. Or, should we rather install a
* reject route for such a case?
*/
if (ip6_forward_rt.ro_rt &&
(ip6_forward_rt.ro_rt->rt_flags &
(RTF_HOST|RTF_GATEWAY)) == RTF_HOST &&
#ifdef RTF_WASCLONED
!(ip6_forward_rt.ro_rt->rt_flags & RTF_WASCLONED) &&
#endif
#ifdef RTF_CLONED
!(ip6_forward_rt.ro_rt->rt_flags & RTF_CLONED) &&
#endif
#if 0
/*
* The check below is redundant since the comparison of
* the destination and the key of the rtentry has
* already done through looking up the routing table.
*/
IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
&rt6_key(ip6_forward_rt.ro_rt)->sin6_addr)
#endif
ip6_forward_rt.ro_rt->rt_ifp->if_type == IFT_LOOP) {
struct in6_ifaddr *ia6 =
(struct in6_ifaddr *)ip6_forward_rt.ro_rt->rt_ifa;
#ifdef MEASURE_PERFORMANCE
ctr_end = read_tsc();
#ifdef MEASURE_PERFORMANCE_UDPONLY
if (ip6->ip6_nxt == IPPROTO_UDP)
#else
if (1)
#endif
add_performance_log(ctr_end - ctr_beg, &ip6->ip6_dst);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -