Skip to content

Commit 3b24718

Browse files
Merge pull request #17 from Graylog2/additional-syslog-events
Support FortiGate and Cisco syslog events
2 parents f097402 + 48049c6 commit 3b24718

File tree

6 files changed

+503
-7
lines changed

6 files changed

+503
-7
lines changed

.travis.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ sudo: required
22
dist: trusty
33
language: java
44
jdk:
5-
# - openjdk6
6-
# - openjdk7
7-
- oraclejdk7
85
- oraclejdk8
96
addons:
107
# Fix OpenJDK builds

pom.xml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949

5050
<properties>
5151
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
52+
<maven.compiler.source>1.8</maven.compiler.source>
53+
<maven.compiler.target>1.8</maven.compiler.target>
5254
</properties>
5355

5456
<distributionManagement>
@@ -105,6 +107,12 @@
105107
<version>2.4.0</version>
106108
<scope>test</scope>
107109
</dependency>
110+
<dependency>
111+
<groupId>org.assertj</groupId>
112+
<artifactId>assertj-core</artifactId>
113+
<version>3.6.2</version>
114+
<scope>test</scope>
115+
</dependency>
108116
</dependencies>
109117

110118
<build>
@@ -120,10 +128,6 @@
120128
<groupId>org.apache.maven.plugins</groupId>
121129
<artifactId>maven-compiler-plugin</artifactId>
122130
<version>3.5.1</version>
123-
<configuration>
124-
<source>1.6</source>
125-
<target>1.6</target>
126-
</configuration>
127131
</plugin>
128132
<plugin>
129133
<groupId>org.apache.maven.plugins</groupId>
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package org.graylog2.syslog4j.server.impl.event;
2+
3+
import java.net.InetAddress;
4+
import java.time.ZoneOffset;
5+
import java.time.ZonedDateTime;
6+
import java.time.format.DateTimeFormatter;
7+
import java.time.format.DateTimeParseException;
8+
import java.util.Calendar;
9+
import java.util.Date;
10+
import java.util.Locale;
11+
12+
/**
13+
* CiscoSyslogServerEvent provides an implementation of the
14+
* SyslogServerEventIF interface that supports receiving of
15+
* Cisco syslog messages.
16+
*
17+
* @see <a href="http://www.ciscopress.com/articles/article.asp?p=426638">An Overview of the syslog Protocol</a>
18+
*/
19+
public class CiscoSyslogServerEvent extends SyslogServerEvent {
20+
private static final DateTimeFormatter DEFAULT_FORMATTER =
21+
DateTimeFormatter
22+
.ofPattern("yyyy MMM ppd HH:mm:ss[.SSS][ zzz]", Locale.ROOT)
23+
.withZone(ZoneOffset.UTC);
24+
private int sequenceNumber = 0;
25+
26+
public CiscoSyslogServerEvent(final byte[] message, int length, InetAddress inetAddress) {
27+
super();
28+
29+
initialize(message, length, inetAddress);
30+
parse();
31+
}
32+
33+
public CiscoSyslogServerEvent(final String message, InetAddress inetAddress) {
34+
super();
35+
36+
initialize(message, inetAddress);
37+
parse();
38+
}
39+
40+
@Override
41+
protected void parsePriority() {
42+
if (this.message.charAt(0) == '<') {
43+
int i = this.message.indexOf(">");
44+
45+
if (i <= 4 && i > -1) {
46+
String priorityStr = this.message.substring(1, i);
47+
48+
int priority = 0;
49+
try {
50+
priority = Integer.parseInt(priorityStr);
51+
this.facility = priority >> 3;
52+
this.level = priority - (this.facility << 3);
53+
54+
this.message = this.message.substring(i + 1);
55+
56+
parseSequenceNumber();
57+
parseDate();
58+
} catch (NumberFormatException nfe) {
59+
//
60+
}
61+
62+
parseHost();
63+
}
64+
}
65+
}
66+
67+
private void parseSequenceNumber() {
68+
int i = this.message.indexOf(':');
69+
if (i > -1) {
70+
String sequenceNumberStr = this.message.substring(0, i);
71+
if (sequenceNumberStr.isEmpty()) {
72+
this.message = this.message.substring(i + 1);
73+
} else {
74+
try {
75+
this.sequenceNumber = Integer.parseInt(sequenceNumberStr);
76+
this.message = this.message.substring(i + 1);
77+
} catch (NumberFormatException nfe) {
78+
//
79+
}
80+
}
81+
}
82+
}
83+
84+
@Override
85+
protected void parseHost() {
86+
if (message.indexOf('%') < 1) {
87+
this.host = "";
88+
} else {
89+
int i = this.message.indexOf(' ');
90+
if (i > -1) {
91+
this.host = this.message.substring(0, i).trim();
92+
93+
// Skip ' ' and ':' characters
94+
char c = message.charAt(i);
95+
while (c == ' ' || c == ':') {
96+
c = message.charAt(++i);
97+
}
98+
99+
this.message = this.message.substring(i);
100+
}
101+
}
102+
}
103+
104+
@Override
105+
protected void parseDate() {
106+
// Skip leading spaces
107+
while (message.charAt(0) == ' ') {
108+
message = message.substring(1);
109+
}
110+
111+
// Skip leading asterisk
112+
if (message.charAt(0) == '*') {
113+
message = message.substring(1);
114+
}
115+
116+
int dateLength = message.indexOf(": ");
117+
if (this.message.length() > dateLength) {
118+
boolean isYearMissing = Character.isLetter(message.charAt(0));
119+
String originalDate = this.message.substring(0, dateLength);
120+
DateTimeFormatter formatter = DEFAULT_FORMATTER;
121+
122+
// Hacky override for: "Mar 06 2016 12:53:10 DEVICENAME :"
123+
if (Character.isDigit(message.charAt(7))
124+
&& Character.isDigit(message.charAt(8))
125+
&& Character.isDigit(message.charAt(9))
126+
&& Character.isDigit(message.charAt(10))) {
127+
dateLength = 20;
128+
isYearMissing = false;
129+
originalDate = this.message.substring(0, dateLength);
130+
formatter = DateTimeFormatter
131+
.ofPattern("MMM ppd yyyy HH:mm:ss", Locale.ROOT)
132+
.withZone(ZoneOffset.UTC);
133+
}
134+
135+
try {
136+
if (isYearMissing) {
137+
String year = Integer.toString(Calendar.getInstance().get(Calendar.YEAR));
138+
String modifiedDate = year + " " + originalDate;
139+
final ZonedDateTime dateTime = ZonedDateTime.parse(modifiedDate, formatter);
140+
this.date = Date.from(dateTime.toInstant());
141+
} else {
142+
final ZonedDateTime dateTime = ZonedDateTime.parse(originalDate, formatter);
143+
this.date = Date.from(dateTime.toInstant());
144+
}
145+
146+
this.message = this.message.substring(dateLength + 1);
147+
148+
} catch (DateTimeParseException pe) {
149+
this.date = new Date();
150+
}
151+
}
152+
}
153+
154+
public int getSequenceNumber() {
155+
return sequenceNumber;
156+
}
157+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package org.graylog2.syslog4j.server.impl.event;
2+
3+
import org.graylog2.syslog4j.server.SyslogServerEventIF;
4+
5+
import java.nio.charset.Charset;
6+
import java.nio.charset.StandardCharsets;
7+
import java.time.LocalDate;
8+
import java.time.LocalTime;
9+
import java.time.ZoneOffset;
10+
import java.time.ZonedDateTime;
11+
import java.time.format.DateTimeFormatter;
12+
import java.util.Collections;
13+
import java.util.Date;
14+
import java.util.HashMap;
15+
import java.util.Map;
16+
import java.util.regex.Matcher;
17+
import java.util.regex.Pattern;
18+
19+
import static java.util.Objects.requireNonNull;
20+
21+
/**
22+
* FortiGateSyslogEvent provides an implementation of the
23+
* SyslogServerEventIF interface that supports receiving of
24+
* FortiGate/FortiOS syslog messages.
25+
*
26+
* @see <a href="http://help.fortinet.com/fos50hlp/54/Content/FortiOS/fortigate-logging-reporting-54/logs.htm#Log_messages">FortiGate logging and reporting overview</a>
27+
*/
28+
public class FortiGateSyslogEvent implements SyslogServerEventIF {
29+
private static final Pattern PRI_PATTERN = Pattern.compile("^<(\\d{1,3})>(.*)$");
30+
private static final Pattern KV_PATTERN = Pattern.compile("(\\w+)=([^\\s\"]*)");
31+
private static final Pattern QUOTED_KV_PATTERN = Pattern.compile("(\\w+)=\"([^\"]*)\"");
32+
33+
private final String rawEvent;
34+
private Date date;
35+
private int facility;
36+
private int level;
37+
private String host;
38+
private String message;
39+
private Charset charSet = StandardCharsets.UTF_8;
40+
private Map<String, String> fields = Collections.emptyMap();
41+
42+
public FortiGateSyslogEvent(final String rawEvent) {
43+
this.rawEvent = requireNonNull(rawEvent, "rawEvent");
44+
parse(rawEvent);
45+
}
46+
47+
private void parse(String event) {
48+
final Matcher matcher = PRI_PATTERN.matcher(event);
49+
if (!matcher.find()) {
50+
throw new IllegalArgumentException("Invalid Fortigate syslog message");
51+
} else {
52+
final String priority = matcher.group(1);
53+
final String message = matcher.group(2);
54+
55+
parsePriority(priority);
56+
setMessage(message);
57+
parseFields(message);
58+
parseDate(fields.get("date"), fields.get("time"));
59+
setHost(fields.get("devname"));
60+
}
61+
}
62+
63+
private void parsePriority(String priorityString) {
64+
try {
65+
final int priority = Integer.parseInt(priorityString);
66+
setFacility(priority / 8);
67+
setLevel(priority % 8);
68+
} catch (NumberFormatException e) {
69+
throw new IllegalArgumentException("Couldn't parse message priority", e);
70+
}
71+
}
72+
73+
private void parseFields(String event) {
74+
final Map<String, String> fields = new HashMap<>();
75+
final Matcher matcher = KV_PATTERN.matcher(event);
76+
while (matcher.find()) {
77+
fields.put(matcher.group(1), matcher.group(2));
78+
}
79+
final Matcher quotedMatcher = QUOTED_KV_PATTERN.matcher(event);
80+
while (quotedMatcher.find()) {
81+
fields.put(quotedMatcher.group(1), quotedMatcher.group(2));
82+
}
83+
setFields(fields);
84+
}
85+
86+
private void parseDate(String date, String time) {
87+
if (date != null && time != null) {
88+
final ZonedDateTime dateTime = ZonedDateTime.of(
89+
LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneOffset.UTC)),
90+
LocalTime.parse(time, DateTimeFormatter.ISO_LOCAL_TIME.withZone(ZoneOffset.UTC)),
91+
ZoneOffset.UTC);
92+
setDate(Date.from(dateTime.toInstant()));
93+
94+
} else {
95+
setDate(new Date());
96+
}
97+
}
98+
99+
@Override
100+
public byte[] getRaw() {
101+
return rawEvent.getBytes(charSet);
102+
}
103+
104+
@Override
105+
public int getFacility() {
106+
return facility;
107+
}
108+
109+
@Override
110+
public void setFacility(int facility) {
111+
this.facility = requireNonNull(facility, "facility");
112+
}
113+
114+
@Override
115+
public Date getDate() {
116+
return date;
117+
}
118+
119+
@Override
120+
public void setDate(Date date) {
121+
this.date = requireNonNull(date, "date");
122+
}
123+
124+
@Override
125+
public int getLevel() {
126+
return level;
127+
}
128+
129+
@Override
130+
public void setLevel(int level) {
131+
this.level = requireNonNull(level, "level");
132+
}
133+
134+
@Override
135+
public String getHost() {
136+
return host;
137+
}
138+
139+
@Override
140+
public void setHost(String host) {
141+
this.host = host;
142+
}
143+
144+
@Override
145+
public boolean isHostStrippedFromMessage() {
146+
return false;
147+
}
148+
149+
@Override
150+
public String getMessage() {
151+
return message;
152+
}
153+
154+
@Override
155+
public void setMessage(String message) {
156+
this.message = requireNonNull(message, "message");
157+
}
158+
159+
@Override
160+
public String getCharSet() {
161+
return charSet.name();
162+
}
163+
164+
@Override
165+
public void setCharSet(String charSet) {
166+
this.charSet = Charset.forName(charSet);
167+
}
168+
169+
public Map<String, String> getFields() {
170+
return Collections.unmodifiableMap(fields);
171+
}
172+
173+
public void setFields(Map<String, String> fields) {
174+
this.fields = requireNonNull(fields, "fields");
175+
}
176+
}

0 commit comments

Comments
 (0)