linux-old/net/ipv4/ip_forward.c
<<
>>
Prefs
   1/*
   2 * INET         An implementation of the TCP/IP protocol suite for the LINUX
   3 *              operating system.  INET is implemented using the  BSD Socket
   4 *              interface as the means of communication with the user level.
   5 *
   6 *              The IP forwarding functionality.
   7 *              
   8 * Version:     $Id: ip_forward.c,v 1.43 1999/03/21 05:22:37 davem Exp $
   9 *
  10 * Authors:     see ip.c
  11 *
  12 * Fixes:
  13 *              Many            :       Split from ip.c , see ip_input.c for 
  14 *                                      history.
  15 *              Dave Gregorich  :       NULL ip_rt_put fix for multicast 
  16 *                                      routing.
  17 *              Jos Vos         :       Add call_out_firewall before sending,
  18 *                                      use output device for accounting.
  19 *              Jos Vos         :       Call forward firewall after routing
  20 *                                      (always use output device).
  21 *              Mike McLagan    :       Routing by source
  22 */
  23
  24#include <linux/config.h>
  25#include <linux/types.h>
  26#include <linux/mm.h>
  27#include <linux/sched.h>
  28#include <linux/skbuff.h>
  29#include <linux/ip.h>
  30#include <linux/icmp.h>
  31#include <linux/netdevice.h>
  32#include <net/sock.h>
  33#include <net/ip.h>
  34#include <net/tcp.h>
  35#include <net/udp.h>
  36#include <net/icmp.h>
  37#include <linux/tcp.h>
  38#include <linux/udp.h>
  39#include <linux/firewall.h>
  40#include <linux/ip_fw.h>
  41#ifdef CONFIG_IP_MASQUERADE
  42#include <net/ip_masq.h>
  43#endif
  44#include <net/checksum.h>
  45#include <linux/route.h>
  46#include <net/route.h>
  47
  48#ifdef CONFIG_IP_TRANSPARENT_PROXY
  49/*
  50 *      Check the packet against our socket administration to see
  51 *      if it is related to a connection on our system.
  52 *      Needed for transparent proxying.
  53 */
  54
  55int ip_chksock(struct sk_buff *skb)
  56{
  57        switch (skb->nh.iph->protocol) {
  58        case IPPROTO_ICMP:
  59                return icmp_chkaddr(skb);
  60        case IPPROTO_TCP:
  61                return tcp_chkaddr(skb);
  62        case IPPROTO_UDP:
  63                return udp_chkaddr(skb);
  64        default:
  65                return 0;
  66        }
  67}
  68#endif
  69
  70
  71int ip_forward(struct sk_buff *skb)
  72{
  73        struct device *dev2;    /* Output device */
  74        struct iphdr *iph;      /* Our header */
  75        struct rtable *rt;      /* Route we use */
  76        struct ip_options * opt = &(IPCB(skb)->opt);
  77        unsigned short mtu;
  78#if defined(CONFIG_FIREWALL) || defined(CONFIG_IP_MASQUERADE)
  79        int fw_res = 0;
  80#endif
  81
  82        if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
  83                return 0;
  84
  85        if (skb->pkt_type != PACKET_HOST)
  86                goto drop;
  87        
  88        /*
  89         *      According to the RFC, we must first decrease the TTL field. If
  90         *      that reaches zero, we must reply an ICMP control message telling
  91         *      that the packet's lifetime expired.
  92         */
  93
  94        iph = skb->nh.iph;
  95        rt = (struct rtable*)skb->dst;
  96
  97#ifdef CONFIG_CPU_IS_SLOW
  98        if (net_cpu_congestion > 1 && !(iph->tos&IPTOS_RELIABILITY) &&
  99            IPTOS_PREC(iph->tos) < IPTOS_PREC_INTERNETCONTROL) {
 100                if (((xtime.tv_usec&0xF)<<net_cpu_congestion) > 0x1C)
 101                        goto drop;
 102        }
 103#endif
 104
 105
 106#ifdef CONFIG_IP_TRANSPARENT_PROXY
 107        if (ip_chksock(skb))
 108                goto local_pkt;
 109#endif
 110
 111        if (iph->ttl <= 1)
 112                goto too_many_hops;
 113
 114        if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
 115                goto sr_failed;
 116
 117        /*
 118         *      Having picked a route we can now send the frame out
 119         *      after asking the firewall permission to do so.
 120         */
 121
 122        skb->priority = rt_tos2priority(iph->tos);
 123        dev2 = rt->u.dst.dev;
 124        mtu = rt->u.dst.pmtu;
 125
 126#ifdef CONFIG_NET_SECURITY
 127        call_fw_firewall(PF_SECURITY, dev2, NULL, &mtu, NULL);
 128#endif  
 129        
 130        /*
 131         *      We now generate an ICMP HOST REDIRECT giving the route
 132         *      we calculated.
 133         */
 134        if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr)
 135                ip_rt_send_redirect(skb);
 136
 137        /* We are about to mangle packet. Copy it! */
 138        if ((skb = skb_cow(skb, dev2->hard_header_len)) == NULL)
 139                return -1;
 140        iph = skb->nh.iph;
 141        opt = &(IPCB(skb)->opt);
 142
 143        /* Decrease ttl after skb cow done */
 144        ip_decrease_ttl(iph);
 145
 146        /*
 147         * We now may allocate a new buffer, and copy the datagram into it.
 148         * If the indicated interface is up and running, kick it.
 149         */
 150
 151        if (skb->len > mtu && (ntohs(iph->frag_off) & IP_DF))
 152                goto frag_needed;
 153
 154#ifdef CONFIG_IP_ROUTE_NAT
 155        if (rt->rt_flags & RTCF_NAT) {
 156                if (ip_do_nat(skb)) {
 157                        kfree_skb(skb);
 158                        return -1;
 159                }
 160        }
 161#endif
 162
 163#ifdef CONFIG_IP_MASQUERADE
 164        if(!(IPCB(skb)->flags&IPSKB_MASQUERADED)) {
 165                /* 
 166                 *      Check that any ICMP packets are not for a 
 167                 *      masqueraded connection.  If so rewrite them
 168                 *      and skip the firewall checks
 169                 */
 170                if (iph->protocol == IPPROTO_ICMP) {
 171                        __u32 maddr;
 172#ifdef CONFIG_IP_MASQUERADE_ICMP
 173                        struct icmphdr *icmph = (struct icmphdr *)((char*)iph + (iph->ihl << 2));
 174                        if ((icmph->type==ICMP_DEST_UNREACH)||
 175                            (icmph->type==ICMP_SOURCE_QUENCH)||
 176                            (icmph->type==ICMP_TIME_EXCEEDED))
 177                        {
 178#endif
 179                                maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
 180                                fw_res = ip_fw_masq_icmp(&skb, maddr);
 181                                if (fw_res < 0) {
 182                                        kfree_skb(skb);
 183                                        return -1;
 184                                }
 185
 186                                if (fw_res)
 187                                        /* ICMP matched - skip firewall */
 188                                        goto skip_call_fw_firewall;
 189#ifdef CONFIG_IP_MASQUERADE_ICMP
 190                               }
 191#endif                          
 192                }
 193                if (rt->rt_flags&RTCF_MASQ)
 194                        goto skip_call_fw_firewall;
 195#endif /* CONFIG_IP_MASQUERADE */
 196
 197#ifdef CONFIG_FIREWALL
 198                fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL, &skb);
 199                switch (fw_res) {
 200                case FW_ACCEPT:
 201                case FW_MASQUERADE:
 202                        break;
 203                case FW_REJECT:
 204                        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
 205                        /* fall thru */
 206                default:
 207                        kfree_skb(skb);
 208                        return -1;
 209                }
 210#endif
 211
 212#ifdef CONFIG_IP_MASQUERADE
 213        }
 214
 215skip_call_fw_firewall:
 216        /*
 217         * If this fragment needs masquerading, make it so...
 218         * (Don't masquerade de-masqueraded fragments)
 219         */
 220        if (!(IPCB(skb)->flags&IPSKB_MASQUERADED) &&
 221            (fw_res==FW_MASQUERADE || rt->rt_flags&RTCF_MASQ)) {
 222                u32 maddr;
 223
 224#ifdef CONFIG_IP_ROUTE_NAT
 225                maddr = (rt->rt_flags&RTCF_MASQ) ? rt->rt_src_map : 0;
 226
 227                if (maddr == 0)
 228#endif
 229                        maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
 230
 231                        if (ip_fw_masquerade(&skb, maddr) < 0) {
 232                                kfree_skb(skb);
 233                                return -1;
 234                        } else {
 235                                /*
 236                                 *      Masquerader may have changed skb 
 237                                 */
 238                                iph = skb->nh.iph;
 239                                opt = &(IPCB(skb)->opt);
 240                        }
 241        }
 242#endif
 243
 244
 245#ifdef CONFIG_FIREWALL
 246        if ((fw_res = call_out_firewall(PF_INET, dev2, iph, NULL,&skb)) < FW_ACCEPT) {
 247                /* FW_ACCEPT and FW_MASQUERADE are treated equal:
 248                   masquerading is only supported via forward rules */
 249                if (fw_res == FW_REJECT)
 250                        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
 251                kfree_skb(skb);
 252                return -1;
 253        }
 254#endif
 255
 256        ip_statistics.IpForwDatagrams++;
 257
 258        if (opt->optlen == 0) {
 259#ifdef CONFIG_NET_FASTROUTE
 260                if (rt->rt_flags&RTCF_FAST && !netdev_fastroute_obstacles) {
 261                        unsigned h = ((*(u8*)&rt->key.dst)^(*(u8*)&rt->key.src))&NETDEV_FASTROUTE_HMASK;
 262                        /* Time to switch to functional programming :-) */
 263                        dst_release_irqwait(xchg(&skb->dev->fastpath[h], dst_clone(&rt->u.dst)));
 264                }
 265#endif
 266                ip_send(skb);
 267                return 0;
 268        }
 269
 270        ip_forward_options(skb);
 271        ip_send(skb);
 272        return 0;
 273
 274#ifdef CONFIG_IP_TRANSPARENT_PROXY
 275local_pkt:
 276        return ip_local_deliver(skb);
 277#endif
 278
 279frag_needed:
 280        ip_statistics.IpFragFails++;
 281        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
 282        goto drop;
 283
 284sr_failed:
 285        /*
 286         *      Strict routing permits no gatewaying
 287         */
 288         icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);
 289         goto drop;
 290
 291too_many_hops:
 292        /* Tell the sender its packet died... */
 293        icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
 294drop:
 295        kfree_skb(skb);
 296        return -1;
 297}
 298
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.