Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/test/config/utility.cc
Line
Count
Source (jump to first uncovered line)
1
#include "test/config/utility.h"
2
3
#include "envoy/config/bootstrap/v3/bootstrap.pb.h"
4
#include "envoy/config/cluster/v3/cluster.pb.h"
5
#include "envoy/config/core/v3/base.pb.h"
6
#include "envoy/config/endpoint/v3/endpoint.pb.h"
7
#include "envoy/config/listener/v3/listener_components.pb.h"
8
#include "envoy/config/route/v3/route_components.pb.h"
9
#include "envoy/extensions/access_loggers/file/v3/file.pb.h"
10
#include "envoy/extensions/filters/http/upstream_codec/v3/upstream_codec.pb.h"
11
#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
12
#include "envoy/extensions/transport_sockets/quic/v3/quic_transport.pb.h"
13
#include "envoy/extensions/transport_sockets/tls/v3/cert.pb.h"
14
#include "envoy/extensions/transport_sockets/tls/v3/common.pb.h"
15
#include "envoy/http/codec.h"
16
#include "envoy/service/discovery/v3/discovery.pb.h"
17
18
#include "source/common/common/assert.h"
19
#include "source/common/http/utility.h"
20
#include "source/common/protobuf/utility.h"
21
22
#include "test/config/integration/certs/client2cert_hash.h"
23
#include "test/config/integration/certs/client_ecdsacert_hash.h"
24
#include "test/config/integration/certs/clientcert_hash.h"
25
#include "test/test_common/environment.h"
26
#include "test/test_common/network_utility.h"
27
#include "test/test_common/resources.h"
28
#include "test/test_common/utility.h"
29
30
#include "absl/strings/str_replace.h"
31
#include "gtest/gtest.h"
32
33
namespace Envoy {
34
namespace {
35
envoy::config::bootstrap::v3::Bootstrap&
36
0
basicBootstrap(envoy::config::bootstrap::v3::Bootstrap& bootstrap, const std::string& config) {
37
0
#ifdef ENVOY_ENABLE_YAML
38
0
  TestUtility::loadFromYaml(config, bootstrap);
39
#else
40
  UNREFERENCED_PARAMETER(config);
41
  UNREFERENCED_PARAMETER(bootstrap);
42
  PANIC("JSON compiled out: can't load config");
43
#endif
44
0
  return bootstrap;
45
0
}
46
} // namespace
47
48
1.96k
std::string ConfigHelper::baseConfigNoListeners() {
49
1.96k
  return fmt::format(R"EOF(
50
1.96k
admin:
51
1.96k
  access_log:
52
1.96k
  - name: envoy.access_loggers.file
53
1.96k
    typed_config:
54
1.96k
      "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
55
1.96k
      path: "{}"
56
1.96k
  address:
57
1.96k
    socket_address:
58
1.96k
      address: 127.0.0.1
59
1.96k
      port_value: 0
60
1.96k
dynamic_resources:
61
1.96k
  lds_config:
62
1.96k
    path_config_source:
63
1.96k
      path: {}
64
1.96k
static_resources:
65
1.96k
  secrets:
66
1.96k
  - name: "secret_static_0"
67
1.96k
    tls_certificate:
68
1.96k
      certificate_chain:
69
1.96k
        inline_string: "DUMMY_INLINE_BYTES"
70
1.96k
      private_key:
71
1.96k
        inline_string: "DUMMY_INLINE_BYTES"
72
1.96k
      password:
73
1.96k
        inline_string: "DUMMY_INLINE_BYTES"
74
1.96k
  clusters:
75
1.96k
    name: cluster_0
76
1.96k
    load_assignment:
77
1.96k
      cluster_name: cluster_0
78
1.96k
      endpoints:
79
1.96k
      - lb_endpoints:
80
1.96k
        - endpoint:
81
1.96k
            address:
82
1.96k
              socket_address:
83
1.96k
                address: 127.0.0.1
84
1.96k
                port_value: 0
85
1.96k
)EOF",
86
1.96k
                     Platform::null_device_path, Platform::null_device_path);
87
1.96k
}
88
89
1.96k
std::string ConfigHelper::baseConfig(bool multiple_addresses) {
90
1.96k
  if (multiple_addresses) {
91
0
    return absl::StrCat(baseConfigNoListeners(), R"EOF(
92
0
  listeners:
93
0
  - name: listener_0
94
0
    address:
95
0
      socket_address:
96
0
        address: 127.0.0.1
97
0
        port_value: 0
98
0
    additional_addresses:
99
0
    - address:
100
0
        socket_address:
101
0
          address: 127.0.0.1
102
0
          port_value: 0
103
0
)EOF");
104
0
  }
105
1.96k
  return absl::StrCat(baseConfigNoListeners(), R"EOF(
106
1.96k
  listeners:
107
1.96k
  - name: listener_0
108
1.96k
    address:
109
1.96k
      socket_address:
110
1.96k
        address: 127.0.0.1
111
1.96k
        port_value: 0
112
1.96k
)EOF");
113
1.96k
}
114
115
std::string ConfigHelper::baseUdpListenerConfig(std::string listen_address,
116
0
                                                bool multiple_addresses) {
117
0
  std::string config = fmt::format(R"EOF(
118
0
admin:
119
0
  access_log:
120
0
  - name: envoy.access_loggers.file
121
0
    typed_config:
122
0
      "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
123
0
      path: "{}"
124
0
  address:
125
0
    socket_address:
126
0
      address: 127.0.0.1
127
0
      port_value: 0
128
0
static_resources:
129
0
  clusters:
130
0
    name: cluster_0
131
0
    load_assignment:
132
0
      cluster_name: cluster_0
133
0
      endpoints:
134
0
      - lb_endpoints:
135
0
        - endpoint:
136
0
            address:
137
0
              socket_address:
138
0
                address: 127.0.0.1
139
0
                port_value: 0
140
0
)EOF",
141
0
                                   Platform::null_device_path);
142
143
0
  if (multiple_addresses) {
144
0
    return absl::StrCat(config, fmt::format(R"EOF(
145
0
  listeners:
146
0
    name: listener_0
147
0
    address:
148
0
      socket_address:
149
0
        address: {}
150
0
        port_value: 0
151
0
        protocol: udp
152
0
    additional_addresses:
153
0
    - address:
154
0
        socket_address:
155
0
          address: {}
156
0
          port_value: 0
157
0
          protocol: udp
158
0
)EOF",
159
0
                                            listen_address, listen_address));
160
0
  }
161
0
  return absl::StrCat(config, fmt::format(R"EOF(
162
0
  listeners:
163
0
    name: listener_0
164
0
    address:
165
0
      socket_address:
166
0
        address: {}
167
0
        port_value: 0
168
0
        protocol: udp
169
0
)EOF",
170
0
                                          listen_address));
171
0
}
172
173
0
std::string ConfigHelper::tcpProxyConfig() {
174
0
  return absl::StrCat(baseConfig(), R"EOF(
175
0
    filter_chains:
176
0
      filters:
177
0
        name: tcp
178
0
        typed_config:
179
0
          "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
180
0
          stat_prefix: tcpproxy_stats
181
0
          cluster: cluster_0
182
0
)EOF");
183
0
}
184
185
0
std::string ConfigHelper::startTlsConfig() {
186
0
  return absl::StrCat(
187
0
      tcpProxyConfig(),
188
0
      fmt::format(R"EOF(
189
0
      transport_socket:
190
0
        name: "starttls"
191
0
        typed_config:
192
0
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.starttls.v3.StartTlsConfig
193
0
          cleartext_socket_config:
194
0
          tls_socket_config:
195
0
            common_tls_context:
196
0
              tls_certificates:
197
0
                certificate_chain:
198
0
                  filename: {}
199
0
                private_key:
200
0
                  filename: {}
201
0
)EOF",
202
0
                  TestEnvironment::runfilesPath("test/config/integration/certs/servercert.pem"),
203
0
                  TestEnvironment::runfilesPath("test/config/integration/certs/serverkey.pem")));
204
0
}
205
206
0
std::string ConfigHelper::testInspectorFilter() {
207
0
  return R"EOF(
208
0
name: "envoy.filters.listener.test"
209
0
typed_config:
210
0
  "@type": type.googleapis.com/test.integration.filters.TestInspectorFilterConfig
211
0
)EOF";
212
0
}
213
214
0
std::string ConfigHelper::tlsInspectorFilter(bool enable_ja3_fingerprinting) {
215
0
  if (!enable_ja3_fingerprinting) {
216
0
    return R"EOF(
217
0
name: "envoy.filters.listener.tls_inspector"
218
0
typed_config:
219
0
  "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
220
0
)EOF";
221
0
  }
222
223
0
  return R"EOF(
224
0
name: "envoy.filters.listener.tls_inspector"
225
0
typed_config:
226
0
  "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
227
0
  enable_ja3_fingerprinting: true
228
0
)EOF";
229
0
}
230
231
1.96k
std::string ConfigHelper::httpProxyConfig(bool downstream_use_quic, bool multiple_addresses) {
232
1.96k
  if (downstream_use_quic) {
233
0
    return quicHttpProxyConfig(multiple_addresses);
234
0
  }
235
1.96k
  return absl::StrCat(baseConfig(multiple_addresses), fmt::format(R"EOF(
236
1.96k
    filter_chains:
237
1.96k
      filters:
238
1.96k
        name: http
239
1.96k
        typed_config:
240
1.96k
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
241
1.96k
          stat_prefix: config_test
242
1.96k
          delayed_close_timeout:
243
1.96k
            nanos: 10000000
244
1.96k
          http_filters:
245
1.96k
          - name: envoy.filters.http.router
246
1.96k
            typed_config:
247
1.96k
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
248
1.96k
          codec_type: HTTP1
249
1.96k
          access_log:
250
1.96k
            name: accesslog
251
1.96k
            filter:
252
1.96k
              not_health_check_filter:  {{}}
253
1.96k
            typed_config:
254
1.96k
              "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
255
1.96k
              path: {}
256
1.96k
          route_config:
257
1.96k
            virtual_hosts:
258
1.96k
              name: integration
259
1.96k
              routes:
260
1.96k
                route:
261
1.96k
                  cluster: cluster_0
262
1.96k
                match:
263
1.96k
                  prefix: "/"
264
1.96k
              domains: "*"
265
1.96k
            name: route_config_0
266
1.96k
)EOF",
267
1.96k
                                                                  Platform::null_device_path));
268
1.96k
}
269
270
// TODO(danzh): For better compatibility with HTTP integration test framework,
271
// it's better to combine with HTTP_PROXY_CONFIG, and use config modifiers to
272
// specify quic specific things.
273
0
std::string ConfigHelper::quicHttpProxyConfig(bool multiple_addresses) {
274
0
  return absl::StrCat(baseUdpListenerConfig("127.0.0.1", multiple_addresses),
275
0
                      fmt::format(R"EOF(
276
0
    filter_chains:
277
0
      transport_socket:
278
0
        name: envoy.transport_sockets.quic
279
0
        typed_config:
280
0
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicDownstreamTransport
281
0
      filters:
282
0
        name: http
283
0
        typed_config:
284
0
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
285
0
          stat_prefix: config_test
286
0
          http_filters:
287
0
          - name: envoy.filters.http.router
288
0
            typed_config:
289
0
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
290
0
          codec_type: HTTP3
291
0
          access_log:
292
0
            name: file_access_log
293
0
            filter:
294
0
              not_health_check_filter:  {{}}
295
0
            typed_config:
296
0
              "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
297
0
              path: {}
298
0
          route_config:
299
0
            virtual_hosts:
300
0
              name: integration
301
0
              routes:
302
0
                route:
303
0
                  cluster: cluster_0
304
0
                match:
305
0
                  prefix: "/"
306
0
              domains: "*"
307
0
            name: route_config_0
308
0
    udp_listener_config:
309
0
      quic_options: {{}}
310
0
)EOF",
311
0
                                  Platform::null_device_path));
312
0
}
313
314
0
std::string ConfigHelper::defaultBufferFilter() {
315
0
  return R"EOF(
316
0
name: buffer
317
0
typed_config:
318
0
    "@type": type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer
319
0
    max_request_bytes : 5242880
320
0
)EOF";
321
0
}
322
323
0
std::string ConfigHelper::smallBufferFilter() {
324
0
  return R"EOF(
325
0
name: buffer
326
0
typed_config:
327
0
    "@type": type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer
328
0
    max_request_bytes : 1024
329
0
)EOF";
330
0
}
331
332
0
std::string ConfigHelper::defaultHealthCheckFilter() {
333
0
  return R"EOF(
334
0
name: health_check
335
0
typed_config:
336
0
    "@type": type.googleapis.com/envoy.extensions.filters.http.health_check.v3.HealthCheck
337
0
    pass_through_mode: false
338
0
)EOF";
339
0
}
340
341
0
std::string ConfigHelper::defaultSquashFilter() {
342
0
  return R"EOF(
343
0
name: squash
344
0
typed_config:
345
0
  "@type": type.googleapis.com/envoy.extensions.filters.http.squash.v3.Squash
346
0
  cluster: squash
347
0
  attachment_template:
348
0
    spec:
349
0
      attachment:
350
0
        env: "{{ SQUASH_ENV_TEST }}"
351
0
      match_request: true
352
0
  attachment_timeout:
353
0
    seconds: 1
354
0
    nanos: 0
355
0
  attachment_poll_period:
356
0
    seconds: 2
357
0
    nanos: 0
358
0
  request_timeout:
359
0
    seconds: 1
360
0
    nanos: 0
361
0
)EOF";
362
0
}
363
364
0
std::string ConfigHelper::clustersNoListenerBootstrap(const std::string& api_type) {
365
0
  return fmt::format(
366
0
      R"EOF(
367
0
admin:
368
0
  access_log:
369
0
  - name: envoy.access_loggers.file
370
0
    typed_config:
371
0
      "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
372
0
      path: "{}"
373
0
  address:
374
0
    socket_address:
375
0
      address: 127.0.0.1
376
0
      port_value: 0
377
0
dynamic_resources:
378
0
  cds_config:
379
0
    api_config_source:
380
0
      api_type: {}
381
0
      grpc_services:
382
0
        envoy_grpc:
383
0
          cluster_name: my_cds_cluster
384
0
      set_node_on_first_message_only: true
385
0
static_resources:
386
0
  clusters:
387
0
  - name: my_cds_cluster
388
0
    typed_extension_protocol_options:
389
0
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
390
0
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
391
0
        explicit_http_config:
392
0
          http2_protocol_options: {{}}
393
0
    load_assignment:
394
0
      cluster_name: my_cds_cluster
395
0
      endpoints:
396
0
      - lb_endpoints:
397
0
        - endpoint:
398
0
            address:
399
0
              socket_address:
400
0
                address: 127.0.0.1
401
0
                port_value: 0
402
0
)EOF",
403
0
      Platform::null_device_path, api_type);
404
0
}
405
406
// TODO(#6327) cleaner approach to testing with static config.
407
0
std::string ConfigHelper::discoveredClustersBootstrap(const std::string& api_type) {
408
0
  return absl::StrCat(clustersNoListenerBootstrap(api_type),
409
0
                      R"EOF(
410
0
  listeners:
411
0
    name: http
412
0
    address:
413
0
      socket_address:
414
0
        address: 127.0.0.1
415
0
        port_value: 0
416
0
    filter_chains:
417
0
      filters:
418
0
        name: http
419
0
        typed_config:
420
0
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
421
0
          stat_prefix: config_test
422
0
          http_filters:
423
0
          - name: envoy.filters.http.router
424
0
            typed_config:
425
0
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
426
0
          codec_type: HTTP2
427
0
          route_config:
428
0
            name: route_config_0
429
0
            validate_clusters: false
430
0
            virtual_hosts:
431
0
              name: integration
432
0
              routes:
433
0
              - route:
434
0
                  cluster: cluster_1
435
0
                match:
436
0
                  prefix: "/cluster1"
437
0
              - route:
438
0
                  cluster: cluster_2
439
0
                match:
440
0
                  prefix: "/cluster2"
441
0
              domains: "*"
442
0
)EOF");
443
0
}
444
445
// TODO(#6327) cleaner approach to testing with static config.
446
14
std::string ConfigHelper::adsBootstrap(const std::string& api_type) {
447
  // We use this to allow tests to default to having a single API version but override and make
448
  // the transport/resource API version distinction when needed.
449
14
  return fmt::format(R"EOF(
450
14
dynamic_resources:
451
14
  lds_config:
452
14
    ads: {{}}
453
14
  cds_config:
454
14
    ads: {{}}
455
14
  ads_config:
456
14
    api_type: {0}
457
14
    set_node_on_first_message_only: true
458
14
static_resources:
459
14
  clusters:
460
14
    name: dummy_cluster
461
14
    connect_timeout:
462
14
      seconds: 5
463
14
    type: STATIC
464
14
    load_assignment:
465
14
      cluster_name: dummy_cluster
466
14
      endpoints:
467
14
      - lb_endpoints:
468
14
        - endpoint:
469
14
            address:
470
14
              socket_address:
471
14
                address: 127.0.0.1
472
14
                port_value: 0
473
14
    lb_policy: ROUND_ROBIN
474
14
    typed_extension_protocol_options:
475
14
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
476
14
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
477
14
        explicit_http_config:
478
14
          http2_protocol_options: {{}}
479
14
admin:
480
14
  access_log:
481
14
  - name: envoy.access_loggers.file
482
14
    typed_config:
483
14
      "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
484
14
      path: "{1}"
485
14
  address:
486
14
    socket_address:
487
14
      address: 127.0.0.1
488
14
      port_value: 0
489
14
)EOF",
490
14
                     api_type, Platform::null_device_path);
491
14
}
492
493
// TODO(samflattery): bundle this up with buildCluster
494
envoy::config::cluster::v3::Cluster
495
ConfigHelper::buildStaticCluster(const std::string& name, int port, const std::string& address,
496
0
                                 const envoy::config::cluster::v3::Cluster::LbPolicy lb_policy) {
497
0
  envoy::config::cluster::v3::Cluster cluster;
498
0
  cluster.mutable_connect_timeout()->set_seconds(5);
499
0
  cluster.set_type(envoy::config::cluster::v3::Cluster::STATIC);
500
0
  cluster.set_name(name);
501
0
  cluster.mutable_load_assignment()->set_cluster_name(name);
502
0
  auto* endpoint =
503
0
      cluster.mutable_load_assignment()->add_endpoints()->add_lb_endpoints()->mutable_endpoint();
504
0
  auto* addr = endpoint->mutable_address();
505
0
  addr->mutable_socket_address()->set_address(address);
506
0
  addr->mutable_socket_address()->set_port_value(port);
507
0
  addr = endpoint->mutable_health_check_config()->mutable_address();
508
0
  addr->mutable_socket_address()->set_address(address);
509
0
  addr->mutable_socket_address()->set_port_value(port);
510
0
  cluster.set_lb_policy(lb_policy);
511
0
  envoy::extensions::upstreams::http::v3::HttpProtocolOptions protocol_options;
512
0
  protocol_options.mutable_explicit_http_config()->mutable_http2_protocol_options();
513
514
0
  (*cluster.mutable_typed_extension_protocol_options())
515
0
      ["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"]
516
0
          .PackFrom(protocol_options);
517
0
  return cluster;
518
0
}
519
520
envoy::config::cluster::v3::Cluster ConfigHelper::buildH1ClusterWithHighCircuitBreakersLimits(
521
    const std::string& name, int port, const std::string& address,
522
0
    const envoy::config::cluster::v3::Cluster::LbPolicy lb_policy) {
523
0
  envoy::config::cluster::v3::Cluster cluster;
524
0
  cluster.set_name(name);
525
0
  cluster.mutable_connect_timeout()->set_seconds(50);
526
0
  cluster.set_type(envoy::config::cluster::v3::Cluster::STATIC);
527
0
  auto* threshold = cluster.mutable_circuit_breakers()->mutable_thresholds()->Add();
528
0
  threshold->set_priority(envoy::config::core::v3::RoutingPriority::DEFAULT);
529
0
  threshold->mutable_max_connections()->set_value(10000);
530
0
  threshold->mutable_max_pending_requests()->set_value(10000);
531
0
  threshold->mutable_max_requests()->set_value(10000);
532
0
  threshold->mutable_max_retries()->set_value(10000);
533
0
  cluster.mutable_load_assignment()->set_cluster_name(name);
534
0
  auto* endpoint =
535
0
      cluster.mutable_load_assignment()->add_endpoints()->add_lb_endpoints()->mutable_endpoint();
536
0
  cluster.set_lb_policy(lb_policy);
537
0
  auto* addr = endpoint->mutable_address();
538
0
  addr->mutable_socket_address()->set_address(address);
539
0
  addr->mutable_socket_address()->set_port_value(port);
540
0
  return cluster;
541
0
}
542
543
envoy::config::cluster::v3::Cluster
544
ConfigHelper::buildCluster(const std::string& name,
545
28
                           const envoy::config::cluster::v3::Cluster::LbPolicy lb_policy) {
546
28
  envoy::config::cluster::v3::Cluster cluster;
547
28
  cluster.mutable_connect_timeout()->set_seconds(5);
548
28
  cluster.set_type(envoy::config::cluster::v3::Cluster::EDS);
549
28
  cluster.set_name(name);
550
28
  cluster.set_lb_policy(lb_policy);
551
552
28
  auto* eds = cluster.mutable_eds_cluster_config()->mutable_eds_config();
553
28
  eds->set_resource_api_version(envoy::config::core::v3::ApiVersion::V3);
554
28
  eds->mutable_ads();
555
556
28
  envoy::extensions::upstreams::http::v3::HttpProtocolOptions protocol_options;
557
28
  protocol_options.mutable_explicit_http_config()->mutable_http2_protocol_options();
558
28
  (*cluster.mutable_typed_extension_protocol_options())
559
28
      ["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"]
560
28
          .PackFrom(protocol_options);
561
562
28
  return cluster;
563
28
}
564
565
envoy::config::cluster::v3::Cluster
566
ConfigHelper::buildTlsCluster(const std::string& name,
567
0
                              const envoy::config::cluster::v3::Cluster::LbPolicy lb_policy) {
568
0
  envoy::config::cluster::v3::Cluster cluster = buildCluster(name, lb_policy);
569
570
0
  auto* socket = cluster.mutable_transport_socket();
571
0
  envoy::extensions::transport_sockets::tls::v3::UpstreamTlsContext tls_socket;
572
0
  tls_socket.mutable_common_tls_context()
573
0
      ->mutable_validation_context()
574
0
      ->mutable_trusted_ca()
575
0
      ->set_filename(
576
0
          TestEnvironment::runfilesPath("test/config/integration/certs/upstreamcacert.pem"));
577
0
  socket->set_name("envoy.transport_sockets.tls");
578
0
  socket->mutable_typed_config()->PackFrom(tls_socket);
579
0
  return cluster;
580
0
}
581
582
envoy::config::endpoint::v3::ClusterLoadAssignment
583
ConfigHelper::buildClusterLoadAssignment(const std::string& name, const std::string& address_str,
584
28
                                         uint32_t port) {
585
28
  API_NO_BOOST(envoy::config::endpoint::v3::ClusterLoadAssignment) cluster_load_assignment;
586
28
  cluster_load_assignment.set_cluster_name(name);
587
28
  auto* address = cluster_load_assignment.add_endpoints()
588
28
                      ->add_lb_endpoints()
589
28
                      ->mutable_endpoint()
590
28
                      ->mutable_address()
591
28
                      ->mutable_socket_address();
592
28
  address->set_address(address_str);
593
28
  address->set_port_value(port);
594
595
28
  return cluster_load_assignment;
596
28
}
597
598
envoy::config::endpoint::v3::ClusterLoadAssignment
599
ConfigHelper::buildClusterLoadAssignmentWithLeds(const std::string& name,
600
0
                                                 const std::string& leds_collection_name) {
601
0
  API_NO_BOOST(envoy::config::endpoint::v3::ClusterLoadAssignment) cluster_load_assignment;
602
603
0
  cluster_load_assignment.set_cluster_name(name);
604
0
  auto* lclc = cluster_load_assignment.add_endpoints()->mutable_leds_cluster_locality_config();
605
0
  auto* leds = lclc->mutable_leds_config();
606
0
  leds->set_resource_api_version(envoy::config::core::v3::ApiVersion::V3);
607
0
  leds->mutable_ads();
608
0
  lclc->set_leds_collection_name(leds_collection_name);
609
0
  return cluster_load_assignment;
610
0
}
611
612
envoy::config::endpoint::v3::LbEndpoint
613
0
ConfigHelper::buildLbEndpoint(const std::string& address_str, uint32_t port) {
614
0
  API_NO_BOOST(envoy::config::endpoint::v3::LbEndpoint) lb_endpoint;
615
0
  auto* address = lb_endpoint.mutable_endpoint()->mutable_address()->mutable_socket_address();
616
0
  address->set_address(address_str);
617
0
  address->set_port_value(port);
618
0
  return lb_endpoint;
619
0
}
620
621
envoy::config::listener::v3::Listener
622
ConfigHelper::buildBaseListener(const std::string& name, const std::string& address,
623
90
                                const std::string& filter_chains) {
624
90
  API_NO_BOOST(envoy::config::listener::v3::Listener) listener;
625
90
#ifdef ENVOY_ENABLE_YAML
626
90
  TestUtility::loadFromYaml(fmt::format(
627
90
                                R"EOF(
628
90
      name: {}
629
90
      address:
630
90
        socket_address:
631
90
          address: {}
632
90
          port_value: 0
633
90
      filter_chains:
634
90
      {}
635
90
    )EOF",
636
90
                                name, address, filter_chains),
637
90
                            listener);
638
90
  return listener;
639
#else
640
  UNREFERENCED_PARAMETER(name);
641
  UNREFERENCED_PARAMETER(address);
642
  UNREFERENCED_PARAMETER(filter_chains);
643
  PANIC("YAML support compiled out");
644
#endif
645
90
}
646
647
envoy::config::listener::v3::Listener ConfigHelper::buildListener(const std::string& name,
648
                                                                  const std::string& route_config,
649
                                                                  const std::string& address,
650
90
                                                                  const std::string& stat_prefix) {
651
90
  std::string hcm = fmt::format(
652
90
      R"EOF(
653
90
        filters:
654
90
        - name: http
655
90
          typed_config:
656
90
            "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
657
90
            stat_prefix: {}
658
90
            codec_type: HTTP2
659
90
            rds:
660
90
              route_config_name: {}
661
90
              config_source:
662
90
                ads: {{}}
663
90
            http_filters:
664
90
            - name: envoy.filters.http.router
665
90
              typed_config:
666
90
                "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
667
90
    )EOF",
668
90
      stat_prefix, route_config);
669
90
  return buildBaseListener(name, address, hcm);
670
90
}
671
672
envoy::config::route::v3::RouteConfiguration
673
46
ConfigHelper::buildRouteConfig(const std::string& name, const std::string& cluster) {
674
46
  API_NO_BOOST(envoy::config::route::v3::RouteConfiguration) route;
675
46
#ifdef ENVOY_ENABLE_YAML
676
46
  TestUtility::loadFromYaml(fmt::format(R"EOF(
677
46
      name: "{}"
678
46
      virtual_hosts:
679
46
      - name: integration
680
46
        domains: ["*"]
681
46
        routes:
682
46
        - match: {{ prefix: "/" }}
683
46
          route: {{ cluster: "{}" }}
684
46
    )EOF",
685
46
                                        name, cluster),
686
46
                            route);
687
46
  return route;
688
#else
689
  UNREFERENCED_PARAMETER(name);
690
  UNREFERENCED_PARAMETER(cluster);
691
  PANIC("YAML support compiled out");
692
#endif
693
46
}
694
695
0
envoy::config::endpoint::v3::Endpoint ConfigHelper::buildEndpoint(const std::string& address) {
696
0
  envoy::config::endpoint::v3::Endpoint endpoint;
697
0
  endpoint.mutable_address()->mutable_socket_address()->set_address(address);
698
0
  return endpoint;
699
0
}
700
701
ConfigHelper::ConfigHelper(const Network::Address::IpVersion version, Api::Api&,
702
                           const std::string& config)
703
0
    : ConfigHelper(version, basicBootstrap(bootstrap_, config)) {}
704
705
ConfigHelper::ConfigHelper(const Network::Address::IpVersion version,
706
1.97k
                           const envoy::config::bootstrap::v3::Bootstrap& bootstrap) {
707
1.97k
  RELEASE_ASSERT(!finalized_, "");
708
1.97k
  bootstrap_ = bootstrap;
709
710
  // Fix up all the socket addresses with the correct version.
711
1.97k
  auto* admin = bootstrap_.mutable_admin();
712
1.97k
  auto* admin_socket_addr = admin->mutable_address()->mutable_socket_address();
713
1.97k
  admin_socket_addr->set_address(Network::Test::getLoopbackAddressString(version));
714
715
1.97k
  auto* static_resources = bootstrap_.mutable_static_resources();
716
3.93k
  for (int i = 0; i < static_resources->listeners_size(); ++i) {
717
1.96k
    auto* listener = static_resources->mutable_listeners(i);
718
1.96k
    if (listener->mutable_address()->has_envoy_internal_address()) {
719
0
      ENVOY_LOG_MISC(
720
0
          debug, "Listener {} has internal address {}. Will not reset to loop back socket address.",
721
0
          i, listener->mutable_address()->envoy_internal_address().server_listener_name());
722
0
      continue;
723
0
    }
724
1.96k
    if (listener->mutable_address()->has_pipe()) {
725
0
      ENVOY_LOG_MISC(debug,
726
0
                     "Listener {} has pipe address {}. Will not reset to loop back socket address.",
727
0
                     i, listener->mutable_address()->pipe().path());
728
0
      continue;
729
0
    }
730
1.96k
    auto* listener_socket_addr = listener->mutable_address()->mutable_socket_address();
731
1.96k
    if (listener_socket_addr->address() == "0.0.0.0" || listener_socket_addr->address() == "::") {
732
0
      listener_socket_addr->set_address(Network::Test::getAnyAddressString(version));
733
1.96k
    } else {
734
1.96k
      listener_socket_addr->set_address(Network::Test::getLoopbackAddressString(version));
735
1.96k
    }
736
737
1.96k
    for (int i = 0; i < listener->additional_addresses_size(); i++) {
738
0
      auto* listener_socket_addr =
739
0
          listener->mutable_additional_addresses(i)->mutable_address()->mutable_socket_address();
740
0
      if (listener_socket_addr->address() == "0.0.0.0" || listener_socket_addr->address() == "::") {
741
0
        listener_socket_addr->set_address(Network::Test::getAnyAddressString(version));
742
0
      } else {
743
0
        listener_socket_addr->set_address(Network::Test::getLoopbackAddressString(version));
744
0
      }
745
0
    }
746
1.96k
  }
747
748
3.95k
  for (int i = 0; i < static_resources->clusters_size(); ++i) {
749
1.97k
    auto* cluster = static_resources->mutable_clusters(i);
750
3.95k
    for (int j = 0; j < cluster->load_assignment().endpoints_size(); ++j) {
751
1.97k
      auto* locality_lb = cluster->mutable_load_assignment()->mutable_endpoints(j);
752
3.95k
      for (int k = 0; k < locality_lb->lb_endpoints_size(); ++k) {
753
1.97k
        auto* lb_endpoint = locality_lb->mutable_lb_endpoints(k);
754
1.97k
        if (lb_endpoint->endpoint().address().has_socket_address()) {
755
1.97k
          lb_endpoint->mutable_endpoint()->mutable_address()->mutable_socket_address()->set_address(
756
1.97k
              Network::Test::getLoopbackAddressString(version));
757
1.97k
        }
758
1.97k
      }
759
1.97k
    }
760
1.97k
  }
761
762
  // Ensure we have a basic admin-capable runtime layer.
763
1.97k
  if (bootstrap_.mutable_layered_runtime()->layers_size() == 0) {
764
1.97k
    auto* static_layer = bootstrap_.mutable_layered_runtime()->add_layers();
765
1.97k
    static_layer->set_name("static_layer");
766
1.97k
    static_layer->mutable_static_layer();
767
1.97k
    auto* admin_layer = bootstrap_.mutable_layered_runtime()->add_layers();
768
1.97k
    admin_layer->set_name("admin");
769
1.97k
    admin_layer->mutable_admin_layer();
770
1.97k
  }
771
1.97k
}
772
773
0
void ConfigHelper::addListenerTypedMetadata(absl::string_view key, ProtobufWkt::Any& packed_value) {
774
0
  RELEASE_ASSERT(!finalized_, "");
775
0
  auto* static_resources = bootstrap_.mutable_static_resources();
776
0
  ASSERT_TRUE(static_resources->listeners_size() > 0);
777
0
  auto* listener = static_resources->mutable_listeners(0);
778
0
  auto* map = listener->mutable_metadata()->mutable_typed_filter_metadata();
779
0
  (*map)[std::string(key)] = packed_value;
780
0
};
781
782
void ConfigHelper::addClusterFilterMetadata(absl::string_view metadata_yaml,
783
0
                                            absl::string_view cluster_name) {
784
0
#ifdef ENVOY_ENABLE_YAML
785
0
  RELEASE_ASSERT(!finalized_, "");
786
0
  ProtobufWkt::Struct cluster_metadata;
787
0
  TestUtility::loadFromYaml(std::string(metadata_yaml), cluster_metadata);
788
789
0
  auto* static_resources = bootstrap_.mutable_static_resources();
790
0
  for (int i = 0; i < static_resources->clusters_size(); ++i) {
791
0
    auto* cluster = static_resources->mutable_clusters(i);
792
0
    if (cluster->name() != cluster_name) {
793
0
      continue;
794
0
    }
795
0
    for (const auto& kvp : cluster_metadata.fields()) {
796
0
      ASSERT_TRUE(kvp.second.kind_case() == ProtobufWkt::Value::KindCase::kStructValue);
797
0
      cluster->mutable_metadata()->mutable_filter_metadata()->insert(
798
0
          {kvp.first, kvp.second.struct_value()});
799
0
    }
800
0
    break;
801
0
  }
802
#else
803
  UNREFERENCED_PARAMETER(metadata_yaml);
804
  UNREFERENCED_PARAMETER(cluster_name);
805
  PANIC("YAML support compiled out");
806
#endif
807
0
}
808
809
void ConfigHelper::setConnectConfig(
810
    envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& hcm,
811
    bool terminate_connect, bool allow_post, bool http3,
812
0
    absl::optional<envoy::config::core::v3::ProxyProtocolConfig::Version> proxy_protocol_version) {
813
0
  auto* route_config = hcm.mutable_route_config();
814
0
  ASSERT_EQ(1, route_config->virtual_hosts_size());
815
0
  auto* route = route_config->mutable_virtual_hosts(0)->mutable_routes(0);
816
0
  auto* match = route->mutable_match();
817
0
  match->Clear();
818
819
0
  if (allow_post) {
820
0
    match->set_prefix("/");
821
822
0
    auto* header = match->add_headers();
823
0
    header->set_name(":method");
824
0
    header->mutable_string_match()->set_exact("POST");
825
0
  } else {
826
0
    match->mutable_connect_matcher();
827
0
  }
828
829
0
  auto* upgrade = route->mutable_route()->add_upgrade_configs();
830
0
  upgrade->set_upgrade_type("CONNECT");
831
832
0
  if (terminate_connect) {
833
0
    auto* config = upgrade->mutable_connect_config();
834
0
    if (allow_post) {
835
0
      config->set_allow_post(true);
836
0
    }
837
838
0
    if (proxy_protocol_version.has_value()) {
839
0
      config->mutable_proxy_protocol_config()->set_version(proxy_protocol_version.value());
840
0
    }
841
0
  }
842
843
0
  hcm.add_upgrade_configs()->set_upgrade_type("CONNECT");
844
0
  hcm.mutable_http2_protocol_options()->set_allow_connect(true);
845
0
  if (http3) {
846
0
    hcm.mutable_http3_protocol_options()->set_allow_extended_connect(true);
847
0
  }
848
0
}
849
850
void ConfigHelper::setConnectUdpConfig(
851
    envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& hcm,
852
0
    bool terminate_connect, bool http3) {
853
0
  auto* route_config = hcm.mutable_route_config();
854
0
  ASSERT_EQ(1, route_config->virtual_hosts_size());
855
0
  auto* route = route_config->mutable_virtual_hosts(0)->mutable_routes(0);
856
0
  auto* match = route->mutable_match();
857
0
  match->Clear();
858
0
  match->mutable_connect_matcher();
859
860
0
  auto* upgrade = route->mutable_route()->add_upgrade_configs();
861
0
  upgrade->set_upgrade_type("connect-udp");
862
863
0
  if (terminate_connect) {
864
0
    upgrade->mutable_connect_config();
865
0
  }
866
867
0
  hcm.add_upgrade_configs()->set_upgrade_type("connect-udp");
868
0
  hcm.mutable_http2_protocol_options()->set_allow_connect(true);
869
0
  if (http3) {
870
0
    hcm.mutable_http3_protocol_options()->set_allow_extended_connect(true);
871
0
  }
872
0
}
873
874
1.97k
void ConfigHelper::applyConfigModifiers() {
875
5.01k
  for (const auto& config_modifier : config_modifiers_) {
876
5.01k
    config_modifier(bootstrap_);
877
5.01k
  }
878
1.97k
  config_modifiers_.clear();
879
1.97k
}
880
881
void ConfigHelper::configureUpstreamTls(
882
    bool use_alpn, bool http3,
883
    absl::optional<envoy::config::core::v3::AlternateProtocolsCacheOptions>
884
        alternate_protocol_cache_config,
885
    std::function<void(envoy::extensions::transport_sockets::tls::v3::CommonTlsContext&)>
886
0
        configure_tls_context) {
887
0
  addConfigModifier([use_alpn, http3, alternate_protocol_cache_config,
888
0
                     configure_tls_context](envoy::config::bootstrap::v3::Bootstrap& bootstrap) {
889
0
    auto* cluster = bootstrap.mutable_static_resources()->mutable_clusters(0);
890
891
0
    ConfigHelper::HttpProtocolOptions protocol_options;
892
0
    protocol_options.mutable_upstream_http_protocol_options()->set_auto_sni(true);
893
0
    ConfigHelper::setProtocolOptions(*cluster, protocol_options);
894
895
0
    if (use_alpn) {
896
0
      ConfigHelper::HttpProtocolOptions new_protocol_options;
897
898
0
      HttpProtocolOptions old_protocol_options =
899
0
          MessageUtil::anyConvert<ConfigHelper::HttpProtocolOptions>(
900
0
              (*cluster->mutable_typed_extension_protocol_options())
901
0
                  ["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"]);
902
0
      protocol_options.MergeFrom(old_protocol_options);
903
904
0
      new_protocol_options = old_protocol_options;
905
0
      new_protocol_options.clear_explicit_http_config();
906
0
      new_protocol_options.mutable_auto_config();
907
0
      if (old_protocol_options.explicit_http_config().has_http_protocol_options()) {
908
0
        new_protocol_options.mutable_auto_config()->mutable_http_protocol_options()->MergeFrom(
909
0
            old_protocol_options.explicit_http_config().http_protocol_options());
910
0
      } else if (old_protocol_options.explicit_http_config().has_http2_protocol_options()) {
911
0
        new_protocol_options.mutable_auto_config()->mutable_http2_protocol_options()->MergeFrom(
912
0
            old_protocol_options.explicit_http_config().http2_protocol_options());
913
0
      }
914
0
      if (http3 || old_protocol_options.explicit_http_config().has_http3_protocol_options()) {
915
0
        new_protocol_options.mutable_auto_config()->mutable_http3_protocol_options()->MergeFrom(
916
0
            old_protocol_options.explicit_http_config().http3_protocol_options());
917
0
      }
918
0
      if (alternate_protocol_cache_config.has_value()) {
919
0
        new_protocol_options.mutable_auto_config()
920
0
            ->mutable_alternate_protocols_cache_options()
921
0
            ->set_name("default_alternate_protocols_cache");
922
0
        new_protocol_options.mutable_auto_config()
923
0
            ->mutable_alternate_protocols_cache_options()
924
0
            ->CopyFrom(alternate_protocol_cache_config.value());
925
0
      }
926
0
      (*cluster->mutable_typed_extension_protocol_options())
927
0
          ["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"]
928
0
              .PackFrom(new_protocol_options);
929
0
    }
930
0
    envoy::extensions::transport_sockets::tls::v3::UpstreamTlsContext tls_context;
931
0
    if (configure_tls_context != nullptr) {
932
0
      configure_tls_context(*tls_context.mutable_common_tls_context());
933
0
    }
934
0
    auto* validation_context =
935
0
        tls_context.mutable_common_tls_context()->mutable_validation_context();
936
0
    validation_context->mutable_trusted_ca()->set_filename(
937
0
        TestEnvironment::runfilesPath("test/config/integration/certs/upstreamcacert.pem"));
938
    // The test certs are for *.lyft.com, so make sure SNI matches.
939
0
    tls_context.set_sni("foo.lyft.com");
940
0
    if (http3) {
941
0
      envoy::extensions::transport_sockets::quic::v3::QuicUpstreamTransport quic_context;
942
0
      quic_context.mutable_upstream_tls_context()->CopyFrom(tls_context);
943
0
      cluster->mutable_transport_socket()->set_name("envoy.transport_sockets.quic");
944
0
      cluster->mutable_transport_socket()->mutable_typed_config()->PackFrom(quic_context);
945
0
    } else {
946
0
      cluster->mutable_transport_socket()->set_name("envoy.transport_sockets.tls");
947
0
      cluster->mutable_transport_socket()->mutable_typed_config()->PackFrom(tls_context);
948
0
    }
949
0
  });
950
0
}
951
952
1.99k
void ConfigHelper::addRuntimeOverride(absl::string_view key, absl::string_view value) {
953
1.99k
  auto* static_layer =
954
1.99k
      bootstrap_.mutable_layered_runtime()->mutable_layers(0)->mutable_static_layer();
955
956
1.99k
  if (value == "true") {
957
7
    (*static_layer->mutable_fields())[std::string(key)] = ValueUtil::boolValue(true);
958
1.98k
  } else if (value == "false") {
959
1.98k
    (*static_layer->mutable_fields())[std::string(key)] = ValueUtil::boolValue(false);
960
1.98k
  } else {
961
0
    (*static_layer->mutable_fields())[std::string(key)] =
962
0
        ValueUtil::stringValue(std::string(value));
963
0
  }
964
1.99k
}
965
966
void ConfigHelper::setProtocolOptions(envoy::config::cluster::v3::Cluster& cluster,
967
2.28k
                                      HttpProtocolOptions& protocol_options) {
968
2.28k
  if (cluster.typed_extension_protocol_options().contains(
969
2.28k
          "envoy.extensions.upstreams.http.v3.HttpProtocolOptions")) {
970
780
    HttpProtocolOptions old_options = MessageUtil::anyConvert<ConfigHelper::HttpProtocolOptions>(
971
780
        (*cluster.mutable_typed_extension_protocol_options())
972
780
            ["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"]);
973
780
    bool auto_config = old_options.has_auto_config();
974
780
    old_options.MergeFrom(protocol_options);
975
780
    protocol_options.CopyFrom(old_options);
976
780
    if (auto_config) {
977
0
      protocol_options.mutable_auto_config();
978
0
    }
979
780
  }
980
2.28k
  (*cluster.mutable_typed_extension_protocol_options())
981
2.28k
      ["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"]
982
2.28k
          .PackFrom(protocol_options);
983
2.28k
}
984
985
806
void ConfigHelper::setHttp2(envoy::config::cluster::v3::Cluster& cluster) {
986
806
  HttpProtocolOptions protocol_options;
987
806
  protocol_options.mutable_explicit_http_config()->mutable_http2_protocol_options();
988
806
  setProtocolOptions(cluster, protocol_options);
989
806
}
990
991
1.97k
void ConfigHelper::finalize(const std::vector<uint32_t>& ports) {
992
1.97k
  RELEASE_ASSERT(!finalized_, "");
993
994
1.97k
  applyConfigModifiers();
995
996
1.97k
  setPorts(ports);
997
998
1.97k
  if (!connect_timeout_set_) {
999
#ifdef __APPLE__
1000
    // Set a high default connect timeout. Under heavy load (and in particular in CI), macOS
1001
    // connections can take inordinately long to complete.
1002
    setConnectTimeout(std::chrono::seconds(30));
1003
#else
1004
    // Set a default connect timeout.
1005
1.97k
    setConnectTimeout(std::chrono::seconds(5));
1006
1.97k
#endif
1007
1.97k
  }
1008
1009
1.97k
  finalized_ = true;
1010
1.97k
}
1011
1012
1.97k
void ConfigHelper::setPorts(const std::vector<uint32_t>& ports, bool override_port_zero) {
1013
1.97k
  uint32_t port_idx = 0;
1014
1.97k
  bool eds_hosts = false;
1015
1.97k
  bool custom_cluster = false;
1016
1.97k
  bool original_dst_cluster = false;
1017
1.97k
  auto* static_resources = bootstrap_.mutable_static_resources();
1018
4.36k
  for (int i = 0; i < bootstrap_.mutable_static_resources()->clusters_size(); ++i) {
1019
2.39k
    auto* cluster = static_resources->mutable_clusters(i);
1020
2.39k
    if (cluster->type() == envoy::config::cluster::v3::Cluster::EDS) {
1021
0
      eds_hosts = true;
1022
2.39k
    } else if (cluster->type() == envoy::config::cluster::v3::Cluster::ORIGINAL_DST) {
1023
0
      original_dst_cluster = true;
1024
2.39k
    } else if (cluster->has_cluster_type()) {
1025
0
      custom_cluster = true;
1026
2.39k
    } else {
1027
      // Assign ports to statically defined load_assignment hosts.
1028
4.78k
      for (int j = 0; j < cluster->load_assignment().endpoints_size(); ++j) {
1029
2.39k
        auto locality_lb = cluster->mutable_load_assignment()->mutable_endpoints(j);
1030
4.78k
        for (int k = 0; k < locality_lb->lb_endpoints_size(); ++k) {
1031
2.39k
          auto lb_endpoint = locality_lb->mutable_lb_endpoints(k);
1032
2.39k
          if (lb_endpoint->endpoint().address().has_socket_address()) {
1033
2.39k
            if (lb_endpoint->endpoint().address().socket_address().port_value() == 0 ||
1034
2.39k
                override_port_zero) {
1035
1.99k
              RELEASE_ASSERT(ports.size() > port_idx, "");
1036
1.99k
              lb_endpoint->mutable_endpoint()
1037
1.99k
                  ->mutable_address()
1038
1.99k
                  ->mutable_socket_address()
1039
1.99k
                  ->set_port_value(ports[port_idx++]);
1040
1.99k
            } else {
1041
403
              ENVOY_LOG_MISC(debug, "Not overriding preset port",
1042
403
                             lb_endpoint->endpoint().address().socket_address().port_value());
1043
403
            }
1044
2.39k
          }
1045
2.39k
        }
1046
2.39k
      }
1047
2.39k
    }
1048
2.39k
  }
1049
1.97k
  ASSERT(skip_port_usage_validation_ || port_idx == ports.size() || eds_hosts ||
1050
1.97k
         original_dst_cluster || custom_cluster || bootstrap_.dynamic_resources().has_cds_config());
1051
1.97k
}
1052
1053
0
void ConfigHelper::setSourceAddress(const std::string& address_string) {
1054
0
  RELEASE_ASSERT(!finalized_, "");
1055
0
  bootstrap_.mutable_cluster_manager()
1056
0
      ->mutable_upstream_bind_config()
1057
0
      ->mutable_source_address()
1058
0
      ->set_address(address_string);
1059
  // We don't have the ability to bind to specific ports yet.
1060
0
  bootstrap_.mutable_cluster_manager()
1061
0
      ->mutable_upstream_bind_config()
1062
0
      ->mutable_source_address()
1063
0
      ->set_port_value(0);
1064
0
}
1065
1066
0
void ConfigHelper::setDefaultHostAndRoute(const std::string& domains, const std::string& prefix) {
1067
0
  RELEASE_ASSERT(!finalized_, "");
1068
0
  envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager
1069
0
      hcm_config;
1070
0
  loadHttpConnectionManager(hcm_config);
1071
1072
0
  auto* virtual_host = hcm_config.mutable_route_config()->mutable_virtual_hosts(0);
1073
0
  virtual_host->set_domains(0, domains);
1074
0
  virtual_host->mutable_routes(0)->mutable_match()->set_prefix(prefix);
1075
1076
0
  storeHttpConnectionManager(hcm_config);
1077
0
}
1078
1079
void ConfigHelper::setBufferLimits(uint32_t upstream_buffer_limit,
1080
403
                                   uint32_t downstream_buffer_limit) {
1081
403
  RELEASE_ASSERT(!finalized_, "");
1082
403
  auto* listener = bootstrap_.mutable_static_resources()->mutable_listeners(0);
1083
403
  listener->mutable_per_connection_buffer_limit_bytes()->set_value(downstream_buffer_limit);
1084
403
  const uint32_t stream_buffer_size = std::max(
1085
403
      downstream_buffer_limit, Http2::Utility::OptionsLimits::MIN_INITIAL_STREAM_WINDOW_SIZE);
1086
403
  if (Network::Utility::protobufAddressSocketType(listener->address()) ==
1087
403
          Network::Socket::Type::Datagram &&
1088
403
      listener->udp_listener_config().has_quic_options()) {
1089
    // QUIC stream's flow control window is configured in listener config.
1090
0
    listener->mutable_udp_listener_config()
1091
0
        ->mutable_quic_options()
1092
0
        ->mutable_quic_protocol_options()
1093
0
        ->mutable_initial_stream_window_size()
1094
        // The same as kStreamReceiveWindowLimit in QUICHE which only supports stream flow control
1095
        // window no larger than 16MB.
1096
0
        ->set_value(std::min(16u * 1024 * 1024, stream_buffer_size));
1097
0
  }
1098
1099
403
  auto* static_resources = bootstrap_.mutable_static_resources();
1100
806
  for (int i = 0; i < bootstrap_.mutable_static_resources()->clusters_size(); ++i) {
1101
403
    auto* cluster = static_resources->mutable_clusters(i);
1102
403
    cluster->mutable_per_connection_buffer_limit_bytes()->set_value(upstream_buffer_limit);
1103
403
  }
1104
1105
403
  auto filter = getFilterFromListener("http");
1106
403
  if (filter) {
1107
403
    envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager
1108
403
        hcm_config;
1109
403
    loadHttpConnectionManager(hcm_config);
1110
403
    if (hcm_config.codec_type() == envoy::extensions::filters::network::http_connection_manager::
1111
403
                                       v3::HttpConnectionManager::HTTP2) {
1112
403
      auto* options = hcm_config.mutable_http2_protocol_options();
1113
403
      options->mutable_initial_stream_window_size()->set_value(stream_buffer_size);
1114
403
      storeHttpConnectionManager(hcm_config);
1115
403
    }
1116
403
  }
1117
403
}
1118
1119
0
void ConfigHelper::setListenerSendBufLimits(uint32_t limit) {
1120
0
  RELEASE_ASSERT(!finalized_, "");
1121
0
  RELEASE_ASSERT(bootstrap_.mutable_static_resources()->listeners_size() == 1, "");
1122
0
  auto* listener = bootstrap_.mutable_static_resources()->mutable_listeners(0);
1123
0
  auto* options = listener->add_socket_options();
1124
0
  options->set_description("SO_SNDBUF");
1125
0
  options->set_level(SOL_SOCKET);
1126
0
  options->set_int_value(limit);
1127
0
  options->set_name(SO_SNDBUF);
1128
0
}
1129
1130
0
void ConfigHelper::setDownstreamHttpIdleTimeout(std::chrono::milliseconds timeout) {
1131
0
  addConfigModifier(
1132
0
      [timeout](
1133
0
          envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
1134
0
              hcm) {
1135
0
        hcm.mutable_common_http_protocol_options()->mutable_idle_timeout()->MergeFrom(
1136
0
            ProtobufUtil::TimeUtil::MillisecondsToDuration(timeout.count()));
1137
0
      });
1138
0
}
1139
1140
0
void ConfigHelper::setDownstreamMaxConnectionDuration(std::chrono::milliseconds timeout) {
1141
0
  addConfigModifier(
1142
0
      [timeout](
1143
0
          envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
1144
0
              hcm) {
1145
0
        hcm.mutable_common_http_protocol_options()->mutable_max_connection_duration()->MergeFrom(
1146
0
            ProtobufUtil::TimeUtil::MillisecondsToDuration(timeout.count()));
1147
0
      });
1148
0
}
1149
1150
0
void ConfigHelper::setDownstreamMaxStreamDuration(std::chrono::milliseconds timeout) {
1151
0
  addConfigModifier(
1152
0
      [timeout](
1153
0
          envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
1154
0
              hcm) {
1155
0
        hcm.mutable_common_http_protocol_options()->mutable_max_stream_duration()->MergeFrom(
1156
0
            ProtobufUtil::TimeUtil::MillisecondsToDuration(timeout.count()));
1157
0
      });
1158
0
}
1159
1160
1.97k
void ConfigHelper::setConnectTimeout(std::chrono::milliseconds timeout) {
1161
1.97k
  RELEASE_ASSERT(!finalized_, "");
1162
1163
1.97k
  auto* static_resources = bootstrap_.mutable_static_resources();
1164
4.36k
  for (int i = 0; i < bootstrap_.mutable_static_resources()->clusters_size(); ++i) {
1165
2.39k
    auto* cluster = static_resources->mutable_clusters(i);
1166
2.39k
    cluster->mutable_connect_timeout()->MergeFrom(
1167
2.39k
        ProtobufUtil::TimeUtil::MillisecondsToDuration(timeout.count()));
1168
2.39k
  }
1169
1.97k
  connect_timeout_set_ = true;
1170
1.97k
}
1171
1172
0
void ConfigHelper::disableDelayClose() {
1173
0
  addConfigModifier(
1174
0
      [](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
1175
0
             hcm) { hcm.mutable_delayed_close_timeout()->set_nanos(0); });
1176
0
}
1177
1178
0
void ConfigHelper::setDownstreamMaxRequestsPerConnection(uint64_t max_requests_per_connection) {
1179
0
  addConfigModifier(
1180
0
      [max_requests_per_connection](
1181
0
          envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
1182
0
              hcm) {
1183
0
        hcm.mutable_common_http_protocol_options()
1184
0
            ->mutable_max_requests_per_connection()
1185
0
            ->set_value(max_requests_per_connection);
1186
0
      });
1187
0
}
1188
1189
envoy::config::route::v3::VirtualHost
1190
0
ConfigHelper::createVirtualHost(const char* domain, const char* prefix, const char* cluster) {
1191
0
  envoy::config::route::v3::VirtualHost virtual_host;
1192
0
  virtual_host.set_name(domain);
1193
0
  virtual_host.add_domains(domain);
1194
0
  virtual_host.add_routes()->mutable_match()->set_prefix(prefix);
1195
0
  auto* route = virtual_host.mutable_routes(0)->mutable_route();
1196
0
  route->set_cluster(cluster);
1197
0
  return virtual_host;
1198
0
}
1199
1200
0
void ConfigHelper::addVirtualHost(const envoy::config::route::v3::VirtualHost& vhost) {
1201
0
  RELEASE_ASSERT(!finalized_, "");
1202
0
  envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager
1203
0
      hcm_config;
1204
0
  loadHttpConnectionManager(hcm_config);
1205
0
  auto route_config = hcm_config.mutable_route_config();
1206
0
  auto* virtual_host = route_config->add_virtual_hosts();
1207
0
  virtual_host->CopyFrom(vhost);
1208
0
  storeHttpConnectionManager(hcm_config);
1209
0
}
1210
1211
0
void ConfigHelper::addFilter(const std::string& config) { prependFilter(config); }
1212
1213
403
void ConfigHelper::prependFilter(const std::string& config, bool downstream) {
1214
403
  RELEASE_ASSERT(!finalized_, "");
1215
403
  if (downstream) {
1216
403
    envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager
1217
403
        hcm_config;
1218
403
    loadHttpConnectionManager(hcm_config);
1219
1220
403
    auto* filter_list_back = hcm_config.add_http_filters();
1221
403
#ifdef ENVOY_ENABLE_YAML
1222
403
    TestUtility::loadFromYaml(config, *filter_list_back);
1223
#else
1224
    UNREFERENCED_PARAMETER(config);
1225
    UNREFERENCED_PARAMETER(filter_list_back);
1226
    PANIC("YAML support compiled out");
1227
#endif
1228
1229
    // Now move it to the front.
1230
806
    for (int i = hcm_config.http_filters_size() - 1; i > 0; --i) {
1231
403
      hcm_config.mutable_http_filters()->SwapElements(i, i - 1);
1232
403
    }
1233
403
    storeHttpConnectionManager(hcm_config);
1234
403
    return;
1235
403
  }
1236
1237
0
  auto* static_resources = bootstrap_.mutable_static_resources();
1238
0
  for (int i = 0; i < static_resources->clusters_size(); ++i) {
1239
0
    auto* cluster = static_resources->mutable_clusters(i);
1240
1241
0
    HttpProtocolOptions old_protocol_options;
1242
0
    if (cluster->typed_extension_protocol_options().contains(
1243
0
            "envoy.extensions.upstreams.http.v3.HttpProtocolOptions")) {
1244
0
      old_protocol_options = MessageUtil::anyConvert<ConfigHelper::HttpProtocolOptions>(
1245
0
          (*cluster->mutable_typed_extension_protocol_options())
1246
0
              ["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"]);
1247
0
    }
1248
0
    if (old_protocol_options.http_filters().empty()) {
1249
0
      auto* codec_filter = old_protocol_options.add_http_filters();
1250
0
      codec_filter->set_name("envoy.filters.http.upstream_codec");
1251
0
      codec_filter->mutable_typed_config()->PackFrom(
1252
0
          envoy::extensions::filters::http::upstream_codec::v3::UpstreamCodec::default_instance());
1253
0
    }
1254
0
    auto* filter_list_back = old_protocol_options.add_http_filters();
1255
0
#ifdef ENVOY_ENABLE_YAML
1256
0
    TestUtility::loadFromYaml(config, *filter_list_back);
1257
#else
1258
    UNREFERENCED_PARAMETER(filter_list_back);
1259
    PANIC("YAML support compiled out");
1260
#endif
1261
0
    for (int i = old_protocol_options.http_filters_size() - 1; i > 0; --i) {
1262
0
      old_protocol_options.mutable_http_filters()->SwapElements(i, i - 1);
1263
0
    }
1264
0
    (*cluster->mutable_typed_extension_protocol_options())
1265
0
        ["envoy.extensions.upstreams.http.v3.HttpProtocolOptions"]
1266
0
            .PackFrom(old_protocol_options);
1267
0
  }
1268
0
}
1269
1270
void ConfigHelper::setClientCodec(envoy::extensions::filters::network::http_connection_manager::v3::
1271
3.07k
                                      HttpConnectionManager::CodecType type) {
1272
3.07k
  RELEASE_ASSERT(!finalized_, "");
1273
3.07k
  envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager
1274
3.07k
      hcm_config;
1275
3.07k
  if (loadHttpConnectionManager(hcm_config)) {
1276
3.06k
    hcm_config.set_codec_type(type);
1277
3.06k
    storeHttpConnectionManager(hcm_config);
1278
3.06k
  }
1279
3.07k
}
1280
1281
void ConfigHelper::configDownstreamTransportSocketWithTls(
1282
    envoy::config::bootstrap::v3::Bootstrap& bootstrap,
1283
    std::function<void(envoy::extensions::transport_sockets::tls::v3::CommonTlsContext&)>
1284
        configure_tls_context,
1285
0
    bool enable_quic_early_data) {
1286
0
  for (auto& listener : *bootstrap.mutable_static_resources()->mutable_listeners()) {
1287
0
    ASSERT(listener.filter_chains_size() > 0);
1288
0
    auto* filter_chain = listener.mutable_filter_chains(0);
1289
0
    auto* transport_socket = filter_chain->mutable_transport_socket();
1290
0
    if (listener.has_udp_listener_config() && listener.udp_listener_config().has_quic_options()) {
1291
0
      transport_socket->set_name("envoy.transport_sockets.quic");
1292
0
      envoy::extensions::transport_sockets::quic::v3::QuicDownstreamTransport
1293
0
          quic_transport_socket_config;
1294
0
      configure_tls_context(*quic_transport_socket_config.mutable_downstream_tls_context()
1295
0
                                 ->mutable_common_tls_context());
1296
0
      quic_transport_socket_config.mutable_enable_early_data()->set_value(enable_quic_early_data);
1297
0
      transport_socket->mutable_typed_config()->PackFrom(quic_transport_socket_config);
1298
0
    } else if (!listener.has_udp_listener_config()) {
1299
0
      transport_socket->set_name("envoy.transport_sockets.tls");
1300
0
      envoy::extensions::transport_sockets::tls::v3::DownstreamTlsContext tls_context;
1301
0
      configure_tls_context(*tls_context.mutable_common_tls_context());
1302
0
      transport_socket->mutable_typed_config()->PackFrom(tls_context);
1303
0
    }
1304
0
  }
1305
0
}
1306
1307
0
void ConfigHelper::addSslConfig(const ServerSslOptions& options) {
1308
0
  RELEASE_ASSERT(!finalized_, "");
1309
1310
0
  auto* filter_chain =
1311
0
      bootstrap_.mutable_static_resources()->mutable_listeners(0)->mutable_filter_chains(0);
1312
0
  envoy::extensions::transport_sockets::tls::v3::DownstreamTlsContext tls_context;
1313
0
  initializeTls(options, *tls_context.mutable_common_tls_context(), false);
1314
0
  if (options.ocsp_staple_required_) {
1315
0
    tls_context.set_ocsp_staple_policy(
1316
0
        envoy::extensions::transport_sockets::tls::v3::DownstreamTlsContext::MUST_STAPLE);
1317
0
  }
1318
0
  tls_context.set_prefer_client_ciphers(options.prefer_client_ciphers_);
1319
0
  filter_chain->mutable_transport_socket()->set_name("envoy.transport_sockets.tls");
1320
0
  filter_chain->mutable_transport_socket()->mutable_typed_config()->PackFrom(tls_context);
1321
0
}
1322
1323
void ConfigHelper::addQuicDownstreamTransportSocketConfig(
1324
0
    bool enable_early_data, std::vector<absl::string_view> custom_alpns) {
1325
0
  for (auto& listener : *bootstrap_.mutable_static_resources()->mutable_listeners()) {
1326
0
    if (listener.udp_listener_config().has_quic_options()) {
1327
      // Disable SO_REUSEPORT, because it undesirably allows parallel test jobs to use the same
1328
      // port.
1329
0
      listener.mutable_enable_reuse_port()->set_value(false);
1330
0
    }
1331
0
  }
1332
0
  configDownstreamTransportSocketWithTls(
1333
0
      bootstrap_,
1334
0
      [&](envoy::extensions::transport_sockets::tls::v3::CommonTlsContext& common_tls_context) {
1335
0
        initializeTls(ServerSslOptions().setRsaCert(true).setTlsV13(true), common_tls_context,
1336
0
                      true);
1337
0
        for (absl::string_view alpn : custom_alpns) {
1338
0
          common_tls_context.add_alpn_protocols(alpn);
1339
0
        }
1340
0
      },
1341
0
      enable_early_data);
1342
0
}
1343
1344
bool ConfigHelper::setAccessLog(
1345
    const std::string& filename, absl::string_view format,
1346
0
    std::vector<envoy::config::core::v3::TypedExtensionConfig> formatters) {
1347
0
  if (getFilterFromListener("http") == nullptr) {
1348
0
    return false;
1349
0
  }
1350
  // Replace null device with a real path for the file access log.
1351
0
  envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager
1352
0
      hcm_config;
1353
0
  loadHttpConnectionManager(hcm_config);
1354
0
  envoy::extensions::access_loggers::file::v3::FileAccessLog access_log_config;
1355
0
  if (!format.empty()) {
1356
0
    auto* log_format = access_log_config.mutable_log_format();
1357
0
    log_format->mutable_text_format_source()->set_inline_string(absl::StrCat(format, "\n"));
1358
0
    if (!formatters.empty()) {
1359
0
      for (const auto& formatter : formatters) {
1360
0
        auto* added_formatter = log_format->add_formatters();
1361
0
        added_formatter->CopyFrom(formatter);
1362
0
      }
1363
0
    }
1364
0
  }
1365
0
  access_log_config.set_path(filename);
1366
0
  hcm_config.mutable_access_log(0)->mutable_typed_config()->PackFrom(access_log_config);
1367
0
  storeHttpConnectionManager(hcm_config);
1368
0
  return true;
1369
0
}
1370
1371
0
bool ConfigHelper::setListenerAccessLog(const std::string& filename, absl::string_view format) {
1372
0
  RELEASE_ASSERT(!finalized_, "");
1373
0
  if (bootstrap_.mutable_static_resources()->listeners_size() == 0) {
1374
0
    return false;
1375
0
  }
1376
0
  envoy::extensions::access_loggers::file::v3::FileAccessLog access_log_config;
1377
0
  if (!format.empty()) {
1378
0
    access_log_config.mutable_log_format()->mutable_text_format_source()->set_inline_string(
1379
0
        std::string(format));
1380
0
  }
1381
0
  access_log_config.set_path(filename);
1382
0
  bootstrap_.mutable_static_resources()
1383
0
      ->mutable_listeners(0)
1384
0
      ->add_access_log()
1385
0
      ->mutable_typed_config()
1386
0
      ->PackFrom(access_log_config);
1387
0
  return true;
1388
0
}
1389
1390
void ConfigHelper::initializeTlsKeyLog(
1391
    envoy::extensions::transport_sockets::tls::v3::CommonTlsContext& tls_context,
1392
0
    const ServerSslOptions& options) {
1393
0
  if (options.keylog_path_.empty()) {
1394
0
    return;
1395
0
  }
1396
0
  auto tls_keylog_path = tls_context.mutable_key_log()->mutable_path();
1397
0
  *tls_keylog_path = options.keylog_path_;
1398
1399
0
  if (options.keylog_local_filter_) {
1400
0
    auto tls_keylog_local = tls_context.mutable_key_log()->mutable_local_address_range();
1401
0
    auto new_element_local = tls_keylog_local->Add();
1402
0
    if (options.keylog_local_negative_) {
1403
0
      if (options.ip_version_ == Network::Address::IpVersion::v6) {
1404
0
        new_element_local->set_address_prefix("1::2");
1405
0
        new_element_local->mutable_prefix_len()->set_value(128);
1406
0
      } else {
1407
0
        new_element_local->set_address_prefix("127.0.0.2");
1408
0
        new_element_local->mutable_prefix_len()->set_value(32);
1409
0
      }
1410
0
    } else {
1411
0
      new_element_local->set_address_prefix(
1412
0
          Network::Test::getLoopbackAddressString(options.ip_version_));
1413
0
      if (options.keylog_multiple_ips_) {
1414
0
        auto more_local = tls_keylog_local->Add();
1415
0
        if (options.ip_version_ == Network::Address::IpVersion::v6) {
1416
0
          more_local->set_address_prefix("1::2");
1417
0
          more_local->mutable_prefix_len()->set_value(128);
1418
0
        } else {
1419
0
          more_local->set_address_prefix("127.0.0.2");
1420
0
          more_local->mutable_prefix_len()->set_value(32);
1421
0
        }
1422
0
      }
1423
0
    }
1424
0
  }
1425
1426
0
  if (options.keylog_remote_filter_) {
1427
0
    auto tls_keylog_remote = tls_context.mutable_key_log()->mutable_remote_address_range();
1428
0
    auto new_element_remote = tls_keylog_remote->Add();
1429
0
    if (options.keylog_remote_negative_) {
1430
0
      if (options.ip_version_ == Network::Address::IpVersion::v6) {
1431
0
        new_element_remote->set_address_prefix("1::2");
1432
0
        new_element_remote->mutable_prefix_len()->set_value(128);
1433
0
      } else {
1434
0
        new_element_remote->set_address_prefix("127.0.0.2");
1435
0
        new_element_remote->mutable_prefix_len()->set_value(32);
1436
0
      }
1437
0
    } else {
1438
0
      new_element_remote->set_address_prefix(
1439
0
          Network::Test::getLoopbackAddressString(options.ip_version_));
1440
0
      if (options.keylog_multiple_ips_) {
1441
0
        auto more_remote = tls_keylog_remote->Add();
1442
0
        if (options.ip_version_ == Network::Address::IpVersion::v6) {
1443
0
          more_remote->set_address_prefix("1::2");
1444
0
          more_remote->mutable_prefix_len()->set_value(128);
1445
0
        } else {
1446
0
          more_remote->set_address_prefix("127.0.0.2");
1447
0
          more_remote->mutable_prefix_len()->set_value(32);
1448
0
        }
1449
0
      }
1450
0
    }
1451
0
  }
1452
0
}
1453
1454
void ConfigHelper::initializeTls(
1455
    const ServerSslOptions& options,
1456
    envoy::extensions::transport_sockets::tls::v3::CommonTlsContext& common_tls_context,
1457
0
    bool http3) {
1458
0
  if (!http3) {
1459
    // If it's HTTP/3, leave it empty as QUIC will derive the supported ALPNs from QUIC version by
1460
    // default.
1461
0
    common_tls_context.add_alpn_protocols(Http::Utility::AlpnNames::get().Http2);
1462
0
    common_tls_context.add_alpn_protocols(Http::Utility::AlpnNames::get().Http11);
1463
0
  }
1464
1465
0
  auto* validation_context = common_tls_context.mutable_validation_context();
1466
0
  if (options.custom_validator_config_) {
1467
0
    validation_context->set_allocated_custom_validator_config(options.custom_validator_config_);
1468
0
  } else {
1469
0
    if (options.client_with_intermediate_cert_) {
1470
0
      validation_context->add_verify_certificate_hash(TEST_CLIENT2_CERT_HASH);
1471
0
      std::string cert_yaml;
1472
0
      if (options.trust_root_only_) {
1473
0
        cert_yaml = R"EOF(
1474
0
        trusted_ca:
1475
0
          filename: "{{ test_rundir }}/test/config/integration/certs/cacert.pem"
1476
0
      )EOF";
1477
0
      } else {
1478
0
        cert_yaml = R"EOF(
1479
0
        trusted_ca:
1480
0
          filename: "{{ test_rundir }}/test/config/integration/certs/intermediate_partial_ca_cert_chain.pem"
1481
0
      )EOF";
1482
0
      }
1483
0
#ifdef ENVOY_ENABLE_YAML
1484
0
      TestUtility::loadFromYaml(TestEnvironment::substitute(cert_yaml), *validation_context);
1485
#else
1486
      UNREFERENCED_PARAMETER(cert_yaml);
1487
      PANIC("YAML support compiled out");
1488
#endif
1489
0
      if (options.max_verify_depth_.has_value()) {
1490
0
        validation_context->mutable_max_verify_depth()->set_value(
1491
0
            options.max_verify_depth_.value());
1492
0
      }
1493
0
    } else {
1494
0
      validation_context->mutable_trusted_ca()->set_filename(
1495
0
          TestEnvironment::runfilesPath("test/config/integration/certs/cacert.pem"));
1496
0
      validation_context->add_verify_certificate_hash(
1497
0
          options.expect_client_ecdsa_cert_ ? TEST_CLIENT_ECDSA_CERT_HASH : TEST_CLIENT_CERT_HASH);
1498
0
    }
1499
0
  }
1500
0
  validation_context->set_allow_expired_certificate(options.allow_expired_certificate_);
1501
1502
  // We'll negotiate up to TLSv1.3 for the tests that care, but it really
1503
  // depends on what the client sets.
1504
0
  common_tls_context.mutable_tls_params()->set_tls_maximum_protocol_version(
1505
0
      options.tlsv1_3_ ? envoy::extensions::transport_sockets::tls::v3::TlsParameters::TLSv1_3
1506
0
                       : envoy::extensions::transport_sockets::tls::v3::TlsParameters::TLSv1_2);
1507
0
  for (const auto& curve : options.curves_) {
1508
0
    common_tls_context.mutable_tls_params()->add_ecdh_curves(curve);
1509
0
  }
1510
0
  for (const auto& cipher : options.ciphers_) {
1511
0
    common_tls_context.mutable_tls_params()->add_cipher_suites(cipher);
1512
0
  }
1513
0
  if (options.rsa_cert_) {
1514
0
    auto* tls_certificate = common_tls_context.add_tls_certificates();
1515
0
    tls_certificate->mutable_certificate_chain()->set_filename(
1516
0
        TestEnvironment::runfilesPath("test/config/integration/certs/servercert.pem"));
1517
0
    tls_certificate->mutable_private_key()->set_filename(
1518
0
        TestEnvironment::runfilesPath("test/config/integration/certs/serverkey.pem"));
1519
0
    if (options.rsa_cert_ocsp_staple_) {
1520
0
      tls_certificate->mutable_ocsp_staple()->set_filename(
1521
0
          TestEnvironment::runfilesPath("test/config/integration/certs/server_ocsp_resp.der"));
1522
0
    }
1523
0
  }
1524
0
  if (options.ecdsa_cert_) {
1525
0
    auto* tls_certificate = common_tls_context.add_tls_certificates();
1526
0
    tls_certificate->mutable_certificate_chain()->set_filename(
1527
0
        TestEnvironment::runfilesPath("test/config/integration/certs/server_ecdsacert.pem"));
1528
0
    tls_certificate->mutable_private_key()->set_filename(
1529
0
        TestEnvironment::runfilesPath("test/config/integration/certs/server_ecdsakey.pem"));
1530
0
    if (options.ecdsa_cert_ocsp_staple_) {
1531
0
      tls_certificate->mutable_ocsp_staple()->set_filename(TestEnvironment::runfilesPath(
1532
0
          "test/config/integration/certs/server_ecdsa_ocsp_resp.der"));
1533
0
    }
1534
0
  }
1535
1536
0
  if (!options.san_matchers_.empty()) {
1537
0
    *validation_context->mutable_match_typed_subject_alt_names() = {options.san_matchers_.begin(),
1538
0
                                                                    options.san_matchers_.end()};
1539
0
  }
1540
0
  if (!options.tls_cert_selector_yaml_.empty()) {
1541
0
    auto* cert_selector = common_tls_context.mutable_custom_tls_certificate_selector();
1542
0
#ifdef ENVOY_ENABLE_YAML
1543
0
    TestUtility::loadFromYaml(TestEnvironment::substitute(options.tls_cert_selector_yaml_),
1544
0
                              *cert_selector);
1545
#else
1546
    UNREFERENCED_PARAMETER(cert_selector);
1547
    PANIC("YAML support compiled out");
1548
#endif
1549
0
  }
1550
0
  initializeTlsKeyLog(common_tls_context, options);
1551
0
}
1552
1553
1.97k
void ConfigHelper::renameListener(const std::string& name) {
1554
1.97k
  auto* static_resources = bootstrap_.mutable_static_resources();
1555
1.97k
  if (static_resources->listeners_size() > 0) {
1556
1.96k
    static_resources->mutable_listeners(0)->set_name(name);
1557
1.96k
  }
1558
1.97k
}
1559
1560
10.4k
envoy::config::listener::v3::Filter* ConfigHelper::getFilterFromListener(const std::string& name) {
1561
10.4k
  RELEASE_ASSERT(!finalized_, "");
1562
10.4k
  if (bootstrap_.mutable_static_resources()->listeners_size() == 0) {
1563
14
    return nullptr;
1564
14
  }
1565
10.4k
  auto* listener = bootstrap_.mutable_static_resources()->mutable_listeners(0);
1566
10.4k
  if (listener->filter_chains_size() == 0) {
1567
0
    return nullptr;
1568
0
  }
1569
10.4k
  auto* filter_chain = listener->mutable_filter_chains(0);
1570
10.4k
  for (ssize_t i = 0; i < filter_chain->filters_size(); i++) {
1571
10.4k
    if (filter_chain->mutable_filters(i)->name() == name) {
1572
10.4k
      return filter_chain->mutable_filters(i);
1573
10.4k
    }
1574
10.4k
  }
1575
0
  return nullptr;
1576
10.4k
}
1577
1578
envoy::config::listener::v3::ListenerFilter*
1579
0
ConfigHelper::getListenerFilterFromListener(const std::string& name) {
1580
0
  RELEASE_ASSERT(!finalized_, "");
1581
0
  if (bootstrap_.mutable_static_resources()->listeners_size() == 0) {
1582
0
    return nullptr;
1583
0
  }
1584
0
  auto* listener = bootstrap_.mutable_static_resources()->mutable_listeners(0);
1585
0
  for (ssize_t i = 0; i < listener->listener_filters_size(); i++) {
1586
0
    if (listener->mutable_listener_filters(i)->name() == name) {
1587
0
      return listener->mutable_listener_filters(i);
1588
0
    }
1589
0
  }
1590
0
  return nullptr;
1591
0
}
1592
1593
0
void ConfigHelper::addNetworkFilter(const std::string& filter_yaml) {
1594
0
  RELEASE_ASSERT(!finalized_, "");
1595
0
  auto* filter_chain =
1596
0
      bootstrap_.mutable_static_resources()->mutable_listeners(0)->mutable_filter_chains(0);
1597
0
  auto* filter_list_back = filter_chain->add_filters();
1598
0
#ifdef ENVOY_ENABLE_YAML
1599
0
  TestUtility::loadFromYaml(filter_yaml, *filter_list_back);
1600
#else
1601
  UNREFERENCED_PARAMETER(filter_list_back);
1602
  UNREFERENCED_PARAMETER(filter_yaml);
1603
  PANIC("YAML support compiled out");
1604
#endif
1605
1606
  // Now move it to the front.
1607
0
  for (int i = filter_chain->filters_size() - 1; i > 0; --i) {
1608
0
    filter_chain->mutable_filters()->SwapElements(i, i - 1);
1609
0
  }
1610
0
}
1611
1612
0
void ConfigHelper::addListenerFilter(const std::string& filter_yaml) {
1613
0
  RELEASE_ASSERT(!finalized_, "");
1614
0
  auto* listener = bootstrap_.mutable_static_resources()->mutable_listeners(0);
1615
0
  auto* filter_list_back = listener->add_listener_filters();
1616
0
#ifdef ENVOY_ENABLE_YAML
1617
0
  TestUtility::loadFromYaml(filter_yaml, *filter_list_back);
1618
#else
1619
  UNREFERENCED_PARAMETER(filter_list_back);
1620
  UNREFERENCED_PARAMETER(filter_yaml);
1621
  PANIC("YAML support compiled out");
1622
#endif
1623
1624
  // Now move it to the front.
1625
0
  for (int i = listener->listener_filters_size() - 1; i > 0; --i) {
1626
0
    listener->mutable_listener_filters()->SwapElements(i, i - 1);
1627
0
  }
1628
0
}
1629
1630
0
void ConfigHelper::addBootstrapExtension(const std::string& config) {
1631
0
  RELEASE_ASSERT(!finalized_, "");
1632
0
  auto* extension = bootstrap_.add_bootstrap_extensions();
1633
0
#ifdef ENVOY_ENABLE_YAML
1634
0
  TestUtility::loadFromYaml(config, *extension);
1635
#else
1636
  UNREFERENCED_PARAMETER(extension);
1637
  UNREFERENCED_PARAMETER(config);
1638
  PANIC("YAML support compiled out");
1639
#endif
1640
0
}
1641
1642
bool ConfigHelper::loadHttpConnectionManager(
1643
5.04k
    envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& hcm) {
1644
5.04k
  return loadFilter<
1645
5.04k
      envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager>(
1646
5.04k
      "http", hcm);
1647
5.04k
}
1648
1649
void ConfigHelper::storeHttpConnectionManager(
1650
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
1651
5.02k
        hcm) {
1652
5.02k
  return storeFilter<
1653
5.02k
      envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager>(
1654
5.02k
      "http", hcm);
1655
5.02k
}
1656
1657
0
bool ConfigHelper::loadUdpProxyFilter(UdpProxyConfig& udp_proxy) {
1658
0
  return loadListenerFilter<UdpProxyConfig>("udp_proxy", udp_proxy);
1659
0
}
1660
1661
0
void ConfigHelper::storeUdpProxyFilter(const UdpProxyConfig& udp_proxy) {
1662
0
  return storeListenerFilter<UdpProxyConfig>("udp_proxy", udp_proxy);
1663
0
}
1664
1665
5.01k
void ConfigHelper::addConfigModifier(ConfigModifierFunction function) {
1666
5.01k
  RELEASE_ASSERT(!finalized_, "");
1667
5.01k
  config_modifiers_.push_back(std::move(function));
1668
5.01k
}
1669
1670
1.16k
void ConfigHelper::addConfigModifier(HttpModifierFunction function) {
1671
1.16k
  addConfigModifier([function, this](envoy::config::bootstrap::v3::Bootstrap&) -> void {
1672
1.16k
    envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager
1673
1.16k
        hcm_config;
1674
1.16k
    if (!loadHttpConnectionManager(hcm_config)) {
1675
0
      return;
1676
0
    }
1677
1.16k
    function(hcm_config);
1678
1.16k
    storeHttpConnectionManager(hcm_config);
1679
1.16k
  });
1680
1.16k
}
1681
1682
0
void ConfigHelper::addConfigModifier(UdpProxyModifierFunction function) {
1683
0
  addConfigModifier([function, this](envoy::config::bootstrap::v3::Bootstrap&) -> void {
1684
0
    UdpProxyConfig udp_proxy_config;
1685
0
    if (!loadUdpProxyFilter(udp_proxy_config)) {
1686
0
      return;
1687
0
    }
1688
0
    function(udp_proxy_config);
1689
0
    storeUdpProxyFilter(udp_proxy_config);
1690
0
  });
1691
0
}
1692
1693
0
void ConfigHelper::setLds(absl::string_view version_info) {
1694
0
  applyConfigModifiers();
1695
1696
0
  envoy::service::discovery::v3::DiscoveryResponse lds;
1697
0
  lds.set_version_info(std::string(version_info));
1698
0
  for (auto& listener : bootstrap_.static_resources().listeners()) {
1699
0
    ProtobufWkt::Any* resource = lds.add_resources();
1700
0
    resource->PackFrom(listener);
1701
0
  }
1702
1703
0
  const std::string lds_filename =
1704
0
      bootstrap().dynamic_resources().lds_config().path_config_source().path();
1705
0
#ifdef ENVOY_ENABLE_YAML
1706
0
  std::string file = TestEnvironment::writeStringToFileForTest(
1707
0
      "new_lds_file", MessageUtil::getJsonStringFromMessageOrError(lds));
1708
0
  TestEnvironment::renameFile(file, lds_filename);
1709
#else
1710
  UNREFERENCED_PARAMETER(lds_filename);
1711
  PANIC("YAML support compiled out");
1712
#endif
1713
0
}
1714
1715
void ConfigHelper::setDownstreamOutboundFramesLimits(uint32_t max_all_frames,
1716
0
                                                     uint32_t max_control_frames) {
1717
0
  auto filter = getFilterFromListener("http");
1718
0
  if (filter) {
1719
0
    envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager
1720
0
        hcm_config;
1721
0
    loadHttpConnectionManager(hcm_config);
1722
0
    if (hcm_config.codec_type() == envoy::extensions::filters::network::http_connection_manager::
1723
0
                                       v3::HttpConnectionManager::HTTP2) {
1724
0
      auto* options = hcm_config.mutable_http2_protocol_options();
1725
0
      options->mutable_max_outbound_frames()->set_value(max_all_frames);
1726
0
      options->mutable_max_outbound_control_frames()->set_value(max_control_frames);
1727
0
      storeHttpConnectionManager(hcm_config);
1728
0
    }
1729
0
  }
1730
0
}
1731
1732
void ConfigHelper::setUpstreamOutboundFramesLimits(uint32_t max_all_frames,
1733
0
                                                   uint32_t max_control_frames) {
1734
0
  addConfigModifier(
1735
0
      [max_all_frames, max_control_frames](envoy::config::bootstrap::v3::Bootstrap& bootstrap) {
1736
0
        ConfigHelper::HttpProtocolOptions protocol_options;
1737
0
        auto* http_protocol_options =
1738
0
            protocol_options.mutable_explicit_http_config()->mutable_http2_protocol_options();
1739
0
        http_protocol_options->mutable_max_outbound_frames()->set_value(max_all_frames);
1740
0
        http_protocol_options->mutable_max_outbound_control_frames()->set_value(max_control_frames);
1741
0
        ConfigHelper::setProtocolOptions(*bootstrap.mutable_static_resources()->mutable_clusters(0),
1742
0
                                         protocol_options);
1743
0
      });
1744
0
}
1745
1746
void ConfigHelper::setLocalReply(
1747
    const envoy::extensions::filters::network::http_connection_manager::v3::LocalReplyConfig&
1748
0
        config) {
1749
0
  envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager
1750
0
      hcm_config;
1751
0
  loadHttpConnectionManager(hcm_config);
1752
0
  hcm_config.mutable_local_reply_config()->MergeFrom(config);
1753
0
  storeHttpConnectionManager(hcm_config);
1754
0
}
1755
1756
void ConfigHelper::adjustUpstreamTimeoutForTsan(
1757
0
    envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& hcm) {
1758
0
  auto* route =
1759
0
      hcm.mutable_route_config()->mutable_virtual_hosts(0)->mutable_routes(0)->mutable_route();
1760
0
  uint64_t timeout_ms = PROTOBUF_GET_MS_OR_DEFAULT(*route, timeout, 15000u);
1761
0
  auto* timeout = route->mutable_timeout();
1762
  // QUIC stream processing is slow under TSAN. Use larger timeout to prevent
1763
  // response_timeout.
1764
0
  timeout->set_seconds(TIMEOUT_FACTOR * timeout_ms / 1000);
1765
0
}
1766
1767
envoy::config::core::v3::Http3ProtocolOptions ConfigHelper::http2ToHttp3ProtocolOptions(
1768
    const envoy::config::core::v3::Http2ProtocolOptions& http2_options,
1769
815
    size_t http3_max_stream_receive_window) {
1770
815
  envoy::config::core::v3::Http3ProtocolOptions http3_options;
1771
815
  if (http2_options.has_initial_stream_window_size() &&
1772
815
      http2_options.initial_stream_window_size().value() < http3_max_stream_receive_window) {
1773
    // Set http3 stream flow control window only if the configured http2 stream flow control
1774
    // window is smaller than the upper limit of flow control window supported by QUICHE which is
1775
    // also the default for http3 streams.
1776
0
    http3_options.mutable_quic_protocol_options()->mutable_initial_stream_window_size()->set_value(
1777
0
        http2_options.initial_stream_window_size().value());
1778
0
  }
1779
815
  if (http2_options.has_override_stream_error_on_invalid_http_message()) {
1780
815
    http3_options.mutable_override_stream_error_on_invalid_http_message()->set_value(
1781
815
        http2_options.override_stream_error_on_invalid_http_message().value());
1782
815
  } else if (http2_options.stream_error_on_invalid_http_messaging()) {
1783
0
    http3_options.mutable_override_stream_error_on_invalid_http_message()->set_value(true);
1784
0
  }
1785
815
  return http3_options;
1786
815
}
1787
1788
0
CdsHelper::CdsHelper() : cds_path_(TestEnvironment::writeStringToFileForTest("cds.pb_text", "")) {}
1789
1790
0
void CdsHelper::setCds(const std::vector<envoy::config::cluster::v3::Cluster>& clusters) {
1791
  // Write to file the DiscoveryResponse and trigger inotify watch.
1792
0
  envoy::service::discovery::v3::DiscoveryResponse cds_response;
1793
0
  cds_response.set_version_info(std::to_string(cds_version_++));
1794
0
  cds_response.set_type_url(Config::TypeUrl::get().Cluster);
1795
0
  for (const auto& cluster : clusters) {
1796
0
    cds_response.add_resources()->PackFrom(cluster);
1797
0
  }
1798
  // Past the initial write, need move semantics to trigger inotify move event that the
1799
  // FilesystemSubscriptionImpl is subscribed to.
1800
0
  std::string path = TestEnvironment::writeStringToFileForTest(
1801
0
      "cds.update.pb_text", MessageUtil::toTextProto(cds_response));
1802
0
  TestEnvironment::renameFile(path, cds_path_);
1803
0
}
1804
1805
0
EdsHelper::EdsHelper() : eds_path_(TestEnvironment::writeStringToFileForTest("eds.pb_text", "")) {
1806
  // cluster.cluster_0.update_success will be incremented on the initial
1807
  // load when Envoy comes up.
1808
0
  ++update_successes_;
1809
0
}
1810
1811
void EdsHelper::setEds(const std::vector<envoy::config::endpoint::v3::ClusterLoadAssignment>&
1812
0
                           cluster_load_assignments) {
1813
  // Write to file the DiscoveryResponse and trigger inotify watch.
1814
0
  envoy::service::discovery::v3::DiscoveryResponse eds_response;
1815
0
  eds_response.set_version_info(std::to_string(eds_version_++));
1816
0
  eds_response.set_type_url(Config::TypeUrl::get().ClusterLoadAssignment);
1817
0
  for (const auto& cluster_load_assignment : cluster_load_assignments) {
1818
0
    eds_response.add_resources()->PackFrom(cluster_load_assignment);
1819
0
  }
1820
  // Past the initial write, need move semantics to trigger inotify move event that the
1821
  // FilesystemSubscriptionImpl is subscribed to.
1822
0
  std::string path = TestEnvironment::writeStringToFileForTest(
1823
0
      "eds.update.pb_text", MessageUtil::toTextProto(eds_response));
1824
0
  TestEnvironment::renameFile(path, eds_path_);
1825
0
}
1826
1827
void EdsHelper::setEdsAndWait(
1828
    const std::vector<envoy::config::endpoint::v3::ClusterLoadAssignment>& cluster_load_assignments,
1829
0
    IntegrationTestServerStats& server_stats) {
1830
  // Make sure the last version has been accepted before setting a new one.
1831
0
  server_stats.waitForCounterGe("cluster.cluster_0.update_success", update_successes_);
1832
0
  setEds(cluster_load_assignments);
1833
  // Make sure Envoy has consumed the update now that it is running.
1834
0
  ++update_successes_;
1835
0
  server_stats.waitForCounterGe("cluster.cluster_0.update_success", update_successes_);
1836
0
  RELEASE_ASSERT(
1837
0
      update_successes_ == server_stats.counter("cluster.cluster_0.update_success")->value(), "");
1838
0
}
1839
1840
} // namespace Envoy