google.golang.org/grpc@v1.72.2/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 v1xdsudpatypepb "github.com/cncf/xds/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 // SystemRootCerts is ignored when 810 // CaCertificateProviderInstance is 811 // present. 812 SystemRootCerts: &v3tlspb.CertificateValidationContext_SystemRootCerts{}, 813 }, 814 }, 815 }, 816 }), 817 }, 818 }, 819 }, 820 }, 821 DefaultFilterChain: &v3listenerpb.FilterChain{ 822 Name: "default-filter-chain-1", 823 Filters: emptyValidNetworkFilters, 824 TransportSocket: &v3corepb.TransportSocket{ 825 Name: "envoy.transport_sockets.tls", 826 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 827 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 828 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 829 CommonTlsContext: &v3tlspb.CommonTlsContext{ 830 TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{ 831 InstanceName: "defaultIdentityPluginInstance", 832 CertificateName: "defaultIdentityCertName", 833 }, 834 ValidationContextType: &v3tlspb.CommonTlsContext_CombinedValidationContext{ 835 CombinedValidationContext: &v3tlspb.CommonTlsContext_CombinedCertificateValidationContext{ 836 DefaultValidationContext: &v3tlspb.CertificateValidationContext{ 837 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{ 838 InstanceName: "defaultRootPluginInstance", 839 CertificateName: "defaultRootCertName", 840 }, 841 }, 842 }, 843 }, 844 }, 845 }), 846 }, 847 }, 848 }, 849 }) 850 ) 851 v3LisToTestRBAC := func(xffNumTrustedHops uint32, originalIpDetectionExtensions []*v3corepb.TypedExtensionConfig) *anypb.Any { 852 return testutils.MarshalAny(t, &v3listenerpb.Listener{ 853 Name: v3LDSTarget, 854 Address: localSocketAddress, 855 FilterChains: []*v3listenerpb.FilterChain{ 856 { 857 Name: "filter-chain-1", 858 Filters: []*v3listenerpb.Filter{ 859 { 860 Name: "filter-1", 861 ConfigType: &v3listenerpb.Filter_TypedConfig{ 862 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 863 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 864 RouteConfig: routeConfig, 865 }, 866 HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter}, 867 XffNumTrustedHops: xffNumTrustedHops, 868 OriginalIpDetectionExtensions: originalIpDetectionExtensions, 869 }), 870 }, 871 }, 872 }, 873 }, 874 }, 875 }) 876 } 877 v3LisWithBadRBACConfiguration := func(rbacCfg *v3rbacpb.RBAC) *anypb.Any { 878 return testutils.MarshalAny(t, &v3listenerpb.Listener{ 879 Name: v3LDSTarget, 880 Address: localSocketAddress, 881 FilterChains: []*v3listenerpb.FilterChain{ 882 { 883 Name: "filter-chain-1", 884 Filters: []*v3listenerpb.Filter{ 885 { 886 Name: "filter-1", 887 ConfigType: &v3listenerpb.Filter_TypedConfig{ 888 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 889 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 890 RouteConfig: routeConfig, 891 }, 892 HttpFilters: []*v3httppb.HttpFilter{e2e.HTTPFilter("rbac", rbacCfg), e2e.RouterHTTPFilter}, 893 }), 894 }, 895 }, 896 }, 897 }, 898 }, 899 }) 900 } 901 badRBACCfgRegex := &v3rbacpb.RBAC{ 902 Rules: &rpb.RBAC{ 903 Action: rpb.RBAC_ALLOW, 904 Policies: map[string]*rpb.Policy{ 905 "bad-regex-value": { 906 Permissions: []*rpb.Permission{ 907 {Rule: &rpb.Permission_Any{Any: true}}, 908 }, 909 Principals: []*rpb.Principal{ 910 {Identifier: &rpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_SafeRegexMatch{SafeRegexMatch: &v3matcherpb.RegexMatcher{Regex: "["}}}}}, 911 }, 912 }, 913 }, 914 }, 915 } 916 badRBACCfgDestIP := &v3rbacpb.RBAC{ 917 Rules: &rpb.RBAC{ 918 Action: rpb.RBAC_ALLOW, 919 Policies: map[string]*rpb.Policy{ 920 "certain-destination-ip": { 921 Permissions: []*rpb.Permission{ 922 {Rule: &rpb.Permission_DestinationIp{DestinationIp: &v3corepb.CidrRange{AddressPrefix: "not a correct address", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}}, 923 }, 924 Principals: []*rpb.Principal{ 925 {Identifier: &rpb.Principal_Any{Any: true}}, 926 }, 927 }, 928 }, 929 }, 930 } 931 932 tests := []struct { 933 name string 934 resource *anypb.Any 935 wantName string 936 wantUpdate ListenerUpdate 937 wantErr string 938 }{ 939 { 940 name: "non-empty listener filters", 941 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 942 Name: v3LDSTarget, 943 ListenerFilters: []*v3listenerpb.ListenerFilter{ 944 {Name: "listener-filter-1"}, 945 }, 946 }), 947 wantName: v3LDSTarget, 948 wantErr: "unsupported field 'listener_filters'", 949 }, 950 { 951 name: "use_original_dst is set", 952 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 953 Name: v3LDSTarget, 954 UseOriginalDst: &wrapperspb.BoolValue{Value: true}, 955 }), 956 wantName: v3LDSTarget, 957 wantErr: "unsupported field 'use_original_dst'", 958 }, 959 { 960 name: "no address field", 961 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{Name: v3LDSTarget}), 962 wantName: v3LDSTarget, 963 wantErr: "no address field in LDS response", 964 }, 965 { 966 name: "no socket address field", 967 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 968 Name: v3LDSTarget, 969 Address: &v3corepb.Address{}, 970 }), 971 wantName: v3LDSTarget, 972 wantErr: "no socket_address field in LDS response", 973 }, 974 { 975 name: "no filter chains and no default filter chain", 976 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 977 Name: v3LDSTarget, 978 Address: localSocketAddress, 979 FilterChains: []*v3listenerpb.FilterChain{ 980 { 981 FilterChainMatch: &v3listenerpb.FilterChainMatch{DestinationPort: &wrapperspb.UInt32Value{Value: 666}}, 982 Filters: emptyValidNetworkFilters, 983 }, 984 }, 985 }), 986 wantName: v3LDSTarget, 987 wantErr: "no supported filter chains and no default filter chain", 988 }, 989 { 990 name: "missing http connection manager network filter", 991 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 992 Name: v3LDSTarget, 993 Address: localSocketAddress, 994 FilterChains: []*v3listenerpb.FilterChain{ 995 { 996 Name: "filter-chain-1", 997 }, 998 }, 999 }), 1000 wantName: v3LDSTarget, 1001 wantErr: "missing HttpConnectionManager filter", 1002 }, 1003 { 1004 name: "missing filter name in http filter", 1005 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1006 Name: v3LDSTarget, 1007 Address: localSocketAddress, 1008 FilterChains: []*v3listenerpb.FilterChain{ 1009 { 1010 Name: "filter-chain-1", 1011 Filters: []*v3listenerpb.Filter{ 1012 { 1013 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1014 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{}), 1015 }, 1016 }, 1017 }, 1018 }, 1019 }, 1020 }), 1021 wantName: v3LDSTarget, 1022 wantErr: "missing name field in filter", 1023 }, 1024 { 1025 name: "duplicate filter names in http filter", 1026 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1027 Name: v3LDSTarget, 1028 Address: localSocketAddress, 1029 FilterChains: []*v3listenerpb.FilterChain{ 1030 { 1031 Name: "filter-chain-1", 1032 Filters: []*v3listenerpb.Filter{ 1033 { 1034 Name: "name", 1035 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1036 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 1037 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 1038 RouteConfig: routeConfig, 1039 }, 1040 HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter}, 1041 }), 1042 }, 1043 }, 1044 { 1045 Name: "name", 1046 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1047 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 1048 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 1049 RouteConfig: routeConfig, 1050 }, 1051 HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter}, 1052 }), 1053 }, 1054 }, 1055 }, 1056 }, 1057 }, 1058 }), 1059 wantName: v3LDSTarget, 1060 wantErr: "duplicate filter name", 1061 }, 1062 { 1063 name: "no terminal filter", 1064 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1065 Name: v3LDSTarget, 1066 Address: localSocketAddress, 1067 FilterChains: []*v3listenerpb.FilterChain{ 1068 { 1069 Name: "filter-chain-1", 1070 Filters: []*v3listenerpb.Filter{ 1071 { 1072 Name: "name", 1073 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1074 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 1075 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 1076 RouteConfig: routeConfig, 1077 }, 1078 }), 1079 }, 1080 }, 1081 }, 1082 }, 1083 }, 1084 }), 1085 wantName: v3LDSTarget, 1086 wantErr: "http filters list is empty", 1087 }, 1088 { 1089 name: "terminal filter not last", 1090 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1091 Name: v3LDSTarget, 1092 Address: localSocketAddress, 1093 FilterChains: []*v3listenerpb.FilterChain{ 1094 { 1095 Name: "filter-chain-1", 1096 Filters: []*v3listenerpb.Filter{ 1097 { 1098 Name: "name", 1099 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1100 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 1101 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 1102 RouteConfig: routeConfig, 1103 }, 1104 HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter, serverOnlyCustomFilter}, 1105 }), 1106 }, 1107 }, 1108 }, 1109 }, 1110 }, 1111 }), 1112 wantName: v3LDSTarget, 1113 wantErr: "is a terminal filter but it is not last in the filter chain", 1114 }, 1115 { 1116 name: "last not terminal filter", 1117 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1118 Name: v3LDSTarget, 1119 Address: localSocketAddress, 1120 FilterChains: []*v3listenerpb.FilterChain{ 1121 { 1122 Name: "filter-chain-1", 1123 Filters: []*v3listenerpb.Filter{ 1124 { 1125 Name: "name", 1126 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1127 TypedConfig: testutils.MarshalAny(t, &v3httppb.HttpConnectionManager{ 1128 RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{ 1129 RouteConfig: routeConfig, 1130 }, 1131 HttpFilters: []*v3httppb.HttpFilter{serverOnlyCustomFilter}, 1132 }), 1133 }, 1134 }, 1135 }, 1136 }, 1137 }, 1138 }), 1139 wantName: v3LDSTarget, 1140 wantErr: "is not a terminal filter", 1141 }, 1142 { 1143 name: "unsupported oneof in typed config of http filter", 1144 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1145 Name: v3LDSTarget, 1146 Address: localSocketAddress, 1147 FilterChains: []*v3listenerpb.FilterChain{ 1148 { 1149 Name: "filter-chain-1", 1150 Filters: []*v3listenerpb.Filter{ 1151 { 1152 Name: "name", 1153 ConfigType: &v3listenerpb.Filter_ConfigDiscovery{}, 1154 }, 1155 }, 1156 }, 1157 }, 1158 }), 1159 wantName: v3LDSTarget, 1160 wantErr: "unsupported config_type", 1161 }, 1162 { 1163 name: "overlapping filter chain match criteria", 1164 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1165 Name: v3LDSTarget, 1166 Address: localSocketAddress, 1167 FilterChains: []*v3listenerpb.FilterChain{ 1168 { 1169 FilterChainMatch: &v3listenerpb.FilterChainMatch{SourcePorts: []uint32{1, 2, 3, 4, 5}}, 1170 Filters: emptyValidNetworkFilters, 1171 }, 1172 { 1173 FilterChainMatch: &v3listenerpb.FilterChainMatch{}, 1174 Filters: emptyValidNetworkFilters, 1175 }, 1176 { 1177 FilterChainMatch: &v3listenerpb.FilterChainMatch{SourcePorts: []uint32{5, 6, 7}}, 1178 Filters: emptyValidNetworkFilters, 1179 }, 1180 }, 1181 }), 1182 wantName: v3LDSTarget, 1183 wantErr: "multiple filter chains with overlapping matching rules are defined", 1184 }, 1185 { 1186 name: "unsupported network filter", 1187 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1188 Name: v3LDSTarget, 1189 Address: localSocketAddress, 1190 FilterChains: []*v3listenerpb.FilterChain{ 1191 { 1192 Name: "filter-chain-1", 1193 Filters: []*v3listenerpb.Filter{ 1194 { 1195 Name: "name", 1196 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1197 TypedConfig: testutils.MarshalAny(t, &v3httppb.LocalReplyConfig{}), 1198 }, 1199 }, 1200 }, 1201 }, 1202 }, 1203 }), 1204 wantName: v3LDSTarget, 1205 wantErr: "unsupported network filter", 1206 }, 1207 { 1208 name: "badly marshaled network filter", 1209 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1210 Name: v3LDSTarget, 1211 Address: localSocketAddress, 1212 FilterChains: []*v3listenerpb.FilterChain{ 1213 { 1214 Name: "filter-chain-1", 1215 Filters: []*v3listenerpb.Filter{ 1216 { 1217 Name: "name", 1218 ConfigType: &v3listenerpb.Filter_TypedConfig{ 1219 TypedConfig: &anypb.Any{ 1220 TypeUrl: version.V3HTTPConnManagerURL, 1221 Value: []byte{1, 2, 3, 4}, 1222 }, 1223 }, 1224 }, 1225 }, 1226 }, 1227 }, 1228 }), 1229 wantName: v3LDSTarget, 1230 wantErr: "failed unmarshalling of network filter", 1231 }, 1232 { 1233 name: "unexpected transport socket name", 1234 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1235 Name: v3LDSTarget, 1236 Address: localSocketAddress, 1237 FilterChains: []*v3listenerpb.FilterChain{ 1238 { 1239 Name: "filter-chain-1", 1240 Filters: emptyValidNetworkFilters, 1241 TransportSocket: &v3corepb.TransportSocket{ 1242 Name: "unsupported-transport-socket-name", 1243 }, 1244 }, 1245 }, 1246 }), 1247 wantName: v3LDSTarget, 1248 wantErr: "transport_socket field has unexpected name", 1249 }, 1250 { 1251 name: "unexpected transport socket typedConfig URL", 1252 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1253 Name: v3LDSTarget, 1254 Address: localSocketAddress, 1255 FilterChains: []*v3listenerpb.FilterChain{ 1256 { 1257 Name: "filter-chain-1", 1258 Filters: emptyValidNetworkFilters, 1259 TransportSocket: &v3corepb.TransportSocket{ 1260 Name: "envoy.transport_sockets.tls", 1261 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1262 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{}), 1263 }, 1264 }, 1265 }, 1266 }, 1267 }), 1268 wantName: v3LDSTarget, 1269 wantErr: "transport_socket field has unexpected typeURL", 1270 }, 1271 { 1272 name: "badly marshaled transport socket", 1273 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1274 Name: v3LDSTarget, 1275 Address: localSocketAddress, 1276 FilterChains: []*v3listenerpb.FilterChain{ 1277 { 1278 Name: "filter-chain-1", 1279 Filters: emptyValidNetworkFilters, 1280 TransportSocket: &v3corepb.TransportSocket{ 1281 Name: "envoy.transport_sockets.tls", 1282 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1283 TypedConfig: &anypb.Any{ 1284 TypeUrl: version.V3DownstreamTLSContextURL, 1285 Value: []byte{1, 2, 3, 4}, 1286 }, 1287 }, 1288 }, 1289 }, 1290 }, 1291 }), 1292 wantName: v3LDSTarget, 1293 wantErr: "failed to unmarshal DownstreamTlsContext in LDS response", 1294 }, 1295 { 1296 name: "missing CommonTlsContext", 1297 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1298 Name: v3LDSTarget, 1299 Address: localSocketAddress, 1300 FilterChains: []*v3listenerpb.FilterChain{ 1301 { 1302 Name: "filter-chain-1", 1303 Filters: emptyValidNetworkFilters, 1304 TransportSocket: &v3corepb.TransportSocket{ 1305 Name: "envoy.transport_sockets.tls", 1306 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1307 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{}), 1308 }, 1309 }, 1310 }, 1311 }, 1312 }), 1313 wantName: v3LDSTarget, 1314 wantErr: "DownstreamTlsContext in LDS response does not contain a CommonTlsContext", 1315 }, 1316 { 1317 name: "rbac-allow-equating-direct-remote-ip-and-remote-ip-valid", 1318 resource: v3LisToTestRBAC(0, nil), 1319 wantName: v3LDSTarget, 1320 wantUpdate: ListenerUpdate{ 1321 InboundListenerCfg: &InboundListenerConfig{ 1322 Address: "0.0.0.0", 1323 Port: "9999", 1324 FilterChains: &FilterChainManager{ 1325 dstPrefixMap: map[string]*destPrefixEntry{ 1326 unspecifiedPrefixMapKey: { 1327 srcTypeArr: [3]*sourcePrefixes{ 1328 { 1329 srcPrefixMap: map[string]*sourcePrefixEntry{ 1330 unspecifiedPrefixMapKey: { 1331 srcPortMap: map[int]*FilterChain{ 1332 0: { 1333 InlineRouteConfig: inlineRouteConfig, 1334 HTTPFilters: makeRouterFilterList(t), 1335 }, 1336 }, 1337 }, 1338 }, 1339 }, 1340 }, 1341 }, 1342 }, 1343 }, 1344 }, 1345 Raw: listenerEmptyTransportSocket, 1346 }, 1347 }, 1348 { 1349 name: "rbac-allow-equating-direct-remote-ip-and-remote-ip-invalid-num-untrusted-hops", 1350 resource: v3LisToTestRBAC(1, nil), 1351 wantName: v3LDSTarget, 1352 wantErr: "xff_num_trusted_hops must be unset or zero", 1353 }, 1354 { 1355 name: "rbac-allow-equating-direct-remote-ip-and-remote-ip-invalid-original-ip-detection-extension", 1356 resource: v3LisToTestRBAC(0, []*v3corepb.TypedExtensionConfig{{Name: "something"}}), 1357 wantName: v3LDSTarget, 1358 wantErr: "original_ip_detection_extensions must be empty", 1359 }, 1360 { 1361 name: "rbac-with-invalid-regex", 1362 resource: v3LisWithBadRBACConfiguration(badRBACCfgRegex), 1363 wantName: v3LDSTarget, 1364 wantErr: "error parsing config for filter", 1365 }, 1366 { 1367 name: "rbac-with-invalid-destination-ip-matcher", 1368 resource: v3LisWithBadRBACConfiguration(badRBACCfgDestIP), 1369 wantName: v3LDSTarget, 1370 wantErr: "error parsing config for filter", 1371 }, 1372 { 1373 name: "unsupported validation context in transport socket", 1374 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1375 Name: v3LDSTarget, 1376 Address: localSocketAddress, 1377 FilterChains: []*v3listenerpb.FilterChain{ 1378 { 1379 Name: "filter-chain-1", 1380 Filters: emptyValidNetworkFilters, 1381 TransportSocket: &v3corepb.TransportSocket{ 1382 Name: "envoy.transport_sockets.tls", 1383 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1384 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 1385 CommonTlsContext: &v3tlspb.CommonTlsContext{ 1386 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextSdsSecretConfig{ 1387 ValidationContextSdsSecretConfig: &v3tlspb.SdsSecretConfig{ 1388 Name: "foo-sds-secret", 1389 }, 1390 }, 1391 }, 1392 }), 1393 }, 1394 }, 1395 }, 1396 }, 1397 }), 1398 wantName: v3LDSTarget, 1399 wantErr: "validation context contains unexpected type", 1400 }, 1401 { 1402 name: "empty transport socket", 1403 resource: listenerEmptyTransportSocket, 1404 wantName: v3LDSTarget, 1405 wantUpdate: ListenerUpdate{ 1406 InboundListenerCfg: &InboundListenerConfig{ 1407 Address: "0.0.0.0", 1408 Port: "9999", 1409 FilterChains: &FilterChainManager{ 1410 dstPrefixMap: map[string]*destPrefixEntry{ 1411 unspecifiedPrefixMapKey: { 1412 srcTypeArr: [3]*sourcePrefixes{ 1413 { 1414 srcPrefixMap: map[string]*sourcePrefixEntry{ 1415 unspecifiedPrefixMapKey: { 1416 srcPortMap: map[int]*FilterChain{ 1417 0: { 1418 InlineRouteConfig: inlineRouteConfig, 1419 HTTPFilters: makeRouterFilterList(t), 1420 }, 1421 }, 1422 }, 1423 }, 1424 }, 1425 }, 1426 }, 1427 }, 1428 }, 1429 }, 1430 Raw: listenerEmptyTransportSocket, 1431 }, 1432 }, 1433 { 1434 name: "no identity and root certificate providers using deprecated fields", 1435 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1436 Name: v3LDSTarget, 1437 Address: localSocketAddress, 1438 FilterChains: []*v3listenerpb.FilterChain{ 1439 { 1440 Name: "filter-chain-1", 1441 Filters: emptyValidNetworkFilters, 1442 TransportSocket: &v3corepb.TransportSocket{ 1443 Name: "envoy.transport_sockets.tls", 1444 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1445 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 1446 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 1447 CommonTlsContext: &v3tlspb.CommonTlsContext{ 1448 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{ 1449 InstanceName: "identityPluginInstance", 1450 CertificateName: "identityCertName", 1451 }, 1452 }, 1453 }), 1454 }, 1455 }, 1456 }, 1457 }, 1458 }), 1459 wantName: v3LDSTarget, 1460 wantErr: "security configuration on the server-side does not contain root certificate provider instance name, but require_client_cert field is set", 1461 }, 1462 { 1463 name: "no identity and root certificate providers using new fields", 1464 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1465 Name: v3LDSTarget, 1466 Address: localSocketAddress, 1467 FilterChains: []*v3listenerpb.FilterChain{ 1468 { 1469 Name: "filter-chain-1", 1470 Filters: emptyValidNetworkFilters, 1471 TransportSocket: &v3corepb.TransportSocket{ 1472 Name: "envoy.transport_sockets.tls", 1473 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1474 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 1475 RequireClientCertificate: &wrapperspb.BoolValue{Value: true}, 1476 CommonTlsContext: &v3tlspb.CommonTlsContext{ 1477 TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{ 1478 InstanceName: "identityPluginInstance", 1479 CertificateName: "identityCertName", 1480 }, 1481 }, 1482 }), 1483 }, 1484 }, 1485 }, 1486 }, 1487 }), 1488 wantName: v3LDSTarget, 1489 wantErr: "security configuration on the server-side does not contain root certificate provider instance name, but require_client_cert field is set", 1490 }, 1491 { 1492 name: "no identity certificate provider with require_client_cert", 1493 resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ 1494 Name: v3LDSTarget, 1495 Address: localSocketAddress, 1496 FilterChains: []*v3listenerpb.FilterChain{ 1497 { 1498 Name: "filter-chain-1", 1499 Filters: emptyValidNetworkFilters, 1500 TransportSocket: &v3corepb.TransportSocket{ 1501 Name: "envoy.transport_sockets.tls", 1502 ConfigType: &v3corepb.TransportSocket_TypedConfig{ 1503 TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{ 1504 CommonTlsContext: &v3tlspb.CommonTlsContext{}, 1505 }), 1506 }, 1507 }, 1508 }, 1509 }, 1510 }), 1511 wantName: v3LDSTarget, 1512 wantErr: "security configuration on the server-side does not contain identity certificate provider instance name", 1513 }, 1514 { 1515 name: "happy case with no validation context using deprecated fields", 1516 resource: listenerNoValidationContextDeprecatedFields, 1517 wantName: v3LDSTarget, 1518 wantUpdate: ListenerUpdate{ 1519 InboundListenerCfg: &InboundListenerConfig{ 1520 Address: "0.0.0.0", 1521 Port: "9999", 1522 FilterChains: &FilterChainManager{ 1523 dstPrefixMap: map[string]*destPrefixEntry{ 1524 unspecifiedPrefixMapKey: { 1525 srcTypeArr: [3]*sourcePrefixes{ 1526 { 1527 srcPrefixMap: map[string]*sourcePrefixEntry{ 1528 unspecifiedPrefixMapKey: { 1529 srcPortMap: map[int]*FilterChain{ 1530 0: { 1531 SecurityCfg: &SecurityConfig{ 1532 IdentityInstanceName: "identityPluginInstance", 1533 IdentityCertName: "identityCertName", 1534 }, 1535 InlineRouteConfig: inlineRouteConfig, 1536 HTTPFilters: makeRouterFilterList(t), 1537 }, 1538 }, 1539 }, 1540 }, 1541 }, 1542 }, 1543 }, 1544 }, 1545 def: &FilterChain{ 1546 SecurityCfg: &SecurityConfig{ 1547 IdentityInstanceName: "defaultIdentityPluginInstance", 1548 IdentityCertName: "defaultIdentityCertName", 1549 }, 1550 InlineRouteConfig: inlineRouteConfig, 1551 HTTPFilters: makeRouterFilterList(t), 1552 }, 1553 }, 1554 }, 1555 Raw: listenerNoValidationContextDeprecatedFields, 1556 }, 1557 }, 1558 { 1559 name: "happy case with no validation context using new fields", 1560 resource: listenerNoValidationContextNewFields, 1561 wantName: v3LDSTarget, 1562 wantUpdate: ListenerUpdate{ 1563 InboundListenerCfg: &InboundListenerConfig{ 1564 Address: "0.0.0.0", 1565 Port: "9999", 1566 FilterChains: &FilterChainManager{ 1567 dstPrefixMap: map[string]*destPrefixEntry{ 1568 unspecifiedPrefixMapKey: { 1569 srcTypeArr: [3]*sourcePrefixes{ 1570 { 1571 srcPrefixMap: map[string]*sourcePrefixEntry{ 1572 unspecifiedPrefixMapKey: { 1573 srcPortMap: map[int]*FilterChain{ 1574 0: { 1575 SecurityCfg: &SecurityConfig{ 1576 IdentityInstanceName: "identityPluginInstance", 1577 IdentityCertName: "identityCertName", 1578 }, 1579 InlineRouteConfig: inlineRouteConfig, 1580 HTTPFilters: makeRouterFilterList(t), 1581 }, 1582 }, 1583 }, 1584 }, 1585 }, 1586 }, 1587 }, 1588 }, 1589 def: &FilterChain{ 1590 SecurityCfg: &SecurityConfig{ 1591 IdentityInstanceName: "defaultIdentityPluginInstance", 1592 IdentityCertName: "defaultIdentityCertName", 1593 }, 1594 InlineRouteConfig: inlineRouteConfig, 1595 HTTPFilters: makeRouterFilterList(t), 1596 }, 1597 }, 1598 }, 1599 Raw: listenerNoValidationContextNewFields, 1600 }, 1601 }, 1602 { 1603 name: "happy case with validation context provider instance with deprecated fields", 1604 resource: listenerWithValidationContextDeprecatedFields, 1605 wantName: v3LDSTarget, 1606 wantUpdate: ListenerUpdate{ 1607 InboundListenerCfg: &InboundListenerConfig{ 1608 Address: "0.0.0.0", 1609 Port: "9999", 1610 FilterChains: &FilterChainManager{ 1611 dstPrefixMap: map[string]*destPrefixEntry{ 1612 unspecifiedPrefixMapKey: { 1613 srcTypeArr: [3]*sourcePrefixes{ 1614 { 1615 srcPrefixMap: map[string]*sourcePrefixEntry{ 1616 unspecifiedPrefixMapKey: { 1617 srcPortMap: map[int]*FilterChain{ 1618 0: { 1619 SecurityCfg: &SecurityConfig{ 1620 RootInstanceName: "rootPluginInstance", 1621 RootCertName: "rootCertName", 1622 IdentityInstanceName: "identityPluginInstance", 1623 IdentityCertName: "identityCertName", 1624 RequireClientCert: true, 1625 }, 1626 InlineRouteConfig: inlineRouteConfig, 1627 HTTPFilters: makeRouterFilterList(t), 1628 }, 1629 }, 1630 }, 1631 }, 1632 }, 1633 }, 1634 }, 1635 }, 1636 def: &FilterChain{ 1637 SecurityCfg: &SecurityConfig{ 1638 RootInstanceName: "defaultRootPluginInstance", 1639 RootCertName: "defaultRootCertName", 1640 IdentityInstanceName: "defaultIdentityPluginInstance", 1641 IdentityCertName: "defaultIdentityCertName", 1642 RequireClientCert: true, 1643 }, 1644 InlineRouteConfig: inlineRouteConfig, 1645 HTTPFilters: makeRouterFilterList(t), 1646 }, 1647 }, 1648 }, 1649 Raw: listenerWithValidationContextDeprecatedFields, 1650 }, 1651 }, 1652 { 1653 name: "happy case with validation context provider instance with new fields", 1654 resource: listenerWithValidationContextNewFields, 1655 wantName: v3LDSTarget, 1656 wantUpdate: ListenerUpdate{ 1657 InboundListenerCfg: &InboundListenerConfig{ 1658 Address: "0.0.0.0", 1659 Port: "9999", 1660 FilterChains: &FilterChainManager{ 1661 dstPrefixMap: map[string]*destPrefixEntry{ 1662 unspecifiedPrefixMapKey: { 1663 srcTypeArr: [3]*sourcePrefixes{ 1664 { 1665 srcPrefixMap: map[string]*sourcePrefixEntry{ 1666 unspecifiedPrefixMapKey: { 1667 srcPortMap: map[int]*FilterChain{ 1668 0: { 1669 SecurityCfg: &SecurityConfig{ 1670 RootInstanceName: "rootPluginInstance", 1671 RootCertName: "rootCertName", 1672 IdentityInstanceName: "identityPluginInstance", 1673 IdentityCertName: "identityCertName", 1674 RequireClientCert: true, 1675 }, 1676 InlineRouteConfig: inlineRouteConfig, 1677 HTTPFilters: makeRouterFilterList(t), 1678 }, 1679 }, 1680 }, 1681 }, 1682 }, 1683 }, 1684 }, 1685 }, 1686 def: &FilterChain{ 1687 SecurityCfg: &SecurityConfig{ 1688 RootInstanceName: "defaultRootPluginInstance", 1689 RootCertName: "defaultRootCertName", 1690 IdentityInstanceName: "defaultIdentityPluginInstance", 1691 IdentityCertName: "defaultIdentityCertName", 1692 RequireClientCert: true, 1693 }, 1694 InlineRouteConfig: inlineRouteConfig, 1695 HTTPFilters: makeRouterFilterList(t), 1696 }, 1697 }, 1698 }, 1699 Raw: listenerWithValidationContextNewFields, 1700 }, 1701 }, 1702 } 1703 1704 for _, test := range tests { 1705 t.Run(test.name, func(t *testing.T) { 1706 name, update, err := unmarshalListenerResource(test.resource) 1707 if err != nil && !strings.Contains(err.Error(), test.wantErr) { 1708 t.Errorf("unmarshalListenerResource(%s) = %v wantErr: %q", pretty.ToJSON(test.resource), err, test.wantErr) 1709 } 1710 if name != test.wantName { 1711 t.Errorf("unmarshalListenerResource(%s), got name: %s, want: %s", pretty.ToJSON(test.resource), name, test.wantName) 1712 } 1713 if diff := cmp.Diff(update, test.wantUpdate, cmpOpts); diff != "" { 1714 t.Errorf("unmarshalListenerResource(%s), got unexpected update, diff (-got +want): %v", pretty.ToJSON(test.resource), diff) 1715 } 1716 }) 1717 } 1718 } 1719 1720 type filterConfig struct { 1721 httpfilter.FilterConfig 1722 Cfg proto.Message 1723 Override proto.Message 1724 } 1725 1726 // httpFilter allows testing the http filter registry and parsing functionality. 1727 type httpFilter struct { 1728 httpfilter.ClientInterceptorBuilder 1729 httpfilter.ServerInterceptorBuilder 1730 } 1731 1732 func (httpFilter) TypeURLs() []string { return []string{"custom.filter"} } 1733 1734 func (httpFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1735 return filterConfig{Cfg: cfg}, nil 1736 } 1737 1738 func (httpFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1739 return filterConfig{Override: override}, nil 1740 } 1741 1742 func (httpFilter) IsTerminal() bool { 1743 return false 1744 } 1745 1746 // errHTTPFilter returns errors no matter what is passed to ParseFilterConfig. 1747 type errHTTPFilter struct { 1748 httpfilter.ClientInterceptorBuilder 1749 } 1750 1751 func (errHTTPFilter) TypeURLs() []string { return []string{"err.custom.filter"} } 1752 1753 func (errHTTPFilter) ParseFilterConfig(proto.Message) (httpfilter.FilterConfig, error) { 1754 return nil, fmt.Errorf("error from ParseFilterConfig") 1755 } 1756 1757 func (errHTTPFilter) ParseFilterConfigOverride(proto.Message) (httpfilter.FilterConfig, error) { 1758 return nil, fmt.Errorf("error from ParseFilterConfigOverride") 1759 } 1760 1761 func (errHTTPFilter) IsTerminal() bool { 1762 return false 1763 } 1764 1765 func init() { 1766 httpfilter.Register(httpFilter{}) 1767 httpfilter.Register(errHTTPFilter{}) 1768 httpfilter.Register(serverOnlyHTTPFilter{}) 1769 httpfilter.Register(clientOnlyHTTPFilter{}) 1770 } 1771 1772 // serverOnlyHTTPFilter does not implement ClientInterceptorBuilder 1773 type serverOnlyHTTPFilter struct { 1774 httpfilter.ServerInterceptorBuilder 1775 } 1776 1777 func (serverOnlyHTTPFilter) TypeURLs() []string { return []string{"serverOnly.custom.filter"} } 1778 1779 func (serverOnlyHTTPFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1780 return filterConfig{Cfg: cfg}, nil 1781 } 1782 1783 func (serverOnlyHTTPFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1784 return filterConfig{Override: override}, nil 1785 } 1786 1787 func (serverOnlyHTTPFilter) IsTerminal() bool { 1788 return false 1789 } 1790 1791 // clientOnlyHTTPFilter does not implement ServerInterceptorBuilder 1792 type clientOnlyHTTPFilter struct { 1793 httpfilter.ClientInterceptorBuilder 1794 } 1795 1796 func (clientOnlyHTTPFilter) TypeURLs() []string { return []string{"clientOnly.custom.filter"} } 1797 1798 func (clientOnlyHTTPFilter) ParseFilterConfig(cfg proto.Message) (httpfilter.FilterConfig, error) { 1799 return filterConfig{Cfg: cfg}, nil 1800 } 1801 1802 func (clientOnlyHTTPFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.FilterConfig, error) { 1803 return filterConfig{Override: override}, nil 1804 } 1805 1806 func (clientOnlyHTTPFilter) IsTerminal() bool { 1807 return false 1808 } 1809 1810 var customFilterConfig = &anypb.Any{ 1811 TypeUrl: "custom.filter", 1812 Value: []byte{1, 2, 3}, 1813 } 1814 1815 var errFilterConfig = &anypb.Any{ 1816 TypeUrl: "err.custom.filter", 1817 Value: []byte{1, 2, 3}, 1818 } 1819 1820 var serverOnlyCustomFilterConfig = &anypb.Any{ 1821 TypeUrl: "serverOnly.custom.filter", 1822 Value: []byte{1, 2, 3}, 1823 } 1824 1825 var clientOnlyCustomFilterConfig = &anypb.Any{ 1826 TypeUrl: "clientOnly.custom.filter", 1827 Value: []byte{1, 2, 3}, 1828 } 1829 1830 // This custom filter uses the old TypedStruct message from the cncf/udpa repo. 1831 var customFilterOldTypedStructConfig = &v1xdsudpatypepb.TypedStruct{ 1832 TypeUrl: "custom.filter", 1833 Value: &structpb.Struct{ 1834 Fields: map[string]*structpb.Value{ 1835 "foo": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, 1836 }, 1837 }, 1838 } 1839 1840 // This custom filter uses the new TypedStruct message from the cncf/xds repo. 1841 var customFilterNewTypedStructConfig = &v3xdsxdstypepb.TypedStruct{ 1842 TypeUrl: "custom.filter", 1843 Value: &structpb.Struct{ 1844 Fields: map[string]*structpb.Value{ 1845 "foo": {Kind: &structpb.Value_StringValue{StringValue: "bar"}}, 1846 }, 1847 }, 1848 } 1849 1850 var unknownFilterConfig = &anypb.Any{ 1851 TypeUrl: "unknown.custom.filter", 1852 Value: []byte{1, 2, 3}, 1853 } 1854 1855 func wrappedOptionalFilter(t *testing.T, name string) *anypb.Any { 1856 return testutils.MarshalAny(t, &v3routepb.FilterConfig{ 1857 IsOptional: true, 1858 Config: &anypb.Any{ 1859 TypeUrl: name, 1860 Value: []byte{1, 2, 3}, 1861 }, 1862 }) 1863 }