Skip to content

Commit 6608cb3

Browse files
authored
allow specifying ipv6 range prefixes as well (#819)
1 parent 3b11124 commit 6608cb3

File tree

2 files changed

+27
-12
lines changed

2 files changed

+27
-12
lines changed

internal/webhook/v1alpha2/linodevpc_webhook.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23+
"net"
2324
"net/netip"
2425
"regexp"
2526
"slices"
@@ -304,7 +305,7 @@ func validateSubnetIPv4CIDR(cidr string, path *field.Path) (*netipx.IPSet, *fiel
304305

305306
func validateIPv6Range(ipv6Range *string, path *field.Path) *field.Error {
306307
const (
307-
errIPv6RangeFormat = "IPv6 range must be either 'auto' or start with /. Example: /52"
308+
errIPv6RangeFormat = "IPv6 range must be either 'auto', valid IPv6 prefix or start with /. Example: auto, /52, 2001:db8::/52"
308309
errIPv6RangeNoNumber = "IPv6 range doesn't contain a valid number after /"
309310
errIPv6RangeBounds = "IPv6 range must be between /0 and /128"
310311
)
@@ -319,17 +320,29 @@ func validateIPv6Range(ipv6Range *string, path *field.Path) *field.Error {
319320
return nil
320321
}
321322

322-
if ipv6RangeStr == "" || !strings.HasPrefix(ipv6RangeStr, "/") {
323-
return field.Invalid(path, ipv6RangeStr, errIPv6RangeFormat)
323+
// check for valid IPv6 prefix (e.g., 2001:db8::/52)
324+
if _, ipNet, err := net.ParseCIDR(ipv6RangeStr); err == nil {
325+
if ipNet.IP.To16() != nil && ipNet.IP.To4() == nil {
326+
ones, _ := ipNet.Mask.Size()
327+
if ones < 0 || ones > 128 {
328+
return field.Invalid(path, ipv6RangeStr, errIPv6RangeBounds)
329+
}
330+
return nil
331+
}
324332
}
325333

326-
numStr := strings.TrimPrefix(ipv6RangeStr, "/")
327-
num, err := strconv.Atoi(numStr)
328-
if err != nil {
329-
return field.Invalid(path, ipv6RangeStr, errIPv6RangeNoNumber)
330-
}
331-
if num < 0 || num > 128 {
332-
return field.Invalid(path, ipv6RangeStr, errIPv6RangeBounds)
334+
// Slash-prefixed format (e.g., /52)
335+
if numStr, ok := strings.CutPrefix(ipv6RangeStr, "/"); ok {
336+
num, err := strconv.Atoi(numStr)
337+
if err != nil {
338+
return field.Invalid(path, ipv6RangeStr, errIPv6RangeNoNumber)
339+
}
340+
if num < 0 || num > 128 {
341+
return field.Invalid(path, ipv6RangeStr, errIPv6RangeBounds)
342+
}
343+
return nil
333344
}
334-
return nil
345+
346+
// Invalid
347+
return field.Invalid(path, ipv6RangeStr, errIPv6RangeFormat)
335348
}

internal/webhook/v1alpha2/linodevpc_webhook_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ func TestValidateVPCIPv6Ranges(t *testing.T) {
304304
}
305305
region = linodego.Region{ID: "test"}
306306
capabilities = []string{LinodeVPCCapability}
307-
ErrorIPv6RangeInvalid = "spec.IPv6Range[0].Range: Invalid value: \"48\": IPv6 range must be either 'auto' or start with /. Example: /52"
307+
ErrorIPv6RangeInvalid = "spec.IPv6Range[0].Range: Invalid value: \"48\": IPv6 range must be either 'auto', valid IPv6 prefix or start with /. Example: auto, /52, 2001:db8::/52"
308308
ErrorIPv6RangeInvalidChars = "spec.IPv6Range[0].Range: Invalid value: \"/a48\": IPv6 range doesn't contain a valid number after /"
309309
ErrorIPv6RangeOutOfRange = "spec.IPv6Range[0].Range: Invalid value: \"/130\": IPv6 range must be between /0 and /128"
310310
validator = &linodeVPCValidator{}
@@ -324,6 +324,7 @@ func TestValidateVPCIPv6Ranges(t *testing.T) {
324324
{Range: ptr.To("/48")},
325325
{Range: ptr.To("/52")},
326326
{Range: ptr.To("auto")},
327+
{Range: ptr.To("2001:db8::/52")},
327328
}
328329
errs := validator.validateLinodeVPCSpec(ctx, mck.LinodeClient, vpc.Spec, SkipAPIValidation)
329330
require.Empty(t, errs)
@@ -341,6 +342,7 @@ func TestValidateVPCIPv6Ranges(t *testing.T) {
341342
{Label: "foo", IPv4: "10.0.0.0/24", IPv6Range: []infrav1alpha2.VPCSubnetCreateOptionsIPv6{{Range: ptr.To("/52")}}},
342343
{Label: "bar", IPv4: "10.0.1.0/24", IPv6Range: []infrav1alpha2.VPCSubnetCreateOptionsIPv6{{Range: ptr.To("/64")}}},
343344
{Label: "buzz", IPv4: "10.0.2.0/24", IPv6Range: []infrav1alpha2.VPCSubnetCreateOptionsIPv6{{Range: ptr.To("auto")}}},
345+
{Label: "bazz", IPv4: "10.0.3.0/24", IPv6Range: []infrav1alpha2.VPCSubnetCreateOptionsIPv6{{Range: ptr.To("2001:db8::/56")}}},
344346
}
345347
errs := validator.validateLinodeVPCSpec(ctx, mck.LinodeClient, vpc.Spec, SkipAPIValidation)
346348
require.Empty(t, errs)

0 commit comments

Comments
 (0)