关于netfilter修改数据包的问题
最近在做一个加密网关的项目,网关采用linux系统,要在网关上对经过网关的数据进行加密以及解密工作,下面是写的一个简单的修改数据包的代码static unsigned int send(unsigned int hooknum, struct sk_buff * skb,const struct net_device * in, const struct net_device * out,
int (*okfn)(struct sk_buff *))
{
struct iphdr* iph;
struct udphdr* udph;
struct tcphdr* tcph;
unsigned char *data = NULL;
int datalen;
int ret = 0;
__u16 dst_port,src_port;
__be32 myip;
if(skb)
{
iph = (struct iphdr *)skb_header_pointer(skb,0,0,NULL);
if(iph)
{
if(strcmp(dstIP,"")!=0&&strcmp(dstIP,"0.0.0.0")!=0)
{
myip = in_aton(dstIP);
if(iph->daddr == myip)
{
if(iph->protocol == IPPROTO_UDP)
{
udph = (struct udphdr *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
data = (char *)skb_header_pointer(nskb,TOT_HDR_LEN,0,NULL);
datalen = ntohs(iph->tot_len)-TOT_HDR_LEN;
}
else if(iph->protocol == IPPROTO_TCP)
{
tcph = (struct tcphdr *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
int offlen = IP_HDR_LEN + tcph->doff*4;
data = (char *)skb_header_pointer(skb,offlen,0,NULL);
datalen = ntohs (iph->tot_len)-offlen;
}
int j;
for(j=0; j<datalen; j++)
{
data += 1;
}
printk("encrypted\n");
iph->check = 0;
ip_send_check(iph);
}
}
}
}
return NF_ACCEPT;
}hook点放在POST_ROUTING处,pri为last。同时还写了简单的udpclient与udpserver作为测试。
现在问题是,当udpclient运行在linux网关上时,udpserver可以收到加密后的报文。但是,当udpclient运行在linux网关后的内网时,udpserver收不到加密后的报文,而在udpserver运行的pc上用wireshark进行抓包却抓到了由网关发来的加密后的报文。
恳请各位大大帮小弟解答下这是什么原因,感激不尽 1、代码不完整吧,
if(strcmp(dstIP,"")!=0&&strcmp(dstIP,"0.0.0.0")!=0)
dstIP在哪里?
2、用wireshark能抓到包,那看看IP、端口是不是与UDPserver一致 dstIP是挂载模块之后在用户态由另一个函数传递给内核,wireshark抓包看了port、ip这些都是没问题的回复 2# lonelyair
主机已经能收到包,说明你修改包没问题啊。
确认UDPserver没问题? udpserver应该没问题,因为在加载模块前udpserver是可以print出client发送的信息的回复 4# lonelyair
回复 5# humengez
你的代码里面还有 TCP 的相关代码,测试中用的是只是 UDP 吗,IP 校验和计算是否正确
目前是只测了udp,ip校验和也应该没问题,一是我没有动ip报头里的东西,二是wireshark抓到的包里ipchecksum也是correct回复 6# Godbach
LZ能否多公开点的源码信息啊,靠猜可不靠谱啊 本帖最后由 humengez 于 2014-03-19 17:25 编辑
回复 8# lonelyair #define NIPQUAD(addr)\
((unsigned char *)&addr),\
((unsigned char *)&addr),\
((unsigned char *)&addr),\
((unsigned char *)&addr)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netfilter.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/inet.h>
#include <linux/string.h>
#include <net/tcp.h>
#include <net/udp.h>
#include <net/icmp.h>
#include <linux/netfilter_ipv4.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("who");
#define IP_HDR_LEN 20
#define UDP_HDR_LEN 8
#define TOT_HDR_LEN 28
#define ADDRLEN 16
static char dstIP = {0};
#define SOCKET_OPT_BASE 128
#define SOCKET_OPT_SETTARGET (SOCKET_OPT_BASE)
#define SOCKET_OPT_GETTARGET (SOCKET_OPT_BASE)
#define SOCKET_OPT_MAX (SOCKET_OPT_BASE+1)
static struct nf_hook_ops send_ops;
static struct nf_hook_ops rcv_ops;
struct rtphdr
{
__u8 cc:4;
__u8 x:1;
__u8 p:1;
__u8 v:2;
__u8 pt:7;
__u8 m:1;
__u16 seq;
__u16 ts;
__u32 ssrc;
__u32 csrc;
};
static int recv_cmd(struct sock *sk,int cmd, void __user *user,unsigned int len)
{
int ret = 0;
if(cmd == SOCKET_OPT_SETTARGET)
{
memset(dstIP,0,ADDRLEN);
ret = copy_from_user(dstIP,user,len);
if(ret != 0)
{
printk("error: can not copy data from userspace\n");
return -1;
}
printk("The target IP from User: %s \n",dstIP);
}
return ret;
}
static int send_cmd(struct sock *sk,int cmd, void __user *user,int *len)
{
int ret = 0;
if(cmd == SOCKET_OPT_GETTARGET)
{
if(0!=(ret = copy_to_user(user,dstIP,ADDRLEN)))
{
printk("error: can not copy data to userspace\n");
return -1;
}
printk("The target IP to User: %s \n",dstIP);
}
return ret;
}
static struct nf_sockopt_ops my_sockops = {
.pf = PF_INET,
.set_optmin = SOCKET_OPT_SETTARGET,
.set_optmax = SOCKET_OPT_MAX,
.set = recv_cmd,
.get_optmin = SOCKET_OPT_GETTARGET,
.get_optmax = SOCKET_OPT_MAX,
.get = send_cmd
};
static int index = 1;
static unsigned int send(unsigned int hooknum, struct sk_buff * skb,
const struct net_device * in, const struct net_device * out,
int (*okfn)(struct sk_buff *))
{
struct iphdr* iph;
struct udphdr* udph;
struct tcphdr* tcph;
unsigned char *data = NULL;
int datalen;
int ret = 0;
__u16 dst_port,src_port;
__be32 myip;
if(skb)
{
iph = (struct iphdr *)skb_header_pointer(skb,0,0,NULL);
if(iph)
{
if(strcmp(dstIP,"")!=0&&strcmp(dstIP,"0.0.0.0")!=0)
{
myip = in_aton(dstIP);
if(iph->daddr == myip)
{
if(iph->protocol == IPPROTO_UDP)
{
udph = (struct udphdr *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
data = (char *)skb_header_pointer(nskb,TOT_HDR_LEN,0,NULL);
datalen = ntohs(iph->tot_len)-TOT_HDR_LEN;
}
else if(iph->protocol == IPPROTO_TCP)
{
tcph = (struct tcphdr *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
int offlen = IP_HDR_LEN + tcph->doff*4;
data = (char *)skb_header_pointer(skb,offlen,0,NULL);
datalen = ntohs (iph->tot_len)-offlen;
}
int j;
for(j=0; j<datalen; j++)
{
data += 1;
}
printk("encrypted\n");
iph->check = 0;
ip_send_check(iph);
}
}
}
}
return NF_ACCEPT;
}
static unsigned int rcv(unsigned int hooknum, struct sk_buff * skb,
const struct net_device * in, const struct net_device * out,
int (*okfn)(struct sk_buff *))
{
struct iphdr* iph;
struct udphdr* udph;
struct tcphdr* tcph;
unsigned char *data = NULL;
int datalen;
struct rtphdr * rtph;
int ret = 0;
__u16 dst_port,src_port;
__be32 myip;
if(skb)
{
iph = (struct iphdr *)skb_header_pointer(skb,0,0,NULL);
if(iph)
{
if(strcmp(dstIP,"")!=0&&strcmp(dstIP,"0.0.0.0")!=0)
{
myip = in_aton(dstIP);
if(iph->saddr == myip)
{
if(iph->protocol == IPPROTO_UDP)
{
udph = (struct udphdr *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
data = (char *)skb_header_pointer(skb,TOT_HDR_LEN,0,NULL);
datalen = ntohs(iph->tot_len)-TOT_HDR_LEN;
}
else if(iph->protocol == IPPROTO_TCP)
{
tcph = (struct tcphdr *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
int offlen = IP_HDR_LEN + tcph->doff*4;
data = (char *)skb_header_pointer(skb,offlen,0,NULL);
datalen = ntohs (iph->tot_len)-offlen;
}
int m;
for(m = 0; m<datalen; m++)
{
data -=1;
}
printk("discpered\n");
iph->check = 0;
ip_send_check(iph);
}
}
}
}
return NF_ACCEPT;
}
static int __init init(void)
{
send_ops.hook = send;
send_ops.hooknum = NF_INET_POST_ROUTING;
send_ops.pf = PF_INET;
send_ops.priority = NF_IP_PRI_LAST;
rcv_ops.hook = rcv;
rcv_ops.hooknum = NF_INET_POST_ROUTING;
rcv_ops.pf = PF_INET;
rcv_ops.priority = NF_IP_PRI_FIRST;
nf_register_sockopt(&my_sockops);
nf_register_hook(&send_ops);
nf_register_hook(&rcv_ops);
}
static void __exit fini(void)
{
nf_unregister_hook(&send_ops);
nf_unregister_hook(&rcv_ops);
nf_unregister_hook(&my_sockops);
printk("%s\n", "remove modify skb module.");
}
module_init(init);
module_exit(fini);
这是全部代码,rtphdr目前用不到,是准备以后进一步开发用的
我现在在udpserver上的LOCAL_IN点放了一个监听模块,确定包的发送和接受是都没问题的,修改过的数据包已经到了LOCAL_IN点,问题是他为什么没传给上层的应用。。。。