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.115 retrieving revision 1.190 diff -u -p -r1.115 -r1.190 --- src/sys/netinet/ip_input.c 2000/06/28 03:01:16 1.115 +++ src/sys/netinet/ip_input.c 2003/12/06 23:56:10 1.190 @@ -1,9 +1,9 @@ -/* $NetBSD: ip_input.c,v 1.115 2000/06/28 03:01:16 mrg Exp $ */ +/* $NetBSD: ip_input.c,v 1.190 2003/12/06 23:56:10 jonathan Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -15,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -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. * @@ -101,10 +97,16 @@ * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 */ +#include +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.190 2003/12/06 23:56:10 jonathan Exp $"); + +#include "opt_inet.h" #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 #include @@ -117,11 +119,7 @@ #include #include #include -#include #include - -#include - #include #include @@ -139,6 +137,8 @@ /* just for gif_ttl */ #include #include "gif.h" +#include +#include "gre.h" #ifdef MROUTING #include @@ -147,8 +147,11 @@ #ifdef IPSEC #include #include -#include #endif +#ifdef FAST_IPSEC +#include +#include +#endif /* FAST_IPSEC*/ #ifndef IPFORWARDING #ifdef GATEWAY @@ -167,7 +170,7 @@ #define IPALLOWSRCRT 1 /* allow source-routed packets */ #endif #ifndef IPMTUDISC -#define IPMTUDISC 0 +#define IPMTUDISC 1 #endif #ifndef IPMTUDISCTIMEOUT #define IPMTUDISCTIMEOUT (10 * 60) /* as per RFC 1191 */ @@ -191,23 +194,61 @@ int ip_forwsrcrt = IPFORWSRCRT; int ip_directedbcast = IPDIRECTEDBCAST; int ip_allowsrcrt = IPALLOWSRCRT; int ip_mtudisc = IPMTUDISC; -u_int ip_mtudisc_timeout = IPMTUDISCTIMEOUT; +int ip_mtudisc_timeout = IPMTUDISCTIMEOUT; #ifdef DIAGNOSTIC int ipprintfs = 0; #endif +int ip_do_randomid = 0; + +/* + * 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; extern struct domain inetdomain; int ipqmaxlen = IFQ_MAXLEN; -struct in_ifaddrhead in_ifaddr; +u_long in_ifaddrhash; /* size of hash table - 1 */ +int in_ifaddrentries; /* total number of addrs */ +struct in_ifaddrhead in_ifaddrhead; 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; +uint16_t ip_id; -struct ipqhead ipq; +#ifdef PFIL_HOOKS +struct pfil_head inet_pfil_hook; +#endif + +/* IP datagram reassembly queues (hashed) */ +#define IPREASS_NHASH_LOG2 6 +#define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) +#define IPREASS_HMASK (IPREASS_NHASH - 1) +#define IPREASS_HASH(x,y) \ + (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) +struct ipqhead ipq[IPREASS_NHASH]; +#ifdef notyet +static int nipq = 0; /* total # of reass queues */ +#endif int ipq_locked; +int ip_nfragpackets = 0; +int ip_maxfragpackets = 200; static __inline int ipq_lock_try __P((void)); static __inline void ipq_unlock __P((void)); @@ -217,7 +258,11 @@ ipq_lock_try() { int s; - s = splimp(); + /* + * Use splvm() -- we're blocking things that would cause + * mbuf allocation. + */ + s = splvm(); if (ipq_locked) { splx(s); return (0); @@ -232,7 +277,7 @@ ipq_unlock() { int s; - s = splimp(); + s = splvm(); ipq_locked = 0; splx(s); } @@ -244,14 +289,14 @@ do { \ printf("%s:%d: ipq already locked\n", __FILE__, __LINE__); \ panic("ipq_lock"); \ } \ -} while (0) +} while (/*CONSTCOND*/ 0) #define IPQ_LOCK_CHECK() \ do { \ if (ipq_locked == 0) { \ printf("%s:%d: ipq lock not held\n", __FILE__, __LINE__); \ panic("ipq lock check"); \ } \ -} while (0) +} while (/*CONSTCOND*/ 0) #else #define IPQ_LOCK() (void) ipq_lock_try() #define IPQ_LOCK_CHECK() /* nothing */ @@ -259,8 +304,27 @@ do { \ #define IPQ_UNLOCK() ipq_unlock() +struct pool inmulti_pool; struct pool ipqent_pool; +#ifdef INET_CSUM_COUNTERS +#include + +struct evcnt ip_hwcsum_bad = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, + NULL, "inet", "hwcsum bad"); +struct evcnt ip_hwcsum_ok = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, + NULL, "inet", "hwcsum ok"); +struct evcnt ip_swcsum = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, + NULL, "inet", "swcsum"); + +#define INET_CSUM_COUNTER_INCR(ev) (ev)->ev_count++ + +#else + +#define INET_CSUM_COUNTER_INCR(ev) /* nothing */ + +#endif /* INET_CSUM_COUNTERS */ + /* * We need to save the IP options in case a protocol wants to respond * to an incoming packet over the same route if the packet got here @@ -278,6 +342,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. @@ -288,8 +357,10 @@ 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", - 0, NULL, NULL, M_IPQ); + NULL); pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); if (pr == 0) @@ -301,18 +372,41 @@ ip_init() if (pr->pr_domain->dom_family == PF_INET && pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) ip_protox[pr->pr_protocol] = pr - inetsw; - LIST_INIT(&ipq); - ip_id = time.tv_sec & 0xffff; + for (i = 0; i < IPREASS_NHASH; i++) + LIST_INIT(&ipq[i]); + + ip_id = time.tv_sec & 0xfffff; ipintrq.ifq_maxlen = ipqmaxlen; - TAILQ_INIT(&in_ifaddr); - in_ifaddrhashtbl = - hashinit(IN_IFADDR_HASH_SIZE, M_IFADDR, M_WAITOK, &in_ifaddrhash); - if (ip_mtudisc != 0) - ip_mtudisc_timeout_q = - rt_timer_queue_create(ip_mtudisc_timeout); + TAILQ_INIT(&in_ifaddrhead); + 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(); #endif + +#ifdef PFIL_HOOKS + /* Register our Packet Filter hook. */ + inet_pfil_hook.ph_type = PFIL_TYPE_AF; + inet_pfil_hook.ph_af = AF_INET; + i = pfil_head_register(&inet_pfil_hook); + if (i != 0) + printf("ip_init: WARNING: unable to register pfil hook, " + "error %d\n", i); +#endif /* PFIL_HOOKS */ + +#ifdef INET_CSUM_COUNTERS + evcnt_attach_static(&ip_hwcsum_bad); + 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 }; @@ -328,11 +422,12 @@ ipintr() struct mbuf *m; while (1) { - s = splimp(); + s = splnet(); IF_DEQUEUE(&ipintrq, m); splx(s); if (m == 0) return; + MCLAIM(m, &ip_rx_mowner); ip_input(m); } } @@ -351,37 +446,47 @@ ip_input(struct mbuf *m) struct ipqent *ipqe; int hlen = 0, mff, len; int downmatch; -#ifdef PFIL_HOOKS - struct packet_filter_hook *pfh; - struct mbuf *m0; - int rv; -#endif /* PFIL_HOOKS */ + int checkif; + int srcrt = 0; + u_int hash; +#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. */ - if (in_ifaddr.tqh_first == 0) + if (TAILQ_FIRST(&in_ifaddrhead) == 0) goto bad; ipstat.ips_total++; - if (m->m_len < sizeof (struct ip) && - (m = m_pullup(m, sizeof (struct ip))) == 0) { - ipstat.ips_toosmall++; - return; + /* + * If the IP header is not aligned, slurp it up into a new + * mbuf with space for link headers, in the event we forward + * it. Otherwise, if it is aligned, make sure the entire + * base IP header is in the first mbuf of the chain. + */ + if (IP_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) { + if ((m = m_copyup(m, sizeof(struct ip), + (max_linkhdr + 3) & ~3)) == NULL) { + /* XXXJRT new stat, please */ + ipstat.ips_toosmall++; + return; + } + } else if (__predict_false(m->m_len < sizeof (struct ip))) { + if ((m = m_pullup(m, sizeof (struct ip))) == NULL) { + ipstat.ips_toosmall++; + return; + } } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { @@ -406,21 +511,41 @@ ip_input(struct mbuf *m) * not allowed. */ if (IN_MULTICAST(ip->ip_src.s_addr)) { - /* XXX stat */ + ipstat.ips_badaddr++; goto bad; } - if (in_cksum(m, hlen) != 0) { - ipstat.ips_badsum++; - goto bad; + /* 127/8 must not appear on wire - RFC1122 */ + 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++; + goto bad; + } } - /* - * Convert fields to host representation. - */ - NTOHS(ip->ip_len); - NTOHS(ip->ip_off); - len = ip->ip_len; + switch (m->m_pkthdr.csum_flags & + ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_IPv4) | + M_CSUM_IPv4_BAD)) { + case M_CSUM_IPv4|M_CSUM_IPv4_BAD: + INET_CSUM_COUNTER_INCR(&ip_hwcsum_bad); + goto badcsum; + + case M_CSUM_IPv4: + /* Checksum was okay. */ + INET_CSUM_COUNTER_INCR(&ip_hwcsum_ok); + break; + + default: + /* Must compute it ourselves. */ + INET_CSUM_COUNTER_INCR(&ip_swcsum); + if (in_cksum(m, hlen) != 0) + goto bad; + break; + } + + /* Retrieve the packet length. */ + len = ntohs(ip->ip_len); /* * Check for additional length bogosity @@ -448,8 +573,8 @@ ip_input(struct mbuf *m) m_adj(m, len - m->m_pkthdr.len); } -#ifdef IPSEC - /* ipflow (IP fast fowarding) is not compatible with IPsec. */ +#if defined(IPSEC) || defined(FAST_IPSEC) + /* ipflow (IP fast forwarding) is not compatible with IPsec. */ m->m_flags &= ~M_CANFASTFWD; #else /* @@ -467,21 +592,40 @@ ip_input(struct mbuf *m) * Note that filters must _never_ set this flag, as another filter * in the list may have previously cleared it. */ - m0 = m; - pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); - for (; pfh; pfh = pfh->pfil_link.tqe_next) - if (pfh->pfil_func) { - rv = pfh->pfil_func(ip, hlen, - m->m_pkthdr.rcvif, 0, &m0); - if (rv) - return; - m = m0; - if (m == NULL) - return; - ip = mtod(m, struct ip *); - } + /* + * let ipfilter look at packet on the wire, + * not the decapsulated packet. + */ +#ifdef IPSEC + if (!ipsec_getnhist(m)) +#elif defined(FAST_IPSEC) + if (!ipsec_indone(m)) +#else + 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; + 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 */ +#ifdef ALTQ + /* XXX Temporary until ALTQ is changed to use a pfil hook */ + if (altq_input != NULL && (*altq_input)(m, AF_INET) == 0) { + /* packet dropped by traffic conditioner */ + return; + } +#endif + /* * Process options and, if not destined for us, * ship it on. ip_dooptions returns 1 when an @@ -493,6 +637,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. @@ -500,10 +664,10 @@ ip_input(struct mbuf *m) * as not mine. */ downmatch = 0; - for (ia = IN_IFADDR_HASH(ip->ip_dst.s_addr).lh_first; - ia != NULL; - ia = ia->ia_hash.le_next) { + 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 @@ -513,9 +677,9 @@ ip_input(struct mbuf *m) if (ia != NULL) goto ours; if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) { - for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first; - ifa != NULL; ifa = ifa->ifa_list.tqe_next) { - if (ifa->ifa_addr->sa_family != AF_INET) continue; + TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrlist, ifa_list) { + if (ifa->ifa_addr->sa_family != AF_INET) + continue; ia = ifatoia(ifa); if (in_hosteq(ip->ip_dst, ia->ia_broadaddr.sin_addr) || in_hosteq(ip->ip_dst, ia->ia_netbroadcast) || @@ -539,7 +703,7 @@ ip_input(struct mbuf *m) #ifdef MROUTING extern struct socket *ip_mrouter; - if (m->m_flags & M_EXT) { + if (M_READONLY(m)) { if ((m = m_pullup(m, hlen)) == 0) { ipstat.ips_toosmall++; return; @@ -610,7 +774,42 @@ ip_input(struct mbuf *m) ipstat.ips_cantforward++; return; } - ip_forward(m, 0); +#ifdef IPSEC + if (ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + 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; + } + + /* + * 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; @@ -622,18 +821,31 @@ ours: * if the packet was previously fragmented, * but it's not worth the time; just let them time out.) */ - if (ip->ip_off & ~(IP_DF|IP_RF)) { + if (ip->ip_off & ~htons(IP_DF|IP_RF)) { + if (M_READONLY(m)) { + if ((m = m_pullup(m, hlen)) == NULL) { + ipstat.ips_toosmall++; + goto bad; + } + ip = mtod(m, struct ip *); + } + /* * Look for queue of fragments * of this datagram. */ IPQ_LOCK(); - for (fp = ipq.lh_first; fp != NULL; fp = fp->ipq_q.le_next) + hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); + /* XXX LIST_FOREACH(fp, &ipq[hash], ipq_q) */ + for (fp = LIST_FIRST(&ipq[hash]); fp != NULL; + fp = LIST_NEXT(fp, ipq_q)) { 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) goto found; + + } fp = 0; found: @@ -642,27 +854,28 @@ found: * set ipqe_mff if more fragments are expected, * convert offset of this to bytes. */ - ip->ip_len -= hlen; - mff = (ip->ip_off & IP_MF) != 0; + ip->ip_len = htons(ntohs(ip->ip_len) - hlen); + mff = (ip->ip_off & htons(IP_MF)) != 0; if (mff) { /* * Make sure that fragments have a data length * that's a non-zero multiple of 8 bytes. */ - if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { + if (ntohs(ip->ip_len) == 0 || + (ntohs(ip->ip_len) & 0x7) != 0) { ipstat.ips_badfrags++; IPQ_UNLOCK(); goto bad; } } - ip->ip_off <<= 3; + ip->ip_off = htons((ntohs(ip->ip_off) & IP_OFFMASK) << 3); /* * If datagram marked as having more fragments * or if this is not the first fragment, * attempt reassembly; if it succeeds, proceed. */ - if (mff || ip->ip_off) { + if (mff || ip->ip_off != htons(0)) { ipstat.ips_fragments++; ipqe = pool_get(&ipqent_pool, PR_NOWAIT); if (ipqe == NULL) { @@ -673,7 +886,7 @@ found: ipqe->ipqe_mff = mff; ipqe->ipqe_m = m; ipqe->ipqe_ip = ip; - m = ip_reass(ipqe, fp); + m = ip_reass(ipqe, fp, &ipq[hash]); if (m == 0) { IPQ_UNLOCK(); return; @@ -681,18 +894,71 @@ found: ipstat.ips_reassembled++; ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; - ip->ip_len += hlen; + ip->ip_len = htons(ntohs(ip->ip_len) + hlen); } else if (fp) ip_freef(fp); IPQ_UNLOCK(); } +#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 + * code - like udp/tcp/raw ip. + */ + if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + 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. */ #if IFA_STATS - ia->ia_ifa.ifa_data.ifad_inbytes += ip->ip_len; + if (ia && ip) + ia->ia_ifa.ifa_data.ifad_inbytes += ntohs(ip->ip_len); #endif ipstat.ips_delivered++; { @@ -703,6 +969,11 @@ found: } bad: m_freem(m); + return; + +badcsum: + ipstat.ips_badsum++; + m_freem(m); } /* @@ -712,9 +983,10 @@ bad: * is given as fp; otherwise have to make a chain. */ struct mbuf * -ip_reass(ipqe, fp) +ip_reass(ipqe, fp, ipqhead) struct ipqent *ipqe; struct ipq *fp; + struct ipqhead *ipqhead; { struct mbuf *m = ipqe->ipqe_m; struct ipqent *nq, *p, *q; @@ -736,15 +1008,26 @@ ip_reass(ipqe, fp) * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { + /* + * Enforce upper bound on number of fragmented packets + * for which we attempt reassembly; + * If maxfrag is 0, never accept fragments. + * If maxfrag is -1, accept all fragments without limitation. + */ + if (ip_maxfragpackets < 0) + ; + else if (ip_nfragpackets >= ip_maxfragpackets) + goto dropfrag; + ip_nfragpackets++; MALLOC(fp, struct ipq *, sizeof (struct ipq), M_FTABLE, M_NOWAIT); if (fp == NULL) goto dropfrag; - LIST_INSERT_HEAD(&ipq, fp, ipq_q); + LIST_INSERT_HEAD(ipqhead, fp, ipq_q); fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ipqe->ipqe_ip->ip_p; fp->ipq_id = ipqe->ipqe_ip->ip_id; - LIST_INIT(&fp->ipq_fragq); + TAILQ_INIT(&fp->ipq_fragq); fp->ipq_src = ipqe->ipqe_ip->ip_src; fp->ipq_dst = ipqe->ipqe_ip->ip_dst; p = NULL; @@ -754,9 +1037,9 @@ ip_reass(ipqe, fp) /* * Find a segment which begins after this one does. */ - for (p = NULL, q = fp->ipq_fragq.lh_first; q != NULL; - p = q, q = q->ipqe_q.le_next) - if (q->ipqe_ip->ip_off > ipqe->ipqe_ip->ip_off) + for (p = NULL, q = TAILQ_FIRST(&fp->ipq_fragq); q != NULL; + p = q, q = TAILQ_NEXT(q, ipqe_q)) + if (ntohs(q->ipqe_ip->ip_off) > ntohs(ipqe->ipqe_ip->ip_off)) break; /* @@ -765,14 +1048,16 @@ ip_reass(ipqe, fp) * segment. If it provides all of our data, drop us. */ if (p != NULL) { - i = p->ipqe_ip->ip_off + p->ipqe_ip->ip_len - - ipqe->ipqe_ip->ip_off; + i = ntohs(p->ipqe_ip->ip_off) + ntohs(p->ipqe_ip->ip_len) - + ntohs(ipqe->ipqe_ip->ip_off); if (i > 0) { - if (i >= ipqe->ipqe_ip->ip_len) + if (i >= ntohs(ipqe->ipqe_ip->ip_len)) goto dropfrag; m_adj(ipqe->ipqe_m, i); - ipqe->ipqe_ip->ip_off += i; - ipqe->ipqe_ip->ip_len -= i; + ipqe->ipqe_ip->ip_off = + htons(ntohs(ipqe->ipqe_ip->ip_off) + i); + ipqe->ipqe_ip->ip_len = + htons(ntohs(ipqe->ipqe_ip->ip_len) - i); } } @@ -780,19 +1065,22 @@ ip_reass(ipqe, fp) * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ - for (; q != NULL && ipqe->ipqe_ip->ip_off + ipqe->ipqe_ip->ip_len > - q->ipqe_ip->ip_off; q = nq) { - i = (ipqe->ipqe_ip->ip_off + ipqe->ipqe_ip->ip_len) - - q->ipqe_ip->ip_off; - if (i < q->ipqe_ip->ip_len) { - q->ipqe_ip->ip_len -= i; - q->ipqe_ip->ip_off += i; + for (; q != NULL && + ntohs(ipqe->ipqe_ip->ip_off) + ntohs(ipqe->ipqe_ip->ip_len) > + ntohs(q->ipqe_ip->ip_off); q = nq) { + i = (ntohs(ipqe->ipqe_ip->ip_off) + + ntohs(ipqe->ipqe_ip->ip_len)) - ntohs(q->ipqe_ip->ip_off); + if (i < ntohs(q->ipqe_ip->ip_len)) { + q->ipqe_ip->ip_len = + htons(ntohs(q->ipqe_ip->ip_len) - i); + q->ipqe_ip->ip_off = + htons(ntohs(q->ipqe_ip->ip_off) + i); m_adj(q->ipqe_m, i); break; } - nq = q->ipqe_q.le_next; + nq = TAILQ_NEXT(q, ipqe_q); m_freem(q->ipqe_m); - LIST_REMOVE(q, ipqe_q); + TAILQ_REMOVE(&fp->ipq_fragq, q, ipqe_q); pool_put(&ipqent_pool, q); } @@ -802,16 +1090,16 @@ insert: * check for complete reassembly. */ if (p == NULL) { - LIST_INSERT_HEAD(&fp->ipq_fragq, ipqe, ipqe_q); + TAILQ_INSERT_HEAD(&fp->ipq_fragq, ipqe, ipqe_q); } else { - LIST_INSERT_AFTER(p, ipqe, ipqe_q); + TAILQ_INSERT_AFTER(&fp->ipq_fragq, p, ipqe, ipqe_q); } next = 0; - for (p = NULL, q = fp->ipq_fragq.lh_first; q != NULL; - p = q, q = q->ipqe_q.le_next) { - if (q->ipqe_ip->ip_off != next) + for (p = NULL, q = TAILQ_FIRST(&fp->ipq_fragq); q != NULL; + p = q, q = TAILQ_NEXT(q, ipqe_q)) { + if (ntohs(q->ipqe_ip->ip_off) != next) return (0); - next += q->ipqe_ip->ip_len; + next += ntohs(q->ipqe_ip->ip_len); } if (p->ipqe_mff) return (0); @@ -820,7 +1108,7 @@ insert: * Reassembly is complete. Check for a bogus message size and * concatenate fragments. */ - q = fp->ipq_fragq.lh_first; + q = TAILQ_FIRST(&fp->ipq_fragq); ip = q->ipqe_ip; if ((next + (ip->ip_hl << 2)) > IP_MAXPACKET) { ipstat.ips_toolong++; @@ -831,11 +1119,11 @@ insert: t = m->m_next; m->m_next = 0; m_cat(m, t); - nq = q->ipqe_q.le_next; + nq = TAILQ_NEXT(q, ipqe_q); pool_put(&ipqent_pool, q); for (q = nq; q != NULL; q = nq) { t = q->ipqe_m; - nq = q->ipqe_q.le_next; + nq = TAILQ_NEXT(q, ipqe_q); pool_put(&ipqent_pool, q); m_cat(m, t); } @@ -846,11 +1134,12 @@ insert: * dequeue and discard fragment reassembly header. * Make header visible. */ - ip->ip_len = next; + ip->ip_len = htons(next); ip->ip_src = fp->ipq_src; ip->ip_dst = fp->ipq_dst; LIST_REMOVE(fp, ipq_q); FREE(fp, M_FTABLE); + ip_nfragpackets--; m->m_len += (ip->ip_hl << 2); m->m_data -= (ip->ip_hl << 2); /* some debugging cruft by sklower, below, will go away soon */ @@ -881,14 +1170,15 @@ ip_freef(fp) IPQ_LOCK_CHECK(); - for (q = fp->ipq_fragq.lh_first; q != NULL; q = p) { - p = q->ipqe_q.le_next; + for (q = TAILQ_FIRST(&fp->ipq_fragq); q != NULL; q = p) { + p = TAILQ_NEXT(q, ipqe_q); m_freem(q->ipqe_m); - LIST_REMOVE(q, ipqe_q); + TAILQ_REMOVE(&fp->ipq_fragq, q, ipqe_q); pool_put(&ipqent_pool, q); } LIST_REMOVE(fp, ipq_q); FREE(fp, M_FTABLE); + ip_nfragpackets--; } /* @@ -899,16 +1189,47 @@ ip_freef(fp) void ip_slowtimo() { + static unsigned dropscanidx = 0; + unsigned i; struct ipq *fp, *nfp; int s = splsoftnet(); IPQ_LOCK(); - for (fp = ipq.lh_first; fp != NULL; fp = nfp) { - nfp = fp->ipq_q.le_next; - if (--fp->ipq_ttl == 0) { - ipstat.ips_fragtimeout++; - ip_freef(fp); + for (i = 0; i < IPREASS_NHASH; i++) { + for (fp = LIST_FIRST(&ipq[i]); fp != NULL; fp = nfp) { + nfp = LIST_NEXT(fp, ipq_q); + if (--fp->ipq_ttl == 0) { + ipstat.ips_fragtimeout++; + ip_freef(fp); + } + } + } + /* + * If we are over the maximum number of fragments + * (due to the limit being lowered), drain off + * enough to get down to the new limit. Start draining + * from the reassembly hashqueue most recently drained. + */ + if (ip_maxfragpackets < 0) + ; + else { + int wrapped = 0; + + i = dropscanidx; + while (ip_nfragpackets > ip_maxfragpackets && wrapped == 0) { + while (LIST_FIRST(&ipq[i]) != NULL) + ip_freef(LIST_FIRST(&ipq[i])); + if (++i >= IPREASS_NHASH) { + i = 0; + } + /* + * Dont scan forever even if fragment counters are + * wrong: stop after scanning entire reassembly queue. + */ + if (i == dropscanidx) + wrapped = 1; } + dropscanidx = i; } IPQ_UNLOCK(); #ifdef GATEWAY @@ -923,6 +1244,7 @@ ip_slowtimo() void ip_drain() { + int i; /* * We may be called from a device's interrupt context. If @@ -931,9 +1253,14 @@ ip_drain() if (ipq_lock_try() == 0) return; - while (ipq.lh_first != NULL) { - ipstat.ips_fragdropped++; - ip_freef(ipq.lh_first); + for (i = 0; i < IPREASS_NHASH; i++) { + struct ipqhead *ipqh = &ipq[i]; + struct ipq *fp, *nfp; + for (fp = LIST_FIRST(ipqh); fp != NULL; fp = nfp) { + nfp = LIST_NEXT(fp, ipq_q); + ip_freef(fp); + ipstat.ips_fragdropped++; + } } IPQ_UNLOCK(); @@ -1240,6 +1567,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) */ @@ -1316,11 +1644,11 @@ ip_stripoptions(m, mopt) m->m_len -= olen; if (m->m_flags & M_PKTHDR) m->m_pkthdr.len -= olen; - ip->ip_len -= olen; + ip->ip_len = htons(ntohs(ip->ip_len) - olen); ip->ip_hl = sizeof (struct ip) >> 2; } -int inetctlerrmap[PRC_NCMDS] = { +const int inetctlerrmap[PRC_NCMDS] = { 0, 0, 0, 0, 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, @@ -1355,10 +1683,20 @@ 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; + dest = 0; #ifdef DIAGNOSTIC if (ipprintfs) @@ -1399,8 +1737,11 @@ ip_forward(m, srcrt) /* * Save at most 68 bytes of the packet in case * we need to generate an ICMP message to the src. + * Pullup to avoid sharing mbuf cluster between m and mcopy. */ - mcopy = m_copy(m, 0, imin((int)ip->ip_len, 68)); + mcopy = m_copym(m, 0, imin(ntohs(ip->ip_len), 68), M_DONTWAIT); + if (mcopy) + mcopy = m_pullup(mcopy, ip->ip_hl << 2); /* * If forwarding packet using same interface that it came in on, @@ -1435,12 +1776,10 @@ ip_forward(m, srcrt) } } -#ifdef IPSEC - /* Don't lookup socket in forwading case */ - 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 { @@ -1480,7 +1819,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 @@ -1497,17 +1836,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 @@ -1525,13 +1862,19 @@ ip_forward(m, srcrt) ro = &sp->req->sav->sah->sa_route; if (ro->ro_rt && ro->ro_rt->rt_ifp) { dummyifp.if_mtu = + ro->ro_rt->rt_rmx.rmx_mtu ? + ro->ro_rt->rt_rmx.rmx_mtu : ro->ro_rt->rt_ifp->if_mtu; dummyifp.if_mtu -= ipsechdr; destifp = &dummyifp; } } +#ifdef IPSEC key_freesp(sp); +#else + KEY_FREESP(&sp); +#endif } } #endif /*IPSEC*/ @@ -1539,9 +1882,21 @@ ip_forward(m, srcrt) break; case ENOBUFS: +#if 1 + /* + * a router should not generate ICMP_SOURCEQUENCH as + * required in RFC1812 Requirements for IP Version 4 Routers. + * source quench could be a big problem under DoS attacks, + * or if the underlying interface is rate-limited. + */ + if (mcopy) + m_freem(mcopy); + return; +#else type = ICMP_SOURCEQUENCH; code = 0; break; +#endif } icmp_error(mcopy, type, code, dest, destifp); } @@ -1606,118 +1961,184 @@ ip_savecontrol(inp, mp, ip, m) } } -int -ip_sysctl(name, namelen, oldp, oldlenp, newp, newlen) - int *name; - u_int namelen; - void *oldp; - size_t *oldlenp; - void *newp; - size_t newlen; +/* + * sysctl helper routine for net.inet.ip.mtudisctimeout. checks the + * range of the new value and tweaks timers if it changes. + */ +static int +sysctl_net_inet_ip_pmtudto(SYSCTLFN_ARGS) { - extern int subnetsarelocal, hostzeroisbroadcast; - - int error, old; + int error, tmp; + struct sysctlnode node; - /* All sysctl names at this level are terminal. */ - if (namelen != 1) - return (ENOTDIR); - - switch (name[0]) { - case IPCTL_FORWARDING: - return (sysctl_int(oldp, oldlenp, newp, newlen, &ipforwarding)); - case IPCTL_SENDREDIRECTS: - return (sysctl_int(oldp, oldlenp, newp, newlen, - &ipsendredirects)); - case IPCTL_DEFTTL: - return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_defttl)); -#ifdef notyet - case IPCTL_DEFMTU: - return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_mtu)); -#endif - case IPCTL_FORWSRCRT: - /* Don't allow this to change in a secure environment. */ - if (securelevel > 0) - return (sysctl_rdint(oldp, oldlenp, newp, - ip_forwsrcrt)); - else - return (sysctl_int(oldp, oldlenp, newp, newlen, - &ip_forwsrcrt)); - case IPCTL_DIRECTEDBCAST: - return (sysctl_int(oldp, oldlenp, newp, newlen, - &ip_directedbcast)); - case IPCTL_ALLOWSRCRT: - return (sysctl_int(oldp, oldlenp, newp, newlen, - &ip_allowsrcrt)); - case IPCTL_SUBNETSARELOCAL: - return (sysctl_int(oldp, oldlenp, newp, newlen, - &subnetsarelocal)); - case IPCTL_MTUDISC: - error = sysctl_int(oldp, oldlenp, newp, newlen, - &ip_mtudisc); - if (ip_mtudisc != 0 && ip_mtudisc_timeout_q == NULL) { - ip_mtudisc_timeout_q = - rt_timer_queue_create(ip_mtudisc_timeout); - } else if (ip_mtudisc == 0 && ip_mtudisc_timeout_q != NULL) { - rt_timer_queue_destroy(ip_mtudisc_timeout_q, TRUE); - ip_mtudisc_timeout_q = NULL; - } - return error; - case IPCTL_ANONPORTMIN: - old = anonportmin; - error = sysctl_int(oldp, oldlenp, newp, newlen, &anonportmin); - if (anonportmin >= anonportmax || anonportmin > 65535 -#ifndef IPNOPRIVPORTS - || anonportmin < IPPORT_RESERVED -#endif - ) { - anonportmin = old; - return (EINVAL); - } - return (error); - case IPCTL_ANONPORTMAX: - old = anonportmax; - error = sysctl_int(oldp, oldlenp, newp, newlen, &anonportmax); - if (anonportmin >= anonportmax || anonportmax > 65535 -#ifndef IPNOPRIVPORTS - || anonportmax < IPPORT_RESERVED -#endif - ) { - anonportmax = old; - return (EINVAL); - } - return (error); - case IPCTL_MTUDISCTIMEOUT: - error = sysctl_int(oldp, oldlenp, newp, newlen, - &ip_mtudisc_timeout); - if (ip_mtudisc_timeout_q != NULL) - rt_timer_queue_change(ip_mtudisc_timeout_q, - ip_mtudisc_timeout); + node = *rnode; + tmp = ip_mtudisc_timeout; + node.sysctl_data = &tmp; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) return (error); + if (tmp < 0) + return (EINVAL); + + ip_mtudisc_timeout = tmp; + rt_timer_queue_change(ip_mtudisc_timeout_q, ip_mtudisc_timeout); + + return (0); +} + #ifdef GATEWAY - case IPCTL_MAXFLOWS: - { - int s; +/* + * sysctl helper routine for net.inet.ip.maxflows. apparently if + * maxflows is even looked up, we "reap flows". + */ +static int +sysctl_net_inet_ip_maxflows(SYSCTLFN_ARGS) +{ + int s; - error = sysctl_int(oldp, oldlenp, newp, newlen, - &ip_maxflows); - s = splsoftnet(); - ipflow_reap(0); - splx(s); - return (error); - } -#endif - case IPCTL_HOSTZEROBROADCAST: - return (sysctl_int(oldp, oldlenp, newp, newlen, - &hostzeroisbroadcast)); -#if NGIF > 0 - case IPCTL_GIF_TTL: - return(sysctl_int(oldp, oldlenp, newp, newlen, - &ip_gif_ttl)); -#endif + s = sysctl_lookup(SYSCTLFN_CALL(rnode)); + if (s) + return (s); + + s = splsoftnet(); + ipflow_reap(0); + splx(s); - default: - return (EOPNOTSUPP); - } - /* NOTREACHED */ + return (0); +} +#endif /* GATEWAY */ + + +SYSCTL_SETUP(sysctl_net_inet_ip_setup, "sysctl net.inet.ip subtree setup") +{ + extern int subnetsarelocal, hostzeroisbroadcast; + + sysctl_createv(SYSCTL_PERMANENT, + CTLTYPE_NODE, "net", NULL, + NULL, 0, NULL, 0, + CTL_NET, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT, + CTLTYPE_NODE, "inet", NULL, + NULL, 0, NULL, 0, + CTL_NET, PF_INET, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT, + CTLTYPE_NODE, "ip", NULL, + NULL, 0, NULL, 0, + CTL_NET, PF_INET, IPPROTO_IP, CTL_EOL); + + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "forwarding", NULL, + NULL, 0, &ipforwarding, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_FORWARDING, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "redirect", NULL, + NULL, 0, &ipsendredirects, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_SENDREDIRECTS, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "ttl", NULL, + NULL, 0, &ip_defttl, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_DEFTTL, CTL_EOL); +#ifdef IPCTL_DEFMTU + sysctl_createv(SYSCTL_PERMANENT /* |SYSCTL_READWRITE? */, + CTLTYPE_INT, "mtu", NULL, + NULL, 0, &ip_mtu, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_DEFMTU, CTL_EOL); +#endif /* IPCTL_DEFMTU */ + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READONLY1, + CTLTYPE_INT, "forwsrcrt", NULL, + NULL, 0, &ip_forwsrcrt, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_FORWSRCRT, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "directed-broadcast", NULL, + NULL, 0, &ip_directedbcast, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_DIRECTEDBCAST, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "allowsrcrt", NULL, + NULL, 0, &ip_allowsrcrt, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_ALLOWSRCRT, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "subnetsarelocal", NULL, + NULL, 0, &subnetsarelocal, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_SUBNETSARELOCAL, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "mtudisc", NULL, + NULL, 0, &ip_mtudisc, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_MTUDISC, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "anonportmin", NULL, + sysctl_net_inet_ip_ports, 0, &anonportmin, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_ANONPORTMIN, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "anonportmax", NULL, + sysctl_net_inet_ip_ports, 0, &anonportmax, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_ANONPORTMAX, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "mtudisctimeout", NULL, + sysctl_net_inet_ip_pmtudto, 0, &ip_mtudisc_timeout, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_MTUDISCTIMEOUT, CTL_EOL); +#ifdef GATEWAY + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "maxflows", NULL, + sysctl_net_inet_ip_maxflows, 0, &ip_maxflows, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_MAXFLOWS, CTL_EOL); +#endif /* GATEWAY */ + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "hostzerobroadcast", NULL, + NULL, 0, &hostzeroisbroadcast, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_HOSTZEROBROADCAST, CTL_EOL); +#if NGIF > 0 + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "gifttl", NULL, + NULL, 0, &ip_gif_ttl, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_GIF_TTL, CTL_EOL); +#endif /* NGIF */ +#ifndef IPNOPRIVPORTS + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "lowportmin", NULL, + sysctl_net_inet_ip_ports, 0, &lowportmin, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_LOWPORTMIN, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "lowportmax", NULL, + sysctl_net_inet_ip_ports, 0, &lowportmax, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_LOWPORTMAX, CTL_EOL); +#endif /* IPNOPRIVPORTS */ + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "maxfragpackets", NULL, + NULL, 0, &ip_maxfragpackets, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_MAXFRAGPACKETS, CTL_EOL); +#if NGRE > 0 + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "grettl", NULL, + NULL, 0, &ip_gre_ttl, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_GRE_TTL, CTL_EOL); +#endif /* NGRE */ + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "checkinterface", NULL, + NULL, 0, &ip_checkinterface, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_CHECKINTERFACE, CTL_EOL); + sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE, + CTLTYPE_INT, "random_id", NULL, + NULL, 0, &ip_do_randomid, 0, + CTL_NET, PF_INET, IPPROTO_IP, + IPCTL_RANDOMID, CTL_EOL); }