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