上次看了ubuntuer兄写的教你修改以及重构skb ,受益匪浅,真是经典之作。 但ubuntuer兄的代码是基于2.6.18的,比较旧。今天经过摸索,我终于让其可以在2.6.30上运行了,代码如下: skb_DIY.c #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/inet.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/route.h> #include <net/icmp.h> #include <linux/netfilter_ipv4.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("kenthy@163.com"); #define ETH "eth0" #define SIP "192.168.238.180" #define DIP "192.168.1.101" #define SPORT 39804 #define DPORT 80 unsigned char SMAC[ETH_ALEN] = {0x00,0x0C,0x29,0x4F,0xDE,0xAC}; unsigned char DMAC[ETH_ALEN] = {0x00,0x50,0x56,0xFA,0x70,0x2A}; int cp_dev_xmit_tcp (char * eth, u_char * smac, u_char * dmac, u_char * pkt, int pkt_len, u_long sip, u_long dip, u_short sport, u_short dport, u_long seq, u_long ack_seq, u_char psh, u_char fin) { struct sk_buff * skb = NULL; struct net_device * dev = NULL; struct ethhdr * ethdr = NULL; struct iphdr * iph = NULL; struct tcphdr * tcph = NULL; u_char * pdata = NULL; int nret = 1; if (NULL == smac || NULL == dmac) goto out; dev = dev_get_by_name(&init_net, eth); if (NULL == dev) goto out; skb = alloc_skb (pkt_len + sizeof (struct iphdr) + sizeof (struct tcphdr) + LL_RESERVED_SPACE (dev), GFP_ATOMIC); /* LL_RESERVED_SPACE(dev) = 16 alloc_skb返回以后,skb->head = skb_data = skb->tail = alloc_skb分配的内存区首地址,skb->len = 0; skb->end = skb->tail + size; 注:我的机子是32位x86机器,所以没有定义NET_SKBUFF_DATA_USES_OFFSET,因而, skb->tail,skb->mac_header,skb->network_header,skb->transport_header 这几个成员都是指针 */ if (NULL == skb) goto out; skb_reserve (skb, LL_RESERVED_SPACE (dev));//add data and tail skb->dev = dev; skb->pkt_type = PACKET_OTHERHOST; skb->protocol = __constant_htons(ETH_P_IP); skb->ip_summed = CHECKSUM_NONE; skb->priority = 0; //skb->nh.iph = (struct iphdr*)skb_put(skb, sizeof (struct iphdr)); //skb->h.th = (struct tcphdr*)skb_put(skb, sizeof (struct tcphdr)); skb_set_network_header(skb, 0); //skb->network_header = skb->data + 0; skb_put(skb, sizeof (struct iphdr)); //add tail and len skb_set_transport_header(skb, sizeof (struct iphdr));//skb->transport_header = skb->data + sizeof (struct iphdr) skb_put(skb, sizeof (struct tcphdr)); pdata = skb_put (skb, pkt_len); { if (NULL != pkt) memcpy (pdata, pkt, pkt_len); } { tcph = tcp_hdr(skb); memset (tcph, 0, sizeof (struct tcphdr)); tcph->source = sport; tcph->dest = dport; tcph->seq = seq; tcph->ack_seq = ack_seq; tcph->doff = 5; tcph->psh = psh; tcph->fin = fin; tcph->syn = 1; tcph->ack = 0; tcph->window = __constant_htons (5840); skb->csum = 0; tcph->check = 0; } { iph = ip_hdr(skb); iph->version = 4; iph->ihl = sizeof(struct iphdr)>>2; iph->frag_off = 0; iph->protocol = IPPROTO_TCP; iph->tos = 0; iph->daddr = dip; iph->saddr = sip; iph->ttl = 0x40; iph->tot_len = __constant_htons(skb->len); iph->check = 0; } skb->csum = skb_checksum (skb, iph->ihl*4, skb->len - iph->ihl * 4, 0); tcph->check = csum_tcpudp_magic (sip, dip, skb->len - iph->ihl * 4, IPPROTO_TCP, skb->csum); { ethdr = (struct ethhdr*)skb_push (skb, 14);//reduce data and add len memcpy (ethdr->h_dest, dmac, ETH_ALEN); memcpy (ethdr->h_source, smac, ETH_ALEN); ethdr->h_proto = __constant_htons (ETH_P_IP); } if (0 > dev_queue_xmit(skb)) goto out; nret = 0; out: if (0 != nret && NULL != skb) { dev_put (dev); kfree_skb (skb); } return (nret); } static int __init init(void) { printk("%s/n","insmod skb_diy module/n"); cp_dev_xmit_tcp (ETH, SMAC, DMAC,NULL, 0, in_aton(SIP),in_aton(DIP), htons(SPORT),htons(DPORT), 0, 0, 0, 0); return 0; } static void __exit fini(void) { printk("%s/n","remove skb_diy module./n"); } module_init(init); module_exit(fini); Makefile: PWD:=$(shell pwd) KERNEL_SRC = /lib/modules/`uname -r`/build obj-m:=skb_DIY.o skb_DIY-objs:=skb.o all: make -C $(KERNEL_SRC) M=$(PWD) modules clean: rm -f *.o rm -f *.ko rm -f .*.cmd rm -rf .tmp_versions rm -f *.mod.c rm -f *.symvers rm -f *.order