Linux内核构造和发送vlan&udp数据报文

来源:互联网 发布:管理游戏的软件 编辑:程序博客网 时间:2024/05/16 04:47

原文地址:http://wenx05124561.blog.163.com/blog/static/124000805201242023941402/


Linux内核中构造ip数据包,通过网卡驱动直接发送是一种有效的发送数据包方式。本文通过构造数据包和发送数据包来实现该方式。

  1. 构造数据包:构造vlant头的ip和udp数据包

#define IP_HEAD_LENTH     20

#define UDP_HEAD_LENTH    8

#define VLAN_ETH_HLENTH         18

#define  VLAN_UDP_LENTH  (VLAN_ETH_HLENTH + IP_HEAD_LENTH + UDP_HEAD_LENTH )

#define MTU_SIZE 1500

struct vlan_packet

{

            unsigned char data[MTU_SIZE];

            unsigned short  length;

};

 struct payload_info

{

            unsigned char data[MTU_SIZE - VLAN_UDP_LENTH];

            unsigned short length;

            unsigned int daddr;

};

struct sk_buff *send_skb ;

int create_new_packet(struct vlan_packet *packet, struct payload_info * payload_info)

{

            struct vlan_ethhdr  *vethhdr;

            struct iphdr *iph;

            struct udphdr *uh;

            struct gtp_u_hdr *gh;

            unsigned char *payload;

            //unsigned short udp_check;

            struct net_device *dev;

            struct sk_buff *skb = NULL;

           

 

            if(payload_info->length + VLAN_UDP_LENTH > MTU_SIZE)

                                    return -EINVAL;

            //填充vlan_ethhdr头结构,即MAC数据

            memset(packet->data, 0, MTU_SIZE);         

            vethhdr = (struct vlan_ethhdr*)packet->data;

           

            memcpy (vethhdr->h_dest, dmac, ETH_ALEN);

            memcpy (vethhdr->h_source, smac, ETH_ALEN);

            vethhdr->h_vlan_proto = htons(ETH_P_8021Q); //vlan mac 头

            vethhdr->h_vlan_TCI = htons(0x0);

            vethhdr->h_vlan_encapsulated_proto = htons(0x0800);//下一层协议IP

 

            packet->length = VLAN_ETH_HLEN;

          //填充ip头数据

            iph =(struct iphdr *)(packet->data + VLAN_ETH_HLEN);

            iph->version = 4;

            iph->ihl = 5;

            iph->tos = 0;

            iph->tot_len = htons(VLAN_UDP_LENTH - VLAN_ETH_HLEN + payload_info->length);

            iph->id = 0;

            iph->frag_off = htons(0x4000);

            iph->ttl = 64;

            iph->protocol = IPPROTO_UDP;//下一层udp数据包

 

            dev = dev_get_by_name(&init_net, "eth0");

            iph->daddr = payload_info->daddr;

            iph->saddr = dev->ip_ptr->ifa_list->ifa_address;//获取网口eth0 IP address

            iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);//ip 头校验和

 

            packet->length += IP_HEAD_LENTH;

            //填充udp头数据

            uh = (struct udphdr *)(packet->data + VLAN_ETH_HLEN + IP_HEAD_LENTH);

            uh->source = htons(0x1234);

            uh->dest = htons(U_PORT);

            uh->len = htons(UDP_HEAD_LENTH + payload_info->length);

           

            packet->length += UDP_HEAD_LENTH;

            //填充payload数据

            payload = (packet->data + VLAN_ETH_HLEN + IP_HEAD_LENTH + UDP_HEAD_LENTH);

 

            memcpy(payload, payload_info->data, payload_info->length);

            packet->length += payload_info->length;

 

            //分配skb数据结构

            skb = dev_alloc_skb(packet->length + 200);

            if (NULL == skb)

            {

                        wx_debug("tmp skb alloc failed\n");

                        return -1;

            }

            skb_reserve(skb, 2);

            skb_put(skb, packet->length);

            skb->len = packet->length;

            skb->protocol = htons(ETH_P_8021Q);

            memcpy((unsigned char *)skb->data, packet->data, packet->length);

            skb_pull(skb,  VLAN_ETH_HLEN);

            iph = (struct iphdr *)(skb->data);

 

            skb_pull(skb,  IP_HEAD_LENTH);

            uh = (struct udphdr *)(skb->data);

           

            //进行udp检验和计算

            uh->check = 0;                                     

            skb->csum = csum_partial(skb->data, skb->len, 0);

            uh->check = csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, iph->protocol, skb->csum);

           

            skb_push(skb, IP_HEAD_LENTH + VLAN_ETH_HLEN);

            skb->ip_summed = CHECKSUM_COMPLETE;

                 

            skb->dev=dev_get_by_name(&init_net, "eth0");

            send_skb = skb; //将skb存储于变量send _skb

            return 0;

}

  1. 发送数据包:通过复制存储send_skb, 利用发送函数进行发送。

int alloc_skb_send()

{          

            int ret = 0;

            //复制数据包

            struct sk_buff *skb = skb_clone(skb_send, GFP_KERNEL);

            //发送数据包

            ret = dev_queue_xmit(skb);

            if(ret > 0 && skb != NULL)

            {

                        kfree_skb(skb);

                        printk("dev_queue_xmit failed\n");

                        return -1;

            }

            return 0;

}


0 0