[翻译] 防火墙的敌人: TCP 快速打开

前言: 之所以翻译这篇文章是在搭建 NaïveProxy 的时候,看到有关 Do not turn on TCP Fast Open 的讨论

原文来源:The enemy of firewalls: TCP Fast Open

使用 Kimi 翻译,人工校正

去年在 SRECon16 Europe 会议上,我和 Booking.com 的一位工程师交谈时,他提到他们计划在 L3 负载均衡(ECMP)下的服务器农场部署TCP快速打开(TFO)。

我问他们是否在生产环境中部署了 TFO。第一个回答是:“我们没有,因为我们不知道如何在应用节点之间管理 TFO 密钥。”

然后我脑海中出现了一个问题:“为什么不使用自动化工具同步它们,或者定期这样做,比如在 cookie 内部插入时间戳?”

今天我回想起这个案例,想尝试看看它在现实中的表现如何。我不会深入探讨它的工作原理以及如何为客户端和服务器启用它。如果你需要关于 TFO 如何工作的基本信息,这篇文章非常有用。我将描述其他有用的内容,这些内容在之前提到的帖子中没有涵盖。

验证 TFO 是否工作

第一个验证它是否工作的工具是 tcpdump

使用 TFO 时:

07:03:45.442747 IP 1.1.1.1.41360 > 2.2.2.2.81: Flags [S], seq 3248579141:3248579160, win 29200, options [mss 1460,sackOK,TS val 0 ecr 0,nop,wscale 7,unknown-34 0x2cc5086de402d86a,nop,nop], length 19
07:03:45.442876 IP 2.2.2.2.81 > 1.1.1.1.41360: Flags [S.], seq 1989043609, ack 3248579161, win 28960, options [mss 1460,sackOK,TS val 37965533 ecr 0,nop,wscale 7], length 0
07:03:45.443034 IP 1.1.1.1.41360 > 2.2.2.2.81: Flags [.], ack 1, win 229, options [nop,nop,TS val 1277090187 ecr 37965533], length 0

不使用 TFO(常规的三次握手):

19:36:19.471384 IP 1.1.1.1.62248 > 2.2.2.2.81: Flags [S], seq 1237548774, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 932576322 ecr 0,sackOK,eol], length 0
19:36:19.471483 IP 2.2.2.2.81 > 1.1.1.1.62248: Flags [S.], seq 3862688090, ack 1237548775, win 28960, options [mss 1460,sackOK,TS val 83119562 ecr 932576322,nop,wscale 7], length 0
19:36:19.478781 IP 1.1.1.1.62248 > 2.2.2.2.81: Flags [.], ack 1, win 4117, options [nop,nop,TS val 932576329 ecr 83119562], length 0

你应该注意到第一个输出中的 unknown-34 0x2cc5086de402d86a 部分和 length 19 ,这意味着,SYN 数据包携带了数据(19字节),并且 TFO 的 cookie 是 0x2cc5086de402d86a 。第二个例子显示了没有 TFO 选项的 TCP 常规三次握手。在我的示例中, SYN-ACK 没有携带任何数据,因为我没有使用任何响应请求的应用程序。

TFO 队列长度

在这种情况下,我安装了 HAProxy,它支持 TFO,但似乎没有简单的方法来监控 TFO 队列。使用 stap,你几乎可以像往常一样捕获几乎所有东西。

probe kernel.statement("tcp_fastopen_queue_check@net/ipv4/tcp_fastopen.c:234")
{
        if ($fastopenq->qlen)
                printf("%d/%d\n", $fastopenq->qlen, $fastopenq->max_qlen);
}

产生的输出:

关于 TCP/IP 内核栈如何处理 TCP 选项的一些信息

让我们谈谈这个在 RFC7413 中定义的选项:

                                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                                   |      Kind     |    Length     |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   ~                            Cookie                             ~
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   Kind            1 byte: value = 34
   Length          1 byte: range 6 to 18 (bytes); limited by
                           remaining space in the options field.
                           The number MUST be even.
   Cookie          0, or 4 to 16 bytes (Length - 2)

我开始深入研究 net/ipv4/tcp_input.c ,看看这些 TCP 选项是如何处理的,因为我不理解 KindLength 的含义。

我感兴趣的函数是:

void tcp_parse_options(const struct sk_buff *skb,
                       struct tcp_options_received *opt_rx, int estab,
                       struct tcp_fastopen_cookie *foc)

查看代码本身并不那么有信息量,除非打开另一个有说明的标签页。

所有 TCP 选项都立即放在 TCP 头部之后,因此这个 ptr = (const unsigned char *)(th + 1); 移动指针到选项开始的地方。

好的,我们有了指向选项的指针,现在我们需要逐个解析这些选项。 int opcode = *ptr++; 导致前述的 Kind

后来我们有一个循环,通过opsize = *ptr++; 迭代所有选项,这是定义为Length的偏移量。

现在我们有了 Cookie 。迭代选项,直到你找到 TCPOPT_FASTOPEN (这就是我们在 tcpdump 中看到的 unknown-34 ):

                        case TCPOPT_FASTOPEN:
                                tcp_parse_fastopen_option(
                                        opsize - TCPOLEN_FASTOPEN_BASE,
                                        ptr, th->syn, foc, false);
                                break;

这适当地调用了 tcp_parse_fastopen_option ,并将 cookie 值复制到 tcp_fastopen_cookie 结构中,以便进一步处理,这在 net/ipv4/tcp_fastopen.c 下。然后一切都几乎清晰明了,就像 RFC 中定义的那样:

struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
                              struct request_sock *req,
                              struct tcp_fastopen_cookie *foc,
                              struct dst_entry *dst)

好的,但为什么 TFO 是防火墙的敌人呢?

连接中间的防火墙可能会导致 TFO 在传输中卡住 – 黑洞。这可能发生在以下场景中:

防火墙丢弃带有有效载荷的 SYN 数据包; 防火墙丢弃三次握手中带有有效载荷的 SYN/ACK 数据包。 结果,连接将长时间停滞,客户端将挂起。

这个问题可以通过引入 tcp_fastopen_blackhole_timeout_sec sysctl 来解决,它将使时间呈指数增长以禁用活跃的 TFO。当 TFO 恢复正常时,它会减少这个时间。

总结

  • ip tcp_metrics show 命令在某些情况下很有用;
  • nstat 有助于查看一些 TFO 活动;
  • TFO 目前还不是那么流行,但它正在加速发展(例如:TLS 1.3(False Start))。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
Theme Argon By solstice23
Powered by Netcup
| 耗时 0.043 秒 | 查询 34 次 | 内存 3.86 MB |