github.com/GeniusesGroup/libgo@v0.0.0-20220929090155-5ff932cb408e/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 }