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> 639494d596SBrooks Davis #include <net/if_types.h> 64d314ad7bSJulian Elischer #include <net/if_var.h> 6582c23ebaSBill Fenner #include <net/if_dl.h> 66df8bae1dSRodney W. Grimes #include <net/route.h> 67748e0b0aSGarrett Wollman #include <net/netisr.h> 68367d34f8SBrian Somers #include <net/intrq.h> 69df8bae1dSRodney W. Grimes 70df8bae1dSRodney W. Grimes #include <netinet/in.h> 71df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 72b5e8ce9fSBruce Evans #include <netinet/in_var.h> 73df8bae1dSRodney W. Grimes #include <netinet/ip.h> 74df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 75df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 76df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 7758938916SGarrett Wollman #include <machine/in_cksum.h> 78df8bae1dSRodney W. Grimes 79f0068c4aSGarrett Wollman #include <sys/socketvar.h> 806ddbf1e2SGary Palmer 816ddbf1e2SGary Palmer #include <netinet/ip_fw.h> 82db69a05dSPaul Saab #include <netinet/ip_dummynet.h> 83db69a05dSPaul Saab 846a800098SYoshinobu Inoue #ifdef IPSEC 856a800098SYoshinobu Inoue #include <netinet6/ipsec.h> 866a800098SYoshinobu Inoue #include <netkey/key.h> 876a800098SYoshinobu Inoue #endif 886a800098SYoshinobu Inoue 891c5de19aSGarrett Wollman int rsvp_on = 0; 90f708ef1bSPoul-Henning Kamp static int ip_rsvp_on; 91f0068c4aSGarrett Wollman struct socket *ip_rsvpd; 92f0068c4aSGarrett Wollman 931f91d8c5SDavid Greenman int ipforwarding = 0; 940312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, 953d177f46SBill Fumerola &ipforwarding, 0, "Enable IP forwarding between interfaces"); 960312fbe9SPoul-Henning Kamp 97d4fb926cSGarrett Wollman static int ipsendredirects = 1; /* XXX */ 980312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, 993d177f46SBill Fumerola &ipsendredirects, 0, "Enable sending IP redirects"); 1000312fbe9SPoul-Henning Kamp 101df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 1020312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, 1033d177f46SBill Fumerola &ip_defttl, 0, "Maximum TTL on IP packets"); 1040312fbe9SPoul-Henning Kamp 1050312fbe9SPoul-Henning Kamp static int ip_dosourceroute = 0; 1060312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 1073d177f46SBill Fumerola &ip_dosourceroute, 0, "Enable forwarding source routed IP packets"); 1084fce5804SGuido van Rooij 1094fce5804SGuido van Rooij static int ip_acceptsourceroute = 0; 1104fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 1113d177f46SBill Fumerola CTLFLAG_RW, &ip_acceptsourceroute, 0, 1123d177f46SBill Fumerola "Enable accepting source routed IP packets"); 1136a800098SYoshinobu Inoue 1146a800098SYoshinobu Inoue static int ip_keepfaith = 0; 1156a800098SYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW, 1166a800098SYoshinobu Inoue &ip_keepfaith, 0, 1176a800098SYoshinobu Inoue "Enable packet capture for FAITH IPv4->IPv6 translater daemon"); 1186a800098SYoshinobu Inoue 119690a6055SJesper Skriver static int ip_nfragpackets = 0; 12096c2b042SJesper Skriver static int ip_maxfragpackets; /* initialized in ip_init() */ 121690a6055SJesper Skriver SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW, 122690a6055SJesper Skriver &ip_maxfragpackets, 0, 123690a6055SJesper Skriver "Maximum number of IPv4 fragment reassembly queue entries"); 124690a6055SJesper Skriver 125823db0e9SDon Lewis /* 126823db0e9SDon Lewis * XXX - Setting ip_checkinterface mostly implements the receive side of 127823db0e9SDon Lewis * the Strong ES model described in RFC 1122, but since the routing table 128a8f12100SDon Lewis * and transmit implementation do not implement the Strong ES model, 129823db0e9SDon Lewis * setting this to 1 results in an odd hybrid. 1303f67c834SDon Lewis * 131a8f12100SDon Lewis * XXX - ip_checkinterface currently must be disabled if you use ipnat 132a8f12100SDon Lewis * to translate the destination address to another local interface. 1333f67c834SDon Lewis * 1343f67c834SDon Lewis * XXX - ip_checkinterface must be disabled if you add IP aliases 1353f67c834SDon Lewis * to the loopback interface instead of the interface where the 1363f67c834SDon Lewis * packets for those addresses are received. 137823db0e9SDon Lewis */ 138b3e95d4eSJonathan Lemon static int ip_checkinterface = 1; 139b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW, 140b3e95d4eSJonathan Lemon &ip_checkinterface, 0, "Verify packet arrives on correct interface"); 141b3e95d4eSJonathan Lemon 142df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1430312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 144df8bae1dSRodney W. Grimes #endif 145df8bae1dSRodney W. Grimes 146ca925d9cSJonathan Lemon static int ipqmaxlen = IFQ_MAXLEN; 147ca925d9cSJonathan Lemon 148df8bae1dSRodney W. Grimes extern struct domain inetdomain; 149f0ffb944SJulian Elischer extern struct protosw inetsw[]; 150df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 15159562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 152ca925d9cSJonathan Lemon struct in_ifaddrhashhead *in_ifaddrhashtbl; /* inet addr hash table */ 153ca925d9cSJonathan Lemon u_long in_ifaddrhmask; /* mask for hash table */ 154ca925d9cSJonathan Lemon 155afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW, 1563d177f46SBill Fumerola &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue"); 1570312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1583d177f46SBill Fumerola &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue"); 159df8bae1dSRodney W. Grimes 160f23b4c91SGarrett Wollman struct ipstat ipstat; 161c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW, 1623d177f46SBill Fumerola &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)"); 163194a213eSAndrey A. Chernov 164194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 165194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 166194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 167194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 168194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 169831a80b0SMatthew Dillon (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 170194a213eSAndrey A. Chernov 171462b86feSPoul-Henning Kamp static TAILQ_HEAD(ipqhead, ipq) ipq[IPREASS_NHASH]; 172194a213eSAndrey A. Chernov static int nipq = 0; /* total # of reass queues */ 173194a213eSAndrey A. Chernov static int maxnipq; 174f23b4c91SGarrett Wollman 1750312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1760312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1773d177f46SBill Fumerola &ip_mtu, 0, "Default MTU"); 1780312fbe9SPoul-Henning Kamp #endif 1790312fbe9SPoul-Henning Kamp 1801b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 1811b968362SDag-Erling Smørgrav static int ipstealth = 0; 1821b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW, 1831b968362SDag-Erling Smørgrav &ipstealth, 0, ""); 1841b968362SDag-Erling Smørgrav #endif 1851b968362SDag-Erling Smørgrav 186cfe8b629SGarrett Wollman 18723bf9953SPoul-Henning Kamp /* Firewall hooks */ 18823bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 1899fcc0795SLuigi Rizzo int fw_enable = 1 ; 190e7319babSPoul-Henning Kamp 191db69a05dSPaul Saab /* Dummynet hooks */ 192db69a05dSPaul Saab ip_dn_io_t *ip_dn_io_ptr; 193b715f178SLuigi Rizzo 194afed1b49SDarren Reed 195e7319babSPoul-Henning Kamp /* 196df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 197df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 198df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 199df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 200df8bae1dSRodney W. Grimes * to us. 201df8bae1dSRodney W. Grimes */ 2020312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 203df8bae1dSRodney W. Grimes static struct ip_srcrt { 204df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 205df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 206df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 207df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 208df8bae1dSRodney W. Grimes } ip_srcrt; 209df8bae1dSRodney W. Grimes 210f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr; 211f9e354dfSJulian Elischer 2124d77a549SAlfred Perlstein static void save_rte(u_char *, struct in_addr); 2134d77a549SAlfred Perlstein static int ip_dooptions(struct mbuf *, int); 2144d77a549SAlfred Perlstein static void ip_forward(struct mbuf *, int); 2154d77a549SAlfred Perlstein static void ip_freef(struct ipqhead *, struct ipq *); 2168948e4baSArchie Cobbs #ifdef IPDIVERT 2174d77a549SAlfred Perlstein static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *, struct ipq *, u_int32_t *, u_int16_t *); 2188948e4baSArchie Cobbs #else 2194d77a549SAlfred Perlstein static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *, struct ipq *); 2208948e4baSArchie Cobbs #endif 2214d77a549SAlfred Perlstein static void ipintr(void); 2228948e4baSArchie Cobbs 223df8bae1dSRodney W. Grimes /* 224df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 225df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 226df8bae1dSRodney W. Grimes */ 227df8bae1dSRodney W. Grimes void 228df8bae1dSRodney W. Grimes ip_init() 229df8bae1dSRodney W. Grimes { 230f0ffb944SJulian Elischer register struct protosw *pr; 231df8bae1dSRodney W. Grimes register int i; 232df8bae1dSRodney W. Grimes 23359562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 234ca925d9cSJonathan Lemon in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask); 235f0ffb944SJulian Elischer pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 236df8bae1dSRodney W. Grimes if (pr == 0) 237df8bae1dSRodney W. Grimes panic("ip_init"); 238df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 239df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 240f0ffb944SJulian Elischer for (pr = inetdomain.dom_protosw; 241f0ffb944SJulian Elischer pr < inetdomain.dom_protoswNPROTOSW; pr++) 242df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 243df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 244df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 245194a213eSAndrey A. Chernov 246194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 247462b86feSPoul-Henning Kamp TAILQ_INIT(&ipq[i]); 248194a213eSAndrey A. Chernov 249194a213eSAndrey A. Chernov maxnipq = nmbclusters / 4; 25096c2b042SJesper Skriver ip_maxfragpackets = nmbclusters / 4; 251194a213eSAndrey A. Chernov 25264dddc18SKris Kennaway #ifndef RANDOM_IP_ID 253227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 25464dddc18SKris Kennaway #endif 255df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 2566008862bSJohn Baldwin mtx_init(&ipintrq.ifq_mtx, "ip_inq", NULL, MTX_DEF); 257bedbd47eSMike Smith ipintrq_present = 1; 258242c5536SPeter Wemm 259242c5536SPeter Wemm register_netisr(NETISR_IP, ipintr); 260df8bae1dSRodney W. Grimes } 261df8bae1dSRodney W. Grimes 2620312fbe9SPoul-Henning Kamp static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 2631e3d5af0SRuslan Ermilov struct route ipforward_rt; 264df8bae1dSRodney W. Grimes 265df8bae1dSRodney W. Grimes /* 266df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 267df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 268df8bae1dSRodney W. Grimes */ 269c67b1d17SGarrett Wollman void 270c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 271df8bae1dSRodney W. Grimes { 27223bf9953SPoul-Henning Kamp struct ip *ip; 27323bf9953SPoul-Henning Kamp struct ipq *fp; 2745da9f8faSJosef Karthauser struct in_ifaddr *ia = NULL; 275ca925d9cSJonathan Lemon struct ifaddr *ifa; 276823db0e9SDon Lewis int i, hlen, checkif; 27747c861ecSBrian Somers u_short sum; 2788948e4baSArchie Cobbs u_int16_t divert_cookie; /* firewall cookie */ 2797538a9a0SJonathan Lemon struct in_addr pkt_dst; 2808948e4baSArchie Cobbs #ifdef IPDIVERT 2818948e4baSArchie Cobbs u_int32_t divert_info = 0; /* packet divert/tee info */ 282b715f178SLuigi Rizzo #endif 283830cc178SLuigi Rizzo struct ip_fw *rule = NULL; 284c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 285c4ac87eaSDarren Reed struct packet_filter_hook *pfh; 286c4ac87eaSDarren Reed struct mbuf *m0; 287c4ac87eaSDarren Reed int rv; 288c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 289b715f178SLuigi Rizzo 2908948e4baSArchie Cobbs #ifdef IPDIVERT 2918948e4baSArchie Cobbs /* Get and reset firewall cookie */ 2928948e4baSArchie Cobbs divert_cookie = ip_divert_cookie; 2938948e4baSArchie Cobbs ip_divert_cookie = 0; 2948948e4baSArchie Cobbs #else 2958948e4baSArchie Cobbs divert_cookie = 0; 2968948e4baSArchie Cobbs #endif 2978948e4baSArchie Cobbs 298b715f178SLuigi Rizzo /* 299b715f178SLuigi Rizzo * dummynet packet are prepended a vestigial mbuf with 300b715f178SLuigi Rizzo * m_type = MT_DUMMYNET and m_data pointing to the matching 301b715f178SLuigi Rizzo * rule. 302b715f178SLuigi Rizzo */ 303b715f178SLuigi Rizzo if (m->m_type == MT_DUMMYNET) { 304830cc178SLuigi Rizzo rule = (struct ip_fw *)(m->m_data) ; 305b715f178SLuigi Rizzo m = m->m_next ; 306b715f178SLuigi Rizzo ip = mtod(m, struct ip *); 307b715f178SLuigi Rizzo hlen = IP_VHL_HL(ip->ip_vhl) << 2; 308b715f178SLuigi Rizzo goto iphack ; 309b715f178SLuigi Rizzo } else 310b715f178SLuigi Rizzo rule = NULL ; 311df8bae1dSRodney W. Grimes 312df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 313ed7509acSJulian Elischer if (m == NULL || (m->m_flags & M_PKTHDR) == 0) 31458938916SGarrett Wollman panic("ip_input no HDR"); 315df8bae1dSRodney W. Grimes #endif 316df8bae1dSRodney W. Grimes ipstat.ips_total++; 31758938916SGarrett Wollman 31858938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 31958938916SGarrett Wollman goto tooshort; 32058938916SGarrett Wollman 321df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 322df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 323df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 324c67b1d17SGarrett Wollman return; 325df8bae1dSRodney W. Grimes } 326df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 32758938916SGarrett Wollman 32858938916SGarrett Wollman if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { 329df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 330df8bae1dSRodney W. Grimes goto bad; 331df8bae1dSRodney W. Grimes } 33258938916SGarrett Wollman 33358938916SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 334df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 335df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 336df8bae1dSRodney W. Grimes goto bad; 337df8bae1dSRodney W. Grimes } 338df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 339df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 340df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 341c67b1d17SGarrett Wollman return; 342df8bae1dSRodney W. Grimes } 343df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 344df8bae1dSRodney W. Grimes } 34533841545SHajimu UMEMOTO 34633841545SHajimu UMEMOTO /* 127/8 must not appear on wire - RFC1122 */ 34733841545SHajimu UMEMOTO if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || 34833841545SHajimu UMEMOTO (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { 34933841545SHajimu UMEMOTO if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 35033841545SHajimu UMEMOTO ipstat.ips_badaddr++; 35133841545SHajimu UMEMOTO goto bad; 35233841545SHajimu UMEMOTO } 35333841545SHajimu UMEMOTO } 35433841545SHajimu UMEMOTO 355db4f9cc7SJonathan Lemon if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { 356db4f9cc7SJonathan Lemon sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 357db4f9cc7SJonathan Lemon } else { 35858938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 35947c861ecSBrian Somers sum = in_cksum_hdr(ip); 36058938916SGarrett Wollman } else { 36147c861ecSBrian Somers sum = in_cksum(m, hlen); 36258938916SGarrett Wollman } 363db4f9cc7SJonathan Lemon } 36447c861ecSBrian Somers if (sum) { 365df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 366df8bae1dSRodney W. Grimes goto bad; 367df8bae1dSRodney W. Grimes } 368df8bae1dSRodney W. Grimes 369df8bae1dSRodney W. Grimes /* 370df8bae1dSRodney W. Grimes * Convert fields to host representation. 371df8bae1dSRodney W. Grimes */ 372fd8e4ebcSMike Barcroft ip->ip_len = ntohs(ip->ip_len); 373df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 374df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 375df8bae1dSRodney W. Grimes goto bad; 376df8bae1dSRodney W. Grimes } 377fd8e4ebcSMike Barcroft ip->ip_off = ntohs(ip->ip_off); 378df8bae1dSRodney W. Grimes 379df8bae1dSRodney W. Grimes /* 380df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 381df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 382df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 383df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 384df8bae1dSRodney W. Grimes */ 385df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 38658938916SGarrett Wollman tooshort: 387df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 388df8bae1dSRodney W. Grimes goto bad; 389df8bae1dSRodney W. Grimes } 390df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 391df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 392df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 393df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 394df8bae1dSRodney W. Grimes } else 395df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 396df8bae1dSRodney W. Grimes } 3973f67c834SDon Lewis 39833841545SHajimu UMEMOTO #ifdef IPSEC 39933841545SHajimu UMEMOTO if (ipsec_gethist(m, NULL)) 40033841545SHajimu UMEMOTO goto pass; 40133841545SHajimu UMEMOTO #endif 4023f67c834SDon Lewis 4034dd1662bSUgen J.S. Antsilevich /* 4044dd1662bSUgen J.S. Antsilevich * IpHack's section. 4054dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 4064dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 4074dd1662bSUgen J.S. Antsilevich * deals with it. 40893e0e116SJulian Elischer * - Firewall: deny/allow/divert 409fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 410b715f178SLuigi Rizzo * - Pipe: pass pkt through dummynet. 4114dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 4124dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 4134dd1662bSUgen J.S. Antsilevich */ 414b715f178SLuigi Rizzo 415b715f178SLuigi Rizzo iphack: 416df8bae1dSRodney W. Grimes 417c4ac87eaSDarren Reed #ifdef PFIL_HOOKS 418c4ac87eaSDarren Reed /* 419c4ac87eaSDarren Reed * Run through list of hooks for input packets. If there are any 420c4ac87eaSDarren Reed * filters which require that additional packets in the flow are 421c4ac87eaSDarren Reed * not fast-forwarded, they must clear the M_CANFASTFWD flag. 422c4ac87eaSDarren Reed * Note that filters must _never_ set this flag, as another filter 423c4ac87eaSDarren Reed * in the list may have previously cleared it. 424c4ac87eaSDarren Reed */ 425c4ac87eaSDarren Reed m0 = m; 426c4ac87eaSDarren Reed pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); 427fc2ffbe6SPoul-Henning Kamp for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link)) 428c4ac87eaSDarren Reed if (pfh->pfil_func) { 429c4ac87eaSDarren Reed rv = pfh->pfil_func(ip, hlen, 430c4ac87eaSDarren Reed m->m_pkthdr.rcvif, 0, &m0); 431c4ac87eaSDarren Reed if (rv) 432beec8214SDarren Reed return; 433c4ac87eaSDarren Reed m = m0; 434c4ac87eaSDarren Reed if (m == NULL) 435c4ac87eaSDarren Reed return; 436c4ac87eaSDarren Reed ip = mtod(m, struct ip *); 437beec8214SDarren Reed } 438c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */ 439c4ac87eaSDarren Reed 4407b109fa4SLuigi Rizzo if (fw_enable && IPFW_LOADED) { 441f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 442f9e354dfSJulian Elischer /* 443f9e354dfSJulian Elischer * If we've been forwarded from the output side, then 444f9e354dfSJulian Elischer * skip the firewall a second time 445f9e354dfSJulian Elischer */ 446f9e354dfSJulian Elischer if (ip_fw_fwd_addr) 447f9e354dfSJulian Elischer goto ours; 448f9e354dfSJulian Elischer #endif /* IPFIREWALL_FORWARD */ 449f9e354dfSJulian Elischer /* 4508948e4baSArchie Cobbs * See the comment in ip_output for the return values 451b715f178SLuigi Rizzo * produced by the firewall. 452f9e354dfSJulian Elischer */ 453d60315beSLuigi Rizzo i = ip_fw_chk_ptr(&m, NULL /* oif */, &divert_cookie, 454d60315beSLuigi Rizzo &rule, &ip_fw_fwd_addr); 455d60315beSLuigi Rizzo if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */ 456507b4b54SLuigi Rizzo if (m) 457507b4b54SLuigi Rizzo m_freem(m); 458b715f178SLuigi Rizzo return; 459507b4b54SLuigi Rizzo } 460d60315beSLuigi Rizzo ip = mtod(m, struct ip *); /* just in case m changed */ 461b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ 462b715f178SLuigi Rizzo goto pass; 4637b109fa4SLuigi Rizzo if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) { 4648948e4baSArchie Cobbs /* Send packet to the appropriate pipe */ 465db69a05dSPaul Saab ip_dn_io_ptr(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule, 4666a800098SYoshinobu Inoue 0); 467e4676ba6SJulian Elischer return; 46893e0e116SJulian Elischer } 469b715f178SLuigi Rizzo #ifdef IPDIVERT 4708948e4baSArchie Cobbs if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) { 4718948e4baSArchie Cobbs /* Divert or tee packet */ 4728948e4baSArchie Cobbs divert_info = i; 473b715f178SLuigi Rizzo goto ours; 474b715f178SLuigi Rizzo } 475b715f178SLuigi Rizzo #endif 476b715f178SLuigi Rizzo #ifdef IPFIREWALL_FORWARD 477b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr != NULL) 478b715f178SLuigi Rizzo goto pass; 479b715f178SLuigi Rizzo #endif 480b715f178SLuigi Rizzo /* 481b715f178SLuigi Rizzo * if we get here, the packet must be dropped 482b715f178SLuigi Rizzo */ 483b715f178SLuigi Rizzo m_freem(m); 484b715f178SLuigi Rizzo return; 485b715f178SLuigi Rizzo } 486b715f178SLuigi Rizzo pass: 487100ba1a6SJordan K. Hubbard 488df8bae1dSRodney W. Grimes /* 489df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 490df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 491df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 492df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 493df8bae1dSRodney W. Grimes */ 494df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 495d0ebc0d2SYaroslav Tykhiy if (hlen > sizeof (struct ip) && ip_dooptions(m, 0)) { 496ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD 497ed1ff184SJulian Elischer ip_fw_fwd_addr = NULL; 498ed1ff184SJulian Elischer #endif 499c67b1d17SGarrett Wollman return; 500ed1ff184SJulian Elischer } 501df8bae1dSRodney W. Grimes 502f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 503f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 504f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 505f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 506f0068c4aSGarrett Wollman * grabbing the packet. 507f0068c4aSGarrett Wollman */ 5081c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 509f0068c4aSGarrett Wollman goto ours; 510f0068c4aSGarrett Wollman 511df8bae1dSRodney W. Grimes /* 512df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 513cc766e04SGarrett Wollman * If we don't have any addresses, assume any unicast packet 514cc766e04SGarrett Wollman * we receive might be for us (and let the upper layers deal 515cc766e04SGarrett Wollman * with it). 516df8bae1dSRodney W. Grimes */ 517cc766e04SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead) && 518cc766e04SGarrett Wollman (m->m_flags & (M_MCAST|M_BCAST)) == 0) 519cc766e04SGarrett Wollman goto ours; 520cc766e04SGarrett Wollman 5217538a9a0SJonathan Lemon /* 5227538a9a0SJonathan Lemon * Cache the destination address of the packet; this may be 5237538a9a0SJonathan Lemon * changed by use of 'ipfw fwd'. 5247538a9a0SJonathan Lemon */ 5257538a9a0SJonathan Lemon pkt_dst = ip_fw_fwd_addr == NULL ? 5267538a9a0SJonathan Lemon ip->ip_dst : ip_fw_fwd_addr->sin_addr; 5277538a9a0SJonathan Lemon 528823db0e9SDon Lewis /* 529823db0e9SDon Lewis * Enable a consistency check between the destination address 530823db0e9SDon Lewis * and the arrival interface for a unicast packet (the RFC 1122 531823db0e9SDon Lewis * strong ES model) if IP forwarding is disabled and the packet 532e15ae1b2SDon Lewis * is not locally generated and the packet is not subject to 533e15ae1b2SDon Lewis * 'ipfw fwd'. 5343f67c834SDon Lewis * 5353f67c834SDon Lewis * XXX - Checking also should be disabled if the destination 5363f67c834SDon Lewis * address is ipnat'ed to a different interface. 5373f67c834SDon Lewis * 538a8f12100SDon Lewis * XXX - Checking is incompatible with IP aliases added 5393f67c834SDon Lewis * to the loopback interface instead of the interface where 5403f67c834SDon Lewis * the packets are received. 541823db0e9SDon Lewis */ 542823db0e9SDon Lewis checkif = ip_checkinterface && (ipforwarding == 0) && 5439494d596SBrooks Davis m->m_pkthdr.rcvif != NULL && 544e15ae1b2SDon Lewis ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) && 545e15ae1b2SDon Lewis (ip_fw_fwd_addr == NULL); 546823db0e9SDon Lewis 547ca925d9cSJonathan Lemon /* 548ca925d9cSJonathan Lemon * Check for exact addresses in the hash bucket. 549ca925d9cSJonathan Lemon */ 550ca925d9cSJonathan Lemon LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) { 551f9e354dfSJulian Elischer /* 552823db0e9SDon Lewis * If the address matches, verify that the packet 553823db0e9SDon Lewis * arrived via the correct interface if checking is 554823db0e9SDon Lewis * enabled. 555f9e354dfSJulian Elischer */ 556823db0e9SDon Lewis if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr && 557823db0e9SDon Lewis (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif)) 558ed1ff184SJulian Elischer goto ours; 559ca925d9cSJonathan Lemon } 560823db0e9SDon Lewis /* 561ca925d9cSJonathan Lemon * Check for broadcast addresses. 562ca925d9cSJonathan Lemon * 563ca925d9cSJonathan Lemon * Only accept broadcast packets that arrive via the matching 564ca925d9cSJonathan Lemon * interface. Reception of forwarded directed broadcasts would 565ca925d9cSJonathan Lemon * be handled via ip_forward() and ether_output() with the loopback 566ca925d9cSJonathan Lemon * into the stack for SIMPLEX interfaces handled by ether_output(). 567823db0e9SDon Lewis */ 568ca925d9cSJonathan Lemon if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) { 569ca925d9cSJonathan Lemon TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) { 570ca925d9cSJonathan Lemon if (ifa->ifa_addr->sa_family != AF_INET) 571ca925d9cSJonathan Lemon continue; 572ca925d9cSJonathan Lemon ia = ifatoia(ifa); 573df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 5747538a9a0SJonathan Lemon pkt_dst.s_addr) 575df8bae1dSRodney W. Grimes goto ours; 5767538a9a0SJonathan Lemon if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr) 577df8bae1dSRodney W. Grimes goto ours; 578ca925d9cSJonathan Lemon #ifdef BOOTP_COMPAT 579ca925d9cSJonathan Lemon if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 580ca925d9cSJonathan Lemon goto ours; 581ca925d9cSJonathan Lemon #endif 582df8bae1dSRodney W. Grimes } 583df8bae1dSRodney W. Grimes } 584df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 585df8bae1dSRodney W. Grimes struct in_multi *inm; 586df8bae1dSRodney W. Grimes if (ip_mrouter) { 587df8bae1dSRodney W. Grimes /* 588df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 589df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 590df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 591df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 592df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 593df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 594df8bae1dSRodney W. Grimes */ 595f0068c4aSGarrett Wollman if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 596df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 597df8bae1dSRodney W. Grimes m_freem(m); 598c67b1d17SGarrett Wollman return; 599df8bae1dSRodney W. Grimes } 600df8bae1dSRodney W. Grimes 601df8bae1dSRodney W. Grimes /* 60211612afaSDima Dorfman * The process-level routing daemon needs to receive 603df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 604df8bae1dSRodney W. Grimes * host belongs to their destination groups. 605df8bae1dSRodney W. Grimes */ 606df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 607df8bae1dSRodney W. Grimes goto ours; 608df8bae1dSRodney W. Grimes ipstat.ips_forward++; 609df8bae1dSRodney W. Grimes } 610df8bae1dSRodney W. Grimes /* 611df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 612df8bae1dSRodney W. Grimes * arrival interface. 613df8bae1dSRodney W. Grimes */ 614df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 615df8bae1dSRodney W. Grimes if (inm == NULL) { 61682c39223SGarrett Wollman ipstat.ips_notmember++; 617df8bae1dSRodney W. Grimes m_freem(m); 618c67b1d17SGarrett Wollman return; 619df8bae1dSRodney W. Grimes } 620df8bae1dSRodney W. Grimes goto ours; 621df8bae1dSRodney W. Grimes } 622df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 623df8bae1dSRodney W. Grimes goto ours; 624df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 625df8bae1dSRodney W. Grimes goto ours; 626df8bae1dSRodney W. Grimes 6276a800098SYoshinobu Inoue /* 6286a800098SYoshinobu Inoue * FAITH(Firewall Aided Internet Translator) 6296a800098SYoshinobu Inoue */ 6306a800098SYoshinobu Inoue if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) { 6316a800098SYoshinobu Inoue if (ip_keepfaith) { 6326a800098SYoshinobu Inoue if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP) 6336a800098SYoshinobu Inoue goto ours; 6346a800098SYoshinobu Inoue } 6356a800098SYoshinobu Inoue m_freem(m); 6366a800098SYoshinobu Inoue return; 6376a800098SYoshinobu Inoue } 6389494d596SBrooks Davis 639df8bae1dSRodney W. Grimes /* 640df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 641df8bae1dSRodney W. Grimes */ 642df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 643df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 644df8bae1dSRodney W. Grimes m_freem(m); 645546f251bSChris D. Faulhaber } else { 646546f251bSChris D. Faulhaber #ifdef IPSEC 647546f251bSChris D. Faulhaber /* 648546f251bSChris D. Faulhaber * Enforce inbound IPsec SPD. 649546f251bSChris D. Faulhaber */ 650546f251bSChris D. Faulhaber if (ipsec4_in_reject(m, NULL)) { 651546f251bSChris D. Faulhaber ipsecstat.in_polvio++; 652546f251bSChris D. Faulhaber goto bad; 653546f251bSChris D. Faulhaber } 654546f251bSChris D. Faulhaber #endif /* IPSEC */ 655df8bae1dSRodney W. Grimes ip_forward(m, 0); 656546f251bSChris D. Faulhaber } 657ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD 658ed1ff184SJulian Elischer ip_fw_fwd_addr = NULL; 659ed1ff184SJulian Elischer #endif 660c67b1d17SGarrett Wollman return; 661df8bae1dSRodney W. Grimes 662df8bae1dSRodney W. Grimes ours: 663d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 664d0ebc0d2SYaroslav Tykhiy /* 665d0ebc0d2SYaroslav Tykhiy * IPSTEALTH: Process non-routing options only 666d0ebc0d2SYaroslav Tykhiy * if the packet is destined for us. 667d0ebc0d2SYaroslav Tykhiy */ 668d0ebc0d2SYaroslav Tykhiy if (ipstealth && hlen > sizeof (struct ip) && ip_dooptions(m, 1)) { 669d0ebc0d2SYaroslav Tykhiy #ifdef IPFIREWALL_FORWARD 670d0ebc0d2SYaroslav Tykhiy ip_fw_fwd_addr = NULL; 671d0ebc0d2SYaroslav Tykhiy #endif 672d0ebc0d2SYaroslav Tykhiy return; 673d0ebc0d2SYaroslav Tykhiy } 674d0ebc0d2SYaroslav Tykhiy #endif /* IPSTEALTH */ 675d0ebc0d2SYaroslav Tykhiy 6765da9f8faSJosef Karthauser /* Count the packet in the ip address stats */ 6775da9f8faSJosef Karthauser if (ia != NULL) { 6785da9f8faSJosef Karthauser ia->ia_ifa.if_ipackets++; 6795da9f8faSJosef Karthauser ia->ia_ifa.if_ibytes += m->m_pkthdr.len; 6805da9f8faSJosef Karthauser } 681100ba1a6SJordan K. Hubbard 68263f8d699SJordan K. Hubbard /* 683df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 684df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 685df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 686df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 687df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 688df8bae1dSRodney W. Grimes */ 689b6ea1aa5SRuslan Ermilov if (ip->ip_off & (IP_MF | IP_OFFMASK)) { 6906a800098SYoshinobu Inoue 691194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 692df8bae1dSRodney W. Grimes /* 693df8bae1dSRodney W. Grimes * Look for queue of fragments 694df8bae1dSRodney W. Grimes * of this datagram. 695df8bae1dSRodney W. Grimes */ 696462b86feSPoul-Henning Kamp TAILQ_FOREACH(fp, &ipq[sum], ipq_list) 697df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 698df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 699df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 700df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 701df8bae1dSRodney W. Grimes goto found; 702df8bae1dSRodney W. Grimes 703194a213eSAndrey A. Chernov fp = 0; 704194a213eSAndrey A. Chernov 705194a213eSAndrey A. Chernov /* check if there's a place for the new queue */ 706194a213eSAndrey A. Chernov if (nipq > maxnipq) { 707194a213eSAndrey A. Chernov /* 708194a213eSAndrey A. Chernov * drop something from the tail of the current queue 709194a213eSAndrey A. Chernov * before proceeding further 710194a213eSAndrey A. Chernov */ 711462b86feSPoul-Henning Kamp struct ipq *q = TAILQ_LAST(&ipq[sum], ipqhead); 712462b86feSPoul-Henning Kamp if (q == NULL) { /* gak */ 713194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 714462b86feSPoul-Henning Kamp struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead); 715462b86feSPoul-Henning Kamp if (r) { 716462b86feSPoul-Henning Kamp ip_freef(&ipq[i], r); 717194a213eSAndrey A. Chernov break; 718194a213eSAndrey A. Chernov } 719194a213eSAndrey A. Chernov } 720194a213eSAndrey A. Chernov } else 721462b86feSPoul-Henning Kamp ip_freef(&ipq[sum], q); 722194a213eSAndrey A. Chernov } 723194a213eSAndrey A. Chernov found: 724df8bae1dSRodney W. Grimes /* 725df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 726df8bae1dSRodney W. Grimes * convert offset of this to bytes. 727df8bae1dSRodney W. Grimes */ 728df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 729b6ea1aa5SRuslan Ermilov if (ip->ip_off & IP_MF) { 7306effc713SDoug Rabson /* 7316effc713SDoug Rabson * Make sure that fragments have a data length 7326effc713SDoug Rabson * that's a non-zero multiple of 8 bytes. 7336effc713SDoug Rabson */ 7346effc713SDoug Rabson if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { 7356effc713SDoug Rabson ipstat.ips_toosmall++; /* XXX */ 7366effc713SDoug Rabson goto bad; 7376effc713SDoug Rabson } 7386effc713SDoug Rabson m->m_flags |= M_FRAG; 7396effc713SDoug Rabson } 740df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 741df8bae1dSRodney W. Grimes 742df8bae1dSRodney W. Grimes /* 743b6ea1aa5SRuslan Ermilov * Attempt reassembly; if it succeeds, proceed. 744df8bae1dSRodney W. Grimes */ 745df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 746487bdb38SRuslan Ermilov m->m_pkthdr.header = ip; 7478948e4baSArchie Cobbs #ifdef IPDIVERT 7486a800098SYoshinobu Inoue m = ip_reass(m, 749462b86feSPoul-Henning Kamp &ipq[sum], fp, &divert_info, &divert_cookie); 7508948e4baSArchie Cobbs #else 751462b86feSPoul-Henning Kamp m = ip_reass(m, &ipq[sum], fp); 7528948e4baSArchie Cobbs #endif 7536a800098SYoshinobu Inoue if (m == 0) { 754f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 755f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 756f9e354dfSJulian Elischer #endif 757c67b1d17SGarrett Wollman return; 758f9e354dfSJulian Elischer } 759df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 7606a800098SYoshinobu Inoue ip = mtod(m, struct ip *); 7617e2df452SRuslan Ermilov /* Get the header length of the reassembled packet */ 7627e2df452SRuslan Ermilov hlen = IP_VHL_HL(ip->ip_vhl) << 2; 763af782f1cSBrian Somers #ifdef IPDIVERT 7648948e4baSArchie Cobbs /* Restore original checksum before diverting packet */ 7658948e4baSArchie Cobbs if (divert_info != 0) { 766af782f1cSBrian Somers ip->ip_len += hlen; 767fd8e4ebcSMike Barcroft ip->ip_len = htons(ip->ip_len); 768fd8e4ebcSMike Barcroft ip->ip_off = htons(ip->ip_off); 769af782f1cSBrian Somers ip->ip_sum = 0; 77060123168SRuslan Ermilov if (hlen == sizeof(struct ip)) 771af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 77260123168SRuslan Ermilov else 77360123168SRuslan Ermilov ip->ip_sum = in_cksum(m, hlen); 774fd8e4ebcSMike Barcroft ip->ip_off = ntohs(ip->ip_off); 775fd8e4ebcSMike Barcroft ip->ip_len = ntohs(ip->ip_len); 776af782f1cSBrian Somers ip->ip_len -= hlen; 777af782f1cSBrian Somers } 778af782f1cSBrian Somers #endif 779df8bae1dSRodney W. Grimes } else 780df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 781df8bae1dSRodney W. Grimes 78293e0e116SJulian Elischer #ifdef IPDIVERT 78393e0e116SJulian Elischer /* 7848948e4baSArchie Cobbs * Divert or tee packet to the divert protocol if required. 7858948e4baSArchie Cobbs * 7868948e4baSArchie Cobbs * If divert_info is zero then cookie should be too, so we shouldn't 7878948e4baSArchie Cobbs * need to clear them here. Assume divert_packet() does so also. 78893e0e116SJulian Elischer */ 7898948e4baSArchie Cobbs if (divert_info != 0) { 7908948e4baSArchie Cobbs struct mbuf *clone = NULL; 7918948e4baSArchie Cobbs 7928948e4baSArchie Cobbs /* Clone packet if we're doing a 'tee' */ 7938948e4baSArchie Cobbs if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0) 7948948e4baSArchie Cobbs clone = m_dup(m, M_DONTWAIT); 7958948e4baSArchie Cobbs 7968948e4baSArchie Cobbs /* Restore packet header fields to original values */ 7978948e4baSArchie Cobbs ip->ip_len += hlen; 798fd8e4ebcSMike Barcroft ip->ip_len = htons(ip->ip_len); 799fd8e4ebcSMike Barcroft ip->ip_off = htons(ip->ip_off); 8008948e4baSArchie Cobbs 8018948e4baSArchie Cobbs /* Deliver packet to divert input routine */ 8028948e4baSArchie Cobbs ip_divert_cookie = divert_cookie; 8038948e4baSArchie Cobbs divert_packet(m, 1, divert_info & 0xffff); 804e4676ba6SJulian Elischer ipstat.ips_delivered++; 8058948e4baSArchie Cobbs 8068948e4baSArchie Cobbs /* If 'tee', continue with original packet */ 8078948e4baSArchie Cobbs if (clone == NULL) 80893e0e116SJulian Elischer return; 8098948e4baSArchie Cobbs m = clone; 8108948e4baSArchie Cobbs ip = mtod(m, struct ip *); 81156962689SCrist J. Clark ip->ip_len += hlen; 81256962689SCrist J. Clark divert_info = 0; 81356962689SCrist J. Clark goto pass; 81493e0e116SJulian Elischer } 81593e0e116SJulian Elischer #endif 81693e0e116SJulian Elischer 81733841545SHajimu UMEMOTO #ifdef IPSEC 81833841545SHajimu UMEMOTO /* 81933841545SHajimu UMEMOTO * enforce IPsec policy checking if we are seeing last header. 82033841545SHajimu UMEMOTO * note that we do not visit this with protocols with pcb layer 82133841545SHajimu UMEMOTO * code - like udp/tcp/raw ip. 82233841545SHajimu UMEMOTO */ 82333841545SHajimu UMEMOTO if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && 82433841545SHajimu UMEMOTO ipsec4_in_reject(m, NULL)) { 82533841545SHajimu UMEMOTO ipsecstat.in_polvio++; 82633841545SHajimu UMEMOTO goto bad; 82733841545SHajimu UMEMOTO } 82833841545SHajimu UMEMOTO #endif 82933841545SHajimu UMEMOTO 830df8bae1dSRodney W. Grimes /* 831df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 832df8bae1dSRodney W. Grimes */ 833df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 8346a800098SYoshinobu Inoue { 835f0ffb944SJulian Elischer int off = hlen; 8366a800098SYoshinobu Inoue 837f0ffb944SJulian Elischer (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off); 838f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 839f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; /* tcp needed it */ 840f9e354dfSJulian Elischer #endif 841c67b1d17SGarrett Wollman return; 8426a800098SYoshinobu Inoue } 843df8bae1dSRodney W. Grimes bad: 844f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 845f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 846f9e354dfSJulian Elischer #endif 847df8bae1dSRodney W. Grimes m_freem(m); 848c67b1d17SGarrett Wollman } 849c67b1d17SGarrett Wollman 850c67b1d17SGarrett Wollman /* 851c67b1d17SGarrett Wollman * IP software interrupt routine - to go away sometime soon 852c67b1d17SGarrett Wollman */ 853c67b1d17SGarrett Wollman static void 854c67b1d17SGarrett Wollman ipintr(void) 855c67b1d17SGarrett Wollman { 856c67b1d17SGarrett Wollman struct mbuf *m; 857c67b1d17SGarrett Wollman 858c67b1d17SGarrett Wollman while (1) { 859c67b1d17SGarrett Wollman IF_DEQUEUE(&ipintrq, m); 860c67b1d17SGarrett Wollman if (m == 0) 861c67b1d17SGarrett Wollman return; 862c67b1d17SGarrett Wollman ip_input(m); 863c67b1d17SGarrett Wollman } 864df8bae1dSRodney W. Grimes } 865df8bae1dSRodney W. Grimes 866df8bae1dSRodney W. Grimes /* 8678948e4baSArchie Cobbs * Take incoming datagram fragment and try to reassemble it into 8688948e4baSArchie Cobbs * whole datagram. If a chain for reassembly of this datagram already 8698948e4baSArchie Cobbs * exists, then it is given as fp; otherwise have to make a chain. 8708948e4baSArchie Cobbs * 8718948e4baSArchie Cobbs * When IPDIVERT enabled, keep additional state with each packet that 8728948e4baSArchie Cobbs * tells us if we need to divert or tee the packet we're building. 873df8bae1dSRodney W. Grimes */ 8748948e4baSArchie Cobbs 8756a800098SYoshinobu Inoue static struct mbuf * 8768948e4baSArchie Cobbs #ifdef IPDIVERT 877462b86feSPoul-Henning Kamp ip_reass(m, head, fp, divinfo, divcookie) 8788948e4baSArchie Cobbs #else 879462b86feSPoul-Henning Kamp ip_reass(m, head, fp) 8808948e4baSArchie Cobbs #endif 881462b86feSPoul-Henning Kamp struct mbuf *m; 882462b86feSPoul-Henning Kamp struct ipqhead *head; 883462b86feSPoul-Henning Kamp struct ipq *fp; 8848948e4baSArchie Cobbs #ifdef IPDIVERT 8858948e4baSArchie Cobbs u_int32_t *divinfo; 8868948e4baSArchie Cobbs u_int16_t *divcookie; 8878948e4baSArchie Cobbs #endif 888df8bae1dSRodney W. Grimes { 8896effc713SDoug Rabson struct ip *ip = mtod(m, struct ip *); 890b6ea1aa5SRuslan Ermilov register struct mbuf *p, *q, *nq; 891df8bae1dSRodney W. Grimes struct mbuf *t; 8926effc713SDoug Rabson int hlen = IP_VHL_HL(ip->ip_vhl) << 2; 893df8bae1dSRodney W. Grimes int i, next; 894df8bae1dSRodney W. Grimes 895df8bae1dSRodney W. Grimes /* 896df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 897df8bae1dSRodney W. Grimes * would confuse code below. 898df8bae1dSRodney W. Grimes */ 899df8bae1dSRodney W. Grimes m->m_data += hlen; 900df8bae1dSRodney W. Grimes m->m_len -= hlen; 901df8bae1dSRodney W. Grimes 902df8bae1dSRodney W. Grimes /* 903df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 904df8bae1dSRodney W. Grimes */ 905df8bae1dSRodney W. Grimes if (fp == 0) { 906690a6055SJesper Skriver /* 907690a6055SJesper Skriver * Enforce upper bound on number of fragmented packets 908690a6055SJesper Skriver * for which we attempt reassembly; 909690a6055SJesper Skriver * If maxfrag is 0, never accept fragments. 910690a6055SJesper Skriver * If maxfrag is -1, accept all fragments without limitation. 911690a6055SJesper Skriver */ 912690a6055SJesper Skriver if ((ip_maxfragpackets >= 0) && (ip_nfragpackets >= ip_maxfragpackets)) 913690a6055SJesper Skriver goto dropfrag; 914690a6055SJesper Skriver ip_nfragpackets++; 915df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 916df8bae1dSRodney W. Grimes goto dropfrag; 917df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 918462b86feSPoul-Henning Kamp TAILQ_INSERT_HEAD(head, fp, ipq_list); 919194a213eSAndrey A. Chernov nipq++; 920df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 921df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 922df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 9236effc713SDoug Rabson fp->ipq_src = ip->ip_src; 9246effc713SDoug Rabson fp->ipq_dst = ip->ip_dst; 925af38c68cSLuigi Rizzo fp->ipq_frags = m; 926af38c68cSLuigi Rizzo m->m_nextpkt = NULL; 92793e0e116SJulian Elischer #ifdef IPDIVERT 9288948e4baSArchie Cobbs fp->ipq_div_info = 0; 929bb60f459SJulian Elischer fp->ipq_div_cookie = 0; 93093e0e116SJulian Elischer #endif 931af38c68cSLuigi Rizzo goto inserted; 932df8bae1dSRodney W. Grimes } 933df8bae1dSRodney W. Grimes 9346effc713SDoug Rabson #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) 9356effc713SDoug Rabson 936df8bae1dSRodney W. Grimes /* 937df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 938df8bae1dSRodney W. Grimes */ 9396effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) 9406effc713SDoug Rabson if (GETIP(q)->ip_off > ip->ip_off) 941df8bae1dSRodney W. Grimes break; 942df8bae1dSRodney W. Grimes 943df8bae1dSRodney W. Grimes /* 944df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 945df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 946af38c68cSLuigi Rizzo * segment. If it provides all of our data, drop us, otherwise 947af38c68cSLuigi Rizzo * stick new segment in the proper place. 948db4f9cc7SJonathan Lemon * 949db4f9cc7SJonathan Lemon * If some of the data is dropped from the the preceding 950db4f9cc7SJonathan Lemon * segment, then it's checksum is invalidated. 951df8bae1dSRodney W. Grimes */ 9526effc713SDoug Rabson if (p) { 9536effc713SDoug Rabson i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; 954df8bae1dSRodney W. Grimes if (i > 0) { 955df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 956df8bae1dSRodney W. Grimes goto dropfrag; 9576a800098SYoshinobu Inoue m_adj(m, i); 958db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags = 0; 959df8bae1dSRodney W. Grimes ip->ip_off += i; 960df8bae1dSRodney W. Grimes ip->ip_len -= i; 961df8bae1dSRodney W. Grimes } 962af38c68cSLuigi Rizzo m->m_nextpkt = p->m_nextpkt; 963af38c68cSLuigi Rizzo p->m_nextpkt = m; 964af38c68cSLuigi Rizzo } else { 965af38c68cSLuigi Rizzo m->m_nextpkt = fp->ipq_frags; 966af38c68cSLuigi Rizzo fp->ipq_frags = m; 967df8bae1dSRodney W. Grimes } 968df8bae1dSRodney W. Grimes 969df8bae1dSRodney W. Grimes /* 970df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 971df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 972df8bae1dSRodney W. Grimes */ 9736effc713SDoug Rabson for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; 974af38c68cSLuigi Rizzo q = nq) { 9756effc713SDoug Rabson i = (ip->ip_off + ip->ip_len) - 9766effc713SDoug Rabson GETIP(q)->ip_off; 9776effc713SDoug Rabson if (i < GETIP(q)->ip_len) { 9786effc713SDoug Rabson GETIP(q)->ip_len -= i; 9796effc713SDoug Rabson GETIP(q)->ip_off += i; 9806effc713SDoug Rabson m_adj(q, i); 981db4f9cc7SJonathan Lemon q->m_pkthdr.csum_flags = 0; 982df8bae1dSRodney W. Grimes break; 983df8bae1dSRodney W. Grimes } 9846effc713SDoug Rabson nq = q->m_nextpkt; 985af38c68cSLuigi Rizzo m->m_nextpkt = nq; 9866effc713SDoug Rabson m_freem(q); 987df8bae1dSRodney W. Grimes } 988df8bae1dSRodney W. Grimes 989af38c68cSLuigi Rizzo inserted: 99093e0e116SJulian Elischer 99193e0e116SJulian Elischer #ifdef IPDIVERT 99293e0e116SJulian Elischer /* 9938948e4baSArchie Cobbs * Transfer firewall instructions to the fragment structure. 9948948e4baSArchie Cobbs * Any fragment diverting causes the whole packet to divert. 99593e0e116SJulian Elischer */ 9968948e4baSArchie Cobbs fp->ipq_div_info = *divinfo; 9978948e4baSArchie Cobbs fp->ipq_div_cookie = *divcookie; 9988948e4baSArchie Cobbs *divinfo = 0; 9998948e4baSArchie Cobbs *divcookie = 0; 100093e0e116SJulian Elischer #endif 100193e0e116SJulian Elischer 1002df8bae1dSRodney W. Grimes /* 1003af38c68cSLuigi Rizzo * Check for complete reassembly. 1004df8bae1dSRodney W. Grimes */ 10056effc713SDoug Rabson next = 0; 10066effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { 10076effc713SDoug Rabson if (GETIP(q)->ip_off != next) 10086effc713SDoug Rabson return (0); 10096effc713SDoug Rabson next += GETIP(q)->ip_len; 10106effc713SDoug Rabson } 10116effc713SDoug Rabson /* Make sure the last packet didn't have the IP_MF flag */ 10126effc713SDoug Rabson if (p->m_flags & M_FRAG) 1013df8bae1dSRodney W. Grimes return (0); 1014df8bae1dSRodney W. Grimes 1015df8bae1dSRodney W. Grimes /* 1016430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 1017430d30d8SBill Fenner */ 10186effc713SDoug Rabson q = fp->ipq_frags; 10196effc713SDoug Rabson ip = GETIP(q); 10206effc713SDoug Rabson if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) { 1021430d30d8SBill Fenner ipstat.ips_toolong++; 1022462b86feSPoul-Henning Kamp ip_freef(head, fp); 1023430d30d8SBill Fenner return (0); 1024430d30d8SBill Fenner } 1025430d30d8SBill Fenner 1026430d30d8SBill Fenner /* 1027430d30d8SBill Fenner * Concatenate fragments. 1028df8bae1dSRodney W. Grimes */ 10296effc713SDoug Rabson m = q; 1030df8bae1dSRodney W. Grimes t = m->m_next; 1031df8bae1dSRodney W. Grimes m->m_next = 0; 1032df8bae1dSRodney W. Grimes m_cat(m, t); 10336effc713SDoug Rabson nq = q->m_nextpkt; 1034945aa40dSDoug Rabson q->m_nextpkt = 0; 10356effc713SDoug Rabson for (q = nq; q != NULL; q = nq) { 10366effc713SDoug Rabson nq = q->m_nextpkt; 1037945aa40dSDoug Rabson q->m_nextpkt = NULL; 1038db4f9cc7SJonathan Lemon m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags; 1039db4f9cc7SJonathan Lemon m->m_pkthdr.csum_data += q->m_pkthdr.csum_data; 1040a8db1d93SJonathan Lemon m_cat(m, q); 1041df8bae1dSRodney W. Grimes } 1042df8bae1dSRodney W. Grimes 104393e0e116SJulian Elischer #ifdef IPDIVERT 104493e0e116SJulian Elischer /* 10458948e4baSArchie Cobbs * Extract firewall instructions from the fragment structure. 104693e0e116SJulian Elischer */ 10478948e4baSArchie Cobbs *divinfo = fp->ipq_div_info; 10488948e4baSArchie Cobbs *divcookie = fp->ipq_div_cookie; 104993e0e116SJulian Elischer #endif 105093e0e116SJulian Elischer 1051df8bae1dSRodney W. Grimes /* 1052df8bae1dSRodney W. Grimes * Create header for new ip packet by 1053df8bae1dSRodney W. Grimes * modifying header of first packet; 1054df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 1055df8bae1dSRodney W. Grimes * Make header visible. 1056df8bae1dSRodney W. Grimes */ 1057df8bae1dSRodney W. Grimes ip->ip_len = next; 10586effc713SDoug Rabson ip->ip_src = fp->ipq_src; 10596effc713SDoug Rabson ip->ip_dst = fp->ipq_dst; 1060462b86feSPoul-Henning Kamp TAILQ_REMOVE(head, fp, ipq_list); 1061194a213eSAndrey A. Chernov nipq--; 1062df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1063690a6055SJesper Skriver ip_nfragpackets--; 10646effc713SDoug Rabson m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2); 10656effc713SDoug Rabson m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2); 1066df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 1067df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 1068df8bae1dSRodney W. Grimes register int plen = 0; 10696a800098SYoshinobu Inoue for (t = m; t; t = t->m_next) 10706a800098SYoshinobu Inoue plen += t->m_len; 10716a800098SYoshinobu Inoue m->m_pkthdr.len = plen; 1072df8bae1dSRodney W. Grimes } 10736a800098SYoshinobu Inoue return (m); 1074df8bae1dSRodney W. Grimes 1075df8bae1dSRodney W. Grimes dropfrag: 1076efe39c6aSJulian Elischer #ifdef IPDIVERT 10778948e4baSArchie Cobbs *divinfo = 0; 10788948e4baSArchie Cobbs *divcookie = 0; 1079efe39c6aSJulian Elischer #endif 1080df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 1081df8bae1dSRodney W. Grimes m_freem(m); 1082df8bae1dSRodney W. Grimes return (0); 10836effc713SDoug Rabson 10846effc713SDoug Rabson #undef GETIP 1085df8bae1dSRodney W. Grimes } 1086df8bae1dSRodney W. Grimes 1087df8bae1dSRodney W. Grimes /* 1088df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 1089df8bae1dSRodney W. Grimes * associated datagrams. 1090df8bae1dSRodney W. Grimes */ 10910312fbe9SPoul-Henning Kamp static void 1092462b86feSPoul-Henning Kamp ip_freef(fhp, fp) 1093462b86feSPoul-Henning Kamp struct ipqhead *fhp; 1094df8bae1dSRodney W. Grimes struct ipq *fp; 1095df8bae1dSRodney W. Grimes { 10966effc713SDoug Rabson register struct mbuf *q; 1097df8bae1dSRodney W. Grimes 10986effc713SDoug Rabson while (fp->ipq_frags) { 10996effc713SDoug Rabson q = fp->ipq_frags; 11006effc713SDoug Rabson fp->ipq_frags = q->m_nextpkt; 11016effc713SDoug Rabson m_freem(q); 1102df8bae1dSRodney W. Grimes } 1103462b86feSPoul-Henning Kamp TAILQ_REMOVE(fhp, fp, ipq_list); 1104df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 1105690a6055SJesper Skriver ip_nfragpackets--; 1106194a213eSAndrey A. Chernov nipq--; 1107df8bae1dSRodney W. Grimes } 1108df8bae1dSRodney W. Grimes 1109df8bae1dSRodney W. Grimes /* 1110df8bae1dSRodney W. Grimes * IP timer processing; 1111df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 1112df8bae1dSRodney W. Grimes * queue, discard it. 1113df8bae1dSRodney W. Grimes */ 1114df8bae1dSRodney W. Grimes void 1115df8bae1dSRodney W. Grimes ip_slowtimo() 1116df8bae1dSRodney W. Grimes { 1117df8bae1dSRodney W. Grimes register struct ipq *fp; 1118df8bae1dSRodney W. Grimes int s = splnet(); 1119194a213eSAndrey A. Chernov int i; 1120df8bae1dSRodney W. Grimes 1121194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1122462b86feSPoul-Henning Kamp for(fp = TAILQ_FIRST(&ipq[i]); fp;) { 1123462b86feSPoul-Henning Kamp struct ipq *fpp; 1124462b86feSPoul-Henning Kamp 1125462b86feSPoul-Henning Kamp fpp = fp; 1126462b86feSPoul-Henning Kamp fp = TAILQ_NEXT(fp, ipq_list); 1127462b86feSPoul-Henning Kamp if(--fpp->ipq_ttl == 0) { 1128df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 1129462b86feSPoul-Henning Kamp ip_freef(&ipq[i], fpp); 1130df8bae1dSRodney W. Grimes } 1131df8bae1dSRodney W. Grimes } 1132194a213eSAndrey A. Chernov } 1133690a6055SJesper Skriver /* 1134690a6055SJesper Skriver * If we are over the maximum number of fragments 1135690a6055SJesper Skriver * (due to the limit being lowered), drain off 1136690a6055SJesper Skriver * enough to get down to the new limit. 1137690a6055SJesper Skriver */ 1138690a6055SJesper Skriver for (i = 0; i < IPREASS_NHASH; i++) { 1139690a6055SJesper Skriver if (ip_maxfragpackets >= 0) { 1140690a6055SJesper Skriver while (ip_nfragpackets > ip_maxfragpackets && 1141690a6055SJesper Skriver !TAILQ_EMPTY(&ipq[i])) { 1142690a6055SJesper Skriver ipstat.ips_fragdropped++; 1143690a6055SJesper Skriver ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); 1144690a6055SJesper Skriver } 1145690a6055SJesper Skriver } 1146690a6055SJesper Skriver } 11471f91d8c5SDavid Greenman ipflow_slowtimo(); 1148df8bae1dSRodney W. Grimes splx(s); 1149df8bae1dSRodney W. Grimes } 1150df8bae1dSRodney W. Grimes 1151df8bae1dSRodney W. Grimes /* 1152df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 1153df8bae1dSRodney W. Grimes */ 1154df8bae1dSRodney W. Grimes void 1155df8bae1dSRodney W. Grimes ip_drain() 1156df8bae1dSRodney W. Grimes { 1157194a213eSAndrey A. Chernov int i; 1158ce29ab3aSGarrett Wollman 1159194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 1160462b86feSPoul-Henning Kamp while(!TAILQ_EMPTY(&ipq[i])) { 1161194a213eSAndrey A. Chernov ipstat.ips_fragdropped++; 1162462b86feSPoul-Henning Kamp ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); 1163194a213eSAndrey A. Chernov } 1164194a213eSAndrey A. Chernov } 1165ce29ab3aSGarrett Wollman in_rtqdrain(); 1166df8bae1dSRodney W. Grimes } 1167df8bae1dSRodney W. Grimes 1168df8bae1dSRodney W. Grimes /* 1169df8bae1dSRodney W. Grimes * Do option processing on a datagram, 1170df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 1171df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 1172d0ebc0d2SYaroslav Tykhiy * The pass argument is used when operating in the IPSTEALTH 1173d0ebc0d2SYaroslav Tykhiy * mode to tell what options to process: 1174d0ebc0d2SYaroslav Tykhiy * [LS]SRR (pass 0) or the others (pass 1). 1175d0ebc0d2SYaroslav Tykhiy * The reason for as many as two passes is that when doing IPSTEALTH, 1176d0ebc0d2SYaroslav Tykhiy * non-routing options should be processed only if the packet is for us. 1177df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 1178df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 1179df8bae1dSRodney W. Grimes */ 11800312fbe9SPoul-Henning Kamp static int 1181d0ebc0d2SYaroslav Tykhiy ip_dooptions(m, pass) 1182df8bae1dSRodney W. Grimes struct mbuf *m; 1183d0ebc0d2SYaroslav Tykhiy int pass; 1184df8bae1dSRodney W. Grimes { 1185df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1186df8bae1dSRodney W. Grimes register u_char *cp; 1187df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 1188df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 1189df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 1190df8bae1dSRodney W. Grimes n_time ntime; 1191df8bae1dSRodney W. Grimes 1192df8bae1dSRodney W. Grimes dst = ip->ip_dst; 1193df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 119458938916SGarrett Wollman cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1195df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 1196df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 1197df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 1198df8bae1dSRodney W. Grimes break; 1199df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 1200df8bae1dSRodney W. Grimes optlen = 1; 1201df8bae1dSRodney W. Grimes else { 1202fdcb8debSJun-ichiro itojun Hagino if (cnt < IPOPT_OLEN + sizeof(*cp)) { 1203fdcb8debSJun-ichiro itojun Hagino code = &cp[IPOPT_OLEN] - (u_char *)ip; 1204fdcb8debSJun-ichiro itojun Hagino goto bad; 1205fdcb8debSJun-ichiro itojun Hagino } 1206df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 1207707d00a3SJonathan Lemon if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) { 1208df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 1209df8bae1dSRodney W. Grimes goto bad; 1210df8bae1dSRodney W. Grimes } 1211df8bae1dSRodney W. Grimes } 1212df8bae1dSRodney W. Grimes switch (opt) { 1213df8bae1dSRodney W. Grimes 1214df8bae1dSRodney W. Grimes default: 1215df8bae1dSRodney W. Grimes break; 1216df8bae1dSRodney W. Grimes 1217df8bae1dSRodney W. Grimes /* 1218df8bae1dSRodney W. Grimes * Source routing with record. 1219df8bae1dSRodney W. Grimes * Find interface with current destination address. 1220df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 1221df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 1222df8bae1dSRodney W. Grimes * Record interface address and bring up next address 1223df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 1224df8bae1dSRodney W. Grimes * address is on directly accessible net. 1225df8bae1dSRodney W. Grimes */ 1226df8bae1dSRodney W. Grimes case IPOPT_LSRR: 1227df8bae1dSRodney W. Grimes case IPOPT_SSRR: 1228d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1229d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass > 0) 1230d0ebc0d2SYaroslav Tykhiy break; 1231d0ebc0d2SYaroslav Tykhiy #endif 123233841545SHajimu UMEMOTO if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 123333841545SHajimu UMEMOTO code = &cp[IPOPT_OLEN] - (u_char *)ip; 123433841545SHajimu UMEMOTO goto bad; 123533841545SHajimu UMEMOTO } 1236df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1237df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1238df8bae1dSRodney W. Grimes goto bad; 1239df8bae1dSRodney W. Grimes } 1240df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 1241df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 1242df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 1243df8bae1dSRodney W. Grimes if (ia == 0) { 1244df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1245df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1246df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1247df8bae1dSRodney W. Grimes goto bad; 1248df8bae1dSRodney W. Grimes } 1249bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1250bc189bf8SGuido van Rooij goto nosourcerouting; 1251df8bae1dSRodney W. Grimes /* 1252df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1253df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1254df8bae1dSRodney W. Grimes */ 1255df8bae1dSRodney W. Grimes break; 1256df8bae1dSRodney W. Grimes } 1257df8bae1dSRodney W. Grimes off--; /* 0 origin */ 12585d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) { 1259df8bae1dSRodney W. Grimes /* 1260df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1261df8bae1dSRodney W. Grimes */ 12624fce5804SGuido van Rooij if (!ip_acceptsourceroute) 12634fce5804SGuido van Rooij goto nosourcerouting; 1264df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 1265df8bae1dSRodney W. Grimes break; 1266df8bae1dSRodney W. Grimes } 1267d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1268d0ebc0d2SYaroslav Tykhiy if (ipstealth) 1269d0ebc0d2SYaroslav Tykhiy goto dropit; 1270d0ebc0d2SYaroslav Tykhiy #endif 12711025071fSGarrett Wollman if (!ip_dosourceroute) { 12720af8d3ecSDavid Greenman if (ipforwarding) { 12730af8d3ecSDavid Greenman char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 12740af8d3ecSDavid Greenman /* 12750af8d3ecSDavid Greenman * Acting as a router, so generate ICMP 12760af8d3ecSDavid Greenman */ 1277efa48587SGuido van Rooij nosourcerouting: 1278bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 12791025071fSGarrett Wollman log(LOG_WARNING, 12801025071fSGarrett Wollman "attempted source route from %s to %s\n", 12811025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 12821025071fSGarrett Wollman type = ICMP_UNREACH; 12831025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 12841025071fSGarrett Wollman goto bad; 12850af8d3ecSDavid Greenman } else { 12860af8d3ecSDavid Greenman /* 12870af8d3ecSDavid Greenman * Not acting as a router, so silently drop. 12880af8d3ecSDavid Greenman */ 1289d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1290d0ebc0d2SYaroslav Tykhiy dropit: 1291d0ebc0d2SYaroslav Tykhiy #endif 12920af8d3ecSDavid Greenman ipstat.ips_cantforward++; 12930af8d3ecSDavid Greenman m_freem(m); 12940af8d3ecSDavid Greenman return (1); 12950af8d3ecSDavid Greenman } 12961025071fSGarrett Wollman } 12971025071fSGarrett Wollman 1298df8bae1dSRodney W. Grimes /* 1299df8bae1dSRodney W. Grimes * locate outgoing interface 1300df8bae1dSRodney W. Grimes */ 130194a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1302df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 13031025071fSGarrett Wollman 1304df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1305df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1306df8bae1dSRodney W. Grimes #define SA struct sockaddr * 1307df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 1308df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1309df8bae1dSRodney W. Grimes } else 1310bd714208SRuslan Ermilov ia = ip_rtaddr(ipaddr.sin_addr, &ipforward_rt); 1311df8bae1dSRodney W. Grimes if (ia == 0) { 1312df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1313df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1314df8bae1dSRodney W. Grimes goto bad; 1315df8bae1dSRodney W. Grimes } 1316df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 131794a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 131894a5d9b6SDavid Greenman sizeof(struct in_addr)); 1319df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1320df8bae1dSRodney W. Grimes /* 1321df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1322df8bae1dSRodney W. Grimes */ 1323df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1324df8bae1dSRodney W. Grimes break; 1325df8bae1dSRodney W. Grimes 1326df8bae1dSRodney W. Grimes case IPOPT_RR: 1327d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1328d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass == 0) 1329d0ebc0d2SYaroslav Tykhiy break; 1330d0ebc0d2SYaroslav Tykhiy #endif 1331707d00a3SJonathan Lemon if (optlen < IPOPT_OFFSET + sizeof(*cp)) { 1332707d00a3SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1333707d00a3SJonathan Lemon goto bad; 1334707d00a3SJonathan Lemon } 1335df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1336df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1337df8bae1dSRodney W. Grimes goto bad; 1338df8bae1dSRodney W. Grimes } 1339df8bae1dSRodney W. Grimes /* 1340df8bae1dSRodney W. Grimes * If no space remains, ignore. 1341df8bae1dSRodney W. Grimes */ 1342df8bae1dSRodney W. Grimes off--; /* 0 origin */ 13435d5d5fc0SJonathan Lemon if (off > optlen - (int)sizeof(struct in_addr)) 1344df8bae1dSRodney W. Grimes break; 134594a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1346df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1347df8bae1dSRodney W. Grimes /* 1348df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1349df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1350df8bae1dSRodney W. Grimes */ 1351df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 1352bd714208SRuslan Ermilov (ia = ip_rtaddr(ipaddr.sin_addr, 1353bd714208SRuslan Ermilov &ipforward_rt)) == 0) { 1354df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1355df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1356df8bae1dSRodney W. Grimes goto bad; 1357df8bae1dSRodney W. Grimes } 135894a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 135994a5d9b6SDavid Greenman sizeof(struct in_addr)); 1360df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1361df8bae1dSRodney W. Grimes break; 1362df8bae1dSRodney W. Grimes 1363df8bae1dSRodney W. Grimes case IPOPT_TS: 1364d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH 1365d0ebc0d2SYaroslav Tykhiy if (ipstealth && pass == 0) 1366d0ebc0d2SYaroslav Tykhiy break; 1367d0ebc0d2SYaroslav Tykhiy #endif 1368df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 136907514071SJonathan Lemon if (optlen < 4 || optlen > 40) { 137007514071SJonathan Lemon code = &cp[IPOPT_OLEN] - (u_char *)ip; 1371df8bae1dSRodney W. Grimes goto bad; 137233841545SHajimu UMEMOTO } 137307514071SJonathan Lemon if ((off = cp[IPOPT_OFFSET]) < 5) { 137407514071SJonathan Lemon code = &cp[IPOPT_OLEN] - (u_char *)ip; 137533841545SHajimu UMEMOTO goto bad; 137633841545SHajimu UMEMOTO } 137707514071SJonathan Lemon if (off > optlen - (int)sizeof(int32_t)) { 137807514071SJonathan Lemon cp[IPOPT_OFFSET + 1] += (1 << 4); 137907514071SJonathan Lemon if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) { 138007514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1381df8bae1dSRodney W. Grimes goto bad; 138233841545SHajimu UMEMOTO } 1383df8bae1dSRodney W. Grimes break; 1384df8bae1dSRodney W. Grimes } 138507514071SJonathan Lemon off--; /* 0 origin */ 138607514071SJonathan Lemon sin = (struct in_addr *)(cp + off); 138707514071SJonathan Lemon switch (cp[IPOPT_OFFSET + 1] & 0x0f) { 1388df8bae1dSRodney W. Grimes 1389df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1390df8bae1dSRodney W. Grimes break; 1391df8bae1dSRodney W. Grimes 1392df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 139307514071SJonathan Lemon if (off + sizeof(n_time) + 139407514071SJonathan Lemon sizeof(struct in_addr) > optlen) { 139507514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1396df8bae1dSRodney W. Grimes goto bad; 139733841545SHajimu UMEMOTO } 1398df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1399df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1400df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1401df8bae1dSRodney W. Grimes if (ia == 0) 1402df8bae1dSRodney W. Grimes continue; 140394a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 140494a5d9b6SDavid Greenman sizeof(struct in_addr)); 140507514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1406df8bae1dSRodney W. Grimes break; 1407df8bae1dSRodney W. Grimes 1408df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 140907514071SJonathan Lemon if (off + sizeof(n_time) + 141007514071SJonathan Lemon sizeof(struct in_addr) > optlen) { 141107514071SJonathan Lemon code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1412df8bae1dSRodney W. Grimes goto bad; 141333841545SHajimu UMEMOTO } 141494a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1415df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1416df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1417df8bae1dSRodney W. Grimes continue; 141807514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1419df8bae1dSRodney W. Grimes break; 1420df8bae1dSRodney W. Grimes 1421df8bae1dSRodney W. Grimes default: 142207514071SJonathan Lemon code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip; 1423df8bae1dSRodney W. Grimes goto bad; 1424df8bae1dSRodney W. Grimes } 1425df8bae1dSRodney W. Grimes ntime = iptime(); 142607514071SJonathan Lemon (void)memcpy(cp + off, &ntime, sizeof(n_time)); 142707514071SJonathan Lemon cp[IPOPT_OFFSET] += sizeof(n_time); 1428df8bae1dSRodney W. Grimes } 1429df8bae1dSRodney W. Grimes } 143047174b49SAndrey A. Chernov if (forward && ipforwarding) { 1431df8bae1dSRodney W. Grimes ip_forward(m, 1); 1432df8bae1dSRodney W. Grimes return (1); 1433df8bae1dSRodney W. Grimes } 1434df8bae1dSRodney W. Grimes return (0); 1435df8bae1dSRodney W. Grimes bad: 1436df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1437df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1438df8bae1dSRodney W. Grimes return (1); 1439df8bae1dSRodney W. Grimes } 1440df8bae1dSRodney W. Grimes 1441df8bae1dSRodney W. Grimes /* 1442df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1443df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1444df8bae1dSRodney W. Grimes */ 1445bd714208SRuslan Ermilov struct in_ifaddr * 1446bd714208SRuslan Ermilov ip_rtaddr(dst, rt) 1447df8bae1dSRodney W. Grimes struct in_addr dst; 1448bd714208SRuslan Ermilov struct route *rt; 1449df8bae1dSRodney W. Grimes { 1450df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1451df8bae1dSRodney W. Grimes 1452bd714208SRuslan Ermilov sin = (struct sockaddr_in *)&rt->ro_dst; 1453df8bae1dSRodney W. Grimes 1454bd714208SRuslan Ermilov if (rt->ro_rt == 0 || 1455bd714208SRuslan Ermilov !(rt->ro_rt->rt_flags & RTF_UP) || 14564078ffb1SRuslan Ermilov dst.s_addr != sin->sin_addr.s_addr) { 1457bd714208SRuslan Ermilov if (rt->ro_rt) { 1458bd714208SRuslan Ermilov RTFREE(rt->ro_rt); 1459bd714208SRuslan Ermilov rt->ro_rt = 0; 1460df8bae1dSRodney W. Grimes } 1461df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1462df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1463df8bae1dSRodney W. Grimes sin->sin_addr = dst; 1464df8bae1dSRodney W. Grimes 1465bd714208SRuslan Ermilov rtalloc_ign(rt, RTF_PRCLONING); 1466df8bae1dSRodney W. Grimes } 1467bd714208SRuslan Ermilov if (rt->ro_rt == 0) 1468df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 1469bd714208SRuslan Ermilov return (ifatoia(rt->ro_rt->rt_ifa)); 1470df8bae1dSRodney W. Grimes } 1471df8bae1dSRodney W. Grimes 1472df8bae1dSRodney W. Grimes /* 1473df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1474df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1475df8bae1dSRodney W. Grimes */ 1476df8bae1dSRodney W. Grimes void 1477df8bae1dSRodney W. Grimes save_rte(option, dst) 1478df8bae1dSRodney W. Grimes u_char *option; 1479df8bae1dSRodney W. Grimes struct in_addr dst; 1480df8bae1dSRodney W. Grimes { 1481df8bae1dSRodney W. Grimes unsigned olen; 1482df8bae1dSRodney W. Grimes 1483df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1484df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1485df8bae1dSRodney W. Grimes if (ipprintfs) 1486df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1487df8bae1dSRodney W. Grimes #endif 1488df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1489df8bae1dSRodney W. Grimes return; 14900453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1491df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1492df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1493df8bae1dSRodney W. Grimes } 1494df8bae1dSRodney W. Grimes 1495df8bae1dSRodney W. Grimes /* 1496df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1497df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1498df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1499df8bae1dSRodney W. Grimes */ 1500df8bae1dSRodney W. Grimes struct mbuf * 1501df8bae1dSRodney W. Grimes ip_srcroute() 1502df8bae1dSRodney W. Grimes { 1503df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1504df8bae1dSRodney W. Grimes register struct mbuf *m; 1505df8bae1dSRodney W. Grimes 1506df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1507df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1508cfe8b629SGarrett Wollman m = m_get(M_DONTWAIT, MT_HEADER); 1509df8bae1dSRodney W. Grimes if (m == 0) 1510df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1511df8bae1dSRodney W. Grimes 1512df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1513df8bae1dSRodney W. Grimes 1514df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1515df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1516df8bae1dSRodney W. Grimes OPTSIZ; 1517df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1518df8bae1dSRodney W. Grimes if (ipprintfs) 1519df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1520df8bae1dSRodney W. Grimes #endif 1521df8bae1dSRodney W. Grimes 1522df8bae1dSRodney W. Grimes /* 1523df8bae1dSRodney W. Grimes * First save first hop for return route 1524df8bae1dSRodney W. Grimes */ 1525df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1526df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1527df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1528df8bae1dSRodney W. Grimes if (ipprintfs) 1529af38c68cSLuigi Rizzo printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); 1530df8bae1dSRodney W. Grimes #endif 1531df8bae1dSRodney W. Grimes 1532df8bae1dSRodney W. Grimes /* 1533df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1534df8bae1dSRodney W. Grimes */ 1535df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1536df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 153794a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 153894a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1539df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1540df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1541df8bae1dSRodney W. Grimes #undef OPTSIZ 1542df8bae1dSRodney W. Grimes /* 1543df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1544df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1545df8bae1dSRodney W. Grimes */ 1546df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1547df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1548df8bae1dSRodney W. Grimes if (ipprintfs) 1549af38c68cSLuigi Rizzo printf(" %lx", (u_long)ntohl(q->s_addr)); 1550df8bae1dSRodney W. Grimes #endif 1551df8bae1dSRodney W. Grimes *q++ = *p--; 1552df8bae1dSRodney W. Grimes } 1553df8bae1dSRodney W. Grimes /* 1554df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1555df8bae1dSRodney W. Grimes */ 1556df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1557df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1558df8bae1dSRodney W. Grimes if (ipprintfs) 1559af38c68cSLuigi Rizzo printf(" %lx\n", (u_long)ntohl(q->s_addr)); 1560df8bae1dSRodney W. Grimes #endif 1561df8bae1dSRodney W. Grimes return (m); 1562df8bae1dSRodney W. Grimes } 1563df8bae1dSRodney W. Grimes 1564df8bae1dSRodney W. Grimes /* 1565df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1566df8bae1dSRodney W. Grimes * level protocol in the kernel. 1567df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1568df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1569df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1570df8bae1dSRodney W. Grimes */ 1571df8bae1dSRodney W. Grimes void 1572df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1573df8bae1dSRodney W. Grimes register struct mbuf *m; 1574df8bae1dSRodney W. Grimes struct mbuf *mopt; 1575df8bae1dSRodney W. Grimes { 1576df8bae1dSRodney W. Grimes register int i; 1577df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1578df8bae1dSRodney W. Grimes register caddr_t opts; 1579df8bae1dSRodney W. Grimes int olen; 1580df8bae1dSRodney W. Grimes 158158938916SGarrett Wollman olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1582df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1583df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1584df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1585df8bae1dSRodney W. Grimes m->m_len -= olen; 1586df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1587df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 158858938916SGarrett Wollman ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); 1589df8bae1dSRodney W. Grimes } 1590df8bae1dSRodney W. Grimes 1591df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1592df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1593df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1594df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1595df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1596df8bae1dSRodney W. Grimes 0, 0, 0, 0, 15973b8123b7SJesper Skriver ENOPROTOOPT, ECONNREFUSED 1598df8bae1dSRodney W. Grimes }; 1599df8bae1dSRodney W. Grimes 1600df8bae1dSRodney W. Grimes /* 1601df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1602df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1603df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1604df8bae1dSRodney W. Grimes * of codes and types. 1605df8bae1dSRodney W. Grimes * 1606df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1607df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1608df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1609df8bae1dSRodney W. Grimes * protocol deal with that. 1610df8bae1dSRodney W. Grimes * 1611df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1612df8bae1dSRodney W. Grimes * via a source route. 1613df8bae1dSRodney W. Grimes */ 16140312fbe9SPoul-Henning Kamp static void 1615df8bae1dSRodney W. Grimes ip_forward(m, srcrt) 1616df8bae1dSRodney W. Grimes struct mbuf *m; 1617df8bae1dSRodney W. Grimes int srcrt; 1618df8bae1dSRodney W. Grimes { 1619df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1620df8bae1dSRodney W. Grimes register struct rtentry *rt; 162126f9a767SRodney W. Grimes int error, type = 0, code = 0; 1622df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1623df8bae1dSRodney W. Grimes n_long dest; 16243efc3014SJulian Elischer struct in_addr pkt_dst; 1625df8bae1dSRodney W. Grimes struct ifnet *destifp; 16266a800098SYoshinobu Inoue #ifdef IPSEC 16276a800098SYoshinobu Inoue struct ifnet dummyifp; 16286a800098SYoshinobu Inoue #endif 1629df8bae1dSRodney W. Grimes 1630df8bae1dSRodney W. Grimes dest = 0; 16313efc3014SJulian Elischer /* 16323efc3014SJulian Elischer * Cache the destination address of the packet; this may be 16333efc3014SJulian Elischer * changed by use of 'ipfw fwd'. 16343efc3014SJulian Elischer */ 16353efc3014SJulian Elischer pkt_dst = ip_fw_fwd_addr == NULL ? 16363efc3014SJulian Elischer ip->ip_dst : ip_fw_fwd_addr->sin_addr; 16373efc3014SJulian Elischer 1638df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1639df8bae1dSRodney W. Grimes if (ipprintfs) 164061ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 16413efc3014SJulian Elischer (u_long)ip->ip_src.s_addr, (u_long)pkt_dst.s_addr, 1642162886e2SBruce Evans ip->ip_ttl); 1643df8bae1dSRodney W. Grimes #endif 1644100ba1a6SJordan K. Hubbard 1645100ba1a6SJordan K. Hubbard 16463efc3014SJulian Elischer if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(pkt_dst) == 0) { 1647df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1648df8bae1dSRodney W. Grimes m_freem(m); 1649df8bae1dSRodney W. Grimes return; 1650df8bae1dSRodney W. Grimes } 16511b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 16521b968362SDag-Erling Smørgrav if (!ipstealth) { 16531b968362SDag-Erling Smørgrav #endif 1654df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 16551b968362SDag-Erling Smørgrav icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 16561b968362SDag-Erling Smørgrav dest, 0); 1657df8bae1dSRodney W. Grimes return; 1658df8bae1dSRodney W. Grimes } 16591b968362SDag-Erling Smørgrav #ifdef IPSTEALTH 16601b968362SDag-Erling Smørgrav } 16611b968362SDag-Erling Smørgrav #endif 1662df8bae1dSRodney W. Grimes 16633efc3014SJulian Elischer if (ip_rtaddr(pkt_dst, &ipforward_rt) == 0) { 1664df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1665df8bae1dSRodney W. Grimes return; 16664078ffb1SRuslan Ermilov } else 1667df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1668df8bae1dSRodney W. Grimes 1669df8bae1dSRodney W. Grimes /* 1670bfef7ed4SIan Dowse * Save the IP header and at most 8 bytes of the payload, 1671bfef7ed4SIan Dowse * in case we need to generate an ICMP message to the src. 1672bfef7ed4SIan Dowse * 1673bfef7ed4SIan Dowse * We don't use m_copy() because it might return a reference 1674bfef7ed4SIan Dowse * to a shared cluster. Both this function and ip_output() 1675bfef7ed4SIan Dowse * assume exclusive access to the IP header in `m', so any 1676bfef7ed4SIan Dowse * data in a cluster may change before we reach icmp_error(). 1677df8bae1dSRodney W. Grimes */ 1678bfef7ed4SIan Dowse MGET(mcopy, M_DONTWAIT, m->m_type); 1679bfef7ed4SIan Dowse if (mcopy != NULL) { 1680bfef7ed4SIan Dowse M_COPY_PKTHDR(mcopy, m); 1681bfef7ed4SIan Dowse mcopy->m_len = imin((IP_VHL_HL(ip->ip_vhl) << 2) + 8, 1682bfef7ed4SIan Dowse (int)ip->ip_len); 1683bfef7ed4SIan Dowse m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t)); 1684bfef7ed4SIan Dowse } 168504287599SRuslan Ermilov 168604287599SRuslan Ermilov #ifdef IPSTEALTH 168704287599SRuslan Ermilov if (!ipstealth) { 168804287599SRuslan Ermilov #endif 168904287599SRuslan Ermilov ip->ip_ttl -= IPTTLDEC; 169004287599SRuslan Ermilov #ifdef IPSTEALTH 169104287599SRuslan Ermilov } 169204287599SRuslan Ermilov #endif 1693df8bae1dSRodney W. Grimes 1694df8bae1dSRodney W. Grimes /* 1695df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1696df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1697df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1698df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1699df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1700df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1701df8bae1dSRodney W. Grimes */ 1702df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1703df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1704df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 17053efc3014SJulian Elischer ipsendredirects && !srcrt && !ip_fw_fwd_addr) { 1706df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1707df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1708df8bae1dSRodney W. Grimes 1709df8bae1dSRodney W. Grimes if (RTA(rt) && 1710df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1711df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1712df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1713df8bae1dSRodney W. Grimes else 17143efc3014SJulian Elischer dest = pkt_dst.s_addr; 1715df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1716df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1717df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1718df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1719df8bae1dSRodney W. Grimes if (ipprintfs) 1720df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1721df8bae1dSRodney W. Grimes #endif 1722df8bae1dSRodney W. Grimes } 1723df8bae1dSRodney W. Grimes } 1724df8bae1dSRodney W. Grimes 1725b97d15cbSGarrett Wollman error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 1726b97d15cbSGarrett Wollman IP_FORWARDING, 0); 1727df8bae1dSRodney W. Grimes if (error) 1728df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1729df8bae1dSRodney W. Grimes else { 1730df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1731df8bae1dSRodney W. Grimes if (type) 1732df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1733df8bae1dSRodney W. Grimes else { 17341f91d8c5SDavid Greenman if (mcopy) { 17351f91d8c5SDavid Greenman ipflow_create(&ipforward_rt, mcopy); 1736df8bae1dSRodney W. Grimes m_freem(mcopy); 17371f91d8c5SDavid Greenman } 1738df8bae1dSRodney W. Grimes return; 1739df8bae1dSRodney W. Grimes } 1740df8bae1dSRodney W. Grimes } 1741df8bae1dSRodney W. Grimes if (mcopy == NULL) 1742df8bae1dSRodney W. Grimes return; 1743df8bae1dSRodney W. Grimes destifp = NULL; 1744df8bae1dSRodney W. Grimes 1745df8bae1dSRodney W. Grimes switch (error) { 1746df8bae1dSRodney W. Grimes 1747df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1748df8bae1dSRodney W. Grimes /* type, code set above */ 1749df8bae1dSRodney W. Grimes break; 1750df8bae1dSRodney W. Grimes 1751df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1752df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1753df8bae1dSRodney W. Grimes case ENETDOWN: 1754df8bae1dSRodney W. Grimes case EHOSTDOWN: 1755df8bae1dSRodney W. Grimes default: 1756df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1757df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1758df8bae1dSRodney W. Grimes break; 1759df8bae1dSRodney W. Grimes 1760df8bae1dSRodney W. Grimes case EMSGSIZE: 1761df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1762df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 17636a800098SYoshinobu Inoue #ifndef IPSEC 1764df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) 1765df8bae1dSRodney W. Grimes destifp = ipforward_rt.ro_rt->rt_ifp; 17666a800098SYoshinobu Inoue #else 17676a800098SYoshinobu Inoue /* 17686a800098SYoshinobu Inoue * If the packet is routed over IPsec tunnel, tell the 17696a800098SYoshinobu Inoue * originator the tunnel MTU. 17706a800098SYoshinobu Inoue * tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz 17716a800098SYoshinobu Inoue * XXX quickhack!!! 17726a800098SYoshinobu Inoue */ 17736a800098SYoshinobu Inoue if (ipforward_rt.ro_rt) { 17746a800098SYoshinobu Inoue struct secpolicy *sp = NULL; 17756a800098SYoshinobu Inoue int ipsecerror; 17766a800098SYoshinobu Inoue int ipsechdr; 17776a800098SYoshinobu Inoue struct route *ro; 17786a800098SYoshinobu Inoue 17796a800098SYoshinobu Inoue sp = ipsec4_getpolicybyaddr(mcopy, 17806a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 17816a800098SYoshinobu Inoue IP_FORWARDING, 17826a800098SYoshinobu Inoue &ipsecerror); 17836a800098SYoshinobu Inoue 17846a800098SYoshinobu Inoue if (sp == NULL) 17856a800098SYoshinobu Inoue destifp = ipforward_rt.ro_rt->rt_ifp; 17866a800098SYoshinobu Inoue else { 17876a800098SYoshinobu Inoue /* count IPsec header size */ 17886a800098SYoshinobu Inoue ipsechdr = ipsec4_hdrsiz(mcopy, 17896a800098SYoshinobu Inoue IPSEC_DIR_OUTBOUND, 17906a800098SYoshinobu Inoue NULL); 17916a800098SYoshinobu Inoue 17926a800098SYoshinobu Inoue /* 17936a800098SYoshinobu Inoue * find the correct route for outer IPv4 17946a800098SYoshinobu Inoue * header, compute tunnel MTU. 17956a800098SYoshinobu Inoue * 17966a800098SYoshinobu Inoue * XXX BUG ALERT 17976a800098SYoshinobu Inoue * The "dummyifp" code relies upon the fact 17986a800098SYoshinobu Inoue * that icmp_error() touches only ifp->if_mtu. 17996a800098SYoshinobu Inoue */ 18006a800098SYoshinobu Inoue /*XXX*/ 18016a800098SYoshinobu Inoue destifp = NULL; 18026a800098SYoshinobu Inoue if (sp->req != NULL 18036a800098SYoshinobu Inoue && sp->req->sav != NULL 18046a800098SYoshinobu Inoue && sp->req->sav->sah != NULL) { 18056a800098SYoshinobu Inoue ro = &sp->req->sav->sah->sa_route; 18066a800098SYoshinobu Inoue if (ro->ro_rt && ro->ro_rt->rt_ifp) { 18076a800098SYoshinobu Inoue dummyifp.if_mtu = 18086a800098SYoshinobu Inoue ro->ro_rt->rt_ifp->if_mtu; 18096a800098SYoshinobu Inoue dummyifp.if_mtu -= ipsechdr; 18106a800098SYoshinobu Inoue destifp = &dummyifp; 18116a800098SYoshinobu Inoue } 18126a800098SYoshinobu Inoue } 18136a800098SYoshinobu Inoue 18146a800098SYoshinobu Inoue key_freesp(sp); 18156a800098SYoshinobu Inoue } 18166a800098SYoshinobu Inoue } 18176a800098SYoshinobu Inoue #endif /*IPSEC*/ 1818df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1819df8bae1dSRodney W. Grimes break; 1820df8bae1dSRodney W. Grimes 1821df8bae1dSRodney W. Grimes case ENOBUFS: 1822df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1823df8bae1dSRodney W. Grimes code = 0; 1824df8bae1dSRodney W. Grimes break; 18253a06e3e0SRuslan Ermilov 18263a06e3e0SRuslan Ermilov case EACCES: /* ipfw denied packet */ 18273a06e3e0SRuslan Ermilov m_freem(mcopy); 18283a06e3e0SRuslan Ermilov return; 1829df8bae1dSRodney W. Grimes } 1830df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1831df8bae1dSRodney W. Grimes } 1832df8bae1dSRodney W. Grimes 183382c23ebaSBill Fenner void 183482c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 183582c23ebaSBill Fenner register struct inpcb *inp; 183682c23ebaSBill Fenner register struct mbuf **mp; 183782c23ebaSBill Fenner register struct ip *ip; 183882c23ebaSBill Fenner register struct mbuf *m; 183982c23ebaSBill Fenner { 184082c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 184182c23ebaSBill Fenner struct timeval tv; 184282c23ebaSBill Fenner 184382c23ebaSBill Fenner microtime(&tv); 184482c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 184582c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 184682c23ebaSBill Fenner if (*mp) 184782c23ebaSBill Fenner mp = &(*mp)->m_next; 184882c23ebaSBill Fenner } 184982c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 185082c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 185182c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 185282c23ebaSBill Fenner if (*mp) 185382c23ebaSBill Fenner mp = &(*mp)->m_next; 185482c23ebaSBill Fenner } 185582c23ebaSBill Fenner #ifdef notyet 185682c23ebaSBill Fenner /* XXX 185782c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 185882c23ebaSBill Fenner * than they already were. 185982c23ebaSBill Fenner */ 186082c23ebaSBill Fenner /* options were tossed already */ 186182c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 186282c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 186382c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 186482c23ebaSBill Fenner if (*mp) 186582c23ebaSBill Fenner mp = &(*mp)->m_next; 186682c23ebaSBill Fenner } 186782c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 186882c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 186982c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 187082c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 187182c23ebaSBill Fenner if (*mp) 187282c23ebaSBill Fenner mp = &(*mp)->m_next; 187382c23ebaSBill Fenner } 187482c23ebaSBill Fenner #endif 187582c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 1876d314ad7bSJulian Elischer struct ifnet *ifp; 1877d314ad7bSJulian Elischer struct sdlbuf { 187882c23ebaSBill Fenner struct sockaddr_dl sdl; 1879d314ad7bSJulian Elischer u_char pad[32]; 1880d314ad7bSJulian Elischer } sdlbuf; 1881d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 1882d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 188382c23ebaSBill Fenner 1884d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 1885d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 1886f9132cebSJonathan Lemon sdp = (struct sockaddr_dl *) 1887f9132cebSJonathan Lemon (ifaddr_byindex(ifp->if_index)->ifa_addr); 1888d314ad7bSJulian Elischer /* 1889d314ad7bSJulian Elischer * Change our mind and don't try copy. 1890d314ad7bSJulian Elischer */ 1891d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 1892d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 1893d314ad7bSJulian Elischer goto makedummy; 1894d314ad7bSJulian Elischer } 1895d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 1896d314ad7bSJulian Elischer } else { 1897d314ad7bSJulian Elischer makedummy: 1898d314ad7bSJulian Elischer sdl2->sdl_len 1899d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 1900d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 1901d314ad7bSJulian Elischer sdl2->sdl_index = 0; 1902d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 1903d314ad7bSJulian Elischer } 1904d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 190582c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 190682c23ebaSBill Fenner if (*mp) 190782c23ebaSBill Fenner mp = &(*mp)->m_next; 190882c23ebaSBill Fenner } 190982c23ebaSBill Fenner } 191082c23ebaSBill Fenner 1911df8bae1dSRodney W. Grimes int 1912f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 1913f0068c4aSGarrett Wollman { 1914f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 1915f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 1916f0068c4aSGarrett Wollman return EOPNOTSUPP; 1917f0068c4aSGarrett Wollman 1918f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 1919f0068c4aSGarrett Wollman return EADDRINUSE; 1920f0068c4aSGarrett Wollman 1921f0068c4aSGarrett Wollman ip_rsvpd = so; 19221c5de19aSGarrett Wollman /* 19231c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 19241c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 19251c5de19aSGarrett Wollman */ 19261c5de19aSGarrett Wollman if (!ip_rsvp_on) { 19271c5de19aSGarrett Wollman ip_rsvp_on = 1; 19281c5de19aSGarrett Wollman rsvp_on++; 19291c5de19aSGarrett Wollman } 1930f0068c4aSGarrett Wollman 1931f0068c4aSGarrett Wollman return 0; 1932f0068c4aSGarrett Wollman } 1933f0068c4aSGarrett Wollman 1934f0068c4aSGarrett Wollman int 1935f0068c4aSGarrett Wollman ip_rsvp_done(void) 1936f0068c4aSGarrett Wollman { 1937f0068c4aSGarrett Wollman ip_rsvpd = NULL; 19381c5de19aSGarrett Wollman /* 19391c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 19401c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 19411c5de19aSGarrett Wollman */ 19421c5de19aSGarrett Wollman if (ip_rsvp_on) { 19431c5de19aSGarrett Wollman ip_rsvp_on = 0; 19441c5de19aSGarrett Wollman rsvp_on--; 19451c5de19aSGarrett Wollman } 1946f0068c4aSGarrett Wollman return 0; 1947f0068c4aSGarrett Wollman } 1948