diff mbox series

[xtables-addons,v2,6/7] xt_ipp2p: use `skb_header_pointer` and `skb_find_text`

Message ID 20230605221044.140855-7-jeremy@azazel.net
State Not Applicable, archived
Headers show
Series xt_ipp2p: support for non-linear packets | expand

Commit Message

Jeremy Sowden June 5, 2023, 10:10 p.m. UTC
Use `skb_header_pointer` to copy byte-ranges for matching and
`skb_find_text` for substring searches.  Doing so allows the module to
work with non-linear skbs.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
---
 extensions/xt_ipp2p.c | 487 ++++++++++++++++++++++++++++++++----------
 1 file changed, 372 insertions(+), 115 deletions(-)
diff mbox series

Patch

diff --git a/extensions/xt_ipp2p.c b/extensions/xt_ipp2p.c
index 6fd3e4df5c8b..4322ab3623e5 100644
--- a/extensions/xt_ipp2p.c
+++ b/extensions/xt_ipp2p.c
@@ -1,5 +1,6 @@ 
 #include <linux/gfp.h>
 #include <linux/module.h>
+#include <linux/skbuff.h>
 #include <linux/textsearch.h>
 #include <linux/version.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
@@ -38,7 +39,9 @@  ipv6_transport_len(const struct sk_buff *skb)
 struct ipp2p_result_printer {
 	const union nf_inet_addr *saddr, *daddr;
 	short sport, dport;
-	void (*print)(const union nf_inet_addr *, short, const union nf_inet_addr *, short, bool, unsigned int);
+	void (*print)(const union nf_inet_addr *, short,
+		      const union nf_inet_addr *, short,
+		      bool, unsigned int);
 };
 
 static bool iscrlf(const unsigned char *str)
@@ -57,12 +60,23 @@  print_result(const struct ipp2p_result_printer *rp, bool result,
 
 /* Search for UDP eDonkey/eMule/Kad commands */
 static unsigned int
-udp_search_edk(const unsigned char *t, const unsigned int packet_len,
+udp_search_edk(const struct sk_buff *skb,
+	       const unsigned int packet_off,
+	       const unsigned int packet_len,
 	       const struct ipt_p2p_info *info)
 {
+	unsigned char buf[36], *t;
+
 	if (packet_len < 4)
 		return 0;
 
+	t = skb_header_pointer(skb, packet_off,
+			       packet_len < sizeof(buf) ?
+			       packet_len : sizeof(buf),
+			       buf);
+	if (t == NULL)
+		return 0;
+
 	switch (t[0]) {
 	case 0xe3:
 		/* eDonkey */
@@ -176,9 +190,20 @@  udp_search_edk(const unsigned char *t, const unsigned int packet_len,
 
 /* Search for UDP Gnutella commands */
 static unsigned int
-udp_search_gnu(const unsigned char *t, const unsigned int packet_len,
+udp_search_gnu(const struct sk_buff *skb,
+	       const unsigned int packet_off,
+	       const unsigned int packet_len,
 	       const struct ipt_p2p_info *info)
 {
+	unsigned char buf[9], *t;
+
+	t = skb_header_pointer(skb, packet_off,
+			       packet_len < sizeof(buf) ?
+			       packet_len : sizeof(buf),
+			       buf);
+	if (t == NULL)
+		return 0;
+
 	if (packet_len >= 3 && memcmp(t, "GND", 3) == 0)
 		return IPP2P_GNU * 100 + 51;
 	if (packet_len >= 9 && memcmp(t, "GNUTELLA ", 9) == 0)
@@ -188,39 +213,73 @@  udp_search_gnu(const unsigned char *t, const unsigned int packet_len,
 
 /* Search for UDP KaZaA commands */
 static unsigned int
-udp_search_kazaa(const unsigned char *t, const unsigned int packet_len,
+udp_search_kazaa(const struct sk_buff *skb,
+		 const unsigned int packet_off,
+		 const unsigned int packet_len,
 		 const struct ipt_p2p_info *info)
 {
+	unsigned char buf[6], *t;
+
 	if (packet_len < 6)
 		return 0;
-	if (memcmp(t + packet_len - 6, "KaZaA\x00", 6) == 0)
+
+	t = skb_header_pointer(skb, packet_off + packet_len - 6, 6, buf);
+	if (t == NULL)
+		return 0;
+
+	if (memcmp(t, "KaZaA\x00", 6) == 0)
 		return IPP2P_KAZAA * 100 + 50;
 	return 0;
 }
 
 /* Search for UDP DirectConnect commands */
 static unsigned int
-udp_search_directconnect(const unsigned char *t, const unsigned int packet_len,
+udp_search_directconnect(const struct sk_buff *skb,
+			 const unsigned int packet_off,
+			 const unsigned int packet_len,
 			 const struct ipt_p2p_info *info)
 {
+	unsigned char hbuf[6], *head, tbuf, *tail;
+
 	if (packet_len < 5)
 		return 0;
-	if (t[0] != 0x24)
+
+	head = skb_header_pointer(skb, packet_off, packet_len < 7 ? 4 : 6,
+				  hbuf);
+	if (head == NULL)
 		return 0;
-	if (t[packet_len-1] != 0x7c)
+
+	tail = skb_header_pointer(skb, packet_off + packet_len - 1, 1, &tbuf);
+	if (tail == NULL)
 		return 0;
-	if (memcmp(&t[1], "SR ", 3) == 0)
+
+	if (head[0] != 0x24)
+		return 0;
+	if (tail[0] != 0x7c)
+		return 0;
+	if (memcmp(&head[1], "SR ", 3) == 0)
 		return IPP2P_DC * 100 + 60;
-	if (packet_len >= 7 && memcmp(&t[1], "Ping ", 5) == 0)
+	if (packet_len >= 7 && memcmp(&head[1], "Ping ", 5) == 0)
 		return IPP2P_DC * 100 + 61;
 	return 0;
 }
 
 /* Search for UDP BitTorrent commands */
 static unsigned int
-udp_search_bit(const unsigned char *haystack, const unsigned int packet_len,
+udp_search_bit(const struct sk_buff *skb,
+	       const unsigned int packet_off,
+	       const unsigned int packet_len,
 	       const struct ipt_p2p_info *info)
 {
+	unsigned char buf[32], *haystack;
+
+	haystack = skb_header_pointer(skb, packet_off,
+				      packet_len < sizeof(buf) ?
+				      packet_len : sizeof(buf),
+				      buf);
+	if (haystack == NULL)
+		return 0;
+
 	switch (packet_len) {
 	case 16:
 		/* ^ 00 00 04 17 27 10 19 80 */
@@ -305,11 +364,22 @@  udp_search_bit(const unsigned char *haystack, const unsigned int packet_len,
 
 /* Search for Ares commands */
 static unsigned int
-search_ares(const unsigned char *payload, const unsigned int plen,
+search_ares(const struct sk_buff *skb,
+	    const unsigned int poff,
+	    const unsigned int plen,
 	    const struct ipt_p2p_info *info)
 {
+	unsigned char buf[60], *payload;
+
 	if (plen < 3)
 		return 0;
+
+	payload = skb_header_pointer(skb, poff,
+				     plen < sizeof(buf) ? plen : sizeof(buf),
+				     buf);
+	if (payload == NULL)
+		return 0;
+
 	/* all ares packets start with  */
 	if (payload[1] == 0 && plen - payload[0] == 3) {
 		switch (payload[2]) {
@@ -358,11 +428,22 @@  search_ares(const unsigned char *payload, const unsigned int plen,
 
 /* Search for SoulSeek commands */
 static unsigned int
-search_soul(const unsigned char *payload, const unsigned int plen,
+search_soul(const struct sk_buff *skb,
+	    const unsigned int poff,
+	    const unsigned int plen,
 	    const struct ipt_p2p_info *info)
 {
+	unsigned char buf[16], *payload;
+
 	if (plen < 8)
 		return 0;
+
+	payload = skb_header_pointer(skb, poff,
+				     plen < sizeof(buf) ? plen : sizeof(buf),
+				     buf);
+	if (payload == NULL)
+		return 0;
+
 	/* match: xx xx xx xx | xx = sizeof(payload) - 4 */
 	if (get_u32(payload, 0) == plen - 4) {
 		const uint32_t m = get_u32(payload, 4);
@@ -461,12 +542,20 @@  search_soul(const unsigned char *payload, const unsigned int plen,
 	if (get_u32(payload, 0) == 0x14 && get_u8(payload, 4) == 0x01) {
 		uint32_t y = get_u32(payload, 5);
 		const unsigned char *w;
+		unsigned int off, len;
 
 		/* we need 19 chars + string */
 		if (plen < y + 19)
 			return 0;
 
-		w = payload + 9 + y;
+		off = poff + y + 9;
+		len = plen - y + 9;
+
+		w = skb_header_pointer(skb, off,
+				       len < sizeof(buf) ? len : sizeof(buf),
+				       buf);
+		if (w == NULL)
+			return 0;
 
 		if (get_u32(w, 0) == 0x01 &&
 		    (get_u16(w, 4) == 0x4600 ||
@@ -483,10 +572,19 @@  search_soul(const unsigned char *payload, const unsigned int plen,
 
 /* Search for WinMX commands */
 static unsigned int
-search_winmx(const unsigned char *payload, const unsigned int plen,
+search_winmx(const struct sk_buff *skb,
+	     const unsigned int poff,
+	     const unsigned int plen,
 	     const struct ipt_p2p_info *info)
 {
-	uint16_t start;
+	unsigned char buf[149], *payload;
+	uint16_t start = poff;
+
+	payload = skb_header_pointer(skb, poff,
+				     plen < sizeof(buf) ? plen : sizeof(buf),
+				     buf);
+	if (payload == NULL)
+		return 0;
 
 	if (plen == 4 && memcmp(payload, "SEND", 4) == 0)
 		return IPP2P_WINMX * 100 + 1;
@@ -500,23 +598,18 @@  search_winmx(const unsigned char *payload, const unsigned int plen,
 		return 0;
 
 	if (memcmp(payload, "SEND", 4) == 0)
-		start = 4;
+		start += 4;
 	else if (memcmp(payload, "GET", 3) == 0)
-		start = 3;
-	else
-		start = 0;
+		start += 3;
 
-	if (start) {
+	if (start > poff) {
 		uint8_t count = 0;
 
 		do {
-			struct ts_state state;
 			unsigned int pos;
 
-			pos = textsearch_find_continuous(info->ts_conf_winmx,
-							 &state,
-							 &payload[start],
-							 plen - start);
+			pos = skb_find_text((struct sk_buff *)skb, start,
+					    skb->len, info->ts_conf_winmx);
 			if (pos == UINT_MAX)
 				break;
 
@@ -525,7 +618,7 @@  search_winmx(const unsigned char *payload, const unsigned int plen,
 				return IPP2P_WINMX * 100 + 3;
 
 			start = pos + 2;
-		} while (start < plen);
+		} while (start < skb->len);
 	}
 
 	if (plen == 149 && payload[0] == '8') {
@@ -553,11 +646,22 @@  search_winmx(const unsigned char *payload, const unsigned int plen,
 
 /* Search for appleJuice commands */
 static unsigned int
-search_apple(const unsigned char *payload, const unsigned int plen,
+search_apple(const struct sk_buff *skb,
+	     const unsigned int poff,
+	     const unsigned int plen,
 	     const struct ipt_p2p_info *info)
 {
+	unsigned char buf[8], *payload;
+
 	if (plen < 8)
 		return 0;
+
+	payload = skb_header_pointer(skb, poff,
+				     plen < sizeof(buf) ? plen : sizeof(buf),
+				     buf);
+	if (payload == NULL)
+		return 0;
+
 	if (memcmp(payload, "ajprot\r\n", 8) == 0)
 		return IPP2P_APPLE * 100;
 	return 0;
@@ -565,12 +669,20 @@  search_apple(const unsigned char *payload, const unsigned int plen,
 
 /* Search for BitTorrent commands */
 static unsigned int
-search_bittorrent(const unsigned char *payload, const unsigned int plen,
+search_bittorrent(const struct sk_buff *skb,
+		  const unsigned int poff,
+		  const unsigned int plen,
 		  const struct ipt_p2p_info *info)
 {
-	struct ts_state state;
+	unsigned char buf[20], *payload;
 	unsigned int pos;
 
+	payload = skb_header_pointer(skb, poff,
+				     plen < sizeof(buf) ? plen : sizeof(buf),
+				     buf);
+	if (payload == NULL)
+		return 0;
+
 	/*
 	 * bitcomet encrypts the first packet, so we have to detect another one
 	 * later in the flow.
@@ -598,18 +710,18 @@  search_bittorrent(const unsigned char *payload, const unsigned int plen,
 	if (memcmp(payload, "GET /", 5) != 0)
 		return 0;
 
-	pos = textsearch_find_continuous(info->ts_conf_bt_info_hash,
-					 &state, &payload[5], plen - 5);
+	pos = skb_find_text((struct sk_buff *)skb, poff + 5, skb->len,
+			    info->ts_conf_bt_info_hash);
 	if (pos != UINT_MAX)
 		return IPP2P_BIT * 100 + 1;
 
-	pos = textsearch_find_continuous(info->ts_conf_bt_peer_id,
-					 &state, &payload[5], plen - 5);
+	pos = skb_find_text((struct sk_buff *)skb, poff + 5, skb->len,
+			    info->ts_conf_bt_peer_id);
 	if (pos != UINT_MAX)
 		return IPP2P_BIT * 100 + 2;
 
-	pos = textsearch_find_continuous(info->ts_conf_bt_passkey,
-					 &state, &payload[5], plen - 5);
+	pos = skb_find_text((struct sk_buff *)skb, poff + 5, skb->len,
+			    info->ts_conf_bt_passkey);
 	if (pos != UINT_MAX)
 		return IPP2P_BIT * 100 + 4;
 
@@ -618,13 +730,25 @@  search_bittorrent(const unsigned char *payload, const unsigned int plen,
 
 /* check for Kazaa get command */
 static unsigned int
-search_kazaa(const unsigned char *payload, const unsigned int plen,
+search_kazaa(const struct sk_buff *skb,
+	     const unsigned int poff,
+	     const unsigned int plen,
 	     const struct ipt_p2p_info *info)
 {
+	unsigned char hbuf[11], *head, tbuf[2], *tail;
+
 	if (plen < 13)
 		return 0;
-	if (iscrlf(&payload[plen - 2]) &&
-	    memcmp(payload, "GET /.hash=", 11) == 0)
+
+	head = skb_header_pointer(skb, poff, 11, hbuf);
+	if (head == NULL)
+		return 0;
+
+	tail = skb_header_pointer(skb, poff + plen - 2, 2, tbuf);
+	if (tail == NULL)
+		return 0;
+
+	if (iscrlf(tail) && memcmp(head, "GET /.hash=", 11) == 0)
 		return IPP2P_DATA_KAZAA * 100;
 
 	return 0;
@@ -632,54 +756,87 @@  search_kazaa(const unsigned char *payload, const unsigned int plen,
 
 /* check for Gnutella get command */
 static unsigned int
-search_gnu(const unsigned char *payload, const unsigned int plen,
+search_gnu(const struct sk_buff *skb,
+	   const unsigned int poff,
+	   const unsigned int plen,
 	   const struct ipt_p2p_info *info)
 {
+	unsigned char hbuf[15], *head, tbuf[2], *tail;
+
 	if (plen < 11)
 		return 0;
-	if (!iscrlf(&payload[plen - 2]))
+
+	head = skb_header_pointer(skb, poff,
+				  plen - 2 < sizeof(hbuf) ?
+				  plen - 2 : sizeof(hbuf),
+				  hbuf);
+	if (head == NULL)
+		return 0;
+
+	tail = skb_header_pointer(skb, poff + plen - 2, 2, tbuf);
+	if (tail == NULL)
+		return 0;
+
+	if (!iscrlf(tail))
 		return 0;
-	if (memcmp(payload, "GET /get/", 9) == 0)
+	if (memcmp(head, "GET /get/", 9) == 0)
 		return IPP2P_DATA_GNU * 100 + 1;
-	if (plen >= 15 && memcmp(payload, "GET /uri-res/", 13) == 0)
+	if (plen >= 15 && memcmp(head, "GET /uri-res/", 13) == 0)
 		return IPP2P_DATA_GNU * 100 + 2;
 	return 0;
 }
 
 /* check for Gnutella get commands and other typical data */
 static unsigned int
-search_all_gnu(const unsigned char *payload, const unsigned int plen,
+search_all_gnu(const struct sk_buff *skb,
+	       const unsigned int poff,
+	       const unsigned int plen,
 	       const struct ipt_p2p_info *info)
 {
-	struct ts_state state;
-	unsigned int c, pos;
+	unsigned char hbuf[17], *head, tbuf[2], *tail;
+	unsigned int off, pos;
 
 	if (plen < 11)
 		return 0;
-	if (!iscrlf(&payload[plen - 2]))
+
+	head = skb_header_pointer(skb, poff,
+				  plen - 2 < sizeof(hbuf) ?
+				  plen - 2 : sizeof(hbuf),
+				  hbuf);
+	if (head == NULL)
+		return 0;
+
+	tail = skb_header_pointer(skb, poff + plen - 2, 2, tbuf);
+	if (tail == NULL)
 		return 0;
-	if (plen >= 19 && memcmp(payload, "GNUTELLA CONNECT/", 17) == 0)
+
+	if (!iscrlf(tail))
+		return 0;
+
+	if (plen >= 19 && memcmp(head, "GNUTELLA CONNECT/", 17) == 0)
 		return IPP2P_GNU * 100 + 1;
-	if (memcmp(payload, "GNUTELLA/", 9) == 0)
+
+	if (memcmp(head, "GNUTELLA/", 9) == 0)
 		return IPP2P_GNU * 100 + 2;
 
 	if (plen < 22)
 		return 0;
 
-	if (memcmp(payload, "GET /get/", 9) == 0)
-		c = 9;
-	else if (memcmp(payload, "GET /uri-res/", 13) == 0)
-		c = 13;
+	if (memcmp(head, "GET /get/", 9) == 0)
+		off = 9;
+	else if (memcmp(head, "GET /uri-res/", 13) == 0)
+		off = 13;
 	else
 		return 0;
 
-	pos = textsearch_find_continuous(info->ts_conf_gnu_x_gnutella,
-					 &state, &payload[c], plen - c);
+	pos = skb_find_text((struct sk_buff *)skb, poff + off, skb->len,
+			    info->ts_conf_gnu_x_gnutella);
 	if (pos != UINT_MAX)
 		return IPP2P_GNU * 100 + 3;
 
-	pos = textsearch_find_continuous(info->ts_conf_gnu_x_queue,
-					 &state, &payload[c], plen - c);
+	pos = skb_find_text((struct sk_buff *)skb, poff + off, skb->len,
+			    info->ts_conf_gnu_x_queue);
+
 	if (pos != UINT_MAX)
 		return IPP2P_GNU * 100 + 3;
 
@@ -689,36 +846,46 @@  search_all_gnu(const unsigned char *payload, const unsigned int plen,
 /* check for KaZaA download commands and other typical data */
 /* plen is guaranteed to be >= 5 (see @matchlist) */
 static unsigned int
-search_all_kazaa(const unsigned char *payload, const unsigned int plen,
+search_all_kazaa(const struct sk_buff *skb,
+		 const unsigned int poff,
+		 const unsigned int plen,
 		 const struct ipt_p2p_info *info)
 {
-	struct ts_state state;
+	unsigned char hbuf[5], *head, tbuf[2], *tail;
 	unsigned int pos;
 
 	if (plen < 7)
 		/* too short for anything we test for - early bailout */
 		return 0;
 
-	if (!iscrlf(&payload[plen - 2]))
+	head = skb_header_pointer(skb, poff, sizeof(hbuf), hbuf);
+	if (head == NULL)
+		return 0;
+
+	tail = skb_header_pointer(skb, poff + plen - 2, 2, tbuf);
+	if (tail == NULL)
 		return 0;
 
-	if (memcmp(payload, "GIVE ", 5) == 0)
+	if (!iscrlf(tail))
+		return 0;
+
+	if (memcmp(head, "GIVE ", 5) == 0)
 		return IPP2P_KAZAA * 100 + 1;
 
-	if (memcmp(payload, "GET /", 5) != 0)
+	if (memcmp(head, "GET /", 5) != 0)
 		return 0;
 
 	if (plen < 18)
 		/* The next tests would not succeed anyhow. */
 		return 0;
 
-	pos = textsearch_find_continuous(info->ts_conf_kz_x_kazaa_username,
-					 &state, &payload[5], plen - 5);
+	pos = skb_find_text((struct sk_buff *)skb, poff + 5, skb->len,
+			    info->ts_conf_kz_x_kazaa_username);
 	if (pos != UINT_MAX)
 		return IPP2P_KAZAA * 100 + 2;
 
-	pos = textsearch_find_continuous(info->ts_conf_kz_user_agent,
-					 &state, &payload[5], plen - 5);
+	pos = skb_find_text((struct sk_buff *)skb, poff + 5, skb->len,
+			    info->ts_conf_kz_user_agent);
 	if (pos != UINT_MAX)
 		return IPP2P_KAZAA * 100 + 2;
 
@@ -727,11 +894,20 @@  search_all_kazaa(const unsigned char *payload, const unsigned int plen,
 
 /* fast check for eDonkey file segment transfer command */
 static unsigned int
-search_edk(const unsigned char *payload, const unsigned int plen,
+search_edk(const struct sk_buff *skb,
+	   const unsigned int poff,
+	   const unsigned int plen,
 	   const struct ipt_p2p_info *info)
 {
+	unsigned char buf[6], *payload;
+
 	if (plen < 6)
 		return 0;
+
+	payload = skb_header_pointer(skb, poff, sizeof(buf), buf);
+	if (payload == NULL)
+		return 0;
+
 	if (payload[0] != 0xe3)
 		return 0;
 	if (payload[5] == 0x47)
@@ -741,13 +917,21 @@  search_edk(const unsigned char *payload, const unsigned int plen,
 
 /* intensive but slower search for some eDonkey packets including size check */
 static unsigned int
-search_all_edk(const unsigned char *payload, const unsigned int plen,
+search_all_edk(const struct sk_buff *skb,
+	       const unsigned int poff,
+	       const unsigned int plen,
 	       const struct ipt_p2p_info *info)
 {
+	unsigned char buf[6], *payload;
 	unsigned int cmd;
 
 	if (plen < 6)
 		return 0;
+
+	payload = skb_header_pointer(skb, poff, sizeof(buf), buf);
+	if (payload == NULL)
+		return 0;
+
 	if (payload[0] != 0xe3)
 		return 0;
 
@@ -768,11 +952,20 @@  search_all_edk(const unsigned char *payload, const unsigned int plen,
 
 /* fast check for Direct Connect send command */
 static unsigned int
-search_dc(const unsigned char *payload, const unsigned int plen,
+search_dc(const struct sk_buff *skb,
+	  const unsigned int poff,
+	  const unsigned int plen,
 	  const struct ipt_p2p_info *info)
 {
+	unsigned char buf[6], *payload;
+
 	if (plen < 6)
 		return 0;
+
+	payload = skb_header_pointer(skb, poff, sizeof(buf), buf);
+	if (payload == NULL)
+		return 0;
+
 	if (payload[0] != 0x24)
 		return 0;
 	if (memcmp(&payload[1], "Send|", 5) == 0)
@@ -782,21 +975,35 @@  search_dc(const unsigned char *payload, const unsigned int plen,
 
 /* intensive but slower check for all direct connect packets */
 static unsigned int
-search_all_dc(const unsigned char *payload, const unsigned int plen,
+search_all_dc(const struct sk_buff *skb,
+	      const unsigned int poff,
+	      const unsigned int plen,
 	      const struct ipt_p2p_info *info)
 {
+	unsigned char hbuf[8], *head, tbuf, *tail;
 	const unsigned char *t;
 
 	if (plen < 7)
 		return 0;
 
-	if (payload[0] != 0x24)
+	head = skb_header_pointer(skb, poff,
+				  plen - 1 < sizeof(hbuf) ?
+				  plen - 1 : sizeof(hbuf),
+				  hbuf);
+	if (head == NULL)
 		return 0;
 
-	if (payload[plen-1] != 0x7c)
+	tail = skb_header_pointer(skb, poff + plen - 1, 1, &tbuf);
+	if (tail == NULL)
 		return 0;
 
-	t = &payload[1];
+	if (head[0] != 0x24)
+		return 0;
+
+	if (tail[0] != 0x7c)
+		return 0;
+
+	t = &head[1];
 
 	/* Client-Hub-Protocol */
 	if (memcmp(t, "Lock ", 5) == 0)
@@ -814,18 +1021,21 @@  search_all_dc(const unsigned char *payload, const unsigned int plen,
 
 /* check for mute */
 static unsigned int
-search_mute(const unsigned char *payload, const unsigned int plen,
+search_mute(const struct sk_buff *skb,
+	    const unsigned int poff,
+	    const unsigned int plen,
 	    const struct ipt_p2p_info *info)
 {
 	if (plen == 209 || plen == 345 || plen == 473 || plen == 609 ||
 	    plen == 1121) {
-		//printk(KERN_DEBUG "size hit: %u", size);
+		unsigned char buf[11], *payload;
+
+		payload = skb_header_pointer(skb, poff, sizeof(buf), buf);
+		if (payload == NULL)
+			return 0;
+
 		if (memcmp(payload,"PublicKey: ", 11) == 0) {
 			return IPP2P_MUTE * 100 + 0;
-			/*
-			if (memcmp(t + size - 14, "\x0aEndPublicKey\x0a", 14) == 0)
-				printk(KERN_DEBUG "end pubic key hit: %u", size);
-			*/
 		}
 	}
 	return 0;
@@ -833,24 +1043,37 @@  search_mute(const unsigned char *payload, const unsigned int plen,
 
 /* check for xdcc */
 static unsigned int
-search_xdcc(const unsigned char *payload, const unsigned int plen,
+search_xdcc(const struct sk_buff *skb,
+	    const unsigned int poff,
+	    const unsigned int plen,
 	    const struct ipt_p2p_info *info)
 {
-	struct ts_state state;
+	unsigned char hbuf[8], *head, tbuf[2], *tail;
 	unsigned int pos;
 
 	/* search in small packets only */
 	if (plen <= 20 || plen >= 200)
 		return 0;
 
-	if (memcmp(payload, "PRIVMSG ", 8) != 0 || !iscrlf(&payload[plen - 2]))
+	head = skb_header_pointer(skb, poff,
+				  plen - 2 < sizeof(hbuf) ?
+				  plen - 2 : sizeof(hbuf),
+				  hbuf);
+	if (head == NULL)
+		return 0;
+
+	tail = skb_header_pointer(skb, poff + plen - 2, 2, &tbuf);
+	if (tail == NULL)
+		return 0;
+
+	if (memcmp(head, "PRIVMSG ", 8) != 0 || !iscrlf(tail))
 		return 0;
 
 	/*
 	 * It seems to be an IRC private message, check for xdcc command
 	 */
-	pos = textsearch_find_continuous(info->ts_conf_xdcc,
-					 &state, &payload[8], plen - 8);
+	pos = skb_find_text((struct sk_buff *)skb, poff + 8, skb->len,
+			    info->ts_conf_xdcc);
 	if (pos != UINT_MAX)
 		return IPP2P_XDCC * 100 + 0;
 
@@ -859,10 +1082,23 @@  search_xdcc(const unsigned char *payload, const unsigned int plen,
 
 /* search for waste */
 static unsigned int
-search_waste(const unsigned char *payload, const unsigned int plen,
+search_waste(const struct sk_buff *skb,
+	     const unsigned int poff,
+	     const unsigned int plen,
 	     const struct ipt_p2p_info *info)
 {
-	if (plen >= 9 && memcmp(payload, "GET.sha1:", 9) == 0)
+	unsigned char buf[9], *payload;
+
+	if (plen < 9)
+		return 0;
+
+	payload = skb_header_pointer(skb, poff,
+				     plen < sizeof(buf) ? plen : sizeof(buf),
+				     buf);
+	if (payload == NULL)
+		return 0;
+
+	if (memcmp(payload, "GET.sha1:", 9) == 0)
 		return IPP2P_WASTE * 100 + 0;
 
 	return 0;
@@ -871,7 +1107,9 @@  search_waste(const unsigned char *payload, const unsigned int plen,
 static const struct {
 	unsigned int command;
 	unsigned int packet_len;
-	unsigned int (*function_name)(const unsigned char *, const unsigned int,
+	unsigned int (*function_name)(const struct sk_buff *,
+				      const unsigned int,
+				      const unsigned int,
 				      const struct ipt_p2p_info *);
 } matchlist[] = {
 	{IPP2P_EDK,         20, search_all_edk},
@@ -896,7 +1134,9 @@  static const struct {
 static const struct {
 	unsigned int command;
 	unsigned int packet_len;
-	unsigned int (*function_name)(const unsigned char *, const unsigned int,
+	unsigned int (*function_name)(const struct sk_buff *,
+				      const unsigned int,
+				      const unsigned int,
 				      const struct ipt_p2p_info *);
 } udp_list[] = {
 	{IPP2P_KAZAA, 14, udp_search_kazaa},
@@ -927,8 +1167,9 @@  ipp2p_print_result_tcp6(const union nf_inet_addr *saddr, short sport,
 
 static bool
 ipp2p_mt_tcp(const struct ipt_p2p_info *info, const struct tcphdr *tcph,
-             const unsigned char *haystack, unsigned int hlen,
-             const struct ipp2p_result_printer *rp)
+	     const struct sk_buff *skb, unsigned int packet_off,
+	     unsigned int packet_len,
+	     const struct ipp2p_result_printer *rp)
 {
 	size_t tcph_len = tcph->doff * 4;
 	int i;
@@ -937,25 +1178,26 @@  ipp2p_mt_tcp(const struct ipt_p2p_info *info, const struct tcphdr *tcph,
 	if (tcph->syn) return 0;  /* if SYN bit is set bail out */
 	if (tcph->rst) return 0;  /* if RST bit is set bail out */
 
-	if (hlen < tcph_len) {
+	if (packet_len < tcph_len) {
 		if (info->debug)
 			pr_info("TCP header indicated packet larger than it is\n");
 		return 0;
 	}
-	if (hlen == tcph_len)
+	if (packet_len == tcph_len)
 		return 0;
 
-	haystack += tcph_len;
-	hlen     -= tcph_len;
+	packet_off += tcph_len;
+	packet_len -= tcph_len;
 
 	for (i = 0; matchlist[i].command; ++i) {
 		if ((info->cmd & matchlist[i].command) != matchlist[i].command)
 			continue;
-		if (hlen <= matchlist[i].packet_len)
+		if (packet_len <= matchlist[i].packet_len)
 			continue;
-		if (matchlist[i].function_name(haystack, hlen, info)) {
+		if (matchlist[i].function_name(skb, packet_off, packet_len,
+					       info)) {
 			if (info->debug)
-				print_result(rp, true, hlen);
+				print_result(rp, true, packet_len);
 			return true;
 		}
 	}
@@ -982,31 +1224,33 @@  ipp2p_print_result_udp6(const union nf_inet_addr *saddr, short sport,
 
 static bool
 ipp2p_mt_udp(const struct ipt_p2p_info *info, const struct udphdr *udph,
-             const unsigned char *haystack, unsigned int hlen,
-             const struct ipp2p_result_printer *rp)
+	     const struct sk_buff *skb, unsigned int packet_off,
+	     unsigned int packet_len,
+	     const struct ipp2p_result_printer *rp)
 {
 	size_t udph_len = sizeof(*udph);
 	int i;
 
-	if (hlen < udph_len) {
+	if (packet_len < udph_len) {
 		if (info->debug)
 			pr_info("UDP header indicated packet larger than it is\n");
 		return 0;
 	}
-	if (hlen == udph_len)
+	if (packet_len == udph_len)
 		return 0;
 
-	haystack += udph_len;
-	hlen     -= udph_len;
+	packet_off += udph_len;
+	packet_len -= udph_len;
 
 	for (i = 0; udp_list[i].command; ++i) {
 		if ((info->cmd & udp_list[i].command) != udp_list[i].command)
 			continue;
-		if (hlen <= udp_list[i].packet_len)
+		if (packet_len <= udp_list[i].packet_len)
 			continue;
-		if (udp_list[i].function_name(haystack, hlen, info)) {
+		if (udp_list[i].function_name(skb, packet_off, packet_len,
+					      info)) {
 			if (info->debug)
-				print_result(rp, true, hlen);
+				print_result(rp, true, packet_len);
 			return true;
 		}
 	}
@@ -1019,9 +1263,8 @@  ipp2p_mt(const struct sk_buff *skb, struct xt_action_param *par)
 	const struct ipt_p2p_info *info = par->matchinfo;
 	struct ipp2p_result_printer printer;
 	union nf_inet_addr saddr, daddr;
-	const unsigned char *haystack;  /* packet data */
-	unsigned int hlen;              /* packet data length */
 	uint8_t family = xt_family(par);
+	unsigned int packet_len;
 	int protocol;
 
 	/*
@@ -1046,10 +1289,11 @@  ipp2p_mt(const struct sk_buff *skb, struct xt_action_param *par)
 
 	if (family == NFPROTO_IPV4) {
 		const struct iphdr *ip = ip_hdr(skb);
+
 		saddr.ip = ip->saddr;
 		daddr.ip = ip->daddr;
 		protocol = ip->protocol;
-		hlen = ip_transport_len(skb);
+		packet_len = ip_transport_len(skb);
 	} else {
 		const struct ipv6hdr *ip = ipv6_hdr(skb);
 		int thoff = 0;
@@ -1059,34 +1303,47 @@  ipp2p_mt(const struct sk_buff *skb, struct xt_action_param *par)
 		protocol = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
 		if (protocol < 0)
 			return 0;
-		hlen = ipv6_transport_len(skb);
+		packet_len = ipv6_transport_len(skb);
 	}
 
 	printer.saddr = &saddr;
 	printer.daddr = &daddr;
-	haystack = skb_transport_header(skb);
 
 	switch (protocol) {
 	case IPPROTO_TCP:	/* what to do with a TCP packet */
 	{
-		const struct tcphdr *tcph = tcp_hdr(skb);
+		const struct tcphdr *tcph;
+		struct tcphdr _tcph;
+
+		tcph = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
+		if (tcph == NULL)
+			return 0;
 
 		printer.sport = ntohs(tcph->source);
 		printer.dport = ntohs(tcph->dest);
 		printer.print = family == NFPROTO_IPV6 ?
 		                ipp2p_print_result_tcp6 : ipp2p_print_result_tcp4;
-		return ipp2p_mt_tcp(info, tcph, haystack, hlen, &printer);
+
+		return ipp2p_mt_tcp(info, tcph, skb, par->thoff, packet_len,
+				    &printer);
 	}
 	case IPPROTO_UDP:	/* what to do with a UDP packet */
 	case IPPROTO_UDPLITE:
 	{
-		const struct udphdr *udph = udp_hdr(skb);
+		const struct udphdr *udph;
+		struct udphdr _udph;
+
+		udph = skb_header_pointer(skb, par->thoff, sizeof(_udph), &_udph);
+		if (udph == NULL)
+			return 0;
 
 		printer.sport = ntohs(udph->source);
 		printer.dport = ntohs(udph->dest);
 		printer.print = family == NFPROTO_IPV6 ?
 		                ipp2p_print_result_udp6 : ipp2p_print_result_udp4;
-		return ipp2p_mt_udp(info, udph, haystack, hlen, &printer);
+
+		return ipp2p_mt_udp(info, udph, skb, par->thoff, packet_len,
+				    &printer);
 	}
 	default:
 		return 0;