mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-11-15 16:36:38 +01:00
Server: monitor dnsmasq, create events for DHCP lease trigger, fix teelogger
This commit is contained in:
@@ -178,7 +178,7 @@ func ConstructEventTrigger(triggerType common_web.EvtTriggerType) *pb.Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConstructEventTriggerDHCPLease(iface, mac, ip string) *pb.Event {
|
func ConstructEventTriggerDHCPLease(iface, mac, ip string, hostname string) *pb.Event {
|
||||||
return &pb.Event{
|
return &pb.Event{
|
||||||
Type: common_web.EVT_TRIGGER,
|
Type: common_web.EVT_TRIGGER,
|
||||||
Values: []*pb.EventValue{
|
Values: []*pb.EventValue{
|
||||||
@@ -186,6 +186,7 @@ func ConstructEventTriggerDHCPLease(iface, mac, ip string) *pb.Event {
|
|||||||
{Val: &pb.EventValue_Tstring{Tstring: iface}},
|
{Val: &pb.EventValue_Tstring{Tstring: iface}},
|
||||||
{Val: &pb.EventValue_Tstring{Tstring: mac}},
|
{Val: &pb.EventValue_Tstring{Tstring: mac}},
|
||||||
{Val: &pb.EventValue_Tstring{Tstring: ip}},
|
{Val: &pb.EventValue_Tstring{Tstring: ip}},
|
||||||
|
{Val: &pb.EventValue_Tstring{Tstring: hostname}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,27 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
//"github.com/docker/libcontainer/netlink"
|
//"github.com/docker/libcontainer/netlink"
|
||||||
"github.com/mame82/P4wnP1_go/netlink"
|
"github.com/mame82/P4wnP1_go/netlink"
|
||||||
"net"
|
|
||||||
"log"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
pb "github.com/mame82/P4wnP1_go/proto"
|
pb "github.com/mame82/P4wnP1_go/proto"
|
||||||
"errors"
|
"github.com/mame82/P4wnP1_go/service/util"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrUnmanagedInterface = errors.New("Not a managed network interface")
|
ErrUnmanagedInterface = errors.New("Not a managed network interface")
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewNetworkManager() (nm *NetworkManager, err error){
|
func NewNetworkManager(rootService *Service) (nm *NetworkManager, err error){
|
||||||
nm = &NetworkManager{
|
nm = &NetworkManager{
|
||||||
|
rootSvc: rootService,
|
||||||
ManagedInterfaces: make(map[string]*NetworkInterfaceManager),
|
ManagedInterfaces: make(map[string]*NetworkInterfaceManager),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,10 +45,11 @@ func NewNetworkManager() (nm *NetworkManager, err error){
|
|||||||
|
|
||||||
type NetworkManager struct {
|
type NetworkManager struct {
|
||||||
ManagedInterfaces map[string]*NetworkInterfaceManager
|
ManagedInterfaces map[string]*NetworkInterfaceManager
|
||||||
|
rootSvc *Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nm *NetworkManager) AddManagedInterface(startupConfig *pb.EthernetInterfaceSettings) (err error) {
|
func (nm *NetworkManager) AddManagedInterface(startupConfig *pb.EthernetInterfaceSettings) (err error) {
|
||||||
nim,err := NewNetworkInterfaceManager(startupConfig.Name, startupConfig)
|
nim,err := NewNetworkInterfaceManager(nm, startupConfig.Name, startupConfig)
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
nm.ManagedInterfaces[startupConfig.Name] = nim
|
nm.ManagedInterfaces[startupConfig.Name] = nim
|
||||||
return
|
return
|
||||||
@@ -78,14 +82,41 @@ type NetworkInterfaceState struct {
|
|||||||
|
|
||||||
// ToDo: interface watcher (up/down --> auto redeploy)
|
// ToDo: interface watcher (up/down --> auto redeploy)
|
||||||
type NetworkInterfaceManager struct {
|
type NetworkInterfaceManager struct {
|
||||||
|
nm *NetworkManager
|
||||||
InterfaceName string
|
InterfaceName string
|
||||||
state *NetworkInterfaceState
|
state *NetworkInterfaceState
|
||||||
|
|
||||||
|
CmdDnsmasq *exec.Cmd
|
||||||
|
mutexDnsmasq *sync.Mutex
|
||||||
|
LoggerDnsmasq *util.TeeLogger
|
||||||
|
leaseMonitor *dnsmasqLeaseMonitor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nim *NetworkInterfaceManager) GetState() (res *NetworkInterfaceState) {
|
func (nim *NetworkInterfaceManager) GetState() (res *NetworkInterfaceState) {
|
||||||
return nim.state
|
return nim.state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nim *NetworkInterfaceManager) OnHandedOutDhcpLease(lease *DhcpLease) {
|
||||||
|
fmt.Printf("Lease monitor %s LEASE: %v\n", nim.InterfaceName, lease)
|
||||||
|
// should never happen (dnsmasq output parsing error otherwise)
|
||||||
|
if nim.InterfaceName != lease.Iface {
|
||||||
|
fmt.Println("Interface of handed out DHCP lease doesn't match managed interface, ignoring ...")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//generate trigger event
|
||||||
|
nim.nm.rootSvc.SubSysEvent.Emit(ConstructEventTriggerDHCPLease(lease.Iface, lease.Mac.String(), lease.Ip.String(), lease.Host))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nim *NetworkInterfaceManager) OnReceivedDhcpRelease(release *DhcpLease) {
|
||||||
|
fmt.Printf("Lease monitor %s RELEASE: %v\n", nim.InterfaceName, release)
|
||||||
|
// should never happen (dnsmasq output parsing error otherwise)
|
||||||
|
if nim.InterfaceName != release.Iface {
|
||||||
|
fmt.Println("Interface for received DHCP release doesn't match managed interface, ignoring ...")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (nim *NetworkInterfaceManager) ReDeploy() (err error) {
|
func (nim *NetworkInterfaceManager) ReDeploy() (err error) {
|
||||||
/*
|
/*
|
||||||
if settings, existing := ServiceState.StoredNetworkSettings[ifName]; existing {
|
if settings, existing := ServiceState.StoredNetworkSettings[ifName]; existing {
|
||||||
@@ -110,10 +141,8 @@ func (nim *NetworkInterfaceManager) DeploySettings(settings *pb.EthernetInterfac
|
|||||||
}
|
}
|
||||||
|
|
||||||
//stop DHCP server / client if still running
|
//stop DHCP server / client if still running
|
||||||
running, _, err := IsDHCPServerRunning(settings.Name)
|
nim.StopDHCPServer()
|
||||||
if (err == nil) && running {StopDHCPServer(settings.Name)}
|
nim.StopDHCPClient()
|
||||||
running, _, err = IsDHCPClientRunning(settings.Name)
|
|
||||||
if (err == nil) && running {StopDHCPClient(settings.Name)}
|
|
||||||
|
|
||||||
switch settings.Mode {
|
switch settings.Mode {
|
||||||
case pb.EthernetInterfaceSettings_MANUAL:
|
case pb.EthernetInterfaceSettings_MANUAL:
|
||||||
@@ -172,7 +201,7 @@ func (nim *NetworkInterfaceManager) DeploySettings(settings *pb.EthernetInterfac
|
|||||||
err = DHCPCreateConfigFile(settings.DhcpServerSettings, confName)
|
err = DHCPCreateConfigFile(settings.DhcpServerSettings, confName)
|
||||||
if err != nil {return err}
|
if err != nil {return err}
|
||||||
//stop already running DHCPServers for the interface
|
//stop already running DHCPServers for the interface
|
||||||
StopDHCPServer(ifName)
|
nim.StopDHCPServer()
|
||||||
|
|
||||||
//special case: if the interface name is USB_ETHERNET_BRIDGE_NAME, we delete the old lease file
|
//special case: if the interface name is USB_ETHERNET_BRIDGE_NAME, we delete the old lease file
|
||||||
// the flushing of still running leases is needed, as after USB reinit, RNDIS hosts aren't guaranteed to
|
// the flushing of still running leases is needed, as after USB reinit, RNDIS hosts aren't guaranteed to
|
||||||
@@ -189,7 +218,7 @@ func (nim *NetworkInterfaceManager) DeploySettings(settings *pb.EthernetInterfac
|
|||||||
}
|
}
|
||||||
|
|
||||||
//start the DHCP server
|
//start the DHCP server
|
||||||
err = StartDHCPServer(ifName, confName)
|
err = nim.StartDHCPServer(confName)
|
||||||
if err != nil {return err}
|
if err != nil {return err}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Setting Interface %s to DOWN\n", iface.Name)
|
log.Printf("Setting Interface %s to DOWN\n", iface.Name)
|
||||||
@@ -206,7 +235,7 @@ func (nim *NetworkInterfaceManager) DeploySettings(settings *pb.EthernetInterfac
|
|||||||
err = netlink.NetworkSetMulticast(iface, true)
|
err = netlink.NetworkSetMulticast(iface, true)
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
|
|
||||||
StartDHCPClient(settings.Name)
|
nim.StartDHCPClient()
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Setting Interface %s to DOWN\n", iface.Name)
|
log.Printf("Setting Interface %s to DOWN\n", iface.Name)
|
||||||
err = netlink.NetworkLinkDown(iface)
|
err = netlink.NetworkLinkDown(iface)
|
||||||
@@ -224,40 +253,23 @@ func (nim *NetworkInterfaceManager) DeploySettings(settings *pb.EthernetInterfac
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNetworkInterfaceManager(ifaceName string, startupSettings *pb.EthernetInterfaceSettings) (nim *NetworkInterfaceManager, err error) {
|
func NewNetworkInterfaceManager(nm *NetworkManager, ifaceName string, startupSettings *pb.EthernetInterfaceSettings) (nim *NetworkInterfaceManager, err error) {
|
||||||
nim = &NetworkInterfaceManager{
|
nim = &NetworkInterfaceManager{
|
||||||
|
nm: nm,
|
||||||
InterfaceName: ifaceName,
|
InterfaceName: ifaceName,
|
||||||
state: &NetworkInterfaceState{},
|
state: &NetworkInterfaceState{},
|
||||||
|
mutexDnsmasq: &sync.Mutex{},
|
||||||
|
LoggerDnsmasq: util.NewTeeLogger(false),
|
||||||
}
|
}
|
||||||
|
nim.leaseMonitor = NewDnsmasqLeaseMonitor(nim)
|
||||||
|
|
||||||
|
//nim.LoggerDnsmasq.SetPrefix("dnsmasq-" + ifaceName + ": ")
|
||||||
|
nim.LoggerDnsmasq.AddOutput(nim.leaseMonitor)
|
||||||
|
|
||||||
|
|
||||||
nim.state.CurrentSettings = startupSettings
|
nim.state.CurrentSettings = startupSettings
|
||||||
nim.ReDeploy()
|
nim.ReDeploy()
|
||||||
|
|
||||||
// Deploy startup configuration, to have an initial, defined state
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Startup settings (always DHCP client, Interface up)
|
|
||||||
nim.state.CurrentSettings = &pb.EthernetInterfaceSettings{
|
|
||||||
Name: ifaceName,
|
|
||||||
Mode: pb.EthernetInterfaceSettings_DHCP_CLIENT,
|
|
||||||
Enabled: true,
|
|
||||||
SettingsInUse: true,
|
|
||||||
DhcpServerSettings: &pb.DHCPServerSettings{
|
|
||||||
CallbackScript: "",
|
|
||||||
DoNotBindInterface: false,
|
|
||||||
LeaseFile: nameLeaseFileDHCPSrv(ifaceName),
|
|
||||||
ListenInterface: ifaceName,
|
|
||||||
ListenPort: 0,
|
|
||||||
NotAuthoritative: false,
|
|
||||||
Options: map[uint32]string{
|
|
||||||
3: "",
|
|
||||||
6: "",
|
|
||||||
},
|
|
||||||
Ranges: []*pb.DHCPServerRange{},
|
|
||||||
StaticHosts: []*pb.DHCPServerStaticHost{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
229
service/dhcp.go
229
service/dhcp.go
@@ -3,17 +3,22 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
pb "github.com/mame82/P4wnP1_go/proto"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/mame82/P4wnP1_go/common_web"
|
||||||
|
pb "github.com/mame82/P4wnP1_go/proto"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"log"
|
"regexp"
|
||||||
"errors"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
|
||||||
"strings"
|
"strings"
|
||||||
"github.com/mame82/P4wnP1_go/common_web"
|
"syscall"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -35,14 +40,13 @@ func leaseFileDHCPSrv(s *pb.DHCPServerSettings) (lf string) {
|
|||||||
return common_web.NameLeaseFileDHCPSrv(s.ListenInterface) //default lease file
|
return common_web.NameLeaseFileDHCPSrv(s.ListenInterface) //default lease file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func NameConfigFileDHCPSrv(nameIface string) string {
|
func NameConfigFileDHCPSrv(nameIface string) string {
|
||||||
return fmt.Sprintf("/tmp/dnsmasq_%s.conf", nameIface)
|
return fmt.Sprintf("/tmp/dnsmasq_%s.conf", nameIface)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func StartDHCPClient(nameIface string) (err error) {
|
func (nim *NetworkInterfaceManager) StartDHCPClient() (err error) {
|
||||||
|
nameIface := nim.InterfaceName
|
||||||
log.Printf("Starting DHCP client for interface '%s'...\n", nameIface)
|
log.Printf("Starting DHCP client for interface '%s'...\n", nameIface)
|
||||||
|
|
||||||
//check if interface is valid
|
//check if interface is valid
|
||||||
@@ -65,7 +69,8 @@ func StartDHCPClient(nameIface string) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsDHCPClientRunning(nameIface string) (running bool, pid int, err error) {
|
func (nim *NetworkInterfaceManager) IsDHCPClientRunning() (running bool, pid int, err error) {
|
||||||
|
nameIface := nim.InterfaceName
|
||||||
if_exists,_ := CheckInterfaceExistence(nameIface)
|
if_exists,_ := CheckInterfaceExistence(nameIface)
|
||||||
if !if_exists {
|
if !if_exists {
|
||||||
return false, 0, errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", nameIface))
|
return false, 0, errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", nameIface))
|
||||||
@@ -102,8 +107,9 @@ func IsDHCPClientRunning(nameIface string) (running bool, pid int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func StopDHCPClient(nameIface string) (err error) {
|
func (nim *NetworkInterfaceManager) StopDHCPClient() (err error) {
|
||||||
log.Printf("Stoping DHCP client for interface '%s'...\n", nameIface)
|
nameIface := nim.InterfaceName
|
||||||
|
log.Printf("Stopping DHCP client for interface '%s'...\n", nameIface)
|
||||||
|
|
||||||
//check if interface is valid
|
//check if interface is valid
|
||||||
if_exists,_ := CheckInterfaceExistence(nameIface)
|
if_exists,_ := CheckInterfaceExistence(nameIface)
|
||||||
@@ -125,10 +131,20 @@ func StopDHCPClient(nameIface string) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nim *NetworkInterfaceManager) StartDHCPServer(configPath string) (err error) {
|
||||||
|
nim.mutexDnsmasq.Lock()
|
||||||
|
defer nim.mutexDnsmasq.Unlock()
|
||||||
|
|
||||||
|
//stop dnsmasq if already running
|
||||||
|
if nim.CmdDnsmasq != nil {
|
||||||
|
// avoid deadlock
|
||||||
|
nim.mutexDnsmasq.Unlock()
|
||||||
|
nim.StopDHCPServer()
|
||||||
|
nim.mutexDnsmasq.Lock()
|
||||||
|
}
|
||||||
|
|
||||||
func StartDHCPServer(nameIface string, configPath string) (err error) {
|
nameIface := nim.InterfaceName
|
||||||
log.Printf("Starting DHCP server for interface '%s' with config '%s'...\n", nameIface, configPath)
|
log.Printf("Starting dnsmasq for interface '%s' with config '%s'...\n", nameIface, configPath)
|
||||||
|
|
||||||
//check if interface is valid
|
//check if interface is valid
|
||||||
if_exists,_ := CheckInterfaceExistence(nameIface)
|
if_exists,_ := CheckInterfaceExistence(nameIface)
|
||||||
@@ -136,91 +152,46 @@ func StartDHCPServer(nameIface string, configPath string) (err error) {
|
|||||||
return errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", nameIface))
|
return errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", nameIface))
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if there's already a DHCP server running for the given interface
|
|
||||||
running, _, err := IsDHCPServerRunning(nameIface)
|
|
||||||
if err != nil { return errors.New(fmt.Sprintf("Error fetching state of DHCP server: %v\n", err)) }
|
|
||||||
if running {return errors.New(fmt.Sprintf("Error starting DHCP server for interface '%s', there is already a DHCP server running\n", nameIface))}
|
|
||||||
|
|
||||||
//We use the run command and allow dnsmasq to daemonize
|
nim.CmdDnsmasq = exec.Command("/usr/sbin/dnsmasq", "--log-facility=-", "-k", "-x", pidFileDHCPSrv(nameIface), "-C", configPath)
|
||||||
proc := exec.Command("/usr/sbin/dnsmasq", "-x", pidFileDHCPSrv(nameIface), "-C", configPath)
|
nim.CmdDnsmasq.Stdout = nim.LoggerDnsmasq.LogWriter
|
||||||
//dnsmasq_out, err := proc.CombinedOutput()
|
nim.CmdDnsmasq.Stderr = nim.LoggerDnsmasq.LogWriter
|
||||||
err = proc.Run()
|
|
||||||
if err != nil { return err}
|
|
||||||
//fmt.Printf("Dnsmasq out %s\n", dnsmasq_out)
|
err = nim.CmdDnsmasq.Start()
|
||||||
|
if err != nil {
|
||||||
|
nim.CmdDnsmasq.Wait()
|
||||||
|
return errors.New(fmt.Sprintf("Error starting dnsmasq '%v'", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
log.Printf("... DHCP server for interface '%s' started\n", nameIface)
|
log.Printf("... DHCP server for interface '%s' started\n", nameIface)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nim *NetworkInterfaceManager) StopDHCPServer() (err error) {
|
||||||
|
eSuccess := fmt.Sprintf("... dnsmasq for interface '%s' stopped", nim.InterfaceName)
|
||||||
|
eCantStop := fmt.Sprintf("... couldn't terminate dnsmasq for interface '%s'", nim.InterfaceName)
|
||||||
|
|
||||||
func IsDHCPServerRunning(nameIface string) (running bool, pid int, err error) {
|
log.Println("... killing dnsmasq")
|
||||||
if_exists,_ := CheckInterfaceExistence(nameIface)
|
nim.mutexDnsmasq.Lock()
|
||||||
if !if_exists {
|
defer nim.mutexDnsmasq.Unlock()
|
||||||
return false, 0, errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", nameIface))
|
|
||||||
|
if nim.CmdDnsmasq == nil {
|
||||||
|
log.Printf("... dnsmasq for interface '%s' isn't running, no need to stop it\n", nim.InterfaceName)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_file := pidFileDHCPSrv(nameIface)
|
err = ProcSoftKill(nim.CmdDnsmasq, time.Second)
|
||||||
|
if err != nil { return errors.New(eCantStop) }
|
||||||
|
|
||||||
//Check if the pidFile exists
|
|
||||||
if _, err := os.Stat(pid_file); os.IsNotExist(err) {
|
|
||||||
return false, 0,nil //file doesn't exist, so we assume dnsmasq isn't running
|
|
||||||
}
|
|
||||||
|
|
||||||
//File exists, read the PID
|
nim.CmdDnsmasq = nil
|
||||||
content, err := ioutil.ReadFile(pid_file)
|
log.Println(eSuccess)
|
||||||
if err != nil { return false, 0, err}
|
|
||||||
pid, err = strconv.Atoi(strings.TrimSuffix(string(content), "\n"))
|
|
||||||
if err != nil { return false, 0, errors.New(fmt.Sprintf("Error parsing PID file %s: %v", pid_file, err))}
|
|
||||||
|
|
||||||
//With PID given, check if the process is indeed running (pid_file could stay, even if the dnsmasq process has died already)
|
|
||||||
err_kill := syscall.Kill(pid, 0) //sig 0: doesn't send a signal, but error checking is still performed
|
|
||||||
switch err_kill{
|
|
||||||
case nil:
|
|
||||||
//ToDo: Check if the running process image is indeed dnsmasq
|
|
||||||
return true, pid, nil //Process is running
|
|
||||||
case syscall.ESRCH:
|
|
||||||
//Process doesn't exist
|
|
||||||
return false, pid, nil
|
|
||||||
case syscall.EPERM:
|
|
||||||
//process exists, but we have no access permission
|
|
||||||
return true, pid, err_kill
|
|
||||||
default:
|
|
||||||
return false, pid, err_kill
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func StopDHCPServer(nameIface string) (err error) {
|
|
||||||
//don't check if interface is valid, to allow closing of orphaned DHCP procs (interface went down while running)
|
|
||||||
log.Printf("Stopping DHCP server for interface '%s' ...\n", nameIface)
|
|
||||||
running,pid,err := IsDHCPServerRunning(nameIface)
|
|
||||||
if err != nil { return }
|
|
||||||
|
|
||||||
if running {
|
|
||||||
//send SIGTERM
|
|
||||||
err = syscall.Kill(pid, syscall.SIGTERM)
|
|
||||||
if err != nil { return }
|
|
||||||
} else {
|
|
||||||
log.Printf("... DHCP server for interface '%s' wasn't started\n", nameIface)
|
|
||||||
}
|
|
||||||
|
|
||||||
running,pid,err = IsDHCPServerRunning(nameIface)
|
|
||||||
if err != nil { return }
|
|
||||||
if (running) {
|
|
||||||
log.Printf("... couldn't terminate DHCP server for interface '%s'\n", nameIface)
|
|
||||||
} else {
|
|
||||||
log.Printf("... DHCP server for interface '%s' stopped\n", nameIface)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Delete PID file
|
|
||||||
os.Remove(pidFileDHCPSrv(nameIface))
|
|
||||||
|
|
||||||
//Deleting leaseFile
|
|
||||||
os.Remove(common_web.NameLeaseFileDHCPSrv(nameIface))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func DHCPCreateConfigFile(s *pb.DHCPServerSettings, filename string) (err error) {
|
func DHCPCreateConfigFile(s *pb.DHCPServerSettings, filename string) (err error) {
|
||||||
file_content, err := DHCPCreateConfigFileString(s)
|
file_content, err := DHCPCreateConfigFileString(s)
|
||||||
if err != nil {return}
|
if err != nil {return}
|
||||||
@@ -245,12 +216,19 @@ func DHCPCreateConfigFileString(s *pb.DHCPServerSettings) (config string, err er
|
|||||||
//Iterate over Ranges
|
//Iterate over Ranges
|
||||||
for _, pRange := range s.Ranges {
|
for _, pRange := range s.Ranges {
|
||||||
//ToDo: regex check for leaseTime
|
//ToDo: regex check for leaseTime
|
||||||
|
/*
|
||||||
|
If the lease time is
|
||||||
|
given, then leases will be given for that length of time. The
|
||||||
|
lease time is in seconds, or minutes (eg 45m) or hours (eg 1h)
|
||||||
|
or "infinite". If not given, the default lease time is one
|
||||||
|
hour. The minimum lease time is two minutes
|
||||||
|
*/
|
||||||
//ToDo: check rangeLower + rangeUpper to be valid IP addresses
|
//ToDo: check rangeLower + rangeUpper to be valid IP addresses
|
||||||
if len(pRange.LeaseTime) > 0 {
|
if len(pRange.LeaseTime) > 0 {
|
||||||
config += fmt.Sprintf("dhcp-range=%s,%s,%s\n", pRange.RangeLower, pRange.RangeUpper, pRange.LeaseTime)
|
config += fmt.Sprintf("dhcp-range=%s,%s,%s\n", pRange.RangeLower, pRange.RangeUpper, pRange.LeaseTime)
|
||||||
} else {
|
} else {
|
||||||
//default to 5 minute lease
|
//default to 5 minute lease
|
||||||
config += fmt.Sprintf("dhcp-range=%s,%s,5m\n", pRange.RangeLower, pRange.RangeUpper)
|
config += fmt.Sprintf("dhcp-range=%s,%s\n", pRange.RangeLower, pRange.RangeUpper)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -282,3 +260,86 @@ func DHCPCreateConfigFileString(s *pb.DHCPServerSettings) (config string, err er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lease/Release tracker
|
||||||
|
var reLease = regexp.MustCompile(".*DHCPACK\\((.*)\\) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}) ([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}) (.*)")
|
||||||
|
var reRelease = regexp.MustCompile(".*DHCPRELEASE\\((.*)\\) ([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}) ([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2})")
|
||||||
|
|
||||||
|
|
||||||
|
type DhcpLease struct {
|
||||||
|
Release bool
|
||||||
|
Iface string
|
||||||
|
Ip net.IP
|
||||||
|
Mac net.HardwareAddr
|
||||||
|
Host string //only used for lease, not release
|
||||||
|
}
|
||||||
|
|
||||||
|
type dnsmasqLeaseMonitor struct {
|
||||||
|
nim *NetworkInterfaceManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *dnsmasqLeaseMonitor) Write(p []byte) (n int, err error) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
dnsmasq-wlan0: 16:53:49 dnsmasq-dhcp[1855]: 1450307105 DHCPACK(wlan0) 172.24.0.18 34:e6:xx:xx:xx:xx who-knows
|
||||||
|
dnsmasq-wlan0: 16:53:58 dnsmasq-dhcp[1855]: 4200697351 DHCPRELEASE(wlan0) 172.24.0.18 34:e6:xx:xx:xx:xx
|
||||||
|
*/
|
||||||
|
lineScanner := bufio.NewScanner(bytes.NewReader(p))
|
||||||
|
lineScanner.Split(bufio.ScanLines)
|
||||||
|
for lineScanner.Scan() {
|
||||||
|
line := string(lineScanner.Bytes())
|
||||||
|
switch {
|
||||||
|
case strings.Contains(line, "DHCPACK"):
|
||||||
|
//fmt.Printf("Lease monitor %s LEASE: %s\n", m.nim.InterfaceName, line)
|
||||||
|
|
||||||
|
leaseMatches := reLease.FindStringSubmatch(line)
|
||||||
|
if len(leaseMatches) > 3 {
|
||||||
|
lease := &DhcpLease{}
|
||||||
|
lease.Iface = leaseMatches[1]
|
||||||
|
lease.Ip = net.ParseIP(leaseMatches[2])
|
||||||
|
mac,errP := net.ParseMAC(leaseMatches[3])
|
||||||
|
if errP != nil { continue } //ignore if mac address couldn't be parsed
|
||||||
|
lease.Mac = mac
|
||||||
|
if len(leaseMatches) > 4 {
|
||||||
|
//assume 4th match is hostname
|
||||||
|
lease.Host = leaseMatches[4]
|
||||||
|
}
|
||||||
|
m.nim.OnHandedOutDhcpLease(lease)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
for i,m := range leaseMatches {
|
||||||
|
fmt.Printf("\tRegex lease %d: %s\n", i, m)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case strings.Contains(line, "DHCPRELEASE"):
|
||||||
|
//fmt.Printf("Lease monitor %s RELEASE: %s\n", m.nim.InterfaceName, line)
|
||||||
|
leaseMatches := reRelease.FindStringSubmatch(line)
|
||||||
|
if len(leaseMatches) > 3 {
|
||||||
|
release := &DhcpLease{}
|
||||||
|
release.Iface = leaseMatches[1]
|
||||||
|
release.Ip = net.ParseIP(leaseMatches[2])
|
||||||
|
mac,errP := net.ParseMAC(leaseMatches[3])
|
||||||
|
if errP != nil { continue } //ignore if mac address couldn't be parsed
|
||||||
|
release.Mac = mac
|
||||||
|
release.Release = true
|
||||||
|
|
||||||
|
m.nim.OnReceivedDhcpRelease(release)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return len(p),nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func NewDnsmasqLeaseMonitor(nim *NetworkInterfaceManager) *dnsmasqLeaseMonitor {
|
||||||
|
return &dnsmasqLeaseMonitor{
|
||||||
|
nim: nim,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ func NewService() (svc *Service, err error) {
|
|||||||
svc.SubSysEvent = NewEventManager(20)
|
svc.SubSysEvent = NewEventManager(20)
|
||||||
|
|
||||||
svc.SubSysLed = NewLedService()
|
svc.SubSysLed = NewLedService()
|
||||||
svc.SubSysNetwork, err = NewNetworkManager()
|
svc.SubSysNetwork, err = NewNetworkManager(svc) //Depends on EvenSubSys
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ func (tam *TriggerActionManager) executeActionStartHidScript(evt *pb.Event, ta *
|
|||||||
case triggerTypeGpioIn:
|
case triggerTypeGpioIn:
|
||||||
gpioPin := ta.Trigger.(*pb.TriggerAction_GpioIn).GpioIn.GpioNum
|
gpioPin := ta.Trigger.(*pb.TriggerAction_GpioIn).GpioIn.GpioNum
|
||||||
gpioPinName := pb.GPIONum_name[int32(gpioPin)]
|
gpioPinName := pb.GPIONum_name[int32(gpioPin)]
|
||||||
preScript += fmt.Sprintf("var GPIO_PIN=%s;\n", gpioPinName)
|
preScript += fmt.Sprintf("var GPIO_PIN='%s';\n", gpioPinName)
|
||||||
case triggerTypeGroupReceiveSequence:
|
case triggerTypeGroupReceiveSequence:
|
||||||
groupName := ta.Trigger.(*pb.TriggerAction_GroupReceiveSequence).GroupReceiveSequence.GroupName
|
groupName := ta.Trigger.(*pb.TriggerAction_GroupReceiveSequence).GroupReceiveSequence.GroupName
|
||||||
values := ta.Trigger.(*pb.TriggerAction_GroupReceiveSequence).GroupReceiveSequence.Values
|
values := ta.Trigger.(*pb.TriggerAction_GroupReceiveSequence).GroupReceiveSequence.Values
|
||||||
@@ -425,12 +425,14 @@ func (tam *TriggerActionManager) executeActionStartHidScript(evt *pb.Event, ta *
|
|||||||
iface := evt.Values[1].GetTstring()
|
iface := evt.Values[1].GetTstring()
|
||||||
mac := evt.Values[2].GetTstring()
|
mac := evt.Values[2].GetTstring()
|
||||||
ip := evt.Values[3].GetTstring()
|
ip := evt.Values[3].GetTstring()
|
||||||
preScript += fmt.Sprintf("var DHCP_LEASE_IFACE=%s;\n", iface)
|
host := evt.Values[4].GetTstring()
|
||||||
preScript += fmt.Sprintf("var DHCP_LEASE_MAC=%s;\n", mac)
|
preScript += fmt.Sprintf("var DHCP_LEASE_IFACE='%s';\n", iface)
|
||||||
preScript += fmt.Sprintf("var DHCP_LEASE_IP=%s;\n", ip)
|
preScript += fmt.Sprintf("var DHCP_LEASE_MAC='%s';\n", mac)
|
||||||
|
preScript += fmt.Sprintf("var DHCP_LEASE_IP='%s';\n", ip)
|
||||||
|
preScript += fmt.Sprintf("var DHCP_LEASE_HOST='%s';\n", host)
|
||||||
case triggerTypeSshLogin:
|
case triggerTypeSshLogin:
|
||||||
loginUser := evt.Values[1].GetTstring()
|
loginUser := evt.Values[1].GetTstring()
|
||||||
preScript += fmt.Sprintf("var SSH_LOGIN_USER=%s;\n", loginUser)
|
preScript += fmt.Sprintf("var SSH_LOGIN_USER='%s';\n", loginUser)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,10 +492,12 @@ func (tam *TriggerActionManager) executeActionBashScript(evt *pb.Event, ta *pb.T
|
|||||||
iface := evt.Values[1].GetTstring()
|
iface := evt.Values[1].GetTstring()
|
||||||
mac := evt.Values[2].GetTstring()
|
mac := evt.Values[2].GetTstring()
|
||||||
ip := evt.Values[3].GetTstring()
|
ip := evt.Values[3].GetTstring()
|
||||||
|
host := evt.Values[4].GetTstring()
|
||||||
env = append(env,
|
env = append(env,
|
||||||
fmt.Sprintf("DHCP_LEASE_IFACE=%s", iface),
|
fmt.Sprintf("DHCP_LEASE_IFACE=%s", iface),
|
||||||
fmt.Sprintf("DHCP_LEASE_MAC=%s", mac),
|
fmt.Sprintf("DHCP_LEASE_MAC=%s", mac),
|
||||||
fmt.Sprintf("DHCP_LEASE_IP=%s", ip),
|
fmt.Sprintf("DHCP_LEASE_IP=%s", ip),
|
||||||
|
fmt.Sprintf("DHCP_LEASE_HOST=\"%s\"", host),
|
||||||
)
|
)
|
||||||
case triggerTypeSshLogin:
|
case triggerTypeSshLogin:
|
||||||
loginUser := evt.Values[1].GetTstring()
|
loginUser := evt.Values[1].GetTstring()
|
||||||
@@ -530,7 +534,8 @@ func (tam *TriggerActionManager) executeActionLog(evt *pb.Event, ta *pb.TriggerA
|
|||||||
iface := evt.Values[1].GetTstring()
|
iface := evt.Values[1].GetTstring()
|
||||||
mac := evt.Values[2].GetTstring()
|
mac := evt.Values[2].GetTstring()
|
||||||
ip := evt.Values[3].GetTstring()
|
ip := evt.Values[3].GetTstring()
|
||||||
logMessage += fmt.Sprintf(" (DHCP_LEASE_IFACE=%s, DHCP_LEASE_MAC=%s, DHCP_LEASE_IP=%s)", iface, mac, ip)
|
host := evt.Values[4].GetTstring()
|
||||||
|
logMessage += fmt.Sprintf(" (DHCP_LEASE_IFACE=%s, DHCP_LEASE_MAC=%s, DHCP_LEASE_IP=%s, DHCP_LEASE_HOST='%s')", iface, mac, ip, host)
|
||||||
case triggerTypeSshLogin:
|
case triggerTypeSshLogin:
|
||||||
loginUser := evt.Values[1].GetTstring()
|
loginUser := evt.Values[1].GetTstring()
|
||||||
logMessage += fmt.Sprintf(" (SSH_LOGIN_USER=%s)", loginUser)
|
logMessage += fmt.Sprintf(" (SSH_LOGIN_USER=%s)", loginUser)
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TeeLogger struct {
|
type TeeLogger struct {
|
||||||
@@ -18,11 +20,29 @@ type sublogger struct {
|
|||||||
*TeeLogger
|
*TeeLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// struct to present an additional io.Writer, wrapping TeeLogger to ise its Print() method
|
// struct to present an additional io.Writer, wrapping TeeLogger to ise its Print() method
|
||||||
func (sl sublogger) Write(p []byte) (n int, err error) {
|
func (sl sublogger) Write(p []byte) (n int, err error) {
|
||||||
sl.TeeLogger.Print(string(p))
|
sl.TeeLogger.Print(string(p))
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// struct to present an additional io.Writer, wrapping TeeLogger to ise its Print() method
|
||||||
|
func (sl sublogger) Write(p []byte) (n int, err error) {
|
||||||
|
//fmt.Printf("%s: %s", lw.Prefix, string(p))
|
||||||
|
|
||||||
|
lineScanner := bufio.NewScanner(bytes.NewReader(p))
|
||||||
|
lineScanner.Split(bufio.ScanLines)
|
||||||
|
for lineScanner.Scan() {
|
||||||
|
sl.TeeLogger.Print(string(lineScanner.Bytes()))
|
||||||
|
//fmt.Printf("%s: %s\n", lw.Prefix, string(lineScanner.Bytes()))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return len(p),nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func NewTeeLogger(addStdout bool) (res *TeeLogger) {
|
func NewTeeLogger(addStdout bool) (res *TeeLogger) {
|
||||||
res = &TeeLogger{
|
res = &TeeLogger{
|
||||||
@@ -38,6 +58,7 @@ func NewTeeLogger(addStdout bool) (res *TeeLogger) {
|
|||||||
res.LogWriter = sublogger{ TeeLogger: res }
|
res.LogWriter = sublogger{ TeeLogger: res }
|
||||||
res.SetFlags(log.Ltime)
|
res.SetFlags(log.Ltime)
|
||||||
res.SetOutput(res)
|
res.SetOutput(res)
|
||||||
|
log.Println()
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user