aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/Kconfig48
-rw-r--r--net/netfilter/Makefile4
-rw-r--r--net/netfilter/nf_conntrack_core.c9
-rw-r--r--net/netfilter/nf_conntrack_ftp.c77
-rw-r--r--net/netfilter/nf_conntrack_netlink.c85
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c5
-rw-r--r--net/netfilter/nf_conntrack_proto_udp.c3
-rw-r--r--net/netfilter/nf_conntrack_standalone.c16
-rw-r--r--net/netfilter/xt_CONNSECMARK.c155
-rw-r--r--net/netfilter/xt_SECMARK.c156
-rw-r--r--net/netfilter/xt_connmark.c2
-rw-r--r--net/netfilter/xt_dccp.c3
-rw-r--r--net/netfilter/xt_mark.c2
-rw-r--r--net/netfilter/xt_multiport.c7
-rw-r--r--net/netfilter/xt_quota.c96
-rw-r--r--net/netfilter/xt_sctp.c4
-rw-r--r--net/netfilter/xt_statistic.c112
-rw-r--r--net/netfilter/xt_string.c2
18 files changed, 699 insertions, 87 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index e2893effdfaa..b1622b7de1cf 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -60,6 +60,18 @@ config NF_CONNTRACK_MARK
of packets, but this mark value is kept in the conntrack session
instead of the individual packets.
+config NF_CONNTRACK_SECMARK
+ bool 'Connection tracking security mark support'
+ depends on NF_CONNTRACK && NETWORK_SECMARK
+ help
+ This option enables security markings to be applied to
+ connections. Typically they are copied to connections from
+ packets using the CONNSECMARK target and copied back from
+ connections to packets with the same target, with the packets
+ being originally labeled via SECMARK.
+
+ If unsure, say 'N'.
+
config NF_CONNTRACK_EVENTS
bool "Connection tracking events (EXPERIMENTAL)"
depends on EXPERIMENTAL && NF_CONNTRACK
@@ -174,6 +186,26 @@ config NETFILTER_XT_TARGET_NOTRACK
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
+config NETFILTER_XT_TARGET_SECMARK
+ tristate '"SECMARK" target support'
+ depends on NETFILTER_XTABLES && NETWORK_SECMARK
+ help
+ The SECMARK target allows security marking of network
+ packets, for use with security subsystems.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config NETFILTER_XT_TARGET_CONNSECMARK
+ tristate '"CONNSECMARK" target support'
+ depends on NETFILTER_XTABLES && (NF_CONNTRACK_SECMARK || IP_NF_CONNTRACK_SECMARK)
+ help
+ The CONNSECMARK target copies security markings from packets
+ to connections, and restores security markings from connections
+ to packets (if the packets are not already marked). This would
+ normally be used in conjunction with the SECMARK target.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_MATCH_COMMENT
tristate '"comment" match support'
depends on NETFILTER_XTABLES
@@ -329,6 +361,16 @@ config NETFILTER_XT_MATCH_PKTTYPE
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_QUOTA
+ tristate '"quota" match support'
+ depends on NETFILTER_XTABLES
+ help
+ This option adds a `quota' match, which allows to match on a
+ byte counter.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
config NETFILTER_XT_MATCH_REALM
tristate '"realm" match support'
depends on NETFILTER_XTABLES
@@ -365,6 +407,12 @@ config NETFILTER_XT_MATCH_STATE
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_STATISTIC
+ tristate '"statistic" match support'
+ depends on NETFILTER_XTABLES
+ help
+ statistic module
+
config NETFILTER_XT_MATCH_STRING
tristate '"string" match support'
depends on NETFILTER_XTABLES
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 95b7e416512d..6fa4b7580458 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -28,6 +28,8 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
# matches
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
@@ -44,9 +46,11 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o
obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o
obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o
obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o
obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f9b83f91371a..cd299f4b7db1 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -990,6 +990,9 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
#ifdef CONFIG_NF_CONNTRACK_MARK
conntrack->mark = exp->master->mark;
#endif
+#ifdef CONFIG_NF_CONNTRACK_SECMARK
+ conntrack->secmark = exp->master->secmark;
+#endif
nf_conntrack_get(&conntrack->master->ct_general);
NF_CT_STAT_INC(expect_new);
} else
@@ -1396,6 +1399,12 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
write_lock_bh(&nf_conntrack_lock);
+ /* Only update if this is not a fixed timeout */
+ if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
+ write_unlock_bh(&nf_conntrack_lock);
+ return;
+ }
+
/* If not in hash table, timer will not be active yet */
if (!nf_ct_is_confirmed(ct)) {
ct->timeout.expires = extra_jiffies;
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index e38a4b5a3089..11d3be243536 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -67,37 +67,48 @@ static int try_epsv_response(const char *, size_t, struct nf_conntrack_man *,
char);
static struct ftp_search {
- enum ip_conntrack_dir dir;
const char *pattern;
size_t plen;
char skip;
char term;
enum ip_ct_ftp_type ftptype;
int (*getnum)(const char *, size_t, struct nf_conntrack_man *, char);
-} search[] = {
- {
- IP_CT_DIR_ORIGINAL,
- "PORT", sizeof("PORT") - 1, ' ', '\r',
- IP_CT_FTP_PORT,
- try_rfc959,
+} search[IP_CT_DIR_MAX][2] = {
+ [IP_CT_DIR_ORIGINAL] = {
+ {
+ .pattern = "PORT",
+ .plen = sizeof("PORT") - 1,
+ .skip = ' ',
+ .term = '\r',
+ .ftptype = IP_CT_FTP_PORT,
+ .getnum = try_rfc959,
+ },
+ {
+ .pattern = "EPRT",
+ .plen = sizeof("EPRT") - 1,
+ .skip = ' ',
+ .term = '\r',
+ .ftptype = IP_CT_FTP_EPRT,
+ .getnum = try_eprt,
+ },
},
- {
- IP_CT_DIR_REPLY,
- "227 ", sizeof("227 ") - 1, '(', ')',
- IP_CT_FTP_PASV,
- try_rfc959,
- },
- {
- IP_CT_DIR_ORIGINAL,
- "EPRT", sizeof("EPRT") - 1, ' ', '\r',
- IP_CT_FTP_EPRT,
- try_eprt,
- },
- {
- IP_CT_DIR_REPLY,
- "229 ", sizeof("229 ") - 1, '(', ')',
- IP_CT_FTP_EPSV,
- try_epsv_response,
+ [IP_CT_DIR_REPLY] = {
+ {
+ .pattern = "227 ",
+ .plen = sizeof("227 ") - 1,
+ .skip = '(',
+ .term = ')',
+ .ftptype = IP_CT_FTP_PASV,
+ .getnum = try_rfc959,
+ },
+ {
+ .pattern = "229 ",
+ .plen = sizeof("229 ") - 1,
+ .skip = '(',
+ .term = ')',
+ .ftptype = IP_CT_FTP_EPSV,
+ .getnum = try_epsv_response,
+ },
},
};
@@ -492,17 +503,15 @@ static int help(struct sk_buff **pskb,
memcpy(cmd.u3.all, &ct->tuplehash[dir].tuple.src.u3.all,
sizeof(cmd.u3.all));
- for (i = 0; i < ARRAY_SIZE(search); i++) {
- if (search[i].dir != dir) continue;
-
+ for (i = 0; i < ARRAY_SIZE(search[dir]); i++) {
found = find_pattern(fb_ptr, datalen,
- search[i].pattern,
- search[i].plen,
- search[i].skip,
- search[i].term,
+ search[dir][i].pattern,
+ search[dir][i].plen,
+ search[dir][i].skip,
+ search[dir][i].term,
&matchoff, &matchlen,
&cmd,
- search[i].getnum);
+ search[dir][i].getnum);
if (found) break;
}
if (found == -1) {
@@ -512,7 +521,7 @@ static int help(struct sk_buff **pskb,
this case. */
if (net_ratelimit())
printk("conntrack_ftp: partial %s %u+%u\n",
- search[i].pattern,
+ search[dir][i].pattern,
ntohl(th->seq), datalen);
ret = NF_DROP;
goto out;
@@ -597,7 +606,7 @@ static int help(struct sk_buff **pskb,
/* Now, NAT might want to mangle the packet, and register the
* (possibly changed) expectation itself. */
if (nf_nat_ftp_hook)
- ret = nf_nat_ftp_hook(pskb, ctinfo, search[i].ftptype,
+ ret = nf_nat_ftp_hook(pskb, ctinfo, search[dir][i].ftptype,
matchoff, matchlen, exp, &seq);
else {
/* Can't expect this? Best to drop packet now. */
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index bd10eb944b65..b8c7c567c9df 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -407,6 +407,8 @@ nfattr_failure:
static int ctnetlink_done(struct netlink_callback *cb)
{
+ if (cb->args[1])
+ nf_ct_put((struct nf_conn *)cb->args[1]);
DEBUGP("entered %s\n", __FUNCTION__);
return 0;
}
@@ -416,10 +418,9 @@ static int ctnetlink_done(struct netlink_callback *cb)
static int
ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct nf_conn *ct = NULL;
+ struct nf_conn *ct, *last;
struct nf_conntrack_tuple_hash *h;
struct list_head *i;
- u_int32_t *id = (u_int32_t *) &cb->args[1];
struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
u_int8_t l3proto = nfmsg->nfgen_family;
@@ -427,7 +428,9 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
cb->args[0], *id);
read_lock_bh(&nf_conntrack_lock);
- for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++, *id = 0) {
+ for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
+restart:
+ last = (struct nf_conn *)cb->args[1];
list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) {
h = (struct nf_conntrack_tuple_hash *) i;
if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)
@@ -438,17 +441,30 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
* then dump everything. */
if (l3proto && L3PROTO(ct) != l3proto)
continue;
- if (ct->id <= *id)
- continue;
+ if (last != NULL) {
+ if (ct == last) {
+ nf_ct_put(last);
+ cb->args[1] = 0;
+ last = NULL;
+ } else
+ continue;
+ }
if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
IPCTNL_MSG_CT_NEW,
- 1, ct) < 0)
+ 1, ct) < 0) {
+ nf_conntrack_get(&ct->ct_general);
+ cb->args[1] = (unsigned long)ct;
goto out;
- *id = ct->id;
+ }
+ }
+ if (last != NULL) {
+ nf_ct_put(last);
+ cb->args[1] = 0;
+ goto restart;
}
}
-out:
+out:
read_unlock_bh(&nf_conntrack_lock);
DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
@@ -641,7 +657,7 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = {
};
static inline int
-ctnetlink_parse_nat(struct nfattr *cda[],
+ctnetlink_parse_nat(struct nfattr *nat,
const struct nf_conn *ct, struct ip_nat_range *range)
{
struct nfattr *tb[CTA_NAT_MAX];
@@ -651,7 +667,7 @@ ctnetlink_parse_nat(struct nfattr *cda[],
memset(range, 0, sizeof(*range));
- nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
+ nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
return -EINVAL;
@@ -866,39 +882,30 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[])
/* ASSURED bit can only be set */
return -EINVAL;
- if (cda[CTA_NAT-1]) {
+ if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
#ifndef CONFIG_IP_NF_NAT_NEEDED
return -EINVAL;
#else
- unsigned int hooknum;
struct ip_nat_range range;
- if (ctnetlink_parse_nat(cda, ct, &range) < 0)
- return -EINVAL;
-
- DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n",
- NIPQUAD(range.min_ip), NIPQUAD(range.max_ip),
- htons(range.min.all), htons(range.max.all));
-
- /* This is tricky but it works. ip_nat_setup_info needs the
- * hook number as parameter, so let's do the correct
- * conversion and run away */
- if (status & IPS_SRC_NAT_DONE)
- hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */
- else if (status & IPS_DST_NAT_DONE)
- hooknum = NF_IP_PRE_ROUTING; /* IP_NAT_MANIP_DST */
- else
- return -EINVAL; /* Missing NAT flags */
-
- DEBUGP("NAT status: %lu\n",
- status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
-
- if (ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
- return -EEXIST;
- ip_nat_setup_info(ct, &range, hooknum);
-
- DEBUGP("NAT status after setup_info: %lu\n",
- ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));
+ if (cda[CTA_NAT_DST-1]) {
+ if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct,
+ &range) < 0)
+ return -EINVAL;
+ if (ip_nat_initialized(ct,
+ HOOK2MANIP(NF_IP_PRE_ROUTING)))
+ return -EEXIST;
+ ip_nat_setup_info(ct, &range, hooknum);
+ }
+ if (cda[CTA_NAT_SRC-1]) {
+ if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct,
+ &range) < 0)
+ return -EINVAL;
+ if (ip_nat_initialized(ct,
+ HOOK2MANIP(NF_IP_POST_ROUTING)))
+ return -EEXIST;
+ ip_nat_setup_info(ct, &range, hooknum);
+ }
#endif
}
@@ -1122,7 +1129,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
/* implicit 'else' */
/* we only allow nat config for new conntracks */
- if (cda[CTA_NAT-1]) {
+ if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
err = -EINVAL;
goto out_unlock;
}
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 69899f27d26a..12fb7c0a1509 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -828,8 +828,9 @@ static int tcp_error(struct sk_buff *skb,
* and moreover root might send raw packets.
*/
/* FIXME: Source route IP option packets --RR */
- if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
- (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
+ if (nf_conntrack_checksum &&
+ ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+ (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) {
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index d93edbfde9e3..ae07ebe3ab37 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -134,7 +134,8 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff,
* because the semantic of CHECKSUM_HW is different there
* and moreover root might send raw packets.
* FIXME: Source route IP option packets --RR */
- if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+ if (nf_conntrack_checksum &&
+ ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
(pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
if (LOG_INVALID(IPPROTO_UDP))
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 408960c6a544..e34c574f0351 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -213,6 +213,11 @@ static int ct_seq_show(struct seq_file *s, void *v)
return -ENOSPC;
#endif
+#ifdef CONFIG_NF_CONNTRACK_SECMARK
+ if (seq_printf(s, "secmark=%u ", conntrack->secmark))
+ return -ENOSPC;
+#endif
+
if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
return -ENOSPC;
@@ -455,6 +460,8 @@ extern unsigned int nf_ct_generic_timeout;
static int log_invalid_proto_min = 0;
static int log_invalid_proto_max = 255;
+int nf_conntrack_checksum = 1;
+
static struct ctl_table_header *nf_ct_sysctl_header;
static ctl_table nf_ct_sysctl_table[] = {
@@ -483,6 +490,14 @@ static ctl_table nf_ct_sysctl_table[] = {
.proc_handler = &proc_dointvec,
},
{
+ .ctl_name = NET_NF_CONNTRACK_CHECKSUM,
+ .procname = "nf_conntrack_checksum",
+ .data = &nf_conntrack_checksum,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
.ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
.procname = "nf_conntrack_tcp_timeout_syn_sent",
.data = &nf_ct_tcp_timeout_syn_sent,
@@ -851,6 +866,7 @@ EXPORT_SYMBOL(nf_ct_proto_put);
EXPORT_SYMBOL(nf_ct_l3proto_find_get);
EXPORT_SYMBOL(nf_ct_l3proto_put);
EXPORT_SYMBOL(nf_ct_l3protos);
+EXPORT_SYMBOL_GPL(nf_conntrack_checksum);
EXPORT_SYMBOL(nf_conntrack_expect_alloc);
EXPORT_SYMBOL(nf_conntrack_expect_put);
EXPORT_SYMBOL(nf_conntrack_expect_related);
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
new file mode 100644
index 000000000000..8c011e020769
--- /dev/null
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -0,0 +1,155 @@
+/*
+ * This module is used to copy security markings from packets
+ * to connections, and restore security markings from connections
+ * back to packets. This would normally be performed in conjunction
+ * with the SECMARK target and state match.
+ *
+ * Based somewhat on CONNMARK:
+ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ *
+ * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ * 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/netfilter/x_tables.h>
+#include <linux/netfilter/xt_CONNSECMARK.h>
+#include <net/netfilter/nf_conntrack_compat.h>
+
+#define PFX "CONNSECMARK: "
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Morris <jmorris@redhat.com>");
+MODULE_DESCRIPTION("ip[6]tables CONNSECMARK module");
+MODULE_ALIAS("ipt_CONNSECMARK");
+MODULE_ALIAS("ip6t_CONNSECMARK");
+
+/*
+ * If the packet has a security mark and the connection does not, copy
+ * the security mark from the packet to the connection.
+ */
+static void secmark_save(struct sk_buff *skb)
+{
+ if (skb->secmark) {
+ u32 *connsecmark;
+ enum ip_conntrack_info ctinfo;
+
+ connsecmark = nf_ct_get_secmark(skb, &ctinfo);
+ if (connsecmark && !*connsecmark)
+ if (*connsecmark != skb->secmark)
+ *connsecmark = skb->secmark;
+ }
+}
+
+/*
+ * If packet has no security mark, and the connection does, restore the
+ * security mark from the connection to the packet.
+ */
+static void secmark_restore(struct sk_buff *skb)
+{
+ if (!skb->secmark) {
+ u32 *connsecmark;
+ enum ip_conntrack_info ctinfo;
+
+ connsecmark = nf_ct_get_secmark(skb, &ctinfo);
+ if (connsecmark && *connsecmark)
+ if (skb->secmark != *connsecmark)
+ skb->secmark = *connsecmark;
+ }
+}
+
+static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
+ const struct net_device *out, unsigned int hooknum,
+ const struct xt_target *target,
+ const void *targinfo, void *userinfo)
+{
+ struct sk_buff *skb = *pskb;
+ const struct xt_connsecmark_target_info *info = targinfo;
+
+ switch (info->mode) {
+ case CONNSECMARK_SAVE:
+ secmark_save(skb);
+ break;
+
+ case CONNSECMARK_RESTORE:
+ secmark_restore(skb);
+ break;
+
+ default:
+ BUG();
+ }
+
+ return XT_CONTINUE;
+}
+
+static int checkentry(const char *tablename, const void *entry,
+ const struct xt_target *target, void *targinfo,
+ unsigned int targinfosize, unsigned int hook_mask)
+{
+ struct xt_connsecmark_target_info *info = targinfo;
+
+ switch (info->mode) {
+ case CONNSECMARK_SAVE:
+ case CONNSECMARK_RESTORE:
+ break;
+
+ default:
+ printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct xt_target ipt_connsecmark_reg = {
+ .name = "CONNSECMARK",
+ .target = target,
+ .targetsize = sizeof(struct xt_connsecmark_target_info),
+ .table = "mangle",
+ .checkentry = checkentry,
+ .me = THIS_MODULE,
+ .family = AF_INET,
+ .revision = 0,
+};
+
+static struct xt_target ip6t_connsecmark_reg = {
+ .name = "CONNSECMARK",
+ .target = target,
+ .targetsize = sizeof(struct xt_connsecmark_target_info),
+ .table = "mangle",
+ .checkentry = checkentry,
+ .me = THIS_MODULE,
+ .family = AF_INET6,
+ .revision = 0,
+};
+
+static int __init xt_connsecmark_init(void)
+{
+ int err;
+
+ need_conntrack();
+
+ err = xt_register_target(&ipt_connsecmark_reg);
+ if (err)
+ return err;
+
+ err = xt_register_target(&ip6t_connsecmark_reg);
+ if (err)
+ xt_unregister_target(&ipt_connsecmark_reg);
+
+ return err;
+}
+
+static void __exit xt_connsecmark_fini(void)
+{
+ xt_unregister_target(&ip6t_connsecmark_reg);
+ xt_unregister_target(&ipt_connsecmark_reg);
+}
+
+module_init(xt_connsecmark_init);
+module_exit(xt_connsecmark_fini);
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
new file mode 100644
index 000000000000..c2ce9c4011cc
--- /dev/null
+++ b/net/netfilter/xt_SECMARK.c
@@ -0,0 +1,156 @@
+/*
+ * Module for modifying the secmark field of the skb, for use by
+ * security subsystems.
+ *
+ * Based on the nfmark match by:
+ * (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
+ *
+ * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ * 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/selinux.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_SECMARK.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Morris <jmorris@redhat.com>");
+MODULE_DESCRIPTION("ip[6]tables SECMARK modification module");
+MODULE_ALIAS("ipt_SECMARK");
+MODULE_ALIAS("ip6t_SECMARK");
+
+#define PFX "SECMARK: "
+
+static u8 mode;
+
+static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
+ const struct net_device *out, unsigned int hooknum,
+ const struct xt_target *target,
+ const void *targinfo, void *userinfo)
+{
+ u32 secmark = 0;
+ const struct xt_secmark_target_info *info = targinfo;
+
+ BUG_ON(info->mode != mode);
+
+ switch (mode) {
+ case SECMARK_MODE_SEL:
+ secmark = info->u.sel.selsid;
+ break;
+
+ default:
+ BUG();
+ }
+
+ if ((*pskb)->secmark != secmark)
+ (*pskb)->secmark = secmark;
+
+ return XT_CONTINUE;
+}
+
+static int checkentry_selinux(struct xt_secmark_target_info *info)
+{
+ int err;
+ struct xt_secmark_target_selinux_info *sel = &info->u.sel;
+
+ err = selinux_string_to_sid(sel->selctx, &sel->selsid);
+ if (err) {
+ if (err == -EINVAL)
+ printk(KERN_INFO PFX "invalid SELinux context \'%s\'\n",
+ sel->selctx);
+ return 0;
+ }
+
+ if (!sel->selsid) {
+ printk(KERN_INFO PFX "unable to map SELinux context \'%s\'\n",
+ sel->selctx);
+ return 0;
+ }
+
+ err = selinux_relabel_packet_permission(sel->selsid);
+ if (err) {
+ printk(KERN_INFO PFX "unable to obtain relabeling permission\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int checkentry(const char *tablename, const void *entry,
+ const struct xt_target *target, void *targinfo,
+ unsigned int targinfosize, unsigned int hook_mask)
+{
+ struct xt_secmark_target_info *info = targinfo;
+
+ if (mode && mode != info->mode) {
+ printk(KERN_INFO PFX "mode already set to %hu cannot mix with "
+ "rules for mode %hu\n", mode, info->mode);
+ return 0;
+ }
+
+ switch (info->mode) {
+ case SECMARK_MODE_SEL:
+ if (!checkentry_selinux(info))
+ return 0;
+ break;
+
+ default:
+ printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode);
+ return 0;
+ }
+
+ if (!mode)
+ mode = info->mode;
+ return 1;
+}
+
+static struct xt_target ipt_secmark_reg = {
+ .name = "SECMARK",
+ .target = target,
+ .targetsize = sizeof(struct xt_secmark_target_info),
+ .table = "mangle",
+ .checkentry = checkentry,
+ .me = THIS_MODULE,
+ .family = AF_INET,
+ .revision = 0,
+};
+
+static struct xt_target ip6t_secmark_reg = {
+ .name = "SECMARK",
+ .target = target,
+ .targetsize = sizeof(struct xt_secmark_target_info),
+ .table = "mangle",
+ .checkentry = checkentry,
+ .me = THIS_MODULE,
+ .family = AF_INET6,
+ .revision = 0,
+};
+
+static int __init xt_secmark_init(void)
+{
+ int err;
+
+ err = xt_register_target(&ipt_secmark_reg);
+ if (err)
+ return err;
+
+ err = xt_register_target(&ip6t_secmark_reg);
+ if (err)
+ xt_unregister_target(&ipt_secmark_reg);
+
+ return err;
+}
+
+static void __exit xt_secmark_fini(void)
+{
+ xt_unregister_target(&ip6t_secmark_reg);
+ xt_unregister_target(&ipt_secmark_reg);
+}
+
+module_init(xt_secmark_init);
+module_exit(xt_secmark_fini);
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index dc26a27cbcaf..56324c8aff0a 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -58,7 +58,7 @@ checkentry(const char *tablename,
unsigned int matchsize,
unsigned int hook_mask)
{
- struct xt_connmark_info *cm = (struct xt_connmark_info *)matchinfo;
+ struct xt_connmark_info *cm = matchinfo;
if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
printk(KERN_WARNING "connmark: only support 32bit mark\n");
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c
index dfb10b648e57..2e2f825dad4c 100644
--- a/net/netfilter/xt_dccp.c
+++ b/net/netfilter/xt_dccp.c
@@ -101,8 +101,7 @@ match(const struct sk_buff *skb,
unsigned int protoff,
int *hotdrop)
{
- const struct xt_dccp_info *info =
- (const struct xt_dccp_info *)matchinfo;
+ const struct xt_dccp_info *info = matchinfo;
struct dccp_hdr _dh, *dh;
if (offset)
diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c
index 8b385a34886d..876bc5797738 100644
--- a/net/netfilter/xt_mark.c
+++ b/net/netfilter/xt_mark.c
@@ -42,7 +42,7 @@ checkentry(const char *tablename,
unsigned int matchsize,
unsigned int hook_mask)
{
- struct xt_mark_info *minfo = (struct xt_mark_info *) matchinfo;
+ const struct xt_mark_info *minfo = matchinfo;
if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
printk(KERN_WARNING "mark: only supports 32bit mark\n");
diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c
index b56cd2baaac2..1ff0a25396e7 100644
--- a/net/netfilter/xt_multiport.c
+++ b/net/netfilter/xt_multiport.c
@@ -1,4 +1,4 @@
-/* Kernel module to match one of a list of TCP/UDP ports: ports are in
+/* Kernel module to match one of a list of TCP/UDP/SCTP/DCCP ports: ports are in
the same place so we can treat them as equal. */
/* (C) 1999-2001 Paul `Rusty' Russell
@@ -160,8 +160,9 @@ check(u_int16_t proto,
u_int8_t match_flags,
u_int8_t count)
{
- /* Must specify proto == TCP/UDP, no unknown flags or bad count */
- return (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
+ /* Must specify supported protocol, no unknown flags or bad count */
+ return (proto == IPPROTO_TCP || proto == IPPROTO_UDP
+ || proto == IPPROTO_SCTP || proto == IPPROTO_DCCP)
&& !(ip_invflags & XT_INV_PROTO)
&& (match_flags == XT_MULTIPORT_SOURCE
|| match_flags == XT_MULTIPORT_DESTINATION
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
new file mode 100644
index 000000000000..4cdba7469dc4
--- /dev/null
+++ b/net/netfilter/xt_quota.c
@@ -0,0 +1,96 @@
+/*
+ * netfilter module to enforce network quotas
+ *
+ * Sam Johnston <samj@samj.net>
+ */
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_quota.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
+
+static DEFINE_SPINLOCK(quota_lock);
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, int *hotdrop)
+{
+ struct xt_quota_info *q = ((struct xt_quota_info *)matchinfo)->master;
+ int ret = q->flags & XT_QUOTA_INVERT ? 1 : 0;
+
+ spin_lock_bh(&quota_lock);
+ if (q->quota >= skb->len) {
+ q->quota -= skb->len;
+ ret ^= 1;
+ } else {
+ /* we do not allow even small packets from now on */
+ q->quota = 0;
+ }
+ spin_unlock_bh(&quota_lock);
+
+ return ret;
+}
+
+static int
+checkentry(const char *tablename, const void *entry,
+ const struct xt_match *match, void *matchinfo,
+ unsigned int matchsize, unsigned int hook_mask)
+{
+ struct xt_quota_info *q = (struct xt_quota_info *)matchinfo;
+
+ if (q->flags & ~XT_QUOTA_MASK)
+ return 0;
+ /* For SMP, we only want to use one set of counters. */
+ q->master = q;
+ return 1;
+}
+
+static struct xt_match quota_match = {
+ .name = "quota",
+ .family = AF_INET,
+ .match = match,
+ .matchsize = sizeof(struct xt_quota_info),
+ .checkentry = checkentry,
+ .me = THIS_MODULE
+};
+
+static struct xt_match quota_match6 = {
+ .name = "quota",
+ .family = AF_INET6,
+ .match = match,
+ .matchsize = sizeof(struct xt_quota_info),
+ .checkentry = checkentry,
+ .me = THIS_MODULE
+};
+
+static int __init xt_quota_init(void)
+{
+ int ret;
+
+ ret = xt_register_match(&quota_match);
+ if (ret)
+ goto err1;
+ ret = xt_register_match(&quota_match6);
+ if (ret)
+ goto err2;
+ return ret;
+
+err2:
+ xt_unregister_match(&quota_match);
+err1:
+ return ret;
+}
+
+static void __exit xt_quota_fini(void)
+{
+ xt_unregister_match(&quota_match6);
+ xt_unregister_match(&quota_match);
+}
+
+module_init(xt_quota_init);
+module_exit(xt_quota_fini);
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c
index 34bd87259a09..b5110e5b54b0 100644
--- a/net/netfilter/xt_sctp.c
+++ b/net/netfilter/xt_sctp.c
@@ -129,11 +129,9 @@ match(const struct sk_buff *skb,
unsigned int protoff,
int *hotdrop)
{
- const struct xt_sctp_info *info;
+ const struct xt_sctp_info *info = matchinfo;
sctp_sctphdr_t _sh, *sh;
- info = (const struct xt_sctp_info *)matchinfo;
-
if (offset) {
duprintf("Dropping non-first fragment.. FIXME\n");
return 0;
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c
new file mode 100644
index 000000000000..de1037f58596
--- /dev/null
+++ b/net/netfilter/xt_statistic.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2006 Patrick McHardy <kaber@trash.net>
+ *
+ * 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.
+ *
+ * Based on ipt_random and ipt_nth by Fabrice MARIE <fabrice@netfilter.org>.
+ */
+
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/net.h>
+
+#include <linux/netfilter/xt_statistic.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("xtables statistical match module");
+MODULE_ALIAS("ipt_statistic");
+MODULE_ALIAS("ip6t_statistic");
+
+static DEFINE_SPINLOCK(nth_lock);
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, int *hotdrop)
+{
+ struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo;
+ int ret = info->flags & XT_STATISTIC_INVERT ? 1 : 0;
+
+ switch (info->mode) {
+ case XT_STATISTIC_MODE_RANDOM:
+ if ((net_random() & 0x7FFFFFFF) < info->u.random.probability)
+ ret ^= 1;
+ 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;
+ ret ^= 1;
+ }
+ spin_unlock_bh(&nth_lock);
+ break;
+ }
+
+ return ret;
+}
+
+static int
+checkentry(const char *tablename, const void *entry,
+ const struct xt_match *match, void *matchinfo,
+ unsigned int matchsize, unsigned int hook_mask)
+{
+ struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo;
+
+ if (info->mode > XT_STATISTIC_MODE_MAX ||
+ info->flags & ~XT_STATISTIC_MASK)
+ return 0;
+ info->master = info;
+ return 1;
+}
+
+static struct xt_match statistic_match = {
+ .name = "statistic",
+ .match = match,
+ .matchsize = sizeof(struct xt_statistic_info),
+ .checkentry = checkentry,
+ .family = AF_INET,
+ .me = THIS_MODULE,
+};
+
+static struct xt_match statistic_match6 = {
+ .name = "statistic",
+ .match = match,
+ .matchsize = sizeof(struct xt_statistic_info),
+ .checkentry = checkentry,
+ .family = AF_INET6,
+ .me = THIS_MODULE,
+};
+
+static int __init xt_statistic_init(void)
+{
+ int ret;
+
+ ret = xt_register_match(&statistic_match);
+ if (ret)
+ goto err1;
+
+ ret = xt_register_match(&statistic_match6);
+ if (ret)
+ goto err2;
+ return ret;
+err2:
+ xt_unregister_match(&statistic_match);
+err1:
+ return ret;
+}
+
+static void __exit xt_statistic_fini(void)
+{
+ xt_unregister_match(&statistic_match6);
+ xt_unregister_match(&statistic_match);
+}
+
+module_init(xt_statistic_init);
+module_exit(xt_statistic_fini);
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c
index 79d9ea6964ba..0ebb6ac2c8c7 100644
--- a/net/netfilter/xt_string.c
+++ b/net/netfilter/xt_string.c
@@ -30,8 +30,8 @@ static int match(const struct sk_buff *skb,
unsigned int protoff,
int *hotdrop)
{
+ const struct xt_string_info *conf = matchinfo;
struct ts_state state;
- struct xt_string_info *conf = (struct xt_string_info *) matchinfo;
memset(&state, 0, sizeof(struct ts_state));