fix(plugin): support ipv6 in RealIpResolver - #2598
Open
Hespethorn wants to merge 1 commit into
Open
Hespethorn wants to merge 1 commit into
Hespethorn wants to merge 1 commit into
Conversation
RealIpResolver only handled ipv4. In a dual-stack deployment, ipv6 entries in trust_ips were rejected as malformed ipv4, and ipv6 entries in X-Forwarded-For were silently dropped, causing the plugin to fall back to the reverse proxy's address. Store the CIDR network address as a network-order byte string plus a prefix length (0-32 for ipv4, 0-128 for ipv6) instead of in_addr_t + mask, and compare the leading prefix bits. parseAddress now handles bare ipv6, bracketed ipv6 with and without a port, and ipv4 with a port. The ipv4 path is bit-identical for prefixes 1-32, so no existing configuration changes behaviour. A zero prefix length is now handled explicitly, so the implementation no longer relies on 0xffffffffu << 32, which is undefined behaviour. Closes drogonframework#2596
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2596.
RealIpResolveronly handled ipv4, which the header documented as@note This plugin currently supports only ipv4 address or cidr.In adual-stack deployment this failed silently in two ways: ipv6 entries in
trust_ipswere rejected with a misleading error, and ipv6 entries inX-Forwarded-Forwere dropped, making the plugin fall back to the reverseproxy's address.
What changed
CIDRnow stores the network address as a network-order byte string plus aprefix length, instead of a 32-bit
in_addr_t+ mask.matchCidr()compares the leadingprefixLen_bits of the address bytes(
trantor::InetAddress::toIpNetEndian()returns 4 bytes for ipv4 and 16 foripv6, in network byte order). Different byte-string lengths mean the two
address families can never match, so no family branch is needed.
CIDR::CIDR()now accepts ipv6 addresses and prefix lengths up to 128. TheInetAddressstring constructor does not detect the address family -isIpV6_comes straight from its third argument - so an ipv6 literal is first tried as
ipv4, fails
inet_pton(AF_INET, ...)and comes back unspecified, rather thanraising the ipv6-specific error. The constructor therefore retries as ipv6
before rejecting an entry, which also makes the
"Ipv6 is not supported by RealIpResolver."throw (unreachable in practice)go away.
parseAddress()handles the shapes that occur inX-Forwarded-For:1.2.3.41.2.3.4:5678[2001:db8::1]:5678[2001:db8::1]2001:db8::1Unparseable entries still yield an unspecified address, which the existing
loop already skips, so the previous behaviour for malformed input is preserved.
XForwardedForParserneeded no change - it only splits on space and comma, soipv6 entries already come through intact.
Backward compatibility
The ipv4 path is bit-identical to the previous implementation for every prefix
from 1 to 32, so no existing
trust_ipsconfiguration changes behaviour.Verified by translating both the old masked comparison and the new byte-prefix
comparison into a script and comparing them per prefix over large random
samples: zero disagreements for prefixes 1-32.
A zero prefix length is handled explicitly, so the implementation no longer
relies on
0xffffffffu << 32, which is undefined behaviour.Tests
Extended
RealIpResolverTestfrom 5 to 14 cases (42 CHECK + 14 REQUIREassertions, 56 in total), adding ipv6 coverage to a
trust_ipslist that mixesipv4 and ipv6 entries:
[ipv6]:portand[ipv6]parsing::ffff:4.4.4.4)(
/33- one address inside, one outside)All 14 cases pass, and the five pre-existing ipv4 cases are unchanged.
Notes
since the plugin was merged in Resolve real ip from HttpRequest. #1321 (2022-07).
friend class HodorusesCIDR(const std::string &), theCIDRstype andRealIpResolver::matchCidr. All three public signatures are unchanged, soHodorcompiles without modification.