mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-18 11:17:49 +01:00
Start refactoring protocol code into sub package. Move Packet Encoding and list of Commands. Change SetSelfReportedPorts parameters.
More related commits to follow!
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/PeernetOfficial/core/blockchain"
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
)
|
||||
|
||||
// UserBlockchain is the user's blockchain and exports functions to directly read and write it
|
||||
@@ -21,7 +22,7 @@ const filenameUserBlockchain = "self.blockchain"
|
||||
// initUserBlockchain initializes the users blockchain. It creates the blockchain file if it does not exist already.
|
||||
// If it is corrupted, it will log the error and exit the process.
|
||||
func initUserBlockchain() {
|
||||
blockchain.HashFunction = hashData
|
||||
blockchain.HashFunction = protocol.HashData
|
||||
blockchain.PublicKey2NodeID = PublicKey2NodeID
|
||||
|
||||
var err error
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
@@ -210,7 +211,7 @@ func contactArbitraryPeer(publicKey *btcec.PublicKey, address *net.UDPAddr, rece
|
||||
if len(packets) == 0 || packets[0].err != nil {
|
||||
return false
|
||||
}
|
||||
raw := &PacketRaw{Command: CommandAnnouncement, Payload: packets[0].raw}
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandAnnouncement, Payload: packets[0].raw}
|
||||
|
||||
Filters.MessageOutAnnouncement(publicKey, nil, raw, findSelf, nil, nil, nil)
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ package core
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
)
|
||||
|
||||
// cmdTraverseForward handles an incoming traverse message that should be forwarded to another peer
|
||||
@@ -45,7 +47,7 @@ func (peer *PeerInfo) cmdTraverseForward(msg *MessageTraverse) {
|
||||
return
|
||||
}
|
||||
|
||||
peerTarget.send(&PacketRaw{Command: CommandTraverse, Payload: msg.Payload})
|
||||
peerTarget.send(&protocol.PacketRaw{Command: protocol.CommandTraverse, Payload: msg.Payload})
|
||||
}
|
||||
|
||||
func (peer *PeerInfo) cmdTraverseReceive(msg *MessageTraverse) {
|
||||
@@ -82,7 +84,7 @@ func (peer *PeerInfo) cmdTraverseReceive(msg *MessageTraverse) {
|
||||
|
||||
// ---- fork packetWorker to decode and validate embedded packet ---
|
||||
// Due to missing connection and other embedded details in the message (such as ports), the packet is not just simply queued to rawPacketsIncoming.
|
||||
decoded, senderPublicKey, err := PacketDecrypt(msg.EmbeddedPacketRaw, peerPublicKey)
|
||||
decoded, senderPublicKey, err := protocol.PacketDecrypt(msg.EmbeddedPacketRaw, peerPublicKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -92,7 +94,7 @@ func (peer *PeerInfo) cmdTraverseReceive(msg *MessageTraverse) {
|
||||
return
|
||||
} else if decoded.Protocol != 0 {
|
||||
return
|
||||
} else if decoded.Command != CommandAnnouncement {
|
||||
} else if decoded.Command != protocol.CommandAnnouncement {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -102,7 +104,7 @@ func (peer *PeerInfo) cmdTraverseReceive(msg *MessageTraverse) {
|
||||
|
||||
// process it!
|
||||
switch decoded.Command {
|
||||
case CommandAnnouncement: // Announce
|
||||
case protocol.CommandAnnouncement: // Announce
|
||||
if announce, _ := msgDecodeAnnouncement(raw); announce != nil {
|
||||
if len(announce.UserAgent) > 0 {
|
||||
peerV.UserAgent = announce.UserAgent
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/PeernetOfficial/core/dht"
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
)
|
||||
|
||||
// respondClosesContactsCount is the number of closest contact to respond.
|
||||
@@ -198,7 +199,7 @@ func (peer *PeerInfo) cmdPing(msg *MessageRaw) {
|
||||
return
|
||||
}
|
||||
|
||||
raw := &PacketRaw{Command: CommandPong, Sequence: msg.Sequence}
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandPong, Sequence: msg.Sequence}
|
||||
|
||||
Filters.MessageOutPong(peer, raw)
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
@@ -319,17 +320,17 @@ func (peer *PeerInfo) IsPortForward() (result bool) {
|
||||
// ---- sending code ----
|
||||
|
||||
// send sends the packet to the peer on the connection
|
||||
func (c *Connection) send(packet *PacketRaw, receiverPublicKey *btcec.PublicKey, isFirstPacket bool) (err error) {
|
||||
func (c *Connection) send(packet *protocol.PacketRaw, receiverPublicKey *btcec.PublicKey, isFirstPacket bool) (err error) {
|
||||
if c == nil {
|
||||
return errors.New("invalid connection")
|
||||
}
|
||||
|
||||
packet.Protocol = ProtocolVersion
|
||||
packet.setSelfReportedPorts(c.Network)
|
||||
packet.SetSelfReportedPorts(c.Network.SelfReportedPorts())
|
||||
|
||||
Filters.PacketOut(packet, receiverPublicKey, c)
|
||||
|
||||
raw, err := PacketEncrypt(peerPrivateKey, receiverPublicKey, packet)
|
||||
raw, err := protocol.PacketEncrypt(peerPrivateKey, receiverPublicKey, packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -339,7 +340,7 @@ func (c *Connection) send(packet *PacketRaw, receiverPublicKey *btcec.PublicKey,
|
||||
err = c.Network.send(c.Address.IP, c.Address.Port, raw)
|
||||
|
||||
// Send Traverse message if the peer is behind a NAT and this is the first message. Only for Announcement.
|
||||
if err == nil && isFirstPacket && c.IsBehindNAT() && c.traversePeer != nil && packet.Command == CommandAnnouncement {
|
||||
if err == nil && isFirstPacket && c.IsBehindNAT() && c.traversePeer != nil && packet.Command == protocol.CommandAnnouncement {
|
||||
c.traversePeer.sendTraverse(packet, receiverPublicKey)
|
||||
}
|
||||
|
||||
@@ -347,7 +348,7 @@ func (c *Connection) send(packet *PacketRaw, receiverPublicKey *btcec.PublicKey,
|
||||
}
|
||||
|
||||
// send sends a raw packet to the peer. Only uses active connections.
|
||||
func (peer *PeerInfo) send(packet *PacketRaw) (err error) {
|
||||
func (peer *PeerInfo) send(packet *protocol.PacketRaw) (err error) {
|
||||
if peer.isVirtual { // special case for peers that were not contacted before
|
||||
for _, address := range peer.targetAddresses {
|
||||
sendAllNetworks(peer.PublicKey, packet, &net.UDPAddr{IP: address.IP, Port: int(address.Port)}, address.PortInternal, peer.traversePeer, nil)
|
||||
@@ -397,7 +398,7 @@ func (peer *PeerInfo) send(packet *PacketRaw) (err error) {
|
||||
}
|
||||
|
||||
// sendConnection sends a packet to the peer using the specific connection
|
||||
func (peer *PeerInfo) sendConnection(packet *PacketRaw, connection *Connection) (err error) {
|
||||
func (peer *PeerInfo) sendConnection(packet *protocol.PacketRaw, connection *Connection) (err error) {
|
||||
isFirstPacketOut := atomic.LoadUint64(&peer.StatsPacketSent) == 0 && atomic.LoadUint64(&peer.StatsPacketReceived) == 0
|
||||
atomic.AddUint64(&peer.StatsPacketSent, 1)
|
||||
|
||||
@@ -406,7 +407,7 @@ func (peer *PeerInfo) sendConnection(packet *PacketRaw, connection *Connection)
|
||||
|
||||
// sendAllNetworks sends a raw packet via all networks. It assigns a new sequence for each sent packet.
|
||||
// receiverPortInternal is important for NAT detection and sending the traverse message.
|
||||
func sendAllNetworks(receiverPublicKey *btcec.PublicKey, packet *PacketRaw, remote *net.UDPAddr, receiverPortInternal uint16, traversePeer *PeerInfo, sequenceData interface{}) (err error) {
|
||||
func sendAllNetworks(receiverPublicKey *btcec.PublicKey, packet *protocol.PacketRaw, remote *net.UDPAddr, receiverPortInternal uint16, traversePeer *PeerInfo, sequenceData interface{}) (err error) {
|
||||
networksMutex.RLock()
|
||||
defer networksMutex.RUnlock()
|
||||
|
||||
|
||||
30
Filter.go
30
Filter.go
@@ -12,6 +12,7 @@ import (
|
||||
"log"
|
||||
|
||||
"github.com/PeernetOfficial/core/dht"
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
@@ -37,30 +38,30 @@ var Filters struct {
|
||||
|
||||
// PacketIn is a low-level filter for incoming packets after they are decrypted.
|
||||
// Traverse messages are not covered.
|
||||
PacketIn func(packet *PacketRaw, senderPublicKey *btcec.PublicKey, connection *Connection)
|
||||
PacketIn func(packet *protocol.PacketRaw, senderPublicKey *btcec.PublicKey, connection *Connection)
|
||||
|
||||
// PacketOut is a low-level filter for outgoing packets before they are encrypted.
|
||||
// IPv4 broadcast, IPv6 multicast, and Traverse messages are not covered.
|
||||
PacketOut func(packet *PacketRaw, receiverPublicKey *btcec.PublicKey, connection *Connection)
|
||||
PacketOut func(packet *protocol.PacketRaw, receiverPublicKey *btcec.PublicKey, connection *Connection)
|
||||
|
||||
// MessageIn is a high-level filter for decoded incoming messages. message is of type nil, MessageAnnouncement, MessageResponse, or MessageTraverse
|
||||
MessageIn func(peer *PeerInfo, raw *MessageRaw, message interface{})
|
||||
|
||||
// MessageOutAnnouncement is a high-level filter for outgoing announcements. Peer is nil on first contact.
|
||||
// Broadcast and Multicast messages are not covered.
|
||||
MessageOutAnnouncement func(receiverPublicKey *btcec.PublicKey, peer *PeerInfo, packet *PacketRaw, findSelf bool, findPeer []KeyHash, findValue []KeyHash, files []InfoStore)
|
||||
MessageOutAnnouncement func(receiverPublicKey *btcec.PublicKey, peer *PeerInfo, packet *protocol.PacketRaw, findSelf bool, findPeer []KeyHash, findValue []KeyHash, files []InfoStore)
|
||||
|
||||
// MessageOutResponse is a high-level filter for outgoing responses.
|
||||
MessageOutResponse func(peer *PeerInfo, packet *PacketRaw, hash2Peers []Hash2Peer, filesEmbed []EmbeddedFileData, hashesNotFound [][]byte)
|
||||
MessageOutResponse func(peer *PeerInfo, packet *protocol.PacketRaw, hash2Peers []Hash2Peer, filesEmbed []EmbeddedFileData, hashesNotFound [][]byte)
|
||||
|
||||
// MessageOutTraverse is a high-level filter for outgoing traverse messages.
|
||||
MessageOutTraverse func(peer *PeerInfo, packet *PacketRaw, embeddedPacket *PacketRaw, receiverEnd *btcec.PublicKey)
|
||||
MessageOutTraverse func(peer *PeerInfo, packet *protocol.PacketRaw, embeddedPacket *protocol.PacketRaw, receiverEnd *btcec.PublicKey)
|
||||
|
||||
// MessageOutPing is a high-level filter for outgoing pings.
|
||||
MessageOutPing func(peer *PeerInfo, packet *PacketRaw, connection *Connection)
|
||||
MessageOutPing func(peer *PeerInfo, packet *protocol.PacketRaw, connection *Connection)
|
||||
|
||||
// MessageOutPong is a high-level filter for outgoing pongs.
|
||||
MessageOutPong func(peer *PeerInfo, packet *PacketRaw)
|
||||
MessageOutPong func(peer *PeerInfo, packet *protocol.PacketRaw)
|
||||
}
|
||||
|
||||
func initFilters() {
|
||||
@@ -83,30 +84,31 @@ func initFilters() {
|
||||
Filters.IncomingRequest = func(peer *PeerInfo, Action int, Key []byte, Info interface{}) {}
|
||||
}
|
||||
if Filters.PacketIn == nil {
|
||||
Filters.PacketIn = func(packet *PacketRaw, senderPublicKey *btcec.PublicKey, c *Connection) {}
|
||||
Filters.PacketIn = func(packet *protocol.PacketRaw, senderPublicKey *btcec.PublicKey, c *Connection) {}
|
||||
}
|
||||
if Filters.PacketOut == nil {
|
||||
Filters.PacketOut = func(packet *PacketRaw, receiverPublicKey *btcec.PublicKey, c *Connection) {}
|
||||
Filters.PacketOut = func(packet *protocol.PacketRaw, receiverPublicKey *btcec.PublicKey, c *Connection) {}
|
||||
}
|
||||
if Filters.MessageIn == nil {
|
||||
Filters.MessageIn = func(peer *PeerInfo, raw *MessageRaw, message interface{}) {}
|
||||
}
|
||||
if Filters.MessageOutAnnouncement == nil {
|
||||
Filters.MessageOutAnnouncement = func(receiverPublicKey *btcec.PublicKey, peer *PeerInfo, packet *PacketRaw, findSelf bool, findPeer []KeyHash, findValue []KeyHash, files []InfoStore) {
|
||||
Filters.MessageOutAnnouncement = func(receiverPublicKey *btcec.PublicKey, peer *PeerInfo, packet *protocol.PacketRaw, findSelf bool, findPeer []KeyHash, findValue []KeyHash, files []InfoStore) {
|
||||
}
|
||||
}
|
||||
if Filters.MessageOutResponse == nil {
|
||||
Filters.MessageOutResponse = func(peer *PeerInfo, packet *PacketRaw, hash2Peers []Hash2Peer, filesEmbed []EmbeddedFileData, hashesNotFound [][]byte) {
|
||||
Filters.MessageOutResponse = func(peer *PeerInfo, packet *protocol.PacketRaw, hash2Peers []Hash2Peer, filesEmbed []EmbeddedFileData, hashesNotFound [][]byte) {
|
||||
}
|
||||
}
|
||||
if Filters.MessageOutTraverse == nil {
|
||||
Filters.MessageOutTraverse = func(peer *PeerInfo, packet *PacketRaw, embeddedPacket *PacketRaw, receiverEnd *btcec.PublicKey) {}
|
||||
Filters.MessageOutTraverse = func(peer *PeerInfo, packet *protocol.PacketRaw, embeddedPacket *protocol.PacketRaw, receiverEnd *btcec.PublicKey) {
|
||||
}
|
||||
}
|
||||
if Filters.MessageOutPing == nil {
|
||||
Filters.MessageOutPing = func(peer *PeerInfo, packet *PacketRaw, connection *Connection) {}
|
||||
Filters.MessageOutPing = func(peer *PeerInfo, packet *protocol.PacketRaw, connection *Connection) {}
|
||||
}
|
||||
if Filters.MessageOutPong == nil {
|
||||
Filters.MessageOutPong = func(peer *PeerInfo, packet *PacketRaw) {}
|
||||
Filters.MessageOutPong = func(peer *PeerInfo, packet *protocol.PacketRaw) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core/dht"
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
)
|
||||
|
||||
const alpha = 5 // Count of nodes to be contacted in parallel for finding a key
|
||||
@@ -127,7 +128,7 @@ func (peer *PeerInfo) sendAnnouncementStore(fileHash []byte, fileSize uint64) {
|
||||
|
||||
// Data2Hash returns the hash for the data
|
||||
func Data2Hash(data []byte) (hash []byte) {
|
||||
return hashData(data)
|
||||
return protocol.HashData(data)
|
||||
}
|
||||
|
||||
// GetData returns the requested data. It checks first the local store and then tries via DHT.
|
||||
@@ -152,14 +153,14 @@ func GetDataDHT(hash []byte) (data []byte, senderNodeID []byte, found bool) {
|
||||
|
||||
// StoreDataLocal stores data into the local warehouse.
|
||||
func StoreDataLocal(data []byte) error {
|
||||
key := hashData(data)
|
||||
key := protocol.HashData(data)
|
||||
return Warehouse.Set(key, data)
|
||||
}
|
||||
|
||||
// StoreDataDHT stores data locally and informs closestCount peers in the DHT about it.
|
||||
// Remote peers may choose to keep a record (in case another peers asks) or mirror the full data.
|
||||
func StoreDataDHT(data []byte, closestCount int) error {
|
||||
key := hashData(data)
|
||||
key := protocol.HashData(data)
|
||||
if err := Warehouse.Set(key, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
@@ -25,25 +26,6 @@ const ProtocolVersion = 0
|
||||
// UserAgent should be set by the caller
|
||||
var UserAgent = "Peernet Core/0.1"
|
||||
|
||||
// Commands between peers
|
||||
const (
|
||||
// Peer List Management
|
||||
CommandAnnouncement = 0 // Announcement
|
||||
CommandResponse = 1 // Response
|
||||
CommandPing = 2 // Keep-alive message (no payload).
|
||||
CommandPong = 3 // Response to ping (no payload).
|
||||
CommandLocalDiscovery = 4 // Local discovery
|
||||
CommandTraverse = 5 // Help establish a connection between 2 remote peers
|
||||
|
||||
// Blockchain
|
||||
CommandGet = 6 // Request blocks for specified peer.
|
||||
|
||||
// File Discovery
|
||||
|
||||
// Debug
|
||||
CommandChat = 10 // Chat message [debug]
|
||||
)
|
||||
|
||||
// Actions between peers, sent via Announcement message. They correspond to the bit array index.
|
||||
const (
|
||||
ActionFindSelf = 0 // FIND_SELF Request closest neighbors to self
|
||||
@@ -65,7 +47,7 @@ const (
|
||||
|
||||
// MessageRaw is a high-level message between peers that has not been decoded
|
||||
type MessageRaw struct {
|
||||
PacketRaw
|
||||
protocol.PacketRaw
|
||||
SenderPublicKey *btcec.PublicKey // Sender Public Key, ECDSA (secp256k1) 257-bit
|
||||
connection *Connection // Connection that received the packet
|
||||
sequence *sequenceExpiry // Sequence
|
||||
@@ -478,7 +460,7 @@ func decodeEmbeddedFile(data []byte, count int) (filesEmbed []EmbeddedFileData,
|
||||
index += sizeField
|
||||
|
||||
// validate the hash
|
||||
if !bytes.Equal(hash, hashData(fileData)) {
|
||||
if !bytes.Equal(hash, protocol.HashData(fileData)) {
|
||||
return nil, read, false
|
||||
}
|
||||
|
||||
@@ -494,7 +476,7 @@ const udpMaxPacketSize = 65507
|
||||
|
||||
// isPacketSizeExceed checks if the max packet size would be exceeded with the payload
|
||||
func isPacketSizeExceed(currentSize int, testSize int) bool {
|
||||
return currentSize+testSize > udpMaxPacketSize-packetLengthMin
|
||||
return currentSize+testSize > udpMaxPacketSize-protocol.PacketLengthMin
|
||||
}
|
||||
|
||||
func FeatureSupport() (feature byte) {
|
||||
@@ -656,7 +638,7 @@ createPacketLoop:
|
||||
}
|
||||
|
||||
// EmbeddedFileSizeMax is the maximum size of embedded files in response messages. Any file exceeding that must be shared via regular file transfer.
|
||||
const EmbeddedFileSizeMax = udpMaxPacketSize - packetLengthMin - announcementPayloadHeaderSize - 2 - 35
|
||||
const EmbeddedFileSizeMax = udpMaxPacketSize - protocol.PacketLengthMin - announcementPayloadHeaderSize - 2 - 35
|
||||
|
||||
// msgEncodeResponse encodes a response message
|
||||
// hash2Peers will be modified.
|
||||
@@ -826,19 +808,6 @@ func encodePeerRecord(raw []byte, peer *PeerRecord, reason uint8) {
|
||||
binary.LittleEndian.PutUint16(raw[63:63+2], peer.IPv6PortReportedExternal)
|
||||
}
|
||||
|
||||
// setSelfReportedPorts sets the fields Internal Port and External Port according to the connection details.
|
||||
// This is important for the remote peer to make smart decisions whether this peer is behind a NAT/firewall and supports port forwarding/UPnP.
|
||||
func (packet *PacketRaw) setSelfReportedPorts(n *Network) {
|
||||
if packet.Command != CommandAnnouncement && packet.Command != CommandResponse { // only for Announcement and Response messages
|
||||
return
|
||||
}
|
||||
|
||||
portI, portE := n.SelfReportedPorts()
|
||||
|
||||
binary.LittleEndian.PutUint16(packet.Payload[15:17], portI)
|
||||
binary.LittleEndian.PutUint16(packet.Payload[17:19], portE)
|
||||
}
|
||||
|
||||
// ---- Traverse ----
|
||||
|
||||
const traversePayloadHeaderSize = 76 + 65 + 28
|
||||
@@ -882,7 +851,7 @@ func msgDecodeTraverse(msg *MessageRaw) (result *MessageTraverse, err error) {
|
||||
|
||||
signature := msg.Payload[76+sizePacketEmbed : 76+sizePacketEmbed+65]
|
||||
|
||||
result.SignerPublicKey, _, err = btcec.RecoverCompact(btcec.S256(), signature, hashData(msg.Payload[:76+sizePacketEmbed]))
|
||||
result.SignerPublicKey, _, err = btcec.RecoverCompact(btcec.S256(), signature, protocol.HashData(msg.Payload[:76+sizePacketEmbed]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -932,7 +901,7 @@ func msgEncodeTraverse(senderPrivateKey *btcec.PrivateKey, embeddedPacketRaw []b
|
||||
copy(raw[76:76+sizePacketEmbed], embeddedPacketRaw)
|
||||
|
||||
// add signature
|
||||
signature, err := btcec.SignCompact(btcec.S256(), senderPrivateKey, hashData(raw[:76+sizePacketEmbed]), true)
|
||||
signature, err := btcec.SignCompact(btcec.S256(), senderPrivateKey, protocol.HashData(raw[:76+sizePacketEmbed]), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -978,7 +947,7 @@ func msgEncodeTraverseSetAddress(raw []byte, connectionIPv4, connectionIPv6 *Con
|
||||
|
||||
// pingConnection sends a ping to the target peer via the specified connection
|
||||
func (peer *PeerInfo) pingConnection(connection *Connection) {
|
||||
raw := &PacketRaw{Command: CommandPing, Sequence: peer.msgNewSequence(nil).sequence}
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandPing, Sequence: peer.msgNewSequence(nil).sequence}
|
||||
Filters.MessageOutPing(peer, raw, connection)
|
||||
|
||||
err := peer.sendConnection(raw, connection)
|
||||
@@ -991,7 +960,7 @@ func (peer *PeerInfo) pingConnection(connection *Connection) {
|
||||
|
||||
// Chat sends a text message
|
||||
func (peer *PeerInfo) Chat(text string) {
|
||||
peer.send(&PacketRaw{Command: CommandChat, Payload: []byte(text)})
|
||||
peer.send(&protocol.PacketRaw{Command: protocol.CommandChat, Payload: []byte(text)})
|
||||
}
|
||||
|
||||
// sendAnnouncement sends the announcement message. It acquires a new sequence for each message.
|
||||
@@ -1000,7 +969,7 @@ func (peer *PeerInfo) sendAnnouncement(sendUA, findSelf bool, findPeer []KeyHash
|
||||
|
||||
for _, packet := range packets {
|
||||
packet.sequence = peer.msgNewSequence(sequenceData)
|
||||
raw := &PacketRaw{Command: CommandAnnouncement, Payload: packet.raw, Sequence: packet.sequence.sequence}
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandAnnouncement, Payload: packet.raw, Sequence: packet.sequence.sequence}
|
||||
Filters.MessageOutAnnouncement(peer.PublicKey, peer, raw, findSelf, findPeer, findValue, files)
|
||||
packet.err = peer.send(raw)
|
||||
}
|
||||
@@ -1013,7 +982,7 @@ func (peer *PeerInfo) sendResponse(sequence uint32, sendUA bool, hash2Peers []Ha
|
||||
packets, err := msgEncodeResponse(sendUA, hash2Peers, filesEmbed, hashesNotFound)
|
||||
|
||||
for _, packet := range packets {
|
||||
raw := &PacketRaw{Command: CommandResponse, Payload: packet, Sequence: sequence}
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandResponse, Payload: packet, Sequence: sequence}
|
||||
Filters.MessageOutResponse(peer, raw, hash2Peers, filesEmbed, hashesNotFound)
|
||||
peer.send(raw)
|
||||
}
|
||||
@@ -1022,12 +991,12 @@ func (peer *PeerInfo) sendResponse(sequence uint32, sendUA bool, hash2Peers []Ha
|
||||
}
|
||||
|
||||
// sendTraverse sends a traverse message
|
||||
func (peer *PeerInfo) sendTraverse(packet *PacketRaw, receiverEnd *btcec.PublicKey) (err error) {
|
||||
func (peer *PeerInfo) sendTraverse(packet *protocol.PacketRaw, receiverEnd *btcec.PublicKey) (err error) {
|
||||
packet.Protocol = ProtocolVersion
|
||||
// self-reported ports are not set, as this isn't sent via a specific network but a relay
|
||||
//packet.setSelfReportedPorts(c.Network)
|
||||
//packet.SetSelfReportedPorts(c.Network.SelfReportedPorts())
|
||||
|
||||
embeddedPacketRaw, err := PacketEncrypt(peerPrivateKey, receiverEnd, packet)
|
||||
embeddedPacketRaw, err := protocol.PacketEncrypt(peerPrivateKey, receiverEnd, packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1037,7 +1006,7 @@ func (peer *PeerInfo) sendTraverse(packet *PacketRaw, receiverEnd *btcec.PublicK
|
||||
return err
|
||||
}
|
||||
|
||||
raw := &PacketRaw{Command: CommandTraverse, Payload: packetRaw}
|
||||
raw := &protocol.PacketRaw{Command: protocol.CommandTraverse, Payload: packetRaw}
|
||||
|
||||
Filters.MessageOutTraverse(peer, raw, packet, receiverEnd)
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
@@ -97,7 +98,7 @@ func msgArbitrarySequence(publicKey *btcec.PublicKey, data interface{}) (info *s
|
||||
// msgValidateSequence validates the sequence number of an incoming message. It will set raw.sequence if valid.
|
||||
func msgValidateSequence(raw *MessageRaw, invalidate bool) (valid bool, rtt time.Duration) {
|
||||
// Only Response and Pong
|
||||
if raw.Command != CommandResponse && raw.Command != CommandPong {
|
||||
if raw.Command != protocol.CommandResponse && raw.Command != protocol.CommandPong {
|
||||
return true, rtt
|
||||
}
|
||||
|
||||
@@ -123,7 +124,7 @@ func msgValidateSequence(raw *MessageRaw, invalidate bool) (valid bool, rtt time
|
||||
// invalidate the sequence immediately?
|
||||
if invalidate {
|
||||
delete(sequences, key)
|
||||
} else if raw.Command == CommandResponse {
|
||||
} else if raw.Command == protocol.CommandResponse {
|
||||
// Special case CommandResponse: Extend validity in case there are follow-up responses by half of the round-trip time since they will be sent one-way.
|
||||
sequence.expires = time.Now().Add(time.Duration(ReplyTimeout) * time.Second / 2)
|
||||
}
|
||||
@@ -136,7 +137,7 @@ func msgValidateSequence(raw *MessageRaw, invalidate bool) (valid bool, rtt time
|
||||
// msgInvalidateSequence invalidates the sequence number.
|
||||
func msgInvalidateSequence(raw *MessageRaw) {
|
||||
// Only Response
|
||||
if raw.Command != CommandResponse {
|
||||
if raw.Command != protocol.CommandResponse {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
"github.com/PeernetOfficial/core/reuseport"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
@@ -77,7 +78,7 @@ func (network *Network) BroadcastIPv4Listen() {
|
||||
|
||||
//fmt.Printf("BroadcastIPv4Listen from %s at network %s\n", sender.String(), network.address.String())
|
||||
|
||||
if length < packetLengthMin {
|
||||
if length < protocol.PacketLengthMin {
|
||||
// Discard packets that do not meet the minimum length.
|
||||
continue
|
||||
}
|
||||
@@ -94,7 +95,7 @@ func (network *Network) BroadcastIPv4Send() (err error) {
|
||||
return packets[0].err
|
||||
}
|
||||
|
||||
raw, err := PacketEncrypt(peerPrivateKey, ipv4BroadcastPublicKey, &PacketRaw{Protocol: ProtocolVersion, Command: CommandLocalDiscovery, Payload: packets[0].raw})
|
||||
raw, err := protocol.PacketEncrypt(peerPrivateKey, ipv4BroadcastPublicKey, &protocol.PacketRaw{Protocol: ProtocolVersion, Command: protocol.CommandLocalDiscovery, Payload: packets[0].raw})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
"github.com/PeernetOfficial/core/reuseport"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"golang.org/x/net/ipv6"
|
||||
@@ -123,7 +124,7 @@ func (network *Network) MulticastIPv6Listen() {
|
||||
|
||||
//fmt.Printf("MulticastIPv6Listen from %s at network %s\n", sender.String(), network.address.String())
|
||||
|
||||
if length < packetLengthMin {
|
||||
if length < protocol.PacketLengthMin {
|
||||
// Discard packets that do not meet the minimum length.
|
||||
continue
|
||||
}
|
||||
@@ -140,7 +141,7 @@ func (network *Network) MulticastIPv6Send() (err error) {
|
||||
return packets[0].err
|
||||
}
|
||||
|
||||
raw, err := PacketEncrypt(peerPrivateKey, ipv6MulticastPublicKey, &PacketRaw{Protocol: ProtocolVersion, Command: CommandLocalDiscovery, Payload: packets[0].raw})
|
||||
raw, err := protocol.PacketEncrypt(peerPrivateKey, ipv6MulticastPublicKey, &protocol.PacketRaw{Protocol: ProtocolVersion, Command: protocol.CommandLocalDiscovery, Payload: packets[0].raw})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
19
Network.go
19
Network.go
@@ -13,6 +13,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
"github.com/PeernetOfficial/core/upnp"
|
||||
)
|
||||
|
||||
@@ -131,7 +132,7 @@ func (network *Network) Listen() {
|
||||
continue
|
||||
}
|
||||
|
||||
if length < packetLengthMin {
|
||||
if length < protocol.PacketLengthMin {
|
||||
// Discard packets that do not meet the minimum length.
|
||||
continue
|
||||
}
|
||||
@@ -144,7 +145,7 @@ func (network *Network) Listen() {
|
||||
// packetWorker handles incoming packets.
|
||||
func packetWorker(packets <-chan networkWire) {
|
||||
for packet := range packets {
|
||||
decoded, senderPublicKey, err := PacketDecrypt(packet.raw, packet.receiverPublicKey)
|
||||
decoded, senderPublicKey, err := protocol.PacketDecrypt(packet.raw, packet.receiverPublicKey)
|
||||
if err != nil {
|
||||
//Filters.LogError("packetWorker", "decrypting packet from '%s': %s\n", packet.sender.String(), err.Error()) // Only log for debug purposes.
|
||||
continue
|
||||
@@ -177,7 +178,7 @@ func packetWorker(packets <-chan networkWire) {
|
||||
raw := &MessageRaw{SenderPublicKey: senderPublicKey, PacketRaw: *decoded, connection: connection}
|
||||
|
||||
switch decoded.Command {
|
||||
case CommandAnnouncement: // Announce
|
||||
case protocol.CommandAnnouncement: // Announce
|
||||
if announce, _ := msgDecodeAnnouncement(raw); announce != nil {
|
||||
// Update known internal/external port and User Agent
|
||||
connection.PortInternal = announce.PortInternal
|
||||
@@ -194,7 +195,7 @@ func packetWorker(packets <-chan networkWire) {
|
||||
peer.cmdAnouncement(announce)
|
||||
}
|
||||
|
||||
case CommandResponse: // Response
|
||||
case protocol.CommandResponse: // Response
|
||||
if response, _ := msgDecodeResponse(raw); response != nil {
|
||||
// Validate sequence number which prevents unsolicited responses.
|
||||
if valid, rtt := msgValidateSequence(raw, response.Actions&(1<<ActionSequenceLast) > 0); !valid {
|
||||
@@ -219,7 +220,7 @@ func packetWorker(packets <-chan networkWire) {
|
||||
peer.cmdResponse(response)
|
||||
}
|
||||
|
||||
case CommandLocalDiscovery: // Local discovery, sent via IPv4 broadcast and IPv6 multicast
|
||||
case protocol.CommandLocalDiscovery: // Local discovery, sent via IPv4 broadcast and IPv6 multicast
|
||||
if announce, _ := msgDecodeAnnouncement(raw); announce != nil {
|
||||
if len(announce.UserAgent) > 0 {
|
||||
peer.UserAgent = announce.UserAgent
|
||||
@@ -233,11 +234,11 @@ func packetWorker(packets <-chan networkWire) {
|
||||
peer.cmdLocalDiscovery(announce)
|
||||
}
|
||||
|
||||
case CommandPing: // Ping
|
||||
case protocol.CommandPing: // Ping
|
||||
Filters.MessageIn(peer, raw, nil)
|
||||
peer.cmdPing(raw)
|
||||
|
||||
case CommandPong: // Ping
|
||||
case protocol.CommandPong: // Ping
|
||||
// Validate sequence number which prevents unsolicited responses.
|
||||
if valid, rtt := msgValidateSequence(raw, true); !valid {
|
||||
//Filters.LogError("packetWorker", "message with invalid sequence %d command %d from %s\n", raw.Sequence, raw.Command, raw.connection.Address.String()) // Only log for debug purposes.
|
||||
@@ -250,11 +251,11 @@ func packetWorker(packets <-chan networkWire) {
|
||||
|
||||
peer.cmdPong(raw)
|
||||
|
||||
case CommandChat: // Chat [debug]
|
||||
case protocol.CommandChat: // Chat [debug]
|
||||
Filters.MessageIn(peer, raw, nil)
|
||||
peer.cmdChat(raw)
|
||||
|
||||
case CommandTraverse:
|
||||
case protocol.CommandTraverse:
|
||||
if traverse, _ := msgDecodeTraverse(raw); traverse != nil {
|
||||
Filters.MessageIn(peer, raw, traverse)
|
||||
if traverse.TargetPeer.IsEqual(peerPublicKey) && traverse.AuthorizedRelayPeer.IsEqual(peer.PublicKey) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/PeernetOfficial/core/dht"
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
@@ -198,7 +199,7 @@ func publicKey2Compressed(publicKey *btcec.PublicKey) [btcec.PubKeyBytesLenCompr
|
||||
|
||||
// PublicKey2NodeID translates the Public Key into the node ID used in the Kademlia network.
|
||||
func PublicKey2NodeID(publicKey *btcec.PublicKey) (nodeID []byte) {
|
||||
return hashData(publicKey.SerializeCompressed())
|
||||
return protocol.HashData(publicKey.SerializeCompressed())
|
||||
}
|
||||
|
||||
// records2Nodes translates infoPeer structures to nodes. If the reported nodes are not in the peer table, it will create temporary PeerInfo structures.
|
||||
|
||||
16
Test_test.go
16
Test_test.go
@@ -4,6 +4,8 @@ package core
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/PeernetOfficial/core/protocol"
|
||||
)
|
||||
|
||||
func TestMessageEncodingAnnouncement(t *testing.T) {
|
||||
@@ -14,14 +16,14 @@ func TestMessageEncodingAnnouncement(t *testing.T) {
|
||||
}
|
||||
|
||||
// encode and decode announcement
|
||||
packetR := PacketRaw{Protocol: 0, Command: CommandAnnouncement, Sequence: 123}
|
||||
packetR := protocol.PacketRaw{Protocol: 0, Command: protocol.CommandAnnouncement, Sequence: 123}
|
||||
|
||||
var findPeer []KeyHash
|
||||
var findValue []KeyHash
|
||||
var files []InfoStore
|
||||
|
||||
hash1 := hashData([]byte("test"))
|
||||
hash2 := hashData([]byte("test3"))
|
||||
hash1 := protocol.HashData([]byte("test"))
|
||||
hash2 := protocol.HashData([]byte("test3"))
|
||||
findPeer = append(findPeer, KeyHash{Hash: hash1})
|
||||
findValue = append(findValue, KeyHash{Hash: hash2})
|
||||
|
||||
@@ -47,7 +49,7 @@ func TestMessageEncodingResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
// encode and decode response
|
||||
packetR := PacketRaw{Protocol: 0, Command: CommandResponse}
|
||||
packetR := protocol.PacketRaw{Protocol: 0, Command: protocol.CommandResponse}
|
||||
|
||||
var hash2Peers []Hash2Peer
|
||||
var filesEmbed []EmbeddedFileData
|
||||
@@ -55,12 +57,12 @@ func TestMessageEncodingResponse(t *testing.T) {
|
||||
|
||||
file1Data := []byte("test")
|
||||
file2Data := []byte("test3")
|
||||
file1 := EmbeddedFileData{ID: KeyHash{hashData(file1Data)}, Data: file1Data}
|
||||
file2 := EmbeddedFileData{ID: KeyHash{hashData(file2Data)}, Data: file2Data}
|
||||
file1 := EmbeddedFileData{ID: KeyHash{protocol.HashData(file1Data)}, Data: file1Data}
|
||||
file2 := EmbeddedFileData{ID: KeyHash{protocol.HashData(file2Data)}, Data: file2Data}
|
||||
filesEmbed = append(filesEmbed, file1)
|
||||
filesEmbed = append(filesEmbed, file2)
|
||||
|
||||
hashesNotFound = append(hashesNotFound, hashData([]byte("NA")))
|
||||
hashesNotFound = append(hashesNotFound, protocol.HashData([]byte("NA")))
|
||||
|
||||
packetsRaw, err := msgEncodeResponse(true, hash2Peers, filesEmbed, hashesNotFound)
|
||||
if err != nil {
|
||||
|
||||
27
protocol/Command.go
Normal file
27
protocol/Command.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
File Name: Command.go
|
||||
Copyright: 2021 Peernet s.r.o.
|
||||
Author: Peter Kleissner
|
||||
*/
|
||||
|
||||
package protocol
|
||||
|
||||
// Commands between peers
|
||||
const (
|
||||
// Peer List Management
|
||||
CommandAnnouncement = 0 // Announcement
|
||||
CommandResponse = 1 // Response
|
||||
CommandPing = 2 // Keep-alive message (no payload).
|
||||
CommandPong = 3 // Response to ping (no payload).
|
||||
CommandLocalDiscovery = 4 // Local discovery
|
||||
CommandTraverse = 5 // Help establish a connection between 2 remote peers
|
||||
|
||||
// Blockchain
|
||||
CommandGetBlock = 6 // Request blocks for specified peer.
|
||||
|
||||
// File Discovery
|
||||
CommandTransfer = 8 // File transfer.
|
||||
|
||||
// Debug
|
||||
CommandChat = 10 // Chat message [debug]
|
||||
)
|
||||
18
protocol/Hash.go
Normal file
18
protocol/Hash.go
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
File Name: Hash.go
|
||||
Copyright: 2021 Peernet s.r.o.
|
||||
Author: Peter Kleissner
|
||||
*/
|
||||
|
||||
package protocol
|
||||
|
||||
import "lukechampine.com/blake3"
|
||||
|
||||
// HashData abstracts the hash function.
|
||||
func HashData(data []byte) (hash []byte) {
|
||||
hash32 := blake3.Sum256(data)
|
||||
return hash32[:]
|
||||
}
|
||||
|
||||
// HashSize is blake3 hash digest size = 256 bits
|
||||
const HashSize = 32
|
||||
@@ -19,7 +19,7 @@ The signature is applied on the entire packet, which guarantees that the signatu
|
||||
Because the signature could be a possible fingerpint, it is encrypted itself.
|
||||
*/
|
||||
|
||||
package core
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"golang.org/x/crypto/salsa20"
|
||||
"lukechampine.com/blake3"
|
||||
)
|
||||
|
||||
// PacketRaw is a decrypted P2P message
|
||||
@@ -40,7 +39,7 @@ type PacketRaw struct {
|
||||
}
|
||||
|
||||
// The minimum packet size is 12 bytes (minimum header size) + 65 bytes (signature)
|
||||
const packetLengthMin = 12 + signatureSize
|
||||
const PacketLengthMin = 12 + signatureSize
|
||||
const signatureSize = 65
|
||||
const maxRandomGarbage = 20
|
||||
|
||||
@@ -60,7 +59,7 @@ func PacketDecrypt(raw []byte, receiverPublicKey *btcec.PublicKey) (packet *Pack
|
||||
keySalsa := publicKeyToSalsa20Key(receiverPublicKey)
|
||||
salsa20.XORKeyStream(signature[:], signature[:], nonce, keySalsa)
|
||||
|
||||
senderPublicKey, _, err = btcec.RecoverCompact(btcec.S256(), signature[:], hashData(raw[:len(raw)-signatureSize]))
|
||||
senderPublicKey, _, err = btcec.RecoverCompact(btcec.S256(), signature[:], HashData(raw[:len(raw)-signatureSize]))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -87,8 +86,8 @@ func PacketDecrypt(raw []byte, receiverPublicKey *btcec.PublicKey) (packet *Pack
|
||||
|
||||
// PacketEncrypt encrypts a packet using the provided senders private key and receivers compressed public key.
|
||||
func PacketEncrypt(senderPrivateKey *btcec.PrivateKey, receiverPublicKey *btcec.PublicKey, packet *PacketRaw) (raw []byte, err error) {
|
||||
garbage := packetGarbage(packetLengthMin + len(packet.Payload))
|
||||
raw = make([]byte, packetLengthMin+len(packet.Payload)+len(garbage))
|
||||
garbage := packetGarbage(PacketLengthMin + len(packet.Payload))
|
||||
raw = make([]byte, PacketLengthMin+len(packet.Payload)+len(garbage))
|
||||
|
||||
nonceC := rand.Uint32()
|
||||
nonce := make([]byte, 8)
|
||||
@@ -109,7 +108,7 @@ func PacketEncrypt(senderPrivateKey *btcec.PrivateKey, receiverPublicKey *btcec.
|
||||
salsa20.XORKeyStream(raw[4:12+len(packet.Payload)+len(garbage)], raw[4:12+len(packet.Payload)+len(garbage)], nonce, keySalsa)
|
||||
|
||||
// add signature
|
||||
signature, err := btcec.SignCompact(btcec.S256(), senderPrivateKey, hashData(raw[:len(raw)-signatureSize]), true)
|
||||
signature, err := btcec.SignCompact(btcec.S256(), senderPrivateKey, HashData(raw[:len(raw)-signatureSize]), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -146,11 +145,13 @@ func publicKeyToSalsa20Key(publicKey *btcec.PublicKey) (key *[32]byte) {
|
||||
return key
|
||||
}
|
||||
|
||||
// hashData abstracts the hash function.
|
||||
func hashData(data []byte) (hash []byte) {
|
||||
hash32 := blake3.Sum256(data)
|
||||
return hash32[:]
|
||||
}
|
||||
// SetSelfReportedPorts sets the fields Internal Port and External Port according to the connection details.
|
||||
// This is important for the remote peer to make smart decisions whether this peer is behind a NAT/firewall and supports port forwarding/UPnP.
|
||||
func (packet *PacketRaw) SetSelfReportedPorts(portI, portE uint16) {
|
||||
if packet.Command != CommandAnnouncement && packet.Command != CommandResponse { // only for Announcement and Response messages
|
||||
return
|
||||
}
|
||||
|
||||
// HashSize is blake3 hash digest size = 256 bits
|
||||
const HashSize = 32
|
||||
binary.LittleEndian.PutUint16(packet.Payload[15:17], portI)
|
||||
binary.LittleEndian.PutUint16(packet.Payload[17:19], portE)
|
||||
}
|
||||
3
protocol/readme.md
Normal file
3
protocol/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Protocol
|
||||
|
||||
The Peernet Protocol is defined in the Whitepaper and implemented here accordingly.
|
||||
Reference in New Issue
Block a user