Commit b3f644fc8232ca761da0b5c5ccb6f30b423c4302

Authored by Patrick McHardy
Committed by Pablo Neira Ayuso
1 parent 58a317f106

netfilter: ip6tables: add MASQUERADE target

Signed-off-by: Patrick McHardy <kaber@trash.net>

Showing 7 changed files with 155 additions and 4 deletions Side-by-side Diff

include/net/addrconf.h
... ... @@ -78,7 +78,7 @@
78 78 int strict);
79 79  
80 80 extern int ipv6_dev_get_saddr(struct net *net,
81   - struct net_device *dev,
  81 + const struct net_device *dev,
82 82 const struct in6_addr *daddr,
83 83 unsigned int srcprefs,
84 84 struct in6_addr *saddr);
include/net/netfilter/nf_nat.h
... ... @@ -43,7 +43,9 @@
43 43 struct nf_conn *ct;
44 44 union nf_conntrack_nat_help help;
45 45 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
46   - defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
  46 + defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) || \
  47 + defined(CONFIG_IP6_NF_TARGET_MASQUERADE) || \
  48 + defined(CONFIG_IP6_NF_TARGET_MASQUERADE_MODULE)
47 49 int masq_index;
48 50 #endif
49 51 };
net/ipv4/netfilter/ipt_MASQUERADE.c
... ... @@ -99,7 +99,8 @@
99 99  
100 100 if (!nat)
101 101 return 0;
102   -
  102 + if (nf_ct_l3num(i) != NFPROTO_IPV4)
  103 + return 0;
103 104 return nat->masq_index == (int)(long)ifindex;
104 105 }
105 106  
... ... @@ -1093,7 +1093,7 @@
1093 1093 return ret;
1094 1094 }
1095 1095  
1096   -int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
  1096 +int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
1097 1097 const struct in6_addr *daddr, unsigned int prefs,
1098 1098 struct in6_addr *saddr)
1099 1099 {
net/ipv6/netfilter/Kconfig
... ... @@ -144,6 +144,18 @@
144 144 (e.g. when running oldconfig). It selects
145 145 CONFIG_NETFILTER_XT_TARGET_HL.
146 146  
  147 +config IP6_NF_TARGET_MASQUERADE
  148 + tristate "MASQUERADE target support"
  149 + depends on NF_NAT_IPV6
  150 + help
  151 + Masquerading is a special case of NAT: all outgoing connections are
  152 + changed to seem to come from a particular interface's address, and
  153 + if the interface goes down, those connections are lost. This is
  154 + only useful for dialup accounts with dynamic IP address (ie. your IP
  155 + address will be different on next dialup).
  156 +
  157 + To compile it as a module, choose M here. If unsure, say N.
  158 +
147 159 config IP6_NF_FILTER
148 160 tristate "Packet filtering"
149 161 default m if NETFILTER_ADVANCED=n
net/ipv6/netfilter/Makefile
... ... @@ -34,5 +34,6 @@
34 34 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
35 35  
36 36 # targets
  37 +obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
37 38 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
net/ipv6/netfilter/ip6t_MASQUERADE.c
  1 +/*
  2 + * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
  3 + *
  4 + * This program is free software; you can redistribute it and/or modify
  5 + * it under the terms of the GNU General Public License version 2 as
  6 + * published by the Free Software Foundation.
  7 + *
  8 + * Based on Rusty Russell's IPv6 MASQUERADE target. Development of IPv6
  9 + * NAT funded by Astaro.
  10 + */
  11 +
  12 +#include <linux/kernel.h>
  13 +#include <linux/module.h>
  14 +#include <linux/netdevice.h>
  15 +#include <linux/ipv6.h>
  16 +#include <linux/netfilter.h>
  17 +#include <linux/netfilter_ipv6.h>
  18 +#include <linux/netfilter/x_tables.h>
  19 +#include <net/netfilter/nf_nat.h>
  20 +#include <net/addrconf.h>
  21 +#include <net/ipv6.h>
  22 +
  23 +static unsigned int
  24 +masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par)
  25 +{
  26 + const struct nf_nat_range *range = par->targinfo;
  27 + enum ip_conntrack_info ctinfo;
  28 + struct in6_addr src;
  29 + struct nf_conn *ct;
  30 + struct nf_nat_range newrange;
  31 +
  32 + ct = nf_ct_get(skb, &ctinfo);
  33 + NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
  34 + ctinfo == IP_CT_RELATED_REPLY));
  35 +
  36 + if (ipv6_dev_get_saddr(dev_net(par->out), par->out,
  37 + &ipv6_hdr(skb)->daddr, 0, &src) < 0)
  38 + return NF_DROP;
  39 +
  40 + nfct_nat(ct)->masq_index = par->out->ifindex;
  41 +
  42 + newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
  43 + newrange.min_addr.in6 = src;
  44 + newrange.max_addr.in6 = src;
  45 + newrange.min_proto = range->min_proto;
  46 + newrange.max_proto = range->max_proto;
  47 +
  48 + return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
  49 +}
  50 +
  51 +static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par)
  52 +{
  53 + const struct nf_nat_range *range = par->targinfo;
  54 +
  55 + if (range->flags & NF_NAT_RANGE_MAP_IPS)
  56 + return -EINVAL;
  57 + return 0;
  58 +}
  59 +
  60 +static int device_cmp(struct nf_conn *ct, void *ifindex)
  61 +{
  62 + const struct nf_conn_nat *nat = nfct_nat(ct);
  63 +
  64 + if (!nat)
  65 + return 0;
  66 + if (nf_ct_l3num(ct) != NFPROTO_IPV6)
  67 + return 0;
  68 + return nat->masq_index == (int)(long)ifindex;
  69 +}
  70 +
  71 +static int masq_device_event(struct notifier_block *this,
  72 + unsigned long event, void *ptr)
  73 +{
  74 + const struct net_device *dev = ptr;
  75 + struct net *net = dev_net(dev);
  76 +
  77 + if (event == NETDEV_DOWN)
  78 + nf_ct_iterate_cleanup(net, device_cmp,
  79 + (void *)(long)dev->ifindex);
  80 +
  81 + return NOTIFY_DONE;
  82 +}
  83 +
  84 +static struct notifier_block masq_dev_notifier = {
  85 + .notifier_call = masq_device_event,
  86 +};
  87 +
  88 +static int masq_inet_event(struct notifier_block *this,
  89 + unsigned long event, void *ptr)
  90 +{
  91 + struct inet6_ifaddr *ifa = ptr;
  92 +
  93 + return masq_device_event(this, event, ifa->idev->dev);
  94 +}
  95 +
  96 +static struct notifier_block masq_inet_notifier = {
  97 + .notifier_call = masq_inet_event,
  98 +};
  99 +
  100 +static struct xt_target masquerade_tg6_reg __read_mostly = {
  101 + .name = "MASQUERADE",
  102 + .family = NFPROTO_IPV6,
  103 + .checkentry = masquerade_tg6_checkentry,
  104 + .target = masquerade_tg6,
  105 + .targetsize = sizeof(struct nf_nat_range),
  106 + .table = "nat",
  107 + .hooks = 1 << NF_INET_POST_ROUTING,
  108 + .me = THIS_MODULE,
  109 +};
  110 +
  111 +static int __init masquerade_tg6_init(void)
  112 +{
  113 + int err;
  114 +
  115 + err = xt_register_target(&masquerade_tg6_reg);
  116 + if (err == 0) {
  117 + register_netdevice_notifier(&masq_dev_notifier);
  118 + register_inet6addr_notifier(&masq_inet_notifier);
  119 + }
  120 +
  121 + return err;
  122 +}
  123 +static void __exit masquerade_tg6_exit(void)
  124 +{
  125 + unregister_inet6addr_notifier(&masq_inet_notifier);
  126 + unregister_netdevice_notifier(&masq_dev_notifier);
  127 + xt_unregister_target(&masquerade_tg6_reg);
  128 +}
  129 +
  130 +module_init(masquerade_tg6_init);
  131 +module_exit(masquerade_tg6_exit);
  132 +
  133 +MODULE_LICENSE("GPL");
  134 +MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
  135 +MODULE_DESCRIPTION("Xtables: automatic address SNAT");