TL:DR How to add a warning banner to a web service, when a user visits via IPv4

User awareness for LegacyIP

Recently, I got myself an IPv6-only network, and since then I’m figuring out how to design service connectivity for LegacyIP (also called IPv4). Using LegacyIP addresses in my own network is no option.

My goal is to run IPv6-only services. To realise this, IPv6-Deployment must improve. As I am writing these lines, Google states roughly 50% of German requests are using IPv6. What about the other half?

A key component could be user awareness. Me myself, I moved my mobile plan away from Telefonica, as I got tired of using a VPN each time I needed IPv6. If a relevant part of non-techie End-Users became aware of the problem, maybe more providers and networks would deploy IPv6 over time.

My idea is to warn users when they access a webservice via LegacyIP. As you may have noticed, if you visit over an IPv4-only network.

An additional site (currently WIP) should provide more information. Something like a TLDR of ipv6.jetzt for end users seems reasonable.

Transparently inject IPv4-warnings with nginx

At the moment, I have a central NGINX Reverse-Proxy, which terminates all HTTP(S)-Traffic. At that point, I want to transparently insert the warning. Therefore, I’ll use the nginx “substitutions_filter”-module to rewrite the closing </body>-Tag of the website, and inject the warning banner if the connection comes over LegacyIP.

This way it’s possible to inject the banner without messing up the application code - for example into CodiMD as shown below:

Banner stating that the website is visited via IPv4

If you click on the banner, it will set a cookie and hide the banner for a day.

The full code is available on GitLab. Hosting a Project promoting IPv6 on GitHub would be “interesting” at the moment, so I decided to go with GitHub.

To realize this on your own, you need to add two snippets to your nginx config. There are three blocks of code you need to insert into your vhost:

On the top, outside of your server-block, the distinction between LegacyIP and IPv6 takes place, inspired by ungleich.ch.

geo $ipv4 {
    0.0.0.0/0 ipv4;
}

In your server-block, you need to embed the snippet serving the Javascript:

include /etc/nginx/snippets/legacy-js.conf;

Of course, the location depends on your nginx configuration.

The biggest change is needed inside the location block, where the rewriting happens:

# IP Legacy Banner
sub_filter_types text/html;
include /etc/nginx/snippets/legacy-banner.conf;
if ($ipv4 ~ "^$") {
        set $legacy "</body>"; # Do not modify, IPv6 is used
}
sub_filter "script-src" "script-src 'unsafe-inline'";
sub_filter "</body>" $legacy;

The injected code itself is available in the legacy-banner.conf snippet.

Please note, that the Javascript only works if your Content Security Policy allows scripts from 'self' to be executed. This may depend on your application. You also may need to force the upstream not to use any content compression (like gzip) by adding proxy_set_header Accept-Encoding ""; to your proxy configuration.

The whole vhost could look like this:

geo $ipv4 {
    0.0.0.0/0 ipv4;
}

server {
	#Listen SSL+HTTP/2
	listen 443 ssl http2;
	listen [::]:443 ssl http2;

	#Security Stuff
	include /etc/nginx/snippets/security.conf;

	#Server Name
	server_name margau.net *.margau.net;

	include /etc/nginx/snippets/legacy-js.conf;

	#Forward all
	location / {
		proxy_pass (some-upstream);
		include /etc/nginx/proxy_params.conf;
		# IP Legacy Banner
		sub_filter_types text/html;
		include /etc/nginx/snippets/legacy-banner.conf;
		if ($ipv4 ~ "^$") {
			set $legacy "</body>"; # Do not modify, IPv6 is used
		}
		sub_filter "script-src" "script-src 'unsafe-inline'";
		sub_filter "</body>" $legacy;
	}

	(some-ssl-config)
}

Conclusion

In this post, an easy way of implementing a “LegacyIP-Warning” over different webservices is shown. You can easily deploy this warning to your own nginx-webserver, and therefore encourage users and providers to use IPv6.

Thanks to Xu for supporting this post!