Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebTransportError: Opening handshake failed #166

Closed
darrachequesne opened this issue May 4, 2023 · 15 comments
Closed

WebTransportError: Opening handshake failed #166

darrachequesne opened this issue May 4, 2023 · 15 comments

Comments

@darrachequesne
Copy link

Hi! I'm trying to use the library, but can't achieve connection on Chrome (Version 110.0.5481.177, Ubuntu 20.04).

I've created a sample project reproducing the issue: https://github.com/darrachequesne/webtransport-example

I've taken a look at #76, but it does not seem to be related to the certificate.

It works with the Node.js client though. Thanks in advance!

@martenrichter
Copy link
Member

And, what is the error message on the browser side?

@martenrichter
Copy link
Member

And can you replace the certificate generating code, with the one we use in our unit tests.

@darrachequesne
Copy link
Author

The error in the console

Failed to establish a connection to https://localhost:3001/echo: net::ERR_CONNECTION_REFUSED.
Uncaught (in promise) WebTransportError: Opening handshake failed.

The certificate is valid (10 days validity), according to Chrome:

Screenshot from 2023-05-04 09-10-34

Screenshot from 2023-05-04 09-10-46

I'll try with the code in the unit tests.

@martenrichter
Copy link
Member

The error sounds more like a closed blocked port. Please check, which app is bound to which udp port....
And if the port in general is reachable. If you want to compile the binary yourself, I can also pinpoint you where to add debug output for seeing if someone tries to connect.

@darrachequesne
Copy link
Author

That's weird, the port seems to be open:

$ node client.js
load webtransport binary: ../build/Release/webtransport.node
start GlobalEventLoop
createGlobalEventLoop
Waiting for client to be ready
wait for session
Client ready
Client created stream

With netcat:

$ nc -vz -u 127.0.0.1 3001
Connection to 127.0.0.1 3001 port [udp/*] succeeded!

Tested on Chrome (110.0.5481.177) and Chromium (112.0.5615.49), with Node.js v16.15.1 and v18.12.1.

I feel there is something obvious I am missing.

If you want to compile the binary yourself, I can also pinpoint you where to add debug output for seeing if someone tries to connect.

Yes please.

@darrachequesne
Copy link
Author

Here are the debug logs of the session (in https://netlog-viewer.appspot.com):

327: WEB_TRANSPORT_CLIENT
https://localhost:3001/echo
Start Time: 2023-05-09 09:45:22.658

t=4615 [st=0] +QUIC_SESSION_WEBTRANSPORT_CLIENT_ALIVE  [dt=0]
               --> network_anonymization_key = "https://localhost"
               --> url = "https://localhost:3001/echo"
t=4615 [st=0]    QUIC_SESSION_WEBTRANSPORT_CLIENT_STATE_CHANGED
                 --> last_state = "NEW"
                 --> next_state = "CONNECTING"
t=4615 [st=0]   +PROXY_RESOLUTION_SERVICE  [dt=0]
t=4615 [st=0]      PROXY_RESOLUTION_SERVICE_RESOLVED_PROXY_LIST
                   --> pac_string = "DIRECT"
t=4615 [st=0]   -PROXY_RESOLUTION_SERVICE
t=4615 [st=0]   +HOST_RESOLVER_MANAGER_REQUEST  [dt=0]
                 --> allow_cached_response = true
                 --> dns_query_type = 0
                 --> host = "https://localhost:3001"
                 --> is_speculative = false
                 --> network_anonymization_key = "null"
                 --> secure_dns_policy = 0
t=4615 [st=0]      HOST_RESOLVER_MANAGER_IPV6_REACHABILITY_CHECK
                   --> cached = true
                   --> ipv6_available = true
t=4615 [st=0]   -HOST_RESOLVER_MANAGER_REQUEST
t=4615 [st=0]    QUIC_CONGESTION_CONTROL_CONFIGURED
                 --> congestion_control_type = "CUBIC_BYTES"
                 --> initial_congestion_window = 32
                 --> use_pacing = true
t=4615 [st=0]    QUIC_SESSION_TRANSPORT_PARAMETERS_SENT
                 --> quic_transport_parameters = "[Client legacy[version 00000001] [chosen_version 00000001 other_versions 00000001] max_idle_timeout 30000 max_udp_payload_size 1472 initial_max_data 15728640 initial_max_stream_data_bidi_local 6291456 initial_max_stream_data_bidi_remote 6291456 initial_max_stream_data_uni 6291456 initial_max_streams_bidi 100 initial_max_streams_uni 103 initial_source_connection_id 0 max_datagram_frame_size 65536 google_connection_options RVCM]"
t=4615 [st=0]    QUIC_SESSION_CRYPTO_FRAME_SENT
                 --> data_length = 281
                 --> encryption_level = "ENCRYPTION_INITIAL"
                 --> offset = 0
t=4615 [st=0]    QUIC_SESSION_PACKET_SENT
                 --> encryption_level = "ENCRYPTION_INITIAL"
                 --> packet_number = 1
                 --> sent_time_us = 8881032510
                 --> size = 320
                 --> transmission_type = "NOT_RETRANSMISSION"
t=4615 [st=0]    QUIC_SESSION_CRYPTO_FRAME_SENT
                 --> data_length = 281
                 --> encryption_level = "ENCRYPTION_INITIAL"
                 --> offset = 0
t=4615 [st=0]    QUIC_SESSION_PADDING_FRAME_SENT
                 --> num_padding_bytes = 930
t=4615 [st=0]    QUIC_SESSION_COALESCED_PACKET_SENT
                 --> info = "total_length: 1250 padding_size: 930 packets: {ENCRYPTION_INITIAL}"
t=4615 [st=0]    QUIC_READ_ERROR
                 --> net_error = -102 (ERR_CONNECTION_REFUSED)
t=4615 [st=0]    QUIC_SESSION_WEBTRANSPORT_CLIENT_STATE_CHANGED
                 --> error = {"details":"net::ERR_CONNECTION_REFUSED","net_error":-102,"quic_error":0}
                 --> last_state = "CONNECTING"
                 --> next_state = "FAILED"
t=4615 [st=0]    QUIC_SESSION_CLOSED
                 --> details = "net::ERR_CONNECTION_REFUSED"
                 --> from_peer = false
                 --> quic_error = 51 (QUIC_PACKET_READ_ERROR)
t=4615 [st=0] -QUIC_SESSION_WEBTRANSPORT_CLIENT_ALIVE
               --> net_error = -102 (ERR_CONNECTION_REFUSED)


@martenrichter
Copy link
Member

The best way to debug, is to check the source code out from GitHub and compile it with npm run debug-build . But I have also done it by going into the node_modules directory of the add-in by running the same command.

If it reaches the code here:

if (!info[0].IsUndefined())

The session establishment is nearly done.
Here:
QUICHE_DCHECK_EQ(fd, fd_);

The function called for every UDP packet, so if it is not called, the packets never reach the setup.
Here:
QuicConnection* connection =

you can see if a quick connection is established.
Here:
WebTransportRespPromisePtr promise = std::make_shared<WebTransportRespPromise>();

are WebTransport requests processed.
The whole file here:
QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list);

deals with the connection.
Any way if you put there some print code or place debugger break points, you should see how far it comes.

@darrachequesne
Copy link
Author

I have added a bunch of "cout << "..." << endl; but to no avail, the breakpoints you suggested are not reached...

Are you able to reproduce the issue with the example I provided above (https://github.com/darrachequesne/webtransport-example)? Or is it a problem with my own setup?

Else, is it possible that there is a compatibility issue with latest versions of chromium, as is suggested there?

@martenrichter
Copy link
Member

martenrichter commented May 15, 2023

I have added a bunch of "cout << "..." << endl; but to no avail, the breakpoints you suggested are not reached...

Ok interesting, if you are not hitting OnSocketEvent, then you get no UDP packet. So the UDP are not reaching your socket.
So it might be a network binding to the wrong port with the wrong address. So it looks like a firewall problem.

Are you able to reproduce the issue with the example I provided above (https://github.com/darrachequesne/webtransport-example)? Or is it a problem with my own setup?

I am only doing programming in my free time on weekends, and this weekend did not have enough time.
So sorry, I did not find the time.

Else, is it possible that there is a compatibility issue with latest versions of chromium, as is suggested there?

No I have run it against Chrome Canary on Sunday.

@martenrichter
Copy link
Member

May be look into the server start phase:

int port = 443;

@martenrichter
Copy link
Member

I am now trying it. First thing to note, it seems not to work with localhost, using a normal ip address it works. I will check if this is a problem in the webtransport module.
After this, it is complaining about the certificate. This is not astonishing, since it is not a known certificate authority, so you must pass the fingerprint, which is not part of the example. The ignore certificate stuff, I personally never got to work with chrome, but since I always use fingerprints it is not an issue for me.

@martenrichter
Copy link
Member

I have checked localhost. The code of the library translates it fine to 127.0.0.1 . However, the browser seems to have no clue what localhost ist, but it knows 127.0.0.1 . Could be a bug in chromium, would not be the first.

@darrachequesne
Copy link
Author

It does indeed seem to be linked to the usage of "localhost". If I create an alias in my /etc/hosts file:

$ cat /etc/hosts
127.0.0.1   localhost
127.0.0.1   example.com

And create a self-signed certificate for this domain, then I'm able to successfully reach the server 🚀

In case anyone is interested, here is the diff: darrachequesne/webtransport-example@46a9098

Thanks a lot for your help 👍

@darrachequesne
Copy link
Author

For future readers, using 127.0.0.1 instead of localhost works: https://github.com/darrachequesne/webtransport-example

generate_cert.sh

#!/bin/bash
openssl req -new -x509 -nodes \
    -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
    -out cert.pem -keyout key.pem \
    -subj '/CN=127.0.0.1'

open_chrome.sh

#!/bin/bash
HASH=`openssl x509 -pubkey -noout -in cert.pem |
   openssl pkey -pubin -outform der |
   openssl dgst -sha256 -binary |
   base64`

/opt/google/chrome/chrome \
    --origin-to-force-quic-on=127.0.0.1:3000 \
    --ignore-certificate-errors-spki-list=$HASH \
    https://localhost:3000

No alias needed 🚀

new WebTransport("https://localhost:3000/echo"); doesn't work though, which is a bit weird.

@martenrichter
Copy link
Member

new WebTransport("https://localhost:3000/echo"); doesn't work though, which is a bit weird.

And this may be a bug in chrome, or in my certificate-checking code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants