* [PATCH 01/56] netfilter: ebtables: simplify a device in/out check
2010-06-29 8:42 xt2 table core Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 02/56] netfilter: ebtables: change ebt_basic_match to xt convention Jan Engelhardt
` (33 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Stumbled across and fixed to be more readable.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
net/bridge/netfilter/ebtables.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 59ca00e..3c3fcca 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -140,11 +140,13 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
return 1;
if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
return 1;
- if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
- e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))
+ if (in != NULL && in->br_port != NULL &&
+ FWINV2(ebt_dev_check(e->logical_in, in->br_port->br->dev),
+ EBT_ILOGICALIN))
return 1;
- if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
- e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))
+ if (out != NULL && out->br_port != NULL &&
+ FWINV2(ebt_dev_check(e->logical_out, out->br_port->br->dev),
+ EBT_ILOGICALOUT))
return 1;
if (e->bitmask & EBT_SOURCEMAC) {
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 02/56] netfilter: ebtables: change ebt_basic_match to xt convention
2010-06-29 8:42 xt2 table core Jan Engelhardt
2010-06-29 8:42 ` [PATCH 01/56] netfilter: ebtables: simplify a device in/out check Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 03/56] netfilter: xtables: move functions around Jan Engelhardt
` (32 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
When this will become an xt_match, it needs the xt semantics;
this mandates changing the return values from 1/0 to 0/1.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
net/bridge/netfilter/ebtables.c | 22 +++++++++++-----------
1 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 3c3fcca..dd7af64 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -123,7 +123,7 @@ ebt_dev_check(const char *entry, const struct net_device *device)
#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
/* process standard matches */
-static inline int
+static inline bool
ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
const struct net_device *in, const struct net_device *out)
{
@@ -131,23 +131,23 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
if (e->bitmask & EBT_802_3) {
if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
- return 1;
+ return false;
} else if (!(e->bitmask & EBT_NOPROTO) &&
FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
- return 1;
+ return false;
if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
- return 1;
+ return false;
if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
- return 1;
+ return false;
if (in != NULL && in->br_port != NULL &&
FWINV2(ebt_dev_check(e->logical_in, in->br_port->br->dev),
EBT_ILOGICALIN))
- return 1;
+ return false;
if (out != NULL && out->br_port != NULL &&
FWINV2(ebt_dev_check(e->logical_out, out->br_port->br->dev),
EBT_ILOGICALOUT))
- return 1;
+ return false;
if (e->bitmask & EBT_SOURCEMAC) {
verdict = 0;
@@ -155,7 +155,7 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
e->sourcemsk[i];
if (FWINV2(verdict != 0, EBT_ISOURCE) )
- return 1;
+ return false;
}
if (e->bitmask & EBT_DESTMAC) {
verdict = 0;
@@ -163,9 +163,9 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
verdict |= (h->h_dest[i] ^ e->destmac[i]) &
e->destmsk[i];
if (FWINV2(verdict != 0, EBT_IDEST) )
- return 1;
+ return false;
}
- return 0;
+ return true;
}
static inline __pure
@@ -212,7 +212,7 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
base = private->entries;
i = 0;
while (i < nentries) {
- if (ebt_basic_match(point, eth_hdr(skb), in, out))
+ if (!ebt_basic_match(point, eth_hdr(skb), in, out))
goto letscontinue;
if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &acpar) != 0)
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 03/56] netfilter: xtables: move functions around
2010-06-29 8:42 xt2 table core Jan Engelhardt
2010-06-29 8:42 ` [PATCH 01/56] netfilter: ebtables: simplify a device in/out check Jan Engelhardt
2010-06-29 8:42 ` [PATCH 02/56] netfilter: ebtables: change ebt_basic_match to xt convention Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 04/56] netfilter: xtables: convert basic nfproto match functions into xt matches Jan Engelhardt
` (31 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
For the next patch, the builtin_mt object needs to be available ahead
of ip6t_do_table if we want to do without predeclartions.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
net/ipv4/netfilter/arp_tables.c | 77 +++++++-------
net/ipv4/netfilter/ip_tables.c | 192 ++++++++++++++++++------------------
net/ipv6/netfilter/ip6_tables.c | 208 ++++++++++++++++++++-------------------
3 files changed, 241 insertions(+), 236 deletions(-)
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 16c0ba0..ec89fd4 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -218,6 +218,26 @@ static inline int arp_checkentry(const struct arpt_arp *arp)
return 1;
}
+#ifdef CONFIG_COMPAT
+static void compat_standard_from_user(void *dst, const void *src)
+{
+ int v = *(compat_int_t *)src;
+
+ if (v > 0)
+ v += xt_compat_calc_jump(NFPROTO_ARP, v);
+ memcpy(dst, &v, sizeof(v));
+}
+
+static int compat_standard_to_user(void __user *dst, const void *src)
+{
+ compat_int_t cv = *(int *)src;
+
+ if (cv > 0)
+ cv -= xt_compat_calc_jump(NFPROTO_ARP, cv);
+ return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
+}
+#endif
+
static unsigned int
arpt_error(struct sk_buff *skb, const struct xt_action_param *par)
{
@@ -228,6 +248,25 @@ arpt_error(struct sk_buff *skb, const struct xt_action_param *par)
return NF_DROP;
}
+static struct xt_target arpt_builtin_tg[] __read_mostly = {
+ {
+ .name = ARPT_STANDARD_TARGET,
+ .targetsize = sizeof(int),
+ .family = NFPROTO_ARP,
+#ifdef CONFIG_COMPAT
+ .compatsize = sizeof(compat_int_t),
+ .compat_from_user = compat_standard_from_user,
+ .compat_to_user = compat_standard_to_user,
+#endif
+ },
+ {
+ .name = ARPT_ERROR_TARGET,
+ .target = arpt_error,
+ .targetsize = ARPT_FUNCTION_MAXNAMELEN,
+ .family = NFPROTO_ARP,
+ },
+};
+
static inline const struct arpt_entry_target *
arpt_get_target_c(const struct arpt_entry *e)
{
@@ -821,24 +860,6 @@ static int copy_entries_to_user(unsigned int total_size,
}
#ifdef CONFIG_COMPAT
-static void compat_standard_from_user(void *dst, const void *src)
-{
- int v = *(compat_int_t *)src;
-
- if (v > 0)
- v += xt_compat_calc_jump(NFPROTO_ARP, v);
- memcpy(dst, &v, sizeof(v));
-}
-
-static int compat_standard_to_user(void __user *dst, const void *src)
-{
- compat_int_t cv = *(int *)src;
-
- if (cv > 0)
- cv -= xt_compat_calc_jump(NFPROTO_ARP, cv);
- return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
-}
-
static int compat_calc_entry(const struct arpt_entry *e,
const struct xt_table_info *info,
const void *base, struct xt_table_info *newinfo)
@@ -1821,26 +1842,6 @@ void arpt_unregister_table(struct xt_table *table)
xt_free_table_info(private);
}
-/* The built-in targets: standard (NULL) and error. */
-static struct xt_target arpt_builtin_tg[] __read_mostly = {
- {
- .name = ARPT_STANDARD_TARGET,
- .targetsize = sizeof(int),
- .family = NFPROTO_ARP,
-#ifdef CONFIG_COMPAT
- .compatsize = sizeof(compat_int_t),
- .compat_from_user = compat_standard_from_user,
- .compat_to_user = compat_standard_to_user,
-#endif
- },
- {
- .name = ARPT_ERROR_TARGET,
- .target = arpt_error,
- .targetsize = ARPT_FUNCTION_MAXNAMELEN,
- .family = NFPROTO_ARP,
- },
-};
-
static struct nf_sockopt_ops arpt_sockopts = {
.pf = PF_INET,
.set_optmin = ARPT_BASE_CTL,
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index b38c118..e98347f 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -159,6 +159,73 @@ ip_checkentry(const struct ipt_ip *ip)
return true;
}
+/* Returns 1 if the type and code is matched by the range, 0 otherwise */
+static inline bool
+icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
+ u_int8_t type, u_int8_t code,
+ bool invert)
+{
+ return ((test_type == 0xFF) ||
+ (type == test_type && code >= min_code && code <= max_code))
+ ^ invert;
+}
+
+static bool
+icmp_match(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct icmphdr *ic;
+ struct icmphdr _icmph;
+ const struct ipt_icmp *icmpinfo = par->matchinfo;
+
+ /* Must not be a fragment. */
+ if (par->fragoff != 0)
+ return false;
+
+ ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
+ if (ic == NULL) {
+ /* We've been asked to examine this packet, and we
+ * can't. Hence, no choice but to drop.
+ */
+ duprintf("Dropping evil ICMP tinygram.\n");
+ par->hotdrop = true;
+ return false;
+ }
+
+ return icmp_type_code_match(icmpinfo->type,
+ icmpinfo->code[0],
+ icmpinfo->code[1],
+ ic->type, ic->code,
+ !!(icmpinfo->invflags&IPT_ICMP_INV));
+}
+
+static int icmp_checkentry(const struct xt_mtchk_param *par)
+{
+ const struct ipt_icmp *icmpinfo = par->matchinfo;
+
+ /* Must specify no unknown invflags */
+ return (icmpinfo->invflags & ~IPT_ICMP_INV) ? -EINVAL : 0;
+}
+
+#ifdef CONFIG_COMPAT
+static void compat_standard_from_user(void *dst, const void *src)
+{
+ int v = *(compat_int_t *)src;
+
+ if (v > 0)
+ v += xt_compat_calc_jump(AF_INET, v);
+ memcpy(dst, &v, sizeof(v));
+}
+
+static int compat_standard_to_user(void __user *dst, const void *src)
+{
+ compat_int_t cv = *(int *)src;
+
+ if (cv > 0)
+ cv -= xt_compat_calc_jump(AF_INET, cv);
+ return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
+}
+#endif
+
static unsigned int
ipt_error(struct sk_buff *skb, const struct xt_action_param *par)
{
@@ -168,6 +235,36 @@ ipt_error(struct sk_buff *skb, const struct xt_action_param *par)
return NF_DROP;
}
+static struct xt_target ipt_builtin_tg[] __read_mostly = {
+ {
+ .name = IPT_STANDARD_TARGET,
+ .targetsize = sizeof(int),
+ .family = NFPROTO_IPV4,
+#ifdef CONFIG_COMPAT
+ .compatsize = sizeof(compat_int_t),
+ .compat_from_user = compat_standard_from_user,
+ .compat_to_user = compat_standard_to_user,
+#endif
+ },
+ {
+ .name = IPT_ERROR_TARGET,
+ .target = ipt_error,
+ .targetsize = IPT_FUNCTION_MAXNAMELEN,
+ .family = NFPROTO_IPV4,
+ },
+};
+
+static struct xt_match ipt_builtin_mt[] __read_mostly = {
+ {
+ .name = "icmp",
+ .match = icmp_match,
+ .matchsize = sizeof(struct ipt_icmp),
+ .checkentry = icmp_checkentry,
+ .proto = IPPROTO_ICMP,
+ .family = NFPROTO_IPV4,
+ },
+};
+
/* Performance critical */
static inline struct ipt_entry *
get_entry(const void *base, unsigned int offset)
@@ -1013,24 +1110,6 @@ copy_entries_to_user(unsigned int total_size,
}
#ifdef CONFIG_COMPAT
-static void compat_standard_from_user(void *dst, const void *src)
-{
- int v = *(compat_int_t *)src;
-
- if (v > 0)
- v += xt_compat_calc_jump(AF_INET, v);
- memcpy(dst, &v, sizeof(v));
-}
-
-static int compat_standard_to_user(void __user *dst, const void *src)
-{
- compat_int_t cv = *(int *)src;
-
- if (cv > 0)
- cv -= xt_compat_calc_jump(AF_INET, cv);
- return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
-}
-
static int compat_calc_entry(const struct ipt_entry *e,
const struct xt_table_info *info,
const void *base, struct xt_table_info *newinfo)
@@ -2120,72 +2199,6 @@ void ipt_unregister_table(struct net *net, struct xt_table *table)
xt_free_table_info(private);
}
-/* Returns 1 if the type and code is matched by the range, 0 otherwise */
-static inline bool
-icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
- u_int8_t type, u_int8_t code,
- bool invert)
-{
- return ((test_type == 0xFF) ||
- (type == test_type && code >= min_code && code <= max_code))
- ^ invert;
-}
-
-static bool
-icmp_match(const struct sk_buff *skb, struct xt_action_param *par)
-{
- const struct icmphdr *ic;
- struct icmphdr _icmph;
- const struct ipt_icmp *icmpinfo = par->matchinfo;
-
- /* Must not be a fragment. */
- if (par->fragoff != 0)
- return false;
-
- ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
- if (ic == NULL) {
- /* We've been asked to examine this packet, and we
- * can't. Hence, no choice but to drop.
- */
- duprintf("Dropping evil ICMP tinygram.\n");
- par->hotdrop = true;
- return false;
- }
-
- return icmp_type_code_match(icmpinfo->type,
- icmpinfo->code[0],
- icmpinfo->code[1],
- ic->type, ic->code,
- !!(icmpinfo->invflags&IPT_ICMP_INV));
-}
-
-static int icmp_checkentry(const struct xt_mtchk_param *par)
-{
- const struct ipt_icmp *icmpinfo = par->matchinfo;
-
- /* Must specify no unknown invflags */
- return (icmpinfo->invflags & ~IPT_ICMP_INV) ? -EINVAL : 0;
-}
-
-static struct xt_target ipt_builtin_tg[] __read_mostly = {
- {
- .name = IPT_STANDARD_TARGET,
- .targetsize = sizeof(int),
- .family = NFPROTO_IPV4,
-#ifdef CONFIG_COMPAT
- .compatsize = sizeof(compat_int_t),
- .compat_from_user = compat_standard_from_user,
- .compat_to_user = compat_standard_to_user,
-#endif
- },
- {
- .name = IPT_ERROR_TARGET,
- .target = ipt_error,
- .targetsize = IPT_FUNCTION_MAXNAMELEN,
- .family = NFPROTO_IPV4,
- },
-};
-
static struct nf_sockopt_ops ipt_sockopts = {
.pf = PF_INET,
.set_optmin = IPT_BASE_CTL,
@@ -2203,17 +2216,6 @@ static struct nf_sockopt_ops ipt_sockopts = {
.owner = THIS_MODULE,
};
-static struct xt_match ipt_builtin_mt[] __read_mostly = {
- {
- .name = "icmp",
- .match = icmp_match,
- .matchsize = sizeof(struct ipt_icmp),
- .checkentry = icmp_checkentry,
- .proto = IPPROTO_ICMP,
- .family = NFPROTO_IPV4,
- },
-};
-
static int __net_init ip_tables_net_init(struct net *net)
{
return xt_proto_init(net, NFPROTO_IPV4);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index dc41d6d..2bcf20b 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -82,13 +82,13 @@ EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
int
ip6t_ext_hdr(u8 nexthdr)
{
- return ( (nexthdr == IPPROTO_HOPOPTS) ||
- (nexthdr == IPPROTO_ROUTING) ||
- (nexthdr == IPPROTO_FRAGMENT) ||
- (nexthdr == IPPROTO_ESP) ||
- (nexthdr == IPPROTO_AH) ||
- (nexthdr == IPPROTO_NONE) ||
- (nexthdr == IPPROTO_DSTOPTS) );
+ return nexthdr == IPPROTO_HOPOPTS ||
+ nexthdr == IPPROTO_ROUTING ||
+ nexthdr == IPPROTO_FRAGMENT ||
+ nexthdr == IPPROTO_ESP ||
+ nexthdr == IPPROTO_AH ||
+ nexthdr == IPPROTO_NONE ||
+ nexthdr == IPPROTO_DSTOPTS;
}
/* Returns whether matches rule or not. */
@@ -191,6 +191,73 @@ ip6_checkentry(const struct ip6t_ip6 *ipv6)
return true;
}
+/* Returns 1 if the type and code is matched by the range, 0 otherwise */
+static inline bool
+icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
+ u_int8_t type, u_int8_t code,
+ bool invert)
+{
+ return (type == test_type && code >= min_code && code <= max_code)
+ ^ invert;
+}
+
+static bool
+icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct icmp6hdr *ic;
+ struct icmp6hdr _icmph;
+ const struct ip6t_icmp *icmpinfo = par->matchinfo;
+
+ /* Must not be a fragment. */
+ if (par->fragoff != 0)
+ return false;
+
+ ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
+ if (ic == NULL) {
+ /* We've been asked to examine this packet, and we
+ * can't. Hence, no choice but to drop.
+ */
+ duprintf("Dropping evil ICMP tinygram.\n");
+ par->hotdrop = true;
+ return false;
+ }
+
+ return icmp6_type_code_match(icmpinfo->type,
+ icmpinfo->code[0],
+ icmpinfo->code[1],
+ ic->icmp6_type, ic->icmp6_code,
+ !!(icmpinfo->invflags&IP6T_ICMP_INV));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int icmp6_checkentry(const struct xt_mtchk_param *par)
+{
+ const struct ip6t_icmp *icmpinfo = par->matchinfo;
+
+ /* Must specify no unknown invflags */
+ return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
+}
+
+#ifdef CONFIG_COMPAT
+static void compat_standard_from_user(void *dst, const void *src)
+{
+ int v = *(compat_int_t *)src;
+
+ if (v > 0)
+ v += xt_compat_calc_jump(AF_INET6, v);
+ memcpy(dst, &v, sizeof(v));
+}
+
+static int compat_standard_to_user(void __user *dst, const void *src)
+{
+ compat_int_t cv = *(int *)src;
+
+ if (cv > 0)
+ cv -= xt_compat_calc_jump(AF_INET6, cv);
+ return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
+}
+#endif
+
static unsigned int
ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
{
@@ -200,6 +267,37 @@ ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
return NF_DROP;
}
+/* The built-in targets: standard (NULL) and error. */
+static struct xt_target ip6t_builtin_tg[] __read_mostly = {
+ {
+ .name = IP6T_STANDARD_TARGET,
+ .targetsize = sizeof(int),
+ .family = NFPROTO_IPV6,
+#ifdef CONFIG_COMPAT
+ .compatsize = sizeof(compat_int_t),
+ .compat_from_user = compat_standard_from_user,
+ .compat_to_user = compat_standard_to_user,
+#endif
+ },
+ {
+ .name = IP6T_ERROR_TARGET,
+ .target = ip6t_error,
+ .targetsize = IP6T_FUNCTION_MAXNAMELEN,
+ .family = NFPROTO_IPV6,
+ },
+};
+
+static struct xt_match ip6t_builtin_mt[] __read_mostly = {
+ {
+ .name = "icmp6",
+ .match = icmp6_match,
+ .matchsize = sizeof(struct ip6t_icmp),
+ .checkentry = icmp6_checkentry,
+ .proto = IPPROTO_ICMPV6,
+ .family = NFPROTO_IPV6,
+ },
+};
+
static inline struct ip6t_entry *
get_entry(const void *base, unsigned int offset)
{
@@ -1028,24 +1126,6 @@ copy_entries_to_user(unsigned int total_size,
}
#ifdef CONFIG_COMPAT
-static void compat_standard_from_user(void *dst, const void *src)
-{
- int v = *(compat_int_t *)src;
-
- if (v > 0)
- v += xt_compat_calc_jump(AF_INET6, v);
- memcpy(dst, &v, sizeof(v));
-}
-
-static int compat_standard_to_user(void __user *dst, const void *src)
-{
- compat_int_t cv = *(int *)src;
-
- if (cv > 0)
- cv -= xt_compat_calc_jump(AF_INET6, cv);
- return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
-}
-
static int compat_calc_entry(const struct ip6t_entry *e,
const struct xt_table_info *info,
const void *base, struct xt_table_info *newinfo)
@@ -2136,73 +2216,6 @@ void ip6t_unregister_table(struct net *net, struct xt_table *table)
xt_free_table_info(private);
}
-/* Returns 1 if the type and code is matched by the range, 0 otherwise */
-static inline bool
-icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
- u_int8_t type, u_int8_t code,
- bool invert)
-{
- return (type == test_type && code >= min_code && code <= max_code)
- ^ invert;
-}
-
-static bool
-icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
-{
- const struct icmp6hdr *ic;
- struct icmp6hdr _icmph;
- const struct ip6t_icmp *icmpinfo = par->matchinfo;
-
- /* Must not be a fragment. */
- if (par->fragoff != 0)
- return false;
-
- ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
- if (ic == NULL) {
- /* We've been asked to examine this packet, and we
- * can't. Hence, no choice but to drop.
- */
- duprintf("Dropping evil ICMP tinygram.\n");
- par->hotdrop = true;
- return false;
- }
-
- return icmp6_type_code_match(icmpinfo->type,
- icmpinfo->code[0],
- icmpinfo->code[1],
- ic->icmp6_type, ic->icmp6_code,
- !!(icmpinfo->invflags&IP6T_ICMP_INV));
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int icmp6_checkentry(const struct xt_mtchk_param *par)
-{
- const struct ip6t_icmp *icmpinfo = par->matchinfo;
-
- /* Must specify no unknown invflags */
- return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
-}
-
-/* The built-in targets: standard (NULL) and error. */
-static struct xt_target ip6t_builtin_tg[] __read_mostly = {
- {
- .name = IP6T_STANDARD_TARGET,
- .targetsize = sizeof(int),
- .family = NFPROTO_IPV6,
-#ifdef CONFIG_COMPAT
- .compatsize = sizeof(compat_int_t),
- .compat_from_user = compat_standard_from_user,
- .compat_to_user = compat_standard_to_user,
-#endif
- },
- {
- .name = IP6T_ERROR_TARGET,
- .target = ip6t_error,
- .targetsize = IP6T_FUNCTION_MAXNAMELEN,
- .family = NFPROTO_IPV6,
- },
-};
-
static struct nf_sockopt_ops ip6t_sockopts = {
.pf = PF_INET6,
.set_optmin = IP6T_BASE_CTL,
@@ -2220,17 +2233,6 @@ static struct nf_sockopt_ops ip6t_sockopts = {
.owner = THIS_MODULE,
};
-static struct xt_match ip6t_builtin_mt[] __read_mostly = {
- {
- .name = "icmp6",
- .match = icmp6_match,
- .matchsize = sizeof(struct ip6t_icmp),
- .checkentry = icmp6_checkentry,
- .proto = IPPROTO_ICMPV6,
- .family = NFPROTO_IPV6,
- },
-};
-
static int __net_init ip6_tables_net_init(struct net *net)
{
return xt_proto_init(net, NFPROTO_IPV6);
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 04/56] netfilter: xtables: convert basic nfproto match functions into xt matches
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (2 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 03/56] netfilter: xtables: move functions around Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 05/56] netfilter: xtables2: initial table skeletal functions Jan Engelhardt
` (30 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Each table implementation has a private built-in hardwired match
function for its corresponding nfproto data (e.g. ip_tables: struct
ipt6_ip6 processed by ip6_packet_match to match against the IPv6
header, etc.)
Rewrite the functions so that they are independent xt_matches and can
be used from an nfproto-independent table.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 4 +-
net/bridge/netfilter/ebtables.c | 96 ++++++++++++++++++++---------
net/ipv4/netfilter/arp_tables.c | 118 +++++++++++++++++++++++------------
net/ipv4/netfilter/ip_tables.c | 82 +++++++++++++++----------
net/ipv6/netfilter/ip6_tables.c | 90 ++++++++++++++++------------
5 files changed, 245 insertions(+), 145 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 24e5d01..8067cb5 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -191,14 +191,14 @@ struct xt_counters_info {
* @targetinfo: per-target data
* @in: input netdevice
* @out: output netdevice
- * @fragoff: packet is a fragment, this is the data offset
- * @thoff: position of transport header relative to skb->data
* @hook: hook number given packet came from
* @family: Actual NFPROTO_* through which the function is invoked
* (helpful when match->family == NFPROTO_UNSPEC)
*
* Fields written to by extensions:
*
+ * @fragoff: packet is a fragment, this is the data offset
+ * @thoff: position of transport header relative to skb->data
* @hotdrop: drop packet if we had inspection problems
* Network namespace obtainable using dev_net(in/out)
*/
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index dd7af64..4553ffd 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -123,10 +123,11 @@ ebt_dev_check(const char *entry, const struct net_device *device)
#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
/* process standard matches */
-static inline bool
-ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
- const struct net_device *in, const struct net_device *out)
+static bool
+ebt_basic_match(const struct sk_buff *skb, struct xt_action_param *par)
{
+ const struct ethhdr *h = eth_hdr(skb);
+ const struct ebt_entry *e = par->matchinfo;
int verdict, i;
if (e->bitmask & EBT_802_3) {
@@ -136,16 +137,16 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
return false;
- if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
+ if (FWINV2(ebt_dev_check(e->in, par->in), EBT_IIN))
return false;
- if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
+ if (FWINV2(ebt_dev_check(e->out, par->out), EBT_IOUT))
return false;
- if (in != NULL && in->br_port != NULL &&
- FWINV2(ebt_dev_check(e->logical_in, in->br_port->br->dev),
+ if (par->in != NULL && par->in->br_port != NULL &&
+ FWINV2(ebt_dev_check(e->logical_in, par->in->br_port->br->dev),
EBT_ILOGICALIN))
return false;
- if (out != NULL && out->br_port != NULL &&
- FWINV2(ebt_dev_check(e->logical_out, out->br_port->br->dev),
+ if (par->out != NULL && par->out->br_port != NULL &&
+ FWINV2(ebt_dev_check(e->logical_out, par->out->br_port->br->dev),
EBT_ILOGICALOUT))
return false;
@@ -168,6 +169,35 @@ ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
return true;
}
+static int ebt_basic_checkentry(const struct xt_mtchk_param *par)
+{
+ const struct ebt_entry *e = par->matchinfo;
+
+ if (e->bitmask & ~EBT_F_MASK) {
+ BUGPRINT("Unknown flag for bitmask\n");
+ return -EINVAL;
+ }
+ if (e->invflags & ~EBT_INV_MASK) {
+ BUGPRINT("Unknown flag for inv bitmask\n");
+ return -EINVAL;
+ }
+ if ((e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3)) {
+ BUGPRINT("NOPROTO & 802_3 not allowed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct xt_match ebt_builtin_mt __read_mostly = {
+ .name = "eth",
+ .revision = 0,
+ .family = NFPROTO_BRIDGE,
+ .matchsize = sizeof(struct ebt_entry),
+ .match = ebt_basic_match,
+ .checkentry = ebt_basic_checkentry,
+};
+
static inline __pure
struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry)
{
@@ -212,7 +242,9 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
base = private->entries;
i = 0;
while (i < nentries) {
- if (!ebt_basic_match(point, eth_hdr(skb), in, out))
+ acpar.match = &ebt_builtin_mt;
+ acpar.matchinfo = point;
+ if (!ebt_basic_match(skb, &acpar))
goto letscontinue;
if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &acpar) != 0)
@@ -658,18 +690,18 @@ ebt_check_entry(struct ebt_entry *e, struct net *net,
if (e->bitmask == 0)
return 0;
- if (e->bitmask & ~EBT_F_MASK) {
- BUGPRINT("Unknown flag for bitmask\n");
- return -EINVAL;
- }
- if (e->invflags & ~EBT_INV_MASK) {
- BUGPRINT("Unknown flag for inv bitmask\n");
- return -EINVAL;
- }
- if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
- BUGPRINT("NOPROTO & 802_3 not allowed\n");
- return -EINVAL;
- }
+ mtpar.net = tgpar.net = net;
+ mtpar.table = tgpar.table = name;
+ mtpar.entryinfo = tgpar.entryinfo = e;
+ mtpar.hook_mask = tgpar.hook_mask = hookmask;
+ mtpar.family = tgpar.family = NFPROTO_BRIDGE;
+
+ mtpar.match = &ebt_builtin_mt;
+ mtpar.matchinfo = e;
+ ret = ebt_basic_checkentry(&mtpar);
+ if (ret < 0)
+ return ret;
+
/* what hook do we belong to? */
for (i = 0; i < NF_BR_NUMHOOKS; i++) {
if (!newinfo->hook_entry[i])
@@ -694,11 +726,6 @@ ebt_check_entry(struct ebt_entry *e, struct net *net,
}
i = 0;
- mtpar.net = tgpar.net = net;
- mtpar.table = tgpar.table = name;
- mtpar.entryinfo = tgpar.entryinfo = e;
- mtpar.hook_mask = tgpar.hook_mask = hookmask;
- mtpar.family = tgpar.family = NFPROTO_BRIDGE;
ret = EBT_MATCH_ITERATE(e, ebt_check_match, &mtpar, &i);
if (ret != 0)
goto cleanup_matches;
@@ -2421,19 +2448,26 @@ static int __init ebtables_init(void)
ret = xt_register_target(&ebt_standard_target);
if (ret < 0)
return ret;
+ ret = xt_register_match(&ebt_builtin_mt);
+ if (ret < 0)
+ goto out;
ret = nf_register_sockopt(&ebt_sockopts);
- if (ret < 0) {
- xt_unregister_target(&ebt_standard_target);
- return ret;
- }
+ if (ret < 0)
+ goto out2;
printk(KERN_INFO "Ebtables v2.0 registered\n");
return 0;
+ out2:
+ xt_unregister_match(&ebt_builtin_mt);
+ out:
+ xt_unregister_target(&ebt_standard_target);
+ return ret;
}
static void __exit ebtables_fini(void)
{
nf_unregister_sockopt(&ebt_sockopts);
+ xt_unregister_match(&ebt_builtin_mt);
xt_unregister_target(&ebt_standard_target);
printk(KERN_INFO "Ebtables v2.0 unregistered\n");
}
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index ec89fd4..7f7752a 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -98,12 +98,12 @@ static unsigned long ifname_compare(const char *_a, const char *_b, const char *
}
/* Returns whether packet matches rule or not. */
-static inline int arp_packet_match(const struct arphdr *arphdr,
- struct net_device *dev,
- const char *indev,
- const char *outdev,
- const struct arpt_arp *arpinfo)
+static bool
+arp_packet_match(const struct sk_buff *skb, struct xt_action_param *par)
{
+ static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
+ const struct arphdr *arphdr = arp_hdr(skb);
+ const struct arpt_arp *arpinfo = par->matchinfo;
const char *arpptr = (char *)(arphdr + 1);
const char *src_devaddr, *tgt_devaddr;
__be32 src_ipaddr, tgt_ipaddr;
@@ -116,7 +116,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
dprintf("ARP operation field mismatch.\n");
dprintf("ar_op: %04x info->arpop: %04x info->arpop_mask: %04x\n",
arphdr->ar_op, arpinfo->arpop, arpinfo->arpop_mask);
- return 0;
+ return false;
}
if (FWINV((arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd,
@@ -124,7 +124,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
dprintf("ARP hardware address format mismatch.\n");
dprintf("ar_hrd: %04x info->arhrd: %04x info->arhrd_mask: %04x\n",
arphdr->ar_hrd, arpinfo->arhrd, arpinfo->arhrd_mask);
- return 0;
+ return false;
}
if (FWINV((arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro,
@@ -132,7 +132,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
dprintf("ARP protocol address format mismatch.\n");
dprintf("ar_pro: %04x info->arpro: %04x info->arpro_mask: %04x\n",
arphdr->ar_pro, arpinfo->arpro, arpinfo->arpro_mask);
- return 0;
+ return false;
}
if (FWINV((arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln,
@@ -140,24 +140,24 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
dprintf("ARP hardware address length mismatch.\n");
dprintf("ar_hln: %02x info->arhln: %02x info->arhln_mask: %02x\n",
arphdr->ar_hln, arpinfo->arhln, arpinfo->arhln_mask);
- return 0;
+ return false;
}
src_devaddr = arpptr;
- arpptr += dev->addr_len;
+ arpptr += skb->dev->addr_len;
memcpy(&src_ipaddr, arpptr, sizeof(u32));
arpptr += sizeof(u32);
tgt_devaddr = arpptr;
- arpptr += dev->addr_len;
+ arpptr += skb->dev->addr_len;
memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
- if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len),
- ARPT_INV_SRCDEVADDR) ||
- FWINV(arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len),
- ARPT_INV_TGTDEVADDR)) {
+ if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr,
+ skb->dev->addr_len), ARPT_INV_SRCDEVADDR) ||
+ FWINV(arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr,
+ skb->dev->addr_len), ARPT_INV_TGTDEVADDR)) {
dprintf("Source or target device address mismatch.\n");
- return 0;
+ return false;
}
if (FWINV((src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr,
@@ -176,46 +176,48 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
&arpinfo->tmsk.s_addr,
&arpinfo->tgt.s_addr,
arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : "");
- return 0;
+ return false;
}
/* Look for ifname matches. */
- ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask);
-
+ ret = ifname_compare((par->in == NULL) ? nulldevname : par->in->name,
+ arpinfo->iniface, arpinfo->iniface_mask);
if (FWINV(ret != 0, ARPT_INV_VIA_IN)) {
dprintf("VIA in mismatch (%s vs %s).%s\n",
- indev, arpinfo->iniface,
+ par->in->name, arpinfo->iniface,
arpinfo->invflags&ARPT_INV_VIA_IN ?" (INV)":"");
- return 0;
+ return false;
}
- ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask);
-
+ ret = ifname_compare((par->out == NULL) ? nulldevname : par->out->name,
+ arpinfo->outiface, arpinfo->outiface_mask);
if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) {
dprintf("VIA out mismatch (%s vs %s).%s\n",
- outdev, arpinfo->outiface,
+ par->out->name, arpinfo->outiface,
arpinfo->invflags&ARPT_INV_VIA_OUT ?" (INV)":"");
- return 0;
+ return false;
}
- return 1;
+ return true;
#undef FWINV
}
-static inline int arp_checkentry(const struct arpt_arp *arp)
+static int arp_checkentry(const struct xt_mtchk_param *par)
{
+ const struct arpt_arp *arp = par->matchinfo;
+
if (arp->flags & ~ARPT_F_MASK) {
duprintf("Unknown flag bits set: %08X\n",
arp->flags & ~ARPT_F_MASK);
- return 0;
+ return -EINVAL;
}
if (arp->invflags & ~ARPT_INV_MASK) {
duprintf("Unknown invflag bits set: %08X\n",
arp->invflags & ~ARPT_INV_MASK);
- return 0;
+ return -EINVAL;
}
- return 1;
+ return 0;
}
#ifdef CONFIG_COMPAT
@@ -267,6 +269,15 @@ static struct xt_target arpt_builtin_tg[] __read_mostly = {
},
};
+static struct xt_match arpt_builtin_mt __read_mostly = {
+ .name = "arp",
+ .revision = 0,
+ .family = NFPROTO_ARP,
+ .matchsize = sizeof(struct arpt_arp),
+ .match = arp_packet_match,
+ .checkentry = arp_checkentry,
+};
+
static inline const struct arpt_entry_target *
arpt_get_target_c(const struct arpt_entry *e)
{
@@ -291,11 +302,9 @@ unsigned int arpt_do_table(struct sk_buff *skb,
const struct net_device *out,
struct xt_table *table)
{
- static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
unsigned int verdict = NF_DROP;
const struct arphdr *arp;
struct arpt_entry *e, *back;
- const char *indev, *outdev;
void *table_base;
const struct xt_table_info *private;
struct xt_action_param acpar;
@@ -303,9 +312,6 @@ unsigned int arpt_do_table(struct sk_buff *skb,
if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
return NF_DROP;
- indev = in ? in->name : nulldevname;
- outdev = out ? out->name : nulldevname;
-
xt_info_rdlock_bh();
private = table->private;
table_base = private->entries[smp_processor_id()];
@@ -319,12 +325,19 @@ unsigned int arpt_do_table(struct sk_buff *skb,
acpar.family = NFPROTO_ARP;
acpar.hotdrop = false;
+ /*
+ * For arptables, do these two outside the loop because arp_tables
+ * does not support other matches anyway.
+ */
+ acpar.match = &arpt_builtin_mt;
+ acpar.matchinfo = &e->arp;
+
arp = arp_hdr(skb);
do {
const struct arpt_entry_target *t;
int hdr_len;
- if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
+ if (!arp_packet_match(skb, &acpar)) {
e = arpt_next_entry(e);
continue;
}
@@ -504,13 +517,18 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
return 1;
}
-static inline int check_entry(const struct arpt_entry *e, const char *name)
+static inline int
+check_entry(struct arpt_entry *e, struct xt_mtchk_param *par)
{
const struct arpt_entry_target *t;
+ int ret;
- if (!arp_checkentry(&e->arp)) {
+ par->match = &arpt_builtin_mt;
+ par->matchinfo = &e->arp;
+ ret = arp_checkentry(par);
+ if (ret < 0) {
duprintf("arp_tables: arp check failed %p %s.\n", e, name);
- return -EINVAL;
+ return ret;
}
if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset)
@@ -550,9 +568,14 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size)
{
struct arpt_entry_target *t;
struct xt_target *target;
+ struct xt_mtchk_param mtpar;
int ret;
- ret = check_entry(e, name);
+ mtpar.table = name;
+ mtpar.entryinfo = &e->arp;
+ mtpar.hook_mask = e->comefrom;
+ mtpar.family = NFPROTO_ARP;
+ ret = check_entry(e, &mtpar);
if (ret)
return ret;
@@ -1244,6 +1267,7 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
struct xt_target *target;
unsigned int entry_offset;
int ret, off, h;
+ struct xt_mtchk_param mtpar;
duprintf("check_compat_entry_size_and_hooks %p\n", e);
if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 ||
@@ -1260,7 +1284,13 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
}
/* For purposes of check_entry casting the compat entry is fine */
- ret = check_entry((struct arpt_entry *)e, name);
+ mtpar.table = name;
+ mtpar.entryinfo = &e->arp;
+ mtpar.hook_mask = e->comefrom;
+ mtpar.family = NFPROTO_ARP;
+ mtpar.match = &arpt_builtin_mt;
+ mtpar.matchinfo = &e->arp;
+ ret = check_entry((struct arpt_entry *)e, &mtpar);
if (ret)
return ret;
@@ -1886,6 +1916,9 @@ static int __init arp_tables_init(void)
ret = xt_register_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
if (ret < 0)
goto err2;
+ ret = xt_register_match(&arpt_builtin_mt);
+ if (ret < 0)
+ goto err3;
/* Register setsockopt */
ret = nf_register_sockopt(&arpt_sockopts);
@@ -1896,6 +1929,8 @@ static int __init arp_tables_init(void)
return 0;
err4:
+ xt_unregister_match(&arpt_builtin_mt);
+err3:
xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
err2:
unregister_pernet_subsys(&arp_tables_net_ops);
@@ -1906,6 +1941,7 @@ err1:
static void __exit arp_tables_fini(void)
{
nf_unregister_sockopt(&arpt_sockopts);
+ xt_unregister_match(&arpt_builtin_mt);
xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
unregister_pernet_subsys(&arp_tables_net_ops);
}
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index e98347f..c172d9e 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -79,13 +79,12 @@ EXPORT_SYMBOL_GPL(ipt_alloc_initial_table);
/* Returns whether matches rule or not. */
/* Performance critical - called for every packet */
-static inline bool
-ip_packet_match(const struct iphdr *ip,
- const char *indev,
- const char *outdev,
- const struct ipt_ip *ipinfo,
- int isfrag)
+static bool
+ip_packet_match(const struct sk_buff *skb, struct xt_action_param *par)
{
+ static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
+ const struct iphdr *ip = ip_hdr(skb);
+ const struct ipt_ip *ipinfo = par->matchinfo;
unsigned long ret;
#define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
@@ -105,20 +104,20 @@ ip_packet_match(const struct iphdr *ip,
return false;
}
- ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask);
-
+ ret = ifname_compare_aligned((par->in == NULL) ? nulldevname :
+ par->in->name, ipinfo->iniface, ipinfo->iniface_mask);
if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
dprintf("VIA in mismatch (%s vs %s).%s\n",
- indev, ipinfo->iniface,
+ par->in->name, ipinfo->iniface,
ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
return false;
}
- ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask);
-
+ ret = ifname_compare_aligned((par->out == NULL) ? nulldevname :
+ par->out->name, ipinfo->outiface, ipinfo->outiface_mask);
if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
dprintf("VIA out mismatch (%s vs %s).%s\n",
- outdev, ipinfo->outiface,
+ par->out->name, ipinfo->outiface,
ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
return false;
}
@@ -134,7 +133,8 @@ ip_packet_match(const struct iphdr *ip,
/* If we have a fragment rule but the packet is not a fragment
* then we return zero */
- if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
+ if (FWINV((ipinfo->flags & IPT_F_FRAG) &&
+ par->fragoff == 0, IPT_INV_FRAG)) {
dprintf("Fragment rule but not fragment.%s\n",
ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
return false;
@@ -143,20 +143,21 @@ ip_packet_match(const struct iphdr *ip,
return true;
}
-static bool
-ip_checkentry(const struct ipt_ip *ip)
+static int ip_checkentry(const struct xt_mtchk_param *par)
{
+ const struct ipt_ip *ip = par->matchinfo;
+
if (ip->flags & ~IPT_F_MASK) {
duprintf("Unknown flag bits set: %08X\n",
ip->flags & ~IPT_F_MASK);
- return false;
+ return -EINVAL;
}
if (ip->invflags & ~IPT_INV_MASK) {
duprintf("Unknown invflag bits set: %08X\n",
ip->invflags & ~IPT_INV_MASK);
- return false;
+ return -EINVAL;
}
- return true;
+ return 0;
}
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
@@ -256,6 +257,14 @@ static struct xt_target ipt_builtin_tg[] __read_mostly = {
static struct xt_match ipt_builtin_mt[] __read_mostly = {
{
+ .name = "ipv4",
+ .revision = 0,
+ .family = NFPROTO_IPV4,
+ .matchsize = sizeof(struct ipt_ip),
+ .match = ip_packet_match,
+ .checkentry = ip_checkentry,
+ },
+ {
.name = "icmp",
.match = icmp_match,
.matchsize = sizeof(struct ipt_icmp),
@@ -398,11 +407,9 @@ ipt_do_table(struct sk_buff *skb,
const struct net_device *out,
struct xt_table *table)
{
- static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
const struct iphdr *ip;
/* Initializing verdict to NF_DROP keeps gcc happy. */
unsigned int verdict = NF_DROP;
- const char *indev, *outdev;
const void *table_base;
struct ipt_entry *e, **jumpstack;
unsigned int *stackptr, origptr, cpu;
@@ -411,8 +418,6 @@ ipt_do_table(struct sk_buff *skb,
/* Initialization */
ip = ip_hdr(skb);
- indev = in ? in->name : nulldevname;
- outdev = out ? out->name : nulldevname;
/* We handle fragments by dealing with the first fragment as
* if it was a normal packet. All other fragments are treated
* normally, except that they will NEVER match rules that ask
@@ -447,8 +452,9 @@ ipt_do_table(struct sk_buff *skb,
const struct xt_entry_match *ematch;
IP_NF_ASSERT(e);
- if (!ip_packet_match(ip, indev, outdev,
- &e->ip, acpar.fragoff)) {
+ acpar.match = &ipt_builtin_mt[0]; /* "ipv4" itself */
+ acpar.matchinfo = &e->ip;
+ if (!ip_packet_match(skb, &acpar)) {
no_match:
e = ipt_next_entry(e);
continue;
@@ -663,13 +669,17 @@ static void cleanup_match(struct ipt_entry_match *m, struct net *net)
}
static int
-check_entry(const struct ipt_entry *e, const char *name)
+check_entry(struct ipt_entry *e, struct xt_mtchk_param *par)
{
const struct ipt_entry_target *t;
+ int ret;
- if (!ip_checkentry(&e->ip)) {
+ par->match = &ipt_builtin_mt[0]; /* ipv4 */
+ par->matchinfo = &e->ip;
+ ret = ip_checkentry(par);
+ if (ret < 0) {
duprintf("ip check failed %p %s.\n", e, par->match->name);
- return -EINVAL;
+ return ret;
}
if (e->target_offset + sizeof(struct ipt_entry_target) >
@@ -760,16 +770,15 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
struct xt_mtchk_param mtpar;
struct xt_entry_match *ematch;
- ret = check_entry(e, name);
- if (ret)
- return ret;
-
- j = 0;
mtpar.net = net;
mtpar.table = name;
mtpar.entryinfo = &e->ip;
mtpar.hook_mask = e->comefrom;
mtpar.family = NFPROTO_IPV4;
+ ret = check_entry(e, &mtpar);
+ if (ret < 0)
+ return ret;
+ j = 0;
xt_ematch_foreach(ematch, e) {
ret = find_check_match(ematch, &mtpar);
if (ret != 0)
@@ -1574,6 +1583,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
unsigned int entry_offset;
unsigned int j;
int ret, off, h;
+ struct xt_mtchk_param mtpar;
duprintf("check_compat_entry_size_and_hooks %p\n", e);
if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0 ||
@@ -1590,7 +1600,13 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
}
/* For purposes of check_entry casting the compat entry is fine */
- ret = check_entry((struct ipt_entry *)e, name);
+ mtpar.table = name;
+ mtpar.entryinfo = &e->ip;
+ mtpar.hook_mask = e->comefrom;
+ mtpar.family = NFPROTO_IPV4;
+ mtpar.match = &ipt_builtin_mt[0]; /* ipv4 */
+ mtpar.matchinfo = &e->ip;
+ ret = check_entry((struct ipt_entry *)e, &mtpar);
if (ret)
return ret;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 2bcf20b..bdb1e27 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -93,16 +93,13 @@ ip6t_ext_hdr(u8 nexthdr)
/* Returns whether matches rule or not. */
/* Performance critical - called for every packet */
-static inline bool
-ip6_packet_match(const struct sk_buff *skb,
- const char *indev,
- const char *outdev,
- const struct ip6t_ip6 *ip6info,
- unsigned int *protoff,
- int *fragoff, bool *hotdrop)
+static bool
+ip6_packet_match(const struct sk_buff *skb, struct xt_action_param *par)
{
+ static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
unsigned long ret;
const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
+ const struct ip6t_ip6 *ip6info = par->matchinfo;
#define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
@@ -121,20 +118,22 @@ ip6_packet_match(const struct sk_buff *skb,
return false;
}
- ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
-
+ ret = ifname_compare_aligned((par->in == NULL) ? nulldevname :
+ par->in->name, ip6info->iniface,
+ ip6info->iniface_mask);
if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
dprintf("VIA in mismatch (%s vs %s).%s\n",
- indev, ip6info->iniface,
+ par->in->name, ip6info->iniface,
ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
return false;
}
- ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
-
+ ret = ifname_compare_aligned((par->out == NULL) ? nulldevname :
+ par->out->name, ip6info->outiface,
+ ip6info->outiface_mask);
if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
dprintf("VIA out mismatch (%s vs %s).%s\n",
- outdev, ip6info->outiface,
+ par->out->name, ip6info->outiface,
ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
return false;
}
@@ -146,13 +145,13 @@ ip6_packet_match(const struct sk_buff *skb,
int protohdr;
unsigned short _frag_off;
- protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
+ protohdr = ipv6_find_hdr(skb, &par->thoff, -1, &_frag_off);
if (protohdr < 0) {
if (_frag_off == 0)
- *hotdrop = true;
+ par->hotdrop = true;
return false;
}
- *fragoff = _frag_off;
+ par->fragoff = _frag_off;
dprintf("Packet protocol %hi ?= %s%hi.\n",
protohdr,
@@ -175,20 +174,21 @@ ip6_packet_match(const struct sk_buff *skb,
}
/* should be ip6 safe */
-static bool
-ip6_checkentry(const struct ip6t_ip6 *ipv6)
+static int ip6_checkentry(const struct xt_mtchk_param *par)
{
+ const struct ip6t_ip6 *ipv6 = par->matchinfo;
+
if (ipv6->flags & ~IP6T_F_MASK) {
duprintf("Unknown flag bits set: %08X\n",
ipv6->flags & ~IP6T_F_MASK);
- return false;
+ return -EINVAL;
}
if (ipv6->invflags & ~IP6T_INV_MASK) {
duprintf("Unknown invflag bits set: %08X\n",
ipv6->invflags & ~IP6T_INV_MASK);
- return false;
+ return -EINVAL;
}
- return true;
+ return 0;
}
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
@@ -289,6 +289,14 @@ static struct xt_target ip6t_builtin_tg[] __read_mostly = {
static struct xt_match ip6t_builtin_mt[] __read_mostly = {
{
+ .name = "ipv6",
+ .revision = 0,
+ .family = NFPROTO_IPV6,
+ .matchsize = sizeof(struct ip6t_ip6),
+ .match = ip6_packet_match,
+ .checkentry = ip6_checkentry,
+ },
+ {
.name = "icmp6",
.match = icmp6_match,
.matchsize = sizeof(struct ip6t_icmp),
@@ -429,19 +437,14 @@ ip6t_do_table(struct sk_buff *skb,
const struct net_device *out,
struct xt_table *table)
{
- static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
/* Initializing verdict to NF_DROP keeps gcc happy. */
unsigned int verdict = NF_DROP;
- const char *indev, *outdev;
const void *table_base;
struct ip6t_entry *e, **jumpstack;
unsigned int *stackptr, origptr, cpu;
const struct xt_table_info *private;
struct xt_action_param acpar;
- /* Initialization */
- indev = in ? in->name : nulldevname;
- outdev = out ? out->name : nulldevname;
/* We handle fragments by dealing with the first fragment as
* if it was a normal packet. All other fragments are treated
* normally, except that they will NEVER match rules that ask
@@ -471,8 +474,9 @@ ip6t_do_table(struct sk_buff *skb,
const struct xt_entry_match *ematch;
IP_NF_ASSERT(e);
- if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
- &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
+ acpar.match = &ip6t_builtin_mt[0];
+ acpar.matchinfo = &e->ipv6;
+ if (!ip6_packet_match(skb, &acpar)) {
no_match:
e = ip6t_next_entry(e);
continue;
@@ -679,13 +683,17 @@ static void cleanup_match(struct ip6t_entry_match *m, struct net *net)
}
static int
-check_entry(const struct ip6t_entry *e, const char *name)
+check_entry(struct ip6t_entry *e, struct xt_mtchk_param *par)
{
const struct ip6t_entry_target *t;
+ int ret;
- if (!ip6_checkentry(&e->ipv6)) {
- duprintf("ip_tables: ip check failed %p %s.\n", e, name);
- return -EINVAL;
+ par->match = &ip6t_builtin_mt[0];
+ par->matchinfo = &e->ipv6;
+ ret = ip6_checkentry(par);
+ if (ret < 0) {
+ duprintf("ip6_tables: ip check failed %p %s.\n", e, name);
+ return ret;
}
if (e->target_offset + sizeof(struct ip6t_entry_target) >
@@ -777,16 +785,15 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
struct xt_mtchk_param mtpar;
struct xt_entry_match *ematch;
- ret = check_entry(e, name);
- if (ret)
- return ret;
-
- j = 0;
mtpar.net = net;
mtpar.table = name;
mtpar.entryinfo = &e->ipv6;
mtpar.hook_mask = e->comefrom;
mtpar.family = NFPROTO_IPV6;
+ ret = check_entry(e, &mtpar);
+ if (ret < 0)
+ return ret;
+ j = 0;
xt_ematch_foreach(ematch, e) {
ret = find_check_match(ematch, &mtpar);
if (ret != 0)
@@ -1592,6 +1599,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
unsigned int entry_offset;
unsigned int j;
int ret, off, h;
+ struct xt_mtchk_param mtpar;
duprintf("check_compat_entry_size_and_hooks %p\n", e);
if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 ||
@@ -1608,7 +1616,13 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
}
/* For purposes of check_entry casting the compat entry is fine */
- ret = check_entry((struct ip6t_entry *)e, name);
+ mtpar.table = name;
+ mtpar.entryinfo = &e->ipv6;
+ mtpar.hook_mask = e->comefrom;
+ mtpar.family = NFPROTO_IPV6;
+ mtpar.match = &ip6t_builtin_mt[0]; /* ipv6 */
+ mtpar.matchinfo = &e->ipv6;
+ ret = check_entry((struct ip6t_entry *)e, &mtpar);
if (ret)
return ret;
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 05/56] netfilter: xtables2: initial table skeletal functions
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (3 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 04/56] netfilter: xtables: convert basic nfproto match functions into xt matches Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 06/56] netfilter: xtables2: initial chain " Jan Engelhardt
` (29 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
This patch adds the xt2 table functions. Of course this does not do
anything useful yet, chain and rule support directly follow.
Locking is currently only done at the table level, and that should be
enough at this point given I seek to get it running with the iptables
interfaces first, which do not manipulate rules while a table is live.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 54 +++++++++++++
include/net/net_namespace.h | 1 +
include/net/netns/x_tables.h | 6 ++
net/netfilter/x_tables.c | 145 +++++++++++++++++++++++++++++++++++-
4 files changed, 205 insertions(+), 1 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 8067cb5..638ab33 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -404,6 +404,43 @@ struct xt_table_info {
void *entries[1];
};
+/**
+ * For xt2_tlink_lookup/xt2_table_lookup:
+ *
+ * %XT2_STD_RCULOCK: Standard procedure - acquire RCU lock for search, and
+ * drop it again when done. This is used for when the
+ * mutex is already held, or for basic presence-only
+ * checks.
+ * %XT2_KEEP_RCULOCK: A mnemonic for !XT2_STD_RCULOCK - acquire the RCU lock
+ * and keep it when the search was successful. This is for
+ * when dropping the RCU lock is not appropriate with
+ * respect to code following the search.
+ */
+enum {
+ XT2_STD_RCULOCK = 1 << 0,
+ XT2_KEEP_RCULOCK = 0,
+};
+
+/**
+ * @name: name of this table
+ * @nfproto: nfproto the table is used exclusively with
+ * @owner: encompassing module
+ */
+struct xt2_table {
+ char name[11];
+ uint8_t nfproto;
+ struct module *owner;
+};
+
+/**
+ * We need this as a permanent anchor point for external pointers, e.g.
+ * netns->xt2.ipv6_filter.
+ */
+struct xt2_table_link {
+ struct list_head anchor;
+ struct xt2_table *table;
+};
+
#define XT_TABLE_INFO_SZ (offsetof(struct xt_table_info, entries) \
+ nr_cpu_ids * sizeof(char *))
extern int xt_register_target(struct xt_target *target);
@@ -545,6 +582,23 @@ static inline unsigned long ifname_compare_aligned(const char *_a,
extern struct nf_hook_ops *xt_hook_link(const struct xt_table *, nf_hookfn *);
extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
+extern struct xt2_table *xt2_table_new(void);
+extern struct xt2_table_link *xt2_tlink_lookup(struct net *, const char *,
+ uint8_t, unsigned int);
+extern int xt2_table_register(struct net *, struct xt2_table *);
+extern struct xt2_table *xt2_table_replace(struct net *, struct xt2_table *);
+extern void xt2_table_destroy(struct net *, struct xt2_table *);
+
+static inline struct xt2_table *
+xt2_table_lookup(struct net *net, const char *name, uint8_t nfproto,
+ unsigned int lock_mask)
+{
+ struct xt2_table_link *link;
+
+ link = xt2_tlink_lookup(net, name, nfproto, lock_mask);
+ return (link != NULL) ? link->table : NULL;
+}
+
#ifdef CONFIG_COMPAT
#include <net/compat.h>
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index bd10a79..c73b0c0 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -78,6 +78,7 @@ struct net {
#endif
#ifdef CONFIG_NETFILTER
struct netns_xt xt;
+ struct netns_xt2 xt2;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct netns_ct ct;
#endif
diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
index 591db7d..8a2d497 100644
--- a/include/net/netns/x_tables.h
+++ b/include/net/netns/x_tables.h
@@ -15,4 +15,10 @@ struct netns_xt {
struct ebt_table *frame_nat;
#endif
};
+
+struct netns_xt2 {
+ struct mutex table_lock;
+ struct list_head table_list[NFPROTO_NUMPROTO];
+};
+
#endif
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index e34622f..0bd6a6c 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -17,6 +17,7 @@
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/proc_fs.h>
+#include <linux/rcupdate.h>
#include <linux/seq_file.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
@@ -1237,6 +1238,144 @@ void xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops)
}
EXPORT_SYMBOL_GPL(xt_hook_unlink);
+struct xt2_table *xt2_table_new(void)
+{
+ struct xt2_table *table;
+
+ table = kzalloc(sizeof(*table), GFP_KERNEL);
+ if (table == NULL)
+ return NULL;
+
+ return table;
+}
+EXPORT_SYMBOL_GPL(xt2_table_new);
+
+/**
+ * @net: Netspace to search in
+ * @name:
+ * @table: Name/nfproto to search for
+ * @lock_mask: Locking instructions (%XT2_STD_RCULOCK)
+ */
+struct xt2_table_link *
+xt2_tlink_lookup(struct net *net, const char *name, uint8_t nfproto,
+ unsigned int lock_mask)
+{
+ struct xt2_table_link *link;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(link, &net->xt2.table_list[nfproto], anchor) {
+ if (strcmp(link->table->name, name) != 0)
+ continue;
+ if (lock_mask & XT2_STD_RCULOCK)
+ rcu_read_unlock();
+ return link;
+ }
+ rcu_read_unlock();
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(xt2_tlink_lookup);
+
+int xt2_table_register(struct net *net, struct xt2_table *table)
+{
+ struct xt2_table_link *link;
+ int ret = 0;
+
+ if (*table->name == '\0')
+ /* Empty names don't fly with our strcmp. */
+ return -EINVAL;
+
+ mutex_lock(&net->xt2.table_lock);
+ if (xt2_table_lookup(net, table->name,
+ table->nfproto, XT2_STD_RCULOCK) != NULL) {
+ ret = -EEXIST;
+ goto out;
+ }
+
+ link = kmalloc(sizeof(*link), GFP_KERNEL);
+ if (link == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&link->anchor);
+ link->table = table;
+ list_add_tail_rcu(&link->anchor, &net->xt2.table_list[table->nfproto]);
+ out:
+ mutex_unlock(&net->xt2.table_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xt2_table_register);
+
+/**
+ * @net: accompanying net namespace
+ * @table: new table
+ *
+ * Replace existing table by a new one. The old one is found by scanning the
+ * list for a table with the same name as the new one.
+ * The old table is disconnected from its net namespace and hence, one must
+ * pass %NULL for the first argument to xt2_table_destroy for tables returned
+ * by xt2_table_replace.
+ */
+struct xt2_table *xt2_table_replace(struct net *net, struct xt2_table *table)
+{
+ struct xt2_table_link *link;
+ struct xt2_table *old_table;
+
+ if (*table->name == '\0')
+ return ERR_PTR(-EINVAL);
+
+ link = xt2_tlink_lookup(net, table->name, table->nfproto,
+ XT2_KEEP_RCULOCK);
+ if (link == NULL)
+ return ERR_PTR(-ENOENT);
+
+ mutex_lock(&net->xt2.table_lock);
+ old_table = rcu_dereference(link->table);
+ rcu_assign_pointer(link->table, table);
+ mutex_unlock(&net->xt2.table_lock);
+ rcu_read_unlock();
+ synchronize_rcu();
+ return old_table;
+}
+EXPORT_SYMBOL_GPL(xt2_table_replace);
+
+/**
+ * Unlink a table from the list of known tables. Synchronize RCU so that when
+ * execution in the caller xt2_table_destroy continues, it can free the table
+ * without worry.
+ */
+static void xt2_table_unregister(struct net *net, struct xt2_table *table)
+{
+ struct xt2_table_link *link;
+
+ if (*table->name == '\0')
+ return;
+
+ mutex_lock(&net->xt2.table_lock);
+ link = xt2_tlink_lookup(net, table->name, table->nfproto,
+ XT2_STD_RCULOCK);
+ if (link == NULL) {
+ pr_warning("%s: table %s not found in netns?!\n",
+ __func__, table->name);
+ mutex_unlock(&net->xt2.table_lock);
+ return;
+ }
+ list_del_rcu(&link->anchor);
+ mutex_unlock(&net->xt2.table_lock);
+ synchronize_rcu();
+ link->table = (void *)NETFILTER_LINK_POISON;
+ kfree(link);
+}
+
+void xt2_table_destroy(struct net *net, struct xt2_table *table)
+{
+ if (net != NULL)
+ xt2_table_unregister(net, table);
+
+ kfree(table);
+}
+EXPORT_SYMBOL_GPL(xt2_table_destroy);
+
int xt_proto_init(struct net *net, u_int8_t af)
{
#ifdef CONFIG_PROC_FS
@@ -1313,8 +1452,12 @@ static int __net_init xt_net_init(struct net *net)
{
int i;
- for (i = 0; i < NFPROTO_NUMPROTO; i++)
+ for (i = 0; i < NFPROTO_NUMPROTO; i++) {
INIT_LIST_HEAD(&net->xt.tables[i]);
+ INIT_LIST_HEAD(&net->xt2.table_list[i]);
+ }
+
+ mutex_init(&net->xt2.table_lock);
return 0;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 06/56] netfilter: xtables2: initial chain skeletal functions
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (4 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 05/56] netfilter: xtables2: initial table skeletal functions Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 07/56] netfilter: xtables2: initial rule " Jan Engelhardt
` (28 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 19 +++++++++++++++++++
net/netfilter/x_tables.c | 31 +++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 638ab33..a55d4a4 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -404,6 +404,19 @@ struct xt_table_info {
void *entries[1];
};
+struct xt2_table;
+
+/**
+ * @anchor: list anchor for parent (xt2_table.chain_list)
+ * @name: name of chain
+ * @table: back link to table chain is contained in
+ */
+struct xt2_chain {
+ struct list_head anchor;
+ char name[XT_EXTENSION_MAXNAMELEN];
+ struct xt2_table *table;
+};
+
/**
* For xt2_tlink_lookup/xt2_table_lookup:
*
@@ -422,13 +435,17 @@ enum {
};
/**
+ * @chain_list: list of chains (struct xt2_chain)
* @name: name of this table
* @nfproto: nfproto the table is used exclusively with
+ * @entrypoint: start chains for hooks
* @owner: encompassing module
*/
struct xt2_table {
+ struct list_head chain_list;
char name[11];
uint8_t nfproto;
+ const struct xt2_chain *entrypoint[NF_INET_NUMHOOKS];
struct module *owner;
};
@@ -582,6 +599,8 @@ static inline unsigned long ifname_compare_aligned(const char *_a,
extern struct nf_hook_ops *xt_hook_link(const struct xt_table *, nf_hookfn *);
extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
+extern struct xt2_chain *xt2_chain_new(struct xt2_table *, const char *);
+
extern struct xt2_table *xt2_table_new(void);
extern struct xt2_table_link *xt2_tlink_lookup(struct net *, const char *,
uint8_t, unsigned int);
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 0bd6a6c..e807312 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1238,6 +1238,32 @@ void xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops)
}
EXPORT_SYMBOL_GPL(xt_hook_unlink);
+struct xt2_chain *xt2_chain_new(struct xt2_table *table, const char *name)
+{
+ struct xt2_chain *chain;
+
+ chain = kmalloc(sizeof(*chain), GFP_KERNEL);
+ if (chain == NULL)
+ return NULL;
+
+ chain->table = table;
+ INIT_LIST_HEAD(&chain->anchor);
+ if (name != NULL)
+ strncpy(chain->name, name, sizeof(chain->name));
+ else
+ chain->name[0] = '\0';
+ chain->name[sizeof(chain->name)-1] = '\0';
+ list_add_tail(&chain->anchor, &table->chain_list);
+ return chain;
+}
+EXPORT_SYMBOL_GPL(xt2_chain_new);
+
+static void xt2_chain_free(struct xt2_chain *chain)
+{
+ list_del(&chain->anchor);
+ kfree(chain);
+}
+
struct xt2_table *xt2_table_new(void)
{
struct xt2_table *table;
@@ -1246,6 +1272,7 @@ struct xt2_table *xt2_table_new(void)
if (table == NULL)
return NULL;
+ INIT_LIST_HEAD(&table->chain_list);
return table;
}
EXPORT_SYMBOL_GPL(xt2_table_new);
@@ -1369,9 +1396,13 @@ static void xt2_table_unregister(struct net *net, struct xt2_table *table)
void xt2_table_destroy(struct net *net, struct xt2_table *table)
{
+ struct xt2_chain *chain, *next_chain;
+
if (net != NULL)
xt2_table_unregister(net, table);
+ list_for_each_entry_safe(chain, next_chain, &table->chain_list, anchor)
+ xt2_chain_free(chain);
kfree(table);
}
EXPORT_SYMBOL_GPL(xt2_table_destroy);
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 07/56] netfilter: xtables2: initial rule skeletal functions
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (5 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 06/56] netfilter: xtables2: initial chain " Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 08/56] netfilter: xtables: alternate size checking in xt_check_match Jan Engelhardt
` (27 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Whereas iptables and its derivates (collectively, Xtables1) used a
serialized binary blob, Xtables2's internal layout will be linked
lists. This makes it possible to easily edit single rules later on
without userspace having to upload an entire table if it does not
want to.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 15 +++++++++++++++
net/netfilter/x_tables.c | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index a55d4a4..2d21185 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -407,12 +407,22 @@ struct xt_table_info {
struct xt2_table;
/**
+ * @anchor: list anchor for parent (xt2_chain.rule_list)
+ */
+struct xt2_rule {
+ struct list_head anchor;
+ struct xt2_chain *chain;
+};
+
+/**
* @anchor: list anchor for parent (xt2_table.chain_list)
+ * @rule_list: list of struct xt2_rule
* @name: name of chain
* @table: back link to table chain is contained in
*/
struct xt2_chain {
struct list_head anchor;
+ struct list_head rule_list;
char name[XT_EXTENSION_MAXNAMELEN];
struct xt2_table *table;
};
@@ -439,6 +449,7 @@ enum {
* @name: name of this table
* @nfproto: nfproto the table is used exclusively with
* @entrypoint: start chains for hooks
+ * @underflow: base chain policy (rule)
* @owner: encompassing module
*/
struct xt2_table {
@@ -446,6 +457,7 @@ struct xt2_table {
char name[11];
uint8_t nfproto;
const struct xt2_chain *entrypoint[NF_INET_NUMHOOKS];
+ const struct xt2_rule *underflow[NF_INET_NUMHOOKS];
struct module *owner;
};
@@ -599,7 +611,10 @@ static inline unsigned long ifname_compare_aligned(const char *_a,
extern struct nf_hook_ops *xt_hook_link(const struct xt_table *, nf_hookfn *);
extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
+extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
+
extern struct xt2_chain *xt2_chain_new(struct xt2_table *, const char *);
+extern void xt2_chain_append(struct xt2_rule *);
extern struct xt2_table *xt2_table_new(void);
extern struct xt2_table_link *xt2_tlink_lookup(struct net *, const char *,
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index e807312..f23195e 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1238,6 +1238,26 @@ void xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops)
}
EXPORT_SYMBOL_GPL(xt_hook_unlink);
+struct xt2_rule *xt2_rule_new(struct xt2_chain *chain)
+{
+ struct xt2_rule *rule;
+
+ rule = kmalloc(sizeof(*rule), GFP_KERNEL);
+ if (rule == NULL)
+ return NULL;
+
+ rule->chain = chain;
+ INIT_LIST_HEAD(&rule->anchor);
+ return rule;
+}
+EXPORT_SYMBOL_GPL(xt2_rule_new);
+
+static void xt2_rule_free(struct xt2_rule *rule)
+{
+ list_del(&rule->anchor);
+ kfree(rule);
+}
+
struct xt2_chain *xt2_chain_new(struct xt2_table *table, const char *name)
{
struct xt2_chain *chain;
@@ -1248,6 +1268,7 @@ struct xt2_chain *xt2_chain_new(struct xt2_table *table, const char *name)
chain->table = table;
INIT_LIST_HEAD(&chain->anchor);
+ INIT_LIST_HEAD(&chain->rule_list);
if (name != NULL)
strncpy(chain->name, name, sizeof(chain->name));
else
@@ -1258,9 +1279,23 @@ struct xt2_chain *xt2_chain_new(struct xt2_table *table, const char *name)
}
EXPORT_SYMBOL_GPL(xt2_chain_new);
+/**
+ * Rules are completely constructed first before appending to the chain,
+ * to avoid incomplete rules being run through in xt2_do_action.
+ */
+void xt2_chain_append(struct xt2_rule *rule)
+{
+ list_add_tail(&rule->anchor, &rule->chain->rule_list);
+}
+EXPORT_SYMBOL_GPL(xt2_chain_append);
+
static void xt2_chain_free(struct xt2_chain *chain)
{
+ struct xt2_rule *rule, *next_rule;
+
list_del(&chain->anchor);
+ list_for_each_entry_safe(rule, next_rule, &chain->rule_list, anchor)
+ xt2_rule_free(rule);
kfree(chain);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 08/56] netfilter: xtables: alternate size checking in xt_check_match
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (6 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 07/56] netfilter: xtables2: initial rule " Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 09/56] netfilter: xtables: alternate size checking in xt_check_target Jan Engelhardt
` (26 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Private data areas exist in unserialized form in xt2, hence they do
not need nor have any padding. xt_check_match thus needs a parameter
to know whether to select between comparison against the (un)padded
size.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 3 ++-
net/bridge/netfilter/ebtables.c | 4 ++--
net/ipv4/netfilter/ip_tables.c | 4 ++--
net/ipv6/netfilter/ip6_tables.c | 4 ++--
net/netfilter/x_tables.c | 12 +++++++-----
5 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 2d21185..7bdbecb 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -483,7 +483,8 @@ extern int xt_register_matches(struct xt_match *match, unsigned int n);
extern void xt_unregister_matches(struct xt_match *match, unsigned int n);
extern int xt_check_match(struct xt_mtchk_param *,
- unsigned int size, u_int8_t proto, bool inv_proto);
+ unsigned int size, u_int8_t proto, bool inv_proto,
+ bool check_pad);
extern int xt_check_target(struct xt_tgchk_param *,
unsigned int size, u_int8_t proto, bool inv_proto);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 4553ffd..73c9cec 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -402,8 +402,8 @@ ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
par->match = match;
par->matchinfo = m->data;
- ret = xt_check_match(par, m->match_size,
- e->ethproto, e->invflags & EBT_IPROTO);
+ ret = xt_check_match(par, m->match_size, e->ethproto,
+ e->invflags & EBT_IPROTO, true);
if (ret < 0) {
module_put(match->me);
return ret;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index c172d9e..43adafa 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -702,8 +702,8 @@ check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par)
par->match = m->u.kernel.match;
par->matchinfo = m->data;
- ret = xt_check_match(par, m->u.match_size - sizeof(*m),
- ip->proto, ip->invflags & IPT_INV_PROTO);
+ ret = xt_check_match(par, m->u.match_size - sizeof(*m), ip->proto,
+ ip->invflags & IPT_INV_PROTO, true);
if (ret < 0) {
duprintf("check failed for `%s'.\n", par->match->name);
return ret;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index bdb1e27..0602685 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -715,8 +715,8 @@ static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par)
par->match = m->u.kernel.match;
par->matchinfo = m->data;
- ret = xt_check_match(par, m->u.match_size - sizeof(*m),
- ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
+ ret = xt_check_match(par, m->u.match_size - sizeof(*m), ipv6->proto,
+ ipv6->invflags & IP6T_INV_PROTO, true);
if (ret < 0) {
duprintf("ip_tables: check failed for `%s'.\n",
par.match->name);
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index f23195e..0eef61a 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -366,12 +366,15 @@ static char *textify_hooks(char *buf, size_t size, unsigned int mask)
}
int xt_check_match(struct xt_mtchk_param *par,
- unsigned int size, u_int8_t proto, bool inv_proto)
+ unsigned int size, u_int8_t proto, bool inv_proto,
+ bool check_pad)
{
+ unsigned int required;
int ret;
- if (XT_ALIGN(par->match->matchsize) != size &&
- par->match->matchsize != -1) {
+ required = check_pad ? XT_ALIGN(par->match->matchsize) :
+ par->match->matchsize;
+ if (par->match->matchsize != -1 && required != size) {
/*
* ebt_among is exempt from centralized matchsize checking
* because it uses a dynamic-size data set.
@@ -379,8 +382,7 @@ int xt_check_match(struct xt_mtchk_param *par,
pr_err("%s_tables: %s.%u match: invalid size "
"%u (kernel) != (user) %u\n",
xt_prefix[par->family], par->match->name,
- par->match->revision,
- XT_ALIGN(par->match->matchsize), size);
+ par->match->revision, required, size);
return -EINVAL;
}
if (par->match->table != NULL &&
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 09/56] netfilter: xtables: alternate size checking in xt_check_target
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (7 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 08/56] netfilter: xtables: alternate size checking in xt_check_match Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 10/56] netfilter: xtables2: per-rule match skeletal functions Jan Engelhardt
` (25 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Same as before, but for targets.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 3 ++-
net/bridge/netfilter/ebtables.c | 8 ++++----
net/ipv4/netfilter/arp_tables.c | 3 ++-
net/ipv4/netfilter/ip_tables.c | 4 ++--
net/ipv6/netfilter/ip6_tables.c | 3 ++-
net/netfilter/x_tables.c | 11 +++++++----
net/sched/act_ipt.c | 3 ++-
7 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 7bdbecb..3fc0d9b 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -486,7 +486,8 @@ extern int xt_check_match(struct xt_mtchk_param *,
unsigned int size, u_int8_t proto, bool inv_proto,
bool check_pad);
extern int xt_check_target(struct xt_tgchk_param *,
- unsigned int size, u_int8_t proto, bool inv_proto);
+ unsigned int size, u_int8_t proto, bool inv_proto,
+ bool check_pad);
extern struct xt_table *xt_register_table(struct net *net,
const struct xt_table *table,
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 73c9cec..ab37e1c 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -433,8 +433,8 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
par->target = watcher;
par->targinfo = w->data;
- ret = xt_check_target(par, w->watcher_size,
- e->ethproto, e->invflags & EBT_IPROTO);
+ ret = xt_check_target(par, w->watcher_size, e->ethproto,
+ e->invflags & EBT_IPROTO, true);
if (ret < 0) {
module_put(watcher->me);
return ret;
@@ -763,8 +763,8 @@ ebt_check_entry(struct ebt_entry *e, struct net *net,
tgpar.target = target;
tgpar.targinfo = t->data;
- ret = xt_check_target(&tgpar, t->target_size,
- e->ethproto, e->invflags & EBT_IPROTO);
+ ret = xt_check_target(&tgpar, t->target_size, e->ethproto,
+ e->invflags & EBT_IPROTO, true);
if (ret < 0) {
module_put(target->me);
goto cleanup_watchers;
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 7f7752a..2fee4a5 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -554,7 +554,8 @@ static inline int check_target(struct arpt_entry *e, const char *name)
.family = NFPROTO_ARP,
};
- ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
+ ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
+ 0, false, true);
if (ret < 0) {
duprintf("arp_tables: check failed for `%s'.\n",
t->u.kernel.target->name);
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 43adafa..3809f38 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -749,8 +749,8 @@ static int check_target(struct ipt_entry *e, struct net *net, const char *name)
};
int ret;
- ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
- e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
+ ret = xt_check_target(&par, t->u.target_size - sizeof(*t), e->ip.proto,
+ e->ip.invflags & IPT_INV_PROTO, true);
if (ret < 0) {
duprintf("check failed for `%s'.\n",
t->u.kernel.target->name);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 0602685..cd8a2f1 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -765,7 +765,8 @@ static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
t = ip6t_get_target(e);
ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
- e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
+ e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO,
+ true);
if (ret < 0) {
duprintf("ip_tables: check failed for `%s'.\n",
t->u.kernel.target->name);
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 0eef61a..1f4354f 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -533,16 +533,19 @@ EXPORT_SYMBOL_GPL(xt_compat_match_to_user);
#endif /* CONFIG_COMPAT */
int xt_check_target(struct xt_tgchk_param *par,
- unsigned int size, u_int8_t proto, bool inv_proto)
+ unsigned int size, u_int8_t proto, bool inv_proto,
+ bool check_pad)
{
+ unsigned int required;
int ret;
- if (XT_ALIGN(par->target->targetsize) != size) {
+ required = check_pad ? XT_ALIGN(par->target->targetsize) :
+ par->target->targetsize;
+ if (required != size) {
pr_err("%s_tables: %s.%u target: invalid size "
"%u (kernel) != (user) %u\n",
xt_prefix[par->family], par->target->name,
- par->target->revision,
- XT_ALIGN(par->target->targetsize), size);
+ par->target->revision, required, size);
return -EINVAL;
}
if (par->target->table != NULL &&
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index c7e59e6..79223ec 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -58,7 +58,8 @@ static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int
par.hook_mask = hook;
par.family = NFPROTO_IPV4;
- ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
+ ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
+ 0, false, true);
if (ret < 0) {
module_put(t->u.kernel.target->me);
return ret;
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 10/56] netfilter: xtables2: per-rule match skeletal functions
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (8 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 09/56] netfilter: xtables: alternate size checking in xt_check_target Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 11/56] netfilter: xtables2: per-rule target " Jan Engelhardt
` (24 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Sidenotes: In xt2 rules, the layer-2/3 match structure (e.g. struct
ip6t_ip6) is now a standalone entry_match.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 39 ++++++++++++
net/netfilter/x_tables.c | 120 ++++++++++++++++++++++++++++++++++++
2 files changed, 159 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 3fc0d9b..47951aa 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -406,12 +406,37 @@ struct xt_table_info {
struct xt2_table;
+enum {
+ XT2_INV_L4PROTO = 1 << 0,
+
+ /* The unspecified L4 proto */
+ XT2_L4PROTO_UNSPEC = 0,
+};
+
/**
* @anchor: list anchor for parent (xt2_chain.rule_list)
+ * @match_list: list of called match extensions (xt2_entry_match)
+ * @l4proto: layer-4 protocol used (needed for xt_check_*)
+ * @flags: extra flags (see above)
*/
struct xt2_rule {
struct list_head anchor;
+ struct list_head match_list;
struct xt2_chain *chain;
+ uint8_t l4proto, flags;
+};
+
+/**
+ * @anchor: list anchor for parent (xt2_rule.match_list)
+ * @ext: pointer to extension
+ * @data: parameter block for extension (aka. "matchinfo")
+ * @dsize: size of @data (since @ext->matchsize may be -1)
+ */
+struct xt2_entry_match {
+ struct list_head anchor;
+ const struct xt_match *ext;
+ void *data;
+ unsigned int dsize;
};
/**
@@ -419,12 +444,15 @@ struct xt2_rule {
* @rule_list: list of struct xt2_rule
* @name: name of chain
* @table: back link to table chain is contained in
+ * @comefrom: bitmask from which hooks the chain is entered
+ * (currently needed for xt_check_*)
*/
struct xt2_chain {
struct list_head anchor;
struct list_head rule_list;
char name[XT_EXTENSION_MAXNAMELEN];
struct xt2_table *table;
+ unsigned int comefrom;
};
/**
@@ -450,6 +478,7 @@ enum {
* @nfproto: nfproto the table is used exclusively with
* @entrypoint: start chains for hooks
* @underflow: base chain policy (rule)
+ * @net: encompassing netns. To be set by xt2_table_new caller.
* @owner: encompassing module
*/
struct xt2_table {
@@ -458,6 +487,7 @@ struct xt2_table {
uint8_t nfproto;
const struct xt2_chain *entrypoint[NF_INET_NUMHOOKS];
const struct xt2_rule *underflow[NF_INET_NUMHOOKS];
+ struct net *net;
struct module *owner;
};
@@ -614,6 +644,8 @@ extern struct nf_hook_ops *xt_hook_link(const struct xt_table *, nf_hookfn *);
extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
+extern int xt2_rule_add_match(struct xt2_rule *, const char *, uint8_t,
+ const void *, unsigned int, bool);
extern struct xt2_chain *xt2_chain_new(struct xt2_table *, const char *);
extern void xt2_chain_append(struct xt2_rule *);
@@ -625,6 +657,13 @@ extern int xt2_table_register(struct net *, struct xt2_table *);
extern struct xt2_table *xt2_table_replace(struct net *, struct xt2_table *);
extern void xt2_table_destroy(struct net *, struct xt2_table *);
+static inline int
+xt2_rule_add_oldmatch(struct xt2_rule *rule, const struct xt_entry_match *m)
+{
+ return xt2_rule_add_match(rule, m->u.user.name, m->u.user.revision,
+ m->data, m->u.match_size - sizeof(*m), true);
+}
+
static inline struct xt2_table *
xt2_table_lookup(struct net *net, const char *name, uint8_t nfproto,
unsigned int lock_mask)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 1f4354f..b9d0d3f 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1251,15 +1251,135 @@ struct xt2_rule *xt2_rule_new(struct xt2_chain *chain)
if (rule == NULL)
return NULL;
+ rule->l4proto = XT2_L4PROTO_UNSPEC;
+ rule->flags = 0;
rule->chain = chain;
INIT_LIST_HEAD(&rule->anchor);
+ INIT_LIST_HEAD(&rule->match_list);
return rule;
}
EXPORT_SYMBOL_GPL(xt2_rule_new);
+/**
+ * Find the struct ip6t_ip6 (or other appropriate for a particular L3 proto)
+ * from an xt2 rule. xt_check_match needs this for now.
+ * Returns %NULL if not found.
+ */
+static void *xt2_entryinfo_mt_get(const struct xt2_rule *rule)
+{
+ const struct xt2_entry_match *ematch;
+
+ if (list_empty(&rule->match_list))
+ return NULL;
+ ematch = list_first_entry(&rule->match_list, typeof(*ematch), anchor);
+
+ /* The entryinfo is always in first place in xt1-compat mode. */
+ switch (rule->chain->table->nfproto) {
+ case NFPROTO_IPV4:
+ if (strcmp(ematch->ext->name, "ipv4") != 0)
+ return NULL;
+ break;
+ case NFPROTO_IPV6:
+ if (strcmp(ematch->ext->name, "ipv6") != 0)
+ return NULL;
+ break;
+ case NFPROTO_ARP:
+ if (strcmp(ematch->ext->name, "arp") != 0)
+ return NULL;
+ break;
+ case NFPROTO_BRIDGE:
+ if (strcmp(ematch->ext->name, "eth") != 0)
+ return NULL;
+ break;
+ default:
+ return NULL;
+ }
+
+ return ematch->data;
+}
+
+/**
+ * @ext_name: name of extension
+ * @ext_rev: requested revision
+ * @data: private extension data block (parameters, etc.)
+ * @dsize: size of supplied data
+ */
+int xt2_rule_add_match(struct xt2_rule *rule, const char *ext_name,
+ uint8_t ext_rev, const void *data, unsigned int dsize,
+ bool check_pad)
+{
+ const uint8_t nfproto = rule->chain->table->nfproto;
+ struct xt2_entry_match *ematch;
+ struct xt_mtchk_param mtpar;
+ const struct xt_match *ext;
+ int ret;
+
+ ext = try_then_request_module(xt_find_match(nfproto, ext_name,
+ ext_rev),
+ "%st_%s", xt_prefix[nfproto], ext_name);
+ if (ext == NULL)
+ return -ENOENT;
+ if (IS_ERR(ext))
+ return PTR_ERR(ext);
+
+ ret = -ENOMEM;
+ ematch = kmalloc(sizeof(*ematch), GFP_KERNEL);
+ if (ematch == NULL)
+ goto put_module;
+ ematch->ext = ext;
+ ematch->dsize = dsize;
+ ematch->data = kmemdup(data, dsize, GFP_KERNEL);
+ if (ematch->data == NULL)
+ goto free_ematch;
+
+ mtpar.net = rule->chain->table->net;
+ mtpar.table = rule->chain->table->name;
+ mtpar.match = ext;
+ mtpar.matchinfo = ematch->data;
+ mtpar.hook_mask = rule->chain->comefrom;
+ mtpar.family = rule->chain->table->nfproto;
+ mtpar.entryinfo = xt2_entryinfo_mt_get(rule);
+ ret = xt_check_match(&mtpar, dsize, rule->l4proto,
+ rule->flags & XT2_INV_L4PROTO, check_pad);
+ if (ret < 0)
+ goto free_edata;
+
+ INIT_LIST_HEAD(&ematch->anchor);
+ list_add_tail(&ematch->anchor, &rule->match_list);
+ return 0;
+
+ free_edata:
+ kfree(ematch->data);
+ free_ematch:
+ kfree(ematch);
+ put_module:
+ module_put(ext->me);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xt2_rule_add_match);
+
static void xt2_rule_free(struct xt2_rule *rule)
{
+ struct xt2_entry_match *ematch, *next_ematch;
+ struct xt_mtdtor_param mtpar;
+
+ mtpar.family = rule->chain->table->nfproto;
list_del(&rule->anchor);
+
+ list_for_each_entry_safe(ematch, next_ematch,
+ &rule->match_list, anchor) {
+ list_del(&ematch->anchor);
+ /* Note: ematch->ext is never NULL. */
+ if (ematch->ext->destroy != NULL) {
+ mtpar.net = rule->chain->table->net;
+ mtpar.match = ematch->ext;
+ mtpar.matchinfo = ematch->data;
+ ematch->ext->destroy(&mtpar);
+ }
+ module_put(ematch->ext->me);
+ kfree(ematch->data);
+ kfree(ematch);
+ }
kfree(rule);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 11/56] netfilter: xtables2: per-rule target skeletal functions
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (9 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 10/56] netfilter: xtables2: per-rule match skeletal functions Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 12/56] netfilter: xtables2: xt_check_target in combination with xt2 contexts Jan Engelhardt
` (23 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
By using a list for targets, it becomes possible to use multiple
targets in an xt2 rule.
Loop detection and Origin Tracing is not included here yet. xt1
modules, e.g. ip6_tables, will (continue to) do the loop checking and
"comefrom" marking for the time being.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 48 ++++++++++++++++++++++++
net/netfilter/x_tables.c | 72 +++++++++++++++++++++++++++++++++++-
2 files changed, 119 insertions(+), 1 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 47951aa..335cdc4 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -404,6 +404,14 @@ struct xt_table_info {
void *entries[1];
};
+/*
+ * The use of low negative numbers means we can use IS_ERR()
+ * (See xt2_special_target below.)
+ */
+#define XT2_ACTION_JUMP ((const struct xt_target *)(-2))
+#define XT2_ACTION_GOTO ((const struct xt_target *)(-3))
+#define XT2_FINAL_VERDICT ((const struct xt_target *)(-4))
+
struct xt2_table;
enum {
@@ -416,12 +424,14 @@ enum {
/**
* @anchor: list anchor for parent (xt2_chain.rule_list)
* @match_list: list of called match extensions (xt2_entry_match)
+ * @target_list: list of called target extensions (xt2_entry_targets)
* @l4proto: layer-4 protocol used (needed for xt_check_*)
* @flags: extra flags (see above)
*/
struct xt2_rule {
struct list_head anchor;
struct list_head match_list;
+ struct list_head target_list;
struct xt2_chain *chain;
uint8_t l4proto, flags;
};
@@ -440,6 +450,25 @@ struct xt2_entry_match {
};
/**
+ * @anchor: list anchor for parent (xt2_rule.target_list)
+ * @ext: pointer to extension
+ * @data: parameter block for extension (aka. "targetinfo")
+ * @r_jump: jump target; requires that @ext is %XT2_ACTION_JUMP
+ * @r_goto: goto target; requires that @ext is %XT2_ACTION_GOTO
+ * @verdict: final verdict (%XT_* or %NF_*);
+ * requires that @ext is %XT2_FINAL_VERDICT
+ */
+struct xt2_entry_target {
+ struct list_head anchor;
+ const struct xt_target *ext;
+ union {
+ void *data;
+ const struct xt2_chain *r_jump, *r_goto;
+ unsigned int verdict;
+ };
+};
+
+/**
* @anchor: list anchor for parent (xt2_table.chain_list)
* @rule_list: list of struct xt2_rule
* @name: name of chain
@@ -646,6 +675,8 @@ extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
extern int xt2_rule_add_match(struct xt2_rule *, const char *, uint8_t,
const void *, unsigned int, bool);
+extern int xt2_rule_add_target(struct xt2_rule *, const char *, uint8_t,
+ const void *, unsigned int, bool);
extern struct xt2_chain *xt2_chain_new(struct xt2_table *, const char *);
extern void xt2_chain_append(struct xt2_rule *);
@@ -657,6 +688,15 @@ extern int xt2_table_register(struct net *, struct xt2_table *);
extern struct xt2_table *xt2_table_replace(struct net *, struct xt2_table *);
extern void xt2_table_destroy(struct net *, struct xt2_table *);
+static inline bool xt2_special_target(const struct xt_target *t)
+{
+ /*
+ * We can reuse the error space [-4095..-1], as no pointers will ever
+ * have addresses in that range.
+ */
+ return IS_ERR(t);
+}
+
static inline int
xt2_rule_add_oldmatch(struct xt2_rule *rule, const struct xt_entry_match *m)
{
@@ -664,6 +704,14 @@ xt2_rule_add_oldmatch(struct xt2_rule *rule, const struct xt_entry_match *m)
m->data, m->u.match_size - sizeof(*m), true);
}
+static inline int
+xt2_rule_add_oldtarget(struct xt2_rule *rule, const struct xt_entry_target *t)
+{
+ return xt2_rule_add_target(rule, t->u.user.name, t->u.user.revision,
+ t->data, t->u.target_size - sizeof(*t),
+ true);
+}
+
static inline struct xt2_table *
xt2_table_lookup(struct net *net, const char *name, uint8_t nfproto,
unsigned int lock_mask)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index b9d0d3f..bfa2fea 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1256,6 +1256,7 @@ struct xt2_rule *xt2_rule_new(struct xt2_chain *chain)
rule->chain = chain;
INIT_LIST_HEAD(&rule->anchor);
INIT_LIST_HEAD(&rule->match_list);
+ INIT_LIST_HEAD(&rule->target_list);
return rule;
}
EXPORT_SYMBOL_GPL(xt2_rule_new);
@@ -1358,14 +1359,83 @@ int xt2_rule_add_match(struct xt2_rule *rule, const char *ext_name,
}
EXPORT_SYMBOL_GPL(xt2_rule_add_match);
+int xt2_rule_add_target(struct xt2_rule *rule, const char *ext_name,
+ uint8_t ext_rev, const void *data, unsigned int dsize,
+ bool check_pad)
+{
+ const uint8_t nfproto = rule->chain->table->nfproto;
+ struct xt2_entry_target *etarget;
+ const struct xt_target *ext;
+ struct xt_tgchk_param tgpar;
+ int ret;
+
+ ext = try_then_request_module(xt_find_target(nfproto, ext_name,
+ ext_rev),
+ "%st_%s", xt_prefix[nfproto], ext_name);
+ if (ext == NULL)
+ return -ENOENT;
+ if (IS_ERR(ext))
+ return PTR_ERR(ext);
+
+ ret = -ENOMEM;
+ etarget = kmalloc(sizeof(*etarget), GFP_KERNEL);
+ if (etarget == NULL)
+ goto put_module;
+ etarget->ext = ext;
+ etarget->data = kmemdup(data, dsize, GFP_KERNEL);
+ if (etarget->data == NULL)
+ goto free_etarget;
+
+ tgpar.net = rule->chain->table->net;
+ tgpar.table = rule->chain->table->name;
+ tgpar.target = ext;
+ tgpar.targinfo = etarget->data;
+ tgpar.hook_mask = rule->chain->comefrom;
+ tgpar.family = rule->chain->table->nfproto;
+ ret = xt_check_target(&tgpar, dsize, rule->l4proto,
+ rule->flags & XT2_INV_L4PROTO, check_pad);
+ if (ret < 0)
+ goto free_edata;
+
+ INIT_LIST_HEAD(&etarget->anchor);
+ list_add_tail(&etarget->anchor, &rule->target_list);
+ return 0;
+
+ free_edata:
+ kfree(etarget->data);
+ free_etarget:
+ kfree(etarget);
+ put_module:
+ module_put(ext->me);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xt2_rule_add_target);
+
static void xt2_rule_free(struct xt2_rule *rule)
{
+ struct xt2_entry_target *etarget, *next_etarget;
struct xt2_entry_match *ematch, *next_ematch;
struct xt_mtdtor_param mtpar;
+ struct xt_tgdtor_param tgpar;
- mtpar.family = rule->chain->table->nfproto;
+ mtpar.family = tgpar.family = rule->chain->table->nfproto;
list_del(&rule->anchor);
+ list_for_each_entry_safe(etarget, next_etarget,
+ &rule->target_list, anchor) {
+ list_del(&etarget->anchor);
+ if (!xt2_special_target(etarget->ext)) {
+ if (etarget->ext->destroy != NULL) {
+ tgpar.net = rule->chain->table->net;
+ tgpar.target = etarget->ext;
+ tgpar.targinfo = etarget->data;
+ etarget->ext->destroy(&tgpar);
+ }
+ module_put(etarget->ext->me);
+ kfree(etarget->data);
+ }
+ kfree(etarget);
+ }
list_for_each_entry_safe(ematch, next_ematch,
&rule->match_list, anchor) {
list_del(&ematch->anchor);
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 12/56] netfilter: xtables2: xt_check_target in combination with xt2 contexts
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (10 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 11/56] netfilter: xtables2: per-rule target " Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 13/56] netfilter: xtables2: jumpstack (de)allocation functions Jan Engelhardt
` (22 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
The xt1 entryinfo (e.g. struct ip6t_entry) is not available in xt2
tables. Most targets only use it to get at struct ip6t_ip6 anyway,
but TCPMSS does an ematch traversal in order to look for xt_tcp.
So TCPMSS needs to learn about xt2 ematch traversal, while the other
modules are henceforth adjusted to not depend on entryinfo anymore,
but use the supplied nfp_info set from both xt1 and xt2 contexts.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 7 +++++
net/bridge/netfilter/ebt_arpreply.c | 2 +-
net/bridge/netfilter/ebtables.c | 2 +-
net/ipv4/netfilter/arp_tables.c | 1 +
net/ipv4/netfilter/ip_tables.c | 1 +
net/ipv4/netfilter/ipt_CLUSTERIP.c | 17 ++++++-------
net/ipv4/netfilter/ipt_ECN.c | 4 +-
net/ipv4/netfilter/ipt_REJECT.c | 6 ++--
net/ipv6/netfilter/ip6_tables.c | 1 +
net/ipv6/netfilter/ip6t_REJECT.c | 6 ++--
net/netfilter/x_tables.c | 2 +
net/netfilter/xt_TCPMSS.c | 42 +++++++++++++++++++++-------------
net/netfilter/xt_TPROXY.c | 2 +-
net/sched/act_ipt.c | 3 ++
14 files changed, 60 insertions(+), 36 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 335cdc4..3849383 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -182,6 +182,8 @@ struct xt_counters_info {
#include <linux/netdevice.h>
+struct xt2_rule;
+
/**
* struct xt_action_param - parameters for matches/targets
*
@@ -258,6 +260,9 @@ struct xt_mtdtor_param {
*
* @entryinfo: the family-specific rule data
* (struct ipt_entry, ip6t_entry, arpt_entry, ebt_entry)
+ * @nfproto_info: xt2 layer-2/3 data block (struct ipt_ip, ip6t_ip6,
+ * arpt_arp/ebt_entry). Always valid.
+ * @rule: Pointer to rule target is contained within.
*
* Other fields see above.
*/
@@ -265,6 +270,8 @@ struct xt_tgchk_param {
struct net *net;
const char *table;
const void *entryinfo;
+ const void *nfproto_info;
+ const struct xt2_rule *rule;
const struct xt_target *target;
void *targinfo;
unsigned int hook_mask;
diff --git a/net/bridge/netfilter/ebt_arpreply.c b/net/bridge/netfilter/ebt_arpreply.c
index 070cf13..8ac717b 100644
--- a/net/bridge/netfilter/ebt_arpreply.c
+++ b/net/bridge/netfilter/ebt_arpreply.c
@@ -60,7 +60,7 @@ ebt_arpreply_tg(struct sk_buff *skb, const struct xt_action_param *par)
static int ebt_arpreply_tg_check(const struct xt_tgchk_param *par)
{
const struct ebt_arpreply_info *info = par->targinfo;
- const struct ebt_entry *e = par->entryinfo;
+ const struct ebt_entry *e = par->nfproto_info;
if (BASE_CHAIN && info->target == EBT_RETURN)
return -EINVAL;
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index ab37e1c..8a820cf 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -692,7 +692,7 @@ ebt_check_entry(struct ebt_entry *e, struct net *net,
mtpar.net = tgpar.net = net;
mtpar.table = tgpar.table = name;
- mtpar.entryinfo = tgpar.entryinfo = e;
+ mtpar.entryinfo = tgpar.entryinfo = tgpar.nfproto_info = e;
mtpar.hook_mask = tgpar.hook_mask = hookmask;
mtpar.family = tgpar.family = NFPROTO_BRIDGE;
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 2fee4a5..85ea80e 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -548,6 +548,7 @@ static inline int check_target(struct arpt_entry *e, const char *name)
struct xt_tgchk_param par = {
.table = name,
.entryinfo = e,
+ .nfproto_info = &e->arp,
.target = t->u.kernel.target,
.targinfo = t->data,
.hook_mask = e->comefrom,
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 3809f38..c7757b1 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -742,6 +742,7 @@ static int check_target(struct ipt_entry *e, struct net *net, const char *name)
.net = net,
.table = name,
.entryinfo = e,
+ .nfproto_info = &e->ip,
.target = t->u.kernel.target,
.targinfo = t->data,
.hook_mask = e->comefrom,
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 64d0875..5beed9f 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -358,7 +358,7 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
static int clusterip_tg_check(const struct xt_tgchk_param *par)
{
struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
- const struct ipt_entry *e = par->entryinfo;
+ const struct ipt_ip *eip = par->nfproto_info;
struct clusterip_config *config;
int ret;
@@ -369,37 +369,36 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
return -EINVAL;
}
- if (e->ip.dmsk.s_addr != htonl(0xffffffff) ||
- e->ip.dst.s_addr == 0) {
+ if (eip->dmsk.s_addr != htonl(0xffffffff) || eip->dst.s_addr == 0) {
pr_info("Please specify destination IP\n");
return -EINVAL;
}
/* FIXME: further sanity checks */
- config = clusterip_config_find_get(e->ip.dst.s_addr, 1);
+ config = clusterip_config_find_get(eip->dst.s_addr, 1);
if (!config) {
if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) {
pr_info("no config found for %pI4, need 'new'\n",
- &e->ip.dst.s_addr);
+ &eip->dst.s_addr);
return -EINVAL;
} else {
struct net_device *dev;
- if (e->ip.iniface[0] == '\0') {
+ if (eip->iniface[0] == '\0') {
pr_info("Please specify an interface name\n");
return -EINVAL;
}
- dev = dev_get_by_name(&init_net, e->ip.iniface);
+ dev = dev_get_by_name(&init_net, eip->iniface);
if (!dev) {
pr_info("no such interface %s\n",
- e->ip.iniface);
+ eip->iniface);
return -ENOENT;
}
config = clusterip_config_init(cipinfo,
- e->ip.dst.s_addr, dev);
+ eip->dst.s_addr, dev);
if (!config) {
pr_info("cannot allocate config\n");
dev_put(dev);
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index 4bf3dc4..603ea84 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -96,7 +96,7 @@ ecn_tg(struct sk_buff *skb, const struct xt_action_param *par)
static int ecn_tg_check(const struct xt_tgchk_param *par)
{
const struct ipt_ECN_info *einfo = par->targinfo;
- const struct ipt_entry *e = par->entryinfo;
+ const struct ipt_ip *eip = par->nfproto_info;
if (einfo->operation & IPT_ECN_OP_MASK) {
pr_info("unsupported ECN operation %x\n", einfo->operation);
@@ -107,7 +107,7 @@ static int ecn_tg_check(const struct xt_tgchk_param *par)
return -EINVAL;
}
if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) &&
- (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) {
+ (eip->proto != IPPROTO_TCP || (eip->invflags & XT_INV_PROTO))) {
pr_info("cannot use TCP operations on a non-tcp rule\n");
return -EINVAL;
}
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index f5f4a88..ca35673 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -175,15 +175,15 @@ reject_tg(struct sk_buff *skb, const struct xt_action_param *par)
static int reject_tg_check(const struct xt_tgchk_param *par)
{
const struct ipt_reject_info *rejinfo = par->targinfo;
- const struct ipt_entry *e = par->entryinfo;
+ const struct ipt_ip *eip = par->nfproto_info;
if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
pr_info("ECHOREPLY no longer supported.\n");
return -EINVAL;
} else if (rejinfo->with == IPT_TCP_RESET) {
/* Must specify that it's a TCP packet */
- if (e->ip.proto != IPPROTO_TCP ||
- (e->ip.invflags & XT_INV_PROTO)) {
+ if (eip->proto != IPPROTO_TCP ||
+ (eip->invflags & XT_INV_PROTO)) {
pr_info("TCP_RESET invalid for non-tcp\n");
return -EINVAL;
}
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index cd8a2f1..3b91f0a 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -756,6 +756,7 @@ static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
.net = net,
.table = name,
.entryinfo = e,
+ .nfproto_info = &e->ipv6,
.target = t->u.kernel.target,
.targinfo = t->data,
.hook_mask = e->comefrom,
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 47d2277..14014d6 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -215,15 +215,15 @@ reject_tg6(struct sk_buff *skb, const struct xt_action_param *par)
static int reject_tg6_check(const struct xt_tgchk_param *par)
{
const struct ip6t_reject_info *rejinfo = par->targinfo;
- const struct ip6t_entry *e = par->entryinfo;
+ const struct ip6t_ip6 *eip = par->nfproto_info;
if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
pr_info("ECHOREPLY is not supported.\n");
return -EINVAL;
} else if (rejinfo->with == IP6T_TCP_RESET) {
/* Must specify that it's a TCP packet */
- if (e->ipv6.proto != IPPROTO_TCP ||
- (e->ipv6.invflags & XT_INV_PROTO)) {
+ if (eip->proto != IPPROTO_TCP ||
+ (eip->invflags & XT_INV_PROTO)) {
pr_info("TCP_RESET illegal for non-tcp\n");
return -EINVAL;
}
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index bfa2fea..7126e28 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1386,6 +1386,8 @@ int xt2_rule_add_target(struct xt2_rule *rule, const char *ext_name,
if (etarget->data == NULL)
goto free_etarget;
+ tgpar.nfproto_info = xt2_entryinfo_mt_get(rule);
+ tgpar.rule = rule;
tgpar.net = rule->chain->table->net;
tgpar.table = rule->chain->table->name;
tgpar.target = ext;
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index 1841388..01576f9 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -223,14 +223,30 @@ tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
#define TH_SYN 0x02
/* Must specify -p tcp --syn */
-static inline bool find_syn_match(const struct xt_entry_match *m)
+static inline bool find_syn_match(const struct xt_tgchk_param *par)
{
- const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
+ const struct xt_tcp *tcpinfo;
- if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
- tcpinfo->flg_cmp & TH_SYN &&
- !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
- return true;
+ if (par->rule != NULL) {
+ const struct xt2_entry_match *ematch;
+
+ list_for_each_entry(ematch, &par->rule->match_list, anchor) {
+ tcpinfo = ematch->data;
+ if (strcmp(ematch->ext->name, "tcp") == 0 &&
+ (tcpinfo->flg_cmp & TH_SYN) &&
+ !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
+ return true;
+ }
+ } else {
+ const struct xt_entry_match *ematch;
+ const struct ip6t_entry *e = par->entryinfo;
+
+ xt_ematch_foreach(ematch, e)
+ if (strcmp(ematch->u.kernel.match->name, "tcp") == 0 &&
+ (tcpinfo->flg_cmp & TH_SYN) &&
+ !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
+ return true;
+ }
return false;
}
@@ -238,8 +254,6 @@ static inline bool find_syn_match(const struct xt_entry_match *m)
static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
{
const struct xt_tcpmss_info *info = par->targinfo;
- const struct ipt_entry *e = par->entryinfo;
- const struct xt_entry_match *ematch;
if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
(par->hook_mask & ~((1 << NF_INET_FORWARD) |
@@ -249,9 +263,8 @@ static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
"FORWARD, OUTPUT and POSTROUTING hooks\n");
return -EINVAL;
}
- xt_ematch_foreach(ematch, e)
- if (find_syn_match(ematch))
- return 0;
+ if (find_syn_match(par))
+ return 0;
pr_info("Only works on TCP SYN packets\n");
return -EINVAL;
}
@@ -260,8 +273,6 @@ static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
{
const struct xt_tcpmss_info *info = par->targinfo;
- const struct ip6t_entry *e = par->entryinfo;
- const struct xt_entry_match *ematch;
if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
(par->hook_mask & ~((1 << NF_INET_FORWARD) |
@@ -271,9 +282,8 @@ static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
"FORWARD, OUTPUT and POSTROUTING hooks\n");
return -EINVAL;
}
- xt_ematch_foreach(ematch, e)
- if (find_syn_match(ematch))
- return 0;
+ if (find_syn_match(par))
+ return 0;
pr_info("Only works on TCP SYN packets\n");
return -EINVAL;
}
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index e1a0ded..dcf061a 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -61,7 +61,7 @@ tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par)
static int tproxy_tg_check(const struct xt_tgchk_param *par)
{
- const struct ipt_ip *i = par->entryinfo;
+ const struct ipt_ip *i = par->nfproto_info;
if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
&& !(i->invflags & IPT_INV_PROTO))
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 79223ec..b78887f 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -41,6 +41,7 @@ static struct tcf_hashinfo ipt_hash_info = {
static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
{
+ struct ipt_ip l3info = {};
struct xt_tgchk_param par;
struct xt_target *target;
int ret = 0;
@@ -51,6 +52,8 @@ static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int
return PTR_ERR(target);
t->u.kernel.target = target;
+ par.nfproto_info = &l3info;
+ par.rule = NULL;
par.table = table;
par.entryinfo = NULL;
par.target = target;
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 13/56] netfilter: xtables2: jumpstack (de)allocation functions
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (11 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 12/56] netfilter: xtables2: xt_check_target in combination with xt2 contexts Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 14/56] netfilter: xtables2: table traversal Jan Engelhardt
` (21 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 13 ++++++
net/netfilter/x_tables.c | 73 +++++++++++++++++++++++++++++++++++-
2 files changed, 85 insertions(+), 1 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 3849383..fcca7a6 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -512,6 +512,14 @@ enum {
* @chain_list: list of chains (struct xt2_chain)
* @name: name of this table
* @nfproto: nfproto the table is used exclusively with
+ * @rq_stacksize: Size of the jumpstack. This is usually set to the
+ * number of user chains -- since tables cannot have
+ * loops, at most that many jumps can possibly be made --
+ * or a value dependent thereof, such as when it is
+ * multiplied to allow for reentry.
+ * @stacksize: current size of the stack (@stackptr, @jumpstack)
+ * @stackptr: current stack pointer, one per CPU
+ * @jumpstack: our stack, also one per CPU
* @entrypoint: start chains for hooks
* @underflow: base chain policy (rule)
* @net: encompassing netns. To be set by xt2_table_new caller.
@@ -521,6 +529,11 @@ struct xt2_table {
struct list_head chain_list;
char name[11];
uint8_t nfproto;
+
+ unsigned int rq_stacksize, stacksize;
+ unsigned int __percpu *stackptr;
+ const struct xt2_rule ***jumpstack;
+
const struct xt2_chain *entrypoint[NF_INET_NUMHOOKS];
const struct xt2_rule *underflow[NF_INET_NUMHOOKS];
struct net *net;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 7126e28..c820bdc 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1463,6 +1463,7 @@ struct xt2_chain *xt2_chain_new(struct xt2_table *table, const char *name)
if (chain == NULL)
return NULL;
+ ++table->rq_stacksize;
chain->table = table;
INIT_LIST_HEAD(&chain->anchor);
INIT_LIST_HEAD(&chain->rule_list);
@@ -1491,11 +1492,76 @@ static void xt2_chain_free(struct xt2_chain *chain)
struct xt2_rule *rule, *next_rule;
list_del(&chain->anchor);
+ --chain->table->rq_stacksize;
list_for_each_entry_safe(rule, next_rule, &chain->rule_list, anchor)
xt2_rule_free(rule);
kfree(chain);
}
+/**
+ * Allocate jumpstacks. This is normally called sometime after the chains
+ * have all been added to the table.
+ */
+static int xt2_jumpstack_alloc(struct xt2_table *table)
+{
+ unsigned int size, cpu;
+
+ table->stackptr = alloc_percpu(unsigned int);
+ if (table->stackptr == NULL)
+ return -ENOMEM;
+
+ size = sizeof(struct xt2_rule **) * nr_cpu_ids;
+ if (size > PAGE_SIZE)
+ table->jumpstack = vmalloc(size);
+ else
+ table->jumpstack = kmalloc(size, GFP_KERNEL);
+ if (table->jumpstack == NULL)
+ return -ENOMEM;
+ memset(table->jumpstack, 0, size);
+
+ table->stacksize = table->rq_stacksize * xt_jumpstack_multiplier;
+ size = sizeof(struct xt2_rule *) * table->stacksize;
+ for_each_possible_cpu(cpu) {
+ if (size > PAGE_SIZE)
+ table->jumpstack[cpu] = vmalloc_node(size,
+ cpu_to_node(cpu));
+ else
+ table->jumpstack[cpu] = kmalloc_node(size,
+ GFP_KERNEL,
+ cpu_to_node(cpu));
+ if (table->jumpstack[cpu] == NULL)
+ /*
+ * Freeing will be done later on by the callers. The
+ * chain is: xt2_table_replace ->
+ * ipt2_register_table -> xt2_table_destroy
+ */
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void xt2_jumpstack_free(struct xt2_table *table)
+{
+ unsigned int cpu;
+
+ if (table->jumpstack != NULL) {
+ if (sizeof(struct xt2_rule *) * table->stacksize > PAGE_SIZE) {
+ for_each_possible_cpu(cpu)
+ vfree(table->jumpstack[cpu]);
+ } else {
+ for_each_possible_cpu(cpu)
+ kfree(table->jumpstack[cpu]);
+ }
+ if (sizeof(struct xt2_rule **) * nr_cpu_ids > PAGE_SIZE)
+ vfree(table->jumpstack);
+ else
+ kfree(table->jumpstack);
+ }
+
+ free_percpu(table->stackptr);
+}
+
struct xt2_table *xt2_table_new(void)
{
struct xt2_table *table;
@@ -1537,7 +1603,7 @@ EXPORT_SYMBOL_GPL(xt2_tlink_lookup);
int xt2_table_register(struct net *net, struct xt2_table *table)
{
struct xt2_table_link *link;
- int ret = 0;
+ int ret;
if (*table->name == '\0')
/* Empty names don't fly with our strcmp. */
@@ -1550,6 +1616,10 @@ int xt2_table_register(struct net *net, struct xt2_table *table)
goto out;
}
+ ret = xt2_jumpstack_alloc(table);
+ if (ret < 0)
+ goto out;
+
link = kmalloc(sizeof(*link), GFP_KERNEL);
if (link == NULL) {
ret = -ENOMEM;
@@ -1633,6 +1703,7 @@ void xt2_table_destroy(struct net *net, struct xt2_table *table)
if (net != NULL)
xt2_table_unregister(net, table);
+ xt2_jumpstack_free(table);
list_for_each_entry_safe(chain, next_chain, &table->chain_list, anchor)
xt2_chain_free(chain);
kfree(table);
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 14/56] netfilter: xtables2: table traversal
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (12 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 13/56] netfilter: xtables2: jumpstack (de)allocation functions Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 15/56] netfilter: xtables: add xt_quota revision 3 Jan Engelhardt
` (20 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 5 ++
net/netfilter/x_tables.c | 115 ++++++++++++++++++++++++++++++++++++
2 files changed, 120 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index fcca7a6..a90b758 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -708,6 +708,11 @@ extern int xt2_table_register(struct net *, struct xt2_table *);
extern struct xt2_table *xt2_table_replace(struct net *, struct xt2_table *);
extern void xt2_table_destroy(struct net *, struct xt2_table *);
+extern unsigned int xt2_do_table(struct sk_buff *, unsigned int,
+ const struct net_device *,
+ const struct net_device *,
+ const struct xt2_table *);
+
static inline bool xt2_special_target(const struct xt_target *t)
{
/*
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index c820bdc..f63587a 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -56,6 +56,17 @@ struct xt_af {
static struct xt_af *xt;
+/***
+ * xt2 internal decisions -
+ *
+ * %XT_START_CHAIN: used to implement jump/goto after chain got switched
+ */
+enum {
+ XT_START_CHAIN = 0xFFFFFFF9,
+ /* XT_RETURN = 0xFFFFFFFB, */ /* reminder (x_tables.h) */
+ /* XT_CONTINUE = 0xFFFFFFFF, */ /* reminder (x_tables.h) */
+};
+
static const char *const xt_prefix[NFPROTO_NUMPROTO] = {
[NFPROTO_UNSPEC] = "x",
[NFPROTO_IPV4] = "ip",
@@ -1649,6 +1660,7 @@ struct xt2_table *xt2_table_replace(struct net *net, struct xt2_table *table)
{
struct xt2_table_link *link;
struct xt2_table *old_table;
+ int ret;
if (*table->name == '\0')
return ERR_PTR(-EINVAL);
@@ -1657,6 +1669,11 @@ struct xt2_table *xt2_table_replace(struct net *net, struct xt2_table *table)
XT2_KEEP_RCULOCK);
if (link == NULL)
return ERR_PTR(-ENOENT);
+ ret = xt2_jumpstack_alloc(table);
+ if (ret < 0) {
+ rcu_read_unlock();
+ return ERR_PTR(ret);
+ }
mutex_lock(&net->xt2.table_lock);
old_table = rcu_dereference(link->table);
@@ -1710,6 +1727,104 @@ void xt2_table_destroy(struct net *net, struct xt2_table *table)
}
EXPORT_SYMBOL_GPL(xt2_table_destroy);
+static unsigned int
+xt2_do_actions(struct sk_buff *skb, struct xt_action_param *acpar,
+ const struct xt2_rule *rule, const struct xt2_chain **chain_ptr,
+ unsigned int *stackptr, unsigned int stacksize,
+ const struct xt2_rule **jumpstack)
+{
+ const struct xt2_entry_target *etarget;
+ const struct xt2_entry_match *ematch;
+ /* For rules without targets: */
+ unsigned int verdict = XT_CONTINUE;
+ bool ret;
+
+ list_for_each_entry(ematch, &rule->match_list, anchor) {
+ acpar->match = ematch->ext;
+ acpar->matchinfo = ematch->data;
+ ret = ematch->ext->match(skb, acpar);
+ if (acpar->hotdrop)
+ return NF_DROP;
+ else if (!ret)
+ return XT_CONTINUE;
+ }
+
+ list_for_each_entry(etarget, &rule->target_list, anchor) {
+ if (etarget->ext == XT2_ACTION_GOTO) {
+ *chain_ptr = etarget->r_goto;
+ return XT_START_CHAIN;
+ } else if (etarget->ext == XT2_ACTION_JUMP) {
+ if (*stackptr >= stacksize)
+ return NF_DROP;
+ jumpstack[(*stackptr)++] = rule;
+ *chain_ptr = etarget->r_jump;
+ return XT_START_CHAIN;
+ } else if (etarget->ext == XT2_FINAL_VERDICT) {
+ verdict = etarget->verdict;
+ } else {
+ acpar->target = etarget->ext;
+ acpar->targinfo = etarget->data;
+ verdict = etarget->ext->target(skb, acpar);
+ }
+ if (verdict != XT_CONTINUE)
+ break;
+ }
+
+ return verdict;
+}
+
+unsigned int
+xt2_do_table(struct sk_buff *skb, unsigned int hook,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt2_table *table)
+{
+ unsigned int cpu = smp_processor_id();
+ const struct xt2_rule **jumpstack = table->jumpstack[cpu];
+ unsigned int *stackptr = per_cpu_ptr(table->stackptr, cpu);
+ unsigned int verdict = NF_DROP;
+ const struct xt2_chain *chain;
+ const struct xt2_rule *rule;
+ struct xt_action_param acpar = {
+ .family = table->nfproto,
+ .in = in,
+ .out = out,
+ .hooknum = hook,
+ };
+
+ chain = table->entrypoint[hook];
+ do_chain:
+ rule = list_first_entry(&chain->rule_list, typeof(*rule), anchor);
+ do_rule:
+ if (&rule->anchor == &chain->rule_list)
+ /* End of chain */
+ verdict = XT_RETURN;
+ else
+ verdict = xt2_do_actions(skb, &acpar, rule, &chain, stackptr,
+ table->stacksize, jumpstack);
+
+ switch (verdict) {
+ case XT_START_CHAIN:
+ goto do_chain;
+ case XT_RETURN:
+ if (*stackptr == 0) {
+ rule = table->underflow[hook];
+ chain = rule->chain;
+ goto do_rule;
+ }
+ /* What was on the stack was where we left... */
+ --*stackptr;
+ rule = jumpstack[*stackptr];
+ chain = rule->chain;
+ /* ...fallthru to advance */
+ case XT_CONTINUE:
+ rule = list_entry(rule->anchor.next, typeof(*rule), anchor);
+ goto do_rule;
+ }
+
+ return verdict;
+}
+EXPORT_SYMBOL_GPL(xt2_do_table);
+
int xt_proto_init(struct net *net, u_int8_t af)
{
#ifdef CONFIG_PROC_FS
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 15/56] netfilter: xtables: add xt_quota revision 3
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (13 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 14/56] netfilter: xtables2: table traversal Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 16/56] netfilter: xtables2: make a copy of the ipv6_filter table Jan Engelhardt
` (19 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
The quota match has been extended in Xtables-addons for a while, whereby
it gained packet counting, upcounting support, named counters and
procfs-based read/write support. Its anonymous counters will be used for
traditional per-rule counters.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/xt_quota.h | 19 +++-
net/netfilter/xt_quota.c | 243 ++++++++++++++++++++++++++++++++++--
2 files changed, 248 insertions(+), 14 deletions(-)
diff --git a/include/linux/netfilter/xt_quota.h b/include/linux/netfilter/xt_quota.h
index 8dc89df..f14e36d 100644
--- a/include/linux/netfilter/xt_quota.h
+++ b/include/linux/netfilter/xt_quota.h
@@ -2,9 +2,11 @@
#define _XT_QUOTA_H
enum xt_quota_flags {
- XT_QUOTA_INVERT = 0x1,
+ XT_QUOTA_INVERT = 1 << 0,
+ XT_QUOTA_GROW = 1 << 1,
+ XT_QUOTA_PACKET = 1 << 2,
+ XT_QUOTA_MASK = 0x7,
};
-#define XT_QUOTA_MASK 0x1
struct xt_quota_priv;
@@ -17,4 +19,17 @@ struct xt_quota_info {
struct xt_quota_priv *master;
};
+struct xt_quota_counter;
+
+struct xt_quota_mtinfo3 {
+ char name[15];
+ u_int8_t flags;
+
+ /* Comparison-invariant */
+ aligned_u64 quota;
+
+ /* Used internally by the kernel */
+ struct xt_quota_counter *master __attribute__((aligned(8)));
+};
+
#endif /* _XT_QUOTA_H */
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
index b4f7dfe..d62b35d 100644
--- a/net/netfilter/xt_quota.c
+++ b/net/netfilter/xt_quota.c
@@ -3,9 +3,12 @@
*
* Sam Johnston <samj@samj.net>
*/
+#include <linux/list.h>
+#include <linux/proc_fs.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <asm/atomic.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_quota.h>
@@ -14,14 +17,207 @@ struct xt_quota_priv {
uint64_t quota;
};
+struct xt_quota_counter {
+ u_int64_t quota;
+ spinlock_t lock;
+ struct list_head list;
+ atomic_t ref;
+ char name[sizeof(((struct xt_quota_mtinfo3 *)NULL)->name)];
+ struct proc_dir_entry *procfs_entry;
+};
+
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
-MODULE_DESCRIPTION("Xtables: countdown quota match");
+MODULE_DESCRIPTION("Xtables: counter match");
MODULE_ALIAS("ipt_quota");
MODULE_ALIAS("ip6t_quota");
static DEFINE_SPINLOCK(quota_lock);
+static LIST_HEAD(counter_list);
+static DEFINE_SPINLOCK(counter_list_lock);
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_xt_quota;
+static unsigned int quota_list_perms = S_IRUGO | S_IWUSR;
+static unsigned int quota_list_uid;
+static unsigned int quota_list_gid;
+module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR);
+module_param_named(uid, quota_list_uid, uint, S_IRUGO | S_IWUSR);
+module_param_named(gid, quota_list_gid, uint, S_IRUGO | S_IWUSR);
+
+static int quota_proc_read(char *page, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ struct xt_quota_counter *e = data;
+ int ret;
+
+ spin_lock_bh(&e->lock);
+ ret = snprintf(page, PAGE_SIZE, "%llu\n", e->quota);
+ spin_unlock_bh(&e->lock);
+ return ret;
+}
+
+static int quota_proc_write(struct file *file, const char __user *input,
+ unsigned long size, void *data)
+{
+ struct xt_quota_counter *e = data;
+ char buf[sizeof("18446744073709551616")];
+
+ if (size > sizeof(buf))
+ size = sizeof(buf);
+ if (copy_from_user(buf, input, size) != 0)
+ return -EFAULT;
+ buf[sizeof(buf)-1] = '\0';
+
+ spin_lock_bh(&e->lock);
+ e->quota = simple_strtoull(buf, NULL, 0);
+ spin_unlock_bh(&e->lock);
+ return size;
+}
+#endif
+
+static struct xt_quota_counter *
+q3_new_counter(const struct xt_quota_mtinfo3 *q, bool anon)
+{
+ struct xt_quota_counter *e;
+ unsigned int size;
+
+ /* Do not need all the procfs things for anonymous counters. */
+ size = anon ? offsetof(typeof(*e), list) : sizeof(*e);
+ e = kmalloc(size, GFP_KERNEL);
+ if (e == NULL)
+ return NULL;
+
+ e->quota = q->quota;
+ spin_lock_init(&e->lock);
+ if (!anon) {
+ INIT_LIST_HEAD(&e->list);
+ atomic_set(&e->ref, 1);
+ strncpy(e->name, q->name, sizeof(e->name));
+ }
+ return e;
+}
+
+/**
+ * q3_get_counter - get ref to counter or create new
+ * @name: name of counter
+ */
+static struct xt_quota_counter *
+q3_get_counter(const struct xt_quota_mtinfo3 *q)
+{
+ struct proc_dir_entry *p;
+ struct xt_quota_counter *e;
+
+ if (*q->name == '\0')
+ return q3_new_counter(q, true);
+
+#ifdef CONFIG_PROC_FS
+ spin_lock_bh(&counter_list_lock);
+ list_for_each_entry(e, &counter_list, list)
+ if (strcmp(e->name, q->name) == 0) {
+ atomic_inc(&e->ref);
+ spin_unlock_bh(&counter_list_lock);
+ return e;
+ }
+
+ e = q3_new_counter(q, false);
+ if (e == NULL)
+ goto out;
+
+ p = e->procfs_entry = create_proc_entry(e->name, quota_list_perms,
+ proc_xt_quota);
+ if (p == NULL || IS_ERR(p))
+ goto out;
+
+ p->data = e;
+ p->read_proc = quota_proc_read;
+ p->write_proc = quota_proc_write;
+ p->uid = quota_list_uid;
+ p->gid = quota_list_gid;
+ list_add_tail(&e->list, &counter_list);
+ spin_unlock_bh(&counter_list_lock);
+ return e;
+
+ out:
+ spin_unlock_bh(&counter_list_lock);
+ kfree(e);
+ return NULL;
+#endif
+}
+
+static int quota_mt3_check(const struct xt_mtchk_param *par)
+{
+ struct xt_quota_mtinfo3 *q = par->matchinfo;
+
+ if (q->flags & ~XT_QUOTA_MASK)
+ return -EINVAL;
+
+ q->name[sizeof(q->name)-1] = '\0';
+ if (*q->name == '.' || strchr(q->name, '/') != NULL) {
+ pr_err("xt_quota.3: illegal name\n");
+ return -EINVAL;
+ }
+
+ q->master = q3_get_counter(q);
+ if (q->master == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void quota_mt3_destroy(const struct xt_mtdtor_param *par)
+{
+ struct xt_quota_mtinfo3 *q = par->matchinfo;
+ struct xt_quota_counter *e = q->master;
+
+ if (*q->name == '\0') {
+ /* anon counter */
+ kfree(e);
+ return;
+ }
+#ifdef CONFIG_PROC_FS
+ spin_lock_bh(&counter_list_lock);
+ if (!atomic_dec_and_test(&e->ref)) {
+ spin_unlock_bh(&counter_list_lock);
+ return;
+ }
+
+ list_del(&e->list);
+ remove_proc_entry(e->name, proc_xt_quota);
+ spin_unlock_bh(&counter_list_lock);
+ kfree(e);
+#endif /* CONFIG_PROC_FS */
+}
+
+static bool
+quota_mt3(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ struct xt_quota_mtinfo3 *q = (void *)par->matchinfo;
+ struct xt_quota_counter *e = q->master;
+ bool ret = q->flags & XT_QUOTA_INVERT;
+
+ spin_lock_bh(&e->lock);
+ if (q->flags & XT_QUOTA_GROW) {
+ e->quota += (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
+ q->quota = e->quota;
+ ret = true;
+ } else {
+ if (e->quota >= skb->len) {
+ e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
+ ret = !ret;
+ } else {
+ /* we do not allow even small packets from now on */
+ e->quota = 0;
+ }
+ q->quota = e->quota;
+ }
+ spin_unlock_bh(&e->lock);
+ return ret;
+}
+
+
static bool
quota_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
@@ -66,25 +262,48 @@ static void quota_mt_destroy(const struct xt_mtdtor_param *par)
kfree(q->master);
}
-static struct xt_match quota_mt_reg __read_mostly = {
- .name = "quota",
- .revision = 0,
- .family = NFPROTO_UNSPEC,
- .match = quota_mt,
- .checkentry = quota_mt_check,
- .destroy = quota_mt_destroy,
- .matchsize = sizeof(struct xt_quota_info),
- .me = THIS_MODULE,
+static struct xt_match quota_mt_reg[] __read_mostly = {
+ {
+ .name = "quota",
+ .revision = 0,
+ .family = NFPROTO_UNSPEC,
+ .match = quota_mt,
+ .checkentry = quota_mt_check,
+ .destroy = quota_mt_destroy,
+ .matchsize = sizeof(struct xt_quota_info),
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "quota",
+ .revision = 3,
+ .family = NFPROTO_UNSPEC,
+ .checkentry = quota_mt3_check,
+ .match = quota_mt3,
+ .destroy = quota_mt3_destroy,
+ .matchsize = sizeof(struct xt_quota_mtinfo3),
+ .me = THIS_MODULE,
+ },
};
static int __init quota_mt_init(void)
{
- return xt_register_match("a_mt_reg);
+ int ret;
+
+ /* to be resolved in next patch */
+ proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net);
+ if (proc_xt_quota == NULL)
+ return -ENOMEM;
+
+ ret = xt_register_matches(quota_mt_reg, ARRAY_SIZE(quota_mt_reg));
+ if (ret < 0)
+ remove_proc_entry("xt_quota", init_net.proc_net);
+ return ret;
}
static void __exit quota_mt_exit(void)
{
- xt_unregister_match("a_mt_reg);
+ xt_unregister_matches(quota_mt_reg, ARRAY_SIZE(quota_mt_reg));
+ remove_proc_entry("xt_quota", init_net.proc_net);
}
module_init(quota_mt_init);
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 16/56] netfilter: xtables2: make a copy of the ipv6_filter table
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (14 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 15/56] netfilter: xtables: add xt_quota revision 3 Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 17/56] netfilter: xtables2: initial xt1->xt2 translation for tables Jan Engelhardt
` (18 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
A "filter2" table is temporarily added for testing and patching, so
as to not break bisection operations where ip6table_filter needs to
remain fully functional. It is compiled unconditionally alongside
"filter" for simplicity, only developers see it anyhow while it lives.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/net/netns/x_tables.h | 1 +
net/ipv6/netfilter/Makefile | 2 +-
net/ipv6/netfilter/ip6table_filter2.c | 113 +++++++++++++++++++++++++++++++++
3 files changed, 115 insertions(+), 1 deletions(-)
create mode 100644 net/ipv6/netfilter/ip6table_filter2.c
diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
index 8a2d497..1e96a54 100644
--- a/include/net/netns/x_tables.h
+++ b/include/net/netns/x_tables.h
@@ -19,6 +19,7 @@ struct netns_xt {
struct netns_xt2 {
struct mutex table_lock;
struct list_head table_list[NFPROTO_NUMPROTO];
+ struct xt_table *ipv6_filter;
};
#endif
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index aafbba3..35fa80f 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -4,7 +4,7 @@
# Link order matters here.
obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
-obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
+obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o ip6table_filter2.o
obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
diff --git a/net/ipv6/netfilter/ip6table_filter2.c b/net/ipv6/netfilter/ip6table_filter2.c
new file mode 100644
index 0000000..55750e4
--- /dev/null
+++ b/net/ipv6/netfilter/ip6table_filter2.c
@@ -0,0 +1,113 @@
+/*
+ * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
+ *
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/slab.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
+MODULE_DESCRIPTION("ip6tables filter table");
+
+#define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
+ (1 << NF_INET_FORWARD) | \
+ (1 << NF_INET_LOCAL_OUT))
+
+static const struct xt_table packet_filter = {
+ .name = "filter2",
+ .valid_hooks = FILTER_VALID_HOOKS,
+ .me = THIS_MODULE,
+ .af = NFPROTO_IPV6,
+ .priority = NF_IP6_PRI_FILTER,
+};
+
+/* The work comes in here from netfilter.c. */
+static unsigned int
+ip6table_filter_hook(unsigned int hook, struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ const struct net *net = dev_net((in != NULL) ? in : out);
+
+ return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter);
+}
+
+static struct nf_hook_ops *filter_ops __read_mostly;
+
+/* Default to forward because I got too much mail already. */
+static int forward = NF_ACCEPT;
+module_param(forward, bool, 0000);
+
+static int __net_init ip6table_filter_net_init(struct net *net)
+{
+ struct ip6t_replace *repl;
+
+ repl = ip6t_alloc_initial_table(&packet_filter);
+ if (repl == NULL)
+ return -ENOMEM;
+ /* Entry 1 is the FORWARD hook */
+ ((struct ip6t_standard *)repl->entries)[1].target.verdict =
+ -forward - 1;
+
+ net->xt2.ipv6_filter =
+ ip6t_register_table(net, &packet_filter, repl);
+ kfree(repl);
+ if (IS_ERR(net->xt2.ipv6_filter))
+ return PTR_ERR(net->xt2.ipv6_filter);
+ return 0;
+}
+
+static void __net_exit ip6table_filter_net_exit(struct net *net)
+{
+ ip6t_unregister_table(net, net->xt2.ipv6_filter);
+}
+
+static struct pernet_operations ip6table_filter_net_ops = {
+ .init = ip6table_filter_net_init,
+ .exit = ip6table_filter_net_exit,
+};
+
+static int __init ip6table_filter_init(void)
+{
+ int ret;
+
+ if (forward < 0 || forward > NF_MAX_VERDICT) {
+ pr_err("iptables forward must be 0 or 1\n");
+ return -EINVAL;
+ }
+
+ ret = register_pernet_subsys(&ip6table_filter_net_ops);
+ if (ret < 0)
+ return ret;
+
+ /* Register hooks */
+ filter_ops = xt_hook_link(&packet_filter, ip6table_filter_hook);
+ if (IS_ERR(filter_ops)) {
+ ret = PTR_ERR(filter_ops);
+ goto cleanup_table;
+ }
+
+ return ret;
+
+ cleanup_table:
+ unregister_pernet_subsys(&ip6table_filter_net_ops);
+ return ret;
+}
+
+static void __exit ip6table_filter_fini(void)
+{
+ xt_hook_unlink(&packet_filter, filter_ops);
+ unregister_pernet_subsys(&ip6table_filter_net_ops);
+}
+
+module_init(ip6table_filter_init);
+module_exit(ip6table_filter_fini);
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 17/56] netfilter: xtables2: initial xt1->xt2 translation for tables
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (15 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 16/56] netfilter: xtables2: make a copy of the ipv6_filter table Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 18/56] netfilter: xtables2: xt2->xt1 translation - GET_INFO support Jan Engelhardt
` (17 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
This commit adds enough logic to translate the initial table, as
provided by ip6table modules, to an xt2 table. The translation code
goes into a file xt1_compat.c that is planned to be shared with the
other *_tables too, hence the little #define/#include hack. I deem
this is the better evil -- at least when done right, and it looks
promising -- compared to the real code duplication that is currently
in place.
The "filter2" table can be used for testing: modprobing it/rmmod, and
that packets flow through xt2_do_table(). /usr/sbin/ip6tables cannot
interact with it yet as of this commit.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 9 +
include/linux/netfilter_ipv6/ip6_tables.h | 4 +
include/net/netns/x_tables.h | 2 +-
net/ipv6/netfilter/Kconfig | 1 +
net/ipv6/netfilter/ip6_tables.c | 30 ++--
net/ipv6/netfilter/ip6table_filter2.c | 23 ++-
net/netfilter/Kconfig | 6 +
net/netfilter/Makefile | 1 +
net/netfilter/x_tables.c | 3 +-
net/netfilter/xt1_postshared.c | 52 +++++
net/netfilter/xt1_support.c | 37 ++++
net/netfilter/xt1_translat.c | 290 +++++++++++++++++++++++++++++
12 files changed, 433 insertions(+), 25 deletions(-)
create mode 100644 net/netfilter/xt1_postshared.c
create mode 100644 net/netfilter/xt1_support.c
create mode 100644 net/netfilter/xt1_translat.c
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index a90b758..2adbae6 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -482,6 +482,8 @@ struct xt2_entry_target {
* @table: back link to table chain is contained in
* @comefrom: bitmask from which hooks the chain is entered
* (currently needed for xt_check_*)
+ * @xt1_offset: temporary field to hold the chain offset
+ * used during xt2->xt1 conversion (xt1_compat.c)
*/
struct xt2_chain {
struct list_head anchor;
@@ -489,6 +491,7 @@ struct xt2_chain {
char name[XT_EXTENSION_MAXNAMELEN];
struct xt2_table *table;
unsigned int comefrom;
+ unsigned int xt1_offset;
};
/**
@@ -512,6 +515,7 @@ enum {
* @chain_list: list of chains (struct xt2_chain)
* @name: name of this table
* @nfproto: nfproto the table is used exclusively with
+ * @valid_hooks: hooks the table can be entered on
* @rq_stacksize: Size of the jumpstack. This is usually set to the
* number of user chains -- since tables cannot have
* loops, at most that many jumps can possibly be made --
@@ -529,6 +533,7 @@ struct xt2_table {
struct list_head chain_list;
char name[11];
uint8_t nfproto;
+ unsigned int valid_hooks;
unsigned int rq_stacksize, stacksize;
unsigned int __percpu *stackptr;
@@ -692,11 +697,15 @@ static inline unsigned long ifname_compare_aligned(const char *_a,
extern struct nf_hook_ops *xt_hook_link(const struct xt_table *, nf_hookfn *);
extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
+extern struct xt2_chain *xts_lookup_chain(const struct xt2_table *,
+ unsigned int);
+
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
extern int xt2_rule_add_match(struct xt2_rule *, const char *, uint8_t,
const void *, unsigned int, bool);
extern int xt2_rule_add_target(struct xt2_rule *, const char *, uint8_t,
const void *, unsigned int, bool);
+extern void xt2_rule_free(struct xt2_rule *);
extern struct xt2_chain *xt2_chain_new(struct xt2_table *, const char *);
extern void xt2_chain_append(struct xt2_rule *);
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 18442ff..d1d5d3a 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -310,6 +310,10 @@ extern unsigned int ip6t_do_table(struct sk_buff *skb,
const struct net_device *out,
struct xt_table *table);
+extern struct xt2_table *ip6t2_register_table(struct net *,
+ const struct xt_table *,
+ const struct ip6t_replace *);
+
/* Check for an extension */
extern int ip6t_ext_hdr(u8 nexthdr);
/* find specified header and get offset to it */
diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
index 1e96a54..9365569 100644
--- a/include/net/netns/x_tables.h
+++ b/include/net/netns/x_tables.h
@@ -19,7 +19,7 @@ struct netns_xt {
struct netns_xt2 {
struct mutex table_lock;
struct list_head table_list[NFPROTO_NUMPROTO];
- struct xt_table *ipv6_filter;
+ struct xt2_table_link *ipv6_filter;
};
#endif
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 29d643b..46163b1 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -46,6 +46,7 @@ config IP6_NF_IPTABLES
tristate "IP6 tables support (required for filtering)"
depends on INET && IPV6
select NETFILTER_XTABLES
+ select NETFILTER_XT1_SUPPORT
default m if NETFILTER_ADVANCED=n
help
ip6tables is a general, extensible packet identification framework.
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 3b91f0a..d23f22a 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -63,6 +63,19 @@ MODULE_DESCRIPTION("IPv6 packet filter");
#define inline
#endif
+static int mark_source_chains(const struct xt_table_info *,
+ unsigned int, void *);
+
+#define xtsub_entry ip6t_entry
+#define xtsub_replace ip6t_replace
+#define xtsub_error_target ip6t_error_target
+#define XTSUB_NFPROTO_IPV6 1
+#define XTSUB(x) ip6t_ ## x
+#define XTSUB2(x) ip6t2_ ## x
+
+#include "../../netfilter/xt1_translat.c"
+#include "../../netfilter/xt1_postshared.c"
+
void *ip6t_alloc_initial_table(const struct xt_table *info)
{
return xt_alloc_initial_table(ip6t, IP6T);
@@ -828,21 +841,6 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
return ret;
}
-static bool check_underflow(const struct ip6t_entry *e)
-{
- const struct ip6t_entry_target *t;
- unsigned int verdict;
-
- if (!unconditional(&e->ipv6))
- return false;
- t = ip6t_get_target_c(e);
- if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
- return false;
- verdict = ((struct ip6t_standard_target *)t)->verdict;
- verdict = -verdict - 1;
- return verdict == NF_DROP || verdict == NF_ACCEPT;
-}
-
static int
check_entry_size_and_hooks(struct ip6t_entry *e,
struct xt_table_info *newinfo,
@@ -874,7 +872,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
if ((unsigned char *)e - base == hook_entries[h])
newinfo->hook_entry[h] = hook_entries[h];
if ((unsigned char *)e - base == underflows[h]) {
- if (!check_underflow(e)) {
+ if (!ip6t2_check_underflow(e)) {
pr_err("Underflows must be unconditional and "
"use the STANDARD target with "
"ACCEPT/DROP\n");
diff --git a/net/ipv6/netfilter/ip6table_filter2.c b/net/ipv6/netfilter/ip6table_filter2.c
index 55750e4..f81f98b 100644
--- a/net/ipv6/netfilter/ip6table_filter2.c
+++ b/net/ipv6/netfilter/ip6table_filter2.c
@@ -37,8 +37,14 @@ ip6table_filter_hook(unsigned int hook, struct sk_buff *skb,
int (*okfn)(struct sk_buff *))
{
const struct net *net = dev_net((in != NULL) ? in : out);
-
- return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter);
+ const struct xt2_table_link *link;
+ unsigned int verdict;
+
+ rcu_read_lock();
+ link = rcu_dereference(net->xt2.ipv6_filter);
+ verdict = xt2_do_table(skb, hook, in, out, link->table);
+ rcu_read_unlock();
+ return verdict;
}
static struct nf_hook_ops *filter_ops __read_mostly;
@@ -50,6 +56,7 @@ module_param(forward, bool, 0000);
static int __net_init ip6table_filter_net_init(struct net *net)
{
struct ip6t_replace *repl;
+ struct xt2_table *table;
repl = ip6t_alloc_initial_table(&packet_filter);
if (repl == NULL)
@@ -58,17 +65,19 @@ static int __net_init ip6table_filter_net_init(struct net *net)
((struct ip6t_standard *)repl->entries)[1].target.verdict =
-forward - 1;
- net->xt2.ipv6_filter =
- ip6t_register_table(net, &packet_filter, repl);
+ table = ip6t2_register_table(net, &packet_filter, repl);
kfree(repl);
- if (IS_ERR(net->xt2.ipv6_filter))
- return PTR_ERR(net->xt2.ipv6_filter);
+ if (IS_ERR(table))
+ return PTR_ERR(table);
+ net->xt2.ipv6_filter = xt2_tlink_lookup(net, table->name,
+ table->nfproto,
+ XT2_STD_RCULOCK);
return 0;
}
static void __net_exit ip6table_filter_net_exit(struct net *net)
{
- ip6t_unregister_table(net, net->xt2.ipv6_filter);
+ xt2_table_destroy(net, net->xt2.ipv6_filter->table);
}
static struct pernet_operations ip6table_filter_net_ops = {
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 21be535..4146464 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -314,6 +314,12 @@ config NETFILTER_XTABLES
if NETFILTER_XTABLES
+config NETFILTER_XT1_SUPPORT
+ tristate
+ select NETFILTER_XT_MATCH_QUOTA
+ ---help---
+ Protocol-agnostic part of the xt1 <-> xt2 translation layer.
+
comment "Xtables combined modules"
config NETFILTER_XT_MARK
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index e28420a..2449f3b 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
# generic X tables
obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
+obj-$(CONFIG_NETFILTER_XT1_SUPPORT) += xt1_support.o
# combos
obj-$(CONFIG_NETFILTER_XT_MARK) += xt_mark.o
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index f63587a..fcfa04e 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1424,7 +1424,7 @@ int xt2_rule_add_target(struct xt2_rule *rule, const char *ext_name,
}
EXPORT_SYMBOL_GPL(xt2_rule_add_target);
-static void xt2_rule_free(struct xt2_rule *rule)
+void xt2_rule_free(struct xt2_rule *rule)
{
struct xt2_entry_target *etarget, *next_etarget;
struct xt2_entry_match *ematch, *next_ematch;
@@ -1465,6 +1465,7 @@ static void xt2_rule_free(struct xt2_rule *rule)
}
kfree(rule);
}
+EXPORT_SYMBOL_GPL(xt2_rule_free);
struct xt2_chain *xt2_chain_new(struct xt2_table *table, const char *name)
{
diff --git a/net/netfilter/xt1_postshared.c b/net/netfilter/xt1_postshared.c
new file mode 100644
index 0000000..9fd5852
--- /dev/null
+++ b/net/netfilter/xt1_postshared.c
@@ -0,0 +1,52 @@
+/*
+ * xt1 <-> xt2 translation layer, per-nfproto specific part
+ * Copyright © Jan Engelhardt, 2009
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/netfilter.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+struct xt2_table *
+XTSUB2(register_table)(struct net *net, const struct xt_table *classic_table,
+ const struct xtsub_replace *repl)
+{
+ struct xt2_table *table;
+ void *blob;
+ int ret;
+
+ table = xt2_table_new();
+ if (table == NULL)
+ return ERR_PTR(-ENOMEM);
+ table->net = net;
+ /* Need a writable copy for check_entry_and_size_hooks. */
+ ret = -ENOMEM;
+ blob = vmalloc(repl->size);
+ if (blob == NULL)
+ goto out;
+ memcpy(blob, repl->entries, repl->size);
+ strncpy(table->name, classic_table->name, sizeof(table->name));
+ table->name[sizeof(table->name)-1] = '\0';
+ table->valid_hooks = classic_table->valid_hooks;
+ table->nfproto = classic_table->af;
+
+ ret = XTSUB2(table_to_xt2)(table, blob, repl);
+ vfree(blob);
+ if (ret < 0)
+ goto out;
+ ret = xt2_table_register(net, table);
+ if (ret < 0)
+ goto out;
+ return table;
+
+ out:
+ xt2_table_destroy(NULL, table);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(XTSUB2(register_table));
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
new file mode 100644
index 0000000..d15bfb7
--- /dev/null
+++ b/net/netfilter/xt1_support.c
@@ -0,0 +1,37 @@
+/*
+ * xt1 <-> xt2 translation layer, protocol independent parts
+ * Copyright © Jan Engelhardt, 2009
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/netfilter/x_tables.h>
+
+/**
+ * @table: table to search in
+ * @needle: rule offset in the xt1 blob
+ *
+ * Find the xt2 chain for a given xt1 offset. This assumes the chains are
+ * sorted by xt1_offset, which they should be given our linear translation
+ * mechanism in xt1_compat.c.
+ */
+struct xt2_chain *
+xts_lookup_chain(const struct xt2_table *table, unsigned int needle)
+{
+ struct xt2_chain *chain, *ret = NULL;
+
+ list_for_each_entry(chain, &table->chain_list, anchor) {
+ if (chain->xt1_offset <= needle)
+ ret = chain;
+ else
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xts_lookup_chain);
+
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
new file mode 100644
index 0000000..3d6892a
--- /dev/null
+++ b/net/netfilter/xt1_translat.c
@@ -0,0 +1,290 @@
+/*
+ * xt1 <-> xt2 translation layer, proto-format specific part
+ * Copyright © Jan Engelhardt, 2009
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/netfilter.h>
+#include <linux/slab.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_quota.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#if !defined(XTSUB_NFPROTO_IPV6)
+# error Need to define XTSUB_NFPROTO_xxx.
+#endif
+
+#ifdef XTSUB_NFPROTO_IPV6
+static const struct ip6t_ip6 xtsub_uncond;
+
+static inline bool XTSUB2(unconditional)(const struct xtsub_entry *e)
+{
+ return memcmp(&e->ipv6, &xtsub_uncond, sizeof(xtsub_uncond)) == 0;
+}
+#endif
+
+static inline struct xt_entry_target *
+XTSUB2(get_target)(const struct xtsub_entry *e)
+{
+ return (void *)e + e->target_offset;
+}
+
+static bool XTSUB2(check_underflow)(const struct xtsub_entry *e)
+{
+ const struct xt_entry_target *t;
+ unsigned int verdict;
+
+ if (!XTSUB2(unconditional)(e))
+ return false;
+ t = XTSUB2(get_target)(e);
+ if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
+ return false;
+ verdict = ((struct xt_standard_target *)t)->verdict;
+ verdict = -verdict - 1;
+ return verdict == NF_DROP || verdict == NF_ACCEPT;
+}
+
+/**
+ * Check an xt1 entry for sanity and create chains as we find them.
+ */
+static int
+XTSUB2(rule_check)(struct xtsub_entry *e, struct xt2_table *table,
+ const void *base, const struct xtsub_replace *repl)
+{
+ const void *limit = (void *)base + repl->size;
+ unsigned int delta = (void *)e - base;
+ struct xtsub_error_target *t;
+ struct xt2_chain *chain;
+ unsigned int hook;
+
+ if ((unsigned long)e % __alignof__(struct xtsub_entry) != 0 ||
+ (void *)e + sizeof(struct xtsub_entry) >= limit ||
+ e->next_offset < sizeof(struct xtsub_entry) +
+ sizeof(struct xt_entry_target))
+ return -EINVAL;
+
+ /* Check hooks & underflows */
+ for (hook = 0; hook < ARRAY_SIZE(repl->hook_entry); ++hook) {
+ if (!(repl->valid_hooks & (1 << hook)))
+ continue;
+ if (delta == repl->hook_entry[hook]) {
+ chain = xt2_chain_new(table, NULL);
+ if (chain == NULL)
+ return -ENOMEM;
+
+ table->entrypoint[hook] = chain;
+ chain->comefrom = e->comefrom;
+ /* Aid for finding chains for a given delta. */
+ chain->xt1_offset = delta;
+ }
+ if (delta == repl->underflow[hook] &&
+ !XTSUB2(check_underflow)(e)) {
+ pr_err("Underflows must be unconditional and use the "
+ "STANDARD target with ACCEPT/DROP\n");
+ return -EINVAL;
+ }
+ }
+
+ /* Clear counters and comefrom */
+ memset(&e->counters, 0, sizeof(e->counters));
+ e->comefrom = 0;
+
+ t = (void *)XTSUB2(get_target)(e);
+ if (strcmp(t->target.u.user.name, XT_ERROR_TARGET) == 0) {
+ t->errorname[sizeof(t->errorname)-1] = '\0';
+ if (strcmp(t->errorname, XT_ERROR_TARGET) == 0)
+ /* End of ruleset */
+ return 0;
+ chain = xt2_chain_new(table, t->errorname);
+ if (chain == NULL)
+ return -ENOMEM;
+ chain->xt1_offset = delta;
+ /* Chain marker translated. */
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+XTSUB2(target_to_xt2)(struct xt2_rule *rule, const struct xtsub_entry *entry,
+ unsigned int entry_offset)
+{
+ const struct xt_entry_target *etarget = XTSUB2(get_target)(entry);
+ const struct xt_standard_target *st;
+ struct xt2_entry_target *ntarget;
+
+ if (strcmp(etarget->u.user.name, XT_STANDARD_TARGET) != 0)
+ return xt2_rule_add_oldtarget(rule, etarget);
+
+ ntarget = kmalloc(sizeof(*ntarget), GFP_KERNEL);
+ if (ntarget == NULL)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&ntarget->anchor);
+
+ st = (void *)etarget;
+ if (st->verdict == XT_RETURN) {
+ ntarget->ext = XT2_FINAL_VERDICT;
+ ntarget->verdict = XT_RETURN;
+ } else if (st->verdict < 0) {
+ ntarget->ext = XT2_FINAL_VERDICT;
+ ntarget->verdict = -st->verdict - 1;
+ } else if (st->verdict == entry_offset + entry->next_offset) {
+ ntarget->ext = XT2_FINAL_VERDICT;
+ ntarget->verdict = XT_CONTINUE;
+#ifdef XTSUB_NFPROTO_IPV6
+ } else if (entry->ipv6.flags & IP6T_F_GOTO) {
+ ntarget->ext = XT2_ACTION_GOTO;
+ ntarget->r_goto = xts_lookup_chain(rule->chain->table,
+ st->verdict);
+ /* debug: (we already checked loopfreeness before) */
+ if (ntarget->r_goto == rule->chain)
+ return -ELOOP;
+#endif
+ } else {
+ ntarget->ext = XT2_ACTION_JUMP;
+ ntarget->r_jump = xts_lookup_chain(rule->chain->table,
+ st->verdict);
+ if (ntarget->r_jump == rule->chain)
+ return -ELOOP;
+ }
+
+ list_add_tail(&ntarget->anchor, &rule->target_list);
+ return 0;
+}
+
+/**
+ * Translate a single ip6t_entry into a xt2 rule.
+ */
+static struct xt2_rule *
+XTSUB2(rule_to_xt2)(struct xt2_chain *chain, const struct xtsub_entry *entry,
+ unsigned int entry_offset)
+{
+ const struct xt_entry_match *ematch;
+ struct xt_quota_mtinfo3 byte_counter = {.flags = XT_QUOTA_GROW};
+ struct xt_quota_mtinfo3 packet_counter =
+ {.flags = XT_QUOTA_GROW | XT_QUOTA_PACKET};
+ struct xt2_rule *rule;
+ int ret;
+
+ rule = xt2_rule_new(chain);
+ if (rule == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ rule->chain->comefrom = entry->comefrom;
+#ifdef XTSUB_NFPROTO_IPV6
+ rule->l4proto = entry->ipv6.proto;
+ if (entry->ipv6.flags & IP6T_INV_PROTO)
+ rule->flags |= XT2_INV_L4PROTO;
+ ret = xt2_rule_add_match(rule, "ipv6", 0, &entry->ipv6,
+ sizeof(entry->ipv6), false);
+#endif
+ if (ret < 0)
+ goto out;
+
+ xt_ematch_foreach(ematch, entry) {
+ ret = xt2_rule_add_oldmatch(rule, ematch);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = xt2_rule_add_match(rule, "quota", 3, &byte_counter,
+ sizeof(byte_counter), false);
+ if (ret < 0)
+ goto out;
+ ret = xt2_rule_add_match(rule, "quota", 3, &packet_counter,
+ sizeof(packet_counter), false);
+ if (ret < 0)
+ goto out;
+ ret = XTSUB2(target_to_xt2)(rule, entry, entry_offset);
+ if (ret < 0)
+ goto out;
+ return rule;
+
+ out:
+ xt2_rule_free(rule);
+ return ERR_PTR(ret);
+}
+
+/**
+ * @table: new table
+ * @entry0: blob of <struct ip6t_entry>s
+ * @repl: blob metadata
+ *
+ * Convert a blob table into a xt2 table.
+ */
+static int XTSUB2(table_to_xt2)(struct xt2_table *table, void *entry0,
+ const struct xtsub_replace *repl)
+{
+ struct xt_table_info mark_param;
+ struct xtsub_entry *iter;
+ unsigned int i;
+ int ret = 0;
+
+ i = 0;
+ /* Walk through entries, checking offsets, creating chains. */
+ xt_entry_foreach(iter, entry0, repl->size) {
+ ret = XTSUB2(rule_check)(iter, table, entry0, repl);
+ ++i;
+ if (ret < 0)
+ return ret;
+ else if (ret == 0)
+ continue;
+ }
+
+ if (i != repl->num_entries)
+ return -EINVAL;
+
+ /* Check hooks all assigned */
+ for (i = 0; i < ARRAY_SIZE(repl->hook_entry); ++i) {
+ /* Only hooks which are valid */
+ if (!(repl->valid_hooks & (1 << i)))
+ continue;
+ if (table->entrypoint[i] == NULL)
+ return -EINVAL;
+ }
+
+ memcpy(mark_param.hook_entry, repl->hook_entry,
+ sizeof(repl->hook_entry));
+ mark_param.size = repl->size;
+ if (!mark_source_chains(&mark_param, repl->valid_hooks, entry0))
+ return -ELOOP;
+
+ /* Now process rules. */
+ xt_entry_foreach(iter, entry0, repl->size) {
+ unsigned int hook, delta = (void *)iter - (void *)entry0;
+ const struct xt_entry_target *t;
+ struct xt2_chain *chain;
+ struct xt2_rule *rule;
+
+ t = XTSUB2(get_target)(iter);
+ if (strcmp(t->u.user.name, XT_ERROR_TARGET) == 0)
+ /* already translated */
+ continue;
+ /*
+ * Do not ignore base chain policies (which are rules), though.
+ * We need these for the counters.
+ */
+ chain = xts_lookup_chain(table, delta);
+ if (chain == NULL)
+ return -EINVAL;
+ rule = XTSUB2(rule_to_xt2)(chain, iter, delta);
+ if (IS_ERR(rule))
+ return PTR_ERR(rule);
+ xt2_chain_append(rule);
+
+ for (hook = 0; hook < ARRAY_SIZE(repl->underflow); ++hook) {
+ if (!(table->valid_hooks & (1 << hook)))
+ continue;
+ if (delta == repl->underflow[hook]) {
+ table->underflow[hook] = rule;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 18/56] netfilter: xtables2: xt2->xt1 translation - GET_INFO support
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (16 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 17/56] netfilter: xtables2: initial xt1->xt2 translation for tables Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:42 ` [PATCH 19/56] netfilter: xtables2: xt2->xt1 translation - GET_ENTRIES support Jan Engelhardt
` (16 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Part 1 of the backwards translation. Calculates size and
hook_entry/underflow points.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 29 ++++++++
net/ipv6/netfilter/ip6_tables.c | 42 ++++++++++++-
net/netfilter/xt1_support.c | 124 ++++++++++++++++++++++++++++++++++++
3 files changed, 193 insertions(+), 2 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 2adbae6..9e9876f 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -411,6 +411,26 @@ struct xt_table_info {
void *entries[1];
};
+/**
+ * xt1 size definitions
+ *
+ * @marker_size: size of a user-chain and end-of-ruleset marker
+ * @entry_hdr_size: size of struct ip6t_entry
+ * @pmatch_size: size of struct ip6t_ip6
+ * @first_match: required name of the first match
+ * @ematch_size: size of the ematch header
+ * @etarget_size: size of the etarget header
+ * @standard_tgsize: size of the complete standard target, includes
+ * etarget_size and alignment padding
+ */
+struct xt1_xlat_info {
+ unsigned int marker_size;
+ unsigned int entry_hdr_size, pmatch_size;
+ unsigned int ematch_size, etarget_size;
+ unsigned int standard_tgsize;
+ const char *first_match;
+};
+
/*
* The use of low negative numbers means we can use IS_ERR()
* (See xt2_special_target below.)
@@ -699,6 +719,10 @@ extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
extern struct xt2_chain *xts_lookup_chain(const struct xt2_table *,
unsigned int);
+extern unsigned int xts_blob_prep_table(const struct xt2_table *,
+ const struct xt1_xlat_info *,
+ unsigned int *, unsigned int *,
+ unsigned int *);
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
extern int xt2_rule_add_match(struct xt2_rule *, const char *, uint8_t,
@@ -722,6 +746,11 @@ extern unsigned int xt2_do_table(struct sk_buff *, unsigned int,
const struct net_device *,
const struct xt2_table *);
+static inline bool xt2_builtin_chain(const struct xt2_chain *c)
+{
+ return *c->name == '\0';
+}
+
static inline bool xt2_special_target(const struct xt_target *t)
{
/*
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index d23f22a..d2d34b0 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1187,10 +1187,37 @@ static int compat_table_info(const struct xt_table_info *info,
}
#endif
+static const struct xt1_xlat_info ip6t_xlat_info = {
+ .marker_size = sizeof(struct ip6t_error_target),
+ .entry_hdr_size = sizeof(struct ip6t_entry),
+ .pmatch_size = sizeof(struct ip6t_ip6),
+ .first_match = "ipv6",
+ .ematch_size = sizeof(struct xt_entry_match),
+ .etarget_size = sizeof(struct xt_entry_target),
+ .standard_tgsize = XT_ALIGN(sizeof(struct xt_entry_target) +
+ sizeof(int)),
+};
+
+static int ip6t2_get_info(void __user *uptr, int len,
+ const struct xt2_table *table)
+{
+ struct ip6t_getinfo info = {
+ .valid_hooks = table->valid_hooks,
+ };
+
+ strncpy(info.name, table->name,
+ min(sizeof(info.name), sizeof(table->name)));
+ info.size = xts_blob_prep_table(table, &ip6t_xlat_info,
+ info.hook_entry, info.underflow,
+ &info.num_entries);
+ return (copy_to_user(uptr, &info, sizeof(info)) != 0) ? -EFAULT : 0;
+}
+
static int get_info(struct net *net, void __user *user,
const int *len, int compat)
{
char name[IP6T_TABLE_MAXNAMELEN];
+ struct xt2_table *xt2_table;
struct xt_table *t;
int ret;
@@ -1204,12 +1231,23 @@ static int get_info(struct net *net, void __user *user,
return -EFAULT;
name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
+ t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
+ "ip6table_%s", name);
+ xt2_table = xt2_table_lookup(net, name, NFPROTO_IPV6,
+ XT2_KEEP_RCULOCK);
+ if (xt2_table != NULL) {
+ ret = ip6t2_get_info(user, *len, xt2_table);
+ rcu_read_unlock();
+ if (t != NULL)
+ module_put(t->me);
+ return ret;
+ }
+ rcu_read_unlock();
+
#ifdef CONFIG_COMPAT
if (compat)
xt_compat_lock(AF_INET6);
#endif
- t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
- "ip6table_%s", name);
if (t && !IS_ERR(t)) {
struct ip6t_getinfo info;
const struct xt_table_info *private = t->private;
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
index d15bfb7..4b13f2f 100644
--- a/net/netfilter/xt1_support.c
+++ b/net/netfilter/xt1_support.c
@@ -7,7 +7,9 @@
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*/
+#include <linux/list.h>
#include <linux/module.h>
+#include <linux/rcupdate.h>
#include <linux/netfilter/x_tables.h>
/**
@@ -34,4 +36,126 @@ xts_lookup_chain(const struct xt2_table *table, unsigned int needle)
}
EXPORT_SYMBOL_GPL(xts_lookup_chain);
+/**
+ * get pointer to quota ematches
+ *
+ * Also used for the xt2->xt1 converter. Generalized matches run until the two
+ * last quota matches.
+ */
+static const struct xt2_entry_match *
+xts_rule_quota_ptr(const struct xt2_rule *rule)
+{
+ const struct xt2_entry_match *ematch;
+
+ /* Need at least two ematches */
+ if (list_empty(&rule->match_list) ||
+ rule->match_list.next->next == &rule->match_list)
+ return NULL;
+
+ /* Now need exactly two trailing quota matches */
+ ematch = list_entry(rule->match_list.prev, typeof(*ematch), anchor);
+ if (strcmp(ematch->ext->name, "quota") != 0 &&
+ ematch->ext->revision != 3)
+ return NULL;
+ ematch = list_entry(ematch->anchor.prev, typeof(*ematch), anchor);
+ if (strcmp(ematch->ext->name, "quota") != 0 &&
+ ematch->ext->revision != 3)
+ return NULL;
+ return ematch;
+}
+
+static int
+xts_blob_prep_rule(const struct xt2_rule *rule, const struct xt1_xlat_info *io,
+ unsigned int *underflow, unsigned int z)
+{
+ const struct xt2_table *table = rule->chain->table;
+ const struct xt2_entry_match *ematch, *quota_stop;
+ const struct xt2_entry_target *etarget;
+ unsigned int h;
+
+ /* Quota check implies ematch list empty check. */
+ quota_stop = xts_rule_quota_ptr(rule);
+ if (quota_stop == NULL)
+ return -EIO;
+
+ /* Must have exactly one target */
+ if (list_empty(&rule->target_list) ||
+ rule->target_list.next->next != &rule->target_list)
+ return -EIO;
+
+ ematch = list_first_entry(&rule->match_list,
+ typeof(*ematch), anchor);
+ if (strcmp(ematch->ext->name, io->first_match) != 0)
+ return -EIO;
+
+ /* Do underflow assign first before @z is increased. */
+ for (h = 0; h < ARRAY_SIZE(table->underflow); ++h)
+ if (rule == table->underflow[h])
+ underflow[h] = z;
+
+ /* Subtracting, because it will already be added in the loop. */
+ z += io->entry_hdr_size - io->ematch_size - io->pmatch_size;
+
+ list_for_each_entry(ematch, &rule->match_list, anchor) {
+ if (ematch == quota_stop)
+ /* quotas included in entry_hdr */
+ break;
+ z += io->ematch_size + ematch->dsize;
+ }
+
+ etarget = list_first_entry(&rule->target_list,
+ typeof(*etarget), anchor);
+ z += xt2_special_target(etarget->ext) ? io->standard_tgsize :
+ io->etarget_size +
+ XT_ALIGN(etarget->ext->targetsize);
+ return z;
+}
+
+/**
+ * - calculate details for GETINFO ioctl from xt2 table
+ * @table: the xt2 table
+ * @io: info block on blob's field sizes
+ *
+ * Calculate the details for a GETINFO ioctl from the supplied xt2 table.
+ * Returns -1 if the table cannot be converted to an xt1 blob without
+ * loss of information.
+ */
+unsigned int
+xts_blob_prep_table(const struct xt2_table *table,
+ const struct xt1_xlat_info *io,
+ unsigned int *hook_entry, unsigned int *underflow,
+ unsigned int *entries_ptr)
+{
+ const struct xt2_chain *chain;
+ const struct xt2_rule *rule;
+ unsigned int hook, entries = 0;
+ int z = 0;
+
+ rcu_read_lock();
+ list_for_each_entry(chain, &table->chain_list, anchor) {
+ for (hook = 0; hook < ARRAY_SIZE(table->entrypoint); ++hook)
+ if (table->entrypoint[hook] == chain)
+ hook_entry[hook] = z;
+
+ if (!xt2_builtin_chain(chain)) {
+ z += io->entry_hdr_size + io->marker_size;
+ ++entries;
+ }
+
+ list_for_each_entry(rule, &chain->rule_list, anchor) {
+ ++entries;
+ z = xts_blob_prep_rule(rule, io, underflow, z);
+ if (z < 0)
+ return z;
+ }
+ }
+ rcu_read_unlock();
+
+ /* Table terminator */
+ z += io->entry_hdr_size + io->marker_size;
+ *entries_ptr = ++entries;
+ return z;
+}
+EXPORT_SYMBOL_GPL(xts_blob_prep_table);
+
MODULE_LICENSE("GPL");
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 19/56] netfilter: xtables2: xt2->xt1 translation - GET_ENTRIES support
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (17 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 18/56] netfilter: xtables2: xt2->xt1 translation - GET_INFO support Jan Engelhardt
@ 2010-06-29 8:42 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 20/56] netfilter: xtables2: xt1->xt2 translation - SET_REPLACE support Jan Engelhardt
` (15 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:42 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
With this, `ip6tables -L` can display xt2 tables (if they are
representable in the old format, otherwise returns -EIO).
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 38 +++++++++-
include/linux/netfilter/xt_quota.h | 11 +++
net/ipv6/netfilter/ip6_tables.c | 13 +++-
net/netfilter/x_tables.c | 1 +
net/netfilter/xt1_support.c | 106 +++++++++++++++++++++++---
net/netfilter/xt1_translat.c | 146 ++++++++++++++++++++++++++++++++++++
net/netfilter/xt_quota.c | 9 --
7 files changed, 301 insertions(+), 23 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 9e9876f..3d33a06 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -548,6 +548,7 @@ enum {
* @underflow: base chain policy (rule)
* @net: encompassing netns. To be set by xt2_table_new caller.
* @owner: encompassing module
+ * @xt1_lock: lock for updating chains' xt1_offset
*/
struct xt2_table {
struct list_head chain_list;
@@ -563,6 +564,8 @@ struct xt2_table {
const struct xt2_rule *underflow[NF_INET_NUMHOOKS];
struct net *net;
struct module *owner;
+
+ struct mutex xt1_lock;
};
/**
@@ -719,10 +722,19 @@ extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
extern struct xt2_chain *xts_lookup_chain(const struct xt2_table *,
unsigned int);
-extern unsigned int xts_blob_prep_table(const struct xt2_table *,
+extern const struct xt2_entry_match *
+xts_rule_quota_ptr(const struct xt2_rule *);
+extern void xts_rule_get_quota(const struct xt2_entry_match *,
+ uint64_t *, uint64_t *);
+extern unsigned int xts_blob_prep_table(struct xt2_table *,
const struct xt1_xlat_info *,
unsigned int *, unsigned int *,
unsigned int *);
+extern int xts_starget_to_xt1(void __user **, int *, unsigned int *,
+ const struct xt2_entry_target *,
+ const struct xt1_xlat_info *);
+extern int xts_target_to_xt1(void __user **, int *, unsigned int *,
+ const struct xt2_entry_target *);
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
extern int xt2_rule_add_match(struct xt2_rule *, const char *, uint8_t,
@@ -746,6 +758,30 @@ extern unsigned int xt2_do_table(struct sk_buff *, unsigned int,
const struct net_device *,
const struct xt2_table *);
+/**
+ * @pptr: user pointer
+ * @rem: remaining bytes in user area
+ * @data: source data
+ * @dsize: size of @data
+ * @z: bytes written so far
+ *
+ * Copy @data to userspace, advance pointer and offset,
+ * reduce remaining counter.
+ */
+static inline int
+xts_copy_to_user(void __user **pptr, int *rem, const void *data,
+ unsigned int dsize, unsigned int *z)
+{
+ if (*rem < dsize)
+ return -ENOSPC;
+ if (copy_to_user(*pptr, data, dsize) != 0)
+ return -EFAULT;
+ *pptr += dsize;
+ *z += dsize;
+ *rem -= dsize;
+ return 0;
+}
+
static inline bool xt2_builtin_chain(const struct xt2_chain *c)
{
return *c->name == '\0';
diff --git a/include/linux/netfilter/xt_quota.h b/include/linux/netfilter/xt_quota.h
index f14e36d..7538cd2 100644
--- a/include/linux/netfilter/xt_quota.h
+++ b/include/linux/netfilter/xt_quota.h
@@ -32,4 +32,15 @@ struct xt_quota_mtinfo3 {
struct xt_quota_counter *master __attribute__((aligned(8)));
};
+#ifdef __KERNEL__
+struct xt_quota_counter {
+ u_int64_t quota;
+ spinlock_t lock;
+ struct list_head list;
+ atomic_t ref;
+ char name[sizeof(((struct xt_quota_mtinfo3 *)NULL)->name)];
+ struct proc_dir_entry *procfs_entry;
+};
+#endif
+
#endif /* _XT_QUOTA_H */
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index d2d34b0..ddc0313 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1199,7 +1199,7 @@ static const struct xt1_xlat_info ip6t_xlat_info = {
};
static int ip6t2_get_info(void __user *uptr, int len,
- const struct xt2_table *table)
+ struct xt2_table *table)
{
struct ip6t_getinfo info = {
.valid_hooks = table->valid_hooks,
@@ -1291,6 +1291,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
{
int ret;
struct ip6t_get_entries get;
+ struct xt2_table *xt2_table;
struct xt_table *t;
if (*len < sizeof(get)) {
@@ -1305,6 +1306,16 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
return -EINVAL;
}
+ xt2_table = xt2_table_lookup(net, get.name, NFPROTO_IPV6,
+ XT2_KEEP_RCULOCK);
+ if (xt2_table != NULL) {
+ ret = ip6t2_table_to_xt1(uptr->entrytable, get.size,
+ xt2_table, &ip6t_xlat_info);
+ rcu_read_unlock();
+ return ret;
+ }
+ rcu_read_unlock();
+
t = xt_find_table_lock(net, AF_INET6, get.name);
if (t && !IS_ERR(t)) {
struct xt_table_info *private = t->private;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index fcfa04e..f4794db 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1583,6 +1583,7 @@ struct xt2_table *xt2_table_new(void)
return NULL;
INIT_LIST_HEAD(&table->chain_list);
+ mutex_init(&table->xt1_lock);
return table;
}
EXPORT_SYMBOL_GPL(xt2_table_new);
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
index 4b13f2f..af58cff 100644
--- a/net/netfilter/xt1_support.c
+++ b/net/netfilter/xt1_support.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/rcupdate.h>
#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_quota.h>
/**
* @table: table to search in
@@ -42,7 +43,7 @@ EXPORT_SYMBOL_GPL(xts_lookup_chain);
* Also used for the xt2->xt1 converter. Generalized matches run until the two
* last quota matches.
*/
-static const struct xt2_entry_match *
+const struct xt2_entry_match *
xts_rule_quota_ptr(const struct xt2_rule *rule)
{
const struct xt2_entry_match *ematch;
@@ -63,6 +64,29 @@ xts_rule_quota_ptr(const struct xt2_rule *rule)
return NULL;
return ematch;
}
+EXPORT_SYMBOL_GPL(xts_rule_quota_ptr);
+
+/**
+ * @ematch: pointer to appropriate quota ematch (obtained from
+ * xt1_rule_quota_ptr)
+ */
+void xts_rule_get_quota(const struct xt2_entry_match *ematch,
+ uint64_t *bytes, uint64_t *pkts)
+{
+ const struct xt_quota_mtinfo3 *q;
+
+ /* Bytes */
+ q = ematch->data;
+ spin_lock_bh(&q->master->lock);
+ *bytes = q->master->quota;
+ spin_unlock_bh(&q->master->lock);
+ /* Packets */
+ q = list_entry(ematch->anchor.next, typeof(*ematch), anchor)->data;
+ spin_lock_bh(&q->master->lock);
+ *pkts = q->master->quota;
+ spin_unlock_bh(&q->master->lock);
+}
+EXPORT_SYMBOL_GPL(xts_rule_get_quota);
static int
xts_blob_prep_rule(const struct xt2_rule *rule, const struct xt1_xlat_info *io,
@@ -89,9 +113,10 @@ xts_blob_prep_rule(const struct xt2_rule *rule, const struct xt1_xlat_info *io,
return -EIO;
/* Do underflow assign first before @z is increased. */
- for (h = 0; h < ARRAY_SIZE(table->underflow); ++h)
- if (rule == table->underflow[h])
- underflow[h] = z;
+ if (underflow != NULL)
+ for (h = 0; h < ARRAY_SIZE(table->underflow); ++h)
+ if (rule == table->underflow[h])
+ underflow[h] = z;
/* Subtracting, because it will already be added in the loop. */
z += io->entry_hdr_size - io->ematch_size - io->pmatch_size;
@@ -121,22 +146,25 @@ xts_blob_prep_rule(const struct xt2_rule *rule, const struct xt1_xlat_info *io,
* loss of information.
*/
unsigned int
-xts_blob_prep_table(const struct xt2_table *table,
- const struct xt1_xlat_info *io,
+xts_blob_prep_table(struct xt2_table *table, const struct xt1_xlat_info *io,
unsigned int *hook_entry, unsigned int *underflow,
unsigned int *entries_ptr)
{
- const struct xt2_chain *chain;
+ struct xt2_chain *chain;
const struct xt2_rule *rule;
unsigned int hook, entries = 0;
int z = 0;
rcu_read_lock();
list_for_each_entry(chain, &table->chain_list, anchor) {
- for (hook = 0; hook < ARRAY_SIZE(table->entrypoint); ++hook)
- if (table->entrypoint[hook] == chain)
- hook_entry[hook] = z;
-
+ if (hook_entry != NULL)
+ for (hook = 0; hook < ARRAY_SIZE(table->entrypoint);
+ ++hook)
+ if (table->entrypoint[hook] == chain)
+ hook_entry[hook] = z;
+
+ /* Caller needs to take xt1_lock if xt1_offset is needed. */
+ chain->xt1_offset = z;
if (!xt2_builtin_chain(chain)) {
z += io->entry_hdr_size + io->marker_size;
++entries;
@@ -153,9 +181,63 @@ xts_blob_prep_table(const struct xt2_table *table,
/* Table terminator */
z += io->entry_hdr_size + io->marker_size;
- *entries_ptr = ++entries;
+ if (entries_ptr != NULL)
+ *entries_ptr = ++entries;
return z;
}
EXPORT_SYMBOL_GPL(xts_blob_prep_table);
+int xts_starget_to_xt1(void __user **user_ptr, int *len, unsigned int *z,
+ const struct xt2_entry_target *etarget,
+ const struct xt1_xlat_info *io)
+{
+ struct xt_standard_target blob = {
+ .target.u.user = {
+ .target_size = io->standard_tgsize,
+ .revision = 0,
+ },
+ };
+
+ strncpy(blob.target.u.user.name, XT_STANDARD_TARGET,
+ sizeof(blob.target.u.user.name));
+ if (etarget->ext == XT2_FINAL_VERDICT) {
+ if (etarget->verdict == XT_CONTINUE)
+ blob.verdict = *z + io->standard_tgsize;
+ else if (etarget->verdict == XT_RETURN)
+ blob.verdict = XT_RETURN;
+ else
+ blob.verdict = -etarget->verdict - 1;
+ } else if (etarget->ext == XT2_ACTION_GOTO) {
+ blob.verdict = etarget->r_goto->xt1_offset;
+ } else if (etarget->ext == XT2_ACTION_JUMP) {
+ blob.verdict = etarget->r_jump->xt1_offset;
+ } else {
+ return -EIO;
+ }
+ return xts_copy_to_user(user_ptr, len, &blob, io->standard_tgsize, z);
+}
+EXPORT_SYMBOL_GPL(xts_starget_to_xt1);
+
+int xts_target_to_xt1(void __user **user_ptr, int *len, unsigned int *z,
+ const struct xt2_entry_target *etarget)
+{
+ int ret;
+ struct xt_entry_target blob = {
+ .u.user = {
+ .target_size = sizeof(blob) +
+ XT_ALIGN(etarget->ext->targetsize),
+ .revision = etarget->ext->revision,
+ },
+ };
+
+ strncpy(blob.u.user.name, etarget->ext->name,
+ sizeof(blob.u.user.name));
+ ret = xts_copy_to_user(user_ptr, len, &blob, sizeof(blob), z);
+ if (ret < 0)
+ return ret;
+ return xts_copy_to_user(user_ptr, len, etarget->data,
+ XT_ALIGN(etarget->ext->targetsize), z);
+}
+EXPORT_SYMBOL_GPL(xts_target_to_xt1);
+
MODULE_LICENSE("GPL");
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
index 3d6892a..bff55fc 100644
--- a/net/netfilter/xt1_translat.c
+++ b/net/netfilter/xt1_translat.c
@@ -288,3 +288,149 @@ static int XTSUB2(table_to_xt2)(struct xt2_table *table, void *entry0,
return 0;
}
+
+static int
+XTSUB2(marker_to_xt1)(void __user **user_pptr, int *len,
+ const struct xt2_chain *chain, unsigned int *z)
+{
+ /*
+ * Must write structs separately, or otherwise there is padding between
+ * (compat_)xtsub_entry and xtsub_error_target.
+ */
+ struct xtsub_error_target target = {
+ .target.u.user = {
+ .target_size = sizeof(target),
+ .name = "ERROR",
+ .revision = 0,
+ },
+ };
+ struct xtsub_entry entry = {
+ .target_offset = sizeof(entry),
+ .next_offset = sizeof(entry) + sizeof(target),
+ };
+ int ret;
+
+ strncpy(target.errorname, chain->name,
+ min(sizeof(target.errorname), sizeof(chain->name)));
+ ret = xts_copy_to_user(user_pptr, len, &entry, sizeof(entry), z);
+ if (ret < 0)
+ return ret;
+ return xts_copy_to_user(user_pptr, len, &target, sizeof(target), z);
+}
+
+static int
+XTSUB2(rule_to_xt1)(void __user **user_ptr, int *len, unsigned int *z,
+ const struct xt2_rule *rule,
+ const struct xt1_xlat_info *io)
+{
+ const struct xt2_entry_match *ematch, *quota_ematch;
+ const struct xt2_entry_target *etarget;
+ struct xtsub_entry entry;
+ void __user *entry_uptr;
+ unsigned int z_start;
+ int ret;
+
+ quota_ematch = xts_rule_quota_ptr(rule);
+ if (quota_ematch == NULL)
+ return -EIO;
+
+ /* Must have exactly one target */
+ if (list_empty(&rule->target_list) ||
+ rule->target_list.next->next != &rule->target_list)
+ return -EIO;
+
+ /* Entry master */
+ z_start = *z;
+ ematch = list_first_entry(&rule->match_list, typeof(*ematch), anchor);
+#ifdef XTSUB_NFPROTO_IPV6
+ if (strcmp(ematch->ext->name, "ipv6") != 0)
+ return -EIO;
+ memcpy(&entry.ipv6, ematch->data, sizeof(entry.ipv6));
+#endif
+ entry.comefrom = rule->chain->comefrom;
+ entry.nfcache = 0;
+ xts_rule_get_quota(quota_ematch, &entry.counters.bcnt,
+ &entry.counters.pcnt);
+
+ /* Remember offset for entry header for later update of offsets. */
+ entry_uptr = *user_ptr;
+ ret = xts_copy_to_user(user_ptr, len, &entry, sizeof(entry), z);
+ if (ret < 0)
+ return ret;
+
+ list_for_each_entry_continue(ematch, &rule->match_list, anchor) {
+ struct xt_entry_match blob;
+
+ if (ematch == quota_ematch)
+ break;
+
+ blob.u.match_size = sizeof(blob) + ematch->dsize;
+ blob.u.user.revision = ematch->ext->revision;
+ strncpy(blob.u.user.name, ematch->ext->name,
+ sizeof(blob.u.user.name));
+ ret = xts_copy_to_user(user_ptr, len, &blob, sizeof(blob), z);
+ if (ret < 0)
+ return ret;
+ ret = xts_copy_to_user(user_ptr, len, ematch->data,
+ ematch->dsize, z);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* target and next offsets are relative to the start of the entry. */
+ entry.target_offset = *z - z_start;
+
+ list_for_each_entry(etarget, &rule->target_list, anchor) {
+ ret = xt2_special_target(etarget->ext) ?
+ xts_starget_to_xt1(user_ptr, len, z, etarget, io) :
+ xts_target_to_xt1(user_ptr, len, z, etarget);
+ if (ret < 0)
+ return ret;
+ }
+
+ entry.next_offset = *z - z_start;
+ return copy_to_user(entry_uptr, &entry, sizeof(entry));
+}
+
+static int
+XTSUB2(table_to_xt1)(void __user *user_ptr, int len, struct xt2_table *table,
+ const struct xt1_xlat_info *io)
+{
+ static const struct xt2_chain terminator = {.name = "ERROR"};
+ static const uint32_t filler = ~0U;
+ const struct xt2_rule *rule;
+ struct xt2_chain *chain;
+ unsigned int z = 0;
+ int i, ret;
+
+ for (i = 0; i <= len - sizeof(filler); i += sizeof(filler))
+ if (copy_to_user(user_ptr + i, &filler, sizeof(filler)))
+ return -EFAULT;
+
+ ret = mutex_lock_interruptible(&table->xt1_lock);
+ if (ret < 0)
+ return ret;
+
+ /* Calculate chain offsets. */
+ xts_blob_prep_table(table, io, NULL, NULL, NULL);
+
+ list_for_each_entry(chain, &table->chain_list, anchor) {
+ if (!xt2_builtin_chain(chain)) {
+ ret = XTSUB2(marker_to_xt1)(&user_ptr,
+ &len, chain, &z);
+ if (ret < 0)
+ goto out;
+ }
+ list_for_each_entry(rule, &chain->rule_list, anchor) {
+ ret = XTSUB2(rule_to_xt1)(&user_ptr, &len, &z,
+ rule, io);
+ if (ret < 0)
+ goto out;
+ }
+ }
+
+ ret = XTSUB2(marker_to_xt1)(&user_ptr, &len, &terminator, &z);
+ out:
+ mutex_unlock(&table->xt1_lock);
+ return ret;
+}
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
index d62b35d..d82e287 100644
--- a/net/netfilter/xt_quota.c
+++ b/net/netfilter/xt_quota.c
@@ -17,15 +17,6 @@ struct xt_quota_priv {
uint64_t quota;
};
-struct xt_quota_counter {
- u_int64_t quota;
- spinlock_t lock;
- struct list_head list;
- atomic_t ref;
- char name[sizeof(((struct xt_quota_mtinfo3 *)NULL)->name)];
- struct proc_dir_entry *procfs_entry;
-};
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 20/56] netfilter: xtables2: xt1->xt2 translation - SET_REPLACE support
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (18 preceding siblings ...)
2010-06-29 8:42 ` [PATCH 19/56] netfilter: xtables2: xt2->xt1 translation - GET_ENTRIES support Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 21/56] netfilter: xtables2: return counters after SET_REPLACE Jan Engelhardt
` (14 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Support table replacement from userspace. Currently without
returning counters.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 3 ++
net/ipv6/netfilter/ip6_tables.c | 9 ++++++
net/netfilter/x_tables.c | 3 +-
net/netfilter/xt1_support.c | 32 +++++++++++++++++++++
net/netfilter/xt1_translat.c | 53 ++++++++++++++++++++++++++++++++++++
5 files changed, 99 insertions(+), 1 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 3d33a06..d905a44 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -577,6 +577,8 @@ struct xt2_table_link {
struct xt2_table *table;
};
+extern const char *const xt_prefix[NFPROTO_NUMPROTO];
+
#define XT_TABLE_INFO_SZ (offsetof(struct xt_table_info, entries) \
+ nr_cpu_ids * sizeof(char *))
extern int xt_register_target(struct xt_target *target);
@@ -735,6 +737,7 @@ extern int xts_starget_to_xt1(void __user **, int *, unsigned int *,
const struct xt1_xlat_info *);
extern int xts_target_to_xt1(void __user **, int *, unsigned int *,
const struct xt2_entry_target *);
+extern int xts_table_replace(struct net *, struct xt2_table *);
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
extern int xt2_rule_add_match(struct xt2_rule *, const char *, uint8_t,
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index ddc0313..78dca6f 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -69,6 +69,7 @@ static int mark_source_chains(const struct xt_table_info *,
#define xtsub_entry ip6t_entry
#define xtsub_replace ip6t_replace
#define xtsub_error_target ip6t_error_target
+#define XTSUB_NFPROTO NFPROTO_IPV6
#define XTSUB_NFPROTO_IPV6 1
#define XTSUB(x) ip6t_ ## x
#define XTSUB2(x) ip6t2_ ## x
@@ -1421,6 +1422,14 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
return -EFAULT;
+ /*
+ * If the table goes away just moments later, no problem.
+ * Just dispatching here.
+ */
+ if (xt2_table_lookup(net, tmp.name,
+ NFPROTO_IPV6, XT2_STD_RCULOCK) != NULL)
+ return ip6t2_do_replace(net, user, len);
+
/* overflow check */
if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
return -ENOMEM;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index f4794db..5303ae3 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -67,13 +67,14 @@ enum {
/* XT_CONTINUE = 0xFFFFFFFF, */ /* reminder (x_tables.h) */
};
-static const char *const xt_prefix[NFPROTO_NUMPROTO] = {
+const char *const xt_prefix[NFPROTO_NUMPROTO] = {
[NFPROTO_UNSPEC] = "x",
[NFPROTO_IPV4] = "ip",
[NFPROTO_ARP] = "arp",
[NFPROTO_BRIDGE] = "eb",
[NFPROTO_IPV6] = "ip6",
};
+EXPORT_SYMBOL_GPL(xt_prefix);
/* Allow this many total (re)entries. */
static const unsigned int xt_jumpstack_multiplier = 2;
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
index af58cff..04126d0 100644
--- a/net/netfilter/xt1_support.c
+++ b/net/netfilter/xt1_support.c
@@ -240,4 +240,36 @@ int xts_target_to_xt1(void __user **user_ptr, int *len, unsigned int *z,
}
EXPORT_SYMBOL_GPL(xts_target_to_xt1);
+/**
+ * Load table module, check hook masks, replace table.
+ */
+int xts_table_replace(struct net *net, struct xt2_table *table)
+{
+ struct xt2_table *old_table;
+
+ old_table = try_then_request_module(xt2_table_lookup(net,
+ table->name,
+ table->nfproto,
+ XT2_KEEP_RCULOCK),
+ "%stable_%s",
+ xt_prefix[table->nfproto],
+ table->name);
+ if (old_table == NULL)
+ return -ENOENT;
+ if (table->valid_hooks != old_table->valid_hooks) {
+ pr_err("Invalid hook mix: 0x%x (old) vs 0x%x (new)\n",
+ old_table->valid_hooks, table->valid_hooks);
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ rcu_read_unlock();
+
+ old_table = xt2_table_replace(net, table);
+ if (IS_ERR(old_table))
+ return PTR_ERR(old_table);
+ xt2_table_destroy(NULL, old_table);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xts_table_replace);
+
MODULE_LICENSE("GPL");
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
index bff55fc..669b2b2 100644
--- a/net/netfilter/xt1_translat.c
+++ b/net/netfilter/xt1_translat.c
@@ -434,3 +434,56 @@ XTSUB2(table_to_xt1)(void __user *user_ptr, int len, struct xt2_table *table,
mutex_unlock(&table->xt1_lock);
return ret;
}
+
+static int
+XTSUB2(do_replace)(struct net *net, const void __user *user, unsigned int len)
+{
+ struct xtsub_replace repl;
+ struct xt2_table *table;
+ void *blob;
+ int ret;
+
+ if (copy_from_user(&repl, user, sizeof(repl)) != 0)
+ return -EFAULT;
+
+ /* overflow check */
+ if (repl.num_counters >= INT_MAX / sizeof(struct xt_counters))
+ return -ENOMEM;
+
+#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
+ /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
+ if ((SMP_ALIGN(repl.size) >> PAGE_SHIFT) + 2 > num_physpages)
+ return -ENOMEM;
+#undef SMP_ALIGN
+
+ table = xt2_table_new();
+ if (table == NULL)
+ return -ENOMEM;
+ table->net = net;
+ /* Need a writable copy for check_entry_and_size_hooks. */
+ ret = -ENOMEM;
+ blob = vmalloc(repl.size);
+ if (blob == NULL)
+ goto out;
+ if (copy_from_user(blob, user + sizeof(repl), repl.size) != 0) {
+ ret = -EFAULT;
+ goto out;
+ }
+ strncpy(table->name, repl.name, sizeof(table->name));
+ table->name[sizeof(table->name)-1] = '\0';
+ table->valid_hooks = repl.valid_hooks;
+ table->nfproto = XTSUB_NFPROTO;
+
+ ret = XTSUB2(table_to_xt2)(table, blob, &repl);
+ vfree(blob);
+ if (ret < 0)
+ goto out;
+ ret = xts_table_replace(net, table);
+ if (ret < 0)
+ goto out;
+ return 0;
+
+ out:
+ xt2_table_destroy(NULL, table);
+ return ret;
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 21/56] netfilter: xtables2: return counters after SET_REPLACE
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (19 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 20/56] netfilter: xtables2: xt1->xt2 translation - SET_REPLACE support Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 22/56] netfilter: xtables2: xt1->xt2 translation - ADD_COUNTERS support Jan Engelhardt
` (13 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 3 +-
net/netfilter/xt1_support.c | 58 ++++++++++++++++++++++++++++++++++-
net/netfilter/xt1_translat.c | 2 +-
3 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index d905a44..d672b3d 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -737,7 +737,8 @@ extern int xts_starget_to_xt1(void __user **, int *, unsigned int *,
const struct xt1_xlat_info *);
extern int xts_target_to_xt1(void __user **, int *, unsigned int *,
const struct xt2_entry_target *);
-extern int xts_table_replace(struct net *, struct xt2_table *);
+extern int xts_table_replace(void __user *, unsigned int, struct net *,
+ struct xt2_table *);
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
extern int xt2_rule_add_match(struct xt2_rule *, const char *, uint8_t,
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
index 04126d0..d87e0ab 100644
--- a/net/netfilter/xt1_support.c
+++ b/net/netfilter/xt1_support.c
@@ -241,11 +241,64 @@ int xts_target_to_xt1(void __user **user_ptr, int *len, unsigned int *z,
EXPORT_SYMBOL_GPL(xts_target_to_xt1);
/**
+ * @ptr: room for counters
+ * @cnum: maximum number of counters to copy
+ * @table: input xt2 table
+ */
+static int xts_put_counters(struct xt_counters __user *ptr, unsigned int cnum,
+ const struct xt2_table *table)
+{
+ const struct xt2_entry_match *ematch;
+ const struct xt2_chain *chain;
+ const struct xt2_rule *rule;
+ struct xt_counters ctinfo;
+ unsigned int i = 0;
+ int ret = 0;
+
+ rcu_read_lock();
+ list_for_each_entry(chain, &table->chain_list, anchor) {
+ if (i == cnum)
+ break;
+ if (!xt2_builtin_chain(chain)) {
+ ctinfo.bcnt = ctinfo.pcnt = 0;
+ ret = copy_to_user(&ptr[i++], &ctinfo, sizeof(ctinfo));
+ if (ret < 0)
+ goto out;
+ }
+
+ list_for_each_entry(rule, &chain->rule_list, anchor) {
+ if (i == cnum)
+ break;
+ ematch = xts_rule_quota_ptr(rule);
+ if (ematch == NULL) {
+ ret = -EIO;
+ goto out;
+ }
+ xts_rule_get_quota(ematch, &ctinfo.bcnt, &ctinfo.pcnt);
+ ret = copy_to_user(&ptr[i++], &ctinfo, sizeof(ctinfo));
+ if (ret < 0)
+ goto out;
+ }
+ }
+
+ if (i < cnum) {
+ /* end of ruleset marker: */
+ ctinfo.bcnt = ctinfo.pcnt = 0;
+ ret = copy_to_user(&ptr[i], &ctinfo, sizeof(ctinfo));
+ }
+ out:
+ rcu_read_unlock();
+ return ret;
+}
+
+/**
* Load table module, check hook masks, replace table.
*/
-int xts_table_replace(struct net *net, struct xt2_table *table)
+int xts_table_replace(void __user *counters_ptr, unsigned int num_counters,
+ struct net *net, struct xt2_table *table)
{
struct xt2_table *old_table;
+ int ret;
old_table = try_then_request_module(xt2_table_lookup(net,
table->name,
@@ -267,8 +320,9 @@ int xts_table_replace(struct net *net, struct xt2_table *table)
old_table = xt2_table_replace(net, table);
if (IS_ERR(old_table))
return PTR_ERR(old_table);
+ ret = xts_put_counters(counters_ptr, num_counters, old_table);
xt2_table_destroy(NULL, old_table);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(xts_table_replace);
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
index 669b2b2..159a6c5 100644
--- a/net/netfilter/xt1_translat.c
+++ b/net/netfilter/xt1_translat.c
@@ -478,7 +478,7 @@ XTSUB2(do_replace)(struct net *net, const void __user *user, unsigned int len)
vfree(blob);
if (ret < 0)
goto out;
- ret = xts_table_replace(net, table);
+ ret = xts_table_replace(repl.counters, repl.num_counters, net, table);
if (ret < 0)
goto out;
return 0;
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 22/56] netfilter: xtables2: xt1->xt2 translation - ADD_COUNTERS support
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (20 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 21/56] netfilter: xtables2: return counters after SET_REPLACE Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 23/56] netfilter: xtables2: xt2->xt1 translation - compat GET_INFO support Jan Engelhardt
` (12 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 2 +
net/ipv6/netfilter/ip6_tables.c | 11 ++++++
net/netfilter/xt1_support.c | 63 ++++++++++++++++++++++++++++++++++++
3 files changed, 76 insertions(+), 0 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index d672b3d..99d05ba 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -739,6 +739,8 @@ extern int xts_target_to_xt1(void __user **, int *, unsigned int *,
const struct xt2_entry_target *);
extern int xts_table_replace(void __user *, unsigned int, struct net *,
struct xt2_table *);
+extern int xts_get_counters(struct xt2_table *,
+ const struct xt_counters __user *, unsigned int);
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
extern int xt2_rule_add_match(struct xt2_rule *, const char *, uint8_t,
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 78dca6f..80177a5 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1239,6 +1239,7 @@ static int get_info(struct net *net, void __user *user,
if (xt2_table != NULL) {
ret = ip6t2_get_info(user, *len, xt2_table);
rcu_read_unlock();
+ module_put(xt2_table->owner);
if (t != NULL)
module_put(t->me);
return ret;
@@ -1482,6 +1483,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len,
int ret = 0;
const void *loc_cpu_entry;
struct ip6t_entry *iter;
+ struct xt2_table *xt2_table;
#ifdef CONFIG_COMPAT
struct compat_xt_counters_info compat_tmp;
@@ -1512,6 +1514,15 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len,
if (len != size + num_counters * sizeof(struct xt_counters))
return -EINVAL;
+ xt2_table = xt2_table_lookup(net, name, NFPROTO_IPV6,
+ XT2_KEEP_RCULOCK);
+ if (xt2_table != NULL) {
+ ret = xts_get_counters(xt2_table, user + size, num_counters);
+ rcu_read_unlock();
+ return ret;
+ }
+ rcu_read_unlock();
+
paddc = vmalloc(len - size);
if (!paddc)
return -ENOMEM;
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
index d87e0ab..675428c 100644
--- a/net/netfilter/xt1_support.c
+++ b/net/netfilter/xt1_support.c
@@ -88,6 +88,23 @@ void xts_rule_get_quota(const struct xt2_entry_match *ematch,
}
EXPORT_SYMBOL_GPL(xts_rule_get_quota);
+static void xts_rule_set_quota(const struct xt2_entry_match *ematch,
+ uint64_t bytes, uint64_t pkts)
+{
+ const struct xt_quota_mtinfo3 *q;
+
+ /* Bytes */
+ q = ematch->data;
+ spin_lock_bh(&q->master->lock);
+ q->master->quota = bytes;
+ spin_unlock_bh(&q->master->lock);
+ /* Packets */
+ q = list_entry(ematch->anchor.next, typeof(*ematch), anchor)->data;
+ spin_lock_bh(&q->master->lock);
+ q->master->quota = pkts;
+ spin_unlock_bh(&q->master->lock);
+}
+
static int
xts_blob_prep_rule(const struct xt2_rule *rule, const struct xt1_xlat_info *io,
unsigned int *underflow, unsigned int z)
@@ -326,4 +343,50 @@ int xts_table_replace(void __user *counters_ptr, unsigned int num_counters,
}
EXPORT_SYMBOL_GPL(xts_table_replace);
+/**
+ * @table: xt2 table with rules to modify
+ * @ptr: source counter array
+ * @cnum: maximum number of counters to read
+ */
+int xts_get_counters(struct xt2_table *table,
+ const struct xt_counters __user *ptr, unsigned int cnum)
+{
+ const struct xt2_entry_match *ematch;
+ const struct xt2_chain *chain;
+ const struct xt2_rule *rule;
+ struct xt_counters ctinfo;
+ unsigned int i = 0;
+ int ret = 0;
+
+ rcu_read_lock();
+ list_for_each_entry(chain, &table->chain_list, anchor) {
+ if (i == cnum)
+ break;
+ if (!xt2_builtin_chain(chain))
+ /* Skip counters for start-of-chain marker */
+ ++i;
+
+ list_for_each_entry(rule, &chain->rule_list, anchor) {
+ if (i == cnum)
+ break;
+ ematch = xts_rule_quota_ptr(rule);
+ if (ematch == NULL) {
+ ret = -EIO;
+ goto out;
+ }
+ ret = copy_from_user(&ctinfo, &ptr[i++],
+ sizeof(ctinfo));
+ if (ret < 0)
+ goto out;
+ xts_rule_set_quota(ematch, ctinfo.bcnt, ctinfo.pcnt);
+ }
+ }
+
+ /* Ignore EOR marker or additional counters. */
+ out:
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xts_get_counters);
+
MODULE_LICENSE("GPL");
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 23/56] netfilter: xtables2: xt2->xt1 translation - compat GET_INFO support
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (21 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 22/56] netfilter: xtables2: xt1->xt2 translation - ADD_COUNTERS support Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 24/56] netfilter: ip6tables: move mark_chains to xt1_perproto.c Jan Engelhardt
` (11 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
net/ipv6/netfilter/ip6_tables.c | 23 +++++++++++++++++++----
1 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 80177a5..14804f2 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1188,8 +1188,21 @@ static int compat_table_info(const struct xt_table_info *info,
}
#endif
+static const struct xt1_xlat_info ip6t_compat_xlat_info = {
+#ifdef CONFIG_COMPAT
+ .marker_size = COMPAT_XT_ALIGN(sizeof(struct ip6t_error_target)),
+ .entry_hdr_size = sizeof(struct compat_ip6t_entry),
+ .pmatch_size = sizeof(struct ip6t_ip6),
+ .first_match = "ipv6",
+ .ematch_size = sizeof(struct xt_entry_match),
+ .etarget_size = sizeof(struct xt_entry_target),
+ .standard_tgsize = COMPAT_XT_ALIGN(sizeof(struct xt_entry_target) +
+ sizeof(compat_uint_t)),
+#endif
+};
+
static const struct xt1_xlat_info ip6t_xlat_info = {
- .marker_size = sizeof(struct ip6t_error_target),
+ .marker_size = XT_ALIGN(sizeof(struct ip6t_error_target)),
.entry_hdr_size = sizeof(struct ip6t_entry),
.pmatch_size = sizeof(struct ip6t_ip6),
.first_match = "ipv6",
@@ -1200,7 +1213,7 @@ static const struct xt1_xlat_info ip6t_xlat_info = {
};
static int ip6t2_get_info(void __user *uptr, int len,
- struct xt2_table *table)
+ struct xt2_table *table, bool compat)
{
struct ip6t_getinfo info = {
.valid_hooks = table->valid_hooks,
@@ -1208,7 +1221,9 @@ static int ip6t2_get_info(void __user *uptr, int len,
strncpy(info.name, table->name,
min(sizeof(info.name), sizeof(table->name)));
- info.size = xts_blob_prep_table(table, &ip6t_xlat_info,
+ info.size = xts_blob_prep_table(table,
+ compat ? &ip6t_compat_xlat_info :
+ &ip6t_xlat_info,
info.hook_entry, info.underflow,
&info.num_entries);
return (copy_to_user(uptr, &info, sizeof(info)) != 0) ? -EFAULT : 0;
@@ -1237,7 +1252,7 @@ static int get_info(struct net *net, void __user *user,
xt2_table = xt2_table_lookup(net, name, NFPROTO_IPV6,
XT2_KEEP_RCULOCK);
if (xt2_table != NULL) {
- ret = ip6t2_get_info(user, *len, xt2_table);
+ ret = ip6t2_get_info(user, *len, xt2_table, compat);
rcu_read_unlock();
module_put(xt2_table->owner);
if (t != NULL)
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 24/56] netfilter: ip6tables: move mark_chains to xt1_perproto.c
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (22 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 23/56] netfilter: xtables2: xt2->xt1 translation - compat GET_INFO support Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 25/56] netfilter: xtables2: xt2<->xt1 translation - compat GET_ENTRIES/SET_REPLACE support Jan Engelhardt
` (10 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
In xt2, the xt1compat blob is not translated into xt1 anymore, but
directly to xt2. So we need a mark_chains that handles struct
compat_ip6t_entry. (This merely moves the code around, no change.)
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
net/ipv6/netfilter/ip6_tables.c | 119 +--------------------------------------
net/netfilter/xt1_translat.c | 111 ++++++++++++++++++++++++++++++++++++-
2 files changed, 112 insertions(+), 118 deletions(-)
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 14804f2..1aff1b0 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -63,9 +63,6 @@ MODULE_DESCRIPTION("IPv6 packet filter");
#define inline
#endif
-static int mark_source_chains(const struct xt_table_info *,
- unsigned int, void *);
-
#define xtsub_entry ip6t_entry
#define xtsub_replace ip6t_replace
#define xtsub_error_target ip6t_error_target
@@ -571,118 +568,6 @@ ip6t_do_table(struct sk_buff *skb,
#endif
}
-/* Figures out from what hook each rule can be called: returns 0 if
- there are loops. Puts hook bitmask in comefrom. */
-static int
-mark_source_chains(const struct xt_table_info *newinfo,
- unsigned int valid_hooks, void *entry0)
-{
- unsigned int hook;
-
- /* No recursion; use packet counter to save back ptrs (reset
- to 0 as we leave), and comefrom to save source hook bitmask */
- for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
- unsigned int pos = newinfo->hook_entry[hook];
- struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
-
- if (!(valid_hooks & (1 << hook)))
- continue;
-
- /* Set initial back pointer. */
- e->counters.pcnt = pos;
-
- for (;;) {
- const struct ip6t_standard_target *t
- = (void *)ip6t_get_target_c(e);
- int visited = e->comefrom & (1 << hook);
-
- if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
- pr_err("iptables: loop hook %u pos %u %08X.\n",
- hook, pos, e->comefrom);
- return 0;
- }
- e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
-
- /* Unconditional return/END. */
- if ((e->target_offset == sizeof(struct ip6t_entry) &&
- (strcmp(t->target.u.user.name,
- IP6T_STANDARD_TARGET) == 0) &&
- t->verdict < 0 &&
- unconditional(&e->ipv6)) || visited) {
- unsigned int oldpos, size;
-
- if ((strcmp(t->target.u.user.name,
- IP6T_STANDARD_TARGET) == 0) &&
- t->verdict < -NF_MAX_VERDICT - 1) {
- duprintf("mark_source_chains: bad "
- "negative verdict (%i)\n",
- t->verdict);
- return 0;
- }
-
- /* Return: backtrack through the last
- big jump. */
- do {
- e->comefrom ^= (1<<NF_INET_NUMHOOKS);
-#ifdef DEBUG_IP_FIREWALL_USER
- if (e->comefrom
- & (1 << NF_INET_NUMHOOKS)) {
- duprintf("Back unset "
- "on hook %u "
- "rule %u\n",
- hook, pos);
- }
-#endif
- oldpos = pos;
- pos = e->counters.pcnt;
- e->counters.pcnt = 0;
-
- /* We're at the start. */
- if (pos == oldpos)
- goto next;
-
- e = (struct ip6t_entry *)
- (entry0 + pos);
- } while (oldpos == pos + e->next_offset);
-
- /* Move along one */
- size = e->next_offset;
- e = (struct ip6t_entry *)
- (entry0 + pos + size);
- e->counters.pcnt = pos;
- pos += size;
- } else {
- int newpos = t->verdict;
-
- if (strcmp(t->target.u.user.name,
- IP6T_STANDARD_TARGET) == 0 &&
- newpos >= 0) {
- if (newpos > newinfo->size -
- sizeof(struct ip6t_entry)) {
- duprintf("mark_source_chains: "
- "bad verdict (%i)\n",
- newpos);
- return 0;
- }
- /* This a jump; chase it. */
- duprintf("Jump rule %u -> %u\n",
- pos, newpos);
- } else {
- /* ... this is a fallthru */
- newpos = pos + e->next_offset;
- }
- e = (struct ip6t_entry *)
- (entry0 + newpos);
- e->counters.pcnt = pos;
- pos = newpos;
- }
- }
- next:
- duprintf("Finished chain %u\n", hook);
- }
- return 1;
-}
-
static void cleanup_match(struct ip6t_entry_match *m, struct net *net)
{
struct xt_mtdtor_param par;
@@ -968,7 +853,7 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
}
}
- if (!mark_source_chains(newinfo, repl->valid_hooks, entry0))
+ if (!ip6t2_mark_chains(newinfo, repl->valid_hooks, entry0))
return -ELOOP;
/* Finally, each sanity check must pass */
@@ -1933,7 +1818,7 @@ translate_compat_table(struct net *net,
goto free_newinfo;
ret = -ELOOP;
- if (!mark_source_chains(newinfo, valid_hooks, entry1))
+ if (!ip6t2_mark_chains(newinfo, valid_hooks, entry1))
goto free_newinfo;
i = 0;
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
index 159a6c5..fe6e4be 100644
--- a/net/netfilter/xt1_translat.c
+++ b/net/netfilter/xt1_translat.c
@@ -209,6 +209,115 @@ XTSUB2(rule_to_xt2)(struct xt2_chain *chain, const struct xtsub_entry *entry,
return ERR_PTR(ret);
}
+/* Figures out from what hook each rule can be called: returns 0 if
+ there are loops. Puts hook bitmask in comefrom. */
+static int
+XTSUB2(mark_chains)(const struct xt_table_info *newinfo,
+ unsigned int valid_hooks, void *entry0)
+{
+ unsigned int hook;
+
+ /* No recursion; use packet counter to save back ptrs (reset
+ to 0 as we leave), and comefrom to save source hook bitmask */
+ for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
+ unsigned int pos = newinfo->hook_entry[hook];
+ struct xtsub_entry *e = (void *)(entry0 + pos);
+
+ if (!(valid_hooks & (1 << hook)))
+ continue;
+
+ /* Set initial back pointer. */
+ e->counters.pcnt = pos;
+
+ for (;;) {
+ const struct xt_standard_target *t
+ = (void *)XTSUB2(get_target)(e);
+ int visited = e->comefrom & (1 << hook);
+
+ if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
+ printk("iptables: loop hook %u pos %u %08X.\n",
+ hook, pos, e->comefrom);
+ return false;
+ }
+ e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
+
+ /* Unconditional return/END. */
+ if ((e->target_offset == sizeof(struct xtsub_entry) &&
+ strcmp(t->target.u.user.name,
+ XT_STANDARD_TARGET) == 0 &&
+ t->verdict < 0 &&
+ XTSUB2(unconditional)(e)) || visited) {
+ unsigned int oldpos, size;
+
+ if (strcmp(t->target.u.user.name,
+ XT_STANDARD_TARGET) == 0 &&
+ t->verdict < -NF_MAX_VERDICT - 1) {
+ pr_devel("mark_chains: bad "
+ "negative verdict (%i)\n",
+ t->verdict);
+ return false;
+ }
+
+ /* Return: backtrack through the last
+ big jump. */
+ do {
+ e->comefrom ^= (1<<NF_INET_NUMHOOKS);
+#ifdef DEBUG_IP_FIREWALL_USER
+ if (e->comefrom
+ & (1 << NF_INET_NUMHOOKS)) {
+ pr_devel("Back unset "
+ "on hook %u "
+ "rule %u\n",
+ hook, pos);
+ }
+#endif
+ oldpos = pos;
+ pos = e->counters.pcnt;
+ e->counters.pcnt = 0;
+
+ /* We're at the start. */
+ if (pos == oldpos)
+ goto next;
+
+ e = (void *)(entry0 + pos);
+ } while (oldpos == pos + e->next_offset);
+
+ /* Move along one */
+ size = e->next_offset;
+ e = (void *)(entry0 + pos + size);
+ e->counters.pcnt = pos;
+ pos += size;
+ } else {
+ int newpos = t->verdict;
+
+ if (strcmp(t->target.u.user.name,
+ XT_STANDARD_TARGET) == 0
+ && newpos >= 0) {
+ if (newpos > newinfo->size -
+ sizeof(struct xtsub_entry)) {
+ pr_devel("mark_chains: "
+ "bad verdict (%i)\n",
+ newpos);
+ return false;
+ }
+ /* This a jump; chase it. */
+ pr_devel("Jump rule %u -> %u\n",
+ pos, newpos);
+ } else {
+ /* ... this is a fallthru */
+ newpos = pos + e->next_offset;
+ }
+ e = (void *)(entry0 + newpos);
+ e->counters.pcnt = pos;
+ pos = newpos;
+ }
+ }
+ next:
+ pr_devel("Finished chain %u\n", hook);
+ }
+ return true;
+}
+
/**
* @table: new table
* @entry0: blob of <struct ip6t_entry>s
@@ -250,7 +359,7 @@ static int XTSUB2(table_to_xt2)(struct xt2_table *table, void *entry0,
memcpy(mark_param.hook_entry, repl->hook_entry,
sizeof(repl->hook_entry));
mark_param.size = repl->size;
- if (!mark_source_chains(&mark_param, repl->valid_hooks, entry0))
+ if (!XTSUB2(mark_chains)(&mark_param, repl->valid_hooks, entry0))
return -ELOOP;
/* Now process rules. */
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 25/56] netfilter: xtables2: xt2<->xt1 translation - compat GET_ENTRIES/SET_REPLACE support
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (23 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 24/56] netfilter: ip6tables: move mark_chains to xt1_perproto.c Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 26/56] netfilter: xtables2: compat->normal match data translation Jan Engelhardt
` (9 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
This commit wires up the compat path to the translator. The
translator currently deals with the base entry, e.g. ip6t_entry.
compat<->normal translation of matchinfo data of arbitrary extensions
is done in an upcoming commit.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter_ipv6/ip6_tables.h | 12 +++++++++
net/ipv6/netfilter/ip6_tables.c | 39 ++++++++++++++++++++---------
net/netfilter/xt1_translat.c | 3 +-
3 files changed, 41 insertions(+), 13 deletions(-)
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index d1d5d3a..b86e18c 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -335,6 +335,18 @@ struct compat_ip6t_entry {
unsigned char elems[0];
};
+struct compat_ip6t_replace {
+ char name[IP6T_TABLE_MAXNAMELEN];
+ u32 valid_hooks;
+ u32 num_entries;
+ u32 size;
+ u32 hook_entry[NF_INET_NUMHOOKS];
+ u32 underflow[NF_INET_NUMHOOKS];
+ u32 num_counters;
+ compat_uptr_t counters; /* struct ip6t_counters * */
+ struct compat_ip6t_entry entries[0];
+};
+
static inline struct ip6t_entry_target *
compat_ip6t_get_target(struct compat_ip6t_entry *e)
{
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 1aff1b0..5522533 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -64,6 +64,7 @@ MODULE_DESCRIPTION("IPv6 packet filter");
#endif
#define xtsub_entry ip6t_entry
+#define xtsub_entry_nocompat ip6t_entry
#define xtsub_replace ip6t_replace
#define xtsub_error_target ip6t_error_target
#define XTSUB_NFPROTO NFPROTO_IPV6
@@ -73,6 +74,16 @@ MODULE_DESCRIPTION("IPv6 packet filter");
#include "../../netfilter/xt1_translat.c"
#include "../../netfilter/xt1_postshared.c"
+#undef XTSUB2
+#undef xtsub_entry
+#undef xtsub_replace
+
+#ifdef CONFIG_COMPAT
+#define xtsub_entry compat_ip6t_entry
+#define xtsub_replace compat_ip6t_replace
+#define XTSUB2(x) ip6t2_compat_ ## x
+#include "../../netfilter/xt1_translat.c"
+#endif
void *ip6t_alloc_initial_table(const struct xt_table *info)
{
@@ -1468,18 +1479,6 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len,
}
#ifdef CONFIG_COMPAT
-struct compat_ip6t_replace {
- char name[IP6T_TABLE_MAXNAMELEN];
- u32 valid_hooks;
- u32 num_entries;
- u32 size;
- u32 hook_entry[NF_INET_NUMHOOKS];
- u32 underflow[NF_INET_NUMHOOKS];
- u32 num_counters;
- compat_uptr_t counters; /* struct ip6t_counters * */
- struct compat_ip6t_entry entries[0];
-};
-
static int
compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
unsigned int *size, struct xt_counters *counters,
@@ -1889,6 +1888,10 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
return -EFAULT;
+ if (xt2_table_lookup(net, tmp.name, NFPROTO_IPV6,
+ XT2_STD_RCULOCK) != NULL)
+ return ip6t2_compat_do_replace(net, user, len);
+
/* overflow check */
if (tmp.size >= INT_MAX / num_possible_cpus())
return -ENOMEM;
@@ -2003,6 +2006,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
{
int ret;
struct compat_ip6t_get_entries get;
+ struct xt2_table *xt2_table;
struct xt_table *t;
if (*len < sizeof(get)) {
@@ -2019,6 +2023,17 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
return -EINVAL;
}
+ xt2_table = xt2_table_lookup(net, get.name, NFPROTO_IPV6,
+ XT2_KEEP_RCULOCK);
+ if (xt2_table != NULL) {
+ ret = ip6t2_compat_table_to_xt1(uptr->entrytable, get.size,
+ xt2_table,
+ &ip6t_compat_xlat_info);
+ rcu_read_unlock();
+ return ret;
+ }
+ rcu_read_unlock();
+
xt_compat_lock(AF_INET6);
t = xt_find_table_lock(net, AF_INET6, get.name);
if (t && !IS_ERR(t)) {
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
index fe6e4be..bd8fc2d 100644
--- a/net/netfilter/xt1_translat.c
+++ b/net/netfilter/xt1_translat.c
@@ -587,7 +587,8 @@ XTSUB2(do_replace)(struct net *net, const void __user *user, unsigned int len)
vfree(blob);
if (ret < 0)
goto out;
- ret = xts_table_replace(repl.counters, repl.num_counters, net, table);
+ ret = xts_table_replace((void __user *)(unsigned long)repl.counters,
+ repl.num_counters, net, table);
if (ret < 0)
goto out;
return 0;
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 26/56] netfilter: xtables2: compat->normal match data translation
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (24 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 25/56] netfilter: xtables2: xt2<->xt1 translation - compat GET_ENTRIES/SET_REPLACE support Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 27/56] netfilter: xtables2: compat->normal target " Jan Engelhardt
` (8 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
This patch will translate userspace requests in compat format
to the normalized format. Testable with e.g. `ip6tables -t filter2
-A INPUT -m limit --limit 1/s`, which will submit a struct
xt_entry_match with size 0x3C, and retrieving the ruleset will show
that it has been translated into a struct xt_entry_match with the
size field containing 0x48.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 4 ++
net/ipv6/netfilter/ip6_tables.c | 1 +
net/netfilter/xt1_support.c | 59 ++++++++++++++++++++++++++++++++++++
net/netfilter/xt1_translat.c | 9 +++++-
4 files changed, 72 insertions(+), 1 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 99d05ba..b6aff51 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -741,6 +741,10 @@ extern int xts_table_replace(void __user *, unsigned int, struct net *,
struct xt2_table *);
extern int xts_get_counters(struct xt2_table *,
const struct xt_counters __user *, unsigned int);
+#ifdef CONFIG_COMPAT
+extern int xts_rule_add_cmatch(struct xt2_rule *,
+ const struct xt_entry_match *);
+#endif
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
extern int xt2_rule_add_match(struct xt2_rule *, const char *, uint8_t,
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 5522533..a3db2e0 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -79,6 +79,7 @@ MODULE_DESCRIPTION("IPv6 packet filter");
#undef xtsub_replace
#ifdef CONFIG_COMPAT
+#define XTSUB_DO_COMPAT
#define xtsub_entry compat_ip6t_entry
#define xtsub_replace compat_ip6t_replace
#define XTSUB2(x) ip6t2_compat_ ## x
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
index 675428c..e0dcadd 100644
--- a/net/netfilter/xt1_support.c
+++ b/net/netfilter/xt1_support.c
@@ -389,4 +389,63 @@ int xts_get_counters(struct xt2_table *table,
}
EXPORT_SYMBOL_GPL(xts_get_counters);
+#ifdef CONFIG_COMPAT
+int xts_rule_add_cmatch(struct xt2_rule *rule, const struct xt_entry_match *m)
+{
+ const uint8_t nfproto = rule->chain->table->nfproto;
+ const struct xt_match *ext;
+ unsigned int dsize, required;
+ void *data;
+ int ret;
+
+ ext = try_then_request_module(xt_find_match(nfproto,
+ m->u.user.name,
+ m->u.user.revision),
+ "%st_%s", xt_prefix[nfproto],
+ m->u.user.name);
+ if (ext == NULL)
+ return -ENOENT;
+ if (IS_ERR(ext))
+ return PTR_ERR(ext);
+
+ dsize = m->u.match_size - sizeof(*m);
+ if ((ext->compatsize == 0 && dsize == XT_ALIGN(ext->matchsize)) ||
+ ext->matchsize == -1) {
+ /*
+ * If extension does not have special ->compat_* functions and
+ * is already padded, proceed.
+ * ebt_among uses the -1 special case.
+ */
+ ret = xt2_rule_add_oldmatch(rule, m);
+ goto put_module;
+ }
+ required = (ext->compatsize == 0) ? ext->matchsize : ext->compatsize;
+ if (dsize != COMPAT_XT_ALIGN(required)) {
+ pr_err("%s_tables: %s.%u match: invalid size "
+ "(expected) %u != (given by user) %u\n",
+ xt_prefix[rule->chain->table->nfproto],
+ ext->name, ext->revision, required, dsize);
+ ret = -EINVAL;
+ goto put_module;
+ }
+
+ data = kzalloc(XT_ALIGN(ext->matchsize), GFP_KERNEL);
+ if (data == NULL) {
+ ret = -ENOMEM;
+ goto put_module;
+ }
+ if (ext->compat_from_user == NULL)
+ memcpy(data, m->data, dsize);
+ else
+ ext->compat_from_user(data, m->data);
+ ret = xt2_rule_add_match(rule, m->u.user.name, m->u.user.revision,
+ data, XT_ALIGN(ext->matchsize), true);
+ kfree(data);
+ put_module:
+ module_put(ext->me);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xts_rule_add_cmatch);
+#endif
+
MODULE_LICENSE("GPL");
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
index bd8fc2d..071cabe 100644
--- a/net/netfilter/xt1_translat.c
+++ b/net/netfilter/xt1_translat.c
@@ -16,6 +16,11 @@
#if !defined(XTSUB_NFPROTO_IPV6)
# error Need to define XTSUB_NFPROTO_xxx.
#endif
+#ifdef XTSUB_DO_COMPAT
+# define xtsub_rule_add_match xts_rule_add_cmatch
+#else
+# define xtsub_rule_add_match xt2_rule_add_oldmatch
+#endif
#ifdef XTSUB_NFPROTO_IPV6
static const struct ip6t_ip6 xtsub_uncond;
@@ -186,7 +191,7 @@ XTSUB2(rule_to_xt2)(struct xt2_chain *chain, const struct xtsub_entry *entry,
goto out;
xt_ematch_foreach(ematch, entry) {
- ret = xt2_rule_add_oldmatch(rule, ematch);
+ ret = xtsub_rule_add_match(rule, ematch);
if (ret < 0)
goto out;
}
@@ -597,3 +602,5 @@ XTSUB2(do_replace)(struct net *net, const void __user *user, unsigned int len)
xt2_table_destroy(NULL, table);
return ret;
}
+
+#undef xtsub_rule_add_match
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 27/56] netfilter: xtables2: compat->normal target data translation
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (25 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 26/56] netfilter: xtables2: compat->normal match data translation Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 28/56] netfilter: xtables2: outsource code into xts_match_to_xt1 function Jan Engelhardt
` (7 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
By this, `ip6tables -S` will now correctly receive 0x3C for xt_limit too.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 2 +
net/netfilter/xt1_support.c | 52 ++++++++++++++++++++++++++++++++++++
net/netfilter/xt1_translat.c | 5 +++-
3 files changed, 58 insertions(+), 1 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index b6aff51..ad95d1d 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -744,6 +744,8 @@ extern int xts_get_counters(struct xt2_table *,
#ifdef CONFIG_COMPAT
extern int xts_rule_add_cmatch(struct xt2_rule *,
const struct xt_entry_match *);
+extern int xts_rule_add_ctarget(struct xt2_rule *,
+ const struct xt_entry_target *);
#endif
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
index e0dcadd..e308844 100644
--- a/net/netfilter/xt1_support.c
+++ b/net/netfilter/xt1_support.c
@@ -446,6 +446,58 @@ int xts_rule_add_cmatch(struct xt2_rule *rule, const struct xt_entry_match *m)
return ret;
}
EXPORT_SYMBOL_GPL(xts_rule_add_cmatch);
+
+int xts_rule_add_ctarget(struct xt2_rule *rule,
+ const struct xt_entry_target *t)
+{
+ const uint8_t nfproto = rule->chain->table->nfproto;
+ const struct xt_target *ext;
+ unsigned int dsize, required;
+ void *data;
+ int ret;
+
+ ext = try_then_request_module(xt_find_target(nfproto,
+ t->u.user.name,
+ t->u.user.revision),
+ "%st_%s", xt_prefix[nfproto],
+ t->u.user.name);
+ if (ext == NULL)
+ return -ENOENT;
+ if (IS_ERR(ext))
+ return PTR_ERR(ext);
+
+ dsize = t->u.target_size - sizeof(*t);
+ if (ext->compatsize == 0 && dsize == XT_ALIGN(ext->targetsize)) {
+ ret = xt2_rule_add_oldtarget(rule, t);
+ goto put_module;
+ }
+ required = (ext->compatsize == 0) ? ext->targetsize : ext->compatsize;
+ if (dsize != COMPAT_XT_ALIGN(required)) {
+ pr_err("%s_tables: %s.%u target: invalid size "
+ "(expected) %u != (given by user) %u\n",
+ xt_prefix[rule->chain->table->nfproto],
+ ext->name, ext->revision, required, dsize);
+ ret = -EINVAL;
+ goto put_module;
+ }
+
+ data = kzalloc(XT_ALIGN(ext->targetsize), GFP_KERNEL);
+ if (data == NULL) {
+ ret = -ENOMEM;
+ goto put_module;
+ }
+ if (ext->compat_from_user == NULL)
+ memcpy(data, t->data, dsize);
+ else
+ ext->compat_from_user(data, t->data);
+ ret = xt2_rule_add_target(rule, t->u.user.name, t->u.user.revision,
+ data, XT_ALIGN(ext->targetsize), true);
+ kfree(data);
+ put_module:
+ module_put(ext->me);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xts_rule_add_ctarget);
#endif
MODULE_LICENSE("GPL");
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
index 071cabe..d000fe2 100644
--- a/net/netfilter/xt1_translat.c
+++ b/net/netfilter/xt1_translat.c
@@ -18,8 +18,10 @@
#endif
#ifdef XTSUB_DO_COMPAT
# define xtsub_rule_add_match xts_rule_add_cmatch
+# define xtsub_rule_add_target xts_rule_add_ctarget
#else
# define xtsub_rule_add_match xt2_rule_add_oldmatch
+# define xtsub_rule_add_target xt2_rule_add_oldtarget
#endif
#ifdef XTSUB_NFPROTO_IPV6
@@ -123,7 +125,7 @@ XTSUB2(target_to_xt2)(struct xt2_rule *rule, const struct xtsub_entry *entry,
struct xt2_entry_target *ntarget;
if (strcmp(etarget->u.user.name, XT_STANDARD_TARGET) != 0)
- return xt2_rule_add_oldtarget(rule, etarget);
+ return xtsub_rule_add_target(rule, etarget);
ntarget = kmalloc(sizeof(*ntarget), GFP_KERNEL);
if (ntarget == NULL)
@@ -604,3 +606,4 @@ XTSUB2(do_replace)(struct net *net, const void __user *user, unsigned int len)
}
#undef xtsub_rule_add_match
+#undef xtsub_rule_add_target
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 28/56] netfilter: xtables2: outsource code into xts_match_to_xt1 function
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (26 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 27/56] netfilter: xtables2: compat->normal target " Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 29/56] netfilter: xtables2: normal->compat match data translation Jan Engelhardt
` (6 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 2 ++
net/netfilter/xt1_support.c | 17 +++++++++++++++++
net/netfilter/xt1_translat.c | 13 +------------
3 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index ad95d1d..7ccc3fb 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -732,6 +732,8 @@ extern unsigned int xts_blob_prep_table(struct xt2_table *,
const struct xt1_xlat_info *,
unsigned int *, unsigned int *,
unsigned int *);
+extern int xts_match_to_xt1(void __user **, int *, unsigned int *,
+ const struct xt2_entry_match *);
extern int xts_starget_to_xt1(void __user **, int *, unsigned int *,
const struct xt2_entry_target *,
const struct xt1_xlat_info *);
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
index e308844..5844b0d 100644
--- a/net/netfilter/xt1_support.c
+++ b/net/netfilter/xt1_support.c
@@ -204,6 +204,23 @@ xts_blob_prep_table(struct xt2_table *table, const struct xt1_xlat_info *io,
}
EXPORT_SYMBOL_GPL(xts_blob_prep_table);
+int xts_match_to_xt1(void __user **user_ptr, int *len, unsigned int *z,
+ const struct xt2_entry_match *ematch)
+{
+ struct xt_entry_match blob;
+ int ret;
+
+ blob.u.match_size = sizeof(blob) + ematch->dsize;
+ blob.u.user.revision = ematch->ext->revision;
+ strncpy(blob.u.user.name, ematch->ext->name, sizeof(blob.u.user.name));
+ ret = xts_copy_to_user(user_ptr, len, &blob, sizeof(blob), z);
+ if (ret < 0)
+ return ret;
+ return xts_copy_to_user(user_ptr, len, ematch->data,
+ ematch->dsize, z);
+}
+EXPORT_SYMBOL_GPL(xts_match_to_xt1);
+
int xts_starget_to_xt1(void __user **user_ptr, int *len, unsigned int *z,
const struct xt2_entry_target *etarget,
const struct xt1_xlat_info *io)
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
index d000fe2..c1e82b9 100644
--- a/net/netfilter/xt1_translat.c
+++ b/net/netfilter/xt1_translat.c
@@ -475,20 +475,9 @@ XTSUB2(rule_to_xt1)(void __user **user_ptr, int *len, unsigned int *z,
return ret;
list_for_each_entry_continue(ematch, &rule->match_list, anchor) {
- struct xt_entry_match blob;
-
if (ematch == quota_ematch)
break;
-
- blob.u.match_size = sizeof(blob) + ematch->dsize;
- blob.u.user.revision = ematch->ext->revision;
- strncpy(blob.u.user.name, ematch->ext->name,
- sizeof(blob.u.user.name));
- ret = xts_copy_to_user(user_ptr, len, &blob, sizeof(blob), z);
- if (ret < 0)
- return ret;
- ret = xts_copy_to_user(user_ptr, len, ematch->data,
- ematch->dsize, z);
+ ret = xts_match_to_xt1(user_ptr, len, z, ematch);
if (ret < 0)
return ret;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 29/56] netfilter: xtables2: normal->compat match data translation
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (27 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 28/56] netfilter: xtables2: outsource code into xts_match_to_xt1 function Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 30/56] netfilter: xtables2: normal->compat target " Jan Engelhardt
` (5 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 5 ++++
net/ipv6/netfilter/ip6_tables.c | 1 +
net/netfilter/xt1_support.c | 42 +++++++++++++++++++++++++++++++++++-
net/netfilter/xt1_translat.c | 5 +++-
4 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 7ccc3fb..4103d17 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -422,6 +422,8 @@ struct xt_table_info {
* @etarget_size: size of the etarget header
* @standard_tgsize: size of the complete standard target, includes
* etarget_size and alignment padding
+ * @compat: whether requestor is in normal or compat mode
+ * affects selection of ematch->dsize vs compatsize
*/
struct xt1_xlat_info {
unsigned int marker_size;
@@ -429,6 +431,7 @@ struct xt1_xlat_info {
unsigned int ematch_size, etarget_size;
unsigned int standard_tgsize;
const char *first_match;
+ bool compat;
};
/*
@@ -748,6 +751,8 @@ extern int xts_rule_add_cmatch(struct xt2_rule *,
const struct xt_entry_match *);
extern int xts_rule_add_ctarget(struct xt2_rule *,
const struct xt_entry_target *);
+extern int xts_cmatch_to_xt1(void __user **, int *, unsigned int *,
+ const struct xt2_entry_match *);
#endif
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index a3db2e0..586cd48 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1095,6 +1095,7 @@ static const struct xt1_xlat_info ip6t_compat_xlat_info = {
.etarget_size = sizeof(struct xt_entry_target),
.standard_tgsize = COMPAT_XT_ALIGN(sizeof(struct xt_entry_target) +
sizeof(compat_uint_t)),
+ .compat = true,
#endif
};
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
index 5844b0d..ad52d5e 100644
--- a/net/netfilter/xt1_support.c
+++ b/net/netfilter/xt1_support.c
@@ -142,7 +142,14 @@ xts_blob_prep_rule(const struct xt2_rule *rule, const struct xt1_xlat_info *io,
if (ematch == quota_stop)
/* quotas included in entry_hdr */
break;
- z += io->ematch_size + ematch->dsize;
+ z += io->ematch_size;
+#ifdef CONFIG_COMPAT
+ if (ematch->ext->matchsize != -1 && io->compat &&
+ ematch->ext->compatsize != 0)
+ z += COMPAT_XT_ALIGN(ematch->ext->compatsize);
+ else
+#endif
+ z += ematch->dsize;
}
etarget = list_first_entry(&rule->target_list,
@@ -515,6 +522,39 @@ int xts_rule_add_ctarget(struct xt2_rule *rule,
return ret;
}
EXPORT_SYMBOL_GPL(xts_rule_add_ctarget);
+
+int xts_cmatch_to_xt1(void __user **user_ptr, int *len, unsigned int *z,
+ const struct xt2_entry_match *ematch)
+{
+ struct xt_entry_match blob;
+ unsigned int dsize;
+ int ret;
+
+ if (ematch->ext->compatsize == 0)
+ return xts_match_to_xt1(user_ptr, len, z, ematch);
+
+ dsize = COMPAT_XT_ALIGN(ematch->ext->compatsize);
+ blob.u.match_size = sizeof(blob) + dsize;
+ blob.u.user.revision = ematch->ext->revision;
+ strncpy(blob.u.user.name, ematch->ext->name, sizeof(blob.u.user.name));
+ ret = xts_copy_to_user(user_ptr, len, &blob, sizeof(blob), z);
+ if (ret < 0)
+ return ret;
+ /*
+ * The awkward semantics of compat_to_user means we cannot
+ * use xts_copy_to_user.
+ */
+ if (*len < dsize)
+ return -ENOSPC;
+ ret = ematch->ext->compat_to_user(*user_ptr, ematch->data);
+ if (ret < 0)
+ return ret;
+ *user_ptr += dsize;
+ *z += dsize;
+ *len -= dsize;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xts_cmatch_to_xt1);
#endif
MODULE_LICENSE("GPL");
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
index c1e82b9..4e0ad52 100644
--- a/net/netfilter/xt1_translat.c
+++ b/net/netfilter/xt1_translat.c
@@ -19,9 +19,11 @@
#ifdef XTSUB_DO_COMPAT
# define xtsub_rule_add_match xts_rule_add_cmatch
# define xtsub_rule_add_target xts_rule_add_ctarget
+# define xtsub_match_to_xt1 xts_cmatch_to_xt1
#else
# define xtsub_rule_add_match xt2_rule_add_oldmatch
# define xtsub_rule_add_target xt2_rule_add_oldtarget
+# define xtsub_match_to_xt1 xts_match_to_xt1
#endif
#ifdef XTSUB_NFPROTO_IPV6
@@ -477,7 +479,7 @@ XTSUB2(rule_to_xt1)(void __user **user_ptr, int *len, unsigned int *z,
list_for_each_entry_continue(ematch, &rule->match_list, anchor) {
if (ematch == quota_ematch)
break;
- ret = xts_match_to_xt1(user_ptr, len, z, ematch);
+ ret = xtsub_match_to_xt1(user_ptr, len, z, ematch);
if (ret < 0)
return ret;
}
@@ -596,3 +598,4 @@ XTSUB2(do_replace)(struct net *net, const void __user *user, unsigned int len)
#undef xtsub_rule_add_match
#undef xtsub_rule_add_target
+#undef xtsub_match_to_xt1
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 30/56] netfilter: xtables2: normal->compat target data translation
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (28 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 29/56] netfilter: xtables2: normal->compat match data translation Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 31/56] netfilter: xtables2: packet tracing Jan Engelhardt
` (4 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/linux/netfilter/x_tables.h | 2 +
net/netfilter/xt1_support.c | 43 +++++++++++++++++++++++++++++++++--
net/netfilter/xt1_translat.c | 5 +++-
3 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 4103d17..aee8b92 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -753,6 +753,8 @@ extern int xts_rule_add_ctarget(struct xt2_rule *,
const struct xt_entry_target *);
extern int xts_cmatch_to_xt1(void __user **, int *, unsigned int *,
const struct xt2_entry_match *);
+extern int xts_ctarget_to_xt1(void __user **, int *, unsigned int *,
+ const struct xt2_entry_target *);
#endif
extern struct xt2_rule *xt2_rule_new(struct xt2_chain *);
diff --git a/net/netfilter/xt1_support.c b/net/netfilter/xt1_support.c
index ad52d5e..b90f2ca 100644
--- a/net/netfilter/xt1_support.c
+++ b/net/netfilter/xt1_support.c
@@ -154,9 +154,15 @@ xts_blob_prep_rule(const struct xt2_rule *rule, const struct xt1_xlat_info *io,
etarget = list_first_entry(&rule->target_list,
typeof(*etarget), anchor);
- z += xt2_special_target(etarget->ext) ? io->standard_tgsize :
- io->etarget_size +
- XT_ALIGN(etarget->ext->targetsize);
+ if (xt2_special_target(etarget->ext))
+ z += io->standard_tgsize;
+#ifdef CONFIG_COMPAT
+ else if (io->compat && etarget->ext->compatsize != 0)
+ z += io->etarget_size +
+ COMPAT_XT_ALIGN(etarget->ext->compatsize);
+#endif
+ else
+ z += io->etarget_size + XT_ALIGN(etarget->ext->targetsize);
return z;
}
@@ -555,6 +561,37 @@ int xts_cmatch_to_xt1(void __user **user_ptr, int *len, unsigned int *z,
return 0;
}
EXPORT_SYMBOL_GPL(xts_cmatch_to_xt1);
+
+int xts_ctarget_to_xt1(void __user **user_ptr, int *len, unsigned int *z,
+ const struct xt2_entry_target *etarget)
+{
+ struct xt_entry_target blob;
+ unsigned int dsize;
+ int ret;
+
+ if (etarget->ext->compatsize == 0)
+ return xts_target_to_xt1(user_ptr, len, z, etarget);
+
+ dsize = COMPAT_XT_ALIGN(etarget->ext->compatsize);
+ blob.u.target_size = sizeof(blob) + dsize;
+ blob.u.user.revision = etarget->ext->revision;
+ strncpy(blob.u.user.name, etarget->ext->name,
+ sizeof(blob.u.user.name));
+ ret = xts_copy_to_user(user_ptr, len, &blob, sizeof(blob), z);
+ if (ret < 0)
+ return ret;
+
+ if (*len < dsize)
+ return -ENOSPC;
+ ret = etarget->ext->compat_to_user(*user_ptr, etarget->data);
+ if (ret < 0)
+ return ret;
+ *user_ptr += dsize;
+ *z += dsize;
+ *len -= dsize;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xts_ctarget_to_xt1);
#endif
MODULE_LICENSE("GPL");
diff --git a/net/netfilter/xt1_translat.c b/net/netfilter/xt1_translat.c
index 4e0ad52..45007c9 100644
--- a/net/netfilter/xt1_translat.c
+++ b/net/netfilter/xt1_translat.c
@@ -20,10 +20,12 @@
# define xtsub_rule_add_match xts_rule_add_cmatch
# define xtsub_rule_add_target xts_rule_add_ctarget
# define xtsub_match_to_xt1 xts_cmatch_to_xt1
+# define xtsub_target_to_xt1 xts_ctarget_to_xt1
#else
# define xtsub_rule_add_match xt2_rule_add_oldmatch
# define xtsub_rule_add_target xt2_rule_add_oldtarget
# define xtsub_match_to_xt1 xts_match_to_xt1
+# define xtsub_target_to_xt1 xts_target_to_xt1
#endif
#ifdef XTSUB_NFPROTO_IPV6
@@ -490,7 +492,7 @@ XTSUB2(rule_to_xt1)(void __user **user_ptr, int *len, unsigned int *z,
list_for_each_entry(etarget, &rule->target_list, anchor) {
ret = xt2_special_target(etarget->ext) ?
xts_starget_to_xt1(user_ptr, len, z, etarget, io) :
- xts_target_to_xt1(user_ptr, len, z, etarget);
+ xtsub_target_to_xt1(user_ptr, len, z, etarget);
if (ret < 0)
return ret;
}
@@ -599,3 +601,4 @@ XTSUB2(do_replace)(struct net *net, const void __user *user, unsigned int len)
#undef xtsub_rule_add_match
#undef xtsub_rule_add_target
#undef xtsub_match_to_xt1
+#undef xtsub_target_to_xt1
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 31/56] netfilter: xtables2: packet tracing
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (29 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 30/56] netfilter: xtables2: normal->compat target " Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 32/56] netfilter: xtables: turn procfs entries to walk xt2 table list Jan Engelhardt
` (3 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
net/netfilter/x_tables.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 76 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 5303ae3..f4fce99 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -31,6 +31,7 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_arp/arp_tables.h>
+#include <net/netfilter/nf_log.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
@@ -1730,6 +1731,73 @@ void xt2_table_destroy(struct net *net, struct xt2_table *table)
}
EXPORT_SYMBOL_GPL(xt2_table_destroy);
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+static struct nf_loginfo xt2_trace_loginfo __read_mostly = {
+ .type = NF_LOG_TYPE_LOG,
+ .u.log = {
+ .level = 4,
+ .logflags = NF_LOG_MASK,
+ },
+};
+
+static const char *xt2_verdict_string(unsigned int verdict)
+{
+ switch (verdict) {
+ case XT_RETURN: return "RETURN"; break;
+ case XT_START_CHAIN: return "GOTO/JUMP"; break;
+ case XT_CONTINUE: return "CONTINUE"; break;
+ }
+ switch (verdict & NF_VERDICT_MASK) {
+ case NF_ACCEPT: return "ACCEPT"; break;
+ case NF_DROP: return "DROP"; break;
+ case NF_STOLEN: return "STOLEN"; break;
+ case NF_QUEUE: return "QUEUE"; break;
+ case NF_STOP: return "STOP"; break;
+ default: return "?"; break;
+ }
+}
+
+static void
+xt2_trace_packet(const struct sk_buff *skb, unsigned int hook,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt2_chain *chain, const struct xt2_rule *rule,
+ unsigned int verdict)
+{
+ static const char *const builtin_chain_names[] = {
+ [NF_INET_PRE_ROUTING] = "PREROUTING",
+ [NF_INET_LOCAL_IN] = "INPUT",
+ [NF_INET_FORWARD] = "FORWARD",
+ [NF_INET_LOCAL_OUT] = "OUTPUT",
+ [NF_INET_POST_ROUTING] = "POSTROUTING",
+ };
+ const struct xt2_table *table = chain->table;
+ const struct xt2_rule *zrule;
+ unsigned int rule_index = 0;
+ const char *chain_name, *comment;
+
+ chain_name = xt2_builtin_chain(chain) ?
+ builtin_chain_names[hook] : chain->name;
+ if (rule != NULL)
+ list_for_each_entry(zrule, &chain->rule_list, anchor) {
+ ++rule_index;
+ if (zrule == rule)
+ break;
+ }
+
+ if (rule == NULL)
+ comment = "return"; /* end-of-chain */
+ else if (rule == chain->table->underflow[hook])
+ comment = "policy";
+ else
+ comment = "rule";
+
+ nf_log_packet(table->nfproto, hook, skb, in, out, &xt2_trace_loginfo,
+ "TRACE: %s:%s:%s:%u:%s ", table->name, chain_name,
+ comment, rule_index, xt2_verdict_string(verdict));
+}
+#endif
+
static unsigned int
xt2_do_actions(struct sk_buff *skb, struct xt_action_param *acpar,
const struct xt2_rule *rule, const struct xt2_chain **chain_ptr,
@@ -1805,6 +1873,14 @@ xt2_do_table(struct sk_buff *skb, unsigned int hook,
verdict = xt2_do_actions(skb, &acpar, rule, &chain, stackptr,
table->stacksize, jumpstack);
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+ if (unlikely(skb->nf_trace))
+ xt2_trace_packet(skb, hook, in, out, rule->chain,
+ (&rule->anchor == &chain->rule_list) ? NULL : rule,
+ verdict);
+#endif
+
switch (verdict) {
case XT_START_CHAIN:
goto do_chain;
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 32/56] netfilter: xtables: turn procfs entries to walk xt2 table list
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (30 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 31/56] netfilter: xtables2: packet tracing Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:43 ` [PATCH 33/56] netfilter: xtables2: switch ip6's tables to the xt2 table format Jan Engelhardt
` (2 subsequent siblings)
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
This commit makes /proc/net/ip6_tables_names traverse the xt2 table
list instead of the xt1 one. Developer note: Until the remaining xt1
tables are changed to xt2 (a few commits ahead), they will not show
up momentarily.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
net/netfilter/x_tables.c | 24 ++++++++++--------------
1 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index f4fce99..017f8d1 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -921,39 +921,35 @@ struct xt_names_priv {
};
static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
{
- struct xt_names_priv *priv = seq->private;
+ const struct xt_names_priv *priv = seq->private;
struct net *net = seq_file_net(seq);
u_int8_t af = priv->af;
- mutex_lock(&xt[af].mutex);
- return seq_list_start(&net->xt.tables[af], *pos);
+ rcu_read_lock();
+ return seq_list_start(&net->xt2.table_list[af], *pos);
}
static void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- struct xt_names_priv *priv = seq->private;
+ const struct xt_names_priv *priv = seq->private;
struct net *net = seq_file_net(seq);
u_int8_t af = priv->af;
- return seq_list_next(v, &net->xt.tables[af], pos);
+ return seq_list_next(v, &net->xt2.table_list[af], pos);
}
static void xt_table_seq_stop(struct seq_file *seq, void *v)
{
- struct xt_names_priv *priv = seq->private;
- u_int8_t af = priv->af;
-
- mutex_unlock(&xt[af].mutex);
+ rcu_read_unlock();
}
static int xt_table_seq_show(struct seq_file *seq, void *v)
{
- struct xt_table *table = list_entry(v, struct xt_table, list);
+ const struct xt2_table_link *link =
+ list_entry_rcu(v, typeof(*link), anchor);
+ const struct xt2_table *table = rcu_dereference(link->table);
- if (strlen(table->name))
- return seq_printf(seq, "%s\n", table->name);
- else
- return 0;
+ return seq_printf(seq, "%s\n", table->name);
}
static const struct seq_operations xt_table_seq_ops = {
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* [PATCH 33/56] netfilter: xtables2: switch ip6's tables to the xt2 table format
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (31 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 32/56] netfilter: xtables: turn procfs entries to walk xt2 table list Jan Engelhardt
@ 2010-06-29 8:43 ` Jan Engelhardt
2010-06-29 8:47 ` xt2 table core [*/33, not */56] Jan Engelhardt
2010-07-02 3:32 ` xt2 table core Simon Lodal
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:43 UTC (permalink / raw)
To: netfilter-devel; +Cc: kaber
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
---
include/net/netns/x_tables.h | 3 +-
net/ipv6/netfilter/Makefile | 2 +-
net/ipv6/netfilter/ip6table_filter.c | 24 +++++--
net/ipv6/netfilter/ip6table_filter2.c | 122 --------------------------------
net/ipv6/netfilter/ip6table_mangle.c | 37 ++++++----
net/ipv6/netfilter/ip6table_raw.c | 23 ++++--
net/ipv6/netfilter/ip6table_security.c | 24 ++++--
7 files changed, 76 insertions(+), 159 deletions(-)
delete mode 100644 net/ipv6/netfilter/ip6table_filter2.c
diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
index 9365569..580f27b 100644
--- a/include/net/netns/x_tables.h
+++ b/include/net/netns/x_tables.h
@@ -19,7 +19,8 @@ struct netns_xt {
struct netns_xt2 {
struct mutex table_lock;
struct list_head table_list[NFPROTO_NUMPROTO];
- struct xt2_table_link *ipv6_filter;
+ struct xt2_table_link
+ *ipv6_filter, *ipv6_mangle, *ipv6_raw, *ipv6_security;
};
#endif
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 35fa80f..aafbba3 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -4,7 +4,7 @@
# Link order matters here.
obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
-obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o ip6table_filter2.o
+obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index c9e37c8..99d0340 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/rcupdate.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/slab.h>
@@ -37,8 +38,14 @@ ip6table_filter_hook(unsigned int hook, struct sk_buff *skb,
int (*okfn)(struct sk_buff *))
{
const struct net *net = dev_net((in != NULL) ? in : out);
-
- return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter);
+ const struct xt2_table_link *link;
+ unsigned int verdict;
+
+ rcu_read_lock();
+ link = rcu_dereference(net->xt2.ipv6_filter);
+ verdict = xt2_do_table(skb, hook, in, out, link->table);
+ rcu_read_unlock();
+ return verdict;
}
static struct nf_hook_ops *filter_ops __read_mostly;
@@ -50,6 +57,7 @@ module_param(forward, bool, 0000);
static int __net_init ip6table_filter_net_init(struct net *net)
{
struct ip6t_replace *repl;
+ struct xt2_table *table;
repl = ip6t_alloc_initial_table(&packet_filter);
if (repl == NULL)
@@ -58,17 +66,19 @@ static int __net_init ip6table_filter_net_init(struct net *net)
((struct ip6t_standard *)repl->entries)[1].target.verdict =
-forward - 1;
- net->ipv6.ip6table_filter =
- ip6t_register_table(net, &packet_filter, repl);
+ table = ip6t2_register_table(net, &packet_filter, repl);
kfree(repl);
- if (IS_ERR(net->ipv6.ip6table_filter))
- return PTR_ERR(net->ipv6.ip6table_filter);
+ if (IS_ERR(table))
+ return PTR_ERR(table);
+ net->xt2.ipv6_filter = xt2_tlink_lookup(net, table->name,
+ table->nfproto,
+ XT2_STD_RCULOCK);
return 0;
}
static void __net_exit ip6table_filter_net_exit(struct net *net)
{
- ip6t_unregister_table(net, net->ipv6.ip6table_filter);
+ xt2_table_destroy(net, net->xt2.ipv6_filter->table);
}
static struct pernet_operations ip6table_filter_net_ops = {
diff --git a/net/ipv6/netfilter/ip6table_filter2.c b/net/ipv6/netfilter/ip6table_filter2.c
deleted file mode 100644
index f81f98b..0000000
--- a/net/ipv6/netfilter/ip6table_filter2.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
- *
- * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
- * Copyright (C) 2000-2004 Netfilter Core Team <coreteam@netfilter.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/slab.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-MODULE_DESCRIPTION("ip6tables filter table");
-
-#define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
- (1 << NF_INET_FORWARD) | \
- (1 << NF_INET_LOCAL_OUT))
-
-static const struct xt_table packet_filter = {
- .name = "filter2",
- .valid_hooks = FILTER_VALID_HOOKS,
- .me = THIS_MODULE,
- .af = NFPROTO_IPV6,
- .priority = NF_IP6_PRI_FILTER,
-};
-
-/* The work comes in here from netfilter.c. */
-static unsigned int
-ip6table_filter_hook(unsigned int hook, struct sk_buff *skb,
- const struct net_device *in, const struct net_device *out,
- int (*okfn)(struct sk_buff *))
-{
- const struct net *net = dev_net((in != NULL) ? in : out);
- const struct xt2_table_link *link;
- unsigned int verdict;
-
- rcu_read_lock();
- link = rcu_dereference(net->xt2.ipv6_filter);
- verdict = xt2_do_table(skb, hook, in, out, link->table);
- rcu_read_unlock();
- return verdict;
-}
-
-static struct nf_hook_ops *filter_ops __read_mostly;
-
-/* Default to forward because I got too much mail already. */
-static int forward = NF_ACCEPT;
-module_param(forward, bool, 0000);
-
-static int __net_init ip6table_filter_net_init(struct net *net)
-{
- struct ip6t_replace *repl;
- struct xt2_table *table;
-
- repl = ip6t_alloc_initial_table(&packet_filter);
- if (repl == NULL)
- return -ENOMEM;
- /* Entry 1 is the FORWARD hook */
- ((struct ip6t_standard *)repl->entries)[1].target.verdict =
- -forward - 1;
-
- table = ip6t2_register_table(net, &packet_filter, repl);
- kfree(repl);
- if (IS_ERR(table))
- return PTR_ERR(table);
- net->xt2.ipv6_filter = xt2_tlink_lookup(net, table->name,
- table->nfproto,
- XT2_STD_RCULOCK);
- return 0;
-}
-
-static void __net_exit ip6table_filter_net_exit(struct net *net)
-{
- xt2_table_destroy(net, net->xt2.ipv6_filter->table);
-}
-
-static struct pernet_operations ip6table_filter_net_ops = {
- .init = ip6table_filter_net_init,
- .exit = ip6table_filter_net_exit,
-};
-
-static int __init ip6table_filter_init(void)
-{
- int ret;
-
- if (forward < 0 || forward > NF_MAX_VERDICT) {
- pr_err("iptables forward must be 0 or 1\n");
- return -EINVAL;
- }
-
- ret = register_pernet_subsys(&ip6table_filter_net_ops);
- if (ret < 0)
- return ret;
-
- /* Register hooks */
- filter_ops = xt_hook_link(&packet_filter, ip6table_filter_hook);
- if (IS_ERR(filter_ops)) {
- ret = PTR_ERR(filter_ops);
- goto cleanup_table;
- }
-
- return ret;
-
- cleanup_table:
- unregister_pernet_subsys(&ip6table_filter_net_ops);
- return ret;
-}
-
-static void __exit ip6table_filter_fini(void)
-{
- xt_hook_unlink(&packet_filter, filter_ops);
- unregister_pernet_subsys(&ip6table_filter_net_ops);
-}
-
-module_init(ip6table_filter_init);
-module_exit(ip6table_filter_fini);
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 679a0a3..f348782 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -9,6 +9,7 @@
* published by the Free Software Foundation.
*/
#include <linux/module.h>
+#include <linux/rcupdate.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/slab.h>
@@ -33,6 +34,7 @@ static const struct xt_table packet_mangler = {
static unsigned int
ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
{
+ const struct xt2_table_link *link;
unsigned int ret;
struct in6_addr saddr, daddr;
u_int8_t hop_limit;
@@ -57,8 +59,10 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
/* flowlabel and prio (includes version, which shouldn't change either */
flowlabel = *((u_int32_t *)ipv6_hdr(skb));
- ret = ip6t_do_table(skb, NF_INET_LOCAL_OUT, NULL, out,
- dev_net(out)->ipv6.ip6table_mangle);
+ rcu_read_lock();
+ link = rcu_dereference(dev_net(out)->xt2.ipv6_mangle);
+ ret = xt2_do_table(skb, NF_INET_LOCAL_OUT, NULL, out, link->table);
+ rcu_read_unlock();
if (ret != NF_DROP && ret != NF_STOLEN &&
(memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
@@ -76,35 +80,42 @@ ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
+ const struct net *net = dev_net((in != NULL) ? in : out);
+ const struct xt2_table_link *link;
+ unsigned int verdict;
+
if (hook == NF_INET_LOCAL_OUT)
return ip6t_mangle_out(skb, out);
- if (hook == NF_INET_POST_ROUTING)
- return ip6t_do_table(skb, hook, in, out,
- dev_net(out)->ipv6.ip6table_mangle);
- /* INPUT/FORWARD */
- return ip6t_do_table(skb, hook, in, out,
- dev_net(in)->ipv6.ip6table_mangle);
+
+ rcu_read_lock();
+ link = rcu_dereference(net->xt2.ipv6_mangle);
+ verdict = xt2_do_table(skb, hook, in, out, link->table);
+ rcu_read_unlock();
+ return verdict;
}
static struct nf_hook_ops *mangle_ops __read_mostly;
static int __net_init ip6table_mangle_net_init(struct net *net)
{
struct ip6t_replace *repl;
+ struct xt2_table *table;
repl = ip6t_alloc_initial_table(&packet_mangler);
if (repl == NULL)
return -ENOMEM;
- net->ipv6.ip6table_mangle =
- ip6t_register_table(net, &packet_mangler, repl);
+ table = ip6t2_register_table(net, &packet_mangler, repl);
kfree(repl);
- if (IS_ERR(net->ipv6.ip6table_mangle))
- return PTR_ERR(net->ipv6.ip6table_mangle);
+ if (IS_ERR(table))
+ return PTR_ERR(table);
+ net->xt2.ipv6_mangle = xt2_tlink_lookup(net, table->name,
+ table->nfproto,
+ XT2_STD_RCULOCK);
return 0;
}
static void __net_exit ip6table_mangle_net_exit(struct net *net)
{
- ip6t_unregister_table(net, net->ipv6.ip6table_mangle);
+ xt2_table_destroy(net, net->xt2.ipv6_mangle->table);
}
static struct pernet_operations ip6table_mangle_net_ops = {
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index 5b9926a..a1f1741 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -4,6 +4,7 @@
* Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*/
#include <linux/module.h>
+#include <linux/rcupdate.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/slab.h>
@@ -24,8 +25,14 @@ ip6table_raw_hook(unsigned int hook, struct sk_buff *skb,
int (*okfn)(struct sk_buff *))
{
const struct net *net = dev_net((in != NULL) ? in : out);
-
- return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_raw);
+ const struct xt2_table_link *link;
+ unsigned int verdict;
+
+ rcu_read_lock();
+ link = rcu_dereference(net->xt2.ipv6_raw);
+ verdict = xt2_do_table(skb, hook, in, out, link->table);
+ rcu_read_unlock();
+ return verdict;
}
static struct nf_hook_ops *rawtable_ops __read_mostly;
@@ -33,21 +40,23 @@ static struct nf_hook_ops *rawtable_ops __read_mostly;
static int __net_init ip6table_raw_net_init(struct net *net)
{
struct ip6t_replace *repl;
+ struct xt2_table *table;
repl = ip6t_alloc_initial_table(&packet_raw);
if (repl == NULL)
return -ENOMEM;
- net->ipv6.ip6table_raw =
- ip6t_register_table(net, &packet_raw, repl);
+ table = ip6t2_register_table(net, &packet_raw, repl);
kfree(repl);
- if (IS_ERR(net->ipv6.ip6table_raw))
- return PTR_ERR(net->ipv6.ip6table_raw);
+ if (IS_ERR(table))
+ return PTR_ERR(table);
+ net->xt2.ipv6_raw = xt2_tlink_lookup(net, table->name,
+ table->nfproto, XT2_STD_RCULOCK);
return 0;
}
static void __net_exit ip6table_raw_net_exit(struct net *net)
{
- ip6t_unregister_table(net, net->ipv6.ip6table_raw);
+ xt2_table_destroy(net, net->xt2.ipv6_raw->table);
}
static struct pernet_operations ip6table_raw_net_ops = {
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
index 91aa2b4..8746620 100644
--- a/net/ipv6/netfilter/ip6table_security.c
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -42,8 +42,14 @@ ip6table_security_hook(unsigned int hook, struct sk_buff *skb,
int (*okfn)(struct sk_buff *))
{
const struct net *net = dev_net((in != NULL) ? in : out);
-
- return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_security);
+ const struct xt2_table_link *link;
+ unsigned int verdict;
+
+ rcu_read_lock();
+ link = rcu_dereference(net->xt2.ipv6_security);
+ verdict = xt2_do_table(skb, hook, in, out, link->table);
+ rcu_read_unlock();
+ return verdict;
}
static struct nf_hook_ops *sectbl_ops __read_mostly;
@@ -51,22 +57,24 @@ static struct nf_hook_ops *sectbl_ops __read_mostly;
static int __net_init ip6table_security_net_init(struct net *net)
{
struct ip6t_replace *repl;
+ struct xt2_table *table;
repl = ip6t_alloc_initial_table(&security_table);
if (repl == NULL)
return -ENOMEM;
- net->ipv6.ip6table_security =
- ip6t_register_table(net, &security_table, repl);
+ table = ip6t2_register_table(net, &security_table, repl);
kfree(repl);
- if (IS_ERR(net->ipv6.ip6table_security))
- return PTR_ERR(net->ipv6.ip6table_security);
-
+ if (IS_ERR(table))
+ return PTR_ERR(table);
+ net->xt2.ipv6_security = xt2_tlink_lookup(net, table->name,
+ table->nfproto,
+ XT2_STD_RCULOCK);
return 0;
}
static void __net_exit ip6table_security_net_exit(struct net *net)
{
- ip6t_unregister_table(net, net->ipv6.ip6table_security);
+ xt2_table_destroy(net, net->xt2.ipv6_security->table);
}
static struct pernet_operations ip6table_security_net_ops = {
--
1.7.1
^ permalink raw reply related [flat|nested] 46+ messages in thread* Re: xt2 table core [*/33, not */56]
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (32 preceding siblings ...)
2010-06-29 8:43 ` [PATCH 33/56] netfilter: xtables2: switch ip6's tables to the xt2 table format Jan Engelhardt
@ 2010-06-29 8:47 ` Jan Engelhardt
2010-07-02 3:32 ` xt2 table core Simon Lodal
34 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-06-29 8:47 UTC (permalink / raw)
To: Netfilter Developer Mailing List; +Cc: Patrick McHardy
On Tuesday 2010-06-29 10:42, Jan Engelhardt wrote:
>
>Hi,
>
>
>This patchset adds the xtables2 main proper, and incrementally
>changes ip6_tables to use it. There are more patches for iptables
>and arptables and, but to not make it larger than needed, just this
>much for now.
>
>Previously featured on http://lwn.net/Articles/345176/ .
>
>Jan Engelhardt (33):
[...not 56...]
^ permalink raw reply [flat|nested] 46+ messages in thread* Re: xt2 table core
2010-06-29 8:42 xt2 table core Jan Engelhardt
` (33 preceding siblings ...)
2010-06-29 8:47 ` xt2 table core [*/33, not */56] Jan Engelhardt
@ 2010-07-02 3:32 ` Simon Lodal
2010-07-04 13:56 ` Jan Engelhardt
34 siblings, 1 reply; 46+ messages in thread
From: Simon Lodal @ 2010-07-02 3:32 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: netfilter-devel, kaber
Tirsdag 29 juni 2010 10:42:40 skrev Jan Engelhardt:
> Hi,
>
>
> This patchset adds the xtables2 main proper, and incrementally
> changes ip6_tables to use it. There are more patches for iptables
> and arptables and, but to not make it larger than needed, just this
> much for now.
>
> Previously featured on http://lwn.net/Articles/345176/ .
>
> The full piece is in the xt2-20100629 branch and would look like:
> 38 files changed, 3361 insertions(+), 5644 deletions(-)
> [40% reduction; the remaining 10% were merged already]
>
>
> Please leave some comments!
Nice to see some new development! Guess we all have a long wishlist that is
hard to implement in the current design, and this may make it easier.
But what about performance? I think all these lists must cause a huge amount
of jumps in hot path (eg. filtering packets). The packed blob format is hard to
work with, but once created it is efficient. Do you have any expectations or
even numbers on the performance?
Simon
^ permalink raw reply [flat|nested] 46+ messages in thread* Re: xt2 table core
2010-07-02 3:32 ` xt2 table core Simon Lodal
@ 2010-07-04 13:56 ` Jan Engelhardt
2010-07-04 17:22 ` Simon Lodal
` (2 more replies)
0 siblings, 3 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-07-04 13:56 UTC (permalink / raw)
To: Simon Lodal; +Cc: netfilter-devel, kaber
On Friday 2010-07-02 05:32, Simon Lodal wrote:
>>
>> This patchset adds the xtables2 main proper, and incrementally
>> changes ip6_tables to use it. There are more patches for iptables
>> and arptables and, but to not make it larger than needed, just this
>> much for now.
>>
>> Previously featured on http://lwn.net/Articles/345176/ .
>
>Nice to see some new development! Guess we all have a long wishlist that is
>hard to implement in the current design, and this may make it easier.
>
>But what about performance? I think all these lists must cause a huge amount
>of jumps in hot path (eg. filtering packets). The packed blob format is hard to
>work with, but once created it is efficient. Do you have any expectations or
>even numbers on the performance?
Your suspicion was right, linked lists seem to have their impact.
The command I used was
ping6 localhost -fc 500 -i .001
this sends 500 packets in near-flood fashion (-i0 would lead to
packet drops).
Xtables1 blob-style 2.6.31-rc4:
500 packets transmitted, 500 received, 0% packet loss, time 3532ms
500 packets transmitted, 500 received, 0% packet loss, time 3428ms
500 packets transmitted, 500 received, 0% packet loss, time 3388ms
500 packets transmitted, 500 received, 0% packet loss, time 3339ms
500 packets transmitted, 500 received, 0% packet loss, time 3219ms
Xtables1 blob-style 2.6.34:
500 packets transmitted, 500 received, 0% packet loss, time 3405ms
500 packets transmitted, 500 received, 0% packet loss, time 3525ms
500 packets transmitted, 500 received, 0% packet loss, time 3426ms
500 packets transmitted, 500 received, 0% packet loss, time 3388ms
500 packets transmitted, 500 received, 0% packet loss, time 3328ms
Xtables2 (linked lists) 2.6.35-rc1:
500 packets transmitted, 500 received, 0% packet loss, time 14775ms
500 packets transmitted, 500 received, 0% packet loss, time 14383ms
500 packets transmitted, 500 received, 0% packet loss, time 14381ms
500 packets transmitted, 500 received, 0% packet loss, time 15432ms
500 packets transmitted, 500 received, 0% packet loss, time 14498ms
nftables (uses linked lists) 2.6.31-rc4:
500 packets transmitted, 500 received, 0% packet loss, time 16198ms
500 packets transmitted, 500 received, 0% packet loss, time 16128ms
500 packets transmitted, 500 received, 0% packet loss, time 16492ms
500 packets transmitted, 500 received, 0% packet loss, time 16451ms
500 packets transmitted, 500 received, 0% packet loss, time 16475ms
Well I guess Xt2 isn't the total backlight :-)
Do you have any suggestions for improvement though?
^ permalink raw reply [flat|nested] 46+ messages in thread* Re: xt2 table core
2010-07-04 13:56 ` Jan Engelhardt
@ 2010-07-04 17:22 ` Simon Lodal
2010-07-04 18:00 ` Jan Engelhardt
2010-07-05 8:55 ` Patrick McHardy
2010-07-05 9:36 ` Eric Dumazet
2 siblings, 1 reply; 46+ messages in thread
From: Simon Lodal @ 2010-07-04 17:22 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: netfilter-devel, kaber
Søndag 04 juli 2010 15:56:03 skrev Jan Engelhardt:
> On Friday 2010-07-02 05:32, Simon Lodal wrote:
> >> This patchset adds the xtables2 main proper, and incrementally
> >> changes ip6_tables to use it. There are more patches for iptables
> >> and arptables and, but to not make it larger than needed, just this
> >> much for now.
> >>
> >> Previously featured on http://lwn.net/Articles/345176/ .
> >
> >Nice to see some new development! Guess we all have a long wishlist that
> >is hard to implement in the current design, and this may make it easier.
> >
> >But what about performance? I think all these lists must cause a huge
> >amount of jumps in hot path (eg. filtering packets). The packed blob
> >format is hard to work with, but once created it is efficient. Do you
> >have any expectations or even numbers on the performance?
>
> Your suspicion was right, linked lists seem to have their impact.
>
> The command I used was
>
> ping6 localhost -fc 500 -i .001
>
> this sends 500 packets in near-flood fashion (-i0 would lead to
> packet drops).
>
> Xtables1 blob-style 2.6.31-rc4:
> 500 packets transmitted, 500 received, 0% packet loss, time 3532ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3428ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3388ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3339ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3219ms
>
> Xtables1 blob-style 2.6.34:
> 500 packets transmitted, 500 received, 0% packet loss, time 3405ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3525ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3426ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3388ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3328ms
>
> Xtables2 (linked lists) 2.6.35-rc1:
> 500 packets transmitted, 500 received, 0% packet loss, time 14775ms
> 500 packets transmitted, 500 received, 0% packet loss, time 14383ms
> 500 packets transmitted, 500 received, 0% packet loss, time 14381ms
> 500 packets transmitted, 500 received, 0% packet loss, time 15432ms
> 500 packets transmitted, 500 received, 0% packet loss, time 14498ms
>
> nftables (uses linked lists) 2.6.31-rc4:
> 500 packets transmitted, 500 received, 0% packet loss, time 16198ms
> 500 packets transmitted, 500 received, 0% packet loss, time 16128ms
> 500 packets transmitted, 500 received, 0% packet loss, time 16492ms
> 500 packets transmitted, 500 received, 0% packet loss, time 16451ms
> 500 packets transmitted, 500 received, 0% packet loss, time 16475ms
>
> Well I guess Xt2 isn't the total backlight :-)
>
> Do you have any suggestions for improvement though?
Interesting.
I think it is a question of granularity. At what level do we use lists, vs.
blobs? It seems to be a flexibility/performance tradeoff. I have hundreds of
kpps 24/7 and rarely reload rules, so I am strictly in the performance camp
:-)
Chain granularity that we have now is maybe too big. Match/target granularity
that you use is apparently too small. Also, is the ability to edit matches and
targets really useful? Perhaps rule granularity (keep each rule as one blob)
is right.
Another thought, though beyond the scope of this patchset: The kernel side
could have two rulesets:
1) In linked lists (like your patch), what userspace sees.
2) Big packed blobs, generated in kernel from the lists; what filtering
actually runs off.
So userspace gets flexibility, and kernel side gets performance, plus dealing
with packaging the blob, copying it NR_CPU times, swapping it in atomically.
Simon
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: xt2 table core
2010-07-04 17:22 ` Simon Lodal
@ 2010-07-04 18:00 ` Jan Engelhardt
0 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-07-04 18:00 UTC (permalink / raw)
To: Simon Lodal; +Cc: netfilter-devel, kaber
On Sunday 2010-07-04 19:22, Simon Lodal wrote:
>
>I think it is a question of granularity. At what level do we use lists, vs.
>blobs? It seems to be a flexibility/performance tradeoff. I have hundreds of
>kpps 24/7 and rarely reload rules, so I am strictly in the performance camp
>:-)
>
>Chain granularity that we have now is maybe too big.
Xt1 has table-level granularity. And the problem with blobs is that
you first need to find a memory area large enough to fit it in - which
is why vmalloc is already in use today.
>Match/target granularity
>that you use is apparently too small. Also, is the ability to edit matches and
>targets really useful? Perhaps rule granularity (keep each rule as one blob)
>is right.
I'll try.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: xt2 table core
2010-07-04 13:56 ` Jan Engelhardt
2010-07-04 17:22 ` Simon Lodal
@ 2010-07-05 8:55 ` Patrick McHardy
2010-07-05 9:13 ` Jan Engelhardt
2010-07-05 9:36 ` Eric Dumazet
2 siblings, 1 reply; 46+ messages in thread
From: Patrick McHardy @ 2010-07-05 8:55 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: Simon Lodal, netfilter-devel
Jan Engelhardt wrote:
> On Friday 2010-07-02 05:32, Simon Lodal wrote:
>
>>> This patchset adds the xtables2 main proper, and incrementally
>>> changes ip6_tables to use it. There are more patches for iptables
>>> and arptables and, but to not make it larger than needed, just this
>>> much for now.
>>>
>>> Previously featured on http://lwn.net/Articles/345176/ .
>>>
>> Nice to see some new development! Guess we all have a long wishlist that is
>> hard to implement in the current design, and this may make it easier.
>>
>> But what about performance? I think all these lists must cause a huge amount
>> of jumps in hot path (eg. filtering packets). The packed blob format is hard to
>> work with, but once created it is efficient. Do you have any expectations or
>> even numbers on the performance?
>>
>
> Your suspicion was right, linked lists seem to have their impact.
>
> The command I used was
>
> ping6 localhost -fc 500 -i .001
>
> this sends 500 packets in near-flood fashion (-i0 would lead to
> packet drops).
>
> Xtables1 blob-style 2.6.31-rc4:
> 500 packets transmitted, 500 received, 0% packet loss, time 3532ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3428ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3388ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3339ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3219ms
>
> Xtables1 blob-style 2.6.34:
> 500 packets transmitted, 500 received, 0% packet loss, time 3405ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3525ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3426ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3388ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3328ms
>
> Xtables2 (linked lists) 2.6.35-rc1:
> 500 packets transmitted, 500 received, 0% packet loss, time 14775ms
> 500 packets transmitted, 500 received, 0% packet loss, time 14383ms
> 500 packets transmitted, 500 received, 0% packet loss, time 14381ms
> 500 packets transmitted, 500 received, 0% packet loss, time 15432ms
> 500 packets transmitted, 500 received, 0% packet loss, time 14498ms
>
While this is probably a pretty bad test, you can't seriously expect
me to merge something that degrades performance by 400% for all users?
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: xt2 table core
2010-07-04 13:56 ` Jan Engelhardt
2010-07-04 17:22 ` Simon Lodal
2010-07-05 8:55 ` Patrick McHardy
@ 2010-07-05 9:36 ` Eric Dumazet
2010-07-05 9:42 ` Jan Engelhardt
2 siblings, 1 reply; 46+ messages in thread
From: Eric Dumazet @ 2010-07-05 9:36 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: Simon Lodal, netfilter-devel, kaber
Le dimanche 04 juillet 2010 à 15:56 +0200, Jan Engelhardt a écrit :
> On Friday 2010-07-02 05:32, Simon Lodal wrote:
> >>
> >> This patchset adds the xtables2 main proper, and incrementally
> >> changes ip6_tables to use it. There are more patches for iptables
> >> and arptables and, but to not make it larger than needed, just this
> >> much for now.
> >>
> >> Previously featured on http://lwn.net/Articles/345176/ .
> >
> >Nice to see some new development! Guess we all have a long wishlist that is
> >hard to implement in the current design, and this may make it easier.
> >
> >But what about performance? I think all these lists must cause a huge amount
> >of jumps in hot path (eg. filtering packets). The packed blob format is hard to
> >work with, but once created it is efficient. Do you have any expectations or
> >even numbers on the performance?
>
> Your suspicion was right, linked lists seem to have their impact.
>
> The command I used was
>
> ping6 localhost -fc 500 -i .001
>
> this sends 500 packets in near-flood fashion (-i0 would lead to
> packet drops).
>
> Xtables1 blob-style 2.6.31-rc4:
> 500 packets transmitted, 500 received, 0% packet loss, time 3532ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3428ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3388ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3339ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3219ms
>
> Xtables1 blob-style 2.6.34:
> 500 packets transmitted, 500 received, 0% packet loss, time 3405ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3525ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3426ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3388ms
> 500 packets transmitted, 500 received, 0% packet loss, time 3328ms
>
> Xtables2 (linked lists) 2.6.35-rc1:
> 500 packets transmitted, 500 received, 0% packet loss, time 14775ms
> 500 packets transmitted, 500 received, 0% packet loss, time 14383ms
> 500 packets transmitted, 500 received, 0% packet loss, time 14381ms
> 500 packets transmitted, 500 received, 0% packet loss, time 15432ms
> 500 packets transmitted, 500 received, 0% packet loss, time 14498ms
>
> nftables (uses linked lists) 2.6.31-rc4:
> 500 packets transmitted, 500 received, 0% packet loss, time 16198ms
> 500 packets transmitted, 500 received, 0% packet loss, time 16128ms
> 500 packets transmitted, 500 received, 0% packet loss, time 16492ms
> 500 packets transmitted, 500 received, 0% packet loss, time 16451ms
> 500 packets transmitted, 500 received, 0% packet loss, time 16475ms
>
> Well I guess Xt2 isn't the total backlight :-)
>
> Do you have any suggestions for improvement though?
>
I dont understand how it is possible to spend so much time per packet,
just adding few pointers :)
Are you sure you dont hit another problem ?
Could you give us the rules you use ?
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: xt2 table core
2010-07-05 9:36 ` Eric Dumazet
@ 2010-07-05 9:42 ` Jan Engelhardt
2010-07-05 10:22 ` Eric Dumazet
0 siblings, 1 reply; 46+ messages in thread
From: Jan Engelhardt @ 2010-07-05 9:42 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Simon Lodal, netfilter-devel, kaber
[-- Attachment #1: Type: TEXT/PLAIN, Size: 990 bytes --]
On Monday 2010-07-05 11:36, Eric Dumazet wrote:
>> The command I used was
>>
>> ping6 localhost -fc 500 -i .001
>>
>> this sends 500 packets in near-flood fashion (-i0 would lead to
>> packet drops).
>>
>> Xtables1 blob-style 2.6.31-rc4:
>> 500 packets transmitted, 500 received, 0% packet loss, time 3532ms
>> Xtables1 blob-style 2.6.34:
>> 500 packets transmitted, 500 received, 0% packet loss, time 3405ms
>> Xtables2 (linked lists) 2.6.35-rc1:
>> 500 packets transmitted, 500 received, 0% packet loss, time 14775ms
>> nftables (uses linked lists) 2.6.31-rc4:
>> 500 packets transmitted, 500 received, 0% packet loss, time 16198ms
>>
>> Do you have any suggestions for improvement though?
>
>I dont understand how it is possible to spend so much time per packet,
>just adding few pointers :)
>Are you sure you dont hit another problem ?
If you see where this went awry, I'd be grateful. (The tests have been
run on a single CPU.)
>Could you give us the rules you use ?
Attached.
[-- Attachment #2: Type: APPLICATION/octet-stream, Size: 1072 bytes --]
[-- Attachment #3: Type: APPLICATION/octet-stream, Size: 1252 bytes --]
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: xt2 table core
2010-07-05 9:42 ` Jan Engelhardt
@ 2010-07-05 10:22 ` Eric Dumazet
2010-07-05 10:34 ` Jan Engelhardt
0 siblings, 1 reply; 46+ messages in thread
From: Eric Dumazet @ 2010-07-05 10:22 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: Simon Lodal, netfilter-devel, kaber
Le lundi 05 juillet 2010 à 11:42 +0200, Jan Engelhardt a écrit :
> If you see where this went awry, I'd be grateful. (The tests have been
> run on a single CPU.)
Oh well, thats huge, I could not load them on my (32bit, 8 cpus) dev
machine :)
[ 7838.882153] vmap allocation for size 19869696 failed: use
vmalloc=<size> to increase size.
I guess size of your rules, went from 20 Mbytes per cpu to say... 160
MBytes on xt2 ?
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: xt2 table core
2010-07-05 10:22 ` Eric Dumazet
@ 2010-07-05 10:34 ` Jan Engelhardt
0 siblings, 0 replies; 46+ messages in thread
From: Jan Engelhardt @ 2010-07-05 10:34 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Simon Lodal, netfilter-devel, kaber
On Monday 2010-07-05 12:22, Eric Dumazet wrote:
>Le lundi 05 juillet 2010 à 11:42 +0200, Jan Engelhardt a écrit :
>
>> If you see where this went awry, I'd be grateful. (The tests have been
>> run on a single CPU.)
>
>Oh well, thats huge, I could not load them on my (32bit, 8 cpus) dev
>machine :)
Wuss? I was able to load it into 64-bit VM configured with 1 GB RAM.
>[ 7838.882153] vmap allocation for size 19869696 failed: use
>vmalloc=<size> to increase size.
>
>I guess size of your rules, went from 20 Mbytes per cpu to say... 160
>MBytes on xt2 ?
As a side-effect of multiple allocations of non-blob structures,
probably so.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 46+ messages in thread