Import from old repository
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
This file is part of ${project.name}.
|
||||
Copyright (C) ${project.inceptionYear},${recentYears} ${owner} (${email})
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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/>.
|
||||
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
|
||||
This file is part of Rubanetra.
|
||||
Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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/>.
|
||||
|
||||
-->
|
||||
<licenseSummary xmlns="http://mojo.codehaus.org/">
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The MIT License</name>
|
||||
<url>http://www.slf4j.org/license.html</url>
|
||||
</license>
|
||||
</licenses>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
</license>
|
||||
</licenses>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dnsjava</groupId>
|
||||
<artifactId>dnsjava</artifactId>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The BSD License</name>
|
||||
<url>http://www.dnsjava.org/dnsjava-current/README</url>
|
||||
</license>
|
||||
</licenses>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xpp3</groupId>
|
||||
<artifactId>xpp3_min</artifactId>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Indiana University Extreme! Lab Software License, version 1.1.1</name>
|
||||
<url>http://www.bearcave.com/software/java/xml/xmlpull_license.html</url>
|
||||
</license>
|
||||
</licenses>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
</license>
|
||||
</licenses>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore</artifactId>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
</license>
|
||||
</licenses>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</licenseSummary>
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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/>.
|
||||
*/
|
||||
grammar RubanetraSystemConfiguration;
|
||||
|
||||
/**
|
||||
* This file defines the EBNF grammar of the default system configuration
|
||||
* using the ANTLR v4 syntax (see http://www.antlr.org/wiki/display/ANTLR4/ANTLR+4+Documentation).
|
||||
* The general settings '*_configuration_file' may be used
|
||||
* to indicate the location of the corresponding configuration files, however
|
||||
* the main configuration file path containing the 'general' section
|
||||
* must be known by the system a priori at a fixed location (usually the classpath) or it has to be passed as
|
||||
* command line parameter during runtime.
|
||||
* The recommended setup is to use two configuration files, i.e.
|
||||
* one file containing all static configuration blocks ('general', 'protocols')
|
||||
* and another file containing the dynamic runtime configuration ('input', 'output').
|
||||
* The system configuration itself may be split into four different files according
|
||||
* to the main settings categories 'general', 'protocols', 'input/output' (a coarser split into a single, two or three
|
||||
* file(s) is possible as well).
|
||||
*
|
||||
* The 'system' node serves as grammar entry point and consists of a mandatory 'general'
|
||||
* configuration section, followed by the remaining configurations optionally within the
|
||||
* same file. However, this does not implicate that the protocol/library/runtime configurations
|
||||
* are optional in general.
|
||||
**/
|
||||
system : (generalConfig|inputConfig|outputConfig|protocolConfig)* ;
|
||||
|
||||
/**
|
||||
* Although the general configuration contains a predefined number of settings,
|
||||
* future extensions may lead to a different set of settings, therefore no semantic
|
||||
* restrictions will be laid upon the parser at the top level nodes.
|
||||
**/
|
||||
generalConfig : 'general' '{' (generalSetting)* '}' ';' ;
|
||||
protocolConfig : 'protocols' '{' (protocolConfigurationFileSetting | (protocolSetting)*) '}' ';' ;
|
||||
inputConfig : 'input' '{' (inputConfigurationFileSetting | (inputSetting)*) '}' ';' ;
|
||||
outputConfig : 'output' '{' (outputConfigurationFileSetting | (outputSetting)*) '}' ';' ;
|
||||
|
||||
/**
|
||||
* ##################################
|
||||
* # General Setting Specification #
|
||||
* ##################################
|
||||
**/
|
||||
generalSetting : ( 'drools_base_model_name' '=' droolsBaseModelName // optional, the name of the knowledge base to use (defined in 'kmodule.xml')
|
||||
| 'drools_session_model_name' '=' droolsSessionModelName // optional, the name of the session to use (defined in 'kmodule.xml')
|
||||
| 'drools_configuration_directory' '=' droolsConfigurationFile // required, path of a separate file containing the Drools knowledge base configuration ('kmodule.xml')
|
||||
) ';' ;
|
||||
droolsBaseModelName : STRING ;
|
||||
droolsSessionModelName : STRING ;
|
||||
droolsConfigurationFile : filePath ;
|
||||
// End of General Setting Specification
|
||||
|
||||
/**
|
||||
* ###################################
|
||||
* # Protocol Setting Specification #
|
||||
* ###################################
|
||||
**/
|
||||
protocolConfigurationFileSetting : 'protocol_configuration_file' '=' filePath ;
|
||||
|
||||
protocolSetting : (protocolHeader (portSpecification|protocolBinding|transportLayerMappingSetting)*) ;
|
||||
protocolHeader : '[' protocolId ']' ':' ; // every protocol parser configuration section has an unique identifier
|
||||
|
||||
portSpecification : 'port' '=' ( ALL // matches all network ports [0;2^16-1]
|
||||
| NONE // matches no ports (i.e. another way to disable a protocol)
|
||||
| multiplePorts // matches either one or several single ports or port ranges
|
||||
) ';' ;
|
||||
multiplePorts : portRange (',' portRange)* ;
|
||||
portRange : singlePort ('-' singlePort)? ;
|
||||
protocolBinding : 'protocol_binding' '=' protocolId BIND_OP protocolId ';';
|
||||
transportLayerMappingSetting : 'transport_layer_mapping_strategy' '=' transportLayerMappingStrategy ';' ;
|
||||
transportLayerMappingStrategy : (DESTINATION_PORT) ;
|
||||
// End of Protocol Setting Specification
|
||||
|
||||
/**
|
||||
* ###########################################
|
||||
* # Dynamic Runtime Setting Specification #
|
||||
* ###########################################
|
||||
* The following settings will be used to adjust the concrete runtime behaviour of the system,
|
||||
* i.e. a set of one or multiple PCAP input files, a set of predefined protocols (see Protocol Setting Specification),
|
||||
* a set of rules to enable.
|
||||
**/
|
||||
inputConfigurationFileSetting : 'input_configuration_file' '=' filePath ';' ; // optional, path of a separate file containing the I/O configuration
|
||||
inputSetting : ( 'input_file' '=' inputSpecification // required, list of network capture input files
|
||||
| 'input_format' '=' inputFormat // required, currently only PCAP (all format versions supported by the utilized libpcap library)
|
||||
| 'bpf_filter' '=' bpfFilterString // optional, String representing a Berkeley Packet Filter (BPF) expression - a syntax check will not be performed
|
||||
| 'bpf_netmask' '=' bpfNetmask // optional, integer representing a Berkeley Packet Filter (BPF) netmask
|
||||
| 'bpf_optimize' '=' bpfOptimize // optional, boolean representing a Berkeley Packet Filter (BPF) optimization flag
|
||||
| 'sort_by_first_timestamp' '=' sortByFirstTimestamp // optional, boolean flag indicating whether or not to sort according to the first timestamp of the PCAP entry
|
||||
) ';' ;
|
||||
|
||||
outputConfigurationFileSetting : 'output_configuration_file' '=' filePath ';'; // optional, path of a separate file containing the I/O configuration
|
||||
outputSetting : ( 'output_file' '=' outputSpecification // required, content output stream
|
||||
| 'output_format' '=' outputFormat // plaso parser or general csv format
|
||||
) ';' ;
|
||||
|
||||
inputSpecification : filePath (',' filePath)* ;
|
||||
inputFormat : (PCAP) ;
|
||||
bpfFilterString : STRING ;
|
||||
bpfNetmask : INT ;
|
||||
bpfOptimize : (TRUE|FALSE) ;
|
||||
sortByFirstTimestamp : (TRUE|FALSE) ;
|
||||
outputSpecification : (STDOUT|filePath) ;
|
||||
outputFormat : (PLASO|CSV|NOP) ;
|
||||
// End of Runtime Setting Specification
|
||||
|
||||
regexFlag : // see docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#UNIX_LINES
|
||||
CASE_INSENSITIVE | MULTILINE | DOTALL | UNICODE_CASE | CANON_EQ
|
||||
| UNIX_LINES | LITERAL | UNICODE_CHARACTER_CLASS | COMMENTS | NONE ;
|
||||
ipv6 : // loosely based on RFC 5954, see http://tools.ietf.org/html/rfc5954, semantic check (int range) will be performed after parsing
|
||||
( INT ':' INT ':' INT ':' INT ':' INT ':' INT ':' optIPv6Trailer
|
||||
| '::' INT ':' INT ':' INT ':' INT ':' INT ':' optIPv6Trailer
|
||||
| INT? '::' INT ':' INT ':' INT ':' INT ':' optIPv6Trailer
|
||||
| ((INT ':' )? INT)? '::' INT ':' INT ':' INT ':' optIPv6Trailer
|
||||
| ((INT ':' )? (INT ':' )? INT)? '::' INT ':' INT ':' optIPv6Trailer
|
||||
| ((INT ':' )? (INT ':' )? (INT ':' )? INT)? '::' INT ':' optIPv6Trailer
|
||||
| ((INT ':' )? (INT ':' )? (INT ':' )? (INT ':' )? INT)? '::' optIPv6Trailer
|
||||
| ((INT ':' )? (INT ':' )? (INT ':' )? (INT ':' )? (INT ':' )? INT)? '::' INT
|
||||
| ((INT ':' )? (INT ':' )? (INT ':' )? (INT ':' )? (INT ':' )? (INT ':' )? INT)? '::'
|
||||
)
|
||||
;
|
||||
|
||||
optIPv6Trailer : ( INT ':' INT) | ipv4 ;
|
||||
ipv4 : INT '.' INT '.' INT '.' INT ; // Match an IPv4 address, e.g. 127.0.0.1
|
||||
|
||||
protocolId : ID ;
|
||||
singlePort : INT ;
|
||||
filePath : STRING ;
|
||||
|
||||
DEBUG : [Dd][Ee][Bb][Uu][Gg] ;
|
||||
WARNING : [Ww][Aa][Rr][Nn][Ii][Nn][Gg] ;
|
||||
INFO : [Ii][Nn][Ff][Oo] ;
|
||||
DISABLED : [Dd][Ii][Ss][Aa][Bb][Ll][Ee][Dd] ;
|
||||
PLASO : [Pp][Ll][Aa][Ss][Oo] ;
|
||||
PCAP : [Pp][Cc][Aa][Pp] ;
|
||||
DEFAULT : [Dd][Ee][Ff][Aa][Uu][Ll][Tt] ;
|
||||
DESTINATION_PORT: [Dd][Ee][Ss][Tt][Ii][Nn][Aa][Tt][Ii][Oo][Nn]'_'[Pp][Oo][Rr][Tt] ;
|
||||
CSV : [Cc][Ss][Vv] ;
|
||||
CUSTOM : [Cc][Uu][Ss][Tt][Oo][Mm] ;
|
||||
TRUE : ([Tt][Rr][Uu][Ee]) ;
|
||||
FALSE : ([Ff][Aa][Ll][Ss][Ee]) ;
|
||||
BIND_OP : ([Tt][Oo]) | '->' ;
|
||||
ALL : ([Aa][Ll][Ll]) | ([Aa][Nn][Yy]) ;
|
||||
NONE : [Nn][Oo][Nn][Ee] ;
|
||||
NOP : [Nn][Oo][Pp] ;
|
||||
STDOUT : ([Ss][Tt][Dd][Oo][Uu][Tt]) ;
|
||||
|
||||
/**
|
||||
* Possible Java regular expression flags
|
||||
* See docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#UNIX_LINES
|
||||
**/
|
||||
CASE_INSENSITIVE : [Cc][Aa][Ss][Ee][_][Ii][Nn][Ss][Ee][Nn][Ss][Ii][Tt][Ii][Vv][Ee] ;
|
||||
MULTILINE : [Mm][Uu][Ll][Tt][Ii][Ll][Ii][Nn][Ee];
|
||||
DOTALL : [Dd][Oo][Tt][Aa][Ll][Ll] ;
|
||||
UNICODE_CASE : [Uu][Nn][Ii][Cc][Oo][Dd][Ee][_][Cc][Aa][Ss][Ee] ;
|
||||
CANON_EQ : [Cc][Aa][Nn][Oo][Nn][_][Ee][Qq] ;
|
||||
UNIX_LINES : [Uu][Nn][Ii][Xx][_][Ll][Ii][Nn][Ee][Ss] ;
|
||||
LITERAL : [Ll][Ii][Tt][Ee][Rr][Aa][Ll] ;
|
||||
UNICODE_CHARACTER_CLASS : [Uu][Nn][Ii][Cc][Oo][Dd][Ee][_][Cc][Hh][Aa][Rr][Aa][Cc][Tt][Ee][Rr][_][Cc][Ll][Aa][Ss][Ss] ;
|
||||
COMMENTS : [Cc][Oo][Mm][Mm][Ee][Nn][Tt][Ss] ;
|
||||
|
||||
|
||||
fragment DIGIT : [0-9] ;
|
||||
ID : ([a-zA-Z]+ DIGIT*)+ ; // match lower-case and upper-case identifiers
|
||||
INT : DIGIT+ ; // match natural, positive numbers including 0
|
||||
|
||||
|
||||
STRING : '"' ('\\"'|.)*? '"' ; // match any characters between double quotes, including escaped '"'
|
||||
LINE_COMMENT : ('//'|'#') .*? '\r'? '\n' -> skip ; // match line comments
|
||||
COMMENT : '/*' .*? '*/' -> skip ; // match "/*" multiline comment "*/"
|
||||
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
|
||||
@@ -0,0 +1,96 @@
|
||||
<!--
|
||||
|
||||
This file is part of Rubanetra.
|
||||
Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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/>.
|
||||
|
||||
-->
|
||||
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||
<id>distribution</id>
|
||||
<baseDirectory>${project.build.finalName}-distribution</baseDirectory>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<includes>
|
||||
<include>README*</include>
|
||||
<include>LICENSE*</include>
|
||||
<include>NOTICE*</include>
|
||||
</includes>
|
||||
<filtered>true</filtered>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${archive.output.directory}</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/lib</directory>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/${jnetpcap.native.lib.directory}/native</directory>
|
||||
<outputDirectory>lib/${jnetpcap.native.lib.directory}</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/generated-sources/license</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/generated-resources/licenses</directory>
|
||||
<outputDirectory>lib/licenses</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/generated-resources</directory>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
<includes>
|
||||
<include>licenses.xml</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
|
||||
<fileSet>
|
||||
<directory>src/main/resources</directory>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
<includes>
|
||||
<include>DefaultKnowledgeBase/**</include>
|
||||
<include>META-INF/kmodule.xml</include>
|
||||
<include>*.conf</include>
|
||||
<include>*.properties</include>
|
||||
<include>*.xml</include>
|
||||
</includes>
|
||||
<filtered>true</filtered>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<files>
|
||||
<file>
|
||||
<source>pom.xml</source>
|
||||
<outputDirectory>conf/META-INF/maven/${project.groupId}/${project.artifactId}</outputDirectory>
|
||||
<filtered>true</filtered>
|
||||
</file>
|
||||
<file>
|
||||
<source>${project.build.directory}/maven-archiver/pom.properties</source>
|
||||
<outputDirectory>conf/META-INF/maven/${project.groupId}/${project.artifactId}</outputDirectory>
|
||||
<filtered>true</filtered>
|
||||
</file>
|
||||
</files>
|
||||
</assembly>
|
||||
@@ -0,0 +1,68 @@
|
||||
<!--
|
||||
|
||||
This file is part of Rubanetra.
|
||||
Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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/>.
|
||||
|
||||
-->
|
||||
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||
<id>package</id>
|
||||
<baseDirectory>${project.build.finalName}-package</baseDirectory>
|
||||
<formats>
|
||||
<!--<format>tar.gz</format>-->
|
||||
<!--<format>tar.bz2</format>-->
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}</directory>
|
||||
<includes>
|
||||
<include>README*</include>
|
||||
<include>NOTICE*</include>
|
||||
</includes>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<filtered>true</filtered>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}</directory>
|
||||
<includes>
|
||||
<include>pom.xml</include>
|
||||
</includes>
|
||||
<filtered>false</filtered>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/src/main</directory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/src/license</directory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/generated-sources/license</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}/src</directory>
|
||||
<outputDirectory>/src</outputDirectory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<excludes>
|
||||
<exclude>**/*.log</exclude>
|
||||
<exclude>**/${project.build.directory}/**</exclude>
|
||||
<exclude>**/test/**</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -0,0 +1,638 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBaseListenerImpl;
|
||||
import at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder;
|
||||
import at.jku.fim.rubanetra.drools.DroolsKrakenProtocolHandler;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedList;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* This class serves as the projects main entry point, i.e. it contains a main-method and provides
|
||||
* a basic command line interface. However, it may also serve as basic configuration initializer for use by other
|
||||
* classes.
|
||||
* <p>
|
||||
* The main method of this class relies on the fact that it has been executed and loaded from within a runnable
|
||||
* jar archive containing a manifest file consisting of basic project information.
|
||||
* By default, i.e. without providing any command line arguments, the main configuration will be looked up at the
|
||||
* following locations:
|
||||
* <ul>
|
||||
* <li>File named "rubanetra.conf" in the classpath and as a relative path</li>
|
||||
* <li>"./conf/rubanetra.conf" in the classpath and as relative path</li>
|
||||
* <li>Value of environment variable "RUBANETRA_SYSTEM_CONF_FILE" interpreted as file path.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* If the file could not be located successfully an exception will be thrown.
|
||||
* Alternatively, the main configuration file path may be provided as command line argument using
|
||||
* the switch '-c' or '--configuration-file'.
|
||||
* <p>
|
||||
* During the initialization procedure the ANTLR configuration parser will be invoked. Any encountered syntax errors
|
||||
* will be printed to the standard error stream, however, unless any critical errors during the setup process
|
||||
* occurred the application will continue running.
|
||||
* <p>
|
||||
* After completing the initialization procedure the control over the program flow will be returned
|
||||
* to the caller in the main method, who in turn is able to retrieve the parsed and validated @{RubanetraSystemConfiguration}.
|
||||
* By default, invoking the start-method
|
||||
* of this class will initialize a default @{DroolsKrakenProtocolHandler} which effectively passes all PCAP-entries
|
||||
* to the Kraken protocol decoding pipeline and ultimately to the Drools rule engine.
|
||||
*
|
||||
* @see at.jku.fim.rubanetra.drools.DroolsKrakenProtocolHandler
|
||||
* @see at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder
|
||||
* @see at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration
|
||||
*/
|
||||
public class ConfigurationController {
|
||||
public static final String defaultMainConfigName = "rubanetra.conf";
|
||||
public static final String defaultMainConfigPath = "./conf/" + defaultMainConfigName;
|
||||
public static final String defaultMainConfigEnvVar = "RUBANETRA_SYSTEM_CONF_FILE";
|
||||
private static final Logger log = LoggerFactory.getLogger(ConfigurationController.class);
|
||||
private static final Option helpOption = new Option("h", "help", false, "print the option overview message");
|
||||
private static final Option versionOption = new Option("v", "version", false, "print the version information");
|
||||
private static final Option mainConfigFileOption = new Option("c", "configuration-file", true, "path to the main configuration file");
|
||||
private static final Option inputFiles = new Option("i", "input-files", true, String.format("pcap input files, delimited by '%s' (complements config file)", File.pathSeparatorChar));
|
||||
private static final Option outputFile = new Option("o", "output-file", true, "path to the output file (contents will be overridden)");
|
||||
private static final Option outputType = new Option("t", "output-type", true, "output type/format of the generated content (PLASO, CSV, JSON, XML or NOP)");
|
||||
|
||||
private final RubanetraSystemConfigurationBuilder systemConfigBuilder;
|
||||
private RubanetraSystemConfiguration systemConfiguration;
|
||||
private final LinkedList<String> inputFilePaths = new LinkedList<>();
|
||||
private String outputFilePath;
|
||||
private String outputFormat;
|
||||
|
||||
/**
|
||||
* Creates a new instance of itself and a {@link at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder}
|
||||
*/
|
||||
public ConfigurationController() {
|
||||
systemConfigBuilder = RubanetraSystemConfigurationBuilder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the default command line options, i.e. help (h), version (v), configuration-file (c), input-files (i),
|
||||
* output-file (o), output-type (t)
|
||||
*/
|
||||
public static Options createDefaultOptions() {
|
||||
inputFiles.setArgs(Option.UNLIMITED_VALUES);
|
||||
inputFiles.setValueSeparator(File.pathSeparatorChar);
|
||||
Options options = new Options();
|
||||
options.addOption(helpOption);
|
||||
options.addOption(versionOption);
|
||||
options.addOption(mainConfigFileOption);
|
||||
options.addOption(inputFiles);
|
||||
options.addOption(outputFile);
|
||||
options.addOption(outputType);
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link at.jku.fim.rubanetra.config.ConfigurationController} using default options
|
||||
* {@link #createDefaultOptions()} and a {@link org.apache.commons.cli.GnuParser} to parse the command line
|
||||
* arguments.
|
||||
* After a successful parsing process, {@link ConfigurationController#start()}
|
||||
* will be invoked.
|
||||
*
|
||||
* @param args command line arguments as defined by {@link #createDefaultOptions()}
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
ConfigurationController controller = new ConfigurationController();
|
||||
Options defaultOptions = ConfigurationController.createDefaultOptions();
|
||||
CommandLineParser cliParser = new GnuParser();
|
||||
|
||||
CommandLine cli;
|
||||
try {
|
||||
cli = cliParser.parse(defaultOptions, args);
|
||||
} catch (ParseException e) {
|
||||
log.error("Unable to process parsed arguments: ", e);
|
||||
printHelp(defaultOptions);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cli.hasOption(ConfigurationController.helpOption.getOpt())) {
|
||||
printHelp(defaultOptions);
|
||||
return;
|
||||
} else if (cli.hasOption(ConfigurationController.versionOption.getOpt())) {
|
||||
printVersion();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cli.hasOption(ConfigurationController.inputFiles.getOpt())) {
|
||||
String[] inputFileValues = cli.getOptionValues(ConfigurationController.inputFiles.getOpt());
|
||||
controller.addInputFiles(inputFileValues);
|
||||
}
|
||||
|
||||
if (cli.hasOption(ConfigurationController.outputFile.getOpt())) {
|
||||
String outputFileValue = cli.getOptionValue(ConfigurationController.outputFile.getOpt());
|
||||
controller.setOutputFile(outputFileValue);
|
||||
}
|
||||
|
||||
if (cli.hasOption(ConfigurationController.outputType.getOpt())) {
|
||||
String outputType = cli.getOptionValue(ConfigurationController.outputType.getOpt());
|
||||
controller.setOutputFormat(outputType);
|
||||
}
|
||||
|
||||
boolean initialized;
|
||||
|
||||
String mainConfigurationPath = cli.getOptionValue(ConfigurationController.mainConfigFileOption.getOpt());
|
||||
if (mainConfigurationPath == null) {
|
||||
// config was not provided via command line arg
|
||||
initialized = controller.initialize();
|
||||
} else {
|
||||
initialized = controller.initialize(mainConfigurationPath);
|
||||
}
|
||||
|
||||
if (!initialized || controller.getRubanetraSystemConfiguration() == null) {
|
||||
log.error("Unable to initialize the system: configuration file does either not exist or it is not readable or it is not valid.");
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("System configuration has been initialized successfully, starting the rule engine and input file parsing process.");
|
||||
|
||||
controller.start();
|
||||
}
|
||||
|
||||
private static void printVersion() {
|
||||
Package classPackage = ConfigurationController.class.getPackage();
|
||||
StringBuilder strBuilder = new StringBuilder();
|
||||
Attributes manifestAttributes = getMainAttributes();
|
||||
if (manifestAttributes != null) {
|
||||
strBuilder.append(String.format("%s %s%n", classPackage.getImplementationTitle(), classPackage.getImplementationVersion()));
|
||||
String licShort = manifestAttributes.getValue("License-Short-Name");
|
||||
String licLong = manifestAttributes.getValue("License-Long-Name");
|
||||
String licHeaderLine = manifestAttributes.getValue("License-Short-Header");
|
||||
String licUrl = manifestAttributes.getValue("License-Url");
|
||||
String licInceptionYear = manifestAttributes.getValue("License-Inception-Year");
|
||||
String licRecentYears = manifestAttributes.getValue("License-Recent-Years");
|
||||
String copyrightOwner = manifestAttributes.getValue("Copyright-Owner");
|
||||
strBuilder.append(String.format("Copyright (C) %s,%s %s%n", licInceptionYear, licRecentYears, copyrightOwner));
|
||||
strBuilder.append(String.format("License %s: %s <%s>%n", licShort, licLong, licUrl));
|
||||
String[] headerSplit = licHeaderLine.split("\\.\\s", 2);
|
||||
String headerML = headerSplit.length == 2 ?
|
||||
String.format("%s.%n%s%n", headerSplit[0], headerSplit[1]) : String.format("%s%n", licHeaderLine);
|
||||
strBuilder.append(headerML);
|
||||
} else {
|
||||
strBuilder.append("Unknown version.%n");
|
||||
}
|
||||
System.out.println(strBuilder.toString());
|
||||
}
|
||||
|
||||
private static void printHelp(Options defaultOptions) {
|
||||
Package classPackage = ConfigurationController.class.getPackage();
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
Attributes manifestAttributes = getMainAttributes();
|
||||
|
||||
String cmdLineSyntax;
|
||||
try {
|
||||
cmdLineSyntax = Paths.get(ConfigurationController.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getFileName().toString();
|
||||
} catch (URISyntaxException e) {
|
||||
cmdLineSyntax = String.format("./rubanetra-%s.jar", classPackage.getImplementationVersion());
|
||||
}
|
||||
formatter.printHelp(String.format("java -jar %s <args>", cmdLineSyntax), defaultOptions);
|
||||
|
||||
if (manifestAttributes != null) {
|
||||
StringBuilder strBuilder = new StringBuilder();
|
||||
strBuilder.append(String.format("%nReport bugs to: <%s> or <stefan_rubanetra@swerk.priv.at>%n",
|
||||
manifestAttributes.getValue("Issue-Management")));
|
||||
strBuilder.append(String.format("Project home page: <%s>%n", manifestAttributes.getValue("Project-Home")));
|
||||
System.out.println(strBuilder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the main attributes of the invoked JAR's manifest, containing at least "Implementation-Title",
|
||||
* "Implementation-Version" and "Implementation-Vendor" attributes or null, if the manifest was not found
|
||||
*/
|
||||
public static Attributes getMainAttributes() {
|
||||
Package classPackage = ConfigurationController.class.getPackage();
|
||||
try {
|
||||
Enumeration<URL> resourceEnum = ClassLoader.getSystemResources("META-INF/MANIFEST.MF");
|
||||
while (resourceEnum.hasMoreElements()) {
|
||||
try {
|
||||
URL nextManifestUrl = resourceEnum.nextElement();
|
||||
Manifest manifest = new Manifest(nextManifestUrl.openStream());
|
||||
Attributes manifestAttributes = manifest.getMainAttributes();
|
||||
String mainClassVal = manifestAttributes.getValue("Main-Class");
|
||||
String implementationTitleVal = manifestAttributes.getValue("Implementation-Title");
|
||||
String implementationVersionVal = manifestAttributes.getValue("Implementation-Version");
|
||||
String implementationVendorVal = manifestAttributes.getValue("Implementation-Vendor");
|
||||
if (mainClassVal != null && mainClassVal.equals(ConfigurationController.class.getCanonicalName())
|
||||
&& classPackage.getImplementationTitle().equals(implementationTitleVal)
|
||||
&& classPackage.getImplementationVendor().equals(implementationVendorVal)
|
||||
&& classPackage.getImplementationVersion().equals(implementationVersionVal)) {
|
||||
return manifestAttributes;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Unable to open manifest, skipping...", e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Unable to find any manifest", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method initializes the system invoking a parser for the main configuration file
|
||||
* denoted by mainConfigFile. It tries to canonicalize all encountered file paths and will fail if it is unable
|
||||
* to create a canonical representation.
|
||||
* It relies on {@link at.jku.fim.rubanetra.config.RubanetraSystemConfigurationParser} and
|
||||
* {@link at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBaseListenerImpl} for parsing
|
||||
* functionality and builds the final {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration}
|
||||
* object which can be obtained iff this method returned true via {@link #getRubanetraSystemConfiguration()}.
|
||||
*
|
||||
* @param mainConfigFile the main configuration file, which may not be null
|
||||
* @return true, iff a main configuration instance was created (one may obtain this reference by calling
|
||||
* {@link #getRubanetraSystemConfiguration()}.
|
||||
* @throws java.lang.NullPointerException if the main config file is a null pointer
|
||||
* @throws java.lang.IllegalArgumentException if the main config file is not valid
|
||||
*/
|
||||
public boolean initialize(File mainConfigFile) {
|
||||
if (mainConfigFile == null) {
|
||||
throw new NullPointerException("The main configuration file must not be a null pointer");
|
||||
}
|
||||
try {
|
||||
mainConfigFile = mainConfigFile.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
log.error("Unable to canonicalize file {}", mainConfigFile);
|
||||
return false;
|
||||
}
|
||||
if (!checkMainConfigFile(mainConfigFile)) {
|
||||
return false;
|
||||
}
|
||||
log.info("Trying to load main configuration from file {}", mainConfigFile);
|
||||
|
||||
RubanetraSystemConfigurationParser systemConfigParser = RubanetraSystemConfigurationBaseListenerImpl.createConfigurationFileParser(mainConfigFile);
|
||||
RubanetraSystemConfigurationBaseListenerImpl systemConfigBaseListener = new RubanetraSystemConfigurationBaseListenerImpl(systemConfigBuilder);
|
||||
|
||||
RubanetraSystemConfigurationParser.SystemContext systemContext = systemConfigParser.system();
|
||||
|
||||
if (systemContext == null) {
|
||||
throw new IllegalArgumentException("Invalid configuration file.");
|
||||
}
|
||||
String errorMsg = "Exactly one %s configuration section required, %d have been found";
|
||||
int generalConfigurations = systemContext.generalConfig().size();
|
||||
int inputConfigurations = systemContext.inputConfig().size();
|
||||
int outputConfigurations = systemContext.outputConfig().size();
|
||||
int protocolConfigurations = systemContext.protocolConfig().size();
|
||||
if (generalConfigurations != 1)
|
||||
throw new IllegalArgumentException(String.format(errorMsg, "general", generalConfigurations));
|
||||
if (inputConfigurations != 1)
|
||||
throw new IllegalArgumentException(String.format(errorMsg, "input", inputConfigurations));
|
||||
if (outputConfigurations != 1)
|
||||
throw new IllegalArgumentException(String.format(errorMsg, "output", outputConfigurations));
|
||||
if (protocolConfigurations != 1)
|
||||
throw new IllegalArgumentException(String.format(errorMsg, "protocol", protocolConfigurations));
|
||||
|
||||
/*
|
||||
The general section should be parsed first, as it could contain vital information,
|
||||
followed by the I/O configuration. Due to potentially existing file path entries in those sections and the
|
||||
possibility of a redundant path specification via command line arguments, these settings must be adjusted
|
||||
accordingly, i.e. either complemented or replaced altogether before the Pcap handler can be built, since the
|
||||
protocol configuration depends on an already existing Pcap handler in order to setup listeners.
|
||||
*/
|
||||
ParseTreeWalker.DEFAULT.walk(systemConfigBaseListener, systemContext.generalConfig(0));
|
||||
ParseTreeWalker.DEFAULT.walk(systemConfigBaseListener, systemContext.inputConfig(0));
|
||||
ParseTreeWalker.DEFAULT.walk(systemConfigBaseListener, systemContext.outputConfig(0));
|
||||
complementOrReplaceExistingConfig();
|
||||
systemConfigBuilder.createPcapHandler();
|
||||
ParseTreeWalker.DEFAULT.walk(systemConfigBaseListener, systemContext.protocolConfig(0));
|
||||
|
||||
systemConfiguration = systemConfigBuilder.build();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to either complement (input files) or replace (output file/type) the existing configuration parsed from
|
||||
* the main config files by the provided command line arguments.
|
||||
*/
|
||||
private void complementOrReplaceExistingConfig() {
|
||||
if (this.inputFilePaths.size() > 0) {
|
||||
|
||||
if (!systemConfigBuilder.getInputFiles().isEmpty()) {
|
||||
log.warn("The configuration file contains at least one reference to an input file, complementing with" +
|
||||
" specified command line input file(s)");
|
||||
}
|
||||
for (String inputFilePath : this.inputFilePaths) {
|
||||
systemConfigBuilder.addInputPath(inputFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.outputFilePath != null) {
|
||||
final OutputStream oldOutputStream = systemConfigBuilder.getOutputStream();
|
||||
if (oldOutputStream != null) {
|
||||
log.warn("The configuration file contains at least one reference to an output stream ... replacing it");
|
||||
if (oldOutputStream != System.out && oldOutputStream != System.err) {
|
||||
try {
|
||||
oldOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
log.warn("IOException while trying to close the replaced output stream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outputFilePath.equalsIgnoreCase("stdout") || outputFilePath.equals("-")) {
|
||||
systemConfigBuilder.setOutputStream(System.out);
|
||||
} else {
|
||||
systemConfigBuilder.setOutputFile(outputFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.outputFormat != null) {
|
||||
if (systemConfigBuilder.getOutputFormat() != null) {
|
||||
log.warn("The configuration file contains at least one reference to an output format ... replacing it");
|
||||
}
|
||||
systemConfigBuilder.setOutputFormat(outputFormat);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for {@link #initialize(java.io.File)}.
|
||||
* It creates a file based on the given path.
|
||||
*
|
||||
* @param mainConfigurationPath the path of the main configuration file
|
||||
* @return true, iff the configuration could be parsed (one may obtain a reference to the configuration object by
|
||||
* calling {@link #getRubanetraSystemConfiguration()}.
|
||||
*/
|
||||
public boolean initialize(String mainConfigurationPath) {
|
||||
File systemConfigurationFile = createFileFromResourceString(mainConfigurationPath);
|
||||
if (systemConfigurationFile == null) {
|
||||
systemConfigurationFile = getCanonicalFile(mainConfigurationPath);
|
||||
}
|
||||
|
||||
return initialize(systemConfigurationFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method initializes the system invoking a parser for the main configuration file
|
||||
* denoted by (in processing order):
|
||||
* <ul>
|
||||
* <li>"rubanetra.conf" in the classpath and working directory</li>
|
||||
* <li>"./conf/rubanetra.conf" in the classpath and working directory</li>
|
||||
* <li>path denoted by environment variable FNA_SYSTEM_CONF_FILE in the class path and working directory</li>
|
||||
* </ul>
|
||||
* It tries to canonicalize all encountered file paths and will fail if it is unable
|
||||
* to create a canonical representation.
|
||||
* It relies on {@link at.jku.fim.rubanetra.config.RubanetraSystemConfigurationParser} and
|
||||
* {@link at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBaseListenerImpl} for parsing
|
||||
* functionality and builds the final {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration}
|
||||
* object which can be obtained iff this method returned true via {@link #getRubanetraSystemConfiguration()}.
|
||||
*
|
||||
* @return true, iff a main configuration instance was created (one may obtain this reference by calling
|
||||
* {@link #getRubanetraSystemConfiguration()}.
|
||||
* @throws java.lang.NullPointerException if the main config file is a null pointer
|
||||
* @throws java.lang.IllegalArgumentException if the main config file is not valid
|
||||
*/
|
||||
public boolean initialize() {
|
||||
boolean initialized;
|
||||
log.info("Trying to look up {} in the classpath and the working directory", defaultMainConfigName);
|
||||
// try the default name
|
||||
initialized = initialize(defaultMainConfigName);
|
||||
|
||||
if (!initialized) {
|
||||
log.info("Trying to look up {} in the classpath and the working directory", defaultMainConfigPath);
|
||||
// try the default full path
|
||||
initialized = initialize(defaultMainConfigPath);
|
||||
}
|
||||
if (!initialized) {
|
||||
log.info("Trying to look up path denoted by environment variable {} in the classpath and the working directory",
|
||||
defaultMainConfigEnvVar);
|
||||
// try the default env variable
|
||||
initialized = initializeFromEnvVar(defaultMainConfigEnvVar);
|
||||
}
|
||||
|
||||
return initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to look up the value of the environment variable denoted by envVariableName, and interprets it as
|
||||
* main configuration path ({@link #initialize(java.io.File)} will be called)
|
||||
*
|
||||
* @param envVariableName the name of the environment variable to look up (the value should represent the main
|
||||
* configuration file path)
|
||||
* @return true, iff a main configuration instance was created (one may obtain this reference by calling
|
||||
* {@link #getRubanetraSystemConfiguration()} afterwards.
|
||||
*/
|
||||
public boolean initializeFromEnvVar(String envVariableName) {
|
||||
// try environment variable
|
||||
log.info("Trying to load main configuration path from environment variable {}", envVariableName);
|
||||
File systemConfigurationFile = createFileFromEnvVariable(envVariableName);
|
||||
|
||||
return initialize(systemConfigurationFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to represent the path denoted by mainConfigurationPath canonically.
|
||||
*
|
||||
* @param mainConfigurationPath the file to canonicalize.
|
||||
* @return the file denoted by mainConfigurationPath using a canonical representation or null, if not possible
|
||||
*/
|
||||
public File getCanonicalFile(String mainConfigurationPath) {
|
||||
File systemConfigurationFile;
|
||||
try {
|
||||
systemConfigurationFile = new File(mainConfigurationPath).getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
log.warn("Unable to canonicalize the configuration file path");
|
||||
return null;
|
||||
}
|
||||
return systemConfigurationFile;
|
||||
}
|
||||
|
||||
private File createFileFromEnvVariable(String optionalMainConfigEnvVar) {
|
||||
String mainConfigPath;
|
||||
try {
|
||||
mainConfigPath = System.getenv(optionalMainConfigEnvVar);
|
||||
} catch (SecurityException e) {
|
||||
log.warn("Unable to access environment variable", e);
|
||||
return null;
|
||||
}
|
||||
if (mainConfigPath == null) {
|
||||
log.warn("Unable to load configuration file via environment variable.");
|
||||
} else {
|
||||
File fileFromResourceString = createFileFromResourceString(mainConfigPath);
|
||||
return fileFromResourceString == null ? getCanonicalFile(mainConfigPath) : fileFromResourceString;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to create a file object by looking up filePath in the current classloader's classpath.
|
||||
*
|
||||
* @param filePath the path of the file in the current classpath
|
||||
* @return a file object for filePath, or null if not found
|
||||
*/
|
||||
public File createFileFromResourceString(String filePath) {
|
||||
log.info("Trying to load main configuration as classpath resource: {}", filePath);
|
||||
URL fileUrl = ClassLoader.getSystemResource(filePath);
|
||||
if (fileUrl == null) {
|
||||
log.warn("Unable to find configuration file via class path resource loader: {}", filePath);
|
||||
return null;
|
||||
}
|
||||
File file;
|
||||
try {
|
||||
file = new File(fileUrl.toURI());
|
||||
} catch (URISyntaxException e) {
|
||||
file = new File(filePath);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a simple file metadata validation (is it readable, is it a file),
|
||||
* however, it does not verify the contents of the file itself.
|
||||
*
|
||||
* @param file the file to check
|
||||
* @return true, iff the file is not a directory and is readable and is not null
|
||||
*/
|
||||
public boolean checkMainConfigFile(File file) {
|
||||
if (file != null && !file.isDirectory() && file.canRead()) {
|
||||
return true;
|
||||
}
|
||||
log.warn("Cannot read configuration file {}", file);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds files containing network captures to the configuration builder
|
||||
* {@link at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder}.
|
||||
* <p>
|
||||
* This method may not be invoked after the initialization step has been completed, i.e. this method must be
|
||||
* invoked before {@link #initialize(java.io.File)}.
|
||||
*
|
||||
* @param filePaths a number of file paths containing network captures in the specified
|
||||
* {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.InputFormat}
|
||||
*/
|
||||
public void addInputFiles(String... filePaths) {
|
||||
checkUninitialized();
|
||||
if (filePaths == null) {
|
||||
log.error("Invalid command line input file specification.");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
for (String filePath : filePaths) {
|
||||
if (filePath == null || filePath.isEmpty()) {
|
||||
log.warn("Input file path passed from command line appears to be null/empty - ignoring");
|
||||
} else {
|
||||
inputFilePaths.addLast(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default output file for the derived and parsed data using
|
||||
* {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.OutputFormat}
|
||||
* <p>
|
||||
* This method may not be invoked after the initialization step has been completed, i.e. this method must be
|
||||
* invoked before {@link #initialize(java.io.File)}.
|
||||
*
|
||||
* @param outputFilePath the path of the default output file
|
||||
*/
|
||||
public void setOutputFile(String outputFilePath) {
|
||||
checkUninitialized();
|
||||
if (outputFilePath == null || outputFilePath.isEmpty()) {
|
||||
log.error("Output file path passed from command line appears to be null/empty");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
this.outputFilePath = outputFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.OutputFormat} to apply
|
||||
* as serialization variant.
|
||||
* <p>
|
||||
* This method may not be invoked after the initialization step has been completed, i.e. this method must be
|
||||
* invoked before {@link #initialize(java.io.File)}.
|
||||
*
|
||||
* @param outputFormat the String representation of a {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.OutputFormat}
|
||||
*/
|
||||
public void setOutputFormat(String outputFormat) {
|
||||
checkUninitialized();
|
||||
if (outputFormat == null || outputFormat.isEmpty()) {
|
||||
log.error("Output format path passed from command line appears to be null/empty");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.outputFormat = outputFormat;
|
||||
}
|
||||
|
||||
private void checkUninitialized() {
|
||||
if (this.systemConfiguration != null) {
|
||||
log.error("This system configuration has already been initialized, unable to add additional input files");
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return this method will always return null, unless one of the {@link #initialize(java.io.File)} methods was invoked
|
||||
* successfully, then it will return the constructed {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration}.
|
||||
*/
|
||||
public RubanetraSystemConfiguration getRubanetraSystemConfiguration() {
|
||||
return systemConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will do nothing, unless one of the {@link #initialize(java.io.File)} methods has been invoked
|
||||
* successfully.
|
||||
* <p>
|
||||
* If a valid {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration} is encountered,
|
||||
* a {@link at.jku.fim.rubanetra.drools.DroolsKrakenProtocolHandler} will be constructed and
|
||||
* {@link at.jku.fim.rubanetra.pcap.PcapHandler#readNextPcapEntry(at.jku.fim.rubanetra.pcap.PcapActivityListener)}
|
||||
* will be called as long as it returns true (using an infinite loop), i.e. until all network packets have been read
|
||||
* from the input files. Afterwards, it will try to close all opened input and output streams, that is it will call
|
||||
* {@link at.jku.fim.rubanetra.drools.DroolsKrakenProtocolHandler#close()}
|
||||
* and {@link at.jku.fim.rubanetra.pcap.PcapHandler#close()}.
|
||||
* Ultimately the existing reference to the {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration}
|
||||
* will be erased, therefore allowing for a subsequent initialization call while reusing the same object.
|
||||
*/
|
||||
public void start() {
|
||||
if (this.systemConfiguration == null || systemConfiguration.getPcapHandler() == null) {
|
||||
log.error("System configuration has not been initialized completely.");
|
||||
return;
|
||||
}
|
||||
DroolsKrakenProtocolHandler droolsKrakenProtocolHandler = new DroolsKrakenProtocolHandler(systemConfiguration);
|
||||
while (true) {
|
||||
try {
|
||||
final boolean processingSuccessful = (systemConfiguration.getPcapHandler().readNextPcapEntry(droolsKrakenProtocolHandler));
|
||||
if (!processingSuccessful) break;
|
||||
} catch (Exception e) {
|
||||
log.debug("Catch all exception block was entered", e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
droolsKrakenProtocolHandler.close();
|
||||
} catch (IOException e) {
|
||||
log.warn("Exception occurred while trying to close the Drools/Kraken Protocol Handler:", e);
|
||||
} finally {
|
||||
this.systemConfiguration.getPcapHandler().close();
|
||||
this.systemConfiguration = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model;
|
||||
|
||||
|
||||
import org.jnetpcap.protocol.JProtocol;
|
||||
|
||||
/**
|
||||
* This interface serves as an identifier for a potential {@link org.jnetpcap.protocol.JProtocol}.
|
||||
* Since the current system utilizes the Kraken-library as main reference point, this interface is currently a
|
||||
* placeholder for future refinements.
|
||||
*/
|
||||
public interface JNetPcapProtocolId extends ProtocolId {
|
||||
|
||||
/**
|
||||
* @return the represented {@link org.jnetpcap.protocol.JProtocol}
|
||||
*/
|
||||
JProtocol getJNetPcapProtocol();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model;
|
||||
|
||||
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
|
||||
/**
|
||||
* Implementations of this interface serve as identifiers for potential {@link org.krakenapps.pcap.Protocol}s, i.e.
|
||||
* the application layer specific Kraken-library protocol identifier.
|
||||
*/
|
||||
public interface KrakenApplicationProtocolId extends ProtocolId {
|
||||
|
||||
/**
|
||||
* @return the represented Kraken-library specific {@link org.krakenapps.pcap.Protocol}
|
||||
*/
|
||||
public abstract Protocol getKrakenApplicationProtocol();
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivityListener;
|
||||
import at.jku.fim.rubanetra.pcap.PcapHandler;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenTransportLayerMappingFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This interface specifies methods that may be used to represent the configuration of a single application layer
|
||||
* protocol of the Kraken-library. A {@link at.jku.fim.rubanetra.config.model.impl.KrakenProtocolConfigurationBuilderImpl}
|
||||
* should be used to obtain an implementation of this interface.
|
||||
* <p>
|
||||
* Due to the current design of the Kraken-PCAP-library all application layer protocols
|
||||
* rely on either a UDP ({@link org.krakenapps.pcap.decoder.udp.UdpProtocolMapper}) or a TCP
|
||||
* ({@link org.krakenapps.pcap.decoder.tcp.TcpProtocolMapper}) protocol mapper.
|
||||
* One of the design goals of this framework is the abstraction of this mechanism to enable customizations that do
|
||||
* not require modifications of existing application layer parsers (e.g. HTTP over a custom transport layer protocol
|
||||
* or multiple ports).
|
||||
* A first step to achieve this goal is the introduction of a generic
|
||||
* {@link at.jku.fim.rubanetra.protocol.mapper.TransportLayerMappingStrategy}.
|
||||
* However, currently only a port/service based approach has been implemented. Since Kraken apparently does not allow
|
||||
* the use of multiple ports per application layer parser (since the TCP/UDP-Mapper would override the bindings with
|
||||
* the default parser), a custom {@link at.jku.fim.rubanetra.config.model.PortSpecification} approach
|
||||
* was implemented on an application layer basis, i.e. a single application layer protocol may be bound to a
|
||||
* Kraken-application layer parser for a single, multiple, all or no port(s).
|
||||
* However, as soon as JNetPcap provides suitable application layer parsers for the currently supported protocols,
|
||||
* this mechanism should be replaced by JNetPcap-bindings which is more elegant and convenient.
|
||||
* This interface is implemented by
|
||||
* {@link at.jku.fim.rubanetra.config.model.impl.KrakenProtocolConfigurationBuilderImpl.KrakenProtocolConfigurationImpl}.
|
||||
*/
|
||||
public interface KrakenProtocolConfiguration {
|
||||
/**
|
||||
* The underlying source of all PCAP-packets for this application layer protocol. A listener will be attached
|
||||
* by default to listen for new {@link at.jku.fim.rubanetra.pcap.PcapActivity}-objects.
|
||||
* All parsed PCAP-packets will be either parsed by a Kraken-Application layer parser for this protocol or
|
||||
* discarded by the transport layer mapping strategy and/or port-specification.
|
||||
*
|
||||
* @return the {@link at.jku.fim.rubanetra.pcap.PcapHandler} to use as input stream for
|
||||
* {@link at.jku.fim.rubanetra.pcap.PcapActivity}-objects.
|
||||
* @see #getTransportLayerMappingStrategy()
|
||||
* @see #getPortSpecification()
|
||||
*/
|
||||
public abstract PcapHandler<PcapActivityListener> getPcapHandler();
|
||||
|
||||
/**
|
||||
* Represents a primitive protocol to Kraken-protocol decoder mapping mechanism.
|
||||
* A network protocol within this framework is always identified by a
|
||||
* {@link at.jku.fim.rubanetra.config.model.ProtocolId}. Therefore a mapping of a protocol to
|
||||
* an appropriate Kraken-protocol decoder/parser is needed. All
|
||||
* {@link at.jku.fim.rubanetra.protocol.KrakenBaseProtocol} implementations provide a method to
|
||||
* retrieve a suitable identifier
|
||||
* {@link at.jku.fim.rubanetra.protocol.KrakenBaseProtocol#getProtocolId()}.
|
||||
* These bindings may be configured by using a
|
||||
* {@link at.jku.fim.rubanetra.config.model.impl.KrakenProtocolConfigurationBuilderImpl}.
|
||||
*
|
||||
* @return the immutable copy of all application layer protocol bindings
|
||||
*/
|
||||
public abstract Map<ProtocolId, KrakenBaseProtocol> getBoundProtocols();
|
||||
|
||||
/**
|
||||
* The transport layer mapping strategy to use for this Kraken-application layer protocol decoder.
|
||||
*
|
||||
* @return the transport layer protocol mapping strategy identifier which may be used to obtain an instance of
|
||||
* a {@link at.jku.fim.rubanetra.protocol.mapper.TransportLayerMappingStrategy} by using
|
||||
* {@link at.jku.fim.rubanetra.protocol.mapper.KrakenTransportLayerMappingFactory}.
|
||||
*/
|
||||
public abstract String getTransportLayerMappingStrategy();
|
||||
|
||||
/**
|
||||
* The specification of a number of {@link at.jku.fim.rubanetra.config.model.PortRange}s or
|
||||
* {@link at.jku.fim.rubanetra.config.model.Port}s which filters packets at the transport layer
|
||||
* for this application layer protocol. A simpler alternative to this method is the use of
|
||||
* {@link at.jku.fim.rubanetra.config.model.PortSpecification.UniversalPortSpecification} and
|
||||
* by restricting all transport layer packets globally via a BP-Filter,
|
||||
* see {@link at.jku.fim.rubanetra.pcap.PcapHandler}.
|
||||
*
|
||||
* @return the {@link at.jku.fim.rubanetra.config.model.PortSpecification} as a transport layer
|
||||
* filter for this application layer protocol only
|
||||
* @see at.jku.fim.rubanetra.config.model.PortSpecification.UniversalPortSpecification
|
||||
*/
|
||||
public abstract PortSpecification getPortSpecification();
|
||||
|
||||
/**
|
||||
* This {@link at.jku.fim.rubanetra.protocol.mapper.KrakenTransportLayerMappingFactory} may be used
|
||||
* by the {@link at.jku.fim.rubanetra.protocol.KrakenBaseProtocol} parsers
|
||||
* to obtain instances of the configured {@link #getTransportLayerMappingStrategy()}.
|
||||
*
|
||||
* @return a factory to obtain instances of the transport layer mapping strategy
|
||||
*/
|
||||
public abstract KrakenTransportLayerMappingFactory getTransportLayerMappingFactory();
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivityListener;
|
||||
import at.jku.fim.rubanetra.pcap.PcapHandler;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenTransportLayerMappingFactory;
|
||||
|
||||
/**
|
||||
* Generic specification of a Kraken application protocol configuration builder.
|
||||
*/
|
||||
public interface KrakenProtocolConfigurationBuilder {
|
||||
/**
|
||||
* Builds the protocol configuration that has been set up until now
|
||||
* @return the immutable protocol configuration that has been set up until now
|
||||
*/
|
||||
public abstract KrakenProtocolConfiguration buildProtocolConfiguration();
|
||||
|
||||
/**
|
||||
* Set a transport layer filter for the parser of this protocol
|
||||
* @param transportProtocolPortSpec the port specification for this application layer protocol parser
|
||||
* @return the builder instance
|
||||
* @see at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration
|
||||
*/
|
||||
public abstract KrakenProtocolConfigurationBuilder setPortSpecification(PortSpecification transportProtocolPortSpec);
|
||||
|
||||
/**
|
||||
* Set the transport layer mapping strategy to use for this protocol
|
||||
* @param strategy the {@link at.jku.fim.rubanetra.protocol.mapper.TransportLayerMappingStrategy} to use
|
||||
* @return the builder instance
|
||||
* @see at.jku.fim.rubanetra.protocol.mapper.KrakenTransportLayerMappingFactory
|
||||
*/
|
||||
public abstract KrakenProtocolConfigurationBuilder setTransportProtocolMappingStrategy(String strategy);
|
||||
|
||||
/**
|
||||
* Set the transport layer mapping factory to use for building transport layer mapping strategies
|
||||
* @param mappingFactory the transport layer mapping factory to use
|
||||
* @return the builder instance
|
||||
*/
|
||||
public abstract KrakenProtocolConfigurationBuilder setTransportProtocolMappingFactory(KrakenTransportLayerMappingFactory mappingFactory);
|
||||
|
||||
/**
|
||||
* Set the pcap packet input stream for this application layer protocol parser
|
||||
* @param pcapHandler the Pcap packet input stream
|
||||
* @return the builder instance
|
||||
*/
|
||||
public abstract KrakenProtocolConfigurationBuilder setPcapHandler(PcapHandler<PcapActivityListener> pcapHandler);
|
||||
|
||||
/**
|
||||
* Resets all settings of the current protocol configuration
|
||||
*/
|
||||
public abstract void resetCurrentProtocolConfiguration();
|
||||
|
||||
/**
|
||||
* Bind a protocol handler to another protocol handler, i.e. define the stream of decoded data
|
||||
* (in general one way only, unless bound vice-versa as well)
|
||||
* @param bindFrom the wild protocol identifier which can be mapped by the protocol registry to
|
||||
* an existing protocol handler, and that will be bound to the handler of the bindTo protocol
|
||||
* @param bindTo the wild protocol identifier which can be mapped by the protocol registry to
|
||||
* an existing protocol handler, and that will receive decoded data from the bindFrom handler
|
||||
*
|
||||
* @return the builder instance
|
||||
*/
|
||||
public abstract KrakenProtocolConfigurationBuilder bindProtocol(String bindFrom, String bindTo);
|
||||
|
||||
/**
|
||||
* Set the protocol identifier to use for this protocol configuration.
|
||||
* @param currentProtocolIdentifier a protocol identifier (should be unique within this framework)
|
||||
* @return the builder instance
|
||||
*/
|
||||
public abstract KrakenProtocolConfigurationBuilder setCurrentProtocolIdentifier(String currentProtocolIdentifier);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A transport layer TCP/UDP port number.
|
||||
*/
|
||||
public class Port implements Comparable<Port> {
|
||||
/**
|
||||
* the lower bound of the available port number pool
|
||||
*/
|
||||
public static final int LOWER_BOUND = 0;
|
||||
/**
|
||||
* the upper bound of the available port number pool
|
||||
*/
|
||||
public static final int UPPER_BOUND = 65535;
|
||||
|
||||
private static final Map<Integer, Port> numberPortMap = new HashMap<>();
|
||||
|
||||
private int portNumber;
|
||||
|
||||
|
||||
/**
|
||||
* Private constructor, use {@link #create(int)} instead
|
||||
*
|
||||
* @throws java.lang.IllegalArgumentException if the port-number is not within the allowed range
|
||||
*/
|
||||
private Port(int portNumber) {
|
||||
checkPortNumber(portNumber);
|
||||
this.portNumber = portNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link at.jku.fim.rubanetra.config.model.Port}
|
||||
*
|
||||
* @param portNumber the port number to use
|
||||
* @return a new {@link at.jku.fim.rubanetra.config.model.Port} or
|
||||
* an instance of an already instantiated port.
|
||||
* @throws java.lang.IllegalArgumentException if the port-number is not within the allowed range
|
||||
*/
|
||||
public static Port create(int portNumber) {
|
||||
if (!numberPortMap.containsKey(portNumber)) {
|
||||
numberPortMap.put(portNumber, new Port(portNumber));
|
||||
}
|
||||
return numberPortMap.get(portNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is equivalent to calling {@link #create(int)}.
|
||||
* Create a new {@link at.jku.fim.rubanetra.config.model.Port}
|
||||
*
|
||||
* @param portNumber the port number to use
|
||||
* @return a new {@link at.jku.fim.rubanetra.config.model.Port} or
|
||||
* an instance of an already instantiated port.
|
||||
* @throws java.lang.IllegalArgumentException if the port-number is not within the allowed range
|
||||
*/
|
||||
public static Port getPort(int portNumber) {
|
||||
return create(portNumber);
|
||||
}
|
||||
|
||||
private void checkPortNumber(int portNumber) {
|
||||
if (portNumber < LOWER_BOUND || portNumber > UPPER_BOUND) {
|
||||
throw new IllegalArgumentException(String.format("Port %d is out of range", portNumber));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the represented port number
|
||||
*/
|
||||
public int getPortNumber() {
|
||||
return portNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Port otherPort) {
|
||||
return Integer.compare(getPortNumber(), otherPort.getPortNumber());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(portNumber);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model;
|
||||
|
||||
/**
|
||||
* A port range is defined by an interval that is bound by two ports, i.e.
|
||||
* [lowerPort;upperPort], both bounds are inclusive.
|
||||
*/
|
||||
public class PortRange {
|
||||
private Port lowerPort;
|
||||
private Port higherPort;
|
||||
|
||||
/**
|
||||
* Create a new port range, which represents all possible ports within the interval [lowerPort;upperPort], inclusive
|
||||
*
|
||||
* @param lowerPort the lower bound of the range, must be less than higherPort.
|
||||
* @param higherPort the upper bound of the range, must be greater than lowerPort.
|
||||
* @throws java.lang.IllegalArgumentException if invalid arguments are passed
|
||||
*/
|
||||
public PortRange(Port lowerPort, Port higherPort) {
|
||||
this.lowerPort = lowerPort;
|
||||
this.higherPort = higherPort;
|
||||
checkPortRange(lowerPort, higherPort);
|
||||
}
|
||||
|
||||
private void checkPortRange(Port lowerPort, Port higherPort) {
|
||||
if (lowerPort == null || higherPort == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (lowerPort.compareTo(higherPort) >= 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given port is within this range, i.e. port in [lowerPort;higherPort]
|
||||
* @param port to check
|
||||
* @return true, iff if port is in this range
|
||||
* @throws java.lang.IllegalArgumentException if the port is null
|
||||
*/
|
||||
public boolean isWithinRange(Port port) {
|
||||
if (port == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return port.compareTo(getLowerPort()) >= 0 && port.compareTo(getHigherPort()) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the upper bound of this range
|
||||
*/
|
||||
public Port getHigherPort() {
|
||||
return higherPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the upper bound of this range
|
||||
* @param higherPort the upper bound of the range, must be greater than lowerPort.
|
||||
*/
|
||||
public void setHigherPort(Port higherPort) {
|
||||
checkPortRange(lowerPort, higherPort);
|
||||
this.higherPort = higherPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lower bound of this range
|
||||
*/
|
||||
public Port getLowerPort() {
|
||||
return lowerPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lower bound of the range
|
||||
* @param lowerPort the lower bound of the range, must be less than higherPort.
|
||||
*/
|
||||
public void setLowerPort(Port lowerPort) {
|
||||
checkPortRange(lowerPort, higherPort);
|
||||
this.lowerPort = lowerPort;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class constitutes a higher level specification of the mapping between an application layer protocol and
|
||||
* the associated transport layer (TCP/UDP) port numbers and/or port ranges.
|
||||
* It is utilized for a number of Kraken application layer protocol parser to transport layer mapping abstractions, e.g.
|
||||
* {@link at.jku.fim.rubanetra.protocol.mapper.TransportLayerMappingStrategy}, and configured by
|
||||
* an instance of {@link at.jku.fim.rubanetra.config.model.KrakenProtocolConfigurationBuilder} resulting
|
||||
* in a {@link at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration} object.
|
||||
* Note, that this implementation currently utilizes the Java 8 - Stream API for performing {@link at.jku.fim.rubanetra.config.model.PortRange}
|
||||
* bound checking via predicates, see {@link #contains(Port)}.
|
||||
* Additionally, the subclass {@link at.jku.fim.rubanetra.config.model.PortSpecification.UniversalPortSpecification}
|
||||
* was defined for convenience reasons.
|
||||
* This class is not thread-safe.
|
||||
*/
|
||||
public class PortSpecification {
|
||||
private final Map<Integer, Port> portMap;
|
||||
private final Set<PortRange> portRangeSet;
|
||||
|
||||
public PortSpecification() {
|
||||
this.portMap = new HashMap<>();
|
||||
this.portRangeSet = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a single port to this specification.
|
||||
* A previously defined port with the same port number will be overwritten silently.
|
||||
*
|
||||
* @param singlePort the port to add to this specification
|
||||
* @throws java.lang.IllegalArgumentException if singlePort == null
|
||||
*/
|
||||
public void add(Port singlePort) {
|
||||
if (singlePort == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.portMap.put(singlePort.getPortNumber(), singlePort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new port-range to this specification.
|
||||
* A {@link java.util.HashSet} is used internally to store the port ranges.
|
||||
*
|
||||
* @param portRange the port range to add to this specification
|
||||
* @throws java.lang.IllegalArgumentException if the portRange is null
|
||||
*/
|
||||
public void add(PortRange portRange) {
|
||||
if (portRange == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
this.portRangeSet.add(portRange);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a convenience method for {@link #contains(Port)}.
|
||||
* A new {@link at.jku.fim.rubanetra.config.model.Port} is constructed for the passed
|
||||
* integer argument.
|
||||
*
|
||||
* @param destinationPort the port number to check against this specification
|
||||
* @return false, if the given port was null or if it does not conform to the bounds of this specification,
|
||||
* true, iff the given port is backed by either a port-range or a single port number.
|
||||
* @throws java.lang.IllegalArgumentException if the port number is invalid
|
||||
* @see #contains(Port)
|
||||
*/
|
||||
public boolean contains(int destinationPort) {
|
||||
Port p = Port.getPort(destinationPort);
|
||||
return contains(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a bound check according to the underlying specification.
|
||||
* A port adheres to the specification iff it was specified as a single {@link at.jku.fim.rubanetra.config.model.Port}
|
||||
* or any specified {@link at.jku.fim.rubanetra.config.model.PortRange} returns true by calling
|
||||
* {@link at.jku.fim.rubanetra.config.model.PortRange#isWithinRange(Port)}.
|
||||
* A Java 8 predicate check via the new stream-API is currently used for this check.
|
||||
*
|
||||
* @param destinationPort the port to check against this specification
|
||||
* @return false, if the given port was null or if it does not conform to the bounds of this specification,
|
||||
* true, iff the given port is backed by either a port-range or a single port number.
|
||||
*/
|
||||
public boolean contains(Port destinationPort) {
|
||||
if (destinationPort == null) {
|
||||
return false;
|
||||
}
|
||||
return this.portMap.containsKey(destinationPort.getPortNumber())
|
||||
|| portRangeSet.stream().anyMatch(portRange -> portRange.isWithinRange(destinationPort));
|
||||
}
|
||||
|
||||
/**
|
||||
* A port specification that returns either always true or always false for any given port number.
|
||||
*/
|
||||
public static class UniversalPortSpecification extends PortSpecification {
|
||||
public static final PortSpecification ACCEPT_ALL = new UniversalPortSpecification(true);
|
||||
public static final PortSpecification REJECT_ALL = new UniversalPortSpecification(false);
|
||||
private final boolean acceptPort;
|
||||
|
||||
/**
|
||||
* Only two meaningful implementations available - either return true or false,
|
||||
* therefore a public constructor was deemed to be unnecessary.
|
||||
*/
|
||||
private UniversalPortSpecification(boolean accept) {
|
||||
super();
|
||||
this.acceptPort = accept;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int destinationPort) {
|
||||
Port p = Port.getPort(destinationPort);
|
||||
return contains(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Port destinationPort) {
|
||||
return destinationPort != null && acceptPort;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model;
|
||||
|
||||
|
||||
/**
|
||||
* This interface represents a meta-identifier for network protocols of arbitrary layers and frameworks.
|
||||
* Since the currently included network stack parser/decoder (Kraken/JNetPcap) use their own, partly incompatible
|
||||
* protocol identifier mechanism, this interface tries to provide a common denominator which allows the identification
|
||||
* of a single network protocol within the system's framework.
|
||||
* The provided information of implementations is intended for internal usage only, i.e. the used identifiers are
|
||||
* neither globally unique nor adhere to a specific standard/RFC.
|
||||
* See {@link at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId} and
|
||||
* {@link at.jku.fim.rubanetra.config.model.JNetPcapProtocolId}.
|
||||
*/
|
||||
public interface ProtocolId {
|
||||
|
||||
/**
|
||||
* @return a unique identifier (within the framework) for the network protocol to represent
|
||||
*/
|
||||
public abstract String getProtocolId();
|
||||
|
||||
/**
|
||||
* @return a human-readable name for the network protocol to represent
|
||||
*/
|
||||
public abstract String getName();
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.output.OutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.pcap.PcapFileHandler;
|
||||
import org.kie.api.runtime.KieSession;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The generic specification of the system configuration itself.
|
||||
* This may be considered to constitute many of the essential settings, i.e. how and where to write the derived data, the Pcap
|
||||
* packet input stream, the input files, the Drools knowledge session.
|
||||
* Use a {@link at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder} to obtain an implementation
|
||||
* instance programmatically.
|
||||
*/
|
||||
public interface RubanetraSystemConfiguration {
|
||||
|
||||
/**
|
||||
* The main output stream that is used to write all derived information to.
|
||||
* The format of this data is defined by the {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.OutputFormat},
|
||||
* see{@link #getOutputFormat()}.
|
||||
* The point of time that defines when the data is actually written to this stream, is controlled by the
|
||||
* {@link at.jku.fim.rubanetra.output.OutputWriterStrategy}, see {@link #getOutputWriterStrategy()},
|
||||
* and the Drools knowledge session (i.e. the Rule engine and custom rules).
|
||||
*
|
||||
* @return the main output stream of the derived information
|
||||
*/
|
||||
public OutputStream getOutputStream();
|
||||
|
||||
/**
|
||||
* The format that is used to transform the derived data before it is written to the output-stream.
|
||||
*
|
||||
* @return the format to use for data transformation
|
||||
* @see #getOutputStream()
|
||||
*/
|
||||
public OutputFormat getOutputFormat();
|
||||
|
||||
/**
|
||||
* The writer strategy that is used to transform (using {@link #getOutputFormat()}) and finally write (using
|
||||
* {@link #getOutputStream()}) the derived data (delivered from {@link #getKieSession()}).
|
||||
*
|
||||
* @return the defined writer strategy
|
||||
* @see #getOutputStream()
|
||||
* @see #getOutputFormat()
|
||||
*/
|
||||
public OutputWriterStrategy getOutputWriterStrategy();
|
||||
|
||||
/**
|
||||
* The set of all defined protocol configurations, each representing the complete configuration of a Kraken protocol
|
||||
* parser/decoder, containing protocol mappings (ETHERNET->IPv4->...->...).
|
||||
*
|
||||
* @return the immutable set of defined Kraken protocol parser configurations
|
||||
*/
|
||||
public Set<KrakenProtocolConfiguration> getProtocolSettings();
|
||||
|
||||
/**
|
||||
* The Pcap packet input stream handler that is used to parse and react to Pcap-information
|
||||
* from the set of defined input files.
|
||||
*
|
||||
* @return the pcap input stream handler
|
||||
*/
|
||||
public PcapFileHandler<?> getPcapHandler();
|
||||
|
||||
/**
|
||||
* The set of input files possibly adhering to a PCAP-specification.
|
||||
*
|
||||
* @return the set of pcap input files used for parsing pcap-packets
|
||||
*/
|
||||
public Set<File> getInputFiles();
|
||||
|
||||
/**
|
||||
* The format of all input files (currently always PCAP)
|
||||
*
|
||||
* @return the common input format of all files
|
||||
*/
|
||||
public InputFormat getInputFormat();
|
||||
|
||||
/**
|
||||
* The Drools knowledge session reference, used to pass new facts to the rule engine
|
||||
* decoded by the protocol parsers.
|
||||
*
|
||||
* @return the Drools knowledge session reference
|
||||
*/
|
||||
public KieSession getKieSession();
|
||||
|
||||
/**
|
||||
* The enumeration of possible output formats, used for transforming derived data before it is written to the output
|
||||
* stream.
|
||||
*
|
||||
* @see #getOutputFormat()
|
||||
*/
|
||||
public enum OutputFormat {
|
||||
/**
|
||||
* PLASO may be considered synonymous to XML,
|
||||
*/
|
||||
PLASO,
|
||||
CSV,
|
||||
JSON,
|
||||
XML,
|
||||
/**
|
||||
* no-op, i.e. data will not be written at all
|
||||
*/
|
||||
NOP, CALLBACK
|
||||
}
|
||||
|
||||
/**
|
||||
* The enumeration of possible input formats, used for defining the appropriate input file handler without
|
||||
* guessing
|
||||
*
|
||||
* @see #getInputFormat()
|
||||
*/
|
||||
public enum InputFormat {
|
||||
PCAP
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model.impl;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfigurationBuilder;
|
||||
import at.jku.fim.rubanetra.config.model.PortSpecification;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivityListener;
|
||||
import at.jku.fim.rubanetra.pcap.PcapHandler;
|
||||
import at.jku.fim.rubanetra.protocol.BaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenTransportLayerMappingFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The default implementation of the {@link at.jku.fim.rubanetra.config.model.KrakenProtocolConfigurationBuilder}.
|
||||
* This class may be used to configure protocol parsers from the Kraken-library.
|
||||
*/
|
||||
public class KrakenProtocolConfigurationBuilderImpl implements KrakenProtocolConfigurationBuilder {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final ProtocolClassRegistry protocolRegistry;
|
||||
// a single protocol handler may forward data to multiple receivers, e.g. consider eth->ipv4, eth->ipv6
|
||||
private final Map<ProtocolId, Set<ProtocolId>> currentProtocolBindingMap;
|
||||
private PortSpecification currentProtocolPortSpec;
|
||||
private KrakenTransportLayerMappingFactory currentTransportLayerMappingFactory;
|
||||
private String currentTransportLayerStrategy;
|
||||
private PcapHandler<PcapActivityListener> currentPcapHandler;
|
||||
// the currently set protocol identifier for the protocol-config being built (arbitrary value, should be unique)
|
||||
private String currentProtocolIdentifier;
|
||||
|
||||
/**
|
||||
* Creates a new builder instance using a default protocol lookup registry by calling
|
||||
* {@link ProtocolClassRegistry#createDefaultKrakenProtocolRegistry()}.
|
||||
*/
|
||||
public KrakenProtocolConfigurationBuilderImpl() {
|
||||
this(ProtocolClassRegistry.createDefaultKrakenProtocolRegistry());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder instance using a custom protocol lookup registry.
|
||||
* Be aware that all classes specified in the registry must define a default constructor.
|
||||
*
|
||||
* @param protocolRegistry the custom protocol registry to use for {@link at.jku.fim.rubanetra.config.model.ProtocolId}
|
||||
* lookup
|
||||
*/
|
||||
public KrakenProtocolConfigurationBuilderImpl(ProtocolClassRegistry protocolRegistry) {
|
||||
if (protocolRegistry == null) {
|
||||
log.error("The protocol registry must not be null.");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.protocolRegistry = protocolRegistry;
|
||||
this.currentProtocolBindingMap = new HashMap<>();
|
||||
|
||||
resetCurrentProtocolConfiguration();
|
||||
|
||||
log.info("Decoder available for protocols: {}",
|
||||
protocolRegistry.getRegisteredProtocolIdSet().stream().map(ProtocolId::getName).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see at.jku.fim.rubanetra.config.KrakenProtocolConfigurationBuilder#
|
||||
* resetCurrentProtocolConfiguration()
|
||||
*/
|
||||
@Override
|
||||
public void resetCurrentProtocolConfiguration() {
|
||||
this.currentProtocolIdentifier = null;
|
||||
this.currentPcapHandler = null;
|
||||
this.currentProtocolPortSpec = new PortSpecification();
|
||||
this.currentProtocolBindingMap.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see at.jku.fim.rubanetra.config.KrakenProtocolConfigurationBuilder#bindProtocol
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public KrakenProtocolConfigurationBuilder bindProtocol(String protocolBindFrom, String protocolBindTo) {
|
||||
if (!existsProtocolId(protocolBindFrom) || !existsProtocolId(protocolBindTo)) {
|
||||
throw new IllegalArgumentException(String.format("Unable to bind protocol %s to %s (unkown protocol(s))", protocolBindFrom, protocolBindTo));
|
||||
}
|
||||
ProtocolId bindFrom = getProtocolIdFromWildId(protocolBindFrom);
|
||||
ProtocolId bindTo = getProtocolIdFromWildId(protocolBindTo);
|
||||
log.debug("Adding binding from {} to {}", bindFrom, bindTo);
|
||||
|
||||
if (bindFrom == bindTo) {
|
||||
// or should it be allowed?
|
||||
throw new IllegalArgumentException(String.format("It is not allowed to bind a protocol handler to itself (%s)", bindFrom));
|
||||
}
|
||||
|
||||
if (!currentProtocolBindingMap.containsKey(bindFrom)) {
|
||||
currentProtocolBindingMap.put(bindFrom, new HashSet<>());
|
||||
}
|
||||
currentProtocolBindingMap.get(bindFrom).add(bindTo);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private ProtocolId getProtocolIdFromWildId(String wildProtocolId) {
|
||||
if (wildProtocolId == null || wildProtocolId.isEmpty()) {
|
||||
throw new IllegalArgumentException("Unknown protocol or no protocol is mapped to a protocol id");
|
||||
}
|
||||
// This reduction does not handle multiple registrations to a similar protocolId-String well (it picks the first match found one)
|
||||
return protocolRegistry.getRegisteredProtocolIdSet().stream()
|
||||
.filter(protocolId -> protocolId.getProtocolId().equalsIgnoreCase(wildProtocolId)).findFirst().get();
|
||||
}
|
||||
|
||||
private boolean existsProtocolId(String wildProtocolId) {
|
||||
return wildProtocolId != null
|
||||
&& protocolRegistry.getRegisteredProtocolIdSet().stream()
|
||||
.anyMatch(protocolId -> protocolId.getProtocolId().equalsIgnoreCase(wildProtocolId));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see at.jku.fim.rubanetra.config.KrakenProtocolConfigurationBuilder#
|
||||
* setPortSpecification
|
||||
* (at.jku.fim.rubanetra.config.PortSpecification)
|
||||
*/
|
||||
@Override
|
||||
public KrakenProtocolConfigurationBuilder setPortSpecification(PortSpecification transportProtocolPortSpec) {
|
||||
this.currentProtocolPortSpec = transportProtocolPortSpec;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KrakenProtocolConfigurationBuilder setTransportProtocolMappingStrategy(String strategy) {
|
||||
if (strategy == null) {
|
||||
throw new IllegalArgumentException("Invalid transport layer mapping strategy");
|
||||
}
|
||||
currentTransportLayerStrategy = strategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KrakenProtocolConfigurationBuilder setTransportProtocolMappingFactory(KrakenTransportLayerMappingFactory mappingFactory) {
|
||||
if (mappingFactory == null) {
|
||||
throw new IllegalArgumentException("Invalid transport layer mapping factory");
|
||||
}
|
||||
currentTransportLayerMappingFactory = mappingFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KrakenProtocolConfigurationBuilder setPcapHandler(PcapHandler<PcapActivityListener> pcapHandler) {
|
||||
this.currentPcapHandler = pcapHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KrakenProtocolConfiguration buildProtocolConfiguration() {
|
||||
KrakenProtocolConfiguration setting = new KrakenProtocolConfigurationImpl();
|
||||
resetCurrentProtocolConfiguration();
|
||||
return setting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently set protocol identifier (may be null)
|
||||
*/
|
||||
public String getCurrentProtocolIdentifier() {
|
||||
return currentProtocolIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KrakenProtocolConfigurationBuilder setCurrentProtocolIdentifier(String currentProtocolIdentifier) {
|
||||
if (this.currentProtocolIdentifier != null) {
|
||||
// build is in progress
|
||||
throw new IllegalStateException(String.format("Protocol configuration for %s is incomplete.", this.currentProtocolIdentifier));
|
||||
}
|
||||
this.currentProtocolIdentifier = currentProtocolIdentifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This inner class represents a final protocol configuration object which will be used to initialize Kraken protocol
|
||||
* handlers.
|
||||
* There are no setter methods, since all fields are now considered to be immutable and must not change during the
|
||||
* lifetime of the object.
|
||||
* Instances of this class may be obtained by using and configuring a
|
||||
* {@link at.jku.fim.rubanetra.config.model.impl.KrakenProtocolConfigurationBuilderImpl}.
|
||||
* This implementation relies on the fact that all registered protocol handlers (even custom handlers) define
|
||||
* a default constructor. All handlers may utilize information of this configuration by overriding the
|
||||
* {@link at.jku.fim.rubanetra.protocol.KrakenBaseProtocol#initialize(at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration)}
|
||||
* method, which will be called as soon as possible after construction.
|
||||
* Further note, that this implementation tries to reduce the number of protocol handler instances. The current
|
||||
* mechanism first takes an unbound protocol id of the binding map, constructs an instance and saves this reference
|
||||
* for the provided protocol id.
|
||||
* <p>
|
||||
* Constraints:
|
||||
* The call of the initialization method is in general unordered. However, it is always ensured that
|
||||
* for a given binding 'from'->'to', the protocol handler for 'from' is constructed and initialized before 'to'.
|
||||
* Double bindings 'from'->'to' + 'to'->'from' _should_ be possible, but must be handled carefully (untested).
|
||||
* All bindings are performed after initialization by calling 'from'.bind('to'). All handlers are responsible
|
||||
* to take care of the concrete binding and must handle unsupported bindings appropriately.
|
||||
*
|
||||
* @see at.jku.fim.rubanetra.protocol.BaseProtocol#bind(at.jku.fim.rubanetra.protocol.BaseProtocol)
|
||||
*/
|
||||
public class KrakenProtocolConfigurationImpl implements KrakenProtocolConfiguration {
|
||||
private final PortSpecification transportLayerPortSpec;
|
||||
private final String transportLayerMappingStrategy;
|
||||
private final KrakenTransportLayerMappingFactory transportLayerMappingFactory;
|
||||
private final PcapHandler<PcapActivityListener> pcapHandler;
|
||||
private final Map<ProtocolId, KrakenBaseProtocol> registeredProtocols;
|
||||
|
||||
/**
|
||||
* keep private
|
||||
*/
|
||||
private KrakenProtocolConfigurationImpl() {
|
||||
this.pcapHandler = currentPcapHandler;
|
||||
this.transportLayerPortSpec = currentProtocolPortSpec;
|
||||
this.transportLayerMappingStrategy = currentTransportLayerStrategy;
|
||||
this.transportLayerMappingFactory = currentTransportLayerMappingFactory;
|
||||
|
||||
this.registeredProtocols = new HashMap<>();
|
||||
|
||||
check();
|
||||
log.debug("Bindings to process: {}", currentProtocolBindingMap);
|
||||
|
||||
for (ProtocolId protocolId : currentProtocolBindingMap.keySet()) {
|
||||
KrakenBaseProtocol baseProtocolFrom;
|
||||
if (registeredProtocols.containsKey(protocolId)) {
|
||||
// instance was already constructed and initialized
|
||||
baseProtocolFrom = registeredProtocols.get(protocolId);
|
||||
} else {
|
||||
// construct and initialize a new instance
|
||||
baseProtocolFrom = createBaseProtocolInstance(protocolId);
|
||||
baseProtocolFrom.initialize(this);
|
||||
// remember this instance
|
||||
registeredProtocols.put(protocolId, baseProtocolFrom);
|
||||
}
|
||||
log.debug("[BIND_FROM] ProtocolId: {}, Class: {}", protocolId, baseProtocolFrom.getClass());
|
||||
|
||||
// bind this protocol to ...
|
||||
for (ProtocolId bindToId : currentProtocolBindingMap.get(protocolId)) {
|
||||
KrakenBaseProtocol baseProtocolTo;
|
||||
if (registeredProtocols.containsKey(bindToId)) {
|
||||
// instance was already constructed and initialized
|
||||
baseProtocolTo = registeredProtocols.get(bindToId);
|
||||
} else {
|
||||
// construct and initialize a new instance
|
||||
baseProtocolTo = createBaseProtocolInstance(bindToId);
|
||||
baseProtocolTo.initialize(this);
|
||||
// remember this instance
|
||||
registeredProtocols.put(bindToId, baseProtocolTo);
|
||||
}
|
||||
|
||||
log.debug("[BIND_TO] ProtocolId: {}, Class: {}", bindToId, baseProtocolTo.getClass());
|
||||
// perform the actual binding
|
||||
baseProtocolFrom.bind(baseProtocolTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ENHANCEMENT: do not rely on the fact that there is always a default constructor
|
||||
private KrakenBaseProtocol createBaseProtocolInstance(ProtocolId protocolId) {
|
||||
IllegalStateException unknownProtocol = new IllegalStateException(String.format("Unable to instantiate a BaseProtocol class from protocol identifier: %s", protocolId));
|
||||
Class<? extends BaseProtocol> protocolClass = protocolRegistry.getRegisteredProtocolClass(protocolId);
|
||||
if (protocolClass == null) {
|
||||
throw unknownProtocol;
|
||||
}
|
||||
if (KrakenBaseProtocol.class.isAssignableFrom(protocolClass)) {
|
||||
try {
|
||||
return protocolClass.asSubclass(KrakenBaseProtocol.class).newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
log.error("Unable to instantiate protocol handler {} - does it provide a default constructor?", protocolClass, e);
|
||||
throw unknownProtocol;
|
||||
}
|
||||
} else {
|
||||
log.error("This Protocol Configuration Builder supports KrakenBaseProtocol sub-classes only.");
|
||||
throw new IllegalArgumentException("This Protocol Configuration Builder supports KrakenBaseProtocol sub-classes only.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an immutable map consisting of all protocol id to handler bindings
|
||||
*/
|
||||
public Map<ProtocolId, KrakenBaseProtocol> getBoundProtocols() {
|
||||
return Collections.unmodifiableMap(registeredProtocols);
|
||||
}
|
||||
|
||||
private void check() {
|
||||
if (transportLayerMappingFactory == null || transportLayerMappingStrategy == null || pcapHandler == null || transportLayerPortSpec == null) {
|
||||
log.error("Factory {}, strategy {}, pcapHandler {}, portSpec {}", transportLayerMappingFactory, transportLayerMappingStrategy, pcapHandler, transportLayerPortSpec);
|
||||
throw new IllegalStateException("Unable to build a KrakenProtocolConfiguration.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTransportLayerMappingStrategy() {
|
||||
return this.transportLayerMappingStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PortSpecification getPortSpecification() {
|
||||
return this.transportLayerPortSpec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PcapHandler<PcapActivityListener> getPcapHandler() {
|
||||
return this.pcapHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KrakenTransportLayerMappingFactory getTransportLayerMappingFactory() {
|
||||
return transportLayerMappingFactory;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model.impl;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration;
|
||||
import at.jku.fim.rubanetra.output.OutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.output.impl.CsvOutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.output.impl.JsonOutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.output.impl.NopOutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.output.impl.XmlOutputWriterStrategy;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A simple factory constructing {@link at.jku.fim.rubanetra.output.OutputWriterStrategy} objects
|
||||
* for a known {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.OutputFormat}
|
||||
*/
|
||||
public class OutputStrategyFactory {
|
||||
private static final Logger log = LoggerFactory.getLogger(OutputStrategyFactory.class);
|
||||
private static final NopOutputWriterStrategy nopOutputWriterStrategy = new NopOutputWriterStrategy();
|
||||
|
||||
/**
|
||||
* Returns an object capable of transforming data into the provided {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.OutputFormat}
|
||||
*
|
||||
* @param outputFormat the format to use for transforming data before writing to out
|
||||
* @param out the output stream to write to
|
||||
* @return if any provided argument is null, a {@link at.jku.fim.rubanetra.output.impl.NopOutputWriterStrategy},
|
||||
* or a capable strategy object if an appropriate class is known
|
||||
*/
|
||||
public static OutputWriterStrategy createOutputWriterStrategy(RubanetraSystemConfiguration.OutputFormat outputFormat, OutputStream out) {
|
||||
if (outputFormat == null || out == null) {
|
||||
log.warn("Unable to create a suitable OutputWriterStrategy - null argument was passed.");
|
||||
return nopOutputWriterStrategy;
|
||||
}
|
||||
|
||||
switch (outputFormat) {
|
||||
case PLASO:
|
||||
case XML:
|
||||
return new XmlOutputWriterStrategy(out);
|
||||
case JSON:
|
||||
return new JsonOutputWriterStrategy(out);
|
||||
case CSV:
|
||||
try {
|
||||
return new CsvOutputWriterStrategy(out);
|
||||
} catch (IOException e) {
|
||||
log.warn("Unable to create a suitable OutputWriterStrategy for format {}, using NOP instead", outputFormat);
|
||||
return nopOutputWriterStrategy;
|
||||
}
|
||||
case NOP:
|
||||
return nopOutputWriterStrategy;
|
||||
default:
|
||||
log.warn("Unable to create a suitable OutputWriterStrategy for format {}, using NOP instead", outputFormat);
|
||||
return nopOutputWriterStrategy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model.impl;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.BaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.handler.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A representation of a simple protocol identifier ({@link at.jku.fim.rubanetra.config.model.ProtocolId})
|
||||
* to an arbitrary {@link at.jku.fim.rubanetra.protocol.BaseProtocol} class.
|
||||
* It is expected that all registered classes provide a default constructor.
|
||||
*
|
||||
* @see at.jku.fim.rubanetra.config.model.impl.KrakenProtocolConfigurationBuilderImpl
|
||||
*/
|
||||
public class ProtocolClassRegistry {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final Map<ProtocolId, Class<? extends BaseProtocol>> protocolRegistry;
|
||||
private final Map<String, ProtocolId> protocolIdMap;
|
||||
|
||||
/**
|
||||
* create a new instance
|
||||
*/
|
||||
public ProtocolClassRegistry() {
|
||||
protocolIdMap = new HashMap<>();
|
||||
protocolRegistry = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a protocol identifier to a protocol handler class, which must provide a default constructor
|
||||
*
|
||||
* @param protocolId a protocol identifier, which should be advertised by the protocolHandlerClazz as well
|
||||
* @param protocolHandlerClazz a class that is able to parse the protocol identified by the protocol id and
|
||||
* provides a default constructor
|
||||
* @throws java.lang.IllegalArgumentException if any argument is null or the protocol id was already registered
|
||||
*/
|
||||
public void registerHandler(ProtocolId protocolId, Class<? extends BaseProtocol> protocolHandlerClazz) {
|
||||
if (protocolId == null || protocolId.getProtocolId() == null || protocolHandlerClazz == null) {
|
||||
log.error("The protocol id and the protocol handler must not be null.");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (protocolRegistry.containsKey(protocolId) || protocolIdMap.containsKey(protocolId.getProtocolId())) {
|
||||
log.error("A protocol handler for the given protocol id {} was already registered before.", protocolId);
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
log.debug("Registering {} to class {}.", protocolId, protocolHandlerClazz);
|
||||
protocolIdMap.put(protocolId.getProtocolId(), protocolId);
|
||||
protocolRegistry.put(protocolId, protocolHandlerClazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a registry record, does nothing if the protocol id was not registered
|
||||
* @param protocolId the identifier for the handler to delete from the registry
|
||||
*/
|
||||
public void unregisterHandler(ProtocolId protocolId) {
|
||||
if(protocolId!=null) {
|
||||
protocolRegistry.remove(protocolId);
|
||||
protocolIdMap.remove(protocolId.getProtocolId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the registered class for a given protocol identifier
|
||||
*
|
||||
* @param id the identifier that was registered to this registry
|
||||
* @return a class that should (unchecked) provide a default constructor and should be able to parse
|
||||
* data adhering to the protocol identified by the protocol id
|
||||
*/
|
||||
public Class<? extends BaseProtocol> getRegisteredProtocolClass(ProtocolId id) {
|
||||
return protocolRegistry.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all currently registered protocol identifiers
|
||||
*/
|
||||
public Set<ProtocolId> getRegisteredProtocolIdSet() {
|
||||
return Collections.unmodifiableSet(protocolRegistry.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all currently registered protocol handler classes (duplicates may be possible)
|
||||
*/
|
||||
public Collection<Class<? extends BaseProtocol>> getRegisteredProtocolClassList() {
|
||||
return Collections.unmodifiableCollection(protocolRegistry.values());
|
||||
}
|
||||
|
||||
private static ProtocolClassRegistry defaultKrakenProtocolRegistry;
|
||||
|
||||
/**
|
||||
* @return a default registry containing all originally known protocol ids and handlers.
|
||||
* It will never contain custom protocol handlers unless they are added explicitly afterwards.
|
||||
*/
|
||||
public static ProtocolClassRegistry createDefaultKrakenProtocolRegistry() {
|
||||
if (defaultKrakenProtocolRegistry != null) {
|
||||
return defaultKrakenProtocolRegistry;
|
||||
}
|
||||
defaultKrakenProtocolRegistry = new ProtocolClassRegistry();
|
||||
|
||||
// it would be nice to implement some kind of class auto detection mechanism (Reflection maybe?)...
|
||||
KrakenBaseProtocol[] krakenProtocolHandlers = {
|
||||
new KrakenArpHandler(),
|
||||
new KrakenEthernetProtocolHandler(),
|
||||
new KrakenIpv4Handler(),
|
||||
new KrakenIpv6Handler(),
|
||||
new KrakenIcmpv4Handler(),
|
||||
new KrakenIcmpv6Handler(),
|
||||
new KrakenTcpHandler(),
|
||||
new KrakenUdpHandler(),
|
||||
new KrakenHttpHandler(),
|
||||
new KrakenDnsProtocolHandler(),
|
||||
new KrakenMsnHandler(),
|
||||
new KrakenSmtpHandler(),
|
||||
new KrakenDhcpHandler(),
|
||||
new KrakenFtpHandler(),
|
||||
new KrakenNetbiosHandler(),
|
||||
new KrakenPop3Handler(),
|
||||
new KrakenSnmpHandler(),
|
||||
new KrakenTelnetHandler()
|
||||
};
|
||||
|
||||
for (KrakenBaseProtocol p : krakenProtocolHandlers) {
|
||||
defaultKrakenProtocolRegistry.registerHandler(p.getProtocolId(), p.getClass());
|
||||
}
|
||||
|
||||
return defaultKrakenProtocolRegistry;
|
||||
}
|
||||
}
|
||||
+402
@@ -0,0 +1,402 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model.impl;
|
||||
|
||||
import at.jku.fim.rubanetra.config.RubanetraSystemConfigurationBaseListener;
|
||||
import at.jku.fim.rubanetra.config.RubanetraSystemConfigurationLexer;
|
||||
import at.jku.fim.rubanetra.config.RubanetraSystemConfigurationParser;
|
||||
import at.jku.fim.rubanetra.config.RubanetraSystemConfigurationParser.*;
|
||||
import at.jku.fim.rubanetra.config.model.Port;
|
||||
import at.jku.fim.rubanetra.config.model.PortRange;
|
||||
import at.jku.fim.rubanetra.config.model.PortSpecification;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenTransportLayerMappingFactory;
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.misc.NotNull;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents the implementation of the listener interface that was created previously by the ANTLRv4 parser.
|
||||
* One of the first step of the system is to parse its own configuration. This implementation may be used to parse
|
||||
* all main configuration parts, i.e. input/output, protocol and Drools specific settings can be handled by this
|
||||
* class.
|
||||
* <p>
|
||||
* A {@link at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder} is mainly utilized,
|
||||
* including a {@link at.jku.fim.rubanetra.config.model.impl.KrakenProtocolConfigurationBuilderImpl}
|
||||
* to perform the construction of the main configuration that may be used to further initialize the system.
|
||||
* In order to allow further customizations this listener does not invoke the final call to
|
||||
* {@link RubanetraSystemConfigurationBuilder#create()}, therefore it is the objects instantiator's obligation to ensure
|
||||
* completeness of the configuration and the construction
|
||||
* of the {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration}.
|
||||
* <p>
|
||||
* An appropriate ANTLR parser object can be created by calling the static method {@link #createConfigurationFileParser(java.io.File)}
|
||||
* by passing a valid a configuration file.
|
||||
* The parser should then be pointed to the root node, i.e.:
|
||||
* <p>
|
||||
* {@code RubanetraSystemConfigurationParser systemConfigParser = RubanetraSystemConfigurationBaseListenerImpl.createConfigurationFileParser(mainConfigFile);}
|
||||
* {@code RubanetraSystemConfigurationParser.SystemContext systemContext = systemConfigParser.system();}
|
||||
* <p>
|
||||
* And finally a {@link org.antlr.v4.runtime.tree.ParseTreeWalker} may then be used to traverse the parse tree of the
|
||||
* general configuration:
|
||||
* <p>
|
||||
* {@code ParseTreeWalker.DEFAULT.walk(systemConfigBaseListener, systemContext.generalConfig(0));}
|
||||
*/
|
||||
public class RubanetraSystemConfigurationBaseListenerImpl extends RubanetraSystemConfigurationBaseListener {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final RubanetraSystemConfigurationBuilder systemConfigBuilder;
|
||||
private final KrakenProtocolConfigurationBuilderImpl protocolSettingBuilder;
|
||||
|
||||
/**
|
||||
* Creates a new listener instance, which may be used to react to parsing event generated by a
|
||||
* {@link at.jku.fim.rubanetra.config.RubanetraSystemConfigurationParser}.
|
||||
*
|
||||
* @param systemConfigBuilder an instance of a builder which will be used to setup the system configuration,
|
||||
* may not be null
|
||||
* @throws java.lang.IllegalArgumentException if parser errors are encountered
|
||||
*/
|
||||
public RubanetraSystemConfigurationBaseListenerImpl(RubanetraSystemConfigurationBuilder systemConfigBuilder) {
|
||||
if (systemConfigBuilder == null) {
|
||||
log.error("The passed system configuration may not be null");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.systemConfigBuilder = systemConfigBuilder;
|
||||
protocolSettingBuilder = new KrakenProtocolConfigurationBuilderImpl();
|
||||
}
|
||||
|
||||
public static RubanetraSystemConfigurationParser createConfigurationFileParser(File configurationFile) {
|
||||
final Logger log = LoggerFactory.getLogger(RubanetraSystemConfigurationParser.class);
|
||||
ANTLRFileStream fileStream;
|
||||
try {
|
||||
log.debug("Trying to create an ANTLRFileStream for file {}", configurationFile);
|
||||
fileStream = new ANTLRFileStream(configurationFile.getCanonicalPath());
|
||||
} catch (IOException e) {
|
||||
log.error("Invalid configuration file: {}", configurationFile, e);
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
log.debug("Creating a system configuration lexer.");
|
||||
RubanetraSystemConfigurationLexer systemConfigLexer = new RubanetraSystemConfigurationLexer(fileStream);
|
||||
systemConfigLexer.removeErrorListeners();
|
||||
CommonTokenStream configTokens = new CommonTokenStream(systemConfigLexer);
|
||||
log.debug("Creating a system configuration parser.");
|
||||
RubanetraSystemConfigurationParser systemConfigurationParser = new RubanetraSystemConfigurationParser(configTokens);
|
||||
systemConfigurationParser.removeErrorListeners();
|
||||
systemConfigurationParser.addErrorListener(new BaseErrorListener() {
|
||||
@Override
|
||||
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
|
||||
String sourceName = recognizer.getInputStream().getSourceName();
|
||||
if (!sourceName.isEmpty()) {
|
||||
sourceName = String.format("%s: ", sourceName);
|
||||
}
|
||||
|
||||
log.error("Configuration syntax error: {} line {}:{} {}", sourceName, line, charPositionInLine, msg);
|
||||
}
|
||||
});
|
||||
|
||||
return systemConfigurationParser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSystem(@NotNull SystemContext ctx) {
|
||||
log.debug("Entered system node");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitSystem(@NotNull SystemContext ctx) {
|
||||
// we could call systemConfigBuilder.build() here, instead the user is expected to call it
|
||||
log.debug("Exiting system node");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called by a {@link org.antlr.v4.runtime.tree.ParseTreeWalker} only if the
|
||||
* protocol configuration section was specified within the main system
|
||||
* configuration file and not in a separate file.
|
||||
*/
|
||||
@Override
|
||||
public void enterProtocolConfig(@NotNull ProtocolConfigContext ctx) {
|
||||
// Use another listener to handle the complex protocol configuration
|
||||
// settings
|
||||
//ParseTreeWalker.DEFAULT.walk(this, ctx);
|
||||
log.debug("Entered protocol config node");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterProtocolSetting(@NotNull ProtocolSettingContext ctx) {
|
||||
log.debug("Entered protocol setting node");
|
||||
ProtocolHeaderContext protocolHeaderContext = ctx.protocolHeader();
|
||||
List<PortSpecificationContext> portSpecificationContext = ctx.portSpecification();
|
||||
List<ProtocolBindingContext> protocolBindingContexts = ctx.protocolBinding();
|
||||
List<TransportLayerMappingSettingContext> mappingStrategyContexts = ctx.transportLayerMappingSetting();
|
||||
|
||||
if (protocolHeaderContext == null) {
|
||||
throw new IllegalArgumentException("Missing protocol identifier.");
|
||||
}
|
||||
String protocolIdentifier = protocolHeaderContext.protocolId().getText();
|
||||
protocolSettingBuilder.setCurrentProtocolIdentifier(protocolIdentifier);
|
||||
|
||||
if (portSpecificationContext.isEmpty()) {
|
||||
protocolSettingBuilder.setPortSpecification(PortSpecification.UniversalPortSpecification.ACCEPT_ALL);
|
||||
} else if (portSpecificationContext.size() > 1) {
|
||||
throw new IllegalArgumentException(String.format("Multiple port specifications encountered, but only one is permitted (protocol setting: %s)", protocolIdentifier));
|
||||
|
||||
} else {
|
||||
portSpecificationContext.get(0).enterRule(this);
|
||||
}
|
||||
|
||||
for (ProtocolBindingContext bindingContext : protocolBindingContexts) {
|
||||
List<ProtocolIdContext> protocolIdContexts = bindingContext.protocolId();
|
||||
if (protocolIdContexts.size() != 2)
|
||||
throw new IllegalArgumentException(String.format("Invalid protocol binding encountered (protocol setting: %s, binding: %s)", protocolIdentifier, protocolIdContexts));
|
||||
protocolSettingBuilder.bindProtocol(bindingContext.protocolId(0).ID().getText(), bindingContext.protocolId(1).ID().getText());
|
||||
}
|
||||
|
||||
protocolSettingBuilder.setTransportProtocolMappingFactory(systemConfigBuilder.getTransportLayerMappingFactory());
|
||||
if (mappingStrategyContexts.isEmpty()) {
|
||||
protocolSettingBuilder.setTransportProtocolMappingStrategy(KrakenTransportLayerMappingFactory.DESTINATION_PORT_STRATEGY);
|
||||
} else if (mappingStrategyContexts.size() > 1) {
|
||||
throw new IllegalArgumentException(String.format("Multiple transport layer mapping strategies encountered (protocol setting: %s, binding: %s)", protocolIdentifier, mappingStrategyContexts));
|
||||
} else {
|
||||
protocolSettingBuilder.setTransportProtocolMappingStrategy(mappingStrategyContexts.get(0).transportLayerMappingStrategy().getText().toUpperCase());
|
||||
}
|
||||
|
||||
protocolSettingBuilder.setPcapHandler(systemConfigBuilder.getPcapHandler());
|
||||
systemConfigBuilder.addProtocolSetting(protocolSettingBuilder.buildProtocolConfiguration());
|
||||
protocolSettingBuilder.resetCurrentProtocolConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterPortSpecification(@NotNull PortSpecificationContext ctx) {
|
||||
PortSpecification portSpec;
|
||||
if (ctx.ALL() != null) {
|
||||
portSpec = PortSpecification.UniversalPortSpecification.ACCEPT_ALL;
|
||||
} else if (ctx.NONE() != null) {
|
||||
portSpec = PortSpecification.UniversalPortSpecification.REJECT_ALL;
|
||||
} else {
|
||||
portSpec = new PortSpecification();
|
||||
}
|
||||
|
||||
MultiplePortsContext multiplePortsContext = ctx.multiplePorts();
|
||||
if (multiplePortsContext != null) {
|
||||
for (PortRangeContext portRangeContext : multiplePortsContext.portRange()) {
|
||||
List<SinglePortContext> singlePortContexts = portRangeContext.singlePort();
|
||||
switch (singlePortContexts.size()) {
|
||||
case 1:
|
||||
portSpec.add(parsePortNumber(singlePortContexts.get(0)));
|
||||
break;
|
||||
case 2:
|
||||
portSpec.add(parsePortRange(singlePortContexts.get(0), singlePortContexts.get(1)));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid port specification encountered");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protocolSettingBuilder.setPortSpecification(portSpec);
|
||||
}
|
||||
|
||||
private PortRange parsePortRange(SinglePortContext portContextA, SinglePortContext portContextB) {
|
||||
Port lowerPort, upperPort;
|
||||
lowerPort = parsePortNumber(portContextA);
|
||||
upperPort = parsePortNumber(portContextB);
|
||||
if (lowerPort.compareTo(upperPort) > 0) {
|
||||
Port tmpPort = lowerPort;
|
||||
lowerPort = upperPort;
|
||||
upperPort = tmpPort;
|
||||
}
|
||||
|
||||
return new PortRange(lowerPort, upperPort);
|
||||
}
|
||||
|
||||
private Port parsePortNumber(SinglePortContext singlePortContext) {
|
||||
return Port.create(Integer.parseUnsignedInt(singlePortContext.INT().getText()));
|
||||
}
|
||||
|
||||
/**
|
||||
* **********************************************************************
|
||||
* General configuration options will be parsed by the following methods.
|
||||
* Semantic checks will be performed by the
|
||||
* {@link at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder} only.
|
||||
* **********************************************************************
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void enterBpfFilterString(@NotNull BpfFilterStringContext ctx) {
|
||||
String bpfFilter = unquoteString(ctx.STRING().getText());
|
||||
// syntax check will be performed by the native BPF compiler
|
||||
systemConfigBuilder.setBpfFilter(bpfFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterBpfNetmask(@NotNull BpfNetmaskContext ctx) {
|
||||
int bpfNetmask = Integer.parseUnsignedInt(ctx.INT().getText());
|
||||
systemConfigBuilder.setBpfNetmask(bpfNetmask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterBpfOptimize(@NotNull BpfOptimizeContext ctx) {
|
||||
boolean bpfOptimize = false;
|
||||
if (ctx.TRUE() != null) {
|
||||
bpfOptimize = true;
|
||||
}
|
||||
systemConfigBuilder.setBpfOptimize(bpfOptimize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterDroolsBaseModelName(@NotNull DroolsBaseModelNameContext ctx) {
|
||||
String droolsBaseModelName = unquoteString(ctx.getText());
|
||||
systemConfigBuilder.setDroolsBaseModelName(droolsBaseModelName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterDroolsSessionModelName(@NotNull DroolsSessionModelNameContext ctx) {
|
||||
String droolsSessionModelName = unquoteString(ctx.getText());
|
||||
systemConfigBuilder.setDroolsSessionModelName(droolsSessionModelName);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called by a {@link org.antlr.v4.runtime.tree.ParseTreeWalker} only if the
|
||||
* optional protocol configuration file setting was specified by the user in
|
||||
* the main system configuration file. It will be assumed that there will
|
||||
* not follow a separate protocol configuration section within the main
|
||||
* configuration file, i.e. the
|
||||
* {@link #enterProtocolConfig(at.jku.fim.rubanetra.config.RubanetraSystemConfigurationParser.ProtocolConfigContext)} will not be called by
|
||||
* the {@link org.antlr.v4.runtime.tree.ParseTreeWalker} (otherwise the user has specified two
|
||||
* separate protocol configuration sections, one within the main system
|
||||
* configuration and one in a different file, which is not allowed).
|
||||
*/
|
||||
@Override
|
||||
public void enterProtocolConfigurationFileSetting(@NotNull ProtocolConfigurationFileSettingContext ctx) {
|
||||
String protocolConfigurationString = unquoteString(ctx.filePath().getText());
|
||||
// check file path syntax, i.e. an InvalidPathException may be thrown
|
||||
systemConfigBuilder.setProtocolConfigurationPath(protocolConfigurationString);
|
||||
|
||||
RubanetraSystemConfigurationParser protocolConfigParser = createConfigurationFileParser(systemConfigBuilder.getProtocolConfigurationFile());
|
||||
ParseTree parseTree = protocolConfigParser.protocolConfig(); // begin parsing at the protocol configuration node
|
||||
|
||||
if (parseTree == null) {
|
||||
throw new IllegalArgumentException("The specified protocol configuration file does not contain the protocol configuration section");
|
||||
}
|
||||
|
||||
ParseTreeWalker.DEFAULT.walk(this, parseTree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterDroolsConfigurationFile(@NotNull DroolsConfigurationFileContext ctx) {
|
||||
String droolsConfigurationString = unquoteString(ctx.filePath().getText());
|
||||
systemConfigBuilder.setDroolsConfigurationPath(droolsConfigurationString);
|
||||
|
||||
// we do not need to parse the drools configuration file, due to the already included Drools Parser (also based on ANTLR)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterInputConfigurationFileSetting(@NotNull InputConfigurationFileSettingContext ctx) {
|
||||
String inputConfigurationString = unquoteString(ctx.filePath().getText());
|
||||
systemConfigBuilder.setInputConfigurationPath(inputConfigurationString);
|
||||
|
||||
RubanetraSystemConfigurationParser inputConfigurationParser = createConfigurationFileParser(systemConfigBuilder.getInputConfigurationFile());
|
||||
ParseTree inputConfigurationParseTree = inputConfigurationParser.inputConfig();
|
||||
|
||||
if (inputConfigurationParseTree == null) {
|
||||
throw new IllegalArgumentException("The specified input configuration file does not contain the input configuration section");
|
||||
}
|
||||
|
||||
ParseTreeWalker.DEFAULT.walk(this, inputConfigurationParseTree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterOutputConfigurationFileSetting(@NotNull OutputConfigurationFileSettingContext ctx) {
|
||||
String outputConfigurationString = unquoteString(ctx.filePath().getText());
|
||||
systemConfigBuilder.setOutputConfigurationPath(outputConfigurationString);
|
||||
|
||||
RubanetraSystemConfigurationParser outputConfigurationParser = createConfigurationFileParser(systemConfigBuilder.getOutputConfigurationFile());
|
||||
ParseTree outputConfigurationParseTree = outputConfigurationParser.outputConfig();
|
||||
|
||||
if (outputConfigurationParseTree == null) {
|
||||
throw new IllegalArgumentException("The specified output configuration file does not contain the output configuration section");
|
||||
}
|
||||
|
||||
ParseTreeWalker.DEFAULT.walk(this, outputConfigurationParseTree);
|
||||
}
|
||||
|
||||
/**
|
||||
* **********************************************************************
|
||||
* Dynamic I/O configuration options will be parsed by the following methods.
|
||||
* Semantic checks will be performed by the
|
||||
* {@link at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder} only.
|
||||
* **********************************************************************
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void exitInputConfig(@NotNull InputConfigContext ctx) {
|
||||
// systemConfigBuilder.createPcapHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterInputSpecification(@NotNull InputSpecificationContext ctx) {
|
||||
List<FilePathContext> filePathContexts = ctx.filePath();
|
||||
if (filePathContexts == null || filePathContexts.isEmpty()) {
|
||||
throw new IllegalArgumentException("At least one input file must be specified.");
|
||||
}
|
||||
|
||||
for (FilePathContext f : filePathContexts) {
|
||||
systemConfigBuilder.addInputPath(unquoteString(f.getText()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterInputFormat(@NotNull InputFormatContext ctx) {
|
||||
systemConfigBuilder.setInputFormat(ctx.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSortByFirstTimestamp(@NotNull SortByFirstTimestampContext ctx) {
|
||||
systemConfigBuilder.setSortByFirstTimestamp(ctx.TRUE()!=null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterOutputSpecification(@NotNull OutputSpecificationContext ctx) {
|
||||
if (ctx.STDOUT() != null) {
|
||||
systemConfigBuilder.setOutputStream(System.out);
|
||||
} else {
|
||||
systemConfigBuilder.setOutputFile(unquoteString(ctx.filePath().getText()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterOutputFormat(@NotNull OutputFormatContext ctx) {
|
||||
systemConfigBuilder.setOutputFormat(ctx.getText());
|
||||
}
|
||||
|
||||
private static String unquoteString(String quotedString) {
|
||||
if (quotedString == null || quotedString.length() < 2) {
|
||||
return quotedString;
|
||||
}
|
||||
if (quotedString.startsWith("\"") && quotedString.endsWith("\"")) {
|
||||
return quotedString.substring(1, quotedString.length() - 1);
|
||||
}
|
||||
|
||||
return quotedString;
|
||||
}
|
||||
}
|
||||
+666
@@ -0,0 +1,666 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.config.model.impl;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.OutputFormat;
|
||||
import at.jku.fim.rubanetra.drools.DroolsKnowledgeBaseFactory;
|
||||
import at.jku.fim.rubanetra.output.OutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivityListener;
|
||||
import at.jku.fim.rubanetra.pcap.PcapFileHandler;
|
||||
import at.jku.fim.rubanetra.pcap.PcapFilter;
|
||||
import at.jku.fim.rubanetra.pcap.PcapHandler;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenTransportLayerMappingFactory;
|
||||
import org.kie.api.runtime.KieContainer;
|
||||
import org.kie.api.runtime.KieSession;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.InputFormat;
|
||||
|
||||
/**
|
||||
* This class may be used to setup the essential configuration of the Drools rule engine, the JNetPcap file parser
|
||||
* including optional Berkeley Packet Filter support, the Kraken Pcap and network protocol parser, and finally
|
||||
* general input and output options.
|
||||
* The builder produces a {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration} implementation,
|
||||
* that may be used to create a {@link at.jku.fim.rubanetra.drools.DroolsKrakenProtocolHandler}
|
||||
* which in turn is capable of managing the interaction of the Drools rule engine and the Kraken protocol decoder.
|
||||
*
|
||||
* @see at.jku.fim.rubanetra.drools.DroolsKrakenProtocolHandler
|
||||
* @see at.jku.fim.rubanetra.config.ConfigurationController
|
||||
* @see at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder.RubanetraSystemConfigurationImpl
|
||||
* @see at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBaseListenerImpl
|
||||
*/
|
||||
public class RubanetraSystemConfigurationBuilder {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* The system configuration may be split up into several files (optional)
|
||||
*/
|
||||
private File protocolConfigurationFile;
|
||||
private File droolsConfigurationFile;
|
||||
private File inputConfigurationFile;
|
||||
private File outputConfigurationFile;
|
||||
|
||||
/**
|
||||
* The set of files containing the captured network packets
|
||||
*/
|
||||
private final Set<File> inputFiles;
|
||||
|
||||
/**
|
||||
* The general format of the files containing the network traffic dumps (usually Pcap)
|
||||
*/
|
||||
private InputFormat inputFormat;
|
||||
/**
|
||||
* The output stream to write to, this stream should be closed by calling
|
||||
* {@link at.jku.fim.rubanetra.output.OutputWriterStrategy#closeWriter()}
|
||||
*/
|
||||
private OutputStream outputStream;
|
||||
/**
|
||||
* The general format of the produced output, defines the transform to apply before the dumping process
|
||||
*/
|
||||
private OutputFormat outputFormat;
|
||||
/**
|
||||
* The strategy defining the final data representation and performs the actual writing task
|
||||
*/
|
||||
private OutputWriterStrategy outputWriterStrategy;
|
||||
/**
|
||||
* The Pcap data input stream, which will parse the inputFiles and compile/apply the BPF filter
|
||||
*/
|
||||
private PcapFileHandler<PcapActivityListener> pcapHandler;
|
||||
|
||||
private String bpfFilter;
|
||||
private boolean bpfOptimize = false;
|
||||
private int bpfNetmask = 0;
|
||||
/**
|
||||
* Kraken library specific settings
|
||||
*/
|
||||
private final KrakenTransportLayerMappingFactory transportLayerMappingFactory;
|
||||
|
||||
private final Set<KrakenProtocolConfiguration> protocolSettings;
|
||||
/**
|
||||
* Drools rule engine specific settings
|
||||
*/
|
||||
private String droolsBaseModelName;
|
||||
|
||||
private String droolsSessionModelName;
|
||||
private boolean sortByFirstTimestamp;
|
||||
private RubanetraSystemConfigurationBuilder() {
|
||||
// keep private to prevent public instantiation
|
||||
this.protocolSettings = new HashSet<>();
|
||||
this.inputFiles = new LinkedHashSet<>();
|
||||
this.transportLayerMappingFactory = KrakenTransportLayerMappingFactory.createDefaultKrakenTransportLayerMappingFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new instance of the {@link at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder}
|
||||
*/
|
||||
public static RubanetraSystemConfigurationBuilder create() {
|
||||
return new RubanetraSystemConfigurationBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently configured Pcap handler or null
|
||||
*/
|
||||
public PcapFileHandler<PcapActivityListener> getPcapHandler() {
|
||||
return pcapHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be the last method called, i.e. after all the settings have been defined. This method will finalize
|
||||
* the configuration, perform several validations and checks, create a {@link at.jku.fim.rubanetra.pcap.PcapFileHandler}
|
||||
* (if it was not defined already) and return an immutable implementation of the system configuration itself.
|
||||
* <p>
|
||||
* This method will throw exceptions if invalid settings are encountered.
|
||||
*
|
||||
* @return an immutable, finalized configuration instance, which may be passed to a {@link at.jku.fim.rubanetra.drools.DroolsKrakenProtocolHandler}
|
||||
* @see at.jku.fim.rubanetra.config.model.impl.RubanetraSystemConfigurationBuilder.RubanetraSystemConfigurationImpl
|
||||
* @see at.jku.fim.rubanetra.drools.DroolsKrakenProtocolHandler
|
||||
*/
|
||||
public synchronized RubanetraSystemConfiguration build() {
|
||||
if (pcapHandler == null) {
|
||||
createPcapHandler();
|
||||
}
|
||||
return new RubanetraSystemConfigurationImpl(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and sets a {@link at.jku.fim.rubanetra.pcap.PcapHandler} using all already defined
|
||||
* input files, see {@link #addInputPath(String)}. Unless called before invoking {@link #build()}, this method
|
||||
* will be called during the final build automatically.
|
||||
*
|
||||
* @return a PcapHandler using already defined input files
|
||||
* @throws java.lang.IllegalStateException if this method was called more than once
|
||||
*/
|
||||
public PcapHandler<PcapActivityListener> createPcapHandler() {
|
||||
if (this.pcapHandler != null) {
|
||||
throw new IllegalStateException("A PcapHandler has already been built.");
|
||||
}
|
||||
|
||||
final File[] pcapFiles = inputFiles.toArray(new File[inputFiles.size()]);
|
||||
if (this.bpfFilter != null) {
|
||||
PcapFilter bpfFilter = new PcapFilter(this.bpfFilter, this.bpfOptimize, this.bpfNetmask);
|
||||
this.pcapHandler = new PcapFileHandler<>(bpfFilter, sortByFirstTimestamp, pcapFiles);
|
||||
} else {
|
||||
this.pcapHandler = new PcapFileHandler<>(sortByFirstTimestamp, pcapFiles);
|
||||
}
|
||||
|
||||
return this.pcapHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a Berkeley Packet Filter expression.
|
||||
* Some examples are available at http://www.tcpdump.org/manpages/pcap-filter.7.html
|
||||
* See also Steven McCanne and Van Jacobson paper
|
||||
* 'The BSD packet filter: A New Architecture for User-level Packet Capture',
|
||||
* in USENIX Winter 1993 Conference Proceedings
|
||||
* <p>
|
||||
* This setting is optional.
|
||||
*
|
||||
* @param bpfFilter a String constituting a Berkeley Packet Filter which will be compiled by JNetPcap/libpcap
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setBpfFilter(String bpfFilter) {
|
||||
if (this.pcapHandler != null) {
|
||||
throw new IllegalStateException("A PcapHandler has already been built.");
|
||||
}
|
||||
this.bpfFilter = bpfFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not to try to optimize the given BPF expression, default: false
|
||||
* <p>
|
||||
* This setting is optional.
|
||||
*
|
||||
* @param bpfOptimize true, iff the compiler should try to optimize the expression
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setBpfOptimize(boolean bpfOptimize) {
|
||||
if (this.pcapHandler != null) {
|
||||
throw new IllegalStateException("A PcapHandler has already been built.");
|
||||
}
|
||||
this.bpfOptimize = bpfOptimize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the BPF netmask, default: 0
|
||||
* <p>
|
||||
* This setting is optional.
|
||||
*
|
||||
* @param bpfNetmask the BPF netmask to use
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setBpfNetmask(int bpfNetmask) {
|
||||
if (this.pcapHandler != null) {
|
||||
throw new IllegalStateException("A PcapHandler has already been built.");
|
||||
}
|
||||
this.bpfNetmask = bpfNetmask;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Every Drools knowledge base is identified by a name, this name must be specified only if the default
|
||||
* knowledge base as specified in the Drools configuration file ('kmodule.xml') should not be used.
|
||||
* See http://drools.jboss.org/documentation.
|
||||
* <p>
|
||||
* This setting is optional.
|
||||
*
|
||||
* @param droolsBaseModelName the Drools knowledge base to use for fact insertion and deduction
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setDroolsBaseModelName(String droolsBaseModelName) {
|
||||
this.droolsBaseModelName = droolsBaseModelName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Every drools knowledge base may define several {@link org.kie.api.runtime.KieSession}s,
|
||||
* this parameter must be specified if the default KieSession as specified in the Drools configuration
|
||||
* file ('kmodule.xml') should not be used. See http://drools.jboss.org/documentation.
|
||||
* <p>
|
||||
* This setting is optional.
|
||||
*
|
||||
* @param droolsSessionModelName the Drools session to use for fact insertion and deduction
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setDroolsSessionModelName(String droolsSessionModelName) {
|
||||
this.droolsSessionModelName = droolsSessionModelName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path of the file containing the protocol configuration. The file must exist and be readable.
|
||||
* <p>
|
||||
* This setting is mandatory.
|
||||
*
|
||||
* @param protocolConfigurationPath the path of the file containing the protocol configuration
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setProtocolConfigurationPath(String protocolConfigurationPath) {
|
||||
protocolConfigurationFile = canonicalizeFilePath(protocolConfigurationPath);
|
||||
checkFileReadable(protocolConfigurationFile);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path of the directory containing the drools configuration directory. The directory must contain a 'META-INF'
|
||||
* directory and the file 'kmodule.xml', i.e. 'META-INF/kmodule.xml', as well as 'META-INF/pom.properties' because
|
||||
* Drools apparently expects the knowledge base to reside inside a JAR archive. The creation of a JAR archive for
|
||||
* every change to the rule base is not possible for this
|
||||
* systems use-case, due to the design goal that changes to the knowledge base are both
|
||||
* convenient and easy to perform from a users perspective. The alternative to this approach is to programmatically
|
||||
* define the Drools knowledge base which is currently not feasible.
|
||||
* <p>
|
||||
* ENHANCEMENT: This will probably change in the future,
|
||||
* as soon as a new way to define the knowledge base is found.
|
||||
* <p>
|
||||
* This setting is mandatory.
|
||||
*
|
||||
* @param droolsConfigurationString the path of the directory representing the Drools configuration structure
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setDroolsConfigurationPath(String droolsConfigurationString) {
|
||||
this.droolsConfigurationFile = canonicalizeFilePath(droolsConfigurationString);
|
||||
checkFileReadable(this.droolsConfigurationFile);
|
||||
if (!droolsConfigurationFile.isDirectory()) {
|
||||
throw new IllegalArgumentException("The drools configuration file must represent a directory (containing ./META-INF/kmodule.xml).");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path of the file containing the input configuration. The file must exist and be readable.
|
||||
* <p>
|
||||
* This setting is mandatory.
|
||||
*
|
||||
* @param inputConfigurationString the path of the file containing the input configuration
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setInputConfigurationPath(String inputConfigurationString) {
|
||||
this.inputConfigurationFile = canonicalizeFilePath(inputConfigurationString);
|
||||
checkFileReadable(this.inputConfigurationFile);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path of the file containing the output configuration, this file must exist and be readable.
|
||||
* <p>
|
||||
* This setting is mandatory.
|
||||
*
|
||||
* @param outputConfigurationString the path of the file containing the output configuration
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setOutputConfigurationPath(String outputConfigurationString) {
|
||||
outputConfigurationFile = canonicalizeFilePath(outputConfigurationString);
|
||||
checkFileReadable(outputConfigurationFile);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main output stream for writing the derived and parsed information to. A {@link at.jku.fim.rubanetra.output.OutputWriterStrategy}
|
||||
* performs the actual writing process and transformation.
|
||||
* <p>
|
||||
* This setting is mandatory
|
||||
*
|
||||
* @param out the output stream to use, may not be null
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setOutputStream(OutputStream out) {
|
||||
if (out == null) {
|
||||
throw new IllegalArgumentException("Invalid output stream");
|
||||
}
|
||||
this.outputStream = out;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for {@link #setOutputStream(java.io.OutputStream)}, i.e. it takes a file path
|
||||
* and sets the output stream setting.
|
||||
* The specified file must be writable.
|
||||
* <p>
|
||||
* This setting is optional and replaces the obligation to call {@link #setOutputStream(java.io.OutputStream)}
|
||||
*
|
||||
* @param outputPath the path depicting a file to write to
|
||||
*/
|
||||
public void setOutputFile(String outputPath) {
|
||||
File outputFile = canonicalizeFilePath(outputPath);
|
||||
|
||||
if (outputFile.isDirectory()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
if(outputFile.exists()) {
|
||||
log.warn("Output file {} exists, it will be overwritten.", outputFile.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
setOutputStream(new FileOutputStream(outputFile));
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IllegalArgumentException("Invalid output file, is it writable?");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.OutputFormat} to use
|
||||
* for transforming the written output before it is written.
|
||||
* <p>
|
||||
* This setting is mandatory.
|
||||
*
|
||||
* @param parsedOutputFormat the output format to use as serialization representation
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setOutputFormat(String parsedOutputFormat) {
|
||||
if (parsedOutputFormat == null) {
|
||||
throw new IllegalArgumentException("Invalid output format.");
|
||||
} else {
|
||||
OutputFormat outputFormat = OutputFormat.valueOf(trimAndCapitalize(parsedOutputFormat));
|
||||
if (outputFormat == null) {
|
||||
throw new IllegalArgumentException(String.format("Unknown output format, %s)", parsedOutputFormat));
|
||||
} else {
|
||||
this.outputFormat = outputFormat;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy used to control the serialization process.
|
||||
* <p>
|
||||
* This setting is mandatory.
|
||||
*
|
||||
* @param outputWriter the strategy to use
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setOutputWriterStrategy(OutputWriterStrategy outputWriter) {
|
||||
if (outputWriter == null) {
|
||||
throw new IllegalArgumentException("OutputWriter must not be null.");
|
||||
}
|
||||
|
||||
this.outputWriterStrategy = outputWriter;
|
||||
return this;
|
||||
}
|
||||
|
||||
private String trimAndCapitalize(String aString) {
|
||||
return aString.trim().toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file-path of a readable file containing data adhering to the specified {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.InputFormat}
|
||||
* to the list of files that are to be parsed.
|
||||
* Please note that a input file handler {@link #createPcapHandler()} must not be created before adding all
|
||||
* required input files.
|
||||
* <p>
|
||||
* This setting is optional.
|
||||
*
|
||||
* @param inputPath a readable file containing data adhering to the configured input format (unchecked)
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder addInputPath(String inputPath) {
|
||||
if (this.pcapHandler != null) {
|
||||
throw new IllegalStateException("A PcapHandler has already been built.");
|
||||
}
|
||||
File inputFile = canonicalizeFilePath(inputPath);
|
||||
checkFileReadable(inputFile);
|
||||
if (inputFiles.contains(inputFile)) {
|
||||
throw new IllegalArgumentException(String.format("Duplicate input file: %s", inputFile));
|
||||
}
|
||||
this.inputFiles.add(inputFile);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag that specifies whether or not the Pcap file handler should sort the input files according
|
||||
* to the chronological order of their first PCAP entry.
|
||||
* @param sortByFirstTimestamp true, iff the first timestamp of each file entry should be used for specifying
|
||||
* the order of the input files.
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setSortByFirstTimestamp(boolean sortByFirstTimestamp) {
|
||||
if (this.pcapHandler != null) {
|
||||
throw new IllegalStateException("A PcapHandler has already been built.");
|
||||
}
|
||||
this.sortByFirstTimestamp = sortByFirstTimestamp;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the format/type of the input files to parse. Only a single common type is allowed, i.e. format mixing
|
||||
* is currently not implemented.
|
||||
* <p>
|
||||
* This setting is mandatory.
|
||||
*
|
||||
* @param parsedInputFormat the {@link at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration.InputFormat}
|
||||
* of the input files to parse
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder setInputFormat(String parsedInputFormat) {
|
||||
if (parsedInputFormat == null) {
|
||||
throw new IllegalArgumentException("Invalid input format.");
|
||||
} else {
|
||||
InputFormat inputFormat = InputFormat.valueOf(trimAndCapitalize(parsedInputFormat));
|
||||
if (inputFormat == null) {
|
||||
throw new IllegalArgumentException(String.format("Unknown input format, %s)", parsedInputFormat));
|
||||
} else {
|
||||
this.inputFormat = inputFormat;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void checkFileReadable(File file) {
|
||||
if (!file.canRead()) {
|
||||
log.warn(String.format("The specified file (%s) is not readable.", file));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a concrete protocol configuration to the system's configuration.
|
||||
* It is assumed that the object has finished all required protocol handler bindings and initialization steps.
|
||||
* <p>
|
||||
* This setting is optional.
|
||||
*
|
||||
* @param setting the protocol configuration to add as a system setting
|
||||
* @return the builder instance
|
||||
*/
|
||||
public RubanetraSystemConfigurationBuilder addProtocolSetting(KrakenProtocolConfiguration setting) {
|
||||
this.protocolSettings.add(setting);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently configured protocol configuration file
|
||||
*/
|
||||
public File getProtocolConfigurationFile() {
|
||||
return protocolConfigurationFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently configured directory containing the Drools configuration structure
|
||||
*/
|
||||
public File getDroolsConfigurationFile() {
|
||||
return droolsConfigurationFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently configured input configuration file
|
||||
*/
|
||||
public File getInputConfigurationFile() {
|
||||
return inputConfigurationFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently configured output configuration file
|
||||
*/
|
||||
public File getOutputConfigurationFile() {
|
||||
return outputConfigurationFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the currently configured transport layer mapping factory
|
||||
*/
|
||||
public KrakenTransportLayerMappingFactory getTransportLayerMappingFactory() {
|
||||
return transportLayerMappingFactory;
|
||||
}
|
||||
|
||||
private File canonicalizeFilePath(String filePath) {
|
||||
if (filePath == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
log.debug("Trying to locate and canonicalize file path {}", filePath);
|
||||
File canonicalFile;
|
||||
|
||||
URL resourceUrl = ClassLoader.getSystemResource(filePath);
|
||||
try {
|
||||
if (resourceUrl == null) {
|
||||
log.debug("Could not locate {} in the classpath, interpreting as real path", filePath);
|
||||
canonicalFile = new File(filePath).getCanonicalFile();
|
||||
} else {
|
||||
log.debug("Located {} in the classpath", filePath);
|
||||
canonicalFile = new File(resourceUrl.toURI()).getCanonicalFile();
|
||||
}
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
throw new IllegalArgumentException(String.format("The specified path (%s) cannot be canonicalized.", filePath));
|
||||
}
|
||||
|
||||
return canonicalFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class represents the actual immutable system configuration
|
||||
*/
|
||||
public Set<File> getInputFiles() {
|
||||
return inputFiles;
|
||||
}
|
||||
|
||||
public InputFormat getInputFormat() {
|
||||
return inputFormat;
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
public OutputFormat getOutputFormat() {
|
||||
return outputFormat;
|
||||
}
|
||||
|
||||
public String getBpfFilter() {
|
||||
return bpfFilter;
|
||||
}
|
||||
|
||||
public boolean isBpfOptimize() {
|
||||
return bpfOptimize;
|
||||
}
|
||||
|
||||
public int getBpfNetmask() {
|
||||
return bpfNetmask;
|
||||
}
|
||||
|
||||
public String getDroolsBaseModelName() {
|
||||
return droolsBaseModelName;
|
||||
}
|
||||
|
||||
public String getDroolsSessionModelName() {
|
||||
return droolsSessionModelName;
|
||||
}
|
||||
|
||||
public boolean isSortByFirstTimestamp() {
|
||||
return sortByFirstTimestamp;
|
||||
}
|
||||
|
||||
private final class RubanetraSystemConfigurationImpl implements RubanetraSystemConfiguration {
|
||||
private final Set<KrakenProtocolConfiguration> protocolSettings;
|
||||
private final PcapFileHandler<?> pcapHandler;
|
||||
private final Set<File> inputFiles;
|
||||
private final InputFormat inputFormat;
|
||||
private final OutputFormat outputFormat;
|
||||
private final OutputStream outputStream;
|
||||
private final OutputWriterStrategy outputWriterStrategy;
|
||||
private final KieSession kieSession;
|
||||
|
||||
/**
|
||||
* only the surrounding builder should create instances of this class
|
||||
*/
|
||||
private RubanetraSystemConfigurationImpl(RubanetraSystemConfigurationBuilder builder) {
|
||||
this.protocolSettings = Collections.unmodifiableSet(builder.protocolSettings);
|
||||
this.inputFiles = Collections.unmodifiableSet(builder.inputFiles);
|
||||
this.pcapHandler = builder.pcapHandler;
|
||||
this.inputFormat = builder.inputFormat;
|
||||
this.outputStream = builder.outputStream;
|
||||
this.outputFormat = builder.outputFormat;
|
||||
this.outputWriterStrategy = builder.outputWriterStrategy != null ? builder.outputWriterStrategy : OutputStrategyFactory.createOutputWriterStrategy(outputFormat, outputStream);
|
||||
KieContainer kContainer = DroolsKnowledgeBaseFactory.createKieContainer(builder.droolsConfigurationFile);
|
||||
this.kieSession = DroolsKnowledgeBaseFactory.createKieSession(kContainer, builder.droolsBaseModelName, builder.droolsSessionModelName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputFormat getOutputFormat() {
|
||||
return outputFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<KrakenProtocolConfiguration> getProtocolSettings() {
|
||||
return Collections.unmodifiableSet(protocolSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PcapFileHandler<?> getPcapHandler() {
|
||||
return pcapHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KieSession getKieSession() {
|
||||
return kieSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<File> getInputFiles() {
|
||||
return inputFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputFormat getInputFormat() {
|
||||
return inputFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputWriterStrategy getOutputWriterStrategy() {
|
||||
return outputWriterStrategy;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.drools;
|
||||
|
||||
|
||||
import org.kie.api.KieServices;
|
||||
import org.kie.api.builder.KieFileSystem;
|
||||
import org.kie.api.builder.KieModule;
|
||||
import org.kie.api.builder.KieRepository;
|
||||
import org.kie.api.builder.model.KieBaseModel;
|
||||
import org.kie.api.builder.model.KieModuleModel;
|
||||
import org.kie.api.builder.model.KieSessionModel;
|
||||
import org.kie.api.builder.model.KieSessionModel.KieSessionType;
|
||||
import org.kie.api.conf.EqualityBehaviorOption;
|
||||
import org.kie.api.conf.EventProcessingOption;
|
||||
import org.kie.api.io.Resource;
|
||||
import org.kie.api.runtime.KieContainer;
|
||||
import org.kie.api.runtime.KieSession;
|
||||
import org.kie.api.runtime.conf.ClockTypeOption;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* This factory may be used to create instances of a {@link org.kie.api.runtime.KieSession} and/or
|
||||
* {@link org.kie.api.runtime.KieContainer}.
|
||||
* Several default values were defined to correspond to the default options used by this framework, e.g.
|
||||
* a {@link org.kie.api.builder.model.KieSessionModel.KieSessionType#STATEFUL} session, a pseudo {@link org.kie.api.runtime.conf.ClockTypeOption}
|
||||
* and the event stream options are currently used for this purpose.
|
||||
*
|
||||
* For extended documentation of the used classes and default values, please refer to the Drools documentation at
|
||||
* http://drools.jboss.org/documentation
|
||||
*/
|
||||
public class DroolsKnowledgeBaseFactory {
|
||||
/**
|
||||
* The default session is a stateful one
|
||||
*/
|
||||
public static final KieSessionType DEFAULT_KNOWLEDGE_SESSION_TYPE = KieSessionType.STATEFUL;
|
||||
/**
|
||||
* The default type of the rule engines session clock is a pseudo clock, see
|
||||
* https://docs.jboss.org/drools/release/6.0.1.Final/drools-docs/html/DroolsComplexEventProcessingChapter.html#d0e10068
|
||||
*/
|
||||
public static final ClockTypeOption DEFAULT_CLOCK_TYPE = ClockTypeOption.get("pseudo");
|
||||
/**
|
||||
* The default processing mode is stream mode, since reasoning over time based events should be enabled
|
||||
*/
|
||||
public static final EventProcessingOption DEFAULT_EVENT_PROCESSING = EventProcessingOption.STREAM;
|
||||
public static final EqualityBehaviorOption DEFAULT_EQUALS_BEHAVIOUR = EqualityBehaviorOption.EQUALITY;
|
||||
|
||||
/**
|
||||
* Creates a {@link org.kie.api.runtime.KieContainer} for all the knowledge bases found in the provided
|
||||
* directory. If the provided argument is null, a default classpath container will be returned.
|
||||
* <p>
|
||||
* ENHANCEMENT: This method expects to find a knowledge base descriptor file, 'kmodule.xml' in the provided
|
||||
* directory's sub-directory 'META-INF' among a maven project reference file ('pom.properties' and 'pom.xml', for
|
||||
* Drools {@link org.kie.api.builder.ReleaseId}).
|
||||
* This is inconvenient and a better way should exist to define it programmatically?
|
||||
*
|
||||
* @param knowledgeBaseDir the directory containing the the Drools knowledge base. When null is passed, the default
|
||||
* classpath container will be returned.
|
||||
* @return The container for all knowledge bases found in the provided directory.
|
||||
*/
|
||||
public static KieContainer createKieContainer(File knowledgeBaseDir) {
|
||||
KieServices kServices = KieServices.Factory.get();
|
||||
if (knowledgeBaseDir == null) {
|
||||
return kServices.getKieClasspathContainer();
|
||||
}
|
||||
Resource fileSystemResource = kServices.getResources().newFileSystemResource(knowledgeBaseDir);
|
||||
KieRepository kieRepository = kServices.getRepository();
|
||||
KieModule kModule = kieRepository.addKieModule(fileSystemResource);
|
||||
|
||||
return kServices.newKieContainer(kModule.getReleaseId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a KieSession using the provided base and session name, as well as a number of arbitrary Drools rule files.
|
||||
* By default, this session will be stateful, use a pseudo clock and perform reasoning in stream mode and
|
||||
* use equality as object comparison mechanism.
|
||||
*
|
||||
* @param baseModelName the name of the knowledge base
|
||||
* @param sessionModelName the name of the {@link org.kie.api.runtime.KieSession}
|
||||
* @param ruleFiles a number of Drools rule files
|
||||
* @return a {@link org.kie.api.runtime.KieSession} backed by the provided rule files using default options
|
||||
*/
|
||||
public static KieSession createKieSession(String baseModelName, String sessionModelName, File... ruleFiles) {
|
||||
if (baseModelName == null || sessionModelName == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
KieServices kServices = KieServices.Factory.get();
|
||||
KieModuleModel kModuleModel = kServices.newKieModuleModel();
|
||||
KieBaseModel kBaseModel = kModuleModel.newKieBaseModel(baseModelName);
|
||||
kBaseModel.setDefault(true).setEqualsBehavior(DEFAULT_EQUALS_BEHAVIOUR)
|
||||
.setEventProcessingMode(DEFAULT_EVENT_PROCESSING);
|
||||
|
||||
KieSessionModel kSession = kBaseModel.newKieSessionModel(sessionModelName);
|
||||
kSession.setDefault(true).setType(DEFAULT_KNOWLEDGE_SESSION_TYPE)
|
||||
.setClockType(DEFAULT_CLOCK_TYPE);
|
||||
|
||||
KieFileSystem kFileSystem = kServices.newKieFileSystem();
|
||||
kFileSystem.writeKModuleXML(kModuleModel.toXML());
|
||||
for (File ruleFile : ruleFiles) {
|
||||
kFileSystem.write(kServices.getResources().newFileSystemResource(ruleFile));
|
||||
}
|
||||
|
||||
kServices.newKieBuilder(kFileSystem).buildAll();
|
||||
KieContainer kContainer = kServices.newKieContainer(kServices.getRepository()
|
||||
.getDefaultReleaseId());
|
||||
|
||||
return kContainer.newKieSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the default {@link org.kie.api.runtime.KieSession} without changing any default values for the classpath
|
||||
* container.
|
||||
*
|
||||
* @return a default {@link org.kie.api.runtime.KieSession} using the classpath container (no settings are applied)
|
||||
*/
|
||||
public static KieSession createDefaultKieSession() {
|
||||
KieServices ks = KieServices.Factory.get();
|
||||
KieContainer kContainer = ks.getKieClasspathContainer();
|
||||
return kContainer.newKieSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link org.kie.api.runtime.KieSession} for the classpath container without
|
||||
* changing any default options, using the knowledge base and session name exactly as they are provided.
|
||||
*
|
||||
* @param kBaseName the knowledge base name
|
||||
* @param kSessionName the session name
|
||||
* @return a default kie session instance for the knowledge base
|
||||
*/
|
||||
public static KieSession createKieSession(String kBaseName, String kSessionName) {
|
||||
KieServices ks = KieServices.Factory.get();
|
||||
KieContainer kContainer = ks.getKieClasspathContainer();
|
||||
return createKieSession(kContainer, kBaseName, kSessionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.kie.api.runtime.KieSession} without changing any default options, using the
|
||||
* provided container, knowledge base and session name.
|
||||
*
|
||||
* @param kContainer the container to use
|
||||
* @param kBaseName the knowledge base name
|
||||
* @param kSessionName the session name
|
||||
* @return a default kie session instance for the knowledge base in the provided container, or null if the container
|
||||
* was null
|
||||
*/
|
||||
public static KieSession createKieSession(KieContainer kContainer, String kBaseName, String kSessionName) {
|
||||
if (kContainer == null) {
|
||||
return null;
|
||||
}
|
||||
KieSession kSession;
|
||||
if (kSessionName == null || kSessionName.isEmpty()) {
|
||||
kSession = kContainer.newKieSession();
|
||||
} else {
|
||||
kSession = kContainer.newKieSession(kSessionName);
|
||||
}
|
||||
|
||||
return kSession;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.drools;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.RubanetraSystemConfiguration;
|
||||
import at.jku.fim.rubanetra.output.OutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivityListener;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.Activity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.DroolsBaseActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.ReplaceableActivity;
|
||||
import org.drools.core.time.SessionPseudoClock;
|
||||
import org.kie.api.event.rule.ObjectDeletedEvent;
|
||||
import org.kie.api.event.rule.ObjectInsertedEvent;
|
||||
import org.kie.api.event.rule.ObjectUpdatedEvent;
|
||||
import org.kie.api.event.rule.RuleRuntimeEventListener;
|
||||
import org.kie.api.runtime.KieSession;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* This class may be considered the final link between the Kraken protocol parsing library, the Drools rule engine and
|
||||
* the {@link at.jku.fim.rubanetra.output.OutputWriterStrategy}.
|
||||
* It listens to all appropriate events creates by the protocol decoders and injects them into to Drools knowledge base
|
||||
* session ({@link org.kie.api.runtime.KieSession}).
|
||||
* Finally, it also reacts to Event removal events, which originate from the rule engine itself and are utilized
|
||||
* as indicator to write these events to the pre-defined output stream before they are discarded from memory.
|
||||
* <p>
|
||||
* It is vital to invoke the {@link #close()} method after usage of the rule engine, because otherwise the
|
||||
* remaining events and/or facts which are still in the active knowledge base will _not_ be written to the output stream
|
||||
* and this will lead to missing output.
|
||||
* <p>
|
||||
* This class will provide certain global objects that may be used from the Drools rule files, e.g.
|
||||
* a {@link org.slf4j.Logger} via "log" and the used {@link at.jku.fim.rubanetra.output.OutputWriterStrategy}
|
||||
* via "outputWriter".
|
||||
*/
|
||||
public class DroolsKrakenProtocolHandler implements PcapActivityListener, Closeable {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final RubanetraSystemConfiguration systemConfig;
|
||||
private final Map<ProtocolId, Set<DroolsProtocolPropertyChangeListener>> protocolListener = new HashMap<>();
|
||||
private final SessionPseudoClock droolsClock;
|
||||
private final OutputWriterStrategy outputWriterStrategy;
|
||||
|
||||
private KieSession kieSession;
|
||||
private PcapActivity currentPcapEntry;
|
||||
private Instant previousTimestamp, currentTimestamp;
|
||||
private RuleRuntimeEventListener droolsRuntimeListener = new RuleRuntimeEventListener() {
|
||||
@Override
|
||||
public void objectInserted(ObjectInsertedEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void objectUpdated(ObjectUpdatedEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void objectDeleted(ObjectDeletedEvent event) {
|
||||
/* every deleted/retracted event/fact will not be used for reasoning any more,
|
||||
* therefore those objects can be written to the output stream and finally discarded from memory */
|
||||
if (event.getOldObject() instanceof ReplaceableActivity) {
|
||||
ReplaceableActivity oldActivity = (ReplaceableActivity) event.getOldObject();
|
||||
|
||||
if (!oldActivity.isReplaced() && !oldActivity.isExcludedFromOutput()) {
|
||||
outputWriterStrategy.writeActivity(oldActivity);
|
||||
}
|
||||
logDeletedActivity(oldActivity);
|
||||
} else if (event.getOldObject() instanceof Activity) {
|
||||
Activity oldActivity = (Activity) event.getOldObject();
|
||||
if (!oldActivity.isExcludedFromOutput()) {
|
||||
outputWriterStrategy.writeActivity(oldActivity);
|
||||
}
|
||||
logDeletedActivity(oldActivity);
|
||||
}
|
||||
}
|
||||
|
||||
private void logDeletedActivity(Activity oldActivity) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Deleted activity: {} @ {} # {}", oldActivity.getActivityType(), currentTimestamp, oldActivity.getCompoundFrameNumbers());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiates a new handler for a pre-initialized RubanetraSystemConfiguration
|
||||
*
|
||||
* @param systemConfig the system configuration to use, may not be null and must be initialized
|
||||
*/
|
||||
public DroolsKrakenProtocolHandler(RubanetraSystemConfiguration systemConfig) {
|
||||
if (systemConfig == null) {
|
||||
log.error("The system configuration must not constitute a null pointer");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.systemConfig = systemConfig;
|
||||
this.kieSession = systemConfig.getKieSession();
|
||||
if (kieSession == null) {
|
||||
log.error("The system configuration must contain a valid Kie-Session object, instead a null pointer was passed");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.currentPcapEntry = null;
|
||||
this.droolsClock = kieSession.getSessionClock();
|
||||
|
||||
outputWriterStrategy = systemConfig.getOutputWriterStrategy();
|
||||
if (outputWriterStrategy == null) {
|
||||
log.error("The system configuration must contain a valid output writer, instead a null pointer was passed");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
// listen to all appropriate events, however, try to prevent duplicates
|
||||
for (KrakenProtocolConfiguration setting : systemConfig.getProtocolSettings()) {
|
||||
Map<ProtocolId, KrakenBaseProtocol> boundProtocols = setting.getBoundProtocols();
|
||||
for (ProtocolId id : boundProtocols.keySet()) {
|
||||
if (!protocolListener.containsKey(id)) {
|
||||
// new unique protocol discovered, therefore add a new listener
|
||||
KrakenBaseProtocol krakenBaseProtocol = boundProtocols.get(id);
|
||||
DroolsProtocolPropertyChangeListener changeListener = new DroolsProtocolPropertyChangeListener(krakenBaseProtocol);
|
||||
krakenBaseProtocol.addPropertyChangeListener(changeListener);
|
||||
protocolListener.put(id, new HashSet<>(Arrays.asList(changeListener)));
|
||||
} else if (id instanceof KrakenApplicationProtocolId) {
|
||||
// we want to receive all activities from the application layer, even for redundant application protocols,
|
||||
// e.g. consider UDP->DNS and TCP->DNS.
|
||||
// ENHANCEMENT:
|
||||
// However, this will cause certain duplicate activities iff the application layer handler is bound
|
||||
// to another handler above the application layer (this is currently not the case).
|
||||
// As soon as this constraint is violated, an alternative mechanism has to be implemented.
|
||||
KrakenBaseProtocol krakenBaseProtocol = boundProtocols.get(id);
|
||||
DroolsProtocolPropertyChangeListener changeListener = new DroolsProtocolPropertyChangeListener(krakenBaseProtocol);
|
||||
krakenBaseProtocol.addPropertyChangeListener(changeListener);
|
||||
protocolListener.get(id).add(changeListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* These variables are accessible from within the rule files
|
||||
*/
|
||||
kieSession.setGlobal("outputWriter", outputWriterStrategy);
|
||||
kieSession.setGlobal("log", LoggerFactory.getLogger(DroolsBaseActivity.class));
|
||||
|
||||
kieSession.addEventListener(droolsRuntimeListener);
|
||||
}
|
||||
|
||||
private void updateSessionClock() {
|
||||
if (previousTimestamp == null) {
|
||||
droolsClock.advanceTime(currentTimestamp.getEpochSecond(), TimeUnit.SECONDS);
|
||||
droolsClock.advanceTime(currentTimestamp.getNano(), TimeUnit.NANOSECONDS);
|
||||
log.debug("Setting initial Drools Pseudo clock time to {}", currentTimestamp);
|
||||
log.debug("The current Drools clock time is {}, frame # {}", Instant.ofEpochMilli(droolsClock.getCurrentTime()),
|
||||
currentPcapEntry.getFrameNumber());
|
||||
} else if (previousTimestamp.isBefore(currentTimestamp)) {
|
||||
Duration duration = Duration.between(previousTimestamp, currentTimestamp);
|
||||
log.debug("Advancing Drools Pseudo clock by {}", duration);
|
||||
droolsClock.advanceTime(duration.getSeconds(), TimeUnit.SECONDS);
|
||||
droolsClock.advanceTime(duration.getNano(), TimeUnit.NANOSECONDS);
|
||||
log.debug("The current Drools clock time is {}, reference {}, frame # {}",
|
||||
Instant.ofEpochMilli(droolsClock.getCurrentTime()), currentTimestamp, currentPcapEntry.getFrameNumber());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processPcapActivity(PcapActivity pcapActivity) {
|
||||
if (pcapActivity == null) {
|
||||
log.debug("An invalid pcap activity was passed after {}", currentTimestamp);
|
||||
return;
|
||||
}
|
||||
this.currentPcapEntry = pcapActivity;
|
||||
this.previousTimestamp = currentTimestamp;
|
||||
this.currentTimestamp = pcapActivity.getPcapTimestamp();
|
||||
updateSessionClock();
|
||||
kieSession.fireAllRules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the drools session and deletes, i.e. retracts, all remaining facts and releases any system resources associated
|
||||
* with it. If the session is already closed then invoking this method has no effect.
|
||||
* This method will clode the used {@link at.jku.fim.rubanetra.output.OutputWriterStrategy} and
|
||||
* the used {@link org.kie.api.runtime.KieSession}.
|
||||
*
|
||||
* @throws java.io.IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (kieSession != null) {
|
||||
kieSession.getFactHandles().forEach(kieSession::delete);
|
||||
kieSession.dispose();
|
||||
systemConfig.getOutputWriterStrategy().closeWriter();
|
||||
kieSession = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class listens to all events that carry an {@link at.jku.fim.rubanetra.protocol.activity.Activity}
|
||||
* and injects them into the knowledge session
|
||||
*/
|
||||
private class DroolsProtocolPropertyChangeListener implements PropertyChangeListener {
|
||||
private final KrakenBaseProtocol source;
|
||||
|
||||
private DroolsProtocolPropertyChangeListener(KrakenBaseProtocol source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets called when a bound property is changed.
|
||||
*
|
||||
* @param evt A PropertyChangeEvent object describing the event source
|
||||
* and the property that has changed.
|
||||
*/
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getNewValue() instanceof Activity) {
|
||||
kieSession.insert(evt.getNewValue());
|
||||
} else {
|
||||
log.debug("Passed event object is not an Activity: {}", evt.getNewValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.output;
|
||||
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This interface should be implemented by all {@link at.jku.fim.rubanetra.protocol.activity.Activity} implementations
|
||||
* that can provide their data in a comma separated fashion.
|
||||
*/
|
||||
public interface CsvRecordOutputWriter {
|
||||
/**
|
||||
* Write a single record, i.e. one line, using the provided csvPrinter to the output stream.
|
||||
*
|
||||
* @param csvPrinter An initialized csvPrinter, shared among all activities
|
||||
* @throws IOException If it is not possible to write to the output stream or the printer reached an invalid state.
|
||||
*/
|
||||
public void writeCsvRecord(CSVPrinter csvPrinter) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.output;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.protocol.activity.Activity;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Defines methods for writing {@link at.jku.fim.rubanetra.protocol.activity.Activity} to a provided
|
||||
* output-stream. Implementations of this interface represent the transformation to apply to the passed activties
|
||||
* before they are written out.
|
||||
*/
|
||||
public interface OutputWriterStrategy {
|
||||
/**
|
||||
* Write an {@link at.jku.fim.rubanetra.protocol.activity.Activity} to the provided output-stream
|
||||
* using the implementation-specific transformation of the content.
|
||||
*
|
||||
* @param activity the activity that will be transformed according to the strategy in use and written to the
|
||||
* provided output-stream
|
||||
*/
|
||||
public void writeActivity(Activity activity);
|
||||
|
||||
/**
|
||||
* Closes the writer but does not release or close the underlying output stream.
|
||||
* If the writer is already closed then invoking this
|
||||
* method has no effect.
|
||||
*/
|
||||
public void closeWriter() throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.output.impl;
|
||||
|
||||
import at.jku.fim.rubanetra.output.CsvRecordOutputWriter;
|
||||
import at.jku.fim.rubanetra.output.OutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.protocol.activity.Activity;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
/**
|
||||
* Created by stefan on 9/30/14.
|
||||
*/
|
||||
public class CsvOutputWriterStrategy implements OutputWriterStrategy {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final CSVPrinter csvPrinter;
|
||||
|
||||
public CsvOutputWriterStrategy(OutputStream outputStream) throws IOException {
|
||||
if (outputStream == null) {
|
||||
log.error("Cannot write to passed outputstream - null pointer");
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
this.csvPrinter = new CSVPrinter(new BufferedWriter(new OutputStreamWriter(outputStream)), CSVFormat.RFC4180);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an {@link at.jku.fim.rubanetra.protocol.activity.Activity} to the provided output-stream
|
||||
* using the implementation-specific transformation of the content.
|
||||
*
|
||||
* @param activity the activity that will be transformed according to the strategy in use and written to the
|
||||
* provided output-stream
|
||||
*/
|
||||
@Override
|
||||
public void writeActivity(Activity activity) {
|
||||
if (activity == null) {
|
||||
log.warn("Skipping activity - null pointer");
|
||||
return;
|
||||
}
|
||||
if (CsvRecordOutputWriter.class.isAssignableFrom(activity.getClass())) {
|
||||
try {
|
||||
((CsvRecordOutputWriter) activity).writeCsvRecord(csvPrinter);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
log.warn("Unable to serialize activity {} to the outputstream, skipping.", activity.getCompoundFrameNumbers());
|
||||
log.debug("Exception:", e);
|
||||
}
|
||||
} else {
|
||||
log.warn("Skipping activity - CSVRecordOutputWriter interface is not implemented by class {}", activity.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the writer but does not release or close the underlying output stream.
|
||||
* If the writer is already closed then invoking this
|
||||
* method has no effect.
|
||||
*/
|
||||
@Override
|
||||
public void closeWriter() throws IOException {
|
||||
csvPrinter.flush();
|
||||
csvPrinter.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.output.impl;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.output.OutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.output.mixin.HttpMixIn;
|
||||
import at.jku.fim.rubanetra.output.mixin.PcapMixIn;
|
||||
import at.jku.fim.rubanetra.protocol.activity.Activity;
|
||||
import com.fasterxml.jackson.core.JsonEncoding;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.tcpip.Http;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* This class implements a Json specific transformation (using the Jackson library) of the derived Event/Fact/Activity-data.
|
||||
* By default, it tries to pretty-print the resulting JSON-output, flushes the output stream after each written
|
||||
* activity and does not fail on empty activities, nor will it close the used output-stream.
|
||||
* Because certain classes do not provide appropriate inclusion or exclusion annotations, certain MixIn classes
|
||||
* will be used as substitute.
|
||||
* <p>
|
||||
* Additionally the implementation version, vendor and title is provided for external parsers.
|
||||
*
|
||||
* @see at.jku.fim.rubanetra.output.mixin.HttpMixIn
|
||||
* @see at.jku.fim.rubanetra.output.mixin.PcapMixIn
|
||||
*/
|
||||
public class JsonOutputWriterStrategy implements OutputWriterStrategy {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final OutputStream outputStream;
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private JsonGenerator jsonGenerator;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this strategy, all passed activities will be written to the provided output-stream.
|
||||
*
|
||||
* @param outputStream the output-stream to write the received activity-data in JSON-format to
|
||||
*/
|
||||
public JsonOutputWriterStrategy(OutputStream outputStream) {
|
||||
if (outputStream == null) {
|
||||
log.error("Cannot write to passed outputstream - null pointer");
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.outputStream = outputStream;
|
||||
|
||||
mapper = new ObjectMapper();
|
||||
// to enable standard indentation ("pretty-printing"):
|
||||
mapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
mapper.enable(SerializationFeature.FLUSH_AFTER_WRITE_VALUE);
|
||||
// to allow serialization of "empty" POJOs (no properties to serialize)
|
||||
// (without this setting, an exception is thrown in those cases)
|
||||
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
|
||||
// to write java.util.Date, Calendar as number (timestamp):
|
||||
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
mapper.disable(SerializationFeature.CLOSE_CLOSEABLE);
|
||||
|
||||
mapper.addMixInAnnotations(Http.class, HttpMixIn.class);
|
||||
mapper.addMixInAnnotations(PcapPacket.class, PcapMixIn.class);
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
JsonFactory jsonFactory = mapper.getFactory();
|
||||
Package classPackage = getClass().getPackage();
|
||||
try {
|
||||
jsonGenerator = jsonFactory.createGenerator(outputStream, JsonEncoding.UTF8);
|
||||
jsonGenerator.useDefaultPrettyPrinter();
|
||||
jsonGenerator.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
|
||||
jsonGenerator.enable(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT);
|
||||
jsonGenerator.writeStartObject();
|
||||
|
||||
jsonGenerator.writeStringField("implementationTitle", classPackage.getImplementationTitle());
|
||||
jsonGenerator.writeStringField("implementationVersion", classPackage.getImplementationVersion());
|
||||
jsonGenerator.writeStringField("implementationVendor", classPackage.getImplementationVendor());
|
||||
|
||||
jsonGenerator.writeArrayFieldStart("activities");
|
||||
} catch (IOException e) {
|
||||
log.error("Unable to create Json generator required for the selected output strategy.", e);
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeActivity(Activity activity) {
|
||||
if (activity == null) {
|
||||
log.warn("Skipping activity - null pointer");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mapper.writeValue(jsonGenerator, activity);
|
||||
// mapper.writeValue(outputStream,activity);
|
||||
// System.out.println(mapper.writeValueAsString(activity));
|
||||
} catch (IOException e) {
|
||||
log.warn("Unable to serialize activity {} to the outputstream, skipping.", activity);
|
||||
log.debug("Exception:", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void closeWriter() {
|
||||
if (jsonGenerator != null) {
|
||||
try {
|
||||
jsonGenerator.writeEndArray();
|
||||
jsonGenerator.writeEndObject();
|
||||
jsonGenerator.flush();
|
||||
jsonGenerator.close();
|
||||
jsonGenerator = null;
|
||||
} catch (IOException e) {
|
||||
log.warn("Error occurred while closing the writer", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.output.impl;
|
||||
|
||||
import at.jku.fim.rubanetra.output.OutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.protocol.activity.Activity;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This implementation of the {@link at.jku.fim.rubanetra.output.OutputWriterStrategy} does nothing.
|
||||
* May be useful for debugging purposes without wasting I/O resources.
|
||||
*/
|
||||
public class NopOutputWriterStrategy implements OutputWriterStrategy {
|
||||
@Override
|
||||
public void writeActivity(Activity activity) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeWriter() throws IOException {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.output.impl;
|
||||
|
||||
import at.jku.fim.rubanetra.output.OutputWriterStrategy;
|
||||
import at.jku.fim.rubanetra.output.mixin.HttpMixIn;
|
||||
import at.jku.fim.rubanetra.output.mixin.PcapMixIn;
|
||||
import at.jku.fim.rubanetra.protocol.activity.Activity;
|
||||
import com.fasterxml.jackson.core.JsonEncoding;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
|
||||
import com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.tcpip.Http;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Created by stefan on 9/30/14.
|
||||
*/
|
||||
public class XmlOutputWriterStrategy implements OutputWriterStrategy {
|
||||
public static final QName QNAME_ACTIVITY_ARRAY = new QName("activityArray");
|
||||
public static final QName QNAME_ACTIVITY = new QName("activity");
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final XmlMapper mapper;
|
||||
private ToXmlGenerator xmlGenerator;
|
||||
|
||||
public XmlOutputWriterStrategy(OutputStream outputStream) {
|
||||
if (outputStream == null) {
|
||||
log.error("Cannot write to passed outputstream - null pointer");
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
this.mapper = new XmlMapper();
|
||||
assignDefaultFeatures(mapper);
|
||||
|
||||
final XmlFactory xmlFactory = this.mapper.getFactory();
|
||||
|
||||
Package classPackage = getClass().getPackage();
|
||||
try {
|
||||
xmlGenerator = xmlFactory.createGenerator(outputStream, JsonEncoding.UTF8);
|
||||
DefaultXmlPrettyPrinter pp = new DefaultXmlPrettyPrinter();
|
||||
xmlGenerator.setPrettyPrinter(pp);
|
||||
xmlGenerator.enable(ToXmlGenerator.Feature.WRITE_XML_1_1);
|
||||
QName rootQName = new QName("root");
|
||||
xmlGenerator.initGenerator();
|
||||
xmlGenerator.setNextName(rootQName);
|
||||
xmlGenerator.writeStartObject();
|
||||
final String unknown = "Unknown";
|
||||
xmlGenerator.writeStringField("implementationTitle", classPackage.getImplementationTitle() == null ?
|
||||
unknown : classPackage.getImplementationTitle());
|
||||
|
||||
xmlGenerator.writeStringField("implementationVersion", classPackage.getImplementationVersion() == null ?
|
||||
unknown : classPackage.getImplementationVersion());
|
||||
xmlGenerator.writeStringField("implementationVendor", classPackage.getImplementationVendor() == null ?
|
||||
unknown : classPackage.getImplementationVendor());
|
||||
|
||||
xmlGenerator.startWrappedValue(QNAME_ACTIVITY_ARRAY, QNAME_ACTIVITY);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void assignDefaultFeatures(ObjectMapper mapper) {
|
||||
// to enable standard indentation ("pretty-printing"):
|
||||
mapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
mapper.enable(SerializationFeature.FLUSH_AFTER_WRITE_VALUE);
|
||||
// to allow serialization of "empty" POJOs (no properties to serialize)
|
||||
// (without this setting, an exception is thrown in those cases)
|
||||
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
|
||||
// to write java.util.Date, Calendar as number (timestamp):
|
||||
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
mapper.disable(SerializationFeature.CLOSE_CLOSEABLE);
|
||||
|
||||
mapper.addMixInAnnotations(Http.class, HttpMixIn.class);
|
||||
mapper.addMixInAnnotations(PcapPacket.class, PcapMixIn.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an {@link at.jku.fim.rubanetra.protocol.activity.Activity} to the provided output-stream
|
||||
* using the implementation-specific transformation of the content.
|
||||
*
|
||||
* @param activity the activity that will be transformed according to the strategy in use and written to the
|
||||
* provided output-stream
|
||||
*/
|
||||
@Override
|
||||
public void writeActivity(Activity activity) {
|
||||
if (activity == null) {
|
||||
log.warn("Skipping activity - null pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mapper.writeValue(xmlGenerator, activity);
|
||||
} catch (IOException e) {
|
||||
log.warn("Unable to serialize activity {} to the outputstream, skipping.", activity.getCompoundFrameNumbers());
|
||||
log.debug("Exception: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the writer but does not release or close the underlying output stream.
|
||||
* If the writer is already closed then invoking this
|
||||
* method has no effect.
|
||||
*/
|
||||
@Override
|
||||
public void closeWriter() throws IOException {
|
||||
if (xmlGenerator != null) {
|
||||
xmlGenerator.flush();
|
||||
// xmlGenerator.writeEndArray();
|
||||
try {
|
||||
xmlGenerator.getStaxWriter().writeEndDocument();
|
||||
} catch (XMLStreamException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// xmlGenerator.close();
|
||||
xmlGenerator = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.output.mixin;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* This Mixin will be used by the {@link at.jku.fim.rubanetra.output.impl.JsonOutputWriterStrategy}
|
||||
* to provide Jackson specific annotations to define the properties and fields of the external
|
||||
* {@link org.jnetpcap.protocol.tcpip.Http} class that are to be included in the final output.
|
||||
*/
|
||||
@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
public abstract class HttpMixIn {
|
||||
@JsonProperty("JNetPcap-HTTP-String")
|
||||
public abstract String toString();
|
||||
|
||||
@JsonProperty
|
||||
public abstract String header();
|
||||
|
||||
@JsonProperty
|
||||
public abstract boolean isResponse();
|
||||
|
||||
@JsonProperty
|
||||
public abstract String contentType();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.output.mixin;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* This Mixin will be used by the {@link at.jku.fim.rubanetra.output.impl.JsonOutputWriterStrategy}
|
||||
* to provide Jackson specific annotations to define the properties and fields of the external
|
||||
* {@link org.jnetpcap.Pcap} class that are to be included in the final output.
|
||||
*/
|
||||
@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
public abstract class PcapMixIn {
|
||||
@JsonProperty
|
||||
abstract int getTotalSize();
|
||||
|
||||
@JsonProperty
|
||||
abstract long getFrameNumber();
|
||||
|
||||
@JsonProperty
|
||||
abstract int getHeaderCount();
|
||||
|
||||
@JsonProperty
|
||||
abstract int getPacketWirelen();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.pcap;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* A PcapActivity may be interpreted as a Network Layer 1 activity type, because all common PCAP-Files contain
|
||||
* individual Pcap-entries which are wrapped by this class in order to provide PCAP-specific metadata per entry.
|
||||
* This class currently supports the JNetPcap library only (which in turn relies on the native libpcap library),
|
||||
* however, if the limited Kraken-Pcap-Parser has to be used, consider converting the Kraken-specific Pcap packet
|
||||
* to a {@link org.jnetpcap.packet.JMemoryPacket} in a manner similar to the following (at your own risk):
|
||||
* <p>
|
||||
* {@code byte[] arr = new byte[getPcapPacket().getPacketData().readableBytes()];}
|
||||
* <p>
|
||||
* {@code new ChainBuffer(getPcapPacket().getPacketData()).gets(arr);}
|
||||
* <p>
|
||||
* {@code JMemoryPacket jPacket = new JMemoryPacket(arr);}
|
||||
* <p>
|
||||
* {@code jPacket.scan(Ethernet.ID);}
|
||||
* <p>
|
||||
* {@code Ethernet header = jPacket.getHeader(new Ethernet());}
|
||||
* <p>
|
||||
* If a JNetPcap specific {@link org.jnetpcap.packet.PcapPacket} must be passed to a Kraken parser, the class
|
||||
* {@link at.jku.fim.rubanetra.pcap.PcapPacketToKrakenPcapPacketAdapter} may be useful.
|
||||
*
|
||||
* @see at.jku.fim.rubanetra.pcap.PcapPacketToKrakenPcapPacketAdapter
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public class PcapActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = 1884831815993828991L;
|
||||
private final long frameNumber;
|
||||
private final PcapPacket pcapPacket;
|
||||
private final Instant pcapTimestamp;
|
||||
|
||||
/**
|
||||
* Create a new PcapActivity using the provided frame number (as seen by the
|
||||
* {@link at.jku.fim.rubanetra.pcap.PcapFileHandler}) and the JNetPcap specific PCAP packet.
|
||||
*
|
||||
* @param frameNumber the frame number of the packet, reconstructed by the {@link at.jku.fim.rubanetra.pcap.PcapFileHandler}
|
||||
* @param pcapPacket the JNetPcap specific PCAP packet representation
|
||||
*/
|
||||
public PcapActivity(long frameNumber, PcapPacket pcapPacket) {
|
||||
super(pcapPacket);
|
||||
this.frameNumber = frameNumber;
|
||||
this.pcapPacket = pcapPacket;
|
||||
|
||||
// the JNetPcap timestamp will be interpreted as a Java 8 specific Instant in time
|
||||
this.pcapTimestamp = Instant.ofEpochSecond(pcapPacket.getCaptureHeader().hdr_sec()).
|
||||
plus(Duration.of(pcapPacket.getCaptureHeader().hdr_usec(), ChronoUnit.MICROS));
|
||||
|
||||
setStartInstant(pcapTimestamp);
|
||||
setEndInstant(pcapTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The JNetPcap specific representation of this packet capture activity
|
||||
*/
|
||||
public PcapPacket getPcapPacket() {
|
||||
return this.pcapPacket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the frame number of this packet capture activity as reconstructed by the used
|
||||
* {@link at.jku.fim.rubanetra.pcap.PcapHandler}
|
||||
*/
|
||||
public long getFrameNumber() {
|
||||
return this.frameNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Java 8 specific Instant in time, which was built from the JNetPcap specific timestamp information.
|
||||
* @see org.jnetpcap.packet.PcapPacket#getCaptureHeader()
|
||||
*/
|
||||
public Instant getPcapTimestamp() {
|
||||
return pcapTimestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Long> getCompoundFrameNumbers() {
|
||||
return Collections.unmodifiableCollection(Arrays.asList(getFrameNumber()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PcapActivity{" +
|
||||
"frameNumber=" + frameNumber +
|
||||
", pcapPacket=" + pcapPacket +
|
||||
", pcapTimestamp=" + pcapTimestamp +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.pcap;
|
||||
|
||||
/**
|
||||
* A listener interface for packet capture activities produced by implementations of a
|
||||
* {@link at.jku.fim.rubanetra.pcap.PcapHandler}.
|
||||
*/
|
||||
public interface PcapActivityListener {
|
||||
/**
|
||||
* Do something useful with the Layer 1 packet capture metadata and the actually parsed content
|
||||
*
|
||||
* @param pcapActivity the wrapper of the JNetPcap specific {@link org.jnetpcap.packet.PcapPacket} that was parsed
|
||||
* by a {@link at.jku.fim.rubanetra.pcap.PcapHandler}.
|
||||
*/
|
||||
public abstract void processPcapActivity(PcapActivity pcapActivity);
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.pcap;
|
||||
|
||||
|
||||
import org.jnetpcap.Pcap;
|
||||
import org.jnetpcap.PcapBpfProgram;
|
||||
import org.jnetpcap.packet.JPacket;
|
||||
import org.jnetpcap.packet.JPacketHandler;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Implements a pcap handler for parsing one or multiple files adhering to a supported PCAP-definition (JNetPcap's
|
||||
* native Pcap library, libpcap, will be used).
|
||||
* This class is subject to future changes, currently it employs a custom way to support multiple files, i.e.:
|
||||
* <ul>
|
||||
* <li>if multiple files are passed and the sortByPcapTimestamp flag is set to false, all files are treated in
|
||||
* the order they have been passed</li>
|
||||
* <li>if multiple files are passed and the sortByPcapTimestamp flag is set to true, all files will be opened and
|
||||
* the first available pcap entry will be parsed. All timestamps of the timestamps will be compared against each
|
||||
* other and a chronological file-order will be established. This mechanism will potentially fail if
|
||||
* the files contain overlapping time intervals. A possibly suitable future implementation for this use case
|
||||
* could employ a chronologically sorted buffer to alleviate the effects of this issue.</li>
|
||||
* <li>if a single file is passed, the sortByPcapTimestamp flag will be ignored</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Multiple {@link at.jku.fim.rubanetra.pcap.PcapActivityListener} may be registered with an instance of
|
||||
* this class, note however that the events will be dispatched sequentially in the listener registration order.
|
||||
* The only exception to this rule is a listener object that is passed directly as parameter to the
|
||||
* {@link #readNextPcapEntry(PcapActivityListener)} as this object will be the first one to receive a callback with
|
||||
* the appropriate {@link at.jku.fim.rubanetra.pcap.PcapActivity} event.
|
||||
*
|
||||
* @param <T> A custom implementation of a {@link at.jku.fim.rubanetra.pcap.PcapActivityListener} that
|
||||
* will be called back before all other registered listeners as long as it is passed as argument to the
|
||||
* {@link #readNextPcapEntry(PcapActivityListener)} method.
|
||||
*/
|
||||
public class PcapFileHandler<T extends PcapActivityListener> implements PcapHandler<T> {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final StringBuilder errorBuilder = new StringBuilder();
|
||||
|
||||
private final Queue<File> pcapInputFileQueue;
|
||||
private final int numberOfInputFiles;
|
||||
private final boolean sortByPcapTimestamp;
|
||||
private final List<PcapActivityListener> fileActivityListeners;
|
||||
private final JPacketHandler<PcapActivityListener> pcapPacketHandler = this::processNextPacket;
|
||||
private final PcapFilter pcapFilter;
|
||||
|
||||
private long currentFrameNumber;
|
||||
private PcapActivity currentPcapActivity;
|
||||
private Pcap currentPcapHandle;
|
||||
|
||||
/**
|
||||
* Instantiates a new pcap file handler using the passed Berkeley Packet Filter pcapFilter and a number of
|
||||
* input files. These files will be sorted according to the first encountered timestamp in the pcap entries of each
|
||||
* file iff sortByPcapTimestamp is passed as true.
|
||||
*
|
||||
* @param pcapFilter the Berkeley Packet Filter to apply to all specified pcapFiles
|
||||
* @param sortByPcapTimestamp whether or not to sort the pcapFiles chronologically according to the first
|
||||
* encountered timestamp of the individual pcap entries
|
||||
* @param pcapFiles the files to parse (must adhere to a PCAP specification supported by JNetPcap/libpcap)
|
||||
* @throws java.lang.IllegalArgumentException if no input files are passed
|
||||
*/
|
||||
public PcapFileHandler(PcapFilter pcapFilter, boolean sortByPcapTimestamp, File... pcapFiles) {
|
||||
if (pcapFiles == null || pcapFiles.length <= 0) {
|
||||
throw new IllegalArgumentException("No input files have been passed to the Pcap File Handler.");
|
||||
}
|
||||
this.pcapFilter = pcapFilter;
|
||||
this.pcapInputFileQueue = new ConcurrentLinkedQueue<>();
|
||||
this.sortByPcapTimestamp = sortByPcapTimestamp;
|
||||
if (sortByPcapTimestamp && pcapFiles.length > 1) {
|
||||
sortInputFilesByPcapTimestamp(pcapFiles);
|
||||
} else {
|
||||
Collections.addAll(this.pcapInputFileQueue, pcapFiles);
|
||||
}
|
||||
this.numberOfInputFiles = pcapFiles.length;
|
||||
this.fileActivityListeners = new LinkedList<>();
|
||||
this.currentFrameNumber = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new pcap file handler using no Berkeley Packet Filter.
|
||||
*
|
||||
* @param sortByPcapTimestamp whether or not to sort the pcapFiles chronologically according to the first
|
||||
* encountered timestamp of the individual pcap entries
|
||||
* @param pcapFiles the files to parse (must adhere to a PCAP specification supported by JNetPcap/libpcap)
|
||||
* @throws java.lang.IllegalArgumentException if no input files are passed
|
||||
* @see #PcapFileHandler(PcapFilter, boolean, java.io.File...)
|
||||
*/
|
||||
public PcapFileHandler(boolean sortByPcapTimestamp, File... pcapFiles) {
|
||||
this(null, sortByPcapTimestamp, pcapFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new pcap file handler using no Berkeley Packet Filter and does not sort the input files.
|
||||
*
|
||||
* @param pcapFiles the files to parse (must adhere to a PCAP specification supported by JNetPcap/libpcap)
|
||||
* @throws java.lang.IllegalArgumentException if no input files are passed
|
||||
* @see #PcapFileHandler(PcapFilter, boolean, java.io.File...)
|
||||
*/
|
||||
public PcapFileHandler(File... pcapFiles) {
|
||||
this(null, false, pcapFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to sort the input files using one {@link at.jku.fim.rubanetra.pcap.PcapFileHandler}
|
||||
* per file. This is quite inefficient, therefore:
|
||||
* ENHANCEMENT: implement in place sort and/or handle overlapping time intervals
|
||||
*
|
||||
* @param pcapFiles the input files to sort
|
||||
*/
|
||||
private void sortInputFilesByPcapTimestamp(File[] pcapFiles) {
|
||||
HashMap<PcapActivity, File> firstPcapActivities = new HashMap<>();
|
||||
for (File f : pcapFiles) {
|
||||
PcapFileHandler fileHandler = new PcapFileHandler(pcapFilter, false, f);
|
||||
fileHandler.readNextPcapEntry(pcapActivity -> firstPcapActivities.put(pcapActivity, f));
|
||||
fileHandler.close();
|
||||
}
|
||||
Stream<PcapActivity> sortedPcapActivities = firstPcapActivities.keySet().stream()
|
||||
.sorted((o1, o2) -> o1.getPcapTimestamp().compareTo(o2.getPcapTimestamp()));
|
||||
sortedPcapActivities.forEachOrdered(pcapActivity -> this.pcapInputFileQueue.add(firstPcapActivities.get(pcapActivity)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readNextPcapEntry(PcapActivityListener processor) {
|
||||
if (this.currentPcapHandle == null && !switchToNextReadablePcapFile()) {
|
||||
return false;
|
||||
}
|
||||
int returnCode = this.currentPcapHandle.dispatch(1, pcapPacketHandler, processor);
|
||||
return returnCode > 0 || switchToNextReadablePcapFile() && readNextPcapEntry(processor);
|
||||
|
||||
}
|
||||
|
||||
private void processNextPacket(JPacket packet, PcapActivityListener user) {
|
||||
// packet.scan(JRegistry.mapDLTToId(currentPcapHandle.datalink()));
|
||||
PcapPacket deepCopy = new PcapPacket(packet);
|
||||
this.currentPcapActivity = new PcapActivity(this.currentFrameNumber++, deepCopy);
|
||||
|
||||
for (PcapActivityListener l : fileActivityListeners) {
|
||||
l.processPcapActivity(currentPcapActivity);
|
||||
}
|
||||
if (user != null)
|
||||
user.processPcapActivity(currentPcapActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method opens, if possible, the next available input file and applies the Pcap filter and closes
|
||||
* the previous file handle. Because no checks have been performed until now (whether the next file truly is a
|
||||
* valid Pcap file) it tries to skip over invalid files until another valid file has been found.
|
||||
* An alternative could constitute a generic bail out.
|
||||
*
|
||||
* @return true, iff the switch to another readable PCAP-file was performed successfully
|
||||
*/
|
||||
private boolean switchToNextReadablePcapFile() {
|
||||
boolean switchSuccessful = false;
|
||||
while (!switchSuccessful && !this.pcapInputFileQueue.isEmpty()) {
|
||||
if (this.currentPcapHandle != null) {
|
||||
this.currentPcapHandle.close();
|
||||
this.currentPcapHandle = null;
|
||||
}
|
||||
|
||||
File currentPcapFile = this.pcapInputFileQueue.remove();
|
||||
try {
|
||||
this.currentPcapHandle = Pcap.openOffline(currentPcapFile.getCanonicalPath(),
|
||||
errorBuilder);
|
||||
applyFilter();
|
||||
switchSuccessful = this.currentPcapHandle != null;
|
||||
} catch (IOException e) {
|
||||
log.warn(String.format("Unable to read file %s, trying next file..., reason: %s%n",
|
||||
currentPcapFile, errorBuilder.toString()));
|
||||
errorBuilder.setLength(0);
|
||||
switchSuccessful = false;
|
||||
}
|
||||
}
|
||||
|
||||
return switchSuccessful;
|
||||
}
|
||||
|
||||
private void applyFilter() {
|
||||
if (this.pcapFilter != null && this.currentPcapHandle != null) {
|
||||
PcapBpfProgram bpfProgram = new PcapBpfProgram();
|
||||
if (Pcap.OK != this.currentPcapHandle.compile(bpfProgram,
|
||||
pcapFilter.getBpfExpression(), pcapFilter.isOptimize() ? 1 : 0,
|
||||
pcapFilter.getNetmask())) {
|
||||
log.warn(this.currentPcapHandle.getErr());
|
||||
return;
|
||||
}
|
||||
if (Pcap.OK != this.currentPcapHandle.setFilter(bpfProgram)) {
|
||||
log.warn(this.currentPcapHandle.getErr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (this.currentPcapHandle != null) {
|
||||
this.currentPcapHandle.close();
|
||||
this.currentPcapHandle = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PcapActivity getCurrentPcapActivity() {
|
||||
return currentPcapActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPcapProcessor(T processor) {
|
||||
this.fileActivityListeners.add(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePcapProcessor(T processor) {
|
||||
this.fileActivityListeners.remove(processor);
|
||||
}
|
||||
|
||||
public int getNumberOfInputFiles() {
|
||||
return numberOfInputFiles;
|
||||
}
|
||||
|
||||
public boolean isSortByPcapTimestamp() {
|
||||
return sortByPcapTimestamp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.pcap;
|
||||
|
||||
/**
|
||||
* Represent an intermediary between the native Berkeley Packet Filter compiler and this project external interface.
|
||||
* It is intended as a mere encapsulation of required and optional parameters before passing it as raw values to
|
||||
* the JNetPcap engine for native compilation. Error/Syntax checks will not be performed by this class.
|
||||
*/
|
||||
public class PcapFilter {
|
||||
private final String bpfExpression;
|
||||
private final boolean optimize;
|
||||
private final int netmask;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param bpfExpression a Berkeley Packet Filter expression, may be null or empty
|
||||
* @param optimize whether or not to try to optimize the provided filter expression.
|
||||
* @param netmask an integer representing a network mask that will be applied by the native compiler.
|
||||
*/
|
||||
public PcapFilter(String bpfExpression, boolean optimize, int netmask) {
|
||||
this.bpfExpression = bpfExpression;
|
||||
this.optimize = optimize;
|
||||
this.netmask = netmask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a Berkeley Packet Filter expression, may be null or empty
|
||||
*/
|
||||
public String getBpfExpression() {
|
||||
return bpfExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* JNetPcap expects an integer value, where 0 is equal to false.
|
||||
*
|
||||
* @return whether or not to try to optimize the provided filter expression.
|
||||
*/
|
||||
public boolean isOptimize() {
|
||||
return optimize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an integer representing a network mask that will be applied by the native compiler.
|
||||
*/
|
||||
public int getNetmask() {
|
||||
return netmask;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.pcap;
|
||||
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface PcapHandler<T extends PcapActivityListener> extends Closeable {
|
||||
/**
|
||||
* Read the next Pcap entry from the respective input stream.
|
||||
* Implementations of this method must ensure that the passed processor parameter is called after all registered
|
||||
* PcapProcessors had a chance to handle the Pcap-entry, i.e. after the decoding chain has been traversed.
|
||||
* This constraint ensures that the users pcap processor may access subsequently decoded data.
|
||||
* The methods signature is still subject to change, i.e. it is planned that the boolean return value will
|
||||
* be changed to an integer value indicating a kind of error code.
|
||||
*
|
||||
* @param processor A Pcap-Entry processor capable of handling the read PcapActivity.
|
||||
* @return true, iff the entry has been read and parsed successfully, false otherwise (e.g. end of stream).
|
||||
*/
|
||||
public boolean readNextPcapEntry(T processor);
|
||||
|
||||
/**
|
||||
* A convenience method that provides a reference to the currently processed PcapActivity, i.e. it returns the
|
||||
* latest successfully decoded Pcap entry.
|
||||
*
|
||||
* @return the latest successfully decoded PcapActivity
|
||||
*/
|
||||
public PcapActivity getCurrentPcapActivity();
|
||||
|
||||
/**
|
||||
* Adds a custom listener or processor to the set of already registered listeners.
|
||||
* This processor will receive a notification of all decoded Pcap entries after the previously registered
|
||||
* processors have been notified.
|
||||
*
|
||||
* @param processor a custom listener to decoded pcap entries and related events
|
||||
*/
|
||||
public void addPcapProcessor(T processor);
|
||||
|
||||
/**
|
||||
* Removes a custom listener or processor from the set of already registered listeners.
|
||||
* This processor will no longer receive a notification of decoded Pcap entries.
|
||||
*
|
||||
* @param processor a registered listener
|
||||
*/
|
||||
public void removePcapProcessor(T processor);
|
||||
|
||||
/**
|
||||
* Closes the underlying input streams (if not closed already) and releases any system resources associated
|
||||
* with it. If the streams were already closed then invoking this
|
||||
* method has no effect.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.pcap;
|
||||
|
||||
|
||||
import org.jnetpcap.PcapHeader;
|
||||
import org.krakenapps.pcap.packet.PacketHeader;
|
||||
import org.krakenapps.pcap.packet.PcapPacket;
|
||||
import org.krakenapps.pcap.util.Buffer;
|
||||
import org.krakenapps.pcap.util.ChainBuffer;
|
||||
|
||||
/**
|
||||
* This class is an adapter for a given {@link org.jnetpcap.packet.PcapPacket}. It may be used as a drop-in replacement
|
||||
* for a Kraken-specific {@link org.krakenapps.pcap.packet.PcapPacket}, i.e. instances of this class may be passed
|
||||
* directly to a Kraken decoder pipeline.
|
||||
* This class is still considered experimental, due to potentially dangerous long->int conversions and
|
||||
* different naming conventions among the utilized libraries.
|
||||
*/
|
||||
public class PcapPacketToKrakenPcapPacketAdapter extends PcapPacket {
|
||||
private final org.jnetpcap.packet.PcapPacket pcapPacket;
|
||||
|
||||
/**
|
||||
* Takes a JNetPcap specific PcapPacket and creates a Kraken header and payload-buffer.
|
||||
*
|
||||
* @param pcapPacket the JNetPcap packet to adapt into a Kraken packet
|
||||
*/
|
||||
public PcapPacketToKrakenPcapPacketAdapter(org.jnetpcap.packet.PcapPacket pcapPacket) {
|
||||
super(createKrakenHeader(pcapPacket), createKrakenPayloadBuffer(pcapPacket));
|
||||
this.pcapPacket = pcapPacket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the adapted JNetPcap packet
|
||||
*/
|
||||
public org.jnetpcap.packet.PcapPacket getPcapPacket() {
|
||||
return pcapPacket;
|
||||
}
|
||||
|
||||
private static PacketHeader createKrakenHeader(org.jnetpcap.packet.PcapPacket pcapPacket) {
|
||||
PcapHeader header = pcapPacket.getCaptureHeader();
|
||||
int origLen = header.wirelen();
|
||||
int inclLen = header.caplen();
|
||||
int hdr_sec = checkedInt(header.hdr_sec());
|
||||
int hdr_usec = header.hdr_usec();
|
||||
|
||||
return new PacketHeader(hdr_sec, hdr_usec, inclLen, origLen);
|
||||
}
|
||||
|
||||
private static Buffer createKrakenPayloadBuffer(org.jnetpcap.packet.PcapPacket pcapPacket) {
|
||||
Buffer krakenBuffer = new ChainBuffer();
|
||||
byte[] packetArray = pcapPacket.getByteArray(0, pcapPacket.size());
|
||||
krakenBuffer.addFirst(packetArray);
|
||||
return krakenBuffer;
|
||||
}
|
||||
|
||||
private static int checkedInt(long l) {
|
||||
if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException(String.format("Cannot cast %d to int without data loss", l));
|
||||
}
|
||||
return (int) l;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
|
||||
/**
|
||||
* This is the main interface that currently all provided protocol decoders have to implement.
|
||||
* The currently employed binding mechanism is up to the implementations, e.g. a {@link at.jku.fim.rubanetra.protocol.KrakenBaseProtocol}
|
||||
* based implementation relies on reflection in order to provide multiple {@link #bind(BaseProtocol)} overrides.
|
||||
* In order to provide an internal registry mechanism for this framework every protocol decoder must advertise a
|
||||
* unique protocol identifier that it is able to parse and decode.
|
||||
*/
|
||||
public interface BaseProtocol {
|
||||
/**
|
||||
* An arbitrary identifier for the protocol(s) this decoder should be able to parse and decode.
|
||||
* This identifier must be unique and may not be reused multiple times inside this framework for multiple decoders,
|
||||
* even if the same protocol can be decoded by multiple implementations.
|
||||
*
|
||||
* @return a unique identifier used to represent the decoding capabilities of this decoder
|
||||
*/
|
||||
public abstract ProtocolId getProtocolId();
|
||||
|
||||
/**
|
||||
* A protocol decoder should be able to pass its decoded data to another parser. Therefore it should be possible
|
||||
* to bind multiple decoders to form a decoding pipeline, similar to the Java I/O stream processing pipeline.
|
||||
* One way to implement the network stack would be to statically define which decoder is able to decode which
|
||||
* data on a certain layer. However, this approach seems quite error prone and must be adjusted regularly.
|
||||
* The currently utilized mechanism relies on the protocol decoder implementation advertisements and the user
|
||||
* specifications instead. This way, the protocol parsers can extend their capabilities easily by providing a new
|
||||
* implementation of this bind-method and the user may directly specify the decoding pipeline.
|
||||
* Usually, protocol decoders bind-methods are called depending on user input, therefore every implementing class
|
||||
* should handle errors gracefully.
|
||||
*
|
||||
* @param baseProtocol the protocol decoder to bind this decoder to, e.g. if base protocol refers to a decoder
|
||||
* capable of parsing IPv4 data and this class is able to decode Ethernet, and the user
|
||||
* specified a binding from Ethernet to IPv4, then Ethernet-decoder.bind(IPv4.decoder) will be
|
||||
* called once. All necessary steps must be taken by the caller and callee to ensure
|
||||
* successful data exchange. Currently the data exchange should be kept one way only,
|
||||
* i.e. data will flow from a lower layer to an upper layer only and not vice versa (unless
|
||||
* the user specified a binding from Ipv4 to Ethernet).
|
||||
*/
|
||||
public abstract void bind(BaseProtocol baseProtocol);
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivityListener;
|
||||
import at.jku.fim.rubanetra.pcap.PcapHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* An abstract definition of a possible Kraken protocol parser and decoder wrapper.
|
||||
* It provides an experimental implementation of the basic {@link at.jku.fim.rubanetra.protocol.BaseProtocol#bind(BaseProtocol)}}
|
||||
* specification which relies on reflection to provide a convenient way for subclasses to provide multiple bindings:
|
||||
* While it is possible for subclasses to override this mechanism, subclasses should instead define several bind-method
|
||||
* signatures directly, i.e. it should advertise possible bindings directly via the available bind-methods.
|
||||
* In order to rely on this feature is is mandatory for implementing classes to:
|
||||
* <ul>
|
||||
* <li>define one or multiple 'bind' methods with differing signatures</li>
|
||||
* <li>adhere to the naming convention, i.e. all methods must be called 'bind'</li>
|
||||
* <li>should not call 'bind' methods directly (bew aware of calling loops/recursion!),
|
||||
* as the input handler usually performs this step using a registry of available decoders</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Alternatively, a subclass may disregard this feature and implement a suitable {@link #bind(BaseProtocol)} method
|
||||
* on its own.
|
||||
*/
|
||||
public abstract class KrakenBaseProtocol implements BaseProtocol {
|
||||
public static final String BINDING_METHOD_NAME = "bind";
|
||||
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
protected final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
|
||||
protected KrakenProtocolConfiguration protocolSetting;
|
||||
private boolean settingIsInitialized = false;
|
||||
private PcapHandler<PcapActivityListener> pcapHandler;
|
||||
|
||||
/**
|
||||
* Tries to find a suitable bind-method for two concrete implementations of
|
||||
* {@link at.jku.fim.rubanetra.protocol.BaseProtocol} using reflection tools.
|
||||
* Both classes must share a common naming convention for bind methods, usually 'bind'.
|
||||
*
|
||||
* @param bindFrom bind from one concrete protocol decoder ...
|
||||
* @param bindTo ... to another protocol decoder
|
||||
* @param bindingMethodName the name that indicates the binding method
|
||||
* @return a Method to call for binding the two base protocol decoders together
|
||||
* @throws NoSuchMethodException if no such method was discovered or defined
|
||||
*/
|
||||
public static Method findProtocolBindingMethod(BaseProtocol bindFrom, BaseProtocol bindTo,
|
||||
String bindingMethodName) throws NoSuchMethodException {
|
||||
Class<?> visitable = bindTo.getClass();
|
||||
while (BaseProtocol.class.isAssignableFrom(visitable)) {
|
||||
Class<?> visitor = bindFrom.getClass(); // getClass();
|
||||
if (visitor.isInterface()) {
|
||||
// a binding implementation has to be found, but an interface
|
||||
// (and all super-interfaces) can not provide an implementation,
|
||||
// therefore no appropriate binding method was found
|
||||
throw new NoSuchMethodException(String.format(
|
||||
"Unable to find a suitable binding method (from %s to %s)",
|
||||
bindFrom.getClass(), bindTo.getClass()));
|
||||
}
|
||||
while (BaseProtocol.class.isAssignableFrom(visitor)) {
|
||||
try {
|
||||
return visitor.getDeclaredMethod(bindingMethodName, visitable);
|
||||
} catch (NoSuchMethodException e) {
|
||||
visitor = visitor.getSuperclass();
|
||||
}
|
||||
}
|
||||
visitable = visitable.getSuperclass();
|
||||
}
|
||||
throw new NoSuchMethodException(String.format(
|
||||
"Unable to find a suitable binding method (from %s to %s)", bindFrom.getClass(),
|
||||
bindTo.getClass()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this protocol decoder with the information provided by the user.
|
||||
* This method will be called once by {@link at.jku.fim.rubanetra.config.model.impl.KrakenProtocolConfigurationBuilderImpl}
|
||||
* before the bindings are processed.
|
||||
* This method should be called exactly once, multiple calls will result in an exception being thrown.
|
||||
*
|
||||
* @param krakenProtocolConfigurationImpl the protocol configuration provided by the user
|
||||
*/
|
||||
public void initialize(KrakenProtocolConfiguration krakenProtocolConfigurationImpl) {
|
||||
if (settingIsInitialized) {
|
||||
throw new IllegalStateException(String.format("The Kraken Protocol %s was already initialized - multiple initializations are prohibited.",
|
||||
getClass().getName()));
|
||||
}
|
||||
this.protocolSetting = krakenProtocolConfigurationImpl;
|
||||
this.pcapHandler = krakenProtocolConfigurationImpl.getPcapHandler();
|
||||
|
||||
this.settingIsInitialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the protocol configuration object obtained through initialization
|
||||
*/
|
||||
public KrakenProtocolConfiguration getProtocolConfiguration() {
|
||||
return protocolSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the latest dispatched PcapActivity that may or may not be processed by this decoder
|
||||
*/
|
||||
public PcapActivity getCurrentPcapActivity() {
|
||||
return pcapHandler.getCurrentPcapActivity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the utilized Pcap input stream
|
||||
*/
|
||||
protected PcapHandler<PcapActivityListener> getPcapHandler() {
|
||||
return this.pcapHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(BaseProtocol baseProtocol) {
|
||||
// this implementation relies on reflection
|
||||
try {
|
||||
Method m = findProtocolBindingMethod(this, baseProtocol, BINDING_METHOD_NAME);
|
||||
m.invoke(this, baseProtocol);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
|
||||
| NoSuchMethodException e) {
|
||||
log.warn("Unable to perform protocol decoder binding.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener instance to this object, notifications and property names are subject to the individual
|
||||
* subclass implementations.
|
||||
*
|
||||
* @param l the listener to add
|
||||
*/
|
||||
public void addPropertyChangeListener(PropertyChangeListener l) {
|
||||
this.propertyChangeSupport.addPropertyChangeListener(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener instance to this object, notifications and property names are subject to the individual
|
||||
* subclass implementations.
|
||||
*
|
||||
* @param propertyName the name of the property to listen for events
|
||||
* @param l the listener to add
|
||||
*/
|
||||
public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) {
|
||||
this.propertyChangeSupport.addPropertyChangeListener(propertyName, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a property change listener instance from this objects, i.e. it will no longer receive any notifications
|
||||
* from this object.
|
||||
*
|
||||
* @param l the listener to remove
|
||||
*/
|
||||
public void removePropertyChangeListener(PropertyChangeListener l) {
|
||||
this.propertyChangeSupport.removePropertyChangeListener(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a property change listener instance from this objects, i.e. it will no longer receive any notifications
|
||||
* from this object.
|
||||
*
|
||||
* @param propertyName the name of the property that was used to register this listener in the first place
|
||||
* @param l the listener to remove
|
||||
*/
|
||||
public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) {
|
||||
this.propertyChangeSupport.removePropertyChangeListener(propertyName, l);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.output.CsvRecordOutputWriter;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A template for a non-replaceable {@link at.jku.fim.rubanetra.protocol.activity.Activity}.
|
||||
* It defines an "addFrameNumbers" property that will be used to link two activities regarding the addition
|
||||
* of frame numbers during the reasoning process.
|
||||
* Additionally an activity extension method is provided, see {@link #extendActivity(Activity)}.
|
||||
* If a replaceable activity is required, refer to {@link at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity}.
|
||||
*/
|
||||
@JsonIgnoreProperties({"source", "changeSupport", "startTimestamp", "endTimestamp", "excludedFromOutput", "csvSchemaDefinition"})
|
||||
@JsonPropertyOrder({"activityType", "startInstant", "endInstant", "sourceAddress", "destinationAddress", "description", "compoundFrameNumbers", "optionalFields"})
|
||||
public abstract class AbstractActivity extends EventObject implements Activity, CsvRecordOutputWriter {
|
||||
public static final String PROPERTY_ADD_FRAME_NUMBERS = "addFrameNumbers";
|
||||
public static final String PROPERTY_NEW_START_INSTANT = "newStartInstant";
|
||||
public static final String PROPERTY_NEW_END_INSTANT = "newEndInstant";
|
||||
|
||||
private final PropertyChangeListener frameNumberPropertyListener = evt -> {
|
||||
if (evt.getPropertyName().equals(PROPERTY_ADD_FRAME_NUMBERS) && evt.getNewValue() instanceof Long[]) {
|
||||
addFrameNumbers((Long[]) evt.getNewValue());
|
||||
}
|
||||
};
|
||||
private final PropertyChangeListener startInstantListener = evt -> {
|
||||
if (evt.getPropertyName().equals(PROPERTY_NEW_START_INSTANT) && evt.getNewValue() instanceof Instant) {
|
||||
Instant newStartInstant = (Instant) evt.getNewValue();
|
||||
if (getStartInstant() == null || newStartInstant.isBefore(getStartInstant())) {
|
||||
setStartInstant(newStartInstant);
|
||||
}
|
||||
}
|
||||
};
|
||||
private final PropertyChangeListener endInstantListener = evt -> {
|
||||
if (evt.getPropertyName().equals(PROPERTY_NEW_END_INSTANT) && evt.getNewValue() instanceof Instant) {
|
||||
Instant newEndInstant = (Instant) evt.getNewValue();
|
||||
if (getEndInstant() == null || newEndInstant.isAfter(getEndInstant())) {
|
||||
setEndInstant(newEndInstant);
|
||||
}
|
||||
}
|
||||
};
|
||||
private static final long serialVersionUID = 3477186587937656979L;
|
||||
private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
|
||||
private final Collection<Long> compoundFrameNumbers = new TreeSet<>();
|
||||
private final Collection<OptionalField> optionalFields = new HashSet<>();
|
||||
private String sourceAddress, destinationAddress;
|
||||
private Instant startInstant, endInstant;
|
||||
private String description;
|
||||
private boolean excludedFromOutput;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical Activity event.
|
||||
*
|
||||
* @param source The object on which the Event initially occurred.
|
||||
* @throws IllegalArgumentException if source is null.
|
||||
*/
|
||||
public AbstractActivity(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivityType() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getStartTimestamp() {
|
||||
return Date.from(startInstant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getStartInstant() {
|
||||
return startInstant;
|
||||
}
|
||||
|
||||
public void setStartInstant(Instant startInstant) {
|
||||
Instant oldInstant = this.startInstant;
|
||||
this.startInstant = startInstant;
|
||||
this.changeSupport.firePropertyChange(PROPERTY_NEW_START_INSTANT, oldInstant, this.startInstant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getEndTimestamp() {
|
||||
return Date.from(endInstant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getEndInstant() {
|
||||
return endInstant;
|
||||
}
|
||||
|
||||
public void setEndInstant(Instant endInstant) {
|
||||
Instant oldInstant = this.endInstant;
|
||||
this.endInstant = endInstant;
|
||||
this.changeSupport.firePropertyChange(PROPERTY_NEW_END_INSTANT, oldInstant, this.endInstant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return sourceAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return destinationAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends this activity by act. The following actions are performed:
|
||||
* <ul>
|
||||
* <li>all frame numbers from act are copied into this set of frame numbers</li>
|
||||
* <li>if act is chronologically before this activity, the start Instant of this activity is overwritten</li>
|
||||
* <li>if act is chronologically after this activity, the end Instant of this activity is overwritten</li>
|
||||
* <li>if act is chronologically during this activity, no instants are modified</li>
|
||||
* <li>an ADD_FRAME_NUMBER property listener is registered in act, in order to receive all future updates to the
|
||||
* frame number set</li>
|
||||
* <li>a NEW_START_INSTANT property listener is registered in act, in order to receive all future updates to the
|
||||
* start instant</li>
|
||||
* <li>a NEW_END_INSTANT property listener is registered in act, in order to receive all future updates to the
|
||||
* end instant</li>
|
||||
* </ul>
|
||||
* Unintended consequences may be encountered in the following scenario:
|
||||
* {@code act1.extendActivity(act2); act2.extendActivity(act1);}
|
||||
*
|
||||
* @param act the activity to be merged with this activity
|
||||
*/
|
||||
public void extendActivity(Activity act) {
|
||||
Collection<Long> frameNumbersToAdd = act.getCompoundFrameNumbers();
|
||||
addFrameNumbers(frameNumbersToAdd.toArray(new Long[frameNumbersToAdd.size()]));
|
||||
if (act.getStartInstant() != null && (getStartInstant() == null || act.getStartInstant().isBefore(getStartInstant()))) {
|
||||
setStartInstant(act.getStartInstant());
|
||||
}
|
||||
if (act.getEndInstant() != null && (getEndInstant() == null || act.getEndInstant().isAfter(getEndInstant()))) {
|
||||
setEndInstant(act.getEndInstant());
|
||||
}
|
||||
act.addPropertyChangeListener(PROPERTY_ADD_FRAME_NUMBERS, frameNumberPropertyListener);
|
||||
act.addPropertyChangeListener(PROPERTY_NEW_START_INSTANT, startInstantListener);
|
||||
act.addPropertyChangeListener(PROPERTY_NEW_END_INSTANT, endInstantListener);
|
||||
}
|
||||
|
||||
private void addFrameNumbers(Long... frameNumbers) {
|
||||
Collection<Long> oldFrames = new TreeSet<>(getCompoundFrameNumbers());
|
||||
for (long frameNumber : frameNumbers)
|
||||
this.compoundFrameNumbers.add(frameNumber);
|
||||
if (oldFrames.size() != getCompoundFrameNumbers().size()) {
|
||||
this.changeSupport.firePropertyChange(PROPERTY_ADD_FRAME_NUMBERS, oldFrames, frameNumbers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add an optional field to the collection of all optional fields.
|
||||
*
|
||||
* @param field the optional field to add, may not be null
|
||||
*/
|
||||
protected void addOptionalField(OptionalField field) {
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.optionalFields.add(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Long> getCompoundFrameNumbers() {
|
||||
return Collections.unmodifiableCollection(compoundFrameNumbers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<OptionalField> getOptionalFields() {
|
||||
return Collections.unmodifiableCollection(optionalFields);
|
||||
}
|
||||
|
||||
public void setSourceAddress(String sourceAddress) {
|
||||
this.sourceAddress = sourceAddress;
|
||||
}
|
||||
|
||||
public void setDestinationAddress(String destinationAddress) {
|
||||
this.destinationAddress = destinationAddress;
|
||||
}
|
||||
|
||||
public void removeReplacedActivity(ReplaceableActivity act) {
|
||||
this.compoundFrameNumbers.removeAll(act.getCompoundFrameNumbers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPropertyChangeListener(PropertyChangeListener l) {
|
||||
this.changeSupport.addPropertyChangeListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) {
|
||||
this.changeSupport.addPropertyChangeListener(propertyName, l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePropertyChangeListener(PropertyChangeListener l) {
|
||||
this.changeSupport.removePropertyChangeListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) {
|
||||
this.changeSupport.removePropertyChangeListener(propertyName, l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExcludedFromOutput() {
|
||||
return excludedFromOutput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedFromOutput(boolean isExcludedFromOutput) {
|
||||
this.excludedFromOutput = isExcludedFromOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a single record to the provided csvPrinter. This record currently contains the following fields:
|
||||
* <pre>
|
||||
* activityType, startInstant, endInstant, sourceAddress, destinationAddress, description, frameNumbers, optionalFields
|
||||
* </pre>
|
||||
*
|
||||
* @param csvPrinter An initialized csvPrinter, shared among all activities
|
||||
* @throws IOException If the csvPrinter reaches an invalid state
|
||||
*/
|
||||
@Override
|
||||
public void writeCsvRecord(CSVPrinter csvPrinter) throws IOException {
|
||||
csvPrinter.printRecord(getActivityType(), getStartInstant().toString(), getEndInstant().toString(),
|
||||
getSourceAddressAsString(), getDestinationAddressAsString(), getDescription(),
|
||||
getCompoundFrameNumbers(), getOptionalFields());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AbstractActivity{" +
|
||||
"compoundFrameNumbers=" + compoundFrameNumbers +
|
||||
", optionalFields=" + optionalFields +
|
||||
", sourceAddress='" + sourceAddress + '\'' +
|
||||
", destinationAddress='" + destinationAddress + '\'' +
|
||||
", startInstant=" + startInstant +
|
||||
", endInstant=" + endInstant +
|
||||
", description='" + description + '\'' +
|
||||
", excludedFromOutput=" + excludedFromOutput +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity;
|
||||
|
||||
|
||||
/**
|
||||
* Extension of {@link at.jku.fim.rubanetra.protocol.activity.AbstractActivity}, added abstraction of
|
||||
* a {@link at.jku.fim.rubanetra.protocol.activity.ReplaceableActivity}, i.e. implementations may
|
||||
* replace another activity in addition to a mere extension.
|
||||
*/
|
||||
public abstract class AbstractReplaceableActivity extends AbstractActivity implements ReplaceableActivity {
|
||||
private static final long serialVersionUID = 3930231956209393878L;
|
||||
private boolean replaced;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical Event.
|
||||
*
|
||||
* @param source The object on which the Event initially occurred.
|
||||
* @throws IllegalArgumentException if source is null.
|
||||
*/
|
||||
public AbstractReplaceableActivity(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplaced() {
|
||||
return replaced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReplaced(boolean isReplaced) {
|
||||
replaced = isReplaced;
|
||||
}
|
||||
|
||||
public void replaceActivity(ReplaceableActivity activity) {
|
||||
activity.setReplaced(true);
|
||||
extendActivity(activity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity;
|
||||
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* This interface constitutes the basis of all concrete activity implementations, i.e. it defines those fields that are
|
||||
* common across all activities and are by default available in the final output unless
|
||||
* {@link #setExcludedFromOutput(boolean)} has been called on an object to object basis.
|
||||
* However, implementations of this interface cannot be replaced by other activities by simple means, therefore the use
|
||||
* of {@link at.jku.fim.rubanetra.protocol.activity.ReplaceableActivity} is recommended instead.
|
||||
* Furthermore, the values returned by the getter methods are the only values that will be included in the CVS output
|
||||
* while the Json parser will include all fields of all subclasses.
|
||||
* Generally it is advisable to establish a meaningful implementation of all defined methods, nevertheless a template
|
||||
* is provided by {@link at.jku.fim.rubanetra.protocol.activity.AbstractActivity}.
|
||||
*/
|
||||
public interface Activity extends Serializable {
|
||||
/**
|
||||
* Defines the type of the activity - this value should be unique in the sense that it should be possible to
|
||||
* identify the class of the object by using this String exclusively among all activities.
|
||||
* This value will be used by a python json parser to setup the equivalent of the Java class/activity structure.
|
||||
*
|
||||
* @return a unique identifier of the implemented activity
|
||||
*/
|
||||
String getActivityType();
|
||||
|
||||
/**
|
||||
* Returns a fixed point in time that fixates the start of this activity's time-line, i.e. it returns a point
|
||||
* in time that fulfills any one of the following conditions:
|
||||
* <ul>
|
||||
* <li>if the activity is defined as an event that occurs at exactly one time without a duration/interval
|
||||
* then the returned value corresponds to exactly that time and
|
||||
* {@link #getEndInstant()} must return the same reference</li>
|
||||
* <li>if the activity spans over a period of time or includes multiple intervals,
|
||||
* then the returned value corresponds to the point in time that lies furthest in the past and starts
|
||||
* the first interval of the activity</li>
|
||||
* </ul>
|
||||
* Calling this method multiple times may return different instants, due to the reasoning process that may find
|
||||
* a prior starting point in time. Therefore the returned object should generally not be used as an identifier
|
||||
* for the activity.
|
||||
*
|
||||
* @return the point in time that lies furthest in the past and indicates the start of the activity
|
||||
*/
|
||||
Instant getStartInstant();
|
||||
|
||||
/**
|
||||
* Returns a fixed point in time that fixates the end of this activity's time-line, i.e. it returns a point
|
||||
* in time that fulfills any one of the following conditions:
|
||||
* <ul>
|
||||
* <li>if the activity is defined as an event that occurs at exactly one time without a duration/interval
|
||||
* then the returned value corresponds to exactly that time and
|
||||
* {@link #getStartInstant()} must return the same reference</li>
|
||||
* <li>if the activity spans over a period of time or includes multiple intervals,
|
||||
* then the returned value corresponds to the point in time that lies closest to the current time and ends
|
||||
* the last interval of the activity</li>
|
||||
* </ul>
|
||||
* Calling this method multiple times may return different instants, due to the reasoning process that may find
|
||||
* a later starting point in time. Therefore the returned object should generally not be used as an identifier
|
||||
* for the activity.
|
||||
*
|
||||
* @return the point in time that lies closest to the current time indicates the end of the activity
|
||||
*/
|
||||
Instant getEndInstant();
|
||||
|
||||
/**
|
||||
* An address that can be interpreted as the source address for this activity.
|
||||
* Usually this address should correspond to a human readable value.
|
||||
* Because different protocols may be defining different address formats and types, the returned value
|
||||
* is highly dependant on the actual implementation and may be empty or null if no source address exists at all.
|
||||
*
|
||||
* @return a human-readable protocol-dependant source address or null if no such address exists for this activity
|
||||
*/
|
||||
String getSourceAddressAsString();
|
||||
|
||||
/**
|
||||
* An address that can be interpreted as the destination address for this activity.
|
||||
* Usually this address should correspond to a human readable value.
|
||||
* Because different protocols may be defining different address formats and types, the returned value
|
||||
* is highly dependant on the actual implementation and may be empty or null if no destination address exists at all.
|
||||
*
|
||||
* @return a human-readable protocol-dependant destination address or null if no such address exists for this activity
|
||||
*/
|
||||
String getDestinationAddressAsString();
|
||||
|
||||
/**
|
||||
* @return an arbitrary String that describes this activity, may be null or empty
|
||||
*/
|
||||
String getDescription();
|
||||
|
||||
/**
|
||||
* This method's return value indicates whether or not this activity will be included in the final output.
|
||||
* If this method returns false, the activity will be included in the final output.
|
||||
*
|
||||
* @return true, iff this activity should be excluded from the final output
|
||||
*/
|
||||
boolean isExcludedFromOutput();
|
||||
|
||||
/**
|
||||
* Setter for {@link #isExcludedFromOutput()}.
|
||||
*
|
||||
* @param excludedFromOutput whether or not to exclude this activity from the final output
|
||||
*/
|
||||
void setExcludedFromOutput(boolean excludedFromOutput);
|
||||
|
||||
/**
|
||||
* This method returns a sorted collection of all frame numbers in consecutive order and greater than zero, that
|
||||
* define this activity. It serves as basis for a manual review of the packets that were used during the reasoning
|
||||
* process, i.e. a future use case could consist of using these numbers to extract all frames corresponding to
|
||||
* a single activity individually from a potentially large PCAP file.
|
||||
*
|
||||
* @return a sorted collection of all frame numbers in consecutive order and greater than zero, that
|
||||
* define this activity
|
||||
*/
|
||||
Collection<Long> getCompoundFrameNumbers();
|
||||
|
||||
/**
|
||||
* This method returns a collection of attribute/value pairs that have to be included in the final output of all
|
||||
* output processors including the CVS encoder and the JSON encoder. This serves as an opportunity to include
|
||||
* information that would usually not be available due to the fixed nature of CVS columns specification.
|
||||
*
|
||||
* @return a collection of attribute/value pairs that have to be included in the final output of all
|
||||
* output processors including the CVS encoder and the JSON encoder.
|
||||
*/
|
||||
Collection<OptionalField> getOptionalFields();
|
||||
|
||||
/**
|
||||
* Adds a property change listener for all properties of this activity.
|
||||
*
|
||||
* @param l the listener to add
|
||||
*/
|
||||
void addPropertyChangeListener(PropertyChangeListener l);
|
||||
|
||||
/**
|
||||
* Adds a property change listener for one exactly defined property of this activity.
|
||||
*
|
||||
* @param propertyName the name of property to receive notifications for
|
||||
* @param l the listener to add
|
||||
*/
|
||||
void addPropertyChangeListener(String propertyName, PropertyChangeListener l);
|
||||
|
||||
/**
|
||||
* Removes the specified listener.
|
||||
*
|
||||
* @param l the listener to remove
|
||||
*/
|
||||
void removePropertyChangeListener(PropertyChangeListener l);
|
||||
|
||||
/**
|
||||
* The specified listener will no longer receive notifications for propertyName.
|
||||
*
|
||||
* @param propertyName the name of property to stop receiving notifications for
|
||||
* @param l the listener to remove
|
||||
*/
|
||||
void removePropertyChangeListener(String propertyName, PropertyChangeListener l);
|
||||
|
||||
/**
|
||||
* This method should only be used within Drools rule-files and serve as timestamp indicator. This is currently
|
||||
* required due to the general incompatibility of {@link java.time.Instant} caused by the Drools engine pseudo-clock implementation.
|
||||
*
|
||||
* @return a timestamp in MILLISECOND precision (backed by an {@link java.time.Instant}), representing
|
||||
* the starting point in time for this {@link at.jku.fim.rubanetra.protocol.activity.Activity}.
|
||||
* Please note that this method returns an object which may not be persistent, i.e. the start timestamp
|
||||
* object may be overwritten by implementations.
|
||||
* @see #getStartInstant()
|
||||
* @see at.jku.fim.rubanetra.protocol.activity.AbstractActivity#setStartInstant(java.time.Instant)
|
||||
* @see at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity#setStartInstant(java.time.Instant)
|
||||
*/
|
||||
Date getStartTimestamp();
|
||||
|
||||
/**
|
||||
* This method should only be used within Drools rule-files and serve as timestamp indicator. This is currently
|
||||
* required due to the general incompatibility of {@link java.time.Instant} caused by the Drools engine pseudo-clock implementation.
|
||||
*
|
||||
* @return a timestamp in MILLISECOND precision (backed by an {@link java.time.Instant}), representing
|
||||
* the ending point in time for this {@link at.jku.fim.rubanetra.protocol.activity.Activity}.
|
||||
* Please note that this method returns an object which may not be persistent, i.e. the end timestamp
|
||||
* object may be overwritten by implementations.
|
||||
* @see #getEndInstant()
|
||||
* @see at.jku.fim.rubanetra.protocol.activity.AbstractActivity#setEndInstant(java.time.Instant)
|
||||
* @see at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity#setEndInstant(java.time.Instant)
|
||||
*/
|
||||
Date getEndTimestamp();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity;
|
||||
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class serves as the base class for custom class extension inside the Drools rules files, i.e. any declared
|
||||
* classes using the Drools rule language may extend this class in order to qualify as valid Activity which
|
||||
* is ultimately supposed to be written to the final OutputStream.
|
||||
* As soon as it is possible to extend an abstract class (e.g. the AbstractActivity or the AbstractReplaceableActivity)
|
||||
* inside the Drools rule definition this class can be considered obsolete. However, currently it appears that
|
||||
* the base class requires a default constructor. This class defines a default constructor, however, the source
|
||||
* object is currently substituted by a random UUID.
|
||||
*/
|
||||
public class DroolsBaseActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -5807104716376365130L;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical Event.
|
||||
*
|
||||
* @param source The object on which the Event initially occurred.
|
||||
* @throws IllegalArgumentException if source is null.
|
||||
*/
|
||||
public DroolsBaseActivity(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public DroolsBaseActivity() {
|
||||
super(UUID.randomUUID());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An optional field consists of an identifier and an arbitrary value and may be added to the final OutputStream.
|
||||
*/
|
||||
public class OptionalField implements Serializable {
|
||||
private static final long serialVersionUID = -6391001123309282371L;
|
||||
private String identifier;
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* Default constructor, all values are initialized as null pointers.
|
||||
*/
|
||||
public OptionalField() {
|
||||
this.identifier = null;
|
||||
this.value = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new optional field
|
||||
* @param identifier the unique identifier among all optional field to be included for a single activity-
|
||||
* @param value an arbitrary object
|
||||
*/
|
||||
public OptionalField(String identifier, Object value) {
|
||||
this.identifier = identifier;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* This event may be fired by any custom rule definition and it directs the output handler to write an Activity to
|
||||
* the output stream.
|
||||
*/
|
||||
public class OutputActivityEvent extends EventObject implements Serializable {
|
||||
private static final long serialVersionUID = -4878319387952597370L;
|
||||
private final Activity toOutput;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical Event.
|
||||
*
|
||||
* @param toOutput The activity that should be written to the output stream.
|
||||
* @throws IllegalArgumentException if source is null.
|
||||
*/
|
||||
public OutputActivityEvent(Activity toOutput) {
|
||||
super(toOutput);
|
||||
|
||||
this.toOutput = toOutput;
|
||||
}
|
||||
|
||||
public Activity getToOutput() {
|
||||
return toOutput;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity;
|
||||
|
||||
|
||||
/**
|
||||
* Extension of the {@link at.jku.fim.rubanetra.protocol.activity.Activity} interface, it provides
|
||||
* methods to replace, in addition to extend, an activity.
|
||||
*/
|
||||
public interface ReplaceableActivity extends Activity {
|
||||
/**
|
||||
* @return true, iff this activity has been replaced by at least one other activity.
|
||||
*/
|
||||
public boolean isReplaced();
|
||||
|
||||
/**
|
||||
* Indicate, that this activity has been replaced.
|
||||
*
|
||||
* @param isReplaced whether or not this activity will be replaced by the caller.
|
||||
*/
|
||||
public void setReplaced(boolean isReplaced);
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.arp;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.network.Arp;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
import org.krakenapps.pcap.decoder.arp.ArpPacket;
|
||||
import org.krakenapps.pcap.decoder.ethernet.MacAddress;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* An encapsulation of an {@link org.krakenapps.pcap.decoder.arp.ArpPacket} including IP information if available.
|
||||
* This class also provides the JNetPcap specific Arp packet representation (if available)
|
||||
* {@link org.jnetpcap.protocol.network.Arp}.
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public class ArpActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -6124545150681044570L;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final int hardwareType;
|
||||
private final int protocolType;
|
||||
private final int hardwareAddressLength;
|
||||
private final int protocolAddressLength;
|
||||
private final int operation;
|
||||
private final MacAddress senderHardwareAddress;
|
||||
private final InetAddress senderProtocolAddress;
|
||||
private final MacAddress targetHardwareAddress;
|
||||
private final InetAddress targetProtocolAddress;
|
||||
private final Arp arp;
|
||||
|
||||
/**
|
||||
* Default constructor for this class, the source pcap activity will be replaced.
|
||||
*
|
||||
* @param source on which the ArpActivity occurred or the final PcapActivity that led to the fully decoded packet.
|
||||
* @param p the parsed Arp-packet
|
||||
*/
|
||||
public ArpActivity(PcapActivity source, ArpPacket p) {
|
||||
super(source);
|
||||
this.pcapActivity = source;
|
||||
hardwareType = p.getHardwareType();
|
||||
protocolType = p.getProtocolType();
|
||||
hardwareAddressLength = p.getHardwareSize();
|
||||
protocolAddressLength = p.getProtocolSize();
|
||||
operation = p.getOpcode();
|
||||
senderHardwareAddress = p.getSenderMac();
|
||||
senderProtocolAddress = p.getSenderIp();
|
||||
targetHardwareAddress = p.getTargetMac();
|
||||
targetProtocolAddress = p.getTargetIp();
|
||||
arp = new Arp();
|
||||
PcapPacket packet = pcapActivity.getPcapPacket();
|
||||
packet.hasHeader(getArp());
|
||||
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which the ArpActivity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.krakenapps.pcap.decoder.arp.ArpPacket#getHardwareType()
|
||||
*/
|
||||
public int getHardwareType() {
|
||||
return hardwareType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.krakenapps.pcap.decoder.arp.ArpPacket#getProtocolType()
|
||||
*/
|
||||
public int getProtocolType() {
|
||||
return protocolType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.krakenapps.pcap.decoder.arp.ArpPacket#getHardwareSize()
|
||||
*/
|
||||
public int getHardwareAddressLength() {
|
||||
return hardwareAddressLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.krakenapps.pcap.decoder.arp.ArpPacket#getProtocolSize()
|
||||
*/
|
||||
public int getProtocolAddressLength() {
|
||||
return protocolAddressLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.krakenapps.pcap.decoder.arp.ArpPacket#getOpcode()
|
||||
*/
|
||||
public int getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.krakenapps.pcap.decoder.arp.ArpPacket#getSenderMac()
|
||||
*/
|
||||
public MacAddress getSenderHardwareAddress() {
|
||||
return senderHardwareAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.krakenapps.pcap.decoder.arp.ArpPacket#getSenderIp()
|
||||
*/
|
||||
public InetAddress getSenderProtocolAddress() {
|
||||
return senderProtocolAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.krakenapps.pcap.decoder.arp.ArpPacket#getTargetMac()
|
||||
*/
|
||||
public MacAddress getTargetHardwareAddress() {
|
||||
return targetHardwareAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.krakenapps.pcap.decoder.arp.ArpPacket#getTargetIp()
|
||||
*/
|
||||
public InetAddress getTargetProtocolAddress() {
|
||||
return targetProtocolAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JNetPcap specific Arp packet representation
|
||||
*/
|
||||
public Arp getArp() {
|
||||
return arp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return String.valueOf(getSenderHardwareAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return String.valueOf(getTargetHardwareAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArpActivity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
", hardwareType=" + hardwareType +
|
||||
", protocolType=" + protocolType +
|
||||
", hardwareAddressLength=" + hardwareAddressLength +
|
||||
", protocolAddressLength=" + protocolAddressLength +
|
||||
", operation=" + operation +
|
||||
", senderHardwareAddress=" + senderHardwareAddress +
|
||||
", senderProtocolAddress=" + senderProtocolAddress +
|
||||
", targetHardwareAddress=" + targetHardwareAddress +
|
||||
", targetProtocolAddress=" + targetProtocolAddress +
|
||||
", arp=" + arp +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.dhcp;
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.krakenapps.pcap.decoder.dhcp.DhcpMessage;
|
||||
|
||||
/**
|
||||
* An encapsulation of a {@link org.krakenapps.pcap.decoder.dhcp.DhcpMessage}.
|
||||
*/
|
||||
@Role(Role.Type.EVENT)
|
||||
public class DhcpActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -3031909630697934242L;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final DhcpMessage dhcpMessage;
|
||||
|
||||
/**
|
||||
* Constructs an activity containing the passed Dhcp message, the source pcap activity will be replaced.
|
||||
*
|
||||
* @param source The object on which the Activity occurred.
|
||||
* @param dhcpMessage the decoded Dhcp message
|
||||
* @throws IllegalArgumentException if source is null.
|
||||
*/
|
||||
public DhcpActivity(PcapActivity source, DhcpMessage dhcpMessage) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
this.dhcpMessage = dhcpMessage;
|
||||
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which the ArpActivity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded Dhcp content
|
||||
*/
|
||||
public DhcpMessage getDhcpMessage() {
|
||||
return dhcpMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
if (dhcpMessage != null) {
|
||||
return String.format("%s - %s", String.valueOf(dhcpMessage.getClientAddress()), String.valueOf(dhcpMessage.getClientMac()));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
if (dhcpMessage != null) {
|
||||
return String.valueOf(dhcpMessage.getNextServerAddress());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DhcpActivity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
", dhcpMessage=" + dhcpMessage +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.dns;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
import org.xbill.DNS.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An encapsulation of a decoded {@link org.xbill.DNS.Message}.
|
||||
* The default output stream handler {@link at.jku.fim.rubanetra.output.impl.JsonOutputWriterStrategy}
|
||||
* will not include the original {@link org.xbill.DNS.Message} object due to space conservation issues. Instead, the
|
||||
* available question, answer, authority and additional {@link org.xbill.DNS.Record}s are included as lists and the
|
||||
* {@link org.xbill.DNS.Header} as it was encountered.
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public class DnsActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -476178927847593388L;
|
||||
private final Message dnsMessage;
|
||||
private final List<Record> questionRecords;
|
||||
private final List<Record> answerRecords;
|
||||
private final List<Record> authorityRecords;
|
||||
private final List<Record> additionalRecords;
|
||||
private final Header dnsMessageHeader;
|
||||
private final boolean isResponse;
|
||||
|
||||
private final PcapActivity pcapActivity;
|
||||
|
||||
/**
|
||||
* Constructs a new DnsActivity, while replacing the source pcap activity and wrapping the decoded DNS message
|
||||
*
|
||||
* @param source on which the DnsActivity occurred or the final PcapActivity that led to the fully decoded packet.
|
||||
* @param dnsMessage the fully decoded DNS content
|
||||
*/
|
||||
public DnsActivity(PcapActivity source, Message dnsMessage) {
|
||||
super(source);
|
||||
this.dnsMessage = dnsMessage;
|
||||
questionRecords = Arrays.asList(dnsMessage.getSectionArray(Section.QUESTION));
|
||||
answerRecords = Arrays.asList(dnsMessage.getSectionArray(Section.ANSWER));
|
||||
authorityRecords = Arrays.asList(dnsMessage.getSectionArray(Section.AUTHORITY));
|
||||
additionalRecords = Arrays.asList(dnsMessage.getSectionArray(Section.ADDITIONAL));
|
||||
dnsMessageHeader = dnsMessage.getHeader();
|
||||
isResponse = dnsMessage.getHeader().getFlag(Flags.QR);
|
||||
this.pcapActivity = source;
|
||||
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded DNS content as is
|
||||
*/
|
||||
@JsonIgnore
|
||||
public Message getDnsMessage() {
|
||||
return dnsMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an unmodifiable list of the available question records
|
||||
*/
|
||||
public List<Record> getQuestionRecords() {
|
||||
return Collections.unmodifiableList(questionRecords);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an unmodifiable list of the available answer records
|
||||
*/
|
||||
public List<Record> getAnswerRecords() {
|
||||
return Collections.unmodifiableList(answerRecords);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an unmodifiable list of the available authority records
|
||||
*/
|
||||
public List<Record> getAuthorityRecords() {
|
||||
return Collections.unmodifiableList(authorityRecords);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an unmodifiable list of the available additional records
|
||||
*/
|
||||
public List<Record> getAdditionalRecords() {
|
||||
return Collections.unmodifiableList(additionalRecords);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the DNS message header
|
||||
*/
|
||||
public Header getDnsMessageHeader() {
|
||||
return dnsMessageHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return flag, indicating whether or not this message is a response to a query
|
||||
*/
|
||||
public boolean isResponse() {
|
||||
return isResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which the DnsActivity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DnsActivity{" +
|
||||
"dnsMessage=" + dnsMessage +
|
||||
", questionRecords=" + questionRecords +
|
||||
", answerRecords=" + answerRecords +
|
||||
", authorityRecords=" + authorityRecords +
|
||||
", additionalRecords=" + additionalRecords +
|
||||
", dnsMessageHeader=" + dnsMessageHeader +
|
||||
", isResponse=" + isResponse +
|
||||
", pcapActivity=" + pcapActivity +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.ethernet;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.lan.Ethernet;
|
||||
import org.jnetpcap.protocol.lan.Ethernet.EthernetType;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
import org.krakenapps.pcap.decoder.ethernet.EthernetFrame;
|
||||
import org.krakenapps.pcap.decoder.ethernet.MacAddress;
|
||||
|
||||
/**
|
||||
* This class encapsulates an {@link org.jnetpcap.protocol.lan.Ethernet} object, which should provide a vast amount
|
||||
* of metadata including the content buffer itself. If this activity is created before it has been processed by
|
||||
* subsequent protocol parsers, the content buffer should not be modified in any way, i.e. it should be treated as
|
||||
* read-only medium.
|
||||
* ENHANCEMENT: encapsulate all metadata fields and prohibit access to the content buffer itself
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public class EthernetActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -8495525878251669060L;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final MacAddress destinationMacAddress, sourceMacAddress;
|
||||
private final int ethernetType;
|
||||
private final EthernetType ethernetTypeEnum;
|
||||
private final Ethernet ethernet;
|
||||
|
||||
/**
|
||||
* Constructs a new ethernet activity, replaces the source pcap activity on which the event occurred.
|
||||
*
|
||||
* @param source the Pcap activity on which the event occurred. This activity will be excluded from the
|
||||
* output, unless {@link #setExcludedFromOutput(boolean)} is called with 'false'.
|
||||
* @param frame the decoded Ethernet frame (by Kraken)
|
||||
*/
|
||||
public EthernetActivity(PcapActivity source, EthernetFrame frame) {
|
||||
super(source);
|
||||
this.pcapActivity = source;
|
||||
this.destinationMacAddress = frame.getDestination();
|
||||
this.sourceMacAddress = frame.getSource();
|
||||
this.ethernetType = frame.getType();
|
||||
this.ethernetTypeEnum = EthernetType.valueOf(getEthernetType());
|
||||
this.ethernet = new Ethernet();
|
||||
scanAndFillEthernet();
|
||||
|
||||
replaceActivity(source);
|
||||
setExcludedFromOutput(true);
|
||||
}
|
||||
|
||||
private void scanAndFillEthernet() {
|
||||
PcapPacket pcapPacket = this.pcapActivity.getPcapPacket();
|
||||
pcapPacket.hasHeader(ethernet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Ethernet frame as decoded by JNetPcap
|
||||
*/
|
||||
public Ethernet getEthernet() {
|
||||
return this.ethernet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the physical Ethernet address (source)
|
||||
*/
|
||||
public MacAddress getSourceMacAddress() {
|
||||
return this.sourceMacAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the physical Ethernet address (destination)
|
||||
*/
|
||||
public MacAddress getDestinationMacAddress() {
|
||||
return this.destinationMacAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The payload type as integer
|
||||
* @see #getEthernetTypeEnum()
|
||||
*/
|
||||
public int getEthernetType() {
|
||||
return this.ethernetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the payload type as JNetPcap enumeration object, however, be aware that this enumeration may not be
|
||||
* complete
|
||||
* @see #getEthernetType()
|
||||
*/
|
||||
public EthernetType getEthernetTypeEnum() {
|
||||
return ethernetTypeEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded frame.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return String.valueOf(getSourceMacAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return String.valueOf(getDestinationMacAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EthernetActivity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
", destinationMacAddress=" + destinationMacAddress +
|
||||
", sourceMacAddress=" + sourceMacAddress +
|
||||
", ethernetType=" + ethernetType +
|
||||
", ethernetTypeEnum=" + ethernetTypeEnum +
|
||||
", ethernet=" + ethernet +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.ftp;
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* TODO: this class represent a partial ftp activity, it must be reassembled by Drools rules based on the tcp socket addresses to represent a FTPSession
|
||||
*/
|
||||
public class FtpActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = 8828875279114236211L;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final Type ftpActivityType;
|
||||
|
||||
private String command, reply;
|
||||
private byte[] list;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical activity, replaces the source Pcap activity and stores the type of the FTP message..
|
||||
*
|
||||
* @param source The object on which the activity initially occurred.
|
||||
* @param type the FTP message type leading to a decoded String, i.e. either COMMAND or REPLY
|
||||
* @throws IllegalArgumentException if source is null or an unsupported type was encountered.
|
||||
*/
|
||||
public FtpActivity(PcapActivity source, Type type, String decodedMessage) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
ftpActivityType = type;
|
||||
switch (ftpActivityType) {
|
||||
case COMMAND:
|
||||
this.command = decodedMessage;
|
||||
break;
|
||||
case REPLY:
|
||||
this.reply = decodedMessage;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(String.format("Unsupported FTP message type: %s", type));
|
||||
}
|
||||
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a prototypical activity, replaces the source Pcap activity and stores the type of the FTP message..
|
||||
*
|
||||
* @param source The object on which the activity initially occurred.
|
||||
* @param type the FTP message type leading to a decoded byte [], i.e. VIEW_LIST.
|
||||
* @throws IllegalArgumentException if source is null or an unsupported type was encountered.
|
||||
*/
|
||||
public FtpActivity(PcapActivity source, Type type, byte [] decodedMessage) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
ftpActivityType = type;
|
||||
switch (ftpActivityType) {
|
||||
case VIEW_LIST:
|
||||
this.list = decodedMessage;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(String.format("Unsupported FTP message type: %s", type));
|
||||
}
|
||||
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded frame.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the FTP message type as enumeration
|
||||
*/
|
||||
public Type getFtpActivityTypeEnum() {
|
||||
return ftpActivityType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the command string, if the type of this activity is equal to COMMAND or null otherwise.
|
||||
*/
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded reply string, if the type of this activity is equal to REPLY or null otherwise
|
||||
*/
|
||||
public String getReply() {
|
||||
return reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the result of the VIEW_LIST command or null
|
||||
*/
|
||||
public byte[] getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
COMMAND, REPLY, VIEW_LIST
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FtpActivity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
", ftpActivityType=" + ftpActivityType +
|
||||
", command='" + command + '\'' +
|
||||
", reply='" + reply + '\'' +
|
||||
", list=" + Arrays.toString(list) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.http;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.dns.DnsActivity;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A high level aggregation of a {@link at.jku.fim.rubanetra.protocol.activity.http.HttpRequestActivity}
|
||||
* and a {@link at.jku.fim.rubanetra.protocol.activity.http.HttpResponseActivity}.
|
||||
* Usually instances of this class are created directly by Drools rules, i.e. a request is matched to a response
|
||||
* by one or several rules.
|
||||
* Additionally, this class defines several optional fields, e.g. a potential preceding Dns-Match to this Http-Activity
|
||||
* and multiple {@link at.jku.fim.rubanetra.protocol.activity.http.HttpImageActivity} objects may be
|
||||
* aggregated as well.
|
||||
*/
|
||||
public class HttpActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = 2723756798789149547L;
|
||||
private final HttpRequestActivity request;
|
||||
private final HttpResponseActivity response;
|
||||
private final Set<HttpImageActivity> imageActivities;
|
||||
private DnsActivity dnsMatch;
|
||||
|
||||
/**
|
||||
* Constructs a new Http-Activity and replaces both, the passed request and the response.
|
||||
*
|
||||
* @param req the request that is followed by ...
|
||||
* @param resp ... the response for the request
|
||||
*/
|
||||
public HttpActivity(HttpRequestActivity req, HttpResponseActivity resp) {
|
||||
super(req);
|
||||
this.request = req;
|
||||
this.response = resp;
|
||||
this.dnsMatch = null;
|
||||
this.imageActivities = new HashSet<>();
|
||||
replaceActivity(req);
|
||||
replaceActivity(resp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Http response for the {@link #getRequest()}
|
||||
*/
|
||||
public HttpResponseActivity getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Http request preceding the {@link #getResponse()}
|
||||
*/
|
||||
public HttpRequestActivity getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interpretation of this field depends on the actual specification of the rule that filled this variable in the
|
||||
* first place.
|
||||
* @return a potential DNS-based query leading to the represented Http request/response
|
||||
*/
|
||||
public DnsActivity getDnsMatch() {
|
||||
return dnsMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling this method results in the following actions:
|
||||
* <ul>
|
||||
* <li>if this method was called previously, the old dnsMatch object is will no longer considered to be a
|
||||
* replaced activity and the assigned frames are removed from the frame set</li>
|
||||
* <li>the dnsMatch reference is saved and the DNS activity will be replaced</li>
|
||||
* </ul>
|
||||
* @param dnsMatch a DNS activity that potentially led to this HTTP activity (speculative)
|
||||
*/
|
||||
public void setDnsMatch(DnsActivity dnsMatch) {
|
||||
if (this.dnsMatch != null) {
|
||||
super.removeReplacedActivity(this.dnsMatch);
|
||||
}
|
||||
this.dnsMatch = dnsMatch;
|
||||
replaceActivity(dnsMatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* The interpretation of this field depends on the actual definition of the Drools rules that will fill this set.
|
||||
* @return a collection of activities that potentially originated from this HTTP activity.
|
||||
*/
|
||||
public Set<HttpImageActivity> getImageActivities() {
|
||||
return Collections.unmodifiableSet(imageActivities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds and replaces a Http image activity which origins may be considered to lie within this HTTP activity.
|
||||
* The image activities are currently excluded from output, unless this is overridden manually.
|
||||
* @param imgAct a image activity that was caused by this HTTP activity
|
||||
*/
|
||||
public void addImageActivity(HttpImageActivity imgAct) {
|
||||
if (this.imageActivities.add(imgAct)) {
|
||||
replaceActivity(imgAct);
|
||||
imgAct.setExcludedFromOutput(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
if(getRequest() != null) {
|
||||
return String.valueOf(getRequest().getClientAddress());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
if(getRequest() != null) {
|
||||
return String.valueOf(getRequest().getServerAddress());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpActivity{" +
|
||||
"request=" + request +
|
||||
", response=" + response +
|
||||
", imageActivities=" + imageActivities +
|
||||
", dnsMatch=" + dnsMatch +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.http;
|
||||
|
||||
|
||||
import org.apache.http.HttpHeaders;
|
||||
|
||||
/**
|
||||
* The following header definitions were taken from the {@link org.apache.http.HttpHeaders} (released
|
||||
* under the Apache 2.0 license) class and wrapped into an enumeration to
|
||||
* provide a simple canonicalization method which constitutes a workaround
|
||||
* for the missing normalization of Kraken HTTP header fields (see
|
||||
* {@link org.krakenapps.pcap.decoder.http.HttpHeaders}).
|
||||
* This enum is also used directly inside Drools rule definitions.
|
||||
*/
|
||||
public enum HttpHeader {
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.1
|
||||
*/
|
||||
ACCEPT(HttpHeaders.ACCEPT),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.2
|
||||
*/
|
||||
ACCEPT_CHARSET(HttpHeaders.ACCEPT_CHARSET),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.3
|
||||
*/
|
||||
ACCEPT_ENCODING(HttpHeaders.ACCEPT_ENCODING),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.4
|
||||
*/
|
||||
ACCEPT_LANGUAGE(HttpHeaders.ACCEPT_LANGUAGE),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.5
|
||||
*/
|
||||
ACCEPT_RANGES(HttpHeaders.ACCEPT_RANGES),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.6
|
||||
*/
|
||||
AGE(HttpHeaders.AGE),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.1, RFC 2616 (HTTP/1.1) Section 14.7
|
||||
*/
|
||||
ALLOW(HttpHeaders.ALLOW),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.2, RFC 2616 (HTTP/1.1) Section 14.8
|
||||
*/
|
||||
AUTHORIZATION(HttpHeaders.AUTHORIZATION),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.9
|
||||
*/
|
||||
CACHE_CONTROL(HttpHeaders.CACHE_CONTROL),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.10
|
||||
*/
|
||||
CONNECTION(HttpHeaders.CONNECTION),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.3, RFC 2616 (HTTP/1.1) Section 14.11
|
||||
*/
|
||||
CONTENT_ENCODING(HttpHeaders.CONTENT_ENCODING),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.12
|
||||
*/
|
||||
CONTENT_LANGUAGE(HttpHeaders.CONTENT_LANGUAGE),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.4, RFC 2616 (HTTP/1.1) Section 14.13
|
||||
*/
|
||||
CONTENT_LENGTH(HttpHeaders.CONTENT_LENGTH),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.14
|
||||
*/
|
||||
CONTENT_LOCATION(HttpHeaders.CONTENT_LOCATION),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.15
|
||||
*/
|
||||
CONTENT_MD5(HttpHeaders.CONTENT_MD5),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.16
|
||||
*/
|
||||
CONTENT_RANGE(HttpHeaders.CONTENT_RANGE),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.5, RFC 2616 (HTTP/1.1) Section 14.17
|
||||
*/
|
||||
CONTENT_TYPE(HttpHeaders.CONTENT_TYPE),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.6, RFC 2616 (HTTP/1.1) Section 14.18
|
||||
*/
|
||||
DATE(HttpHeaders.DATE),
|
||||
|
||||
/**
|
||||
* RFC 2518 (WevDAV) Section 9.1
|
||||
*/
|
||||
DAV(HttpHeaders.DAV),
|
||||
|
||||
/**
|
||||
* RFC 2518 (WevDAV) Section 9.2
|
||||
*/
|
||||
DEPTH(HttpHeaders.DEPTH),
|
||||
|
||||
/**
|
||||
* RFC 2518 (WevDAV) Section 9.3
|
||||
*/
|
||||
DESTINATION(HttpHeaders.DESTINATION),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.19
|
||||
*/
|
||||
ETAG(HttpHeaders.ETAG),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.20
|
||||
*/
|
||||
EXPECT(HttpHeaders.EXPECT),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.7, RFC 2616 (HTTP/1.1) Section 14.21
|
||||
*/
|
||||
EXPIRES(HttpHeaders.EXPIRES),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.8, RFC 2616 (HTTP/1.1) Section 14.22
|
||||
*/
|
||||
FROM(HttpHeaders.FROM),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.23
|
||||
*/
|
||||
HOST(HttpHeaders.HOST),
|
||||
|
||||
/**
|
||||
* RFC 2518 (WevDAV) Section 9.4
|
||||
*/
|
||||
IF(HttpHeaders.IF),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.24
|
||||
*/
|
||||
IF_MATCH(HttpHeaders.IF_MATCH),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.9, RFC 2616 (HTTP/1.1) Section 14.25
|
||||
*/
|
||||
IF_MODIFIED_SINCE(HttpHeaders.IF_MODIFIED_SINCE),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.26
|
||||
*/
|
||||
IF_NONE_MATCH(HttpHeaders.IF_NONE_MATCH),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.27
|
||||
*/
|
||||
IF_RANGE(HttpHeaders.IF_RANGE),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.28
|
||||
*/
|
||||
IF_UNMODIFIED_SINCE(HttpHeaders.IF_UNMODIFIED_SINCE),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.10, RFC 2616 (HTTP/1.1) Section 14.29
|
||||
*/
|
||||
LAST_MODIFIED(HttpHeaders.LAST_MODIFIED),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.11, RFC 2616 (HTTP/1.1) Section 14.30
|
||||
*/
|
||||
LOCATION(HttpHeaders.LOCATION),
|
||||
|
||||
/**
|
||||
* RFC 2518 (WevDAV) Section 9.5
|
||||
*/
|
||||
LOCK_TOKEN(HttpHeaders.LOCK_TOKEN),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.31
|
||||
*/
|
||||
MAX_FORWARDS(HttpHeaders.MAX_FORWARDS),
|
||||
|
||||
/**
|
||||
* RFC 2518 (WevDAV) Section 9.6
|
||||
*/
|
||||
OVERWRITE(HttpHeaders.OVERWRITE),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.12, RFC 2616 (HTTP/1.1) Section 14.32
|
||||
*/
|
||||
PRAGMA(HttpHeaders.PRAGMA),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.33
|
||||
*/
|
||||
PROXY_AUTHENTICATE(HttpHeaders.PROXY_AUTHENTICATE),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.34
|
||||
*/
|
||||
PROXY_AUTHORIZATION(HttpHeaders.PROXY_AUTHORIZATION),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.35
|
||||
*/
|
||||
RANGE(HttpHeaders.RANGE),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.13, RFC 2616 (HTTP/1.1) Section 14.36
|
||||
*/
|
||||
REFERER(HttpHeaders.REFERER),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.37
|
||||
*/
|
||||
RETRY_AFTER(HttpHeaders.RETRY_AFTER),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.14, RFC 2616 (HTTP/1.1) Section 14.38
|
||||
*/
|
||||
SERVER(HttpHeaders.SERVER),
|
||||
|
||||
/**
|
||||
* RFC 2518 (WevDAV) Section 9.7
|
||||
*/
|
||||
STATUS_URI(HttpHeaders.STATUS_URI),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.39
|
||||
*/
|
||||
TE(HttpHeaders.TE),
|
||||
|
||||
/**
|
||||
* RFC 2518 (WevDAV) Section 9.8
|
||||
*/
|
||||
TIMEOUT(HttpHeaders.TIMEOUT),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.40
|
||||
*/
|
||||
TRAILER(HttpHeaders.TRAILER),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.41
|
||||
*/
|
||||
TRANSFER_ENCODING(HttpHeaders.TRANSFER_ENCODING),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.42
|
||||
*/
|
||||
UPGRADE(HttpHeaders.UPGRADE),
|
||||
|
||||
/**
|
||||
* RFC 1945 (HTTP/1.0) Section 10.15, RFC 2616 (HTTP/1.1) Section 14.43
|
||||
*/
|
||||
USER_AGENT(HttpHeaders.USER_AGENT),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.44
|
||||
*/
|
||||
VARY(HttpHeaders.VARY),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.45
|
||||
*/
|
||||
VIA(HttpHeaders.VIA),
|
||||
|
||||
/**
|
||||
* RFC 2616 (HTTP/1.1) Section 14.46
|
||||
*/
|
||||
WARNING(HttpHeaders.WARNING), WWW_AUTHENTICATE(HttpHeaders.WWW_AUTHENTICATE);
|
||||
|
||||
private final String name;
|
||||
|
||||
HttpHeader(String httpHeader) {
|
||||
this.name = httpHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalizes a header as encountered by various decoders, i.e. it takes a String, representative for a header,
|
||||
* and tries to return an enumeration object instead.
|
||||
* This method should be considered both, inefficient and potentially unreliable, because it does not remove any
|
||||
* whitespace nor does handle encoding issues.
|
||||
* A simple equalsIgnoreCase is performed against the header enum and the passed String.
|
||||
*
|
||||
* @param wildHeader a non-null String that represent a HTTP header field key
|
||||
* @return a enum object representing the header
|
||||
* @throws java.lang.IllegalArgumentException if no header was found for wildHeader or wildHeader is a null pointer
|
||||
*/
|
||||
public static HttpHeader canonicalizeHeader(String wildHeader) {
|
||||
if (wildHeader != null) {
|
||||
for (HttpHeader h : HttpHeader.values()) {
|
||||
if (wildHeader.equalsIgnoreCase(h.name)) {
|
||||
return h;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.http;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
|
||||
/**
|
||||
* Represents a deduction that was performed by rule-based reasoning that resulted in the fact that the encountered
|
||||
* a {@link at.jku.fim.rubanetra.protocol.activity.http.HttpActivity}-headers contained image-related
|
||||
* metadata.
|
||||
* This class should be considered a convenience class that tries to simplify the collection of derived information
|
||||
* by the Drools rule specifications.
|
||||
*/
|
||||
public class HttpImageActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -6487431475099739380L;
|
||||
private String imageType;
|
||||
private String imagePath;
|
||||
|
||||
public HttpImageActivity(HttpActivity httpActivity) {
|
||||
super(httpActivity);
|
||||
imagePath = null;
|
||||
imageType = null;
|
||||
extendActivity(httpActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type or format of the image as encountered or derived
|
||||
*/
|
||||
public String getImageType() {
|
||||
return imageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param imageType the type or format of the image to set
|
||||
*/
|
||||
public void setImageType(String imageType) {
|
||||
this.imageType = imageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the absolute or relative path of the image as encountered or derived
|
||||
*/
|
||||
public String getImagePath() {
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param imagePath the path of the image to set
|
||||
*/
|
||||
public void setImagePath(String imagePath) {
|
||||
this.imagePath = imagePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpImageActivity{" +
|
||||
"imageType='" + imageType + '\'' +
|
||||
", imagePath='" + imagePath + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.http;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.tcpip.Http;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
import org.krakenapps.pcap.decoder.http.HttpMethod;
|
||||
import org.krakenapps.pcap.decoder.http.HttpRequest;
|
||||
import org.krakenapps.pcap.decoder.http.HttpVersion;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Encapsulates a {@link org.krakenapps.pcap.decoder.http.HttpRequest}, that was decoded by the Kraken library.
|
||||
* The goal of this class is to provide a read-only interface to the encountered Http-related information, however,
|
||||
* currently the actual content buffer that was used by the decoder can both be read from and written to.
|
||||
* Furthermore, a JNetPcap representation is provided in addition to the Kraken-representation.
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public class HttpRequestActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -8446692870521248194L;
|
||||
private final HttpVersion httpVersion;
|
||||
private final InetSocketAddress serverAddress;
|
||||
private final InetSocketAddress clientAddress;
|
||||
private final HttpMethod httpMethod;
|
||||
private final String httpQueryString;
|
||||
private final List<NameValuePair> httpQueryParameters;
|
||||
private final Map<String, String> requestHeaderMap;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final URL url;
|
||||
private final Http httpRequest;
|
||||
|
||||
/**
|
||||
* Constructs a new request activity and replaces the pcap source activity on which this event occurred.
|
||||
* It decodes the query parameters using the default Charset and {@link org.apache.http.client.utils.URLEncodedUtils}.
|
||||
*
|
||||
* @param source the Pcap activity on which this activity occurred
|
||||
* @param request the decoded Http request
|
||||
*/
|
||||
public HttpRequestActivity(PcapActivity source, HttpRequest request) {
|
||||
super(source);
|
||||
this.requestHeaderMap = new HashMap<>();
|
||||
for (String headerKey : request.getHeaderKeys()) {
|
||||
try {
|
||||
HttpHeader canonicalHeader = HttpHeader.canonicalizeHeader(headerKey);
|
||||
requestHeaderMap.put(canonicalHeader.toString(), request.getHeader(headerKey));
|
||||
} catch (IllegalArgumentException e) {
|
||||
requestHeaderMap.put(headerKey, request.getHeader(headerKey));
|
||||
}
|
||||
}
|
||||
httpVersion = request.getHttpVersion();
|
||||
serverAddress = request.getLocalAddress();
|
||||
clientAddress = request.getRemoteAddress();
|
||||
httpMethod = request.getMethod();
|
||||
httpQueryString = request.getQueryString();
|
||||
httpQueryParameters = URLEncodedUtils.parse(httpQueryString, Charset.defaultCharset());
|
||||
pcapActivity = source;
|
||||
url = request.getURL();
|
||||
|
||||
httpRequest = new Http();
|
||||
scanAndFillHttpRequest();
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
private void scanAndFillHttpRequest() {
|
||||
PcapPacket packet = pcapActivity.getPcapPacket();
|
||||
packet.hasHeader(getHttpRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Kraken-specific representation of the version field
|
||||
*/
|
||||
public HttpVersion getHttpVersion() {
|
||||
return httpVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the destination address (Layer 3 and 4)
|
||||
*/
|
||||
public InetSocketAddress getServerAddress() {
|
||||
return serverAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source address (Layer 3 and 4)
|
||||
*/
|
||||
public InetSocketAddress getClientAddress() {
|
||||
return clientAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Kraken-specific representation of the method field
|
||||
*/
|
||||
public HttpMethod getHttpMethod() {
|
||||
return httpMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the unmodified query string
|
||||
*/
|
||||
public String getHttpQueryString() {
|
||||
return httpQueryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a collection of the decoded query-parameters (using the default charset)
|
||||
*/
|
||||
public List<NameValuePair> getHttpQueryParameters() {
|
||||
return Collections.unmodifiableList(httpQueryParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key the header key
|
||||
* @return the value for the key, or null if the key was not defined
|
||||
*/
|
||||
public String getRequestHeader(String key) {
|
||||
return this.requestHeaderMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an unmodifiable collection containing all header keys and values
|
||||
*/
|
||||
public Map<String, String> getRequestHeaderMap() {
|
||||
return Collections.unmodifiableMap(requestHeaderMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an URL representation of the destination resource
|
||||
*/
|
||||
public URL getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JNetPcap specific representation of the request, if available
|
||||
*/
|
||||
public Http getHttpRequest() {
|
||||
return httpRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return String.valueOf(getClientAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return String.valueOf(getServerAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpRequestActivity{" +
|
||||
"httpVersion=" + httpVersion +
|
||||
", serverAddress=" + serverAddress +
|
||||
", clientAddress=" + clientAddress +
|
||||
", httpMethod=" + httpMethod +
|
||||
", httpQueryString='" + httpQueryString + '\'' +
|
||||
", httpQueryParameters=" + httpQueryParameters +
|
||||
", requestHeaderMap=" + requestHeaderMap +
|
||||
", pcapActivity=" + pcapActivity +
|
||||
", url=" + url +
|
||||
", httpRequest=" + httpRequest +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.http;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.tcpip.Http;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.krakenapps.pcap.decoder.http.HttpResponse;
|
||||
import org.krakenapps.pcap.decoder.http.HttpVersion;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Encapsulates a {@link org.krakenapps.pcap.decoder.http.HttpResponse}, that was decoded by the Kraken library.
|
||||
* The goal of this class is to provide a read-only interface to the encountered Http-related information, however,
|
||||
* currently the actual content buffer that was used by the decoder can both be read from and written to.
|
||||
* Furthermore, a JNetPcap representation is provided in addition to the Kraken-representation.
|
||||
*/
|
||||
@Role(Role.Type.EVENT)
|
||||
public class HttpResponseActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = 8779177553506884946L;
|
||||
private final HttpVersion httpVersion;
|
||||
private final int responseStatusCode;
|
||||
private final String responseStatusLine;
|
||||
private final Map<String, String> responseHeaderMap;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final Http httpResponse;
|
||||
|
||||
/**
|
||||
* Constructs a new response activity and replaces the source pcap activity on which this event occurred.
|
||||
* Tries to canonicalize the encountered headers using
|
||||
* {@link at.jku.fim.rubanetra.protocol.activity.http.HttpHeader}, if it fails
|
||||
* the failed header is stored as encountered.
|
||||
*
|
||||
* @param source the pcap activity on which this event occurred
|
||||
* @param response the Http response, decoded by the Kraken library
|
||||
*/
|
||||
public HttpResponseActivity(PcapActivity source, HttpResponse response) {
|
||||
super(source);
|
||||
this.responseHeaderMap = new HashMap<>();
|
||||
for (String headerKey : response.getHeaderKeys()) {
|
||||
try {
|
||||
HttpHeader canonicalHeader = HttpHeader.canonicalizeHeader(headerKey);
|
||||
responseHeaderMap.put(canonicalHeader.toString(), response.getHeader(headerKey));
|
||||
} catch (IllegalArgumentException e) {
|
||||
responseHeaderMap.put(headerKey, response.getHeader(headerKey));
|
||||
}
|
||||
}
|
||||
httpVersion = response.getHttpVersion();
|
||||
responseStatusCode = response.getStatusCode();
|
||||
responseStatusLine = response.getStatusLine();
|
||||
pcapActivity = source;
|
||||
|
||||
httpResponse = new Http();
|
||||
scanAndFillHttpResponse();
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
private void scanAndFillHttpResponse() {
|
||||
PcapPacket packet = pcapActivity.getPcapPacket();
|
||||
packet.hasHeader(getHttpResponse());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Kraken specific representation of the Http version field
|
||||
*/
|
||||
public HttpVersion getHttpVersion() {
|
||||
return httpVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the HTTP response code as encountered
|
||||
*/
|
||||
public int getResponseStatusCode() {
|
||||
return responseStatusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Http response status line as encountered
|
||||
*/
|
||||
public String getResponseStatusLine() {
|
||||
return responseStatusLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an unmodifiable collection containing the decoded headers
|
||||
*/
|
||||
public Map<String, String> getResponseHeaderMap() {
|
||||
return Collections.unmodifiableMap(responseHeaderMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JNetPcap specific representation of the Http response
|
||||
*/
|
||||
public Http getHttpResponse() {
|
||||
return httpResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpResponseActivity{" +
|
||||
"httpVersion=" + httpVersion +
|
||||
", responseStatusCode=" + responseStatusCode +
|
||||
", responseStatusLine='" + responseStatusLine + '\'' +
|
||||
", responseHeaderMap=" + responseHeaderMap +
|
||||
", pcapActivity=" + pcapActivity +
|
||||
", httpResponse=" + httpResponse +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.icmp;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.network.Icmp;
|
||||
import org.jnetpcap.protocol.network.Icmp.IcmpCode;
|
||||
import org.jnetpcap.protocol.network.Icmp.IcmpType;
|
||||
import org.krakenapps.pcap.decoder.icmp.IcmpMessage;
|
||||
import org.krakenapps.pcap.decoder.icmp.IcmpPacket;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* Encapsulates an {@link org.krakenapps.pcap.decoder.icmp.IcmpPacket}.
|
||||
*/
|
||||
public class Icmpv4Activity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -2557140540329408425L;
|
||||
private final int icmpSubType;
|
||||
private final IcmpPacket icmpPacket;
|
||||
private final String icmpMessage;
|
||||
private final PcapActivity pcapActivity;
|
||||
|
||||
private final IcmpType icmpType;
|
||||
private final IcmpCode icmpCode;
|
||||
|
||||
private final InetAddress sourceAddress;
|
||||
private final InetAddress destinationAddress;
|
||||
private final int identifier;
|
||||
private final int sequence;
|
||||
private final Icmp icmp;
|
||||
|
||||
/**
|
||||
* Constructs a new ICMP activity (IPv4 specific) and replaces the source Pcap activity on which this activity occurred
|
||||
*
|
||||
* @param source the Pcap activity on which this event occurred
|
||||
* @param icmpPacket the Kraken specific representation of an ICMP packet
|
||||
*/
|
||||
public Icmpv4Activity(PcapActivity source, IcmpPacket icmpPacket) {
|
||||
super(source);
|
||||
|
||||
icmpSubType = icmpPacket.getCode();
|
||||
icmpMessage = IcmpMessage.getMessage(icmpPacket.getType(), icmpSubType);
|
||||
sourceAddress = icmpPacket.getSource();
|
||||
destinationAddress = icmpPacket.getDestination();
|
||||
identifier = icmpPacket.getId();
|
||||
sequence = icmpPacket.getSeq();
|
||||
this.icmpPacket = icmpPacket;
|
||||
pcapActivity = source;
|
||||
icmpCode = IcmpCode.valueOf(icmpPacket.getType(), icmpSubType);
|
||||
icmpType = IcmpType.valueOf(icmpPacket.getType());
|
||||
|
||||
icmp = new Icmp();
|
||||
|
||||
scanAndFillIcmp();
|
||||
replaceActivity(source);
|
||||
setExcludedFromOutput(true);
|
||||
}
|
||||
|
||||
private void scanAndFillIcmp() {
|
||||
PcapPacket packet = pcapActivity.getPcapPacket();
|
||||
packet.hasHeader(getIcmp());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Kraken specific representation including content buffer
|
||||
*/
|
||||
public IcmpPacket getIcmpPacket() {
|
||||
return icmpPacket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ICMP message String unaltered
|
||||
*/
|
||||
public String getIcmpMessage() {
|
||||
return icmpMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JNetPcap specific enumeration for the ICMP code
|
||||
*/
|
||||
public IcmpCode getIcmpCode() {
|
||||
return icmpCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JNetPcap specific ICMP Type
|
||||
*/
|
||||
public IcmpType getIcmpType() {
|
||||
return icmpType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ICMP Sub-Type or Code as encountered
|
||||
*/
|
||||
public int getIcmpSubType() {
|
||||
return icmpSubType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return L3/L4 source address
|
||||
*/
|
||||
public InetAddress getSourceAddress() {
|
||||
return sourceAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return L3/L4 destination address
|
||||
*/
|
||||
public InetAddress getDestinationAddress() {
|
||||
return destinationAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the message identifier as is
|
||||
*/
|
||||
public int getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sequence number as is
|
||||
*/
|
||||
public int getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JNetPcap specific ICMP representation if available
|
||||
*/
|
||||
public Icmp getIcmp() {
|
||||
return icmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return String.valueOf(getSourceAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return String.valueOf(getDestinationAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Icmpv4Activity{" +
|
||||
"icmpSubType=" + icmpSubType +
|
||||
", icmpPacket=" + icmpPacket +
|
||||
", icmpMessage='" + icmpMessage + '\'' +
|
||||
", pcapActivity=" + pcapActivity +
|
||||
", icmpType=" + icmpType +
|
||||
", icmpCode=" + icmpCode +
|
||||
", sourceAddress=" + sourceAddress +
|
||||
", destinationAddress=" + destinationAddress +
|
||||
", identifier=" + identifier +
|
||||
", sequence=" + sequence +
|
||||
", icmp=" + icmp +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.icmp;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.network.Icmp;
|
||||
import org.krakenapps.pcap.decoder.icmpv6.Icmpv6Message;
|
||||
import org.krakenapps.pcap.decoder.icmpv6.Icmpv6Packet;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* IPv6 specific class similar to {@link at.jku.fim.rubanetra.protocol.activity.icmp.Icmpv4Activity},
|
||||
* but encapsulates an {@link org.krakenapps.pcap.decoder.icmpv6.Icmpv6Packet} instead.
|
||||
*/
|
||||
public class Icmpv6Activity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = 5042112889089462354L;
|
||||
private final int icmpType;
|
||||
private final int icmpSubType;
|
||||
private final Icmpv6Packet icmpPacket;
|
||||
private final String icmpMessage;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final Icmp icmp;
|
||||
private final InetAddress destinationAddress;
|
||||
private final InetAddress sourceAddress;
|
||||
|
||||
/**
|
||||
* Constructs a new ICMPv6 activity, replacing the source Pcap activity and providing a JNetPcap representation of
|
||||
* the packet.
|
||||
* @param source the event that led to the decoded icmpPacket
|
||||
* @param icmpPacket the ICMP message decoded by Kraken
|
||||
*/
|
||||
public Icmpv6Activity(PcapActivity source, Icmpv6Packet icmpPacket) {
|
||||
super(source);
|
||||
icmpType = icmpPacket.getType();
|
||||
icmpSubType = icmpPacket.getCode();
|
||||
icmpMessage = Icmpv6Message.getMessage(icmpType);
|
||||
sourceAddress = icmpPacket.getSource();
|
||||
destinationAddress = icmpPacket.getDestination();
|
||||
this.icmpPacket = icmpPacket;
|
||||
pcapActivity = source;
|
||||
|
||||
icmp = new Icmp();
|
||||
|
||||
scanAndFillIcmp();
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
private void scanAndFillIcmp() {
|
||||
PcapPacket packet = pcapActivity.getPcapPacket();
|
||||
packet.hasHeader(getIcmp());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type of the ICMP message
|
||||
*/
|
||||
public int getIcmpType() {
|
||||
return icmpType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the subtype of the ICMP message
|
||||
*/
|
||||
public int getIcmpSubType() {
|
||||
return icmpSubType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the related Kraken object, as passed to constructor
|
||||
*/
|
||||
public Icmpv6Packet getIcmpPacket() {
|
||||
return icmpPacket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a String representation for various ICMP messages
|
||||
* @see org.krakenapps.pcap.decoder.icmpv6.Icmpv6Message
|
||||
*/
|
||||
public String getIcmpMessage() {
|
||||
return icmpMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JNetPcap's representation of an ICMP packet
|
||||
*/
|
||||
public Icmp getIcmp() {
|
||||
return icmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return L3/L4 source address
|
||||
*/
|
||||
public InetAddress getSourceAddress() {
|
||||
return sourceAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return L3/L4 destination address
|
||||
*/
|
||||
public InetAddress getDestinationAddress() {
|
||||
return destinationAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return String.valueOf(getSourceAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return String.valueOf(getDestinationAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Icmpv6Activity{" +
|
||||
"icmpType=" + icmpType +
|
||||
", icmpSubType=" + icmpSubType +
|
||||
", icmpPacket=" + icmpPacket +
|
||||
", icmpMessage='" + icmpMessage + '\'' +
|
||||
", pcapActivity=" + pcapActivity +
|
||||
", icmp=" + icmp +
|
||||
", destinationAddress=" + destinationAddress +
|
||||
", sourceAddress=" + sourceAddress +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.icmp;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
|
||||
/**
|
||||
* Represents the derived fact, that both an Echo request and a related Echo reply were encountered.
|
||||
* This activity will be constructed by rule evaluations.
|
||||
* ENHANCEMENT: ICMPv6
|
||||
*/
|
||||
@Role(Type.FACT)
|
||||
public class PingActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -7127689333196188386L;
|
||||
private final Icmpv4Activity request;
|
||||
private final Icmpv4Activity reply;
|
||||
|
||||
/**
|
||||
* Constructs a new Ping activity and replaces both the echo request/reply.
|
||||
* @param request the echo request
|
||||
* @param reply the corresponding and matched echo reply
|
||||
*/
|
||||
public PingActivity(Icmpv4Activity request, Icmpv4Activity reply) {
|
||||
super(request);
|
||||
this.request = request;
|
||||
this.reply = reply;
|
||||
replaceActivity(request);
|
||||
replaceActivity(reply);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the encountered echo request
|
||||
*/
|
||||
public Icmpv4Activity getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the matched echo reply
|
||||
*/
|
||||
public Icmpv4Activity getReply() {
|
||||
return reply;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return getRequest().getSourceAddressAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return getReply().getDestinationAddressAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PingActivity{" +
|
||||
"request=" + request +
|
||||
", reply=" + reply +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.ip;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
import org.krakenapps.pcap.decoder.ip.Ipv4Packet;
|
||||
import org.krakenapps.pcap.decoder.ipv6.Ipv6Packet;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* This class represents the abstraction of {@link at.jku.fim.rubanetra.protocol.activity.ip.Ipv4Activity}
|
||||
* and {@link at.jku.fim.rubanetra.protocol.activity.ip.Ipv6Activity}. Several common attributes
|
||||
* are available through instances of this class, in particular:
|
||||
* <ul>
|
||||
* <li>the protocol version</li>
|
||||
* <li>the protocol type</li>
|
||||
* <li>the source L3 address</li>
|
||||
* <li>the destination L3 address</li>
|
||||
* <li>the source Pcap activity from which this IP packet was derived from</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public abstract class IpActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = 8337666572553550945L;
|
||||
private final int version;
|
||||
private final int protocol;
|
||||
private final InetAddress sourceAddress, destinationAddress;
|
||||
private final PcapActivity pcapActivity;
|
||||
|
||||
/**
|
||||
* IPv4 constructor to be called by subclasses. The source activity will be replaced and this instance will be
|
||||
* excluded from output.
|
||||
*
|
||||
* @param source the source event on which the IPv4 packet was found
|
||||
* @param ipv4Packet the decoded IPv4 packet (Kraken)
|
||||
*/
|
||||
public IpActivity(PcapActivity source, Ipv4Packet ipv4Packet) {
|
||||
super(source);
|
||||
|
||||
this.version = ipv4Packet.getVersion();
|
||||
this.protocol = ipv4Packet.getProtocol();
|
||||
this.sourceAddress = ipv4Packet.getSourceAddress();
|
||||
this.destinationAddress = ipv4Packet.getDestinationAddress();
|
||||
|
||||
this.pcapActivity = source;
|
||||
replaceActivity(source);
|
||||
setExcludedFromOutput(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* IPv6 constructor to be called by subclasses. The source activity will be replaced and this instance will be
|
||||
* excluded from output.
|
||||
*
|
||||
* @param source the source event on which the IPv6 packet was found
|
||||
* @param ipv6Packet the decoded IPv6 packet (Kraken)
|
||||
*/
|
||||
public IpActivity(PcapActivity source, Ipv6Packet ipv6Packet) {
|
||||
super(source);
|
||||
|
||||
this.version = ipv6Packet.getVersion();
|
||||
protocol = ipv6Packet.getNextHeader();
|
||||
sourceAddress = ipv6Packet.getSourceAddress();
|
||||
destinationAddress = ipv6Packet.getDestinationAddress();
|
||||
this.pcapActivity = source;
|
||||
replaceActivity(source);
|
||||
setExcludedFromOutput(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internet protocol version
|
||||
*/
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the protocol type (IPv4) or the next header value (IPv6)
|
||||
*/
|
||||
public int getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the IPv4/IPv6 source address
|
||||
*/
|
||||
public InetAddress getSourceAddress() {
|
||||
return sourceAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the IPv4/IPv6 destination address
|
||||
*/
|
||||
public InetAddress getDestinationAddress() {
|
||||
return destinationAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return String.valueOf(getSourceAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return String.valueOf(getDestinationAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IpActivity{" +
|
||||
"version=" + version +
|
||||
", protocol=" + protocol +
|
||||
", sourceAddress=" + sourceAddress +
|
||||
", destinationAddress=" + destinationAddress +
|
||||
", pcapActivity=" + pcapActivity +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.ip;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.network.Ip4;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
import org.krakenapps.pcap.decoder.ip.Ipv4Packet;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Encapsulates all available/decoded IPv4 packet fields and provides a compatible JNetPcap
|
||||
* {@link org.jnetpcap.protocol.network.Ip4} object.
|
||||
* Instances of this class are excluded from output by default in order to decrease verbosity,
|
||||
* {@link #setExcludedFromOutput(boolean)} may be called to change this behaviour.
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public class Ipv4Activity extends IpActivity {
|
||||
private static final long serialVersionUID = -7231432195268189132L;
|
||||
private final int internetHeaderLength;
|
||||
private final int differentiatedServicesCodePoint;
|
||||
private final int totalLength;
|
||||
private final int identification;
|
||||
private final int flags;
|
||||
private final int fragmentOffset;
|
||||
private final int timeToLive;
|
||||
private final int headerChecksum;
|
||||
private final byte[] options;
|
||||
|
||||
private final Ip4 ipv4;
|
||||
|
||||
/**
|
||||
* Constructs a new IPv4 activity that will not be included in the final output. The source pcap activity will be
|
||||
* replaced and the packet fields encapsulated.
|
||||
* @param source the Pcap activity from which this packet was decoded (final one, if fragmented).
|
||||
* @param ipv4Packet the decoded IPv4 packet (Kraken)
|
||||
*/
|
||||
public Ipv4Activity(PcapActivity source, Ipv4Packet ipv4Packet) {
|
||||
super(source, ipv4Packet);
|
||||
|
||||
this.internetHeaderLength = ipv4Packet.getIhl();
|
||||
this.differentiatedServicesCodePoint = ipv4Packet.getTos();
|
||||
this.totalLength = ipv4Packet.getTotalLength();
|
||||
this.identification = ipv4Packet.getId();
|
||||
this.flags = ipv4Packet.getFlags();
|
||||
this.fragmentOffset = ipv4Packet.getFragmentOffset();
|
||||
this.timeToLive = ipv4Packet.getTtl();
|
||||
this.headerChecksum = ipv4Packet.getHeaderChecksum();
|
||||
this.options = ipv4Packet.getOptions();
|
||||
|
||||
PcapPacket pcap = source.getPcapPacket();
|
||||
|
||||
ipv4 = new Ip4();
|
||||
pcap.hasHeader(ipv4);
|
||||
replaceActivity(source);
|
||||
setExcludedFromOutput(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.IllegalStateException since it is not yet implemented
|
||||
*/
|
||||
public int getExplicitCongestionNotification() {
|
||||
throw new IllegalStateException("Not yet implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the length of the IPv4 packet header in bytes
|
||||
*/
|
||||
public int getInternetHeaderLength() {
|
||||
return internetHeaderLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the differentiated services code point value
|
||||
*/
|
||||
public int getDifferentiatedServicesCodePoint() {
|
||||
return differentiatedServicesCodePoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the total packet size in bytes
|
||||
*/
|
||||
public int getTotalLength() {
|
||||
return totalLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the identification value
|
||||
*/
|
||||
public int getIdentification() {
|
||||
return identification;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the flags combined in one integer
|
||||
*/
|
||||
public int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fragment offset value
|
||||
*/
|
||||
public int getFragmentOffset() {
|
||||
return fragmentOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the TTL value
|
||||
*/
|
||||
public int getTimeToLive() {
|
||||
return timeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the checksum
|
||||
*/
|
||||
public int getHeaderChecksum() {
|
||||
return headerChecksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the options as encountered
|
||||
*/
|
||||
public byte[] getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JNetPcap representation of the IPv4 packet iff available, null otherwise (e.g. if the packet is
|
||||
* fragmented)
|
||||
*/
|
||||
public Ip4 getIpv4() {
|
||||
return ipv4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Ipv4Activity{" +
|
||||
"internetHeaderLength=" + internetHeaderLength +
|
||||
", differentiatedServicesCodePoint=" + differentiatedServicesCodePoint +
|
||||
", totalLength=" + totalLength +
|
||||
", identification=" + identification +
|
||||
", flags=" + flags +
|
||||
", fragmentOffset=" + fragmentOffset +
|
||||
", timeToLive=" + timeToLive +
|
||||
", headerChecksum=" + headerChecksum +
|
||||
", options=" + Arrays.toString(options) +
|
||||
", ipv4=" + ipv4 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.ip;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.network.Ip6;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
import org.krakenapps.pcap.decoder.ipv6.Ipv6Packet;
|
||||
|
||||
/**
|
||||
* Encapsulates certain IPv6 packet fields, and provides a compatible JNetPcap representation
|
||||
* ({@link org.jnetpcap.protocol.network.Ip6}) of the packet.
|
||||
* By default, instances of this class will be excluded from the final output due to verbosity,
|
||||
* {@link #setExcludedFromOutput(boolean)} may be called to change this behaviour.
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public class Ipv6Activity extends IpActivity {
|
||||
private static final long serialVersionUID = 6406883861304202335L;
|
||||
private final byte trafficClass;
|
||||
private final int flowLabel;
|
||||
private final int payloadLength;
|
||||
private final byte nextHeader;
|
||||
private final int hopLimit;
|
||||
|
||||
private final Ip6 ipv6;
|
||||
private final Ipv6Packet ipv6Packet;
|
||||
|
||||
/**
|
||||
* Construct a new IPv6 activity and replaces the source Pcap activity on which this activity occurred,
|
||||
*
|
||||
* @param source the Pcap activity on which this event occurred.
|
||||
* @param ipv6Packet the decoded IPv6 packet (Kraken)
|
||||
*/
|
||||
public Ipv6Activity(PcapActivity source, Ipv6Packet ipv6Packet) {
|
||||
super(source, ipv6Packet);
|
||||
this.ipv6Packet = ipv6Packet;
|
||||
|
||||
trafficClass = ipv6Packet.getTrafficClass();
|
||||
flowLabel = ipv6Packet.getFlowLabel();
|
||||
payloadLength = ipv6Packet.getPayloadLength();
|
||||
nextHeader = ipv6Packet.getNextHeader();
|
||||
hopLimit = ipv6Packet.getHopLimit();
|
||||
|
||||
PcapPacket pcap = source.getPcapPacket();
|
||||
ipv6 = new Ip6();
|
||||
pcap.hasHeader(ipv6);
|
||||
replaceActivity(source);
|
||||
setExcludedFromOutput(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the traffic class value
|
||||
*/
|
||||
public byte getTrafficClass() {
|
||||
return trafficClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the flow label value
|
||||
*/
|
||||
public int getFlowLabel() {
|
||||
return flowLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of the payload in bytes
|
||||
*/
|
||||
public int getPayloadLength() {
|
||||
return payloadLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the next header value, redundant to {@link #getProtocol()}
|
||||
*/
|
||||
public byte getNextHeader() {
|
||||
return nextHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Hop limit value
|
||||
*/
|
||||
public int getHopLimit() {
|
||||
return hopLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JNetPcap representation of an IPv6 packet, if available. null otherwise
|
||||
*/
|
||||
public Ip6 getIpv6() {
|
||||
return ipv6;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the original Kraken IPv6 packet representation
|
||||
*/
|
||||
public Ipv6Packet getIpv6Packet() {
|
||||
return ipv6Packet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Ipv6Activity{" +
|
||||
"trafficClass=" + trafficClass +
|
||||
", flowLabel=" + flowLabel +
|
||||
", payloadLength=" + payloadLength +
|
||||
", nextHeader=" + nextHeader +
|
||||
", hopLimit=" + hopLimit +
|
||||
", ipv6=" + ipv6 +
|
||||
", ipv6Packet=" + ipv6Packet +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.msn;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
|
||||
/**
|
||||
* Encapsulates MSN chat messages.
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public class MsnActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -4422657387707609350L;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final String account;
|
||||
private final String chat;
|
||||
|
||||
/**
|
||||
* Constructs a new MSN chat activity, replaces the source pcap activity on which this event occurred.
|
||||
* @param source the source event on which this activity occurred
|
||||
* @param account the account name that was used for the chat
|
||||
* @param chat the chat message
|
||||
*/
|
||||
public MsnActivity(PcapActivity source, String account, String chat) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
this.account = account;
|
||||
this.chat = chat;
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the account name used for chatting
|
||||
*/
|
||||
public String getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the chat message
|
||||
*/
|
||||
public String getChat() {
|
||||
return chat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return getAccount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MsnActivity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
", account='" + account + '\'' +
|
||||
", chat='" + chat + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.netbios;
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.krakenapps.pcap.decoder.netbios.NetBiosDatagramPacket;
|
||||
import org.krakenapps.pcap.decoder.netbios.NetBiosNamePacket;
|
||||
|
||||
/**
|
||||
* Encapsulates {@link org.krakenapps.pcap.decoder.netbios.NetBiosDatagramPacket}s.
|
||||
*/
|
||||
public class NetbiosActivity extends AbstractReplaceableActivity {
|
||||
private final PcapActivity pcapActivity;
|
||||
private final NetBiosNamePacket namePacket;
|
||||
private final NetBiosDatagramPacket datagramPacket;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical Event.
|
||||
*
|
||||
* @param source The object on which the Event initially occurred (will be replaced).
|
||||
* @throws IllegalArgumentException if source is null.
|
||||
*/
|
||||
public NetbiosActivity(PcapActivity source, NetBiosDatagramPacket datagramPacket) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
this.datagramPacket = datagramPacket;
|
||||
this.namePacket = null;
|
||||
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a prototypical Event.
|
||||
*
|
||||
* @param source The object on which the Event initially occurred (will be replaced).
|
||||
* @throws IllegalArgumentException if source is null.
|
||||
*/
|
||||
public NetbiosActivity(PcapActivity source, NetBiosNamePacket namePacket) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
this.namePacket = namePacket;
|
||||
this.datagramPacket = null;
|
||||
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded packet (by Kraken)
|
||||
*/
|
||||
public NetBiosNamePacket getNamePacket() {
|
||||
return namePacket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the original decoded datagram.
|
||||
*/
|
||||
public NetBiosDatagramPacket getDatagramPacket() {
|
||||
return datagramPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NetbiosActivity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
", namePacket=" + namePacket +
|
||||
", datagramPacket=" + datagramPacket +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.pop3;
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.krakenapps.mime.MimeHeader;
|
||||
import org.krakenapps.pcap.decoder.pop3.Pop3Data;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: this class represents a partial Pop3-Activity, i.e. it should be reassembled by drools into a single session
|
||||
* TODO: based on the source/destination socket addresses
|
||||
*/
|
||||
public class Pop3Activity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = 5803080617646591389L;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final Type subType;
|
||||
/**
|
||||
* RECEIVE partial Type fields: header, data
|
||||
*/
|
||||
private MimeHeader header;
|
||||
private Pop3Data data;
|
||||
|
||||
/**
|
||||
* COMMAND partial Type field: command
|
||||
*/
|
||||
private String command;
|
||||
|
||||
/**
|
||||
* RESPONSE partial Type field: response
|
||||
*/
|
||||
private String response;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical Event.
|
||||
*
|
||||
* @param source The object on which the Event initially occurred.
|
||||
* @throws IllegalArgumentException if source is null.
|
||||
*/
|
||||
public Pop3Activity(PcapActivity source, Type partialActivityType) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
this.subType = partialActivityType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the subtype of this POP activity
|
||||
*/
|
||||
public Type getSubType() {
|
||||
return subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded {@link org.krakenapps.mime.MimeHeader} if available, null otherwise
|
||||
*/
|
||||
public MimeHeader getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called by {@link at.jku.fim.rubanetra.protocol.handler.KrakenPop3Handler}
|
||||
* in order to build a partial POP session.
|
||||
*
|
||||
* @param header the decoded MIME header.
|
||||
*/
|
||||
public void setHeader(MimeHeader header) {
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded {@link org.krakenapps.pcap.decoder.pop3.Pop3Data} if available, null otherwise
|
||||
*/
|
||||
public Pop3Data getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called by {@link at.jku.fim.rubanetra.protocol.handler.KrakenPop3Handler}
|
||||
* during the decoding process.
|
||||
*
|
||||
* @param data the decoded POP data
|
||||
*/
|
||||
public void setData(Pop3Data data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded command string if available, null otherwise
|
||||
*/
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called by {@link at.jku.fim.rubanetra.protocol.handler.KrakenPop3Handler} in
|
||||
* order to build a partial session during the encoding process.
|
||||
*
|
||||
* @param command the decoded command.
|
||||
*/
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded response message
|
||||
*/
|
||||
public String getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be called by {@link at.jku.fim.rubanetra.protocol.handler.KrakenPop3Handler} in
|
||||
* order to build a partial session during the encoding process.
|
||||
*
|
||||
* @param response the decoded response string
|
||||
*/
|
||||
public void setResponse(String response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
/**
|
||||
* POP3 Activity type of the surrounding object
|
||||
*/
|
||||
public enum Type {
|
||||
RECEIVE, COMMAND, RESPONSE
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pop3Activity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
", subType=" + subType +
|
||||
", header=" + header +
|
||||
", data=" + data +
|
||||
", command='" + command + '\'' +
|
||||
", response='" + response + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.skype;
|
||||
|
||||
|
||||
import org.jnetpcap.protocol.tcpip.Udp;
|
||||
|
||||
/**
|
||||
* This class does not represent an activity but provides some useful static helper methods. Particularly it provides
|
||||
* quite basic byte-based checks whether or not a certain UDP-Payload could indicate the presence of Skype related
|
||||
* traffic.
|
||||
* Additionally, the Skype object ID can be extracted as well.
|
||||
* Those checks are based on the OpenSkype project, see https://github.com/matthiasbock/OpenSkype
|
||||
*/
|
||||
public class SkypeActivityHelper {
|
||||
/**
|
||||
* Returns the Skype object ID, however, since the object ID could be arbitrary this method
|
||||
* does not check whether the payload corresponds to Skype traffic.
|
||||
*
|
||||
* @param udp the JNetPcap UDP packet representation
|
||||
* @return the skype object id
|
||||
* @see #hasSkypePayload(org.jnetpcap.protocol.tcpip.Udp)
|
||||
*/
|
||||
public static int objectId(Udp udp) {
|
||||
if (udp != null && udp.hasPayload() && udp.getPayloadLength() > 3) {
|
||||
return udp.getPacket().getUShort(udp.getPayloadOffset());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #hasSkypeType(org.jnetpcap.protocol.tcpip.Udp, at.jku.fim.rubanetra.protocol.activity.skype.SkypeActivityHelper.SkypeUdpType)}
|
||||
* with the PAYLOAD flag internally (convenience method).
|
||||
*
|
||||
* @param udp the JNetPcap UDP packet representation
|
||||
* @return true, if this UDP packet could contain Skype related traffic
|
||||
*/
|
||||
public static boolean hasSkypePayload(Udp udp) {
|
||||
return hasSkypeType(udp, SkypeUdpType.PAYLOAD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to determine whether or not the provided UDP packet contains data that corresponds to some known
|
||||
* Skype flags. Note however, that these flags may be invalid at any future point in time.
|
||||
*
|
||||
* @param udp the JNetPcap UDP packet representation
|
||||
* @param type the type of the data to check against
|
||||
* @return true, if udp potentially contains data corresponding to type
|
||||
*/
|
||||
public static boolean hasSkypeType(Udp udp, SkypeUdpType type) {
|
||||
if (udp != null && type != null && udp.hasPayload() && udp.getPayloadLength() > 3) {
|
||||
int thirdByte = udp.getPacket().getUByte(udp.getPayloadOffset() + 2);
|
||||
return (thirdByte & 0x0F) == type.getVal();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Several known Skype payload types including their flag value,
|
||||
* based on the OpenSkype project, see https://github.com/matthiasbock/OpenSkype
|
||||
*/
|
||||
public enum SkypeUdpType {
|
||||
PAYLOAD(0x02), RESEND(0x03), CONFIRM(0x5), ERROR(0x7), AUDIO(0xd), FRAGMENT(0xf);
|
||||
|
||||
private final int val;
|
||||
|
||||
SkypeUdpType(int val) {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public int getVal() {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.smtp;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
|
||||
/**
|
||||
* Represents an abstraction for {@link at.jku.fim.rubanetra.protocol.activity.smtp.SmtpCommandActivity},
|
||||
* {@link at.jku.fim.rubanetra.protocol.activity.smtp.SmtpReplyActivity} and
|
||||
* {@link at.jku.fim.rubanetra.protocol.activity.smtp.SmtpSendActivity} that may be used by Drools rules
|
||||
* in order to determine that some SMTP related traffic occurred for a given {@link at.jku.fim.rubanetra.pcap.PcapActivity}.
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public abstract class SmtpActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = 6159462782844297508L;
|
||||
private final PcapActivity pcapActivity;
|
||||
|
||||
/**
|
||||
* Constructs a SMTP activity and replaced the source pcap activity on which this event occurred.
|
||||
*
|
||||
* @param source the pcap activity on which this event occurred
|
||||
*/
|
||||
public SmtpActivity(PcapActivity source) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SmtpActivity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.smtp;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
|
||||
/**
|
||||
* Encapsulates the SMTP command and parameter values.
|
||||
*/
|
||||
public class SmtpCommandActivity extends SmtpActivity {
|
||||
private static final long serialVersionUID = 1579865560446923831L;
|
||||
private final String command;
|
||||
private final String parameter;
|
||||
|
||||
/**
|
||||
* Constructs a new command activity and replaces the source pcap activity.
|
||||
*
|
||||
* @param source the pcap activity on which this event occurred
|
||||
* @param command the command string
|
||||
* @param parameter the parameter value
|
||||
*/
|
||||
public SmtpCommandActivity(PcapActivity source, String command, String parameter) {
|
||||
super(source);
|
||||
this.command = command;
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the command value
|
||||
*/
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the parameter value
|
||||
*/
|
||||
public String getParameter() {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SmtpCommandActivity{" +
|
||||
"command='" + command + '\'' +
|
||||
", parameter='" + parameter + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.smtp;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
|
||||
/**
|
||||
* Encapsulates the SMTP reply code number and the SMTP message.
|
||||
*/
|
||||
public class SmtpReplyActivity extends SmtpActivity {
|
||||
private static final long serialVersionUID = 7746759264444813246L;
|
||||
private final int code;
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* Constructs a new SMTP reply activity and replaces the source pcap activity on which this event occurred initially.
|
||||
*
|
||||
* @param source the pcap activity on which this event occurred.
|
||||
* @param code the code number of the reply
|
||||
* @param message the decoded message itself
|
||||
*/
|
||||
public SmtpReplyActivity(PcapActivity source, int code, String message) {
|
||||
super(source);
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the reply code number
|
||||
*/
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded message
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SmtpReplyActivity{" +
|
||||
"code=" + code +
|
||||
", message='" + message + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.smtp;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import org.krakenapps.mime.MimeHeader;
|
||||
import org.krakenapps.pcap.decoder.smtp.SmtpData;
|
||||
|
||||
/**
|
||||
* Encapsulates the {@link org.krakenapps.mime.MimeHeader} and the {@link org.krakenapps.pcap.decoder.smtp.SmtpData} for
|
||||
* SMTP.
|
||||
*/
|
||||
public class SmtpSendActivity extends SmtpActivity {
|
||||
private static final long serialVersionUID = -5050757703933049654L;
|
||||
private final MimeHeader header;
|
||||
private final SmtpData data;
|
||||
|
||||
/**
|
||||
* Constructs a new Smtp send activity that replaces the source pcap activity on which this event occurred.
|
||||
*
|
||||
* @param source the pcap activity on which the SMTP send activity occurred.
|
||||
* @param header the decoded MIME header
|
||||
* @param data the SMTP data
|
||||
*/
|
||||
public SmtpSendActivity(PcapActivity source, MimeHeader header, SmtpData data) {
|
||||
super(source);
|
||||
this.header = header;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded MIME header (Kraken)
|
||||
*/
|
||||
public MimeHeader getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded SMTP data (Kraken)
|
||||
*/
|
||||
public SmtpData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SmtpSendActivity{" +
|
||||
"header=" + header +
|
||||
", data=" + data +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.snmp;
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.krakenapps.pcap.decoder.snmp.v1.Pdu;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Encapsulates a {@link org.krakenapps.pcap.decoder.snmp.v1.Pdu} object including source and destination
|
||||
* L3/L4 addresses.
|
||||
*/
|
||||
public class Snmpv1Activity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = 398825166451021814L;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final Pdu pdu;
|
||||
private final InetSocketAddress sourceSocketAddress, destinationSocketAddress;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical Event.
|
||||
*
|
||||
* @param source The object on which the Event initially occurred.
|
||||
* @param pdu the decoded {@link org.krakenapps.pcap.decoder.snmp.v1.Pdu}
|
||||
* @param sourceAddress the L3/L4 source address
|
||||
* @param destinationAddress the L3/L4 destination address
|
||||
*/
|
||||
public Snmpv1Activity(PcapActivity source, Pdu pdu, InetSocketAddress sourceAddress, InetSocketAddress destinationAddress) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
this.pdu = pdu;
|
||||
this.sourceSocketAddress = sourceAddress;
|
||||
this.destinationSocketAddress = destinationAddress;
|
||||
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded PDU
|
||||
*/
|
||||
public Pdu getPdu() {
|
||||
return pdu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L3/L4 source address
|
||||
*/
|
||||
public InetSocketAddress getSourceSocketAddress() {
|
||||
return sourceSocketAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L3/L4 destination address
|
||||
*/
|
||||
public InetSocketAddress getDestinationSocketAddress() {
|
||||
return destinationSocketAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return String.valueOf(getSourceSocketAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return String.valueOf(getDestinationSocketAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Snmpv1Activity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
", pdu=" + pdu +
|
||||
", sourceSocketAddress=" + sourceSocketAddress +
|
||||
", destinationSocketAddress=" + destinationSocketAddress +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.snmp;
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.krakenapps.pcap.decoder.snmp.v2.Pdu;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Created by stefan on 3/19/14.
|
||||
*/
|
||||
public class Snmpv2Activity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -5230001535702929422L;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final Pdu pdu;
|
||||
private final InetSocketAddress sourceSocketAddress, destinationSocketAddress;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical Event.
|
||||
*
|
||||
* @param source The object on which the Event initially occurred.
|
||||
* @param pdu the decoded {@link org.krakenapps.pcap.decoder.snmp.v2.Pdu}
|
||||
* @param sourceAddress the L3/L4 source address
|
||||
* @param destinationAddress the L3/L4 destination address
|
||||
*/
|
||||
public Snmpv2Activity(PcapActivity source, Pdu pdu, InetSocketAddress sourceAddress, InetSocketAddress destinationAddress) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
this.pdu = pdu;
|
||||
this.sourceSocketAddress = sourceAddress;
|
||||
this.destinationSocketAddress = destinationAddress;
|
||||
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded PDU
|
||||
*/
|
||||
public Pdu getPdu() {
|
||||
return pdu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L3/L4 source address
|
||||
*/
|
||||
public InetSocketAddress getSourceSocketAddress() {
|
||||
return sourceSocketAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L3/L4 destination address
|
||||
*/
|
||||
public InetSocketAddress getDestinationSocketAddress() {
|
||||
return destinationSocketAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return String.valueOf(getSourceSocketAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return String.valueOf(getDestinationSocketAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Snmpv2Activity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
", pdu=" + pdu +
|
||||
", sourceSocketAddress=" + sourceSocketAddress +
|
||||
", destinationSocketAddress=" + destinationSocketAddress +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.tcp;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.ip.IpActivity;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.packet.format.FormatUtils;
|
||||
import org.jnetpcap.protocol.tcpip.Tcp;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpDirection;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpPacket;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpSession;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpState;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Encapsulates a vast amount of TCP flags/options/values and derived information, however, some fields have not yet
|
||||
* been implemented by the Kraken TCP-Decoder and/or the JNetPcap-decoder. In these cases either a value of -1 or null
|
||||
* is returned instead, e.g. for relative seq/ack numbers or the client/server state or the traffic direction.
|
||||
* Two constructors are provided, one is intended for use by decoded Kraken TCP packets {@link org.krakenapps.pcap.decoder.tcp.TcpPacket}
|
||||
* the other one for the JNetPcap equivalent {@link org.jnetpcap.protocol.tcpip.Tcp}.
|
||||
* However, independent of the used constructor the JNetPcap representation will always be made available if possible.
|
||||
* Instances of this class will not be included in the final output, {@link #setExcludedFromOutput(boolean)} should be
|
||||
* called appropriately to override this behaviour.
|
||||
*/
|
||||
@Role(Role.Type.EVENT)
|
||||
public class TcpActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -2422097413536740312L;
|
||||
private final int sourcePort, destinationPort;
|
||||
private final InetAddress sourceAddress, destinationAddress;
|
||||
private final long sequenceNumber;
|
||||
private final long acknowledgeNumber;
|
||||
private final int relativeSequenceNumber;
|
||||
private final int relativeAcknowledgeNumber;
|
||||
private final int dataOffset;
|
||||
private final int controlBits;
|
||||
private final int windowSize, checksum, urgentPointer, tcpLength;
|
||||
private final byte[] options, padding;
|
||||
private final boolean syn, ack, psh, fin, rst, urg;
|
||||
private final TcpDirection direction;
|
||||
private final TcpState clientState, serverState;
|
||||
|
||||
private final PcapActivity pcapActivity;
|
||||
private final Tcp tcp;
|
||||
private final InetSocketAddress sourceSocketAddress, destinationSocketAddress;
|
||||
|
||||
/**
|
||||
* Constructs a new Tcp activity using the decoded Kraken data. The source pcap activity on which this TCP-activity
|
||||
* occurred will be replaced.
|
||||
*
|
||||
* @param source the final pacp activity that led to a successful decode by the Kraken TCP decoder.
|
||||
* @param tcpPacket the decoded TCP packet data
|
||||
* @param tcpSession the maintained TCP session information (client & server state)
|
||||
*/
|
||||
public TcpActivity(PcapActivity source, TcpPacket tcpPacket, TcpSession tcpSession) {
|
||||
super(source);
|
||||
this.sourcePort = tcpPacket.getSourcePort();
|
||||
this.destinationPort = tcpPacket.getDestinationPort();
|
||||
this.sourceAddress = tcpPacket.getSourceAddress();
|
||||
this.sourceSocketAddress = tcpPacket.getSource();
|
||||
this.destinationAddress = tcpPacket.getDestinationAddress();
|
||||
this.destinationSocketAddress = tcpPacket.getDestination();
|
||||
this.sequenceNumber = tcpPacket.getSeq();
|
||||
this.acknowledgeNumber = tcpPacket.getAck();
|
||||
this.relativeSequenceNumber = tcpPacket.getRelativeSeq();
|
||||
this.relativeAcknowledgeNumber = tcpPacket.getRelativeAck();
|
||||
this.dataOffset = tcpPacket.getDataOffset();
|
||||
this.controlBits = tcpPacket.getFlags();
|
||||
this.windowSize = tcpPacket.getWindow();
|
||||
this.checksum = tcpPacket.getChecksum();
|
||||
this.urgentPointer = tcpPacket.getUrgentPointer();
|
||||
this.options = tcpPacket.getOptions();
|
||||
this.padding = tcpPacket.getPadding();
|
||||
this.tcpLength = tcpPacket.getTotalLength();
|
||||
this.direction = tcpPacket.getDirection();
|
||||
this.syn = tcpPacket.isSyn();
|
||||
this.ack = tcpPacket.isAck();
|
||||
this.psh = tcpPacket.isPsh();
|
||||
this.fin = tcpPacket.isFin();
|
||||
this.rst = tcpPacket.isRst();
|
||||
this.urg = tcpPacket.isUrg();
|
||||
this.clientState = tcpSession.getClientState();
|
||||
this.serverState = tcpSession.getServerState();
|
||||
this.pcapActivity = source;
|
||||
|
||||
this.tcp = new Tcp();
|
||||
PcapPacket packet = pcapActivity.getPcapPacket();
|
||||
packet.hasHeader(tcp);
|
||||
|
||||
replaceActivity(source);
|
||||
setExcludedFromOutput(true);
|
||||
}
|
||||
|
||||
public TcpActivity(PcapActivity source, Tcp tcp, IpActivity ip) {
|
||||
super(source);
|
||||
this.sourcePort = tcp.source();
|
||||
this.destinationPort = tcp.destination();
|
||||
this.sourceAddress = ip.getSourceAddress();
|
||||
this.sourceSocketAddress = new InetSocketAddress(sourceAddress, sourcePort);
|
||||
this.destinationAddress = ip.getDestinationAddress();
|
||||
this.destinationSocketAddress = new InetSocketAddress(destinationAddress, destinationPort);
|
||||
this.sequenceNumber = tcp.seq();
|
||||
this.acknowledgeNumber = tcp.ack();
|
||||
this.relativeSequenceNumber = -1; // TODO: not yet implemented
|
||||
this.relativeAcknowledgeNumber = -1; //TODO: not yet implemented
|
||||
this.dataOffset = tcp.getOffset();
|
||||
this.controlBits = tcp.flags();
|
||||
this.windowSize = tcp.window();
|
||||
this.checksum = tcp.checksum();
|
||||
this.urgentPointer = tcp.urgent();
|
||||
this.tcpLength = tcp.getLength();
|
||||
this.options = null; // TODO: not yet implemented
|
||||
this.padding = null; // TODO: not yet implemented
|
||||
this.syn = tcp.flags_SYN();
|
||||
this.ack = tcp.flags_ACK();
|
||||
this.psh = tcp.flags_PSH();
|
||||
this.fin = tcp.flags_FIN();
|
||||
this.rst = tcp.flags_RST();
|
||||
this.urg = tcp.flags_URG();
|
||||
this.direction = null; // TODO: not yet implemented
|
||||
this.clientState = null; // TODO: not yet implemented
|
||||
this.serverState = null; // TODO: not yet implemented
|
||||
this.pcapActivity = source;
|
||||
this.tcp = tcp;
|
||||
|
||||
replaceActivity(source);
|
||||
setExcludedFromOutput(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L4 source address information
|
||||
* @see #getSourceSocketAddress()
|
||||
*/
|
||||
public int getSourcePort() {
|
||||
return sourcePort;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L4 destination address information
|
||||
* @see #getDestinationSocketAddress()
|
||||
*/
|
||||
public int getDestinationPort() {
|
||||
return destinationPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L3 source address information
|
||||
* @see #getSourceSocketAddress()
|
||||
*/
|
||||
public InetAddress getSourceAddress() {
|
||||
return sourceAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L3/L4 source address information
|
||||
*/
|
||||
public InetSocketAddress getSourceSocketAddress() {
|
||||
return sourceSocketAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L3 destination address information
|
||||
* @see #getDestinationSocketAddress()
|
||||
*/
|
||||
public InetAddress getDestinationAddress() {
|
||||
return destinationAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L3/L4 destination address information
|
||||
*/
|
||||
public InetSocketAddress getDestinationSocketAddress() {
|
||||
return destinationSocketAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded sequence number
|
||||
*/
|
||||
public long getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded ACK number
|
||||
*/
|
||||
public long getAcknowledgeNumber() {
|
||||
return acknowledgeNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded data offset
|
||||
*/
|
||||
public int getDataOffset() {
|
||||
return dataOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the control flags
|
||||
*/
|
||||
public int getControlBits() {
|
||||
return controlBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the parsed window size
|
||||
*/
|
||||
public int getWindowSize() {
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the parsed checksum
|
||||
*/
|
||||
public int getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the parsed urgent pointer value
|
||||
*/
|
||||
public int getUrgentPointer() {
|
||||
return urgentPointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the content of the TCP length field
|
||||
*/
|
||||
public int getTcpLength() {
|
||||
return tcpLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the options as array or null (if the JNetPcap constructor was used)
|
||||
*/
|
||||
public byte[] getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the padding bytes or null (if the JNetPcap constructor was used)
|
||||
*/
|
||||
public byte[] getPadding() {
|
||||
return padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true, if the syn flag is set
|
||||
*/
|
||||
public boolean isSyn() {
|
||||
return syn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true, if the ack flag is set
|
||||
*/
|
||||
public boolean isAck() {
|
||||
return ack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true, if the psh flag is set
|
||||
*/
|
||||
public boolean isPsh() {
|
||||
return psh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true, if the fin flag is set
|
||||
*/
|
||||
public boolean isFin() {
|
||||
return fin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true, if the rst flag is set
|
||||
*/
|
||||
public boolean isRst() {
|
||||
return rst;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true, if the urg flag is set
|
||||
*/
|
||||
public boolean isUrg() {
|
||||
return urg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the direction of this activity, e.g. client->server. may be null if the JNetPcap constructor was used.
|
||||
*/
|
||||
public TcpDirection getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the client state. may be null if the JNetPcap constructor was used.
|
||||
*/
|
||||
public TcpState getClientState() {
|
||||
return this.clientState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the server state. may be null if the JNetPcap constructor was used.
|
||||
*/
|
||||
public TcpState getServerState() {
|
||||
return this.serverState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the relative sequence number (calculated by the Kraken decoder, may be -1 if the JNetPcap constructor
|
||||
* was used)
|
||||
*/
|
||||
public int getRelativeSequenceNumber() {
|
||||
return relativeSequenceNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the relative ack number (calculated by the Kraken decoder, may be -1 if the JNetPcap constructor
|
||||
* was used)
|
||||
*/
|
||||
public int getRelativeAcknowledgeNumber() {
|
||||
return relativeAcknowledgeNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JNetPcap representation of a decoded TCP packet or null, if not available
|
||||
*/
|
||||
@JsonIgnore
|
||||
public Tcp getTcp() {
|
||||
return tcp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the payload as a String, or null if the payload is not available or empty
|
||||
*/
|
||||
public String payloadString() {
|
||||
byte[] payload = tcp.getPayload();
|
||||
return payload != null && payload.length > 0 ? new String(payload) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a formatted Hex dump of the payload or null if the payload is not available or empty
|
||||
* @see org.jnetpcap.packet.format.FormatUtils#hexdump(byte[])
|
||||
*/
|
||||
public String payloadHexFormattedDump() {
|
||||
byte[] payload = tcp.getPayload();
|
||||
return payload != null && payload.length > 0 ? FormatUtils.hexdump(payload) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a Hex dump of the payload or null if the payload is not available or empty
|
||||
* @see org.jnetpcap.packet.format.FormatUtils#hexdump(byte[])
|
||||
*/
|
||||
public String payloadHexString() {
|
||||
byte[] payload = tcp.getPayload();
|
||||
return payload != null && payload.length > 0 ? FormatUtils.asString(payload) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ENHANCEMENT: Crude check based on the source activity should be replaced by a more detailed comparison
|
||||
* since the decoders may not be deterministic.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof TcpActivity && ((TcpActivity) obj).getPcapActivity().equals(getPcapActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return String.valueOf(getSourceAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return String.valueOf(getDestinationAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TcpActivity{" +
|
||||
"sourcePort=" + sourcePort +
|
||||
", destinationPort=" + destinationPort +
|
||||
", sourceAddress=" + sourceAddress +
|
||||
", destinationAddress=" + destinationAddress +
|
||||
", sequenceNumber=" + sequenceNumber +
|
||||
", acknowledgeNumber=" + acknowledgeNumber +
|
||||
", relativeSequenceNumber=" + relativeSequenceNumber +
|
||||
", relativeAcknowledgeNumber=" + relativeAcknowledgeNumber +
|
||||
", dataOffset=" + dataOffset +
|
||||
", controlBits=" + controlBits +
|
||||
", windowSize=" + windowSize +
|
||||
", checksum=" + checksum +
|
||||
", urgentPointer=" + urgentPointer +
|
||||
", tcpLength=" + tcpLength +
|
||||
", options=" + Arrays.toString(options) +
|
||||
", padding=" + Arrays.toString(padding) +
|
||||
", syn=" + syn +
|
||||
", ack=" + ack +
|
||||
", psh=" + psh +
|
||||
", fin=" + fin +
|
||||
", rst=" + rst +
|
||||
", urg=" + urg +
|
||||
", direction=" + direction +
|
||||
", clientState=" + clientState +
|
||||
", serverState=" + serverState +
|
||||
", pcapActivity=" + pcapActivity +
|
||||
", tcp=" + tcp +
|
||||
", sourceSocketAddress=" + sourceSocketAddress +
|
||||
", destinationSocketAddress=" + destinationSocketAddress +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.telnet;
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import org.krakenapps.pcap.decoder.telnet.AnsiMode;
|
||||
import org.krakenapps.pcap.decoder.telnet.TelnetCommand;
|
||||
import org.krakenapps.pcap.decoder.telnet.TelnetOption;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* TODO: partial types -> drools reassembly
|
||||
*/
|
||||
public class TelnetActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -1020544168748948881L;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final Type subType;
|
||||
|
||||
/**
|
||||
* (CLIENT|SERVER)_(COMMAND|ANSICONTROL)
|
||||
*/
|
||||
private TelnetCommand command;
|
||||
/**
|
||||
* (CLIENT|SERVER)_(COMMAND)
|
||||
*/
|
||||
private TelnetOption option;
|
||||
private byte[] data;
|
||||
|
||||
/**
|
||||
* (CLIENT|SERVER)_ANSICONTROL
|
||||
*/
|
||||
private AnsiMode ansiMode;
|
||||
private int[] arguments;
|
||||
|
||||
/**
|
||||
* (CLIENT|SERVER)_DATA
|
||||
*/
|
||||
private String text;
|
||||
|
||||
/**
|
||||
* (CLIENT|SERVER)_TITLE
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical Event.
|
||||
*
|
||||
* @param source The object on which the Event initially occurred (will be replaced).
|
||||
* @param partialActivityType the subtype of this activity (to be reassembled)
|
||||
* @throws IllegalArgumentException if source is null.
|
||||
*/
|
||||
public TelnetActivity(PcapActivity source, Type partialActivityType) {
|
||||
super(source);
|
||||
pcapActivity = source;
|
||||
this.subType = partialActivityType;
|
||||
|
||||
replaceActivity(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the subtype of this activity for reassembly
|
||||
*/
|
||||
public Type getSubType() {
|
||||
return subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded {@link org.krakenapps.pcap.decoder.telnet.TelnetCommand}
|
||||
*/
|
||||
public TelnetCommand getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set by {@link at.jku.fim.rubanetra.protocol.handler.KrakenTelnetHandler}
|
||||
* @param command the decoded {@link org.krakenapps.pcap.decoder.telnet.TelnetCommand}
|
||||
*/
|
||||
public void setCommand(TelnetCommand command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded {@link org.krakenapps.pcap.decoder.telnet.TelnetOption}
|
||||
*/
|
||||
public TelnetOption getOption() {
|
||||
return option;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set by {@link at.jku.fim.rubanetra.protocol.handler.KrakenTelnetHandler}
|
||||
* @param option the decoded {@link org.krakenapps.pcap.decoder.telnet.TelnetOption}
|
||||
*/
|
||||
public void setOption(TelnetOption option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the available telnet data (provided by the decoder)
|
||||
*/
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set by {@link at.jku.fim.rubanetra.protocol.handler.KrakenTelnetHandler}
|
||||
* @param data the telnet data
|
||||
*/
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded {@link org.krakenapps.pcap.decoder.telnet.AnsiMode}
|
||||
*/
|
||||
public AnsiMode getAnsiMode() {
|
||||
return ansiMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set by {@link at.jku.fim.rubanetra.protocol.handler.KrakenTelnetHandler}
|
||||
* @param ansiMode the decoded {@link org.krakenapps.pcap.decoder.telnet.AnsiMode}
|
||||
*/
|
||||
public void setAnsiMode(AnsiMode ansiMode) {
|
||||
this.ansiMode = ansiMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the available telnet arguments
|
||||
* @see org.krakenapps.pcap.decoder.telnet.TelnetDecoder
|
||||
*/
|
||||
public int[] getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set by {@link at.jku.fim.rubanetra.protocol.handler.KrakenTelnetHandler}
|
||||
* @param arguments the available telnet arguments
|
||||
*/
|
||||
public void setArguments(int[] arguments) {
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded telnet text
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set by {@link at.jku.fim.rubanetra.protocol.handler.KrakenTelnetHandler}
|
||||
* @param text the decoded telnet text
|
||||
*/
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the decoded title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set by {@link at.jku.fim.rubanetra.protocol.handler.KrakenTelnetHandler}
|
||||
* @param title the decoded title
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
CLIENT_COMMAND, SERVER_COMMAND, CLIENT_ANSICONTROL, SERVER_ANSICONTROL,
|
||||
CLIENT_DATA, SERVER_DATA, CLIENT_TITLE, SERVER_TITLE
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TelnetActivity{" +
|
||||
"pcapActivity=" + pcapActivity +
|
||||
", subType=" + subType +
|
||||
", command=" + command +
|
||||
", option=" + option +
|
||||
", data=" + Arrays.toString(data) +
|
||||
", ansiMode=" + ansiMode +
|
||||
", arguments=" + Arrays.toString(arguments) +
|
||||
", text='" + text + '\'' +
|
||||
", title='" + title + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.tls;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.tcp.TcpActivity;
|
||||
import org.kie.api.definition.type.Role;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static org.kie.api.definition.type.Role.Type;
|
||||
|
||||
/**
|
||||
* Encapsulates various {@link at.jku.fim.rubanetra.protocol.activity.tcp.TcpActivity} objects
|
||||
* that are specific to SSL/TLS streams, e.g. typical "Client Hello", "Server Hello" and "ChangeCipherSpec"
|
||||
* messages are stored in this activity - therefore it should be considered a derived fact next to constituting an event.
|
||||
* {@link at.jku.fim.rubanetra.protocol.activity.tls.TlsActivityHelper} may be used to decide whether
|
||||
* or not a TCP payload may contain SSL/TLS protocol messages.
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public class TlsActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = -7664259518283613758L;
|
||||
private final TcpActivity clientHello;
|
||||
private final TcpActivity serverHello;
|
||||
private final SortedSet<Long> clientToServerTraffic, serverToClientTraffic;
|
||||
|
||||
private TcpActivity changeCipherSpec;
|
||||
|
||||
/**
|
||||
* Constructs a prototypical TLS Event using a "Client Hello" and a "Server Hello" TCP messages.
|
||||
* Both messages are extended instead of replaced due to potential wrongful classifications.
|
||||
*/
|
||||
public TlsActivity(TcpActivity clientHello, TcpActivity serverHello) {
|
||||
super(clientHello);
|
||||
|
||||
this.clientHello = clientHello;
|
||||
this.serverHello = serverHello;
|
||||
|
||||
serverToClientTraffic = new TreeSet<>();
|
||||
clientToServerTraffic = new TreeSet<>();
|
||||
|
||||
extendActivity(clientHello);
|
||||
extendActivity(serverHello);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tcp activity resembling the change cipher spec protocol message or null if it has not been set
|
||||
*/
|
||||
public TcpActivity getChangeCipherSpec() {
|
||||
return changeCipherSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Designates the passed TCP activity to containing a "Change Cipher Spec" protocol message.
|
||||
*
|
||||
* @param changeCipherSpec the TCP activity resembling a "Change Cipher Spec" (will be extended)
|
||||
*/
|
||||
public void setChangeCipherSpec(TcpActivity changeCipherSpec) {
|
||||
if (this.changeCipherSpec != null) {
|
||||
removeReplacedActivity(this.changeCipherSpec);
|
||||
}
|
||||
this.changeCipherSpec = changeCipherSpec;
|
||||
extendActivity(changeCipherSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the "Client Hello" protocol message containing TcpActivity
|
||||
*/
|
||||
public TcpActivity getClientHello() {
|
||||
return clientHello;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the "Server Hello" protocol message containing TcpActivity
|
||||
*/
|
||||
public TcpActivity getServerHello() {
|
||||
return serverHello;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a sorted set containing individual frame numbers that are part of the TCP session (client -> server)
|
||||
* ENHANCEMENT: this is quite inefficient, introduction of ranges?
|
||||
*/
|
||||
public SortedSet<Long> getClientToServerTraffic() {
|
||||
return Collections.unmodifiableSortedSet(clientToServerTraffic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a sorted set containing individual frame numbers that are part of the TCP session (server -> client)
|
||||
* ENHANCEMENT: this is quite inefficient, introduction of ranges?
|
||||
*/
|
||||
public SortedSet<Long> getServerToClientTraffic() {
|
||||
return Collections.unmodifiableSortedSet(serverToClientTraffic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns and extends a tcp activity to be part of this TLS/SSL stream
|
||||
*
|
||||
* @param tcp the tcp activity of the same TCP session, client to server direction
|
||||
*/
|
||||
public void addClientToServerTcpActivity(TcpActivity tcp) {
|
||||
this.clientToServerTraffic.addAll(tcp.getCompoundFrameNumbers());
|
||||
extendActivity(tcp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns and extends a tcp activity to be part of this TLS/SSL stream
|
||||
*
|
||||
* @param tcp the tcp activity of the same TCP session, server to client direction
|
||||
*/
|
||||
public void addServerToClientTcpActivity(TcpActivity tcp) {
|
||||
this.serverToClientTraffic.addAll(tcp.getCompoundFrameNumbers());
|
||||
extendActivity(tcp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return getClientHello().getSourceAddressAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return getClientHello().getDestinationAddressAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TlsActivity{" +
|
||||
"clientHello=" + clientHello +
|
||||
", serverHello=" + serverHello +
|
||||
", clientToServerTraffic=" + clientToServerTraffic +
|
||||
", serverToClientTraffic=" + serverToClientTraffic +
|
||||
", changeCipherSpec=" + changeCipherSpec +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.tls;
|
||||
|
||||
|
||||
import org.jnetpcap.protocol.tcpip.Tcp;
|
||||
|
||||
/**
|
||||
* Contains various static methods as indicators of TLS/SSL protocol messages in
|
||||
* {@link at.jku.fim.rubanetra.protocol.activity.tcp.TcpActivity} payloads.
|
||||
* These methods are basically unverified and marginally tested - therefore false positives/negatives may be
|
||||
* possible.
|
||||
*/
|
||||
public class TlsActivityHelper {
|
||||
/**
|
||||
* Returns true if the TCP payload contains a "Handshake" control flag.
|
||||
*
|
||||
* @param tcp the JNetPcap TCP representation containing a payload.
|
||||
* @return true if the TCP payload contains a "Handshake" control flag.
|
||||
*/
|
||||
public static boolean isTlsHandshake(Tcp tcp) {
|
||||
return TlsContentType.HANDSHAKE.matches(tcp, TlsRecord.CONTENT_TYPE)
|
||||
|| TlsContentType.SSL_HANDSHAKE.matches(tcp, TlsRecord.CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the TCP payload contains a "Client Hello" control message.
|
||||
*
|
||||
* @param tcp the JNetPcap TCP representation containing a payload.
|
||||
* @return true if the TCP payload contains a "Client Hello" control message.
|
||||
*/
|
||||
public static boolean isClientHello(Tcp tcp) {
|
||||
if (TlsContentType.HANDSHAKE.matches(tcp, TlsRecord.CONTENT_TYPE)) {
|
||||
return TlsContentType.HANDSHAKE_STATE_CLIENT_HELLO.matches(tcp, TlsRecord.HANDSHAKE_STATE);
|
||||
} else if (TlsContentType.SSL_HANDSHAKE.matches(tcp, TlsRecord.CONTENT_TYPE)) {
|
||||
return TlsContentType.SSL_HANDSHAKE_STATE_CLIENT_HELLO.matches(tcp, TlsRecord.SSL_HANDSHAKE_STATE);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the TCP payload contains a "Server Hello" control message.
|
||||
*
|
||||
* @param tcp the JNetPcap TCP representation containing a payload.
|
||||
* @return true if the TCP payload contains a "Server Hello" control message.
|
||||
*/
|
||||
public static boolean isServerHello(Tcp tcp) {
|
||||
if (TlsContentType.HANDSHAKE.matches(tcp, TlsRecord.CONTENT_TYPE)) {
|
||||
return TlsContentType.HANDSHAKE_STATE_SERVER_HELLO.matches(tcp, TlsRecord.HANDSHAKE_STATE);
|
||||
} else if (TlsContentType.SSL_HANDSHAKE.matches(tcp, TlsRecord.CONTENT_TYPE)) {
|
||||
return TlsContentType.SSL_HANDSHAKE_STATE_SERVER_HELLO.matches(tcp, TlsRecord.SSL_HANDSHAKE_STATE);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the TCP payload contains a "ChangeCipherSpec" control message.
|
||||
*
|
||||
* @param tcp the JNetPcap TCP representation containing a payload.
|
||||
* @return true if the TCP payload contains a "ChangeCipherSpec" control message.
|
||||
*/
|
||||
public static boolean isChangeCipherSpec(Tcp tcp) {
|
||||
return TlsContentType.CHANGE_CIPHER_SPEC.matches(tcp, TlsRecord.CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the TCP payload contains an "Application" control message.
|
||||
*
|
||||
* @param tcp the JNetPcap TCP representation containing a payload.
|
||||
* @return true if the TCP payload contains an "Application" control message.
|
||||
*/
|
||||
public static boolean isApplication(Tcp tcp) {
|
||||
return TlsContentType.APPLICATION.matches(tcp, TlsRecord.CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration of possible SSL/TLS records including byte offset into the payload and length values.
|
||||
*/
|
||||
public enum TlsRecord {
|
||||
CONTENT_TYPE(0, 1),
|
||||
VERSION(1, 2),
|
||||
LENGTH(3, 2),
|
||||
|
||||
// for handshake
|
||||
HANDSHAKE_STATE(5, 1),
|
||||
SSL_HANDSHAKE_STATE(2, 1);
|
||||
|
||||
private final int byteOffset;
|
||||
private final int length;
|
||||
|
||||
TlsRecord(int byteOffset, int length) {
|
||||
this.byteOffset = byteOffset;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration of possible SSL/TLS content types including flag values.
|
||||
*/
|
||||
public enum TlsContentType {
|
||||
CHANGE_CIPHER_SPEC(0x14),
|
||||
ALERT(0x15),
|
||||
HANDSHAKE(0x16),
|
||||
APPLICATION(0x17),
|
||||
|
||||
// special purpose handshake protocol
|
||||
HANDSHAKE_STATE_CLIENT_HELLO(0x01),
|
||||
HANDSHAKE_STATE_SERVER_HELLO(0x02),
|
||||
|
||||
//SSL v2 exception
|
||||
SSL_HANDSHAKE(0x80),
|
||||
|
||||
// special purpose handshake protocol
|
||||
SSL_HANDSHAKE_STATE_CLIENT_HELLO(0x01),
|
||||
SSL_HANDSHAKE_STATE_SERVER_HELLO(0x02);
|
||||
private final int val;
|
||||
|
||||
TlsContentType(int val) {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the payload of tcp contains this flag in its TlsRecord record.
|
||||
*
|
||||
* @param tcp the the JNetPcap TCP representation containing a payload.
|
||||
* @param record the TLSRecord of interest
|
||||
* @return true if the payload of tcp contains this flag in its TlsRecord record.
|
||||
*/
|
||||
public boolean matches(Tcp tcp, TlsRecord record) {
|
||||
if (tcp == null || !tcp.hasPayload()) return false;
|
||||
|
||||
|
||||
if (tcp.getPayloadLength() >= record.byteOffset + record.length) {
|
||||
int off = tcp.getPayloadOffset() + record.byteOffset;
|
||||
switch (record.length) {
|
||||
case 1:
|
||||
return tcp.getPacket().getUByte(off) == val;
|
||||
case 2:
|
||||
return tcp.getPacket().getUShort(off) == val;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.activity.udp;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.AbstractReplaceableActivity;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.protocol.tcpip.Udp;
|
||||
import org.kie.api.definition.type.Role;
|
||||
import org.kie.api.definition.type.Role.Type;
|
||||
import org.krakenapps.pcap.decoder.udp.UdpPacket;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Encapsulates various UDP packet specific values (decoded by Kraken) and
|
||||
* provides a JNetPcap representation of the same UDP data.
|
||||
*/
|
||||
@Role(Type.EVENT)
|
||||
public class UdpActivity extends AbstractReplaceableActivity {
|
||||
private static final long serialVersionUID = 351329488071596679L;
|
||||
private final int sourcePort;
|
||||
private final int destinationPort;
|
||||
private final int length;
|
||||
private final int checksum;
|
||||
private final PcapActivity pcapActivity;
|
||||
private final Udp udp;
|
||||
private final InetSocketAddress sourceSocketAddress;
|
||||
private final InetSocketAddress destinationSocketAddress;
|
||||
|
||||
/**
|
||||
* Constructs a new Udp activity, replaces the source pcap activity on which this event occurred and excludes it
|
||||
* from the final output due to verbosity.
|
||||
*
|
||||
* @param source the pcap activity on which this activity occurred
|
||||
* @param packet the decoded UDP data (Kraken)
|
||||
*/
|
||||
public UdpActivity(PcapActivity source, UdpPacket packet) {
|
||||
super(source);
|
||||
|
||||
sourcePort = packet.getSourcePort();
|
||||
destinationPort = packet.getDestinationPort();
|
||||
length = packet.getLength();
|
||||
checksum = packet.getChecksum();
|
||||
sourceSocketAddress = packet.getSource();
|
||||
destinationSocketAddress = packet.getDestination();
|
||||
|
||||
pcapActivity = source;
|
||||
|
||||
this.udp = new Udp();
|
||||
|
||||
PcapPacket p = pcapActivity.getPcapPacket();
|
||||
p.hasHeader(udp);
|
||||
replaceActivity(source);
|
||||
setExcludedFromOutput(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JNetPcap representation of the decoded UDP data
|
||||
*/
|
||||
@JsonIgnore
|
||||
public Udp getUdp() {
|
||||
return udp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L4 source address information
|
||||
*/
|
||||
public int getSourcePort() {
|
||||
return sourcePort;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L4 destination address information
|
||||
*/
|
||||
public int getDestinationPort() {
|
||||
return destinationPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L3/L4 source address
|
||||
*/
|
||||
public InetSocketAddress getSourceSocketAddress() {
|
||||
return sourceSocketAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the L3/L4 destination address
|
||||
*/
|
||||
public InetSocketAddress getDestinationSocketAddress() {
|
||||
return destinationSocketAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return payload length in bytes
|
||||
*/
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return packet checksum as encountered
|
||||
*/
|
||||
public int getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source on which this activity occurred or the final PcapActivity that led to the fully
|
||||
* decoded packet.
|
||||
*/
|
||||
public PcapActivity getPcapActivity() {
|
||||
return pcapActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceAddressAsString() {
|
||||
return String.valueOf(getSourceSocketAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressAsString() {
|
||||
return String.valueOf(getDestinationSocketAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UdpActivity{" +
|
||||
"sourcePort=" + sourcePort +
|
||||
", destinationPort=" + destinationPort +
|
||||
", length=" + length +
|
||||
", checksum=" + checksum +
|
||||
", pcapActivity=" + pcapActivity +
|
||||
", udp=" + udp +
|
||||
", sourceSocketAddress=" + sourceSocketAddress +
|
||||
", destinationSocketAddress=" + destinationSocketAddress +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.arp.ArpActivity;
|
||||
import org.krakenapps.pcap.decoder.arp.ArpDecoder;
|
||||
import org.krakenapps.pcap.decoder.arp.ArpPacket;
|
||||
|
||||
/**
|
||||
* Represents a link to the Kraken library, i.e. it receives decoded ARP data, wraps it into suitable
|
||||
* activities ({@link at.jku.fim.rubanetra.protocol.activity.arp.ArpActivity}) and
|
||||
* passes it on to interested objects.
|
||||
* The Kraken library expects an Ethernet-Decoder that transfers decoded frames to an
|
||||
* {@link org.krakenapps.pcap.decoder.arp.ArpDecoder}, therefore this Ethernet decoder must be bound from
|
||||
* a {@link at.jku.fim.rubanetra.protocol.handler.KrakenEthernetProtocolHandler} to this Arp Decoder
|
||||
* ({@link #getKrakenArpDecoder()}).
|
||||
* This class does not provide a binding method implementation, i.e. it is not possible to bind this handler
|
||||
* to another one.
|
||||
*/
|
||||
public class KrakenArpHandler extends KrakenBaseProtocol {
|
||||
public static final String NEW_ARP_ACTIVITY_PROPERTY_NAME = "newArpActivity";
|
||||
public static final ProtocolId krakenArpProtocolId = new ProtocolId() {
|
||||
private final String id = "Arp";
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
|
||||
private final ArpDecoder krakenArpDecoder;
|
||||
|
||||
/**
|
||||
* Constructs a new Arp handler by creating an {@link org.krakenapps.pcap.decoder.arp.ArpDecoder}, a
|
||||
* {@link at.jku.fim.rubanetra.protocol.handler.KrakenEthernetProtocolHandler} and binding to it.
|
||||
*/
|
||||
public KrakenArpHandler() {
|
||||
super();
|
||||
|
||||
krakenArpDecoder = new ArpDecoder();
|
||||
krakenArpDecoder.register(this::fireNewArpActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenArpProtocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(KrakenProtocolConfiguration setting) {
|
||||
super.initialize(setting);
|
||||
}
|
||||
|
||||
private void fireNewArpActivity(ArpPacket p) {
|
||||
ArpActivity act = new ArpActivity(getCurrentPcapActivity(), p);
|
||||
propertyChangeSupport.firePropertyChange(NEW_ARP_ACTIVITY_PROPERTY_NAME, null, act);
|
||||
}
|
||||
|
||||
public ArpDecoder getKrakenArpDecoder() {
|
||||
return krakenArpDecoder;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.dhcp.DhcpActivity;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.dhcp.DhcpDecoder;
|
||||
import org.krakenapps.pcap.decoder.dhcp.DhcpMessage;
|
||||
|
||||
/**
|
||||
* Utilizes a {@link org.krakenapps.pcap.decoder.dhcp.DhcpDecoder} in order to receive decoded DHCP data, which
|
||||
* is in turn distributed as {@link at.jku.fim.rubanetra.protocol.activity.dhcp.DhcpActivity} to
|
||||
* interested observers.
|
||||
* This class does not define any concrete bindings.
|
||||
*/
|
||||
public class KrakenDhcpHandler extends KrakenBaseProtocol {
|
||||
public static final String PROPERTY_NEW_DHCP_ACTIVITY = "newDhcpActivity";
|
||||
private final DhcpDecoder krakenDhcpDecoder;
|
||||
|
||||
public KrakenDhcpHandler() {
|
||||
krakenDhcpDecoder = new DhcpDecoder();
|
||||
krakenDhcpDecoder.register(this::fireNewDhcpActivity);
|
||||
}
|
||||
|
||||
private void fireNewDhcpActivity(DhcpMessage dhcpMessage) {
|
||||
DhcpActivity dhcpActivity = new DhcpActivity(getCurrentPcapActivity(), dhcpMessage);
|
||||
propertyChangeSupport.firePropertyChange(PROPERTY_NEW_DHCP_ACTIVITY, null, dhcpActivity);
|
||||
}
|
||||
|
||||
public static final KrakenApplicationProtocolId krakenDhcpProtocolId = new KrakenApplicationProtocolId() {
|
||||
private final String protocolId = Protocol.DHCP.name();
|
||||
|
||||
@Override
|
||||
public Protocol getKrakenApplicationProtocol() {
|
||||
return Protocol.DHCP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Dhcp";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenDhcpProtocolId;
|
||||
}
|
||||
|
||||
public DhcpDecoder getKrakenDhcpDecoder() {
|
||||
return krakenDhcpDecoder;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.dns.DnsActivity;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpProcessor;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpSessionKey;
|
||||
import org.krakenapps.pcap.decoder.udp.UdpPacket;
|
||||
import org.krakenapps.pcap.decoder.udp.UdpProcessor;
|
||||
import org.krakenapps.pcap.util.Buffer;
|
||||
import org.krakenapps.pcap.util.ChainBuffer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xbill.DNS.Message;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class does not utilize a Kraken decoder directly, instead it represents the decoding processors as
|
||||
* an implementation of {@link org.krakenapps.pcap.decoder.udp.UdpProcessor} and
|
||||
* {@link org.krakenapps.pcap.decoder.tcp.TcpProcessor}.
|
||||
* The org.xbill.dns Java library (see {@link org.xbill.DNS.Message}) is used as primary payload decoder.
|
||||
* Several modifications were required to process both, UDP- and TCP-based payloads, therefore this implementation
|
||||
* is still considered experimental and may (silently) fail to decode valid DNS messages.
|
||||
*/
|
||||
public class KrakenDnsProtocolHandler extends KrakenBaseProtocol implements UdpProcessor, TcpProcessor {
|
||||
public static final String NEW_DNS_ACTIVITY_PROPERTY_NAME = "newDnsActivity";
|
||||
public static final KrakenApplicationProtocolId krakenDnsProtocolId = new KrakenApplicationProtocolId() {
|
||||
private final String protocolId = Protocol.DNS.name();
|
||||
|
||||
@Override
|
||||
public Protocol getKrakenApplicationProtocol() {
|
||||
return Protocol.DNS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Dns";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
private final Map<TcpSessionKey, DnsSession> sessionMap = new HashMap<>();
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenDnsProtocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(UdpPacket p) {
|
||||
Buffer udpData = p.getData();
|
||||
int readableBytes = udpData.readableBytes();
|
||||
byte[] dnsData = new byte[readableBytes];
|
||||
udpData.gets(dnsData);
|
||||
try {
|
||||
Message dnsMessage = new Message(dnsData);
|
||||
DnsActivity dnsActivity = new DnsActivity(getCurrentPcapActivity(), dnsMessage);
|
||||
fireNewDnsActivity(dnsActivity);
|
||||
} catch (IOException e) {
|
||||
log.debug("Failed to decode UdpPacket {} {}", getCurrentPcapActivity().getFrameNumber(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void fireNewDnsActivity(DnsActivity dnsActivity) {
|
||||
propertyChangeSupport.firePropertyChange(NEW_DNS_ACTIVITY_PROPERTY_NAME, null, dnsActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReset(TcpSessionKey key) {
|
||||
onFinish(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEstablish(TcpSessionKey key) {
|
||||
// take the valuable IP information and create a new potential DNS session
|
||||
InetAddress clientIp = key.getClientIp();
|
||||
InetAddress serverIp = key.getServerIp();
|
||||
InetSocketAddress clientAddr = new InetSocketAddress(clientIp, key.getClientPort());
|
||||
InetSocketAddress serverAddr = new InetSocketAddress(serverIp, key.getServerPort());
|
||||
sessionMap.put(key, new DnsSession(clientAddr, serverAddr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(TcpSessionKey key) {
|
||||
sessionMap.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTx(TcpSessionKey session, Buffer data) {
|
||||
DnsSession dnsSession = sessionMap.get(session);
|
||||
dnsSession.txBuffer.addLast(data);
|
||||
if (dnsSession.txMessageSize <= 0) {
|
||||
// DNS over TCP is prefixed by a two byte length field (see RFC 1035)
|
||||
dnsSession.txMessageSize = dnsSession.txBuffer.getUnsignedShort();
|
||||
}
|
||||
dnsSession.txBuffer.mark();
|
||||
int readableBytes = dnsSession.txBuffer.readableBytes();
|
||||
if (readableBytes == dnsSession.txMessageSize) {
|
||||
byte[] dnsData = new byte[readableBytes];
|
||||
dnsSession.txBuffer.gets(dnsData);
|
||||
try {
|
||||
Message dnsMessage = new Message(dnsData);
|
||||
DnsActivity dnsActivity = new DnsActivity(getCurrentPcapActivity(), dnsMessage);
|
||||
fireNewDnsActivity(dnsActivity);
|
||||
} catch (IOException e) {
|
||||
log.debug("Failed to decode DNS message over tcp {} {}", getCurrentPcapActivity().getFrameNumber(), e);
|
||||
dnsSession.txBuffer.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRx(TcpSessionKey session, Buffer data) {
|
||||
DnsSession dnsSession = sessionMap.get(session);
|
||||
dnsSession.rxBuffer.addLast(data);
|
||||
if (dnsSession.rxMessageSize <= 0) {
|
||||
// DNS over TCP is prefixed by a two byte length field (see RFC 1035)
|
||||
dnsSession.rxMessageSize = dnsSession.rxBuffer.getUnsignedShort();
|
||||
}
|
||||
//dnsSession.rxBuffer.skip(2); // skip DNS Message size??
|
||||
dnsSession.rxBuffer.mark();
|
||||
int readableBytes = dnsSession.rxBuffer.readableBytes();
|
||||
if (readableBytes == dnsSession.rxMessageSize) {
|
||||
byte[] dnsData = new byte[readableBytes];
|
||||
dnsSession.rxBuffer.gets(dnsData);
|
||||
try {
|
||||
Message dnsMessage = new Message(dnsData);
|
||||
DnsActivity dnsActivity = new DnsActivity(getCurrentPcapActivity(), dnsMessage);
|
||||
fireNewDnsActivity(dnsActivity);
|
||||
} catch (IOException e) {
|
||||
log.debug("Failed to decode DNS message over tcp {} {}", getCurrentPcapActivity().getFrameNumber(), e);
|
||||
dnsSession.rxBuffer.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates RX/TX buffers for DNS messages exchanged between a client and a server
|
||||
*/
|
||||
private class DnsSession {
|
||||
private final InetSocketAddress client;
|
||||
private final InetSocketAddress server;
|
||||
private final ChainBuffer txBuffer;
|
||||
private final ChainBuffer rxBuffer;
|
||||
|
||||
private int txMessageSize, rxMessageSize;
|
||||
|
||||
DnsSession(InetSocketAddress client, InetSocketAddress server) {
|
||||
|
||||
this.client = client;
|
||||
this.server = server;
|
||||
txBuffer = new ChainBuffer();
|
||||
rxBuffer = new ChainBuffer();
|
||||
this.txMessageSize = this.rxMessageSize = -1;
|
||||
}
|
||||
|
||||
public InetSocketAddress getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public InetSocketAddress getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public ChainBuffer getTxBuffer() {
|
||||
return txBuffer;
|
||||
}
|
||||
|
||||
public ChainBuffer getRxBuffer() {
|
||||
return rxBuffer;
|
||||
}
|
||||
|
||||
public int getTxMessageSize() {
|
||||
return txMessageSize;
|
||||
}
|
||||
|
||||
public int getRxMessageSize() {
|
||||
return rxMessageSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.pcap.PcapActivity;
|
||||
import at.jku.fim.rubanetra.pcap.PcapPacketToKrakenPcapPacketAdapter;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.ethernet.EthernetActivity;
|
||||
import org.krakenapps.pcap.decoder.ethernet.EthernetDecoder;
|
||||
import org.krakenapps.pcap.decoder.ethernet.EthernetFrame;
|
||||
import org.krakenapps.pcap.decoder.ethernet.EthernetType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Kraken network layer 2 decoder {@link org.krakenapps.pcap.decoder.ethernet.EthernetDecoder} is used by this
|
||||
* handler in order to create and deliver {@link at.jku.fim.rubanetra.protocol.activity.ethernet.EthernetActivity}
|
||||
* instances. Furthermore, several bindings have been implemented, i.e.:
|
||||
* <ul>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenIpv4Handler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenIpv6Handler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenArpHandler}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class KrakenEthernetProtocolHandler extends KrakenBaseProtocol {
|
||||
public static final ProtocolId krakenEthernetProtocolId = new ProtocolId() {
|
||||
private final String protocolId = "Ethernet";
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
public static final String PROPERTY_NEW_ETHERNET_ACTIVITY = "newEthernetActivity";
|
||||
|
||||
private final EthernetDecoder krakenEthernetDecoder;
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public KrakenEthernetProtocolHandler() {
|
||||
super();
|
||||
krakenEthernetDecoder = new EthernetDecoder();
|
||||
krakenEthernetDecoder.register(this::fireNewEthernetActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenEthernetProtocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(KrakenProtocolConfiguration setting) {
|
||||
super.initialize(setting);
|
||||
getPcapHandler().addPcapProcessor(this::decodePcapPacket);
|
||||
|
||||
}
|
||||
|
||||
private void fireNewEthernetActivity(EthernetFrame frame) {
|
||||
EthernetActivity ethernetActivity = new EthernetActivity(getCurrentPcapActivity(), frame);
|
||||
propertyChangeSupport.firePropertyChange(PROPERTY_NEW_ETHERNET_ACTIVITY, null, ethernetActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the internal {@link org.krakenapps.pcap.decoder.ethernet.EthernetDecoder} to an IPv4 decoder, i.e.
|
||||
* a decoder that shall receive all decoded Ethernet frames.
|
||||
*
|
||||
* @param ipv4Protocol the IPv4 decoder to bind to
|
||||
* @throws java.lang.IllegalArgumentException if the parameter is a null pointer
|
||||
*/
|
||||
public void bind(KrakenIpv4Handler ipv4Protocol) {
|
||||
if (ipv4Protocol == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
krakenEthernetDecoder.register(EthernetType.IPV4, ipv4Protocol.getKrakenIpv4Decoder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the internal {@link org.krakenapps.pcap.decoder.ethernet.EthernetDecoder} to an IPv6 decoder, i.e.
|
||||
* a decoder that shall receive all decoded Ethernet frames.
|
||||
*
|
||||
* @param ipv6Handler the IPv6 decoder to bind to
|
||||
* @throws java.lang.IllegalArgumentException if the parameter is a null pointer
|
||||
*/
|
||||
public void bind(KrakenIpv6Handler ipv6Handler) {
|
||||
krakenEthernetDecoder.register(EthernetType.IPV6, ipv6Handler.getKrakenIpv6Decoder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the internal {@link org.krakenapps.pcap.decoder.ethernet.EthernetDecoder} to an ARP decoder, i.e.
|
||||
* a decoder that shall receive all decoded Ethernet frames.
|
||||
*
|
||||
* @param arpHandler the ARP decoder to bind to
|
||||
* @throws java.lang.IllegalArgumentException if the parameter is a null pointer
|
||||
*/
|
||||
public void bind(KrakenArpHandler arpHandler) {
|
||||
krakenEthernetDecoder.register(EthernetType.ARP, arpHandler.getKrakenArpDecoder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a Pcap entry and tries to decode the payload as an Ethernet frame using a
|
||||
* {@link org.krakenapps.pcap.decoder.ethernet.EthernetDecoder} and a suitable Pcap wrapper
|
||||
* {@link at.jku.fim.rubanetra.pcap.PcapPacketToKrakenPcapPacketAdapter}.
|
||||
*
|
||||
* @param pcapActivity the Pcap entry whose payload is to be decoded as an Ethernet frame
|
||||
* @throws java.lang.NullPointerException if pcapActivity is a null pointer
|
||||
*/
|
||||
public void decodePcapPacket(PcapActivity pcapActivity) {
|
||||
if (pcapActivity != null && pcapActivity.getPcapPacket() != null) {
|
||||
krakenEthernetDecoder.decode(new PcapPacketToKrakenPcapPacketAdapter(pcapActivity.getPcapPacket()));
|
||||
} else {
|
||||
log.warn("Unable to decode a null pointer Pcap entry");
|
||||
throw new NullPointerException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Ethernet decoder used internally
|
||||
*/
|
||||
public EthernetDecoder getKrakenEthernetDecoder() {
|
||||
return krakenEthernetDecoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.ftp.FtpActivity;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.ftp.FtpDecoder;
|
||||
import org.krakenapps.pcap.decoder.ftp.FtpProcessor;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpPortProtocolMapper;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* This is an Kraken application layer decoder handler, i.e. it does not provide any forward bindings.
|
||||
* Internally, a {@link org.krakenapps.pcap.decoder.ftp.FtpDecoder} is used to build partial
|
||||
* {@link at.jku.fim.rubanetra.protocol.activity.ftp.FtpActivity} instances.
|
||||
*/
|
||||
public class KrakenFtpHandler extends KrakenBaseProtocol {
|
||||
public static final String PROPERTY_NEW_PARTIAL_FTP_ACTIVITY = "newPartialFtpActivity";
|
||||
public static final KrakenApplicationProtocolId krakenFtpProtocolId = new KrakenApplicationProtocolId() {
|
||||
private final String protocolId = Protocol.FTP.name();
|
||||
|
||||
@Override
|
||||
public Protocol getKrakenApplicationProtocol() {
|
||||
return Protocol.FTP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Ftp";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
|
||||
private final FtpDecoder krakenFtpDecoder;
|
||||
private final FtpProcessor ftpProcessor = new FtpProcessor() {
|
||||
@Override
|
||||
public void onCommand(String command) {
|
||||
FtpActivity activity = new FtpActivity(getCurrentPcapActivity(), FtpActivity.Type.COMMAND, command);
|
||||
fireNewPartialFtpActivity(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReply(String reply) {
|
||||
FtpActivity activity = new FtpActivity(getCurrentPcapActivity(), FtpActivity.Type.REPLY, reply);
|
||||
fireNewPartialFtpActivity(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void viewList(byte[] list) {
|
||||
FtpActivity activity = new FtpActivity(getCurrentPcapActivity(), FtpActivity.Type.VIEW_LIST, list);
|
||||
fireNewPartialFtpActivity(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExtractFile(InputStream is, String fileName) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
public KrakenFtpHandler() {
|
||||
krakenFtpDecoder = new FtpDecoder(new TcpPortProtocolMapper());
|
||||
krakenFtpDecoder.register(ftpProcessor);
|
||||
}
|
||||
|
||||
private void fireNewPartialFtpActivity(FtpActivity partialFtpActivity) {
|
||||
propertyChangeSupport.firePropertyChange(PROPERTY_NEW_PARTIAL_FTP_ACTIVITY, null, partialFtpActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenFtpProtocolId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the FTP decoder that is used internally
|
||||
*/
|
||||
public FtpDecoder getKrakenFtpDecoder() {
|
||||
return krakenFtpDecoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.http.HttpRequestActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.http.HttpResponseActivity;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.http.HttpDecoder;
|
||||
import org.krakenapps.pcap.decoder.http.HttpProcessor;
|
||||
import org.krakenapps.pcap.decoder.http.HttpRequest;
|
||||
import org.krakenapps.pcap.decoder.http.HttpResponse;
|
||||
import org.krakenapps.pcap.util.Buffer;
|
||||
|
||||
/**
|
||||
* Represents an application layer Kraken decoder handler, i.e. it does not provide any forward bindings.
|
||||
* A {@link org.krakenapps.pcap.decoder.http.HttpDecoder} is used internally to decode HTTP data which is used to
|
||||
* build {@link at.jku.fim.rubanetra.protocol.activity.http.HttpRequestActivity} and
|
||||
* {@link at.jku.fim.rubanetra.protocol.activity.http.HttpResponseActivity} objects.
|
||||
* However, it does not handle Multipart data (the buffers will be silently discarded).
|
||||
*/
|
||||
public class KrakenHttpHandler extends KrakenBaseProtocol {
|
||||
public static final String NEW_HTTP_REQUEST_ACTIVITY_PROPERTY_NAME = "newHttpRequestActivity";
|
||||
public static final String NEW_HTTP_RESPONSE_ACTIVITY_PROPERTY_NAME = "newHttpResponseActivity";
|
||||
public static final KrakenApplicationProtocolId krakenHttpProtocolId = new KrakenApplicationProtocolId() {
|
||||
private final String protocolIdString = Protocol.HTTP.name();
|
||||
|
||||
@Override
|
||||
public Protocol getKrakenApplicationProtocol() {
|
||||
return Protocol.HTTP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolIdString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Http";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
private final HttpDecoder krakenHttpDecoder;
|
||||
|
||||
public KrakenHttpHandler() {
|
||||
krakenHttpDecoder = new HttpDecoder();
|
||||
krakenHttpDecoder.register(new HttpProcessor() {
|
||||
|
||||
@Override
|
||||
public void onResponse(HttpRequest req, HttpResponse resp) {
|
||||
fireNewHttpResponseActivity(resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequest(HttpRequest req) {
|
||||
fireNewHttpRequestActivity(req);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMultipartData(Buffer buffer) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void fireNewHttpRequestActivity(HttpRequest req) {
|
||||
HttpRequestActivity requestActivity = new HttpRequestActivity(getCurrentPcapActivity(), req);
|
||||
propertyChangeSupport.firePropertyChange(NEW_HTTP_REQUEST_ACTIVITY_PROPERTY_NAME, null, requestActivity);
|
||||
}
|
||||
|
||||
protected void fireNewHttpResponseActivity(HttpResponse resp) {
|
||||
HttpResponseActivity responseActivity = new HttpResponseActivity(getCurrentPcapActivity(), resp);
|
||||
propertyChangeSupport.firePropertyChange(NEW_HTTP_RESPONSE_ACTIVITY_PROPERTY_NAME, null, responseActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenHttpProtocolId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the HTTP decoder that is used internally
|
||||
*/
|
||||
public HttpDecoder getKrakenHttpDecoder() {
|
||||
return krakenHttpDecoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.icmp.Icmpv4Activity;
|
||||
import org.krakenapps.pcap.decoder.icmp.IcmpDecoder;
|
||||
import org.krakenapps.pcap.decoder.icmp.IcmpPacket;
|
||||
import org.krakenapps.pcap.decoder.icmp.IcmpProcessor;
|
||||
|
||||
/**
|
||||
* This ICMP decoder handler relies on {@link org.krakenapps.pcap.decoder.icmp.IcmpDecoder} which is provided by the
|
||||
* Kraken library and on {@link at.jku.fim.rubanetra.protocol.handler.KrakenIpv4Handler} in order to
|
||||
* receive the IPv4 payload used to transport the ICMP data.
|
||||
* No forward bindings are provided by this class.
|
||||
*/
|
||||
public class KrakenIcmpv4Handler extends KrakenBaseProtocol {
|
||||
public static final String NEW_ICMPV_4_ACTIVITY_PROPERTY_NAME = "newIcmpv4Activity";
|
||||
public static final ProtocolId krakenIcmpv4ProtocolId = new ProtocolId() {
|
||||
private final String protocolId = "Icmpv4";
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
private final IcmpProcessor generalIcmpProcessor = new IcmpProcessor() {
|
||||
private long lastProcessedFrameNumber = -1;
|
||||
|
||||
@Override
|
||||
public void process(IcmpPacket p) {
|
||||
// this is a workaround to prevent the redundant call from Kraken's IcmpDecoder of the same event using
|
||||
// two different objects
|
||||
if (lastProcessedFrameNumber != getCurrentPcapActivity().getFrameNumber()) {
|
||||
fireNewIcmpActivity(p);
|
||||
}
|
||||
lastProcessedFrameNumber = getCurrentPcapActivity().getFrameNumber();
|
||||
}
|
||||
};
|
||||
|
||||
private final IcmpDecoder krakenIcmpv4Decoder;
|
||||
|
||||
public KrakenIcmpv4Handler() {
|
||||
krakenIcmpv4Decoder = new IcmpDecoder();
|
||||
krakenIcmpv4Decoder.register(generalIcmpProcessor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenIcmpv4ProtocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(KrakenProtocolConfiguration setting) {
|
||||
super.initialize(setting);
|
||||
}
|
||||
|
||||
protected void fireNewIcmpActivity(IcmpPacket p) {
|
||||
Icmpv4Activity icmpActivity = new Icmpv4Activity(getCurrentPcapActivity(), p);
|
||||
propertyChangeSupport.firePropertyChange(NEW_ICMPV_4_ACTIVITY_PROPERTY_NAME, null, icmpActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ICMP decoder that is used internally
|
||||
*/
|
||||
public IcmpDecoder getKrakenIcmpv4Decoder() {
|
||||
return krakenIcmpv4Decoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.icmp.Icmpv6Activity;
|
||||
import org.krakenapps.pcap.decoder.icmpv6.Icmpv6Decoder;
|
||||
import org.krakenapps.pcap.decoder.icmpv6.Icmpv6Packet;
|
||||
|
||||
/**
|
||||
* Handles decoded ICMPv6 data received from a {@link org.krakenapps.pcap.decoder.icmpv6.Icmpv6Decoder} in order to
|
||||
* build {@link at.jku.fim.rubanetra.protocol.activity.icmp.Icmpv6Activity} objects.
|
||||
* This class does not provide any forward bindings.
|
||||
*/
|
||||
public class KrakenIcmpv6Handler extends KrakenBaseProtocol {
|
||||
public static final String NEW_ICMPV_6_ACTIVITY_PROPERTY_NAME = "newIcmpv6Activity";
|
||||
public static final ProtocolId krakenIcmpv6ProtocolId = new ProtocolId() {
|
||||
private final String protocolId = "Icmpv6";
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
|
||||
private final Icmpv6Decoder krakenImpv6Decoder;
|
||||
|
||||
public KrakenIcmpv6Handler() {
|
||||
krakenImpv6Decoder = new Icmpv6Decoder();
|
||||
krakenImpv6Decoder.register(this::fireNewIcmpActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenIcmpv6ProtocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(KrakenProtocolConfiguration setting) {
|
||||
super.initialize(setting);
|
||||
}
|
||||
|
||||
protected void fireNewIcmpActivity(Icmpv6Packet p) {
|
||||
Icmpv6Activity icmpActivity = new Icmpv6Activity(getCurrentPcapActivity(), p);
|
||||
propertyChangeSupport.firePropertyChange(NEW_ICMPV_6_ACTIVITY_PROPERTY_NAME, null, icmpActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ICMPv6 decoder that is used internally
|
||||
*/
|
||||
public Icmpv6Decoder getKrakenImpv6Decoder() {
|
||||
return krakenImpv6Decoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.ip.Ipv4Activity;
|
||||
import org.krakenapps.pcap.decoder.ethernet.EthernetType;
|
||||
import org.krakenapps.pcap.decoder.ip.InternetProtocol;
|
||||
import org.krakenapps.pcap.decoder.ip.IpDecoder;
|
||||
import org.krakenapps.pcap.decoder.ip.IpProcessor;
|
||||
import org.krakenapps.pcap.decoder.ip.Ipv4Packet;
|
||||
|
||||
/**
|
||||
* This is an inefficient handler for Kraken's {@link org.krakenapps.pcap.decoder.ip.IpDecoder} implementation.
|
||||
* Since the utilized IP next protocol numbers are not known a priori this class registers all numbers in the
|
||||
* range [0x01;0xFF[ during initialization.
|
||||
* Forward bindings are provided for:
|
||||
* <ul>
|
||||
* <li>{@link at.jku.fim.rubanetra.protocol.handler.KrakenUdpHandler}</li>
|
||||
* <li>{@link at.jku.fim.rubanetra.protocol.handler.KrakenTcpHandler}</li>
|
||||
* <li>{@link at.jku.fim.rubanetra.protocol.handler.KrakenIcmpv4Handler}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class KrakenIpv4Handler extends KrakenBaseProtocol {
|
||||
public static final String NEW_IPV_4_ACTIVITY_PROPERTY_NAME = "newIpv4Activity";
|
||||
public static final ProtocolId krakenIpv4ProtocolId = new ProtocolId() {
|
||||
private final String protocolId = "Ipv4";
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
private final IpProcessor generalIpv4Processor = this::fireNewIpv4Activity;
|
||||
private final IpDecoder krakenIpv4Decoder;
|
||||
|
||||
public KrakenIpv4Handler() {
|
||||
krakenIpv4Decoder = new IpDecoder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenIpv4ProtocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(KrakenProtocolConfiguration setting) {
|
||||
super.initialize(setting);
|
||||
|
||||
// the Kraken IPv4 parser always calls back protocol id 0
|
||||
krakenIpv4Decoder.register(0, generalIpv4Processor);
|
||||
}
|
||||
|
||||
private void fireNewIpv4Activity(Ipv4Packet packet) {
|
||||
Ipv4Activity ipActivity = new Ipv4Activity(getCurrentPcapActivity(), packet);
|
||||
propertyChangeSupport.firePropertyChange(NEW_IPV_4_ACTIVITY_PROPERTY_NAME, null, ipActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* An experimental backward binding, i.e. it registers ethernetProtocol Kraken decoder to this IPv4 decoder
|
||||
*
|
||||
* @param ethernetProtocol the Ethernet decoder to bind to this IPv4 decoder
|
||||
*/
|
||||
public void bind(KrakenEthernetProtocolHandler ethernetProtocol) {
|
||||
ethernetProtocol.getKrakenEthernetDecoder().register(EthernetType.IPV4, krakenIpv4Decoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding to the tcpProtocol internal TCP decoder, i.e. all decoded IPv4 packets are forwarded to the
|
||||
* TCP handler.
|
||||
*
|
||||
* @param tcpProtocol the handler for the decoded IPv4 packets
|
||||
*/
|
||||
public void bind(KrakenTcpHandler tcpProtocol) {
|
||||
krakenIpv4Decoder.register(InternetProtocol.TCP, tcpProtocol.getKrakenTcpDecoder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding to the udpProtocol internal UDP decoder, i.e. all decoded IPv4 packets are forwarded to this
|
||||
* UDP handler.
|
||||
*
|
||||
* @param udpProtocol the handler for the decoded IPv4 packets
|
||||
*/
|
||||
public void bind(KrakenUdpHandler udpProtocol) {
|
||||
krakenIpv4Decoder.register(InternetProtocol.UDP, udpProtocol.getKrakenUdpDecoder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the internal {@link org.krakenapps.pcap.decoder.ip.IpDecoder} to an ICMPv4 decoder, i.e.
|
||||
* a decoder that shall receive all decoded IP packets.
|
||||
*
|
||||
* @param icmpv4Handler the ICMPv4 decoder to bind to
|
||||
* @throws java.lang.IllegalArgumentException if the parameter is a null pointer
|
||||
*/
|
||||
public void bind(KrakenIcmpv4Handler icmpv4Handler) {
|
||||
krakenIpv4Decoder.register(InternetProtocol.ICMP, icmpv4Handler.getKrakenIcmpv4Decoder());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internal IPv4 decoder
|
||||
*/
|
||||
public IpDecoder getKrakenIpv4Decoder() {
|
||||
return krakenIpv4Decoder;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.ip.Ipv6Activity;
|
||||
import org.krakenapps.pcap.decoder.ethernet.EthernetType;
|
||||
import org.krakenapps.pcap.decoder.ip.InternetProtocol;
|
||||
import org.krakenapps.pcap.decoder.ipv6.Ipv6Decoder;
|
||||
import org.krakenapps.pcap.decoder.ipv6.Ipv6Packet;
|
||||
import org.krakenapps.pcap.decoder.ipv6.Ipv6Processor;
|
||||
|
||||
/**
|
||||
* Handles IPv6 packets decoded by {@link org.krakenapps.pcap.decoder.ipv6.Ipv6Decoder} and builds
|
||||
* {@link at.jku.fim.rubanetra.protocol.activity.ip.Ipv6Activity} objects during the process.
|
||||
* Since the protocol numbers for the next protocol decoder may be arbitrary it registers to all protocol numbers in the
|
||||
* range [0x00;0xFF[ using the same processor.
|
||||
* Forward bindings are provided for:
|
||||
* <ul>
|
||||
* <li>{@link at.jku.fim.rubanetra.protocol.handler.KrakenTcpHandler}</li>
|
||||
* <li>{@link at.jku.fim.rubanetra.protocol.handler.KrakenUdpHandler}</li>
|
||||
* <li>{@link at.jku.fim.rubanetra.protocol.handler.KrakenIcmpv6Handler}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class KrakenIpv6Handler extends KrakenBaseProtocol {
|
||||
public static final String NEW_IPV_6_ACTIVITY_PROPERTY_NAME = "newIpv6Activity";
|
||||
public static final ProtocolId krakenIpv6ProtocolId = new ProtocolId() {
|
||||
private final String protocolId = "Ipv6";
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
private final Ipv6Processor krakenIpv6Processor = this::fireNewIpv6Activity;
|
||||
private final Ipv6Decoder krakenIpv6Decoder;
|
||||
|
||||
public KrakenIpv6Handler() {
|
||||
krakenIpv6Decoder = new Ipv6Decoder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenIpv6ProtocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(KrakenProtocolConfiguration setting) {
|
||||
super.initialize(setting);
|
||||
for (byte protocolNumber = Byte.MIN_VALUE; protocolNumber < Byte.MAX_VALUE; protocolNumber++) {
|
||||
krakenIpv6Decoder.register(protocolNumber, krakenIpv6Processor);
|
||||
}
|
||||
}
|
||||
|
||||
private void fireNewIpv6Activity(Ipv6Packet packet) {
|
||||
Ipv6Activity ipActivity = new Ipv6Activity(getCurrentPcapActivity(), packet);
|
||||
propertyChangeSupport.firePropertyChange(NEW_IPV_6_ACTIVITY_PROPERTY_NAME, null, ipActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental backward binding using an Ethernet decoder that is to be bound to this IPv6 decoder.
|
||||
*
|
||||
* @param ethernetProtocol the Ethernet decoder to bind to this IPv6 decoder
|
||||
*/
|
||||
public void bind(KrakenEthernetProtocolHandler ethernetProtocol) {
|
||||
ethernetProtocol.getKrakenEthernetDecoder().register(EthernetType.IPV6, krakenIpv6Decoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding from this IPv6 decoder to a TCP protocol decoder.
|
||||
*
|
||||
* @param tcpProtocol the TCP decoder to receive the decoded IPv6 packets
|
||||
*/
|
||||
public void bind(KrakenTcpHandler tcpProtocol) {
|
||||
krakenIpv6Decoder.register(InternetProtocol.TCP, tcpProtocol.getKrakenTcpDecoder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding from this IPv6 decoder to an UDP decoder.
|
||||
*
|
||||
* @param udpHandler the UDP decoder to receive the decoded IPv6 packets
|
||||
*/
|
||||
public void bind(KrakenUdpHandler udpHandler) {
|
||||
krakenIpv6Decoder.register(InternetProtocol.UDP, udpHandler.getKrakenUdpDecoder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the internal {@link org.krakenapps.pcap.decoder.ipv6.Ipv6Decoder} to an ICMPv6 decoder, i.e.
|
||||
* a decoder that shall receive all decoded IP packets.
|
||||
*
|
||||
* @param icmpv6Handler the ICMPv6 decoder to bind to
|
||||
* @throws java.lang.IllegalArgumentException if the parameter is a null pointer
|
||||
*/
|
||||
public void bind(KrakenIcmpv6Handler icmpv6Handler) {
|
||||
krakenIpv6Decoder.register(InternetProtocol.ICMPV6, icmpv6Handler.getKrakenImpv6Decoder());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Internally used IPv6 decoder
|
||||
*/
|
||||
public Ipv6Decoder getKrakenIpv6Decoder() {
|
||||
return krakenIpv6Decoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.msn.MsnActivity;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenTcpProtocolMapperStrategy;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenTransportLayerMappingFactory;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.msn.MsnDecoder;
|
||||
|
||||
/**
|
||||
* Handles Kraken's {@link org.krakenapps.pcap.decoder.msn.MsnDecoder} output
|
||||
* and creates suitable {@link at.jku.fim.rubanetra.protocol.activity.msn.MsnActivity} objects
|
||||
* during the process.
|
||||
* This class does not provide any bindings.
|
||||
*/
|
||||
public class KrakenMsnHandler extends KrakenBaseProtocol {
|
||||
public static final String NEW_MSN_ACTIVITY_PROPERTY_NAME = "newMsnActivity";
|
||||
public static final KrakenApplicationProtocolId krakenMsnProtocolId = new KrakenApplicationProtocolId() {
|
||||
private final String protocolId = Protocol.MSN.name();
|
||||
|
||||
@Override
|
||||
public Protocol getKrakenApplicationProtocol() {
|
||||
return Protocol.MSN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Msn";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
private final KrakenTransportLayerMappingFactory mappingFactory = new KrakenTransportLayerMappingFactory();
|
||||
private KrakenTcpProtocolMapperStrategy tcpMappingStrategy;
|
||||
private MsnDecoder krakenMsnDecoder;
|
||||
|
||||
public KrakenMsnHandler() {
|
||||
krakenMsnDecoder = new MsnDecoder();
|
||||
krakenMsnDecoder.register(this::fireNewMsnActivity);
|
||||
}
|
||||
|
||||
private void fireNewMsnActivity(String account, String chat) {
|
||||
MsnActivity msnAct = new MsnActivity(getCurrentPcapActivity(), account, chat);
|
||||
propertyChangeSupport.firePropertyChange(NEW_MSN_ACTIVITY_PROPERTY_NAME, null, msnAct);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenMsnProtocolId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internally used MSN decoder
|
||||
*/
|
||||
public MsnDecoder getKrakenMsnDecoder() {
|
||||
return krakenMsnDecoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.netbios.NetbiosActivity;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.netbios.NetBiosDecoder;
|
||||
|
||||
/**
|
||||
* This class tries to handle various Netbios events dispatched by the internally
|
||||
* used {@link org.krakenapps.pcap.decoder.netbios.NetBiosDecoder}.
|
||||
* Appropriate {@link at.jku.fim.rubanetra.protocol.activity.netbios.NetbiosActivity}
|
||||
* objects are constructed for those events, however, be aware that this class
|
||||
* has not yet been tested at all.
|
||||
* This class does not provide any bindings.
|
||||
*/
|
||||
public class KrakenNetbiosHandler extends KrakenBaseProtocol {
|
||||
public static final KrakenApplicationProtocolId krakenNetbiosProtocolId = new KrakenApplicationProtocolId() {
|
||||
@Override
|
||||
public Protocol getKrakenApplicationProtocol() {
|
||||
return Protocol.NETBIOS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return Protocol.NETBIOS.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Netbios";
|
||||
}
|
||||
};
|
||||
|
||||
private final NetBiosDecoder krakenNetbiosDecoder;
|
||||
|
||||
public KrakenNetbiosHandler() {
|
||||
krakenNetbiosDecoder = new NetBiosDecoder();
|
||||
krakenNetbiosDecoder.registerDatagramProcessor(netBiosDatagramPacket -> {
|
||||
NetbiosActivity act = new NetbiosActivity(getCurrentPcapActivity(), netBiosDatagramPacket);
|
||||
fireNewNetbiosActivity(act);
|
||||
});
|
||||
krakenNetbiosDecoder.registerNameProcessor(netBiosNamePacket -> {
|
||||
NetbiosActivity act = new NetbiosActivity(getCurrentPcapActivity(), netBiosNamePacket);
|
||||
fireNewNetbiosActivity(act);
|
||||
});
|
||||
}
|
||||
|
||||
private void fireNewNetbiosActivity(NetbiosActivity act) {
|
||||
propertyChangeSupport.firePropertyChange("newNetbiosActivity", null, act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenNetbiosProtocolId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internally used NetBios decoder
|
||||
*/
|
||||
public NetBiosDecoder getKrakenNetbiosDecoder() {
|
||||
return krakenNetbiosDecoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.pop3.Pop3Activity;
|
||||
import org.krakenapps.mime.MimeHeader;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.pop3.Pop3Data;
|
||||
import org.krakenapps.pcap.decoder.pop3.Pop3Decoder;
|
||||
import org.krakenapps.pcap.decoder.pop3.Pop3Processor;
|
||||
|
||||
/**
|
||||
* This class utilizes a {@link org.krakenapps.pcap.decoder.pop3.Pop3Decoder} in order
|
||||
* to dispatch {@link at.jku.fim.rubanetra.protocol.activity.pop3.Pop3Activity} objects
|
||||
* for decoded events.
|
||||
* It does not provide any bindings.
|
||||
*/
|
||||
public class KrakenPop3Handler extends KrakenBaseProtocol {
|
||||
public static final KrakenApplicationProtocolId krakenPop3ProtocolId = new KrakenApplicationProtocolId() {
|
||||
@Override
|
||||
public Protocol getKrakenApplicationProtocol() {
|
||||
return Protocol.POP3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return Protocol.POP3.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Pop3";
|
||||
}
|
||||
};
|
||||
|
||||
private final Pop3Decoder krakenPop3Decoder;
|
||||
|
||||
public KrakenPop3Handler() {
|
||||
krakenPop3Decoder = new Pop3Decoder();
|
||||
krakenPop3Decoder.register(new Pop3Processor() {
|
||||
@Override
|
||||
public void onReceive(MimeHeader header, Pop3Data data) {
|
||||
Pop3Activity act = new Pop3Activity(getCurrentPcapActivity(), Pop3Activity.Type.RECEIVE);
|
||||
act.setHeader(header);
|
||||
act.setData(data);
|
||||
fireNewPartialPop3Activity(act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommand(String command) {
|
||||
Pop3Activity act = new Pop3Activity(getCurrentPcapActivity(), Pop3Activity.Type.COMMAND);
|
||||
act.setCommand(command);
|
||||
fireNewPartialPop3Activity(act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(String response) {
|
||||
Pop3Activity act = new Pop3Activity(getCurrentPcapActivity(), Pop3Activity.Type.RESPONSE);
|
||||
act.setResponse(response);
|
||||
fireNewPartialPop3Activity(act);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fireNewPartialPop3Activity(Pop3Activity act) {
|
||||
propertyChangeSupport.firePropertyChange("newPartialPop3Activity", null, act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenPop3ProtocolId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internally used Pop3 decoder
|
||||
*/
|
||||
public Pop3Decoder getKrakenPop3Decoder() {
|
||||
return krakenPop3Decoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.smtp.SmtpActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.smtp.SmtpCommandActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.smtp.SmtpReplyActivity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.smtp.SmtpSendActivity;
|
||||
import org.krakenapps.mime.MimeHeader;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.smtp.SmtpData;
|
||||
import org.krakenapps.pcap.decoder.smtp.SmtpDecoder;
|
||||
import org.krakenapps.pcap.decoder.smtp.SmtpProcessor;
|
||||
|
||||
/**
|
||||
* Uses a {@link org.krakenapps.pcap.decoder.smtp.SmtpDecoder} to receive decoded
|
||||
* SMTP data that is wrapped into appropriate {@link at.jku.fim.rubanetra.protocol.activity.smtp.SmtpActivity}
|
||||
* extension instances.
|
||||
* This class does not provide any bindings.
|
||||
*/
|
||||
public class KrakenSmtpHandler extends KrakenBaseProtocol {
|
||||
public static final String NEW_SMTP_SEND_ACTIVITY_PROPERTY_NAME = "newSmtpSendActivity";
|
||||
public static final String NEW_SMTP_COMMAND_ACTIVITY_PROPERTY_NAME = "newSmtpCommandActivity";
|
||||
public static final String NEW_SMTP_REPLY_ACTIVITY_PROPERTY_NAME = "newSmtpReplyActivity";
|
||||
public static final KrakenApplicationProtocolId krakenSmtpProtocolId = new KrakenApplicationProtocolId() {
|
||||
private final String protocolId = Protocol.SMTP.name();
|
||||
|
||||
@Override
|
||||
public Protocol getKrakenApplicationProtocol() {
|
||||
return Protocol.SMTP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Smtp";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
|
||||
private final SmtpDecoder krakenSmtpDecoder;
|
||||
|
||||
public KrakenSmtpHandler() {
|
||||
krakenSmtpDecoder = new SmtpDecoder();
|
||||
krakenSmtpDecoder.register(new SmtpProcessor() {
|
||||
@Override
|
||||
public void onSend(MimeHeader header, SmtpData data) {
|
||||
SmtpActivity act = new SmtpSendActivity(getCurrentPcapActivity(), header, data);
|
||||
propertyChangeSupport.firePropertyChange(NEW_SMTP_SEND_ACTIVITY_PROPERTY_NAME, null, act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommand(String command, String parameter) {
|
||||
SmtpActivity act = new SmtpCommandActivity(getCurrentPcapActivity(), command, parameter);
|
||||
propertyChangeSupport.firePropertyChange(NEW_SMTP_COMMAND_ACTIVITY_PROPERTY_NAME, null, act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReply(int code, String message) {
|
||||
SmtpActivity act = new SmtpReplyActivity(getCurrentPcapActivity(), code, message);
|
||||
propertyChangeSupport.firePropertyChange(NEW_SMTP_REPLY_ACTIVITY_PROPERTY_NAME, null, act);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenSmtpProtocolId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internally used SMTP decoder
|
||||
*/
|
||||
public SmtpDecoder getKrakenSmtpDecoder() {
|
||||
return krakenSmtpDecoder;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.snmp.Snmpv1Activity;
|
||||
import at.jku.fim.rubanetra.protocol.activity.snmp.Snmpv2Activity;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.snmp.SnmpDecoder;
|
||||
import org.krakenapps.pcap.decoder.snmp.v1.Pdu;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Handles decoded SNMP data by listening to appropriate events that are fired by
|
||||
* {@link org.krakenapps.pcap.decoder.snmp.SnmpDecoder} and creates
|
||||
* {@link at.jku.fim.rubanetra.protocol.activity.snmp.Snmpv1Activity}
|
||||
* and/or {@link at.jku.fim.rubanetra.protocol.activity.snmp.Snmpv2Activity}
|
||||
* objects.
|
||||
* This class does not provide any forward bindings and does not support
|
||||
* SNMPv3 due to lacking decoder support..
|
||||
*/
|
||||
public class KrakenSnmpHandler extends KrakenBaseProtocol {
|
||||
public static final KrakenApplicationProtocolId krakenSnmpProtocolId = new KrakenApplicationProtocolId() {
|
||||
@Override
|
||||
public Protocol getKrakenApplicationProtocol() {
|
||||
return Protocol.SNMP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return Protocol.SNMP.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Snmp";
|
||||
}
|
||||
};
|
||||
public static final String PROPERTY_NEW_SNMPV_1_ACTIVITY = "newSnmpv1Activity";
|
||||
public static final String PROPERTY_NEW_SNMPV_2_ACTIVITY = "newSnmpv2Activity";
|
||||
private final SnmpDecoder krakenSnmpDecoder;
|
||||
|
||||
public KrakenSnmpHandler() {
|
||||
krakenSnmpDecoder = new SnmpDecoder();
|
||||
krakenSnmpDecoder.register((InetSocketAddress source, InetSocketAddress destination, Pdu pdu) -> {
|
||||
Snmpv1Activity act = new Snmpv1Activity(getCurrentPcapActivity(), pdu, source, destination);
|
||||
propertyChangeSupport.firePropertyChange(PROPERTY_NEW_SNMPV_1_ACTIVITY, null, act);
|
||||
});
|
||||
krakenSnmpDecoder.register((InetSocketAddress source, InetSocketAddress destination, org.krakenapps.pcap.decoder.snmp.v2.Pdu pdu) -> {
|
||||
Snmpv2Activity act = new Snmpv2Activity(getCurrentPcapActivity(), pdu, source, destination);
|
||||
propertyChangeSupport.firePropertyChange(PROPERTY_NEW_SNMPV_2_ACTIVITY, null, act);
|
||||
});
|
||||
// V3 is not yet implemented by Kraken
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenSnmpProtocolId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internally used SNMP decoder
|
||||
*/
|
||||
public SnmpDecoder getKrakenSnmpDecoder() {
|
||||
return krakenSnmpDecoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.tcp.TcpActivity;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenTcpProtocolMapperStrategy;
|
||||
import org.krakenapps.pcap.decoder.ip.InternetProtocol;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpDecoder;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpPacket;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpSession;
|
||||
|
||||
/**
|
||||
* This class handles TCP transport layer related events that are dispatched by
|
||||
* a {@link org.krakenapps.pcap.decoder.tcp.TcpDecoder}. The following properties
|
||||
* may be observed:
|
||||
* Due to Kraken's constraint of using a TCP-Next Protocol mapper, which is per se
|
||||
* not always desirable for certain use cases, a corresponding Mapper has to be
|
||||
* constructed and passed during the creation of the TCP decoder itself. Currently,
|
||||
* this is not directly feasible because in theory, the exact strategy is chosen
|
||||
* by the user and may deviate from application layer protocol to another application layer
|
||||
* protocol. This library constraint is respected by creating the TCP decoder
|
||||
* only during the invocation of {@link #initialize(at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration)}
|
||||
* as well as the transport layer to application layer mapping strategy.
|
||||
* However, if a restriction based, e.g. port-based, mapping strategy is considered it should be noted that
|
||||
* this class tries to dispatch TCP activities regardless of the mapping strategy
|
||||
* in use. These activities are exclusively passed to listeners on the individual
|
||||
* instance of this class, which may not care about a potential application layer
|
||||
* restriction that would in practice discard any non-relevant packets at the
|
||||
* transport layer due to the mapping strategy in use and prevent potentially useful analysis.
|
||||
* Therefore, {@link at.jku.fim.rubanetra.protocol.activity.tcp.TcpActivity} objects
|
||||
* are dispatched to all registered listeners regardless of mapping strategy restrictions in place, and any protocol handler
|
||||
* bindings will only receive those decoded packets that pass and conform to the mapping strategy in use (which
|
||||
* could be all, none or a subset of all TCP packets).
|
||||
* These forward bindings are currently comprised of:
|
||||
* <ul>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenHttpHandler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenMsnHandler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenDnsProtocolHandler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenFtpHandler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenNetbiosHandler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenPop3Handler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenTelnetHandler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenSmtpHandler}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class KrakenTcpHandler extends KrakenBaseProtocol {
|
||||
public static final String NEW_TCP_ACTIVITY_PROPERTY_NAME = "newTcpActivity";
|
||||
public static final ProtocolId krakenTcpProtocolId = new ProtocolId() {
|
||||
private final String protocolId = "Tcp";
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
private TcpDecoder krakenTcpDecoder;
|
||||
private KrakenTcpProtocolMapperStrategy tcpMappingStrategy;
|
||||
|
||||
@Override
|
||||
public void initialize(KrakenProtocolConfiguration setting) {
|
||||
super.initialize(setting);
|
||||
String mappingStrategyId = setting.getTransportLayerMappingStrategy();
|
||||
tcpMappingStrategy = setting.getTransportLayerMappingFactory().createTcpMappingStrategy(mappingStrategyId);
|
||||
tcpMappingStrategy.setup(setting);
|
||||
krakenTcpDecoder = new TcpDecoder(tcpMappingStrategy);
|
||||
krakenTcpDecoder.registerSegmentCallback((session, segment) -> fireNewTcpActivity((TcpPacket) segment, session));
|
||||
}
|
||||
|
||||
protected void fireNewTcpActivity(TcpPacket tcpPacket, TcpSession tcpSession) {
|
||||
TcpActivity tcpActivity = new TcpActivity(getCurrentPcapActivity(), tcpPacket, tcpSession);
|
||||
log.debug("Fire new TcpActivity, frame number: {}", tcpActivity.getPcapActivity().getFrameNumber());
|
||||
propertyChangeSupport.firePropertyChange(NEW_TCP_ACTIVITY_PROPERTY_NAME, null, tcpActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenTcpProtocolId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental backward binding from an IPv4 handler to this TCP handler
|
||||
*
|
||||
* @param protocol the IPv4 handler
|
||||
*/
|
||||
public void bind(KrakenIpv4Handler protocol) {
|
||||
protocol.getKrakenIpv4Decoder().register(InternetProtocol.TCP, krakenTcpDecoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental backward binding from an IPv6 handler to this TCP handler
|
||||
*
|
||||
* @param protocol the IPv6 handler
|
||||
*/
|
||||
public void bind(KrakenIpv6Handler protocol) {
|
||||
protocol.getKrakenIpv6Decoder().register(InternetProtocol.TCP, krakenTcpDecoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding to a HTTP protocol handler, i.e. all decoded TCP segments that correspond
|
||||
* to the transport layer mapping strategy will be forwarded to the provided HTTP handler.
|
||||
*
|
||||
* @param protocolHandler the HTTP protocol handler
|
||||
*/
|
||||
public void bind(KrakenHttpHandler protocolHandler) {
|
||||
tcpMappingStrategy.register(protocolHandler.getKrakenHttpDecoder(), KrakenHttpHandler.krakenHttpProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding to a MSN handler, i.e. all decoded TCP segments that correspond to
|
||||
* the transport layer mapping strategy will be forwarded to the provided MSN handler.
|
||||
*
|
||||
* @param protocolHandler the MSN protocol handler
|
||||
*/
|
||||
public void bind(KrakenMsnHandler protocolHandler) {
|
||||
tcpMappingStrategy.register(protocolHandler.getKrakenMsnDecoder(), KrakenMsnHandler.krakenMsnProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding to a DNS handler, i.e. all decoded TCP segments that correspond to
|
||||
* the transport layer mapping strategy will be forwarded to the provided DNS handler.
|
||||
*
|
||||
* @param dnsHandler the DNS protocol handler
|
||||
*/
|
||||
public void bind(KrakenDnsProtocolHandler dnsHandler) {
|
||||
tcpMappingStrategy.register(dnsHandler, KrakenDnsProtocolHandler.krakenDnsProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding to a FTP handler, i.e. all decoded TCP segments that correspond to
|
||||
* the transport layer mapping strategy will be forwarded to the provided protocol handler.
|
||||
*
|
||||
* @param ftpHandler the FTP protocol handler
|
||||
*/
|
||||
public void bind(KrakenFtpHandler ftpHandler) {
|
||||
tcpMappingStrategy.register(ftpHandler.getKrakenFtpDecoder(), KrakenFtpHandler.krakenFtpProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding to a NetBios handler, i.e. all decoded TCP segments that correspond to
|
||||
* the transport layer mapping strategy will be forwarded to the provided protocol handler.
|
||||
*
|
||||
* @param netbiosHandler the NetBios handler
|
||||
*/
|
||||
public void bind(KrakenNetbiosHandler netbiosHandler) {
|
||||
tcpMappingStrategy.register(netbiosHandler.getKrakenNetbiosDecoder(), KrakenNetbiosHandler.krakenNetbiosProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding to a POP3 handler, i.e. all decoded TCP segments that correspond to
|
||||
* the transport layer mapping strategy will be forwarded to the provided protocol handler.
|
||||
*
|
||||
* @param pop3Handler the POP3 handler
|
||||
*/
|
||||
public void bind(KrakenPop3Handler pop3Handler) {
|
||||
tcpMappingStrategy.register(pop3Handler.getKrakenPop3Decoder(), KrakenPop3Handler.krakenPop3ProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding to a Telnet handler, i.e. all decoded TCP segments that correspond to
|
||||
* the transport layer mapping strategy will be forwarded to the provided protocol handler.
|
||||
*
|
||||
* @param telnetHandler the Telnet handler
|
||||
*/
|
||||
public void bind(KrakenTelnetHandler telnetHandler) {
|
||||
tcpMappingStrategy.register(telnetHandler.getKrakenTelnetDecoder(), KrakenTelnetHandler.krakenTelnetProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding to a SMTP handler, i.e. all decoded TCP segments that correspond to
|
||||
* the transport layer mapping strategy will be forwarded to the provided protocol handler.
|
||||
*
|
||||
* @param smtpHandler the SMTP handler
|
||||
*/
|
||||
public void bind(KrakenSmtpHandler smtpHandler) {
|
||||
tcpMappingStrategy.register(smtpHandler.getKrakenSmtpDecoder(), KrakenSmtpHandler.krakenSmtpProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internally used TCP decoder
|
||||
*/
|
||||
public TcpDecoder getKrakenTcpDecoder() {
|
||||
return krakenTcpDecoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.telnet.TelnetActivity;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.telnet.*;
|
||||
|
||||
/**
|
||||
* Handles Telnet data decoded by the Kraken library and creates suitable
|
||||
* {@link at.jku.fim.rubanetra.protocol.activity.telnet.TelnetActivity}
|
||||
* objects that are dispatched to all registered listeners. These activities are
|
||||
* currently not reassembled, i.e. the session reassembly should be performed
|
||||
* via appropriate Drools rule specifications.
|
||||
*/
|
||||
public class KrakenTelnetHandler extends KrakenBaseProtocol {
|
||||
public static final KrakenApplicationProtocolId krakenTelnetProtocolId = new KrakenApplicationProtocolId() {
|
||||
@Override
|
||||
public Protocol getKrakenApplicationProtocol() {
|
||||
return Protocol.TELNET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return Protocol.TELNET.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Telnet";
|
||||
}
|
||||
};
|
||||
private final TelnetDecoder krakenTelnetDecoder;
|
||||
|
||||
public KrakenTelnetHandler() {
|
||||
krakenTelnetDecoder = new TelnetDecoder();
|
||||
krakenTelnetDecoder.register(new TelnetProcessor() {
|
||||
@Override
|
||||
public void onClientCommand(TelnetCommand command, TelnetOption option, byte[] data) {
|
||||
TelnetActivity act = new TelnetActivity(getCurrentPcapActivity(), TelnetActivity.Type.CLIENT_COMMAND);
|
||||
act.setCommand(command);
|
||||
act.setOption(option);
|
||||
act.setData(data);
|
||||
fireNewTelnetActivity(act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerCommand(TelnetCommand command, TelnetOption option, byte[] data) {
|
||||
TelnetActivity act = new TelnetActivity(getCurrentPcapActivity(), TelnetActivity.Type.SERVER_COMMAND);
|
||||
act.setCommand(command);
|
||||
act.setOption(option);
|
||||
act.setData(data);
|
||||
fireNewTelnetActivity(act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientAnsiControl(AnsiMode mode, TelnetCommand command, int[] arguments) {
|
||||
TelnetActivity act = new TelnetActivity(getCurrentPcapActivity(), TelnetActivity.Type.CLIENT_ANSICONTROL);
|
||||
act.setAnsiMode(mode);
|
||||
act.setCommand(command);
|
||||
act.setArguments(arguments);
|
||||
fireNewTelnetActivity(act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerAnsiControl(AnsiMode mode, TelnetCommand command, int[] arguments) {
|
||||
TelnetActivity act = new TelnetActivity(getCurrentPcapActivity(), TelnetActivity.Type.SERVER_ANSICONTROL);
|
||||
act.setAnsiMode(mode);
|
||||
act.setCommand(command);
|
||||
act.setArguments(arguments);
|
||||
fireNewTelnetActivity(act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientData(String text) {
|
||||
TelnetActivity act = new TelnetActivity(getCurrentPcapActivity(), TelnetActivity.Type.CLIENT_DATA);
|
||||
act.setText(text);
|
||||
fireNewTelnetActivity(act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerData(String text) {
|
||||
TelnetActivity act = new TelnetActivity(getCurrentPcapActivity(), TelnetActivity.Type.SERVER_DATA);
|
||||
act.setText(text);
|
||||
fireNewTelnetActivity(act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientTitle(String title) {
|
||||
TelnetActivity act = new TelnetActivity(getCurrentPcapActivity(), TelnetActivity.Type.CLIENT_TITLE);
|
||||
act.setTitle(title);
|
||||
fireNewTelnetActivity(act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerTitle(String title) {
|
||||
TelnetActivity act = new TelnetActivity(getCurrentPcapActivity(), TelnetActivity.Type.SERVER_TITLE);
|
||||
act.setTitle(title);
|
||||
fireNewTelnetActivity(act);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fireNewTelnetActivity(TelnetActivity act) {
|
||||
propertyChangeSupport.firePropertyChange("newPartialTelnetActivity", null, act);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenTelnetProtocolId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internally used Telnet decoder
|
||||
*/
|
||||
public TelnetDecoder getKrakenTelnetDecoder() {
|
||||
return krakenTelnetDecoder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.handler;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.ProtocolId;
|
||||
import at.jku.fim.rubanetra.protocol.KrakenBaseProtocol;
|
||||
import at.jku.fim.rubanetra.protocol.activity.udp.UdpActivity;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenTransportLayerMappingFactory;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenUdpProtocolMapperStrategy;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.ip.InternetProtocol;
|
||||
import org.krakenapps.pcap.decoder.udp.UdpDecoder;
|
||||
import org.krakenapps.pcap.decoder.udp.UdpPacket;
|
||||
|
||||
/**
|
||||
* This class handles UDP transport layer related events that are dispatched by
|
||||
* a {@link org.krakenapps.pcap.decoder.udp.UdpDecoder} similar to the
|
||||
* {@link at.jku.fim.rubanetra.protocol.handler.KrakenTcpHandler} implementation.
|
||||
* Due to Kraken's constraint of using a UDP-Next Protocol mapper, which is per se
|
||||
* not always desirable for certain use cases, a corresponding Mapper has to be
|
||||
* constructed and passed during the creation of the UDP decoder itself. Currently,
|
||||
* this is not directly feasible because in theory, the exact strategy is chosen
|
||||
* by the user and may deviate from application layer protocol to another application layer
|
||||
* protocol. This library constraint is respected by creating the UDP decoder
|
||||
* only during the invocation of {@link #initialize(at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration)}
|
||||
* as well as the transport layer to application layer mapping strategy.
|
||||
* However, if a restriction based, e.g. port-based, mapping strategy is considered it should be noted that
|
||||
* this class tries to dispatch UDP activities regardless of the mapping strategy
|
||||
* in use. These activities are exclusively passed to listeners on the individual
|
||||
* instance of this class, which may not care about a potential application layer
|
||||
* restriction that would in practice discard any non-relevant packets at the
|
||||
* transport layer due to the mapping strategy in use and prevent potentially useful analysis.
|
||||
* Therefore, {@link at.jku.fim.rubanetra.protocol.activity.udp.UdpActivity} objects
|
||||
* are dispatched to all registered listeners regardless of mapping strategy restrictions in place, and any protocol handler
|
||||
* bindings will only receive those decoded packets that pass and conform to the mapping strategy in use (which
|
||||
* could be all, none or a subset of all UDP packets).
|
||||
* These forward bindings are currently comprised of:
|
||||
* <ul>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenDnsProtocolHandler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenDhcpHandler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenNetbiosHandler}</li>
|
||||
* <li>-> {@link at.jku.fim.rubanetra.protocol.handler.KrakenSnmpHandler}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class KrakenUdpHandler extends KrakenBaseProtocol {
|
||||
private UdpDecoder krakenUdpDecoder;
|
||||
private KrakenUdpProtocolMapperStrategy mappingStrategy;
|
||||
|
||||
@Override
|
||||
public void initialize(KrakenProtocolConfiguration setting) {
|
||||
super.initialize(setting);
|
||||
String mappingStrategyId = setting.getTransportLayerMappingStrategy();
|
||||
mappingStrategy = setting.getTransportLayerMappingFactory().createUdpMappingStrategy(mappingStrategyId);
|
||||
mappingStrategy.setup(setting);
|
||||
krakenUdpDecoder = new UdpDecoder(mappingStrategy);
|
||||
krakenUdpDecoder.registerUdpProcessor(this::fireNewUdpActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolId getProtocolId() {
|
||||
return krakenUdpProtocolId;
|
||||
}
|
||||
|
||||
public static final ProtocolId krakenUdpProtocolId = new ProtocolId() {
|
||||
private final String protocolId = "Udp";
|
||||
|
||||
@Override
|
||||
public String getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
};
|
||||
|
||||
protected void fireNewUdpActivity(UdpPacket udpPacket) {
|
||||
UdpActivity udpActivity = new UdpActivity(getCurrentPcapActivity(), udpPacket);
|
||||
propertyChangeSupport.firePropertyChange("newUdpActivity", null, udpActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental backward binding from an IPv4 protocol decoder to this UDP decoder
|
||||
*
|
||||
* @param protocol the IPv4 handler
|
||||
*/
|
||||
public void bind(KrakenIpv4Handler protocol) {
|
||||
protocol.getKrakenIpv4Decoder().register(InternetProtocol.UDP, krakenUdpDecoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental backward binding from an IPv6 protocol decoder to this UDP decoder
|
||||
*
|
||||
* @param protocol the IPv6 handler
|
||||
*/
|
||||
public void bind(KrakenIpv6Handler protocol) {
|
||||
protocol.getKrakenIpv6Decoder().register(InternetProtocol.UDP, krakenUdpDecoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding from this UDP decoder to the provided DNS protocol handler, i.e.
|
||||
* any decoded UDP segments will be forwarded to the passed protocol decoder.
|
||||
*
|
||||
* @param dnsHandler the DNS protocol handler
|
||||
*/
|
||||
public void bind(KrakenDnsProtocolHandler dnsHandler) {
|
||||
mappingStrategy.register(dnsHandler, KrakenDnsProtocolHandler.krakenDnsProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding from this UDP decoder to the provided DHCP protocol handler, i.e.
|
||||
* any decoded UDP segments will be forwarded to the passed protocol decoder.
|
||||
*
|
||||
* @param dhcpHandler the DHCP protocol handler
|
||||
*/
|
||||
public void bind(KrakenDhcpHandler dhcpHandler) {
|
||||
mappingStrategy.register(dhcpHandler.getKrakenDhcpDecoder(), KrakenDhcpHandler.krakenDhcpProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding from this UDP decoder to the provided NetBios protocol handler, i.e.
|
||||
* any decoded UDP segments will be forwarded to the passed protocol decoder.
|
||||
*
|
||||
* @param netbiosHandler the NetBios handler
|
||||
*/
|
||||
public void bind(KrakenNetbiosHandler netbiosHandler) {
|
||||
mappingStrategy.register(netbiosHandler.getKrakenNetbiosDecoder(), KrakenNetbiosHandler.krakenNetbiosProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward binding from this UDP decoder to the provided SNMP protocol handler, i.e.
|
||||
* any decoded UDP segments will be forwarded to the passed protocol decoder.
|
||||
*
|
||||
* @param snmpHandler the SNMP protocol handler
|
||||
*/
|
||||
public void bind(KrakenSnmpHandler snmpHandler) {
|
||||
mappingStrategy.register(snmpHandler.getKrakenSnmpDecoder(), KrakenSnmpHandler.krakenSnmpProtocolId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internally used UDP protocol
|
||||
*/
|
||||
public UdpDecoder getKrakenUdpDecoder() {
|
||||
return krakenUdpDecoder;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.mapper;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpProcessor;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpProtocolMapper;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Extends the Kraken interface used for mapping a transport layer protocol (TCP in this case) to application layer
|
||||
* protocol decoders.
|
||||
*/
|
||||
public interface KrakenTcpProtocolMapperStrategy extends TcpProtocolMapper, TransportLayerMappingStrategy {
|
||||
/**
|
||||
* An unmodifiable collection of all registered decoders that are capable of processing TCP payloads.
|
||||
*
|
||||
* @return an unmodifiable collection of all registered decoders that are capable of processing TCP payloads.
|
||||
*/
|
||||
public abstract Set<TcpProcessor> getTcpProcessors();
|
||||
|
||||
/**
|
||||
* Registers a TCP processor for the given application layer protocol.
|
||||
*
|
||||
* @param processor the TCP processor to be registered for ...
|
||||
* @param protocolId ... the application layer protocol id
|
||||
*/
|
||||
public abstract void register(TcpProcessor processor, KrakenApplicationProtocolId protocolId);
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.mapper;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.protocol.mapper.impl.KrakenTcpDestinationPortProtocolMapper;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.impl.KrakenUdpDestinationPortProtocolMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Constructs suitable {@link at.jku.fim.rubanetra.protocol.mapper.TransportLayerMappingStrategy}
|
||||
* implementations given a specific strategy identifier string.
|
||||
* Handles both, the UDP and TCP strategies, i.e.: {@link at.jku.fim.rubanetra.protocol.mapper.KrakenTcpProtocolMapperStrategy}
|
||||
* and {@link at.jku.fim.rubanetra.protocol.mapper.KrakenUdpProtocolMapperStrategy}.
|
||||
* Custom strategies may be registered during runtime.
|
||||
* The default factory {@link #createDefaultKrakenTransportLayerMappingFactory()} only provides a
|
||||
* destination port strategy for TCP/UDP.
|
||||
*/
|
||||
public class KrakenTransportLayerMappingFactory {
|
||||
public static final String DESTINATION_PORT_STRATEGY = "DESTINATION_PORT";
|
||||
private final Map<String, Class<? extends KrakenTcpProtocolMapperStrategy>> tcpStrategyMap;
|
||||
private final Map<String, Class<? extends KrakenUdpProtocolMapperStrategy>> udpStrategyMap;
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public KrakenTransportLayerMappingFactory() {
|
||||
tcpStrategyMap = new HashMap<>();
|
||||
udpStrategyMap = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a default transport layer mapping factory that consists of only one strategy: a Destination port to
|
||||
* application layer protocol strategy, i.e. {@link at.jku.fim.rubanetra.protocol.mapper.impl.KrakenTcpDestinationPortProtocolMapper}
|
||||
* and {@link at.jku.fim.rubanetra.protocol.mapper.impl.KrakenUdpDestinationPortProtocolMapper}.
|
||||
*
|
||||
* @return the default transport layer mapping factory
|
||||
*/
|
||||
public static KrakenTransportLayerMappingFactory createDefaultKrakenTransportLayerMappingFactory() {
|
||||
KrakenTransportLayerMappingFactory factory = new KrakenTransportLayerMappingFactory();
|
||||
factory.registerTcpStrategy(DESTINATION_PORT_STRATEGY, KrakenTcpDestinationPortProtocolMapper.class);
|
||||
factory.registerUdpStrategy(DESTINATION_PORT_STRATEGY, KrakenUdpDestinationPortProtocolMapper.class);
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new TCP mapping strategy, the provided class must define a default constructor.
|
||||
*
|
||||
* @param tcpStrategyId the unique strategy identifier
|
||||
* @param tcpStrategyClass the class to map to the identifier
|
||||
*/
|
||||
public void registerTcpStrategy(String tcpStrategyId, Class<? extends KrakenTcpProtocolMapperStrategy> tcpStrategyClass) {
|
||||
if (tcpStrategyMap.containsKey(tcpStrategyId)) {
|
||||
log.error("{} has already been registered as TCP mapping strategy.", tcpStrategyId);
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
tcpStrategyMap.put(tcpStrategyId, tcpStrategyClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new UDP mapping strategy, the provided class must define a default constructor
|
||||
*
|
||||
* @param udpStrategyId the unique strategy identifier
|
||||
* @param udpStrategyClass the class to map to the identifier
|
||||
*/
|
||||
public void registerUdpStrategy(String udpStrategyId, Class<? extends KrakenUdpProtocolMapperStrategy> udpStrategyClass) {
|
||||
if (udpStrategyMap.containsKey(udpStrategyId)) {
|
||||
log.error("{} has already been registered as UDP mapping strategy.", udpStrategyId);
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
udpStrategyMap.put(udpStrategyId, udpStrategyClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to create a new mapping strategy using the passed identifier to determine the mapping class that will be
|
||||
* instantiated using the default constructor.
|
||||
*
|
||||
* @param mappingStrategy the identifier that was used to register the TCP mapping strategy
|
||||
* @return a new instance of a TCP mapping strategy
|
||||
*/
|
||||
public KrakenTcpProtocolMapperStrategy createTcpMappingStrategy(String mappingStrategy) {
|
||||
Class<? extends KrakenTcpProtocolMapperStrategy> tcpProtocolMapperClass = tcpStrategyMap.get(mappingStrategy);
|
||||
if (tcpProtocolMapperClass == null) {
|
||||
throw new IllegalArgumentException(String.format("Mapping strategy %s was not registered to the TransportLayerMappingFactory", mappingStrategy));
|
||||
}
|
||||
|
||||
try {
|
||||
return tcpProtocolMapperClass.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
throw new IllegalArgumentException(String.format("A default constructor for mapping strategy %s and class %s must be provided.", mappingStrategy, tcpProtocolMapperClass.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to create a new mapping strategy using the passed identifier to determine the mapping class that will be
|
||||
* instantiated using the default constructor.
|
||||
*
|
||||
* @param mappingStrategy the identifier that was used to register the UDP mapping strategy
|
||||
* @return a new instance of a UDP mapping strategy
|
||||
*/
|
||||
public KrakenUdpProtocolMapperStrategy createUdpMappingStrategy(String mappingStrategy) {
|
||||
Class<? extends KrakenUdpProtocolMapperStrategy> udpProtocolMapperClass = udpStrategyMap.get(mappingStrategy);
|
||||
if (udpProtocolMapperClass == null) {
|
||||
throw new IllegalArgumentException(String.format("Mapping strategy %s was not registered to the TransportLayerMappingFactory", mappingStrategy));
|
||||
}
|
||||
|
||||
try {
|
||||
return udpProtocolMapperClass.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
throw new IllegalArgumentException(String.format("Please provide a default constructor for mapping strategy %s and class %s.", mappingStrategy, udpProtocolMapperClass.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.mapper;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import org.krakenapps.pcap.decoder.udp.UdpProcessor;
|
||||
import org.krakenapps.pcap.decoder.udp.UdpProtocolMapper;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Extends the Kraken interface used for mapping a transport layer protocol (UDP in this case) to application layer
|
||||
* protocol decoders following a certain strategy.
|
||||
*/
|
||||
public interface KrakenUdpProtocolMapperStrategy extends UdpProtocolMapper, TransportLayerMappingStrategy {
|
||||
/**
|
||||
* Registers an UDP processor that is capable of parsing application layer protocol, identified by
|
||||
* the protocolId, specific data.
|
||||
*
|
||||
* @param processor the UDP processor for a protocol identified by ...
|
||||
* @param protocolId the application layer protocol identifier
|
||||
*/
|
||||
public abstract void register(UdpProcessor processor, KrakenApplicationProtocolId protocolId);
|
||||
|
||||
/**
|
||||
* Returns the unmodifiable set of all registered UDP processors.
|
||||
*
|
||||
* @return the unmodifiable set of all registered UDP processors
|
||||
*/
|
||||
public abstract Set<UdpProcessor> getUdpProcessors();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.mapper;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
|
||||
/**
|
||||
* Defines a strategy that defines a way how a transport layer protocol is mapped to an application layer protocol
|
||||
* decoder.
|
||||
*/
|
||||
public interface TransportLayerMappingStrategy {
|
||||
public abstract void setup(KrakenProtocolConfiguration protocolSetting);
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.mapper.impl;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.PortSpecification;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenTcpProtocolMapperStrategy;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpProcessor;
|
||||
import org.krakenapps.pcap.decoder.tcp.TcpSegment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Maps a TCP based {@link at.jku.fim.rubanetra.config.model.PortSpecification} to a single application
|
||||
* layer protocol. Multiple TCP processors may be registered for the same application layer protocol.
|
||||
*/
|
||||
public class KrakenTcpDestinationPortProtocolMapper implements KrakenTcpProtocolMapperStrategy {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final Set<TcpProcessor> tcpProcessorSet;
|
||||
private PortSpecification portSpec;
|
||||
private KrakenApplicationProtocolId applicationProtocolId;
|
||||
|
||||
public KrakenTcpDestinationPortProtocolMapper() {
|
||||
this.tcpProcessorSet = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol map(TcpSegment segment) {
|
||||
// at this point we have to identify the protocol, however,
|
||||
// this is not feasible due to the invalid assumption that there is a single Protocol per port.
|
||||
// Therefore whenever the destination port is checked at this point not only one but several protocols
|
||||
// may be identified. There are at least two solutions to this issue: Either the raw buffer is parsed according
|
||||
// to every application protocol setting or the packet is decoded multiple times by different Protocol
|
||||
// Mappers.
|
||||
if (this.applicationProtocolId != null && portSpec.contains(segment.getDestinationPort())) {
|
||||
return this.applicationProtocolId.getKrakenApplicationProtocol();
|
||||
} else {
|
||||
log.debug("returning null pointer as KrakenProtocol for application layer protocol {}", applicationProtocolId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<TcpProcessor> getTcpProcessors(Protocol protocol) {
|
||||
if (this.applicationProtocolId == null) {
|
||||
if (protocol == null) {
|
||||
// this means probably that there is no official Application Layer Protocol as successor, therefore we return the set
|
||||
return Collections.unmodifiableCollection(tcpProcessorSet);
|
||||
} else {
|
||||
// protocols do not match
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
return protocol == this.applicationProtocolId.getKrakenApplicationProtocol() ?
|
||||
Collections.unmodifiableCollection(tcpProcessorSet) : Collections.unmodifiableCollection(new HashSet<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Protocol protocol, TcpProcessor processor) {
|
||||
if (this.applicationProtocolId == null || protocol != this.applicationProtocolId.getKrakenApplicationProtocol()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.tcpProcessorSet.add(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(Protocol protocol, TcpProcessor processor) {
|
||||
this.tcpProcessorSet.remove(processor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(InetSocketAddress server, Protocol protocol) {
|
||||
throw new IllegalStateException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(InetSocketAddress server) {
|
||||
throw new IllegalStateException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public TcpProcessor getTcpProcessor(Protocol protocol) {
|
||||
throw new IllegalStateException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void unregister(Protocol protocol) {
|
||||
throw new IllegalStateException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(KrakenProtocolConfiguration protocolSetting) {
|
||||
this.portSpec = protocolSetting.getPortSpecification();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(TcpProcessor processor, KrakenApplicationProtocolId protocolId) {
|
||||
if (this.applicationProtocolId != null) {
|
||||
throw new IllegalStateException("This destination port protocol mapper only supports a single Application Layer Protocol per instance");
|
||||
}
|
||||
this.tcpProcessorSet.add(processor);
|
||||
this.applicationProtocolId = protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TcpProcessor> getTcpProcessors() {
|
||||
return Collections.unmodifiableSet(tcpProcessorSet);
|
||||
}
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* This file is part of Rubanetra.
|
||||
* Copyright (C) 2013,2014 Stefan Swerk (stefan_rubanetra@swerk.priv.at)
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 at.jku.fim.rubanetra.protocol.mapper.impl;
|
||||
|
||||
|
||||
import at.jku.fim.rubanetra.config.model.KrakenApplicationProtocolId;
|
||||
import at.jku.fim.rubanetra.config.model.KrakenProtocolConfiguration;
|
||||
import at.jku.fim.rubanetra.config.model.PortSpecification;
|
||||
import at.jku.fim.rubanetra.protocol.mapper.KrakenUdpProtocolMapperStrategy;
|
||||
import org.krakenapps.pcap.Protocol;
|
||||
import org.krakenapps.pcap.decoder.udp.UdpPacket;
|
||||
import org.krakenapps.pcap.decoder.udp.UdpProcessor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Maps an UDP based {@link at.jku.fim.rubanetra.config.model.PortSpecification} to a single application
|
||||
* layer protocol. Multiple UDP processors may be registered for the same application layer protocol.
|
||||
*/
|
||||
public class KrakenUdpDestinationPortProtocolMapper implements KrakenUdpProtocolMapperStrategy {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private final Set<UdpProcessor> udpProcessorSet;
|
||||
private PortSpecification portSpec;
|
||||
private KrakenApplicationProtocolId applicationProtocolId;
|
||||
|
||||
public KrakenUdpDestinationPortProtocolMapper() {
|
||||
this.udpProcessorSet = new HashSet<>();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Protocol map(UdpPacket packet) {
|
||||
// at this point we have to identify the protocol, however,
|
||||
// this is not feasible due to the invalid assumption that there is a
|
||||
// single Protocol per port.
|
||||
// Therefore whenever the destination port is checked at this point not
|
||||
// only one but several protocols
|
||||
// may be identified. There are at least two solutions to this issue: Either the
|
||||
// raw buffer is parsed according
|
||||
// to every application protocol setting or the packet is decoded
|
||||
// multiple times by different Protocol
|
||||
// Mappers.
|
||||
if (this.applicationProtocolId != null && portSpec.contains(packet.getDestinationPort())) {
|
||||
return this.applicationProtocolId.getKrakenApplicationProtocol();
|
||||
} else {
|
||||
log.debug("returning null pointer as KrakenProtocol for application layer protocol {}", applicationProtocolId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<UdpProcessor> getUdpProcessors(Protocol protocol) {
|
||||
if (this.applicationProtocolId == null) {
|
||||
if (protocol == null) {
|
||||
// this means probably that there is no official Application Layer Protocol as successor, therefore we return the set
|
||||
return Collections.unmodifiableCollection(udpProcessorSet);
|
||||
} else {
|
||||
// protocols do not match
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
return protocol == this.applicationProtocolId.getKrakenApplicationProtocol() ?
|
||||
Collections.unmodifiableCollection(udpProcessorSet) : Collections.unmodifiableCollection(new HashSet<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public UdpProcessor getUdpProcessor(Protocol protocol) {
|
||||
throw new IllegalStateException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Protocol protocol, UdpProcessor processor) {
|
||||
if (this.applicationProtocolId == null || protocol != this.applicationProtocolId.getKrakenApplicationProtocol()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.udpProcessorSet.add(processor);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void unregister(Protocol protocol) {
|
||||
throw new IllegalStateException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(Protocol protocol, UdpProcessor processor) {
|
||||
throw new IllegalStateException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerTemporaryMapping(InetSocketAddress sockAddr, Protocol protocol) {
|
||||
throw new IllegalStateException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterTemporaryMapping(InetSocketAddress sockAddr) {
|
||||
throw new IllegalStateException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(KrakenProtocolConfiguration protocolSetting) {
|
||||
this.portSpec = protocolSetting.getPortSpecification();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(UdpProcessor processor, KrakenApplicationProtocolId protocolId) {
|
||||
if (this.applicationProtocolId != null) {
|
||||
throw new IllegalStateException("This destination port protocol mapper only supports a single Application Layer Protocol per instance");
|
||||
}
|
||||
this.udpProcessorSet.add(processor);
|
||||
this.applicationProtocolId = protocolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UdpProcessor> getUdpProcessors() {
|
||||
return Collections.unmodifiableSet(udpProcessorSet);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user