Skip to content

Allow ALPN fallback #45056

@pimterry

Description

@pimterry

What is the problem this feature will solve?

I want to create a TLS server that uses ALPN but accepts all protocols from the client.

There's all sorts of interesting cases for this, but the simplest is when the server is really a TLS-terminating proxy of some kind that's just forwarding data upstream. ALPN is necessary in these cases because some clients (e.g. GRPC) will completely fail to connect to a server that does not explicitly support their protocol of choice. I suspect that'll become even more common in future as ALPN becomes widespread outside HTTP/2.

My case is a little more specific: my server is a proxy that supports network debugging, and I specifically want to accept all protocols so that I can capture and debug unexpected traffic, rather than rejecting it at the door. I think this applies more widely though.

What is the feature you are proposing to solve the problem?

An additional TLS server option like allowALPNFallback: <boolean>.

If set, at the end of the SelectALPNCallback callback if status == OPENSSL_NPN_NEGOTIATED then SSL_TLSEXT_ERR_OK should be returned instead of SSL_TLSEXT_ERR_ALERT_FATAL, thereby accepting the out value set by SSL_select_next_proto in the lines above.

I believe this works because the feature described is already the default behaviour of OpenSSL's SSL_select_next_proto function, which sets out in this callback to the client's first protocol preference by default if no matching server protocol is found. Docs here: https://www.openssl.org/docs/man3.0/man3/SSL_select_next_proto.html. The only reason that this doesn't work already is the additional check the Node adds, which sends an alert and kills the connection instead.

What alternatives have you considered?

I've opened this because this behaviour was recently changed in Node 19 in #44031. Previously in many cases it was possible to at least detect and in some cases fudge these connections because the connection continued (without an ALPN response but without failure) despite the lack of ALPN protocol agreement. Now it will always be rejected explicitly, which makes this use case more complicated.

I do agree the new behaviour in #44031 is correct as the default, but I just don't think that the RFC quoted there mandates this strict behaviour for all TLS servers. As quoted in that PR, the RFC says:

It is expected that a server will have a list of protocols that it supports, in preference order, and will only select a protocol if the client supports it. In that case, the server SHOULD select the most highly preferred protocol that it supports and that is also advertised by the client. In the event that the server supports no protocols that the client advertises, then the server SHALL respond with a fatal "no_application_protocol" alert.

In my case, the server effectively supports all protocols (i.e. it doesn't care, it's just proxying raw traffic) and so it's not required to send the alert - it's reasonable to accept the client's preference for unknown protocols.

A more general alternative would be an ALPN callback, to allow TLS servers to implement arbitrary logic like this or other ways to pick the ALPN protocol from JS directly. Imo that's interesting and all very cool, but not really necessary, and quite a bit more complicated, so probably not worthwhile. Could be worth considering if others see a good use cases for this though.

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestIssues that request new features to be added to Node.js.tlsIssues and PRs related to the tls subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions