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

原文地址: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;

}


VLAN讲解(重点难点详解) 里面有经典案例 完整配置命令 一下是部分内容 什么是VLANVLAN(Virtual LAN),翻译成中文是“虚拟局域网”。LAN可以是由少数几台家用计算机构成的网络, 也可以是数以百计的计算机构成的企业网络。VLAN所指的LAN特指使用路由器分割的网络——也就是广 播域。 在此让我们先复习一下广播域的概念。广播域,指的是广播帧(目标MAC地址全部为1)所能传递到的范 围,亦即能够直接通信的范围。严格地说,并不仅仅是广播帧,多播帧(Multicast Frame)和目标不明的 单播帧(Unknown Unicast Frame)也能在同一个广播域中畅行无阻。 本来,二层交换机只能构建单一的广播域,不过使用VLAN功能后,它能够将网络分割成多个广播域。 未分割广播域时…… 那么,为什么需要分割广播域呢?那是因为,如果仅有一个广播域,有可能会影响到网络整体的传输性 能。具体原因,请参看附图加深理解。 图中,是一个由5台二层交换机(交换机1~5)连接了大量客户机构成的网络。假设这时,计算机A需要与 计算机B通信。在基于以太网的通信中,必须在数据帧中指定目标MAC地址才能正常通信,因此计算机A 必须先广播“ARP请求(ARP Request)信息”,来尝试获取计算机B的MAC地址。 交换机1收到广播帧(ARP请求)后,会将它转发给除接收端口外的其他所有端口,也就是Flooding了。接 着,交换机2收到广播帧后也会Flooding。交换机3、4、5也还会Flooding。最终ARP请求会被转发到同一网 络中的所有客户机上。 交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值