linux/net/ipv4/netfilter/iptable_mangle.c
<<
>>
Prefs
   1/*
   2 * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
   3 *
   4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
   5 * Copyright (C) 2000-2004 Netfilter Core Team <coreteam@netfilter.org>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11#include <linux/module.h>
  12#include <linux/netfilter_ipv4/ip_tables.h>
  13#include <linux/netdevice.h>
  14#include <linux/skbuff.h>
  15#include <net/sock.h>
  16#include <net/route.h>
  17#include <linux/ip.h>
  18#include <net/ip.h>
  19
  20MODULE_LICENSE("GPL");
  21MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
  22MODULE_DESCRIPTION("iptables mangle table");
  23
  24#define MANGLE_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
  25                            (1 << NF_INET_LOCAL_IN) | \
  26                            (1 << NF_INET_FORWARD) | \
  27                            (1 << NF_INET_LOCAL_OUT) | \
  28                            (1 << NF_INET_POST_ROUTING))
  29
  30/* Ouch - five different hooks? Maybe this should be a config option..... -- BC */
  31static const struct
  32{
  33        struct ipt_replace repl;
  34        struct ipt_standard entries[5];
  35        struct ipt_error term;
  36} initial_table __net_initdata = {
  37        .repl = {
  38                .name = "mangle",
  39                .valid_hooks = MANGLE_VALID_HOOKS,
  40                .num_entries = 6,
  41                .size = sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
  42                .hook_entry = {
  43                        [NF_INET_PRE_ROUTING]   = 0,
  44                        [NF_INET_LOCAL_IN]      = sizeof(struct ipt_standard),
  45                        [NF_INET_FORWARD]       = sizeof(struct ipt_standard) * 2,
  46                        [NF_INET_LOCAL_OUT]     = sizeof(struct ipt_standard) * 3,
  47                        [NF_INET_POST_ROUTING]  = sizeof(struct ipt_standard) * 4,
  48                },
  49                .underflow = {
  50                        [NF_INET_PRE_ROUTING]   = 0,
  51                        [NF_INET_LOCAL_IN]      = sizeof(struct ipt_standard),
  52                        [NF_INET_FORWARD]       = sizeof(struct ipt_standard) * 2,
  53                        [NF_INET_LOCAL_OUT]     = sizeof(struct ipt_standard) * 3,
  54                        [NF_INET_POST_ROUTING]  = sizeof(struct ipt_standard) * 4,
  55                },
  56        },
  57        .entries = {
  58                IPT_STANDARD_INIT(NF_ACCEPT),   /* PRE_ROUTING */
  59                IPT_STANDARD_INIT(NF_ACCEPT),   /* LOCAL_IN */
  60                IPT_STANDARD_INIT(NF_ACCEPT),   /* FORWARD */
  61                IPT_STANDARD_INIT(NF_ACCEPT),   /* LOCAL_OUT */
  62                IPT_STANDARD_INIT(NF_ACCEPT),   /* POST_ROUTING */
  63        },
  64        .term = IPT_ERROR_INIT,                 /* ERROR */
  65};
  66
  67static const struct xt_table packet_mangler = {
  68        .name           = "mangle",
  69        .valid_hooks    = MANGLE_VALID_HOOKS,
  70        .me             = THIS_MODULE,
  71        .af             = NFPROTO_IPV4,
  72};
  73
  74/* The work comes in here from netfilter.c. */
  75static unsigned int
  76ipt_pre_routing_hook(unsigned int hook,
  77                     struct sk_buff *skb,
  78                     const struct net_device *in,
  79                     const struct net_device *out,
  80                     int (*okfn)(struct sk_buff *))
  81{
  82        return ipt_do_table(skb, hook, in, out,
  83                            dev_net(in)->ipv4.iptable_mangle);
  84}
  85
  86static unsigned int
  87ipt_post_routing_hook(unsigned int hook,
  88                      struct sk_buff *skb,
  89                      const struct net_device *in,
  90                      const struct net_device *out,
  91                      int (*okfn)(struct sk_buff *))
  92{
  93        return ipt_do_table(skb, hook, in, out,
  94                            dev_net(out)->ipv4.iptable_mangle);
  95}
  96
  97static unsigned int
  98ipt_local_in_hook(unsigned int hook,
  99                  struct sk_buff *skb,
 100                  const struct net_device *in,
 101                  const struct net_device *out,
 102                  int (*okfn)(struct sk_buff *))
 103{
 104        return ipt_do_table(skb, hook, in, out,
 105                            dev_net(in)->ipv4.iptable_mangle);
 106}
 107
 108static unsigned int
 109ipt_forward_hook(unsigned int hook,
 110         struct sk_buff *skb,
 111         const struct net_device *in,
 112         const struct net_device *out,
 113         int (*okfn)(struct sk_buff *))
 114{
 115        return ipt_do_table(skb, hook, in, out,
 116                            dev_net(in)->ipv4.iptable_mangle);
 117}
 118
 119static unsigned int
 120ipt_local_hook(unsigned int hook,
 121                   struct sk_buff *skb,
 122                   const struct net_device *in,
 123                   const struct net_device *out,
 124                   int (*okfn)(struct sk_buff *))
 125{
 126        unsigned int ret;
 127        const struct iphdr *iph;
 128        u_int8_t tos;
 129        __be32 saddr, daddr;
 130        u_int32_t mark;
 131
 132        /* root is playing with raw sockets. */
 133        if (skb->len < sizeof(struct iphdr)
 134            || ip_hdrlen(skb) < sizeof(struct iphdr))
 135                return NF_ACCEPT;
 136
 137        /* Save things which could affect route */
 138        mark = skb->mark;
 139        iph = ip_hdr(skb);
 140        saddr = iph->saddr;
 141        daddr = iph->daddr;
 142        tos = iph->tos;
 143
 144        ret = ipt_do_table(skb, hook, in, out,
 145                           dev_net(out)->ipv4.iptable_mangle);
 146        /* Reroute for ANY change. */
 147        if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) {
 148                iph = ip_hdr(skb);
 149
 150                if (iph->saddr != saddr ||
 151                    iph->daddr != daddr ||
 152                    skb->mark != mark ||
 153                    iph->tos != tos)
 154                        if (ip_route_me_harder(skb, RTN_UNSPEC))
 155                                ret = NF_DROP;
 156        }
 157
 158        return ret;
 159}
 160
 161static struct nf_hook_ops ipt_ops[] __read_mostly = {
 162        {
 163                .hook           = ipt_pre_routing_hook,
 164                .owner          = THIS_MODULE,
 165                .pf             = NFPROTO_IPV4,
 166                .hooknum        = NF_INET_PRE_ROUTING,
 167                .priority       = NF_IP_PRI_MANGLE,
 168        },
 169        {
 170                .hook           = ipt_local_in_hook,
 171                .owner          = THIS_MODULE,
 172                .pf             = NFPROTO_IPV4,
 173                .hooknum        = NF_INET_LOCAL_IN,
 174                .priority       = NF_IP_PRI_MANGLE,
 175        },
 176        {
 177                .hook           = ipt_forward_hook,
 178                .owner          = THIS_MODULE,
 179                .pf             = NFPROTO_IPV4,
 180                .hooknum        = NF_INET_FORWARD,
 181                .priority       = NF_IP_PRI_MANGLE,
 182        },
 183        {
 184                .hook           = ipt_local_hook,
 185                .owner          = THIS_MODULE,
 186                .pf             = NFPROTO_IPV4,
 187                .hooknum        = NF_INET_LOCAL_OUT,
 188                .priority       = NF_IP_PRI_MANGLE,
 189        },
 190        {
 191                .hook           = ipt_post_routing_hook,
 192                .owner          = THIS_MODULE,
 193                .pf             = NFPROTO_IPV4,
 194                .hooknum        = NF_INET_POST_ROUTING,
 195                .priority       = NF_IP_PRI_MANGLE,
 196        },
 197};
 198
 199static int __net_init iptable_mangle_net_init(struct net *net)
 200{
 201        /* Register table */
 202        net->ipv4.iptable_mangle =
 203                ipt_register_table(net, &packet_mangler, &initial_table.repl);
 204        if (IS_ERR(net->ipv4.iptable_mangle))
 205                return PTR_ERR(net->ipv4.iptable_mangle);
 206        return 0;
 207}
 208
 209static void __net_exit iptable_mangle_net_exit(struct net *net)
 210{
 211        ipt_unregister_table(net->ipv4.iptable_mangle);
 212}
 213
 214static struct pernet_operations iptable_mangle_net_ops = {
 215        .init = iptable_mangle_net_init,
 216        .exit = iptable_mangle_net_exit,
 217};
 218
 219static int __init iptable_mangle_init(void)
 220{
 221        int ret;
 222
 223        ret = register_pernet_subsys(&iptable_mangle_net_ops);
 224        if (ret < 0)
 225                return ret;
 226
 227        /* Register hooks */
 228        ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
 229        if (ret < 0)
 230                goto cleanup_table;
 231
 232        return ret;
 233
 234 cleanup_table:
 235        unregister_pernet_subsys(&iptable_mangle_net_ops);
 236        return ret;
 237}
 238
 239static void __exit iptable_mangle_fini(void)
 240{
 241        nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
 242        unregister_pernet_subsys(&iptable_mangle_net_ops);
 243}
 244
 245module_init(iptable_mangle_init);
 246module_exit(iptable_mangle_fini);
 247