this repo has no description
0
fork

Configure Feed

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

pkg/net: add ip arithmetic functions

This change introduces two functions to adding numerical offsets to IP
addresses or CIDR networks.

Closes #3815 as merged as of commit a140ef04d.
Fixes #3142

Signed-off-by: takonomura <takonomura@users.noreply.github.com>
Change-Id: I6bd3dc0fcb1ea234bb369004f693c37a1a7c293e
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1220044
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>

authored by

takonomura and committed by
Roger Peppe
f374d290 ae345858

+126
+62
pkg/net/ip.go
··· 16 16 package net 17 17 18 18 import ( 19 + "errors" 19 20 "fmt" 21 + "math/big" 20 22 "net/netip" 21 23 22 24 "cuelang.org/go/cue" ··· 242 244 } 243 245 return ipdata.String(), nil 244 246 } 247 + 248 + func netIPAdd(addr netip.Addr, offset *big.Int) (netip.Addr, error) { 249 + i := big.NewInt(0).SetBytes(addr.AsSlice()) 250 + i = i.Add(i, offset) 251 + 252 + if i.Sign() < 0 { 253 + return netip.Addr{}, errors.New("IP address arithmetic resulted in out-of-range address (underflow)") 254 + } 255 + 256 + b := i.Bytes() 257 + size := addr.BitLen() / 8 258 + 259 + if len(b) > size { 260 + return netip.Addr{}, errors.New("IP address arithmetic resulted in out-of-range address (overflow)") 261 + } 262 + 263 + if len(b) < size { 264 + b = append(make([]byte, size-len(b), size), b...) 265 + } 266 + addr, _ = netip.AddrFromSlice(b) 267 + return addr, nil 268 + } 269 + 270 + // AddIP adds a numerical offset to a given IP address. 271 + // The address can be provided as a string, byte array, or CIDR subnet notation. 272 + // It returns the resulting IP address or CIDR subnet notation as a string. 273 + func AddIP(ip cue.Value, offset *big.Int) (string, error) { 274 + prefix, err := netGetIPCIDR(ip) 275 + if err == nil { 276 + addr, err := netIPAdd(prefix.Addr(), offset) 277 + if err != nil { 278 + return "", err 279 + } 280 + return netip.PrefixFrom(addr, prefix.Bits()).String(), nil 281 + } 282 + ipdata := netGetIP(ip) 283 + if !ipdata.IsValid() { 284 + return "", fmt.Errorf("invalid IP %q", ip) 285 + } 286 + addr, err := netIPAdd(ipdata, offset) 287 + if err != nil { 288 + return "", err 289 + } 290 + return addr.String(), nil 291 + } 292 + 293 + // AddIPCIDR adds a numerical offset to a given CIDR subnet 294 + // string, returning a CIDR string. 295 + func AddIPCIDR(ip cue.Value, offset *big.Int) (string, error) { 296 + prefix, err := netGetIPCIDR(ip) 297 + if err != nil { 298 + return "", err 299 + } 300 + shifted := big.NewInt(0).Lsh(offset, (uint)(prefix.Addr().BitLen()-prefix.Bits())) 301 + addr, err := netIPAdd(prefix.Addr(), shifted) 302 + if err != nil { 303 + return "", err 304 + } 305 + return netip.PrefixFrom(addr, prefix.Bits()).String(), nil 306 + }
+26
pkg/net/pkg.go
··· 238 238 } 239 239 }, 240 240 }, { 241 + Name: "AddIP", 242 + Params: []pkg.Param{ 243 + {Kind: adt.TopKind}, 244 + {Kind: adt.IntKind}, 245 + }, 246 + Result: adt.StringKind, 247 + Func: func(c *pkg.CallCtxt) { 248 + ip, offset := c.Value(0), c.BigInt(1) 249 + if c.Do() { 250 + c.Ret, c.Err = AddIP(ip, offset) 251 + } 252 + }, 253 + }, { 254 + Name: "AddIPCIDR", 255 + Params: []pkg.Param{ 256 + {Kind: adt.TopKind}, 257 + {Kind: adt.IntKind}, 258 + }, 259 + Result: adt.StringKind, 260 + Func: func(c *pkg.CallCtxt) { 261 + ip, offset := c.Value(0), c.BigInt(1) 262 + if c.Do() { 263 + c.Ret, c.Err = AddIPCIDR(ip, offset) 264 + } 265 + }, 266 + }, { 241 267 Name: "PathEscape", 242 268 Params: []pkg.Param{ 243 269 {Kind: adt.StringKind},
+38
pkg/net/testdata/gen.txtar
··· 37 37 t32: net.AbsURL & "/foo/bar" 38 38 t33: net.AbsURL & "https://foo.com/bar" 39 39 t34: net.AbsURL & "%" 40 + t35: net.AddIP("127.0.0.1", 1) 41 + t36: net.AddIP("127.0.0.1/8", 2) 42 + t37: net.AddIP("2001:db8::", 1) 43 + t38: net.AddIP("2001:db8::/64", 2) 44 + t39: net.AddIP("invalid ip", 1) 45 + t40: net.AddIP("0.0.0.0", -1) 46 + t41: net.AddIP("255.255.255.255", 1) 47 + t42: net.AddIP("::ffff:127.0.0.1", 1) 48 + t43: net.AddIPCIDR("192.168.0.0/23", 1) 49 + t44: net.AddIPCIDR("2001:db8:1111:2222::/64", 1) 50 + t45: net.AddIPCIDR("192.168.0.0", 1) 51 + t46: net.AddIPCIDR("10.0.0.0/8", -11) 52 + t47: net.AddIPCIDR("255.0.0.0/8", 1) 40 53 -- out/net -- 41 54 Errors: 42 55 t25: invalid value "2001:db8::1234567" (does not satisfy net.IPv6): ··· 64 77 t27: invalid value "23.23.23.23" (does not satisfy net.IPv6): 65 78 ./in.cue:29:6 66 79 ./in.cue:29:19 80 + t39: error in call to net.AddIP: invalid IP "invalid ip": 81 + ./in.cue:41:6 82 + t40: error in call to net.AddIP: IP address arithmetic resulted in out-of-range address (underflow): 83 + ./in.cue:42:6 84 + t41: error in call to net.AddIP: IP address arithmetic resulted in out-of-range address (overflow): 85 + ./in.cue:43:6 86 + t45: error in call to net.AddIPCIDR: netip.ParsePrefix("192.168.0.0"): no '/': 87 + ./in.cue:47:6 88 + t46: error in call to net.AddIPCIDR: IP address arithmetic resulted in out-of-range address (underflow): 89 + ./in.cue:48:6 90 + t47: error in call to net.AddIPCIDR: IP address arithmetic resulted in out-of-range address (overflow): 91 + ./in.cue:49:6 67 92 68 93 Result: 69 94 t1: "foo.bar." ··· 100 125 t32: _|_ // t32: invalid value "/foo/bar" (does not satisfy net.AbsURL): t32: error in call to net.AbsURL: URL is not absolute 101 126 t33: "https://foo.com/bar" 102 127 t34: _|_ // t34: invalid value "%" (does not satisfy net.AbsURL): t34: error in call to net.AbsURL: parse "%": invalid URL escape "%" 128 + t35: "127.0.0.2" 129 + t36: "127.0.0.3/8" 130 + t37: "2001:db8::1" 131 + t38: "2001:db8::2/64" 132 + t39: _|_ // t39: error in call to net.AddIP: invalid IP "invalid ip" 133 + t40: _|_ // t40: error in call to net.AddIP: IP address arithmetic resulted in out-of-range address (underflow) 134 + t41: _|_ // t41: error in call to net.AddIP: IP address arithmetic resulted in out-of-range address (overflow) 135 + t42: "::ffff:127.0.0.2" 136 + t43: "192.168.2.0/23" 137 + t44: "2001:db8:1111:2223::/64" 138 + t45: _|_ // t45: error in call to net.AddIPCIDR: netip.ParsePrefix("192.168.0.0"): no '/' 139 + t46: _|_ // t46: error in call to net.AddIPCIDR: IP address arithmetic resulted in out-of-range address (underflow) 140 + t47: _|_ // t47: error in call to net.AddIPCIDR: IP address arithmetic resulted in out-of-range address (overflow)