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 34cc766e04SGarrett Wollman * $Id: ip_input.c,v 1.113 1999/01/27 22:42:25 dillon Exp $ 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" 4474a9466cSGary Palmer 4582c23ebaSBill Fenner #include <stddef.h> 4682c23ebaSBill Fenner 47df8bae1dSRodney W. Grimes #include <sys/param.h> 48df8bae1dSRodney W. Grimes #include <sys/systm.h> 49df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 50b715f178SLuigi Rizzo #include <sys/malloc.h> 51df8bae1dSRodney W. Grimes #include <sys/domain.h> 52df8bae1dSRodney W. Grimes #include <sys/protosw.h> 53df8bae1dSRodney W. Grimes #include <sys/socket.h> 54df8bae1dSRodney W. Grimes #include <sys/time.h> 55df8bae1dSRodney W. Grimes #include <sys/kernel.h> 561025071fSGarrett Wollman #include <sys/syslog.h> 57b5e8ce9fSBruce Evans #include <sys/sysctl.h> 58df8bae1dSRodney W. Grimes 59df8bae1dSRodney W. Grimes #include <net/if.h> 60d314ad7bSJulian Elischer #include <net/if_var.h> 6182c23ebaSBill Fenner #include <net/if_dl.h> 62df8bae1dSRodney W. Grimes #include <net/route.h> 63748e0b0aSGarrett Wollman #include <net/netisr.h> 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes #include <netinet/in.h> 66df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 67b5e8ce9fSBruce Evans #include <netinet/in_var.h> 68df8bae1dSRodney W. Grimes #include <netinet/ip.h> 69df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 70df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 71df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h> 7258938916SGarrett Wollman #include <machine/in_cksum.h> 73df8bae1dSRodney W. Grimes 74f0068c4aSGarrett Wollman #include <sys/socketvar.h> 756ddbf1e2SGary Palmer 766ddbf1e2SGary Palmer #ifdef IPFIREWALL 776ddbf1e2SGary Palmer #include <netinet/ip_fw.h> 786ddbf1e2SGary Palmer #endif 796ddbf1e2SGary Palmer 80b715f178SLuigi Rizzo #ifdef DUMMYNET 81b715f178SLuigi Rizzo #include <netinet/ip_dummynet.h> 82b715f178SLuigi Rizzo #endif 83b715f178SLuigi Rizzo 841c5de19aSGarrett Wollman int rsvp_on = 0; 85f708ef1bSPoul-Henning Kamp static int ip_rsvp_on; 86f0068c4aSGarrett Wollman struct socket *ip_rsvpd; 87f0068c4aSGarrett Wollman 881f91d8c5SDavid Greenman int ipforwarding = 0; 890312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, 900312fbe9SPoul-Henning Kamp &ipforwarding, 0, ""); 910312fbe9SPoul-Henning Kamp 92d4fb926cSGarrett Wollman static int ipsendredirects = 1; /* XXX */ 930312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, 940312fbe9SPoul-Henning Kamp &ipsendredirects, 0, ""); 950312fbe9SPoul-Henning Kamp 96df8bae1dSRodney W. Grimes int ip_defttl = IPDEFTTL; 970312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW, 980312fbe9SPoul-Henning Kamp &ip_defttl, 0, ""); 990312fbe9SPoul-Henning Kamp 1000312fbe9SPoul-Henning Kamp static int ip_dosourceroute = 0; 1010312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW, 1020312fbe9SPoul-Henning Kamp &ip_dosourceroute, 0, ""); 1034fce5804SGuido van Rooij 1044fce5804SGuido van Rooij static int ip_acceptsourceroute = 0; 1054fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute, 1064fce5804SGuido van Rooij CTLFLAG_RW, &ip_acceptsourceroute, 0, ""); 107df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1080312fbe9SPoul-Henning Kamp static int ipprintfs = 0; 109df8bae1dSRodney W. Grimes #endif 110df8bae1dSRodney W. Grimes 111df8bae1dSRodney W. Grimes extern struct domain inetdomain; 112df8bae1dSRodney W. Grimes extern struct protosw inetsw[]; 113df8bae1dSRodney W. Grimes u_char ip_protox[IPPROTO_MAX]; 1140312fbe9SPoul-Henning Kamp static int ipqmaxlen = IFQ_MAXLEN; 11559562606SGarrett Wollman struct in_ifaddrhead in_ifaddrhead; /* first inet address */ 116df8bae1dSRodney W. Grimes struct ifqueue ipintrq; 1170312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RD, 1180312fbe9SPoul-Henning Kamp &ipintrq.ifq_maxlen, 0, ""); 1190312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD, 1200312fbe9SPoul-Henning Kamp &ipintrq.ifq_drops, 0, ""); 121df8bae1dSRodney W. Grimes 122f23b4c91SGarrett Wollman struct ipstat ipstat; 1236fce01c9SGarrett Wollman SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD, 1246fce01c9SGarrett Wollman &ipstat, ipstat, ""); 125194a213eSAndrey A. Chernov 126194a213eSAndrey A. Chernov /* Packet reassembly stuff */ 127194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2 6 128194a213eSAndrey A. Chernov #define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2) 129194a213eSAndrey A. Chernov #define IPREASS_HMASK (IPREASS_NHASH - 1) 130194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \ 131831a80b0SMatthew Dillon (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK) 132194a213eSAndrey A. Chernov 133194a213eSAndrey A. Chernov static struct ipq ipq[IPREASS_NHASH]; 134194a213eSAndrey A. Chernov static int nipq = 0; /* total # of reass queues */ 135194a213eSAndrey A. Chernov static int maxnipq; 136f23b4c91SGarrett Wollman 1370312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU 1380312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW, 1390312fbe9SPoul-Henning Kamp &ip_mtu, 0, ""); 1400312fbe9SPoul-Henning Kamp #endif 1410312fbe9SPoul-Henning Kamp 14258938916SGarrett Wollman #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 14358938916SGarrett Wollman #undef COMPAT_IPFW 14458938916SGarrett Wollman #define COMPAT_IPFW 1 14558938916SGarrett Wollman #else 14658938916SGarrett Wollman #undef COMPAT_IPFW 14758938916SGarrett Wollman #endif 14858938916SGarrett Wollman 14958938916SGarrett Wollman #ifdef COMPAT_IPFW 150cfe8b629SGarrett Wollman 151cfe8b629SGarrett Wollman #include <netinet/ip_fw.h> 152cfe8b629SGarrett Wollman 15323bf9953SPoul-Henning Kamp /* Firewall hooks */ 15423bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr; 15523bf9953SPoul-Henning Kamp ip_fw_ctl_t *ip_fw_ctl_ptr; 156e7319babSPoul-Henning Kamp 157b715f178SLuigi Rizzo #ifdef DUMMYNET 158b715f178SLuigi Rizzo ip_dn_ctl_t *ip_dn_ctl_ptr; 159b715f178SLuigi Rizzo #endif 160b715f178SLuigi Rizzo 161fed1c7e9SSøren Schmidt /* IP Network Address Translation (NAT) hooks */ 162fed1c7e9SSøren Schmidt ip_nat_t *ip_nat_ptr; 163fed1c7e9SSøren Schmidt ip_nat_ctl_t *ip_nat_ctl_ptr; 16458938916SGarrett Wollman #endif 165fed1c7e9SSøren Schmidt 166afed1b49SDarren Reed #if defined(IPFILTER_LKM) || defined(IPFILTER) 1671ee25934SPeter Wemm int iplattach __P((void)); 168afed1b49SDarren Reed int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)) = NULL; 169afed1b49SDarren Reed #endif 170afed1b49SDarren Reed 171afed1b49SDarren Reed 172e7319babSPoul-Henning Kamp /* 173df8bae1dSRodney W. Grimes * We need to save the IP options in case a protocol wants to respond 174df8bae1dSRodney W. Grimes * to an incoming packet over the same route if the packet got here 175df8bae1dSRodney W. Grimes * using IP source routing. This allows connection establishment and 176df8bae1dSRodney W. Grimes * maintenance when the remote end is on a network that is not known 177df8bae1dSRodney W. Grimes * to us. 178df8bae1dSRodney W. Grimes */ 1790312fbe9SPoul-Henning Kamp static int ip_nhops = 0; 180df8bae1dSRodney W. Grimes static struct ip_srcrt { 181df8bae1dSRodney W. Grimes struct in_addr dst; /* final destination */ 182df8bae1dSRodney W. Grimes char nop; /* one NOP to align */ 183df8bae1dSRodney W. Grimes char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ 184df8bae1dSRodney W. Grimes struct in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)]; 185df8bae1dSRodney W. Grimes } ip_srcrt; 186df8bae1dSRodney W. Grimes 18793e0e116SJulian Elischer #ifdef IPDIVERT 18893e0e116SJulian Elischer /* 18993e0e116SJulian Elischer * Shared variable between ip_input() and ip_reass() to communicate 19093e0e116SJulian Elischer * about which packets, once assembled from fragments, get diverted, 19193e0e116SJulian Elischer * and to which port. 19293e0e116SJulian Elischer */ 19393e0e116SJulian Elischer static u_short frag_divert_port; 19493e0e116SJulian Elischer #endif 19593e0e116SJulian Elischer 196f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr; 197f9e354dfSJulian Elischer 198df8bae1dSRodney W. Grimes static void save_rte __P((u_char *, struct in_addr)); 1990312fbe9SPoul-Henning Kamp static int ip_dooptions __P((struct mbuf *)); 2000312fbe9SPoul-Henning Kamp static void ip_forward __P((struct mbuf *, int)); 2010312fbe9SPoul-Henning Kamp static void ip_freef __P((struct ipq *)); 2020312fbe9SPoul-Henning Kamp static struct ip * 2036effc713SDoug Rabson ip_reass __P((struct mbuf *, struct ipq *, struct ipq *)); 2040312fbe9SPoul-Henning Kamp static struct in_ifaddr * 2050312fbe9SPoul-Henning Kamp ip_rtaddr __P((struct in_addr)); 2060312fbe9SPoul-Henning Kamp static void ipintr __P((void)); 207df8bae1dSRodney W. Grimes /* 208df8bae1dSRodney W. Grimes * IP initialization: fill in IP protocol switch table. 209df8bae1dSRodney W. Grimes * All protocols not implemented in kernel go to raw IP protocol handler. 210df8bae1dSRodney W. Grimes */ 211df8bae1dSRodney W. Grimes void 212df8bae1dSRodney W. Grimes ip_init() 213df8bae1dSRodney W. Grimes { 214df8bae1dSRodney W. Grimes register struct protosw *pr; 215df8bae1dSRodney W. Grimes register int i; 216df8bae1dSRodney W. Grimes 21759562606SGarrett Wollman TAILQ_INIT(&in_ifaddrhead); 218df8bae1dSRodney W. Grimes pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); 219df8bae1dSRodney W. Grimes if (pr == 0) 220df8bae1dSRodney W. Grimes panic("ip_init"); 221df8bae1dSRodney W. Grimes for (i = 0; i < IPPROTO_MAX; i++) 222df8bae1dSRodney W. Grimes ip_protox[i] = pr - inetsw; 223df8bae1dSRodney W. Grimes for (pr = inetdomain.dom_protosw; 224df8bae1dSRodney W. Grimes pr < inetdomain.dom_protoswNPROTOSW; pr++) 225df8bae1dSRodney W. Grimes if (pr->pr_domain->dom_family == PF_INET && 226df8bae1dSRodney W. Grimes pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 227df8bae1dSRodney W. Grimes ip_protox[pr->pr_protocol] = pr - inetsw; 228194a213eSAndrey A. Chernov 229194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) 230194a213eSAndrey A. Chernov ipq[i].next = ipq[i].prev = &ipq[i]; 231194a213eSAndrey A. Chernov 232194a213eSAndrey A. Chernov maxnipq = nmbclusters/4; 233194a213eSAndrey A. Chernov 234227ee8a1SPoul-Henning Kamp ip_id = time_second & 0xffff; 235df8bae1dSRodney W. Grimes ipintrq.ifq_maxlen = ipqmaxlen; 236b715f178SLuigi Rizzo #ifdef DUMMYNET 237b715f178SLuigi Rizzo ip_dn_init(); 238b715f178SLuigi Rizzo #endif 239fed1c7e9SSøren Schmidt #ifdef IPNAT 240fed1c7e9SSøren Schmidt ip_nat_init(); 241fed1c7e9SSøren Schmidt #endif 2421ee25934SPeter Wemm #ifdef IPFILTER 2431ee25934SPeter Wemm iplattach(); 2441ee25934SPeter Wemm #endif 245fed1c7e9SSøren Schmidt 246df8bae1dSRodney W. Grimes } 247df8bae1dSRodney W. Grimes 2480312fbe9SPoul-Henning Kamp static struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; 249f708ef1bSPoul-Henning Kamp static struct route ipforward_rt; 250df8bae1dSRodney W. Grimes 251df8bae1dSRodney W. Grimes /* 252df8bae1dSRodney W. Grimes * Ip input routine. Checksum and byte swap header. If fragmented 253df8bae1dSRodney W. Grimes * try to reassemble. Process options. Pass to next level. 254df8bae1dSRodney W. Grimes */ 255c67b1d17SGarrett Wollman void 256c67b1d17SGarrett Wollman ip_input(struct mbuf *m) 257df8bae1dSRodney W. Grimes { 25823bf9953SPoul-Henning Kamp struct ip *ip; 25923bf9953SPoul-Henning Kamp struct ipq *fp; 26023bf9953SPoul-Henning Kamp struct in_ifaddr *ia; 2616effc713SDoug Rabson int i, hlen, mff; 26247c861ecSBrian Somers u_short sum; 263b715f178SLuigi Rizzo #ifndef IPDIVERT /* dummy variable for the firewall code to play with */ 264b715f178SLuigi Rizzo u_short ip_divert_cookie = 0 ; 265b715f178SLuigi Rizzo #endif 266b715f178SLuigi Rizzo #ifdef COMPAT_IPFW 267b715f178SLuigi Rizzo struct ip_fw_chain *rule = NULL ; 268b715f178SLuigi Rizzo #endif 269b715f178SLuigi Rizzo 270b715f178SLuigi Rizzo #if defined(IPFIREWALL) && defined(DUMMYNET) 271b715f178SLuigi Rizzo /* 272b715f178SLuigi Rizzo * dummynet packet are prepended a vestigial mbuf with 273b715f178SLuigi Rizzo * m_type = MT_DUMMYNET and m_data pointing to the matching 274b715f178SLuigi Rizzo * rule. 275b715f178SLuigi Rizzo */ 276b715f178SLuigi Rizzo if (m->m_type == MT_DUMMYNET) { 277b715f178SLuigi Rizzo struct mbuf *m0 = m ; 278b715f178SLuigi Rizzo rule = (struct ip_fw_chain *)(m->m_data) ; 279b715f178SLuigi Rizzo m = m->m_next ; 280b715f178SLuigi Rizzo free(m0, M_IPFW); 281b715f178SLuigi Rizzo ip = mtod(m, struct ip *); 282b715f178SLuigi Rizzo hlen = IP_VHL_HL(ip->ip_vhl) << 2; 283b715f178SLuigi Rizzo goto iphack ; 284b715f178SLuigi Rizzo } else 285b715f178SLuigi Rizzo rule = NULL ; 286b715f178SLuigi Rizzo #endif 287df8bae1dSRodney W. Grimes 288df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 289ed7509acSJulian Elischer if (m == NULL || (m->m_flags & M_PKTHDR) == 0) 29058938916SGarrett Wollman panic("ip_input no HDR"); 291df8bae1dSRodney W. Grimes #endif 292df8bae1dSRodney W. Grimes ipstat.ips_total++; 29358938916SGarrett Wollman 29458938916SGarrett Wollman if (m->m_pkthdr.len < sizeof(struct ip)) 29558938916SGarrett Wollman goto tooshort; 29658938916SGarrett Wollman 297df8bae1dSRodney W. Grimes if (m->m_len < sizeof (struct ip) && 298df8bae1dSRodney W. Grimes (m = m_pullup(m, sizeof (struct ip))) == 0) { 299df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 300c67b1d17SGarrett Wollman return; 301df8bae1dSRodney W. Grimes } 302df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 30358938916SGarrett Wollman 30458938916SGarrett Wollman if (IP_VHL_V(ip->ip_vhl) != IPVERSION) { 305df8bae1dSRodney W. Grimes ipstat.ips_badvers++; 306df8bae1dSRodney W. Grimes goto bad; 307df8bae1dSRodney W. Grimes } 30858938916SGarrett Wollman 30958938916SGarrett Wollman hlen = IP_VHL_HL(ip->ip_vhl) << 2; 310df8bae1dSRodney W. Grimes if (hlen < sizeof(struct ip)) { /* minimum header length */ 311df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 312df8bae1dSRodney W. Grimes goto bad; 313df8bae1dSRodney W. Grimes } 314df8bae1dSRodney W. Grimes if (hlen > m->m_len) { 315df8bae1dSRodney W. Grimes if ((m = m_pullup(m, hlen)) == 0) { 316df8bae1dSRodney W. Grimes ipstat.ips_badhlen++; 317c67b1d17SGarrett Wollman return; 318df8bae1dSRodney W. Grimes } 319df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 320df8bae1dSRodney W. Grimes } 32158938916SGarrett Wollman if (hlen == sizeof(struct ip)) { 32247c861ecSBrian Somers sum = in_cksum_hdr(ip); 32358938916SGarrett Wollman } else { 32447c861ecSBrian Somers sum = in_cksum(m, hlen); 32558938916SGarrett Wollman } 32647c861ecSBrian Somers if (sum) { 327df8bae1dSRodney W. Grimes ipstat.ips_badsum++; 328df8bae1dSRodney W. Grimes goto bad; 329df8bae1dSRodney W. Grimes } 330df8bae1dSRodney W. Grimes 331df8bae1dSRodney W. Grimes /* 332df8bae1dSRodney W. Grimes * Convert fields to host representation. 333df8bae1dSRodney W. Grimes */ 334df8bae1dSRodney W. Grimes NTOHS(ip->ip_len); 335df8bae1dSRodney W. Grimes if (ip->ip_len < hlen) { 336df8bae1dSRodney W. Grimes ipstat.ips_badlen++; 337df8bae1dSRodney W. Grimes goto bad; 338df8bae1dSRodney W. Grimes } 339df8bae1dSRodney W. Grimes NTOHS(ip->ip_id); 340df8bae1dSRodney W. Grimes NTOHS(ip->ip_off); 341df8bae1dSRodney W. Grimes 342df8bae1dSRodney W. Grimes /* 343df8bae1dSRodney W. Grimes * Check that the amount of data in the buffers 344df8bae1dSRodney W. Grimes * is as at least much as the IP header would have us expect. 345df8bae1dSRodney W. Grimes * Trim mbufs if longer than we expect. 346df8bae1dSRodney W. Grimes * Drop packet if shorter than we expect. 347df8bae1dSRodney W. Grimes */ 348df8bae1dSRodney W. Grimes if (m->m_pkthdr.len < ip->ip_len) { 34958938916SGarrett Wollman tooshort: 350df8bae1dSRodney W. Grimes ipstat.ips_tooshort++; 351df8bae1dSRodney W. Grimes goto bad; 352df8bae1dSRodney W. Grimes } 353df8bae1dSRodney W. Grimes if (m->m_pkthdr.len > ip->ip_len) { 354df8bae1dSRodney W. Grimes if (m->m_len == m->m_pkthdr.len) { 355df8bae1dSRodney W. Grimes m->m_len = ip->ip_len; 356df8bae1dSRodney W. Grimes m->m_pkthdr.len = ip->ip_len; 357df8bae1dSRodney W. Grimes } else 358df8bae1dSRodney W. Grimes m_adj(m, ip->ip_len - m->m_pkthdr.len); 359df8bae1dSRodney W. Grimes } 3604dd1662bSUgen J.S. Antsilevich /* 3614dd1662bSUgen J.S. Antsilevich * IpHack's section. 3624dd1662bSUgen J.S. Antsilevich * Right now when no processing on packet has done 3634dd1662bSUgen J.S. Antsilevich * and it is still fresh out of network we do our black 3644dd1662bSUgen J.S. Antsilevich * deals with it. 36593e0e116SJulian Elischer * - Firewall: deny/allow/divert 366fed1c7e9SSøren Schmidt * - Xlate: translate packet's addr/port (NAT). 367b715f178SLuigi Rizzo * - Pipe: pass pkt through dummynet. 3684dd1662bSUgen J.S. Antsilevich * - Wrap: fake packet's addr/port <unimpl.> 3694dd1662bSUgen J.S. Antsilevich * - Encapsulate: put it in another IP and send out. <unimp.> 3704dd1662bSUgen J.S. Antsilevich */ 371b715f178SLuigi Rizzo 372dee383e0SEivind Eklund #if defined(IPFIREWALL) && defined(DUMMYNET) 373b715f178SLuigi Rizzo iphack: 374dee383e0SEivind Eklund #endif 375beec8214SDarren Reed #if defined(IPFILTER) || defined(IPFILTER_LKM) 376beec8214SDarren Reed /* 377beec8214SDarren Reed * Check if we want to allow this packet to be processed. 378beec8214SDarren Reed * Consider it to be bad if not. 379beec8214SDarren Reed */ 3801ee25934SPeter Wemm if (fr_checkp) { 381beec8214SDarren Reed struct mbuf *m1 = m; 382df8bae1dSRodney W. Grimes 383beec8214SDarren Reed if ((*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m1) || !m1) 384beec8214SDarren Reed return; 385beec8214SDarren Reed ip = mtod(m = m1, struct ip *); 386beec8214SDarren Reed } 387beec8214SDarren Reed #endif 38858938916SGarrett Wollman #ifdef COMPAT_IPFW 38993e0e116SJulian Elischer if (ip_fw_chk_ptr) { 390f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 391f9e354dfSJulian Elischer /* 392f9e354dfSJulian Elischer * If we've been forwarded from the output side, then 393f9e354dfSJulian Elischer * skip the firewall a second time 394f9e354dfSJulian Elischer */ 395f9e354dfSJulian Elischer if (ip_fw_fwd_addr) 396f9e354dfSJulian Elischer goto ours; 397f9e354dfSJulian Elischer #endif /* IPFIREWALL_FORWARD */ 398b715f178SLuigi Rizzo i = (*ip_fw_chk_ptr)(&ip, hlen, NULL, &ip_divert_cookie, 399b715f178SLuigi Rizzo &m, &rule, &ip_fw_fwd_addr); 400f9e354dfSJulian Elischer /* 401b715f178SLuigi Rizzo * see the comment in ip_output for the return values 402b715f178SLuigi Rizzo * produced by the firewall. 403f9e354dfSJulian Elischer */ 404b715f178SLuigi Rizzo if (!m) /* packet discarded by firewall */ 405b715f178SLuigi Rizzo return ; 406b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr == NULL) /* common case */ 407b715f178SLuigi Rizzo goto pass ; 408b715f178SLuigi Rizzo #ifdef DUMMYNET 409b715f178SLuigi Rizzo if (i & 0x10000) { 410b715f178SLuigi Rizzo /* send packet to the appropriate pipe */ 411b715f178SLuigi Rizzo dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule); 412e4676ba6SJulian Elischer return ; 41393e0e116SJulian Elischer } 414b715f178SLuigi Rizzo #endif 415b715f178SLuigi Rizzo #ifdef IPDIVERT 416b715f178SLuigi Rizzo if (i > 0 && i < 0x10000) { 417b715f178SLuigi Rizzo /* Divert packet */ 418b715f178SLuigi Rizzo frag_divert_port = i & 0xffff ; 419b715f178SLuigi Rizzo goto ours; 420b715f178SLuigi Rizzo } 421b715f178SLuigi Rizzo #endif 422b715f178SLuigi Rizzo #ifdef IPFIREWALL_FORWARD 423b715f178SLuigi Rizzo if (i == 0 && ip_fw_fwd_addr != NULL) 424b715f178SLuigi Rizzo goto pass ; 425b715f178SLuigi Rizzo #endif 426b715f178SLuigi Rizzo /* 427b715f178SLuigi Rizzo * if we get here, the packet must be dropped 428b715f178SLuigi Rizzo */ 429b715f178SLuigi Rizzo m_freem(m); 430b715f178SLuigi Rizzo return; 431b715f178SLuigi Rizzo } 432b715f178SLuigi Rizzo pass: 433100ba1a6SJordan K. Hubbard 4346713d4a7SSøren Schmidt if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, m->m_pkthdr.rcvif, IP_NAT_IN)) 435fed1c7e9SSøren Schmidt return; 436f9e354dfSJulian Elischer #endif /* !COMPAT_IPFW */ 437fed1c7e9SSøren Schmidt 438df8bae1dSRodney W. Grimes /* 439df8bae1dSRodney W. Grimes * Process options and, if not destined for us, 440df8bae1dSRodney W. Grimes * ship it on. ip_dooptions returns 1 when an 441df8bae1dSRodney W. Grimes * error was detected (causing an icmp message 442df8bae1dSRodney W. Grimes * to be sent and the original packet to be freed). 443df8bae1dSRodney W. Grimes */ 444df8bae1dSRodney W. Grimes ip_nhops = 0; /* for source routed packets */ 445df8bae1dSRodney W. Grimes if (hlen > sizeof (struct ip) && ip_dooptions(m)) 446c67b1d17SGarrett Wollman return; 447df8bae1dSRodney W. Grimes 448f0068c4aSGarrett Wollman /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no 449f0068c4aSGarrett Wollman * matter if it is destined to another node, or whether it is 450f0068c4aSGarrett Wollman * a multicast one, RSVP wants it! and prevents it from being forwarded 451f0068c4aSGarrett Wollman * anywhere else. Also checks if the rsvp daemon is running before 452f0068c4aSGarrett Wollman * grabbing the packet. 453f0068c4aSGarrett Wollman */ 4541c5de19aSGarrett Wollman if (rsvp_on && ip->ip_p==IPPROTO_RSVP) 455f0068c4aSGarrett Wollman goto ours; 456f0068c4aSGarrett Wollman 457df8bae1dSRodney W. Grimes /* 458df8bae1dSRodney W. Grimes * Check our list of addresses, to see if the packet is for us. 459cc766e04SGarrett Wollman * If we don't have any addresses, assume any unicast packet 460cc766e04SGarrett Wollman * we receive might be for us (and let the upper layers deal 461cc766e04SGarrett Wollman * with it). 462df8bae1dSRodney W. Grimes */ 463cc766e04SGarrett Wollman if (TAILQ_EMPTY(&in_ifaddrhead) && 464cc766e04SGarrett Wollman (m->m_flags & (M_MCAST|M_BCAST)) == 0) 465cc766e04SGarrett Wollman goto ours; 466cc766e04SGarrett Wollman 467d4295c32SJulian Elischer for (ia = TAILQ_FIRST(&in_ifaddrhead); ia; 468f9e354dfSJulian Elischer ia = TAILQ_NEXT(ia, ia_link)) { 469df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 470df8bae1dSRodney W. Grimes 471df8bae1dSRodney W. Grimes if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) 472df8bae1dSRodney W. Grimes goto ours; 473432aad0eSTor Egge #ifdef BOOTP_COMPAT 474432aad0eSTor Egge if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) 475432aad0eSTor Egge goto ours; 476432aad0eSTor Egge #endif 477f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 478f9e354dfSJulian Elischer /* 479f9e354dfSJulian Elischer * If the addr to forward to is one of ours, we pretend to 480f9e354dfSJulian Elischer * be the destination for this packet. 481f9e354dfSJulian Elischer */ 482f9e354dfSJulian Elischer if (ip_fw_fwd_addr != NULL && 483f9e354dfSJulian Elischer IA_SIN(ia)->sin_addr.s_addr == 484f9e354dfSJulian Elischer ip_fw_fwd_addr->sin_addr.s_addr) 485f9e354dfSJulian Elischer goto ours; 486f9e354dfSJulian Elischer #endif 4876ed666afSPoul-Henning Kamp if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) { 488df8bae1dSRodney W. Grimes if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 489df8bae1dSRodney W. Grimes ip->ip_dst.s_addr) 490df8bae1dSRodney W. Grimes goto ours; 491df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) 492df8bae1dSRodney W. Grimes goto ours; 493df8bae1dSRodney W. Grimes } 494df8bae1dSRodney W. Grimes } 495df8bae1dSRodney W. Grimes if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { 496df8bae1dSRodney W. Grimes struct in_multi *inm; 497df8bae1dSRodney W. Grimes if (ip_mrouter) { 498df8bae1dSRodney W. Grimes /* 499df8bae1dSRodney W. Grimes * If we are acting as a multicast router, all 500df8bae1dSRodney W. Grimes * incoming multicast packets are passed to the 501df8bae1dSRodney W. Grimes * kernel-level multicast forwarding function. 502df8bae1dSRodney W. Grimes * The packet is returned (relatively) intact; if 503df8bae1dSRodney W. Grimes * ip_mforward() returns a non-zero value, the packet 504df8bae1dSRodney W. Grimes * must be discarded, else it may be accepted below. 505df8bae1dSRodney W. Grimes * 506df8bae1dSRodney W. Grimes * (The IP ident field is put in the same byte order 507df8bae1dSRodney W. Grimes * as expected when ip_mforward() is called from 508df8bae1dSRodney W. Grimes * ip_output().) 509df8bae1dSRodney W. Grimes */ 510df8bae1dSRodney W. Grimes ip->ip_id = htons(ip->ip_id); 511f0068c4aSGarrett Wollman if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) { 512df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 513df8bae1dSRodney W. Grimes m_freem(m); 514c67b1d17SGarrett Wollman return; 515df8bae1dSRodney W. Grimes } 516df8bae1dSRodney W. Grimes ip->ip_id = ntohs(ip->ip_id); 517df8bae1dSRodney W. Grimes 518df8bae1dSRodney W. Grimes /* 519df8bae1dSRodney W. Grimes * The process-level routing demon needs to receive 520df8bae1dSRodney W. Grimes * all multicast IGMP packets, whether or not this 521df8bae1dSRodney W. Grimes * host belongs to their destination groups. 522df8bae1dSRodney W. Grimes */ 523df8bae1dSRodney W. Grimes if (ip->ip_p == IPPROTO_IGMP) 524df8bae1dSRodney W. Grimes goto ours; 525df8bae1dSRodney W. Grimes ipstat.ips_forward++; 526df8bae1dSRodney W. Grimes } 527df8bae1dSRodney W. Grimes /* 528df8bae1dSRodney W. Grimes * See if we belong to the destination multicast group on the 529df8bae1dSRodney W. Grimes * arrival interface. 530df8bae1dSRodney W. Grimes */ 531df8bae1dSRodney W. Grimes IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); 532df8bae1dSRodney W. Grimes if (inm == NULL) { 53382c39223SGarrett Wollman ipstat.ips_notmember++; 534df8bae1dSRodney W. Grimes m_freem(m); 535c67b1d17SGarrett Wollman return; 536df8bae1dSRodney W. Grimes } 537df8bae1dSRodney W. Grimes goto ours; 538df8bae1dSRodney W. Grimes } 539df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) 540df8bae1dSRodney W. Grimes goto ours; 541df8bae1dSRodney W. Grimes if (ip->ip_dst.s_addr == INADDR_ANY) 542df8bae1dSRodney W. Grimes goto ours; 543df8bae1dSRodney W. Grimes 544df8bae1dSRodney W. Grimes /* 545df8bae1dSRodney W. Grimes * Not for us; forward if possible and desirable. 546df8bae1dSRodney W. Grimes */ 547df8bae1dSRodney W. Grimes if (ipforwarding == 0) { 548df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 549df8bae1dSRodney W. Grimes m_freem(m); 550df8bae1dSRodney W. Grimes } else 551df8bae1dSRodney W. Grimes ip_forward(m, 0); 552c67b1d17SGarrett Wollman return; 553df8bae1dSRodney W. Grimes 554df8bae1dSRodney W. Grimes ours: 555100ba1a6SJordan K. Hubbard 55663f8d699SJordan K. Hubbard /* 557df8bae1dSRodney W. Grimes * If offset or IP_MF are set, must reassemble. 558df8bae1dSRodney W. Grimes * Otherwise, nothing need be done. 559df8bae1dSRodney W. Grimes * (We could look in the reassembly queue to see 560df8bae1dSRodney W. Grimes * if the packet was previously fragmented, 561df8bae1dSRodney W. Grimes * but it's not worth the time; just let them time out.) 562df8bae1dSRodney W. Grimes */ 563c383a33fSDima Ruban if (ip->ip_off & (IP_MF | IP_OFFMASK | IP_RF)) { 564df8bae1dSRodney W. Grimes if (m->m_flags & M_EXT) { /* XXX */ 565af38c68cSLuigi Rizzo if ((m = m_pullup(m, hlen)) == 0) { 566df8bae1dSRodney W. Grimes ipstat.ips_toosmall++; 56793e0e116SJulian Elischer #ifdef IPDIVERT 56893e0e116SJulian Elischer frag_divert_port = 0; 569c977d4c7SJulian Elischer ip_divert_cookie = 0; 57093e0e116SJulian Elischer #endif 571c67b1d17SGarrett Wollman return; 572df8bae1dSRodney W. Grimes } 573df8bae1dSRodney W. Grimes ip = mtod(m, struct ip *); 574df8bae1dSRodney W. Grimes } 575194a213eSAndrey A. Chernov sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id); 576df8bae1dSRodney W. Grimes /* 577df8bae1dSRodney W. Grimes * Look for queue of fragments 578df8bae1dSRodney W. Grimes * of this datagram. 579df8bae1dSRodney W. Grimes */ 580194a213eSAndrey A. Chernov for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next) 581df8bae1dSRodney W. Grimes if (ip->ip_id == fp->ipq_id && 582df8bae1dSRodney W. Grimes ip->ip_src.s_addr == fp->ipq_src.s_addr && 583df8bae1dSRodney W. Grimes ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 584df8bae1dSRodney W. Grimes ip->ip_p == fp->ipq_p) 585df8bae1dSRodney W. Grimes goto found; 586df8bae1dSRodney W. Grimes 587194a213eSAndrey A. Chernov fp = 0; 588194a213eSAndrey A. Chernov 589194a213eSAndrey A. Chernov /* check if there's a place for the new queue */ 590194a213eSAndrey A. Chernov if (nipq > maxnipq) { 591194a213eSAndrey A. Chernov /* 592194a213eSAndrey A. Chernov * drop something from the tail of the current queue 593194a213eSAndrey A. Chernov * before proceeding further 594194a213eSAndrey A. Chernov */ 595194a213eSAndrey A. Chernov if (ipq[sum].prev == &ipq[sum]) { /* gak */ 596194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 597194a213eSAndrey A. Chernov if (ipq[i].prev != &ipq[i]) { 598194a213eSAndrey A. Chernov ip_freef(ipq[i].prev); 599194a213eSAndrey A. Chernov break; 600194a213eSAndrey A. Chernov } 601194a213eSAndrey A. Chernov } 602194a213eSAndrey A. Chernov } else 603194a213eSAndrey A. Chernov ip_freef(ipq[sum].prev); 604194a213eSAndrey A. Chernov } 605194a213eSAndrey A. Chernov found: 606df8bae1dSRodney W. Grimes /* 607df8bae1dSRodney W. Grimes * Adjust ip_len to not reflect header, 608df8bae1dSRodney W. Grimes * set ip_mff if more fragments are expected, 609df8bae1dSRodney W. Grimes * convert offset of this to bytes. 610df8bae1dSRodney W. Grimes */ 611df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 6126effc713SDoug Rabson mff = (ip->ip_off & IP_MF) != 0; 6136effc713SDoug Rabson if (mff) { 6146effc713SDoug Rabson /* 6156effc713SDoug Rabson * Make sure that fragments have a data length 6166effc713SDoug Rabson * that's a non-zero multiple of 8 bytes. 6176effc713SDoug Rabson */ 6186effc713SDoug Rabson if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { 6196effc713SDoug Rabson ipstat.ips_toosmall++; /* XXX */ 6206effc713SDoug Rabson goto bad; 6216effc713SDoug Rabson } 6226effc713SDoug Rabson m->m_flags |= M_FRAG; 6236effc713SDoug Rabson } 624df8bae1dSRodney W. Grimes ip->ip_off <<= 3; 625df8bae1dSRodney W. Grimes 626df8bae1dSRodney W. Grimes /* 627df8bae1dSRodney W. Grimes * If datagram marked as having more fragments 628df8bae1dSRodney W. Grimes * or if this is not the first fragment, 629df8bae1dSRodney W. Grimes * attempt reassembly; if it succeeds, proceed. 630df8bae1dSRodney W. Grimes */ 6316effc713SDoug Rabson if (mff || ip->ip_off) { 632df8bae1dSRodney W. Grimes ipstat.ips_fragments++; 6336effc713SDoug Rabson m->m_pkthdr.header = ip; 6346effc713SDoug Rabson ip = ip_reass(m, fp, &ipq[sum]); 635f9e354dfSJulian Elischer if (ip == 0) { 636f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 637f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 638f9e354dfSJulian Elischer #endif 639c67b1d17SGarrett Wollman return; 640f9e354dfSJulian Elischer } 64181aee63dSPoul-Henning Kamp /* Get the length of the reassembled packets header */ 64281aee63dSPoul-Henning Kamp hlen = IP_VHL_HL(ip->ip_vhl) << 2; 643df8bae1dSRodney W. Grimes ipstat.ips_reassembled++; 644df8bae1dSRodney W. Grimes m = dtom(ip); 645af782f1cSBrian Somers #ifdef IPDIVERT 646af782f1cSBrian Somers if (frag_divert_port) { 647af782f1cSBrian Somers ip->ip_len += hlen; 648af782f1cSBrian Somers HTONS(ip->ip_len); 649af782f1cSBrian Somers HTONS(ip->ip_off); 650af782f1cSBrian Somers HTONS(ip->ip_id); 651af782f1cSBrian Somers ip->ip_sum = 0; 652af782f1cSBrian Somers ip->ip_sum = in_cksum_hdr(ip); 653af782f1cSBrian Somers NTOHS(ip->ip_id); 654af782f1cSBrian Somers NTOHS(ip->ip_off); 655af782f1cSBrian Somers NTOHS(ip->ip_len); 656af782f1cSBrian Somers ip->ip_len -= hlen; 657af782f1cSBrian Somers } 658af782f1cSBrian Somers #endif 659df8bae1dSRodney W. Grimes } else 660df8bae1dSRodney W. Grimes if (fp) 661df8bae1dSRodney W. Grimes ip_freef(fp); 662df8bae1dSRodney W. Grimes } else 663df8bae1dSRodney W. Grimes ip->ip_len -= hlen; 664df8bae1dSRodney W. Grimes 66593e0e116SJulian Elischer #ifdef IPDIVERT 66693e0e116SJulian Elischer /* 667e4676ba6SJulian Elischer * Divert reassembled packets to the divert protocol if required 668efe39c6aSJulian Elischer * If divert port is null then cookie should be too, 669efe39c6aSJulian Elischer * so we shouldn't need to clear them here. Assume ip_divert does so. 67093e0e116SJulian Elischer */ 67193e0e116SJulian Elischer if (frag_divert_port) { 672e4676ba6SJulian Elischer ipstat.ips_delivered++; 67393e0e116SJulian Elischer ip_divert_port = frag_divert_port; 67493e0e116SJulian Elischer frag_divert_port = 0; 67593e0e116SJulian Elischer (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, hlen); 67693e0e116SJulian Elischer return; 67793e0e116SJulian Elischer } 67879755dc5SJulian Elischer 67979755dc5SJulian Elischer /* Don't let packets divert themselves */ 68079755dc5SJulian Elischer if (ip->ip_p == IPPROTO_DIVERT) { 68179755dc5SJulian Elischer ipstat.ips_noproto++; 68279755dc5SJulian Elischer goto bad; 68379755dc5SJulian Elischer } 684bb60f459SJulian Elischer 68593e0e116SJulian Elischer #endif 68693e0e116SJulian Elischer 687df8bae1dSRodney W. Grimes /* 688df8bae1dSRodney W. Grimes * Switch out to protocol's input routine. 689df8bae1dSRodney W. Grimes */ 690df8bae1dSRodney W. Grimes ipstat.ips_delivered++; 691df8bae1dSRodney W. Grimes (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); 692f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 693f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; /* tcp needed it */ 694f9e354dfSJulian Elischer #endif 695c67b1d17SGarrett Wollman return; 696df8bae1dSRodney W. Grimes bad: 697f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD 698f9e354dfSJulian Elischer ip_fw_fwd_addr = NULL; 699f9e354dfSJulian Elischer #endif 700df8bae1dSRodney W. Grimes m_freem(m); 701c67b1d17SGarrett Wollman } 702c67b1d17SGarrett Wollman 703c67b1d17SGarrett Wollman /* 704c67b1d17SGarrett Wollman * IP software interrupt routine - to go away sometime soon 705c67b1d17SGarrett Wollman */ 706c67b1d17SGarrett Wollman static void 707c67b1d17SGarrett Wollman ipintr(void) 708c67b1d17SGarrett Wollman { 709c67b1d17SGarrett Wollman int s; 710c67b1d17SGarrett Wollman struct mbuf *m; 711c67b1d17SGarrett Wollman 712c67b1d17SGarrett Wollman while(1) { 713c67b1d17SGarrett Wollman s = splimp(); 714c67b1d17SGarrett Wollman IF_DEQUEUE(&ipintrq, m); 715c67b1d17SGarrett Wollman splx(s); 716c67b1d17SGarrett Wollman if (m == 0) 717c67b1d17SGarrett Wollman return; 718c67b1d17SGarrett Wollman ip_input(m); 719c67b1d17SGarrett Wollman } 720df8bae1dSRodney W. Grimes } 721df8bae1dSRodney W. Grimes 722748e0b0aSGarrett Wollman NETISR_SET(NETISR_IP, ipintr); 723748e0b0aSGarrett Wollman 724df8bae1dSRodney W. Grimes /* 725df8bae1dSRodney W. Grimes * Take incoming datagram fragment and try to 726df8bae1dSRodney W. Grimes * reassemble it into whole datagram. If a chain for 727df8bae1dSRodney W. Grimes * reassembly of this datagram already exists, then it 728df8bae1dSRodney W. Grimes * is given as fp; otherwise have to make a chain. 729df8bae1dSRodney W. Grimes */ 7300312fbe9SPoul-Henning Kamp static struct ip * 7316effc713SDoug Rabson ip_reass(m, fp, where) 7326effc713SDoug Rabson register struct mbuf *m; 733df8bae1dSRodney W. Grimes register struct ipq *fp; 734194a213eSAndrey A. Chernov struct ipq *where; 735df8bae1dSRodney W. Grimes { 7366effc713SDoug Rabson struct ip *ip = mtod(m, struct ip *); 7376effc713SDoug Rabson register struct mbuf *p = 0, *q, *nq; 738df8bae1dSRodney W. Grimes struct mbuf *t; 7396effc713SDoug Rabson int hlen = IP_VHL_HL(ip->ip_vhl) << 2; 740df8bae1dSRodney W. Grimes int i, next; 741df8bae1dSRodney W. Grimes 742df8bae1dSRodney W. Grimes /* 743df8bae1dSRodney W. Grimes * Presence of header sizes in mbufs 744df8bae1dSRodney W. Grimes * would confuse code below. 745df8bae1dSRodney W. Grimes */ 746df8bae1dSRodney W. Grimes m->m_data += hlen; 747df8bae1dSRodney W. Grimes m->m_len -= hlen; 748df8bae1dSRodney W. Grimes 749df8bae1dSRodney W. Grimes /* 750df8bae1dSRodney W. Grimes * If first fragment to arrive, create a reassembly queue. 751df8bae1dSRodney W. Grimes */ 752df8bae1dSRodney W. Grimes if (fp == 0) { 753df8bae1dSRodney W. Grimes if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) 754df8bae1dSRodney W. Grimes goto dropfrag; 755df8bae1dSRodney W. Grimes fp = mtod(t, struct ipq *); 756194a213eSAndrey A. Chernov insque(fp, where); 757194a213eSAndrey A. Chernov nipq++; 758df8bae1dSRodney W. Grimes fp->ipq_ttl = IPFRAGTTL; 759df8bae1dSRodney W. Grimes fp->ipq_p = ip->ip_p; 760df8bae1dSRodney W. Grimes fp->ipq_id = ip->ip_id; 7616effc713SDoug Rabson fp->ipq_src = ip->ip_src; 7626effc713SDoug Rabson fp->ipq_dst = ip->ip_dst; 763af38c68cSLuigi Rizzo fp->ipq_frags = m; 764af38c68cSLuigi Rizzo m->m_nextpkt = NULL; 76593e0e116SJulian Elischer #ifdef IPDIVERT 76693e0e116SJulian Elischer fp->ipq_divert = 0; 767bb60f459SJulian Elischer fp->ipq_div_cookie = 0; 76893e0e116SJulian Elischer #endif 769af38c68cSLuigi Rizzo goto inserted; 770df8bae1dSRodney W. Grimes } 771df8bae1dSRodney W. Grimes 7726effc713SDoug Rabson #define GETIP(m) ((struct ip*)((m)->m_pkthdr.header)) 7736effc713SDoug Rabson 774df8bae1dSRodney W. Grimes /* 775df8bae1dSRodney W. Grimes * Find a segment which begins after this one does. 776df8bae1dSRodney W. Grimes */ 7776effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) 7786effc713SDoug Rabson if (GETIP(q)->ip_off > ip->ip_off) 779df8bae1dSRodney W. Grimes break; 780df8bae1dSRodney W. Grimes 781df8bae1dSRodney W. Grimes /* 782df8bae1dSRodney W. Grimes * If there is a preceding segment, it may provide some of 783df8bae1dSRodney W. Grimes * our data already. If so, drop the data from the incoming 784af38c68cSLuigi Rizzo * segment. If it provides all of our data, drop us, otherwise 785af38c68cSLuigi Rizzo * stick new segment in the proper place. 786df8bae1dSRodney W. Grimes */ 7876effc713SDoug Rabson if (p) { 7886effc713SDoug Rabson i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off; 789df8bae1dSRodney W. Grimes if (i > 0) { 790df8bae1dSRodney W. Grimes if (i >= ip->ip_len) 791df8bae1dSRodney W. Grimes goto dropfrag; 792df8bae1dSRodney W. Grimes m_adj(dtom(ip), i); 793df8bae1dSRodney W. Grimes ip->ip_off += i; 794df8bae1dSRodney W. Grimes ip->ip_len -= i; 795df8bae1dSRodney W. Grimes } 796af38c68cSLuigi Rizzo m->m_nextpkt = p->m_nextpkt; 797af38c68cSLuigi Rizzo p->m_nextpkt = m; 798af38c68cSLuigi Rizzo } else { 799af38c68cSLuigi Rizzo m->m_nextpkt = fp->ipq_frags; 800af38c68cSLuigi Rizzo fp->ipq_frags = m; 801df8bae1dSRodney W. Grimes } 802df8bae1dSRodney W. Grimes 803df8bae1dSRodney W. Grimes /* 804df8bae1dSRodney W. Grimes * While we overlap succeeding segments trim them or, 805df8bae1dSRodney W. Grimes * if they are completely covered, dequeue them. 806df8bae1dSRodney W. Grimes */ 8076effc713SDoug Rabson for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off; 808af38c68cSLuigi Rizzo q = nq) { 8096effc713SDoug Rabson i = (ip->ip_off + ip->ip_len) - 8106effc713SDoug Rabson GETIP(q)->ip_off; 8116effc713SDoug Rabson if (i < GETIP(q)->ip_len) { 8126effc713SDoug Rabson GETIP(q)->ip_len -= i; 8136effc713SDoug Rabson GETIP(q)->ip_off += i; 8146effc713SDoug Rabson m_adj(q, i); 815df8bae1dSRodney W. Grimes break; 816df8bae1dSRodney W. Grimes } 8176effc713SDoug Rabson nq = q->m_nextpkt; 818af38c68cSLuigi Rizzo m->m_nextpkt = nq; 8196effc713SDoug Rabson m_freem(q); 820df8bae1dSRodney W. Grimes } 821df8bae1dSRodney W. Grimes 822af38c68cSLuigi Rizzo inserted: 82393e0e116SJulian Elischer 82493e0e116SJulian Elischer #ifdef IPDIVERT 82593e0e116SJulian Elischer /* 82693e0e116SJulian Elischer * Any fragment diverting causes the whole packet to divert 82793e0e116SJulian Elischer */ 828efe39c6aSJulian Elischer if (frag_divert_port) { 82993e0e116SJulian Elischer fp->ipq_divert = frag_divert_port; 830c977d4c7SJulian Elischer fp->ipq_div_cookie = ip_divert_cookie; 831bb60f459SJulian Elischer } 83293e0e116SJulian Elischer frag_divert_port = 0; 833c977d4c7SJulian Elischer ip_divert_cookie = 0; 83493e0e116SJulian Elischer #endif 83593e0e116SJulian Elischer 836df8bae1dSRodney W. Grimes /* 837af38c68cSLuigi Rizzo * Check for complete reassembly. 838df8bae1dSRodney W. Grimes */ 8396effc713SDoug Rabson next = 0; 8406effc713SDoug Rabson for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { 8416effc713SDoug Rabson if (GETIP(q)->ip_off != next) 8426effc713SDoug Rabson return (0); 8436effc713SDoug Rabson next += GETIP(q)->ip_len; 8446effc713SDoug Rabson } 8456effc713SDoug Rabson /* Make sure the last packet didn't have the IP_MF flag */ 8466effc713SDoug Rabson if (p->m_flags & M_FRAG) 847df8bae1dSRodney W. Grimes return (0); 848df8bae1dSRodney W. Grimes 849df8bae1dSRodney W. Grimes /* 850430d30d8SBill Fenner * Reassembly is complete. Make sure the packet is a sane size. 851430d30d8SBill Fenner */ 8526effc713SDoug Rabson q = fp->ipq_frags; 8536effc713SDoug Rabson ip = GETIP(q); 8546effc713SDoug Rabson if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) { 855430d30d8SBill Fenner ipstat.ips_toolong++; 856430d30d8SBill Fenner ip_freef(fp); 857430d30d8SBill Fenner return (0); 858430d30d8SBill Fenner } 859430d30d8SBill Fenner 860430d30d8SBill Fenner /* 861430d30d8SBill Fenner * Concatenate fragments. 862df8bae1dSRodney W. Grimes */ 8636effc713SDoug Rabson m = q; 864df8bae1dSRodney W. Grimes t = m->m_next; 865df8bae1dSRodney W. Grimes m->m_next = 0; 866df8bae1dSRodney W. Grimes m_cat(m, t); 8676effc713SDoug Rabson nq = q->m_nextpkt; 868945aa40dSDoug Rabson q->m_nextpkt = 0; 8696effc713SDoug Rabson for (q = nq; q != NULL; q = nq) { 8706effc713SDoug Rabson nq = q->m_nextpkt; 871945aa40dSDoug Rabson q->m_nextpkt = NULL; 8726effc713SDoug Rabson m_cat(m, q); 873df8bae1dSRodney W. Grimes } 874df8bae1dSRodney W. Grimes 87593e0e116SJulian Elischer #ifdef IPDIVERT 87693e0e116SJulian Elischer /* 877c977d4c7SJulian Elischer * extract divert port for packet, if any 87893e0e116SJulian Elischer */ 87993e0e116SJulian Elischer frag_divert_port = fp->ipq_divert; 880c977d4c7SJulian Elischer ip_divert_cookie = fp->ipq_div_cookie; 88193e0e116SJulian Elischer #endif 88293e0e116SJulian Elischer 883df8bae1dSRodney W. Grimes /* 884df8bae1dSRodney W. Grimes * Create header for new ip packet by 885df8bae1dSRodney W. Grimes * modifying header of first packet; 886df8bae1dSRodney W. Grimes * dequeue and discard fragment reassembly header. 887df8bae1dSRodney W. Grimes * Make header visible. 888df8bae1dSRodney W. Grimes */ 889df8bae1dSRodney W. Grimes ip->ip_len = next; 8906effc713SDoug Rabson ip->ip_src = fp->ipq_src; 8916effc713SDoug Rabson ip->ip_dst = fp->ipq_dst; 892df8bae1dSRodney W. Grimes remque(fp); 893194a213eSAndrey A. Chernov nipq--; 894df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 8956effc713SDoug Rabson m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2); 8966effc713SDoug Rabson m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2); 897df8bae1dSRodney W. Grimes /* some debugging cruft by sklower, below, will go away soon */ 898df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ 899df8bae1dSRodney W. Grimes register int plen = 0; 900df8bae1dSRodney W. Grimes for (t = m; m; m = m->m_next) 901df8bae1dSRodney W. Grimes plen += m->m_len; 902df8bae1dSRodney W. Grimes t->m_pkthdr.len = plen; 903df8bae1dSRodney W. Grimes } 9046effc713SDoug Rabson return (ip); 905df8bae1dSRodney W. Grimes 906df8bae1dSRodney W. Grimes dropfrag: 907efe39c6aSJulian Elischer #ifdef IPDIVERT 908efe39c6aSJulian Elischer frag_divert_port = 0; 909efe39c6aSJulian Elischer ip_divert_cookie = 0; 910efe39c6aSJulian Elischer #endif 911df8bae1dSRodney W. Grimes ipstat.ips_fragdropped++; 912df8bae1dSRodney W. Grimes m_freem(m); 913df8bae1dSRodney W. Grimes return (0); 9146effc713SDoug Rabson 9156effc713SDoug Rabson #undef GETIP 916df8bae1dSRodney W. Grimes } 917df8bae1dSRodney W. Grimes 918df8bae1dSRodney W. Grimes /* 919df8bae1dSRodney W. Grimes * Free a fragment reassembly header and all 920df8bae1dSRodney W. Grimes * associated datagrams. 921df8bae1dSRodney W. Grimes */ 9220312fbe9SPoul-Henning Kamp static void 923df8bae1dSRodney W. Grimes ip_freef(fp) 924df8bae1dSRodney W. Grimes struct ipq *fp; 925df8bae1dSRodney W. Grimes { 9266effc713SDoug Rabson register struct mbuf *q; 927df8bae1dSRodney W. Grimes 9286effc713SDoug Rabson while (fp->ipq_frags) { 9296effc713SDoug Rabson q = fp->ipq_frags; 9306effc713SDoug Rabson fp->ipq_frags = q->m_nextpkt; 9316effc713SDoug Rabson m_freem(q); 932df8bae1dSRodney W. Grimes } 933df8bae1dSRodney W. Grimes remque(fp); 934df8bae1dSRodney W. Grimes (void) m_free(dtom(fp)); 935194a213eSAndrey A. Chernov nipq--; 936df8bae1dSRodney W. Grimes } 937df8bae1dSRodney W. Grimes 938df8bae1dSRodney W. Grimes /* 939df8bae1dSRodney W. Grimes * IP timer processing; 940df8bae1dSRodney W. Grimes * if a timer expires on a reassembly 941df8bae1dSRodney W. Grimes * queue, discard it. 942df8bae1dSRodney W. Grimes */ 943df8bae1dSRodney W. Grimes void 944df8bae1dSRodney W. Grimes ip_slowtimo() 945df8bae1dSRodney W. Grimes { 946df8bae1dSRodney W. Grimes register struct ipq *fp; 947df8bae1dSRodney W. Grimes int s = splnet(); 948194a213eSAndrey A. Chernov int i; 949df8bae1dSRodney W. Grimes 950194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 951194a213eSAndrey A. Chernov fp = ipq[i].next; 952194a213eSAndrey A. Chernov if (fp == 0) 953194a213eSAndrey A. Chernov continue; 954194a213eSAndrey A. Chernov while (fp != &ipq[i]) { 955df8bae1dSRodney W. Grimes --fp->ipq_ttl; 956df8bae1dSRodney W. Grimes fp = fp->next; 957df8bae1dSRodney W. Grimes if (fp->prev->ipq_ttl == 0) { 958df8bae1dSRodney W. Grimes ipstat.ips_fragtimeout++; 959df8bae1dSRodney W. Grimes ip_freef(fp->prev); 960df8bae1dSRodney W. Grimes } 961df8bae1dSRodney W. Grimes } 962194a213eSAndrey A. Chernov } 9631f91d8c5SDavid Greenman ipflow_slowtimo(); 964df8bae1dSRodney W. Grimes splx(s); 965df8bae1dSRodney W. Grimes } 966df8bae1dSRodney W. Grimes 967df8bae1dSRodney W. Grimes /* 968df8bae1dSRodney W. Grimes * Drain off all datagram fragments. 969df8bae1dSRodney W. Grimes */ 970df8bae1dSRodney W. Grimes void 971df8bae1dSRodney W. Grimes ip_drain() 972df8bae1dSRodney W. Grimes { 973194a213eSAndrey A. Chernov int i; 974ce29ab3aSGarrett Wollman 975194a213eSAndrey A. Chernov for (i = 0; i < IPREASS_NHASH; i++) { 976194a213eSAndrey A. Chernov while (ipq[i].next != &ipq[i]) { 977194a213eSAndrey A. Chernov ipstat.ips_fragdropped++; 978194a213eSAndrey A. Chernov ip_freef(ipq[i].next); 979194a213eSAndrey A. Chernov } 980194a213eSAndrey A. Chernov } 981ce29ab3aSGarrett Wollman in_rtqdrain(); 982df8bae1dSRodney W. Grimes } 983df8bae1dSRodney W. Grimes 984df8bae1dSRodney W. Grimes /* 985df8bae1dSRodney W. Grimes * Do option processing on a datagram, 986df8bae1dSRodney W. Grimes * possibly discarding it if bad options are encountered, 987df8bae1dSRodney W. Grimes * or forwarding it if source-routed. 988df8bae1dSRodney W. Grimes * Returns 1 if packet has been forwarded/freed, 989df8bae1dSRodney W. Grimes * 0 if the packet should be processed further. 990df8bae1dSRodney W. Grimes */ 9910312fbe9SPoul-Henning Kamp static int 992df8bae1dSRodney W. Grimes ip_dooptions(m) 993df8bae1dSRodney W. Grimes struct mbuf *m; 994df8bae1dSRodney W. Grimes { 995df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 996df8bae1dSRodney W. Grimes register u_char *cp; 997df8bae1dSRodney W. Grimes register struct ip_timestamp *ipt; 998df8bae1dSRodney W. Grimes register struct in_ifaddr *ia; 999df8bae1dSRodney W. Grimes int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; 1000df8bae1dSRodney W. Grimes struct in_addr *sin, dst; 1001df8bae1dSRodney W. Grimes n_time ntime; 1002df8bae1dSRodney W. Grimes 1003df8bae1dSRodney W. Grimes dst = ip->ip_dst; 1004df8bae1dSRodney W. Grimes cp = (u_char *)(ip + 1); 100558938916SGarrett Wollman cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1006df8bae1dSRodney W. Grimes for (; cnt > 0; cnt -= optlen, cp += optlen) { 1007df8bae1dSRodney W. Grimes opt = cp[IPOPT_OPTVAL]; 1008df8bae1dSRodney W. Grimes if (opt == IPOPT_EOL) 1009df8bae1dSRodney W. Grimes break; 1010df8bae1dSRodney W. Grimes if (opt == IPOPT_NOP) 1011df8bae1dSRodney W. Grimes optlen = 1; 1012df8bae1dSRodney W. Grimes else { 1013df8bae1dSRodney W. Grimes optlen = cp[IPOPT_OLEN]; 1014df8bae1dSRodney W. Grimes if (optlen <= 0 || optlen > cnt) { 1015df8bae1dSRodney W. Grimes code = &cp[IPOPT_OLEN] - (u_char *)ip; 1016df8bae1dSRodney W. Grimes goto bad; 1017df8bae1dSRodney W. Grimes } 1018df8bae1dSRodney W. Grimes } 1019df8bae1dSRodney W. Grimes switch (opt) { 1020df8bae1dSRodney W. Grimes 1021df8bae1dSRodney W. Grimes default: 1022df8bae1dSRodney W. Grimes break; 1023df8bae1dSRodney W. Grimes 1024df8bae1dSRodney W. Grimes /* 1025df8bae1dSRodney W. Grimes * Source routing with record. 1026df8bae1dSRodney W. Grimes * Find interface with current destination address. 1027df8bae1dSRodney W. Grimes * If none on this machine then drop if strictly routed, 1028df8bae1dSRodney W. Grimes * or do nothing if loosely routed. 1029df8bae1dSRodney W. Grimes * Record interface address and bring up next address 1030df8bae1dSRodney W. Grimes * component. If strictly routed make sure next 1031df8bae1dSRodney W. Grimes * address is on directly accessible net. 1032df8bae1dSRodney W. Grimes */ 1033df8bae1dSRodney W. Grimes case IPOPT_LSRR: 1034df8bae1dSRodney W. Grimes case IPOPT_SSRR: 1035df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1036df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1037df8bae1dSRodney W. Grimes goto bad; 1038df8bae1dSRodney W. Grimes } 1039df8bae1dSRodney W. Grimes ipaddr.sin_addr = ip->ip_dst; 1040df8bae1dSRodney W. Grimes ia = (struct in_ifaddr *) 1041df8bae1dSRodney W. Grimes ifa_ifwithaddr((struct sockaddr *)&ipaddr); 1042df8bae1dSRodney W. Grimes if (ia == 0) { 1043df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1044df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1045df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1046df8bae1dSRodney W. Grimes goto bad; 1047df8bae1dSRodney W. Grimes } 1048bc189bf8SGuido van Rooij if (!ip_dosourceroute) 1049bc189bf8SGuido van Rooij goto nosourcerouting; 1050df8bae1dSRodney W. Grimes /* 1051df8bae1dSRodney W. Grimes * Loose routing, and not at next destination 1052df8bae1dSRodney W. Grimes * yet; nothing to do except forward. 1053df8bae1dSRodney W. Grimes */ 1054df8bae1dSRodney W. Grimes break; 1055df8bae1dSRodney W. Grimes } 1056df8bae1dSRodney W. Grimes off--; /* 0 origin */ 1057df8bae1dSRodney W. Grimes if (off > optlen - sizeof(struct in_addr)) { 1058df8bae1dSRodney W. Grimes /* 1059df8bae1dSRodney W. Grimes * End of source route. Should be for us. 1060df8bae1dSRodney W. Grimes */ 10614fce5804SGuido van Rooij if (!ip_acceptsourceroute) 10624fce5804SGuido van Rooij goto nosourcerouting; 1063df8bae1dSRodney W. Grimes save_rte(cp, ip->ip_src); 1064df8bae1dSRodney W. Grimes break; 1065df8bae1dSRodney W. Grimes } 10661025071fSGarrett Wollman 10671025071fSGarrett Wollman if (!ip_dosourceroute) { 10680af8d3ecSDavid Greenman if (ipforwarding) { 10690af8d3ecSDavid Greenman char buf[16]; /* aaa.bbb.ccc.ddd\0 */ 10700af8d3ecSDavid Greenman /* 10710af8d3ecSDavid Greenman * Acting as a router, so generate ICMP 10720af8d3ecSDavid Greenman */ 1073efa48587SGuido van Rooij nosourcerouting: 1074bc189bf8SGuido van Rooij strcpy(buf, inet_ntoa(ip->ip_dst)); 10751025071fSGarrett Wollman log(LOG_WARNING, 10761025071fSGarrett Wollman "attempted source route from %s to %s\n", 10771025071fSGarrett Wollman inet_ntoa(ip->ip_src), buf); 10781025071fSGarrett Wollman type = ICMP_UNREACH; 10791025071fSGarrett Wollman code = ICMP_UNREACH_SRCFAIL; 10801025071fSGarrett Wollman goto bad; 10810af8d3ecSDavid Greenman } else { 10820af8d3ecSDavid Greenman /* 10830af8d3ecSDavid Greenman * Not acting as a router, so silently drop. 10840af8d3ecSDavid Greenman */ 10850af8d3ecSDavid Greenman ipstat.ips_cantforward++; 10860af8d3ecSDavid Greenman m_freem(m); 10870af8d3ecSDavid Greenman return (1); 10880af8d3ecSDavid Greenman } 10891025071fSGarrett Wollman } 10901025071fSGarrett Wollman 1091df8bae1dSRodney W. Grimes /* 1092df8bae1dSRodney W. Grimes * locate outgoing interface 1093df8bae1dSRodney W. Grimes */ 109494a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, cp + off, 1095df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 10961025071fSGarrett Wollman 1097df8bae1dSRodney W. Grimes if (opt == IPOPT_SSRR) { 1098df8bae1dSRodney W. Grimes #define INA struct in_ifaddr * 1099df8bae1dSRodney W. Grimes #define SA struct sockaddr * 1100df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) 1101df8bae1dSRodney W. Grimes ia = (INA)ifa_ifwithnet((SA)&ipaddr); 1102df8bae1dSRodney W. Grimes } else 1103df8bae1dSRodney W. Grimes ia = ip_rtaddr(ipaddr.sin_addr); 1104df8bae1dSRodney W. Grimes if (ia == 0) { 1105df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1106df8bae1dSRodney W. Grimes code = ICMP_UNREACH_SRCFAIL; 1107df8bae1dSRodney W. Grimes goto bad; 1108df8bae1dSRodney W. Grimes } 1109df8bae1dSRodney W. Grimes ip->ip_dst = ipaddr.sin_addr; 111094a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 111194a5d9b6SDavid Greenman sizeof(struct in_addr)); 1112df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1113df8bae1dSRodney W. Grimes /* 1114df8bae1dSRodney W. Grimes * Let ip_intr's mcast routing check handle mcast pkts 1115df8bae1dSRodney W. Grimes */ 1116df8bae1dSRodney W. Grimes forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); 1117df8bae1dSRodney W. Grimes break; 1118df8bae1dSRodney W. Grimes 1119df8bae1dSRodney W. Grimes case IPOPT_RR: 1120df8bae1dSRodney W. Grimes if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { 1121df8bae1dSRodney W. Grimes code = &cp[IPOPT_OFFSET] - (u_char *)ip; 1122df8bae1dSRodney W. Grimes goto bad; 1123df8bae1dSRodney W. Grimes } 1124df8bae1dSRodney W. Grimes /* 1125df8bae1dSRodney W. Grimes * If no space remains, ignore. 1126df8bae1dSRodney W. Grimes */ 1127df8bae1dSRodney W. Grimes off--; /* 0 origin */ 1128df8bae1dSRodney W. Grimes if (off > optlen - sizeof(struct in_addr)) 1129df8bae1dSRodney W. Grimes break; 113094a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, &ip->ip_dst, 1131df8bae1dSRodney W. Grimes sizeof(ipaddr.sin_addr)); 1132df8bae1dSRodney W. Grimes /* 1133df8bae1dSRodney W. Grimes * locate outgoing interface; if we're the destination, 1134df8bae1dSRodney W. Grimes * use the incoming interface (should be same). 1135df8bae1dSRodney W. Grimes */ 1136df8bae1dSRodney W. Grimes if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && 1137df8bae1dSRodney W. Grimes (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { 1138df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1139df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1140df8bae1dSRodney W. Grimes goto bad; 1141df8bae1dSRodney W. Grimes } 114294a5d9b6SDavid Greenman (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 114394a5d9b6SDavid Greenman sizeof(struct in_addr)); 1144df8bae1dSRodney W. Grimes cp[IPOPT_OFFSET] += sizeof(struct in_addr); 1145df8bae1dSRodney W. Grimes break; 1146df8bae1dSRodney W. Grimes 1147df8bae1dSRodney W. Grimes case IPOPT_TS: 1148df8bae1dSRodney W. Grimes code = cp - (u_char *)ip; 1149df8bae1dSRodney W. Grimes ipt = (struct ip_timestamp *)cp; 1150df8bae1dSRodney W. Grimes if (ipt->ipt_len < 5) 1151df8bae1dSRodney W. Grimes goto bad; 11520c8d2590SBruce Evans if (ipt->ipt_ptr > ipt->ipt_len - sizeof(int32_t)) { 1153df8bae1dSRodney W. Grimes if (++ipt->ipt_oflw == 0) 1154df8bae1dSRodney W. Grimes goto bad; 1155df8bae1dSRodney W. Grimes break; 1156df8bae1dSRodney W. Grimes } 1157df8bae1dSRodney W. Grimes sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); 1158df8bae1dSRodney W. Grimes switch (ipt->ipt_flg) { 1159df8bae1dSRodney W. Grimes 1160df8bae1dSRodney W. Grimes case IPOPT_TS_TSONLY: 1161df8bae1dSRodney W. Grimes break; 1162df8bae1dSRodney W. Grimes 1163df8bae1dSRodney W. Grimes case IPOPT_TS_TSANDADDR: 1164b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1165df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1166df8bae1dSRodney W. Grimes goto bad; 1167df8bae1dSRodney W. Grimes ipaddr.sin_addr = dst; 1168df8bae1dSRodney W. Grimes ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, 1169df8bae1dSRodney W. Grimes m->m_pkthdr.rcvif); 1170df8bae1dSRodney W. Grimes if (ia == 0) 1171df8bae1dSRodney W. Grimes continue; 117294a5d9b6SDavid Greenman (void)memcpy(sin, &IA_SIN(ia)->sin_addr, 117394a5d9b6SDavid Greenman sizeof(struct in_addr)); 1174df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1175df8bae1dSRodney W. Grimes break; 1176df8bae1dSRodney W. Grimes 1177df8bae1dSRodney W. Grimes case IPOPT_TS_PRESPEC: 1178b8e8c209SDavid Greenman if (ipt->ipt_ptr - 1 + sizeof(n_time) + 1179df8bae1dSRodney W. Grimes sizeof(struct in_addr) > ipt->ipt_len) 1180df8bae1dSRodney W. Grimes goto bad; 118194a5d9b6SDavid Greenman (void)memcpy(&ipaddr.sin_addr, sin, 1182df8bae1dSRodney W. Grimes sizeof(struct in_addr)); 1183df8bae1dSRodney W. Grimes if (ifa_ifwithaddr((SA)&ipaddr) == 0) 1184df8bae1dSRodney W. Grimes continue; 1185df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(struct in_addr); 1186df8bae1dSRodney W. Grimes break; 1187df8bae1dSRodney W. Grimes 1188df8bae1dSRodney W. Grimes default: 1189df8bae1dSRodney W. Grimes goto bad; 1190df8bae1dSRodney W. Grimes } 1191df8bae1dSRodney W. Grimes ntime = iptime(); 119294a5d9b6SDavid Greenman (void)memcpy(cp + ipt->ipt_ptr - 1, &ntime, 1193df8bae1dSRodney W. Grimes sizeof(n_time)); 1194df8bae1dSRodney W. Grimes ipt->ipt_ptr += sizeof(n_time); 1195df8bae1dSRodney W. Grimes } 1196df8bae1dSRodney W. Grimes } 119747174b49SAndrey A. Chernov if (forward && ipforwarding) { 1198df8bae1dSRodney W. Grimes ip_forward(m, 1); 1199df8bae1dSRodney W. Grimes return (1); 1200df8bae1dSRodney W. Grimes } 1201df8bae1dSRodney W. Grimes return (0); 1202df8bae1dSRodney W. Grimes bad: 120358938916SGarrett Wollman ip->ip_len -= IP_VHL_HL(ip->ip_vhl) << 2; /* XXX icmp_error adds in hdr length */ 1204df8bae1dSRodney W. Grimes icmp_error(m, type, code, 0, 0); 1205df8bae1dSRodney W. Grimes ipstat.ips_badoptions++; 1206df8bae1dSRodney W. Grimes return (1); 1207df8bae1dSRodney W. Grimes } 1208df8bae1dSRodney W. Grimes 1209df8bae1dSRodney W. Grimes /* 1210df8bae1dSRodney W. Grimes * Given address of next destination (final or next hop), 1211df8bae1dSRodney W. Grimes * return internet address info of interface to be used to get there. 1212df8bae1dSRodney W. Grimes */ 12130312fbe9SPoul-Henning Kamp static struct in_ifaddr * 1214df8bae1dSRodney W. Grimes ip_rtaddr(dst) 1215df8bae1dSRodney W. Grimes struct in_addr dst; 1216df8bae1dSRodney W. Grimes { 1217df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1218df8bae1dSRodney W. Grimes 1219df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; 1220df8bae1dSRodney W. Grimes 1221df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { 1222df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1223df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1224df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1225df8bae1dSRodney W. Grimes } 1226df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1227df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1228df8bae1dSRodney W. Grimes sin->sin_addr = dst; 1229df8bae1dSRodney W. Grimes 12302c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1231df8bae1dSRodney W. Grimes } 1232df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) 1233df8bae1dSRodney W. Grimes return ((struct in_ifaddr *)0); 1234df8bae1dSRodney W. Grimes return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa); 1235df8bae1dSRodney W. Grimes } 1236df8bae1dSRodney W. Grimes 1237df8bae1dSRodney W. Grimes /* 1238df8bae1dSRodney W. Grimes * Save incoming source route for use in replies, 1239df8bae1dSRodney W. Grimes * to be picked up later by ip_srcroute if the receiver is interested. 1240df8bae1dSRodney W. Grimes */ 1241df8bae1dSRodney W. Grimes void 1242df8bae1dSRodney W. Grimes save_rte(option, dst) 1243df8bae1dSRodney W. Grimes u_char *option; 1244df8bae1dSRodney W. Grimes struct in_addr dst; 1245df8bae1dSRodney W. Grimes { 1246df8bae1dSRodney W. Grimes unsigned olen; 1247df8bae1dSRodney W. Grimes 1248df8bae1dSRodney W. Grimes olen = option[IPOPT_OLEN]; 1249df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1250df8bae1dSRodney W. Grimes if (ipprintfs) 1251df8bae1dSRodney W. Grimes printf("save_rte: olen %d\n", olen); 1252df8bae1dSRodney W. Grimes #endif 1253df8bae1dSRodney W. Grimes if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) 1254df8bae1dSRodney W. Grimes return; 12550453d3cbSBruce Evans bcopy(option, ip_srcrt.srcopt, olen); 1256df8bae1dSRodney W. Grimes ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); 1257df8bae1dSRodney W. Grimes ip_srcrt.dst = dst; 1258df8bae1dSRodney W. Grimes } 1259df8bae1dSRodney W. Grimes 1260df8bae1dSRodney W. Grimes /* 1261df8bae1dSRodney W. Grimes * Retrieve incoming source route for use in replies, 1262df8bae1dSRodney W. Grimes * in the same form used by setsockopt. 1263df8bae1dSRodney W. Grimes * The first hop is placed before the options, will be removed later. 1264df8bae1dSRodney W. Grimes */ 1265df8bae1dSRodney W. Grimes struct mbuf * 1266df8bae1dSRodney W. Grimes ip_srcroute() 1267df8bae1dSRodney W. Grimes { 1268df8bae1dSRodney W. Grimes register struct in_addr *p, *q; 1269df8bae1dSRodney W. Grimes register struct mbuf *m; 1270df8bae1dSRodney W. Grimes 1271df8bae1dSRodney W. Grimes if (ip_nhops == 0) 1272df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1273cfe8b629SGarrett Wollman m = m_get(M_DONTWAIT, MT_HEADER); 1274df8bae1dSRodney W. Grimes if (m == 0) 1275df8bae1dSRodney W. Grimes return ((struct mbuf *)0); 1276df8bae1dSRodney W. Grimes 1277df8bae1dSRodney W. Grimes #define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) 1278df8bae1dSRodney W. Grimes 1279df8bae1dSRodney W. Grimes /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ 1280df8bae1dSRodney W. Grimes m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + 1281df8bae1dSRodney W. Grimes OPTSIZ; 1282df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1283df8bae1dSRodney W. Grimes if (ipprintfs) 1284df8bae1dSRodney W. Grimes printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len); 1285df8bae1dSRodney W. Grimes #endif 1286df8bae1dSRodney W. Grimes 1287df8bae1dSRodney W. Grimes /* 1288df8bae1dSRodney W. Grimes * First save first hop for return route 1289df8bae1dSRodney W. Grimes */ 1290df8bae1dSRodney W. Grimes p = &ip_srcrt.route[ip_nhops - 1]; 1291df8bae1dSRodney W. Grimes *(mtod(m, struct in_addr *)) = *p--; 1292df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1293df8bae1dSRodney W. Grimes if (ipprintfs) 1294af38c68cSLuigi Rizzo printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr)); 1295df8bae1dSRodney W. Grimes #endif 1296df8bae1dSRodney W. Grimes 1297df8bae1dSRodney W. Grimes /* 1298df8bae1dSRodney W. Grimes * Copy option fields and padding (nop) to mbuf. 1299df8bae1dSRodney W. Grimes */ 1300df8bae1dSRodney W. Grimes ip_srcrt.nop = IPOPT_NOP; 1301df8bae1dSRodney W. Grimes ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; 130294a5d9b6SDavid Greenman (void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr), 130394a5d9b6SDavid Greenman &ip_srcrt.nop, OPTSIZ); 1304df8bae1dSRodney W. Grimes q = (struct in_addr *)(mtod(m, caddr_t) + 1305df8bae1dSRodney W. Grimes sizeof(struct in_addr) + OPTSIZ); 1306df8bae1dSRodney W. Grimes #undef OPTSIZ 1307df8bae1dSRodney W. Grimes /* 1308df8bae1dSRodney W. Grimes * Record return path as an IP source route, 1309df8bae1dSRodney W. Grimes * reversing the path (pointers are now aligned). 1310df8bae1dSRodney W. Grimes */ 1311df8bae1dSRodney W. Grimes while (p >= ip_srcrt.route) { 1312df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1313df8bae1dSRodney W. Grimes if (ipprintfs) 1314af38c68cSLuigi Rizzo printf(" %lx", (u_long)ntohl(q->s_addr)); 1315df8bae1dSRodney W. Grimes #endif 1316df8bae1dSRodney W. Grimes *q++ = *p--; 1317df8bae1dSRodney W. Grimes } 1318df8bae1dSRodney W. Grimes /* 1319df8bae1dSRodney W. Grimes * Last hop goes to final destination. 1320df8bae1dSRodney W. Grimes */ 1321df8bae1dSRodney W. Grimes *q = ip_srcrt.dst; 1322df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1323df8bae1dSRodney W. Grimes if (ipprintfs) 1324af38c68cSLuigi Rizzo printf(" %lx\n", (u_long)ntohl(q->s_addr)); 1325df8bae1dSRodney W. Grimes #endif 1326df8bae1dSRodney W. Grimes return (m); 1327df8bae1dSRodney W. Grimes } 1328df8bae1dSRodney W. Grimes 1329df8bae1dSRodney W. Grimes /* 1330df8bae1dSRodney W. Grimes * Strip out IP options, at higher 1331df8bae1dSRodney W. Grimes * level protocol in the kernel. 1332df8bae1dSRodney W. Grimes * Second argument is buffer to which options 1333df8bae1dSRodney W. Grimes * will be moved, and return value is their length. 1334df8bae1dSRodney W. Grimes * XXX should be deleted; last arg currently ignored. 1335df8bae1dSRodney W. Grimes */ 1336df8bae1dSRodney W. Grimes void 1337df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt) 1338df8bae1dSRodney W. Grimes register struct mbuf *m; 1339df8bae1dSRodney W. Grimes struct mbuf *mopt; 1340df8bae1dSRodney W. Grimes { 1341df8bae1dSRodney W. Grimes register int i; 1342df8bae1dSRodney W. Grimes struct ip *ip = mtod(m, struct ip *); 1343df8bae1dSRodney W. Grimes register caddr_t opts; 1344df8bae1dSRodney W. Grimes int olen; 1345df8bae1dSRodney W. Grimes 134658938916SGarrett Wollman olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); 1347df8bae1dSRodney W. Grimes opts = (caddr_t)(ip + 1); 1348df8bae1dSRodney W. Grimes i = m->m_len - (sizeof (struct ip) + olen); 1349df8bae1dSRodney W. Grimes bcopy(opts + olen, opts, (unsigned)i); 1350df8bae1dSRodney W. Grimes m->m_len -= olen; 1351df8bae1dSRodney W. Grimes if (m->m_flags & M_PKTHDR) 1352df8bae1dSRodney W. Grimes m->m_pkthdr.len -= olen; 135358938916SGarrett Wollman ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); 1354df8bae1dSRodney W. Grimes } 1355df8bae1dSRodney W. Grimes 1356df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = { 1357df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1358df8bae1dSRodney W. Grimes 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, 1359df8bae1dSRodney W. Grimes EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 1360df8bae1dSRodney W. Grimes EMSGSIZE, EHOSTUNREACH, 0, 0, 1361df8bae1dSRodney W. Grimes 0, 0, 0, 0, 1362df8bae1dSRodney W. Grimes ENOPROTOOPT 1363df8bae1dSRodney W. Grimes }; 1364df8bae1dSRodney W. Grimes 1365df8bae1dSRodney W. Grimes /* 1366df8bae1dSRodney W. Grimes * Forward a packet. If some error occurs return the sender 1367df8bae1dSRodney W. Grimes * an icmp packet. Note we can't always generate a meaningful 1368df8bae1dSRodney W. Grimes * icmp message because icmp doesn't have a large enough repertoire 1369df8bae1dSRodney W. Grimes * of codes and types. 1370df8bae1dSRodney W. Grimes * 1371df8bae1dSRodney W. Grimes * If not forwarding, just drop the packet. This could be confusing 1372df8bae1dSRodney W. Grimes * if ipforwarding was zero but some routing protocol was advancing 1373df8bae1dSRodney W. Grimes * us as a gateway to somewhere. However, we must let the routing 1374df8bae1dSRodney W. Grimes * protocol deal with that. 1375df8bae1dSRodney W. Grimes * 1376df8bae1dSRodney W. Grimes * The srcrt parameter indicates whether the packet is being forwarded 1377df8bae1dSRodney W. Grimes * via a source route. 1378df8bae1dSRodney W. Grimes */ 13790312fbe9SPoul-Henning Kamp static void 1380df8bae1dSRodney W. Grimes ip_forward(m, srcrt) 1381df8bae1dSRodney W. Grimes struct mbuf *m; 1382df8bae1dSRodney W. Grimes int srcrt; 1383df8bae1dSRodney W. Grimes { 1384df8bae1dSRodney W. Grimes register struct ip *ip = mtod(m, struct ip *); 1385df8bae1dSRodney W. Grimes register struct sockaddr_in *sin; 1386df8bae1dSRodney W. Grimes register struct rtentry *rt; 138726f9a767SRodney W. Grimes int error, type = 0, code = 0; 1388df8bae1dSRodney W. Grimes struct mbuf *mcopy; 1389df8bae1dSRodney W. Grimes n_long dest; 1390df8bae1dSRodney W. Grimes struct ifnet *destifp; 1391df8bae1dSRodney W. Grimes 1392df8bae1dSRodney W. Grimes dest = 0; 1393df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1394df8bae1dSRodney W. Grimes if (ipprintfs) 139561ce519bSPoul-Henning Kamp printf("forward: src %lx dst %lx ttl %x\n", 1396162886e2SBruce Evans (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr, 1397162886e2SBruce Evans ip->ip_ttl); 1398df8bae1dSRodney W. Grimes #endif 1399100ba1a6SJordan K. Hubbard 1400100ba1a6SJordan K. Hubbard 140192af003dSGarrett Wollman if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { 1402df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1403df8bae1dSRodney W. Grimes m_freem(m); 1404df8bae1dSRodney W. Grimes return; 1405df8bae1dSRodney W. Grimes } 1406df8bae1dSRodney W. Grimes HTONS(ip->ip_id); 1407df8bae1dSRodney W. Grimes if (ip->ip_ttl <= IPTTLDEC) { 1408df8bae1dSRodney W. Grimes icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); 1409df8bae1dSRodney W. Grimes return; 1410df8bae1dSRodney W. Grimes } 1411df8bae1dSRodney W. Grimes ip->ip_ttl -= IPTTLDEC; 1412df8bae1dSRodney W. Grimes 1413df8bae1dSRodney W. Grimes sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; 1414df8bae1dSRodney W. Grimes if ((rt = ipforward_rt.ro_rt) == 0 || 1415df8bae1dSRodney W. Grimes ip->ip_dst.s_addr != sin->sin_addr.s_addr) { 1416df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) { 1417df8bae1dSRodney W. Grimes RTFREE(ipforward_rt.ro_rt); 1418df8bae1dSRodney W. Grimes ipforward_rt.ro_rt = 0; 1419df8bae1dSRodney W. Grimes } 1420df8bae1dSRodney W. Grimes sin->sin_family = AF_INET; 1421df8bae1dSRodney W. Grimes sin->sin_len = sizeof(*sin); 1422df8bae1dSRodney W. Grimes sin->sin_addr = ip->ip_dst; 1423df8bae1dSRodney W. Grimes 14242c17fe93SGarrett Wollman rtalloc_ign(&ipforward_rt, RTF_PRCLONING); 1425df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt == 0) { 1426df8bae1dSRodney W. Grimes icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); 1427df8bae1dSRodney W. Grimes return; 1428df8bae1dSRodney W. Grimes } 1429df8bae1dSRodney W. Grimes rt = ipforward_rt.ro_rt; 1430df8bae1dSRodney W. Grimes } 1431df8bae1dSRodney W. Grimes 1432df8bae1dSRodney W. Grimes /* 1433df8bae1dSRodney W. Grimes * Save at most 64 bytes of the packet in case 1434df8bae1dSRodney W. Grimes * we need to generate an ICMP message to the src. 1435df8bae1dSRodney W. Grimes */ 1436df8bae1dSRodney W. Grimes mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64)); 1437df8bae1dSRodney W. Grimes 1438df8bae1dSRodney W. Grimes /* 1439df8bae1dSRodney W. Grimes * If forwarding packet using same interface that it came in on, 1440df8bae1dSRodney W. Grimes * perhaps should send a redirect to sender to shortcut a hop. 1441df8bae1dSRodney W. Grimes * Only send redirect if source is sending directly to us, 1442df8bae1dSRodney W. Grimes * and if packet was not source routed (or has any options). 1443df8bae1dSRodney W. Grimes * Also, don't send redirect if forwarding using a default route 1444df8bae1dSRodney W. Grimes * or a route modified by a redirect. 1445df8bae1dSRodney W. Grimes */ 1446df8bae1dSRodney W. Grimes #define satosin(sa) ((struct sockaddr_in *)(sa)) 1447df8bae1dSRodney W. Grimes if (rt->rt_ifp == m->m_pkthdr.rcvif && 1448df8bae1dSRodney W. Grimes (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && 1449df8bae1dSRodney W. Grimes satosin(rt_key(rt))->sin_addr.s_addr != 0 && 1450df8bae1dSRodney W. Grimes ipsendredirects && !srcrt) { 1451df8bae1dSRodney W. Grimes #define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) 1452df8bae1dSRodney W. Grimes u_long src = ntohl(ip->ip_src.s_addr); 1453df8bae1dSRodney W. Grimes 1454df8bae1dSRodney W. Grimes if (RTA(rt) && 1455df8bae1dSRodney W. Grimes (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { 1456df8bae1dSRodney W. Grimes if (rt->rt_flags & RTF_GATEWAY) 1457df8bae1dSRodney W. Grimes dest = satosin(rt->rt_gateway)->sin_addr.s_addr; 1458df8bae1dSRodney W. Grimes else 1459df8bae1dSRodney W. Grimes dest = ip->ip_dst.s_addr; 1460df8bae1dSRodney W. Grimes /* Router requirements says to only send host redirects */ 1461df8bae1dSRodney W. Grimes type = ICMP_REDIRECT; 1462df8bae1dSRodney W. Grimes code = ICMP_REDIRECT_HOST; 1463df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1464df8bae1dSRodney W. Grimes if (ipprintfs) 1465df8bae1dSRodney W. Grimes printf("redirect (%d) to %lx\n", code, (u_long)dest); 1466df8bae1dSRodney W. Grimes #endif 1467df8bae1dSRodney W. Grimes } 1468df8bae1dSRodney W. Grimes } 1469df8bae1dSRodney W. Grimes 1470b97d15cbSGarrett Wollman error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 1471b97d15cbSGarrett Wollman IP_FORWARDING, 0); 1472df8bae1dSRodney W. Grimes if (error) 1473df8bae1dSRodney W. Grimes ipstat.ips_cantforward++; 1474df8bae1dSRodney W. Grimes else { 1475df8bae1dSRodney W. Grimes ipstat.ips_forward++; 1476df8bae1dSRodney W. Grimes if (type) 1477df8bae1dSRodney W. Grimes ipstat.ips_redirectsent++; 1478df8bae1dSRodney W. Grimes else { 14791f91d8c5SDavid Greenman if (mcopy) { 14801f91d8c5SDavid Greenman ipflow_create(&ipforward_rt, mcopy); 1481df8bae1dSRodney W. Grimes m_freem(mcopy); 14821f91d8c5SDavid Greenman } 1483df8bae1dSRodney W. Grimes return; 1484df8bae1dSRodney W. Grimes } 1485df8bae1dSRodney W. Grimes } 1486df8bae1dSRodney W. Grimes if (mcopy == NULL) 1487df8bae1dSRodney W. Grimes return; 1488df8bae1dSRodney W. Grimes destifp = NULL; 1489df8bae1dSRodney W. Grimes 1490df8bae1dSRodney W. Grimes switch (error) { 1491df8bae1dSRodney W. Grimes 1492df8bae1dSRodney W. Grimes case 0: /* forwarded, but need redirect */ 1493df8bae1dSRodney W. Grimes /* type, code set above */ 1494df8bae1dSRodney W. Grimes break; 1495df8bae1dSRodney W. Grimes 1496df8bae1dSRodney W. Grimes case ENETUNREACH: /* shouldn't happen, checked above */ 1497df8bae1dSRodney W. Grimes case EHOSTUNREACH: 1498df8bae1dSRodney W. Grimes case ENETDOWN: 1499df8bae1dSRodney W. Grimes case EHOSTDOWN: 1500df8bae1dSRodney W. Grimes default: 1501df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1502df8bae1dSRodney W. Grimes code = ICMP_UNREACH_HOST; 1503df8bae1dSRodney W. Grimes break; 1504df8bae1dSRodney W. Grimes 1505df8bae1dSRodney W. Grimes case EMSGSIZE: 1506df8bae1dSRodney W. Grimes type = ICMP_UNREACH; 1507df8bae1dSRodney W. Grimes code = ICMP_UNREACH_NEEDFRAG; 1508df8bae1dSRodney W. Grimes if (ipforward_rt.ro_rt) 1509df8bae1dSRodney W. Grimes destifp = ipforward_rt.ro_rt->rt_ifp; 1510df8bae1dSRodney W. Grimes ipstat.ips_cantfrag++; 1511df8bae1dSRodney W. Grimes break; 1512df8bae1dSRodney W. Grimes 1513df8bae1dSRodney W. Grimes case ENOBUFS: 1514df8bae1dSRodney W. Grimes type = ICMP_SOURCEQUENCH; 1515df8bae1dSRodney W. Grimes code = 0; 1516df8bae1dSRodney W. Grimes break; 1517df8bae1dSRodney W. Grimes } 1518df8bae1dSRodney W. Grimes icmp_error(mcopy, type, code, dest, destifp); 1519df8bae1dSRodney W. Grimes } 1520df8bae1dSRodney W. Grimes 152182c23ebaSBill Fenner void 152282c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m) 152382c23ebaSBill Fenner register struct inpcb *inp; 152482c23ebaSBill Fenner register struct mbuf **mp; 152582c23ebaSBill Fenner register struct ip *ip; 152682c23ebaSBill Fenner register struct mbuf *m; 152782c23ebaSBill Fenner { 152882c23ebaSBill Fenner if (inp->inp_socket->so_options & SO_TIMESTAMP) { 152982c23ebaSBill Fenner struct timeval tv; 153082c23ebaSBill Fenner 153182c23ebaSBill Fenner microtime(&tv); 153282c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), 153382c23ebaSBill Fenner SCM_TIMESTAMP, SOL_SOCKET); 153482c23ebaSBill Fenner if (*mp) 153582c23ebaSBill Fenner mp = &(*mp)->m_next; 153682c23ebaSBill Fenner } 153782c23ebaSBill Fenner if (inp->inp_flags & INP_RECVDSTADDR) { 153882c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, 153982c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); 154082c23ebaSBill Fenner if (*mp) 154182c23ebaSBill Fenner mp = &(*mp)->m_next; 154282c23ebaSBill Fenner } 154382c23ebaSBill Fenner #ifdef notyet 154482c23ebaSBill Fenner /* XXX 154582c23ebaSBill Fenner * Moving these out of udp_input() made them even more broken 154682c23ebaSBill Fenner * than they already were. 154782c23ebaSBill Fenner */ 154882c23ebaSBill Fenner /* options were tossed already */ 154982c23ebaSBill Fenner if (inp->inp_flags & INP_RECVOPTS) { 155082c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) opts_deleted_above, 155182c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP); 155282c23ebaSBill Fenner if (*mp) 155382c23ebaSBill Fenner mp = &(*mp)->m_next; 155482c23ebaSBill Fenner } 155582c23ebaSBill Fenner /* ip_srcroute doesn't do what we want here, need to fix */ 155682c23ebaSBill Fenner if (inp->inp_flags & INP_RECVRETOPTS) { 155782c23ebaSBill Fenner *mp = sbcreatecontrol((caddr_t) ip_srcroute(), 155882c23ebaSBill Fenner sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP); 155982c23ebaSBill Fenner if (*mp) 156082c23ebaSBill Fenner mp = &(*mp)->m_next; 156182c23ebaSBill Fenner } 156282c23ebaSBill Fenner #endif 156382c23ebaSBill Fenner if (inp->inp_flags & INP_RECVIF) { 1564d314ad7bSJulian Elischer struct ifnet *ifp; 1565d314ad7bSJulian Elischer struct sdlbuf { 156682c23ebaSBill Fenner struct sockaddr_dl sdl; 1567d314ad7bSJulian Elischer u_char pad[32]; 1568d314ad7bSJulian Elischer } sdlbuf; 1569d314ad7bSJulian Elischer struct sockaddr_dl *sdp; 1570d314ad7bSJulian Elischer struct sockaddr_dl *sdl2 = &sdlbuf.sdl; 157182c23ebaSBill Fenner 1572d314ad7bSJulian Elischer if (((ifp = m->m_pkthdr.rcvif)) 1573d314ad7bSJulian Elischer && ( ifp->if_index && (ifp->if_index <= if_index))) { 1574d314ad7bSJulian Elischer sdp = (struct sockaddr_dl *)(ifnet_addrs 1575d314ad7bSJulian Elischer [ifp->if_index - 1]->ifa_addr); 1576d314ad7bSJulian Elischer /* 1577d314ad7bSJulian Elischer * Change our mind and don't try copy. 1578d314ad7bSJulian Elischer */ 1579d314ad7bSJulian Elischer if ((sdp->sdl_family != AF_LINK) 1580d314ad7bSJulian Elischer || (sdp->sdl_len > sizeof(sdlbuf))) { 1581d314ad7bSJulian Elischer goto makedummy; 1582d314ad7bSJulian Elischer } 1583d314ad7bSJulian Elischer bcopy(sdp, sdl2, sdp->sdl_len); 1584d314ad7bSJulian Elischer } else { 1585d314ad7bSJulian Elischer makedummy: 1586d314ad7bSJulian Elischer sdl2->sdl_len 1587d314ad7bSJulian Elischer = offsetof(struct sockaddr_dl, sdl_data[0]); 1588d314ad7bSJulian Elischer sdl2->sdl_family = AF_LINK; 1589d314ad7bSJulian Elischer sdl2->sdl_index = 0; 1590d314ad7bSJulian Elischer sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0; 1591d314ad7bSJulian Elischer } 1592d314ad7bSJulian Elischer *mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len, 159382c23ebaSBill Fenner IP_RECVIF, IPPROTO_IP); 159482c23ebaSBill Fenner if (*mp) 159582c23ebaSBill Fenner mp = &(*mp)->m_next; 159682c23ebaSBill Fenner } 159782c23ebaSBill Fenner } 159882c23ebaSBill Fenner 1599df8bae1dSRodney W. Grimes int 1600f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so) 1601f0068c4aSGarrett Wollman { 1602f0068c4aSGarrett Wollman if (so->so_type != SOCK_RAW || 1603f0068c4aSGarrett Wollman so->so_proto->pr_protocol != IPPROTO_RSVP) 1604f0068c4aSGarrett Wollman return EOPNOTSUPP; 1605f0068c4aSGarrett Wollman 1606f0068c4aSGarrett Wollman if (ip_rsvpd != NULL) 1607f0068c4aSGarrett Wollman return EADDRINUSE; 1608f0068c4aSGarrett Wollman 1609f0068c4aSGarrett Wollman ip_rsvpd = so; 16101c5de19aSGarrett Wollman /* 16111c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-increment 16121c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 16131c5de19aSGarrett Wollman */ 16141c5de19aSGarrett Wollman if (!ip_rsvp_on) { 16151c5de19aSGarrett Wollman ip_rsvp_on = 1; 16161c5de19aSGarrett Wollman rsvp_on++; 16171c5de19aSGarrett Wollman } 1618f0068c4aSGarrett Wollman 1619f0068c4aSGarrett Wollman return 0; 1620f0068c4aSGarrett Wollman } 1621f0068c4aSGarrett Wollman 1622f0068c4aSGarrett Wollman int 1623f0068c4aSGarrett Wollman ip_rsvp_done(void) 1624f0068c4aSGarrett Wollman { 1625f0068c4aSGarrett Wollman ip_rsvpd = NULL; 16261c5de19aSGarrett Wollman /* 16271c5de19aSGarrett Wollman * This may seem silly, but we need to be sure we don't over-decrement 16281c5de19aSGarrett Wollman * the RSVP counter, in case something slips up. 16291c5de19aSGarrett Wollman */ 16301c5de19aSGarrett Wollman if (ip_rsvp_on) { 16311c5de19aSGarrett Wollman ip_rsvp_on = 0; 16321c5de19aSGarrett Wollman rsvp_on--; 16331c5de19aSGarrett Wollman } 1634f0068c4aSGarrett Wollman return 0; 1635f0068c4aSGarrett Wollman } 1636