|
@@ -51,12 +51,7 @@ MODULE_DESCRIPTION("IPv4 packet filter");
|
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_NETFILTER_DEBUG
|
|
|
-#define IP_NF_ASSERT(x) \
|
|
|
-do { \
|
|
|
- if (!(x)) \
|
|
|
- printk("IP_NF_ASSERT: %s:%s:%u\n", \
|
|
|
- __func__, __FILE__, __LINE__); \
|
|
|
-} while(0)
|
|
|
+#define IP_NF_ASSERT(x) WARN_ON(!(x))
|
|
|
#else
|
|
|
#define IP_NF_ASSERT(x)
|
|
|
#endif
|
|
@@ -165,7 +160,7 @@ ip_checkentry(const struct ipt_ip *ip)
|
|
|
}
|
|
|
|
|
|
static unsigned int
|
|
|
-ipt_error(struct sk_buff *skb, const struct xt_target_param *par)
|
|
|
+ipt_error(struct sk_buff *skb, const struct xt_action_param *par)
|
|
|
{
|
|
|
if (net_ratelimit())
|
|
|
pr_info("error: `%s'\n", (const char *)par->targinfo);
|
|
@@ -173,21 +168,6 @@ ipt_error(struct sk_buff *skb, const struct xt_target_param *par)
|
|
|
return NF_DROP;
|
|
|
}
|
|
|
|
|
|
-/* Performance critical - called for every packet */
|
|
|
-static inline bool
|
|
|
-do_match(const struct ipt_entry_match *m, const struct sk_buff *skb,
|
|
|
- struct xt_match_param *par)
|
|
|
-{
|
|
|
- par->match = m->u.kernel.match;
|
|
|
- par->matchinfo = m->data;
|
|
|
-
|
|
|
- /* Stop iteration if it doesn't match */
|
|
|
- if (!m->u.kernel.match->match(skb, par))
|
|
|
- return true;
|
|
|
- else
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
/* Performance critical */
|
|
|
static inline struct ipt_entry *
|
|
|
get_entry(const void *base, unsigned int offset)
|
|
@@ -323,7 +303,6 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
{
|
|
|
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
|
|
|
const struct iphdr *ip;
|
|
|
- bool hotdrop = false;
|
|
|
/* Initializing verdict to NF_DROP keeps gcc happy. */
|
|
|
unsigned int verdict = NF_DROP;
|
|
|
const char *indev, *outdev;
|
|
@@ -331,8 +310,7 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
struct ipt_entry *e, **jumpstack;
|
|
|
unsigned int *stackptr, origptr, cpu;
|
|
|
const struct xt_table_info *private;
|
|
|
- struct xt_match_param mtpar;
|
|
|
- struct xt_target_param tgpar;
|
|
|
+ struct xt_action_param acpar;
|
|
|
|
|
|
/* Initialization */
|
|
|
ip = ip_hdr(skb);
|
|
@@ -344,13 +322,13 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
* things we don't know, ie. tcp syn flag or ports). If the
|
|
|
* rule is also a fragment-specific rule, non-fragments won't
|
|
|
* match it. */
|
|
|
- mtpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
|
|
|
- mtpar.thoff = ip_hdrlen(skb);
|
|
|
- mtpar.hotdrop = &hotdrop;
|
|
|
- mtpar.in = tgpar.in = in;
|
|
|
- mtpar.out = tgpar.out = out;
|
|
|
- mtpar.family = tgpar.family = NFPROTO_IPV4;
|
|
|
- mtpar.hooknum = tgpar.hooknum = hook;
|
|
|
+ acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
|
|
|
+ acpar.thoff = ip_hdrlen(skb);
|
|
|
+ acpar.hotdrop = false;
|
|
|
+ acpar.in = in;
|
|
|
+ acpar.out = out;
|
|
|
+ acpar.family = NFPROTO_IPV4;
|
|
|
+ acpar.hooknum = hook;
|
|
|
|
|
|
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
|
|
|
xt_info_rdlock_bh();
|
|
@@ -373,15 +351,18 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
|
|
|
IP_NF_ASSERT(e);
|
|
|
if (!ip_packet_match(ip, indev, outdev,
|
|
|
- &e->ip, mtpar.fragoff)) {
|
|
|
+ &e->ip, acpar.fragoff)) {
|
|
|
no_match:
|
|
|
e = ipt_next_entry(e);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- xt_ematch_foreach(ematch, e)
|
|
|
- if (do_match(ematch, skb, &mtpar) != 0)
|
|
|
+ xt_ematch_foreach(ematch, e) {
|
|
|
+ acpar.match = ematch->u.kernel.match;
|
|
|
+ acpar.matchinfo = ematch->data;
|
|
|
+ if (!acpar.match->match(skb, &acpar))
|
|
|
goto no_match;
|
|
|
+ }
|
|
|
|
|
|
ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
|
|
|
|
|
@@ -434,11 +415,10 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- tgpar.target = t->u.kernel.target;
|
|
|
- tgpar.targinfo = t->data;
|
|
|
-
|
|
|
+ acpar.target = t->u.kernel.target;
|
|
|
+ acpar.targinfo = t->data;
|
|
|
|
|
|
- verdict = t->u.kernel.target->target(skb, &tgpar);
|
|
|
+ verdict = t->u.kernel.target->target(skb, &acpar);
|
|
|
/* Target might have changed stuff. */
|
|
|
ip = ip_hdr(skb);
|
|
|
if (verdict == IPT_CONTINUE)
|
|
@@ -446,7 +426,7 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
else
|
|
|
/* Verdict */
|
|
|
break;
|
|
|
- } while (!hotdrop);
|
|
|
+ } while (!acpar.hotdrop);
|
|
|
xt_info_rdunlock_bh();
|
|
|
pr_debug("Exiting %s; resetting sp from %u to %u\n",
|
|
|
__func__, *stackptr, origptr);
|
|
@@ -454,7 +434,7 @@ ipt_do_table(struct sk_buff *skb,
|
|
|
#ifdef DEBUG_ALLOW_ALL
|
|
|
return NF_ACCEPT;
|
|
|
#else
|
|
|
- if (hotdrop)
|
|
|
+ if (acpar.hotdrop)
|
|
|
return NF_DROP;
|
|
|
else return verdict;
|
|
|
#endif
|
|
@@ -486,7 +466,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
|
|
|
int visited = e->comefrom & (1 << hook);
|
|
|
|
|
|
if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
|
|
|
- printk("iptables: loop hook %u pos %u %08X.\n",
|
|
|
+ pr_err("iptables: loop hook %u pos %u %08X.\n",
|
|
|
hook, pos, e->comefrom);
|
|
|
return 0;
|
|
|
}
|
|
@@ -591,7 +571,7 @@ check_entry(const struct ipt_entry *e, const char *name)
|
|
|
const struct ipt_entry_target *t;
|
|
|
|
|
|
if (!ip_checkentry(&e->ip)) {
|
|
|
- duprintf("ip check failed %p %s.\n", e, name);
|
|
|
+ duprintf("ip check failed %p %s.\n", e, par->match->name);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
@@ -618,7 +598,7 @@ check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par)
|
|
|
ret = xt_check_match(par, m->u.match_size - sizeof(*m),
|
|
|
ip->proto, ip->invflags & IPT_INV_PROTO);
|
|
|
if (ret < 0) {
|
|
|
- duprintf("check failed for `%s'.\n", par.match->name);
|
|
|
+ duprintf("check failed for `%s'.\n", par->match->name);
|
|
|
return ret;
|
|
|
}
|
|
|
return 0;
|
|
@@ -2152,7 +2132,7 @@ icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
|
|
|
}
|
|
|
|
|
|
static bool
|
|
|
-icmp_match(const struct sk_buff *skb, const struct xt_match_param *par)
|
|
|
+icmp_match(const struct sk_buff *skb, struct xt_action_param *par)
|
|
|
{
|
|
|
const struct icmphdr *ic;
|
|
|
struct icmphdr _icmph;
|
|
@@ -2168,7 +2148,7 @@ icmp_match(const struct sk_buff *skb, const struct xt_match_param *par)
|
|
|
* can't. Hence, no choice but to drop.
|
|
|
*/
|
|
|
duprintf("Dropping evil ICMP tinygram.\n");
|
|
|
- *par->hotdrop = true;
|
|
|
+ par->hotdrop = true;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -2187,23 +2167,23 @@ static int icmp_checkentry(const struct xt_mtchk_param *par)
|
|
|
return (icmpinfo->invflags & ~IPT_ICMP_INV) ? -EINVAL : 0;
|
|
|
}
|
|
|
|
|
|
-/* The built-in targets: standard (NULL) and error. */
|
|
|
-static struct xt_target ipt_standard_target __read_mostly = {
|
|
|
- .name = IPT_STANDARD_TARGET,
|
|
|
- .targetsize = sizeof(int),
|
|
|
- .family = NFPROTO_IPV4,
|
|
|
+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,
|
|
|
+ .compatsize = sizeof(compat_int_t),
|
|
|
+ .compat_from_user = compat_standard_from_user,
|
|
|
+ .compat_to_user = compat_standard_to_user,
|
|
|
#endif
|
|
|
-};
|
|
|
-
|
|
|
-static struct xt_target ipt_error_target __read_mostly = {
|
|
|
- .name = IPT_ERROR_TARGET,
|
|
|
- .target = ipt_error,
|
|
|
- .targetsize = IPT_FUNCTION_MAXNAMELEN,
|
|
|
- .family = NFPROTO_IPV4,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = IPT_ERROR_TARGET,
|
|
|
+ .target = ipt_error,
|
|
|
+ .targetsize = IPT_FUNCTION_MAXNAMELEN,
|
|
|
+ .family = NFPROTO_IPV4,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static struct nf_sockopt_ops ipt_sockopts = {
|
|
@@ -2223,13 +2203,15 @@ static struct nf_sockopt_ops ipt_sockopts = {
|
|
|
.owner = THIS_MODULE,
|
|
|
};
|
|
|
|
|
|
-static struct xt_match icmp_matchstruct __read_mostly = {
|
|
|
- .name = "icmp",
|
|
|
- .match = icmp_match,
|
|
|
- .matchsize = sizeof(struct ipt_icmp),
|
|
|
- .checkentry = icmp_checkentry,
|
|
|
- .proto = IPPROTO_ICMP,
|
|
|
- .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,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static int __net_init ip_tables_net_init(struct net *net)
|
|
@@ -2256,13 +2238,10 @@ static int __init ip_tables_init(void)
|
|
|
goto err1;
|
|
|
|
|
|
/* Noone else will be downing sem now, so we won't sleep */
|
|
|
- ret = xt_register_target(&ipt_standard_target);
|
|
|
+ ret = xt_register_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
|
|
|
if (ret < 0)
|
|
|
goto err2;
|
|
|
- ret = xt_register_target(&ipt_error_target);
|
|
|
- if (ret < 0)
|
|
|
- goto err3;
|
|
|
- ret = xt_register_match(&icmp_matchstruct);
|
|
|
+ ret = xt_register_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
|
|
|
if (ret < 0)
|
|
|
goto err4;
|
|
|
|
|
@@ -2275,11 +2254,9 @@ static int __init ip_tables_init(void)
|
|
|
return 0;
|
|
|
|
|
|
err5:
|
|
|
- xt_unregister_match(&icmp_matchstruct);
|
|
|
+ xt_unregister_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
|
|
|
err4:
|
|
|
- xt_unregister_target(&ipt_error_target);
|
|
|
-err3:
|
|
|
- xt_unregister_target(&ipt_standard_target);
|
|
|
+ xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
|
|
|
err2:
|
|
|
unregister_pernet_subsys(&ip_tables_net_ops);
|
|
|
err1:
|
|
@@ -2290,10 +2267,8 @@ static void __exit ip_tables_fini(void)
|
|
|
{
|
|
|
nf_unregister_sockopt(&ipt_sockopts);
|
|
|
|
|
|
- xt_unregister_match(&icmp_matchstruct);
|
|
|
- xt_unregister_target(&ipt_error_target);
|
|
|
- xt_unregister_target(&ipt_standard_target);
|
|
|
-
|
|
|
+ xt_unregister_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
|
|
|
+ xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
|
|
|
unregister_pernet_subsys(&ip_tables_net_ops);
|
|
|
}
|
|
|
|