/*
* Copyright (C) 2007-2014 Christian Bockermann <chris@jwall.org>
*
* This file is part of the web-audit library.
*
* web-audit library is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The web-audit library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.jwall.web.audit;
import java.io.File;
import java.io.PrintStream;
import java.io.Serializable;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minidev.json.JSONObject;
import org.jwall.audit.EventProcessor;
import org.jwall.web.audit.io.AuditEventReader;
import org.jwall.web.audit.io.ModSecurity2AuditReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import stream.Data;
import stream.Processor;
import stream.data.DataFactory;
import stream.util.KeyFilter;
/**
* This class implements a simple event processor that sends event-messages in
* GELF format for each incoming event.
*
* @author Christian Bockermann <chris@jwall.org>
*
*/
public class GELFSender implements EventProcessor<AuditEvent>, Processor {
static Logger log = LoggerFactory.getLogger(GELFSender.class);
String prefix = "_rule:";
String key = "event";
String[] keys = null;
String address;
Integer port;
Socket socket;
PrintStream out;
protected void connect() throws Exception {
log.debug("Opening socket connection to {}:{}... ", address, port);
try {
socket = new Socket(address, port);
out = new PrintStream(socket.getOutputStream());
} catch (Exception e) {
socket = null;
throw e;
}
}
@Override
public Data process(Data input) {
Serializable value = input.get(key);
if (value != null && value instanceof AuditEvent) {
AuditEvent evt = (AuditEvent) value;
try {
evt = processEvent(evt, new HashMap<String, Object>());
input.put(key, evt);
} catch (Exception e) {
log.error("Failed to process item: {}", e.getMessage());
if (log.isDebugEnabled()) {
e.printStackTrace();
}
}
}
return input;
}
@Override
public AuditEvent processEvent(AuditEvent evt, Map<String, Object> context)
throws Exception {
final String txId = evt.get(ModSecurity.TX_ID);
final Long timestamp = evt.getTimestamp();
AuditEventMessage[] msgs = evt.getEventMessages();
for (int i = 0; i < msgs.length; i++) {
AuditEventMessage msg = msgs[i];
Data item = DataFactory.create();
item.put("version", "1.0");
item.put("host", evt.get(ModSecurity.REQUEST_HEADERS + ":Host"));
item.put("short_message", msg.getRuleMsg());
item.put("full_message", msg.getRuleMsg());
item.put("timestamp", timestamp.doubleValue() / 1000.0d);
item.put("level", msg.getSeverity());
item.put("facility",
"ModSecurity:" + evt.get(AuditEvent.SENSOR_NAME));
item.put("file", msg.getFile());
item.put("line", msg.getLine());
item.put("_event:txId", txId);
String ruleId = msg.getRuleId();
if (ruleId != null) {
item.put(prefix + "id", msg.getRuleId());
}
List<String> tags = msg.getRuleTags();
if (tags != null && !tags.isEmpty()) {
item.put(prefix + "tags", join(msg.getRuleTags()));
}
log.debug("Emitting item {} to {}", item, address);
emit(item);
}
return null;
}
protected void emit(Data input) {
try {
if (socket == null) {
log.debug("Socket not connected, trying to connect...");
connect();
}
String json;
if (keys != null) {
Set<String> selected = KeyFilter.select(input, keys);
Data item = DataFactory.create();
for (String k : selected) {
item.put(k, input.get(k));
}
log.debug("Sending item {}", item);
json = JSONObject.toJSONString(item);
} else {
json = JSONObject.toJSONString(input);
}
out.println(json);
} catch (Exception e) {
log.error("Faild to send item: {}", e.getMessage());
if (log.isDebugEnabled()) {
e.printStackTrace();
}
}
}
/**
* @see stream.AbstractProcessor#finish()
*/
public void finish() throws Exception {
if (out != null)
out.close();
if (socket != null)
socket.close();
}
public String join(List<String> strs) {
StringBuffer s = new StringBuffer();
if (strs == null || strs.isEmpty()) {
return s.toString();
}
Iterator<String> it = strs.iterator();
while (it.hasNext()) {
s.append(it.next());
if (it.hasNext())
s.append(",");
}
return s.toString();
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public static void main(String[] args) throws Exception {
AuditEventReader reader = new ModSecurity2AuditReader(new File(
"/Users/chris/audit/jwall-audit.log"));
AuditEvent evt = reader.readNext();
GELFSender sender = new GELFSender();
sender.setAddress("127.0.0.1");
sender.setPort(9105);
sender.processEvent(evt, new HashMap<String, Object>());
}
}