deno: Fetching https://1.1.1.1 or any other bare IP address fails with 'invalid dnsname'

HTTPS fetch with bare IPv4 address fails:

> deno run --allow-net https://deno.land/std@0.70.0/examples/curl.ts https://1.1.1.1/
error: Uncaught Http: error sending request for url (https://1.1.1.1/): error trying to connect: invalid dnsname
    at Object.jsonOpAsync (core.js:236:13)
    at async fetch (deno:op_crates/fetch/26_fetch.js:1272:29)
    at async https://deno.land/std@0.70.0/examples/curl.ts:3:13

HTTPS fetch with bare IPv6 address fails:

> deno run --allow-net https://deno.land/std@0.70.0/examples/curl.ts https://[2606:4700:4700::1111]
error: Uncaught Http: error sending request for url (https://[2606:4700:4700::1111]/): error trying to connect: invalid dnsname
    at Object.jsonOpAsync (core.js:236:13)
    at async fetch (deno:op_crates/fetch/26_fetch.js:1272:29)
    at async https://deno.land/std@0.70.0/examples/curl.ts:3:13

Real curl is fine:

> curl -sI https://[2606:4700:4700::1111] | head -n1
HTTP/1.1 200 OK

> curl -sI https://1.1.1.1/ | head -n1
HTTP/1.1 200 OK

HTTPS fetch with DNS name that resolves to said IP addresses works:

> deno run --allow-net https://deno.land/std@0.70.0/examples/curl.ts https://one.one.one.one | grep \\.\\.
............................................................
.........1............1............1............1...........
........11...........11...........11...........11...........
.......111..........111..........111..........111...........
......1111.........1111.........1111.........1111...........
........11...........11...........11...........11...........
........11...........11...........11...........11...........
........11...........11...........11...........11...........
........11...........11...........11...........11...........
........11...........11...........11...........11...........
........11...........11...........11...........11...........
........11...........11...........11...........11...........
........11...........11...........11...........11...........
........11...........11...........11...........11...........
........11....ooo....11....ooo....11....ooo....11...........
......111111..ooo..111111..ooo..111111..ooo..111111.........
............................................................
> deno --version
deno 1.4.1
v8 8.7.75
typescript 4.0.2

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 18
  • Comments: 23 (13 by maintainers)

Commits related to this issue

Most upvoted comments

https://www.memorysafety.org/blog/rustls-new-features/

The first big feature is support for TLS certificates containing IP addresses. Rustls can now be used to set up TLS connections addressed by IP rather than a domain name. This is useful for things like Kubernetes pods, which often use IP addresses instead of domain names, and for DNS over HTTPS/TLS which need an IP address for the server to avoid circular dependency on name resolution. TLS certificates for IP addresses have been the most heavily requested feature for quite a while now and it’s great to have it completed.

Hello, this exact problem is probably off-topic for this thread, which is that Deno cannot connect to IP address hosts using HTTPS.


However, I can confirm that Deno has the above message when you try using a CA certificate directly on a server. I have a personal CA and just loaded up Deno HTTPS server using it. Resulting in:

> deno run --allow-net --cert /tmp/ca.crt https://deno.land/std@0.83.0/examples/curl.ts https://localhost:4443
Sending fatal alert BadCertificate
error: Uncaught (in promise) TypeError: error sending request for url (https://localhost:4443/): error trying to connect: invalid certificate: CAUsedAsEndEntity
    at processResponse (deno:core/core.js:223:11)
    at Object.jsonOpAsync (deno:core/core.js:240:12)
    at async fetch (deno:op_crates/fetch/26_fetch.js:1278:29)
    at async https://deno.land/std@0.83.0/examples/curl.ts:3:13

That being said, Google Chrome is also refusing to establish a connection:

This site can’t be reached The webpage at https://localhost:4443/ might be temporarily down or it may have moved permanently to a new web address. ERR_SSL_KEY_USAGE_INCOMPATIBLE

as well as curl:

> curl --cacert /tmp/ca.crt https://localhost:4443 
curl: (60) SSL certificate problem: unsupported certificate purpose
More details here: https://curl.se/docs/sslcerts.html

Wow, it looks like wget’s only problem is the hostname being wrong 😅

> wget --ca-certificate /tmp/ca.crt https://localhost:4443
--2021-01-03 22:12:24--  https://localhost:4443/
Loaded CA certificate '/tmp/ca.crt'
Resolving localhost (localhost)... ::1, 127.0.0.1
Connecting to localhost (localhost)|::1|:4443... connected.
The certificate's owner does not match hostname ‘localhost’

Surely I’d be able to golf a bit with the certificate’s usage flags to get one that works elsewhere, and while I’m there I could fix the CA flag as well.


It’s unfortunate that the rust TLS ecosystem is acting a bit stagnant. I personally am quite blocked by the IP address issue, to the point where I’m writing code like Deno.run({cmd: ["curl", "https://....."]}). Hopefully some movement happens with the recent work on webpki’s repo.

I’m trying to do something similar and I believe this issue has its roots deep down the Rust ecosystem.

Deno’s fetch() is implemented in the op_crates/fetch crate which uses reqwest to perform the http requests.

Inside that Cargo.toml, we see that the reqwest build uses rustls (https://github.com/denoland/deno/blob/master/op_crates/fetch/Cargo.toml#L18)

There is currently a limitation using Rustls when sending http requests to plain ip addresses (see https://github.com/ctz/rustls/issues/281) which seems to stem from https://github.com/briansmith/webpki/issues/54, an issue which has been open for 3 years.

It seems there’s not much you can do right now to get around this limitation apart from using a third-party request library which doesn’t use rustls

in the meantime, anyone who runs into this can create an entry in their hosts file as a workaround.

Based on this quote and my own use-case for this feature, perhaps a more practical step forward would be adding a parameter to replicate the servername option in Node.JS. The goal being that I could tell Deno what DNS name I expect the certificate to be good for. Then rustls should be able to validate successfully from there.

  • In the GKE (Kubernetes) situation I can expect that a cluster IP address certificate is also always good for kubernetes.default.svc.
  • In home automation perhaps the certificate is also good for localhost or similar.

I’d be ok telling Deno those servernames ^^ if it means avoiding ‘invalid dnsname’.

Of course the title issue should still be fixed, but upstream movement on it seems to be pretty slow.

Straight off it’s kinda odd that the docs give examples that don’t work, and the default argument to Deno.connectTls will result in an error but rather than create PRs for that let’s keep pushing in the other direction 😅 , making it work!

Going to see if I can drive this forward a little bit, because… well… I love Deno, but this was rather painful for me.

So as I understand it, connecting to a Postgres Database with no DNS, just a hostname, using TLS, currently fails.

Small code sample:

await Deno.connectTls({
  hostname: "34.76.80.151",
  port: 5432,
  certFile: "server-ca.pem",
});

Let’s see if we can get that one step closer to working 💪 !

I’ve been quiet for a year or so 😃 just checking in.

It looks like the error message is different nowadays (Deno 1.29.1) for IPv4: presented server name type wasn't supported

$ deno run --allow-net https://deno.land/std@0.70.0/examples/curl.ts https://1.1.1.1/
Sending fatal alert BadCertificate
error: Uncaught (in promise) TypeError: error sending request for url (https://1.1.1.1/): error trying to connect: presented server name type wasn't supported

Interestingly, IPv6 IPs still just report invalid dnsname 🤔

And, in fact, the request does now work with --unsafely-ignore-certificate-errors given to Deno, though I don’t plan on using that flag in practice. Providing an alternate servername would be a safer workaround ^_^

Looking upstream, it seems rustls 0.21.0 will include a step towards this issue. I look forward to seeing where that goes: