You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中如何将TCP打洞后的连接升级为TLS加密连接?

TCP打洞后升级现有连接为TLS加密的问题

两个客户端通过TCP hole punching(TCP打洞)实现互相连接,复用原本连接到rendez-vous server的socket(该socket原本是TLSSocket),打洞时的代码如下:

// 该socket已存在,原本连接到rendez-vous server
// 我复用它与服务器通信时使用的本地端口和地址,现在尝试连接对等方
socket.connect({
    localAddress,
    localPort,
    port: peerAddresses.remoteAddress.port,
    host: peerAddresses.remoteAddress.host,
});

打洞过程能正常工作,但连接到对等方后,原有的加密功能失效(经Wireshark观测确认)。

我需要找到方法将对等方之间的连接升级为加密连接,已尝试以下几种方式:

tls.connect({ socket: socket, secureContext: tls.createSecureContext(...) });

// 或

new tls.TLSSocket(socket, { secureContext: ..., isServer: true /* 仅在一端设置 */ })

分别尝试了仅在连接的一端设置server角色(理解TLS需要一端为server一端为client),以及两端都设置,但均无效果。我希望避免手动执行Diffie-Hellman密钥交换。

补充示例代码

以下是两个客户端尝试互相连接并升级的具体代码:

clientA.js

const net = require('net');
const tls = require('tls');
const fs = require('fs');

const localPort = 3018;
const peerPort = 3019;

const socket = net.createConnection({
  localPort: localPort,
  port: peerPort
});

socket.on('connect', () => {
  console.log('connected!');

  const secureContext = tls.createSecureContext({
    key: fs.readFileSync('./ca-key.pem'),
    cert: fs.readFileSync('./ca-cert.pem'),
  });

  const secureSocket = new tls.TLSSocket(socket, { isServer: true, secureContext });

  secureSocket.on('session', session => console.log('session', session));

  secureSocket.on('secureConnect', () => {
    console.log('securely connected!');
  });

  secureSocket.on('close', () => console.log('closing secure socket A'));
});

socket.on('error', (e) => { console.log(e); });

socket.on('close', () => {
  socket.connect({
    localPort: localPort,
    port: peerPort
  });
});

clientB.js

const net = require('net');
const tls = require('tls');
const fs = require('fs');

const localPort = 3019;
const peerPort = 3018;

const socket = net.createConnection({
  localPort: localPort,
  port: peerPort
});

socket.on('connect', () => {
  console.log('connected!');

  const secureSocket = new tls.TLSSocket(socket, { isServer: false });

  secureSocket.on('session', () => {
    console.log('session');
  });

  secureSocket.on('secureConnect', () => {
    console.log('securely connected!');
  });

  secureSocket.on('close', () => console.log('closing secure socket B'));
});

socket.on('error', (e) => { console.log(e); });

socket.on('close', () => {
  socket.connect({
    localPort: localPort,
    port: peerPort
  });
});

示例中的问题

运行后能收到connected!消息,但securely connected!以及安全socket的session、close事件均未触发。直接在现有socket外实例化新的TLSSocket没有任何作用,连接并未升级。

若调用secureSocket.connect({ localPort: localPort, port: peerPort })会收到EADDRINUSE错误,这符合预期。尝试过在两端都调用tls.connect({ socket: socket, secureContext: tls.createSecureContext(...) }),但这种方式无法指定哪一端作为server,显然也不正确。

希望得到相关建议,目前对底层原理了解有限,可能需要深入研究Node.js内部实现。

内容的提问来源于stack exchange,提问作者qnilab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 21:45:16