130 lines
2.9 KiB
Go
130 lines
2.9 KiB
Go
package hostapd
|
|
|
|
import (
|
|
"bufio"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/nemunaire/repeater/internal/models"
|
|
)
|
|
|
|
// DHCPCorrelator helps correlate hostapd stations with DHCP leases to discover IP addresses
|
|
type DHCPCorrelator struct {
|
|
backend *Backend
|
|
dhcpLeasesPath string
|
|
stopChan chan struct{}
|
|
running bool
|
|
}
|
|
|
|
// NewDHCPCorrelator creates a new DHCP correlator
|
|
func NewDHCPCorrelator(backend *Backend, dhcpLeasesPath string) *DHCPCorrelator {
|
|
if dhcpLeasesPath == "" {
|
|
dhcpLeasesPath = "/var/lib/dhcp/dhcpd.leases"
|
|
}
|
|
|
|
return &DHCPCorrelator{
|
|
backend: backend,
|
|
dhcpLeasesPath: dhcpLeasesPath,
|
|
stopChan: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
// Start begins periodic correlation of DHCP leases with hostapd stations
|
|
func (dc *DHCPCorrelator) Start() {
|
|
if dc.running {
|
|
return
|
|
}
|
|
|
|
dc.running = true
|
|
go dc.correlationLoop()
|
|
log.Printf("DHCP correlation started for hostapd backend")
|
|
}
|
|
|
|
// Stop stops the correlation loop
|
|
func (dc *DHCPCorrelator) Stop() {
|
|
if !dc.running {
|
|
return
|
|
}
|
|
|
|
dc.running = false
|
|
close(dc.stopChan)
|
|
log.Printf("DHCP correlation stopped")
|
|
}
|
|
|
|
// correlationLoop periodically correlates DHCP leases with stations
|
|
func (dc *DHCPCorrelator) correlationLoop() {
|
|
// Do an initial correlation immediately
|
|
dc.correlate()
|
|
|
|
// Then correlate every 10 seconds
|
|
ticker := time.NewTicker(10 * time.Second)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
dc.correlate()
|
|
case <-dc.stopChan:
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// correlate performs one correlation cycle
|
|
func (dc *DHCPCorrelator) correlate() {
|
|
// Parse DHCP leases
|
|
leases, err := parseDHCPLeases(dc.dhcpLeasesPath)
|
|
if err != nil {
|
|
log.Printf("Warning: Failed to parse DHCP leases: %v", err)
|
|
return
|
|
}
|
|
|
|
// Build MAC -> IP mapping
|
|
macToIP := make(map[string]string)
|
|
for _, lease := range leases {
|
|
macToIP[lease.MAC] = lease.IP
|
|
}
|
|
|
|
// Update backend with IP mappings
|
|
dc.backend.UpdateIPMapping(macToIP)
|
|
}
|
|
|
|
// parseDHCPLeases reads and parses DHCP lease file
|
|
func parseDHCPLeases(path string) ([]models.DHCPLease, error) {
|
|
var leases []models.DHCPLease
|
|
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return leases, err
|
|
}
|
|
defer file.Close()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
var currentLease models.DHCPLease
|
|
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
|
|
if strings.HasPrefix(line, "lease ") {
|
|
ip := strings.Fields(line)[1]
|
|
currentLease = models.DHCPLease{IP: ip}
|
|
} else if strings.Contains(line, "hardware ethernet") {
|
|
mac := strings.Fields(line)[2]
|
|
mac = strings.TrimSuffix(mac, ";")
|
|
currentLease.MAC = mac
|
|
} else if strings.Contains(line, "client-hostname") {
|
|
hostname := strings.Fields(line)[1]
|
|
hostname = strings.Trim(hostname, `";`)
|
|
currentLease.Hostname = hostname
|
|
} else if line == "}" {
|
|
if currentLease.IP != "" && currentLease.MAC != "" {
|
|
leases = append(leases, currentLease)
|
|
}
|
|
currentLease = models.DHCPLease{}
|
|
}
|
|
}
|
|
|
|
return leases, scanner.Err()
|
|
}
|