对连接跟踪的INVALID状态的深入理解
用户态的连接跟踪中的几种状态
连接跟踪系统中定义了一个连接可能处于以下几种状态:
- NEW:一个连接的初始状态(例如:TCP连接中,一个SYN包的到来),或者防火墙只收到一个方向的流量(例如:防火墙在没有收到回复包之前)。
- ESTABLISHED:连接已经建立完成,换句话说防火墙已经看到了这条连接的双向通信。
- RELATED:这是一个关联连接,是一个主链接的子连接,例如ftp的数据通道的连接。
- INVALID:这是一个特殊的状态,用于记录那些没有按照预期行为进行的连接(比如LVS的DR,TUNNEL模式的非第一个syn报文就是INVALID的,INVALID并不一定会丢报文,不设定规则是不会丢弃这种报文的)。系统管理员可以定义一个iptables规则来记录和丢弃这种数据包。就像前面说的连接跟踪不会过滤数据包,但是他提供了一种方法来过滤。
在内核中如何对应这些状态呢?
内核中的几种状态
/* Connection state tracking for netfilter. This is separated from,
but required by, the NAT layer; it can also be used by an iptables
extension. */
enum ip_conntrack_info {
/* Part of an established connection (either direction). */
IP_CT_ESTABLISHED,//对应用户态的ESTABLISHED的请求方向
/* Like NEW, but related to an existing connection, or ICMP error
(in either direction). */
IP_CT_RELATED,//对应用户态的RELATED的请求方向
/* Started a new connection to track (only
IP_CT_DIR_ORIGINAL); may be a retransmission. */
IP_CT_NEW,//对应用户态的NEW
/* >= this indicates reply direction */
IP_CT_IS_REPLY,//等价于IP_CT_ESTABLISHED_REPLY,这就是为什么将IP_CT_ESTABLISHED设置为0的原因了
IP_CT_ESTABLISHED_REPLY = IP_CT_ESTABLISHED + IP_CT_IS_REPLY,//对应用户态的ESTABLISHED的应答方向
IP_CT_RELATED_REPLY = IP_CT_RELATED + IP_CT_IS_REPLY,//对应于用户态的RELATED的应答方向
/* No NEW in reply direction. */
/* Number of distinct IP_CT types. */
IP_CT_NUMBER,
/* only for userspace compatibility */
#ifndef __KERNEL__
IP_CT_NEW_REPLY = IP_CT_NUMBER,
#else
IP_CT_UNTRACKED = 7,//没有进行连接跟踪,用户态可以通过设置规则让报文不进行连接跟踪
#endif
};
从上面的对比可以看出,用户态的INVALID状态在内核中没有对应的描述,那么那个状态表示INVALID状态了,我们可以看一下”state“match的执行函数
static bool
state_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_state_info *sinfo = par->matchinfo;
enum ip_conntrack_info ctinfo;
unsigned int statebit;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
if (ct)
statebit = XT_STATE_BIT(ctinfo);
else if (ctinfo == IP_CT_UNTRACKED)
statebit = XT_STATE_UNTRACKED;
else
statebit = XT_STATE_INVALID;
return (sinfo->statemask & statebit);
}
/* Return conntrack_info and tuple hash for given skb. */
static inline struct nf_conn *
nf_ct_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
{
*ctinfo = skb->_nfct & NFCT_INFOMASK;
return (struct nf_conn *)(skb->_nfct & NFCT_PTRMASK);
}
//skb->_nfct的定义为:unsigned long _nfct;
//在连接跟踪中的作用有两个,LSB三个bit用来表示连接跟踪的状态,即枚举ip_conntrack_info中的值,剩下的bit用来
//表示其对应的ct的地址,通过强制类型转换得到。这是因为在分配内存时ct的地址是按照8字节对齐的(这是通过slab分配器中
//的SLAB_HWCACHE_ALIGN标志实现的),所以lsb三个bit永远为0,kernel刚好使用该特性来表示状态。
从这个函数可以看出,当报文不存在ct,并且其状态不为IP_CT_UNTRACKED时,即认为其状态为XT_STATE_INVALID。
配置样例
配置设备只接受ssh流量(INPOUT节点默认策略配置成DROP)
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p tcp --dport 22 -m state --state NEW -j ACCEPT
如果配置成:
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
这种配置不仅会接收正常的ssh请求报文,也会接收INVALID状态的报文。