连接跟踪(conntrack)

概述

连接跟踪是很多网络服务和应用的基础。例如,kubernetes的service,ServiceMesh sidecar,4层负载均衡软件LVS/IPVS,容器网络,OpenvSwitch,OpenStack安全组等等都是依赖连接跟踪。

概念

顾名思义,连接跟踪就是跟踪或维护网络连接及其状态的。


Linux主机上连接跟踪示例

上图中,Linux主机的IP地址是10.1.1.2,包含3个连接:
1、10.1.1.2:55667 <-> 10.2.2.2.:80:本地发起的连接,用于访问外部HTTP/TCP服务。
2、10.3.3.3:23456 <-> 10.3.3.2.:21:外部连接访问该节点的FTP/TCP服务。
3、10.1.1.2:33987 <-> 10.4.4.4.:53:本地发起的连接,用于访问外部DNS/UDP服务。
Conntrack模块负责发现和记录这些连接及其状态,包括:

  • 提取数据包的五元组,区分数据包和相关连接。
  • 为所有连接维护一个“数据库”(连接跟踪表),存储连接的创建时间、发送的数据包、发送的字节信息等。
  • 回收陈旧的连接信息(GC)。
  • 为上层功能服务,例如NAT。

但是请注意,“连接跟踪”中的术语“连接”不同于我们常在TCP/IP栈中所指的“连接”概念。简而言之:

  • 在TCP/IP协议栈中,“连接”是4层概念。TCP是一种面向连接的协议,所有的报文都需要得到确认(ACK),并且有重传机制。UDP是一种无连接协议,不需要确认(ACK),也不需要重传。
  • 在连接跟踪中,五元组唯一地定义数据流,数据流表示连接。
    后面我们将看到即使ICMP(3层协议)也有连接数据。但并不是所有的协议都有连接跟踪。
    我们所说的“连接”,在大多数情况下是指后者,即“连接跟踪”上下文中的“连接”。

理论

有了上述概念,让我们来分析连接跟踪的基本理论。要跟踪一个节点上所有连接的状态,我们需要:
1、读取(或过滤)通过该节点的每个数据包,并分析数据包。
2、设置一个“数据库”记录这些连接的状态。
3、根据数据包提取信息,及时更新连接状态到数据库(连接跟踪表)。
例如:
1、当读取一个TCP SYC数据包时,我们将确认这是在尝试新的连接,我们需要创建一个新的连接跟踪记录。
2、当得到一个属于现有连接的数据包时,我们需要更新连接跟踪的统计信息,例如发送的字节数、发送的数据包数、超时值等。
3、当超过30分钟没有包匹配conntrack条目时,我们考虑从数据库中删除该条目。

除了上述功能外,性能也是值得我们关注的,因为conntrack模块会对每一个数据包进行过滤和分析。性能是相当重要的,但它们超出了本文的范围。在稍后介绍内核conntrack实现时,我们将再次回到性能问题。
另外,最好有一些管理工具,方便使用conntrack。

Netfilter

Linux内核中的连接跟踪是在Netfilter框架中作为一个模块实现的。

Linux内核中的Netfilter架构

Netfilter是内核内部的一个包操作和过滤框架。它在内核中提供了几个挂钩点hook,因此可以完成包读取、过滤和许多其他处理。

更清楚地说,钩子(hook)是一种在包的遍历路径上放置多个检查点的机制。当一个包到达一个钩子时,首先检查规则,检查结果可能是:
1、通过:对数据包不做任何处理,把它推回到原来的路径,让它通过。
2、修改:替换网络地址(NAT),然后推回到原来的路径,继续通过。
3、丢弃:例如,通过在这个检查(挂钩)点配置的防火墙规则。
注意,conntrack模块只提取连接信息并维护其数据库,它不会修改或丢弃数据包。修改和删除是由其他模块完成的,例如NAT。

Netfilter是Linux内核中最早的网络框架之一,它最初于1998年开发,2000年合并到内核2.4.x主线中。经过20多年的发展,它变得非常复杂,以至于在某些场景中导致性能下降,我们稍后将对此进行更多讨论。

进一步考虑

根据我们在上一节的讨论,连接跟踪的概念独立于Netfilter,而后者只是连接跟踪的一种实现。
换句话说,只要具备了钩子(hook)功能——能钩住经过系统的每一个数据包——我们就可以实现自己的连接跟踪。


Cilium的连接跟踪和NAT架构

Cilium是Kubernetes的一个云原生网络解决方案,实现了这样的连接跟踪和NAT机制。实现的基础:
1、基于BPF钩子来勾住数据包(BPF类似于Netfilter的Hook)。
2、基于BPF钩子实现一个全新的连接跟踪和NAT模块。内核版本4.19+。
因此,可以完全移除整个Netfilter模块,Cilium还可以为Kubernetes提供网络功能例如ClusterIP,NodePort,ExternalIP和负载均衡。

因为它的连接跟踪实现独立于Netfilter,Cilium的连接跟踪和NAT信息不是存储在系统的连接跟踪表和NAT表中。因此,通常使用的网络工具conntrack/netstats/ss/lsof无法查询到相关信息,你必须使用Cilium的方式,例如;

$ cilium bpf nat list
$ cilium bpf ct list global

而且,配置也是独立的,你需要指定Cilium的参数,例如命令行参数-bpf-ct-tcp-max。
我们澄清了conntrack的概念是独立于NAT模块的,但是出于性能考虑,代码可能是耦合的。例如,当对conntrack表执行GC时,它将有效地删除NAT表中的相关条目,而不是为NAT表维护一个单独的GC循环。

使用场景

我们来看看一些基于conntrack的具体网络应用程序/函数。

NAT网络地址转换

顾名思义,NAT转换(数据包)网络地址(IP+端口)。


节点地址转换

上图中,假设节点IP 10.1.1.2可以被其他节点访问,但是内部网络地址范围在192.168.1.0/24的,外部访问不了,类似节点上容器地址。这表明:
1、数据包原地址在192.168.1.0/24范围内可以被发送,因为出口路由只依赖于目的IP。
2、但是,响应数据包(目的IP范围是在192.168.1.0/24内)就无法返回了,因为192.168.1.0/24在节点上是不能直接被外界访问的。

这种情况的一种解决方案就是:
1、在发送原地址范围在192.168.1.0/24的数据包时,将原地址IP替换成节点IP 10.1.1.2然后再发送出去。
2、接收到返回数据包,做相反的操作,并转发给原始发送者。
这只是NAT的底层工作机制。

容器网络默认是网桥模式,使用的就是上面的NAT机制来实现容器与外部节点的通信的。在节点内,每个Docker容器分配一个本地IP地址。该地址支持节点内容器之间的通信,但当与节点外的服务通信时,通信将被NAT处理。

NAT也可以替换源端口。这并不难理解:每个IP地址可以使用完整的端口范围(例如1~65535)。假设我们有两个连接:

  • 192.168.1.2:3333 <–> NAT <–> 10.2.2.2:80
  • 192.168.1.3:3333 <–> NAT <–> 10.2.2.2:80
    如果NAT只将源IP地址替换为节点IP地址,则上述两个不同连接NAT处理好后是:
  • 10.1.1.2:3333 <–> 10.2.2.2:80
  • 10.1.1.2:3333 <–> 10.2.2.2:80
    两个连接混在一起无法区分,返回数据将不能做地址转换操作,因此,如果发生冲突,NAT也会替换源端口。

NAT还可以进一步分类:

  • SNAT:原地址转换。
  • DNAT:目的地址转换。
  • Full NAT:原地址和目的地址都转换。
    上图中使用的是SNAT转换。NAT依赖于连接跟踪,并且NAT是连接跟踪最重要使用场景。
4层负载均衡(L4LB)

让我们再进一步讨论,基于NAT模式的4层负载均衡。L4LB是根据数据包的L3+L4信息来转发流量的,例如src/dst ip(原地址/目的地址),src/dst端口。

VIP(虚地址):是实现4层负载均衡的一种方式:

  • 具有不同真实IP的多个后端节点注册到相同的虚IP (VIP)
  • 来自客户端的流量首先到达VIP,然后负载均衡到特定的后端ip。
    如果L4LB采用NAT模式(VIP和Real ip之间),L4LB会对客户端和服务器之间的流量进行全NAT转换,数据流如下图所示:


    4层负载均衡:NAT模式
有状态防火墙

有状态防火墙是相对于早期的无状态防火墙而言。很明显,要提供有状态防火墙,必须跟踪数据流和状态—这正是连接跟踪所做的事情。

我们来看一个具体例子:OpenStack安全组,主机防火墙解决方案。

OpenStack security group

安全组提供的是虚拟机级别的安全隔离,它是通过在虚拟机的主机网络设备上应用有状态防火墙规则来实现的。在当时,最成熟的有状态防火墙可能是Netfilter/iptables。

现在回到每个计算节点内部的网络拓扑:


OpenStack计算节点网络拓扑

每个计算节点用一个OVS桥接(br-int)连接(集成)它内部的所有虚拟机vm。如果只考虑网络连接,每个VM应该直接连接到br-int。但问题来了:

  • OVS早期版本没有连接跟踪模块conntrack。
  • Linux内核有conntrack模块,基于连接跟踪的防火墙工作在IP层(L3),通过iptables操作。
  • OVS是L2模块,这意味着它不能利用L3模块,因此,无法对虚拟机的OVS(节点侧)网络设备设置防火墙。
    OpenStack通过在每个VM和br-int之间插入一个Linux桥来解决这个问题,如上图所示。
    Linux 网桥也是一个L2模块,所以不能使用iptables。但是,它有一种称为ebtables的L2过滤机制,可以跳转到iptables规则,从而使Netfilter/iptables可行。

但是这种解决方法很难看,并且会导致严重的性能问题。因此,在2016年,RedHat提出了一种OVS连接跟踪解决方案,可以在具有安全组功能的情况下关闭Linux桥接。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容