mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-09-20 01:44:10 +03:00
14e55e3c98
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@17844 3c298f89-4303-0410-b956-a3cf2f4a3e73
418 lines
15 KiB
Diff
418 lines
15 KiB
Diff
--- a/net/ipv4/netfilter/Config.in
|
|
+++ b/net/ipv4/netfilter/Config.in
|
|
@@ -11,6 +11,8 @@ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ];
|
|
dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
|
|
dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
|
|
dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
|
|
+ dep_tristate ' Connection tracking flow accounting' CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK
|
|
+ dep_tristate ' Connection byte counter support' CONFIG_IP_NF_MATCH_CONNBYTES $CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES
|
|
fi
|
|
|
|
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
|
|
--- a/net/ipv4/netfilter/Makefile
|
|
+++ b/net/ipv4/netfilter/Makefile
|
|
@@ -85,6 +85,7 @@ obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_
|
|
obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
|
|
obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
|
|
obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
|
|
+obj-$(CONFIG_IP_NF_MATCH_CONNBYTES) += ipt_connbytes.o
|
|
obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
|
|
obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
|
|
obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
|
|
--- a/net/ipv4/netfilter/ip_conntrack_amanda.c
|
|
+++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
|
|
@@ -75,7 +75,7 @@ static int help(const struct iphdr *iph,
|
|
|
|
/* increase the UDP timeout of the master connection as replies from
|
|
* Amanda clients to the server can be quite delayed */
|
|
- ip_ct_refresh(ct, master_timeout * HZ);
|
|
+ ip_ct_refresh_acct(ct,ctinfo,NULL, master_timeout * HZ);
|
|
|
|
/* Search for "CONNECT " string */
|
|
do {
|
|
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
|
|
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
|
|
@@ -211,7 +211,7 @@ static int tcp_packet(struct ip_conntrac
|
|
set_bit(IPS_ASSURED_BIT, &conntrack->status);
|
|
|
|
WRITE_UNLOCK(&tcp_lock);
|
|
- ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
|
|
+ ip_ct_refresh_acct(conntrack,ctinfo,iph, *tcp_timeouts[newconntrack]);
|
|
}
|
|
|
|
return NF_ACCEPT;
|
|
--- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c
|
|
+++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
|
|
@@ -47,16 +47,16 @@ static unsigned int udp_print_conntrack(
|
|
/* Returns verdict for packet, and may modify conntracktype */
|
|
static int udp_packet(struct ip_conntrack *conntrack,
|
|
struct iphdr *iph, size_t len,
|
|
- enum ip_conntrack_info conntrackinfo)
|
|
+ enum ip_conntrack_info ctinfo)
|
|
{
|
|
/* If we've seen traffic both ways, this is some kind of UDP
|
|
stream. Extend timeout. */
|
|
if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
|
|
- ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream);
|
|
+ ip_ct_refresh_acct(conntrack,ctinfo,iph,ip_ct_udp_timeout_stream);
|
|
/* Also, more likely to be important, and not a probe */
|
|
set_bit(IPS_ASSURED_BIT, &conntrack->status);
|
|
} else
|
|
- ip_ct_refresh(conntrack, ip_ct_udp_timeout);
|
|
+ ip_ct_refresh_acct(conntrack,ctinfo,iph, ip_ct_udp_timeout);
|
|
|
|
return NF_ACCEPT;
|
|
}
|
|
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
|
|
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
|
|
@@ -79,6 +79,18 @@ print_expect(char *buffer, const struct
|
|
return len;
|
|
}
|
|
|
|
+#if defined(CONFIG_IP_NF_CT_ACCT) || \
|
|
+ defined(CONFIG_IP_NF_CT_ACCT_MODULE)
|
|
+static unsigned int
|
|
+print_counters(char *buffer, struct ip_conntrack_counter *counter)
|
|
+{
|
|
+ return sprintf(buffer, "packets=%llu bytes=%llu ",
|
|
+ counter->packets, counter->bytes);
|
|
+}
|
|
+#else
|
|
+#define print_counters(x, y) 0
|
|
+#endif
|
|
+
|
|
static unsigned int
|
|
print_conntrack(char *buffer, struct ip_conntrack *conntrack)
|
|
{
|
|
@@ -98,11 +110,15 @@ print_conntrack(char *buffer, struct ip_
|
|
len += print_tuple(buffer + len,
|
|
&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
|
|
proto);
|
|
+ len += print_counters(buffer + len,
|
|
+ &conntrack->counters[IP_CT_DIR_ORIGINAL]);
|
|
if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
|
|
len += sprintf(buffer + len, "[UNREPLIED] ");
|
|
len += print_tuple(buffer + len,
|
|
&conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
|
|
proto);
|
|
+ len += print_counters(buffer + len,
|
|
+ &conntrack->counters[IP_CT_DIR_REPLY]);
|
|
if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
|
|
len += sprintf(buffer + len, "[ASSURED] ");
|
|
len += sprintf(buffer + len, "use=%u ",
|
|
@@ -481,7 +497,7 @@ EXPORT_SYMBOL(ip_conntrack_get);
|
|
EXPORT_SYMBOL(ip_conntrack_helper_register);
|
|
EXPORT_SYMBOL(ip_conntrack_helper_unregister);
|
|
EXPORT_SYMBOL(ip_ct_iterate_cleanup);
|
|
-EXPORT_SYMBOL(ip_ct_refresh);
|
|
+EXPORT_SYMBOL(ip_ct_refresh_acct);
|
|
EXPORT_SYMBOL(ip_ct_find_proto);
|
|
EXPORT_SYMBOL(__ip_ct_find_proto);
|
|
EXPORT_SYMBOL(ip_ct_find_helper);
|
|
--- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c
|
|
+++ b/net/ipv4/netfilter/ip_conntrack_proto_generic.c
|
|
@@ -41,9 +41,9 @@ static unsigned int generic_print_conntr
|
|
/* Returns verdict for packet, or -1 for invalid. */
|
|
static int established(struct ip_conntrack *conntrack,
|
|
struct iphdr *iph, size_t len,
|
|
- enum ip_conntrack_info conntrackinfo)
|
|
+ enum ip_conntrack_info ctinfo)
|
|
{
|
|
- ip_ct_refresh(conntrack, ip_ct_generic_timeout);
|
|
+ ip_ct_refresh_acct(conntrack, ctinfo,iph,ip_ct_generic_timeout);
|
|
return NF_ACCEPT;
|
|
}
|
|
|
|
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
|
|
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
|
|
@@ -82,7 +82,7 @@ static int icmp_packet(struct ip_conntra
|
|
ct->timeout.function((unsigned long)ct);
|
|
} else {
|
|
atomic_inc(&ct->proto.icmp.count);
|
|
- ip_ct_refresh(ct, ip_ct_icmp_timeout);
|
|
+ ip_ct_refresh_acct(ct,ctinfo,iph, ip_ct_icmp_timeout);
|
|
}
|
|
|
|
return NF_ACCEPT;
|
|
--- a/net/ipv4/netfilter/ip_conntrack_core.c
|
|
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
|
|
@@ -1193,22 +1193,40 @@ void ip_conntrack_helper_unregister(stru
|
|
|
|
MOD_DEC_USE_COUNT;
|
|
}
|
|
+static inline void ct_add_counters(struct ip_conntrack *ct,
|
|
+ enum ip_conntrack_info ctinfo,
|
|
+ const struct iphdr *iph)
|
|
+{
|
|
+#if defined(CONFIG_IP_NF_CT_ACCT) || \
|
|
+ defined(CONFIG_IP_NF_CT_ACCT_MODULE)
|
|
+ if (iph) {
|
|
+ ct->counters[CTINFO2DIR(ctinfo)].packets++;
|
|
+ ct->counters[CTINFO2DIR(ctinfo)].bytes +=
|
|
+ ntohs(iph->tot_len);
|
|
+ }
|
|
+#endif
|
|
+}
|
|
|
|
/* Refresh conntrack for this many jiffies. */
|
|
-void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
|
|
+void ip_ct_refresh_acct(struct ip_conntrack *ct,
|
|
+ enum ip_conntrack_info ctinfo,
|
|
+ const struct iphdr *iph,
|
|
+ unsigned long extra_jiffies)
|
|
{
|
|
IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
|
|
|
|
WRITE_LOCK(&ip_conntrack_lock);
|
|
/* If not in hash table, timer will not be active yet */
|
|
- if (!is_confirmed(ct))
|
|
+ if (!is_confirmed(ct)) {
|
|
ct->timeout.expires = extra_jiffies;
|
|
- else {
|
|
+ ct_add_counters(ct, ctinfo,iph);
|
|
+ } else {
|
|
/* Need del_timer for race avoidance (may already be dying). */
|
|
if (del_timer(&ct->timeout)) {
|
|
ct->timeout.expires = jiffies + extra_jiffies;
|
|
add_timer(&ct->timeout);
|
|
}
|
|
+ ct_add_counters(ct, ctinfo, iph);
|
|
}
|
|
WRITE_UNLOCK(&ip_conntrack_lock);
|
|
}
|
|
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
|
|
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
|
|
@@ -156,6 +156,12 @@ struct ip_conntrack_expect
|
|
union ip_conntrack_expect_help help;
|
|
};
|
|
|
|
+struct ip_conntrack_counter
|
|
+{
|
|
+ u_int64_t packets;
|
|
+ u_int64_t bytes;
|
|
+};
|
|
+
|
|
struct ip_conntrack_helper;
|
|
|
|
struct ip_conntrack
|
|
@@ -173,6 +179,12 @@ struct ip_conntrack
|
|
/* Timer function; drops refcnt when it goes off. */
|
|
struct timer_list timeout;
|
|
|
|
+#if defined(CONFIG_IP_NF_CT_ACCT) || \
|
|
+ defined(CONFIG_IP_NF_CT_ACCT_MODULE)
|
|
+ /* Accounting Information (same cache line as other written members) */
|
|
+ struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
|
|
+#endif
|
|
+
|
|
/* If we're expecting another related connection, this will be
|
|
in expected linked list */
|
|
struct list_head sibling_list;
|
|
@@ -256,8 +268,10 @@ extern int invert_tuplepr(struct ip_conn
|
|
const struct ip_conntrack_tuple *orig);
|
|
|
|
/* Refresh conntrack for this many jiffies */
|
|
-extern void ip_ct_refresh(struct ip_conntrack *ct,
|
|
- unsigned long extra_jiffies);
|
|
+extern void ip_ct_refresh_acct(struct ip_conntrack *ct,
|
|
+ enum ip_conntrack_info ctinfo,
|
|
+ const struct iphdr *iph,
|
|
+ unsigned long extra_jiffies);
|
|
|
|
/* These are for NAT. Icky. */
|
|
/* Call me when a conntrack is destroyed. */
|
|
--- /dev/null
|
|
+++ b/net/ipv4/netfilter/ipt_connbytes.c
|
|
@@ -0,0 +1,163 @@
|
|
+/* Kernel module to match connection tracking byte counter.
|
|
+ * GPL (C) 2002 Martin Devera (devik@cdi.cz).
|
|
+ *
|
|
+ * 2004-07-20 Harald Welte <laforge at netfilter.org>
|
|
+ * - reimplemented to use per-connection accounting counters
|
|
+ * - add functionality to match number of packets
|
|
+ * - add functionality to match average packet size
|
|
+ * - add support to match directions seperately
|
|
+ *
|
|
+ * 2004-10-24 Piotr Chytla <pch at fouk.org>
|
|
+ * - Connbytes with per-connection accouting backported to 2.4
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/skbuff.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/netfilter_ipv4/ip_conntrack.h>
|
|
+#include <linux/netfilter_ipv4/ip_tables.h>
|
|
+#include <linux/netfilter_ipv4/ipt_connbytes.h>
|
|
+
|
|
+#include <asm/div64.h>
|
|
+
|
|
+static u_int64_t mydiv(u_int64_t arg1,u_int32_t arg2)
|
|
+{
|
|
+ do_div(arg1,arg2);
|
|
+ return arg1;
|
|
+}
|
|
+
|
|
+static int
|
|
+match(const struct sk_buff *skb,
|
|
+ const struct net_device *in,
|
|
+ const struct net_device *out,
|
|
+ const void *matchinfo,
|
|
+ int offset,
|
|
+ const void *hdr,
|
|
+ u_int16_t datalen,
|
|
+ int *hotdrop)
|
|
+{
|
|
+ static u_int64_t what;
|
|
+ const struct ipt_connbytes_info *sinfo = matchinfo;
|
|
+ enum ip_conntrack_info ctinfo;
|
|
+ struct ip_conntrack *ct;
|
|
+
|
|
+ if (!(ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)))
|
|
+ return 0; /* no match */
|
|
+ switch (sinfo->what) {
|
|
+ case IPT_CONNBYTES_PKTS:
|
|
+ switch (sinfo->direction) {
|
|
+ case IPT_CONNBYTES_DIR_ORIGINAL:
|
|
+ what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
|
|
+ break;
|
|
+ case IPT_CONNBYTES_DIR_REPLY:
|
|
+ what = ct->counters[IP_CT_DIR_REPLY].packets;
|
|
+ break;
|
|
+ case IPT_CONNBYTES_DIR_BOTH:
|
|
+ what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
|
|
+ what += ct->counters[IP_CT_DIR_REPLY].packets;
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case IPT_CONNBYTES_BYTES:
|
|
+ switch (sinfo->direction) {
|
|
+ case IPT_CONNBYTES_DIR_ORIGINAL:
|
|
+ what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
|
|
+ break;
|
|
+ case IPT_CONNBYTES_DIR_REPLY:
|
|
+ what = ct->counters[IP_CT_DIR_REPLY].bytes;
|
|
+ break;
|
|
+ case IPT_CONNBYTES_DIR_BOTH:
|
|
+ what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
|
|
+ what += ct->counters[IP_CT_DIR_REPLY].bytes;
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case IPT_CONNBYTES_AVGPKT:
|
|
+ switch (sinfo->direction) {
|
|
+ case IPT_CONNBYTES_DIR_ORIGINAL:
|
|
+ {
|
|
+ u_int32_t pkts32;
|
|
+
|
|
+ if (ct->counters[IP_CT_DIR_ORIGINAL].packets > 0xfffffffff)
|
|
+ pkts32 = 0xffffffff;
|
|
+ else
|
|
+ pkts32 = ct->counters[IP_CT_DIR_ORIGINAL].packets;
|
|
+ what = mydiv(ct->counters[IP_CT_DIR_ORIGINAL].bytes,pkts32);
|
|
+ }
|
|
+ break;
|
|
+ case IPT_CONNBYTES_DIR_REPLY:
|
|
+ {
|
|
+ u_int32_t pkts32;
|
|
+
|
|
+ if (ct->counters[IP_CT_DIR_REPLY].packets > 0xffffffff)
|
|
+ pkts32 = 0xffffffff;
|
|
+ else
|
|
+ pkts32 = ct->counters[IP_CT_DIR_REPLY].packets;
|
|
+ what = mydiv(ct->counters[IP_CT_DIR_REPLY].bytes,pkts32);
|
|
+ }
|
|
+ break;
|
|
+ case IPT_CONNBYTES_DIR_BOTH:
|
|
+ {
|
|
+ u_int64_t bytes;
|
|
+ u_int64_t pkts;
|
|
+ u_int32_t pkts32;
|
|
+ bytes = ct->counters[IP_CT_DIR_ORIGINAL].bytes +
|
|
+ ct->counters[IP_CT_DIR_REPLY].bytes;
|
|
+ pkts = ct->counters[IP_CT_DIR_ORIGINAL].packets +
|
|
+ ct->counters[IP_CT_DIR_REPLY].packets;
|
|
+ if (pkts > 0xffffffff)
|
|
+ pkts32 = 0xffffffff;
|
|
+ else
|
|
+ pkts32 = pkts;
|
|
+ what = mydiv(bytes,pkts);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ if (sinfo->count.to)
|
|
+ return (what <= sinfo->count.to && what >= sinfo->count.from);
|
|
+ else
|
|
+ return (what >= sinfo->count.from);
|
|
+}
|
|
+
|
|
+static int check(const char *tablename,
|
|
+ const struct ipt_ip *ip,
|
|
+ void *matchinfo,
|
|
+ unsigned int matchsize,
|
|
+ unsigned int hook_mask)
|
|
+{
|
|
+ const struct ipt_connbytes_info *sinfo = matchinfo;
|
|
+
|
|
+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_connbytes_info)))
|
|
+ return 0;
|
|
+ if (sinfo->what != IPT_CONNBYTES_PKTS &&
|
|
+ sinfo->what != IPT_CONNBYTES_BYTES &&
|
|
+ sinfo->what != IPT_CONNBYTES_AVGPKT)
|
|
+ return 0;
|
|
+
|
|
+ if (sinfo->direction != IPT_CONNBYTES_DIR_ORIGINAL &&
|
|
+ sinfo->direction != IPT_CONNBYTES_DIR_REPLY &&
|
|
+ sinfo->direction != IPT_CONNBYTES_DIR_BOTH)
|
|
+ return 0;
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static struct ipt_match state_match
|
|
+= { { NULL, NULL }, "connbytes", &match, &check, NULL, THIS_MODULE };
|
|
+
|
|
+static int __init init(void)
|
|
+{
|
|
+ return ipt_register_match(&state_match);
|
|
+}
|
|
+
|
|
+static void __exit fini(void)
|
|
+{
|
|
+ ipt_unregister_match(&state_match);
|
|
+}
|
|
+
|
|
+module_init(init);
|
|
+module_exit(fini);
|
|
+MODULE_LICENSE("GPL");
|
|
--- /dev/null
|
|
+++ b/include/linux/netfilter_ipv4/ipt_connbytes.h
|
|
@@ -0,0 +1,25 @@
|
|
+#ifndef _IPT_CONNBYTES_H
|
|
+#define _IPT_CONNBYTES_H
|
|
+enum ipt_connbytes_what {
|
|
+ IPT_CONNBYTES_PKTS,
|
|
+ IPT_CONNBYTES_BYTES,
|
|
+ IPT_CONNBYTES_AVGPKT,
|
|
+};
|
|
+
|
|
+enum ipt_connbytes_direction {
|
|
+ IPT_CONNBYTES_DIR_ORIGINAL,
|
|
+ IPT_CONNBYTES_DIR_REPLY,
|
|
+ IPT_CONNBYTES_DIR_BOTH,
|
|
+};
|
|
+
|
|
+struct ipt_connbytes_info
|
|
+{
|
|
+ struct {
|
|
+ u_int64_t from; /* count to be matched */
|
|
+ u_int64_t to; /* count to be matched */
|
|
+ } count;
|
|
+ u_int8_t what; /* ipt_connbytes_what */
|
|
+ u_int8_t direction; /* ipt_connbytes_direction */
|
|
+};
|
|
+
|
|
+#endif
|