|
17 | 17 |
|
18 | 18 | #include "absl/numeric/int128.h" |
19 | 19 | #include "cilium/filter_state_cilium_destination.h" |
| 20 | +#include "cilium/filter_state_cilium_policy.h" |
| 21 | +#include "cilium/policy_id.h" |
20 | 22 |
|
21 | 23 | namespace Envoy { |
22 | 24 | namespace Cilium { |
23 | 25 |
|
24 | 26 | SourceAddressSocketOption::SourceAddressSocketOption( |
25 | | - uint32_t source_identity, int linger_time, |
| 27 | + uint32_t source_identity, const PolicyResolverSharedPtr& policy_resolver, int linger_time, |
26 | 28 | Network::Address::InstanceConstSharedPtr original_source_address, |
27 | 29 | Network::Address::InstanceConstSharedPtr ipv4_source_address, |
28 | 30 | Network::Address::InstanceConstSharedPtr ipv6_source_address, |
29 | 31 | std::shared_ptr<CiliumDestinationFilterState> dest_fs) |
30 | | - : source_identity_(source_identity), linger_time_(linger_time), |
31 | | - original_source_address_(std::move(original_source_address)), |
| 32 | + : source_identity_(source_identity), policy_resolver_(policy_resolver), |
| 33 | + linger_time_(linger_time), original_source_address_(std::move(original_source_address)), |
32 | 34 | ipv4_source_address_(std::move(ipv4_source_address)), |
33 | 35 | ipv6_source_address_(std::move(ipv6_source_address)), dest_fs_(std::move(dest_fs)) { |
34 | 36 | ENVOY_LOG(debug, |
@@ -71,14 +73,42 @@ bool SourceAddressSocketOption::setOption( |
71 | 73 | } |
72 | 74 |
|
73 | 75 | if (source_address->ip() && dest_fs_->getDestinationAddress() && |
74 | | - dest_fs_->getDestinationAddress()->ip() && |
75 | | - source_address->ip()->addressAsString() == |
76 | | - dest_fs_->getDestinationAddress()->ip()->addressAsString()) { |
77 | | - ENVOY_LOG(trace, |
78 | | - "Skipping restore of local address on socket: {} - source address is same as " |
79 | | - "destination address {}", |
80 | | - socket.ioHandle().fdDoNotUse(), source_address->ip()->addressAsString()); |
81 | | - return true; |
| 76 | + dest_fs_->getDestinationAddress()->ip()) { |
| 77 | + // Skip using original source if hairpinning back to the source, as otherwise Linux would |
| 78 | + // drop the packet |
| 79 | + auto destination_ip = dest_fs_->getDestinationAddress()->ip(); |
| 80 | + const auto& destination_ip_str = destination_ip->addressAsString(); |
| 81 | + if (source_address->ip()->addressAsString() == destination_ip_str) { |
| 82 | + ENVOY_LOG(trace, |
| 83 | + "Skipping restore of local address on socket: {} - source address is same as " |
| 84 | + "destination address {}", |
| 85 | + socket.ioHandle().fdDoNotUse(), destination_ip_str); |
| 86 | + return true; |
| 87 | + } |
| 88 | + // Also skip using original source if destination is a local pod or the local host, |
| 89 | + // as otherwise there could be 5-tuple collisions, and the local host may not be able to |
| 90 | + // send replies back to the proxy otherwise. |
| 91 | + auto destination_identity = policy_resolver_->resolvePolicyId(destination_ip); |
| 92 | + ENVOY_LOG(trace, "Socket {} destination address {} has security identity {}", |
| 93 | + socket.ioHandle().fdDoNotUse(), destination_ip_str, destination_identity); |
| 94 | + |
| 95 | + if (destination_identity == Cilium::ID::Host) { |
| 96 | + ENVOY_LOG( |
| 97 | + trace, |
| 98 | + "Skipping restore of local address on socket: {} - destination is the local host {}", |
| 99 | + socket.ioHandle().fdDoNotUse(), destination_ip_str); |
| 100 | + return true; |
| 101 | + } |
| 102 | + |
| 103 | + if (policy_resolver_->exists(destination_ip_str)) { |
| 104 | + ENVOY_LOG(trace, |
| 105 | + "Skipping restore of local address on socket: {} - destination is a local pod {}", |
| 106 | + socket.ioHandle().fdDoNotUse(), destination_ip_str); |
| 107 | + return true; |
| 108 | + } |
| 109 | + } else if (source_address->ip()) { |
| 110 | + ENVOY_LOG(debug, "Destination address filter state for socket {} is not available", |
| 111 | + socket.ioHandle().fdDoNotUse()); |
82 | 112 | } |
83 | 113 |
|
84 | 114 | // Note: SO_LINGER option is set on the socket of the upstream connection. |
|
0 commit comments