humengez 发表于 2014-03-19 16:03

关于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进行抓包却抓到了由网关发来的加密后的报文。
恳请各位大大帮小弟解答下这是什么原因,感激不尽

lonelyair 发表于 2014-03-19 16:20

1、代码不完整吧,
if(strcmp(dstIP,"")!=0&&strcmp(dstIP,"0.0.0.0")!=0)
dstIP在哪里?
2、用wireshark能抓到包,那看看IP、端口是不是与UDPserver一致

humengez 发表于 2014-03-19 16:37

dstIP是挂载模块之后在用户态由另一个函数传递给内核,wireshark抓包看了port、ip这些都是没问题的回复 2# lonelyair


   

lonelyair 发表于 2014-03-19 16:52

主机已经能收到包,说明你修改包没问题啊。
确认UDPserver没问题?

humengez 发表于 2014-03-19 16:53

udpserver应该没问题,因为在加载模块前udpserver是可以print出client发送的信息的回复 4# lonelyair


   

Godbach 发表于 2014-03-19 17:08

回复 5# humengez

你的代码里面还有 TCP 的相关代码,测试中用的是只是 UDP 吗,IP 校验和计算是否正确
   

humengez 发表于 2014-03-19 17:13

目前是只测了udp,ip校验和也应该没问题,一是我没有动ip报头里的东西,二是wireshark抓到的包里ipchecksum也是correct回复 6# Godbach


   

lonelyair 发表于 2014-03-19 17:21

LZ能否多公开点的源码信息啊,靠猜可不靠谱啊

humengez 发表于 2014-03-19 17:24

本帖最后由 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目前用不到,是准备以后进一步开发用的
   

humengez 发表于 2014-03-19 17:45

我现在在udpserver上的LOCAL_IN点放了一个监听模块,确定包的发送和接受是都没问题的,修改过的数据包已经到了LOCAL_IN点,问题是他为什么没传给上层的应用。。。。
页: [1] 2 3
查看完整版本: 关于netfilter修改数据包的问题