github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/ipv6/addr.go (about)

     1  /* For license and copyright information please see LEGAL file in repository */
     2  
     3  package ipv6
     4  
     5  import "../protocol"
     6  
     7  // An Addr is an IP address version 6.
     8  type Addr [Addrlen]byte
     9  
    10  const (
    11  	// Addrlen address lengths 128 bit || 16 byte.
    12  	Addrlen = 16
    13  
    14  	hextable = "0123456789abcdef"
    15  )
    16  
    17  // Well-known IPv6 addresses
    18  var (
    19  	AddrZero                   = Addr{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    20  	AddrUnspecified            = Addr{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // "::"
    21  	AddrLoopback               = Addr{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
    22  	AddrInterfaceLocalAllNodes = Addr{0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
    23  	AddrLinkLocalAllnodes      = Addr{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
    24  	AddrLinkLocalAllRouters    = Addr{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}
    25  )
    26  
    27  func (addr Addr) IsUnspecified() bool             { return addr == AddrUnspecified }
    28  func (addr Addr) IsLoopback() bool                { return addr == AddrLoopback }
    29  func (addr Addr) IsMulticast() bool               { return addr[0] == 0xff }
    30  func (addr Addr) IsInterfaceLocalMulticast() bool { return addr[0] == 0xff && addr[1]&0x0f == 0x01 }
    31  func (addr Addr) IsLinkLocalMulticast() bool      { return addr[0] == 0xff && addr[1]&0x0f == 0x02 }
    32  func (addr Addr) IsLinkLocalUnicast() bool        { return addr[0] == 0xfe && addr[1]&0xc0 == 0x80 }
    33  
    34  // IsGlobalUnicast reports whether ip is a global unicast address.
    35  // It returns true even if ip is local IPv6 unicast address space.
    36  // https://tools.ietf.org/html/rfc1122
    37  // https://tools.ietf.org/html/rfc4632
    38  // https://tools.ietf.org/html/rfc4291
    39  func (addr *Addr) IsGlobalUnicast() bool {
    40  	return !addr.IsUnspecified() &&
    41  		!addr.IsLoopback() &&
    42  		!addr.IsMulticast() &&
    43  		!addr.IsLinkLocalUnicast()
    44  }
    45  
    46  // ToString returns canonical string representation of IPv6.
    47  func (addr Addr) ToString() string {
    48  	// Find longest run of zeros.
    49  	var e0 = -1
    50  	var e1 = -1
    51  	for i := 0; i < Addrlen; i += 2 {
    52  		j := i
    53  		for j < Addrlen && addr[j] == 0 && addr[j+1] == 0 {
    54  			j += 2
    55  		}
    56  		if j > i && j-i > e1-e0 {
    57  			e0 = i
    58  			e1 = j
    59  			i = j
    60  		}
    61  	}
    62  	// The symbol "::" MUST NOT be used to shorten just one 16 bit 0 field.
    63  	if e1-e0 <= 2 {
    64  		e0 = -1
    65  		e1 = -1
    66  	}
    67  
    68  	const maxStringLen = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
    69  	var b = make([]byte, 0, maxStringLen)
    70  
    71  	// Print with possible :: in place of run of zeros
    72  	for i := 0; i < Addrlen; i += 2 {
    73  		if i == e0 {
    74  			b = append(b, ':', ':')
    75  			i = e1
    76  			if i >= Addrlen {
    77  				break
    78  			}
    79  		} else if i > 0 {
    80  			b = append(b, ':')
    81  		}
    82  		b[i*2] = hextable[addr[i]>>4]
    83  		b[i*2+1] = hextable[addr[i+1]&0x0f]
    84  	}
    85  	return string(b)
    86  }
    87  
    88  // FromString parses ip as a literal IPv6 address described in RFC 4291 and RFC 5952.
    89  func (addr *Addr) FromString(ip string) (err protocol.Error) {
    90  	var ellipsis = -1 // position of ellipsis in ip
    91  
    92  	// Might have leading ellipsis
    93  	if len(ip) >= 2 && ip[0] == ':' && ip[1] == ':' {
    94  		ellipsis = 0
    95  		ip = ip[2:]
    96  		// Might be only ellipsis
    97  		if len(ip) == 0 {
    98  			return
    99  		}
   100  	}
   101  
   102  	// Loop, parsing hex numbers followed by colon.
   103  	var i = 0
   104  	for i < Addrlen {
   105  		// Hex number.
   106  		n, c, ok := xtoi(ip)
   107  		if !ok || n > 0xFFFF {
   108  			return
   109  		}
   110  
   111  		// Save this 16-bit chunk.
   112  		addr[i] = byte(n >> 8)
   113  		addr[i+1] = byte(n)
   114  		i += 2
   115  
   116  		// Stop at end of string.
   117  		ip = ip[c:]
   118  		if len(ip) == 0 {
   119  			break
   120  		}
   121  
   122  		// Otherwise must be followed by colon and more.
   123  		if ip[0] != ':' || len(ip) == 1 {
   124  			return
   125  		}
   126  		ip = ip[1:]
   127  
   128  		// Look for ellipsis.
   129  		if ip[0] == ':' {
   130  			if ellipsis >= 0 { // already have one
   131  				return
   132  			}
   133  			ellipsis = i
   134  			ip = ip[1:]
   135  			if len(ip) == 0 { // can be at end
   136  				break
   137  			}
   138  		}
   139  	}
   140  
   141  	// Must have used entire string.
   142  	if len(ip) != 0 {
   143  		return
   144  	}
   145  
   146  	// If didn't parse enough, expand ellipsis.
   147  	if i < Addrlen {
   148  		if ellipsis < 0 {
   149  			return
   150  		}
   151  		var n = Addrlen - i
   152  		for j := i - 1; j >= ellipsis; j-- {
   153  			addr[j+n] = addr[j]
   154  		}
   155  		for j := ellipsis + n - 1; j >= ellipsis; j-- {
   156  			addr[j] = 0
   157  		}
   158  	} else if ellipsis >= 0 {
   159  		// Ellipsis must represent at least one 0 group.
   160  		return
   161  	}
   162  }
   163  
   164  // Bigger than we need, not too big to worry about overflow
   165  const big = 0xFFFFFF
   166  
   167  // Hexadecimal to integer.
   168  // Returns number, characters consumed, success.
   169  func xtoi(s string) (n int, i int, ok bool) {
   170  	n = 0
   171  	for i = 0; i < len(s); i++ {
   172  		if '0' <= s[i] && s[i] <= '9' {
   173  			n *= 16
   174  			n += int(s[i] - '0')
   175  		} else if 'a' <= s[i] && s[i] <= 'f' {
   176  			n *= 16
   177  			n += int(s[i]-'a') + 10
   178  		} else if 'A' <= s[i] && s[i] <= 'F' {
   179  			n *= 16
   180  			n += int(s[i]-'A') + 10
   181  		} else {
   182  			break
   183  		}
   184  		if n >= big {
   185  			return 0, i, false
   186  		}
   187  	}
   188  	if i == 0 {
   189  		return 0, i, false
   190  	}
   191  	return n, i, true
   192  }