1
#include "source/extensions/bootstrap/reverse_tunnel/downstream_socket_interface/reverse_connection_resolver.h"
2

            
3
namespace Envoy {
4
namespace Extensions {
5
namespace Bootstrap {
6
namespace ReverseConnection {
7

            
8
absl::StatusOr<Network::Address::InstanceConstSharedPtr>
9
26
ReverseConnectionResolver::resolve(const envoy::config::core::v3::SocketAddress& socket_address) {
10

            
11
  // Check if address starts with rc://
12
  // Expected format: "rc://src_node_id:src_cluster_id:src_tenant_id@cluster_name:count"
13
26
  const std::string& address_str = socket_address.address();
14
26
  if (!absl::StartsWith(address_str, "rc://")) {
15
1
    return absl::InvalidArgumentError(fmt::format(
16
1
        "Address must start with 'rc://' for reverse connection resolver. "
17
1
        "Expected format: rc://src_node_id:src_cluster_id:src_tenant_id@cluster_name:count"));
18
1
  }
19

            
20
  // For reverse connections, only port 0 is supported.
21
25
  if (socket_address.port_value() != 0) {
22
1
    return absl::InvalidArgumentError(
23
1
        fmt::format("Only port 0 is supported for reverse connections. Got port: {}",
24
1
                    socket_address.port_value()));
25
1
  }
26

            
27
  // Extract reverse connection config.
28
24
  auto reverse_conn_config_or_error = extractReverseConnectionConfig(socket_address);
29
24
  if (!reverse_conn_config_or_error.ok()) {
30
1
    return reverse_conn_config_or_error.status();
31
1
  }
32

            
33
  // Create and return ReverseConnectionAddress.
34
23
  auto reverse_conn_address =
35
23
      std::make_shared<ReverseConnectionAddress>(reverse_conn_config_or_error.value());
36

            
37
23
  return reverse_conn_address;
38
24
}
39

            
40
absl::StatusOr<ReverseConnectionAddress::ReverseConnectionConfig>
41
ReverseConnectionResolver::extractReverseConnectionConfig(
42
31
    const envoy::config::core::v3::SocketAddress& socket_address) {
43

            
44
31
  const std::string& address_str = socket_address.address();
45

            
46
  // Parse the reverse connection URL format.
47
31
  std::string config_part = address_str.substr(5); // Remove "rc://" prefix
48

            
49
  // Split by '@' to separate source info from cluster config.
50
31
  std::vector<std::string> parts = absl::StrSplit(config_part, '@');
51
31
  if (parts.size() != 2) {
52
1
    return absl::InvalidArgumentError(
53
1
        "Invalid reverse connection address format. Expected: "
54
1
        "rc://src_node_id:src_cluster_id:src_tenant_id@cluster_name:count");
55
1
  }
56

            
57
  // Parse source info (node_id:cluster_id:tenant_id)
58
30
  std::vector<std::string> source_parts = absl::StrSplit(parts[0], ':');
59
30
  if (source_parts.size() != 3) {
60
1
    return absl::InvalidArgumentError(
61
1
        "Invalid source info format. Expected: src_node_id:src_cluster_id:src_tenant_id");
62
1
  }
63

            
64
  // Validate that node_id and cluster_id are not empty.
65
29
  if (source_parts[0].empty()) {
66
1
    return absl::InvalidArgumentError("Source node ID cannot be empty");
67
1
  }
68
28
  if (source_parts[1].empty()) {
69
1
    return absl::InvalidArgumentError("Source cluster ID cannot be empty");
70
1
  }
71

            
72
  // Parse cluster configuration (cluster_name:count)
73
27
  std::vector<std::string> cluster_parts = absl::StrSplit(parts[1], ':');
74
27
  if (cluster_parts.size() != 2) {
75
1
    return absl::InvalidArgumentError(
76
1
        fmt::format("Invalid cluster config format: {}. Expected: cluster_name:count", parts[1]));
77
1
  }
78

            
79
26
  uint32_t count;
80
26
  if (!absl::SimpleAtoi(cluster_parts[1], &count)) {
81
1
    return absl::InvalidArgumentError(
82
1
        fmt::format("Invalid connection count: {}", cluster_parts[1]));
83
1
  }
84

            
85
  // Create the config struct.
86
25
  ReverseConnectionAddress::ReverseConnectionConfig config;
87
25
  config.src_node_id = source_parts[0];
88
25
  config.src_cluster_id = source_parts[1];
89
25
  config.src_tenant_id = source_parts[2];
90
25
  config.remote_cluster = cluster_parts[0];
91
25
  config.connection_count = count;
92

            
93
25
  ENVOY_LOG(
94
25
      debug,
95
25
      "reverse connection config: node_id={}, cluster_id={}, tenant_id={}, remote_cluster={}, "
96
25
      "count={}",
97
25
      config.src_node_id, config.src_cluster_id, config.src_tenant_id, config.remote_cluster,
98
25
      config.connection_count);
99

            
100
25
  return config;
101
26
}
102

            
103
// Register the factory.
104
REGISTER_FACTORY(ReverseConnectionResolver, Network::Address::Resolver);
105

            
106
} // namespace ReverseConnection
107
} // namespace Bootstrap
108
} // namespace Extensions
109
} // namespace Envoy