测试环境: CentOS5.3 2.6.18 工具: sendip和wireshark sendip可以发送各种数据包,确实方便.wireshark图形化的显示对于分析整个数据包还是相当不错的... 一:内核态基于Netfilter构造数据包 主要有两种方式: 1. alloc_skb申请一个skb结构体,然后根据实际的应用填充不同的成员,或者基于当前数据包的skb, 调用skb_copy() pskb_copy() skb_copy_expand()等新申请一个nskb,并且拷贝skb的内容。 2. 直接在先前接收到的数据包skb上作修改,主要有源IP、目IP,如果是TCP/UDP协议的话,还有源端口目的端口号。 就是根据你自己的需求去调整数据包的相关成员即可。然后重新计算各个部分的校验和。
不管你第一种方式还是第二种方式,你需要知道你也必须知道的就是对于l2 l3 l4层的数据你都必须去构造,我之前就是 由于没有构造L2而郁闷了一天... 让我们先从一个小程序开始,把5个hook都挂上mac这个函数,主要就是看看l2,对于l3 l4以及应用层我以前的几个帖子里面 已经有很多了,这里就不说了
- printk("------begin %s--------\n", hooks[hooknum]);
- print_ipproto(iph->protocol);
- printk("len is %d, data len is %d\n", nskb->len, nskb->data_len);
- if(nskb->mac_len > 0)
- {
- eth = (struct ethhdr*)(nskb->mac.raw);
- print_mac(eth);
- }
- printk("------end %s--------\n", hooks[hooknum]);
复制代码
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/netfilter.h>
- #include <linux/skbuff.h>
- #include <linux/ip.h>
- #include <linux/netdevice.h>
- #include <linux/if_ether.h>
- #include <linux/if_packet.h>
- #include <net/tcp.h>
- #include <net/udp.h>
- #include <net/icmp.h>
- #include <linux/netfilter_ipv4.h>
- #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
- #define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("kenthy@163.com");
- const char* hooks[] ={ "NF_IP_PRE_ROUTING",
- "NF_IP_LOCAL_IN",
- "NF_IP_FORWARD",
- "NF_IP_LOCAL_OUT",
- "NF_IP_POST_ROUTING"};
- void print_ipproto(int proto)
- {
- switch(proto)
- {
- case IPPROTO_ICMP:
- printk("%s\n", "IPPROTO_ICMP");
- break;
- case IPPROTO_TCP:
- printk("%s\n", "IPPROTO_TCP");
- break;
- case IPPROTO_UDP:
- printk("%s\n", "IPPROTO_UDP");
- break;
- default:
- printk("%s\n", "other IPPROTO");
- }
- }
- void print_mac(struct ethhdr* eth)
- {
- if(eth==NULL)
- return;
-
- if(eth->h_source!=NULL)
- printk("SOURCE:" MAC_FMT "\n", MAC_ARG(eth->h_source));
- if(eth->h_dest!=NULL)
- printk("DEST:" MAC_FMT "\n", MAC_ARG(eth->h_dest));
- }
- unsigned int
- mac(unsigned int hooknum,
- struct sk_buff** skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff*))
- {
- struct sk_buff* nskb;
- struct iphdr *iph = NULL;
- struct ethhdr* eth;
-
- nskb = *skb;
- if(nskb==NULL)
- {
- printk("%s\n", "*skb is NULL");
- return NF_ACCEPT;
- }
-
- iph = ip_hdr(nskb);
- if(iph == NULL)
- {
- printk("%s\n", "*iph is NULL");
- return NF_ACCEPT;
- }
-
- printk("------begin %s--------\n", hooks[hooknum]);
- print_ipproto(iph->protocol);
- printk("len is %d, data len is %d\n", nskb->len, nskb->data_len);
- if(nskb->mac_len > 0)
- {
- eth = (struct ethhdr*)(nskb->mac.raw);
- print_mac(eth);
- }
- else
- printk("%s", "mac is NULL");
-
-
- printk("------end %s--------\n", hooks[hooknum]);
-
- return NF_ACCEPT;
- }
-
- static struct nf_hook_ops mac_ops[] = {
- {
- .hook = mac,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_IP_PRE_ROUTING,
- .priority = NF_IP_PRI_FIRST,
- },
- {
- .hook = mac,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_IP_LOCAL_IN,
- .priority = NF_IP_PRI_FIRST,
- },
- {
- .hook = mac,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_IP_FORWARD,
- .priority = NF_IP_PRI_FIRST,
- },
- {
- .hook = mac,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_IP_LOCAL_OUT,
- .priority = NF_IP_PRI_FIRST,
- },
- {
- .hook = mac,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_IP_PRE_ROUTING,
- .priority = NF_IP_POST_ROUTING,
- },
- };
- static int __init init(void)
- {
- int ret;
- ret = nf_register_hooks(mac_ops, ARRAY_SIZE(mac_ops));
- if (ret < 0) {
- printk("http detect:can't register mac_ops detect hook!\n");
- return ret;
- }
- printk("insmod mac_ops detect module\n");
- return 0;
- }
- static void __exit fini(void)
- {
- nf_unregister_hooks(mac_ops, ARRAY_SIZE(mac_ops));
- printk("remove mac_ops detect module.\n");
- }
- module_init(init);
- module_exit(fini);
复制代码 insmod mac.ko加载mac模块后,随便发个ping包 Jan 10 09:44:13 nfs-client kernel: ------begin NF_IP_LOCAL_OUT-------- Jan 10 09:44:13 nfs-client kernel: IPPROTO_ICMP Jan 10 09:44:13 nfs-client kernel: len is 84, data len is 0 Jan 10 09:44:13 nfs-client kernel: mac is NULL------end NF_IP_LOCAL_OUT-------- Jan 10 09:44:13 nfs-client kernel: ------begin NF_IP_PRE_ROUTING-------- Jan 10 09:44:13 nfs-client kernel: IPPROTO_ICMP Jan 10 09:44:13 nfs-client kernel: len is 84, data len is 0 Jan 10 09:44:13 nfs-client kernel: SOURCE:00:50:56:fa:70:2a Jan 10 09:44:13 nfs-client kernel: DEST:00:0c:29:4f:de:ac Jan 10 09:44:13 nfs-client kernel: ------end NF_IP_PRE_ROUTING-------- Jan 10 09:44:13 nfs-client kernel: ------begin NF_IP_LOCAL_IN-------- Jan 10 09:44:13 nfs-client kernel: IPPROTO_ICMP Jan 10 09:44:13 nfs-client kernel: len is 84, data len is 0 Jan 10 09:44:13 nfs-client kernel: SOURCE:00:50:56:fa:70:2a Jan 10 09:44:13 nfs-client kernel: DEST:00:0c:29:4f:de:ac Jan 10 09:44:13 nfs-client kernel: ------end NF_IP_LOCAL_IN-------- 可以看到对于挂载在out上的数据包mac已经被剥掉
当接收一个包时,处理n层协议头的函数从n-1层收到一个缓冲区,它的skb->data指向n层协议的头。处理n层协议的函数把本层的指针(例如,L3对应的是skb->nh指针)初始化为skb->data,因为这个指针的值会在处理下一层协议时改变(skb->data将被初始化成缓冲区里的其他地址)。在处理n层协议的函数结束时,在把包传递给n+1层的处理函数前,它会把skb->data指针指向n层协议头的末尾,这正好是n+1层协议的协议头。
发送包的过程与此相反,但是由于要为每一层添加新的协议头,这个过程要比接收包的过程复杂。 |
评论