Source code for idstools.scripts.dumpdynamicrules

# Copyright (c) 2015 Jason Ish
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

"""Dump Snort SO rule stub helper program. Can optionally repack a
Snort rule tarball with the generated stubs, in place or to a new
file.

"""

from __future__ import print_function

import sys
import os
import os.path
import logging
import subprocess
import re
import tempfile
import atexit
import shutil
import glob

if sys.argv[0] == __file__:
    sys.path.insert(
        0, os.path.abspath(os.path.join(__file__, "..", "..", "..")))

try:
    import argparse
except:
    # Python 2.6.
    from idstools.compat.argparse import argparse

from idstools import snort

logging.basicConfig(level=logging.INFO, format="%(message)s")
logger = logging.getLogger()

[docs]def mktempdir(delete_on_exit=True): """ Create a temporary directory that is removed on exit. """ tmpdir = tempfile.mkdtemp("idstools") if delete_on_exit: atexit.register(shutil.rmtree, tmpdir, ignore_errors=True) return tmpdir
[docs]def find_snort(): """ Find the path to Snort from the PATH. """ for path in os.environ["PATH"].split(os.pathsep): filename = os.path.join("snort") if os.path.exists(filename): return filename return None
[docs]def repack(prefix, stubs, filename): logger.info("Repacking to %s.", filename) stubdir = os.path.join(prefix, "so_rules") existing_stubs = glob.glob("%s/*.rules" % (stubdir)) for stub in stubs: rpath = os.path.join("so_rules", stub) fpath = os.path.join(prefix, rpath) if fpath in existing_stubs: logger.debug("Overwriting %s.", rpath) existing_stubs.remove(fpath) else: print("Creating %s." % (rpath)) # Log the orphaned stubs. logger.debug("Orphaned SO stubs: %s", ",".join(existing_stubs)) logger.info("Writing %s.", filename) subprocess.Popen( "tar cf - * | gzip -c > %s" % (filename), shell=True, cwd=prefix).communicate()
[docs]def main(): parser = argparse.ArgumentParser() parser.add_argument( "--snort", dest="snort", help="path to snort") parser.add_argument( "--version", dest="version", help="Snort version") parser.add_argument( "--dist", dest="dist", help="operating system/distribution") parser.add_argument( "--out", dest="out", help="path to output SO stubs to") parser.add_argument( "--repack", nargs="?", metavar="filename", const=True, default=False, help="repack archive with generated SO stubs") parser.add_argument( "-v", "--verbose", action="store_true", default=False, help="log more information") parser.add_argument( "path", metavar="<path>", help="SO rule directory or rule tarball") args = parser.parse_args() if args.verbose: logger.setLevel(logging.DEBUG) if not args.snort: args.snort = find_snort() if not args.snort: logger.error("Failed to find Snort program on path.") return 1 elif not os.path.exists(args.snort): logger.error("Error: %s does not exists.", args.snort) return 1 snort_app = snort.SnortApp(path=args.snort) logger.info("Using Snort %s.", snort_app.version()[1]) if not args.version: args.version = snort_app.version()[0] path = os.path.realpath(args.path) if os.path.isdir(path): stubs = snort_app.dump_dynamic_rules(path, verbose=True) else: tempdir = mktempdir(delete_on_exit=False) logger.info("Expanding %s to directory %s." % (path, tempdir)) subprocess.Popen( "gunzip -c %s | tar xf -" % (path), cwd=tempdir, shell=True).wait() precompiled_dir = "%s/so_rules/precompiled" % (tempdir) if args.dist: path = "%s/%s/%s/%s" % (precompiled_dir, args.dist, snort_app.arch, args.version) logger.info("Using %s.", path) stubs = snort_app.dump_dynamic_rules(path, verbose=args.verbose) else: for dist in reversed(os.listdir(precompiled_dir)): path = "%s/%s/%s/%s" % (precompiled_dir, dist, snort_app.arch, args.version) print("Trying %s." % path) stubs = snort_app.dump_dynamic_rules(path, args.verbose) if stubs: break logger.info("Generated %d stubs.", len(stubs)) if stubs and args.out: if not os.path.exists(args.out): logger.info("Creating directory %s.", args.out) os.makedirs(args.out) for stub in stubs: out_path = os.path.join(args.out, stub) logger.info("Writing %s.", out_path) with open(out_path, "w") as fileobj: fileobj.write(stubs[stub]) if args.repack: if os.path.isdir(path): logger.error("Error: Repacking not available when input is a directory") else: if not stubs: logger.error("Error: No stubs generated, nothing to repack.") repack(tempdir, stubs, path if args.repack == True else args.repack)
if __name__ == "__main__": sys.exit(main())