找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 4535|回复: 0

[iptables] [转帖]iptables的状态检测机制

[复制链接]
发表于 2009-1-31 21:40:04 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

×
  1.什么是状态检测
  
  每个网络连接包括以下信息:源地址、目的地址、源端口和目的端口,叫作套接字对(socket pairs);协议类型、连接状态(tcp协议)和超时时间等。防火墙把这些信息叫作状态(stateful),能够检测每个连接状态的防火墙叫作状态包过滤防火墙。它除了能够完成简单包过滤防火墙的包过滤工作外,还在自己的内存中维护一个跟踪连接状态的表,比简单包过滤防火墙具有更大的安全性。
  
  iptables中的状态检测功能是由state选项来实现的。对这个选项,在iptables的手册页中有以下描述:
  
  state
  
  这个模块能够跟踪分组的连接状态(即状态检测)。
  
  --state state
  
  这里,state是一个用逗号分割的列表,表示要匹配的连接状态。有效的状态选项包括:invaild,表示分组对应的连接是未知的;established,表示分组对应的连接已经进行了双向的分组传输,也就是说连接已经建立;new,表示这个分组需要发起一个连接,或者说,分组对应的连接在两个方向上都没有进行过分组传输;related,表示分组要发起一个新的连接,但是这个连接和一个现有的连接有关,例如:ftp的数据传输连接和控制连接之间就是related关系。
  
  对于本地产生分组,在prerouting或者output链中都可以对连接的状态进行跟踪。在进行状态检测之前,需要重组分组的分片。这就是为什么在iptables中不再使用ipchains的ip_always_defrag开关。
  
  udp和tcp连接的状态表由/proc/net/ip_conntrack进行维护。稍后我们再介绍它的内容。
  
  状态表能够保存的最大连接数保存在/proc/sys/net/ipv4/ip_conntrack_max中。它取决于硬件的物理内存。
  
  2.iptables的状态检测是如何工作的?
  
  2.1.iptables概述
  
  在讨论iptables状态检测之前,我们先大体看一下整个netfilter框架。如果要在两个网络接口之间转发一个分组,这个分组将以以下的顺序接收规则链的检查:
  
  prerouting链
  
  如果必要对这个分组进行目的网络地址转换(dnat)和mangle处理。同时,iptables的状态检测机制将重组分组,并且以以下某种方式跟踪其状态:
  
  分组是否匹配状态表中的一个已经实现(established)的连接。
  
  它是否是和状态表中某个udp/tcp连接相关(related)的一个icmp分组。
  
  这个分组是否要发起一个新(new)的连接。
  
  如果分组和任何连接无关,就被认为是无效(invalid)的。
  
  forward链
  
  把分组的状态和过滤表中的规则进行匹配,如果分组与所有的规则都无法匹配,就使用默认的策略进行处理。
  
  postrouting链
  
  如果有必要,就对分组进行源网络地址转换(snat),
  
  注意:所有的分组都必须和过滤表的规则进行比较。如果你修改了规则,要拒绝所有的网络流量,那么即使分组的状态匹配状态表中的一个established条目,也将被拒绝。
  
  下面,我们对udp、tcp和icmp三个协议分别进行分析。
  
  2.2.udp连接
  
  udp(用户数据包协议)是一种无状态协议,以为这个协议没有序列号。不过,这并不意味着我们不能跟踪udp连接。虽然没有序列号,但是我们还可以使用其它的一些信息跟踪udp连接的状态。下面是状态表中关于udp连接的条目:
  
  udp 17 19 src=192.168.1.2 dst=192.168.1.50 sport=1032 dport=53 [unreplied] src=192.168.1.50 dst=192.168.1.2 sport=53 dport=1032 use=1
  
  这个状态表项只有在iptables过滤规则允许建立新的连接时,才能建立。以下的规则可以产生这类状态表项,这两条规则只允许向外的udp连接:
  
  iptables -a input -p udp -m state --state established -j accept
  iptables -a output -p udp -m state --state new,established -j accept
  
  
  上面的状态表项包含如下信息:
  
  
  连接的协议是udp(ip协议号17)。
  
  
  这个状态表项还有19秒中就超时。
  
  
  发起连接方向上的源、目的地址和源、目的端口。
  
  
  应答方向上的源、目的地址和源、目的端口。这个连接使用unreplied标记,表示还没有收到应答。
  
  
  udp连接的超时时间在/usr/src/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c文件中设置,如果改变了这个值,需要重新编译linux内核源代码才能生效。下面是udp连接超时时间的相关的源代码:
  
  
  #define udp_timeout (30*hz)
  #define udp_stream_timeout (180*hz)
  
  一个udp请求等待应答的时间是30*hz(这个值一般是30秒)。在上面的例子中,等待的时间已经消耗了11秒,还剩余19秒,如果在这段时间之内没有收到应答分组,这个表项就会被删除。一旦收到了应答,这个值就被重置为30,unreplied标志也被删除。这个表项编程如下形式:
  
  udp 17 28 src=192.168.1.2 dst=192.168.1.50 sport=1032 dport=53 src=192.168.1.50 dst=192.168.1.2 sport=53 dport=1032 use=1
  
  如果在这一对源、目的地址和源、目的端口上,发生了多个请求和应答,这个表项就作为一个数据流表项,它的超时时间是180秒。这种情况下,这个表项就变成如下形式:
  
  udp 17 177 src=192.168.1.2 dst=192.168.1.50 sport=1032 dport=53 src=192.168.1.50 dst=192.168.1.2 sport=53 dport=1032 [assured] use=1
  
  这时我们看到这个表项使用assured标志。一旦连接表项使用assured标志,那么即使在网络负沉重的情况下,也不会被丢弃。如果状态表已经饱和,当新的连接到达时,使用unreplied标志的表项会受被丢弃。
  
  2.3.tcp连接
  
  一个tcp连接是通过三次握手的方式完成的。首先,客户程序发出一个同步请求(发出一个syn分组);接着,服务器端回应一个syn|ack分组;最后返回一个ack分组,连接完成。整个过程如下所示:
  
  client server
  
  syn --->
  <--- syn+ack
  ack --->
  <--- ack
  ack --->
  .........
  .........
  
  syn和ack是由tcp分组头的标志决定的。在每个tcp分组头还有32位的序列号和应答号用于跟踪会话。
  
  为了跟踪一个tcp连接的状态,你需要使用下面这样的规则:
  
  iptables -a input -p tcp -m state --state established -j accept
  iptables -a output -p tcp -m state --state new,established -j accept
  
  2.3.1.连接建立过程中状态表的变化
  
  下面,我们详细讨论在连接建立的每个阶段中,状态表发生的变化:
  
  一旦一个初始syn分组进入output链,并且输出规则允许这个分组建立一个新的连接,状态表的相关表项将如下所示:
  
  cp 6 119 syn_sent src=140.208.5.62 dst=207.46.230.218 sport=1311 dport=80 [unreplied] src=207.46.230.218 dst=140.208.5.62 sport=80 dport=1311 use=1
  
  其中,tcp连接状态是syn_sent,连接被标记为unreplied。
  
  现在,我们等待syn+ack分组的响应。一旦得到响应,这个tcp连接表项就变为:
  
  tcp 6 57 syn_recv src=140.208.5.62 dst=207.46.230.218 sport=1311 dport=80 src=207.46.230.218 dst=140.208.5.62 sport=80 dport=1311 use=1
  
  连接的状态变为syn_recv,unreplied标志被清除。
  
  现在我们需要等待完成握手的ack分组。ack分组到达后,我们首先对其序列号进行一些检查,如果正确,就把这个连接的状态变为established,并且使用assured标记这个连接。这时,这个连接的状态如下所示:
  
  cp 6 431995 established src=140.208.5.62 dst=207.46.230.218 sport=1311 dport=80 src=207.46.230.218 dst=140.208.5.62 sport=80 dport=1311 [assured] use=1
  
  2.3.2.透视状态表
  
  上面,我们涉及了很多cp连接的状态。现在,我们分析一下tcp连接的状态检测。实际上,状态表只知道new、established、related和invalid。
  
  要注意:状态检测的状态不等于tcp状态。当一个syn分组的响应syn+ack分组到达,netfilter的状态检测模块就会认为连接已经建立。但是,这时还没有完成三次握手,因此tcp连接还没有建立。
  
  另外,包过滤规则不能删除状态表中的表项,只有连接超时,对应的状态表项才会被删除。ack分组能够建立一个new状态表项。向防火墙之后一台并不存在主机发送ack分组,并不会返回rst分组,可以证明这个结论。因此,你需要使用以下的规则明确新的tcp连接应该是syn分组建立的:
  
  iptables -a input -p tcp !--syn -m state --state new -j drop
  
  这样可以阻止空会话的继续进行。
  
  2.3.3.超时
  
  所谓状态表项的超时值是指每个表项存在的最大时间,这些超时值的大小在/usr/src/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c文件中设置。以下是相关的代码:
  
  static unsigned long tcp_timeouts[]
  = { 30 mins, /* tcp_conntrack_none, */
  5 days, /* tcp_conntrack_established, */
  2 mins, /* tcp_conntrack_syn_sent, */
  60 secs, /* tcp_conntrack_syn_recv, */
  2 mins, /* tcp_conntrack_fin_wait, */
  2 mins, /* tcp_conntrack_time_wait, */
  10 secs, /* tcp_conntrack_close, */
  60 secs, /* tcp_conntrack
本贴来自天极网群乐社区--http://q.yesky.com/group/review-17640958.html
routeros
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|手机版|小黑屋|软路由 ( 渝ICP备15001194号-1|渝公网安备 50011602500124号 )

GMT+8, 2024-3-28 16:56 , Processed in 0.057638 second(s), 5 queries , Gzip On, Redis On.

Powered by Discuz! X3.5 Licensed

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表