* Re: NetFilter unclean modue in 2.6.x kernels
2005-01-21 23:33 ` NetFilter unclean modue in 2.6.x kernels Harald Welte
@ 2005-01-24 8:40 ` Jozsef Kadlecsik
2005-01-24 8:57 ` Harald Welte
2005-01-24 10:21 ` Pablo Neira
0 siblings, 2 replies; 7+ messages in thread
From: Jozsef Kadlecsik @ 2005-01-24 8:40 UTC (permalink / raw)
To: Harald Welte; +Cc: Oleg V. Sapon, netfilter-devel
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1501 bytes --]
Hi Harald,
On Sat, 22 Jan 2005, Harald Welte wrote:
> On Sat, Jan 22, 2005 at 12:13:56AM +0300, Oleg V. Sapon wrote:
> > Can you help locate unclean module for 2.6.x kernel or we must use
> > source files from 2.6.0-test4?
>
> I fear nobody did that port to recent 2.6.x and put it into
> patch-o-matic :(
>
> I just did that with the old code from 2.6.0-testX. I didn't have the
> time to give it any runtime testing, but at least it compiled (after
> fixing up some includes).
I also ported the unclean patch to 2.6 some time ago. The main reason I
did not post it was the slightly modified API.
The port I created verifies the checksums as well, relying on hardware
checksums when possible. It also flags the clean packet in nfcache (that
is where the API was changed) so that the TCP connection tracking code can
rely on the results of the unclean match:
iptables -t raw -A PREROUTING -m unclean -j DROP
If there are plans to submit the unclean match into the kernel, I think
something like my port should be considered.
In order to make the unclean patch acceptable for kernel inclusion, we
could probably add a '--check-reserved' flag to it which would enable all
checkings, while the default would skip checking the reserved bits.
Best regards,
Jozsef
-
E-mail : kadlec@blackhole.kfki.hu, kadlec@sunserv.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
H-1525 Budapest 114, POB. 49, Hungary
[-- Attachment #2: unclean.patch --]
[-- Type: TEXT/PLAIN, Size: 37600 bytes --]
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/include/linux/netfilter.h linux-2.6.9-unclean/include/linux/netfilter.h
--- linux-2.6.9-orig/include/linux/netfilter.h 2004-10-18 23:54:08.000000000 +0200
+++ linux-2.6.9-unclean/include/linux/netfilter.h 2004-12-16 09:59:54.000000000 +0100
@@ -24,6 +24,8 @@
<= 0x2000 is used for protocol-flags. */
#define NFC_UNKNOWN 0x4000
#define NFC_ALTERED 0x8000
+/* #define NFC_TRACE 0x10000 */
+#define NFC_CLEAN 0x20000
#ifdef __KERNEL__
#include <linux/config.h>
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/include/linux/netfilter_ipv4/ip_tables.h linux-2.6.9-unclean/include/linux/netfilter_ipv4/ip_tables.h
--- linux-2.6.9-orig/include/linux/netfilter_ipv4/ip_tables.h 2004-10-18 23:54:31.000000000 +0200
+++ linux-2.6.9-unclean/include/linux/netfilter_ipv4/ip_tables.h 2004-12-16 09:47:34.000000000 +0100
@@ -355,6 +355,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop);
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/Kconfig linux-2.6.9-unclean/net/ipv4/netfilter/Kconfig
--- linux-2.6.9-orig/net/ipv4/netfilter/Kconfig 2004-10-18 23:54:55.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/Kconfig 2004-12-16 09:58:18.000000000 +0100
@@ -610,6 +610,29 @@
<file:Documentation/modules.txt>. If unsure, say `N'.
help
+config IP_NF_MATCH_UNCLEAN
+ tristate 'unclean match support'
+ depends on IP_NF_RAW
+ help
+ Unclean packet matching matches any strange or invalid packets,
+ by looking at a series of fields in the IP, TCP, UDP and ICMP
+ headers.
+
+ If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. If unsure, say `N'.
+
+config IP_NF_MATCH_UNCLEAN_HWCSUM
+ bool 'unclean match supporting hardware checksumming'
+ default n
+ depends on IP_NF_MATCH_UNCLEAN
+ help
+ With this option enabled, the unclean match will be able
+ to use the hardware checksums generated by the network
+ interfaces (if those support HW checksumming) with the price
+ that the match can then be used only in the PREROUTING chain.
+ If the option is disabled, the match itself have to compute
+ the checksums but it can be used in any chain.
+
config IP_NF_TARGET_NOTRACK
tristate 'NOTRACK target support'
depends on IP_NF_RAW
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/Makefile linux-2.6.9-unclean/net/ipv4/netfilter/Makefile
--- linux-2.6.9-orig/net/ipv4/netfilter/Makefile 2004-10-18 23:53:43.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/Makefile 2004-12-16 09:47:50.000000000 +0100
@@ -67,6 +67,7 @@
obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o
+obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
# targets
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.6.9-unclean/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2004-10-18 23:55:29.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2004-12-16 10:02:26.000000000 +0100
@@ -776,6 +776,10 @@
struct tcphdr _tcph, *th;
unsigned int tcplen = skb->len - iph->ihl * 4;
u_int8_t tcpflags;
+
+ /* Already verified by ipt_unclean? */
+ if (skb->nfcache & NFC_CLEAN)
+ return NF_ACCEPT;
/* Smaller that minimal TCP header? */
th = skb_header_pointer(skb, iph->ihl * 4,
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ip_tables.c linux-2.6.9-unclean/net/ipv4/netfilter/ip_tables.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ip_tables.c 2004-10-18 23:53:43.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ip_tables.c 2004-12-16 09:47:34.000000000 +0100
@@ -238,11 +238,13 @@
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
/* Stop iteration if it doesn't match */
- if (!m->u.kernel.match->match(skb, in, out, m->data, offset, hotdrop))
+ if (!m->u.kernel.match->match(skb, in, out, m->data,
+ nfcache, offset, hotdrop))
return 1;
else
return 0;
@@ -318,6 +320,7 @@
if (IPT_MATCH_ITERATE(e, do_match,
*pskb, in, out,
+ &(*pskb)->nfcache,
offset, &hotdrop) != 0)
goto no_match;
@@ -1491,6 +1494,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
@@ -1572,6 +1576,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
@@ -1645,6 +1650,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_addrtype.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_addrtype.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_addrtype.c 2004-10-18 23:53:06.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_addrtype.c 2004-12-16 09:47:34.000000000 +0100
@@ -29,7 +29,7 @@
static int match(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *matchinfo,
- int offset, int *hotdrop)
+ u_int32_t *nfcache, int offset, int *hotdrop)
{
const struct ipt_addrtype_info *info = matchinfo;
const struct iphdr *iph = skb->nh.iph;
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_ah.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ah.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_ah.c 2004-10-18 23:54:37.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ah.c 2004-12-16 09:47:34.000000000 +0100
@@ -40,6 +40,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_comment.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_comment.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_comment.c 2004-10-18 23:54:27.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_comment.c 2004-12-16 09:47:34.000000000 +0100
@@ -18,6 +18,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_conntrack.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_conntrack.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_conntrack.c 2004-10-18 23:55:07.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_conntrack.c 2004-12-16 09:47:34.000000000 +0100
@@ -23,6 +23,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_dscp.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_dscp.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_dscp.c 2004-10-18 23:54:39.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_dscp.c 2004-12-16 09:47:34.000000000 +0100
@@ -21,7 +21,7 @@
static int match(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *matchinfo,
- int offset, int *hotdrop)
+ u_int32_t *nfcache, int offset, int *hotdrop)
{
const struct ipt_dscp_info *info = matchinfo;
const struct iphdr *iph = skb->nh.iph;
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_ecn.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ecn.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_ecn.c 2004-10-18 23:54:08.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ecn.c 2004-12-16 09:47:34.000000000 +0100
@@ -67,7 +67,7 @@
static int match(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *matchinfo,
- int offset, int *hotdrop)
+ u_int32_t *nfcache, int offset, int *hotdrop)
{
const struct ipt_ecn_info *info = matchinfo;
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_esp.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_esp.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_esp.c 2004-10-18 23:54:24.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_esp.c 2004-12-16 09:47:34.000000000 +0100
@@ -41,6 +41,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_helper.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_helper.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_helper.c 2004-10-18 23:55:36.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_helper.c 2004-12-16 09:47:34.000000000 +0100
@@ -34,6 +34,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_iprange.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_iprange.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_iprange.c 2004-10-18 23:54:20.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_iprange.c 2004-12-16 09:47:34.000000000 +0100
@@ -28,6 +28,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset, int *hotdrop)
{
const struct ipt_iprange_info *info = matchinfo;
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_length.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_length.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_length.c 2004-10-18 23:54:40.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_length.c 2004-12-16 09:47:34.000000000 +0100
@@ -21,6 +21,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_limit.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_limit.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_limit.c 2004-10-18 23:53:09.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_limit.c 2004-12-16 09:47:34.000000000 +0100
@@ -67,6 +67,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_mac.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_mac.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_mac.c 2004-10-18 23:53:13.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_mac.c 2004-12-16 09:47:34.000000000 +0100
@@ -24,6 +24,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_mark.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_mark.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_mark.c 2004-10-18 23:55:36.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_mark.c 2004-12-16 09:47:34.000000000 +0100
@@ -22,6 +22,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_multiport.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_multiport.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_multiport.c 2004-10-18 23:53:23.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_multiport.c 2004-12-16 09:47:34.000000000 +0100
@@ -51,6 +51,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_owner.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_owner.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_owner.c 2004-10-18 23:55:24.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_owner.c 2004-12-16 09:47:34.000000000 +0100
@@ -125,6 +125,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_physdev.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_physdev.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_physdev.c 2004-10-18 23:53:45.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_physdev.c 2004-12-16 09:47:34.000000000 +0100
@@ -25,6 +25,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_pkttype.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_pkttype.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_pkttype.c 2004-10-18 23:55:36.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_pkttype.c 2004-12-16 09:47:34.000000000 +0100
@@ -21,6 +21,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_realm.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_realm.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_realm.c 2004-10-18 23:54:30.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_realm.c 2004-12-16 09:47:34.000000000 +0100
@@ -26,6 +26,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_recent.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_recent.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_recent.c 2004-10-18 23:53:21.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_recent.c 2004-12-16 09:47:34.000000000 +0100
@@ -103,6 +103,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop);
@@ -317,7 +318,7 @@
skb->nh.iph->daddr = 0;
/* Clear ttl since we have no way of knowing it */
skb->nh.iph->ttl = 0;
- match(skb,NULL,NULL,info,0,NULL);
+ match(skb,NULL,NULL,info,NULL,0,NULL);
kfree(skb->nh.iph);
out_free_skb:
@@ -356,6 +357,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_sctp.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_sctp.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_sctp.c 2004-10-18 23:53:51.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_sctp.c 2004-12-16 09:47:34.000000000 +0100
@@ -117,6 +117,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_state.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_state.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_state.c 2004-10-18 23:55:35.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_state.c 2004-12-16 09:47:34.000000000 +0100
@@ -23,6 +23,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_tcpmss.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_tcpmss.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_tcpmss.c 2004-10-18 23:53:21.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_tcpmss.c 2004-12-16 09:47:34.000000000 +0100
@@ -78,6 +78,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_tos.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_tos.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_tos.c 2004-10-18 23:55:28.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_tos.c 2004-12-16 09:47:34.000000000 +0100
@@ -22,6 +22,7 @@
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
+ u_int32_t *nfcache,
int offset,
int *hotdrop)
{
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_ttl.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ttl.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_ttl.c 2004-10-18 23:55:35.000000000 +0200
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_ttl.c 2004-12-16 09:47:34.000000000 +0100
@@ -21,7 +21,7 @@
static int match(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *matchinfo,
- int offset, int *hotdrop)
+ u_int32_t *nfcache, int offset, int *hotdrop)
{
const struct ipt_ttl_info *info = matchinfo;
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.9-orig/net/ipv4/netfilter/ipt_unclean.c linux-2.6.9-unclean/net/ipv4/netfilter/ipt_unclean.c
--- linux-2.6.9-orig/net/ipv4/netfilter/ipt_unclean.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-unclean/net/ipv4/netfilter/ipt_unclean.c 2005-01-24 08:00:35.000000000 +0100
@@ -0,0 +1,687 @@
+/* Kernel module to match suspect packets. */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/tcp.h>
+#include <linux/icmp.h>
+#include <net/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#ifdef CONFIG_IP_NF_MATCH_UNCLEAN_HWCSUM
+#define may_use_csum(skb) (skb->ip_summed == CHECKSUM_HW)
+#else
+#define may_use_csum(skb) 0
+#endif
+
+#define limpk(format, args...) \
+do { \
+ if (net_ratelimit()) \
+ printk("ipt_unclean: %s" format, \
+ embedded ? "(in embedded packet) " : "" , \
+ ## args); \
+} while(0)
+
+enum icmp_error_status
+{
+ ICMP_MAY_BE_ERROR,
+ ICMP_IS_ERROR,
+ ICMP_NOT_ERROR
+};
+
+struct icmp_info
+{
+ size_t min_len, max_len;
+ enum icmp_error_status err;
+ u_int8_t min_code, max_code;
+};
+
+static int
+check_ip(const struct sk_buff *skb, size_t length,
+ int embedded, size_t seen);
+
+/* ICMP-specific checks. */
+static int
+check_icmp(const struct sk_buff *skb,
+ u_int16_t datalen,
+ unsigned int offset,
+ int more_frags,
+ int embedded,
+ u_int16_t seen)
+{
+ struct icmphdr _icmph, *icmph;
+ static struct icmp_info info[]
+ = { [ICMP_ECHOREPLY]
+ = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
+ [ICMP_DEST_UNREACH]
+ = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 15 },
+ [ICMP_SOURCE_QUENCH]
+ = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 0 },
+ [ICMP_REDIRECT]
+ = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 3 },
+ [ICMP_ECHO]
+ = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
+ /* Router advertisement. */
+ [9]
+ = { 8, 8 + 255 * 8, ICMP_NOT_ERROR, 0, 0 },
+ /* Router solicitation. */
+ [10]
+ = { 8, 8, ICMP_NOT_ERROR, 0, 0 },
+ [ICMP_TIME_EXCEEDED]
+ = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 1 },
+ [ICMP_PARAMETERPROB]
+ = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 1 },
+ [ICMP_TIMESTAMP]
+ = { 20, 20, ICMP_NOT_ERROR, 0, 0 },
+ [ICMP_TIMESTAMPREPLY]
+ = { 20, 20, ICMP_NOT_ERROR, 0, 0 },
+ [ICMP_INFO_REQUEST]
+ = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
+ [ICMP_INFO_REPLY]
+ = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
+ [ICMP_ADDRESS]
+ = { 12, 12, ICMP_NOT_ERROR, 0, 0 },
+ [ICMP_ADDRESSREPLY]
+ = { 12, 12, ICMP_NOT_ERROR, 0, 0 } };
+
+ /* Can't do anything if it's a fragment. */
+ if (offset)
+ return 1;
+
+ /* Must cover type and code. */
+ if (datalen < 2) {
+ limpk("ICMP len=%u too short\n", datalen);
+ return 0;
+ }
+
+ /* Must cover the ICMP header */
+ icmph = skb_header_pointer(skb, seen, sizeof(_icmph), &_icmph);
+ if (icmph == NULL) {
+ limpk("Evil ICMP tinygram\n");
+ return 0;
+ }
+
+ /* If not embedded. */
+ if (!embedded) {
+ /* Bad checksum? Don't print, just ignore. */
+ if (!more_frags
+ && (u16)csum_fold(skb_checksum(skb, seen, datalen, 0)))
+ return 0;
+
+ /* CHECK: Truncated ICMP (even if first fragment). */
+ if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
+ && info[icmph->type].min_len != 0
+ && datalen < info[icmph->type].min_len) {
+ limpk("ICMP type %u len %u too short\n",
+ icmph->type, datalen);
+ return 0;
+ }
+
+ /* CHECK: Check within known error ICMPs. */
+ if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
+ && info[icmph->type].err == ICMP_IS_ERROR) {
+ /* CHECK: Check inner packet. */
+ if (!check_ip(skb, datalen - 8, 1, seen + 8))
+ return 0;
+ }
+ } else {
+ /* CHECK: Can't embed ICMP unless known non-error. */
+ if (icmph->type >= sizeof(info)/sizeof(struct icmp_info)
+ || info[icmph->type].err != ICMP_NOT_ERROR) {
+ limpk("ICMP type %u not embeddable\n",
+ icmph->type);
+ return 0;
+ }
+ }
+
+ /* CHECK: Invalid ICMP codes. */
+ if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
+ && (icmph->code < info[icmph->type].min_code
+ || icmph->code > info[icmph->type].max_code)) {
+ limpk("ICMP type=%u code=%u\n",
+ icmph->type, icmph->code);
+ return 0;
+ }
+
+ /* CHECK: Above maximum length. */
+ if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
+ && info[icmph->type].max_len != 0
+ && datalen > info[icmph->type].max_len) {
+ limpk("ICMP type=%u too long: %u bytes\n",
+ icmph->type, datalen);
+ return 0;
+ }
+
+ switch (icmph->type) {
+ case ICMP_PARAMETERPROB: {
+ /* CHECK: Problem param must be within error packet's
+ * IP header. */
+ u_int32_t arg = ntohl(icmph->un.gateway);
+
+ if (icmph->code == 0) {
+ /* Code 0 means that upper 8 bits is pointer
+ to problem. */
+ struct iphdr _iph, *iph;
+
+ iph = skb_header_pointer(skb, seen + 8,
+ sizeof(_iph), &_iph);
+ if (iph == NULL) {
+ limpk("Evil ICMP PARAMPROB tinygram\n");
+ return 0;
+ }
+ if ((arg >> 24) >= iph->ihl*4) {
+ limpk("ICMP PARAMETERPROB ptr = %u\n",
+ ntohl(icmph->un.gateway) >> 24);
+ return 0;
+ }
+ arg &= 0x00FFFFFF;
+ }
+
+ /* CHECK: Rest must be zero. */
+ if (arg) {
+ limpk("ICMP PARAMETERPROB nonzero arg = %u\n",
+ arg);
+ return 0;
+ }
+ break;
+ }
+
+ case ICMP_TIME_EXCEEDED:
+ case ICMP_SOURCE_QUENCH:
+ /* CHECK: Unused must be zero. */
+ if (icmph->un.gateway != 0) {
+ limpk("ICMP type=%u unused = %u\n",
+ icmph->type, ntohl(icmph->un.gateway));
+ return 0;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+/* UDP-specific checks. */
+static int
+check_udp(const struct sk_buff *skb,
+ const struct iphdr *iph,
+ u_int16_t datalen,
+ unsigned int offset,
+ int more_frags,
+ int embedded,
+ u_int16_t seen)
+{
+ struct udphdr _udph, *udph;
+
+ /* Can't do anything if it's a fragment. */
+ if (offset)
+ return 1;
+
+ /* CHECK: Must cover UDP header. */
+ if (datalen < sizeof(struct udphdr)) {
+ limpk("UDP len=%u too short\n", datalen);
+ return 0;
+ }
+ udph = skb_header_pointer(skb, seen, sizeof(_udph), &_udph);
+ if (udph == NULL) {
+ limpk("Evil UDP tinygram\n");
+ return 0;
+ }
+
+ /* Bad checksum? Don't print, just say it's unclean. */
+ /* FIXME: SRC ROUTE packets won't match checksum --RR */
+ if (!more_frags && !embedded && udph->check
+ && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_UDP,
+ may_use_csum(skb) ? skb->csum
+ : skb_checksum(skb, seen, datalen, 0)))
+ return 0;
+
+ /* CHECK: Destination port can't be zero. */
+ if (!udph->dest) {
+ limpk("UDP zero destination port\n");
+ return 0;
+ }
+
+ if (!more_frags) {
+ if (!embedded) {
+ /* CHECK: UDP length must match. */
+ if (ntohs(udph->len) != datalen) {
+ limpk("UDP len too short %u vs %u\n",
+ ntohs(udph->len), datalen);
+ return 0;
+ }
+ } else {
+ /* CHECK: UDP length be >= this truncated pkt. */
+ if (ntohs(udph->len) < datalen) {
+ limpk("UDP len too long %u vs %u\n",
+ ntohs(udph->len), datalen);
+ return 0;
+ }
+ }
+ } else {
+ /* CHECK: UDP length must be > this frag's length. */
+ if (ntohs(udph->len) <= datalen) {
+ limpk("UDP fragment len too short %u vs %u\n",
+ ntohs(udph->len), datalen);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+#define TH_FIN 0x01
+#define TH_SYN 0x02
+#define TH_RST 0x04
+#define TH_PUSH 0x08
+#define TH_ACK 0x10
+#define TH_URG 0x20
+#define TH_ECE 0x40
+#define TH_CWR 0x80
+
+/* table of valid flag combinations - ECE and CWR are always valid */
+static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] =
+{
+ [TH_SYN] = 1,
+ [TH_SYN|TH_ACK] = 1,
+ [TH_RST] = 1,
+ [TH_RST|TH_ACK] = 1,
+ [TH_RST|TH_ACK|TH_PUSH] = 1,
+ [TH_FIN|TH_ACK] = 1,
+ [TH_ACK] = 1,
+ [TH_ACK|TH_PUSH] = 1,
+ [TH_ACK|TH_URG] = 1,
+ [TH_ACK|TH_URG|TH_PUSH] = 1,
+ [TH_FIN|TH_ACK|TH_PUSH] = 1,
+ [TH_FIN|TH_ACK|TH_URG] = 1,
+ [TH_FIN|TH_ACK|TH_URG|TH_PUSH] = 1
+};
+
+/* TCP-specific checks. */
+static int
+check_tcp(const struct sk_buff *skb,
+ const struct iphdr *iph,
+ u_int16_t datalen,
+ unsigned int offset,
+ int more_frags,
+ int embedded,
+ u_int16_t seen)
+{
+ struct tcphdr _tcph, *tcph;
+ u_int8_t _opt[60 - sizeof(_tcph)], *opt;
+ u_int8_t tcpflags;
+ int end_of_options = 0, optlen;
+ size_t i = sizeof(_tcph);
+
+ /* CHECK: Can't have offset=1: used to override TCP syn-checks. */
+ /* In fact, this is caught below (offset < 516). */
+
+ /* Can't do anything if it's a fragment. */
+ if (offset)
+ return 1;
+
+ /* CHECK: Smaller than minimal TCP hdr. */
+ if (datalen < sizeof(struct tcphdr)) {
+ if (!embedded) {
+ limpk("Packet length %u < TCP header.\n", datalen);
+ return 0;
+ }
+ /* Must have ports available (datalen >= 8), from check_ip */
+ i = 8;
+ }
+
+ tcph = skb_header_pointer(skb, seen, i, &_tcph);
+ if (tcph == NULL) {
+ limpk("Evil TCP tinygram\n");
+ return 0;
+ }
+
+ /* CHECK: TCP ports inside ICMP error */
+ if (embedded && (!tcph->source || !tcph->dest)) {
+ limpk("Zero TCP ports %u/%u.\n",
+ htons(tcph->source), htons(tcph->dest));
+ return 0;
+ }
+
+ /* CHECK: Smaller than actual TCP hdr. */
+ if (datalen < tcph->doff * 4) {
+ if (!embedded) {
+ limpk("Packet length %u < actual TCP header.\n",
+ datalen);
+ return 0;
+ } else
+ return 1;
+ }
+
+ /* Bad checksum? Don't print, just say it's unclean. */
+ /* FIXME: SRC ROUTE packets won't match checksum --RR */
+ if (!more_frags && !embedded
+ && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_TCP,
+ may_use_csum(skb) ? skb->csum
+ : skb_checksum(skb, seen, datalen, 0)))
+ return 0;
+
+ /* CHECK: TCP ports non-zero */
+ if (!tcph->source || !tcph->dest) {
+ limpk("Zero TCP ports %u/%u.\n",
+ htons(tcph->source), htons(tcph->dest));
+ return 0;
+ }
+
+ /* CHECK: TCP reserved bits zero. */
+ if(tcp_flag_word(tcph) & TCP_RESERVED_BITS) {
+ limpk("TCP reserved bits not zero\n");
+ return 0;
+ }
+
+ /* CHECK: TCP flags. */
+ tcpflags = (((u_int8_t *)tcph)[13] & ~(TH_ECE|TH_CWR));
+ if (!tcp_valid_flags[tcpflags]) {
+ limpk("TCP flags bad: %u\n", tcpflags);
+ return 0;
+ }
+
+ /* CHECK: malformed header size */
+ if (tcph->doff * 4 < sizeof(struct tcphdr)) {
+ limpk("Header size %u < minimal TCP header.\n", tcph->doff * 4);
+ return 0;
+ }
+
+ optlen = tcph->doff * 4 - sizeof(_tcph);
+ opt = skb_header_pointer(skb, seen + sizeof(_tcph), optlen, &_opt);
+ if (opt == NULL) {
+ limpk("Evil TCP packet with options.\n");
+ return 0;
+ }
+ for (i = 0; i < optlen; ) {
+ switch (opt[i]) {
+ case 0:
+ end_of_options = 1;
+ i++;
+ break;
+ case 1:
+ i++;
+ break;
+ default:
+ /* CHECK: options after EOO. */
+ if (end_of_options) {
+ limpk("TCP option %u after end\n",
+ opt[i]);
+ return 0;
+ }
+ /* CHECK: options at tail. */
+ else if (i+1 >= optlen) {
+ limpk("TCP option %u at tail\n",
+ opt[i]);
+ return 0;
+ }
+ /* CHECK: zero-length options. */
+ else if (opt[i+1] == 0) {
+ limpk("TCP option %u 0 len\n",
+ opt[i]);
+ return 0;
+ }
+ /* CHECK: oversize options. */
+ else if (i + opt[i+1] > optlen) {
+ limpk("TCP option %u at %u too long\n",
+ (unsigned int) opt[i], i);
+ return 0;
+ }
+ /* Move to next option */
+ i += opt[i+1];
+ }
+ }
+
+ return 1;
+}
+
+/* Returns 1 if ok */
+/* Standard IP checks. */
+static int
+check_ip(const struct sk_buff *skb, size_t length,
+ int embedded, size_t seen)
+{
+ struct iphdr _iph, *iph;
+ u_int8_t _opt[60 - sizeof(struct iphdr)], *opt;
+ int end_of_options = 0, optlen;
+ size_t datalen;
+ unsigned int i, offset;
+
+ /* Should only happen for local outgoing raw-socket packets. */
+ /* CHECK: length >= ip header. */
+ if (length < sizeof(struct iphdr)) {
+ limpk("Packet length %u < IP header.\n", length);
+ return 0;
+ }
+ if (embedded) {
+ iph = skb_header_pointer(skb, seen, sizeof(_iph), &_iph);
+ if (iph == NULL) {
+ limpk("Evil IP packet.\n");
+ return 0;
+ }
+ } else
+ iph = skb->nh.iph;
+
+ /* Should only happen for local outgoing raw-socket packets. */
+ /* CHECK: length >= ip header size. */
+ if (length < iph->ihl * 4) {
+ limpk("Packet length %u < actual IP header.\n", length);
+ return 0;
+ }
+
+ /* CHECK: malformed header size */
+ if (iph->ihl * 4 < sizeof(struct iphdr)) {
+ limpk("Header size %u < minimal IP header.\n", iph->ihl * 4);
+ return 0;
+ }
+
+ /* CHECK: Embedded packet must be at least
+ length of iph + 8 bytes. */
+ if (embedded && length < iph->ihl * 4 + 8) {
+ limpk("ICMP error internal too short\n");
+ return 0;
+ }
+
+ offset = ntohs(iph->frag_off) & IP_OFFSET;
+ optlen = iph->ihl * 4 - sizeof(struct iphdr);
+ datalen = length - iph->ihl * 4;
+
+ /* CHECK: Embedded fragment. */
+ if (embedded && offset) {
+ limpk("Embedded fragment.\n");
+ return 0;
+ }
+
+ opt = skb_header_pointer(skb, seen + sizeof(_iph), optlen, &_opt);
+ if (opt == NULL) {
+ limpk("Evil IP packet with options.\n");
+ return 0;
+ }
+ for (i = 0; i < optlen; ) {
+ switch (opt[i]) {
+ case 0:
+ end_of_options = 1;
+ i++;
+ break;
+ case 1:
+ i++;
+ break;
+ default:
+ /* CHECK: options after EOO. */
+ if (end_of_options) {
+ limpk("IP option %u after end\n",
+ opt[i]);
+ return 0;
+ }
+ /* CHECK: options at tail. */
+ else if (i+1 >= optlen) {
+ limpk("IP option %u at tail\n",
+ opt[i]);
+ return 0;
+ }
+ /* CHECK: zero-length or one-length options. */
+ else if (opt[i+1] < 2) {
+ limpk("IP option %u %u len\n",
+ opt[i], opt[i+1]);
+ return 0;
+ }
+ /* CHECK: oversize options. */
+ else if (i + opt[i+1] > optlen) {
+ limpk("IP option %u at %u too long\n",
+ opt[i], i);
+ return 0;
+ }
+ /* Move to next option */
+ i += opt[i+1];
+ }
+ }
+
+ /* Fragment checks. */
+
+ /* CHECK: More fragments, but doesn't fill 8-byte boundary. */
+ if ((ntohs(iph->frag_off) & IP_MF) && datalen % 8 != 0) {
+ limpk("Truncated fragment %u long.\n", datalen);
+ return 0;
+ }
+
+ /* CHECK: Oversize fragment a-la Ping of Death. */
+ if (offset * 8 + datalen > 65535) {
+ limpk("Oversize fragment to %u.\n", offset * 8);
+ return 0;
+ }
+
+ /* CHECK: Zero-sized fragments. */
+ if ((offset || (ntohs(iph->frag_off) & IP_MF))
+ && datalen == 0) {
+ limpk("Zero size fragment offset=%u\n", offset);
+ return 0;
+ }
+
+ /* Note: we can have even middle fragments smaller than this:
+ consider a large packet passing through a 600MTU then
+ 576MTU link: this gives a fragment of 24 data bytes. But
+ everyone packs fragments largest first, hence a fragment
+ can't START before 576 - MAX_IP_HEADER_LEN. */
+
+ /* Used to be min-size 576: I recall Alan Cox saying ax25 goes
+ down to 128 (576 taken from RFC 791: All hosts must be
+ prepared to accept datagrams of up to 576 octets). Use 128
+ here. */
+#define MIN_LIKELY_MTU 128
+ /* CHECK: Min size of first frag = 128. */
+ if ((ntohs(iph->frag_off) & IP_MF)
+ && offset == 0
+ && ntohs(iph->tot_len) < MIN_LIKELY_MTU) {
+ limpk("First fragment size %u < %u\n", ntohs(iph->tot_len),
+ MIN_LIKELY_MTU);
+ return 0;
+ }
+
+ /* CHECK: Min offset of frag = 128 - IP hdr len. */
+ if (offset && offset * 8 < MIN_LIKELY_MTU - iph->ihl * 4) {
+ limpk("Fragment starts at %u < %u\n", offset * 8,
+ MIN_LIKELY_MTU - iph->ihl * 4);
+ return 0;
+ }
+
+ /* CHECK: Protocol specification non-zero. */
+ if (iph->protocol == 0) {
+ limpk("Zero protocol\n");
+ return 0;
+ }
+
+ /* CHECK: Do not use what is unused.
+ * First bit of fragmentation flags should be unused.
+ * May be used by OS fingerprinting tools.
+ * 04 Jun 2002, Maciej Soltysiak, solt@dns.toxicfilms.tv
+ */
+ if (ntohs(iph->frag_off)>>15) {
+ limpk("IP unused bit set\n");
+ return 0;
+ }
+
+ seen += iph->ihl * 4;
+ /* Per-protocol checks. */
+ switch (iph->protocol) {
+ case IPPROTO_ICMP:
+ return check_icmp(skb, datalen, offset,
+ (ntohs(iph->frag_off) & IP_MF),
+ embedded, seen);
+
+ case IPPROTO_UDP:
+ return check_udp(skb, iph, datalen, offset,
+ (ntohs(iph->frag_off) & IP_MF),
+ embedded, seen);
+
+ case IPPROTO_TCP:
+ return check_tcp(skb, iph, datalen, offset,
+ (ntohs(iph->frag_off) & IP_MF),
+ embedded, seen);
+ default:
+ /* Ignorance is bliss. */
+ return 1;
+ }
+}
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const void *matchinfo,
+ u_int32_t *nfcache,
+ int offset,
+ int *hotdrop)
+{
+ int res = check_ip(skb, skb->len, 0, 0);
+
+ /* Cache the negative result. */
+ if (res)
+ *nfcache |= NFC_CLEAN;
+
+ return (!res);
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+ const struct ipt_ip *ip,
+ void *matchinfo,
+ unsigned int matchsize,
+ unsigned int hook_mask)
+{
+#ifdef CONFIG_IP_NF_MATCH_UNCLEAN_HWCSUM
+ /* Only valid in PREROUTING */
+ if (hook_mask & ~(1 << NF_IP_PRE_ROUTING)) {
+ printk("ipt_unclean: only valid in PREROUTING.\n");
+ return 0;
+ }
+#endif
+ if (matchsize != IPT_ALIGN(0))
+ return 0;
+
+ return 1;
+}
+
+static struct ipt_match unclean_match = {
+ .name = "unclean",
+ .match = &match,
+ .checkentry = &checkentry,
+ .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+ return ipt_register_match(&unclean_match);
+}
+
+static void __exit fini(void)
+{
+ ipt_unregister_match(&unclean_match);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("iptables 'unclean' packets match module");
^ permalink raw reply [flat|nested] 7+ messages in thread