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 34b715f178SLuigi Rizzo * $Id: ip_input.c,v 1.101 1998/09/10 08:56:40 dfr Exp $ 3558938916SGarrett Wollman * $ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $ 36df8bae1dSRodney W. Grimes */ 37df8bae1dSRodney W. Grimes 3858938916SGarrett Wollman #define _IP_VHL 3958938916SGarrett Wollman 40e4f4247aSEivind Eklund #include "opt_bootp.h" 4174a9466cSGary Palmer #include "opt_ipfw.h" 42b715f178SLuigi Rizzo #include "opt_ipdn.h" 43fbd1372aSJoerg Wunsch #include "opt_ipdivert.h" 441ee25934SPeter Wemm #include "opt_ipfilter.h" 4574a9466cSGary Palmer 4682c23ebaSBill Fenner #include <stddef.h> 4782c23ebaSBill Fenner 48df8bae1dSRodney W. Grimes #include <sys/param.h> 49df8bae1dSRodney W. Grimes #include <sys/systm.h> 50df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 51b715f178SLuigi Rizzo #include <sys/malloc.h> 52df8bae1dSRodney W. Grimes #include <sys/domain.h> 53df8bae1dSRodney W. Grimes #include <sys/protosw.h> 54df8bae1dSRodney W. Grimes #include <sys/socket.h> 55df8bae1dSRodney W. Grimes #include <sys/time.h> 56df8bae1dSRodney W. Grimes #include <sys/kernel.h> 571025071fSGarrett Wollman #include <sys/syslog.h> 58b5e8ce9fSBruce Evans #include <sys/sysctl.h> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes #include <net/if.h> 61d314ad7bSJulian Elischer #include <net/if_var.h> 6282c23ebaSBill Fenner #include <net/if_dl.h> 63df8bae1dSRodney W. Grimes #include <net/route.h> 64748e0b0aSGarrett Wollman #include <net/netisr.h> 65df8bae1dSRodney W. Grimes 66df8bae1dSRodney W. Grimes #include <netinet/in.h> 67df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 68b5e8ce9fSBruce Evans #include <netinet/in_var.h> 69df8bae1dSRodney W. Grimes #include <netinet/ip.h> 70df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 71df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 72df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 7358938916SGarrett Wollman #include <machine/in_cksum.h> 74df8bae1dSRodney W. Grimes 75f0068c4aSGarrett Wollman #include <sys/socketvar.h> 766ddbf1e2SGary Palmer 776ddbf1e2SGary Palmer #ifdef IPFIREWALL 786ddbf1e2SGary Palmer #include <netinet/ip_fw.h> 796ddbf1e2SGary Palmer #endif 806ddbf1e2SGary Palmer 81b715f178SLuigi Rizzo #ifdef DUMMYNET 82b715f178SLuigi Rizzo #include <netinet/ip_dummynet.h> 83b715f178SLuigi Rizzo #endif 84b715f178SLuigi Rizzo 851c5de19aSGarrett Wollman int rsvp_on = 0; 86f708ef1bSPoul-Henning Kamp static int ip_rsvp_on; 87f0068c4aSGarrett Wollman struct socket *ip_rsvpd; 88f0068c4aSGarrett Wollman 891f91d8c5SDavid Greenman int ipforwarding = 0; 900312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, 910312fbe9SPoul-Henning Kamp &ipforwarding, 0, ""); 920312fbe9SPoul-Henning Kamp 93d4fb926cSGarrett Wollman static int ipsendredirects = 1; /* XXX */ 940312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, 950312fbe9SPoul-Henning Kamp &ipsendredirects, 0, ""); 960312fbe9SPoul-Henning Kamp 97df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 980312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, 990312fbe9SPoul-Henning Kamp &ip_defttl, 0, ""); 1000312fbe9SPoul-Henning Kamp 1010312fbe9SPoul-Henning Kamp static int ip_dosourceroute = 0; 1020312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 1030312fbe9SPoul-Henning Kamp &ip_dosourceroute, 0, ""); 1044fce5804SGuido van Rooij 1054fce5804SGuido van Rooij static int ip_acceptsourceroute = 0; 1064fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 1074fce5804SGuido van Rooij CTLFLAG_RW, &ip_acceptsourceroute, 0, ""); 108df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1090312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 110df8bae1dSRodney W. Grimes #endif 111df8bae1dSRodney W. Grimes 112df8bae1dSRodney W. Grimes extern struct domain inetdomain; 113df8bae1dSRodney W. Grimes extern struct protosw inetsw[]; 114df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 1150312fbe9SPoul-Henning Kamp static int ipqmaxlen = IFQ_MAXLEN; 11659562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 117df8bae1dSRodney W. Grimes struct ifqueue ipintrq; 1180312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RD, 1190312fbe9SPoul-Henning Kamp &ipintrq.ifq_maxlen, 0, ""); 1200312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1210312fbe9SPoul-Henning Kamp &ipintrq.ifq_drops, 0, ""); 122df8bae1dSRodney W. Grimes 123f23b4c91SGarrett Wollman struct ipstat ipstat; 1246fce01c9SGarrett Wollman SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD, 1256fce01c9SGarrett Wollman &ipstat, ipstat, ""); 126194a213eSAndrey A. Chernov 127194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 128194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 129194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 130194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 131194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 132194a213eSAndrey A. Chernov ((((x) & 0xF | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 133194a213eSAndrey A. Chernov 134194a213eSAndrey A. Chernov static struct ipq ipq[IPREASS_NHASH]; 135194a213eSAndrey A. Chernov static int nipq = 0; /* total # of reass queues */ 136194a213eSAndrey A. Chernov static int maxnipq; 137f23b4c91SGarrett Wollman 1380312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1390312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1400312fbe9SPoul-Henning Kamp &ip_mtu, 0, ""); 1410312fbe9SPoul-Henning Kamp #endif 1420312fbe9SPoul-Henning Kamp 14358938916SGarrett Wollman #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 14458938916SGarrett Wollman #undef COMPAT_IPFW 14558938916SGarrett Wollman #define COMPAT_IPFW 1 14658938916SGarrett Wollman #else 14758938916SGarrett Wollman #undef COMPAT_IPFW 14858938916SGarrett Wollman #endif 14958938916SGarrett Wollman 15058938916SGarrett Wollman #ifdef COMPAT_IPFW 151cfe8b629SGarrett Wollman 152cfe8b629SGarrett Wollman #include <netinet/ip_fw.h> 153cfe8b629SGarrett Wollman 15423bf9953SPoul-Henning Kamp /* Firewall hooks */ 15523bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 15623bf9953SPoul-Henning Kamp ip_fw_ctl_t *ip_fw_ctl_ptr; 157e7319babSPoul-Henning Kamp 158b715f178SLuigi Rizzo #ifdef DUMMYNET 159b715f178SLuigi Rizzo ip_dn_ctl_t *ip_dn_ctl_ptr; 160b715f178SLuigi Rizzo #endif 161b715f178SLuigi Rizzo 162fed1c7e9SSøren Schmidt /* IP Network Address Translation (NAT) hooks */ 163fed1c7e9SSøren Schmidt ip_nat_t *ip_nat_ptr; 164fed1c7e9SSøren Schmidt ip_nat_ctl_t *ip_nat_ctl_ptr; 16558938916SGarrett Wollman #endif 166fed1c7e9SSøren Schmidt 167afed1b49SDarren Reed #if defined(IPFILTER_LKM) || defined(IPFILTER) 1681ee25934SPeter Wemm int iplattach __P((void)); 169afed1b49SDarren Reed int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)) = NULL; 170afed1b49SDarren Reed #endif 171afed1b49SDarren Reed 172afed1b49SDarren Reed 173e7319babSPoul-Henning Kamp /* 174df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 175df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 176df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 177df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 178df8bae1dSRodney W. Grimes * to us. 179df8bae1dSRodney W. Grimes */ 1800312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 181df8bae1dSRodney W. Grimes static struct ip_srcrt { 182df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 183df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 184df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 185df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 186df8bae1dSRodney W. Grimes } ip_srcrt; 187df8bae1dSRodney W. Grimes 18893e0e116SJulian Elischer #ifdef IPDIVERT 18993e0e116SJulian Elischer /* 19093e0e116SJulian Elischer * Shared variable between ip_input() and ip_reass() to communicate 19193e0e116SJulian Elischer * about which packets, once assembled from fragments, get diverted, 19293e0e116SJulian Elischer * and to which port. 19393e0e116SJulian Elischer */ 19493e0e116SJulian Elischer static u_short frag_divert_port; 19593e0e116SJulian Elischer #endif 19693e0e116SJulian Elischer 197f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr; 198f9e354dfSJulian Elischer 199df8bae1dSRodney W. Grimes static void save_rte __P((u_char *, struct in_addr)); 2000312fbe9SPoul-Henning Kamp static int ip_dooptions __P((struct mbuf *)); 2010312fbe9SPoul-Henning Kamp static void ip_forward __P((struct mbuf *, int)); 2020312fbe9SPoul-Henning Kamp static void ip_freef __P((struct ipq *)); 2030312fbe9SPoul-Henning Kamp static struct ip * 2046effc713SDoug Rabson ip_reass __P((struct mbuf *, struct ipq *, struct ipq *)); 2050312fbe9SPoul-Henning Kamp static struct in_ifaddr * 2060312fbe9SPoul-Henning Kamp ip_rtaddr __P((struct in_addr)); 2070312fbe9SPoul-Henning Kamp static void ipintr __P((void)); 208df8bae1dSRodney W. Grimes /* 209df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 210df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 211df8bae1dSRodney W. Grimes */ 212df8bae1dSRodney W. Grimes void 213df8bae1dSRodney W. Grimes ip_init() 214df8bae1dSRodney W. Grimes { 215df8bae1dSRodney W. Grimes register struct protosw *pr; 216df8bae1dSRodney W. Grimes register int i; 217df8bae1dSRodney W. Grimes 21859562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 219df8bae1dSRodney W. Grimes pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 220df8bae1dSRodney W. Grimes if (pr == 0) 221df8bae1dSRodney W. Grimes panic("ip_init"); 222df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 223df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 224df8bae1dSRodney W. Grimes for (pr = inetdomain.dom_protosw; 225df8bae1dSRodney W. Grimes pr < inetdomain.dom_protoswNPROTOSW; pr++) 226df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 227df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 228df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 229194a213eSAndrey A. Chernov 230194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 231194a213eSAndrey A. Chernov ipq[i].next = ipq[i].prev = &ipq[i]; 232194a213eSAndrey A. Chernov 233194a213eSAndrey A. Chernov maxnipq = nmbclusters/4; 234194a213eSAndrey A. Chernov 235227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 236df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 237b715f178SLuigi Rizzo #ifdef IPFIREWALL 238b715f178SLuigi Rizzo ip_fw_init(); 239b715f178SLuigi Rizzo #endif 240b715f178SLuigi Rizzo #ifdef DUMMYNET 241b715f178SLuigi Rizzo ip_dn_init(); 242b715f178SLuigi Rizzo #endif 243fed1c7e9SSøren Schmidt #ifdef IPNAT 244fed1c7e9SSøren Schmidt ip_nat_init(); 245fed1c7e9SSøren Schmidt #endif 2461ee25934SPeter Wemm #ifdef IPFILTER 2471ee25934SPeter Wemm iplattach(); 2481ee25934SPeter Wemm #endif 249fed1c7e9SSøren Schmidt 250df8bae1dSRodney W. Grimes } 251df8bae1dSRodney W. Grimes 2520312fbe9SPoul-Henning Kamp static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 253f708ef1bSPoul-Henning Kamp static struct route ipforward_rt; 254df8bae1dSRodney W. Grimes 255df8bae1dSRodney W. Grimes /* 256df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 257df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 258df8bae1dSRodney W. Grimes */ 259c67b1d17SGarrett Wollman void 260c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 261df8bae1dSRodney W. Grimes { 26223bf9953SPoul-Henning Kamp struct ip *ip; 26323bf9953SPoul-Henning Kamp struct ipq *fp; 264b715f178SLuigi Rizzo struct ipqent *ipqe; 26523bf9953SPoul-Henning Kamp struct in_ifaddr *ia; 2666effc713SDoug Rabson int i, hlen, mff; 26747c861ecSBrian Somers u_short sum; 268b715f178SLuigi Rizzo #ifndef IPDIVERT /* dummy variable for the firewall code to play with */ 269b715f178SLuigi Rizzo u_short ip_divert_cookie = 0 ; 270b715f178SLuigi Rizzo #endif 271b715f178SLuigi Rizzo #ifdef COMPAT_IPFW 272b715f178SLuigi Rizzo struct ip_fw_chain *rule = NULL ; 273b715f178SLuigi Rizzo #endif 274b715f178SLuigi Rizzo 275b715f178SLuigi Rizzo #if defined(IPFIREWALL) && defined(DUMMYNET) 276b715f178SLuigi Rizzo /* 277b715f178SLuigi Rizzo * dummynet packet are prepended a vestigial mbuf with 278b715f178SLuigi Rizzo * m_type = MT_DUMMYNET and m_data pointing to the matching 279b715f178SLuigi Rizzo * rule. 280b715f178SLuigi Rizzo */ 281b715f178SLuigi Rizzo if (m->m_type == MT_DUMMYNET) { 282b715f178SLuigi Rizzo struct mbuf *m0 = m ; 283b715f178SLuigi Rizzo rule = (struct ip_fw_chain *)(m->m_data) ; 284b715f178SLuigi Rizzo m = m->m_next ; 285b715f178SLuigi Rizzo free(m0, M_IPFW); 286b715f178SLuigi Rizzo ip = mtod(m, struct ip *); 287b715f178SLuigi Rizzo hlen = IP_VHL_HL(ip->ip_vhl) << 2; 288b715f178SLuigi Rizzo goto iphack ; 289b715f178SLuigi Rizzo } else 290b715f178SLuigi Rizzo rule = NULL ; 291b715f178SLuigi Rizzo #endif 292df8bae1dSRodney W. Grimes 293df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 294ed7509acSJulian Elischer if (m == NULL || (m->m_flags & M_PKTHDR) == 0) 29558938916SGarrett Wollman panic("ip_input no HDR"); 296df8bae1dSRodney W. Grimes #endif 297df8bae1dSRodney W. Grimes /* 298df8bae1dSRodney W. Grimes * If no IP addresses have been set yet but the interfaces 299df8bae1dSRodney W. Grimes * are receiving, can't do anything with incoming packets yet. 30059562606SGarrett Wollman * XXX This is broken! We should be able to receive broadcasts 30159562606SGarrett Wollman * and multicasts even without any local addresses configured. 302df8bae1dSRodney W. Grimes */ 30359562606SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead)) 304df8bae1dSRodney W. Grimes goto bad; 305df8bae1dSRodney W. Grimes ipstat.ips_total++; 30658938916SGarrett Wollman 30758938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 30858938916SGarrett Wollman goto tooshort; 30958938916SGarrett Wollman 310df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 311df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 312df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 313c67b1d17SGarrett Wollman return; 314df8bae1dSRodney W. Grimes } 315df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 31658938916SGarrett Wollman 31758938916SGarrett Wollman if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { 318df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 319df8bae1dSRodney W. Grimes goto bad; 320df8bae1dSRodney W. Grimes } 32158938916SGarrett Wollman 32258938916SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 323df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 324df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 325df8bae1dSRodney W. Grimes goto bad; 326df8bae1dSRodney W. Grimes } 327df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 328df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 329df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 330c67b1d17SGarrett Wollman return; 331df8bae1dSRodney W. Grimes } 332df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 333df8bae1dSRodney W. Grimes } 33458938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 33547c861ecSBrian Somers sum = in_cksum_hdr(ip); 33658938916SGarrett Wollman } else { 33747c861ecSBrian Somers sum = in_cksum(m, hlen); 33858938916SGarrett Wollman } 33947c861ecSBrian Somers if (sum) { 340df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 341df8bae1dSRodney W. Grimes goto bad; 342df8bae1dSRodney W. Grimes } 343df8bae1dSRodney W. Grimes 344df8bae1dSRodney W. Grimes /* 345df8bae1dSRodney W. Grimes * Convert fields to host representation. 346df8bae1dSRodney W. Grimes */ 347df8bae1dSRodney W. Grimes NTOHS(ip->ip_len); 348df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 349df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 350df8bae1dSRodney W. Grimes goto bad; 351df8bae1dSRodney W. Grimes } 352df8bae1dSRodney W. Grimes NTOHS(ip->ip_id); 353df8bae1dSRodney W. Grimes NTOHS(ip->ip_off); 354df8bae1dSRodney W. Grimes 355df8bae1dSRodney W. Grimes /* 356df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 357df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 358df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 359df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 360df8bae1dSRodney W. Grimes */ 361df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 36258938916SGarrett Wollman tooshort: 363df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 364df8bae1dSRodney W. Grimes goto bad; 365df8bae1dSRodney W. Grimes } 366df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 367df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 368df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 369df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 370df8bae1dSRodney W. Grimes } else 371df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 372df8bae1dSRodney W. Grimes } 3734dd1662bSUgen J.S. Antsilevich /* 3744dd1662bSUgen J.S. Antsilevich * IpHack's section. 3754dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 3764dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 3774dd1662bSUgen J.S. Antsilevich * deals with it. 37893e0e116SJulian Elischer * - Firewall: deny/allow/divert 379fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 380b715f178SLuigi Rizzo * - Pipe: pass pkt through dummynet. 3814dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 3824dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 3834dd1662bSUgen J.S. Antsilevich */ 384b715f178SLuigi Rizzo 385b715f178SLuigi Rizzo iphack: 386beec8214SDarren Reed #if defined(IPFILTER) || defined(IPFILTER_LKM) 387beec8214SDarren Reed /* 388beec8214SDarren Reed * Check if we want to allow this packet to be processed. 389beec8214SDarren Reed * Consider it to be bad if not. 390beec8214SDarren Reed */ 3911ee25934SPeter Wemm if (fr_checkp) { 392beec8214SDarren Reed struct mbuf *m1 = m; 393df8bae1dSRodney W. Grimes 394beec8214SDarren Reed if ((*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m1) || !m1) 395beec8214SDarren Reed return; 396beec8214SDarren Reed ip = mtod(m = m1, struct ip *); 397beec8214SDarren Reed } 398beec8214SDarren Reed #endif 39958938916SGarrett Wollman #ifdef COMPAT_IPFW 40093e0e116SJulian Elischer if (ip_fw_chk_ptr) { 401f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 402f9e354dfSJulian Elischer /* 403f9e354dfSJulian Elischer * If we've been forwarded from the output side, then 404f9e354dfSJulian Elischer * skip the firewall a second time 405f9e354dfSJulian Elischer */ 406f9e354dfSJulian Elischer if (ip_fw_fwd_addr) 407f9e354dfSJulian Elischer goto ours; 408f9e354dfSJulian Elischer #endif /* IPFIREWALL_FORWARD */ 409b715f178SLuigi Rizzo i = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie, 410b715f178SLuigi Rizzo &m, &rule, &ip_fw_fwd_addr); 411f9e354dfSJulian Elischer /* 412b715f178SLuigi Rizzo * see the comment in ip_output for the return values 413b715f178SLuigi Rizzo * produced by the firewall. 414f9e354dfSJulian Elischer */ 415b715f178SLuigi Rizzo if (!m) /* packet discarded by firewall */ 416b715f178SLuigi Rizzo return ; 417b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ 418b715f178SLuigi Rizzo goto pass ; 419b715f178SLuigi Rizzo #ifdef DUMMYNET 420b715f178SLuigi Rizzo if (i & 0x10000) { 421b715f178SLuigi Rizzo /* send packet to the appropriate pipe */ 422b715f178SLuigi Rizzo dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule); 423e4676ba6SJulian Elischer return ; 42493e0e116SJulian Elischer } 425b715f178SLuigi Rizzo #endif 426b715f178SLuigi Rizzo #ifdef IPDIVERT 427b715f178SLuigi Rizzo if (i > 0 && i < 0x10000) { 428b715f178SLuigi Rizzo /* Divert packet */ 429b715f178SLuigi Rizzo frag_divert_port = i & 0xffff ; 430b715f178SLuigi Rizzo goto ours; 431b715f178SLuigi Rizzo } 432b715f178SLuigi Rizzo #endif 433b715f178SLuigi Rizzo #ifdef IPFIREWALL_FORWARD 434b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr != NULL) 435b715f178SLuigi Rizzo goto pass ; 436b715f178SLuigi Rizzo #endif 437b715f178SLuigi Rizzo /* 438b715f178SLuigi Rizzo * if we get here, the packet must be dropped 439b715f178SLuigi Rizzo */ 440b715f178SLuigi Rizzo m_freem(m); 441b715f178SLuigi Rizzo return; 442b715f178SLuigi Rizzo } 443b715f178SLuigi Rizzo pass: 444100ba1a6SJordan K. Hubbard 4456713d4a7SSøren Schmidt if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN)) 446fed1c7e9SSøren Schmidt return; 447f9e354dfSJulian Elischer #endif /* !COMPAT_IPFW */ 448fed1c7e9SSøren Schmidt 449df8bae1dSRodney W. Grimes /* 450df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 451df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 452df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 453df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 454df8bae1dSRodney W. Grimes */ 455df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 456df8bae1dSRodney W. Grimes if (hlen > sizeof (struct ip) && ip_dooptions(m)) 457c67b1d17SGarrett Wollman return; 458df8bae1dSRodney W. Grimes 459f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 460f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 461f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 462f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 463f0068c4aSGarrett Wollman * grabbing the packet. 464f0068c4aSGarrett Wollman */ 4651c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 466f0068c4aSGarrett Wollman goto ours; 467f0068c4aSGarrett Wollman 468df8bae1dSRodney W. Grimes /* 469df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 470df8bae1dSRodney W. Grimes */ 471d4295c32SJulian Elischer for (ia = TAILQ_FIRST(&in_ifaddrhead); ia; 472f9e354dfSJulian Elischer ia = TAILQ_NEXT(ia, ia_link)) { 473df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 474df8bae1dSRodney W. Grimes 475df8bae1dSRodney W. Grimes if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) 476df8bae1dSRodney W. Grimes goto ours; 477432aad0eSTor Egge #ifdef BOOTP_COMPAT 478432aad0eSTor Egge if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 479432aad0eSTor Egge goto ours; 480432aad0eSTor Egge #endif 481f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 482f9e354dfSJulian Elischer /* 483f9e354dfSJulian Elischer * If the addr to forward to is one of ours, we pretend to 484f9e354dfSJulian Elischer * be the destination for this packet. 485f9e354dfSJulian Elischer */ 486f9e354dfSJulian Elischer if (ip_fw_fwd_addr != NULL && 487f9e354dfSJulian Elischer IA_SIN(ia)->sin_addr.s_addr == 488f9e354dfSJulian Elischer ip_fw_fwd_addr->sin_addr.s_addr) 489f9e354dfSJulian Elischer goto ours; 490f9e354dfSJulian Elischer #endif 4916ed666afSPoul-Henning Kamp if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { 492df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 493df8bae1dSRodney W. Grimes ip->ip_dst.s_addr) 494df8bae1dSRodney W. Grimes goto ours; 495df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) 496df8bae1dSRodney W. Grimes goto ours; 497df8bae1dSRodney W. Grimes } 498df8bae1dSRodney W. Grimes } 499df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 500df8bae1dSRodney W. Grimes struct in_multi *inm; 501df8bae1dSRodney W. Grimes if (ip_mrouter) { 502df8bae1dSRodney W. Grimes /* 503df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 504df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 505df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 506df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 507df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 508df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 509df8bae1dSRodney W. Grimes * 510df8bae1dSRodney W. Grimes * (The IP ident field is put in the same byte order 511df8bae1dSRodney W. Grimes * as expected when ip_mforward() is called from 512df8bae1dSRodney W. Grimes * ip_output().) 513df8bae1dSRodney W. Grimes */ 514df8bae1dSRodney W. Grimes ip->ip_id = htons(ip->ip_id); 515f0068c4aSGarrett Wollman if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 516df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 517df8bae1dSRodney W. Grimes m_freem(m); 518c67b1d17SGarrett Wollman return; 519df8bae1dSRodney W. Grimes } 520df8bae1dSRodney W. Grimes ip->ip_id = ntohs(ip->ip_id); 521df8bae1dSRodney W. Grimes 522df8bae1dSRodney W. Grimes /* 523df8bae1dSRodney W. Grimes * The process-level routing demon needs to receive 524df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 525df8bae1dSRodney W. Grimes * host belongs to their destination groups. 526df8bae1dSRodney W. Grimes */ 527df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 528df8bae1dSRodney W. Grimes goto ours; 529df8bae1dSRodney W. Grimes ipstat.ips_forward++; 530df8bae1dSRodney W. Grimes } 531df8bae1dSRodney W. Grimes /* 532df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 533df8bae1dSRodney W. Grimes * arrival interface. 534df8bae1dSRodney W. Grimes */ 535df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 536df8bae1dSRodney W. Grimes if (inm == NULL) { 53782c39223SGarrett Wollman ipstat.ips_notmember++; 538df8bae1dSRodney W. Grimes m_freem(m); 539c67b1d17SGarrett Wollman return; 540df8bae1dSRodney W. Grimes } 541df8bae1dSRodney W. Grimes goto ours; 542df8bae1dSRodney W. Grimes } 543df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 544df8bae1dSRodney W. Grimes goto ours; 545df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 546df8bae1dSRodney W. Grimes goto ours; 547df8bae1dSRodney W. Grimes 548df8bae1dSRodney W. Grimes /* 549df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 550df8bae1dSRodney W. Grimes */ 551df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 552df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 553df8bae1dSRodney W. Grimes m_freem(m); 554df8bae1dSRodney W. Grimes } else 555df8bae1dSRodney W. Grimes ip_forward(m, 0); 556c67b1d17SGarrett Wollman return; 557df8bae1dSRodney W. Grimes 558df8bae1dSRodney W. Grimes ours: 559100ba1a6SJordan K. Hubbard 56063f8d699SJordan K. Hubbard /* 561df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 562df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 563df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 564df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 565df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 566df8bae1dSRodney W. Grimes */ 567c383a33fSDima Ruban if (ip->ip_off & (IP_MF | IP_OFFMASK | IP_RF)) { 568df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { /* XXX */ 569b715f178SLuigi Rizzo if ((m = m_pullup(m, sizeof (struct ip))) == 0) { 570df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 57193e0e116SJulian Elischer #ifdef IPDIVERT 57293e0e116SJulian Elischer frag_divert_port = 0; 573c977d4c7SJulian Elischer ip_divert_cookie = 0; 57493e0e116SJulian Elischer #endif 575c67b1d17SGarrett Wollman return; 576df8bae1dSRodney W. Grimes } 577df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 578df8bae1dSRodney W. Grimes } 579194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 580df8bae1dSRodney W. Grimes /* 581df8bae1dSRodney W. Grimes * Look for queue of fragments 582df8bae1dSRodney W. Grimes * of this datagram. 583df8bae1dSRodney W. Grimes */ 584194a213eSAndrey A. Chernov for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next) 585df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 586df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 587df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 588df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 589df8bae1dSRodney W. Grimes goto found; 590df8bae1dSRodney W. Grimes 591194a213eSAndrey A. Chernov fp = 0; 592194a213eSAndrey A. Chernov 593194a213eSAndrey A. Chernov /* check if there's a place for the new queue */ 594194a213eSAndrey A. Chernov if (nipq > maxnipq) { 595194a213eSAndrey A. Chernov /* 596194a213eSAndrey A. Chernov * drop something from the tail of the current queue 597194a213eSAndrey A. Chernov * before proceeding further 598194a213eSAndrey A. Chernov */ 599194a213eSAndrey A. Chernov if (ipq[sum].prev == &ipq[sum]) { /* gak */ 600194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 601194a213eSAndrey A. Chernov if (ipq[i].prev != &ipq[i]) { 602194a213eSAndrey A. Chernov ip_freef(ipq[i].prev); 603194a213eSAndrey A. Chernov break; 604194a213eSAndrey A. Chernov } 605194a213eSAndrey A. Chernov } 606194a213eSAndrey A. Chernov } else 607194a213eSAndrey A. Chernov ip_freef(ipq[sum].prev); 608194a213eSAndrey A. Chernov } 609194a213eSAndrey A. Chernov found: 610df8bae1dSRodney W. Grimes /* 611df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 612df8bae1dSRodney W. Grimes * set ip_mff if more fragments are expected, 613df8bae1dSRodney W. Grimes * convert offset of this to bytes. 614df8bae1dSRodney W. Grimes */ 615df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 6166effc713SDoug Rabson mff = (ip->ip_off & IP_MF) != 0; 6176effc713SDoug Rabson if (mff) { 6186effc713SDoug Rabson /* 6196effc713SDoug Rabson * Make sure that fragments have a data length 6206effc713SDoug Rabson * that's a non-zero multiple of 8 bytes. 6216effc713SDoug Rabson */ 6226effc713SDoug Rabson if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { 6236effc713SDoug Rabson ipstat.ips_toosmall++; /* XXX */ 6246effc713SDoug Rabson goto bad; 6256effc713SDoug Rabson } 6266effc713SDoug Rabson m->m_flags |= M_FRAG; 6276effc713SDoug Rabson } 628df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 629df8bae1dSRodney W. Grimes 630df8bae1dSRodney W. Grimes /* 631df8bae1dSRodney W. Grimes * If datagram marked as having more fragments 632df8bae1dSRodney W. Grimes * or if this is not the first fragment, 633df8bae1dSRodney W. Grimes * attempt reassembly; if it succeeds, proceed. 634df8bae1dSRodney W. Grimes */ 6356effc713SDoug Rabson if (mff || ip->ip_off) { 636df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 6376effc713SDoug Rabson m->m_pkthdr.header = ip; 6386effc713SDoug Rabson ip = ip_reass(m, fp, &ipq[sum]); 639f9e354dfSJulian Elischer if (ip == 0) { 640f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 641f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 642f9e354dfSJulian Elischer #endif 643c67b1d17SGarrett Wollman return; 644f9e354dfSJulian Elischer } 64581aee63dSPoul-Henning Kamp /* Get the length of the reassembled packets header */ 64681aee63dSPoul-Henning Kamp hlen = IP_VHL_HL(ip->ip_vhl) << 2; 647df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 648df8bae1dSRodney W. Grimes m = dtom(ip); 649af782f1cSBrian Somers #ifdef IPDIVERT 650af782f1cSBrian Somers if (frag_divert_port) { 651af782f1cSBrian Somers ip->ip_len += hlen; 652af782f1cSBrian Somers HTONS(ip->ip_len); 653af782f1cSBrian Somers HTONS(ip->ip_off); 654af782f1cSBrian Somers HTONS(ip->ip_id); 655af782f1cSBrian Somers ip->ip_sum = 0; 656af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 657af782f1cSBrian Somers NTOHS(ip->ip_id); 658af782f1cSBrian Somers NTOHS(ip->ip_off); 659af782f1cSBrian Somers NTOHS(ip->ip_len); 660af782f1cSBrian Somers ip->ip_len -= hlen; 661af782f1cSBrian Somers } 662af782f1cSBrian Somers #endif 663df8bae1dSRodney W. Grimes } else 664df8bae1dSRodney W. Grimes if (fp) 665df8bae1dSRodney W. Grimes ip_freef(fp); 666df8bae1dSRodney W. Grimes } else 667df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 668df8bae1dSRodney W. Grimes 66993e0e116SJulian Elischer #ifdef IPDIVERT 67093e0e116SJulian Elischer /* 671e4676ba6SJulian Elischer * Divert reassembled packets to the divert protocol if required 672efe39c6aSJulian Elischer * If divert port is null then cookie should be too, 673efe39c6aSJulian Elischer * so we shouldn't need to clear them here. Assume ip_divert does so. 67493e0e116SJulian Elischer */ 67593e0e116SJulian Elischer if (frag_divert_port) { 676e4676ba6SJulian Elischer ipstat.ips_delivered++; 67793e0e116SJulian Elischer ip_divert_port = frag_divert_port; 67893e0e116SJulian Elischer frag_divert_port = 0; 67993e0e116SJulian Elischer (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, hlen); 68093e0e116SJulian Elischer return; 68193e0e116SJulian Elischer } 68279755dc5SJulian Elischer 68379755dc5SJulian Elischer /* Don't let packets divert themselves */ 68479755dc5SJulian Elischer if (ip->ip_p == IPPROTO_DIVERT) { 68579755dc5SJulian Elischer ipstat.ips_noproto++; 68679755dc5SJulian Elischer goto bad; 68779755dc5SJulian Elischer } 688bb60f459SJulian Elischer 68993e0e116SJulian Elischer #endif 69093e0e116SJulian Elischer 691df8bae1dSRodney W. Grimes /* 692df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 693df8bae1dSRodney W. Grimes */ 694df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 695df8bae1dSRodney W. Grimes (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); 696f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 697f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; /* tcp needed it */ 698f9e354dfSJulian Elischer #endif 699c67b1d17SGarrett Wollman return; 700df8bae1dSRodney W. Grimes bad: 701f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 702f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 703f9e354dfSJulian Elischer #endif 704df8bae1dSRodney W. Grimes m_freem(m); 705c67b1d17SGarrett Wollman } 706c67b1d17SGarrett Wollman 707c67b1d17SGarrett Wollman /* 708c67b1d17SGarrett Wollman * IP software interrupt routine - to go away sometime soon 709c67b1d17SGarrett Wollman */ 710c67b1d17SGarrett Wollman static void 711c67b1d17SGarrett Wollman ipintr(void) 712c67b1d17SGarrett Wollman { 713c67b1d17SGarrett Wollman int s; 714c67b1d17SGarrett Wollman struct mbuf *m; 715c67b1d17SGarrett Wollman 716c67b1d17SGarrett Wollman while(1) { 717c67b1d17SGarrett Wollman s = splimp(); 718c67b1d17SGarrett Wollman IF_DEQUEUE(&ipintrq, m); 719c67b1d17SGarrett Wollman splx(s); 720c67b1d17SGarrett Wollman if (m == 0) 721c67b1d17SGarrett Wollman return; 722c67b1d17SGarrett Wollman ip_input(m); 723c67b1d17SGarrett Wollman } 724df8bae1dSRodney W. Grimes } 725df8bae1dSRodney W. Grimes 726748e0b0aSGarrett Wollman NETISR_SET(NETISR_IP, ipintr); 727748e0b0aSGarrett Wollman 728df8bae1dSRodney W. Grimes /* 729df8bae1dSRodney W. Grimes * Take incoming datagram fragment and try to 730df8bae1dSRodney W. Grimes * reassemble it into whole datagram. If a chain for 731df8bae1dSRodney W. Grimes * reassembly of this datagram already exists, then it 732df8bae1dSRodney W. Grimes * is given as fp; otherwise have to make a chain. 733df8bae1dSRodney W. Grimes */ 7340312fbe9SPoul-Henning Kamp static struct ip * 7356effc713SDoug Rabson ip_reass(m, fp, where) 7366effc713SDoug Rabson register struct mbuf *m; 737df8bae1dSRodney W. Grimes register struct ipq *fp; 738194a213eSAndrey A. Chernov struct ipq *where; 739df8bae1dSRodney W. Grimes { 7406effc713SDoug Rabson struct ip *ip = mtod(m, struct ip *); 7416effc713SDoug Rabson register struct mbuf *p = 0, *q, *nq; 742df8bae1dSRodney W. Grimes struct mbuf *t; 7436effc713SDoug Rabson int hlen = IP_VHL_HL(ip->ip_vhl) << 2; 744df8bae1dSRodney W. Grimes int i, next; 745df8bae1dSRodney W. Grimes 746df8bae1dSRodney W. Grimes /* 747df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 748df8bae1dSRodney W. Grimes * would confuse code below. 749df8bae1dSRodney W. Grimes */ 750df8bae1dSRodney W. Grimes m->m_data += hlen; 751df8bae1dSRodney W. Grimes m->m_len -= hlen; 752df8bae1dSRodney W. Grimes 753df8bae1dSRodney W. Grimes /* 754df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 755df8bae1dSRodney W. Grimes */ 756df8bae1dSRodney W. Grimes if (fp == 0) { 757df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 758df8bae1dSRodney W. Grimes goto dropfrag; 759df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 760194a213eSAndrey A. Chernov insque(fp, where); 761194a213eSAndrey A. Chernov nipq++; 762df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 763df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 764df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 7656effc713SDoug Rabson fp->ipq_src = ip->ip_src; 7666effc713SDoug Rabson fp->ipq_dst = ip->ip_dst; 767b715f178SLuigi Rizzo fp->ipq_frags = 0; 76893e0e116SJulian Elischer #ifdef IPDIVERT 76993e0e116SJulian Elischer fp->ipq_divert = 0; 770bb60f459SJulian Elischer fp->ipq_div_cookie = 0; 77193e0e116SJulian Elischer #endif 772b715f178SLuigi Rizzo q = 0; 773b715f178SLuigi Rizzo goto insert; 774df8bae1dSRodney W. Grimes } 775df8bae1dSRodney W. Grimes 7766effc713SDoug Rabson #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) 7776effc713SDoug Rabson 778df8bae1dSRodney W. Grimes /* 779df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 780df8bae1dSRodney W. Grimes */ 7816effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) 7826effc713SDoug Rabson if (GETIP(q)->ip_off > ip->ip_off) 783df8bae1dSRodney W. Grimes break; 784df8bae1dSRodney W. Grimes 785df8bae1dSRodney W. Grimes /* 786df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 787df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 788b715f178SLuigi Rizzo * segment. If it provides all of our data, drop us. 789df8bae1dSRodney W. Grimes */ 7906effc713SDoug Rabson if (p) { 7916effc713SDoug Rabson i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; 792df8bae1dSRodney W. Grimes if (i > 0) { 793df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 794df8bae1dSRodney W. Grimes goto dropfrag; 795df8bae1dSRodney W. Grimes m_adj(dtom(ip), i); 796df8bae1dSRodney W. Grimes ip->ip_off += i; 797df8bae1dSRodney W. Grimes ip->ip_len -= i; 798df8bae1dSRodney W. Grimes } 799df8bae1dSRodney W. Grimes } 800df8bae1dSRodney W. Grimes 801df8bae1dSRodney W. Grimes /* 802df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 803df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 804df8bae1dSRodney W. Grimes */ 8056effc713SDoug Rabson for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; 806b715f178SLuigi Rizzo p = q, q = nq) { 8076effc713SDoug Rabson i = (ip->ip_off + ip->ip_len) - 8086effc713SDoug Rabson GETIP(q)->ip_off; 8096effc713SDoug Rabson if (i < GETIP(q)->ip_len) { 8106effc713SDoug Rabson GETIP(q)->ip_len -= i; 8116effc713SDoug Rabson GETIP(q)->ip_off += i; 8126effc713SDoug Rabson m_adj(q, i); 813df8bae1dSRodney W. Grimes break; 814df8bae1dSRodney W. Grimes } 8156effc713SDoug Rabson nq = q->m_nextpkt; 816b715f178SLuigi Rizzo if (p) 817b715f178SLuigi Rizzo p->m_nextpkt = nq; 818b715f178SLuigi Rizzo else 819b715f178SLuigi Rizzo fp->ipq_frags = nq; 8206effc713SDoug Rabson m_freem(q); 821df8bae1dSRodney W. Grimes } 822df8bae1dSRodney W. Grimes 823b715f178SLuigi Rizzo insert: 82493e0e116SJulian Elischer 82593e0e116SJulian Elischer #ifdef IPDIVERT 82693e0e116SJulian Elischer /* 82793e0e116SJulian Elischer * Any fragment diverting causes the whole packet to divert 82893e0e116SJulian Elischer */ 829efe39c6aSJulian Elischer if (frag_divert_port) { 83093e0e116SJulian Elischer fp->ipq_divert = frag_divert_port; 831c977d4c7SJulian Elischer fp->ipq_div_cookie = ip_divert_cookie; 832bb60f459SJulian Elischer } 83393e0e116SJulian Elischer frag_divert_port = 0; 834c977d4c7SJulian Elischer ip_divert_cookie = 0; 83593e0e116SJulian Elischer #endif 83693e0e116SJulian Elischer 837df8bae1dSRodney W. Grimes /* 838b715f178SLuigi Rizzo * Stick new segment in its place; 839b715f178SLuigi Rizzo * check for complete reassembly. 840df8bae1dSRodney W. Grimes */ 841b715f178SLuigi Rizzo if (p == NULL) { 842b715f178SLuigi Rizzo m->m_nextpkt = fp->ipq_frags; 843b715f178SLuigi Rizzo fp->ipq_frags = m; 844b715f178SLuigi Rizzo } else { 845b715f178SLuigi Rizzo m->m_nextpkt = p->m_nextpkt; 846b715f178SLuigi Rizzo p->m_nextpkt = m; 847b715f178SLuigi Rizzo } 8486effc713SDoug Rabson next = 0; 8496effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { 8506effc713SDoug Rabson if (GETIP(q)->ip_off != next) 8516effc713SDoug Rabson return (0); 8526effc713SDoug Rabson next += GETIP(q)->ip_len; 8536effc713SDoug Rabson } 8546effc713SDoug Rabson /* Make sure the last packet didn't have the IP_MF flag */ 8556effc713SDoug Rabson if (p->m_flags & M_FRAG) 856df8bae1dSRodney W. Grimes return (0); 857df8bae1dSRodney W. Grimes 858df8bae1dSRodney W. Grimes /* 859430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 860430d30d8SBill Fenner */ 8616effc713SDoug Rabson q = fp->ipq_frags; 8626effc713SDoug Rabson ip = GETIP(q); 8636effc713SDoug Rabson if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) { 864430d30d8SBill Fenner ipstat.ips_toolong++; 865430d30d8SBill Fenner ip_freef(fp); 866430d30d8SBill Fenner return (0); 867430d30d8SBill Fenner } 868430d30d8SBill Fenner 869430d30d8SBill Fenner /* 870430d30d8SBill Fenner * Concatenate fragments. 871df8bae1dSRodney W. Grimes */ 8726effc713SDoug Rabson m = q; 873df8bae1dSRodney W. Grimes t = m->m_next; 874df8bae1dSRodney W. Grimes m->m_next = 0; 875df8bae1dSRodney W. Grimes m_cat(m, t); 8766effc713SDoug Rabson nq = q->m_nextpkt; 877945aa40dSDoug Rabson q->m_nextpkt = 0; 8786effc713SDoug Rabson for (q = nq; q != NULL; q = nq) { 8796effc713SDoug Rabson nq = q->m_nextpkt; 880945aa40dSDoug Rabson q->m_nextpkt = NULL; 8816effc713SDoug Rabson m_cat(m, q); 882df8bae1dSRodney W. Grimes } 883df8bae1dSRodney W. Grimes 88493e0e116SJulian Elischer #ifdef IPDIVERT 88593e0e116SJulian Elischer /* 886c977d4c7SJulian Elischer * extract divert port for packet, if any 88793e0e116SJulian Elischer */ 88893e0e116SJulian Elischer frag_divert_port = fp->ipq_divert; 889c977d4c7SJulian Elischer ip_divert_cookie = fp->ipq_div_cookie; 89093e0e116SJulian Elischer #endif 89193e0e116SJulian Elischer 892df8bae1dSRodney W. Grimes /* 893df8bae1dSRodney W. Grimes * Create header for new ip packet by 894df8bae1dSRodney W. Grimes * modifying header of first packet; 895df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 896df8bae1dSRodney W. Grimes * Make header visible. 897df8bae1dSRodney W. Grimes */ 898df8bae1dSRodney W. Grimes ip->ip_len = next; 8996effc713SDoug Rabson ip->ip_src = fp->ipq_src; 9006effc713SDoug Rabson ip->ip_dst = fp->ipq_dst; 901df8bae1dSRodney W. Grimes remque(fp); 902194a213eSAndrey A. Chernov nipq--; 903df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 9046effc713SDoug Rabson m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2); 9056effc713SDoug Rabson m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2); 906df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 907df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 908df8bae1dSRodney W. Grimes register int plen = 0; 909df8bae1dSRodney W. Grimes for (t = m; m; m = m->m_next) 910df8bae1dSRodney W. Grimes plen += m->m_len; 911df8bae1dSRodney W. Grimes t->m_pkthdr.len = plen; 912df8bae1dSRodney W. Grimes } 9136effc713SDoug Rabson return (ip); 914df8bae1dSRodney W. Grimes 915df8bae1dSRodney W. Grimes dropfrag: 916efe39c6aSJulian Elischer #ifdef IPDIVERT 917efe39c6aSJulian Elischer frag_divert_port = 0; 918efe39c6aSJulian Elischer ip_divert_cookie = 0; 919efe39c6aSJulian Elischer #endif 920df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 921df8bae1dSRodney W. Grimes m_freem(m); 922df8bae1dSRodney W. Grimes return (0); 9236effc713SDoug Rabson 9246effc713SDoug Rabson #undef GETIP 925df8bae1dSRodney W. Grimes } 926df8bae1dSRodney W. Grimes 927df8bae1dSRodney W. Grimes /* 928df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 929df8bae1dSRodney W. Grimes * associated datagrams. 930df8bae1dSRodney W. Grimes */ 9310312fbe9SPoul-Henning Kamp static void 932df8bae1dSRodney W. Grimes ip_freef(fp) 933df8bae1dSRodney W. Grimes struct ipq *fp; 934df8bae1dSRodney W. Grimes { 9356effc713SDoug Rabson register struct mbuf *q; 936df8bae1dSRodney W. Grimes 9376effc713SDoug Rabson while (fp->ipq_frags) { 9386effc713SDoug Rabson q = fp->ipq_frags; 9396effc713SDoug Rabson fp->ipq_frags = q->m_nextpkt; 9406effc713SDoug Rabson m_freem(q); 941df8bae1dSRodney W. Grimes } 942df8bae1dSRodney W. Grimes remque(fp); 943df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 944194a213eSAndrey A. Chernov nipq--; 945df8bae1dSRodney W. Grimes } 946df8bae1dSRodney W. Grimes 947df8bae1dSRodney W. Grimes /* 948df8bae1dSRodney W. Grimes * IP timer processing; 949df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 950df8bae1dSRodney W. Grimes * queue, discard it. 951df8bae1dSRodney W. Grimes */ 952df8bae1dSRodney W. Grimes void 953df8bae1dSRodney W. Grimes ip_slowtimo() 954df8bae1dSRodney W. Grimes { 955df8bae1dSRodney W. Grimes register struct ipq *fp; 956df8bae1dSRodney W. Grimes int s = splnet(); 957194a213eSAndrey A. Chernov int i; 958df8bae1dSRodney W. Grimes 959194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 960194a213eSAndrey A. Chernov fp = ipq[i].next; 961194a213eSAndrey A. Chernov if (fp == 0) 962194a213eSAndrey A. Chernov continue; 963194a213eSAndrey A. Chernov while (fp != &ipq[i]) { 964df8bae1dSRodney W. Grimes --fp->ipq_ttl; 965df8bae1dSRodney W. Grimes fp = fp->next; 966df8bae1dSRodney W. Grimes if (fp->prev->ipq_ttl == 0) { 967df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 968df8bae1dSRodney W. Grimes ip_freef(fp->prev); 969df8bae1dSRodney W. Grimes } 970df8bae1dSRodney W. Grimes } 971194a213eSAndrey A. Chernov } 9721f91d8c5SDavid Greenman ipflow_slowtimo(); 973df8bae1dSRodney W. Grimes splx(s); 974df8bae1dSRodney W. Grimes } 975df8bae1dSRodney W. Grimes 976df8bae1dSRodney W. Grimes /* 977df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 978df8bae1dSRodney W. Grimes */ 979df8bae1dSRodney W. Grimes void 980df8bae1dSRodney W. Grimes ip_drain() 981df8bae1dSRodney W. Grimes { 982194a213eSAndrey A. Chernov int i; 983ce29ab3aSGarrett Wollman 984194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 985194a213eSAndrey A. Chernov while (ipq[i].next != &ipq[i]) { 986194a213eSAndrey A. Chernov ipstat.ips_fragdropped++; 987194a213eSAndrey A. Chernov ip_freef(ipq[i].next); 988194a213eSAndrey A. Chernov } 989194a213eSAndrey A. Chernov } 990ce29ab3aSGarrett Wollman in_rtqdrain(); 991df8bae1dSRodney W. Grimes } 992df8bae1dSRodney W. Grimes 993df8bae1dSRodney W. Grimes /* 994df8bae1dSRodney W. Grimes * Do option processing on a datagram, 995df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 996df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 997df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 998df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 999df8bae1dSRodney W. Grimes */ 10000312fbe9SPoul-Henning Kamp static int 1001df8bae1dSRodney W. Grimes ip_dooptions(m) 1002df8bae1dSRodney W. Grimes struct mbuf *m; 1003df8bae1dSRodney W. Grimes { 1004df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1005df8bae1dSRodney W. Grimes register u_char *cp; 1006df8bae1dSRodney W. Grimes register struct ip_timestamp *ipt; 1007df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 1008df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 1009df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 1010df8bae1dSRodney W. Grimes n_time ntime; 1011df8bae1dSRodney W. Grimes 1012df8bae1dSRodney W. Grimes dst = ip->ip_dst; 1013df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 101458938916SGarrett Wollman cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1015df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 1016df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 1017df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 1018df8bae1dSRodney W. Grimes break; 1019df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 1020df8bae1dSRodney W. Grimes optlen = 1; 1021df8bae1dSRodney W. Grimes else { 1022df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 1023df8bae1dSRodney W. Grimes if (optlen <= 0 || optlen > cnt) { 1024df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 1025df8bae1dSRodney W. Grimes goto bad; 1026df8bae1dSRodney W. Grimes } 1027df8bae1dSRodney W. Grimes } 1028df8bae1dSRodney W. Grimes switch (opt) { 1029df8bae1dSRodney W. Grimes 1030df8bae1dSRodney W. Grimes default: 1031df8bae1dSRodney W. Grimes break; 1032df8bae1dSRodney W. Grimes 1033df8bae1dSRodney W. Grimes /* 1034df8bae1dSRodney W. Grimes * Source routing with record. 1035df8bae1dSRodney W. Grimes * Find interface with current destination address. 1036df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 1037df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 1038df8bae1dSRodney W. Grimes * Record interface address and bring up next address 1039df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 1040df8bae1dSRodney W. Grimes * address is on directly accessible net. 1041df8bae1dSRodney W. Grimes */ 1042df8bae1dSRodney W. Grimes case IPOPT_LSRR: 1043df8bae1dSRodney W. Grimes case IPOPT_SSRR: 1044df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1045df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1046df8bae1dSRodney W. Grimes goto bad; 1047df8bae1dSRodney W. Grimes } 1048df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 1049df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 1050df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 1051df8bae1dSRodney W. Grimes if (ia == 0) { 1052df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1053df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1054df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1055df8bae1dSRodney W. Grimes goto bad; 1056df8bae1dSRodney W. Grimes } 1057bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1058bc189bf8SGuido van Rooij goto nosourcerouting; 1059df8bae1dSRodney W. Grimes /* 1060df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1061df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1062df8bae1dSRodney W. Grimes */ 1063df8bae1dSRodney W. Grimes break; 1064df8bae1dSRodney W. Grimes } 1065df8bae1dSRodney W. Grimes off--; /* 0 origin */ 1066df8bae1dSRodney W. Grimes if (off > optlen - sizeof(struct in_addr)) { 1067df8bae1dSRodney W. Grimes /* 1068df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1069df8bae1dSRodney W. Grimes */ 10704fce5804SGuido van Rooij if (!ip_acceptsourceroute) 10714fce5804SGuido van Rooij goto nosourcerouting; 1072df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 1073df8bae1dSRodney W. Grimes break; 1074df8bae1dSRodney W. Grimes } 10751025071fSGarrett Wollman 10761025071fSGarrett Wollman if (!ip_dosourceroute) { 10770af8d3ecSDavid Greenman if (ipforwarding) { 10780af8d3ecSDavid Greenman char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 10790af8d3ecSDavid Greenman /* 10800af8d3ecSDavid Greenman * Acting as a router, so generate ICMP 10810af8d3ecSDavid Greenman */ 1082efa48587SGuido van Rooij nosourcerouting: 1083bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 10841025071fSGarrett Wollman log(LOG_WARNING, 10851025071fSGarrett Wollman "attempted source route from %s to %s\n", 10861025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 10871025071fSGarrett Wollman type = ICMP_UNREACH; 10881025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 10891025071fSGarrett Wollman goto bad; 10900af8d3ecSDavid Greenman } else { 10910af8d3ecSDavid Greenman /* 10920af8d3ecSDavid Greenman * Not acting as a router, so silently drop. 10930af8d3ecSDavid Greenman */ 10940af8d3ecSDavid Greenman ipstat.ips_cantforward++; 10950af8d3ecSDavid Greenman m_freem(m); 10960af8d3ecSDavid Greenman return (1); 10970af8d3ecSDavid Greenman } 10981025071fSGarrett Wollman } 10991025071fSGarrett Wollman 1100df8bae1dSRodney W. Grimes /* 1101df8bae1dSRodney W. Grimes * locate outgoing interface 1102df8bae1dSRodney W. Grimes */ 110394a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1104df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 11051025071fSGarrett Wollman 1106df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1107df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1108df8bae1dSRodney W. Grimes #define SA struct sockaddr * 1109df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 1110df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1111df8bae1dSRodney W. Grimes } else 1112df8bae1dSRodney W. Grimes ia = ip_rtaddr(ipaddr.sin_addr); 1113df8bae1dSRodney W. Grimes if (ia == 0) { 1114df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1115df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1116df8bae1dSRodney W. Grimes goto bad; 1117df8bae1dSRodney W. Grimes } 1118df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 111994a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 112094a5d9b6SDavid Greenman sizeof(struct in_addr)); 1121df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1122df8bae1dSRodney W. Grimes /* 1123df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1124df8bae1dSRodney W. Grimes */ 1125df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1126df8bae1dSRodney W. Grimes break; 1127df8bae1dSRodney W. Grimes 1128df8bae1dSRodney W. Grimes case IPOPT_RR: 1129df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1130df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1131df8bae1dSRodney W. Grimes goto bad; 1132df8bae1dSRodney W. Grimes } 1133df8bae1dSRodney W. Grimes /* 1134df8bae1dSRodney W. Grimes * If no space remains, ignore. 1135df8bae1dSRodney W. Grimes */ 1136df8bae1dSRodney W. Grimes off--; /* 0 origin */ 1137df8bae1dSRodney W. Grimes if (off > optlen - sizeof(struct in_addr)) 1138df8bae1dSRodney W. Grimes break; 113994a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1140df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1141df8bae1dSRodney W. Grimes /* 1142df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1143df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1144df8bae1dSRodney W. Grimes */ 1145df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 1146df8bae1dSRodney W. Grimes (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 1147df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1148df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1149df8bae1dSRodney W. Grimes goto bad; 1150df8bae1dSRodney W. Grimes } 115194a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 115294a5d9b6SDavid Greenman sizeof(struct in_addr)); 1153df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1154df8bae1dSRodney W. Grimes break; 1155df8bae1dSRodney W. Grimes 1156df8bae1dSRodney W. Grimes case IPOPT_TS: 1157df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 1158df8bae1dSRodney W. Grimes ipt = (struct ip_timestamp *)cp; 1159df8bae1dSRodney W. Grimes if (ipt->ipt_len < 5) 1160df8bae1dSRodney W. Grimes goto bad; 11610c8d2590SBruce Evans if (ipt->ipt_ptr > ipt->ipt_len - sizeof(int32_t)) { 1162df8bae1dSRodney W. Grimes if (++ipt->ipt_oflw == 0) 1163df8bae1dSRodney W. Grimes goto bad; 1164df8bae1dSRodney W. Grimes break; 1165df8bae1dSRodney W. Grimes } 1166df8bae1dSRodney W. Grimes sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 1167df8bae1dSRodney W. Grimes switch (ipt->ipt_flg) { 1168df8bae1dSRodney W. Grimes 1169df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1170df8bae1dSRodney W. Grimes break; 1171df8bae1dSRodney W. Grimes 1172df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 1173b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1174df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1175df8bae1dSRodney W. Grimes goto bad; 1176df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1177df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1178df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1179df8bae1dSRodney W. Grimes if (ia == 0) 1180df8bae1dSRodney W. Grimes continue; 118194a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 118294a5d9b6SDavid Greenman sizeof(struct in_addr)); 1183df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1184df8bae1dSRodney W. Grimes break; 1185df8bae1dSRodney W. Grimes 1186df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 1187b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1188df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1189df8bae1dSRodney W. Grimes goto bad; 119094a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1191df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1192df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1193df8bae1dSRodney W. Grimes continue; 1194df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1195df8bae1dSRodney W. Grimes break; 1196df8bae1dSRodney W. Grimes 1197df8bae1dSRodney W. Grimes default: 1198df8bae1dSRodney W. Grimes goto bad; 1199df8bae1dSRodney W. Grimes } 1200df8bae1dSRodney W. Grimes ntime = iptime(); 120194a5d9b6SDavid Greenman (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime, 1202df8bae1dSRodney W. Grimes sizeof(n_time)); 1203df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(n_time); 1204df8bae1dSRodney W. Grimes } 1205df8bae1dSRodney W. Grimes } 120647174b49SAndrey A. Chernov if (forward && ipforwarding) { 1207df8bae1dSRodney W. Grimes ip_forward(m, 1); 1208df8bae1dSRodney W. Grimes return (1); 1209df8bae1dSRodney W. Grimes } 1210df8bae1dSRodney W. Grimes return (0); 1211df8bae1dSRodney W. Grimes bad: 121258938916SGarrett Wollman ip->ip_len -= IP_VHL_HL(ip->ip_vhl) << 2; /* XXX icmp_error adds in hdr length */ 1213df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1214df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1215df8bae1dSRodney W. Grimes return (1); 1216df8bae1dSRodney W. Grimes } 1217df8bae1dSRodney W. Grimes 1218df8bae1dSRodney W. Grimes /* 1219df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1220df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1221df8bae1dSRodney W. Grimes */ 12220312fbe9SPoul-Henning Kamp static struct in_ifaddr * 1223df8bae1dSRodney W. Grimes ip_rtaddr(dst) 1224df8bae1dSRodney W. Grimes struct in_addr dst; 1225df8bae1dSRodney W. Grimes { 1226df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1227df8bae1dSRodney W. Grimes 1228df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 1229df8bae1dSRodney W. Grimes 1230df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { 1231df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1232df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1233df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1234df8bae1dSRodney W. Grimes } 1235df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1236df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1237df8bae1dSRodney W. Grimes sin->sin_addr = dst; 1238df8bae1dSRodney W. Grimes 12392c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1240df8bae1dSRodney W. Grimes } 1241df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) 1242df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 1243df8bae1dSRodney W. Grimes return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); 1244df8bae1dSRodney W. Grimes } 1245df8bae1dSRodney W. Grimes 1246df8bae1dSRodney W. Grimes /* 1247df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1248df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1249df8bae1dSRodney W. Grimes */ 1250df8bae1dSRodney W. Grimes void 1251df8bae1dSRodney W. Grimes save_rte(option, dst) 1252df8bae1dSRodney W. Grimes u_char *option; 1253df8bae1dSRodney W. Grimes struct in_addr dst; 1254df8bae1dSRodney W. Grimes { 1255df8bae1dSRodney W. Grimes unsigned olen; 1256df8bae1dSRodney W. Grimes 1257df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1258df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1259df8bae1dSRodney W. Grimes if (ipprintfs) 1260df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1261df8bae1dSRodney W. Grimes #endif 1262df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1263df8bae1dSRodney W. Grimes return; 12640453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1265df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1266df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1267df8bae1dSRodney W. Grimes } 1268df8bae1dSRodney W. Grimes 1269df8bae1dSRodney W. Grimes /* 1270df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1271df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1272df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1273df8bae1dSRodney W. Grimes */ 1274df8bae1dSRodney W. Grimes struct mbuf * 1275df8bae1dSRodney W. Grimes ip_srcroute() 1276df8bae1dSRodney W. Grimes { 1277df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1278df8bae1dSRodney W. Grimes register struct mbuf *m; 1279df8bae1dSRodney W. Grimes 1280df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1281df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1282cfe8b629SGarrett Wollman m = m_get(M_DONTWAIT, MT_HEADER); 1283df8bae1dSRodney W. Grimes if (m == 0) 1284df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1285df8bae1dSRodney W. Grimes 1286df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1287df8bae1dSRodney W. Grimes 1288df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1289df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1290df8bae1dSRodney W. Grimes OPTSIZ; 1291df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1292df8bae1dSRodney W. Grimes if (ipprintfs) 1293df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1294df8bae1dSRodney W. Grimes #endif 1295df8bae1dSRodney W. Grimes 1296df8bae1dSRodney W. Grimes /* 1297df8bae1dSRodney W. Grimes * First save first hop for return route 1298df8bae1dSRodney W. Grimes */ 1299df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1300df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1301df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1302df8bae1dSRodney W. Grimes if (ipprintfs) 1303b715f178SLuigi Rizzo printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr)); 1304df8bae1dSRodney W. Grimes #endif 1305df8bae1dSRodney W. Grimes 1306df8bae1dSRodney W. Grimes /* 1307df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1308df8bae1dSRodney W. Grimes */ 1309df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1310df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 131194a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 131294a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1313df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1314df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1315df8bae1dSRodney W. Grimes #undef OPTSIZ 1316df8bae1dSRodney W. Grimes /* 1317df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1318df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1319df8bae1dSRodney W. Grimes */ 1320df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1321df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1322df8bae1dSRodney W. Grimes if (ipprintfs) 1323b715f178SLuigi Rizzo printf(" %lx", ntohl(q->s_addr)); 1324df8bae1dSRodney W. Grimes #endif 1325df8bae1dSRodney W. Grimes *q++ = *p--; 1326df8bae1dSRodney W. Grimes } 1327df8bae1dSRodney W. Grimes /* 1328df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1329df8bae1dSRodney W. Grimes */ 1330df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1331df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1332df8bae1dSRodney W. Grimes if (ipprintfs) 1333b715f178SLuigi Rizzo printf(" %lx\n", ntohl(q->s_addr)); 1334df8bae1dSRodney W. Grimes #endif 1335df8bae1dSRodney W. Grimes return (m); 1336df8bae1dSRodney W. Grimes } 1337df8bae1dSRodney W. Grimes 1338df8bae1dSRodney W. Grimes /* 1339df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1340df8bae1dSRodney W. Grimes * level protocol in the kernel. 1341df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1342df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1343df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1344df8bae1dSRodney W. Grimes */ 1345df8bae1dSRodney W. Grimes void 1346df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1347df8bae1dSRodney W. Grimes register struct mbuf *m; 1348df8bae1dSRodney W. Grimes struct mbuf *mopt; 1349df8bae1dSRodney W. Grimes { 1350df8bae1dSRodney W. Grimes register int i; 1351df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1352df8bae1dSRodney W. Grimes register caddr_t opts; 1353df8bae1dSRodney W. Grimes int olen; 1354df8bae1dSRodney W. Grimes 135558938916SGarrett Wollman olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1356df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1357df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1358df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1359df8bae1dSRodney W. Grimes m->m_len -= olen; 1360df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1361df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 136258938916SGarrett Wollman ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); 1363df8bae1dSRodney W. Grimes } 1364df8bae1dSRodney W. Grimes 1365df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1366df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1367df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1368df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1369df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1370df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1371df8bae1dSRodney W. Grimes ENOPROTOOPT 1372df8bae1dSRodney W. Grimes }; 1373df8bae1dSRodney W. Grimes 1374df8bae1dSRodney W. Grimes /* 1375df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1376df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1377df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1378df8bae1dSRodney W. Grimes * of codes and types. 1379df8bae1dSRodney W. Grimes * 1380df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1381df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1382df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1383df8bae1dSRodney W. Grimes * protocol deal with that. 1384df8bae1dSRodney W. Grimes * 1385df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1386df8bae1dSRodney W. Grimes * via a source route. 1387df8bae1dSRodney W. Grimes */ 13880312fbe9SPoul-Henning Kamp static void 1389df8bae1dSRodney W. Grimes ip_forward(m, srcrt) 1390df8bae1dSRodney W. Grimes struct mbuf *m; 1391df8bae1dSRodney W. Grimes int srcrt; 1392df8bae1dSRodney W. Grimes { 1393df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1394df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1395df8bae1dSRodney W. Grimes register struct rtentry *rt; 139626f9a767SRodney W. Grimes int error, type = 0, code = 0; 1397df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1398df8bae1dSRodney W. Grimes n_long dest; 1399df8bae1dSRodney W. Grimes struct ifnet *destifp; 1400df8bae1dSRodney W. Grimes 1401df8bae1dSRodney W. Grimes dest = 0; 1402df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1403df8bae1dSRodney W. Grimes if (ipprintfs) 140461ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 1405162886e2SBruce Evans (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr, 1406162886e2SBruce Evans ip->ip_ttl); 1407df8bae1dSRodney W. Grimes #endif 1408100ba1a6SJordan K. Hubbard 1409100ba1a6SJordan K. Hubbard 1410df8bae1dSRodney W. Grimes if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) { 1411df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1412df8bae1dSRodney W. Grimes m_freem(m); 1413df8bae1dSRodney W. Grimes return; 1414df8bae1dSRodney W. Grimes } 1415df8bae1dSRodney W. Grimes HTONS(ip->ip_id); 1416df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 1417df8bae1dSRodney W. Grimes icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); 1418df8bae1dSRodney W. Grimes return; 1419df8bae1dSRodney W. Grimes } 1420df8bae1dSRodney W. Grimes ip->ip_ttl -= IPTTLDEC; 1421df8bae1dSRodney W. Grimes 1422df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; 1423df8bae1dSRodney W. Grimes if ((rt = ipforward_rt.ro_rt) == 0 || 1424df8bae1dSRodney W. Grimes ip->ip_dst.s_addr != sin->sin_addr.s_addr) { 1425df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1426df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1427df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1428df8bae1dSRodney W. Grimes } 1429df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1430df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1431df8bae1dSRodney W. Grimes sin->sin_addr = ip->ip_dst; 1432df8bae1dSRodney W. Grimes 14332c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1434df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) { 1435df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1436df8bae1dSRodney W. Grimes return; 1437df8bae1dSRodney W. Grimes } 1438df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1439df8bae1dSRodney W. Grimes } 1440df8bae1dSRodney W. Grimes 1441df8bae1dSRodney W. Grimes /* 1442df8bae1dSRodney W. Grimes * Save at most 64 bytes of the packet in case 1443df8bae1dSRodney W. Grimes * we need to generate an ICMP message to the src. 1444df8bae1dSRodney W. Grimes */ 1445df8bae1dSRodney W. Grimes mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); 1446df8bae1dSRodney W. Grimes 1447df8bae1dSRodney W. Grimes /* 1448df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1449df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1450df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1451df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1452df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1453df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1454df8bae1dSRodney W. Grimes */ 1455df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 1456df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1457df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1458df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 1459df8bae1dSRodney W. Grimes ipsendredirects && !srcrt) { 1460df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1461df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1462df8bae1dSRodney W. Grimes 1463df8bae1dSRodney W. Grimes if (RTA(rt) && 1464df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1465df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1466df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1467df8bae1dSRodney W. Grimes else 1468df8bae1dSRodney W. Grimes dest = ip->ip_dst.s_addr; 1469df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1470df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1471df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1472df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1473df8bae1dSRodney W. Grimes if (ipprintfs) 1474df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1475df8bae1dSRodney W. Grimes #endif 1476df8bae1dSRodney W. Grimes } 1477df8bae1dSRodney W. Grimes } 1478df8bae1dSRodney W. Grimes 1479b97d15cbSGarrett Wollman error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 1480b97d15cbSGarrett Wollman IP_FORWARDING, 0); 1481df8bae1dSRodney W. Grimes if (error) 1482df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1483df8bae1dSRodney W. Grimes else { 1484df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1485df8bae1dSRodney W. Grimes if (type) 1486df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1487df8bae1dSRodney W. Grimes else { 14881f91d8c5SDavid Greenman if (mcopy) { 14891f91d8c5SDavid Greenman ipflow_create(&ipforward_rt, mcopy); 1490df8bae1dSRodney W. Grimes m_freem(mcopy); 14911f91d8c5SDavid Greenman } 1492df8bae1dSRodney W. Grimes return; 1493df8bae1dSRodney W. Grimes } 1494df8bae1dSRodney W. Grimes } 1495df8bae1dSRodney W. Grimes if (mcopy == NULL) 1496df8bae1dSRodney W. Grimes return; 1497df8bae1dSRodney W. Grimes destifp = NULL; 1498df8bae1dSRodney W. Grimes 1499df8bae1dSRodney W. Grimes switch (error) { 1500df8bae1dSRodney W. Grimes 1501df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1502df8bae1dSRodney W. Grimes /* type, code set above */ 1503df8bae1dSRodney W. Grimes break; 1504df8bae1dSRodney W. Grimes 1505df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1506df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1507df8bae1dSRodney W. Grimes case ENETDOWN: 1508df8bae1dSRodney W. Grimes case EHOSTDOWN: 1509df8bae1dSRodney W. Grimes default: 1510df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1511df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1512df8bae1dSRodney W. Grimes break; 1513df8bae1dSRodney W. Grimes 1514df8bae1dSRodney W. Grimes case EMSGSIZE: 1515df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1516df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 1517df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) 1518df8bae1dSRodney W. Grimes destifp = ipforward_rt.ro_rt->rt_ifp; 1519df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1520df8bae1dSRodney W. Grimes break; 1521df8bae1dSRodney W. Grimes 1522df8bae1dSRodney W. Grimes case ENOBUFS: 1523df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1524df8bae1dSRodney W. Grimes code = 0; 1525df8bae1dSRodney W. Grimes break; 1526df8bae1dSRodney W. Grimes } 1527df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1528df8bae1dSRodney W. Grimes } 1529df8bae1dSRodney W. Grimes 153082c23ebaSBill Fenner void 153182c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 153282c23ebaSBill Fenner register struct inpcb *inp; 153382c23ebaSBill Fenner register struct mbuf **mp; 153482c23ebaSBill Fenner register struct ip *ip; 153582c23ebaSBill Fenner register struct mbuf *m; 153682c23ebaSBill Fenner { 153782c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 153882c23ebaSBill Fenner struct timeval tv; 153982c23ebaSBill Fenner 154082c23ebaSBill Fenner microtime(&tv); 154182c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 154282c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 154382c23ebaSBill Fenner if (*mp) 154482c23ebaSBill Fenner mp = &(*mp)->m_next; 154582c23ebaSBill Fenner } 154682c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 154782c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 154882c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 154982c23ebaSBill Fenner if (*mp) 155082c23ebaSBill Fenner mp = &(*mp)->m_next; 155182c23ebaSBill Fenner } 155282c23ebaSBill Fenner #ifdef notyet 155382c23ebaSBill Fenner /* XXX 155482c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 155582c23ebaSBill Fenner * than they already were. 155682c23ebaSBill Fenner */ 155782c23ebaSBill Fenner /* options were tossed already */ 155882c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 155982c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 156082c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 156182c23ebaSBill Fenner if (*mp) 156282c23ebaSBill Fenner mp = &(*mp)->m_next; 156382c23ebaSBill Fenner } 156482c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 156582c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 156682c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 156782c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 156882c23ebaSBill Fenner if (*mp) 156982c23ebaSBill Fenner mp = &(*mp)->m_next; 157082c23ebaSBill Fenner } 157182c23ebaSBill Fenner #endif 157282c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 1573d314ad7bSJulian Elischer struct ifnet *ifp; 1574d314ad7bSJulian Elischer struct sdlbuf { 157582c23ebaSBill Fenner struct sockaddr_dl sdl; 1576d314ad7bSJulian Elischer u_char pad[32]; 1577d314ad7bSJulian Elischer } sdlbuf; 1578d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 1579d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 158082c23ebaSBill Fenner 1581d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 1582d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 1583d314ad7bSJulian Elischer sdp = (struct sockaddr_dl *)(ifnet_addrs 1584d314ad7bSJulian Elischer [ifp->if_index - 1]->ifa_addr); 1585d314ad7bSJulian Elischer /* 1586d314ad7bSJulian Elischer * Change our mind and don't try copy. 1587d314ad7bSJulian Elischer */ 1588d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 1589d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 1590d314ad7bSJulian Elischer goto makedummy; 1591d314ad7bSJulian Elischer } 1592d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 1593d314ad7bSJulian Elischer } else { 1594d314ad7bSJulian Elischer makedummy: 1595d314ad7bSJulian Elischer sdl2->sdl_len 1596d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 1597d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 1598d314ad7bSJulian Elischer sdl2->sdl_index = 0; 1599d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 1600d314ad7bSJulian Elischer } 1601d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 160282c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 160382c23ebaSBill Fenner if (*mp) 160482c23ebaSBill Fenner mp = &(*mp)->m_next; 160582c23ebaSBill Fenner } 160682c23ebaSBill Fenner } 160782c23ebaSBill Fenner 1608df8bae1dSRodney W. Grimes int 1609f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 1610f0068c4aSGarrett Wollman { 1611f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 1612f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 1613f0068c4aSGarrett Wollman return EOPNOTSUPP; 1614f0068c4aSGarrett Wollman 1615f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 1616f0068c4aSGarrett Wollman return EADDRINUSE; 1617f0068c4aSGarrett Wollman 1618f0068c4aSGarrett Wollman ip_rsvpd = so; 16191c5de19aSGarrett Wollman /* 16201c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 16211c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 16221c5de19aSGarrett Wollman */ 16231c5de19aSGarrett Wollman if (!ip_rsvp_on) { 16241c5de19aSGarrett Wollman ip_rsvp_on = 1; 16251c5de19aSGarrett Wollman rsvp_on++; 16261c5de19aSGarrett Wollman } 1627f0068c4aSGarrett Wollman 1628f0068c4aSGarrett Wollman return 0; 1629f0068c4aSGarrett Wollman } 1630f0068c4aSGarrett Wollman 1631f0068c4aSGarrett Wollman int 1632f0068c4aSGarrett Wollman ip_rsvp_done(void) 1633f0068c4aSGarrett Wollman { 1634f0068c4aSGarrett Wollman ip_rsvpd = NULL; 16351c5de19aSGarrett Wollman /* 16361c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 16371c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 16381c5de19aSGarrett Wollman */ 16391c5de19aSGarrett Wollman if (ip_rsvp_on) { 16401c5de19aSGarrett Wollman ip_rsvp_on = 0; 16411c5de19aSGarrett Wollman rsvp_on--; 16421c5de19aSGarrett Wollman } 1643f0068c4aSGarrett Wollman return 0; 1644f0068c4aSGarrett Wollman } 1645