这个问题纠结了一个星期,现在可以用了。以下是自己在调试过程中一个杂记。新手一个,不合适的地方欢迎大家来喷
1,生成一个新包,注意事项直接baidu skb函数
我使用的是alloc_skb,当然也可以用skb_copy_expand等,看个人需求了。
2,对新生成的包进行自组内容,
就四个部分,二层,三层,四层,和数据内容。不考虑分片。直接skb_share_info一个结构全部0。
组包时需要注意,最好能用内核提供的接口就用接口,不要自己想着写一个或是干什么,这些数据在以后发包的时候要做一些查询和验证,如果自己写到时候就傻了。
我的一段代码
skb_t = alloc_skb(pkt_len, GFP_ATOMIC);//pkt_len是报文总长度
if( skb_t == NULL)
{
goto truncation_drop;
}
dev = dev_get_by_name(&init_net, "br-lan");
// dev = dev_get_by_name(&init_net, "eth0.2");
if (NULL == dev)
{
return FAIL;
}
DEBUG(" get dev name %s\n",dev->name);
skb_t->dev = dev;
dev_hold(skb_t->dev);
skb_t->pkt_type = PACKET_HOST;
skb_t->protocol = __constant_htons(ETH_P_IP);
skb_t->ip_summed = CHECKSUM_NONE;
skb_t->priority = 0;
skb_t->mac_len = eth_hdr_len;
skb_reserve(skb_t, eth_hdr_len + ipv4_hdr_len + tcp_hdr_len);
//Ïòβ²¿À©Õ¹data room
skb_put(skb_t, data_len);
memcpy(skb_t->data, (void *)data_hdr_t, (s32)data_len);
skb_push(skb_t, tcp_hdr_len);
memcpy(skb_t->data, (void *)tcp_hdr_t, (s32)tcp_hdr_len);
skb_reset_transport_header(skb_t);
skb_push(skb_t, ipv4_hdr_len);
memcpy(skb_t->data, (void *)ipv4_hdr_t, (s32)ipv4_hdr_len);
skb_reset_network_header(skb_t);
skb_push(skb_t, eth_hdr_len);
memcpy(skb_t->data, (void *)eth_hdr_t, (s32)eth_hdr_len);
skb_reset_mac_header(skb_t);
skb_t->data = skb_t->data + eth_hdr_len;
3,对dev_queue_xmit 和 ip_route_input , dst_output 的个人理解
dev_queue_xmit调用这个函数这前需要完成对skb->dev结构的赋值,它直接会把skb挂到相应接口的发送队列等待发送了。
ip_route_input , dst_output ,使用这两个函数就是和走linux 内核的转发差不多,先查下路由,得到rt->dst 和相应dev结构,再去查二层。之后挂到发送队列。目前我用的是这个。对于不同版本的内核,接口函数的参数也不一定一样,所以没有一个统一的东西。上网找也没找到,我的发送函数
static u32 skb_send_to_route(struct sk_buff *skb, struct iphdr *iph, struct tcphdr *tcphdr)
{
struct rtable *rt = NULL;
//struct iphdr *iph = (struct iphdr *)skb->network_header;
struct flowi4 fl4;
int err;
//struct tcphdr *tcphdr = (struct tcphdr *)skb->transport_header;
fl4.daddr = iph->daddr;
//fl4.saddr = iph->saddr;,//这个不要是因为查路由的时候会去验证一些东西,量后就直接所回查找失败,后正我用不到直接不管了。
fl4.flowi4_tos = RT_TOS(iph->tos);
fl4.flowi4_oif = skb->dev->ifindex;
err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
iph->tos, skb->dev);
if (unlikely(err)) {
DEBUG("ip route input fail\n\n");
return FAIL;
}
//看查成功没有,
rt = skb_rtable(skb);
if (IS_ERR(rt))
{
DEBUG("rt is error\n\n");
kfree_skb(skb);
return FAIL;
}
err = dst_output(skb);
DEBUG(" return NF_STOLEN ret = %d!\n\n",err);
return OK;
}