C语言 Netfilter内核模块未获取ftp数据包的数据

cnjp1d6j  于 2022-12-02  发布在  其他
关注(0)|答案(1)|浏览(136)

Netfilter Kernel module doesn't get the FTP packets' data

Question

I've been trying to write a kernel module to read outgoing FTP packets' username, password and cmd by netfilter.When I test my code ,I find the ftp packets' length is right,but all the data I get is 0x00 when check kernel module's output.

Code

Here is my code. And I wirte a pkt_hex_dump functioin to dump all my packets's bytes above the Internet layer(Include Internet layer) accroding to this Printing sk_buff data :

/* Sample code to install a Netfilter hook function */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>

MODULE_LICENSE("MIT");
MODULE_AUTHOR("1933");
MODULE_DESCRIPTION("An net sniff module for demonstration");
MODULE_VERSION("1.0");

/* Used to describe our Netfilter hooks */
static struct nf_hook_ops post_hook;

/* THESE values are used to keep the USERname and PASSword until
 * they are queried. Only one USER/PASS pair will be held at one
 * time
 */

static char *username = NULL;
static char *password = NULL;
static unsigned short src_port = 0; 
static int  have_pair = 0;   /* Marks if we already have a pair */

/* dump packet's data */
void pkt_hex_dump(struct sk_buff *skb){
    size_t len;
    int rowsize = 16;
    int i, l, linelen, remaining;
    int li = 0;
    uint8_t *data, ch; 
    struct iphdr *ip = (struct iphdr *)skb_network_header(skb);

    printk("Packet hex dump:\n");
    data = (uint8_t *) skb_network_header(skb);

    len=ntohs(ip->tot_len);

    remaining = len;
    for (i = 0; i < len; i += rowsize) {
        printk("%06d\t", li);
        linelen = min(remaining, rowsize);
        remaining -= rowsize;
        for (l = 0; l < linelen; l++) {
            ch = data[l];
            printk(KERN_CONT "%02X ", (uint32_t) ch);
        }
        data += linelen;
        li += 10; 

        printk(KERN_CONT "\n");
    }
}

/* This is the hook function itself */
unsigned int watch_out(void *priv,
        struct sk_buff *skb,
        const struct nf_hook_state *state)
{
    struct iphdr *ip = NULL;
    struct tcphdr *tcp = NULL;
    unsigned char *data=NULL;

    ip = (struct iphdr *)skb_network_header(skb);
    if (ip->protocol != IPPROTO_TCP){
        return NF_ACCEPT;
    }

    tcp = (struct tcphdr *)skb_transport_header(skb);

    /* Now check to see if it's an FTP packet */
    if (tcp->dest!= htons(21)){
        return NF_ACCEPT;    
    }
    
    pkt_hex_dump(skb);
  /* Parse the FTP packet for relevant information if we don't already
   * have a username and password pair. */
     data = (unsigned char *)((unsigned char *)tcp + (tcp->doff * 4));

    printk("hex : data[0-3] = 0x%02x%02x%02x%02x\n", data[0], data[1], data[2], data[3]);
    printk("char: data[0-3] = %c%c%c%c\n", data[0], data[1], data[2], data[3]);
    printk("--------------- findpkt_iwant ------------------\n");
    return NF_ACCEPT;
}

/* Initialisation routine */
int init_module(){
    /* Fill in our hook structure */
    post_hook.hook = watch_out;         /* Handler function */
    post_hook.hooknum  = NF_INET_POST_ROUTING; 
    post_hook.pf       = AF_INET;
    post_hook.priority = NF_IP_PRI_FIRST;   /* Make our function first */

    nf_register_net_hook(&init_net,&post_hook);

    // Debug
    printk("HELLO:  this is hello module speaking\n");
    return 0;
}

/* Cleanup routine */
void cleanup_module(){
    printk("HELLO : Goodbye!\n");
    nf_unregister_net_hook(&init_net,&post_hook);
}

Enviroment

  • Linux 5.13.0-37-generic x86_64 GNU/Linux
  • Ubuntu 20.04.4 LTS
  • Makefile:
obj-m+=NetKernal.o

all:
    make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules

The Kernel module's Output and the Wireshark' capture:

  • This is the whole demsg output when I connected to ftp server and inputed my username and password on my Local area network.
  • And this is the whole wireshark packet after adding filter rule: tcp.dstport == 21 .The Internet layer bytes start with the offset 0xe in the pcapng.

What weird is these ftp packets.Take the fourth packet for example.

  • This is Kernel module's log.(The /**/ which does not exist in the original data is comment I added for better understanding)
[ 4964.195893] Packet hex dump:
[ 4964.195904] 000000   45 10 00 42 D9 86 40 00 40 06 DD BC C0 A8 01 07     /* dump start from Internet layer */
[ 4964.195953] 000010   C0 A8 01 0B 93 E4 00 15 A5 63 17 A8 92 28 25 E3 
[ 4964.195982] 000020   80 18 01 F6 83 97 00 00 01 01 08 0A C0 EC BD AB 
[ 4964.196011] 000030   00 08 A7 2F 00 00 00 00 00 00 00 00 00 00 00 00     /* ftp content:0x00 */
[ 4964.196038] 000040   00 00 
[ 4964.196045] hex : data[0-3] = 0x00000000
[ 4964.196049] char: data[0-3] = 
[ 4964.196052] --------------- findpkt_iwant ------------------
  • And this is the wireshark captured packet accroding to:
No.     Time           Source                Source Port Destination           Destination Port Protocol Length Info
    132 14.635575358   192.168.1.7           37860       192.168.1.11          21               FTP      80     Request: USER ftpuser

Frame 132: 80 bytes on wire (640 bits), 80 bytes captured (640 bits) on interface wlp3s0, id 0
Ethernet II, Src: 58:a0:23:05:3b:2e, Dst: 1c:c1:de:65:e5:d4
Internet Protocol Version 4, Src: 192.168.1.7, Dst: 192.168.1.11
Transmission Control Protocol, Src Port: 37860, Dst Port: 21, Seq: 1, Ack: 28, Len: 14
File Transfer Protocol (FTP)
[Current working directory: ]

0000  1c c1 de 65 e5 d4 58 a0 23 05 3b 2e 08 00 45 10   ...e..X.#.;...E.    /* # Internet layer starts from the offset 0x0e */
0010  00 42 d9 86 40 00 40 06 dd bc c0 a8 01 07 c0 a8   .B..@.@.........
0020  01 0b 93 e4 00 15 a5 63 17 a8 92 28 25 e3 80 18   .......c...(%...
0030  01 f6 ab 01 00 00 01 01 08 0a c0 ec bd ab 00 08   ................
0040  a7 2f 55 53 45 52 20 66 74 70 75 73 65 72 0d 0a   ./USER ftpuser..

As can be seen,the ftp packet's content is 0x00 ,but whole packet's length is right(above the Internet layer).And all other ftp packets have the same problem. It seems sk_buff don't get the ftp data.
As wireshark can get the correct packets, I don't think it's firewall's queseton.

My quesetons are :

  • Why all ftp packets' content is all 0x00 while packets' length is correct ?
  • Where is my ftp data in the struct sk_buff or it's stored in other place?
  • Is there anyone who has had the same problem?

Any help will be appreciated.

e5nqia27

e5nqia271#

我想你遇到了和我一样的情况,你无法过滤/记录任何类型的TCP负载,我使用的是带有内核5.18.x的arch Linux,我必须重新编译内核,使其支持netfilter TCP数据包负载过滤,以便使其工作,另一个有趣的事实是,我也无法使用nftables的字符串匹配,因为它根本不起作用!wireshark有一个不同的故事,我认为它使用一个单独的TAP或其他东西,而不是netfilter,以保持眼睛的有效负载,在这一点上,我不太记得什么内核选项,你必须启用,以获得netfilter TCP有效负载跟踪器的工作,但给予它一个搜索,这是所有我可以帮助。
记住(我的经验告诉我),每次你遇到像这样的奇怪问题时:得到意外的空结果,或者任何你发现它们不可能修复的奇怪错误,或者根本没有意义,在大多数情况下,一定有一些与你的内核相关的东西(AKA内核配置):
例如:

  • nf_conntrack为空:缺少conntrack模块
  • 引导后无内核POST:缺少帧缓冲区模块

相关问题