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