github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/p2p/discv5/udp.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package discv5 13 14 import ( 15 "bytes" 16 "crypto/ecdsa" 17 "errors" 18 "fmt" 19 "net" 20 "time" 21 22 "github.com/Sberex/go-sberex/common" 23 "github.com/Sberex/go-sberex/crypto" 24 "github.com/Sberex/go-sberex/log" 25 "github.com/Sberex/go-sberex/p2p/nat" 26 "github.com/Sberex/go-sberex/p2p/netutil" 27 "github.com/Sberex/go-sberex/rlp" 28 ) 29 30 const Version = 4 31 32 // Errors 33 var ( 34 errPacketTooSmall = errors.New("too small") 35 errBadPrefix = errors.New("bad prefix") 36 errExpired = errors.New("expired") 37 errUnsolicitedReply = errors.New("unsolicited reply") 38 errUnknownNode = errors.New("unknown node") 39 errTimeout = errors.New("RPC timeout") 40 errClockWarp = errors.New("reply deadline too far in the future") 41 errClosed = errors.New("socket closed") 42 ) 43 44 // Timeouts 45 const ( 46 respTimeout = 500 * time.Millisecond 47 queryDelay = 1000 * time.Millisecond 48 expiration = 20 * time.Second 49 50 ntpFailureThreshold = 32 // Continuous timeouts after which to check NTP 51 ntpWarningCooldown = 10 * time.Minute // Minimum amount of time to pass before repeating NTP warning 52 driftThreshold = 10 * time.Second // Allowed clock drift before warning user 53 ) 54 55 // RPC request structures 56 type ( 57 ping struct { 58 Version uint 59 From, To rpcEndpoint 60 Expiration uint64 61 62 // v5 63 Topics []Topic 64 65 // Ignore additional fields (for forward compatibility). 66 Rest []rlp.RawValue `rlp:"tail"` 67 } 68 69 // pong is the reply to ping. 70 pong struct { 71 // This field should mirror the UDP envelope address 72 // of the ping packet, which provides a way to discover the 73 // the external address (after NAT). 74 To rpcEndpoint 75 76 ReplyTok []byte // This contains the hash of the ping packet. 77 Expiration uint64 // Absolute timestamp at which the packet becomes invalid. 78 79 // v5 80 TopicHash common.Hash 81 TicketSerial uint32 82 WaitPeriods []uint32 83 84 // Ignore additional fields (for forward compatibility). 85 Rest []rlp.RawValue `rlp:"tail"` 86 } 87 88 // findnode is a query for nodes close to the given target. 89 findnode struct { 90 Target NodeID // doesn't need to be an actual public key 91 Expiration uint64 92 // Ignore additional fields (for forward compatibility). 93 Rest []rlp.RawValue `rlp:"tail"` 94 } 95 96 // findnode is a query for nodes close to the given target. 97 findnodeHash struct { 98 Target common.Hash 99 Expiration uint64 100 // Ignore additional fields (for forward compatibility). 101 Rest []rlp.RawValue `rlp:"tail"` 102 } 103 104 // reply to findnode 105 neighbors struct { 106 Nodes []rpcNode 107 Expiration uint64 108 // Ignore additional fields (for forward compatibility). 109 Rest []rlp.RawValue `rlp:"tail"` 110 } 111 112 topicRegister struct { 113 Topics []Topic 114 Idx uint 115 Pong []byte 116 } 117 118 topicQuery struct { 119 Topic Topic 120 Expiration uint64 121 } 122 123 // reply to topicQuery 124 topicNodes struct { 125 Echo common.Hash 126 Nodes []rpcNode 127 } 128 129 rpcNode struct { 130 IP net.IP // len 4 for IPv4 or 16 for IPv6 131 UDP uint16 // for discovery protocol 132 TCP uint16 // for RLPx protocol 133 ID NodeID 134 } 135 136 rpcEndpoint struct { 137 IP net.IP // len 4 for IPv4 or 16 for IPv6 138 UDP uint16 // for discovery protocol 139 TCP uint16 // for RLPx protocol 140 } 141 ) 142 143 var ( 144 versionPrefix = []byte("temporary discovery v5") 145 versionPrefixSize = len(versionPrefix) 146 sigSize = 520 / 8 147 headSize = versionPrefixSize + sigSize // space of packet frame data 148 ) 149 150 // Neighbors replies are sent across multiple packets to 151 // stay below the 1280 byte limit. We compute the maximum number 152 // of entries by stuffing a packet until it grows too large. 153 var maxNeighbors = func() int { 154 p := neighbors{Expiration: ^uint64(0)} 155 maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)} 156 for n := 0; ; n++ { 157 p.Nodes = append(p.Nodes, maxSizeNode) 158 size, _, err := rlp.EncodeToReader(p) 159 if err != nil { 160 // If this ever happens, it will be caught by the unit tests. 161 panic("cannot encode: " + err.Error()) 162 } 163 if headSize+size+1 >= 1280 { 164 return n 165 } 166 } 167 }() 168 169 var maxTopicNodes = func() int { 170 p := topicNodes{} 171 maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)} 172 for n := 0; ; n++ { 173 p.Nodes = append(p.Nodes, maxSizeNode) 174 size, _, err := rlp.EncodeToReader(p) 175 if err != nil { 176 // If this ever happens, it will be caught by the unit tests. 177 panic("cannot encode: " + err.Error()) 178 } 179 if headSize+size+1 >= 1280 { 180 return n 181 } 182 } 183 }() 184 185 func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint { 186 ip := addr.IP.To4() 187 if ip == nil { 188 ip = addr.IP.To16() 189 } 190 return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort} 191 } 192 193 func (e1 rpcEndpoint) equal(e2 rpcEndpoint) bool { 194 return e1.UDP == e2.UDP && e1.TCP == e2.TCP && e1.IP.Equal(e2.IP) 195 } 196 197 func nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) { 198 if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil { 199 return nil, err 200 } 201 n := NewNode(rn.ID, rn.IP, rn.UDP, rn.TCP) 202 err := n.validateComplete() 203 return n, err 204 } 205 206 func nodeToRPC(n *Node) rpcNode { 207 return rpcNode{ID: n.ID, IP: n.IP, UDP: n.UDP, TCP: n.TCP} 208 } 209 210 type ingressPacket struct { 211 remoteID NodeID 212 remoteAddr *net.UDPAddr 213 ev nodeEvent 214 hash []byte 215 data interface{} // one of the RPC structs 216 rawData []byte 217 } 218 219 type conn interface { 220 ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) 221 WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) 222 Close() error 223 LocalAddr() net.Addr 224 } 225 226 // udp implements the RPC protocol. 227 type udp struct { 228 conn conn 229 priv *ecdsa.PrivateKey 230 ourEndpoint rpcEndpoint 231 nat nat.Interface 232 net *Network 233 } 234 235 // ListenUDP returns a new table that listens for UDP packets on laddr. 236 func ListenUDP(priv *ecdsa.PrivateKey, conn conn, realaddr *net.UDPAddr, nodeDBPath string, netrestrict *netutil.Netlist) (*Network, error) { 237 transport, err := listenUDP(priv, conn, realaddr) 238 if err != nil { 239 return nil, err 240 } 241 net, err := newNetwork(transport, priv.PublicKey, nodeDBPath, netrestrict) 242 if err != nil { 243 return nil, err 244 } 245 log.Info("UDP listener up", "net", net.tab.self) 246 transport.net = net 247 go transport.readLoop() 248 return net, nil 249 } 250 251 func listenUDP(priv *ecdsa.PrivateKey, conn conn, realaddr *net.UDPAddr) (*udp, error) { 252 return &udp{conn: conn, priv: priv, ourEndpoint: makeEndpoint(realaddr, uint16(realaddr.Port))}, nil 253 } 254 255 func (t *udp) localAddr() *net.UDPAddr { 256 return t.conn.LocalAddr().(*net.UDPAddr) 257 } 258 259 func (t *udp) Close() { 260 t.conn.Close() 261 } 262 263 func (t *udp) send(remote *Node, ptype nodeEvent, data interface{}) (hash []byte) { 264 hash, _ = t.sendPacket(remote.ID, remote.addr(), byte(ptype), data) 265 return hash 266 } 267 268 func (t *udp) sendPing(remote *Node, toaddr *net.UDPAddr, topics []Topic) (hash []byte) { 269 hash, _ = t.sendPacket(remote.ID, toaddr, byte(pingPacket), ping{ 270 Version: Version, 271 From: t.ourEndpoint, 272 To: makeEndpoint(toaddr, uint16(toaddr.Port)), // TODO: maybe use known TCP port from DB 273 Expiration: uint64(time.Now().Add(expiration).Unix()), 274 Topics: topics, 275 }) 276 return hash 277 } 278 279 func (t *udp) sendFindnode(remote *Node, target NodeID) { 280 t.sendPacket(remote.ID, remote.addr(), byte(findnodePacket), findnode{ 281 Target: target, 282 Expiration: uint64(time.Now().Add(expiration).Unix()), 283 }) 284 } 285 286 func (t *udp) sendNeighbours(remote *Node, results []*Node) { 287 // Send neighbors in chunks with at most maxNeighbors per packet 288 // to stay below the 1280 byte limit. 289 p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} 290 for i, result := range results { 291 p.Nodes = append(p.Nodes, nodeToRPC(result)) 292 if len(p.Nodes) == maxNeighbors || i == len(results)-1 { 293 t.sendPacket(remote.ID, remote.addr(), byte(neighborsPacket), p) 294 p.Nodes = p.Nodes[:0] 295 } 296 } 297 } 298 299 func (t *udp) sendFindnodeHash(remote *Node, target common.Hash) { 300 t.sendPacket(remote.ID, remote.addr(), byte(findnodeHashPacket), findnodeHash{ 301 Target: target, 302 Expiration: uint64(time.Now().Add(expiration).Unix()), 303 }) 304 } 305 306 func (t *udp) sendTopicRegister(remote *Node, topics []Topic, idx int, pong []byte) { 307 t.sendPacket(remote.ID, remote.addr(), byte(topicRegisterPacket), topicRegister{ 308 Topics: topics, 309 Idx: uint(idx), 310 Pong: pong, 311 }) 312 } 313 314 func (t *udp) sendTopicNodes(remote *Node, queryHash common.Hash, nodes []*Node) { 315 p := topicNodes{Echo: queryHash} 316 var sent bool 317 for _, result := range nodes { 318 if result.IP.Equal(t.net.tab.self.IP) || netutil.CheckRelayIP(remote.IP, result.IP) == nil { 319 p.Nodes = append(p.Nodes, nodeToRPC(result)) 320 } 321 if len(p.Nodes) == maxTopicNodes { 322 t.sendPacket(remote.ID, remote.addr(), byte(topicNodesPacket), p) 323 p.Nodes = p.Nodes[:0] 324 sent = true 325 } 326 } 327 if !sent || len(p.Nodes) > 0 { 328 t.sendPacket(remote.ID, remote.addr(), byte(topicNodesPacket), p) 329 } 330 } 331 332 func (t *udp) sendPacket(toid NodeID, toaddr *net.UDPAddr, ptype byte, req interface{}) (hash []byte, err error) { 333 //fmt.Println("sendPacket", nodeEvent(ptype), toaddr.String(), toid.String()) 334 packet, hash, err := encodePacket(t.priv, ptype, req) 335 if err != nil { 336 //fmt.Println(err) 337 return hash, err 338 } 339 log.Trace(fmt.Sprintf(">>> %v to %x@%v", nodeEvent(ptype), toid[:8], toaddr)) 340 if _, err = t.conn.WriteToUDP(packet, toaddr); err != nil { 341 log.Trace(fmt.Sprint("UDP send failed:", err)) 342 } 343 //fmt.Println(err) 344 return hash, err 345 } 346 347 // zeroed padding space for encodePacket. 348 var headSpace = make([]byte, headSize) 349 350 func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (p, hash []byte, err error) { 351 b := new(bytes.Buffer) 352 b.Write(headSpace) 353 b.WriteByte(ptype) 354 if err := rlp.Encode(b, req); err != nil { 355 log.Error(fmt.Sprint("error encoding packet:", err)) 356 return nil, nil, err 357 } 358 packet := b.Bytes() 359 sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv) 360 if err != nil { 361 log.Error(fmt.Sprint("could not sign packet:", err)) 362 return nil, nil, err 363 } 364 copy(packet, versionPrefix) 365 copy(packet[versionPrefixSize:], sig) 366 hash = crypto.Keccak256(packet[versionPrefixSize:]) 367 return packet, hash, nil 368 } 369 370 // readLoop runs in its own goroutine. it injects ingress UDP packets 371 // into the network loop. 372 func (t *udp) readLoop() { 373 defer t.conn.Close() 374 // Discovery packets are defined to be no larger than 1280 bytes. 375 // Packets larger than this size will be cut at the end and treated 376 // as invalid because their hash won't match. 377 buf := make([]byte, 1280) 378 for { 379 nbytes, from, err := t.conn.ReadFromUDP(buf) 380 if netutil.IsTemporaryError(err) { 381 // Ignore temporary read errors. 382 log.Debug(fmt.Sprintf("Temporary read error: %v", err)) 383 continue 384 } else if err != nil { 385 // Shut down the loop for permament errors. 386 log.Debug(fmt.Sprintf("Read error: %v", err)) 387 return 388 } 389 t.handlePacket(from, buf[:nbytes]) 390 } 391 } 392 393 func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error { 394 pkt := ingressPacket{remoteAddr: from} 395 if err := decodePacket(buf, &pkt); err != nil { 396 log.Debug(fmt.Sprintf("Bad packet from %v: %v", from, err)) 397 //fmt.Println("bad packet", err) 398 return err 399 } 400 t.net.reqReadPacket(pkt) 401 return nil 402 } 403 404 func decodePacket(buffer []byte, pkt *ingressPacket) error { 405 if len(buffer) < headSize+1 { 406 return errPacketTooSmall 407 } 408 buf := make([]byte, len(buffer)) 409 copy(buf, buffer) 410 prefix, sig, sigdata := buf[:versionPrefixSize], buf[versionPrefixSize:headSize], buf[headSize:] 411 if !bytes.Equal(prefix, versionPrefix) { 412 return errBadPrefix 413 } 414 fromID, err := recoverNodeID(crypto.Keccak256(buf[headSize:]), sig) 415 if err != nil { 416 return err 417 } 418 pkt.rawData = buf 419 pkt.hash = crypto.Keccak256(buf[versionPrefixSize:]) 420 pkt.remoteID = fromID 421 switch pkt.ev = nodeEvent(sigdata[0]); pkt.ev { 422 case pingPacket: 423 pkt.data = new(ping) 424 case pongPacket: 425 pkt.data = new(pong) 426 case findnodePacket: 427 pkt.data = new(findnode) 428 case neighborsPacket: 429 pkt.data = new(neighbors) 430 case findnodeHashPacket: 431 pkt.data = new(findnodeHash) 432 case topicRegisterPacket: 433 pkt.data = new(topicRegister) 434 case topicQueryPacket: 435 pkt.data = new(topicQuery) 436 case topicNodesPacket: 437 pkt.data = new(topicNodes) 438 default: 439 return fmt.Errorf("unknown packet type: %d", sigdata[0]) 440 } 441 s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0) 442 err = s.Decode(pkt.data) 443 return err 444 }