打印TCP数据包数据
在TCP通信中,当数据包从以太网传输到网络(IP)层时,我想打印该数据包中的数据?
我正在研究linux。
我得到了一些信息,可以借助linux内核代码,即在linux NAT防火墙代码中完成。 但是我会在哪里获得内核源代码? 这些编码在哪里?
如何从TCP数据包打印数据
下面是一个完全符合您需求的示例:挂钩接收TCP数据包并打印其有效负载。 如果要从接收的数据包中打印一些其他信息(如二进制数据),您只需要修改此注释下的部分:
/* ----- Print all needed information from received TCP packet ------ */
如果您需要跟踪传输的数据包而不是接收的数据包,则可以替换此行:
nfho.hooknum = NF_INET_PRE_ROUTING;
与这一个:
nfho.hooknum = NF_INET_POST_ROUTING;
保存下一个文件并发出make
命令来构建内核模块。 然后执行sudo insmod print_tcp.ko
加载它。 之后,您将能够使用dmesg
命令查看嗅探信息。 如果要卸载模块,请运行sudo rmmod print_tcp
命令。
print_tcp.c :
#include #include #include #include #include #define PTCP_WATCH_PORT 80 /* HTTP port */ static struct nf_hook_ops nfho; static unsigned int ptcp_hook_func(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct iphdr *iph; /* IPv4 header */ struct tcphdr *tcph; /* TCP header */ u16 sport, dport; /* Source and destination ports */ u32 saddr, daddr; /* Source and destination addresses */ unsigned char *user_data; /* TCP data begin pointer */ unsigned char *tail; /* TCP data end pointer */ unsigned char *it; /* TCP data iterator */ /* Network packet is empty, seems like some problem occurred. Skip it */ if (!skb) return NF_ACCEPT; iph = ip_hdr(skb); /* get IP header */ /* Skip if it's not TCP packet */ if (iph->protocol != IPPROTO_TCP) return NF_ACCEPT; tcph = tcp_hdr(skb); /* get TCP header */ /* Convert network endianness to host endiannes */ saddr = ntohl(iph->saddr); daddr = ntohl(iph->daddr); sport = ntohs(tcph->source); dport = ntohs(tcph->dest); /* Watch only port of interest */ if (sport != PTCP_WATCH_PORT) return NF_ACCEPT; /* Calculate pointers for begin and end of TCP packet data */ user_data = (unsigned char *)((unsigned char *)tcph + (tcph->doff * 4)); tail = skb_tail_pointer(skb); /* ----- Print all needed information from received TCP packet ------ */ /* Show only HTTP packets */ if (user_data[0] != 'H' || user_data[1] != 'T' || user_data[2] != 'T' || user_data[3] != 'P') { return NF_ACCEPT; } /* Print packet route */ pr_debug("print_tcp: %pI4h:%d -> %pI4h:%d\n", &saddr, sport, &daddr, dport); /* Print TCP packet data (payload) */ pr_debug("print_tcp: data:\n"); for (it = user_data; it != tail; ++it) { char c = *(char *)it; if (c == '\0') break; printk("%c", c); } printk("\n\n"); return NF_ACCEPT; } static int __init ptcp_init(void) { int res; nfho.hook = (nf_hookfn *)ptcp_hook_func; /* hook function */ nfho.hooknum = NF_INET_PRE_ROUTING; /* received packets */ nfho.pf = PF_INET; /* IPv4 */ nfho.priority = NF_IP_PRI_FIRST; /* max hook priority */ res = nf_register_hook(&nfho); if (res < 0) { pr_err("print_tcp: error in nf_register_hook()\n"); return res; } pr_debug("print_tcp: loaded\n"); return 0; } static void __exit ptcp_exit(void) { nf_unregister_hook(&nfho); pr_debug("print_tcp: unloaded\n"); } module_init(ptcp_init); module_exit(ptcp_exit); MODULE_AUTHOR("Sam Protsenko"); MODULE_DESCRIPTION("Module for printing TCP packet data"); MODULE_LICENSE("GPL");
Makefile :
ifeq ($(KERNELRELEASE),) KERNELDIR ?= /lib/modules/$(shell uname -r)/build module: $(MAKE) -C $(KERNELDIR) M=$(PWD) C=1 modules clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) C=1 clean .PHONY: module clean else MODULE = print_tcp.o CFLAGS_$(MODULE) := -DDEBUG obj-m := $(MODULE) endif
说明
我建议你阅读这本书:[4]。 特别是你对下一章感兴趣:
- 第11章:第4层协议
- TCP(传输控制协议)
- 使用TCP从网络层(L3)接收数据包
- 使用TCP发送数据包
- TCP(传输控制协议)
- 第9章:Netfilter
- Netfilter Hooks
如何获取Linux内核源代码
您可以使用您喜欢的方式获取内核源代码:
-
来自kernel.org的 vanilla内核(更具体地来自kernel / git / torvalds / linux.git ),使用Git 。 例如,如果您需要k3.13,可以通过下一步方式完成:
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git $ cd linux/ $ git checkout v3.13
-
您的发行版的内核源代码。 例如在Debian中你可以安装
linux-source
包(源代码将安装到/usr/src
)。 对于Ubuntu,请参阅这些说明 。
细节:
[1] 如何从sk_buff获取TCP头
[2] Linux内核中的网络流量控制
[3] 使用netfilter钩子编写可加载内核模块
[4] Rami Rosen撰写的“Linux内核网络:实现与理论”
[5] 如何从tcphdr访问数据/有效负载
UPDATE
钩子捕获此示例的数据包的位置? 换句话说,它是否在TCP堆栈上,以便我不需要处理数据包丢失,重新排序等?
在ip_rcv()
函数( 这里 )中调用Netfilter钩子,因此您基本上在IPv4层(OSI中的网络层)中工作。 所以我认为在netfilter挂钩中还没有处理丢包处理,数据包重新排序等。
请参阅下一个链接以获取见解:
- Netfilter数据包流
- Linux网络中的控制流程
- 网络数据流经内核(图)
如果您想在传输层(TCP)上使用挂钩数据包 - netfilter不足以完成此任务,因为它仅在网络层(IPv4)中工作。
您希望使用tcpdump
工具检查线路上的TCP数据包。
您没有说明您要查看的数据类型。
这会在DNS端口53上转储流量
tcpdump -vvv -s 0 -l -n port 53
这个页面有一个很好的概述。
您可以像这样使用tcpdump:
tcpdump -vvv -s 0 -l -n port 80 -i NameOfYourDevice
或更好:
tcpdump -i NameOfYourDevice -a -x -n port 80