Skip to content

Commit

Permalink
Updating EndpointSlice validation to match Endpoints validation
Browse files Browse the repository at this point in the history
  • Loading branch information
robscott committed Apr 22, 2021
1 parent 02b9dd6 commit 006614e
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 9 deletions.
18 changes: 11 additions & 7 deletions pkg/apis/core/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -4220,7 +4220,7 @@ func ValidateService(service *core.Service, allowAppProtocol bool) field.ErrorLi
allErrs = append(allErrs, field.Invalid(idxPath, ip, msgs[i]))
}
} else {
allErrs = append(allErrs, validateNonSpecialIP(ip, idxPath)...)
allErrs = append(allErrs, ValidateNonSpecialIP(ip, idxPath)...)
}
}

Expand Down Expand Up @@ -5717,15 +5717,19 @@ func validateEndpointAddress(address *core.EndpointAddress, fldPath *field.Path)
allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), *address.NodeName, msg))
}
}
allErrs = append(allErrs, validateNonSpecialIP(address.IP, fldPath.Child("ip"))...)
allErrs = append(allErrs, ValidateNonSpecialIP(address.IP, fldPath.Child("ip"))...)
return allErrs
}

func validateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList {
// We disallow some IPs as endpoints or external-ips. Specifically,
// unspecified and loopback addresses are nonsensical and link-local
// addresses tend to be used for node-centric purposes (e.g. metadata
// service).
// ValidateNonSpecialIP is used to validate Endpoints, EndpointSlices, and
// external IPs. Specifically, this disallows unspecified and loopback addresses
// are nonsensical and link-local addresses tend to be used for node-centric
// purposes (e.g. metadata service).
//
// IPv6 references
// - https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
// - https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml
func ValidateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
ip := net.ParseIP(ipAddress)
if ip == nil {
Expand Down
40 changes: 40 additions & 0 deletions pkg/apis/core/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16028,3 +16028,43 @@ func TestValidatePodTemplateSpecSeccomp(t *testing.T) {
asserttestify.Equal(t, test.expectedErr, err, "TestCase[%d]: %s", i, test.description)
}
}

func TestValidateNonSpecialIP(t *testing.T) {
fp := field.NewPath("ip")

// Valid values.
for _, tc := range []struct {
desc string
ip string
}{
{"ipv4", "10.1.2.3"},
{"ipv6", "2000::1"},
} {
t.Run(tc.desc, func(t *testing.T) {
errs := ValidateNonSpecialIP(tc.ip, fp)
if len(errs) != 0 {
t.Errorf("ValidateNonSpecialIP(%q, ...) = %v; want nil", tc.ip, errs)
}
})
}
// Invalid cases
for _, tc := range []struct {
desc string
ip string
}{
{"ipv4 unspecified", "0.0.0.0"},
{"ipv6 unspecified", "::0"},
{"ipv4 localhost", "127.0.0.0"},
{"ipv4 localhost", "127.255.255.255"},
{"ipv6 localhost", "::1"},
{"ipv6 link local", "fe80::"},
{"ipv6 local multicast", "ff02::"},
} {
t.Run(tc.desc, func(t *testing.T) {
errs := ValidateNonSpecialIP(tc.ip, fp)
if len(errs) == 0 {
t.Errorf("ValidateNonSpecialIP(%q, ...) = nil; want non-nil (errors)", tc.ip)
}
})
}
}
2 changes: 2 additions & 0 deletions pkg/apis/discovery/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,10 @@ func validateEndpoints(endpoints []discovery.Endpoint, addrType discovery.Addres
}
case discovery.AddressTypeIPv4:
allErrs = append(allErrs, validation.IsValidIPv4Address(addressPath.Index(i), address)...)
allErrs = append(allErrs, apivalidation.ValidateNonSpecialIP(address, addressPath.Index(i))...)
case discovery.AddressTypeIPv6:
allErrs = append(allErrs, validation.IsValidIPv6Address(addressPath.Index(i), address)...)
allErrs = append(allErrs, apivalidation.ValidateNonSpecialIP(address, addressPath.Index(i))...)
case discovery.AddressTypeFQDN:
allErrs = append(allErrs, validation.IsFullyQualifiedDomainName(addressPath.Index(i), address)...)
}
Expand Down
49 changes: 47 additions & 2 deletions pkg/apis/discovery/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,21 @@ func TestValidateEndpointSlice(t *testing.T) {
}},
},
},
"good-ipv6": {
expectedErrors: 0,
endpointSlice: &discovery.EndpointSlice{
ObjectMeta: standardMeta,
AddressType: discovery.AddressTypeIPv6,
Ports: []discovery.EndpointPort{{
Name: utilpointer.StringPtr("http"),
Protocol: protocolPtr(api.ProtocolTCP),
}},
Endpoints: []discovery.Endpoint{{
Addresses: []string{"a00:100::4"},
Hostname: utilpointer.StringPtr("valid-123"),
}},
},
},
"good-fqdns": {
expectedErrors: 0,
endpointSlice: &discovery.EndpointSlice{
Expand Down Expand Up @@ -390,7 +405,7 @@ func TestValidateEndpointSlice(t *testing.T) {
},
},
"bad-ipv4": {
expectedErrors: 2,
expectedErrors: 3,
endpointSlice: &discovery.EndpointSlice{
ObjectMeta: standardMeta,
AddressType: discovery.AddressTypeIPv4,
Expand All @@ -405,7 +420,7 @@ func TestValidateEndpointSlice(t *testing.T) {
},
},
"bad-ipv6": {
expectedErrors: 2,
expectedErrors: 4,
endpointSlice: &discovery.EndpointSlice{
ObjectMeta: standardMeta,
AddressType: discovery.AddressTypeIPv6,
Expand Down Expand Up @@ -454,6 +469,36 @@ func TestValidateEndpointSlice(t *testing.T) {
expectedErrors: 3,
endpointSlice: &discovery.EndpointSlice{},
},
"special-ipv4": {
expectedErrors: 1,
endpointSlice: &discovery.EndpointSlice{
ObjectMeta: standardMeta,
AddressType: discovery.AddressTypeIPv4,
Ports: []discovery.EndpointPort{{
Name: utilpointer.StringPtr("http"),
Protocol: protocolPtr(api.ProtocolTCP),
}},
Endpoints: []discovery.Endpoint{{
Addresses: []string{"127.0.0.1"},
Hostname: utilpointer.StringPtr("valid-123"),
}},
},
},
"special-ipv6": {
expectedErrors: 1,
endpointSlice: &discovery.EndpointSlice{
ObjectMeta: standardMeta,
AddressType: discovery.AddressTypeIPv6,
Ports: []discovery.EndpointPort{{
Name: utilpointer.StringPtr("http"),
Protocol: protocolPtr(api.ProtocolTCP),
}},
Endpoints: []discovery.Endpoint{{
Addresses: []string{"fe80::9656:d028:8652:66b6"},
Hostname: utilpointer.StringPtr("valid-123"),
}},
},
},
}

for name, testCase := range testCases {
Expand Down

0 comments on commit 006614e

Please sign in to comment.