Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
131 lines (119 sloc) 4.34 KB
--- linux-2.4.24.orig/include/linux/netfilter_ipv4/ipt_string.h 2004-03-23 00:24:17.000000000 -0500
+++ linux-2.4.24/include/linux/netfilter_ipv4/ipt_string.h 2004-03-22 22:04:50.000000000 -0500
@@ -14,8 +14,10 @@
struct ipt_string_info {
char string[BM_MAX_NLEN];
+ char replace_str[BM_MAX_NLEN];
u_int16_t invert;
u_int16_t len;
+ u_int16_t replace_len;
};
#endif /* _IPT_STRING_H */
--- linux-2.4.24.orig/net/ipv4/netfilter/ipt_string.c 2004-03-23 00:24:17.000000000 -0500
+++ linux-2.4.24/net/ipv4/netfilter/ipt_string.c 2004-03-23 01:25:07.000000000 -0500
@@ -3,6 +3,10 @@
* Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be>
*
* ChangeLog
+ * 22.03.2004: Michael Rash <mbr@cipherdyne.org>
+ * Added ability to replace a matching string in packet data
+ * with a new string (checksum automatically recalculated for
+ * tcp).
* 19.02.2002: Gianni Tedesco <gianni@ecsc.co.uk>
* Fixed SMP re-entrancy problem using per-cpu data areas
* for the skip/shift tables.
@@ -22,6 +26,8 @@
#include <linux/skbuff.h>
#include <linux/file.h>
#include <net/sock.h>
+#include <net/tcp.h>
+#include <net/udp.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_string.h>
@@ -52,7 +58,7 @@
/* Setup skip/shift tables */
M1 = right_end = needle_len-1;
for (i = 0; i < BM_MAX_HLEN; i++) skip[i] = needle_len;
- for (i = 0; needle[i]; i++) skip[needle[i]] = M1 - i;
+ for (i = 0; (int) needle[i]; i++) skip[(int) needle[i]] = M1 - i;
for (i = 1; i < needle_len; i++) {
for (j = 0; j < needle_len && needle[M1 - j] == needle[M1 - i - j]; j++);
@@ -77,7 +83,7 @@
return haystack+(right_end - M1);
}
- sk = skip[haystack[right_end - i]];
+ sk = skip[(int) haystack[right_end - i]];
sh = shift[i];
right_end = max(right_end - i + sk, right_end + sh);
}
@@ -113,18 +119,27 @@
{
const struct ipt_string_info *info = matchinfo;
struct iphdr *ip = skb->nh.iph;
- int hlen, nlen;
- char *needle, *haystack;
+ struct tcphdr *tcph;
+ struct udphdr *udph;
+ int hlen, nlen, rlen, rctr;
+ char *needle, *haystack, *repl_str, *repl_ptr;
proc_ipt_search search=search_linear;
if ( !ip ) return 0;
- /* get lenghts, and validate them */
+ /* get lengths, and validate them */
nlen=info->len;
+ rlen=info->replace_len;
hlen=ntohs(ip->tot_len)-(ip->ihl*4);
if ( nlen > hlen ) return 0;
+ /* if we are altering packet data, make absolutely sure
+ * replace length is less than or equal to needle length.
+ * We cannot start breaking protocols! */
+ if ( rlen > 0 && rlen > nlen ) return 0;
+
needle=(char *)&info->string;
+ repl_str=(char *)&info->replace_str;
haystack=(char *)ip+(ip->ihl*4);
/* The sublinear search comes in to its own
@@ -141,7 +156,44 @@
}
}
- return ((search(needle, haystack, nlen, hlen)!=NULL) ^ info->invert);
+ repl_ptr = search(needle, haystack, nlen, hlen);
+
+ if (repl_ptr != NULL && rlen > 0) {
+ /* if we change the data portion of the packet we recalculate
+ * the transport layer checksum (mandatory for TCP). */
+ if (skb->nh.iph->protocol == IPPROTO_TCP) {
+ /* repl_ptr points to the start of the needle
+ * in the packet, and we know the entire needle
+ * is there so we can just replace. */
+ for (rctr=0; rctr < rlen; rctr++)
+ repl_ptr[rctr] = repl_str[rctr];
+
+ tcph = (struct tcphdr *)((u_int32_t*)skb->nh.iph + skb->nh.iph->ihl);
+ unsigned int tcplen = skb->len - (skb->nh.iph->ihl<<2);
+ tcph->check = 0;
+ tcph->check = tcp_v4_check(tcph, tcplen, skb->nh.iph->saddr,
+ skb->nh.iph->daddr,
+ csum_partial((char *)tcph, tcplen, 0));
+ } else if (skb->nh.iph->protocol == IPPROTO_UDP) {
+ /* repl_ptr points to the start of the needle
+ * in the packet, and we know the entire needle
+ * is there so we can just replace. */
+ for (rctr=0; rctr < rlen; rctr++)
+ repl_ptr[rctr] = repl_str[rctr];
+ /* recalculate UDP checksum only if it was previously
+ * calculated */
+ udph = (struct udphdr *)((char *)skb->nh.iph + (skb->nh.iph->ihl<<2));
+ unsigned int udplen = skb->len - (skb->nh.iph->ihl<<2);
+ if (udph->check) {
+ udph->check = 0;
+ udph->check = csum_tcpudp_magic(skb->nh.iph->saddr,
+ skb->nh.iph->daddr,
+ udplen, IPPROTO_UDP,
+ csum_partial((char *)udph, udplen, 0));
+ }
+ }
+ }
+ return ((repl_ptr!=NULL) ^ info->invert);
}
static int
Jump to Line
Something went wrong with that request. Please try again.