Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet/ip_input.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet/ip_input.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.254.4.2 retrieving revision 1.264 diff -u -p -r1.254.4.2 -r1.264 --- src/sys/netinet/ip_input.c 2007/12/08 18:21:13 1.254.4.2 +++ src/sys/netinet/ip_input.c 2008/04/07 06:31:28 1.264 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.254.4.2 2007/12/08 18:21:13 mjf Exp $ */ +/* $NetBSD: ip_input.c,v 1.264 2008/04/07 06:31:28 thorpej Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -98,7 +98,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.254.4.2 2007/12/08 18:21:13 mjf Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.264 2008/04/07 06:31:28 thorpej Exp $"); #include "opt_inet.h" #include "opt_gateway.h" @@ -230,7 +230,7 @@ u_long in_multihash; /* size of hash int in_multientries; /* total number of addrs */ struct in_multihashhead *in_multihashtbl; struct ifqueue ipintrq; -struct ipstat ipstat; +uint64_t ipstat[IP_NSTATS]; uint16_t ip_id; #ifdef PFIL_HOOKS @@ -417,6 +417,7 @@ ip_init(void) for (i = 0; i < IPREASS_NHASH; i++) LIST_INIT(&ipq[i]); + ip_initid(); ip_id = time_second & 0xfffff; ipintrq.ifq_maxlen = ipqmaxlen; @@ -510,7 +511,7 @@ ip_input(struct mbuf *m) */ if (TAILQ_FIRST(&in_ifaddrhead) == 0) goto bad; - ipstat.ips_total++; + ipstat[IP_STAT_TOTAL]++; /* * If the IP header is not aligned, slurp it up into a new * mbuf with space for link headers, in the event we forward @@ -521,28 +522,28 @@ ip_input(struct mbuf *m) if ((m = m_copyup(m, sizeof(struct ip), (max_linkhdr + 3) & ~3)) == NULL) { /* XXXJRT new stat, please */ - ipstat.ips_toosmall++; + ipstat[IP_STAT_TOOSMALL]++; return; } } else if (__predict_false(m->m_len < sizeof (struct ip))) { if ((m = m_pullup(m, sizeof (struct ip))) == NULL) { - ipstat.ips_toosmall++; + ipstat[IP_STAT_TOOSMALL]++; return; } } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { - ipstat.ips_badvers++; + ipstat[IP_STAT_BADVERS]++; goto bad; } hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) { /* minimum header length */ - ipstat.ips_badhlen++; + ipstat[IP_STAT_BADHLEN]++; goto bad; } if (hlen > m->m_len) { if ((m = m_pullup(m, hlen)) == 0) { - ipstat.ips_badhlen++; + ipstat[IP_STAT_BADHLEN]++; return; } ip = mtod(m, struct ip *); @@ -553,7 +554,7 @@ ip_input(struct mbuf *m) * not allowed. */ if (IN_MULTICAST(ip->ip_src.s_addr)) { - ipstat.ips_badaddr++; + ipstat[IP_STAT_BADADDR]++; goto bad; } @@ -561,7 +562,7 @@ ip_input(struct mbuf *m) if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { - ipstat.ips_badaddr++; + ipstat[IP_STAT_BADADDR]++; goto bad; } } @@ -599,7 +600,7 @@ ip_input(struct mbuf *m) * Check for additional length bogosity */ if (len < hlen) { - ipstat.ips_badlen++; + ipstat[IP_STAT_BADLEN]++; goto bad; } @@ -610,7 +611,7 @@ ip_input(struct mbuf *m) * Drop packet if shorter than we expect. */ if (m->m_pkthdr.len < len) { - ipstat.ips_tooshort++; + ipstat[IP_STAT_TOOSHORT]++; goto bad; } if (m->m_pkthdr.len > len) { @@ -779,7 +780,7 @@ ip_input(struct mbuf *m) * ip_output().) */ if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) { - ipstat.ips_cantforward++; + ipstat[IP_STAT_CANTFORWARD]++; m_freem(m); return; } @@ -791,7 +792,7 @@ ip_input(struct mbuf *m) */ if (ip->ip_p == IPPROTO_IGMP) goto ours; - ipstat.ips_forward++; + ipstat[IP_STAT_CANTFORWARD]++; } #endif /* @@ -800,7 +801,7 @@ ip_input(struct mbuf *m) */ IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); if (inm == NULL) { - ipstat.ips_cantforward++; + ipstat[IP_STAT_CANTFORWARD]++; m_freem(m); return; } @@ -814,7 +815,7 @@ ip_input(struct mbuf *m) * Not for us; forward if possible and desirable. */ if (ipforwarding == 0) { - ipstat.ips_cantforward++; + ipstat[IP_STAT_CANTFORWARD]++; m_freem(m); } else { /* @@ -825,7 +826,7 @@ ip_input(struct mbuf *m) */ if (downmatch) { icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); - ipstat.ips_cantforward++; + ipstat[IP_STAT_CANTFORWARD]++; return; } #ifdef IPSEC @@ -858,7 +859,7 @@ ip_input(struct mbuf *m) KEY_FREESP(&sp); splx(s); if (error) { - ipstat.ips_cantforward++; + ipstat[IP_STAT_CANTFORWARD]++; goto bad; } @@ -896,7 +897,18 @@ ours: * but it's not worth the time; just let them time out.) */ if (ip->ip_off & ~htons(IP_DF|IP_RF)) { - + uint16_t off; + /* + * Prevent TCP blind data attacks by not allowing non-initial + * fragments to start at less than 68 bytes (minimal fragment + * size) and making sure the first fragment is at least 68 + * bytes. + */ + off = (ntohs(ip->ip_off) & IP_OFFMASK) << 3; + if ((off > 0 ? off + hlen : len) < IP_MINFRAGSIZE - 1) { + ipstat[IP_STAT_BADFRAGS]++; + goto bad; + } /* * Look for queue of fragments * of this datagram. @@ -907,9 +919,17 @@ ours: if (ip->ip_id == fp->ipq_id && in_hosteq(ip->ip_src, fp->ipq_src) && in_hosteq(ip->ip_dst, fp->ipq_dst) && - ip->ip_p == fp->ipq_p) + ip->ip_p == fp->ipq_p) { + /* + * Make sure the TOS is matches previous + * fragments. + */ + if (ip->ip_tos != fp->ipq_tos) { + ipstat[IP_STAT_BADFRAGS]++; + goto bad; + } goto found; - + } } fp = 0; found: @@ -928,7 +948,7 @@ found: */ if (ntohs(ip->ip_len) == 0 || (ntohs(ip->ip_len) & 0x7) != 0) { - ipstat.ips_badfrags++; + ipstat[IP_STAT_BADFRAGS]++; IPQ_UNLOCK(); goto bad; } @@ -941,12 +961,12 @@ found: * attempt reassembly; if it succeeds, proceed. */ if (mff || ip->ip_off != htons(0)) { - ipstat.ips_fragments++; + ipstat[IP_STAT_FRAGMENTS]++; s = splvm(); ipqe = pool_get(&ipqent_pool, PR_NOWAIT); splx(s); if (ipqe == NULL) { - ipstat.ips_rcvmemdrop++; + ipstat[IP_STAT_RCVMEMDROP]++; IPQ_UNLOCK(); goto bad; } @@ -958,7 +978,7 @@ found: IPQ_UNLOCK(); return; } - ipstat.ips_reassembled++; + ipstat[IP_STAT_REASSEMBLED]++; ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; ip->ip_len = htons(ntohs(ip->ip_len) + hlen); @@ -1026,7 +1046,7 @@ DPRINTF(("ip_input: no SP, packet discar if (ia && ip) ia->ia_ifa.ifa_data.ifad_inbytes += ntohs(ip->ip_len); #endif - ipstat.ips_delivered++; + ipstat[IP_STAT_DELIVERED]++; { int off = hlen, nh = ip->ip_p; @@ -1038,7 +1058,7 @@ bad: return; badcsum: - ipstat.ips_badsum++; + ipstat[IP_STAT_BADSUM]++; m_freem(m); } @@ -1105,6 +1125,7 @@ ip_reass(struct ipqent *ipqe, struct ipq fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ipqe->ipqe_ip->ip_p; fp->ipq_id = ipqe->ipqe_ip->ip_id; + fp->ipq_tos = ipqe->ipqe_ip->ip_tos; TAILQ_INIT(&fp->ipq_fragq); fp->ipq_src = ipqe->ipqe_ip->ip_src; fp->ipq_dst = ipqe->ipqe_ip->ip_dst; @@ -1195,7 +1216,7 @@ insert: q = TAILQ_FIRST(&fp->ipq_fragq); ip = q->ipqe_ip; if ((next + (ip->ip_hl << 2)) > IP_MAXPACKET) { - ipstat.ips_toolong++; + ipstat[IP_STAT_TOOLONG]++; ip_freef(fp); return (0); } @@ -1245,7 +1266,7 @@ dropfrag: if (fp != 0) fp->ipq_nfrags--; ip_nfrags--; - ipstat.ips_fragdropped++; + ipstat[IP_STAT_FRAGDROPPED]++; m_freem(m); s = splvm(); pool_put(&ipqent_pool, ipqe); @@ -1312,7 +1333,7 @@ ip_reass_ttl_decr(u_int ticks) 0 : fp->ipq_ttl - ticks); nfp = LIST_NEXT(fp, ipq_q); if (fp->ipq_ttl == 0) { - ipstat.ips_fragtimeout++; + ipstat[IP_STAT_FRAGTIMEOUT]++; ip_freef(fp); } else { nfrags += fp->ipq_nfrags; @@ -1659,7 +1680,7 @@ ip_dooptions(struct mbuf *m) return (0); bad: icmp_error(m, type, code, 0, 0); - ipstat.ips_badoptions++; + ipstat[IP_STAT_BADOPTIONS]++; return (1); } @@ -1832,7 +1853,7 @@ ip_forward(struct mbuf *m, int srcrt) } #endif if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { - ipstat.ips_cantforward++; + ipstat[IP_STAT_CANTFORWARD]++; m_freem(m); return; } @@ -1896,11 +1917,11 @@ ip_forward(struct mbuf *m, int srcrt) (struct ip_moptions *)NULL, (struct socket *)NULL); if (error) - ipstat.ips_cantforward++; + ipstat[IP_STAT_CANTFORWARD]++; else { - ipstat.ips_forward++; + ipstat[IP_STAT_FORWARD]++; if (type) - ipstat.ips_redirectsent++; + ipstat[IP_STAT_REDIRECTSENT]++; else { if (mcopy) { #ifdef GATEWAY @@ -1933,17 +1954,17 @@ ip_forward(struct mbuf *m, int srcrt) case EMSGSIZE: type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG; -#if !defined(IPSEC) && !defined(FAST_IPSEC) - if (ipforward_rt.ro_rt != NULL) - destmtu = ipforward_rt.ro_rt->rt_ifp->if_mtu; -#else - /* - * If the packet is routed over IPsec tunnel, tell the - * originator the tunnel MTU. - * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz - * XXX quickhack!!! - */ - if (ipforward_rt.ro_rt != NULL) { + + if ((rt = rtcache_validate(&ipforward_rt)) != NULL) { + +#if defined(IPSEC) || defined(FAST_IPSEC) + /* + * If the packet is routed over IPsec tunnel, tell the + * originator the tunnel MTU. + * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz + * XXX quickhack!!! + */ + struct secpolicy *sp; int ipsecerror; size_t ipsechdr; @@ -1952,10 +1973,11 @@ ip_forward(struct mbuf *m, int srcrt) sp = ipsec4_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND, IP_FORWARDING, &ipsecerror); +#endif - if (sp == NULL) - destmtu = ipforward_rt.ro_rt->rt_ifp->if_mtu; - else { + destmtu = rt->rt_ifp->if_mtu; +#if defined(IPSEC) || defined(FAST_IPSEC) + if (sp != NULL) { /* count IPsec header size */ ipsechdr = ipsec4_hdrsiz(mcopy, IPSEC_DIR_OUTBOUND, NULL); @@ -1969,11 +1991,11 @@ ip_forward(struct mbuf *m, int srcrt) && sp->req->sav != NULL && sp->req->sav->sah != NULL) { ro = &sp->req->sav->sah->sa_route; - if (ro->ro_rt && ro->ro_rt->rt_ifp) { + if (rt && rt->rt_ifp) { destmtu = - ro->ro_rt->rt_rmx.rmx_mtu ? - ro->ro_rt->rt_rmx.rmx_mtu : - ro->ro_rt->rt_ifp->if_mtu; + rt->rt_rmx.rmx_mtu ? + rt->rt_rmx.rmx_mtu : + rt->rt_ifp->if_mtu; destmtu -= ipsechdr; } } @@ -1984,9 +2006,9 @@ ip_forward(struct mbuf *m, int srcrt) KEY_FREESP(&sp); #endif } +#endif /*defined(IPSEC) || defined(FAST_IPSEC)*/ } -#endif /*IPSEC*/ - ipstat.ips_cantfrag++; + ipstat[IP_STAT_CANTFRAG]++; break; case ENOBUFS: @@ -2369,7 +2391,7 @@ SYSCTL_SETUP(sysctl_net_inet_ip_setup, " CTLFLAG_PERMANENT, CTLTYPE_STRUCT, "stats", SYSCTL_DESCR("IP statistics"), - NULL, 0, &ipstat, sizeof(ipstat), + NULL, 0, ipstat, sizeof(ipstat), CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS, CTL_EOL); }