Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6

This commit is contained in:
David S. Miller
2009-03-24 13:24:36 -07:00
71 changed files with 1627 additions and 785 deletions
+63
View File
@@ -357,6 +357,45 @@ config NETFILTER_XT_TARGET_DSCP
To compile it as a module, choose M here. If unsure, say N.
config NETFILTER_XT_TARGET_HL
tristate '"HL" hoplimit target support'
depends on IP_NF_MANGLE || IP6_NF_MANGLE
depends on NETFILTER_ADVANCED
---help---
This option adds the "HL" (for IPv6) and "TTL" (for IPv4)
targets, which enable the user to change the
hoplimit/time-to-live value of the IP header.
While it is safe to decrement the hoplimit/TTL value, the
modules also allow to increment and set the hoplimit value of
the header to arbitrary values. This is EXTREMELY DANGEROUS
since you can easily create immortal packets that loop
forever on the network.
config NETFILTER_XT_TARGET_LED
tristate '"LED" target support'
depends on LEDS_CLASS
depends on NETFILTER_ADVANCED
help
This option adds a `LED' target, which allows you to blink LEDs in
response to particular packets passing through your machine.
This can be used to turn a spare LED into a network activity LED,
which only flashes in response to FTP transfers, for example. Or
you could have an LED which lights up for a minute or two every time
somebody connects to your machine via SSH.
You will need support for the "led" class to make this work.
To create an LED trigger for incoming SSH traffic:
iptables -A INPUT -p tcp --dport 22 -j LED --led-trigger-id ssh --led-delay 1000
Then attach the new trigger to an LED on your system:
echo netfilter-ssh > /sys/class/leds/<ledname>/trigger
For more information on the LEDs available on your system, see
Documentation/leds-class.txt
config NETFILTER_XT_TARGET_MARK
tristate '"MARK" target support'
default m if NETFILTER_ADVANCED=n
@@ -488,6 +527,22 @@ config NETFILTER_XT_TARGET_TCPOPTSTRIP
This option adds a "TCPOPTSTRIP" target, which allows you to strip
TCP options from TCP packets.
config NETFILTER_XT_MATCH_CLUSTER
tristate '"cluster" match support'
depends on NF_CONNTRACK
depends on NETFILTER_ADVANCED
---help---
This option allows you to build work-load-sharing clusters of
network servers/stateful firewalls without having a dedicated
load-balancing router/server/switch. Basically, this match returns
true when the packet must be handled by this cluster node. Thus,
all nodes see all packets and this match decides which node handles
what packets. The work-load sharing algorithm is based on source
address hashing.
If you say Y or M here, try `iptables -m cluster --help` for
more information.
config NETFILTER_XT_MATCH_COMMENT
tristate '"comment" match support'
depends on NETFILTER_ADVANCED
@@ -605,6 +660,14 @@ config NETFILTER_XT_MATCH_HELPER
To compile it as a module, choose M here. If unsure, say Y.
config NETFILTER_XT_MATCH_HL
tristate '"hl" hoplimit/TTL match support'
depends on NETFILTER_ADVANCED
---help---
HL matching allows you to match packets based on the hoplimit
in the IPv6 header, or the time-to-live field in the IPv4
header of the packet.
config NETFILTER_XT_MATCH_IPRANGE
tristate '"iprange" address range match support'
depends on NETFILTER_ADVANCED
+4
View File
@@ -45,6 +45,8 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
@@ -57,6 +59,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
# matches
obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
@@ -67,6 +70,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o
obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
-2
View File
@@ -174,7 +174,6 @@ next_hook:
outdev, &elem, okfn, hook_thresh);
if (verdict == NF_ACCEPT || verdict == NF_STOP) {
ret = 1;
goto unlock;
} else if (verdict == NF_DROP) {
kfree_skb(skb);
ret = -EPERM;
@@ -183,7 +182,6 @@ next_hook:
verdict >> NF_VERDICT_BITS))
goto next_hook;
}
unlock:
rcu_read_unlock();
return ret;
}
+9 -5
View File
@@ -54,7 +54,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_lock);
unsigned int nf_conntrack_htable_size __read_mostly;
EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
int nf_conntrack_max __read_mostly;
unsigned int nf_conntrack_max __read_mostly;
EXPORT_SYMBOL_GPL(nf_conntrack_max);
struct nf_conn nf_conntrack_untracked __read_mostly;
@@ -472,7 +472,8 @@ struct nf_conn *nf_conntrack_alloc(struct net *net,
struct nf_conn *ct;
if (unlikely(!nf_conntrack_hash_rnd_initted)) {
get_random_bytes(&nf_conntrack_hash_rnd, 4);
get_random_bytes(&nf_conntrack_hash_rnd,
sizeof(nf_conntrack_hash_rnd));
nf_conntrack_hash_rnd_initted = 1;
}
@@ -516,16 +517,17 @@ EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
static void nf_conntrack_free_rcu(struct rcu_head *head)
{
struct nf_conn *ct = container_of(head, struct nf_conn, rcu);
struct net *net = nf_ct_net(ct);
nf_ct_ext_free(ct);
kmem_cache_free(nf_conntrack_cachep, ct);
atomic_dec(&net->ct.count);
}
void nf_conntrack_free(struct nf_conn *ct)
{
struct net *net = nf_ct_net(ct);
nf_ct_ext_destroy(ct);
atomic_dec(&net->ct.count);
call_rcu(&ct->rcu, nf_conntrack_free_rcu);
}
EXPORT_SYMBOL_GPL(nf_conntrack_free);
@@ -733,6 +735,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
NF_CT_STAT_INC_ATOMIC(net, invalid);
if (ret == -NF_DROP)
NF_CT_STAT_INC_ATOMIC(net, drop);
return -ret;
}
@@ -1103,7 +1107,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
/* We have to rehahs for the new table anyway, so we also can
* use a newrandom seed */
get_random_bytes(&rnd, 4);
get_random_bytes(&rnd, sizeof(rnd));
/* Lookups in the old hash might happen in parallel, which means we
* might get false negatives during connection lookup. New connections
+2 -1
View File
@@ -72,7 +72,8 @@ static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple
unsigned int hash;
if (unlikely(!nf_ct_expect_hash_rnd_initted)) {
get_random_bytes(&nf_ct_expect_hash_rnd, 4);
get_random_bytes(&nf_ct_expect_hash_rnd,
sizeof(nf_ct_expect_hash_rnd));
nf_ct_expect_hash_rnd_initted = 1;
}
+72 -89
View File
@@ -518,6 +518,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
nla_put_failure:
rcu_read_unlock();
nlmsg_failure:
nfnetlink_set_err(0, group, -ENOBUFS);
kfree_skb(skb);
return NOTIFY_DONE;
}
@@ -599,7 +600,8 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple)
nla_parse_nested(tb, CTA_IP_MAX, attr, NULL);
l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);
rcu_read_lock();
l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
if (likely(l3proto->nlattr_to_tuple)) {
ret = nla_validate_nested(attr, CTA_IP_MAX,
@@ -608,7 +610,7 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple)
ret = l3proto->nlattr_to_tuple(tb, tuple);
}
nf_ct_l3proto_put(l3proto);
rcu_read_unlock();
return ret;
}
@@ -633,7 +635,8 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr,
return -EINVAL;
tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]);
l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum);
rcu_read_lock();
l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
if (likely(l4proto->nlattr_to_tuple)) {
ret = nla_validate_nested(attr, CTA_PROTO_MAX,
@@ -642,7 +645,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr,
ret = l4proto->nlattr_to_tuple(tb, tuple);
}
nf_ct_l4proto_put(l4proto);
rcu_read_unlock();
return ret;
}
@@ -989,10 +992,11 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[])
nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL);
l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct));
rcu_read_lock();
l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
if (l4proto->from_nlattr)
err = l4proto->from_nlattr(tb, ct);
nf_ct_l4proto_put(l4proto);
rcu_read_unlock();
return err;
}
@@ -1062,6 +1066,10 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[])
{
int err;
/* only allow NAT changes and master assignation for new conntracks */
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST] || cda[CTA_TUPLE_MASTER])
return -EOPNOTSUPP;
if (cda[CTA_HELP]) {
err = ctnetlink_change_helper(ct, cda);
if (err < 0)
@@ -1124,13 +1132,11 @@ ctnetlink_event_report(struct nf_conn *ct, u32 pid, int report)
report);
}
static int
static struct nf_conn *
ctnetlink_create_conntrack(struct nlattr *cda[],
struct nf_conntrack_tuple *otuple,
struct nf_conntrack_tuple *rtuple,
struct nf_conn *master_ct,
u32 pid,
int report)
u8 u3)
{
struct nf_conn *ct;
int err = -EINVAL;
@@ -1138,10 +1144,10 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC);
if (IS_ERR(ct))
return -ENOMEM;
return ERR_PTR(-ENOMEM);
if (!cda[CTA_TIMEOUT])
goto err;
goto err1;
ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT]));
ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
@@ -1152,10 +1158,8 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
char *helpname;
err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
if (err < 0) {
rcu_read_unlock();
goto err;
}
if (err < 0)
goto err2;
helper = __nf_conntrack_helper_find_byname(helpname);
if (helper == NULL) {
@@ -1163,28 +1167,26 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
#ifdef CONFIG_MODULES
if (request_module("nfct-helper-%s", helpname) < 0) {
err = -EOPNOTSUPP;
goto err;
goto err1;
}
rcu_read_lock();
helper = __nf_conntrack_helper_find_byname(helpname);
if (helper) {
rcu_read_unlock();
err = -EAGAIN;
goto err;
goto err2;
}
rcu_read_unlock();
#endif
err = -EOPNOTSUPP;
goto err;
goto err1;
} else {
struct nf_conn_help *help;
help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
if (help == NULL) {
rcu_read_unlock();
err = -ENOMEM;
goto err;
goto err2;
}
/* not in hash table yet so not strictly necessary */
@@ -1193,44 +1195,34 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
} else {
/* try an implicit helper assignation */
err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
if (err < 0) {
rcu_read_unlock();
goto err;
}
if (err < 0)
goto err2;
}
if (cda[CTA_STATUS]) {
err = ctnetlink_change_status(ct, cda);
if (err < 0) {
rcu_read_unlock();
goto err;
}
if (err < 0)
goto err2;
}
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
err = ctnetlink_change_nat(ct, cda);
if (err < 0) {
rcu_read_unlock();
goto err;
}
if (err < 0)
goto err2;
}
#ifdef CONFIG_NF_NAT_NEEDED
if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) {
err = ctnetlink_change_nat_seq_adj(ct, cda);
if (err < 0) {
rcu_read_unlock();
goto err;
}
if (err < 0)
goto err2;
}
#endif
if (cda[CTA_PROTOINFO]) {
err = ctnetlink_change_protoinfo(ct, cda);
if (err < 0) {
rcu_read_unlock();
goto err;
}
if (err < 0)
goto err2;
}
nf_ct_acct_ext_add(ct, GFP_ATOMIC);
@@ -1241,23 +1233,37 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
#endif
/* setup master conntrack: this is a confirmed expectation */
if (master_ct) {
if (cda[CTA_TUPLE_MASTER]) {
struct nf_conntrack_tuple master;
struct nf_conntrack_tuple_hash *master_h;
struct nf_conn *master_ct;
err = ctnetlink_parse_tuple(cda, &master, CTA_TUPLE_MASTER, u3);
if (err < 0)
goto err2;
master_h = __nf_conntrack_find(&init_net, &master);
if (master_h == NULL) {
err = -ENOENT;
goto err2;
}
master_ct = nf_ct_tuplehash_to_ctrack(master_h);
nf_conntrack_get(&master_ct->ct_general);
__set_bit(IPS_EXPECTED_BIT, &ct->status);
ct->master = master_ct;
}
nf_conntrack_get(&ct->ct_general);
add_timer(&ct->timeout);
nf_conntrack_hash_insert(ct);
rcu_read_unlock();
ctnetlink_event_report(ct, pid, report);
nf_ct_put(ct);
return 0;
return ct;
err:
err2:
rcu_read_unlock();
err1:
nf_conntrack_free(ct);
return err;
return ERR_PTR(err);
}
static int
@@ -1289,38 +1295,25 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
h = __nf_conntrack_find(&init_net, &rtuple);
if (h == NULL) {
struct nf_conntrack_tuple master;
struct nf_conntrack_tuple_hash *master_h = NULL;
struct nf_conn *master_ct = NULL;
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE) {
struct nf_conn *ct;
if (cda[CTA_TUPLE_MASTER]) {
err = ctnetlink_parse_tuple(cda,
&master,
CTA_TUPLE_MASTER,
u3);
if (err < 0)
goto out_unlock;
master_h = __nf_conntrack_find(&init_net, &master);
if (master_h == NULL) {
err = -ENOENT;
ct = ctnetlink_create_conntrack(cda, &otuple,
&rtuple, u3);
if (IS_ERR(ct)) {
err = PTR_ERR(ct);
goto out_unlock;
}
master_ct = nf_ct_tuplehash_to_ctrack(master_h);
nf_conntrack_get(&master_ct->ct_general);
}
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE)
err = ctnetlink_create_conntrack(cda,
&otuple,
&rtuple,
master_ct,
NETLINK_CB(skb).pid,
nlmsg_report(nlh));
spin_unlock_bh(&nf_conntrack_lock);
if (err < 0 && master_ct)
nf_ct_put(master_ct);
err = 0;
nf_conntrack_get(&ct->ct_general);
spin_unlock_bh(&nf_conntrack_lock);
ctnetlink_event_report(ct,
NETLINK_CB(skb).pid,
nlmsg_report(nlh));
nf_ct_put(ct);
} else
spin_unlock_bh(&nf_conntrack_lock);
return err;
}
@@ -1332,17 +1325,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
/* we only allow nat config for new conntracks */
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
err = -EOPNOTSUPP;
goto out_unlock;
}
/* can't link an existing conntrack to a master */
if (cda[CTA_TUPLE_MASTER]) {
err = -EOPNOTSUPP;
goto out_unlock;
}
err = ctnetlink_change_conntrack(ct, cda);
if (err == 0) {
nf_conntrack_get(&ct->ct_general);
@@ -1533,6 +1515,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
nla_put_failure:
rcu_read_unlock();
nlmsg_failure:
nfnetlink_set_err(0, 0, -ENOBUFS);
kfree_skb(skb);
return NOTIFY_DONE;
}
-21
View File
@@ -74,27 +74,6 @@ EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find);
/* this is guaranteed to always return a valid protocol helper, since
* it falls back to generic_protocol */
struct nf_conntrack_l4proto *
nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto)
{
struct nf_conntrack_l4proto *p;
rcu_read_lock();
p = __nf_ct_l4proto_find(l3proto, l4proto);
if (!try_module_get(p->me))
p = &nf_conntrack_l4proto_generic;
rcu_read_unlock();
return p;
}
EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get);
void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p)
{
module_put(p->me);
}
EXPORT_SYMBOL_GPL(nf_ct_l4proto_put);
struct nf_conntrack_l3proto *
nf_ct_l3proto_find_get(u_int16_t l3proto)
{
+108 -37
View File
@@ -16,6 +16,9 @@
#include <linux/skbuff.h>
#include <linux/dccp.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
@@ -23,8 +26,6 @@
static DEFINE_RWLOCK(dccp_lock);
static int nf_ct_dccp_loose __read_mostly = 1;
/* Timeouts are based on values from RFC4340:
*
* - REQUEST:
@@ -72,16 +73,6 @@ static int nf_ct_dccp_loose __read_mostly = 1;
#define DCCP_MSL (2 * 60 * HZ)
static unsigned int dccp_timeout[CT_DCCP_MAX + 1] __read_mostly = {
[CT_DCCP_REQUEST] = 2 * DCCP_MSL,
[CT_DCCP_RESPOND] = 4 * DCCP_MSL,
[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL,
[CT_DCCP_OPEN] = 12 * 3600 * HZ,
[CT_DCCP_CLOSEREQ] = 64 * HZ,
[CT_DCCP_CLOSING] = 64 * HZ,
[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL,
};
static const char * const dccp_state_names[] = {
[CT_DCCP_NONE] = "NONE",
[CT_DCCP_REQUEST] = "REQUEST",
@@ -393,6 +384,22 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
},
};
/* this module per-net specifics */
static int dccp_net_id;
struct dccp_net {
int dccp_loose;
unsigned int dccp_timeout[CT_DCCP_MAX + 1];
#ifdef CONFIG_SYSCTL
struct ctl_table_header *sysctl_header;
struct ctl_table *sysctl_table;
#endif
};
static inline struct dccp_net *dccp_pernet(struct net *net)
{
return net_generic(net, dccp_net_id);
}
static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
struct nf_conntrack_tuple *tuple)
{
@@ -419,6 +426,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff)
{
struct net *net = nf_ct_net(ct);
struct dccp_net *dn;
struct dccp_hdr _dh, *dh;
const char *msg;
u_int8_t state;
@@ -429,7 +437,8 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
switch (state) {
default:
if (nf_ct_dccp_loose == 0) {
dn = dccp_pernet(net);
if (dn->dccp_loose == 0) {
msg = "nf_ct_dccp: not picking up existing connection ";
goto out_invalid;
}
@@ -465,6 +474,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
u_int8_t pf, unsigned int hooknum)
{
struct net *net = nf_ct_net(ct);
struct dccp_net *dn;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
struct dccp_hdr _dh, *dh;
u_int8_t type, old_state, new_state;
@@ -542,7 +552,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
ct->proto.dccp.last_pkt = type;
ct->proto.dccp.state = new_state;
write_unlock_bh(&dccp_lock);
nf_ct_refresh_acct(ct, ctinfo, skb, dccp_timeout[new_state]);
dn = dccp_pernet(net);
nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]);
return NF_ACCEPT;
}
@@ -660,13 +672,11 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
#endif
#ifdef CONFIG_SYSCTL
static unsigned int dccp_sysctl_table_users;
static struct ctl_table_header *dccp_sysctl_header;
static ctl_table dccp_sysctl_table[] = {
/* template, data assigned later */
static struct ctl_table dccp_sysctl_table[] = {
{
.ctl_name = CTL_UNNUMBERED,
.procname = "nf_conntrack_dccp_timeout_request",
.data = &dccp_timeout[CT_DCCP_REQUEST],
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
@@ -674,7 +684,6 @@ static ctl_table dccp_sysctl_table[] = {
{
.ctl_name = CTL_UNNUMBERED,
.procname = "nf_conntrack_dccp_timeout_respond",
.data = &dccp_timeout[CT_DCCP_RESPOND],
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
@@ -682,7 +691,6 @@ static ctl_table dccp_sysctl_table[] = {
{
.ctl_name = CTL_UNNUMBERED,
.procname = "nf_conntrack_dccp_timeout_partopen",
.data = &dccp_timeout[CT_DCCP_PARTOPEN],
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
@@ -690,7 +698,6 @@ static ctl_table dccp_sysctl_table[] = {
{
.ctl_name = CTL_UNNUMBERED,
.procname = "nf_conntrack_dccp_timeout_open",
.data = &dccp_timeout[CT_DCCP_OPEN],
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
@@ -698,7 +705,6 @@ static ctl_table dccp_sysctl_table[] = {
{
.ctl_name = CTL_UNNUMBERED,
.procname = "nf_conntrack_dccp_timeout_closereq",
.data = &dccp_timeout[CT_DCCP_CLOSEREQ],
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
@@ -706,7 +712,6 @@ static ctl_table dccp_sysctl_table[] = {
{
.ctl_name = CTL_UNNUMBERED,
.procname = "nf_conntrack_dccp_timeout_closing",
.data = &dccp_timeout[CT_DCCP_CLOSING],
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
@@ -714,7 +719,6 @@ static ctl_table dccp_sysctl_table[] = {
{
.ctl_name = CTL_UNNUMBERED,
.procname = "nf_conntrack_dccp_timeout_timewait",
.data = &dccp_timeout[CT_DCCP_TIMEWAIT],
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
@@ -722,8 +726,7 @@ static ctl_table dccp_sysctl_table[] = {
{
.ctl_name = CTL_UNNUMBERED,
.procname = "nf_conntrack_dccp_loose",
.data = &nf_ct_dccp_loose,
.maxlen = sizeof(nf_ct_dccp_loose),
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
@@ -751,11 +754,6 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy,
#endif
#ifdef CONFIG_SYSCTL
.ctl_table_users = &dccp_sysctl_table_users,
.ctl_table_header = &dccp_sysctl_header,
.ctl_table = dccp_sysctl_table,
#endif
};
static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
@@ -776,34 +774,107 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy,
#endif
};
static __net_init int dccp_net_init(struct net *net)
{
struct dccp_net *dn;
int err;
dn = kmalloc(sizeof(*dn), GFP_KERNEL);
if (!dn)
return -ENOMEM;
/* default values */
dn->dccp_loose = 1;
dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL;
dn->dccp_timeout[CT_DCCP_RESPOND] = 4 * DCCP_MSL;
dn->dccp_timeout[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL;
dn->dccp_timeout[CT_DCCP_OPEN] = 12 * 3600 * HZ;
dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ;
dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ;
dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL;
err = net_assign_generic(net, dccp_net_id, dn);
if (err)
goto out;
#ifdef CONFIG_SYSCTL
.ctl_table_users = &dccp_sysctl_table_users,
.ctl_table_header = &dccp_sysctl_header,
.ctl_table = dccp_sysctl_table,
err = -ENOMEM;
dn->sysctl_table = kmemdup(dccp_sysctl_table,
sizeof(dccp_sysctl_table), GFP_KERNEL);
if (!dn->sysctl_table)
goto out;
dn->sysctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
dn->sysctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
dn->sysctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
dn->sysctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
dn->sysctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
dn->sysctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
dn->sysctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
dn->sysctl_table[7].data = &dn->dccp_loose;
dn->sysctl_header = register_net_sysctl_table(net,
nf_net_netfilter_sysctl_path, dn->sysctl_table);
if (!dn->sysctl_header) {
kfree(dn->sysctl_table);
goto out;
}
#endif
return 0;
out:
kfree(dn);
return err;
}
static __net_exit void dccp_net_exit(struct net *net)
{
struct dccp_net *dn = dccp_pernet(net);
#ifdef CONFIG_SYSCTL
unregister_net_sysctl_table(dn->sysctl_header);
kfree(dn->sysctl_table);
#endif
kfree(dn);
net_assign_generic(net, dccp_net_id, NULL);
}
static struct pernet_operations dccp_net_ops = {
.init = dccp_net_init,
.exit = dccp_net_exit,
};
static int __init nf_conntrack_proto_dccp_init(void)
{
int err;
err = nf_conntrack_l4proto_register(&dccp_proto4);
err = register_pernet_gen_subsys(&dccp_net_id, &dccp_net_ops);
if (err < 0)
goto err1;
err = nf_conntrack_l4proto_register(&dccp_proto6);
err = nf_conntrack_l4proto_register(&dccp_proto4);
if (err < 0)
goto err2;
err = nf_conntrack_l4proto_register(&dccp_proto6);
if (err < 0)
goto err3;
return 0;
err2:
err3:
nf_conntrack_l4proto_unregister(&dccp_proto4);
err2:
unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops);
err1:
return err;
}
static void __exit nf_conntrack_proto_dccp_fini(void)
{
unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops);
nf_conntrack_l4proto_unregister(&dccp_proto6);
nf_conntrack_l4proto_unregister(&dccp_proto4);
}
+1 -1
View File
@@ -92,7 +92,7 @@ static struct ctl_table generic_compat_sysctl_table[] = {
struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
{
.l3proto = PF_UNSPEC,
.l4proto = 0,
.l4proto = 255,
.name = "unknown",
.pkt_to_tuple = generic_pkt_to_tuple,
.invert_tuple = generic_invert_tuple,
+2
View File
@@ -25,6 +25,8 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_ecache.h>
#include <net/netfilter/nf_log.h>
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
/* Protects ct->proto.tcp */
static DEFINE_RWLOCK(tcp_lock);
+2
View File
@@ -22,6 +22,8 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_ecache.h>
#include <net/netfilter/nf_log.h>
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ;
static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ;
+170 -33
View File
@@ -14,58 +14,63 @@
LOG target modules */
#define NF_LOG_PREFIXLEN 128
#define NFLOGGER_NAME_LEN 64
static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly;
static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly;
static DEFINE_MUTEX(nf_log_mutex);
/* return EBUSY if somebody else is registered, EEXIST if the same logger
* is registred, 0 on success. */
int nf_log_register(u_int8_t pf, const struct nf_logger *logger)
static struct nf_logger *__find_logger(int pf, const char *str_logger)
{
int ret;
struct nf_logger *t;
list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) {
if (!strnicmp(str_logger, t->name, strlen(t->name)))
return t;
}
return NULL;
}
/* return EEXIST if the same logger is registred, 0 on success. */
int nf_log_register(u_int8_t pf, struct nf_logger *logger)
{
const struct nf_logger *llog;
if (pf >= ARRAY_SIZE(nf_loggers))
return -EINVAL;
/* Any setup of logging members must be done before
* substituting pointer. */
ret = mutex_lock_interruptible(&nf_log_mutex);
if (ret < 0)
return ret;
mutex_lock(&nf_log_mutex);
if (!nf_loggers[pf])
rcu_assign_pointer(nf_loggers[pf], logger);
else if (nf_loggers[pf] == logger)
ret = -EEXIST;
else
ret = -EBUSY;
if (pf == NFPROTO_UNSPEC) {
int i;
for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
list_add_tail(&(logger->list[i]), &(nf_loggers_l[i]));
} else {
/* register at end of list to honor first register win */
list_add_tail(&logger->list[pf], &nf_loggers_l[pf]);
llog = rcu_dereference(nf_loggers[pf]);
if (llog == NULL)
rcu_assign_pointer(nf_loggers[pf], logger);
}
mutex_unlock(&nf_log_mutex);
return ret;
return 0;
}
EXPORT_SYMBOL(nf_log_register);
void nf_log_unregister_pf(u_int8_t pf)
{
if (pf >= ARRAY_SIZE(nf_loggers))
return;
mutex_lock(&nf_log_mutex);
rcu_assign_pointer(nf_loggers[pf], NULL);
mutex_unlock(&nf_log_mutex);
/* Give time to concurrent readers. */
synchronize_rcu();
}
EXPORT_SYMBOL(nf_log_unregister_pf);
void nf_log_unregister(const struct nf_logger *logger)
void nf_log_unregister(struct nf_logger *logger)
{
const struct nf_logger *c_logger;
int i;
mutex_lock(&nf_log_mutex);
for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) {
if (nf_loggers[i] == logger)
c_logger = rcu_dereference(nf_loggers[i]);
if (c_logger == logger)
rcu_assign_pointer(nf_loggers[i], NULL);
list_del(&logger->list[i]);
}
mutex_unlock(&nf_log_mutex);
@@ -73,6 +78,27 @@ void nf_log_unregister(const struct nf_logger *logger)
}
EXPORT_SYMBOL(nf_log_unregister);
int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
{
mutex_lock(&nf_log_mutex);
if (__find_logger(pf, logger->name) == NULL) {
mutex_unlock(&nf_log_mutex);
return -ENOENT;
}
rcu_assign_pointer(nf_loggers[pf], logger);
mutex_unlock(&nf_log_mutex);
return 0;
}
EXPORT_SYMBOL(nf_log_bind_pf);
void nf_log_unbind_pf(u_int8_t pf)
{
mutex_lock(&nf_log_mutex);
rcu_assign_pointer(nf_loggers[pf], NULL);
mutex_unlock(&nf_log_mutex);
}
EXPORT_SYMBOL(nf_log_unbind_pf);
void nf_log_packet(u_int8_t pf,
unsigned int hooknum,
const struct sk_buff *skb,
@@ -129,13 +155,37 @@ static int seq_show(struct seq_file *s, void *v)
{
loff_t *pos = v;
const struct nf_logger *logger;
struct nf_logger *t;
int ret;
logger = rcu_dereference(nf_loggers[*pos]);
if (!logger)
return seq_printf(s, "%2lld NONE\n", *pos);
ret = seq_printf(s, "%2lld NONE (", *pos);
else
ret = seq_printf(s, "%2lld %s (", *pos, logger->name);
return seq_printf(s, "%2lld %s\n", *pos, logger->name);
if (ret < 0)
return ret;
mutex_lock(&nf_log_mutex);
list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) {
ret = seq_printf(s, "%s", t->name);
if (ret < 0) {
mutex_unlock(&nf_log_mutex);
return ret;
}
if (&t->list[*pos] != nf_loggers_l[*pos].prev) {
ret = seq_printf(s, ",");
if (ret < 0) {
mutex_unlock(&nf_log_mutex);
return ret;
}
}
}
mutex_unlock(&nf_log_mutex);
return seq_printf(s, ")\n");
}
static const struct seq_operations nflog_seq_ops = {
@@ -158,15 +208,102 @@ static const struct file_operations nflog_file_ops = {
.release = seq_release,
};
#endif /* PROC_FS */
#ifdef CONFIG_SYSCTL
struct ctl_path nf_log_sysctl_path[] = {
{ .procname = "net", .ctl_name = CTL_NET, },
{ .procname = "netfilter", .ctl_name = NET_NETFILTER, },
{ .procname = "nf_log", .ctl_name = CTL_UNNUMBERED, },
{ }
};
static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
static struct ctl_table_header *nf_log_dir_header;
static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp, loff_t *ppos)
{
const struct nf_logger *logger;
int r = 0;
int tindex = (unsigned long)table->extra1;
if (write) {
if (!strcmp(buffer, "NONE")) {
nf_log_unbind_pf(tindex);
return 0;
}
mutex_lock(&nf_log_mutex);
logger = __find_logger(tindex, buffer);
if (logger == NULL) {
mutex_unlock(&nf_log_mutex);
return -ENOENT;
}
rcu_assign_pointer(nf_loggers[tindex], logger);
mutex_unlock(&nf_log_mutex);
} else {
rcu_read_lock();
logger = rcu_dereference(nf_loggers[tindex]);
if (!logger)
table->data = "NONE";
else
table->data = logger->name;
r = proc_dostring(table, write, filp, buffer, lenp, ppos);
rcu_read_unlock();
}
return r;
}
static __init int netfilter_log_sysctl_init(void)
{
int i;
for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
snprintf(nf_log_sysctl_fnames[i-NFPROTO_UNSPEC], 3, "%d", i);
nf_log_sysctl_table[i].ctl_name = CTL_UNNUMBERED;
nf_log_sysctl_table[i].procname =
nf_log_sysctl_fnames[i-NFPROTO_UNSPEC];
nf_log_sysctl_table[i].data = NULL;
nf_log_sysctl_table[i].maxlen =
NFLOGGER_NAME_LEN * sizeof(char);
nf_log_sysctl_table[i].mode = 0644;
nf_log_sysctl_table[i].proc_handler = nf_log_proc_dostring;
nf_log_sysctl_table[i].extra1 = (void *)(unsigned long) i;
}
nf_log_dir_header = register_sysctl_paths(nf_log_sysctl_path,
nf_log_sysctl_table);
if (!nf_log_dir_header)
return -ENOMEM;
return 0;
}
#else
static __init int netfilter_log_sysctl_init(void)
{
return 0;
}
#endif /* CONFIG_SYSCTL */
int __init netfilter_log_init(void)
{
int i, r;
#ifdef CONFIG_PROC_FS
if (!proc_create("nf_log", S_IRUGO,
proc_net_netfilter, &nflog_file_ops))
return -1;
#endif
/* Errors will trigger panic, unroll on error is unnecessary. */
r = netfilter_log_sysctl_init();
if (r < 0)
return r;
for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
INIT_LIST_HEAD(&(nf_loggers_l[i]));
return 0;
}
+6
View File
@@ -113,6 +113,12 @@ int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
}
EXPORT_SYMBOL_GPL(nfnetlink_send);
void nfnetlink_set_err(u32 pid, u32 group, int error)
{
netlink_set_err(nfnl, pid, group, error);
}
EXPORT_SYMBOL_GPL(nfnetlink_set_err);
int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags)
{
return netlink_unicast(nfnl, skb, pid, flags);
+13 -5
View File
@@ -693,7 +693,7 @@ nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
return -ENOTSUPP;
}
static const struct nf_logger nfulnl_logger = {
static struct nf_logger nfulnl_logger __read_mostly = {
.name = "nfnetlink_log",
.logfn = &nfulnl_log_packet,
.me = THIS_MODULE,
@@ -725,9 +725,9 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
/* Commands without queue context */
switch (cmd->command) {
case NFULNL_CFG_CMD_PF_BIND:
return nf_log_register(pf, &nfulnl_logger);
return nf_log_bind_pf(pf, &nfulnl_logger);
case NFULNL_CFG_CMD_PF_UNBIND:
nf_log_unregister_pf(pf);
nf_log_unbind_pf(pf);
return 0;
}
}
@@ -952,17 +952,25 @@ static int __init nfnetlink_log_init(void)
goto cleanup_netlink_notifier;
}
status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger);
if (status < 0) {
printk(KERN_ERR "log: failed to register logger\n");
goto cleanup_subsys;
}
#ifdef CONFIG_PROC_FS
if (!proc_create("nfnetlink_log", 0440,
proc_net_netfilter, &nful_file_ops))
goto cleanup_subsys;
goto cleanup_logger;
#endif
return status;
#ifdef CONFIG_PROC_FS
cleanup_logger:
nf_log_unregister(&nfulnl_logger);
#endif
cleanup_subsys:
nfnetlink_subsys_unregister(&nfulnl_subsys);
#endif
cleanup_netlink_notifier:
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
return status;
+21 -5
View File
@@ -625,6 +625,20 @@ void xt_free_table_info(struct xt_table_info *info)
}
EXPORT_SYMBOL(xt_free_table_info);
void xt_table_entry_swap_rcu(struct xt_table_info *oldinfo,
struct xt_table_info *newinfo)
{
unsigned int cpu;
for_each_possible_cpu(cpu) {
void *p = oldinfo->entries[cpu];
rcu_assign_pointer(oldinfo->entries[cpu], newinfo->entries[cpu]);
newinfo->entries[cpu] = p;
}
}
EXPORT_SYMBOL_GPL(xt_table_entry_swap_rcu);
/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
const char *name)
@@ -671,21 +685,22 @@ xt_replace_table(struct xt_table *table,
struct xt_table_info *oldinfo, *private;
/* Do the substitution. */
write_lock_bh(&table->lock);
mutex_lock(&table->lock);
private = table->private;
/* Check inside lock: is the old number correct? */
if (num_counters != private->number) {
duprintf("num_counters != table->private->number (%u/%u)\n",
num_counters, private->number);
write_unlock_bh(&table->lock);
mutex_unlock(&table->lock);
*error = -EAGAIN;
return NULL;
}
oldinfo = private;
table->private = newinfo;
rcu_assign_pointer(table->private, newinfo);
newinfo->initial_entries = oldinfo->initial_entries;
write_unlock_bh(&table->lock);
mutex_unlock(&table->lock);
synchronize_net();
return oldinfo;
}
EXPORT_SYMBOL_GPL(xt_replace_table);
@@ -719,7 +734,8 @@ struct xt_table *xt_register_table(struct net *net, struct xt_table *table,
/* Simplifies replace_table code. */
table->private = bootstrap;
rwlock_init(&table->lock);
mutex_init(&table->lock);
if (!xt_replace_table(table, 0, newinfo, &ret))
goto unlock;
+171
View File
@@ -0,0 +1,171 @@
/*
* TTL modification target for IP tables
* (C) 2000,2005 by Harald Welte <laforge@netfilter.org>
*
* Hop Limit modification target for ip6tables
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
*
* 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/skbuff.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/checksum.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_TTL.h>
#include <linux/netfilter_ipv6/ip6t_HL.h>
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target");
MODULE_LICENSE("GPL");
static unsigned int
ttl_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
struct iphdr *iph;
const struct ipt_TTL_info *info = par->targinfo;
int new_ttl;
if (!skb_make_writable(skb, skb->len))
return NF_DROP;
iph = ip_hdr(skb);
switch (info->mode) {
case IPT_TTL_SET:
new_ttl = info->ttl;
break;
case IPT_TTL_INC:
new_ttl = iph->ttl + info->ttl;
if (new_ttl > 255)
new_ttl = 255;
break;
case IPT_TTL_DEC:
new_ttl = iph->ttl - info->ttl;
if (new_ttl < 0)
new_ttl = 0;
break;
default:
new_ttl = iph->ttl;
break;
}
if (new_ttl != iph->ttl) {
csum_replace2(&iph->check, htons(iph->ttl << 8),
htons(new_ttl << 8));
iph->ttl = new_ttl;
}
return XT_CONTINUE;
}
static unsigned int
hl_tg6(struct sk_buff *skb, const struct xt_target_param *par)
{
struct ipv6hdr *ip6h;
const struct ip6t_HL_info *info = par->targinfo;
int new_hl;
if (!skb_make_writable(skb, skb->len))
return NF_DROP;
ip6h = ipv6_hdr(skb);
switch (info->mode) {
case IP6T_HL_SET:
new_hl = info->hop_limit;
break;
case IP6T_HL_INC:
new_hl = ip6h->hop_limit + info->hop_limit;
if (new_hl > 255)
new_hl = 255;
break;
case IP6T_HL_DEC:
new_hl = ip6h->hop_limit - info->hop_limit;
if (new_hl < 0)
new_hl = 0;
break;
default:
new_hl = ip6h->hop_limit;
break;
}
ip6h->hop_limit = new_hl;
return XT_CONTINUE;
}
static bool ttl_tg_check(const struct xt_tgchk_param *par)
{
const struct ipt_TTL_info *info = par->targinfo;
if (info->mode > IPT_TTL_MAXMODE) {
printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n",
info->mode);
return false;
}
if (info->mode != IPT_TTL_SET && info->ttl == 0)
return false;
return true;
}
static bool hl_tg6_check(const struct xt_tgchk_param *par)
{
const struct ip6t_HL_info *info = par->targinfo;
if (info->mode > IP6T_HL_MAXMODE) {
printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n",
info->mode);
return false;
}
if (info->mode != IP6T_HL_SET && info->hop_limit == 0) {
printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
"make sense with value 0\n");
return false;
}
return true;
}
static struct xt_target hl_tg_reg[] __read_mostly = {
{
.name = "TTL",
.revision = 0,
.family = NFPROTO_IPV4,
.target = ttl_tg,
.targetsize = sizeof(struct ipt_TTL_info),
.table = "mangle",
.checkentry = ttl_tg_check,
.me = THIS_MODULE,
},
{
.name = "HL",
.revision = 0,
.family = NFPROTO_IPV6,
.target = hl_tg6,
.targetsize = sizeof(struct ip6t_HL_info),
.table = "mangle",
.checkentry = hl_tg6_check,
.me = THIS_MODULE,
},
};
static int __init hl_tg_init(void)
{
return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg));
}
static void __exit hl_tg_exit(void)
{
xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg));
}
module_init(hl_tg_init);
module_exit(hl_tg_exit);
MODULE_ALIAS("ipt_TTL");
MODULE_ALIAS("ip6t_HL");
+161
View File
@@ -0,0 +1,161 @@
/*
* xt_LED.c - netfilter target to make LEDs blink upon packet matches
*
* Copyright (C) 2008 Adam Nielsen <a.nielsen@shikadi.net>
*
* 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; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter/x_tables.h>
#include <linux/leds.h>
#include <linux/mutex.h>
#include <linux/netfilter/xt_LED.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>");
MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match");
/*
* This is declared in here (the kernel module) only, to avoid having these
* dependencies in userspace code. This is what xt_led_info.internal_data
* points to.
*/
struct xt_led_info_internal {
struct led_trigger netfilter_led_trigger;
struct timer_list timer;
};
static unsigned int
led_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_led_info *ledinfo = par->targinfo;
struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
/*
* If "always blink" is enabled, and there's still some time until the
* LED will switch off, briefly switch it off now.
*/
if ((ledinfo->delay > 0) && ledinfo->always_blink &&
timer_pending(&ledinternal->timer))
led_trigger_event(&ledinternal->netfilter_led_trigger,LED_OFF);
led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL);
/* If there's a positive delay, start/update the timer */
if (ledinfo->delay > 0) {
mod_timer(&ledinternal->timer,
jiffies + msecs_to_jiffies(ledinfo->delay));
/* Otherwise if there was no delay given, blink as fast as possible */
} else if (ledinfo->delay == 0) {
led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
}
/* else the delay is negative, which means switch on and stay on */
return XT_CONTINUE;
}
static void led_timeout_callback(unsigned long data)
{
struct xt_led_info *ledinfo = (struct xt_led_info *)data;
struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
}
static bool led_tg_check(const struct xt_tgchk_param *par)
{
struct xt_led_info *ledinfo = par->targinfo;
struct xt_led_info_internal *ledinternal;
int err;
if (ledinfo->id[0] == '\0') {
printk(KERN_ERR KBUILD_MODNAME ": No 'id' parameter given.\n");
return false;
}
ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL);
if (!ledinternal) {
printk(KERN_CRIT KBUILD_MODNAME ": out of memory\n");
return false;
}
ledinternal->netfilter_led_trigger.name = ledinfo->id;
err = led_trigger_register(&ledinternal->netfilter_led_trigger);
if (err) {
printk(KERN_CRIT KBUILD_MODNAME
": led_trigger_register() failed\n");
if (err == -EEXIST)
printk(KERN_ERR KBUILD_MODNAME
": Trigger name is already in use.\n");
goto exit_alloc;
}
/* See if we need to set up a timer */
if (ledinfo->delay > 0)
setup_timer(&ledinternal->timer, led_timeout_callback,
(unsigned long)ledinfo);
ledinfo->internal_data = ledinternal;
return true;
exit_alloc:
kfree(ledinternal);
return false;
}
static void led_tg_destroy(const struct xt_tgdtor_param *par)
{
const struct xt_led_info *ledinfo = par->targinfo;
struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
if (ledinfo->delay > 0)
del_timer_sync(&ledinternal->timer);
led_trigger_unregister(&ledinternal->netfilter_led_trigger);
kfree(ledinternal);
}
static struct xt_target led_tg_reg __read_mostly = {
.name = "LED",
.revision = 0,
.family = NFPROTO_UNSPEC,
.target = led_tg,
.targetsize = XT_ALIGN(sizeof(struct xt_led_info)),
.checkentry = led_tg_check,
.destroy = led_tg_destroy,
.me = THIS_MODULE,
};
static int __init led_tg_init(void)
{
return xt_register_target(&led_tg_reg);
}
static void __exit led_tg_exit(void)
{
xt_unregister_target(&led_tg_reg);
}
module_init(led_tg_init);
module_exit(led_tg_exit);
+164
View File
@@ -0,0 +1,164 @@
/*
* (C) 2008-2009 Pablo Neira Ayuso <pablo@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/skbuff.h>
#include <linux/jhash.h>
#include <linux/ip.h>
#include <net/ipv6.h>
#include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_conntrack.h>
#include <linux/netfilter/xt_cluster.h>
static inline u_int32_t nf_ct_orig_ipv4_src(const struct nf_conn *ct)
{
return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
}
static inline const void *nf_ct_orig_ipv6_src(const struct nf_conn *ct)
{
return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6;
}
static inline u_int32_t
xt_cluster_hash_ipv4(u_int32_t ip, const struct xt_cluster_match_info *info)
{
return jhash_1word(ip, info->hash_seed);
}
static inline u_int32_t
xt_cluster_hash_ipv6(const void *ip, const struct xt_cluster_match_info *info)
{
return jhash2(ip, NF_CT_TUPLE_L3SIZE / sizeof(__u32), info->hash_seed);
}
static inline u_int32_t
xt_cluster_hash(const struct nf_conn *ct,
const struct xt_cluster_match_info *info)
{
u_int32_t hash = 0;
switch(nf_ct_l3num(ct)) {
case AF_INET:
hash = xt_cluster_hash_ipv4(nf_ct_orig_ipv4_src(ct), info);
break;
case AF_INET6:
hash = xt_cluster_hash_ipv6(nf_ct_orig_ipv6_src(ct), info);
break;
default:
WARN_ON(1);
break;
}
return (((u64)hash * info->total_nodes) >> 32);
}
static inline bool
xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family)
{
bool is_multicast = false;
switch(family) {
case NFPROTO_IPV4:
is_multicast = ipv4_is_multicast(ip_hdr(skb)->daddr);
break;
case NFPROTO_IPV6:
is_multicast = ipv6_addr_type(&ipv6_hdr(skb)->daddr) &
IPV6_ADDR_MULTICAST;
break;
default:
WARN_ON(1);
break;
}
return is_multicast;
}
static bool
xt_cluster_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
struct sk_buff *pskb = (struct sk_buff *)skb;
const struct xt_cluster_match_info *info = par->matchinfo;
const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
unsigned long hash;
/* This match assumes that all nodes see the same packets. This can be
* achieved if the switch that connects the cluster nodes support some
* sort of 'port mirroring'. However, if your switch does not support
* this, your cluster nodes can reply ARP request using a multicast MAC
* address. Thus, your switch will flood the same packets to the
* cluster nodes with the same multicast MAC address. Using a multicast
* link address is a RFC 1812 (section 3.3.2) violation, but this works
* fine in practise.
*
* Unfortunately, if you use the multicast MAC address, the link layer
* sets skbuff's pkt_type to PACKET_MULTICAST, which is not accepted
* by TCP and others for packets coming to this node. For that reason,
* this match mangles skbuff's pkt_type if it detects a packet
* addressed to a unicast address but using PACKET_MULTICAST. Yes, I
* know, matches should not alter packets, but we are doing this here
* because we would need to add a PKTTYPE target for this sole purpose.
*/
if (!xt_cluster_is_multicast_addr(skb, par->family) &&
skb->pkt_type == PACKET_MULTICAST) {
pskb->pkt_type = PACKET_HOST;
}
ct = nf_ct_get(skb, &ctinfo);
if (ct == NULL)
return false;
if (ct == &nf_conntrack_untracked)
return false;
if (ct->master)
hash = xt_cluster_hash(ct->master, info);
else
hash = xt_cluster_hash(ct, info);
return !!((1 << hash) & info->node_mask) ^
!!(info->flags & XT_CLUSTER_F_INV);
}
static bool xt_cluster_mt_checkentry(const struct xt_mtchk_param *par)
{
struct xt_cluster_match_info *info = par->matchinfo;
if (info->node_mask >= (1 << info->total_nodes)) {
printk(KERN_ERR "xt_cluster: this node mask cannot be "
"higher than the total number of nodes\n");
return false;
}
return true;
}
static struct xt_match xt_cluster_match __read_mostly = {
.name = "cluster",
.family = NFPROTO_UNSPEC,
.match = xt_cluster_mt,
.checkentry = xt_cluster_mt_checkentry,
.matchsize = sizeof(struct xt_cluster_match_info),
.me = THIS_MODULE,
};
static int __init xt_cluster_mt_init(void)
{
return xt_register_match(&xt_cluster_match);
}
static void __exit xt_cluster_mt_fini(void)
{
xt_unregister_match(&xt_cluster_match);
}
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Xtables: hash-based cluster match");
MODULE_ALIAS("ipt_cluster");
MODULE_ALIAS("ip6t_cluster");
module_init(xt_cluster_mt_init);
module_exit(xt_cluster_mt_fini);
+2 -5
View File
@@ -149,7 +149,7 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht,
/* initialize hash with random val at the time we allocate
* the first hashtable entry */
if (!ht->rnd_initialized) {
get_random_bytes(&ht->rnd, 4);
get_random_bytes(&ht->rnd, sizeof(ht->rnd));
ht->rnd_initialized = 1;
}
@@ -565,8 +565,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
static bool
hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
{
const struct xt_hashlimit_info *r =
((const struct xt_hashlimit_info *)par->matchinfo)->u.master;
const struct xt_hashlimit_info *r = par->matchinfo;
struct xt_hashlimit_htable *hinfo = r->hinfo;
unsigned long now = jiffies;
struct dsthash_ent *dh;
@@ -702,8 +701,6 @@ static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par)
}
mutex_unlock(&hlimit_mutex);
/* Ugly hack: For SMP, we only want to use one set */
r->u.master = r;
return true;
}
+108
View File
@@ -0,0 +1,108 @@
/*
* IP tables module for matching the value of the TTL
* (C) 2000,2001 by Harald Welte <laforge@netfilter.org>
*
* Hop Limit matching module
* (C) 2001-2002 Maciej Soltysiak <solt@dns.toxicfilms.tv>
*
* 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/ip.h>
#include <linux/ipv6.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_ttl.h>
#include <linux/netfilter_ipv6/ip6t_hl.h>
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
MODULE_DESCRIPTION("Xtables: Hoplimit/TTL field match");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_ttl");
MODULE_ALIAS("ip6t_hl");
static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
const struct ipt_ttl_info *info = par->matchinfo;
const u8 ttl = ip_hdr(skb)->ttl;
switch (info->mode) {
case IPT_TTL_EQ:
return ttl == info->ttl;
case IPT_TTL_NE:
return ttl != info->ttl;
case IPT_TTL_LT:
return ttl < info->ttl;
case IPT_TTL_GT:
return ttl > info->ttl;
default:
printk(KERN_WARNING "ipt_ttl: unknown mode %d\n",
info->mode);
return false;
}
return false;
}
static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
{
const struct ip6t_hl_info *info = par->matchinfo;
const struct ipv6hdr *ip6h = ipv6_hdr(skb);
switch (info->mode) {
case IP6T_HL_EQ:
return ip6h->hop_limit == info->hop_limit;
break;
case IP6T_HL_NE:
return ip6h->hop_limit != info->hop_limit;
break;
case IP6T_HL_LT:
return ip6h->hop_limit < info->hop_limit;
break;
case IP6T_HL_GT:
return ip6h->hop_limit > info->hop_limit;
break;
default:
printk(KERN_WARNING "ip6t_hl: unknown mode %d\n",
info->mode);
return false;
}
return false;
}
static struct xt_match hl_mt_reg[] __read_mostly = {
{
.name = "ttl",
.revision = 0,
.family = NFPROTO_IPV4,
.match = ttl_mt,
.matchsize = sizeof(struct ipt_ttl_info),
.me = THIS_MODULE,
},
{
.name = "hl",
.revision = 0,
.family = NFPROTO_IPV6,
.match = hl_mt6,
.matchsize = sizeof(struct ip6t_hl_info),
.me = THIS_MODULE,
},
};
static int __init hl_mt_init(void)
{
return xt_register_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg));
}
static void __exit hl_mt_exit(void)
{
xt_unregister_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg));
}
module_init(hl_mt_init);
module_exit(hl_mt_exit);
+29 -11
View File
@@ -14,6 +14,11 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_limit.h>
struct xt_limit_priv {
unsigned long prev;
uint32_t credit;
};
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
MODULE_DESCRIPTION("Xtables: rate-limit match");
@@ -60,18 +65,18 @@ static DEFINE_SPINLOCK(limit_lock);
static bool
limit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
struct xt_rateinfo *r =
((const struct xt_rateinfo *)par->matchinfo)->master;
const struct xt_rateinfo *r = par->matchinfo;
struct xt_limit_priv *priv = r->master;
unsigned long now = jiffies;
spin_lock_bh(&limit_lock);
r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY;
if (r->credit > r->credit_cap)
r->credit = r->credit_cap;
priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY;
if (priv->credit > r->credit_cap)
priv->credit = r->credit_cap;
if (r->credit >= r->cost) {
if (priv->credit >= r->cost) {
/* We're not limited. */
r->credit -= r->cost;
priv->credit -= r->cost;
spin_unlock_bh(&limit_lock);
return true;
}
@@ -95,6 +100,7 @@ user2credits(u_int32_t user)
static bool limit_mt_check(const struct xt_mtchk_param *par)
{
struct xt_rateinfo *r = par->matchinfo;
struct xt_limit_priv *priv;
/* Check for overflow. */
if (r->burst == 0
@@ -104,19 +110,30 @@ static bool limit_mt_check(const struct xt_mtchk_param *par)
return false;
}
/* For SMP, we only want to use one set of counters. */
r->master = r;
priv = kmalloc(sizeof(*priv), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
/* For SMP, we only want to use one set of state. */
r->master = priv;
if (r->cost == 0) {
/* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
128. */
r->prev = jiffies;
r->credit = user2credits(r->avg * r->burst); /* Credits full. */
priv->prev = jiffies;
priv->credit = user2credits(r->avg * r->burst); /* Credits full. */
r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
r->cost = user2credits(r->avg);
}
return true;
}
static void limit_mt_destroy(const struct xt_mtdtor_param *par)
{
const struct xt_rateinfo *info = par->matchinfo;
kfree(info->master);
}
#ifdef CONFIG_COMPAT
struct compat_xt_rateinfo {
u_int32_t avg;
@@ -167,6 +184,7 @@ static struct xt_match limit_mt_reg __read_mostly = {
.family = NFPROTO_UNSPEC,
.match = limit_mt,
.checkentry = limit_mt_check,
.destroy = limit_mt_destroy,
.matchsize = sizeof(struct xt_rateinfo),
#ifdef CONFIG_COMPAT
.compatsize = sizeof(struct compat_xt_rateinfo),
+23 -14
View File
@@ -20,13 +20,30 @@ MODULE_DESCRIPTION("Xtables: Bridge physical device match");
MODULE_ALIAS("ipt_physdev");
MODULE_ALIAS("ip6t_physdev");
static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
{
const unsigned long *a = (const unsigned long *)_a;
const unsigned long *b = (const unsigned long *)_b;
const unsigned long *mask = (const unsigned long *)_mask;
unsigned long ret;
ret = (a[0] ^ b[0]) & mask[0];
if (IFNAMSIZ > sizeof(unsigned long))
ret |= (a[1] ^ b[1]) & mask[1];
if (IFNAMSIZ > 2 * sizeof(unsigned long))
ret |= (a[2] ^ b[2]) & mask[2];
if (IFNAMSIZ > 3 * sizeof(unsigned long))
ret |= (a[3] ^ b[3]) & mask[3];
BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
return ret;
}
static bool
physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
int i;
static const char nulldevname[IFNAMSIZ];
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
const struct xt_physdev_info *info = par->matchinfo;
bool ret;
unsigned long ret;
const char *indev, *outdev;
const struct nf_bridge_info *nf_bridge;
@@ -68,11 +85,7 @@ physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par)
if (!(info->bitmask & XT_PHYSDEV_OP_IN))
goto match_outdev;
indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) {
ret |= (((const unsigned int *)indev)[i]
^ ((const unsigned int *)info->physindev)[i])
& ((const unsigned int *)info->in_mask)[i];
}
ret = ifname_compare(indev, info->physindev, info->in_mask);
if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN))
return false;
@@ -82,13 +95,9 @@ match_outdev:
return true;
outdev = nf_bridge->physoutdev ?
nf_bridge->physoutdev->name : nulldevname;
for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) {
ret |= (((const unsigned int *)outdev)[i]
^ ((const unsigned int *)info->physoutdev)[i])
& ((const unsigned int *)info->out_mask)[i];
}
ret = ifname_compare(outdev, info->physoutdev, info->out_mask);
return ret ^ !(info->invert & XT_PHYSDEV_OP_OUT);
return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT));
}
static bool physdev_mt_check(const struct xt_mtchk_param *par)
+24 -7
View File
@@ -9,6 +9,10 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_quota.h>
struct xt_quota_priv {
uint64_t quota;
};
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
MODULE_DESCRIPTION("Xtables: countdown quota match");
@@ -20,18 +24,20 @@ static DEFINE_SPINLOCK(quota_lock);
static bool
quota_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
struct xt_quota_info *q =
((const struct xt_quota_info *)par->matchinfo)->master;
struct xt_quota_info *q = (void *)par->matchinfo;
struct xt_quota_priv *priv = q->master;
bool ret = q->flags & XT_QUOTA_INVERT;
spin_lock_bh(&quota_lock);
if (q->quota >= skb->len) {
q->quota -= skb->len;
if (priv->quota >= skb->len) {
priv->quota -= skb->len;
ret = !ret;
} else {
/* we do not allow even small packets from now on */
q->quota = 0;
priv->quota = 0;
}
/* Copy quota back to matchinfo so that iptables can display it */
q->quota = priv->quota;
spin_unlock_bh(&quota_lock);
return ret;
@@ -43,17 +49,28 @@ static bool quota_mt_check(const struct xt_mtchk_param *par)
if (q->flags & ~XT_QUOTA_MASK)
return false;
/* For SMP, we only want to use one set of counters. */
q->master = q;
q->master = kmalloc(sizeof(*q->master), GFP_KERNEL);
if (q->master == NULL)
return -ENOMEM;
return true;
}
static void quota_mt_destroy(const struct xt_mtdtor_param *par)
{
const struct xt_quota_info *q = par->matchinfo;
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,
};
+23 -5
View File
@@ -16,6 +16,10 @@
#include <linux/netfilter/xt_statistic.h>
#include <linux/netfilter/x_tables.h>
struct xt_statistic_priv {
uint32_t count;
};
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)");
@@ -27,7 +31,7 @@ static DEFINE_SPINLOCK(nth_lock);
static bool
statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
struct xt_statistic_info *info = (void *)par->matchinfo;
const struct xt_statistic_info *info = par->matchinfo;
bool ret = info->flags & XT_STATISTIC_INVERT;
switch (info->mode) {
@@ -36,10 +40,9 @@ statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par)
ret = !ret;
break;
case XT_STATISTIC_MODE_NTH:
info = info->master;
spin_lock_bh(&nth_lock);
if (info->u.nth.count++ == info->u.nth.every) {
info->u.nth.count = 0;
if (info->master->count++ == info->u.nth.every) {
info->master->count = 0;
ret = !ret;
}
spin_unlock_bh(&nth_lock);
@@ -56,16 +59,31 @@ static bool statistic_mt_check(const struct xt_mtchk_param *par)
if (info->mode > XT_STATISTIC_MODE_MAX ||
info->flags & ~XT_STATISTIC_MASK)
return false;
info->master = info;
info->master = kzalloc(sizeof(*info->master), GFP_KERNEL);
if (info->master == NULL) {
printk(KERN_ERR KBUILD_MODNAME ": Out of memory\n");
return false;
}
info->master->count = info->u.nth.count;
return true;
}
static void statistic_mt_destroy(const struct xt_mtdtor_param *par)
{
const struct xt_statistic_info *info = par->matchinfo;
kfree(info->master);
}
static struct xt_match xt_statistic_mt_reg __read_mostly = {
.name = "statistic",
.revision = 0,
.family = NFPROTO_UNSPEC,
.match = statistic_mt,
.checkentry = statistic_mt_check,
.destroy = statistic_mt_destroy,
.matchsize = sizeof(struct xt_statistic_info),
.me = THIS_MODULE,
};