actions / runner-images

GitHub Actions runner images
MIT License
10.1k stars 3.04k forks source link

Cannot send outbound requests using node fetch, failing with IPv6 DNS error UND_ERR_CONNECT_TIMEOUT #9540

Closed undergroundwires closed 7 months ago

undergroundwires commented 7 months ago

Description

Sending more than one (sometimes two or three) requests using fetch results in DNS errors.

I get UND_ERR_CONNECT_TIMEOUT errors which is related to IPv6 issues in node. Related issue for node: nodejs/node#41625, Related issue for node fetch: nodejs/undic#1531 Related issue for GitHub runners not being able to do IPv6: actions/runner-images#668, actions/runner#3138 image

Platforms affected

Runner images affected

Image version and build link

Failed build: https://github.com/undergroundwires/node-fetch-ipv6/actions/runs/8350276298

Is it regression?

Yes, successful build runs are old

Expected behavior

The requests are being sent fine, this was the case before.

Actual behavior

I created a repository to reproduce this in as minimal way as possible: https://github.com/undergroundwires/node-fetch-ipv6

I run fetch on using vite test runner on node and without any test runner. I get same results. I realize that the first two requests are successful, I start getting the error after the second or third one.

See the test: test file

Second test (multiple fetch in order) fails, and all run fine locally. I run tests on default GitHub runners using both latest node 20 and 18. I get same errors:

Repro steps

  1. Run the job from undergroundwires/node-fetch-ipv6
  2. Check output
Alexey-Ayupov commented 7 months ago

Hello @undergroundwires, do I understand correctly that you are trying to fetch using ipv6?

undergroundwires commented 7 months ago

I @Alexey-Ayupov. According to my research, the error UND_ERR_CONNECT_TIMEOUT related to DNS, and community reports mostly about IPv6, that's why I brought up IPv6. I cannot relate this to any outbound request limitation, even second/third requests fails after 10 seconds interval.

The test failing is simple:

const urls = [
    'https://web.archive.org/web/20221029145712/https://kb.mozillazine.org/Downloads.rdf',
    'https://web.archive.org/web/20240120213614/https://techcommunity.microsoft.com/t5/windows-it-pro-blog/group-configuration-search-highlights-in-windows/ba-p/3263989',
    'https://web.archive.org/web/20230929132845/https://support.microsoft.com/en-us/topic/compatibility-update-for-keeping-windows-up-to-date-in-windows-server-2012-r2-and-windows-server-2008-r2-sp1-c62197fb-d711-f7d3-f135-172844b9f322',
    'https://web.archive.org/web/20231004100105/https://nvd.nist.gov/vuln/search/results?form_type=Basic&results_type=overview&query=microsoft+store&queryType=phrase&search_type=all&isCpeNameSearch=false',
    'https://web.archive.org/web/20240219205516/https://wiki.archlinux.org/title/spotify',
    'https://web.archive.org/web/20240119160347/https://github.com/undergroundwires/privacy.sexy/issues/247',
    'https://web.archive.org/web/20231206171559/https://bestgamingtips.com/fix-xbox-identity-provider-not-working/',
    'https://web.archive.org/web/20230806192800/https://www.hexacorn.com/blog/2018/09/02/beyond-good-ol-run-key-part-86/',
    'https://web.archive.org/web/20231020012236/https://answers.microsoft.com/es-es/windows/forum/all/windows-10-carpeta-y-archivos-sih/4d318121-fed6-4202-8b92-d4dc236b468e',
    'https://web.archive.org/web/20221029141626/https://kb.mozillazine.org/Places.sqlite'
  ];
  for (const url of urls) {
    console.log('Fetching: ', url);
    const response = await fetch(url, { method: 'HEAD'});
    await sleep(10000);
    expect(response.status).to.equal(200);
  }

The error I'm getting after first, sometimes second request:

Caused by: ConnectTimeoutError: Connect Timeout Error
mikhailkoliada commented 7 months ago

hosted runners do not support ipv6 yet, that is why every "real" ipv6 inquiry will fail, and there is no ETA on ipv6 fully available unfortunately.

undergroundwires commented 7 months ago

Hi @mikhailkoliada, I tested more and verify that this is not about IPv6 requests being made.

This is how I prove it's not about IPv6 resolution directly:

I get UND_ERR_CONNECT_TIMEOUT regardless.

Can it be possible that this is because of some ongoing connection (network/DNS requests) limitation in the image or cloud service you're running?

undergroundwires commented 6 months ago

Here's my workaround (open-source and documented) that I hope that can help you too:

After days of research and trial/error, this is how I got this working:

  1. Create a script called force-ipv4.sh, that configures system to prefer IPv4 over IPv6, call it to configure the machine. It was not easy to find a reliable cross-platform solution and I went Cloudflare WARP for DNS resolution along with some system configurations.
  2. To easily use the script in GitHub workflows, create GitHub action called force-ipv4 and call it in GitHub runners.
  3. Fixes the IPv6 request issues, and you can happily run e.g. fetch API from Node.

Related commit introducing this fix: https://github.com/undergroundwires/privacy.sexy/commit/52fadcd6177ed06216be9c67dad57192ae02a4f9