ip6_input.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,515 行 · 第 1/5 页
C
2,515 行
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 /* * record address information into m_aux. */ (void)ip6_setdstifaddr(m, ia6); /* * packets to a tentative, duplicated, or somehow invalid * address must not be accepted. */ if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { /* this address is ready */ ours = 1; deliverifp = ia6->ia_ifp; /* correct? */#if defined(__FreeBSD__) && __FreeBSD__ >= 4 /* Count the packet in the ip address stats */ ia6->ia_ifa.if_ipackets++; ia6->ia_ifa.if_ibytes += m->m_pkthdr.len;#elif defined(__bsdi__) && _BSDI_VERSION >= 199802 /* Count the packet in the ip address stats */ ia6->ia_ifa.ifa_ipackets++; ia6->ia_ifa.ifa_ibytes += m->m_pkthdr.len;#endif goto hbhcheck; } else { /* address is not ready, so discard the packet. */ nd6log((LOG_INFO, "ip6_input: packet to an unready address %s->%s\n", ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst))); goto bad; } } } /* XXX indentation (see above) */#ifdef MEASURE_PERFORMANCE /* we detected that packet is not ours thru the basic algorithm */ ctr_end = read_tsc();#ifdef MEASURE_PERFORMANCE_UDPONLY if (ip6->ip6_nxt == IPPROTO_UDP)#else
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?