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  }