/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.opensoc.parsing; import java.io.IOException; import java.util.Map; import org.apache.commons.configuration.Configuration; import org.json.simple.JSONObject; import backtype.storm.task.OutputCollector; import backtype.storm.task.TopologyContext; import backtype.storm.topology.OutputFieldsDeclarer; import backtype.storm.tuple.Fields; import backtype.storm.tuple.Tuple; import backtype.storm.tuple.Values; import com.opensoc.helpers.topology.ErrorGenerator; import com.opensoc.json.serialization.JSONEncoderHelper; import com.opensoc.metrics.MetricReporter; import com.opensoc.parser.interfaces.MessageFilter; import com.opensoc.parser.interfaces.MessageParser; /** * Uses an adapter to parse a telemetry message from its native format into a * standard JSON. For a list of available adapter please check * com.opensoc.parser.parsers. The input is a raw byte array and the output is a * JSONObject * <p> * The parsing conventions are as follows: * <p> * <ul> * * <li>ip_src_addr = source ip of a message * <li>ip_dst_addr = destination ip of a message * <li>ip_src_port = source port of a message * <li>ip_dst_port = destination port of a message * <li>protocol = protocol of a message * <ul> * <p> * <p> * If a message does not contain at least one of these variables it will be * failed **/ @SuppressWarnings("rawtypes") public class TelemetryParserBolt extends AbstractParserBolt { private static final long serialVersionUID = -2647123143398352020L; private JSONObject metricConfiguration; /** * @param parser * The parser class for parsing the incoming raw message byte * stream * @return Instance of this class */ public TelemetryParserBolt withMessageParser(MessageParser parser) { _parser = parser; return this; } /** * @param OutputFieldName * Field name of the output tuple * @return Instance of this class */ public TelemetryParserBolt withOutputFieldName(String OutputFieldName) { this.OutputFieldName = OutputFieldName; return this; } /** * @param filter * A class for filtering/dropping incomming telemetry messages * @return Instance of this class */ public TelemetryParserBolt withMessageFilter(MessageFilter filter) { this._filter = filter; return this; } /** * @param config * A class for generating custom metrics into graphite * @return Instance of this class */ public TelemetryParserBolt withMetricConfig(Configuration config) { this.metricConfiguration = JSONEncoderHelper.getJSON(config .subset("com.opensoc.metrics")); return this; } @Override void doPrepare(Map conf, TopologyContext topologyContext, OutputCollector collector) throws IOException { LOG.info("[OpenSOC] Preparing TelemetryParser Bolt..."); if (metricConfiguration != null) { _reporter = new MetricReporter(); _reporter .initialize(metricConfiguration, TelemetryParserBolt.class); LOG.info("[OpenSOC] Metric reporter is initialized"); } else { LOG.info("[OpenSOC] Metric reporter is not initialized"); } this.registerCounters(); if(_parser != null) _parser.init(); } @SuppressWarnings("unchecked") public void execute(Tuple tuple) { LOG.trace("[OpenSOC] Starting to process a new incoming tuple"); byte[] original_message = null; try { original_message = tuple.getBinary(0); LOG.trace("[OpenSOC] Starting the parsing process"); if (original_message == null || original_message.length == 0) { LOG.error("Incomming tuple is null"); throw new Exception("Invalid message length"); } LOG.trace("[OpenSOC] Attempting to transofrm binary message to JSON"); JSONObject transformed_message = _parser.parse(original_message); LOG.debug("[OpenSOC] Transformed Telemetry message: " + transformed_message); if (transformed_message == null || transformed_message.isEmpty()) throw new Exception("Unable to turn binary message into a JSON"); LOG.trace("[OpenSOC] Checking if the transformed JSON conforms to the right schema"); if (!checkForSchemaCorrectness(transformed_message)) { throw new Exception("Incorrect formatting on message: " + transformed_message); } else { LOG.trace("[OpenSOC] JSON message has the right schema"); boolean filtered = false; if (_filter != null) { if (!_filter.emitTuple(transformed_message)) { filtered = true; } } if (!filtered) { String ip1 = null; if (transformed_message.containsKey("ip_src_addr")) ip1 = transformed_message.get("ip_src_addr").toString(); String ip2 = null; if (transformed_message.containsKey("ip_dst_addr")) ip2 = transformed_message.get("ip_dst_addr").toString(); String key = generateTopologyKey(ip1, ip2); JSONObject new_message = new JSONObject(); new_message.put("message", transformed_message); _collector.emit("message", new Values(key, new_message)); } _collector.ack(tuple); if (metricConfiguration != null) ackCounter.inc(); } } catch (Exception e) { e.printStackTrace(); LOG.error("Failed to parse telemetry message :" + original_message); _collector.fail(tuple); if (metricConfiguration != null) failCounter.inc(); JSONObject error = ErrorGenerator.generateErrorMessage( "Parsing problem: " + new String(original_message), e); _collector.emit("error", new Values(error)); } } public void declareOutputFields(OutputFieldsDeclarer declearer) { declearer.declareStream("message", new Fields("key", "message")); declearer.declareStream("error", new Fields("message")); } }