From b15be2bf8f84df6dfeb77c395dbdc1a692dda6a1 Mon Sep 17 00:00:00 2001 From: MaMe82 Date: Fri, 26 Oct 2018 11:41:24 +0200 Subject: [PATCH] Server: monitor dnsmasq, create events for DHCP lease trigger, fix teelogger --- service/Event.go | 3 +- .../{network.go => SubSysNetworkManager.go} | 98 ++++---- service/dhcp.go | 229 +++++++++++------- service/service.go | 2 +- service/triggerAction.go | 17 +- service/util/teelogger.go | 23 +- 6 files changed, 236 insertions(+), 136 deletions(-) rename service/{network.go => SubSysNetworkManager.go} (83%) diff --git a/service/Event.go b/service/Event.go index ccea2fb..c62d423 100644 --- a/service/Event.go +++ b/service/Event.go @@ -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{ Type: common_web.EVT_TRIGGER, 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: mac}}, {Val: &pb.EventValue_Tstring{Tstring: ip}}, + {Val: &pb.EventValue_Tstring{Tstring: hostname}}, }, } } diff --git a/service/network.go b/service/SubSysNetworkManager.go similarity index 83% rename from service/network.go rename to service/SubSysNetworkManager.go index 394a8cd..703c467 100644 --- a/service/network.go +++ b/service/SubSysNetworkManager.go @@ -1,24 +1,27 @@ package service import ( + "errors" + "fmt" //"github.com/docker/libcontainer/netlink" "github.com/mame82/P4wnP1_go/netlink" - "net" - "log" - "io/ioutil" - "os" - "fmt" - pb "github.com/mame82/P4wnP1_go/proto" - "errors" + "github.com/mame82/P4wnP1_go/service/util" + "io/ioutil" + "log" + "net" + "os" + "os/exec" + "sync" ) var ( ErrUnmanagedInterface = errors.New("Not a managed network interface") ) -func NewNetworkManager() (nm *NetworkManager, err error){ +func NewNetworkManager(rootService *Service) (nm *NetworkManager, err error){ nm = &NetworkManager{ + rootSvc: rootService, ManagedInterfaces: make(map[string]*NetworkInterfaceManager), } @@ -42,10 +45,11 @@ func NewNetworkManager() (nm *NetworkManager, err error){ type NetworkManager struct { ManagedInterfaces map[string]*NetworkInterfaceManager + rootSvc *Service } 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 } nm.ManagedInterfaces[startupConfig.Name] = nim return @@ -78,14 +82,41 @@ type NetworkInterfaceState struct { // ToDo: interface watcher (up/down --> auto redeploy) type NetworkInterfaceManager struct { + nm *NetworkManager InterfaceName string state *NetworkInterfaceState + + CmdDnsmasq *exec.Cmd + mutexDnsmasq *sync.Mutex + LoggerDnsmasq *util.TeeLogger + leaseMonitor *dnsmasqLeaseMonitor } func (nim *NetworkInterfaceManager) GetState() (res *NetworkInterfaceState) { 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) { /* 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 - running, _, err := IsDHCPServerRunning(settings.Name) - if (err == nil) && running {StopDHCPServer(settings.Name)} - running, _, err = IsDHCPClientRunning(settings.Name) - if (err == nil) && running {StopDHCPClient(settings.Name)} + nim.StopDHCPServer() + nim.StopDHCPClient() switch settings.Mode { case pb.EthernetInterfaceSettings_MANUAL: @@ -172,7 +201,7 @@ func (nim *NetworkInterfaceManager) DeploySettings(settings *pb.EthernetInterfac err = DHCPCreateConfigFile(settings.DhcpServerSettings, confName) if err != nil {return err} //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 // 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 - err = StartDHCPServer(ifName, confName) + err = nim.StartDHCPServer(confName) if err != nil {return err} } else { 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) if err != nil { return err } - StartDHCPClient(settings.Name) + nim.StartDHCPClient() } else { log.Printf("Setting Interface %s to DOWN\n", iface.Name) err = netlink.NetworkLinkDown(iface) @@ -224,40 +253,23 @@ func (nim *NetworkInterfaceManager) DeploySettings(settings *pb.EthernetInterfac 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{ + nm: nm, InterfaceName: ifaceName, 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.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 } diff --git a/service/dhcp.go b/service/dhcp.go index 00a1a5d..3bdfac8 100644 --- a/service/dhcp.go +++ b/service/dhcp.go @@ -3,17 +3,22 @@ package service import ( - pb "github.com/mame82/P4wnP1_go/proto" + "bufio" + "bytes" + "errors" "fmt" + "github.com/mame82/P4wnP1_go/common_web" + pb "github.com/mame82/P4wnP1_go/proto" "io/ioutil" + "log" + "net" "os" "os/exec" - "log" - "errors" + "regexp" "strconv" - "syscall" "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 } - - func NameConfigFileDHCPSrv(nameIface string) string { 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) //check if interface is valid @@ -65,7 +69,8 @@ func StartDHCPClient(nameIface string) (err error) { 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 !if_exists { 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) { - log.Printf("Stoping DHCP client for interface '%s'...\n", nameIface) +func (nim *NetworkInterfaceManager) StopDHCPClient() (err error) { + nameIface := nim.InterfaceName + log.Printf("Stopping DHCP client for interface '%s'...\n", nameIface) //check if interface is valid if_exists,_ := CheckInterfaceExistence(nameIface) @@ -125,10 +131,20 @@ func StopDHCPClient(nameIface string) (err error) { 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) { - log.Printf("Starting DHCP server for interface '%s' with config '%s'...\n", nameIface, configPath) + nameIface := nim.InterfaceName + log.Printf("Starting dnsmasq for interface '%s' with config '%s'...\n", nameIface, configPath) //check if interface is valid 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)) } - //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 - proc := exec.Command("/usr/sbin/dnsmasq", "-x", pidFileDHCPSrv(nameIface), "-C", configPath) - //dnsmasq_out, err := proc.CombinedOutput() - err = proc.Run() - if err != nil { return err} - //fmt.Printf("Dnsmasq out %s\n", dnsmasq_out) + nim.CmdDnsmasq = exec.Command("/usr/sbin/dnsmasq", "--log-facility=-", "-k", "-x", pidFileDHCPSrv(nameIface), "-C", configPath) + nim.CmdDnsmasq.Stdout = nim.LoggerDnsmasq.LogWriter + nim.CmdDnsmasq.Stderr = nim.LoggerDnsmasq.LogWriter + + + 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) 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) { - if_exists,_ := CheckInterfaceExistence(nameIface) - if !if_exists { - return false, 0, errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", nameIface)) + log.Println("... killing dnsmasq") + nim.mutexDnsmasq.Lock() + defer nim.mutexDnsmasq.Unlock() + + 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 - content, err := ioutil.ReadFile(pid_file) - 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)) + nim.CmdDnsmasq = nil + log.Println(eSuccess) return nil } - func DHCPCreateConfigFile(s *pb.DHCPServerSettings, filename string) (err error) { file_content, err := DHCPCreateConfigFileString(s) if err != nil {return} @@ -245,12 +216,19 @@ func DHCPCreateConfigFileString(s *pb.DHCPServerSettings) (config string, err er //Iterate over Ranges for _, pRange := range s.Ranges { //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 if len(pRange.LeaseTime) > 0 { config += fmt.Sprintf("dhcp-range=%s,%s,%s\n", pRange.RangeLower, pRange.RangeUpper, pRange.LeaseTime) } else { //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 } +// 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, + } +} diff --git a/service/service.go b/service/service.go index d36b05c..300a795 100644 --- a/service/service.go +++ b/service/service.go @@ -135,7 +135,7 @@ func NewService() (svc *Service, err error) { svc.SubSysEvent = NewEventManager(20) svc.SubSysLed = NewLedService() - svc.SubSysNetwork, err = NewNetworkManager() + svc.SubSysNetwork, err = NewNetworkManager(svc) //Depends on EvenSubSys if err != nil { return nil, err } diff --git a/service/triggerAction.go b/service/triggerAction.go index 9c28778..978fc34 100644 --- a/service/triggerAction.go +++ b/service/triggerAction.go @@ -400,7 +400,7 @@ func (tam *TriggerActionManager) executeActionStartHidScript(evt *pb.Event, ta * case triggerTypeGpioIn: gpioPin := ta.Trigger.(*pb.TriggerAction_GpioIn).GpioIn.GpioNum 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: groupName := ta.Trigger.(*pb.TriggerAction_GroupReceiveSequence).GroupReceiveSequence.GroupName 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() mac := evt.Values[2].GetTstring() ip := evt.Values[3].GetTstring() - preScript += fmt.Sprintf("var DHCP_LEASE_IFACE=%s;\n", iface) - preScript += fmt.Sprintf("var DHCP_LEASE_MAC=%s;\n", mac) - preScript += fmt.Sprintf("var DHCP_LEASE_IP=%s;\n", ip) + host := evt.Values[4].GetTstring() + preScript += fmt.Sprintf("var DHCP_LEASE_IFACE='%s';\n", iface) + 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: 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() mac := evt.Values[2].GetTstring() ip := evt.Values[3].GetTstring() + host := evt.Values[4].GetTstring() env = append(env, fmt.Sprintf("DHCP_LEASE_IFACE=%s", iface), fmt.Sprintf("DHCP_LEASE_MAC=%s", mac), fmt.Sprintf("DHCP_LEASE_IP=%s", ip), + fmt.Sprintf("DHCP_LEASE_HOST=\"%s\"", host), ) case triggerTypeSshLogin: loginUser := evt.Values[1].GetTstring() @@ -530,7 +534,8 @@ func (tam *TriggerActionManager) executeActionLog(evt *pb.Event, ta *pb.TriggerA iface := evt.Values[1].GetTstring() mac := evt.Values[2].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: loginUser := evt.Values[1].GetTstring() logMessage += fmt.Sprintf(" (SSH_LOGIN_USER=%s)", loginUser) diff --git a/service/util/teelogger.go b/service/util/teelogger.go index 9f35c45..9528add 100644 --- a/service/util/teelogger.go +++ b/service/util/teelogger.go @@ -1,10 +1,12 @@ package util import ( + "bufio" + "bytes" "io" "log" - "sync" "os" + "sync" ) type TeeLogger struct { @@ -18,11 +20,29 @@ type sublogger struct { *TeeLogger } +/* // struct to present an additional io.Writer, wrapping TeeLogger to ise its Print() method func (sl sublogger) Write(p []byte) (n int, err error) { sl.TeeLogger.Print(string(p)) 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) { res = &TeeLogger{ @@ -38,6 +58,7 @@ func NewTeeLogger(addStdout bool) (res *TeeLogger) { res.LogWriter = sublogger{ TeeLogger: res } res.SetFlags(log.Ltime) res.SetOutput(res) + log.Println() return res }