-
Notifications
You must be signed in to change notification settings - Fork 16
/
netaddress.go
210 lines (183 loc) · 6.46 KB
/
netaddress.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// Copyright (c) 2017-2018 The qitmeer developers
// Copyright (c) 2013-2015 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package types
import (
"encoding/binary"
"errors"
"github.com/Qitmeer/qng/common/network"
"github.com/Qitmeer/qng/common/roughtime"
"github.com/Qitmeer/qng/core/protocol"
s "github.com/Qitmeer/qng/core/serialization"
"io"
"net"
"strconv"
"time"
)
// ErrInvalidNetAddr describes an error that indicates the caller didn't specify
// a TCP address as required.
var ErrInvalidNetAddr = errors.New("provided net.Addr is not a net.TCPAddr")
// MaxNetAddressPayload returns the max payload size for the NetAddress
// based on the protocol version.
func MaxNetAddressPayload(pver uint32) uint32 {
// Services 8 bytes + ip 16 bytes + port 2 bytes.
plen := uint32(26)
// Timestamp 4 bytes.
plen += 4
return plen
}
// NetAddress defines information about a peer on the network including the time
// it was last seen, the services it supports, its IP address, and port.
type NetAddress struct {
// Last time the address was seen. This is, unfortunately, encoded as a
// uint32 on the wire and therefore is limited to 2106. This field is
// not present in the version message (MsgVersion) nor was it
// added until protocol version >= NetAddressTimeVersion.
Timestamp time.Time
// Bitfield which identifies the services supported by the address.
Services protocol.ServiceFlag
// IP address of the peer.
IP net.IP
// Port the peer is using. This is encoded in big endian on the wire
// which differs from most everything else.
Port uint16
}
// HasService returns whether the specified service is supported by the address.
func (na *NetAddress) HasService(service protocol.ServiceFlag) bool {
return na.Services&service == service
}
// AddService adds service as a supported service by the peer generating the
// message.
func (na *NetAddress) AddService(service protocol.ServiceFlag) {
na.Services |= service
}
// NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and
// supported services with defaults for the remaining fields.
func NewNetAddressIPPort(ip net.IP, port uint16, services protocol.ServiceFlag) *NetAddress {
return NewNetAddressTimestamp(roughtime.Now(), services, ip, port)
}
// NewNetAddressTimestamp returns a new NetAddress using the provided
// timestamp, IP, port, and supported services. The timestamp is rounded to
// single second precision.
func NewNetAddressTimestamp(
timestamp time.Time, services protocol.ServiceFlag, ip net.IP, port uint16) *NetAddress {
// Limit the timestamp to one second precision since the protocol
// doesn't support better.
na := NetAddress{
Timestamp: time.Unix(timestamp.Unix(), 0),
Services: services,
IP: ip,
Port: port,
}
return &na
}
// NewNetAddress returns a new NetAddress using the provided TCP address and
// supported services with defaults for the remaining fields.
//
// Note that addr must be a net.TCPAddr. An ErrInvalidNetAddr is returned
// if it is not.
func NewNetAddress(addr net.Addr, services protocol.ServiceFlag) (*NetAddress, error) {
tcpAddr, ok := addr.(*net.TCPAddr)
if !ok {
return nil, ErrInvalidNetAddr
}
na := NewNetAddressIPPort(tcpAddr.IP, uint16(tcpAddr.Port), services)
return na, nil
}
// NewNetAddressFailBack add more attempts to extract the IP address and port from the passed
// net.Addr interface and create a NetAddress structure using that information.
func NewNetAddressFailBack(addr net.Addr, services protocol.ServiceFlag) (*NetAddress, error) {
// addr will be a net.TCPAddr when not using a proxy.
if tcpAddr, ok := addr.(*net.TCPAddr); ok {
ip := tcpAddr.IP
port := uint16(tcpAddr.Port)
na := NewNetAddressIPPort(ip, port, services)
return na, nil
}
// addr will be a socks.ProxiedAddr when using a proxy.
if proxiedAddr, ok := addr.(*network.ProxiedAddr); ok {
ip := net.ParseIP(proxiedAddr.Host)
if ip == nil {
ip = net.ParseIP("0.0.0.0")
}
port := uint16(proxiedAddr.Port)
na := NewNetAddressIPPort(ip, port, services)
return na, nil
}
// For the most part, addr should be one of the two above cases, but
// to be safe, fall back to trying to parse the information from the
// address string as a last resort.
host, portStr, err := net.SplitHostPort(addr.String())
if err != nil {
return nil, err
}
ip := net.ParseIP(host)
port, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
return nil, err
}
na := NewNetAddressIPPort(ip, uint16(port), services)
return na, nil
}
// readNetAddress reads an encoded NetAddress from r depending on the protocol
// version and whether or not the timestamp is included per ts. Some messages
// like version do not include the timestamp.
func ReadNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error {
var ip [16]byte
// TODO fix time ambiguous
// NOTE: The protocol uses a uint32 for the timestamp so it will
// stop working somewhere around 2106. Also timestamp wasn't added until
// protocol version >= NetAddressTimeVersion
if ts {
err := s.ReadElements(r, (*s.Uint32Time)(&na.Timestamp))
if err != nil {
return err
}
}
err := s.ReadElements(r, &na.Services, &ip)
if err != nil {
return err
}
// TODO unify endian
// Sigh. protocol mixes little and big endian.
port, err := s.BinarySerializer.Uint16(r, binary.BigEndian)
if err != nil {
return err
}
*na = NetAddress{
Timestamp: na.Timestamp,
Services: na.Services,
IP: net.IP(ip[:]),
Port: port,
}
return nil
}
// writeNetAddress serializes a NetAddress to w depending on the protocol
// version and whether or not the timestamp is included per ts. Some messages
// like version do not include the timestamp.
func WriteNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error {
// TODO fix time ambiguous
// NOTE: The protocol uses a uint32 for the timestamp so it will
// stop working somewhere around 2106. Also timestamp wasn't added until
// until protocol version >= NetAddressTimeVersion.
if ts {
err := s.WriteElements(w, uint32(na.Timestamp.Unix()))
if err != nil {
return err
}
}
// Ensure to always write 16 bytes even if the ip is nil.
var ip [16]byte
if na.IP != nil {
copy(ip[:], na.IP.To16())
}
err := s.WriteElements(w, na.Services, ip)
if err != nil {
return err
}
// TODO unify endian
// Sigh. protocol mixes little and big endian.
return binary.Write(w, binary.BigEndian, na.Port)
}