├── .gitignore ├── .travis.yml ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── LICENSE ├── Makefile.am ├── NEWS ├── README ├── README.md ├── autogen.sh ├── config.h.in ├── configure.ac ├── doc ├── Makefile ├── make.bat └── source │ ├── command-line-options.rst │ ├── conf.py │ ├── console-output.rst │ ├── core.rst │ ├── getting-help.rst │ ├── index.rst │ ├── install.rst │ ├── output.rst │ ├── starting-meer.rst │ └── what-is-meer.rst ├── etc └── meer.yaml ├── extra └── build-test │ └── build-test.sh ├── screenshots └── discord.png ├── src ├── Makefile.am ├── calculate-stats.c ├── calculate-stats.h ├── config-yaml.c ├── config-yaml.h ├── counters.c ├── counters.h ├── daemonize.c ├── daemonize.h ├── decode-json.c ├── decode-json.h ├── decode-output-json-client-stats.c ├── decode-output-json-client-stats.h ├── geoip.c ├── geoip.h ├── get-dns.c ├── get-dns.h ├── get-fingerprint.c ├── get-fingerprint.h ├── get-geoip.c ├── get-geoip.h ├── get-oui.c ├── get-oui.h ├── input-plugins │ ├── commandline.c │ ├── commandline.h │ ├── file.c │ ├── file.h │ ├── redis.c │ └── redis.h ├── lockfile.c ├── lockfile.h ├── meer-def.h ├── meer.c ├── meer.h ├── ndp-collector.c ├── ndp-collector.h ├── oui.c ├── oui.h ├── output-plugins │ ├── bluedot.c │ ├── bluedot.h │ ├── elasticsearch.c │ ├── elasticsearch.h │ ├── external.c │ ├── external.h │ ├── file.c │ ├── file.h │ ├── pipe.c │ ├── pipe.h │ ├── redis.c │ ├── redis.h │ ├── syslog.c │ └── syslog.h ├── output.c ├── output.h ├── stats.c ├── stats.h ├── usage.c ├── usage.h ├── util-base64.c ├── util-base64.h ├── util-dns.c ├── util-dns.h ├── util-md5.c ├── util-md5.h ├── util-signal.c ├── util-signal.h ├── util-strlcat.c ├── util-strlcpy.c ├── util.c ├── util.h ├── version.h ├── waldo.c └── waldo.h ├── stamp-h1 └── tools ├── external ├── external-program-blocklist │ ├── README.md │ ├── blocklist.cgi │ ├── blocklist.sql │ ├── blocklister.j2 │ ├── blocklister_cron.j2 │ └── external-program-sql-blocklist.j2 ├── external-program-http-get └── external-program-iptables └── reference_handler ├── README.md ├── reference_data.sql └── reference_sources.conf /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Default parameters, even this default build is excluded in the build 2 | # matrix below. We define so Travis doesn't think this is a Ruby 3 | # project. 4 | os: linux 5 | language: c 6 | compiler: gcc 7 | 8 | # Define the default CFLAGS used by all builds as a YAML anchor. 9 | default-cflags: &default-cflags 10 | CFLAGS="-Wall -Wno-unused-parameter -Wno-unused-function" 11 | #CFLAGS="-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-function" 12 | 13 | # The default build is Linux with gcc. Add additional builds to the 14 | # matrix here. 15 | matrix: 16 | # Exclude the default build so any the builds in the matrix will be done. 17 | exclude: 18 | - os: linux 19 | compiler: gcc 20 | include: 21 | # Linux, gcc, tests enabled. 22 | - os: linux 23 | compiler: gcc 24 | env: 25 | - NAME="linux,gcc" 26 | - *default-cflags 27 | # Linux, clang. For this build we'll also enable -Wshadow. 28 | - os: linux 29 | compiler: clang 30 | env: 31 | - NAME="linux,clang" 32 | - *default-cflags 33 | - EXTRA_CFLAGS="-Wshadow" 34 | 35 | # Change this to your needs 36 | script: 37 | - ./autogen.sh 38 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then 39 | ./configure || { echo "!!!! ERROR !!!!"; cat config.log && false; } 40 | fi 41 | - make 42 | 43 | before_install: 44 | - | 45 | if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then 46 | 47 | sudo apt-get update -qq 48 | sudo apt-get install -y libjson-c-dev libyaml-dev \ 49 | build-essential autoconf automake libyaml-0-2 pkg-config libhiredis-dev 50 | fi 51 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quadrantsec/meer/68362cac477f9fe6d8d3662aed245239c0c65725/AUTHORS -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | Release v2.0.0 [2021/XX/XX] 2 | 3 | Same as v1.0.0, but with SQL removed. 4 | 5 | Release v1.0.0 [2021/11/29] 6 | 7 | Inital release of version 1.0 of Meer! 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPIONS=foreign no-dependencies subdir-objects 2 | ACLOCAL_AMFLAGS = 3 | SUBDIRS = src 4 | 5 | #INCLUDES = @INCLUDES@ 6 | 7 | install-data-local: 8 | test -z "$(DESTDIR)$(sysconfdir)" || /bin/mkdir -p "$(DESTDIR)$(sysconfdir)" 9 | test -f "$(DESTDIR)$(sysconfdir)/meer.yaml" || $(INSTALL_DATA) etc/meer.yaml "$(DESTDIR)$(sysconfdir)/meer.yaml" 10 | test -z "$(DESTDIR)$(bindir)" || /bin/mkdir -p "$(DESTDIR)$(bindir)" 11 | $(INSTALL) -m 755 src/meer "$(DESTDIR)$(bindir)/meer" 12 | @echo "" 13 | @echo "------------------------------------------------------------------------------" 14 | @echo "Meer has been installed!" 15 | @echo "------------------------------------------------------------------------------" 16 | @echo "" 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quadrantsec/meer/68362cac477f9fe6d8d3662aed245239c0c65725/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | 3 | See README.md 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
 2 | @@@@@@@@@@  @@@@@@@@ @@@@@@@@ @@@@@@@    
 3 | @@! @@! @@! @@!      @@!      @@!  @@@   Quadrant Information Security
 4 | @!! !!@ @!@ @!!!:!   @!!!:!   @!@!!@a    https://quadrantsec.com
 5 | !!:     !!: !!:      !!:      !!: :!a    Copyright (C) 2018-2023
 6 | :      :   : :: ::  : :: ::   :   : :
 7 | 
8 | 9 | # Join the Meer Discord channel 10 | 11 | [![Discord](./screenshots/discord.png)](https://discord.gg/VS6jTjH4gW) 12 | 13 | # Meer Documentation 14 | 15 | Meer "Read The Docs! https://meer.readthedocs.io 16 | 17 | # What is “Meer”. 18 | 19 | "Meer" is a dedicated data broker for the `Suricata `_ IDS/IPS systems and the `Sagan ` log analysis engine. 20 | 21 | Meer takes EVE data (JSON) from Suricata or Sagan (via an ``input-plugin``), augments it by enriching it 22 | with DNS, GeoIP, and other information (via the ``meer-core``), and then pushes the data to a database (via a ``output-plugin``) of your choice. 23 | 24 | Meer is written in C which makes it fast and very light weight. This makes is suitable for processing data on systems with limited resource. 25 | 26 | Meer ``input-plugins`` that are currently supported are Suricata/Sagan EVE ("spool") files and Redis. 27 | 28 | Meer ``output-plugins`` that are currently supported are Elasticsearch, Opensearch, Zincsearch 29 | (https://github.com/zinclabs/zinc), Redis, named pipes, files, and "external" programs. Meer release 1.0.0 30 | supports SQL (MariaDB, MySQL and PostgreSQL) that is compatible with older "Barnyard2" systems. Meer versions 31 | _after_ 1.0.0 do _not_ support SQL. 32 | 33 | # Input Plugins 34 | 35 | * file - Meer can read ("follow") data files generated by Suricata or Sagan 36 | 37 | * Redis - Meer can connect to and read data via a Redis PUB/SUB. 38 | 39 | # Output Plugins: 40 | 41 | * Redis - Meer can write store data to a Redis database similar to Suricata (list/lpush, rpush, channel/publish or set). 42 | 43 | * "elasticsearch" support - This allows Meer to write Sagan & Suricata EVE (JSON) data to Elasticsearch search. 44 | 45 | * "external" support - This allows you to call your own program. When an event happens and if the signature specifies the option, Meer will 'call' your program. The EVE/JSON is handed to your program via stdin. This can be useful to build custom firewall routines, customer reactions to events, custom ways to store data, etc. 46 | 47 | * "pipe" support - This allows Meer to write EVE/JSON data to a Unix "named pipe" or FIFO. Meer acts as a pipe "writer" and you can have a consumer (reader) on the other side of the "pipe". For example, you might use a program like "Sagan" (https://sagan.io) to analyze the data received via a named pipe. 48 | 49 | # Current Features: 50 | 51 | * Meer can "enrich" EVE/JSON data! For example, Meer can add DNS records, do OUI (hardware manufacturer) on MAC addresses, add GeoIP data and more! 52 | * Meer is written in C and has a very small memory footprint (only several meg of RAM). It also CPU efficient. 53 | * Fast startup times (under one second). 54 | * Simple command line and configuration syntax. Meer uses a YAML configurations similar to Suricata and Sagan. 55 | * Out of the box IPv6 support. 56 | * Meer can do reverse DNS/PTR record lookups. Meer has an internal DNS cache system so to not overburden DNS servers with repeated queries. 57 | * Supports "fingerprint" rule set. These are special Suricata & Sagan signatures that allow you to collect data about devices in your network and store them in a Redis database. See https://github.com/quadrantsec/fingerprint-rules for more information. 58 | * Supports "client stats" for Meer when injecting Sagan EVE/JSON data. This allows give you statistics about who and what is sending Sagan data within an environment. 59 | * Meer can generated "non-repetitive" data which can be useful for fast Indicator of Compromise (IoC) searches. This is known as "Network Data Points" or NDP. 60 | 61 | # Future "output" support: 62 | 63 | Meer is under development. This is our brief "road-map" of what we would like to see Meer do. If 64 | you have any ideas or requests, please let us know via our "issues" page (https://github.com/quadrantsec/meer/issues). 65 | 66 | * Syslog support (JSON, decoded, etc). 67 | 68 | # Support: 69 | 70 | * Need help getting started or looking for documentation? Go to https://meer.readthedocs.org ! 71 | 72 | * Have a question or comment about Meer? Please post to the Meer mailing at https://groups.google.com/forum/#!forum/meer-users. You can also visit the Sagan/Meer Discord channel by going to https://discord.gg/VS6jTjH4gW 73 | 74 | * If you need to report a bug, please post that in our Github "issues" page. That is at https://github.com/quadrantsec/meer/issues 75 | 76 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This generates Makefiles, ./configure, etc. 4 | 5 | autoreconf -vfi 6 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = source 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /doc/source/command-line-options.rst: -------------------------------------------------------------------------------- 1 | Command Line Options 2 | ==================== 3 | 4 | The majority of controls for Meer are within the ``meer.yaml`` file. 5 | 6 | .. option:: -d, --daemon 7 | 8 | This option tells Meer to fork to the background. 9 | 10 | .. option:: -c, --config 11 | 12 | This option tells what configuration file to use. By default Meer uses ``/usr/local/etc/meer.yaml``. 13 | 14 | .. option:: -h, --help 15 | 16 | The Meer help screen. 17 | 18 | .. option:: -q, --quiet 19 | 20 | This option to tells Meer to not output to the console. Logs are still sent to the /var/log/meer directory. 21 | 22 | .. option:: -q, --file 23 | 24 | This option bypasses the meer.yaml 'input-type' option and reads in files from the command line. Gzip compressed files can be read if Meer is compiled with GZIP support. If specifying multiple files, make sure to enclose your options with quotes (for example, --file "/var/log/suricata/*.gz") 25 | 26 | -------------------------------------------------------------------------------- /doc/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/master/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | # import os 16 | # import sys 17 | # sys.path.insert(0, os.path.abspath('.')) 18 | 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = u'Meer User Guide' 23 | copyright = u'2018,2019 Champ Clark III' 24 | author = u'Champ Clark III' 25 | 26 | # The short X.Y version 27 | version = u'' 28 | # The full version, including alpha/beta/rc tags 29 | release = u'0.0.3' 30 | 31 | 32 | # -- General configuration --------------------------------------------------- 33 | 34 | # If your documentation needs a minimal Sphinx version, state it here. 35 | # 36 | # needs_sphinx = '1.0' 37 | 38 | # Add any Sphinx extension module names here, as strings. They can be 39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 40 | # ones. 41 | extensions = [ 42 | 'sphinx.ext.autodoc', 43 | 'sphinx.ext.doctest', 44 | 'sphinx.ext.intersphinx', 45 | 'sphinx.ext.todo', 46 | 'sphinx.ext.coverage', 47 | 'sphinx.ext.mathjax', 48 | 'sphinx.ext.ifconfig', 49 | 'sphinx.ext.viewcode', 50 | 'sphinx.ext.githubpages', 51 | ] 52 | 53 | # Add any paths that contain templates here, relative to this directory. 54 | templates_path = ['_templates'] 55 | 56 | # The suffix(es) of source filenames. 57 | # You can specify multiple suffix as a list of string: 58 | # 59 | # source_suffix = ['.rst', '.md'] 60 | source_suffix = '.rst' 61 | 62 | # The master toctree document. 63 | master_doc = 'index' 64 | 65 | # The language for content autogenerated by Sphinx. Refer to documentation 66 | # for a list of supported languages. 67 | # 68 | # This is also used if you do content translation via gettext catalogs. 69 | # Usually you set "language" from the command line for these cases. 70 | language = None 71 | 72 | # List of patterns, relative to source directory, that match files and 73 | # directories to ignore when looking for source files. 74 | # This pattern also affects html_static_path and html_extra_path. 75 | exclude_patterns = [] 76 | 77 | # The name of the Pygments (syntax highlighting) style to use. 78 | pygments_style = None 79 | 80 | 81 | # -- Options for HTML output ------------------------------------------------- 82 | 83 | # The theme to use for HTML and HTML Help pages. See the documentation for 84 | # a list of builtin themes. 85 | # 86 | #html_theme = 'alabaster' 87 | #html_theme = 'default' 88 | html_theme = 'sphinx_rtd_theme' 89 | 90 | # Theme options are theme-specific and customize the look and feel of a theme 91 | # further. For a list of options available for each theme, see the 92 | # documentation. 93 | # 94 | # html_theme_options = {} 95 | 96 | # Add any paths that contain custom static files (such as style sheets) here, 97 | # relative to this directory. They are copied after the builtin static files, 98 | # so a file named "default.css" will overwrite the builtin "default.css". 99 | html_static_path = ['_static'] 100 | 101 | # Custom sidebar templates, must be a dictionary that maps document names 102 | # to template names. 103 | # 104 | # The default sidebars (for documents that don't match any pattern) are 105 | # defined by theme itself. Builtin themes are using these templates by 106 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 107 | # 'searchbox.html']``. 108 | # 109 | # html_sidebars = {} 110 | 111 | 112 | # -- Options for HTMLHelp output --------------------------------------------- 113 | 114 | # Output file base name for HTML help builder. 115 | htmlhelp_basename = 'MeerUserGuidedoc' 116 | 117 | 118 | # -- Options for LaTeX output ------------------------------------------------ 119 | 120 | latex_elements = { 121 | # The paper size ('letterpaper' or 'a4paper'). 122 | # 123 | # 'papersize': 'letterpaper', 124 | 125 | # The font size ('10pt', '11pt' or '12pt'). 126 | # 127 | # 'pointsize': '10pt', 128 | 129 | # Additional stuff for the LaTeX preamble. 130 | # 131 | # 'preamble': '', 132 | 133 | # Latex figure (float) alignment 134 | # 135 | # 'figure_align': 'htbp', 136 | } 137 | 138 | # Grouping the document tree into LaTeX files. List of tuples 139 | # (source start file, target name, title, 140 | # author, documentclass [howto, manual, or own class]). 141 | latex_documents = [ 142 | (master_doc, 'MeerUserGuide.tex', u'Meer User Guide Documentation', 143 | u'Champ Clark III', 'manual'), 144 | ] 145 | 146 | 147 | # -- Options for manual page output ------------------------------------------ 148 | 149 | # One entry per manual page. List of tuples 150 | # (source start file, name, description, authors, manual section). 151 | man_pages = [ 152 | (master_doc, 'meeruserguide', u'Meer User Guide Documentation', 153 | [author], 1) 154 | ] 155 | 156 | 157 | # -- Options for Texinfo output ---------------------------------------------- 158 | 159 | # Grouping the document tree into Texinfo files. List of tuples 160 | # (source start file, target name, title, author, 161 | # dir menu entry, description, category) 162 | texinfo_documents = [ 163 | (master_doc, 'MeerUserGuide', u'Meer User Guide Documentation', 164 | author, 'MeerUserGuide', 'One line description of project.', 165 | 'Miscellaneous'), 166 | ] 167 | 168 | 169 | # -- Options for Epub output ------------------------------------------------- 170 | 171 | # Bibliographic Dublin Core info. 172 | epub_title = project 173 | 174 | # The unique identifier of the text. This can be a ISBN number 175 | # or the project homepage. 176 | # 177 | # epub_identifier = '' 178 | 179 | # A unique identification for the text. 180 | # 181 | # epub_uid = '' 182 | 183 | # A list of files that should not be packed into the epub file. 184 | epub_exclude_files = ['search.html'] 185 | 186 | 187 | # -- Extension configuration ------------------------------------------------- 188 | 189 | # -- Options for intersphinx extension --------------------------------------- 190 | 191 | # Example configuration for intersphinx: refer to the Python standard library. 192 | intersphinx_mapping = {'https://docs.python.org/': None} 193 | 194 | # -- Options for todo extension ---------------------------------------------- 195 | 196 | # If true, `todo` and `todoList` produce output, else they produce nothing. 197 | todo_include_todos = True 198 | -------------------------------------------------------------------------------- /doc/source/console-output.rst: -------------------------------------------------------------------------------- 1 | Console Output 2 | ============== 3 | 4 | Console/Log Startup 5 | ------------------- 6 | 7 | At start up, the logs and console output give you information about the status of Meer. 8 | For example, you will want to note the ``Redis`` and ``Elasticsearch``, such as the driver and whether 9 | a successful connection was made. If there is a problem making a connection to your database, 10 | Meer will display the error that is causing the issues. 11 | 12 | Another important item to note is the database sensor ID. This will be the ID number used in 13 | the database to store events. 14 | 15 | Common issues are database rights and directory/file permission problems. 16 | 17 | If Meer makes it to the ``Waiting of new data...``, then Meer has successfully started. 18 | 19 | :: 20 | 21 | [*] [10/20/2021 20:55:23] Configuration '/usr/local/etc/meer.yaml' for host 'dev' successfully loaded. 22 | [*] [10/20/2021 20:55:23] 23 | [*] [10/20/2021 20:55:23] @@@@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@ Meer version 1.0.0-git 24 | [*] [10/20/2021 20:55:23] @@! @@! @@! @@! @@! @@! @@@ Quadrant Information Security 25 | [*] [10/20/2021 20:55:23] @!! !!@ @!@ @!!!:! @!!!:! @!@!!@a https://quadrantsec.com 26 | [*] [10/20/2021 20:55:23] !!: !!: !!: !!: !!: :!a Copyright (C) 2018-2021 27 | [*] [10/20/2021 20:55:23] : : : :: :: : :: :: : : : 28 | [*] [10/20/2021 20:55:23] 29 | [*] [10/20/2021 20:55:23] Meer's PID is 14606 30 | [*] [10/20/2021 20:55:23] Dropping privileges! [UID: 1011 GID: 1011] 31 | [*] [10/20/2021 20:55:23] Loaded 40382 entries from OUI database [/usr/local/etc/manuf]. 32 | [*] [10/20/2021 20:55:23] Classifications file loaded [/usr/local/etc/sagan-rules/classification.config]. 33 | [*] [10/20/2021 20:55:23] 34 | [*] [10/20/2021 20:55:23] Fingerprint support : enabled 35 | [*] [10/20/2021 20:55:23] Health updates : enabled 36 | [*] [10/20/2021 20:55:23] 37 | [*] [10/20/2021 20:55:23] GeoIP support : enabled 38 | [*] [10/20/2021 20:55:23] GeoIP database : /usr/local/share/GeoIP2/GeoLite2-City.mmdb 39 | [*] [10/20/2021 20:55:23] 40 | [*] [10/20/2021 20:55:23] Waldo loaded. Current position: 2345 41 | [*] [10/20/2021 20:55:23] 42 | [*] [10/20/2021 20:55:23] --[ Redis output information ]-------------------------------------- 43 | [*] [10/20/2021 20:55:23] 44 | [*] [10/20/2021 20:55:23] Successfully connected to Redis server at 127.0.0.1:6379. 45 | [*] [10/20/2021 20:55:23] Got PONG from Redis at 127.0.0.1:6379. 46 | [*] [10/20/2021 20:55:23] 47 | [*] [10/20/2021 20:55:23] Write 'alert' : enabled 48 | [*] [10/20/2021 20:55:23] Write 'stats' : enabled 49 | [*] [10/20/2021 20:55:23] Write 'email' : enabled 50 | [*] [10/20/2021 20:55:23] Write 'dns' : enabled 51 | [*] [10/20/2021 20:55:23] Write 'flow' : enabled 52 | [*] [10/20/2021 20:55:23] Write 'http' : enabled 53 | [*] [10/20/2021 20:55:23] Write 'tls' : enabled 54 | [*] [10/20/2021 20:55:23] Write 'ssh' : enabled 55 | [*] [10/20/2021 20:55:23] Write 'smtp' : enabled 56 | [*] [10/20/2021 20:55:23] Write 'files' : enabled 57 | [*] [10/20/2021 20:55:23] Write 'fileinfo' : enabled 58 | [*] [10/20/2021 20:55:23] Write 'dhcp' : enabled 59 | [*] [10/20/2021 20:55:23] Write 'rdp' : enabled 60 | [*] [10/20/2021 20:55:23] Write 'sip' : enabled 61 | [*] [10/20/2021 20:55:23] Write 'ftp' : enabled 62 | [*] [10/20/2021 20:55:23] Write 'ikev2' : enabled 63 | [*] [10/20/2021 20:55:23] Write 'nfs' : enabled 64 | [*] [10/20/2021 20:55:23] Write 'tftp' : enabled 65 | [*] [10/20/2021 20:55:23] Write 'smb' : enabled 66 | [*] [10/20/2021 20:55:23] Write 'dcerpc' : enabled 67 | [*] [10/20/2021 20:55:23] Write 'mqtt' : enabled 68 | [*] [10/20/2021 20:55:23] Write 'netflow' : enabled 69 | [*] [10/20/2021 20:55:23] Write 'metadata' : enabled 70 | [*] [10/20/2021 20:55:23] Write 'dnp3' : enabled 71 | [*] [10/20/2021 20:55:23] Write 'anomaly' : enabled 72 | [*] [10/20/2021 20:55:23] Write 'client_stats' : enabled 73 | [*] [10/20/2021 20:55:23] 74 | [*] [10/20/2021 20:55:23] --[ Elasticsearch output information ]--------------------------- 75 | [*] [10/20/2021 20:55:23] 76 | [*] [10/20/2021 20:55:23] URL to connect to : "https://127.0.0.1:9200/_bulk" 77 | [*] [10/20/2021 20:55:23] Index template : "suricata_$EVENTTYPE_$YEAR$MONTH$DAY" 78 | [*] [10/20/2021 20:55:23] Batch size per/POST : 100 79 | [*] [10/20/2021 20:55:23] Threads : 10 80 | [*] [10/20/2021 20:55:23] Authentication : enabled 81 | [*] [10/20/2021 20:55:23] 82 | [*] [10/20/2021 20:55:23] Record 'alert' : enabled 83 | [*] [10/20/2021 20:55:23] Record 'files' : enabled 84 | [*] [10/20/2021 20:55:23] Record 'flow' : enabled 85 | [*] [10/20/2021 20:55:23] Record 'dns' : enabled 86 | [*] [10/20/2021 20:55:23] Record 'http' : enabled 87 | [*] [10/20/2021 20:55:23] Record 'tls' : enabled 88 | [*] [10/20/2021 20:55:23] Record 'ssh' : enabled 89 | [*] [10/20/2021 20:55:23] Record 'smtp' : enabled 90 | [*] [10/20/2021 20:55:23] Record 'email' : enabled 91 | [*] [10/20/2021 20:55:23] Record 'fileinfo' : enabled 92 | [*] [10/20/2021 20:55:23] Record 'dhcp' : enabled 93 | [*] [10/20/2021 20:55:23] Record 'stats' : enabled 94 | [*] [10/20/2021 20:55:23] Record 'rdp' : enabled 95 | [*] [10/20/2021 20:55:23] Record 'sip' : enabled 96 | [*] [10/20/2021 20:55:23] Record 'ftp' : enabled 97 | [*] [10/20/2021 20:55:23] Record 'nfs' : enabled 98 | [*] [10/20/2021 20:55:23] Record 'tftp' : enabled 99 | [*] [10/20/2021 20:55:23] Record 'smb' : enabled 100 | [*] [10/20/2021 20:55:23] Record 'mqtt' : enabled 101 | [*] [10/20/2021 20:55:23] Record 'dcerpc' : enabled 102 | [*] [10/20/2021 20:55:23] Record 'netflow' : enabled 103 | [*] [10/20/2021 20:55:23] Record 'metadata' : enabled 104 | [*] [10/20/2021 20:55:23] Record 'dnp3' : enabled 105 | [*] [10/20/2021 20:55:23] Record 'anomaly' : enabled 106 | [*] [10/20/2021 20:55:23] 107 | [*] [10/20/2021 20:55:23] Spawning 10 Elasticsearch threads. 108 | [*] [10/20/2021 20:55:23] 109 | [*] [10/20/2021 20:55:23] --[ Meer engine information ]------------------------------------- 110 | [*] [10/20/2021 20:55:23] 111 | [*] [10/20/2021 20:55:23] Successfully opened /home/champ/test.eve 112 | [*] [10/20/2021 20:55:23] Skipping to record 2345 in /home/champ/test.eve 113 | [*] [10/20/2021 20:55:23] Reached target record of 2345. Processing new records. 114 | [*] [10/20/2021 20:55:23] Read in 2345 lines 115 | [*] [10/20/2021 20:55:23] Waiting for new data...... 116 | 117 | -------------------------------------------------------------------------------- /doc/source/getting-help.rst: -------------------------------------------------------------------------------- 1 | Getting help 2 | ============ 3 | 4 | The Meer Github site is located at: 5 | 6 | https://github.com/quadrantsec/meer 7 | 8 | If you are having issues getting Meer to work, consider posting in the Meer mailing list. This list 9 | is good for general configuration, install, and usage questions. 10 | 11 | https://groups.google.com/forum/#!forum/meer-users 12 | 13 | If you need to report a compile or programming issue, please use our Github.com issues page. That is 14 | located at: 15 | 16 | https://github.com/quadrantsec/meer/issues 17 | 18 | You can also get support via our Meer Discord channel. That is at: 19 | 20 | https://discord.gg/VS6jTjH4gW 21 | -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | Meer User Guide 2 | =============== 3 | 4 | .. toctree:: 5 | :numbered: 6 | :maxdepth: 2 7 | 8 | what-is-meer 9 | install.rst 10 | command-line-options 11 | starting-meer 12 | core 13 | input 14 | output 15 | console-output 16 | getting-help 17 | 18 | -------------------------------------------------------------------------------- /doc/source/install.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | Quick start from source 5 | ------------------------ 6 | 7 | Quick installation using common flags. For more information on packages and flags, skip to ``Required Prerequisites`` and ``Optional Prerequisites``. 8 | 9 | :: 10 | 11 | sudo apt-get install libjson-c-dev libyaml-dev libmaxminddb-dev libcurl4-openssl-dev libhiredis-dev libevent-dev zlib1g-dev 12 | git clone https://github.com/quadrantsec/meer 13 | cd meer 14 | ./autogen.sh 15 | ./configure --enable-redis --enable-elasticsearch --enable-geoip 16 | make 17 | sudo make install 18 | 19 | By default, this will install Meer into the ``/usr/local/bin/`` directory with the default Meer configuration file in the ``/usr/local/etc/`` directory. By default (without any flags), Meer will compile with only Redis support. 20 | 21 | 22 | Required Prerequisites 23 | ---------------------- 24 | 25 | Meer uses a YAML configuration file. This means that Meer will need libyaml installed on the system. On Ubuntu/Debian systems, this can be installed via: 26 | 27 | .. option:: apt-get install libyaml-dev 28 | 29 | Meer uses `JSON-C `_ to parse JSON (EVE) output from Sagan and Suricata. On Ubuntu/Debian systems, this prerequisite can be installed via: 30 | 31 | .. option:: apt-get install libjson-c-dev 32 | 33 | Optional Prerequisites 34 | ---------------------- 35 | 36 | Redis 37 | ~~~~~ 38 | 39 | If you would like to have Meer store data into Redis, which is enabled by default during compile time, you will need the "hiredis" library and development files. You will also need ``libevent`` installed as well. 40 | 41 | On Ubuntu/Debian systems: 42 | 43 | .. option:: sudo apt-get install libhiredis-dev libevent-dev 44 | 45 | 46 | Elasticsearch 47 | ~~~~~~~~~~~~~ 48 | 49 | If you would like Meer to use the 'elasticsearch' output plugin, then you'll need to install libcurl. To do this on Ubuntu/Debian systems, do the following: 50 | 51 | .. option:: apt-get install libcurl4-openssl-dev 52 | 53 | Maxmind (GeoIP support) 54 | ~~~~~~~~~~~~~~~~~~~~~~~ 55 | 56 | If you would like Meer to add GeoIP data to Suricata/Sagan EVE data, you'll want to install the Maxmind (https://maxmind.com) library. To do this on Ubuntu/Debian systems, do the following: 57 | 58 | .. option:: apt-get install libmaxminddb-dev 59 | 60 | JEMalloc 61 | ~~~~~~~~ 62 | 63 | For JEMalloc support, on Debian/Ubuntu systems, install the JEMalloc library: 64 | 65 | .. option:: apt-get install libjemalloc-dev 66 | 67 | TCMalloc 68 | ~~~~~~~~ 69 | 70 | For TCMalloc support, on Debian/Ubuntu systems, install the TCMalloc library: 71 | 72 | .. option:: apt-get install libtcmalloc-minimal4 73 | 74 | 75 | Common configure options 76 | ^^^^^^^^^^^^^^^^^^^^^^^^ 77 | 78 | .. option:: --prefix=/usr/ 79 | 80 | Installs the Meer binary in the /usr/bin. The default is ``/usr/local/bin``. 81 | 82 | .. option:: --sysconfdir=/etc 83 | 84 | Installs the Meer configuration file (meer.yaml) in the /etc directory. The default is ``/usr/local/etc/``. 85 | 86 | .. option:: --with-libjsonc-libraries 87 | 88 | This option points Meer to where the json-c libraries reside. 89 | 90 | .. option:: --with-libjsonc-includes 91 | 92 | This option points Meer to where the json-c header files reside. 93 | 94 | .. option:: --with-libyaml_libraries 95 | 96 | This option points Meer to where the libyaml files reside. 97 | 98 | .. option:: --with-libyaml-includes 99 | 100 | This option points Meer to where the libyaml header files reside. 101 | 102 | .. option:: --enable-redis 103 | 104 | This option enables Redis output support. It requires "hiredis" to be installedt. 105 | 106 | .. option:: --enable-elastcisearch 107 | 108 | This option enables Elastcisearch support. It requires "libcurl" to be installed. 109 | 110 | .. option:: --enable-geoip 111 | 112 | This option enables Maxmind's GeoIP support. It requires "libmaxminddb" Maxmind library to be install. 113 | 114 | .. option:: --enable-bluedot 115 | 116 | This optino allows Meer to write to a Bluedot "threat intel" database alert data via HTTP. This 117 | requres that "libcurl" be installed. You probably don't want this. 118 | 119 | .. option:: --enable-tcmalloc 120 | 121 | This options enables support for Google's TCMalloc. For more information, see https://github.com/google/tcmalloc 122 | 123 | .. option:: --enable-jemalloc 124 | 125 | This options enables support for JEMalloc. For more information, see https://jemalloc.net. 126 | 127 | 128 | -------------------------------------------------------------------------------- /doc/source/starting-meer.rst: -------------------------------------------------------------------------------- 1 | Starting Meer 2 | ============= 3 | 4 | To start Meer as root type:: 5 | 6 | /usr/local/bin/meer 7 | 8 | To start Meer with a specified configuration file as root type:: 9 | 10 | /usr/local/bin/meer --config /path/to/my/config 11 | 12 | To start Meer with a specified configuration file in "quiet" mode as root type:: 13 | 14 | /usr/local/bin/meer --config /path/to/my/config --quiet 15 | 16 | to start Meer in the background as "root" type:: 17 | 18 | /usr/local/bin/meer --daemon 19 | 20 | -------------------------------------------------------------------------------- /doc/source/what-is-meer.rst: -------------------------------------------------------------------------------- 1 | What is Meer 2 | ============ 3 | 4 | "Meer" is a dedicated data broker for the `Suricata `_ IDS/IPS system and the `Sagan `_ log analysis engine. 5 | 6 | Meer takes EVE data (JSON) from Suricata or Sagan (via an ``input-plugin``), augments it by enriching it 7 | with DNS, GeoIP, and other information (via the ``meer-core``), and then pushes the data to a database (via a ``output-plugin``) of your choice. 8 | 9 | Meer is written in C which makes it fast and very light weight. This makes is suitable for processing data on systems with limited resource. 10 | 11 | Meer ``input-plugins`` that are currently supported are Suricata/Sagan EVE ("spool") files and Redis. 12 | 13 | Meer ``output-plugins`` that are currently supported are Elasticsearch, Opensearch, Zincsearch 14 | (https://github.com/zinclabs/zinc), Redis, named pipes, files, and "external" programs. Meer release 1.0.0 15 | supports SQL (MariaDB, MySQL and PostgreSQL) that is compatible with older "Barnyard2" systems. Meer versions 16 | _after_ 1.0.0 do _not_ support SQL. 17 | 18 | The primary Meer site is located at: 19 | 20 | https://github.com/quadrantsec/meer 21 | 22 | 23 | License 24 | ------- 25 | 26 | Meer is licensed under the GNU/GPL version 2. 27 | 28 | -------------------------------------------------------------------------------- /extra/build-test/build-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Simple shell script that compiles Meern with multiple flags. This helps 4 | # hunt down compile time bugs. 5 | # 6 | # - Public release (20211004) 7 | # --disable-tcmalloc 8 | # 9 | # - Disabled mysql/postgresql support (20211129) 10 | 11 | STANDARD="--disable-elasticsearch --disable-bluedot --disable-geoip --enable-redis --disable-jemalloc --disable-gzip --enable-syslog" 12 | ALLFLAGS="--enable-elasticsearch --enable-bluedot --enable-geoip --enable-redis --enable-jemalloc --enable-gzip -enable-syslog" 13 | NOFLAG="--disable-elasticsearch --disable-bluedot --disable-geoip --disable-redis --disable-jemalloc --disable-gzip --disable-syslog" 14 | 15 | LOG="output.log" 16 | 17 | MAKE_FLAGS="-j7" 18 | 19 | autoreconf -vfi 20 | 21 | echo "**** STANDARD BUILD | NO FLAGS ****" 22 | echo "**** STANDARD BUILD | NO FLAGS ****" >> $LOG 23 | 24 | #make clean 25 | #cd tools && make clean && cd .. 26 | 27 | CFLAGS=-Wall ./configure 28 | 29 | if [ "$?" != "0" ] 30 | then 31 | echo "./configure failed!"; 32 | exit 33 | fi 34 | 35 | make $MAKE_FLAGS 2>> $LOG 36 | 37 | if [ "$?" != "0" ] 38 | then 39 | echo "Error on standard build!"; 40 | exit 41 | fi 42 | 43 | echo "**** ALL FLAGS : $ALLFLAGS ****" 44 | echo "**** ALL FLAGS : $ALLFLAGS ****" >> $LOG 45 | 46 | make clean 47 | 48 | CFLAGS=-Wall ./configure $ALLFLAGS 49 | 50 | if [ "$?" != "0" ] 51 | then 52 | echo "./configure failed!"; 53 | exit 54 | fi 55 | 56 | make $MAKE_FLAGS 2>> $LOG 57 | 58 | if [ "$?" != "0" ] 59 | then 60 | echo "Error on standard build!"; 61 | exit 62 | fi 63 | 64 | echo "**** NO FLAGS : $NOFLAG ****" 65 | echo "**** NO FLAGS : $NOFLAG ****" >> $LOG 66 | 67 | make clean 68 | 69 | CFLAGS=-Wall ./configure $NOFLAG 70 | 71 | if [ "$?" != "0" ] 72 | then 73 | echo "./configure failed!"; 74 | exit 75 | fi 76 | 77 | make $MAKE_FLAGS 2>> $LOG 78 | 79 | if [ "$?" != "0" ] 80 | then 81 | echo "Error on standard build!"; 82 | exit 83 | fi 84 | 85 | echo "--------------------[ Rotating Through Flags ]--------------------" 86 | echo "--------------------[ Rotating Through Flags ]--------------------" >> $LOG 87 | 88 | for I in $STANDARD 89 | do 90 | 91 | make clean 92 | 93 | echo "**** FLAGS $I *****" 94 | echo "**** FLAGS $I *****" >> $LOG 95 | 96 | CFLAGS=-Wall ./configure $I 97 | 98 | if [ "$?" != "0" ] 99 | then 100 | echo "./configure failed!"; 101 | exit 102 | fi 103 | 104 | make $MAKE_FLAGS 2>> $LOG 105 | 106 | if [ "$?" != "0" ] 107 | then 108 | echo "Error on with $I"; 109 | exit 110 | fi 111 | done 112 | 113 | for I in $ALLFLAGS 114 | do 115 | 116 | make clean 117 | 118 | echo "**** FLAGS $I *****" 119 | echo "**** FLAGS $I *****" >> $LOG 120 | 121 | CFLAGS=-Wall ./configure $I 122 | 123 | if [ "$?" != "0" ] 124 | then 125 | echo "./configure failed!"; 126 | exit 127 | fi 128 | 129 | make $MAKE_FLAGS 2>> $LOG 130 | 131 | if [ "$?" != "0" ] 132 | then 133 | echo "Error on with $I"; 134 | exit 135 | fi 136 | done 137 | 138 | for I in $NOFLAGS 139 | do 140 | 141 | make clean 142 | 143 | echo "**** FLAGS $I *****" 144 | echo "**** FLAGS $I *****" >> $LOG 145 | 146 | CFLAGS=-Wall ./configure $I 147 | 148 | if [ "$?" != "0" ] 149 | then 150 | echo "./configure failed!"; 151 | exit 152 | fi 153 | 154 | make $MAKE_FLAGS 2>> $LOG 155 | 156 | if [ "$?" != "0" ] 157 | then 158 | echo "Error on with $I"; 159 | exit 160 | fi 161 | done 162 | 163 | -------------------------------------------------------------------------------- /screenshots/discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quadrantsec/meer/68362cac477f9fe6d8d3662aed245239c0c65725/screenshots/discord.png -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | AUTOMAKE_OPIONS=foreign no-dependencies subdir-objects 4 | 5 | bin_PROGRAMS = meer 6 | meer_CPPFLAGS = -I$(top_srcdir) $(LIBFASTJSON_CFLAGS) $(LIBESTR_CFLAGS) 7 | meer_LDADD = $(LIBFASTJSON_LIBS) $(LIBLOGNORM_LIBS) $(LIBESTR_LIBS) 8 | 9 | meer_SOURCES = meer.c \ 10 | config-yaml.c \ 11 | util.c \ 12 | daemonize.c \ 13 | util-strlcpy.c \ 14 | util-strlcat.c \ 15 | util-signal.c \ 16 | util-base64.c \ 17 | util-md5.c \ 18 | util-dns.c \ 19 | get-dns.c \ 20 | get-geoip.c \ 21 | get-oui.c \ 22 | get-fingerprint.c \ 23 | lockfile.c \ 24 | counters.c \ 25 | stats.c \ 26 | waldo.c \ 27 | output.c \ 28 | usage.c \ 29 | oui.c \ 30 | geoip.c \ 31 | calculate-stats.c \ 32 | ndp-collector.c \ 33 | decode-json.c \ 34 | decode-output-json-client-stats.c \ 35 | output-plugins/pipe.c \ 36 | output-plugins/external.c \ 37 | output-plugins/redis.c \ 38 | output-plugins/bluedot.c \ 39 | output-plugins/elasticsearch.c \ 40 | output-plugins/file.c \ 41 | output-plugins/syslog.c \ 42 | input-plugins/file.c \ 43 | input-plugins/redis.c \ 44 | input-plugins/commandline.c 45 | 46 | 47 | install-data-local: 48 | 49 | -------------------------------------------------------------------------------- /src/calculate-stats.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Calculate_Stats( struct json_object *json_obj, char *str ); 22 | 23 | -------------------------------------------------------------------------------- /src/config-yaml.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | /* Prototypes */ 26 | 27 | void Load_YAML_Config ( char *yaml_file ); 28 | 29 | 30 | #ifdef HAVE_LIBYAML 31 | 32 | /************************/ 33 | /* Minimum YAML version */ 34 | /************************/ 35 | 36 | #define YAML_VERSION_MAJOR 1 37 | #define YAML_VERSION_MINOR 1 38 | 39 | /*****************/ 40 | /* Primary types */ 41 | /*****************/ 42 | 43 | #define YAML_TYPE_MEER 1 44 | #define YAML_TYPE_OUTPUT 2 45 | #define YAML_TYPE_INPUT 3 46 | 47 | /*******************/ 48 | /* Secondary types */ 49 | /*******************/ 50 | 51 | #define YAML_MEER_CORE_CORE 1 52 | #define YAML_MEER_PIPE 2 53 | #define YAML_MEER_EXTERNAL 3 54 | #define YAML_MEER_REDIS 4 55 | #define YAML_MEER_BLUEDOT 5 56 | #define YAML_MEER_ELASTICSEARCH 6 57 | #define YAML_MEER_FILE 7 58 | #define YAML_MEER_SYSLOG 8 59 | 60 | /***************/ 61 | /* Input types */ 62 | /***************/ 63 | 64 | #define YAML_INPUT_FILE 1 65 | #define YAML_INPUT_PIPE 2 66 | #define YAML_INPUT_REDIS 3 67 | #define YAML_INPUT_COMMAND_LINE 4 68 | 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/counters.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "meer.h" 30 | #include "meer-def.h" 31 | #include "counters.h" 32 | 33 | extern struct _MeerCounters *MeerCounters; 34 | 35 | void Counters ( const char *event_type ) 36 | { 37 | 38 | MeerCounters->total++; 39 | 40 | if ( !strcmp(event_type, "alert" ) ) 41 | { 42 | MeerCounters->alert++; 43 | return; 44 | } 45 | 46 | else if ( !strcmp(event_type, "files" ) ) 47 | { 48 | MeerCounters->files++; 49 | return; 50 | } 51 | 52 | else if ( !strcmp(event_type, "flow" ) ) 53 | { 54 | MeerCounters->flow++; 55 | return; 56 | } 57 | 58 | else if ( !strcmp(event_type, "dns" ) ) 59 | { 60 | MeerCounters->dns++; 61 | return; 62 | } 63 | 64 | else if ( !strcmp(event_type, "http" ) ) 65 | { 66 | MeerCounters->http++; 67 | return; 68 | } 69 | 70 | else if ( !strcmp(event_type, "tls" ) ) 71 | { 72 | MeerCounters->tls++; 73 | return; 74 | } 75 | 76 | else if ( !strcmp(event_type, "ssh" ) ) 77 | { 78 | MeerCounters->ssh++; 79 | return; 80 | } 81 | 82 | else if ( !strcmp(event_type, "smtp" ) ) 83 | { 84 | MeerCounters->smtp++; 85 | return; 86 | } 87 | 88 | else if ( !strcmp(event_type, "email" ) ) 89 | { 90 | MeerCounters->email++; 91 | return; 92 | } 93 | 94 | else if ( !strcmp(event_type, "fileinfo" ) ) 95 | { 96 | MeerCounters->fileinfo++; 97 | return; 98 | } 99 | 100 | else if ( !strcmp(event_type, "dhcp" ) ) 101 | { 102 | MeerCounters->dhcp++; 103 | return; 104 | } 105 | 106 | else if ( !strcmp(event_type, "stats" ) ) 107 | { 108 | MeerCounters->stats++; 109 | return; 110 | } 111 | 112 | else if ( !strcmp(event_type, "rdp" ) ) 113 | { 114 | MeerCounters->rdp++; 115 | return; 116 | } 117 | 118 | else if ( !strcmp(event_type, "sip" ) ) 119 | { 120 | MeerCounters->sip++; 121 | return; 122 | } 123 | 124 | else if ( !strcmp(event_type, "ftp" ) || !strcmp(event_type, "ftp_data" ) ) 125 | { 126 | MeerCounters->ftp++; 127 | return; 128 | } 129 | 130 | else if ( !strcmp(event_type, "ikev2" ) ) 131 | { 132 | MeerCounters->ikev2++; 133 | return; 134 | } 135 | 136 | else if ( !strcmp(event_type, "nfs" ) ) 137 | { 138 | MeerCounters->nfs++; 139 | return; 140 | } 141 | 142 | else if ( !strcmp(event_type, "tftp" ) ) 143 | { 144 | MeerCounters->tftp++; 145 | return; 146 | } 147 | 148 | else if ( !strcmp(event_type, "smb" ) ) 149 | { 150 | MeerCounters->smb++; 151 | return; 152 | } 153 | 154 | else if ( !strcmp(event_type, "dcerpc" ) ) 155 | { 156 | MeerCounters->dcerpc++; 157 | return; 158 | } 159 | 160 | else if ( !strcmp(event_type, "mqtt" ) ) 161 | { 162 | MeerCounters->mqtt++; 163 | return; 164 | } 165 | 166 | else if ( !strcmp(event_type, "netflow" ) ) 167 | { 168 | MeerCounters->netflow++; 169 | return; 170 | } 171 | 172 | else if ( !strcmp(event_type, "metadata" ) ) 173 | { 174 | MeerCounters->metadata++; 175 | return; 176 | } 177 | 178 | else if ( !strcmp(event_type, "dnp3" ) ) 179 | { 180 | MeerCounters->dnp3++; 181 | return; 182 | } 183 | 184 | else if ( !strcmp(event_type, "anomaly" ) ) 185 | { 186 | MeerCounters->anomaly++; 187 | return; 188 | } 189 | 190 | else if ( !strcmp(event_type, "fingerprint" ) ) 191 | { 192 | MeerCounters->fingerprint++; 193 | return; 194 | } 195 | 196 | else if ( !strcmp(event_type, "client_stats" ) ) 197 | { 198 | MeerCounters->client_stats++; 199 | return; 200 | } 201 | 202 | MeerCounters->unknown++; 203 | Meer_Log(WARN, "[%s, line %d] Unknown event_type '%s'. Skipping....", __FILE__, __LINE__, event_type); 204 | 205 | } 206 | -------------------------------------------------------------------------------- /src/counters.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Counters ( const char *event_type ); 22 | -------------------------------------------------------------------------------- /src/daemonize.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | #include "meer-def.h" 35 | #include "meer.h" 36 | 37 | extern struct _MeerConfig *MeerConfig; 38 | 39 | void Daemonize() 40 | { 41 | 42 | Meer_Log(NORMAL, "Becoming a daemon!"); 43 | 44 | pid_t pid = 0; 45 | pid = fork(); 46 | 47 | if ( pid == 0 ) 48 | { 49 | 50 | /* Child */ 51 | 52 | if ( setsid() == -1 ) 53 | { 54 | Meer_Log(ERROR, "[%s, line %d] Failed creating new session while daemonizing", __FILE__, __LINE__); 55 | exit(1); 56 | } 57 | 58 | pid = fork(); 59 | 60 | if ( pid == 0 ) 61 | { 62 | 63 | /* Grandchild, the actual daemon */ 64 | 65 | if ( chdir("/") == -1 ) 66 | { 67 | Meer_Log(ERROR, "[%s, line %d] Failed changing directory to / after daemonizing [errno %d]", __FILE__, __LINE__, errno); 68 | exit(1); 69 | } 70 | 71 | /* Close and re-open stdin, stdout, and stderr, so as to 72 | to release anyone waiting on them. */ 73 | 74 | close(0); 75 | close(1); 76 | close(2); 77 | 78 | if ( open("/dev/null", O_RDONLY) == -1 ) 79 | { 80 | Meer_Log(ERROR, "[%s, line %d] Failed reopening stdin after daemonizing [errno %d]", __FILE__, __LINE__, errno); 81 | } 82 | 83 | if ( open("/dev/null", O_WRONLY) == -1 ) 84 | { 85 | Meer_Log(ERROR, "[%s, line %d] Failed reopening stdout after daemonizing [errno %d]", __FILE__, __LINE__, errno); 86 | } 87 | 88 | if ( open("/dev/null", O_RDWR) == -1 ) 89 | { 90 | Meer_Log(ERROR, "[%s, line %d] Failed reopening stderr after daemonizing [errno %d]", __FILE__, __LINE__, errno); 91 | } 92 | 93 | } 94 | else if ( pid < 0 ) 95 | { 96 | 97 | Meer_Log(ERROR, "[%s, line %d] Failed second fork while daemonizing", __FILE__, __LINE__); 98 | exit(1); 99 | 100 | } 101 | else 102 | { 103 | 104 | exit(0); 105 | } 106 | 107 | } 108 | else if ( pid < 0 ) 109 | { 110 | 111 | Meer_Log(ERROR, "[%s, line %d] Failed first fork while daemonizing", __FILE__, __LINE__); 112 | exit(1); 113 | 114 | } 115 | else 116 | { 117 | 118 | /* Wait for child to exit */ 119 | waitpid(pid, NULL, 0); 120 | exit(0); 121 | } 122 | 123 | } 124 | 125 | -------------------------------------------------------------------------------- /src/daemonize.h: -------------------------------------------------------------------------------- 1 | void Daemonize(); 2 | -------------------------------------------------------------------------------- /src/decode-json.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | bool Decode_JSON( char *json_string ); 22 | -------------------------------------------------------------------------------- /src/decode-output-json-client-stats.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #ifdef HAVE_LIBJSON_C 26 | #include 27 | #endif 28 | 29 | #ifndef HAVE_LIBJSON_C 30 | libjson-c is required for Meer to function! 31 | #endif 32 | 33 | void Decode_Output_JSON_Client_Stats ( struct json_object *json_obj, const char *json_string ); 34 | 35 | -------------------------------------------------------------------------------- /src/geoip.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #ifdef HAVE_LIBMAXMINDDB 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "meer.h" 34 | #include "meer-def.h" 35 | #include "util.h" 36 | #include "geoip.h" 37 | 38 | extern struct _MeerConfig *MeerConfig; 39 | 40 | MMDB_s geoip; 41 | 42 | void Open_GeoIP_Database( void ) 43 | { 44 | 45 | int status; 46 | 47 | /* 48 | * The GeoIP library gives a really vague error when it cannot load 49 | * the GeoIP database. We give the user more information here so 50 | * that they might fix the issue. 51 | */ 52 | 53 | status = access(MeerConfig->geoip_database, R_OK); 54 | 55 | if ( status != 0 ) 56 | { 57 | Meer_Log(WARN, "Cannot open '%s' [%s]!", MeerConfig->geoip_database, strerror(errno)); 58 | Meer_Log(ERROR, "Make sure the GeoIP database '%s' is readable by '%s'.", MeerConfig->geoip_database, MeerConfig->runas); 59 | } 60 | 61 | status = MMDB_open(MeerConfig->geoip_database, MMDB_MODE_MMAP, &geoip); 62 | 63 | if ( status != 0 ) 64 | { 65 | Meer_Log(ERROR, "Error loading Maxmind GeoIP data (%s). Are you trying to load an older, non-GeoIP database?", MeerConfig->geoip_database); 66 | } 67 | 68 | 69 | } 70 | 71 | void GeoIP_Lookup( const char *ip_address, struct _GeoIP *GeoIP ) 72 | { 73 | 74 | int gai_error; 75 | int mmdb_error; 76 | int res; 77 | 78 | bool failure = false; 79 | 80 | unsigned char ip_convert[MAXIPBIT] = { 0 }; 81 | 82 | IP2Bit( (char*)ip_address, ip_convert); 83 | 84 | if ( Is_Notroutable(ip_convert) ) 85 | { 86 | return; 87 | } 88 | 89 | MMDB_lookup_result_s result = MMDB_lookup_string(&geoip, ip_address, &gai_error, &mmdb_error); 90 | MMDB_entry_data_s entry_data; 91 | 92 | /* Country code */ 93 | 94 | res = MMDB_get_value(&result.entry, &entry_data, "country", "iso_code", NULL); 95 | 96 | if (res != MMDB_SUCCESS) 97 | { 98 | strlcpy(GeoIP->country, "LOOKUP_FAILURE", sizeof(GeoIP->country)); 99 | failure = true; 100 | } 101 | 102 | if ( !entry_data.has_data || entry_data.type != MMDB_DATA_TYPE_UTF8_STRING ) 103 | { 104 | strlcpy( GeoIP->country, "NOT_FOUND", sizeof( GeoIP->country ) ); 105 | failure = true; 106 | } 107 | 108 | if ( failure == false ) 109 | { 110 | strlcpy(GeoIP->country, entry_data.utf8_string, 3); 111 | } 112 | 113 | /* City */ 114 | 115 | MMDB_get_value(&result.entry, &entry_data, "city", "names", "en", NULL); 116 | 117 | if ( entry_data.has_data ) 118 | { 119 | strlcpy(GeoIP->city, entry_data.utf8_string, entry_data.data_size+1); 120 | } 121 | 122 | /* Subdivision */ 123 | 124 | MMDB_get_value(&result.entry, &entry_data, "subdivisions", "0", "iso_code", NULL); 125 | 126 | if ( entry_data.has_data ) 127 | { 128 | strlcpy(GeoIP->subdivision, entry_data.utf8_string, entry_data.data_size+1); 129 | } 130 | 131 | /* Postal */ 132 | 133 | MMDB_get_value(&result.entry, &entry_data, "postal", "code", NULL); 134 | 135 | if ( entry_data.has_data ) 136 | { 137 | strlcpy(GeoIP->postal, entry_data.utf8_string, entry_data.data_size+1); 138 | } 139 | 140 | /* Timezone */ 141 | 142 | MMDB_get_value(&result.entry, &entry_data, "location", "time_zone", NULL); 143 | 144 | if ( entry_data.has_data ) 145 | { 146 | strlcpy(GeoIP->timezone, entry_data.utf8_string, entry_data.data_size+1); 147 | } 148 | 149 | /* Latitude */ 150 | 151 | MMDB_get_value(&result.entry, &entry_data, "location", "latitude", NULL); 152 | 153 | if ( entry_data.has_data ) 154 | { 155 | snprintf(GeoIP->latitude, sizeof(GeoIP->latitude), "%f", entry_data.double_value); 156 | GeoIP->latitude[ sizeof(GeoIP->latitude) - 1 ] = '\0'; 157 | } 158 | 159 | /* Longitude */ 160 | 161 | MMDB_get_value(&result.entry, &entry_data, "location", "longitude", NULL); 162 | 163 | if ( entry_data.has_data ) 164 | { 165 | snprintf(GeoIP->longitude, sizeof(GeoIP->longitude), "%f", entry_data.double_value); 166 | GeoIP->longitude[ sizeof(GeoIP->longitude) - 1 ] = '\0'; 167 | } 168 | 169 | } 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /src/geoip.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | typedef struct _GeoIP _GeoIP; 21 | struct _GeoIP 22 | { 23 | 24 | uint_fast8_t results; 25 | 26 | char city[32]; 27 | char country[32]; 28 | char subdivision[3]; 29 | char postal[16]; 30 | char timezone[32]; 31 | char latitude[16]; 32 | char longitude[16]; 33 | 34 | }; 35 | 36 | 37 | void Open_GeoIP_Database( void ); 38 | void GeoIP_Lookup( const char *ip_address, struct _GeoIP *GeoIP ); 39 | 40 | -------------------------------------------------------------------------------- /src/get-dns.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include "meer-def.h" 31 | #include "meer.h" 32 | #include "util-dns.h" 33 | 34 | extern struct _MeerConfig *MeerConfig; 35 | extern struct _MeerCounters *MeerCounters; 36 | 37 | /******************************************************************/ 38 | /* Get_DNS() - looks up and adds DNS PTR records to a JSON object */ 39 | /******************************************************************/ 40 | 41 | void Get_DNS( struct json_object *json_obj, char *str ) 42 | { 43 | 44 | struct json_object *tmp = NULL; 45 | 46 | char src_ip[64] = { 0 }; 47 | char dest_ip[64] = { 0 }; 48 | 49 | char src_dns[256] = { 0 }; 50 | char dest_dns[256] = { 0 }; 51 | 52 | json_object_object_get_ex(json_obj, "src_ip", &tmp); 53 | strlcpy( src_ip, json_object_get_string(tmp), sizeof(src_ip) ); 54 | 55 | json_object_object_get_ex(json_obj, "dest_ip", &tmp); 56 | strlcpy( dest_ip, json_object_get_string(tmp), sizeof(dest_ip) ); 57 | 58 | DNS_Lookup_Reverse( src_ip, src_dns, sizeof( src_dns ) ); 59 | 60 | if ( src_dns[0] != '\0' ) 61 | { 62 | json_object *jsrc_dns = json_object_new_string(src_dns); 63 | json_object_object_add(json_obj,"src_dns", jsrc_dns); 64 | } 65 | 66 | DNS_Lookup_Reverse( dest_ip, dest_dns, sizeof( dest_dns ) ); 67 | 68 | if ( dest_dns[0] != '\0' ) 69 | { 70 | json_object *jdest_dns = json_object_new_string(dest_dns); 71 | json_object_object_add(json_obj,"dest_dns", jdest_dns); 72 | } 73 | 74 | snprintf(str, MeerConfig->payload_buffer_size, "%s", (char*)json_object_to_json_string(json_obj) ); 75 | 76 | } 77 | 78 | /****************************************************************************/ 79 | /* Is_DNS_Event_Type() - Used to determine if an "event_type" need to have */ 80 | /* DNS PTR records added or not. */ 81 | /****************************************************************************/ 82 | 83 | bool Is_DNS_Event_Type( const char *event_type ) 84 | { 85 | 86 | uint8_t i = 0; 87 | 88 | /* If it's 'all' we always return true */ 89 | 90 | if ( MeerConfig->dns_lookup_types[0][0] == 'a' && MeerConfig->dns_lookup_types[0][1] == 'l' && 91 | MeerConfig->dns_lookup_types[0][2] == 'l' ) 92 | { 93 | return(true); 94 | } 95 | 96 | /* Lookup event_type and decide DNS PTR is needed */ 97 | 98 | for ( i = 0; i < MeerConfig->dns_lookup_types_count; i++ ) 99 | { 100 | 101 | if ( !strcmp( event_type, MeerConfig->dns_lookup_types[i] ) ) 102 | { 103 | return(true); 104 | } 105 | 106 | } 107 | 108 | return(false); 109 | } 110 | 111 | -------------------------------------------------------------------------------- /src/get-dns.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Get_DNS( struct json_object *json_obj, char *str ); 22 | bool Is_DNS_Event_Type( const char *event_type ); 23 | 24 | -------------------------------------------------------------------------------- /src/get-fingerprint.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | 22 | void Fingerprint_DHCP ( struct json_object *json_obj, const char *json_string ); 23 | bool Fingerprint_In_Range( char *ip_address ); 24 | bool Is_Fingerprint( struct json_object *json_obj ); 25 | bool Fingerprint_JSON_IP_Redis ( struct json_object *json_obj ); 26 | bool Fingerprint_JSON_Event_Redis ( struct json_object *json_obj, char *str, size_t size ); 27 | void Get_Fingerprint( struct json_object *json_obj, char *str, size_t size, const char *json_string ); 28 | 29 | -------------------------------------------------------------------------------- /src/get-geoip.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "meer-def.h" 30 | #include "meer.h" 31 | 32 | #include "geoip.h" 33 | 34 | extern struct _MeerCounters *MeerCounters; 35 | extern struct _MeerConfig *MeerConfig; 36 | 37 | #ifdef HAVE_LIBMAXMINDDB 38 | 39 | void Get_GeoIP( struct json_object *json_obj, char *str, const char *src_ip, const char *dest_ip ) 40 | { 41 | 42 | /*************************************************/ 43 | /* Add any GeoIP data for the source/destination */ 44 | /*************************************************/ 45 | 46 | struct _GeoIP *GeoIP; 47 | GeoIP = malloc(sizeof(_GeoIP)); 48 | 49 | if ( GeoIP == NULL ) 50 | { 51 | Meer_Log(ERROR, "[%s, line %d] Failed to allocate memory for _GeoIP. Abort!", __FILE__, __LINE__); 52 | } 53 | 54 | memset(GeoIP, 0, sizeof(_GeoIP)); 55 | 56 | /*******************/ 57 | /* Get src_ip data */ 58 | /*******************/ 59 | 60 | GeoIP_Lookup( src_ip, GeoIP ); 61 | 62 | if ( GeoIP->country[0] != '\0' ) 63 | { 64 | 65 | /* Only allocate json_object when we actually need to tie it to *json_obj 66 | We won't need to deallocate it as it will become part of *json_obj! */ 67 | 68 | struct json_object *jobj_geoip_src = NULL; 69 | jobj_geoip_src = json_object_new_object(); 70 | 71 | json_object *jgeoip_country = json_object_new_string( GeoIP->country ); 72 | json_object_object_add(jobj_geoip_src,"country", jgeoip_country); 73 | 74 | if ( GeoIP->city[0] != '\0' ) 75 | { 76 | json_object *jgeoip_city = json_object_new_string( GeoIP->city ); 77 | json_object_object_add(jobj_geoip_src,"city", jgeoip_city); 78 | } 79 | 80 | if ( GeoIP->subdivision[0] != '\0' ) 81 | { 82 | json_object *jgeoip_subdivision = json_object_new_string( GeoIP->subdivision ); 83 | json_object_object_add(jobj_geoip_src,"subdivision", jgeoip_subdivision); 84 | } 85 | 86 | if ( GeoIP->postal[0] != '\0' ) 87 | { 88 | json_object *jgeoip_postal = json_object_new_string( GeoIP->postal ); 89 | json_object_object_add(jobj_geoip_src,"postal", jgeoip_postal); 90 | } 91 | 92 | if ( GeoIP->timezone[0] != '\0' ) 93 | { 94 | json_object *jgeoip_timezone = json_object_new_string( GeoIP->timezone ); 95 | json_object_object_add(jobj_geoip_src,"timezone", jgeoip_timezone); 96 | } 97 | 98 | if ( GeoIP->longitude[0] != '\0' ) 99 | { 100 | json_object *jgeoip_longitude = json_object_new_string( GeoIP->longitude ); 101 | json_object_object_add(jobj_geoip_src,"longitude", jgeoip_longitude); 102 | } 103 | 104 | if ( GeoIP->latitude[0] != '\0' ) 105 | { 106 | json_object *jgeoip_latitude = json_object_new_string( GeoIP->latitude ); 107 | json_object_object_add(jobj_geoip_src,"latitude", jgeoip_latitude); 108 | } 109 | 110 | json_object_object_add(json_obj, "geoip_src", jobj_geoip_src); 111 | 112 | } 113 | 114 | /*****************************************/ 115 | /* Get dest_ip GeoIP information (reset) */ 116 | /*****************************************/ 117 | 118 | memset(GeoIP, 0, sizeof(_GeoIP)); 119 | 120 | GeoIP_Lookup( dest_ip, GeoIP ); 121 | 122 | if ( GeoIP->country[0] != '\0' ) 123 | { 124 | 125 | struct json_object *jobj_geoip_dest = NULL; 126 | jobj_geoip_dest = json_object_new_object(); 127 | 128 | json_object *jgeoip_country = json_object_new_string( GeoIP->country ); 129 | json_object_object_add(jobj_geoip_dest,"country", jgeoip_country); 130 | 131 | if ( GeoIP->city[0] != '\0' ) 132 | { 133 | json_object *jgeoip_city = json_object_new_string( GeoIP->city ); 134 | json_object_object_add(jobj_geoip_dest,"city", jgeoip_city); 135 | } 136 | 137 | if ( GeoIP->subdivision[0] != '\0' ) 138 | { 139 | json_object *jgeoip_subdivision = json_object_new_string( GeoIP->subdivision ); 140 | json_object_object_add(jobj_geoip_dest,"subdivision", jgeoip_subdivision); 141 | } 142 | 143 | if ( GeoIP->postal[0] != '\0' ) 144 | { 145 | json_object *jgeoip_postal = json_object_new_string( GeoIP->postal ); 146 | json_object_object_add(jobj_geoip_dest,"postal", jgeoip_postal); 147 | } 148 | 149 | if ( GeoIP->timezone[0] != '\0' ) 150 | { 151 | json_object *jgeoip_timezone = json_object_new_string( GeoIP->timezone ); 152 | json_object_object_add(jobj_geoip_dest,"timezone", jgeoip_timezone); 153 | } 154 | 155 | if ( GeoIP->longitude[0] != '\0' ) 156 | { 157 | json_object *jgeoip_longitude = json_object_new_string( GeoIP->longitude ); 158 | json_object_object_add(jobj_geoip_dest,"longitude", jgeoip_longitude); 159 | } 160 | 161 | if ( GeoIP->latitude[0] != '\0' ) 162 | { 163 | json_object *jgeoip_latitude = json_object_new_string( GeoIP->latitude ); 164 | json_object_object_add(jobj_geoip_dest,"latitude", jgeoip_latitude); 165 | } 166 | 167 | json_object_object_add(json_obj, "geoip_dest", jobj_geoip_dest); 168 | 169 | } 170 | 171 | snprintf(str, MeerConfig->payload_buffer_size, "%s", (char*)json_object_to_json_string(json_obj) ); 172 | free(GeoIP); 173 | 174 | } 175 | 176 | #endif 177 | -------------------------------------------------------------------------------- /src/get-geoip.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Get_GeoIP( struct json_object *json_obj, char *str, const char *src_ip, const char *dest_ip ); 22 | -------------------------------------------------------------------------------- /src/get-oui.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Get_OUI( struct json_object *json_obj, char *str ); 22 | 23 | -------------------------------------------------------------------------------- /src/input-plugins/commandline.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or 7 | ** distribute this program under any other version of the GNU General 8 | ** Public License. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | /* --file command line for normal and gzip files */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #ifdef HAVE_CONFIG_H 30 | #include "config.h" /* From autoconf */ 31 | #endif 32 | 33 | #ifdef HAVE_LIBZ 34 | #include 35 | #endif 36 | 37 | #include "meer.h" 38 | #include "meer-def.h" 39 | #include "util.h" 40 | 41 | #include "input-plugins/commandline.h" 42 | 43 | extern struct _MeerConfig *MeerConfig; 44 | 45 | void Command_Line() 46 | { 47 | 48 | glob_t globbuf = {0}; 49 | 50 | Meer_Log(NORMAL, "--[ Command line - file input information ]--------------------------------------"); 51 | Meer_Log(NORMAL, ""); 52 | 53 | glob(MeerConfig->command_line, GLOB_DOOFFS, NULL, &globbuf); 54 | 55 | for (size_t z = 0; z != globbuf.gl_pathc; ++z) 56 | { 57 | 58 | if ( globbuf.gl_pathv[z][ strlen(globbuf.gl_pathv[z]) - 3 ] == '.' && 59 | globbuf.gl_pathv[z][ strlen(globbuf.gl_pathv[z]) - 2 ] == 'g' && 60 | globbuf.gl_pathv[z][ strlen(globbuf.gl_pathv[z]) - 1 ] == 'z' ) 61 | { 62 | #ifdef HAVE_LIBZ 63 | GZIP_Input( globbuf.gl_pathv[z] ); 64 | #endif 65 | 66 | #ifndef HAVE_LIBZ 67 | Meer_Log(WARN, "[%s, line %d] Meer lacks gzip/libz support. Skipping %s.", __FILE__, __LINE__, globbuf.gl_pathv[z]); 68 | #endif 69 | } 70 | else 71 | { 72 | Read_File( globbuf.gl_pathv[z] ); 73 | } 74 | } 75 | 76 | Meer_Log(NORMAL, "Done processing all files."); 77 | 78 | } 79 | 80 | #ifdef HAVE_LIBZ 81 | 82 | void GZIP_Input( const char *filename ) 83 | { 84 | 85 | uint64_t linecount = 0; 86 | 87 | gzFile fd; 88 | 89 | if (( fd = gzopen(filename, "rb")) == NULL ) 90 | { 91 | Meer_Log(ERROR, "[%s, line %d] Cannot open %s! [%s]", __FILE__, __LINE__, filename, strerror(errno)); 92 | } 93 | 94 | Meer_Log(NORMAL, "Successfully opened GZIP file %s.... processing.....", filename); 95 | 96 | char *buf = malloc(MeerConfig->payload_buffer_size); 97 | 98 | if ( buf == NULL ) 99 | { 100 | fprintf(stderr, "[%s, line %d] Fatal Error: Can't allocate memory for buf! Abort!\n", __FILE__, __LINE__); 101 | exit(-1); 102 | } 103 | 104 | 105 | while(gzgets(fd, buf, MeerConfig->payload_buffer_size) != NULL) 106 | { 107 | 108 | if ( Validate_JSON_String( buf ) == 0 ) 109 | { 110 | Decode_JSON( buf ); 111 | } 112 | 113 | linecount++; 114 | 115 | } 116 | 117 | Meer_Log(NORMAL, "Done with %s. Processed %"PRIu64 " lines", filename, linecount); 118 | 119 | free(buf); 120 | 121 | gzclose(fd); 122 | } 123 | 124 | #endif 125 | 126 | 127 | void Read_File( const char *filename ) 128 | { 129 | 130 | FILE *fd_file; 131 | 132 | struct stat st; 133 | 134 | bool skip_flag = 0; 135 | bool wait_flag = false; 136 | 137 | uint64_t linecount = 0; 138 | 139 | /* DEBUG: This never gets hit!??! */ 140 | 141 | if ( ( fd_file = fopen("whatever", "r" )) == NULL ) 142 | { 143 | Meer_Log(ERROR, "[%s, line %d] Cannot open %s [%s]", __FILE__, __LINE__, filename, strerror(errno)); 144 | } 145 | 146 | char *buf = malloc(MeerConfig->payload_buffer_size); 147 | 148 | if ( buf == NULL ) 149 | { 150 | fprintf(stderr, "[%s, line %d] Fatal Error: Can't allocate memory for buf! Abort!\n", __FILE__, __LINE__); 151 | exit(-1); 152 | } 153 | 154 | Meer_Log(NORMAL, "Processing %s......", filename); 155 | 156 | while(fgets(buf, MeerConfig->payload_buffer_size, fd_file) != NULL) 157 | { 158 | 159 | if ( Validate_JSON_String( buf ) == 0 ) 160 | { 161 | Decode_JSON( buf ); 162 | } 163 | 164 | linecount++; 165 | 166 | } 167 | 168 | Meer_Log(NORMAL, "Done with %s. Processed %"PRIu64 " lines", filename, linecount); 169 | 170 | free(buf); 171 | fclose(fd_file); 172 | 173 | } 174 | -------------------------------------------------------------------------------- /src/input-plugins/commandline.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or 7 | ** distribute this program under any other version of the GNU General 8 | ** Public License. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | 21 | void Command_Line( void ); 22 | void GZIP_Input( const char *input_file ); 23 | void Read_File( const char *filename ); 24 | 25 | -------------------------------------------------------------------------------- /src/input-plugins/file.h: -------------------------------------------------------------------------------- 1 | 2 | void Input_File( void ); 3 | -------------------------------------------------------------------------------- /src/input-plugins/redis.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or 7 | ** distribute this program under any other version of the GNU General 8 | ** Public License. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | /* Redis "input" - Support for "pub/sub" */ 21 | 22 | #ifdef HAVE_CONFIG_H 23 | #include "config.h" /* From autoconf */ 24 | #endif 25 | 26 | #ifdef HAVE_LIBHIREDIS 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "meer-def.h" 38 | #include "meer.h" 39 | #include "util.h" 40 | #include "util-signal.h" 41 | 42 | #include "input-plugins/redis.h" 43 | 44 | /* Proto for connect callback */ 45 | 46 | void connectCallback(const redisAsyncContext *c, int status); 47 | 48 | extern struct _MeerConfig *MeerConfig; 49 | extern struct _MeerInput *MeerInput; 50 | 51 | /*************************************************************/ 52 | /* onMessage - Call back for what to do with data from Redis */ 53 | /*************************************************************/ 54 | 55 | void onMessage(redisAsyncContext *c, void *reply, void *privdata) 56 | { 57 | 58 | bool skip_flag = false; 59 | 60 | char *buf = malloc(MeerConfig->payload_buffer_size); 61 | 62 | if ( buf == NULL ) 63 | { 64 | Meer_Log(ERROR, "[%s, line %d] Fatal Error: Can't allocate memory for buf! Abort!\n", __FILE__, __LINE__); 65 | } 66 | 67 | memset(buf, 0, MeerConfig->payload_buffer_size); 68 | 69 | redisReply *r = reply; 70 | 71 | /* Can't allocate for reply */ 72 | 73 | if (reply == NULL) 74 | { 75 | Meer_Log(WARN, "[%s, line %d] Can't allocate memory for reply!", __FILE__, __LINE__); 76 | free(buf); 77 | return; 78 | } 79 | 80 | 81 | /* Get array of data */ 82 | 83 | if (r->type == REDIS_REPLY_ARRAY) 84 | { 85 | 86 | if ( r->element[2]->str != NULL ) 87 | { 88 | 89 | 90 | snprintf(buf, MeerConfig->payload_buffer_size, "%s\n", r->element[2]->str); 91 | buf[ MeerConfig->payload_buffer_size -1 ] = '\0'; 92 | 93 | skip_flag = Validate_JSON_String( buf ); 94 | 95 | if ( skip_flag == 0 ) 96 | { 97 | Decode_JSON( buf ); 98 | } 99 | 100 | } 101 | } 102 | 103 | free(buf); 104 | } 105 | 106 | 107 | void Input_Redis_Subscribe( void ) 108 | { 109 | 110 | char tmp_command[512] = { 0 }; 111 | 112 | struct event_base *base = event_base_new(); 113 | 114 | redisAsyncContext *c = redisAsyncConnect(MeerInput->redis_server, MeerInput->redis_port); 115 | 116 | if (c->err) 117 | { 118 | Meer_Log(WARN, "[%s, line %d] Redis error: %s", __FILE__, __LINE__, c->errstr); 119 | redisAsyncFree(c); 120 | return; 121 | } 122 | 123 | 124 | if ( MeerInput->redis_password[0] != '\0' ) 125 | { 126 | 127 | if ( redisAsyncCommand( c, NULL, NULL, "AUTH %s", MeerInput->redis_password) != REDIS_OK ) 128 | { 129 | Meer_Log(ERROR, "ERROR LOGGING IN\n"); 130 | } 131 | 132 | } 133 | 134 | 135 | snprintf(tmp_command, sizeof(tmp_command), "SUBSCRIBE %s", MeerInput->redis_key); 136 | tmp_command[ sizeof(tmp_command) - 1 ] = '\0'; 137 | 138 | redisLibeventAttach(c, base); 139 | redisAsyncSetConnectCallback(c,connectCallback); 140 | 141 | redisAsyncCommand( c, onMessage, NULL, tmp_command ); 142 | 143 | event_base_dispatch(base); 144 | 145 | event_base_free(base); 146 | 147 | return; 148 | 149 | } 150 | 151 | 152 | void connectCallback(const redisAsyncContext *c, int status) 153 | { 154 | if (status != REDIS_OK) 155 | { 156 | printf("Error: %s\n", c->errstr); 157 | return; 158 | } 159 | Meer_Log(NORMAL, "Connected and streaming data from \"%s\".....", MeerInput->redis_key ); 160 | } 161 | 162 | //void disconnectCallback(const redisAsyncContext *c, int status) { 163 | // if (status != REDIS_OK) { 164 | // printf("Error: %s\n", c->errstr); 165 | // return; 166 | // } 167 | 168 | // Meer_Log(NORMAL, "Disconnect from stream \"%s\"", MeerInput->redis_key ); 169 | 170 | //} 171 | 172 | #endif 173 | 174 | -------------------------------------------------------------------------------- /src/input-plugins/redis.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Input_Redis_Subscribe( void ); 22 | -------------------------------------------------------------------------------- /src/lockfile.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | /* Lock file routines */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" /* From autoconf */ 25 | #endif 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "meer.h" 37 | #include "meer-def.h" 38 | #include "lockfile.h" 39 | 40 | extern struct _MeerConfig *MeerConfig; 41 | 42 | void CheckLockFile ( void ) 43 | { 44 | 45 | char buf[10]; 46 | FILE *lck; 47 | int pid; 48 | struct stat lckcheck; 49 | 50 | /* Check for lockfile first */ 51 | 52 | if (stat(MeerConfig->lock_file, &lckcheck) == 0 ) 53 | { 54 | 55 | /* Lock file is present, open for read */ 56 | 57 | if (( lck = fopen(MeerConfig->lock_file, "r" )) == NULL ) 58 | { 59 | Meer_Log(ERROR, "[%s, line %d] Lock file '%s' is present but can't be read [%s]", __FILE__, __LINE__, MeerConfig->lock_file, strerror(errno)); 60 | } 61 | else 62 | { 63 | if (!fgets(buf, sizeof(buf), lck)) 64 | { 65 | Meer_Log(ERROR, "[%s, line %d] Lock file (%s) is open for reading, but can't read contents.", __FILE__, __LINE__, MeerConfig->lock_file); 66 | } 67 | 68 | fclose(lck); 69 | pid = atoi(buf); 70 | 71 | if ( pid == 0 ) 72 | { 73 | Meer_Log(ERROR, "[%s, line %d] Lock file read but pid value is zero. Aborting.....", __FILE__, __LINE__); 74 | } 75 | 76 | /* Check to see if process is running. We use kill with 0 signal 77 | * to determine this. We check this return value. Signal 0 78 | * won't affect running processes */ 79 | 80 | if ( kill(pid, 0) != -1 ) 81 | { 82 | Meer_Log(ERROR, "[%s, line %d] It appears that Meer is already running (pid: %d).", __FILE__, __LINE__, pid); 83 | } 84 | else 85 | { 86 | 87 | Meer_Log(NORMAL, "Lock file is present, but Meer isn't at pid %d (Removing stale %s file)", pid, MeerConfig->lock_file); 88 | 89 | if (unlink(MeerConfig->lock_file)) 90 | { 91 | Meer_Log(ERROR, "Unable to unlink %s.", MeerConfig->lock_file); 92 | } 93 | } 94 | } 95 | } 96 | else 97 | { 98 | 99 | /* No lock file present, so create it */ 100 | 101 | if (( lck = fopen(MeerConfig->lock_file, "w" )) == NULL ) 102 | { 103 | Meer_Log(ERROR, "[%s, line %d] Cannot create lock file (%s - %s)", __FILE__, __LINE__, MeerConfig->lock_file, strerror(errno)); 104 | } 105 | else 106 | { 107 | fprintf(lck, "%d", getpid() ); 108 | fflush(lck); 109 | fclose(lck); 110 | } 111 | } 112 | } 113 | 114 | void Remove_Lock_File ( void ) 115 | { 116 | 117 | struct stat lckcheck; 118 | 119 | if ( (stat(MeerConfig->lock_file, &lckcheck) == 0) && unlink(MeerConfig->lock_file) != 0 ) 120 | { 121 | Meer_Log(ERROR, "[%s, line %d] Cannot remove lock file (%s - %s)", __FILE__, __LINE__, MeerConfig->lock_file, strerror(errno)); 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /src/lockfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Remove_Lock_File ( void ); 22 | void CheckLockFile ( void ); 23 | 24 | -------------------------------------------------------------------------------- /src/meer-def.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #define DEFAULT_CONFIG "/usr/local/etc/meer.yaml" 26 | 27 | #define BUFFER_SIZE 10240 28 | 29 | #define MEER_LOG "/var/log/meer.log" 30 | 31 | #define BAD_IP "127.127.127.127" 32 | #define MEER_DESC "My Awesome Sensor" 33 | 34 | #define NORMAL 0 35 | #define ERROR 1 36 | #define WARN 2 37 | #define DEBUG 3 38 | 39 | #define TCP 6 40 | #define UDP 17 41 | #define ICMP 1 42 | 43 | #define SSH_SERVER 0 44 | #define SSH_CLIENT 1 45 | 46 | #define MAXIP 64 /* Max IP length */ 47 | #define MAXIPBIT 16 /* Max IP length in bytes */ 48 | 49 | #define IPv4 4 50 | #define IPv6 6 51 | 52 | #define DNS_CACHE_DEFAULT 900 53 | #define DNS_LOOKUP_TYPES "alert,ssh,http,rdp,ftp" 54 | #define DNS_MAX_TYPES 20 55 | #define DNS_MAX_TYPES_LEN 16 56 | 57 | #define PACKET_BUFFER_SIZE_DEFAULT 1048576 58 | 59 | #define SQL_RECONNECT_TIME 10 60 | 61 | #define MAX_SQL_QUERY 10240 + PACKET_BUFFER_SIZE_DEFAULT 62 | 63 | 64 | #define EXTRA_ORIGNAL_CLIENT_IPV4 1 65 | #define EXTRA_ORIGNAL_CLIENT_IPV6 2 66 | #define EXTRA_UNUSED 3 67 | #define EXTRA_GZIP_DECOMPRESSED_DATA 4 68 | #define EXTRA_SMTP_FILENAME 5 69 | #define EXTRA_SMTP_MAIL_FROM 6 70 | #define EXTRA_SMTP_RCPT_TO 7 71 | #define EXTRA_SMTP_EMAIL_HEADERS 8 72 | #define EXTRA_HTTP_URI 9 73 | #define EXTRA_HTTP_HOSTNAME 10 74 | #define EXTRA_IPV6_SOURCE_ADDRESS 11 75 | #define EXTRA_IPV6_DESTINATION_ADDRESS 12 76 | #define EXTRA_NORMALIZED_JAVASCRIPT 13 77 | 78 | #define DEFAULT_PIPE_SIZE 1048576 79 | 80 | #define MAX_REDIS_BATCH 100 81 | #define DEFAULT_REDIS_KEY "suricata" 82 | 83 | #define MAX_ELASTICSEARCH_BATCH 10000 84 | 85 | #define FINGERPRINT_REDIS_KEY "fingerprint" 86 | #define FINGERPRINT_REDIS_EXPIRE 3600 87 | #define FINGERPRINT_DHCP_REDIS_EXPIRE 86400 88 | #define FINGERPRINT_IP_REDIS_EXPIRE 86400 89 | #define FINGERPRINT_EVENT_REDIS_EXPIRE 86400 90 | 91 | #define MEER_USER_AGENT "User-Agent: Meer" 92 | #define MEER_BLUEDOT_SOURCE "Meer" 93 | 94 | #define MD5_SIZE 33 95 | #define SHA1_SIZE 41 96 | #define SHA256_SIZE 65 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/ndp-collector.h: -------------------------------------------------------------------------------- 1 | /* ** Copyright (C) 2018-2023 Quadrant Information Security ** Copyright (C) 2018-2023 Champ Clark III ** ** This program is free software; you can redistribute it and/or modify 2 | ** it under the terms of the GNU General Public License Version 2 as 3 | ** published by the Free Software Foundation. You may not use, modify or 4 | ** distribute this program under any other version of the GNU General 5 | ** Public License. 6 | ** 7 | ** This program is distributed in the hope that it will be useful, 8 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | ** GNU General Public License for more details. 11 | ** 12 | ** You should have received a copy of the GNU General Public License 13 | ** along with this program; if not, write to the Free Software 14 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15 | */ 16 | 17 | typedef struct _NDP_SMB_Commands _NDP_SMB_Commands; 18 | struct _NDP_SMB_Commands 19 | { 20 | char command[32]; 21 | }; 22 | 23 | typedef struct _NDP_FTP_Commands _NDP_FTP_Commands; 24 | struct _NDP_FTP_Commands 25 | { 26 | char command[5]; 27 | }; 28 | 29 | 30 | bool NDP_In_Range( char *ip_address ); 31 | void NDP_Collector( struct json_object *json_obj, const char *json_string, const char *event_type, const char *src_ip, const char *dest_ip, const char *flow_id ); 32 | void NDP_Flow( struct json_object *json_obj, const char *src_ip, const char *dest_ip, const char *flow_id ); 33 | void NDP_FileInfo( struct json_object *json_obj, const char *src_ip, const char *dest_ip, const char *flow_id ); 34 | void NDP_TLS( struct json_object *json_obj, const char *src_ip, const char *dest_ip, const char *flow_id ); 35 | void NDP_DNS( struct json_object *json_obj, const char *src_ip, const char *dest_ip, const char *flow_id ); 36 | void NDP_SSH( struct json_object *json_obj, const char *src_ip, const char *dest_ip, const char *flow_id ); 37 | void NDP_HTTP( struct json_object *json_obj, const char *src_ip, const char *dest_ip, const char *flow_id ); 38 | void NDP_SMB( struct json_object *json_obj, const char *src_ip, const char *dest_ip, const char *flow_id ); 39 | void NDP_FTP( struct json_object *json_obj, const char *src_ip, const char *dest_ip, const char *flow_id ); 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/oui.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | 22 | /* Lookup routines for MAC address / vender */ 23 | 24 | #ifdef HAVE_CONFIG_H 25 | #include "config.h" /* From autoconf */ 26 | #endif 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "meer.h" 34 | #include "meer-def.h" 35 | #include "util.h" 36 | #include "oui.h" 37 | 38 | extern struct _MeerCounters *MeerCounters; 39 | extern struct _MeerConfig *MeerConfig; 40 | 41 | struct _Manfact_Struct *MF_Struct = NULL; 42 | 43 | /*****************************************************************************/ 44 | /* Load MAC/Vendor information into memory. This list is from the Wireshark */ 45 | /* team. Get it: */ 46 | /* https://gitlab.com/wireshark/wireshark/raw/master/manuf */ 47 | /* The list need to be in the wireshark format! */ 48 | /*****************************************************************************/ 49 | 50 | void Load_OUI( void ) 51 | { 52 | 53 | char buf[1024] = { 0 }; 54 | char *saveptr = NULL; 55 | 56 | char *mac = NULL; 57 | char *short_manfact = NULL; 58 | char *long_manfact = NULL; 59 | 60 | int linecount = 0; 61 | 62 | FILE *mf; 63 | 64 | if (( mf = fopen(MeerConfig->oui_filename, "r" )) == NULL ) 65 | { 66 | Meer_Log(ERROR, "[%s, line %d] Cannot open rule file %s. [%s]", __FILE__, __LINE__, MeerConfig->oui_filename, strerror(errno) ); 67 | } 68 | 69 | while(fgets(buf, sizeof(buf), mf) != NULL) 70 | { 71 | 72 | linecount++; 73 | 74 | /* Skip comments, etc */ 75 | 76 | if (buf[0] == '#' || buf[0] == 10 || buf[0] == ';' || buf[0] == 32) 77 | { 78 | continue; 79 | } 80 | 81 | buf[ strlen(buf) - 1 ] = '\0'; /* Remove return */ 82 | 83 | /* Pull in all values */ 84 | 85 | mac = strtok_r(buf, "\t", &saveptr); 86 | short_manfact = strtok_r(NULL, "\t", &saveptr); 87 | long_manfact = strtok_r(NULL, "\t", &saveptr); 88 | 89 | /* mac / short_manfact should _always be there. long_manfact isn't 90 | always there */ 91 | 92 | if ( mac == NULL || short_manfact == NULL ) 93 | { 94 | Meer_Log(ERROR, "[%s, line %d] %s incorrectly formated at line %d", __FILE__, __LINE__, MeerConfig->oui_filename, linecount ); 95 | } 96 | 97 | /* if no long_manfact is present */ 98 | 99 | if ( long_manfact == NULL ) 100 | { 101 | long_manfact = "0"; 102 | } 103 | 104 | /* Allocate memory for classifications, but not comments */ 105 | 106 | MF_Struct = (_Manfact_Struct *) realloc(MF_Struct, (MeerCounters->OUICount+1) * sizeof(_Manfact_Struct)); 107 | 108 | if ( MF_Struct == NULL ) 109 | { 110 | Meer_Log(ERROR, "[%s, line %d] Failed to reallocate memory for _Manfact_Struct. Abort!", __FILE__, __LINE__); 111 | } 112 | 113 | memset(&MF_Struct[MeerCounters->OUICount], 0, sizeof(struct _Manfact_Struct)); 114 | 115 | 116 | /* Store into memory the values */ 117 | 118 | strlcpy(MF_Struct[MeerCounters->OUICount].mac, mac, sizeof(MF_Struct[MeerCounters->OUICount].mac)); 119 | strlcpy(MF_Struct[MeerCounters->OUICount].short_manfact, short_manfact, sizeof(MF_Struct[MeerCounters->OUICount].short_manfact)); 120 | strlcpy(MF_Struct[MeerCounters->OUICount].long_manfact, long_manfact, sizeof(MF_Struct[MeerCounters->OUICount].long_manfact)); 121 | 122 | MeerCounters->OUICount++; 123 | 124 | } 125 | 126 | Meer_Log(NORMAL, "Loaded %d entries from OUI database [%s].", MeerCounters->OUICount, MeerConfig->oui_filename); 127 | 128 | } 129 | 130 | 131 | /**************************************************************/ 132 | /* OUI_Lookup - looks up a MAC address and returns the vender */ 133 | /**************************************************************/ 134 | 135 | void OUI_Lookup ( char *mac, char *str, size_t size ) 136 | { 137 | 138 | char *s1 = NULL; 139 | char *s2 = NULL; 140 | char *s3 = NULL; 141 | char *saveptr = NULL; 142 | 143 | int i = 0; 144 | 145 | char new_mac[32] = { 0 }; 146 | char search_string[9] = { 0 }; 147 | 148 | /* Convert the MAC to upper case */ 149 | 150 | strlcpy(new_mac, mac, sizeof(new_mac)); 151 | To_UpperC(new_mac); 152 | 153 | /* Break up the MAC ( 00:00:00 ) */ 154 | 155 | s1 = strtok_r(new_mac, ":", &saveptr); 156 | s2 = strtok_r(NULL, ":", &saveptr); 157 | s3 = strtok_r(NULL, ":", &saveptr); 158 | 159 | /* Our new search string */ 160 | 161 | snprintf(search_string, sizeof(search_string), "%s:%s:%s", s1, s2, s3); 162 | search_string[ sizeof(search_string) - 1 ] = '\0'; 163 | 164 | /* See if we can find the MAC address */ 165 | 166 | for ( i = 0; i < MeerCounters->OUICount; i++ ) 167 | { 168 | 169 | if ( !strncmp(search_string, MF_Struct[i].mac, 8) ) 170 | { 171 | 172 | /* By default, return the long_manfact information. If that 173 | isn't present, then return the short_manfact data */ 174 | 175 | if ( MF_Struct[i].long_manfact[0] != '0' ) 176 | { 177 | snprintf(str, size, "%s", MF_Struct[i].long_manfact); 178 | str[ size - 1 ] = '\0'; 179 | return; 180 | } 181 | else 182 | { 183 | snprintf(str, size, "%s", MF_Struct[i].short_manfact); 184 | str[ size - 1 ] = '\0'; 185 | return; 186 | } 187 | 188 | } 189 | 190 | } 191 | 192 | /* Unknown / not found */ 193 | 194 | str[0] = '\0'; 195 | 196 | } 197 | 198 | -------------------------------------------------------------------------------- /src/oui.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | typedef struct _Manfact_Struct _Manfact_Struct; 22 | struct _Manfact_Struct 23 | { 24 | char mac[22]; 25 | char short_manfact[9]; 26 | char long_manfact[128]; 27 | }; 28 | 29 | 30 | void Load_OUI( void ); 31 | void OUI_Lookup ( char *mac, char *str, size_t size ); 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/output-plugins/bluedot.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | /* 22 | * bluedot: 23 | * enabled: yes 24 | * debug: yes 25 | * url: "https://bluedot.quadrantsec.com/insert.php?apikey=KEYHERE" 26 | * insecure: true # Only applied when https is used. 27 | * source: "Field Sensors" 28 | * skip_networks: "10.0.0.0/8,192.168.0.0/16,172.16.0.0/12,12.159.2.0/24,199.188.171.0/27" 29 | * 30 | * 31 | */ 32 | 33 | #ifdef HAVE_CONFIG_H 34 | #include "config.h" /* From autoconf */ 35 | #endif 36 | 37 | #ifdef WITH_BLUEDOT 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | #include 48 | 49 | #include "meer.h" 50 | #include "meer-def.h" 51 | #include "util.h" 52 | #include "bluedot.h" 53 | 54 | extern struct _MeerOutput *MeerOutput; 55 | extern struct _MeerCounters *MeerCounters; 56 | extern struct _Bluedot_Skip *Bluedot_Skip; 57 | 58 | 59 | CURL *curl_bluedot; 60 | struct curl_slist *headers = NULL; 61 | 62 | void Bluedot_Init( void ) 63 | { 64 | 65 | curl_global_init(CURL_GLOBAL_ALL); 66 | curl_bluedot = curl_easy_init(); 67 | 68 | if ( MeerOutput->bluedot_insecure == true ) 69 | { 70 | 71 | curl_easy_setopt(curl_bluedot, CURLOPT_SSL_VERIFYPEER, false); 72 | curl_easy_setopt(curl_bluedot, CURLOPT_SSL_VERIFYHOST, false); 73 | curl_easy_setopt(curl_bluedot, CURLOPT_SSL_VERIFYSTATUS, false); 74 | 75 | } 76 | 77 | if ( MeerOutput->bluedot_debug == true ) 78 | { 79 | curl_easy_setopt(curl_bluedot, CURLOPT_VERBOSE, 1); 80 | curl_easy_setopt(curl_bluedot, CURLOPT_NOBODY, 0); /* Show output for debigging */ 81 | } 82 | else 83 | { 84 | curl_easy_setopt(curl_bluedot, CURLOPT_NOBODY, 1); /* Throw away output */ 85 | } 86 | 87 | 88 | curl_easy_setopt(curl_bluedot, CURLOPT_NOSIGNAL, 1); /* Will send SIGALRM if not set */ 89 | 90 | headers = curl_slist_append (headers, MEER_USER_AGENT); 91 | curl_easy_setopt(curl_bluedot, CURLOPT_HTTPHEADER, headers); 92 | 93 | } 94 | 95 | void Bluedot ( const char *metadata, struct json_object *json_obj ) 96 | { 97 | 98 | char ip[MAXIP] = { 0 }; 99 | char buff[8192] = { 0 }; 100 | unsigned char ip_convert[MAXIPBIT] = { 0 }; 101 | 102 | const char *bluedot = NULL; 103 | const char *alert = NULL; 104 | const char *signature = NULL; 105 | 106 | struct json_object *json_obj_metadata = NULL; 107 | struct json_object *json_obj_alert = NULL; 108 | 109 | struct json_object *tmp = NULL; 110 | 111 | uint32_t i = 0; 112 | 113 | CURLcode res; 114 | 115 | char *source_encoded = NULL; 116 | char *comments_encoded = NULL; 117 | 118 | json_obj_metadata = json_tokener_parse(metadata); 119 | 120 | if (json_object_object_get_ex(json_obj_metadata, "bluedot", &tmp)) 121 | { 122 | bluedot = (char *)json_object_get_string(tmp); 123 | 124 | if ( bluedot == NULL ) 125 | { 126 | json_object_put(json_obj_metadata); 127 | return; 128 | } 129 | 130 | if ( strstr( bluedot, "by_source" ) ) 131 | { 132 | json_object_object_get_ex(json_obj, "src_ip", &tmp); 133 | strlcpy(ip, json_object_get_string(tmp), MAXIP); 134 | } 135 | 136 | else if ( strstr ( bluedot, "by_destination" ) ) 137 | { 138 | json_object_object_get_ex(json_obj, "dest_ip", &tmp); 139 | strlcpy(ip, json_object_get_string(tmp), MAXIP); 140 | } 141 | 142 | } 143 | 144 | /* This should never, ever happen */ 145 | 146 | if ( ip[0] == '\0' ) 147 | { 148 | Meer_Log(WARN, "No 'by_source' or 'by_destination' not found in signature!"); 149 | json_object_put(json_obj_metadata); 150 | return; 151 | } 152 | 153 | json_object_object_get_ex(json_obj, "alert", &tmp); 154 | alert = json_object_get_string(tmp); 155 | 156 | if ( alert == NULL ) 157 | { 158 | Meer_Log(WARN, "No 'alert' data found!"); 159 | json_object_put(json_obj_metadata); 160 | return; 161 | } 162 | 163 | json_obj_alert = json_tokener_parse(alert); 164 | 165 | json_object_object_get_ex(json_obj_alert, "signature", &tmp); 166 | signature = json_object_get_string(tmp); 167 | 168 | if ( signature == NULL ) 169 | { 170 | Meer_Log(WARN, "No 'signature' data found!"); 171 | json_object_put(json_obj_metadata); 172 | json_object_put(json_obj_alert); 173 | return; 174 | } 175 | 176 | IP2Bit( ip, ip_convert ); 177 | 178 | /* Is the IP within the "skip_networks"? Is so, skip it! */ 179 | 180 | for ( i = 0; i < MeerCounters->bluedot_skip_count; i++ ) 181 | { 182 | 183 | if ( Is_Inrange(ip_convert, (unsigned char *)&Bluedot_Skip[i].range, 1) ) 184 | { 185 | 186 | if ( MeerOutput->bluedot_debug == true ) 187 | { 188 | Meer_Log(DEBUG, "IP address %s is in the 'skip_network' range. Skipping!", ip); 189 | } 190 | 191 | json_object_put(json_obj_metadata); 192 | return; 193 | } 194 | 195 | } 196 | 197 | /* We need to encode some data */ 198 | 199 | comments_encoded = curl_easy_escape(curl_bluedot, signature, strlen(signature)); 200 | source_encoded = curl_easy_escape(curl_bluedot, MeerOutput->bluedot_source, strlen(MeerOutput->bluedot_source)); 201 | 202 | snprintf(buff, sizeof(buff), "%s&ip=%s&code=4&comments=%s&source=%s", MeerOutput->bluedot_url,ip, comments_encoded, source_encoded); 203 | 204 | buff[ sizeof(buff) - 1 ] = '\0'; 205 | 206 | curl_easy_setopt(curl_bluedot, CURLOPT_URL, buff); 207 | res = curl_easy_perform(curl_bluedot); 208 | 209 | if(res != CURLE_OK) 210 | { 211 | Meer_Log(WARN, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); 212 | } 213 | 214 | json_object_put(json_obj_metadata); 215 | json_object_put(json_obj_alert); 216 | 217 | } 218 | 219 | #endif 220 | -------------------------------------------------------------------------------- /src/output-plugins/bluedot.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | void Bluedot_Init( void ); 21 | void Bluedot ( const char *metadata, struct json_object *json_obj ); 22 | 23 | typedef struct _Bluedot_Skip _Bluedot_Skip; 24 | struct _Bluedot_Skip 25 | { 26 | 27 | struct 28 | { 29 | unsigned char ipbits[MAXIPBIT]; 30 | unsigned char maskbits[MAXIPBIT]; 31 | } range; 32 | 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /src/output-plugins/elasticsearch.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | 22 | #define MEER_AUTO_AUTH 0 23 | #define MEER_BASIC_AUTH 1 24 | #define MEER_DIGEST_AUTH 2 25 | #define MEER_NTLM_AUTH 3 26 | #define MEER_NEGOTIATE_AUTH 4 27 | 28 | struct MemoryStruct 29 | { 30 | char *memory; 31 | size_t size; 32 | }; 33 | 34 | void Elasticsearch_Init( void ); 35 | void Elasticsearch_Get_Index ( char *str, size_t size, const char *event_type ); 36 | void Elasticsearch( void ); 37 | -------------------------------------------------------------------------------- /src/output-plugins/external.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | /* 22 | * This calls an external program 23 | */ 24 | 25 | #ifdef HAVE_CONFIG_H 26 | #include "config.h" /* From autoconf */ 27 | #endif 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "meer.h" 38 | #include "meer-def.h" 39 | #include "util.h" 40 | 41 | extern struct _MeerOutput *MeerOutput; 42 | extern struct _MeerCounters *MeerCounters; 43 | extern struct _MeerConfig *MeerConfig; 44 | 45 | bool External( const char *json_string ) 46 | { 47 | 48 | int in[2]; 49 | int out[2]; 50 | int pid; 51 | int n; 52 | 53 | char *buf = malloc((MeerConfig->payload_buffer_size)*sizeof(char)); 54 | 55 | if ( buf == NULL ) 56 | { 57 | fprintf(stderr, "[%s, line %d] Fatal Error: Can't allocate memory! Abort!\n", __FILE__, __LINE__); 58 | exit(-1); 59 | } 60 | 61 | 62 | if( File_Check( MeerOutput->external_program ) != 1 ) 63 | { 64 | 65 | Meer_Log(WARN, "Warning! The external program '%s' does not exsist!", MeerOutput->external_program); 66 | MeerCounters->ExternalMissCount++; 67 | free(buf); 68 | return(1); 69 | 70 | } 71 | 72 | if ( pipe(in) < 0 ) 73 | { 74 | Meer_Log(WARN, "[%s, line %d] Cannot create input pipe!", __FILE__, __LINE__); 75 | MeerCounters->ExternalMissCount++; 76 | free(buf); 77 | return(1); 78 | } 79 | 80 | 81 | if ( pipe(out) < 0 ) 82 | { 83 | Meer_Log(WARN, "[%s, line %d] Cannot create output pipe!", __FILE__, __LINE__); 84 | MeerCounters->ExternalMissCount++; 85 | free(buf); 86 | return(1); 87 | } 88 | 89 | pid=fork(); 90 | if ( pid < 0 ) 91 | { 92 | Meer_Log(WARN, "[%s, line %d] Cannot create external program process", __FILE__, __LINE__); 93 | MeerCounters->ExternalMissCount++; 94 | free(buf); 95 | return(1); 96 | } 97 | else if ( pid == 0 ) 98 | { 99 | /* Causes problems with alert.log */ 100 | 101 | 102 | close(0); 103 | close(1); 104 | close(2); 105 | 106 | dup2(in[0],0); 107 | dup2(out[1],1); 108 | dup2(out[1],2); 109 | 110 | close(in[1]); 111 | close(out[0]); 112 | 113 | execl(MeerOutput->external_program, MeerOutput->external_program, NULL, (char *)NULL); 114 | 115 | Meer_Log(WARN, "[%s, line %d] Cannot execute %s", __FILE__, __LINE__, MeerOutput->external_program); 116 | MeerCounters->ExternalMissCount++; 117 | } 118 | 119 | close(in[0]); 120 | close(out[1]); 121 | 122 | /* Write to child input */ 123 | 124 | n = write(in[1], json_string, strlen(json_string)); 125 | n = write(in[1], "\n", 1); /* Take on \n */ 126 | close(in[1]); 127 | 128 | n = read(out[0], buf, sizeof(buf)); 129 | close(out[0]); 130 | buf[n] = 0; 131 | 132 | waitpid(pid, NULL, 0); 133 | 134 | if ( MeerOutput->external_debug ) 135 | { 136 | Meer_Log(DEBUG, "DEBUG: Executed '%s'", MeerOutput->external_program); 137 | } 138 | 139 | MeerCounters->ExternalHitCount++; 140 | 141 | free(buf); 142 | return(0); 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/output-plugins/external.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | bool External( const char *json_string ); 22 | -------------------------------------------------------------------------------- /src/output-plugins/file.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "output-plugins/file.h" 31 | 32 | #include "meer.h" 33 | #include "meer-def.h" 34 | #include "util.h" 35 | 36 | extern struct _MeerOutput *MeerOutput; 37 | 38 | bool Output_Do_File ( const char *json_string ) 39 | { 40 | fprintf(MeerOutput->file_fd, "%s\n", json_string); 41 | fflush(MeerOutput->file_fd); 42 | return(true); 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/output-plugins/file.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | 22 | bool Output_Do_File ( const char *json_string ); 23 | -------------------------------------------------------------------------------- /src/output-plugins/pipe.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | /**************************************************************************** 22 | * This takes input data (JSON) and writes it out to a named pipe/FIFO 23 | ****************************************************************************/ 24 | 25 | #ifdef HAVE_CONFIG_H 26 | #include "config.h" /* From autoconf */ 27 | #endif 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "meer.h" 35 | #include "meer-def.h" 36 | #include "pipe.h" 37 | 38 | extern struct _MeerOutput *MeerOutput; 39 | extern struct _MeerCounters *MeerCounters; 40 | 41 | void Pipe_Write ( const char *json_string ) 42 | { 43 | uint32_t ret = 0; 44 | 45 | ret = write(MeerOutput->pipe_fd, json_string, strlen(json_string)); 46 | 47 | if ( ret < 0 ) 48 | { 49 | Meer_Log(WARN, "Could not write pipe. Error: %s", strerror(errno)); 50 | return; 51 | } 52 | 53 | /* Tack on newline */ 54 | 55 | ret = write(MeerOutput->pipe_fd, "\n", 1); 56 | 57 | if ( ret < 0 ) 58 | { 59 | Meer_Log(WARN, "Could not write pipe. Error: %s", strerror(errno)); 60 | return; 61 | } 62 | 63 | 64 | MeerCounters->JSONPipeWrites++; 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/output-plugins/pipe.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Pipe_Write( const char *json_string ); 22 | 23 | -------------------------------------------------------------------------------- /src/output-plugins/redis.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security ** Copyright (C) 2018-2023 Champ Clark III 3 | ** 4 | ** This program is free software; you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License Version 2 as 6 | ** published by the Free Software Foundation. You may not use, modify or 7 | ** distribute this program under any other version of the GNU General 8 | ** Public License. 9 | ** 10 | ** This program is distributed in the hope that it will be useful, 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ** GNU General Public License for more details. 14 | ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | #define REDIS_PUBSUB 1 21 | 22 | void Redis_Init ( void ); 23 | void Redis_Close ( void ); 24 | void Redis_Connect( void ); 25 | void Redis_Reader ( char *redis_command, char *str, size_t size ); 26 | bool Redis_Writer ( const char *command, const char *key, const char *value, int expire ); 27 | void JSON_To_Redis ( const char *json_string, const char *key ); 28 | 29 | -------------------------------------------------------------------------------- /src/output-plugins/syslog.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #ifdef WITH_SYSLOG 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "output-plugins/syslog.h" 34 | 35 | #include "meer.h" 36 | #include "meer-def.h" 37 | #include "util.h" 38 | 39 | extern struct _MeerOutput *MeerOutput; 40 | 41 | bool Output_Do_Syslog ( const char *json_string, const char *event_type ) 42 | { 43 | 44 | openlog(event_type, MeerOutput->syslog_options, MeerOutput->syslog_facility); 45 | syslog(MeerOutput->syslog_priority, "%s", json_string); 46 | closelog(); 47 | 48 | } 49 | 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/output-plugins/syslog.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | 22 | bool Output_Do_Syslog ( const char *json_string, const char *event_type ); 23 | -------------------------------------------------------------------------------- /src/output.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #include 22 | 23 | void Init_Output( void ); 24 | bool Output_Pipe ( const char *json_string, const char *event_type ); 25 | bool Output_External ( const char *json_string, struct json_object *json_obj, const char *event_type ); 26 | void Output_Bluedot ( struct json_object *json_obj ); 27 | bool Output_Elasticsearch ( const char *json_string, const char *event_type, const char *id ); 28 | bool Output_Do_Elasticsearch ( const char *json_string, const char *event_type, const char *id ); 29 | bool Output_File ( const char *json_string, const char *event_type ); 30 | bool Output_Redis( const char *json_string, const char *event_type ); 31 | bool Output_Syslog ( const char *json_string, const char *event_type ); 32 | 33 | -------------------------------------------------------------------------------- /src/stats.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | /* Display statistics */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" /* From autoconf */ 25 | #endif 26 | 27 | #include 28 | 29 | #include "meer.h" 30 | #include "meer-def.h" 31 | #include "stats.h" 32 | #include "util.h" 33 | #include "config-yaml.h" 34 | 35 | 36 | extern struct _MeerCounters *MeerCounters; 37 | extern struct _MeerWaldo *MeerWaldo; 38 | extern struct _MeerConfig *MeerConfig; 39 | extern struct _MeerOutput *MeerOutput; 40 | extern struct _MeerInput *MeerInput; 41 | 42 | 43 | void Statistics( void ) 44 | { 45 | 46 | /* Idea: Add "JSON per/sec"? */ 47 | 48 | Meer_Log(NORMAL, ""); 49 | Meer_Log(NORMAL, "--[ Meer Statistics ]---------------------------------------"); 50 | Meer_Log(NORMAL, ""); 51 | Meer_Log(NORMAL, " - Decoded Statistics:"); 52 | Meer_Log(NORMAL, ""); 53 | Meer_Log(NORMAL, " Total : %" PRIu64 "", MeerCounters->total); 54 | Meer_Log(NORMAL, " Bad : %" PRIu64 " (%.3f%%)", MeerCounters->bad, CalcPct( MeerCounters->bad, MeerCounters->total ) ); 55 | Meer_Log(NORMAL, ""); 56 | Meer_Log(NORMAL, " alert : %" PRIu64 " (%.3f%%)", MeerCounters->alert, CalcPct( MeerCounters->alert, MeerCounters->total ) ); 57 | Meer_Log(NORMAL, " files : %" PRIu64 " (%.3f%%)", MeerCounters->files, CalcPct( MeerCounters->files, MeerCounters->total ) ); 58 | Meer_Log(NORMAL, " flow : %" PRIu64 " (%.3f%%)", MeerCounters->flow, CalcPct( MeerCounters->flow, MeerCounters->total ) ); 59 | Meer_Log(NORMAL, " dns : %" PRIu64 " (%.3f%%)", MeerCounters->dns, CalcPct( MeerCounters->dns, MeerCounters->total ) ); 60 | Meer_Log(NORMAL, " http : %" PRIu64 " (%.3f%%)", MeerCounters->http, CalcPct( MeerCounters->http, MeerCounters->total ) ); 61 | Meer_Log(NORMAL, " tls : %" PRIu64 " (%.3f%%)", MeerCounters->tls, CalcPct( MeerCounters->tls, MeerCounters->total ) ); 62 | Meer_Log(NORMAL, " ssh : %" PRIu64 " (%.3f%%)", MeerCounters->ssh, CalcPct( MeerCounters->ssh, MeerCounters->total ) ); 63 | Meer_Log(NORMAL, " smtp : %" PRIu64 " (%.3f%%)", MeerCounters->smtp, CalcPct( MeerCounters->smtp, MeerCounters->total ) ); 64 | Meer_Log(NORMAL, " email : %" PRIu64 " (%.3f%%)", MeerCounters->email, CalcPct( MeerCounters->email, MeerCounters->total ) ); 65 | Meer_Log(NORMAL, " fileinfo : %" PRIu64 " (%.3f%%)", MeerCounters->fileinfo, CalcPct( MeerCounters->fileinfo, MeerCounters->total ) ); 66 | Meer_Log(NORMAL, " dhcp : %" PRIu64 " (%.3f%%)", MeerCounters->dhcp, CalcPct( MeerCounters->dhcp, MeerCounters->total ) ); 67 | Meer_Log(NORMAL, " stats : %" PRIu64 " (%.3f%%)", MeerCounters->stats, CalcPct( MeerCounters->stats, MeerCounters->total ) ); 68 | Meer_Log(NORMAL, " rdp : %" PRIu64 " (%.3f%%)", MeerCounters->rdp, CalcPct( MeerCounters->rdp, MeerCounters->total ) ); 69 | Meer_Log(NORMAL, " sip : %" PRIu64 " (%.3f%%)", MeerCounters->sip, CalcPct( MeerCounters->sip, MeerCounters->total ) ); 70 | Meer_Log(NORMAL, " ftp : %" PRIu64 " (%.3f%%)", MeerCounters->ftp, CalcPct( MeerCounters->ftp, MeerCounters->total ) ); 71 | Meer_Log(NORMAL, " ikev2 : %" PRIu64 " (%.3f%%)", MeerCounters->ikev2, CalcPct( MeerCounters->ikev2, MeerCounters->total ) ); 72 | Meer_Log(NORMAL, " nfs : %" PRIu64 " (%.3f%%)", MeerCounters->nfs, CalcPct( MeerCounters->nfs, MeerCounters->total ) ); 73 | Meer_Log(NORMAL, " tftp : %" PRIu64 " (%.3f%%)", MeerCounters->tftp, CalcPct( MeerCounters->tftp, MeerCounters->total ) ); 74 | Meer_Log(NORMAL, " smb : %" PRIu64 " (%.3f%%)", MeerCounters->smb, CalcPct( MeerCounters->smb, MeerCounters->total ) ); 75 | Meer_Log(NORMAL, " dcerpc : %" PRIu64 " (%.3f%%)", MeerCounters->dcerpc, CalcPct( MeerCounters->dcerpc, MeerCounters->total ) ); 76 | Meer_Log(NORMAL, " mqtt : %" PRIu64 " (%.3f%%)", MeerCounters->mqtt, CalcPct( MeerCounters->mqtt, MeerCounters->total ) ); 77 | Meer_Log(NORMAL, " netflow : %" PRIu64 " (%.3f%%)", MeerCounters->netflow, CalcPct( MeerCounters->netflow, MeerCounters->total ) ); 78 | Meer_Log(NORMAL, " metadata : %" PRIu64 " (%.3f%%)", MeerCounters->metadata, CalcPct( MeerCounters->metadata, MeerCounters->total ) ); 79 | Meer_Log(NORMAL, " dnp3 : %" PRIu64 " (%.3f%%)", MeerCounters->dnp3, CalcPct( MeerCounters->dnp3, MeerCounters->total ) ); 80 | Meer_Log(NORMAL, " anomaly : %" PRIu64 " (%.3f%%)", MeerCounters->anomaly, CalcPct( MeerCounters->anomaly, MeerCounters->total ) ); 81 | Meer_Log(NORMAL, " client_stats : %" PRIu64 " (%.3f%%)", MeerCounters->client_stats, CalcPct( MeerCounters->client_stats, MeerCounters->total ) ); 82 | Meer_Log(NORMAL, " ndp : %" PRIu64 " (%.3f%%)", MeerCounters->ndp, CalcPct( MeerCounters->ndp, MeerCounters->total ) ); 83 | Meer_Log(NORMAL, " ndp skipped : %" PRIu64 " (%.3f%%)", MeerCounters->ndp_skip, CalcPct( MeerCounters->ndp_skip, MeerCounters->total ) ); 84 | 85 | 86 | Meer_Log(NORMAL, ""); 87 | 88 | if ( MeerInput->type == YAML_INPUT_FILE ) 89 | { 90 | Meer_Log(NORMAL, " Waldo Postion : %" PRIu64 "", MeerWaldo->position); 91 | } 92 | 93 | // Meer_Log(NORMAL, " JSON : %" PRIu64 "", MeerCounters->JSONCount); 94 | // Meer_Log(NORMAL, " Invalid JSON : %" PRIu64 " (%.3f%%)", MeerCounters->bad, CalcPct(MeerCounters->JSONCount,MeerCounters->bad)); 95 | 96 | #ifdef BLUEDOT 97 | Meer_Log(NORMAL, " Bluedot : %" PRIu64 "", MeerCounters->bluedot); 98 | #endif 99 | 100 | 101 | Meer_Log(NORMAL, ""); 102 | 103 | if ( MeerConfig->dns == true ) 104 | { 105 | 106 | Meer_Log(NORMAL, " - DNS Statistics:"); 107 | Meer_Log(NORMAL, ""); 108 | Meer_Log(NORMAL, " DNS Lookups : %"PRIu64 "", MeerCounters->DNSCount); 109 | Meer_Log(NORMAL, " DNS Cache Hits: %"PRIu64 " (%.3f%%)", MeerCounters->DNSCacheCount, CalcPct(MeerCounters->DNSCacheCount,MeerCounters->DNSCount)); 110 | Meer_Log(NORMAL, ""); 111 | 112 | } 113 | 114 | if ( MeerOutput->pipe_enabled == true ) 115 | { 116 | 117 | Meer_Log(NORMAL, " - Pipe Statistics:"); 118 | Meer_Log(NORMAL, ""); 119 | Meer_Log(NORMAL, " JSON writes : %"PRIu64 "", MeerCounters->JSONPipeWrites); 120 | Meer_Log(NORMAL, " JSON misses/errors : %"PRIu64 " (%.3f%%)", MeerCounters->JSONPipeMisses, CalcPct(MeerCounters->JSONPipeWrites, MeerCounters->JSONPipeMisses)); 121 | 122 | } 123 | 124 | if ( MeerOutput->external_enabled == true ) 125 | { 126 | 127 | Meer_Log(NORMAL, " - External Statistics:"); 128 | Meer_Log(NORMAL, ""); 129 | Meer_Log(NORMAL, " Success : %"PRIu64 "", MeerCounters->ExternalHitCount); 130 | Meer_Log(NORMAL, " Failures : %"PRIu64 "", MeerCounters->ExternalMissCount); 131 | 132 | } 133 | 134 | 135 | Meer_Log(NORMAL, ""); 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/stats.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Statistics( void ); 22 | -------------------------------------------------------------------------------- /src/usage.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #include 22 | 23 | #include "meer-def.h" 24 | #include "version.h" 25 | 26 | void Usage( void ) 27 | { 28 | 29 | printf("\n"); 30 | printf("@@@@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@ Meer version %s\n", VERSION); 31 | printf("@@! @@! @@! @@! @@! @@! @@@ Quadrant Information Security\n"); 32 | printf("@!! !!@ @!@ @!!!:! @!!!:! @!@!!@a https://quadrantsec.com\n"); 33 | printf("!!: !!: !!: !!: !!: :!a Copyright (C) 2018-2023\n"); 34 | printf(": : : :: :: : :: :: : : :\n\n"); 35 | 36 | printf("-D, --dameon\t\tPut Meer in the background.\n"); 37 | printf("-c, --config\t\tMeer Configuration File [default: %s]\n", DEFAULT_CONFIG); 38 | printf("-h, --help\t\tMeer help screen.\n"); 39 | printf("-q, --quiet\t\tTell Meer to be quiet.\n"); 40 | printf("-f, --file\t\tGrab files, process them and store the results.\n"); 41 | printf("\nMeer was compile on %s at %s.\n", __DATE__, __TIME__); 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/usage.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Usage( void ); 22 | -------------------------------------------------------------------------------- /src/util-base64.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "util-base64.h" 31 | 32 | #define ASCII_BLOCK 3 33 | #define B64_BLOCK 4 34 | #define BASE64_TABLE_MAX 122 35 | 36 | static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK]); 37 | static inline int GetBase64Value(uint8_t c); 38 | 39 | 40 | /* Base64 character to index conversion table */ 41 | /* Characters are mapped as "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" */ 42 | 43 | static const int b64table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47 | -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 48 | 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, 49 | -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 50 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 51 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 52 | 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 53 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 54 | 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 55 | 49, 50, 51 56 | }; 57 | 58 | 59 | uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len, 60 | int strict) 61 | { 62 | int val; 63 | uint32_t padding = 0, numDecoded = 0, bbidx = 0, valid = 1, i; 64 | uint8_t *dptr = dest; 65 | uint8_t b64[B64_BLOCK] = { 0,0,0,0 }; 66 | 67 | /* Traverse through each alpha-numeric letter in the source array */ 68 | for(i = 0; i < len && src[i] != 0; i++) 69 | { 70 | 71 | /* Get decimal representation */ 72 | val = GetBase64Value(src[i]); 73 | if (val < 0) 74 | { 75 | 76 | /* Invalid character found, so decoding fails */ 77 | if (src[i] != '=') 78 | { 79 | valid = 0; 80 | if (strict) 81 | { 82 | numDecoded = 0; 83 | } 84 | break; 85 | } 86 | padding++; 87 | } 88 | 89 | /* For each alpha-numeric letter in the source array, find the numeric 90 | * value */ 91 | b64[bbidx++] = (val > 0 ? val : 0); 92 | 93 | /* Decode every 4 base64 bytes into 3 ascii bytes */ 94 | if (bbidx == B64_BLOCK) 95 | { 96 | 97 | /* For every 4 bytes, add 3 bytes but deduct the '=' padded blocks */ 98 | numDecoded += ASCII_BLOCK - (padding < B64_BLOCK ? 99 | padding : ASCII_BLOCK); 100 | 101 | /* Decode base-64 block into ascii block and move pointer */ 102 | DecodeBase64Block(dptr, b64); 103 | dptr += ASCII_BLOCK; 104 | 105 | /* Reset base-64 block and index */ 106 | bbidx = 0; 107 | padding = 0; 108 | } 109 | } 110 | 111 | /* Finish remaining b64 bytes by padding */ 112 | if (valid && bbidx > 0) 113 | { 114 | 115 | /* Decode remaining */ 116 | numDecoded += ASCII_BLOCK - (B64_BLOCK - bbidx); 117 | DecodeBase64Block(dptr, b64); 118 | } 119 | 120 | // if (numDecoded == 0) { 121 | // SCLogDebug("base64 decoding failed"); 122 | // } 123 | 124 | return numDecoded; 125 | } 126 | 127 | 128 | static inline int GetBase64Value(uint8_t c) 129 | { 130 | int val = -1; 131 | 132 | /* Pull from conversion table */ 133 | if (c <= BASE64_TABLE_MAX) 134 | { 135 | val = b64table[(int) c]; 136 | } 137 | 138 | return val; 139 | } 140 | 141 | static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK]) 142 | { 143 | ascii[0] = (uint8_t) (b64[0] << 2) | (b64[1] >> 4); 144 | ascii[1] = (uint8_t) (b64[1] << 4) | (b64[2] >> 2); 145 | ascii[2] = (uint8_t) (b64[2] << 6) | (b64[3]); 146 | } 147 | 148 | -------------------------------------------------------------------------------- /src/util-base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len, int strict); 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/util-dns.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "meer-def.h" 35 | #include "meer.h" 36 | 37 | #include "util-dns.h" 38 | 39 | 40 | extern struct _MeerConfig *MeerConfig; 41 | extern struct _MeerCounters *MeerCounters; 42 | 43 | struct _DnsCache *DnsCache; 44 | uint32_t DnsCacheCount = 0; 45 | 46 | void DNS_Lookup_Reverse( char *host, char *str, size_t size ) 47 | { 48 | 49 | struct sockaddr_in ipaddr; 50 | time_t t; 51 | struct tm *run; 52 | char utime_string[20] = { 0 }; 53 | int i = 0; 54 | 55 | t = time(NULL); 56 | run=localtime(&t); 57 | strftime(utime_string, sizeof(utime_string), "%s", run); 58 | uint64_t utime = atol(utime_string); 59 | 60 | char host_r[NI_MAXHOST] = { 0 }; 61 | 62 | /* Don't return a DNS lookup for the "bad IP" value */ 63 | 64 | if ( !strcmp( host, BAD_IP ) ) 65 | { 66 | str[0] = '\0'; 67 | return; 68 | } 69 | 70 | for (i=0; idns_cache ) 79 | { 80 | 81 | MeerCounters->DNSCacheCount++; 82 | 83 | snprintf(str, size, "%s", DnsCache[i].reverse); 84 | str[ size - 1 ] ='\0'; 85 | return; 86 | 87 | } 88 | else 89 | { 90 | 91 | /* Re-look it up and return it if cache is stale */ 92 | 93 | memset(&ipaddr, 0, sizeof(struct sockaddr_in)); 94 | 95 | ipaddr.sin_family = AF_INET; 96 | ipaddr.sin_port = htons(0); 97 | 98 | inet_pton(AF_INET, host, &ipaddr.sin_addr); 99 | 100 | (void)getnameinfo((struct sockaddr *)&ipaddr, sizeof(struct sockaddr_in), host_r, sizeof(host_r), NULL, 0, NI_NAMEREQD); 101 | 102 | strlcpy(DnsCache[i].reverse, host_r, sizeof(DnsCache[i].reverse)); 103 | DnsCache[i].lookup_time = utime; 104 | 105 | MeerCounters->DNSCount++; 106 | 107 | snprintf(str, size, "%s", DnsCache[i].reverse); 108 | str[ size - 1 ] = '0'; 109 | 110 | return; 111 | } 112 | 113 | } 114 | 115 | } 116 | 117 | memset(&ipaddr, 0, sizeof(struct sockaddr_in)); 118 | 119 | ipaddr.sin_family = AF_INET; 120 | ipaddr.sin_port = htons(0); 121 | 122 | inet_pton(AF_INET, host, &ipaddr.sin_addr); 123 | 124 | (void)getnameinfo((struct sockaddr *)&ipaddr, sizeof(struct sockaddr_in), host_r, sizeof(host_r), NULL, 0, NI_NAMEREQD); 125 | 126 | /* Insert DNS into cache */ 127 | 128 | DnsCache = (_DnsCache *) realloc(DnsCache, (DnsCacheCount+1) * sizeof(_DnsCache)); 129 | 130 | strlcpy(DnsCache[DnsCacheCount].ipaddress, host, sizeof(DnsCache[DnsCacheCount].ipaddress)); 131 | strlcpy(DnsCache[DnsCacheCount].reverse, host_r, sizeof(DnsCache[DnsCacheCount].reverse)); 132 | DnsCache[DnsCacheCount].lookup_time = utime; 133 | 134 | DnsCacheCount++; 135 | MeerCounters->DNSCount++; 136 | 137 | snprintf(str, size, "%s", host_r); 138 | str[ size - 1 ] = '\0'; 139 | 140 | } 141 | 142 | int DNS_Lookup_Forward( const char *host, char *str, size_t size ) 143 | { 144 | 145 | char ipstr[INET6_ADDRSTRLEN] = { 0 }; 146 | 147 | struct addrinfo hints = {0}, *res = NULL; 148 | int status; 149 | void *addr; 150 | 151 | memset(&hints, 0, sizeof hints); 152 | hints.ai_family = AF_UNSPEC; /* AF_INET or AF_INET6 to force version */ 153 | hints.ai_socktype = SOCK_STREAM; 154 | 155 | if ((status = getaddrinfo(host, NULL, &hints, &res)) != 0) 156 | { 157 | 158 | Meer_Log(WARN, "%s: %s", gai_strerror(status), host); 159 | return -1; 160 | 161 | } 162 | 163 | if (res->ai_family == AF_INET) /* IPv4 */ 164 | { 165 | 166 | struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr; 167 | addr = &(ipv4->sin_addr); 168 | 169 | } 170 | else /* IPv6 */ 171 | { 172 | 173 | struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr; 174 | addr = &(ipv6->sin6_addr); 175 | 176 | } 177 | 178 | inet_ntop(res->ai_family, addr, ipstr, sizeof ipstr); 179 | freeaddrinfo(res); 180 | 181 | snprintf(str, size, "%s", ipstr); 182 | str[ size - 1 ] = '\0'; 183 | 184 | return 0; 185 | } 186 | 187 | -------------------------------------------------------------------------------- /src/util-dns.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. ** 15 | ** You should have received a copy of the GNU General Public License 16 | ** along with this program; if not, write to the Free Software 17 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | 21 | typedef struct _DnsCache _DnsCache; 22 | struct _DnsCache 23 | { 24 | char ipaddress[48]; 25 | char reverse[256]; 26 | uint64_t lookup_time; 27 | 28 | }; 29 | 30 | 31 | void DNS_Lookup_Reverse( char *host, char *str, size_t size ); 32 | int DNS_Lookup_Forward( const char *host, char *str, size_t size ); 33 | 34 | -------------------------------------------------------------------------------- /src/util-md5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | void MD5(uint8_t *initial_msg, size_t initial_len, char *str, size_t size) 8 | { 9 | 10 | #define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c)))) 11 | 12 | uint8_t *msg = NULL; 13 | uint32_t h0, h1, h2, h3; 14 | 15 | char digest[41] = { 0 }; 16 | char tmp[9] = { 0 }; 17 | 18 | // Note: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating 19 | 20 | // r specifies the per-round shift amounts 21 | 22 | uint32_t r[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 23 | 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 24 | 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 25 | 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 26 | }; 27 | 28 | // Use binary integer part of the sines of integers (in radians) as constants// Initialize variables: 29 | 30 | uint32_t k[] = 31 | { 32 | 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 33 | 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 34 | 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 35 | 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 36 | 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 37 | 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 38 | 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 39 | 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 40 | 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 41 | 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 42 | 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 43 | 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 44 | 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 45 | 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 46 | 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 47 | 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 48 | }; 49 | 50 | h0 = 0x67452301; 51 | h1 = 0xefcdab89; 52 | h2 = 0x98badcfe; 53 | h3 = 0x10325476; 54 | 55 | // Pre-processing: adding a single 1 bit 56 | // append "1" bit to message 57 | /* Notice: the input bytes are considered as bits strings, 58 | where the first bit is the most significant bit of the byte.[37] */ 59 | 60 | // Pre-processing: padding with zeros 61 | // append "0" bit until message length in bit ≡ 448 (mod 512) 62 | // append length mod (2 pow 64) to message 63 | 64 | int new_len = ((((initial_len + 8) / 64) + 1) * 64) - 8; 65 | 66 | msg = calloc(new_len + 64, 1); // also appends "0" bits 67 | // (we alloc also 64 extra bytes...) 68 | memcpy(msg, initial_msg, initial_len); 69 | msg[initial_len] = 128; // write the "1" bit 70 | 71 | uint32_t bits_len = 8*initial_len; // note, we append the len 72 | memcpy(msg + new_len, &bits_len, 4); // in bits at the end of the buffer 73 | 74 | // Process the message in successive 512-bit chunks: 75 | //for each 512-bit chunk of message: 76 | int offset; 77 | for(offset=0; offset 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "meer.h" 34 | #include "meer-def.h" 35 | #include "config-yaml.h" 36 | #include "lockfile.h" 37 | #include "stats.h" 38 | #include "waldo.h" 39 | #include "config-yaml.h" 40 | 41 | #if defined(WITH_BLUEDOT) || defined(WITH_ELASTICSEARCH) 42 | #include 43 | #endif 44 | 45 | #ifdef WITH_ELASTICSEARCH 46 | #include 47 | bool elasticsearch_death = false; 48 | uint8_t elasticsearch_death_count = 0; 49 | extern uint_fast16_t elastic_proc_running; 50 | extern char *big_batch; 51 | extern char *big_batch_THREAD; 52 | #endif 53 | 54 | #ifdef HAVE_LIBHIREDIS 55 | #include 56 | #endif 57 | 58 | #ifdef WITH_BLUEDOT 59 | #include 60 | extern CURL *curl_bluedot; 61 | #endif 62 | 63 | extern struct _MeerWaldo *MeerWaldo; 64 | extern struct _MeerConfig *MeerConfig; 65 | extern struct _MeerOutput *MeerOutput; 66 | extern struct _MeerInput *MeerInput; 67 | 68 | void Signal_Handler(int sig_num) 69 | { 70 | 71 | Meer_Log(NORMAL, "Got signal %d!", sig_num); 72 | 73 | switch( sig_num ) 74 | { 75 | 76 | /* exit */ 77 | 78 | case SIGQUIT: 79 | case SIGINT: 80 | case SIGTERM: 81 | // case SIGSEGV: 82 | // case SIGABRT: 83 | 84 | if ( MeerOutput->pipe_enabled == true ) 85 | { 86 | close(MeerOutput->pipe_fd); 87 | } 88 | 89 | #ifdef HAVE_LIBHIREDIS 90 | 91 | if ( MeerOutput->redis_enabled == true ) 92 | { 93 | Redis_Close(); 94 | } 95 | 96 | #endif 97 | 98 | 99 | #ifdef WITH_ELASTICSEARCH 100 | 101 | if ( MeerOutput->elasticsearch_enabled == true ) 102 | { 103 | 104 | elasticsearch_death = true; 105 | elasticsearch_death_count = 0; 106 | 107 | while ( elastic_proc_running != 0 ) 108 | { 109 | Meer_Log(NORMAL, "Waiting on %d Elasticseach thread to shutdown.", elastic_proc_running); 110 | sleep(1); 111 | 112 | if ( elasticsearch_death_count == 15 ) 113 | { 114 | Meer_Log(WARN, "Timemout reached! Forcing shutdown."); 115 | break; 116 | } 117 | 118 | elasticsearch_death_count++; 119 | 120 | } 121 | 122 | if ( elastic_proc_running == 0 ) 123 | { 124 | free( big_batch ); 125 | free( big_batch_THREAD); 126 | } 127 | 128 | } 129 | 130 | #endif 131 | 132 | /* Some gymnastics to cleanup libcurl */ 133 | 134 | #if defined(WITH_BLUEDOT) || defined(WITH_ELASTICSEARCH) 135 | 136 | bool clean_up = false; 137 | 138 | #ifdef WITH_BLUEDOT 139 | 140 | if ( MeerOutput->bluedot_flag == true ) 141 | { 142 | curl_global_cleanup(); 143 | clean_up = true; 144 | } 145 | 146 | #endif 147 | 148 | #ifdef WITH_ELASTICSEARCH 149 | 150 | if ( MeerOutput->elasticsearch_enabled == true && clean_up == false ) 151 | { 152 | curl_global_cleanup(); 153 | } 154 | #endif 155 | 156 | #endif 157 | 158 | if ( MeerOutput->file_enabled == true ) 159 | { 160 | fflush(MeerOutput->file_fd); 161 | fclose(MeerOutput->file_fd); 162 | } 163 | 164 | 165 | 166 | Remove_Lock_File(); 167 | 168 | Statistics(); 169 | 170 | 171 | if ( MeerInput->type == YAML_INPUT_FILE ) 172 | { 173 | fsync(MeerInput->waldo_fd); 174 | close(MeerInput->waldo_fd); 175 | Waldo_Close(); 176 | } 177 | 178 | Meer_Log(NORMAL, "Shutdown complete."); 179 | 180 | fclose(MeerConfig->meer_log_fd); 181 | fflush(stdout); 182 | 183 | exit(0); 184 | 185 | /* Signals to ignore */ 186 | 187 | case 17: /* Child process has exited. */ 188 | case 28: /* Terminal 'resize'/alarm. */ 189 | 190 | break; 191 | 192 | case SIGUSR1: 193 | 194 | Statistics(); 195 | break; 196 | 197 | case SIGUSR2: 198 | 199 | Statistics(); 200 | break; 201 | 202 | case SIGPIPE: 203 | Meer_Log(NORMAL, "[Received signal %d [SIGPIPE]. Possible incomplete JSON?", sig_num); 204 | break; 205 | 206 | 207 | default: 208 | Meer_Log(NORMAL, "[Received signal %d. Meer doesn't know how to deal with.", sig_num); 209 | } 210 | 211 | } 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /src/util-signal.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Signal_Handler(int sig_num); 22 | 23 | -------------------------------------------------------------------------------- /src/util-strlcat.c: -------------------------------------------------------------------------------- 1 | /* strlcat 2 | * 3 | * Provided by the OpenBSD team. This is here for systems that do not 4 | * support the strlcat call. 5 | * 6 | */ 7 | 8 | 9 | /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ 10 | /* 11 | * Copyright (c) 1998 Todd C. Miller 12 | * 13 | * Permission to use, copy, modify, and distribute this software for any 14 | * purpose with or without fee is hereby granted, provided that the above 15 | * copyright notice and this permission notice appear in all copies. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 18 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 19 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 20 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 21 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 22 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 23 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 24 | */ 25 | 26 | #ifdef HAVE_CONFIG_H 27 | #include "config.h" /* From autoconf */ 28 | #endif 29 | 30 | #ifndef HAVE_STRLCAT 31 | 32 | #include 33 | #include 34 | 35 | /* 36 | * Appends src to string dst of size siz (unlike strncat, siz is the 37 | * full size of dst, not space left). At most siz-1 characters 38 | * will be copied. Always NUL terminates (unless siz <= strlen(dst)). 39 | * Returns strlen(src) + MIN(siz, strlen(initial dst)). 40 | * If retval >= siz, truncation occurred. 41 | */ 42 | size_t 43 | strlcat(char *dst, const char *src, size_t siz) 44 | { 45 | char *d = dst; 46 | const char *s = src; 47 | size_t n = siz; 48 | size_t dlen; 49 | 50 | /* Find the end of dst and adjust bytes left but don't go past end */ 51 | while (n-- != 0 && *d != '\0') 52 | d++; 53 | dlen = d - dst; 54 | n = siz - dlen; 55 | 56 | if (n == 0) 57 | return(dlen + strlen(s)); 58 | while (*s != '\0') 59 | { 60 | if (n != 1) 61 | { 62 | *d++ = *s; 63 | n--; 64 | } 65 | s++; 66 | } 67 | *d = '\0'; 68 | 69 | return(dlen + (s - src)); /* count does not include NUL */ 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/util-strlcpy.c: -------------------------------------------------------------------------------- 1 | /* strlcpy 2 | * 3 | * Provided by the OpenBSD team. This file is here for systems that 4 | * do not support the strlcpy call. 5 | * 6 | */ 7 | 8 | /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ 9 | 10 | /* 11 | * Copyright (c) 1998 Todd C. Miller 12 | * 13 | * Permission to use, copy, modify, and distribute this software for any 14 | * purpose with or without fee is hereby granted, provided that the above 15 | * copyright notice and this permission notice appear in all copies. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 18 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 19 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 20 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 21 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 22 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 23 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 24 | */ 25 | 26 | #ifdef HAVE_CONFIG_H 27 | #include "config.h" /* From autoconf */ 28 | #endif 29 | 30 | #ifndef HAVE_STRLCPY 31 | 32 | #include 33 | #include 34 | 35 | /* 36 | * Copy src to string dst of size siz. At most siz-1 characters 37 | * will be copied. Always NUL terminates (unless siz == 0). 38 | * Returns strlen(src); if retval >= siz, truncation occurred. 39 | */ 40 | size_t 41 | strlcpy(char *dst, const char *src, size_t siz) 42 | { 43 | char *d = dst; 44 | const char *s = src; 45 | size_t n = siz; 46 | 47 | /* Copy as many bytes as will fit */ 48 | if (n != 0) 49 | { 50 | while (--n != 0) 51 | { 52 | if ((*d++ = *s++) == '\0') 53 | break; 54 | } 55 | } 56 | 57 | /* Not enough room in dst, add NUL and traverse rest of src */ 58 | if (n == 0) 59 | { 60 | if (siz != 0) 61 | *d = '\0'; /* NUL-terminate dst */ 62 | while (*s++) 63 | ; 64 | } 65 | 66 | return(s - src - 1); /* count does not include NUL */ 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #include 22 | #include "meer-def.h" 23 | 24 | typedef struct _Fingerprint_Networks _Fingerprint_Networks; 25 | struct _Fingerprint_Networks 26 | { 27 | 28 | struct 29 | { 30 | unsigned char ipbits[MAXIPBIT]; 31 | unsigned char maskbits[MAXIPBIT]; 32 | } range; 33 | 34 | }; 35 | 36 | typedef struct _NDP_Ignore _NDP_Ignore; 37 | struct _NDP_Ignore 38 | { 39 | 40 | struct 41 | { 42 | unsigned char ipbits[MAXIPBIT]; 43 | unsigned char maskbits[MAXIPBIT]; 44 | } range; 45 | 46 | }; 47 | 48 | void Drop_Priv(void); 49 | bool Check_Endian(void); 50 | char *Hexify(char *xdata, int length); 51 | bool Validate_JSON_String( const char *buf ); 52 | bool IP2Bit(char *ipaddr, unsigned char *out); 53 | bool Mask2Bit(int mask, unsigned char *out); 54 | void Remove_Spaces(char *s); 55 | void Remove_Return(char *s); 56 | uint64_t Current_Epoch( void ); 57 | bool Is_IPv6 (char *ipaddr); 58 | double CalcPct(uint64_t cnt, uint64_t total); 59 | 60 | bool Is_IP (char *ipaddr, int ver ); 61 | int File_Check (char *filename); 62 | bool Is_Inrange ( unsigned char *ip, unsigned char *tests, int count); 63 | void To_UpperC(char *const s); 64 | uint32_t Djb2_Hash(char *str); 65 | void Convert_ISO8601_For_SQL( char *time, char *str, size_t size ); 66 | bool Is_Notroutable ( unsigned char *ip ); 67 | bool Try_And_Fix_IP ( char *orig_ip, char *str, size_t size ); 68 | 69 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #define VERSION "2.1.0" 2 | -------------------------------------------------------------------------------- /src/waldo.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" /* From autoconf */ 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "meer.h" 37 | #include "meer-def.h" 38 | 39 | extern struct _MeerWaldo *MeerWaldo; 40 | //extern struct _MeerConfig *MeerConfig; 41 | extern struct _MeerInput *MeerInput; 42 | 43 | void Waldo_Sync( void ) 44 | { 45 | msync(MeerWaldo, sizeof(_MeerWaldo), MS_ASYNC); 46 | } 47 | 48 | void Waldo_Close( void ) 49 | { 50 | 51 | Waldo_Sync(); 52 | munmap(MeerWaldo, sizeof(_MeerWaldo)); 53 | 54 | } 55 | 56 | void Init_Waldo( void ) 57 | { 58 | 59 | bool new_waldo = false; 60 | 61 | 62 | if (( MeerInput->waldo_fd = open(MeerInput->waldo_file, (O_CREAT | O_EXCL | O_RDWR), (S_IREAD | S_IWRITE))) > 0 ) 63 | { 64 | Meer_Log(NORMAL,"New waldo file created."); 65 | new_waldo = true; 66 | } 67 | 68 | 69 | else if ((MeerInput->waldo_fd = open(MeerInput->waldo_file, (O_CREAT | O_RDWR), (S_IREAD | S_IWRITE))) < 0 ) 70 | { 71 | Meer_Log(ERROR, "[%s, line %d] Cannot open() for waldo '%s' [%s]", __FILE__, __LINE__, MeerInput->waldo_file, strerror(errno)); 72 | } 73 | 74 | if ( ftruncate(MeerInput->waldo_fd, sizeof(_MeerWaldo)) != 0 ) 75 | { 76 | Meer_Log(ERROR, "[%s, line %d] Failed to ftruncate for _MeerWaldo. [%s]", __FILE__, __LINE__, strerror(errno)); 77 | } 78 | 79 | if (( MeerWaldo = mmap(0, sizeof(_MeerWaldo), (PROT_READ | PROT_WRITE), MAP_SHARED, MeerInput->waldo_fd, 0)) == MAP_FAILED ) 80 | { 81 | Meer_Log(ERROR,"[%s, line %d] Error allocating memory for counters object! [%s]", __FILE__, __LINE__, strerror(errno)); 82 | } 83 | 84 | if ( new_waldo == false ) 85 | { 86 | Meer_Log(NORMAL, "Waldo loaded. Current position: %" PRIu64 "", MeerWaldo->position); 87 | } 88 | 89 | Meer_Log(NORMAL, ""); 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/waldo.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2018-2023 Quadrant Information Security 3 | ** Copyright (C) 2018-2023 Champ Clark III 4 | ** 5 | ** This program is free software; you can redistribute it and/or modify 6 | ** it under the terms of the GNU General Public License Version 2 as 7 | ** published by the Free Software Foundation. You may not use, modify or 8 | ** distribute this program under any other version of the GNU General 9 | ** Public License. 10 | ** 11 | ** This program is distributed in the hope that it will be useful, 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ** GNU General Public License for more details. 15 | ** 16 | ** You should have received a copy of the GNU General Public License 17 | ** along with this program; if not, write to the Free Software 18 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 | */ 20 | 21 | void Waldo_Sync( void ); 22 | void Waldo_Close( void ); 23 | void Init_Waldo( void ); 24 | -------------------------------------------------------------------------------- /stamp-h1: -------------------------------------------------------------------------------- 1 | timestamp for config.h 2 | -------------------------------------------------------------------------------- /tools/external/external-program-blocklist/README.md: -------------------------------------------------------------------------------- 1 | # External 2 | 3 | These are a set of simple routines that allow Meer to write out "block lists" 4 | to a MySQL/MariaDB database. The list can then be consumed by other devices 5 | (firewalls for example) as a "block list". 6 | 7 | ## SQL 8 | 9 | SQL database/table for routines to use. To setup, do this: 10 | 11 | $ mysqladmin -u root -p create blocklist 12 | $ mysql -u root -p blocklist < blocklist.sql 13 | 14 | ## Inserting Into SQL 15 | 16 | ### external-program-sql-blocklist.j2 17 | 18 | This is the routine that will be called by Meer's "external" processors. This 19 | needs to be fed "alert" data. 20 | 21 | As provided, it is a Ansible J2 template. 22 | 23 | The following need for it. 24 | 25 | - BLOCKLISTER_USER 26 | - BLOCKLISTER_PASS 27 | - BLOCKLISTER_DB 28 | - BLOCKLISTER_SERVER 29 | - BLOCKLISTER_LOG 30 | - BLOCKLISTER_IGNORE_PORTS 31 | 32 | ## Fetching 33 | 34 | ### blocklist.cgi 35 | 36 | This is the web CGI that "sends" the block list to the "client". As IP 37 | addresses are sent, they are removed. This routines URL is where you would 38 | configured you device to get blocklist. For example: 39 | 40 | http://10.10.10.10/cgi-bin/blocklist.cgi?apikey=yourkeyhere 41 | 42 | The API key is set in the blocklist.cgi routine. This prevents unauthorized 43 | access to you block lists. 44 | 45 | This script will also remove the entries when fetched. 46 | 47 | Any subnets in `/usr/local/etc/blocklister_ignore_subnets` will be ignored. 48 | 49 | ### blocklister.j2 50 | 51 | Generates a size limited list of IPs and subnets for use with like Fortigates. 52 | 53 | Unlike blocklist.cgi, this script builds a list of nets to ignore. Where possible 54 | if a set of IPs can be collapsed into a full subnet they will. Any subnets ending in 55 | `/32` or `/128` have the netmask removed to save space as it is just a IP. 56 | 57 | If the size execeds the max allowable size, the oldest entry will be removed and it 58 | will try again. It will do this till it gets down to a max size. 59 | 60 | As provided it is a Ansible J2 template. The following keys below are used. 61 | 62 | - BLOCKLISTER_DB 63 | - BLOCKLISTER_SERVER 64 | - BLOCKLISTER_USER 65 | - BLOCKLISTER_PASS 66 | - BLOCKLISTER_MAX_SIZE 67 | - BLOCKLISTER_MAX_AGE 68 | - BLOCKLISTER_RM_OLD 69 | 70 | ## Cron 71 | 72 | The example cron Ansible J2 template provides a example of running this and copying 73 | it some place it can be fetched. Copied to a file name specied by `BLOCKLISTER_KEY` in 74 | the default www on a basic Debian based systems. 75 | 76 | ## Template Variables 77 | 78 | | Variable | Type | Suggested Base Settings | Description | 79 | |---------------------------|--------|---------------------------|-------------------------------------------------------------| 80 | | BLOCKLISTER_DB | string | blocklist | The DB name to connect to. | 81 | | BLOCKLISTER_DB_ENABLE | bool | 0 | Enable the DB related bits for Blocklister | 82 | | BLOCKLISTER_ENABLE | bool | 0 | Enables BLOCKLISTER_DB_ENABLE and BLOCKLISTER_SCRIPT_ENABLE | 83 | | BLOCKLISTER_KEY | string | undef | Access key/filename. | 84 | | BLOCKLISTER_MAX_AGE | int | 7776000 | Max age in seconds. Default is 90 days. | 85 | | BLOCKLISTER_MAX_SIZE | int | 10000000 | Max size in bytes. The default is based on Fortigate. | 86 | | BLOCKLISTER_PASS | string | undef | Password for the DB user. | 87 | | BLOCKLISTER_RM_OLD | bool | 0 | Remove items that have a age older than the max age. | 88 | | BLOCKLISTER_SCRIPT_ENABLE | bool | 0 | Enable the script related bits for Blocklister. | 89 | | BLOCKLISTER_SERVER | IP | 127.0.0.1 | IP to connect to. | 90 | | BLOCKLISTER_USER | string | blocklister | DB user | 91 | | BLOCKLISTER_IGNORE_PORTS | string | | A space seperated string of ports to ignore. | 92 | | BLOCKLISTER_LOG | string | /var/log/meer/blocklister | Where to write the logs out to. | 93 | -------------------------------------------------------------------------------- /tools/external/external-program-blocklist/blocklist.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | ############################################################################# 4 | # blocklist.cgi - Simple routine that reads data put into a table by 5 | # "external-program-blocklist" (called by Meer) and sends to to the caller. 6 | # As the data is being sent, it is removed from the SQL database to prevent 7 | # repeatedly sending the same data over and over again. 8 | # This can be useful for creating block lists for firewalls to read (Palo 9 | # Alto, Forigate, etc). 10 | # 11 | # Champ Clark III 12 | # 20220908 13 | ############################################################################# 14 | 15 | use DBI; 16 | use CGI qw(:all); 17 | 18 | # Set this to your database credentials 19 | 20 | my $my_username = "username"; 21 | my $my_password = "password"; 22 | my $my_host = "127.0.0.1"; 23 | my $my_database = "blocklist"; 24 | 25 | my $API_KEY = "1ee217b83185ffdceb1597994ce0e4c710577085"; 26 | 27 | my $api_key = &remove_unwanted(scalar param("apikey")); 28 | 29 | ############################################################################# 30 | # Connect to SQL database! 31 | ############################################################################# 32 | 33 | my $db = "DBI:MariaDB:database=$my_database;host=$my_host"; 34 | my $dbh = DBI->connect($db, $my_username, $my_password) || die "$DBI::errstr\n"; 35 | 36 | my $db2 = "DBI:MariaDB:database=$my_database;host=$my_host"; 37 | my $dbh2 = DBI->connect($db2, $my_username, $my_password) || die "$DBI::errstr\n"; 38 | 39 | my $sql; 40 | my $sql2; 41 | my $sth; 42 | my $sth2; 43 | 44 | print "Content-type: text/plain\n\n"; 45 | 46 | # Verify that the API key is valid! 47 | 48 | if ( $api_key ne $API_KEY ) 49 | { 50 | print "Access Denied.\n"; 51 | exit(0); 52 | } 53 | 54 | # Pull list of active IP address that need to be sent (blocked) 55 | 56 | $sql = "SELECT id,ip FROM drop_list"; 57 | $sth = $dbh->prepare( $sql ); 58 | $sth->execute || die "$DBI::errstr\n"; 59 | 60 | while (my(@bl)=$sth->fetchrow_array) 61 | { 62 | 63 | my $id = $bl[0]; 64 | my $ip = $bl[1]; 65 | 66 | print "$ip\n"; 67 | 68 | # Delete after sending. Prevent resending data if interrupted 69 | 70 | $sql2 = "DELETE FROM drop_list WHERE id=$id"; 71 | $sth2 = $dbh2->prepare( $sql2 ); 72 | $sth2->execute || die "$DBI::errstr\n"; 73 | 74 | } 75 | 76 | exit 0; 77 | 78 | ############################################################################# 79 | # remove_unwanted - input validation 80 | ############################################################################# 81 | 82 | sub remove_unwanted { 83 | our $s; 84 | local($s) = @_; 85 | $s =~ s/\.\.//g; 86 | $s =~ s/[^A-Za-z0-9\@\-\_\/:.]//g if defined $s; 87 | return $s; 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /tools/external/external-program-blocklist/blocklist.sql: -------------------------------------------------------------------------------- 1 | 2 | DROP TABLE IF EXISTS `drop_list`; 3 | CREATE TABLE IF NOT EXISTS `drop_list` ( 4 | `id` int(11) NOT NULL AUTO_INCREMENT, 5 | `timestamp` DATETIME NOT NULL, 6 | `ip` VARCHAR(64) NOT NULL, 7 | `sid` BIGINT(20) NOT NULL, 8 | KEY `id` (`id`), 9 | INDEX `ip` (`ip`) 10 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 11 | ALTER TABLE drop_list ADD UNIQUE(ip); 12 | -------------------------------------------------------------------------------- /tools/external/external-program-blocklist/blocklister.j2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | ############################################################################# 4 | # Based on blocklist.cgi by Champ Clark III and updated for building size 5 | # subnet limited collections by Zane C. Bowers-Hadley for the use with 6 | # like Fortigate etc. 7 | # 8 | # 20221230 9 | ############################################################################# 10 | 11 | use DBI; 12 | use warnings; 13 | use strict; 14 | use Net::CIDR::Lite; 15 | use TOML qw(from_toml); 16 | use File::Slurp; 17 | use Time::Piece; 18 | 19 | my $config_file = '/usr/local/etc/blocklister.toml'; 20 | 21 | # 7776000 = 90 days in seconds 22 | my $config = { 23 | dsn => 'DBI:MariaDB:database={{ BLOCKLISTER_DB }};host={{ BLOCKLISTER_SERVER }}', 24 | user => '{{ BLOCKLISTER_USER }}', 25 | pass => '{{ BLOCKLISTER_PASS }}', 26 | max_size => '{{ BLOCKLISTER_MAX_SIZE }}', 27 | max_age => '{{ BLOCKLISTER_MAX_AGE }}', 28 | remote_only => '1', 29 | delete => '0', 30 | delete_old => '{{ BLOCKLISTER_RM_OLD }}', 31 | cache_dir => '/var/cache/blocklister', 32 | }; 33 | 34 | if ( -f $config_file ) { 35 | die( '"' . $config_file . '" does not exist' ); 36 | 37 | my $config_raw = slurp($config_file); 38 | my ( $config_parsed, $err ) = from_toml($config_raw); 39 | unless ($config) { 40 | die "Error parsing toml: $err"; 41 | } 42 | 43 | my @keys = keys( %{$config} ); 44 | foreach my $key (@keys) { 45 | if ( defined( $config_parsed->{$key} ) ) { 46 | $config->{$key} = $config_parsed->{$key}; 47 | } 48 | } 49 | } 50 | 51 | if ( !-d $config->{cache_dir} ) { 52 | mkdir( $config->{cache_dir} ) || die( '"' . $config->{cache_dir} . '" does not exist and could not be created' ); 53 | } 54 | 55 | my $cache_file = $config->{cache_dir} . '/cache'; 56 | 57 | my $cache = {}; 58 | if ( !$config->{remote_only} ) { 59 | if ( -f $cache_file ) { 60 | my $cache_raw = slurp($cache_file); 61 | my @cache_split = split( /\n/, $cache_raw ); 62 | foreach my $line (@cache_split) { 63 | my ( $ip, $time ) = split( /\,/, $line ); 64 | $cache->{$ip} = $time; 65 | } 66 | } 67 | } 68 | 69 | my $current_time = time; 70 | my $max_age = $current_time - $config->{max_age}; 71 | 72 | my $dbh = DBI->connect( $config->{dsn}, $config->{user}, $config->{pass} ) || die "$DBI::errstr\n"; 73 | my $dbh2 = DBI->connect( $config->{dsn}, $config->{user}, $config->{pass} ) || die "$DBI::errstr\n"; 74 | 75 | my $sql = "SELECT id,ip,timestamp FROM drop_list"; 76 | my $sth = $dbh->prepare($sql); 77 | $sth->execute || die "$DBI::errstr\n"; 78 | 79 | while ( my (@bl) = $sth->fetchrow_array ) { 80 | my $id = $bl[0]; 81 | my $ip = $bl[1]; 82 | my $timestamp = $bl[2]; 83 | 84 | # 2022-12-01 02:30:14 85 | my $t = Time::Piece->strptime( $timestamp, '%Y-%m-%d %H:%M:%S' ); 86 | 87 | # check to see if max age if not zero and if not 88 | # only add it if it falls inside the time frame we want 89 | my $add_it = 1; 90 | if ( $config->{max_age} != 0 && $t->epoch < $max_age ) { 91 | $add_it = 0; 92 | } 93 | if ($add_it) { 94 | $cache->{$ip} = $t->epoch; 95 | } 96 | 97 | # remove it if removing all or it is old and removing old 98 | if ( $config->{delete} || ( $config->{delete_old} && !$add_it ) ) { 99 | my $sql2 = "DELETE FROM drop_list WHERE id=$id"; 100 | my $sth2 = $dbh2->prepare($sql2); 101 | $sth2->execute || die "$DBI::errstr\n"; 102 | } 103 | } 104 | 105 | # if not remote only and we have a max age set, check the cache 106 | # if remote only, then we did not add any old items 107 | if ( $config->{max_age} > 0 && !$config->{remote_only} ) { 108 | my @keys = keys( %{$cache} ); 109 | foreach my $ip (@keys) { 110 | if ( $$cache->{ip} < $max_age ) { 111 | delete( $cache->{$ip} ); 112 | } 113 | } 114 | } 115 | 116 | # save the updated cache if needed 117 | if ( !$config->{remote_only} ) { 118 | my $cache_raw = ''; 119 | my @keys = keys( %{$cache} ); 120 | foreach my $ip (@keys) { 121 | $cache_raw = $cache_raw . $ip . ',' . $cache->{$ip} . "\n"; 122 | } 123 | write_file( $cache_file, $cache_raw ); 124 | } 125 | 126 | my $output = ''; 127 | 128 | # put together the output file, looping until we have one small enough to use 129 | my $oversized = 1; 130 | my $resized = 0; 131 | while ($oversized) { 132 | 133 | # Net::CIDR::Lite can't work both, add each IP to it's respective one 134 | my $cidr_ipv4 = Net::CIDR::Lite->new; 135 | my $cidr_ipv6 = Net::CIDR::Lite->new; 136 | my @keys = keys( %{$cache} ); 137 | foreach my $ip (@keys) { 138 | if ( $ip =~ /\./ ) { 139 | $cidr_ipv4->add( $ip . "/32" ); 140 | } 141 | else { 142 | $cidr_ipv6->add( $ip . "/128" ); 143 | } 144 | } 145 | 146 | # put together the output 147 | my @ipv4 = $cidr_ipv4->list; 148 | my $output_ipv4 = join( "\n", @ipv4 ) . "\n"; 149 | my @ipv6 = $cidr_ipv6->list; 150 | my $output_ipv6 = join( "\n", @ipv6 ) . "\n"; 151 | $output = $output_ipv4 . $output_ipv6; 152 | $output =~ s/\n\n+/\n/g; 153 | 154 | # remove subnet ending for full IPs 155 | $output =~ s/\/32//g; 156 | $output =~ s/\/128//g; 157 | 158 | # check size 159 | if ( length($output) < $config->{max_size} ) { 160 | $oversized = 0; 161 | } 162 | else { 163 | # if oversized still, remove the oldest key and try again 164 | my $oldest; 165 | foreach my $ip (@keys) { 166 | if ( !defined($oldest) ) { 167 | $oldest = $ip; 168 | } 169 | else { 170 | if ( $cache->{$oldest} > $cache->{$ip} ) { 171 | $oldest = $ip; 172 | } 173 | } 174 | } 175 | delete( $cache->{$oldest} ); 176 | $resized = 1; 177 | } 178 | } 179 | 180 | # save the saved cache since some keys were removed if needed 181 | if ( !$config->{remote_only} ) { 182 | my $cache_raw = ''; 183 | if ($resized) { 184 | my @keys = keys( %{$cache} ); 185 | foreach my $ip (@keys) { 186 | $cache_raw = $cache_raw . $ip . ',' . $cache->{$ip} . "\n"; 187 | } 188 | write_file( $cache_file, $cache_raw ); 189 | } 190 | } 191 | 192 | write_file( $config->{cache_dir} . '/output', $output ); 193 | 194 | exit 0; 195 | -------------------------------------------------------------------------------- /tools/external/external-program-blocklist/blocklister_cron.j2: -------------------------------------------------------------------------------- 1 | */10 * * * * root /usr/bin/env LC_ALL=C /usr/local/quadrant/bin/blocklister 2> /dev/null; cp /var/cache/blocklister/output /var/www/html/{{BLOCKLISTER_KEY}} 2> /dev/null 2 | -------------------------------------------------------------------------------- /tools/external/external-program-blocklist/external-program-sql-blocklist.j2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | ############################################################################# 4 | # external-program-sql-blocklist - Simple routine that takes Surcata/Sagan 5 | # EVE data, parses it and sends a "blocklist" SQL database. This data can 6 | # then be retrieve by the get-blocklists.cgi. 7 | # 8 | # Champ Clark III (cclark@quadrantsec.com) 9 | # 20220907 10 | # 11 | ############################################################################# 12 | 13 | use JSON; 14 | use Net::Subnet qw(subnet_matcher); 15 | use DBI; 16 | use File::Slurp; 17 | 18 | use warnings; 19 | use strict; 20 | 21 | ############################################################################# 22 | # SQL Authentication Data 23 | ############################################################################# 24 | 25 | my $my_username = "{{ BLOCKLISTER_USER }}"; 26 | my $my_password = "{{ BLOCKLISTER_PASS }}"; 27 | my $my_database = "{{ BLOCKLISTER_DB }}"; 28 | my $my_host = "{{ BLOCKLISTER_SERVER }}"; 29 | my $ignore_subnet_file = "/usr/local/etc/blocklister_ignore_subnets"; 30 | my $LOG_FILE = "{{ BLOCKLISTER_LOG }}"; # Log file 31 | 32 | ############################################################################# 33 | # Connect to SQL database! 34 | ############################################################################# 35 | 36 | my $db = "DBI:MariaDB:database=$my_database;host=$my_host"; 37 | my $dbh = DBI->connect( $db, $my_username, $my_password ) || die "$DBI::errstr\n"; 38 | 39 | my $sql; 40 | my $sth; 41 | 42 | ############################################################################# 43 | # The $white_list are IP address that you do NOT to send blocks for. You'll 44 | # likely want to put your network (internal & external) IP address ranges 45 | # within this list! 46 | ############################################################################# 47 | 48 | my $ignore_raw = read_file($ignore_subnet_file); 49 | my @to_ignore = split( /\n/, $ignore_raw ); 50 | @to_ignore = grep( !/^[\ \t]*\#/, @to_ignore ); 51 | @to_ignore = grep( !/^\w*$/, @to_ignore ); 52 | 53 | my $int = 0; 54 | while ( defined( $to_ignore[$int] ) ) { 55 | $to_ignore[$int] =~ s/^[\ \t]*//; 56 | $to_ignore[$int] =~ s/[\ \t].*$//; 57 | $to_ignore[$int] =~ s/#.*$//; 58 | $int++; 59 | } 60 | my $white_list = subnet_matcher @to_ignore; 61 | 62 | ######################################################################################### 63 | # Build a list of ports to ignore. Array used for the templating purposes 64 | ######################################################################################### 65 | 66 | my @ignore_ports_array = qw( 67 | {{ BLOCKLISTER_IGNORE_PORTS }} 68 | ); 69 | 70 | my %ignore_ports; 71 | foreach my $port (@ignore_ports_array) { 72 | $ignore_ports{$port} = 1; 73 | } 74 | 75 | ############################################################################# 76 | # You shouldn't need to mess with anything else below this 77 | ############################################################################# 78 | 79 | my $json_d; 80 | my $target; 81 | my $src_ip; 82 | my $src_port; 83 | my $dest_ip; 84 | my $dest_port; 85 | my $signature; 86 | my $sig_id; 87 | 88 | # Handle signals cleanly... 89 | 90 | $SIG{'INT'} = \&Signal_Handler; 91 | $SIG{'TERM'} = \&Signal_Handler; 92 | $SIG{'HUP'} = \&Signal_Handler; 93 | 94 | open( LOG, ">> $LOG_FILE" ) || die "Cannot open $LOG_FILE!\n"; 95 | 96 | # Wait on stdin and collect the incoming json. 97 | 98 | while (<>) { 99 | 100 | Log("------------------------------------------------------------------------------"); 101 | Log( "** Received EVE: " . $_ ); 102 | 103 | $json_d = decode_json($_); 104 | 105 | $src_ip = $json_d->{src_ip}; 106 | $src_port = $json_d->{src_port}; 107 | $dest_ip = $json_d->{dest_ip}; 108 | $dest_port = $json_d->{dest_port}; 109 | $signature = $json_d->{alert}{signature}; 110 | $sig_id = $json_d->{alert}{signature_id}; 111 | 112 | # Do some quick sanity checks for the data comming in. 113 | 114 | if ( $src_ip eq "" ) { 115 | Log("Error. Soruce IP address is missing or couldn't be parsed."); 116 | exit(1); 117 | } 118 | 119 | if ( $dest_ip eq "" ) { 120 | Log("Error. Destination IP address is missing or couldn't be parsed."); 121 | exit(1); 122 | } 123 | 124 | if ( $signature eq "" ) { 125 | Log("Error. The 'siganture' missing or couldn't be parsed."); 126 | exit(1); 127 | } 128 | 129 | if ( $sig_id eq "" ) { 130 | Log("Error. The 'siganture_id' missing or couldn't be parsed."); 131 | exit(1); 132 | } 133 | 134 | Log("Parsed $src_ip -> $dest_ip"); 135 | 136 | # Got good data. Try to figure out what "side" of the connection to send 137 | # the block request for, prioritizing blocking the src_ip 138 | 139 | if ( !$white_list->($src_ip) && !defined( $ignore_ports{$src_port} ) ) { 140 | $target = $src_ip; 141 | } 142 | elsif ( !$white_list->($dest_ip) && !defined( $ignore_ports{$dest_port} ) ) { 143 | $target = $dest_ip; 144 | } 145 | 146 | if ( !$target ) { 147 | Log("No usable firewall targets in $src_ip -> $dest_ip. Abort"); 148 | exit(0); 149 | } 150 | 151 | Log("Writing $target for '$signature' [Sig ID: $sig_id] to the database"); 152 | 153 | ############################################################################# 154 | # Target goes into SQL 155 | ############################################################################# 156 | 157 | $sql = "REPLACE INTO drop_list ( `timestamp`, `ip`, `sid` ) VALUES ( now(), ?, ? )"; 158 | $sth = $dbh->prepare($sql); 159 | $sth->bind_param( 1, $target ); 160 | $sth->bind_param( 2, $sig_id ); 161 | $sth->execute || die "$DBI::errstr\n"; 162 | 163 | } 164 | 165 | Log("Execution complete."); 166 | 167 | close(LOG); 168 | exit(0); 169 | 170 | ############################################################################# 171 | # Signal_Handler - What to do on signals.. 172 | ############################################################################# 173 | 174 | sub Signal_Handler { 175 | 176 | close(LOG); 177 | exit(0); 178 | 179 | } 180 | 181 | ############################################################################# 182 | # Log - Simple "logging" routine to include timestamp. 183 | ############################################################################# 184 | 185 | sub Log { 186 | 187 | our $s; 188 | local ($s) = @_; 189 | my $dt = localtime(); 190 | print LOG "[$dt] $s\n"; 191 | 192 | } 193 | -------------------------------------------------------------------------------- /tools/external/external-program-http-get: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | ############################################################################# 4 | # external-program-http-get - Simple routine that takes Surcata/Sagan EVE 5 | # data, parses it and sends a "block" request to a remote URL via a HTTP 6 | # GET request. 7 | # 8 | # Champ Clark III (cclark@quadrantsec.com) 9 | # 2019/07/17 10 | # 11 | ############################################################################# 12 | 13 | use JSON; 14 | use Net::Subnet qw(subnet_matcher); 15 | use LWP::UserAgent; 16 | 17 | use warnings; 18 | use strict; 19 | 20 | my $LOG_FILE = "/tmp/firewall.log"; # Log file 21 | my $block_url = "http://example.com/blockip="; # URL to send blocks to. 22 | 23 | ############################################################################# 24 | # The $white_list are IP address that you do NOT to send blocks for. You'll 25 | # likely want to put your network (internal & external) IP address ranges 26 | # within this list! 27 | ############################################################################# 28 | 29 | my $white_list = subnet_matcher qw( 30 | 10.0.0.0/8 31 | 192.168.0.0/16 32 | 172.16.0.0/12 33 | 169.254.0.0/16 34 | fd00::/8 35 | ); 36 | 37 | ############################################################################# 38 | # You shouldn't need to mess with anything else below this 39 | ############################################################################# 40 | 41 | my $json_d; 42 | my $url; 43 | my $response; 44 | my $target; 45 | my $src_ip; 46 | my $dest_ip; 47 | my $signature; 48 | my $sig_id; 49 | 50 | my $ua = LWP::UserAgent->new; 51 | 52 | # Handle signals cleanly... 53 | 54 | $SIG{'INT'} = \&Signal_Handler; 55 | $SIG{'TERM'} = \&Signal_Handler; 56 | $SIG{'HUP'} = \&Signal_Handler; 57 | 58 | open(LOG, ">> $LOG_FILE") || die "Cannot open $LOG_FILE!\n"; 59 | 60 | # Wait on stdin and collect the incoming json. 61 | 62 | while (<>) { 63 | 64 | Log("------------------------------------------------------------------------------"); 65 | Log("** Received EVE: " . $_); 66 | 67 | $json_d = decode_json($_); 68 | 69 | $src_ip = $json_d->{src_ip}; 70 | $dest_ip = $json_d->{dest_ip}; 71 | $signature = $json_d->{alert}{signature}; 72 | $sig_id = $json_d->{alert}{signature_id}; 73 | 74 | # Do some quick sanity checks for the data comming in. 75 | 76 | if ( $src_ip eq "" ) 77 | { 78 | Log("Error. Soruce IP address is missing or couldn't be parsed."); 79 | exit(1); 80 | } 81 | 82 | if ( $dest_ip eq "" ) 83 | { 84 | Log("Error. Destination IP address is missing or couldn't be parsed."); 85 | exit(1); 86 | } 87 | 88 | if ( $signature eq "" ) 89 | { 90 | Log("Error. The 'siganture' missing or couldn't be parsed."); 91 | exit(1); 92 | } 93 | 94 | if ( $sig_id eq "" ) 95 | { 96 | Log("Error. The 'siganture_id' missing or couldn't be parsed."); 97 | exit(1); 98 | } 99 | 100 | 101 | Log("Parsed $src_ip -> $dest_ip"); 102 | 103 | # Got good data. Try to figure out what "side" of the connection to send 104 | # the block request for. 105 | 106 | if ( !$white_list->($dest_ip) ) 107 | { 108 | $target = $dest_ip; 109 | } 110 | 111 | if ( !$white_list->($src_ip) ) 112 | { 113 | $target = $src_ip; 114 | } 115 | 116 | if ( !$target ) 117 | { 118 | Log("No usable firewall targets in $src_ip -> $dest_ip. Abort"); 119 | exit(0); 120 | } 121 | 122 | # Send block request! 123 | 124 | Log("Target to firewall is $target for '$signature' [Sig ID: $sig_id]"); 125 | 126 | $url = $block_url . $target; 127 | 128 | Log("Sending $url"); 129 | 130 | $ua->timeout(60); 131 | $ua->agent("Meer Blocking Agent"); 132 | $response = $ua->get($url); 133 | 134 | # Check block request response. 135 | 136 | if ( $response->is_success ) 137 | { 138 | Log("Successfully send to $url [" . $response->status_line . "]"); 139 | } else { 140 | Log("Failed to send to $url [" . $response->status_line . "]"); 141 | } 142 | 143 | } 144 | 145 | Log("Execution complete."); 146 | 147 | close(LOG); 148 | exit(0); 149 | 150 | ############################################################################# 151 | # Signal_Handler - What to do on signals.. 152 | ############################################################################# 153 | 154 | sub Signal_Handler { 155 | 156 | close(LOG); 157 | exit(0); 158 | 159 | } 160 | 161 | ############################################################################# 162 | # Log - Simple "logging" routine to include timestamp. 163 | ############################################################################# 164 | 165 | sub Log { 166 | 167 | our $s; 168 | local($s) = @_; 169 | my $dt = localtime(); 170 | print LOG "[$dt] $s\n"; 171 | 172 | } 173 | 174 | -------------------------------------------------------------------------------- /tools/external/external-program-iptables: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | ############################################################################# 4 | # external-program-iptables - Simple routine that takes Surcata/Sagan EVE 5 | # data, parses it and firewalls via iptables. 6 | # 7 | # In order for this routine to work, the user will need to be able to run 8 | # iptables as "root". To do this, we add the following lines to your 9 | # /etc/sudoers via the "visudo" command. 10 | # 11 | # suricata ALL=(ALL) NOPASSWD: /sbin/iptables -A INPUT -s * -j DROP,/sbin/iptables -A INPUT -d * -j DROP,/sbin/iptables -A FORWARD -s * -j DROP,/sbin/iptables -A FORWARD -d * -j DROP 12 | 13 | # 14 | # (Replaces 'suricata' with whatever you run Suricata/Sagan as) 15 | # 16 | # Champ Clark III (cclark@quadrantsec.com) 17 | # 2019/07/20 18 | # 19 | ############################################################################# 20 | 21 | use JSON; 22 | use Net::Subnet qw(subnet_matcher); 23 | 24 | use warnings; 25 | use strict; 26 | 27 | my $LOG_FILE = "/tmp/firewall.log"; # Log file 28 | my $IPTABLES = "/usr/bin/sudo /sbin/iptables"; 29 | 30 | ############################################################################# 31 | # The $white_list are IP address that you do NOT to send blocks for. You'll 32 | # likely want to put your network (internal & external) IP address ranges 33 | # within this list! 34 | ############################################################################# 35 | 36 | my $white_list = subnet_matcher qw( 37 | 10.0.0.0/8 38 | 192.168.0.0/16 39 | 172.16.0.0/12 40 | 169.254.0.0/16 41 | fd00::/8 42 | ); 43 | 44 | ############################################################################# 45 | # You shouldn't need to mess with anything else below this 46 | ############################################################################# 47 | 48 | my $json_d; 49 | my $cmd; 50 | my $target; 51 | my $src_ip; 52 | my $dest_ip; 53 | my $signature; 54 | my $sig_id; 55 | my $direction; 56 | 57 | # Handle signals cleanly... 58 | 59 | $SIG{'INT'} = \&Signal_Handler; 60 | $SIG{'TERM'} = \&Signal_Handler; 61 | $SIG{'HUP'} = \&Signal_Handler; 62 | 63 | open(LOG, ">> $LOG_FILE") || die "Cannot open $LOG_FILE!\n"; 64 | 65 | # Wait on stdin and collect the incoming json. 66 | 67 | while (<>) { 68 | 69 | Log("------------------------------------------------------------------------------"); 70 | Log("** Received EVE: " . $_); 71 | 72 | $json_d = decode_json($_); 73 | 74 | $src_ip = $json_d->{src_ip}; 75 | $dest_ip = $json_d->{dest_ip}; 76 | $signature = $json_d->{alert}{signature}; 77 | $sig_id = $json_d->{alert}{signature_id}; 78 | 79 | # Do some quick sanity checks for the data comming in. 80 | 81 | if ( $src_ip eq "" ) 82 | { 83 | Log("Error. Soruce IP address is missing or couldn't be parsed."); 84 | exit(1); 85 | } 86 | 87 | if ( $dest_ip eq "" ) 88 | { 89 | Log("Error. Destination IP address is missing or couldn't be parsed."); 90 | exit(1); 91 | } 92 | 93 | if ( $signature eq "" ) 94 | { 95 | Log("Error. The 'siganture' missing or couldn't be parsed."); 96 | exit(1); 97 | } 98 | 99 | if ( $sig_id eq "" ) 100 | { 101 | Log("Error. The 'siganture_id' missing or couldn't be parsed."); 102 | exit(1); 103 | } 104 | 105 | 106 | Log("Parsed $src_ip -> $dest_ip"); 107 | 108 | # Got good data. Try to figure out what "side" of the connection to send 109 | # the block request for. 110 | 111 | if ( !$white_list->($dest_ip) ) 112 | { 113 | $target = $dest_ip; 114 | $direction = "-d"; 115 | } 116 | 117 | if ( !$white_list->($src_ip) ) 118 | { 119 | $target = $src_ip; 120 | $direction = "-s"; 121 | } 122 | 123 | if ( !$target ) 124 | { 125 | Log("No usable firewall targets in $src_ip -> $dest_ip. Abort"); 126 | exit(0); 127 | } 128 | 129 | # Send block request! 130 | 131 | Log("Target to firewall is $target for '$signature' [Sig ID: $sig_id]"); 132 | 133 | $cmd = "$IPTABLES -A FORWARD $direction $target -j DROP; $IPTABLES -A INPUT $direction $target -j DROP"; 134 | 135 | Log("Executing command: $cmd"); 136 | system($cmd); 137 | Log("System cal completed."); 138 | 139 | } 140 | 141 | Log("Execution complete."); 142 | 143 | close(LOG); 144 | exit(0); 145 | 146 | ############################################################################# 147 | # Signal_Handler - What to do on signals.. 148 | ############################################################################# 149 | 150 | sub Signal_Handler { 151 | 152 | close(LOG); 153 | exit(0); 154 | 155 | } 156 | 157 | ############################################################################# 158 | # Log - Simple "logging" routine to include timestamp. 159 | ############################################################################# 160 | 161 | sub Log { 162 | 163 | our $s; 164 | local($s) = @_; 165 | my $dt = localtime(); 166 | print LOG "[$dt] $s\n"; 167 | 168 | } 169 | 170 | -------------------------------------------------------------------------------- /tools/reference_handler/README.md: -------------------------------------------------------------------------------- 1 | # Meer - Reference_Handlers 2 | 3 | This takes "reference" data from Suricata/Sagan/Snort rules and populates a centralized database 4 | with that data. If you have more than one Suricata/Snort/Sagan database, you'll likely want 5 | to use this than the "traditional" reference system. 6 | 7 | -------------------------------------------------------------------------------- /tools/reference_handler/reference_data.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Table structure for table `reference_data` 3 | -- 4 | 5 | DROP TABLE IF EXISTS `reference_data`; 6 | 7 | CREATE TABLE `reference_data` ( 8 | `sid` bigint(20) NOT NULL, 9 | `ref_type` varchar(10) NOT NULL, 10 | `ref_url` varchar(255) NOT NULL, 11 | PRIMARY KEY (`sid`,`ref_type`,`ref_url`) 12 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 13 | -------------------------------------------------------------------------------- /tools/reference_handler/reference_sources.conf: -------------------------------------------------------------------------------- 1 | # List of references used by Snort/Sagan/Suricata Rules. 2 | # 3 | url|http:// 4 | bugtraq|http://www.securityfocus.com/bid/ 5 | nessus|https://www.tenable.com/plugins/index.php?view=single&id= 6 | cve|http://www.cve.mitre.org/cgi-bin/cvename.cgi?name= 7 | md5|http://virustotalorsomething 8 | quadrant|http://wiki.quadrantsec.com/bin/view/Main/ 9 | quadrantsec|http://wiki.quadrantsec.com/bin/view/Main/ 10 | arachnids|http://ifolderlinks.ru/404/ 11 | mcafee|https://home.mcafee.com/virusinfo/virusprofile.aspx?key= 12 | bid|http://www.securityfocus.com/bid/ 13 | secunia|http://www.secunia.com/advisories/ 14 | et|http://doc.emergingthreats.net/ 15 | etpro|http://doc.emergingthreatpro.com/ 16 | #telus|http:// 17 | osvb|http://osvdb.org/show/osvdb/ 18 | threatexpert|http://www.threatexpert.com/report.aspx?md5= 19 | exploitdb|http://www.exploit-db.com/exploits/ 20 | openpacket|https://www.openpacket.org/capture/grab/ 21 | securitytracker|http://securitytracker.com/id? 22 | xforce|http://xforce.iss.net/xforce/xfdb/ 23 | --------------------------------------------------------------------------------