WEB开发网
开发学院操作系统Linux/Unix Linux实现基于Loopback的NVI(NAT Virtual Interfa... 阅读

Linux实现基于Loopback的NVI(NAT Virtual Interface)

 2013-10-04 13:48:57 来源:WEB开发网   
核心提示:知道了问题所在以及解决方案,现在就可以动手了,Linux实现基于Loopback的NVI(NAT Virtual Interface)(2),本文的目标是实现一个类似Cisco NVI的东西,也就是一个虚拟网卡,RAW表:-A PREROUTING -i lo -j MARK --set-xmark 100说明:从lo
知道了问题所在以及解决方案,现在就可以动手了。本文的目标是实现一个类似Cisco NVI的东西,也就是一个虚拟网卡,在虚拟网卡的发送流程中实现NAT。鉴于有loopback这么好的现成的东西,我也就不再写虚拟网卡了,直接用loopback模拟一个也好。大体流程如下:
数据包从物理网卡进入->执行DNAT->路由到loopback->执行SNAT->loopback口发出->策略路由->物理网卡发出
可以看到,路由执行了两次,第一次是为了NAT,第二次是真正的路由。
除了使用loopback,编写一个类似veth的虚拟网卡是一个更不错的选择:
Veth stands for Virtual ETHernet. It is a simple tunnel driver that works at the link layer and looks like a pair of ethernet devices interconnected
with each other.
比loopback好的是,这基本可以不修改代码实现NVI,并且可以很容易取到数据包原始的进入接口。该驱动的逻辑非常简单,即一个pair中包含一个主接口和一个辅助接口,数据包从主接口进入被路由到该主接口的辅助接口,注意,不改变skb的接收接口,这个所谓的路由只是为了搞一次“从物理网卡接收到发送到某另一个网卡的动作”,此时PREROUTING/POSTROUTING都已经完成了,真正的路由之后就可以从另一个主接口发出了。
这次先不急着自己写虚拟网卡,先折腾完loopback再说,那么现在动手吧!
1.对代码的修改:
重新封装RAW表的NF_INET_PRE_ROUTING钩子函数,在ipt_hook的调用前调用下面的逻辑:

//判断有点太鲁莽,正常应该可以设计成一个匹配算法的
if (skb->dev->flags & IFF_LOOPBACK && skb->nfct) {
    skb->nfct = &nf_conntrack_untracked.ct_general;
    skb->nfctinfo = IP_CT_NEW;
    nf_conntrack_get(skb->nfct);
    skb_dst_drop(skb);
    return NF_ACCEPT;
} 

这段代码的意思是说,如果是数据包从物理网卡进入,显然是需要匹配和应用规则(比如NAT)的,如果这件事做完了,数据也就是要通过路由导入loopback接口了,此时就不要再使用conntrack了,然而此时skb的nfct可能已经被设置了,于是将其NOTRACK,并且将skb的路由缓存丢弃。Linux的IP路由是这么对待loopback的,如果路由查询的结果出口是loopback接口,就是直接设置dst,loopback的xmit将数据包发出,调用一个netif_rx重新接收,到达ip_rcv_finish的时候,由于已经有了dst,就不必再查询路由了。但是如果这样的话,我们的第二次路由查询-实际上是策略路由的查询将无法实现,因此必须drop掉原有的dst。
2.配置IP地址和Netfilter策略
IP地址:
3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
link/ether 00:0c:29:90:66:c5 brd ff:ff:ff:ff:ff:ff
inet 192.168.2.249/24 brd 192.168.2.255 scope global eth2
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:90:66:cf brd ff:ff:ff:ff:ff:ff
inet 192.168.40.249/24 scope global eth2
说明:暂用两块网卡,eth1连接内部,eth2连接外部

NAT表:
-A POSTROUTING -j SNAT -i eth1 --to-source 192.168.40.249
说明:将所有的发起于内部的数据包源IP都转换成本机的IP地址。
RAW表:
-A PREROUTING -i lo -j MARK --set-xmark 100
说明:从lo口进入,说明第一次路由查询导致的NAT已经完成,打上MARK让后续的路由逻辑将其识别为第二次真正的路由查询。


策略:

0: from all lookup local

Tags:Linux 实现 基于

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接