我在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缓存。