iprd

package
v0.5.1 Latest Latest
Warning

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

Go to latest
Published: Aug 13, 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 (
	// 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 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 ParseMACAddress added in v0.3.1

func ParseMACAddress(address string) string

ParseMACAddress parses address and returns a normalized MAC address.

func WriteIPRDConfigToFile added in v0.2.1

func WriteIPRDConfigToFile(supplied *IPRDConfig, filePath string) error

WriteIPRDConfigToFile write TOML configuration of supplied to filePath

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 FlagInterface added in v0.5.0

type FlagInterface map[string]*InterfaceConfig

FlagInterface is a flag value representing a interface configuration. Each key is an interface selector (e.g. "eth0" or 1), with attached InterfaceConfig representing supplied options. Options are specified after ":" separated by commas (e.g., "eth0:no-root-network,add-network=172.16").

func (FlagInterface) Configs added in v0.5.0

func (f FlagInterface) Configs() []InterfaceConfig

Configs returns the flag values as a deterministic list of interface configurations.

func (FlagInterface) Selectors added in v0.5.0

func (f FlagInterface) Selectors() []string

Selectors returns the configured interface selectors in deterministic order.

func (*FlagInterface) Set added in v0.5.0

func (f *FlagInterface) Set(value string) error

func (*FlagInterface) String added in v0.5.0

func (f *FlagInterface) String() string

type FlagSlice added in v0.5.0

type FlagSlice []string

FlagSlice is a flag value that supports multiple comma-separated values and chaining.

func (*FlagSlice) Set added in v0.5.0

func (f *FlagSlice) Set(value string) error

func (*FlagSlice) String added in v0.5.0

func (f *FlagSlice) String() string

type ForwardConfig added in v0.5.0

type ForwardConfig struct {
	Bind string `toml:"forward_bind" json:"forward_bind"`
	Port int    `toml:"forward_port" json:"forward_port"`
	MDNS bool   `toml:"mdns" json:"mdns"`
}

ForwardConfig describes the daemon's TCP forwarding endpoint and service advertisement.

func DefaultForwardConfig added in v0.5.0

func DefaultForwardConfig() *ForwardConfig

DefaultForwardConfig returns the default daemon forwarding configuration.

func (*ForwardConfig) Merge added in v0.5.0

func (cfg *ForwardConfig) Merge(target *ForwardConfig) *ForwardConfig

Merge returns a new ForwardConfig with non-zero values from target applied.

func (*ForwardConfig) Validate added in v0.5.0

func (cfg *ForwardConfig) Validate() error

Validate returns an error if ForwardConfig contains invalid endpoint values.

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.

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 IPRDConfig added in v0.2.1

type IPRDConfig struct {
	ListenerConfig
	ForwardConfig
}

IPRDConfig combines reusable listener settings with daemon forwarding settings. ListenerConfig is embedded so existing flat TOML and JSON formats are preserved.

func DefaultIPRDConfig added in v0.2.1

func DefaultIPRDConfig() *IPRDConfig

DefaultIPRDConfig returns the default daemon configuration.

func NewIPRDConfigFromBytes added in v0.2.1

func NewIPRDConfigFromBytes(data []byte) (*IPRDConfig, error)

NewIPRDConfigFromBytes unmarshals TOML data into IPRDConfig

func NewIPRDConfigFromFile added in v0.2.1

func NewIPRDConfigFromFile(filePath string) (*IPRDConfig, error)

NewIPRDConfigFromFile reads a TOML configuration file at filePath into IPRDConfig

func ParseConfig added in v0.2.1

func ParseConfig(supplied *IPRDConfig) (*IPRDConfig, error)

ParseConfig applies daemon defaults, normalizes interface selectors, and validates the result.

func (*IPRDConfig) Merge added in v0.2.1

func (cfg *IPRDConfig) Merge(target *IPRDConfig) *IPRDConfig

Merge returns a new IPRDConfig with non-zero values from target applied.

func (*IPRDConfig) Validate added in v0.2.1

func (cfg *IPRDConfig) Validate() error

Validate returns an error if IPRDConfig contains invalid listener or forwarding values.

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 *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 InterfaceConfig added in v0.5.0

type InterfaceConfig struct {
	Selector          string   `toml:"selector" json:"selector"`
	NoRootNetwork     bool     `toml:"no_root_network" json:"no_root_network"`
	IgnoredDevices    []string `toml:"ignored_devices" json:"ignored_devices"`
	NetworkInclusions []string `toml:"network_inclusions" json:"network_inclusions"`
	NetworkExclusions []string `toml:"network_exclusions" json:"network_exclusions"`
}

InterfaceConfig describes BPF configuration for a specific interface.

func DefaultInterfaceConfig added in v0.5.0

func DefaultInterfaceConfig() *InterfaceConfig

DefaultInterfaceConfig returns a default InterfaceConfig

type ListenerConfig added in v0.5.0

type ListenerConfig struct {
	Debug              bool              `toml:"debug" json:"debug"`
	Auto               bool              `toml:"auto" json:"auto"`
	ListenInterfaces   []string          `toml:"listen_interfaces,omitempty" json:"listen_interfaces,omitempty"`
	ListenInterface    string            `toml:"listen_interface,omitempty" json:"listen_interface,omitempty"` // Deprecated: use ListenInterfaces.
	Interfaces         []InterfaceConfig `toml:"interfaces,omitempty" json:"interfaces,omitempty"`
	ForwardKnown       bool              `toml:"forward_known" json:"forward_known"`
	NoRootNetwork      bool              `toml:"no_root_network" json:"no_root_network"`
	IgnoredDevices     []string          `toml:"ignored_devices" json:"ignored_devices"`
	NetworkInclusions  []string          `toml:"network_inclusions" json:"network_inclusions"`
	NetworkExclusions  []string          `toml:"network_exclusions" json:"network_exclusions"`
	CaptureFile        string            `toml:"capture_file" json:"capture_file"`
	RotateCaptureFiles bool              `toml:"rotate_capture_files" json:"rotate_capture_files"`
}

ListenerConfig describes packet capture and IP report processing behavior.

func DefaultListenerConfig added in v0.5.0

func DefaultListenerConfig() *ListenerConfig

DefaultListenerConfig returns the default packet listener configuration.

func ParseListenerConfig added in v0.5.0

func ParseListenerConfig(supplied *ListenerConfig) (*ListenerConfig, error)

ParseListenerConfig applies listener defaults, normalizes interface selectors, and validates the resulting configuration.

func (*ListenerConfig) Merge added in v0.5.0

func (cfg *ListenerConfig) Merge(target *ListenerConfig) *ListenerConfig

Merge returns a new ListenerConfig with non-zero values from target applied.

func (*ListenerConfig) Validate added in v0.5.0

func (cfg *ListenerConfig) Validate() error

Validate returns an error if ListenerConfig contains invalid values.

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 *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.

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 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 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 TCPCommand

type TCPCommand struct {
	Command string `json:"command"`
}

TCPCommand describes a tcp command.

Jump to

Keyboard shortcuts

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