ip_fastfwd.c revision 148887
1184610Salfred/*- 2184610Salfred * Copyright (c) 2003 Andre Oppermann, Internet Business Solutions AG 3184610Salfred * All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 3. The name of the author may not be used to endorse or promote 14184610Salfred * products derived from this software without specific prior written 15184610Salfred * permission. 16184610Salfred * 17184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27194677Sthompsa * SUCH DAMAGE. 28194677Sthompsa * 29194677Sthompsa * $FreeBSD: head/sys/netinet/ip_fastfwd.c 148887 2005-08-09 10:20:02Z rwatson $ 30194677Sthompsa */ 31194677Sthompsa 32194677Sthompsa/* 33194677Sthompsa * ip_fastforward gets its speed from processing the forwarded packet to 34194677Sthompsa * completion (if_output on the other side) without any queues or netisr's. 35194677Sthompsa * The receiving interface DMAs the packet into memory, the upper half of 36194677Sthompsa * driver calls ip_fastforward, we do our routing table lookup and directly 37194677Sthompsa * send it off to the outgoing interface, which DMAs the packet to the 38194677Sthompsa * network card. The only part of the packet we touch with the CPU is the 39194677Sthompsa * IP header (unless there are complex firewall rules touching other parts 40194677Sthompsa * of the packet, but that is up to you). We are essentially limited by bus 41194677Sthompsa * bandwidth and how fast the network card/driver can set up receives and 42194677Sthompsa * transmits. 43194677Sthompsa * 44194677Sthompsa * We handle basic errors, IP header errors, checksum errors, 45194677Sthompsa * destination unreachable, fragmentation and fragmentation needed and 46194677Sthompsa * report them via ICMP to the sender. 47194677Sthompsa * 48188942Sthompsa * Else if something is not pure IPv4 unicast forwarding we fall back to 49188942Sthompsa * the normal ip_input processing path. We should only be called from 50194677Sthompsa * interfaces connected to the outside world. 51194677Sthompsa * 52184610Salfred * Firewalling is fully supported including divert, ipfw fwd and ipfilter 53184610Salfred * ipnat and address rewrite. 54184610Salfred * 55188942Sthompsa * IPSEC is not supported if this host is a tunnel broker. IPSEC is 56194677Sthompsa * supported for connections to/from local host. 57188942Sthompsa * 58188942Sthompsa * We try to do the least expensive (in CPU ops) checks and operations 59188942Sthompsa * first to catch junk with as little overhead as possible. 60188942Sthompsa * 61188942Sthompsa * We take full advantage of hardware support for IP checksum and 62188942Sthompsa * fragmentation offloading. 63188942Sthompsa * 64188942Sthompsa * We don't do ICMP redirect in the fast forwarding path. I have had my own 65188942Sthompsa * cases where two core routers with Zebra routing suite would send millions 66188942Sthompsa * ICMP redirects to connected hosts if the destination router was not the 67184610Salfred * default gateway. In one case it was filling the routing table of a host 68188942Sthompsa * with approximately 300.000 cloned redirect entries until it ran out of 69188942Sthompsa * kernel memory. However the networking code proved very robust and it didn't 70184610Salfred * crash or fail in other ways. 71190191Sthompsa */ 72190191Sthompsa 73184610Salfred/* 74184610Salfred * Many thanks to Matt Thomas of NetBSD for basic structure of ip_flow.c which 75184610Salfred * is being followed here. 76184610Salfred */ 77184610Salfred 78184610Salfred#include "opt_ipfw.h" 79184610Salfred#include "opt_ipstealth.h" 80184610Salfred 81193045Sthompsa#include <sys/param.h> 82193045Sthompsa#include <sys/systm.h> 83207080Sthompsa#include <sys/kernel.h> 84207080Sthompsa#include <sys/malloc.h> 85193045Sthompsa#include <sys/mbuf.h> 86193045Sthompsa#include <sys/protosw.h> 87207080Sthompsa#include <sys/socket.h> 88184610Salfred#include <sys/sysctl.h> 89193045Sthompsa 90193045Sthompsa#include <net/pfil.h> 91193045Sthompsa#include <net/if.h> 92193045Sthompsa#include <net/if_types.h> 93193045Sthompsa#include <net/if_var.h> 94193045Sthompsa#include <net/if_dl.h> 95193045Sthompsa#include <net/route.h> 96184610Salfred 97192984Sthompsa#include <netinet/in.h> 98192984Sthompsa#include <netinet/in_systm.h> 99192984Sthompsa#include <netinet/in_var.h> 100192984Sthompsa#include <netinet/ip.h> 101192984Sthompsa#include <netinet/ip_var.h> 102192984Sthompsa#include <netinet/ip_icmp.h> 103192984Sthompsa 104192984Sthompsa#include <machine/in_cksum.h> 105192984Sthompsa 106194228Sthompsastatic int ipfastforward_active = 0; 107192984SthompsaSYSCTL_INT(_net_inet_ip, OID_AUTO, fastforwarding, CTLFLAG_RW, 108192984Sthompsa &ipfastforward_active, 0, "Enable fast IP forwarding"); 109192984Sthompsa 110192984Sthompsastatic struct sockaddr_in * 111213432Shselaskyip_findroute(struct route *ro, struct in_addr dest, struct mbuf *m) 112184610Salfred{ 113184610Salfred struct sockaddr_in *dst; 114184610Salfred struct rtentry *rt; 115194228Sthompsa 116184610Salfred /* 117184610Salfred * Find route to destination. 118184610Salfred */ 119185087Salfred bzero(ro, sizeof(*ro)); 120184610Salfred dst = (struct sockaddr_in *)&ro->ro_dst; 121184610Salfred dst->sin_family = AF_INET; 122184610Salfred dst->sin_len = sizeof(*dst); 123184610Salfred dst->sin_addr.s_addr = dest.s_addr; 124184610Salfred rtalloc_ign(ro, RTF_CLONING); 125184610Salfred 126194677Sthompsa /* 127184610Salfred * Route there and interface still up? 128184610Salfred */ 129192502Sthompsa rt = ro->ro_rt; 130192502Sthompsa if (rt && (rt->rt_flags & RTF_UP) && 131184610Salfred (rt->rt_ifp->if_flags & IFF_UP) && 132199675Sthompsa (rt->rt_ifp->if_drv_flags & IFF_DRV_RUNNING)) { 133199675Sthompsa if (rt->rt_flags & RTF_GATEWAY) 134184610Salfred dst = (struct sockaddr_in *)rt->rt_gateway; 135184610Salfred } else { 136184610Salfred ipstat.ips_noroute++; 137184610Salfred ipstat.ips_cantforward++; 138184610Salfred if (rt) 139184610Salfred RTFREE(rt); 140192984Sthompsa icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); 141192984Sthompsa return NULL; 142184610Salfred } 143194677Sthompsa return dst; 144192984Sthompsa} 145193644Sthompsa 146184610Salfred/* 147184610Salfred * Try to forward a packet based on the destination address. 148184610Salfred * This is a fast path optimized for the plain forwarding case. 149184610Salfred * If the packet is handled (and consumed) here then we return 1; 150184610Salfred * otherwise 0 is returned and the packet should be delivered 151194228Sthompsa * to ip_input for full processing. 152184610Salfred */ 153184610Salfredint 154194228Sthompsaip_fastforward(struct mbuf *m) 155184610Salfred{ 156184610Salfred struct ip *ip; 157184610Salfred struct mbuf *m0 = NULL; 158184610Salfred struct route ro; 159194228Sthompsa struct sockaddr_in *dst = NULL; 160184610Salfred struct in_ifaddr *ia = NULL; 161184610Salfred struct ifaddr *ifa = NULL; 162194228Sthompsa struct ifnet *ifp; 163184610Salfred struct in_addr odest, dest; 164184610Salfred u_short sum, ip_len; 165184610Salfred int error = 0; 166184610Salfred int hlen, mtu; 167194228Sthompsa#ifdef IPFIREWALL_FORWARD 168184610Salfred struct m_tag *fwd_tag; 169184610Salfred#endif 170184610Salfred 171184610Salfred /* 172184610Salfred * Are we active and forwarding packets? 173184610Salfred */ 174184610Salfred if (!ipfastforward_active || !ipforwarding) 175184610Salfred return 0; 176192984Sthompsa 177184610Salfred M_ASSERTVALID(m); 178194677Sthompsa M_ASSERTPKTHDR(m); 179193644Sthompsa 180184610Salfred ro.ro_rt = NULL; 181184610Salfred 182184610Salfred /* 183184610Salfred * Step 1: check for packet drop conditions (and sanity checks) 184184610Salfred */ 185194228Sthompsa 186187180Sthompsa /* 187187180Sthompsa * Is entire packet big enough? 188187180Sthompsa */ 189187180Sthompsa if (m->m_pkthdr.len < sizeof(struct ip)) { 190187180Sthompsa ipstat.ips_tooshort++; 191187180Sthompsa goto drop; 192184610Salfred } 193184610Salfred 194187180Sthompsa /* 195184610Salfred * Is first mbuf large enough for ip header and is header present? 196184610Salfred */ 197184610Salfred if (m->m_len < sizeof (struct ip) && 198184610Salfred (m = m_pullup(m, sizeof (struct ip))) == NULL) { 199184610Salfred ipstat.ips_toosmall++; 200184610Salfred return 1; /* mbuf already free'd */ 201184610Salfred } 202184610Salfred 203184610Salfred ip = mtod(m, struct ip *); 204184610Salfred 205184610Salfred /* 206184610Salfred * Is it IPv4? 207184610Salfred */ 208184610Salfred if (ip->ip_v != IPVERSION) { 209184610Salfred ipstat.ips_badvers++; 210192984Sthompsa goto drop; 211184610Salfred } 212184610Salfred 213184610Salfred /* 214184610Salfred * Is IP header length correct and is it in first mbuf? 215184610Salfred */ 216184610Salfred hlen = ip->ip_hl << 2; 217194228Sthompsa if (hlen < sizeof(struct ip)) { /* minimum header length */ 218194228Sthompsa ipstat.ips_badlen++; 219184610Salfred goto drop; 220184610Salfred } 221194228Sthompsa if (hlen > m->m_len) { 222194228Sthompsa if ((m = m_pullup(m, hlen)) == 0) { 223184610Salfred ipstat.ips_badhlen++; 224184610Salfred return 1; 225184610Salfred } 226185290Salfred ip = mtod(m, struct ip *); 227184610Salfred } 228184610Salfred 229184610Salfred /* 230184610Salfred * Checksum correct? 231192984Sthompsa */ 232184610Salfred if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) 233192984Sthompsa sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); 234194677Sthompsa else { 235193644Sthompsa if (hlen == sizeof(struct ip)) 236184610Salfred sum = in_cksum_hdr(ip); 237184610Salfred else 238184610Salfred sum = in_cksum(m, hlen); 239184610Salfred } 240184610Salfred if (sum) { 241184610Salfred ipstat.ips_badsum++; 242184610Salfred goto drop; 243192984Sthompsa } 244184610Salfred 245192984Sthompsa /* 246192984Sthompsa * Remember that we have checked the IP header and found it valid. 247192984Sthompsa */ 248192984Sthompsa m->m_pkthdr.csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID); 249192984Sthompsa 250192984Sthompsa ip_len = ntohs(ip->ip_len); 251192984Sthompsa 252192984Sthompsa /* 253184610Salfred * Is IP length longer than packet we have got? 254192984Sthompsa */ 255192984Sthompsa if (m->m_pkthdr.len < ip_len) { 256192984Sthompsa ipstat.ips_tooshort++; 257192984Sthompsa goto drop; 258192984Sthompsa } 259192984Sthompsa 260184610Salfred /* 261184610Salfred * Is packet longer than IP header tells us? If yes, truncate packet. 262184610Salfred */ 263184610Salfred if (m->m_pkthdr.len > ip_len) { 264184610Salfred if (m->m_len == m->m_pkthdr.len) { 265192984Sthompsa m->m_len = ip_len; 266184610Salfred m->m_pkthdr.len = ip_len; 267207080Sthompsa } else 268192984Sthompsa m_adj(m, ip_len - m->m_pkthdr.len); 269192984Sthompsa } 270192984Sthompsa 271192984Sthompsa /* 272184610Salfred * Is packet from or to 127/8? 273184610Salfred */ 274184610Salfred if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || 275184610Salfred (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { 276184610Salfred ipstat.ips_badaddr++; 277184610Salfred goto drop; 278184610Salfred } 279192984Sthompsa 280192984Sthompsa#ifdef ALTQ 281192984Sthompsa /* 282192984Sthompsa * Is packet dropped by traffic conditioner? 283192984Sthompsa */ 284184610Salfred if (altq_input != NULL && (*altq_input)(m, AF_INET) == 0) 285184610Salfred return 1; 286192984Sthompsa#endif 287184610Salfred 288192984Sthompsa /* 289184610Salfred * Step 2: fallback conditions to normal ip_input path processing 290184610Salfred */ 291184610Salfred 292184610Salfred /* 293184610Salfred * Only IP packets without options 294184610Salfred */ 295184610Salfred if (ip->ip_hl != (sizeof(struct ip) >> 2)) { 296184610Salfred if (ip_doopts == 1) 297184610Salfred return 0; 298184610Salfred else if (ip_doopts == 2) { 299192984Sthompsa icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB, 300184610Salfred 0, 0); 301192984Sthompsa return 1; 302194677Sthompsa } 303193644Sthompsa /* else ignore IP options and continue */ 304184610Salfred } 305184610Salfred 306184610Salfred /* 307184610Salfred * Only unicast IP, not from loopback, no L2 or IP broadcast, 308184610Salfred * no multicast, no INADDR_ANY 309184610Salfred * 310184610Salfred * XXX: Probably some of these checks could be direct drop 311192984Sthompsa * conditions. However it is not clear whether there are some 312184610Salfred * hacks or obscure behaviours which make it neccessary to 313192984Sthompsa * let ip_input handle it. We play safe here and let ip_input 314192984Sthompsa * deal with it until it is proven that we can directly drop it. 315192984Sthompsa */ 316192984Sthompsa if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) || 317192984Sthompsa ntohl(ip->ip_src.s_addr) == (u_long)INADDR_BROADCAST || 318192984Sthompsa ntohl(ip->ip_dst.s_addr) == (u_long)INADDR_BROADCAST || 319192984Sthompsa IN_MULTICAST(ntohl(ip->ip_src.s_addr)) || 320192984Sthompsa IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || 321184610Salfred ip->ip_dst.s_addr == INADDR_ANY ) 322192984Sthompsa return 0; 323192984Sthompsa 324192984Sthompsa /* 325192984Sthompsa * Is it for a local address on this host? 326192984Sthompsa */ 327192984Sthompsa if (in_localip(ip->ip_dst)) 328184610Salfred return 0; 329184610Salfred 330184610Salfred /* 331184610Salfred * Or is it for a local IP broadcast address on this host? 332184610Salfred */ 333192984Sthompsa if ((m->m_flags & M_BCAST) && 334184610Salfred (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST)) { 335192984Sthompsa TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) { 336192984Sthompsa if (ifa->ifa_addr->sa_family != AF_INET) 337207080Sthompsa continue; 338192984Sthompsa ia = ifatoia(ifa); 339184610Salfred if (ia->ia_netbroadcast.s_addr == ip->ip_dst.s_addr) 340192984Sthompsa return 0; 341184610Salfred if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 342184610Salfred ip->ip_dst.s_addr) 343184610Salfred return 0; 344184610Salfred } 345184610Salfred } 346184610Salfred ipstat.ips_total++; 347184610Salfred 348192984Sthompsa /* 349192984Sthompsa * Step 3: incoming packet firewall processing 350192984Sthompsa */ 351192984Sthompsa 352192984Sthompsa /* 353184610Salfred * Convert to host representation 354184610Salfred */ 355192984Sthompsa ip->ip_len = ntohs(ip->ip_len); 356184610Salfred ip->ip_off = ntohs(ip->ip_off); 357192984Sthompsa 358184610Salfred odest.s_addr = dest.s_addr = ip->ip_dst.s_addr; 359184610Salfred 360184610Salfred /* 361184610Salfred * Run through list of ipfilter hooks for input packets 362184610Salfred */ 363184610Salfred if (inet_pfil_hook.ph_busy_count == -1) 364184610Salfred goto passin; 365184610Salfred 366184610Salfred if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN, NULL) || 367184610Salfred m == NULL) 368184610Salfred return 1; 369192984Sthompsa 370184610Salfred M_ASSERTVALID(m); 371184610Salfred M_ASSERTPKTHDR(m); 372184610Salfred 373184610Salfred ip = mtod(m, struct ip *); /* m may have changed by pfil hook */ 374194228Sthompsa dest.s_addr = ip->ip_dst.s_addr; 375184610Salfred 376184610Salfred /* 377194228Sthompsa * Destination address changed? 378194228Sthompsa */ 379184610Salfred if (odest.s_addr != dest.s_addr) { 380184610Salfred /* 381184610Salfred * Is it now for a local address on this host? 382192984Sthompsa */ 383184610Salfred if (in_localip(dest)) 384184610Salfred goto forwardlocal; 385184610Salfred /* 386184610Salfred * Go on with new destination address 387194228Sthompsa */ 388184610Salfred } 389184610Salfred#ifdef IPFIREWALL_FORWARD 390194228Sthompsa if (m->m_flags & M_FASTFWD_OURS) { 391194228Sthompsa /* 392184610Salfred * ipfw changed it for a local address on this host. 393184610Salfred */ 394184610Salfred goto forwardlocal; 395192984Sthompsa } 396184610Salfred#endif /* IPFIREWALL_FORWARD */ 397184610Salfred 398194228Sthompsapassin: 399194228Sthompsa /* 400184610Salfred * Step 4: decrement TTL and look up route 401184610Salfred */ 402184610Salfred 403207080Sthompsa /* 404184610Salfred * Check TTL 405194677Sthompsa */ 406192984Sthompsa#ifdef IPSTEALTH 407184610Salfred if (!ipstealth) { 408184610Salfred#endif 409184610Salfred if (ip->ip_ttl <= IPTTLDEC) { 410184610Salfred icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, 0); 411184610Salfred return 1; 412184610Salfred } 413184610Salfred 414184610Salfred /* 415184610Salfred * Decrement the TTL and incrementally change the IP header checksum. 416184610Salfred * Don't bother doing this with hw checksum offloading, it's faster 417184610Salfred * doing it right here. 418184610Salfred */ 419184610Salfred ip->ip_ttl -= IPTTLDEC; 420184610Salfred if (ip->ip_sum >= (u_int16_t) ~htons(IPTTLDEC << 8)) 421184610Salfred ip->ip_sum -= ~htons(IPTTLDEC << 8); 422184610Salfred else 423184610Salfred ip->ip_sum += htons(IPTTLDEC << 8); 424184610Salfred#ifdef IPSTEALTH 425184610Salfred } 426184610Salfred#endif 427194228Sthompsa 428184610Salfred /* 429184610Salfred * Find route to destination. 430184610Salfred */ 431184610Salfred if ((dst = ip_findroute(&ro, dest, m)) == NULL) 432194228Sthompsa return 1; /* icmp unreach already sent */ 433184610Salfred ifp = ro.ro_rt->rt_ifp; 434184610Salfred 435184610Salfred /* 436184610Salfred * Immediately drop blackholed traffic. 437194677Sthompsa */ 438194228Sthompsa if (ro.ro_rt->rt_flags & RTF_BLACKHOLE) 439184610Salfred goto drop; 440184610Salfred 441184610Salfred /* 442184610Salfred * Step 5: outgoing firewall packet processing 443184610Salfred */ 444190188Sthompsa 445194228Sthompsa /* 446184610Salfred * Run through list of hooks for output packets. 447184610Salfred */ 448194228Sthompsa if (inet_pfil_hook.ph_busy_count == -1) 449184610Salfred goto passout; 450184610Salfred 451184610Salfred if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT, NULL) || m == NULL) { 452184610Salfred goto consumed; 453184610Salfred } 454184610Salfred 455207080Sthompsa M_ASSERTVALID(m); 456184610Salfred M_ASSERTPKTHDR(m); 457194677Sthompsa 458193045Sthompsa ip = mtod(m, struct ip *); 459184610Salfred dest.s_addr = ip->ip_dst.s_addr; 460184610Salfred 461184610Salfred /* 462184610Salfred * Destination address changed? 463184610Salfred */ 464184610Salfred#ifndef IPFIREWALL_FORWARD 465184610Salfred if (odest.s_addr != dest.s_addr) { 466184610Salfred#else 467184610Salfred fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); 468184610Salfred if (odest.s_addr != dest.s_addr || fwd_tag != NULL) { 469184610Salfred#endif /* IPFIREWALL_FORWARD */ 470194228Sthompsa /* 471184610Salfred * Is it now for a local address on this host? 472184610Salfred */ 473184610Salfred#ifndef IPFIREWALL_FORWARD 474184610Salfred if (in_localip(dest)) { 475184610Salfred#else 476194228Sthompsa if (m->m_flags & M_FASTFWD_OURS || in_localip(dest)) { 477184610Salfred#endif /* IPFIREWALL_FORWARD */ 478194677Sthompsaforwardlocal: 479194228Sthompsa /* 480184610Salfred * Return packet for processing by ip_input(). 481184610Salfred * Keep host byte order as expected at ip_input's 482184610Salfred * "ours"-label. 483184610Salfred */ 484184610Salfred m->m_flags |= M_FASTFWD_OURS; 485184610Salfred if (ro.ro_rt) 486194228Sthompsa RTFREE(ro.ro_rt); 487184610Salfred return 0; 488184610Salfred } 489184610Salfred /* 490184610Salfred * Redo route lookup with new destination address 491184610Salfred */ 492184610Salfred#ifdef IPFIREWALL_FORWARD 493194677Sthompsa if (fwd_tag) { 494184610Salfred if (!in_localip(ip->ip_src) && !in_localaddr(ip->ip_dst)) 495194677Sthompsa dest.s_addr = ((struct sockaddr_in *)(fwd_tag+1))->sin_addr.s_addr; 496192984Sthompsa m_tag_delete(m, fwd_tag); 497184610Salfred } 498184610Salfred#endif /* IPFIREWALL_FORWARD */ 499184610Salfred RTFREE(ro.ro_rt); 500184610Salfred if ((dst = ip_findroute(&ro, dest, m)) == NULL) 501184610Salfred return 1; /* icmp unreach already sent */ 502194228Sthompsa ifp = ro.ro_rt->rt_ifp; 503184610Salfred } 504184610Salfred 505194228Sthompsapassout: 506184610Salfred /* 507184610Salfred * Step 6: send off the packet 508184610Salfred */ 509184610Salfred 510194677Sthompsa /* 511184610Salfred * Check if route is dampned (when ARP is unable to resolve) 512194677Sthompsa */ 513192984Sthompsa if ((ro.ro_rt->rt_flags & RTF_REJECT) && 514184610Salfred ro.ro_rt->rt_rmx.rmx_expire >= time_second) { 515184610Salfred icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); 516184610Salfred goto consumed; 517184610Salfred } 518184610Salfred 519194228Sthompsa#ifndef ALTQ 520184610Salfred /* 521184610Salfred * Check if there is enough space in the interface queue 522194228Sthompsa */ 523184610Salfred if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >= 524184610Salfred ifp->if_snd.ifq_maxlen) { 525184610Salfred ipstat.ips_odropped++; 526184610Salfred /* would send source quench here but that is depreciated */ 527194677Sthompsa goto drop; 528184610Salfred } 529194677Sthompsa#endif 530193045Sthompsa 531193045Sthompsa /* 532184610Salfred * Check if media link state of interface is not down 533184610Salfred */ 534184610Salfred if (ifp->if_link_state == LINK_STATE_DOWN) { 535184610Salfred icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); 536184610Salfred goto consumed; 537184610Salfred } 538184610Salfred 539184610Salfred /* 540184610Salfred * Check if packet fits MTU or if hardware will fragment for us 541184610Salfred */ 542184610Salfred if (ro.ro_rt->rt_rmx.rmx_mtu) 543194228Sthompsa mtu = min(ro.ro_rt->rt_rmx.rmx_mtu, ifp->if_mtu); 544184610Salfred else 545184610Salfred mtu = ifp->if_mtu; 546184610Salfred 547184610Salfred if (ip->ip_len <= mtu || 548184610Salfred (ifp->if_hwassist & CSUM_FRAGMENT && (ip->ip_off & IP_DF) == 0)) { 549184610Salfred /* 550184610Salfred * Restore packet header fields to original values 551184610Salfred */ 552194677Sthompsa ip->ip_len = htons(ip->ip_len); 553184610Salfred ip->ip_off = htons(ip->ip_off); 554194228Sthompsa /* 555184610Salfred * Send off the packet via outgoing interface 556184610Salfred */ 557184610Salfred error = (*ifp->if_output)(ifp, m, 558184610Salfred (struct sockaddr *)dst, ro.ro_rt); 559184610Salfred } else { 560184610Salfred /* 561184610Salfred * Handle EMSGSIZE with icmp reply needfrag for TCP MTU discovery 562184610Salfred */ 563184610Salfred if (ip->ip_off & IP_DF) { 564184610Salfred ipstat.ips_cantfrag++; 565184610Salfred icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 566194677Sthompsa 0, mtu); 567184610Salfred goto consumed; 568194677Sthompsa } else { 569193045Sthompsa /* 570193045Sthompsa * We have to fragment the packet 571193045Sthompsa */ 572184610Salfred m->m_pkthdr.csum_flags |= CSUM_IP; 573184610Salfred /* 574184610Salfred * ip_fragment expects ip_len and ip_off in host byte 575184610Salfred * order but returns all packets in network byte order 576184610Salfred */ 577184610Salfred if (ip_fragment(ip, &m, mtu, ifp->if_hwassist, 578184610Salfred (~ifp->if_hwassist & CSUM_DELAY_IP))) { 579184610Salfred goto drop; 580184610Salfred } 581194228Sthompsa KASSERT(m != NULL, ("null mbuf and no error")); 582184610Salfred /* 583194677Sthompsa * Send off the fragments via outgoing interface 584184610Salfred */ 585184610Salfred error = 0; 586184610Salfred do { 587184610Salfred m0 = m->m_nextpkt; 588184610Salfred m->m_nextpkt = NULL; 589184610Salfred 590184610Salfred error = (*ifp->if_output)(ifp, m, 591184610Salfred (struct sockaddr *)dst, ro.ro_rt); 592194677Sthompsa if (error) 593184610Salfred break; 594194228Sthompsa } while ((m = m0) != NULL); 595184610Salfred if (error) { 596184610Salfred /* Reclaim remaining fragments */ 597184610Salfred for (m = m0; m; m = m0) { 598184610Salfred m0 = m->m_nextpkt; 599184610Salfred m_freem(m); 600184610Salfred } 601184610Salfred } else 602184610Salfred ipstat.ips_fragmented++; 603184610Salfred } 604184610Salfred } 605184610Salfred 606192984Sthompsa if (error != 0) 607184610Salfred ipstat.ips_odropped++; 608184610Salfred else { 609184610Salfred ro.ro_rt->rt_rmx.rmx_pksent++; 610192499Sthompsa ipstat.ips_forward++; 611184610Salfred ipstat.ips_fastforward++; 612184610Salfred } 613184610Salfredconsumed: 614184610Salfred RTFREE(ro.ro_rt); 615184610Salfred return 1; 616184610Salfreddrop: 617184610Salfred if (m) 618185290Salfred m_freem(m); 619185290Salfred if (ro.ro_rt) 620185290Salfred RTFREE(ro.ro_rt); 621185290Salfred return 1; 622185290Salfred} 623185290Salfred