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 * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 3758938916SGarrett Wollman #define _IP_VHL 3858938916SGarrett Wollman 39e4f4247aSEivind Eklund #include "opt_bootp.h" 4074a9466cSGary Palmer #include "opt_ipfw.h" 41b715f178SLuigi Rizzo #include "opt_ipdn.h" 42fbd1372aSJoerg Wunsch #include "opt_ipdivert.h" 431ee25934SPeter Wemm #include "opt_ipfilter.h" 4427108a15SDag-Erling Smørgrav #include "opt_ipstealth.h" 456a800098SYoshinobu Inoue #include "opt_ipsec.h" 46c4ac87eaSDarren Reed #include "opt_pfil_hooks.h" 4764dddc18SKris Kennaway #include "opt_random_ip_id.h" 4874a9466cSGary Palmer 49df8bae1dSRodney W. Grimes #include <sys/param.h> 50df8bae1dSRodney W. Grimes #include <sys/systm.h> 51df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 52b715f178SLuigi Rizzo #include <sys/malloc.h> 53df8bae1dSRodney W. Grimes #include <sys/domain.h> 54df8bae1dSRodney W. Grimes #include <sys/protosw.h> 55df8bae1dSRodney W. Grimes #include <sys/socket.h> 56df8bae1dSRodney W. Grimes #include <sys/time.h> 57df8bae1dSRodney W. Grimes #include <sys/kernel.h> 581025071fSGarrett Wollman #include <sys/syslog.h> 59b5e8ce9fSBruce Evans #include <sys/sysctl.h> 60df8bae1dSRodney W. Grimes 61c85540ddSAndrey A. Chernov #include <net/pfil.h> 62df8bae1dSRodney W. Grimes #include <net/if.h> 63d314ad7bSJulian Elischer #include <net/if_var.h> 6482c23ebaSBill Fenner #include <net/if_dl.h> 65df8bae1dSRodney W. Grimes #include <net/route.h> 66748e0b0aSGarrett Wollman #include <net/netisr.h> 67367d34f8SBrian Somers #include <net/intrq.h> 68df8bae1dSRodney W. Grimes 69df8bae1dSRodney W. Grimes #include <netinet/in.h> 70df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 71b5e8ce9fSBruce Evans #include <netinet/in_var.h> 72df8bae1dSRodney W. Grimes #include <netinet/ip.h> 73df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 74df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 75df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 7658938916SGarrett Wollman #include <machine/in_cksum.h> 77df8bae1dSRodney W. Grimes 786a800098SYoshinobu Inoue #include <netinet/ipprotosw.h> 796a800098SYoshinobu Inoue 80f0068c4aSGarrett Wollman #include <sys/socketvar.h> 816ddbf1e2SGary Palmer 826ddbf1e2SGary Palmer #include <netinet/ip_fw.h> 836ddbf1e2SGary Palmer 846a800098SYoshinobu Inoue #ifdef IPSEC 856a800098SYoshinobu Inoue #include <netinet6/ipsec.h> 866a800098SYoshinobu Inoue #include <netkey/key.h> 876a800098SYoshinobu Inoue #endif 886a800098SYoshinobu Inoue 896a800098SYoshinobu Inoue #include "faith.h" 906a800098SYoshinobu Inoue #if defined(NFAITH) && NFAITH > 0 916a800098SYoshinobu Inoue #include <net/if_types.h> 926a800098SYoshinobu Inoue #endif 936a800098SYoshinobu Inoue 94b715f178SLuigi Rizzo #ifdef DUMMYNET 95b715f178SLuigi Rizzo #include <netinet/ip_dummynet.h> 96b715f178SLuigi Rizzo #endif 97b715f178SLuigi Rizzo 981c5de19aSGarrett Wollman int rsvp_on = 0; 99f708ef1bSPoul-Henning Kamp static int ip_rsvp_on; 100f0068c4aSGarrett Wollman struct socket *ip_rsvpd; 101f0068c4aSGarrett Wollman 1021f91d8c5SDavid Greenman int ipforwarding = 0; 1030312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, 1043d177f46SBill Fumerola &ipforwarding, 0, "Enable IP forwarding between interfaces"); 1050312fbe9SPoul-Henning Kamp 106d4fb926cSGarrett Wollman static int ipsendredirects = 1; /* XXX */ 1070312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, 1083d177f46SBill Fumerola &ipsendredirects, 0, "Enable sending IP redirects"); 1090312fbe9SPoul-Henning Kamp 110df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 1110312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, 1123d177f46SBill Fumerola &ip_defttl, 0, "Maximum TTL on IP packets"); 1130312fbe9SPoul-Henning Kamp 1140312fbe9SPoul-Henning Kamp static int ip_dosourceroute = 0; 1150312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 1163d177f46SBill Fumerola &ip_dosourceroute, 0, "Enable forwarding source routed IP packets"); 1174fce5804SGuido van Rooij 1184fce5804SGuido van Rooij static int ip_acceptsourceroute = 0; 1194fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 1203d177f46SBill Fumerola CTLFLAG_RW, &ip_acceptsourceroute, 0, 1213d177f46SBill Fumerola "Enable accepting source routed IP packets"); 1226a800098SYoshinobu Inoue 1236a800098SYoshinobu Inoue static int ip_keepfaith = 0; 1246a800098SYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW, 1256a800098SYoshinobu Inoue &ip_keepfaith, 0, 1266a800098SYoshinobu Inoue "Enable packet capture for FAITH IPv4->IPv6 translater daemon"); 1276a800098SYoshinobu Inoue 128690a6055SJesper Skriver static int ip_nfragpackets = 0; 12996c2b042SJesper Skriver static int ip_maxfragpackets; /* initialized in ip_init() */ 130690a6055SJesper Skriver SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW, 131690a6055SJesper Skriver &ip_maxfragpackets, 0, 132690a6055SJesper Skriver "Maximum number of IPv4 fragment reassembly queue entries"); 133690a6055SJesper Skriver 134823db0e9SDon Lewis /* 135823db0e9SDon Lewis * XXX - Setting ip_checkinterface mostly implements the receive side of 136823db0e9SDon Lewis * the Strong ES model described in RFC 1122, but since the routing table 137a8f12100SDon Lewis * and transmit implementation do not implement the Strong ES model, 138823db0e9SDon Lewis * setting this to 1 results in an odd hybrid. 1393f67c834SDon Lewis * 140a8f12100SDon Lewis * XXX - ip_checkinterface currently must be disabled if you use ipnat 141a8f12100SDon Lewis * to translate the destination address to another local interface. 1423f67c834SDon Lewis * 1433f67c834SDon Lewis * XXX - ip_checkinterface must be disabled if you add IP aliases 1443f67c834SDon Lewis * to the loopback interface instead of the interface where the 1453f67c834SDon Lewis * packets for those addresses are received. 146823db0e9SDon Lewis */ 147b3e95d4eSJonathan Lemon static int ip_checkinterface = 1; 148b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW, 149b3e95d4eSJonathan Lemon &ip_checkinterface, 0, "Verify packet arrives on correct interface"); 150b3e95d4eSJonathan Lemon 151df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1520312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 153df8bae1dSRodney W. Grimes #endif 154df8bae1dSRodney W. Grimes 155df8bae1dSRodney W. Grimes extern struct domain inetdomain; 1566a800098SYoshinobu Inoue extern struct ipprotosw inetsw[]; 157df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 1580312fbe9SPoul-Henning Kamp static int ipqmaxlen = IFQ_MAXLEN; 15959562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 160afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW, 1613d177f46SBill Fumerola &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue"); 1620312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1633d177f46SBill Fumerola &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue"); 164df8bae1dSRodney W. Grimes 165f23b4c91SGarrett Wollman struct ipstat ipstat; 1666fce01c9SGarrett Wollman SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD, 1673d177f46SBill Fumerola &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); 168194a213eSAndrey A. Chernov 169194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 170194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 171194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 172194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 173194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 174831a80b0SMatthew Dillon (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 175194a213eSAndrey A. Chernov 176462b86feSPoul-Henning Kamp static TAILQ_HEAD(ipqhead, ipq) ipq[IPREASS_NHASH]; 177194a213eSAndrey A. Chernov static int nipq = 0; /* total # of reass queues */ 178194a213eSAndrey A. Chernov static int maxnipq; 179367d34f8SBrian Somers const int ipintrq_present = 1; 180f23b4c91SGarrett Wollman 1810312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1820312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1833d177f46SBill Fumerola &ip_mtu, 0, "Default MTU"); 1840312fbe9SPoul-Henning Kamp #endif 1850312fbe9SPoul-Henning Kamp 1861b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 1871b968362SDag-Erling Smørgrav static int ipstealth = 0; 1881b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW, 1891b968362SDag-Erling Smørgrav &ipstealth, 0, ""); 1901b968362SDag-Erling Smørgrav #endif 1911b968362SDag-Erling Smørgrav 192cfe8b629SGarrett Wollman 19323bf9953SPoul-Henning Kamp /* Firewall hooks */ 19423bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 19523bf9953SPoul-Henning Kamp ip_fw_ctl_t *ip_fw_ctl_ptr; 1969fcc0795SLuigi Rizzo int fw_enable = 1 ; 197e7319babSPoul-Henning Kamp 198b715f178SLuigi Rizzo #ifdef DUMMYNET 199b715f178SLuigi Rizzo ip_dn_ctl_t *ip_dn_ctl_ptr; 200b715f178SLuigi Rizzo #endif 201b715f178SLuigi Rizzo 202afed1b49SDarren Reed 203e7319babSPoul-Henning Kamp /* 204df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 205df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 206df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 207df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 208df8bae1dSRodney W. Grimes * to us. 209df8bae1dSRodney W. Grimes */ 2100312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 211df8bae1dSRodney W. Grimes static struct ip_srcrt { 212df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 213df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 214df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 215df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 216df8bae1dSRodney W. Grimes } ip_srcrt; 217df8bae1dSRodney W. Grimes 218f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr; 219f9e354dfSJulian Elischer 220df8bae1dSRodney W. Grimes static void save_rte __P((u_char *, struct in_addr)); 2210312fbe9SPoul-Henning Kamp static int ip_dooptions __P((struct mbuf *)); 2220312fbe9SPoul-Henning Kamp static void ip_forward __P((struct mbuf *, int)); 223462b86feSPoul-Henning Kamp static void ip_freef __P((struct ipqhead *, struct ipq *)); 2248948e4baSArchie Cobbs #ifdef IPDIVERT 225462b86feSPoul-Henning Kamp static struct mbuf *ip_reass __P((struct mbuf *, struct ipqhead *, struct ipq *, u_int32_t *, u_int16_t *)); 2268948e4baSArchie Cobbs #else 227462b86feSPoul-Henning Kamp static struct mbuf *ip_reass __P((struct mbuf *, struct ipqhead *, struct ipq *)); 2288948e4baSArchie Cobbs #endif 2298948e4baSArchie Cobbs static struct in_ifaddr *ip_rtaddr __P((struct in_addr)); 2300312fbe9SPoul-Henning Kamp static void ipintr __P((void)); 2318948e4baSArchie Cobbs 232df8bae1dSRodney W. Grimes /* 233df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 234df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 235df8bae1dSRodney W. Grimes */ 236df8bae1dSRodney W. Grimes void 237df8bae1dSRodney W. Grimes ip_init() 238df8bae1dSRodney W. Grimes { 2396a800098SYoshinobu Inoue register struct ipprotosw *pr; 240df8bae1dSRodney W. Grimes register int i; 241df8bae1dSRodney W. Grimes 24259562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 2436a800098SYoshinobu Inoue pr = (struct ipprotosw *)pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 244df8bae1dSRodney W. Grimes if (pr == 0) 245df8bae1dSRodney W. Grimes panic("ip_init"); 246df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 247df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 2486a800098SYoshinobu Inoue for (pr = (struct ipprotosw *)inetdomain.dom_protosw; 2496a800098SYoshinobu Inoue pr < (struct ipprotosw *)inetdomain.dom_protoswNPROTOSW; pr++) 250df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 251df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 252df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 253194a213eSAndrey A. Chernov 254194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 255462b86feSPoul-Henning Kamp TAILQ_INIT(&ipq[i]); 256194a213eSAndrey A. Chernov 257194a213eSAndrey A. Chernov maxnipq = nmbclusters / 4; 25896c2b042SJesper Skriver ip_maxfragpackets = nmbclusters / 4; 259194a213eSAndrey A. Chernov 26064dddc18SKris Kennaway #ifndef RANDOM_IP_ID 261227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 26264dddc18SKris Kennaway #endif 263df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 264df5e1987SJonathan Lemon mtx_init(&ipintrq.ifq_mtx, "ip_inq", MTX_DEF); 265242c5536SPeter Wemm 266242c5536SPeter Wemm register_netisr(NETISR_IP, ipintr); 267df8bae1dSRodney W. Grimes } 268df8bae1dSRodney W. Grimes 2690312fbe9SPoul-Henning Kamp static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 2701e3d5af0SRuslan Ermilov struct route ipforward_rt; 271df8bae1dSRodney W. Grimes 272df8bae1dSRodney W. Grimes /* 273df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 274df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 275df8bae1dSRodney W. Grimes */ 276c67b1d17SGarrett Wollman void 277c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 278df8bae1dSRodney W. Grimes { 27923bf9953SPoul-Henning Kamp struct ip *ip; 28023bf9953SPoul-Henning Kamp struct ipq *fp; 2815da9f8faSJosef Karthauser struct in_ifaddr *ia = NULL; 282823db0e9SDon Lewis int i, hlen, checkif; 28347c861ecSBrian Somers u_short sum; 2848948e4baSArchie Cobbs u_int16_t divert_cookie; /* firewall cookie */ 2857538a9a0SJonathan Lemon struct in_addr pkt_dst; 2868948e4baSArchie Cobbs #ifdef IPDIVERT 2878948e4baSArchie Cobbs u_int32_t divert_info = 0; /* packet divert/tee info */ 288b715f178SLuigi Rizzo #endif 289b715f178SLuigi Rizzo struct ip_fw_chain *rule = NULL; 290c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 291c4ac87eaSDarren Reed struct packet_filter_hook *pfh; 292c4ac87eaSDarren Reed struct mbuf *m0; 293c4ac87eaSDarren Reed int rv; 294c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 295b715f178SLuigi Rizzo 2968948e4baSArchie Cobbs #ifdef IPDIVERT 2978948e4baSArchie Cobbs /* Get and reset firewall cookie */ 2988948e4baSArchie Cobbs divert_cookie = ip_divert_cookie; 2998948e4baSArchie Cobbs ip_divert_cookie = 0; 3008948e4baSArchie Cobbs #else 3018948e4baSArchie Cobbs divert_cookie = 0; 3028948e4baSArchie Cobbs #endif 3038948e4baSArchie Cobbs 304b715f178SLuigi Rizzo #if defined(IPFIREWALL) && defined(DUMMYNET) 305b715f178SLuigi Rizzo /* 306b715f178SLuigi Rizzo * dummynet packet are prepended a vestigial mbuf with 307b715f178SLuigi Rizzo * m_type = MT_DUMMYNET and m_data pointing to the matching 308b715f178SLuigi Rizzo * rule. 309b715f178SLuigi Rizzo */ 310b715f178SLuigi Rizzo if (m->m_type == MT_DUMMYNET) { 311b715f178SLuigi Rizzo rule = (struct ip_fw_chain *)(m->m_data) ; 312b715f178SLuigi Rizzo m = m->m_next ; 313b715f178SLuigi Rizzo ip = mtod(m, struct ip *); 314b715f178SLuigi Rizzo hlen = IP_VHL_HL(ip->ip_vhl) << 2; 315b715f178SLuigi Rizzo goto iphack ; 316b715f178SLuigi Rizzo } else 317b715f178SLuigi Rizzo rule = NULL ; 318b715f178SLuigi Rizzo #endif 319df8bae1dSRodney W. Grimes 320df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 321ed7509acSJulian Elischer if (m == NULL || (m->m_flags & M_PKTHDR) == 0) 32258938916SGarrett Wollman panic("ip_input no HDR"); 323df8bae1dSRodney W. Grimes #endif 324df8bae1dSRodney W. Grimes ipstat.ips_total++; 32558938916SGarrett Wollman 32658938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 32758938916SGarrett Wollman goto tooshort; 32858938916SGarrett Wollman 329df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 330df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 331df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 332c67b1d17SGarrett Wollman return; 333df8bae1dSRodney W. Grimes } 334df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 33558938916SGarrett Wollman 33658938916SGarrett Wollman if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { 337df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 338df8bae1dSRodney W. Grimes goto bad; 339df8bae1dSRodney W. Grimes } 34058938916SGarrett Wollman 34158938916SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 342df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 343df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 344df8bae1dSRodney W. Grimes goto bad; 345df8bae1dSRodney W. Grimes } 346df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 347df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 348df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 349c67b1d17SGarrett Wollman return; 350df8bae1dSRodney W. Grimes } 351df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 352df8bae1dSRodney W. Grimes } 35333841545SHajimu UMEMOTO 35433841545SHajimu UMEMOTO /* 127/8 must not appear on wire - RFC1122 */ 35533841545SHajimu UMEMOTO if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || 35633841545SHajimu UMEMOTO (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { 35733841545SHajimu UMEMOTO if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 35833841545SHajimu UMEMOTO ipstat.ips_badaddr++; 35933841545SHajimu UMEMOTO goto bad; 36033841545SHajimu UMEMOTO } 36133841545SHajimu UMEMOTO } 36233841545SHajimu UMEMOTO 363db4f9cc7SJonathan Lemon if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { 364db4f9cc7SJonathan Lemon sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 365db4f9cc7SJonathan Lemon } else { 36658938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 36747c861ecSBrian Somers sum = in_cksum_hdr(ip); 36858938916SGarrett Wollman } else { 36947c861ecSBrian Somers sum = in_cksum(m, hlen); 37058938916SGarrett Wollman } 371db4f9cc7SJonathan Lemon } 37247c861ecSBrian Somers if (sum) { 373df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 374df8bae1dSRodney W. Grimes goto bad; 375df8bae1dSRodney W. Grimes } 376df8bae1dSRodney W. Grimes 377df8bae1dSRodney W. Grimes /* 378df8bae1dSRodney W. Grimes * Convert fields to host representation. 379df8bae1dSRodney W. Grimes */ 380df8bae1dSRodney W. Grimes NTOHS(ip->ip_len); 381df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 382df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 383df8bae1dSRodney W. Grimes goto bad; 384df8bae1dSRodney W. Grimes } 385df8bae1dSRodney W. Grimes NTOHS(ip->ip_off); 386df8bae1dSRodney W. Grimes 387df8bae1dSRodney W. Grimes /* 388df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 389df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 390df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 391df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 392df8bae1dSRodney W. Grimes */ 393df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 39458938916SGarrett Wollman tooshort: 395df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 396df8bae1dSRodney W. Grimes goto bad; 397df8bae1dSRodney W. Grimes } 398df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 399df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 400df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 401df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 402df8bae1dSRodney W. Grimes } else 403df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 404df8bae1dSRodney W. Grimes } 4053f67c834SDon Lewis 40633841545SHajimu UMEMOTO #ifdef IPSEC 40733841545SHajimu UMEMOTO if (ipsec_gethist(m, NULL)) 40833841545SHajimu UMEMOTO goto pass; 40933841545SHajimu UMEMOTO #endif 4103f67c834SDon Lewis 4114dd1662bSUgen J.S. Antsilevich /* 4124dd1662bSUgen J.S. Antsilevich * IpHack's section. 4134dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 4144dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 4154dd1662bSUgen J.S. Antsilevich * deals with it. 41693e0e116SJulian Elischer * - Firewall: deny/allow/divert 417fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 418b715f178SLuigi Rizzo * - Pipe: pass pkt through dummynet. 4194dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 4204dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 4214dd1662bSUgen J.S. Antsilevich */ 422b715f178SLuigi Rizzo 423dee383e0SEivind Eklund #if defined(IPFIREWALL) && defined(DUMMYNET) 424b715f178SLuigi Rizzo iphack: 425dee383e0SEivind Eklund #endif 426df8bae1dSRodney W. Grimes 427c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 428c4ac87eaSDarren Reed /* 429c4ac87eaSDarren Reed * Run through list of hooks for input packets. If there are any 430c4ac87eaSDarren Reed * filters which require that additional packets in the flow are 431c4ac87eaSDarren Reed * not fast-forwarded, they must clear the M_CANFASTFWD flag. 432c4ac87eaSDarren Reed * Note that filters must _never_ set this flag, as another filter 433c4ac87eaSDarren Reed * in the list may have previously cleared it. 434c4ac87eaSDarren Reed */ 435c4ac87eaSDarren Reed m0 = m; 436c4ac87eaSDarren Reed pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 437fc2ffbe6SPoul-Henning Kamp for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link)) 438c4ac87eaSDarren Reed if (pfh->pfil_func) { 439c4ac87eaSDarren Reed rv = pfh->pfil_func(ip, hlen, 440c4ac87eaSDarren Reed m->m_pkthdr.rcvif, 0, &m0); 441c4ac87eaSDarren Reed if (rv) 442beec8214SDarren Reed return; 443c4ac87eaSDarren Reed m = m0; 444c4ac87eaSDarren Reed if (m == NULL) 445c4ac87eaSDarren Reed return; 446c4ac87eaSDarren Reed ip = mtod(m, struct ip *); 447beec8214SDarren Reed } 448c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 449c4ac87eaSDarren Reed 4506bc748b0SLuigi Rizzo if (fw_enable && ip_fw_chk_ptr) { 451f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 452f9e354dfSJulian Elischer /* 453f9e354dfSJulian Elischer * If we've been forwarded from the output side, then 454f9e354dfSJulian Elischer * skip the firewall a second time 455f9e354dfSJulian Elischer */ 456f9e354dfSJulian Elischer if (ip_fw_fwd_addr) 457f9e354dfSJulian Elischer goto ours; 458f9e354dfSJulian Elischer #endif /* IPFIREWALL_FORWARD */ 459f9e354dfSJulian Elischer /* 4608948e4baSArchie Cobbs * See the comment in ip_output for the return values 461b715f178SLuigi Rizzo * produced by the firewall. 462f9e354dfSJulian Elischer */ 4638948e4baSArchie Cobbs i = (*ip_fw_chk_ptr)(&ip, 4648948e4baSArchie Cobbs hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr); 465507b4b54SLuigi Rizzo if (i & IP_FW_PORT_DENY_FLAG) { /* XXX new interface-denied */ 466507b4b54SLuigi Rizzo if (m) 467507b4b54SLuigi Rizzo m_freem(m); 468b715f178SLuigi Rizzo return ; 469507b4b54SLuigi Rizzo } 470507b4b54SLuigi Rizzo if (m == NULL) { /* Packet discarded by firewall */ 471507b4b54SLuigi Rizzo static int __debug=10; 472507b4b54SLuigi Rizzo if (__debug >0) { 473507b4b54SLuigi Rizzo printf("firewall returns NULL, please update!\n"); 474507b4b54SLuigi Rizzo __debug-- ; 475507b4b54SLuigi Rizzo } 476507b4b54SLuigi Rizzo return; 477507b4b54SLuigi Rizzo } 478b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ 479b715f178SLuigi Rizzo goto pass; 480b715f178SLuigi Rizzo #ifdef DUMMYNET 4818948e4baSArchie Cobbs if ((i & IP_FW_PORT_DYNT_FLAG) != 0) { 4828948e4baSArchie Cobbs /* Send packet to the appropriate pipe */ 4836a800098SYoshinobu Inoue dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule, 4846a800098SYoshinobu Inoue 0); 485e4676ba6SJulian Elischer return; 48693e0e116SJulian Elischer } 487b715f178SLuigi Rizzo #endif 488b715f178SLuigi Rizzo #ifdef IPDIVERT 4898948e4baSArchie Cobbs if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) { 4908948e4baSArchie Cobbs /* Divert or tee packet */ 4918948e4baSArchie Cobbs divert_info = i; 492b715f178SLuigi Rizzo goto ours; 493b715f178SLuigi Rizzo } 494b715f178SLuigi Rizzo #endif 495b715f178SLuigi Rizzo #ifdef IPFIREWALL_FORWARD 496b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr != NULL) 497b715f178SLuigi Rizzo goto pass; 498b715f178SLuigi Rizzo #endif 499b715f178SLuigi Rizzo /* 500b715f178SLuigi Rizzo * if we get here, the packet must be dropped 501b715f178SLuigi Rizzo */ 502b715f178SLuigi Rizzo m_freem(m); 503b715f178SLuigi Rizzo return; 504b715f178SLuigi Rizzo } 505b715f178SLuigi Rizzo pass: 506100ba1a6SJordan K. Hubbard 507df8bae1dSRodney W. Grimes /* 508df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 509df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 510df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 511df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 512df8bae1dSRodney W. Grimes */ 513df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 514ed1ff184SJulian Elischer if (hlen > sizeof (struct ip) && ip_dooptions(m)) { 515ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD 516ed1ff184SJulian Elischer ip_fw_fwd_addr = NULL; 517ed1ff184SJulian Elischer #endif 518c67b1d17SGarrett Wollman return; 519ed1ff184SJulian Elischer } 520df8bae1dSRodney W. Grimes 521f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 522f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 523f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 524f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 525f0068c4aSGarrett Wollman * grabbing the packet. 526f0068c4aSGarrett Wollman */ 5271c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 528f0068c4aSGarrett Wollman goto ours; 529f0068c4aSGarrett Wollman 530df8bae1dSRodney W. Grimes /* 531df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 532cc766e04SGarrett Wollman * If we don't have any addresses, assume any unicast packet 533cc766e04SGarrett Wollman * we receive might be for us (and let the upper layers deal 534cc766e04SGarrett Wollman * with it). 535df8bae1dSRodney W. Grimes */ 536cc766e04SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead) && 537cc766e04SGarrett Wollman (m->m_flags & (M_MCAST|M_BCAST)) == 0) 538cc766e04SGarrett Wollman goto ours; 539cc766e04SGarrett Wollman 5407538a9a0SJonathan Lemon /* 5417538a9a0SJonathan Lemon * Cache the destination address of the packet; this may be 5427538a9a0SJonathan Lemon * changed by use of 'ipfw fwd'. 5437538a9a0SJonathan Lemon */ 5447538a9a0SJonathan Lemon pkt_dst = ip_fw_fwd_addr == NULL ? 5457538a9a0SJonathan Lemon ip->ip_dst : ip_fw_fwd_addr->sin_addr; 5467538a9a0SJonathan Lemon 547823db0e9SDon Lewis /* 548823db0e9SDon Lewis * Enable a consistency check between the destination address 549823db0e9SDon Lewis * and the arrival interface for a unicast packet (the RFC 1122 550823db0e9SDon Lewis * strong ES model) if IP forwarding is disabled and the packet 551e15ae1b2SDon Lewis * is not locally generated and the packet is not subject to 552e15ae1b2SDon Lewis * 'ipfw fwd'. 5533f67c834SDon Lewis * 5543f67c834SDon Lewis * XXX - Checking also should be disabled if the destination 5553f67c834SDon Lewis * address is ipnat'ed to a different interface. 5563f67c834SDon Lewis * 557a8f12100SDon Lewis * XXX - Checking is incompatible with IP aliases added 5583f67c834SDon Lewis * to the loopback interface instead of the interface where 5593f67c834SDon Lewis * the packets are received. 560823db0e9SDon Lewis */ 561823db0e9SDon Lewis checkif = ip_checkinterface && (ipforwarding == 0) && 562e15ae1b2SDon Lewis ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) && 563e15ae1b2SDon Lewis (ip_fw_fwd_addr == NULL); 564823db0e9SDon Lewis 56537d40066SPoul-Henning Kamp TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 566df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 567df8bae1dSRodney W. Grimes 568432aad0eSTor Egge #ifdef BOOTP_COMPAT 569432aad0eSTor Egge if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 570432aad0eSTor Egge goto ours; 571432aad0eSTor Egge #endif 572f9e354dfSJulian Elischer /* 573823db0e9SDon Lewis * If the address matches, verify that the packet 574823db0e9SDon Lewis * arrived via the correct interface if checking is 575823db0e9SDon Lewis * enabled. 576f9e354dfSJulian Elischer */ 577823db0e9SDon Lewis if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && 578823db0e9SDon Lewis (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif)) 579ed1ff184SJulian Elischer goto ours; 580823db0e9SDon Lewis /* 581823db0e9SDon Lewis * Only accept broadcast packets that arrive via the 582823db0e9SDon Lewis * matching interface. Reception of forwarded directed 583823db0e9SDon Lewis * broadcasts would be handled via ip_forward() and 584823db0e9SDon Lewis * ether_output() with the loopback into the stack for 585823db0e9SDon Lewis * SIMPLEX interfaces handled by ether_output(). 586823db0e9SDon Lewis */ 587823db0e9SDon Lewis if (ia->ia_ifp == m->m_pkthdr.rcvif && 588823db0e9SDon Lewis ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { 589df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 5907538a9a0SJonathan Lemon pkt_dst.s_addr) 591df8bae1dSRodney W. Grimes goto ours; 5927538a9a0SJonathan Lemon if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr) 593df8bae1dSRodney W. Grimes goto ours; 594df8bae1dSRodney W. Grimes } 595df8bae1dSRodney W. Grimes } 596df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 597df8bae1dSRodney W. Grimes struct in_multi *inm; 598df8bae1dSRodney W. Grimes if (ip_mrouter) { 599df8bae1dSRodney W. Grimes /* 600df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 601df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 602df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 603df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 604df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 605df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 606df8bae1dSRodney W. Grimes */ 607f0068c4aSGarrett Wollman if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 608df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 609df8bae1dSRodney W. Grimes m_freem(m); 610c67b1d17SGarrett Wollman return; 611df8bae1dSRodney W. Grimes } 612df8bae1dSRodney W. Grimes 613df8bae1dSRodney W. Grimes /* 614df8bae1dSRodney W. Grimes * The process-level routing demon needs to receive 615df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 616df8bae1dSRodney W. Grimes * host belongs to their destination groups. 617df8bae1dSRodney W. Grimes */ 618df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 619df8bae1dSRodney W. Grimes goto ours; 620df8bae1dSRodney W. Grimes ipstat.ips_forward++; 621df8bae1dSRodney W. Grimes } 622df8bae1dSRodney W. Grimes /* 623df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 624df8bae1dSRodney W. Grimes * arrival interface. 625df8bae1dSRodney W. Grimes */ 626df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 627df8bae1dSRodney W. Grimes if (inm == NULL) { 62882c39223SGarrett Wollman ipstat.ips_notmember++; 629df8bae1dSRodney W. Grimes m_freem(m); 630c67b1d17SGarrett Wollman return; 631df8bae1dSRodney W. Grimes } 632df8bae1dSRodney W. Grimes goto ours; 633df8bae1dSRodney W. Grimes } 634df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 635df8bae1dSRodney W. Grimes goto ours; 636df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 637df8bae1dSRodney W. Grimes goto ours; 638df8bae1dSRodney W. Grimes 6396a800098SYoshinobu Inoue #if defined(NFAITH) && 0 < NFAITH 6406a800098SYoshinobu Inoue /* 6416a800098SYoshinobu Inoue * FAITH(Firewall Aided Internet Translator) 6426a800098SYoshinobu Inoue */ 6436a800098SYoshinobu Inoue if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 6446a800098SYoshinobu Inoue if (ip_keepfaith) { 6456a800098SYoshinobu Inoue if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP) 6466a800098SYoshinobu Inoue goto ours; 6476a800098SYoshinobu Inoue } 6486a800098SYoshinobu Inoue m_freem(m); 6496a800098SYoshinobu Inoue return; 6506a800098SYoshinobu Inoue } 6516a800098SYoshinobu Inoue #endif 652df8bae1dSRodney W. Grimes /* 653df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 654df8bae1dSRodney W. Grimes */ 655df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 656df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 657df8bae1dSRodney W. Grimes m_freem(m); 658df8bae1dSRodney W. Grimes } else 659df8bae1dSRodney W. Grimes ip_forward(m, 0); 660ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD 661ed1ff184SJulian Elischer ip_fw_fwd_addr = NULL; 662ed1ff184SJulian Elischer #endif 663c67b1d17SGarrett Wollman return; 664df8bae1dSRodney W. Grimes 665df8bae1dSRodney W. Grimes ours: 6665da9f8faSJosef Karthauser /* Count the packet in the ip address stats */ 6675da9f8faSJosef Karthauser if (ia != NULL) { 6685da9f8faSJosef Karthauser ia->ia_ifa.if_ipackets++; 6695da9f8faSJosef Karthauser ia->ia_ifa.if_ibytes += m->m_pkthdr.len; 6705da9f8faSJosef Karthauser } 671100ba1a6SJordan K. Hubbard 67263f8d699SJordan K. Hubbard /* 673df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 674df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 675df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 676df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 677df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 678df8bae1dSRodney W. Grimes */ 679b6ea1aa5SRuslan Ermilov if (ip->ip_off & (IP_MF | IP_OFFMASK)) { 6806a800098SYoshinobu Inoue 681194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 682df8bae1dSRodney W. Grimes /* 683df8bae1dSRodney W. Grimes * Look for queue of fragments 684df8bae1dSRodney W. Grimes * of this datagram. 685df8bae1dSRodney W. Grimes */ 686462b86feSPoul-Henning Kamp TAILQ_FOREACH(fp, &ipq[sum], ipq_list) 687df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 688df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 689df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 690df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 691df8bae1dSRodney W. Grimes goto found; 692df8bae1dSRodney W. Grimes 693194a213eSAndrey A. Chernov fp = 0; 694194a213eSAndrey A. Chernov 695194a213eSAndrey A. Chernov /* check if there's a place for the new queue */ 696194a213eSAndrey A. Chernov if (nipq > maxnipq) { 697194a213eSAndrey A. Chernov /* 698194a213eSAndrey A. Chernov * drop something from the tail of the current queue 699194a213eSAndrey A. Chernov * before proceeding further 700194a213eSAndrey A. Chernov */ 701462b86feSPoul-Henning Kamp struct ipq *q = TAILQ_LAST(&ipq[sum], ipqhead); 702462b86feSPoul-Henning Kamp if (q == NULL) { /* gak */ 703194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 704462b86feSPoul-Henning Kamp struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead); 705462b86feSPoul-Henning Kamp if (r) { 706462b86feSPoul-Henning Kamp ip_freef(&ipq[i], r); 707194a213eSAndrey A. Chernov break; 708194a213eSAndrey A. Chernov } 709194a213eSAndrey A. Chernov } 710194a213eSAndrey A. Chernov } else 711462b86feSPoul-Henning Kamp ip_freef(&ipq[sum], q); 712194a213eSAndrey A. Chernov } 713194a213eSAndrey A. Chernov found: 714df8bae1dSRodney W. Grimes /* 715df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 716df8bae1dSRodney W. Grimes * convert offset of this to bytes. 717df8bae1dSRodney W. Grimes */ 718df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 719b6ea1aa5SRuslan Ermilov if (ip->ip_off & IP_MF) { 7206effc713SDoug Rabson /* 7216effc713SDoug Rabson * Make sure that fragments have a data length 7226effc713SDoug Rabson * that's a non-zero multiple of 8 bytes. 7236effc713SDoug Rabson */ 7246effc713SDoug Rabson if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { 7256effc713SDoug Rabson ipstat.ips_toosmall++; /* XXX */ 7266effc713SDoug Rabson goto bad; 7276effc713SDoug Rabson } 7286effc713SDoug Rabson m->m_flags |= M_FRAG; 7296effc713SDoug Rabson } 730df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 731df8bae1dSRodney W. Grimes 732df8bae1dSRodney W. Grimes /* 733b6ea1aa5SRuslan Ermilov * Attempt reassembly; if it succeeds, proceed. 734df8bae1dSRodney W. Grimes */ 735df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 736487bdb38SRuslan Ermilov m->m_pkthdr.header = ip; 7378948e4baSArchie Cobbs #ifdef IPDIVERT 7386a800098SYoshinobu Inoue m = ip_reass(m, 739462b86feSPoul-Henning Kamp &ipq[sum], fp, &divert_info, &divert_cookie); 7408948e4baSArchie Cobbs #else 741462b86feSPoul-Henning Kamp m = ip_reass(m, &ipq[sum], fp); 7428948e4baSArchie Cobbs #endif 7436a800098SYoshinobu Inoue if (m == 0) { 744f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 745f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 746f9e354dfSJulian Elischer #endif 747c67b1d17SGarrett Wollman return; 748f9e354dfSJulian Elischer } 749df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 7506a800098SYoshinobu Inoue ip = mtod(m, struct ip *); 7517e2df452SRuslan Ermilov /* Get the header length of the reassembled packet */ 7527e2df452SRuslan Ermilov hlen = IP_VHL_HL(ip->ip_vhl) << 2; 753af782f1cSBrian Somers #ifdef IPDIVERT 7548948e4baSArchie Cobbs /* Restore original checksum before diverting packet */ 7558948e4baSArchie Cobbs if (divert_info != 0) { 756af782f1cSBrian Somers ip->ip_len += hlen; 757af782f1cSBrian Somers HTONS(ip->ip_len); 758af782f1cSBrian Somers HTONS(ip->ip_off); 759af782f1cSBrian Somers ip->ip_sum = 0; 76060123168SRuslan Ermilov if (hlen == sizeof(struct ip)) 761af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 76260123168SRuslan Ermilov else 76360123168SRuslan Ermilov ip->ip_sum = in_cksum(m, hlen); 764af782f1cSBrian Somers NTOHS(ip->ip_off); 765af782f1cSBrian Somers NTOHS(ip->ip_len); 766af782f1cSBrian Somers ip->ip_len -= hlen; 767af782f1cSBrian Somers } 768af782f1cSBrian Somers #endif 769df8bae1dSRodney W. Grimes } else 770df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 771df8bae1dSRodney W. Grimes 77293e0e116SJulian Elischer #ifdef IPDIVERT 77393e0e116SJulian Elischer /* 7748948e4baSArchie Cobbs * Divert or tee packet to the divert protocol if required. 7758948e4baSArchie Cobbs * 7768948e4baSArchie Cobbs * If divert_info is zero then cookie should be too, so we shouldn't 7778948e4baSArchie Cobbs * need to clear them here. Assume divert_packet() does so also. 77893e0e116SJulian Elischer */ 7798948e4baSArchie Cobbs if (divert_info != 0) { 7808948e4baSArchie Cobbs struct mbuf *clone = NULL; 7818948e4baSArchie Cobbs 7828948e4baSArchie Cobbs /* Clone packet if we're doing a 'tee' */ 7838948e4baSArchie Cobbs if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0) 7848948e4baSArchie Cobbs clone = m_dup(m, M_DONTWAIT); 7858948e4baSArchie Cobbs 7868948e4baSArchie Cobbs /* Restore packet header fields to original values */ 7878948e4baSArchie Cobbs ip->ip_len += hlen; 7888948e4baSArchie Cobbs HTONS(ip->ip_len); 7898948e4baSArchie Cobbs HTONS(ip->ip_off); 7908948e4baSArchie Cobbs 7918948e4baSArchie Cobbs /* Deliver packet to divert input routine */ 7928948e4baSArchie Cobbs ip_divert_cookie = divert_cookie; 7938948e4baSArchie Cobbs divert_packet(m, 1, divert_info & 0xffff); 794e4676ba6SJulian Elischer ipstat.ips_delivered++; 7958948e4baSArchie Cobbs 7968948e4baSArchie Cobbs /* If 'tee', continue with original packet */ 7978948e4baSArchie Cobbs if (clone == NULL) 79893e0e116SJulian Elischer return; 7998948e4baSArchie Cobbs m = clone; 8008948e4baSArchie Cobbs ip = mtod(m, struct ip *); 80193e0e116SJulian Elischer } 80293e0e116SJulian Elischer #endif 80393e0e116SJulian Elischer 80433841545SHajimu UMEMOTO #ifdef IPSEC 80533841545SHajimu UMEMOTO /* 80633841545SHajimu UMEMOTO * enforce IPsec policy checking if we are seeing last header. 80733841545SHajimu UMEMOTO * note that we do not visit this with protocols with pcb layer 80833841545SHajimu UMEMOTO * code - like udp/tcp/raw ip. 80933841545SHajimu UMEMOTO */ 81033841545SHajimu UMEMOTO if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && 81133841545SHajimu UMEMOTO ipsec4_in_reject(m, NULL)) { 81233841545SHajimu UMEMOTO ipsecstat.in_polvio++; 81333841545SHajimu UMEMOTO goto bad; 81433841545SHajimu UMEMOTO } 81533841545SHajimu UMEMOTO #endif 81633841545SHajimu UMEMOTO 817df8bae1dSRodney W. Grimes /* 818df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 819df8bae1dSRodney W. Grimes */ 820df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 8216a800098SYoshinobu Inoue { 8226a800098SYoshinobu Inoue int off = hlen, nh = ip->ip_p; 8236a800098SYoshinobu Inoue 8246a800098SYoshinobu Inoue (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off, nh); 825f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 826f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; /* tcp needed it */ 827f9e354dfSJulian Elischer #endif 828c67b1d17SGarrett Wollman return; 8296a800098SYoshinobu Inoue } 830df8bae1dSRodney W. Grimes bad: 831f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 832f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 833f9e354dfSJulian Elischer #endif 834df8bae1dSRodney W. Grimes m_freem(m); 835c67b1d17SGarrett Wollman } 836c67b1d17SGarrett Wollman 837c67b1d17SGarrett Wollman /* 838c67b1d17SGarrett Wollman * IP software interrupt routine - to go away sometime soon 839c67b1d17SGarrett Wollman */ 840c67b1d17SGarrett Wollman static void 841c67b1d17SGarrett Wollman ipintr(void) 842c67b1d17SGarrett Wollman { 843c67b1d17SGarrett Wollman struct mbuf *m; 844c67b1d17SGarrett Wollman 845c67b1d17SGarrett Wollman while (1) { 846c67b1d17SGarrett Wollman IF_DEQUEUE(&ipintrq, m); 847c67b1d17SGarrett Wollman if (m == 0) 848c67b1d17SGarrett Wollman return; 849c67b1d17SGarrett Wollman ip_input(m); 850c67b1d17SGarrett Wollman } 851df8bae1dSRodney W. Grimes } 852df8bae1dSRodney W. Grimes 853df8bae1dSRodney W. Grimes /* 8548948e4baSArchie Cobbs * Take incoming datagram fragment and try to reassemble it into 8558948e4baSArchie Cobbs * whole datagram. If a chain for reassembly of this datagram already 8568948e4baSArchie Cobbs * exists, then it is given as fp; otherwise have to make a chain. 8578948e4baSArchie Cobbs * 8588948e4baSArchie Cobbs * When IPDIVERT enabled, keep additional state with each packet that 8598948e4baSArchie Cobbs * tells us if we need to divert or tee the packet we're building. 860df8bae1dSRodney W. Grimes */ 8618948e4baSArchie Cobbs 8626a800098SYoshinobu Inoue static struct mbuf * 8638948e4baSArchie Cobbs #ifdef IPDIVERT 864462b86feSPoul-Henning Kamp ip_reass(m, head, fp, divinfo, divcookie) 8658948e4baSArchie Cobbs #else 866462b86feSPoul-Henning Kamp ip_reass(m, head, fp) 8678948e4baSArchie Cobbs #endif 868462b86feSPoul-Henning Kamp struct mbuf *m; 869462b86feSPoul-Henning Kamp struct ipqhead *head; 870462b86feSPoul-Henning Kamp struct ipq *fp; 8718948e4baSArchie Cobbs #ifdef IPDIVERT 8728948e4baSArchie Cobbs u_int32_t *divinfo; 8738948e4baSArchie Cobbs u_int16_t *divcookie; 8748948e4baSArchie Cobbs #endif 875df8bae1dSRodney W. Grimes { 8766effc713SDoug Rabson struct ip *ip = mtod(m, struct ip *); 877b6ea1aa5SRuslan Ermilov register struct mbuf *p, *q, *nq; 878df8bae1dSRodney W. Grimes struct mbuf *t; 8796effc713SDoug Rabson int hlen = IP_VHL_HL(ip->ip_vhl) << 2; 880df8bae1dSRodney W. Grimes int i, next; 881df8bae1dSRodney W. Grimes 882df8bae1dSRodney W. Grimes /* 883df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 884df8bae1dSRodney W. Grimes * would confuse code below. 885df8bae1dSRodney W. Grimes */ 886df8bae1dSRodney W. Grimes m->m_data += hlen; 887df8bae1dSRodney W. Grimes m->m_len -= hlen; 888df8bae1dSRodney W. Grimes 889df8bae1dSRodney W. Grimes /* 890df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 891df8bae1dSRodney W. Grimes */ 892df8bae1dSRodney W. Grimes if (fp == 0) { 893690a6055SJesper Skriver /* 894690a6055SJesper Skriver * Enforce upper bound on number of fragmented packets 895690a6055SJesper Skriver * for which we attempt reassembly; 896690a6055SJesper Skriver * If maxfrag is 0, never accept fragments. 897690a6055SJesper Skriver * If maxfrag is -1, accept all fragments without limitation. 898690a6055SJesper Skriver */ 899690a6055SJesper Skriver if ((ip_maxfragpackets >= 0) && (ip_nfragpackets >= ip_maxfragpackets)) 900690a6055SJesper Skriver goto dropfrag; 901690a6055SJesper Skriver ip_nfragpackets++; 902df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 903df8bae1dSRodney W. Grimes goto dropfrag; 904df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 905462b86feSPoul-Henning Kamp TAILQ_INSERT_HEAD(head, fp, ipq_list); 906194a213eSAndrey A. Chernov nipq++; 907df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 908df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 909df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 9106effc713SDoug Rabson fp->ipq_src = ip->ip_src; 9116effc713SDoug Rabson fp->ipq_dst = ip->ip_dst; 912af38c68cSLuigi Rizzo fp->ipq_frags = m; 913af38c68cSLuigi Rizzo m->m_nextpkt = NULL; 91493e0e116SJulian Elischer #ifdef IPDIVERT 9158948e4baSArchie Cobbs fp->ipq_div_info = 0; 916bb60f459SJulian Elischer fp->ipq_div_cookie = 0; 91793e0e116SJulian Elischer #endif 918af38c68cSLuigi Rizzo goto inserted; 919df8bae1dSRodney W. Grimes } 920df8bae1dSRodney W. Grimes 9216effc713SDoug Rabson #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) 9226effc713SDoug Rabson 923df8bae1dSRodney W. Grimes /* 924df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 925df8bae1dSRodney W. Grimes */ 9266effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) 9276effc713SDoug Rabson if (GETIP(q)->ip_off > ip->ip_off) 928df8bae1dSRodney W. Grimes break; 929df8bae1dSRodney W. Grimes 930df8bae1dSRodney W. Grimes /* 931df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 932df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 933af38c68cSLuigi Rizzo * segment. If it provides all of our data, drop us, otherwise 934af38c68cSLuigi Rizzo * stick new segment in the proper place. 935db4f9cc7SJonathan Lemon * 936db4f9cc7SJonathan Lemon * If some of the data is dropped from the the preceding 937db4f9cc7SJonathan Lemon * segment, then it's checksum is invalidated. 938df8bae1dSRodney W. Grimes */ 9396effc713SDoug Rabson if (p) { 9406effc713SDoug Rabson i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; 941df8bae1dSRodney W. Grimes if (i > 0) { 942df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 943df8bae1dSRodney W. Grimes goto dropfrag; 9446a800098SYoshinobu Inoue m_adj(m, i); 945db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags = 0; 946df8bae1dSRodney W. Grimes ip->ip_off += i; 947df8bae1dSRodney W. Grimes ip->ip_len -= i; 948df8bae1dSRodney W. Grimes } 949af38c68cSLuigi Rizzo m->m_nextpkt = p->m_nextpkt; 950af38c68cSLuigi Rizzo p->m_nextpkt = m; 951af38c68cSLuigi Rizzo } else { 952af38c68cSLuigi Rizzo m->m_nextpkt = fp->ipq_frags; 953af38c68cSLuigi Rizzo fp->ipq_frags = m; 954df8bae1dSRodney W. Grimes } 955df8bae1dSRodney W. Grimes 956df8bae1dSRodney W. Grimes /* 957df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 958df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 959df8bae1dSRodney W. Grimes */ 9606effc713SDoug Rabson for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; 961af38c68cSLuigi Rizzo q = nq) { 9626effc713SDoug Rabson i = (ip->ip_off + ip->ip_len) - 9636effc713SDoug Rabson GETIP(q)->ip_off; 9646effc713SDoug Rabson if (i < GETIP(q)->ip_len) { 9656effc713SDoug Rabson GETIP(q)->ip_len -= i; 9666effc713SDoug Rabson GETIP(q)->ip_off += i; 9676effc713SDoug Rabson m_adj(q, i); 968db4f9cc7SJonathan Lemon q->m_pkthdr.csum_flags = 0; 969df8bae1dSRodney W. Grimes break; 970df8bae1dSRodney W. Grimes } 9716effc713SDoug Rabson nq = q->m_nextpkt; 972af38c68cSLuigi Rizzo m->m_nextpkt = nq; 9736effc713SDoug Rabson m_freem(q); 974df8bae1dSRodney W. Grimes } 975df8bae1dSRodney W. Grimes 976af38c68cSLuigi Rizzo inserted: 97793e0e116SJulian Elischer 97893e0e116SJulian Elischer #ifdef IPDIVERT 97993e0e116SJulian Elischer /* 9808948e4baSArchie Cobbs * Transfer firewall instructions to the fragment structure. 9818948e4baSArchie Cobbs * Any fragment diverting causes the whole packet to divert. 98293e0e116SJulian Elischer */ 9838948e4baSArchie Cobbs fp->ipq_div_info = *divinfo; 9848948e4baSArchie Cobbs fp->ipq_div_cookie = *divcookie; 9858948e4baSArchie Cobbs *divinfo = 0; 9868948e4baSArchie Cobbs *divcookie = 0; 98793e0e116SJulian Elischer #endif 98893e0e116SJulian Elischer 989df8bae1dSRodney W. Grimes /* 990af38c68cSLuigi Rizzo * Check for complete reassembly. 991df8bae1dSRodney W. Grimes */ 9926effc713SDoug Rabson next = 0; 9936effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { 9946effc713SDoug Rabson if (GETIP(q)->ip_off != next) 9956effc713SDoug Rabson return (0); 9966effc713SDoug Rabson next += GETIP(q)->ip_len; 9976effc713SDoug Rabson } 9986effc713SDoug Rabson /* Make sure the last packet didn't have the IP_MF flag */ 9996effc713SDoug Rabson if (p->m_flags & M_FRAG) 1000df8bae1dSRodney W. Grimes return (0); 1001df8bae1dSRodney W. Grimes 1002df8bae1dSRodney W. Grimes /* 1003430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 1004430d30d8SBill Fenner */ 10056effc713SDoug Rabson q = fp->ipq_frags; 10066effc713SDoug Rabson ip = GETIP(q); 10076effc713SDoug Rabson if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) { 1008430d30d8SBill Fenner ipstat.ips_toolong++; 1009462b86feSPoul-Henning Kamp ip_freef(head, fp); 1010430d30d8SBill Fenner return (0); 1011430d30d8SBill Fenner } 1012430d30d8SBill Fenner 1013430d30d8SBill Fenner /* 1014430d30d8SBill Fenner * Concatenate fragments. 1015df8bae1dSRodney W. Grimes */ 10166effc713SDoug Rabson m = q; 1017df8bae1dSRodney W. Grimes t = m->m_next; 1018df8bae1dSRodney W. Grimes m->m_next = 0; 1019df8bae1dSRodney W. Grimes m_cat(m, t); 10206effc713SDoug Rabson nq = q->m_nextpkt; 1021945aa40dSDoug Rabson q->m_nextpkt = 0; 10226effc713SDoug Rabson for (q = nq; q != NULL; q = nq) { 10236effc713SDoug Rabson nq = q->m_nextpkt; 1024945aa40dSDoug Rabson q->m_nextpkt = NULL; 1025db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; 1026db4f9cc7SJonathan Lemon m->m_pkthdr.csum_data += q->m_pkthdr.csum_data; 1027a8db1d93SJonathan Lemon m_cat(m, q); 1028df8bae1dSRodney W. Grimes } 1029df8bae1dSRodney W. Grimes 103093e0e116SJulian Elischer #ifdef IPDIVERT 103193e0e116SJulian Elischer /* 10328948e4baSArchie Cobbs * Extract firewall instructions from the fragment structure. 103393e0e116SJulian Elischer */ 10348948e4baSArchie Cobbs *divinfo = fp->ipq_div_info; 10358948e4baSArchie Cobbs *divcookie = fp->ipq_div_cookie; 103693e0e116SJulian Elischer #endif 103793e0e116SJulian Elischer 1038df8bae1dSRodney W. Grimes /* 1039df8bae1dSRodney W. Grimes * Create header for new ip packet by 1040df8bae1dSRodney W. Grimes * modifying header of first packet; 1041df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 1042df8bae1dSRodney W. Grimes * Make header visible. 1043df8bae1dSRodney W. Grimes */ 1044df8bae1dSRodney W. Grimes ip->ip_len = next; 10456effc713SDoug Rabson ip->ip_src = fp->ipq_src; 10466effc713SDoug Rabson ip->ip_dst = fp->ipq_dst; 1047462b86feSPoul-Henning Kamp TAILQ_REMOVE(head, fp, ipq_list); 1048194a213eSAndrey A. Chernov nipq--; 1049df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1050690a6055SJesper Skriver ip_nfragpackets--; 10516effc713SDoug Rabson m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2); 10526effc713SDoug Rabson m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2); 1053df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 1054df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 1055df8bae1dSRodney W. Grimes register int plen = 0; 10566a800098SYoshinobu Inoue for (t = m; t; t = t->m_next) 10576a800098SYoshinobu Inoue plen += t->m_len; 10586a800098SYoshinobu Inoue m->m_pkthdr.len = plen; 1059df8bae1dSRodney W. Grimes } 10606a800098SYoshinobu Inoue return (m); 1061df8bae1dSRodney W. Grimes 1062df8bae1dSRodney W. Grimes dropfrag: 1063efe39c6aSJulian Elischer #ifdef IPDIVERT 10648948e4baSArchie Cobbs *divinfo = 0; 10658948e4baSArchie Cobbs *divcookie = 0; 1066efe39c6aSJulian Elischer #endif 1067df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 1068df8bae1dSRodney W. Grimes m_freem(m); 1069df8bae1dSRodney W. Grimes return (0); 10706effc713SDoug Rabson 10716effc713SDoug Rabson #undef GETIP 1072df8bae1dSRodney W. Grimes } 1073df8bae1dSRodney W. Grimes 1074df8bae1dSRodney W. Grimes /* 1075df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 1076df8bae1dSRodney W. Grimes * associated datagrams. 1077df8bae1dSRodney W. Grimes */ 10780312fbe9SPoul-Henning Kamp static void 1079462b86feSPoul-Henning Kamp ip_freef(fhp, fp) 1080462b86feSPoul-Henning Kamp struct ipqhead *fhp; 1081df8bae1dSRodney W. Grimes struct ipq *fp; 1082df8bae1dSRodney W. Grimes { 10836effc713SDoug Rabson register struct mbuf *q; 1084df8bae1dSRodney W. Grimes 10856effc713SDoug Rabson while (fp->ipq_frags) { 10866effc713SDoug Rabson q = fp->ipq_frags; 10876effc713SDoug Rabson fp->ipq_frags = q->m_nextpkt; 10886effc713SDoug Rabson m_freem(q); 1089df8bae1dSRodney W. Grimes } 1090462b86feSPoul-Henning Kamp TAILQ_REMOVE(fhp, fp, ipq_list); 1091df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1092690a6055SJesper Skriver ip_nfragpackets--; 1093194a213eSAndrey A. Chernov nipq--; 1094df8bae1dSRodney W. Grimes } 1095df8bae1dSRodney W. Grimes 1096df8bae1dSRodney W. Grimes /* 1097df8bae1dSRodney W. Grimes * IP timer processing; 1098df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 1099df8bae1dSRodney W. Grimes * queue, discard it. 1100df8bae1dSRodney W. Grimes */ 1101df8bae1dSRodney W. Grimes void 1102df8bae1dSRodney W. Grimes ip_slowtimo() 1103df8bae1dSRodney W. Grimes { 1104df8bae1dSRodney W. Grimes register struct ipq *fp; 1105df8bae1dSRodney W. Grimes int s = splnet(); 1106194a213eSAndrey A. Chernov int i; 1107df8bae1dSRodney W. Grimes 1108194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1109462b86feSPoul-Henning Kamp for(fp = TAILQ_FIRST(&ipq[i]); fp;) { 1110462b86feSPoul-Henning Kamp struct ipq *fpp; 1111462b86feSPoul-Henning Kamp 1112462b86feSPoul-Henning Kamp fpp = fp; 1113462b86feSPoul-Henning Kamp fp = TAILQ_NEXT(fp, ipq_list); 1114462b86feSPoul-Henning Kamp if(--fpp->ipq_ttl == 0) { 1115df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 1116462b86feSPoul-Henning Kamp ip_freef(&ipq[i], fpp); 1117df8bae1dSRodney W. Grimes } 1118df8bae1dSRodney W. Grimes } 1119194a213eSAndrey A. Chernov } 1120690a6055SJesper Skriver /* 1121690a6055SJesper Skriver * If we are over the maximum number of fragments 1122690a6055SJesper Skriver * (due to the limit being lowered), drain off 1123690a6055SJesper Skriver * enough to get down to the new limit. 1124690a6055SJesper Skriver */ 1125690a6055SJesper Skriver for (i = 0; i < IPREASS_NHASH; i++) { 1126690a6055SJesper Skriver if (ip_maxfragpackets >= 0) { 1127690a6055SJesper Skriver while (ip_nfragpackets > ip_maxfragpackets && 1128690a6055SJesper Skriver !TAILQ_EMPTY(&ipq[i])) { 1129690a6055SJesper Skriver ipstat.ips_fragdropped++; 1130690a6055SJesper Skriver ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); 1131690a6055SJesper Skriver } 1132690a6055SJesper Skriver } 1133690a6055SJesper Skriver } 11341f91d8c5SDavid Greenman ipflow_slowtimo(); 1135df8bae1dSRodney W. Grimes splx(s); 1136df8bae1dSRodney W. Grimes } 1137df8bae1dSRodney W. Grimes 1138df8bae1dSRodney W. Grimes /* 1139df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 1140df8bae1dSRodney W. Grimes */ 1141df8bae1dSRodney W. Grimes void 1142df8bae1dSRodney W. Grimes ip_drain() 1143df8bae1dSRodney W. Grimes { 1144194a213eSAndrey A. Chernov int i; 1145ce29ab3aSGarrett Wollman 1146194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1147462b86feSPoul-Henning Kamp while(!TAILQ_EMPTY(&ipq[i])) { 1148194a213eSAndrey A. Chernov ipstat.ips_fragdropped++; 1149462b86feSPoul-Henning Kamp ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); 1150194a213eSAndrey A. Chernov } 1151194a213eSAndrey A. Chernov } 1152ce29ab3aSGarrett Wollman in_rtqdrain(); 1153df8bae1dSRodney W. Grimes } 1154df8bae1dSRodney W. Grimes 1155df8bae1dSRodney W. Grimes /* 1156df8bae1dSRodney W. Grimes * Do option processing on a datagram, 1157df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 1158df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 1159df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 1160df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 1161df8bae1dSRodney W. Grimes */ 11620312fbe9SPoul-Henning Kamp static int 1163df8bae1dSRodney W. Grimes ip_dooptions(m) 1164df8bae1dSRodney W. Grimes struct mbuf *m; 1165df8bae1dSRodney W. Grimes { 1166df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1167df8bae1dSRodney W. Grimes register u_char *cp; 1168df8bae1dSRodney W. Grimes register struct ip_timestamp *ipt; 1169df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 1170df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 1171df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 1172df8bae1dSRodney W. Grimes n_time ntime; 1173df8bae1dSRodney W. Grimes 1174df8bae1dSRodney W. Grimes dst = ip->ip_dst; 1175df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 117658938916SGarrett Wollman cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1177df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 1178df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 1179df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 1180df8bae1dSRodney W. Grimes break; 1181df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 1182df8bae1dSRodney W. Grimes optlen = 1; 1183df8bae1dSRodney W. Grimes else { 1184fdcb8debSJun-ichiro itojun Hagino if (cnt < IPOPT_OLEN + sizeof(*cp)) { 1185fdcb8debSJun-ichiro itojun Hagino code = &cp[IPOPT_OLEN] - (u_char *)ip; 1186fdcb8debSJun-ichiro itojun Hagino goto bad; 1187fdcb8debSJun-ichiro itojun Hagino } 1188df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 1189707d00a3SJonathan Lemon if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { 1190df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 1191df8bae1dSRodney W. Grimes goto bad; 1192df8bae1dSRodney W. Grimes } 1193df8bae1dSRodney W. Grimes } 1194df8bae1dSRodney W. Grimes switch (opt) { 1195df8bae1dSRodney W. Grimes 1196df8bae1dSRodney W. Grimes default: 1197df8bae1dSRodney W. Grimes break; 1198df8bae1dSRodney W. Grimes 1199df8bae1dSRodney W. Grimes /* 1200df8bae1dSRodney W. Grimes * Source routing with record. 1201df8bae1dSRodney W. Grimes * Find interface with current destination address. 1202df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 1203df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 1204df8bae1dSRodney W. Grimes * Record interface address and bring up next address 1205df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 1206df8bae1dSRodney W. Grimes * address is on directly accessible net. 1207df8bae1dSRodney W. Grimes */ 1208df8bae1dSRodney W. Grimes case IPOPT_LSRR: 1209df8bae1dSRodney W. Grimes case IPOPT_SSRR: 121033841545SHajimu UMEMOTO if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 121133841545SHajimu UMEMOTO code = &cp[IPOPT_OLEN] - (u_char *)ip; 121233841545SHajimu UMEMOTO goto bad; 121333841545SHajimu UMEMOTO } 1214df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1215df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1216df8bae1dSRodney W. Grimes goto bad; 1217df8bae1dSRodney W. Grimes } 1218df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 1219df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 1220df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 1221df8bae1dSRodney W. Grimes if (ia == 0) { 1222df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1223df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1224df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1225df8bae1dSRodney W. Grimes goto bad; 1226df8bae1dSRodney W. Grimes } 1227bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1228bc189bf8SGuido van Rooij goto nosourcerouting; 1229df8bae1dSRodney W. Grimes /* 1230df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1231df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1232df8bae1dSRodney W. Grimes */ 1233df8bae1dSRodney W. Grimes break; 1234df8bae1dSRodney W. Grimes } 1235df8bae1dSRodney W. Grimes off--; /* 0 origin */ 12365d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) { 1237df8bae1dSRodney W. Grimes /* 1238df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1239df8bae1dSRodney W. Grimes */ 12404fce5804SGuido van Rooij if (!ip_acceptsourceroute) 12414fce5804SGuido van Rooij goto nosourcerouting; 1242df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 1243df8bae1dSRodney W. Grimes break; 1244df8bae1dSRodney W. Grimes } 12451025071fSGarrett Wollman 12461025071fSGarrett Wollman if (!ip_dosourceroute) { 12470af8d3ecSDavid Greenman if (ipforwarding) { 12480af8d3ecSDavid Greenman char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 12490af8d3ecSDavid Greenman /* 12500af8d3ecSDavid Greenman * Acting as a router, so generate ICMP 12510af8d3ecSDavid Greenman */ 1252efa48587SGuido van Rooij nosourcerouting: 1253bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 12541025071fSGarrett Wollman log(LOG_WARNING, 12551025071fSGarrett Wollman "attempted source route from %s to %s\n", 12561025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 12571025071fSGarrett Wollman type = ICMP_UNREACH; 12581025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 12591025071fSGarrett Wollman goto bad; 12600af8d3ecSDavid Greenman } else { 12610af8d3ecSDavid Greenman /* 12620af8d3ecSDavid Greenman * Not acting as a router, so silently drop. 12630af8d3ecSDavid Greenman */ 12640af8d3ecSDavid Greenman ipstat.ips_cantforward++; 12650af8d3ecSDavid Greenman m_freem(m); 12660af8d3ecSDavid Greenman return (1); 12670af8d3ecSDavid Greenman } 12681025071fSGarrett Wollman } 12691025071fSGarrett Wollman 1270df8bae1dSRodney W. Grimes /* 1271df8bae1dSRodney W. Grimes * locate outgoing interface 1272df8bae1dSRodney W. Grimes */ 127394a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1274df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 12751025071fSGarrett Wollman 1276df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1277df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1278df8bae1dSRodney W. Grimes #define SA struct sockaddr * 1279df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 1280df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1281df8bae1dSRodney W. Grimes } else 1282df8bae1dSRodney W. Grimes ia = ip_rtaddr(ipaddr.sin_addr); 1283df8bae1dSRodney W. Grimes if (ia == 0) { 1284df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1285df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1286df8bae1dSRodney W. Grimes goto bad; 1287df8bae1dSRodney W. Grimes } 1288df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 128994a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 129094a5d9b6SDavid Greenman sizeof(struct in_addr)); 1291df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1292df8bae1dSRodney W. Grimes /* 1293df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1294df8bae1dSRodney W. Grimes */ 1295df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1296df8bae1dSRodney W. Grimes break; 1297df8bae1dSRodney W. Grimes 1298df8bae1dSRodney W. Grimes case IPOPT_RR: 1299707d00a3SJonathan Lemon if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 1300707d00a3SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1301707d00a3SJonathan Lemon goto bad; 1302707d00a3SJonathan Lemon } 1303df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1304df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1305df8bae1dSRodney W. Grimes goto bad; 1306df8bae1dSRodney W. Grimes } 1307df8bae1dSRodney W. Grimes /* 1308df8bae1dSRodney W. Grimes * If no space remains, ignore. 1309df8bae1dSRodney W. Grimes */ 1310df8bae1dSRodney W. Grimes off--; /* 0 origin */ 13115d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) 1312df8bae1dSRodney W. Grimes break; 131394a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1314df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1315df8bae1dSRodney W. Grimes /* 1316df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1317df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1318df8bae1dSRodney W. Grimes */ 1319df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 1320df8bae1dSRodney W. Grimes (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 1321df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1322df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1323df8bae1dSRodney W. Grimes goto bad; 1324df8bae1dSRodney W. Grimes } 132594a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 132694a5d9b6SDavid Greenman sizeof(struct in_addr)); 1327df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1328df8bae1dSRodney W. Grimes break; 1329df8bae1dSRodney W. Grimes 1330df8bae1dSRodney W. Grimes case IPOPT_TS: 1331df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 1332df8bae1dSRodney W. Grimes ipt = (struct ip_timestamp *)cp; 133333841545SHajimu UMEMOTO if (ipt->ipt_len < 4 || ipt->ipt_len > 40) { 133433841545SHajimu UMEMOTO code = (u_char *)&ipt->ipt_len - (u_char *)ip; 1335df8bae1dSRodney W. Grimes goto bad; 133633841545SHajimu UMEMOTO } 133733841545SHajimu UMEMOTO if (ipt->ipt_ptr < 5) { 133833841545SHajimu UMEMOTO code = (u_char *)&ipt->ipt_ptr - (u_char *)ip; 133933841545SHajimu UMEMOTO goto bad; 134033841545SHajimu UMEMOTO } 13415d5d5fc0SJonathan Lemon if (ipt->ipt_ptr > 13425d5d5fc0SJonathan Lemon ipt->ipt_len - (int)sizeof(int32_t)) { 134333841545SHajimu UMEMOTO if (++ipt->ipt_oflw == 0) { 134433841545SHajimu UMEMOTO code = (u_char *)&ipt->ipt_ptr - 134533841545SHajimu UMEMOTO (u_char *)ip; 1346df8bae1dSRodney W. Grimes goto bad; 134733841545SHajimu UMEMOTO } 1348df8bae1dSRodney W. Grimes break; 1349df8bae1dSRodney W. Grimes } 1350df8bae1dSRodney W. Grimes sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 1351df8bae1dSRodney W. Grimes switch (ipt->ipt_flg) { 1352df8bae1dSRodney W. Grimes 1353df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1354df8bae1dSRodney W. Grimes break; 1355df8bae1dSRodney W. Grimes 1356df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 1357b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 135833841545SHajimu UMEMOTO sizeof(struct in_addr) > ipt->ipt_len) { 135933841545SHajimu UMEMOTO code = (u_char *)&ipt->ipt_ptr - 136033841545SHajimu UMEMOTO (u_char *)ip; 1361df8bae1dSRodney W. Grimes goto bad; 136233841545SHajimu UMEMOTO } 1363df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1364df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1365df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1366df8bae1dSRodney W. Grimes if (ia == 0) 1367df8bae1dSRodney W. Grimes continue; 136894a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 136994a5d9b6SDavid Greenman sizeof(struct in_addr)); 1370df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1371df8bae1dSRodney W. Grimes break; 1372df8bae1dSRodney W. Grimes 1373df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 1374b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 137533841545SHajimu UMEMOTO sizeof(struct in_addr) > ipt->ipt_len) { 137633841545SHajimu UMEMOTO code = (u_char *)&ipt->ipt_ptr - 137733841545SHajimu UMEMOTO (u_char *)ip; 1378df8bae1dSRodney W. Grimes goto bad; 137933841545SHajimu UMEMOTO } 138094a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1381df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1382df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1383df8bae1dSRodney W. Grimes continue; 1384df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1385df8bae1dSRodney W. Grimes break; 1386df8bae1dSRodney W. Grimes 1387df8bae1dSRodney W. Grimes default: 138833841545SHajimu UMEMOTO /* XXX can't take &ipt->ipt_flg */ 138933841545SHajimu UMEMOTO code = (u_char *)&ipt->ipt_ptr - 139033841545SHajimu UMEMOTO (u_char *)ip + 1; 1391df8bae1dSRodney W. Grimes goto bad; 1392df8bae1dSRodney W. Grimes } 1393df8bae1dSRodney W. Grimes ntime = iptime(); 139494a5d9b6SDavid Greenman (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime, 1395df8bae1dSRodney W. Grimes sizeof(n_time)); 1396df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(n_time); 1397df8bae1dSRodney W. Grimes } 1398df8bae1dSRodney W. Grimes } 139947174b49SAndrey A. Chernov if (forward && ipforwarding) { 1400df8bae1dSRodney W. Grimes ip_forward(m, 1); 1401df8bae1dSRodney W. Grimes return (1); 1402df8bae1dSRodney W. Grimes } 1403df8bae1dSRodney W. Grimes return (0); 1404df8bae1dSRodney W. Grimes bad: 1405df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1406df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1407df8bae1dSRodney W. Grimes return (1); 1408df8bae1dSRodney W. Grimes } 1409df8bae1dSRodney W. Grimes 1410df8bae1dSRodney W. Grimes /* 1411df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1412df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1413df8bae1dSRodney W. Grimes */ 14140312fbe9SPoul-Henning Kamp static struct in_ifaddr * 1415df8bae1dSRodney W. Grimes ip_rtaddr(dst) 1416df8bae1dSRodney W. Grimes struct in_addr dst; 1417df8bae1dSRodney W. Grimes { 1418df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1419df8bae1dSRodney W. Grimes 1420df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 1421df8bae1dSRodney W. Grimes 14224078ffb1SRuslan Ermilov if (ipforward_rt.ro_rt == 0 || 14234078ffb1SRuslan Ermilov !(ipforward_rt.ro_rt->rt_flags & RTF_UP) || 14244078ffb1SRuslan Ermilov dst.s_addr != sin->sin_addr.s_addr) { 1425df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1426df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1427df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1428df8bae1dSRodney W. Grimes } 1429df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1430df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1431df8bae1dSRodney W. Grimes sin->sin_addr = dst; 1432df8bae1dSRodney W. Grimes 14332c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1434df8bae1dSRodney W. Grimes } 1435df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) 1436df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 1437df8bae1dSRodney W. Grimes return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); 1438df8bae1dSRodney W. Grimes } 1439df8bae1dSRodney W. Grimes 1440df8bae1dSRodney W. Grimes /* 1441df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1442df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1443df8bae1dSRodney W. Grimes */ 1444df8bae1dSRodney W. Grimes void 1445df8bae1dSRodney W. Grimes save_rte(option, dst) 1446df8bae1dSRodney W. Grimes u_char *option; 1447df8bae1dSRodney W. Grimes struct in_addr dst; 1448df8bae1dSRodney W. Grimes { 1449df8bae1dSRodney W. Grimes unsigned olen; 1450df8bae1dSRodney W. Grimes 1451df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1452df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1453df8bae1dSRodney W. Grimes if (ipprintfs) 1454df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1455df8bae1dSRodney W. Grimes #endif 1456df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1457df8bae1dSRodney W. Grimes return; 14580453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1459df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1460df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1461df8bae1dSRodney W. Grimes } 1462df8bae1dSRodney W. Grimes 1463df8bae1dSRodney W. Grimes /* 1464df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1465df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1466df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1467df8bae1dSRodney W. Grimes */ 1468df8bae1dSRodney W. Grimes struct mbuf * 1469df8bae1dSRodney W. Grimes ip_srcroute() 1470df8bae1dSRodney W. Grimes { 1471df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1472df8bae1dSRodney W. Grimes register struct mbuf *m; 1473df8bae1dSRodney W. Grimes 1474df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1475df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1476cfe8b629SGarrett Wollman m = m_get(M_DONTWAIT, MT_HEADER); 1477df8bae1dSRodney W. Grimes if (m == 0) 1478df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1479df8bae1dSRodney W. Grimes 1480df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1481df8bae1dSRodney W. Grimes 1482df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1483df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1484df8bae1dSRodney W. Grimes OPTSIZ; 1485df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1486df8bae1dSRodney W. Grimes if (ipprintfs) 1487df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1488df8bae1dSRodney W. Grimes #endif 1489df8bae1dSRodney W. Grimes 1490df8bae1dSRodney W. Grimes /* 1491df8bae1dSRodney W. Grimes * First save first hop for return route 1492df8bae1dSRodney W. Grimes */ 1493df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1494df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1495df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1496df8bae1dSRodney W. Grimes if (ipprintfs) 1497af38c68cSLuigi Rizzo printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); 1498df8bae1dSRodney W. Grimes #endif 1499df8bae1dSRodney W. Grimes 1500df8bae1dSRodney W. Grimes /* 1501df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1502df8bae1dSRodney W. Grimes */ 1503df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1504df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 150594a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 150694a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1507df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1508df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1509df8bae1dSRodney W. Grimes #undef OPTSIZ 1510df8bae1dSRodney W. Grimes /* 1511df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1512df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1513df8bae1dSRodney W. Grimes */ 1514df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1515df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1516df8bae1dSRodney W. Grimes if (ipprintfs) 1517af38c68cSLuigi Rizzo printf(" %lx", (u_long)ntohl(q->s_addr)); 1518df8bae1dSRodney W. Grimes #endif 1519df8bae1dSRodney W. Grimes *q++ = *p--; 1520df8bae1dSRodney W. Grimes } 1521df8bae1dSRodney W. Grimes /* 1522df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1523df8bae1dSRodney W. Grimes */ 1524df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1525df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1526df8bae1dSRodney W. Grimes if (ipprintfs) 1527af38c68cSLuigi Rizzo printf(" %lx\n", (u_long)ntohl(q->s_addr)); 1528df8bae1dSRodney W. Grimes #endif 1529df8bae1dSRodney W. Grimes return (m); 1530df8bae1dSRodney W. Grimes } 1531df8bae1dSRodney W. Grimes 1532df8bae1dSRodney W. Grimes /* 1533df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1534df8bae1dSRodney W. Grimes * level protocol in the kernel. 1535df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1536df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1537df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1538df8bae1dSRodney W. Grimes */ 1539df8bae1dSRodney W. Grimes void 1540df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1541df8bae1dSRodney W. Grimes register struct mbuf *m; 1542df8bae1dSRodney W. Grimes struct mbuf *mopt; 1543df8bae1dSRodney W. Grimes { 1544df8bae1dSRodney W. Grimes register int i; 1545df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1546df8bae1dSRodney W. Grimes register caddr_t opts; 1547df8bae1dSRodney W. Grimes int olen; 1548df8bae1dSRodney W. Grimes 154958938916SGarrett Wollman olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1550df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1551df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1552df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1553df8bae1dSRodney W. Grimes m->m_len -= olen; 1554df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1555df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 155658938916SGarrett Wollman ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); 1557df8bae1dSRodney W. Grimes } 1558df8bae1dSRodney W. Grimes 1559df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1560df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1561df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1562df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1563df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1564df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1565e4bb5b05SJonathan Lemon ENOPROTOOPT, ENETRESET 1566df8bae1dSRodney W. Grimes }; 1567df8bae1dSRodney W. Grimes 1568df8bae1dSRodney W. Grimes /* 1569df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1570df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1571df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1572df8bae1dSRodney W. Grimes * of codes and types. 1573df8bae1dSRodney W. Grimes * 1574df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1575df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1576df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1577df8bae1dSRodney W. Grimes * protocol deal with that. 1578df8bae1dSRodney W. Grimes * 1579df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1580df8bae1dSRodney W. Grimes * via a source route. 1581df8bae1dSRodney W. Grimes */ 15820312fbe9SPoul-Henning Kamp static void 1583df8bae1dSRodney W. Grimes ip_forward(m, srcrt) 1584df8bae1dSRodney W. Grimes struct mbuf *m; 1585df8bae1dSRodney W. Grimes int srcrt; 1586df8bae1dSRodney W. Grimes { 1587df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1588df8bae1dSRodney W. Grimes register struct rtentry *rt; 158926f9a767SRodney W. Grimes int error, type = 0, code = 0; 1590df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1591df8bae1dSRodney W. Grimes n_long dest; 1592df8bae1dSRodney W. Grimes struct ifnet *destifp; 15936a800098SYoshinobu Inoue #ifdef IPSEC 15946a800098SYoshinobu Inoue struct ifnet dummyifp; 15956a800098SYoshinobu Inoue #endif 1596df8bae1dSRodney W. Grimes 1597df8bae1dSRodney W. Grimes dest = 0; 1598df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1599df8bae1dSRodney W. Grimes if (ipprintfs) 160061ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 1601162886e2SBruce Evans (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr, 1602162886e2SBruce Evans ip->ip_ttl); 1603df8bae1dSRodney W. Grimes #endif 1604100ba1a6SJordan K. Hubbard 1605100ba1a6SJordan K. Hubbard 160692af003dSGarrett Wollman if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { 1607df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1608df8bae1dSRodney W. Grimes m_freem(m); 1609df8bae1dSRodney W. Grimes return; 1610df8bae1dSRodney W. Grimes } 16111b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 16121b968362SDag-Erling Smørgrav if (!ipstealth) { 16131b968362SDag-Erling Smørgrav #endif 1614df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 16151b968362SDag-Erling Smørgrav icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 16161b968362SDag-Erling Smørgrav dest, 0); 1617df8bae1dSRodney W. Grimes return; 1618df8bae1dSRodney W. Grimes } 16191b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 16201b968362SDag-Erling Smørgrav } 16211b968362SDag-Erling Smørgrav #endif 1622df8bae1dSRodney W. Grimes 16234078ffb1SRuslan Ermilov if (ip_rtaddr(ip->ip_dst) == 0) { 1624df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1625df8bae1dSRodney W. Grimes return; 16264078ffb1SRuslan Ermilov } else 1627df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1628df8bae1dSRodney W. Grimes 1629df8bae1dSRodney W. Grimes /* 1630bfef7ed4SIan Dowse * Save the IP header and at most 8 bytes of the payload, 1631bfef7ed4SIan Dowse * in case we need to generate an ICMP message to the src. 1632bfef7ed4SIan Dowse * 1633bfef7ed4SIan Dowse * We don't use m_copy() because it might return a reference 1634bfef7ed4SIan Dowse * to a shared cluster. Both this function and ip_output() 1635bfef7ed4SIan Dowse * assume exclusive access to the IP header in `m', so any 1636bfef7ed4SIan Dowse * data in a cluster may change before we reach icmp_error(). 1637df8bae1dSRodney W. Grimes */ 1638bfef7ed4SIan Dowse MGET(mcopy, M_DONTWAIT, m->m_type); 1639bfef7ed4SIan Dowse if (mcopy != NULL) { 1640bfef7ed4SIan Dowse M_COPY_PKTHDR(mcopy, m); 1641bfef7ed4SIan Dowse mcopy->m_len = imin((IP_VHL_HL(ip->ip_vhl) << 2) + 8, 1642bfef7ed4SIan Dowse (int)ip->ip_len); 1643bfef7ed4SIan Dowse m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t)); 1644bfef7ed4SIan Dowse } 164504287599SRuslan Ermilov 164604287599SRuslan Ermilov #ifdef IPSTEALTH 164704287599SRuslan Ermilov if (!ipstealth) { 164804287599SRuslan Ermilov #endif 164904287599SRuslan Ermilov ip->ip_ttl -= IPTTLDEC; 165004287599SRuslan Ermilov #ifdef IPSTEALTH 165104287599SRuslan Ermilov } 165204287599SRuslan Ermilov #endif 1653df8bae1dSRodney W. Grimes 1654df8bae1dSRodney W. Grimes /* 1655df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1656df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1657df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1658df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1659df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1660df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1661df8bae1dSRodney W. Grimes */ 1662df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 1663df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1664df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1665df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 1666df8bae1dSRodney W. Grimes ipsendredirects && !srcrt) { 1667df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1668df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1669df8bae1dSRodney W. Grimes 1670df8bae1dSRodney W. Grimes if (RTA(rt) && 1671df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1672df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1673df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1674df8bae1dSRodney W. Grimes else 1675df8bae1dSRodney W. Grimes dest = ip->ip_dst.s_addr; 1676df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1677df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1678df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1679df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1680df8bae1dSRodney W. Grimes if (ipprintfs) 1681df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1682df8bae1dSRodney W. Grimes #endif 1683df8bae1dSRodney W. Grimes } 1684df8bae1dSRodney W. Grimes } 1685df8bae1dSRodney W. Grimes 1686b97d15cbSGarrett Wollman error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 1687b97d15cbSGarrett Wollman IP_FORWARDING, 0); 1688df8bae1dSRodney W. Grimes if (error) 1689df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1690df8bae1dSRodney W. Grimes else { 1691df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1692df8bae1dSRodney W. Grimes if (type) 1693df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1694df8bae1dSRodney W. Grimes else { 16951f91d8c5SDavid Greenman if (mcopy) { 16961f91d8c5SDavid Greenman ipflow_create(&ipforward_rt, mcopy); 1697df8bae1dSRodney W. Grimes m_freem(mcopy); 16981f91d8c5SDavid Greenman } 1699df8bae1dSRodney W. Grimes return; 1700df8bae1dSRodney W. Grimes } 1701df8bae1dSRodney W. Grimes } 1702df8bae1dSRodney W. Grimes if (mcopy == NULL) 1703df8bae1dSRodney W. Grimes return; 1704df8bae1dSRodney W. Grimes destifp = NULL; 1705df8bae1dSRodney W. Grimes 1706df8bae1dSRodney W. Grimes switch (error) { 1707df8bae1dSRodney W. Grimes 1708df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1709df8bae1dSRodney W. Grimes /* type, code set above */ 1710df8bae1dSRodney W. Grimes break; 1711df8bae1dSRodney W. Grimes 1712df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1713df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1714df8bae1dSRodney W. Grimes case ENETDOWN: 1715df8bae1dSRodney W. Grimes case EHOSTDOWN: 1716df8bae1dSRodney W. Grimes default: 1717df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1718df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1719df8bae1dSRodney W. Grimes break; 1720df8bae1dSRodney W. Grimes 1721df8bae1dSRodney W. Grimes case EMSGSIZE: 1722df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1723df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 17246a800098SYoshinobu Inoue #ifndef IPSEC 1725df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) 1726df8bae1dSRodney W. Grimes destifp = ipforward_rt.ro_rt->rt_ifp; 17276a800098SYoshinobu Inoue #else 17286a800098SYoshinobu Inoue /* 17296a800098SYoshinobu Inoue * If the packet is routed over IPsec tunnel, tell the 17306a800098SYoshinobu Inoue * originator the tunnel MTU. 17316a800098SYoshinobu Inoue * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 17326a800098SYoshinobu Inoue * XXX quickhack!!! 17336a800098SYoshinobu Inoue */ 17346a800098SYoshinobu Inoue if (ipforward_rt.ro_rt) { 17356a800098SYoshinobu Inoue struct secpolicy *sp = NULL; 17366a800098SYoshinobu Inoue int ipsecerror; 17376a800098SYoshinobu Inoue int ipsechdr; 17386a800098SYoshinobu Inoue struct route *ro; 17396a800098SYoshinobu Inoue 17406a800098SYoshinobu Inoue sp = ipsec4_getpolicybyaddr(mcopy, 17416a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 17426a800098SYoshinobu Inoue IP_FORWARDING, 17436a800098SYoshinobu Inoue &ipsecerror); 17446a800098SYoshinobu Inoue 17456a800098SYoshinobu Inoue if (sp == NULL) 17466a800098SYoshinobu Inoue destifp = ipforward_rt.ro_rt->rt_ifp; 17476a800098SYoshinobu Inoue else { 17486a800098SYoshinobu Inoue /* count IPsec header size */ 17496a800098SYoshinobu Inoue ipsechdr = ipsec4_hdrsiz(mcopy, 17506a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 17516a800098SYoshinobu Inoue NULL); 17526a800098SYoshinobu Inoue 17536a800098SYoshinobu Inoue /* 17546a800098SYoshinobu Inoue * find the correct route for outer IPv4 17556a800098SYoshinobu Inoue * header, compute tunnel MTU. 17566a800098SYoshinobu Inoue * 17576a800098SYoshinobu Inoue * XXX BUG ALERT 17586a800098SYoshinobu Inoue * The "dummyifp" code relies upon the fact 17596a800098SYoshinobu Inoue * that icmp_error() touches only ifp->if_mtu. 17606a800098SYoshinobu Inoue */ 17616a800098SYoshinobu Inoue /*XXX*/ 17626a800098SYoshinobu Inoue destifp = NULL; 17636a800098SYoshinobu Inoue if (sp->req != NULL 17646a800098SYoshinobu Inoue && sp->req->sav != NULL 17656a800098SYoshinobu Inoue && sp->req->sav->sah != NULL) { 17666a800098SYoshinobu Inoue ro = &sp->req->sav->sah->sa_route; 17676a800098SYoshinobu Inoue if (ro->ro_rt && ro->ro_rt->rt_ifp) { 17686a800098SYoshinobu Inoue dummyifp.if_mtu = 17696a800098SYoshinobu Inoue ro->ro_rt->rt_ifp->if_mtu; 17706a800098SYoshinobu Inoue dummyifp.if_mtu -= ipsechdr; 17716a800098SYoshinobu Inoue destifp = &dummyifp; 17726a800098SYoshinobu Inoue } 17736a800098SYoshinobu Inoue } 17746a800098SYoshinobu Inoue 17756a800098SYoshinobu Inoue key_freesp(sp); 17766a800098SYoshinobu Inoue } 17776a800098SYoshinobu Inoue } 17786a800098SYoshinobu Inoue #endif /*IPSEC*/ 1779df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1780df8bae1dSRodney W. Grimes break; 1781df8bae1dSRodney W. Grimes 1782df8bae1dSRodney W. Grimes case ENOBUFS: 1783df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1784df8bae1dSRodney W. Grimes code = 0; 1785df8bae1dSRodney W. Grimes break; 17863a06e3e0SRuslan Ermilov 17873a06e3e0SRuslan Ermilov case EACCES: /* ipfw denied packet */ 17883a06e3e0SRuslan Ermilov m_freem(mcopy); 17893a06e3e0SRuslan Ermilov return; 1790df8bae1dSRodney W. Grimes } 1791df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1792df8bae1dSRodney W. Grimes } 1793df8bae1dSRodney W. Grimes 179482c23ebaSBill Fenner void 179582c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 179682c23ebaSBill Fenner register struct inpcb *inp; 179782c23ebaSBill Fenner register struct mbuf **mp; 179882c23ebaSBill Fenner register struct ip *ip; 179982c23ebaSBill Fenner register struct mbuf *m; 180082c23ebaSBill Fenner { 180182c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 180282c23ebaSBill Fenner struct timeval tv; 180382c23ebaSBill Fenner 180482c23ebaSBill Fenner microtime(&tv); 180582c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 180682c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 180782c23ebaSBill Fenner if (*mp) 180882c23ebaSBill Fenner mp = &(*mp)->m_next; 180982c23ebaSBill Fenner } 181082c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 181182c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 181282c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 181382c23ebaSBill Fenner if (*mp) 181482c23ebaSBill Fenner mp = &(*mp)->m_next; 181582c23ebaSBill Fenner } 181682c23ebaSBill Fenner #ifdef notyet 181782c23ebaSBill Fenner /* XXX 181882c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 181982c23ebaSBill Fenner * than they already were. 182082c23ebaSBill Fenner */ 182182c23ebaSBill Fenner /* options were tossed already */ 182282c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 182382c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 182482c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 182582c23ebaSBill Fenner if (*mp) 182682c23ebaSBill Fenner mp = &(*mp)->m_next; 182782c23ebaSBill Fenner } 182882c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 182982c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 183082c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 183182c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 183282c23ebaSBill Fenner if (*mp) 183382c23ebaSBill Fenner mp = &(*mp)->m_next; 183482c23ebaSBill Fenner } 183582c23ebaSBill Fenner #endif 183682c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 1837d314ad7bSJulian Elischer struct ifnet *ifp; 1838d314ad7bSJulian Elischer struct sdlbuf { 183982c23ebaSBill Fenner struct sockaddr_dl sdl; 1840d314ad7bSJulian Elischer u_char pad[32]; 1841d314ad7bSJulian Elischer } sdlbuf; 1842d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 1843d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 184482c23ebaSBill Fenner 1845d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 1846d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 1847d314ad7bSJulian Elischer sdp = (struct sockaddr_dl *)(ifnet_addrs 1848d314ad7bSJulian Elischer [ifp->if_index - 1]->ifa_addr); 1849d314ad7bSJulian Elischer /* 1850d314ad7bSJulian Elischer * Change our mind and don't try copy. 1851d314ad7bSJulian Elischer */ 1852d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 1853d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 1854d314ad7bSJulian Elischer goto makedummy; 1855d314ad7bSJulian Elischer } 1856d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 1857d314ad7bSJulian Elischer } else { 1858d314ad7bSJulian Elischer makedummy: 1859d314ad7bSJulian Elischer sdl2->sdl_len 1860d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 1861d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 1862d314ad7bSJulian Elischer sdl2->sdl_index = 0; 1863d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 1864d314ad7bSJulian Elischer } 1865d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 186682c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 186782c23ebaSBill Fenner if (*mp) 186882c23ebaSBill Fenner mp = &(*mp)->m_next; 186982c23ebaSBill Fenner } 187082c23ebaSBill Fenner } 187182c23ebaSBill Fenner 1872df8bae1dSRodney W. Grimes int 1873f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 1874f0068c4aSGarrett Wollman { 1875f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 1876f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 1877f0068c4aSGarrett Wollman return EOPNOTSUPP; 1878f0068c4aSGarrett Wollman 1879f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 1880f0068c4aSGarrett Wollman return EADDRINUSE; 1881f0068c4aSGarrett Wollman 1882f0068c4aSGarrett Wollman ip_rsvpd = so; 18831c5de19aSGarrett Wollman /* 18841c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 18851c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 18861c5de19aSGarrett Wollman */ 18871c5de19aSGarrett Wollman if (!ip_rsvp_on) { 18881c5de19aSGarrett Wollman ip_rsvp_on = 1; 18891c5de19aSGarrett Wollman rsvp_on++; 18901c5de19aSGarrett Wollman } 1891f0068c4aSGarrett Wollman 1892f0068c4aSGarrett Wollman return 0; 1893f0068c4aSGarrett Wollman } 1894f0068c4aSGarrett Wollman 1895f0068c4aSGarrett Wollman int 1896f0068c4aSGarrett Wollman ip_rsvp_done(void) 1897f0068c4aSGarrett Wollman { 1898f0068c4aSGarrett Wollman ip_rsvpd = NULL; 18991c5de19aSGarrett Wollman /* 19001c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 19011c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 19021c5de19aSGarrett Wollman */ 19031c5de19aSGarrett Wollman if (ip_rsvp_on) { 19041c5de19aSGarrett Wollman ip_rsvp_on = 0; 19051c5de19aSGarrett Wollman rsvp_on--; 19061c5de19aSGarrett Wollman } 1907f0068c4aSGarrett Wollman return 0; 1908f0068c4aSGarrett Wollman } 1909