node-ldapjs icon indicating copy to clipboard operation
node-ldapjs copied to clipboard

Handling econnreset on TLS connections

Open worldwidewoogie opened this issue 5 years ago • 3 comments

I have an environment where networking gear in between my client and the LDAP server routinely issues connection resets. I am attempting to gracefully handle them without the client crashing. I have code similar to the following to intercept the errors (actual logic of the error handling excluded):

client = ldap.createClient(options);

client.on('error', function(err) {
    console.dir(err);
})

This seems to handle unencrypted connections fine. I see log entries similar to the following:

[[14:57:00.486]] [DIR]    Error: read ECONNRESET
    at TCP.onStreamRead (internal/stream_base_commons.js:201:27) {
  errno: -104,
  code: 'ECONNRESET',
  syscall: 'read'
}

And, after my error handling, the code resumes as normal. However, on encrypted connections, I see log entries similar to the following:

[[13:14:31.788]] [DIR]    Error: read ECONNRESET
    at TLSWrap.onStreamRead (internal/stream_base_commons.js:201:27) {
  errno: -104,
  code: 'ECONNRESET',
  syscall: 'read'
}

and then my application exits. Is there some difference between TLSWrap.onStreamRead and TCP.onStreamRead that would cause the client.on to not intercept the error?

worldwidewoogie avatar May 05 '20 23:05 worldwidewoogie

What you have written looks to me like the error is being handled. You could supply a logger set trace level output to get some better insight.

jsumners avatar May 06 '20 11:05 jsumners

This might be related -- https://github.com/fastify/fastify/issues/2253

jsumners avatar May 06 '20 11:05 jsumners

I am running a forked version of promised-ldap, patched to use my error handling. You can find it here:

https://github.com/worldwidewoogie/promised-ldap/blob/master/index.js

Here is the source of my test script:

require('console-stamp')(console, '[HH:MM:ss.l]')

const sleep = (milliseconds) => {
    return new Promise(resolve => setTimeout(resolve, milliseconds))
}

async function doit() {
    while (true) {
        await sleep(500)
        console.dir('.')
        try {
            let ldap = require('promised-ldap')
            let ldapClient = new ldap({
                url: 'ldaps://ldap.example.com:636'
            })
            await ldapClient.bind('uid=a,dc=example,dc=com', 'x')
        }
        catch (e) {
            //console.dir('.')
            if (!e.lde_message || e.lde_message != 'Invalid Credentials') {
                console.dir(e)
            }
        }
    }
}

doit()

The script intentionally provides invalid credentials for the user. Here is the end of the output:

[[09:14:52.732]] [DIR] '.' [[09:14:53.531]] [DIR] '.' [[09:14:54.155]] [DIR] '.' [[09:14:54.782]] [DIR] '.' [[09:15:05.487]] [DIR] Error: read ECONNRESET at TLSWrap.onStreamRead (internal/stream_base_commons.js:201:27) { errno: -104, code: 'ECONNRESET', syscall: 'read' }

After that, the test script does not exit, but it sends no further output. If I change to non-TLS connection, I see the following:

[[10:03:27.077]] [DIR] '.' [[10:03:27.634]] [DIR] '.' [[10:03:28.325]] [DIR] '.' [[10:03:28.935]] [DIR] '.' [[10:03:29.484]] [DIR] '.' [[10:03:29.539]] [DIR] Error: read ECONNRESET at TCP.onStreamRead (internal/stream_base_commons.js:201:27) { errno: -104, code: 'ECONNRESET', syscall: 'read' } [[10:03:29.542]] [DIR] ConnectionError: 20__ldap://ldap.example.com:3890 closed at /home/woogie/src/iam/IAM-APIs/node_modules/ldapjs/lib/client/client.js:1277:17 at Array.forEach () at Client._onClose (/home/woogie/src/iam/IAM-APIs/node_modules/ldapjs/lib/client/client.js:1272:19) at Object.onceWrapper (events.js:300:26) at Socket.emit (events.js:210:5) at TCP. (net.js:659:12) { lde_message: '20__ldap://ldap.example.com:3890 closed', lde_dn: null }

...a bunch of connection reset errors elided...

[[10:04:17.504]] [DIR] '.' [[10:04:17.566]] [DIR] Error: read ECONNRESET at TCP.onStreamRead (internal/stream_base_commons.js:201:27) { errno: -104, code: 'ECONNRESET', syscall: 'read' } [[10:04:17.568]] [DIR] ConnectionError: 102__ldap://ldap.example.com:3890 closed at /home/woogie/src/iam/IAM-APIs/node_modules/ldapjs/lib/client/client.js:1277:17 at Array.forEach () at Client._onClose (/home/woogie/src/iam/IAM-APIs/node_modules/ldapjs/lib/client/client.js:1272:19) at Object.onceWrapper (events.js:300:26) at Socket.emit (events.js:210:5) at TCP. (net.js:659:12) { lde_message: '102__ldap://ldap.example.com:3890 closed', lde_dn: null } [[10:04:18.070]] [DIR] '.' [[10:04:18.819]] [DIR] '.' [[10:04:19.399]] [DIR] '.' [[10:04:19.966]] [DIR] '.' [[10:04:20.518]] [DIR] '.'

The script continues to execute until another cluster of resets occurs.

worldwidewoogie avatar May 06 '20 14:05 worldwidewoogie

👋

On February 22, 2023, we released version 3 of this library. As a result, we are closing this issue/pull request.

Please see issue #839 for more information, including how to proceed if you feel this closure is in error.

jsumners avatar Feb 22 '23 19:02 jsumners