免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2549 | 回复: 5
打印 上一主题 下一主题

[网络子系统] netfilter ip做dnat的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-08-01 16:22 |只看该作者 |倒序浏览
我是一下系统管理员,对写代码基本是不熟悉。根据网上的例子捣鼓了一个程序,想实现一个功能:
把从192.168.1.148 发到192.168.5.148 的dns请求转发到 192.168.1.24

简单实现一个dnat+snat功能。我只是在prerouting和postrouting的位置修改了ip 地址直接发出去。

通过tcpdump抓包,发现包都转发成功了,但是用dig或者nslookup却得不到dns查询结果。很奇怪。
代码如下:
//nethook.c  
#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/netfilter.h>  
#include <linux/netfilter_ipv4.h>  
#include <linux/netdevice.h>  
#include <linux/skbuff.h>  
#include <linux/ip.h>  
#include <net/ip.h>  
#include <linux/udp.h>  
//
/* 从192.168.1.148 到 192.168.5.148:53 转到 192.168.1.20:53
   struct tcphdr *thead;
   thead = (void *) iph + iph->ihl * 4;

*/
static struct nf_hook_ops nfho,nfho2;  

__be32 gwip=0x9405A8C0;
__be32 dnsip=0x0101A8C0;
__be32 serverip=0x1801A8C0;
__be32 clientip=0x9401A8C0;

//prerouting
unsigned int hook_func(unsigned int hooknum,  
                struct sk_buff *skb,  
                const struct net_device *in,  
                struct net_device *out,  
                int (*okfn)(struct sk_buff *))  
{
        struct iphdr *iph = NULL;  
        iph = ip_hdr(skb);
        struct udphdr *udph;
        udph = (void *) iph + iph->ihl * 4;
        if (iph->protocol != IPPROTO_UDP)
        {
                return NF_ACCEPT;
        }


        if (udph->dest != 0x3500 &&udph->source != 0x3500 )
        {
                return NF_ACCEPT;
        }
        // 客户端到服务器
        // dstip: 192.168.5.148
        // dstport: 53

        printk("dnat前%pI4:%x -> %pI4:%x\t",&iph->saddr,udph->source,&iph->daddr,udph->dest);
        if(iph->saddr == clientip){
                iph->daddr = serverip;
                ip_send_check(iph);
                printk("dnat后 %pI4:%x -> %pI4:%x\n",&iph->saddr,udph->source,&iph->daddr,udph->dest);
                return NF_ACCEPT;   
        }
        // 服务器到客户端
        // dstip: 192.168.5.148
        // srcport: 53
        if(iph->saddr == serverip){
                iph->daddr = clientip;
                ip_send_check(iph);
                printk("dnat后 %pI4:%x -> %pI4:%x\n",&iph->saddr,udph->source,&iph->daddr,udph->dest);
                return NF_ACCEPT;   
        }
        printk("dnat 没修改%pI4 -> %pI4\n",&iph->saddr,&iph->daddr);
        return NF_ACCEPT;   
}  

//postrouting
unsigned int hook_func2(unsigned int hooknum,  
                struct sk_buff *skb,  
                const struct net_device *in,  
                struct net_device *out,  
                int (*okfn)(struct sk_buff *))  
{       
        struct iphdr *iph = NULL;  
        //192.168.1.20
        //192.168.1.20
        iph = ip_hdr(skb);
        if (iph->protocol != IPPROTO_UDP)
        {
                return NF_ACCEPT;
        }

        struct udphdr *udph;
        udph = (void *) iph + iph->ihl * 4;
        if (udph->dest != 0x3500 &&udph->source != 0x3500 )
        {
                return NF_ACCEPT;
        }
        if (iph->saddr == dnsip ||iph->daddr == dnsip){
                return NF_ACCEPT;
        }

        //
        printk("snat前 %pI4:%x -> %pI4:%x\t",&iph->saddr,udph->source,&iph->daddr,udph->dest);
        if(iph->saddr == clientip||iph->saddr== serverip){
                iph->saddr = gwip;
                ip_send_check(iph);
                printk("snat后 %pI4:%x -> %pI4:%x\n",&iph->saddr,udph->source,&iph->daddr,udph->dest);
                return NF_ACCEPT;   
        }
        printk("snat 没修改%pI4 -> %pI4\n",&iph->saddr,&iph->daddr);
        return NF_ACCEPT;   

}


static int __init init_nethook(void)  
{  
        nfho.hook = hook_func;   
        nfho.hooknum = NF_INET_PRE_ROUTING;       
        nfho.pf = PF_INET;  
        nfho.priority = NF_IP_PRI_FIRST;   


        nfho2.hook = hook_func2;   
        nfho2.hooknum = NF_INET_POST_ROUTING;       
        nfho2.pf = PF_INET;  
        nfho2.priority = NF_IP_PRI_FIRST;   
        nf_register_hook(&nfho);  
        nf_register_hook(&nfho2);  
        return 0;  
}  





static void __exit exit_nethook(void)  
{  
        nf_unregister_hook(&nfho);  
        nf_unregister_hook(&nfho2);  
}  

module_init(init_nethook);  
module_exit(exit_nethook);  

论坛徽章:
0
2 [报告]
发表于 2014-08-01 17:39 |只看该作者
调试了一下,转发icmp协议是没问题。成功。但是 udp不行。

论坛徽章:
0
3 [报告]
发表于 2014-08-01 21:58 |只看该作者
估计也是网络字节序的问题。     
if (udph->dest != 0x3500 &&udph->source != 0x3500 )
        {
                return NF_ACCEPT;
        }
        // 客户端到服务器
        // dstip: 192.168.5.148
        // dstport: 53
你确定你的端口是53?

论坛徽章:
0
4 [报告]
发表于 2014-08-01 22:08 |只看该作者
__be32 gwip=0x9405A8C0;
__be32 dnsip=0x0101A8C0;
__be32 serverip=0x1801A8C0;
__be32 clientip=0x9401A8C0;
你开头这么写,你怎么知道你的机器大端还是小端地址

论坛徽章:
1
摩羯座
日期:2014-05-07 11:21:33
5 [报告]
发表于 2014-08-02 09:32 |只看该作者
楼主是想发种包吧,192.168.1.148---》192.168.5.148   经过DNAT与SNAT后变为192.168.1.1 ----->192.168.1.24 ??
  iph->saddr = gwip;这句是有问题的,无法对应两个方向。gwip和dnsip也弄反了吧?
应该可以用iptables规则来实现呀

论坛徽章:
0
6 [报告]
发表于 2014-08-04 09:14 |只看该作者
恩,iptables可以实现,我主要就是做一个实验而已。

另外刚开始开发,不熟悉里面的函数,所以只用用16进制的ip地址,不知道应该用什么函数来写ip地址。

楼上提到的疑问,我用tcpdump来抓包,包都是正确转发了的,转发本身没出现问题。因为我用icmp验证过了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP