utility: Fix address comparisons in isLocalConnection(), add tests.#5373
utility: Fix address comparisons in isLocalConnection(), add tests.#5373jrajahalme wants to merge 6 commits intoenvoyproxy:masterfrom
Conversation
Add test case for LocalConnection test where local and remote addresses have the same IP address. Fix the test code to actually use the intended local address. Fix the utility implementation to compare the actual addresses rather than the pointers to them. Fixes: envoyproxy#4682 Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Address comparisons in Utility::isLocalConnection() should be performed on the IP addresses, ignoring any port numbers. Skip the temporary Instance in the comparison loop. Add test cases with port numbers. Fixes: envoyproxy#4682 Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
There was a problem hiding this comment.
This is a lot to read in a conditional statement. Is there a way you can add the needed comparison into an equality operator on the appropriate object to make this statement look a lot clearer? Then you can hide the complexity of this and v4 vs. v6 in the right place.
There was a problem hiding this comment.
Envoy does not have a generic address type for an IP address without a port number. Typically an IP address type with a zero port number is used to approximate it, but real connection addresses always have non-zero port numbers, so given the current type system this is the only way to implement the comparison here. We could move this to an utility function (e.g., isSameIPAddress(addr1, addr2)) to make it easier to read, though.
There was a problem hiding this comment.
Ah, that's right. I think it would be best to use a utility function, then.
3f41d3d to
d8337e7
Compare
Add a new utility function to compare if two address instances are the same IP address, ignoring the port numbers. Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
| return false; | ||
| } | ||
|
|
||
| if (address1.ip()->version() == Address::IpVersion::v4) { |
There was a problem hiding this comment.
This might look less verbose as a switch statement.
|
|
||
| bool Utility::isSameIPAddress(const Address::Instance& address1, | ||
| const Address::Instance& address2) { | ||
| if (address1.type() != Address::Type::Ip || |
There was a problem hiding this comment.
maybe this should be an assert?
| } | ||
| } else { | ||
| const auto* addr = reinterpret_cast<const struct sockaddr_in6*>(ifa->ifa_addr); | ||
| absl::uint128 v6addr = remote_address->ip()->ipv6()->address(); |
There was a problem hiding this comment.
might be good to call this remote_v6addr for maximum clarity, too.
| return true; | ||
| } | ||
| } else { | ||
| const auto* addr = reinterpret_cast<const struct sockaddr_in6*>(ifa->ifa_addr); |
There was a problem hiding this comment.
Used if_addr instead.
| if (remote_address == local_address) { | ||
| return true; | ||
| if (af_look_up == AF_INET) { | ||
| const auto* addr = reinterpret_cast<const struct sockaddr_in*>(ifa->ifa_addr); |
Restore the order of comparisons to pass tests that count the number of calls to localAddress(). Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
| if (remote_address->type() == Envoy::Network::Address::Type::Pipe || | ||
| remote_address == socket.localAddress() || isLoopbackAddress(*remote_address)) { | ||
| if (remote_address->type() != Envoy::Network::Address::Type::Ip || | ||
| isSameIPAddress(*remote_address, *socket.localAddress()) || |
There was a problem hiding this comment.
Sorry, but could you explain why doesn't this work with ==?
Also, can't we fix the operator== instead of adding an utility function, since presumably this is broken in other places as well?
There was a problem hiding this comment.
remote_address (as well as socket.localAddress are shared pointers (InstanceConstSharedPtr). Equality operator of pointers compares the pointers themselves, rather than the objects they point to.
Secondly, even if the addresses were compared, this comparison must ignore the port numbers that are embedded in every Envoy Ip address instance.
There was a problem hiding this comment.
operator== is correct for comparing the whole IP address + port combination. It also works in many places where it is known that the port numbers of both addresses are the same (e.g., zero).
There was a problem hiding this comment.
You may want to review the two commits separately, as they address the above issues one at a time.
There was a problem hiding this comment.
Ah, I completely missed the port part, thanks!
|
Dan: can you assign a senior reviewer when you're done on your pass? |
|
|
||
| if (remote_address == local_address) { | ||
| return true; | ||
| if (af_look_up == AF_INET) { |
There was a problem hiding this comment.
Could you move this comparison into isSameIPAddress(const Address::Instance& address1, const struct sockaddr *address2)?
There was a problem hiding this comment.
isSameIPAddress() already checks the IP version, but here, within a loop, we don't want to create temporary IP Address Instances so we are open-coding the comparison.
However, upon a second look I removed the assert in isSameIPAddress() so that it is safe to call on any type of an Address.
There was a problem hiding this comment.
Note that I'm suggesting extracting this to isSameIPAddress() with different arguments, so you'd invoke it using isSameIPAddress(*remote_address, ifa->ifa_addr) without creating temporary Address::Instance object (which I agree would be an overkill).
Basically, extracting this code for readability, since compiler is going to inline it here anyway.
I'm fine with you leaving it here, if feel strongly about it, though.
There was a problem hiding this comment.
Friendly ping on what you prefer to do here (leave it as-is, in which case it's ready to be merged, or extracting it to isSameIPAddress(const Address::Instance&, const struct sockaddr *)), to make sure that we're not stuck waiting on each other.
| } | ||
| } else { | ||
| const auto* if_addr = reinterpret_cast<const struct sockaddr_in6*>(ifa->ifa_addr); | ||
| const absl::uint128 remote_v6addr = remote_address->ip()->ipv6()->address(); |
There was a problem hiding this comment.
Please make sure to not overread the memory:
static_assert(sizeof(absl::uint128) == sizeof(if_addr->sin6_addr.s6_addr),
"sizeof(absl::uint128) != sizeof(if_addr->sin6_addr.s6_addr)");
|
|
||
| testing::NiceMock<Network::MockConnectionSocket> socket; | ||
|
|
||
| EXPECT_CALL(socket, remoteAddress()).WillRepeatedly(testing::ReturnRef(local_addr)); |
| local_addr.reset(new Network::Address::Ipv6Instance("fabc::42", 80)); | ||
| remote_addr.reset(new Network::Address::Ipv6Instance( | ||
| Utility::getLocalAddress(Address::IpVersion::v6)->ip()->addressAsString(), 23413)); | ||
| EXPECT_TRUE(Utility::isLocalConnection(socket)); |
There was a problem hiding this comment.
Could you add a test comparing IPv4 and IPv6 addresses? It looks that we're missing it.
| if (remote_address->type() == Envoy::Network::Address::Type::Pipe || | ||
| remote_address == socket.localAddress() || isLoopbackAddress(*remote_address)) { | ||
| if (remote_address->type() != Envoy::Network::Address::Type::Ip || | ||
| isSameIPAddress(*remote_address, *socket.localAddress()) || |
There was a problem hiding this comment.
Ah, I completely missed the port part, thanks!
Make isSameIPAddress() safe to call on any type of Address Instances. Add an assert for IPv6 address size. Add a case with mixed IPv4/IPv6 addresses to the LocalConnection Test. Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
|
@PiotrSikora Addressed your concerns, can you have another look? |
|
This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
|
This pull request has been automatically closed because it has not had activity in the last 14 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
|
Not stale, pending response from @jrajahalme. |
Add test case for LocalConnection test where local and remote
addresses have the same IP address. Fix the test code to actually use
the intended local address. Fix the utility implementation to compare
the actual addresses rather than the pointers to them.
Address comparisons in Utility::isLocalConnection() should be performed on
the IP addresses, ignoring any port numbers. Skip the temporary
Instance in the comparison loop. Add test cases with port numbers.
Fixes: #4682
Signed-off-by: Jarno Rajahalme jarno@covalent.io