Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 38 additions & 10 deletions lex.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,11 +275,18 @@ func lexProtocol(l *lexer) stateFn {
// lexSourceAddress consumes a source address.
func lexSourceAddress(l *lexer) stateFn {
l.ignoreSpaces()
var depth int
for {
switch l.next() {
case '[':
depth++
case ']':
depth--
case ' ':
l.emit(itemSourceAddress, true)
return lexSourcePort
if depth <= 0 {
l.emit(itemSourceAddress, true)
return lexSourcePort
}
case eof:
return l.unexpectedEOF()
}
Expand All @@ -289,11 +296,18 @@ func lexSourceAddress(l *lexer) stateFn {
// lexSourcePort consumes a source port.
func lexSourcePort(l *lexer) stateFn {
l.ignoreSpaces()
var depth int
for {
switch l.next() {
case '[':
depth++
case ']':
depth--
case ' ':
l.emit(itemSourcePort, true)
return lexDirection
if depth <= 0 {
l.emit(itemSourcePort, true)
return lexDirection
}
case eof:
return l.unexpectedEOF()
}
Expand All @@ -314,11 +328,18 @@ func lexDirection(l *lexer) stateFn {
// lexDestinationAddress consumes a destination address.
func lexDestinationAddress(l *lexer) stateFn {
l.ignoreSpaces()
var depth int
for {
switch l.next() {
case '[':
depth++
case ']':
depth--
case ' ':
l.emit(itemDestinationAddress, true)
return lexDestinationPort
if depth <= 0 {
l.emit(itemDestinationAddress, true)
return lexDestinationPort
}
case eof:
return l.unexpectedEOF()
}
Expand All @@ -327,13 +348,20 @@ func lexDestinationAddress(l *lexer) stateFn {

// lexDestinationPort consumes a destination port.
func lexDestinationPort(l *lexer) stateFn {
var depth int
for {
switch l.next() {
case '[':
depth++
case ']':
depth--
case '(':
l.backup()
l.emit(itemDestinationPort, true)
l.skipNext()
return lexOptionKey
if depth <= 0 {
l.backup()
l.emit(itemDestinationPort, true)
l.skipNext()
return lexOptionKey
}
case eof:
return l.unexpectedEOF()
}
Expand Down
16 changes: 16 additions & 0 deletions lex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,22 @@ func TestLexer(t *testing.T) {
{itemEOR, ""},
},
},
{
name: "spaces in network component",
input: "alert tcp [1.1.1.1, 1.1.1.2] [80, 443] -> [2.2.2.2, 2.2.2.3] [8080, 8443] (key1:value1;)",
items: []item{
{itemAction, "alert"},
{itemProtocol, "tcp"},
{itemSourceAddress, "[1.1.1.1, 1.1.1.2]"},
{itemSourcePort, "[80, 443]"},
{itemDirection, "->"},
{itemDestinationAddress, "[2.2.2.2, 2.2.2.3]"},
{itemDestinationPort, "[8080, 8443]"},
{itemOptionKey, "key1"},
{itemOptionValue, "value1"},
{itemEOR, ""},
},
},
{
name: "parentheses in value",
input: `alert dns $HOME_NET any -> any any (reference:url,en.wikipedia.org/wiki/Tor_(anonymity_network); sid:42;)`,
Expand Down
5 changes: 3 additions & 2 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,9 +470,10 @@ func (r *Rule) protocol(key item) error {

// network decodes an IDS rule network (networks and ports) based on its key.
func (r *Rule) network(key item) error {
val := strings.ReplaceAll(key.value, " ", "")
// Identify if the whole network component is negated.
tmp := strings.TrimPrefix(key.value, "!")
negated := len(tmp) < len(key.value)
tmp := strings.TrimPrefix(val, "!")
negated := len(tmp) < len(val)

// This is a hack. We use a regexp to replace the outer `,` with `___`
// to give us a discrete string to split on, avoiding the inner `,`.
Expand Down
43 changes: 40 additions & 3 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,30 @@ func TestParseRule(t *testing.T) {
},
},
},
{
name: "spaces in network object",
rule: `alert tcp any any -> [1.1.1.1, 1.1.1.2] any (msg:"test"; content:"123"; sid:1; rev:1;)`,
want: &Rule{
Action: "alert",
Protocol: "tcp",
Source: Network{
Nets: []string{"any"},
Ports: []string{"any"},
},
Destination: Network{
Nets: []string{"1.1.1.1,1.1.1.2"},
Ports: []string{"any"},
},
SID: 1,
Revision: 1,
Description: "test",
Matchers: []orderedMatcher{
&Content{
Pattern: []byte("123"),
},
},
},
},
{
name: "simple content",
rule: `alert udp $HOME_NET any -> $EXTERNAL_NET any (sid:1337; msg:"foo"; content:"AA"; rev:2;)`,
Expand Down Expand Up @@ -2167,9 +2191,22 @@ func TestParseRule(t *testing.T) {
wantErr: true,
},
{
name: "network with space",
rule: `alert tcp $EXTERNAL_NET 443 -> $HOME_NET [123, 234] (msg:"bad network definition"; sid:4321;)`,
wantErr: true,
name: "network with space",
rule: `alert tcp $EXTERNAL_NET 443 -> $HOME_NET [123, 234] (msg:"bad network definition"; sid:4321;)`,
want: &Rule{
Action: "alert",
Protocol: "tcp",
Source: Network{
Nets: []string{"$EXTERNAL_NET"},
Ports: []string{"443"},
},
Destination: Network{
Nets: []string{"$HOME_NET"},
Ports: []string{"123,234"},
},
SID: 4321,
Description: "bad network definition",
},
},
{
name: "content with backslash at end",
Expand Down
Loading