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

netfilter: nf_tables: add compatibility layer for x_tables

This patch adds the x_tables compatibility layer. This allows you
to use existing x_tables matches and targets from nf_tables.

This compatibility later allows us to use existing matches/targets
for features that are still missing in nf_tables. We can progressively
replace them with native nf_tables extensions. It also provides the
userspace compatibility software that allows you to express the
rule-set using the iptables syntax but using the nf_tables kernel
components.

In order to get this compatibility layer working, I've done the
following things:

* add NFNL_SUBSYS_NFT_COMPAT: this new nfnetlink subsystem is used
to query the x_tables match/target revision, so we don't need to
use the native x_table getsockopt interface.

* emulate xt structures: this required extending the struct nft_pktinfo
to include the fragment offset, which is already obtained from
ip[6]_tables and that is used by some matches/targets.

* add support for default policy to base chains, required to emulate
x_tables.

* add NFTA_CHAIN_USE attribute to obtain the number of references to
chains, required by x_tables emulation.

* add chain packet/byte counters using per-cpu.

* support 32-64 bits compat.

For historical reasons, this patch includes the following patches
that were posted in the netfilter-devel mailing list.

From Pablo Neira Ayuso:
* nf_tables: add default policy to base chains
* netfilter: nf_tables: add NFTA_CHAIN_USE attribute
* nf_tables: nft_compat: private data of target and matches in contiguous area
* nf_tables: validate hooks for compat match/target
* nf_tables: nft_compat: release cached matches/targets
* nf_tables: x_tables support as a compile time option
* nf_tables: fix alias for xtables over nftables module
* nf_tables: add packet and byte counters per chain
* nf_tables: fix per-chain counter stats if no counters are passed
* nf_tables: don't bump chain stats
* nf_tables: add protocol and flags for xtables over nf_tables
* nf_tables: add ip[6]t_entry emulation
* nf_tables: move specific layer 3 compat code to nf_tables_ipv[4|6]
* nf_tables: support 32bits-64bits x_tables compat
* nf_tables: fix compilation if CONFIG_COMPAT is disabled

From Patrick McHardy:
* nf_tables: move policy to struct nft_base_chain
* nf_tables: send notifications for base chain policy changes

From Alexander Primak:
* nf_tables: remove the duplicate NF_INET_LOCAL_OUT

From Nicolas Dichtel:
* nf_tables: fix compilation when nf-netlink is a module

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+1241 -78
+37 -7
include/net/netfilter/nf_tables.h
··· 3 3 4 4 #include <linux/list.h> 5 5 #include <linux/netfilter.h> 6 + #include <linux/netfilter/x_tables.h> 6 7 #include <linux/netfilter/nf_tables.h> 7 8 #include <net/netlink.h> 8 9 ··· 16 15 u8 hooknum; 17 16 u8 nhoff; 18 17 u8 thoff; 18 + /* for x_tables compatibility */ 19 + struct xt_action_param xt; 19 20 }; 21 + 22 + static inline void nft_set_pktinfo(struct nft_pktinfo *pkt, 23 + const struct nf_hook_ops *ops, 24 + struct sk_buff *skb, 25 + const struct net_device *in, 26 + const struct net_device *out) 27 + { 28 + pkt->skb = skb; 29 + pkt->in = pkt->xt.in = in; 30 + pkt->out = pkt->xt.out = out; 31 + pkt->hooknum = pkt->xt.hooknum = ops->hooknum; 32 + pkt->xt.family = ops->pf; 33 + } 20 34 21 35 struct nft_data { 22 36 union { ··· 73 57 * @afi: address family info 74 58 * @table: the table the chain is contained in 75 59 * @chain: the chain the rule is contained in 60 + * @nla: netlink attributes 76 61 */ 77 62 struct nft_ctx { 78 63 const struct sk_buff *skb; ··· 81 64 const struct nft_af_info *afi; 82 65 const struct nft_table *table; 83 66 const struct nft_chain *chain; 67 + const struct nlattr * const *nla; 84 68 }; 85 69 86 70 struct nft_data_desc { ··· 253 235 * @maxattr: highest netlink attribute number 254 236 */ 255 237 struct nft_expr_type { 256 - const struct nft_expr_ops *(*select_ops)(const struct nlattr * const tb[]); 238 + const struct nft_expr_ops *(*select_ops)(const struct nft_ctx *, 239 + const struct nlattr * const tb[]); 257 240 const struct nft_expr_ops *ops; 258 241 struct list_head list; 259 242 const char *name; ··· 272 253 * @destroy: destruction function 273 254 * @dump: function to dump parameters 274 255 * @type: expression type 256 + * @validate: validate expression, called during loop detection 257 + * @data: extra data to attach to this expression operation 275 258 */ 276 259 struct nft_expr; 277 260 struct nft_expr_ops { ··· 288 267 void (*destroy)(const struct nft_expr *expr); 289 268 int (*dump)(struct sk_buff *skb, 290 269 const struct nft_expr *expr); 291 - const struct nft_data * (*get_verdict)(const struct nft_expr *expr); 270 + int (*validate)(const struct nft_ctx *ctx, 271 + const struct nft_expr *expr, 272 + const struct nft_data **data); 292 273 const struct nft_expr_type *type; 274 + void *data; 293 275 }; 294 276 295 277 #define NFT_EXPR_MAXATTR 16 ··· 392 368 NFT_CHAIN_T_MAX 393 369 }; 394 370 371 + struct nft_stats { 372 + u64 bytes; 373 + u64 pkts; 374 + }; 375 + 395 376 /** 396 377 * struct nft_base_chain - nf_tables base chain 397 378 * 398 379 * @ops: netfilter hook ops 399 380 * @type: chain type 381 + * @policy: default policy 382 + * @stats: per-cpu chain stats 400 383 * @chain: the chain 401 384 */ 402 385 struct nft_base_chain { 403 386 struct nf_hook_ops ops; 404 387 enum nft_chain_type type; 388 + u8 policy; 389 + struct nft_stats __percpu *stats; 405 390 struct nft_chain chain; 406 391 }; 407 392 ··· 419 386 return container_of(chain, struct nft_base_chain, chain); 420 387 } 421 388 422 - extern unsigned int nft_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 - int (*okfn)(struct sk_buff *)); 389 + extern unsigned int nft_do_chain_pktinfo(struct nft_pktinfo *pkt, 390 + const struct nf_hook_ops *ops); 427 391 428 392 /** 429 393 * struct nft_table - nf_tables table
+23
include/net/netfilter/nf_tables_ipv4.h
··· 1 + #ifndef _NF_TABLES_IPV4_H_ 2 + #define _NF_TABLES_IPV4_H_ 3 + 4 + #include <net/netfilter/nf_tables.h> 5 + #include <net/ip.h> 6 + 7 + static inline void 8 + nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt, 9 + const struct nf_hook_ops *ops, 10 + struct sk_buff *skb, 11 + const struct net_device *in, 12 + const struct net_device *out) 13 + { 14 + struct iphdr *ip; 15 + 16 + nft_set_pktinfo(pkt, ops, skb, in, out); 17 + 18 + pkt->xt.thoff = ip_hdrlen(pkt->skb); 19 + ip = ip_hdr(pkt->skb); 20 + pkt->xt.fragoff = ntohs(ip->frag_off) & IP_OFFSET; 21 + } 22 + 23 + #endif
+30
include/net/netfilter/nf_tables_ipv6.h
··· 1 + #ifndef _NF_TABLES_IPV6_H_ 2 + #define _NF_TABLES_IPV6_H_ 3 + 4 + #include <linux/netfilter_ipv6/ip6_tables.h> 5 + #include <net/ipv6.h> 6 + 7 + static inline int 8 + nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt, 9 + const struct nf_hook_ops *ops, 10 + struct sk_buff *skb, 11 + const struct net_device *in, 12 + const struct net_device *out) 13 + { 14 + int protohdr, thoff = 0; 15 + unsigned short frag_off; 16 + 17 + nft_set_pktinfo(pkt, ops, skb, in, out); 18 + 19 + protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, NULL); 20 + /* If malformed, drop it */ 21 + if (protohdr < 0) 22 + return -1; 23 + 24 + pkt->xt.thoff = thoff; 25 + pkt->xt.fragoff = frag_off; 26 + 27 + return 0; 28 + } 29 + 30 + #endif
+1
include/uapi/linux/netfilter/Kbuild
··· 6 6 header-y += nf_conntrack_tcp.h 7 7 header-y += nf_conntrack_tuple_common.h 8 8 header-y += nf_tables.h 9 + header-y += nf_tables_compat.h 9 10 header-y += nf_nat.h 10 11 header-y += nfnetlink.h 11 12 header-y += nfnetlink_acct.h
+32
include/uapi/linux/netfilter/nf_tables.h
··· 115 115 * @NFTA_CHAIN_HANDLE: numeric handle of the chain (NLA_U64) 116 116 * @NFTA_CHAIN_NAME: name of the chain (NLA_STRING) 117 117 * @NFTA_CHAIN_HOOK: hook specification for basechains (NLA_NESTED: nft_hook_attributes) 118 + * @NFTA_CHAIN_POLICY: numeric policy of the chain (NLA_U32) 119 + * @NFTA_CHAIN_USE: number of references to this chain (NLA_U32) 118 120 * @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING) 121 + * @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes) 119 122 */ 120 123 enum nft_chain_attributes { 121 124 NFTA_CHAIN_UNSPEC, ··· 126 123 NFTA_CHAIN_HANDLE, 127 124 NFTA_CHAIN_NAME, 128 125 NFTA_CHAIN_HOOK, 126 + NFTA_CHAIN_POLICY, 127 + NFTA_CHAIN_USE, 129 128 NFTA_CHAIN_TYPE, 129 + NFTA_CHAIN_COUNTERS, 130 130 __NFTA_CHAIN_MAX 131 131 }; 132 132 #define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1) ··· 141 135 * @NFTA_RULE_CHAIN: name of the chain containing the rule (NLA_STRING) 142 136 * @NFTA_RULE_HANDLE: numeric handle of the rule (NLA_U64) 143 137 * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes) 138 + * @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes) 144 139 */ 145 140 enum nft_rule_attributes { 146 141 NFTA_RULE_UNSPEC, ··· 149 142 NFTA_RULE_CHAIN, 150 143 NFTA_RULE_HANDLE, 151 144 NFTA_RULE_EXPRESSIONS, 145 + NFTA_RULE_COMPAT, 152 146 __NFTA_RULE_MAX 153 147 }; 154 148 #define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1) 149 + 150 + /** 151 + * enum nft_rule_compat_flags - nf_tables rule compat flags 152 + * 153 + * @NFT_RULE_COMPAT_F_INV: invert the check result 154 + */ 155 + enum nft_rule_compat_flags { 156 + NFT_RULE_COMPAT_F_INV = (1 << 1), 157 + NFT_RULE_COMPAT_F_MASK = NFT_RULE_COMPAT_F_INV, 158 + }; 159 + 160 + /** 161 + * enum nft_rule_compat_attributes - nf_tables rule compat attributes 162 + * 163 + * @NFTA_RULE_COMPAT_PROTO: numerice value of handled protocol (NLA_U32) 164 + * @NFTA_RULE_COMPAT_FLAGS: bitmask of enum nft_rule_compat_flags (NLA_U32) 165 + */ 166 + enum nft_rule_compat_attributes { 167 + NFTA_RULE_COMPAT_UNSPEC, 168 + NFTA_RULE_COMPAT_PROTO, 169 + NFTA_RULE_COMPAT_FLAGS, 170 + __NFTA_RULE_COMPAT_MAX 171 + }; 172 + #define NFTA_RULE_COMPAT_MAX (__NFTA_RULE_COMPAT_MAX - 1) 155 173 156 174 /** 157 175 * enum nft_set_flags - nf_tables set flags
+38
include/uapi/linux/netfilter/nf_tables_compat.h
··· 1 + #ifndef _NFT_COMPAT_NFNETLINK_H_ 2 + #define _NFT_COMPAT_NFNETLINK_H_ 3 + 4 + enum nft_target_attributes { 5 + NFTA_TARGET_UNSPEC, 6 + NFTA_TARGET_NAME, 7 + NFTA_TARGET_REV, 8 + NFTA_TARGET_INFO, 9 + __NFTA_TARGET_MAX 10 + }; 11 + #define NFTA_TARGET_MAX (__NFTA_TARGET_MAX - 1) 12 + 13 + enum nft_match_attributes { 14 + NFTA_MATCH_UNSPEC, 15 + NFTA_MATCH_NAME, 16 + NFTA_MATCH_REV, 17 + NFTA_MATCH_INFO, 18 + __NFTA_MATCH_MAX 19 + }; 20 + #define NFTA_MATCH_MAX (__NFTA_MATCH_MAX - 1) 21 + 22 + #define NFT_COMPAT_NAME_MAX 32 23 + 24 + enum { 25 + NFNL_MSG_COMPAT_GET, 26 + NFNL_MSG_COMPAT_MAX 27 + }; 28 + 29 + enum { 30 + NFTA_COMPAT_UNSPEC = 0, 31 + NFTA_COMPAT_NAME, 32 + NFTA_COMPAT_REV, 33 + NFTA_COMPAT_TYPE, 34 + __NFTA_COMPAT_MAX, 35 + }; 36 + #define NFTA_COMPAT_MAX (__NFTA_COMPAT_MAX - 1) 37 + 38 + #endif
+2 -1
include/uapi/linux/netfilter/nfnetlink.h
··· 54 54 #define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8 55 55 #define NFNL_SUBSYS_CTHELPER 9 56 56 #define NFNL_SUBSYS_NFTABLES 10 57 - #define NFNL_SUBSYS_COUNT 11 57 + #define NFNL_SUBSYS_NFT_COMPAT 11 58 + #define NFNL_SUBSYS_COUNT 12 58 59 59 60 #endif /* _UAPI_NFNETLINK_H */
+26 -6
net/ipv4/netfilter/nf_tables_ipv4.c
··· 15 15 #include <linux/netfilter_ipv4.h> 16 16 #include <net/netfilter/nf_tables.h> 17 17 #include <net/ip.h> 18 + #include <net/net_namespace.h> 19 + #include <net/netfilter/nf_tables_ipv4.h> 18 20 19 21 static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, 20 22 struct sk_buff *skb, ··· 24 22 const struct net_device *out, 25 23 int (*okfn)(struct sk_buff *)) 26 24 { 25 + struct nft_pktinfo pkt; 26 + 27 27 if (unlikely(skb->len < sizeof(struct iphdr) || 28 28 ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) { 29 29 if (net_ratelimit()) ··· 33 29 "packet\n"); 34 30 return NF_ACCEPT; 35 31 } 32 + nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); 36 33 37 - return nft_do_chain(ops, skb, in, out, okfn); 34 + return nft_do_chain_pktinfo(&pkt, ops); 38 35 } 39 36 40 37 static struct nft_af_info nft_af_ipv4 __read_mostly = { ··· 47 42 }, 48 43 }; 49 44 45 + 46 + static unsigned int 47 + nft_do_chain_ipv4(const struct nf_hook_ops *ops, 48 + struct sk_buff *skb, 49 + const struct net_device *in, 50 + const struct net_device *out, 51 + int (*okfn)(struct sk_buff *)) 52 + { 53 + struct nft_pktinfo pkt; 54 + 55 + nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); 56 + 57 + return nft_do_chain_pktinfo(&pkt, ops); 58 + } 59 + 50 60 static struct nf_chain_type filter_ipv4 = { 51 61 .family = NFPROTO_IPV4, 52 62 .name = "filter", ··· 72 52 (1 << NF_INET_PRE_ROUTING) | 73 53 (1 << NF_INET_POST_ROUTING), 74 54 .fn = { 75 - [NF_INET_LOCAL_IN] = nft_do_chain, 76 - [NF_INET_LOCAL_OUT] = nft_do_chain, 77 - [NF_INET_FORWARD] = nft_do_chain, 78 - [NF_INET_PRE_ROUTING] = nft_do_chain, 79 - [NF_INET_POST_ROUTING] = nft_do_chain, 55 + [NF_INET_LOCAL_IN] = nft_do_chain_ipv4, 56 + [NF_INET_LOCAL_OUT] = nft_ipv4_output, 57 + [NF_INET_FORWARD] = nft_do_chain_ipv4, 58 + [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4, 59 + [NF_INET_POST_ROUTING] = nft_do_chain_ipv4, 80 60 }, 81 61 }; 82 62
+5 -1
net/ipv4/netfilter/nft_chain_nat_ipv4.c
··· 23 23 #include <net/netfilter/nf_nat.h> 24 24 #include <net/netfilter/nf_nat_core.h> 25 25 #include <net/netfilter/nf_tables.h> 26 + #include <net/netfilter/nf_tables_ipv4.h> 26 27 #include <net/netfilter/nf_nat_l3proto.h> 27 28 #include <net/ip.h> 28 29 ··· 182 181 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 183 182 struct nf_conn_nat *nat; 184 183 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); 184 + struct nft_pktinfo pkt; 185 185 unsigned int ret; 186 186 187 187 if (ct == NULL || nf_ct_is_untracked(ct)) ··· 215 213 if (nf_nat_initialized(ct, maniptype)) 216 214 break; 217 215 218 - ret = nft_do_chain(ops, skb, in, out, okfn); 216 + nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); 217 + 218 + ret = nft_do_chain_pktinfo(&pkt, ops); 219 219 if (ret != NF_ACCEPT) 220 220 return ret; 221 221 if (!nf_nat_initialized(ct, maniptype)) {
+5 -1
net/ipv4/netfilter/nft_chain_route_ipv4.c
··· 17 17 #include <linux/netfilter/nfnetlink.h> 18 18 #include <linux/netfilter/nf_tables.h> 19 19 #include <net/netfilter/nf_tables.h> 20 + #include <net/netfilter/nf_tables_ipv4.h> 20 21 #include <net/route.h> 21 22 #include <net/ip.h> 22 23 ··· 28 27 int (*okfn)(struct sk_buff *)) 29 28 { 30 29 unsigned int ret; 30 + struct nft_pktinfo pkt; 31 31 u32 mark; 32 32 __be32 saddr, daddr; 33 33 u_int8_t tos; ··· 39 37 ip_hdrlen(skb) < sizeof(struct iphdr)) 40 38 return NF_ACCEPT; 41 39 40 + nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); 41 + 42 42 mark = skb->mark; 43 43 iph = ip_hdr(skb); 44 44 saddr = iph->saddr; 45 45 daddr = iph->daddr; 46 46 tos = iph->tos; 47 47 48 - ret = nft_do_chain(ops, skb, in, out, okfn); 48 + ret = nft_do_chain_pktinfo(&pkt, ops); 49 49 if (ret != NF_DROP && ret != NF_QUEUE) { 50 50 iph = ip_hdr(skb); 51 51
+27 -6
net/ipv6/netfilter/nf_tables_ipv6.c
··· 14 14 #include <linux/ipv6.h> 15 15 #include <linux/netfilter_ipv6.h> 16 16 #include <net/netfilter/nf_tables.h> 17 + #include <net/netfilter/nf_tables_ipv6.h> 17 18 18 19 static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops, 19 20 struct sk_buff *skb, ··· 22 21 const struct net_device *out, 23 22 int (*okfn)(struct sk_buff *)) 24 23 { 24 + struct nft_pktinfo pkt; 25 + 25 26 if (unlikely(skb->len < sizeof(struct ipv6hdr))) { 26 27 if (net_ratelimit()) 27 28 pr_info("nf_tables_ipv6: ignoring short SOCK_RAW " 28 29 "packet\n"); 29 30 return NF_ACCEPT; 30 31 } 32 + if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) 33 + return NF_DROP; 31 34 32 - return nft_do_chain(ops, skb, in, out, okfn); 35 + return nft_do_chain_pktinfo(&pkt, ops); 33 36 } 34 37 35 38 static struct nft_af_info nft_af_ipv6 __read_mostly = { ··· 45 40 }, 46 41 }; 47 42 43 + static unsigned int 44 + nft_do_chain_ipv6(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 *)) 49 + { 50 + struct nft_pktinfo pkt; 51 + 52 + /* malformed packet, drop it */ 53 + if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) 54 + return NF_DROP; 55 + 56 + return nft_do_chain_pktinfo(&pkt, ops); 57 + } 58 + 48 59 static struct nf_chain_type filter_ipv6 = { 49 60 .family = NFPROTO_IPV6, 50 61 .name = "filter", ··· 71 50 (1 << NF_INET_PRE_ROUTING) | 72 51 (1 << NF_INET_POST_ROUTING), 73 52 .fn = { 74 - [NF_INET_LOCAL_IN] = nft_do_chain, 75 - [NF_INET_LOCAL_OUT] = nft_do_chain, 76 - [NF_INET_FORWARD] = nft_do_chain, 77 - [NF_INET_PRE_ROUTING] = nft_do_chain, 78 - [NF_INET_POST_ROUTING] = nft_do_chain, 53 + [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, 54 + [NF_INET_LOCAL_OUT] = nft_ipv6_output, 55 + [NF_INET_FORWARD] = nft_do_chain_ipv6, 56 + [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6, 57 + [NF_INET_POST_ROUTING] = nft_do_chain_ipv6, 79 58 }, 80 59 }; 81 60
+7 -1
net/ipv6/netfilter/nft_chain_route_ipv6.c
··· 19 19 #include <linux/netfilter/nfnetlink.h> 20 20 #include <linux/netfilter/nf_tables.h> 21 21 #include <net/netfilter/nf_tables.h> 22 + #include <net/netfilter/nf_tables_ipv6.h> 22 23 #include <net/route.h> 23 24 24 25 static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, ··· 29 28 int (*okfn)(struct sk_buff *)) 30 29 { 31 30 unsigned int ret; 31 + struct nft_pktinfo pkt; 32 32 struct in6_addr saddr, daddr; 33 33 u_int8_t hop_limit; 34 34 u32 mark, flowlabel; 35 + 36 + /* malformed packet, drop it */ 37 + if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) 38 + return NF_DROP; 35 39 36 40 /* save source/dest address, mark, hoplimit, flowlabel, priority */ 37 41 memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr)); ··· 47 41 /* flowlabel and prio (includes version, which shouldn't change either */ 48 42 flowlabel = *((u32 *)ipv6_hdr(skb)); 49 43 50 - ret = nft_do_chain(ops, skb, in, out, okfn); 44 + ret = nft_do_chain_pktinfo(&pkt, ops); 51 45 if (ret != NF_DROP && ret != NF_QUEUE && 52 46 (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || 53 47 memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
+9
net/netfilter/Kconfig
··· 450 450 depends on NF_TABLES 451 451 tristate "Netfilter nf_tables limit module" 452 452 453 + config NFT_COMPAT 454 + depends on NF_TABLES 455 + depends on NETFILTER_XTABLES 456 + tristate "Netfilter x_tables over nf_tables module" 457 + help 458 + This is required if you intend to use any of existing 459 + x_tables match/target extensions over the nf_tables 460 + framework. 461 + 453 462 config NETFILTER_XTABLES 454 463 tristate "Netfilter Xtables support (required for ip_tables)" 455 464 default m if NETFILTER_ADVANCED=n
+1
net/netfilter/Makefile
··· 70 70 nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o 71 71 72 72 obj-$(CONFIG_NF_TABLES) += nf_tables.o 73 + obj-$(CONFIG_NFT_COMPAT) += nft_compat.o 73 74 obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o 74 75 obj-$(CONFIG_NFT_META) += nft_meta.o 75 76 obj-$(CONFIG_NFT_CT) += nft_ct.o
+191 -29
net/netfilter/nf_tables_api.c
··· 438 438 [NFTA_CHAIN_NAME] = { .type = NLA_STRING, 439 439 .len = NFT_CHAIN_MAXNAMELEN - 1 }, 440 440 [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED }, 441 + [NFTA_CHAIN_POLICY] = { .type = NLA_U32 }, 441 442 [NFTA_CHAIN_TYPE] = { .type = NLA_NUL_STRING }, 443 + [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED }, 442 444 }; 443 445 444 446 static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = { 445 447 [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 }, 446 448 [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 }, 447 449 }; 450 + 451 + static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats) 452 + { 453 + struct nft_stats *cpu_stats, total; 454 + struct nlattr *nest; 455 + int cpu; 456 + 457 + memset(&total, 0, sizeof(total)); 458 + for_each_possible_cpu(cpu) { 459 + cpu_stats = per_cpu_ptr(stats, cpu); 460 + total.pkts += cpu_stats->pkts; 461 + total.bytes += cpu_stats->bytes; 462 + } 463 + nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS); 464 + if (nest == NULL) 465 + goto nla_put_failure; 466 + 467 + if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.pkts)) || 468 + nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes))) 469 + goto nla_put_failure; 470 + 471 + nla_nest_end(skb, nest); 472 + return 0; 473 + 474 + nla_put_failure: 475 + return -ENOSPC; 476 + } 448 477 449 478 static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq, 450 479 int event, u32 flags, int family, ··· 501 472 goto nla_put_failure; 502 473 503 474 if (chain->flags & NFT_BASE_CHAIN) { 504 - const struct nf_hook_ops *ops = &nft_base_chain(chain)->ops; 505 - struct nlattr *nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); 475 + const struct nft_base_chain *basechain = nft_base_chain(chain); 476 + const struct nf_hook_ops *ops = &basechain->ops; 477 + struct nlattr *nest; 478 + 479 + nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); 506 480 if (nest == NULL) 507 481 goto nla_put_failure; 508 482 if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum))) ··· 514 482 goto nla_put_failure; 515 483 nla_nest_end(skb, nest); 516 484 485 + if (nla_put_be32(skb, NFTA_CHAIN_POLICY, 486 + htonl(basechain->policy))) 487 + goto nla_put_failure; 488 + 517 489 if (nla_put_string(skb, NFTA_CHAIN_TYPE, 518 490 chain_type[ops->pf][nft_base_chain(chain)->type]->name)) 519 491 goto nla_put_failure; 492 + 493 + if (nft_dump_stats(skb, nft_base_chain(chain)->stats)) 494 + goto nla_put_failure; 520 495 } 496 + 497 + if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use))) 498 + goto nla_put_failure; 521 499 522 500 return nlmsg_end(skb, nlh); 523 501 ··· 659 617 return err; 660 618 } 661 619 620 + static int 621 + nf_tables_chain_policy(struct nft_base_chain *chain, const struct nlattr *attr) 622 + { 623 + switch (ntohl(nla_get_be32(attr))) { 624 + case NF_DROP: 625 + chain->policy = NF_DROP; 626 + break; 627 + case NF_ACCEPT: 628 + chain->policy = NF_ACCEPT; 629 + break; 630 + default: 631 + return -EINVAL; 632 + } 633 + return 0; 634 + } 635 + 636 + static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = { 637 + [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 }, 638 + [NFTA_COUNTER_BYTES] = { .type = NLA_U64 }, 639 + }; 640 + 641 + static int 642 + nf_tables_counters(struct nft_base_chain *chain, const struct nlattr *attr) 643 + { 644 + struct nlattr *tb[NFTA_COUNTER_MAX+1]; 645 + struct nft_stats __percpu *newstats; 646 + struct nft_stats *stats; 647 + int err; 648 + 649 + err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy); 650 + if (err < 0) 651 + return err; 652 + 653 + if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS]) 654 + return -EINVAL; 655 + 656 + newstats = alloc_percpu(struct nft_stats); 657 + if (newstats == NULL) 658 + return -ENOMEM; 659 + 660 + /* Restore old counters on this cpu, no problem. Per-cpu statistics 661 + * are not exposed to userspace. 662 + */ 663 + stats = this_cpu_ptr(newstats); 664 + stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES])); 665 + stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS])); 666 + 667 + if (chain->stats) { 668 + /* nfnl_lock is held, add some nfnl function for this, later */ 669 + struct nft_stats __percpu *oldstats = 670 + rcu_dereference_protected(chain->stats, 1); 671 + 672 + rcu_assign_pointer(chain->stats, newstats); 673 + synchronize_rcu(); 674 + free_percpu(oldstats); 675 + } else 676 + rcu_assign_pointer(chain->stats, newstats); 677 + 678 + return 0; 679 + } 680 + 662 681 static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, 663 682 const struct nlmsghdr *nlh, 664 683 const struct nlattr * const nla[]) ··· 729 626 const struct nft_af_info *afi; 730 627 struct nft_table *table; 731 628 struct nft_chain *chain; 732 - struct nft_base_chain *basechain; 629 + struct nft_base_chain *basechain = NULL; 733 630 struct nlattr *ha[NFTA_HOOK_MAX + 1]; 734 631 int family = nfmsg->nfgen_family; 735 632 u64 handle = 0; ··· 775 672 if (nla[NFTA_CHAIN_HANDLE] && name && 776 673 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]))) 777 674 return -EEXIST; 675 + 676 + if (nla[NFTA_CHAIN_POLICY]) { 677 + if (!(chain->flags & NFT_BASE_CHAIN)) 678 + return -EOPNOTSUPP; 679 + 680 + err = nf_tables_chain_policy(nft_base_chain(chain), 681 + nla[NFTA_CHAIN_POLICY]); 682 + if (err < 0) 683 + return err; 684 + } 685 + 686 + if (nla[NFTA_CHAIN_COUNTERS]) { 687 + if (!(chain->flags & NFT_BASE_CHAIN)) 688 + return -EOPNOTSUPP; 689 + 690 + err = nf_tables_counters(nft_base_chain(chain), 691 + nla[NFTA_CHAIN_COUNTERS]); 692 + if (err < 0) 693 + return err; 694 + } 778 695 779 696 if (nla[NFTA_CHAIN_HANDLE] && name) 780 697 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN); ··· 850 727 ops->hook = afi->hooks[ops->hooknum]; 851 728 852 729 chain->flags |= NFT_BASE_CHAIN; 730 + 731 + if (nla[NFTA_CHAIN_POLICY]) { 732 + err = nf_tables_chain_policy(basechain, 733 + nla[NFTA_CHAIN_POLICY]); 734 + if (err < 0) { 735 + free_percpu(basechain->stats); 736 + kfree(basechain); 737 + return err; 738 + } 739 + } else 740 + basechain->policy = NF_ACCEPT; 741 + 742 + if (nla[NFTA_CHAIN_COUNTERS]) { 743 + err = nf_tables_counters(basechain, 744 + nla[NFTA_CHAIN_COUNTERS]); 745 + if (err < 0) { 746 + free_percpu(basechain->stats); 747 + kfree(basechain); 748 + return err; 749 + } 750 + } else { 751 + struct nft_stats __percpu *newstats; 752 + 753 + newstats = alloc_percpu(struct nft_stats); 754 + if (newstats == NULL) 755 + return -ENOMEM; 756 + 757 + rcu_assign_pointer(nft_base_chain(chain)->stats, 758 + newstats); 759 + } 853 760 } else { 854 761 chain = kzalloc(sizeof(*chain), GFP_KERNEL); 855 762 if (chain == NULL) ··· 892 739 893 740 list_add_tail(&chain->list, &table->chains); 894 741 table->use++; 742 + 743 + if (chain->flags & NFT_BASE_CHAIN) { 744 + err = nf_register_hook(&nft_base_chain(chain)->ops); 745 + if (err < 0) { 746 + free_percpu(basechain->stats); 747 + kfree(basechain); 748 + return err; 749 + } 750 + } 895 751 notify: 896 752 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_NEWCHAIN, 897 753 family); ··· 913 751 914 752 BUG_ON(chain->use > 0); 915 753 916 - if (chain->flags & NFT_BASE_CHAIN) 754 + if (chain->flags & NFT_BASE_CHAIN) { 755 + free_percpu(nft_base_chain(chain)->stats); 917 756 kfree(nft_base_chain(chain)); 918 - else 757 + } else 919 758 kfree(chain); 920 759 } 921 760 ··· 964 801 const struct nlmsghdr *nlh, 965 802 const struct nft_af_info *afi, 966 803 const struct nft_table *table, 967 - const struct nft_chain *chain) 804 + const struct nft_chain *chain, 805 + const struct nlattr * const *nla) 968 806 { 969 807 ctx->skb = skb; 970 808 ctx->nlh = nlh; 971 809 ctx->afi = afi; 972 810 ctx->table = table; 973 811 ctx->chain = chain; 812 + ctx->nla = nla; 974 813 } 975 814 976 815 /* ··· 1075 910 struct nlattr *tb[NFT_EXPR_MAXATTR + 1]; 1076 911 }; 1077 912 1078 - static int nf_tables_expr_parse(const struct nlattr *nla, 913 + static int nf_tables_expr_parse(const struct nft_ctx *ctx, 914 + const struct nlattr *nla, 1079 915 struct nft_expr_info *info) 1080 916 { 1081 917 const struct nft_expr_type *type; ··· 1101 935 memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1)); 1102 936 1103 937 if (type->select_ops != NULL) { 1104 - ops = type->select_ops((const struct nlattr * const *)info->tb); 938 + ops = type->select_ops(ctx, 939 + (const struct nlattr * const *)info->tb); 1105 940 if (IS_ERR(ops)) { 1106 941 err = PTR_ERR(ops); 1107 942 goto err1; ··· 1179 1012 .len = NFT_CHAIN_MAXNAMELEN - 1 }, 1180 1013 [NFTA_RULE_HANDLE] = { .type = NLA_U64 }, 1181 1014 [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED }, 1015 + [NFTA_RULE_COMPAT] = { .type = NLA_NESTED }, 1182 1016 }; 1183 1017 1184 1018 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, ··· 1437 1269 handle = nf_tables_alloc_handle(table); 1438 1270 } 1439 1271 1272 + nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla); 1273 + 1440 1274 n = 0; 1441 1275 size = 0; 1442 1276 if (nla[NFTA_RULE_EXPRESSIONS]) { ··· 1448 1278 goto err1; 1449 1279 if (n == NFT_RULE_MAXEXPRS) 1450 1280 goto err1; 1451 - err = nf_tables_expr_parse(tmp, &info[n]); 1281 + err = nf_tables_expr_parse(&ctx, tmp, &info[n]); 1452 1282 if (err < 0) 1453 1283 goto err1; 1454 1284 size += info[n].ops->size; ··· 1464 1294 rule->handle = handle; 1465 1295 rule->dlen = size; 1466 1296 1467 - nft_ctx_init(&ctx, skb, nlh, afi, table, chain); 1468 1297 expr = nft_expr_first(rule); 1469 1298 for (i = 0; i < n; i++) { 1470 1299 err = nf_tables_newexpr(&ctx, &info[i], expr); ··· 1471 1302 goto err2; 1472 1303 info[i].ops = NULL; 1473 1304 expr = nft_expr_next(expr); 1474 - } 1475 - 1476 - /* Register hook when first rule is inserted into a base chain */ 1477 - if (list_empty(&chain->rules) && chain->flags & NFT_BASE_CHAIN) { 1478 - err = nf_register_hook(&nft_base_chain(chain)->ops); 1479 - if (err < 0) 1480 - goto err2; 1481 1305 } 1482 1306 1483 1307 if (nlh->nlmsg_flags & NLM_F_REPLACE) { ··· 1540 1378 nf_tables_rule_destroy(rule); 1541 1379 } 1542 1380 } 1543 - 1544 - /* Unregister hook when last rule from base chain is deleted */ 1545 - if (list_empty(&chain->rules) && chain->flags & NFT_BASE_CHAIN) 1546 - nf_unregister_hook(&nft_base_chain(chain)->ops); 1547 1381 1548 1382 return 0; 1549 1383 } ··· 1628 1470 return PTR_ERR(table); 1629 1471 } 1630 1472 1631 - nft_ctx_init(ctx, skb, nlh, afi, table, NULL); 1473 + nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla); 1632 1474 return 0; 1633 1475 } 1634 1476 ··· 1957 1799 if (IS_ERR(table)) 1958 1800 return PTR_ERR(table); 1959 1801 1960 - nft_ctx_init(&ctx, skb, nlh, afi, table, NULL); 1802 + nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla); 1961 1803 1962 1804 set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]); 1963 1805 if (IS_ERR(set)) { ··· 2145 1987 if (IS_ERR(table)) 2146 1988 return PTR_ERR(table); 2147 1989 2148 - nft_ctx_init(ctx, skb, nlh, afi, table, NULL); 1990 + nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla); 2149 1991 return 0; 2150 1992 } 2151 1993 ··· 2593 2435 { 2594 2436 const struct nft_rule *rule; 2595 2437 const struct nft_expr *expr, *last; 2596 - const struct nft_data *data; 2597 2438 const struct nft_set *set; 2598 2439 struct nft_set_binding *binding; 2599 2440 struct nft_set_iter iter; 2600 - int err; 2601 2441 2602 2442 if (ctx->chain == chain) 2603 2443 return -ELOOP; 2604 2444 2605 2445 list_for_each_entry(rule, &chain->rules, list) { 2606 2446 nft_rule_for_each_expr(expr, last, rule) { 2607 - if (!expr->ops->get_verdict) 2447 + const struct nft_data *data = NULL; 2448 + int err; 2449 + 2450 + if (!expr->ops->validate) 2608 2451 continue; 2609 2452 2610 - data = expr->ops->get_verdict(expr); 2453 + err = expr->ops->validate(ctx, expr, &data); 2454 + if (err < 0) 2455 + return err; 2456 + 2611 2457 if (data == NULL) 2612 - break; 2458 + continue; 2613 2459 2614 2460 switch (data->verdict) { 2615 2461 case NFT_JUMP:
+27 -19
net/netfilter/nf_tables_core.c
··· 60 60 return true; 61 61 } 62 62 63 - unsigned int nft_do_chain(const struct nf_hook_ops *ops, 64 - struct sk_buff *skb, 65 - const struct net_device *in, 66 - const struct net_device *out, 67 - int (*okfn)(struct sk_buff *)) 63 + struct nft_jumpstack { 64 + const struct nft_chain *chain; 65 + const struct nft_rule *rule; 66 + }; 67 + 68 + static inline void 69 + nft_chain_stats(const struct nft_chain *this, const struct nft_pktinfo *pkt, 70 + struct nft_jumpstack *jumpstack, unsigned int stackptr) 71 + { 72 + struct nft_stats __percpu *stats; 73 + const struct nft_chain *chain = stackptr ? jumpstack[0].chain : this; 74 + 75 + rcu_read_lock_bh(); 76 + stats = rcu_dereference(nft_base_chain(chain)->stats); 77 + __this_cpu_inc(stats->pkts); 78 + __this_cpu_add(stats->bytes, pkt->skb->len); 79 + rcu_read_unlock_bh(); 80 + } 81 + 82 + unsigned int 83 + nft_do_chain_pktinfo(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) 68 84 { 69 85 const struct nft_chain *chain = ops->priv; 70 86 const struct nft_rule *rule; 71 87 const struct nft_expr *expr, *last; 72 88 struct nft_data data[NFT_REG_MAX + 1]; 73 - const struct nft_pktinfo pkt = { 74 - .skb = skb, 75 - .in = in, 76 - .out = out, 77 - .hooknum = ops->hooknum, 78 - }; 79 89 unsigned int stackptr = 0; 80 - struct { 81 - const struct nft_chain *chain; 82 - const struct nft_rule *rule; 83 - } jumpstack[NFT_JUMP_STACK_SIZE]; 90 + struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; 84 91 85 92 do_chain: 86 93 rule = list_entry(&chain->rules, struct nft_rule, list); ··· 98 91 if (expr->ops == &nft_cmp_fast_ops) 99 92 nft_cmp_fast_eval(expr, data); 100 93 else if (expr->ops != &nft_payload_fast_ops || 101 - !nft_payload_fast_eval(expr, data, &pkt)) 102 - expr->ops->eval(expr, data, &pkt); 94 + !nft_payload_fast_eval(expr, data, pkt)) 95 + expr->ops->eval(expr, data, pkt); 103 96 104 97 if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE) 105 98 break; ··· 142 135 rule = jumpstack[stackptr].rule; 143 136 goto next_rule; 144 137 } 138 + nft_chain_stats(chain, pkt, jumpstack, stackptr); 145 139 146 - return NF_ACCEPT; 140 + return nft_base_chain(chain)->policy; 147 141 } 148 - EXPORT_SYMBOL_GPL(nft_do_chain); 142 + EXPORT_SYMBOL_GPL(nft_do_chain_pktinfo); 149 143 150 144 int __init nf_tables_core_module_init(void) 151 145 {
+2 -1
net/netfilter/nft_cmp.c
··· 162 162 .dump = nft_cmp_fast_dump, 163 163 }; 164 164 165 - static const struct nft_expr_ops *nft_cmp_select_ops(const struct nlattr * const tb[]) 165 + static const struct nft_expr_ops * 166 + nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) 166 167 { 167 168 struct nft_data_desc desc; 168 169 struct nft_data data;
+768
net/netfilter/nft_compat.c
··· 1 + /* 2 + * (C) 2012-2013 by Pablo Neira Ayuso <pablo@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 + * This software has been sponsored by Sophos Astaro <http://www.sophos.com> 9 + */ 10 + 11 + #include <linux/kernel.h> 12 + #include <linux/init.h> 13 + #include <linux/module.h> 14 + #include <linux/netlink.h> 15 + #include <linux/netfilter.h> 16 + #include <linux/netfilter/nfnetlink.h> 17 + #include <linux/netfilter/nf_tables.h> 18 + #include <linux/netfilter/nf_tables_compat.h> 19 + #include <linux/netfilter/x_tables.h> 20 + #include <linux/netfilter_ipv4/ip_tables.h> 21 + #include <linux/netfilter_ipv6/ip6_tables.h> 22 + #include <asm/uaccess.h> /* for set_fs */ 23 + #include <net/netfilter/nf_tables.h> 24 + 25 + union nft_entry { 26 + struct ipt_entry e4; 27 + struct ip6t_entry e6; 28 + }; 29 + 30 + static inline void 31 + nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info) 32 + { 33 + par->target = xt; 34 + par->targinfo = xt_info; 35 + par->hotdrop = false; 36 + } 37 + 38 + static void nft_target_eval(const struct nft_expr *expr, 39 + struct nft_data data[NFT_REG_MAX + 1], 40 + const struct nft_pktinfo *pkt) 41 + { 42 + void *info = nft_expr_priv(expr); 43 + struct xt_target *target = expr->ops->data; 44 + struct sk_buff *skb = pkt->skb; 45 + int ret; 46 + 47 + nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info); 48 + 49 + ret = target->target(skb, &pkt->xt); 50 + 51 + if (pkt->xt.hotdrop) 52 + ret = NF_DROP; 53 + 54 + switch(ret) { 55 + case XT_CONTINUE: 56 + data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; 57 + break; 58 + default: 59 + data[NFT_REG_VERDICT].verdict = ret; 60 + break; 61 + } 62 + return; 63 + } 64 + 65 + static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = { 66 + [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING }, 67 + [NFTA_TARGET_REV] = { .type = NLA_U32 }, 68 + [NFTA_TARGET_INFO] = { .type = NLA_BINARY }, 69 + }; 70 + 71 + static void 72 + nft_target_set_tgchk_param(struct xt_tgchk_param *par, 73 + const struct nft_ctx *ctx, 74 + struct xt_target *target, void *info, 75 + union nft_entry *entry, u8 proto, bool inv) 76 + { 77 + par->net = &init_net; 78 + par->table = ctx->table->name; 79 + switch (ctx->afi->family) { 80 + case AF_INET: 81 + entry->e4.ip.proto = proto; 82 + entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0; 83 + break; 84 + case AF_INET6: 85 + entry->e6.ipv6.proto = proto; 86 + entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; 87 + break; 88 + } 89 + par->entryinfo = entry; 90 + par->target = target; 91 + par->targinfo = info; 92 + if (ctx->chain->flags & NFT_BASE_CHAIN) { 93 + const struct nft_base_chain *basechain = 94 + nft_base_chain(ctx->chain); 95 + const struct nf_hook_ops *ops = &basechain->ops; 96 + 97 + par->hook_mask = 1 << ops->hooknum; 98 + } 99 + par->family = ctx->afi->family; 100 + } 101 + 102 + static void target_compat_from_user(struct xt_target *t, void *in, void *out) 103 + { 104 + #ifdef CONFIG_COMPAT 105 + if (t->compat_from_user) { 106 + int pad; 107 + 108 + t->compat_from_user(out, in); 109 + pad = XT_ALIGN(t->targetsize) - t->targetsize; 110 + if (pad > 0) 111 + memset(out + t->targetsize, 0, pad); 112 + } else 113 + #endif 114 + memcpy(out, in, XT_ALIGN(t->targetsize)); 115 + } 116 + 117 + static inline int nft_compat_target_offset(struct xt_target *target) 118 + { 119 + #ifdef CONFIG_COMPAT 120 + return xt_compat_target_offset(target); 121 + #else 122 + return 0; 123 + #endif 124 + } 125 + 126 + static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] = { 127 + [NFTA_RULE_COMPAT_PROTO] = { .type = NLA_U32 }, 128 + [NFTA_RULE_COMPAT_FLAGS] = { .type = NLA_U32 }, 129 + }; 130 + 131 + static u8 nft_parse_compat(const struct nlattr *attr, bool *inv) 132 + { 133 + struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1]; 134 + u32 flags; 135 + int err; 136 + 137 + err = nla_parse_nested(tb, NFTA_RULE_COMPAT_MAX, attr, 138 + nft_rule_compat_policy); 139 + if (err < 0) 140 + return err; 141 + 142 + if (!tb[NFTA_RULE_COMPAT_PROTO] || !tb[NFTA_RULE_COMPAT_FLAGS]) 143 + return -EINVAL; 144 + 145 + flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS])); 146 + if (flags & ~NFT_RULE_COMPAT_F_MASK) 147 + return -EINVAL; 148 + if (flags & NFT_RULE_COMPAT_F_INV) 149 + *inv = true; 150 + 151 + return ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO])); 152 + } 153 + 154 + static int 155 + nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 156 + const struct nlattr * const tb[]) 157 + { 158 + void *info = nft_expr_priv(expr); 159 + struct xt_target *target = expr->ops->data; 160 + struct xt_tgchk_param par; 161 + size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO])); 162 + u8 proto = 0; 163 + bool inv = false; 164 + union nft_entry e = {}; 165 + int ret; 166 + 167 + target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info); 168 + 169 + if (ctx->nla[NFTA_RULE_COMPAT]) 170 + proto = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &inv); 171 + 172 + nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv); 173 + 174 + ret = xt_check_target(&par, size, proto, inv); 175 + if (ret < 0) 176 + goto err; 177 + 178 + /* The standard target cannot be used */ 179 + if (target->target == NULL) { 180 + ret = -EINVAL; 181 + goto err; 182 + } 183 + 184 + return 0; 185 + err: 186 + module_put(target->me); 187 + return ret; 188 + } 189 + 190 + static void 191 + nft_target_destroy(const struct nft_expr *expr) 192 + { 193 + struct xt_target *target = expr->ops->data; 194 + 195 + module_put(target->me); 196 + } 197 + 198 + static int 199 + target_dump_info(struct sk_buff *skb, const struct xt_target *t, const void *in) 200 + { 201 + int ret; 202 + 203 + #ifdef CONFIG_COMPAT 204 + if (t->compat_to_user) { 205 + mm_segment_t old_fs; 206 + void *out; 207 + 208 + out = kmalloc(XT_ALIGN(t->targetsize), GFP_ATOMIC); 209 + if (out == NULL) 210 + return -ENOMEM; 211 + 212 + /* We want to reuse existing compat_to_user */ 213 + old_fs = get_fs(); 214 + set_fs(KERNEL_DS); 215 + t->compat_to_user(out, in); 216 + set_fs(old_fs); 217 + ret = nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(t->targetsize), out); 218 + kfree(out); 219 + } else 220 + #endif 221 + ret = nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(t->targetsize), in); 222 + 223 + return ret; 224 + } 225 + 226 + static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr) 227 + { 228 + const struct xt_target *target = expr->ops->data; 229 + void *info = nft_expr_priv(expr); 230 + 231 + if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) || 232 + nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) || 233 + target_dump_info(skb, target, info)) 234 + goto nla_put_failure; 235 + 236 + return 0; 237 + 238 + nla_put_failure: 239 + return -1; 240 + } 241 + 242 + static int nft_target_validate(const struct nft_ctx *ctx, 243 + const struct nft_expr *expr, 244 + const struct nft_data **data) 245 + { 246 + struct xt_target *target = expr->ops->data; 247 + unsigned int hook_mask = 0; 248 + 249 + if (ctx->chain->flags & NFT_BASE_CHAIN) { 250 + const struct nft_base_chain *basechain = 251 + nft_base_chain(ctx->chain); 252 + const struct nf_hook_ops *ops = &basechain->ops; 253 + 254 + hook_mask = 1 << ops->hooknum; 255 + if (hook_mask & target->hooks) 256 + return 0; 257 + 258 + /* This target is being called from an invalid chain */ 259 + return -EINVAL; 260 + } 261 + return 0; 262 + } 263 + 264 + static void nft_match_eval(const struct nft_expr *expr, 265 + struct nft_data data[NFT_REG_MAX + 1], 266 + const struct nft_pktinfo *pkt) 267 + { 268 + void *info = nft_expr_priv(expr); 269 + struct xt_match *match = expr->ops->data; 270 + struct sk_buff *skb = pkt->skb; 271 + bool ret; 272 + 273 + nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info); 274 + 275 + ret = match->match(skb, (struct xt_action_param *)&pkt->xt); 276 + 277 + if (pkt->xt.hotdrop) { 278 + data[NFT_REG_VERDICT].verdict = NF_DROP; 279 + return; 280 + } 281 + 282 + switch(ret) { 283 + case true: 284 + data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; 285 + break; 286 + case false: 287 + data[NFT_REG_VERDICT].verdict = NFT_BREAK; 288 + break; 289 + } 290 + } 291 + 292 + static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { 293 + [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, 294 + [NFTA_MATCH_REV] = { .type = NLA_U32 }, 295 + [NFTA_MATCH_INFO] = { .type = NLA_BINARY }, 296 + }; 297 + 298 + /* struct xt_mtchk_param and xt_tgchk_param look very similar */ 299 + static void 300 + nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, 301 + struct xt_match *match, void *info, 302 + union nft_entry *entry, u8 proto, bool inv) 303 + { 304 + par->net = &init_net; 305 + par->table = ctx->table->name; 306 + switch (ctx->afi->family) { 307 + case AF_INET: 308 + entry->e4.ip.proto = proto; 309 + entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0; 310 + break; 311 + case AF_INET6: 312 + entry->e6.ipv6.proto = proto; 313 + entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; 314 + break; 315 + } 316 + par->entryinfo = entry; 317 + par->match = match; 318 + par->matchinfo = info; 319 + if (ctx->chain->flags & NFT_BASE_CHAIN) { 320 + const struct nft_base_chain *basechain = 321 + nft_base_chain(ctx->chain); 322 + const struct nf_hook_ops *ops = &basechain->ops; 323 + 324 + par->hook_mask = 1 << ops->hooknum; 325 + } 326 + par->family = ctx->afi->family; 327 + } 328 + 329 + static void match_compat_from_user(struct xt_match *m, void *in, void *out) 330 + { 331 + #ifdef CONFIG_COMPAT 332 + if (m->compat_from_user) { 333 + int pad; 334 + 335 + m->compat_from_user(out, in); 336 + pad = XT_ALIGN(m->matchsize) - m->matchsize; 337 + if (pad > 0) 338 + memset(out + m->matchsize, 0, pad); 339 + } else 340 + #endif 341 + memcpy(out, in, XT_ALIGN(m->matchsize)); 342 + } 343 + 344 + static int 345 + nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 346 + const struct nlattr * const tb[]) 347 + { 348 + void *info = nft_expr_priv(expr); 349 + struct xt_match *match = expr->ops->data; 350 + struct xt_mtchk_param par; 351 + size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO])); 352 + u8 proto = 0; 353 + bool inv = false; 354 + union nft_entry e = {}; 355 + int ret; 356 + 357 + match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info); 358 + 359 + if (ctx->nla[NFTA_RULE_COMPAT]) 360 + proto = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &inv); 361 + 362 + nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv); 363 + 364 + ret = xt_check_match(&par, size, proto, inv); 365 + if (ret < 0) 366 + goto err; 367 + 368 + return 0; 369 + err: 370 + module_put(match->me); 371 + return ret; 372 + } 373 + 374 + static void 375 + nft_match_destroy(const struct nft_expr *expr) 376 + { 377 + struct xt_match *match = expr->ops->data; 378 + 379 + module_put(match->me); 380 + } 381 + 382 + static int 383 + match_dump_info(struct sk_buff *skb, const struct xt_match *m, const void *in) 384 + { 385 + int ret; 386 + 387 + #ifdef CONFIG_COMPAT 388 + if (m->compat_to_user) { 389 + mm_segment_t old_fs; 390 + void *out; 391 + 392 + out = kmalloc(XT_ALIGN(m->matchsize), GFP_ATOMIC); 393 + if (out == NULL) 394 + return -ENOMEM; 395 + 396 + /* We want to reuse existing compat_to_user */ 397 + old_fs = get_fs(); 398 + set_fs(KERNEL_DS); 399 + m->compat_to_user(out, in); 400 + set_fs(old_fs); 401 + ret = nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(m->matchsize), out); 402 + kfree(out); 403 + } else 404 + #endif 405 + ret = nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(m->matchsize), in); 406 + 407 + return ret; 408 + } 409 + 410 + static inline int nft_compat_match_offset(struct xt_match *match) 411 + { 412 + #ifdef CONFIG_COMPAT 413 + return xt_compat_match_offset(match); 414 + #else 415 + return 0; 416 + #endif 417 + } 418 + 419 + static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr) 420 + { 421 + void *info = nft_expr_priv(expr); 422 + struct xt_match *match = expr->ops->data; 423 + 424 + if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) || 425 + nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) || 426 + match_dump_info(skb, match, info)) 427 + goto nla_put_failure; 428 + 429 + return 0; 430 + 431 + nla_put_failure: 432 + return -1; 433 + } 434 + 435 + static int nft_match_validate(const struct nft_ctx *ctx, 436 + const struct nft_expr *expr, 437 + const struct nft_data **data) 438 + { 439 + struct xt_match *match = expr->ops->data; 440 + unsigned int hook_mask = 0; 441 + 442 + if (ctx->chain->flags & NFT_BASE_CHAIN) { 443 + const struct nft_base_chain *basechain = 444 + nft_base_chain(ctx->chain); 445 + const struct nf_hook_ops *ops = &basechain->ops; 446 + 447 + hook_mask = 1 << ops->hooknum; 448 + if (hook_mask & match->hooks) 449 + return 0; 450 + 451 + /* This match is being called from an invalid chain */ 452 + return -EINVAL; 453 + } 454 + return 0; 455 + } 456 + 457 + static int 458 + nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, 459 + int event, u16 family, const char *name, 460 + int rev, int target) 461 + { 462 + struct nlmsghdr *nlh; 463 + struct nfgenmsg *nfmsg; 464 + unsigned int flags = portid ? NLM_F_MULTI : 0; 465 + 466 + event |= NFNL_SUBSYS_NFT_COMPAT << 8; 467 + nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); 468 + if (nlh == NULL) 469 + goto nlmsg_failure; 470 + 471 + nfmsg = nlmsg_data(nlh); 472 + nfmsg->nfgen_family = family; 473 + nfmsg->version = NFNETLINK_V0; 474 + nfmsg->res_id = 0; 475 + 476 + if (nla_put_string(skb, NFTA_COMPAT_NAME, name) || 477 + nla_put_be32(skb, NFTA_COMPAT_REV, htonl(rev)) || 478 + nla_put_be32(skb, NFTA_COMPAT_TYPE, htonl(target))) 479 + goto nla_put_failure; 480 + 481 + nlmsg_end(skb, nlh); 482 + return skb->len; 483 + 484 + nlmsg_failure: 485 + nla_put_failure: 486 + nlmsg_cancel(skb, nlh); 487 + return -1; 488 + } 489 + 490 + static int 491 + nfnl_compat_get(struct sock *nfnl, struct sk_buff *skb, 492 + const struct nlmsghdr *nlh, const struct nlattr * const tb[]) 493 + { 494 + int ret = 0, target; 495 + struct nfgenmsg *nfmsg; 496 + const char *fmt; 497 + const char *name; 498 + u32 rev; 499 + struct sk_buff *skb2; 500 + 501 + if (tb[NFTA_COMPAT_NAME] == NULL || 502 + tb[NFTA_COMPAT_REV] == NULL || 503 + tb[NFTA_COMPAT_TYPE] == NULL) 504 + return -EINVAL; 505 + 506 + name = nla_data(tb[NFTA_COMPAT_NAME]); 507 + rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV])); 508 + target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE])); 509 + 510 + nfmsg = nlmsg_data(nlh); 511 + 512 + switch(nfmsg->nfgen_family) { 513 + case AF_INET: 514 + fmt = "ipt_%s"; 515 + break; 516 + case AF_INET6: 517 + fmt = "ip6t_%s"; 518 + break; 519 + default: 520 + pr_err("nft_compat: unsupported protocol %d\n", 521 + nfmsg->nfgen_family); 522 + return -EINVAL; 523 + } 524 + 525 + try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name, 526 + rev, target, &ret), 527 + fmt, name); 528 + 529 + if (ret < 0) 530 + return ret; 531 + 532 + skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 533 + if (skb2 == NULL) 534 + return -ENOMEM; 535 + 536 + /* include the best revision for this extension in the message */ 537 + if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid, 538 + nlh->nlmsg_seq, 539 + NFNL_MSG_TYPE(nlh->nlmsg_type), 540 + NFNL_MSG_COMPAT_GET, 541 + nfmsg->nfgen_family, 542 + name, ret, target) <= 0) { 543 + kfree_skb(skb2); 544 + return -ENOSPC; 545 + } 546 + 547 + ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, 548 + MSG_DONTWAIT); 549 + if (ret > 0) 550 + ret = 0; 551 + 552 + return ret == -EAGAIN ? -ENOBUFS : ret; 553 + } 554 + 555 + static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = { 556 + [NFTA_COMPAT_NAME] = { .type = NLA_NUL_STRING, 557 + .len = NFT_COMPAT_NAME_MAX-1 }, 558 + [NFTA_COMPAT_REV] = { .type = NLA_U32 }, 559 + [NFTA_COMPAT_TYPE] = { .type = NLA_U32 }, 560 + }; 561 + 562 + static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = { 563 + [NFNL_MSG_COMPAT_GET] = { .call = nfnl_compat_get, 564 + .attr_count = NFTA_COMPAT_MAX, 565 + .policy = nfnl_compat_policy_get }, 566 + }; 567 + 568 + static const struct nfnetlink_subsystem nfnl_compat_subsys = { 569 + .name = "nft-compat", 570 + .subsys_id = NFNL_SUBSYS_NFT_COMPAT, 571 + .cb_count = NFNL_MSG_COMPAT_MAX, 572 + .cb = nfnl_nft_compat_cb, 573 + }; 574 + 575 + static LIST_HEAD(nft_match_list); 576 + 577 + struct nft_xt { 578 + struct list_head head; 579 + struct nft_expr_ops ops; 580 + }; 581 + 582 + static struct nft_expr_type nft_match_type; 583 + 584 + static const struct nft_expr_ops * 585 + nft_match_select_ops(const struct nft_ctx *ctx, 586 + const struct nlattr * const tb[]) 587 + { 588 + struct nft_xt *nft_match; 589 + struct xt_match *match; 590 + char *mt_name; 591 + __u32 rev, family; 592 + 593 + if (tb[NFTA_MATCH_NAME] == NULL || 594 + tb[NFTA_MATCH_REV] == NULL || 595 + tb[NFTA_MATCH_INFO] == NULL) 596 + return ERR_PTR(-EINVAL); 597 + 598 + mt_name = nla_data(tb[NFTA_MATCH_NAME]); 599 + rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV])); 600 + family = ctx->afi->family; 601 + 602 + /* Re-use the existing match if it's already loaded. */ 603 + list_for_each_entry(nft_match, &nft_match_list, head) { 604 + struct xt_match *match = nft_match->ops.data; 605 + 606 + if (strcmp(match->name, mt_name) == 0 && 607 + match->revision == rev && match->family == family) 608 + return &nft_match->ops; 609 + } 610 + 611 + match = xt_request_find_match(family, mt_name, rev); 612 + if (IS_ERR(match)) 613 + return ERR_PTR(-ENOENT); 614 + 615 + /* This is the first time we use this match, allocate operations */ 616 + nft_match = kzalloc(sizeof(struct nft_xt), GFP_KERNEL); 617 + if (nft_match == NULL) 618 + return ERR_PTR(-ENOMEM); 619 + 620 + nft_match->ops.type = &nft_match_type; 621 + nft_match->ops.size = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize) + 622 + nft_compat_match_offset(match)); 623 + nft_match->ops.eval = nft_match_eval; 624 + nft_match->ops.init = nft_match_init; 625 + nft_match->ops.destroy = nft_match_destroy; 626 + nft_match->ops.dump = nft_match_dump; 627 + nft_match->ops.validate = nft_match_validate; 628 + nft_match->ops.data = match; 629 + 630 + list_add(&nft_match->head, &nft_match_list); 631 + 632 + return &nft_match->ops; 633 + } 634 + 635 + static void nft_match_release(void) 636 + { 637 + struct nft_xt *nft_match; 638 + 639 + list_for_each_entry(nft_match, &nft_match_list, head) 640 + kfree(nft_match); 641 + } 642 + 643 + static struct nft_expr_type nft_match_type __read_mostly = { 644 + .name = "match", 645 + .select_ops = nft_match_select_ops, 646 + .policy = nft_match_policy, 647 + .maxattr = NFTA_MATCH_MAX, 648 + .owner = THIS_MODULE, 649 + }; 650 + 651 + static LIST_HEAD(nft_target_list); 652 + 653 + static struct nft_expr_type nft_target_type; 654 + 655 + static const struct nft_expr_ops * 656 + nft_target_select_ops(const struct nft_ctx *ctx, 657 + const struct nlattr * const tb[]) 658 + { 659 + struct nft_xt *nft_target; 660 + struct xt_target *target; 661 + char *tg_name; 662 + __u32 rev, family; 663 + 664 + if (tb[NFTA_TARGET_NAME] == NULL || 665 + tb[NFTA_TARGET_REV] == NULL || 666 + tb[NFTA_TARGET_INFO] == NULL) 667 + return ERR_PTR(-EINVAL); 668 + 669 + tg_name = nla_data(tb[NFTA_TARGET_NAME]); 670 + rev = ntohl(nla_get_be32(tb[NFTA_TARGET_REV])); 671 + family = ctx->afi->family; 672 + 673 + /* Re-use the existing target if it's already loaded. */ 674 + list_for_each_entry(nft_target, &nft_match_list, head) { 675 + struct xt_target *target = nft_target->ops.data; 676 + 677 + if (strcmp(target->name, tg_name) == 0 && 678 + target->revision == rev && target->family == family) 679 + return &nft_target->ops; 680 + } 681 + 682 + target = xt_request_find_target(family, tg_name, rev); 683 + if (IS_ERR(target)) 684 + return ERR_PTR(-ENOENT); 685 + 686 + /* This is the first time we use this target, allocate operations */ 687 + nft_target = kzalloc(sizeof(struct nft_xt), GFP_KERNEL); 688 + if (nft_target == NULL) 689 + return ERR_PTR(-ENOMEM); 690 + 691 + nft_target->ops.type = &nft_target_type; 692 + nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize) + 693 + nft_compat_target_offset(target)); 694 + nft_target->ops.eval = nft_target_eval; 695 + nft_target->ops.init = nft_target_init; 696 + nft_target->ops.destroy = nft_target_destroy; 697 + nft_target->ops.dump = nft_target_dump; 698 + nft_target->ops.validate = nft_target_validate; 699 + nft_target->ops.data = target; 700 + 701 + list_add(&nft_target->head, &nft_target_list); 702 + 703 + return &nft_target->ops; 704 + } 705 + 706 + static void nft_target_release(void) 707 + { 708 + struct nft_xt *nft_target; 709 + 710 + list_for_each_entry(nft_target, &nft_target_list, head) 711 + kfree(nft_target); 712 + } 713 + 714 + static struct nft_expr_type nft_target_type __read_mostly = { 715 + .name = "target", 716 + .select_ops = nft_target_select_ops, 717 + .policy = nft_target_policy, 718 + .maxattr = NFTA_TARGET_MAX, 719 + .owner = THIS_MODULE, 720 + }; 721 + 722 + static int __init nft_compat_module_init(void) 723 + { 724 + int ret; 725 + 726 + ret = nft_register_expr(&nft_match_type); 727 + if (ret < 0) 728 + return ret; 729 + 730 + ret = nft_register_expr(&nft_target_type); 731 + if (ret < 0) 732 + goto err_match; 733 + 734 + ret = nfnetlink_subsys_register(&nfnl_compat_subsys); 735 + if (ret < 0) { 736 + pr_err("nft_compat: cannot register with nfnetlink.\n"); 737 + goto err_target; 738 + } 739 + 740 + pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n"); 741 + 742 + return ret; 743 + 744 + err_target: 745 + nft_unregister_expr(&nft_target_type); 746 + err_match: 747 + nft_unregister_expr(&nft_match_type); 748 + return ret; 749 + } 750 + 751 + static void __exit nft_compat_module_exit(void) 752 + { 753 + nfnetlink_subsys_unregister(&nfnl_compat_subsys); 754 + nft_unregister_expr(&nft_target_type); 755 + nft_unregister_expr(&nft_match_type); 756 + nft_match_release(); 757 + nft_target_release(); 758 + } 759 + 760 + MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT); 761 + 762 + module_init(nft_compat_module_init); 763 + module_exit(nft_compat_module_exit); 764 + 765 + MODULE_LICENSE("GPL"); 766 + MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 767 + MODULE_ALIAS_NFT_EXPR("match"); 768 + MODULE_ALIAS_NFT_EXPR("target");
+7 -5
net/netfilter/nft_immediate.c
··· 90 90 return -1; 91 91 } 92 92 93 - static const struct nft_data *nft_immediate_get_verdict(const struct nft_expr *expr) 93 + static int nft_immediate_validate(const struct nft_ctx *ctx, 94 + const struct nft_expr *expr, 95 + const struct nft_data **data) 94 96 { 95 97 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 96 98 97 99 if (priv->dreg == NFT_REG_VERDICT) 98 - return &priv->data; 99 - else 100 - return NULL; 100 + *data = &priv->data; 101 + 102 + return 0; 101 103 } 102 104 103 105 static struct nft_expr_type nft_imm_type; ··· 110 108 .init = nft_immediate_init, 111 109 .destroy = nft_immediate_destroy, 112 110 .dump = nft_immediate_dump, 113 - .get_verdict = nft_immediate_get_verdict, 111 + .validate = nft_immediate_validate, 114 112 }; 115 113 116 114 static struct nft_expr_type nft_imm_type __read_mostly = {
+3 -1
net/netfilter/nft_payload.c
··· 107 107 .dump = nft_payload_dump, 108 108 }; 109 109 110 - static const struct nft_expr_ops *nft_payload_select_ops(const struct nlattr * const tb[]) 110 + static const struct nft_expr_ops * 111 + nft_payload_select_ops(const struct nft_ctx *ctx, 112 + const struct nlattr * const tb[]) 111 113 { 112 114 enum nft_payload_bases base; 113 115 unsigned int offset, len;