Add configuration system and ARP-based device discovery
Implement comprehensive configuration management with CLI flags for WiFi interface, device discovery method, and file paths. Add ARP table parsing as an alternative to DHCP leases for more reliable device detection. Improve WiFi scanning to handle concurrent scan requests gracefully. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
accd7e75d8
commit
2b3a5b89f8
8 changed files with 156 additions and 28 deletions
|
|
@ -2,25 +2,71 @@ package device
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/nemunaire/repeater/internal/config"
|
||||
"github.com/nemunaire/repeater/internal/models"
|
||||
)
|
||||
|
||||
// ARPEntry represents an entry in the ARP table
|
||||
type ARPEntry struct {
|
||||
IP net.IP
|
||||
HWType int
|
||||
Flags int
|
||||
HWAddress net.HardwareAddr
|
||||
Mask string
|
||||
Device string
|
||||
}
|
||||
|
||||
// GetConnectedDevices returns a list of connected devices
|
||||
func GetConnectedDevices() ([]models.ConnectedDevice, error) {
|
||||
func GetConnectedDevices(cfg *config.Config) ([]models.ConnectedDevice, error) {
|
||||
if cfg.UseARPDiscovery {
|
||||
return getDevicesFromARP(cfg)
|
||||
}
|
||||
return getDevicesFromDHCP(cfg)
|
||||
}
|
||||
|
||||
// getDevicesFromARP discovers devices using ARP table
|
||||
func getDevicesFromARP(cfg *config.Config) ([]models.ConnectedDevice, error) {
|
||||
var devices []models.ConnectedDevice
|
||||
|
||||
// Read DHCP leases
|
||||
leases, err := parseDHCPLeases()
|
||||
arpEntries, err := parseARPTable(cfg.ARPTablePath)
|
||||
if err != nil {
|
||||
return devices, err
|
||||
}
|
||||
|
||||
// Get ARP information
|
||||
for _, entry := range arpEntries {
|
||||
// Only include entries with valid flags (2 = COMPLETE, 6 = COMPLETE|PERM)
|
||||
if entry.Flags == 2 || entry.Flags == 6 {
|
||||
device := models.ConnectedDevice{
|
||||
Name: "", // No hostname available from ARP
|
||||
MAC: entry.HWAddress.String(),
|
||||
IP: entry.IP.String(),
|
||||
Type: guessDeviceType("", entry.HWAddress.String()),
|
||||
}
|
||||
devices = append(devices, device)
|
||||
}
|
||||
}
|
||||
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
// getDevicesFromDHCP discovers devices using DHCP leases and ARP validation
|
||||
func getDevicesFromDHCP(cfg *config.Config) ([]models.ConnectedDevice, error) {
|
||||
var devices []models.ConnectedDevice
|
||||
|
||||
// Read DHCP leases
|
||||
leases, err := parseDHCPLeases(cfg.DHCPLeasesPath)
|
||||
if err != nil {
|
||||
return devices, err
|
||||
}
|
||||
|
||||
// Get ARP information for validation
|
||||
arpInfo, err := getARPInfo()
|
||||
if err != nil {
|
||||
return devices, err
|
||||
|
|
@ -43,11 +89,57 @@ func GetConnectedDevices() ([]models.ConnectedDevice, error) {
|
|||
return devices, nil
|
||||
}
|
||||
|
||||
// parseARPTable reads and parses ARP table from /proc/net/arp format
|
||||
func parseARPTable(path string) ([]ARPEntry, error) {
|
||||
var entries []ARPEntry
|
||||
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return entries, err
|
||||
}
|
||||
|
||||
for _, line := range strings.Split(string(content), "\n") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) > 5 {
|
||||
var entry ARPEntry
|
||||
|
||||
// Parse HWType (hex format)
|
||||
if _, err := fmt.Sscanf(fields[1], "0x%x", &entry.HWType); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse Flags (hex format)
|
||||
if _, err := fmt.Sscanf(fields[2], "0x%x", &entry.Flags); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse IP address
|
||||
entry.IP = net.ParseIP(fields[0])
|
||||
if entry.IP == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse MAC address
|
||||
entry.HWAddress, err = net.ParseMAC(fields[3])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
entry.Mask = fields[4]
|
||||
entry.Device = fields[5]
|
||||
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
// parseDHCPLeases reads and parses DHCP lease file
|
||||
func parseDHCPLeases() ([]models.DHCPLease, error) {
|
||||
func parseDHCPLeases(path string) ([]models.DHCPLease, error) {
|
||||
var leases []models.DHCPLease
|
||||
|
||||
file, err := os.Open("/var/lib/dhcp/dhcpd.leases")
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return leases, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue