cuelang.org/go@v0.10.1/pkg/net/ip.go (about) 1 // Copyright 2019 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package net defines net-related types. 16 package net 17 18 import ( 19 "fmt" 20 "net/netip" 21 22 "cuelang.org/go/cue" 23 ) 24 25 // IP address lengths (bytes). 26 const ( 27 IPv4len = 4 28 IPv6len = 16 29 ) 30 31 func netGetIP(ip cue.Value) (goip netip.Addr) { 32 switch ip.Kind() { 33 case cue.StringKind: 34 s, err := ip.String() 35 if err != nil { 36 return netip.Addr{} 37 } 38 goip, err := netip.ParseAddr(s) 39 if err != nil { 40 return netip.Addr{} 41 } 42 return goip 43 44 case cue.BytesKind: 45 b, err := ip.Bytes() 46 if err != nil { 47 return netip.Addr{} 48 } 49 goip, err := netip.ParseAddr(string(b)) 50 if err != nil { 51 return netip.Addr{} 52 } 53 return goip 54 55 case cue.ListKind: 56 iter, err := ip.List() 57 if err != nil { 58 return netip.Addr{} 59 } 60 var bytes []byte 61 for iter.Next() { 62 v, err := iter.Value().Int64() 63 if err != nil { 64 return netip.Addr{} 65 } 66 if v < 0 || 255 < v { 67 return netip.Addr{} 68 } 69 bytes = append(bytes, byte(v)) 70 } 71 goip, ok := netip.AddrFromSlice(bytes) 72 if !ok { 73 return netip.Addr{} 74 } 75 return goip 76 77 default: 78 // TODO: return canonical invalid type. 79 return netip.Addr{} 80 } 81 } 82 83 func netGetIPCIDR(ip cue.Value) (gonet *netip.Prefix, err error) { 84 switch ip.Kind() { 85 case cue.StringKind: 86 s, err := ip.String() 87 if err != nil { 88 return nil, err 89 } 90 cidr, err := netip.ParsePrefix(s) 91 if err != nil { 92 return nil, err 93 } 94 return &cidr, nil 95 96 case cue.BytesKind: 97 b, err := ip.Bytes() 98 if err != nil { 99 return nil, err 100 } 101 cidr, err := netip.ParsePrefix(string(b)) 102 if err != nil { 103 return nil, err 104 } 105 return &cidr, nil 106 107 default: 108 // TODO: return canonical invalid type. 109 return nil, nil 110 } 111 } 112 113 // ParseIP parses s as an IP address, returning the result. 114 // The string s can be in dotted decimal ("192.0.2.1") 115 // or IPv6 ("2001:db8::68") form. 116 // If s is not a valid textual representation of an IP address, 117 // ParseIP returns nil. 118 func ParseIP(s string) ([]uint, error) { 119 goip, err := netip.ParseAddr(s) 120 if err != nil { 121 return nil, fmt.Errorf("invalid IP address %q", s) 122 } 123 return netToList(goip.AsSlice()), nil 124 } 125 126 func netToList(ip []byte) []uint { 127 a := make([]uint, len(ip)) 128 for i, p := range ip { 129 a[i] = uint(p) 130 } 131 return a 132 } 133 134 // IPv4 reports whether ip is a valid IPv4 address. 135 // 136 // The address may be a string or list of bytes. 137 func IPv4(ip cue.Value) bool { 138 // TODO: convert to native CUE. 139 return netGetIP(ip).Is4() 140 } 141 142 // IPv6 reports whether ip is a valid IPv6 address. 143 // 144 // The address may be a string or list of bytes. 145 func IPv6(ip cue.Value) bool { 146 return netGetIP(ip).Is6() 147 } 148 149 // IP reports whether ip is a valid IPv4 or IPv6 address. 150 // 151 // The address may be a string or list of bytes. 152 func IP(ip cue.Value) bool { 153 // TODO: convert to native CUE. 154 return netGetIP(ip).IsValid() 155 } 156 157 // IPCIDR reports whether ip is a valid IPv4 or IPv6 address with CIDR subnet notation. 158 // 159 // The address may be a string or list of bytes. 160 func IPCIDR(ip cue.Value) (bool, error) { 161 _, err := netGetIPCIDR(ip) 162 return err == nil, err 163 } 164 165 // LoopbackIP reports whether ip is a loopback address. 166 func LoopbackIP(ip cue.Value) bool { 167 return netGetIP(ip).IsLoopback() 168 } 169 170 // MulticastIP reports whether ip is a multicast address. 171 func MulticastIP(ip cue.Value) bool { 172 return netGetIP(ip).IsMulticast() 173 } 174 175 // InterfaceLocalMulticastIP reports whether ip is an interface-local multicast 176 // address. 177 func InterfaceLocalMulticastIP(ip cue.Value) bool { 178 return netGetIP(ip).IsInterfaceLocalMulticast() 179 } 180 181 // LinkLocalMulticast reports whether ip is a link-local multicast address. 182 func LinkLocalMulticastIP(ip cue.Value) bool { 183 return netGetIP(ip).IsLinkLocalMulticast() 184 } 185 186 // LinkLocalUnicastIP reports whether ip is a link-local unicast address. 187 func LinkLocalUnicastIP(ip cue.Value) bool { 188 return netGetIP(ip).IsLinkLocalUnicast() 189 } 190 191 // GlobalUnicastIP reports whether ip is a global unicast address. 192 // 193 // The identification of global unicast addresses uses address type 194 // identification as defined in RFC 1122, RFC 4632 and RFC 4291 with the 195 // exception of IPv4 directed broadcast addresses. It returns true even if ip is 196 // in IPv4 private address space or local IPv6 unicast address space. 197 func GlobalUnicastIP(ip cue.Value) bool { 198 return netGetIP(ip).IsGlobalUnicast() 199 } 200 201 // UnspecifiedIP reports whether ip is an unspecified address, either the IPv4 202 // address "0.0.0.0" or the IPv6 address "::". 203 func UnspecifiedIP(ip cue.Value) bool { 204 return netGetIP(ip).IsUnspecified() 205 } 206 207 // ToIP4 converts a given IP address, which may be a string or a list, to its 208 // 4-byte representation. 209 func ToIP4(ip cue.Value) ([]uint, error) { 210 ipdata := netGetIP(ip) 211 if !ipdata.IsValid() { 212 return nil, fmt.Errorf("invalid IP %q", ip) 213 } 214 if !ipdata.Is4() { 215 return nil, fmt.Errorf("cannot convert %q to IPv4", ipdata) 216 } 217 as4 := ipdata.As4() 218 return netToList(as4[:]), nil 219 } 220 221 // ToIP16 converts a given IP address, which may be a string or a list, to its 222 // 16-byte representation. 223 func ToIP16(ip cue.Value) ([]uint, error) { 224 ipdata := netGetIP(ip) 225 if !ipdata.IsValid() { 226 return nil, fmt.Errorf("invalid IP %q", ip) 227 } 228 as16 := ipdata.As16() 229 return netToList(as16[:]), nil 230 } 231 232 // IPString returns the string form of the IP address ip. It returns one of 4 forms: 233 // 234 // - "<nil>", if ip has length 0 235 // - dotted decimal ("192.0.2.1"), if ip is an IPv4 or IP4-mapped IPv6 address 236 // - IPv6 ("2001:db8::1"), if ip is a valid IPv6 address 237 // - the hexadecimal form of ip, without punctuation, if no other cases apply 238 func IPString(ip cue.Value) (string, error) { 239 ipdata := netGetIP(ip) 240 if !ipdata.IsValid() { 241 return "", fmt.Errorf("invalid IP %q", ip) 242 } 243 return ipdata.String(), nil 244 }