From 00db57aed8e9523a04c2d79a9708bfca3121adf5 Mon Sep 17 00:00:00 2001 From: Kleissner Date: Sun, 18 Apr 2021 21:50:30 +0200 Subject: [PATCH] Provide the new sequence number in responses. New message Local Discovery to be sent instead of Announcement via IPv4 Broadcast and IPv6 Multicast. Detecting IPv6 link-local addresses as local ones. Fixes. --- Commands.go | 30 ++++++++++++++++++++++++++++-- Message Encoding.go | 15 ++++++++------- Network Detection.go | 9 ++++++--- Network IPv4 Broadcast.go | 2 +- Network IPv6 Multicast.go | 2 +- Network.go | 5 +++++ Peer ID.go | 2 +- 7 files changed, 50 insertions(+), 15 deletions(-) diff --git a/Commands.go b/Commands.go index abbde90..7ffb307 100644 --- a/Commands.go +++ b/Commands.go @@ -8,7 +8,9 @@ package core import ( "bytes" + "encoding/hex" "fmt" + "log" "time" "github.com/PeernetOfficial/core/dht" @@ -102,7 +104,7 @@ func (peer *PeerInfo) cmdAnouncement(msg *MessageAnnouncement) { peer.announcementStore(msg.InfoStoreFiles) } - peer.sendResponse(added, hash2Peers, filesEmbed, hashesNotFound) + peer.sendResponse(msg.Sequence, added, hash2Peers, filesEmbed, hashesNotFound) } func (peer *PeerInfo) peer2Record(allowLocal, allowIPv4, allowIPv6 bool) (result *PeerRecord) { @@ -140,7 +142,7 @@ func (peer *PeerInfo) cmdResponse(msg *MessageResponse) { info := nodesDHT.IRLookup(peer.NodeID, hash2Peer.ID.Hash) if info == nil { // Response to FIND_SELF? - if bytes.Equal(info.Key, nodeID) && len(hash2Peer.Closest) > 0 { + if bytes.Equal(hash2Peer.ID.Hash, nodeID) && len(hash2Peer.Closest) > 0 { peer.cmdResponseFindSelf(msg, hash2Peer.Closest) } continue @@ -196,6 +198,30 @@ func (peer *PeerInfo) cmdChat(msg *MessageRaw) { fmt.Printf("Chat from '%s': %s\n", msg.connection.Address.String(), string(msg.PacketRaw.Payload)) } +// cmdLocalDiscovery handles an incoming announcement via local discovery +func (peer *PeerInfo) cmdLocalDiscovery(msg *MessageAnnouncement) { + // only accept local discovery message from private IPs for IPv4 + // IPv6 DHCP routers typically assign public IPv6s and they can join multicast in the local network. + if msg.connection.IsIPv4() && !msg.connection.IsLocal() { + log.Printf("cmdLocalDiscovery message received from non-local IP %s peer ID %s\n", msg.connection.Address.String(), hex.EncodeToString(msg.SenderPublicKey.SerializeCompressed())) + return + } + + var added bool + if peer == nil { + // The added check is required due to potential race condition; initially the client may receive multiple incoming announcement from the same peer via different connections. + if peer, added = PeerlistAdd(msg.SenderPublicKey, msg.connection); !added { + return + } + + fmt.Printf("Incoming initial local discovery from %s\n", msg.connection.Address.String()) + //} else { + // fmt.Printf("Incoming secondary local discovery from %s\n", msg.connection.Address.String()) + } + + peer.sendAnnouncement(true, true, nil, nil, nil) +} + // pingTime is the time in seconds to send out ping messages const pingTime = 10 diff --git a/Message Encoding.go b/Message Encoding.go index 535fb14..0f3889e 100644 --- a/Message Encoding.go +++ b/Message Encoding.go @@ -28,13 +28,14 @@ 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). + CommandAnnouncement = 0 // Announcement + CommandResponse = 1 // Response + CommandPing = 2 // Keep-alive message (no payload). + CommandPong = 3 // Response to ping (no payload). + CommandLocalDiscovery = 4 // Local discovery // Blockchain - CommandGet = 4 // Request blocks for specified peer. + CommandGet = 6 // Request blocks for specified peer. // File Discovery @@ -762,11 +763,11 @@ func (peer *PeerInfo) sendAnnouncement(sendUA, findSelf bool, findPeer []KeyHash } // sendResponse sends the response message -func (peer *PeerInfo) sendResponse(sendUA bool, hash2Peers []Hash2Peer, filesEmbed []EmbeddedFileData, hashesNotFound [][]byte) (err error) { +func (peer *PeerInfo) sendResponse(sequence uint32, sendUA bool, hash2Peers []Hash2Peer, filesEmbed []EmbeddedFileData, hashesNotFound [][]byte) (err error) { packets, err := msgEncodeResponse(sendUA, hash2Peers, filesEmbed, hashesNotFound) for _, packet := range packets { - peer.send(&PacketRaw{Command: CommandResponse, Payload: packet}) + peer.send(&PacketRaw{Command: CommandResponse, Payload: packet, Sequence: sequence}) } return err diff --git a/Network Detection.go b/Network Detection.go index 589858e..36a37ae 100644 --- a/Network Detection.go +++ b/Network Detection.go @@ -249,13 +249,16 @@ func networkChangeIPRemove(iface net.Interface, address net.Addr) { } } -// IsIPLocal reports whether ip is a private (local) address. [forked function] +// IsIPLocal reports whether ip is a private (local) address. // The identification of private, or local, unicast addresses uses address type -// indentification as defined in RFC 1918 for ip4 and RFC 4193 for ip6 with the exception of ip4 directed broadcast addresses. +// indentification as defined in RFC 1918 for ip4 and RFC 4193 (fc00::/7) for ip6 with the exception of ip4 directed broadcast addresses. // Unassigned, reserved, multicast and limited-broadcast addresses are not handled and will return false. +// IPv6 link-local addresses (fe80::/10) are included in this check. func IsIPLocal(ip net.IP) bool { if ip4 := ip.To4(); ip4 != nil { return ip4[0] == 10 || (ip4[0] == 172 && ip4[1]&0xf0 == 16) || (ip4[0] == 192 && ip4[1] == 168) } - return len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc + return len(ip) == net.IPv6len && + (ip[0]&0xfe == 0xfc || // fc00::/7 + (ip[0] == 0xfe && ip[1]&0xC0 == 0x80)) // fe80::/10 } diff --git a/Network IPv4 Broadcast.go b/Network IPv4 Broadcast.go index 74673a6..838cafa 100644 --- a/Network IPv4 Broadcast.go +++ b/Network IPv4 Broadcast.go @@ -95,7 +95,7 @@ func (network *Network) BroadcastIPv4Send() (err error) { return err } - raw, err := PacketEncrypt(peerPrivateKey, ipv4BroadcastPublicKey, &PacketRaw{Protocol: ProtocolVersion, Command: CommandAnnouncement, Payload: packets[0]}) + raw, err := PacketEncrypt(peerPrivateKey, ipv4BroadcastPublicKey, &PacketRaw{Protocol: ProtocolVersion, Command: CommandLocalDiscovery, Payload: packets[0]}) if err != nil { return err } diff --git a/Network IPv6 Multicast.go b/Network IPv6 Multicast.go index 82f837b..538ad2b 100644 --- a/Network IPv6 Multicast.go +++ b/Network IPv6 Multicast.go @@ -141,7 +141,7 @@ func (network *Network) MulticastIPv6Send() (err error) { return err } - raw, err := PacketEncrypt(peerPrivateKey, ipv6MulticastPublicKey, &PacketRaw{Protocol: ProtocolVersion, Command: CommandAnnouncement, Payload: packets[0]}) + raw, err := PacketEncrypt(peerPrivateKey, ipv6MulticastPublicKey, &PacketRaw{Protocol: ProtocolVersion, Command: CommandLocalDiscovery, Payload: packets[0]}) if err != nil { return err } diff --git a/Network.go b/Network.go index d675755..3fa1f7d 100644 --- a/Network.go +++ b/Network.go @@ -166,6 +166,11 @@ func packetWorker(packets <-chan networkWire) { peer.cmdResponse(response) } + case CommandLocalDiscovery: // Local discovery, sent via IPv4 broadcast and IPv6 multicast + if announce, _ := msgDecodeAnnouncement(raw); announce != nil { + peer.cmdLocalDiscovery(announce) + } + case CommandPing: // Ping peer.cmdPing(raw) diff --git a/Peer ID.go b/Peer ID.go index d99bbb4..cd2f289 100644 --- a/Peer ID.go +++ b/Peer ID.go @@ -49,7 +49,7 @@ func initPeerID() { nodeID = publicKey2NodeID(peerPublicKey) // save the newly generated private key into the config - config.PrivateKey = hex.EncodeToString(peerPublicKey.SerializeCompressed()) + config.PrivateKey = hex.EncodeToString(peerPrivateKey.Serialize()) saveConfig() }