在模块加载时构造SYN包并发送到本机
Hi 大大们,在下初学 Netfilter 遇到一个问题,麻烦大家帮帮忙,在此先谢谢了~有一台客户端机器为 Win7 系统,服务器为 RHEL-6.2 x86_64 系统,现在在服务器上编写了一个内核模块,并在加载时向服务器上层发送 SYN 包,源地址、端口为客户端地址 172.30.40.26:1234, 目标地址为服务器地址 172.30.40.90:80,
并且在服务器上已开启 80 端口。我的代码如下,在客户端上使用 Wireshark 抓包,测试结果:
1. 调用 dev_queue_xmit(skb) 时能在客户端抓到抓,由于目标地址不为客户端,所以客户端无响应;
2. 调用 dst_input(skb) 时,在客户端不能抓到来自服务端响应的 SYN_ACK;
3. 调用 netif_rx(skb) 与第 2 点测试情况相同;
skb 中加入 MAC 头或不加,测试结果相同。
请各位高手帮忙一下,看看代码哪里有问题?非常谢谢~
int SendTcpPacket(__be32 sip, __be16 sport, __be32 dip, __be16 dport, __be32 seq, __u8 syn, __u8 fin, __u8 rst, __u8 ack, __be32 seq_ack)
{
struct dst_entry* dest = NULL;
struct sk_buff *skb;
struct tcphdr* tcph;
struct iphdr *iph;
struct ethhdr *ethh;
int ip_payload_size;
int result;
unsigned char mac_source = {0xC0, 0x3F, 0xD5, 0x71, 0x97, 0xA5};
unsigned char mac_dest = {0x00, 0x0C, 0x29, 0x51, 0x97, 0xA7};
skb = alloc_skb(MAX_TCP_HEADER + 128, GFP_ATOMIC|__GFP_ZERO);
if (skb == NULL)
{
printk(KERN_ALERT"Failed to alloc_skb\n");
return -1;
}
skb_reserve(skb, MAX_TCP_HEADER);
// TCP header
tcph = (struct tcphdr *)skb_push(skb, sizeof(struct tcphdr));
tcph->source= sport;
tcph->dest = dport;
tcph->doff = (sizeof(struct tcphdr) >> 2);
tcph->seq = seq;
tcph->syn = syn;
tcph->fin = fin;
tcph->rst = rst;
tcph->ack = ack;
tcph->ack_seq = seq_ack;
tcph->window = htons(0xFFFF);
skb_reset_transport_header(skb);
// IP Header
iph = (struct iphdr *)skb_push(skb, sizeof(struct iphdr));
iph->ihl = (sizeof(struct iphdr) >> 2);
iph->version= 4;
iph->tot_len= htons(skb->len);
iph->ttl = 64;
iph->protocol = IPPROTO_TCP;
iph->saddr = sip;
iph->daddr = dip;
ip_send_check(iph);
skb_reset_network_header(skb);
// MAC header
ethh = (struct ethhdr *)skb_push(skb, sizeof(struct ethhdr));
memcpy(ethh->h_source, mac_source, ETH_ALEN);
memcpy(ethh->h_dest, mac_dest, ETH_ALEN);
ethh->h_proto = __constant_htons(ETH_P_IP);
skb_reset_mac_header(skb);
ip_payload_size = skb->len - sizeof(struct ethhdr) - sizeof(struct iphdr);
skb->csum = skb_checksum(skb, sizeof(struct ethhdr) + sizeof(struct iphdr), ip_payload_size, 0);
tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, ip_payload_size, iph->protocol, skb->csum);
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->pkt_type = PACKET_HOST;
if (0 != get_dest(sip, &dest))
{
printk(KERN_ALERT"Failed to get_dest\n");
return -1;
}
skb->dev = dest->dev;
skb_dst_set(skb, dest);
result = dev_queue_xmit(skb);
// result = dst_input(skb);
// result = dst_output(skb);
// result = netif_rx(skb);
if (result != NET_RX_SUCCESS)
{
kfree_skb(skb);
printk(KERN_ALERT"Failed to send packet. ErrCode=%d\n", result);
}
else
{
printk(KERN_ALERT"Send packet succeeded from %pI4:%d to %pI4:%d\n", &sip, ntohs(sport), &dip, ntohs(dport));
}
return 0;
} 回复 1# 世事皆虚幻
你在服务器上构造 SYN 包,然后发给上层,那还要让走 dev_queue_xmit() 啊?
回复 2# Godbach
谢谢关注,我是调了一下这个函数测试一下在客户端抓包,Wireshark 分析出计算的 checksum 是正确的,先保证一下构造的 sk_buff 内容是正确的。 回复 2# Godbach
麻烦版主帮忙看看,谢谢~ 回复 3# 世事皆虚幻
你构造包到底发给谁,发给 server 的话,为什么还要走 dev_queue_xmit ?
回复 5# Godbach
多谢版主回复,我是要在服务器中运行内核模块,发送给本机。其实我是想调用 dst_input(skb) 函数,理论上发送到上层后,服务器会向源地址回应 SYN_ACK, 但是我在客户端上抓不到包。 回复 1# 世事皆虚幻
1. 调用 dev_queue_xmit(skb) 时能在客户端抓到抓,由于目标地址不为客户端,所以客户端无响应;
你构造的 SYN 包源 IP 是 client 的 IP 吗。
不太清楚你写这个程序,要是做什么的。就算是构造包,用的环境感觉也有些非常规。
回复 7# Godbach
多谢回复。我是这个需求,有二台服务器,实现主备,当主服务器宕机时,将客户端的 TCP 连接转移至备机。
目前在主备上部署 heartbeat 模块,实现宕机后的 IP 漂移。在这二台服务器上,运行着二个相同的内核模块,有客户端连接时,主服务器会将连接信息通过 UDP 同步至备机,一旦主机挂掉,备机会切为主机,备机会与上层发送 SYN 报文,并拦截上层的 SYN_ACK, 回复 ACK 后 NF_DROP 掉,这样的话,便可以保证该 TCP 连接相对于客户端来说是未断开的。
目前阻塞在备机向上层发送 SYN 报文这儿,SYN 报文里填写的源地址是客户端的 IP。 回复 8# 世事皆虚幻
你发 syn 包的话,相当于初始连接。而大多时候,主机 down 掉了,现有的了连接要是在备机上维持,要保证 seq/ack 等信息都一样的。
回复 9# Godbach
这个没问题,主机上客户端的发送序号和服务端的发送序号都同步过去了,在我的模块中都会转换。
现在我的问题是,构造出一个 SYN 报文的 skb, 用 dst_input() 函数发给上层没反应,不知哪儿出问题了。
页:
[1]
2