Skip to content

Allow upgrading from HTTP/1.1 to other protocols#481

Closed
chtsanti wants to merge 108 commits intosquid-cache:masterfrom
measurement-factory:SQUID-323-WebSocket-support
Closed

Allow upgrading from HTTP/1.1 to other protocols#481
chtsanti wants to merge 108 commits intosquid-cache:masterfrom
measurement-factory:SQUID-323-WebSocket-support

Conversation

@chtsanti
Copy link
Contributor

@chtsanti chtsanti commented Sep 26, 2019

Support admin-authorized HTTP Upgrade-driven (RFC 7230 Section 6.7)
protocol switching. The new http_upgrade_request_protocols configuration
directive allows admin to control what client Upgrade offer(s) are
forwarded to the server. Squid does not automatically check whether the
server selection matches one of the client offers, but the admin can
deny unacceptable server responses using http_reply_access.

By default, Squid still does not forward any Upgrade headers,
effectively blocking an upgrade attempt.

Squid itself does not understand the protocols being upgraded to and
participates in the upgraded communication only as a dumb TCP proxy.

This is a Measurement Factory project.

@yadij
Copy link
Contributor

yadij commented Sep 27, 2019

Squid itself does not understand the protocols being upgraded to and
participates in the upgraded communication only as a dumb TCP proxy.

This violates the RFC7230 requirement:

server MUST NOT switch protocols unless the received message semantics can be honored by the new protocol;

In other words, Squid has to understand the new protocol sufficiently to perform any handshake protocol and message translation from the HTTP request into other protocol native format for that request - including understanding whether tunnel is the correct thing to do. We simply cannot do that generically - such as the "OTHER" being added by this PR.

Even WebSocket/1 needs some translation, it is intentionally and explicitly not tolerant of HTTP/1 syntax violations in its handshake message. The Parser changes I/we have been doing have fixed a lot of those, but the handling of unknown and generic String headers and field-values has yet to happen. This PR in its current design would make it possible to DoS a WebSocket server behind Squid.

@chtsanti
Copy link
Contributor Author

Squid itself does not understand the protocols being upgraded to and
participates in the upgraded communication only as a dumb TCP proxy.

This violates the RFC7230 requirement:

We are violating RFCs in other cases too for example when we are allowing to add or remove http headers, when we are ignoring Cache-Control etc.
Upgrading to other protocols by default is not enabled and uses acls.
We can add a related WARNING in http_upgrade_request_protocols documentation.

This PR in its current design would make it possible to DoS a WebSocket server behind Squid.

I do not believe that it is more dangerous than allowing CONNECT tunnels through squid.

@rousskov
Copy link
Contributor

Squid itself does not understand the protocols being upgraded to and
participates in the upgraded communication only as a dumb TCP proxy.

This violates the RFC7230 requirement:

server MUST NOT switch protocols unless the received message semantics can be honored by the new protocol;

The quoted Squid behavior (i.e. "This") does not violate (and does not even relate to!) the quoted MUST: Before Squid switches protocols, the Squid admin has to tell Squid that the "received message" (e.g., a GET request) "semantics can be honored by the new protocol". (The origin server also confirms that admin's determination before the protocols are switched, but that is secondary).

In other words, Squid has to understand the new protocol sufficiently to perform any handshake protocol and message translation from the HTTP request into other protocol native format for that request - including understanding whether tunnel is the correct thing to do.

There is no such requirement in the RFC text you quoted. In other words, you are misrepresenting what that MUST actually requires. Not all protocols can be tunneled, of course. Squid knows that it can tunnel in each particular case because the admin told Squid that it can (and the origin server confirmed).

We simply cannot do that generically - such as the "OTHER" being added by this PR.

We are not doing this generically, not even in the OTHER case. In all cases, there is an explicit instruction from the admin. Needless to say, the admin may misconfigure Squid, but that is true for most Squid features.

Even WebSocket/1 needs some translation, it is intentionally and explicitly not tolerant of HTTP/1 syntax violations in its handshake message.

@yadij, it is not clear how your statement relates to this PR. Are you implying that this PR does not support any WebSocket/1 upgrades? Let's start with the basic/targeted case of a trusted client attempting an HTTP Upgrade to a trusted server behind Squid, with Squid admin permission (based on tests, knowledge of the application, etc.). Is this PR lacking something critical in that case?

@chtsanti, do WebSocket/1 upgrades work in your tests?

This PR in its current design would make it possible to DoS a WebSocket server behind Squid.

Since virtually any design would make it possible to DoS a WebSocket server behind Squid, you need to be a lot more specific in your criticism for Christos to be able to actually address your concerns. To simplify, let's start with the basic/targeted case of a trusted client attempting an HTTP Upgrade to a trusted server behind Squid, with a well-informed Squid admin permission. Does this PR make things worse in that case?

@rousskov rousskov added S-waiting-for-author author action is expected (and usually required) S-waiting-for-more-reviewers needs a reviewer and/or a second opinion labels Oct 8, 2019
@chtsanti chtsanti force-pushed the SQUID-323-WebSocket-support branch from 786cf26 to 9128cf4 Compare October 9, 2019 14:36
@chtsanti
Copy link
Contributor Author

chtsanti commented Oct 9, 2019

I am not an websockets expert so somethings from the following I am writing maybe are not accurate.

Even WebSocket/1 needs some translation, it is intentionally and explicitly not tolerant of HTTP/1 syntax violations in its handshake message.

@yadij, it is not clear how your statement relates to this PR. Are you implying that this PR does not support any WebSocket/1 upgrades? Let's start with the basic/targeted case of a trusted client attempting an HTTP Upgrade to a trusted server behind Squid, with Squid admin permission (based on tests, knowledge of the application, etc.). Is this PR lacking something critical in that case?

@chtsanti, do WebSocket/1 upgrades work in your tests?

My understanding is that @yadij refers to Websockets emulation protocol which is uses HTTP request/responses to transfer websockets packets. These requests must include between others the header "X-WebSocket-Version: wseb-1.0". I found very few information on web about this protocol. However looks that this is should work in squid and without this patch.

The websockets protocol described in RFC6455 and which is uses the upgrade mechanism works very well using this patch in my tests.

Simple tests someone can do using the following urls:
http://demos.kaazing.com/echo/index.html
https://www.websocket.org/echo.html

The first one uses the websockets emulation protocol when plain websockets is selected (I suppose to overcome possible proxy problems) but normal websockets if TLS is used. You can test TLS websockets using SSL bumping.

@chtsanti chtsanti removed the S-waiting-for-author author action is expected (and usually required) label Oct 10, 2019
squid-anubis pushed a commit that referenced this pull request Oct 12, 2019
This patch implements the http_upgrade_request_protocols configuration
parameter to controls client-initiated and server-confirmed switching
from  HTTP to another protocol (or to several protocols) using HTTP
Upgrade mechanism (RFC 7230 Section 6.7).

Squid itself does not understand the protocols being upgraded to and
participates in the upgraded communication only as a dumb TCP proxy.

This is a Measurement Factory project
@squid-anubis squid-anubis added M-waiting-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels M-passed-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels and removed M-waiting-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels M-passed-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels labels Oct 12, 2019
@rousskov
Copy link
Contributor

@yadij, any objections to this going in? It looks like Christos is certain the code works for the targeted WebSocket use case. It is not clear whether you were talking about that case or something else in your original comment. If you have objections, please block this PR and clarify your remaining concerns. Otherwise, Christos should clear this PR for merge.

@rousskov rousskov added the S-waiting-for-committer privileged action is expected (and usually required) label Oct 16, 2019
@squid-anubis squid-anubis removed the M-passed-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels label Oct 19, 2019
@chtsanti chtsanti force-pushed the SQUID-323-WebSocket-support branch from 9128cf4 to 47916f2 Compare October 23, 2019 13:35
Copy link
Contributor

@rousskov rousskov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not reviewed the code, but I accidentally noticed that it is using std::function. I want to make sure its overhead is justifiable. Please give me a day or two to check the corresponding code.

@rousskov rousskov removed the S-waiting-for-committer privileged action is expected (and usually required) label Oct 23, 2019
@chtsanti
Copy link
Contributor Author

I have not reviewed the code, but I accidentally noticed that it is using std::function. I want to make sure its overhead is justifiable.

Could we use something like the following instead:
const MemberFilter ft = [item, ilen](const char *check, int checkLen) { ...}
bool found = strListIsMember_if(upgradeHeaderOut, ',', ref(ft));

Else we can use a pointer to standard C function instead or a class.

Please give me a day or two to check the corresponding code.

yep

Copy link
Contributor

@rousskov rousskov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chtsanti, I am still finding and fixing problems, but I have several questions that you may be able to help me with, parallelizing our work. Please see inlined change requests.

Copy link
Contributor

@rousskov rousskov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix two out of three issues we have discussed. Please see inlined change requests for details.

@rousskov rousskov added the S-waiting-for-author author action is expected (and usually required) label Nov 5, 2019
@rousskov rousskov added S-waiting-for-reviewer ready for review: Set this when requesting a (re)review using GitHub PR Reviewers box and removed S-waiting-for-author author action is expected (and usually required) labels May 29, 2020
rousskov added 5 commits May 29, 2020 15:32
I had to move NamedGuard::NamedGuard STUB to the end of the file
because, AFAICT, astyle gets confused by a combination of member
initializations and a braceless STUB_NOP. I did not want to use braces
around STUB_NOP (even though some code uses them) because they should
not be needed (and most code does not use them).

Bad lambda formatting highlights astyle v2.04 limitations. I do not know
if modern astyle can handle lambdas better. I suspect clang-format can.
Copy link
Contributor

@rousskov rousskov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am content with the current PR state and do not plan doing further reviews or polishing.

@rousskov rousskov dismissed their stale review May 29, 2020 21:28

My change request has been addressed.

@rousskov
Copy link
Contributor

I polished PR description to fix a typo, emphasize what controls the admin has, and document that the default no-upgrades behavior is preserved.

Copy link
Contributor

@yadij yadij left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No objections from me to current implementation.

@yadij yadij added M-cleared-for-merge https://github.com/measurement-factory/anubis#pull-request-labels and removed S-waiting-for-reviewer ready for review: Set this when requesting a (re)review using GitHub PR Reviewers box labels Jun 1, 2020
squid-anubis pushed a commit that referenced this pull request Jun 1, 2020
Support admin-authorized HTTP Upgrade-driven (RFC 7230 Section 6.7)
protocol switching. The new http_upgrade_request_protocols configuration
directive allows admin to control what client Upgrade offer(s) are
forwarded to the server. Squid does not automatically check whether the
server selection matches one of the client offers, but the admin can
deny unacceptable server responses using http_reply_access.

By default, Squid still does not forward any Upgrade headers,
effectively blocking an upgrade attempt.

Squid itself does not understand the protocols being upgraded to and
participates in the upgraded communication only as a dumb TCP proxy.

This is a Measurement Factory project.
@squid-anubis squid-anubis added the M-waiting-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels label Jun 1, 2020
@rousskov rousskov removed the review-1 label Jun 1, 2020
@squid-anubis squid-anubis added M-merged https://github.com/measurement-factory/anubis#pull-request-labels and removed M-cleared-for-merge https://github.com/measurement-factory/anubis#pull-request-labels M-waiting-staging-checks https://github.com/measurement-factory/anubis#pull-request-labels labels Jun 1, 2020
squidadm pushed a commit to squidadm/squid that referenced this pull request Jun 11, 2020
Support admin-authorized HTTP Upgrade-driven (RFC 7230 Section 6.7)
protocol switching. The new http_upgrade_request_protocols configuration
directive allows admin to control what client Upgrade offer(s) are
forwarded to the server. Squid does not automatically check whether the
server selection matches one of the client offers, but the admin can
deny unacceptable server responses using http_reply_access.

By default, Squid still does not forward any Upgrade headers,
effectively blocking an upgrade attempt.

Squid itself does not understand the protocols being upgraded to and
participates in the upgraded communication only as a dumb TCP proxy.

This is a Measurement Factory project.
yadij pushed a commit that referenced this pull request Jun 11, 2020
Support admin-authorized HTTP Upgrade-driven (RFC 7230 Section 6.7)
protocol switching. The new http_upgrade_request_protocols configuration
directive allows admin to control what client Upgrade offer(s) are
forwarded to the server. Squid does not automatically check whether the
server selection matches one of the client offers, but the admin can
deny unacceptable server responses using http_reply_access.

By default, Squid still does not forward any Upgrade headers,
effectively blocking an upgrade attempt.

Squid itself does not understand the protocols being upgraded to and
participates in the upgraded communication only as a dumb TCP proxy.

This is a Measurement Factory project.
yadij pushed a commit to yadij/squid that referenced this pull request Aug 17, 2020
Support admin-authorized HTTP Upgrade-driven (RFC 7230 Section 6.7)
protocol switching. The new http_upgrade_request_protocols configuration
directive allows admin to control what client Upgrade offer(s) are
forwarded to the server. Squid does not automatically check whether the
server selection matches one of the client offers, but the admin can
deny unacceptable server responses using http_reply_access.

By default, Squid still does not forward any Upgrade headers,
effectively blocking an upgrade attempt.

Squid itself does not understand the protocols being upgraded to and
participates in the upgraded communication only as a dumb TCP proxy.

This is a Measurement Factory project.
@RoieRMeta
Copy link

RoieRMeta commented Oct 11, 2020

Does this PR have any relation with running websockets via ssl_bump ?

@yadij
Copy link
Contributor

yadij commented Oct 11, 2020

Sorry got the previous reply backwards. A WebSockets client which is correctly using the opening handshake inside TLS would be decrypted and reach this feature for handling as WebSockets.

@rousskov
Copy link
Contributor

Does this PR have any relation with running websockets via ssl_bump?

This PR adds a feature that allows Squid to support HTTP Upgrade, including "upgrade" to a WebSocket tunnel. The PR itself is unrelated to SslBump, but we hope that the feature works for bumped HTTPS connections just like it works for plain HTTP connections.

@RoieRMeta
Copy link

Are there plans to merge this feature to branch 4.x ?

@yadij
Copy link
Contributor

yadij commented Oct 24, 2020

Are there plans to merge this feature to branch 4.x ?

No. Squid-4 has been in production release for several years already and its merge criteria is restricted to changes such as bugs and security issues. This is a relatively large behavioural change that adds risk of adding stability problems to a few popular features.

Squid-5 is close to production ready and should be usable if this is a required feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

M-merged https://github.com/measurement-factory/anubis#pull-request-labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants