mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-16 18:37:51 +01:00
* added upload status * added changes for progress bar with more logs and bug fixes, Documentation yet to be added * huge changes that need more doucmenting * added possibility to get profile using NodeID * added fix profile listing user profile information * removed profile image from the explore reult struct * saving current changes * added filter to search based on NodeID * Monday bug fixing * updates to the profile * changes for tracing the blockchain profile image not shown * added condition to ensure TAG is not sent and removed debug prints * updated webapi docs
182 lines
5.8 KiB
Go
182 lines
5.8 KiB
Go
/*
|
|
File Username: Network IPv4 Broadcast.go
|
|
Copyright: 2021 Peernet s.r.o.
|
|
Author: Peter Kleissner
|
|
|
|
IPv4 Multicast just sucks (can't use socket bound to 0.0.0.0:PortMain and send to 224.0.0.1:PortMulticast), so we rely on Broadcast instead.
|
|
*/
|
|
|
|
package core
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"errors"
|
|
"net"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/PeernetOfficial/core/btcec"
|
|
"github.com/PeernetOfficial/core/protocol"
|
|
"github.com/PeernetOfficial/core/reuseport"
|
|
)
|
|
|
|
const ipv4BroadcastPort = 12912
|
|
|
|
// special Public-Private Key pair for local discovery
|
|
var ipv4BroadcastPrivateKey *btcec.PrivateKey
|
|
var ipv4BroadcastPublicKey *btcec.PublicKey
|
|
|
|
const ipv4BroadcastPrivateKeyH = "5e27ecc8e54a24e71dca9ba84a9bf465400e27b8c46a977d34962d3d88558c8e"
|
|
|
|
func initBroadcastIPv4() {
|
|
if configPK, err := hex.DecodeString(ipv4BroadcastPrivateKeyH); err == nil {
|
|
ipv4BroadcastPrivateKey, ipv4BroadcastPublicKey = btcec.PrivKeyFromBytes(btcec.S256(), configPK)
|
|
}
|
|
}
|
|
|
|
// BroadcastIPv4 prepares sending Broadcasts
|
|
func (network *Network) BroadcastIPv4() (err error) {
|
|
if ipv4BroadcastPrivateKey == nil || ipv4BroadcastPublicKey == nil {
|
|
return
|
|
}
|
|
|
|
// listen on a special socket
|
|
network.broadcastSocket, err = reuseport.ListenPacket("udp4", net.JoinHostPort(network.address.IP.String(), strconv.Itoa(ipv4BroadcastPort)))
|
|
if err != nil {
|
|
network.backend.LogError("BroadcastIPv4", "broadcast socket listen on IP '%s' port '%d': %v\n", network.address.IP.String(), ipv4BroadcastPort, err)
|
|
return err
|
|
}
|
|
|
|
network.broadcastIPv4 = networkToIPv4BroadcastIPs(network.ipnet)
|
|
|
|
go network.BroadcastIPv4Listen()
|
|
|
|
return nil
|
|
}
|
|
|
|
// BroadcastIPv4Listen listens for incoming broadcast packets
|
|
// Fork from network.Listen! Keep any changes synced.
|
|
func (network *Network) BroadcastIPv4Listen() {
|
|
for {
|
|
// Buffer: Must be created for each packet as it is passed as pointer.
|
|
// If the buffer is too small, ReadFromUDP only reads until its length and returns this error: "wsarecvfrom: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself."
|
|
buffer := make([]byte, maxPacketSize)
|
|
length, sender, err := network.broadcastSocket.ReadFrom(buffer)
|
|
|
|
if err != nil {
|
|
network.backend.LogError("BroadcastIPv4Listen", "receiving UDP message: %v\n", err) // Only log for debug purposes.
|
|
time.Sleep(time.Millisecond * 50) // In case of endless errors, prevent ddos of CPU.
|
|
continue
|
|
}
|
|
|
|
if network.networkGroup.ipListen.IsAddressSelf(sender.(*net.UDPAddr)) {
|
|
continue
|
|
}
|
|
|
|
// For good network practice (and reducing amount of parallel connections), do not allow link-local to talk to non-link-local addresses.
|
|
if sender.(*net.UDPAddr).IP.IsLinkLocalUnicast() != network.address.IP.IsLinkLocalUnicast() {
|
|
continue
|
|
}
|
|
|
|
//fmt.Printf("BroadcastIPv4Listen from %s at network %s\n", sender.String(), network.address.String())
|
|
|
|
if length < protocol.PacketLengthMin {
|
|
// Discard packets that do not meet the minimum length.
|
|
continue
|
|
}
|
|
|
|
// send the packet to a channel which is processed by multiple workers.
|
|
network.networkGroup.rawPacketsIncoming <- networkWire{network: network, sender: sender.(*net.UDPAddr), raw: buffer[:length], receiverPublicKey: ipv4BroadcastPublicKey, unicast: false}
|
|
}
|
|
}
|
|
|
|
// BroadcastIPv4Send sends out a single broadcast messages to discover peers
|
|
func (network *Network) BroadcastIPv4Send() (err error) {
|
|
_, blockchainHeight, blockchainVersion := network.backend.UserBlockchain.Header()
|
|
packets := protocol.EncodeAnnouncement(true, true, nil, nil, nil, network.backend.FeatureSupport(), blockchainHeight, blockchainVersion, network.backend.userAgent)
|
|
if len(packets) == 0 {
|
|
return errors.New("error encoding broadcast announcement")
|
|
}
|
|
|
|
raw, err := protocol.PacketEncrypt(network.backend.PeerPrivateKey, ipv4BroadcastPublicKey, &protocol.PacketRaw{Protocol: protocol.ProtocolVersion, Command: protocol.CommandLocalDiscovery, Payload: packets[0]})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// send out the wire
|
|
for _, ip := range network.broadcastIPv4 {
|
|
err = network.send(ip, ipv4BroadcastPort, raw)
|
|
if err != nil {
|
|
network.backend.LogError("BroadcastIPv4Send", "sending UDP packet: %v\n", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// networkToIPv4BroadcastIPs generates the IPv4 addresses to send out the broadcast to
|
|
func networkToIPv4BroadcastIPs(ipnet *net.IPNet) (broadcastIPs []net.IP) {
|
|
broadcastIPs = append(broadcastIPs, net.IPv4bcast)
|
|
|
|
if ipnet != nil {
|
|
if ip2 := ipv4DirectedBroadcast(ipnet); ip2 != nil {
|
|
broadcastIPs = append(broadcastIPs, ip2)
|
|
}
|
|
} else {
|
|
interfaceList, err := net.Interfaces()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, iface := range interfaceList {
|
|
addresses, err := iface.Addrs()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
for _, address := range addresses {
|
|
net1 := address.(*net.IPNet)
|
|
|
|
// TODO: Does the rfc3927Net make sense?
|
|
if !IsIPv4(net1.IP) || rfc3927Net.Contains(net1.IP) {
|
|
continue
|
|
}
|
|
|
|
if ip2 := ipv4DirectedBroadcast(net1); ip2 != nil {
|
|
broadcastIPs = append(broadcastIPs, ip2)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Result could contain duplicates, filter them out
|
|
|
|
return broadcastIPs
|
|
}
|
|
|
|
func ipv4DirectedBroadcast(n *net.IPNet) net.IP {
|
|
ip4 := n.IP.To4()
|
|
if ip4 == nil {
|
|
return nil
|
|
}
|
|
last := make(net.IP, len(ip4))
|
|
copy(last, ip4)
|
|
for i := range ip4 {
|
|
last[i] |= ^n.Mask[i]
|
|
}
|
|
return last
|
|
}
|
|
|
|
var (
|
|
// rfc3927Net specifies the IPv4 auto configuration address block as
|
|
// defined by RFC3927 (169.254.0.0/16).
|
|
rfc3927Net = ipNet("169.254.0.0", 16, 32)
|
|
)
|
|
|
|
// ipNet returns a net.IPNet struct given the passed IP address string, number
|
|
// of one bits to include at the start of the mask, and the total number of bits
|
|
// for the mask.
|
|
func ipNet(ip string, ones, bits int) net.IPNet {
|
|
return net.IPNet{IP: net.ParseIP(ip), Mask: net.CIDRMask(ones, bits)}
|
|
}
|