1
#include "source/extensions/quic/server_preferred_address/datasource_server_preferred_address_config.h"
2

            
3
#include "envoy/common/exception.h"
4

            
5
#include "source/common/common/utility.h"
6
#include "source/common/config/datasource.h"
7
#include "source/common/network/utility.h"
8
#include "source/common/quic/envoy_quic_utils.h"
9
#include "source/extensions/quic/server_preferred_address/server_preferred_address.h"
10

            
11
namespace Envoy {
12
namespace Quic {
13

            
14
namespace {
15

            
16
quic::QuicIpAddress parseIp(const envoy::config::core::v3::DataSource& source,
17
                            quiche::IpAddressFamily address_family,
18
                            absl::string_view address_family_str, const Protobuf::Message& message,
19
16
                            Server::Configuration::ServerFactoryContext& context) {
20
16
  std::string data =
21
16
      THROW_OR_RETURN_VALUE(Config::DataSource::read(source, false, context.api()), std::string);
22

            
23
16
  quic::QuicIpAddress ip;
24
16
  if (!ip.FromString(std::string(StringUtil::trim(data)))) {
25
1
    ProtoExceptionUtil::throwProtoValidationException(
26
1
        absl::StrCat("bad ", address_family_str, " server preferred address: ", data), message);
27
1
  }
28

            
29
16
  if (ip.address_family() != address_family) {
30
2
    ProtoExceptionUtil::throwProtoValidationException(
31
2
        absl::StrCat("wrong address family for ", address_family_str,
32
2
                     " server preferred address: ", data),
33
2
        message);
34
2
  }
35
16
  return ip;
36
16
}
37

            
38
ServerPreferredAddressConfig::IpVersionConfig
39
parseFamily(const envoy::extensions::quic::server_preferred_address::v3::
40
                DataSourceServerPreferredAddressConfig::AddressFamilyConfig& addresses,
41
            quiche::IpAddressFamily address_family, absl::string_view address_family_str,
42
            const Protobuf::Message& message,
43
12
            Server::Configuration::ServerFactoryContext& context) {
44
12
  ServerPreferredAddressConfig::IpVersionConfig ret;
45

            
46
12
  const quic::QuicIpAddress spa_addr =
47
12
      parseIp(addresses.address(), address_family, address_family_str, message, context);
48

            
49
12
  if (!addresses.has_dnat_address() && addresses.has_port()) {
50
1
    ProtoExceptionUtil::throwProtoValidationException(
51
1
        fmt::format("port must be unset unless 'dnat_address' is set "
52
1
                    "for address family {}",
53
1
                    address_family_str),
54
1
        message);
55
1
  }
56

            
57
12
  uint16_t spa_port = 0;
58
12
  if (addresses.has_port()) {
59
4
    std::string port_str = THROW_OR_RETURN_VALUE(
60
4
        Config::DataSource::read(addresses.port(), false, context.api()), std::string);
61

            
62
    // absl::SimpleAtoi doesn't work with uint16_t, so first convert to uint32_t.
63
4
    uint32_t big_port = 0;
64
4
    const bool success = absl::SimpleAtoi(port_str, &big_port);
65
4
    if (!success || big_port > UINT16_MAX) {
66
1
      ProtoExceptionUtil::throwProtoValidationException(
67
1
          absl::StrCat("server preferred address ", address_family_str,
68
1
                       " port was not a valid port: ", port_str),
69
1
          message);
70
1
    }
71

            
72
4
    spa_port = big_port;
73
4
  }
74
12
  ret.spa_ = quic::QuicSocketAddress(spa_addr, spa_port);
75

            
76
12
  if (addresses.has_dnat_address()) {
77
4
    ret.dnat_ =
78
4
        parseIp(addresses.dnat_address(), address_family, address_family_str, message, context);
79
4
  }
80

            
81
12
  return ret;
82
12
}
83

            
84
} // namespace
85

            
86
Quic::EnvoyQuicServerPreferredAddressConfigPtr
87
DataSourceServerPreferredAddressConfigFactory::createServerPreferredAddressConfig(
88
    const Protobuf::Message& message, ProtobufMessage::ValidationVisitor& validation_visitor,
89
13
    Server::Configuration::ServerFactoryContext& context) {
90
13
  auto& config =
91
13
      MessageUtil::downcastAndValidate<const envoy::extensions::quic::server_preferred_address::v3::
92
13
                                           DataSourceServerPreferredAddressConfig&>(
93
13
          message, validation_visitor);
94

            
95
13
  ServerPreferredAddressConfig::IpVersionConfig v4;
96
13
  if (config.has_ipv4_config()) {
97
11
    v4 = parseFamily(config.ipv4_config(), quiche::IpAddressFamily::IP_V4, "v4", message, context);
98
11
  }
99

            
100
13
  ServerPreferredAddressConfig::IpVersionConfig v6;
101
13
  if (config.has_ipv6_config()) {
102
1
    v6 = parseFamily(config.ipv6_config(), quiche::IpAddressFamily::IP_V6, "v6", message, context);
103
1
  }
104

            
105
13
  return std::make_unique<ServerPreferredAddressConfig>(v4, v6);
106
13
}
107

            
108
REGISTER_FACTORY(DataSourceServerPreferredAddressConfigFactory,
109
                 Quic::EnvoyQuicServerPreferredAddressConfigFactory);
110

            
111
} // namespace Quic
112
} // namespace Envoy