TCP/IP卷一:94---TCP保活机制

一、一个TCP持续连接的情况

  • 许多TCP/IP的初学者会惊奇地发现,在一个空闲的TCP连接中不会有任何数据交换。 也就是说,如果TCP连接的双方都不向对方发送数据,那么TCP连接的两端就不会有任何的数据交换。例如,在TCP协议中,没有其他网络协议中的轮询机制
  • 这意味着我们可以启动一个客户端进程,与服务器端建立连接,然后离开几个小时、几天、几星期,甚至几个月,而连接依然会保持。理论上,中间路由器可以崩溃和重启,数据线可以断开再连接,只要连接两端的主机没有被重新启动(或者更改IP地址),那么它们将会保持连接状态

TCP/IP卷一:94---TCP保活机制_第1张图片

二、保活机制

为什么设计保活机制?

  • 一些情况下:
    • 客户端和服务器需要了解什么时候终止进程或者与对方断开连接
    • 而在另 一些情况下,虽然应用进程之间没有任何数据交换,但仍然需要通过连接保持一个最小的数据流
  • TCP保活机制就是为了解决上述两种情况而设计的

保活计时器与保活探测

  • 保活机制是一种在不影响数据流内容的情况下探测对方的方式
  • 它是由一个保活计时器实现的。当计时器被激发,连接一端将发送一个保活探测(简称保活)报文,另一端接收报文的同时会发送一个ACK作为响应

TCP/IP卷一:94---TCP保活机制_第2张图片

保活机制的争议

  • TCP保活机制存在争议:
    • 许多人认为,如果需要,这一功能也不应在TCP协议中提供,而应在应用程序中实现
    • 另一种观点认为,如果许多应用程序中都需要这一功能,那么在TCP协议中提供的话就可以使所有的实现都包含这一功能
  • 保活机制是一个可选择激活的功能。它可能会导致一个好的连接由于两端系统之间网络的短暂断开而终止。例如,如果在中间路由器崩溃并重新启动的时候保活探测,那么TCP协议将错误地认为对方主机已经崩溃

三、保活机制的使用场景

  • 保活功能一般是为服务器应用程序提供的,服务器应用程序希望知道客户主机是否崩溃或离开,从而决定是否为客户端绑定资源。利用TCP保活功能来探测离开的主机,有助于服务器与非交互性客户端进行相对短时间的对话,例如,Web服务器、 POP和IMAP电子邮件服务器
  • 而更多地实现长时间交互服务的服务器可能不希望使用保活功能,如ssh和 Windows远程桌面这样的远程登录系统

保活机制的使用场景①

  • 可以通过一个简单例子来说明保活功能的可用性
  • 用户利用ssh(安全shell)远程登录程序穿越NAT路由器登录远程主机:
    • 如果建立连接,并做了相关操作,然后在一天结束时没有退出,而是直接关闭了主机,那么便会留下一个半开放的连接
    • 在“TCP连接管理”中已经提到过,通过一个半开放的连接发送数据会返回一个重置信息,但那是来自正在发送数据的客户端
    • 如果客户端离开了,只剩下服务器端的一个半开放的连接,而服务器又在等待客户端发来的数据,那么服务器将会永远地等待下去
    • 在服务器端探测到这种半开放的连接时,就可以使用保活功能

保活机制的使用场景②

  • 相反的情况下同样需要使用保活机制:
    • 如果用户没有关闭计算机,而是整个晚上保持连接,第二天可以继续使用,那么连接将连续几个小时处于空闲状态
    • 在“NAT”文章中我们提到过,大部分NAT路由器包含超时机制。当连接在一段时间内处于非活动状态时,路由器将断开连接。如果NAT超时时限小于用户重新登录之前的几个小时,且NAT不能探测到端主机并确认它还处于活动状态,或者NAT路由器崩溃,那么该连接将被终止
    • 为了避免这种情况的发生,用户可以配置ssh,启动TCP保活功能。ssh还能够使用应用程序管理的保活功能
  • 两种功能的行为模式不同,特别是安全性方面(见最下面的与TCP保活机制相关的攻击)

四、保活机制的实现

  • 保活功能在默认情况下是关闭的
  • TCP连接的任何一端都可以请求打开这一功能。保活功能可以被设置在连接的一端、两端,或者两端都没有。有几个配置参数可以用来控制保活功能的操作

保活机制的原理

  • 如果在一段时间(称为保活时间,keepalive time)内连接处于非活动状态,开启保活功能的一端将向对方发送一个“保活探测报文”
  • 如果发送端没有收到响应报文,那么经过一个已经提前配置好的保活时间间隔(keepalive interval),将继续发送保活探测报文,直到发送探测报文的次数达到“保活探测数”(keepalive probe),这时对方主机将被确认为不可到达,连接也将被中断

保活探测报文

  • 保活探测报文为一个空报文段(或只包含1字节)。它的序列号等于对方主机发送的ACK报文的最大序列号减1。因为这一序列号的数据段已经被成功接收,所以不会对到达的报文段造成影响,但探测报文返回的响应可以确定连接是否仍在工作
  • 探测及其响应报文都不包含任何新的有效数据(它是“垃圾”数据),当它们丢失时也不会进行重传
  • [RFCl122]指出,仅凭一个没有被响应的探测报文不能判断连接是否已经停止工作。这就是“保活探测数参数”需要被提前设置的原因
  • 值得注意的是,一些TCP实现(大部分是早期的TCP实现)不会响应那些不包含“垃圾”数据的保活探测报文

保活机制检测到的4种状态

  • TCP保活功能工作过程中,开启该功能的一端会发现对方处于以下四种状态之一:
    • ①对方主机仍在工作,并且可以到达。对方的TCP响应正常,并且请求端也知道对方在正常工作。请求端将保活计时器重置(重新设定为保活时间值)。如果在计时器超时之前有应用程序通过该连接传输数据,那么计时器将再次被设定为保活时间值
    • ②对方主机已经崩溃,包括已经关闭或者正在重新启动。这时对方的TCP将不会响应。 请求端不会接收到响应报文,并在经过保活时间间隔指定的时间后超时。超时前,请求端会持续发送探测报文,一共发送保活探测数指定次数的探测报文,如果请求端没有收到任何探测报文的响应,那么它将认为对方主机已经关闭,连接也将被断开
    • ③客户主机崩溃并且已重启在这种情况下,请求端会收到一个对其保活探测报文的响应,但这个响应是一个重置报文段,请求端将会断开连接
    • ④对方主机仍在工作,但是由于某些原因不能到达请求端(例如网络无法传输,而且可能使用ICMP通知也可能不通知对方这一事实)。这种情况与状态2相同,因为TCP不能区分状态2与状态4,结果都是没有收到探测报文的响应
  • 请求端不必担心对方主机正常关闭然后重启(不同于主机崩溃)的情况。当系统关机时,所有的应用进程也会终止(即对方的进程),这会使对方的TCP发送一个FIN。请求端接收 到FIN后,会向请求端进程报告文件结束,并在检测到该状态后退出
  • 在第①种情况下,请求端的应用层不会觉察到保活探测的进行(除非请求端应用层激活保活功能)。一切操作均在TCP层完成,因此这一过程对应用层是透明的,直至第②、③、 ④种 情况中的某种情况发生。在这三种情况中,请求端的应用层将收到一个来自其TCP层的差错报告(通常请求端已经向网络发出了读操作请求,并且等待来自对方的数据。如果保活功能返回了一个差错报告,则该差错报告将作为读操作请求的返回值返回给请求端)。在第②种情况下,差错是诸如“连接超时”之类的信息,而在第③种情况下则为“连接被对方重置”。第④种情况可能是连接超时,也可能是其他的错误信息
  • 在下一节中我们将重点讨论这四种情况

五、“保活时间、保活时间间隔、保活探测数”设置

  • “变量保活时间、保活时间间隔和保活探测数”的设置通常是可以变更的。有些系统允许用户在每次建立连接时设置这些变量,还有一些系统规定只有在系统启动时才能设置(有的系统两者皆可)

Linux系统

  • 这些变量分别对应sysctl变量net.ipv4.tcp_keepalive_time、 net.ipv4.tcp_keepalive_intvl、 net.ipv4.tcp_keepalve_probes
  • 默认设置是7200秒(2小时)、 75秒和9次探测

FreeBSD、Mac OS X系统

  • 在FreeBSD和Mac OS X系统中,前两个变量对应sysctl变量net.inet.tcp.keepidle和net.inet.tcp.keepintvl,默认设置为7200秒(2小时)和75000毫秒(75秒)
  • 这两个系统还包含一个名为net.inet.tcp.always_keepalive的布尔变量。如果这个变量被激活,那么即使应用程序没有请求,所有TCP连接的保活功能都会被激活。探测次数被设定为固定值8(FreeBSD系统)或9(MacOSX系统)

Windows系统

  • 在Windows系统中,可通过在系统键值下修改注册表项来设置变量:

  • KeepAliveTime保活时间默认为7200000毫秒(2小时),KeepAliveInterval(保活时间间隔)默认为1000毫秒(1秒)。如果10个保活探测报文都没有响应,Windows系统将终止连接
  • 值得注意的是,[RFCl122]明确给出了用户使用保活功能的限制。保活时间值必须是可配置的,而且默认不能小于2小时。此外,除非应用层请求开启保活功能,否则不能使用该功能(而如果net.inet.tcp.always_keepalive变量被设置时会违反这一限制) 。没有经过应用层 的请求,Linux系统不会提供保活功能,但是一个特殊库会被预先载入(即在载入普通共享库之前),从而实现该功能[LKA]

六、演示案例

待续

七、与TCP保活机制相关的攻击

  • 之前提到过,ssh(第2版)中含有一种应用层的保活机制,称为服务器保活报文和客户端保活报文。与TCP保活报文的区别在于,它们是在应用层通过一条加密的链路传输的,而且这些报文中包含数据。TCP保活报文中不包含任何用户数据,所以它最多只进行有限的 加密。因此TCP保活机制容易受到欺骗攻击。当受到欺骗攻击时,在相当长的一段时间内,受害主机必须维护不必要的会话资源
  • 还有一些相对次要的问题。TCP保活机制的计时器是由之前提到的不同配置参数决定的,而不是用于数据传输的重传计时器。对于被动的观察者来说,他们能够注意到保活报文的存在,并观察保活报文发送的间隔时间,从而了解系统的配置参数(可能获取发送系统类别信息,称为系统指纹)或者网络的拓扑结构(即下一跳路由器是否能够转发数据流量)。这些问题在某些环境下是非常重要

你可能感兴趣的:(TCP/IP卷一)