diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/bridge/netfilter/nf_tables_bridge.c | 44 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nf_tables_arp.c | 44 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nf_tables_ipv4.c | 60 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nft_chain_nat_ipv4.c | 10 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nft_chain_route_ipv4.c | 10 | ||||
| -rw-r--r-- | net/ipv6/netfilter/nf_tables_ipv6.c | 65 | ||||
| -rw-r--r-- | net/ipv6/netfilter/nft_chain_nat_ipv6.c | 10 | ||||
| -rw-r--r-- | net/ipv6/netfilter/nft_chain_route_ipv6.c | 10 | ||||
| -rw-r--r-- | net/netfilter/Kconfig | 8 | ||||
| -rw-r--r-- | net/netfilter/Makefile | 1 | ||||
| -rw-r--r-- | net/netfilter/nf_tables_api.c | 223 | ||||
| -rw-r--r-- | net/netfilter/nf_tables_core.c | 6 | ||||
| -rw-r--r-- | net/netfilter/nf_tables_inet.c | 104 | ||||
| -rw-r--r-- | net/netfilter/nft_compat.c | 8 | ||||
| -rw-r--r-- | net/netfilter/nft_ct.c | 199 | ||||
| -rw-r--r-- | net/netfilter/nft_log.c | 2 | ||||
| -rw-r--r-- | net/netfilter/nft_meta.c | 11 | ||||
| -rw-r--r-- | net/netfilter/nft_reject.c | 9 |
18 files changed, 547 insertions, 277 deletions
diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c index cf54b22818c8..5bcc0d8b31f2 100644 --- a/net/bridge/netfilter/nf_tables_bridge.c +++ b/net/bridge/netfilter/nf_tables_bridge.c | |||
| @@ -14,10 +14,30 @@ | |||
| 14 | #include <linux/netfilter_bridge.h> | 14 | #include <linux/netfilter_bridge.h> |
| 15 | #include <net/netfilter/nf_tables.h> | 15 | #include <net/netfilter/nf_tables.h> |
| 16 | 16 | ||
| 17 | static unsigned int | ||
| 18 | nft_do_chain_bridge(const struct nf_hook_ops *ops, | ||
| 19 | struct sk_buff *skb, | ||
| 20 | const struct net_device *in, | ||
| 21 | const struct net_device *out, | ||
| 22 | int (*okfn)(struct sk_buff *)) | ||
| 23 | { | ||
| 24 | struct nft_pktinfo pkt; | ||
| 25 | |||
| 26 | nft_set_pktinfo(&pkt, ops, skb, in, out); | ||
| 27 | |||
| 28 | return nft_do_chain(&pkt, ops); | ||
| 29 | } | ||
| 30 | |||
| 17 | static struct nft_af_info nft_af_bridge __read_mostly = { | 31 | static struct nft_af_info nft_af_bridge __read_mostly = { |
| 18 | .family = NFPROTO_BRIDGE, | 32 | .family = NFPROTO_BRIDGE, |
| 19 | .nhooks = NF_BR_NUMHOOKS, | 33 | .nhooks = NF_BR_NUMHOOKS, |
| 20 | .owner = THIS_MODULE, | 34 | .owner = THIS_MODULE, |
| 35 | .nops = 1, | ||
| 36 | .hooks = { | ||
| 37 | [NF_BR_LOCAL_IN] = nft_do_chain_bridge, | ||
| 38 | [NF_BR_FORWARD] = nft_do_chain_bridge, | ||
| 39 | [NF_BR_LOCAL_OUT] = nft_do_chain_bridge, | ||
| 40 | }, | ||
| 21 | }; | 41 | }; |
| 22 | 42 | ||
| 23 | static int nf_tables_bridge_init_net(struct net *net) | 43 | static int nf_tables_bridge_init_net(struct net *net) |
| @@ -48,32 +68,14 @@ static struct pernet_operations nf_tables_bridge_net_ops = { | |||
| 48 | .exit = nf_tables_bridge_exit_net, | 68 | .exit = nf_tables_bridge_exit_net, |
| 49 | }; | 69 | }; |
| 50 | 70 | ||
| 51 | static unsigned int | 71 | static const struct nf_chain_type filter_bridge = { |
| 52 | nft_do_chain_bridge(const struct nf_hook_ops *ops, | ||
| 53 | struct sk_buff *skb, | ||
| 54 | const struct net_device *in, | ||
| 55 | const struct net_device *out, | ||
| 56 | int (*okfn)(struct sk_buff *)) | ||
| 57 | { | ||
| 58 | struct nft_pktinfo pkt; | ||
| 59 | |||
| 60 | nft_set_pktinfo(&pkt, ops, skb, in, out); | ||
| 61 | |||
| 62 | return nft_do_chain_pktinfo(&pkt, ops); | ||
| 63 | } | ||
| 64 | |||
| 65 | static struct nf_chain_type filter_bridge = { | ||
| 66 | .family = NFPROTO_BRIDGE, | ||
| 67 | .name = "filter", | 72 | .name = "filter", |
| 68 | .type = NFT_CHAIN_T_DEFAULT, | 73 | .type = NFT_CHAIN_T_DEFAULT, |
| 74 | .family = NFPROTO_BRIDGE, | ||
| 75 | .owner = THIS_MODULE, | ||
| 69 | .hook_mask = (1 << NF_BR_LOCAL_IN) | | 76 | .hook_mask = (1 << NF_BR_LOCAL_IN) | |
| 70 | (1 << NF_BR_FORWARD) | | 77 | (1 << NF_BR_FORWARD) | |
| 71 | (1 << NF_BR_LOCAL_OUT), | 78 | (1 << NF_BR_LOCAL_OUT), |
| 72 | .fn = { | ||
| 73 | [NF_BR_LOCAL_IN] = nft_do_chain_bridge, | ||
| 74 | [NF_BR_FORWARD] = nft_do_chain_bridge, | ||
| 75 | [NF_BR_LOCAL_OUT] = nft_do_chain_bridge, | ||
| 76 | }, | ||
| 77 | }; | 79 | }; |
| 78 | 80 | ||
| 79 | static int __init nf_tables_bridge_init(void) | 81 | static int __init nf_tables_bridge_init(void) |
diff --git a/net/ipv4/netfilter/nf_tables_arp.c b/net/ipv4/netfilter/nf_tables_arp.c index 3e67ef1c676f..19412a4063fb 100644 --- a/net/ipv4/netfilter/nf_tables_arp.c +++ b/net/ipv4/netfilter/nf_tables_arp.c | |||
| @@ -14,10 +14,30 @@ | |||
| 14 | #include <linux/netfilter_arp.h> | 14 | #include <linux/netfilter_arp.h> |
| 15 | #include <net/netfilter/nf_tables.h> | 15 | #include <net/netfilter/nf_tables.h> |
| 16 | 16 | ||
| 17 | static unsigned int | ||
| 18 | nft_do_chain_arp(const struct nf_hook_ops *ops, | ||
| 19 | struct sk_buff *skb, | ||
| 20 | const struct net_device *in, | ||
| 21 | const struct net_device *out, | ||
| 22 | int (*okfn)(struct sk_buff *)) | ||
| 23 | { | ||
| 24 | struct nft_pktinfo pkt; | ||
| 25 | |||
| 26 | nft_set_pktinfo(&pkt, ops, skb, in, out); | ||
| 27 | |||
| 28 | return nft_do_chain(&pkt, ops); | ||
| 29 | } | ||
| 30 | |||
| 17 | static struct nft_af_info nft_af_arp __read_mostly = { | 31 | static struct nft_af_info nft_af_arp __read_mostly = { |
| 18 | .family = NFPROTO_ARP, | 32 | .family = NFPROTO_ARP, |
| 19 | .nhooks = NF_ARP_NUMHOOKS, | 33 | .nhooks = NF_ARP_NUMHOOKS, |
| 20 | .owner = THIS_MODULE, | 34 | .owner = THIS_MODULE, |
| 35 | .nops = 1, | ||
| 36 | .hooks = { | ||
| 37 | [NF_ARP_IN] = nft_do_chain_arp, | ||
| 38 | [NF_ARP_OUT] = nft_do_chain_arp, | ||
| 39 | [NF_ARP_FORWARD] = nft_do_chain_arp, | ||
| 40 | }, | ||
| 21 | }; | 41 | }; |
| 22 | 42 | ||
| 23 | static int nf_tables_arp_init_net(struct net *net) | 43 | static int nf_tables_arp_init_net(struct net *net) |
| @@ -48,32 +68,14 @@ static struct pernet_operations nf_tables_arp_net_ops = { | |||
| 48 | .exit = nf_tables_arp_exit_net, | 68 | .exit = nf_tables_arp_exit_net, |
| 49 | }; | 69 | }; |
| 50 | 70 | ||
| 51 | static unsigned int | 71 | static const struct nf_chain_type filter_arp = { |
| 52 | nft_do_chain_arp(const struct nf_hook_ops *ops, | ||
| 53 | struct sk_buff *skb, | ||
| 54 | const struct net_device *in, | ||
| 55 | const struct net_device *out, | ||
| 56 | int (*okfn)(struct sk_buff *)) | ||
| 57 | { | ||
| 58 | struct nft_pktinfo pkt; | ||
| 59 | |||
| 60 | nft_set_pktinfo(&pkt, ops, skb, in, out); | ||
| 61 | |||
| 62 | return nft_do_chain_pktinfo(&pkt, ops); | ||
| 63 | } | ||
| 64 | |||
| 65 | static struct nf_chain_type filter_arp = { | ||
| 66 | .family = NFPROTO_ARP, | ||
| 67 | .name = "filter", | 72 | .name = "filter", |
| 68 | .type = NFT_CHAIN_T_DEFAULT, | 73 | .type = NFT_CHAIN_T_DEFAULT, |
| 74 | .family = NFPROTO_ARP, | ||
| 75 | .owner = THIS_MODULE, | ||
| 69 | .hook_mask = (1 << NF_ARP_IN) | | 76 | .hook_mask = (1 << NF_ARP_IN) | |
| 70 | (1 << NF_ARP_OUT) | | 77 | (1 << NF_ARP_OUT) | |
| 71 | (1 << NF_ARP_FORWARD), | 78 | (1 << NF_ARP_FORWARD), |
| 72 | .fn = { | ||
| 73 | [NF_ARP_IN] = nft_do_chain_arp, | ||
| 74 | [NF_ARP_OUT] = nft_do_chain_arp, | ||
| 75 | [NF_ARP_FORWARD] = nft_do_chain_arp, | ||
| 76 | }, | ||
| 77 | }; | 79 | }; |
| 78 | 80 | ||
| 79 | static int __init nf_tables_arp_init(void) | 81 | static int __init nf_tables_arp_init(void) |
diff --git a/net/ipv4/netfilter/nf_tables_ipv4.c b/net/ipv4/netfilter/nf_tables_ipv4.c index 0f4cbfeb19bd..6820c8c40842 100644 --- a/net/ipv4/netfilter/nf_tables_ipv4.c +++ b/net/ipv4/netfilter/nf_tables_ipv4.c | |||
| @@ -18,14 +18,25 @@ | |||
| 18 | #include <net/ip.h> | 18 | #include <net/ip.h> |
| 19 | #include <net/netfilter/nf_tables_ipv4.h> | 19 | #include <net/netfilter/nf_tables_ipv4.h> |
| 20 | 20 | ||
| 21 | static unsigned int nft_do_chain_ipv4(const struct nf_hook_ops *ops, | ||
| 22 | struct sk_buff *skb, | ||
| 23 | const struct net_device *in, | ||
| 24 | const struct net_device *out, | ||
| 25 | int (*okfn)(struct sk_buff *)) | ||
| 26 | { | ||
| 27 | struct nft_pktinfo pkt; | ||
| 28 | |||
| 29 | nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); | ||
| 30 | |||
| 31 | return nft_do_chain(&pkt, ops); | ||
| 32 | } | ||
| 33 | |||
| 21 | static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, | 34 | static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, |
| 22 | struct sk_buff *skb, | 35 | struct sk_buff *skb, |
| 23 | const struct net_device *in, | 36 | const struct net_device *in, |
| 24 | const struct net_device *out, | 37 | const struct net_device *out, |
| 25 | int (*okfn)(struct sk_buff *)) | 38 | int (*okfn)(struct sk_buff *)) |
| 26 | { | 39 | { |
| 27 | struct nft_pktinfo pkt; | ||
| 28 | |||
| 29 | if (unlikely(skb->len < sizeof(struct iphdr) || | 40 | if (unlikely(skb->len < sizeof(struct iphdr) || |
| 30 | ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) { | 41 | ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) { |
| 31 | if (net_ratelimit()) | 42 | if (net_ratelimit()) |
| @@ -33,19 +44,24 @@ static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, | |||
| 33 | "packet\n"); | 44 | "packet\n"); |
| 34 | return NF_ACCEPT; | 45 | return NF_ACCEPT; |
| 35 | } | 46 | } |
| 36 | nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); | ||
| 37 | 47 | ||
| 38 | return nft_do_chain_pktinfo(&pkt, ops); | 48 | return nft_do_chain_ipv4(ops, skb, in, out, okfn); |
| 39 | } | 49 | } |
| 40 | 50 | ||
| 41 | static struct nft_af_info nft_af_ipv4 __read_mostly = { | 51 | struct nft_af_info nft_af_ipv4 __read_mostly = { |
| 42 | .family = NFPROTO_IPV4, | 52 | .family = NFPROTO_IPV4, |
| 43 | .nhooks = NF_INET_NUMHOOKS, | 53 | .nhooks = NF_INET_NUMHOOKS, |
| 44 | .owner = THIS_MODULE, | 54 | .owner = THIS_MODULE, |
| 55 | .nops = 1, | ||
| 45 | .hooks = { | 56 | .hooks = { |
| 57 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv4, | ||
| 46 | [NF_INET_LOCAL_OUT] = nft_ipv4_output, | 58 | [NF_INET_LOCAL_OUT] = nft_ipv4_output, |
| 59 | [NF_INET_FORWARD] = nft_do_chain_ipv4, | ||
| 60 | [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4, | ||
| 61 | [NF_INET_POST_ROUTING] = nft_do_chain_ipv4, | ||
| 47 | }, | 62 | }, |
| 48 | }; | 63 | }; |
| 64 | EXPORT_SYMBOL_GPL(nft_af_ipv4); | ||
| 49 | 65 | ||
| 50 | static int nf_tables_ipv4_init_net(struct net *net) | 66 | static int nf_tables_ipv4_init_net(struct net *net) |
| 51 | { | 67 | { |
| @@ -75,42 +91,28 @@ static struct pernet_operations nf_tables_ipv4_net_ops = { | |||
| 75 | .exit = nf_tables_ipv4_exit_net, | 91 | .exit = nf_tables_ipv4_exit_net, |
| 76 | }; | 92 | }; |
| 77 | 93 | ||
| 78 | static unsigned int | 94 | static const struct nf_chain_type filter_ipv4 = { |
| 79 | nft_do_chain_ipv4(const struct nf_hook_ops *ops, | ||
| 80 | struct sk_buff *skb, | ||
| 81 | const struct net_device *in, | ||
| 82 | const struct net_device *out, | ||
| 83 | int (*okfn)(struct sk_buff *)) | ||
| 84 | { | ||
| 85 | struct nft_pktinfo pkt; | ||
| 86 | |||
| 87 | nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); | ||
| 88 | |||
| 89 | return nft_do_chain_pktinfo(&pkt, ops); | ||
| 90 | } | ||
| 91 | |||
| 92 | static struct nf_chain_type filter_ipv4 = { | ||
| 93 | .family = NFPROTO_IPV4, | ||
| 94 | .name = "filter", | 95 | .name = "filter", |
| 95 | .type = NFT_CHAIN_T_DEFAULT, | 96 | .type = NFT_CHAIN_T_DEFAULT, |
| 97 | .family = NFPROTO_IPV4, | ||
| 98 | .owner = THIS_MODULE, | ||
| 96 | .hook_mask = (1 << NF_INET_LOCAL_IN) | | 99 | .hook_mask = (1 << NF_INET_LOCAL_IN) | |
| 97 | (1 << NF_INET_LOCAL_OUT) | | 100 | (1 << NF_INET_LOCAL_OUT) | |
| 98 | (1 << NF_INET_FORWARD) | | 101 | (1 << NF_INET_FORWARD) | |
| 99 | (1 << NF_INET_PRE_ROUTING) | | 102 | (1 << NF_INET_PRE_ROUTING) | |
| 100 | (1 << NF_INET_POST_ROUTING), | 103 | (1 << NF_INET_POST_ROUTING), |
| 101 | .fn = { | ||
| 102 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv4, | ||
| 103 | [NF_INET_LOCAL_OUT] = nft_ipv4_output, | ||
| 104 | [NF_INET_FORWARD] = nft_do_chain_ipv4, | ||
| 105 | [NF_INET_PRE_ROUTING] = nft_do_chain_ipv4, | ||
| 106 | [NF_INET_POST_ROUTING] = nft_do_chain_ipv4, | ||
| 107 | }, | ||
| 108 | }; | 104 | }; |
| 109 | 105 | ||
| 110 | static int __init nf_tables_ipv4_init(void) | 106 | static int __init nf_tables_ipv4_init(void) |
| 111 | { | 107 | { |
| 108 | int ret; | ||
| 109 | |||
| 112 | nft_register_chain_type(&filter_ipv4); | 110 | nft_register_chain_type(&filter_ipv4); |
| 113 | return register_pernet_subsys(&nf_tables_ipv4_net_ops); | 111 | ret = register_pernet_subsys(&nf_tables_ipv4_net_ops); |
| 112 | if (ret < 0) | ||
| 113 | nft_unregister_chain_type(&filter_ipv4); | ||
| 114 | |||
| 115 | return ret; | ||
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | static void __exit nf_tables_ipv4_exit(void) | 118 | static void __exit nf_tables_ipv4_exit(void) |
diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c index cf2c792cd971..b5b256d45e67 100644 --- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c +++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c | |||
| @@ -75,7 +75,7 @@ static unsigned int nf_nat_fn(const struct nf_hook_ops *ops, | |||
| 75 | 75 | ||
| 76 | nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); | 76 | nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); |
| 77 | 77 | ||
| 78 | ret = nft_do_chain_pktinfo(&pkt, ops); | 78 | ret = nft_do_chain(&pkt, ops); |
| 79 | if (ret != NF_ACCEPT) | 79 | if (ret != NF_ACCEPT) |
| 80 | return ret; | 80 | return ret; |
| 81 | if (!nf_nat_initialized(ct, maniptype)) { | 81 | if (!nf_nat_initialized(ct, maniptype)) { |
| @@ -164,21 +164,21 @@ static unsigned int nf_nat_output(const struct nf_hook_ops *ops, | |||
| 164 | return ret; | 164 | return ret; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | static struct nf_chain_type nft_chain_nat_ipv4 = { | 167 | static const struct nf_chain_type nft_chain_nat_ipv4 = { |
| 168 | .family = NFPROTO_IPV4, | ||
| 169 | .name = "nat", | 168 | .name = "nat", |
| 170 | .type = NFT_CHAIN_T_NAT, | 169 | .type = NFT_CHAIN_T_NAT, |
| 170 | .family = NFPROTO_IPV4, | ||
| 171 | .owner = THIS_MODULE, | ||
| 171 | .hook_mask = (1 << NF_INET_PRE_ROUTING) | | 172 | .hook_mask = (1 << NF_INET_PRE_ROUTING) | |
| 172 | (1 << NF_INET_POST_ROUTING) | | 173 | (1 << NF_INET_POST_ROUTING) | |
| 173 | (1 << NF_INET_LOCAL_OUT) | | 174 | (1 << NF_INET_LOCAL_OUT) | |
| 174 | (1 << NF_INET_LOCAL_IN), | 175 | (1 << NF_INET_LOCAL_IN), |
| 175 | .fn = { | 176 | .hooks = { |
| 176 | [NF_INET_PRE_ROUTING] = nf_nat_prerouting, | 177 | [NF_INET_PRE_ROUTING] = nf_nat_prerouting, |
| 177 | [NF_INET_POST_ROUTING] = nf_nat_postrouting, | 178 | [NF_INET_POST_ROUTING] = nf_nat_postrouting, |
| 178 | [NF_INET_LOCAL_OUT] = nf_nat_output, | 179 | [NF_INET_LOCAL_OUT] = nf_nat_output, |
| 179 | [NF_INET_LOCAL_IN] = nf_nat_fn, | 180 | [NF_INET_LOCAL_IN] = nf_nat_fn, |
| 180 | }, | 181 | }, |
| 181 | .me = THIS_MODULE, | ||
| 182 | }; | 182 | }; |
| 183 | 183 | ||
| 184 | static int __init nft_chain_nat_init(void) | 184 | static int __init nft_chain_nat_init(void) |
diff --git a/net/ipv4/netfilter/nft_chain_route_ipv4.c b/net/ipv4/netfilter/nft_chain_route_ipv4.c index 4e6bf9a3d7aa..125b66766c0a 100644 --- a/net/ipv4/netfilter/nft_chain_route_ipv4.c +++ b/net/ipv4/netfilter/nft_chain_route_ipv4.c | |||
| @@ -47,7 +47,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, | |||
| 47 | daddr = iph->daddr; | 47 | daddr = iph->daddr; |
| 48 | tos = iph->tos; | 48 | tos = iph->tos; |
| 49 | 49 | ||
| 50 | ret = nft_do_chain_pktinfo(&pkt, ops); | 50 | ret = nft_do_chain(&pkt, ops); |
| 51 | if (ret != NF_DROP && ret != NF_QUEUE) { | 51 | if (ret != NF_DROP && ret != NF_QUEUE) { |
| 52 | iph = ip_hdr(skb); | 52 | iph = ip_hdr(skb); |
| 53 | 53 | ||
| @@ -61,15 +61,15 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, | |||
| 61 | return ret; | 61 | return ret; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static struct nf_chain_type nft_chain_route_ipv4 = { | 64 | static const struct nf_chain_type nft_chain_route_ipv4 = { |
| 65 | .family = NFPROTO_IPV4, | ||
| 66 | .name = "route", | 65 | .name = "route", |
| 67 | .type = NFT_CHAIN_T_ROUTE, | 66 | .type = NFT_CHAIN_T_ROUTE, |
| 67 | .family = NFPROTO_IPV4, | ||
| 68 | .owner = THIS_MODULE, | ||
| 68 | .hook_mask = (1 << NF_INET_LOCAL_OUT), | 69 | .hook_mask = (1 << NF_INET_LOCAL_OUT), |
| 69 | .fn = { | 70 | .hooks = { |
| 70 | [NF_INET_LOCAL_OUT] = nf_route_table_hook, | 71 | [NF_INET_LOCAL_OUT] = nf_route_table_hook, |
| 71 | }, | 72 | }, |
| 72 | .me = THIS_MODULE, | ||
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | static int __init nft_chain_route_init(void) | 75 | static int __init nft_chain_route_init(void) |
diff --git a/net/ipv6/netfilter/nf_tables_ipv6.c b/net/ipv6/netfilter/nf_tables_ipv6.c index d77db8a13505..0d812b31277d 100644 --- a/net/ipv6/netfilter/nf_tables_ipv6.c +++ b/net/ipv6/netfilter/nf_tables_ipv6.c | |||
| @@ -16,34 +16,51 @@ | |||
| 16 | #include <net/netfilter/nf_tables.h> | 16 | #include <net/netfilter/nf_tables.h> |
| 17 | #include <net/netfilter/nf_tables_ipv6.h> | 17 | #include <net/netfilter/nf_tables_ipv6.h> |
| 18 | 18 | ||
| 19 | static unsigned int nft_do_chain_ipv6(const struct nf_hook_ops *ops, | ||
| 20 | struct sk_buff *skb, | ||
| 21 | const struct net_device *in, | ||
| 22 | const struct net_device *out, | ||
| 23 | int (*okfn)(struct sk_buff *)) | ||
| 24 | { | ||
| 25 | struct nft_pktinfo pkt; | ||
| 26 | |||
| 27 | /* malformed packet, drop it */ | ||
| 28 | if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) | ||
| 29 | return NF_DROP; | ||
| 30 | |||
| 31 | return nft_do_chain(&pkt, ops); | ||
| 32 | } | ||
| 33 | |||
| 19 | static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops, | 34 | static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops, |
| 20 | struct sk_buff *skb, | 35 | struct sk_buff *skb, |
| 21 | const struct net_device *in, | 36 | const struct net_device *in, |
| 22 | const struct net_device *out, | 37 | const struct net_device *out, |
| 23 | int (*okfn)(struct sk_buff *)) | 38 | int (*okfn)(struct sk_buff *)) |
| 24 | { | 39 | { |
| 25 | struct nft_pktinfo pkt; | ||
| 26 | |||
| 27 | if (unlikely(skb->len < sizeof(struct ipv6hdr))) { | 40 | if (unlikely(skb->len < sizeof(struct ipv6hdr))) { |
| 28 | if (net_ratelimit()) | 41 | if (net_ratelimit()) |
| 29 | pr_info("nf_tables_ipv6: ignoring short SOCK_RAW " | 42 | pr_info("nf_tables_ipv6: ignoring short SOCK_RAW " |
| 30 | "packet\n"); | 43 | "packet\n"); |
| 31 | return NF_ACCEPT; | 44 | return NF_ACCEPT; |
| 32 | } | 45 | } |
| 33 | if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) | ||
| 34 | return NF_DROP; | ||
| 35 | 46 | ||
| 36 | return nft_do_chain_pktinfo(&pkt, ops); | 47 | return nft_do_chain_ipv6(ops, skb, in, out, okfn); |
| 37 | } | 48 | } |
| 38 | 49 | ||
| 39 | static struct nft_af_info nft_af_ipv6 __read_mostly = { | 50 | struct nft_af_info nft_af_ipv6 __read_mostly = { |
| 40 | .family = NFPROTO_IPV6, | 51 | .family = NFPROTO_IPV6, |
| 41 | .nhooks = NF_INET_NUMHOOKS, | 52 | .nhooks = NF_INET_NUMHOOKS, |
| 42 | .owner = THIS_MODULE, | 53 | .owner = THIS_MODULE, |
| 54 | .nops = 1, | ||
| 43 | .hooks = { | 55 | .hooks = { |
| 56 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, | ||
| 44 | [NF_INET_LOCAL_OUT] = nft_ipv6_output, | 57 | [NF_INET_LOCAL_OUT] = nft_ipv6_output, |
| 58 | [NF_INET_FORWARD] = nft_do_chain_ipv6, | ||
| 59 | [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6, | ||
| 60 | [NF_INET_POST_ROUTING] = nft_do_chain_ipv6, | ||
| 45 | }, | 61 | }, |
| 46 | }; | 62 | }; |
| 63 | EXPORT_SYMBOL_GPL(nft_af_ipv6); | ||
| 47 | 64 | ||
| 48 | static int nf_tables_ipv6_init_net(struct net *net) | 65 | static int nf_tables_ipv6_init_net(struct net *net) |
| 49 | { | 66 | { |
| @@ -73,44 +90,28 @@ static struct pernet_operations nf_tables_ipv6_net_ops = { | |||
| 73 | .exit = nf_tables_ipv6_exit_net, | 90 | .exit = nf_tables_ipv6_exit_net, |
| 74 | }; | 91 | }; |
| 75 | 92 | ||
| 76 | static unsigned int | 93 | static const struct nf_chain_type filter_ipv6 = { |
| 77 | nft_do_chain_ipv6(const struct nf_hook_ops *ops, | ||
| 78 | struct sk_buff *skb, | ||
| 79 | const struct net_device *in, | ||
| 80 | const struct net_device *out, | ||
| 81 | int (*okfn)(struct sk_buff *)) | ||
| 82 | { | ||
| 83 | struct nft_pktinfo pkt; | ||
| 84 | |||
| 85 | /* malformed packet, drop it */ | ||
| 86 | if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) | ||
| 87 | return NF_DROP; | ||
| 88 | |||
| 89 | return nft_do_chain_pktinfo(&pkt, ops); | ||
| 90 | } | ||
| 91 | |||
| 92 | static struct nf_chain_type filter_ipv6 = { | ||
| 93 | .family = NFPROTO_IPV6, | ||
| 94 | .name = "filter", | 94 | .name = "filter", |
| 95 | .type = NFT_CHAIN_T_DEFAULT, | 95 | .type = NFT_CHAIN_T_DEFAULT, |
| 96 | .family = NFPROTO_IPV6, | ||
| 97 | .owner = THIS_MODULE, | ||
| 96 | .hook_mask = (1 << NF_INET_LOCAL_IN) | | 98 | .hook_mask = (1 << NF_INET_LOCAL_IN) | |
| 97 | (1 << NF_INET_LOCAL_OUT) | | 99 | (1 << NF_INET_LOCAL_OUT) | |
| 98 | (1 << NF_INET_FORWARD) | | 100 | (1 << NF_INET_FORWARD) | |
| 99 | (1 << NF_INET_PRE_ROUTING) | | 101 | (1 << NF_INET_PRE_ROUTING) | |
| 100 | (1 << NF_INET_POST_ROUTING), | 102 | (1 << NF_INET_POST_ROUTING), |
| 101 | .fn = { | ||
| 102 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, | ||
| 103 | [NF_INET_LOCAL_OUT] = nft_ipv6_output, | ||
| 104 | [NF_INET_FORWARD] = nft_do_chain_ipv6, | ||
| 105 | [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6, | ||
| 106 | [NF_INET_POST_ROUTING] = nft_do_chain_ipv6, | ||
| 107 | }, | ||
| 108 | }; | 103 | }; |
| 109 | 104 | ||
| 110 | static int __init nf_tables_ipv6_init(void) | 105 | static int __init nf_tables_ipv6_init(void) |
| 111 | { | 106 | { |
| 107 | int ret; | ||
| 108 | |||
| 112 | nft_register_chain_type(&filter_ipv6); | 109 | nft_register_chain_type(&filter_ipv6); |
| 113 | return register_pernet_subsys(&nf_tables_ipv6_net_ops); | 110 | ret = register_pernet_subsys(&nf_tables_ipv6_net_ops); |
| 111 | if (ret < 0) | ||
| 112 | nft_unregister_chain_type(&filter_ipv6); | ||
| 113 | |||
| 114 | return ret; | ||
| 114 | } | 115 | } |
| 115 | 116 | ||
| 116 | static void __exit nf_tables_ipv6_exit(void) | 117 | static void __exit nf_tables_ipv6_exit(void) |
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c index e86dcd70dc76..9c3297a768fd 100644 --- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c | |||
| @@ -79,7 +79,7 @@ static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, | |||
| 79 | 79 | ||
| 80 | nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); | 80 | nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); |
| 81 | 81 | ||
| 82 | ret = nft_do_chain_pktinfo(&pkt, ops); | 82 | ret = nft_do_chain(&pkt, ops); |
| 83 | if (ret != NF_ACCEPT) | 83 | if (ret != NF_ACCEPT) |
| 84 | return ret; | 84 | return ret; |
| 85 | if (!nf_nat_initialized(ct, maniptype)) { | 85 | if (!nf_nat_initialized(ct, maniptype)) { |
| @@ -170,21 +170,21 @@ static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops, | |||
| 170 | return ret; | 170 | return ret; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | static struct nf_chain_type nft_chain_nat_ipv6 = { | 173 | static const struct nf_chain_type nft_chain_nat_ipv6 = { |
| 174 | .family = NFPROTO_IPV6, | ||
| 175 | .name = "nat", | 174 | .name = "nat", |
| 176 | .type = NFT_CHAIN_T_NAT, | 175 | .type = NFT_CHAIN_T_NAT, |
| 176 | .family = NFPROTO_IPV6, | ||
| 177 | .owner = THIS_MODULE, | ||
| 177 | .hook_mask = (1 << NF_INET_PRE_ROUTING) | | 178 | .hook_mask = (1 << NF_INET_PRE_ROUTING) | |
| 178 | (1 << NF_INET_POST_ROUTING) | | 179 | (1 << NF_INET_POST_ROUTING) | |
| 179 | (1 << NF_INET_LOCAL_OUT) | | 180 | (1 << NF_INET_LOCAL_OUT) | |
| 180 | (1 << NF_INET_LOCAL_IN), | 181 | (1 << NF_INET_LOCAL_IN), |
| 181 | .fn = { | 182 | .hooks = { |
| 182 | [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, | 183 | [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, |
| 183 | [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, | 184 | [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, |
| 184 | [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, | 185 | [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, |
| 185 | [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn, | 186 | [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn, |
| 186 | }, | 187 | }, |
| 187 | .me = THIS_MODULE, | ||
| 188 | }; | 188 | }; |
| 189 | 189 | ||
| 190 | static int __init nft_chain_nat_ipv6_init(void) | 190 | static int __init nft_chain_nat_ipv6_init(void) |
diff --git a/net/ipv6/netfilter/nft_chain_route_ipv6.c b/net/ipv6/netfilter/nft_chain_route_ipv6.c index 3fe40f0456ad..42031299585e 100644 --- a/net/ipv6/netfilter/nft_chain_route_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_route_ipv6.c | |||
| @@ -47,7 +47,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, | |||
| 47 | /* flowlabel and prio (includes version, which shouldn't change either */ | 47 | /* flowlabel and prio (includes version, which shouldn't change either */ |
| 48 | flowlabel = *((u32 *)ipv6_hdr(skb)); | 48 | flowlabel = *((u32 *)ipv6_hdr(skb)); |
| 49 | 49 | ||
| 50 | ret = nft_do_chain_pktinfo(&pkt, ops); | 50 | ret = nft_do_chain(&pkt, ops); |
| 51 | if (ret != NF_DROP && ret != NF_QUEUE && | 51 | if (ret != NF_DROP && ret != NF_QUEUE && |
| 52 | (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || | 52 | (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || |
| 53 | memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || | 53 | memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || |
| @@ -59,15 +59,15 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, | |||
| 59 | return ret; | 59 | return ret; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | static struct nf_chain_type nft_chain_route_ipv6 = { | 62 | static const struct nf_chain_type nft_chain_route_ipv6 = { |
| 63 | .family = NFPROTO_IPV6, | ||
| 64 | .name = "route", | 63 | .name = "route", |
| 65 | .type = NFT_CHAIN_T_ROUTE, | 64 | .type = NFT_CHAIN_T_ROUTE, |
| 65 | .family = NFPROTO_IPV6, | ||
| 66 | .owner = THIS_MODULE, | ||
| 66 | .hook_mask = (1 << NF_INET_LOCAL_OUT), | 67 | .hook_mask = (1 << NF_INET_LOCAL_OUT), |
| 67 | .fn = { | 68 | .hooks = { |
| 68 | [NF_INET_LOCAL_OUT] = nf_route_table_hook, | 69 | [NF_INET_LOCAL_OUT] = nf_route_table_hook, |
| 69 | }, | 70 | }, |
| 70 | .me = THIS_MODULE, | ||
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | static int __init nft_chain_route_init(void) | 73 | static int __init nft_chain_route_init(void) |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index c3b3b26c4c4e..37d2092705a7 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
| @@ -428,6 +428,14 @@ config NF_TABLES | |||
| 428 | 428 | ||
| 429 | To compile it as a module, choose M here. | 429 | To compile it as a module, choose M here. |
| 430 | 430 | ||
| 431 | config NF_TABLES_INET | ||
| 432 | depends on NF_TABLES | ||
| 433 | select NF_TABLES_IPV4 | ||
| 434 | select NF_TABLES_IPV6 | ||
| 435 | tristate "Netfilter nf_tables mixed IPv4/IPv6 tables support" | ||
| 436 | help | ||
| 437 | This option enables support for a mixed IPv4/IPv6 "inet" table. | ||
| 438 | |||
| 431 | config NFT_EXTHDR | 439 | config NFT_EXTHDR |
| 432 | depends on NF_TABLES | 440 | depends on NF_TABLES |
| 433 | tristate "Netfilter nf_tables IPv6 exthdr module" | 441 | tristate "Netfilter nf_tables IPv6 exthdr module" |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 78b4e1c9c595..74c066109334 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
| @@ -70,6 +70,7 @@ nf_tables-objs += nft_immediate.o nft_cmp.o nft_lookup.o | |||
| 70 | nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o | 70 | nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o |
| 71 | 71 | ||
| 72 | obj-$(CONFIG_NF_TABLES) += nf_tables.o | 72 | obj-$(CONFIG_NF_TABLES) += nf_tables.o |
| 73 | obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o | ||
| 73 | obj-$(CONFIG_NFT_COMPAT) += nft_compat.o | 74 | obj-$(CONFIG_NFT_COMPAT) += nft_compat.o |
| 74 | obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o | 75 | obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o |
| 75 | obj-$(CONFIG_NFT_META) += nft_meta.o | 76 | obj-$(CONFIG_NFT_META) += nft_meta.o |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 1fcef1ec1dc1..36add31e08e7 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
| @@ -124,37 +124,43 @@ static inline u64 nf_tables_alloc_handle(struct nft_table *table) | |||
| 124 | return ++table->hgenerator; | 124 | return ++table->hgenerator; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | static struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX]; | 127 | static const struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX]; |
| 128 | 128 | ||
| 129 | static int __nf_tables_chain_type_lookup(int family, const struct nlattr *nla) | 129 | static const struct nf_chain_type * |
| 130 | __nf_tables_chain_type_lookup(int family, const struct nlattr *nla) | ||
| 130 | { | 131 | { |
| 131 | int i; | 132 | int i; |
| 132 | 133 | ||
| 133 | for (i=0; i<NFT_CHAIN_T_MAX; i++) { | 134 | for (i = 0; i < NFT_CHAIN_T_MAX; i++) { |
| 134 | if (chain_type[family][i] != NULL && | 135 | if (chain_type[family][i] != NULL && |
| 135 | !nla_strcmp(nla, chain_type[family][i]->name)) | 136 | !nla_strcmp(nla, chain_type[family][i]->name)) |
| 136 | return i; | 137 | return chain_type[family][i]; |
| 137 | } | 138 | } |
| 138 | return -1; | 139 | return NULL; |
| 139 | } | 140 | } |
| 140 | 141 | ||
| 141 | static int nf_tables_chain_type_lookup(const struct nft_af_info *afi, | 142 | static const struct nf_chain_type * |
| 142 | const struct nlattr *nla, | 143 | nf_tables_chain_type_lookup(const struct nft_af_info *afi, |
| 143 | bool autoload) | 144 | const struct nlattr *nla, |
| 145 | bool autoload) | ||
| 144 | { | 146 | { |
| 145 | int type; | 147 | const struct nf_chain_type *type; |
| 146 | 148 | ||
| 147 | type = __nf_tables_chain_type_lookup(afi->family, nla); | 149 | type = __nf_tables_chain_type_lookup(afi->family, nla); |
| 150 | if (type != NULL) | ||
| 151 | return type; | ||
| 148 | #ifdef CONFIG_MODULES | 152 | #ifdef CONFIG_MODULES |
| 149 | if (type < 0 && autoload) { | 153 | if (autoload) { |
| 150 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 154 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| 151 | request_module("nft-chain-%u-%*.s", afi->family, | 155 | request_module("nft-chain-%u-%*.s", afi->family, |
| 152 | nla_len(nla)-1, (const char *)nla_data(nla)); | 156 | nla_len(nla)-1, (const char *)nla_data(nla)); |
| 153 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 157 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 154 | type = __nf_tables_chain_type_lookup(afi->family, nla); | 158 | type = __nf_tables_chain_type_lookup(afi->family, nla); |
| 159 | if (type != NULL) | ||
| 160 | return ERR_PTR(-EAGAIN); | ||
| 155 | } | 161 | } |
| 156 | #endif | 162 | #endif |
| 157 | return type; | 163 | return ERR_PTR(-ENOENT); |
| 158 | } | 164 | } |
| 159 | 165 | ||
| 160 | static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = { | 166 | static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = { |
| @@ -307,7 +313,8 @@ err: | |||
| 307 | return err; | 313 | return err; |
| 308 | } | 314 | } |
| 309 | 315 | ||
| 310 | static int nf_tables_table_enable(struct nft_table *table) | 316 | static int nf_tables_table_enable(const struct nft_af_info *afi, |
| 317 | struct nft_table *table) | ||
| 311 | { | 318 | { |
| 312 | struct nft_chain *chain; | 319 | struct nft_chain *chain; |
| 313 | int err, i = 0; | 320 | int err, i = 0; |
| @@ -316,7 +323,7 @@ static int nf_tables_table_enable(struct nft_table *table) | |||
| 316 | if (!(chain->flags & NFT_BASE_CHAIN)) | 323 | if (!(chain->flags & NFT_BASE_CHAIN)) |
| 317 | continue; | 324 | continue; |
| 318 | 325 | ||
| 319 | err = nf_register_hook(&nft_base_chain(chain)->ops); | 326 | err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops); |
| 320 | if (err < 0) | 327 | if (err < 0) |
| 321 | goto err; | 328 | goto err; |
| 322 | 329 | ||
| @@ -331,18 +338,20 @@ err: | |||
| 331 | if (i-- <= 0) | 338 | if (i-- <= 0) |
| 332 | break; | 339 | break; |
| 333 | 340 | ||
| 334 | nf_unregister_hook(&nft_base_chain(chain)->ops); | 341 | nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops); |
| 335 | } | 342 | } |
| 336 | return err; | 343 | return err; |
| 337 | } | 344 | } |
| 338 | 345 | ||
| 339 | static int nf_tables_table_disable(struct nft_table *table) | 346 | static int nf_tables_table_disable(const struct nft_af_info *afi, |
| 347 | struct nft_table *table) | ||
| 340 | { | 348 | { |
| 341 | struct nft_chain *chain; | 349 | struct nft_chain *chain; |
| 342 | 350 | ||
| 343 | list_for_each_entry(chain, &table->chains, list) { | 351 | list_for_each_entry(chain, &table->chains, list) { |
| 344 | if (chain->flags & NFT_BASE_CHAIN) | 352 | if (chain->flags & NFT_BASE_CHAIN) |
| 345 | nf_unregister_hook(&nft_base_chain(chain)->ops); | 353 | nf_unregister_hooks(nft_base_chain(chain)->ops, |
| 354 | afi->nops); | ||
| 346 | } | 355 | } |
| 347 | 356 | ||
| 348 | return 0; | 357 | return 0; |
| @@ -357,7 +366,7 @@ static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb, | |||
| 357 | int family = nfmsg->nfgen_family, ret = 0; | 366 | int family = nfmsg->nfgen_family, ret = 0; |
| 358 | 367 | ||
| 359 | if (nla[NFTA_TABLE_FLAGS]) { | 368 | if (nla[NFTA_TABLE_FLAGS]) { |
| 360 | __be32 flags; | 369 | u32 flags; |
| 361 | 370 | ||
| 362 | flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS])); | 371 | flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS])); |
| 363 | if (flags & ~NFT_TABLE_F_DORMANT) | 372 | if (flags & ~NFT_TABLE_F_DORMANT) |
| @@ -365,12 +374,12 @@ static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb, | |||
| 365 | 374 | ||
| 366 | if ((flags & NFT_TABLE_F_DORMANT) && | 375 | if ((flags & NFT_TABLE_F_DORMANT) && |
| 367 | !(table->flags & NFT_TABLE_F_DORMANT)) { | 376 | !(table->flags & NFT_TABLE_F_DORMANT)) { |
| 368 | ret = nf_tables_table_disable(table); | 377 | ret = nf_tables_table_disable(afi, table); |
| 369 | if (ret >= 0) | 378 | if (ret >= 0) |
| 370 | table->flags |= NFT_TABLE_F_DORMANT; | 379 | table->flags |= NFT_TABLE_F_DORMANT; |
| 371 | } else if (!(flags & NFT_TABLE_F_DORMANT) && | 380 | } else if (!(flags & NFT_TABLE_F_DORMANT) && |
| 372 | table->flags & NFT_TABLE_F_DORMANT) { | 381 | table->flags & NFT_TABLE_F_DORMANT) { |
| 373 | ret = nf_tables_table_enable(table); | 382 | ret = nf_tables_table_enable(afi, table); |
| 374 | if (ret >= 0) | 383 | if (ret >= 0) |
| 375 | table->flags &= ~NFT_TABLE_F_DORMANT; | 384 | table->flags &= ~NFT_TABLE_F_DORMANT; |
| 376 | } | 385 | } |
| @@ -393,6 +402,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, | |||
| 393 | struct nft_table *table; | 402 | struct nft_table *table; |
| 394 | struct net *net = sock_net(skb->sk); | 403 | struct net *net = sock_net(skb->sk); |
| 395 | int family = nfmsg->nfgen_family; | 404 | int family = nfmsg->nfgen_family; |
| 405 | u32 flags = 0; | ||
| 396 | 406 | ||
| 397 | afi = nf_tables_afinfo_lookup(net, family, true); | 407 | afi = nf_tables_afinfo_lookup(net, family, true); |
| 398 | if (IS_ERR(afi)) | 408 | if (IS_ERR(afi)) |
| @@ -414,25 +424,25 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, | |||
| 414 | return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table); | 424 | return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table); |
| 415 | } | 425 | } |
| 416 | 426 | ||
| 427 | if (nla[NFTA_TABLE_FLAGS]) { | ||
| 428 | flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS])); | ||
| 429 | if (flags & ~NFT_TABLE_F_DORMANT) | ||
| 430 | return -EINVAL; | ||
| 431 | } | ||
| 432 | |||
| 433 | if (!try_module_get(afi->owner)) | ||
| 434 | return -EAFNOSUPPORT; | ||
| 435 | |||
| 417 | table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL); | 436 | table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL); |
| 418 | if (table == NULL) | 437 | if (table == NULL) { |
| 438 | module_put(afi->owner); | ||
| 419 | return -ENOMEM; | 439 | return -ENOMEM; |
| 440 | } | ||
| 420 | 441 | ||
| 421 | nla_strlcpy(table->name, name, nla_len(name)); | 442 | nla_strlcpy(table->name, name, nla_len(name)); |
| 422 | INIT_LIST_HEAD(&table->chains); | 443 | INIT_LIST_HEAD(&table->chains); |
| 423 | INIT_LIST_HEAD(&table->sets); | 444 | INIT_LIST_HEAD(&table->sets); |
| 424 | 445 | table->flags = flags; | |
| 425 | if (nla[NFTA_TABLE_FLAGS]) { | ||
| 426 | __be32 flags; | ||
| 427 | |||
| 428 | flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS])); | ||
| 429 | if (flags & ~NFT_TABLE_F_DORMANT) { | ||
| 430 | kfree(table); | ||
| 431 | return -EINVAL; | ||
| 432 | } | ||
| 433 | |||
| 434 | table->flags |= flags; | ||
| 435 | } | ||
| 436 | 446 | ||
| 437 | list_add_tail(&table->list, &afi->tables); | 447 | list_add_tail(&table->list, &afi->tables); |
| 438 | nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family); | 448 | nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family); |
| @@ -457,16 +467,17 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb, | |||
| 457 | if (IS_ERR(table)) | 467 | if (IS_ERR(table)) |
| 458 | return PTR_ERR(table); | 468 | return PTR_ERR(table); |
| 459 | 469 | ||
| 460 | if (table->use) | 470 | if (!list_empty(&table->chains) || !list_empty(&table->sets)) |
| 461 | return -EBUSY; | 471 | return -EBUSY; |
| 462 | 472 | ||
| 463 | list_del(&table->list); | 473 | list_del(&table->list); |
| 464 | nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family); | 474 | nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family); |
| 465 | kfree(table); | 475 | kfree(table); |
| 476 | module_put(afi->owner); | ||
| 466 | return 0; | 477 | return 0; |
| 467 | } | 478 | } |
| 468 | 479 | ||
| 469 | int nft_register_chain_type(struct nf_chain_type *ctype) | 480 | int nft_register_chain_type(const struct nf_chain_type *ctype) |
| 470 | { | 481 | { |
| 471 | int err = 0; | 482 | int err = 0; |
| 472 | 483 | ||
| @@ -475,10 +486,6 @@ int nft_register_chain_type(struct nf_chain_type *ctype) | |||
| 475 | err = -EBUSY; | 486 | err = -EBUSY; |
| 476 | goto out; | 487 | goto out; |
| 477 | } | 488 | } |
| 478 | |||
| 479 | if (!try_module_get(ctype->me)) | ||
| 480 | goto out; | ||
| 481 | |||
| 482 | chain_type[ctype->family][ctype->type] = ctype; | 489 | chain_type[ctype->family][ctype->type] = ctype; |
| 483 | out: | 490 | out: |
| 484 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 491 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| @@ -486,11 +493,10 @@ out: | |||
| 486 | } | 493 | } |
| 487 | EXPORT_SYMBOL_GPL(nft_register_chain_type); | 494 | EXPORT_SYMBOL_GPL(nft_register_chain_type); |
| 488 | 495 | ||
| 489 | void nft_unregister_chain_type(struct nf_chain_type *ctype) | 496 | void nft_unregister_chain_type(const struct nf_chain_type *ctype) |
| 490 | { | 497 | { |
| 491 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 498 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 492 | chain_type[ctype->family][ctype->type] = NULL; | 499 | chain_type[ctype->family][ctype->type] = NULL; |
| 493 | module_put(ctype->me); | ||
| 494 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 500 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| 495 | } | 501 | } |
| 496 | EXPORT_SYMBOL_GPL(nft_unregister_chain_type); | 502 | EXPORT_SYMBOL_GPL(nft_unregister_chain_type); |
| @@ -598,7 +604,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq, | |||
| 598 | 604 | ||
| 599 | if (chain->flags & NFT_BASE_CHAIN) { | 605 | if (chain->flags & NFT_BASE_CHAIN) { |
| 600 | const struct nft_base_chain *basechain = nft_base_chain(chain); | 606 | const struct nft_base_chain *basechain = nft_base_chain(chain); |
| 601 | const struct nf_hook_ops *ops = &basechain->ops; | 607 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
| 602 | struct nlattr *nest; | 608 | struct nlattr *nest; |
| 603 | 609 | ||
| 604 | nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); | 610 | nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); |
| @@ -614,9 +620,8 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq, | |||
| 614 | htonl(basechain->policy))) | 620 | htonl(basechain->policy))) |
| 615 | goto nla_put_failure; | 621 | goto nla_put_failure; |
| 616 | 622 | ||
| 617 | if (nla_put_string(skb, NFTA_CHAIN_TYPE, | 623 | if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name)) |
| 618 | chain_type[ops->pf][nft_base_chain(chain)->type]->name)) | 624 | goto nla_put_failure; |
| 619 | goto nla_put_failure; | ||
| 620 | 625 | ||
| 621 | if (nft_dump_stats(skb, nft_base_chain(chain)->stats)) | 626 | if (nft_dump_stats(skb, nft_base_chain(chain)->stats)) |
| 622 | goto nla_put_failure; | 627 | goto nla_put_failure; |
| @@ -757,22 +762,6 @@ err: | |||
| 757 | return err; | 762 | return err; |
| 758 | } | 763 | } |
| 759 | 764 | ||
| 760 | static int | ||
| 761 | nf_tables_chain_policy(struct nft_base_chain *chain, const struct nlattr *attr) | ||
| 762 | { | ||
| 763 | switch (ntohl(nla_get_be32(attr))) { | ||
| 764 | case NF_DROP: | ||
| 765 | chain->policy = NF_DROP; | ||
| 766 | break; | ||
| 767 | case NF_ACCEPT: | ||
| 768 | chain->policy = NF_ACCEPT; | ||
| 769 | break; | ||
| 770 | default: | ||
| 771 | return -EINVAL; | ||
| 772 | } | ||
| 773 | return 0; | ||
| 774 | } | ||
| 775 | |||
| 776 | static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = { | 765 | static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = { |
| 777 | [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 }, | 766 | [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 }, |
| 778 | [NFTA_COUNTER_BYTES] = { .type = NLA_U64 }, | 767 | [NFTA_COUNTER_BYTES] = { .type = NLA_U64 }, |
| @@ -831,7 +820,9 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 831 | struct nlattr *ha[NFTA_HOOK_MAX + 1]; | 820 | struct nlattr *ha[NFTA_HOOK_MAX + 1]; |
| 832 | struct net *net = sock_net(skb->sk); | 821 | struct net *net = sock_net(skb->sk); |
| 833 | int family = nfmsg->nfgen_family; | 822 | int family = nfmsg->nfgen_family; |
| 823 | u8 policy = NF_ACCEPT; | ||
| 834 | u64 handle = 0; | 824 | u64 handle = 0; |
| 825 | unsigned int i; | ||
| 835 | int err; | 826 | int err; |
| 836 | bool create; | 827 | bool create; |
| 837 | 828 | ||
| @@ -845,9 +836,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 845 | if (IS_ERR(table)) | 836 | if (IS_ERR(table)) |
| 846 | return PTR_ERR(table); | 837 | return PTR_ERR(table); |
| 847 | 838 | ||
| 848 | if (table->use == UINT_MAX) | ||
| 849 | return -EOVERFLOW; | ||
| 850 | |||
| 851 | chain = NULL; | 839 | chain = NULL; |
| 852 | name = nla[NFTA_CHAIN_NAME]; | 840 | name = nla[NFTA_CHAIN_NAME]; |
| 853 | 841 | ||
| @@ -865,6 +853,22 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 865 | } | 853 | } |
| 866 | } | 854 | } |
| 867 | 855 | ||
| 856 | if (nla[NFTA_CHAIN_POLICY]) { | ||
| 857 | if ((chain != NULL && | ||
| 858 | !(chain->flags & NFT_BASE_CHAIN)) || | ||
| 859 | nla[NFTA_CHAIN_HOOK] == NULL) | ||
| 860 | return -EOPNOTSUPP; | ||
| 861 | |||
| 862 | policy = nla_get_be32(nla[NFTA_CHAIN_POLICY]); | ||
| 863 | switch (policy) { | ||
| 864 | case NF_DROP: | ||
| 865 | case NF_ACCEPT: | ||
| 866 | break; | ||
| 867 | default: | ||
| 868 | return -EINVAL; | ||
| 869 | } | ||
| 870 | } | ||
| 871 | |||
| 868 | if (chain != NULL) { | 872 | if (chain != NULL) { |
| 869 | if (nlh->nlmsg_flags & NLM_F_EXCL) | 873 | if (nlh->nlmsg_flags & NLM_F_EXCL) |
| 870 | return -EEXIST; | 874 | return -EEXIST; |
| @@ -875,16 +879,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 875 | !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]))) | 879 | !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]))) |
| 876 | return -EEXIST; | 880 | return -EEXIST; |
| 877 | 881 | ||
| 878 | if (nla[NFTA_CHAIN_POLICY]) { | ||
| 879 | if (!(chain->flags & NFT_BASE_CHAIN)) | ||
| 880 | return -EOPNOTSUPP; | ||
| 881 | |||
| 882 | err = nf_tables_chain_policy(nft_base_chain(chain), | ||
| 883 | nla[NFTA_CHAIN_POLICY]); | ||
| 884 | if (err < 0) | ||
| 885 | return err; | ||
| 886 | } | ||
| 887 | |||
| 888 | if (nla[NFTA_CHAIN_COUNTERS]) { | 882 | if (nla[NFTA_CHAIN_COUNTERS]) { |
| 889 | if (!(chain->flags & NFT_BASE_CHAIN)) | 883 | if (!(chain->flags & NFT_BASE_CHAIN)) |
| 890 | return -EOPNOTSUPP; | 884 | return -EOPNOTSUPP; |
| @@ -895,24 +889,31 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 895 | return err; | 889 | return err; |
| 896 | } | 890 | } |
| 897 | 891 | ||
| 892 | if (nla[NFTA_CHAIN_POLICY]) | ||
| 893 | nft_base_chain(chain)->policy = policy; | ||
| 894 | |||
| 898 | if (nla[NFTA_CHAIN_HANDLE] && name) | 895 | if (nla[NFTA_CHAIN_HANDLE] && name) |
| 899 | nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN); | 896 | nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN); |
| 900 | 897 | ||
| 901 | goto notify; | 898 | goto notify; |
| 902 | } | 899 | } |
| 903 | 900 | ||
| 901 | if (table->use == UINT_MAX) | ||
| 902 | return -EOVERFLOW; | ||
| 903 | |||
| 904 | if (nla[NFTA_CHAIN_HOOK]) { | 904 | if (nla[NFTA_CHAIN_HOOK]) { |
| 905 | const struct nf_chain_type *type; | ||
| 905 | struct nf_hook_ops *ops; | 906 | struct nf_hook_ops *ops; |
| 906 | nf_hookfn *hookfn; | 907 | nf_hookfn *hookfn; |
| 907 | u32 hooknum; | 908 | u32 hooknum, priority; |
| 908 | int type = NFT_CHAIN_T_DEFAULT; | ||
| 909 | 909 | ||
| 910 | type = chain_type[family][NFT_CHAIN_T_DEFAULT]; | ||
| 910 | if (nla[NFTA_CHAIN_TYPE]) { | 911 | if (nla[NFTA_CHAIN_TYPE]) { |
| 911 | type = nf_tables_chain_type_lookup(afi, | 912 | type = nf_tables_chain_type_lookup(afi, |
| 912 | nla[NFTA_CHAIN_TYPE], | 913 | nla[NFTA_CHAIN_TYPE], |
| 913 | create); | 914 | create); |
| 914 | if (type < 0) | 915 | if (IS_ERR(type)) |
| 915 | return -ENOENT; | 916 | return PTR_ERR(type); |
| 916 | } | 917 | } |
| 917 | 918 | ||
| 918 | err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK], | 919 | err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK], |
| @@ -926,46 +927,23 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 926 | hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); | 927 | hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); |
| 927 | if (hooknum >= afi->nhooks) | 928 | if (hooknum >= afi->nhooks) |
| 928 | return -EINVAL; | 929 | return -EINVAL; |
| 930 | priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY])); | ||
| 929 | 931 | ||
| 930 | hookfn = chain_type[family][type]->fn[hooknum]; | 932 | if (!(type->hook_mask & (1 << hooknum))) |
| 931 | if (hookfn == NULL) | ||
| 932 | return -EOPNOTSUPP; | 933 | return -EOPNOTSUPP; |
| 934 | if (!try_module_get(type->owner)) | ||
| 935 | return -ENOENT; | ||
| 936 | hookfn = type->hooks[hooknum]; | ||
| 933 | 937 | ||
| 934 | basechain = kzalloc(sizeof(*basechain), GFP_KERNEL); | 938 | basechain = kzalloc(sizeof(*basechain), GFP_KERNEL); |
| 935 | if (basechain == NULL) | 939 | if (basechain == NULL) |
| 936 | return -ENOMEM; | 940 | return -ENOMEM; |
| 937 | 941 | ||
| 938 | basechain->type = type; | ||
| 939 | chain = &basechain->chain; | ||
| 940 | |||
| 941 | ops = &basechain->ops; | ||
| 942 | ops->pf = family; | ||
| 943 | ops->owner = afi->owner; | ||
| 944 | ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])); | ||
| 945 | ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY])); | ||
| 946 | ops->priv = chain; | ||
| 947 | ops->hook = hookfn; | ||
| 948 | if (afi->hooks[ops->hooknum]) | ||
| 949 | ops->hook = afi->hooks[ops->hooknum]; | ||
| 950 | |||
| 951 | chain->flags |= NFT_BASE_CHAIN; | ||
| 952 | |||
| 953 | if (nla[NFTA_CHAIN_POLICY]) { | ||
| 954 | err = nf_tables_chain_policy(basechain, | ||
| 955 | nla[NFTA_CHAIN_POLICY]); | ||
| 956 | if (err < 0) { | ||
| 957 | free_percpu(basechain->stats); | ||
| 958 | kfree(basechain); | ||
| 959 | return err; | ||
| 960 | } | ||
| 961 | } else | ||
| 962 | basechain->policy = NF_ACCEPT; | ||
| 963 | |||
| 964 | if (nla[NFTA_CHAIN_COUNTERS]) { | 942 | if (nla[NFTA_CHAIN_COUNTERS]) { |
| 965 | err = nf_tables_counters(basechain, | 943 | err = nf_tables_counters(basechain, |
| 966 | nla[NFTA_CHAIN_COUNTERS]); | 944 | nla[NFTA_CHAIN_COUNTERS]); |
| 967 | if (err < 0) { | 945 | if (err < 0) { |
| 968 | free_percpu(basechain->stats); | 946 | module_put(type->owner); |
| 969 | kfree(basechain); | 947 | kfree(basechain); |
| 970 | return err; | 948 | return err; |
| 971 | } | 949 | } |
| @@ -973,12 +951,33 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 973 | struct nft_stats __percpu *newstats; | 951 | struct nft_stats __percpu *newstats; |
| 974 | 952 | ||
| 975 | newstats = alloc_percpu(struct nft_stats); | 953 | newstats = alloc_percpu(struct nft_stats); |
| 976 | if (newstats == NULL) | 954 | if (newstats == NULL) { |
| 955 | module_put(type->owner); | ||
| 956 | kfree(basechain); | ||
| 977 | return -ENOMEM; | 957 | return -ENOMEM; |
| 958 | } | ||
| 959 | rcu_assign_pointer(basechain->stats, newstats); | ||
| 960 | } | ||
| 978 | 961 | ||
| 979 | rcu_assign_pointer(nft_base_chain(chain)->stats, | 962 | basechain->type = type; |
| 980 | newstats); | 963 | chain = &basechain->chain; |
| 964 | |||
| 965 | for (i = 0; i < afi->nops; i++) { | ||
| 966 | ops = &basechain->ops[i]; | ||
| 967 | ops->pf = family; | ||
| 968 | ops->owner = afi->owner; | ||
| 969 | ops->hooknum = hooknum; | ||
| 970 | ops->priority = priority; | ||
| 971 | ops->priv = chain; | ||
| 972 | ops->hook = afi->hooks[ops->hooknum]; | ||
| 973 | if (hookfn) | ||
| 974 | ops->hook = hookfn; | ||
| 975 | if (afi->hook_ops_init) | ||
| 976 | afi->hook_ops_init(ops, i); | ||
| 981 | } | 977 | } |
| 978 | |||
| 979 | chain->flags |= NFT_BASE_CHAIN; | ||
| 980 | basechain->policy = policy; | ||
| 982 | } else { | 981 | } else { |
| 983 | chain = kzalloc(sizeof(*chain), GFP_KERNEL); | 982 | chain = kzalloc(sizeof(*chain), GFP_KERNEL); |
| 984 | if (chain == NULL) | 983 | if (chain == NULL) |
| @@ -993,8 +992,9 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 993 | 992 | ||
| 994 | if (!(table->flags & NFT_TABLE_F_DORMANT) && | 993 | if (!(table->flags & NFT_TABLE_F_DORMANT) && |
| 995 | chain->flags & NFT_BASE_CHAIN) { | 994 | chain->flags & NFT_BASE_CHAIN) { |
| 996 | err = nf_register_hook(&nft_base_chain(chain)->ops); | 995 | err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops); |
| 997 | if (err < 0) { | 996 | if (err < 0) { |
| 997 | module_put(basechain->type->owner); | ||
| 998 | free_percpu(basechain->stats); | 998 | free_percpu(basechain->stats); |
| 999 | kfree(basechain); | 999 | kfree(basechain); |
| 1000 | return err; | 1000 | return err; |
| @@ -1015,6 +1015,7 @@ static void nf_tables_rcu_chain_destroy(struct rcu_head *head) | |||
| 1015 | BUG_ON(chain->use > 0); | 1015 | BUG_ON(chain->use > 0); |
| 1016 | 1016 | ||
| 1017 | if (chain->flags & NFT_BASE_CHAIN) { | 1017 | if (chain->flags & NFT_BASE_CHAIN) { |
| 1018 | module_put(nft_base_chain(chain)->type->owner); | ||
| 1018 | free_percpu(nft_base_chain(chain)->stats); | 1019 | free_percpu(nft_base_chain(chain)->stats); |
| 1019 | kfree(nft_base_chain(chain)); | 1020 | kfree(nft_base_chain(chain)); |
| 1020 | } else | 1021 | } else |
| @@ -1052,7 +1053,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 1052 | 1053 | ||
| 1053 | if (!(table->flags & NFT_TABLE_F_DORMANT) && | 1054 | if (!(table->flags & NFT_TABLE_F_DORMANT) && |
| 1054 | chain->flags & NFT_BASE_CHAIN) | 1055 | chain->flags & NFT_BASE_CHAIN) |
| 1055 | nf_unregister_hook(&nft_base_chain(chain)->ops); | 1056 | nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops); |
| 1056 | 1057 | ||
| 1057 | nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN, | 1058 | nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN, |
| 1058 | family); | 1059 | family); |
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index e8fcc343c2b9..0d879fcb8763 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c | |||
| @@ -109,14 +109,14 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt, | |||
| 109 | { | 109 | { |
| 110 | struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); | 110 | struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); |
| 111 | 111 | ||
| 112 | nf_log_packet(net, pkt->xt.family, pkt->hooknum, pkt->skb, pkt->in, | 112 | nf_log_packet(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in, |
| 113 | pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ", | 113 | pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ", |
| 114 | chain->table->name, chain->name, comments[type], | 114 | chain->table->name, chain->name, comments[type], |
| 115 | rulenum); | 115 | rulenum); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | unsigned int | 118 | unsigned int |
| 119 | nft_do_chain_pktinfo(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) | 119 | nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) |
| 120 | { | 120 | { |
| 121 | const struct nft_chain *chain = ops->priv; | 121 | const struct nft_chain *chain = ops->priv; |
| 122 | const struct nft_rule *rule; | 122 | const struct nft_rule *rule; |
| @@ -216,7 +216,7 @@ next_rule: | |||
| 216 | 216 | ||
| 217 | return nft_base_chain(chain)->policy; | 217 | return nft_base_chain(chain)->policy; |
| 218 | } | 218 | } |
| 219 | EXPORT_SYMBOL_GPL(nft_do_chain_pktinfo); | 219 | EXPORT_SYMBOL_GPL(nft_do_chain); |
| 220 | 220 | ||
| 221 | int __init nf_tables_core_module_init(void) | 221 | int __init nf_tables_core_module_init(void) |
| 222 | { | 222 | { |
diff --git a/net/netfilter/nf_tables_inet.c b/net/netfilter/nf_tables_inet.c new file mode 100644 index 000000000000..9dd2d216cfc1 --- /dev/null +++ b/net/netfilter/nf_tables_inet.c | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012-2014 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 | |||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/ip.h> | ||
| 12 | #include <linux/netfilter_ipv4.h> | ||
| 13 | #include <linux/netfilter_ipv6.h> | ||
| 14 | #include <net/netfilter/nf_tables.h> | ||
| 15 | #include <net/netfilter/nf_tables_ipv4.h> | ||
| 16 | #include <net/netfilter/nf_tables_ipv6.h> | ||
| 17 | #include <net/ip.h> | ||
| 18 | |||
| 19 | static void nft_inet_hook_ops_init(struct nf_hook_ops *ops, unsigned int n) | ||
| 20 | { | ||
| 21 | struct nft_af_info *afi; | ||
| 22 | |||
| 23 | if (n == 1) | ||
| 24 | afi = &nft_af_ipv4; | ||
| 25 | else | ||
| 26 | afi = &nft_af_ipv6; | ||
| 27 | |||
| 28 | ops->pf = afi->family; | ||
| 29 | if (afi->hooks[ops->hooknum]) | ||
| 30 | ops->hook = afi->hooks[ops->hooknum]; | ||
| 31 | } | ||
| 32 | |||
| 33 | static struct nft_af_info nft_af_inet __read_mostly = { | ||
| 34 | .family = NFPROTO_INET, | ||
| 35 | .nhooks = NF_INET_NUMHOOKS, | ||
| 36 | .owner = THIS_MODULE, | ||
| 37 | .nops = 2, | ||
| 38 | .hook_ops_init = nft_inet_hook_ops_init, | ||
| 39 | }; | ||
| 40 | |||
| 41 | static int __net_init nf_tables_inet_init_net(struct net *net) | ||
| 42 | { | ||
| 43 | net->nft.inet = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL); | ||
| 44 | if (net->nft.inet == NULL) | ||
| 45 | return -ENOMEM; | ||
| 46 | memcpy(net->nft.inet, &nft_af_inet, sizeof(nft_af_inet)); | ||
| 47 | |||
| 48 | if (nft_register_afinfo(net, net->nft.inet) < 0) | ||
| 49 | goto err; | ||
| 50 | |||
| 51 | return 0; | ||
| 52 | |||
| 53 | err: | ||
| 54 | kfree(net->nft.inet); | ||
| 55 | return -ENOMEM; | ||
| 56 | } | ||
| 57 | |||
| 58 | static void __net_exit nf_tables_inet_exit_net(struct net *net) | ||
| 59 | { | ||
| 60 | nft_unregister_afinfo(net->nft.inet); | ||
| 61 | kfree(net->nft.inet); | ||
| 62 | } | ||
| 63 | |||
| 64 | static struct pernet_operations nf_tables_inet_net_ops = { | ||
| 65 | .init = nf_tables_inet_init_net, | ||
| 66 | .exit = nf_tables_inet_exit_net, | ||
| 67 | }; | ||
| 68 | |||
| 69 | static const struct nf_chain_type filter_inet = { | ||
| 70 | .name = "filter", | ||
| 71 | .type = NFT_CHAIN_T_DEFAULT, | ||
| 72 | .family = NFPROTO_INET, | ||
| 73 | .owner = THIS_MODULE, | ||
| 74 | .hook_mask = (1 << NF_INET_LOCAL_IN) | | ||
| 75 | (1 << NF_INET_LOCAL_OUT) | | ||
| 76 | (1 << NF_INET_FORWARD) | | ||
| 77 | (1 << NF_INET_PRE_ROUTING) | | ||
| 78 | (1 << NF_INET_POST_ROUTING), | ||
| 79 | }; | ||
| 80 | |||
| 81 | static int __init nf_tables_inet_init(void) | ||
| 82 | { | ||
| 83 | int ret; | ||
| 84 | |||
| 85 | nft_register_chain_type(&filter_inet); | ||
| 86 | ret = register_pernet_subsys(&nf_tables_inet_net_ops); | ||
| 87 | if (ret < 0) | ||
| 88 | nft_unregister_chain_type(&filter_inet); | ||
| 89 | |||
| 90 | return ret; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void __exit nf_tables_inet_exit(void) | ||
| 94 | { | ||
| 95 | unregister_pernet_subsys(&nf_tables_inet_net_ops); | ||
| 96 | nft_unregister_chain_type(&filter_inet); | ||
| 97 | } | ||
| 98 | |||
| 99 | module_init(nf_tables_inet_init); | ||
| 100 | module_exit(nf_tables_inet_exit); | ||
| 101 | |||
| 102 | MODULE_LICENSE("GPL"); | ||
| 103 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
| 104 | MODULE_ALIAS_NFT_FAMILY(1); | ||
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index da0c1f4ada12..82cb8236f8a1 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c | |||
| @@ -92,7 +92,7 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par, | |||
| 92 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 92 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
| 93 | const struct nft_base_chain *basechain = | 93 | const struct nft_base_chain *basechain = |
| 94 | nft_base_chain(ctx->chain); | 94 | nft_base_chain(ctx->chain); |
| 95 | const struct nf_hook_ops *ops = &basechain->ops; | 95 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
| 96 | 96 | ||
| 97 | par->hook_mask = 1 << ops->hooknum; | 97 | par->hook_mask = 1 << ops->hooknum; |
| 98 | } | 98 | } |
| @@ -253,7 +253,7 @@ static int nft_target_validate(const struct nft_ctx *ctx, | |||
| 253 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 253 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
| 254 | const struct nft_base_chain *basechain = | 254 | const struct nft_base_chain *basechain = |
| 255 | nft_base_chain(ctx->chain); | 255 | nft_base_chain(ctx->chain); |
| 256 | const struct nf_hook_ops *ops = &basechain->ops; | 256 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
| 257 | 257 | ||
| 258 | hook_mask = 1 << ops->hooknum; | 258 | hook_mask = 1 << ops->hooknum; |
| 259 | if (hook_mask & target->hooks) | 259 | if (hook_mask & target->hooks) |
| @@ -323,7 +323,7 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, | |||
| 323 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 323 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
| 324 | const struct nft_base_chain *basechain = | 324 | const struct nft_base_chain *basechain = |
| 325 | nft_base_chain(ctx->chain); | 325 | nft_base_chain(ctx->chain); |
| 326 | const struct nf_hook_ops *ops = &basechain->ops; | 326 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
| 327 | 327 | ||
| 328 | par->hook_mask = 1 << ops->hooknum; | 328 | par->hook_mask = 1 << ops->hooknum; |
| 329 | } | 329 | } |
| @@ -449,7 +449,7 @@ static int nft_match_validate(const struct nft_ctx *ctx, | |||
| 449 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 449 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
| 450 | const struct nft_base_chain *basechain = | 450 | const struct nft_base_chain *basechain = |
| 451 | nft_base_chain(ctx->chain); | 451 | nft_base_chain(ctx->chain); |
| 452 | const struct nf_hook_ops *ops = &basechain->ops; | 452 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
| 453 | 453 | ||
| 454 | hook_mask = 1 << ops->hooknum; | 454 | hook_mask = 1 << ops->hooknum; |
| 455 | if (hook_mask & match->hooks) | 455 | if (hook_mask & match->hooks) |
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index 955f4e6e7089..c7c12858e113 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c | |||
| @@ -18,17 +18,21 @@ | |||
| 18 | #include <net/netfilter/nf_conntrack.h> | 18 | #include <net/netfilter/nf_conntrack.h> |
| 19 | #include <net/netfilter/nf_conntrack_tuple.h> | 19 | #include <net/netfilter/nf_conntrack_tuple.h> |
| 20 | #include <net/netfilter/nf_conntrack_helper.h> | 20 | #include <net/netfilter/nf_conntrack_helper.h> |
| 21 | #include <net/netfilter/nf_conntrack_ecache.h> | ||
| 21 | 22 | ||
| 22 | struct nft_ct { | 23 | struct nft_ct { |
| 23 | enum nft_ct_keys key:8; | 24 | enum nft_ct_keys key:8; |
| 24 | enum ip_conntrack_dir dir:8; | 25 | enum ip_conntrack_dir dir:8; |
| 25 | enum nft_registers dreg:8; | 26 | union{ |
| 27 | enum nft_registers dreg:8; | ||
| 28 | enum nft_registers sreg:8; | ||
| 29 | }; | ||
| 26 | uint8_t family; | 30 | uint8_t family; |
| 27 | }; | 31 | }; |
| 28 | 32 | ||
| 29 | static void nft_ct_eval(const struct nft_expr *expr, | 33 | static void nft_ct_get_eval(const struct nft_expr *expr, |
| 30 | struct nft_data data[NFT_REG_MAX + 1], | 34 | struct nft_data data[NFT_REG_MAX + 1], |
| 31 | const struct nft_pktinfo *pkt) | 35 | const struct nft_pktinfo *pkt) |
| 32 | { | 36 | { |
| 33 | const struct nft_ct *priv = nft_expr_priv(expr); | 37 | const struct nft_ct *priv = nft_expr_priv(expr); |
| 34 | struct nft_data *dest = &data[priv->dreg]; | 38 | struct nft_data *dest = &data[priv->dreg]; |
| @@ -123,24 +127,77 @@ err: | |||
| 123 | data[NFT_REG_VERDICT].verdict = NFT_BREAK; | 127 | data[NFT_REG_VERDICT].verdict = NFT_BREAK; |
| 124 | } | 128 | } |
| 125 | 129 | ||
| 130 | static void nft_ct_set_eval(const struct nft_expr *expr, | ||
| 131 | struct nft_data data[NFT_REG_MAX + 1], | ||
| 132 | const struct nft_pktinfo *pkt) | ||
| 133 | { | ||
| 134 | const struct nft_ct *priv = nft_expr_priv(expr); | ||
| 135 | struct sk_buff *skb = pkt->skb; | ||
| 136 | u32 value = data[priv->sreg].data[0]; | ||
| 137 | enum ip_conntrack_info ctinfo; | ||
| 138 | struct nf_conn *ct; | ||
| 139 | |||
| 140 | ct = nf_ct_get(skb, &ctinfo); | ||
| 141 | if (ct == NULL) | ||
| 142 | return; | ||
| 143 | |||
| 144 | switch (priv->key) { | ||
| 145 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
| 146 | case NFT_CT_MARK: | ||
| 147 | if (ct->mark != value) { | ||
| 148 | ct->mark = value; | ||
| 149 | nf_conntrack_event_cache(IPCT_MARK, ct); | ||
| 150 | } | ||
| 151 | break; | ||
| 152 | #endif | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 126 | static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = { | 156 | static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = { |
| 127 | [NFTA_CT_DREG] = { .type = NLA_U32 }, | 157 | [NFTA_CT_DREG] = { .type = NLA_U32 }, |
| 128 | [NFTA_CT_KEY] = { .type = NLA_U32 }, | 158 | [NFTA_CT_KEY] = { .type = NLA_U32 }, |
| 129 | [NFTA_CT_DIRECTION] = { .type = NLA_U8 }, | 159 | [NFTA_CT_DIRECTION] = { .type = NLA_U8 }, |
| 160 | [NFTA_CT_SREG] = { .type = NLA_U32 }, | ||
| 130 | }; | 161 | }; |
| 131 | 162 | ||
| 132 | static int nft_ct_init(const struct nft_ctx *ctx, | 163 | static int nft_ct_l3proto_try_module_get(uint8_t family) |
| 133 | const struct nft_expr *expr, | ||
| 134 | const struct nlattr * const tb[]) | ||
| 135 | { | 164 | { |
| 136 | struct nft_ct *priv = nft_expr_priv(expr); | ||
| 137 | int err; | 165 | int err; |
| 138 | 166 | ||
| 139 | if (tb[NFTA_CT_DREG] == NULL || | 167 | if (family == NFPROTO_INET) { |
| 140 | tb[NFTA_CT_KEY] == NULL) | 168 | err = nf_ct_l3proto_try_module_get(NFPROTO_IPV4); |
| 141 | return -EINVAL; | 169 | if (err < 0) |
| 170 | goto err1; | ||
| 171 | err = nf_ct_l3proto_try_module_get(NFPROTO_IPV6); | ||
| 172 | if (err < 0) | ||
| 173 | goto err2; | ||
| 174 | } else { | ||
| 175 | err = nf_ct_l3proto_try_module_get(family); | ||
| 176 | if (err < 0) | ||
| 177 | goto err1; | ||
| 178 | } | ||
| 179 | return 0; | ||
| 180 | |||
| 181 | err2: | ||
| 182 | nf_ct_l3proto_module_put(NFPROTO_IPV4); | ||
| 183 | err1: | ||
| 184 | return err; | ||
| 185 | } | ||
| 186 | |||
| 187 | static void nft_ct_l3proto_module_put(uint8_t family) | ||
| 188 | { | ||
| 189 | if (family == NFPROTO_INET) { | ||
| 190 | nf_ct_l3proto_module_put(NFPROTO_IPV4); | ||
| 191 | nf_ct_l3proto_module_put(NFPROTO_IPV6); | ||
| 192 | } else | ||
| 193 | nf_ct_l3proto_module_put(family); | ||
| 194 | } | ||
| 195 | |||
| 196 | static int nft_ct_init_validate_get(const struct nft_expr *expr, | ||
| 197 | const struct nlattr * const tb[]) | ||
| 198 | { | ||
| 199 | struct nft_ct *priv = nft_expr_priv(expr); | ||
| 142 | 200 | ||
| 143 | priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY])); | ||
| 144 | if (tb[NFTA_CT_DIRECTION] != NULL) { | 201 | if (tb[NFTA_CT_DIRECTION] != NULL) { |
| 145 | priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]); | 202 | priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]); |
| 146 | switch (priv->dir) { | 203 | switch (priv->dir) { |
| @@ -179,34 +236,72 @@ static int nft_ct_init(const struct nft_ctx *ctx, | |||
| 179 | return -EOPNOTSUPP; | 236 | return -EOPNOTSUPP; |
| 180 | } | 237 | } |
| 181 | 238 | ||
| 182 | err = nf_ct_l3proto_try_module_get(ctx->afi->family); | 239 | return 0; |
| 240 | } | ||
| 241 | |||
| 242 | static int nft_ct_init_validate_set(uint32_t key) | ||
| 243 | { | ||
| 244 | switch (key) { | ||
| 245 | case NFT_CT_MARK: | ||
| 246 | break; | ||
| 247 | default: | ||
| 248 | return -EOPNOTSUPP; | ||
| 249 | } | ||
| 250 | |||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | static int nft_ct_init(const struct nft_ctx *ctx, | ||
| 255 | const struct nft_expr *expr, | ||
| 256 | const struct nlattr * const tb[]) | ||
| 257 | { | ||
| 258 | struct nft_ct *priv = nft_expr_priv(expr); | ||
| 259 | int err; | ||
| 260 | |||
| 261 | priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY])); | ||
| 262 | |||
| 263 | if (tb[NFTA_CT_DREG]) { | ||
| 264 | err = nft_ct_init_validate_get(expr, tb); | ||
| 265 | if (err < 0) | ||
| 266 | return err; | ||
| 267 | |||
| 268 | priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG])); | ||
| 269 | err = nft_validate_output_register(priv->dreg); | ||
| 270 | if (err < 0) | ||
| 271 | return err; | ||
| 272 | |||
| 273 | err = nft_validate_data_load(ctx, priv->dreg, NULL, | ||
| 274 | NFT_DATA_VALUE); | ||
| 275 | if (err < 0) | ||
| 276 | return err; | ||
| 277 | } else { | ||
| 278 | err = nft_ct_init_validate_set(priv->key); | ||
| 279 | if (err < 0) | ||
| 280 | return err; | ||
| 281 | |||
| 282 | priv->sreg = ntohl(nla_get_be32(tb[NFTA_CT_SREG])); | ||
| 283 | err = nft_validate_input_register(priv->sreg); | ||
| 284 | if (err < 0) | ||
| 285 | return err; | ||
| 286 | } | ||
| 287 | |||
| 288 | err = nft_ct_l3proto_try_module_get(ctx->afi->family); | ||
| 183 | if (err < 0) | 289 | if (err < 0) |
| 184 | return err; | 290 | return err; |
| 185 | priv->family = ctx->afi->family; | ||
| 186 | 291 | ||
| 187 | priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG])); | 292 | priv->family = ctx->afi->family; |
| 188 | err = nft_validate_output_register(priv->dreg); | ||
| 189 | if (err < 0) | ||
| 190 | goto err1; | ||
| 191 | 293 | ||
| 192 | err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); | ||
| 193 | if (err < 0) | ||
| 194 | goto err1; | ||
| 195 | return 0; | 294 | return 0; |
| 196 | |||
| 197 | err1: | ||
| 198 | nf_ct_l3proto_module_put(ctx->afi->family); | ||
| 199 | return err; | ||
| 200 | } | 295 | } |
| 201 | 296 | ||
| 202 | static void nft_ct_destroy(const struct nft_expr *expr) | 297 | static void nft_ct_destroy(const struct nft_expr *expr) |
| 203 | { | 298 | { |
| 204 | struct nft_ct *priv = nft_expr_priv(expr); | 299 | struct nft_ct *priv = nft_expr_priv(expr); |
| 205 | 300 | ||
| 206 | nf_ct_l3proto_module_put(priv->family); | 301 | nft_ct_l3proto_module_put(priv->family); |
| 207 | } | 302 | } |
| 208 | 303 | ||
| 209 | static int nft_ct_dump(struct sk_buff *skb, const struct nft_expr *expr) | 304 | static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr) |
| 210 | { | 305 | { |
| 211 | const struct nft_ct *priv = nft_expr_priv(expr); | 306 | const struct nft_ct *priv = nft_expr_priv(expr); |
| 212 | 307 | ||
| @@ -222,19 +317,61 @@ nla_put_failure: | |||
| 222 | return -1; | 317 | return -1; |
| 223 | } | 318 | } |
| 224 | 319 | ||
| 320 | static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr) | ||
| 321 | { | ||
| 322 | const struct nft_ct *priv = nft_expr_priv(expr); | ||
| 323 | |||
| 324 | if (nla_put_be32(skb, NFTA_CT_SREG, htonl(priv->sreg))) | ||
| 325 | goto nla_put_failure; | ||
| 326 | if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key))) | ||
| 327 | goto nla_put_failure; | ||
| 328 | return 0; | ||
| 329 | |||
| 330 | nla_put_failure: | ||
| 331 | return -1; | ||
| 332 | } | ||
| 333 | |||
| 225 | static struct nft_expr_type nft_ct_type; | 334 | static struct nft_expr_type nft_ct_type; |
| 226 | static const struct nft_expr_ops nft_ct_ops = { | 335 | static const struct nft_expr_ops nft_ct_get_ops = { |
| 227 | .type = &nft_ct_type, | 336 | .type = &nft_ct_type, |
| 228 | .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)), | 337 | .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)), |
| 229 | .eval = nft_ct_eval, | 338 | .eval = nft_ct_get_eval, |
| 230 | .init = nft_ct_init, | 339 | .init = nft_ct_init, |
| 231 | .destroy = nft_ct_destroy, | 340 | .destroy = nft_ct_destroy, |
| 232 | .dump = nft_ct_dump, | 341 | .dump = nft_ct_get_dump, |
| 233 | }; | 342 | }; |
| 234 | 343 | ||
| 344 | static const struct nft_expr_ops nft_ct_set_ops = { | ||
| 345 | .type = &nft_ct_type, | ||
| 346 | .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)), | ||
| 347 | .eval = nft_ct_set_eval, | ||
| 348 | .init = nft_ct_init, | ||
| 349 | .destroy = nft_ct_destroy, | ||
| 350 | .dump = nft_ct_set_dump, | ||
| 351 | }; | ||
| 352 | |||
| 353 | static const struct nft_expr_ops * | ||
| 354 | nft_ct_select_ops(const struct nft_ctx *ctx, | ||
| 355 | const struct nlattr * const tb[]) | ||
| 356 | { | ||
| 357 | if (tb[NFTA_CT_KEY] == NULL) | ||
| 358 | return ERR_PTR(-EINVAL); | ||
| 359 | |||
| 360 | if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG]) | ||
| 361 | return ERR_PTR(-EINVAL); | ||
| 362 | |||
| 363 | if (tb[NFTA_CT_DREG]) | ||
| 364 | return &nft_ct_get_ops; | ||
| 365 | |||
| 366 | if (tb[NFTA_CT_SREG]) | ||
| 367 | return &nft_ct_set_ops; | ||
| 368 | |||
| 369 | return ERR_PTR(-EINVAL); | ||
| 370 | } | ||
| 371 | |||
| 235 | static struct nft_expr_type nft_ct_type __read_mostly = { | 372 | static struct nft_expr_type nft_ct_type __read_mostly = { |
| 236 | .name = "ct", | 373 | .name = "ct", |
| 237 | .ops = &nft_ct_ops, | 374 | .select_ops = &nft_ct_select_ops, |
| 238 | .policy = nft_ct_policy, | 375 | .policy = nft_ct_policy, |
| 239 | .maxattr = NFTA_CT_MAX, | 376 | .maxattr = NFTA_CT_MAX, |
| 240 | .owner = THIS_MODULE, | 377 | .owner = THIS_MODULE, |
diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c index 57cad072a13e..5af790123ad8 100644 --- a/net/netfilter/nft_log.c +++ b/net/netfilter/nft_log.c | |||
| @@ -33,7 +33,7 @@ static void nft_log_eval(const struct nft_expr *expr, | |||
| 33 | const struct nft_log *priv = nft_expr_priv(expr); | 33 | const struct nft_log *priv = nft_expr_priv(expr); |
| 34 | struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); | 34 | struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); |
| 35 | 35 | ||
| 36 | nf_log_packet(net, priv->family, pkt->hooknum, pkt->skb, pkt->in, | 36 | nf_log_packet(net, priv->family, pkt->ops->hooknum, pkt->skb, pkt->in, |
| 37 | pkt->out, &priv->loginfo, "%s", priv->prefix); | 37 | pkt->out, &priv->loginfo, "%s", priv->prefix); |
| 38 | } | 38 | } |
| 39 | 39 | ||
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 1ceaaa6dfe72..e8254ad2e5a9 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c | |||
| @@ -43,6 +43,12 @@ static void nft_meta_get_eval(const struct nft_expr *expr, | |||
| 43 | case NFT_META_PROTOCOL: | 43 | case NFT_META_PROTOCOL: |
| 44 | *(__be16 *)dest->data = skb->protocol; | 44 | *(__be16 *)dest->data = skb->protocol; |
| 45 | break; | 45 | break; |
| 46 | case NFT_META_NFPROTO: | ||
| 47 | dest->data[0] = pkt->ops->pf; | ||
| 48 | break; | ||
| 49 | case NFT_META_L4PROTO: | ||
| 50 | dest->data[0] = pkt->tprot; | ||
| 51 | break; | ||
| 46 | case NFT_META_PRIORITY: | 52 | case NFT_META_PRIORITY: |
| 47 | dest->data[0] = skb->priority; | 53 | dest->data[0] = skb->priority; |
| 48 | break; | 54 | break; |
| @@ -181,6 +187,8 @@ static int nft_meta_init_validate_get(uint32_t key) | |||
| 181 | switch (key) { | 187 | switch (key) { |
| 182 | case NFT_META_LEN: | 188 | case NFT_META_LEN: |
| 183 | case NFT_META_PROTOCOL: | 189 | case NFT_META_PROTOCOL: |
| 190 | case NFT_META_NFPROTO: | ||
| 191 | case NFT_META_L4PROTO: | ||
| 184 | case NFT_META_PRIORITY: | 192 | case NFT_META_PRIORITY: |
| 185 | case NFT_META_MARK: | 193 | case NFT_META_MARK: |
| 186 | case NFT_META_IIF: | 194 | case NFT_META_IIF: |
| @@ -231,6 +239,9 @@ static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
| 231 | return err; | 239 | return err; |
| 232 | 240 | ||
| 233 | priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG])); | 241 | priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG])); |
| 242 | err = nft_validate_input_register(priv->sreg); | ||
| 243 | if (err < 0) | ||
| 244 | return err; | ||
| 234 | 245 | ||
| 235 | return 0; | 246 | return 0; |
| 236 | } | 247 | } |
diff --git a/net/netfilter/nft_reject.c b/net/netfilter/nft_reject.c index 0d690d4101d2..5e204711d704 100644 --- a/net/netfilter/nft_reject.c +++ b/net/netfilter/nft_reject.c | |||
| @@ -34,8 +34,9 @@ static void nft_reject_eval(const struct nft_expr *expr, | |||
| 34 | const struct nft_pktinfo *pkt) | 34 | const struct nft_pktinfo *pkt) |
| 35 | { | 35 | { |
| 36 | struct nft_reject *priv = nft_expr_priv(expr); | 36 | struct nft_reject *priv = nft_expr_priv(expr); |
| 37 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | ||
| 37 | struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out); | 38 | struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out); |
| 38 | 39 | #endif | |
| 39 | switch (priv->type) { | 40 | switch (priv->type) { |
| 40 | case NFT_REJECT_ICMP_UNREACH: | 41 | case NFT_REJECT_ICMP_UNREACH: |
| 41 | if (priv->family == NFPROTO_IPV4) | 42 | if (priv->family == NFPROTO_IPV4) |
| @@ -43,15 +44,15 @@ static void nft_reject_eval(const struct nft_expr *expr, | |||
| 43 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | 44 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) |
| 44 | else if (priv->family == NFPROTO_IPV6) | 45 | else if (priv->family == NFPROTO_IPV6) |
| 45 | nf_send_unreach6(net, pkt->skb, priv->icmp_code, | 46 | nf_send_unreach6(net, pkt->skb, priv->icmp_code, |
| 46 | pkt->hooknum); | 47 | pkt->ops->hooknum); |
| 47 | #endif | 48 | #endif |
| 48 | break; | 49 | break; |
| 49 | case NFT_REJECT_TCP_RST: | 50 | case NFT_REJECT_TCP_RST: |
| 50 | if (priv->family == NFPROTO_IPV4) | 51 | if (priv->family == NFPROTO_IPV4) |
| 51 | nf_send_reset(pkt->skb, pkt->hooknum); | 52 | nf_send_reset(pkt->skb, pkt->ops->hooknum); |
| 52 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) | 53 | #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) |
| 53 | else if (priv->family == NFPROTO_IPV6) | 54 | else if (priv->family == NFPROTO_IPV6) |
| 54 | nf_send_reset6(net, pkt->skb, pkt->hooknum); | 55 | nf_send_reset6(net, pkt->skb, pkt->ops->hooknum); |
| 55 | #endif | 56 | #endif |
| 56 | break; | 57 | break; |
| 57 | } | 58 | } |
