API connections with IPv6

Follow-up of: API connection via ipv6 vs. ipv4 - support - Discourse Meta

I recently upgraded Node.js from 18 to 20 and my application suddenly stopped getting API response back from Discourse. It took me a while to figure out it was related to the above issue. I verified this by making a connection only over IPv4 like:

import {Agent} from 'node:https'
import axios from 'axios'
import {env} from 'node:process'
export const axiosDiscourse = axios.create({
  baseURL: 'https://<discourse-url>',
  headers: {
    'api-key': env['DISCOURSE_KEY'],
    'api-username': env['DISCOURSE_USERNAME']
  },
  httpsAgent: new Agent({
    family: 4
  })
})

the important part being specifying the HTTP Agent - I was using it without that before. This now works, but I was in an attempt to migrate off Axios, so I can use other fetch-based libraries like Wretch (primarly to reduce the bundle size by using that in the frontend as well): elbywan/wretch: A tiny wrapper built around fetch with an intuitive syntax. :candy: (github.com). However, there’s no option to specify the IPv4 or IPv6 with fetch. Thus, I figured I need to either:

  1. Force using IPv4 only somehow and in spite of all my attempts so far, this has not been possible
  2. Check with Discourse on how I could get this working on IPv6.

I am connecting to various other APIs from my application, none have this issue, it’s only the connection with Discourse that’s failing.

This is the error I’m getting in case it helps:

Error: connect ETIMEDOUT 184.105.99.43:443
    at createConnectionError (node:net:1634:14)
    at Timeout.internalConnectMultipleTimeout (node:net:1685:38)
    at listOnTimeout (node:internal/timers:575:11)
    at processTimers (node:internal/timers:514:7) {
  errno: -110,
  code: 'ETIMEDOUT',
  syscall: 'connect',
  address: '184.105.99.43',
  port: 443
},
Error: connect ENETUNREACH 2602:fd3f:3:ff01::2b:443 - Local (:::0)
    at internalConnectMultiple (node:net:1176:40)
    at Timeout.internalConnectMultipleTimeout (node:net:1687:3)
    at listOnTimeout (node:internal/timers:575:11)
    at processTimers (node:internal/timers:514:7) {
  errno: -101,
  code: 'ENETUNREACH',
  syscall: 'connect',
  address: '2602:fd3f:3:ff01::2b',
  port: 443
}

What’s interesting is, unlike the above mentioned thread, I don’t get response after long. My request immediately fails with this error. The API call works fine in the browser, curl and anything else I can test.

My way of making a request to the API doesn’t matter as long as I’m making a request from my application. It simply fails and works only by using the family option as mentioned above. In the linked thread, I see this being mentioned:’

You’ll need to investigate why IPv6 connections don’t work on your network.

I have 2 concerns with that:

  1. I don’t know how to specifically check that.
  2. Not sure why this would be a problem only with Discourse, and only with my application.
1 Like

Another point to note, this happens only inside my WSL instance. If I run my application directly on my host Windows device, it’s able to connect fine.

I know this is probably something very specific to my setup, but I simply don’t know where to look for problems right now. Any pointers would be helpful!

1 Like

It looks like the library you’re using is attempting connections over both IPv4 and IPv6; that’s good news and means you don’t have the same problem as over here!

Let’s address them separately:

This means that your side set a TCP SYN to attempt the connection to the hosted instance, but didn’t get back a response. That generally means one of:

  • the request didn’t make it to the server
  • the server (or something along the path) deliberately silently dropped it
  • the response didn’t make it back to your machine

Since

it’s likely a problem with the networking setup on your machine.

This means your networking stack said “I can’t get there” and is fine since what you’re using evidently falls back to IPv4.

Looking at everything, I suspect:

  • IPv4 fails from your machine (it’s not clear if this is true, please verify — “it’s able to connect fine” might mean it’s using either IPv4 or IPv6)
  • IPv4 fails from your WSL container
  • IPv6 works from your machine
  • IPv6 fails from your WSL container

Please send a note to @team with your external IPv4 address and we’ll check to see if it’s being deliberately dropped - we do have some badly behaved IP ranges blocked and this will let us rule that out.

If, however, both IPv4 and IPv6 work from your machine but fail from your WSL container, that’s something you’ll need to solve with regards to your WSL setup.

Thank you so much for getting back.

Regarding your suspects, this is what I could test so far:

  • I tried disabling IPv6 from Windows settings:

Which, as per my understanding should make connections only from IPv4. If yes, that worked.

  • I tried running:
 curl -4 https://<host>/latest.json?order=created

from WSL and it worked fine (I got the response)

  • Not sure how I can test only IPv6 because as soon as I disable IPv4 similar to IPv6 from the above screenshot (while leaving IPv6 on), my PC basically got disconnected from the internet - all connections failed which could be expected.

  • I tried:

 curl -6 https://<host>/latest.json?order=created -v
*   Trying 2602:fd3f:3:ff01::2b:443...
* Immediate connect fail for 2602:fd3f:3:ff01::2b: Network is unreachable
* Closing connection 0
curl: (7) Couldn't connect to server

from WSL and that failed… instantly.

I ran into some troubles with WSL today, so I ended up configuring a fresh installation. This is a brand new instance with simply asdf and Node.js installed (and all system packages updated). Not sure if this is still related to some misconfiguration in the WSL end - I should be using all the defaults right now.

I’m sharing my public IPv4 address to the mentioned group.

Oh well, I don’t see a way to send a private message yet, probably because I’m a new user.

Something more interesting… when I was checking my public IPv4 address, the website attempted to show me my IPv6 address as well and said, IPv6 not detected. So, I went ahead to check if I have a IPv6 connection at all, and I found this page: How to set up IPv6 service on the TP-Link wireless router

It shows that routers should have a dedicated section to use IPv6. My router doesn’t have one and I also don’t get the PPPoE v6 option as shown there. So maybe, my router doesn’t support IPv6 at all - which could be why IPv6 connections are failing (and also why I basically lost internet connectivity when I disabled IPv4 in Windows settings).

EDIT: I have this router TL-WR841N | 300Mbps Wireless N Router | TP-Link India and it says IPv6 supported :thinking:

EDIT2: But using something like: v6.testmyipv6.com gives me ERR_NAME_NOT_RESOLVED, so looks like IPv6 is indeed not working for me.

If that’s the problem, I still don’t know why this started to happen suddenly. It was working fine for quite some time.

I’ve given you a little bump. :slight_smile: You should see the message button if you click on @team now. :+1:

1 Like

Thanks, sent!

1 Like

Additional data point, I switched to hotspot from my mobile network which uses IPv6. I can now verify using:

curl -6 https://<host>/latest.json?order=created -v
*   Trying 2602:fd3f:3:ff01::2b:443...
* Immediate connect fail for 2602:fd3f:3:ff01::2b: Network is unreachable
* Closing connection 0
curl: (7) Couldn't connect to server

still fails in a similar way. However, with IPv4 disabled in Windows settings, I am able to access the internet unlike before. So new data:

  • IPv4 on Windows: Works
  • IPv6 on Windows: Works
  • IPv4 on WSL: Works
  • IPv6 on WSL: Fails

If I don’t specify -4 or -6 to curl, it falls back to IPv4 (IPv6 fails immediately):

curl https://<host>/latest.json?order=created -v
*   Trying 184.105.99.43:443...
*   Trying 2602:fd3f:3:ff01::2b:443...
* Immediate connect fail for 2602:fd3f:3:ff01::2b: Network is unreachable
* Connected to <host> (184.105.99.43) port 443 (#0)

I also ran:

ping -6 google.com

From Windows as well as WSL. It works on Windows, fails in WSL. I think I now have enough info and validation that something is going wrong with my WSL instance’s IPv6 connectivity. Looks like an issue: cannot reach ipv6 only address · Issue #4518 · microsoft/WSL (github.com)

Finally!

Based on the above linked discussion, I was able to add

[experimental]
networkingMode=mirrored

to .wslconfig and that gave me IPv6 connectivity inside my WSL instance. I can now successfully run:

curl -6 https://<host>/latest.json?order=created

It still doesn’t work on my WiFi though and that’s very likely becuase this old router doesn’t support IPv6. It works fine when using my phone’s hotspot.

Thank you so much @JammyDodger for the pointers, you led me in the right direction!

OK, so something evidently changed in between the original post and this, since you were getting:

Glad to see it’s working now.

Yeah, that still baffles me. As I had mentioned before, I was able to send a curl request through WSL even before and that would work. Somehow, it was failing using Axios in my application (maybe that’s an Axios or a Node.js thing?).

Somehow, the curl -4 still works, and Axios also works when I specify the httpFamily as shown in my original post. But that’s not an error I’m going to lose any further of my sleep over.

Just for sanity check, I reverted back to Node.js 18 and I was able to connect without specifying the httpFamily so this is definitely something that has changed in Node.js 19 or 20. But due to that, I at least figured out about this IPv6 thing, or else I would still not have searched or learned about this.

I’m also able to run the code with bun instead of Node.js without having to specify the IPv4 thing. I have reached out to Node.js: What exactly changed between Node.js 18 and Node.js 20 that's causing my API requests to fail? · nodejs · Discussion #50826 · GitHub