this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

pkg/net: add ParseCIDR to extract CIDR information

For example, net.ParseCIDR("10.20.30.40/24") returns:

{
prefix_mask: "255.255.255.0"
prefix_len: 24
prefix_addr: "10.20.30.0"
broadcast_addr: "10.20.30.255"
}

The names are chosen to loosely follow the API in Go's net/netip
as well as the basic terminology used on Wikipedia.

We might add more fields to this struct in the future,
as long as it's information that is useful and cheap to compute.

Fixes #4236.

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
Change-Id: I072c85e62976f7ce1041b00d406938b04638f779
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1229761
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
Reviewed-by: Matthew Sackman <matthew@cue.works>

+154
+2
pkg/gen.go
··· 474 474 // use CUE function signatures to validate their parameters and results. 475 475 case "*cuelang.org/go/pkg/time.Parts": 476 476 return "adt.StructKind" 477 + case "*cuelang.org/go/pkg/net.ParsedCIDR": 478 + return "adt.StructKind" 477 479 } 478 480 log.Fatal("adtKind: unhandled Go type ", typ.String()) 479 481 return ""
+50
pkg/net/ip.go
··· 305 305 return netip.PrefixFrom(addr, prefix.Bits()).String(), nil 306 306 } 307 307 308 + // ParsedCIDR holds the parsed components of a CIDR notation string. 309 + type ParsedCIDR struct { 310 + PrefixMask string `json:"prefix_mask"` 311 + PrefixLen int `json:"prefix_len"` 312 + PrefixAddr string `json:"prefix_addr"` 313 + // BroadcastAddr is only set for IPv4 CIDRs. 314 + BroadcastAddr string `json:"broadcast_addr,omitempty"` 315 + } 316 + 317 + // ParseCIDR parses a CIDR notation string and returns its components: 318 + // prefix_mask (e.g. "255.255.255.0"), prefix_len (e.g. 24), 319 + // prefix_addr (e.g. "10.20.30.0"), and broadcast_addr (e.g. "10.20.30.255"). 320 + // broadcast_addr is only set for IPv4 CIDRs. 321 + func ParseCIDR(s string) (*ParsedCIDR, error) { 322 + prefix, err := netip.ParsePrefix(s) 323 + if err != nil { 324 + return nil, err 325 + } 326 + 327 + bits := prefix.Bits() 328 + addr := prefix.Addr() 329 + maskBytes := make([]byte, addr.BitLen()/8) 330 + for i := range bits / 8 { 331 + maskBytes[i] = 0xFF 332 + } 333 + if rem := bits % 8; rem > 0 { 334 + maskBytes[bits/8] = ^byte(0xFF >> rem) 335 + } 336 + netmask, _ := netip.AddrFromSlice(maskBytes) 337 + 338 + networkAddr := prefix.Masked().Addr() 339 + 340 + result := &ParsedCIDR{ 341 + PrefixMask: netmask.String(), 342 + PrefixLen: bits, 343 + PrefixAddr: networkAddr.String(), 344 + } 345 + 346 + if addr.Is4() { 347 + broadcastBytes := networkAddr.AsSlice() 348 + for i := range broadcastBytes { 349 + broadcastBytes[i] |= ^maskBytes[i] 350 + } 351 + broadcastAddr, _ := netip.AddrFromSlice(broadcastBytes) 352 + result.BroadcastAddr = broadcastAddr.String() 353 + } 354 + 355 + return result, nil 356 + } 357 + 308 358 // InCIDR reports whether an IP address is contained a CIDR subnet string. 309 359 func InCIDR(ip, cidr cue.Value) (bool, error) { 310 360 ipAddr := netGetIP(ip)
+12
pkg/net/pkg.go
··· 264 264 } 265 265 }, 266 266 }, { 267 + Name: "ParseCIDR", 268 + Params: []pkg.Param{ 269 + {Kind: adt.StringKind}, 270 + }, 271 + Result: adt.StructKind, 272 + Func: func(c *pkg.CallCtxt) { 273 + s := c.String(0) 274 + if c.Do() { 275 + c.Ret, c.Err = ParseCIDR(s) 276 + } 277 + }, 278 + }, { 267 279 Name: "InCIDR", 268 280 Params: []pkg.Param{ 269 281 {Kind: adt.TopKind},
+90
pkg/net/testdata/parsecidr.txtar
··· 1 + -- in.cue -- 2 + import "net" 3 + 4 + // IPv4 tests 5 + t1: net.ParseCIDR("10.20.30.40/24") 6 + t2: net.ParseCIDR("192.168.1.0/24") 7 + t3: net.ParseCIDR("10.0.0.0/8") 8 + t4: net.ParseCIDR("172.16.0.0/16") 9 + t5: net.ParseCIDR("192.168.1.128/25") 10 + 11 + // IPv6 tests 12 + t6: net.ParseCIDR("2001:db8::/32") 13 + t7: net.ParseCIDR("fe80::/10") 14 + 15 + // Edge cases 16 + t8: net.ParseCIDR("0.0.0.0/0") 17 + t9: net.ParseCIDR("255.255.255.255/32") 18 + 19 + // Error cases 20 + t10: net.ParseCIDR("invalid") 21 + t11: net.ParseCIDR("192.168.1.1") 22 + -- out/net-v3 -- 23 + Errors: 24 + t10: error in call to net.ParseCIDR: netip.ParsePrefix("invalid"): no '/': 25 + ./in.cue:19:6 26 + t11: error in call to net.ParseCIDR: netip.ParsePrefix("192.168.1.1"): no '/': 27 + ./in.cue:20:6 28 + 29 + Result: 30 + // IPv4 tests 31 + t1: { 32 + prefix_mask: "255.255.255.0" 33 + prefix_len: 24 34 + prefix_addr: "10.20.30.0" 35 + broadcast_addr: "10.20.30.255" 36 + } 37 + t2: { 38 + prefix_mask: "255.255.255.0" 39 + prefix_len: 24 40 + prefix_addr: "192.168.1.0" 41 + broadcast_addr: "192.168.1.255" 42 + } 43 + t3: { 44 + prefix_mask: "255.0.0.0" 45 + prefix_len: 8 46 + prefix_addr: "10.0.0.0" 47 + broadcast_addr: "10.255.255.255" 48 + } 49 + t4: { 50 + prefix_mask: "255.255.0.0" 51 + prefix_len: 16 52 + prefix_addr: "172.16.0.0" 53 + broadcast_addr: "172.16.255.255" 54 + } 55 + t5: { 56 + prefix_mask: "255.255.255.128" 57 + prefix_len: 25 58 + prefix_addr: "192.168.1.128" 59 + broadcast_addr: "192.168.1.255" 60 + } 61 + 62 + // IPv6 tests 63 + t6: { 64 + prefix_mask: "ffff:ffff::" 65 + prefix_len: 32 66 + prefix_addr: "2001:db8::" 67 + } 68 + t7: { 69 + prefix_mask: "ffc0::" 70 + prefix_len: 10 71 + prefix_addr: "fe80::" 72 + } 73 + 74 + // Edge cases 75 + t8: { 76 + prefix_mask: "0.0.0.0" 77 + prefix_len: 0 78 + prefix_addr: "0.0.0.0" 79 + broadcast_addr: "255.255.255.255" 80 + } 81 + t9: { 82 + prefix_mask: "255.255.255.255" 83 + prefix_len: 32 84 + prefix_addr: "255.255.255.255" 85 + broadcast_addr: "255.255.255.255" 86 + } 87 + 88 + // Error cases 89 + t10: _|_ // t10: error in call to net.ParseCIDR: netip.ParsePrefix("invalid"): no '/' 90 + t11: _|_ // t11: error in call to net.ParseCIDR: netip.ParsePrefix("192.168.1.1"): no '/'