123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- // Copyright 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
- // Copyright 2009 The Go Authors
- // Released under the MIT license
-
- package flatip
-
- import (
- "bytes"
- "errors"
- "net"
- )
-
- var (
- v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
-
- IPv6loopback = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
- IPv6zero = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- IPv4zero = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0}
-
- ErrInvalidIPString = errors.New("String could not be interpreted as an IP address")
- )
-
- // packed versions of net.IP and net.IPNet; these are pure value types,
- // so they can be compared with == and used as map keys.
-
- // IP is a 128-bit representation of an IP address, using the 4-in-6 mapping
- // to represent IPv4 addresses.
- type IP [16]byte
-
- // IPNet is a IP network. In a valid value, all bits after PrefixLen are zeroes.
- type IPNet struct {
- IP
- PrefixLen uint8
- }
-
- // NetIP converts an IP into a net.IP.
- func (ip IP) NetIP() (result net.IP) {
- result = make(net.IP, 16)
- copy(result[:], ip[:])
- return
- }
-
- // FromNetIP converts a net.IP into an IP.
- func FromNetIP(ip net.IP) (result IP) {
- if len(ip) == 16 {
- copy(result[:], ip[:])
- } else {
- result[10] = 0xff
- result[11] = 0xff
- copy(result[12:], ip[:])
- }
- return
- }
-
- // IPv4 returns the IP address representation of a.b.c.d
- func IPv4(a, b, c, d byte) (result IP) {
- copy(result[:12], v4InV6Prefix)
- result[12] = a
- result[13] = b
- result[14] = c
- result[15] = d
- return
- }
-
- // ParseIP parses a string representation of an IP address into an IP.
- // Unlike net.ParseIP, it returns an error instead of a zero value on failure,
- // since the zero value of `IP` is a representation of a valid IP (::0, the
- // IPv6 "unspecified address").
- func ParseIP(ipstr string) (ip IP, err error) {
- // TODO reimplement this without net.ParseIP
- netip := net.ParseIP(ipstr)
- if netip == nil {
- err = ErrInvalidIPString
- return
- }
- netip = netip.To16()
- copy(ip[:], netip)
- return
- }
-
- // String returns the string representation of an IP
- func (ip IP) String() string {
- // TODO reimplement this without using (net.IP).String()
- return (net.IP)(ip[:]).String()
- }
-
- // IsIPv4 returns whether the IP is an IPv4 address.
- func (ip IP) IsIPv4() bool {
- return bytes.Equal(ip[:12], v4InV6Prefix)
- }
-
- // IsLoopback returns whether the IP is a loopback address.
- func (ip IP) IsLoopback() bool {
- if ip.IsIPv4() {
- return ip[12] == 127
- } else {
- return ip == IPv6loopback
- }
- }
-
- func (ip IP) IsUnspecified() bool {
- return ip == IPv4zero || ip == IPv6zero
- }
-
- func rawCidrMask(length int) (m IP) {
- n := uint(length)
- for i := 0; i < 16; i++ {
- if n >= 8 {
- m[i] = 0xff
- n -= 8
- continue
- }
- m[i] = ^byte(0xff >> n)
- return
- }
- return
- }
-
- func (ip IP) applyMask(mask IP) (result IP) {
- for i := 0; i < 16; i += 1 {
- result[i] = ip[i] & mask[i]
- }
- return
- }
-
- func cidrMask(ones, bits int) (result IP) {
- switch bits {
- case 32:
- return rawCidrMask(96 + ones)
- case 128:
- return rawCidrMask(ones)
- default:
- return
- }
- }
-
- // Mask returns the result of masking ip with the CIDR mask of
- // length 'ones', out of a total of 'bits' (which must be either
- // 32 for an IPv4 subnet or 128 for an IPv6 subnet).
- func (ip IP) Mask(ones, bits int) (result IP) {
- return ip.applyMask(cidrMask(ones, bits))
- }
-
- // ToNetIPNet converts an IPNet into a net.IPNet.
- func (cidr IPNet) ToNetIPNet() (result net.IPNet) {
- return net.IPNet{
- IP: cidr.IP.NetIP(),
- Mask: net.CIDRMask(int(cidr.PrefixLen), 128),
- }
- }
-
- // Contains retuns whether the network contains `ip`.
- func (cidr IPNet) Contains(ip IP) bool {
- maskedIP := ip.Mask(int(cidr.PrefixLen), 128)
- return cidr.IP == maskedIP
- }
-
- // FromNetIPnet converts a net.IPNet into an IPNet.
- func FromNetIPNet(network net.IPNet) (result IPNet) {
- ones, _ := network.Mask.Size()
- if len(network.IP) == 16 {
- copy(result.IP[:], network.IP[:])
- } else {
- result.IP[10] = 0xff
- result.IP[11] = 0xff
- copy(result.IP[12:], network.IP[:])
- ones += 96
- }
- // perform masking so that equal CIDRs are ==
- result.IP = result.IP.Mask(ones, 128)
- result.PrefixLen = uint8(ones)
- return
- }
-
- // String returns a string representation of an IPNet.
- func (cidr IPNet) String() string {
- ip := make(net.IP, 16)
- copy(ip[:], cidr.IP[:])
- ipnet := net.IPNet{
- IP: ip,
- Mask: net.CIDRMask(int(cidr.PrefixLen), 128),
- }
- return ipnet.String()
- }
-
- // HumanReadableString returns a string representation of an IPNet;
- // if the network contains only a single IP address, it returns
- // a representation of that address.
- func (cidr IPNet) HumanReadableString() string {
- if cidr.PrefixLen == 128 {
- return cidr.IP.String()
- }
- return cidr.String()
- }
-
- // IsZero tests whether ipnet is the zero value of an IPNet, 0::0/0.
- // Although this is a valid subnet, it can still be used as a sentinel
- // value in some contexts.
- func (ipnet IPNet) IsZero() bool {
- return ipnet == IPNet{}
- }
-
- // ParseCIDR parses a string representation of an IP network in CIDR notation,
- // then returns it as an IPNet (along with the original, unmasked address).
- func ParseCIDR(netstr string) (ip IP, ipnet IPNet, err error) {
- // TODO reimplement this without net.ParseCIDR
- nip, nipnet, err := net.ParseCIDR(netstr)
- if err != nil {
- return
- }
- return FromNetIP(nip), FromNetIPNet(*nipnet), nil
- }
|