github.com/openshift/installer@v1.4.17/pkg/ipnet/ipnet.go (about) 1 // Package ipnet wraps net.IPNet to get CIDR serialization. 2 package ipnet 3 4 import ( 5 "encoding/json" 6 "net" 7 "reflect" 8 9 "github.com/pkg/errors" 10 ) 11 12 var nullString = "null" 13 var nullBytes = []byte(nullString) 14 var emptyIPNet = net.IPNet{} 15 16 // IPNet wraps net.IPNet to get CIDR serialization. 17 // +kubebuilder:validation:Type=string 18 type IPNet struct { 19 net.IPNet 20 } 21 22 // String returns a CIDR serialization of the subnet, or an empty 23 // string if the subnet is nil. 24 func (ipnet *IPNet) String() string { 25 if ipnet == nil { 26 return "" 27 } 28 return ipnet.IPNet.String() 29 } 30 31 // MarshalJSON interface for an IPNet 32 func (ipnet IPNet) MarshalJSON() (data []byte, err error) { 33 if reflect.DeepEqual(ipnet.IPNet, emptyIPNet) { 34 return nullBytes, nil 35 } 36 37 return json.Marshal(ipnet.String()) 38 } 39 40 // UnmarshalJSON interface for an IPNet 41 func (ipnet *IPNet) UnmarshalJSON(b []byte) (err error) { 42 if string(b) == nullString { 43 ipnet.IP = net.IP{} 44 ipnet.Mask = net.IPMask{} 45 return nil 46 } 47 48 var cidr string 49 err = json.Unmarshal(b, &cidr) 50 if err != nil { 51 return errors.Wrap(err, "failed to Unmarshal string") 52 } 53 54 parsedIPNet, err := ParseCIDR(cidr) 55 if err != nil { 56 return errors.Wrap(err, "failed to Parse cidr string to net.IPNet") 57 } 58 59 *ipnet = *parsedIPNet 60 61 return nil 62 } 63 64 // ParseCIDR parses a CIDR from its string representation. 65 func ParseCIDR(s string) (*IPNet, error) { 66 ip, cidr, err := net.ParseCIDR(s) 67 if err != nil { 68 return nil, err 69 } 70 71 // This check is needed in order to work around a strange quirk in the Go 72 // standard library. All of the addresses returned by net.ParseCIDR() are 73 // 16-byte addresses. This does _not_ imply that they are IPv6 addresses, 74 // which is what some libraries (e.g. github.com/apparentlymart/go-cidr) 75 // assume. By forcing the address to be the expected length, we can work 76 // around these bugs. 77 if ip.To4() != nil { 78 ip = ip.To4() 79 } 80 81 return &IPNet{ 82 IPNet: net.IPNet{ 83 IP: ip, 84 Mask: cidr.Mask, 85 }, 86 }, nil 87 } 88 89 // MustParseCIDR parses a CIDR from its string representation. If the parse fails, 90 // the function will panic. 91 func MustParseCIDR(s string) *IPNet { 92 cidr, err := ParseCIDR(s) 93 if err != nil { 94 panic(err) 95 } 96 return cidr 97 }