diff options
-rw-r--r-- | include/linux/netfilter/nfnetlink_acct.h | 8 | ||||
-rw-r--r-- | include/net/netfilter/nf_nat.h | 2 | ||||
-rw-r--r-- | include/uapi/linux/netfilter/nfnetlink.h | 2 | ||||
-rw-r--r-- | include/uapi/linux/netfilter/nfnetlink_acct.h | 9 | ||||
-rw-r--r-- | net/ipv4/netfilter/iptable_nat.c | 14 | ||||
-rw-r--r-- | net/ipv4/netfilter/nft_chain_nat_ipv4.c | 12 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6table_nat.c | 14 | ||||
-rw-r--r-- | net/ipv6/netfilter/nft_chain_nat_ipv6.c | 12 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_nat_core.c | 24 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_acct.c | 85 | ||||
-rw-r--r-- | net/netfilter/xt_nfacct.c | 5 |
12 files changed, 138 insertions, 51 deletions
diff --git a/include/linux/netfilter/nfnetlink_acct.h b/include/linux/netfilter/nfnetlink_acct.h index b2e85e59f760..6ec975748742 100644 --- a/include/linux/netfilter/nfnetlink_acct.h +++ b/include/linux/netfilter/nfnetlink_acct.h | |||
@@ -3,11 +3,17 @@ | |||
3 | 3 | ||
4 | #include <uapi/linux/netfilter/nfnetlink_acct.h> | 4 | #include <uapi/linux/netfilter/nfnetlink_acct.h> |
5 | 5 | ||
6 | enum { | ||
7 | NFACCT_NO_QUOTA = -1, | ||
8 | NFACCT_UNDERQUOTA, | ||
9 | NFACCT_OVERQUOTA, | ||
10 | }; | ||
6 | 11 | ||
7 | struct nf_acct; | 12 | struct nf_acct; |
8 | 13 | ||
9 | struct nf_acct *nfnl_acct_find_get(const char *filter_name); | 14 | struct nf_acct *nfnl_acct_find_get(const char *filter_name); |
10 | void nfnl_acct_put(struct nf_acct *acct); | 15 | void nfnl_acct_put(struct nf_acct *acct); |
11 | void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct); | 16 | void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct); |
12 | 17 | extern int nfnl_acct_overquota(const struct sk_buff *skb, | |
18 | struct nf_acct *nfacct); | ||
13 | #endif /* _NFNL_ACCT_H */ | 19 | #endif /* _NFNL_ACCT_H */ |
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h index 07eaaf604092..a71dd333ac68 100644 --- a/include/net/netfilter/nf_nat.h +++ b/include/net/netfilter/nf_nat.h | |||
@@ -48,6 +48,8 @@ unsigned int nf_nat_setup_info(struct nf_conn *ct, | |||
48 | extern unsigned int nf_nat_alloc_null_binding(struct nf_conn *ct, | 48 | extern unsigned int nf_nat_alloc_null_binding(struct nf_conn *ct, |
49 | unsigned int hooknum); | 49 | unsigned int hooknum); |
50 | 50 | ||
51 | struct nf_conn_nat *nf_ct_nat_ext_add(struct nf_conn *ct); | ||
52 | |||
51 | /* Is this tuple already taken? (not by us)*/ | 53 | /* Is this tuple already taken? (not by us)*/ |
52 | int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, | 54 | int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, |
53 | const struct nf_conn *ignored_conntrack); | 55 | const struct nf_conn *ignored_conntrack); |
diff --git a/include/uapi/linux/netfilter/nfnetlink.h b/include/uapi/linux/netfilter/nfnetlink.h index 596ddd45253c..354a7e5e50f2 100644 --- a/include/uapi/linux/netfilter/nfnetlink.h +++ b/include/uapi/linux/netfilter/nfnetlink.h | |||
@@ -20,6 +20,8 @@ enum nfnetlink_groups { | |||
20 | #define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY | 20 | #define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY |
21 | NFNLGRP_NFTABLES, | 21 | NFNLGRP_NFTABLES, |
22 | #define NFNLGRP_NFTABLES NFNLGRP_NFTABLES | 22 | #define NFNLGRP_NFTABLES NFNLGRP_NFTABLES |
23 | NFNLGRP_ACCT_QUOTA, | ||
24 | #define NFNLGRP_ACCT_QUOTA NFNLGRP_ACCT_QUOTA | ||
23 | __NFNLGRP_MAX, | 25 | __NFNLGRP_MAX, |
24 | }; | 26 | }; |
25 | #define NFNLGRP_MAX (__NFNLGRP_MAX - 1) | 27 | #define NFNLGRP_MAX (__NFNLGRP_MAX - 1) |
diff --git a/include/uapi/linux/netfilter/nfnetlink_acct.h b/include/uapi/linux/netfilter/nfnetlink_acct.h index c7b6269e760b..51404ec19022 100644 --- a/include/uapi/linux/netfilter/nfnetlink_acct.h +++ b/include/uapi/linux/netfilter/nfnetlink_acct.h | |||
@@ -10,15 +10,24 @@ enum nfnl_acct_msg_types { | |||
10 | NFNL_MSG_ACCT_GET, | 10 | NFNL_MSG_ACCT_GET, |
11 | NFNL_MSG_ACCT_GET_CTRZERO, | 11 | NFNL_MSG_ACCT_GET_CTRZERO, |
12 | NFNL_MSG_ACCT_DEL, | 12 | NFNL_MSG_ACCT_DEL, |
13 | NFNL_MSG_ACCT_OVERQUOTA, | ||
13 | NFNL_MSG_ACCT_MAX | 14 | NFNL_MSG_ACCT_MAX |
14 | }; | 15 | }; |
15 | 16 | ||
17 | enum nfnl_acct_flags { | ||
18 | NFACCT_F_QUOTA_PKTS = (1 << 0), | ||
19 | NFACCT_F_QUOTA_BYTES = (1 << 1), | ||
20 | NFACCT_F_OVERQUOTA = (1 << 2), /* can't be set from userspace */ | ||
21 | }; | ||
22 | |||
16 | enum nfnl_acct_type { | 23 | enum nfnl_acct_type { |
17 | NFACCT_UNSPEC, | 24 | NFACCT_UNSPEC, |
18 | NFACCT_NAME, | 25 | NFACCT_NAME, |
19 | NFACCT_PKTS, | 26 | NFACCT_PKTS, |
20 | NFACCT_BYTES, | 27 | NFACCT_BYTES, |
21 | NFACCT_USE, | 28 | NFACCT_USE, |
29 | NFACCT_FLAGS, | ||
30 | NFACCT_QUOTA, | ||
22 | __NFACCT_MAX | 31 | __NFACCT_MAX |
23 | }; | 32 | }; |
24 | #define NFACCT_MAX (__NFACCT_MAX - 1) | 33 | #define NFACCT_MAX (__NFACCT_MAX - 1) |
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c index ee2886126e3d..f1787c04a4dd 100644 --- a/net/ipv4/netfilter/iptable_nat.c +++ b/net/ipv4/netfilter/iptable_nat.c | |||
@@ -91,17 +91,9 @@ nf_nat_ipv4_fn(const struct nf_hook_ops *ops, | |||
91 | if (nf_ct_is_untracked(ct)) | 91 | if (nf_ct_is_untracked(ct)) |
92 | return NF_ACCEPT; | 92 | return NF_ACCEPT; |
93 | 93 | ||
94 | nat = nfct_nat(ct); | 94 | nat = nf_ct_nat_ext_add(ct); |
95 | if (!nat) { | 95 | if (nat == NULL) |
96 | /* NAT module was loaded late. */ | 96 | return NF_ACCEPT; |
97 | if (nf_ct_is_confirmed(ct)) | ||
98 | return NF_ACCEPT; | ||
99 | nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | ||
100 | if (nat == NULL) { | ||
101 | pr_debug("failed to add NAT extension\n"); | ||
102 | return NF_ACCEPT; | ||
103 | } | ||
104 | } | ||
105 | 97 | ||
106 | switch (ctinfo) { | 98 | switch (ctinfo) { |
107 | case IP_CT_RELATED: | 99 | case IP_CT_RELATED: |
diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c index b5b256d45e67..3964157d826c 100644 --- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c +++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c | |||
@@ -48,15 +48,9 @@ static unsigned int nf_nat_fn(const struct nf_hook_ops *ops, | |||
48 | 48 | ||
49 | NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET))); | 49 | NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET))); |
50 | 50 | ||
51 | nat = nfct_nat(ct); | 51 | nat = nf_ct_nat_ext_add(ct); |
52 | if (nat == NULL) { | 52 | if (nat == NULL) |
53 | /* Conntrack module was loaded late, can't add extension. */ | 53 | return NF_ACCEPT; |
54 | if (nf_ct_is_confirmed(ct)) | ||
55 | return NF_ACCEPT; | ||
56 | nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | ||
57 | if (nat == NULL) | ||
58 | return NF_ACCEPT; | ||
59 | } | ||
60 | 54 | ||
61 | switch (ctinfo) { | 55 | switch (ctinfo) { |
62 | case IP_CT_RELATED: | 56 | case IP_CT_RELATED: |
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index 84c7f33d0cf8..387d8b8fc18d 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c | |||
@@ -90,17 +90,9 @@ nf_nat_ipv6_fn(const struct nf_hook_ops *ops, | |||
90 | if (nf_ct_is_untracked(ct)) | 90 | if (nf_ct_is_untracked(ct)) |
91 | return NF_ACCEPT; | 91 | return NF_ACCEPT; |
92 | 92 | ||
93 | nat = nfct_nat(ct); | 93 | nat = nf_ct_nat_ext_add(ct); |
94 | if (!nat) { | 94 | if (nat == NULL) |
95 | /* NAT module was loaded late. */ | 95 | return NF_ACCEPT; |
96 | if (nf_ct_is_confirmed(ct)) | ||
97 | return NF_ACCEPT; | ||
98 | nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | ||
99 | if (nat == NULL) { | ||
100 | pr_debug("failed to add NAT extension\n"); | ||
101 | return NF_ACCEPT; | ||
102 | } | ||
103 | } | ||
104 | 96 | ||
105 | switch (ctinfo) { | 97 | switch (ctinfo) { |
106 | case IP_CT_RELATED: | 98 | case IP_CT_RELATED: |
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c index 9c3297a768fd..d189fcb437fe 100644 --- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c | |||
@@ -47,15 +47,9 @@ static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, | |||
47 | if (ct == NULL || nf_ct_is_untracked(ct)) | 47 | if (ct == NULL || nf_ct_is_untracked(ct)) |
48 | return NF_ACCEPT; | 48 | return NF_ACCEPT; |
49 | 49 | ||
50 | nat = nfct_nat(ct); | 50 | nat = nf_ct_nat_ext_add(ct); |
51 | if (nat == NULL) { | 51 | if (nat == NULL) |
52 | /* Conntrack module was loaded late, can't add extension. */ | 52 | return NF_ACCEPT; |
53 | if (nf_ct_is_confirmed(ct)) | ||
54 | return NF_ACCEPT; | ||
55 | nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | ||
56 | if (nat == NULL) | ||
57 | return NF_ACCEPT; | ||
58 | } | ||
59 | 53 | ||
60 | switch (ctinfo) { | 54 | switch (ctinfo) { |
61 | case IP_CT_RELATED: | 55 | case IP_CT_RELATED: |
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 4f26ee46b51f..d9da8c448c76 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
@@ -97,7 +97,7 @@ const char *ip_vs_proto_name(unsigned int proto) | |||
97 | return "ICMPv6"; | 97 | return "ICMPv6"; |
98 | #endif | 98 | #endif |
99 | default: | 99 | default: |
100 | sprintf(buf, "IP_%d", proto); | 100 | sprintf(buf, "IP_%u", proto); |
101 | return buf; | 101 | return buf; |
102 | } | 102 | } |
103 | } | 103 | } |
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 52ca952b802c..09096a670c45 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c | |||
@@ -358,6 +358,19 @@ out: | |||
358 | rcu_read_unlock(); | 358 | rcu_read_unlock(); |
359 | } | 359 | } |
360 | 360 | ||
361 | struct nf_conn_nat *nf_ct_nat_ext_add(struct nf_conn *ct) | ||
362 | { | ||
363 | struct nf_conn_nat *nat = nfct_nat(ct); | ||
364 | if (nat) | ||
365 | return nat; | ||
366 | |||
367 | if (!nf_ct_is_confirmed(ct)) | ||
368 | nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | ||
369 | |||
370 | return nat; | ||
371 | } | ||
372 | EXPORT_SYMBOL_GPL(nf_ct_nat_ext_add); | ||
373 | |||
361 | unsigned int | 374 | unsigned int |
362 | nf_nat_setup_info(struct nf_conn *ct, | 375 | nf_nat_setup_info(struct nf_conn *ct, |
363 | const struct nf_nat_range *range, | 376 | const struct nf_nat_range *range, |
@@ -368,14 +381,9 @@ nf_nat_setup_info(struct nf_conn *ct, | |||
368 | struct nf_conn_nat *nat; | 381 | struct nf_conn_nat *nat; |
369 | 382 | ||
370 | /* nat helper or nfctnetlink also setup binding */ | 383 | /* nat helper or nfctnetlink also setup binding */ |
371 | nat = nfct_nat(ct); | 384 | nat = nf_ct_nat_ext_add(ct); |
372 | if (!nat) { | 385 | if (nat == NULL) |
373 | nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | 386 | return NF_ACCEPT; |
374 | if (nat == NULL) { | ||
375 | pr_debug("failed to add NAT extension\n"); | ||
376 | return NF_ACCEPT; | ||
377 | } | ||
378 | } | ||
379 | 387 | ||
380 | NF_CT_ASSERT(maniptype == NF_NAT_MANIP_SRC || | 388 | NF_CT_ASSERT(maniptype == NF_NAT_MANIP_SRC || |
381 | maniptype == NF_NAT_MANIP_DST); | 389 | maniptype == NF_NAT_MANIP_DST); |
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c index c7b6d466a662..70e86bbb3637 100644 --- a/net/netfilter/nfnetlink_acct.c +++ b/net/netfilter/nfnetlink_acct.c | |||
@@ -32,18 +32,24 @@ static LIST_HEAD(nfnl_acct_list); | |||
32 | struct nf_acct { | 32 | struct nf_acct { |
33 | atomic64_t pkts; | 33 | atomic64_t pkts; |
34 | atomic64_t bytes; | 34 | atomic64_t bytes; |
35 | unsigned long flags; | ||
35 | struct list_head head; | 36 | struct list_head head; |
36 | atomic_t refcnt; | 37 | atomic_t refcnt; |
37 | char name[NFACCT_NAME_MAX]; | 38 | char name[NFACCT_NAME_MAX]; |
38 | struct rcu_head rcu_head; | 39 | struct rcu_head rcu_head; |
40 | char data[0]; | ||
39 | }; | 41 | }; |
40 | 42 | ||
43 | #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES) | ||
44 | |||
41 | static int | 45 | static int |
42 | nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, | 46 | nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, |
43 | const struct nlmsghdr *nlh, const struct nlattr * const tb[]) | 47 | const struct nlmsghdr *nlh, const struct nlattr * const tb[]) |
44 | { | 48 | { |
45 | struct nf_acct *nfacct, *matching = NULL; | 49 | struct nf_acct *nfacct, *matching = NULL; |
46 | char *acct_name; | 50 | char *acct_name; |
51 | unsigned int size = 0; | ||
52 | u32 flags = 0; | ||
47 | 53 | ||
48 | if (!tb[NFACCT_NAME]) | 54 | if (!tb[NFACCT_NAME]) |
49 | return -EINVAL; | 55 | return -EINVAL; |
@@ -68,15 +74,39 @@ nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb, | |||
68 | /* reset counters if you request a replacement. */ | 74 | /* reset counters if you request a replacement. */ |
69 | atomic64_set(&matching->pkts, 0); | 75 | atomic64_set(&matching->pkts, 0); |
70 | atomic64_set(&matching->bytes, 0); | 76 | atomic64_set(&matching->bytes, 0); |
77 | smp_mb__before_clear_bit(); | ||
78 | /* reset overquota flag if quota is enabled. */ | ||
79 | if ((matching->flags & NFACCT_F_QUOTA)) | ||
80 | clear_bit(NFACCT_F_OVERQUOTA, &matching->flags); | ||
71 | return 0; | 81 | return 0; |
72 | } | 82 | } |
73 | return -EBUSY; | 83 | return -EBUSY; |
74 | } | 84 | } |
75 | 85 | ||
76 | nfacct = kzalloc(sizeof(struct nf_acct), GFP_KERNEL); | 86 | nfacct = kzalloc(sizeof(struct nf_acct), GFP_KERNEL); |
87 | if (tb[NFACCT_FLAGS]) { | ||
88 | flags = ntohl(nla_get_be32(tb[NFACCT_FLAGS])); | ||
89 | if (flags & ~NFACCT_F_QUOTA) | ||
90 | return -EOPNOTSUPP; | ||
91 | if ((flags & NFACCT_F_QUOTA) == NFACCT_F_QUOTA) | ||
92 | return -EINVAL; | ||
93 | if (flags & NFACCT_F_OVERQUOTA) | ||
94 | return -EINVAL; | ||
95 | |||
96 | size += sizeof(u64); | ||
97 | } | ||
98 | |||
99 | nfacct = kzalloc(sizeof(struct nf_acct) + size, GFP_KERNEL); | ||
77 | if (nfacct == NULL) | 100 | if (nfacct == NULL) |
78 | return -ENOMEM; | 101 | return -ENOMEM; |
79 | 102 | ||
103 | if (flags & NFACCT_F_QUOTA) { | ||
104 | u64 *quota = (u64 *)nfacct->data; | ||
105 | |||
106 | *quota = be64_to_cpu(nla_get_be64(tb[NFACCT_QUOTA])); | ||
107 | nfacct->flags = flags; | ||
108 | } | ||
109 | |||
80 | strncpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX); | 110 | strncpy(nfacct->name, nla_data(tb[NFACCT_NAME]), NFACCT_NAME_MAX); |
81 | 111 | ||
82 | if (tb[NFACCT_BYTES]) { | 112 | if (tb[NFACCT_BYTES]) { |
@@ -117,6 +147,9 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, | |||
117 | if (type == NFNL_MSG_ACCT_GET_CTRZERO) { | 147 | if (type == NFNL_MSG_ACCT_GET_CTRZERO) { |
118 | pkts = atomic64_xchg(&acct->pkts, 0); | 148 | pkts = atomic64_xchg(&acct->pkts, 0); |
119 | bytes = atomic64_xchg(&acct->bytes, 0); | 149 | bytes = atomic64_xchg(&acct->bytes, 0); |
150 | smp_mb__before_clear_bit(); | ||
151 | if (acct->flags & NFACCT_F_QUOTA) | ||
152 | clear_bit(NFACCT_F_OVERQUOTA, &acct->flags); | ||
120 | } else { | 153 | } else { |
121 | pkts = atomic64_read(&acct->pkts); | 154 | pkts = atomic64_read(&acct->pkts); |
122 | bytes = atomic64_read(&acct->bytes); | 155 | bytes = atomic64_read(&acct->bytes); |
@@ -125,7 +158,13 @@ nfnl_acct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, | |||
125 | nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes)) || | 158 | nla_put_be64(skb, NFACCT_BYTES, cpu_to_be64(bytes)) || |
126 | nla_put_be32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt)))) | 159 | nla_put_be32(skb, NFACCT_USE, htonl(atomic_read(&acct->refcnt)))) |
127 | goto nla_put_failure; | 160 | goto nla_put_failure; |
161 | if (acct->flags & NFACCT_F_QUOTA) { | ||
162 | u64 *quota = (u64 *)acct->data; | ||
128 | 163 | ||
164 | if (nla_put_be32(skb, NFACCT_FLAGS, htonl(acct->flags)) || | ||
165 | nla_put_be64(skb, NFACCT_QUOTA, cpu_to_be64(*quota))) | ||
166 | goto nla_put_failure; | ||
167 | } | ||
129 | nlmsg_end(skb, nlh); | 168 | nlmsg_end(skb, nlh); |
130 | return skb->len; | 169 | return skb->len; |
131 | 170 | ||
@@ -270,6 +309,8 @@ static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = { | |||
270 | [NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 }, | 309 | [NFACCT_NAME] = { .type = NLA_NUL_STRING, .len = NFACCT_NAME_MAX-1 }, |
271 | [NFACCT_BYTES] = { .type = NLA_U64 }, | 310 | [NFACCT_BYTES] = { .type = NLA_U64 }, |
272 | [NFACCT_PKTS] = { .type = NLA_U64 }, | 311 | [NFACCT_PKTS] = { .type = NLA_U64 }, |
312 | [NFACCT_FLAGS] = { .type = NLA_U32 }, | ||
313 | [NFACCT_QUOTA] = { .type = NLA_U64 }, | ||
273 | }; | 314 | }; |
274 | 315 | ||
275 | static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = { | 316 | static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = { |
@@ -336,6 +377,50 @@ void nfnl_acct_update(const struct sk_buff *skb, struct nf_acct *nfacct) | |||
336 | } | 377 | } |
337 | EXPORT_SYMBOL_GPL(nfnl_acct_update); | 378 | EXPORT_SYMBOL_GPL(nfnl_acct_update); |
338 | 379 | ||
380 | static void nfnl_overquota_report(struct nf_acct *nfacct) | ||
381 | { | ||
382 | int ret; | ||
383 | struct sk_buff *skb; | ||
384 | |||
385 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | ||
386 | if (skb == NULL) | ||
387 | return; | ||
388 | |||
389 | ret = nfnl_acct_fill_info(skb, 0, 0, NFNL_MSG_ACCT_OVERQUOTA, 0, | ||
390 | nfacct); | ||
391 | if (ret <= 0) { | ||
392 | kfree_skb(skb); | ||
393 | return; | ||
394 | } | ||
395 | netlink_broadcast(init_net.nfnl, skb, 0, NFNLGRP_ACCT_QUOTA, | ||
396 | GFP_ATOMIC); | ||
397 | } | ||
398 | |||
399 | int nfnl_acct_overquota(const struct sk_buff *skb, struct nf_acct *nfacct) | ||
400 | { | ||
401 | u64 now; | ||
402 | u64 *quota; | ||
403 | int ret = NFACCT_UNDERQUOTA; | ||
404 | |||
405 | /* no place here if we don't have a quota */ | ||
406 | if (!(nfacct->flags & NFACCT_F_QUOTA)) | ||
407 | return NFACCT_NO_QUOTA; | ||
408 | |||
409 | quota = (u64 *)nfacct->data; | ||
410 | now = (nfacct->flags & NFACCT_F_QUOTA_PKTS) ? | ||
411 | atomic64_read(&nfacct->pkts) : atomic64_read(&nfacct->bytes); | ||
412 | |||
413 | ret = now > *quota; | ||
414 | |||
415 | if (now >= *quota && | ||
416 | !test_and_set_bit(NFACCT_F_OVERQUOTA, &nfacct->flags)) { | ||
417 | nfnl_overquota_report(nfacct); | ||
418 | } | ||
419 | |||
420 | return ret; | ||
421 | } | ||
422 | EXPORT_SYMBOL_GPL(nfnl_acct_overquota); | ||
423 | |||
339 | static int __init nfnl_acct_init(void) | 424 | static int __init nfnl_acct_init(void) |
340 | { | 425 | { |
341 | int ret; | 426 | int ret; |
diff --git a/net/netfilter/xt_nfacct.c b/net/netfilter/xt_nfacct.c index b3be0ef21f19..8c646ed9c921 100644 --- a/net/netfilter/xt_nfacct.c +++ b/net/netfilter/xt_nfacct.c | |||
@@ -21,11 +21,14 @@ MODULE_ALIAS("ip6t_nfacct"); | |||
21 | 21 | ||
22 | static bool nfacct_mt(const struct sk_buff *skb, struct xt_action_param *par) | 22 | static bool nfacct_mt(const struct sk_buff *skb, struct xt_action_param *par) |
23 | { | 23 | { |
24 | int overquota; | ||
24 | const struct xt_nfacct_match_info *info = par->targinfo; | 25 | const struct xt_nfacct_match_info *info = par->targinfo; |
25 | 26 | ||
26 | nfnl_acct_update(skb, info->nfacct); | 27 | nfnl_acct_update(skb, info->nfacct); |
27 | 28 | ||
28 | return true; | 29 | overquota = nfnl_acct_overquota(skb, info->nfacct); |
30 | |||
31 | return overquota == NFACCT_UNDERQUOTA ? false : true; | ||
29 | } | 32 | } |
30 | 33 | ||
31 | static int | 34 | static int |