Skip to content

Commit 75f8a84

Browse files
authored
True transparent (#38)
* Read timestamp and facility in transparent * Use facility_num if available * Added test * Update run script
1 parent 1560a84 commit 75f8a84

File tree

7 files changed

+421
-118
lines changed

7 files changed

+421
-118
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,21 @@ Example:
6868

6969
### trasparent
7070

71-
A variation of plain sender without facility and source (they are in original message).
71+
A variation of plain sender which tries to keep facility and source from fields, resulting in having a passthrough effect with Graylog Syslog input.
72+
If configured, can omit header if your message already contains header.
73+
7274
Example:
7375

7476
```
7577
<14>Feb 11 17:32:06 graylog01 sshd[26524]: Failed password for admin7 from 10.128.230.28 port 58363 ssh2
7678
```
7779

80+
To test, configure Syslog input and send to it using netcat:
81+
82+
```
83+
echo "<86>_sourcehost_ messagetext86" | nc -v -w 0 localhost 1514
84+
```
85+
7886
### snare
7987

8088
Re-build a snare log format of windows event in stream.
@@ -148,3 +156,5 @@ If existing fields does not contain such keys, following fields will be added to
148156
- https://www.graylog.org/resources/gelf-2/
149157
- http://docs.graylog.org/en/1.0/pages/plugins.html
150158
- https://community.saas.hpe.com/t5/ArcSight-Connectors/ArcSight-Common-Event-Format-CEF-Guide/ta-p/1589306
159+
- https://success.trendmicro.com/solution/TP000086250-What-are-Syslog-Facilities-and-Levels
160+

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<groupId>com.wizecore.graylog2</groupId>
1212
<artifactId>graylog-output-syslog</artifactId>
13-
<version>3.3.0</version>
13+
<version>3.3.1</version>
1414
<packaging>jar</packaging>
1515

1616
<name>graylog-output-syslog</name>

run-graylog

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@ mkdir -p $TT
66
#sudo umount $TT
77
#sudo mount -o bind,noexec $TT $TT
88
#export JAVA_OPTS="-Djava.io.tmpdir=$TT"
9-
rm -Rf $GL/data
9+
#rm -Rf $GL/data
1010
mkdir -p $GL/data
1111
mvn package -DskipTests
12-
cp target/graylog-output-syslog-2.5.1.jar $GL/plugin
12+
cp target/graylog-output-syslog-3.3.1.jar $GL/plugin
1313
export GRAYLOG_CONF=$GL/graylog.conf
14-
docker rm -f elastic
15-
docker run --name elastic -p 9200:9200 -d elasticsearch:5
16-
docker rm -f mongo
17-
docker run --name mongo -p 27017:27017 -d mongo:3.6
18-
docker start elastic
19-
docker start mongo
14+
#docker rm -f elastic
15+
#docker run --name elastic -p 9200:9200 -d elasticsearch:5
16+
#docker rm -f mongo
17+
#docker run --name mongo -p 27017:27017 -d mongo:3.6
18+
#docker start elastic
19+
#docker start mongo
2020
sleep 5
2121
$GL/bin/graylogctl run
2222

src/main/java/com/wizecore/graylog2/plugin/SyslogOutput.java

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
11
package com.wizecore.graylog2.plugin;
22

33

4-
import java.util.List;
5-
import java.util.Map;
6-
import java.util.HashMap;
7-
import java.util.logging.Logger;
8-
9-
import javax.inject.Inject;
10-
4+
import com.google.common.collect.ImmutableMap;
5+
import com.google.inject.assistedinject.Assisted;
116
import org.graylog2.plugin.Message;
127
import org.graylog2.plugin.configuration.Configuration;
138
import org.graylog2.plugin.configuration.ConfigurationRequest;
9+
import org.graylog2.plugin.configuration.fields.BooleanField;
1410
import org.graylog2.plugin.configuration.fields.ConfigurationField;
1511
import org.graylog2.plugin.configuration.fields.DropdownField;
1612
import org.graylog2.plugin.configuration.fields.TextField;
17-
import org.graylog2.plugin.configuration.fields.BooleanField;
1813
import org.graylog2.plugin.outputs.MessageOutput;
1914
import org.graylog2.plugin.streams.Stream;
2015
import org.graylog2.syslog4j.Syslog;
2116
import org.graylog2.syslog4j.SyslogConfigIF;
2217
import org.graylog2.syslog4j.SyslogIF;
18+
import org.graylog2.syslog4j.impl.message.processor.SyslogMessageProcessor;
2319
import org.graylog2.syslog4j.impl.net.tcp.TCPNetSyslogConfig;
2420
import org.graylog2.syslog4j.impl.net.tcp.ssl.SSLTCPNetSyslogConfig;
2521
import org.graylog2.syslog4j.impl.net.udp.UDPNetSyslogConfig;
26-
import org.graylog2.syslog4j.server.impl.net.tcp.ssl.SSLTCPNetSyslogServerConfig;
2722

28-
import com.google.common.collect.ImmutableMap;
29-
import com.google.inject.assistedinject.Assisted;
23+
import javax.inject.Inject;
24+
import java.util.Date;
25+
import java.util.HashMap;
26+
import java.util.List;
27+
import java.util.Map;
28+
import java.util.logging.Logger;
3029

3130

3231
/**
@@ -54,7 +53,7 @@ public static MessageSender createSender(String fmt, Configuration conf) {
5453
return new PlainSender();
5554
} else
5655
if (fmt == null || fmt.equalsIgnoreCase("transparent")) {
57-
return new TrasparentSyslogSender(conf);
56+
return new TransparentSyslogSender(conf);
5857
} else
5958
if (fmt == null || fmt.equalsIgnoreCase("snare")) {
6059
return new SnareWindowsSender();
@@ -144,11 +143,26 @@ public SyslogOutput(@Assisted Stream stream, @Assisted Configuration conf) {
144143
syslog = Syslog.exists(hash) ? Syslog.getInstance(hash) : Syslog.createInstance(hash, config);
145144

146145
sender = createSender(format, conf);
146+
147+
if (sender instanceof TransparentSyslogSender) {
148+
// Always send empty header, which we will construct ourselves
149+
syslog.setMessageProcessor(new SyslogMessageProcessor() {
150+
@Override
151+
public String createSyslogHeader(int facility, int level, String localName, boolean sendLocalName, Date datetime) {
152+
return "";
153+
}
154+
155+
@Override
156+
public String createSyslogHeader(int facility, int level, String localName, boolean sendLocalTimestamp, boolean sendLocalName) {
157+
return "";
158+
}
159+
});
160+
}
161+
147162
if (sender instanceof StructuredSender) {
148163
// Always send via structured data
149164
syslog.getConfig().setUseStructuredData(true);
150-
} else
151-
if (sender instanceof PlainSender || sender instanceof CEFSender) {
165+
} else if (sender instanceof PlainSender || sender instanceof CEFSender) {
152166
// Will write this fields manually
153167
syslog.getConfig().setSendLocalName(false);
154168
syslog.getConfig().setSendLocalTimestamp(false);
@@ -255,30 +269,30 @@ public ConfigurationRequest getRequestedConfiguration() {
255269
configurationRequest.addField(new TextField("host", "Syslog host", "localhost", "Remote host to send syslog messages to.", ConfigurationField.Optional.NOT_OPTIONAL));
256270
configurationRequest.addField(new TextField("port", "Syslog port", "514", "Syslog port on the remote host. Default is 514.", ConfigurationField.Optional.NOT_OPTIONAL));
257271

258-
HashMap<String, String> types = new HashMap<String,String>();
259-
types.put("plain", "plain");
260-
types.put("structured", "structured");
261-
types.put("cef", "cef");
262-
types.put("full", "full");
263-
types.put("transparent", "transparent");
264-
types.put("snare", "snare");
272+
HashMap<String, String> types = new HashMap<String, String>();
273+
types.put("plain", "plain");
274+
types.put("structured", "structured");
275+
types.put("cef", "cef");
276+
types.put("full", "full");
277+
types.put("transparent", "transparent");
278+
types.put("snare", "snare");
265279

266280
final Map<String, String> formats = ImmutableMap.copyOf(types);
267281
configurationRequest.addField(new DropdownField(
268282
"format", "Message format", "plain", formats,
269283
"Message format. For detailed explanation, see https://github.com/wizecore/graylog2-output-syslog",
270284
ConfigurationField.Optional.NOT_OPTIONAL)
271285
);
272-
configurationRequest.addField(new BooleanField("transparentFormatRemoveHeader", "Remove header (only for transparent)", false, "Do not insert timestamp header when it forwards the message content."));
286+
configurationRequest.addField(new BooleanField("transparentFormatRemoveHeader", "Remove header (only for transparent)", false, "Do not insert header when it forwards the message content."));
273287

274288
configurationRequest.addField(new TextField("maxlen", "Maximum message length", "", "Maximum message (body) length. Longer messages will be truncated. If not specified defaults to 16384 bytes.", ConfigurationField.Optional.OPTIONAL));
275-
289+
276290
configurationRequest.addField(new TextField("keystore", "Key store", "", "Path to Java keystore (required for SSL over TCP). Must contain private key and cert for this client.", ConfigurationField.Optional.OPTIONAL));
277291
configurationRequest.addField(new TextField("keystorePassword", "Key store password", "", "", ConfigurationField.Optional.OPTIONAL));
278-
292+
279293
configurationRequest.addField(new TextField("truststore", "Trust store", "", "Path to Java keystore (required for SSL over TCP). Optional (if not set, equals to key store). Must contain peers we trust connecting to.", ConfigurationField.Optional.OPTIONAL));
280294
configurationRequest.addField(new TextField("truststorePassword", "Trust store password", "", "", ConfigurationField.Optional.OPTIONAL));
281-
295+
282296
return configurationRequest;
283297
}
284298
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package com.wizecore.graylog2.plugin;
2+
3+
import org.graylog2.plugin.Message;
4+
import org.graylog2.plugin.configuration.Configuration;
5+
import org.graylog2.syslog4j.SyslogConstants;
6+
import org.graylog2.syslog4j.SyslogIF;
7+
import org.joda.time.DateTime;
8+
9+
import java.text.SimpleDateFormat;
10+
import java.util.Date;
11+
import java.util.Locale;
12+
import java.util.logging.Logger;
13+
14+
/**
15+
* Retain as much as possible original message, facility and level, giving maximum compatibility to the Graylog internal syslog input,
16+
* so that messages recevied will be sent unmodified to the remote syslog server.
17+
*/
18+
public class TransparentSyslogSender implements MessageSender {
19+
private Logger log = Logger.getLogger(TransparentSyslogSender.class.getName());
20+
private boolean removeHeader = false;
21+
22+
public static final String SYSLOG_DATEFORMAT = "MMM dd HH:mm:ss";
23+
24+
public TransparentSyslogSender(Configuration conf) {
25+
removeHeader = conf.getBoolean("transparentFormatRemoveHeader");
26+
}
27+
28+
29+
/**
30+
* From syslog4j
31+
*
32+
* @param dt
33+
* @return
34+
*/
35+
public static void appendSyslogTimestamp(Message msg, StringBuilder buffer) {
36+
SimpleDateFormat dateFormat = new SimpleDateFormat(SYSLOG_DATEFORMAT, Locale.ENGLISH);
37+
38+
Date dt = null;
39+
Object ts = msg.getField("timestamp");
40+
if (ts instanceof Number) {
41+
dt = new Date(((Number) ts).longValue());
42+
} else if (ts instanceof DateTime) {
43+
DateTime jt = ((DateTime) ts);
44+
dt = jt.toDate();
45+
} else {
46+
System.out.println("Missing timestamp: " + msg.getId() + ", " + ts);
47+
}
48+
49+
if (dt == null) {
50+
dt = new Date();
51+
}
52+
53+
String datePrefix = dateFormat.format(dt);
54+
55+
int pos = buffer.length() + 4;
56+
buffer.append(datePrefix);
57+
58+
// RFC 3164 requires leading space for days 1-9
59+
if (buffer.charAt(pos) == '0') {
60+
buffer.setCharAt(pos, ' ');
61+
}
62+
}
63+
64+
protected int findFacility(Message msg) {
65+
int facility = SyslogConstants.FACILITY_USER;
66+
// Use field from
67+
Object fn = msg.getField("facility_num");
68+
if (fn instanceof Number) {
69+
return ((Number) fn).intValue();
70+
}
71+
72+
fn = msg.getField("facility");
73+
if (fn instanceof Number) {
74+
facility = ((Number) fn).intValue();
75+
} else if (fn instanceof String) {
76+
String fs = ((String) fn);
77+
// NB: Keep in sync with org.graylog2.plugin.Tools#syslogFacilityToReadable
78+
switch (fs) {
79+
case "kernel":
80+
facility = 0;
81+
break;
82+
case "user-level":
83+
facility = 1;
84+
break;
85+
case "mail":
86+
facility = 2;
87+
break;
88+
case "system daemon":
89+
facility = 3;
90+
break;
91+
case "security/authorization":
92+
// SyslogConstants.FACILITY_AUTH
93+
facility = 4;
94+
// SyslogConstants.FACILITY_AUTHPRIV
95+
// facility = 10;
96+
break;
97+
case "syslogd":
98+
facility = 5;
99+
break;
100+
case "line printer":
101+
facility = 6;
102+
break;
103+
case "network news":
104+
facility = 7;
105+
break;
106+
case "UUCP":
107+
facility = 8;
108+
break;
109+
case "clock":
110+
// SyslogConstants.FACILITY_CLOCK
111+
facility = 9;
112+
// SyslogConstants.FACILITY_CLOCK2
113+
// facility = 15;
114+
break;
115+
case "FTP":
116+
facility = 11;
117+
break;
118+
case "NTP":
119+
facility = 12;
120+
break;
121+
case "log audit":
122+
facility = 13;
123+
break;
124+
case "log alert":
125+
facility = 14;
126+
break;
127+
case "local0":
128+
facility = 16;
129+
break;
130+
case "local1":
131+
facility = 17;
132+
break;
133+
case "local2":
134+
facility = 18;
135+
break;
136+
case "local3":
137+
facility = 19;
138+
break;
139+
case "local4":
140+
facility = 20;
141+
break;
142+
case "local5":
143+
facility = 21;
144+
break;
145+
case "local6":
146+
facility = 22;
147+
break;
148+
case "local7":
149+
facility = 23;
150+
break;
151+
case "Unknown":
152+
default:
153+
System.err.println("Unknown literal facility: " + msg.getId() + ", " + fn);
154+
facility = SyslogConstants.FACILITY_USER;
155+
}
156+
}
157+
return facility;
158+
}
159+
160+
protected void appendPriority(Message msg, int level, StringBuilder out) {
161+
int facility = findFacility(msg);
162+
facility = facility << 3;
163+
int priority = facility + level;
164+
out.append("<");
165+
out.append(priority);
166+
out.append(">");
167+
}
168+
169+
@Override
170+
public void send(SyslogIF syslog, int level, Message msg) {
171+
StringBuilder out = new StringBuilder();
172+
if (removeHeader != true) {
173+
appendHeader(msg, level, out);
174+
}
175+
176+
// Remove source (hostname) from source message
177+
String str = msg.getMessage();
178+
String source = msg.getSource();
179+
if (source != null && str.startsWith(source) && str.substring(source.length(), source.length() + 1).equals(" ")) {
180+
str = str.substring(source.length() + 1);
181+
}
182+
out.append(str);
183+
syslog.log(level, out.toString());
184+
}
185+
186+
protected void appendLocalName(Message msg, StringBuilder out) {
187+
// Write source (host)
188+
String source = msg.getSource();
189+
if (source != null) {
190+
out.append(source);
191+
} else {
192+
out.append("-");
193+
}
194+
}
195+
196+
public void appendHeader(Message msg, int level, StringBuilder out) {
197+
appendPriority(msg, level, out);
198+
appendSyslogTimestamp(msg, out);
199+
out.append(" ");
200+
appendLocalName(msg, out);
201+
out.append(" ");
202+
}
203+
}

0 commit comments

Comments
 (0)