conntrack链接 tcp

2024-04-30 14:18
文章标签 tcp 链接 conntrack

本文主要是介绍conntrack链接 tcp,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、连接跟踪的预备知识

连接跟踪的概念及作用,这里都不做介绍了。下面先说一下连接跟踪在Netfilter中起效的hook点以及对应的hook函数。


/* [color=Blue]Connection tracking may drop packets, but never alters them, so
 
   make it the first hook. */
 
static struct nf_hook_ops ip_conntrack_in_ops
 
= { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_PRE_ROUTING,
 
        NF_IP_PRI_CONNTRACK };
 
static struct nf_hook_ops ip_conntrack_local_out_ops
 
= { { NULL, NULL }, ip_conntrack_local, PF_INET, NF_IP_LOCAL_OUT,
 
        NF_IP_PRI_CONNTRACK };
 
/* Refragmenter; last chance. */
 
static struct nf_hook_ops ip_conntrack_out_ops
 
= { { NULL, NULL }, ip_refrag, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_LAST };
 
static struct nf_hook_ops ip_conntrack_local_in_ops
 
= { { NULL, NULL }, ip_confirm, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_LAST-1 };[/color]


以上是连接跟踪在Netfilter中注册的hook点,对应的hook函数,以及函数调用的优先级,也可以通过图ip_conntrack_hook直观的看出来.
hook.JPG

2008-12-26 16:13 上传
下载附件 (15.55 KB)


二、链接跟踪建立的三条路径
根据上面注册的Hook点,可以总结出链接跟踪的建立有三条路径:
1. 转发的包,见图Foward.jpg

如果是新的包,在PREROUTING 处生成连接记录,通过POSTROUTING 后加到hash
foward.JPG
2008-12-26 16:11 上传
下载附件 (11.78 KB)


2. 本地接收的包, 见图localin.jpg

PREROUTING 处生成连接记录,在LOCAL_IN 处把生成的连接记录加到hash
localin.JPG
2008-12-26 16:09 上传
下载附件 (9.72 KB)


3. 本地发送的包, 见图localout.jpg

LOCAL_OUT 处生成连接记录,在POSTROUTING 处把生成的连接记录加到hash
localout.JPG
2008-12-26 16:09 上传
下载附件 (9.13 KB)


下面就按照本地发包和接收包的路径来分析连接跟踪的整个流程。

三、IP层接收和发送数据包进入连接跟踪钩子函数的入口
整个分析是基于IP层进行的。
1. IP层接收数据包的函数为:ip_rcv()ip_input.c

该函数执行到最后:
return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
ip_rcv_finish);

执行所有NF_IP_PRE_ROUTING上的钩子,仅当所有钩子函数都返回NF_ACCEPT,接着执行ip_rcv_finish。由于连接跟踪的优先级最高,所以会执行连接跟踪的钩子函数ip_conntrack_in()。

2. IP层发送数据包(TCP包)的函数为:
int ip_queue_xmit(struct sk_buff *skb) ip_output.c

该函数执行到最后:
returnNF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
ip_queue_xmit2);


执行所有NF_IP_LOCAL_OUT上的钩子,仅当所有钩子函数都返回NF_ACCEPT,接着执行ip_queue_xmit2。由于连接跟踪的优先级最高,所以先执行连接跟踪的钩子函数ip_conntrack_local(),该函数处理一下Raw Socket之后,接着调用ip_conntrack_in()进行处理

四、连接跟踪的流程分析
以下以TCP包为例,整理一下连接跟踪的建立。前面已经讲了大致的流程,这里主要分析数据包到达ip_conntrack_inip_confirm的处理,借此了解连接跟踪状态的转换。

1. TCP SYN包,c -> s.本地主机为c,远程主机为s
(1) Hook点为NF_IP_LOCAL_OUT,仍旧是最高的优先级,先进入ip_conntrack_local,然后调用ip_conntrack_in,该函数将该数据包对应的协议结构取出来,这里是TCP的协议结构。

(2) 调用resolve_normal_ct函数查找该数据包是否对应的有连接记录。该函数里首先通过skb参数获得数据包对应的tuple,通过调用ip_conntrack_find_get查找全局变量ip_conntrack_hash表中是否有该tuple
a) 有匹配的tuple,则将该返回该tuple对应的struct ip_conntrack_tuple_hash结构。

b) 如果没有匹配的,则通过init_conntrack创建一个struct ip_conntrack结构。由于我们这里是有c发送的SYN包。所以应该查不到匹配的tuple。因此要创建一个ip_conntrack. 该函数里完成了SYN对应的正向tuple和方向tuple的计算,ip_conntrack结构的初始化等等。重要的是给数组tuplehash[0]tuplehash[1]的赋值,以及对成员conntrack->infos的赋值即
conntrack->infos.master=&
conntrack->ct_general;
这样将新建的conntrack结构体的首地址保存在了 conntrack->infos.master。
该函数也返回一个struct ip_conntrack_tuple_hash结构

c) 处理完数据包是否有匹配的tuple之后,继续函数resolve_normal_ct的执行。接着判断该tuple_hash结构h的方向。很显然该包是一个新建立的包,所以
*ctinfo = IP_CT_NEW;
*setreply = 0;
最后将skb->nfct = &h->ctrack->infos[*ctinfo];
相当于把当前的连接跟踪结构体的地址保存在了skb中。至此,resolve_normal_ct函数执行结束。该函数返回的是一个ip_conntrack 结构体ct,对应当前数据的连接跟踪记录。

d) 接着ip_conntrack_in的处理。对ct进行指针检查之后,进入对应协议的packet函数处理。由于这里是TCP协议,所以proto->packet函数指针指向了tcp_packet(ip_conntrack_proto_tcp.c). 该函数对SYN包进行的相应处理,这里我们只需要知道
conntrack->proto.tcp.state= TCP_CONNTRACK_SYN_SENT
e) ip_conntrack_in函数执行完毕,数据包接着被其他Hook函数处理。

(3) 对数据包进行ip_conntrack_local处理之后,最后就等着数据包离开本机了。数据包离开本机之前,要经过NF_IP_POSTROUTING点,钩子函数为ip_refrag. 该函数首先调用
ip_confirm-> ip_conntrack_confirm-> __ip_conntrack_confirm。__ip_conntrack_confirm函数最终对数据包进行实际的处理。

__ip_conntrack_confirm首先检查数据包的方向,这里本地发出的包,应该为IP_CT_DIR_ORIGINAL(当且仅当使用REJECT target时,会出现不是ORIGINAL的情形,其它非ORIGINAL数据包在ip_conntrack_confirm函数中被返回NF_ACCEPT,不会进入到该函数的处理中),然后计算该数据包的正反两个方向tuple的hash值。如果ip_conntrack_hash静态表中没有这两个tuple,则加入进去。并将超时处理挂到time_list标上,同时将ip_conntrack结构的ct_general成员加1,并将ip_conntrac结构的status的第IPS_CONFIRMED_BIT=3位置位. 随后返回NF_ACCEPT,将该数据包发送出去。

至此,SYN包的连接记录已经建立,连接记录的超时处理函数也挂在了全局timer_list里面。


[ 本帖最后由 Godbach 于 2008-8-14 17:40 编辑 ]
----------
欢迎光临Godbach的博客:
HAProxy 研究笔记
---------
明犯我强汉天威者,穷搜天下,万里追杀,覆其巢,断其苗裔,戮其身,追其魂,屠其魄,虽远必诛!
联想布局云计算,信心满满路在何方?| 大数据挖掘哪家强?IBM企业峰会看端详 | 无孔不入的Linux:为何火到爆 | web前端工程师修炼之道:如何从菜鸟到大神
 
   
Godbach
To be 千里马!
Godbach 当前离线
空间积分
3
信誉积分
2338
UID
10167808
阅读权限
100
积分
5503
帖子
15534
精华
21
可用积分
5507
专家积分
79
在线时间
7651 小时
注册时间
2007-03-09
最后登录
2014-11-05
查看详细资料

版主

Rank: 8Rank: 8

帖子
15534
主题
372
精华
21
可用积分
5507
专家积分
79
在线时间
7651 小时
注册时间
2007-03-09
最后登录
2014-11-05
  • 问答
  • 好友
5楼[报告]
发表于 2008-08-12 14:24:45 | 只看该作者
2. TCP SYN+ACK包,s -> c (这里的处理步骤可以比照1中的相应处理步骤)

(1) 连接跟踪注册在NF_IP_PRE_ROUTING点的hook函数为:ip_conntrack_in, 用来处理接受到的数据包。该函数同样取出协议结构,这里为TCP。

(2) 调用resolve_normal_ct该函数,通过计算skb相关参数计算出对应的tuple,很明显这里可以查找到全局变量ip_conntrack_hash已经有该tuple的存在。

a) 有匹配的tuple,则返回该tuple对应的struct ip_conntrack_tuple_hash结构。
b) 继续函数resolve_normal_ct的执行。接着判断该tuple_hash结构h的方向。可以得出该数据包的方向是IP_CT_DIR_REPLY,因此
*ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
/* Please set reply bit if this packet OK */
*set_reply = 1;
最后将skb->nfct = &h->ctrack->infos[*ctinfo]; 相当于把当前的连接跟踪结构体的地址保存在了skb中。至此,resolve_normal_ct函数执行结束。该函数返回的是一个ip_conntrack 结构体ct,对应当前数据的连接跟踪记录。
c) 接着ip_conntrack_in的处理。对ct进行指针检查之后,进入对应协议的packet函数处理。由于这里是TCP协议,所以proto->packet函数指针指向了tcp_packet.
进入该函数,
oldtcpstate = conntrack->proto.tcp.state = SYNC_SENT(2);
newconntrack = tcp_conntracks[CTINFO2DIR(ctinfo)] [get_conntrack_index(tcph)][oldtcpstate];
= tcp_conntracks[1][0][2]
= sSR = TCP_CONNTRACK_SYN_RECV(3)
并且conntrack->proto.tcp.state = TCP_CONNTRACK_SYN_RECV (3)
然后:
conntrack->proto.tcp.handshake_ack = htonl(ntohl(tcph->seq)+ 1);
这里是将连接跟踪的的握手信号置位当前数据包的seq+1, 即相当于接收方将要发送数据包的seq_ack,留待以后做比较之用。
d) 根据当前数据包的情况,执行代码:
set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
接着ip_conntrack_in函数执行完毕,数据包接着被其他Hook函数处理。

(3) 对数据包的ip_conntrack_in处理之后,就等着数据包进入本机的Hook点,NF_IP_LOACL_IN。连接跟踪在这里注册的函数是ip_confirm,该函数是调用ip_conntrack_confirm,这里应该直接返回NF_ACCEPT。
至此,由于有相应连接记录的存在,这里只对连接记录的若干状态进行修改,然后就接收到了本地主机c上。这里也表明了连接跟踪将相关的连接都归于同一条连接记录上。

3. TCP ACK包, c-> s (这里的处理步骤可以比照1和2中的相应处理步骤)

(1) 由于这次又是本地发出的数据包,所以经过的hook点以及hook函数和1中的保持一致。按照1.(1)处理完毕之后,进行2.(2)的处理,根据当前数据包的状况,resolve_normal_ct函数对数据包的处理,我们主要关注以下两行:
*ctinfo = IP_CT_ESTABLISHED;
*set_reply = 0;
然后同样是skb中保存连接记录的地址,完成resolve_normal_ct函数的执行。

(2)接着ip_conntrack_in的处理。对ct进行指针检查之后,进入对应协议的packet函数处理。由于这里是TCP协议,所以proto->packet函数指针指向了tcp_packet. 进入该函数,参照2.(2).c):
oldtcpstate = conntrack->proto.tcp.state
= TCP_CONNTRACK_SYN_RECV
newconntrack = tcp_conntracks[CTINFO2DIR(ctinfo)] [get_conntrack_index(tcph)][oldtcpstate];
= tcp_conntracks[0][2][3]
= sES = TCP_CONNTRACK_ESTABLISHED
并且conntrack->proto.tcp.state = TCP_CONNTRACK_ESTABLISHED
根据数据包的状况,tcp_packet还将执行以下两行代码:
/*设置status*/
set_bit(IPS_ASSURED_BIT, &conntrack->status);
*更新连接记录的超时时间*/
ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
结束tcp_packet的执行,返回NF_ACCEPT。
继续ip_conntrack_in函数的执行,该函数也接着返回NF_ACCEPT. 至此,连接跟踪在该Hook点已经执行完毕。

(3) 对数据包进行ip_conntrack_in处理之后,最后就等着数据包离开本机了。数据包离开本机之前,要经过NF_IP_POSTROUTING点,钩子函数为ip_refrag. 该函数首先调用
ip_confirm-> ip_conntrack_confirm,对于本次数据包,该函数应该直接返回NF_ACCEPT。

至此,TCP的连接跟踪记录已经确定下来,以后数据进行传输的过程,应该就是重复2和3的过程。

这篇关于conntrack链接 tcp的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/949096

相关文章

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

QT实现TCP客户端自动连接

《QT实现TCP客户端自动连接》这篇文章主要为大家详细介绍了QT中一个TCP客户端自动连接的测试模型,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录版本 1:没有取消按钮 测试效果测试代码版本 2:有取消按钮测试效果测试代码版本 1:没有取消按钮 测试效果缺陷:无法手动停

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

【Go】go连接clickhouse使用TCP协议

离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么                      🎵 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time""github.com/ClickHouse/clickhouse-go/v2")func main(

2024.9.8 TCP/IP协议学习笔记

1.所谓的层就是数据交换的深度,电脑点对点就是单层,物理层,加上集线器还是物理层,加上交换机就变成链路层了,有地址表,路由器就到了第三层网络层,每个端口都有一个mac地址 2.A 给 C 发数据包,怎么知道是否要通过路由器转发呢?答案:子网 3.将源 IP 与目的 IP 分别同这个子网掩码进行与运算****,相等则是在一个子网,不相等就是在不同子网 4.A 如何知道,哪个设备是路由器?答案:在 A

每日一练7:简写单词(含链接)

1.链接 简写单词_牛客题霸_牛客网 2.题目 3.代码1(错误经验) #include <iostream>#include <string>using namespace std;int main() {string s;string ret;int count = 0;while(cin >> s)for(auto a : s){if(count == 0){if( a <=

图解TCP三次握手|深度解析|为什么是三次

写在前面 这篇文章我们来讲解析 TCP三次握手。 TCP 报文段 传输控制块TCB:存储了每一个连接中的一些重要信息。比如TCP连接表,指向发送和接收缓冲的指针,指向重传队列的指针,当前的发送和接收序列等等。 我们再来看一下TCP报文段的组成结构 TCP 三次握手 过程 假设有一台客户端,B有一台服务器。最初两端的TCP进程都是处于CLOSED关闭状态,客户端A打开链接,服务器端

短链接算法原理

平时我们在上网的时候,印象最深刻的有一次是短链接的服务。例如:平时在微信上看一个网页的时候,如果我们选择在浏览器打开的时候,会看到很长的URL,我们分享的时候,会看到一个很短URL,这就是本次所说的短链接的应用之一。 长链接示例:https://mp.weixin.qq.com/s?__biz=MzAxNzMwOTQ0NA==&mid=2653355437&idx=1&sn=5901826ea63

网络原理之TCP协议(万字详解!!!)

目录 前言 TCP协议段格式 TCP协议相关特性 1.确认应答 2.超时重传 3.连接管理(三次握手、四次挥手) 三次握手(建立TCP连接) 四次挥手(断开连接)  4.滑动窗口 5.流量控制 6.拥塞控制 7.延迟应答 8.捎带应答  9.基于字节流 10.异常情况的处理 小结  前言 在前面,我们已经讲解了有关UDP协议的相关知识,但是在传输层,还有

Vue2电商项目(二) Home模块的开发;(还需要补充js节流和防抖的回顾链接)

文章目录 一、Home模块拆分1. 三级联动组件TypeNav2. 其余组件 二、发送请求的准备工作1. axios的二次封装2. 统一管理接口API----跨域3. nprogress进度条 三、 vuex模块开发四、TypeNav三级联动组件开发1. 动态展示三级联动数据2. 三级联动 动态背景(1)、方式一:CSS样式(2)、方式二:JS 3. 控制二三级数据隐藏与显示--绑定styl