1
#include "source/common/network/socket_option_factory.h"
2

            
3
#include "envoy/config/core/v3/base.pb.h"
4
#include "envoy/network/address.h"
5

            
6
#include "source/common/common/fmt.h"
7
#include "source/common/network/addr_family_aware_socket_option_impl.h"
8
#include "source/common/network/socket_option_impl.h"
9
#include "source/common/network/win32_redirect_records_option_impl.h"
10

            
11
namespace Envoy {
12
namespace Network {
13

            
14
std::unique_ptr<Socket::Options>
15
31
SocketOptionFactory::buildTcpKeepaliveOptions(Network::TcpKeepaliveConfig keepalive_config) {
16
31
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
17
31
  if (isTcpKeepaliveConfigDisabled(keepalive_config)) {
18
4
    return options;
19
4
  }
20
27
  absl::optional<Network::Socket::Type> tcp_only = {Network::Socket::Type::Stream};
21
27
  options->push_back(std::make_shared<Network::SocketOptionImpl>(
22
27
      envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_SO_KEEPALIVE, 1,
23
27
      tcp_only));
24

            
25
27
  if (keepalive_config.keepalive_probes_.has_value()) {
26
12
    options->push_back(std::make_shared<Network::SocketOptionImpl>(
27
12
        envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_TCP_KEEPCNT,
28
12
        keepalive_config.keepalive_probes_.value(), tcp_only));
29
12
  }
30
27
  if (keepalive_config.keepalive_interval_.has_value()) {
31
9
    options->push_back(std::make_shared<Network::SocketOptionImpl>(
32
9
        envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_TCP_KEEPINTVL,
33
9
        keepalive_config.keepalive_interval_.value(), tcp_only));
34
9
  }
35
27
  if (keepalive_config.keepalive_time_.has_value()) {
36
11
    options->push_back(std::make_shared<Network::SocketOptionImpl>(
37
11
        envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_TCP_KEEPIDLE,
38
11
        keepalive_config.keepalive_time_.value(), tcp_only));
39
11
  }
40
27
  return options;
41
31
}
42

            
43
27
std::unique_ptr<Socket::Options> SocketOptionFactory::buildIpFreebindOptions() {
44
27
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
45
27
  options->push_back(std::make_shared<Network::AddrFamilyAwareSocketOptionImpl>(
46
27
      envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_IP_FREEBIND,
47
27
      ENVOY_SOCKET_IPV6_FREEBIND, 1));
48
27
  return options;
49
27
}
50

            
51
30
std::unique_ptr<Socket::Options> SocketOptionFactory::buildIpTransparentOptions() {
52
30
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
53
30
  options->push_back(std::make_shared<Network::AddrFamilyAwareSocketOptionImpl>(
54
30
      envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_IP_TRANSPARENT,
55
30
      ENVOY_SOCKET_IPV6_TRANSPARENT, 1));
56
30
  options->push_back(std::make_shared<Network::AddrFamilyAwareSocketOptionImpl>(
57
30
      envoy::config::core::v3::SocketOption::STATE_BOUND, ENVOY_SOCKET_IP_TRANSPARENT,
58
30
      ENVOY_SOCKET_IPV6_TRANSPARENT, 1));
59
30
  return options;
60
30
}
61

            
62
std::unique_ptr<Socket::Options>
63
4
SocketOptionFactory::buildWFPRedirectRecordsOptions(const Win32RedirectRecords& redirect_records) {
64
4
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
65
4
  options->push_back(std::make_shared<Network::Win32RedirectRecordsOptionImpl>(redirect_records));
66
4
  return options;
67
4
}
68

            
69
3
std::unique_ptr<Socket::Options> SocketOptionFactory::buildSocketMarkOptions(uint32_t mark) {
70
3
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
71
  // we need this to happen prior to binding or prior to connecting. In both cases, PREBIND will
72
  // fire.
73
3
  options->push_back(std::make_shared<Network::SocketOptionImpl>(
74
3
      envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_SO_MARK, mark));
75
3
  return options;
76
3
}
77

            
78
std::unique_ptr<Socket::Options> SocketOptionFactory::buildSocketNoSigpipeOptions() {
79
  // Provide additional handling for `SIGPIPE` at the socket layer by converting it to `EPIPE`.
80
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
81
  options->push_back(std::make_shared<Network::SocketOptionImpl>(
82
      envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_SO_NOSIGPIPE, 1));
83
  return options;
84
}
85

            
86
std::unique_ptr<Socket::Options> SocketOptionFactory::buildLiteralOptions(
87
11941
    const Protobuf::RepeatedPtrField<envoy::config::core::v3::SocketOption>& socket_options) {
88
11941
  auto options = std::make_unique<Socket::Options>();
89
11955
  for (const auto& socket_option : socket_options) {
90
104
    std::string buf;
91
104
    int int_value;
92
104
    switch (socket_option.value_case()) {
93
102
    case envoy::config::core::v3::SocketOption::ValueCase::kIntValue:
94
102
      int_value = socket_option.int_value();
95
102
      buf.append(reinterpret_cast<char*>(&int_value), sizeof(int_value));
96
102
      break;
97
1
    case envoy::config::core::v3::SocketOption::ValueCase::kBufValue:
98
1
      buf.append(socket_option.buf_value());
99
1
      break;
100
1
    default:
101
1
      ENVOY_LOG(warn, "Socket option specified with no or unknown value: {}",
102
1
                socket_option.DebugString());
103
1
      continue;
104
104
    }
105

            
106
103
    absl::optional<Network::Socket::Type> socket_type = absl::nullopt;
107
103
    if (socket_option.has_type() && socket_option.type().has_stream()) {
108
2
      if (socket_option.type().has_datagram()) {
109
1
        ENVOY_LOG(
110
1
            warn,
111
1
            "Both Stream and Datagram socket types are set, setting the socket type to Stream.");
112
1
      }
113
2
      socket_type = Network::Socket::Type::Stream;
114
101
    } else if (socket_option.has_type() && socket_option.type().has_datagram()) {
115
1
      socket_type = Network::Socket::Type::Datagram;
116
1
    }
117
103
    absl::optional<Network::Address::IpVersion> socket_ip_version = absl::nullopt;
118
103
    switch (socket_option.ip_version()) {
119
101
    case envoy::config::core::v3::SocketOption::SOCKET_IP_VERSION_UNSPECIFIED:
120
101
      break;
121
1
    case envoy::config::core::v3::SocketOption::SOCKET_IP_VERSION_IPV4:
122
1
      socket_ip_version = Network::Address::IpVersion::v4;
123
1
      break;
124
1
    case envoy::config::core::v3::SocketOption::SOCKET_IP_VERSION_IPV6:
125
1
      socket_ip_version = Network::Address::IpVersion::v6;
126
1
      break;
127
    default:
128
      ENVOY_LOG(warn, "Socket option specified with unknown ip_version: {}",
129
                socket_option.DebugString());
130
      break;
131
103
    }
132
103
    options->emplace_back(std::make_shared<Network::SocketOptionImpl>(
133
103
        socket_option.state(),
134
103
        Network::SocketOptionName(
135
103
            socket_option.level(), socket_option.name(),
136
103
            fmt::format("{}/{}", socket_option.level(), socket_option.name())),
137
103
        buf, socket_type, socket_ip_version));
138
103
  }
139
11941
  return options;
140
11941
}
141

            
142
std::unique_ptr<Socket::Options>
143
5
SocketOptionFactory::buildTcpFastOpenOptions(uint32_t queue_length) {
144
5
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
145
5
  options->push_back(std::make_shared<Network::SocketOptionImpl>(
146
5
      envoy::config::core::v3::SocketOption::STATE_LISTENING, ENVOY_SOCKET_TCP_FASTOPEN,
147
5
      queue_length));
148
5
  return options;
149
5
}
150

            
151
5583
std::unique_ptr<Socket::Options> SocketOptionFactory::buildIpPacketInfoOptions() {
152
5583
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
153
5583
  options->push_back(std::make_shared<AddrFamilyAwareSocketOptionImpl>(
154
5583
      envoy::config::core::v3::SocketOption::STATE_BOUND, ENVOY_SELF_IP_ADDR, ENVOY_SELF_IPV6_ADDR,
155
5583
      1));
156
5583
  return options;
157
5583
}
158

            
159
5582
std::unique_ptr<Socket::Options> SocketOptionFactory::buildRxQueueOverFlowOptions() {
160
5582
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
161
5582
#ifdef SO_RXQ_OVFL
162
5582
  options->push_back(std::make_shared<Network::SocketOptionImpl>(
163
5582
      envoy::config::core::v3::SocketOption::STATE_BOUND,
164
5582
      ENVOY_MAKE_SOCKET_OPTION_NAME(SOL_SOCKET, SO_RXQ_OVFL), 1));
165
5582
#endif
166
5582
  return options;
167
5582
}
168

            
169
10825
std::unique_ptr<Socket::Options> SocketOptionFactory::buildReusePortOptions() {
170
10825
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
171
10825
  options->push_back(std::make_shared<Network::SocketOptionImpl>(
172
10825
      envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_SO_REUSEPORT, 1));
173
10825
  return options;
174
10825
}
175

            
176
4334
std::unique_ptr<Socket::Options> SocketOptionFactory::buildUdpGroOptions() {
177
4334
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
178
4334
  options->push_back(std::make_shared<SocketOptionImpl>(
179
4334
      envoy::config::core::v3::SocketOption::STATE_BOUND, ENVOY_SOCKET_UDP_GRO, 1));
180
4334
  return options;
181
4334
}
182

            
183
437
std::unique_ptr<Socket::Options> SocketOptionFactory::buildZeroSoLingerOptions() {
184
437
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
185
437
  struct linger linger;
186
437
  linger.l_onoff = 1;
187
437
  linger.l_linger = 0;
188
437
  absl::string_view linger_bstr{reinterpret_cast<const char*>(&linger), sizeof(struct linger)};
189
437
  options->push_back(std::make_shared<SocketOptionImpl>(
190
437
      envoy::config::core::v3::SocketOption::STATE_LISTENING,
191
437
      ENVOY_MAKE_SOCKET_OPTION_NAME(SOL_SOCKET, SO_LINGER), linger_bstr));
192
437
  return options;
193
437
}
194

            
195
3128
std::unique_ptr<Socket::Options> SocketOptionFactory::buildIpRecvTosOptions() {
196
3128
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
197
3128
  options->push_back(std::make_shared<AddrFamilyAwareSocketOptionImpl>(
198
3128
      envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_SOCKET_IP_RECVTOS,
199
3128
      ENVOY_SOCKET_IPV6_RECVTCLASS, 1));
200
3128
  return options;
201
3128
}
202

            
203
18
std::unique_ptr<Socket::Options> SocketOptionFactory::buildBindAddressNoPort() {
204
18
  std::unique_ptr<Socket::Options> options = std::make_unique<Socket::Options>();
205
18
  options->push_back(
206
18
      std::make_shared<SocketOptionImpl>(envoy::config::core::v3::SocketOption::STATE_PREBIND,
207
18
                                         ENVOY_SOCKET_IP_BIND_ADDRESS_NO_PORT, 1));
208
18
  return options;
209
18
}
210

            
211
std::unique_ptr<Socket::Options>
212
4359
SocketOptionFactory::buildDoNotFragmentOptions(bool supports_v4_mapped_v6_addresses) {
213
4359
  auto options = std::make_unique<Socket::Options>();
214
#ifdef ENVOY_IP_DONTFRAG
215
  options->push_back(std::make_shared<AddrFamilyAwareSocketOptionImpl>(
216
      envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_IP_DONTFRAG, ENVOY_IPV6_DONTFRAG,
217
      1));
218
  // v4 mapped v6 addresses don't support ENVOY_IP_DONTFRAG on MAC OS.
219
  (void)supports_v4_mapped_v6_addresses;
220
#elif defined(ENVOY_IP_MTU_DISCOVER)
221
  options->push_back(std::make_shared<AddrFamilyAwareSocketOptionImpl>(
222
4359
      envoy::config::core::v3::SocketOption::STATE_PREBIND, ENVOY_IP_MTU_DISCOVER,
223
4359
      ENVOY_IP_MTU_DISCOVER_VALUE, ENVOY_IPV6_MTU_DISCOVER, ENVOY_IPV6_MTU_DISCOVER_VALUE));
224

            
225
4359
  if (supports_v4_mapped_v6_addresses) {
226
1
    ENVOY_LOG_MISC(trace, "Also apply the V4 option to v6 socket to support v4-mapped addresses.");
227
1
    options->push_back(
228
1
        std::make_shared<SocketOptionImpl>(envoy::config::core::v3::SocketOption::STATE_PREBIND,
229
1
                                           ENVOY_IP_MTU_DISCOVER, ENVOY_IP_MTU_DISCOVER_VALUE));
230
1
  }
231
#else
232
  (void)supports_v4_mapped_v6_addresses;
233
  ENVOY_LOG_MISC(trace, "Platform supports neither socket option IP_DONTFRAG nor IP_MTU_DISCOVER");
234
#endif
235
4359
  return options;
236
4359
}
237

            
238
} // namespace Network
239
} // namespace Envoy