google.golang.org/grpc@v1.62.1/xds/internal/xdsclient/xdsresource/unmarshal_lds_test.go (about) 1 /* 2 * 3 * Copyright 2021 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package xdsresource 19 20 import ( 21 "fmt" 22 "strings" 23 "testing" 24 "time" 25 26 v2xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2" 27 "github.com/google/go-cmp/cmp" 28 "google.golang.org/grpc/internal/pretty" 29 "google.golang.org/grpc/internal/testutils" 30 "google.golang.org/grpc/internal/testutils/xds/e2e" 31 "google.golang.org/grpc/xds/internal/httpfilter" 32 "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" 33 "google.golang.org/protobuf/proto" 34 "google.golang.org/protobuf/types/known/anypb" 35 "google.golang.org/protobuf/types/known/durationpb" 36 "google.golang.org/protobuf/types/known/structpb" 37 "google.golang.org/protobuf/types/known/wrapperspb" 38 39 v1udpaudpatypepb "github.com/cncf/udpa/go/udpa/type/v1" 40 v3xdsxdstypepb "github.com/cncf/xds/go/xds/type/v3" 41 v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" 42 v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" 43 rpb "github.com/envoyproxy/go-control-plane/envoy/config/rbac/v3" 44 v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" 45 v3rbacpb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/rbac/v3" 46 v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" 47 v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" 48 v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" 49 v3matcherpb "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3" 50 51 _ "google.golang.org/grpc/xds/internal/httpfilter/rbac" // Register the RBAC HTTP filter. 52 _ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter. 53 ) 54 55 func (s) TestUnmarshalListener_ClientSide(t *testing.T) { 56 const ( 57 v3LDSTarget = "lds.target.good:3333" 58 v3RouteConfigName = "v3RouteConfig" 59 routeName = "routeName" 60 ) 61 62 var ( 63 customFilter = &v3httppb.HttpFilter{ 64 Name: "customFilter", 65 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: customFilterConfig}, 66 } 67 oldTypedStructFilter = &v3httppb.HttpFilter{ 68 Name: "customFilter", 69 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: testutils.MarshalAny(t, customFilterOldTypedStructConfig)}, 70 } 71 newTypedStructFilter = &v3httppb.HttpFilter{ 72 Name: "customFilter", 73 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: testutils.MarshalAny(t, customFilterNewTypedStructConfig)}, 74 } 75 customOptionalFilter = &v3httppb.HttpFilter{ 76 Name: "customFilter", 77 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: customFilterConfig}, 78 IsOptional: true, 79 } 80 customFilter2 = &v3httppb.HttpFilter{ 81 Name: "customFilter2", 82 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: customFilterConfig}, 83 } 84 errFilter = &v3httppb.HttpFilter{ 85 Name: "errFilter", 86 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: errFilterConfig}, 87 } 88 errOptionalFilter = &v3httppb.HttpFilter{ 89 Name: "errFilter", 90 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: errFilterConfig}, 91 IsOptional: true, 92 } 93 clientOnlyCustomFilter = &v3httppb.HttpFilter{ 94 Name: "clientOnlyCustomFilter", 95 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: clientOnlyCustomFilterConfig}, 96 } 97 serverOnlyCustomFilter = &v3httppb.HttpFilter{ 98 Name: "serverOnlyCustomFilter", 99 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: serverOnlyCustomFilterConfig}, 100 } 101 serverOnlyOptionalCustomFilter = &v3httppb.HttpFilter{ 102 Name: "serverOnlyOptionalCustomFilter", 103 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: serverOnlyCustomFilterConfig}, 104 IsOptional: true, 105 } 106 unknownFilter = &v3httppb.HttpFilter{ 107 Name: "unknownFilter", 108 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: unknownFilterConfig}, 109 } 110 unknownOptionalFilter = &v3httppb.HttpFilter{ 111 Name: "unknownFilter", 112 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: unknownFilterConfig}, 113 IsOptional: true, 114 } 115 v3LisWithInlineRoute = testutils.MarshalAny(t, &v3listenerpb.Listener{ 116 Name: v3LDSTarget, 117 ApiListener: &v3listenerpb.ApiListener{ 118 ApiListener: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 119 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 120 RouteConfig: &v3routepb.RouteConfiguration{ 121 Name: routeName, 122 VirtualHosts: []*v3routepb.VirtualHost{{ 123 Domains: []string{v3LDSTarget}, 124 Routes: []*v3routepb.Route{{ 125 Match: &v3routepb.RouteMatch{ 126 PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"}, 127 }, 128 Action: &v3routepb.Route_Route{ 129 Route: &v3routepb.RouteAction{ 130 ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: clusterName}, 131 }}}}}}}, 132 }, 133 HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter}, 134 CommonHttpProtocolOptions: &v3corepb.HttpProtocolOptions{ 135 MaxStreamDuration: durationpb.New(time.Second), 136 }, 137 }), 138 }, 139 }) 140 v3LisWithFilters = func(fs ...*v3httppb.HttpFilter) *anypb.Any { 141 fs = append(fs, emptyRouterFilter) 142 return testutils.MarshalAny(t, &v3listenerpb.Listener{ 143 Name: v3LDSTarget, 144 ApiListener: &v3listenerpb.ApiListener{ 145 ApiListener: testutils.MarshalAny(t, 146 &v3httppb.HttpConnectionManager{ 147 RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ 148 Rds: &v3httppb.Rds{ 149 ConfigSource: &v3corepb.ConfigSource{ 150 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}}, 151 }, 152 RouteConfigName: v3RouteConfigName, 153 }, 154 }, 155 CommonHttpProtocolOptions: &v3corepb.HttpProtocolOptions{ 156 MaxStreamDuration: durationpb.New(time.Second), 157 }, 158 HttpFilters: fs, 159 }), 160 }, 161 }) 162 } 163 v3LisToTestRBAC = func(xffNumTrustedHops uint32, originalIpDetectionExtensions []*v3corepb.TypedExtensionConfig) *anypb.Any { 164 return testutils.MarshalAny(t, &v3listenerpb.Listener{ 165 Name: v3LDSTarget, 166 ApiListener: &v3listenerpb.ApiListener{ 167 ApiListener: testutils.MarshalAny(t, 168 &v3httppb.HttpConnectionManager{ 169 RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ 170 Rds: &v3httppb.Rds{ 171 ConfigSource: &v3corepb.ConfigSource{ 172 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}}, 173 }, 174 RouteConfigName: v3RouteConfigName, 175 }, 176 }, 177 CommonHttpProtocolOptions: &v3corepb.HttpProtocolOptions{ 178 MaxStreamDuration: durationpb.New(time.Second), 179 }, 180 HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter}, 181 XffNumTrustedHops: xffNumTrustedHops, 182 OriginalIpDetectionExtensions: originalIpDetectionExtensions, 183 }), 184 }, 185 }) 186 } 187 188 v3ListenerWithCDSConfigSourceSelf = testutils.MarshalAny(t, &v3listenerpb.Listener{ 189 Name: v3LDSTarget, 190 ApiListener: &v3listenerpb.ApiListener{ 191 ApiListener: testutils.MarshalAny(t, 192 &v3httppb.HttpConnectionManager{ 193 RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ 194 Rds: &v3httppb.Rds{ 195 ConfigSource: &v3corepb.ConfigSource{ 196 ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{}, 197 }, 198 RouteConfigName: v3RouteConfigName, 199 }, 200 }, 201 HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter}, 202 }), 203 }, 204 }) 205 ) 206 207 tests := []struct { 208 name string 209 resource *anypb.Any 210 wantName string 211 wantUpdate ListenerUpdate 212 wantErr bool 213 }{ 214 { 215 name: "non-listener resource", 216 resource: &anypb.Any{TypeUrl: version.V3HTTPConnManagerURL}, 217 wantErr: true, 218 }, 219 { 220 name: "badly marshaled listener resource", 221 resource: &anypb.Any{ 222 TypeUrl: version.V3ListenerURL, 223 Value: func() []byte { 224 lis := &v3listenerpb.Listener{ 225 Name: v3LDSTarget, 226 ApiListener: &v3listenerpb.ApiListener{ 227 ApiListener: &anypb.Any{ 228 TypeUrl: version.V3HTTPConnManagerURL, 229 Value: []byte{1, 2, 3, 4}, 230 }, 231 }, 232 } 233 mLis, _ := proto.Marshal(lis) 234 return mLis 235 }(), 236 }, 237 wantName: v3LDSTarget, 238 wantErr: true, 239 }, 240 { 241 name: "wrong type in apiListener", 242 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 243 Name: v3LDSTarget, 244 ApiListener: &v3listenerpb.ApiListener{ 245 ApiListener: testutils.MarshalAny(t, &v2xdspb.Listener{}), 246 }, 247 }), 248 wantName: v3LDSTarget, 249 wantErr: true, 250 }, 251 { 252 name: "empty httpConnMgr in apiListener", 253 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 254 Name: v3LDSTarget, 255 ApiListener: &v3listenerpb.ApiListener{ 256 ApiListener: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 257 RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ 258 Rds: &v3httppb.Rds{}, 259 }, 260 }), 261 }, 262 }), 263 wantName: v3LDSTarget, 264 wantErr: true, 265 }, 266 { 267 name: "scopedRoutes routeConfig in apiListener", 268 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 269 Name: v3LDSTarget, 270 ApiListener: &v3listenerpb.ApiListener{ 271 ApiListener: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 272 RouteSpecifier: &v3httppb.HttpConnectionManager_ScopedRoutes{}, 273 }), 274 }, 275 }), 276 wantName: v3LDSTarget, 277 wantErr: true, 278 }, 279 { 280 name: "rds.ConfigSource in apiListener is Self", 281 resource: v3ListenerWithCDSConfigSourceSelf, 282 wantName: v3LDSTarget, 283 wantUpdate: ListenerUpdate{ 284 RouteConfigName: v3RouteConfigName, 285 HTTPFilters: []HTTPFilter{makeRouterFilter(t)}, 286 Raw: v3ListenerWithCDSConfigSourceSelf, 287 }, 288 }, 289 { 290 name: "rds.ConfigSource in apiListener is not ADS or Self", 291 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 292 Name: v3LDSTarget, 293 ApiListener: &v3listenerpb.ApiListener{ 294 ApiListener: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 295 RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ 296 Rds: &v3httppb.Rds{ 297 ConfigSource: &v3corepb.ConfigSource{ 298 ConfigSourceSpecifier: &v3corepb.ConfigSource_Path{ 299 Path: "/some/path", 300 }, 301 }, 302 RouteConfigName: v3RouteConfigName, 303 }, 304 }, 305 }), 306 }, 307 }), 308 wantName: v3LDSTarget, 309 wantErr: true, 310 }, 311 { 312 name: "v3 with no filters", 313 resource: v3LisWithFilters(), 314 wantName: v3LDSTarget, 315 wantUpdate: ListenerUpdate{ 316 RouteConfigName: v3RouteConfigName, 317 MaxStreamDuration: time.Second, 318 HTTPFilters: makeRouterFilterList(t), 319 Raw: v3LisWithFilters(), 320 }, 321 }, 322 { 323 name: "v3 no terminal filter", 324 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 325 Name: v3LDSTarget, 326 ApiListener: &v3listenerpb.ApiListener{ 327 ApiListener: testutils.MarshalAny(t, 328 &v3httppb.HttpConnectionManager{ 329 RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ 330 Rds: &v3httppb.Rds{ 331 ConfigSource: &v3corepb.ConfigSource{ 332 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}}, 333 }, 334 RouteConfigName: v3RouteConfigName, 335 }, 336 }, 337 CommonHttpProtocolOptions: &v3corepb.HttpProtocolOptions{ 338 MaxStreamDuration: durationpb.New(time.Second), 339 }, 340 }), 341 }, 342 }), 343 wantName: v3LDSTarget, 344 wantErr: true, 345 }, 346 { 347 name: "v3 with custom filter", 348 resource: v3LisWithFilters(customFilter), 349 wantName: v3LDSTarget, 350 wantUpdate: ListenerUpdate{ 351 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 352 HTTPFilters: []HTTPFilter{ 353 { 354 Name: "customFilter", 355 Filter: httpFilter{}, 356 Config: filterConfig{Cfg: customFilterConfig}, 357 }, 358 makeRouterFilter(t), 359 }, 360 Raw: v3LisWithFilters(customFilter), 361 }, 362 }, 363 { 364 name: "v3 with custom filter in old typed struct", 365 resource: v3LisWithFilters(oldTypedStructFilter), 366 wantName: v3LDSTarget, 367 wantUpdate: ListenerUpdate{ 368 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 369 HTTPFilters: []HTTPFilter{ 370 { 371 Name: "customFilter", 372 Filter: httpFilter{}, 373 Config: filterConfig{Cfg: customFilterOldTypedStructConfig}, 374 }, 375 makeRouterFilter(t), 376 }, 377 Raw: v3LisWithFilters(oldTypedStructFilter), 378 }, 379 }, 380 { 381 name: "v3 with custom filter in new typed struct", 382 resource: v3LisWithFilters(newTypedStructFilter), 383 wantName: v3LDSTarget, 384 wantUpdate: ListenerUpdate{ 385 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 386 HTTPFilters: []HTTPFilter{ 387 { 388 Name: "customFilter", 389 Filter: httpFilter{}, 390 Config: filterConfig{Cfg: customFilterNewTypedStructConfig}, 391 }, 392 makeRouterFilter(t), 393 }, 394 Raw: v3LisWithFilters(newTypedStructFilter), 395 }, 396 }, 397 { 398 name: "v3 with optional custom filter", 399 resource: v3LisWithFilters(customOptionalFilter), 400 wantName: v3LDSTarget, 401 wantUpdate: ListenerUpdate{ 402 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 403 HTTPFilters: []HTTPFilter{ 404 { 405 Name: "customFilter", 406 Filter: httpFilter{}, 407 Config: filterConfig{Cfg: customFilterConfig}, 408 }, 409 makeRouterFilter(t), 410 }, 411 Raw: v3LisWithFilters(customOptionalFilter), 412 }, 413 }, 414 { 415 name: "v3 with two filters with same name", 416 resource: v3LisWithFilters(customFilter, customFilter), 417 wantName: v3LDSTarget, 418 wantErr: true, 419 }, 420 { 421 name: "v3 with two filters - same type different name", 422 resource: v3LisWithFilters(customFilter, customFilter2), 423 wantName: v3LDSTarget, 424 wantUpdate: ListenerUpdate{ 425 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 426 HTTPFilters: []HTTPFilter{{ 427 Name: "customFilter", 428 Filter: httpFilter{}, 429 Config: filterConfig{Cfg: customFilterConfig}, 430 }, { 431 Name: "customFilter2", 432 Filter: httpFilter{}, 433 Config: filterConfig{Cfg: customFilterConfig}, 434 }, 435 makeRouterFilter(t), 436 }, 437 Raw: v3LisWithFilters(customFilter, customFilter2), 438 }, 439 }, 440 { 441 name: "v3 with server-only filter", 442 resource: v3LisWithFilters(serverOnlyCustomFilter), 443 wantName: v3LDSTarget, 444 wantErr: true, 445 }, 446 { 447 name: "v3 with optional server-only filter", 448 resource: v3LisWithFilters(serverOnlyOptionalCustomFilter), 449 wantName: v3LDSTarget, 450 wantUpdate: ListenerUpdate{ 451 RouteConfigName: v3RouteConfigName, 452 MaxStreamDuration: time.Second, 453 Raw: v3LisWithFilters(serverOnlyOptionalCustomFilter), 454 HTTPFilters: makeRouterFilterList(t), 455 }, 456 }, 457 { 458 name: "v3 with client-only filter", 459 resource: v3LisWithFilters(clientOnlyCustomFilter), 460 wantName: v3LDSTarget, 461 wantUpdate: ListenerUpdate{ 462 RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, 463 HTTPFilters: []HTTPFilter{ 464 { 465 Name: "clientOnlyCustomFilter", 466 Filter: clientOnlyHTTPFilter{}, 467 Config: filterConfig{Cfg: clientOnlyCustomFilterConfig}, 468 }, 469 makeRouterFilter(t)}, 470 Raw: v3LisWithFilters(clientOnlyCustomFilter), 471 }, 472 }, 473 { 474 name: "v3 with err filter", 475 resource: v3LisWithFilters(errFilter), 476 wantName: v3LDSTarget, 477 wantErr: true, 478 }, 479 { 480 name: "v3 with optional err filter", 481 resource: v3LisWithFilters(errOptionalFilter), 482 wantName: v3LDSTarget, 483 wantErr: true, 484 }, 485 { 486 name: "v3 with unknown filter", 487 resource: v3LisWithFilters(unknownFilter), 488 wantName: v3LDSTarget, 489 wantErr: true, 490 }, 491 { 492 name: "v3 with unknown filter (optional)", 493 resource: v3LisWithFilters(unknownOptionalFilter), 494 wantName: v3LDSTarget, 495 wantUpdate: ListenerUpdate{ 496 RouteConfigName: v3RouteConfigName, 497 MaxStreamDuration: time.Second, 498 HTTPFilters: makeRouterFilterList(t), 499 Raw: v3LisWithFilters(unknownOptionalFilter), 500 }, 501 }, 502 { 503 name: "v3 listener resource", 504 resource: v3LisWithFilters(), 505 wantName: v3LDSTarget, 506 wantUpdate: ListenerUpdate{ 507 RouteConfigName: v3RouteConfigName, 508 MaxStreamDuration: time.Second, 509 HTTPFilters: makeRouterFilterList(t), 510 Raw: v3LisWithFilters(), 511 }, 512 }, 513 { 514 name: "v3 listener resource wrapped", 515 resource: testutils.MarshalAny(t, &v3discoverypb.Resource{Resource: v3LisWithFilters()}), 516 wantName: v3LDSTarget, 517 wantUpdate: ListenerUpdate{ 518 RouteConfigName: v3RouteConfigName, 519 MaxStreamDuration: time.Second, 520 HTTPFilters: makeRouterFilterList(t), 521 Raw: v3LisWithFilters(), 522 }, 523 }, 524 // "To allow equating RBAC's direct_remote_ip and 525 // remote_ip...HttpConnectionManager.xff_num_trusted_hops must be unset 526 // or zero and HttpConnectionManager.original_ip_detection_extensions 527 // must be empty." - A41 528 { 529 name: "rbac-allow-equating-direct-remote-ip-and-remote-ip-valid", 530 resource: v3LisToTestRBAC(0, nil), 531 wantName: v3LDSTarget, 532 wantUpdate: ListenerUpdate{ 533 RouteConfigName: v3RouteConfigName, 534 MaxStreamDuration: time.Second, 535 HTTPFilters: []HTTPFilter{makeRouterFilter(t)}, 536 Raw: v3LisToTestRBAC(0, nil), 537 }, 538 }, 539 // In order to support xDS Configured RBAC HTTPFilter equating direct 540 // remote ip and remote ip, xffNumTrustedHops cannot be greater than 541 // zero. This is because if you can trust a ingress proxy hop when 542 // determining an origin clients ip address, direct remote ip != remote 543 // ip. 544 { 545 name: "rbac-allow-equating-direct-remote-ip-and-remote-ip-invalid-num-untrusted-hops", 546 resource: v3LisToTestRBAC(1, nil), 547 wantName: v3LDSTarget, 548 wantErr: true, 549 }, 550 // In order to support xDS Configured RBAC HTTPFilter equating direct 551 // remote ip and remote ip, originalIpDetectionExtensions must be empty. 552 // This is because if you have to ask ip-detection-extension for the 553 // original ip, direct remote ip might not equal remote ip. 554 { 555 name: "rbac-allow-equating-direct-remote-ip-and-remote-ip-invalid-original-ip-detection-extension", 556 resource: v3LisToTestRBAC(0, []*v3corepb.TypedExtensionConfig{{Name: "something"}}), 557 wantName: v3LDSTarget, 558 wantErr: true, 559 }, 560 { 561 name: "v3 listener with inline route configuration", 562 resource: v3LisWithInlineRoute, 563 wantName: v3LDSTarget, 564 wantUpdate: ListenerUpdate{ 565 InlineRouteConfig: &RouteConfigUpdate{ 566 VirtualHosts: []*VirtualHost{{ 567 Domains: []string{v3LDSTarget}, 568 Routes: []*Route{{Prefix: newStringP("/"), WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}}, ActionType: RouteActionRoute}}, 569 }}}, 570 MaxStreamDuration: time.Second, 571 Raw: v3LisWithInlineRoute, 572 HTTPFilters: makeRouterFilterList(t), 573 }, 574 }, 575 } 576 577 for _, test := range tests { 578 t.Run(test.name, func(t *testing.T) { 579 name, update, err := unmarshalListenerResource(test.resource) 580 if (err != nil) != test.wantErr { 581 t.Errorf("unmarshalListenerResource(%s), got err: %v, wantErr: %v", pretty.ToJSON(test.resource), err, test.wantErr) 582 } 583 if name != test.wantName { 584 t.Errorf("unmarshalListenerResource(%s), got name: %s, want: %s", pretty.ToJSON(test.resource), name, test.wantName) 585 } 586 if diff := cmp.Diff(update, test.wantUpdate, cmpOpts); diff != "" { 587 t.Errorf("unmarshalListenerResource(%s), got unexpected update, diff (-got +want): %v", pretty.ToJSON(test.resource), diff) 588 } 589 }) 590 } 591 } 592 593 func (s) TestUnmarshalListener_ServerSide(t *testing.T) { 594 const ( 595 v3LDSTarget = "grpc/server?xds.resource.listening_address=0.0.0.0:9999" 596 testVersion = "test-version-lds-server" 597 ) 598 599 var ( 600 serverOnlyCustomFilter = &v3httppb.HttpFilter{ 601 Name: "serverOnlyCustomFilter", 602 ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: serverOnlyCustomFilterConfig}, 603 } 604 routeConfig = &v3routepb.RouteConfiguration{ 605 Name: "routeName", 606 VirtualHosts: []*v3routepb.VirtualHost{{ 607 Domains: []string{"lds.target.good:3333"}, 608 Routes: []*v3routepb.Route{{ 609 Match: &v3routepb.RouteMatch{ 610 PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"}, 611 }, 612 Action: &v3routepb.Route_NonForwardingAction{}, 613 }}}}} 614 inlineRouteConfig = &RouteConfigUpdate{ 615 VirtualHosts: []*VirtualHost{{ 616 Domains: []string{"lds.target.good:3333"}, 617 Routes: []*Route{{Prefix: newStringP("/"), ActionType: RouteActionNonForwardingAction}}, 618 }}} 619 emptyValidNetworkFilters = []*v3listenerpb.Filter{ 620 { 621 Name: "filter-1", 622 ConfigType: &v3listenerpb.Filter_TypedConfig{ 623 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 624 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 625 RouteConfig: routeConfig, 626 }, 627 HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter}, 628 }), 629 }, 630 }, 631 } 632 localSocketAddress = &v3corepb.Address{ 633 Address: &v3corepb.Address_SocketAddress{ 634 SocketAddress: &v3corepb.SocketAddress{ 635 Address: "0.0.0.0", 636 PortSpecifier: &v3corepb.SocketAddress_PortValue{ 637 PortValue: 9999, 638 }, 639 }, 640 }, 641 } 642 listenerEmptyTransportSocket = testutils.MarshalAny(t, &v3listenerpb.Listener{ 643 Name: v3LDSTarget, 644 Address: localSocketAddress, 645 FilterChains: []*v3listenerpb.FilterChain{ 646 { 647 Name: "filter-chain-1", 648 Filters: emptyValidNetworkFilters, 649 }, 650 }, 651 }) 652 listenerNoValidationContextDeprecatedFields = testutils.MarshalAny(t, &v3listenerpb.Listener{ 653 Name: v3LDSTarget, 654 Address: localSocketAddress, 655 FilterChains: []*v3listenerpb.FilterChain{ 656 { 657 Name: "filter-chain-1", 658 Filters: emptyValidNetworkFilters, 659 TransportSocket: &v3corepb.TransportSocket{ 660 Name: "envoy.transport_sockets.tls", 661 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 662 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 663 CommonTlsContext: &v3tlspb.CommonTlsContext{ 664 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 665 InstanceName: "identityPluginInstance", 666 CertificateName: "identityCertName", 667 }, 668 }, 669 }), 670 }, 671 }, 672 }, 673 }, 674 DefaultFilterChain: &v3listenerpb.FilterChain{ 675 Name: "default-filter-chain-1", 676 Filters: emptyValidNetworkFilters, 677 TransportSocket: &v3corepb.TransportSocket{ 678 Name: "envoy.transport_sockets.tls", 679 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 680 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 681 CommonTlsContext: &v3tlspb.CommonTlsContext{ 682 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 683 InstanceName: "defaultIdentityPluginInstance", 684 CertificateName: "defaultIdentityCertName", 685 }, 686 }, 687 }), 688 }, 689 }, 690 }, 691 }) 692 listenerNoValidationContextNewFields = testutils.MarshalAny(t, &v3listenerpb.Listener{ 693 Name: v3LDSTarget, 694 Address: localSocketAddress, 695 FilterChains: []*v3listenerpb.FilterChain{ 696 { 697 Name: "filter-chain-1", 698 Filters: emptyValidNetworkFilters, 699 TransportSocket: &v3corepb.TransportSocket{ 700 Name: "envoy.transport_sockets.tls", 701 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 702 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 703 CommonTlsContext: &v3tlspb.CommonTlsContext{ 704 TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{ 705 InstanceName: "identityPluginInstance", 706 CertificateName: "identityCertName", 707 }, 708 }, 709 }), 710 }, 711 }, 712 }, 713 }, 714 DefaultFilterChain: &v3listenerpb.FilterChain{ 715 Name: "default-filter-chain-1", 716 Filters: emptyValidNetworkFilters, 717 TransportSocket: &v3corepb.TransportSocket{ 718 Name: "envoy.transport_sockets.tls", 719 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 720 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 721 CommonTlsContext: &v3tlspb.CommonTlsContext{ 722 TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{ 723 InstanceName: "defaultIdentityPluginInstance", 724 CertificateName: "defaultIdentityCertName", 725 }, 726 }, 727 }), 728 }, 729 }, 730 }, 731 }) 732 listenerWithValidationContextDeprecatedFields = testutils.MarshalAny(t, &v3listenerpb.Listener{ 733 Name: v3LDSTarget, 734 Address: localSocketAddress, 735 FilterChains: []*v3listenerpb.FilterChain{ 736 { 737 Name: "filter-chain-1", 738 Filters: emptyValidNetworkFilters, 739 TransportSocket: &v3corepb.TransportSocket{ 740 Name: "envoy.transport_sockets.tls", 741 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 742 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 743 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 744 CommonTlsContext: &v3tlspb.CommonTlsContext{ 745 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 746 InstanceName: "identityPluginInstance", 747 CertificateName: "identityCertName", 748 }, 749 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextCertificateProviderInstance{ 750 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 751 InstanceName: "rootPluginInstance", 752 CertificateName: "rootCertName", 753 }, 754 }, 755 }, 756 }), 757 }, 758 }, 759 }, 760 }, 761 DefaultFilterChain: &v3listenerpb.FilterChain{ 762 Name: "default-filter-chain-1", 763 Filters: emptyValidNetworkFilters, 764 TransportSocket: &v3corepb.TransportSocket{ 765 Name: "envoy.transport_sockets.tls", 766 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 767 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 768 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 769 CommonTlsContext: &v3tlspb.CommonTlsContext{ 770 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 771 InstanceName: "defaultIdentityPluginInstance", 772 CertificateName: "defaultIdentityCertName", 773 }, 774 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextCertificateProviderInstance{ 775 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 776 InstanceName: "defaultRootPluginInstance", 777 CertificateName: "defaultRootCertName", 778 }, 779 }, 780 }, 781 }), 782 }, 783 }, 784 }, 785 }) 786 listenerWithValidationContextNewFields = testutils.MarshalAny(t, &v3listenerpb.Listener{ 787 Name: v3LDSTarget, 788 Address: localSocketAddress, 789 FilterChains: []*v3listenerpb.FilterChain{ 790 { 791 Name: "filter-chain-1", 792 Filters: emptyValidNetworkFilters, 793 TransportSocket: &v3corepb.TransportSocket{ 794 Name: "envoy.transport_sockets.tls", 795 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 796 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 797 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 798 CommonTlsContext: &v3tlspb.CommonTlsContext{ 799 TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{ 800 InstanceName: "identityPluginInstance", 801 CertificateName: "identityCertName", 802 }, 803 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{ 804 ValidationContext: &v3tlspb.CertificateValidationContext{ 805 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{ 806 InstanceName: "rootPluginInstance", 807 CertificateName: "rootCertName", 808 }, 809 }, 810 }, 811 }, 812 }), 813 }, 814 }, 815 }, 816 }, 817 DefaultFilterChain: &v3listenerpb.FilterChain{ 818 Name: "default-filter-chain-1", 819 Filters: emptyValidNetworkFilters, 820 TransportSocket: &v3corepb.TransportSocket{ 821 Name: "envoy.transport_sockets.tls", 822 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 823 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 824 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 825 CommonTlsContext: &v3tlspb.CommonTlsContext{ 826 TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{ 827 InstanceName: "defaultIdentityPluginInstance", 828 CertificateName: "defaultIdentityCertName", 829 }, 830 ValidationContextType: &v3tlspb.CommonTlsContext_CombinedValidationContext{ 831 CombinedValidationContext: &v3tlspb.CommonTlsContext_CombinedCertificateValidationContext{ 832 DefaultValidationContext: &v3tlspb.CertificateValidationContext{ 833 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{ 834 InstanceName: "defaultRootPluginInstance", 835 CertificateName: "defaultRootCertName", 836 }, 837 }, 838 }, 839 }, 840 }, 841 }), 842 }, 843 }, 844 }, 845 }) 846 ) 847 v3LisToTestRBAC := func(xffNumTrustedHops uint32, originalIpDetectionExtensions []*v3corepb.TypedExtensionConfig) *anypb.Any { 848 return testutils.MarshalAny(t, &v3listenerpb.Listener{ 849 Name: v3LDSTarget, 850 Address: localSocketAddress, 851 FilterChains: []*v3listenerpb.FilterChain{ 852 { 853 Name: "filter-chain-1", 854 Filters: []*v3listenerpb.Filter{ 855 { 856 Name: "filter-1", 857 ConfigType: &v3listenerpb.Filter_TypedConfig{ 858 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 859 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 860 RouteConfig: routeConfig, 861 }, 862 HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter}, 863 XffNumTrustedHops: xffNumTrustedHops, 864 OriginalIpDetectionExtensions: originalIpDetectionExtensions, 865 }), 866 }, 867 }, 868 }, 869 }, 870 }, 871 }) 872 } 873 v3LisWithBadRBACConfiguration := func(rbacCfg *v3rbacpb.RBAC) *anypb.Any { 874 return testutils.MarshalAny(t, &v3listenerpb.Listener{ 875 Name: v3LDSTarget, 876 Address: localSocketAddress, 877 FilterChains: []*v3listenerpb.FilterChain{ 878 { 879 Name: "filter-chain-1", 880 Filters: []*v3listenerpb.Filter{ 881 { 882 Name: "filter-1", 883 ConfigType: &v3listenerpb.Filter_TypedConfig{ 884 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 885 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 886 RouteConfig: routeConfig, 887 }, 888 HttpFilters: []*v3httppb.HttpFilter{e2e.HTTPFilter("rbac", rbacCfg), e2e.RouterHTTPFilter}, 889 }), 890 }, 891 }, 892 }, 893 }, 894 }, 895 }) 896 } 897 badRBACCfgRegex := &v3rbacpb.RBAC{ 898 Rules: &rpb.RBAC{ 899 Action: rpb.RBAC_ALLOW, 900 Policies: map[string]*rpb.Policy{ 901 "bad-regex-value": { 902 Permissions: []*rpb.Permission{ 903 {Rule: &rpb.Permission_Any{Any: true}}, 904 }, 905 Principals: []*rpb.Principal{ 906 {Identifier: &rpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_SafeRegexMatch{SafeRegexMatch: &v3matcherpb.RegexMatcher{Regex: "["}}}}}, 907 }, 908 }, 909 }, 910 }, 911 } 912 badRBACCfgDestIP := &v3rbacpb.RBAC{ 913 Rules: &rpb.RBAC{ 914 Action: rpb.RBAC_ALLOW, 915 Policies: map[string]*rpb.Policy{ 916 "certain-destination-ip": { 917 Permissions: []*rpb.Permission{ 918 {Rule: &rpb.Permission_DestinationIp{DestinationIp: &v3corepb.CidrRange{AddressPrefix: "not a correct address", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}}, 919 }, 920 Principals: []*rpb.Principal{ 921 {Identifier: &rpb.Principal_Any{Any: true}}, 922 }, 923 }, 924 }, 925 }, 926 } 927 928 tests := []struct { 929 name string 930 resource *anypb.Any 931 wantName string 932 wantUpdate ListenerUpdate 933 wantErr string 934 }{ 935 { 936 name: "non-empty listener filters", 937 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 938 Name: v3LDSTarget, 939 ListenerFilters: []*v3listenerpb.ListenerFilter{ 940 {Name: "listener-filter-1"}, 941 }, 942 }), 943 wantName: v3LDSTarget, 944 wantErr: "unsupported field 'listener_filters'", 945 }, 946 { 947 name: "use_original_dst is set", 948 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 949 Name: v3LDSTarget, 950 UseOriginalDst: &wrapperspb.BoolValue{Value: true}, 951 }), 952 wantName: v3LDSTarget, 953 wantErr: "unsupported field 'use_original_dst'", 954 }, 955 { 956 name: "no address field", 957 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{Name: v3LDSTarget}), 958 wantName: v3LDSTarget, 959 wantErr: "no address field in LDS response", 960 }, 961 { 962 name: "no socket address field", 963 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 964 Name: v3LDSTarget, 965 Address: &v3corepb.Address{}, 966 }), 967 wantName: v3LDSTarget, 968 wantErr: "no socket_address field in LDS response", 969 }, 970 { 971 name: "no filter chains and no default filter chain", 972 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 973 Name: v3LDSTarget, 974 Address: localSocketAddress, 975 FilterChains: []*v3listenerpb.FilterChain{ 976 { 977 FilterChainMatch: &v3listenerpb.FilterChainMatch{DestinationPort: &wrapperspb.UInt32Value{Value: 666}}, 978 Filters: emptyValidNetworkFilters, 979 }, 980 }, 981 }), 982 wantName: v3LDSTarget, 983 wantErr: "no supported filter chains and no default filter chain", 984 }, 985 { 986 name: "missing http connection manager network filter", 987 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 988 Name: v3LDSTarget, 989 Address: localSocketAddress, 990 FilterChains: []*v3listenerpb.FilterChain{ 991 { 992 Name: "filter-chain-1", 993 }, 994 }, 995 }), 996 wantName: v3LDSTarget, 997 wantErr: "missing HttpConnectionManager filter", 998 }, 999 { 1000 name: "missing filter name in http filter", 1001 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1002 Name: v3LDSTarget, 1003 Address: localSocketAddress, 1004 FilterChains: []*v3listenerpb.FilterChain{ 1005 { 1006 Name: "filter-chain-1", 1007 Filters: []*v3listenerpb.Filter{ 1008 { 1009 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1010 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{}), 1011 }, 1012 }, 1013 }, 1014 }, 1015 }, 1016 }), 1017 wantName: v3LDSTarget, 1018 wantErr: "missing name field in filter", 1019 }, 1020 { 1021 name: "duplicate filter names in http filter", 1022 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1023 Name: v3LDSTarget, 1024 Address: localSocketAddress, 1025 FilterChains: []*v3listenerpb.FilterChain{ 1026 { 1027 Name: "filter-chain-1", 1028 Filters: []*v3listenerpb.Filter{ 1029 { 1030 Name: "name", 1031 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1032 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 1033 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 1034 RouteConfig: routeConfig, 1035 }, 1036 HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter}, 1037 }), 1038 }, 1039 }, 1040 { 1041 Name: "name", 1042 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1043 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 1044 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 1045 RouteConfig: routeConfig, 1046 }, 1047 HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter}, 1048 }), 1049 }, 1050 }, 1051 }, 1052 }, 1053 }, 1054 }), 1055 wantName: v3LDSTarget, 1056 wantErr: "duplicate filter name", 1057 }, 1058 { 1059 name: "no terminal filter", 1060 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1061 Name: v3LDSTarget, 1062 Address: localSocketAddress, 1063 FilterChains: []*v3listenerpb.FilterChain{ 1064 { 1065 Name: "filter-chain-1", 1066 Filters: []*v3listenerpb.Filter{ 1067 { 1068 Name: "name", 1069 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1070 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 1071 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 1072 RouteConfig: routeConfig, 1073 }, 1074 }), 1075 }, 1076 }, 1077 }, 1078 }, 1079 }, 1080 }), 1081 wantName: v3LDSTarget, 1082 wantErr: "http filters list is empty", 1083 }, 1084 { 1085 name: "terminal filter not last", 1086 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1087 Name: v3LDSTarget, 1088 Address: localSocketAddress, 1089 FilterChains: []*v3listenerpb.FilterChain{ 1090 { 1091 Name: "filter-chain-1", 1092 Filters: []*v3listenerpb.Filter{ 1093 { 1094 Name: "name", 1095 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1096 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 1097 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 1098 RouteConfig: routeConfig, 1099 }, 1100 HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter, serverOnlyCustomFilter}, 1101 }), 1102 }, 1103 }, 1104 }, 1105 }, 1106 }, 1107 }), 1108 wantName: v3LDSTarget, 1109 wantErr: "is a terminal filter but it is not last in the filter chain", 1110 }, 1111 { 1112 name: "last not terminal filter", 1113 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1114 Name: v3LDSTarget, 1115 Address: localSocketAddress, 1116 FilterChains: []*v3listenerpb.FilterChain{ 1117 { 1118 Name: "filter-chain-1", 1119 Filters: []*v3listenerpb.Filter{ 1120 { 1121 Name: "name", 1122 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1123 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 1124 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 1125 RouteConfig: routeConfig, 1126 }, 1127 HttpFilters: []*v3httppb.HttpFilter{serverOnlyCustomFilter}, 1128 }), 1129 }, 1130 }, 1131 }, 1132 }, 1133 }, 1134 }), 1135 wantName: v3LDSTarget, 1136 wantErr: "is not a terminal filter", 1137 }, 1138 { 1139 name: "unsupported oneof in typed config of http filter", 1140 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1141 Name: v3LDSTarget, 1142 Address: localSocketAddress, 1143 FilterChains: []*v3listenerpb.FilterChain{ 1144 { 1145 Name: "filter-chain-1", 1146 Filters: []*v3listenerpb.Filter{ 1147 { 1148 Name: "name", 1149 ConfigType: &v3listenerpb.Filter_ConfigDiscovery{}, 1150 }, 1151 }, 1152 }, 1153 }, 1154 }), 1155 wantName: v3LDSTarget, 1156 wantErr: "unsupported config_type", 1157 }, 1158 { 1159 name: "overlapping filter chain match criteria", 1160 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1161 Name: v3LDSTarget, 1162 Address: localSocketAddress, 1163 FilterChains: []*v3listenerpb.FilterChain{ 1164 { 1165 FilterChainMatch: &v3listenerpb.FilterChainMatch{SourcePorts: []uint32{1, 2, 3, 4, 5}}, 1166 Filters: emptyValidNetworkFilters, 1167 }, 1168 { 1169 FilterChainMatch: &v3listenerpb.FilterChainMatch{}, 1170 Filters: emptyValidNetworkFilters, 1171 }, 1172 { 1173 FilterChainMatch: &v3listenerpb.FilterChainMatch{SourcePorts: []uint32{5, 6, 7}}, 1174 Filters: emptyValidNetworkFilters, 1175 }, 1176 }, 1177 }), 1178 wantName: v3LDSTarget, 1179 wantErr: "multiple filter chains with overlapping matching rules are defined", 1180 }, 1181 { 1182 name: "unsupported network filter", 1183 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1184 Name: v3LDSTarget, 1185 Address: localSocketAddress, 1186 FilterChains: []*v3listenerpb.FilterChain{ 1187 { 1188 Name: "filter-chain-1", 1189 Filters: []*v3listenerpb.Filter{ 1190 { 1191 Name: "name", 1192 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1193 TypedConfig: testutils.MarshalAny(t, &v3httppb.LocalReplyConfig{}), 1194 }, 1195 }, 1196 }, 1197 }, 1198 }, 1199 }), 1200 wantName: v3LDSTarget, 1201 wantErr: "unsupported network filter", 1202 }, 1203 { 1204 name: "badly marshaled network filter", 1205 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1206 Name: v3LDSTarget, 1207 Address: localSocketAddress, 1208 FilterChains: []*v3listenerpb.FilterChain{ 1209 { 1210 Name: "filter-chain-1", 1211 Filters: []*v3listenerpb.Filter{ 1212 { 1213 Name: "name", 1214 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1215 TypedConfig: &anypb.Any{ 1216 TypeUrl: version.V3HTTPConnManagerURL, 1217 Value: []byte{1, 2, 3, 4}, 1218 }, 1219 }, 1220 }, 1221 }, 1222 }, 1223 }, 1224 }), 1225 wantName: v3LDSTarget, 1226 wantErr: "failed unmarshaling of network filter", 1227 }, 1228 { 1229 name: "unexpected transport socket name", 1230 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1231 Name: v3LDSTarget, 1232 Address: localSocketAddress, 1233 FilterChains: []*v3listenerpb.FilterChain{ 1234 { 1235 Name: "filter-chain-1", 1236 Filters: emptyValidNetworkFilters, 1237 TransportSocket: &v3corepb.TransportSocket{ 1238 Name: "unsupported-transport-socket-name", 1239 }, 1240 }, 1241 }, 1242 }), 1243 wantName: v3LDSTarget, 1244 wantErr: "transport_socket field has unexpected name", 1245 }, 1246 { 1247 name: "unexpected transport socket typedConfig URL", 1248 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1249 Name: v3LDSTarget, 1250 Address: localSocketAddress, 1251 FilterChains: []*v3listenerpb.FilterChain{ 1252 { 1253 Name: "filter-chain-1", 1254 Filters: emptyValidNetworkFilters, 1255 TransportSocket: &v3corepb.TransportSocket{ 1256 Name: "envoy.transport_sockets.tls", 1257 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1258 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{}), 1259 }, 1260 }, 1261 }, 1262 }, 1263 }), 1264 wantName: v3LDSTarget, 1265 wantErr: "transport_socket field has unexpected typeURL", 1266 }, 1267 { 1268 name: "badly marshaled transport socket", 1269 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1270 Name: v3LDSTarget, 1271 Address: localSocketAddress, 1272 FilterChains: []*v3listenerpb.FilterChain{ 1273 { 1274 Name: "filter-chain-1", 1275 Filters: emptyValidNetworkFilters, 1276 TransportSocket: &v3corepb.TransportSocket{ 1277 Name: "envoy.transport_sockets.tls", 1278 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1279 TypedConfig: &anypb.Any{ 1280 TypeUrl: version.V3DownstreamTLSContextURL, 1281 Value: []byte{1, 2, 3, 4}, 1282 }, 1283 }, 1284 }, 1285 }, 1286 }, 1287 }), 1288 wantName: v3LDSTarget, 1289 wantErr: "failed to unmarshal DownstreamTlsContext in LDS response", 1290 }, 1291 { 1292 name: "missing CommonTlsContext", 1293 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1294 Name: v3LDSTarget, 1295 Address: localSocketAddress, 1296 FilterChains: []*v3listenerpb.FilterChain{ 1297 { 1298 Name: "filter-chain-1", 1299 Filters: emptyValidNetworkFilters, 1300 TransportSocket: &v3corepb.TransportSocket{ 1301 Name: "envoy.transport_sockets.tls", 1302 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1303 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{}), 1304 }, 1305 }, 1306 }, 1307 }, 1308 }), 1309 wantName: v3LDSTarget, 1310 wantErr: "DownstreamTlsContext in LDS response does not contain a CommonTlsContext", 1311 }, 1312 { 1313 name: "rbac-allow-equating-direct-remote-ip-and-remote-ip-valid", 1314 resource: v3LisToTestRBAC(0, nil), 1315 wantName: v3LDSTarget, 1316 wantUpdate: ListenerUpdate{ 1317 InboundListenerCfg: &InboundListenerConfig{ 1318 Address: "0.0.0.0", 1319 Port: "9999", 1320 FilterChains: &FilterChainManager{ 1321 dstPrefixMap: map[string]*destPrefixEntry{ 1322 unspecifiedPrefixMapKey: { 1323 srcTypeArr: [3]*sourcePrefixes{ 1324 { 1325 srcPrefixMap: map[string]*sourcePrefixEntry{ 1326 unspecifiedPrefixMapKey: { 1327 srcPortMap: map[int]*FilterChain{ 1328 0: { 1329 InlineRouteConfig: inlineRouteConfig, 1330 HTTPFilters: makeRouterFilterList(t), 1331 }, 1332 }, 1333 }, 1334 }, 1335 }, 1336 }, 1337 }, 1338 }, 1339 }, 1340 }, 1341 Raw: listenerEmptyTransportSocket, 1342 }, 1343 }, 1344 { 1345 name: "rbac-allow-equating-direct-remote-ip-and-remote-ip-invalid-num-untrusted-hops", 1346 resource: v3LisToTestRBAC(1, nil), 1347 wantName: v3LDSTarget, 1348 wantErr: "xff_num_trusted_hops must be unset or zero", 1349 }, 1350 { 1351 name: "rbac-allow-equating-direct-remote-ip-and-remote-ip-invalid-original-ip-detection-extension", 1352 resource: v3LisToTestRBAC(0, []*v3corepb.TypedExtensionConfig{{Name: "something"}}), 1353 wantName: v3LDSTarget, 1354 wantErr: "original_ip_detection_extensions must be empty", 1355 }, 1356 { 1357 name: "rbac-with-invalid-regex", 1358 resource: v3LisWithBadRBACConfiguration(badRBACCfgRegex), 1359 wantName: v3LDSTarget, 1360 wantErr: "error parsing config for filter", 1361 }, 1362 { 1363 name: "rbac-with-invalid-destination-ip-matcher", 1364 resource: v3LisWithBadRBACConfiguration(badRBACCfgDestIP), 1365 wantName: v3LDSTarget, 1366 wantErr: "error parsing config for filter", 1367 }, 1368 { 1369 name: "unsupported validation context in transport socket", 1370 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1371 Name: v3LDSTarget, 1372 Address: localSocketAddress, 1373 FilterChains: []*v3listenerpb.FilterChain{ 1374 { 1375 Name: "filter-chain-1", 1376 Filters: emptyValidNetworkFilters, 1377 TransportSocket: &v3corepb.TransportSocket{ 1378 Name: "envoy.transport_sockets.tls", 1379 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1380 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 1381 CommonTlsContext: &v3tlspb.CommonTlsContext{ 1382 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextSdsSecretConfig{ 1383 ValidationContextSdsSecretConfig: &v3tlspb.SdsSecretConfig{ 1384 Name: "foo-sds-secret", 1385 }, 1386 }, 1387 }, 1388 }), 1389 }, 1390 }, 1391 }, 1392 }, 1393 }), 1394 wantName: v3LDSTarget, 1395 wantErr: "validation context contains unexpected type", 1396 }, 1397 { 1398 name: "empty transport socket", 1399 resource: listenerEmptyTransportSocket, 1400 wantName: v3LDSTarget, 1401 wantUpdate: ListenerUpdate{ 1402 InboundListenerCfg: &InboundListenerConfig{ 1403 Address: "0.0.0.0", 1404 Port: "9999", 1405 FilterChains: &FilterChainManager{ 1406 dstPrefixMap: map[string]*destPrefixEntry{ 1407 unspecifiedPrefixMapKey: { 1408 srcTypeArr: [3]*sourcePrefixes{ 1409 { 1410 srcPrefixMap: map[string]*sourcePrefixEntry{ 1411 unspecifiedPrefixMapKey: { 1412 srcPortMap: map[int]*FilterChain{ 1413 0: { 1414 InlineRouteConfig: inlineRouteConfig, 1415 HTTPFilters: makeRouterFilterList(t), 1416 }, 1417 }, 1418 }, 1419 }, 1420 }, 1421 }, 1422 }, 1423 }, 1424 }, 1425 }, 1426 Raw: listenerEmptyTransportSocket, 1427 }, 1428 }, 1429 { 1430 name: "no identity and root certificate providers using deprecated fields", 1431 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1432 Name: v3LDSTarget, 1433 Address: localSocketAddress, 1434 FilterChains: []*v3listenerpb.FilterChain{ 1435 { 1436 Name: "filter-chain-1", 1437 Filters: emptyValidNetworkFilters, 1438 TransportSocket: &v3corepb.TransportSocket{ 1439 Name: "envoy.transport_sockets.tls", 1440 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1441 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 1442 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 1443 CommonTlsContext: &v3tlspb.CommonTlsContext{ 1444 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 1445 InstanceName: "identityPluginInstance", 1446 CertificateName: "identityCertName", 1447 }, 1448 }, 1449 }), 1450 }, 1451 }, 1452 }, 1453 }, 1454 }), 1455 wantName: v3LDSTarget, 1456 wantErr: "security configuration on the server-side does not contain root certificate provider instance name, but require_client_cert field is set", 1457 }, 1458 { 1459 name: "no identity and root certificate providers using new fields", 1460 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1461 Name: v3LDSTarget, 1462 Address: localSocketAddress, 1463 FilterChains: []*v3listenerpb.FilterChain{ 1464 { 1465 Name: "filter-chain-1", 1466 Filters: emptyValidNetworkFilters, 1467 TransportSocket: &v3corepb.TransportSocket{ 1468 Name: "envoy.transport_sockets.tls", 1469 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1470 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 1471 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 1472 CommonTlsContext: &v3tlspb.CommonTlsContext{ 1473 TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{ 1474 InstanceName: "identityPluginInstance", 1475 CertificateName: "identityCertName", 1476 }, 1477 }, 1478 }), 1479 }, 1480 }, 1481 }, 1482 }, 1483 }), 1484 wantName: v3LDSTarget, 1485 wantErr: "security configuration on the server-side does not contain root certificate provider instance name, but require_client_cert field is set", 1486 }, 1487 { 1488 name: "no identity certificate provider with require_client_cert", 1489 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1490 Name: v3LDSTarget, 1491 Address: localSocketAddress, 1492 FilterChains: []*v3listenerpb.FilterChain{ 1493 { 1494 Name: "filter-chain-1", 1495 Filters: emptyValidNetworkFilters, 1496 TransportSocket: &v3corepb.TransportSocket{ 1497 Name: "envoy.transport_sockets.tls", 1498 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1499 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 1500 CommonTlsContext: &v3tlspb.CommonTlsContext{}, 1501 }), 1502 }, 1503 }, 1504 }, 1505 }, 1506 }), 1507 wantName: v3LDSTarget, 1508 wantErr: "security configuration on the server-side does not contain identity certificate provider instance name", 1509 }, 1510 { 1511 name: "happy case with no validation context using deprecated fields", 1512 resource: listenerNoValidationContextDeprecatedFields, 1513 wantName: v3LDSTarget, 1514 wantUpdate: ListenerUpdate{ 1515 InboundListenerCfg: &InboundListenerConfig{ 1516 Address: "0.0.0.0", 1517 Port: "9999", 1518 FilterChains: &FilterChainManager{ 1519 dstPrefixMap: map[string]*destPrefixEntry{ 1520 unspecifiedPrefixMapKey: { 1521 srcTypeArr: [3]*sourcePrefixes{ 1522 { 1523 srcPrefixMap: map[string]*sourcePrefixEntry{ 1524 unspecifiedPrefixMapKey: { 1525 srcPortMap: map[int]*FilterChain{ 1526 0: { 1527 SecurityCfg: &SecurityConfig{ 1528 IdentityInstanceName: "identityPluginInstance", 1529 IdentityCertName: "identityCertName", 1530 }, 1531 InlineRouteConfig: inlineRouteConfig, 1532 HTTPFilters: makeRouterFilterList(t), 1533 }, 1534 }, 1535 }, 1536 }, 1537 }, 1538 }, 1539 }, 1540 }, 1541 def: &FilterChain{ 1542 SecurityCfg: &SecurityConfig{ 1543 IdentityInstanceName: "defaultIdentityPluginInstance", 1544 IdentityCertName: "defaultIdentityCertName", 1545 }, 1546 InlineRouteConfig: inlineRouteConfig, 1547 HTTPFilters: makeRouterFilterList(t), 1548 }, 1549 }, 1550 }, 1551 Raw: listenerNoValidationContextDeprecatedFields, 1552 }, 1553 }, 1554 { 1555 name: "happy case with no validation context using new fields", 1556 resource: listenerNoValidationContextNewFields, 1557 wantName: v3LDSTarget, 1558 wantUpdate: ListenerUpdate{ 1559 InboundListenerCfg: &InboundListenerConfig{ 1560 Address: "0.0.0.0", 1561 Port: "9999", 1562 FilterChains: &FilterChainManager{ 1563 dstPrefixMap: map[string]*destPrefixEntry{ 1564 unspecifiedPrefixMapKey: { 1565 srcTypeArr: [3]*sourcePrefixes{ 1566 { 1567 srcPrefixMap: map[string]*sourcePrefixEntry{ 1568 unspecifiedPrefixMapKey: { 1569 srcPortMap: map[int]*FilterChain{ 1570 0: { 1571 SecurityCfg: &SecurityConfig{ 1572 IdentityInstanceName: "identityPluginInstance", 1573 IdentityCertName: "identityCertName", 1574 }, 1575 InlineRouteConfig: inlineRouteConfig, 1576 HTTPFilters: makeRouterFilterList(t), 1577 }, 1578 }, 1579 }, 1580 }, 1581 }, 1582 }, 1583 }, 1584 }, 1585 def: &FilterChain{ 1586 SecurityCfg: &SecurityConfig{ 1587 IdentityInstanceName: "defaultIdentityPluginInstance", 1588 IdentityCertName: "defaultIdentityCertName", 1589 }, 1590 InlineRouteConfig: inlineRouteConfig, 1591 HTTPFilters: makeRouterFilterList(t), 1592 }, 1593 }, 1594 }, 1595 Raw: listenerNoValidationContextNewFields, 1596 }, 1597 }, 1598 { 1599 name: "happy case with validation context provider instance with deprecated fields", 1600 resource: listenerWithValidationContextDeprecatedFields, 1601 wantName: v3LDSTarget, 1602 wantUpdate: ListenerUpdate{ 1603 InboundListenerCfg: &InboundListenerConfig{ 1604 Address: "0.0.0.0", 1605 Port: "9999", 1606 FilterChains: &FilterChainManager{ 1607 dstPrefixMap: map[string]*destPrefixEntry{ 1608 unspecifiedPrefixMapKey: { 1609 srcTypeArr: [3]*sourcePrefixes{ 1610 { 1611 srcPrefixMap: map[string]*sourcePrefixEntry{ 1612 unspecifiedPrefixMapKey: { 1613 srcPortMap: map[int]*FilterChain{ 1614 0: { 1615 SecurityCfg: &SecurityConfig{ 1616 RootInstanceName: "rootPluginInstance", 1617 RootCertName: "rootCertName", 1618 IdentityInstanceName: "identityPluginInstance", 1619 IdentityCertName: "identityCertName", 1620 RequireClientCert: true, 1621 }, 1622 InlineRouteConfig: inlineRouteConfig, 1623 HTTPFilters: makeRouterFilterList(t), 1624 }, 1625 }, 1626 }, 1627 }, 1628 }, 1629 }, 1630 }, 1631 }, 1632 def: &FilterChain{ 1633 SecurityCfg: &SecurityConfig{ 1634 RootInstanceName: "defaultRootPluginInstance", 1635 RootCertName: "defaultRootCertName", 1636 IdentityInstanceName: "defaultIdentityPluginInstance", 1637 IdentityCertName: "defaultIdentityCertName", 1638 RequireClientCert: true, 1639 }, 1640 InlineRouteConfig: inlineRouteConfig, 1641 HTTPFilters: makeRouterFilterList(t), 1642 }, 1643 }, 1644 }, 1645 Raw: listenerWithValidationContextDeprecatedFields, 1646 }, 1647 }, 1648 { 1649 name: "happy case with validation context provider instance with new fields", 1650 resource: listenerWithValidationContextNewFields, 1651 wantName: v3LDSTarget, 1652 wantUpdate: ListenerUpdate{ 1653 InboundListenerCfg: &InboundListenerConfig{ 1654 Address: "0.0.0.0", 1655 Port: "9999", 1656 FilterChains: &FilterChainManager{ 1657 dstPrefixMap: map[string]*destPrefixEntry{ 1658 unspecifiedPrefixMapKey: { 1659 srcTypeArr: [3]*sourcePrefixes{ 1660 { 1661 srcPrefixMap: map[string]*sourcePrefixEntry{ 1662 unspecifiedPrefixMapKey: { 1663 srcPortMap: map[int]*FilterChain{ 1664 0: { 1665 SecurityCfg: &SecurityConfig{ 1666 RootInstanceName: "rootPluginInstance", 1667 RootCertName: "rootCertName", 1668 IdentityInstanceName: "identityPluginInstance", 1669 IdentityCertName: "identityCertName", 1670 RequireClientCert: true, 1671 }, 1672 InlineRouteConfig: inlineRouteConfig, 1673 HTTPFilters: makeRouterFilterList(t), 1674 }, 1675 }, 1676 }, 1677 }, 1678 }, 1679 }, 1680 }, 1681 }, 1682 def: &FilterChain{ 1683 SecurityCfg: &SecurityConfig{ 1684 RootInstanceName: "defaultRootPluginInstance", 1685 RootCertName: "defaultRootCertName", 1686 IdentityInstanceName: "defaultIdentityPluginInstance", 1687 IdentityCertName: "defaultIdentityCertName", 1688 RequireClientCert: true, 1689 }, 1690 InlineRouteConfig: inlineRouteConfig, 1691 HTTPFilters: makeRouterFilterList(t), 1692 }, 1693 }, 1694 }, 1695 Raw: listenerWithValidationContextNewFields, 1696 }, 1697 }, 1698 } 1699 1700 for _, test := range tests { 1701 t.Run(test.name, func(t *testing.T) { 1702 name, update, err := unmarshalListenerResource(test.resource) 1703 if err != nil && !strings.Contains(err.Error(), test.wantErr) { 1704 t.Errorf("unmarshalListenerResource(%s) = %v wantErr: %q", pretty.ToJSON(test.resource), err, test.wantErr) 1705 } 1706 if name != test.wantName { 1707 t.Errorf("unmarshalListenerResource(%s), got name: %s, want: %s", pretty.ToJSON(test.resource), name, test.wantName) 1708 } 1709 if diff := cmp.Diff(update, test.wantUpdate, cmpOpts); diff != "" { 1710 t.Errorf("unmarshalListenerResource(%s), got unexpected update, diff (-got +want): %v", pretty.ToJSON(test.resource), diff) 1711 } 1712 }) 1713 } 1714 } 1715 1716 type filterConfig struct { 1717 httpfilter.FilterConfig 1718 Cfg proto.Message 1719 Override proto.Message 1720 } 1721 1722 // httpFilter allows testing the http filter registry and parsing functionality. 1723 type httpFilter struct { 1724 httpfilter.ClientInterceptorBuilder 1725 httpfilter.ServerInterceptorBuilder 1726 } 1727 1728 func (httpFilter) TypeURLs() []string { return []string{"custom.filter"} } 1729 1730 func (httpFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1731 return filterConfig{Cfg: cfg}, nil 1732 } 1733 1734 func (httpFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1735 return filterConfig{Override: override}, nil 1736 } 1737 1738 func (httpFilter) IsTerminal() bool { 1739 return false 1740 } 1741 1742 // errHTTPFilter returns errors no matter what is passed to ParseFilterConfig. 1743 type errHTTPFilter struct { 1744 httpfilter.ClientInterceptorBuilder 1745 } 1746 1747 func (errHTTPFilter) TypeURLs() []string { return []string{"err.custom.filter"} } 1748 1749 func (errHTTPFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1750 return nil, fmt.Errorf("error from ParseFilterConfig") 1751 } 1752 1753 func (errHTTPFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1754 return nil, fmt.Errorf("error from ParseFilterConfigOverride") 1755 } 1756 1757 func (errHTTPFilter) IsTerminal() bool { 1758 return false 1759 } 1760 1761 func init() { 1762 httpfilter.Register(httpFilter{}) 1763 httpfilter.Register(errHTTPFilter{}) 1764 httpfilter.Register(serverOnlyHTTPFilter{}) 1765 httpfilter.Register(clientOnlyHTTPFilter{}) 1766 } 1767 1768 // serverOnlyHTTPFilter does not implement ClientInterceptorBuilder 1769 type serverOnlyHTTPFilter struct { 1770 httpfilter.ServerInterceptorBuilder 1771 } 1772 1773 func (serverOnlyHTTPFilter) TypeURLs() []string { return []string{"serverOnly.custom.filter"} } 1774 1775 func (serverOnlyHTTPFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1776 return filterConfig{Cfg: cfg}, nil 1777 } 1778 1779 func (serverOnlyHTTPFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1780 return filterConfig{Override: override}, nil 1781 } 1782 1783 func (serverOnlyHTTPFilter) IsTerminal() bool { 1784 return false 1785 } 1786 1787 // clientOnlyHTTPFilter does not implement ServerInterceptorBuilder 1788 type clientOnlyHTTPFilter struct { 1789 httpfilter.ClientInterceptorBuilder 1790 } 1791 1792 func (clientOnlyHTTPFilter) TypeURLs() []string { return []string{"clientOnly.custom.filter"} } 1793 1794 func (clientOnlyHTTPFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1795 return filterConfig{Cfg: cfg}, nil 1796 } 1797 1798 func (clientOnlyHTTPFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1799 return filterConfig{Override: override}, nil 1800 } 1801 1802 func (clientOnlyHTTPFilter) IsTerminal() bool { 1803 return false 1804 } 1805 1806 var customFilterConfig = &anypb.Any{ 1807 TypeUrl: "custom.filter", 1808 Value: []byte{1, 2, 3}, 1809 } 1810 1811 var errFilterConfig = &anypb.Any{ 1812 TypeUrl: "err.custom.filter", 1813 Value: []byte{1, 2, 3}, 1814 } 1815 1816 var serverOnlyCustomFilterConfig = &anypb.Any{ 1817 TypeUrl: "serverOnly.custom.filter", 1818 Value: []byte{1, 2, 3}, 1819 } 1820 1821 var clientOnlyCustomFilterConfig = &anypb.Any{ 1822 TypeUrl: "clientOnly.custom.filter", 1823 Value: []byte{1, 2, 3}, 1824 } 1825 1826 // This custom filter uses the old TypedStruct message from the cncf/udpa repo. 1827 var customFilterOldTypedStructConfig = &v1udpaudpatypepb.TypedStruct{ 1828 TypeUrl: "custom.filter", 1829 Value: &structpb.Struct{ 1830 Fields: map[string]*structpb.Value{ 1831 "foo": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, 1832 }, 1833 }, 1834 } 1835 1836 // This custom filter uses the new TypedStruct message from the cncf/xds repo. 1837 var customFilterNewTypedStructConfig = &v3xdsxdstypepb.TypedStruct{ 1838 TypeUrl: "custom.filter", 1839 Value: &structpb.Struct{ 1840 Fields: map[string]*structpb.Value{ 1841 "foo": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, 1842 }, 1843 }, 1844 } 1845 1846 var unknownFilterConfig = &anypb.Any{ 1847 TypeUrl: "unknown.custom.filter", 1848 Value: []byte{1, 2, 3}, 1849 } 1850 1851 func wrappedOptionalFilter(t *testing.T, name string) *anypb.Any { 1852 return testutils.MarshalAny(t, &v3routepb.FilterConfig{ 1853 IsOptional: true, 1854 Config: &anypb.Any{ 1855 TypeUrl: name, 1856 Value: []byte{1, 2, 3}, 1857 }, 1858 }) 1859 }