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