diff options
| author | Patrick McHardy <kaber@trash.net> | 2012-08-26 13:14:14 -0400 |
|---|---|---|
| committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-08-29 21:00:18 -0400 |
| commit | b3f644fc8232ca761da0b5c5ccb6f30b423c4302 (patch) | |
| tree | 6141514d1bb2046c90f66e93234c3494e658e04c | |
| parent | 58a317f1061c894d2344c0b6a18ab4a64b69b815 (diff) | |
netfilter: ip6tables: add MASQUERADE target
Signed-off-by: Patrick McHardy <kaber@trash.net>
| -rw-r--r-- | include/net/addrconf.h | 2 | ||||
| -rw-r--r-- | include/net/netfilter/nf_nat.h | 4 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ipt_MASQUERADE.c | 3 | ||||
| -rw-r--r-- | net/ipv6/addrconf.c | 2 | ||||
| -rw-r--r-- | net/ipv6/netfilter/Kconfig | 12 | ||||
| -rw-r--r-- | net/ipv6/netfilter/Makefile | 1 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6t_MASQUERADE.c | 135 |
7 files changed, 155 insertions, 4 deletions
diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 089a09d001d1..9e63e76b20e7 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h | |||
| @@ -78,7 +78,7 @@ extern struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, | |||
| 78 | int strict); | 78 | int strict); |
| 79 | 79 | ||
| 80 | extern int ipv6_dev_get_saddr(struct net *net, | 80 | extern int ipv6_dev_get_saddr(struct net *net, |
| 81 | struct net_device *dev, | 81 | const struct net_device *dev, |
| 82 | const struct in6_addr *daddr, | 82 | const struct in6_addr *daddr, |
| 83 | unsigned int srcprefs, | 83 | unsigned int srcprefs, |
| 84 | struct in6_addr *saddr); | 84 | struct in6_addr *saddr); |
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h index 1752f1339054..bd8eea720f2e 100644 --- a/include/net/netfilter/nf_nat.h +++ b/include/net/netfilter/nf_nat.h | |||
| @@ -43,7 +43,9 @@ struct nf_conn_nat { | |||
| 43 | struct nf_conn *ct; | 43 | struct nf_conn *ct; |
| 44 | union nf_conntrack_nat_help help; | 44 | union nf_conntrack_nat_help help; |
| 45 | #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ | 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 | int masq_index; | 49 | int masq_index; |
| 48 | #endif | 50 | #endif |
| 49 | }; | 51 | }; |
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 1c3aa28b51ae..5d5d4d1be9c2 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c | |||
| @@ -99,7 +99,8 @@ device_cmp(struct nf_conn *i, void *ifindex) | |||
| 99 | 99 | ||
| 100 | if (!nat) | 100 | if (!nat) |
| 101 | return 0; | 101 | return 0; |
| 102 | 102 | if (nf_ct_l3num(i) != NFPROTO_IPV4) | |
| 103 | return 0; | ||
| 103 | return nat->masq_index == (int)(long)ifindex; | 104 | return nat->masq_index == (int)(long)ifindex; |
| 104 | } | 105 | } |
| 105 | 106 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e581009cb09e..19d4bffda9d7 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -1093,7 +1093,7 @@ out: | |||
| 1093 | return ret; | 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 | const struct in6_addr *daddr, unsigned int prefs, | 1097 | const struct in6_addr *daddr, unsigned int prefs, |
| 1098 | struct in6_addr *saddr) | 1098 | struct in6_addr *saddr) |
| 1099 | { | 1099 | { |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index b27e0ad4b738..54a5032ea3df 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
| @@ -144,6 +144,18 @@ config IP6_NF_TARGET_HL | |||
| 144 | (e.g. when running oldconfig). It selects | 144 | (e.g. when running oldconfig). It selects |
| 145 | CONFIG_NETFILTER_XT_TARGET_HL. | 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 | config IP6_NF_FILTER | 159 | config IP6_NF_FILTER |
| 148 | tristate "Packet filtering" | 160 | tristate "Packet filtering" |
| 149 | default m if NETFILTER_ADVANCED=n | 161 | default m if NETFILTER_ADVANCED=n |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 76779376da4c..068bad199587 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
| @@ -34,4 +34,5 @@ obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o | |||
| 34 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o | 34 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o |
| 35 | 35 | ||
| 36 | # targets | 36 | # targets |
| 37 | obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o | ||
| 37 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o | 38 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o |
diff --git a/net/ipv6/netfilter/ip6t_MASQUERADE.c b/net/ipv6/netfilter/ip6t_MASQUERADE.c new file mode 100644 index 000000000000..60e9053bab05 --- /dev/null +++ b/net/ipv6/netfilter/ip6t_MASQUERADE.c | |||
| @@ -0,0 +1,135 @@ | |||
| 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); | ||
