mirror of
https://github.com/PeernetOfficial/Cmd.git
synced 2026-07-17 02:47:52 +01:00
357 lines
13 KiB
Go
357 lines
13 KiB
Go
/*
|
|
File Name: Command Debug.go
|
|
Copyright: 2021 Peernet Foundation s.r.o.
|
|
Author: Peter Kleissner
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/PeernetOfficial/core"
|
|
"github.com/PeernetOfficial/core/btcec"
|
|
"github.com/PeernetOfficial/core/dht"
|
|
"github.com/PeernetOfficial/core/protocol"
|
|
)
|
|
|
|
// debugCmdConnect connects to the node ID
|
|
func debugCmdConnect(backend *core.Backend, nodeID []byte, output io.Writer) {
|
|
fmt.Fprintf(output, "---------------- Connect to node %s ----------------\n", hex.EncodeToString(nodeID))
|
|
defer fmt.Fprintf(output, "---------------- done node %s ----------------\n", hex.EncodeToString(nodeID))
|
|
|
|
// in local DHT list?
|
|
_, peer := backend.IsNodeContact(nodeID)
|
|
if peer != nil {
|
|
fmt.Fprintf(output, "* In local routing table: Yes.\n")
|
|
} else {
|
|
fmt.Fprintf(output, "* In local routing table: No. Lookup via DHT. Timeout = 10 seconds.\n")
|
|
|
|
hashMonitorControl(nodeID, 0, output)
|
|
defer hashMonitorControl(nodeID, 1, nil)
|
|
|
|
// Discovery via DHT.
|
|
_, peer, _ = backend.FindNode(nodeID, time.Second*10)
|
|
if peer == nil {
|
|
fmt.Fprintf(output, "* Not found via DHT :(\n")
|
|
return
|
|
}
|
|
|
|
fmt.Fprintf(output, "* Successfully discovered via DHT.\n")
|
|
}
|
|
|
|
fmt.Fprintf(output, "* Peer details:\n")
|
|
fmt.Fprintf(output, " Uncontacted: %t\n", peer.IsVirtual())
|
|
fmt.Fprintf(output, " Root peer: %t\n", peer.IsRootPeer)
|
|
fmt.Fprintf(output, " User Agent: %s\n", peer.UserAgent)
|
|
fmt.Fprintf(output, " Firewall: %t\n", peer.IsFirewallReported())
|
|
|
|
// virtual peer?
|
|
if peer.IsVirtual() {
|
|
fmt.Fprintf(output, "* Peer is virtual and was not contacted before. Sending out ping.\n")
|
|
peer.Ping()
|
|
} else {
|
|
fmt.Fprintf(output, "* Connections:\n")
|
|
fmt.Fprintf(output, "%s", textPeerConnections(peer))
|
|
}
|
|
|
|
// ping via all connections TODO
|
|
//fmt.Fprintf(output, "* Sending ping:\n")
|
|
}
|
|
|
|
// ---- filter for outgoing DHT searches ----
|
|
|
|
// debug output of monitored keys searched in the DHT
|
|
|
|
var monitorKeys map[string]io.Writer = make(map[string]io.Writer)
|
|
var monitorKeysMutex sync.RWMutex
|
|
|
|
// hashMonitorControl adds (0), removes (1), or inverts (2) a hash on the list
|
|
func hashMonitorControl(key []byte, action int, output io.Writer) (added bool) {
|
|
monitorKeysMutex.Lock()
|
|
defer monitorKeysMutex.Unlock()
|
|
|
|
switch action {
|
|
case 0:
|
|
monitorKeys[string(key)] = output
|
|
added = true
|
|
case 1:
|
|
delete(monitorKeys, string(key))
|
|
case 2:
|
|
if _, ok := monitorKeys[string(key)]; !ok {
|
|
monitorKeys[string(key)] = output
|
|
added = true
|
|
} else {
|
|
delete(monitorKeys, string(key))
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func hashIsMonitored(keys ...[]byte) (monitored bool, output io.Writer) {
|
|
monitorKeysMutex.Lock()
|
|
defer monitorKeysMutex.Unlock()
|
|
|
|
for _, key := range keys {
|
|
if output, monitored = monitorKeys[string(key)]; monitored {
|
|
return true, output
|
|
}
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
const keyMonitorAllSearches = "all searches" // special key to monitor all searches
|
|
|
|
func filterSearchStatus(client *dht.SearchClient, function, format string, v ...interface{}) {
|
|
monitored, output := hashIsMonitored(client.Key, []byte(keyMonitorAllSearches))
|
|
if !monitored {
|
|
return
|
|
}
|
|
|
|
keyA := client.Key
|
|
if len(keyA) > 8 {
|
|
keyA = keyA[:8]
|
|
}
|
|
|
|
intend := " ->"
|
|
|
|
switch function {
|
|
case "search.sendInfoRequest":
|
|
intend = " >"
|
|
case "dht.FindNode", "dht.Get", "dht.Store":
|
|
intend = " -"
|
|
case "search.startSearch":
|
|
intend = " >"
|
|
}
|
|
|
|
fmt.Fprintf(output, intend+" "+function+" ["+hex.EncodeToString(keyA)+"] "+format, v...)
|
|
}
|
|
|
|
// ---- filter for incoming information requests ----
|
|
|
|
const keyMonitorAllRequests = "all requests" // special key to monitor all info requests
|
|
|
|
func filterIncomingRequest(peer *core.PeerInfo, Action int, Key []byte, Info interface{}) {
|
|
monitored, output := hashIsMonitored(peer.NodeID, []byte(keyMonitorAllRequests))
|
|
if !monitored {
|
|
return
|
|
}
|
|
|
|
requestType := "UNKNOWN"
|
|
switch Action {
|
|
case protocol.ActionFindSelf:
|
|
requestType = "FIND_SELF"
|
|
case protocol.ActionFindPeer:
|
|
requestType = "FIND_PEER"
|
|
case protocol.ActionFindValue:
|
|
requestType = "FIND_VALUE"
|
|
case protocol.ActionInfoStore:
|
|
requestType = "INFO_STORE"
|
|
}
|
|
|
|
if Action == protocol.ActionFindSelf && bytes.Equal(peer.NodeID, Key) {
|
|
fmt.Fprintf(output, "Info request from %s %s\n", hex.EncodeToString(peer.NodeID), requestType)
|
|
} else {
|
|
fmt.Fprintf(output, "Info request from %s %s for key %s\n", hex.EncodeToString(peer.NodeID), requestType, hex.EncodeToString(Key))
|
|
}
|
|
}
|
|
|
|
// ---- filter for incoming and outgoing packets ----
|
|
|
|
func filterMessageIn(peer *core.PeerInfo, raw *protocol.MessageRaw, message interface{}) {
|
|
monitored, output := hashIsMonitored(peer.NodeID)
|
|
if !monitored {
|
|
// TODO: For Announcement/Response also check data, Traverse the final target
|
|
return
|
|
}
|
|
|
|
commandA := "Unknown"
|
|
|
|
switch raw.Command {
|
|
case protocol.CommandAnnouncement:
|
|
commandA = "Announcement"
|
|
case protocol.CommandResponse:
|
|
commandA = "Response"
|
|
case protocol.CommandPing:
|
|
commandA = "Ping"
|
|
case protocol.CommandPong:
|
|
commandA = "Pong"
|
|
case protocol.CommandLocalDiscovery:
|
|
commandA = "Local Discovery"
|
|
case protocol.CommandTraverse:
|
|
commandA = "Traverse"
|
|
case protocol.CommandChat:
|
|
commandA = "Chat"
|
|
}
|
|
|
|
text := fmt.Sprintf("-------- Node %s Incoming %s --------\n", hex.EncodeToString(peer.NodeID), commandA)
|
|
text += fmt.Sprintf("Sender Peer ID: %s\n", hex.EncodeToString(peer.PublicKey.SerializeCompressed()))
|
|
|
|
if !raw.SenderPublicKey.IsEqual(peer.PublicKey) {
|
|
text += fmt.Sprintf("WARNING: Mismatch of public keys, sender %s and packet indicates %s\n", hex.EncodeToString(peer.PublicKey.SerializeCompressed()), hex.EncodeToString(raw.SenderPublicKey.SerializeCompressed()))
|
|
}
|
|
|
|
if message == nil {
|
|
text += "(no message decoded)\n"
|
|
} else if announce, ok := message.(*protocol.MessageAnnouncement); ok {
|
|
text += fmt.Sprintf("Fields:\n Protocol supported %d\n", announce.Protocol)
|
|
text += fmt.Sprintf(" Feature bits %d\n", announce.Features)
|
|
text += fmt.Sprintf(" Action bits %d\n", announce.Actions)
|
|
text += fmt.Sprintf(" Blockchain Height %d\n", announce.BlockchainHeight)
|
|
text += fmt.Sprintf(" Blockchain Version %d\n", announce.BlockchainVersion)
|
|
text += fmt.Sprintf(" Port Internal %d\n", announce.PortInternal)
|
|
text += fmt.Sprintf(" Port External %d\n", announce.PortExternal)
|
|
text += fmt.Sprintf(" User Agent %s\n", announce.UserAgent)
|
|
|
|
if len(announce.FindPeerKeys) > 0 {
|
|
text += fmt.Sprintf("FIND_PEER %d records:\n", len(announce.FindPeerKeys))
|
|
}
|
|
for _, find := range announce.FindPeerKeys {
|
|
text += fmt.Sprintf(" - Find peer %s\n", hex.EncodeToString(find.Hash))
|
|
}
|
|
if len(announce.FindDataKeys) > 0 {
|
|
text += fmt.Sprintf("FIND_VALUE %d records:\n", len(announce.FindDataKeys))
|
|
}
|
|
for _, find := range announce.FindDataKeys {
|
|
text += fmt.Sprintf(" - Find data %s\n", hex.EncodeToString(find.Hash))
|
|
}
|
|
if len(announce.InfoStoreFiles) > 0 {
|
|
text += fmt.Sprintf("INFO_STORE %d records:\n", len(announce.InfoStoreFiles))
|
|
}
|
|
for _, info := range announce.InfoStoreFiles {
|
|
text += fmt.Sprintf(" - Info store %s, type %d, size %d\n", hex.EncodeToString(info.ID.Hash), info.Type, info.Size)
|
|
}
|
|
} else if response, ok := message.(*protocol.MessageResponse); ok {
|
|
text += fmt.Sprintf("Fields:\n Protocol supported %d\n", response.Protocol)
|
|
text += fmt.Sprintf(" Feature bits %d\n", response.Features)
|
|
text += fmt.Sprintf(" Action bits %d\n", response.Actions)
|
|
text += fmt.Sprintf(" Blockchain Height %d\n", response.BlockchainHeight)
|
|
text += fmt.Sprintf(" Blockchain Version %d\n", response.BlockchainVersion)
|
|
text += fmt.Sprintf(" Port Internal %d\n", response.PortInternal)
|
|
text += fmt.Sprintf(" Port External %d\n", response.PortExternal)
|
|
text += fmt.Sprintf(" User Agent %s\n", response.UserAgent)
|
|
|
|
for _, hash := range response.Hash2Peers {
|
|
isLast := ""
|
|
if hash.IsLast {
|
|
isLast = " [last result in sequence]"
|
|
}
|
|
text += fmt.Sprintf(" - Peers known for the hash %s%s\n", hex.EncodeToString(hash.ID.Hash), isLast)
|
|
for n := range hash.Closest {
|
|
text += fmt.Sprintf(" Close peer:\n%s\n", outputPeerRecord(&hash.Closest[n]))
|
|
}
|
|
for n := range hash.Storing {
|
|
text += fmt.Sprintf(" Peer stores:\n%s\n", outputPeerRecord(&hash.Storing[n]))
|
|
}
|
|
}
|
|
for _, find := range response.FilesEmbed {
|
|
text += fmt.Sprintf(" - File embedded %s (%d bytes)\n", hex.EncodeToString(find.ID.Hash), len(find.Data))
|
|
}
|
|
for _, hash := range response.HashesNotFound {
|
|
text += fmt.Sprintf(" - Hash not found %s\n", hex.EncodeToString(hash))
|
|
}
|
|
} else if traverse, ok := message.(*protocol.MessageTraverse); ok {
|
|
text += fmt.Sprintf("Fields:\n Target Peer %s\n", hex.EncodeToString(traverse.TargetPeer.SerializeCompressed()))
|
|
text += fmt.Sprintf(" Authorized Relay Peer %s\n", hex.EncodeToString(traverse.AuthorizedRelayPeer.SerializeCompressed()))
|
|
text += fmt.Sprintf(" Signer Public Key %s\n", hex.EncodeToString(traverse.SignerPublicKey.SerializeCompressed()))
|
|
text += fmt.Sprintf(" Expires %s\n", traverse.Expires.String())
|
|
text += fmt.Sprintf(" IPv4 %s\n", traverse.IPv4.String())
|
|
text += fmt.Sprintf(" Port IPv4 %d\n", traverse.PortIPv4)
|
|
text += fmt.Sprintf(" Port IPv4 Reported External %d\n", traverse.PortIPv4ReportedExternal)
|
|
text += fmt.Sprintf(" IPv6 %s\n", traverse.IPv6.String())
|
|
text += fmt.Sprintf(" Port IPv6 %d\n", traverse.PortIPv6)
|
|
text += fmt.Sprintf(" Port IPv6 Reported External %d\n", traverse.PortIPv6ReportedExternal)
|
|
}
|
|
|
|
text += "--------\n"
|
|
|
|
output.Write([]byte(text))
|
|
}
|
|
|
|
func outputPeerRecord(record *protocol.PeerRecord) (output string) {
|
|
output += fmt.Sprintf(" * Peer ID %s\n", hex.EncodeToString(record.PublicKey.SerializeCompressed()))
|
|
output += fmt.Sprintf(" Node ID %s\n", hex.EncodeToString(record.NodeID))
|
|
if record.IPv4 != nil && !record.IPv4.IsUnspecified() {
|
|
output += fmt.Sprintf(" IPv4 %s\n", record.IPv4.String())
|
|
output += fmt.Sprintf(" Port IPv4 %d\n", record.IPv4Port)
|
|
output += fmt.Sprintf(" Port IPv4 Reported Internal %d\n", record.IPv4PortReportedInternal)
|
|
output += fmt.Sprintf(" Port IPv4 Reported External %d\n", record.IPv4PortReportedExternal)
|
|
}
|
|
if record.IPv6 != nil && !record.IPv6.IsUnspecified() {
|
|
output += fmt.Sprintf(" IPv6 %s\n", record.IPv6.String())
|
|
output += fmt.Sprintf(" Port IPv6 %d\n", record.IPv6Port)
|
|
output += fmt.Sprintf(" Port IPv6 Reported Internal %d\n", record.IPv6PortReportedInternal)
|
|
output += fmt.Sprintf(" Port IPv6 Reported External %d\n", record.IPv6PortReportedExternal)
|
|
}
|
|
output += fmt.Sprintf(" Last Contact %s", record.LastContactT.Format(dateFormat))
|
|
|
|
return
|
|
}
|
|
|
|
func outputOutgoingMessage(peer *core.PeerInfo, packet *protocol.PacketRaw) {
|
|
monitored, output := hashIsMonitored(peer.NodeID)
|
|
if !monitored {
|
|
// TODO: For Announcement/Response also check data, Traverse the final target
|
|
return
|
|
}
|
|
|
|
commandA := "Unknown"
|
|
|
|
switch packet.Command {
|
|
case protocol.CommandAnnouncement:
|
|
commandA = "Announcement"
|
|
case protocol.CommandResponse:
|
|
commandA = "Response"
|
|
case protocol.CommandPing:
|
|
commandA = "Ping"
|
|
case protocol.CommandPong:
|
|
commandA = "Pong"
|
|
case protocol.CommandLocalDiscovery:
|
|
commandA = "Local Discovery"
|
|
case protocol.CommandTraverse:
|
|
commandA = "Traverse"
|
|
case protocol.CommandChat:
|
|
commandA = "Chat"
|
|
}
|
|
|
|
text := fmt.Sprintf("-------- Node %s Outgoing %s --------\n", hex.EncodeToString(peer.NodeID), commandA)
|
|
text += fmt.Sprintf("Receiver Peer ID: %s\n", hex.EncodeToString(peer.PublicKey.SerializeCompressed()))
|
|
|
|
// TODO: Decoding of payload data (done by caller of this function)
|
|
|
|
text += "--------\n"
|
|
|
|
output.Write([]byte(text))
|
|
}
|
|
|
|
func filterMessageOutAnnouncement(receiverPublicKey *btcec.PublicKey, peer *core.PeerInfo, packet *protocol.PacketRaw, findSelf bool, findPeer []protocol.KeyHash, findValue []protocol.KeyHash, files []protocol.InfoStore) {
|
|
if peer == nil {
|
|
peer = &core.PeerInfo{PublicKey: receiverPublicKey, NodeID: protocol.PublicKey2NodeID(receiverPublicKey)}
|
|
}
|
|
|
|
outputOutgoingMessage(peer, packet)
|
|
}
|
|
|
|
func filterMessageOutResponse(peer *core.PeerInfo, packet *protocol.PacketRaw, hash2Peers []protocol.Hash2Peer, filesEmbed []protocol.EmbeddedFileData, hashesNotFound [][]byte) {
|
|
outputOutgoingMessage(peer, packet)
|
|
}
|
|
|
|
func filterMessageOutTraverse(peer *core.PeerInfo, packet *protocol.PacketRaw, embeddedPacket *protocol.PacketRaw, receiverEnd *btcec.PublicKey) {
|
|
outputOutgoingMessage(peer, packet)
|
|
}
|
|
|
|
func filterMessageOutPing(peer *core.PeerInfo, packet *protocol.PacketRaw, connection *core.Connection) {
|
|
outputOutgoingMessage(peer, packet)
|
|
}
|
|
|
|
func filterMessageOutPong(peer *core.PeerInfo, packet *protocol.PacketRaw) {
|
|
outputOutgoingMessage(peer, packet)
|
|
}
|