Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 IPAM Webhook allows empty gateway for IPv6 Address #8525

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions exp/ipam/internal/webhooks/ipaddress.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,35 @@ func (webhook *IPAddress) validate(ctx context.Context, ip *ipamv1.IPAddress) er
"prefix is too large for an IPv6 address",
))
}

_, err = netip.ParseAddr(ip.Spec.Gateway)
if err != nil {
if addr.Is4() && ip.Spec.Gateway == "" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just reading through this, are we not specifying a mode of operation? Wouldn't it be possible in this way to mix ipv4 and ipv6 settings under the same specs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't anything explicit that specifies the mode of operation on the IPAddress, but as part of this PR we did add validation to ensure address and gateway fields are not mixed, which I think would be sufficient to prevent mixing ipv4 and ipv6 on the same IPAddress.

allErrs = append(allErrs,
field.Invalid(
specPath.Child("gateway"),
ip.Spec.Gateway,
"not a valid IP address",
"gateway is required for an IPv4 address",
))
}

if ip.Spec.Gateway != "" {
gateway, err := netip.ParseAddr(ip.Spec.Gateway)
if err != nil {
allErrs = append(allErrs,
field.Invalid(
specPath.Child("gateway"),
ip.Spec.Gateway,
"not a valid IP address",
))
}

if addr.Is4() && gateway.Is6() ||
addr.Is6() && gateway.Is4() {
allErrs = append(allErrs,
field.Invalid(
specPath.Child("gateway"),
ip.Spec.Gateway,
"gateway and address IP family must match",
))
}
}
if ip.Spec.PoolRef.APIGroup == nil {
allErrs = append(allErrs,
field.Invalid(
Expand Down
32 changes: 32 additions & 0 deletions exp/ipam/internal/webhooks/ipaddress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,38 @@ func TestIPAddressValidateCreate(t *testing.T) {
extraObjs: []client.Object{claim},
expectErr: false,
},
{
name: "a valid IPv6 Address with no gateway should be accepted",
ip: getAddress(true, func(addr *ipamv1.IPAddress) {
addr.Spec.Gateway = ""
}),
extraObjs: []client.Object{claim},
expectErr: false,
},
{
name: "an IPv4 Address with no gateway should be rejected",
ip: getAddress(false, func(addr *ipamv1.IPAddress) {
addr.Spec.Gateway = ""
}),
extraObjs: []client.Object{claim},
expectErr: true,
},
{
name: "a valid IPv4 Address with valid IPv6 gateway should be rejected",
ip: getAddress(false, func(addr *ipamv1.IPAddress) {
addr.Spec.Gateway = "42::ffff"
}),
extraObjs: []client.Object{claim},
expectErr: true,
},
{
name: "a valid IPv6 Address with valid IPv4 gateway should be rejected",
ip: getAddress(true, func(addr *ipamv1.IPAddress) {
addr.Spec.Gateway = "10.0.0.254"
}),
extraObjs: []client.Object{claim},
expectErr: true,
},
{
name: "a prefix that is negative should be rejected",
ip: getAddress(false, func(addr *ipamv1.IPAddress) {
Expand Down