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

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

====================
nf-next pull request

The following patchset contains Netfilter/IPVS updates for your
net-next tree. Regarding nf_tables, most updates focus on consolidating
the NAT infrastructure and adding support for masquerading. More
specifically, they are:

1) use __u8 instead of u_int8_t in arptables header, from
Mike Frysinger.

2) Add support to match by skb->pkttype to the meta expression, from
Ana Rey.

3) Add support to match by cpu to the meta expression, also from
Ana Rey.

4) A smatch warning about IPSET_ATTR_MARKMASK validation, patch from
Vytas Dauksa.

5) Fix netnet and netportnet hash types the range support for IPv4,
from Sergey Popovich.

6) Fix missing-field-initializer warnings resolved, from Mark Rustad.

7) Dan Carperter reported possible integer overflows in ipset, from
Jozsef Kadlecsick.

8) Filter out accounting objects in nfacct by type, so you can
selectively reset quotas, from Alexey Perevalov.

9) Move specific NAT IPv4 functions to the core so x_tables and
nf_tables can share the same NAT IPv4 engine.

10) Use the new NAT IPv4 functions from nft_chain_nat_ipv4.

11) Move specific NAT IPv6 functions to the core so x_tables and
nf_tables can share the same NAT IPv4 engine.

12) Use the new NAT IPv6 functions from nft_chain_nat_ipv6.

13) Refactor code to add nft_delrule(), which can be reused in the
enhancement of the NFT_MSG_DELTABLE to remove a table and its
content, from Arturo Borrero.

14) Add a helper function to unregister chain hooks, from
Arturo Borrero.

15) A cleanup to rename to nft_delrule_by_chain for consistency with
the new nft_*() functions, also from Arturo.

16) Add support to match devgroup to the meta expression, from Ana Rey.

17) Reduce stack usage for IPVS socket option, from Julian Anastasov.

18) Remove unnecessary textsearch state initialization in xt_string,
from Bojan Prtvar.

19) Add several helper functions to nf_tables, more work to prepare
the enhancement of NFT_MSG_DELTABLE, again from Arturo Borrero.

20) Enhance NFT_MSG_DELTABLE to delete a table and its content, from
Arturo Borrero.

21) Support NAT flags in the nat expression to indicate the flavour,
eg. random fully, from Arturo.

22) Add missing audit code to ebtables when replacing tables, from
Nicolas Dichtel.

23) Generalize the IPv4 masquerading code to allow its re-use from
nf_tables, from Arturo.

24) Generalize the IPv6 masquerading code, also from Arturo.

25) Add the new masq expression to support IPv4/IPv6 masquerading
from nf_tables, also from Arturo.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1761 -1072
+1
include/linux/netfilter/ipset/ip_set_list.h
··· 6 6 7 7 #define IP_SET_LIST_DEFAULT_SIZE 8 8 8 #define IP_SET_LIST_MIN_SIZE 4 9 + #define IP_SET_LIST_MAX_SIZE 65536 9 10 10 11 #endif /* __IP_SET_LIST_H */
+14
include/net/netfilter/ipv4/nf_nat_masquerade.h
··· 1 + #ifndef _NF_NAT_MASQUERADE_IPV4_H_ 2 + #define _NF_NAT_MASQUERADE_IPV4_H_ 3 + 4 + #include <net/netfilter/nf_nat.h> 5 + 6 + unsigned int 7 + nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum, 8 + const struct nf_nat_range *range, 9 + const struct net_device *out); 10 + 11 + void nf_nat_masquerade_ipv4_register_notifier(void); 12 + void nf_nat_masquerade_ipv4_unregister_notifier(void); 13 + 14 + #endif /*_NF_NAT_MASQUERADE_IPV4_H_ */
+10
include/net/netfilter/ipv6/nf_nat_masquerade.h
··· 1 + #ifndef _NF_NAT_MASQUERADE_IPV6_H_ 2 + #define _NF_NAT_MASQUERADE_IPV6_H_ 3 + 4 + unsigned int 5 + nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range *range, 6 + const struct net_device *out); 7 + void nf_nat_masquerade_ipv6_register_notifier(void); 8 + void nf_nat_masquerade_ipv6_unregister_notifier(void); 9 + 10 + #endif /* _NF_NAT_MASQUERADE_IPV6_H_ */
+75
include/net/netfilter/nf_nat_l3proto.h
··· 42 42 int nf_nat_icmp_reply_translation(struct sk_buff *skb, struct nf_conn *ct, 43 43 enum ip_conntrack_info ctinfo, 44 44 unsigned int hooknum); 45 + 46 + unsigned int nf_nat_ipv4_in(const struct nf_hook_ops *ops, struct sk_buff *skb, 47 + const struct net_device *in, 48 + const struct net_device *out, 49 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 50 + struct sk_buff *skb, 51 + const struct net_device *in, 52 + const struct net_device *out, 53 + struct nf_conn *ct)); 54 + 55 + unsigned int nf_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb, 56 + const struct net_device *in, 57 + const struct net_device *out, 58 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 59 + struct sk_buff *skb, 60 + const struct net_device *in, 61 + const struct net_device *out, 62 + struct nf_conn *ct)); 63 + 64 + unsigned int nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, 65 + struct sk_buff *skb, 66 + const struct net_device *in, 67 + const struct net_device *out, 68 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 69 + struct sk_buff *skb, 70 + const struct net_device *in, 71 + const struct net_device *out, 72 + struct nf_conn *ct)); 73 + 74 + unsigned int nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, 75 + const struct net_device *in, 76 + const struct net_device *out, 77 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 78 + struct sk_buff *skb, 79 + const struct net_device *in, 80 + const struct net_device *out, 81 + struct nf_conn *ct)); 82 + 45 83 int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, struct nf_conn *ct, 46 84 enum ip_conntrack_info ctinfo, 47 85 unsigned int hooknum, unsigned int hdrlen); 86 + 87 + unsigned int nf_nat_ipv6_in(const struct nf_hook_ops *ops, struct sk_buff *skb, 88 + const struct net_device *in, 89 + const struct net_device *out, 90 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 91 + struct sk_buff *skb, 92 + const struct net_device *in, 93 + const struct net_device *out, 94 + struct nf_conn *ct)); 95 + 96 + unsigned int nf_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb, 97 + const struct net_device *in, 98 + const struct net_device *out, 99 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 100 + struct sk_buff *skb, 101 + const struct net_device *in, 102 + const struct net_device *out, 103 + struct nf_conn *ct)); 104 + 105 + unsigned int nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, 106 + struct sk_buff *skb, 107 + const struct net_device *in, 108 + const struct net_device *out, 109 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 110 + struct sk_buff *skb, 111 + const struct net_device *in, 112 + const struct net_device *out, 113 + struct nf_conn *ct)); 114 + 115 + unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, 116 + const struct net_device *in, 117 + const struct net_device *out, 118 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 119 + struct sk_buff *skb, 120 + const struct net_device *in, 121 + const struct net_device *out, 122 + struct nf_conn *ct)); 48 123 49 124 #endif /* _NF_NAT_L3PROTO_H */
+16
include/net/netfilter/nft_masq.h
··· 1 + #ifndef _NFT_MASQ_H_ 2 + #define _NFT_MASQ_H_ 3 + 4 + struct nft_masq { 5 + u32 flags; 6 + }; 7 + 8 + extern const struct nla_policy nft_masq_policy[]; 9 + 10 + int nft_masq_init(const struct nft_ctx *ctx, 11 + const struct nft_expr *expr, 12 + const struct nlattr * const tb[]); 13 + 14 + int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr); 15 + 16 + #endif /* _NFT_MASQ_H_ */
+5
include/uapi/linux/netfilter/nf_nat.h
··· 13 13 #define NF_NAT_RANGE_PROTO_RANDOM_ALL \ 14 14 (NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY) 15 15 16 + #define NF_NAT_RANGE_MASK \ 17 + (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \ 18 + NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \ 19 + NF_NAT_RANGE_PROTO_RANDOM_FULLY) 20 + 16 21 struct nf_nat_ipv4_range { 17 22 unsigned int flags; 18 23 __be32 min_ip;
+21
include/uapi/linux/netfilter/nf_tables.h
··· 571 571 * @NFT_META_L4PROTO: layer 4 protocol number 572 572 * @NFT_META_BRI_IIFNAME: packet input bridge interface name 573 573 * @NFT_META_BRI_OIFNAME: packet output bridge interface name 574 + * @NFT_META_PKTTYPE: packet type (skb->pkt_type), special handling for loopback 575 + * @NFT_META_CPU: cpu id through smp_processor_id() 576 + * @NFT_META_IIFGROUP: packet input interface group 577 + * @NFT_META_OIFGROUP: packet output interface group 574 578 */ 575 579 enum nft_meta_keys { 576 580 NFT_META_LEN, ··· 596 592 NFT_META_L4PROTO, 597 593 NFT_META_BRI_IIFNAME, 598 594 NFT_META_BRI_OIFNAME, 595 + NFT_META_PKTTYPE, 596 + NFT_META_CPU, 597 + NFT_META_IIFGROUP, 598 + NFT_META_OIFGROUP, 599 599 }; 600 600 601 601 /** ··· 785 777 * @NFTA_NAT_REG_ADDR_MAX: source register of address range end (NLA_U32: nft_registers) 786 778 * @NFTA_NAT_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) 787 779 * @NFTA_NAT_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) 780 + * @NFTA_NAT_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) 788 781 */ 789 782 enum nft_nat_attributes { 790 783 NFTA_NAT_UNSPEC, ··· 795 786 NFTA_NAT_REG_ADDR_MAX, 796 787 NFTA_NAT_REG_PROTO_MIN, 797 788 NFTA_NAT_REG_PROTO_MAX, 789 + NFTA_NAT_FLAGS, 798 790 __NFTA_NAT_MAX 799 791 }; 800 792 #define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1) 793 + 794 + /** 795 + * enum nft_masq_attributes - nf_tables masquerade expression attributes 796 + * 797 + * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) 798 + */ 799 + enum nft_masq_attributes { 800 + NFTA_MASQ_FLAGS, 801 + __NFTA_MASQ_MAX 802 + }; 803 + #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) 801 804 802 805 #endif /* _LINUX_NF_TABLES_H */
+1 -1
include/uapi/linux/netfilter_arp/arpt_mangle.h
··· 13 13 union { 14 14 struct in_addr tgt_ip; 15 15 } u_t; 16 - u_int8_t flags; 16 + __u8 flags; 17 17 int target; 18 18 }; 19 19
+15
net/bridge/netfilter/ebtables.c
··· 26 26 #include <asm/uaccess.h> 27 27 #include <linux/smp.h> 28 28 #include <linux/cpumask.h> 29 + #include <linux/audit.h> 29 30 #include <net/sock.h> 30 31 /* needed for logical [in,out]-dev filtering */ 31 32 #include "../br_private.h" ··· 1059 1058 vfree(table); 1060 1059 1061 1060 vfree(counterstmp); 1061 + 1062 + #ifdef CONFIG_AUDIT 1063 + if (audit_enabled) { 1064 + struct audit_buffer *ab; 1065 + 1066 + ab = audit_log_start(current->audit_context, GFP_KERNEL, 1067 + AUDIT_NETFILTER_CFG); 1068 + if (ab) { 1069 + audit_log_format(ab, "table=%s family=%u entries=%u", 1070 + repl->name, AF_BRIDGE, repl->nentries); 1071 + audit_log_end(ab); 1072 + } 1073 + } 1074 + #endif 1062 1075 return ret; 1063 1076 1064 1077 free_unlock:
+13
net/ipv4/netfilter/Kconfig
··· 232 232 233 233 if IP_NF_NAT 234 234 235 + config NF_NAT_MASQUERADE_IPV4 236 + tristate "IPv4 masquerade support" 237 + help 238 + This is the kernel functionality to provide NAT in the masquerade 239 + flavour (automatic source address selection). 240 + 241 + config NFT_MASQ_IPV4 242 + tristate "IPv4 masquerading support for nf_tables" 243 + depends on NF_TABLES_IPV4 244 + depends on NFT_MASQ 245 + select NF_NAT_MASQUERADE_IPV4 246 + 235 247 config IP_NF_TARGET_MASQUERADE 236 248 tristate "MASQUERADE target support" 249 + select NF_NAT_MASQUERADE_IPV4 237 250 default m if NETFILTER_ADVANCED=n 238 251 help 239 252 Masquerading is a special case of NAT: all outgoing connections are
+2
net/ipv4/netfilter/Makefile
··· 27 27 obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o 28 28 obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o 29 29 obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o 30 + obj-$(CONFIG_NF_NAT_MASQUERADE_IPV4) += nf_nat_masquerade_ipv4.o 30 31 31 32 # NAT protocols (nf_nat) 32 33 obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o ··· 36 35 obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o 37 36 obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o 38 37 obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o 38 + obj-$(CONFIG_NFT_MASQ_IPV4) += nft_masq_ipv4.o 39 39 obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o 40 40 41 41 # generic IP tables
+9 -99
net/ipv4/netfilter/ipt_MASQUERADE.c
··· 22 22 #include <linux/netfilter_ipv4.h> 23 23 #include <linux/netfilter/x_tables.h> 24 24 #include <net/netfilter/nf_nat.h> 25 + #include <net/netfilter/ipv4/nf_nat_masquerade.h> 25 26 26 27 MODULE_LICENSE("GPL"); 27 28 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); ··· 47 46 static unsigned int 48 47 masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par) 49 48 { 50 - struct nf_conn *ct; 51 - struct nf_conn_nat *nat; 52 - enum ip_conntrack_info ctinfo; 53 - struct nf_nat_range newrange; 49 + struct nf_nat_range range; 54 50 const struct nf_nat_ipv4_multi_range_compat *mr; 55 - const struct rtable *rt; 56 - __be32 newsrc, nh; 57 - 58 - NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING); 59 - 60 - ct = nf_ct_get(skb, &ctinfo); 61 - nat = nfct_nat(ct); 62 - 63 - NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || 64 - ctinfo == IP_CT_RELATED_REPLY)); 65 - 66 - /* Source address is 0.0.0.0 - locally generated packet that is 67 - * probably not supposed to be masqueraded. 68 - */ 69 - if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0) 70 - return NF_ACCEPT; 71 51 72 52 mr = par->targinfo; 73 - rt = skb_rtable(skb); 74 - nh = rt_nexthop(rt, ip_hdr(skb)->daddr); 75 - newsrc = inet_select_addr(par->out, nh, RT_SCOPE_UNIVERSE); 76 - if (!newsrc) { 77 - pr_info("%s ate my IP address\n", par->out->name); 78 - return NF_DROP; 79 - } 53 + range.flags = mr->range[0].flags; 54 + range.min_proto = mr->range[0].min; 55 + range.max_proto = mr->range[0].max; 80 56 81 - nat->masq_index = par->out->ifindex; 82 - 83 - /* Transfer from original range. */ 84 - memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); 85 - memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); 86 - newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS; 87 - newrange.min_addr.ip = newsrc; 88 - newrange.max_addr.ip = newsrc; 89 - newrange.min_proto = mr->range[0].min; 90 - newrange.max_proto = mr->range[0].max; 91 - 92 - /* Hand modified range to generic setup. */ 93 - return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); 57 + return nf_nat_masquerade_ipv4(skb, par->hooknum, &range, par->out); 94 58 } 95 - 96 - static int 97 - device_cmp(struct nf_conn *i, void *ifindex) 98 - { 99 - const struct nf_conn_nat *nat = nfct_nat(i); 100 - 101 - if (!nat) 102 - return 0; 103 - if (nf_ct_l3num(i) != NFPROTO_IPV4) 104 - return 0; 105 - return nat->masq_index == (int)(long)ifindex; 106 - } 107 - 108 - static int masq_device_event(struct notifier_block *this, 109 - unsigned long event, 110 - void *ptr) 111 - { 112 - const struct net_device *dev = netdev_notifier_info_to_dev(ptr); 113 - struct net *net = dev_net(dev); 114 - 115 - if (event == NETDEV_DOWN) { 116 - /* Device was downed. Search entire table for 117 - conntracks which were associated with that device, 118 - and forget them. */ 119 - NF_CT_ASSERT(dev->ifindex != 0); 120 - 121 - nf_ct_iterate_cleanup(net, device_cmp, 122 - (void *)(long)dev->ifindex, 0, 0); 123 - } 124 - 125 - return NOTIFY_DONE; 126 - } 127 - 128 - static int masq_inet_event(struct notifier_block *this, 129 - unsigned long event, 130 - void *ptr) 131 - { 132 - struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; 133 - struct netdev_notifier_info info; 134 - 135 - netdev_notifier_info_init(&info, dev); 136 - return masq_device_event(this, event, &info); 137 - } 138 - 139 - static struct notifier_block masq_dev_notifier = { 140 - .notifier_call = masq_device_event, 141 - }; 142 - 143 - static struct notifier_block masq_inet_notifier = { 144 - .notifier_call = masq_inet_event, 145 - }; 146 59 147 60 static struct xt_target masquerade_tg_reg __read_mostly = { 148 61 .name = "MASQUERADE", ··· 75 160 76 161 ret = xt_register_target(&masquerade_tg_reg); 77 162 78 - if (ret == 0) { 79 - /* Register for device down reports */ 80 - register_netdevice_notifier(&masq_dev_notifier); 81 - /* Register IP address change reports */ 82 - register_inetaddr_notifier(&masq_inet_notifier); 83 - } 163 + if (ret == 0) 164 + nf_nat_masquerade_ipv4_register_notifier(); 84 165 85 166 return ret; 86 167 } ··· 84 173 static void __exit masquerade_tg_exit(void) 85 174 { 86 175 xt_unregister_target(&masquerade_tg_reg); 87 - unregister_netdevice_notifier(&masq_dev_notifier); 88 - unregister_inetaddr_notifier(&masq_inet_notifier); 176 + nf_nat_masquerade_ipv4_unregister_notifier(); 89 177 } 90 178 91 179 module_init(masquerade_tg_init);
+34 -199
net/ipv4/netfilter/iptable_nat.c
··· 28 28 .af = NFPROTO_IPV4, 29 29 }; 30 30 31 - static unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) 32 - { 33 - /* Force range to this IP; let proto decide mapping for 34 - * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). 35 - */ 36 - struct nf_nat_range range; 37 - 38 - range.flags = 0; 39 - pr_debug("Allocating NULL binding for %p (%pI4)\n", ct, 40 - HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ? 41 - &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip : 42 - &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); 43 - 44 - return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum)); 45 - } 46 - 47 - static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum, 48 - const struct net_device *in, 49 - const struct net_device *out, 50 - struct nf_conn *ct) 31 + static unsigned int iptable_nat_do_chain(const struct nf_hook_ops *ops, 32 + struct sk_buff *skb, 33 + const struct net_device *in, 34 + const struct net_device *out, 35 + struct nf_conn *ct) 51 36 { 52 37 struct net *net = nf_ct_net(ct); 53 - unsigned int ret; 54 38 55 - ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table); 56 - if (ret == NF_ACCEPT) { 57 - if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) 58 - ret = alloc_null_binding(ct, hooknum); 59 - } 60 - return ret; 39 + return ipt_do_table(skb, ops->hooknum, in, out, net->ipv4.nat_table); 61 40 } 62 41 63 - static unsigned int 64 - nf_nat_ipv4_fn(const struct nf_hook_ops *ops, 65 - struct sk_buff *skb, 66 - const struct net_device *in, 67 - const struct net_device *out, 68 - int (*okfn)(struct sk_buff *)) 42 + static unsigned int iptable_nat_ipv4_fn(const struct nf_hook_ops *ops, 43 + struct sk_buff *skb, 44 + const struct net_device *in, 45 + const struct net_device *out, 46 + int (*okfn)(struct sk_buff *)) 69 47 { 70 - struct nf_conn *ct; 71 - enum ip_conntrack_info ctinfo; 72 - struct nf_conn_nat *nat; 73 - /* maniptype == SRC for postrouting. */ 74 - enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); 75 - 76 - /* We never see fragments: conntrack defrags on pre-routing 77 - * and local-out, and nf_nat_out protects post-routing. 78 - */ 79 - NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb))); 80 - 81 - ct = nf_ct_get(skb, &ctinfo); 82 - /* Can't track? It's not due to stress, or conntrack would 83 - * have dropped it. Hence it's the user's responsibilty to 84 - * packet filter it out, or implement conntrack/NAT for that 85 - * protocol. 8) --RR 86 - */ 87 - if (!ct) 88 - return NF_ACCEPT; 89 - 90 - /* Don't try to NAT if this packet is not conntracked */ 91 - if (nf_ct_is_untracked(ct)) 92 - return NF_ACCEPT; 93 - 94 - nat = nf_ct_nat_ext_add(ct); 95 - if (nat == NULL) 96 - return NF_ACCEPT; 97 - 98 - switch (ctinfo) { 99 - case IP_CT_RELATED: 100 - case IP_CT_RELATED_REPLY: 101 - if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { 102 - if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, 103 - ops->hooknum)) 104 - return NF_DROP; 105 - else 106 - return NF_ACCEPT; 107 - } 108 - /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ 109 - case IP_CT_NEW: 110 - /* Seen it before? This can happen for loopback, retrans, 111 - * or local packets. 112 - */ 113 - if (!nf_nat_initialized(ct, maniptype)) { 114 - unsigned int ret; 115 - 116 - ret = nf_nat_rule_find(skb, ops->hooknum, in, out, ct); 117 - if (ret != NF_ACCEPT) 118 - return ret; 119 - } else { 120 - pr_debug("Already setup manip %s for ct %p\n", 121 - maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 122 - ct); 123 - if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) 124 - goto oif_changed; 125 - } 126 - break; 127 - 128 - default: 129 - /* ESTABLISHED */ 130 - NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || 131 - ctinfo == IP_CT_ESTABLISHED_REPLY); 132 - if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) 133 - goto oif_changed; 134 - } 135 - 136 - return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); 137 - 138 - oif_changed: 139 - nf_ct_kill_acct(ct, ctinfo, skb); 140 - return NF_DROP; 48 + return nf_nat_ipv4_fn(ops, skb, in, out, iptable_nat_do_chain); 141 49 } 142 50 143 - static unsigned int 144 - nf_nat_ipv4_in(const struct nf_hook_ops *ops, 145 - struct sk_buff *skb, 146 - const struct net_device *in, 147 - const struct net_device *out, 148 - int (*okfn)(struct sk_buff *)) 51 + static unsigned int iptable_nat_ipv4_in(const struct nf_hook_ops *ops, 52 + struct sk_buff *skb, 53 + const struct net_device *in, 54 + const struct net_device *out, 55 + int (*okfn)(struct sk_buff *)) 149 56 { 150 - unsigned int ret; 151 - __be32 daddr = ip_hdr(skb)->daddr; 152 - 153 - ret = nf_nat_ipv4_fn(ops, skb, in, out, okfn); 154 - if (ret != NF_DROP && ret != NF_STOLEN && 155 - daddr != ip_hdr(skb)->daddr) 156 - skb_dst_drop(skb); 157 - 158 - return ret; 57 + return nf_nat_ipv4_in(ops, skb, in, out, iptable_nat_do_chain); 159 58 } 160 59 161 - static unsigned int 162 - nf_nat_ipv4_out(const struct nf_hook_ops *ops, 163 - struct sk_buff *skb, 164 - const struct net_device *in, 165 - const struct net_device *out, 166 - int (*okfn)(struct sk_buff *)) 60 + static unsigned int iptable_nat_ipv4_out(const struct nf_hook_ops *ops, 61 + struct sk_buff *skb, 62 + const struct net_device *in, 63 + const struct net_device *out, 64 + int (*okfn)(struct sk_buff *)) 167 65 { 168 - #ifdef CONFIG_XFRM 169 - const struct nf_conn *ct; 170 - enum ip_conntrack_info ctinfo; 171 - int err; 172 - #endif 173 - unsigned int ret; 174 - 175 - /* root is playing with raw sockets. */ 176 - if (skb->len < sizeof(struct iphdr) || 177 - ip_hdrlen(skb) < sizeof(struct iphdr)) 178 - return NF_ACCEPT; 179 - 180 - ret = nf_nat_ipv4_fn(ops, skb, in, out, okfn); 181 - #ifdef CONFIG_XFRM 182 - if (ret != NF_DROP && ret != NF_STOLEN && 183 - !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && 184 - (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 185 - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 186 - 187 - if ((ct->tuplehash[dir].tuple.src.u3.ip != 188 - ct->tuplehash[!dir].tuple.dst.u3.ip) || 189 - (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP && 190 - ct->tuplehash[dir].tuple.src.u.all != 191 - ct->tuplehash[!dir].tuple.dst.u.all)) { 192 - err = nf_xfrm_me_harder(skb, AF_INET); 193 - if (err < 0) 194 - ret = NF_DROP_ERR(err); 195 - } 196 - } 197 - #endif 198 - return ret; 66 + return nf_nat_ipv4_out(ops, skb, in, out, iptable_nat_do_chain); 199 67 } 200 68 201 - static unsigned int 202 - nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, 203 - struct sk_buff *skb, 204 - const struct net_device *in, 205 - const struct net_device *out, 206 - int (*okfn)(struct sk_buff *)) 69 + static unsigned int iptable_nat_ipv4_local_fn(const struct nf_hook_ops *ops, 70 + struct sk_buff *skb, 71 + const struct net_device *in, 72 + const struct net_device *out, 73 + int (*okfn)(struct sk_buff *)) 207 74 { 208 - const struct nf_conn *ct; 209 - enum ip_conntrack_info ctinfo; 210 - unsigned int ret; 211 - int err; 212 - 213 - /* root is playing with raw sockets. */ 214 - if (skb->len < sizeof(struct iphdr) || 215 - ip_hdrlen(skb) < sizeof(struct iphdr)) 216 - return NF_ACCEPT; 217 - 218 - ret = nf_nat_ipv4_fn(ops, skb, in, out, okfn); 219 - if (ret != NF_DROP && ret != NF_STOLEN && 220 - (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 221 - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 222 - 223 - if (ct->tuplehash[dir].tuple.dst.u3.ip != 224 - ct->tuplehash[!dir].tuple.src.u3.ip) { 225 - err = ip_route_me_harder(skb, RTN_UNSPEC); 226 - if (err < 0) 227 - ret = NF_DROP_ERR(err); 228 - } 229 - #ifdef CONFIG_XFRM 230 - else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && 231 - ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP && 232 - ct->tuplehash[dir].tuple.dst.u.all != 233 - ct->tuplehash[!dir].tuple.src.u.all) { 234 - err = nf_xfrm_me_harder(skb, AF_INET); 235 - if (err < 0) 236 - ret = NF_DROP_ERR(err); 237 - } 238 - #endif 239 - } 240 - return ret; 75 + return nf_nat_ipv4_local_fn(ops, skb, in, out, iptable_nat_do_chain); 241 76 } 242 77 243 78 static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = { 244 79 /* Before packet filtering, change destination */ 245 80 { 246 - .hook = nf_nat_ipv4_in, 81 + .hook = iptable_nat_ipv4_in, 247 82 .owner = THIS_MODULE, 248 83 .pf = NFPROTO_IPV4, 249 84 .hooknum = NF_INET_PRE_ROUTING, ··· 86 251 }, 87 252 /* After packet filtering, change source */ 88 253 { 89 - .hook = nf_nat_ipv4_out, 254 + .hook = iptable_nat_ipv4_out, 90 255 .owner = THIS_MODULE, 91 256 .pf = NFPROTO_IPV4, 92 257 .hooknum = NF_INET_POST_ROUTING, ··· 94 259 }, 95 260 /* Before packet filtering, change destination */ 96 261 { 97 - .hook = nf_nat_ipv4_local_fn, 262 + .hook = iptable_nat_ipv4_local_fn, 98 263 .owner = THIS_MODULE, 99 264 .pf = NFPROTO_IPV4, 100 265 .hooknum = NF_INET_LOCAL_OUT, ··· 102 267 }, 103 268 /* After packet filtering, change source */ 104 269 { 105 - .hook = nf_nat_ipv4_fn, 270 + .hook = iptable_nat_ipv4_fn, 106 271 .owner = THIS_MODULE, 107 272 .pf = NFPROTO_IPV4, 108 273 .hooknum = NF_INET_LOCAL_IN,
+199
net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
··· 254 254 } 255 255 EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); 256 256 257 + unsigned int 258 + nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, 259 + const struct net_device *in, const struct net_device *out, 260 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 261 + struct sk_buff *skb, 262 + const struct net_device *in, 263 + const struct net_device *out, 264 + struct nf_conn *ct)) 265 + { 266 + struct nf_conn *ct; 267 + enum ip_conntrack_info ctinfo; 268 + struct nf_conn_nat *nat; 269 + /* maniptype == SRC for postrouting. */ 270 + enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); 271 + 272 + /* We never see fragments: conntrack defrags on pre-routing 273 + * and local-out, and nf_nat_out protects post-routing. 274 + */ 275 + NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb))); 276 + 277 + ct = nf_ct_get(skb, &ctinfo); 278 + /* Can't track? It's not due to stress, or conntrack would 279 + * have dropped it. Hence it's the user's responsibilty to 280 + * packet filter it out, or implement conntrack/NAT for that 281 + * protocol. 8) --RR 282 + */ 283 + if (!ct) 284 + return NF_ACCEPT; 285 + 286 + /* Don't try to NAT if this packet is not conntracked */ 287 + if (nf_ct_is_untracked(ct)) 288 + return NF_ACCEPT; 289 + 290 + nat = nf_ct_nat_ext_add(ct); 291 + if (nat == NULL) 292 + return NF_ACCEPT; 293 + 294 + switch (ctinfo) { 295 + case IP_CT_RELATED: 296 + case IP_CT_RELATED_REPLY: 297 + if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { 298 + if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, 299 + ops->hooknum)) 300 + return NF_DROP; 301 + else 302 + return NF_ACCEPT; 303 + } 304 + /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ 305 + case IP_CT_NEW: 306 + /* Seen it before? This can happen for loopback, retrans, 307 + * or local packets. 308 + */ 309 + if (!nf_nat_initialized(ct, maniptype)) { 310 + unsigned int ret; 311 + 312 + ret = do_chain(ops, skb, in, out, ct); 313 + if (ret != NF_ACCEPT) 314 + return ret; 315 + 316 + if (nf_nat_initialized(ct, HOOK2MANIP(ops->hooknum))) 317 + break; 318 + 319 + ret = nf_nat_alloc_null_binding(ct, ops->hooknum); 320 + if (ret != NF_ACCEPT) 321 + return ret; 322 + } else { 323 + pr_debug("Already setup manip %s for ct %p\n", 324 + maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 325 + ct); 326 + if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) 327 + goto oif_changed; 328 + } 329 + break; 330 + 331 + default: 332 + /* ESTABLISHED */ 333 + NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || 334 + ctinfo == IP_CT_ESTABLISHED_REPLY); 335 + if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) 336 + goto oif_changed; 337 + } 338 + 339 + return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); 340 + 341 + oif_changed: 342 + nf_ct_kill_acct(ct, ctinfo, skb); 343 + return NF_DROP; 344 + } 345 + EXPORT_SYMBOL_GPL(nf_nat_ipv4_fn); 346 + 347 + unsigned int 348 + nf_nat_ipv4_in(const struct nf_hook_ops *ops, struct sk_buff *skb, 349 + const struct net_device *in, const struct net_device *out, 350 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 351 + struct sk_buff *skb, 352 + const struct net_device *in, 353 + const struct net_device *out, 354 + struct nf_conn *ct)) 355 + { 356 + unsigned int ret; 357 + __be32 daddr = ip_hdr(skb)->daddr; 358 + 359 + ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain); 360 + if (ret != NF_DROP && ret != NF_STOLEN && 361 + daddr != ip_hdr(skb)->daddr) 362 + skb_dst_drop(skb); 363 + 364 + return ret; 365 + } 366 + EXPORT_SYMBOL_GPL(nf_nat_ipv4_in); 367 + 368 + unsigned int 369 + nf_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb, 370 + const struct net_device *in, const struct net_device *out, 371 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 372 + struct sk_buff *skb, 373 + const struct net_device *in, 374 + const struct net_device *out, 375 + struct nf_conn *ct)) 376 + { 377 + #ifdef CONFIG_XFRM 378 + const struct nf_conn *ct; 379 + enum ip_conntrack_info ctinfo; 380 + int err; 381 + #endif 382 + unsigned int ret; 383 + 384 + /* root is playing with raw sockets. */ 385 + if (skb->len < sizeof(struct iphdr) || 386 + ip_hdrlen(skb) < sizeof(struct iphdr)) 387 + return NF_ACCEPT; 388 + 389 + ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain); 390 + #ifdef CONFIG_XFRM 391 + if (ret != NF_DROP && ret != NF_STOLEN && 392 + !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && 393 + (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 394 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 395 + 396 + if ((ct->tuplehash[dir].tuple.src.u3.ip != 397 + ct->tuplehash[!dir].tuple.dst.u3.ip) || 398 + (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP && 399 + ct->tuplehash[dir].tuple.src.u.all != 400 + ct->tuplehash[!dir].tuple.dst.u.all)) { 401 + err = nf_xfrm_me_harder(skb, AF_INET); 402 + if (err < 0) 403 + ret = NF_DROP_ERR(err); 404 + } 405 + } 406 + #endif 407 + return ret; 408 + } 409 + EXPORT_SYMBOL_GPL(nf_nat_ipv4_out); 410 + 411 + unsigned int 412 + nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, 413 + const struct net_device *in, const struct net_device *out, 414 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 415 + struct sk_buff *skb, 416 + const struct net_device *in, 417 + const struct net_device *out, 418 + struct nf_conn *ct)) 419 + { 420 + const struct nf_conn *ct; 421 + enum ip_conntrack_info ctinfo; 422 + unsigned int ret; 423 + int err; 424 + 425 + /* root is playing with raw sockets. */ 426 + if (skb->len < sizeof(struct iphdr) || 427 + ip_hdrlen(skb) < sizeof(struct iphdr)) 428 + return NF_ACCEPT; 429 + 430 + ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain); 431 + if (ret != NF_DROP && ret != NF_STOLEN && 432 + (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 433 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 434 + 435 + if (ct->tuplehash[dir].tuple.dst.u3.ip != 436 + ct->tuplehash[!dir].tuple.src.u3.ip) { 437 + err = ip_route_me_harder(skb, RTN_UNSPEC); 438 + if (err < 0) 439 + ret = NF_DROP_ERR(err); 440 + } 441 + #ifdef CONFIG_XFRM 442 + else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && 443 + ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP && 444 + ct->tuplehash[dir].tuple.dst.u.all != 445 + ct->tuplehash[!dir].tuple.src.u.all) { 446 + err = nf_xfrm_me_harder(skb, AF_INET); 447 + if (err < 0) 448 + ret = NF_DROP_ERR(err); 449 + } 450 + #endif 451 + } 452 + return ret; 453 + } 454 + EXPORT_SYMBOL_GPL(nf_nat_ipv4_local_fn); 455 + 257 456 static int __init nf_nat_l3proto_ipv4_init(void) 258 457 { 259 458 int err;
+153
net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
··· 1 + /* (C) 1999-2001 Paul `Rusty' Russell 2 + * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 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 + 9 + #include <linux/types.h> 10 + #include <linux/module.h> 11 + #include <linux/atomic.h> 12 + #include <linux/inetdevice.h> 13 + #include <linux/ip.h> 14 + #include <linux/timer.h> 15 + #include <linux/netfilter.h> 16 + #include <net/protocol.h> 17 + #include <net/ip.h> 18 + #include <net/checksum.h> 19 + #include <net/route.h> 20 + #include <linux/netfilter_ipv4.h> 21 + #include <linux/netfilter/x_tables.h> 22 + #include <net/netfilter/nf_nat.h> 23 + #include <net/netfilter/ipv4/nf_nat_masquerade.h> 24 + 25 + unsigned int 26 + nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum, 27 + const struct nf_nat_range *range, 28 + const struct net_device *out) 29 + { 30 + struct nf_conn *ct; 31 + struct nf_conn_nat *nat; 32 + enum ip_conntrack_info ctinfo; 33 + struct nf_nat_range newrange; 34 + const struct rtable *rt; 35 + __be32 newsrc, nh; 36 + 37 + NF_CT_ASSERT(hooknum == NF_INET_POST_ROUTING); 38 + 39 + ct = nf_ct_get(skb, &ctinfo); 40 + nat = nfct_nat(ct); 41 + 42 + NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || 43 + ctinfo == IP_CT_RELATED_REPLY)); 44 + 45 + /* Source address is 0.0.0.0 - locally generated packet that is 46 + * probably not supposed to be masqueraded. 47 + */ 48 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0) 49 + return NF_ACCEPT; 50 + 51 + rt = skb_rtable(skb); 52 + nh = rt_nexthop(rt, ip_hdr(skb)->daddr); 53 + newsrc = inet_select_addr(out, nh, RT_SCOPE_UNIVERSE); 54 + if (!newsrc) { 55 + pr_info("%s ate my IP address\n", out->name); 56 + return NF_DROP; 57 + } 58 + 59 + nat->masq_index = out->ifindex; 60 + 61 + /* Transfer from original range. */ 62 + memset(&newrange.min_addr, 0, sizeof(newrange.min_addr)); 63 + memset(&newrange.max_addr, 0, sizeof(newrange.max_addr)); 64 + newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; 65 + newrange.min_addr.ip = newsrc; 66 + newrange.max_addr.ip = newsrc; 67 + newrange.min_proto = range->min_proto; 68 + newrange.max_proto = range->max_proto; 69 + 70 + /* Hand modified range to generic setup. */ 71 + return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); 72 + } 73 + EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4); 74 + 75 + static int device_cmp(struct nf_conn *i, void *ifindex) 76 + { 77 + const struct nf_conn_nat *nat = nfct_nat(i); 78 + 79 + if (!nat) 80 + return 0; 81 + if (nf_ct_l3num(i) != NFPROTO_IPV4) 82 + return 0; 83 + return nat->masq_index == (int)(long)ifindex; 84 + } 85 + 86 + static int masq_device_event(struct notifier_block *this, 87 + unsigned long event, 88 + void *ptr) 89 + { 90 + const struct net_device *dev = netdev_notifier_info_to_dev(ptr); 91 + struct net *net = dev_net(dev); 92 + 93 + if (event == NETDEV_DOWN) { 94 + /* Device was downed. Search entire table for 95 + * conntracks which were associated with that device, 96 + * and forget them. 97 + */ 98 + NF_CT_ASSERT(dev->ifindex != 0); 99 + 100 + nf_ct_iterate_cleanup(net, device_cmp, 101 + (void *)(long)dev->ifindex, 0, 0); 102 + } 103 + 104 + return NOTIFY_DONE; 105 + } 106 + 107 + static int masq_inet_event(struct notifier_block *this, 108 + unsigned long event, 109 + void *ptr) 110 + { 111 + struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; 112 + struct netdev_notifier_info info; 113 + 114 + netdev_notifier_info_init(&info, dev); 115 + return masq_device_event(this, event, &info); 116 + } 117 + 118 + static struct notifier_block masq_dev_notifier = { 119 + .notifier_call = masq_device_event, 120 + }; 121 + 122 + static struct notifier_block masq_inet_notifier = { 123 + .notifier_call = masq_inet_event, 124 + }; 125 + 126 + static atomic_t masquerade_notifier_refcount = ATOMIC_INIT(0); 127 + 128 + void nf_nat_masquerade_ipv4_register_notifier(void) 129 + { 130 + /* check if the notifier was already set */ 131 + if (atomic_inc_return(&masquerade_notifier_refcount) > 1) 132 + return; 133 + 134 + /* Register for device down reports */ 135 + register_netdevice_notifier(&masq_dev_notifier); 136 + /* Register IP address change reports */ 137 + register_inetaddr_notifier(&masq_inet_notifier); 138 + } 139 + EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_register_notifier); 140 + 141 + void nf_nat_masquerade_ipv4_unregister_notifier(void) 142 + { 143 + /* check if the notifier still has clients */ 144 + if (atomic_dec_return(&masquerade_notifier_refcount) > 0) 145 + return; 146 + 147 + unregister_netdevice_notifier(&masq_dev_notifier); 148 + unregister_inetaddr_notifier(&masq_inet_notifier); 149 + } 150 + EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_unregister_notifier); 151 + 152 + MODULE_LICENSE("GPL"); 153 + MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
+38 -121
net/ipv4/netfilter/nft_chain_nat_ipv4.c
··· 26 26 #include <net/netfilter/nf_nat_l3proto.h> 27 27 #include <net/ip.h> 28 28 29 - /* 30 - * NAT chains 31 - */ 32 - 33 - static unsigned int nf_nat_fn(const struct nf_hook_ops *ops, 34 - struct sk_buff *skb, 35 - const struct net_device *in, 36 - const struct net_device *out, 37 - int (*okfn)(struct sk_buff *)) 38 - { 39 - enum ip_conntrack_info ctinfo; 40 - struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 41 - struct nf_conn_nat *nat; 42 - enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); 43 - struct nft_pktinfo pkt; 44 - unsigned int ret; 45 - 46 - if (ct == NULL || nf_ct_is_untracked(ct)) 47 - return NF_ACCEPT; 48 - 49 - NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET))); 50 - 51 - nat = nf_ct_nat_ext_add(ct); 52 - if (nat == NULL) 53 - return NF_ACCEPT; 54 - 55 - switch (ctinfo) { 56 - case IP_CT_RELATED: 57 - case IP_CT_RELATED + IP_CT_IS_REPLY: 58 - if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { 59 - if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, 60 - ops->hooknum)) 61 - return NF_DROP; 62 - else 63 - return NF_ACCEPT; 64 - } 65 - /* Fall through */ 66 - case IP_CT_NEW: 67 - if (nf_nat_initialized(ct, maniptype)) 68 - break; 69 - 70 - nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); 71 - 72 - ret = nft_do_chain(&pkt, ops); 73 - if (ret != NF_ACCEPT) 74 - return ret; 75 - if (!nf_nat_initialized(ct, maniptype)) { 76 - ret = nf_nat_alloc_null_binding(ct, ops->hooknum); 77 - if (ret != NF_ACCEPT) 78 - return ret; 79 - } 80 - default: 81 - break; 82 - } 83 - 84 - return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); 85 - } 86 - 87 - static unsigned int nf_nat_prerouting(const struct nf_hook_ops *ops, 29 + static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops, 88 30 struct sk_buff *skb, 89 31 const struct net_device *in, 90 32 const struct net_device *out, 91 - int (*okfn)(struct sk_buff *)) 33 + struct nf_conn *ct) 92 34 { 93 - __be32 daddr = ip_hdr(skb)->daddr; 94 - unsigned int ret; 35 + struct nft_pktinfo pkt; 95 36 96 - ret = nf_nat_fn(ops, skb, in, out, okfn); 97 - if (ret != NF_DROP && ret != NF_STOLEN && 98 - ip_hdr(skb)->daddr != daddr) { 99 - skb_dst_drop(skb); 100 - } 101 - return ret; 37 + nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); 38 + 39 + return nft_do_chain(&pkt, ops); 102 40 } 103 41 104 - static unsigned int nf_nat_postrouting(const struct nf_hook_ops *ops, 105 - struct sk_buff *skb, 106 - const struct net_device *in, 107 - const struct net_device *out, 108 - int (*okfn)(struct sk_buff *)) 42 + static unsigned int nft_nat_ipv4_fn(const struct nf_hook_ops *ops, 43 + struct sk_buff *skb, 44 + const struct net_device *in, 45 + const struct net_device *out, 46 + int (*okfn)(struct sk_buff *)) 109 47 { 110 - enum ip_conntrack_info ctinfo __maybe_unused; 111 - const struct nf_conn *ct __maybe_unused; 112 - unsigned int ret; 113 - 114 - ret = nf_nat_fn(ops, skb, in, out, okfn); 115 - #ifdef CONFIG_XFRM 116 - if (ret != NF_DROP && ret != NF_STOLEN && 117 - (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 118 - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 119 - 120 - if (ct->tuplehash[dir].tuple.src.u3.ip != 121 - ct->tuplehash[!dir].tuple.dst.u3.ip || 122 - ct->tuplehash[dir].tuple.src.u.all != 123 - ct->tuplehash[!dir].tuple.dst.u.all) 124 - return nf_xfrm_me_harder(skb, AF_INET) == 0 ? 125 - ret : NF_DROP; 126 - } 127 - #endif 128 - return ret; 48 + return nf_nat_ipv4_fn(ops, skb, in, out, nft_nat_do_chain); 129 49 } 130 50 131 - static unsigned int nf_nat_output(const struct nf_hook_ops *ops, 132 - struct sk_buff *skb, 133 - const struct net_device *in, 134 - const struct net_device *out, 135 - int (*okfn)(struct sk_buff *)) 51 + static unsigned int nft_nat_ipv4_in(const struct nf_hook_ops *ops, 52 + struct sk_buff *skb, 53 + const struct net_device *in, 54 + const struct net_device *out, 55 + int (*okfn)(struct sk_buff *)) 136 56 { 137 - enum ip_conntrack_info ctinfo; 138 - const struct nf_conn *ct; 139 - unsigned int ret; 57 + return nf_nat_ipv4_in(ops, skb, in, out, nft_nat_do_chain); 58 + } 140 59 141 - ret = nf_nat_fn(ops, skb, in, out, okfn); 142 - if (ret != NF_DROP && ret != NF_STOLEN && 143 - (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 144 - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 60 + static unsigned int nft_nat_ipv4_out(const struct nf_hook_ops *ops, 61 + struct sk_buff *skb, 62 + const struct net_device *in, 63 + const struct net_device *out, 64 + int (*okfn)(struct sk_buff *)) 65 + { 66 + return nf_nat_ipv4_out(ops, skb, in, out, nft_nat_do_chain); 67 + } 145 68 146 - if (ct->tuplehash[dir].tuple.dst.u3.ip != 147 - ct->tuplehash[!dir].tuple.src.u3.ip) { 148 - if (ip_route_me_harder(skb, RTN_UNSPEC)) 149 - ret = NF_DROP; 150 - } 151 - #ifdef CONFIG_XFRM 152 - else if (ct->tuplehash[dir].tuple.dst.u.all != 153 - ct->tuplehash[!dir].tuple.src.u.all) 154 - if (nf_xfrm_me_harder(skb, AF_INET)) 155 - ret = NF_DROP; 156 - #endif 157 - } 158 - return ret; 69 + static unsigned int nft_nat_ipv4_local_fn(const struct nf_hook_ops *ops, 70 + struct sk_buff *skb, 71 + const struct net_device *in, 72 + const struct net_device *out, 73 + int (*okfn)(struct sk_buff *)) 74 + { 75 + return nf_nat_ipv4_local_fn(ops, skb, in, out, nft_nat_do_chain); 159 76 } 160 77 161 78 static const struct nf_chain_type nft_chain_nat_ipv4 = { ··· 85 168 (1 << NF_INET_LOCAL_OUT) | 86 169 (1 << NF_INET_LOCAL_IN), 87 170 .hooks = { 88 - [NF_INET_PRE_ROUTING] = nf_nat_prerouting, 89 - [NF_INET_POST_ROUTING] = nf_nat_postrouting, 90 - [NF_INET_LOCAL_OUT] = nf_nat_output, 91 - [NF_INET_LOCAL_IN] = nf_nat_fn, 171 + [NF_INET_PRE_ROUTING] = nft_nat_ipv4_in, 172 + [NF_INET_POST_ROUTING] = nft_nat_ipv4_out, 173 + [NF_INET_LOCAL_OUT] = nft_nat_ipv4_local_fn, 174 + [NF_INET_LOCAL_IN] = nft_nat_ipv4_fn, 92 175 }, 93 176 }; 94 177
+89
net/ipv4/netfilter/nft_masq_ipv4.c
··· 1 + /* 2 + * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> 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 + 9 + #include <linux/kernel.h> 10 + #include <linux/init.h> 11 + #include <linux/module.h> 12 + #include <linux/netlink.h> 13 + #include <linux/netfilter.h> 14 + #include <linux/netfilter/nf_tables.h> 15 + #include <net/netfilter/nf_tables.h> 16 + #include <net/netfilter/nft_masq.h> 17 + #include <net/netfilter/ipv4/nf_nat_masquerade.h> 18 + 19 + static void nft_masq_ipv4_eval(const struct nft_expr *expr, 20 + struct nft_data data[NFT_REG_MAX + 1], 21 + const struct nft_pktinfo *pkt) 22 + { 23 + struct nft_masq *priv = nft_expr_priv(expr); 24 + struct nf_nat_range range; 25 + unsigned int verdict; 26 + 27 + range.flags = priv->flags; 28 + 29 + verdict = nf_nat_masquerade_ipv4(pkt->skb, pkt->ops->hooknum, 30 + &range, pkt->out); 31 + 32 + data[NFT_REG_VERDICT].verdict = verdict; 33 + } 34 + 35 + static int nft_masq_ipv4_init(const struct nft_ctx *ctx, 36 + const struct nft_expr *expr, 37 + const struct nlattr * const tb[]) 38 + { 39 + int err; 40 + 41 + err = nft_masq_init(ctx, expr, tb); 42 + if (err < 0) 43 + return err; 44 + 45 + nf_nat_masquerade_ipv4_register_notifier(); 46 + return 0; 47 + } 48 + 49 + static void nft_masq_ipv4_destroy(const struct nft_ctx *ctx, 50 + const struct nft_expr *expr) 51 + { 52 + nf_nat_masquerade_ipv4_unregister_notifier(); 53 + } 54 + 55 + static struct nft_expr_type nft_masq_ipv4_type; 56 + static const struct nft_expr_ops nft_masq_ipv4_ops = { 57 + .type = &nft_masq_ipv4_type, 58 + .size = NFT_EXPR_SIZE(sizeof(struct nft_masq)), 59 + .eval = nft_masq_ipv4_eval, 60 + .init = nft_masq_ipv4_init, 61 + .destroy = nft_masq_ipv4_destroy, 62 + .dump = nft_masq_dump, 63 + }; 64 + 65 + static struct nft_expr_type nft_masq_ipv4_type __read_mostly = { 66 + .family = NFPROTO_IPV4, 67 + .name = "masq", 68 + .ops = &nft_masq_ipv4_ops, 69 + .policy = nft_masq_policy, 70 + .maxattr = NFTA_MASQ_MAX, 71 + .owner = THIS_MODULE, 72 + }; 73 + 74 + static int __init nft_masq_ipv4_module_init(void) 75 + { 76 + return nft_register_expr(&nft_masq_ipv4_type); 77 + } 78 + 79 + static void __exit nft_masq_ipv4_module_exit(void) 80 + { 81 + nft_unregister_expr(&nft_masq_ipv4_type); 82 + } 83 + 84 + module_init(nft_masq_ipv4_module_init); 85 + module_exit(nft_masq_ipv4_module_exit); 86 + 87 + MODULE_LICENSE("GPL"); 88 + MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>"); 89 + MODULE_ALIAS_NFT_AF_EXPR(AF_INET, "masq");
+13
net/ipv6/netfilter/Kconfig
··· 258 258 259 259 if IP6_NF_NAT 260 260 261 + config NF_NAT_MASQUERADE_IPV6 262 + tristate "IPv6 masquerade support" 263 + help 264 + This is the kernel functionality to provide NAT in the masquerade 265 + flavour (automatic source address selection) for IPv6. 266 + 267 + config NFT_MASQ_IPV6 268 + tristate "IPv6 masquerade support for nf_tables" 269 + depends on NF_TABLES_IPV6 270 + depends on NFT_MASQ 271 + select NF_NAT_MASQUERADE_IPV6 272 + 261 273 config IP6_NF_TARGET_MASQUERADE 262 274 tristate "MASQUERADE target support" 275 + select NF_NAT_MASQUERADE_IPV6 263 276 help 264 277 Masquerading is a special case of NAT: all outgoing connections are 265 278 changed to seem to come from a particular interface's address, and
+2
net/ipv6/netfilter/Makefile
··· 18 18 19 19 nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o 20 20 obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o 21 + obj-$(CONFIG_NF_NAT_MASQUERADE_IPV6) += nf_nat_masquerade_ipv6.o 21 22 22 23 # defrag 23 24 nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o ··· 32 31 obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o 33 32 obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o 34 33 obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o 34 + obj-$(CONFIG_NFT_MASQ_IPV6) += nft_masq_ipv6.o 35 35 36 36 # matches 37 37 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
+5 -71
net/ipv6/netfilter/ip6t_MASQUERADE.c
··· 19 19 #include <net/netfilter/nf_nat.h> 20 20 #include <net/addrconf.h> 21 21 #include <net/ipv6.h> 22 + #include <net/netfilter/ipv6/nf_nat_masquerade.h> 22 23 23 24 static unsigned int 24 25 masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par) 25 26 { 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); 27 + return nf_nat_masquerade_ipv6(skb, par->targinfo, par->out); 49 28 } 50 29 51 30 static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par) ··· 35 56 return -EINVAL; 36 57 return 0; 37 58 } 38 - 39 - static int device_cmp(struct nf_conn *ct, void *ifindex) 40 - { 41 - const struct nf_conn_nat *nat = nfct_nat(ct); 42 - 43 - if (!nat) 44 - return 0; 45 - if (nf_ct_l3num(ct) != NFPROTO_IPV6) 46 - return 0; 47 - return nat->masq_index == (int)(long)ifindex; 48 - } 49 - 50 - static int masq_device_event(struct notifier_block *this, 51 - unsigned long event, void *ptr) 52 - { 53 - const struct net_device *dev = netdev_notifier_info_to_dev(ptr); 54 - struct net *net = dev_net(dev); 55 - 56 - if (event == NETDEV_DOWN) 57 - nf_ct_iterate_cleanup(net, device_cmp, 58 - (void *)(long)dev->ifindex, 0, 0); 59 - 60 - return NOTIFY_DONE; 61 - } 62 - 63 - static struct notifier_block masq_dev_notifier = { 64 - .notifier_call = masq_device_event, 65 - }; 66 - 67 - static int masq_inet_event(struct notifier_block *this, 68 - unsigned long event, void *ptr) 69 - { 70 - struct inet6_ifaddr *ifa = ptr; 71 - struct netdev_notifier_info info; 72 - 73 - netdev_notifier_info_init(&info, ifa->idev->dev); 74 - return masq_device_event(this, event, &info); 75 - } 76 - 77 - static struct notifier_block masq_inet_notifier = { 78 - .notifier_call = masq_inet_event, 79 - }; 80 59 81 60 static struct xt_target masquerade_tg6_reg __read_mostly = { 82 61 .name = "MASQUERADE", ··· 52 115 int err; 53 116 54 117 err = xt_register_target(&masquerade_tg6_reg); 55 - if (err == 0) { 56 - register_netdevice_notifier(&masq_dev_notifier); 57 - register_inet6addr_notifier(&masq_inet_notifier); 58 - } 118 + if (err == 0) 119 + nf_nat_masquerade_ipv6_register_notifier(); 59 120 60 121 return err; 61 122 } 62 123 static void __exit masquerade_tg6_exit(void) 63 124 { 64 - unregister_inet6addr_notifier(&masq_inet_notifier); 65 - unregister_netdevice_notifier(&masq_dev_notifier); 125 + nf_nat_masquerade_ipv6_unregister_notifier(); 66 126 xt_unregister_target(&masquerade_tg6_reg); 67 127 } 68 128
+34 -199
net/ipv6/netfilter/ip6table_nat.c
··· 30 30 .af = NFPROTO_IPV6, 31 31 }; 32 32 33 - static unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) 34 - { 35 - /* Force range to this IP; let proto decide mapping for 36 - * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). 37 - */ 38 - struct nf_nat_range range; 39 - 40 - range.flags = 0; 41 - pr_debug("Allocating NULL binding for %p (%pI6)\n", ct, 42 - HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ? 43 - &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6 : 44 - &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6); 45 - 46 - return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum)); 47 - } 48 - 49 - static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum, 50 - const struct net_device *in, 51 - const struct net_device *out, 52 - struct nf_conn *ct) 33 + static unsigned int ip6table_nat_do_chain(const struct nf_hook_ops *ops, 34 + struct sk_buff *skb, 35 + const struct net_device *in, 36 + const struct net_device *out, 37 + struct nf_conn *ct) 53 38 { 54 39 struct net *net = nf_ct_net(ct); 55 - unsigned int ret; 56 40 57 - ret = ip6t_do_table(skb, hooknum, in, out, net->ipv6.ip6table_nat); 58 - if (ret == NF_ACCEPT) { 59 - if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) 60 - ret = alloc_null_binding(ct, hooknum); 61 - } 62 - return ret; 41 + return ip6t_do_table(skb, ops->hooknum, in, out, net->ipv6.ip6table_nat); 63 42 } 64 43 65 - static unsigned int 66 - nf_nat_ipv6_fn(const struct nf_hook_ops *ops, 67 - struct sk_buff *skb, 68 - const struct net_device *in, 69 - const struct net_device *out, 70 - int (*okfn)(struct sk_buff *)) 44 + static unsigned int ip6table_nat_fn(const struct nf_hook_ops *ops, 45 + struct sk_buff *skb, 46 + const struct net_device *in, 47 + const struct net_device *out, 48 + int (*okfn)(struct sk_buff *)) 71 49 { 72 - struct nf_conn *ct; 73 - enum ip_conntrack_info ctinfo; 74 - struct nf_conn_nat *nat; 75 - enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); 76 - __be16 frag_off; 77 - int hdrlen; 78 - u8 nexthdr; 79 - 80 - ct = nf_ct_get(skb, &ctinfo); 81 - /* Can't track? It's not due to stress, or conntrack would 82 - * have dropped it. Hence it's the user's responsibilty to 83 - * packet filter it out, or implement conntrack/NAT for that 84 - * protocol. 8) --RR 85 - */ 86 - if (!ct) 87 - return NF_ACCEPT; 88 - 89 - /* Don't try to NAT if this packet is not conntracked */ 90 - if (nf_ct_is_untracked(ct)) 91 - return NF_ACCEPT; 92 - 93 - nat = nf_ct_nat_ext_add(ct); 94 - if (nat == NULL) 95 - return NF_ACCEPT; 96 - 97 - switch (ctinfo) { 98 - case IP_CT_RELATED: 99 - case IP_CT_RELATED_REPLY: 100 - nexthdr = ipv6_hdr(skb)->nexthdr; 101 - hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), 102 - &nexthdr, &frag_off); 103 - 104 - if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { 105 - if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, 106 - ops->hooknum, 107 - hdrlen)) 108 - return NF_DROP; 109 - else 110 - return NF_ACCEPT; 111 - } 112 - /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ 113 - case IP_CT_NEW: 114 - /* Seen it before? This can happen for loopback, retrans, 115 - * or local packets. 116 - */ 117 - if (!nf_nat_initialized(ct, maniptype)) { 118 - unsigned int ret; 119 - 120 - ret = nf_nat_rule_find(skb, ops->hooknum, in, out, ct); 121 - if (ret != NF_ACCEPT) 122 - return ret; 123 - } else { 124 - pr_debug("Already setup manip %s for ct %p\n", 125 - maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 126 - ct); 127 - if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) 128 - goto oif_changed; 129 - } 130 - break; 131 - 132 - default: 133 - /* ESTABLISHED */ 134 - NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || 135 - ctinfo == IP_CT_ESTABLISHED_REPLY); 136 - if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) 137 - goto oif_changed; 138 - } 139 - 140 - return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); 141 - 142 - oif_changed: 143 - nf_ct_kill_acct(ct, ctinfo, skb); 144 - return NF_DROP; 50 + return nf_nat_ipv6_fn(ops, skb, in, out, ip6table_nat_do_chain); 145 51 } 146 52 147 - static unsigned int 148 - nf_nat_ipv6_in(const struct nf_hook_ops *ops, 149 - struct sk_buff *skb, 150 - const struct net_device *in, 151 - const struct net_device *out, 152 - int (*okfn)(struct sk_buff *)) 53 + static unsigned int ip6table_nat_in(const struct nf_hook_ops *ops, 54 + struct sk_buff *skb, 55 + const struct net_device *in, 56 + const struct net_device *out, 57 + int (*okfn)(struct sk_buff *)) 153 58 { 154 - unsigned int ret; 155 - struct in6_addr daddr = ipv6_hdr(skb)->daddr; 156 - 157 - ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); 158 - if (ret != NF_DROP && ret != NF_STOLEN && 159 - ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) 160 - skb_dst_drop(skb); 161 - 162 - return ret; 59 + return nf_nat_ipv6_in(ops, skb, in, out, ip6table_nat_do_chain); 163 60 } 164 61 165 - static unsigned int 166 - nf_nat_ipv6_out(const struct nf_hook_ops *ops, 167 - struct sk_buff *skb, 168 - const struct net_device *in, 169 - const struct net_device *out, 170 - int (*okfn)(struct sk_buff *)) 62 + static unsigned int ip6table_nat_out(const struct nf_hook_ops *ops, 63 + struct sk_buff *skb, 64 + const struct net_device *in, 65 + const struct net_device *out, 66 + int (*okfn)(struct sk_buff *)) 171 67 { 172 - #ifdef CONFIG_XFRM 173 - const struct nf_conn *ct; 174 - enum ip_conntrack_info ctinfo; 175 - int err; 176 - #endif 177 - unsigned int ret; 178 - 179 - /* root is playing with raw sockets. */ 180 - if (skb->len < sizeof(struct ipv6hdr)) 181 - return NF_ACCEPT; 182 - 183 - ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); 184 - #ifdef CONFIG_XFRM 185 - if (ret != NF_DROP && ret != NF_STOLEN && 186 - !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 187 - (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 188 - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 189 - 190 - if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, 191 - &ct->tuplehash[!dir].tuple.dst.u3) || 192 - (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && 193 - ct->tuplehash[dir].tuple.src.u.all != 194 - ct->tuplehash[!dir].tuple.dst.u.all)) { 195 - err = nf_xfrm_me_harder(skb, AF_INET6); 196 - if (err < 0) 197 - ret = NF_DROP_ERR(err); 198 - } 199 - } 200 - #endif 201 - return ret; 68 + return nf_nat_ipv6_out(ops, skb, in, out, ip6table_nat_do_chain); 202 69 } 203 70 204 - static unsigned int 205 - nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, 206 - struct sk_buff *skb, 207 - const struct net_device *in, 208 - const struct net_device *out, 209 - int (*okfn)(struct sk_buff *)) 71 + static unsigned int ip6table_nat_local_fn(const struct nf_hook_ops *ops, 72 + struct sk_buff *skb, 73 + const struct net_device *in, 74 + const struct net_device *out, 75 + int (*okfn)(struct sk_buff *)) 210 76 { 211 - const struct nf_conn *ct; 212 - enum ip_conntrack_info ctinfo; 213 - unsigned int ret; 214 - int err; 215 - 216 - /* root is playing with raw sockets. */ 217 - if (skb->len < sizeof(struct ipv6hdr)) 218 - return NF_ACCEPT; 219 - 220 - ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); 221 - if (ret != NF_DROP && ret != NF_STOLEN && 222 - (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 223 - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 224 - 225 - if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, 226 - &ct->tuplehash[!dir].tuple.src.u3)) { 227 - err = ip6_route_me_harder(skb); 228 - if (err < 0) 229 - ret = NF_DROP_ERR(err); 230 - } 231 - #ifdef CONFIG_XFRM 232 - else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 233 - ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && 234 - ct->tuplehash[dir].tuple.dst.u.all != 235 - ct->tuplehash[!dir].tuple.src.u.all) { 236 - err = nf_xfrm_me_harder(skb, AF_INET6); 237 - if (err < 0) 238 - ret = NF_DROP_ERR(err); 239 - } 240 - #endif 241 - } 242 - return ret; 77 + return nf_nat_ipv6_local_fn(ops, skb, in, out, ip6table_nat_do_chain); 243 78 } 244 79 245 80 static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { 246 81 /* Before packet filtering, change destination */ 247 82 { 248 - .hook = nf_nat_ipv6_in, 83 + .hook = ip6table_nat_in, 249 84 .owner = THIS_MODULE, 250 85 .pf = NFPROTO_IPV6, 251 86 .hooknum = NF_INET_PRE_ROUTING, ··· 88 253 }, 89 254 /* After packet filtering, change source */ 90 255 { 91 - .hook = nf_nat_ipv6_out, 256 + .hook = ip6table_nat_out, 92 257 .owner = THIS_MODULE, 93 258 .pf = NFPROTO_IPV6, 94 259 .hooknum = NF_INET_POST_ROUTING, ··· 96 261 }, 97 262 /* Before packet filtering, change destination */ 98 263 { 99 - .hook = nf_nat_ipv6_local_fn, 264 + .hook = ip6table_nat_local_fn, 100 265 .owner = THIS_MODULE, 101 266 .pf = NFPROTO_IPV6, 102 267 .hooknum = NF_INET_LOCAL_OUT, ··· 104 269 }, 105 270 /* After packet filtering, change source */ 106 271 { 107 - .hook = nf_nat_ipv6_fn, 272 + .hook = ip6table_nat_fn, 108 273 .owner = THIS_MODULE, 109 274 .pf = NFPROTO_IPV6, 110 275 .hooknum = NF_INET_LOCAL_IN,
+199
net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
··· 261 261 } 262 262 EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation); 263 263 264 + unsigned int 265 + nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, 266 + const struct net_device *in, const struct net_device *out, 267 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 268 + struct sk_buff *skb, 269 + const struct net_device *in, 270 + const struct net_device *out, 271 + struct nf_conn *ct)) 272 + { 273 + struct nf_conn *ct; 274 + enum ip_conntrack_info ctinfo; 275 + struct nf_conn_nat *nat; 276 + enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); 277 + __be16 frag_off; 278 + int hdrlen; 279 + u8 nexthdr; 280 + 281 + ct = nf_ct_get(skb, &ctinfo); 282 + /* Can't track? It's not due to stress, or conntrack would 283 + * have dropped it. Hence it's the user's responsibilty to 284 + * packet filter it out, or implement conntrack/NAT for that 285 + * protocol. 8) --RR 286 + */ 287 + if (!ct) 288 + return NF_ACCEPT; 289 + 290 + /* Don't try to NAT if this packet is not conntracked */ 291 + if (nf_ct_is_untracked(ct)) 292 + return NF_ACCEPT; 293 + 294 + nat = nf_ct_nat_ext_add(ct); 295 + if (nat == NULL) 296 + return NF_ACCEPT; 297 + 298 + switch (ctinfo) { 299 + case IP_CT_RELATED: 300 + case IP_CT_RELATED_REPLY: 301 + nexthdr = ipv6_hdr(skb)->nexthdr; 302 + hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), 303 + &nexthdr, &frag_off); 304 + 305 + if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { 306 + if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, 307 + ops->hooknum, 308 + hdrlen)) 309 + return NF_DROP; 310 + else 311 + return NF_ACCEPT; 312 + } 313 + /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ 314 + case IP_CT_NEW: 315 + /* Seen it before? This can happen for loopback, retrans, 316 + * or local packets. 317 + */ 318 + if (!nf_nat_initialized(ct, maniptype)) { 319 + unsigned int ret; 320 + 321 + ret = do_chain(ops, skb, in, out, ct); 322 + if (ret != NF_ACCEPT) 323 + return ret; 324 + 325 + if (nf_nat_initialized(ct, HOOK2MANIP(ops->hooknum))) 326 + break; 327 + 328 + ret = nf_nat_alloc_null_binding(ct, ops->hooknum); 329 + if (ret != NF_ACCEPT) 330 + return ret; 331 + } else { 332 + pr_debug("Already setup manip %s for ct %p\n", 333 + maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", 334 + ct); 335 + if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) 336 + goto oif_changed; 337 + } 338 + break; 339 + 340 + default: 341 + /* ESTABLISHED */ 342 + NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || 343 + ctinfo == IP_CT_ESTABLISHED_REPLY); 344 + if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) 345 + goto oif_changed; 346 + } 347 + 348 + return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); 349 + 350 + oif_changed: 351 + nf_ct_kill_acct(ct, ctinfo, skb); 352 + return NF_DROP; 353 + } 354 + EXPORT_SYMBOL_GPL(nf_nat_ipv6_fn); 355 + 356 + unsigned int 357 + nf_nat_ipv6_in(const struct nf_hook_ops *ops, struct sk_buff *skb, 358 + const struct net_device *in, const struct net_device *out, 359 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 360 + struct sk_buff *skb, 361 + const struct net_device *in, 362 + const struct net_device *out, 363 + struct nf_conn *ct)) 364 + { 365 + unsigned int ret; 366 + struct in6_addr daddr = ipv6_hdr(skb)->daddr; 367 + 368 + ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); 369 + if (ret != NF_DROP && ret != NF_STOLEN && 370 + ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) 371 + skb_dst_drop(skb); 372 + 373 + return ret; 374 + } 375 + EXPORT_SYMBOL_GPL(nf_nat_ipv6_in); 376 + 377 + unsigned int 378 + nf_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb, 379 + const struct net_device *in, const struct net_device *out, 380 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 381 + struct sk_buff *skb, 382 + const struct net_device *in, 383 + const struct net_device *out, 384 + struct nf_conn *ct)) 385 + { 386 + #ifdef CONFIG_XFRM 387 + const struct nf_conn *ct; 388 + enum ip_conntrack_info ctinfo; 389 + int err; 390 + #endif 391 + unsigned int ret; 392 + 393 + /* root is playing with raw sockets. */ 394 + if (skb->len < sizeof(struct ipv6hdr)) 395 + return NF_ACCEPT; 396 + 397 + ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); 398 + #ifdef CONFIG_XFRM 399 + if (ret != NF_DROP && ret != NF_STOLEN && 400 + !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 401 + (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 402 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 403 + 404 + if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, 405 + &ct->tuplehash[!dir].tuple.dst.u3) || 406 + (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && 407 + ct->tuplehash[dir].tuple.src.u.all != 408 + ct->tuplehash[!dir].tuple.dst.u.all)) { 409 + err = nf_xfrm_me_harder(skb, AF_INET6); 410 + if (err < 0) 411 + ret = NF_DROP_ERR(err); 412 + } 413 + } 414 + #endif 415 + return ret; 416 + } 417 + EXPORT_SYMBOL_GPL(nf_nat_ipv6_out); 418 + 419 + unsigned int 420 + nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, 421 + const struct net_device *in, const struct net_device *out, 422 + unsigned int (*do_chain)(const struct nf_hook_ops *ops, 423 + struct sk_buff *skb, 424 + const struct net_device *in, 425 + const struct net_device *out, 426 + struct nf_conn *ct)) 427 + { 428 + const struct nf_conn *ct; 429 + enum ip_conntrack_info ctinfo; 430 + unsigned int ret; 431 + int err; 432 + 433 + /* root is playing with raw sockets. */ 434 + if (skb->len < sizeof(struct ipv6hdr)) 435 + return NF_ACCEPT; 436 + 437 + ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); 438 + if (ret != NF_DROP && ret != NF_STOLEN && 439 + (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 440 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 441 + 442 + if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, 443 + &ct->tuplehash[!dir].tuple.src.u3)) { 444 + err = ip6_route_me_harder(skb); 445 + if (err < 0) 446 + ret = NF_DROP_ERR(err); 447 + } 448 + #ifdef CONFIG_XFRM 449 + else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 450 + ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && 451 + ct->tuplehash[dir].tuple.dst.u.all != 452 + ct->tuplehash[!dir].tuple.src.u.all) { 453 + err = nf_xfrm_me_harder(skb, AF_INET6); 454 + if (err < 0) 455 + ret = NF_DROP_ERR(err); 456 + } 457 + #endif 458 + } 459 + return ret; 460 + } 461 + EXPORT_SYMBOL_GPL(nf_nat_ipv6_local_fn); 462 + 264 463 static int __init nf_nat_l3proto_ipv6_init(void) 265 464 { 266 465 int err;
+120
net/ipv6/netfilter/nf_nat_masquerade_ipv6.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/atomic.h> 15 + #include <linux/netdevice.h> 16 + #include <linux/ipv6.h> 17 + #include <linux/netfilter.h> 18 + #include <linux/netfilter_ipv6.h> 19 + #include <net/netfilter/nf_nat.h> 20 + #include <net/addrconf.h> 21 + #include <net/ipv6.h> 22 + #include <net/netfilter/ipv6/nf_nat_masquerade.h> 23 + 24 + unsigned int 25 + nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range *range, 26 + const struct net_device *out) 27 + { 28 + enum ip_conntrack_info ctinfo; 29 + struct in6_addr src; 30 + struct nf_conn *ct; 31 + struct nf_nat_range newrange; 32 + 33 + ct = nf_ct_get(skb, &ctinfo); 34 + NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || 35 + ctinfo == IP_CT_RELATED_REPLY)); 36 + 37 + if (ipv6_dev_get_saddr(dev_net(out), out, 38 + &ipv6_hdr(skb)->daddr, 0, &src) < 0) 39 + return NF_DROP; 40 + 41 + nfct_nat(ct)->masq_index = out->ifindex; 42 + 43 + newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; 44 + newrange.min_addr.in6 = src; 45 + newrange.max_addr.in6 = src; 46 + newrange.min_proto = range->min_proto; 47 + newrange.max_proto = range->max_proto; 48 + 49 + return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); 50 + } 51 + EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6); 52 + 53 + static int device_cmp(struct nf_conn *ct, void *ifindex) 54 + { 55 + const struct nf_conn_nat *nat = nfct_nat(ct); 56 + 57 + if (!nat) 58 + return 0; 59 + if (nf_ct_l3num(ct) != NFPROTO_IPV6) 60 + return 0; 61 + return nat->masq_index == (int)(long)ifindex; 62 + } 63 + 64 + static int masq_device_event(struct notifier_block *this, 65 + unsigned long event, void *ptr) 66 + { 67 + const struct net_device *dev = netdev_notifier_info_to_dev(ptr); 68 + struct net *net = dev_net(dev); 69 + 70 + if (event == NETDEV_DOWN) 71 + nf_ct_iterate_cleanup(net, device_cmp, 72 + (void *)(long)dev->ifindex, 0, 0); 73 + 74 + return NOTIFY_DONE; 75 + } 76 + 77 + static struct notifier_block masq_dev_notifier = { 78 + .notifier_call = masq_device_event, 79 + }; 80 + 81 + static int masq_inet_event(struct notifier_block *this, 82 + unsigned long event, void *ptr) 83 + { 84 + struct inet6_ifaddr *ifa = ptr; 85 + struct netdev_notifier_info info; 86 + 87 + netdev_notifier_info_init(&info, ifa->idev->dev); 88 + return masq_device_event(this, event, &info); 89 + } 90 + 91 + static struct notifier_block masq_inet_notifier = { 92 + .notifier_call = masq_inet_event, 93 + }; 94 + 95 + static atomic_t masquerade_notifier_refcount = ATOMIC_INIT(0); 96 + 97 + void nf_nat_masquerade_ipv6_register_notifier(void) 98 + { 99 + /* check if the notifier is already set */ 100 + if (atomic_inc_return(&masquerade_notifier_refcount) > 1) 101 + return; 102 + 103 + register_netdevice_notifier(&masq_dev_notifier); 104 + register_inet6addr_notifier(&masq_inet_notifier); 105 + } 106 + EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_register_notifier); 107 + 108 + void nf_nat_masquerade_ipv6_unregister_notifier(void) 109 + { 110 + /* check if the notifier still has clients */ 111 + if (atomic_dec_return(&masquerade_notifier_refcount) > 0) 112 + return; 113 + 114 + unregister_inet6addr_notifier(&masq_inet_notifier); 115 + unregister_netdevice_notifier(&masq_dev_notifier); 116 + } 117 + EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_unregister_notifier); 118 + 119 + MODULE_LICENSE("GPL"); 120 + MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+37 -128
net/ipv6/netfilter/nft_chain_nat_ipv6.c
··· 24 24 #include <net/netfilter/nf_nat_l3proto.h> 25 25 #include <net/ipv6.h> 26 26 27 - /* 28 - * IPv6 NAT chains 29 - */ 30 - 31 - static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, 32 - struct sk_buff *skb, 33 - const struct net_device *in, 34 - const struct net_device *out, 35 - int (*okfn)(struct sk_buff *)) 27 + static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops, 28 + struct sk_buff *skb, 29 + const struct net_device *in, 30 + const struct net_device *out, 31 + struct nf_conn *ct) 36 32 { 37 - enum ip_conntrack_info ctinfo; 38 - struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 39 - struct nf_conn_nat *nat; 40 - enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); 41 - __be16 frag_off; 42 - int hdrlen; 43 - u8 nexthdr; 44 33 struct nft_pktinfo pkt; 45 - unsigned int ret; 46 34 47 - if (ct == NULL || nf_ct_is_untracked(ct)) 48 - return NF_ACCEPT; 35 + nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); 49 36 50 - nat = nf_ct_nat_ext_add(ct); 51 - if (nat == NULL) 52 - return NF_ACCEPT; 53 - 54 - switch (ctinfo) { 55 - case IP_CT_RELATED: 56 - case IP_CT_RELATED + IP_CT_IS_REPLY: 57 - nexthdr = ipv6_hdr(skb)->nexthdr; 58 - hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), 59 - &nexthdr, &frag_off); 60 - 61 - if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { 62 - if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, 63 - ops->hooknum, 64 - hdrlen)) 65 - return NF_DROP; 66 - else 67 - return NF_ACCEPT; 68 - } 69 - /* Fall through */ 70 - case IP_CT_NEW: 71 - if (nf_nat_initialized(ct, maniptype)) 72 - break; 73 - 74 - nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); 75 - 76 - ret = nft_do_chain(&pkt, ops); 77 - if (ret != NF_ACCEPT) 78 - return ret; 79 - if (!nf_nat_initialized(ct, maniptype)) { 80 - ret = nf_nat_alloc_null_binding(ct, ops->hooknum); 81 - if (ret != NF_ACCEPT) 82 - return ret; 83 - } 84 - default: 85 - break; 86 - } 87 - 88 - return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); 37 + return nft_do_chain(&pkt, ops); 89 38 } 90 39 91 - static unsigned int nf_nat_ipv6_prerouting(const struct nf_hook_ops *ops, 92 - struct sk_buff *skb, 93 - const struct net_device *in, 94 - const struct net_device *out, 95 - int (*okfn)(struct sk_buff *)) 40 + static unsigned int nft_nat_ipv6_fn(const struct nf_hook_ops *ops, 41 + struct sk_buff *skb, 42 + const struct net_device *in, 43 + const struct net_device *out, 44 + int (*okfn)(struct sk_buff *)) 96 45 { 97 - struct in6_addr daddr = ipv6_hdr(skb)->daddr; 98 - unsigned int ret; 99 - 100 - ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); 101 - if (ret != NF_DROP && ret != NF_STOLEN && 102 - ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) 103 - skb_dst_drop(skb); 104 - 105 - return ret; 46 + return nf_nat_ipv6_fn(ops, skb, in, out, nft_nat_do_chain); 106 47 } 107 48 108 - static unsigned int nf_nat_ipv6_postrouting(const struct nf_hook_ops *ops, 109 - struct sk_buff *skb, 110 - const struct net_device *in, 111 - const struct net_device *out, 112 - int (*okfn)(struct sk_buff *)) 49 + static unsigned int nft_nat_ipv6_in(const struct nf_hook_ops *ops, 50 + struct sk_buff *skb, 51 + const struct net_device *in, 52 + const struct net_device *out, 53 + int (*okfn)(struct sk_buff *)) 113 54 { 114 - enum ip_conntrack_info ctinfo __maybe_unused; 115 - const struct nf_conn *ct __maybe_unused; 116 - unsigned int ret; 117 - 118 - ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); 119 - #ifdef CONFIG_XFRM 120 - if (ret != NF_DROP && ret != NF_STOLEN && 121 - !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 122 - (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 123 - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 124 - 125 - if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, 126 - &ct->tuplehash[!dir].tuple.dst.u3) || 127 - (ct->tuplehash[dir].tuple.src.u.all != 128 - ct->tuplehash[!dir].tuple.dst.u.all)) 129 - if (nf_xfrm_me_harder(skb, AF_INET6) < 0) 130 - ret = NF_DROP; 131 - } 132 - #endif 133 - return ret; 55 + return nf_nat_ipv6_in(ops, skb, in, out, nft_nat_do_chain); 134 56 } 135 57 136 - static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops, 137 - struct sk_buff *skb, 138 - const struct net_device *in, 139 - const struct net_device *out, 140 - int (*okfn)(struct sk_buff *)) 58 + static unsigned int nft_nat_ipv6_out(const struct nf_hook_ops *ops, 59 + struct sk_buff *skb, 60 + const struct net_device *in, 61 + const struct net_device *out, 62 + int (*okfn)(struct sk_buff *)) 141 63 { 142 - enum ip_conntrack_info ctinfo; 143 - const struct nf_conn *ct; 144 - unsigned int ret; 64 + return nf_nat_ipv6_out(ops, skb, in, out, nft_nat_do_chain); 65 + } 145 66 146 - ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); 147 - if (ret != NF_DROP && ret != NF_STOLEN && 148 - (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 149 - enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 150 - 151 - if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, 152 - &ct->tuplehash[!dir].tuple.src.u3)) { 153 - if (ip6_route_me_harder(skb)) 154 - ret = NF_DROP; 155 - } 156 - #ifdef CONFIG_XFRM 157 - else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 158 - ct->tuplehash[dir].tuple.dst.u.all != 159 - ct->tuplehash[!dir].tuple.src.u.all) 160 - if (nf_xfrm_me_harder(skb, AF_INET6)) 161 - ret = NF_DROP; 162 - #endif 163 - } 164 - return ret; 67 + static unsigned int nft_nat_ipv6_local_fn(const struct nf_hook_ops *ops, 68 + struct sk_buff *skb, 69 + const struct net_device *in, 70 + const struct net_device *out, 71 + int (*okfn)(struct sk_buff *)) 72 + { 73 + return nf_nat_ipv6_local_fn(ops, skb, in, out, nft_nat_do_chain); 165 74 } 166 75 167 76 static const struct nf_chain_type nft_chain_nat_ipv6 = { ··· 83 174 (1 << NF_INET_LOCAL_OUT) | 84 175 (1 << NF_INET_LOCAL_IN), 85 176 .hooks = { 86 - [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, 87 - [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, 88 - [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, 89 - [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn, 177 + [NF_INET_PRE_ROUTING] = nft_nat_ipv6_in, 178 + [NF_INET_POST_ROUTING] = nft_nat_ipv6_out, 179 + [NF_INET_LOCAL_OUT] = nft_nat_ipv6_local_fn, 180 + [NF_INET_LOCAL_IN] = nft_nat_ipv6_fn, 90 181 }, 91 182 }; 92 183
+89
net/ipv6/netfilter/nft_masq_ipv6.c
··· 1 + /* 2 + * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> 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 + 9 + #include <linux/kernel.h> 10 + #include <linux/init.h> 11 + #include <linux/module.h> 12 + #include <linux/netlink.h> 13 + #include <linux/netfilter.h> 14 + #include <linux/netfilter/nf_tables.h> 15 + #include <net/netfilter/nf_tables.h> 16 + #include <net/netfilter/nf_nat.h> 17 + #include <net/netfilter/nft_masq.h> 18 + #include <net/netfilter/ipv6/nf_nat_masquerade.h> 19 + 20 + static void nft_masq_ipv6_eval(const struct nft_expr *expr, 21 + struct nft_data data[NFT_REG_MAX + 1], 22 + const struct nft_pktinfo *pkt) 23 + { 24 + struct nft_masq *priv = nft_expr_priv(expr); 25 + struct nf_nat_range range; 26 + unsigned int verdict; 27 + 28 + range.flags = priv->flags; 29 + 30 + verdict = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out); 31 + 32 + data[NFT_REG_VERDICT].verdict = verdict; 33 + } 34 + 35 + static int nft_masq_ipv6_init(const struct nft_ctx *ctx, 36 + const struct nft_expr *expr, 37 + const struct nlattr * const tb[]) 38 + { 39 + int err; 40 + 41 + err = nft_masq_init(ctx, expr, tb); 42 + if (err < 0) 43 + return err; 44 + 45 + nf_nat_masquerade_ipv6_register_notifier(); 46 + return 0; 47 + } 48 + 49 + static void nft_masq_ipv6_destroy(const struct nft_ctx *ctx, 50 + const struct nft_expr *expr) 51 + { 52 + nf_nat_masquerade_ipv6_unregister_notifier(); 53 + } 54 + 55 + static struct nft_expr_type nft_masq_ipv6_type; 56 + static const struct nft_expr_ops nft_masq_ipv6_ops = { 57 + .type = &nft_masq_ipv6_type, 58 + .size = NFT_EXPR_SIZE(sizeof(struct nft_masq)), 59 + .eval = nft_masq_ipv6_eval, 60 + .init = nft_masq_ipv6_init, 61 + .destroy = nft_masq_ipv6_destroy, 62 + .dump = nft_masq_dump, 63 + }; 64 + 65 + static struct nft_expr_type nft_masq_ipv6_type __read_mostly = { 66 + .family = NFPROTO_IPV6, 67 + .name = "masq", 68 + .ops = &nft_masq_ipv6_ops, 69 + .policy = nft_masq_policy, 70 + .maxattr = NFTA_MASQ_MAX, 71 + .owner = THIS_MODULE, 72 + }; 73 + 74 + static int __init nft_masq_ipv6_module_init(void) 75 + { 76 + return nft_register_expr(&nft_masq_ipv6_type); 77 + } 78 + 79 + static void __exit nft_masq_ipv6_module_exit(void) 80 + { 81 + nft_unregister_expr(&nft_masq_ipv6_type); 82 + } 83 + 84 + module_init(nft_masq_ipv6_module_init); 85 + module_exit(nft_masq_ipv6_module_exit); 86 + 87 + MODULE_LICENSE("GPL"); 88 + MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>"); 89 + MODULE_ALIAS_NFT_AF_EXPR(AF_INET6, "masq");
+9
net/netfilter/Kconfig
··· 496 496 This option adds the "limit" expression that you can use to 497 497 ratelimit rule matchings. 498 498 499 + config NFT_MASQ 500 + depends on NF_TABLES 501 + depends on NF_CONNTRACK 502 + depends on NF_NAT 503 + tristate "Netfilter nf_tables masquerade support" 504 + help 505 + This option adds the "masquerade" expression that you can use 506 + to perform NAT in the masquerade flavour. 507 + 499 508 config NFT_NAT 500 509 depends on NF_TABLES 501 510 depends on NF_CONNTRACK
+1
net/netfilter/Makefile
··· 87 87 obj-$(CONFIG_NFT_HASH) += nft_hash.o 88 88 obj-$(CONFIG_NFT_COUNTER) += nft_counter.o 89 89 obj-$(CONFIG_NFT_LOG) += nft_log.o 90 + obj-$(CONFIG_NFT_MASQ) += nft_masq.o 90 91 91 92 # generic X tables 92 93 obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
+2 -2
net/netfilter/ipset/ip_set_bitmap_ip.c
··· 112 112 { 113 113 struct bitmap_ip *map = set->data; 114 114 ipset_adtfn adtfn = set->variant->adt[adt]; 115 - struct bitmap_ip_adt_elem e = { }; 115 + struct bitmap_ip_adt_elem e = { .id = 0 }; 116 116 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 117 117 u32 ip; 118 118 ··· 132 132 struct bitmap_ip *map = set->data; 133 133 ipset_adtfn adtfn = set->variant->adt[adt]; 134 134 u32 ip = 0, ip_to = 0; 135 - struct bitmap_ip_adt_elem e = { }; 135 + struct bitmap_ip_adt_elem e = { .id = 0 }; 136 136 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 137 137 int ret = 0; 138 138
+2 -2
net/netfilter/ipset/ip_set_bitmap_ipmac.c
··· 203 203 { 204 204 struct bitmap_ipmac *map = set->data; 205 205 ipset_adtfn adtfn = set->variant->adt[adt]; 206 - struct bitmap_ipmac_adt_elem e = {}; 206 + struct bitmap_ipmac_adt_elem e = { .id = 0 }; 207 207 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 208 208 u32 ip; 209 209 ··· 232 232 { 233 233 const struct bitmap_ipmac *map = set->data; 234 234 ipset_adtfn adtfn = set->variant->adt[adt]; 235 - struct bitmap_ipmac_adt_elem e = {}; 235 + struct bitmap_ipmac_adt_elem e = { .id = 0 }; 236 236 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 237 237 u32 ip = 0; 238 238 int ret = 0;
+2 -2
net/netfilter/ipset/ip_set_bitmap_port.c
··· 104 104 { 105 105 struct bitmap_port *map = set->data; 106 106 ipset_adtfn adtfn = set->variant->adt[adt]; 107 - struct bitmap_port_adt_elem e = {}; 107 + struct bitmap_port_adt_elem e = { .id = 0 }; 108 108 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 109 109 __be16 __port; 110 110 u16 port = 0; ··· 129 129 { 130 130 struct bitmap_port *map = set->data; 131 131 ipset_adtfn adtfn = set->variant->adt[adt]; 132 - struct bitmap_port_adt_elem e = {}; 132 + struct bitmap_port_adt_elem e = { .id = 0 }; 133 133 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 134 134 u32 port; /* wraparound */ 135 135 u16 port_to;
+1 -1
net/netfilter/ipset/ip_set_hash_gen.h
··· 1093 1093 if (tb[IPSET_ATTR_MARKMASK]) { 1094 1094 markmask = ntohl(nla_get_u32(tb[IPSET_ATTR_MARKMASK])); 1095 1095 1096 - if ((markmask > 4294967295u) || markmask == 0) 1096 + if (markmask == 0) 1097 1097 return -IPSET_ERR_INVALID_MARKMASK; 1098 1098 } 1099 1099 #endif
+4 -4
net/netfilter/ipset/ip_set_hash_ip.c
··· 84 84 { 85 85 const struct hash_ip *h = set->data; 86 86 ipset_adtfn adtfn = set->variant->adt[adt]; 87 - struct hash_ip4_elem e = {}; 87 + struct hash_ip4_elem e = { 0 }; 88 88 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 89 89 __be32 ip; 90 90 ··· 103 103 { 104 104 const struct hash_ip *h = set->data; 105 105 ipset_adtfn adtfn = set->variant->adt[adt]; 106 - struct hash_ip4_elem e = {}; 106 + struct hash_ip4_elem e = { 0 }; 107 107 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 108 108 u32 ip = 0, ip_to = 0, hosts; 109 109 int ret = 0; ··· 222 222 { 223 223 const struct hash_ip *h = set->data; 224 224 ipset_adtfn adtfn = set->variant->adt[adt]; 225 - struct hash_ip6_elem e = {}; 225 + struct hash_ip6_elem e = { { .all = { 0 } } }; 226 226 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 227 227 228 228 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); ··· 239 239 { 240 240 const struct hash_ip *h = set->data; 241 241 ipset_adtfn adtfn = set->variant->adt[adt]; 242 - struct hash_ip6_elem e = {}; 242 + struct hash_ip6_elem e = { { .all = { 0 } } }; 243 243 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 244 244 int ret; 245 245
+4 -4
net/netfilter/ipset/ip_set_hash_ipport.c
··· 94 94 enum ipset_adt adt, struct ip_set_adt_opt *opt) 95 95 { 96 96 ipset_adtfn adtfn = set->variant->adt[adt]; 97 - struct hash_ipport4_elem e = { }; 97 + struct hash_ipport4_elem e = { .ip = 0 }; 98 98 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 99 99 100 100 if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, ··· 111 111 { 112 112 const struct hash_ipport *h = set->data; 113 113 ipset_adtfn adtfn = set->variant->adt[adt]; 114 - struct hash_ipport4_elem e = { }; 114 + struct hash_ipport4_elem e = { .ip = 0 }; 115 115 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 116 116 u32 ip, ip_to = 0, p = 0, port, port_to; 117 117 bool with_ports = false; ··· 258 258 enum ipset_adt adt, struct ip_set_adt_opt *opt) 259 259 { 260 260 ipset_adtfn adtfn = set->variant->adt[adt]; 261 - struct hash_ipport6_elem e = { }; 261 + struct hash_ipport6_elem e = { .ip = { .all = { 0 } } }; 262 262 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 263 263 264 264 if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, ··· 275 275 { 276 276 const struct hash_ipport *h = set->data; 277 277 ipset_adtfn adtfn = set->variant->adt[adt]; 278 - struct hash_ipport6_elem e = { }; 278 + struct hash_ipport6_elem e = { .ip = { .all = { 0 } } }; 279 279 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 280 280 u32 port, port_to; 281 281 bool with_ports = false;
+4 -4
net/netfilter/ipset/ip_set_hash_ipportip.c
··· 95 95 enum ipset_adt adt, struct ip_set_adt_opt *opt) 96 96 { 97 97 ipset_adtfn adtfn = set->variant->adt[adt]; 98 - struct hash_ipportip4_elem e = { }; 98 + struct hash_ipportip4_elem e = { .ip = 0 }; 99 99 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 100 100 101 101 if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, ··· 113 113 { 114 114 const struct hash_ipportip *h = set->data; 115 115 ipset_adtfn adtfn = set->variant->adt[adt]; 116 - struct hash_ipportip4_elem e = { }; 116 + struct hash_ipportip4_elem e = { .ip = 0 }; 117 117 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 118 118 u32 ip, ip_to = 0, p = 0, port, port_to; 119 119 bool with_ports = false; ··· 265 265 enum ipset_adt adt, struct ip_set_adt_opt *opt) 266 266 { 267 267 ipset_adtfn adtfn = set->variant->adt[adt]; 268 - struct hash_ipportip6_elem e = { }; 268 + struct hash_ipportip6_elem e = { .ip = { .all = { 0 } } }; 269 269 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 270 270 271 271 if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, ··· 283 283 { 284 284 const struct hash_ipportip *h = set->data; 285 285 ipset_adtfn adtfn = set->variant->adt[adt]; 286 - struct hash_ipportip6_elem e = { }; 286 + struct hash_ipportip6_elem e = { .ip = { .all = { 0 } } }; 287 287 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 288 288 u32 port, port_to; 289 289 bool with_ports = false;
+7 -6
net/netfilter/ipset/ip_set_hash_netnet.c
··· 203 203 flags |= (IPSET_FLAG_NOMATCH << 16); 204 204 } 205 205 206 - if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] && 206 + if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] || 207 207 tb[IPSET_ATTR_IP2_TO])) { 208 208 e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0])); 209 209 e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1])); ··· 219 219 return ret; 220 220 if (ip_to < ip) 221 221 swap(ip, ip_to); 222 - if (ip + UINT_MAX == ip_to) 222 + if (unlikely(ip + UINT_MAX == ip_to)) 223 223 return -IPSET_ERR_HASH_RANGE; 224 - } 224 + } else 225 + ip_set_mask_from_to(ip, ip_to, e.cidr[0]); 225 226 226 227 ip2_to = ip2_from; 227 228 if (tb[IPSET_ATTR_IP2_TO]) { ··· 231 230 return ret; 232 231 if (ip2_to < ip2_from) 233 232 swap(ip2_from, ip2_to); 234 - if (ip2_from + UINT_MAX == ip2_to) 233 + if (unlikely(ip2_from + UINT_MAX == ip2_to)) 235 234 return -IPSET_ERR_HASH_RANGE; 236 - 237 - } 235 + } else 236 + ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); 238 237 239 238 if (retried) 240 239 ip = ntohl(h->next.ip[0]);
+4 -2
net/netfilter/ipset/ip_set_hash_netportnet.c
··· 257 257 swap(ip, ip_to); 258 258 if (unlikely(ip + UINT_MAX == ip_to)) 259 259 return -IPSET_ERR_HASH_RANGE; 260 - } 260 + } else 261 + ip_set_mask_from_to(ip, ip_to, e.cidr[0]); 261 262 262 263 port_to = port = ntohs(e.port); 263 264 if (tb[IPSET_ATTR_PORT_TO]) { ··· 276 275 swap(ip2_from, ip2_to); 277 276 if (unlikely(ip2_from + UINT_MAX == ip2_to)) 278 277 return -IPSET_ERR_HASH_RANGE; 279 - } 278 + } else 279 + ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); 280 280 281 281 if (retried) 282 282 ip = ntohl(h->next.ip[0]);
+3 -1
net/netfilter/ipset/ip_set_list_set.c
··· 597 597 struct set_elem *e; 598 598 u32 i; 599 599 600 - map = kzalloc(sizeof(*map) + size * set->dsize, GFP_KERNEL); 600 + map = kzalloc(sizeof(*map) + 601 + min_t(u32, size, IP_SET_LIST_MAX_SIZE) * set->dsize, 602 + GFP_KERNEL); 601 603 if (!map) 602 604 return false; 603 605
+62 -51
net/netfilter/ipvs/ip_vs_ctl.c
··· 2179 2179 return 0; 2180 2180 } 2181 2181 2182 + #define CMDID(cmd) (cmd - IP_VS_BASE_CTL) 2182 2183 2183 - #define SET_CMDID(cmd) (cmd - IP_VS_BASE_CTL) 2184 - #define SERVICE_ARG_LEN (sizeof(struct ip_vs_service_user)) 2185 - #define SVCDEST_ARG_LEN (sizeof(struct ip_vs_service_user) + \ 2186 - sizeof(struct ip_vs_dest_user)) 2187 - #define TIMEOUT_ARG_LEN (sizeof(struct ip_vs_timeout_user)) 2188 - #define DAEMON_ARG_LEN (sizeof(struct ip_vs_daemon_user)) 2189 - #define MAX_ARG_LEN SVCDEST_ARG_LEN 2190 - 2191 - static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = { 2192 - [SET_CMDID(IP_VS_SO_SET_ADD)] = SERVICE_ARG_LEN, 2193 - [SET_CMDID(IP_VS_SO_SET_EDIT)] = SERVICE_ARG_LEN, 2194 - [SET_CMDID(IP_VS_SO_SET_DEL)] = SERVICE_ARG_LEN, 2195 - [SET_CMDID(IP_VS_SO_SET_FLUSH)] = 0, 2196 - [SET_CMDID(IP_VS_SO_SET_ADDDEST)] = SVCDEST_ARG_LEN, 2197 - [SET_CMDID(IP_VS_SO_SET_DELDEST)] = SVCDEST_ARG_LEN, 2198 - [SET_CMDID(IP_VS_SO_SET_EDITDEST)] = SVCDEST_ARG_LEN, 2199 - [SET_CMDID(IP_VS_SO_SET_TIMEOUT)] = TIMEOUT_ARG_LEN, 2200 - [SET_CMDID(IP_VS_SO_SET_STARTDAEMON)] = DAEMON_ARG_LEN, 2201 - [SET_CMDID(IP_VS_SO_SET_STOPDAEMON)] = DAEMON_ARG_LEN, 2202 - [SET_CMDID(IP_VS_SO_SET_ZERO)] = SERVICE_ARG_LEN, 2184 + struct ip_vs_svcdest_user { 2185 + struct ip_vs_service_user s; 2186 + struct ip_vs_dest_user d; 2203 2187 }; 2188 + 2189 + static const unsigned char set_arglen[CMDID(IP_VS_SO_SET_MAX) + 1] = { 2190 + [CMDID(IP_VS_SO_SET_ADD)] = sizeof(struct ip_vs_service_user), 2191 + [CMDID(IP_VS_SO_SET_EDIT)] = sizeof(struct ip_vs_service_user), 2192 + [CMDID(IP_VS_SO_SET_DEL)] = sizeof(struct ip_vs_service_user), 2193 + [CMDID(IP_VS_SO_SET_ADDDEST)] = sizeof(struct ip_vs_svcdest_user), 2194 + [CMDID(IP_VS_SO_SET_DELDEST)] = sizeof(struct ip_vs_svcdest_user), 2195 + [CMDID(IP_VS_SO_SET_EDITDEST)] = sizeof(struct ip_vs_svcdest_user), 2196 + [CMDID(IP_VS_SO_SET_TIMEOUT)] = sizeof(struct ip_vs_timeout_user), 2197 + [CMDID(IP_VS_SO_SET_STARTDAEMON)] = sizeof(struct ip_vs_daemon_user), 2198 + [CMDID(IP_VS_SO_SET_STOPDAEMON)] = sizeof(struct ip_vs_daemon_user), 2199 + [CMDID(IP_VS_SO_SET_ZERO)] = sizeof(struct ip_vs_service_user), 2200 + }; 2201 + 2202 + union ip_vs_set_arglen { 2203 + struct ip_vs_service_user field_IP_VS_SO_SET_ADD; 2204 + struct ip_vs_service_user field_IP_VS_SO_SET_EDIT; 2205 + struct ip_vs_service_user field_IP_VS_SO_SET_DEL; 2206 + struct ip_vs_svcdest_user field_IP_VS_SO_SET_ADDDEST; 2207 + struct ip_vs_svcdest_user field_IP_VS_SO_SET_DELDEST; 2208 + struct ip_vs_svcdest_user field_IP_VS_SO_SET_EDITDEST; 2209 + struct ip_vs_timeout_user field_IP_VS_SO_SET_TIMEOUT; 2210 + struct ip_vs_daemon_user field_IP_VS_SO_SET_STARTDAEMON; 2211 + struct ip_vs_daemon_user field_IP_VS_SO_SET_STOPDAEMON; 2212 + struct ip_vs_service_user field_IP_VS_SO_SET_ZERO; 2213 + }; 2214 + 2215 + #define MAX_SET_ARGLEN sizeof(union ip_vs_set_arglen) 2204 2216 2205 2217 static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc, 2206 2218 struct ip_vs_service_user *usvc_compat) ··· 2251 2239 { 2252 2240 struct net *net = sock_net(sk); 2253 2241 int ret; 2254 - unsigned char arg[MAX_ARG_LEN]; 2242 + unsigned char arg[MAX_SET_ARGLEN]; 2255 2243 struct ip_vs_service_user *usvc_compat; 2256 2244 struct ip_vs_service_user_kern usvc; 2257 2245 struct ip_vs_service *svc; ··· 2259 2247 struct ip_vs_dest_user_kern udest; 2260 2248 struct netns_ipvs *ipvs = net_ipvs(net); 2261 2249 2250 + BUILD_BUG_ON(sizeof(arg) > 255); 2262 2251 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 2263 2252 return -EPERM; 2264 2253 2265 2254 if (cmd < IP_VS_BASE_CTL || cmd > IP_VS_SO_SET_MAX) 2266 2255 return -EINVAL; 2267 - if (len < 0 || len > MAX_ARG_LEN) 2268 - return -EINVAL; 2269 - if (len != set_arglen[SET_CMDID(cmd)]) { 2270 - pr_err("set_ctl: len %u != %u\n", 2271 - len, set_arglen[SET_CMDID(cmd)]); 2256 + if (len != set_arglen[CMDID(cmd)]) { 2257 + IP_VS_DBG(1, "set_ctl: len %u != %u\n", 2258 + len, set_arglen[CMDID(cmd)]); 2272 2259 return -EINVAL; 2273 2260 } 2274 2261 ··· 2523 2512 #endif 2524 2513 } 2525 2514 2526 - 2527 - #define GET_CMDID(cmd) (cmd - IP_VS_BASE_CTL) 2528 - #define GET_INFO_ARG_LEN (sizeof(struct ip_vs_getinfo)) 2529 - #define GET_SERVICES_ARG_LEN (sizeof(struct ip_vs_get_services)) 2530 - #define GET_SERVICE_ARG_LEN (sizeof(struct ip_vs_service_entry)) 2531 - #define GET_DESTS_ARG_LEN (sizeof(struct ip_vs_get_dests)) 2532 - #define GET_TIMEOUT_ARG_LEN (sizeof(struct ip_vs_timeout_user)) 2533 - #define GET_DAEMON_ARG_LEN (sizeof(struct ip_vs_daemon_user) * 2) 2534 - 2535 - static const unsigned char get_arglen[GET_CMDID(IP_VS_SO_GET_MAX)+1] = { 2536 - [GET_CMDID(IP_VS_SO_GET_VERSION)] = 64, 2537 - [GET_CMDID(IP_VS_SO_GET_INFO)] = GET_INFO_ARG_LEN, 2538 - [GET_CMDID(IP_VS_SO_GET_SERVICES)] = GET_SERVICES_ARG_LEN, 2539 - [GET_CMDID(IP_VS_SO_GET_SERVICE)] = GET_SERVICE_ARG_LEN, 2540 - [GET_CMDID(IP_VS_SO_GET_DESTS)] = GET_DESTS_ARG_LEN, 2541 - [GET_CMDID(IP_VS_SO_GET_TIMEOUT)] = GET_TIMEOUT_ARG_LEN, 2542 - [GET_CMDID(IP_VS_SO_GET_DAEMON)] = GET_DAEMON_ARG_LEN, 2515 + static const unsigned char get_arglen[CMDID(IP_VS_SO_GET_MAX) + 1] = { 2516 + [CMDID(IP_VS_SO_GET_VERSION)] = 64, 2517 + [CMDID(IP_VS_SO_GET_INFO)] = sizeof(struct ip_vs_getinfo), 2518 + [CMDID(IP_VS_SO_GET_SERVICES)] = sizeof(struct ip_vs_get_services), 2519 + [CMDID(IP_VS_SO_GET_SERVICE)] = sizeof(struct ip_vs_service_entry), 2520 + [CMDID(IP_VS_SO_GET_DESTS)] = sizeof(struct ip_vs_get_dests), 2521 + [CMDID(IP_VS_SO_GET_TIMEOUT)] = sizeof(struct ip_vs_timeout_user), 2522 + [CMDID(IP_VS_SO_GET_DAEMON)] = 2 * sizeof(struct ip_vs_daemon_user), 2543 2523 }; 2524 + 2525 + union ip_vs_get_arglen { 2526 + char field_IP_VS_SO_GET_VERSION[64]; 2527 + struct ip_vs_getinfo field_IP_VS_SO_GET_INFO; 2528 + struct ip_vs_get_services field_IP_VS_SO_GET_SERVICES; 2529 + struct ip_vs_service_entry field_IP_VS_SO_GET_SERVICE; 2530 + struct ip_vs_get_dests field_IP_VS_SO_GET_DESTS; 2531 + struct ip_vs_timeout_user field_IP_VS_SO_GET_TIMEOUT; 2532 + struct ip_vs_daemon_user field_IP_VS_SO_GET_DAEMON[2]; 2533 + }; 2534 + 2535 + #define MAX_GET_ARGLEN sizeof(union ip_vs_get_arglen) 2544 2536 2545 2537 static int 2546 2538 do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) 2547 2539 { 2548 - unsigned char arg[128]; 2540 + unsigned char arg[MAX_GET_ARGLEN]; 2549 2541 int ret = 0; 2550 2542 unsigned int copylen; 2551 2543 struct net *net = sock_net(sk); 2552 2544 struct netns_ipvs *ipvs = net_ipvs(net); 2553 2545 2554 2546 BUG_ON(!net); 2547 + BUILD_BUG_ON(sizeof(arg) > 255); 2555 2548 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 2556 2549 return -EPERM; 2557 2550 2558 2551 if (cmd < IP_VS_BASE_CTL || cmd > IP_VS_SO_GET_MAX) 2559 2552 return -EINVAL; 2560 2553 2561 - if (*len < get_arglen[GET_CMDID(cmd)]) { 2562 - pr_err("get_ctl: len %u < %u\n", 2563 - *len, get_arglen[GET_CMDID(cmd)]); 2554 + copylen = get_arglen[CMDID(cmd)]; 2555 + if (*len < (int) copylen) { 2556 + IP_VS_DBG(1, "get_ctl: len %d < %u\n", *len, copylen); 2564 2557 return -EINVAL; 2565 2558 } 2566 - 2567 - copylen = get_arglen[GET_CMDID(cmd)]; 2568 - if (copylen > 128) 2569 - return -EINVAL; 2570 2559 2571 2560 if (copy_from_user(arg, user, copylen) != 0) 2572 2561 return -EFAULT;
+280 -174
net/netfilter/nf_tables_api.c
··· 127 127 kfree(trans); 128 128 } 129 129 130 + static void nf_tables_unregister_hooks(const struct nft_table *table, 131 + const struct nft_chain *chain, 132 + unsigned int hook_nops) 133 + { 134 + if (!(table->flags & NFT_TABLE_F_DORMANT) && 135 + chain->flags & NFT_BASE_CHAIN) 136 + nf_unregister_hooks(nft_base_chain(chain)->ops, hook_nops); 137 + } 138 + 139 + /* Internal table flags */ 140 + #define NFT_TABLE_INACTIVE (1 << 15) 141 + 142 + static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type) 143 + { 144 + struct nft_trans *trans; 145 + 146 + trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_table)); 147 + if (trans == NULL) 148 + return -ENOMEM; 149 + 150 + if (msg_type == NFT_MSG_NEWTABLE) 151 + ctx->table->flags |= NFT_TABLE_INACTIVE; 152 + 153 + list_add_tail(&trans->list, &ctx->net->nft.commit_list); 154 + return 0; 155 + } 156 + 157 + static int nft_deltable(struct nft_ctx *ctx) 158 + { 159 + int err; 160 + 161 + err = nft_trans_table_add(ctx, NFT_MSG_DELTABLE); 162 + if (err < 0) 163 + return err; 164 + 165 + list_del_rcu(&ctx->table->list); 166 + return err; 167 + } 168 + 169 + static int nft_trans_chain_add(struct nft_ctx *ctx, int msg_type) 170 + { 171 + struct nft_trans *trans; 172 + 173 + trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_chain)); 174 + if (trans == NULL) 175 + return -ENOMEM; 176 + 177 + if (msg_type == NFT_MSG_NEWCHAIN) 178 + ctx->chain->flags |= NFT_CHAIN_INACTIVE; 179 + 180 + list_add_tail(&trans->list, &ctx->net->nft.commit_list); 181 + return 0; 182 + } 183 + 184 + static int nft_delchain(struct nft_ctx *ctx) 185 + { 186 + int err; 187 + 188 + err = nft_trans_chain_add(ctx, NFT_MSG_DELCHAIN); 189 + if (err < 0) 190 + return err; 191 + 192 + ctx->table->use--; 193 + list_del_rcu(&ctx->chain->list); 194 + 195 + return err; 196 + } 197 + 198 + static inline bool 199 + nft_rule_is_active(struct net *net, const struct nft_rule *rule) 200 + { 201 + return (rule->genmask & (1 << net->nft.gencursor)) == 0; 202 + } 203 + 204 + static inline int gencursor_next(struct net *net) 205 + { 206 + return net->nft.gencursor+1 == 1 ? 1 : 0; 207 + } 208 + 209 + static inline int 210 + nft_rule_is_active_next(struct net *net, const struct nft_rule *rule) 211 + { 212 + return (rule->genmask & (1 << gencursor_next(net))) == 0; 213 + } 214 + 215 + static inline void 216 + nft_rule_activate_next(struct net *net, struct nft_rule *rule) 217 + { 218 + /* Now inactive, will be active in the future */ 219 + rule->genmask = (1 << net->nft.gencursor); 220 + } 221 + 222 + static inline void 223 + nft_rule_deactivate_next(struct net *net, struct nft_rule *rule) 224 + { 225 + rule->genmask = (1 << gencursor_next(net)); 226 + } 227 + 228 + static inline void nft_rule_clear(struct net *net, struct nft_rule *rule) 229 + { 230 + rule->genmask = 0; 231 + } 232 + 233 + static int 234 + nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule) 235 + { 236 + /* You cannot delete the same rule twice */ 237 + if (nft_rule_is_active_next(ctx->net, rule)) { 238 + nft_rule_deactivate_next(ctx->net, rule); 239 + ctx->chain->use--; 240 + return 0; 241 + } 242 + return -ENOENT; 243 + } 244 + 245 + static struct nft_trans *nft_trans_rule_add(struct nft_ctx *ctx, int msg_type, 246 + struct nft_rule *rule) 247 + { 248 + struct nft_trans *trans; 249 + 250 + trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_rule)); 251 + if (trans == NULL) 252 + return NULL; 253 + 254 + nft_trans_rule(trans) = rule; 255 + list_add_tail(&trans->list, &ctx->net->nft.commit_list); 256 + 257 + return trans; 258 + } 259 + 260 + static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule) 261 + { 262 + struct nft_trans *trans; 263 + int err; 264 + 265 + trans = nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule); 266 + if (trans == NULL) 267 + return -ENOMEM; 268 + 269 + err = nf_tables_delrule_deactivate(ctx, rule); 270 + if (err < 0) { 271 + nft_trans_destroy(trans); 272 + return err; 273 + } 274 + 275 + return 0; 276 + } 277 + 278 + static int nft_delrule_by_chain(struct nft_ctx *ctx) 279 + { 280 + struct nft_rule *rule; 281 + int err; 282 + 283 + list_for_each_entry(rule, &ctx->chain->rules, list) { 284 + err = nft_delrule(ctx, rule); 285 + if (err < 0) 286 + return err; 287 + } 288 + return 0; 289 + } 290 + 291 + /* Internal set flag */ 292 + #define NFT_SET_INACTIVE (1 << 15) 293 + 294 + static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type, 295 + struct nft_set *set) 296 + { 297 + struct nft_trans *trans; 298 + 299 + trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_set)); 300 + if (trans == NULL) 301 + return -ENOMEM; 302 + 303 + if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) { 304 + nft_trans_set_id(trans) = 305 + ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID])); 306 + set->flags |= NFT_SET_INACTIVE; 307 + } 308 + nft_trans_set(trans) = set; 309 + list_add_tail(&trans->list, &ctx->net->nft.commit_list); 310 + 311 + return 0; 312 + } 313 + 314 + static int nft_delset(struct nft_ctx *ctx, struct nft_set *set) 315 + { 316 + int err; 317 + 318 + err = nft_trans_set_add(ctx, NFT_MSG_DELSET, set); 319 + if (err < 0) 320 + return err; 321 + 322 + list_del_rcu(&set->list); 323 + ctx->table->use--; 324 + 325 + return err; 326 + } 327 + 130 328 /* 131 329 * Tables 132 330 */ ··· 507 309 return skb->len; 508 310 } 509 311 510 - /* Internal table flags */ 511 - #define NFT_TABLE_INACTIVE (1 << 15) 512 - 513 312 static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb, 514 313 const struct nlmsghdr *nlh, 515 314 const struct nlattr * const nla[]) ··· 638 443 return ret; 639 444 } 640 445 641 - static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type) 642 - { 643 - struct nft_trans *trans; 644 - 645 - trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_table)); 646 - if (trans == NULL) 647 - return -ENOMEM; 648 - 649 - if (msg_type == NFT_MSG_NEWTABLE) 650 - ctx->table->flags |= NFT_TABLE_INACTIVE; 651 - 652 - list_add_tail(&trans->list, &ctx->net->nft.commit_list); 653 - return 0; 654 - } 655 - 656 446 static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, 657 447 const struct nlmsghdr *nlh, 658 448 const struct nlattr * const nla[]) ··· 707 527 return 0; 708 528 } 709 529 530 + static int nft_flush_table(struct nft_ctx *ctx) 531 + { 532 + int err; 533 + struct nft_chain *chain, *nc; 534 + struct nft_set *set, *ns; 535 + 536 + list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) { 537 + ctx->chain = chain; 538 + 539 + err = nft_delrule_by_chain(ctx); 540 + if (err < 0) 541 + goto out; 542 + 543 + err = nft_delchain(ctx); 544 + if (err < 0) 545 + goto out; 546 + } 547 + 548 + list_for_each_entry_safe(set, ns, &ctx->table->sets, list) { 549 + if (set->flags & NFT_SET_ANONYMOUS && 550 + !list_empty(&set->bindings)) 551 + continue; 552 + 553 + err = nft_delset(ctx, set); 554 + if (err < 0) 555 + goto out; 556 + } 557 + 558 + err = nft_deltable(ctx); 559 + out: 560 + return err; 561 + } 562 + 563 + static int nft_flush(struct nft_ctx *ctx, int family) 564 + { 565 + struct nft_af_info *afi; 566 + struct nft_table *table, *nt; 567 + const struct nlattr * const *nla = ctx->nla; 568 + int err = 0; 569 + 570 + list_for_each_entry(afi, &ctx->net->nft.af_info, list) { 571 + if (family != AF_UNSPEC && afi->family != family) 572 + continue; 573 + 574 + ctx->afi = afi; 575 + list_for_each_entry_safe(table, nt, &afi->tables, list) { 576 + if (nla[NFTA_TABLE_NAME] && 577 + nla_strcmp(nla[NFTA_TABLE_NAME], table->name) != 0) 578 + continue; 579 + 580 + ctx->table = table; 581 + 582 + err = nft_flush_table(ctx); 583 + if (err < 0) 584 + goto out; 585 + } 586 + } 587 + out: 588 + return err; 589 + } 590 + 710 591 static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb, 711 592 const struct nlmsghdr *nlh, 712 593 const struct nlattr * const nla[]) ··· 776 535 struct nft_af_info *afi; 777 536 struct nft_table *table; 778 537 struct net *net = sock_net(skb->sk); 779 - int family = nfmsg->nfgen_family, err; 538 + int family = nfmsg->nfgen_family; 780 539 struct nft_ctx ctx; 540 + 541 + nft_ctx_init(&ctx, skb, nlh, NULL, NULL, NULL, nla); 542 + if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL) 543 + return nft_flush(&ctx, family); 781 544 782 545 afi = nf_tables_afinfo_lookup(net, family, false); 783 546 if (IS_ERR(afi)) ··· 792 547 return PTR_ERR(table); 793 548 if (table->flags & NFT_TABLE_INACTIVE) 794 549 return -ENOENT; 795 - if (table->use > 0) 796 - return -EBUSY; 797 550 798 - nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla); 799 - err = nft_trans_table_add(&ctx, NFT_MSG_DELTABLE); 800 - if (err < 0) 801 - return err; 551 + ctx.afi = afi; 552 + ctx.table = table; 802 553 803 - list_del_rcu(&table->list); 804 - return 0; 554 + return nft_flush_table(&ctx); 805 555 } 806 556 807 557 static void nf_tables_table_destroy(struct nft_ctx *ctx) ··· 1153 913 rcu_assign_pointer(chain->stats, newstats); 1154 914 } 1155 915 1156 - static int nft_trans_chain_add(struct nft_ctx *ctx, int msg_type) 1157 - { 1158 - struct nft_trans *trans; 1159 - 1160 - trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_chain)); 1161 - if (trans == NULL) 1162 - return -ENOMEM; 1163 - 1164 - if (msg_type == NFT_MSG_NEWCHAIN) 1165 - ctx->chain->flags |= NFT_CHAIN_INACTIVE; 1166 - 1167 - list_add_tail(&trans->list, &ctx->net->nft.commit_list); 1168 - return 0; 1169 - } 1170 - 1171 916 static void nf_tables_chain_destroy(struct nft_chain *chain) 1172 917 { 1173 918 BUG_ON(chain->use > 0); ··· 1382 1157 list_add_tail_rcu(&chain->list, &table->chains); 1383 1158 return 0; 1384 1159 err2: 1385 - if (!(table->flags & NFT_TABLE_F_DORMANT) && 1386 - chain->flags & NFT_BASE_CHAIN) { 1387 - nf_unregister_hooks(nft_base_chain(chain)->ops, 1388 - afi->nops); 1389 - } 1160 + nf_tables_unregister_hooks(table, chain, afi->nops); 1390 1161 err1: 1391 1162 nf_tables_chain_destroy(chain); 1392 1163 return err; ··· 1399 1178 struct net *net = sock_net(skb->sk); 1400 1179 int family = nfmsg->nfgen_family; 1401 1180 struct nft_ctx ctx; 1402 - int err; 1403 1181 1404 1182 afi = nf_tables_afinfo_lookup(net, family, false); 1405 1183 if (IS_ERR(afi)) ··· 1419 1199 return -EBUSY; 1420 1200 1421 1201 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla); 1422 - err = nft_trans_chain_add(&ctx, NFT_MSG_DELCHAIN); 1423 - if (err < 0) 1424 - return err; 1425 1202 1426 - table->use--; 1427 - list_del_rcu(&chain->list); 1428 - return 0; 1203 + return nft_delchain(&ctx); 1429 1204 } 1430 1205 1431 1206 /* ··· 1742 1527 return err; 1743 1528 } 1744 1529 1745 - static inline bool 1746 - nft_rule_is_active(struct net *net, const struct nft_rule *rule) 1747 - { 1748 - return (rule->genmask & (1 << net->nft.gencursor)) == 0; 1749 - } 1750 - 1751 - static inline int gencursor_next(struct net *net) 1752 - { 1753 - return net->nft.gencursor+1 == 1 ? 1 : 0; 1754 - } 1755 - 1756 - static inline int 1757 - nft_rule_is_active_next(struct net *net, const struct nft_rule *rule) 1758 - { 1759 - return (rule->genmask & (1 << gencursor_next(net))) == 0; 1760 - } 1761 - 1762 - static inline void 1763 - nft_rule_activate_next(struct net *net, struct nft_rule *rule) 1764 - { 1765 - /* Now inactive, will be active in the future */ 1766 - rule->genmask = (1 << net->nft.gencursor); 1767 - } 1768 - 1769 - static inline void 1770 - nft_rule_disactivate_next(struct net *net, struct nft_rule *rule) 1771 - { 1772 - rule->genmask = (1 << gencursor_next(net)); 1773 - } 1774 - 1775 - static inline void nft_rule_clear(struct net *net, struct nft_rule *rule) 1776 - { 1777 - rule->genmask = 0; 1778 - } 1779 - 1780 1530 static int nf_tables_dump_rules(struct sk_buff *skb, 1781 1531 struct netlink_callback *cb) 1782 1532 { ··· 1867 1687 kfree(rule); 1868 1688 } 1869 1689 1870 - static struct nft_trans *nft_trans_rule_add(struct nft_ctx *ctx, int msg_type, 1871 - struct nft_rule *rule) 1872 - { 1873 - struct nft_trans *trans; 1874 - 1875 - trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_rule)); 1876 - if (trans == NULL) 1877 - return NULL; 1878 - 1879 - nft_trans_rule(trans) = rule; 1880 - list_add_tail(&trans->list, &ctx->net->nft.commit_list); 1881 - 1882 - return trans; 1883 - } 1884 - 1885 1690 #define NFT_RULE_MAXEXPRS 128 1886 1691 1887 1692 static struct nft_expr_info *info; ··· 1988 1823 err = -ENOMEM; 1989 1824 goto err2; 1990 1825 } 1991 - nft_rule_disactivate_next(net, old_rule); 1826 + nft_rule_deactivate_next(net, old_rule); 1992 1827 chain->use--; 1993 1828 list_add_tail_rcu(&rule->list, &old_rule->list); 1994 1829 } else { ··· 2032 1867 return err; 2033 1868 } 2034 1869 2035 - static int 2036 - nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule) 2037 - { 2038 - /* You cannot delete the same rule twice */ 2039 - if (nft_rule_is_active_next(ctx->net, rule)) { 2040 - if (nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule) == NULL) 2041 - return -ENOMEM; 2042 - nft_rule_disactivate_next(ctx->net, rule); 2043 - ctx->chain->use--; 2044 - return 0; 2045 - } 2046 - return -ENOENT; 2047 - } 2048 - 2049 - static int nf_table_delrule_by_chain(struct nft_ctx *ctx) 2050 - { 2051 - struct nft_rule *rule; 2052 - int err; 2053 - 2054 - list_for_each_entry(rule, &ctx->chain->rules, list) { 2055 - err = nf_tables_delrule_one(ctx, rule); 2056 - if (err < 0) 2057 - return err; 2058 - } 2059 - return 0; 2060 - } 2061 - 2062 1870 static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb, 2063 1871 const struct nlmsghdr *nlh, 2064 1872 const struct nlattr * const nla[]) ··· 2070 1932 if (IS_ERR(rule)) 2071 1933 return PTR_ERR(rule); 2072 1934 2073 - err = nf_tables_delrule_one(&ctx, rule); 1935 + err = nft_delrule(&ctx, rule); 2074 1936 } else { 2075 - err = nf_table_delrule_by_chain(&ctx); 1937 + err = nft_delrule_by_chain(&ctx); 2076 1938 } 2077 1939 } else { 2078 1940 list_for_each_entry(chain, &table->chains, list) { 2079 1941 ctx.chain = chain; 2080 - err = nf_table_delrule_by_chain(&ctx); 1942 + err = nft_delrule_by_chain(&ctx); 2081 1943 if (err < 0) 2082 1944 break; 2083 1945 } ··· 2460 2322 return 0; 2461 2323 } 2462 2324 2463 - #define NFT_SET_INACTIVE (1 << 15) /* Internal set flag */ 2464 - 2465 2325 static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb, 2466 2326 const struct nlmsghdr *nlh, 2467 2327 const struct nlattr * const nla[]) ··· 2530 2394 2531 2395 if (da[NFTA_SET_DESC_SIZE] != NULL) 2532 2396 desc->size = ntohl(nla_get_be32(da[NFTA_SET_DESC_SIZE])); 2533 - 2534 - return 0; 2535 - } 2536 - 2537 - static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type, 2538 - struct nft_set *set) 2539 - { 2540 - struct nft_trans *trans; 2541 - 2542 - trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_set)); 2543 - if (trans == NULL) 2544 - return -ENOMEM; 2545 - 2546 - if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) { 2547 - nft_trans_set_id(trans) = 2548 - ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID])); 2549 - set->flags |= NFT_SET_INACTIVE; 2550 - } 2551 - nft_trans_set(trans) = set; 2552 - list_add_tail(&trans->list, &ctx->net->nft.commit_list); 2553 2397 2554 2398 return 0; 2555 2399 } ··· 2727 2611 if (!list_empty(&set->bindings)) 2728 2612 return -EBUSY; 2729 2613 2730 - err = nft_trans_set_add(&ctx, NFT_MSG_DELSET, set); 2731 - if (err < 0) 2732 - return err; 2733 - 2734 - list_del_rcu(&set->list); 2735 - ctx.table->use--; 2736 - return 0; 2614 + return nft_delset(&ctx, set); 2737 2615 } 2738 2616 2739 2617 static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx, ··· 3462 3352 break; 3463 3353 case NFT_MSG_DELCHAIN: 3464 3354 nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN); 3465 - if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && 3466 - trans->ctx.chain->flags & NFT_BASE_CHAIN) { 3467 - nf_unregister_hooks(nft_base_chain(trans->ctx.chain)->ops, 3468 - trans->ctx.afi->nops); 3469 - } 3355 + nf_tables_unregister_hooks(trans->ctx.table, 3356 + trans->ctx.chain, 3357 + trans->ctx.afi->nops); 3470 3358 break; 3471 3359 case NFT_MSG_NEWRULE: 3472 3360 nft_rule_clear(trans->ctx.net, nft_trans_rule(trans)); ··· 3587 3479 } else { 3588 3480 trans->ctx.table->use--; 3589 3481 list_del_rcu(&trans->ctx.chain->list); 3590 - if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && 3591 - trans->ctx.chain->flags & NFT_BASE_CHAIN) { 3592 - nf_unregister_hooks(nft_base_chain(trans->ctx.chain)->ops, 3593 - trans->ctx.afi->nops); 3594 - } 3482 + nf_tables_unregister_hooks(trans->ctx.table, 3483 + trans->ctx.chain, 3484 + trans->ctx.afi->nops); 3595 3485 } 3596 3486 break; 3597 3487 case NFT_MSG_DELCHAIN:
+59
net/netfilter/nft_masq.c
··· 1 + /* 2 + * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> 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 + 9 + #include <linux/kernel.h> 10 + #include <linux/init.h> 11 + #include <linux/module.h> 12 + #include <linux/netlink.h> 13 + #include <linux/netfilter.h> 14 + #include <linux/netfilter/nf_tables.h> 15 + #include <net/netfilter/nf_tables.h> 16 + #include <net/netfilter/nf_nat.h> 17 + #include <net/netfilter/nft_masq.h> 18 + 19 + const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { 20 + [NFTA_MASQ_FLAGS] = { .type = NLA_U32 }, 21 + }; 22 + EXPORT_SYMBOL_GPL(nft_masq_policy); 23 + 24 + int nft_masq_init(const struct nft_ctx *ctx, 25 + const struct nft_expr *expr, 26 + const struct nlattr * const tb[]) 27 + { 28 + struct nft_masq *priv = nft_expr_priv(expr); 29 + 30 + if (tb[NFTA_MASQ_FLAGS] == NULL) 31 + return 0; 32 + 33 + priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); 34 + if (priv->flags & ~NF_NAT_RANGE_MASK) 35 + return -EINVAL; 36 + 37 + return 0; 38 + } 39 + EXPORT_SYMBOL_GPL(nft_masq_init); 40 + 41 + int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr) 42 + { 43 + const struct nft_masq *priv = nft_expr_priv(expr); 44 + 45 + if (priv->flags == 0) 46 + return 0; 47 + 48 + if (nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) 49 + goto nla_put_failure; 50 + 51 + return 0; 52 + 53 + nla_put_failure: 54 + return -1; 55 + } 56 + EXPORT_SYMBOL_GPL(nft_masq_dump); 57 + 58 + MODULE_LICENSE("GPL"); 59 + MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>");
+45
net/netfilter/nft_meta.c
··· 14 14 #include <linux/netlink.h> 15 15 #include <linux/netfilter.h> 16 16 #include <linux/netfilter/nf_tables.h> 17 + #include <linux/in.h> 18 + #include <linux/ip.h> 19 + #include <linux/ipv6.h> 20 + #include <linux/smp.h> 17 21 #include <net/dst.h> 18 22 #include <net/sock.h> 19 23 #include <net/tcp_states.h> /* for TCP_TIME_WAIT */ ··· 128 124 dest->data[0] = skb->secmark; 129 125 break; 130 126 #endif 127 + case NFT_META_PKTTYPE: 128 + if (skb->pkt_type != PACKET_LOOPBACK) { 129 + dest->data[0] = skb->pkt_type; 130 + break; 131 + } 132 + 133 + switch (pkt->ops->pf) { 134 + case NFPROTO_IPV4: 135 + if (ipv4_is_multicast(ip_hdr(skb)->daddr)) 136 + dest->data[0] = PACKET_MULTICAST; 137 + else 138 + dest->data[0] = PACKET_BROADCAST; 139 + break; 140 + case NFPROTO_IPV6: 141 + if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF) 142 + dest->data[0] = PACKET_MULTICAST; 143 + else 144 + dest->data[0] = PACKET_BROADCAST; 145 + break; 146 + default: 147 + WARN_ON(1); 148 + goto err; 149 + } 150 + break; 151 + case NFT_META_CPU: 152 + dest->data[0] = smp_processor_id(); 153 + break; 154 + case NFT_META_IIFGROUP: 155 + if (in == NULL) 156 + goto err; 157 + dest->data[0] = in->group; 158 + break; 159 + case NFT_META_OIFGROUP: 160 + if (out == NULL) 161 + goto err; 162 + dest->data[0] = out->group; 163 + break; 131 164 default: 132 165 WARN_ON(1); 133 166 goto err; ··· 236 195 #ifdef CONFIG_NETWORK_SECMARK 237 196 case NFT_META_SECMARK: 238 197 #endif 198 + case NFT_META_PKTTYPE: 199 + case NFT_META_CPU: 200 + case NFT_META_IIFGROUP: 201 + case NFT_META_OIFGROUP: 239 202 break; 240 203 default: 241 204 return -EOPNOTSUPP;
+16
net/netfilter/nft_nat.c
··· 33 33 enum nft_registers sreg_proto_max:8; 34 34 enum nf_nat_manip_type type:8; 35 35 u8 family; 36 + u16 flags; 36 37 }; 37 38 38 39 static void nft_nat_eval(const struct nft_expr *expr, ··· 72 71 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 73 72 } 74 73 74 + range.flags |= priv->flags; 75 + 75 76 data[NFT_REG_VERDICT].verdict = 76 77 nf_nat_setup_info(ct, &range, priv->type); 77 78 } ··· 85 82 [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 }, 86 83 [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 }, 87 84 [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 }, 85 + [NFTA_NAT_FLAGS] = { .type = NLA_U32 }, 88 86 }; 89 87 90 88 static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, ··· 153 149 } else 154 150 priv->sreg_proto_max = priv->sreg_proto_min; 155 151 152 + if (tb[NFTA_NAT_FLAGS]) { 153 + priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS])); 154 + if (priv->flags & ~NF_NAT_RANGE_MASK) 155 + return -EINVAL; 156 + } 157 + 156 158 return 0; 157 159 } 158 160 ··· 193 183 htonl(priv->sreg_proto_max))) 194 184 goto nla_put_failure; 195 185 } 186 + 187 + if (priv->flags != 0) { 188 + if (nla_put_be32(skb, NFTA_NAT_FLAGS, htonl(priv->flags))) 189 + goto nla_put_failure; 190 + } 191 + 196 192 return 0; 197 193 198 194 nla_put_failure:
-1
net/netfilter/xt_string.c
··· 29 29 struct ts_state state; 30 30 bool invert; 31 31 32 - memset(&state, 0, sizeof(struct ts_state)); 33 32 invert = conf->u.v1.flags & XT_STRING_FLAG_INVERT; 34 33 35 34 return (skb_find_text((struct sk_buff *)skb, conf->from_offset,