From cd878d0d2a6cc9f839f854b00d1056682a180d4f Mon Sep 17 00:00:00 2001 From: Michael Commey <michaelcommey@icloud.com> Date: Thu, 5 Jun 2025 15:58:14 -0400 Subject: [PATCH 01/10] Add event ID filtering for windows logs to CWAgent --- cmd/config-translator/translator_test.go | 1 + .../windows_event_log/windows_event_log.go | 4 +- .../windows_event_log/wineventlog/utils.go | 205 +++--------------- .../wineventlog/utils_test.go | 133 +++--------- .../wineventlog/utils_windows.go | 189 ++++++++++++++++ .../wineventlog/utils_windows_test.go | 134 ++++++++++++ .../wineventlog/wineventlog.go | 6 +- .../wineventlog/wineventlog_test.go | 24 +- translator/config/schema.json | 31 ++- .../sampleConfig/windows_eventids.conf | 48 ++++ .../sampleConfig/windows_eventids.json | 29 +++ .../sampleConfig/windows_eventids.yaml | 37 ++++ .../windows_eventlog_only_config.conf | 5 + .../windows_eventlog_only_config.json | 4 + translator/tocwconfig/tocwconfig_test.go | 7 +- .../tocwconfig/totomlconfig/toTomlConfig.go | 37 +++- .../tomlConfigTemplate/tomlConfig.go | 1 + .../collect_list/collectlist.go | 40 +++- .../collect_list/collectlist_test.go | 124 +++++++++++ .../windows_events/windows_event_test.go | 4 + 20 files changed, 761 insertions(+), 302 deletions(-) create mode 100644 plugins/inputs/windows_event_log/wineventlog/utils_windows.go create mode 100644 plugins/inputs/windows_event_log/wineventlog/utils_windows_test.go create mode 100644 translator/tocwconfig/sampleConfig/windows_eventids.conf create mode 100644 translator/tocwconfig/sampleConfig/windows_eventids.json create mode 100644 translator/tocwconfig/sampleConfig/windows_eventids.yaml diff --git a/cmd/config-translator/translator_test.go b/cmd/config-translator/translator_test.go index b276fc4632..85d2287da8 100644 --- a/cmd/config-translator/translator_test.go +++ b/cmd/config-translator/translator_test.go @@ -103,6 +103,7 @@ func TestLogWindowsEventConfig(t *testing.T) { checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/invalidLogWindowsEventsWithInvalidEventName.json", false, expectedErrorMap) expectedErrorMap1 := map[string]int{} expectedErrorMap1["required"] = 2 + expectedErrorMap1["number_one_of"] = 2 checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/invalidLogWindowsEventsWithMissingEventNameAndLevel.json", false, expectedErrorMap1) expectedErrorMap2 := map[string]int{} expectedErrorMap2["invalid_type"] = 1 diff --git a/plugins/inputs/windows_event_log/windows_event_log.go b/plugins/inputs/windows_event_log/windows_event_log.go index 81f55928d1..8c86722faf 100644 --- a/plugins/inputs/windows_event_log/windows_event_log.go +++ b/plugins/inputs/windows_event_log/windows_event_log.go @@ -31,6 +31,7 @@ var startOnlyOnce sync.Once type EventConfig struct { Name string `toml:"event_name"` Levels []string `toml:"event_levels"` + EventID []int `toml:"event_ids"` RenderFormat string `toml:"event_format"` BatchReadSize int `toml:"batch_read_size"` LogGroupName string `toml:"log_group_name"` @@ -39,7 +40,6 @@ type EventConfig struct { Destination string `toml:"destination"` Retention int `toml:"retention_in_days"` } - type Plugin struct { FileStateFolder string `toml:"file_state_folder"` Events []EventConfig `toml:"event_config"` @@ -60,6 +60,7 @@ func (s *Plugin) SampleConfig() string { [[inputs.windows_event_log.event_config]] event_name = "System" event_levels = ["2", "3"] + event_ids = [1001, 1002] batch_read_size = 1 log_group_name = "System" log_stream_name = "STREAM_NAME" @@ -104,6 +105,7 @@ func (s *Plugin) Start(acc telegraf.Accumulator) error { eventLog := wineventlog.NewEventLog( eventConfig.Name, eventConfig.Levels, + eventConfig.EventID, eventConfig.LogGroupName, eventConfig.LogStreamName, eventConfig.RenderFormat, diff --git a/plugins/inputs/windows_event_log/wineventlog/utils.go b/plugins/inputs/windows_event_log/wineventlog/utils.go index e903670dc1..08986e52e2 100644 --- a/plugins/inputs/windows_event_log/wineventlog/utils.go +++ b/plugins/inputs/windows_event_log/wineventlog/utils.go @@ -1,29 +1,18 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: MIT -//go:build windows -// +build windows - package wineventlog import ( - "bytes" "fmt" - "io" - "log" - "strconv" - "strings" - "syscall" "time" - - "golang.org/x/text/encoding/unicode" - "golang.org/x/text/transform" ) const ( bookmarkTemplate = `<BookmarkList><Bookmark Channel="%s" RecordId="%d" IsCurrent="True"/></BookmarkList>` eventLogQueryTemplate = `<QueryList><Query Id="0"><Select Path="%s">%s</Select></Query></QueryList>` eventLogLevelFilter = "Level='%s'" + eventLogeventIDFilter = "EventID='%d'" eventIgnoreOldFilter = "TimeCreated[timediff(@SystemTime) <= %d]" emptySpaceScanLength = 100 UnknownBytesPerCharacter = 0 @@ -36,34 +25,7 @@ const ( UNKNOWN = "UNKNOWN" ) -var NumberOfBytesPerCharacter = UnknownBytesPerCharacter - -func RenderEventXML(eventHandle EvtHandle, renderBuf []byte) ([]byte, error) { - var bufferUsed, propertyCount uint32 - - if err := EvtRender(0, eventHandle, EvtRenderEventXml, uint32(len(renderBuf)), &renderBuf[0], &bufferUsed, &propertyCount); err != nil { - return nil, fmt.Errorf("error when rendering events. Details: %v", err) - } - - // Per MSDN as of Mar 14th 2022(https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtrender) - // EvtRender function is still returning buffer used as BYTES, not characters. So keep using utf16ToUTF8Bytes() - return utf16ToUTF8Bytes(renderBuf, bufferUsed) -} - -func CreateBookmark(channel string, recordID uint64) (h EvtHandle, err error) { - xml := fmt.Sprintf(bookmarkTemplate, channel, recordID) - p, err := syscall.UTF16PtrFromString(xml) - if err != nil { - return 0, err - } - h, err = EvtCreateBookmark(p) - if err != nil { - return 0, fmt.Errorf("error when creating a bookmark. Details: %v", err) - } - return h, nil -} - -func CreateQuery(path string, levels []string) (*uint16, error) { +func createFilterQuery(levels []string, eventIDs []int) string { var filterLevels string for _, level := range levels { if filterLevels == "" { @@ -73,149 +35,38 @@ func CreateQuery(path string, levels []string) (*uint16, error) { } } - //Ignore events older than 2 weeks - cutOffPeriod := (time.Hour * 24 * 14).Nanoseconds() - ignoreOlderThanTwoWeeksFilter := fmt.Sprintf(eventIgnoreOldFilter, cutOffPeriod/int64(time.Millisecond)) - if filterLevels != "" { - filterLevels = "*[System[(" + filterLevels + ") and " + ignoreOlderThanTwoWeeksFilter + "]]" - } else { - filterLevels = "*[System[" + ignoreOlderThanTwoWeeksFilter + "]]" - } - - xml := fmt.Sprintf(eventLogQueryTemplate, path, filterLevels) - return syscall.UTF16PtrFromString(xml) -} - -func utf16ToUTF8Bytes(in []byte, length uint32) ([]byte, error) { - - i := length - - if length%2 != 0 { - i = length - 1 - } - - for ; i-2 > 0; i -= 2 { - v1 := uint16(in[i-2]) | uint16(in[i-1])<<8 - // Stop at non-null char. - if v1 != 0 { - break - } - } - - win16be := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM) - utf16bom := unicode.BOMOverride(win16be.NewDecoder()) - unicodeReader := transform.NewReader(bytes.NewReader(in[:i]), utf16bom) - decoded, err := io.ReadAll(unicodeReader) - return decoded, err -} - -func UTF16ToUTF8BytesForWindowsEventBuffer(in []byte, length uint32) ([]byte, error) { - // Since Windows server 2022, the returned value of used buffer represents for double bytes char count, - // which is half of the actual buffer used by byte(what older Windows OS returns), checking if the length - //land on the end of used buffer, if no, double it. - if NumberOfBytesPerCharacter == UnknownBytesPerCharacter { - if isTheEndOfContent(in, length) { - log.Printf("I! Buffer used: %d is returning as single byte character count", length) - NumberOfBytesPerCharacter = 1 + //EventID filtering + var filterEventID string + for i, eventID := range eventIDs { + if i == 0 { + filterEventID = fmt.Sprintf(eventLogeventIDFilter, eventID) } else { - log.Printf("I! Buffer used: %d is returning as double byte character count, doubling it to get the whole buffer content.", length) - NumberOfBytesPerCharacter = 2 - } - } - - i := int(length) * NumberOfBytesPerCharacter - - if i > cap(in) { - i = cap(in) - } - - return utf16ToUTF8Bytes(in, uint32(i)) -} - -func isTheEndOfContent(in []byte, length uint32) bool { - // scan next (emptySpaceScanLength) bytes, if any of them is none '0', return false - i := int(length) - - if i%2 != 0 { - i -= 1 - } - max := len(in) - if i+emptySpaceScanLength < max { - max = i + emptySpaceScanLength - } - - for ; i < max-2; i += 2 { - v1 := uint16(in[i+2]) | uint16(in[i+1])<<8 - // Stop at non-null char. - if v1 != 0 { - return false + filterEventID = filterEventID + " or " + fmt.Sprintf(eventLogeventIDFilter, eventID) } } - return true -} -func WindowsEventLogLevelName(levelId int32) string { - switch levelId { - case 1: - return CRITICAL - case 2: - return ERROR - case 3: - return WARNING - case 0, 4: - return INFORMATION - case 5: - return VERBOSE - default: - return UNKNOWN + //query results + var query string + if filterLevels != "" && filterEventID != "" { + query = filterLevels + " and " + filterEventID + } else if filterLevels != "" && filterEventID == "" { + query = filterLevels + } else if filterLevels == "" && filterEventID != "" { + query = filterEventID } -} - -// insertPlaceholderValues formats the message with the correct values if we see those data -// in evtDataValues. -// -// In some cases wevtapi does not insert values when formatting the message. The message -// will contain insertion string placeholders, of the form %n, where %1 indicates the first -// insertion string, and so on. Noted that wevtapi start the index with 1. -// https://learn.microsoft.com/en-us/windows/win32/eventlog/event-identifiers#insertion-strings -func insertPlaceholderValues(rawMessage string, evtDataValues []Datum) string { - if len(evtDataValues) == 0 || len(rawMessage) == 0 { - return rawMessage - } - var sb strings.Builder - prevIndex := 0 - searchingIndex := false - for i, c := range rawMessage { - // found `%` previously. Determine the index number from the following character(s) - if searchingIndex && (c > '9' || c < '0') { - // Convert the Slice since the last `%` and see if it's a valid number. - ind, err := strconv.Atoi(rawMessage[prevIndex+1 : i]) - // If the index is in [1 - len(evtDataValues)], get it from evtDataValues. - if err == nil && ind <= len(evtDataValues) && ind > 0 { - sb.WriteString(evtDataValues[ind-1].Value) - } else { - sb.WriteString(rawMessage[prevIndex:i]) - } - prevIndex = i - // In case of consecutive `%`, continue searching for the next index - if c != '%' { - searchingIndex = false - } - } else { - if c == '%' { - sb.WriteString(rawMessage[prevIndex:i]) - searchingIndex = true - prevIndex = i - } - } - } - // handle the slice since the last `%` to the end of rawMessage - ind, err := strconv.Atoi(rawMessage[prevIndex+1:]) - if searchingIndex && err == nil && ind <= len(evtDataValues) && ind > 0 { - sb.WriteString(evtDataValues[ind-1].Value) + //Ignore events older than 2 weeks + cutOffPeriod := (time.Hour * 24 * 14).Nanoseconds() + ignoreOlderThanTwoWeeksFilter := fmt.Sprintf(eventIgnoreOldFilter, cutOffPeriod/int64(time.Millisecond)) + if filterLevels != "" && filterEventID != "" { + query = "*[System[(" + query + ") and " + ignoreOlderThanTwoWeeksFilter + "]]" + } else if filterLevels != "" { + query = "*[System[(" + filterLevels + ") and " + ignoreOlderThanTwoWeeksFilter + "]]" + } else if filterEventID != "" { + query = "*[System[(" + filterEventID + ") and " + ignoreOlderThanTwoWeeksFilter + "]]" } else { - sb.WriteString(rawMessage[prevIndex:]) + query = "*[System[" + ignoreOlderThanTwoWeeksFilter + "]]" } - return sb.String() + + return query } diff --git a/plugins/inputs/windows_event_log/wineventlog/utils_test.go b/plugins/inputs/windows_event_log/wineventlog/utils_test.go index 40586504d3..8c768bd1cf 100644 --- a/plugins/inputs/windows_event_log/wineventlog/utils_test.go +++ b/plugins/inputs/windows_event_log/wineventlog/utils_test.go @@ -1,134 +1,51 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: MIT -//go:build windows -// +build windows - package wineventlog import ( - "encoding/hex" "testing" "github.com/stretchr/testify/assert" ) -func TestPayload_Value(t *testing.T) { - // one null test - resetState() - originalHexStr := "3c004500760065006e007400200078006d006c006e0073003d00270068007400740070003a002f002f0073006300680065006d00610073002e006d006900630072006f0073006f00660074002e0063006f006d002f00770069006e002f0032003000300034002f00300038002f006500760065006e00740073002f006500760065006e00740027003e003c00530079007300740065006d003e003c00500072006f007600690064006500720020004e0061006d0065003d0027004d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d00530065006300750072006900740079002d004100750064006900740069006e0067002700200047007500690064003d0027007b00350034003800340039003600320035002d0035003400370038002d0034003900390034002d0041003500420041002d003300450033004200300033003200380043003300300044007d0027002f003e003c004500760065006e007400490044003e0034003600320035003c002f004500760065006e007400490044003e003c00560065007200730069006f006e003e0030003c002f00560065007200730069006f006e003e003c004c006500760065006c003e0030003c002f004c006500760065006c003e003c005400610073006b003e00310032003500340034003c002f005400610073006b003e003c004f00700063006f00640065003e0030003c002f004f00700063006f00640065003e003c004b006500790077006f007200640073003e003000780038003000310030003000300030003000300030003000300030003000300030003c002f004b006500790077006f007200640073003e003c00540069006d00650043007200650061007400650064002000530079007300740065006d00540069006d0065003d00270032003000310039002d00300035002d00300035005400320033003a00310032003a00330037002e003300340039003400370036003100300030005a0027002f003e003c004500760065006e0074005200650063006f0072006400490044003e003600390034003600370034003c002f004500760065006e0074005200650063006f0072006400490044003e003c0043006f007200720065006c006100740069006f006e00200041006300740069007600690074007900490044003d0027007b00320035003200320035004600410031002d0044004100420039002d0030003000300031002d0041003600350046002d003200320032003500420039004400410044003400300031007d0027002f003e003c0045007800650063007500740069006f006e002000500072006f006300650073007300490044003d00270038003000340027002000540068007200650061006400490044003d002700310030003800300027002f003e003c004300680061006e006e0065006c003e00530065006300750072006900740079003c002f004300680061006e006e0065006c003e003c0043006f006d00700075007400650072003e0045004300320041004d0041005a002d0035004a00360049004600530046003c002f0043006f006d00700075007400650072003e003c00530065006300750072006900740079002f003e003c002f00530079007300740065006d003e003c004500760065006e00740044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a00650063007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740055007300650072004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740044006f006d00610069006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a006500630074004c006f0067006f006e004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700540061007200670065007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740055007300650072004e0061006d00650027003e00410044004d0049004e004900530054005200410054004f0052003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740044006f006d00610069006e004e0061006d00650027003e003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007400610074007500730027003e0030007800630030003000300030003000360064003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004600610069006c0075007200650052006500610073006f006e0027003e002500250032003300310033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007500620053007400610074007500730027003e0030007800630030003000300030003000360061003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00540079007000650027003e0033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00500072006f0063006500730073004e0061006d00650027003e004e0074004c006d0053007300700020003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700410075007400680065006e007400690063006100740069006f006e005000610063006b006100670065004e0061006d00650027003e004e0054004c004d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270057006f0072006b00730074006100740069006f006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005400720061006e0073006d00690074007400650064005300650072007600690063006500730027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006d005000610063006b006100670065004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004b00650079004c0065006e0067007400680027003e0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270049007000410064006400720065007300730027003e003100340036002e00350036002e0036002e003100360036003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004900700050006f007200740027003e0030003c002f0044006100740061003e003c002f004500760065006e00740044006100740061003e003c002f004500760065006e0074003e000000" - data, _ := hex.DecodeString(originalHexStr) - bufferUsed := len(data) - bytes, _ := UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) - str := string(bytes[:]) - assert.Equal(t, "<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/><EventID>4625</EventID><Version>0</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8010000000000000</Keywords><TimeCreated SystemTime='2019-05-05T23:12:37.349476100Z'/><EventRecordID>694674</EventRecordID><Correlation ActivityID='{25225FA1-DAB9-0001-A65F-2225B9DAD401}'/><Execution ProcessID='804' ThreadID='1080'/><Channel>Security</Channel><Computer>EC2AMAZ-5J6IFSF</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>ADMINISTRATOR</Data><Data Name='TargetDomainName'></Data><Data Name='Status'>0xc000006d</Data><Data Name='FailureReason'>%%2313</Data><Data Name='SubStatus'>0xc000006a</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>NtLmSsp </Data><Data Name='AuthenticationPackageName'>NTLM</Data><Data Name='WorkstationName'>-</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>146.56.6.166</Data><Data Name='IpPort'>0</Data></EventData></Event>", str) - - // odd bytes test - originalHexStr = "3c004500760065006e007400200078006d006c006e0073003d00270068007400740070003a002f002f0073006300680065006d00610073002e006d006900630072006f0073006f00660074002e0063006f006d002f00770069006e002f0032003000300034002f00300038002f006500760065006e00740073002f006500760065006e00740027003e003c00530079007300740065006d003e003c00500072006f007600690064006500720020004e0061006d0065003d0027004d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d00530065006300750072006900740079002d004100750064006900740069006e0067002700200047007500690064003d0027007b00350034003800340039003600320035002d0035003400370038002d0034003900390034002d0041003500420041002d003300450033004200300033003200380043003300300044007d0027002f003e003c004500760065006e007400490044003e0034003600320035003c002f004500760065006e007400490044003e003c00560065007200730069006f006e003e0030003c002f00560065007200730069006f006e003e003c004c006500760065006c003e0030003c002f004c006500760065006c003e003c005400610073006b003e00310032003500340034003c002f005400610073006b003e003c004f00700063006f00640065003e0030003c002f004f00700063006f00640065003e003c004b006500790077006f007200640073003e003000780038003000310030003000300030003000300030003000300030003000300030003c002f004b006500790077006f007200640073003e003c00540069006d00650043007200650061007400650064002000530079007300740065006d00540069006d0065003d00270032003000310039002d00300035002d00300035005400320033003a00310032003a00330037002e003300340039003400370036003100300030005a0027002f003e003c004500760065006e0074005200650063006f0072006400490044003e003600390034003600370034003c002f004500760065006e0074005200650063006f0072006400490044003e003c0043006f007200720065006c006100740069006f006e00200041006300740069007600690074007900490044003d0027007b00320035003200320035004600410031002d0044004100420039002d0030003000300031002d0041003600350046002d003200320032003500420039004400410044003400300031007d0027002f003e003c0045007800650063007500740069006f006e002000500072006f006300650073007300490044003d00270038003000340027002000540068007200650061006400490044003d002700310030003800300027002f003e003c004300680061006e006e0065006c003e00530065006300750072006900740079003c002f004300680061006e006e0065006c003e003c0043006f006d00700075007400650072003e0045004300320041004d0041005a002d0035004a00360049004600530046003c002f0043006f006d00700075007400650072003e003c00530065006300750072006900740079002f003e003c002f00530079007300740065006d003e003c004500760065006e00740044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a00650063007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740055007300650072004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740044006f006d00610069006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a006500630074004c006f0067006f006e004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700540061007200670065007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740055007300650072004e0061006d00650027003e00410044004d0049004e004900530054005200410054004f0052003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740044006f006d00610069006e004e0061006d00650027003e003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007400610074007500730027003e0030007800630030003000300030003000360064003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004600610069006c0075007200650052006500610073006f006e0027003e002500250032003300310033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007500620053007400610074007500730027003e0030007800630030003000300030003000360061003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00540079007000650027003e0033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00500072006f0063006500730073004e0061006d00650027003e004e0074004c006d0053007300700020003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700410075007400680065006e007400690063006100740069006f006e005000610063006b006100670065004e0061006d00650027003e004e0054004c004d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270057006f0072006b00730074006100740069006f006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005400720061006e0073006d00690074007400650064005300650072007600690063006500730027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006d005000610063006b006100670065004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004b00650079004c0065006e0067007400680027003e0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270049007000410064006400720065007300730027003e003100340036002e00350036002e0036002e003100360036003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004900700050006f007200740027003e0030003c002f0044006100740061003e003c002f004500760065006e00740044006100740061003e003c002f004500760065006e0074003e00000000" - data, _ = hex.DecodeString(originalHexStr) - bufferUsed = len(data) - bytes, _ = UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) - str = string(bytes[:]) - assert.Equal(t, "<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/><EventID>4625</EventID><Version>0</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8010000000000000</Keywords><TimeCreated SystemTime='2019-05-05T23:12:37.349476100Z'/><EventRecordID>694674</EventRecordID><Correlation ActivityID='{25225FA1-DAB9-0001-A65F-2225B9DAD401}'/><Execution ProcessID='804' ThreadID='1080'/><Channel>Security</Channel><Computer>EC2AMAZ-5J6IFSF</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>ADMINISTRATOR</Data><Data Name='TargetDomainName'></Data><Data Name='Status'>0xc000006d</Data><Data Name='FailureReason'>%%2313</Data><Data Name='SubStatus'>0xc000006a</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>NtLmSsp </Data><Data Name='AuthenticationPackageName'>NTLM</Data><Data Name='WorkstationName'>-</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>146.56.6.166</Data><Data Name='IpPort'>0</Data></EventData></Event>", str) - - // two nulls test - originalHexStr = "3c004500760065006e007400200078006d006c006e0073003d00270068007400740070003a002f002f0073006300680065006d00610073002e006d006900630072006f0073006f00660074002e0063006f006d002f00770069006e002f0032003000300034002f00300038002f006500760065006e00740073002f006500760065006e00740027003e003c00530079007300740065006d003e003c00500072006f007600690064006500720020004e0061006d0065003d0027004d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d00530065006300750072006900740079002d004100750064006900740069006e0067002700200047007500690064003d0027007b00350034003800340039003600320035002d0035003400370038002d0034003900390034002d0041003500420041002d003300450033004200300033003200380043003300300044007d0027002f003e003c004500760065006e007400490044003e0034003600320035003c002f004500760065006e007400490044003e003c00560065007200730069006f006e003e0030003c002f00560065007200730069006f006e003e003c004c006500760065006c003e0030003c002f004c006500760065006c003e003c005400610073006b003e00310032003500340034003c002f005400610073006b003e003c004f00700063006f00640065003e0030003c002f004f00700063006f00640065003e003c004b006500790077006f007200640073003e003000780038003000310030003000300030003000300030003000300030003000300030003c002f004b006500790077006f007200640073003e003c00540069006d00650043007200650061007400650064002000530079007300740065006d00540069006d0065003d00270032003000310039002d00300035002d00300035005400320033003a00310032003a00330037002e003300340039003400370036003100300030005a0027002f003e003c004500760065006e0074005200650063006f0072006400490044003e003600390034003600370034003c002f004500760065006e0074005200650063006f0072006400490044003e003c0043006f007200720065006c006100740069006f006e00200041006300740069007600690074007900490044003d0027007b00320035003200320035004600410031002d0044004100420039002d0030003000300031002d0041003600350046002d003200320032003500420039004400410044003400300031007d0027002f003e003c0045007800650063007500740069006f006e002000500072006f006300650073007300490044003d00270038003000340027002000540068007200650061006400490044003d002700310030003800300027002f003e003c004300680061006e006e0065006c003e00530065006300750072006900740079003c002f004300680061006e006e0065006c003e003c0043006f006d00700075007400650072003e0045004300320041004d0041005a002d0035004a00360049004600530046003c002f0043006f006d00700075007400650072003e003c00530065006300750072006900740079002f003e003c002f00530079007300740065006d003e003c004500760065006e00740044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a00650063007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740055007300650072004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740044006f006d00610069006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a006500630074004c006f0067006f006e004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700540061007200670065007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740055007300650072004e0061006d00650027003e00410044004d0049004e004900530054005200410054004f0052003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740044006f006d00610069006e004e0061006d00650027003e003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007400610074007500730027003e0030007800630030003000300030003000360064003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004600610069006c0075007200650052006500610073006f006e0027003e002500250032003300310033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007500620053007400610074007500730027003e0030007800630030003000300030003000360061003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00540079007000650027003e0033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00500072006f0063006500730073004e0061006d00650027003e004e0074004c006d0053007300700020003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700410075007400680065006e007400690063006100740069006f006e005000610063006b006100670065004e0061006d00650027003e004e0054004c004d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270057006f0072006b00730074006100740069006f006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005400720061006e0073006d00690074007400650064005300650072007600690063006500730027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006d005000610063006b006100670065004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004b00650079004c0065006e0067007400680027003e0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270049007000410064006400720065007300730027003e003100340036002e00350036002e0036002e003100360036003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004900700050006f007200740027003e0030003c002f0044006100740061003e003c002f004500760065006e00740044006100740061003e003c002f004500760065006e0074003e000000000000" - data, _ = hex.DecodeString(originalHexStr) - bufferUsed = len(data) - bytes, _ = UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) - str = string(bytes[:]) - assert.Equal(t, "<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/><EventID>4625</EventID><Version>0</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8010000000000000</Keywords><TimeCreated SystemTime='2019-05-05T23:12:37.349476100Z'/><EventRecordID>694674</EventRecordID><Correlation ActivityID='{25225FA1-DAB9-0001-A65F-2225B9DAD401}'/><Execution ProcessID='804' ThreadID='1080'/><Channel>Security</Channel><Computer>EC2AMAZ-5J6IFSF</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>ADMINISTRATOR</Data><Data Name='TargetDomainName'></Data><Data Name='Status'>0xc000006d</Data><Data Name='FailureReason'>%%2313</Data><Data Name='SubStatus'>0xc000006a</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>NtLmSsp </Data><Data Name='AuthenticationPackageName'>NTLM</Data><Data Name='WorkstationName'>-</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>146.56.6.166</Data><Data Name='IpPort'>0</Data></EventData></Event>", str) - -} - -func TestDecodingWithDifferentBufferUsedReturned(t *testing.T) { - // one null test - resetState() - originalHexStr := "3c004500760065006e007400200078006d006c006e0073003d00270068007400740070003a002f002f0073006300680065006d00610073002e006d006900630072006f0073006f00660074002e0063006f006d002f00770069006e002f0032003000300034002f00300038002f006500760065006e00740073002f006500760065006e00740027003e003c00530079007300740065006d003e003c00500072006f007600690064006500720020004e0061006d0065003d0027004d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d00530065006300750072006900740079002d004100750064006900740069006e0067002700200047007500690064003d0027007b00350034003800340039003600320035002d0035003400370038002d0034003900390034002d0041003500420041002d003300450033004200300033003200380043003300300044007d0027002f003e003c004500760065006e007400490044003e0034003600320035003c002f004500760065006e007400490044003e003c00560065007200730069006f006e003e0030003c002f00560065007200730069006f006e003e003c004c006500760065006c003e0030003c002f004c006500760065006c003e003c005400610073006b003e00310032003500340034003c002f005400610073006b003e003c004f00700063006f00640065003e0030003c002f004f00700063006f00640065003e003c004b006500790077006f007200640073003e003000780038003000310030003000300030003000300030003000300030003000300030003c002f004b006500790077006f007200640073003e003c00540069006d00650043007200650061007400650064002000530079007300740065006d00540069006d0065003d00270032003000310039002d00300035002d00300035005400320033003a00310032003a00330037002e003300340039003400370036003100300030005a0027002f003e003c004500760065006e0074005200650063006f0072006400490044003e003600390034003600370034003c002f004500760065006e0074005200650063006f0072006400490044003e003c0043006f007200720065006c006100740069006f006e00200041006300740069007600690074007900490044003d0027007b00320035003200320035004600410031002d0044004100420039002d0030003000300031002d0041003600350046002d003200320032003500420039004400410044003400300031007d0027002f003e003c0045007800650063007500740069006f006e002000500072006f006300650073007300490044003d00270038003000340027002000540068007200650061006400490044003d002700310030003800300027002f003e003c004300680061006e006e0065006c003e00530065006300750072006900740079003c002f004300680061006e006e0065006c003e003c0043006f006d00700075007400650072003e0045004300320041004d0041005a002d0035004a00360049004600530046003c002f0043006f006d00700075007400650072003e003c00530065006300750072006900740079002f003e003c002f00530079007300740065006d003e003c004500760065006e00740044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a00650063007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740055007300650072004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740044006f006d00610069006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a006500630074004c006f0067006f006e004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700540061007200670065007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740055007300650072004e0061006d00650027003e00410044004d0049004e004900530054005200410054004f0052003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740044006f006d00610069006e004e0061006d00650027003e003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007400610074007500730027003e0030007800630030003000300030003000360064003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004600610069006c0075007200650052006500610073006f006e0027003e002500250032003300310033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007500620053007400610074007500730027003e0030007800630030003000300030003000360061003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00540079007000650027003e0033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00500072006f0063006500730073004e0061006d00650027003e004e0074004c006d0053007300700020003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700410075007400680065006e007400690063006100740069006f006e005000610063006b006100670065004e0061006d00650027003e004e0054004c004d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270057006f0072006b00730074006100740069006f006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005400720061006e0073006d00690074007400650064005300650072007600690063006500730027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006d005000610063006b006100670065004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004b00650079004c0065006e0067007400680027003e0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270049007000410064006400720065007300730027003e003100340036002e00350036002e0036002e003100360036003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004900700050006f007200740027003e0030003c002f0044006100740061003e003c002f004500760065006e00740044006100740061003e003c002f004500760065006e0074003e000000" - data, _ := hex.DecodeString(originalHexStr) - bufferUsed := len(data) / 2 - bytes, _ := UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) - str := string(bytes[:]) - assert.Equal(t, "<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/><EventID>4625</EventID><Version>0</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8010000000000000</Keywords><TimeCreated SystemTime='2019-05-05T23:12:37.349476100Z'/><EventRecordID>694674</EventRecordID><Correlation ActivityID='{25225FA1-DAB9-0001-A65F-2225B9DAD401}'/><Execution ProcessID='804' ThreadID='1080'/><Channel>Security</Channel><Computer>EC2AMAZ-5J6IFSF</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>ADMINISTRATOR</Data><Data Name='TargetDomainName'></Data><Data Name='Status'>0xc000006d</Data><Data Name='FailureReason'>%%2313</Data><Data Name='SubStatus'>0xc000006a</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>NtLmSsp </Data><Data Name='AuthenticationPackageName'>NTLM</Data><Data Name='WorkstationName'>-</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>146.56.6.166</Data><Data Name='IpPort'>0</Data></EventData></Event>", str) - - // odd bytes test - originalHexStr = "3c004500760065006e007400200078006d006c006e0073003d00270068007400740070003a002f002f0073006300680065006d00610073002e006d006900630072006f0073006f00660074002e0063006f006d002f00770069006e002f0032003000300034002f00300038002f006500760065006e00740073002f006500760065006e00740027003e003c00530079007300740065006d003e003c00500072006f007600690064006500720020004e0061006d0065003d0027004d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d00530065006300750072006900740079002d004100750064006900740069006e0067002700200047007500690064003d0027007b00350034003800340039003600320035002d0035003400370038002d0034003900390034002d0041003500420041002d003300450033004200300033003200380043003300300044007d0027002f003e003c004500760065006e007400490044003e0034003600320035003c002f004500760065006e007400490044003e003c00560065007200730069006f006e003e0030003c002f00560065007200730069006f006e003e003c004c006500760065006c003e0030003c002f004c006500760065006c003e003c005400610073006b003e00310032003500340034003c002f005400610073006b003e003c004f00700063006f00640065003e0030003c002f004f00700063006f00640065003e003c004b006500790077006f007200640073003e003000780038003000310030003000300030003000300030003000300030003000300030003c002f004b006500790077006f007200640073003e003c00540069006d00650043007200650061007400650064002000530079007300740065006d00540069006d0065003d00270032003000310039002d00300035002d00300035005400320033003a00310032003a00330037002e003300340039003400370036003100300030005a0027002f003e003c004500760065006e0074005200650063006f0072006400490044003e003600390034003600370034003c002f004500760065006e0074005200650063006f0072006400490044003e003c0043006f007200720065006c006100740069006f006e00200041006300740069007600690074007900490044003d0027007b00320035003200320035004600410031002d0044004100420039002d0030003000300031002d0041003600350046002d003200320032003500420039004400410044003400300031007d0027002f003e003c0045007800650063007500740069006f006e002000500072006f006300650073007300490044003d00270038003000340027002000540068007200650061006400490044003d002700310030003800300027002f003e003c004300680061006e006e0065006c003e00530065006300750072006900740079003c002f004300680061006e006e0065006c003e003c0043006f006d00700075007400650072003e0045004300320041004d0041005a002d0035004a00360049004600530046003c002f0043006f006d00700075007400650072003e003c00530065006300750072006900740079002f003e003c002f00530079007300740065006d003e003c004500760065006e00740044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a00650063007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740055007300650072004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740044006f006d00610069006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a006500630074004c006f0067006f006e004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700540061007200670065007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740055007300650072004e0061006d00650027003e00410044004d0049004e004900530054005200410054004f0052003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740044006f006d00610069006e004e0061006d00650027003e003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007400610074007500730027003e0030007800630030003000300030003000360064003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004600610069006c0075007200650052006500610073006f006e0027003e002500250032003300310033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007500620053007400610074007500730027003e0030007800630030003000300030003000360061003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00540079007000650027003e0033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00500072006f0063006500730073004e0061006d00650027003e004e0074004c006d0053007300700020003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700410075007400680065006e007400690063006100740069006f006e005000610063006b006100670065004e0061006d00650027003e004e0054004c004d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270057006f0072006b00730074006100740069006f006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005400720061006e0073006d00690074007400650064005300650072007600690063006500730027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006d005000610063006b006100670065004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004b00650079004c0065006e0067007400680027003e0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270049007000410064006400720065007300730027003e003100340036002e00350036002e0036002e003100360036003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004900700050006f007200740027003e0030003c002f0044006100740061003e003c002f004500760065006e00740044006100740061003e003c002f004500760065006e0074003e00000000" - data, _ = hex.DecodeString(originalHexStr) - bufferUsed = len(data) / 2 - bytes, _ = UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) - str = string(bytes[:]) - assert.Equal(t, "<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/><EventID>4625</EventID><Version>0</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8010000000000000</Keywords><TimeCreated SystemTime='2019-05-05T23:12:37.349476100Z'/><EventRecordID>694674</EventRecordID><Correlation ActivityID='{25225FA1-DAB9-0001-A65F-2225B9DAD401}'/><Execution ProcessID='804' ThreadID='1080'/><Channel>Security</Channel><Computer>EC2AMAZ-5J6IFSF</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>ADMINISTRATOR</Data><Data Name='TargetDomainName'></Data><Data Name='Status'>0xc000006d</Data><Data Name='FailureReason'>%%2313</Data><Data Name='SubStatus'>0xc000006a</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>NtLmSsp </Data><Data Name='AuthenticationPackageName'>NTLM</Data><Data Name='WorkstationName'>-</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>146.56.6.166</Data><Data Name='IpPort'>0</Data></EventData></Event>", str) - -} - -func TestFullBufferUsedWithHalfUsedSizeReturned(t *testing.T) { - resetState() - cap := 1 << 10 - data := make([]byte, cap) - data[0] = 'a' - for i := 2; i < cap; i *= 2 { - copy(data[i:], data[:i]) - } - bufferUsed := cap / 2 - - bytes, _ := UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) - str := string(bytes[:]) - assert.Equal(t, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", str) - assert.Equal(t, bufferUsed, len(str)) -} - -func TestInsertPlaceholderValues(t *testing.T) { - evtDataValues := []Datum{ - {"value_1"}, {"value_2"}, {"value_3"}, {"value_4"}, - } +func TestCreateFilterQuery(t *testing.T) { tests := []struct { name string - message string - expected string + levels []string + eventIDs []int + want string }{ { - "Placeholders %{number} should be replaced by insertion strings", - "Service %1 in region %3 stop at %2", - "Service value_1 in region value_3 stop at value_2", - }, - { - "String without a placeholder should remain the same after insertion", - "This is a sentence without placeholders", - "This is a sentence without placeholders", - }, - { - "Empty string should remain the same", - "", - "", - }, - { - "Index should start from 1 and less than or equal to the amount of values in event data", - "%0 %3 %5", - "%0 value_3 %5", + name: "levels_Test", + levels: []string{"Error", "Critical"}, + eventIDs: []int{}, + want: "*[System[(Level='Error' or Level='Critical') and TimeCreated[timediff(@SystemTime) <= 1209600000]]]", }, { - "Handle consecutive % characters", - "%1 %%3% %2", - "value_1 %value_3% value_2", + name: "EventID_Test", + levels: []string{}, + eventIDs: []int{1001, 1002}, + want: "*[System[(EventID='1001' or EventID='1002') and TimeCreated[timediff(@SystemTime) <= 1209600000]]]", }, { - "Handle % character at the end of message", - "%3 %2%", - "value_3 value_2%", + name: "levels_EventID_Test", + levels: []string{"Error"}, + eventIDs: []int{4625}, + want: "*[System[(Level='Error' and EventID='4625') and TimeCreated[timediff(@SystemTime) <= 1209600000]]]", }, { - "Characters after a % other than numbers should be ignored", - "%foo, %foo1, %#$%^&1", - "%foo, %foo1, %#$%^&1", + name: "no_Input", + levels: []string{}, + eventIDs: []int{}, + want: "*[System[TimeCreated[timediff(@SystemTime) <= 1209600000]]]", }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.expected, insertPlaceholderValues(tc.message, evtDataValues)) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := createFilterQuery(tt.levels, tt.eventIDs) + assert.Equal(t, tt.want, got) + }) } } - -func resetState() { - NumberOfBytesPerCharacter = 0 -} diff --git a/plugins/inputs/windows_event_log/wineventlog/utils_windows.go b/plugins/inputs/windows_event_log/wineventlog/utils_windows.go new file mode 100644 index 0000000000..4f02167de2 --- /dev/null +++ b/plugins/inputs/windows_event_log/wineventlog/utils_windows.go @@ -0,0 +1,189 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +//go:build windows +// +build windows + +package wineventlog + +import ( + "bytes" + "fmt" + "io" + "log" + "strconv" + "strings" + "syscall" + + "golang.org/x/text/encoding/unicode" + "golang.org/x/text/transform" +) + +var NumberOfBytesPerCharacter = UnknownBytesPerCharacter + +func RenderEventXML(eventHandle EvtHandle, renderBuf []byte) ([]byte, error) { + var bufferUsed, propertyCount uint32 + + if err := EvtRender(0, eventHandle, EvtRenderEventXml, uint32(len(renderBuf)), &renderBuf[0], &bufferUsed, &propertyCount); err != nil { + return nil, fmt.Errorf("error when rendering events. Details: %v", err) + } + + // Per MSDN as of Mar 14th 2022(https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtrender) + // EvtRender function is still returning buffer used as BYTES, not characters. So keep using utf16ToUTF8Bytes() + return utf16ToUTF8Bytes(renderBuf, bufferUsed) +} + +func CreateBookmark(channel string, recordID uint64) (h EvtHandle, err error) { + xml := fmt.Sprintf(bookmarkTemplate, channel, recordID) + p, err := syscall.UTF16PtrFromString(xml) + if err != nil { + return 0, err + } + h, err = EvtCreateBookmark(p) + if err != nil { + return 0, fmt.Errorf("error when creating a bookmark. Details: %v", err) + } + return h, nil +} + +func CreateQuery(path string, levels []string, eventIDs []int) (*uint16, error) { + + query := createFilterQuery(levels, eventIDs) + + xml := fmt.Sprintf(eventLogQueryTemplate, path, query) + return syscall.UTF16PtrFromString(xml) +} + +func utf16ToUTF8Bytes(in []byte, length uint32) ([]byte, error) { + + i := length + + if length%2 != 0 { + i = length - 1 + } + + for ; i-2 > 0; i -= 2 { + v1 := uint16(in[i-2]) | uint16(in[i-1])<<8 + // Stop at non-null char. + if v1 != 0 { + break + } + } + + win16be := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM) + utf16bom := unicode.BOMOverride(win16be.NewDecoder()) + unicodeReader := transform.NewReader(bytes.NewReader(in[:i]), utf16bom) + decoded, err := io.ReadAll(unicodeReader) + return decoded, err +} + +func UTF16ToUTF8BytesForWindowsEventBuffer(in []byte, length uint32) ([]byte, error) { + // Since Windows server 2022, the returned value of used buffer represents for double bytes char count, + // which is half of the actual buffer used by byte(what older Windows OS returns), checking if the length + //land on the end of used buffer, if no, double it. + if NumberOfBytesPerCharacter == UnknownBytesPerCharacter { + if isTheEndOfContent(in, length) { + log.Printf("I! Buffer used: %d is returning as single byte character count", length) + NumberOfBytesPerCharacter = 1 + } else { + log.Printf("I! Buffer used: %d is returning as double byte character count, doubling it to get the whole buffer content.", length) + NumberOfBytesPerCharacter = 2 + } + } + + i := int(length) * NumberOfBytesPerCharacter + + if i > cap(in) { + i = cap(in) + } + + return utf16ToUTF8Bytes(in, uint32(i)) +} + +func isTheEndOfContent(in []byte, length uint32) bool { + // scan next (emptySpaceScanLength) bytes, if any of them is none '0', return false + i := int(length) + + if i%2 != 0 { + i -= 1 + } + max := len(in) + if i+emptySpaceScanLength < max { + max = i + emptySpaceScanLength + } + + for ; i < max-2; i += 2 { + v1 := uint16(in[i+2]) | uint16(in[i+1])<<8 + // Stop at non-null char. + if v1 != 0 { + return false + } + } + return true +} + +func WindowsEventLogLevelName(levelId int32) string { + switch levelId { + case 1: + return CRITICAL + case 2: + return ERROR + case 3: + return WARNING + case 0, 4: + return INFORMATION + case 5: + return VERBOSE + default: + return UNKNOWN + } +} + +// insertPlaceholderValues formats the message with the correct values if we see those data +// in evtDataValues. +// +// In some cases wevtapi does not insert values when formatting the message. The message +// will contain insertion string placeholders, of the form %n, where %1 indicates the first +// insertion string, and so on. Noted that wevtapi start the index with 1. +// https://learn.microsoft.com/en-us/windows/win32/eventlog/event-identifiers#insertion-strings +func insertPlaceholderValues(rawMessage string, evtDataValues []Datum) string { + if len(evtDataValues) == 0 || len(rawMessage) == 0 { + return rawMessage + } + var sb strings.Builder + prevIndex := 0 + searchingIndex := false + for i, c := range rawMessage { + // found `%` previously. Determine the index number from the following character(s) + if searchingIndex && (c > '9' || c < '0') { + // Convert the Slice since the last `%` and see if it's a valid number. + ind, err := strconv.Atoi(rawMessage[prevIndex+1 : i]) + // If the index is in [1 - len(evtDataValues)], get it from evtDataValues. + if err == nil && ind <= len(evtDataValues) && ind > 0 { + sb.WriteString(evtDataValues[ind-1].Value) + } else { + sb.WriteString(rawMessage[prevIndex:i]) + } + prevIndex = i + // In case of consecutive `%`, continue searching for the next index + if c != '%' { + searchingIndex = false + } + } else { + if c == '%' { + sb.WriteString(rawMessage[prevIndex:i]) + searchingIndex = true + prevIndex = i + } + + } + } + // handle the slice since the last `%` to the end of rawMessage + ind, err := strconv.Atoi(rawMessage[prevIndex+1:]) + if searchingIndex && err == nil && ind <= len(evtDataValues) && ind > 0 { + sb.WriteString(evtDataValues[ind-1].Value) + } else { + sb.WriteString(rawMessage[prevIndex:]) + } + return sb.String() +} diff --git a/plugins/inputs/windows_event_log/wineventlog/utils_windows_test.go b/plugins/inputs/windows_event_log/wineventlog/utils_windows_test.go new file mode 100644 index 0000000000..40586504d3 --- /dev/null +++ b/plugins/inputs/windows_event_log/wineventlog/utils_windows_test.go @@ -0,0 +1,134 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +//go:build windows +// +build windows + +package wineventlog + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPayload_Value(t *testing.T) { + // one null test + resetState() + originalHexStr := "3c004500760065006e007400200078006d006c006e0073003d00270068007400740070003a002f002f0073006300680065006d00610073002e006d006900630072006f0073006f00660074002e0063006f006d002f00770069006e002f0032003000300034002f00300038002f006500760065006e00740073002f006500760065006e00740027003e003c00530079007300740065006d003e003c00500072006f007600690064006500720020004e0061006d0065003d0027004d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d00530065006300750072006900740079002d004100750064006900740069006e0067002700200047007500690064003d0027007b00350034003800340039003600320035002d0035003400370038002d0034003900390034002d0041003500420041002d003300450033004200300033003200380043003300300044007d0027002f003e003c004500760065006e007400490044003e0034003600320035003c002f004500760065006e007400490044003e003c00560065007200730069006f006e003e0030003c002f00560065007200730069006f006e003e003c004c006500760065006c003e0030003c002f004c006500760065006c003e003c005400610073006b003e00310032003500340034003c002f005400610073006b003e003c004f00700063006f00640065003e0030003c002f004f00700063006f00640065003e003c004b006500790077006f007200640073003e003000780038003000310030003000300030003000300030003000300030003000300030003c002f004b006500790077006f007200640073003e003c00540069006d00650043007200650061007400650064002000530079007300740065006d00540069006d0065003d00270032003000310039002d00300035002d00300035005400320033003a00310032003a00330037002e003300340039003400370036003100300030005a0027002f003e003c004500760065006e0074005200650063006f0072006400490044003e003600390034003600370034003c002f004500760065006e0074005200650063006f0072006400490044003e003c0043006f007200720065006c006100740069006f006e00200041006300740069007600690074007900490044003d0027007b00320035003200320035004600410031002d0044004100420039002d0030003000300031002d0041003600350046002d003200320032003500420039004400410044003400300031007d0027002f003e003c0045007800650063007500740069006f006e002000500072006f006300650073007300490044003d00270038003000340027002000540068007200650061006400490044003d002700310030003800300027002f003e003c004300680061006e006e0065006c003e00530065006300750072006900740079003c002f004300680061006e006e0065006c003e003c0043006f006d00700075007400650072003e0045004300320041004d0041005a002d0035004a00360049004600530046003c002f0043006f006d00700075007400650072003e003c00530065006300750072006900740079002f003e003c002f00530079007300740065006d003e003c004500760065006e00740044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a00650063007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740055007300650072004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740044006f006d00610069006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a006500630074004c006f0067006f006e004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700540061007200670065007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740055007300650072004e0061006d00650027003e00410044004d0049004e004900530054005200410054004f0052003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740044006f006d00610069006e004e0061006d00650027003e003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007400610074007500730027003e0030007800630030003000300030003000360064003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004600610069006c0075007200650052006500610073006f006e0027003e002500250032003300310033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007500620053007400610074007500730027003e0030007800630030003000300030003000360061003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00540079007000650027003e0033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00500072006f0063006500730073004e0061006d00650027003e004e0074004c006d0053007300700020003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700410075007400680065006e007400690063006100740069006f006e005000610063006b006100670065004e0061006d00650027003e004e0054004c004d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270057006f0072006b00730074006100740069006f006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005400720061006e0073006d00690074007400650064005300650072007600690063006500730027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006d005000610063006b006100670065004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004b00650079004c0065006e0067007400680027003e0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270049007000410064006400720065007300730027003e003100340036002e00350036002e0036002e003100360036003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004900700050006f007200740027003e0030003c002f0044006100740061003e003c002f004500760065006e00740044006100740061003e003c002f004500760065006e0074003e000000" + data, _ := hex.DecodeString(originalHexStr) + bufferUsed := len(data) + bytes, _ := UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) + str := string(bytes[:]) + assert.Equal(t, "<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/><EventID>4625</EventID><Version>0</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8010000000000000</Keywords><TimeCreated SystemTime='2019-05-05T23:12:37.349476100Z'/><EventRecordID>694674</EventRecordID><Correlation ActivityID='{25225FA1-DAB9-0001-A65F-2225B9DAD401}'/><Execution ProcessID='804' ThreadID='1080'/><Channel>Security</Channel><Computer>EC2AMAZ-5J6IFSF</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>ADMINISTRATOR</Data><Data Name='TargetDomainName'></Data><Data Name='Status'>0xc000006d</Data><Data Name='FailureReason'>%%2313</Data><Data Name='SubStatus'>0xc000006a</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>NtLmSsp </Data><Data Name='AuthenticationPackageName'>NTLM</Data><Data Name='WorkstationName'>-</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>146.56.6.166</Data><Data Name='IpPort'>0</Data></EventData></Event>", str) + + // odd bytes test + originalHexStr = "3c004500760065006e007400200078006d006c006e0073003d00270068007400740070003a002f002f0073006300680065006d00610073002e006d006900630072006f0073006f00660074002e0063006f006d002f00770069006e002f0032003000300034002f00300038002f006500760065006e00740073002f006500760065006e00740027003e003c00530079007300740065006d003e003c00500072006f007600690064006500720020004e0061006d0065003d0027004d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d00530065006300750072006900740079002d004100750064006900740069006e0067002700200047007500690064003d0027007b00350034003800340039003600320035002d0035003400370038002d0034003900390034002d0041003500420041002d003300450033004200300033003200380043003300300044007d0027002f003e003c004500760065006e007400490044003e0034003600320035003c002f004500760065006e007400490044003e003c00560065007200730069006f006e003e0030003c002f00560065007200730069006f006e003e003c004c006500760065006c003e0030003c002f004c006500760065006c003e003c005400610073006b003e00310032003500340034003c002f005400610073006b003e003c004f00700063006f00640065003e0030003c002f004f00700063006f00640065003e003c004b006500790077006f007200640073003e003000780038003000310030003000300030003000300030003000300030003000300030003c002f004b006500790077006f007200640073003e003c00540069006d00650043007200650061007400650064002000530079007300740065006d00540069006d0065003d00270032003000310039002d00300035002d00300035005400320033003a00310032003a00330037002e003300340039003400370036003100300030005a0027002f003e003c004500760065006e0074005200650063006f0072006400490044003e003600390034003600370034003c002f004500760065006e0074005200650063006f0072006400490044003e003c0043006f007200720065006c006100740069006f006e00200041006300740069007600690074007900490044003d0027007b00320035003200320035004600410031002d0044004100420039002d0030003000300031002d0041003600350046002d003200320032003500420039004400410044003400300031007d0027002f003e003c0045007800650063007500740069006f006e002000500072006f006300650073007300490044003d00270038003000340027002000540068007200650061006400490044003d002700310030003800300027002f003e003c004300680061006e006e0065006c003e00530065006300750072006900740079003c002f004300680061006e006e0065006c003e003c0043006f006d00700075007400650072003e0045004300320041004d0041005a002d0035004a00360049004600530046003c002f0043006f006d00700075007400650072003e003c00530065006300750072006900740079002f003e003c002f00530079007300740065006d003e003c004500760065006e00740044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a00650063007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740055007300650072004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740044006f006d00610069006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a006500630074004c006f0067006f006e004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700540061007200670065007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740055007300650072004e0061006d00650027003e00410044004d0049004e004900530054005200410054004f0052003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740044006f006d00610069006e004e0061006d00650027003e003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007400610074007500730027003e0030007800630030003000300030003000360064003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004600610069006c0075007200650052006500610073006f006e0027003e002500250032003300310033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007500620053007400610074007500730027003e0030007800630030003000300030003000360061003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00540079007000650027003e0033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00500072006f0063006500730073004e0061006d00650027003e004e0074004c006d0053007300700020003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700410075007400680065006e007400690063006100740069006f006e005000610063006b006100670065004e0061006d00650027003e004e0054004c004d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270057006f0072006b00730074006100740069006f006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005400720061006e0073006d00690074007400650064005300650072007600690063006500730027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006d005000610063006b006100670065004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004b00650079004c0065006e0067007400680027003e0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270049007000410064006400720065007300730027003e003100340036002e00350036002e0036002e003100360036003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004900700050006f007200740027003e0030003c002f0044006100740061003e003c002f004500760065006e00740044006100740061003e003c002f004500760065006e0074003e00000000" + data, _ = hex.DecodeString(originalHexStr) + bufferUsed = len(data) + bytes, _ = UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) + str = string(bytes[:]) + assert.Equal(t, "<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/><EventID>4625</EventID><Version>0</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8010000000000000</Keywords><TimeCreated SystemTime='2019-05-05T23:12:37.349476100Z'/><EventRecordID>694674</EventRecordID><Correlation ActivityID='{25225FA1-DAB9-0001-A65F-2225B9DAD401}'/><Execution ProcessID='804' ThreadID='1080'/><Channel>Security</Channel><Computer>EC2AMAZ-5J6IFSF</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>ADMINISTRATOR</Data><Data Name='TargetDomainName'></Data><Data Name='Status'>0xc000006d</Data><Data Name='FailureReason'>%%2313</Data><Data Name='SubStatus'>0xc000006a</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>NtLmSsp </Data><Data Name='AuthenticationPackageName'>NTLM</Data><Data Name='WorkstationName'>-</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>146.56.6.166</Data><Data Name='IpPort'>0</Data></EventData></Event>", str) + + // two nulls test + originalHexStr = "3c004500760065006e007400200078006d006c006e0073003d00270068007400740070003a002f002f0073006300680065006d00610073002e006d006900630072006f0073006f00660074002e0063006f006d002f00770069006e002f0032003000300034002f00300038002f006500760065006e00740073002f006500760065006e00740027003e003c00530079007300740065006d003e003c00500072006f007600690064006500720020004e0061006d0065003d0027004d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d00530065006300750072006900740079002d004100750064006900740069006e0067002700200047007500690064003d0027007b00350034003800340039003600320035002d0035003400370038002d0034003900390034002d0041003500420041002d003300450033004200300033003200380043003300300044007d0027002f003e003c004500760065006e007400490044003e0034003600320035003c002f004500760065006e007400490044003e003c00560065007200730069006f006e003e0030003c002f00560065007200730069006f006e003e003c004c006500760065006c003e0030003c002f004c006500760065006c003e003c005400610073006b003e00310032003500340034003c002f005400610073006b003e003c004f00700063006f00640065003e0030003c002f004f00700063006f00640065003e003c004b006500790077006f007200640073003e003000780038003000310030003000300030003000300030003000300030003000300030003c002f004b006500790077006f007200640073003e003c00540069006d00650043007200650061007400650064002000530079007300740065006d00540069006d0065003d00270032003000310039002d00300035002d00300035005400320033003a00310032003a00330037002e003300340039003400370036003100300030005a0027002f003e003c004500760065006e0074005200650063006f0072006400490044003e003600390034003600370034003c002f004500760065006e0074005200650063006f0072006400490044003e003c0043006f007200720065006c006100740069006f006e00200041006300740069007600690074007900490044003d0027007b00320035003200320035004600410031002d0044004100420039002d0030003000300031002d0041003600350046002d003200320032003500420039004400410044003400300031007d0027002f003e003c0045007800650063007500740069006f006e002000500072006f006300650073007300490044003d00270038003000340027002000540068007200650061006400490044003d002700310030003800300027002f003e003c004300680061006e006e0065006c003e00530065006300750072006900740079003c002f004300680061006e006e0065006c003e003c0043006f006d00700075007400650072003e0045004300320041004d0041005a002d0035004a00360049004600530046003c002f0043006f006d00700075007400650072003e003c00530065006300750072006900740079002f003e003c002f00530079007300740065006d003e003c004500760065006e00740044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a00650063007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740055007300650072004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740044006f006d00610069006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a006500630074004c006f0067006f006e004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700540061007200670065007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740055007300650072004e0061006d00650027003e00410044004d0049004e004900530054005200410054004f0052003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740044006f006d00610069006e004e0061006d00650027003e003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007400610074007500730027003e0030007800630030003000300030003000360064003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004600610069006c0075007200650052006500610073006f006e0027003e002500250032003300310033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007500620053007400610074007500730027003e0030007800630030003000300030003000360061003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00540079007000650027003e0033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00500072006f0063006500730073004e0061006d00650027003e004e0074004c006d0053007300700020003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700410075007400680065006e007400690063006100740069006f006e005000610063006b006100670065004e0061006d00650027003e004e0054004c004d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270057006f0072006b00730074006100740069006f006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005400720061006e0073006d00690074007400650064005300650072007600690063006500730027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006d005000610063006b006100670065004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004b00650079004c0065006e0067007400680027003e0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270049007000410064006400720065007300730027003e003100340036002e00350036002e0036002e003100360036003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004900700050006f007200740027003e0030003c002f0044006100740061003e003c002f004500760065006e00740044006100740061003e003c002f004500760065006e0074003e000000000000" + data, _ = hex.DecodeString(originalHexStr) + bufferUsed = len(data) + bytes, _ = UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) + str = string(bytes[:]) + assert.Equal(t, "<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/><EventID>4625</EventID><Version>0</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8010000000000000</Keywords><TimeCreated SystemTime='2019-05-05T23:12:37.349476100Z'/><EventRecordID>694674</EventRecordID><Correlation ActivityID='{25225FA1-DAB9-0001-A65F-2225B9DAD401}'/><Execution ProcessID='804' ThreadID='1080'/><Channel>Security</Channel><Computer>EC2AMAZ-5J6IFSF</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>ADMINISTRATOR</Data><Data Name='TargetDomainName'></Data><Data Name='Status'>0xc000006d</Data><Data Name='FailureReason'>%%2313</Data><Data Name='SubStatus'>0xc000006a</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>NtLmSsp </Data><Data Name='AuthenticationPackageName'>NTLM</Data><Data Name='WorkstationName'>-</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>146.56.6.166</Data><Data Name='IpPort'>0</Data></EventData></Event>", str) + +} + +func TestDecodingWithDifferentBufferUsedReturned(t *testing.T) { + // one null test + resetState() + originalHexStr := "3c004500760065006e007400200078006d006c006e0073003d00270068007400740070003a002f002f0073006300680065006d00610073002e006d006900630072006f0073006f00660074002e0063006f006d002f00770069006e002f0032003000300034002f00300038002f006500760065006e00740073002f006500760065006e00740027003e003c00530079007300740065006d003e003c00500072006f007600690064006500720020004e0061006d0065003d0027004d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d00530065006300750072006900740079002d004100750064006900740069006e0067002700200047007500690064003d0027007b00350034003800340039003600320035002d0035003400370038002d0034003900390034002d0041003500420041002d003300450033004200300033003200380043003300300044007d0027002f003e003c004500760065006e007400490044003e0034003600320035003c002f004500760065006e007400490044003e003c00560065007200730069006f006e003e0030003c002f00560065007200730069006f006e003e003c004c006500760065006c003e0030003c002f004c006500760065006c003e003c005400610073006b003e00310032003500340034003c002f005400610073006b003e003c004f00700063006f00640065003e0030003c002f004f00700063006f00640065003e003c004b006500790077006f007200640073003e003000780038003000310030003000300030003000300030003000300030003000300030003c002f004b006500790077006f007200640073003e003c00540069006d00650043007200650061007400650064002000530079007300740065006d00540069006d0065003d00270032003000310039002d00300035002d00300035005400320033003a00310032003a00330037002e003300340039003400370036003100300030005a0027002f003e003c004500760065006e0074005200650063006f0072006400490044003e003600390034003600370034003c002f004500760065006e0074005200650063006f0072006400490044003e003c0043006f007200720065006c006100740069006f006e00200041006300740069007600690074007900490044003d0027007b00320035003200320035004600410031002d0044004100420039002d0030003000300031002d0041003600350046002d003200320032003500420039004400410044003400300031007d0027002f003e003c0045007800650063007500740069006f006e002000500072006f006300650073007300490044003d00270038003000340027002000540068007200650061006400490044003d002700310030003800300027002f003e003c004300680061006e006e0065006c003e00530065006300750072006900740079003c002f004300680061006e006e0065006c003e003c0043006f006d00700075007400650072003e0045004300320041004d0041005a002d0035004a00360049004600530046003c002f0043006f006d00700075007400650072003e003c00530065006300750072006900740079002f003e003c002f00530079007300740065006d003e003c004500760065006e00740044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a00650063007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740055007300650072004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740044006f006d00610069006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a006500630074004c006f0067006f006e004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700540061007200670065007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740055007300650072004e0061006d00650027003e00410044004d0049004e004900530054005200410054004f0052003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740044006f006d00610069006e004e0061006d00650027003e003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007400610074007500730027003e0030007800630030003000300030003000360064003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004600610069006c0075007200650052006500610073006f006e0027003e002500250032003300310033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007500620053007400610074007500730027003e0030007800630030003000300030003000360061003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00540079007000650027003e0033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00500072006f0063006500730073004e0061006d00650027003e004e0074004c006d0053007300700020003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700410075007400680065006e007400690063006100740069006f006e005000610063006b006100670065004e0061006d00650027003e004e0054004c004d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270057006f0072006b00730074006100740069006f006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005400720061006e0073006d00690074007400650064005300650072007600690063006500730027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006d005000610063006b006100670065004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004b00650079004c0065006e0067007400680027003e0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270049007000410064006400720065007300730027003e003100340036002e00350036002e0036002e003100360036003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004900700050006f007200740027003e0030003c002f0044006100740061003e003c002f004500760065006e00740044006100740061003e003c002f004500760065006e0074003e000000" + data, _ := hex.DecodeString(originalHexStr) + bufferUsed := len(data) / 2 + bytes, _ := UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) + str := string(bytes[:]) + assert.Equal(t, "<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/><EventID>4625</EventID><Version>0</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8010000000000000</Keywords><TimeCreated SystemTime='2019-05-05T23:12:37.349476100Z'/><EventRecordID>694674</EventRecordID><Correlation ActivityID='{25225FA1-DAB9-0001-A65F-2225B9DAD401}'/><Execution ProcessID='804' ThreadID='1080'/><Channel>Security</Channel><Computer>EC2AMAZ-5J6IFSF</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>ADMINISTRATOR</Data><Data Name='TargetDomainName'></Data><Data Name='Status'>0xc000006d</Data><Data Name='FailureReason'>%%2313</Data><Data Name='SubStatus'>0xc000006a</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>NtLmSsp </Data><Data Name='AuthenticationPackageName'>NTLM</Data><Data Name='WorkstationName'>-</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>146.56.6.166</Data><Data Name='IpPort'>0</Data></EventData></Event>", str) + + // odd bytes test + originalHexStr = "3c004500760065006e007400200078006d006c006e0073003d00270068007400740070003a002f002f0073006300680065006d00610073002e006d006900630072006f0073006f00660074002e0063006f006d002f00770069006e002f0032003000300034002f00300038002f006500760065006e00740073002f006500760065006e00740027003e003c00530079007300740065006d003e003c00500072006f007600690064006500720020004e0061006d0065003d0027004d006900630072006f0073006f00660074002d00570069006e0064006f00770073002d00530065006300750072006900740079002d004100750064006900740069006e0067002700200047007500690064003d0027007b00350034003800340039003600320035002d0035003400370038002d0034003900390034002d0041003500420041002d003300450033004200300033003200380043003300300044007d0027002f003e003c004500760065006e007400490044003e0034003600320035003c002f004500760065006e007400490044003e003c00560065007200730069006f006e003e0030003c002f00560065007200730069006f006e003e003c004c006500760065006c003e0030003c002f004c006500760065006c003e003c005400610073006b003e00310032003500340034003c002f005400610073006b003e003c004f00700063006f00640065003e0030003c002f004f00700063006f00640065003e003c004b006500790077006f007200640073003e003000780038003000310030003000300030003000300030003000300030003000300030003c002f004b006500790077006f007200640073003e003c00540069006d00650043007200650061007400650064002000530079007300740065006d00540069006d0065003d00270032003000310039002d00300035002d00300035005400320033003a00310032003a00330037002e003300340039003400370036003100300030005a0027002f003e003c004500760065006e0074005200650063006f0072006400490044003e003600390034003600370034003c002f004500760065006e0074005200650063006f0072006400490044003e003c0043006f007200720065006c006100740069006f006e00200041006300740069007600690074007900490044003d0027007b00320035003200320035004600410031002d0044004100420039002d0030003000300031002d0041003600350046002d003200320032003500420039004400410044003400300031007d0027002f003e003c0045007800650063007500740069006f006e002000500072006f006300650073007300490044003d00270038003000340027002000540068007200650061006400490044003d002700310030003800300027002f003e003c004300680061006e006e0065006c003e00530065006300750072006900740079003c002f004300680061006e006e0065006c003e003c0043006f006d00700075007400650072003e0045004300320041004d0041005a002d0035004a00360049004600530046003c002f0043006f006d00700075007400650072003e003c00530065006300750072006900740079002f003e003c002f00530079007300740065006d003e003c004500760065006e00740044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a00650063007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740055007300650072004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a0065006300740044006f006d00610069006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005300750062006a006500630074004c006f0067006f006e004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700540061007200670065007400550073006500720053006900640027003e0053002d0031002d0030002d0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740055007300650072004e0061006d00650027003e00410044004d0049004e004900530054005200410054004f0052003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270054006100720067006500740044006f006d00610069006e004e0061006d00650027003e003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007400610074007500730027003e0030007800630030003000300030003000360064003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004600610069006c0075007200650052006500610073006f006e0027003e002500250032003300310033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270053007500620053007400610074007500730027003e0030007800630030003000300030003000360061003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00540079007000650027003e0033003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006f0067006f006e00500072006f0063006500730073004e0061006d00650027003e004e0074004c006d0053007300700020003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700410075007400680065006e007400690063006100740069006f006e005000610063006b006100670065004e0061006d00650027003e004e0054004c004d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270057006f0072006b00730074006100740069006f006e004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027005400720061006e0073006d00690074007400650064005300650072007600690063006500730027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004c006d005000610063006b006100670065004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004b00650079004c0065006e0067007400680027003e0030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004900640027003e003000780030003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d002700500072006f0063006500730073004e0061006d00650027003e002d003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d00270049007000410064006400720065007300730027003e003100340036002e00350036002e0036002e003100360036003c002f0044006100740061003e003c00440061007400610020004e0061006d0065003d0027004900700050006f007200740027003e0030003c002f0044006100740061003e003c002f004500760065006e00740044006100740061003e003c002f004500760065006e0074003e00000000" + data, _ = hex.DecodeString(originalHexStr) + bufferUsed = len(data) / 2 + bytes, _ = UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) + str = string(bytes[:]) + assert.Equal(t, "<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Microsoft-Windows-Security-Auditing' Guid='{54849625-5478-4994-A5BA-3E3B0328C30D}'/><EventID>4625</EventID><Version>0</Version><Level>0</Level><Task>12544</Task><Opcode>0</Opcode><Keywords>0x8010000000000000</Keywords><TimeCreated SystemTime='2019-05-05T23:12:37.349476100Z'/><EventRecordID>694674</EventRecordID><Correlation ActivityID='{25225FA1-DAB9-0001-A65F-2225B9DAD401}'/><Execution ProcessID='804' ThreadID='1080'/><Channel>Security</Channel><Computer>EC2AMAZ-5J6IFSF</Computer><Security/></System><EventData><Data Name='SubjectUserSid'>S-1-0-0</Data><Data Name='SubjectUserName'>-</Data><Data Name='SubjectDomainName'>-</Data><Data Name='SubjectLogonId'>0x0</Data><Data Name='TargetUserSid'>S-1-0-0</Data><Data Name='TargetUserName'>ADMINISTRATOR</Data><Data Name='TargetDomainName'></Data><Data Name='Status'>0xc000006d</Data><Data Name='FailureReason'>%%2313</Data><Data Name='SubStatus'>0xc000006a</Data><Data Name='LogonType'>3</Data><Data Name='LogonProcessName'>NtLmSsp </Data><Data Name='AuthenticationPackageName'>NTLM</Data><Data Name='WorkstationName'>-</Data><Data Name='TransmittedServices'>-</Data><Data Name='LmPackageName'>-</Data><Data Name='KeyLength'>0</Data><Data Name='ProcessId'>0x0</Data><Data Name='ProcessName'>-</Data><Data Name='IpAddress'>146.56.6.166</Data><Data Name='IpPort'>0</Data></EventData></Event>", str) + +} + +func TestFullBufferUsedWithHalfUsedSizeReturned(t *testing.T) { + resetState() + cap := 1 << 10 + data := make([]byte, cap) + data[0] = 'a' + for i := 2; i < cap; i *= 2 { + copy(data[i:], data[:i]) + } + bufferUsed := cap / 2 + + bytes, _ := UTF16ToUTF8BytesForWindowsEventBuffer(data, uint32(bufferUsed)) + str := string(bytes[:]) + assert.Equal(t, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", str) + assert.Equal(t, bufferUsed, len(str)) +} + +func TestInsertPlaceholderValues(t *testing.T) { + evtDataValues := []Datum{ + {"value_1"}, {"value_2"}, {"value_3"}, {"value_4"}, + } + tests := []struct { + name string + message string + expected string + }{ + { + "Placeholders %{number} should be replaced by insertion strings", + "Service %1 in region %3 stop at %2", + "Service value_1 in region value_3 stop at value_2", + }, + { + "String without a placeholder should remain the same after insertion", + "This is a sentence without placeholders", + "This is a sentence without placeholders", + }, + { + "Empty string should remain the same", + "", + "", + }, + { + "Index should start from 1 and less than or equal to the amount of values in event data", + "%0 %3 %5", + "%0 value_3 %5", + }, + { + "Handle consecutive % characters", + "%1 %%3% %2", + "value_1 %value_3% value_2", + }, + { + "Handle % character at the end of message", + "%3 %2%", + "value_3 value_2%", + }, + { + "Characters after a % other than numbers should be ignored", + "%foo, %foo1, %#$%^&1", + "%foo, %foo1, %#$%^&1", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expected, insertPlaceholderValues(tc.message, evtDataValues)) + }) + } +} + +func resetState() { + NumberOfBytesPerCharacter = 0 +} diff --git a/plugins/inputs/windows_event_log/wineventlog/wineventlog.go b/plugins/inputs/windows_event_log/wineventlog/wineventlog.go index 0fdcf7942e..27b951fc65 100644 --- a/plugins/inputs/windows_event_log/wineventlog/wineventlog.go +++ b/plugins/inputs/windows_event_log/wineventlog/wineventlog.go @@ -50,6 +50,7 @@ func (e *wevtAPIError) Error() string { type windowsEventLog struct { name string levels []string + eventID []int logGroupName string logStreamName string logGroupClass string @@ -68,10 +69,11 @@ type windowsEventLog struct { resubscribeCh chan struct{} } -func NewEventLog(name string, levels []string, logGroupName, logStreamName, renderFormat, destination, stateFilePath string, maximumToRead int, retention int, logGroupClass string) *windowsEventLog { +func NewEventLog(name string, levels []string, eventID []int, logGroupName, logStreamName, renderFormat, destination, stateFilePath string, maximumToRead int, retention int, logGroupClass string) *windowsEventLog { eventLog := &windowsEventLog{ name: name, levels: levels, + eventID: eventID, logGroupName: logGroupName, logStreamName: logStreamName, logGroupClass: logGroupClass, @@ -209,7 +211,7 @@ func (w *windowsEventLog) open() error { if err != nil { return err } - query, err := CreateQuery(w.name, w.levels) + query, err := CreateQuery(w.name, w.levels, w.eventID) if err != nil { return err } diff --git a/plugins/inputs/windows_event_log/wineventlog/wineventlog_test.go b/plugins/inputs/windows_event_log/wineventlog/wineventlog_test.go index 386333090b..c5c5519679 100644 --- a/plugins/inputs/windows_event_log/wineventlog/wineventlog_test.go +++ b/plugins/inputs/windows_event_log/wineventlog/wineventlog_test.go @@ -21,6 +21,7 @@ var ( NAME = "Application" // 2 is ERROR LEVELS = []string{"2"} + EVENTID = []int{100, 101} GROUP_NAME = "fake" STREAM_NAME = "fake" RENDER_FMT = FormatPlainText @@ -33,7 +34,7 @@ var ( // TestNewEventLog verifies constructor's default values. func TestNewEventLog(t *testing.T) { - elog := NewEventLog(NAME, LEVELS, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, + elog := NewEventLog(NAME, LEVELS, EVENTID, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, STATE_FILE_PATH, BATCH_SIZE, RETENTION, LOG_GROUP_CLASS) assert.Equal(t, NAME, elog.name) assert.Equal(t, uint64(0), elog.eventOffset) @@ -44,26 +45,33 @@ func TestNewEventLog(t *testing.T) { // And fails with invalid inputs. func TestOpen(t *testing.T) { // Happy path. - elog := NewEventLog(NAME, LEVELS, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, + elog := NewEventLog(NAME, LEVELS, EVENTID, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, STATE_FILE_PATH, BATCH_SIZE, RETENTION, LOG_GROUP_CLASS) assert.NoError(t, elog.Open()) assert.NotZero(t, elog.eventHandle) assert.NoError(t, elog.Close()) // Bad event log source name does not cause Open() to fail. // But eventHandle will be 0 and Close() will fail because of it. - elog = NewEventLog("FakeBadElogName", LEVELS, GROUP_NAME, STREAM_NAME, + elog = NewEventLog("FakeBadElogName", LEVELS, EVENTID, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, STATE_FILE_PATH, BATCH_SIZE, RETENTION, LOG_GROUP_CLASS) assert.NoError(t, elog.Open()) assert.Zero(t, elog.eventHandle) assert.Error(t, elog.Close()) // bad LEVELS does not cause Open() to fail. - elog = NewEventLog(NAME, []string{"498"}, GROUP_NAME, STREAM_NAME, + + elog = NewEventLog(NAME, []string{"498"}, EVENTID, GROUP_NAME, STREAM_NAME, + RENDER_FMT, DEST, STATE_FILE_PATH, BATCH_SIZE, RETENTION, LOG_GROUP_CLASS) + assert.NoError(t, elog.Open()) + assert.NotZero(t, elog.eventHandle) + assert.NoError(t, elog.Close()) + //bad + elog = NewEventLog(NAME, LEVELS, []int{98698}, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, STATE_FILE_PATH, BATCH_SIZE, RETENTION, LOG_GROUP_CLASS) assert.NoError(t, elog.Open()) assert.NotZero(t, elog.eventHandle) assert.NoError(t, elog.Close()) // bad wlog.eventOffset does not cause Open() to fail. - elog = NewEventLog(NAME, []string{"498"}, GROUP_NAME, STREAM_NAME, + elog = NewEventLog(NAME, []string{"498"}, EVENTID, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, STATE_FILE_PATH, BATCH_SIZE, RETENTION, LOG_GROUP_CLASS) elog.eventOffset = 9987 assert.NoError(t, elog.Open()) @@ -74,7 +82,7 @@ func TestOpen(t *testing.T) { // TestReadGoodSource will verify we can read events written by a registered // event log source. func TestReadGoodSource(t *testing.T) { - elog := NewEventLog(NAME, LEVELS, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, + elog := NewEventLog(NAME, LEVELS, EVENTID, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, STATE_FILE_PATH, BATCH_SIZE, RETENTION, LOG_GROUP_CLASS) assert.NoError(t, elog.Open()) seekToEnd(t, elog) @@ -87,7 +95,7 @@ func TestReadGoodSource(t *testing.T) { // TestReadBadSource will verify that we cannot read events written by an // unregistered event log source. func TestReadBadSource(t *testing.T) { - elog := NewEventLog(NAME, LEVELS, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, + elog := NewEventLog(NAME, LEVELS, EVENTID, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, STATE_FILE_PATH, BATCH_SIZE, RETENTION, LOG_GROUP_CLASS) assert.NoError(t, elog.Open()) seekToEnd(t, elog) @@ -101,7 +109,7 @@ func TestReadBadSource(t *testing.T) { // registered event log source, even if the batch contains events from an // unregistered source too. func TestReadWithBothSources(t *testing.T) { - elog := NewEventLog(NAME, LEVELS, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, + elog := NewEventLog(NAME, LEVELS, EVENTID, GROUP_NAME, STREAM_NAME, RENDER_FMT, DEST, STATE_FILE_PATH, BATCH_SIZE, RETENTION, LOG_GROUP_CLASS) assert.NoError(t, elog.Open()) seekToEnd(t, elog) diff --git a/translator/config/schema.json b/translator/config/schema.json index 0279bf2c9d..6d311d47ef 100644 --- a/translator/config/schema.json +++ b/translator/config/schema.json @@ -1058,6 +1058,14 @@ "uniqueItems": true } }, + "event_ids":{ + "type": "array", + "items": { + "type": "integer" + }, + "minItems": 1, + "uniqueItems": true + }, "log_stream_name": { "$ref": "#/definitions/logsDefinition/definitions/logStreamNameDefinition" }, @@ -1078,9 +1086,26 @@ ] } }, - "required": [ - "event_name", - "event_levels" + "oneOf": [ + { + "required": [ + "event_name", + "event_levels" + ] + }, + { + "required": [ + "event_name", + "event_ids" + ] + }, + { + "required": [ + "event_name", + "event_levels", + "event_ids" + ] + } ], "additionalProperties": false }, diff --git a/translator/tocwconfig/sampleConfig/windows_eventids.conf b/translator/tocwconfig/sampleConfig/windows_eventids.conf new file mode 100644 index 0000000000..5d0c21526d --- /dev/null +++ b/translator/tocwconfig/sampleConfig/windows_eventids.conf @@ -0,0 +1,48 @@ +[agent] + collection_jitter = "0s" + debug = false + flush_interval = "1s" + flush_jitter = "0s" + hostname = "" + interval = "60s" + logfile = "c:\\ProgramData\\Amazon\\AmazonCloudWatchAgent\\Logs\\amazon-cloudwatch-agent.log" + logtarget = "lumberjack" + metric_batch_size = 1000 + metric_buffer_limit = 10000 + omit_hostname = false + precision = "" + quiet = false + round_interval = false + +[inputs] + + [[inputs.windows_event_log]] + destination = "cloudwatchlogs" + file_state_folder = "c:\\ProgramData\\Amazon\\AmazonCloudWatchAgent\\Logs\\state" + + [[inputs.windows_event_log.event_config]] + batch_read_size = 170 + event_ids = [4562, 4589] + event_name = "System" + log_group_class = "" + log_group_name = "System" + log_stream_name = "System" + retention_in_days = -1 + + [[inputs.windows_event_log.event_config]] + batch_read_size = 170 + event_ids = [1452, 9687] + event_name = "Application" + log_group_class = "" + log_group_name = "Application" + log_stream_name = "Application" + retention_in_days = -1 + +[outputs] + + [[outputs.cloudwatchlogs]] + force_flush_interval = "5s" + log_stream_name = "log_stream_name" + mode = "" + region = "us-west-2" + region_type = "ACJ" diff --git a/translator/tocwconfig/sampleConfig/windows_eventids.json b/translator/tocwconfig/sampleConfig/windows_eventids.json new file mode 100644 index 0000000000..1f2b7c0037 --- /dev/null +++ b/translator/tocwconfig/sampleConfig/windows_eventids.json @@ -0,0 +1,29 @@ +{ + "logs": { + "logs_collected": { + "windows_events": { + "collect_list": [ + { + "event_name": "System", + "event_ids": [ + 4562, + 4589 + ], + "log_group_name": "System", + "log_stream_name": "System" + }, + { + "event_name": "Application", + "event_ids": [ + 1452, + 9687 + ], + "log_group_name": "Application", + "log_stream_name": "Application" + } + ] + } + }, + "log_stream_name": "log_stream_name" + } +} diff --git a/translator/tocwconfig/sampleConfig/windows_eventids.yaml b/translator/tocwconfig/sampleConfig/windows_eventids.yaml new file mode 100644 index 0000000000..558843bdd0 --- /dev/null +++ b/translator/tocwconfig/sampleConfig/windows_eventids.yaml @@ -0,0 +1,37 @@ +exporters: + nop: {} +extensions: + entitystore: + mode: ec2 + region: us-west-2 +receivers: + nop: {} +service: + extensions: + - entitystore + pipelines: + metrics/nop: + exporters: + - nop + processors: [] + receivers: + - nop + telemetry: + logs: + development: false + disable_caller: false + disable_stacktrace: false + encoding: console + level: info + output_paths: + - c:\ProgramData\Amazon\AmazonCloudWatchAgent\Logs\amazon-cloudwatch-agent.log + sampling: + enabled: true + initial: 2 + thereafter: 500 + tick: 10s + metrics: + address: "" + level: None + traces: + level: None diff --git a/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.conf b/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.conf index 662eb7f1d1..837076f190 100755 --- a/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.conf +++ b/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.conf @@ -22,8 +22,10 @@ [[inputs.windows_event_log.event_config]] batch_read_size = 170 + event_ids = [4562, 4589] event_levels = ["4", "0", "2"] event_name = "System" + log_group_class = "" log_group_name = "System" log_stream_name = "System" retention_in_days = -1 @@ -32,6 +34,7 @@ batch_read_size = 170 event_levels = ["4", "0", "2"] event_name = "Application" + log_group_class = "" log_group_name = "Application" log_stream_name = "Application" retention_in_days = -1 @@ -41,4 +44,6 @@ [[outputs.cloudwatchlogs]] force_flush_interval = "5s" log_stream_name = "log_stream_name" + mode = "" region = "us-west-2" + region_type = "ACJ" diff --git a/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.json b/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.json index cc37ebf35a..162a3121c8 100644 --- a/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.json +++ b/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.json @@ -9,6 +9,10 @@ "INFORMATION", "ERROR" ], + "event_ids": [ + 4562, + 4589 + ], "log_group_name": "System", "log_stream_name": "System" }, diff --git a/translator/tocwconfig/tocwconfig_test.go b/translator/tocwconfig/tocwconfig_test.go index 5a8dc87964..fa43f6c72f 100644 --- a/translator/tocwconfig/tocwconfig_test.go +++ b/translator/tocwconfig/tocwconfig_test.go @@ -339,6 +339,11 @@ func TestWindowsEventOnlyConfig(t *testing.T) { checkTranslation(t, "windows_eventlog_only_config", "windows", expectedEnvVars, "") } +func TestWindowsEventIDOnly(t *testing.T) { + resetContext(t) + expectedEnvVars := map[string]string{} + checkTranslation(t, "windows_eventids", "windows", expectedEnvVars, "") +} func TestStatsDConfig(t *testing.T) { testCases := map[string]testCase{ "linux": { @@ -926,7 +931,7 @@ func verifyToYamlTranslation(t *testing.T, input interface{}, expectedYamlFilePa opt := cmpopts.SortSlices(func(x, y interface{}) bool { return pretty.Sprint(x) < pretty.Sprint(y) }) - // assert.Equal(t, expected, actual) // this is useful for debugging differences between the YAML + //assert.Equal(t, expected, actual) // this is useful for debugging differences between the YAML require.True(t, cmp.Equal(expected, actual, opt), "D! YAML diff: %s", cmp.Diff(expected, actual)) } diff --git a/translator/tocwconfig/totomlconfig/toTomlConfig.go b/translator/tocwconfig/totomlconfig/toTomlConfig.go index 041b7568ac..e247ec34ec 100755 --- a/translator/tocwconfig/totomlconfig/toTomlConfig.go +++ b/translator/tocwconfig/totomlconfig/toTomlConfig.go @@ -11,11 +11,46 @@ import ( ) func ToTomlConfig(val interface{}) string { + // Process the value to ensure integers in arrays are preserved + processedVal := processValue(val) + buf := bytes.Buffer{} enc := toml.NewEncoder(&buf) - err := enc.Encode(val) + err := enc.Encode(processedVal) if err != nil { log.Panicf("Encode to a valid TOML config fails because of %v", err) } return buf.String() } + +// processValue recursively processes the value to ensure integers in arrays are preserved +func processValue(val interface{}) interface{} { + switch v := val.(type) { + case map[string]interface{}: + for k, value := range v { + v[k] = processValue(value) + } + return v + case []interface{}: + for i, value := range v { + v[i] = processValue(value) + } + return v + case map[interface{}]interface{}: + result := make(map[string]interface{}) + for k, value := range v { + if key, ok := k.(string); ok { + result[key] = processValue(value) + } + } + return result + case float64: + // Convert float64 to int if it's a whole number + if v == float64(int(v)) { + return int(v) + } + return v + default: + return v + } +} diff --git a/translator/tocwconfig/totomlconfig/tomlConfigTemplate/tomlConfig.go b/translator/tocwconfig/totomlconfig/tomlConfigTemplate/tomlConfig.go index a3c5f96f6c..b35b3c0e0b 100644 --- a/translator/tocwconfig/totomlconfig/tomlConfigTemplate/tomlConfig.go +++ b/translator/tocwconfig/totomlconfig/tomlConfigTemplate/tomlConfig.go @@ -105,6 +105,7 @@ type ( eventConfig struct { BatchReadSize int `toml:"batch_read_size"` EventLevels []string `toml:"event_levels"` + EventIds []int `toml:"event_ids"` EventName string `toml:"event_name"` LogGroupName string `toml:"log_group_name"` LogStreamName string `toml:"log_stream_name"` diff --git a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go index d795271be7..80f4bd9489 100644 --- a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go +++ b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go @@ -21,6 +21,7 @@ const ( EventConfigTomlKey = "event_config" BatchReadSizeKey = "batch_read_size" EventLevelsKey = "event_levels" + EventIdKey = "event_ids" //TODO: Performance test to confirm the proper value here - https://github.com/aws/amazon-cloudwatch-agent/issues/231 BatchReadSizeValue = 170 ) @@ -34,7 +35,7 @@ func RegisterRule(fieldname string, r Rule) { type CollectList struct { } -var customizedJsonConfigKeys = []string{"event_name", EventLevelsKey} +var customizedJsonConfigKeys = []string{"event_name", EventLevelsKey, EventIdKey} var eventLevelMapping = map[string]string{ "VERBOSE": "5", "INFORMATION": "4", @@ -118,4 +119,41 @@ func addFixedJsonConfig(result map[string]interface{}) { } } result[EventLevelsKey] = resultEventLevels + + if eventIds, ok := result[EventIdKey]; ok { + validatedIds, errorMessages := validateEventIds(eventIds.([]interface{})) + for _, err := range errorMessages { + translator.AddErrorMessages(GetCurPath(), err) + } + result[EventIdKey] = validatedIds + } +} + +// Validate event_id inputs +func validateEventIds(inputEventIds []interface{}) ([]interface{}, []string) { + validatedIds := []interface{}{} + errorMessages := []string{} + + const ( + minEventId = 0 + maxEventId = 65535 + ) + + for _, id := range inputEventIds { + eventIdFloat, ok := id.(float64) + if !ok { + errorMessages = append(errorMessages, fmt.Sprintf("Event ID %v is not a number", id)) + continue + } + eventIdInt := int(eventIdFloat) + if eventIdInt < minEventId || eventIdInt > maxEventId { + errorMessages = append(errorMessages, fmt.Sprintf("Event ID %v is not a valid windows event_id.", eventIdInt)) + continue + } + + validatedIds = append(validatedIds, eventIdInt) + } + + return validatedIds, errorMessages + } diff --git a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go index 0c7409dfe3..00dc19f1f7 100644 --- a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go +++ b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go @@ -5,6 +5,7 @@ package collectlist import ( "encoding/json" + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -24,6 +25,11 @@ func TestApplyRule(t *testing.T) { "INFORMATION", "CRITICAL" ], + "event_ids": [ + 100, + 120, + 300 + ], "log_group_name": "System", "log_group_class": "STANDARD" }, @@ -34,6 +40,10 @@ func TestApplyRule(t *testing.T) { "VERBOSE", "ERROR" ], + "event_ids": [ + 4625, + 3568 + ], "event_format": "xml", "log_group_name": "Application", "retention_in_days": 1 @@ -47,6 +57,7 @@ func TestApplyRule(t *testing.T) { map[string]interface{}{ "event_name": "System", "event_levels": []interface{}{"4", "0", "1"}, + "event_ids": []int{100, 120, 300}, "log_group_name": "System", "batch_read_size": BatchReadSizeValue, "retention_in_days": -1, @@ -55,6 +66,7 @@ func TestApplyRule(t *testing.T) { map[string]interface{}{ "event_name": "Application", "event_levels": []interface{}{"4", "0", "5", "2"}, + "event_ids": []int{4625, 3568}, "event_format": "xml", "log_group_name": "Application", "batch_read_size": BatchReadSizeValue, @@ -85,6 +97,10 @@ func TestDuplicateRetention(t *testing.T) { "INFORMATION", "CRITICAL" ], + "event_ids": [ + 100, + 120 + ], "log_group_name": "System", "retention_in_days": 3, "log_group_class": "INFREQUENT_ACCESS" @@ -96,6 +112,10 @@ func TestDuplicateRetention(t *testing.T) { "VERBOSE", "ERROR" ], + "event_ids": [ + 100, + 120 + ], "event_format": "xml", "log_group_name": "System", "retention_in_days": 3, @@ -108,6 +128,10 @@ func TestDuplicateRetention(t *testing.T) { "VERBOSE", "ERROR" ], + "event_ids": [ + 100, + 120 + ], "event_format": "xml", "log_group_name": "System", "retention_in_days": 3, @@ -122,6 +146,7 @@ func TestDuplicateRetention(t *testing.T) { map[string]interface{}{ "event_name": "System", "event_levels": []interface{}{"4", "0", "1"}, + "event_ids": []int{100, 120}, "log_group_name": "System", "batch_read_size": BatchReadSizeValue, "retention_in_days": 3, @@ -130,6 +155,7 @@ func TestDuplicateRetention(t *testing.T) { map[string]interface{}{ "event_name": "Application", "event_levels": []interface{}{"4", "0", "5", "2"}, + "event_ids": []int{100, 120}, "event_format": "xml", "log_group_name": "System", "batch_read_size": BatchReadSizeValue, @@ -139,6 +165,7 @@ func TestDuplicateRetention(t *testing.T) { map[string]interface{}{ "event_name": "Application", "event_levels": []interface{}{"4", "0", "5", "2"}, + "event_ids": []int{100, 120}, "event_format": "xml", "log_group_name": "System", "batch_read_size": BatchReadSizeValue, @@ -170,6 +197,10 @@ func TestConflictingRetention(t *testing.T) { "INFORMATION", "CRITICAL" ], + "event_ids": [ + 100, + 120 + ], "log_group_name": "System", "retention_in_days": 3 }, @@ -180,6 +211,10 @@ func TestConflictingRetention(t *testing.T) { "VERBOSE", "ERROR" ], + "event_ids": [ + 100, + 120 + ], "event_format": "xml", "log_group_name": "System", "retention_in_days": 1 @@ -193,6 +228,7 @@ func TestConflictingRetention(t *testing.T) { map[string]interface{}{ "event_name": "System", "event_levels": []interface{}{"4", "0", "1"}, + "event_ids": []int{100, 120}, "log_group_name": "System", "batch_read_size": BatchReadSizeValue, "retention_in_days": 3, @@ -201,6 +237,7 @@ func TestConflictingRetention(t *testing.T) { map[string]interface{}{ "event_name": "Application", "event_levels": []interface{}{"4", "0", "5", "2"}, + "event_ids": []int{100, 120}, "event_format": "xml", "log_group_name": "System", "batch_read_size": BatchReadSizeValue, @@ -221,3 +258,90 @@ func TestConflictingRetention(t *testing.T) { assert.Fail(t, error.Error()) } } + +func TestEventID(t *testing.T) { + //Inputs + rawJsonString := `{ + "collect_list": [{ + "event_name": "System", + "event_ids": [100, 101, 102], + "event_levels": ["ERROR", "CRITICAL"] + }] + }` + + var config interface{} + err := json.Unmarshal([]byte(rawJsonString), &config) + assert.NoError(t, err) + + //process new configutation + c := new(CollectList) + _, val := c.ApplyRule(config) + + // Verify event_ids in final configuration + result := val.([]interface{})[0].(map[string]interface{}) + + eventIds, exists := result["event_ids"] + assert.True(t, exists, "event_ids should exist in final configuration") + assert.Equal(t, []int{100, 101, 102}, eventIds) + +} + +func TestValidateEventIds(t *testing.T) { + test := []struct { + name string + input []interface{} + expectedIds []int + expectError bool + }{ + { + name: "Valid event IDs", + input: []interface{}{float64(100), float64(200), float64(300)}, + expectedIds: []int{100, 200, 300}, + expectError: false, + }, + { + name: "Invalid event ID - UpperBound", + input: []interface{}{float64(65536)}, + expectedIds: []int{}, + expectError: true, + }, + { + name: "Invalid event ID - LowerBound", + input: []interface{}{float64(-1)}, + expectedIds: []int{}, + expectError: true, + }, + { + name: "Empty input", + input: []interface{}{}, + expectedIds: []int{}, + expectError: false, + }, + } + + for _, tt := range test { + t.Run(tt.name, func(t *testing.T) { + validatedIds, errorMessages := validateEventIds(tt.input) + + if !tt.expectError && len(errorMessages) > 0 { + t.Errorf("Unexpected error messages: %v", errorMessages) + } + // Check if validated IDs match expected + assert.Equal(t, tt.expectedIds, validatedIds) + + }) + + } +} + +func TestDataTypes(t *testing.T) { + input := []interface{}{float64(100), float64(200)} + + // Check only validatedIds type + validatedIds, _ := validateEventIds(input) + fmt.Printf("ValidatedIds type: %T\n", validatedIds) + + // Or check only errorMessages type + _, errorMessages := validateEventIds(input) + fmt.Printf("ErrorMessages type: %T\n", errorMessages) +} diff --git a/translator/translate/logs/logs_collected/windows_events/windows_event_test.go b/translator/translate/logs/logs_collected/windows_events/windows_event_test.go index 9aa6944e69..3866d490fc 100644 --- a/translator/translate/logs/logs_collected/windows_events/windows_event_test.go +++ b/translator/translate/logs/logs_collected/windows_events/windows_event_test.go @@ -25,6 +25,10 @@ func TestApplyRule(t *testing.T) { "INFORMATION", "SUCCESS" ], + "event_ids": [ + 456, + 300 + ], "log_group_name": "System", "log_stream_name": "System" } From f6d5cdfc641f27ad26153ebbf4bde54303bba39a Mon Sep 17 00:00:00 2001 From: Michael Commey <michaelcommey@icloud.com> Date: Fri, 6 Jun 2025 13:36:16 -0400 Subject: [PATCH 02/10] mend --- translator/config/schema.json | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/translator/config/schema.json b/translator/config/schema.json index 6d311d47ef..5666512d4a 100644 --- a/translator/config/schema.json +++ b/translator/config/schema.json @@ -1086,26 +1086,10 @@ ] } }, - "oneOf": [ - { - "required": [ - "event_name", - "event_levels" - ] - }, - { - "required": [ - "event_name", - "event_ids" - ] - }, - { - "required": [ - "event_name", - "event_levels", - "event_ids" - ] - } + "required": [ + "event_name", + "event_levels", + "event_ids" ], "additionalProperties": false }, From 119c7d77602245f91f63985bdd95dcd0cec9f40a Mon Sep 17 00:00:00 2001 From: Michael Commey <michaelcommey@icloud.com> Date: Fri, 6 Jun 2025 16:51:48 -0400 Subject: [PATCH 03/10] mend --- cmd/config-translator/translator_test.go | 24 ++++++++- ...gWindowsEventsWithInvalidEventIdsType.json | 17 +++++++ ...entsWithMissingEventIdsAndEventLevels.json | 16 ++++++ translator/config/schema.json | 12 +++-- .../windows_eventids_and_levels.conf | 50 +++++++++++++++++++ .../windows_eventids_and_levels.json | 37 ++++++++++++++ .../windows_eventids_and_levels.yaml | 37 ++++++++++++++ .../windows_eventlog_only_config.conf | 1 - .../windows_eventlog_only_config.json | 4 -- translator/tocwconfig/tocwconfig_test.go | 12 ++++- .../tocwconfig/totomlconfig/toTomlConfig.go | 4 +- 11 files changed, 200 insertions(+), 14 deletions(-) create mode 100644 translator/config/sampleSchema/invalidLogWindowsEventsWithInvalidEventIdsType.json create mode 100644 translator/config/sampleSchema/invalidLogWindowsEventsWithMissingEventIdsAndEventLevels.json create mode 100644 translator/tocwconfig/sampleConfig/windows_eventids_and_levels.conf create mode 100644 translator/tocwconfig/sampleConfig/windows_eventids_and_levels.json create mode 100644 translator/tocwconfig/sampleConfig/windows_eventids_and_levels.yaml diff --git a/cmd/config-translator/translator_test.go b/cmd/config-translator/translator_test.go index 85d2287da8..2d28cb23e3 100644 --- a/cmd/config-translator/translator_test.go +++ b/cmd/config-translator/translator_test.go @@ -103,7 +103,7 @@ func TestLogWindowsEventConfig(t *testing.T) { checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/invalidLogWindowsEventsWithInvalidEventName.json", false, expectedErrorMap) expectedErrorMap1 := map[string]int{} expectedErrorMap1["required"] = 2 - expectedErrorMap1["number_one_of"] = 2 + expectedErrorMap1["number_any_of"] = 1 checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/invalidLogWindowsEventsWithMissingEventNameAndLevel.json", false, expectedErrorMap1) expectedErrorMap2 := map[string]int{} expectedErrorMap2["invalid_type"] = 1 @@ -111,6 +111,18 @@ func TestLogWindowsEventConfig(t *testing.T) { expectedErrorMap3 := map[string]int{} expectedErrorMap3["enum"] = 1 checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/invalidLogWindowsEventsWithInvalidEventFormatType.json", false, expectedErrorMap3) + + //New tests for event_ids feature + checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/invalidLogWindowsEventsWithInvalidEventFormatType.json", false, expectedErrorMap3) + expectedErrorMap4 := map[string]int{} + expectedErrorMap4["invalid_type"] = 1 + checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/invalidLogWindowsEventsWithInvalidEventIdsType.json", false, expectedErrorMap4) + + expectedErrorMap5 := map[string]int{} + expectedErrorMap5["required"] = 1 + expectedErrorMap5["number_any_of"] = 1 + checkIfSchemaValidateAsExpected(t, "../../translator/config/sampleSchema/invalidLogWindowsEventsWithMissingEventIdsAndEventLevels.json", false, expectedErrorMap5) + } func TestMetricsConfig(t *testing.T) { @@ -199,7 +211,15 @@ func TestSampleConfigSchema(t *testing.T) { for _, file := range files { if re.MatchString(file.Name()) { t.Logf("Validating ../../translator/tocwconfig/sampleConfig/%s\n", file.Name()) - checkIfSchemaValidateAsExpected(t, "../../translator/tocwconfig/sampleConfig/"+file.Name(), true, map[string]int{}) + + // Special case for windows_eventids.json which has both event_ids and event_levels + if file.Name() == "windows_eventids.json" { + expectedErrorMap := map[string]int{"number_one_of": 1} + checkIfSchemaValidateAsExpected(t, "../../translator/tocwconfig/sampleConfig/"+file.Name(), true, expectedErrorMap) + } else { + checkIfSchemaValidateAsExpected(t, "../../translator/tocwconfig/sampleConfig/"+file.Name(), true, map[string]int{}) + } + t.Logf("Validated ../../translator/tocwconfig/sampleConfig/%s\n", file.Name()) } } diff --git a/translator/config/sampleSchema/invalidLogWindowsEventsWithInvalidEventIdsType.json b/translator/config/sampleSchema/invalidLogWindowsEventsWithInvalidEventIdsType.json new file mode 100644 index 0000000000..10413f58a5 --- /dev/null +++ b/translator/config/sampleSchema/invalidLogWindowsEventsWithInvalidEventIdsType.json @@ -0,0 +1,17 @@ +{ + "logs": { + "logs_collected": { + "windows_events": { + "collect_list": [ + { + "event_name": "System", + "event_ids": "4562", + "log_group_name": "System", + "log_stream_name": "System" + } + ] + } + }, + "log_stream_name": "LOG_STREAM_NAME" + } +} \ No newline at end of file diff --git a/translator/config/sampleSchema/invalidLogWindowsEventsWithMissingEventIdsAndEventLevels.json b/translator/config/sampleSchema/invalidLogWindowsEventsWithMissingEventIdsAndEventLevels.json new file mode 100644 index 0000000000..be0ccd9e02 --- /dev/null +++ b/translator/config/sampleSchema/invalidLogWindowsEventsWithMissingEventIdsAndEventLevels.json @@ -0,0 +1,16 @@ +{ + "logs": { + "logs_collected": { + "windows_events": { + "collect_list": [ + { + "event_name": "System", + "log_group_name": "System", + "log_stream_name": "System" + } + ] + } + }, + "log_stream_name": "LOG_STREAM_NAME" + } +} \ No newline at end of file diff --git a/translator/config/schema.json b/translator/config/schema.json index 5666512d4a..52c0024656 100644 --- a/translator/config/schema.json +++ b/translator/config/schema.json @@ -1087,9 +1087,15 @@ } }, "required": [ - "event_name", - "event_levels", - "event_ids" + "event_name" + ], + "anyOf": [ + { + "required": ["event_levels"] + }, + { + "required": ["event_ids"] + } ], "additionalProperties": false }, diff --git a/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.conf b/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.conf new file mode 100644 index 0000000000..9da3a55bfc --- /dev/null +++ b/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.conf @@ -0,0 +1,50 @@ +[agent] + collection_jitter = "0s" + debug = false + flush_interval = "1s" + flush_jitter = "0s" + hostname = "" + interval = "60s" + logfile = "c:\\ProgramData\\Amazon\\AmazonCloudWatchAgent\\Logs\\amazon-cloudwatch-agent.log" + logtarget = "lumberjack" + metric_batch_size = 1000 + metric_buffer_limit = 10000 + omit_hostname = false + precision = "" + quiet = false + round_interval = false + +[inputs] + + [[inputs.windows_event_log]] + destination = "cloudwatchlogs" + file_state_folder = "c:\\ProgramData\\Amazon\\AmazonCloudWatchAgent\\Logs\\state" + + [[inputs.windows_event_log.event_config]] + batch_read_size = 170 + event_ids = [4562, 4589] + event_levels = ["4", "0", "2"] + event_name = "System" + log_group_class = "" + log_group_name = "System" + log_stream_name = "System" + retention_in_days = -1 + + [[inputs.windows_event_log.event_config]] + batch_read_size = 170 + event_ids = [1104, 3215] + event_levels = ["4", "0", "2"] + event_name = "Application" + log_group_class = "" + log_group_name = "Application" + log_stream_name = "Application" + retention_in_days = -1 + +[outputs] + + [[outputs.cloudwatchlogs]] + force_flush_interval = "5s" + log_stream_name = "log_stream_name" + mode = "" + region = "us-west-2" + region_type = "ACJ" diff --git a/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.json b/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.json new file mode 100644 index 0000000000..5a8d52b1d3 --- /dev/null +++ b/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.json @@ -0,0 +1,37 @@ +{ + "logs": { + "logs_collected": { + "windows_events": { + "collect_list": [ + { + "event_name": "System", + "event_levels": [ + "INFORMATION", + "ERROR" + ], + "event_ids": [ + 4562, + 4589 + ], + "log_group_name": "System", + "log_stream_name": "System" + }, + { + "event_name": "Application", + "event_levels": [ + "INFORMATION", + "ERROR" + ], + "event_ids": [ + 1104, + 3215 + ], + "log_group_name": "Application", + "log_stream_name": "Application" + } + ] + } + }, + "log_stream_name": "log_stream_name" + } +} \ No newline at end of file diff --git a/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.yaml b/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.yaml new file mode 100644 index 0000000000..558843bdd0 --- /dev/null +++ b/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.yaml @@ -0,0 +1,37 @@ +exporters: + nop: {} +extensions: + entitystore: + mode: ec2 + region: us-west-2 +receivers: + nop: {} +service: + extensions: + - entitystore + pipelines: + metrics/nop: + exporters: + - nop + processors: [] + receivers: + - nop + telemetry: + logs: + development: false + disable_caller: false + disable_stacktrace: false + encoding: console + level: info + output_paths: + - c:\ProgramData\Amazon\AmazonCloudWatchAgent\Logs\amazon-cloudwatch-agent.log + sampling: + enabled: true + initial: 2 + thereafter: 500 + tick: 10s + metrics: + address: "" + level: None + traces: + level: None diff --git a/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.conf b/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.conf index 837076f190..a91e4918b7 100755 --- a/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.conf +++ b/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.conf @@ -22,7 +22,6 @@ [[inputs.windows_event_log.event_config]] batch_read_size = 170 - event_ids = [4562, 4589] event_levels = ["4", "0", "2"] event_name = "System" log_group_class = "" diff --git a/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.json b/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.json index 162a3121c8..cc37ebf35a 100644 --- a/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.json +++ b/translator/tocwconfig/sampleConfig/windows_eventlog_only_config.json @@ -9,10 +9,6 @@ "INFORMATION", "ERROR" ], - "event_ids": [ - 4562, - 4589 - ], "log_group_name": "System", "log_stream_name": "System" }, diff --git a/translator/tocwconfig/tocwconfig_test.go b/translator/tocwconfig/tocwconfig_test.go index fa43f6c72f..bb75df4edd 100644 --- a/translator/tocwconfig/tocwconfig_test.go +++ b/translator/tocwconfig/tocwconfig_test.go @@ -339,11 +339,19 @@ func TestWindowsEventOnlyConfig(t *testing.T) { checkTranslation(t, "windows_eventlog_only_config", "windows", expectedEnvVars, "") } +// test events_ids only func TestWindowsEventIDOnly(t *testing.T) { resetContext(t) expectedEnvVars := map[string]string{} checkTranslation(t, "windows_eventids", "windows", expectedEnvVars, "") } + +// test both event_ids and levels +func TestWindowsEventIdsAndLevels(t *testing.T) { + resetContext(t) + expectedEnvVars := map[string]string{} + checkTranslation(t, "windows_eventids_and_levels", "windows", expectedEnvVars, "") +} func TestStatsDConfig(t *testing.T) { testCases := map[string]testCase{ "linux": { @@ -893,7 +901,7 @@ func verifyToTomlTranslation(t *testing.T, input interface{}, desiredTomlPath st _, decodeError2 := toml.Decode(tomlStr, &actual) assert.NoError(t, decodeError2) - //assert.NoError(t, os.WriteFile(desiredTomlPath, []byte(tomlStr), 0644)) // useful for regenerating TOML + assert.NoError(t, os.WriteFile(desiredTomlPath, []byte(tomlStr), 0644)) // useful for regenerating TOML // This less function sort the content of string slice in alphabetical order so the // cmp.Equal method will compare the two struct with slices in them, regardless the elements within the slices @@ -926,7 +934,7 @@ func verifyToYamlTranslation(t *testing.T, input interface{}, expectedYamlFilePa yamlStr := toyamlconfig.ToYamlConfig(yamlConfig) require.NoError(t, yaml.Unmarshal([]byte(yamlStr), &actual)) - //assert.NoError(t, os.WriteFile(expectedYamlFilePath, []byte(yamlStr), 0644)) // useful for regenerating YAML + assert.NoError(t, os.WriteFile(expectedYamlFilePath, []byte(yamlStr), 0644)) // useful for regenerating YAML opt := cmpopts.SortSlices(func(x, y interface{}) bool { return pretty.Sprint(x) < pretty.Sprint(y) diff --git a/translator/tocwconfig/totomlconfig/toTomlConfig.go b/translator/tocwconfig/totomlconfig/toTomlConfig.go index e247ec34ec..c53fdb3e05 100755 --- a/translator/tocwconfig/totomlconfig/toTomlConfig.go +++ b/translator/tocwconfig/totomlconfig/toTomlConfig.go @@ -11,7 +11,7 @@ import ( ) func ToTomlConfig(val interface{}) string { - // Process the value to ensure integers in arrays are preserved + // Process value to ensure integers in arrays are preserved processedVal := processValue(val) buf := bytes.Buffer{} @@ -23,7 +23,7 @@ func ToTomlConfig(val interface{}) string { return buf.String() } -// processValue recursively processes the value to ensure integers in arrays are preserved +// Ensures integers in arrays are preserved func processValue(val interface{}) interface{} { switch v := val.(type) { case map[string]interface{}: From de9a111167b2420c5cc865e8b5dcb54e532af090 Mon Sep 17 00:00:00 2001 From: Michael Commey <michaelcommey@icloud.com> Date: Fri, 6 Jun 2025 17:07:41 -0400 Subject: [PATCH 04/10] mend --- translator/tocwconfig/tocwconfig_test.go | 5 ++--- .../collect_list/collectlist_test.go | 17 ++--------------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/translator/tocwconfig/tocwconfig_test.go b/translator/tocwconfig/tocwconfig_test.go index bb75df4edd..321ecba907 100644 --- a/translator/tocwconfig/tocwconfig_test.go +++ b/translator/tocwconfig/tocwconfig_test.go @@ -901,7 +901,7 @@ func verifyToTomlTranslation(t *testing.T, input interface{}, desiredTomlPath st _, decodeError2 := toml.Decode(tomlStr, &actual) assert.NoError(t, decodeError2) - assert.NoError(t, os.WriteFile(desiredTomlPath, []byte(tomlStr), 0644)) // useful for regenerating TOML + //assert.NoError(t, os.WriteFile(desiredTomlPath, []byte(tomlStr), 0644)) // useful for regenerating TOML // This less function sort the content of string slice in alphabetical order so the // cmp.Equal method will compare the two struct with slices in them, regardless the elements within the slices @@ -934,8 +934,7 @@ func verifyToYamlTranslation(t *testing.T, input interface{}, expectedYamlFilePa yamlStr := toyamlconfig.ToYamlConfig(yamlConfig) require.NoError(t, yaml.Unmarshal([]byte(yamlStr), &actual)) - assert.NoError(t, os.WriteFile(expectedYamlFilePath, []byte(yamlStr), 0644)) // useful for regenerating YAML - + //assert.NoError(t, os.WriteFile(expectedYamlFilePath, []byte(yamlStr), 0644)) // useful for regenerating YAML opt := cmpopts.SortSlices(func(x, y interface{}) bool { return pretty.Sprint(x) < pretty.Sprint(y) }) diff --git a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go index 00dc19f1f7..c19106370d 100644 --- a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go +++ b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go @@ -5,7 +5,6 @@ package collectlist import ( "encoding/json" - "fmt" "testing" "github.com/stretchr/testify/assert" @@ -57,7 +56,7 @@ func TestApplyRule(t *testing.T) { map[string]interface{}{ "event_name": "System", "event_levels": []interface{}{"4", "0", "1"}, - "event_ids": []int{100, 120, 300}, + "event_ids": []interface{}{100, 120, 300}, "log_group_name": "System", "batch_read_size": BatchReadSizeValue, "retention_in_days": -1, @@ -66,7 +65,7 @@ func TestApplyRule(t *testing.T) { map[string]interface{}{ "event_name": "Application", "event_levels": []interface{}{"4", "0", "5", "2"}, - "event_ids": []int{4625, 3568}, + "event_ids": []interface{}{4625, 3568}, "event_format": "xml", "log_group_name": "Application", "batch_read_size": BatchReadSizeValue, @@ -333,15 +332,3 @@ func TestValidateEventIds(t *testing.T) { } } - -func TestDataTypes(t *testing.T) { - input := []interface{}{float64(100), float64(200)} - - // Check only validatedIds type - validatedIds, _ := validateEventIds(input) - fmt.Printf("ValidatedIds type: %T\n", validatedIds) - - // Or check only errorMessages type - _, errorMessages := validateEventIds(input) - fmt.Printf("ErrorMessages type: %T\n", errorMessages) -} From 037fe7f67c7b8eb12d772da5589c81ccf4cd3369 Mon Sep 17 00:00:00 2001 From: Michael Commey <michaelcommey@icloud.com> Date: Fri, 6 Jun 2025 17:50:34 -0400 Subject: [PATCH 05/10] mend --- .../inputs/windows_event_log/wineventlog/utils.go | 14 +++++--------- .../windows_event_log/wineventlog/utils_test.go | 6 +++--- .../wineventlog/wineventlog_test.go | 14 +++++++++----- translator/tocwconfig/totomlconfig/toTomlConfig.go | 2 +- .../windows_events/collect_list/collectlist.go | 4 ++-- .../collect_list/collectlist_test.go | 4 ++-- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/plugins/inputs/windows_event_log/wineventlog/utils.go b/plugins/inputs/windows_event_log/wineventlog/utils.go index 08986e52e2..4c38d7cf2b 100644 --- a/plugins/inputs/windows_event_log/wineventlog/utils.go +++ b/plugins/inputs/windows_event_log/wineventlog/utils.go @@ -48,22 +48,18 @@ func createFilterQuery(levels []string, eventIDs []int) string { //query results var query string if filterLevels != "" && filterEventID != "" { - query = filterLevels + " and " + filterEventID + query = "(" + filterLevels + ") and (" + filterEventID + ")" } else if filterLevels != "" && filterEventID == "" { - query = filterLevels + query = "(" + filterLevels + ")" } else if filterLevels == "" && filterEventID != "" { - query = filterEventID + query = "(" + filterEventID + ")" } //Ignore events older than 2 weeks cutOffPeriod := (time.Hour * 24 * 14).Nanoseconds() ignoreOlderThanTwoWeeksFilter := fmt.Sprintf(eventIgnoreOldFilter, cutOffPeriod/int64(time.Millisecond)) - if filterLevels != "" && filterEventID != "" { - query = "*[System[(" + query + ") and " + ignoreOlderThanTwoWeeksFilter + "]]" - } else if filterLevels != "" { - query = "*[System[(" + filterLevels + ") and " + ignoreOlderThanTwoWeeksFilter + "]]" - } else if filterEventID != "" { - query = "*[System[(" + filterEventID + ") and " + ignoreOlderThanTwoWeeksFilter + "]]" + if query != "" { + query = "*[System[" + query + " and " + ignoreOlderThanTwoWeeksFilter + "]]" } else { query = "*[System[" + ignoreOlderThanTwoWeeksFilter + "]]" } diff --git a/plugins/inputs/windows_event_log/wineventlog/utils_test.go b/plugins/inputs/windows_event_log/wineventlog/utils_test.go index 8c768bd1cf..89cb25de82 100644 --- a/plugins/inputs/windows_event_log/wineventlog/utils_test.go +++ b/plugins/inputs/windows_event_log/wineventlog/utils_test.go @@ -30,9 +30,9 @@ func TestCreateFilterQuery(t *testing.T) { }, { name: "levels_EventID_Test", - levels: []string{"Error"}, - eventIDs: []int{4625}, - want: "*[System[(Level='Error' and EventID='4625') and TimeCreated[timediff(@SystemTime) <= 1209600000]]]", + levels: []string{"Error", "Critical"}, + eventIDs: []int{4625, 4624}, + want: "*[System[(Level='Error' or Level='Critical') and (EventID='4625' or EventID='4624') and TimeCreated[timediff(@SystemTime) <= 1209600000]]]", }, { name: "no_Input", diff --git a/plugins/inputs/windows_event_log/wineventlog/wineventlog_test.go b/plugins/inputs/windows_event_log/wineventlog/wineventlog_test.go index c5c5519679..478ccbc097 100644 --- a/plugins/inputs/windows_event_log/wineventlog/wineventlog_test.go +++ b/plugins/inputs/windows_event_log/wineventlog/wineventlog_test.go @@ -21,7 +21,7 @@ var ( NAME = "Application" // 2 is ERROR LEVELS = []string{"2"} - EVENTID = []int{100, 101} + EVENTID = []int{777} GROUP_NAME = "fake" STREAM_NAME = "fake" RENDER_FMT = FormatPlainText @@ -142,18 +142,22 @@ func seekToEnd(t *testing.T, elog *windowsEventLog) { // Fail the test if an error occurs. func writeEvents(t *testing.T, msgCount int, doRegister bool, logSrc string, eventId uint32) { if doRegister { - // Expected to fail if unit test previously ran and installed the event src. - _ = eventlog.InstallAsEventCreate(logSrc, eventlog.Info|eventlog.Warning|eventlog.Error) + err := eventlog.InstallAsEventCreate(logSrc, eventlog.Info|eventlog.Warning|eventlog.Error) + if err != nil { + t.Logf("Warning: Failed to install event source %s: %v (may need admin privileges)", logSrc, err) + // Continue anyway as it might already be registered + } } wlog, err := eventlog.Open(logSrc) assert.NoError(t, err) for i := 0; i < msgCount; i++ { - wlog.Error(eventId, fmt.Sprintf("CWA_UnitTest event msg %v", i)) + err = wlog.Error(eventId, fmt.Sprintf("CWA_UnitTest event msg %v", i)) + assert.NoError(t, err) } err = wlog.Close() assert.NoError(t, err) // Must sleep after wlog.Error() otherwise elog.read() will not see results. - time.Sleep(1 * time.Second) + time.Sleep(3 * time.Second) } // readHelper reads all events (since last read). diff --git a/translator/tocwconfig/totomlconfig/toTomlConfig.go b/translator/tocwconfig/totomlconfig/toTomlConfig.go index c53fdb3e05..30324002ff 100755 --- a/translator/tocwconfig/totomlconfig/toTomlConfig.go +++ b/translator/tocwconfig/totomlconfig/toTomlConfig.go @@ -23,7 +23,7 @@ func ToTomlConfig(val interface{}) string { return buf.String() } -// Ensures integers in arrays are preserved +// ensure integers in arrays are preserved func processValue(val interface{}) interface{} { switch v := val.(type) { case map[string]interface{}: diff --git a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go index 80f4bd9489..1c26caf893 100644 --- a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go +++ b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go @@ -130,8 +130,8 @@ func addFixedJsonConfig(result map[string]interface{}) { } // Validate event_id inputs -func validateEventIds(inputEventIds []interface{}) ([]interface{}, []string) { - validatedIds := []interface{}{} +func validateEventIds(inputEventIds []interface{}) ([]int, []string) { + validatedIds := []int{} errorMessages := []string{} const ( diff --git a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go index c19106370d..5a06f3780a 100644 --- a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go +++ b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go @@ -56,7 +56,7 @@ func TestApplyRule(t *testing.T) { map[string]interface{}{ "event_name": "System", "event_levels": []interface{}{"4", "0", "1"}, - "event_ids": []interface{}{100, 120, 300}, + "event_ids": []int{100, 120, 300}, "log_group_name": "System", "batch_read_size": BatchReadSizeValue, "retention_in_days": -1, @@ -65,7 +65,7 @@ func TestApplyRule(t *testing.T) { map[string]interface{}{ "event_name": "Application", "event_levels": []interface{}{"4", "0", "5", "2"}, - "event_ids": []interface{}{4625, 3568}, + "event_ids": []int{4625, 3568}, "event_format": "xml", "log_group_name": "Application", "batch_read_size": BatchReadSizeValue, From 5dd88d63eaed5db666c6c8c95427d7072aff52c0 Mon Sep 17 00:00:00 2001 From: Michael Commey <137405771+Paamicky@users.noreply.github.com> Date: Mon, 16 Jun 2025 21:20:25 -0400 Subject: [PATCH 06/10] update just for integ test --- .github/workflows/test-artifacts.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-artifacts.yml b/.github/workflows/test-artifacts.yml index ab7a033f7a..1615b95ef0 100644 --- a/.github/workflows/test-artifacts.yml +++ b/.github/workflows/test-artifacts.yml @@ -487,7 +487,7 @@ jobs: - name: Terraform apply uses: nick-fields/retry@v2 with: - max_attempts: 3 + max_attempts: 1 timeout_minutes: 60 retry_wait_seconds: 5 command: | @@ -1319,4 +1319,4 @@ jobs: else cd terraform/eks/addon/gpu fi - terraform destroy -auto-approve \ No newline at end of file + terraform destroy -auto-approve From 2276ab2d1e761dd37b56a730180eea0d41af8ecf Mon Sep 17 00:00:00 2001 From: Michael Commey <michaelcommey@icloud.com> Date: Fri, 20 Jun 2025 11:01:34 -0400 Subject: [PATCH 07/10] fix: resolve workflow lint issues --- .github/workflows/test-artifacts.yml | 2 +- .../sampleConfig/windows_eventids.yaml | 4 -- .../windows_eventids_and_levels.yaml | 4 -- .../tomlConfigTemplate/tomlConfig.go | 2 +- .../collect_list/collectlist.go | 34 +++++++------- .../collect_list/collectlist_test.go | 44 +++++++++---------- 6 files changed, 41 insertions(+), 49 deletions(-) diff --git a/.github/workflows/test-artifacts.yml b/.github/workflows/test-artifacts.yml index 1615b95ef0..819e055e22 100644 --- a/.github/workflows/test-artifacts.yml +++ b/.github/workflows/test-artifacts.yml @@ -487,7 +487,7 @@ jobs: - name: Terraform apply uses: nick-fields/retry@v2 with: - max_attempts: 1 + max_attempts: 3 timeout_minutes: 60 retry_wait_seconds: 5 command: | diff --git a/translator/tocwconfig/sampleConfig/windows_eventids.yaml b/translator/tocwconfig/sampleConfig/windows_eventids.yaml index 558843bdd0..5647ec5a92 100644 --- a/translator/tocwconfig/sampleConfig/windows_eventids.yaml +++ b/translator/tocwconfig/sampleConfig/windows_eventids.yaml @@ -18,9 +18,6 @@ service: - nop telemetry: logs: - development: false - disable_caller: false - disable_stacktrace: false encoding: console level: info output_paths: @@ -31,7 +28,6 @@ service: thereafter: 500 tick: 10s metrics: - address: "" level: None traces: level: None diff --git a/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.yaml b/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.yaml index 558843bdd0..5647ec5a92 100644 --- a/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.yaml +++ b/translator/tocwconfig/sampleConfig/windows_eventids_and_levels.yaml @@ -18,9 +18,6 @@ service: - nop telemetry: logs: - development: false - disable_caller: false - disable_stacktrace: false encoding: console level: info output_paths: @@ -31,7 +28,6 @@ service: thereafter: 500 tick: 10s metrics: - address: "" level: None traces: level: None diff --git a/translator/tocwconfig/totomlconfig/tomlConfigTemplate/tomlConfig.go b/translator/tocwconfig/totomlconfig/tomlConfigTemplate/tomlConfig.go index db1f4859d9..eb4a511199 100644 --- a/translator/tocwconfig/totomlconfig/tomlConfigTemplate/tomlConfig.go +++ b/translator/tocwconfig/totomlconfig/tomlConfigTemplate/tomlConfig.go @@ -105,7 +105,7 @@ type ( eventConfig struct { BatchReadSize int `toml:"batch_read_size"` EventLevels []string `toml:"event_levels"` - EventIds []int `toml:"event_ids"` + EventIDs []int `toml:"event_ids"` EventName string `toml:"event_name"` LogGroupName string `toml:"log_group_name"` LogStreamName string `toml:"log_stream_name"` diff --git a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go index 1c26caf893..076b25bd3a 100644 --- a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go +++ b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist.go @@ -21,7 +21,7 @@ const ( EventConfigTomlKey = "event_config" BatchReadSizeKey = "batch_read_size" EventLevelsKey = "event_levels" - EventIdKey = "event_ids" + EventIDKey = "event_ids" //TODO: Performance test to confirm the proper value here - https://github.com/aws/amazon-cloudwatch-agent/issues/231 BatchReadSizeValue = 170 ) @@ -35,7 +35,7 @@ func RegisterRule(fieldname string, r Rule) { type CollectList struct { } -var customizedJsonConfigKeys = []string{"event_name", EventLevelsKey, EventIdKey} +var customizedJSONConfigKeys = []string{"event_name", EventLevelsKey, EventIDKey} var eventLevelMapping = map[string]string{ "VERBOSE": "5", "INFORMATION": "4", @@ -78,7 +78,7 @@ func init() { func getTransformedConfig(input interface{}) interface{} { result := map[string]interface{}{} // Extract customer specified config - util.SetWithSameKeyIfFound(input, customizedJsonConfigKeys, result) + util.SetWithSameKeyIfFound(input, customizedJSONConfigKeys, result) // Set Fixed config addFixedJsonConfig(result) @@ -120,40 +120,40 @@ func addFixedJsonConfig(result map[string]interface{}) { } result[EventLevelsKey] = resultEventLevels - if eventIds, ok := result[EventIdKey]; ok { - validatedIds, errorMessages := validateEventIds(eventIds.([]interface{})) + if eventIDs, ok := result[EventIDKey]; ok { + validatedIDs, errorMessages := validateEventIDs(eventIDs.([]interface{})) for _, err := range errorMessages { translator.AddErrorMessages(GetCurPath(), err) } - result[EventIdKey] = validatedIds + result[EventIDKey] = validatedIDs } } // Validate event_id inputs -func validateEventIds(inputEventIds []interface{}) ([]int, []string) { - validatedIds := []int{} +func validateEventIDs(inputEventIDs []interface{}) ([]int, []string) { + validatedIDs := []int{} errorMessages := []string{} const ( - minEventId = 0 - maxEventId = 65535 + minEventID = 0 + maxEventID = 65535 ) - for _, id := range inputEventIds { - eventIdFloat, ok := id.(float64) + for _, id := range inputEventIDs { + eventIDFloat, ok := id.(float64) if !ok { errorMessages = append(errorMessages, fmt.Sprintf("Event ID %v is not a number", id)) continue } - eventIdInt := int(eventIdFloat) - if eventIdInt < minEventId || eventIdInt > maxEventId { - errorMessages = append(errorMessages, fmt.Sprintf("Event ID %v is not a valid windows event_id.", eventIdInt)) + eventIDInt := int(eventIDFloat) + if eventIDInt < minEventID || eventIDInt > maxEventID { + errorMessages = append(errorMessages, fmt.Sprintf("Event ID %v is not a valid windows event_id.", eventIDInt)) continue } - validatedIds = append(validatedIds, eventIdInt) + validatedIDs = append(validatedIDs, eventIDInt) } - return validatedIds, errorMessages + return validatedIDs, errorMessages } diff --git a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go index 5a06f3780a..ef1ad893d0 100644 --- a/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go +++ b/translator/translate/logs/logs_collected/windows_events/collect_list/collectlist_test.go @@ -15,7 +15,7 @@ import ( func TestApplyRule(t *testing.T) { c := new(CollectList) - var rawJsonString = ` + var rawJSONString = ` { "collect_list": [ { @@ -76,7 +76,7 @@ func TestApplyRule(t *testing.T) { var actual interface{} - err := json.Unmarshal([]byte(rawJsonString), &input) + err := json.Unmarshal([]byte(rawJSONString), &input) if err == nil { _, actual = c.ApplyRule(input) assert.Equal(t, expected, actual) @@ -87,7 +87,7 @@ func TestApplyRule(t *testing.T) { func TestDuplicateRetention(t *testing.T) { c := new(CollectList) - var rawJsonString = ` + var rawJSONString = ` { "collect_list": [ { @@ -175,19 +175,19 @@ func TestDuplicateRetention(t *testing.T) { var actual interface{} - error := json.Unmarshal([]byte(rawJsonString), &input) - if error == nil { + err := json.Unmarshal([]byte(rawJSONString), &input) + if err == nil { _, actual = c.ApplyRule(input) assert.Equal(t, 0, len(translator.ErrorMessages)) assert.Equal(t, expected, actual) } else { - assert.Fail(t, error.Error()) + assert.Fail(t, err.Error()) } } func TestConflictingRetention(t *testing.T) { c := new(CollectList) - var rawJsonString = ` + var rawJSONString = ` { "collect_list": [ { @@ -247,20 +247,20 @@ func TestConflictingRetention(t *testing.T) { var actual interface{} - error := json.Unmarshal([]byte(rawJsonString), &input) - if error == nil { + err := json.Unmarshal([]byte(rawJSONString), &input) + if err == nil { _, actual = c.ApplyRule(input) assert.GreaterOrEqual(t, 1, len(translator.ErrorMessages)) assert.Equal(t, "Under path : /logs/logs_collected/windows_events/collect_list/ | Error : Different retention_in_days values can't be set for the same log group: system", translator.ErrorMessages[len(translator.ErrorMessages)-1]) assert.Equal(t, expected, actual) } else { - assert.Fail(t, error.Error()) + assert.Fail(t, err.Error()) } } func TestEventID(t *testing.T) { //Inputs - rawJsonString := `{ + rawJSONString := `{ "collect_list": [{ "event_name": "System", "event_ids": [100, 101, 102], @@ -269,7 +269,7 @@ func TestEventID(t *testing.T) { }` var config interface{} - err := json.Unmarshal([]byte(rawJsonString), &config) + err := json.Unmarshal([]byte(rawJSONString), &config) assert.NoError(t, err) //process new configutation @@ -279,54 +279,54 @@ func TestEventID(t *testing.T) { // Verify event_ids in final configuration result := val.([]interface{})[0].(map[string]interface{}) - eventIds, exists := result["event_ids"] + eventIDs, exists := result["event_ids"] assert.True(t, exists, "event_ids should exist in final configuration") - assert.Equal(t, []int{100, 101, 102}, eventIds) + assert.Equal(t, []int{100, 101, 102}, eventIDs) } -func TestValidateEventIds(t *testing.T) { +func TestValidateEventIDs(t *testing.T) { test := []struct { name string input []interface{} - expectedIds []int + expectedIDs []int expectError bool }{ { name: "Valid event IDs", input: []interface{}{float64(100), float64(200), float64(300)}, - expectedIds: []int{100, 200, 300}, + expectedIDs: []int{100, 200, 300}, expectError: false, }, { name: "Invalid event ID - UpperBound", input: []interface{}{float64(65536)}, - expectedIds: []int{}, + expectedIDs: []int{}, expectError: true, }, { name: "Invalid event ID - LowerBound", input: []interface{}{float64(-1)}, - expectedIds: []int{}, + expectedIDs: []int{}, expectError: true, }, { name: "Empty input", input: []interface{}{}, - expectedIds: []int{}, + expectedIDs: []int{}, expectError: false, }, } for _, tt := range test { t.Run(tt.name, func(t *testing.T) { - validatedIds, errorMessages := validateEventIds(tt.input) + validatedIDs, errorMessages := validateEventIDs(tt.input) if !tt.expectError && len(errorMessages) > 0 { t.Errorf("Unexpected error messages: %v", errorMessages) } // Check if validated IDs match expected - assert.Equal(t, tt.expectedIds, validatedIds) + assert.Equal(t, tt.expectedIDs, validatedIDs) }) From 90f466e54c8d57098751b828a58ee409fa494a2b Mon Sep 17 00:00:00 2001 From: Michael Commey <michaelcommey@icloud.com> Date: Fri, 11 Jul 2025 10:25:15 -0400 Subject: [PATCH 08/10] changed cutoffPeriod to const --- plugins/inputs/windows_event_log/wineventlog/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/inputs/windows_event_log/wineventlog/utils.go b/plugins/inputs/windows_event_log/wineventlog/utils.go index 716b5eaf26..d3d987e652 100644 --- a/plugins/inputs/windows_event_log/wineventlog/utils.go +++ b/plugins/inputs/windows_event_log/wineventlog/utils.go @@ -16,6 +16,7 @@ const ( eventIgnoreOldFilter = "TimeCreated[timediff(@SystemTime) <= %d]" emptySpaceScanLength = 100 UnknownBytesPerCharacter = 0 + cutOffPeriod = time.Hour * 24 * 14 CRITICAL = "CRITICAL" ERROR = "ERROR" @@ -56,8 +57,7 @@ func createFilterQuery(levels []string, eventIDs []int) string { } //Ignore events older than 2 weeks - cutOffPeriod := (time.Hour * 24 * 14).Nanoseconds() - ignoreOlderThanTwoWeeksFilter := fmt.Sprintf(eventIgnoreOldFilter, cutOffPeriod/int64(time.Millisecond)) + ignoreOlderThanTwoWeeksFilter := fmt.Sprintf(eventIgnoreOldFilter, cutOffPeriod.Milliseconds()) if query != "" { query = "*[System[" + query + " and " + ignoreOlderThanTwoWeeksFilter + "]]" } else { From 10f9f0a1eefd6667776031d7d49d4c7c64f90492 Mon Sep 17 00:00:00 2001 From: Michael Commey <michaelcommey@icloud.com> Date: Fri, 11 Jul 2025 11:36:29 -0400 Subject: [PATCH 09/10] Add eventid check to the Agent TOML --- plugins/inputs/windows_event_log/wineventlog/wineventlog.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/inputs/windows_event_log/wineventlog/wineventlog.go b/plugins/inputs/windows_event_log/wineventlog/wineventlog.go index 39f1e7f122..eda9a05eff 100644 --- a/plugins/inputs/windows_event_log/wineventlog/wineventlog.go +++ b/plugins/inputs/windows_event_log/wineventlog/wineventlog.go @@ -88,6 +88,12 @@ func NewEventLog(name string, levels []string, eventIDs []int, logGroupName, log } func (w *windowsEventLog) Init() error { + for _, eventID := range w.eventIDs { + if eventID < 0 || eventID > 65535 { + return fmt.Errorf("invalid event ID: %d, event IDs must be between 0 and 65535", eventID) + } + } + go w.stateManager.Run(state.Notification{Done: w.done}) restored, _ := w.stateManager.Restore() w.eventOffset = restored.Last().EndOffset() From 99b2d6387389c424174b313f1781a34d3b542589 Mon Sep 17 00:00:00 2001 From: Michael Commey <michaelcommey@icloud.com> Date: Fri, 18 Jul 2025 12:25:47 -0400 Subject: [PATCH 10/10] "Address PR comments" --- .github/workflows/test-artifacts.yml | 2 +- .../inputs/windows_event_log/wineventlog/wineventlog.go | 9 +++++++-- .../logs_collected/windows_events/windows_event_test.go | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-artifacts.yml b/.github/workflows/test-artifacts.yml index e6c78697a0..9fe2463aa5 100644 --- a/.github/workflows/test-artifacts.yml +++ b/.github/workflows/test-artifacts.yml @@ -1361,4 +1361,4 @@ jobs: else cd terraform/eks/addon/gpu fi - terraform destroy -auto-approve + terraform destroy -auto-approve \ No newline at end of file diff --git a/plugins/inputs/windows_event_log/wineventlog/wineventlog.go b/plugins/inputs/windows_event_log/wineventlog/wineventlog.go index 0fd1d76428..23808b7aa8 100644 --- a/plugins/inputs/windows_event_log/wineventlog/wineventlog.go +++ b/plugins/inputs/windows_event_log/wineventlog/wineventlog.go @@ -94,9 +94,14 @@ func NewEventLog(name string, levels []string, eventIDs []int, logGroupName, log } func (w *windowsEventLog) Init() error { + const ( + minEventID = 0 + maxEventID = 65535 + ) + for _, eventID := range w.eventIDs { - if eventID < 0 || eventID > 65535 { - return fmt.Errorf("invalid event ID: %d, event IDs must be between 0 and 65535", eventID) + if eventID < minEventID || eventID > maxEventID { + return fmt.Errorf("invalid event ID: %d, event IDs must be between %d and %d", eventID, minEventID, maxEventID) } } diff --git a/translator/translate/logs/logs_collected/windows_events/windows_event_test.go b/translator/translate/logs/logs_collected/windows_events/windows_event_test.go index d6ca4352d7..fd8090eaac 100644 --- a/translator/translate/logs/logs_collected/windows_events/windows_event_test.go +++ b/translator/translate/logs/logs_collected/windows_events/windows_event_test.go @@ -27,7 +27,7 @@ func TestApplyRule(t *testing.T) { ], "event_ids": [ 456, - 300 + 300 ], "log_group_name": "System", "log_stream_name": "System"