Coverage Report

Created: 2023-11-12 09:30

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