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.130.2.16 retrieving revision 1.179 diff -u -p -r1.130.2.16 -r1.179 --- src/sys/netinet/ip_input.c 2002/12/11 06:46:37 1.130.2.16 +++ src/sys/netinet/ip_input.c 2003/09/28 04:45:14 1.179 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.130.2.16 2002/12/11 06:46:37 thorpej Exp $ */ +/* $NetBSD: ip_input.c,v 1.179 2003/09/28 04:45:14 mycroft Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -78,11 +78,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -102,12 +98,13 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.130.2.16 2002/12/11 06:46:37 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.179 2003/09/28 04:45:14 mycroft Exp $"); #include "opt_gateway.h" #include "opt_pfil_hooks.h" #include "opt_ipsec.h" #include "opt_mrouting.h" +#include "opt_mbuftrace.h" #include "opt_inet_csum.h" #include @@ -150,6 +147,10 @@ __KERNEL_RCSID(0, "$NetBSD: ip_input.c,v #include #include #endif +#ifdef FAST_IPSEC +#include +#include +#endif /* FAST_IPSEC*/ #ifndef IPFORWARDING #ifdef GATEWAY @@ -196,6 +197,21 @@ int ip_mtudisc_timeout = IPMTUDISCTIMEOU #ifdef DIAGNOSTIC int ipprintfs = 0; #endif +/* + * XXX - Setting ip_checkinterface mostly implements the receive side of + * the Strong ES model described in RFC 1122, but since the routing table + * and transmit implementation do not implement the Strong ES model, + * setting this to 1 results in an odd hybrid. + * + * XXX - ip_checkinterface currently must be disabled if you use ipnat + * to translate the destination address to another local interface. + * + * XXX - ip_checkinterface must be disabled if you add IP aliases + * to the loopback interface instead of the interface where the + * packets for those addresses are received. + */ +int ip_checkinterface = 0; + struct rttimer_queue *ip_mtudisc_timeout_q = NULL; @@ -205,9 +221,11 @@ u_long in_ifaddrhash; /* size of hash int in_ifaddrentries; /* total number of addrs */ struct in_ifaddrhead in_ifaddr; struct in_ifaddrhashhead *in_ifaddrhashtbl; +u_long in_multihash; /* size of hash table - 1 */ +int in_multientries; /* total number of addrs */ +struct in_multihashhead *in_multihashtbl; struct ifqueue ipintrq; struct ipstat ipstat; -u_int16_t ip_id; #ifdef PFIL_HOOKS struct pfil_head inet_pfil_hook; @@ -272,6 +290,7 @@ do { \ #define IPQ_UNLOCK() ipq_unlock() +struct pool inmulti_pool; struct pool ipqent_pool; #ifdef INET_CSUM_COUNTERS @@ -309,6 +328,11 @@ static struct ip_srcrt { static void save_rte __P((u_char *, struct in_addr)); +#ifdef MBUFTRACE +struct mowner ip_rx_mowner = { "internet", "rx" }; +struct mowner ip_tx_mowner = { "internet", "tx" }; +#endif + /* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. @@ -319,6 +343,8 @@ ip_init() struct protosw *pr; int i; + pool_init(&inmulti_pool, sizeof(struct in_multi), 0, 0, 0, "inmltpl", + NULL); pool_init(&ipqent_pool, sizeof(struct ipqent), 0, 0, 0, "ipqepl", NULL); @@ -333,11 +359,12 @@ ip_init() pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) ip_protox[pr->pr_protocol] = pr - inetsw; LIST_INIT(&ipq); - ip_id = time.tv_sec & 0xffff; ipintrq.ifq_maxlen = ipqmaxlen; TAILQ_INIT(&in_ifaddr); in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, M_IFADDR, M_WAITOK, &in_ifaddrhash); + in_multihashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, M_IPMADDR, + M_WAITOK, &in_multihash); ip_mtudisc_timeout_q = rt_timer_queue_create(ip_mtudisc_timeout); #ifdef GATEWAY ipflow_init(); @@ -358,6 +385,11 @@ ip_init() evcnt_attach_static(&ip_hwcsum_ok); evcnt_attach_static(&ip_swcsum); #endif /* INET_CSUM_COUNTERS */ + +#ifdef MBUFTRACE + MOWNER_ATTACH(&ip_tx_mowner); + MOWNER_ATTACH(&ip_rx_mowner); +#endif /* MBUFTRACE */ } struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; @@ -378,6 +410,7 @@ ipintr() splx(s); if (m == 0) return; + MCLAIM(m, &ip_rx_mowner); ip_input(m); } } @@ -396,21 +429,21 @@ ip_input(struct mbuf *m) struct ipqent *ipqe; int hlen = 0, mff, len; int downmatch; + int checkif; + int srcrt = 0; +#ifdef FAST_IPSEC + struct m_tag *mtag; + struct tdb_ident *tdbi; + struct secpolicy *sp; + int s, error; +#endif /* FAST_IPSEC */ + MCLAIM(m, &ip_rx_mowner); #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("ipintr no HDR"); #endif -#ifdef IPSEC - /* - * should the inner packet be considered authentic? - * see comment in ah4_input(). - */ - if (m) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } -#endif + /* * If no IP addresses have been set yet but the interfaces * are receiving, can't do anything with incoming packets yet. @@ -551,13 +584,17 @@ ip_input(struct mbuf *m) if (1) #endif { + struct in_addr odst; + + odst = ip->ip_dst; if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, - PFIL_IN) != 0) - return; + PFIL_IN) != 0) + return; if (m == NULL) return; ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; + srcrt = (odst.s_addr != ip->ip_dst.s_addr); } #endif /* PFIL_HOOKS */ @@ -580,6 +617,26 @@ ip_input(struct mbuf *m) return; /* + * Enable a consistency check between the destination address + * and the arrival interface for a unicast packet (the RFC 1122 + * strong ES model) if IP forwarding is disabled and the packet + * is not locally generated. + * + * XXX - Checking also should be disabled if the destination + * address is ipnat'ed to a different interface. + * + * XXX - Checking is incompatible with IP aliases added + * to the loopback interface instead of the interface where + * the packets are received. + * + * XXX - We need to add a per ifaddr flag for this so that + * we get finer grain control. + */ + checkif = ip_checkinterface && (ipforwarding == 0) && + (m->m_pkthdr.rcvif != NULL) && + ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0); + + /* * Check our list of addresses, to see if the packet is for us. * * Traditional 4.4BSD did not consult IFF_UP at all. @@ -589,6 +646,8 @@ ip_input(struct mbuf *m) downmatch = 0; LIST_FOREACH(ia, &IN_IFADDR_HASH(ip->ip_dst.s_addr), ia_hash) { if (in_hosteq(ia->ia_addr.sin_addr, ip->ip_dst)) { + if (checkif && ia->ia_ifp != m->m_pkthdr.rcvif) + continue; if ((ia->ia_ifp->if_flags & IFF_UP) != 0) break; else @@ -701,8 +760,36 @@ ip_input(struct mbuf *m) goto bad; } #endif +#ifdef FAST_IPSEC + mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); + s = splsoftnet(); + if (mtag != NULL) { + tdbi = (struct tdb_ident *)(mtag + 1); + sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); + } else { + sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, + IP_FORWARDING, &error); + } + if (sp == NULL) { /* NB: can happen if error */ + splx(s); + /*XXX error stat???*/ + DPRINTF(("ip_input: no SP for forwarding\n")); /*XXX*/ + goto bad; + } - ip_forward(m, 0); + /* + * Check security policy against packet attributes. + */ + error = ipsec_in_reject(sp, m); + KEY_FREESP(&sp); + splx(s); + if (error) { + ipstat.ips_cantforward++; + goto bad; + } +#endif /* FAST_IPSEC */ + + ip_forward(m, srcrt); } return; @@ -789,7 +876,7 @@ found: IPQ_UNLOCK(); } -#ifdef IPSEC +#if defined(IPSEC) /* * enforce IPsec policy checking if we are seeing last header. * note that we do not visit this with protocols with pcb layer @@ -801,6 +888,45 @@ found: goto bad; } #endif +#if FAST_IPSEC + /* + * enforce IPsec policy checking if we are seeing last header. + * note that we do not visit this with protocols with pcb layer + * code - like udp/tcp/raw ip. + */ + if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0) { + /* + * Check if the packet has already had IPsec processing + * done. If so, then just pass it along. This tag gets + * set during AH, ESP, etc. input handling, before the + * packet is returned to the ip input queue for delivery. + */ + mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); + s = splsoftnet(); + if (mtag != NULL) { + tdbi = (struct tdb_ident *)(mtag + 1); + sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); + } else { + sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, + IP_FORWARDING, &error); + } + if (sp != NULL) { + /* + * Check security policy against packet attributes. + */ + error = ipsec_in_reject(sp, m); + KEY_FREESP(&sp); + } else { + /* XXX error stat??? */ + error = EINVAL; +DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/ + goto bad; + } + splx(s); + if (error) + goto bad; + } +#endif /* FAST_IPSEC */ /* * Switch out to protocol's input routine. @@ -1389,6 +1515,7 @@ ip_srcroute() if (m == 0) return ((struct mbuf *)0); + MCLAIM(m, &inetdomain.dom_mowner); #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ @@ -1504,11 +1631,16 @@ ip_forward(m, srcrt) struct mbuf *mcopy; n_long dest; struct ifnet *destifp; -#ifdef IPSEC +#if defined(IPSEC) || defined(FAST_IPSEC) struct ifnet dummyifp; #endif /* + * We are now in the output path. + */ + MCLAIM(m, &ip_tx_mowner); + + /* * Clear any in-bound checksum flags for this packet. */ m->m_pkthdr.csum_flags = 0; @@ -1592,12 +1724,10 @@ ip_forward(m, srcrt) } } -#ifdef IPSEC - /* Don't lookup socket in forwarding case */ - (void)ipsec_setsocket(m, NULL); -#endif error = ip_output(m, (struct mbuf *)0, &ipforward_rt, - (IP_FORWARDING | (ip_directedbcast ? IP_ALLOWBROADCAST : 0)), 0); + (IP_FORWARDING | (ip_directedbcast ? IP_ALLOWBROADCAST : 0)), + (struct ip_moptions *)NULL, (struct socket *)NULL); + if (error) ipstat.ips_cantforward++; else { @@ -1637,7 +1767,7 @@ ip_forward(m, srcrt) case EMSGSIZE: type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG; -#ifndef IPSEC +#if !defined(IPSEC) && !defined(FAST_IPSEC) if (ipforward_rt.ro_rt) destifp = ipforward_rt.ro_rt->rt_ifp; #else @@ -1654,17 +1784,15 @@ ip_forward(m, srcrt) struct route *ro; sp = ipsec4_getpolicybyaddr(mcopy, - IPSEC_DIR_OUTBOUND, - IP_FORWARDING, - &ipsecerror); + IPSEC_DIR_OUTBOUND, IP_FORWARDING, + &ipsecerror); if (sp == NULL) destifp = ipforward_rt.ro_rt->rt_ifp; else { /* count IPsec header size */ ipsechdr = ipsec4_hdrsiz(mcopy, - IPSEC_DIR_OUTBOUND, - NULL); + IPSEC_DIR_OUTBOUND, NULL); /* * find the correct route for outer IPv4 @@ -1690,7 +1818,11 @@ ip_forward(m, srcrt) } } +#ifdef IPSEC key_freesp(sp); +#else + KEY_FREESP(&sp); +#endif } } #endif /*IPSEC*/ @@ -1924,6 +2056,9 @@ ip_sysctl(name, namelen, oldp, oldlenp, return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_maxfragpackets)); + case IPCTL_CHECKINTERFACE: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &ip_checkinterface)); default: return (EOPNOTSUPP); }