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