假设您有一台在 Linux 机器上运行的 24/7 服务器,它处理传入连接以及“普通”TCP 作为 TLS(通过 OpenSSL)。为了确保服务正常运行,客户端需要始终保持与此服务的连接。不幸的是,当服务器关闭连接时,其中一些客户端不会立即重新连接,因此服务器会尽力保持连接永远有效。
但是,如果服务器需要重新启动(例如由于维护),连接将丢失。
为了避免断开连接,我想使用 TCP_REPAIR 机制 ( https://lwn.net/Articles/495304/ ) 将已建立的 TCP 会话“移动”到另一台机器。基本上,这意味着保存来自机器 A 的 TCP 套接字信息(例如 Syn/Ack 编号),恢复机器 B 上的 TCP 套接字信息并确保将新的 IP 数据包发送到新机器。
这对于普通 TCP 来说效果很好,客户端不会注意到 TCP 连接被重定向到另一台机器。但是当使用 TLS 时,这显然需要做更多的工作。
为了简化,我们假设线路上没有 TLS 消息,没有待处理的 SSL_read 和 SSL_write,并且所有先前的 TLS 消息都已完全发送和接收。
我到目前为止尝试过的:
方法 1:使用相同的 SSL_SESSION 静默地重新创建一个新的 SSL 对象
尝试创建一个新的 SSL 对象,使其“已建立”并将其附加到 fd:
- 在新机器上,创建一个(临时)客户端 SSL_CTX,添加来自旧机器的 SSL_SESSION 对象。由于此 SSL_SESSION 对象是从旧机器上的服务器 SSL_CTX 中获取的,因此这种方法可能完全没用,但我还是尝试了一下。
- 创建两个新的 SSL 对象(一个来自客户端-ctx(仅临时),一个来自服务器-ctx),通过内存 BIO 连接它们,将 SSL_SESSION 设置为 SSL 客户端对象。
- 发起握手
- 握手完成后,使用重建的 TCP 连接将服务器 SSL 对象的 bio 更改为 BIO_fd
- 销毁(不再需要的)内存 BIO 和客户端 SSL 对象。
这根本不起作用。我总是看到完整的握手,SSL_session_reused 对两个 SSL 对象都返回 0。即使 SSL_SESSION 被重用,我仍然怀疑这是否足够。
方法 2:memcpy 方法
这基本上是尝试创建类似“i2d_SSL”和“d2i_SSL”的方法。
- 从新服务器的 SSL_CTX 创建一个简单的 SSL 对象。
- 从旧服务器的 SSL 对象附加 SSL_SESSION
- 使用内部 OpenSSL 标头,将 SSL 对象转换为 SSL_CONNECTION 结构
- 从 SSL_CONNECTION 结构中复制一些字段:
- 秘密
- .s3 子结构中的随机场
- .s3.tmp 子结构中的 *_md 字段
- .statem 子结构中的状态
- ...还有一些(或多或少是反复试验)。
我认为方法 2可行,但找出真正相关的字段相当困难 - 如果这种方法可行的话。
有人可以解释一下这个问题吗?