Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/ip6_input.c
Show First 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | |||||
#include <netinet/icmp6.h> | #include <netinet/icmp6.h> | ||||
#include <netinet6/scope6_var.h> | #include <netinet6/scope6_var.h> | ||||
#include <netinet6/in6_ifattach.h> | #include <netinet6/in6_ifattach.h> | ||||
#include <netinet6/mld6_var.h> | #include <netinet6/mld6_var.h> | ||||
#include <netinet6/nd6.h> | #include <netinet6/nd6.h> | ||||
#include <netinet6/in6_rss.h> | #include <netinet6/in6_rss.h> | ||||
#ifdef IPSEC | #ifdef IPSEC | ||||
#include <netipsec/key.h> | |||||
#include <netipsec/ipsec.h> | #include <netipsec/ipsec.h> | ||||
#include <netinet6/ip6_ipsec.h> | #include <netinet6/ip6_ipsec.h> | ||||
#include <netipsec/ipsec6.h> | #include <netipsec/ipsec6.h> | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
#include <netinet6/ip6protosw.h> | #include <netinet6/ip6protosw.h> | ||||
extern struct domain inet6domain; | extern struct domain inet6domain; | ||||
▲ Show 20 Lines • Show All 413 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
void | void | ||||
ip6_input(struct mbuf *m) | ip6_input(struct mbuf *m) | ||||
{ | { | ||||
struct in6_addr odst; | struct in6_addr odst; | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
struct in6_ifaddr *ia; | struct in6_ifaddr *ia; | ||||
struct ifnet *rcvif; | |||||
u_int32_t plen; | u_int32_t plen; | ||||
u_int32_t rtalert = ~0; | u_int32_t rtalert = ~0; | ||||
int off = sizeof(struct ip6_hdr), nest; | int off = sizeof(struct ip6_hdr), nest; | ||||
int nxt, ours = 0; | int nxt, ours = 0; | ||||
int srcrt = 0; | int srcrt = 0; | ||||
/* | |||||
* Drop the packet if IPv6 operation is disabled on the interface. | |||||
*/ | |||||
rcvif = m->m_pkthdr.rcvif; | |||||
if ((ND_IFINFO(rcvif)->flags & ND6_IFF_IFDISABLED)) | |||||
goto bad; | |||||
#ifdef IPSEC | #ifdef IPSEC | ||||
/* | /* | ||||
* should the inner packet be considered authentic? | * should the inner packet be considered authentic? | ||||
* see comment in ah4_input(). | * see comment in ah4_input(). | ||||
* NB: m cannot be NULL when passed to the input routine | * NB: m cannot be NULL when passed to the input routine | ||||
*/ | */ | ||||
m->m_flags &= ~M_AUTHIPHDR; | m->m_flags &= ~M_AUTHIPHDR; | ||||
m->m_flags &= ~M_AUTHIPDGM; | m->m_flags &= ~M_AUTHIPDGM; | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
if (m->m_flags & M_FASTFWD_OURS) { | |||||
/* | /* | ||||
* Firewall changed destination to local. | * Update statistics. | ||||
*/ | */ | ||||
m->m_flags &= ~M_FASTFWD_OURS; | |||||
ours = 1; | |||||
ip6 = mtod(m, struct ip6_hdr *); | |||||
goto hbhcheck; | |||||
} | |||||
/* | |||||
* mbuf statistics | |||||
*/ | |||||
if (m->m_flags & M_EXT) { | if (m->m_flags & M_EXT) { | ||||
if (m->m_next) | if (m->m_next) | ||||
IP6STAT_INC(ip6s_mext2m); | IP6STAT_INC(ip6s_mext2m); | ||||
else | else | ||||
IP6STAT_INC(ip6s_mext1); | IP6STAT_INC(ip6s_mext1); | ||||
} else { | } else { | ||||
if (m->m_next) { | if (m->m_next) { | ||||
if (m->m_flags & M_LOOP) { | if (m->m_flags & M_LOOP) { | ||||
IP6STAT_INC(ip6s_m2m[V_loif->if_index]); | IP6STAT_INC(ip6s_m2m[V_loif->if_index]); | ||||
} else if (m->m_pkthdr.rcvif->if_index < IP6S_M2MMAX) | } else if (rcvif->if_index < IP6S_M2MMAX) | ||||
IP6STAT_INC( | IP6STAT_INC(ip6s_m2m[rcvif->if_index]); | ||||
ip6s_m2m[m->m_pkthdr.rcvif->if_index]); | |||||
else | else | ||||
bz: All these "rcvif" changes could be factored out into a separate change and committed as non… | |||||
Not Done Inline ActionsOk, I'll resubmit the patch a bit later. ae: Ok, I'll resubmit the patch a bit later. | |||||
Not Done Inline ActionsGreat. Thanks! bz: Great. Thanks! | |||||
IP6STAT_INC(ip6s_m2m[0]); | IP6STAT_INC(ip6s_m2m[0]); | ||||
} else | } else | ||||
IP6STAT_INC(ip6s_m1); | IP6STAT_INC(ip6s_m1); | ||||
} | } | ||||
/* drop the packet if IPv6 operation is disabled on the IF */ | in6_ifstat_inc(rcvif, ifs6_in_receive); | ||||
if ((ND_IFINFO(m->m_pkthdr.rcvif)->flags & ND6_IFF_IFDISABLED)) | |||||
goto bad; | |||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); | |||||
IP6STAT_INC(ip6s_total); | IP6STAT_INC(ip6s_total); | ||||
if (m->m_flags & M_FASTFWD_OURS) { | |||||
/* | |||||
* Firewall changed destination to local. | |||||
*/ | |||||
m->m_flags &= ~M_FASTFWD_OURS; | |||||
ours = 1; | |||||
ip6 = mtod(m, struct ip6_hdr *); | |||||
goto hbhcheck; | |||||
} | |||||
#ifndef PULLDOWN_TEST | #ifndef PULLDOWN_TEST | ||||
/* | /* | ||||
* L2 bridge code and some other code can return mbuf chain | * L2 bridge code and some other code can return mbuf chain | ||||
* that does not conform to KAME requirement. too bad. | * that does not conform to KAME requirement. too bad. | ||||
* XXX: fails to join if interface MTU > MCLBYTES. jumbogram? | * XXX: fails to join if interface MTU > MCLBYTES. jumbogram? | ||||
*/ | */ | ||||
if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) { | if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) { | ||||
struct mbuf *n; | struct mbuf *n; | ||||
if (m->m_pkthdr.len > MHLEN) | if (m->m_pkthdr.len > MHLEN) | ||||
n = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | n = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | ||||
else | else | ||||
n = m_gethdr(M_NOWAIT, MT_DATA); | n = m_gethdr(M_NOWAIT, MT_DATA); | ||||
if (n == NULL) { | if (n == NULL) | ||||
m_freem(m); | goto bad; | ||||
return; /* ENOBUFS */ | |||||
} | |||||
m_move_pkthdr(n, m); | m_move_pkthdr(n, m); | ||||
m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t)); | m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t)); | ||||
n->m_len = n->m_pkthdr.len; | n->m_len = n->m_pkthdr.len; | ||||
m_freem(m); | m_freem(m); | ||||
m = n; | m = n; | ||||
} | } | ||||
IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /* nothing */); | IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /* nothing */); | ||||
#endif | #endif | ||||
if (m->m_len < sizeof(struct ip6_hdr)) { | 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))) == NULL) { | if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { | ||||
IP6STAT_INC(ip6s_toosmall); | IP6STAT_INC(ip6s_toosmall); | ||||
in6_ifstat_inc(inifp, ifs6_in_hdrerr); | in6_ifstat_inc(rcvif, ifs6_in_hdrerr); | ||||
return; | goto bad; | ||||
} | } | ||||
} | } | ||||
ip6 = mtod(m, struct ip6_hdr *); | ip6 = mtod(m, struct ip6_hdr *); | ||||
if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { | if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { | ||||
IP6STAT_INC(ip6s_badvers); | IP6STAT_INC(ip6s_badvers); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); | in6_ifstat_inc(rcvif, ifs6_in_hdrerr); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
IP6STAT_INC(ip6s_nxthist[ip6->ip6_nxt]); | IP6STAT_INC(ip6s_nxthist[ip6->ip6_nxt]); | ||||
IP_PROBE(receive, NULL, NULL, ip6, rcvif, NULL, ip6); | |||||
IP_PROBE(receive, NULL, NULL, ip6, m->m_pkthdr.rcvif, NULL, ip6); | |||||
/* | /* | ||||
* Check against address spoofing/corruption. | * Check against address spoofing/corruption. | ||||
*/ | */ | ||||
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || | if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || | ||||
IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { | IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { | ||||
/* | /* | ||||
* XXX: "badscope" is not very suitable for a multicast source. | * XXX: "badscope" is not very suitable for a multicast source. | ||||
*/ | */ | ||||
IP6STAT_INC(ip6s_badscope); | IP6STAT_INC(ip6s_badscope); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); | in6_ifstat_inc(rcvif, ifs6_in_addrerr); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) && | if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) && | ||||
!(m->m_flags & M_LOOP)) { | !(m->m_flags & M_LOOP)) { | ||||
/* | /* | ||||
* In this case, the packet should come from the loopback | * In this case, the packet should come from the loopback | ||||
* interface. However, we cannot just check the if_flags, | * interface. However, we cannot just check the if_flags, | ||||
* because ip6_mloopback() passes the "actual" interface | * because ip6_mloopback() passes the "actual" interface | ||||
* as the outgoing/incoming interface. | * as the outgoing/incoming interface. | ||||
*/ | */ | ||||
IP6STAT_INC(ip6s_badscope); | IP6STAT_INC(ip6s_badscope); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); | in6_ifstat_inc(rcvif, ifs6_in_addrerr); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && | if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && | ||||
IPV6_ADDR_MC_SCOPE(&ip6->ip6_dst) == 0) { | IPV6_ADDR_MC_SCOPE(&ip6->ip6_dst) == 0) { | ||||
/* | /* | ||||
* RFC4291 2.7: | * RFC4291 2.7: | ||||
* Nodes must not originate a packet to a multicast address | * Nodes must not originate a packet to a multicast address | ||||
* whose scop field contains the reserved value 0; if such | * whose scop field contains the reserved value 0; if such | ||||
* a packet is received, it must be silently dropped. | * a packet is received, it must be silently dropped. | ||||
*/ | */ | ||||
IP6STAT_INC(ip6s_badscope); | IP6STAT_INC(ip6s_badscope); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); | in6_ifstat_inc(rcvif, ifs6_in_addrerr); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
#ifdef ALTQ | #ifdef ALTQ | ||||
if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) { | if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) { | ||||
/* packet is dropped by traffic conditioner */ | /* packet is dropped by traffic conditioner */ | ||||
return; | return; | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* The following check is not documented in specs. A malicious | * The following check is not documented in specs. A malicious | ||||
* party may be able to use IPv4 mapped addr to confuse tcp/udp stack | * 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 | * 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. | * IPv6 src ::ffff:127.0.0.1). Be cautious. | ||||
* | * | ||||
* This check chokes if we are in an SIIT cloud. As none of BSDs | * This check chokes if we are in an SIIT cloud. As none of BSDs | ||||
* support IPv4-less kernel compilation, we cannot support SIIT | * support IPv4-less kernel compilation, we cannot support SIIT | ||||
* environment at all. So, it makes more sense for us to reject any | * environment at all. So, it makes more sense for us to reject any | ||||
* malicious packets for non-SIIT environment, than try to do a | * malicious packets for non-SIIT environment, than try to do a | ||||
* partial support for SIIT environment. | * partial support for SIIT environment. | ||||
*/ | */ | ||||
if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || | if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || | ||||
IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { | IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { | ||||
IP6STAT_INC(ip6s_badscope); | IP6STAT_INC(ip6s_badscope); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); | in6_ifstat_inc(rcvif, ifs6_in_addrerr); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
#if 0 | #if 0 | ||||
/* | /* | ||||
* Reject packets with IPv4 compatible addresses (auto tunnel). | * Reject packets with IPv4 compatible addresses (auto tunnel). | ||||
* | * | ||||
* The code forbids auto tunnel relay case in RFC1933 (the check is | * 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 | * stronger than RFC1933). We may want to re-enable it if mech-xx | ||||
* is revised to forbid relaying case. | * is revised to forbid relaying case. | ||||
*/ | */ | ||||
if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || | if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || | ||||
IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { | IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { | ||||
IP6STAT_INC(ip6s_badscope); | IP6STAT_INC(ip6s_badscope); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); | in6_ifstat_inc(rcvif, ifs6_in_addrerr); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
#endif | #endif | ||||
/* Try to forward the packet, but if we fail continue */ | |||||
#ifdef IPSEC | #ifdef IPSEC | ||||
if (!key_havesp(IPSEC_DIR_INBOUND) && | |||||
!key_havesp(IPSEC_DIR_OUTBOUND) && V_ip6_forwarding != 0) | |||||
Not Done Inline ActionsPut the V_ip6_forwarding check first please? bz: Put the V_ip6_forwarding check first please? | |||||
Not Done Inline ActionsYes of course. Also we have to do the same for both ipv4. ae: Yes of course. Also we have to do the same for both ipv4. | |||||
if (ip6_tryforward(m) == NULL) | |||||
return; | |||||
/* | /* | ||||
* Bypass packet filtering for packets previously handled by IPsec. | * Bypass packet filtering for packets previously handled by IPsec. | ||||
*/ | */ | ||||
if (ip6_ipsec_filtertunnel(m)) | if (ip6_ipsec_filtertunnel(m)) | ||||
goto passin; | goto passin; | ||||
#else | |||||
if (V_ip6_forwarding != 0) | |||||
if (ip6_tryforward(m) == NULL) | |||||
return; | |||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
/* | /* | ||||
* Run through list of hooks for input packets. | * Run through list of hooks for input packets. | ||||
* | * | ||||
* NB: Beware of the destination address changing | * NB: Beware of the destination address changing | ||||
* (e.g. by NAT rewriting). When this happens, | * (e.g. by NAT rewriting). When this happens, | ||||
* tell ip6_forward to do the right thing. | * tell ip6_forward to do the right thing. | ||||
*/ | */ | ||||
odst = ip6->ip6_dst; | odst = ip6->ip6_dst; | ||||
/* Jump over all PFIL processing if hooks are not active. */ | /* Jump over all PFIL processing if hooks are not active. */ | ||||
if (!PFIL_HOOKED(&V_inet6_pfil_hook)) | if (!PFIL_HOOKED(&V_inet6_pfil_hook)) | ||||
goto passin; | goto passin; | ||||
if (pfil_run_hooks(&V_inet6_pfil_hook, &m, | if (pfil_run_hooks(&V_inet6_pfil_hook, &m, rcvif, PFIL_IN, NULL)) | ||||
m->m_pkthdr.rcvif, PFIL_IN, NULL)) | |||||
return; | return; | ||||
if (m == NULL) /* consumed by filter */ | if (m == NULL) /* consumed by filter */ | ||||
return; | return; | ||||
ip6 = mtod(m, struct ip6_hdr *); | ip6 = mtod(m, struct ip6_hdr *); | ||||
srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); | srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); | ||||
if (m->m_flags & M_FASTFWD_OURS) { | if (m->m_flags & M_FASTFWD_OURS) { | ||||
m->m_flags &= ~M_FASTFWD_OURS; | m->m_flags &= ~M_FASTFWD_OURS; | ||||
Show All 21 Lines | passin: | ||||
* in6_setscope() then also checks and rejects the cases where src or | * in6_setscope() then also checks and rejects the cases where src or | ||||
* dst are the loopback address and the receiving interface | * dst are the loopback address and the receiving interface | ||||
* is not loopback. | * is not loopback. | ||||
*/ | */ | ||||
if (in6_clearscope(&ip6->ip6_src) || in6_clearscope(&ip6->ip6_dst)) { | if (in6_clearscope(&ip6->ip6_src) || in6_clearscope(&ip6->ip6_dst)) { | ||||
IP6STAT_INC(ip6s_badscope); /* XXX */ | IP6STAT_INC(ip6s_badscope); /* XXX */ | ||||
goto bad; | goto bad; | ||||
} | } | ||||
if (in6_setscope(&ip6->ip6_src, m->m_pkthdr.rcvif, NULL) || | if (in6_setscope(&ip6->ip6_src, rcvif, NULL) || | ||||
in6_setscope(&ip6->ip6_dst, m->m_pkthdr.rcvif, NULL)) { | in6_setscope(&ip6->ip6_dst, rcvif, NULL)) { | ||||
IP6STAT_INC(ip6s_badscope); | IP6STAT_INC(ip6s_badscope); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
/* | /* | ||||
* Multicast check. Assume packet is for us to avoid | * Multicast check. Assume packet is for us to avoid | ||||
* prematurely taking locks. | * prematurely taking locks. | ||||
*/ | */ | ||||
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { | if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { | ||||
ours = 1; | ours = 1; | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mcast); | in6_ifstat_inc(rcvif, ifs6_in_mcast); | ||||
goto hbhcheck; | goto hbhcheck; | ||||
} | } | ||||
/* | /* | ||||
* Unicast check | * Unicast check | ||||
* XXX: For now we keep link-local IPv6 addresses with embedded | * XXX: For now we keep link-local IPv6 addresses with embedded | ||||
* scope zone id, therefore we use zero zoneid here. | * scope zone id, therefore we use zero zoneid here. | ||||
*/ | */ | ||||
ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); | ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); | ||||
Show All 18 Lines | passin: | ||||
} | } | ||||
/* | /* | ||||
* Now there is no reason to process the packet if it's not our own | * Now there is no reason to process the packet if it's not our own | ||||
* and we're not a router. | * and we're not a router. | ||||
*/ | */ | ||||
if (!V_ip6_forwarding) { | if (!V_ip6_forwarding) { | ||||
IP6STAT_INC(ip6s_cantforward); | IP6STAT_INC(ip6s_cantforward); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); | in6_ifstat_inc(rcvif, ifs6_in_discard); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
hbhcheck: | hbhcheck: | ||||
/* | /* | ||||
* Process Hop-by-Hop options header if it's contained. | * Process Hop-by-Hop options header if it's contained. | ||||
* m may be modified in ip6_hopopts_input(). | * m may be modified in ip6_hopopts_input(). | ||||
* If a JumboPayload option is included, plen will also be modified. | * If a JumboPayload option is included, plen will also be modified. | ||||
Show All 15 Lines | passin: | ||||
/* | /* | ||||
* Check that the amount of data in the buffers | * Check that the amount of data in the buffers | ||||
* is as at least much as the IPv6 header would have us expect. | * is as at least much as the IPv6 header would have us expect. | ||||
* Trim mbufs if longer than we expect. | * Trim mbufs if longer than we expect. | ||||
* Drop packet if shorter than we expect. | * Drop packet if shorter than we expect. | ||||
*/ | */ | ||||
if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { | if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { | ||||
IP6STAT_INC(ip6s_tooshort); | IP6STAT_INC(ip6s_tooshort); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); | in6_ifstat_inc(rcvif, ifs6_in_truncated); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { | if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { | ||||
if (m->m_len == m->m_pkthdr.len) { | if (m->m_len == m->m_pkthdr.len) { | ||||
m->m_len = sizeof(struct ip6_hdr) + plen; | m->m_len = sizeof(struct ip6_hdr) + plen; | ||||
m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen; | m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen; | ||||
} else | } else | ||||
m_adj(m, sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len); | m_adj(m, sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len); | ||||
Show All 11 Lines | if (V_ip6_mrouter && | ||||
* The packet is returned (relatively) intact; if | * The packet is returned (relatively) intact; if | ||||
* ip6_mforward() returns a non-zero value, the packet | * ip6_mforward() returns a non-zero value, the packet | ||||
* must be discarded, else it may be accepted below. | * must be discarded, else it may be accepted below. | ||||
* | * | ||||
* XXX TODO: Check hlim and multicast scope here to avoid | * XXX TODO: Check hlim and multicast scope here to avoid | ||||
* unnecessarily calling into ip6_mforward(). | * unnecessarily calling into ip6_mforward(). | ||||
*/ | */ | ||||
if (ip6_mforward && | if (ip6_mforward && | ||||
ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) { | ip6_mforward(ip6, rcvif, m)) { | ||||
IP6STAT_INC(ip6s_cantforward); | IP6STAT_INC(ip6s_cantforward); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); | in6_ifstat_inc(rcvif, ifs6_in_discard); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
} else if (!ours) { | } else if (!ours) { | ||||
ip6_forward(m, srcrt); | ip6_forward(m, srcrt); | ||||
return; | return; | ||||
} | } | ||||
ip6 = mtod(m, struct ip6_hdr *); | ip6 = mtod(m, struct ip6_hdr *); | ||||
/* | /* | ||||
* Malicious party may be able to use IPv4 mapped addr to confuse | * 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 | * 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. | * 127.0.0.1 by using IPv6 src ::ffff:127.0.0.1). Be cautious. | ||||
* | * | ||||
* For SIIT end node behavior, you may want to disable the check. | * For SIIT end node behavior, you may want to disable the check. | ||||
* However, you will become vulnerable to attacks using IPv4 mapped | * However, you will become vulnerable to attacks using IPv4 mapped | ||||
* source. | * source. | ||||
*/ | */ | ||||
if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || | if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || | ||||
IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { | IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { | ||||
IP6STAT_INC(ip6s_badscope); | IP6STAT_INC(ip6s_badscope); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); | in6_ifstat_inc(rcvif, ifs6_in_addrerr); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
/* | /* | ||||
* Tell launch routine the next header | * Tell launch routine the next header | ||||
*/ | */ | ||||
IP6STAT_INC(ip6s_delivered); | IP6STAT_INC(ip6s_delivered); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_deliver); | in6_ifstat_inc(rcvif, ifs6_in_deliver); | ||||
nest = 0; | nest = 0; | ||||
while (nxt != IPPROTO_DONE) { | while (nxt != IPPROTO_DONE) { | ||||
if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { | if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { | ||||
IP6STAT_INC(ip6s_toomanyhdr); | IP6STAT_INC(ip6s_toomanyhdr); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
/* | /* | ||||
* protection against faulty packet - there should be | * protection against faulty packet - there should be | ||||
* more sanity checks in header chain processing. | * more sanity checks in header chain processing. | ||||
*/ | */ | ||||
if (m->m_pkthdr.len < off) { | if (m->m_pkthdr.len < off) { | ||||
IP6STAT_INC(ip6s_tooshort); | IP6STAT_INC(ip6s_tooshort); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); | in6_ifstat_inc(rcvif, ifs6_in_truncated); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
#ifdef IPSEC | #ifdef IPSEC | ||||
/* | /* | ||||
* enforce IPsec policy checking if we are seeing last header. | * enforce IPsec policy checking if we are seeing last header. | ||||
* note that we do not visit this with protocols with pcb layer | * note that we do not visit this with protocols with pcb layer | ||||
* code - like udp/tcp/raw ip. | * code - like udp/tcp/raw ip. | ||||
*/ | */ | ||||
if (ip6_ipsec_input(m, nxt)) | if (ip6_ipsec_input(m, nxt)) | ||||
goto bad; | goto bad; | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); | nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); | ||||
} | } | ||||
return; | return; | ||||
bad: | bad: | ||||
in6_ifstat_inc(rcvif, ifs6_in_discard); | |||||
if (m != NULL) | |||||
m_freem(m); | m_freem(m); | ||||
} | } | ||||
/* | /* | ||||
* Hop-by-Hop options header processing. If a valid jumbo payload option is | * Hop-by-Hop options header processing. If a valid jumbo payload option is | ||||
* included, the real payload length will be stored in plenp. | * included, the real payload length will be stored in plenp. | ||||
* | * | ||||
* rtalertp - XXX: should be stored more smart way | * rtalertp - XXX: should be stored more smart way | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 807 Lines • Show Last 20 Lines |
All these "rcvif" changes could be factored out into a separate change and committed as non-functional change irrelevant to this work, please?