打印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发送数据包
  • 第9章:Netfilter
    • Netfilter Hooks

如何获取Linux内核源代码

您可以使用您喜欢的方式获取内核源代码:

  1. 来自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 
  2. 您的发行版的内核源代码。 例如在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)中工作。

在内核级别不确定。

您可以使用libpcap实用程序捕获数据包并进行剖析。 例如:

http://yuba.stanford.edu/~casado/pcap/section2.html

您希望使用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