代码之家  ›  专栏  ›  技术社区  ›  VirtualWolf

如何使用节点。js的TLSSocket连接(并重新连接)到服务器?

  •  0
  • VirtualWolf  · 技术社区  · 2 年前

    我有一个 toy IRC bot 我一直在攻击它,它能够同时连接到多个服务器,包括未加密的服务器和通过TLS的服务器。原来是我的 connection code looked like this :

    constructor({host, port, tlsEnabled, nick, channels}: {host: string, port: number, tlsEnabled: boolean, nick: string, channels: Channels}) {
        this.host = host;
        this.port = port
            ? port
            : tlsEnabled
                ? 6697
                : 6667;
        this.tlsEnabled = tlsEnabled;
        this.nick = nick;
        this.channels = channels;
    
        this.client = this.tlsEnabled
            ? tls.connect({host: this.host, port: this.port, timeout: 180000}, () => this.sendClientRegistration())
            : net.connect({host: this.host, port: this.port, timeout: 180000}, () => this.sendClientRegistration());
    
        [...]
    
        this.client.on('close', (hadError) => {
            logMessage('INFO', this.host, `Connection to ${host} closed`);
    
            try {
                setTimeout(() => this.client.connect({host: this.host, port: this.port}, () => this.sendClientRegistration()), 60000);
            } catch (err) {
                logMessage('INFO', this.host, `Failed to reconnect to ${this.host}`);
            }
        });
    }
    
    

    它基本上工作正常,除非与服务器的连接被中断足够长的时间,否则我最终会遇到问题 MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 connect listeners added to [Socket] 消息,它永远不会重新连接。

    refactored the connection code 看起来像这样:

    constructor({host, port, tlsEnabled, nick, channels}: {host: string, port: number, tlsEnabled: boolean, nick: string, channels: Channels}) {
        this.host = host;
        this.port = port
            ? port
            : tlsEnabled
                ? 6697
                : 6667;
        this.tlsEnabled = tlsEnabled;
        this.nick = nick;
        this.channels = channels;
    
        this.client = this.tlsEnabled
            ? new tls.TLSSocket(new net.Socket())
            : new net.Socket();
    
        [...]
    
        this.client.on('close', () => {
            logMessage('INFO', this.host, `Connection to ${host} closed`);
    
            try {
                setTimeout(() => this.connect(), 60000);
            } catch (err) {
                logMessage('INFO', this.host, `Failed to reconnect to ${this.host}`);
            }
        });
    
        this.connect();
    }
    
    connect() {
        this.client.connect({host: this.host, port: this.port});
    }
    
    

    虽然这对非TLS连接非常有效,并且可以根据需要多次尝试重新连接,而不会创建太多事件侦听器,但对于TLS连接,它甚至不会尝试连接,如果我的配置中只有一个TLS连接,应用程序会立即干净地退出。

    我偶然发现 this answer 这看起来很相似,但我还没有找到一点运气,弄清楚如何让它在我的案例和节点中真正起作用。js TLS文档也没有带来启发。 It says this 对于 socket 选择 tls.connect() :

    socket <stream.Duplex> 在给定的套接字上建立安全连接,而不是创建新的套接字。通常,这是一个 net.Socket ,但任何 Duplex 流是允许的。如果指定了此选项, path , host port 被忽略,证书验证除外。通常,一个套接字在传递到时已经连接 tls。连接() ,但可以稍后再连接。连接/断开/破坏 插座 是用户的责任;使命感 tls。连接() 不会导致 net.connect() 被称为。

    我再次更新了连接代码,如下所示:

    constructor({host, port, tlsEnabled, nick, channels}: {host: string, port: number, tlsEnabled: boolean, nick: string, channels: Channels}) {
        this.host = host;
        this.port = port
            ? port
            : tlsEnabled
                ? 6697
                : 6667;
        this.tlsEnabled = tlsEnabled;
        this.nick = nick;
        this.channels = channels;
    
        this.client = new net.Socket();
    
        [...]
    
        this.connect();
    }
    
    connect() {
        if (this.tlsEnabled) {
            tls.connect({
                socket: this.client,
            })
        }
    
        this.client.connect({host: this.host, port: this.port});
    }
    

    但很明显我做错了,因为我最终 Error: read ECONNRESET 我的应用程序和IRC服务器出错 ngircd SSL protocol error: SSL_accept (error:1408F10B:SSL routines:ssl3_get_record:wrong version number) .

    怎么样 tls。连接() 当你通过一个现有的插座时,它还能工作吗?

    0 回复  |  直到 2 年前