如何建立网站快捷方式,做网站建设还有钱赚吗,微信网站案例,wordpress 附件 函数Articles (gitee.io)
IPtables-朱双印博客 (zsythink.net)
在 Netfilter 是如何工作的(五) 中连接跟踪信息使用的创建-确认机制的 Netfilter在报文进入系统的入口处#xff0c;将连接跟踪信息记录在报文上#xff0c;在出口进行confirm.确认后的连接信息 本文以一个本机上送…Articles (gitee.io)
IPtables-朱双印博客 (zsythink.net)
在 Netfilter 是如何工作的(五) 中连接跟踪信息使用的创建-确认机制的 Netfilter在报文进入系统的入口处将连接跟踪信息记录在报文上在出口进行confirm.确认后的连接信息 本文以一个本机上送过程中的TCP/IPv4的SYN握手报文为例详细分析连接跟踪机制的工作流程。
入口 出口 由于是本机上送流程因此SYN报文的入口是 PRE_ROUTING而出口则是 LOCAL_IN。Netfilter 在初始化时会在这两个 HOOK 点注册连接跟踪相关的处理函数。
static struct nf_hook_ops ipv4_conntrack_ops[] {{.hook ipv4_conntrack_in, // 入口回调函数.pf NFPROTO_IPV4,.hooknum NF_INET_PRE_ROUTING, // PRE_ROUTING HOOK 点.priority NF_IP_PRI_CONNTRACK, // 优先级},......{.hook ipv4_confirm, // 出口的回调函数.pf NFPROTO_IPV4,.hooknum NF_INET_LOCAL_IN, // LOCAL_IN HOOK 点 .priority NF_IP_PRI_CONNTRACK_CONFIRM, // 优先级},
}入口
SYN 报文进入连接跟踪的入口是 ipv4_conntrack_in()然后调用nf_conntrack_in, 后面这个函数较长因此我们这里分段来看
ipv4_conntrack_in||-- nf_conntrack_innf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, struct sk_buff *skb)
{// ......if (skb-nfct) {/* Previously seen (loopback or untracked)? Ignore. */tmpl (struct nf_conn *)skb-nfct;if (!nf_ct_is_template(tmpl)) {NF_CT_STAT_INC_ATOMIC(net, ignore);return NF_ACCEPT;}skb-nfct NULL;}// ......
}首先是检查 skb 上是否已经关联了连接跟踪信息。这里不是入口吗为什么 skb 上会由连接跟踪信息 ?! 注释写了如果这个包是从 loopback 口收到的话这时它就有可能已经关联的链接跟踪信息了这时就会把已关联的连接跟踪信息作为模板(tmpl)。而在我们的情境中SYN 报文从外部网卡收到所以显然这里 skb 是不会有连接跟踪信息的。
接着往下看 l3proto __nf_ct_l3proto_find(pf);ret l3proto-get_l4proto(skb, skb_network_offset(skb),dataoff, protonum);l4proto __nf_ct_l4proto_find(pf, protonum); 这一段代码片段完成了两件事
将协议族 pf 转换得到 L3 协议对应的函数操作集(operations)在我们的例子中入参pf AF_INET也就是 IP 协议因此这里会得到l3proto nf_conntrack_l3proto_ipv4进一步解析报文 L4 对应的协议号这里会调用ipv4_get_l4proto在我们的例子中会得到 TCP 对应的协议号protonum 6进而得到l4proto nf_conntrack_l4proto_tcp4
接下来就是入口函数的核心流程resolve_normal_ct(), 正常情况下这个函数会返回连接跟踪信息的指针ct和简要信息ctinfo并将它们分别设置到skb-nfcf和skb-ctinfo struct nf_conn *ct;enum ip_conntrack_info ctinfo;int set_reply 0;ct resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,l3proto, l4proto, set_reply, ctinfo);下面将 resolve_normal_ct 展开
第一步调用nf_ct_get_tuple, 将报文的五元组信息填充到struct nf_conntrack_tuple结构的变量中
static inline struct nf_conn *
resolve_normal_ct(struct net *net, struct nf_conn *tmpl,struct sk_buff *skb,unsigned int dataoff,u_int16_t l3num,u_int8_t protonum,struct nf_conntrack_l3proto *l3proto,struct nf_conntrack_l4proto *l4proto,int *set_reply,enum ip_conntrack_info *ctinfo)
{ const struct nf_conntrack_zone *zone;struct nf_conntrack_tuple tuple;struct nf_conntrack_tuple_hash *h;// tuple 是出参, 对tcp来说是 tcp_pkt_to_tuple, 只是填了dport和sportif (!nf_ct_get_tuple(skb, skb_network_offset(skb),dataoff, l3num, protonum, net, tuple, l3proto,l4proto)) {pr_debug(resolve_normal_ct: Cant get tuple\n);return NULL;}// ......
}第二步计算tuple的哈希值然后根据此哈希值查找连接跟踪信息表中是否已存在这个哈希值的记录将其值赋予h ......zone nf_ct_zone_tmpl(tmpl, skb, tmp);hash hash_conntrack_raw(tuple); // 计算hashh __nf_conntrack_find_get(net, zone, tuple, hash); // 查找该tuple的元组信息是否已经存在在我们的例子中假设原本没有这样的记录于是这里会使用init_conntrack创建一条新的连接跟踪信息 if (!h) {h init_conntrack(net, tmpl, tuple, l3proto, l4proto,skb, dataoff, hash);最后将连接跟踪信息设置到报文skb上。特别注意这里只会将连接信息保存在skb上并不会将这条信息插入到连接跟踪信息表中插入到表中这是出口 confirm 阶段的工作。 ct nf_ct_tuplehash_to_ctrack(h);......} else {......} else {pr_debug(nf_conntrack_in: new packet for %p\n, ct);*ctinfo IP_CT_NEW;}*set_reply 0;}skb-nfct ct-ct_general;skb-nfctinfo *ctinfo;出口
出口处Netfilter 将连接跟踪信息设置到报文 skb 上这样在出口的地方就可以将其取出再插入到连接信息的哈希表中完成确认
ipv4_confirm||-- nf_conntrack_confirm||-- __nf_conntrack_confirm/* Confirm a connection given skb; places it in hash table */
int
__nf_conntrack_confirm(struct sk_buff *skb)
{struct nf_conn *ct;enum ip_conntrack_info ctinfo;// ......ct nf_ct_get(skb, ctinfo);// ......__nf_conntrack_hash_insert(ct, hash, reply_hash);// ......return NF_ACCEPT;
}