Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: ip6tables: add MASQUERADE target

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

authored by

Patrick McHardy and committed by
Pablo Neira Ayuso
b3f644fc 58a317f1

+155 -4
+1 -1
include/net/addrconf.h
··· 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);
+3 -1
include/net/netfilter/nf_nat.h
··· 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 };
+2 -1
net/ipv4/netfilter/ipt_MASQUERADE.c
··· 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
+1 -1
net/ipv6/addrconf.c
··· 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 {
+12
net/ipv6/netfilter/Kconfig
··· 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
+1
net/ipv6/netfilter/Makefile
··· 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
+135
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");