Skip to content

Bad Host header when using ipv6 and the default protocol ports #3274

@bengentil

Description

@bengentil

Summary

In request.js:295 the Host header is set to the URI hostname when the URI port match the protocol port.

According to the RFCs, the Host header should be the host of the uri.
https://tools.ietf.org/html/rfc7230#section-5.4
https://tools.ietf.org/html/rfc7230#section-2.7.1
https://tools.ietf.org/html/rfc3986#section-3.2.2

The main difference here is with ipv6 where self.uri.host contains the ip between bracket + the port (eg. [2001:db8::1]:443) and self.uri.hostname only contains the ip without brackets (eg. 2001:db8::1).

This cause ipv6 URI to fail TLS verification as the calculateServerName function expect an ipv6 enclosed by brackets (https://github.com/nodejs/node/blob/a494d127236d09e4413631c33ee95c1324eb8814/lib/_http_agent.js#L275)

error: Hostname/IP does not match certificate's altnames: Host: 2001. is not in the cert's altnames: DNS:localhost, IP Address:0:0:0:0:0:0:0:1, IP Address:2001:DB8:1:0:0:242:AC11:2 

Simplest Example to Reproduce

  1. Generate a CA and a certificate valid for any ipv6 like 2001:db8::1 (::1 is a special case)
  2. Run a webserver on this ipv6 with this certificate
  3. Try to GET a ipv6 url (like https://[2001:db8::1]:443/
const request = require('request');
const fs = require('fs')

const options = {
   url: `https://[2001:db8::1]:443/`,
   ca: fs.readFileSync('ca.crt'),
   strictSSL: true,
};
request(options, function (error, response, body) {
    if (error) {
        console.log('error:', error.message); // Print the error if one occurred
    }
    console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
    console.log('body:', body); // Print the HTML for the Google homepage.
});

I made a docker image which does everything: setup certificates, run a server, try to get (fail), patch and retry (successfully): https://github.com/bengentil/request-ipv6-issue

Expected Behavior

Having a Host header matching the URI host (ipv6 with brackets)

Current Behavior

When using ipv6 + a standard port in the URI, the Host header become the ipv6 without the brackets

Possible Solution

Removing the condition that sets the Host header to the URI hostname

Context

https://github.com/cilium/hubble-ui/ won't work with ipv6 without this fixed

Your Environment

Latest node docker image

software version
request 2.88.2
node v13.8.0
npm 6.13.6
Operating System Debian stretch

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions