+++ /dev/null
-#! /usr/bin/env bash
-#
-# Script to provision a new application layer detector and parser.
-
-set -e
-
-# Fail if "ed" is not available.
-if ! which ed > /dev/null 2>&1; then
- echo "error: the program \"ed\" is required for this script"
- exit 1
-fi
-
-function usage() {
- cat <<EOF
-
-usage: $0 <protocol name> <buffer name>
-
-This script will provision content inspection for app-layer decoded
-buffers.
-
-Examples:
-
- $0 Gopher Buffer
- $0 DNP3 Buffer
- $0 Http Etag
-
-EOF
-}
-
-# Make sure we are running from the correct directory.
-set_dir() {
- if [ -e ./suricata.c ]; then
- cd ..
- elif [ -e ./src/suricata.c ]; then
- # Do nothing.
- true
- else
- echo "error: this does not appear to be a suricata source directory."
- exit 1
- fi
-}
-
-fail_if_exists() {
- path="$1"
- if test -e "${path}"; then
- echo "error: ${path} already exists."
- exit 1
- fi
-}
-
-function copy_template_file() {
- src="$1"
- dst="$2"
-
- echo "Creating ${dst}."
-
- sed -e '/TEMPLATE_START_REMOVE/,/TEMPLATE_END_REMOVE/d' \
- -e "s/TEMPLATE_BUFFER/${protoname_upper}_${buffername_upper}/g" \
- -e "s/TEMPLATE/${protoname_upper}/g" \
- -e "s/template-buffer/${protoname_lower}-${buffername_lower}/g" \
- -e "s/template/${protoname_lower}/g" \
- -e "s/TemplateBuffer/${protoname}${buffername}/g" \
- -e "s/Template/${protoname}/g" \
- > ${dst} < ${src}
-}
-
-function copy_templates() {
- detect_h_dst="src/detect-${protoname_lower}-${buffername_lower}.h"
- detect_c_dst="src/detect-${protoname_lower}-${buffername_lower}.c"
- tests_detect_c_dst="src/tests/detect-${protoname_lower}-${buffername_lower}.c"
-
- fail_if_exists ${detect_h_dst}
- fail_if_exists ${detect_c_dst}
- fail_if_exists ${tests_detect_c_dst}
-
- copy_template_file "src/detect-template-buffer.h" ${detect_h_dst}
- copy_template_file "src/detect-template-buffer.c" ${detect_c_dst}
- copy_template_file "src/tests/detect-template-buffer.c" ${tests_detect_c_dst}
-}
-
-function patch() {
- filename="src/Makefile.am"
- echo "Patching ${filename}."
- ed -s ${filename} > /dev/null <<EOF
-/^detect-template-buffer.c
-t-
-s/template-buffer/${protoname_lower}-${buffername_lower}/g
-w
-EOF
-
- filename="src/detect-engine-register.c"
- echo "Patching ${filename}."
-
- ed -s ${filename} > /dev/null <<EOF
-/#include "detect-template-buffer.h"
-t-
-s/template-buffer/${protoname_lower}-${buffername_lower}/
-w
-EOF
-
- ed -s ${filename} > /dev/null <<EOF
-/DetectTemplateBufferRegister
-t-
-s/TemplateBuffer/${protoname}${buffername}/
-w
-EOF
-
- filename="src/detect-engine-register.h"
- echo "Patching ${filename}."
- ed -s ${filename} > /dev/null <<EOF
-/DETECT_AL_TEMPLATE_BUFFER
-t-
-s/TEMPLATE_BUFFER/${protoname_upper}_${buffername_upper}/
-w
-EOF
-}
-
-set_dir
-
-protoname="$1"
-buffername="$2"
-
-if [ "${protoname}" = "" ] || [ "${buffername}" = "" ]; then
- usage
- exit 1
-fi
-
-# Make sure the protocol name looks like a proper name (starts with a
-# capital letter).
-case "${protoname}" in
-
- [[:upper:]]*)
- # OK.
- ;;
-
- "")
- usage
- exit 1
- ;;
-
- *)
- echo "error: protocol name must beging with an upper case letter"
- exit 1
- ;;
-
-esac
-
-protoname_lower=$(printf ${protoname} | tr '[:upper:]' '[:lower:]')
-protoname_upper=$(printf ${protoname} | tr '[:lower:]' '[:upper:]')
-buffername_lower=$(printf ${buffername} | tr '[:upper:]' '[:lower:]')
-buffername_upper=$(printf ${buffername} | tr '[:lower:]' '[:upper:]')
-
-copy_templates
-patch
-
-cat <<EOF
-
-The following files have been created and linked into the build:
-
- detect-${protoname_lower}-${buffername_lower}.h detect-${protoname_lower}-${buffername_lower}.c
-
- The setup for the content inspection sticky buffer keyword.
-
-Please fix in src/detect.h the values for:
- SIG_MASK_REQUIRE_${protoname_upper}_STATE
- SIG_MASK_REQUIRE_TEMPLATE_STATE
-
-EOF
if os.path.exists(filename):
raise SetupError("%s already exists" % (filename))
-def common_copy_templates(proto, pairs):
+def common_copy_templates(proto, pairs, replacements=()):
upper = proto.upper()
lower = proto.lower()
if skip:
continue
+ for (old, new) in replacements:
+ line = line.replace(old, new)
+
line = re.sub("TEMPLATE(_RUST)?", upper, line)
line = re.sub("template(-rust)?", lower, line)
line = re.sub("Template(Rust)?", proto, line)
"src/app-layer-%s.h" % (lower)),
("rust/src/applayertemplate/mod.rs",
"rust/src/applayer%s/mod.rs" % (lower)),
+ ("rust/src/applayertemplate/template.rs",
+ "rust/src/applayer%s/gopher.rs" % (lower)),
("rust/src/applayertemplate/parser.rs",
"rust/src/applayer%s/parser.rs" % (lower)),
)
output.write(line)
open(filename, "w").write(output.getvalue())
+def detect_copy_templates(proto, buffername, rust):
+ lower = proto.lower()
+ buffername_lower = buffername.lower()
+
+ if rust:
+ pairs = (
+ ("src/detect-template-rust-buffer.h",
+ "src/detect-%s-%s.h" % (lower, buffername_lower)),
+ ("src/detect-template-rust-buffer.c",
+ "src/detect-%s-%s.c" % (lower, buffername_lower)),
+ )
+ replacements = (
+ ("TEMPLATE_RUST_BUFFER", "%s_%s" % (
+ proto.upper(), buffername.upper())),
+ ("template-rust-buffer", "%s-%s" % (
+ proto.lower(), buffername.lower())),
+ ("template_rust_buffer", "%s_%s" % (
+ proto.lower(), buffername.lower())),
+ ("TemplateRustBuffer", "%s%s" % (proto, buffername)),
+ )
+ else:
+ pairs = (
+ ("src/detect-template-buffer.h",
+ "src/detect-%s-%s.h" % (lower, buffername_lower)),
+ ("src/detect-template-buffer.c",
+ "src/detect-%s-%s.c" % (lower, buffername_lower)),
+ )
+ replacements = (
+ ("TEMPLATE_BUFFER", "%s_%s" % (proto.upper(), buffername.upper())),
+ ("template-buffer", "%s-%s" % (proto.lower(), buffername.lower())),
+ ("template_buffer", "%s_%s" % (proto.lower(), buffername.lower())),
+ ("TemplateBuffer", "%s%s" % (proto, buffername)),
+ )
+
+ common_copy_templates(proto, pairs, replacements)
+
+def detect_patch_makefile_am(protoname, buffername):
+ filename = "src/Makefile.am"
+ print("Patching %s." % (filename))
+ output = io.StringIO()
+ with open(filename) as infile:
+ for line in infile:
+ if line.startswith("detect-template-buffer.c"):
+ new = line.replace("template-buffer", "%s-%s" % (
+ protoname.lower(), buffername.lower()))
+ output.write(new)
+ output.write(line)
+ open(filename, "w").write(output.getvalue())
+
+def detect_patch_detect_enginer_register_c(protoname, buffername):
+ filename = "src/detect-engine-register.c"
+ print("Patching %s." % (filename))
+ output = io.StringIO()
+ with open(filename) as infile:
+ for line in infile:
+
+ if line.find("detect-template-buffer.h") > -1:
+ new = line.replace("template-buffer", "%s-%s" % (
+ protoname.lower(), buffername.lower()))
+ output.write(new)
+
+ if line.find("DetectTemplateBufferRegister") > -1:
+ new = line.replace("TemplateBuffer", "%s%s" % (
+ protoname, buffername))
+ output.write(new)
+
+ output.write(line)
+ open(filename, "w").write(output.getvalue())
+
+def detect_patch_detect_enginer_register_h(protoname, buffername):
+ filename = "src/detect-engine-register.h"
+ print("Patching %s." % (filename))
+ output = io.StringIO()
+ with open(filename) as infile:
+ for line in infile:
+
+ if line.find("DETECT_AL_TEMPLATE_BUFFER") > -1:
+ new = line.replace("TEMPLATE_BUFFER", "%s_%s" % (
+ protoname.upper(), buffername.upper()))
+ output.write(new)
+
+ output.write(line)
+ open(filename, "w").write(output.getvalue())
+
def proto_exists(proto):
upper = proto.upper()
for line in open("src/app-layer-protos.h"):
%(progname)s DNP3
%(progname)s Gopher
+
+This script can also setup a detect buffer. This is a separate
+operation that must be done after creating the parser.
+
+Examples:
+
+ %(progname)s --detect Gopher Request
""" % { "progname": progname, }
def main():
help="Generate logger.")
parser.add_argument("--parser", action="store_true", default=False,
help="Generate parser.")
+ parser.add_argument("--detect", action="store_true", default=False,
+ help="Generate detect module.")
parser.add_argument("proto", help="Name of protocol")
+ parser.add_argument("buffer", help="Name of buffer (for --detect)",
+ nargs="?")
args = parser.parse_args()
proto = args.proto
# Determine what to generate.
parser = False
logger = False
+ detect = False
# If no --parser or no --logger, generate both.
- if not args.parser and not args.logger:
+ if not args.parser and not args.logger and not args.detect:
parser = True
logger = True
else:
parser = args.parser
logger = args.logger
+ detect = args.detect
+
+ if detect:
+ if args.buffer is None:
+ raise SetupError("--detect requires a buffer name")
# Make sure we are in the correct directory.
if os.path.exists("./suricata.c"):
logger_patch_suricata_yaml_in(proto)
logger_patch_util_profiling_c(proto)
+ if detect:
+ if not proto_exists(proto):
+ raise SetupError("no app-layer parser exists for %s" % (proto))
+ detect_copy_templates(proto, args.buffer, args.rust)
+ detect_patch_makefile_am(proto, args.buffer)
+ detect_patch_detect_enginer_register_c(proto, args.buffer)
+ detect_patch_detect_enginer_register_h(proto, args.buffer)
+
if parser:
if args.rust:
print("""
"proto_lower": proto.lower(),
})
+ if detect:
+ print("""
+The following files have been created and linked into the build:
+
+ detect-%(protoname_lower)s-%(buffername_lower)s.h
+ detect-%(protoname_lower)s-%(buffername_lower)s.c
+""" % {
+ "protoname_lower": proto.lower(),
+ "buffername_lower": args.buffer.lower(),
+})
+
if parser or logger:
print("""
Suricata should now build cleanly. Try running "make".