Bugfix - First Working
This commit is contained in:
152
main.go
152
main.go
@@ -41,6 +41,10 @@ const (
|
||||
ServiceLogInfo = 1
|
||||
)
|
||||
|
||||
const (
|
||||
ERROR_EVT_INVALID_OPERATION syscall.Errno = 15010
|
||||
)
|
||||
|
||||
const AgentConfigPath = `C:\ProgramData\WinEventForwarder\agent.json`
|
||||
|
||||
type ChannelConfig struct {
|
||||
@@ -181,6 +185,7 @@ func (m *myservice) Execute(args []string, r <-chan svc.ChangeRequest, status ch
|
||||
log.Printf("[%s] Starte Watcher-Chunk %d/%d mit %d IDs",
|
||||
cfg.Name, chunkNo+1, len(chunks), len(cfg.IDs))
|
||||
runChannelWatcher(ctx, hostname, cfg, out)
|
||||
log.Println("Prozess fertig oder abgebrochen", cfg)
|
||||
}(i, workerCfg)
|
||||
}
|
||||
}
|
||||
@@ -325,16 +330,16 @@ func runDebug(cfg *AgentConfig, state *AgentState) {
|
||||
}
|
||||
|
||||
func runChannelWatcher(ctx context.Context, hostname string, cfg ChannelConfig, out chan<- LogPayload) {
|
||||
query := buildXPathQuery(cfg.IDs)
|
||||
query := buildXPathQuery2(cfg.IDs)
|
||||
|
||||
signal, err := windows.CreateEvent(nil, 1, 0, nil)
|
||||
signalEvent, err := windows.CreateEvent(nil, 1, 0, nil)
|
||||
if err != nil {
|
||||
log.Printf("[%s] CreateEvent-Fehler: %v", cfg.Name, err)
|
||||
return
|
||||
}
|
||||
defer windows.CloseHandle(signal)
|
||||
defer windows.CloseHandle(signalEvent)
|
||||
|
||||
sub, err := evtSubscribe(cfg.Name, query, signal, evtSubscribeToFutureEvents)
|
||||
sub, err := evtSubscribe(cfg.Name, query, signalEvent, evtSubscribeToFutureEvents)
|
||||
if err != nil {
|
||||
log.Printf("[%s] Subscribe-Fehler: %v | Query=%s", cfg.Name, err, query)
|
||||
return
|
||||
@@ -343,35 +348,28 @@ func runChannelWatcher(ctx context.Context, hostname string, cfg ChannelConfig,
|
||||
|
||||
log.Printf("[%s] Überwachung gestartet mit Filter %s", cfg.Name, query)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
waitStatus, err := windows.WaitForSingleObject(signal, PollWaitMS)
|
||||
if err != nil {
|
||||
log.Printf("[%s] WaitForSingleObject-Fehler: %v", cfg.Name, err)
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
switch waitStatus {
|
||||
case uint32(windows.WAIT_OBJECT_0):
|
||||
drain := func() {
|
||||
for {
|
||||
events, err := evtNext(sub, BatchSize, 0)
|
||||
if err != nil {
|
||||
if isIgnorableEvtNextError(err) {
|
||||
_ = windows.ResetEvent(signal)
|
||||
continue
|
||||
code := winErrCode(err)
|
||||
|
||||
// Diese Fehler sind bei deinem Polling nicht fatal.
|
||||
if code == windows.ERROR_TIMEOUT ||
|
||||
code == windows.ERROR_NO_MORE_ITEMS ||
|
||||
strings.Contains(strings.ToLower(err.Error()), "operation identifier is not valid") {
|
||||
return
|
||||
}
|
||||
log.Printf("[%s] EvtNext-Fehler: %v", cfg.Name, err)
|
||||
_ = windows.ResetEvent(signal)
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
|
||||
log.Printf("[%s] EvtNext-Fehler: %v | Code=%d", cfg.Name, err, uint32(code))
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[%s] EvtNext lieferte %d Events", cfg.Name, len(events))
|
||||
if len(events) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[%s] %d neue Events gefunden", cfg.Name, len(events))
|
||||
|
||||
for _, h := range events {
|
||||
payload, err := buildPayloadFromEventHandle(hostname, cfg.Name, h)
|
||||
@@ -382,37 +380,64 @@ func runChannelWatcher(ctx context.Context, hostname string, cfg ChannelConfig,
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("[%s] Event empfangen: EventID=%d Source=%s Time=%s",
|
||||
if !cfg.IDs[payload.EventID] {
|
||||
log.Printf("[%s] EventID %d ignoriert, nicht in Filter", cfg.Name, payload.EventID)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("[%s] Event erkannt: ID=%d Source=%s Time=%s",
|
||||
cfg.Name,
|
||||
payload.EventID,
|
||||
payload.Source,
|
||||
payload.Time.Format(time.RFC3339),
|
||||
)
|
||||
|
||||
if !cfg.IDs[payload.EventID] {
|
||||
log.Printf("[%s] Event weggefiltert: EventID=%d", cfg.Name, payload.EventID)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("[%s] Event wird gesendet: EventID=%d", cfg.Name, payload.EventID)
|
||||
|
||||
select {
|
||||
case out <- payload:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_ = windows.ResetEvent(signal)
|
||||
|
||||
case uint32(windows.WAIT_TIMEOUT):
|
||||
continue
|
||||
|
||||
default:
|
||||
log.Printf("[%s] Unerwarteter Wait-Status: %d", cfg.Name, waitStatus)
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
waitStatus, err := windows.WaitForSingleObject(signalEvent, PollWaitMS)
|
||||
if err != nil {
|
||||
log.Printf("[%s] WaitForSingleObject-Fehler: %v", cfg.Name, err)
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
if waitStatus == uint32(windows.WAIT_OBJECT_0) {
|
||||
_ = windows.ResetEvent(signalEvent)
|
||||
drain()
|
||||
continue
|
||||
}
|
||||
|
||||
if waitStatus == uint32(windows.WAIT_TIMEOUT) {
|
||||
// Wichtig: bei dir nötig, weil das Signal offenbar nicht zuverlässig kommt.
|
||||
drain()
|
||||
continue
|
||||
}
|
||||
_ = windows.ResetEvent(signalEvent)
|
||||
log.Printf("[%s] Unerwarteter Wait-Status: %d", cfg.Name, waitStatus)
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func winErrCode(err error) syscall.Errno {
|
||||
var errno syscall.Errno
|
||||
if errors.As(err, &errno) {
|
||||
return errno
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func runSender(
|
||||
@@ -557,6 +582,28 @@ func buildXPathQuery(ids map[uint32]bool) string {
|
||||
return fmt.Sprintf("*[System[(%s)]]", strings.Join(parts, " or "))
|
||||
}
|
||||
|
||||
func buildXPathQuery2(ids map[uint32]bool) string {
|
||||
if len(ids) == 0 {
|
||||
return "*"
|
||||
}
|
||||
|
||||
list := make([]int, 0, len(ids))
|
||||
for id := range ids {
|
||||
list = append(list, int(id))
|
||||
}
|
||||
sort.Ints(list)
|
||||
|
||||
parts := make([]string, 0, len(list))
|
||||
for _, id := range list {
|
||||
// Manche Windows-Versionen bevorzugen EventID ohne System/ davor
|
||||
// innerhalb des System-Knotens.
|
||||
parts = append(parts, fmt.Sprintf("EventID=%d", id))
|
||||
}
|
||||
|
||||
// WICHTIG: Keine unnötigen Leerzeichen innerhalb der XPath-Klammern
|
||||
return fmt.Sprintf("*[System[(%s)]]", strings.Join(parts, " or "))
|
||||
}
|
||||
|
||||
func sendBatch(client *http.Client, backendURL string, state *AgentState, enrollmentKey string, batch []LogPayload) (bool, error) {
|
||||
data, err := json.Marshal(batch)
|
||||
if err != nil {
|
||||
@@ -660,11 +707,14 @@ func evtNext(resultSet windows.Handle, maxHandles uint32, timeout uint32) ([]win
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&returned)),
|
||||
)
|
||||
|
||||
// r1 == 0 bedeutet, die Funktion war nicht erfolgreich (False)
|
||||
if r1 == 0 {
|
||||
if e1 != syscall.Errno(0) {
|
||||
return nil, e1
|
||||
// Wir prüfen, welcher Fehlercode vorliegt
|
||||
if e1 == windows.ERROR_NO_MORE_ITEMS || e1 == windows.ERROR_TIMEOUT {
|
||||
return nil, nil // Das ist kein Fehler, nur das Ende der Schlange
|
||||
}
|
||||
return nil, errors.New("EvtNext fehlgeschlagen")
|
||||
return nil, e1 // Ein echter Windows-Fehler
|
||||
}
|
||||
|
||||
if returned == 0 {
|
||||
@@ -737,9 +787,9 @@ func evtClose(h windows.Handle) error {
|
||||
func isIgnorableEvtNextError(err error) bool {
|
||||
var errno syscall.Errno
|
||||
if errors.As(err, &errno) {
|
||||
if errno == windows.ERROR_TIMEOUT || errno == windows.ERROR_NO_MORE_ITEMS {
|
||||
return true
|
||||
}
|
||||
return errno == windows.ERROR_TIMEOUT ||
|
||||
errno == windows.ERROR_NO_MORE_ITEMS ||
|
||||
errno == ERROR_EVT_INVALID_OPERATION
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
BIN
siem-agent.exe
Normal file
BIN
siem-agent.exe
Normal file
Binary file not shown.
Reference in New Issue
Block a user