Bootstrap

iptables实现网卡包转发

mips小板上有两个网卡eth0、eth1,现在要实现的是将eth0接收到的数据从eth1中转发出去。

 

iptables -t nat -A PREROUTING -i eth0 -p tcp -m tcp -s ! 10.0.0.1 -d 12.0.0.1 --dport 21 -j DNAT --to-destination 10.0.0.2:8888
iptables -t nat -A POSTROUTING -o eth0 -p tcp -m tcp -d 10.0.0.2 --dport 8888 -j SNAT --to-source 12.0.0.1
或者
iptables -t nat -A POSTROUTING -o eth0 -p tcp -m tcp -d 10.0.0.2 --dport 8888 -j MASQUERADE
IP_FORWARD已经打开

这两条规则链转发没有问题
但是问题是  来源地址的IP被  POSTROUTING链给修改为了 12.0.0.1
有没有什么办法可以 让IPTABLES只做包转发   不改变 数据包的来源地址。
有哪位知道的话 告诉一下
谢谢!

-------------[   ip 18.0.10.1      ]-------------------[ 12.0.0.1:21]
                                                                          |
                                                                          |
                                                                          |
                                                                  [   10.0.0.1:8888  ]
描述 。IP180.0.10.1访问  12.0.0.1:21端口
          12.0.0.1把来自21端口的访问 重定向道公网的  10.0.0.1:8888
          10.0.0.1:8888看到的来源地址  需要时   18.0.10.1 而不是  12.0.0.1

 

 设我们有一台计算机,有两块网卡,eth0连外网,ip为1.2.3.4;eth1连内网,ip为192.168.0.1.现在需要把发往地址1.2.3.4的81端口的ip包转发到ip地址192.168.0.2的8180端口,设置如下:

  1. iptables -t nat -A PREROUTING -d 1.2.3.4 -p tcp -m tcp --dport 81 -j DNAT --to-destination192.168.0.2:8180

  2. iptables -t nat -A POSTROUTING -s 192.168.0.0/255.255.0.0 -d 192.168.0.2 -p tcp -m tcp --dport 8180 -j SNAT --to-source 192.168.0.1

  真实的传输过程如下所示:

  假设某客户机的ip地址为6.7.8.9,它使用本机的1080端口连接1.2.3.4的81端口,发出的ip包源地址为6.7.8.9,源端口为1080,目的地址为1.2.3.4,目的端口为81.

  主机1.2.3.4接收到这个包后,根据nat表的第一条规则,将该ip包的目的地址更该为192.168.0.2,目的端口更该为8180。同时在连接跟踪表中创建一个条目,(可从/proc/net/ip_conntrack文件中看到),然后发送到路由模块,通过查路由表,确定该ip包应发送到eth1接口。在向eth1接口发送该ip包之前,根据nat表的第二条规则,如果该ip包来自同一子网,则将该ip包的源地址更该为192.168.0.1,同时更新该连接跟踪表中的相应条目,然后送0接口发出.

  此时连接跟踪表中有一项:

  连接进入: src=6.7.8.9 dst=1.2.3.4 sport=1080 dport=81

  连接返回: src=192.168.0.2 dst=6.7.8.9 sport=8180 dport=1080

  是否使用: use=1

  而从192.168.0.2发回的ip包,源端口为8180,目的地址为6.7.8.9,目的端口为1080,主机1.2.3.4的TCP/IP栈接收到该ip包后,由核心查找连接跟踪表中的连接返回栏目中是否有同样源和目的地址和端口的匹配项,找到后,根据条目中的记录将ip包的源地址由192.168.0.2更该为1.2.3.4, 源端口由8180更该为81,保持目的端口号1080不变.这样服务器的返回包就可以正确的返回发起连接的客户机,通讯就这样开始.

  还有一点, 在filter表中还应该允许从eth0连接192.168.0.2地址的8180端口:

  iptables -A INPUT -d 192.168.0.2 -p tcp -m tcp --dport 8180 -i eth0 -j ACCEPT

 

 

什么是Iptables? 

iptables 是建立在 netfilter 架构基础上的一个包过滤管理工具,最主要的作用是用来做防火墙或透明代理。Iptables 从 ipchains 发展而来,它的功能更为强大。Iptables 提供以下三种功能:包过滤、NAT(网络地址转换)和通用的 pre-route packet mangling。

包过滤:用来过滤包,但是不修改包的内容。Iptables 在包过滤方面相对于 ipchians 的主要优点是速度更快,使用更方便。

NAT:NAT 可以分为源地址 NAT 和目的地址 NAT。 

Iptables 可以追加、插入或删除包过滤规则。实际上真正执行这些过虑规则的是 netfilter 及其相关模块(如 iptables 模块和 nat 模块)。

Netfilter 是 Linux 核心中一个通用架构,它提供了一系列的 “表”(tables),每个表由若干 “链”(chains)组成,而每条链中可以有一条或数条 “规则”(rule)组成。 

iptables 可以操纵3 个表:filter 表,nat 表,mangle 表。 
NAT 和一般的 mangle 用 -t 参数指定要操作哪个表。filter 是默认的表,如果没有 -t 参数,就默认对 filter 表操作。
 “filter”表中包含了 INPUT、FORWARD 和 OUTPUT 3 个链。 

每一条链中可以有一条或数条规则,每一条规则都是这样定义的:如果数据包头符合这样的条件,就这样处理这个数据包。当一个数据包到达一个链时,系统就会从第一条规则开始检查,看是否符合该规则所定义的条件: 如果满足,系统将根据该条规则所定义的方法处理该数据包;如果不满足则继续检查下一条规则。最后,如果该数据包不符合该链中任一条规则的话,系统就会根据该链预先定义的策略来处理该数据包。 


 


规则:

Rule 规则:过滤规则,端口转发规则等,例如:禁止任何机器 ping 我们的服务器,可以在服务器上设置一条规则: 

iptables -A INPUT -s ! 127.0.0.1 -p icmp -j DROP 

从 –s 开始即是一条规则,-j 前面是规则的条件,-j 开始是规则的行为(目的)。整条命令解释为,在filter 表中的 INPUT 规则链中插入一条规则,所有源地址不为 127.0.0.1 的 icmp 包都被抛弃。 
(下面的一些例子可以此例子为参考)


Chain (规则链):由一系列规则组成,每个包顺序经过 chain 中的每一条规则。chain 又分为系统 chain和用户创建的 chain。下面先叙述系统 链。 

filter 表的系统 链: INPUT,FORWARD,OUTPUT 

nat 表的系统 链: PREROUTING,POSTROUTING,OUTPUT 

mangle 表的系统 链: PREROUTING,OUTPUT 

每条系统 chain 在确定的位置被检查。比如在包过滤中,所有的目的地址为本地的包,则会进入INPUT 规则链,而从本地出去的包会进入 OUTPUT 规则链。 

所有的表(table) 和 链(chain) 开机时都为空,设置 iptables 的方法就是在合适的 table 和系统 chain 中添相应的规则。 



iptables:

表:   iptables从其使用的三个表(filter、nat、mangle)而得名, 对包过滤只使用 filter 表, filter还是默认表,无需显示说4明. 

操作命令: 即添加、删除、更新等。 

链:  对于包过滤可以针对filter表中的INPUT、OUTPUT、FORWARD链,也可以操作用户自定义的链。 

规则匹配器: 可以指定各种规则匹配,如IP地址、端口、包类型等。 

目标动作: 当规则匹配一个包时,真正要执行的任务,常用的有: 

ACCEPT 允许包通过 

DROP 丢弃包



一些扩展的目标还有: 

REJECT 拒绝包,丢弃包同时给发送者发送没有接受的通知 

LOG 包有关信息记录到日志 

TOS 改写包的TOS值 




为使FORWARD规则能够生效,可使用下面2种方法的某种: 

[root@rhlinux root]# vi /proc/sys/net/ipv4/ip_forward 
[root@rhlinux root]# echo "1" > /proc/sys/net/ipv4/ip_forward 

[root@rhlinux root]# vi /etc/sysconfig/network 
[root@rhlinux root]# echo "FORWARD_IPV4=true" > /etc/sysconfig/network

 




iptables语法可以简化为下面的形式: 

iptables [-t table] CMD [chain] [rule-matcher] [-j target] 

CMD  常用操作命令: 

-A 或 -append 在所选链尾加入一条或多条规则


-D 或 -delete 在所选链尾部删除一条或者多条规则 

-R 或 -replace 在所选链中替换一条匹配规则 

-I 或 -insert 以给出的规则号在所选链中插入一条或者多条规则. 如果规则号为1,即在链头部. 

-L 或 -list 列出指定链中的所有规则,如果没有指定链,将列出链中的所有规则. 

-F 或 -flush 清除指定链和表中的所由规则, 假如不指定链,那么所有链都将被清空. 

-N 或 -new-chain 以指定名创建一条新的用户自定义链,不能与已有链名相同. 

-X 或 -delete-chain 删除指定的用户定义帘,必需保证链中的规则都不在使用时才能删除,若没有指定链,则删除所有用户链. 

-P 或 -policy 为永久帘指定默认规则(内置链策略),用户定义帘没有缺省规则,缺省规则也使规则链中的最后一条规则,用-L显示时它在第一行显示. 

-C 或 -check 检查给定的包是否与指定链的规则相匹配. 

-Z 或 -zero 将指定帘中所由的规则包字节(BYTE)计数器清零. 

-h 显示帮助信息. 

matcher  常用匹配规则器: 

-p , [!] protocol 指出要匹配的协议,可以是tcp, udp, icmp, all, 前缀!为逻辑非,表示除该协议外的所有协议. 

-s [!] address[/mask] 指定源地址或者地址范围. 

-sport [!] port[:port] 指定源端口号或范围,可以用端口号也可以用/ETC/SERVICES文件中的名子. 

-d [!] address[/mask] 指定目的地址或者地址范围. 

-dport [!] port[:port] 指定目的端口号或范围,可以用端口号也可以用/ETC/SERVICES文件中的名子. 

-icmp-type [!] typename 指定匹配规则的ICMP信息类型(可以使用 iptables -p icmp -h 查看有效的ICMP类型名) 

-i [!] interface name[+] 匹配单独或某种类型的接口,此参数忽略时,默认符合所有接口,接口可以使用"!"来匹配捕食指定接口来的包.参数interface是接口名,如 eth0, eht1, ppp0等,指定一个目前不存在的接口是完全合法的,规则直到接口工作时才起作用,折中指定对于PPP等类似连接是非常有用的."+"表示匹配所有此类型接口.该选项只针对于INPUT,FORWARD和PREROUTING链是合法的. 

-o [!] interface name[+] 匹配规则的对外网络接口,该选项只针对于OUTPUT,FORWARD,POSTROUTING链是合法的. 

[!] --syn 仅仅匹配设置了SYN位, 清除了ACK, FIN位的TCP包. 这些包表示请求初始化的TCP连接.阻止从接口来的这样的包将会阻止外来的TCP连接请求.但输出的TCP连接请求将不受影响.这个参数仅仅当协议类型设置为了TCP才能使用. 此参数可以使用"!"标志匹配已存在的返回包,一般用于限制网络流量,即只允许已有的,向外发送的连接所返回的包. 

 -m module_name 使用扩展模块来进行数据包的匹配。如:

        -m tcp 的意思是使用 tcp 扩展模块的功能 (tcp扩展模块提供了 --dport, --tcp-flags, --sync等功能).

 


-j target :

 ACCEPT target

这个target没有任何选项和参数,使用也很简单,指定-j ACCEPT即可。一旦包满足了指定的匹配条件,就会被ACCEPT,并且不会再去匹配当前链中的其他规则或同一个表内的其他规则,但它还要通过其他表中的链,而且在那儿可能会百DROP也说不准哦

 

DNAT target

这个target是用来做目的网络地址转换的,就是重写包的目的IP地址。如果一个包被匹配了,那么和它属于同一个流的所有的包都会被自动转换,然后就可以被路由到正确的主机或网络。DNAT target是非常有用的。

比如,你的Web服务器在LAN内部,而且没有可在Internet上使用的真实IP地址,那就可以使用这个 target让防火墙把所有到它自己HTTP端口的包转发给LAN内部真正的Web服务器。目的地址也可以是一个范围,这样的话,DNAT会为每一个流随机分配一个地址。因此,我们可以用这个target做某种类型地负载平衡。

注意,DANT target只能用在nat表的PREROUTING和OUTPUT链中,或者是被这两条链调用的链里。但还要注意的是,包含DANT target的链不能被除此之外的其他链调用,如POSTROUTING。

例:

Option

--to-destination

Example

iptables -t nat -A PREROUTING -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10

解释

指定要写入IP头的地址,这也是包要被转发到的地方。上面的例子就是把所有发往地址15.45.23.67的包都转发到一段LAN使用的私有地址中,即192.168.1.1到 192.168.1.10。如前所述,在这种情况下,每个流都会被随机分配一个要转发到的地址,但同一个流总是使用同一个地址。我们也可以只指定一个IP地址作为参数,这样所有的包都被转发到同一台机子。我们还可以在地址后指定一个或一个范围的端口。比如:--to-destination 192.168.1.1:80或 --to-destination 192.168.1.1:80-100。SNAT的语法和这个target的一样,只是目的不同罢了。要注意,只有先用--protocol指定了TCP或 UDP协议,才能使用端口。

因为DNAT要做很多工作,所以我要再罗嗦一点。我们通过一个例子来大致理解一下它是如何工作的。比如,我想通过Internet连接发布我们的网站,但是HTTP server在我们的内网里,而且我们对外只有一个合法的IP,就是防火墙那个对外的IP——$INET_IP。防火墙还有一个内网的IP——$LAN_IP,HTTP server的IP是$HTTP_IP (这当然是内网的了)。为了完成我们的设想,要做的第一件事就是把下面的这个简单的规则加入到nat表的PREROUTING链中:

iptables -t nat -A PREROUTING --dst $INET_IP -p tcp --dport 80 -j DNAT \ --to-destination $HTTP_IP

现在,所有从Internet来的、到防火墙的80端口去的包都会被转发(或称做被DNAT )到在内网的HTTP服务器上。如果你在Internet上试验一下,一切正常吧。再从内网里试验一下,完全不能用吧。这其实是路由的问题。下面我们来好好分析这个问题。为了容易阅读,我们把在外网上访问我们服务器的那台机子的IP地址记为$EXT_BOX。

 

DROP target

顾名思义,如果包符合条件,这个target就会把它丢掉,也就是说包的生命到此结束,不会再向前走一步,效果就是包被阻塞了。在某些情况下,这个target会引起意外的结果,因为它不会向发送者返回任何信息,也不会向路由器返回信息,这就可能会使连接的另一方的sockets因苦等回音而亡:) 解决这个问题的较好的办法是使用REJECT target,(译者注:因为它在丢弃包的同时还会向发送者返回一个错误信息,这样另一方就能正常结束),尤其是在阻止端口扫描工具获得更多的信息时,可以隐蔽被过滤掉的端口等等(译者注:因为扫描工具扫描一个端口时,如果没有返回信息,一般会认为端口未打开或被防火墙等设备过滤掉了)。还要注意如果包在子链中被DROP了,那么它在主链里也不会再继续前进,不管是在当前的表还是在其他表里。总之,包死翘翘了。


 



如何制定永久规则集: 

/etc/sysconfig/iptables 文件是 iptables 守护进程调用的默认规则集文件. 

可以使用以下命令保存执行过的IPTABLES命令: 

/sbin/iptables-save > /etc/sysconfig/iptables 

要恢复原来的规则库,可以使用: 

/sbin/iptables-restore < /etc/sysconfig/iptables 

iptables命令和route等命令一样,重启之后就会恢复,所以: 

[root@rhlinux root]# service iptables save 
将当前规则储存到 /etc/sysconfig/iptables: [ 确定 ] 

令一种方法是 /etc/rc.d/init.d/iptables 是IPTABLES的启动脚本,所以: 

[root@rhlinux root]# /etc/rc.d/init.d/iptables save 
将当前规则储存到 /etc/sysconfig/iptables: [ 确定 ] 

以上几种方法只使用某种即可. 

若要自定义脚本,可直接使用iptables命令编写一个规则脚本,并在启动时执行: 

例如若规则使用脚本文件名/etc/fw/rule, 则可以在/etc/rc.d/rc.local中加入以下代码: 

if [-x /etc/fw/rule]; then /etc/fw/sule; fi; 

这样每次启动都执行该规则脚本,如果用这种方法,建议NTSYSV中停止IPTABLES. 

;