github.com/btcsuite/btcd@v0.24.0/wire/netaddress.go (about) 1 // Copyright (c) 2013-2015 The btcsuite developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package wire 6 7 import ( 8 "io" 9 "net" 10 "time" 11 ) 12 13 // maxNetAddressPayload returns the max payload size for a bitcoin NetAddress 14 // based on the protocol version. 15 func maxNetAddressPayload(pver uint32) uint32 { 16 // Services 8 bytes + ip 16 bytes + port 2 bytes. 17 plen := uint32(26) 18 19 // NetAddressTimeVersion added a timestamp field. 20 if pver >= NetAddressTimeVersion { 21 // Timestamp 4 bytes. 22 plen += 4 23 } 24 25 return plen 26 } 27 28 // NetAddress defines information about a peer on the network including the time 29 // it was last seen, the services it supports, its IP address, and port. 30 type NetAddress struct { 31 // Last time the address was seen. This is, unfortunately, encoded as a 32 // uint32 on the wire and therefore is limited to 2106. This field is 33 // not present in the bitcoin version message (MsgVersion) nor was it 34 // added until protocol version >= NetAddressTimeVersion. 35 Timestamp time.Time 36 37 // Bitfield which identifies the services supported by the address. 38 Services ServiceFlag 39 40 // IP address of the peer. 41 IP net.IP 42 43 // Port the peer is using. This is encoded in big endian on the wire 44 // which differs from most everything else. 45 Port uint16 46 } 47 48 // HasService returns whether the specified service is supported by the address. 49 func (na *NetAddress) HasService(service ServiceFlag) bool { 50 return na.Services&service == service 51 } 52 53 // AddService adds service as a supported service by the peer generating the 54 // message. 55 func (na *NetAddress) AddService(service ServiceFlag) { 56 na.Services |= service 57 } 58 59 // NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and 60 // supported services with defaults for the remaining fields. 61 func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress { 62 return NewNetAddressTimestamp(time.Now(), services, ip, port) 63 } 64 65 // NewNetAddressTimestamp returns a new NetAddress using the provided 66 // timestamp, IP, port, and supported services. The timestamp is rounded to 67 // single second precision. 68 func NewNetAddressTimestamp( 69 timestamp time.Time, services ServiceFlag, ip net.IP, port uint16) *NetAddress { 70 // Limit the timestamp to one second precision since the protocol 71 // doesn't support better. 72 na := NetAddress{ 73 Timestamp: time.Unix(timestamp.Unix(), 0), 74 Services: services, 75 IP: ip, 76 Port: port, 77 } 78 return &na 79 } 80 81 // NewNetAddress returns a new NetAddress using the provided TCP address and 82 // supported services with defaults for the remaining fields. 83 func NewNetAddress(addr *net.TCPAddr, services ServiceFlag) *NetAddress { 84 return NewNetAddressIPPort(addr.IP, uint16(addr.Port), services) 85 } 86 87 // readNetAddress reads an encoded NetAddress from r depending on the protocol 88 // version and whether or not the timestamp is included per ts. Some messages 89 // like version do not include the timestamp. 90 func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error { 91 buf := binarySerializer.Borrow() 92 defer binarySerializer.Return(buf) 93 94 err := readNetAddressBuf(r, pver, na, ts, buf) 95 return err 96 } 97 98 // readNetAddressBuf reads an encoded NetAddress from r depending on the 99 // protocol version and whether or not the timestamp is included per ts. Some 100 // messages like version do not include the timestamp. 101 // 102 // If b is non-nil, the provided buffer will be used for serializing small 103 // values. Otherwise a buffer will be drawn from the binarySerializer's pool 104 // and return when the method finishes. 105 // 106 // NOTE: b MUST either be nil or at least an 8-byte slice. 107 func readNetAddressBuf(r io.Reader, pver uint32, na *NetAddress, ts bool, 108 buf []byte) error { 109 110 var ( 111 timestamp time.Time 112 services ServiceFlag 113 ip [16]byte 114 port uint16 115 ) 116 117 // NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will 118 // stop working somewhere around 2106. Also timestamp wasn't added until 119 // protocol version >= NetAddressTimeVersion 120 if ts && pver >= NetAddressTimeVersion { 121 if _, err := io.ReadFull(r, buf[:4]); err != nil { 122 return err 123 } 124 timestamp = time.Unix(int64(littleEndian.Uint32(buf[:4])), 0) 125 } 126 127 if _, err := io.ReadFull(r, buf); err != nil { 128 return err 129 } 130 services = ServiceFlag(littleEndian.Uint64(buf)) 131 132 if _, err := io.ReadFull(r, ip[:]); err != nil { 133 return err 134 } 135 136 // Sigh. Bitcoin protocol mixes little and big endian. 137 if _, err := io.ReadFull(r, buf[:2]); err != nil { 138 return err 139 } 140 port = bigEndian.Uint16(buf[:2]) 141 142 *na = NetAddress{ 143 Timestamp: timestamp, 144 Services: services, 145 IP: net.IP(ip[:]), 146 Port: port, 147 } 148 return nil 149 } 150 151 // writeNetAddress serializes a NetAddress to w depending on the protocol 152 // version and whether or not the timestamp is included per ts. Some messages 153 // like version do not include the timestamp. 154 func writeNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error { 155 buf := binarySerializer.Borrow() 156 defer binarySerializer.Return(buf) 157 err := writeNetAddressBuf(w, pver, na, ts, buf) 158 159 return err 160 } 161 162 // writeNetAddressBuf serializes a NetAddress to w depending on the protocol 163 // version and whether or not the timestamp is included per ts. Some messages 164 // like version do not include the timestamp. 165 // 166 // If b is non-nil, the provided buffer will be used for serializing small 167 // values. Otherwise a buffer will be drawn from the binarySerializer's pool 168 // and return when the method finishes. 169 // 170 // NOTE: b MUST either be nil or at least an 8-byte slice. 171 func writeNetAddressBuf(w io.Writer, pver uint32, na *NetAddress, ts bool, buf []byte) error { 172 // NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will 173 // stop working somewhere around 2106. Also timestamp wasn't added until 174 // until protocol version >= NetAddressTimeVersion. 175 if ts && pver >= NetAddressTimeVersion { 176 littleEndian.PutUint32(buf[:4], uint32(na.Timestamp.Unix())) 177 if _, err := w.Write(buf[:4]); err != nil { 178 return err 179 } 180 } 181 182 littleEndian.PutUint64(buf, uint64(na.Services)) 183 if _, err := w.Write(buf); err != nil { 184 return err 185 } 186 187 // Ensure to always write 16 bytes even if the ip is nil. 188 var ip [16]byte 189 if na.IP != nil { 190 copy(ip[:], na.IP.To16()) 191 } 192 if _, err := w.Write(ip[:]); err != nil { 193 return err 194 } 195 196 // Sigh. Bitcoin protocol mixes little and big endian. 197 bigEndian.PutUint16(buf[:2], na.Port) 198 _, err := w.Write(buf[:2]) 199 200 return err 201 }