commit 5382fa57a4fa3100a56219e193f8eda3a3840ff3 Author: Stefan Date: Mon Apr 6 18:44:45 2020 +0200 Import from old repository diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0791525 --- /dev/null +++ b/README.md @@ -0,0 +1,99 @@ +### Compiling the project + +In order to compile this project the following prerequisites must be fulfilled: + - Java Development Kit v1.8 must be installed + (see http://www.oracle.com/technetwork/java/javase/downloads or http://openjdk.java.net/ ) + - Apache Maven must be installed (see https://maven.apache.org/, version 3.2.3 was used during development). + +The compilation process will not execute the provided test cases by default, nevertheless this behaviour +may be changed but additional prerequisites must be fulfilled first, please refer to the README file located in the test +resources directory (usually `src/test/resources/`). + +Afterwards, within the projects top level directory (containing the file `pom.xml`) execute: +```sh + $ mvn clean install +``` +This will create the new directory `target`, containing: + - **rubanetra-0.0.6-distribution.zip** + This archive represents the final binary project files, including default configuration files (`./conf/` + and dependencies (`./lib/`). + Use/unpack this archive to install the project on the target machine, however, please refer to the runtime + requirements listed below first. Ultimately, this archive should contain: + - **rubanetra-0.0.6.jar** + The compiled project binary. + - **rubanetra-0.0.6-(test-)sources.jar** + This archive contains the projects (test-)source code, including generated (test-)sources + and default configuration files. + - **rubanetra-0.0.6-javadoc.jar** + This archive contains the projects Java documentation. + - the directory `lib`, which contains all compiled third-party java-dependencies. + - the directory `conf`, which contains modifiable project specific configuration files. + - **rubanetra-0.0.6-package.zip** + This archive contains all sources needed to compile the project from scratch using maven. + It does not contain any binary dependencies. + +### Running the project +In order to run this project it must be ensured that + - jNetPcap/libpcap/WinPcap (platform dependent) native libraries are accessible via Java classpath. + - the main configuration file (defaults to `./conf/rubanetra.conf`) is available/accessible and adjusted accordingly. + The path to this file may alternatively be provided via command line argument `-c`). + - the Drools configuration folder (defaults to `./conf/META-INF`) is available/accessible and adjusted accordingly. + Note that for the current version 0.0.6, the actual Drools configuration folder must be + named `META-INF` and contain the file `kmodule.xml`, which represents the Drools knowledge base configuration + and is looked up/compiled by Drools during runtime. This allows to adjust the Knowledge-Base, + i.e. rule modifications/additions/deletions before each invocation without the need to compile a separate JAR. + - the SLF4J-logback logging configuration file (defaults to `./conf/logback.xml`) is available/accessible and + adjusted accordingly. + - the project was successfully compiled and Maven was able to resolve all dependencies. + +Additionally, it is recommended to compile the Rubanetra binding for the plaso project (http://plaso.kiddaland.net/) as +well, which is currently available at http://gitlab.swerk.priv.at/stefan/plaso-rubanetra. +For compilation instructions please follow the *Developers Guide* chapter +at https://github.com/log2timeline/plaso/wiki/Developers-Guide. + +The frontend main method for the project may then be invoked from the terminal by executing: +```sh + $ java -jar rubanetra-0.0.6.jar +``` +To provide the native libraries via `/usr/lib`: +```sh + $ java -cp /usr/lib -jar rubanetra-0.0.6.jar +``` +To provide a custom configuration directory (e.g. `/etc/rubanetra/conf`) and +native libraries via `/usr/lib`(substitute `:` with the underlying system path separator): +```sh + $ java -cp "/etc/rubanetra/conf:/usr/lib" -jar rubanetra-0.0.6.jar +``` + +### Dependencies + +This project utilizes jNetPcap (http://jnetpcap.com/) and therefore libpcap/WinPcap as PCAP-library. +Please follow the installation instructions of the jNetPcap-library (project was compiled with version +1.4.r1425-1d), especially the native library section and adjust the Java-Classpath accordingly. +As an alternative, the required native file classpath may be included in the final jar-Archive manifest by adjusting +the projects `pom.xml` property section (i.e. `library.directory` and `native.lib.classpath` properties) first +and recompiling afterwards. + +For a list of all utilized (including transitive) third party libraries refer to file `THIRD-PARTY.txt`. + +### Bugs + +Please report bugs concerning this project to: +http://gitlab.swerk.priv.at/stefan/rubanetra/issues + +### Version control / project home + +The latest version of this project may be obtained via git: +```sh + $ git clone http://gitlab.swerk.priv.at/stefan/rubanetra.git +``` +or by pointing a browser to http://gitlab.swerk.priv.at/stefan/rubanetra. + +### Hints +If a runtime exception like the following +> java.lang.UnsatisfiedLinkError: com.slytechs.library.NativeLibrary.dlopen(Ljava/lang/String;) + +is encountered, the JNetPcap-library (Java) was unable to locate the native library in the classpath, i.e. +either the JNetPcap native binding or libpcap is missing (see above). + +Special note for Ubuntu 12.04/14.04: The package `libpcap-dev` must be installed. diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..b3127fb --- /dev/null +++ b/README.txt @@ -0,0 +1,97 @@ +########################### +# Compiling the project # +########################### +In order to compile this project the following prerequisites must be fulfilled: + - Java Development Kit v1.8 must be installed + (see http://www.oracle.com/technetwork/java/javase/downloads or http://openjdk.java.net/ ) + - Apache Maven must be installed (see https://maven.apache.org/, version 3.2.3 was used during development). + +The compilation process will not execute the provided test cases by default, nevertheless this behaviour +may be changed but additional prerequisites must be fulfilled first, please refer to the README file located in the test +resources directory (usually 'src/test/resources/'). + +Afterwards, within the projects top level directory (containing the file 'pom.xml') execute: + $ mvn clean install + +This will create the new directory 'target', containing: + - "rubanetra-0.0.6-distribution.zip" + This archive represents the final binary project files, including default configuration files ('./conf/' + and dependencies ('./lib/'). + Use/unpack this archive to install the project on the target machine, however, please refer to the runtime + requirements listed below first. Ultimately, this archive should contain: + * "rubanetra-0.0.6.jar" + The compiled project binary. + * "rubanetra-0.0.6-(test-)sources.jar" + This archive contains the projects (test-)source code, including generated (test-)sources + and default configuration files. + * "rubanetra-0.0.6-javadoc.jar" + This archive contains the projects Java documentation. + * the directory 'lib', which contains all compiled third-party java-dependencies. + * the directory 'conf', which contains modifiable project specific configuration files. + - "rubanetra-0.0.6-package.zip" + This archive contains all sources needed to compile the project from scratch using maven. + It does not contain any binary dependencies. + +####################### +# Running the project # +####################### +In order to run this project it must be ensured that + - jNetPcap/libpcap/WinPcap (platform dependent) native libraries are accessible via Java classpath. + - the main configuration file (defaults to './conf/rubanetra.conf') is available/accessible and adjusted accordingly. + The path to this file may alternatively be provided via command line argument '-c'). + - the Drools configuration folder (defaults to './conf/META-INF') is available/accessible and adjusted accordingly. + Note that for the current version 0.0.6, the actual Drools configuration folder must be + named 'META-INF' and contain the file 'kmodule.xml', which represents the Drools knowledge base configuration + and is looked up/compiled by Drools during runtime. This allows to adjust the Knowledge-Base, + i.e. rule modifications/additions/deletions before each invocation without the need to compile a separate JAR. + - the SLF4J-logback logging configuration file (defaults to './conf/logback.xml') is available/accessible and + adjusted accordingly. + - the project was successfully compiled and Maven was able to resolve all dependencies. +Additionally, it is recommended to compile the Rubanetra binding for the plaso project (http://plaso.kiddaland.net/) as +well, which is currently available at http://gitlab.swerk.priv.at/stefan/plaso-rubanetra. +For compilation instructions please follow the "Developers Guide - How to build plaso from scratch" chapter +at https://github.com/log2timeline/plaso/wiki/Developers-Guide. + +The frontend main method for the project may then be invoked from the terminal by executing: + $ java -jar rubanetra-0.0.6.jar +To provide the native libraries via '/usr/lib': + $ java -cp /usr/lib -jar rubanetra-0.0.6.jar +To provide a custom configuration directory (e.g. '/etc/rubanetra/conf') and +native libraries via '/usr/lib'(substitute ':' with the underlying system path separator): + $ java -cp "/etc/rubanetra/conf:/usr/lib" -jar rubanetra-0.0.6.jar + +################ +# Dependencies # +################ +This project utilizes jNetPcap (http://jnetpcap.com/) and therefore libpcap/WinPcap as PCAP-library. +Please follow the installation instructions of the jNetPcap-library (project was compiled with version 1.4.r1425-1d), +especially the native library section and adjust the Java-Classpath accordingly. +As an alternative the required native file classpath may be included in the final jar-Archive manifest by adjusting +the projects 'pom.xml' property section (i.e. 'library.directory' and 'native.lib.classpath' properties) first +and recompiling afterwards. + +For a list of all utilized (including transitive) third party libraries refer to file 'THIRD-PARTY.txt'. + +######## +# Bugs # +######## +Please report bugs concerning this project to: + http://gitlab.swerk.priv.at/stefan/rubanetra/issues + +################################## +# Version control / project home # +################################## +The latest version of this project may be obtained via git: + git clone http://gitlab.swerk.priv.at/stefan/rubanetra.git +or by pointing a browser to: + http://gitlab.swerk.priv.at/stefan/rubanetra + +######### +# Hints # +######### +If a runtime exception like the following + java.lang.UnsatisfiedLinkError: com.slytechs.library.NativeLibrary.dlopen(Ljava/lang/String;) +is encountered, the JNetPcap-library (Java) was unable to locate the native library in the classpath, i.e. +either the JNetPcap native binding or libpcap is missing (see above). + +Special note for Ubuntu 12.04: The package 'libpcap-dev' must be installed. diff --git a/THIRD-PARTY.txt b/THIRD-PARTY.txt new file mode 100644 index 0000000..d810272 --- /dev/null +++ b/THIRD-PARTY.txt @@ -0,0 +1,51 @@ + +Lists of 49 third-party dependencies. + (Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Classic Module (ch.qos.logback:logback-classic:1.1.1 - http://logback.qos.ch) + (Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Core Module (ch.qos.logback:logback-core:1.1.1 - http://logback.qos.ch) + (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.5.0 - http://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.5.3 - https://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.5.3 - http://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) Jackson-dataformat-XML (com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.3 - http://wiki.fasterxml.com/JacksonExtensionXmlDataBinding) + (The Apache Software License, Version 2.0) Jackson-module-JAXB-annotations (com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.5.3 - http://wiki.fasterxml.com/JacksonJAXBAnnotations) + (New BSD license) Protocol Buffer Java API (com.google.protobuf:protobuf-java:2.5.0 - http://code.google.com/p/protobuf) + (BSD style) XStream Core (com.thoughtworks.xstream:xstream:1.4.7 - http://codehaus.org/xstream-parent/xstream/) + (The Apache Software License, Version 2.0) Commons CLI (commons-cli:commons-cli:1.2 - http://commons.apache.org/cli/) + (The Apache Software License, Version 2.0) Commons Codec (commons-codec:commons-codec:1.6 - http://commons.apache.org/codec/) + (The Apache Software License, Version 2.0) Commons Logging (commons-logging:commons-logging:1.1.3 - http://commons.apache.org/proper/commons-logging/) + (BSD 2-Clause license) dnsjava (dnsjava:dnsjava:2.1.7 - http://www.dnsjava.org) + (CDDL) (GPLv2+CE) JavaMail API (compat) (javax.mail:mail:1.4.7 - http://kenai.com/projects/javamail/mail) + (COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0) (GNU General Public Library) Streaming API for XML (javax.xml.stream:stax-api:1.0-2 - no url defined) + (GNU Lesser General Public License (LGPL) Version 3) jnetpcap (jnetpcap:jnetpcap:1.4.r1425-1d - no url defined) + (Common Public License Version 1.0) JUnit (junit:junit:4.11 - http://junit.org) + (BSD 3-Clause "New" or "Revised" License (BSD-3-Clause)) abego TreeLayout Core (org.abego.treelayout:org.abego.treelayout.core:1.0.1 - http://code.google.com/p/treelayout/) + (BSD licence) ANTLR 3 Runtime (org.antlr:antlr-runtime:3.5 - http://www.antlr.org) + (BSD 3-Clause License) ANTLR 4 Runtime (org.antlr:antlr4-runtime:4.5 - http://www.antlr.org) + (The Apache Software License, Version 2.0) Apache Commons CSV (org.apache.commons:commons-csv:1.0 - http://commons.apache.org/proper/commons-csv/) + (Apache License, Version 2.0) Apache HttpClient (org.apache.httpcomponents:httpclient:4.3.3 - http://hc.apache.org/httpcomponents-client) + (Apache License, Version 2.0) Apache HttpCore (org.apache.httpcomponents:httpcore:4.3.2 - http://hc.apache.org/httpcomponents-core-ga) + (The BSD License) Stax2 API (org.codehaus.woodstox:stax2-api:3.1.4 - http://wiki.fasterxml.com/WoodstoxStax2) + (The Apache Software License, Version 2.0) Woodstox (org.codehaus.woodstox:woodstox-core-asl:4.3.0 - http://woodstox.codehaus.org) + (The Apache Software License, Version 2.0) Drools :: Compiler (org.drools:drools-compiler:6.1.0.Final - http://www.jboss.org/drools/kie-parent-with-dependencies/drools-multiproject/drools-compiler) + (The Apache Software License, Version 2.0) Drools :: Core (org.drools:drools-core:6.1.0.Final - http://www.jboss.org/drools/kie-parent-with-dependencies/drools-multiproject/drools-core) + (Eclipse Public License v1.0) Eclipse ECJ (org.eclipse.jdt.core.compiler:ecj:4.3.1 - http://www.eclipse.org/jdt/) + (New BSD License) Hamcrest Core (org.hamcrest:hamcrest-core:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-core) + (The Apache Software License, Version 2.0) KIE API (org.kie:kie-api:6.1.0.Final - http://www.jboss.org/drools/kie-parent-with-dependencies/kie-api-parent/kie-api) + (The Apache Software License, Version 2.0) KIE Internal (org.kie:kie-internal:6.1.0.Final - http://www.jboss.org/drools/kie-parent-with-dependencies/kie-api-parent/kie-internal) + (Apache Software License 2) Kraken API (org.krakenapps:kraken-api:2.1.1 - http://maven.apache.org) + (Apache Software License 2) Kraken DHCP Decoder (org.krakenapps:kraken-dhcp-decoder:1.0.1 - http://krakenapps.org/kraken-pcap-pom/kraken-dhcp-decoder) + (Apache Software License 2) Kraken FTP Decoder (org.krakenapps:kraken-ftp-decoder:1.2.0 - http://krakenapps.org/kraken-pcap-pom/kraken-ftp-decoder) + (Apache Software License 2) Kraken HTTP Decoder (org.krakenapps:kraken-http-decoder:1.1.0 - http://krakenapps.org/kraken-pcap-pom/kraken-http-decoder) + (Apache Software License 2) Kraken JSON (org.krakenapps:kraken-json:1.1.1 - http://krakenapps.org/kraken-format-pom/kraken-json) + (Apache Software License 2) Kraken Mime (org.krakenapps:kraken-mime:1.0.0 - http://krakenapps.org/kraken-format-pom/kraken-mime) + (Apache Software License 2) Kraken MSN Decoder (org.krakenapps:kraken-msn-decoder:1.2.0 - http://krakenapps.org/kraken-pcap-pom/kraken-msn-decoder) + (Apache Software License 2) Kraken Netbios Decoder (org.krakenapps:kraken-netbios-decoder:1.0.0 - http://krakenapps.org/kraken-pcap-pom/kraken-netbios-decoder) + (Apache Software License 2) Kraken PCAP (org.krakenapps:kraken-pcap:1.7.1 - http://krakenapps.org/kraken-pcap-pom/kraken-pcap) + (Apache Software License 2) Kraken POP3 Decoder (org.krakenapps:kraken-pop3-decoder:1.0.0 - http://krakenapps.org/kraken-pcap-pom/kraken-pop3-decoder) + (Apache Software License 2) Kraken SMTP Decoder (org.krakenapps:kraken-smtp-decoder:1.1.0 - http://krakenapps.org/kraken-pcap-pom/kraken-smtp-decoder) + (Apache Software License 2) Kraken SNMP Decoder (org.krakenapps:kraken-snmp-decoder:1.1.0 - http://krakenapps.org/kraken-pcap-pom/kraken-snmp-decoder) + (Apache Software License 2) Kraken Telnet Decoder (org.krakenapps:kraken-telnet-decoder:1.0.0 - http://krakenapps.org/kraken-pcap-pom/kraken-telnet-decoder) + (The Apache Software License, Version 2.0) mvel (org.mvel:mvel2:2.2.1.Final - http://mvel.codehaus.org/) + (MIT License) JCL 1.1.1 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.7.6 - http://www.slf4j.org) + (MIT License) SLF4J API Module (org.slf4j:slf4j-api:1.7.6 - http://www.slf4j.org) + (Public Domain) XML Pull Parsing API (xmlpull:xmlpull:1.1.3.1 - http://www.xmlpull.org) + (Indiana University Extreme! Lab Software License, vesion 1.1.1) (Public Domain) MXP1: Xml Pull Parser 3rd Edition (XPP3) (xpp3:xpp3_min:1.1.4c - http://www.extreme.indiana.edu/xgws/xsoap/xpp/mxp1/) diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..3590837 --- /dev/null +++ b/pom.xml @@ -0,0 +1,748 @@ + + + 4.0.0 + at.jku.fim + rubanetra + 0.0.6 + Rubanetra + 2013 + + + + GNU General Public License, Version 3 + https://gnu.org/licenses/gpl-3.0.txt + repo + + + + + Institute of networks and security + https://ins.jku.at + + + + + stefan + Stefan Swerk + stefan_rubanetra@swerk.priv.at + + developer + + +1 + + + + + scm:git:http://gitlab.swerk.priv.at/stefan/rubanetra.git + http://gitlab.swerk.priv.at/stefan/rubanetra + + + Gitlab + http://gitlab.swerk.priv.at/stefan/rubanetra/issues + + + + + DefaultKnowledgeBase + DefaultSession + pcap + stdout + plaso + info + ./logs + ./lib + ./conf + /usr/lib + + + UTF-8 + UTF-8 + false + true + ${project.build.directory}/archive + 2014 + + + 1.4.r1425-1d + libjnetpcap + 1.7.1 + 4.5 + 6.1.0.Final + 4.3.3 + 2.1.7 + 4.11 + 2.5.3 + 1.7.6 + + + + + + OpenSOC-Kraken-Repo + OpenSOC Kraken Repository + https://raw.github.com/opensoc/kraken/mvn-repo + + + + + + + + + + + krakenapps.org - workaround + + true + ignore + + + false + + file://${project.basedir}/src/main/resources/kraken-workaround-repository + + + + + jboss-public-repository-group + JBoss Public Maven Repository Group + http://repository.jboss.org/nexus/content/groups/public/ + default + + true + always + + + true + always + + + + central + Central Maven Repository + default + http://repo1.maven.org/maven2 + + true + + + + clojars.org + Clojars Community Maven Repository + http://clojars.org/repo + + + + + jboss-public-repository-group + JBoss Public Maven Repository Group + http://repository.jboss.org/nexus/content/groups/public/ + default + + + central + Central Maven Repository + default + http://repo1.maven.org/maven2 + + true + + + + + + + junit + junit + ${junit.version} + test + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + jcl-over-slf4j + ${slf4j.version} + + + ch.qos.logback + logback-classic + 1.1.1 + + + commons-logging + commons-logging + 1.1.3 + provided + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + ${jackson.version} + + + org.codehaus.woodstox + woodstox-core-asl + 4.3.0 + + + javax.mail + mail + 1.4.7 + + + activation + javax.activation + + + + + org.krakenapps + kraken-pcap + ${krakenpcap.version} + + + slf4j-simple + org.slf4j + + + + + org.krakenapps + kraken-http-decoder + 1.1.0 + + + mail + javax.mail + + + + + org.krakenapps + kraken-smtp-decoder + 1.1.0 + + + activation + javax.activation + + + mail + javax.mail + + + + + org.krakenapps + kraken-ftp-decoder + 1.2.0 + + + mail + javax.mail + + + + + org.krakenapps + kraken-msn-decoder + 1.2.0 + + + mail + javax.mail + + + + + org.krakenapps + kraken-netbios-decoder + 1.0.0 + + + org.krakenapps + kraken-pop3-decoder + 1.0.0 + + + mail + javax.mail + + + + + org.krakenapps + kraken-dhcp-decoder + 1.0.1 + + + org.krakenapps + kraken-snmp-decoder + 1.1.0 + + + mail + javax.mail + + + + + org.krakenapps + kraken-telnet-decoder + 1.0.0 + + + jnetpcap + jnetpcap + ${jnetpcap.version} + + + org.antlr + antlr4-runtime + ${antlr.version} + + + org.drools + drools-core + ${drools.version} + + + org.drools + drools-compiler + ${drools.version} + + + org.kie + kie-api + ${drools.version} + + + org.apache.httpcomponents + httpclient + ${apachehttpclient.version} + + + commons-cli + commons-cli + 1.2 + + + org.apache.commons + commons-csv + 1.0 + + + dnsjava + dnsjava + ${dnsjava.version} + + + + + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.8 + 1.8 + true + true + -proc:none + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + false + ${archive.output.directory} + -Xdoclint:none + + + + attach-javadocs + prepare-package + + jar + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.16 + + true + + ${project.build.directory}/logs + DEBUG + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.4 + + + package + + single + + + + + + src/main/assembly/distribution-zip.xml + src/main/assembly/package-zip.xml + + gnu + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + ${archive.output.directory} + + + true + + false + ${library.directory}/ + false + at.jku.fim.rubanetra.config.ConfigurationController + true + + + ${config.directory}/ ${native.lib.classpath}/ + ${java.version} + ${os.name} + ${os.arch} + GPLv3 + GNU General Public License, Version 3 + https://gnu.org/licenses/gpl-3.0.txt + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + + ${project.inceptionYear} + ${recentYears} + Stefan Swerk (stefan_rubanetra@swerk.priv.at) + ${project.issueManagement.url} + ${project.scm.url} + + + + **/*.properties + **/*.drl + **/*.xml + **/*.conf + kraken-workaround-repository/** + ${droolsKnowledgeBase}/** + + + + + prepare-package + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + true + ${archive.output.directory} + + + + attach-sources + prepare-package + + jar-no-fork + + + + attach-test-sources + prepare-package + + test-jar-no-fork + + + + **/captures/** + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/antlr4 + + + + + + + org.antlr + antlr4-maven-plugin + ${antlr.version} + + + antlr + generate-sources + + antlr4 + + + + + + + + + + org.kie + kie-maven-plugin + ${drools.version} + true + + + org.apache.maven.plugins + maven-dependency-plugin + 2.8 + + + copy-dependencies + prepare-package + + copy-dependencies + + + ${project.build.directory}/lib + false + false + true + true + + + + unpack + compile + + unpack + + + + + jnetpcap + jnetpcap + ${jnetpcap.version} + jar + false + ${project.build.directory}/lib/${jnetpcap.native.lib.dirname} + + + + native/** + + + + + + org.codehaus.mojo + license-maven-plugin + 1.6 + + gpl_v3 + Stefan Swerk (stefan_rubanetra@swerk.priv.at) + true + true + + The Apache Software License, Version 2.0|Apache 2 + The Apache Software License, Version 2.0|Apache + License + + The Apache Software License, Version 2.0|Apache + License, Version 2.0 + + + + + + add-third-party + + add-third-party + + process-sources + + + + + + + + + + update-project-license + + update-project-license + + process-sources + + + + + org.apache.maven.plugins + maven-install-plugin + 2.5.1 + + true + + + + net.ju-n.maven.plugins + checksum-maven-plugin + 1.2 + + + + artifacts + + + + + + MD5 + SHA-1 + SHA-256 + + + + + com.mycila + license-maven-plugin + 2.6 + +
src/license/gpl_v3/header.txt
+ + Stefan Swerk + ${project.inceptionYear} + ${recentYears} + ${maven.build.timestamp} + stefan_rubanetra@swerk.priv.at + + true + + JAVADOC_STYLE + JAVADOC_STYLE + JAVADOC_STYLE + +
+ + + license-basedir + process-sources + + format + + + ${project.basedir} + + **/README* + **/LICENSE* + src/license/gpl_v3/** + src/main/resources/kraken-workaround-repository/** + src/test/resources/captures/** + + + pom.xml + src/** + + + + + license-gen-src + process-sources + + format + + + ${project.build.directory}/generated-sources/antlr4 + + **/README* + **/LICENSE* + **/*.tokens + + + + +
+
+
+
diff --git a/rubanetra-0.0.6-distribution/LICENSE.txt b/rubanetra-0.0.6-distribution/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/rubanetra-0.0.6-distribution/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/rubanetra-0.0.6-distribution/README.md b/rubanetra-0.0.6-distribution/README.md new file mode 100644 index 0000000..0791525 --- /dev/null +++ b/rubanetra-0.0.6-distribution/README.md @@ -0,0 +1,99 @@ +### Compiling the project + +In order to compile this project the following prerequisites must be fulfilled: + - Java Development Kit v1.8 must be installed + (see http://www.oracle.com/technetwork/java/javase/downloads or http://openjdk.java.net/ ) + - Apache Maven must be installed (see https://maven.apache.org/, version 3.2.3 was used during development). + +The compilation process will not execute the provided test cases by default, nevertheless this behaviour +may be changed but additional prerequisites must be fulfilled first, please refer to the README file located in the test +resources directory (usually `src/test/resources/`). + +Afterwards, within the projects top level directory (containing the file `pom.xml`) execute: +```sh + $ mvn clean install +``` +This will create the new directory `target`, containing: + - **rubanetra-0.0.6-distribution.zip** + This archive represents the final binary project files, including default configuration files (`./conf/` + and dependencies (`./lib/`). + Use/unpack this archive to install the project on the target machine, however, please refer to the runtime + requirements listed below first. Ultimately, this archive should contain: + - **rubanetra-0.0.6.jar** + The compiled project binary. + - **rubanetra-0.0.6-(test-)sources.jar** + This archive contains the projects (test-)source code, including generated (test-)sources + and default configuration files. + - **rubanetra-0.0.6-javadoc.jar** + This archive contains the projects Java documentation. + - the directory `lib`, which contains all compiled third-party java-dependencies. + - the directory `conf`, which contains modifiable project specific configuration files. + - **rubanetra-0.0.6-package.zip** + This archive contains all sources needed to compile the project from scratch using maven. + It does not contain any binary dependencies. + +### Running the project +In order to run this project it must be ensured that + - jNetPcap/libpcap/WinPcap (platform dependent) native libraries are accessible via Java classpath. + - the main configuration file (defaults to `./conf/rubanetra.conf`) is available/accessible and adjusted accordingly. + The path to this file may alternatively be provided via command line argument `-c`). + - the Drools configuration folder (defaults to `./conf/META-INF`) is available/accessible and adjusted accordingly. + Note that for the current version 0.0.6, the actual Drools configuration folder must be + named `META-INF` and contain the file `kmodule.xml`, which represents the Drools knowledge base configuration + and is looked up/compiled by Drools during runtime. This allows to adjust the Knowledge-Base, + i.e. rule modifications/additions/deletions before each invocation without the need to compile a separate JAR. + - the SLF4J-logback logging configuration file (defaults to `./conf/logback.xml`) is available/accessible and + adjusted accordingly. + - the project was successfully compiled and Maven was able to resolve all dependencies. + +Additionally, it is recommended to compile the Rubanetra binding for the plaso project (http://plaso.kiddaland.net/) as +well, which is currently available at http://gitlab.swerk.priv.at/stefan/plaso-rubanetra. +For compilation instructions please follow the *Developers Guide* chapter +at https://github.com/log2timeline/plaso/wiki/Developers-Guide. + +The frontend main method for the project may then be invoked from the terminal by executing: +```sh + $ java -jar rubanetra-0.0.6.jar +``` +To provide the native libraries via `/usr/lib`: +```sh + $ java -cp /usr/lib -jar rubanetra-0.0.6.jar +``` +To provide a custom configuration directory (e.g. `/etc/rubanetra/conf`) and +native libraries via `/usr/lib`(substitute `:` with the underlying system path separator): +```sh + $ java -cp "/etc/rubanetra/conf:/usr/lib" -jar rubanetra-0.0.6.jar +``` + +### Dependencies + +This project utilizes jNetPcap (http://jnetpcap.com/) and therefore libpcap/WinPcap as PCAP-library. +Please follow the installation instructions of the jNetPcap-library (project was compiled with version +1.4.r1425-1d), especially the native library section and adjust the Java-Classpath accordingly. +As an alternative, the required native file classpath may be included in the final jar-Archive manifest by adjusting +the projects `pom.xml` property section (i.e. `library.directory` and `native.lib.classpath` properties) first +and recompiling afterwards. + +For a list of all utilized (including transitive) third party libraries refer to file `THIRD-PARTY.txt`. + +### Bugs + +Please report bugs concerning this project to: +http://gitlab.swerk.priv.at/stefan/rubanetra/issues + +### Version control / project home + +The latest version of this project may be obtained via git: +```sh + $ git clone http://gitlab.swerk.priv.at/stefan/rubanetra.git +``` +or by pointing a browser to http://gitlab.swerk.priv.at/stefan/rubanetra. + +### Hints +If a runtime exception like the following +> java.lang.UnsatisfiedLinkError: com.slytechs.library.NativeLibrary.dlopen(Ljava/lang/String;) + +is encountered, the JNetPcap-library (Java) was unable to locate the native library in the classpath, i.e. +either the JNetPcap native binding or libpcap is missing (see above). + +Special note for Ubuntu 12.04/14.04: The package `libpcap-dev` must be installed. diff --git a/rubanetra-0.0.6-distribution/README.txt b/rubanetra-0.0.6-distribution/README.txt new file mode 100644 index 0000000..b3127fb --- /dev/null +++ b/rubanetra-0.0.6-distribution/README.txt @@ -0,0 +1,97 @@ +########################### +# Compiling the project # +########################### +In order to compile this project the following prerequisites must be fulfilled: + - Java Development Kit v1.8 must be installed + (see http://www.oracle.com/technetwork/java/javase/downloads or http://openjdk.java.net/ ) + - Apache Maven must be installed (see https://maven.apache.org/, version 3.2.3 was used during development). + +The compilation process will not execute the provided test cases by default, nevertheless this behaviour +may be changed but additional prerequisites must be fulfilled first, please refer to the README file located in the test +resources directory (usually 'src/test/resources/'). + +Afterwards, within the projects top level directory (containing the file 'pom.xml') execute: + $ mvn clean install + +This will create the new directory 'target', containing: + - "rubanetra-0.0.6-distribution.zip" + This archive represents the final binary project files, including default configuration files ('./conf/' + and dependencies ('./lib/'). + Use/unpack this archive to install the project on the target machine, however, please refer to the runtime + requirements listed below first. Ultimately, this archive should contain: + * "rubanetra-0.0.6.jar" + The compiled project binary. + * "rubanetra-0.0.6-(test-)sources.jar" + This archive contains the projects (test-)source code, including generated (test-)sources + and default configuration files. + * "rubanetra-0.0.6-javadoc.jar" + This archive contains the projects Java documentation. + * the directory 'lib', which contains all compiled third-party java-dependencies. + * the directory 'conf', which contains modifiable project specific configuration files. + - "rubanetra-0.0.6-package.zip" + This archive contains all sources needed to compile the project from scratch using maven. + It does not contain any binary dependencies. + +####################### +# Running the project # +####################### +In order to run this project it must be ensured that + - jNetPcap/libpcap/WinPcap (platform dependent) native libraries are accessible via Java classpath. + - the main configuration file (defaults to './conf/rubanetra.conf') is available/accessible and adjusted accordingly. + The path to this file may alternatively be provided via command line argument '-c'). + - the Drools configuration folder (defaults to './conf/META-INF') is available/accessible and adjusted accordingly. + Note that for the current version 0.0.6, the actual Drools configuration folder must be + named 'META-INF' and contain the file 'kmodule.xml', which represents the Drools knowledge base configuration + and is looked up/compiled by Drools during runtime. This allows to adjust the Knowledge-Base, + i.e. rule modifications/additions/deletions before each invocation without the need to compile a separate JAR. + - the SLF4J-logback logging configuration file (defaults to './conf/logback.xml') is available/accessible and + adjusted accordingly. + - the project was successfully compiled and Maven was able to resolve all dependencies. +Additionally, it is recommended to compile the Rubanetra binding for the plaso project (http://plaso.kiddaland.net/) as +well, which is currently available at http://gitlab.swerk.priv.at/stefan/plaso-rubanetra. +For compilation instructions please follow the "Developers Guide - How to build plaso from scratch" chapter +at https://github.com/log2timeline/plaso/wiki/Developers-Guide. + +The frontend main method for the project may then be invoked from the terminal by executing: + $ java -jar rubanetra-0.0.6.jar +To provide the native libraries via '/usr/lib': + $ java -cp /usr/lib -jar rubanetra-0.0.6.jar +To provide a custom configuration directory (e.g. '/etc/rubanetra/conf') and +native libraries via '/usr/lib'(substitute ':' with the underlying system path separator): + $ java -cp "/etc/rubanetra/conf:/usr/lib" -jar rubanetra-0.0.6.jar + +################ +# Dependencies # +################ +This project utilizes jNetPcap (http://jnetpcap.com/) and therefore libpcap/WinPcap as PCAP-library. +Please follow the installation instructions of the jNetPcap-library (project was compiled with version 1.4.r1425-1d), +especially the native library section and adjust the Java-Classpath accordingly. +As an alternative the required native file classpath may be included in the final jar-Archive manifest by adjusting +the projects 'pom.xml' property section (i.e. 'library.directory' and 'native.lib.classpath' properties) first +and recompiling afterwards. + +For a list of all utilized (including transitive) third party libraries refer to file 'THIRD-PARTY.txt'. + +######## +# Bugs # +######## +Please report bugs concerning this project to: + http://gitlab.swerk.priv.at/stefan/rubanetra/issues + +################################## +# Version control / project home # +################################## +The latest version of this project may be obtained via git: + git clone http://gitlab.swerk.priv.at/stefan/rubanetra.git +or by pointing a browser to: + http://gitlab.swerk.priv.at/stefan/rubanetra + +######### +# Hints # +######### +If a runtime exception like the following + java.lang.UnsatisfiedLinkError: com.slytechs.library.NativeLibrary.dlopen(Ljava/lang/String;) +is encountered, the JNetPcap-library (Java) was unable to locate the native library in the classpath, i.e. +either the JNetPcap native binding or libpcap is missing (see above). + +Special note for Ubuntu 12.04: The package 'libpcap-dev' must be installed. diff --git a/rubanetra-0.0.6-distribution/THIRD-PARTY.txt b/rubanetra-0.0.6-distribution/THIRD-PARTY.txt new file mode 100644 index 0000000..d810272 --- /dev/null +++ b/rubanetra-0.0.6-distribution/THIRD-PARTY.txt @@ -0,0 +1,51 @@ + +Lists of 49 third-party dependencies. + (Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Classic Module (ch.qos.logback:logback-classic:1.1.1 - http://logback.qos.ch) + (Eclipse Public License - v 1.0) (GNU Lesser General Public License) Logback Core Module (ch.qos.logback:logback-core:1.1.1 - http://logback.qos.ch) + (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.5.0 - http://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.5.3 - https://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.5.3 - http://github.com/FasterXML/jackson) + (The Apache Software License, Version 2.0) Jackson-dataformat-XML (com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.3 - http://wiki.fasterxml.com/JacksonExtensionXmlDataBinding) + (The Apache Software License, Version 2.0) Jackson-module-JAXB-annotations (com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.5.3 - http://wiki.fasterxml.com/JacksonJAXBAnnotations) + (New BSD license) Protocol Buffer Java API (com.google.protobuf:protobuf-java:2.5.0 - http://code.google.com/p/protobuf) + (BSD style) XStream Core (com.thoughtworks.xstream:xstream:1.4.7 - http://codehaus.org/xstream-parent/xstream/) + (The Apache Software License, Version 2.0) Commons CLI (commons-cli:commons-cli:1.2 - http://commons.apache.org/cli/) + (The Apache Software License, Version 2.0) Commons Codec (commons-codec:commons-codec:1.6 - http://commons.apache.org/codec/) + (The Apache Software License, Version 2.0) Commons Logging (commons-logging:commons-logging:1.1.3 - http://commons.apache.org/proper/commons-logging/) + (BSD 2-Clause license) dnsjava (dnsjava:dnsjava:2.1.7 - http://www.dnsjava.org) + (CDDL) (GPLv2+CE) JavaMail API (compat) (javax.mail:mail:1.4.7 - http://kenai.com/projects/javamail/mail) + (COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0) (GNU General Public Library) Streaming API for XML (javax.xml.stream:stax-api:1.0-2 - no url defined) + (GNU Lesser General Public License (LGPL) Version 3) jnetpcap (jnetpcap:jnetpcap:1.4.r1425-1d - no url defined) + (Common Public License Version 1.0) JUnit (junit:junit:4.11 - http://junit.org) + (BSD 3-Clause "New" or "Revised" License (BSD-3-Clause)) abego TreeLayout Core (org.abego.treelayout:org.abego.treelayout.core:1.0.1 - http://code.google.com/p/treelayout/) + (BSD licence) ANTLR 3 Runtime (org.antlr:antlr-runtime:3.5 - http://www.antlr.org) + (BSD 3-Clause License) ANTLR 4 Runtime (org.antlr:antlr4-runtime:4.5 - http://www.antlr.org) + (The Apache Software License, Version 2.0) Apache Commons CSV (org.apache.commons:commons-csv:1.0 - http://commons.apache.org/proper/commons-csv/) + (Apache License, Version 2.0) Apache HttpClient (org.apache.httpcomponents:httpclient:4.3.3 - http://hc.apache.org/httpcomponents-client) + (Apache License, Version 2.0) Apache HttpCore (org.apache.httpcomponents:httpcore:4.3.2 - http://hc.apache.org/httpcomponents-core-ga) + (The BSD License) Stax2 API (org.codehaus.woodstox:stax2-api:3.1.4 - http://wiki.fasterxml.com/WoodstoxStax2) + (The Apache Software License, Version 2.0) Woodstox (org.codehaus.woodstox:woodstox-core-asl:4.3.0 - http://woodstox.codehaus.org) + (The Apache Software License, Version 2.0) Drools :: Compiler (org.drools:drools-compiler:6.1.0.Final - http://www.jboss.org/drools/kie-parent-with-dependencies/drools-multiproject/drools-compiler) + (The Apache Software License, Version 2.0) Drools :: Core (org.drools:drools-core:6.1.0.Final - http://www.jboss.org/drools/kie-parent-with-dependencies/drools-multiproject/drools-core) + (Eclipse Public License v1.0) Eclipse ECJ (org.eclipse.jdt.core.compiler:ecj:4.3.1 - http://www.eclipse.org/jdt/) + (New BSD License) Hamcrest Core (org.hamcrest:hamcrest-core:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-core) + (The Apache Software License, Version 2.0) KIE API (org.kie:kie-api:6.1.0.Final - http://www.jboss.org/drools/kie-parent-with-dependencies/kie-api-parent/kie-api) + (The Apache Software License, Version 2.0) KIE Internal (org.kie:kie-internal:6.1.0.Final - http://www.jboss.org/drools/kie-parent-with-dependencies/kie-api-parent/kie-internal) + (Apache Software License 2) Kraken API (org.krakenapps:kraken-api:2.1.1 - http://maven.apache.org) + (Apache Software License 2) Kraken DHCP Decoder (org.krakenapps:kraken-dhcp-decoder:1.0.1 - http://krakenapps.org/kraken-pcap-pom/kraken-dhcp-decoder) + (Apache Software License 2) Kraken FTP Decoder (org.krakenapps:kraken-ftp-decoder:1.2.0 - http://krakenapps.org/kraken-pcap-pom/kraken-ftp-decoder) + (Apache Software License 2) Kraken HTTP Decoder (org.krakenapps:kraken-http-decoder:1.1.0 - http://krakenapps.org/kraken-pcap-pom/kraken-http-decoder) + (Apache Software License 2) Kraken JSON (org.krakenapps:kraken-json:1.1.1 - http://krakenapps.org/kraken-format-pom/kraken-json) + (Apache Software License 2) Kraken Mime (org.krakenapps:kraken-mime:1.0.0 - http://krakenapps.org/kraken-format-pom/kraken-mime) + (Apache Software License 2) Kraken MSN Decoder (org.krakenapps:kraken-msn-decoder:1.2.0 - http://krakenapps.org/kraken-pcap-pom/kraken-msn-decoder) + (Apache Software License 2) Kraken Netbios Decoder (org.krakenapps:kraken-netbios-decoder:1.0.0 - http://krakenapps.org/kraken-pcap-pom/kraken-netbios-decoder) + (Apache Software License 2) Kraken PCAP (org.krakenapps:kraken-pcap:1.7.1 - http://krakenapps.org/kraken-pcap-pom/kraken-pcap) + (Apache Software License 2) Kraken POP3 Decoder (org.krakenapps:kraken-pop3-decoder:1.0.0 - http://krakenapps.org/kraken-pcap-pom/kraken-pop3-decoder) + (Apache Software License 2) Kraken SMTP Decoder (org.krakenapps:kraken-smtp-decoder:1.1.0 - http://krakenapps.org/kraken-pcap-pom/kraken-smtp-decoder) + (Apache Software License 2) Kraken SNMP Decoder (org.krakenapps:kraken-snmp-decoder:1.1.0 - http://krakenapps.org/kraken-pcap-pom/kraken-snmp-decoder) + (Apache Software License 2) Kraken Telnet Decoder (org.krakenapps:kraken-telnet-decoder:1.0.0 - http://krakenapps.org/kraken-pcap-pom/kraken-telnet-decoder) + (The Apache Software License, Version 2.0) mvel (org.mvel:mvel2:2.2.1.Final - http://mvel.codehaus.org/) + (MIT License) JCL 1.1.1 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.7.6 - http://www.slf4j.org) + (MIT License) SLF4J API Module (org.slf4j:slf4j-api:1.7.6 - http://www.slf4j.org) + (Public Domain) XML Pull Parsing API (xmlpull:xmlpull:1.1.3.1 - http://www.xmlpull.org) + (Indiana University Extreme! Lab Software License, vesion 1.1.1) (Public Domain) MXP1: Xml Pull Parser 3rd Edition (XPP3) (xpp3:xpp3_min:1.1.4c - http://www.extreme.indiana.edu/xgws/xsoap/xpp/mxp1/) diff --git a/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/00.Basic.Metadata.drl b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/00.Basic.Metadata.drl new file mode 100644 index 0000000..29b836c --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/00.Basic.Metadata.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.arp.*; +import at.jku.fim.rubanetra.protocol.activity.dhcp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import at.jku.fim.rubanetra.protocol.activity.ethernet.*; +import at.jku.fim.rubanetra.protocol.activity.ftp.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.msn.*; +import at.jku.fim.rubanetra.protocol.activity.netbios.*; +import at.jku.fim.rubanetra.protocol.activity.pop3.*; +import at.jku.fim.rubanetra.protocol.activity.skype.*; +import at.jku.fim.rubanetra.protocol.activity.smtp.*; +import at.jku.fim.rubanetra.protocol.activity.snmp.*; +import at.jku.fim.rubanetra.protocol.activity.tcp.*; +import at.jku.fim.rubanetra.protocol.activity.telnet.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.udp.*; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * The following statements declare the metadata of already existing Java abstract classes/interfaces of the + * at.jku.fim.rubanetra.protocol.activity package. + * Specifically it defines these classes as events using the start-timestamp of the activity itself + * as the actual timestamp (used for reasoning) and sets the expiration time of the individual objects. + * If the objects should not expire based on this timer, remove or adapt the @expires attributes. + * Note, however, unless these attributes are overwritten on the Activity-class implementation level, these settings + * will be inherited for all activities (since all Activity-implementations should extend or implement one of the + * abstract classes/interfaces listed below. + */ + +declare DroolsBaseActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + @expires( 30m ) +end + +declare Activity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + @expires( 30m ) +end + +declare ReplaceableActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + @expires( 30m ) +end + +declare AbstractActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + @expires( 30m ) +end + +declare AbstractReplaceableActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + @expires( 30m ) +end \ No newline at end of file diff --git a/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/01.Basic.Output.drl b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/01.Basic.Output.drl new file mode 100644 index 0000000..674dd41 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/01.Basic.Output.drl @@ -0,0 +1,44 @@ +/** + * 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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * This global variable constitutes the default output writer that is used to write derived facts, i.e. Activity objects, + * to the final output stream. + */ +global at.jku.fim.rubanetra.output.OutputWriterStrategy outputWriter; + +/** + * This rule will ensure that all encountered OutputActivityEvents will be written to the final output stream, + * as long as the enclosed Activity 'toOutput' is not null and the global 'outputWriter' exists. + * The encountered, valid OutputActivityEvent will be retracted afterwards. + * This behaviour is useful to free memory in case the default event expiration time is not defined or + * set to a high value. + */ +rule "Write to OutputStream (event-based)" + when + $outEvent : OutputActivityEvent(toOutput != null) + then + if (outputWriter != null) { + outputWriter.writeActivity($outEvent.getToOutput()); + } + retract($outEvent); +end diff --git a/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/02.Basic.Http.drl b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/02.Basic.Http.drl new file mode 100644 index 0000000..b545318 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/02.Basic.Http.drl @@ -0,0 +1,201 @@ +/** + * 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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.tcp.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import org.xbill.DNS.*; +import org.apache.http.HttpHeaders; +import org.jnetpcap.protocol.tcpip.Tcp; +import org.jnetpcap.packet.PcapPacket; +import org.apache.commons.codec.binary.Hex; +import java.net.InetSocketAddress; +import java.util.HashSet; +import java.util.Date +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Set; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +/** + * This declaration serves as an example to demonstrate the basic attribute overriding process. + * Usually this class extends the Activity-interface and is declared to be an event. + * However, currently no time-based reasoning will be performed for these objects, therefore it can be + * converted to a Fact. + * This declaration may be removed to use the default attributes again (see 00.Basic.Metadata.drl). + */ +declare HttpImageActivity + @role( fact ) + @author( Stefan Swerk ) + @dateOfCreation( 10.01.2014 ) +end + +/** + * The following Tcp declaration represents the jNetPcap-Tcp class, see org.jnetpcap.protocol.tcpip.Tcp. + * Due to 'Tcp' being a Java class of a different library it cannot extend or implement one of the Activity + * base classes and therefore is not treated as a Drools-event per se. Therefore, the metadata of this custom + * class must be defined individually, which can be interpreted as a forward declaration. + */ +declare Tcp + @role( event ) + @author( Stefan Swerk ) + @timestamp( getPacket().getCaptureHeader().timestampInMillis() ) + @expires( 30m ) +end + +/** + * Currently it appears as if the Tcp-decoder of the Kraken library does not parse all valid Tcp-packets successfully. + * As a kind of workaround this rule has been defined to fallback to the jNetPcap library (hence the previous Tcp-forward + * declaration) for all IPv4 activities that indicate TCP as the encapsulated protocol, + * but that have not been decoded by the Kraken-Tcp-Decoder until now. + * This rule will ensure that an appropriate drop-in TcpActivity will be created and inserted in the event-stream, + * which may be used by other rules. + */ +rule "TCP (work around Kraken limitation)" +when + $ip : Ipv4Activity(ipv4.nextHeaderId == Tcp.ID) + not (exists TcpActivity(pcapActivity == $ip.pcapActivity)) +then + Tcp tcp = new Tcp(); + PcapPacket p = $ip.getPcapActivity().getPcapPacket(); + p.hasHeader(tcp); + log.debug("A workaround Tcp-Activity will be created for frames {}", $ip.getCompoundFrameNumbers()); + + TcpActivity tcpActivity = new TcpActivity($ip.getPcapActivity(),tcp,$ip); + tcpActivity.replaceActivity($ip); + insert(tcpActivity); +end + +/** + * This rules makes use of a custom entry-point called "fact-stream" and the previously declared fact-attribute of + * HttpImageActivity. If a HttpActivity is encountered containing an response that defined an "image/..." content_type + * header, it may be assumed that this reponse was used for delivering image data and the corresponding URL of the request + * contained the image path. + */ +rule "Http Image Activity" +no-loop +when + $httpActivity : HttpActivity($contentType : response.responseHeaderMap[HttpHeaders.CONTENT_TYPE] matches "image/.*", + imageActivities.isEmpty()) +then + log.debug("An HttpImageActivity based on the content type was found for frames {}", $httpActivity.getCompoundFrameNumbers()); + + HttpImageActivity imgAct = new HttpImageActivity($httpActivity); + imgAct.setImagePath($httpActivity.getRequest().getUrl().getFile()); + imgAct.setImageType($contentType); + imgAct.setStartInstant($httpActivity.getStartInstant()); + imgAct.setEndInstant($httpActivity.getEndInstant()); + drools.getEntryPoint("fact-stream").insert(imgAct); + modify($httpActivity){ + addImageActivity(imgAct) + } +end + +/** + * This rule fires iff there is a HttpImageActivity whose Requests REFERER Header field matches the Request-URI of + * another HttpActivity, i.e. it collects ImageActivities which may be related to a single HttpActivity. + * Consider the following example: A user queries a HTML-Resource that contains external image resources, + * and usually the browser creates subsequent HTTP requests for the image data retrieval. + * Whenever the Browser sets the Referer header field for those separate requests, we could correlate those separate + * image requests with a single HTML resource request. + */ +rule "Collect Http Image Activities (based on referer header)" +when + $http : HttpActivity($req : request, $reqResource : request.url.toString()) + $imgAct : HttpImageActivity(this not memberOf $http.imageActivities, + source#HttpActivity.request.requestHeaderMap[HttpHeaders.REFERER] matches $reqResource) + from entry-point "fact-stream" + +// add an additional time based constraint +// $htmlRequest : HttpRequestActivity( pcapActivity == $req.pcapActivity) +// $imgRequest : HttpRequestActivity( pcapActivity == $imgAct.source#HttpActivity.request.pcapActivity, +// this after[0s,10s] $htmlRequest) +// +// match a single image request for an image resource to a single request for an html resource only +// not (exists HttpRequestActivity(pcapActivity != $htmlRequest.pcapActivity, +// url.toString() matches $reqResource, +// this before $imgRequest)) +then + modify($http) { + addImageActivity($imgAct) + } +end + +/** + * Currently the event stream will only contain not yet matched HttpRequests and HttpResponses. + * Since the reasoning process will be enhanced by correlated each request to a response this rule tries to achieve + * a simple matching mechanism based on the TCP/IP source and destination port and address. + */ +rule "Http Request and Response Matching (based on TCP/IP source/destination and time)" +when + $tcpReq : TcpActivity( $reqId := pcapActivity, $src : sourceAddress, $dst : destinationAddress) + $request : HttpRequestActivity( $reqId := pcapActivity) + + $tcpResp : TcpActivity( $respId : pcapActivity, $tcpReq.sourcePort == destinationPort, + $src == destinationAddress, $dst == sourceAddress) + $response : HttpResponseActivity(pcapActivity == $respId, this after[0s,1m] $request) + + not (exists HttpActivity(request == $request || response == $response)) + +then + HttpActivity activity = new HttpActivity($request, $response); + log.debug("A HttpRequest was matched with a HttpResponse (frames {})", activity.getCompoundFrameNumbers()); + + insert(activity); +end + +/** + * This rule tries to match a DNS response to a an already existing HttpActivity using the hostname header field and + * a maximum interval between the DNS response and the Http response of [0s;20s]. + * An already existing DNS match of a HttpActivity will not be overwritten. + */ +rule "HttpActivity as a potential result of a preceding DNS activity" +when + $http : HttpActivity($hostHeader : request.requestHeaderMap[HttpHeaders.HOST], dnsMatch==null) + $dnsResponse : DnsActivity(isResponse(), this before[0s,20s] $http) + + /** + * The first two checks are IP based, i.e: was the ip address from the DNS A/AAAA record called and does it match the HTTP server IP? + * The last check is domain based, i.e. the "Host:"-Header field from the HttpRequest is compared against the DNS name reply. + */ + exists( ARecord( $address : getAddress(), $address!.getHostAddress() == $http.request.serverAddress.getAddress().getHostAddress()) + from $dnsResponse.getAnswerRecords() + or AAAARecord( $address : getAddress(), $address!.getHostAddress() == $http.request.serverAddress.getAddress().getHostAddress()) + from $dnsResponse.getAnswerRecords() + or Record( $address : name, $address!.toString().startsWith($hostHeader)) + from $dnsResponse.getAnswerRecords() + ) +then + // At this point there was a preceding DNS response and a matching subsequent HTTP Request and Response + modify($http) { + setDnsMatch($dnsResponse); + }; +end \ No newline at end of file diff --git a/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/03.Basic.Tls.drl b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/03.Basic.Tls.drl new file mode 100644 index 0000000..d044bd6 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/03.Basic.Tls.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.tcp.*; +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress +import java.util.List; +import java.util.Set +import java.util.HashSet; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +/** + * This experimental rule looks for sequences of three related TCP-activities, i.e.: + * First, it tries to find a "ClientHello" Packet (according to the TLS handshake) followed by a "ServerHello". + * Finally an additional "ChangeCipher" message is expected before classifying this sequence as a TLS/SSL stream, see + * RFC 5246 (https://tools.ietf.org/html/rfc5246). + * The remaining packets will be assembled by the "TLS traffic"-rules (see below) + */ +rule "TLS Handshake" +when + $clientHello : TcpActivity( $payload : payloadHexFormattedDump(), $payload!=null, + TlsActivityHelper.isClientHello(tcp)) + $serverHello : TcpActivity( sourceSocketAddress==$clientHello.destinationSocketAddress, + destinationSocketAddress==$clientHello.sourceSocketAddress, + TlsActivityHelper.isServerHello(tcp), + this after[0s,10s] $clientHello) + $changeCipher : TcpActivity(sourceSocketAddress==$clientHello.destinationSocketAddress, + destinationSocketAddress==$clientHello.sourceSocketAddress, + TlsActivityHelper.isChangeCipherSpec(tcp), + this after[0s,10s] $serverHello) + + exists TcpActivity( sourceSocketAddress==$clientHello.destinationSocketAddress, + destinationSocketAddress==$clientHello.sourceSocketAddress, + TlsActivityHelper.isChangeCipherSpec(tcp), + this after[0s,10s] $changeCipher) + not (exists TlsActivity(clientHello==$clientHello || serverHello==$serverHello || changeCipherSpec==$changeCipher)) +then + TlsActivity tls = new TlsActivity($clientHello,$serverHello); + tls.setChangeCipherSpec($changeCipher); + insert(tls); +end + +/** + * Collects TCP activities for a given TlsActivity (client to server only) based on source/destionation ip/port + */ +rule "TLS traffic (client -> server)" +when + $tls : TlsActivity($clientHello : clientHello) + $tcp : TcpActivity( sourceSocketAddress==$clientHello.sourceSocketAddress, + destinationSocketAddress==$clientHello.destinationSocketAddress) +then + $tls.addClientToServerTcpActivity($tcp); +end + +/** + * Collects TCP activities for a given TlsActivity (server to client only) based on source/destionation ip/port + */ +rule "TLS traffic (server -> client)" +when + $tls : TlsActivity($serverHello : serverHello) + $tcp : TcpActivity( sourceSocketAddress==$serverHello.sourceSocketAddress, + destinationSocketAddress==$serverHello.destinationSocketAddress) +then + $tls.addServerToClientTcpActivity($tcp); +end \ No newline at end of file diff --git a/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/04.Derived.Https.drl b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/04.Derived.Https.drl new file mode 100644 index 0000000..78fe688 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/04.Derived.Https.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import org.xbill.DNS.*; +import org.apache.http.HttpHeaders; +import org.jnetpcap.protocol.tcpip.Tcp; +import org.jnetpcap.packet.PcapPacket; +import org.apache.commons.codec.binary.Hex; +import java.net.InetSocketAddress; +import java.util.HashSet; +import java.util.Date +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress +import java.util.List; +import java.util.Set; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +// this forward declaration is required to demonstrate the in-place definition of a custom event class, +// see HttpsActivity below +declare DroolsBaseActivity +end + +/** + * This declaration demonstrates an in-place declaration of a custom event class. + * A HttpsActivity currently consists of a client/server socket address and TLS-Activity, however, + * it includes all relevant frame numbers for further analysis because it replaces the TLS-activity. + */ +declare HttpsActivity extends DroolsBaseActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + + client : InetSocketAddress + server : InetSocketAddress + tlsActivity : TlsActivity +end + +rule "HTTPS" when + $tls : TlsActivity( clientHello.destinationPort == 443, !replaced) + not (exists HttpsActivity($tls == tlsActivity)) +then + HttpsActivity httpsActivity = new HttpsActivity(); + httpsActivity.setClient($tls.getClientHello().getSourceSocketAddress()); + httpsActivity.setServer($tls.getClientHello().getDestinationSocketAddress()); + httpsActivity.setTlsActivity($tls); + httpsActivity.replaceActivity($tls); + insert(httpsActivity); +end diff --git a/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/05.Basic.Icmp.drl b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/05.Basic.Icmp.drl new file mode 100644 index 0000000..08cdf88 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/05.Basic.Icmp.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import org.xbill.DNS.*; +import org.jnetpcap.protocol.network.Icmp.IcmpCode; +import org.jnetpcap.protocol.network.Icmp.IcmpType; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +/** + * Groups ICMP echo requests and echo replies to a PingActivity + */ +rule "Ping (Icmpv4)" +when + $req : Icmpv4Activity( $id : identifier, $seq : sequence, icmpType == IcmpType.ECHO_REQUEST) + $rep : Icmpv4Activity( identifier == $id, sequence == $seq, icmpType == IcmpType.ECHO_REPLY) + + not (exists PingActivity(request == $req || reply == $rep)) +then + insert(new PingActivity($req, $rep)); +end \ No newline at end of file diff --git a/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/06.Application.OpenSSH.drl b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/06.Application.OpenSSH.drl new file mode 100644 index 0000000..afc353d --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/06.Application.OpenSSH.drl @@ -0,0 +1,112 @@ +/** + * 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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import at.jku.fim.rubanetra.protocol.activity.tcp.*; +import java.util.HashSet; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +/** + * forward declaration, used for declaring the OpenSSHActivity + */ +declare DroolsBaseActivity +end + +/** + * Represents OpenSSH traffic between a client and a server. + */ +declare OpenSSHActivity extends DroolsBaseActivity + @role( event ) + @timestamp( getStartTimestamp() ) + + handshakeQuery : TcpActivity + handshakeReply : TcpActivity + + clientToServerTraffic : HashSet + serverToClientTraffic : HashSet +end + +/** + * Tries to identfiy an OpenSSH handshake by relying on the presence of the 'SSH-' substring of the + * payload to identify the handshake. + */ +rule "OpenSSH Handshake" +when + $handshakeQuery : TcpActivity( payloadString!.startsWith("SSH-"), + payloadString!.contains("OpenSSH")) + $handshakeReply : TcpActivity( pcapActivity != $handshakeQuery.getPcapActivity(), + payloadString!.startsWith("SSH-"), + payloadString!.contains("OpenSSH"), + sourcePort==$handshakeQuery.destinationPort, + destinationPort==$handshakeQuery.sourcePort, + this after[0s,10s] $handshakeQuery) + + // there should not exist another reply before the matched reply + not(exists TcpActivity( pcapActivity != $handshakeQuery.getPcapActivity(), + payloadString!.startsWith("SSH-"), + sourcePort==$handshakeQuery.destinationPort, destinationPort==$handshakeQuery.sourcePort, + this before $handshakeReply, this after $handshakeQuery)) +then + OpenSSHActivity sshAct = new OpenSSHActivity(); + sshAct.setHandshakeQuery($handshakeQuery); + sshAct.setHandshakeReply($handshakeReply); + sshAct.setClientToServerTraffic(new HashSet()); + sshAct.setServerToClientTraffic(new HashSet()); + sshAct.replaceActivity($handshakeQuery); + sshAct.replaceActivity($handshakeReply); + insert(sshAct); +end + +/** + * Collects client to server traffic (TCP activities) + */ +rule "OpenSSH traffic (client -> server)" +when + $sshAct : OpenSSHActivity() + $tcp : TcpActivity( pcapActivity.frameNumber not memberOf $sshAct.compoundFrameNumbers, + sourceSocketAddress==$sshAct.handshakeQuery.sourceSocketAddress, + destinationSocketAddress==$sshAct.handshakeQuery.destinationSocketAddress) +then + $sshAct.getClientToServerTraffic().addAll($tcp.getCompoundFrameNumbers()); + $sshAct.replaceActivity($tcp); +end + +/** + * Collects server to client traffic (TCP activities) + */ +rule "OpenSSH traffic (server -> client)" +when + $sshAct : OpenSSHActivity() + $tcp : TcpActivity( pcapActivity.frameNumber not memberOf $sshAct.compoundFrameNumbers, + sourceSocketAddress==$sshAct.handshakeReply.sourceSocketAddress, + destinationSocketAddress==$sshAct.handshakeReply.destinationSocketAddress) +then + $sshAct.getServerToClientTraffic().addAll($tcp.getCompoundFrameNumbers()); + $sshAct.replaceActivity($tcp); +end diff --git a/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/07.Application.Dropbox.drl b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/07.Application.Dropbox.drl new file mode 100644 index 0000000..b74d597 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/07.Application.Dropbox.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Set; +import java.util.HashSet; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +// forward declaration +declare DroolsBaseActivity +end + +/** + * A DropboxTlsActivity contains a DNS query/reply, client/server address/port and the associated Tls-Activity + */ +declare DropboxTlsActivity extends DroolsBaseActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + + dnsQuestion : DnsActivity + dnsAnswer : DnsActivity + + clientAddress : InetSocketAddress + serverAddress : InetSocketAddress + + associatedTlsActivity : TlsActivity +end + +/** + * Due to the generally encrypted dropbox traffic a DnsActivity containing the rule looks for query to "*.dropbox.com" + * first and gathers the relevant Ip-Addresses for which possible TlsActivitiy-objects will be probed against. + */ +rule "Dropbox TLS traffic based on previous DnsActivity" +when + $dnsQuery : DnsActivity(!isResponse(), !questionRecords.isEmpty(), + $queryId : dnsMessageHeader.ID,$question : dnsMessage.question.name, + $question.toString() matches ".*\\.dropbox.com\\.$") + $dnsReply : DnsActivity(isResponse(),!answerRecords.isEmpty(), + dnsMessageHeader.ID == $queryId, + this after[0s,10s] $dnsQuery) + $tls : TlsActivity(this after[0s,10s] $dnsReply) + + exists ( ARecord( $address : getAddress(), + $address!.getHostAddress() == $tls.getServerHello().getSourceAddress().getHostAddress()) + from $dnsReply.getAnswerRecords() + or AAAARecord( $address : getAddress(), + $address!.getHostAddress() == $tls.getServerHello().getSourceAddress().getHostAddress()) + from $dnsReply.getAnswerRecords() + ) + not ( exists DropboxTlsActivity($tls == associatedTlsActivity)) +then + DropboxTlsActivity act = new DropboxTlsActivity(); + act.setClientAddress($tls.getClientHello().getSourceSocketAddress()); + act.setServerAddress($tls.getServerHello().getSourceSocketAddress()); + act.setDnsQuestion($dnsQuery); + act.setDnsAnswer($dnsReply); + act.setAssociatedTlsActivity($tls); + act.replaceActivity($dnsQuery); act.replaceActivity($dnsReply); act.replaceActivity($tls); + + insert(act); +end \ No newline at end of file diff --git a/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/08.Application.SpiderOak.drl b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/08.Application.SpiderOak.drl new file mode 100644 index 0000000..f387589 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/08.Application.SpiderOak.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Set; +import java.util.HashSet; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +// forward declaration +declare DroolsBaseActivity +end + +/** + * This declaration defines an SpiderOak related Activity, consisting of DNS query/reply, client/server address/port + * and the associated TlsActivity + */ +declare SpiderOakActivity extends DroolsBaseActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + + dnsAnswer : DnsActivity + + clientAddress : InetSocketAddress + serverAddress : InetSocketAddress + + associatedTlsActivity : TlsActivity +end + +/** + * This rule is quite similar to the Dropbox tls traffic matching rule. + * It looks for a DNS query to "*.spideroak.com" and gathers the relevant IP addresses for probing existing, yet unmatched + * TlsActivities. + */ +rule "Spideroak TLS traffic based on DnsActivity" +when + $dnsReply : DnsActivity(isResponse(), !answerRecords.isEmpty(), + $question : dnsMessage.question.name, + $question.toString() matches ".*\\.spideroak.com\\.$") + $tls : TlsActivity(this after[0s,10s] $dnsReply) + + exists( ARecord($address : getAddress(), + $address!.getHostAddress() == $tls.getServerHello().getSourceAddress().getHostAddress()) + from $dnsReply.getAnswerRecords() + or + AAAARecord( $address : getAddress(), + $address!.getHostAddress() == $tls.getServerHello().getSourceAddress().getHostAddress()) + from $dnsReply.getAnswerRecords() + ) +then + SpiderOakActivity spiderOakActivity = new SpiderOakActivity(); + spiderOakActivity.setDnsAnswer($dnsReply); + spiderOakActivity.setClientAddress($tls.getClientHello().getSourceSocketAddress()); + spiderOakActivity.setServerAddress($tls.getServerHello().getSourceSocketAddress()); + spiderOakActivity.setAssociatedTlsActivity($tls); + + spiderOakActivity.replaceActivity($dnsReply); + spiderOakActivity.replaceActivity($tls); + + insert(spiderOakActivity); +end diff --git a/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/09.Application.Skype.drl b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/09.Application.Skype.drl new file mode 100644 index 0000000..6936ed0 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/09.Application.Skype.drl @@ -0,0 +1,114 @@ +/** + * 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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import at.jku.fim.rubanetra.protocol.activity.tcp.*; +import at.jku.fim.rubanetra.protocol.activity.udp.*; +import at.jku.fim.rubanetra.protocol.activity.skype.*; +import at.jku.fim.rubanetra.protocol.activity.DroolsBaseActivity; +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress +import java.util.List; +import java.util.Set +import java.util.HashSet +import org.jnetpcap.protocol.tcpip.Udp; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +// forward declaration +declare DroolsBaseActivity end + +/** + * Represents a Skype payload of arbitrary type, consisting of an source/destination object id and hosts. + */ +declare SkypePayloadActivity extends DroolsBaseActivity + @role( event ) + @timestamp( getStartTimestamp() ) + + sourceObjectId : int + destinationObjectId : int + + sourceHost : InetSocketAddress + destinationHost : InetSocketAddress +end + +/** + * This rule is based on a crude heuristic which is again partially based on: https://github.com/matthiasbock/OpenSkype. + * Skype traffic usually consists of Udp-packets containing a certain kind of object id, therefore those special packets + * have to be matched first. + * This rule should be disabled/removed/improved if it causes false-positives (to reduce the negative impact, this + * rule does not replace any Activities, but extends them instead). + * Possible enhancements include: + * - Use Dns-matches to obtain the skype hosts, if possible (see Dropbox/Spideroak examples) + * - Extend the SkypePayloadActivity according to the known metadata (see https://github.com/matthiasbock/OpenSkype) + */ +rule "Skype Payload (one way, two matches)" +no-loop + when + $udp : UdpActivity( $objectId : SkypeActivityHelper.objectId(udp), SkypeActivityHelper.hasSkypePayload(udp)) + $udpResp : UdpActivity( $objectIdResp : SkypeActivityHelper.objectId(udp), + SkypeActivityHelper.hasSkypePayload(udp), + sourceSocketAddress==$udp.destinationSocketAddress, + destinationSocketAddress==$udp.sourceSocketAddress, + this after[0s,10s] $udp) + exists( UdpActivity($oid : SkypeActivityHelper.objectId(udp), + ($objectId + 10) > $oid, + $oid > $objectId, + SkypeActivityHelper.hasSkypePayload(udp), + sourceSocketAddress==$udp.sourceSocketAddress, + destinationSocketAddress==$udp.destinationSocketAddress, + this after[0s,10s] $udp) ) + exists( UdpActivity($oid : SkypeActivityHelper.objectId(udp), + ($objectIdResp + 10) > $oid, + $oid > $objectIdResp, + SkypeActivityHelper.hasSkypePayload(udp), + sourceSocketAddress==$udpResp.sourceSocketAddress, + destinationSocketAddress==$udpResp.destinationSocketAddress, + this after[0s,10s] $udpResp) ) + + not ( exists UdpActivity( SkypeActivityHelper.objectId(udp)<$objectId, + SkypeActivityHelper.hasSkypePayload(udp), + sourceSocketAddress==$udp.sourceSocketAddress, + destinationSocketAddress==$udp.destinationSocketAddress, + this after[10s] $udp)) + not ( exists UdpActivity( SkypeActivityHelper.objectId(udp)<$objectIdResp, + SkypeActivityHelper.hasSkypePayload(udp), + sourceSocketAddress==$udpResp.sourceSocketAddress, + destinationSocketAddress==$udpResp.destinationSocketAddress, + this after[10s] $udpResp)) + not ( exists SkypePayloadActivity(sourceObjectId==$objectId || sourceObjectId==$objectIdResp + || destinationObjectId==$objectId || destinationObjectId==$objectIdResp)) + then + SkypePayloadActivity act = new SkypePayloadActivity(); + act.setSourceObjectId($objectId); act.setDestinationObjectId($objectIdResp); + act.setSourceHost($udp.getSourceSocketAddress()); act.setDestinationHost($udp.getDestinationSocketAddress()); + act.extendActivity($udp); act.extendActivity($udpResp); + insert(act); +end diff --git a/rubanetra-0.0.6-distribution/conf/META-INF/kmodule.xml b/rubanetra-0.0.6-distribution/conf/META-INF/kmodule.xml new file mode 100644 index 0000000..74cfc11 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/META-INF/kmodule.xml @@ -0,0 +1,33 @@ + + + + + + + + \ No newline at end of file diff --git a/rubanetra-0.0.6-distribution/conf/META-INF/maven/at.jku.fim/rubanetra/pom.properties b/rubanetra-0.0.6-distribution/conf/META-INF/maven/at.jku.fim/rubanetra/pom.properties new file mode 100644 index 0000000..a24825a --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/META-INF/maven/at.jku.fim/rubanetra/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Tue Jul 07 12:26:27 CEST 2015 +version=0.0.6 +groupId=at.jku.fim +artifactId=rubanetra diff --git a/rubanetra-0.0.6-distribution/conf/META-INF/maven/at.jku.fim/rubanetra/pom.xml b/rubanetra-0.0.6-distribution/conf/META-INF/maven/at.jku.fim/rubanetra/pom.xml new file mode 100644 index 0000000..3a1e9fa --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/META-INF/maven/at.jku.fim/rubanetra/pom.xml @@ -0,0 +1,748 @@ + + + 4.0.0 + at.jku.fim + rubanetra + 0.0.6 + Rubanetra + 2013 + + + + GNU General Public License, Version 3 + https://gnu.org/licenses/gpl-3.0.txt + repo + + + + + Institute of networks and security + https://ins.jku.at + + + + + stefan + Stefan Swerk + stefan_rubanetra@swerk.priv.at + + developer + + +1 + + + + + scm:git:http://gitlab.swerk.priv.at/stefan/rubanetra.git + http://gitlab.swerk.priv.at/stefan/rubanetra + + + Gitlab + http://gitlab.swerk.priv.at/stefan/rubanetra/issues + + + + + DefaultKnowledgeBase + DefaultSession + pcap + stdout + plaso + info + ./logs + ./lib + ./conf + /usr/lib + + + UTF-8 + UTF-8 + false + true + /home/stefan/IdeaProjects/rubanetra/target/archive + 2014 + + + 1.4.r1425-1d + libjnetpcap + 1.7.1 + 4.5 + 6.1.0.Final + 4.3.3 + 2.1.7 + 4.11 + 2.5.3 + 1.7.6 + + + + + + OpenSOC-Kraken-Repo + OpenSOC Kraken Repository + https://raw.github.com/opensoc/kraken/mvn-repo + + + + + + + + + + + krakenapps.org - workaround + + true + ignore + + + false + + file:///home/stefan/IdeaProjects/rubanetra/src/main/resources/kraken-workaround-repository + + + + + jboss-public-repository-group + JBoss Public Maven Repository Group + http://repository.jboss.org/nexus/content/groups/public/ + default + + true + always + + + true + always + + + + central + Central Maven Repository + default + http://repo1.maven.org/maven2 + + true + + + + clojars.org + Clojars Community Maven Repository + http://clojars.org/repo + + + + + jboss-public-repository-group + JBoss Public Maven Repository Group + http://repository.jboss.org/nexus/content/groups/public/ + default + + + central + Central Maven Repository + default + http://repo1.maven.org/maven2 + + true + + + + + + + junit + junit + 4.11 + test + + + org.slf4j + slf4j-api + 1.7.6 + + + org.slf4j + jcl-over-slf4j + 1.7.6 + + + ch.qos.logback + logback-classic + 1.1.1 + + + commons-logging + commons-logging + 1.1.3 + provided + + + com.fasterxml.jackson.core + jackson-databind + 2.5.3 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.5.3 + + + org.codehaus.woodstox + woodstox-core-asl + 4.3.0 + + + javax.mail + mail + 1.4.7 + + + activation + javax.activation + + + + + org.krakenapps + kraken-pcap + 1.7.1 + + + slf4j-simple + org.slf4j + + + + + org.krakenapps + kraken-http-decoder + 1.1.0 + + + mail + javax.mail + + + + + org.krakenapps + kraken-smtp-decoder + 1.1.0 + + + activation + javax.activation + + + mail + javax.mail + + + + + org.krakenapps + kraken-ftp-decoder + 1.2.0 + + + mail + javax.mail + + + + + org.krakenapps + kraken-msn-decoder + 1.2.0 + + + mail + javax.mail + + + + + org.krakenapps + kraken-netbios-decoder + 1.0.0 + + + org.krakenapps + kraken-pop3-decoder + 1.0.0 + + + mail + javax.mail + + + + + org.krakenapps + kraken-dhcp-decoder + 1.0.1 + + + org.krakenapps + kraken-snmp-decoder + 1.1.0 + + + mail + javax.mail + + + + + org.krakenapps + kraken-telnet-decoder + 1.0.0 + + + jnetpcap + jnetpcap + 1.4.r1425-1d + + + org.antlr + antlr4-runtime + 4.5 + + + org.drools + drools-core + 6.1.0.Final + + + org.drools + drools-compiler + 6.1.0.Final + + + org.kie + kie-api + 6.1.0.Final + + + org.apache.httpcomponents + httpclient + 4.3.3 + + + commons-cli + commons-cli + 1.2 + + + org.apache.commons + commons-csv + 1.0 + + + dnsjava + dnsjava + 2.1.7 + + + + + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.8 + 1.8 + true + true + -proc:none + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + false + /home/stefan/IdeaProjects/rubanetra/target/archive + -Xdoclint:none + + + + attach-javadocs + prepare-package + + jar + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.16 + + true + + /home/stefan/IdeaProjects/rubanetra/target/logs + DEBUG + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.4 + + + package + + single + + + + + + src/main/assembly/distribution-zip.xml + src/main/assembly/package-zip.xml + + gnu + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + /home/stefan/IdeaProjects/rubanetra/target/archive + + + true + + false + ./lib/ + false + at.jku.fim.rubanetra.config.ConfigurationController + true + + + ./conf/ /usr/lib/ + 1.8.0_45 + Linux + amd64 + GPLv3 + GNU General Public License, Version 3 + https://gnu.org/licenses/gpl-3.0.txt + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + + 2013 + 2014 + Stefan Swerk (stefan_rubanetra@swerk.priv.at) + http://gitlab.swerk.priv.at/stefan/rubanetra/issues + http://gitlab.swerk.priv.at/stefan/rubanetra + + + + **/*.properties + **/*.drl + **/*.xml + **/*.conf + kraken-workaround-repository/** + DefaultKnowledgeBase/** + + + + + prepare-package + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + true + /home/stefan/IdeaProjects/rubanetra/target/archive + + + + attach-sources + prepare-package + + jar-no-fork + + + + attach-test-sources + prepare-package + + test-jar-no-fork + + + + **/captures/** + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + generate-sources + + add-source + + + + /home/stefan/IdeaProjects/rubanetra/target/generated-sources/antlr4 + + + + + + + org.antlr + antlr4-maven-plugin + 4.5 + + + antlr + generate-sources + + antlr4 + + + + + + + + + + org.kie + kie-maven-plugin + 6.1.0.Final + true + + + org.apache.maven.plugins + maven-dependency-plugin + 2.8 + + + copy-dependencies + prepare-package + + copy-dependencies + + + /home/stefan/IdeaProjects/rubanetra/target/lib + false + false + true + true + + + + unpack + compile + + unpack + + + + + jnetpcap + jnetpcap + 1.4.r1425-1d + jar + false + /home/stefan/IdeaProjects/rubanetra/target/lib/libjnetpcap + + + + native/** + + + + + + org.codehaus.mojo + license-maven-plugin + 1.6 + + gpl_v3 + Stefan Swerk (stefan_rubanetra@swerk.priv.at) + true + true + + The Apache Software License, Version 2.0|Apache 2 + The Apache Software License, Version 2.0|Apache + License + + The Apache Software License, Version 2.0|Apache + License, Version 2.0 + + + + + + add-third-party + + add-third-party + + process-sources + + + + + + + + + + update-project-license + + update-project-license + + process-sources + + + + + org.apache.maven.plugins + maven-install-plugin + 2.5.1 + + true + + + + net.ju-n.maven.plugins + checksum-maven-plugin + 1.2 + + + + artifacts + + + + + + MD5 + SHA-1 + SHA-256 + + + + + com.mycila + license-maven-plugin + 2.6 + +
src/license/gpl_v3/header.txt
+ + Stefan Swerk + 2013 + 2014 + ${maven.build.timestamp} + stefan_rubanetra@swerk.priv.at + + true + + JAVADOC_STYLE + JAVADOC_STYLE + JAVADOC_STYLE + +
+ + + license-basedir + process-sources + + format + + + /home/stefan/IdeaProjects/rubanetra + + **/README* + **/LICENSE* + src/license/gpl_v3/** + src/main/resources/kraken-workaround-repository/** + src/test/resources/captures/** + + + pom.xml + src/** + + + + + license-gen-src + process-sources + + format + + + /home/stefan/IdeaProjects/rubanetra/target/generated-sources/antlr4 + + **/README* + **/LICENSE* + **/*.tokens + + + + +
+
+
+
diff --git a/rubanetra-0.0.6-distribution/conf/logback.xml b/rubanetra-0.0.6-distribution/conf/logback.xml new file mode 100644 index 0000000..c8cc333 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/logback.xml @@ -0,0 +1,54 @@ + + + + + System.err + + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5p - %m%n + + + info + + + + + true + ./logs/rubanetra.log + + %date %level [%thread] [%file:%line] - %msg%n + + + info + + + 5 + ./logs/rubanetra.log.%i + + + 10MB + + + + + + + + diff --git a/rubanetra-0.0.6-distribution/conf/rubanetra.conf b/rubanetra-0.0.6-distribution/conf/rubanetra.conf new file mode 100644 index 0000000..76c9f89 --- /dev/null +++ b/rubanetra-0.0.6-distribution/conf/rubanetra.conf @@ -0,0 +1,471 @@ +/** + * 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 . + */ +/** + * This file serves as the Rubanetra configuration entry point and will be looked up by the main executable jar. + * Therefore this file must be either directly available via classpath entry, or the file-path has to be passed via + * command line argument (for further details refer to the README file). + * + * While this file must contain all configuration sections, i.e. 'general', 'protocols', 'input' and 'output' + * at once, one may prefer to split certain dynamically changing configuration sections into separate and therefore + * replaceable files. However, please note that the general section must reside in a statically known location to the + * Rubanetra executable and the paths to the dynamically changed files must be defined in the appropriate sections. + * + * Since all configuration files will be parsed by ANTLRv4, the corresponding grammar defining the exact syntax + * is available in the source archive, see 'src/main/antlr4/.../RubanetraSystemConfiguration.g4'. + */ + +/** + * ######################### + * # General Configuration # + * ######################### + */ +general { + /** + * Defines the base directory containing the Drools knowledge-base configuration. + * Currently this directory must contain: + * - 'META-INF' as subdirectory, containing: + * ~ 'kmodule.xml', the Drools configuration file, i.e. 'META-INF/kmodule.xml' + * ~ the subsequent Apache Maven configuration structure, i.e.: + * + 'maven/at.jku.fim/rubanetra/' sub-directories + * + 'maven/at.jku.fim/rubanetra/pom.xml' the project's Maven configuration file + * + 'maven/at.jku.fim/rubanetra/pom.properties' Maven-generated properties + * + * If this setting is changed, the default 'META-INF' directory should be removed either from the classpath + * or directly from the configuration directory (since this directory is by default in the classpath). + * + * Default value "./conf", this setting is mandatory. + */ + drools_configuration_directory = "./conf"; + + /** + * Defines the name of the Drools knowledge base to use for the reasoning process. + * This knowledge base name must be listed in the Drools knowledge base descriptor file 'kmodule.xml'. + * If this setting is not specified the default knowledge base as specified in the Drools descriptor file will + * be compiled and used. + * + * Default value "DefaultKnowledgeBase", this setting is optional. + */ + drools_base_model_name = "DefaultKnowledgeBase"; + + /** + * Defines the name of the Drools session to use for the reasoning process. + * This session name must be listed in the Drools knowledge base descriptor file 'kmodule.xml' as session entry + * under the specified (or the default) 'drools_base_model_name'. + * If this setting is not specified the default session name as specified in the Drools descriptor file will be + * used instead. + * + * Default value "DefaultSession", this setting is optional. + */ + drools_session_model_name = "DefaultSession"; +}; + +/** + * ########################## + * # Protocol Configuration # + * # (Application Layer) # + * ########################## + * + * This section should be filled with application layer specific protocol settings, i.e. underlying lower layer + * protocol parser bindings and potential port filters, if applicable. The listed application layer parser settings + * also serve as a vital tool of directing the output generation engine. By default, any parser output below the + * application layer will be suppressed due to verboseness, however, this behaviour may be overturned by appropriate + * rule definitions inside the used Knowledge Base. For further information on how to achieve this, please refer to + * the documentation of Activity#setExcludedFromOutput(boolean). + * Additional Notes: An application layer parser will only produce output if all of the following conditions are met: + * - A protocol decoder pipeline has been setup, including all lower layer protocols, + * e.g.: L2 -> L3 -> L4 -> + * - The destination port restriction may not be 'None' and has to include the relevant port(s). + * - The PCAP file actually contains relevant packets applicable to and defined port(s). + * + * Furthermore, it is recommended to specify one protocol identifier per application layer protocol parser, however, + * remember that there must be a 1:1 mapping between a transport layer parser and an application layer parser, therefore + * the following example will not work: + * [HTTPandDNSoverTCP]: + * port = ALL; + * protocol_binding = Ethernet -> Ipv4; + * protocol_binding = Ipv4 -> Tcp; + * protocol_binding = Tcp -> Http; + * protocol_binding = Tcp -> Dns; + * + * In general, the following implementation constraints may be observed: + * - 1:n mapping between Layer1 (Pcap) and Layer2 (link) parsers + * - n:m mapping between Layer2 (link) and Layer3 (IP), Layer3 and Layer4 (transport) parsers + * - 1:1 mapping between Layer4 (transport) and application layer parsers + * + * On the other hand, if extremely fine grained control over the actual PCAP data is required, see the BPF setting + * in the 'input' configuration section. + * + * If the Drools knowledge base contains rules that require certain protocol parsers, those parsers must be referenced + * at least one time in this configuration section. However, rule based parsers must be configured entirely in the + * Drools rule files. + */ +protocols { + /** + * If a 'protocol_configuration_file' setting is specified all remaining protocol specific settings will be looked + * up in the referenced file. This file must exist and be readable for the invoking process. + * Note, however, that there will be no explicit checks against configuration file dereferencing chains, i.e. + * it should be ensured that there is no 'protocol_configuration_file' setting in the referenced file again. + * The referenced file must contain a "protocols {};" section containing the entire protocol specific configuration. + * + * This setting is optional, but if it is specified all remaining protocol specific settings in the + * main configuration file will be ignored. + */ + //protocol_configuration_file = "/path/to/protocol.conf"; + + /** + * An unique protocol id should be defined for each application layer protocol parser that should be used, i.e. + * by default the name of an application layer protocol should suffice. + * Syntax: '[ Protocol_ID ]:', where Protocol_ID represents an unique protocol identifier conforming + * to ([a-zA-Z]+ DIGIT*)+. + * A number of protocol specific settings may be specified subsequently. + * This setting may be repeated multiple times for configuring different protocol parsers. + * + * Constraints: It is currently not defined what will happen in the case of multiple different protocol ids that + * contain exactly the same protocol bindings. Consider for instance: + * [HTTP]: ... as below ... + * [HTTP1]: ... as [HTTP] ... + * + * The rule engine will probably receive double notifications for all HTTP related events in this case and this + * could lead to severe issues during the reasoning process and the corresponding output (two identical frame numbers + * for two different parser instances). + */ + [HTTP]: + /** + * The strategy to use for mapping Kraken's transport layer parsers to the application layer parsers. + * Currently only the destination port strategy has been implemented, i.e. an application layer parser receives + * packets that match the specified destination port number(s) defined by the "port" setting. + * + * Default value "destination_port", this setting is required. + */ + transport_layer_mapping_strategy = destination_port; + + /** + * Restricts the transport layer parser (UDP/TCP) to the specified destination ports and/or port-ranges. + * A similar result could be achieved globally (and more efficiently) via the input BPF filter setting. + * + * Default value "80", this setting is required if the mapping strategy used is "destination_port". + * Exemplary values: + * - ALL or ANY, i.e. do not apply any port based restriction to the parser (matches all ports) + * - NONE, i.e. disable this protocol since no ports will be allowed (matches no ports) + * - 80, i.e. match only packets with destination port 80, any valid port numbers are allowed + * - 80,8080,8081 matches packets with destination port 80 or 8080 or 8081 + * - 80,8080-8088 matches packets with destination port 80 or the destination port range 8080-8088 + * Warning: A setting of ALL should be used with care, as it may cause a library decoder to crash and + * prevent the continued parsing process of valid HTTP data. + */ + port = 80; + + /** + * The "protocol_binding" setting binds an available protocol parser to another protocol parser that is capable + * of decoding the previously "unwrapped/decoded" content. Usually this setting should be used to define + * the network layer decoding pipeline. The lowest network layer parser available is currently a + * layer 2 parser, e.g. ethernet. Layer 1 (basically PCAP-entries) may be implicitly assumed to be always + * provided in decoded form. + * A network layer protocol parser is always identified by the unique protocol identifier that this parser is + * advertising as capable of decoding. Unless custom protocol parsers have been registered, the following parsers + * should be available: + * Ethernet, Arp, + * Ipv4, Ipv6, Icmpv4, Icmpv6, + * Tcp, Udp, + * Telnet, Snmp, Netbios, Dhcp, Pop3, Msn, Ftp, Dns, Smtp, Http + * + * This setting is not required, however, if no bindings are specified no parsers will be setup. + * This setting must be specified multiple times in case of different bindings for the same higher layer protocol + * parser, i.e. the entire network layer stack below the highest defined protocol parser layer must be bound. + * For instance, if the highest network layer protocol specified is TCP (layer 4), a layer 2 parser + * must be bound to layer 3 and a layer 3 parser must be bound to tcp. If the parsers are incompatible or the + * pipeline is not complete, the parser of the highest layer will not receive any decoded data. + * Multiple lower layer parsers leading to a common higher layer parser are nevertheless allowed, e.g. + * ethernet -> ipv4, ethernet -> ipv6, + * ipv4 -> tcp, ipv6 -> tcp, + * tcp -> http + * + * In general, the following implementation constraints may be observed: + * - 1:n mapping between Layer1 (Pcap) and Layer2 (link) parsers + * - n:m mapping between Layer2 (link) and Layer3 (IP), Layer3 and Layer4 (transport) parsers + * - 1:1 mapping between Layer4 (transport) and application layer parsers + * + * Note: Not all theoretically possible bindings are implemented, e.g. a binding from ethernet -> http will + * cause a runtime exception because the Http-parser handles decoded TCP/IP-data only. + * It is also discouraged to bind a higher layer parser to a lower layer, e.g. http -> tcp, since this will + * depend solely on the individual parser implementation on how this case is handled and should therefore + * be avoided. + */ + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Http; + + /** + * Example of a possible DNS protocol parser pipeline setup. Note that larger DNS messages are sent via + * the TCP transport layer instead of UDP. This pipeline is capable of handling Ethernet, IPv4/IPv6, UDP/TCP and + * the DNS parsers. however, the TCP -> DNS parser is currently considered experimental. + */ + [DNS]: + transport_layer_mapping_strategy = destination_port; + port = Any; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv4 -> Udp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Ipv6 -> Udp; + protocol_binding = Tcp -> Dns; + protocol_binding = Udp -> Dns; + + /** + * Exemplary SNMP v1/v2 Pipeline configuration. + * (default: disabled) + */ + [SNMPv1v2]: + transport_layer_mapping_strategy = destination_port; + port = None; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Udp; + protocol_binding = Ipv6 -> Udp; + protocol_binding = Udp -> Snmp; + + /** + * Exemplary DHCP Pipeline configuration. + * (default: enabled for port 67,68) + */ + [DHCP]: + transport_layer_mapping_strategy = destination_port; + port = 67,68; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Udp; + protocol_binding = Ipv6 -> Udp; + protocol_binding = Udp -> Dhcp; + + /** + * Exemplary Netbios Pipeline configuration. + * (default: disabled) + */ + [Netbios]: + transport_layer_mapping_strategy = destination_port; + port = None; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Udp; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Udp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Udp -> Netbios; + protocol_binding = Tcp -> Netbios; + + /** + * Exemplary Msn Pipeline configuration. + * (default: disabled) + */ + [MSN]: + transport_layer_mapping_strategy = destination_port; + port = None; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Msn; + + /** + * Exemplary Ftp Pipeline configuration. + * (default: disabled) + */ + [FTP]: + transport_layer_mapping_strategy = destination_port; + port = None; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Ftp; + + /** + * Exemplary Pop3 Pipeline configuration. + * (default: enabled for ports 110, 995) + */ + [Pop3]: + transport_layer_mapping_strategy = destination_port; + port = 110, 995; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Pop3; + + /** + * Exemplary Telnet Pipeline configuration. + * (default: enabled for port 23) + */ + [Telnet]: + transport_layer_mapping_strategy = destination_port; + port = 23; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Telnet; + + /** + * Exemplary Smtp Pipeline configuration. + * (default: enabled for ports 25, 587, 465) + */ + [SMTP]: + transport_layer_mapping_strategy = destination_port; + port = 25, 587, 465; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Smtp; + + /** + * Exemplary ICMPv4/v6 Pipeline configuration. + * (default: enabled, a port based restriction is not possible) + */ + [ICMP]: + transport_layer_mapping_strategy = destination_port; + port = None; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Icmpv4; + protocol_binding = Ipv6 -> Icmpv6; +}; + +/** + * ####################### + * # Input Configuration # + * ####################### + */ +input { + /** + * If a 'input_configuration_file' setting is specified, all remaining input specific settings will be looked + * up in the referenced file. This file must exist and be readable for the invoking process. + * Note, however, that there will be no explicit checks against configuration file dereferencing chains, i.e. + * it should be ensured that there is no 'input_configuration_file' setting in the referenced file again. + * The referenced file must contain a "input {};" section containing the entire input specific configuration. + * + * This setting is optional, but if it is specified all remaining input specific settings in the + * main configuration file will be ignored. + */ + //input_configuration_file = "path/to/input.conf"; + + /** + * The path to the input files to parse. All specified files must adhere to the format specified by + * the "input_format" setting. + * + * This setting is required, syntax (curly braces indicate arbitrary repetitions and must not be included): + * input_file = "/path/to/file1" {, "/path/to/another/file"}; + * This setting may be specified multiple times, all occurrences will be processed. + * + * Notes: Input files that were specified by using the command line interface will not replace the input_file + * specifications of this section, i.e. all sources will be combined and processed. + */ + //input_file = "path/to/input/file"; + + /** + * The format of the specified input files. + * Currently only a pcap parser has been implemented. + * + * This setting is required. + */ + input_format = pcap; + + /** + * A Berkeley Packet Filter string to facilitate an efficient way to filter the entire PCAP-Stream before it is + * passed to the parsers. This string will be compiled and applied by the native PCAP-decoding library by the means + * of JNetPcap. + * + * This setting is optional. + * Syntax definition: . + */ + bpf_filter = ""; + + /** + * The Berkeley Packet Filter optimization flag. + * This boolean value will be passed along the bpf_netmask and the bpf_filter string to the native PCAP decoding + * library and indicates whether or not the bpf_filter string should be optimized by the compiler. + * + * This setting is optional, default value = false. + */ + bpf_optimize = false; + + /** + * If this setting is set to true, all specified input files will be opened and the first content entry will be + * parsed respectively, i.e. the timestamp of the first entry in each file will be analyzed and compared. + * The File-Handler will then try to sort all files chronologically according to this timestamp, so that + * the "real" parsing process provides all packet capture entries in the original order (the oldest entry will + * be parsed first). + * Because this process relies only on the first timestamp of each file, it cannot handle overlapping + * time-intervals. + * + * This setting is optional, default value: false + * Possible values: + * - false, i.e. parse in the order the files were specified in the configuration itself. + * - true, try to sort all files chronologically according to the timestamp of their first network capture entry. + */ + sort_by_first_timestamp = false; +}; + +/** + * ######################## + * # Output Configuration # + * ######################## + */ +output { + /** + * If a 'output_configuration_file' setting is specified, all remaining output specific settings will be looked + * up in the referenced file. This file must exist and be readable for the invoking process. + * Note, however, that there will be no explicit checks against configuration file dereferencing chains, i.e. + * it should be ensured that there is no 'output_configuration_file' setting in the referenced file again. + * The referenced file must contain a "output {};" section containing the entire output specific configuration. + * + * This setting is optional, but if it is specified all remaining output specific settings in the + * main configuration file will be ignored. + */ + //output_configuration_file = "path/to/output.conf"; + + /** + * The file descriptor to use for writing the derived information to. The information will be transformed + * according to the specified output_format before it is written to the output-stream. + * + * This setting is required, default value: stdout. + * The file or stream must be writable by the invoking process. + * Possible values: + * - STDOUT, the standard output stream + * - "path/to/a/file", a file-path + */ + output_file = stdout; + + /** + * The output format that is used to transform the derived information to before writing it to "output_file". + * + * This setting is required, default value: plaso + * Possible values: + * - plaso, a format that can be parsed by the provided Plaso specific parser (currently XML) + * - xml, however, without a schema definition + * - json + * - csv, generic/limited comma separated value content will be produced + * If extended output for certain activities is desired, a custom CSV schema has to be provided first. + * - nop, does not write anything to "output_file". + * - callback, as 'nop', mainly interesting for developers/testing. + */ + output_format = plaso; +}; \ No newline at end of file diff --git a/rubanetra-0.0.6-distribution/lib/antlr-runtime-3.5.jar b/rubanetra-0.0.6-distribution/lib/antlr-runtime-3.5.jar new file mode 100644 index 0000000..a8b5969 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/antlr-runtime-3.5.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/antlr4-runtime-4.5.jar b/rubanetra-0.0.6-distribution/lib/antlr4-runtime-4.5.jar new file mode 100644 index 0000000..924fcce Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/antlr4-runtime-4.5.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/commons-cli-1.2.jar b/rubanetra-0.0.6-distribution/lib/commons-cli-1.2.jar new file mode 100644 index 0000000..ce4b9ff Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/commons-cli-1.2.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/commons-codec-1.6.jar b/rubanetra-0.0.6-distribution/lib/commons-codec-1.6.jar new file mode 100644 index 0000000..ee1bc49 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/commons-codec-1.6.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/commons-csv-1.0.jar b/rubanetra-0.0.6-distribution/lib/commons-csv-1.0.jar new file mode 100644 index 0000000..5f58e40 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/commons-csv-1.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/commons-logging-1.1.3.jar b/rubanetra-0.0.6-distribution/lib/commons-logging-1.1.3.jar new file mode 100644 index 0000000..ab51254 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/commons-logging-1.1.3.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/dnsjava-2.1.7.jar b/rubanetra-0.0.6-distribution/lib/dnsjava-2.1.7.jar new file mode 100644 index 0000000..111fef9 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/dnsjava-2.1.7.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/drools-compiler-6.1.0.Final.jar b/rubanetra-0.0.6-distribution/lib/drools-compiler-6.1.0.Final.jar new file mode 100644 index 0000000..ab1b2b7 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/drools-compiler-6.1.0.Final.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/drools-core-6.1.0.Final.jar b/rubanetra-0.0.6-distribution/lib/drools-core-6.1.0.Final.jar new file mode 100644 index 0000000..d2af06d Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/drools-core-6.1.0.Final.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/ecj-4.3.1.jar b/rubanetra-0.0.6-distribution/lib/ecj-4.3.1.jar new file mode 100644 index 0000000..dc07007 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/ecj-4.3.1.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/hamcrest-core-1.3.jar b/rubanetra-0.0.6-distribution/lib/hamcrest-core-1.3.jar new file mode 100644 index 0000000..9d5fe16 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/hamcrest-core-1.3.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/httpclient-4.3.3.jar b/rubanetra-0.0.6-distribution/lib/httpclient-4.3.3.jar new file mode 100644 index 0000000..6c46bff Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/httpclient-4.3.3.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/httpcore-4.3.2.jar b/rubanetra-0.0.6-distribution/lib/httpcore-4.3.2.jar new file mode 100644 index 0000000..813ec23 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/httpcore-4.3.2.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/jackson-annotations-2.5.0.jar b/rubanetra-0.0.6-distribution/lib/jackson-annotations-2.5.0.jar new file mode 100644 index 0000000..6252131 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/jackson-annotations-2.5.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/jackson-core-2.5.3.jar b/rubanetra-0.0.6-distribution/lib/jackson-core-2.5.3.jar new file mode 100644 index 0000000..f3ae1ae Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/jackson-core-2.5.3.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/jackson-databind-2.5.3.jar b/rubanetra-0.0.6-distribution/lib/jackson-databind-2.5.3.jar new file mode 100644 index 0000000..e217187 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/jackson-databind-2.5.3.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/jackson-dataformat-xml-2.5.3.jar b/rubanetra-0.0.6-distribution/lib/jackson-dataformat-xml-2.5.3.jar new file mode 100644 index 0000000..1b629f1 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/jackson-dataformat-xml-2.5.3.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/jackson-module-jaxb-annotations-2.5.3.jar b/rubanetra-0.0.6-distribution/lib/jackson-module-jaxb-annotations-2.5.3.jar new file mode 100644 index 0000000..587b0bd Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/jackson-module-jaxb-annotations-2.5.3.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/jcl-over-slf4j-1.7.6.jar b/rubanetra-0.0.6-distribution/lib/jcl-over-slf4j-1.7.6.jar new file mode 100644 index 0000000..1a1ceee Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/jcl-over-slf4j-1.7.6.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/jnetpcap-1.4.r1425-1d.jar b/rubanetra-0.0.6-distribution/lib/jnetpcap-1.4.r1425-1d.jar new file mode 100644 index 0000000..69c272c Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/jnetpcap-1.4.r1425-1d.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/junit-4.11.jar b/rubanetra-0.0.6-distribution/lib/junit-4.11.jar new file mode 100644 index 0000000..aaf7444 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/junit-4.11.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kie-api-6.1.0.Final.jar b/rubanetra-0.0.6-distribution/lib/kie-api-6.1.0.Final.jar new file mode 100644 index 0000000..bed3687 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kie-api-6.1.0.Final.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kie-internal-6.1.0.Final.jar b/rubanetra-0.0.6-distribution/lib/kie-internal-6.1.0.Final.jar new file mode 100644 index 0000000..1224271 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kie-internal-6.1.0.Final.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-api-2.1.1.jar b/rubanetra-0.0.6-distribution/lib/kraken-api-2.1.1.jar new file mode 100644 index 0000000..ba5a51d Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-api-2.1.1.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-dhcp-decoder-1.0.1.jar b/rubanetra-0.0.6-distribution/lib/kraken-dhcp-decoder-1.0.1.jar new file mode 100644 index 0000000..d52b382 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-dhcp-decoder-1.0.1.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-ftp-decoder-1.2.0.jar b/rubanetra-0.0.6-distribution/lib/kraken-ftp-decoder-1.2.0.jar new file mode 100644 index 0000000..948375d Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-ftp-decoder-1.2.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-http-decoder-1.1.0.jar b/rubanetra-0.0.6-distribution/lib/kraken-http-decoder-1.1.0.jar new file mode 100644 index 0000000..7578975 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-http-decoder-1.1.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-json-1.1.1.jar b/rubanetra-0.0.6-distribution/lib/kraken-json-1.1.1.jar new file mode 100644 index 0000000..e62b00e Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-json-1.1.1.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-mime-1.0.0.jar b/rubanetra-0.0.6-distribution/lib/kraken-mime-1.0.0.jar new file mode 100644 index 0000000..8e1add2 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-mime-1.0.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-msn-decoder-1.2.0.jar b/rubanetra-0.0.6-distribution/lib/kraken-msn-decoder-1.2.0.jar new file mode 100644 index 0000000..1576c9a Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-msn-decoder-1.2.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-netbios-decoder-1.0.0.jar b/rubanetra-0.0.6-distribution/lib/kraken-netbios-decoder-1.0.0.jar new file mode 100644 index 0000000..757ab9d Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-netbios-decoder-1.0.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-pcap-1.7.1.jar b/rubanetra-0.0.6-distribution/lib/kraken-pcap-1.7.1.jar new file mode 100644 index 0000000..825fca8 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-pcap-1.7.1.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-pop3-decoder-1.0.0.jar b/rubanetra-0.0.6-distribution/lib/kraken-pop3-decoder-1.0.0.jar new file mode 100644 index 0000000..9d69a18 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-pop3-decoder-1.0.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-smtp-decoder-1.1.0.jar b/rubanetra-0.0.6-distribution/lib/kraken-smtp-decoder-1.1.0.jar new file mode 100644 index 0000000..51db30a Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-smtp-decoder-1.1.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-snmp-decoder-1.1.0.jar b/rubanetra-0.0.6-distribution/lib/kraken-snmp-decoder-1.1.0.jar new file mode 100644 index 0000000..58a9e8f Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-snmp-decoder-1.1.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/kraken-telnet-decoder-1.0.0.jar b/rubanetra-0.0.6-distribution/lib/kraken-telnet-decoder-1.0.0.jar new file mode 100644 index 0000000..4006215 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/kraken-telnet-decoder-1.0.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/amd64/libjnetpcap-pcap100.so b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/amd64/libjnetpcap-pcap100.so new file mode 100644 index 0000000..f2bcce1 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/amd64/libjnetpcap-pcap100.so differ diff --git a/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/amd64/libjnetpcap.so b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/amd64/libjnetpcap.so new file mode 100644 index 0000000..e4e3a98 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/amd64/libjnetpcap.so differ diff --git a/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/i386/libjnetpcap-pcap100.so b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/i386/libjnetpcap-pcap100.so new file mode 100644 index 0000000..5b149c0 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/i386/libjnetpcap-pcap100.so differ diff --git a/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/i386/libjnetpcap.so b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/i386/libjnetpcap.so new file mode 100644 index 0000000..4a2b222 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/linux/i386/libjnetpcap.so differ diff --git a/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86/jnetpcap-pcap100.dll b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86/jnetpcap-pcap100.dll new file mode 100644 index 0000000..5b3061b Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86/jnetpcap-pcap100.dll differ diff --git a/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86/jnetpcap.dll b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86/jnetpcap.dll new file mode 100644 index 0000000..86c12ed Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86/jnetpcap.dll differ diff --git a/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86_64/jnetpcap-pcap100.dll b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86_64/jnetpcap-pcap100.dll new file mode 100644 index 0000000..edf5101 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86_64/jnetpcap-pcap100.dll differ diff --git a/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86_64/jnetpcap.dll b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86_64/jnetpcap.dll new file mode 100644 index 0000000..b905ece Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/libjnetpcap/native/windows/x86_64/jnetpcap.dll differ diff --git a/rubanetra-0.0.6-distribution/lib/logback-classic-1.1.1.jar b/rubanetra-0.0.6-distribution/lib/logback-classic-1.1.1.jar new file mode 100644 index 0000000..39f68c4 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/logback-classic-1.1.1.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/logback-core-1.1.1.jar b/rubanetra-0.0.6-distribution/lib/logback-core-1.1.1.jar new file mode 100644 index 0000000..893962d Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/logback-core-1.1.1.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/mail-1.4.7.jar b/rubanetra-0.0.6-distribution/lib/mail-1.4.7.jar new file mode 100644 index 0000000..236fcdb Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/mail-1.4.7.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/mvel2-2.2.1.Final.jar b/rubanetra-0.0.6-distribution/lib/mvel2-2.2.1.Final.jar new file mode 100644 index 0000000..ce7e1a5 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/mvel2-2.2.1.Final.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/org.abego.treelayout.core-1.0.1.jar b/rubanetra-0.0.6-distribution/lib/org.abego.treelayout.core-1.0.1.jar new file mode 100644 index 0000000..2350adc Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/org.abego.treelayout.core-1.0.1.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/protobuf-java-2.5.0.jar b/rubanetra-0.0.6-distribution/lib/protobuf-java-2.5.0.jar new file mode 100644 index 0000000..4c4e686 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/protobuf-java-2.5.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/slf4j-api-1.7.6.jar b/rubanetra-0.0.6-distribution/lib/slf4j-api-1.7.6.jar new file mode 100644 index 0000000..19aaf37 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/slf4j-api-1.7.6.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/stax-api-1.0-2.jar b/rubanetra-0.0.6-distribution/lib/stax-api-1.0-2.jar new file mode 100644 index 0000000..015169d Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/stax-api-1.0-2.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/stax2-api-3.1.4.jar b/rubanetra-0.0.6-distribution/lib/stax2-api-3.1.4.jar new file mode 100644 index 0000000..dded036 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/stax2-api-3.1.4.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/woodstox-core-asl-4.3.0.jar b/rubanetra-0.0.6-distribution/lib/woodstox-core-asl-4.3.0.jar new file mode 100644 index 0000000..f0dd996 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/woodstox-core-asl-4.3.0.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/xmlpull-1.1.3.1.jar b/rubanetra-0.0.6-distribution/lib/xmlpull-1.1.3.1.jar new file mode 100644 index 0000000..cbc149d Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/xmlpull-1.1.3.1.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/xpp3_min-1.1.4c.jar b/rubanetra-0.0.6-distribution/lib/xpp3_min-1.1.4c.jar new file mode 100644 index 0000000..813a9a8 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/xpp3_min-1.1.4c.jar differ diff --git a/rubanetra-0.0.6-distribution/lib/xstream-1.4.7.jar b/rubanetra-0.0.6-distribution/lib/xstream-1.4.7.jar new file mode 100644 index 0000000..ea4b6a2 Binary files /dev/null and b/rubanetra-0.0.6-distribution/lib/xstream-1.4.7.jar differ diff --git a/rubanetra-0.0.6-distribution/rubanetra-0.0.6-javadoc.jar b/rubanetra-0.0.6-distribution/rubanetra-0.0.6-javadoc.jar new file mode 100644 index 0000000..76eadb7 Binary files /dev/null and b/rubanetra-0.0.6-distribution/rubanetra-0.0.6-javadoc.jar differ diff --git a/rubanetra-0.0.6-distribution/rubanetra-0.0.6-sources.jar b/rubanetra-0.0.6-distribution/rubanetra-0.0.6-sources.jar new file mode 100644 index 0000000..c5dd4c4 Binary files /dev/null and b/rubanetra-0.0.6-distribution/rubanetra-0.0.6-sources.jar differ diff --git a/rubanetra-0.0.6-distribution/rubanetra-0.0.6-test-sources.jar b/rubanetra-0.0.6-distribution/rubanetra-0.0.6-test-sources.jar new file mode 100644 index 0000000..05f5a2e Binary files /dev/null and b/rubanetra-0.0.6-distribution/rubanetra-0.0.6-test-sources.jar differ diff --git a/rubanetra-0.0.6-distribution/rubanetra-0.0.6.jar b/rubanetra-0.0.6-distribution/rubanetra-0.0.6.jar new file mode 100644 index 0000000..a54596a Binary files /dev/null and b/rubanetra-0.0.6-distribution/rubanetra-0.0.6.jar differ diff --git a/src/license/gpl_v3/header.txt b/src/license/gpl_v3/header.txt new file mode 100644 index 0000000..49b5275 --- /dev/null +++ b/src/license/gpl_v3/header.txt @@ -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 . \ No newline at end of file diff --git a/src/license/licenses.xml b/src/license/licenses.xml new file mode 100644 index 0000000..05c1a68 --- /dev/null +++ b/src/license/licenses.xml @@ -0,0 +1,84 @@ + + + + + + org.slf4j + slf4j-simple + + + The MIT License + http://www.slf4j.org/license.html + + + + + commons-codec + commons-codec + + + The Apache Software License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + + + + + dnsjava + dnsjava + + + The BSD License + http://www.dnsjava.org/dnsjava-current/README + + + + + xpp3 + xpp3_min + + + Indiana University Extreme! Lab Software License, version 1.1.1 + http://www.bearcave.com/software/java/xml/xmlpull_license.html + + + + + org.apache.httpcomponents + httpclient + + + The Apache Software License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + + + + + org.apache.httpcomponents + httpcore + + + The Apache Software License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + + + + + \ No newline at end of file diff --git a/src/main/antlr4/at/jku/fim/rubanetra/config/RubanetraSystemConfiguration.g4 b/src/main/antlr4/at/jku/fim/rubanetra/config/RubanetraSystemConfiguration.g4 new file mode 100644 index 0000000..7a7ee99 --- /dev/null +++ b/src/main/antlr4/at/jku/fim/rubanetra/config/RubanetraSystemConfiguration.g4 @@ -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 . + */ +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 diff --git a/src/main/assembly/distribution-zip.xml b/src/main/assembly/distribution-zip.xml new file mode 100644 index 0000000..35311cd --- /dev/null +++ b/src/main/assembly/distribution-zip.xml @@ -0,0 +1,96 @@ + + + distribution + ${project.build.finalName}-distribution + + zip + + + + + ${project.basedir} + / + + README* + LICENSE* + NOTICE* + + true + + + ${archive.output.directory} + / + + *.jar + + + + ${project.build.directory}/lib + lib + + + ${project.build.directory}/${jnetpcap.native.lib.directory}/native + lib/${jnetpcap.native.lib.directory} + + + ${project.build.directory}/generated-sources/license + / + + + ${project.build.directory}/generated-resources/licenses + lib/licenses + + + ${project.build.directory}/generated-resources + lib + + licenses.xml + + + + + src/main/resources + conf + + DefaultKnowledgeBase/** + META-INF/kmodule.xml + *.conf + *.properties + *.xml + + true + + + + + pom.xml + conf/META-INF/maven/${project.groupId}/${project.artifactId} + true + + + ${project.build.directory}/maven-archiver/pom.properties + conf/META-INF/maven/${project.groupId}/${project.artifactId} + true + + + diff --git a/src/main/assembly/package-zip.xml b/src/main/assembly/package-zip.xml new file mode 100644 index 0000000..14c75ee --- /dev/null +++ b/src/main/assembly/package-zip.xml @@ -0,0 +1,68 @@ + + + package + ${project.build.finalName}-package + + + + zip + + + + ${project.basedir} + + README* + NOTICE* + + true + true + + + ${project.basedir} + + pom.xml + + false + + + ${project.basedir}/src/main + + + ${project.basedir}/src/license + + + ${project.build.directory}/generated-sources/license + / + + + ${project.basedir}/src + /src + true + + **/*.log + **/${project.build.directory}/** + **/test/** + + + + \ No newline at end of file diff --git a/src/main/java/at/jku/fim/rubanetra/config/ConfigurationController.java b/src/main/java/at/jku/fim/rubanetra/config/ConfigurationController.java new file mode 100644 index 0000000..2b8f611 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/ConfigurationController.java @@ -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 . + */ +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. + *

+ * 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: + *

    + *
  • File named "rubanetra.conf" in the classpath and as a relative path
  • + *
  • "./conf/rubanetra.conf" in the classpath and as relative path
  • + *
  • Value of environment variable "RUBANETRA_SYSTEM_CONF_FILE" interpreted as file path.
  • + *
+ *

+ * 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'. + *

+ * 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. + *

+ * 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 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 ", cmdLineSyntax), defaultOptions); + + if (manifestAttributes != null) { + StringBuilder strBuilder = new StringBuilder(); + strBuilder.append(String.format("%nReport bugs to: <%s> or %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 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): + *

    + *
  • "rubanetra.conf" in the classpath and working directory
  • + *
  • "./conf/rubanetra.conf" in the classpath and working directory
  • + *
  • path denoted by environment variable FNA_SYSTEM_CONF_FILE in the class path and working directory
  • + *
+ * 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}. + *

+ * 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} + *

+ * 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. + *

+ * 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. + *

+ * 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; + } + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/JNetPcapProtocolId.java b/src/main/java/at/jku/fim/rubanetra/config/model/JNetPcapProtocolId.java new file mode 100644 index 0000000..7cbf86c --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/JNetPcapProtocolId.java @@ -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 . + */ +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(); +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/KrakenApplicationProtocolId.java b/src/main/java/at/jku/fim/rubanetra/config/model/KrakenApplicationProtocolId.java new file mode 100644 index 0000000..df60c35 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/KrakenApplicationProtocolId.java @@ -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 . + */ +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(); +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/KrakenProtocolConfiguration.java b/src/main/java/at/jku/fim/rubanetra/config/model/KrakenProtocolConfiguration.java new file mode 100644 index 0000000..94fe158 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/KrakenProtocolConfiguration.java @@ -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 . + */ +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. + *

+ * 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 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 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(); +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/KrakenProtocolConfigurationBuilder.java b/src/main/java/at/jku/fim/rubanetra/config/model/KrakenProtocolConfigurationBuilder.java new file mode 100644 index 0000000..76aa0f1 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/KrakenProtocolConfigurationBuilder.java @@ -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 . + */ +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 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); +} \ No newline at end of file diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/Port.java b/src/main/java/at/jku/fim/rubanetra/config/model/Port.java new file mode 100644 index 0000000..f7be849 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/Port.java @@ -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 . + */ +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 { + /** + * 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 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); + } + +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/PortRange.java b/src/main/java/at/jku/fim/rubanetra/config/model/PortRange.java new file mode 100644 index 0000000..37953de --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/PortRange.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/PortSpecification.java b/src/main/java/at/jku/fim/rubanetra/config/model/PortSpecification.java new file mode 100644 index 0000000..268aa6f --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/PortSpecification.java @@ -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 . + */ +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 portMap; + private final Set 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; + } + } + +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/ProtocolId.java b/src/main/java/at/jku/fim/rubanetra/config/model/ProtocolId.java new file mode 100644 index 0000000..f28b770 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/ProtocolId.java @@ -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 . + */ +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(); +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/RubanetraSystemConfiguration.java b/src/main/java/at/jku/fim/rubanetra/config/model/RubanetraSystemConfiguration.java new file mode 100644 index 0000000..48da65e --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/RubanetraSystemConfiguration.java @@ -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 . + */ +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 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 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 + } + + +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/impl/KrakenProtocolConfigurationBuilderImpl.java b/src/main/java/at/jku/fim/rubanetra/config/model/impl/KrakenProtocolConfigurationBuilderImpl.java new file mode 100644 index 0000000..3cd24f4 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/impl/KrakenProtocolConfigurationBuilderImpl.java @@ -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 . + */ +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> currentProtocolBindingMap; + private PortSpecification currentProtocolPortSpec; + private KrakenTransportLayerMappingFactory currentTransportLayerMappingFactory; + private String currentTransportLayerStrategy; + private PcapHandler 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 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. + *

+ * 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 pcapHandler; + private final Map 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 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 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 getPcapHandler() { + return this.pcapHandler; + } + + @Override + public KrakenTransportLayerMappingFactory getTransportLayerMappingFactory() { + return transportLayerMappingFactory; + } + } + +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/impl/OutputStrategyFactory.java b/src/main/java/at/jku/fim/rubanetra/config/model/impl/OutputStrategyFactory.java new file mode 100644 index 0000000..d266630 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/impl/OutputStrategyFactory.java @@ -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 . + */ +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; + } + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/impl/ProtocolClassRegistry.java b/src/main/java/at/jku/fim/rubanetra/config/model/impl/ProtocolClassRegistry.java new file mode 100644 index 0000000..5041c99 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/impl/ProtocolClassRegistry.java @@ -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 . + */ +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> protocolRegistry; + private final Map 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 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 getRegisteredProtocolClass(ProtocolId id) { + return protocolRegistry.get(id); + } + + /** + * @return all currently registered protocol identifiers + */ + public Set getRegisteredProtocolIdSet() { + return Collections.unmodifiableSet(protocolRegistry.keySet()); + } + + /** + * @return all currently registered protocol handler classes (duplicates may be possible) + */ + public Collection> 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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/impl/RubanetraSystemConfigurationBaseListenerImpl.java b/src/main/java/at/jku/fim/rubanetra/config/model/impl/RubanetraSystemConfigurationBaseListenerImpl.java new file mode 100644 index 0000000..894c1ed --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/impl/RubanetraSystemConfigurationBaseListenerImpl.java @@ -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 . + */ +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. + *

+ * 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}. + *

+ * 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.: + *

+ * {@code RubanetraSystemConfigurationParser systemConfigParser = RubanetraSystemConfigurationBaseListenerImpl.createConfigurationFileParser(mainConfigFile);} + * {@code RubanetraSystemConfigurationParser.SystemContext systemContext = systemConfigParser.system();} + *

+ * And finally a {@link org.antlr.v4.runtime.tree.ParseTreeWalker} may then be used to traverse the parse tree of the + * general configuration: + *

+ * {@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 = ctx.portSpecification(); + List protocolBindingContexts = ctx.protocolBinding(); + List 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 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 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 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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/config/model/impl/RubanetraSystemConfigurationBuilder.java b/src/main/java/at/jku/fim/rubanetra/config/model/impl/RubanetraSystemConfigurationBuilder.java new file mode 100644 index 0000000..0c82b6b --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/config/model/impl/RubanetraSystemConfigurationBuilder.java @@ -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 . + */ +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 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 pcapHandler; + + private String bpfFilter; + private boolean bpfOptimize = false; + private int bpfNetmask = 0; + /** + * Kraken library specific settings + */ + private final KrakenTransportLayerMappingFactory transportLayerMappingFactory; + + private final Set 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 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. + *

+ * 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 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 + *

+ * 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 + *

+ * 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 + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * ENHANCEMENT: This will probably change in the future, + * as soon as a new way to define the knowledge base is found. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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 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 protocolSettings; + private final PcapFileHandler pcapHandler; + private final Set 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 getProtocolSettings() { + return Collections.unmodifiableSet(protocolSettings); + } + + @Override + public PcapFileHandler getPcapHandler() { + return pcapHandler; + } + + @Override + public KieSession getKieSession() { + return kieSession; + } + + @Override + public Set getInputFiles() { + return inputFiles; + } + + @Override + public InputFormat getInputFormat() { + return inputFormat; + } + + @Override + public OutputWriterStrategy getOutputWriterStrategy() { + return outputWriterStrategy; + } + } + +} diff --git a/src/main/java/at/jku/fim/rubanetra/drools/DroolsKnowledgeBaseFactory.java b/src/main/java/at/jku/fim/rubanetra/drools/DroolsKnowledgeBaseFactory.java new file mode 100644 index 0000000..dc6edc4 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/drools/DroolsKnowledgeBaseFactory.java @@ -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 . + */ +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. + *

+ * 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; + } + + +} diff --git a/src/main/java/at/jku/fim/rubanetra/drools/DroolsKrakenProtocolHandler.java b/src/main/java/at/jku/fim/rubanetra/drools/DroolsKrakenProtocolHandler.java new file mode 100644 index 0000000..b2cd34f --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/drools/DroolsKrakenProtocolHandler.java @@ -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 . + */ +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. + *

+ * 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. + *

+ * 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> 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 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()); + } + } + } + +} diff --git a/src/main/java/at/jku/fim/rubanetra/output/CsvRecordOutputWriter.java b/src/main/java/at/jku/fim/rubanetra/output/CsvRecordOutputWriter.java new file mode 100644 index 0000000..08fa638 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/output/CsvRecordOutputWriter.java @@ -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 . + */ +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; +} diff --git a/src/main/java/at/jku/fim/rubanetra/output/OutputWriterStrategy.java b/src/main/java/at/jku/fim/rubanetra/output/OutputWriterStrategy.java new file mode 100644 index 0000000..cabf282 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/output/OutputWriterStrategy.java @@ -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 . + */ +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; +} diff --git a/src/main/java/at/jku/fim/rubanetra/output/impl/CsvOutputWriterStrategy.java b/src/main/java/at/jku/fim/rubanetra/output/impl/CsvOutputWriterStrategy.java new file mode 100644 index 0000000..f892e90 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/output/impl/CsvOutputWriterStrategy.java @@ -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 . + */ +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(); + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/output/impl/JsonOutputWriterStrategy.java b/src/main/java/at/jku/fim/rubanetra/output/impl/JsonOutputWriterStrategy.java new file mode 100644 index 0000000..3299dd4 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/output/impl/JsonOutputWriterStrategy.java @@ -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 . + */ +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. + *

+ * 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); + } + } + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/output/impl/NopOutputWriterStrategy.java b/src/main/java/at/jku/fim/rubanetra/output/impl/NopOutputWriterStrategy.java new file mode 100644 index 0000000..5156ad7 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/output/impl/NopOutputWriterStrategy.java @@ -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 . + */ +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 + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/output/impl/XmlOutputWriterStrategy.java b/src/main/java/at/jku/fim/rubanetra/output/impl/XmlOutputWriterStrategy.java new file mode 100644 index 0000000..1db4cbf --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/output/impl/XmlOutputWriterStrategy.java @@ -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 . + */ +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; + } + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/output/mixin/HttpMixIn.java b/src/main/java/at/jku/fim/rubanetra/output/mixin/HttpMixIn.java new file mode 100644 index 0000000..01ed217 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/output/mixin/HttpMixIn.java @@ -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 . + */ +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(); +} diff --git a/src/main/java/at/jku/fim/rubanetra/output/mixin/PcapMixIn.java b/src/main/java/at/jku/fim/rubanetra/output/mixin/PcapMixIn.java new file mode 100644 index 0000000..80305a7 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/output/mixin/PcapMixIn.java @@ -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 . + */ +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(); + +} diff --git a/src/main/java/at/jku/fim/rubanetra/pcap/PcapActivity.java b/src/main/java/at/jku/fim/rubanetra/pcap/PcapActivity.java new file mode 100644 index 0000000..7d62bae --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/pcap/PcapActivity.java @@ -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 . + */ +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): + *

+ * {@code byte[] arr = new byte[getPcapPacket().getPacketData().readableBytes()];} + *

+ * {@code new ChainBuffer(getPcapPacket().getPacketData()).gets(arr);} + *

+ * {@code JMemoryPacket jPacket = new JMemoryPacket(arr);} + *

+ * {@code jPacket.scan(Ethernet.ID);} + *

+ * {@code Ethernet header = jPacket.getHeader(new Ethernet());} + *

+ * 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 getCompoundFrameNumbers() { + return Collections.unmodifiableCollection(Arrays.asList(getFrameNumber())); + } + + @Override + public String toString() { + return "PcapActivity{" + + "frameNumber=" + frameNumber + + ", pcapPacket=" + pcapPacket + + ", pcapTimestamp=" + pcapTimestamp + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/pcap/PcapActivityListener.java b/src/main/java/at/jku/fim/rubanetra/pcap/PcapActivityListener.java new file mode 100644 index 0000000..f4e5bfe --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/pcap/PcapActivityListener.java @@ -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 . + */ +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); +} diff --git a/src/main/java/at/jku/fim/rubanetra/pcap/PcapFileHandler.java b/src/main/java/at/jku/fim/rubanetra/pcap/PcapFileHandler.java new file mode 100644 index 0000000..bded17e --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/pcap/PcapFileHandler.java @@ -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 . + */ +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.: + *

    + *
  • if multiple files are passed and the sortByPcapTimestamp flag is set to false, all files are treated in + * the order they have been passed
  • + *
  • 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.
  • + *
  • if a single file is passed, the sortByPcapTimestamp flag will be ignored
  • + *
+ *

+ * 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 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 implements PcapHandler { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final StringBuilder errorBuilder = new StringBuilder(); + + private final Queue pcapInputFileQueue; + private final int numberOfInputFiles; + private final boolean sortByPcapTimestamp; + private final List fileActivityListeners; + private final JPacketHandler 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 firstPcapActivities = new HashMap<>(); + for (File f : pcapFiles) { + PcapFileHandler fileHandler = new PcapFileHandler(pcapFilter, false, f); + fileHandler.readNextPcapEntry(pcapActivity -> firstPcapActivities.put(pcapActivity, f)); + fileHandler.close(); + } + Stream 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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/pcap/PcapFilter.java b/src/main/java/at/jku/fim/rubanetra/pcap/PcapFilter.java new file mode 100644 index 0000000..a3dabb5 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/pcap/PcapFilter.java @@ -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 . + */ +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; + } + +} diff --git a/src/main/java/at/jku/fim/rubanetra/pcap/PcapHandler.java b/src/main/java/at/jku/fim/rubanetra/pcap/PcapHandler.java new file mode 100644 index 0000000..dd3a6cb --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/pcap/PcapHandler.java @@ -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 . + */ +package at.jku.fim.rubanetra.pcap; + + +import java.io.Closeable; +import java.io.IOException; + +public interface PcapHandler 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; +} diff --git a/src/main/java/at/jku/fim/rubanetra/pcap/PcapPacketToKrakenPcapPacketAdapter.java b/src/main/java/at/jku/fim/rubanetra/pcap/PcapPacketToKrakenPcapPacketAdapter.java new file mode 100644 index 0000000..9dadab1 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/pcap/PcapPacketToKrakenPcapPacketAdapter.java @@ -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 . + */ +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; + } + +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/BaseProtocol.java b/src/main/java/at/jku/fim/rubanetra/protocol/BaseProtocol.java new file mode 100644 index 0000000..4ce2a16 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/BaseProtocol.java @@ -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 . + */ +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); +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/KrakenBaseProtocol.java b/src/main/java/at/jku/fim/rubanetra/protocol/KrakenBaseProtocol.java new file mode 100644 index 0000000..d85874f --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/KrakenBaseProtocol.java @@ -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 . + */ +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: + *

    + *
  • define one or multiple 'bind' methods with differing signatures
  • + *
  • adhere to the naming convention, i.e. all methods must be called 'bind'
  • + *
  • 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
  • + *
+ *

+ * 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 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 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); + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/AbstractActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/AbstractActivity.java new file mode 100644 index 0000000..257175f --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/AbstractActivity.java @@ -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 . + */ +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 compoundFrameNumbers = new TreeSet<>(); + private final Collection 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: + *

    + *
  • all frame numbers from act are copied into this set of frame numbers
  • + *
  • if act is chronologically before this activity, the start Instant of this activity is overwritten
  • + *
  • if act is chronologically after this activity, the end Instant of this activity is overwritten
  • + *
  • if act is chronologically during this activity, no instants are modified
  • + *
  • an ADD_FRAME_NUMBER property listener is registered in act, in order to receive all future updates to the + * frame number set
  • + *
  • a NEW_START_INSTANT property listener is registered in act, in order to receive all future updates to the + * start instant
  • + *
  • a NEW_END_INSTANT property listener is registered in act, in order to receive all future updates to the + * end instant
  • + *
+ * 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 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 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 getCompoundFrameNumbers() { + return Collections.unmodifiableCollection(compoundFrameNumbers); + } + + @Override + public Collection 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: + *
+     * activityType, startInstant, endInstant, sourceAddress, destinationAddress, description, frameNumbers, optionalFields
+     * 
+ * + * @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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/AbstractReplaceableActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/AbstractReplaceableActivity.java new file mode 100644 index 0000000..00ee2bb --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/AbstractReplaceableActivity.java @@ -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 . + */ +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); + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/Activity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/Activity.java new file mode 100644 index 0000000..161d473 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/Activity.java @@ -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 . + */ +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: + *
    + *
  • 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
  • + *
  • 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
  • + *
+ * 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: + *
    + *
  • 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
  • + *
  • 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
  • + *
+ * 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 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 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(); +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/DroolsBaseActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/DroolsBaseActivity.java new file mode 100644 index 0000000..71d3a08 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/DroolsBaseActivity.java @@ -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 . + */ +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()); + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/OptionalField.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/OptionalField.java new file mode 100644 index 0000000..1e07b3f --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/OptionalField.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/OutputActivityEvent.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/OutputActivityEvent.java new file mode 100644 index 0000000..63d0e4b --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/OutputActivityEvent.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/ReplaceableActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ReplaceableActivity.java new file mode 100644 index 0000000..4adf463 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ReplaceableActivity.java @@ -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 . + */ +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); +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/arp/ArpActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/arp/ArpActivity.java new file mode 100644 index 0000000..faaa103 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/arp/ArpActivity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/dhcp/DhcpActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/dhcp/DhcpActivity.java new file mode 100644 index 0000000..f03f246 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/dhcp/DhcpActivity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/dns/DnsActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/dns/DnsActivity.java new file mode 100644 index 0000000..33f7f21 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/dns/DnsActivity.java @@ -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 . + */ +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 questionRecords; + private final List answerRecords; + private final List authorityRecords; + private final List 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 getQuestionRecords() { + return Collections.unmodifiableList(questionRecords); + } + + /** + * @return an unmodifiable list of the available answer records + */ + public List getAnswerRecords() { + return Collections.unmodifiableList(answerRecords); + } + + /** + * @return an unmodifiable list of the available authority records + */ + public List getAuthorityRecords() { + return Collections.unmodifiableList(authorityRecords); + } + + /** + * @return an unmodifiable list of the available additional records + */ + public List 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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/ethernet/EthernetActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ethernet/EthernetActivity.java new file mode 100644 index 0000000..60f6002 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ethernet/EthernetActivity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/ftp/FtpActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ftp/FtpActivity.java new file mode 100644 index 0000000..3f6c570 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ftp/FtpActivity.java @@ -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 . + */ +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) + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpActivity.java new file mode 100644 index 0000000..404130c --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpActivity.java @@ -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 . + */ +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 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: + *
    + *
  • 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
  • + *
  • the dnsMatch reference is saved and the DNS activity will be replaced
  • + *
+ * @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 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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpHeader.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpHeader.java new file mode 100644 index 0000000..d1be476 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpHeader.java @@ -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 . + */ +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; + } +} \ No newline at end of file diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpImageActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpImageActivity.java new file mode 100644 index 0000000..7f65a9e --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpImageActivity.java @@ -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 . + */ +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 + '\'' + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpRequestActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpRequestActivity.java new file mode 100644 index 0000000..834ffc1 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpRequestActivity.java @@ -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 . + */ +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 httpQueryParameters; + private final Map 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 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 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 + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpResponseActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpResponseActivity.java new file mode 100644 index 0000000..587f375 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/http/HttpResponseActivity.java @@ -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 . + */ +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 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 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 + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/icmp/Icmpv4Activity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/icmp/Icmpv4Activity.java new file mode 100644 index 0000000..d3a7cbb --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/icmp/Icmpv4Activity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/icmp/Icmpv6Activity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/icmp/Icmpv6Activity.java new file mode 100644 index 0000000..14d98c4 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/icmp/Icmpv6Activity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/icmp/PingActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/icmp/PingActivity.java new file mode 100644 index 0000000..a7043b8 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/icmp/PingActivity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/ip/IpActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ip/IpActivity.java new file mode 100644 index 0000000..b272b36 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ip/IpActivity.java @@ -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 . + */ +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: + *
    + *
  • the protocol version
  • + *
  • the protocol type
  • + *
  • the source L3 address
  • + *
  • the destination L3 address
  • + *
  • the source Pcap activity from which this IP packet was derived from
  • + *
+ */ +@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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/ip/Ipv4Activity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ip/Ipv4Activity.java new file mode 100644 index 0000000..04c8484 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ip/Ipv4Activity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/ip/Ipv6Activity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ip/Ipv6Activity.java new file mode 100644 index 0000000..266ce0b --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/ip/Ipv6Activity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/msn/MsnActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/msn/MsnActivity.java new file mode 100644 index 0000000..2814ed7 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/msn/MsnActivity.java @@ -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 . + */ +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 + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/netbios/NetbiosActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/netbios/NetbiosActivity.java new file mode 100644 index 0000000..b9aeb34 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/netbios/NetbiosActivity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/pop3/Pop3Activity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/pop3/Pop3Activity.java new file mode 100644 index 0000000..e6487ea --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/pop3/Pop3Activity.java @@ -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 . + */ +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 + '\'' + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/skype/SkypeActivityHelper.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/skype/SkypeActivityHelper.java new file mode 100644 index 0000000..a64a4e7 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/skype/SkypeActivityHelper.java @@ -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 . + */ +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; + } + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpActivity.java new file mode 100644 index 0000000..fc897c8 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpActivity.java @@ -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 . + */ +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 + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpCommandActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpCommandActivity.java new file mode 100644 index 0000000..e9f6ab2 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpCommandActivity.java @@ -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 . + */ +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 + '\'' + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpReplyActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpReplyActivity.java new file mode 100644 index 0000000..5b6a2b1 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpReplyActivity.java @@ -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 . + */ +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 + '\'' + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpSendActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpSendActivity.java new file mode 100644 index 0000000..0f84915 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/smtp/SmtpSendActivity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/snmp/Snmpv1Activity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/snmp/Snmpv1Activity.java new file mode 100644 index 0000000..4cfc06a --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/snmp/Snmpv1Activity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/snmp/Snmpv2Activity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/snmp/Snmpv2Activity.java new file mode 100644 index 0000000..39fb9c9 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/snmp/Snmpv2Activity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/tcp/TcpActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/tcp/TcpActivity.java new file mode 100644 index 0000000..0e6cb81 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/tcp/TcpActivity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/telnet/TelnetActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/telnet/TelnetActivity.java new file mode 100644 index 0000000..3397da0 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/telnet/TelnetActivity.java @@ -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 . + */ +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 + '\'' + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/tls/TlsActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/tls/TlsActivity.java new file mode 100644 index 0000000..6e72a3b --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/tls/TlsActivity.java @@ -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 . + */ +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 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 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 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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/tls/TlsActivityHelper.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/tls/TlsActivityHelper.java new file mode 100644 index 0000000..3e7cb94 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/tls/TlsActivityHelper.java @@ -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 . + */ +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; + + } + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/activity/udp/UdpActivity.java b/src/main/java/at/jku/fim/rubanetra/protocol/activity/udp/UdpActivity.java new file mode 100644 index 0000000..6e5dece --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/activity/udp/UdpActivity.java @@ -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 . + */ +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 + + '}'; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenArpHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenArpHandler.java new file mode 100644 index 0000000..5e678e2 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenArpHandler.java @@ -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 . + */ +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; + } + +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenDhcpHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenDhcpHandler.java new file mode 100644 index 0000000..d9b8e18 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenDhcpHandler.java @@ -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 . + */ +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; + } + +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenDnsProtocolHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenDnsProtocolHandler.java new file mode 100644 index 0000000..21b9c7d --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenDnsProtocolHandler.java @@ -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 . + */ +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 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; + } + } + + +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenEthernetProtocolHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenEthernetProtocolHandler.java new file mode 100644 index 0000000..387bbf5 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenEthernetProtocolHandler.java @@ -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 . + */ +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.: + *
    + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenIpv4Handler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenIpv6Handler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenArpHandler}
  • + *
+ */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenFtpHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenFtpHandler.java new file mode 100644 index 0000000..7834890 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenFtpHandler.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenHttpHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenHttpHandler.java new file mode 100644 index 0000000..a70975b --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenHttpHandler.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIcmpv4Handler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIcmpv4Handler.java new file mode 100644 index 0000000..8f5fdc5 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIcmpv4Handler.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIcmpv6Handler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIcmpv6Handler.java new file mode 100644 index 0000000..6bd955f --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIcmpv6Handler.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIpv4Handler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIpv4Handler.java new file mode 100644 index 0000000..5327378 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIpv4Handler.java @@ -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 . + */ +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: + *
    + *
  • {@link at.jku.fim.rubanetra.protocol.handler.KrakenUdpHandler}
  • + *
  • {@link at.jku.fim.rubanetra.protocol.handler.KrakenTcpHandler}
  • + *
  • {@link at.jku.fim.rubanetra.protocol.handler.KrakenIcmpv4Handler}
  • + *
+ */ +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; + } + + +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIpv6Handler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIpv6Handler.java new file mode 100644 index 0000000..db510e5 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenIpv6Handler.java @@ -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 . + */ +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: + *
    + *
  • {@link at.jku.fim.rubanetra.protocol.handler.KrakenTcpHandler}
  • + *
  • {@link at.jku.fim.rubanetra.protocol.handler.KrakenUdpHandler}
  • + *
  • {@link at.jku.fim.rubanetra.protocol.handler.KrakenIcmpv6Handler}
  • + *
+ */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenMsnHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenMsnHandler.java new file mode 100644 index 0000000..0e4752f --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenMsnHandler.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenNetbiosHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenNetbiosHandler.java new file mode 100644 index 0000000..7c2a13f --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenNetbiosHandler.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenPop3Handler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenPop3Handler.java new file mode 100644 index 0000000..2d01c41 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenPop3Handler.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenSmtpHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenSmtpHandler.java new file mode 100644 index 0000000..4eae48d --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenSmtpHandler.java @@ -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 . + */ +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; + } + + +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenSnmpHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenSnmpHandler.java new file mode 100644 index 0000000..26e33b4 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenSnmpHandler.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenTcpHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenTcpHandler.java new file mode 100644 index 0000000..48f1d47 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenTcpHandler.java @@ -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 . + */ +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: + *
    + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenHttpHandler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenMsnHandler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenDnsProtocolHandler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenFtpHandler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenNetbiosHandler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenPop3Handler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenTelnetHandler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenSmtpHandler}
  • + *
+ */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenTelnetHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenTelnetHandler.java new file mode 100644 index 0000000..cb2fc45 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenTelnetHandler.java @@ -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 . + */ +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; + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenUdpHandler.java b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenUdpHandler.java new file mode 100644 index 0000000..7d7d425 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/handler/KrakenUdpHandler.java @@ -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 . + */ +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: + *
    + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenDnsProtocolHandler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenDhcpHandler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenNetbiosHandler}
  • + *
  • -> {@link at.jku.fim.rubanetra.protocol.handler.KrakenSnmpHandler}
  • + *
+ */ +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; + } + + +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/mapper/KrakenTcpProtocolMapperStrategy.java b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/KrakenTcpProtocolMapperStrategy.java new file mode 100644 index 0000000..38cf8fa --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/KrakenTcpProtocolMapperStrategy.java @@ -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 . + */ +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 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); +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/mapper/KrakenTransportLayerMappingFactory.java b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/KrakenTransportLayerMappingFactory.java new file mode 100644 index 0000000..c729b3a --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/KrakenTransportLayerMappingFactory.java @@ -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 . + */ +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> tcpStrategyMap; + private final Map> 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 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 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 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 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())); + } + } + +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/mapper/KrakenUdpProtocolMapperStrategy.java b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/KrakenUdpProtocolMapperStrategy.java new file mode 100644 index 0000000..d9a3e93 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/KrakenUdpProtocolMapperStrategy.java @@ -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 . + */ +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 getUdpProcessors(); +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/mapper/TransportLayerMappingStrategy.java b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/TransportLayerMappingStrategy.java new file mode 100644 index 0000000..27982d0 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/TransportLayerMappingStrategy.java @@ -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 . + */ +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); +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/mapper/impl/KrakenTcpDestinationPortProtocolMapper.java b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/impl/KrakenTcpDestinationPortProtocolMapper.java new file mode 100644 index 0000000..f187d88 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/impl/KrakenTcpDestinationPortProtocolMapper.java @@ -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 . + */ +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 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 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 getTcpProcessors() { + return Collections.unmodifiableSet(tcpProcessorSet); + } +} diff --git a/src/main/java/at/jku/fim/rubanetra/protocol/mapper/impl/KrakenUdpDestinationPortProtocolMapper.java b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/impl/KrakenUdpDestinationPortProtocolMapper.java new file mode 100644 index 0000000..5c3ddd3 --- /dev/null +++ b/src/main/java/at/jku/fim/rubanetra/protocol/mapper/impl/KrakenUdpDestinationPortProtocolMapper.java @@ -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 . + */ +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 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 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 getUdpProcessors() { + return Collections.unmodifiableSet(udpProcessorSet); + } +} diff --git a/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/00.Basic.Metadata.drl b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/00.Basic.Metadata.drl new file mode 100644 index 0000000..29b836c --- /dev/null +++ b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/00.Basic.Metadata.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.arp.*; +import at.jku.fim.rubanetra.protocol.activity.dhcp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import at.jku.fim.rubanetra.protocol.activity.ethernet.*; +import at.jku.fim.rubanetra.protocol.activity.ftp.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.msn.*; +import at.jku.fim.rubanetra.protocol.activity.netbios.*; +import at.jku.fim.rubanetra.protocol.activity.pop3.*; +import at.jku.fim.rubanetra.protocol.activity.skype.*; +import at.jku.fim.rubanetra.protocol.activity.smtp.*; +import at.jku.fim.rubanetra.protocol.activity.snmp.*; +import at.jku.fim.rubanetra.protocol.activity.tcp.*; +import at.jku.fim.rubanetra.protocol.activity.telnet.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.udp.*; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * The following statements declare the metadata of already existing Java abstract classes/interfaces of the + * at.jku.fim.rubanetra.protocol.activity package. + * Specifically it defines these classes as events using the start-timestamp of the activity itself + * as the actual timestamp (used for reasoning) and sets the expiration time of the individual objects. + * If the objects should not expire based on this timer, remove or adapt the @expires attributes. + * Note, however, unless these attributes are overwritten on the Activity-class implementation level, these settings + * will be inherited for all activities (since all Activity-implementations should extend or implement one of the + * abstract classes/interfaces listed below. + */ + +declare DroolsBaseActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + @expires( 30m ) +end + +declare Activity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + @expires( 30m ) +end + +declare ReplaceableActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + @expires( 30m ) +end + +declare AbstractActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + @expires( 30m ) +end + +declare AbstractReplaceableActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + @expires( 30m ) +end \ No newline at end of file diff --git a/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/01.Basic.Output.drl b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/01.Basic.Output.drl new file mode 100644 index 0000000..674dd41 --- /dev/null +++ b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/01.Basic.Output.drl @@ -0,0 +1,44 @@ +/** + * 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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * This global variable constitutes the default output writer that is used to write derived facts, i.e. Activity objects, + * to the final output stream. + */ +global at.jku.fim.rubanetra.output.OutputWriterStrategy outputWriter; + +/** + * This rule will ensure that all encountered OutputActivityEvents will be written to the final output stream, + * as long as the enclosed Activity 'toOutput' is not null and the global 'outputWriter' exists. + * The encountered, valid OutputActivityEvent will be retracted afterwards. + * This behaviour is useful to free memory in case the default event expiration time is not defined or + * set to a high value. + */ +rule "Write to OutputStream (event-based)" + when + $outEvent : OutputActivityEvent(toOutput != null) + then + if (outputWriter != null) { + outputWriter.writeActivity($outEvent.getToOutput()); + } + retract($outEvent); +end diff --git a/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/02.Basic.Http.drl b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/02.Basic.Http.drl new file mode 100644 index 0000000..b545318 --- /dev/null +++ b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/02.Basic.Http.drl @@ -0,0 +1,201 @@ +/** + * 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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.tcp.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import org.xbill.DNS.*; +import org.apache.http.HttpHeaders; +import org.jnetpcap.protocol.tcpip.Tcp; +import org.jnetpcap.packet.PcapPacket; +import org.apache.commons.codec.binary.Hex; +import java.net.InetSocketAddress; +import java.util.HashSet; +import java.util.Date +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Set; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +/** + * This declaration serves as an example to demonstrate the basic attribute overriding process. + * Usually this class extends the Activity-interface and is declared to be an event. + * However, currently no time-based reasoning will be performed for these objects, therefore it can be + * converted to a Fact. + * This declaration may be removed to use the default attributes again (see 00.Basic.Metadata.drl). + */ +declare HttpImageActivity + @role( fact ) + @author( Stefan Swerk ) + @dateOfCreation( 10.01.2014 ) +end + +/** + * The following Tcp declaration represents the jNetPcap-Tcp class, see org.jnetpcap.protocol.tcpip.Tcp. + * Due to 'Tcp' being a Java class of a different library it cannot extend or implement one of the Activity + * base classes and therefore is not treated as a Drools-event per se. Therefore, the metadata of this custom + * class must be defined individually, which can be interpreted as a forward declaration. + */ +declare Tcp + @role( event ) + @author( Stefan Swerk ) + @timestamp( getPacket().getCaptureHeader().timestampInMillis() ) + @expires( 30m ) +end + +/** + * Currently it appears as if the Tcp-decoder of the Kraken library does not parse all valid Tcp-packets successfully. + * As a kind of workaround this rule has been defined to fallback to the jNetPcap library (hence the previous Tcp-forward + * declaration) for all IPv4 activities that indicate TCP as the encapsulated protocol, + * but that have not been decoded by the Kraken-Tcp-Decoder until now. + * This rule will ensure that an appropriate drop-in TcpActivity will be created and inserted in the event-stream, + * which may be used by other rules. + */ +rule "TCP (work around Kraken limitation)" +when + $ip : Ipv4Activity(ipv4.nextHeaderId == Tcp.ID) + not (exists TcpActivity(pcapActivity == $ip.pcapActivity)) +then + Tcp tcp = new Tcp(); + PcapPacket p = $ip.getPcapActivity().getPcapPacket(); + p.hasHeader(tcp); + log.debug("A workaround Tcp-Activity will be created for frames {}", $ip.getCompoundFrameNumbers()); + + TcpActivity tcpActivity = new TcpActivity($ip.getPcapActivity(),tcp,$ip); + tcpActivity.replaceActivity($ip); + insert(tcpActivity); +end + +/** + * This rules makes use of a custom entry-point called "fact-stream" and the previously declared fact-attribute of + * HttpImageActivity. If a HttpActivity is encountered containing an response that defined an "image/..." content_type + * header, it may be assumed that this reponse was used for delivering image data and the corresponding URL of the request + * contained the image path. + */ +rule "Http Image Activity" +no-loop +when + $httpActivity : HttpActivity($contentType : response.responseHeaderMap[HttpHeaders.CONTENT_TYPE] matches "image/.*", + imageActivities.isEmpty()) +then + log.debug("An HttpImageActivity based on the content type was found for frames {}", $httpActivity.getCompoundFrameNumbers()); + + HttpImageActivity imgAct = new HttpImageActivity($httpActivity); + imgAct.setImagePath($httpActivity.getRequest().getUrl().getFile()); + imgAct.setImageType($contentType); + imgAct.setStartInstant($httpActivity.getStartInstant()); + imgAct.setEndInstant($httpActivity.getEndInstant()); + drools.getEntryPoint("fact-stream").insert(imgAct); + modify($httpActivity){ + addImageActivity(imgAct) + } +end + +/** + * This rule fires iff there is a HttpImageActivity whose Requests REFERER Header field matches the Request-URI of + * another HttpActivity, i.e. it collects ImageActivities which may be related to a single HttpActivity. + * Consider the following example: A user queries a HTML-Resource that contains external image resources, + * and usually the browser creates subsequent HTTP requests for the image data retrieval. + * Whenever the Browser sets the Referer header field for those separate requests, we could correlate those separate + * image requests with a single HTML resource request. + */ +rule "Collect Http Image Activities (based on referer header)" +when + $http : HttpActivity($req : request, $reqResource : request.url.toString()) + $imgAct : HttpImageActivity(this not memberOf $http.imageActivities, + source#HttpActivity.request.requestHeaderMap[HttpHeaders.REFERER] matches $reqResource) + from entry-point "fact-stream" + +// add an additional time based constraint +// $htmlRequest : HttpRequestActivity( pcapActivity == $req.pcapActivity) +// $imgRequest : HttpRequestActivity( pcapActivity == $imgAct.source#HttpActivity.request.pcapActivity, +// this after[0s,10s] $htmlRequest) +// +// match a single image request for an image resource to a single request for an html resource only +// not (exists HttpRequestActivity(pcapActivity != $htmlRequest.pcapActivity, +// url.toString() matches $reqResource, +// this before $imgRequest)) +then + modify($http) { + addImageActivity($imgAct) + } +end + +/** + * Currently the event stream will only contain not yet matched HttpRequests and HttpResponses. + * Since the reasoning process will be enhanced by correlated each request to a response this rule tries to achieve + * a simple matching mechanism based on the TCP/IP source and destination port and address. + */ +rule "Http Request and Response Matching (based on TCP/IP source/destination and time)" +when + $tcpReq : TcpActivity( $reqId := pcapActivity, $src : sourceAddress, $dst : destinationAddress) + $request : HttpRequestActivity( $reqId := pcapActivity) + + $tcpResp : TcpActivity( $respId : pcapActivity, $tcpReq.sourcePort == destinationPort, + $src == destinationAddress, $dst == sourceAddress) + $response : HttpResponseActivity(pcapActivity == $respId, this after[0s,1m] $request) + + not (exists HttpActivity(request == $request || response == $response)) + +then + HttpActivity activity = new HttpActivity($request, $response); + log.debug("A HttpRequest was matched with a HttpResponse (frames {})", activity.getCompoundFrameNumbers()); + + insert(activity); +end + +/** + * This rule tries to match a DNS response to a an already existing HttpActivity using the hostname header field and + * a maximum interval between the DNS response and the Http response of [0s;20s]. + * An already existing DNS match of a HttpActivity will not be overwritten. + */ +rule "HttpActivity as a potential result of a preceding DNS activity" +when + $http : HttpActivity($hostHeader : request.requestHeaderMap[HttpHeaders.HOST], dnsMatch==null) + $dnsResponse : DnsActivity(isResponse(), this before[0s,20s] $http) + + /** + * The first two checks are IP based, i.e: was the ip address from the DNS A/AAAA record called and does it match the HTTP server IP? + * The last check is domain based, i.e. the "Host:"-Header field from the HttpRequest is compared against the DNS name reply. + */ + exists( ARecord( $address : getAddress(), $address!.getHostAddress() == $http.request.serverAddress.getAddress().getHostAddress()) + from $dnsResponse.getAnswerRecords() + or AAAARecord( $address : getAddress(), $address!.getHostAddress() == $http.request.serverAddress.getAddress().getHostAddress()) + from $dnsResponse.getAnswerRecords() + or Record( $address : name, $address!.toString().startsWith($hostHeader)) + from $dnsResponse.getAnswerRecords() + ) +then + // At this point there was a preceding DNS response and a matching subsequent HTTP Request and Response + modify($http) { + setDnsMatch($dnsResponse); + }; +end \ No newline at end of file diff --git a/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/03.Basic.Tls.drl b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/03.Basic.Tls.drl new file mode 100644 index 0000000..d044bd6 --- /dev/null +++ b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/03.Basic.Tls.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.tcp.*; +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress +import java.util.List; +import java.util.Set +import java.util.HashSet; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +/** + * This experimental rule looks for sequences of three related TCP-activities, i.e.: + * First, it tries to find a "ClientHello" Packet (according to the TLS handshake) followed by a "ServerHello". + * Finally an additional "ChangeCipher" message is expected before classifying this sequence as a TLS/SSL stream, see + * RFC 5246 (https://tools.ietf.org/html/rfc5246). + * The remaining packets will be assembled by the "TLS traffic"-rules (see below) + */ +rule "TLS Handshake" +when + $clientHello : TcpActivity( $payload : payloadHexFormattedDump(), $payload!=null, + TlsActivityHelper.isClientHello(tcp)) + $serverHello : TcpActivity( sourceSocketAddress==$clientHello.destinationSocketAddress, + destinationSocketAddress==$clientHello.sourceSocketAddress, + TlsActivityHelper.isServerHello(tcp), + this after[0s,10s] $clientHello) + $changeCipher : TcpActivity(sourceSocketAddress==$clientHello.destinationSocketAddress, + destinationSocketAddress==$clientHello.sourceSocketAddress, + TlsActivityHelper.isChangeCipherSpec(tcp), + this after[0s,10s] $serverHello) + + exists TcpActivity( sourceSocketAddress==$clientHello.destinationSocketAddress, + destinationSocketAddress==$clientHello.sourceSocketAddress, + TlsActivityHelper.isChangeCipherSpec(tcp), + this after[0s,10s] $changeCipher) + not (exists TlsActivity(clientHello==$clientHello || serverHello==$serverHello || changeCipherSpec==$changeCipher)) +then + TlsActivity tls = new TlsActivity($clientHello,$serverHello); + tls.setChangeCipherSpec($changeCipher); + insert(tls); +end + +/** + * Collects TCP activities for a given TlsActivity (client to server only) based on source/destionation ip/port + */ +rule "TLS traffic (client -> server)" +when + $tls : TlsActivity($clientHello : clientHello) + $tcp : TcpActivity( sourceSocketAddress==$clientHello.sourceSocketAddress, + destinationSocketAddress==$clientHello.destinationSocketAddress) +then + $tls.addClientToServerTcpActivity($tcp); +end + +/** + * Collects TCP activities for a given TlsActivity (server to client only) based on source/destionation ip/port + */ +rule "TLS traffic (server -> client)" +when + $tls : TlsActivity($serverHello : serverHello) + $tcp : TcpActivity( sourceSocketAddress==$serverHello.sourceSocketAddress, + destinationSocketAddress==$serverHello.destinationSocketAddress) +then + $tls.addServerToClientTcpActivity($tcp); +end \ No newline at end of file diff --git a/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/04.Derived.Https.drl b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/04.Derived.Https.drl new file mode 100644 index 0000000..78fe688 --- /dev/null +++ b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/04.Derived.Https.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import org.xbill.DNS.*; +import org.apache.http.HttpHeaders; +import org.jnetpcap.protocol.tcpip.Tcp; +import org.jnetpcap.packet.PcapPacket; +import org.apache.commons.codec.binary.Hex; +import java.net.InetSocketAddress; +import java.util.HashSet; +import java.util.Date +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress +import java.util.List; +import java.util.Set; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +// this forward declaration is required to demonstrate the in-place definition of a custom event class, +// see HttpsActivity below +declare DroolsBaseActivity +end + +/** + * This declaration demonstrates an in-place declaration of a custom event class. + * A HttpsActivity currently consists of a client/server socket address and TLS-Activity, however, + * it includes all relevant frame numbers for further analysis because it replaces the TLS-activity. + */ +declare HttpsActivity extends DroolsBaseActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + + client : InetSocketAddress + server : InetSocketAddress + tlsActivity : TlsActivity +end + +rule "HTTPS" when + $tls : TlsActivity( clientHello.destinationPort == 443, !replaced) + not (exists HttpsActivity($tls == tlsActivity)) +then + HttpsActivity httpsActivity = new HttpsActivity(); + httpsActivity.setClient($tls.getClientHello().getSourceSocketAddress()); + httpsActivity.setServer($tls.getClientHello().getDestinationSocketAddress()); + httpsActivity.setTlsActivity($tls); + httpsActivity.replaceActivity($tls); + insert(httpsActivity); +end diff --git a/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/05.Basic.Icmp.drl b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/05.Basic.Icmp.drl new file mode 100644 index 0000000..08cdf88 --- /dev/null +++ b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/05.Basic.Icmp.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import org.xbill.DNS.*; +import org.jnetpcap.protocol.network.Icmp.IcmpCode; +import org.jnetpcap.protocol.network.Icmp.IcmpType; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +/** + * Groups ICMP echo requests and echo replies to a PingActivity + */ +rule "Ping (Icmpv4)" +when + $req : Icmpv4Activity( $id : identifier, $seq : sequence, icmpType == IcmpType.ECHO_REQUEST) + $rep : Icmpv4Activity( identifier == $id, sequence == $seq, icmpType == IcmpType.ECHO_REPLY) + + not (exists PingActivity(request == $req || reply == $rep)) +then + insert(new PingActivity($req, $rep)); +end \ No newline at end of file diff --git a/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/06.Application.OpenSSH.drl b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/06.Application.OpenSSH.drl new file mode 100644 index 0000000..afc353d --- /dev/null +++ b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/06.Application.OpenSSH.drl @@ -0,0 +1,112 @@ +/** + * 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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import at.jku.fim.rubanetra.protocol.activity.tcp.*; +import java.util.HashSet; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +/** + * forward declaration, used for declaring the OpenSSHActivity + */ +declare DroolsBaseActivity +end + +/** + * Represents OpenSSH traffic between a client and a server. + */ +declare OpenSSHActivity extends DroolsBaseActivity + @role( event ) + @timestamp( getStartTimestamp() ) + + handshakeQuery : TcpActivity + handshakeReply : TcpActivity + + clientToServerTraffic : HashSet + serverToClientTraffic : HashSet +end + +/** + * Tries to identfiy an OpenSSH handshake by relying on the presence of the 'SSH-' substring of the + * payload to identify the handshake. + */ +rule "OpenSSH Handshake" +when + $handshakeQuery : TcpActivity( payloadString!.startsWith("SSH-"), + payloadString!.contains("OpenSSH")) + $handshakeReply : TcpActivity( pcapActivity != $handshakeQuery.getPcapActivity(), + payloadString!.startsWith("SSH-"), + payloadString!.contains("OpenSSH"), + sourcePort==$handshakeQuery.destinationPort, + destinationPort==$handshakeQuery.sourcePort, + this after[0s,10s] $handshakeQuery) + + // there should not exist another reply before the matched reply + not(exists TcpActivity( pcapActivity != $handshakeQuery.getPcapActivity(), + payloadString!.startsWith("SSH-"), + sourcePort==$handshakeQuery.destinationPort, destinationPort==$handshakeQuery.sourcePort, + this before $handshakeReply, this after $handshakeQuery)) +then + OpenSSHActivity sshAct = new OpenSSHActivity(); + sshAct.setHandshakeQuery($handshakeQuery); + sshAct.setHandshakeReply($handshakeReply); + sshAct.setClientToServerTraffic(new HashSet()); + sshAct.setServerToClientTraffic(new HashSet()); + sshAct.replaceActivity($handshakeQuery); + sshAct.replaceActivity($handshakeReply); + insert(sshAct); +end + +/** + * Collects client to server traffic (TCP activities) + */ +rule "OpenSSH traffic (client -> server)" +when + $sshAct : OpenSSHActivity() + $tcp : TcpActivity( pcapActivity.frameNumber not memberOf $sshAct.compoundFrameNumbers, + sourceSocketAddress==$sshAct.handshakeQuery.sourceSocketAddress, + destinationSocketAddress==$sshAct.handshakeQuery.destinationSocketAddress) +then + $sshAct.getClientToServerTraffic().addAll($tcp.getCompoundFrameNumbers()); + $sshAct.replaceActivity($tcp); +end + +/** + * Collects server to client traffic (TCP activities) + */ +rule "OpenSSH traffic (server -> client)" +when + $sshAct : OpenSSHActivity() + $tcp : TcpActivity( pcapActivity.frameNumber not memberOf $sshAct.compoundFrameNumbers, + sourceSocketAddress==$sshAct.handshakeReply.sourceSocketAddress, + destinationSocketAddress==$sshAct.handshakeReply.destinationSocketAddress) +then + $sshAct.getServerToClientTraffic().addAll($tcp.getCompoundFrameNumbers()); + $sshAct.replaceActivity($tcp); +end diff --git a/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/07.Application.Dropbox.drl b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/07.Application.Dropbox.drl new file mode 100644 index 0000000..b74d597 --- /dev/null +++ b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/07.Application.Dropbox.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Set; +import java.util.HashSet; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +// forward declaration +declare DroolsBaseActivity +end + +/** + * A DropboxTlsActivity contains a DNS query/reply, client/server address/port and the associated Tls-Activity + */ +declare DropboxTlsActivity extends DroolsBaseActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + + dnsQuestion : DnsActivity + dnsAnswer : DnsActivity + + clientAddress : InetSocketAddress + serverAddress : InetSocketAddress + + associatedTlsActivity : TlsActivity +end + +/** + * Due to the generally encrypted dropbox traffic a DnsActivity containing the rule looks for query to "*.dropbox.com" + * first and gathers the relevant Ip-Addresses for which possible TlsActivitiy-objects will be probed against. + */ +rule "Dropbox TLS traffic based on previous DnsActivity" +when + $dnsQuery : DnsActivity(!isResponse(), !questionRecords.isEmpty(), + $queryId : dnsMessageHeader.ID,$question : dnsMessage.question.name, + $question.toString() matches ".*\\.dropbox.com\\.$") + $dnsReply : DnsActivity(isResponse(),!answerRecords.isEmpty(), + dnsMessageHeader.ID == $queryId, + this after[0s,10s] $dnsQuery) + $tls : TlsActivity(this after[0s,10s] $dnsReply) + + exists ( ARecord( $address : getAddress(), + $address!.getHostAddress() == $tls.getServerHello().getSourceAddress().getHostAddress()) + from $dnsReply.getAnswerRecords() + or AAAARecord( $address : getAddress(), + $address!.getHostAddress() == $tls.getServerHello().getSourceAddress().getHostAddress()) + from $dnsReply.getAnswerRecords() + ) + not ( exists DropboxTlsActivity($tls == associatedTlsActivity)) +then + DropboxTlsActivity act = new DropboxTlsActivity(); + act.setClientAddress($tls.getClientHello().getSourceSocketAddress()); + act.setServerAddress($tls.getServerHello().getSourceSocketAddress()); + act.setDnsQuestion($dnsQuery); + act.setDnsAnswer($dnsReply); + act.setAssociatedTlsActivity($tls); + act.replaceActivity($dnsQuery); act.replaceActivity($dnsReply); act.replaceActivity($tls); + + insert(act); +end \ No newline at end of file diff --git a/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/08.Application.SpiderOak.drl b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/08.Application.SpiderOak.drl new file mode 100644 index 0000000..f387589 --- /dev/null +++ b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/08.Application.SpiderOak.drl @@ -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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Set; +import java.util.HashSet; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +// forward declaration +declare DroolsBaseActivity +end + +/** + * This declaration defines an SpiderOak related Activity, consisting of DNS query/reply, client/server address/port + * and the associated TlsActivity + */ +declare SpiderOakActivity extends DroolsBaseActivity + @role( event ) + @author( Stefan Swerk ) + @timestamp( getStartTimestamp() ) + + dnsAnswer : DnsActivity + + clientAddress : InetSocketAddress + serverAddress : InetSocketAddress + + associatedTlsActivity : TlsActivity +end + +/** + * This rule is quite similar to the Dropbox tls traffic matching rule. + * It looks for a DNS query to "*.spideroak.com" and gathers the relevant IP addresses for probing existing, yet unmatched + * TlsActivities. + */ +rule "Spideroak TLS traffic based on DnsActivity" +when + $dnsReply : DnsActivity(isResponse(), !answerRecords.isEmpty(), + $question : dnsMessage.question.name, + $question.toString() matches ".*\\.spideroak.com\\.$") + $tls : TlsActivity(this after[0s,10s] $dnsReply) + + exists( ARecord($address : getAddress(), + $address!.getHostAddress() == $tls.getServerHello().getSourceAddress().getHostAddress()) + from $dnsReply.getAnswerRecords() + or + AAAARecord( $address : getAddress(), + $address!.getHostAddress() == $tls.getServerHello().getSourceAddress().getHostAddress()) + from $dnsReply.getAnswerRecords() + ) +then + SpiderOakActivity spiderOakActivity = new SpiderOakActivity(); + spiderOakActivity.setDnsAnswer($dnsReply); + spiderOakActivity.setClientAddress($tls.getClientHello().getSourceSocketAddress()); + spiderOakActivity.setServerAddress($tls.getServerHello().getSourceSocketAddress()); + spiderOakActivity.setAssociatedTlsActivity($tls); + + spiderOakActivity.replaceActivity($dnsReply); + spiderOakActivity.replaceActivity($tls); + + insert(spiderOakActivity); +end diff --git a/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/09.Application.Skype.drl b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/09.Application.Skype.drl new file mode 100644 index 0000000..6936ed0 --- /dev/null +++ b/src/main/resources/DefaultKnowledgeBase/at.jku.fim.rubanetra.drools.rules/09.Application.Skype.drl @@ -0,0 +1,114 @@ +/** + * 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 . + */ +import at.jku.fim.rubanetra.protocol.activity.*; +import at.jku.fim.rubanetra.protocol.activity.tls.*; +import at.jku.fim.rubanetra.protocol.activity.http.*; +import at.jku.fim.rubanetra.protocol.activity.ip.*; +import at.jku.fim.rubanetra.protocol.activity.icmp.*; +import at.jku.fim.rubanetra.protocol.activity.dns.*; +import at.jku.fim.rubanetra.protocol.activity.tcp.*; +import at.jku.fim.rubanetra.protocol.activity.udp.*; +import at.jku.fim.rubanetra.protocol.activity.skype.*; +import at.jku.fim.rubanetra.protocol.activity.DroolsBaseActivity; +import java.util.SortedSet; +import java.util.TreeSet; +import org.xbill.DNS.Record; +import java.net.InetSocketAddress +import java.util.List; +import java.util.Set +import java.util.HashSet +import org.jnetpcap.protocol.tcpip.Udp; + +// using the MVEL expression language, see http://mvel.codehaus.org/ +dialect "mvel" + +/** + * A logger that may be used for logging custom messages + */ +global org.slf4j.Logger log; + +// forward declaration +declare DroolsBaseActivity end + +/** + * Represents a Skype payload of arbitrary type, consisting of an source/destination object id and hosts. + */ +declare SkypePayloadActivity extends DroolsBaseActivity + @role( event ) + @timestamp( getStartTimestamp() ) + + sourceObjectId : int + destinationObjectId : int + + sourceHost : InetSocketAddress + destinationHost : InetSocketAddress +end + +/** + * This rule is based on a crude heuristic which is again partially based on: https://github.com/matthiasbock/OpenSkype. + * Skype traffic usually consists of Udp-packets containing a certain kind of object id, therefore those special packets + * have to be matched first. + * This rule should be disabled/removed/improved if it causes false-positives (to reduce the negative impact, this + * rule does not replace any Activities, but extends them instead). + * Possible enhancements include: + * - Use Dns-matches to obtain the skype hosts, if possible (see Dropbox/Spideroak examples) + * - Extend the SkypePayloadActivity according to the known metadata (see https://github.com/matthiasbock/OpenSkype) + */ +rule "Skype Payload (one way, two matches)" +no-loop + when + $udp : UdpActivity( $objectId : SkypeActivityHelper.objectId(udp), SkypeActivityHelper.hasSkypePayload(udp)) + $udpResp : UdpActivity( $objectIdResp : SkypeActivityHelper.objectId(udp), + SkypeActivityHelper.hasSkypePayload(udp), + sourceSocketAddress==$udp.destinationSocketAddress, + destinationSocketAddress==$udp.sourceSocketAddress, + this after[0s,10s] $udp) + exists( UdpActivity($oid : SkypeActivityHelper.objectId(udp), + ($objectId + 10) > $oid, + $oid > $objectId, + SkypeActivityHelper.hasSkypePayload(udp), + sourceSocketAddress==$udp.sourceSocketAddress, + destinationSocketAddress==$udp.destinationSocketAddress, + this after[0s,10s] $udp) ) + exists( UdpActivity($oid : SkypeActivityHelper.objectId(udp), + ($objectIdResp + 10) > $oid, + $oid > $objectIdResp, + SkypeActivityHelper.hasSkypePayload(udp), + sourceSocketAddress==$udpResp.sourceSocketAddress, + destinationSocketAddress==$udpResp.destinationSocketAddress, + this after[0s,10s] $udpResp) ) + + not ( exists UdpActivity( SkypeActivityHelper.objectId(udp)<$objectId, + SkypeActivityHelper.hasSkypePayload(udp), + sourceSocketAddress==$udp.sourceSocketAddress, + destinationSocketAddress==$udp.destinationSocketAddress, + this after[10s] $udp)) + not ( exists UdpActivity( SkypeActivityHelper.objectId(udp)<$objectIdResp, + SkypeActivityHelper.hasSkypePayload(udp), + sourceSocketAddress==$udpResp.sourceSocketAddress, + destinationSocketAddress==$udpResp.destinationSocketAddress, + this after[10s] $udpResp)) + not ( exists SkypePayloadActivity(sourceObjectId==$objectId || sourceObjectId==$objectIdResp + || destinationObjectId==$objectId || destinationObjectId==$objectIdResp)) + then + SkypePayloadActivity act = new SkypePayloadActivity(); + act.setSourceObjectId($objectId); act.setDestinationObjectId($objectIdResp); + act.setSourceHost($udp.getSourceSocketAddress()); act.setDestinationHost($udp.getDestinationSocketAddress()); + act.extendActivity($udp); act.extendActivity($udpResp); + insert(act); +end diff --git a/src/main/resources/META-INF/kmodule.xml b/src/main/resources/META-INF/kmodule.xml new file mode 100644 index 0000000..6c5ded2 --- /dev/null +++ b/src/main/resources/META-INF/kmodule.xml @@ -0,0 +1,33 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/1.0.0/kraken-pcap-pom-1.0.0.pom b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/1.0.0/kraken-pcap-pom-1.0.0.pom new file mode 100644 index 0000000..e7595c0 --- /dev/null +++ b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/1.0.0/kraken-pcap-pom-1.0.0.pom @@ -0,0 +1,207 @@ + + + + 4.0.0 + + Kraken Project + http://krakenapps.org + + org.krakenapps + 1.0.0 + kraken + Kraken Parent POM + pom + + fusioncharts-data-service + kraken-api + kraken-ahocorasick + kraken-core + kraken-cron + kraken-csv-servlet + kraken-dns + kraken-filter + kraken-http + kraken-ipojo + kraken-jpa + kraken-json-servlet + kraken-json + kraken-mac-lookup + kraken-pcap + kraken-rrd + kraken-rss + kraken-snmp + kraken-syslog + kraken-text-servlet + kraken-xml-servlet + kraken-xmlrpc-servlet + kraken-xmlrpc + kraken-bloomfilter + kraken-http-decoder + kraken-msn-decoder + kraken-pop3-decoder + kraken-smtp-decoder + kraken-snmp-decoder + kraken-ftp-decoder + kraken-telnet-decoder + kraken-mail + kraken-query-browser + kraken-sonar + kraken-rpc + kraken-dhcp-decoder + kraken-codec + kraken-arpwatch + kraken-winapi + kraken-fluxmon + kraken-geoip + kraken-mime + kraken-ca + kraken-jython + kraken-sentry + kraken-base + kraken-datasource + kraken-util + kraken-portmon + kraken-smb-decoder + kraken-windows-sentry + kraken-log-api + kraken-birt + kraken-netbios-decoder + kraken-sql-parser + kraken-bnf + kraken-syslog-parser + kraken-stormbringer + kraken-webconsole + kraken-msgbus + kraken-proxy + kraken-linux-api + kraken-opencsv + kraken-linux-sentry + kraken-maldomain + kraken-logfile-parser + kraken-logstorage + kraken-iptables + kraken-firewall-api + kraken-event-api + kraken-siem + kraken-dom + kraken-http-rule + kraken-rule + kraken-util-directoryfile + kraken-tftp + kraken-btree + kraken-dcerpc + kraken-tftp-decoder + kraken-ldap + kraken-filemon + kraken-ftp + kraken-isc-api + kraken-ntp + kraken-ipmanager + kraken-dhcp + kraken-captive-portal + kraken-radius + kraken-grid + kraken-logdb-client + kraken-logdb + kraken-confdb + kraken-snmpmon + + http://krakenapps.org + 2008 + + scm:svn:ssh://krakenapps.org/kraken + + scm:svn:ssh://krakenapps.org/kraken + + http://krakenapps.org/browser + + Kraken is a enterprise-class open source monitoring + framework. + + + + Apache Software License 2 + http://krakenapps.org/wiki/License + repo + + + + + krakenapps + KrakenApps Maven Repository + default + http://download.krakenapps.org/ + + true + + + + + + krakenapps + Kraken Apps + scp://krakenapps.org/home/maven + + + + + + org.krakenapps + kraken-api + 1.7.0 + + + + junit + junit + 4.8.1 + test + + + + + + + junit + junit + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + UTF-8 + 1.6 + 1.6 + true + true + true + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + + + org.apache.maven.wagon + wagon-ssh + 1.0-beta-7 + + + + \ No newline at end of file diff --git a/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/1.0.0/kraken-pcap-pom-1.0.0.pom.md5 b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/1.0.0/kraken-pcap-pom-1.0.0.pom.md5 new file mode 100644 index 0000000..b3e3565 --- /dev/null +++ b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/1.0.0/kraken-pcap-pom-1.0.0.pom.md5 @@ -0,0 +1 @@ +0037c4ff2b23e26bcf4fbb6851d3ee52 \ No newline at end of file diff --git a/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/1.0.0/kraken-pcap-pom-1.0.0.pom.sha1 b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/1.0.0/kraken-pcap-pom-1.0.0.pom.sha1 new file mode 100644 index 0000000..ac40f54 --- /dev/null +++ b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/1.0.0/kraken-pcap-pom-1.0.0.pom.sha1 @@ -0,0 +1 @@ +fc1b5c7de418f917daa190d3ac00e709bb430cbf \ No newline at end of file diff --git a/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/maven-metadata-local.xml b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/maven-metadata-local.xml new file mode 100644 index 0000000..b5a074a --- /dev/null +++ b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/maven-metadata-local.xml @@ -0,0 +1,12 @@ + + + org.krakenapps + kraken-pcap-pom + + 1.0.0 + + 1.0.0 + + 20140121195608 + + diff --git a/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/maven-metadata-local.xml.md5 b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/maven-metadata-local.xml.md5 new file mode 100644 index 0000000..1343f48 --- /dev/null +++ b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/maven-metadata-local.xml.md5 @@ -0,0 +1 @@ +88712d8fba761a31e137d9d79cb132d6 \ No newline at end of file diff --git a/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/maven-metadata-local.xml.sha1 b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/maven-metadata-local.xml.sha1 new file mode 100644 index 0000000..ff800f4 --- /dev/null +++ b/src/main/resources/kraken-workaround-repository/org/krakenapps/kraken-pcap-pom/maven-metadata-local.xml.sha1 @@ -0,0 +1 @@ +73ce722aa7b1035f1c542d9cdc57b3a2be0b117c \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..5ca984a --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,54 @@ + + + + + System.err + + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5p - %m%n + + + ${logLevel} + + + + + true + ${logDirectory}/rubanetra.log + + %date %level [%thread] [%file:%line] - %msg%n + + + ${logLevel} + + + 5 + ${logDirectory}/rubanetra.log.%i + + + 10MB + + + + + + + + diff --git a/src/main/resources/rubanetra.conf b/src/main/resources/rubanetra.conf new file mode 100644 index 0000000..b3b539c --- /dev/null +++ b/src/main/resources/rubanetra.conf @@ -0,0 +1,471 @@ +/** + * 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 . + */ +/** + * This file serves as the Rubanetra configuration entry point and will be looked up by the main executable jar. + * Therefore this file must be either directly available via classpath entry, or the file-path has to be passed via + * command line argument (for further details refer to the README file). + * + * While this file must contain all configuration sections, i.e. 'general', 'protocols', 'input' and 'output' + * at once, one may prefer to split certain dynamically changing configuration sections into separate and therefore + * replaceable files. However, please note that the general section must reside in a statically known location to the + * Rubanetra executable and the paths to the dynamically changed files must be defined in the appropriate sections. + * + * Since all configuration files will be parsed by ANTLRv4, the corresponding grammar defining the exact syntax + * is available in the source archive, see 'src/main/antlr4/.../RubanetraSystemConfiguration.g4'. + */ + +/** + * ######################### + * # General Configuration # + * ######################### + */ +general { + /** + * Defines the base directory containing the Drools knowledge-base configuration. + * Currently this directory must contain: + * - 'META-INF' as subdirectory, containing: + * ~ 'kmodule.xml', the Drools configuration file, i.e. 'META-INF/kmodule.xml' + * ~ the subsequent Apache Maven configuration structure, i.e.: + * + 'maven/at.jku.fim/rubanetra/' sub-directories + * + 'maven/at.jku.fim/rubanetra/pom.xml' the project's Maven configuration file + * + 'maven/at.jku.fim/rubanetra/pom.properties' Maven-generated properties + * + * If this setting is changed, the default 'META-INF' directory should be removed either from the classpath + * or directly from the configuration directory (since this directory is by default in the classpath). + * + * Default value "${config.directory}", this setting is mandatory. + */ + drools_configuration_directory = "${config.directory}"; + + /** + * Defines the name of the Drools knowledge base to use for the reasoning process. + * This knowledge base name must be listed in the Drools knowledge base descriptor file 'kmodule.xml'. + * If this setting is not specified the default knowledge base as specified in the Drools descriptor file will + * be compiled and used. + * + * Default value "${droolsKnowledgeBase}", this setting is optional. + */ + drools_base_model_name = "${droolsKnowledgeBase}"; + + /** + * Defines the name of the Drools session to use for the reasoning process. + * This session name must be listed in the Drools knowledge base descriptor file 'kmodule.xml' as session entry + * under the specified (or the default) 'drools_base_model_name'. + * If this setting is not specified the default session name as specified in the Drools descriptor file will be + * used instead. + * + * Default value "${droolsSessionName}", this setting is optional. + */ + drools_session_model_name = "${droolsSessionName}"; +}; + +/** + * ########################## + * # Protocol Configuration # + * # (Application Layer) # + * ########################## + * + * This section should be filled with application layer specific protocol settings, i.e. underlying lower layer + * protocol parser bindings and potential port filters, if applicable. The listed application layer parser settings + * also serve as a vital tool of directing the output generation engine. By default, any parser output below the + * application layer will be suppressed due to verboseness, however, this behaviour may be overturned by appropriate + * rule definitions inside the used Knowledge Base. For further information on how to achieve this, please refer to + * the documentation of Activity#setExcludedFromOutput(boolean). + * Additional Notes: An application layer parser will only produce output if all of the following conditions are met: + * - A protocol decoder pipeline has been setup, including all lower layer protocols, + * e.g.: L2 -> L3 -> L4 -> + * - The destination port restriction may not be 'None' and has to include the relevant port(s). + * - The PCAP file actually contains relevant packets applicable to and defined port(s). + * + * Furthermore, it is recommended to specify one protocol identifier per application layer protocol parser, however, + * remember that there must be a 1:1 mapping between a transport layer parser and an application layer parser, therefore + * the following example will not work: + * [HTTPandDNSoverTCP]: + * port = ALL; + * protocol_binding = Ethernet -> Ipv4; + * protocol_binding = Ipv4 -> Tcp; + * protocol_binding = Tcp -> Http; + * protocol_binding = Tcp -> Dns; + * + * In general, the following implementation constraints may be observed: + * - 1:n mapping between Layer1 (Pcap) and Layer2 (link) parsers + * - n:m mapping between Layer2 (link) and Layer3 (IP), Layer3 and Layer4 (transport) parsers + * - 1:1 mapping between Layer4 (transport) and application layer parsers + * + * On the other hand, if extremely fine grained control over the actual PCAP data is required, see the BPF setting + * in the 'input' configuration section. + * + * If the Drools knowledge base contains rules that require certain protocol parsers, those parsers must be referenced + * at least one time in this configuration section. However, rule based parsers must be configured entirely in the + * Drools rule files. + */ +protocols { + /** + * If a 'protocol_configuration_file' setting is specified all remaining protocol specific settings will be looked + * up in the referenced file. This file must exist and be readable for the invoking process. + * Note, however, that there will be no explicit checks against configuration file dereferencing chains, i.e. + * it should be ensured that there is no 'protocol_configuration_file' setting in the referenced file again. + * The referenced file must contain a "protocols {};" section containing the entire protocol specific configuration. + * + * This setting is optional, but if it is specified all remaining protocol specific settings in the + * main configuration file will be ignored. + */ + //protocol_configuration_file = "/path/to/protocol.conf"; + + /** + * An unique protocol id should be defined for each application layer protocol parser that should be used, i.e. + * by default the name of an application layer protocol should suffice. + * Syntax: '[ Protocol_ID ]:', where Protocol_ID represents an unique protocol identifier conforming + * to ([a-zA-Z]+ DIGIT*)+. + * A number of protocol specific settings may be specified subsequently. + * This setting may be repeated multiple times for configuring different protocol parsers. + * + * Constraints: It is currently not defined what will happen in the case of multiple different protocol ids that + * contain exactly the same protocol bindings. Consider for instance: + * [HTTP]: ... as below ... + * [HTTP1]: ... as [HTTP] ... + * + * The rule engine will probably receive double notifications for all HTTP related events in this case and this + * could lead to severe issues during the reasoning process and the corresponding output (two identical frame numbers + * for two different parser instances). + */ + [HTTP]: + /** + * The strategy to use for mapping Kraken's transport layer parsers to the application layer parsers. + * Currently only the destination port strategy has been implemented, i.e. an application layer parser receives + * packets that match the specified destination port number(s) defined by the "port" setting. + * + * Default value "destination_port", this setting is required. + */ + transport_layer_mapping_strategy = destination_port; + + /** + * Restricts the transport layer parser (UDP/TCP) to the specified destination ports and/or port-ranges. + * A similar result could be achieved globally (and more efficiently) via the input BPF filter setting. + * + * Default value "80", this setting is required if the mapping strategy used is "destination_port". + * Exemplary values: + * - ALL or ANY, i.e. do not apply any port based restriction to the parser (matches all ports) + * - NONE, i.e. disable this protocol since no ports will be allowed (matches no ports) + * - 80, i.e. match only packets with destination port 80, any valid port numbers are allowed + * - 80,8080,8081 matches packets with destination port 80 or 8080 or 8081 + * - 80,8080-8088 matches packets with destination port 80 or the destination port range 8080-8088 + * Warning: A setting of ALL should be used with care, as it may cause a library decoder to crash and + * prevent the continued parsing process of valid HTTP data. + */ + port = 80; + + /** + * The "protocol_binding" setting binds an available protocol parser to another protocol parser that is capable + * of decoding the previously "unwrapped/decoded" content. Usually this setting should be used to define + * the network layer decoding pipeline. The lowest network layer parser available is currently a + * layer 2 parser, e.g. ethernet. Layer 1 (basically PCAP-entries) may be implicitly assumed to be always + * provided in decoded form. + * A network layer protocol parser is always identified by the unique protocol identifier that this parser is + * advertising as capable of decoding. Unless custom protocol parsers have been registered, the following parsers + * should be available: + * Ethernet, Arp, + * Ipv4, Ipv6, Icmpv4, Icmpv6, + * Tcp, Udp, + * Telnet, Snmp, Netbios, Dhcp, Pop3, Msn, Ftp, Dns, Smtp, Http + * + * This setting is not required, however, if no bindings are specified no parsers will be setup. + * This setting must be specified multiple times in case of different bindings for the same higher layer protocol + * parser, i.e. the entire network layer stack below the highest defined protocol parser layer must be bound. + * For instance, if the highest network layer protocol specified is TCP (layer 4), a layer 2 parser + * must be bound to layer 3 and a layer 3 parser must be bound to tcp. If the parsers are incompatible or the + * pipeline is not complete, the parser of the highest layer will not receive any decoded data. + * Multiple lower layer parsers leading to a common higher layer parser are nevertheless allowed, e.g. + * ethernet -> ipv4, ethernet -> ipv6, + * ipv4 -> tcp, ipv6 -> tcp, + * tcp -> http + * + * In general, the following implementation constraints may be observed: + * - 1:n mapping between Layer1 (Pcap) and Layer2 (link) parsers + * - n:m mapping between Layer2 (link) and Layer3 (IP), Layer3 and Layer4 (transport) parsers + * - 1:1 mapping between Layer4 (transport) and application layer parsers + * + * Note: Not all theoretically possible bindings are implemented, e.g. a binding from ethernet -> http will + * cause a runtime exception because the Http-parser handles decoded TCP/IP-data only. + * It is also discouraged to bind a higher layer parser to a lower layer, e.g. http -> tcp, since this will + * depend solely on the individual parser implementation on how this case is handled and should therefore + * be avoided. + */ + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Http; + + /** + * Example of a possible DNS protocol parser pipeline setup. Note that larger DNS messages are sent via + * the TCP transport layer instead of UDP. This pipeline is capable of handling Ethernet, IPv4/IPv6, UDP/TCP and + * the DNS parsers. however, the TCP -> DNS parser is currently considered experimental. + */ + [DNS]: + transport_layer_mapping_strategy = destination_port; + port = Any; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv4 -> Udp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Ipv6 -> Udp; + protocol_binding = Tcp -> Dns; + protocol_binding = Udp -> Dns; + + /** + * Exemplary SNMP v1/v2 Pipeline configuration. + * (default: disabled) + */ + [SNMPv1v2]: + transport_layer_mapping_strategy = destination_port; + port = None; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Udp; + protocol_binding = Ipv6 -> Udp; + protocol_binding = Udp -> Snmp; + + /** + * Exemplary DHCP Pipeline configuration. + * (default: enabled for port 67,68) + */ + [DHCP]: + transport_layer_mapping_strategy = destination_port; + port = 67,68; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Udp; + protocol_binding = Ipv6 -> Udp; + protocol_binding = Udp -> Dhcp; + + /** + * Exemplary Netbios Pipeline configuration. + * (default: disabled) + */ + [Netbios]: + transport_layer_mapping_strategy = destination_port; + port = None; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Udp; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Udp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Udp -> Netbios; + protocol_binding = Tcp -> Netbios; + + /** + * Exemplary Msn Pipeline configuration. + * (default: disabled) + */ + [MSN]: + transport_layer_mapping_strategy = destination_port; + port = None; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Msn; + + /** + * Exemplary Ftp Pipeline configuration. + * (default: disabled) + */ + [FTP]: + transport_layer_mapping_strategy = destination_port; + port = None; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Ftp; + + /** + * Exemplary Pop3 Pipeline configuration. + * (default: enabled for ports 110, 995) + */ + [Pop3]: + transport_layer_mapping_strategy = destination_port; + port = 110, 995; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Pop3; + + /** + * Exemplary Telnet Pipeline configuration. + * (default: enabled for port 23) + */ + [Telnet]: + transport_layer_mapping_strategy = destination_port; + port = 23; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Telnet; + + /** + * Exemplary Smtp Pipeline configuration. + * (default: enabled for ports 25, 587, 465) + */ + [SMTP]: + transport_layer_mapping_strategy = destination_port; + port = 25, 587, 465; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Tcp; + protocol_binding = Ipv6 -> Tcp; + protocol_binding = Tcp -> Smtp; + + /** + * Exemplary ICMPv4/v6 Pipeline configuration. + * (default: enabled, a port based restriction is not possible) + */ + [ICMP]: + transport_layer_mapping_strategy = destination_port; + port = None; + protocol_binding = Ethernet -> Ipv4; + protocol_binding = Ethernet -> Ipv6; + protocol_binding = Ipv4 -> Icmpv4; + protocol_binding = Ipv6 -> Icmpv6; +}; + +/** + * ####################### + * # Input Configuration # + * ####################### + */ +input { + /** + * If a 'input_configuration_file' setting is specified, all remaining input specific settings will be looked + * up in the referenced file. This file must exist and be readable for the invoking process. + * Note, however, that there will be no explicit checks against configuration file dereferencing chains, i.e. + * it should be ensured that there is no 'input_configuration_file' setting in the referenced file again. + * The referenced file must contain a "input {};" section containing the entire input specific configuration. + * + * This setting is optional, but if it is specified all remaining input specific settings in the + * main configuration file will be ignored. + */ + //input_configuration_file = "path/to/input.conf"; + + /** + * The path to the input files to parse. All specified files must adhere to the format specified by + * the "input_format" setting. + * + * This setting is required, syntax (curly braces indicate arbitrary repetitions and must not be included): + * input_file = "/path/to/file1" {, "/path/to/another/file"}; + * This setting may be specified multiple times, all occurrences will be processed. + * + * Notes: Input files that were specified by using the command line interface will not replace the input_file + * specifications of this section, i.e. all sources will be combined and processed. + */ + //input_file = "path/to/input/file"; + + /** + * The format of the specified input files. + * Currently only a ${fnaInputFormat} parser has been implemented. + * + * This setting is required. + */ + input_format = ${fnaInputFormat}; + + /** + * A Berkeley Packet Filter string to facilitate an efficient way to filter the entire PCAP-Stream before it is + * passed to the parsers. This string will be compiled and applied by the native PCAP-decoding library by the means + * of JNetPcap. + * + * This setting is optional. + * Syntax definition: . + */ + bpf_filter = ""; + + /** + * The Berkeley Packet Filter optimization flag. + * This boolean value will be passed along the bpf_netmask and the bpf_filter string to the native PCAP decoding + * library and indicates whether or not the bpf_filter string should be optimized by the compiler. + * + * This setting is optional, default value = false. + */ + bpf_optimize = false; + + /** + * If this setting is set to true, all specified input files will be opened and the first content entry will be + * parsed respectively, i.e. the timestamp of the first entry in each file will be analyzed and compared. + * The File-Handler will then try to sort all files chronologically according to this timestamp, so that + * the "real" parsing process provides all packet capture entries in the original order (the oldest entry will + * be parsed first). + * Because this process relies only on the first timestamp of each file, it cannot handle overlapping + * time-intervals. + * + * This setting is optional, default value: false + * Possible values: + * - false, i.e. parse in the order the files were specified in the configuration itself. + * - true, try to sort all files chronologically according to the timestamp of their first network capture entry. + */ + sort_by_first_timestamp = false; +}; + +/** + * ######################## + * # Output Configuration # + * ######################## + */ +output { + /** + * If a 'output_configuration_file' setting is specified, all remaining output specific settings will be looked + * up in the referenced file. This file must exist and be readable for the invoking process. + * Note, however, that there will be no explicit checks against configuration file dereferencing chains, i.e. + * it should be ensured that there is no 'output_configuration_file' setting in the referenced file again. + * The referenced file must contain a "output {};" section containing the entire output specific configuration. + * + * This setting is optional, but if it is specified all remaining output specific settings in the + * main configuration file will be ignored. + */ + //output_configuration_file = "path/to/output.conf"; + + /** + * The file descriptor to use for writing the derived information to. The information will be transformed + * according to the specified output_format before it is written to the output-stream. + * + * This setting is required, default value: ${fnaOutputFile}. + * The file or stream must be writable by the invoking process. + * Possible values: + * - STDOUT, the standard output stream + * - "path/to/a/file", a file-path + */ + output_file = ${fnaOutputFile}; + + /** + * The output format that is used to transform the derived information to before writing it to "output_file". + * + * This setting is required, default value: ${fnaOutputFormat} + * Possible values: + * - plaso, a format that can be parsed by the provided Plaso specific parser (currently XML) + * - xml, however, without a schema definition + * - json + * - csv, generic/limited comma separated value content will be produced + * If extended output for certain activities is desired, a custom CSV schema has to be provided first. + * - nop, does not write anything to "output_file". + * - callback, as 'nop', mainly interesting for developers/testing. + */ + output_format = ${fnaOutputFormat}; +}; \ No newline at end of file