实现一个做双向NAT的虚拟网卡
问题描写叙述与解决方式
还是老问题。Linux系统中通过iptables配置的NAT无法在双向通信环境中使用,你无法配置一条NAT规则实现对两个方向主动发起的流量做NAT,解决问题的方案有好几种:
1.配置两条NAT规则
iptables的NAT配置本身就是先match再运行一个target,因此一条规则仅仅能表示一种转换策略,要想实现“来自x的数据包的源地址转换为y,去往y的数据包的目标地址转为x”这种逻辑,必须使用两条规则。那么为何不使用两条规则呢?由于iptables的nat配置是基于数据流的,它仅仅对一个创建ip_conntrack结构体的那个数据包进行规则查找。因此在一个流已经创建并在传输数据的时候。加入一条nat配置是无效的。
xtables-addons中有一个RAWNAT,不再基于ip_conntrack了,也就是它是基于数据包而不是数据流的NAT。即时生效问题攻克了,可是由于它还是一个match-target规则,因此要想实现双向的NAT,还是要配置两条规则。
2.编写一个Netfilter HOOK
编写一个Netfilter HOOK模块不是什么难事,我自己写过好几个,可是,Netfilter框架是在协议栈的处理路径上拦截数据包进行检查-匹配/动作的。它对每个经过协议栈的数据包都要进行检查,也就是说每个数据包都要经过HOOK函数的过滤。在Netfilter HOOK过多的时候,大大减少了效率。
3.使用专门的虚拟设备
这是一种全新的理念。实现一个虚拟网卡,其xmit函数是这种:
- static netdev_tx_t sdnat_net_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct sdnat_struct *sdnat = netdev_priv(dev);
- unsigned int flags = sdnat->flags;
- struct nat_entry *entry;
- entry = find_sdnat_policy(skb, flags);
- if (unlikely(!entry)) {
- goto xmit;
- }
- if (flags & SNAT) {
- do_trans_src(entry, skb);
- } else if (flags & DNAT) {
- do_trans_dst(entry, skb);
- }
- // 此时skb的dst为将数据包导入NAT设备的dst_entry,
- // 为了防止循环路由,将其drop,NAT已经完毕。已经没实用了
- skb_dst_drop(skb);
- // 清除mark,由于一般通过mark策略路由将数据包导入NAT设备
- // 这也是为了防止循环路由
- skb->mark = 0;
- xmit:
- netif_rx_ni(skb);
- drop:
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
do_trans_src/dst全然能够通过一个函数实现,此处是为了使接口更加清晰。详细的转换就不多说了,非常easy,改动掉IP报头的源地址或者目标地址,然后又一次计算L3,L4的校验码。
关键是怎样组织nat规则。
我使用一个nat_entry来保存每一条规则:
- struct nat_entry {
- struct hlist_node hash_list;
- __be32 key1; //对于SNAT即原始IP地址。对于DNAT即要转换到的IP地址
- __be32 key2; //对于SNAT即要转换到的IP地址,对于DNAT即原始IP地址
- __be32 hash; /数据包源IP或者目标IP的jhash_2words值
- int flags;
- };
hash的计算例如以下:
- static u32 keys_get_hash(__be32 key)
- {
- return jhash_2words(key, 0x01, 0x0);
- }
模块载入的时候,会创建两个虚拟网卡。一个负责SNAT。一个负责DNAT,同一时候系统中也会有两个sdnat_struct结构体,一个负责SNAT,一个负责DNAT:
- struct sdnat_struct {
- int flags;
- struct net_device *dev;
- struct hlist_head entrys[1024];
- };
Linux上要配置就是两条策略路由:
a.从内网口进入往外发的数据包导入到SNAT网卡设备进行SANT;
b.从外网口进入到内网口的数据包导入到DNAT网卡设备进行DNAT。
这样就能够双向自己主动转换了。无论数据是从哪个首先发起的。实现了“来自x的数据包的源地址转换为y,去往y的数据包的目标地址转为x”。是不是和Cisco的static NAT有些相似呢?定义出入设备而不是靠iptables的match来过滤数据包。
我比較喜欢使用procfs作为用户接口,由于它方便shell操作:
echo +192.168.1.1 9.24.100.1 >/proc/net/nat
上面的命令运行后,将会在两块网卡共享的hash表中加入一个nat_entry,key1为192.168.1.1。key2为9.24.100.1。在SNAT网卡设备中,将会用skb的iph->saddr做hash后查表匹配其key1,取出key2作为要转换的IP地址,在DNAT网卡设备中,将会用skb的iph->daddr做hash后查表匹配key2,取出key1作为要转换到的IP地址。
假设想删除一条规则,那么就运行:
echo -192.168.1.1 9.24.100.1 >/proc/net/nat
策略路由规则例如以下:
ip rule add iif $内网口 table snat
ip rule add iif $外网口 table dnat
ip route add 0.0.0.0/0 dev snat0 table snat
ip route add 0.0.0.0/0 dev dnat0 table dnat
依靠路由来做是否要进行NAT的推断,是不是更加高效些呢?而不再须要通过Netfilter模块去匹配每个数据包了。也不须要折腾低效率的ip_conntrack了。值得注意的是,sdnat设备的xmit函数终于运行了一个netif_rx_ni这相当于将数据包又一次注入其本身,此时数据包的iif将不再是内网口或者外网口了,而是实实在在的sdant虚拟网卡设备,因此数据包再次到达路由模块的时候将不会再次进入sdnat设备。
引申出来的思想和含义
除了Netfilter框架之外,我们也能够使用Linux的网卡设备模型来构建还有一套数据包过滤系统。是的。其思想就是上面展示的。
我以前写过几篇关于在路由项中保存信息。然后通过查路由表的方式获取信息的技巧。当中使用了自定义的“路由表”。查询方式依旧是最长前缀匹配法,仅仅是路由项中保存的东西变了。在本文中,我给出的是使用Linux原生的路由表(不是自定义的)+自定义的虚拟网卡设备实现数据包过滤的思想,依照这种思想,iptables的每个target就是一个虚拟网卡设备,每一系列的matches就是一条路由。该路由的路由项就是将数据包导入相应的虚拟网卡设备,路由的方式来匹配数据包将比Netfilter的方式高效,由于它使用了hash/trie这类高效的数据结构。而不是像Netfilter那样遍历好几层的链表。
其实,这种思想非常新吗?不!
路由项不是有unreachable或者blackhole吗?它们不正是iptables的REJECT和DROP么?
实现一个做双向NAT的虚拟网卡的更多相关文章
- tunctl和虚拟网卡
1 tun/tap驱动 1.1 网卡驱动 同tcp/ip协议栈打交道,接受和发送数据包 1.2 字符驱动 内核和用户态通过字符设备交换数据包. 2 tun虚拟网卡的创建 tunctl -t tun0 ...
- 转【Ubuntu】添加虚拟网卡的三种方式
原文:https://blog.csdn.net/White_Idiot/article/details/82934338 ------------------------------ 1. ifco ...
- Linux添加虚拟网卡的多种方法
Linux添加虚拟网卡的多种方法有时候,一台服务器需要设置多个ip,但又不想添加多块网卡,那就需要设置虚拟网卡.这里介绍几种方式在linux服务器上添加虚拟网卡. 我们向eth0中添加一块虚拟网卡: ...
- 【转】Linux添加虚拟网卡
转自:https://blog.csdn.net/hzhsan/article/details/44677867 有时候,一台服务器需要设置多个ip,但又不想添加多块网卡,那就需要设置虚拟网卡.这里介 ...
- CentOS设置虚拟网卡做NAT方式和Bridge方式桥接
CentOS设置虚拟网卡做NAT方式和Bridge方式桥接 http://www.centoscn.com/CentOS/config/2015/0225/4736.html 摘要:KVM虚拟机网络配 ...
- 通过桥接虚拟网卡使VMWare和宿主机实现双向通讯
0.为什么选择虚拟网卡和桥接模式 首先虚拟机网络设置为NAT,虚拟机实现上网是很方便的,但是宿主机访问虚拟机就比较麻烦了(需要单独配置端口转发),桥接就能很好的解决这个问题,桥接模式会把虚拟机当做宿主 ...
- 【强烈推荐】利用NAT、Host-Only双虚拟网卡,实现Virtual Box中CentOS6.3联网
问题背景: 先前都是在Virtual Box中以“网络共享”方式,让里面的Linux虚拟机Host-Only方式联网,参考如下: Virtual Box下配置Host-Only联网方式详解 但最近被公 ...
- 【荐】利用NAT、Host-Only双虚拟网卡,实现Virtual Box中CentOS5.x联网
一.虚拟机与主机互联,通常有三种方式,详细介绍请看: VMware虚拟机三种网络模式(Bridged,Nat,Host-only)区别详解 二.通过网络共享,Host-Only联网,详细案例请看: W ...
- 虚拟机Linux与本地虚拟网卡配置---NAT链接方式
虚拟机Linux与本地虚拟网卡配置---NAT链接方式 **********这是我亲自尝试多次实践出来的结果,不是复制粘贴************************* 首先进行初始化,这样避免有 ...
随机推荐
- python安装完毕后,提示找不到ssl模块的解决方示
python安装完毕后,提示找不到ssl模块: [root@localhost ~]# python2.7.5 Python 2.7.5 (default, Jun 3 2013, 11:08:43) ...
- mac系统奔溃无法启动时,如何备份重要资料
虽然说苹果系统以稳定性获得高度好评,但是作为一名程序员,还是要考虑到系统奔溃的情况. 当遇到系统奔溃,无法启动,而我们还没有备份电脑里面的重要资料,这时候不用着急.可以用下面的 方法来拯救你的苹果电脑 ...
- H264源码分析(二)
原文出自http://blog.csdn.net/xfding/article/details/5476763(转载收集) (四)图像参数集语义 pic_parameter_set_rbsp( ) { ...
- java整合easyui进行的增删改操作
首先发一下效果图 显示全部用户信息 加入用户信息 删除用户信息 编辑用户信息 以下就来介绍一下easyui的crud,在java中是怎么与后台进行交换的 前台html页面,我将它命名为crud1.ht ...
- 从一个非开发人员转行silverlight满一年的工作总结(第一次发帖)
自2013年3月进入公司到现在已整整一年.这一年,让我从一个大学毕业就去参军并且专业还不对口的大学生步入了软件开发这个高门槛行业.说实话,我真的很庆幸,庆幸遇到了两位赏识自己的领导从很多专业对口.能力 ...
- (一)使用Fragment实现QQ的底部按钮
版权声明:本文出自郭霖的博客,转载必须注明出处. 转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/13171191 现在Fragmen ...
- L10 数据入站、转发、出站流程
二 写出防火墙规则链之间的顺序也就是入站数据流向.转发数据流向.出站数据流向的过程 入站:PREROUTING→INPUT 数据包到达防火墙,由prerouting处理,判断是否修改地址 路由选择:判 ...
- linux常用命令详解 (一) 安装和登录命令
Linux必学的60个命令 Linux提供了大量的命令,利用它可以有效地完成大量的工 作,如磁盘操作.文件存 Linux提供了大量的命令,利用它可以有效地完成大量的工作,如磁盘操作.文件存取. ...
- 学习ios设计(1)
两年前,苹果为现代的使用者完全改变了设计语言.对于设计者来说,这使得他们更容易关注动画和功能而不是其他的细枝末节. 我已经被问过很多次怎样开始设计或者是有什么捷径可以成为更好的设计师.虽然没有银弹,然 ...
- javascript 手机号抽奖
案例 ---- 手机号抽奖 开始抽奖 停止 *具体的备注在代 ...