iprd

package
v0.5.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 15, 2026 License: MIT Imports: 32 Imported by: 0

README

iprd

This package serves as the core library for the IP Reporter daemon (iprd). It provides all the necessary tooling to sniff IP Report packets from ASIC miners on a local network.

Documentation

Run go doc -http for more information on what is included.

Example Usage

See cmd/example/starter/main.go for an basic example program.

Documentation

Index

Constants

View Source
const (
	TCPCommandSubscribe = "iprd_subscribe"
	TCPCommandStatus    = "iprd_status"
)
View Source
const (
	// MDNSServiceType is the DNS-SD service type advertised by iprd.
	MDNSServiceType = "_iprd._tcp"
)

Variables

View Source
var (
	// ErrDuplicatePacket indicates that the processor recently handled an IP
	// report from the same source MAC address.
	ErrDuplicatePacket = errors.New("duplicate packet")
)
View Source
var (
	// ErrListenerManagerAlreadyStarted is returned when the listener manager is started more than once.
	ErrListenerManagerAlreadyStarted = errors.New("listener manager may only be run once")
)

Functions

func GetKnownMinerPorts added in v0.5.3

func GetKnownMinerPorts() []int

GetKnownMinerPorts returns a list of known miner UDP destination ports.

func GetMsgPatternFromHint added in v0.5.0

func GetMsgPatternFromHint(hint MinerTypeHint) (*regexp.Regexp, bool)

GetMsgPatternFromHint returns the UDP payload regex pattern for the given MinerTypeHint, if known.

func ParseBPFNetwork added in v0.4.4

func ParseBPFNetwork(network string) string

ParseBPFNetwork returns the parsed BPF network, or an empty string if invalid. network is a BPF IPv4 network number that can be written as a dotted quad (192.168.1.0), dotted triple (192.168.1), dotted pair (192.168) or single number (10).

func ParseIPAddress added in v0.5.3

func ParseIPAddress(address string) string

ParseIPAddress parses address and returns a normalized IP address.

func ParseMACAddress added in v0.3.1

func ParseMACAddress(address string) string

ParseMACAddress parses address and returns a normalized MAC address.

Types

type AuradineIPReport added in v0.5.0

type AuradineIPReport struct {
	Command      string `json:"command"`
	SerialNo     string `json:"SerialNo"`
	IPAddress    string `json:"ip"`
	MACAddress   string `json:"mac"`
	Model        string `json:"model"`
	Version      string `json:"version"`
	Hostname     string `json:"hostname"`
	InternalType string `json:"InternalType"`
}

AuradineIPReport represents the IP report JSON payload from Auradine miners.

type CaptureWriter added in v0.5.0

type CaptureWriter struct {
	// contains filtered or unexported fields
}

CaptureWriter writes interface-tagged packets to a bounded PCAP-NG capture. It is owned by ListenerManager and must be called serially.

func NewCaptureWriter added in v0.5.0

func NewCaptureWriter(path string, rotate bool, logger Logger) *CaptureWriter

NewCaptureWriter returns a PCAP-NG writer. An empty path disables capture.

func (*CaptureWriter) Close added in v0.5.0

func (w *CaptureWriter) Close() error

Close flushes and closes the active capture file.

func (*CaptureWriter) Open added in v0.5.0

func (w *CaptureWriter) Open() error

Open validates and creates the configured capture path. The PCAP-NG section is initialized lazily when the first packet supplies interface metadata.

func (*CaptureWriter) Path added in v0.5.0

func (w *CaptureWriter) Path() string

Path returns the normalized capture path, or an empty string when disabled.

func (*CaptureWriter) Write added in v0.5.0

func (w *CaptureWriter) Write(packet CapturedPacket) error

Write writes and flushes a captured packet, then applies the configured size limit. Flushing keeps byte accounting accurate and capture data durable.

type CapturedPacket added in v0.5.0

type CapturedPacket struct {
	Data        []byte
	CaptureInfo gopacket.CaptureInfo
	LinkType    layers.LinkType
	Interface   IPRInterface
}

CapturedPacket is a raw packet and the interface metadata associated with its capture. The listener emits these events without parsing their contents.

type GoldshellIPReport added in v0.5.0

type GoldshellIPReport struct {
	Version     string          `json:"version"`
	IPAddress   string          `json:"ip"`
	DHCP        string          `json:"dhcp"`
	Model       string          `json:"model"`
	CtrlBoardSN string          `json:"ctrlsn"`
	MACAddress  string          `json:"mac"`
	Netmask     string          `json:"mask"`
	Gateway     string          `json:"gateway"`
	BoardSNs    json.RawMessage `json:"cpbsn"`
	DNS         json.RawMessage `json:"dns"`
	Serial      string          `json:"boxsn"`
	Time        string          `json:"time"`
	LEDStatus   bool            `json:"ledstatus"`
}

GoldshellIPReport represents the IP report JSON payload from Goldshell miners.

type IPRBroadcast

type IPRBroadcast struct {
	Msgs chan []byte
	Errs chan error
	// contains filtered or unexported fields
}

func NewBroadcaster

func NewBroadcaster(logger Logger, bind string, port int) (*IPRBroadcast, error)

NewBroadcaster returns a new IPRBroadcast at specified port. bind is the local IP address to listen on; an empty bind binds all interfaces.

func (*IPRBroadcast) Listen

func (b *IPRBroadcast) Listen()

Listen accepts incoming clients and subscribes them for broadcasted messages.

func (*IPRBroadcast) SetStatusProvider added in v0.5.2

func (b *IPRBroadcast) SetStatusProvider(provider StatusProvider)

SetStatusProvider configures the provider used by the iprd_status command.

type IPRBroadcastMessage

type IPRBroadcastMessage struct {
	Timestamp int64         `json:"timestamp"`
	PacketID  string        `json:"packetID"`
	DstPort   int           `json:"dstPort"`
	SrcIP     string        `json:"srcIP"`
	SrcMAC    string        `json:"srcMAC"`
	MinerHint MinerTypeHint `json:"minerHint"`
}

IPRBroadcastMessage describes the JSON message structure of a IPReportPacket.

func NewIPRBroadcastMessage added in v0.5.0

func NewIPRBroadcastMessage(report *IPReportPacket) (IPRBroadcastMessage, error)

NewIPRBroadcastMessage creates a new IPRBroadcastMessage from an IPReportPacket.

func (IPRBroadcastMessage) Marshal added in v0.5.0

func (m IPRBroadcastMessage) Marshal() ([]byte, error)

Marshal serializes the broadcast message without changing its packet ID.

type IPRInterface

type IPRInterface struct {
	Index        int
	Name         string
	FriendlyName string
	Description  string
	IPv4         net.IP
	HardwareAddr net.HardwareAddr
	Flags        net.Flags
}

IPRInterface describes a network interface supported for IP Report listening.

func FindLANInterface

func FindLANInterface() (*IPRInterface, error)

FindLANInterface returns the first IPRInterface marked as LAN, if any.

func GetInterfaceByIndex added in v0.2.1

func GetInterfaceByIndex(index int) (*IPRInterface, error)

GetInterfaceByIndex returns the IPRInterface matching index.

func GetInterfaceByName

func GetInterfaceByName(name string) (*IPRInterface, error)

GetInterfaceByName returns the IPRInterface matching name.

func GetInterfaces added in v0.2.1

func GetInterfaces() ([]IPRInterface, error)

GetInterfaces returns all available IPRInterfaces that can be listened on. Returns error if no valid interfaces found.

func (*IPRInterface) IPAddr

func (i *IPRInterface) IPAddr() string

IPAddr returns IPv4 as string.

func (*IPRInterface) IsLAN

func (i *IPRInterface) IsLAN() bool

IsLAN returns bool for if IPRInterface is marked as LAN interface.

func (*IPRInterface) IsUp

func (i *IPRInterface) IsUp() bool

IsUp returns bool for if IPRInterface is marked as UP.

func (*IPRInterface) MACAddr

func (i *IPRInterface) MACAddr() string

MACAddr returns HardwareAddr as string.

func (*IPRInterface) NetworkPrefix

func (i *IPRInterface) NetworkPrefix() string

NetworkPrefix returns the network prefix(leading two octets) of IPv4.

func (IPRInterface) String added in v0.2.1

func (i IPRInterface) String() string

String returns IPRInterface as string.

type IPRListener

type IPRListener struct {
	// contains filtered or unexported fields
}

func NewListener

func NewListener(cfg *iprdconfig.ListenerConfig, logger Logger, iface *IPRInterface) *IPRListener

NewListener returns a new IPRListener configured by ListenerConfig. If logger is nil, a new IPRLogger is created. If iface is supplied it is pinned and reused; otherwise the interface is resolved from cfg (and re-resolved on each reconnect).

func (*IPRListener) Activate

func (l *IPRListener) Activate() error

Activate sets a new active pcap handle on iface. This must be called once before Listen().

func (*IPRListener) Listen

func (l *IPRListener) Listen()

Listen starts reading packets from the active handle and sends raw capture events to Packets(). It blocks until the handle errors. For a resilient, self-reconnecting listener use Run().

func (*IPRListener) Packets added in v0.5.0

func (l *IPRListener) Packets() <-chan CapturedPacket

Packets returns the listener's stream of raw captured packets.

func (*IPRListener) Run added in v0.4.6

func (l *IPRListener) Run(ctx context.Context) error

Run supervises capture on the interface: it activates a handle, captures until the handle errors (e.g. the interface goes down/away) or ctx is cancelled, and on error re-resolves the interface and re-activates with exponential backoff. It returns when ctx is cancelled. The packet channel and any downstream consumers stay intact across reconnects. Run is the resilient alternative to Activate()+Listen().

type IPRLogger

type IPRLogger struct {
	*log.Logger
}

func NewLogger

func NewLogger() *IPRLogger

NewLogger returns a new IPRLogger to stdout.

func (*IPRLogger) Debug

func (l *IPRLogger) Debug(msg string)

func (*IPRLogger) Error

func (l *IPRLogger) Error(err error)

func (*IPRLogger) Fatal

func (l *IPRLogger) Fatal(err error)

func (*IPRLogger) Info

func (l *IPRLogger) Info(raw string)

func (*IPRLogger) Panic

func (l *IPRLogger) Panic(err error)

func (*IPRLogger) Warn

func (l *IPRLogger) Warn(raw string)

type IPReportPacket

type IPReportPacket struct {
	Timestamp      time.Time
	Length         int
	CaptureLength  int
	InterfaceIndex int
	InterfaceName  string
	SrcIP          string
	DstIP          string
	SrcMAC         string
	DstMAC         string
	SrcPort        int
	DstPort        int
	Datagram       []byte
	Payload        string
	MinerHint      MinerTypeHint
}

IPReportPacket represents a IP Report packet.

func NewIPReportPacket

func NewIPReportPacket(packet gopacket.Packet) (*IPReportPacket, error)

NewIPReportPacket initializes packet into IPReportPacket. Returns an error on failure.

func (*IPReportPacket) Marshal

func (r *IPReportPacket) Marshal() ([]byte, error)

Marshal creates and serializes an IPRBroadcastMessage. Deprecated: call NewIPRBroadcastMessage and marshal the returned message when the generated packet ID must remain stable across multiple serializations.

func (IPReportPacket) String

func (r IPReportPacket) String() string

String returns relevent IPReportPacket info as a string.

type ListenerManager added in v0.5.0

type ListenerManager struct {
	// contains filtered or unexported fields
}

ListenerManager coordinates interface listeners, capture writing, packet processing, and a single combined IP report stream.

func NewListenerManager added in v0.5.0

func NewListenerManager(cfg *iprdconfig.ListenerConfig, logger Logger) (*ListenerManager, error)

NewListenerManager returns a manager with one listener per configured interface. Auto mode creates one listener and ignores explicit selectors.

func (*ListenerManager) Reports added in v0.5.0

func (m *ListenerManager) Reports() <-chan *IPReportPacket

Reports returns the manager's combined stream of validated IP reports. The stream is buffered; if the consumer falls behind and the buffer fills, packet processing applies backpressure until reports are consumed.

func (*ListenerManager) Run added in v0.5.0

func (m *ListenerManager) Run(ctx context.Context) error

Run processes captured packets while supervising every listener. Each listener reconnects independently; an unexpected listener termination stops the manager. Run returns when ctx is cancelled or a fatal error occurs. A manager may only be run once; Reports is closed before the first call returns.

func (*ListenerManager) Status added in v0.5.2

func (m *ListenerManager) Status() ManagerStatus

Status returns a concurrency-safe snapshot of manager health and cumulative packet and listener diagnostics. Calling Status does not reset any counters.

type ListenerState added in v0.5.2

type ListenerState string

ListenerState describes the current lifecycle state of an interface listener.

const (
	ListenerStateIdle         ListenerState = "idle"
	ListenerStateStarting     ListenerState = "starting"
	ListenerStateActive       ListenerState = "active"
	ListenerStateReconnecting ListenerState = "reconnecting"
	ListenerStateStopped      ListenerState = "stopped"
)

type ListenerStatus added in v0.5.2

type ListenerStatus struct {
	Interface          string        `json:"interface"`
	State              ListenerState `json:"state"`
	ActivationFailures uint64        `json:"activationFailures"`
	CaptureErrors      uint64        `json:"captureErrors"`
	Reconnects         uint64        `json:"reconnects"`
	LastError          string        `json:"lastError,omitempty"`
	LastErrorAt        time.Time     `json:"lastErrorAt,omitempty"`
}

ListenerStatus is a concurrency-safe snapshot of one interface listener.

type Logger added in v0.5.0

type Logger interface {
	Debug(msg string)
	Info(msg string)
	Warn(msg string)
	Error(err error)
}

type MDNSAdvertiser added in v0.4.7

type MDNSAdvertiser struct {
	// contains filtered or unexported fields
}

MDNSAdvertiser publishes the iprd TCP endpoint over mDNS/DNS-SD.

func NewMDNSAdvertiser added in v0.4.7

func NewMDNSAdvertiser(bind string, port int, version string) (*MDNSAdvertiser, error)

NewMDNSAdvertiser advertises the iprd TCP endpoint. A wildcard bind is published on all operational multicast-capable interfaces; an explicit bind is limited to the local interface that owns that address.

func (*MDNSAdvertiser) Close added in v0.4.7

func (a *MDNSAdvertiser) Close() error

Close gracefully withdraws the DNS-SD record. It is safe to call more than once.

type ManagerState added in v0.5.2

type ManagerState string

ManagerState describes the current ListenerManager lifecycle state.

const (
	ManagerStateIdle     ManagerState = "idle"
	ManagerStateStarting ManagerState = "starting"
	ManagerStateHealthy  ManagerState = "healthy"
	ManagerStateDegraded ManagerState = "degraded"
	ManagerStateFailed   ManagerState = "failed"
	ManagerStateStopped  ManagerState = "stopped"
)

type ManagerStatus added in v0.5.2

type ManagerStatus struct {
	State               ManagerState     `json:"state"`
	ListenersConfigured int              `json:"listenersConfigured"`
	ListenersActive     int              `json:"listenersActive"`
	ActivationFailures  uint64           `json:"activationFailures"`
	CaptureErrors       uint64           `json:"captureErrors"`
	Reconnects          uint64           `json:"reconnects"`
	CaptureWriteErrors  uint64           `json:"captureWriteErrors"`
	Packets             PacketCounters   `json:"packets"`
	Listeners           []ListenerStatus `json:"listeners"`
	LastPacketAt        time.Time        `json:"lastPacketAt,omitempty"`
	LastReportAt        time.Time        `json:"lastReportAt,omitempty"`
	LastError           string           `json:"lastError,omitempty"`
	LastErrorAt         time.Time        `json:"lastErrorAt,omitempty"`
}

ManagerStatus is a concurrency-safe snapshot of a ListenerManager. Degraded means at least one listener is unavailable while the manager is still retrying; it can therefore have zero active listeners. Failed means Run has terminated with an error.

type MinerTypeHint

type MinerTypeHint string
const (
	UnknownType MinerTypeHint = "unknown"
	Antminer    MinerTypeHint = "antminer"
	Iceriver    MinerTypeHint = "iceriver"
	Whatsminer  MinerTypeHint = "whatsminer"
	Goldshell   MinerTypeHint = "goldshell"
	Sealminer   MinerTypeHint = "sealminer"
	Elphapex    MinerTypeHint = "elphapex"
	Auradine    MinerTypeHint = "auradine"
	IPollo      MinerTypeHint = "ipollo"
	HiveGPU     MinerTypeHint = "hivegpu"
)

func GetMinerHintFromPort added in v0.5.0

func GetMinerHintFromPort(port int) (MinerTypeHint, bool)

GetMinerHintFromPort returns the MinerTypeHint for the given port, if known.

type OfflineHandler added in v0.5.1

type OfflineHandler func(OfflinePacketResult) error

OfflineHandler handles the result of processing one captured frame.

type OfflinePacketResult added in v0.5.1

type OfflinePacketResult struct {
	Timestamp     time.Time
	Number        int64
	InterfaceName string
	Packet        gopacket.Packet
	Report        *IPReportPacket
	Err           error
}

OfflinePacketResult describes the outcome of processing one captured frame. Report is nil when the frame could not be decoded as an IP report packet.

type OfflineResult added in v0.5.1

type OfflineResult struct {
	Processed  int
	Reports    int
	Invalid    int
	Duplicates int
}

OfflineResult summarizes the packets processed from an offline capture.

func ProcessCapture added in v0.5.1

func ProcessCapture(ctx context.Context, reader io.Reader, handler OfflineHandler) (OfflineResult, error)

ProcessCapture reads a classic PCAP or PCAP-NG stream and invokes handler for every captured frame. Packet decoding and duplicate detection use the same PacketProcessor behavior as live capture processing.

func (OfflineResult) String added in v0.5.1

func (r OfflineResult) String() string

String returns a string representation of an offline capture result.

type PacketCounters added in v0.5.2

type PacketCounters struct {
	Processed       uint64 `json:"processed"`
	Reports         uint64 `json:"reports"`
	Invalid         uint64 `json:"invalid"`
	Duplicates      uint64 `json:"duplicates"`
	UnknownFiltered uint64 `json:"unknownFiltered"`
}

PacketCounters contains cumulative packet outcomes for the lifetime of a manager. Reports counts validated reports produced by manager packet processing.

type PacketProcessor added in v0.5.0

type PacketProcessor struct {
	// contains filtered or unexported fields
}

PacketProcessor validates IP report packets and owns their duplicate record. A processor should be shared anywhere duplicate detection must be shared. Calls must be serialized because Record is not safe for concurrent use.

func NewPacketProcessor added in v0.5.0

func NewPacketProcessor(record *Record) *PacketProcessor

NewPacketProcessor returns a processor using record for duplicate detection. A default record is created when record is nil.

func (*PacketProcessor) IsDuplicate added in v0.5.1

func (p *PacketProcessor) IsDuplicate(packet *IPReportPacket) bool

IsDuplicate returns true if the packet is a duplicate based on the processor's record. A packet is considered a duplicate if it has the same source MAC as an existing record entry and is within the record's minimum age. After the record's minimum age (10 seconds), the packet is no longer considered a duplicate and can be reported again.

func (*PacketProcessor) ParseIPReportPacket added in v0.5.0

func (p *PacketProcessor) ParseIPReportPacket(packet *IPReportPacket) error

ParseIPReportPacket analyzes packet for a valid IP report packet. Returns an error if the packet is invalid or a duplicate.

func (*PacketProcessor) ToIPRPacket added in v0.5.1

func (p *PacketProcessor) ToIPRPacket(captured CapturedPacket) (*IPReportPacket, error)

ToIPRPacket decodes a captured packet into an IPReportPacket.

type Record

type Record struct {
	// contains filtered or unexported fields
}

Record is a fixed-size LRU cache of RecordEntry items. Serves as a cache for IP report entries to avoid processing duplicates.

func NewRecord

func NewRecord(capacity int) *Record

NewRecord returns a new Record with maximum size of capacity.

func (*Record) Add

func (r *Record) Add(key string, entry RecordEntry)

Add creates or updates an RecordEntry in Record. Once capacity is reached, entries are removed in FIFO order.

func (*Record) Cap added in v0.1.1

func (r *Record) Cap() int

Cap returns the capacity set on Record

func (*Record) Clear added in v0.1.1

func (r *Record) Clear()

Clear removes all entries in Record and resets order.

func (*Record) Display

func (r *Record) Display()

Display prints the current record entries and length of record to stdout. Useful for logging/debugging.

func (*Record) Get

func (r *Record) Get(key string) (*RecordEntry, bool)

Get returns the RecordEntry for the given key, and a bool indicating if the key was found.

func (*Record) Length

func (r *Record) Length() int

Length returns the current length/size of Record

func (*Record) Remove added in v0.1.1

func (r *Record) Remove(key string) error

Remove deletes entry matching key in Record, if it exists.

type RecordEntry

type RecordEntry struct {
	SrcIP     string
	SrcMAC    string
	MinerHint MinerTypeHint
	CreatedAt int64
	UpdatedAt int64
}

RecordEntry represents an IP report entry in Record

type SealminerIPReport added in v0.5.0

type SealminerIPReport struct {
	Info       sealminerInfo
	Interfaces []sealminerInterface
}

SealminerIPReport represents the IP report JSON payload from Sealminer miners.

func (*SealminerIPReport) UnmarshalJSON added in v0.5.0

func (r *SealminerIPReport) UnmarshalJSON(data []byte) error

type StatusProvider added in v0.5.2

type StatusProvider interface {
	Status() ManagerStatus
}

StatusProvider supplies the current listener manager status.

type TCPCommand

type TCPCommand struct {
	Command   string `json:"command"`
	RequestID string `json:"requestID,omitempty"`
}

TCPCommand describes a TCP command.

type TCPResponse added in v0.5.2

type TCPResponse struct {
	Type      string         `json:"type"`
	RequestID string         `json:"requestID,omitempty"`
	Timestamp int64          `json:"timestamp"`
	Status    *ManagerStatus `json:"status,omitempty"`
	Error     string         `json:"error,omitempty"`
}

TCPResponse is the response envelope for one-shot TCP commands.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL