github.com/core-coin/go-core/v2@v2.1.9/p2p/discover/v4wire/v4wire.go (about) 1 // Copyright 2020 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 v4wire implements the Discovery v4 Wire Protocol. 18 package v4wire 19 20 import ( 21 "bytes" 22 "errors" 23 "fmt" 24 "net" 25 "time" 26 27 "github.com/core-coin/go-core/v2/crypto" 28 "github.com/core-coin/go-core/v2/p2p/enode" 29 "github.com/core-coin/go-core/v2/p2p/enr" 30 "github.com/core-coin/go-core/v2/rlp" 31 ) 32 33 // RPC packet types 34 const ( 35 PingPacket = iota + 1 // zero is 'reserved' 36 PongPacket 37 FindnodePacket 38 NeighborsPacket 39 ENRRequestPacket 40 ENRResponsePacket 41 ) 42 43 // RPC request structures 44 type ( 45 Ping struct { 46 Version uint 47 From, To Endpoint 48 Expiration uint64 49 // Ignore additional fields (for forward compatibility). 50 Rest []rlp.RawValue `rlp:"tail"` 51 } 52 53 // Pong is the reply to ping. 54 Pong struct { 55 // This field should mirror the UDP envelope address 56 // of the ping packet, which provides a way to discover the 57 // the external address (after NAT). 58 To Endpoint 59 ReplyTok []byte // This contains the hash of the ping packet. 60 Expiration uint64 // Absolute timestamp at which the packet becomes invalid. 61 // Ignore additional fields (for forward compatibility). 62 Rest []rlp.RawValue `rlp:"tail"` 63 } 64 65 // Findnode is a query for nodes close to the given target. 66 Findnode struct { 67 Target Pubkey 68 Expiration uint64 69 // Ignore additional fields (for forward compatibility). 70 Rest []rlp.RawValue `rlp:"tail"` 71 } 72 73 // Neighbors is the reply to findnode. 74 Neighbors struct { 75 Nodes []Node 76 Expiration uint64 77 // Ignore additional fields (for forward compatibility). 78 Rest []rlp.RawValue `rlp:"tail"` 79 } 80 81 // enrRequest queries for the remote node's record. 82 ENRRequest struct { 83 Expiration uint64 84 // Ignore additional fields (for forward compatibility). 85 Rest []rlp.RawValue `rlp:"tail"` 86 } 87 88 // enrResponse is the reply to enrRequest. 89 ENRResponse struct { 90 ReplyTok []byte // Hash of the enrRequest packet. 91 Record enr.Record 92 // Ignore additional fields (for forward compatibility). 93 Rest []rlp.RawValue `rlp:"tail"` 94 } 95 ) 96 97 // This number is the maximum number of neighbor nodes in a Neigbors packet. 98 const MaxNeighbors = 12 99 100 // This code computes the MaxNeighbors constant value. 101 102 // func init() { 103 // var maxNeighbors int 104 // p := Neighbors{Expiration: ^uint64(0)} 105 // maxSizeNode := Node{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)} 106 // for n := 0; ; n++ { 107 // p.Nodes = append(p.Nodes, maxSizeNode) 108 // size, _, err := rlp.EncodeToReader(p) 109 // if err != nil { 110 // // If this ever happens, it will be caught by the unit tests. 111 // panic("cannot encode: " + err.Error()) 112 // } 113 // if headSize+size+1 >= 1280 { 114 // maxNeighbors = n 115 // break 116 // } 117 // } 118 // fmt.Println("maxNeighbors", maxNeighbors) 119 // } 120 121 // Pubkey represents an encoded 57-byte ed448 public key. 122 type Pubkey [57]byte 123 124 // ID returns the node ID corresponding to the public key. 125 func (e Pubkey) ID() enode.ID { 126 return enode.ID(crypto.SHA3Hash(e[:])) 127 } 128 129 // Node represents information about a node. 130 type Node struct { 131 IP net.IP // len 4 for IPv4 or 16 for IPv6 132 UDP uint16 // for discovery protocol 133 TCP uint16 // for RLPx protocol 134 ID Pubkey 135 } 136 137 // Endpoint represents a network endpoint. 138 type Endpoint struct { 139 IP net.IP // len 4 for IPv4 or 16 for IPv6 140 UDP uint16 // for discovery protocol 141 TCP uint16 // for RLPx protocol 142 } 143 144 // NewEndpoint creates an endpoint. 145 func NewEndpoint(addr *net.UDPAddr, tcpPort uint16) Endpoint { 146 ip := net.IP{} 147 if ip4 := addr.IP.To4(); ip4 != nil { 148 ip = ip4 149 } else if ip6 := addr.IP.To16(); ip6 != nil { 150 ip = ip6 151 } 152 return Endpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort} 153 } 154 155 type Packet interface { 156 // packet name and type for logging purposes. 157 Name() string 158 Kind() byte 159 } 160 161 func (req *Ping) Name() string { return "PING/v4" } 162 func (req *Ping) Kind() byte { return PingPacket } 163 func (req *Ping) ENRSeq() uint64 { return seqFromTail(req.Rest) } 164 165 func (req *Pong) Name() string { return "PONG/v4" } 166 func (req *Pong) Kind() byte { return PongPacket } 167 func (req *Pong) ENRSeq() uint64 { return seqFromTail(req.Rest) } 168 169 func (req *Findnode) Name() string { return "FINDNODE/v4" } 170 func (req *Findnode) Kind() byte { return FindnodePacket } 171 172 func (req *Neighbors) Name() string { return "NEIGHBORS/v4" } 173 func (req *Neighbors) Kind() byte { return NeighborsPacket } 174 175 func (req *ENRRequest) Name() string { return "ENRREQUEST/v4" } 176 func (req *ENRRequest) Kind() byte { return ENRRequestPacket } 177 178 func (req *ENRResponse) Name() string { return "ENRRESPONSE/v4" } 179 func (req *ENRResponse) Kind() byte { return ENRResponsePacket } 180 181 // Expired checks whether the given UNIX time stamp is in the past. 182 func Expired(ts uint64) bool { 183 return time.Unix(int64(ts), 0).Before(time.Now()) 184 } 185 186 func seqFromTail(tail []rlp.RawValue) uint64 { 187 if len(tail) == 0 { 188 return 0 189 } 190 var seq uint64 191 rlp.DecodeBytes(tail[0], &seq) 192 return seq 193 } 194 195 // Encoder/decoder. 196 197 const ( 198 macSize = 32 199 sigSize = crypto.ExtendedSignatureLength 200 headSize = macSize + sigSize // space of packet frame data 201 ) 202 203 var ( 204 ErrPacketTooSmall = errors.New("too small") 205 ErrBadHash = errors.New("bad hash") 206 ErrBadPoint = errors.New("invalid curve point") 207 ) 208 209 var headSpace = make([]byte, headSize) 210 211 // Decode reads a discovery v4 packet. 212 func Decode(input []byte) (Packet, Pubkey, []byte, error) { 213 if len(input) < headSize+1 { 214 return nil, Pubkey{}, nil, ErrPacketTooSmall 215 } 216 hash, sig, sigdata := input[:macSize], input[macSize:headSize], input[headSize:] 217 shouldhash := crypto.SHA3(input[macSize:]) 218 if !bytes.Equal(hash, shouldhash) { 219 return nil, Pubkey{}, nil, ErrBadHash 220 } 221 fromKey, err := recoverNodeKey(crypto.SHA3(input[headSize:]), sig) 222 if err != nil { 223 return nil, fromKey, hash, err 224 } 225 226 var req Packet 227 switch ptype := sigdata[0]; ptype { 228 case PingPacket: 229 req = new(Ping) 230 case PongPacket: 231 req = new(Pong) 232 case FindnodePacket: 233 req = new(Findnode) 234 case NeighborsPacket: 235 req = new(Neighbors) 236 case ENRRequestPacket: 237 req = new(ENRRequest) 238 case ENRResponsePacket: 239 req = new(ENRResponse) 240 default: 241 return nil, fromKey, hash, fmt.Errorf("unknown type: %d", ptype) 242 } 243 s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0) 244 err = s.Decode(req) 245 return req, fromKey, hash, err 246 } 247 248 // Encode encodes a discovery packet. 249 func Encode(priv *crypto.PrivateKey, req Packet) (packet, hash []byte, err error) { 250 b := new(bytes.Buffer) 251 b.Write(headSpace) 252 b.WriteByte(req.Kind()) 253 if err := rlp.Encode(b, req); err != nil { 254 return nil, nil, err 255 } 256 packet = b.Bytes() 257 sig, err := crypto.Sign(crypto.SHA3(packet[headSize:]), priv) 258 if err != nil { 259 return nil, nil, err 260 } 261 copy(packet[macSize:], sig) 262 // Add the hash to the front. Note: this doesn't protect the packet in any way. 263 hash = crypto.SHA3(packet[macSize:]) 264 copy(packet, hash) 265 return packet, hash, nil 266 } 267 268 // recoverNodeKey computes the public key used to sign the given hash from the signature. 269 func recoverNodeKey(hash, sig []byte) (key Pubkey, err error) { 270 pubkey, err := crypto.Ecrecover(hash, sig) 271 if err != nil { 272 return key, err 273 } 274 copy(key[:], pubkey[:]) 275 return key, nil 276 } 277 278 // EncodePubkey encodes a ed448 public key. 279 func EncodePubkey(key *crypto.PublicKey) Pubkey { 280 var e Pubkey 281 copy(e[:], key[:]) 282 return e 283 } 284 285 // DecodePubkey reads an encoded ed448 public key. 286 func DecodePubkey(e Pubkey) *crypto.PublicKey { 287 var key crypto.PublicKey 288 copy(key[:], e[:]) 289 return &key 290 }