Closed Bug 1698061 Opened 4 years ago Closed 4 years ago

firefox accessing the wrong ipv6 address with http/2

Categories

(Core :: Networking, defect)

Firefox 86
defect

Tracking

()

RESOLVED DUPLICATE of bug 1420777

People

(Reporter: beaaegicfqmq6ryvbypaiqqdcnew6gismu, Unassigned)

Details

User Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0

Steps to reproduce:

I have a server with different vhosts in a mixed sni-setup. Each vhost has the same ipv4 address but different ipv6 addresses.

For example:
vhost1.domain.example A 192.0.2.1 AAAA 2001:db8:ffff::1
vhost2.domain.example A 192.0.2.1 AAAA 2001:db8:ffff::2
vhost3.domain.example A 192.0.2.1 AAAA 2001:db8:ffff::3

When accessing https://vhost1 firefox prefers ipv6 and connects to 2001:db8:ffff::1. Let's have vhost1 have some ajax or something running that keeps the connection open:

$ ss -ntp | grep 443
ESTAB 0      0      [2001:db8:aaaa::1]:42640 [2001:db8:ffff:1]:443  users:(("firefox",pid=12345,fd=123))

Now I try to access https://vhost2. See "what happened" and "what should have happened" for a tl;dr.

--%snip%--

  • How I tested:
  • create a dummy wildcard certificate *.domain.example and import the dummy ca to Firefox
  • use Oracle Linux 8 as server (should work with any distribution, but who knows?)
  • configure 192.0.2.1/32 and 2001:db8:ffff::{1..3} onto that server
  • install stock httpd: dnf -y module enable httpd:2.4 ; dnf -y install httpd mod_ssl mod_http2
  • add the wildcard certificate and key to /etc/pki/tls/certs resp. /etc/pki/tls/private
  • create document roots: /var/www/html/vhost{1..3}
  • add this script to /var/www/cgi-bin/vhost.py and make it executable:
#!/usr/bin/python3
import time
import os
print("Content-Type: text/plain\n")
print("Hello world!")
for k in ['SERVER_NAME', 'SERVER_ADDR', 'DOCUMENT_ROOT', 'SCRIPT_FILENAME']:
    print(f"{k}={os.environ.get(k)}")
time.sleep(10)
print("slept for 10s to keep the connection open")
  • add this config file to /etc/httpd/conf.d/vhosts.conf
Protocols h2 h2c http/1.1
<VirtualHost 192.0.2.1:80 [2001:db8:ffff::1]:80>
	Servername vhost1.domain.example
	DocumentRoot /var/www/html/vhost1
</VirtualHost>
<VirtualHost 192.0.2.1:80 [2001:db8:ffff::2]:80>
	Servername vhost2.domain.example
	DocumentRoot /var/www/html/vhost2
</VirtualHost>
<VirtualHost 192.0.2.1:80 [2001:db8:ffff::3]:80>
	Servername vhost3.domain.example
	DocumentRoot /var/www/html/vhost3
</VirtualHost>
<VirtualHost 192.0.2.1:443 [2001:db8:ffff::1]:443>
	Servername vhost1.domain.example
	DocumentRoot /var/www/html/vhost1
	SSLEngine on
	SSLCertificateFile /etc/pki/tls/certs/domain.example.pem
	SSLCertificateKeyFile /etc/pki/tls/private/domain.example.key
</VirtualHost>
<VirtualHost 192.0.2.1:443 [2001:db8:ffff::2]:443>
	Servername vhost2.domain.example
	DocumentRoot /var/www/html/vhost2
	SSLEngine on
	SSLCertificateFile /etc/pki/tls/certs/domain.example.pem
	SSLCertificateKeyFile /etc/pki/tls/private/domain.example.key
</VirtualHost>
<VirtualHost 192.0.2.1:443 [2001:db8:ffff::3]:443>
	Servername vhost3.domain.example
	DocumentRoot /var/www/html/vhost3
	SSLEngine on
	SSLCertificateFile /etc/pki/tls/certs/domain.example.pem
	SSLCertificateKeyFile /etc/pki/tls/private/domain.example.key
</VirtualHost>
  • add this to your /etc/hosts:
192.0.2.1 vhost1.domain.example vhost2.domain.example vhost3.domain.example
2001:db8:ffff::1 vhost1.domain.example
2001:db8:ffff::2 vhost2.domain.example
2001:db8:ffff::3 vhost3.domain.example

tab 1

Hello world!
SERVER_NAME=vhost1.domain.example
SERVER_ADDR=2001:db8:ffff::1
DOCUMENT_ROOT=/var/www/html/vhost1
SCRIPT_FILENAME=/var/www/cgi-bin/vhost.py
slept for 10s to keep the connection open

tab 2

Hello world!
SERVER_NAME=vhost2.domain.example
SERVER_ADDR=2001:db8:ffff::1
DOCUMENT_ROOT=/var/www/html/vhost1
SCRIPT_FILENAME=/var/www/cgi-bin/vhost.py
slept for 10s to keep the connection open

tab 3

Hello world!
SERVER_NAME=vhost3.domain.example
SERVER_ADDR=2001:db8:ffff::1
DOCUMENT_ROOT=/var/www/html/vhost1
SCRIPT_FILENAME=/var/www/cgi-bin/vhost.py
slept for 10s to keep the connection open
  • Additional information:
  • http (unencrypted) is not affected. Firefox connects to each of the ipv6 addresses
  • http/1.1 (encrypted) is not affected: one connection to each ipv6 address
  • afaict only http/2 is affected

Actual results:

I'd expect firefox to open a new connection to 2001:db8:ffff:2, but it reuses the existing connection (fd=123) and asks vhost1 for the content of vhost2:
--%snip%--
$ ss -ntp | grep 443
ESTAB 0 0 [2001:db8:aaaa::1]:42640 [2001:db8:ffff:1]:443 users:(("firefox",pid=12345,fd=123))
--%snip%--

So the browser shows "https://vhost2.domain.example/" in the address bar but the content of vhost1.

Expected results:

Firefox should have opened a new connection to 2001:db8:ffff:2.

The Bugbug bot thinks this bug should belong to the 'Core::DOM: Security' component, and is moving the bug to that component. Please revert this change in case you think the bot is wrong.

Component: Untriaged → DOM: Security
Product: Firefox → Core

(In reply to Release mgmt bot [:sylvestre / :calixte / :marco for bugbug] from comment #1)

The Bugbug bot thinks this bug should belong to the 'Core::DOM: Security' component, and is moving the bug to that component. Please revert this change in case you think the bot is wrong.

Seems rather like Necko ...

Component: DOM: Security → Networking

This seems to be another case of connection-coalescing issues.
https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/

Status: UNCONFIRMED → RESOLVED
Closed: 4 years ago
Resolution: --- → DUPLICATE

Thanks for the information on why this happens.

So there are actually two issues in here:

  1. firefox is wrongly reusing a connection
  2. apache httpd is not responding with a 421 even though the request was made for the wrong vhost

I believe the situation described in comment #0 of having a dual stack setup with one ipv4 address and multiple ipv6 addresses server side is not that extraordinary. While it's perfectly fine to reuse the connection for the ipv4 address that's shared between all vhosts, it's wrong with ipv6 where the ipv6 address does not match the host name (i.e. vhost3.domain.example does not resolve to 2001:db8:ffff:1). IMHO firefox should check whether or not the active connection is valid for that address.

The other thing is that apache httpd doesn't care about the "Host"-header after the connection is established (http/https):

$ curl -6 -H "Host: vhost3.domain.example" http://vhost1.domain.example/cgi-bin/vhost.py
Hello world!
SERVER_NAME=vhost3.domain.example
SERVER_ADDR=2001:db8:ffff::1
DOCUMENT_ROOT=/var/www/html/vhost1
SCRIPT_FILENAME=/var/www/cgi-bin/vhost.py
slept for 10s to keep the connection open

I worked around this by adding something like

<If "req('Host') != 'vhost3.domain.example'">
       Redirect 421 /
</If>

to my httpd configuration. Now Firefox is reconnecting to the correct address when falsely asking the wrong vhost. But I can do that only for my servers, so it'd be nice to make Firefox check for the current connection's validity before sending its request.

You need to log in before you can comment on or make changes to this bug.