1 package btcwire
2 3 import (
4 "encoding/binary"
5 "fmt"
6 "strconv"
7 "strings"
8 )
9 10 // NetAddress is a Bitcoin network address as carried by the version message:
11 // the services offered by the peer, its IP address, and its port.
12 //
13 // The IP field holds 16 bytes. IPv4 addresses are stored in their
14 // IPv4-mapped IPv6 form (::ffff:a.b.c.d), which is how they appear on the
15 // wire. The port is big endian on the wire, unlike every other integer in the
16 // protocol.
17 type NetAddress struct {
18 // Services is the set of service bits advertised by the peer.
19 Services uint64
20 21 // IP is the 16-byte IP address.
22 IP [16]byte
23 24 // Port is the TCP port.
25 Port uint16
26 }
27 28 // v4MappedPrefix is the 12-byte prefix of an IPv4-mapped IPv6 address.
29 var v4MappedPrefix = [12]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
30 31 // NewNetAddress parses host, which must be an IPv4 dotted quad or an IPv6
32 // literal as defined by RFC 4291 (optionally enclosed in brackets), and
33 // returns an address with the given port. IPv6 zone identifiers are not
34 // supported, and DNS names are not resolved: this package performs no name
35 // service work and does not import the net package.
36 func NewNetAddress(host string, port uint16) (*NetAddress, error) {
37 ip, err := parseIP(host)
38 if err != nil {
39 return nil, err
40 }
41 return &NetAddress{IP: ip, Port: port}, nil
42 }
43 44 // IsZero reports whether the address holds no endpoint, that is, whether both
45 // its IP and its port are zero.
46 func (na *NetAddress) IsZero() bool {
47 if na.Port != 0 {
48 return false
49 }
50 return na.IP == [16]byte{}
51 }
52 53 // IPString returns the textual form of the address's IP: dotted quad for
54 // IPv4 and IPv4-mapped addresses, and RFC 5952 IPv6 notation otherwise.
55 func (na *NetAddress) IPString() string {
56 return formatIP(na.IP)
57 }
58 59 // String returns the address as host:port, with the host bracketed when it is
60 // an IPv6 address.
61 func (na *NetAddress) String() string {
62 host := formatIP(na.IP)
63 port := strconv.FormatUint(uint64(na.Port), 10)
64 if strings.IndexByte(host, ':') >= 0 {
65 return "[" + host + "]:" + port
66 }
67 return host + ":" + port
68 }
69 70 // encode appends the wire encoding of the address: services, IP, and big
71 // endian port.
72 func (na *NetAddress) encode(e *Encoder) {
73 e.Uint64(na.Services)
74 e.Write(na.IP[:])
75 e.Uint16BE(na.Port)
76 }
77 78 // decode replaces the address with the one decoded from d.
79 func (na *NetAddress) decode(d *Decoder) error {
80 services, err := d.Uint64()
81 if err != nil {
82 return fmt.Errorf("btcwire: decoding address services: %w", err)
83 }
84 ip, err := d.Bytes(len(na.IP))
85 if err != nil {
86 return fmt.Errorf("btcwire: decoding address IP: %w", err)
87 }
88 port, err := d.Uint16BE()
89 if err != nil {
90 return fmt.Errorf("btcwire: decoding address port: %w", err)
91 }
92 na.Services = services
93 copy(na.IP[:], ip)
94 na.Port = port
95 return nil
96 }
97 98 // parseIP parses host, which may be an IPv4 or IPv6 literal and may be
99 // bracketed, into its 16-byte wire representation.
100 func parseIP(host string) ([16]byte, error) {
101 var ip [16]byte
102 if len(host) >= 2 && host[0] == '[' && host[len(host)-1] == ']' {
103 host = host[1 : len(host)-1]
104 }
105 if host == "" {
106 return ip, fmt.Errorf("%w: empty host", ErrInvalidAddress)
107 }
108 if strings.IndexByte(host, ':') >= 0 {
109 parsed, ok := parseIPv6(host)
110 if !ok {
111 return ip, fmt.Errorf("%w: %q is not an IPv6 address", ErrInvalidAddress, host)
112 }
113 return parsed, nil
114 }
115 v4, ok := parseIPv4(host)
116 if !ok {
117 return ip, fmt.Errorf("%w: %q is not an IPv4 address", ErrInvalidAddress, host)
118 }
119 copy(ip[:len(v4MappedPrefix)], v4MappedPrefix[:])
120 copy(ip[12:16], v4[:])
121 return ip, nil
122 }
123 124 // parseIPv4 parses a dotted quad. Leading zeros are rejected because they make
125 // the interpretation ambiguous.
126 func parseIPv4(s string) ([4]byte, bool) {
127 var out [4]byte
128 parts := strings.Split(s, ".")
129 if len(parts) != 4 {
130 return out, false
131 }
132 for i, part := range parts {
133 if len(part) == 0 || len(part) > 3 {
134 return out, false
135 }
136 if len(part) > 1 && part[0] == '0' {
137 return out, false
138 }
139 n := 0
140 for j := 0; j < len(part); j++ {
141 c := part[j]
142 if c < '0' || c > '9' {
143 return out, false
144 }
145 n = n*10 + int(c-'0')
146 }
147 if n > 255 {
148 return out, false
149 }
150 out[i] = byte(n)
151 }
152 return out, true
153 }
154 155 // parseIPv6 parses an IPv6 literal, including forms with an embedded IPv4
156 // dotted quad and at most one "::" compression.
157 func parseIPv6(s string) ([16]byte, bool) {
158 var ip [16]byte
159 if idx := strings.Index(s, "::"); idx >= 0 {
160 rest := s[idx+2:]
161 if strings.Contains(rest, "::") {
162 return ip, false
163 }
164 head, ok := parseIPv6Groups(s[:idx], false)
165 if !ok {
166 return ip, false
167 }
168 tail, ok := parseIPv6Groups(rest, true)
169 if !ok {
170 return ip, false
171 }
172 if len(head)+len(tail) > 7 {
173 return ip, false
174 }
175 for i, g := range head {
176 binary.BigEndian.PutUint16(ip[2*i:], g)
177 }
178 base := 8 - len(tail)
179 for i, g := range tail {
180 binary.BigEndian.PutUint16(ip[2*(base+i):], g)
181 }
182 return ip, true
183 }
184 groups, ok := parseIPv6Groups(s, true)
185 if !ok || len(groups) != 8 {
186 return ip, false
187 }
188 for i, g := range groups {
189 binary.BigEndian.PutUint16(ip[2*i:], g)
190 }
191 return ip, true
192 }
193 194 // parseIPv6Groups parses the colon-separated 16-bit groups of s. When
195 // allowIPv4 is true the final group may be a dotted quad, which contributes
196 // two 16-bit groups.
197 func parseIPv6Groups(s string, allowIPv4 bool) ([]uint16, bool) {
198 if s == "" {
199 return nil, true
200 }
201 parts := strings.Split(s, ":")
202 groups := make([]uint16, 0, len(parts))
203 for i, part := range parts {
204 if part == "" {
205 return nil, false
206 }
207 if allowIPv4 && i == len(parts)-1 && strings.IndexByte(part, '.') >= 0 {
208 v4, ok := parseIPv4(part)
209 if !ok {
210 return nil, false
211 }
212 groups = append(groups,
213 binary.BigEndian.Uint16(v4[0:2]),
214 binary.BigEndian.Uint16(v4[2:4]),
215 )
216 continue
217 }
218 if len(part) > 4 {
219 return nil, false
220 }
221 var group uint16
222 for j := 0; j < len(part); j++ {
223 c := part[j]
224 var digit uint16
225 switch {
226 case c >= '0' && c <= '9':
227 digit = uint16(c - '0')
228 case c >= 'a' && c <= 'f':
229 digit = uint16(c-'a') + 10
230 case c >= 'A' && c <= 'F':
231 digit = uint16(c-'A') + 10
232 default:
233 return nil, false
234 }
235 group = group<<4 | digit
236 }
237 groups = append(groups, group)
238 }
239 return groups, true
240 }
241 242 // formatIP renders a 16-byte IP in its shortest standard textual form.
243 func formatIP(ip [16]byte) string {
244 if v4, ok := ipv4FromMapped(ip); ok {
245 return strconv.Itoa(int(v4[0])) + "." + strconv.Itoa(int(v4[1])) + "." +
246 strconv.Itoa(int(v4[2])) + "." + strconv.Itoa(int(v4[3]))
247 }
248 var groups [8]uint16
249 for i := range groups {
250 groups[i] = binary.BigEndian.Uint16(ip[2*i:])
251 }
252 // Find the longest run of zero groups; the leftmost run wins ties. Only
253 // runs of two or more groups are compressed.
254 bestStart, bestLen := -1, 0
255 for i := 0; i < len(groups); {
256 if groups[i] != 0 {
257 i++
258 continue
259 }
260 j := i
261 for j < len(groups) && groups[j] == 0 {
262 j++
263 }
264 if j-i > bestLen {
265 bestStart, bestLen = i, j-i
266 }
267 i = j
268 }
269 if bestLen < 2 {
270 bestStart, bestLen = -1, 0
271 }
272 var b strings.Builder
273 wrote := false
274 justCompressed := false
275 for i := 0; i < len(groups); i++ {
276 if i == bestStart {
277 b.WriteString("::")
278 wrote, justCompressed = true, true
279 i += bestLen - 1
280 continue
281 }
282 if wrote && !justCompressed {
283 b.WriteByte(':')
284 }
285 b.WriteString(strconv.FormatUint(uint64(groups[i]), 16))
286 wrote, justCompressed = true, false
287 }
288 return b.String()
289 }
290 291 // ipv4FromMapped returns the dotted-quad bytes of an IPv4-mapped IPv6
292 // address.
293 func ipv4FromMapped(ip [16]byte) ([4]byte, bool) {
294 var v4 [4]byte
295 for i := 0; i < len(v4MappedPrefix); i++ {
296 if ip[i] != v4MappedPrefix[i] {
297 return v4, false
298 }
299 }
300 copy(v4[:], ip[12:16])
301 return v4, true
302 }
303