Opened 9 months ago

Closed 9 months ago

#2524 closed enhancement (duplicate)

ngx_http_realip_module cannot read CloudFront-Viewer-Address IPV6 header

Reported by: K3ndu@… Owned by:
Priority: minor Milestone:
Component: nginx-module Version: 1.25.x
Keywords: ngx_http_realip_module, ipv6, cloudfront-viewer-address Cc:
uname -a: Linux wordpress-deployment-6bd9bdb7b8-hjqdm 5.10.184-175.731.amzn2.aarch64 #1 SMP Tue Jun 27 21:48:49 UTC 2023 aarch64 GNU/Linux
nginx -V: nginx version: nginx/1.25.1
built by gcc 12.2.0 (Debian 12.2.0-14)
built with OpenSSL 3.0.9 30 May 2023

Description

We have problem that nginx cannot read CloudFront-Viewer-Address if the client is coming with IPV6 address.
Manually tampering the CloudFront-Viewer-Address I have come to the following conclusion which works and which not:
ipv6 with or without brackets and no port - fine
ipv6 with brackets and port - fine
ipv6 without brackets and port - broken

Problem is that it's not customizable on Cloudfront side on which format to send this header. It can only send you the IP without brackets and port in the following format:
"cloudfront-viewer-address": "2001:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:60776",

Any ideas how to solve this problem?

Documentation about this header is here:
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-cloudfront-headers.html

Change History (1)

comment:1 by Maxim Dounin, 9 months ago

Priority: majorminor
Resolution: duplicate
Status: newclosed
Type: defectenhancement

In IPv6 addresses, text representation can contain varying number of components separated by colons due to zero compression, and simply adding :<port> to an IPv6 address is not going to work: the result is not distinguishable from a bare IPv6 address. For example, consider the 2001:db8::1 address and port 8080: combined, they will lead to the 2001:db8::1:8080 string, which is a perfectly valid IPv6 address by itself. See Wikipedia and RFC 5952 for details.

As such, when combining IPv6 addresses with port numbers it is important to provide additional syntax constructs, such as square brackets in [2001:db8::1]:8080. For example, this what usually done for X-Fowarded-For headers when ports are used.

On the linked page, description of the CloudFront-Viewer-Address header is as follows:

CloudFront-Viewer-Address – Contains the IP address of the viewer and the source port of the request. For example, a header value of 198.51.100.10:46532 means the viewer's IP address is 198.51.100.10 and the request source port is 46532.

Unfortunately, from the description it looks like the header was designed for IPv4, without IPv6 in mind, and it is completely unclear how IPv6 is expected to be handled in this header, if at all. You may want to report this to Cloudfront team, it looks like they have something to fix here.

The only approach I can think of is to strictly assume <address>:<port> format, and parse everything after the last colon in the header as a port, and everything before it as an address. This is not something nginx supports natively though: instead, it expects and address, and tolerates an optional port if there is one.

On nginx side, the easiest solution would be to use the X-Forwarded-For header instead, with appropriate settings (you'll have to use real_ip_recursive and appropriate IP address blocks in set_real_ip_from).

Alternatively, you can alter the header to something nginx accepts by using an additional proxying, as recommended as a workaround in #2350.

Closing this as a duplicate of #2350 - the expected enhancement should make it possible to do arbitrary modifications to headers before they are used by the realip module, including custom parsing of headers.

Note: See TracTickets for help on using tickets.