从Linux内核发送自定义skbuff时,查找以太网头的下一跳MAC地址

时间:2016-09-15 10:02:18

标签: c linux networking kernel ethernet

我在Linux内核中构建自己的TCP数据包,方法是填充skbuff数据结构并通过dev_queue_xmit发送出去。通过WAN进行通信。

但是,我完全在堆栈中找到正确的目标MAC地址并在内核中组装以太网头。 为了测试我当前的实现,我硬编码了下一跳MAC,我能够建立通信。

如何通过了解目标IP在内核中正确组装以太网头?我想尽可能避免使用原始内核套接字来执行发送操作。

如果你能指出一些例子,我将不胜感激。

谢谢!

修改

这是我创建skbuff的初始代码

static struct sk_buff* construct_tcp_skb(struct net_device *dev, char * usr_data, uint16_t usr_data_len) {

    unsigned char srcmac[] = {0x03, 0x00, 0xa0, 0x4f, 0xa4, 0x02};
    unsigned char dstmac[] = {0x03, 0x00, 0xa0, 0x30, 0xba, 0x12};

    struct ethhdr *ethh;
    struct iphdr *iph;
    struct tcphdr * tcph;
    struct sk_buff *skb;

    unsigned char * p_usr_data;
    int err = 0;
    int tcplen = 0;    

    uint16_t header_len = 300;
    skb = alloc_skb(1000, GFP_KERNEL);
    skb_reserve(skb, header_len);

    tcph = (struct tcphdr*) skb_push(skb, sizeof(struct tcphdr));
    iph = (struct iphdr*) skb_push(skb, sizeof(struct iphdr));
    ethh = (struct ethhdr*) skb_push(skb, sizeof(struct ethhdr));

    memcpy(ethh->h_source, srcmac, 6);
    memcpy(ethh->h_dest, dstmac, 6);
    ethh->h_proto = htons(ETH_P_IP);    

    iph->ihl = 5;
    iph->version = 4;
    iph->ttl = 32;
    iph->tos = 0;
    iph->protocol = IPPROTO_TCP;    
    iph->saddr = my_inet_addr("192.168.0.2");
    iph->daddr = my_inet_addr("192.168.0.1");

    iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
    iph->check = 0;
    iph->id = 12345;
    iph->frag_off = 0;
    iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr) + usr_data_len );
    ip_send_check(iph);

    tcph->source = htons(12457); 
    tcph->dest = htons(5200);   
    tcph->seq = htonl(100000);
    tcph->ack_seq = htonl(100000);
    tcph->doff = 5;  
    tcph->fin=0;
    tcph->syn=0;
    tcph->rst=0;
    tcph->psh=0;
    tcph->ack=1;
    tcph->urg=0;
    tcph->window = htons (5840);
    tcph->check = 0; 
    tcph->urg_ptr = 0;

    skb->pkt_type = PACKET_OUTGOING;

    p_usr_data = skb_put(skb, usr_data_len);    
    skb->csum = csum_and_copy_from_user(p_usr_data, usr_data, usr_data_len, 0, &err);

    tcph->check = 0;
    tcplen = sizeof(struct tcphdr) + usr_data_len;
    tcph->check = tcp_v4_check(tcplen,
                               iph->saddr, iph->daddr,
                               csum_partial((char *)tcph, tcplen, 0));

    skb->protocol = IPPROTO_TCP;
    skb->dev = dev;
    skb->pkt_type = PACKET_HOST;
    skb->priority = 0;

    return skb;
}

虽然您可以看到src / dst IP和src MAC是硬编码的,但我知道如何获取这些值。但是,我遇到的问题是将dstmac设置为dst IP的下一跳MAC。

你可以假设ARP表已经包含了关于目的地的必要信息,因此我想避免制作我自己的ARP然后自己解码它们。此外,这个函数(在我的代码示例中)预计会运行多次,因此我不想重复发送ARP,而是从内核以某种方式读取现有的ARP缓存。

0 个答案:

没有答案