]> git.ipfire.org Git - thirdparty/xtables-addons.git/commitdiff
xt_ipp2p: use skb_header_pointer and skb_find_text functions
authorJeremy Sowden <jeremy@azazel.net>
Mon, 5 Jun 2023 15:10:43 +0000 (00:10 +0900)
committerJan Engelhardt <jengelh@inai.de>
Tue, 6 Jun 2023 12:23:37 +0000 (21:23 +0900)
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

index 33b3604ada59d3fd7663fc0d9c28c7930a572793..272223f111991cca4c7dc01527c7a8be258b6bfc 100644 (file)
@@ -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;
+
+       tail = skb_header_pointer(skb, packet_off + packet_len - 1, 1, &tbuf);
+       if (tail == NULL)
+               return 0;
+
+       if (head[0] != 0x24)
                return 0;
-       if (t[packet_len-1] != 0x7c)
+       if (tail[0] != 0x7c)
                return 0;
-       if (memcmp(&t[1], "SR ", 3) == 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,11 +542,19 @@ 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 ||
                     get_u16(w, 4) == 0x5000) &&
@@ -481,10 +570,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;
@@ -498,23 +596,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;
 
@@ -523,7 +616,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') {
@@ -551,11 +644,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;
@@ -563,12 +667,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.
@@ -594,18 +706,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;
        return 0;
@@ -613,13 +725,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;
@@ -627,52 +751,85 @@ 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 (!iscrlf(tail))
                return 0;
-       if (plen >= 19 && memcmp(payload, "GNUTELLA CONNECT/", 17) == 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;
        return 0;
@@ -681,35 +838,45 @@ 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 (!iscrlf(tail))
                return 0;
 
-       if (memcmp(payload, "GIVE ", 5) == 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;
 
@@ -718,11 +885,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)
@@ -732,13 +908,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;
 
@@ -758,11 +942,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)
@@ -772,18 +965,30 @@ 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)
                return IPP2P_DC * 100 + 1;
@@ -798,18 +1003,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;
@@ -817,22 +1025,33 @@ 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;
 
@@ -841,10 +1060,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;
@@ -853,7 +1085,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},
@@ -878,7 +1112,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},
@@ -909,8 +1145,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;
@@ -919,25 +1156,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;
                }
        }
@@ -964,31 +1202,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;
                }
        }
@@ -1001,9 +1241,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;
 
        /*
@@ -1028,10 +1267,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;
@@ -1041,34 +1281,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;