1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1988, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 14df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 15df8bae1dSRodney W. Grimes * without specific prior written permission. 16df8bae1dSRodney W. Grimes * 17df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27df8bae1dSRodney W. Grimes * SUCH DAMAGE. 28df8bae1dSRodney W. Grimes * 29df8bae1dSRodney W. Grimes * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 30c3aac50fSPeter Wemm * $FreeBSD$ 31df8bae1dSRodney W. Grimes */ 32df8bae1dSRodney W. Grimes 33e4f4247aSEivind Eklund #include "opt_bootp.h" 3474a9466cSGary Palmer #include "opt_ipfw.h" 35b715f178SLuigi Rizzo #include "opt_ipdn.h" 36fbd1372aSJoerg Wunsch #include "opt_ipdivert.h" 371ee25934SPeter Wemm #include "opt_ipfilter.h" 3827108a15SDag-Erling Smørgrav #include "opt_ipstealth.h" 396a800098SYoshinobu Inoue #include "opt_ipsec.h" 4036b0360bSRobert Watson #include "opt_mac.h" 41c4ac87eaSDarren Reed #include "opt_pfil_hooks.h" 4264dddc18SKris Kennaway #include "opt_random_ip_id.h" 4374a9466cSGary Palmer 44df8bae1dSRodney W. Grimes #include <sys/param.h> 45df8bae1dSRodney W. Grimes #include <sys/systm.h> 4636b0360bSRobert Watson #include <sys/mac.h> 47df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 48b715f178SLuigi Rizzo #include <sys/malloc.h> 49df8bae1dSRodney W. Grimes #include <sys/domain.h> 50df8bae1dSRodney W. Grimes #include <sys/protosw.h> 51df8bae1dSRodney W. Grimes #include <sys/socket.h> 52df8bae1dSRodney W. Grimes #include <sys/time.h> 53df8bae1dSRodney W. Grimes #include <sys/kernel.h> 541025071fSGarrett Wollman #include <sys/syslog.h> 55b5e8ce9fSBruce Evans #include <sys/sysctl.h> 56df8bae1dSRodney W. Grimes 57c85540ddSAndrey A. Chernov #include <net/pfil.h> 58df8bae1dSRodney W. Grimes #include <net/if.h> 599494d596SBrooks Davis #include <net/if_types.h> 60d314ad7bSJulian Elischer #include <net/if_var.h> 6182c23ebaSBill Fenner #include <net/if_dl.h> 62df8bae1dSRodney W. Grimes #include <net/route.h> 63748e0b0aSGarrett Wollman #include <net/netisr.h> 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes #include <netinet/in.h> 66df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 67b5e8ce9fSBruce Evans #include <netinet/in_var.h> 68df8bae1dSRodney W. Grimes #include <netinet/ip.h> 69df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 70df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 71df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 7258938916SGarrett Wollman #include <machine/in_cksum.h> 73df8bae1dSRodney W. Grimes 74f0068c4aSGarrett Wollman #include <sys/socketvar.h> 756ddbf1e2SGary Palmer 766ddbf1e2SGary Palmer #include <netinet/ip_fw.h> 77ac9d7e26SMax Laier #include <netinet/ip_divert.h> 78db69a05dSPaul Saab #include <netinet/ip_dummynet.h> 79db69a05dSPaul Saab 806a800098SYoshinobu Inoue #ifdef IPSEC 816a800098SYoshinobu Inoue #include <netinet6/ipsec.h> 826a800098SYoshinobu Inoue #include <netkey/key.h> 836a800098SYoshinobu Inoue #endif 846a800098SYoshinobu Inoue 85b9234fafSSam Leffler #ifdef FAST_IPSEC 86b9234fafSSam Leffler #include <netipsec/ipsec.h> 87b9234fafSSam Leffler #include <netipsec/key.h> 88b9234fafSSam Leffler #endif 89b9234fafSSam Leffler 901c5de19aSGarrett Wollman int rsvp_on = 0; 91f0068c4aSGarrett Wollman 921f91d8c5SDavid Greenman int ipforwarding = 0; 930312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, 943d177f46SBill Fumerola &ipforwarding, 0, "Enable IP forwarding between interfaces"); 950312fbe9SPoul-Henning Kamp 96d4fb926cSGarrett Wollman static int ipsendredirects = 1; /* XXX */ 970312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, 983d177f46SBill Fumerola &ipsendredirects, 0, "Enable sending IP redirects"); 990312fbe9SPoul-Henning Kamp 100df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 1010312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, 1023d177f46SBill Fumerola &ip_defttl, 0, "Maximum TTL on IP packets"); 1030312fbe9SPoul-Henning Kamp 1040312fbe9SPoul-Henning Kamp static int ip_dosourceroute = 0; 1050312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 1063d177f46SBill Fumerola &ip_dosourceroute, 0, "Enable forwarding source routed IP packets"); 1074fce5804SGuido van Rooij 1084fce5804SGuido van Rooij static int ip_acceptsourceroute = 0; 1094fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 1103d177f46SBill Fumerola CTLFLAG_RW, &ip_acceptsourceroute, 0, 1113d177f46SBill Fumerola "Enable accepting source routed IP packets"); 1126a800098SYoshinobu Inoue 1132bde81acSAndre Oppermann int ip_doopts = 1; /* 0 = ignore, 1 = process, 2 = reject */ 1142bde81acSAndre Oppermann SYSCTL_INT(_net_inet_ip, OID_AUTO, process_options, CTLFLAG_RW, 1152bde81acSAndre Oppermann &ip_doopts, 0, "Enable IP options processing ([LS]SRR, RR, TS)"); 1162bde81acSAndre Oppermann 1176a800098SYoshinobu Inoue static int ip_keepfaith = 0; 1186a800098SYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW, 1196a800098SYoshinobu Inoue &ip_keepfaith, 0, 1206a800098SYoshinobu Inoue "Enable packet capture for FAITH IPv4->IPv6 translater daemon"); 1216a800098SYoshinobu Inoue 122402062e8SMike Silbersack static int nipq = 0; /* total # of reass queues */ 123402062e8SMike Silbersack static int maxnipq; 124690a6055SJesper Skriver SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW, 125402062e8SMike Silbersack &maxnipq, 0, 126690a6055SJesper Skriver "Maximum number of IPv4 fragment reassembly queue entries"); 127690a6055SJesper Skriver 128375386e2SMike Silbersack static int maxfragsperpacket; 129375386e2SMike Silbersack SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragsperpacket, CTLFLAG_RW, 130375386e2SMike Silbersack &maxfragsperpacket, 0, 131375386e2SMike Silbersack "Maximum number of IPv4 fragments allowed per packet"); 132375386e2SMike Silbersack 133df285b3dSMike Silbersack static int ip_sendsourcequench = 0; 134df285b3dSMike Silbersack SYSCTL_INT(_net_inet_ip, OID_AUTO, sendsourcequench, CTLFLAG_RW, 135df285b3dSMike Silbersack &ip_sendsourcequench, 0, 136df285b3dSMike Silbersack "Enable the transmission of source quench packets"); 137df285b3dSMike Silbersack 138823db0e9SDon Lewis /* 139823db0e9SDon Lewis * XXX - Setting ip_checkinterface mostly implements the receive side of 140823db0e9SDon Lewis * the Strong ES model described in RFC 1122, but since the routing table 141a8f12100SDon Lewis * and transmit implementation do not implement the Strong ES model, 142823db0e9SDon Lewis * setting this to 1 results in an odd hybrid. 1433f67c834SDon Lewis * 144a8f12100SDon Lewis * XXX - ip_checkinterface currently must be disabled if you use ipnat 145a8f12100SDon Lewis * to translate the destination address to another local interface. 1463f67c834SDon Lewis * 1473f67c834SDon Lewis * XXX - ip_checkinterface must be disabled if you add IP aliases 1483f67c834SDon Lewis * to the loopback interface instead of the interface where the 1493f67c834SDon Lewis * packets for those addresses are received. 150823db0e9SDon Lewis */ 151b3e95d4eSJonathan Lemon static int ip_checkinterface = 1; 152b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW, 153b3e95d4eSJonathan Lemon &ip_checkinterface, 0, "Verify packet arrives on correct interface"); 154b3e95d4eSJonathan Lemon 155df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1560312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 157df8bae1dSRodney W. Grimes #endif 158134ea224SSam Leffler #ifdef PFIL_HOOKS 159134ea224SSam Leffler struct pfil_head inet_pfil_hook; 160134ea224SSam Leffler #endif 161df8bae1dSRodney W. Grimes 1621cafed39SJonathan Lemon static struct ifqueue ipintrq; 163ca925d9cSJonathan Lemon static int ipqmaxlen = IFQ_MAXLEN; 164ca925d9cSJonathan Lemon 165df8bae1dSRodney W. Grimes extern struct domain inetdomain; 166f0ffb944SJulian Elischer extern struct protosw inetsw[]; 167df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 16859562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 169ca925d9cSJonathan Lemon struct in_ifaddrhashhead *in_ifaddrhashtbl; /* inet addr hash table */ 170ca925d9cSJonathan Lemon u_long in_ifaddrhmask; /* mask for hash table */ 171ca925d9cSJonathan Lemon 172afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW, 1733d177f46SBill Fumerola &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue"); 1740312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1753d177f46SBill Fumerola &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue"); 176df8bae1dSRodney W. Grimes 177f23b4c91SGarrett Wollman struct ipstat ipstat; 178c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW, 1793d177f46SBill Fumerola &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); 180194a213eSAndrey A. Chernov 181194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 182194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 183194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 184194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 185194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 186831a80b0SMatthew Dillon (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 187194a213eSAndrey A. Chernov 188462b86feSPoul-Henning Kamp static TAILQ_HEAD(ipqhead, ipq) ipq[IPREASS_NHASH]; 1892fad1e93SSam Leffler struct mtx ipqlock; 1902fad1e93SSam Leffler 1912fad1e93SSam Leffler #define IPQ_LOCK() mtx_lock(&ipqlock) 1922fad1e93SSam Leffler #define IPQ_UNLOCK() mtx_unlock(&ipqlock) 193888c2a3cSSam Leffler #define IPQ_LOCK_INIT() mtx_init(&ipqlock, "ipqlock", NULL, MTX_DEF) 194888c2a3cSSam Leffler #define IPQ_LOCK_ASSERT() mtx_assert(&ipqlock, MA_OWNED) 195f23b4c91SGarrett Wollman 1960312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1970312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1983d177f46SBill Fumerola &ip_mtu, 0, "Default MTU"); 1990312fbe9SPoul-Henning Kamp #endif 2000312fbe9SPoul-Henning Kamp 2011b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 202c76ff708SAndre Oppermann int ipstealth = 0; 2031b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW, 2041b968362SDag-Erling Smørgrav &ipstealth, 0, ""); 2051b968362SDag-Erling Smørgrav #endif 2061b968362SDag-Erling Smørgrav 207cfe8b629SGarrett Wollman 20823bf9953SPoul-Henning Kamp /* Firewall hooks */ 20923bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 2109fcc0795SLuigi Rizzo int fw_enable = 1 ; 21197850a5dSLuigi Rizzo int fw_one_pass = 1; 212e7319babSPoul-Henning Kamp 213db69a05dSPaul Saab /* Dummynet hooks */ 214db69a05dSPaul Saab ip_dn_io_t *ip_dn_io_ptr; 215b715f178SLuigi Rizzo 216929b31ddSSam Leffler /* 2174d2e3692SLuigi Rizzo * XXX this is ugly -- the following two global variables are 2184d2e3692SLuigi Rizzo * used to store packet state while it travels through the stack. 2194d2e3692SLuigi Rizzo * Note that the code even makes assumptions on the size and 2204d2e3692SLuigi Rizzo * alignment of fields inside struct ip_srcrt so e.g. adding some 2214d2e3692SLuigi Rizzo * fields will break the code. This needs to be fixed. 2224d2e3692SLuigi Rizzo * 223df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 224df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 225df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 226df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 227df8bae1dSRodney W. Grimes * to us. 228df8bae1dSRodney W. Grimes */ 2290312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 230df8bae1dSRodney W. Grimes static struct ip_srcrt { 231df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 232df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 233df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 234df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 235df8bae1dSRodney W. Grimes } ip_srcrt; 236df8bae1dSRodney W. Grimes 2374d77a549SAlfred Perlstein static void save_rte(u_char *, struct in_addr); 2382b25acc1SLuigi Rizzo static int ip_dooptions(struct mbuf *m, int, 2392b25acc1SLuigi Rizzo struct sockaddr_in *next_hop); 24002c1c707SAndre Oppermann static void ip_forward(struct mbuf *m, int srcrt, 2412b25acc1SLuigi Rizzo struct sockaddr_in *next_hop); 2424d77a549SAlfred Perlstein static void ip_freef(struct ipqhead *, struct ipq *); 243ac9d7e26SMax Laier static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *, struct ipq *); 2448948e4baSArchie Cobbs 245df8bae1dSRodney W. Grimes /* 246df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 247df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 248df8bae1dSRodney W. Grimes */ 249df8bae1dSRodney W. Grimes void 250df8bae1dSRodney W. Grimes ip_init() 251df8bae1dSRodney W. Grimes { 252f0ffb944SJulian Elischer register struct protosw *pr; 253df8bae1dSRodney W. Grimes register int i; 254df8bae1dSRodney W. Grimes 25559562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 256ca925d9cSJonathan Lemon in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask); 257f0ffb944SJulian Elischer pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 258df8bae1dSRodney W. Grimes if (pr == 0) 259df8bae1dSRodney W. Grimes panic("ip_init"); 260df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 261df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 262f0ffb944SJulian Elischer for (pr = inetdomain.dom_protosw; 263f0ffb944SJulian Elischer pr < inetdomain.dom_protoswNPROTOSW; pr++) 264df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 265df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 266df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 267194a213eSAndrey A. Chernov 268134ea224SSam Leffler #ifdef PFIL_HOOKS 269134ea224SSam Leffler inet_pfil_hook.ph_type = PFIL_TYPE_AF; 270134ea224SSam Leffler inet_pfil_hook.ph_af = AF_INET; 271134ea224SSam Leffler if ((i = pfil_head_register(&inet_pfil_hook)) != 0) 272134ea224SSam Leffler printf("%s: WARNING: unable to register pfil hook, " 273134ea224SSam Leffler "error %d\n", __func__, i); 274134ea224SSam Leffler #endif /* PFIL_HOOKS */ 275134ea224SSam Leffler 2762fad1e93SSam Leffler IPQ_LOCK_INIT(); 277194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 278462b86feSPoul-Henning Kamp TAILQ_INIT(&ipq[i]); 279194a213eSAndrey A. Chernov 280375386e2SMike Silbersack maxnipq = nmbclusters / 32; 281375386e2SMike Silbersack maxfragsperpacket = 16; 282194a213eSAndrey A. Chernov 28364dddc18SKris Kennaway #ifndef RANDOM_IP_ID 284227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 28564dddc18SKris Kennaway #endif 286df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 2876008862bSJohn Baldwin mtx_init(&ipintrq.ifq_mtx, "ip_inq", NULL, MTX_DEF); 2887902224cSSam Leffler netisr_register(NETISR_IP, ip_input, &ipintrq, NETISR_MPSAFE); 289df8bae1dSRodney W. Grimes } 290df8bae1dSRodney W. Grimes 2914d2e3692SLuigi Rizzo /* 292df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 293df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 294df8bae1dSRodney W. Grimes */ 295c67b1d17SGarrett Wollman void 296c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 297df8bae1dSRodney W. Grimes { 2989188b4a1SAndre Oppermann struct ip *ip = NULL; 29923bf9953SPoul-Henning Kamp struct ipq *fp; 3005da9f8faSJosef Karthauser struct in_ifaddr *ia = NULL; 301ca925d9cSJonathan Lemon struct ifaddr *ifa; 3029188b4a1SAndre Oppermann int i, checkif, hlen = 0; 30347c861ecSBrian Somers u_short sum; 3047538a9a0SJonathan Lemon struct in_addr pkt_dst; 305ac9d7e26SMax Laier #ifdef IPDIVERT 306ac9d7e26SMax Laier u_int32_t divert_info; /* packet divert/tee info */ 307ac9d7e26SMax Laier #endif 3082b25acc1SLuigi Rizzo struct ip_fw_args args; 30902c1c707SAndre Oppermann int dchg = 0; /* dest changed after fw */ 310f51f805fSSam Leffler #ifdef PFIL_HOOKS 311f51f805fSSam Leffler struct in_addr odst; /* original dst address */ 312f51f805fSSam Leffler #endif 313b9234fafSSam Leffler #ifdef FAST_IPSEC 31436e8826fSMax Laier struct m_tag *mtag; 315b9234fafSSam Leffler struct tdb_ident *tdbi; 316b9234fafSSam Leffler struct secpolicy *sp; 317b9234fafSSam Leffler int s, error; 318b9234fafSSam Leffler #endif /* FAST_IPSEC */ 319b715f178SLuigi Rizzo 3202b25acc1SLuigi Rizzo args.eh = NULL; 3212b25acc1SLuigi Rizzo args.oif = NULL; 322df8bae1dSRodney W. Grimes 323fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(m); 324db40007dSAndrew R. Reiter 3252f3f1e67SDarren Reed args.next_hop = m_claim_next(m, PACKET_TAG_IPFORWARD); 326ac9d7e26SMax Laier args.rule = ip_dn_claim_rule(m); 327ac9d7e26SMax Laier 328ac9d7e26SMax Laier if (m->m_flags & M_FASTFWD_OURS) { 329ac9d7e26SMax Laier /* ip_fastforward firewall changed dest to local */ 330ac9d7e26SMax Laier m->m_flags &= ~M_FASTFWD_OURS; /* for reflected mbufs */ 3319188b4a1SAndre Oppermann goto ours; 332ac9d7e26SMax Laier } 33336e8826fSMax Laier 3342b25acc1SLuigi Rizzo if (args.rule) { /* dummynet already filtered us */ 3352b25acc1SLuigi Rizzo ip = mtod(m, struct ip *); 33653be11f6SPoul-Henning Kamp hlen = ip->ip_hl << 2; 3372b25acc1SLuigi Rizzo goto iphack ; 3382b25acc1SLuigi Rizzo } 3392b25acc1SLuigi Rizzo 340df8bae1dSRodney W. Grimes ipstat.ips_total++; 34158938916SGarrett Wollman 34258938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 34358938916SGarrett Wollman goto tooshort; 34458938916SGarrett Wollman 345df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 346df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 347df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 348c67b1d17SGarrett Wollman return; 349df8bae1dSRodney W. Grimes } 350df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 35158938916SGarrett Wollman 35253be11f6SPoul-Henning Kamp if (ip->ip_v != IPVERSION) { 353df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 354df8bae1dSRodney W. Grimes goto bad; 355df8bae1dSRodney W. Grimes } 35658938916SGarrett Wollman 35753be11f6SPoul-Henning Kamp hlen = ip->ip_hl << 2; 358df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 359df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 360df8bae1dSRodney W. Grimes goto bad; 361df8bae1dSRodney W. Grimes } 362df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 363df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 364df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 365c67b1d17SGarrett Wollman return; 366df8bae1dSRodney W. Grimes } 367df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 368df8bae1dSRodney W. Grimes } 36933841545SHajimu UMEMOTO 37033841545SHajimu UMEMOTO /* 127/8 must not appear on wire - RFC1122 */ 37133841545SHajimu UMEMOTO if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || 37233841545SHajimu UMEMOTO (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { 37333841545SHajimu UMEMOTO if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 37433841545SHajimu UMEMOTO ipstat.ips_badaddr++; 37533841545SHajimu UMEMOTO goto bad; 37633841545SHajimu UMEMOTO } 37733841545SHajimu UMEMOTO } 37833841545SHajimu UMEMOTO 379db4f9cc7SJonathan Lemon if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { 380db4f9cc7SJonathan Lemon sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 381db4f9cc7SJonathan Lemon } else { 38258938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 38347c861ecSBrian Somers sum = in_cksum_hdr(ip); 38458938916SGarrett Wollman } else { 38547c861ecSBrian Somers sum = in_cksum(m, hlen); 38658938916SGarrett Wollman } 387db4f9cc7SJonathan Lemon } 38847c861ecSBrian Somers if (sum) { 389df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 390df8bae1dSRodney W. Grimes goto bad; 391df8bae1dSRodney W. Grimes } 392df8bae1dSRodney W. Grimes 39302b199f1SMax Laier #ifdef ALTQ 39402b199f1SMax Laier if (altq_input != NULL && (*altq_input)(m, AF_INET) == 0) 39502b199f1SMax Laier /* packet is dropped by traffic conditioner */ 39602b199f1SMax Laier return; 39702b199f1SMax Laier #endif 39802b199f1SMax Laier 399df8bae1dSRodney W. Grimes /* 400df8bae1dSRodney W. Grimes * Convert fields to host representation. 401df8bae1dSRodney W. Grimes */ 402fd8e4ebcSMike Barcroft ip->ip_len = ntohs(ip->ip_len); 403df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 404df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 405df8bae1dSRodney W. Grimes goto bad; 406df8bae1dSRodney W. Grimes } 407fd8e4ebcSMike Barcroft ip->ip_off = ntohs(ip->ip_off); 408df8bae1dSRodney W. Grimes 409df8bae1dSRodney W. Grimes /* 410df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 411df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 412df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 413df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 414df8bae1dSRodney W. Grimes */ 415df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 41658938916SGarrett Wollman tooshort: 417df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 418df8bae1dSRodney W. Grimes goto bad; 419df8bae1dSRodney W. Grimes } 420df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 421df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 422df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 423df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 424df8bae1dSRodney W. Grimes } else 425df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 426df8bae1dSRodney W. Grimes } 42714dd6717SSam Leffler #if defined(IPSEC) && !defined(IPSEC_FILTERGIF) 42814dd6717SSam Leffler /* 42914dd6717SSam Leffler * Bypass packet filtering for packets from a tunnel (gif). 43014dd6717SSam Leffler */ 4310f9ade71SHajimu UMEMOTO if (ipsec_getnhist(m)) 43214dd6717SSam Leffler goto pass; 43314dd6717SSam Leffler #endif 4341f76a5e2SSam Leffler #if defined(FAST_IPSEC) && !defined(IPSEC_FILTERGIF) 4351f76a5e2SSam Leffler /* 4361f76a5e2SSam Leffler * Bypass packet filtering for packets from a tunnel (gif). 4371f76a5e2SSam Leffler */ 4381f76a5e2SSam Leffler if (m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL) 4391f76a5e2SSam Leffler goto pass; 4401f76a5e2SSam Leffler #endif 4413f67c834SDon Lewis 4424dd1662bSUgen J.S. Antsilevich /* 4434dd1662bSUgen J.S. Antsilevich * IpHack's section. 4444dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 4454dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 4464dd1662bSUgen J.S. Antsilevich * deals with it. 44793e0e116SJulian Elischer * - Firewall: deny/allow/divert 448fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 449b715f178SLuigi Rizzo * - Pipe: pass pkt through dummynet. 4504dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 4514dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 4524dd1662bSUgen J.S. Antsilevich */ 453b715f178SLuigi Rizzo 454b715f178SLuigi Rizzo iphack: 455df8bae1dSRodney W. Grimes 456c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 457c4ac87eaSDarren Reed /* 458134ea224SSam Leffler * Run through list of hooks for input packets. 459f51f805fSSam Leffler * 460f51f805fSSam Leffler * NB: Beware of the destination address changing (e.g. 461f51f805fSSam Leffler * by NAT rewriting). When this happens, tell 462f51f805fSSam Leffler * ip_forward to do the right thing. 463c4ac87eaSDarren Reed */ 464f51f805fSSam Leffler odst = ip->ip_dst; 465134ea224SSam Leffler if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, 466134ea224SSam Leffler PFIL_IN) != 0) 467beec8214SDarren Reed return; 468134ea224SSam Leffler if (m == NULL) /* consumed by filter */ 469c4ac87eaSDarren Reed return; 470c4ac87eaSDarren Reed ip = mtod(m, struct ip *); 47102c1c707SAndre Oppermann dchg = (odst.s_addr != ip->ip_dst.s_addr); 472c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 473c4ac87eaSDarren Reed 4747b109fa4SLuigi Rizzo if (fw_enable && IPFW_LOADED) { 475f9e354dfSJulian Elischer /* 476f9e354dfSJulian Elischer * If we've been forwarded from the output side, then 477f9e354dfSJulian Elischer * skip the firewall a second time 478f9e354dfSJulian Elischer */ 4792b25acc1SLuigi Rizzo if (args.next_hop) 480f9e354dfSJulian Elischer goto ours; 4812b25acc1SLuigi Rizzo 4822b25acc1SLuigi Rizzo args.m = m; 4832b25acc1SLuigi Rizzo i = ip_fw_chk_ptr(&args); 4842b25acc1SLuigi Rizzo m = args.m; 4852b25acc1SLuigi Rizzo 486d60315beSLuigi Rizzo if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */ 487507b4b54SLuigi Rizzo if (m) 488507b4b54SLuigi Rizzo m_freem(m); 489b715f178SLuigi Rizzo return; 490507b4b54SLuigi Rizzo } 491d60315beSLuigi Rizzo ip = mtod(m, struct ip *); /* just in case m changed */ 4922b25acc1SLuigi Rizzo if (i == 0 && args.next_hop == NULL) /* common case */ 493b715f178SLuigi Rizzo goto pass; 4947b109fa4SLuigi Rizzo if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) { 4958948e4baSArchie Cobbs /* Send packet to the appropriate pipe */ 4962b25acc1SLuigi Rizzo ip_dn_io_ptr(m, i&0xffff, DN_TO_IP_IN, &args); 497e4676ba6SJulian Elischer return; 49893e0e116SJulian Elischer } 499b715f178SLuigi Rizzo #ifdef IPDIVERT 5008948e4baSArchie Cobbs if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) { 5018948e4baSArchie Cobbs /* Divert or tee packet */ 502b715f178SLuigi Rizzo goto ours; 503b715f178SLuigi Rizzo } 504b715f178SLuigi Rizzo #endif 5052b25acc1SLuigi Rizzo if (i == 0 && args.next_hop != NULL) 506b715f178SLuigi Rizzo goto pass; 507b715f178SLuigi Rizzo /* 508b715f178SLuigi Rizzo * if we get here, the packet must be dropped 509b715f178SLuigi Rizzo */ 510b715f178SLuigi Rizzo m_freem(m); 511b715f178SLuigi Rizzo return; 512b715f178SLuigi Rizzo } 513b715f178SLuigi Rizzo pass: 514100ba1a6SJordan K. Hubbard 515df8bae1dSRodney W. Grimes /* 516df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 517df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 518df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 519df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 520df8bae1dSRodney W. Grimes */ 521df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 5222b25acc1SLuigi Rizzo if (hlen > sizeof (struct ip) && ip_dooptions(m, 0, args.next_hop)) 523c67b1d17SGarrett Wollman return; 524df8bae1dSRodney W. Grimes 525f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 526f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 527f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 528f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 529f0068c4aSGarrett Wollman * grabbing the packet. 530f0068c4aSGarrett Wollman */ 5311c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 532f0068c4aSGarrett Wollman goto ours; 533f0068c4aSGarrett Wollman 534df8bae1dSRodney W. Grimes /* 535df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 536cc766e04SGarrett Wollman * If we don't have any addresses, assume any unicast packet 537cc766e04SGarrett Wollman * we receive might be for us (and let the upper layers deal 538cc766e04SGarrett Wollman * with it). 539df8bae1dSRodney W. Grimes */ 540cc766e04SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead) && 541cc766e04SGarrett Wollman (m->m_flags & (M_MCAST|M_BCAST)) == 0) 542cc766e04SGarrett Wollman goto ours; 543cc766e04SGarrett Wollman 5447538a9a0SJonathan Lemon /* 5457538a9a0SJonathan Lemon * Cache the destination address of the packet; this may be 5467538a9a0SJonathan Lemon * changed by use of 'ipfw fwd'. 5477538a9a0SJonathan Lemon */ 5482b25acc1SLuigi Rizzo pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst; 5497538a9a0SJonathan Lemon 550823db0e9SDon Lewis /* 551823db0e9SDon Lewis * Enable a consistency check between the destination address 552823db0e9SDon Lewis * and the arrival interface for a unicast packet (the RFC 1122 553823db0e9SDon Lewis * strong ES model) if IP forwarding is disabled and the packet 554e15ae1b2SDon Lewis * is not locally generated and the packet is not subject to 555e15ae1b2SDon Lewis * 'ipfw fwd'. 5563f67c834SDon Lewis * 5573f67c834SDon Lewis * XXX - Checking also should be disabled if the destination 5583f67c834SDon Lewis * address is ipnat'ed to a different interface. 5593f67c834SDon Lewis * 560a8f12100SDon Lewis * XXX - Checking is incompatible with IP aliases added 5613f67c834SDon Lewis * to the loopback interface instead of the interface where 5623f67c834SDon Lewis * the packets are received. 563823db0e9SDon Lewis */ 564823db0e9SDon Lewis checkif = ip_checkinterface && (ipforwarding == 0) && 5659494d596SBrooks Davis m->m_pkthdr.rcvif != NULL && 566e15ae1b2SDon Lewis ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) && 567189a0ba4SMax Laier (args.next_hop == NULL) && (dchg == 0); 568823db0e9SDon Lewis 569ca925d9cSJonathan Lemon /* 570ca925d9cSJonathan Lemon * Check for exact addresses in the hash bucket. 571ca925d9cSJonathan Lemon */ 572ca925d9cSJonathan Lemon LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) { 573f9e354dfSJulian Elischer /* 574823db0e9SDon Lewis * If the address matches, verify that the packet 575823db0e9SDon Lewis * arrived via the correct interface if checking is 576823db0e9SDon Lewis * enabled. 577f9e354dfSJulian Elischer */ 578823db0e9SDon Lewis if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && 579823db0e9SDon Lewis (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif)) 580ed1ff184SJulian Elischer goto ours; 581ca925d9cSJonathan Lemon } 582823db0e9SDon Lewis /* 583ca925d9cSJonathan Lemon * Check for broadcast addresses. 584ca925d9cSJonathan Lemon * 585ca925d9cSJonathan Lemon * Only accept broadcast packets that arrive via the matching 586ca925d9cSJonathan Lemon * interface. Reception of forwarded directed broadcasts would 587ca925d9cSJonathan Lemon * be handled via ip_forward() and ether_output() with the loopback 588ca925d9cSJonathan Lemon * into the stack for SIMPLEX interfaces handled by ether_output(). 589823db0e9SDon Lewis */ 590ca925d9cSJonathan Lemon if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) { 591ca925d9cSJonathan Lemon TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) { 592ca925d9cSJonathan Lemon if (ifa->ifa_addr->sa_family != AF_INET) 593ca925d9cSJonathan Lemon continue; 594ca925d9cSJonathan Lemon ia = ifatoia(ifa); 595df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 5967538a9a0SJonathan Lemon pkt_dst.s_addr) 597df8bae1dSRodney W. Grimes goto ours; 5987538a9a0SJonathan Lemon if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr) 599df8bae1dSRodney W. Grimes goto ours; 600ca925d9cSJonathan Lemon #ifdef BOOTP_COMPAT 601ca925d9cSJonathan Lemon if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 602ca925d9cSJonathan Lemon goto ours; 603ca925d9cSJonathan Lemon #endif 604df8bae1dSRodney W. Grimes } 605df8bae1dSRodney W. Grimes } 606df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 607df8bae1dSRodney W. Grimes struct in_multi *inm; 608df8bae1dSRodney W. Grimes if (ip_mrouter) { 609df8bae1dSRodney W. Grimes /* 610df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 611df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 612df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 613df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 614df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 615df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 616df8bae1dSRodney W. Grimes */ 617bbb4330bSLuigi Rizzo if (ip_mforward && 618bbb4330bSLuigi Rizzo ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 619df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 620df8bae1dSRodney W. Grimes m_freem(m); 621c67b1d17SGarrett Wollman return; 622df8bae1dSRodney W. Grimes } 623df8bae1dSRodney W. Grimes 624df8bae1dSRodney W. Grimes /* 62511612afaSDima Dorfman * The process-level routing daemon needs to receive 626df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 627df8bae1dSRodney W. Grimes * host belongs to their destination groups. 628df8bae1dSRodney W. Grimes */ 629df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 630df8bae1dSRodney W. Grimes goto ours; 631df8bae1dSRodney W. Grimes ipstat.ips_forward++; 632df8bae1dSRodney W. Grimes } 633df8bae1dSRodney W. Grimes /* 634df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 635df8bae1dSRodney W. Grimes * arrival interface. 636df8bae1dSRodney W. Grimes */ 637df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 638df8bae1dSRodney W. Grimes if (inm == NULL) { 63982c39223SGarrett Wollman ipstat.ips_notmember++; 640df8bae1dSRodney W. Grimes m_freem(m); 641c67b1d17SGarrett Wollman return; 642df8bae1dSRodney W. Grimes } 643df8bae1dSRodney W. Grimes goto ours; 644df8bae1dSRodney W. Grimes } 645df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 646df8bae1dSRodney W. Grimes goto ours; 647df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 648df8bae1dSRodney W. Grimes goto ours; 649df8bae1dSRodney W. Grimes 6506a800098SYoshinobu Inoue /* 6516a800098SYoshinobu Inoue * FAITH(Firewall Aided Internet Translator) 6526a800098SYoshinobu Inoue */ 6536a800098SYoshinobu Inoue if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 6546a800098SYoshinobu Inoue if (ip_keepfaith) { 6556a800098SYoshinobu Inoue if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP) 6566a800098SYoshinobu Inoue goto ours; 6576a800098SYoshinobu Inoue } 6586a800098SYoshinobu Inoue m_freem(m); 6596a800098SYoshinobu Inoue return; 6606a800098SYoshinobu Inoue } 6619494d596SBrooks Davis 662df8bae1dSRodney W. Grimes /* 663df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 664df8bae1dSRodney W. Grimes */ 665df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 666df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 667df8bae1dSRodney W. Grimes m_freem(m); 668546f251bSChris D. Faulhaber } else { 669546f251bSChris D. Faulhaber #ifdef IPSEC 670546f251bSChris D. Faulhaber /* 671546f251bSChris D. Faulhaber * Enforce inbound IPsec SPD. 672546f251bSChris D. Faulhaber */ 673546f251bSChris D. Faulhaber if (ipsec4_in_reject(m, NULL)) { 674546f251bSChris D. Faulhaber ipsecstat.in_polvio++; 675546f251bSChris D. Faulhaber goto bad; 676546f251bSChris D. Faulhaber } 677546f251bSChris D. Faulhaber #endif /* IPSEC */ 678b9234fafSSam Leffler #ifdef FAST_IPSEC 679b9234fafSSam Leffler mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 680b9234fafSSam Leffler s = splnet(); 681b9234fafSSam Leffler if (mtag != NULL) { 682b9234fafSSam Leffler tdbi = (struct tdb_ident *)(mtag + 1); 683b9234fafSSam Leffler sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); 684b9234fafSSam Leffler } else { 685b9234fafSSam Leffler sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, 686b9234fafSSam Leffler IP_FORWARDING, &error); 687b9234fafSSam Leffler } 688b9234fafSSam Leffler if (sp == NULL) { /* NB: can happen if error */ 689b9234fafSSam Leffler splx(s); 690b9234fafSSam Leffler /*XXX error stat???*/ 691b9234fafSSam Leffler DPRINTF(("ip_input: no SP for forwarding\n")); /*XXX*/ 692b9234fafSSam Leffler goto bad; 693b9234fafSSam Leffler } 694b9234fafSSam Leffler 695b9234fafSSam Leffler /* 696b9234fafSSam Leffler * Check security policy against packet attributes. 697b9234fafSSam Leffler */ 698b9234fafSSam Leffler error = ipsec_in_reject(sp, m); 699b9234fafSSam Leffler KEY_FREESP(&sp); 700b9234fafSSam Leffler splx(s); 701b9234fafSSam Leffler if (error) { 702b9234fafSSam Leffler ipstat.ips_cantforward++; 703b9234fafSSam Leffler goto bad; 704b9234fafSSam Leffler } 705b9234fafSSam Leffler #endif /* FAST_IPSEC */ 70602c1c707SAndre Oppermann ip_forward(m, dchg, args.next_hop); 707546f251bSChris D. Faulhaber } 708c67b1d17SGarrett Wollman return; 709df8bae1dSRodney W. Grimes 710df8bae1dSRodney W. Grimes ours: 711d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 712d0ebc0d2SYaroslav Tykhiy /* 713d0ebc0d2SYaroslav Tykhiy * IPSTEALTH: Process non-routing options only 714d0ebc0d2SYaroslav Tykhiy * if the packet is destined for us. 715d0ebc0d2SYaroslav Tykhiy */ 7162b25acc1SLuigi Rizzo if (ipstealth && hlen > sizeof (struct ip) && 7172b25acc1SLuigi Rizzo ip_dooptions(m, 1, args.next_hop)) 718d0ebc0d2SYaroslav Tykhiy return; 719d0ebc0d2SYaroslav Tykhiy #endif /* IPSTEALTH */ 720d0ebc0d2SYaroslav Tykhiy 7215da9f8faSJosef Karthauser /* Count the packet in the ip address stats */ 7225da9f8faSJosef Karthauser if (ia != NULL) { 7235da9f8faSJosef Karthauser ia->ia_ifa.if_ipackets++; 7245da9f8faSJosef Karthauser ia->ia_ifa.if_ibytes += m->m_pkthdr.len; 7255da9f8faSJosef Karthauser } 726100ba1a6SJordan K. Hubbard 72763f8d699SJordan K. Hubbard /* 728df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 729df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 730df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 731df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 732df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 733df8bae1dSRodney W. Grimes */ 734b6ea1aa5SRuslan Ermilov if (ip->ip_off & (IP_MF | IP_OFFMASK)) { 7356a800098SYoshinobu Inoue 736ecf44c01SMike Silbersack /* If maxnipq is 0, never accept fragments. */ 737ac64c866SMike Silbersack if (maxnipq == 0) { 738ac64c866SMike Silbersack ipstat.ips_fragments++; 739ac64c866SMike Silbersack ipstat.ips_fragdropped++; 740ac64c866SMike Silbersack goto bad; 741ac64c866SMike Silbersack } 742ac64c866SMike Silbersack 743194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 7442fad1e93SSam Leffler IPQ_LOCK(); 745df8bae1dSRodney W. Grimes /* 746df8bae1dSRodney W. Grimes * Look for queue of fragments 747df8bae1dSRodney W. Grimes * of this datagram. 748df8bae1dSRodney W. Grimes */ 749462b86feSPoul-Henning Kamp TAILQ_FOREACH(fp, &ipq[sum], ipq_list) 750df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 751df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 752df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 75336b0360bSRobert Watson #ifdef MAC 75436b0360bSRobert Watson mac_fragment_match(m, fp) && 75536b0360bSRobert Watson #endif 756df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 757df8bae1dSRodney W. Grimes goto found; 758df8bae1dSRodney W. Grimes 759042bbfa3SRobert Watson fp = NULL; 760194a213eSAndrey A. Chernov 761ac64c866SMike Silbersack /* 762ac64c866SMike Silbersack * Enforce upper bound on number of fragmented packets 763ac64c866SMike Silbersack * for which we attempt reassembly; 764ac64c866SMike Silbersack * If maxnipq is -1, accept all fragments without limitation. 765ac64c866SMike Silbersack */ 766ac64c866SMike Silbersack if ((nipq > maxnipq) && (maxnipq > 0)) { 767194a213eSAndrey A. Chernov /* 768194a213eSAndrey A. Chernov * drop something from the tail of the current queue 769194a213eSAndrey A. Chernov * before proceeding further 770194a213eSAndrey A. Chernov */ 771462b86feSPoul-Henning Kamp struct ipq *q = TAILQ_LAST(&ipq[sum], ipqhead); 772462b86feSPoul-Henning Kamp if (q == NULL) { /* gak */ 773194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 774462b86feSPoul-Henning Kamp struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead); 775462b86feSPoul-Henning Kamp if (r) { 77699e8617dSMaxim Konovalov ipstat.ips_fragtimeout += r->ipq_nfrags; 777462b86feSPoul-Henning Kamp ip_freef(&ipq[i], r); 778194a213eSAndrey A. Chernov break; 779194a213eSAndrey A. Chernov } 780194a213eSAndrey A. Chernov } 781ac64c866SMike Silbersack } else { 78299e8617dSMaxim Konovalov ipstat.ips_fragtimeout += q->ipq_nfrags; 783462b86feSPoul-Henning Kamp ip_freef(&ipq[sum], q); 784ac64c866SMike Silbersack } 785194a213eSAndrey A. Chernov } 786194a213eSAndrey A. Chernov found: 787df8bae1dSRodney W. Grimes /* 788df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 789df8bae1dSRodney W. Grimes * convert offset of this to bytes. 790df8bae1dSRodney W. Grimes */ 791df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 792b6ea1aa5SRuslan Ermilov if (ip->ip_off & IP_MF) { 7936effc713SDoug Rabson /* 7946effc713SDoug Rabson * Make sure that fragments have a data length 7956effc713SDoug Rabson * that's a non-zero multiple of 8 bytes. 7966effc713SDoug Rabson */ 7976effc713SDoug Rabson if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { 7982fad1e93SSam Leffler IPQ_UNLOCK(); 7996effc713SDoug Rabson ipstat.ips_toosmall++; /* XXX */ 8006effc713SDoug Rabson goto bad; 8016effc713SDoug Rabson } 8026effc713SDoug Rabson m->m_flags |= M_FRAG; 8031cf43499SMaxim Konovalov } else 8041cf43499SMaxim Konovalov m->m_flags &= ~M_FRAG; 805df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 806df8bae1dSRodney W. Grimes 807df8bae1dSRodney W. Grimes /* 808b6ea1aa5SRuslan Ermilov * Attempt reassembly; if it succeeds, proceed. 809ac9d7e26SMax Laier * ip_reass() will return a different mbuf. 810df8bae1dSRodney W. Grimes */ 811df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 812487bdb38SRuslan Ermilov m->m_pkthdr.header = ip; 813ac9d7e26SMax Laier m = ip_reass(m, &ipq[sum], fp); 8142fad1e93SSam Leffler IPQ_UNLOCK(); 8152b25acc1SLuigi Rizzo if (m == 0) 816c67b1d17SGarrett Wollman return; 817df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 8186a800098SYoshinobu Inoue ip = mtod(m, struct ip *); 8197e2df452SRuslan Ermilov /* Get the header length of the reassembled packet */ 82053be11f6SPoul-Henning Kamp hlen = ip->ip_hl << 2; 821af782f1cSBrian Somers #ifdef IPDIVERT 8228948e4baSArchie Cobbs /* Restore original checksum before diverting packet */ 823ac9d7e26SMax Laier if (divert_find_info(m) != 0) { 824af782f1cSBrian Somers ip->ip_len += hlen; 825fd8e4ebcSMike Barcroft ip->ip_len = htons(ip->ip_len); 826fd8e4ebcSMike Barcroft ip->ip_off = htons(ip->ip_off); 827af782f1cSBrian Somers ip->ip_sum = 0; 82860123168SRuslan Ermilov if (hlen == sizeof(struct ip)) 829af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 83060123168SRuslan Ermilov else 83160123168SRuslan Ermilov ip->ip_sum = in_cksum(m, hlen); 832fd8e4ebcSMike Barcroft ip->ip_off = ntohs(ip->ip_off); 833fd8e4ebcSMike Barcroft ip->ip_len = ntohs(ip->ip_len); 834af782f1cSBrian Somers ip->ip_len -= hlen; 835af782f1cSBrian Somers } 836af782f1cSBrian Somers #endif 837df8bae1dSRodney W. Grimes } else 838df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 839df8bae1dSRodney W. Grimes 84093e0e116SJulian Elischer #ifdef IPDIVERT 84193e0e116SJulian Elischer /* 8428948e4baSArchie Cobbs * Divert or tee packet to the divert protocol if required. 84393e0e116SJulian Elischer */ 844ac9d7e26SMax Laier divert_info = divert_find_info(m); 8458948e4baSArchie Cobbs if (divert_info != 0) { 846ac9d7e26SMax Laier struct mbuf *clone; 8478948e4baSArchie Cobbs 8488948e4baSArchie Cobbs /* Clone packet if we're doing a 'tee' */ 8498948e4baSArchie Cobbs if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0) 850ac9d7e26SMax Laier clone = divert_clone(m); 851ac9d7e26SMax Laier else 852ac9d7e26SMax Laier clone = NULL; 8538948e4baSArchie Cobbs 8548948e4baSArchie Cobbs /* Restore packet header fields to original values */ 8558948e4baSArchie Cobbs ip->ip_len += hlen; 856fd8e4ebcSMike Barcroft ip->ip_len = htons(ip->ip_len); 857fd8e4ebcSMike Barcroft ip->ip_off = htons(ip->ip_off); 8588948e4baSArchie Cobbs 8598948e4baSArchie Cobbs /* Deliver packet to divert input routine */ 860ac9d7e26SMax Laier divert_packet(m, 1); 861e4676ba6SJulian Elischer ipstat.ips_delivered++; 8628948e4baSArchie Cobbs 8638948e4baSArchie Cobbs /* If 'tee', continue with original packet */ 8648948e4baSArchie Cobbs if (clone == NULL) 86593e0e116SJulian Elischer return; 8668948e4baSArchie Cobbs m = clone; 8678948e4baSArchie Cobbs ip = mtod(m, struct ip *); 86856962689SCrist J. Clark ip->ip_len += hlen; 8692b25acc1SLuigi Rizzo /* 8702b25acc1SLuigi Rizzo * Jump backwards to complete processing of the 871ac9d7e26SMax Laier * packet. We do not need to clear args.next_hop 872ac9d7e26SMax Laier * as that will not be used again and the cloned packet 873ac9d7e26SMax Laier * doesn't contain a divert packet tag so we won't 874ac9d7e26SMax Laier * re-entry this block. 8752b25acc1SLuigi Rizzo */ 87656962689SCrist J. Clark goto pass; 87793e0e116SJulian Elischer } 87893e0e116SJulian Elischer #endif 87993e0e116SJulian Elischer 88033841545SHajimu UMEMOTO #ifdef IPSEC 88133841545SHajimu UMEMOTO /* 88233841545SHajimu UMEMOTO * enforce IPsec policy checking if we are seeing last header. 88333841545SHajimu UMEMOTO * note that we do not visit this with protocols with pcb layer 88433841545SHajimu UMEMOTO * code - like udp/tcp/raw ip. 88533841545SHajimu UMEMOTO */ 88633841545SHajimu UMEMOTO if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && 88733841545SHajimu UMEMOTO ipsec4_in_reject(m, NULL)) { 88833841545SHajimu UMEMOTO ipsecstat.in_polvio++; 88933841545SHajimu UMEMOTO goto bad; 89033841545SHajimu UMEMOTO } 89133841545SHajimu UMEMOTO #endif 892b9234fafSSam Leffler #if FAST_IPSEC 893b9234fafSSam Leffler /* 894b9234fafSSam Leffler * enforce IPsec policy checking if we are seeing last header. 895b9234fafSSam Leffler * note that we do not visit this with protocols with pcb layer 896b9234fafSSam Leffler * code - like udp/tcp/raw ip. 897b9234fafSSam Leffler */ 898b9234fafSSam Leffler if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0) { 899b9234fafSSam Leffler /* 900b9234fafSSam Leffler * Check if the packet has already had IPsec processing 901b9234fafSSam Leffler * done. If so, then just pass it along. This tag gets 902b9234fafSSam Leffler * set during AH, ESP, etc. input handling, before the 903b9234fafSSam Leffler * packet is returned to the ip input queue for delivery. 904b9234fafSSam Leffler */ 905b9234fafSSam Leffler mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 906b9234fafSSam Leffler s = splnet(); 907b9234fafSSam Leffler if (mtag != NULL) { 908b9234fafSSam Leffler tdbi = (struct tdb_ident *)(mtag + 1); 909b9234fafSSam Leffler sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); 910b9234fafSSam Leffler } else { 911b9234fafSSam Leffler sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, 912b9234fafSSam Leffler IP_FORWARDING, &error); 913b9234fafSSam Leffler } 914b9234fafSSam Leffler if (sp != NULL) { 915b9234fafSSam Leffler /* 916b9234fafSSam Leffler * Check security policy against packet attributes. 917b9234fafSSam Leffler */ 918b9234fafSSam Leffler error = ipsec_in_reject(sp, m); 919b9234fafSSam Leffler KEY_FREESP(&sp); 920b9234fafSSam Leffler } else { 921b9234fafSSam Leffler /* XXX error stat??? */ 922b9234fafSSam Leffler error = EINVAL; 923b9234fafSSam Leffler DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/ 924b9234fafSSam Leffler goto bad; 925b9234fafSSam Leffler } 926b9234fafSSam Leffler splx(s); 927b9234fafSSam Leffler if (error) 928b9234fafSSam Leffler goto bad; 929b9234fafSSam Leffler } 930b9234fafSSam Leffler #endif /* FAST_IPSEC */ 93133841545SHajimu UMEMOTO 932df8bae1dSRodney W. Grimes /* 933df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 934df8bae1dSRodney W. Grimes */ 935df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 9362b25acc1SLuigi Rizzo if (args.next_hop && ip->ip_p == IPPROTO_TCP) { 937ac9d7e26SMax Laier /* attach next hop info for TCP */ 938ac9d7e26SMax Laier struct m_tag *mtag = m_tag_get(PACKET_TAG_IPFORWARD, 939ac9d7e26SMax Laier sizeof(struct sockaddr_in *), M_NOWAIT); 940ac9d7e26SMax Laier if (mtag == NULL) 941ac9d7e26SMax Laier goto bad; 942ac9d7e26SMax Laier *(struct sockaddr_in **)(mtag+1) = args.next_hop; 943ac9d7e26SMax Laier m_tag_prepend(m, mtag); 944ac9d7e26SMax Laier } 9452b25acc1SLuigi Rizzo (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); 946c67b1d17SGarrett Wollman return; 947df8bae1dSRodney W. Grimes bad: 948df8bae1dSRodney W. Grimes m_freem(m); 949c67b1d17SGarrett Wollman } 950c67b1d17SGarrett Wollman 951c67b1d17SGarrett Wollman /* 9528948e4baSArchie Cobbs * Take incoming datagram fragment and try to reassemble it into 9538948e4baSArchie Cobbs * whole datagram. If a chain for reassembly of this datagram already 9548948e4baSArchie Cobbs * exists, then it is given as fp; otherwise have to make a chain. 9558948e4baSArchie Cobbs * 9568948e4baSArchie Cobbs * When IPDIVERT enabled, keep additional state with each packet that 9578948e4baSArchie Cobbs * tells us if we need to divert or tee the packet we're building. 9582b25acc1SLuigi Rizzo * In particular, *divinfo includes the port and TEE flag, 9592b25acc1SLuigi Rizzo * *divert_rule is the number of the matching rule. 960df8bae1dSRodney W. Grimes */ 9618948e4baSArchie Cobbs 9626a800098SYoshinobu Inoue static struct mbuf * 963ac9d7e26SMax Laier ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp) 964df8bae1dSRodney W. Grimes { 9656effc713SDoug Rabson struct ip *ip = mtod(m, struct ip *); 966b6ea1aa5SRuslan Ermilov register struct mbuf *p, *q, *nq; 967df8bae1dSRodney W. Grimes struct mbuf *t; 96853be11f6SPoul-Henning Kamp int hlen = ip->ip_hl << 2; 969df8bae1dSRodney W. Grimes int i, next; 97059dfcba4SHajimu UMEMOTO u_int8_t ecn, ecn0; 971df8bae1dSRodney W. Grimes 9722fad1e93SSam Leffler IPQ_LOCK_ASSERT(); 9732fad1e93SSam Leffler 974df8bae1dSRodney W. Grimes /* 975df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 976df8bae1dSRodney W. Grimes * would confuse code below. 977df8bae1dSRodney W. Grimes */ 978df8bae1dSRodney W. Grimes m->m_data += hlen; 979df8bae1dSRodney W. Grimes m->m_len -= hlen; 980df8bae1dSRodney W. Grimes 981df8bae1dSRodney W. Grimes /* 982df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 983df8bae1dSRodney W. Grimes */ 984042bbfa3SRobert Watson if (fp == NULL) { 985a163d034SWarner Losh if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 986df8bae1dSRodney W. Grimes goto dropfrag; 987df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 98836b0360bSRobert Watson #ifdef MAC 9895e7ce478SRobert Watson if (mac_init_ipq(fp, M_NOWAIT) != 0) { 9905e7ce478SRobert Watson m_free(t); 9915e7ce478SRobert Watson goto dropfrag; 9925e7ce478SRobert Watson } 99336b0360bSRobert Watson mac_create_ipq(m, fp); 99436b0360bSRobert Watson #endif 995462b86feSPoul-Henning Kamp TAILQ_INSERT_HEAD(head, fp, ipq_list); 996194a213eSAndrey A. Chernov nipq++; 997375386e2SMike Silbersack fp->ipq_nfrags = 1; 998df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 999df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 1000df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 10016effc713SDoug Rabson fp->ipq_src = ip->ip_src; 10026effc713SDoug Rabson fp->ipq_dst = ip->ip_dst; 1003af38c68cSLuigi Rizzo fp->ipq_frags = m; 1004af38c68cSLuigi Rizzo m->m_nextpkt = NULL; 1005af38c68cSLuigi Rizzo goto inserted; 100636b0360bSRobert Watson } else { 1007375386e2SMike Silbersack fp->ipq_nfrags++; 100836b0360bSRobert Watson #ifdef MAC 100936b0360bSRobert Watson mac_update_ipq(m, fp); 101036b0360bSRobert Watson #endif 1011df8bae1dSRodney W. Grimes } 1012df8bae1dSRodney W. Grimes 10136effc713SDoug Rabson #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) 10146effc713SDoug Rabson 1015df8bae1dSRodney W. Grimes /* 101659dfcba4SHajimu UMEMOTO * Handle ECN by comparing this segment with the first one; 101759dfcba4SHajimu UMEMOTO * if CE is set, do not lose CE. 101859dfcba4SHajimu UMEMOTO * drop if CE and not-ECT are mixed for the same packet. 101959dfcba4SHajimu UMEMOTO */ 102059dfcba4SHajimu UMEMOTO ecn = ip->ip_tos & IPTOS_ECN_MASK; 102159dfcba4SHajimu UMEMOTO ecn0 = GETIP(fp->ipq_frags)->ip_tos & IPTOS_ECN_MASK; 102259dfcba4SHajimu UMEMOTO if (ecn == IPTOS_ECN_CE) { 102359dfcba4SHajimu UMEMOTO if (ecn0 == IPTOS_ECN_NOTECT) 102459dfcba4SHajimu UMEMOTO goto dropfrag; 102559dfcba4SHajimu UMEMOTO if (ecn0 != IPTOS_ECN_CE) 102659dfcba4SHajimu UMEMOTO GETIP(fp->ipq_frags)->ip_tos |= IPTOS_ECN_CE; 102759dfcba4SHajimu UMEMOTO } 102859dfcba4SHajimu UMEMOTO if (ecn == IPTOS_ECN_NOTECT && ecn0 != IPTOS_ECN_NOTECT) 102959dfcba4SHajimu UMEMOTO goto dropfrag; 103059dfcba4SHajimu UMEMOTO 103159dfcba4SHajimu UMEMOTO /* 1032df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 1033df8bae1dSRodney W. Grimes */ 10346effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) 10356effc713SDoug Rabson if (GETIP(q)->ip_off > ip->ip_off) 1036df8bae1dSRodney W. Grimes break; 1037df8bae1dSRodney W. Grimes 1038df8bae1dSRodney W. Grimes /* 1039df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 1040df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 1041af38c68cSLuigi Rizzo * segment. If it provides all of our data, drop us, otherwise 1042af38c68cSLuigi Rizzo * stick new segment in the proper place. 1043db4f9cc7SJonathan Lemon * 1044db4f9cc7SJonathan Lemon * If some of the data is dropped from the the preceding 1045db4f9cc7SJonathan Lemon * segment, then it's checksum is invalidated. 1046df8bae1dSRodney W. Grimes */ 10476effc713SDoug Rabson if (p) { 10486effc713SDoug Rabson i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; 1049df8bae1dSRodney W. Grimes if (i > 0) { 1050df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 1051df8bae1dSRodney W. Grimes goto dropfrag; 10526a800098SYoshinobu Inoue m_adj(m, i); 1053db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags = 0; 1054df8bae1dSRodney W. Grimes ip->ip_off += i; 1055df8bae1dSRodney W. Grimes ip->ip_len -= i; 1056df8bae1dSRodney W. Grimes } 1057af38c68cSLuigi Rizzo m->m_nextpkt = p->m_nextpkt; 1058af38c68cSLuigi Rizzo p->m_nextpkt = m; 1059af38c68cSLuigi Rizzo } else { 1060af38c68cSLuigi Rizzo m->m_nextpkt = fp->ipq_frags; 1061af38c68cSLuigi Rizzo fp->ipq_frags = m; 1062df8bae1dSRodney W. Grimes } 1063df8bae1dSRodney W. Grimes 1064df8bae1dSRodney W. Grimes /* 1065df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 1066df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 1067df8bae1dSRodney W. Grimes */ 10686effc713SDoug Rabson for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; 1069af38c68cSLuigi Rizzo q = nq) { 1070b36f5b37SMaxim Konovalov i = (ip->ip_off + ip->ip_len) - GETIP(q)->ip_off; 10716effc713SDoug Rabson if (i < GETIP(q)->ip_len) { 10726effc713SDoug Rabson GETIP(q)->ip_len -= i; 10736effc713SDoug Rabson GETIP(q)->ip_off += i; 10746effc713SDoug Rabson m_adj(q, i); 1075db4f9cc7SJonathan Lemon q->m_pkthdr.csum_flags = 0; 1076df8bae1dSRodney W. Grimes break; 1077df8bae1dSRodney W. Grimes } 10786effc713SDoug Rabson nq = q->m_nextpkt; 1079af38c68cSLuigi Rizzo m->m_nextpkt = nq; 108099e8617dSMaxim Konovalov ipstat.ips_fragdropped++; 1081375386e2SMike Silbersack fp->ipq_nfrags--; 10826effc713SDoug Rabson m_freem(q); 1083df8bae1dSRodney W. Grimes } 1084df8bae1dSRodney W. Grimes 1085af38c68cSLuigi Rizzo inserted: 108693e0e116SJulian Elischer 108793e0e116SJulian Elischer #ifdef IPDIVERT 1088ac9d7e26SMax Laier if (ip->ip_off != 0) { 108993e0e116SJulian Elischer /* 1090ac9d7e26SMax Laier * Strip any divert information; only the info 1091ac9d7e26SMax Laier * on the first fragment is used/kept. 109293e0e116SJulian Elischer */ 1093ac9d7e26SMax Laier struct m_tag *mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL); 1094ac9d7e26SMax Laier if (mtag) 1095ac9d7e26SMax Laier m_tag_delete(m, mtag); 10962b25acc1SLuigi Rizzo } 109793e0e116SJulian Elischer #endif 109893e0e116SJulian Elischer 1099df8bae1dSRodney W. Grimes /* 1100375386e2SMike Silbersack * Check for complete reassembly and perform frag per packet 1101375386e2SMike Silbersack * limiting. 1102375386e2SMike Silbersack * 1103375386e2SMike Silbersack * Frag limiting is performed here so that the nth frag has 1104375386e2SMike Silbersack * a chance to complete the packet before we drop the packet. 1105375386e2SMike Silbersack * As a result, n+1 frags are actually allowed per packet, but 1106375386e2SMike Silbersack * only n will ever be stored. (n = maxfragsperpacket.) 1107375386e2SMike Silbersack * 1108df8bae1dSRodney W. Grimes */ 11096effc713SDoug Rabson next = 0; 11106effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { 1111375386e2SMike Silbersack if (GETIP(q)->ip_off != next) { 111299e8617dSMaxim Konovalov if (fp->ipq_nfrags > maxfragsperpacket) { 111399e8617dSMaxim Konovalov ipstat.ips_fragdropped += fp->ipq_nfrags; 1114375386e2SMike Silbersack ip_freef(head, fp); 111599e8617dSMaxim Konovalov } 11166effc713SDoug Rabson return (0); 1117375386e2SMike Silbersack } 11186effc713SDoug Rabson next += GETIP(q)->ip_len; 11196effc713SDoug Rabson } 11206effc713SDoug Rabson /* Make sure the last packet didn't have the IP_MF flag */ 1121375386e2SMike Silbersack if (p->m_flags & M_FRAG) { 112299e8617dSMaxim Konovalov if (fp->ipq_nfrags > maxfragsperpacket) { 112399e8617dSMaxim Konovalov ipstat.ips_fragdropped += fp->ipq_nfrags; 1124375386e2SMike Silbersack ip_freef(head, fp); 112599e8617dSMaxim Konovalov } 1126df8bae1dSRodney W. Grimes return (0); 1127375386e2SMike Silbersack } 1128df8bae1dSRodney W. Grimes 1129df8bae1dSRodney W. Grimes /* 1130430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 1131430d30d8SBill Fenner */ 11326effc713SDoug Rabson q = fp->ipq_frags; 11336effc713SDoug Rabson ip = GETIP(q); 113453be11f6SPoul-Henning Kamp if (next + (ip->ip_hl << 2) > IP_MAXPACKET) { 1135430d30d8SBill Fenner ipstat.ips_toolong++; 113699e8617dSMaxim Konovalov ipstat.ips_fragdropped += fp->ipq_nfrags; 1137462b86feSPoul-Henning Kamp ip_freef(head, fp); 1138430d30d8SBill Fenner return (0); 1139430d30d8SBill Fenner } 1140430d30d8SBill Fenner 1141430d30d8SBill Fenner /* 1142430d30d8SBill Fenner * Concatenate fragments. 1143df8bae1dSRodney W. Grimes */ 11446effc713SDoug Rabson m = q; 1145df8bae1dSRodney W. Grimes t = m->m_next; 1146df8bae1dSRodney W. Grimes m->m_next = 0; 1147df8bae1dSRodney W. Grimes m_cat(m, t); 11486effc713SDoug Rabson nq = q->m_nextpkt; 1149945aa40dSDoug Rabson q->m_nextpkt = 0; 11506effc713SDoug Rabson for (q = nq; q != NULL; q = nq) { 11516effc713SDoug Rabson nq = q->m_nextpkt; 1152945aa40dSDoug Rabson q->m_nextpkt = NULL; 1153db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; 1154db4f9cc7SJonathan Lemon m->m_pkthdr.csum_data += q->m_pkthdr.csum_data; 1155a8db1d93SJonathan Lemon m_cat(m, q); 1156df8bae1dSRodney W. Grimes } 115736b0360bSRobert Watson #ifdef MAC 115836b0360bSRobert Watson mac_create_datagram_from_ipq(fp, m); 115936b0360bSRobert Watson mac_destroy_ipq(fp); 116036b0360bSRobert Watson #endif 1161df8bae1dSRodney W. Grimes 1162df8bae1dSRodney W. Grimes /* 1163df8bae1dSRodney W. Grimes * Create header for new ip packet by 1164df8bae1dSRodney W. Grimes * modifying header of first packet; 1165df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 1166df8bae1dSRodney W. Grimes * Make header visible. 1167df8bae1dSRodney W. Grimes */ 1168df8bae1dSRodney W. Grimes ip->ip_len = next; 11696effc713SDoug Rabson ip->ip_src = fp->ipq_src; 11706effc713SDoug Rabson ip->ip_dst = fp->ipq_dst; 1171462b86feSPoul-Henning Kamp TAILQ_REMOVE(head, fp, ipq_list); 1172194a213eSAndrey A. Chernov nipq--; 1173df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 117453be11f6SPoul-Henning Kamp m->m_len += (ip->ip_hl << 2); 117553be11f6SPoul-Henning Kamp m->m_data -= (ip->ip_hl << 2); 1176df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 1177a5554bf0SPoul-Henning Kamp if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */ 1178a5554bf0SPoul-Henning Kamp m_fixhdr(m); 11796a800098SYoshinobu Inoue return (m); 1180df8bae1dSRodney W. Grimes 1181df8bae1dSRodney W. Grimes dropfrag: 1182df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 1183042bbfa3SRobert Watson if (fp != NULL) 1184375386e2SMike Silbersack fp->ipq_nfrags--; 1185df8bae1dSRodney W. Grimes m_freem(m); 1186df8bae1dSRodney W. Grimes return (0); 11876effc713SDoug Rabson 11886effc713SDoug Rabson #undef GETIP 1189df8bae1dSRodney W. Grimes } 1190df8bae1dSRodney W. Grimes 1191df8bae1dSRodney W. Grimes /* 1192df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 1193df8bae1dSRodney W. Grimes * associated datagrams. 1194df8bae1dSRodney W. Grimes */ 11950312fbe9SPoul-Henning Kamp static void 1196462b86feSPoul-Henning Kamp ip_freef(fhp, fp) 1197462b86feSPoul-Henning Kamp struct ipqhead *fhp; 1198df8bae1dSRodney W. Grimes struct ipq *fp; 1199df8bae1dSRodney W. Grimes { 12006effc713SDoug Rabson register struct mbuf *q; 1201df8bae1dSRodney W. Grimes 12022fad1e93SSam Leffler IPQ_LOCK_ASSERT(); 12032fad1e93SSam Leffler 12046effc713SDoug Rabson while (fp->ipq_frags) { 12056effc713SDoug Rabson q = fp->ipq_frags; 12066effc713SDoug Rabson fp->ipq_frags = q->m_nextpkt; 12076effc713SDoug Rabson m_freem(q); 1208df8bae1dSRodney W. Grimes } 1209462b86feSPoul-Henning Kamp TAILQ_REMOVE(fhp, fp, ipq_list); 1210df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1211194a213eSAndrey A. Chernov nipq--; 1212df8bae1dSRodney W. Grimes } 1213df8bae1dSRodney W. Grimes 1214df8bae1dSRodney W. Grimes /* 1215df8bae1dSRodney W. Grimes * IP timer processing; 1216df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 1217df8bae1dSRodney W. Grimes * queue, discard it. 1218df8bae1dSRodney W. Grimes */ 1219df8bae1dSRodney W. Grimes void 1220df8bae1dSRodney W. Grimes ip_slowtimo() 1221df8bae1dSRodney W. Grimes { 1222df8bae1dSRodney W. Grimes register struct ipq *fp; 1223df8bae1dSRodney W. Grimes int s = splnet(); 1224194a213eSAndrey A. Chernov int i; 1225df8bae1dSRodney W. Grimes 12262fad1e93SSam Leffler IPQ_LOCK(); 1227194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1228462b86feSPoul-Henning Kamp for(fp = TAILQ_FIRST(&ipq[i]); fp;) { 1229462b86feSPoul-Henning Kamp struct ipq *fpp; 1230462b86feSPoul-Henning Kamp 1231462b86feSPoul-Henning Kamp fpp = fp; 1232462b86feSPoul-Henning Kamp fp = TAILQ_NEXT(fp, ipq_list); 1233462b86feSPoul-Henning Kamp if(--fpp->ipq_ttl == 0) { 123499e8617dSMaxim Konovalov ipstat.ips_fragtimeout += fpp->ipq_nfrags; 1235462b86feSPoul-Henning Kamp ip_freef(&ipq[i], fpp); 1236df8bae1dSRodney W. Grimes } 1237df8bae1dSRodney W. Grimes } 1238194a213eSAndrey A. Chernov } 1239690a6055SJesper Skriver /* 1240690a6055SJesper Skriver * If we are over the maximum number of fragments 1241690a6055SJesper Skriver * (due to the limit being lowered), drain off 1242690a6055SJesper Skriver * enough to get down to the new limit. 1243690a6055SJesper Skriver */ 1244a75a485dSMike Silbersack if (maxnipq >= 0 && nipq > maxnipq) { 1245690a6055SJesper Skriver for (i = 0; i < IPREASS_NHASH; i++) { 1246b36f5b37SMaxim Konovalov while (nipq > maxnipq && !TAILQ_EMPTY(&ipq[i])) { 124799e8617dSMaxim Konovalov ipstat.ips_fragdropped += 124899e8617dSMaxim Konovalov TAILQ_FIRST(&ipq[i])->ipq_nfrags; 1249690a6055SJesper Skriver ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); 1250690a6055SJesper Skriver } 1251690a6055SJesper Skriver } 1252690a6055SJesper Skriver } 12532fad1e93SSam Leffler IPQ_UNLOCK(); 1254df8bae1dSRodney W. Grimes splx(s); 1255df8bae1dSRodney W. Grimes } 1256df8bae1dSRodney W. Grimes 1257df8bae1dSRodney W. Grimes /* 1258df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 1259df8bae1dSRodney W. Grimes */ 1260df8bae1dSRodney W. Grimes void 1261df8bae1dSRodney W. Grimes ip_drain() 1262df8bae1dSRodney W. Grimes { 1263194a213eSAndrey A. Chernov int i; 1264ce29ab3aSGarrett Wollman 12652fad1e93SSam Leffler IPQ_LOCK(); 1266194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1267462b86feSPoul-Henning Kamp while(!TAILQ_EMPTY(&ipq[i])) { 126899e8617dSMaxim Konovalov ipstat.ips_fragdropped += 126999e8617dSMaxim Konovalov TAILQ_FIRST(&ipq[i])->ipq_nfrags; 1270462b86feSPoul-Henning Kamp ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); 1271194a213eSAndrey A. Chernov } 1272194a213eSAndrey A. Chernov } 12732fad1e93SSam Leffler IPQ_UNLOCK(); 1274ce29ab3aSGarrett Wollman in_rtqdrain(); 1275df8bae1dSRodney W. Grimes } 1276df8bae1dSRodney W. Grimes 1277df8bae1dSRodney W. Grimes /* 1278df8bae1dSRodney W. Grimes * Do option processing on a datagram, 1279df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 1280df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 1281d0ebc0d2SYaroslav Tykhiy * The pass argument is used when operating in the IPSTEALTH 1282d0ebc0d2SYaroslav Tykhiy * mode to tell what options to process: 1283d0ebc0d2SYaroslav Tykhiy * [LS]SRR (pass 0) or the others (pass 1). 1284d0ebc0d2SYaroslav Tykhiy * The reason for as many as two passes is that when doing IPSTEALTH, 1285d0ebc0d2SYaroslav Tykhiy * non-routing options should be processed only if the packet is for us. 1286df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 1287df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 1288df8bae1dSRodney W. Grimes */ 12890312fbe9SPoul-Henning Kamp static int 12902b25acc1SLuigi Rizzo ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop) 1291df8bae1dSRodney W. Grimes { 12922b25acc1SLuigi Rizzo struct ip *ip = mtod(m, struct ip *); 12932b25acc1SLuigi Rizzo u_char *cp; 12942b25acc1SLuigi Rizzo struct in_ifaddr *ia; 1295df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 1296df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 1297df8bae1dSRodney W. Grimes n_time ntime; 12984d2e3692SLuigi Rizzo struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 1299df8bae1dSRodney W. Grimes 13002bde81acSAndre Oppermann /* ignore or reject packets with IP options */ 13012bde81acSAndre Oppermann if (ip_doopts == 0) 13022bde81acSAndre Oppermann return 0; 13032bde81acSAndre Oppermann else if (ip_doopts == 2) { 13042bde81acSAndre Oppermann type = ICMP_UNREACH; 13052bde81acSAndre Oppermann code = ICMP_UNREACH_FILTER_PROHIB; 13062bde81acSAndre Oppermann goto bad; 13072bde81acSAndre Oppermann } 13082bde81acSAndre Oppermann 1309df8bae1dSRodney W. Grimes dst = ip->ip_dst; 1310df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 131153be11f6SPoul-Henning Kamp cnt = (ip->ip_hl << 2) - sizeof (struct ip); 1312df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 1313df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 1314df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 1315df8bae1dSRodney W. Grimes break; 1316df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 1317df8bae1dSRodney W. Grimes optlen = 1; 1318df8bae1dSRodney W. Grimes else { 1319fdcb8debSJun-ichiro itojun Hagino if (cnt < IPOPT_OLEN + sizeof(*cp)) { 1320fdcb8debSJun-ichiro itojun Hagino code = &cp[IPOPT_OLEN] - (u_char *)ip; 1321fdcb8debSJun-ichiro itojun Hagino goto bad; 1322fdcb8debSJun-ichiro itojun Hagino } 1323df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 1324707d00a3SJonathan Lemon if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { 1325df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 1326df8bae1dSRodney W. Grimes goto bad; 1327df8bae1dSRodney W. Grimes } 1328df8bae1dSRodney W. Grimes } 1329df8bae1dSRodney W. Grimes switch (opt) { 1330df8bae1dSRodney W. Grimes 1331df8bae1dSRodney W. Grimes default: 1332df8bae1dSRodney W. Grimes break; 1333df8bae1dSRodney W. Grimes 1334df8bae1dSRodney W. Grimes /* 1335df8bae1dSRodney W. Grimes * Source routing with record. 1336df8bae1dSRodney W. Grimes * Find interface with current destination address. 1337df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 1338df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 1339df8bae1dSRodney W. Grimes * Record interface address and bring up next address 1340df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 1341df8bae1dSRodney W. Grimes * address is on directly accessible net. 1342df8bae1dSRodney W. Grimes */ 1343df8bae1dSRodney W. Grimes case IPOPT_LSRR: 1344df8bae1dSRodney W. Grimes case IPOPT_SSRR: 1345d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1346d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass > 0) 1347d0ebc0d2SYaroslav Tykhiy break; 1348d0ebc0d2SYaroslav Tykhiy #endif 134933841545SHajimu UMEMOTO if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 135033841545SHajimu UMEMOTO code = &cp[IPOPT_OLEN] - (u_char *)ip; 135133841545SHajimu UMEMOTO goto bad; 135233841545SHajimu UMEMOTO } 1353df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1354df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1355df8bae1dSRodney W. Grimes goto bad; 1356df8bae1dSRodney W. Grimes } 1357df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 1358df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 1359df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 1360df8bae1dSRodney W. Grimes if (ia == 0) { 1361df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1362df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1363df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1364df8bae1dSRodney W. Grimes goto bad; 1365df8bae1dSRodney W. Grimes } 1366bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1367bc189bf8SGuido van Rooij goto nosourcerouting; 1368df8bae1dSRodney W. Grimes /* 1369df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1370df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1371df8bae1dSRodney W. Grimes */ 1372df8bae1dSRodney W. Grimes break; 1373df8bae1dSRodney W. Grimes } 1374df8bae1dSRodney W. Grimes off--; /* 0 origin */ 13755d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) { 1376df8bae1dSRodney W. Grimes /* 1377df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1378df8bae1dSRodney W. Grimes */ 13794fce5804SGuido van Rooij if (!ip_acceptsourceroute) 13804fce5804SGuido van Rooij goto nosourcerouting; 1381df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 1382df8bae1dSRodney W. Grimes break; 1383df8bae1dSRodney W. Grimes } 1384d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1385d0ebc0d2SYaroslav Tykhiy if (ipstealth) 1386d0ebc0d2SYaroslav Tykhiy goto dropit; 1387d0ebc0d2SYaroslav Tykhiy #endif 13881025071fSGarrett Wollman if (!ip_dosourceroute) { 13890af8d3ecSDavid Greenman if (ipforwarding) { 13900af8d3ecSDavid Greenman char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 13910af8d3ecSDavid Greenman /* 13920af8d3ecSDavid Greenman * Acting as a router, so generate ICMP 13930af8d3ecSDavid Greenman */ 1394efa48587SGuido van Rooij nosourcerouting: 1395bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 13961025071fSGarrett Wollman log(LOG_WARNING, 13971025071fSGarrett Wollman "attempted source route from %s to %s\n", 13981025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 13991025071fSGarrett Wollman type = ICMP_UNREACH; 14001025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 14011025071fSGarrett Wollman goto bad; 14020af8d3ecSDavid Greenman } else { 14030af8d3ecSDavid Greenman /* 14040af8d3ecSDavid Greenman * Not acting as a router, so silently drop. 14050af8d3ecSDavid Greenman */ 1406d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1407d0ebc0d2SYaroslav Tykhiy dropit: 1408d0ebc0d2SYaroslav Tykhiy #endif 14090af8d3ecSDavid Greenman ipstat.ips_cantforward++; 14100af8d3ecSDavid Greenman m_freem(m); 14110af8d3ecSDavid Greenman return (1); 14120af8d3ecSDavid Greenman } 14131025071fSGarrett Wollman } 14141025071fSGarrett Wollman 1415df8bae1dSRodney W. Grimes /* 1416df8bae1dSRodney W. Grimes * locate outgoing interface 1417df8bae1dSRodney W. Grimes */ 141894a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1419df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 14201025071fSGarrett Wollman 1421df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1422df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1423df8bae1dSRodney W. Grimes #define SA struct sockaddr * 1424df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 1425df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1426df8bae1dSRodney W. Grimes } else 142702c1c707SAndre Oppermann ia = ip_rtaddr(ipaddr.sin_addr); 1428df8bae1dSRodney W. Grimes if (ia == 0) { 1429df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1430df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1431df8bae1dSRodney W. Grimes goto bad; 1432df8bae1dSRodney W. Grimes } 1433df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 143494a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 143594a5d9b6SDavid Greenman sizeof(struct in_addr)); 1436df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1437df8bae1dSRodney W. Grimes /* 1438df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1439df8bae1dSRodney W. Grimes */ 1440df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1441df8bae1dSRodney W. Grimes break; 1442df8bae1dSRodney W. Grimes 1443df8bae1dSRodney W. Grimes case IPOPT_RR: 1444d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1445d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass == 0) 1446d0ebc0d2SYaroslav Tykhiy break; 1447d0ebc0d2SYaroslav Tykhiy #endif 1448707d00a3SJonathan Lemon if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 1449707d00a3SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1450707d00a3SJonathan Lemon goto bad; 1451707d00a3SJonathan Lemon } 1452df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1453df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1454df8bae1dSRodney W. Grimes goto bad; 1455df8bae1dSRodney W. Grimes } 1456df8bae1dSRodney W. Grimes /* 1457df8bae1dSRodney W. Grimes * If no space remains, ignore. 1458df8bae1dSRodney W. Grimes */ 1459df8bae1dSRodney W. Grimes off--; /* 0 origin */ 14605d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) 1461df8bae1dSRodney W. Grimes break; 146294a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1463df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1464df8bae1dSRodney W. Grimes /* 1465df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1466df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1467df8bae1dSRodney W. Grimes */ 1468df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 146902c1c707SAndre Oppermann (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 1470df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1471df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1472df8bae1dSRodney W. Grimes goto bad; 1473df8bae1dSRodney W. Grimes } 147494a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 147594a5d9b6SDavid Greenman sizeof(struct in_addr)); 1476df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1477df8bae1dSRodney W. Grimes break; 1478df8bae1dSRodney W. Grimes 1479df8bae1dSRodney W. Grimes case IPOPT_TS: 1480d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1481d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass == 0) 1482d0ebc0d2SYaroslav Tykhiy break; 1483d0ebc0d2SYaroslav Tykhiy #endif 1484df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 148507514071SJonathan Lemon if (optlen < 4 || optlen > 40) { 148607514071SJonathan Lemon code = &cp[IPOPT_OLEN] - (u_char *)ip; 1487df8bae1dSRodney W. Grimes goto bad; 148833841545SHajimu UMEMOTO } 148907514071SJonathan Lemon if ((off = cp[IPOPT_OFFSET]) < 5) { 149007514071SJonathan Lemon code = &cp[IPOPT_OLEN] - (u_char *)ip; 149133841545SHajimu UMEMOTO goto bad; 149233841545SHajimu UMEMOTO } 149307514071SJonathan Lemon if (off > optlen - (int)sizeof(int32_t)) { 149407514071SJonathan Lemon cp[IPOPT_OFFSET + 1] += (1 << 4); 149507514071SJonathan Lemon if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) { 149607514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1497df8bae1dSRodney W. Grimes goto bad; 149833841545SHajimu UMEMOTO } 1499df8bae1dSRodney W. Grimes break; 1500df8bae1dSRodney W. Grimes } 150107514071SJonathan Lemon off--; /* 0 origin */ 150207514071SJonathan Lemon sin = (struct in_addr *)(cp + off); 150307514071SJonathan Lemon switch (cp[IPOPT_OFFSET + 1] & 0x0f) { 1504df8bae1dSRodney W. Grimes 1505df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1506df8bae1dSRodney W. Grimes break; 1507df8bae1dSRodney W. Grimes 1508df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 150907514071SJonathan Lemon if (off + sizeof(n_time) + 151007514071SJonathan Lemon sizeof(struct in_addr) > optlen) { 151107514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1512df8bae1dSRodney W. Grimes goto bad; 151333841545SHajimu UMEMOTO } 1514df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1515df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1516df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1517df8bae1dSRodney W. Grimes if (ia == 0) 1518df8bae1dSRodney W. Grimes continue; 151994a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 152094a5d9b6SDavid Greenman sizeof(struct in_addr)); 152107514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1522a5428e3aSMaxim Konovalov off += sizeof(struct in_addr); 1523df8bae1dSRodney W. Grimes break; 1524df8bae1dSRodney W. Grimes 1525df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 152607514071SJonathan Lemon if (off + sizeof(n_time) + 152707514071SJonathan Lemon sizeof(struct in_addr) > optlen) { 152807514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1529df8bae1dSRodney W. Grimes goto bad; 153033841545SHajimu UMEMOTO } 153194a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1532df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1533df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1534df8bae1dSRodney W. Grimes continue; 153507514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1536a5428e3aSMaxim Konovalov off += sizeof(struct in_addr); 1537df8bae1dSRodney W. Grimes break; 1538df8bae1dSRodney W. Grimes 1539df8bae1dSRodney W. Grimes default: 154007514071SJonathan Lemon code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip; 1541df8bae1dSRodney W. Grimes goto bad; 1542df8bae1dSRodney W. Grimes } 1543df8bae1dSRodney W. Grimes ntime = iptime(); 154407514071SJonathan Lemon (void)memcpy(cp + off, &ntime, sizeof(n_time)); 154507514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(n_time); 1546df8bae1dSRodney W. Grimes } 1547df8bae1dSRodney W. Grimes } 154847174b49SAndrey A. Chernov if (forward && ipforwarding) { 154902c1c707SAndre Oppermann ip_forward(m, 1, next_hop); 1550df8bae1dSRodney W. Grimes return (1); 1551df8bae1dSRodney W. Grimes } 1552df8bae1dSRodney W. Grimes return (0); 1553df8bae1dSRodney W. Grimes bad: 1554df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1555df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1556df8bae1dSRodney W. Grimes return (1); 1557df8bae1dSRodney W. Grimes } 1558df8bae1dSRodney W. Grimes 1559df8bae1dSRodney W. Grimes /* 1560df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1561df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1562df8bae1dSRodney W. Grimes */ 1563bd714208SRuslan Ermilov struct in_ifaddr * 156402c1c707SAndre Oppermann ip_rtaddr(dst) 1565df8bae1dSRodney W. Grimes struct in_addr dst; 1566df8bae1dSRodney W. Grimes { 156797d8d152SAndre Oppermann struct route sro; 156802c1c707SAndre Oppermann struct sockaddr_in *sin; 156902c1c707SAndre Oppermann struct in_ifaddr *ifa; 1570df8bae1dSRodney W. Grimes 15710cfbbe3bSAndre Oppermann bzero(&sro, sizeof(sro)); 157297d8d152SAndre Oppermann sin = (struct sockaddr_in *)&sro.ro_dst; 1573df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1574df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1575df8bae1dSRodney W. Grimes sin->sin_addr = dst; 157697d8d152SAndre Oppermann rtalloc_ign(&sro, RTF_CLONING); 1577df8bae1dSRodney W. Grimes 157897d8d152SAndre Oppermann if (sro.ro_rt == NULL) 1579df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 158002c1c707SAndre Oppermann 158197d8d152SAndre Oppermann ifa = ifatoia(sro.ro_rt->rt_ifa); 158297d8d152SAndre Oppermann RTFREE(sro.ro_rt); 158302c1c707SAndre Oppermann return ifa; 1584df8bae1dSRodney W. Grimes } 1585df8bae1dSRodney W. Grimes 1586df8bae1dSRodney W. Grimes /* 1587df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1588df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1589df8bae1dSRodney W. Grimes */ 159037c84183SPoul-Henning Kamp static void 1591df8bae1dSRodney W. Grimes save_rte(option, dst) 1592df8bae1dSRodney W. Grimes u_char *option; 1593df8bae1dSRodney W. Grimes struct in_addr dst; 1594df8bae1dSRodney W. Grimes { 1595df8bae1dSRodney W. Grimes unsigned olen; 1596df8bae1dSRodney W. Grimes 1597df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1598df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1599df8bae1dSRodney W. Grimes if (ipprintfs) 1600df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1601df8bae1dSRodney W. Grimes #endif 1602df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1603df8bae1dSRodney W. Grimes return; 16040453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1605df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1606df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1607df8bae1dSRodney W. Grimes } 1608df8bae1dSRodney W. Grimes 1609df8bae1dSRodney W. Grimes /* 1610df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1611df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1612df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1613df8bae1dSRodney W. Grimes */ 1614df8bae1dSRodney W. Grimes struct mbuf * 1615df8bae1dSRodney W. Grimes ip_srcroute() 1616df8bae1dSRodney W. Grimes { 1617df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1618df8bae1dSRodney W. Grimes register struct mbuf *m; 1619df8bae1dSRodney W. Grimes 1620df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1621df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1622a163d034SWarner Losh m = m_get(M_DONTWAIT, MT_HEADER); 1623df8bae1dSRodney W. Grimes if (m == 0) 1624df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1625df8bae1dSRodney W. Grimes 1626df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1627df8bae1dSRodney W. Grimes 1628df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1629df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1630df8bae1dSRodney W. Grimes OPTSIZ; 1631df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1632df8bae1dSRodney W. Grimes if (ipprintfs) 1633df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1634df8bae1dSRodney W. Grimes #endif 1635df8bae1dSRodney W. Grimes 1636df8bae1dSRodney W. Grimes /* 1637df8bae1dSRodney W. Grimes * First save first hop for return route 1638df8bae1dSRodney W. Grimes */ 1639df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1640df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1641df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1642df8bae1dSRodney W. Grimes if (ipprintfs) 1643af38c68cSLuigi Rizzo printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); 1644df8bae1dSRodney W. Grimes #endif 1645df8bae1dSRodney W. Grimes 1646df8bae1dSRodney W. Grimes /* 1647df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1648df8bae1dSRodney W. Grimes */ 1649df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1650df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 165194a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 165294a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1653df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1654df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1655df8bae1dSRodney W. Grimes #undef OPTSIZ 1656df8bae1dSRodney W. Grimes /* 1657df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1658df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1659df8bae1dSRodney W. Grimes */ 1660df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1661df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1662df8bae1dSRodney W. Grimes if (ipprintfs) 1663af38c68cSLuigi Rizzo printf(" %lx", (u_long)ntohl(q->s_addr)); 1664df8bae1dSRodney W. Grimes #endif 1665df8bae1dSRodney W. Grimes *q++ = *p--; 1666df8bae1dSRodney W. Grimes } 1667df8bae1dSRodney W. Grimes /* 1668df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1669df8bae1dSRodney W. Grimes */ 1670df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1671df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1672df8bae1dSRodney W. Grimes if (ipprintfs) 1673af38c68cSLuigi Rizzo printf(" %lx\n", (u_long)ntohl(q->s_addr)); 1674df8bae1dSRodney W. Grimes #endif 1675df8bae1dSRodney W. Grimes return (m); 1676df8bae1dSRodney W. Grimes } 1677df8bae1dSRodney W. Grimes 1678df8bae1dSRodney W. Grimes /* 1679df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1680df8bae1dSRodney W. Grimes * level protocol in the kernel. 1681df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1682df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1683df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1684df8bae1dSRodney W. Grimes */ 1685df8bae1dSRodney W. Grimes void 1686df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1687df8bae1dSRodney W. Grimes register struct mbuf *m; 1688df8bae1dSRodney W. Grimes struct mbuf *mopt; 1689df8bae1dSRodney W. Grimes { 1690df8bae1dSRodney W. Grimes register int i; 1691df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1692df8bae1dSRodney W. Grimes register caddr_t opts; 1693df8bae1dSRodney W. Grimes int olen; 1694df8bae1dSRodney W. Grimes 169553be11f6SPoul-Henning Kamp olen = (ip->ip_hl << 2) - sizeof (struct ip); 1696df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1697df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1698df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1699df8bae1dSRodney W. Grimes m->m_len -= olen; 1700df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1701df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 170253be11f6SPoul-Henning Kamp ip->ip_v = IPVERSION; 170353be11f6SPoul-Henning Kamp ip->ip_hl = sizeof(struct ip) >> 2; 1704df8bae1dSRodney W. Grimes } 1705df8bae1dSRodney W. Grimes 1706df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1707df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1708df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1709df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1710df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1711fcaf9f91SMike Silbersack 0, 0, EHOSTUNREACH, 0, 17123b8123b7SJesper Skriver ENOPROTOOPT, ECONNREFUSED 1713df8bae1dSRodney W. Grimes }; 1714df8bae1dSRodney W. Grimes 1715df8bae1dSRodney W. Grimes /* 1716df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1717df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1718df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1719df8bae1dSRodney W. Grimes * of codes and types. 1720df8bae1dSRodney W. Grimes * 1721df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1722df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1723df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1724df8bae1dSRodney W. Grimes * protocol deal with that. 1725df8bae1dSRodney W. Grimes * 1726df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1727df8bae1dSRodney W. Grimes * via a source route. 1728df8bae1dSRodney W. Grimes */ 17290312fbe9SPoul-Henning Kamp static void 173002c1c707SAndre Oppermann ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop) 1731df8bae1dSRodney W. Grimes { 17322b25acc1SLuigi Rizzo struct ip *ip = mtod(m, struct ip *); 173302c1c707SAndre Oppermann struct in_ifaddr *ia; 173426f9a767SRodney W. Grimes int error, type = 0, code = 0; 1735df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1736df8bae1dSRodney W. Grimes n_long dest; 17373efc3014SJulian Elischer struct in_addr pkt_dst; 1738df8bae1dSRodney W. Grimes struct ifnet *destifp; 1739b9234fafSSam Leffler #if defined(IPSEC) || defined(FAST_IPSEC) 17406a800098SYoshinobu Inoue struct ifnet dummyifp; 17416a800098SYoshinobu Inoue #endif 1742df8bae1dSRodney W. Grimes 17433efc3014SJulian Elischer /* 17443efc3014SJulian Elischer * Cache the destination address of the packet; this may be 17453efc3014SJulian Elischer * changed by use of 'ipfw fwd'. 17463efc3014SJulian Elischer */ 17472b25acc1SLuigi Rizzo pkt_dst = next_hop ? next_hop->sin_addr : ip->ip_dst; 17483efc3014SJulian Elischer 1749df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1750df8bae1dSRodney W. Grimes if (ipprintfs) 175161ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 17523efc3014SJulian Elischer (u_long)ip->ip_src.s_addr, (u_long)pkt_dst.s_addr, 1753162886e2SBruce Evans ip->ip_ttl); 1754df8bae1dSRodney W. Grimes #endif 1755100ba1a6SJordan K. Hubbard 1756100ba1a6SJordan K. Hubbard 17573efc3014SJulian Elischer if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(pkt_dst) == 0) { 1758df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1759df8bae1dSRodney W. Grimes m_freem(m); 1760df8bae1dSRodney W. Grimes return; 1761df8bae1dSRodney W. Grimes } 17621b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 17631b968362SDag-Erling Smørgrav if (!ipstealth) { 17641b968362SDag-Erling Smørgrav #endif 1765df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 17661b968362SDag-Erling Smørgrav icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 176702c1c707SAndre Oppermann 0, 0); 1768df8bae1dSRodney W. Grimes return; 1769df8bae1dSRodney W. Grimes } 17701b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 17711b968362SDag-Erling Smørgrav } 17721b968362SDag-Erling Smørgrav #endif 1773df8bae1dSRodney W. Grimes 177402c1c707SAndre Oppermann if ((ia = ip_rtaddr(pkt_dst)) == 0) { 177502c1c707SAndre Oppermann icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); 1776df8bae1dSRodney W. Grimes return; 177702c1c707SAndre Oppermann } 1778df8bae1dSRodney W. Grimes 1779df8bae1dSRodney W. Grimes /* 1780bfef7ed4SIan Dowse * Save the IP header and at most 8 bytes of the payload, 1781bfef7ed4SIan Dowse * in case we need to generate an ICMP message to the src. 1782bfef7ed4SIan Dowse * 17834d2e3692SLuigi Rizzo * XXX this can be optimized a lot by saving the data in a local 17844d2e3692SLuigi Rizzo * buffer on the stack (72 bytes at most), and only allocating the 17854d2e3692SLuigi Rizzo * mbuf if really necessary. The vast majority of the packets 17864d2e3692SLuigi Rizzo * are forwarded without having to send an ICMP back (either 17874d2e3692SLuigi Rizzo * because unnecessary, or because rate limited), so we are 17884d2e3692SLuigi Rizzo * really we are wasting a lot of work here. 17894d2e3692SLuigi Rizzo * 1790bfef7ed4SIan Dowse * We don't use m_copy() because it might return a reference 1791bfef7ed4SIan Dowse * to a shared cluster. Both this function and ip_output() 1792bfef7ed4SIan Dowse * assume exclusive access to the IP header in `m', so any 1793bfef7ed4SIan Dowse * data in a cluster may change before we reach icmp_error(). 1794df8bae1dSRodney W. Grimes */ 1795a163d034SWarner Losh MGET(mcopy, M_DONTWAIT, m->m_type); 1796a163d034SWarner Losh if (mcopy != NULL && !m_dup_pkthdr(mcopy, m, M_DONTWAIT)) { 17979967cafcSSam Leffler /* 17989967cafcSSam Leffler * It's probably ok if the pkthdr dup fails (because 17999967cafcSSam Leffler * the deep copy of the tag chain failed), but for now 18009967cafcSSam Leffler * be conservative and just discard the copy since 18019967cafcSSam Leffler * code below may some day want the tags. 18029967cafcSSam Leffler */ 18039967cafcSSam Leffler m_free(mcopy); 18049967cafcSSam Leffler mcopy = NULL; 18059967cafcSSam Leffler } 1806bfef7ed4SIan Dowse if (mcopy != NULL) { 180753be11f6SPoul-Henning Kamp mcopy->m_len = imin((ip->ip_hl << 2) + 8, 1808bfef7ed4SIan Dowse (int)ip->ip_len); 1809e6b0a570SBruce M Simpson mcopy->m_pkthdr.len = mcopy->m_len; 1810bfef7ed4SIan Dowse m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t)); 1811bfef7ed4SIan Dowse } 181204287599SRuslan Ermilov 181304287599SRuslan Ermilov #ifdef IPSTEALTH 181404287599SRuslan Ermilov if (!ipstealth) { 181504287599SRuslan Ermilov #endif 181604287599SRuslan Ermilov ip->ip_ttl -= IPTTLDEC; 181704287599SRuslan Ermilov #ifdef IPSTEALTH 181804287599SRuslan Ermilov } 181904287599SRuslan Ermilov #endif 1820df8bae1dSRodney W. Grimes 1821df8bae1dSRodney W. Grimes /* 1822df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1823df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1824df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1825df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1826df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1827df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1828df8bae1dSRodney W. Grimes */ 182902c1c707SAndre Oppermann dest = 0; 183002c1c707SAndre Oppermann if (ipsendredirects && ia->ia_ifp == m->m_pkthdr.rcvif) { 183102c1c707SAndre Oppermann struct sockaddr_in *sin; 183202c1c707SAndre Oppermann struct route ro; 183302c1c707SAndre Oppermann struct rtentry *rt; 183402c1c707SAndre Oppermann 18350cfbbe3bSAndre Oppermann bzero(&ro, sizeof(ro)); 183602c1c707SAndre Oppermann sin = (struct sockaddr_in *)&ro.ro_dst; 183702c1c707SAndre Oppermann sin->sin_family = AF_INET; 183802c1c707SAndre Oppermann sin->sin_len = sizeof(*sin); 183902c1c707SAndre Oppermann sin->sin_addr = pkt_dst; 184026d02ca7SAndre Oppermann rtalloc_ign(&ro, RTF_CLONING); 184102c1c707SAndre Oppermann 184202c1c707SAndre Oppermann rt = ro.ro_rt; 184302c1c707SAndre Oppermann 184402c1c707SAndre Oppermann if (rt && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1845df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 18462b25acc1SLuigi Rizzo ipsendredirects && !srcrt && !next_hop) { 1847df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1848df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1849df8bae1dSRodney W. Grimes 1850df8bae1dSRodney W. Grimes if (RTA(rt) && 1851df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1852df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1853df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1854df8bae1dSRodney W. Grimes else 18553efc3014SJulian Elischer dest = pkt_dst.s_addr; 1856df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1857df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1858df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1859df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1860df8bae1dSRodney W. Grimes if (ipprintfs) 1861df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1862df8bae1dSRodney W. Grimes #endif 1863df8bae1dSRodney W. Grimes } 1864df8bae1dSRodney W. Grimes } 186502c1c707SAndre Oppermann if (rt) 186602c1c707SAndre Oppermann RTFREE(rt); 186702c1c707SAndre Oppermann } 1868df8bae1dSRodney W. Grimes 1869ea779ff3SLuigi Rizzo if (next_hop) { 1870ac9d7e26SMax Laier struct m_tag *mtag = m_tag_get(PACKET_TAG_IPFORWARD, 1871ac9d7e26SMax Laier sizeof(struct sockaddr_in *), M_NOWAIT); 1872ac9d7e26SMax Laier if (mtag == NULL) { 1873ac9d7e26SMax Laier m_freem(m); 1874ac9d7e26SMax Laier return; 1875ac9d7e26SMax Laier } 1876ac9d7e26SMax Laier *(struct sockaddr_in **)(mtag+1) = next_hop; 1877ac9d7e26SMax Laier m_tag_prepend(m, mtag); 1878ea779ff3SLuigi Rizzo } 187902c1c707SAndre Oppermann error = ip_output(m, (struct mbuf *)0, NULL, IP_FORWARDING, 0, NULL); 1880df8bae1dSRodney W. Grimes if (error) 1881df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1882df8bae1dSRodney W. Grimes else { 1883df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1884df8bae1dSRodney W. Grimes if (type) 1885df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1886df8bae1dSRodney W. Grimes else { 18879188b4a1SAndre Oppermann if (mcopy) 1888df8bae1dSRodney W. Grimes m_freem(mcopy); 1889df8bae1dSRodney W. Grimes return; 1890df8bae1dSRodney W. Grimes } 1891df8bae1dSRodney W. Grimes } 1892df8bae1dSRodney W. Grimes if (mcopy == NULL) 1893df8bae1dSRodney W. Grimes return; 1894df8bae1dSRodney W. Grimes destifp = NULL; 1895df8bae1dSRodney W. Grimes 1896df8bae1dSRodney W. Grimes switch (error) { 1897df8bae1dSRodney W. Grimes 1898df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1899df8bae1dSRodney W. Grimes /* type, code set above */ 1900df8bae1dSRodney W. Grimes break; 1901df8bae1dSRodney W. Grimes 1902df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1903df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1904df8bae1dSRodney W. Grimes case ENETDOWN: 1905df8bae1dSRodney W. Grimes case EHOSTDOWN: 1906df8bae1dSRodney W. Grimes default: 1907df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1908df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1909df8bae1dSRodney W. Grimes break; 1910df8bae1dSRodney W. Grimes 1911df8bae1dSRodney W. Grimes case EMSGSIZE: 1912df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1913df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 191402c1c707SAndre Oppermann #if defined(IPSEC) || defined(FAST_IPSEC) 19156a800098SYoshinobu Inoue /* 19166a800098SYoshinobu Inoue * If the packet is routed over IPsec tunnel, tell the 19176a800098SYoshinobu Inoue * originator the tunnel MTU. 19186a800098SYoshinobu Inoue * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 19196a800098SYoshinobu Inoue * XXX quickhack!!! 19206a800098SYoshinobu Inoue */ 192102c1c707SAndre Oppermann { 19226a800098SYoshinobu Inoue struct secpolicy *sp = NULL; 19236a800098SYoshinobu Inoue int ipsecerror; 19246a800098SYoshinobu Inoue int ipsechdr; 192502c1c707SAndre Oppermann struct route *ro; 19266a800098SYoshinobu Inoue 192702c1c707SAndre Oppermann #ifdef IPSEC 19286a800098SYoshinobu Inoue sp = ipsec4_getpolicybyaddr(mcopy, 19296a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 19306a800098SYoshinobu Inoue IP_FORWARDING, 19316a800098SYoshinobu Inoue &ipsecerror); 193202c1c707SAndre Oppermann #else /* FAST_IPSEC */ 1933b9234fafSSam Leffler sp = ipsec_getpolicybyaddr(mcopy, 1934b9234fafSSam Leffler IPSEC_DIR_OUTBOUND, 1935b9234fafSSam Leffler IP_FORWARDING, 1936b9234fafSSam Leffler &ipsecerror); 193702c1c707SAndre Oppermann #endif 193802c1c707SAndre Oppermann if (sp != NULL) { 1939b9234fafSSam Leffler /* count IPsec header size */ 1940b9234fafSSam Leffler ipsechdr = ipsec4_hdrsiz(mcopy, 1941b9234fafSSam Leffler IPSEC_DIR_OUTBOUND, 1942b9234fafSSam Leffler NULL); 1943b9234fafSSam Leffler 1944b9234fafSSam Leffler /* 1945b9234fafSSam Leffler * find the correct route for outer IPv4 1946b9234fafSSam Leffler * header, compute tunnel MTU. 1947b9234fafSSam Leffler * 1948b9234fafSSam Leffler * XXX BUG ALERT 1949b9234fafSSam Leffler * The "dummyifp" code relies upon the fact 1950b9234fafSSam Leffler * that icmp_error() touches only ifp->if_mtu. 1951b9234fafSSam Leffler */ 1952b9234fafSSam Leffler /*XXX*/ 1953b9234fafSSam Leffler destifp = NULL; 1954b9234fafSSam Leffler if (sp->req != NULL 1955b9234fafSSam Leffler && sp->req->sav != NULL 1956b9234fafSSam Leffler && sp->req->sav->sah != NULL) { 195702c1c707SAndre Oppermann ro = &sp->req->sav->sah->sa_route; 195802c1c707SAndre Oppermann if (ro->ro_rt && ro->ro_rt->rt_ifp) { 1959b9234fafSSam Leffler dummyifp.if_mtu = 196002c1c707SAndre Oppermann ro->ro_rt->rt_ifp->if_mtu; 1961b9234fafSSam Leffler dummyifp.if_mtu -= ipsechdr; 1962b9234fafSSam Leffler destifp = &dummyifp; 1963b9234fafSSam Leffler } 1964b9234fafSSam Leffler } 1965b9234fafSSam Leffler 196602c1c707SAndre Oppermann #ifdef IPSEC 196702c1c707SAndre Oppermann key_freesp(sp); 196802c1c707SAndre Oppermann #else /* FAST_IPSEC */ 1969b9234fafSSam Leffler KEY_FREESP(&sp); 197002c1c707SAndre Oppermann #endif 197102c1c707SAndre Oppermann ipstat.ips_cantfrag++; 197202c1c707SAndre Oppermann break; 197302c1c707SAndre Oppermann } else 197402c1c707SAndre Oppermann #endif /*IPSEC || FAST_IPSEC*/ 197502c1c707SAndre Oppermann destifp = ia->ia_ifp; 197602c1c707SAndre Oppermann #if defined(IPSEC) || defined(FAST_IPSEC) 1977b9234fafSSam Leffler } 197802c1c707SAndre Oppermann #endif /*IPSEC || FAST_IPSEC*/ 1979df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1980df8bae1dSRodney W. Grimes break; 1981df8bae1dSRodney W. Grimes 1982df8bae1dSRodney W. Grimes case ENOBUFS: 1983df285b3dSMike Silbersack /* 1984df285b3dSMike Silbersack * A router should not generate ICMP_SOURCEQUENCH as 1985df285b3dSMike Silbersack * required in RFC1812 Requirements for IP Version 4 Routers. 1986df285b3dSMike Silbersack * Source quench could be a big problem under DoS attacks, 1987df285b3dSMike Silbersack * or if the underlying interface is rate-limited. 1988df285b3dSMike Silbersack * Those who need source quench packets may re-enable them 1989df285b3dSMike Silbersack * via the net.inet.ip.sendsourcequench sysctl. 1990df285b3dSMike Silbersack */ 1991df285b3dSMike Silbersack if (ip_sendsourcequench == 0) { 1992df285b3dSMike Silbersack m_freem(mcopy); 1993df285b3dSMike Silbersack return; 1994df285b3dSMike Silbersack } else { 1995df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1996df8bae1dSRodney W. Grimes code = 0; 1997df285b3dSMike Silbersack } 1998df8bae1dSRodney W. Grimes break; 19993a06e3e0SRuslan Ermilov 20003a06e3e0SRuslan Ermilov case EACCES: /* ipfw denied packet */ 20013a06e3e0SRuslan Ermilov m_freem(mcopy); 20023a06e3e0SRuslan Ermilov return; 2003df8bae1dSRodney W. Grimes } 2004df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 2005df8bae1dSRodney W. Grimes } 2006df8bae1dSRodney W. Grimes 200782c23ebaSBill Fenner void 200882c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 200982c23ebaSBill Fenner register struct inpcb *inp; 201082c23ebaSBill Fenner register struct mbuf **mp; 201182c23ebaSBill Fenner register struct ip *ip; 201282c23ebaSBill Fenner register struct mbuf *m; 201382c23ebaSBill Fenner { 2014be8a62e8SPoul-Henning Kamp if (inp->inp_socket->so_options & (SO_BINTIME | SO_TIMESTAMP)) { 2015be8a62e8SPoul-Henning Kamp struct bintime bt; 2016be8a62e8SPoul-Henning Kamp 2017be8a62e8SPoul-Henning Kamp bintime(&bt); 2018be8a62e8SPoul-Henning Kamp if (inp->inp_socket->so_options & SO_BINTIME) { 2019be8a62e8SPoul-Henning Kamp *mp = sbcreatecontrol((caddr_t) &bt, sizeof(bt), 2020be8a62e8SPoul-Henning Kamp SCM_BINTIME, SOL_SOCKET); 2021be8a62e8SPoul-Henning Kamp if (*mp) 2022be8a62e8SPoul-Henning Kamp mp = &(*mp)->m_next; 2023be8a62e8SPoul-Henning Kamp } 202482c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 202582c23ebaSBill Fenner struct timeval tv; 202682c23ebaSBill Fenner 2027be8a62e8SPoul-Henning Kamp bintime2timeval(&bt, &tv); 202882c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 202982c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 203082c23ebaSBill Fenner if (*mp) 203182c23ebaSBill Fenner mp = &(*mp)->m_next; 20324cc20ab1SSeigo Tanimura } 2033be8a62e8SPoul-Henning Kamp } 203482c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 203582c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 203682c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 203782c23ebaSBill Fenner if (*mp) 203882c23ebaSBill Fenner mp = &(*mp)->m_next; 203982c23ebaSBill Fenner } 20404957466bSMatthew N. Dodd if (inp->inp_flags & INP_RECVTTL) { 20414957466bSMatthew N. Dodd *mp = sbcreatecontrol((caddr_t) &ip->ip_ttl, 20424957466bSMatthew N. Dodd sizeof(u_char), IP_RECVTTL, IPPROTO_IP); 20434957466bSMatthew N. Dodd if (*mp) 20444957466bSMatthew N. Dodd mp = &(*mp)->m_next; 20454957466bSMatthew N. Dodd } 204682c23ebaSBill Fenner #ifdef notyet 204782c23ebaSBill Fenner /* XXX 204882c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 204982c23ebaSBill Fenner * than they already were. 205082c23ebaSBill Fenner */ 205182c23ebaSBill Fenner /* options were tossed already */ 205282c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 205382c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 205482c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 205582c23ebaSBill Fenner if (*mp) 205682c23ebaSBill Fenner mp = &(*mp)->m_next; 205782c23ebaSBill Fenner } 205882c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 205982c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 206082c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 206182c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 206282c23ebaSBill Fenner if (*mp) 206382c23ebaSBill Fenner mp = &(*mp)->m_next; 206482c23ebaSBill Fenner } 206582c23ebaSBill Fenner #endif 206682c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 2067d314ad7bSJulian Elischer struct ifnet *ifp; 2068d314ad7bSJulian Elischer struct sdlbuf { 206982c23ebaSBill Fenner struct sockaddr_dl sdl; 2070d314ad7bSJulian Elischer u_char pad[32]; 2071d314ad7bSJulian Elischer } sdlbuf; 2072d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 2073d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 207482c23ebaSBill Fenner 2075d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 2076d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 2077f9132cebSJonathan Lemon sdp = (struct sockaddr_dl *) 2078f9132cebSJonathan Lemon (ifaddr_byindex(ifp->if_index)->ifa_addr); 2079d314ad7bSJulian Elischer /* 2080d314ad7bSJulian Elischer * Change our mind and don't try copy. 2081d314ad7bSJulian Elischer */ 2082d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 2083d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 2084d314ad7bSJulian Elischer goto makedummy; 2085d314ad7bSJulian Elischer } 2086d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 2087d314ad7bSJulian Elischer } else { 2088d314ad7bSJulian Elischer makedummy: 2089d314ad7bSJulian Elischer sdl2->sdl_len 2090d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 2091d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 2092d314ad7bSJulian Elischer sdl2->sdl_index = 0; 2093d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 2094d314ad7bSJulian Elischer } 2095d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 209682c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 209782c23ebaSBill Fenner if (*mp) 209882c23ebaSBill Fenner mp = &(*mp)->m_next; 209982c23ebaSBill Fenner } 210082c23ebaSBill Fenner } 210182c23ebaSBill Fenner 21024d2e3692SLuigi Rizzo /* 21034d2e3692SLuigi Rizzo * XXX these routines are called from the upper part of the kernel. 21044d2e3692SLuigi Rizzo * They need to be locked when we remove Giant. 21054d2e3692SLuigi Rizzo * 21064d2e3692SLuigi Rizzo * They could also be moved to ip_mroute.c, since all the RSVP 21074d2e3692SLuigi Rizzo * handling is done there already. 21084d2e3692SLuigi Rizzo */ 21094d2e3692SLuigi Rizzo static int ip_rsvp_on; 21104d2e3692SLuigi Rizzo struct socket *ip_rsvpd; 2111df8bae1dSRodney W. Grimes int 2112f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 2113f0068c4aSGarrett Wollman { 2114f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 2115f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 2116f0068c4aSGarrett Wollman return EOPNOTSUPP; 2117f0068c4aSGarrett Wollman 2118f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 2119f0068c4aSGarrett Wollman return EADDRINUSE; 2120f0068c4aSGarrett Wollman 2121f0068c4aSGarrett Wollman ip_rsvpd = so; 21221c5de19aSGarrett Wollman /* 21231c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 21241c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 21251c5de19aSGarrett Wollman */ 21261c5de19aSGarrett Wollman if (!ip_rsvp_on) { 21271c5de19aSGarrett Wollman ip_rsvp_on = 1; 21281c5de19aSGarrett Wollman rsvp_on++; 21291c5de19aSGarrett Wollman } 2130f0068c4aSGarrett Wollman 2131f0068c4aSGarrett Wollman return 0; 2132f0068c4aSGarrett Wollman } 2133f0068c4aSGarrett Wollman 2134f0068c4aSGarrett Wollman int 2135f0068c4aSGarrett Wollman ip_rsvp_done(void) 2136f0068c4aSGarrett Wollman { 2137f0068c4aSGarrett Wollman ip_rsvpd = NULL; 21381c5de19aSGarrett Wollman /* 21391c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 21401c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 21411c5de19aSGarrett Wollman */ 21421c5de19aSGarrett Wollman if (ip_rsvp_on) { 21431c5de19aSGarrett Wollman ip_rsvp_on = 0; 21441c5de19aSGarrett Wollman rsvp_on--; 21451c5de19aSGarrett Wollman } 2146f0068c4aSGarrett Wollman return 0; 2147f0068c4aSGarrett Wollman } 2148bbb4330bSLuigi Rizzo 2149bbb4330bSLuigi Rizzo void 2150bbb4330bSLuigi Rizzo rsvp_input(struct mbuf *m, int off) /* XXX must fixup manually */ 2151bbb4330bSLuigi Rizzo { 2152bbb4330bSLuigi Rizzo if (rsvp_input_p) { /* call the real one if loaded */ 2153bbb4330bSLuigi Rizzo rsvp_input_p(m, off); 2154bbb4330bSLuigi Rizzo return; 2155bbb4330bSLuigi Rizzo } 2156bbb4330bSLuigi Rizzo 2157bbb4330bSLuigi Rizzo /* Can still get packets with rsvp_on = 0 if there is a local member 2158bbb4330bSLuigi Rizzo * of the group to which the RSVP packet is addressed. But in this 2159bbb4330bSLuigi Rizzo * case we want to throw the packet away. 2160bbb4330bSLuigi Rizzo */ 2161bbb4330bSLuigi Rizzo 2162bbb4330bSLuigi Rizzo if (!rsvp_on) { 2163bbb4330bSLuigi Rizzo m_freem(m); 2164bbb4330bSLuigi Rizzo return; 2165bbb4330bSLuigi Rizzo } 2166bbb4330bSLuigi Rizzo 2167bbb4330bSLuigi Rizzo if (ip_rsvpd != NULL) { 2168bbb4330bSLuigi Rizzo rip_input(m, off); 2169bbb4330bSLuigi Rizzo return; 2170bbb4330bSLuigi Rizzo } 2171bbb4330bSLuigi Rizzo /* Drop the packet */ 2172bbb4330bSLuigi Rizzo m_freem(m); 2173bbb4330bSLuigi Rizzo } 2174