您的位置:首页 > 运维架构 > Linux

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

2014-02-08 10:51 127 查看
原文地址:http://wenx05124561.blog.163.com/blog/static/124000805201242023941402/

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

构造数据包:构造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;

}

发送数据包:通过复制存储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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: