From ee1d2b8dd64a26a3c689def38e27282d66c72a42 Mon Sep 17 00:00:00 2001 From: wayward710 Date: Thu, 31 Mar 2016 03:34:23 -0500 Subject: [PATCH 1/8] Added Bro support to Prism --- components.js | 4 + components/prism-bro.js | 86 +++++ components/prism-bro.min.js | 1 + examples.js | 3 +- examples/prism-bro.html | 657 ++++++++++++++++++++++++++++++++++++ 5 files changed, 750 insertions(+), 1 deletion(-) create mode 100644 components/prism-bro.js create mode 100644 components/prism-bro.min.js create mode 100644 examples/prism-bro.html diff --git a/components.js b/components.js index b422f92273..df838b9122 100644 --- a/components.js +++ b/components.js @@ -121,6 +121,10 @@ var components = { "title": "Brainfuck", "owner": "Golmote" }, + "bro": { + "title": "Bro", + "owner": "wayward710" + }, "c": { "title": "C", "require": "clike", diff --git a/components/prism-bro.js b/components/prism-bro.js new file mode 100644 index 0000000000..47ae7907b8 --- /dev/null +++ b/components/prism-bro.js @@ -0,0 +1,86 @@ +Prism.languages.bro = { + 'comment': [ + { + pattern: /(^|[^\\$])#.*/, + lookbehind: true + } + ], + + 'string': /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, + + 'boolean': /\b(T|F)\b/, + + 'keyword': [ + /\b(break|next|continue)\b/, + /\b(alarm|using|of|add|delete)\b/, + /\b(default|export|event)\b/, + /\b(print|redef|return|schedule)\b/, + /\b(when|timeout)\b/, + /\b(addr|any|bool|count)\b/, + /\b(double|enum)\b/, + /\b(file|int|interval)\b/, + /\b(pattern)\b/, + /\b(port|record|set)\b/, + /\b(string|subnet|table)\b/, + /\b(time|vector)\b/, + /\b(for|if|else)\b/, + /\b(day|hr|min|sec|usec)s\b/ + + + ], + 'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/, + + 'function': + { + pattern: /function [a-z0-9_]+/i, + inside: { + keyword: /function/ + } + }, + + 'variable': + [{ + pattern: /global [a-z0-9_]+/i, + inside: { + keyword: /global/ + } + }, + { + pattern: /local [a-z0-9_]+/i, + inside: { + keyword: /local/ + } + }], + + + 'number': [ + /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i, + + ], + + 'italic': /\b(TODO|FIXME|XXX)\b/, + 'punctuation': /[{}[\];(),.:]/, + + 'builtin': [ + /@load\s+/, + /@load-sigs\s+/, + /@load-plugin\s+/, + /@unload\s+/, + /@prefixes\s+/, + /@if\s+/, + /@ifdef\s+/, + /@ifndef\s+/, + /@else\s+/, + /@endif\s+/, + /@DIR\s+/, + /@FILENAME\s+/ + ], + + 'constant': + { + pattern: /const [a-z0-9_]+/i, + inside: { + keyword: /const/ + } + }, +}; diff --git a/components/prism-bro.min.js b/components/prism-bro.min.js new file mode 100644 index 0000000000..850d55a2e6 --- /dev/null +++ b/components/prism-bro.min.js @@ -0,0 +1 @@ +Prism.languages.bro={"comment":[{pattern:/(^|[^\\$])#.*/,lookbehind:true}],"string":/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"boolean":/\b(T|F)\b/,"keyword":[/\b(break|next|continue)\b/,/\b(alarm|using|of|add|delete)\b/,/\b(default|export|event)\b/,/\b(print|redef|return|schedule)\b/,/\b(when|timeout)\b/,/\b(addr|any|bool|count)\b/,/\b(double|enum)\b/,/\b(file|int|interval)\b/,/\b(pattern)\b/,/\b(port|record|set)\b/,/\b(string|subnet|table)\b/,/\b(time|vector)\b/,/\b(for|if|else)\b/,/\b(day|hr|min|sec|usec)s\b/],"operator":/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,"function":{pattern:/function [a-z0-9_]+/i,inside:{keyword:/function/}},"variable":[{pattern:/global [a-z0-9_]+/i,inside:{keyword:/global/}},{pattern:/local [a-z0-9_]+/i,inside:{keyword:/local/}}],"number":[/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,],"italic":/\b(TODO|FIXME|XXX)\b/,"punctuation":/[{}[\];(),.:]/,"builtin":[/@load\s+/,/@load-sigs\s+/,/@load-plugin\s+/,/@unload\s+/,/@prefixes\s+/,/@if\s+/,/@ifdef\s+/,/@ifndef\s+/,/@else\s+/,/@endif\s+/,/@DIR\s+/,/@FILENAME\s+/],"constant":{pattern:/const [a-z0-9_]+/i,inside:{keyword:/const/}},}; \ No newline at end of file diff --git a/examples.js b/examples.js index a686fa787f..83bc2286b3 100644 --- a/examples.js +++ b/examples.js @@ -85,7 +85,8 @@ function fileExists(filepath) { return true; } } - return false; + //return false; + return true; }); } diff --git a/examples/prism-bro.html b/examples/prism-bro.html new file mode 100644 index 0000000000..33084d5f10 --- /dev/null +++ b/examples/prism-bro.html @@ -0,0 +1,657 @@ +

Bro

+

To use this language, use the class "language-bro".

+ +

Comments

+
# Single line comment
+
+ +

Strings

+

+"a", "b"
+
+ +

Numbers

+
123
+123.456
+-123.456
+.3f
+1.3e9d
+0xaf
+0xAF
+0xFF.AEP-4
+
+ +

Full example

+

+##! Scan detector ported from Bro 1.x.
+##!
+##! This script has evolved over many years and is quite a mess right now. We
+##! have adapted it to work with Bro 2.x, but eventually Bro 2.x will
+##! get its own rewritten and generalized scan detector.
+
+@load base/frameworks/notice/main
+
+module Scan;
+
+export {
+	redef enum Notice::Type += {
+		## The source has scanned a number of ports.
+		PortScan,
+		## The source has scanned a number of addresses.
+		AddressScan,
+		## Apparent flooding backscatter seen from source.
+		BackscatterSeen,
+
+		## Summary of scanning activity.
+		ScanSummary,
+		## Summary of distinct ports per scanner.
+		PortScanSummary,
+		## Summary of distinct low ports per scanner.
+		LowPortScanSummary,
+
+		## Source reached :bro:id:`Scan::shut_down_thresh`
+		ShutdownThresh,
+		## Source touched privileged ports.
+		LowPortTrolling,
+	};
+
+	# Whether to consider UDP "connections" for scan detection.
+	# Can lead to false positives due to UDP fanout from some P2P apps.
+	const suppress_UDP_scan_checks = F &redef;
+
+	const activate_priv_port_check = T &redef;
+	const activate_landmine_check = F &redef;
+	const landmine_thresh_trigger = 5 &redef;
+
+	const landmine_address: set[addr] &redef;
+
+	const scan_summary_trigger = 25 &redef;
+	const port_summary_trigger = 20 &redef;
+	const lowport_summary_trigger = 10 &redef;
+
+	# Raise ShutdownThresh after this many failed attempts
+	const shut_down_thresh = 100 &redef;
+
+	# Which services should be analyzed when detecting scanning
+	# (not consulted if analyze_all_services is set).
+	const analyze_services: set[port] &redef;
+	const analyze_all_services = T &redef;
+
+	# Track address scaners only if at least these many hosts contacted.
+	const addr_scan_trigger = 0 &redef;
+
+	# Ignore address scanners for further scan detection after
+	# scanning this many hosts.
+	# 0 disables.
+	const ignore_scanners_threshold = 0 &redef;
+
+	# Report a scan of peers at each of these points.
+	const report_peer_scan: vector of count = {
+		20, 100, 1000, 10000, 50000, 100000, 250000, 500000, 1000000,
+	} &redef;
+
+	const report_outbound_peer_scan: vector of count = {
+		100, 1000, 10000,
+	} &redef;
+
+	# Report a scan of ports at each of these points.
+	const report_port_scan: vector of count = {
+		50, 250, 1000, 5000, 10000, 25000, 65000,
+	} &redef;
+
+	# Once a source has scanned this many different ports (to however many
+	# different remote hosts), start tracking its per-destination access.
+	const possible_port_scan_thresh = 20 &redef;
+
+	# Threshold for scanning privileged ports.
+	const priv_scan_trigger = 5 &redef;
+	const troll_skip_service = {
+		25/tcp, 21/tcp, 22/tcp, 20/tcp, 80/tcp,
+	} &redef;
+
+	const report_accounts_tried: vector of count = {
+		20, 100, 1000, 10000, 100000, 1000000,
+	} &redef;
+
+	const report_remote_accounts_tried: vector of count = {
+		100, 500,
+	} &redef;
+
+	# Report a successful password guessing if the source attempted
+	# at least this many.
+	const password_guessing_success_threshhold = 20 &redef;
+
+	const skip_accounts_tried: set[addr] &redef;
+
+	const addl_web = {
+		81/tcp, 443/tcp, 8000/tcp, 8001/tcp, 8080/tcp, }
+	&redef;
+
+	const skip_services = { 113/tcp, } &redef;
+	const skip_outbound_services = { 21/tcp, addl_web, }
+		&redef;
+
+	const skip_scan_sources = {
+		255.255.255.255,	# who knows why we see these, but we do
+	} &redef;
+
+	const skip_scan_nets: set[subnet] = {} &redef;
+
+	# List of well known local server/ports to exclude for scanning
+	# purposes.
+	const skip_dest_server_ports: set[addr, port] = {} &redef;
+
+	# Reverse (SYN-ack) scans seen from these ports are considered
+	# to reflect possible SYN-flooding backscatter, and not true
+	# (stealth) scans.
+	const backscatter_ports = {
+		80/tcp, 8080/tcp, 53/tcp, 53/udp, 179/tcp, 6666/tcp, 6667/tcp,
+	} &redef;
+
+	const report_backscatter: vector of count = {
+		20,
+	} &redef;
+
+	global check_scan:
+		function(c: connection, established: bool, reverse: bool): bool;
+
+	# The following tables are defined here so that we can redef
+	# the expire timeouts.
+	# FIXME: should we allow redef of attributes on IDs which
+	# are not exported?
+
+	# How many different hosts connected to with a possible
+	# backscatter signature.
+	global distinct_backscatter_peers: table[addr] of table[addr] of count
+		&read_expire = 15 min;
+
+	# Expire functions that trigger summaries.
+	global scan_summary:
+		function(t: table[addr] of set[addr], orig: addr): interval;
+	global port_summary:
+		function(t: table[addr] of set[port], orig: addr): interval;
+	global lowport_summary:
+		function(t: table[addr] of set[port], orig: addr): interval;
+
+	# Indexed by scanner address, yields # distinct peers scanned.
+	# pre_distinct_peers tracks until addr_scan_trigger hosts first.
+	global pre_distinct_peers: table[addr] of set[addr]
+		&read_expire = 15 mins &redef;
+
+	global distinct_peers: table[addr] of set[addr]
+		&read_expire = 15 mins &expire_func=scan_summary &redef;
+	global distinct_ports: table[addr] of set[port]
+		&read_expire = 15 mins &expire_func=port_summary &redef;
+	global distinct_low_ports: table[addr] of set[port]
+		&read_expire = 15 mins &expire_func=lowport_summary &redef;
+
+	# Indexed by scanner address, yields a table with scanned hosts
+	# (and ports).
+	global scan_triples: table[addr] of table[addr] of set[port];
+
+	global remove_possible_source:
+		function(s: set[addr], idx: addr): interval;
+	global possible_scan_sources: set[addr]
+		&expire_func=remove_possible_source &read_expire = 15 mins;
+
+	# Indexed by source address, yields user name & password tried.
+	global accounts_tried: table[addr] of set[string, string]
+		&read_expire = 1 days;
+
+	global ignored_scanners: set[addr] &create_expire = 1 day &redef;
+
+	# These tables track whether a threshold has been reached.
+	# More precisely, the counter is the next index of threshold vector.
+	global shut_down_thresh_reached: table[addr] of bool &default=F;
+	global rb_idx: table[addr] of count
+			&default=1 &read_expire = 1 days &redef;
+	global rps_idx: table[addr] of count
+			&default=1 &read_expire = 1 days &redef;
+	global rops_idx: table[addr] of count
+			&default=1 &read_expire = 1 days &redef;
+	global rpts_idx: table[addr,addr] of count
+			&default=1 &read_expire = 1 days &redef;
+	global rat_idx: table[addr] of count
+			&default=1 &read_expire = 1 days &redef;
+	global rrat_idx: table[addr] of count
+			&default=1 &read_expire = 1 days &redef;
+}
+
+global thresh_check: function(v: vector of count, idx: table[addr] of count,
+				orig: addr, n: count): bool;
+global thresh_check_2: function(v: vector of count,
+				idx: table[addr,addr] of count, orig: addr,
+				resp: addr, n: count): bool;
+
+function scan_summary(t: table[addr] of set[addr], orig: addr): interval
+	{
+	local num_distinct_peers = orig in t ? |t[orig]| : 0;
+
+	if ( num_distinct_peers >= scan_summary_trigger )
+		NOTICE([$note=ScanSummary, $src=orig, $n=num_distinct_peers,
+			$identifier=fmt("%s", orig),
+			$msg=fmt("%s scanned a total of %d hosts",
+					orig, num_distinct_peers)]);
+
+	return 0 secs;
+	}
+
+function port_summary(t: table[addr] of set[port], orig: addr): interval
+	{
+	local num_distinct_ports = orig in t ? |t[orig]| : 0;
+
+	if ( num_distinct_ports >= port_summary_trigger )
+		NOTICE([$note=PortScanSummary, $src=orig, $n=num_distinct_ports,
+			$identifier=fmt("%s", orig),
+			$msg=fmt("%s scanned a total of %d ports",
+					orig, num_distinct_ports)]);
+
+	return 0 secs;
+	}
+
+function lowport_summary(t: table[addr] of set[port], orig: addr): interval
+	{
+	local num_distinct_lowports = orig in t ? |t[orig]| : 0;
+
+	if ( num_distinct_lowports >= lowport_summary_trigger )
+		NOTICE([$note=LowPortScanSummary, $src=orig,
+			$n=num_distinct_lowports,
+			$identifier=fmt("%s", orig),
+			$msg=fmt("%s scanned a total of %d low ports",
+					orig, num_distinct_lowports)]);
+
+	return 0 secs;
+	}
+
+function clear_addr(a: addr)
+	{
+	delete distinct_peers[a];
+	delete distinct_ports[a];
+	delete distinct_low_ports[a];
+	delete scan_triples[a];
+	delete possible_scan_sources[a];
+	delete distinct_backscatter_peers[a];
+	delete pre_distinct_peers[a];
+	delete rb_idx[a];
+	delete rps_idx[a];
+	delete rops_idx[a];
+	delete rat_idx[a];
+	delete rrat_idx[a];
+	delete shut_down_thresh_reached[a];
+	delete ignored_scanners[a];
+	}
+
+function ignore_addr(a: addr)
+	{
+	clear_addr(a);
+	add ignored_scanners[a];
+	}
+
+function check_scan(c: connection, established: bool, reverse: bool): bool
+	{
+	local id = c$id;
+
+	local service = "ftp-data" in c$service ? 20/tcp
+			: (reverse ? id$orig_p : id$resp_p);
+	local rev_service = reverse ? id$resp_p : id$orig_p;
+	local orig = reverse ? id$resp_h : id$orig_h;
+	local resp = reverse ? id$orig_h : id$resp_h;
+	local outbound = Site::is_local_addr(orig);
+
+	# The following works better than using get_conn_transport_proto()
+	# because c might not correspond to an active connection (which
+	# causes the function to fail).
+	if ( suppress_UDP_scan_checks &&
+	     service >= 0/udp && service <= 65535/udp )
+		return F;
+
+	if ( service in skip_services && ! outbound )
+		return F;
+
+	if ( outbound && service in skip_outbound_services )
+		return F;
+
+	if ( orig in skip_scan_sources )
+		return F;
+
+	if ( orig in skip_scan_nets )
+		return F;
+
+	# Don't include well known server/ports for scanning purposes.
+	if ( ! outbound && [resp, service] in skip_dest_server_ports )
+		return F;
+
+	if ( orig in ignored_scanners)
+		return F;
+
+	if ( ! established &&
+		# not established, service not expressly allowed
+
+		# not known peer set
+		(orig !in distinct_peers || resp !in distinct_peers[orig]) &&
+
+		# want to consider service for scan detection
+		(analyze_all_services || service in analyze_services) )
+		{
+		if ( reverse && rev_service in backscatter_ports &&
+		     # reverse, non-priv backscatter port
+		     service >= 1024/tcp )
+			{
+			if ( orig !in distinct_backscatter_peers )
+				{
+				local empty_bs_table:
+					table[addr] of count &default=0;
+				distinct_backscatter_peers[orig] =
+					empty_bs_table;
+				}
+
+			if ( ++distinct_backscatter_peers[orig][resp] <= 2 &&
+			     # The test is <= 2 because we get two check_scan()
+			     # calls, once on connection attempt and once on
+			     # tear-down.
+
+			     distinct_backscatter_peers[orig][resp] == 1 &&
+
+			     # Looks like backscatter, and it's not scanning
+			     # a privileged port.
+
+			     thresh_check(report_backscatter, rb_idx, orig,
+					|distinct_backscatter_peers[orig]|)
+			   )
+				{
+				NOTICE([$note=BackscatterSeen, $src=orig,
+					$p=rev_service,
+					$identifier=fmt("%s", orig),
+					$msg=fmt("backscatter seen from %s (%d hosts; %s)",
+						orig, |distinct_backscatter_peers[orig]|, rev_service)]);
+				}
+
+			if ( ignore_scanners_threshold > 0 &&
+			     |distinct_backscatter_peers[orig]| >
+					ignore_scanners_threshold )
+				ignore_addr(orig);
+			}
+
+		else
+			{ # done with backscatter check
+			local ignore = F;
+
+			if ( orig !in distinct_peers && addr_scan_trigger > 0 )
+				{
+				if ( orig !in pre_distinct_peers )
+					pre_distinct_peers[orig] = set();
+
+				add pre_distinct_peers[orig][resp];
+				if ( |pre_distinct_peers[orig]| < addr_scan_trigger )
+					ignore = T;
+				}
+
+			if ( ! ignore )
+				{ # XXXXX
+
+				if ( orig !in distinct_peers )
+					distinct_peers[orig] = set() &mergeable;
+
+				if ( resp !in distinct_peers[orig] )
+					add distinct_peers[orig][resp];
+
+				local n = |distinct_peers[orig]|;
+
+				# Check for threshold if not outbound.
+				if ( ! shut_down_thresh_reached[orig] &&
+				     n >= shut_down_thresh &&
+				     ! outbound && orig !in Site::neighbor_nets )
+					{
+					shut_down_thresh_reached[orig] = T;
+					local msg = fmt("shutdown threshold reached for %s", orig);
+					NOTICE([$note=ShutdownThresh, $src=orig,
+						$identifier=fmt("%s", orig),
+						$p=service, $msg=msg]);
+					}
+
+				else
+					{
+					local address_scan = F;
+					if ( outbound &&
+					     # inside host scanning out?
+					     thresh_check(report_outbound_peer_scan, rops_idx, orig, n) )
+						address_scan = T;
+
+					if ( ! outbound &&
+					     thresh_check(report_peer_scan, rps_idx, orig, n) )
+						address_scan = T;
+
+					if ( address_scan )
+						NOTICE([$note=AddressScan,
+							$src=orig, $p=service,
+							$n=n,
+							$identifier=fmt("%s-%d", orig, n),
+							$msg=fmt("%s has scanned %d hosts (%s)",
+								orig, n, service)]);
+
+					if ( address_scan &&
+					     ignore_scanners_threshold > 0 &&
+					     n > ignore_scanners_threshold )
+						ignore_addr(orig);
+					}
+				}
+			} # XXXX
+		}
+
+	if ( established )
+		# Don't consider established connections for port scanning,
+		# it's too easy to be mislead by FTP-like applications that
+		# legitimately gobble their way through the port space.
+		return F;
+
+	# Coarse search for port-scanning candidates: those that have made
+	# connections (attempts) to possible_port_scan_thresh or more
+	# distinct ports.
+	if ( orig !in distinct_ports || service !in distinct_ports[orig] )
+		{
+		if ( orig !in distinct_ports )
+			distinct_ports[orig] = set() &mergeable;
+
+		if ( service !in distinct_ports[orig] )
+			add distinct_ports[orig][service];
+
+		if ( |distinct_ports[orig]| >= possible_port_scan_thresh &&
+			orig !in scan_triples )
+			{
+			scan_triples[orig] = table() &mergeable;
+			add possible_scan_sources[orig];
+			}
+		}
+
+	# Check for low ports.
+	if ( activate_priv_port_check && ! outbound && service < 1024/tcp &&
+	     service !in troll_skip_service )
+		{
+		if ( orig !in distinct_low_ports ||
+		     service !in distinct_low_ports[orig] )
+			{
+			if ( orig !in distinct_low_ports )
+				distinct_low_ports[orig] = set() &mergeable;
+
+			add distinct_low_ports[orig][service];
+
+			if ( |distinct_low_ports[orig]| == priv_scan_trigger &&
+			     orig !in Site::neighbor_nets )
+				{
+				local svrc_msg = fmt("low port trolling %s %s", orig, service);
+				NOTICE([$note=LowPortTrolling, $src=orig,
+					$identifier=fmt("%s", orig),
+					$p=service, $msg=svrc_msg]);
+				}
+
+			if ( ignore_scanners_threshold > 0 &&
+			     |distinct_low_ports[orig]| >
+					ignore_scanners_threshold )
+				ignore_addr(orig);
+			}
+		}
+
+	# For sources that have been identified as possible scan sources,
+	# keep track of per-host scanning.
+	if ( orig in possible_scan_sources )
+		{
+		if ( orig !in scan_triples )
+			scan_triples[orig] = table() &mergeable;
+
+		if ( resp !in scan_triples[orig] )
+			scan_triples[orig][resp] = set() &mergeable;
+
+		if ( service !in scan_triples[orig][resp] )
+			{
+			add scan_triples[orig][resp][service];
+
+			if ( thresh_check_2(report_port_scan, rpts_idx,
+					    orig, resp,
+					    |scan_triples[orig][resp]|) )
+				{
+				local m = |scan_triples[orig][resp]|;
+				NOTICE([$note=PortScan, $n=m, $src=orig,
+					$p=service,
+					$identifier=fmt("%s-%d", orig, n),
+					$msg=fmt("%s has scanned %d ports of %s",
+					orig, m, resp)]);
+				}
+			}
+		}
+
+	return T;
+	}
+
+
+# Hook into the catch&release dropping. When an address gets restored, we reset
+# the source to allow dropping it again.
+event Drop::address_restored(a: addr)
+	{
+	clear_addr(a);
+	}
+
+event Drop::address_cleared(a: addr)
+	{
+	clear_addr(a);
+	}
+
+# When removing a possible scan source, we automatically delete its scanned
+# hosts and ports.  But we do not want the deletion propagated, because every
+# peer calls the expire_function on its own (and thus applies the delete
+# operation on its own table).
+function remove_possible_source(s: set[addr], idx: addr): interval
+	{
+	suspend_state_updates();
+	delete scan_triples[idx];
+	resume_state_updates();
+
+	return 0 secs;
+	}
+
+# To recognize whether a certain threshhold vector (e.g. report_peer_scans)
+# has been transgressed, a global variable containing the next vector index
+# (idx) must be incremented.  This cumbersome mechanism is necessary because
+# values naturally don't increment by one (e.g. replayed table merges).
+function thresh_check(v: vector of count, idx: table[addr] of count,
+			orig: addr, n: count): bool
+	{
+	if ( ignore_scanners_threshold > 0 && n > ignore_scanners_threshold )
+		{
+		ignore_addr(orig);
+		return F;
+		}
+
+	if ( idx[orig] <= |v| && n >= v[idx[orig]] )
+		{
+		++idx[orig];
+		return T;
+		}
+	else
+		return F;
+	}
+
+# Same as above, except the index has a different type signature.
+function thresh_check_2(v: vector of count, idx: table[addr, addr] of count,
+			orig: addr, resp: addr, n: count): bool
+	{
+	if ( ignore_scanners_threshold > 0 && n > ignore_scanners_threshold )
+		{
+		ignore_addr(orig);
+		return F;
+		}
+
+	if ( idx[orig,resp] <= |v| && n >= v[idx[orig, resp]] )
+		{
+		++idx[orig,resp];
+		return T;
+		}
+	else
+		return F;
+	}
+
+event connection_established(c: connection)
+	{
+	local is_reverse_scan = (c$orig$state == TCP_INACTIVE);
+	Scan::check_scan(c, T, is_reverse_scan);
+	}
+
+event partial_connection(c: connection)
+	{
+	Scan::check_scan(c, T, F);
+	}
+
+event connection_attempt(c: connection)
+	{
+	Scan::check_scan(c, F, c$orig$state == TCP_INACTIVE);
+	}
+
+event connection_half_finished(c: connection)
+	{
+	# Half connections never were "established", so do scan-checking here.
+	Scan::check_scan(c, F, F);
+	}
+
+event connection_rejected(c: connection)
+	{
+	local is_reverse_scan = c$orig$state == TCP_RESET;
+
+	Scan::check_scan(c, F, is_reverse_scan);
+	}
+
+event connection_reset(c: connection)
+	{
+	if ( c$orig$state == TCP_INACTIVE || c$resp$state == TCP_INACTIVE )
+		# We never heard from one side - that looks like a scan.
+		Scan::check_scan(c, c$orig$size + c$resp$size > 0,
+				c$orig$state == TCP_INACTIVE);
+	}
+
+event connection_pending(c: connection)
+	{
+	if ( c$orig$state == TCP_PARTIAL && c$resp$state == TCP_INACTIVE )
+		Scan::check_scan(c, F, F);
+	}
+
+# Report the remaining entries in the tables.
+event bro_done()
+	{
+	for ( orig in distinct_peers )
+		scan_summary(distinct_peers, orig);
+
+	for ( orig in distinct_ports )
+		port_summary(distinct_ports, orig);
+
+	for ( orig in distinct_low_ports )
+		lowport_summary(distinct_low_ports, orig);
+	}
+
+ +

Known failures

+

There are certain edge cases where Prism will fail. + There are always such cases in every regex-based syntax highlighter. + However, Prism dares to be open and honest about them. + If a failure is listed here, it doesn’t mean it will never be fixed. This is more of a “known bugs” list, just with a certain type of bug. +

+ +

Comment-like substrings

+
"foo /* bar */ baz"; "foo // bar";
\ No newline at end of file From 4b1698bb200272dc87f5cd9135a37e14d96b0293 Mon Sep 17 00:00:00 2001 From: wayward710 Date: Fri, 1 Apr 2016 02:08:35 -0500 Subject: [PATCH 2/8] More improvements to Bro --- components/prism-bro.js | 52 +++-- examples/prism-bro.html | 447 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 481 insertions(+), 18 deletions(-) diff --git a/components/prism-bro.js b/components/prism-bro.js index 47ae7907b8..1f8d841048 100644 --- a/components/prism-bro.js +++ b/components/prism-bro.js @@ -13,55 +13,69 @@ Prism.languages.bro = { 'keyword': [ /\b(break|next|continue)\b/, /\b(alarm|using|of|add|delete)\b/, - /\b(default|export|event)\b/, - /\b(print|redef|return|schedule)\b/, + /\b(export)\b/, + /\b(print|return|schedule)\b/, /\b(when|timeout)\b/, /\b(addr|any|bool|count)\b/, /\b(double|enum)\b/, /\b(file|int|interval)\b/, - /\b(pattern)\b/, + /\b(pattern|opaque)\b/, /\b(port|record|set)\b/, /\b(string|subnet|table)\b/, /\b(time|vector)\b/, - /\b(for|if|else)\b/, - /\b(day|hr|min|sec|usec)s\b/ - - + /\b(for|if|else)\b/, ], - 'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/, - 'function': + 'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/, + + 'function': [ { - pattern: /function [a-z0-9_]+/i, + pattern: /function [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i, inside: { keyword: /function/ } }, + { + pattern: /hook [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i, + inside: { + keyword: /hook/ + } + }, + + { + pattern: /event [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i, + inside: { + keyword: /event/ + } + } + ], + 'variable': [{ - pattern: /global [a-z0-9_]+/i, + pattern: /global [a-zA-Z0-9_]+/i, inside: { keyword: /global/ } }, { - pattern: /local [a-z0-9_]+/i, + pattern: /local [a-zA-Z0-9_]+/i, inside: { keyword: /local/ } }], - 'number': [ + 'number': [ /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i, - ], + ], 'italic': /\b(TODO|FIXME|XXX)\b/, 'punctuation': /[{}[\];(),.:]/, - 'builtin': [ + 'builtin': + [ /@load\s+/, /@load-sigs\s+/, /@load-plugin\s+/, @@ -73,12 +87,14 @@ Prism.languages.bro = { /@else\s+/, /@endif\s+/, /@DIR\s+/, - /@FILENAME\s+/ + /@FILENAME\s+/, + {pattern: /&(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column)/, + } ], - + 'constant': { - pattern: /const [a-z0-9_]+/i, + pattern: /const [a-zA-Z0-9_]+/i, inside: { keyword: /const/ } diff --git a/examples/prism-bro.html b/examples/prism-bro.html index 33084d5f10..ee9d899090 100644 --- a/examples/prism-bro.html +++ b/examples/prism-bro.html @@ -646,6 +646,453 @@

Full example

} +

+
+
+# $Id: conn.bro 6782 2009-06-28 02:19:03Z vern $
+
+@load notice
+@load hot
+@load port-name
+@load netstats
+@load conn-id
+
+redef enum Notice += {
+	SensitiveConnection,	# connection marked "hot"
+};
+
+const conn_closed = { TCP_CLOSED, TCP_RESET };
+
+global have_FTP = F;	# if true, we've loaded ftp.bro
+global have_SMTP = F;	# if true, we've loaded smtp.bro
+global is_ftp_data_conn: function(c: connection): bool;
+
+# Whether to include connection state history in the logs generated
+# by record_connection.
+const record_state_history = F &redef;
+
+# Whether to translate the local address in SensitiveConnection notices
+# to a hostname.  Meant as a demonstration of the "when" construct.
+const xlate_hot_local_addr = F &redef;
+
+# Whether to use DPD for generating the service field in the summaries.
+# Default off, because it changes the format of conn.log in a way
+# potentially incompatible with existing scripts.
+const dpd_conn_logs = F &redef;
+
+# Maps a given port on a given server's address to an RPC service.
+# If we haven't loaded portmapper.bro, then it will be empty
+# (and, ideally, queries to it would be optimized away ...).
+global RPC_server_map: table[addr, port] of string;
+
+const conn_file = open_log_file("conn") &redef;
+
+function conn_state(c: connection, trans: transport_proto): string
+	{
+	local os = c$orig$state;
+	local rs = c$resp$state;
+
+	local o_inactive = os == TCP_INACTIVE || os == TCP_PARTIAL;
+	local r_inactive = rs == TCP_INACTIVE || rs == TCP_PARTIAL;
+
+	if ( trans == tcp )
+		{
+		if ( rs == TCP_RESET )
+			{
+			if ( os == TCP_SYN_SENT || os == TCP_SYN_ACK_SENT ||
+			     (os == TCP_RESET &&
+			      c$orig$size == 0 && c$resp$size == 0) )
+				return "REJ";
+			else if ( o_inactive )
+				return "RSTRH";
+			else
+				return "RSTR";
+			}
+		else if ( os == TCP_RESET )
+			return r_inactive ? "RSTOS0" : "RSTO";
+		else if ( rs == TCP_CLOSED && os == TCP_CLOSED )
+			return "SF";
+		else if ( os == TCP_CLOSED )
+			return r_inactive ? "SH" : "S2";
+		else if ( rs == TCP_CLOSED )
+			return o_inactive ? "SHR" : "S3";
+		else if ( os == TCP_SYN_SENT && rs == TCP_INACTIVE )
+			return "S0";
+		else if ( os == TCP_ESTABLISHED && rs == TCP_ESTABLISHED )
+			return "S1";
+		else
+			return "OTH";
+		}
+
+	else if ( trans == udp )
+		{
+		if ( os == UDP_ACTIVE )
+			return rs == UDP_ACTIVE ? "SF" : "S0";
+		else
+			return rs == UDP_ACTIVE ? "SHR" : "OTH";
+		}
+
+	else
+		return "OTH";
+	}
+
+function conn_size(e: endpoint, trans: transport_proto): string
+	{
+	if ( e$size > 0 || (trans == tcp && e$state == TCP_CLOSED) )
+		return fmt("%d", e$size);
+	else
+		### should return 0 for TCP_RESET that went through TCP_CLOSED
+		return "?";
+	}
+
+function service_name(c: connection): string
+	{
+	local p = c$id$resp_p;
+
+	if ( p in port_names )
+		return port_names[p];
+	else
+		return "other";
+	}
+
+const state_graphic = {
+	["OTH"] = "?>?", ["REJ"] = "[",
+	["RSTO"] = ">]", ["RSTOS0"] = "}]", ["RSTR"] = ">[", ["RSTRH"] = "<[",
+	["S0"] = "}", ["S1"] = ">", ["S2"] = "}2", ["S3"] = "}3",
+	["SF"] = ">", ["SH"] = ">h", ["SHR"] = " 0 )
+		log_hot_conn(c);
+
+	if ( trans == tcp )
+		{
+		if ( c$orig$state in conn_closed || c$resp$state in conn_closed )
+			duration = fmt("%.06f", c$duration);
+		else
+			duration = "?";
+		}
+	else
+		duration = fmt("%.06f", c$duration);
+
+	local addl = c$addl;
+
+@ifdef ( estimate_flow_size_and_remove )
+	# Annotate connection with separately-estimated size, if present.
+	local orig_est = estimate_flow_size_and_remove(id, T);
+	local resp_est = estimate_flow_size_and_remove(id, F);
+
+	if ( orig_est$have_est )
+		addl = fmt("%s olower=%.0fMB oupper=%.0fMB oincon=%s", addl,
+				orig_est$lower / 1e6, orig_est$upper / 1e6,
+				orig_est$num_inconsistent);
+
+	if ( resp_est$have_est )
+		addl = fmt("%s rlower=%.0fMB rupper=%.0fMB rincon=%s", addl,
+				resp_est$lower / 1e6, resp_est$upper / 1e6,
+				resp_est$num_inconsistent);
+@endif
+
+	local service = determine_service(c);
+
+	local log_msg =
+		fmt("%.6f %s %s %s %s %d %d %s %s %s %s %s",
+			c$start_time, duration, id$orig_h, id$resp_h, service,
+			id$orig_p, id$resp_p, trans,
+			conn_size(c$orig, trans), conn_size(c$resp, trans),
+			conn_state(c, trans), flags);
+
+	if ( record_state_history )
+		log_msg = fmt("%s %s", log_msg,
+				c$history == "" ? "X" : c$history);
+
+	if ( addl != "" )
+		log_msg = fmt("%s %s", log_msg, addl);
+
+	print f, log_msg;
+	}
+
+event protocol_confirmation(c: connection, atype: count, aid: count)
+	{
+	if ( ! dpd_conn_logs )
+		return;
+
+	delete c$service[fmt("-%s",analyzer_name(atype))];
+	add c$service[analyzer_name(atype)];
+	}
+
+event protocol_violation(c: connection, atype: count, aid: count,
+				reason: string) &priority = 10
+	{
+	if ( ! dpd_conn_logs )
+		return;
+
+	delete c$service[analyzer_name(atype)];
+	add c$service[fmt("-%s",analyzer_name(atype))];
+	}
+
+event connection_established(c: connection)
+	{
+	Hot::check_hot(c, Hot::CONN_ESTABLISHED);
+
+	if ( c$hot > 0 )
+		log_hot_conn(c);
+	}
+
+event partial_connection(c: connection)
+	{
+	if ( c$orig$state == TCP_PARTIAL && c$resp$state == TCP_INACTIVE )
+		# This appears to be a stealth scan.  Don't do hot-checking
+		# as there wasn't an established connection.
+		;
+	else
+		{
+		Hot::check_hot(c, Hot::CONN_ESTABLISHED);
+		Hot::check_hot(c, Hot::APPL_ESTABLISHED);	# assume it's been established
+		}
+
+	if ( c$hot > 0 )
+		log_hot_conn(c);
+	}
+
+event connection_attempt(c: connection)
+	{
+	Hot::check_spoof(c);
+	Hot::check_hot(c, Hot::CONN_ATTEMPTED);
+	}
+
+event connection_finished(c: connection)
+	{
+	if ( c$orig$size == 0 || c$resp$size == 0 )
+		# Hard to get excited about this - not worth logging again.
+		c$hot = 0;
+	else
+		Hot::check_hot(c, Hot::CONN_FINISHED);
+	}
+
+event connection_partial_close(c: connection)
+	{
+	if ( c$orig$size == 0 || c$resp$size == 0 )
+		# Hard to get excited about this - not worth logging again.
+		c$hot = 0;
+	else
+		Hot::check_hot(c, Hot::CONN_FINISHED);
+	}
+
+event connection_half_finished(c: connection)
+	{
+	Hot::check_hot(c, Hot::CONN_ATTEMPTED);
+	}
+
+event connection_rejected(c: connection)
+	{
+	Hot::check_hot(c, Hot::CONN_REJECTED);
+	}
+
+event connection_reset(c: connection)
+	{
+	Hot::check_hot(c, Hot::CONN_FINISHED);
+	}
+
+event connection_pending(c: connection)
+	{
+	if ( c$orig$state in conn_closed &&
+	     (c$resp$state == TCP_INACTIVE || c$resp$state == TCP_PARTIAL) )
+		# This is a stray FIN or RST - don't bother reporting.
+		return;
+
+	if ( c$orig$state == TCP_RESET || c$resp$state == TCP_RESET )
+		# We already reported this connection when the RST
+		# occurred.
+		return;
+
+	Hot::check_hot(c, Hot::CONN_FINISHED);
+	}
+
+function connection_gone(c: connection, gone_type: string)
+	{
+	if ( c$orig$size == 0 || c$resp$size == 0 )
+		{
+		if ( c$orig$state == TCP_RESET && c$resp$state == TCP_INACTIVE)
+			# A bare RST, no other context.  Ignore it.
+			return;
+
+		# Hard to get excited about this - not worth logging again,
+		# per connection_finished().
+		c$hot = 0;
+		}
+	else
+		Hot::check_hot(c, Hot::CONN_TIMEOUT);
+	}
+
+event connection_state_remove(c: connection) &priority = -10
+	{
+	local os = c$orig$state;
+	local rs = c$resp$state;
+
+	if ( os == TCP_ESTABLISHED && rs == TCP_ESTABLISHED )
+		# It was still active, no summary generated.
+		connection_gone(c, "remove");
+
+	else if ( (os == TCP_CLOSED || rs == TCP_CLOSED) &&
+		  (os == TCP_ESTABLISHED || rs == TCP_ESTABLISHED) )
+		# One side has closed, the other hasn't - it's in state S2
+		# or S3, hasn't been reported yet.
+		connection_gone(c, "remove");
+
+	record_connection(conn_file, c);
+
+	delete hot_conns_reported[c$id];
+	}
+
+

Known failures

There are certain edge cases where Prism will fail. There are always such cases in every regex-based syntax highlighter. From 3e6eed3e9878971cd674c852a829d8fe5efbe750 Mon Sep 17 00:00:00 2001 From: wayward710 Date: Fri, 1 Apr 2016 02:48:10 -0500 Subject: [PATCH 3/8] Minified prism-bro.js file to prism-bro.min.js --- components/prism-bro.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/prism-bro.min.js b/components/prism-bro.min.js index 850d55a2e6..779efb6e94 100644 --- a/components/prism-bro.min.js +++ b/components/prism-bro.min.js @@ -1 +1 @@ -Prism.languages.bro={"comment":[{pattern:/(^|[^\\$])#.*/,lookbehind:true}],"string":/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"boolean":/\b(T|F)\b/,"keyword":[/\b(break|next|continue)\b/,/\b(alarm|using|of|add|delete)\b/,/\b(default|export|event)\b/,/\b(print|redef|return|schedule)\b/,/\b(when|timeout)\b/,/\b(addr|any|bool|count)\b/,/\b(double|enum)\b/,/\b(file|int|interval)\b/,/\b(pattern)\b/,/\b(port|record|set)\b/,/\b(string|subnet|table)\b/,/\b(time|vector)\b/,/\b(for|if|else)\b/,/\b(day|hr|min|sec|usec)s\b/],"operator":/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,"function":{pattern:/function [a-z0-9_]+/i,inside:{keyword:/function/}},"variable":[{pattern:/global [a-z0-9_]+/i,inside:{keyword:/global/}},{pattern:/local [a-z0-9_]+/i,inside:{keyword:/local/}}],"number":[/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,],"italic":/\b(TODO|FIXME|XXX)\b/,"punctuation":/[{}[\];(),.:]/,"builtin":[/@load\s+/,/@load-sigs\s+/,/@load-plugin\s+/,/@unload\s+/,/@prefixes\s+/,/@if\s+/,/@ifdef\s+/,/@ifndef\s+/,/@else\s+/,/@endif\s+/,/@DIR\s+/,/@FILENAME\s+/],"constant":{pattern:/const [a-z0-9_]+/i,inside:{keyword:/const/}},}; \ No newline at end of file +Prism.languages.bro={"comment":[{pattern:/(^|[^\\$])#.*/,lookbehind:true}],"string":/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"boolean":/\b(T|F)\b/,"keyword":[/\b(break|next|continue)\b/,/\b(alarm|using|of|add|delete)\b/,/\b(export)\b/,/\b(print|return|schedule)\b/,/\b(when|timeout)\b/,/\b(addr|any|bool|count)\b/,/\b(double|enum)\b/,/\b(file|int|interval)\b/,/\b(pattern|opaque)\b/,/\b(port|record|set)\b/,/\b(string|subnet|table)\b/,/\b(time|vector)\b/,/\b(for|if|else)\b/,],"operator":/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/,"function":[{pattern:/function [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i,inside:{keyword:/function/}},{pattern:/hook [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i,inside:{keyword:/hook/}},{pattern:/event [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i,inside:{keyword:/event/}}],"variable":[{pattern:/global [a-zA-Z0-9_]+/i,inside:{keyword:/global/}},{pattern:/local [a-zA-Z0-9_]+/i,inside:{keyword:/local/}}],"number":[/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,],"italic":/\b(TODO|FIXME|XXX)\b/,"punctuation":/[{}[\];(),.:]/,"builtin":[/@load\s+/,/@load-sigs\s+/,/@load-plugin\s+/,/@unload\s+/,/@prefixes\s+/,/@if\s+/,/@ifdef\s+/,/@ifndef\s+/,/@else\s+/,/@endif\s+/,/@DIR\s+/,/@FILENAME\s+/,{pattern:/&(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column)/,}],"constant":{pattern:/const [a-zA-Z0-9_]+/i,inside:{keyword:/const/}},}; \ No newline at end of file From ba43d2a67684bd9bbb44785a623cb0866938a174 Mon Sep 17 00:00:00 2001 From: wayward710 Date: Fri, 1 Apr 2016 02:56:29 -0500 Subject: [PATCH 4/8] Better HTML example --- examples.js | 1 - examples/prism-bro.html | 457 +--------------------------------------- 2 files changed, 1 insertion(+), 457 deletions(-) diff --git a/examples.js b/examples.js index 83bc2286b3..02897d34ea 100644 --- a/examples.js +++ b/examples.js @@ -85,7 +85,6 @@ function fileExists(filepath) { return true; } } - //return false; return true; }); } diff --git a/examples/prism-bro.html b/examples/prism-bro.html index ee9d899090..c8a7f18026 100644 --- a/examples/prism-bro.html +++ b/examples/prism-bro.html @@ -14,11 +14,6 @@

Numbers

123
 123.456
 -123.456
-.3f
-1.3e9d
-0xaf
-0xAF
-0xFF.AEP-4
 

Full example

@@ -646,459 +641,9 @@

Full example

} -

-
-
-# $Id: conn.bro 6782 2009-06-28 02:19:03Z vern $
-
-@load notice
-@load hot
-@load port-name
-@load netstats
-@load conn-id
-
-redef enum Notice += {
-	SensitiveConnection,	# connection marked "hot"
-};
-
-const conn_closed = { TCP_CLOSED, TCP_RESET };
-
-global have_FTP = F;	# if true, we've loaded ftp.bro
-global have_SMTP = F;	# if true, we've loaded smtp.bro
-global is_ftp_data_conn: function(c: connection): bool;
-
-# Whether to include connection state history in the logs generated
-# by record_connection.
-const record_state_history = F &redef;
-
-# Whether to translate the local address in SensitiveConnection notices
-# to a hostname.  Meant as a demonstration of the "when" construct.
-const xlate_hot_local_addr = F &redef;
-
-# Whether to use DPD for generating the service field in the summaries.
-# Default off, because it changes the format of conn.log in a way
-# potentially incompatible with existing scripts.
-const dpd_conn_logs = F &redef;
-
-# Maps a given port on a given server's address to an RPC service.
-# If we haven't loaded portmapper.bro, then it will be empty
-# (and, ideally, queries to it would be optimized away ...).
-global RPC_server_map: table[addr, port] of string;
-
-const conn_file = open_log_file("conn") &redef;
-
-function conn_state(c: connection, trans: transport_proto): string
-	{
-	local os = c$orig$state;
-	local rs = c$resp$state;
-
-	local o_inactive = os == TCP_INACTIVE || os == TCP_PARTIAL;
-	local r_inactive = rs == TCP_INACTIVE || rs == TCP_PARTIAL;
-
-	if ( trans == tcp )
-		{
-		if ( rs == TCP_RESET )
-			{
-			if ( os == TCP_SYN_SENT || os == TCP_SYN_ACK_SENT ||
-			     (os == TCP_RESET &&
-			      c$orig$size == 0 && c$resp$size == 0) )
-				return "REJ";
-			else if ( o_inactive )
-				return "RSTRH";
-			else
-				return "RSTR";
-			}
-		else if ( os == TCP_RESET )
-			return r_inactive ? "RSTOS0" : "RSTO";
-		else if ( rs == TCP_CLOSED && os == TCP_CLOSED )
-			return "SF";
-		else if ( os == TCP_CLOSED )
-			return r_inactive ? "SH" : "S2";
-		else if ( rs == TCP_CLOSED )
-			return o_inactive ? "SHR" : "S3";
-		else if ( os == TCP_SYN_SENT && rs == TCP_INACTIVE )
-			return "S0";
-		else if ( os == TCP_ESTABLISHED && rs == TCP_ESTABLISHED )
-			return "S1";
-		else
-			return "OTH";
-		}
-
-	else if ( trans == udp )
-		{
-		if ( os == UDP_ACTIVE )
-			return rs == UDP_ACTIVE ? "SF" : "S0";
-		else
-			return rs == UDP_ACTIVE ? "SHR" : "OTH";
-		}
-
-	else
-		return "OTH";
-	}
-
-function conn_size(e: endpoint, trans: transport_proto): string
-	{
-	if ( e$size > 0 || (trans == tcp && e$state == TCP_CLOSED) )
-		return fmt("%d", e$size);
-	else
-		### should return 0 for TCP_RESET that went through TCP_CLOSED
-		return "?";
-	}
-
-function service_name(c: connection): string
-	{
-	local p = c$id$resp_p;
-
-	if ( p in port_names )
-		return port_names[p];
-	else
-		return "other";
-	}
-
-const state_graphic = {
-	["OTH"] = "?>?", ["REJ"] = "[",
-	["RSTO"] = ">]", ["RSTOS0"] = "}]", ["RSTR"] = ">[", ["RSTRH"] = "<[",
-	["S0"] = "}", ["S1"] = ">", ["S2"] = "}2", ["S3"] = "}3",
-	["SF"] = ">", ["SH"] = ">h", ["SHR"] = " 0 )
-		log_hot_conn(c);
-
-	if ( trans == tcp )
-		{
-		if ( c$orig$state in conn_closed || c$resp$state in conn_closed )
-			duration = fmt("%.06f", c$duration);
-		else
-			duration = "?";
-		}
-	else
-		duration = fmt("%.06f", c$duration);
-
-	local addl = c$addl;
-
-@ifdef ( estimate_flow_size_and_remove )
-	# Annotate connection with separately-estimated size, if present.
-	local orig_est = estimate_flow_size_and_remove(id, T);
-	local resp_est = estimate_flow_size_and_remove(id, F);
-
-	if ( orig_est$have_est )
-		addl = fmt("%s olower=%.0fMB oupper=%.0fMB oincon=%s", addl,
-				orig_est$lower / 1e6, orig_est$upper / 1e6,
-				orig_est$num_inconsistent);
-
-	if ( resp_est$have_est )
-		addl = fmt("%s rlower=%.0fMB rupper=%.0fMB rincon=%s", addl,
-				resp_est$lower / 1e6, resp_est$upper / 1e6,
-				resp_est$num_inconsistent);
-@endif
-
-	local service = determine_service(c);
-
-	local log_msg =
-		fmt("%.6f %s %s %s %s %d %d %s %s %s %s %s",
-			c$start_time, duration, id$orig_h, id$resp_h, service,
-			id$orig_p, id$resp_p, trans,
-			conn_size(c$orig, trans), conn_size(c$resp, trans),
-			conn_state(c, trans), flags);
-
-	if ( record_state_history )
-		log_msg = fmt("%s %s", log_msg,
-				c$history == "" ? "X" : c$history);
-
-	if ( addl != "" )
-		log_msg = fmt("%s %s", log_msg, addl);
-
-	print f, log_msg;
-	}
-
-event protocol_confirmation(c: connection, atype: count, aid: count)
-	{
-	if ( ! dpd_conn_logs )
-		return;
-
-	delete c$service[fmt("-%s",analyzer_name(atype))];
-	add c$service[analyzer_name(atype)];
-	}
-
-event protocol_violation(c: connection, atype: count, aid: count,
-				reason: string) &priority = 10
-	{
-	if ( ! dpd_conn_logs )
-		return;
-
-	delete c$service[analyzer_name(atype)];
-	add c$service[fmt("-%s",analyzer_name(atype))];
-	}
-
-event connection_established(c: connection)
-	{
-	Hot::check_hot(c, Hot::CONN_ESTABLISHED);
-
-	if ( c$hot > 0 )
-		log_hot_conn(c);
-	}
-
-event partial_connection(c: connection)
-	{
-	if ( c$orig$state == TCP_PARTIAL && c$resp$state == TCP_INACTIVE )
-		# This appears to be a stealth scan.  Don't do hot-checking
-		# as there wasn't an established connection.
-		;
-	else
-		{
-		Hot::check_hot(c, Hot::CONN_ESTABLISHED);
-		Hot::check_hot(c, Hot::APPL_ESTABLISHED);	# assume it's been established
-		}
-
-	if ( c$hot > 0 )
-		log_hot_conn(c);
-	}
-
-event connection_attempt(c: connection)
-	{
-	Hot::check_spoof(c);
-	Hot::check_hot(c, Hot::CONN_ATTEMPTED);
-	}
-
-event connection_finished(c: connection)
-	{
-	if ( c$orig$size == 0 || c$resp$size == 0 )
-		# Hard to get excited about this - not worth logging again.
-		c$hot = 0;
-	else
-		Hot::check_hot(c, Hot::CONN_FINISHED);
-	}
-
-event connection_partial_close(c: connection)
-	{
-	if ( c$orig$size == 0 || c$resp$size == 0 )
-		# Hard to get excited about this - not worth logging again.
-		c$hot = 0;
-	else
-		Hot::check_hot(c, Hot::CONN_FINISHED);
-	}
-
-event connection_half_finished(c: connection)
-	{
-	Hot::check_hot(c, Hot::CONN_ATTEMPTED);
-	}
-
-event connection_rejected(c: connection)
-	{
-	Hot::check_hot(c, Hot::CONN_REJECTED);
-	}
-
-event connection_reset(c: connection)
-	{
-	Hot::check_hot(c, Hot::CONN_FINISHED);
-	}
-
-event connection_pending(c: connection)
-	{
-	if ( c$orig$state in conn_closed &&
-	     (c$resp$state == TCP_INACTIVE || c$resp$state == TCP_PARTIAL) )
-		# This is a stray FIN or RST - don't bother reporting.
-		return;
-
-	if ( c$orig$state == TCP_RESET || c$resp$state == TCP_RESET )
-		# We already reported this connection when the RST
-		# occurred.
-		return;
-
-	Hot::check_hot(c, Hot::CONN_FINISHED);
-	}
-
-function connection_gone(c: connection, gone_type: string)
-	{
-	if ( c$orig$size == 0 || c$resp$size == 0 )
-		{
-		if ( c$orig$state == TCP_RESET && c$resp$state == TCP_INACTIVE)
-			# A bare RST, no other context.  Ignore it.
-			return;
-
-		# Hard to get excited about this - not worth logging again,
-		# per connection_finished().
-		c$hot = 0;
-		}
-	else
-		Hot::check_hot(c, Hot::CONN_TIMEOUT);
-	}
-
-event connection_state_remove(c: connection) &priority = -10
-	{
-	local os = c$orig$state;
-	local rs = c$resp$state;
-
-	if ( os == TCP_ESTABLISHED && rs == TCP_ESTABLISHED )
-		# It was still active, no summary generated.
-		connection_gone(c, "remove");
-
-	else if ( (os == TCP_CLOSED || rs == TCP_CLOSED) &&
-		  (os == TCP_ESTABLISHED || rs == TCP_ESTABLISHED) )
-		# One side has closed, the other hasn't - it's in state S2
-		# or S3, hasn't been reported yet.
-		connection_gone(c, "remove");
-
-	record_connection(conn_file, c);
-
-	delete hot_conns_reported[c$id];
-	}
-
-

Known failures

There are certain edge cases where Prism will fail. There are always such cases in every regex-based syntax highlighter. However, Prism dares to be open and honest about them. If a failure is listed here, it doesn’t mean it will never be fixed. This is more of a “known bugs” list, just with a certain type of bug. -

- -

Comment-like substrings

-
"foo /* bar */ baz"; "foo // bar";
\ No newline at end of file +

\ No newline at end of file From 215ddc23f951ec0ebb5cf8a386517592b0939552 Mon Sep 17 00:00:00 2001 From: wayward710 Date: Thu, 7 Apr 2016 01:12:38 -0500 Subject: [PATCH 5/8] Fixed issues pointed out in previous pull request --- components/prism-bro.js | 115 +++++++++++----------------------------- examples.js | 2 +- examples/prism-bro.html | 5 ++ 3 files changed, 36 insertions(+), 86 deletions(-) diff --git a/components/prism-bro.js b/components/prism-bro.js index 1f8d841048..d76ea1dc9f 100644 --- a/components/prism-bro.js +++ b/components/prism-bro.js @@ -1,97 +1,42 @@ Prism.languages.bro = { - 'comment': [ - { - pattern: /(^|[^\\$])#.*/, - lookbehind: true - } - ], - 'string': /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, + 'comment': { + pattern: /(^|[^\\$])#.*/, + lookbehind: true + }, + + 'string': /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, - 'boolean': /\b(T|F)\b/, + 'boolean': /\b(T|F)\b/, - 'keyword': [ - /\b(break|next|continue)\b/, - /\b(alarm|using|of|add|delete)\b/, - /\b(export)\b/, - /\b(print|return|schedule)\b/, - /\b(when|timeout)\b/, - /\b(addr|any|bool|count)\b/, - /\b(double|enum)\b/, - /\b(file|int|interval)\b/, - /\b(pattern|opaque)\b/, - /\b(port|record|set)\b/, - /\b(string|subnet|table)\b/, - /\b(time|vector)\b/, - /\b(for|if|else)\b/, - ], - + 'keyword': + /\b(break|next|continue|alarm|using|of|add|delete|export|print|return|schedule|when|timeout|addr|any|bool|count|double|enum|file|int|interval|pattern|opaque|port|record|set|string|subnet|table|time|vector|for|if|else|in|module)\b/, + 'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/, - - 'function': [ - { - pattern: /function [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i, - inside: { - keyword: /function/ - } - }, - - { - pattern: /hook [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i, - inside: { - keyword: /hook/ - } + + 'function': { + pattern: /(?:function|hook|event) [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/, + inside: { + keyword: /^(?:function|hook|event)/ + } }, - - { - pattern: /event [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i, - inside: { - keyword: /event/ - } - } - ], - - 'variable': - [{ - pattern: /global [a-zA-Z0-9_]+/i, - inside: { - keyword: /global/ - } + + 'variable': { + pattern: /(?:global|local) [a-zA-Z0-9_]+/i, + inside: { + keyword: /(?:global|local)/ + } + }, - { - pattern: /local [a-zA-Z0-9_]+/i, - inside: { - keyword: /local/ - } - }], - - - 'number': [ - /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i, - - ], - - 'italic': /\b(TODO|FIXME|XXX)\b/, + + 'number': /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i, + + 'italic': /\b(TODO|FIXME|XXX)\b/, 'punctuation': /[{}[\];(),.:]/, - + 'builtin': - [ - /@load\s+/, - /@load-sigs\s+/, - /@load-plugin\s+/, - /@unload\s+/, - /@prefixes\s+/, - /@if\s+/, - /@ifdef\s+/, - /@ifndef\s+/, - /@else\s+/, - /@endif\s+/, - /@DIR\s+/, - /@FILENAME\s+/, - {pattern: /&(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column)/, - } - ], - + /(@(load(-(sigs|plugin))?|unload|prefixes|ifn?def|else|(end)?if|DIR|FILENAME))|(&?(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column))/, + 'constant': { pattern: /const [a-zA-Z0-9_]+/i, diff --git a/examples.js b/examples.js index 02897d34ea..a686fa787f 100644 --- a/examples.js +++ b/examples.js @@ -85,7 +85,7 @@ function fileExists(filepath) { return true; } } - return true; + return false; }); } diff --git a/examples/prism-bro.html b/examples/prism-bro.html index c8a7f18026..cddf567e99 100644 --- a/examples/prism-bro.html +++ b/examples/prism-bro.html @@ -16,6 +16,11 @@

Numbers

-123.456 +

Misc

+

+@ifndef ourexp
+
+

Full example


 ##! Scan detector ported from Bro 1.x.

From b7de515f301327905327b55976034b63bdc47d6a Mon Sep 17 00:00:00 2001
From: wayward710 
Date: Thu, 7 Apr 2016 01:18:46 -0500
Subject: [PATCH 6/8] Corrected indentation issue

---
 components/prism-bro.js | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/components/prism-bro.js b/components/prism-bro.js
index d76ea1dc9f..d616083098 100644
--- a/components/prism-bro.js
+++ b/components/prism-bro.js
@@ -22,11 +22,10 @@ Prism.languages.bro = {
 	},
 
 	'variable':	{
-				pattern: /(?:global|local) [a-zA-Z0-9_]+/i,
-				inside: {
-					keyword: /(?:global|local)/
-				}
-
+		pattern: /(?:global|local) [a-zA-Z0-9_]+/i,
+		inside: {
+			keyword: /(?:global|local)/
+		}
 	},
 
 	'number': /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,
@@ -37,8 +36,7 @@ Prism.languages.bro = {
 	'builtin': 
 	    /(@(load(-(sigs|plugin))?|unload|prefixes|ifn?def|else|(end)?if|DIR|FILENAME))|(&?(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column))/,           
 
-	'constant': 
-	{
+	'constant': {
 		pattern: /const [a-zA-Z0-9_]+/i,
 		inside: {
 			keyword: /const/

From 4d7fee8783fb35823ff7478dcfffce16908ac59c Mon Sep 17 00:00:00 2001
From: wayward710 
Date: Thu, 7 Apr 2016 01:20:30 -0500
Subject: [PATCH 7/8] Updated minified JS file

---
 components/prism-bro.min.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/components/prism-bro.min.js b/components/prism-bro.min.js
index 779efb6e94..5770f8ff96 100644
--- a/components/prism-bro.min.js
+++ b/components/prism-bro.min.js
@@ -1 +1 @@
-Prism.languages.bro={"comment":[{pattern:/(^|[^\\$])#.*/,lookbehind:true}],"string":/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"boolean":/\b(T|F)\b/,"keyword":[/\b(break|next|continue)\b/,/\b(alarm|using|of|add|delete)\b/,/\b(export)\b/,/\b(print|return|schedule)\b/,/\b(when|timeout)\b/,/\b(addr|any|bool|count)\b/,/\b(double|enum)\b/,/\b(file|int|interval)\b/,/\b(pattern|opaque)\b/,/\b(port|record|set)\b/,/\b(string|subnet|table)\b/,/\b(time|vector)\b/,/\b(for|if|else)\b/,],"operator":/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/,"function":[{pattern:/function [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i,inside:{keyword:/function/}},{pattern:/hook [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i,inside:{keyword:/hook/}},{pattern:/event [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/i,inside:{keyword:/event/}}],"variable":[{pattern:/global [a-zA-Z0-9_]+/i,inside:{keyword:/global/}},{pattern:/local [a-zA-Z0-9_]+/i,inside:{keyword:/local/}}],"number":[/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,],"italic":/\b(TODO|FIXME|XXX)\b/,"punctuation":/[{}[\];(),.:]/,"builtin":[/@load\s+/,/@load-sigs\s+/,/@load-plugin\s+/,/@unload\s+/,/@prefixes\s+/,/@if\s+/,/@ifdef\s+/,/@ifndef\s+/,/@else\s+/,/@endif\s+/,/@DIR\s+/,/@FILENAME\s+/,{pattern:/&(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column)/,}],"constant":{pattern:/const [a-zA-Z0-9_]+/i,inside:{keyword:/const/}},};
\ No newline at end of file
+Prism.languages.bro={"comment":{pattern:/(^|[^\\$])#.*/,lookbehind:true},"string":/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"boolean":/\b(T|F)\b/,"keyword":/\b(break|next|continue|alarm|using|of|add|delete|export|print|return|schedule|when|timeout|addr|any|bool|count|double|enum|file|int|interval|pattern|opaque|port|record|set|string|subnet|table|time|vector|for|if|else|in|module)\b/,"operator":/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/,"function":{pattern:/(?:function|hook|event) [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/,inside:{keyword:/^(?:function|hook|event)/}},"variable":{pattern:/(?:global|local) [a-zA-Z0-9_]+/i,inside:{keyword:/(?:global|local)/}},"number":/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,"italic":/\b(TODO|FIXME|XXX)\b/,"punctuation":/[{}[\];(),.:]/,"builtin":/(@(load(-(sigs|plugin))?|unload|prefixes|ifn?def|else|(end)?if|DIR|FILENAME))|(&?(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column))/,"constant":{pattern:/const [a-zA-Z0-9_]+/i,inside:{keyword:/const/}},};
\ No newline at end of file

From f6938b9a2547f09c8b5a9bc6844756050bf9d1f8 Mon Sep 17 00:00:00 2001
From: wayward710 
Date: Thu, 7 Apr 2016 23:50:03 -0500
Subject: [PATCH 8/8] Fixed whitespaces, reordered tokens, used Gulp to min JS

---
 components/prism-bro.js     | 36 +++++++++++++++++++-----------------
 components/prism-bro.min.js |  2 +-
 examples/prism-bro.html     |  1 +
 3 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/components/prism-bro.js b/components/prism-bro.js
index d616083098..4591d92cc2 100644
--- a/components/prism-bro.js
+++ b/components/prism-bro.js
@@ -2,23 +2,21 @@ Prism.languages.bro = {
 
 	'comment': {
 		pattern: /(^|[^\\$])#.*/,
-		lookbehind: true
+		lookbehind: true,
+			inside: {
+				'italic':  /\b(TODO|FIXME|XXX)\b/
+		}
 	},
 
 	'string': /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
 
 	'boolean': /\b(T|F)\b/,
 
-	'keyword': 
-		/\b(break|next|continue|alarm|using|of|add|delete|export|print|return|schedule|when|timeout|addr|any|bool|count|double|enum|file|int|interval|pattern|opaque|port|record|set|string|subnet|table|time|vector|for|if|else|in|module)\b/,                     
-	            
-	'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/,
-
 	'function': {
-	    pattern: /(?:function|hook|event) [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/,
-	    inside: {
-	        keyword: /^(?:function|hook|event)/
-	    }
+		pattern: /(?:function|hook|event) [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/,
+		inside: {
+			keyword: /^(?:function|hook|event)/
+		}
 	},
 
 	'variable':	{
@@ -28,13 +26,8 @@ Prism.languages.bro = {
 		}
 	},
 
-	'number': /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,
-
-	'italic':  /\b(TODO|FIXME|XXX)\b/,
-	'punctuation': /[{}[\];(),.:]/,
-
-	'builtin': 
-	    /(@(load(-(sigs|plugin))?|unload|prefixes|ifn?def|else|(end)?if|DIR|FILENAME))|(&?(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column))/,           
+	'builtin':
+		/(@(load(-(sigs|plugin))?|unload|prefixes|ifn?def|else|(end)?if|DIR|FILENAME))|(&?(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column))/,
 
 	'constant': {
 		pattern: /const [a-zA-Z0-9_]+/i,
@@ -42,4 +35,13 @@ Prism.languages.bro = {
 			keyword: /const/
 		}
 	},
+
+	'keyword': 
+		/\b(break|next|continue|alarm|using|of|add|delete|export|print|return|schedule|when|timeout|addr|any|bool|count|double|enum|file|int|interval|pattern|opaque|port|record|set|string|subnet|table|time|vector|for|if|else|in|module|function)\b/,
+
+	'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/,
+
+	'number': /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,
+
+	'punctuation': /[{}[\];(),.:]/
 };
diff --git a/components/prism-bro.min.js b/components/prism-bro.min.js
index 5770f8ff96..bc8a64981e 100644
--- a/components/prism-bro.min.js
+++ b/components/prism-bro.min.js
@@ -1 +1 @@
-Prism.languages.bro={"comment":{pattern:/(^|[^\\$])#.*/,lookbehind:true},"string":/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"boolean":/\b(T|F)\b/,"keyword":/\b(break|next|continue|alarm|using|of|add|delete|export|print|return|schedule|when|timeout|addr|any|bool|count|double|enum|file|int|interval|pattern|opaque|port|record|set|string|subnet|table|time|vector|for|if|else|in|module)\b/,"operator":/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/,"function":{pattern:/(?:function|hook|event) [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/,inside:{keyword:/^(?:function|hook|event)/}},"variable":{pattern:/(?:global|local) [a-zA-Z0-9_]+/i,inside:{keyword:/(?:global|local)/}},"number":/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,"italic":/\b(TODO|FIXME|XXX)\b/,"punctuation":/[{}[\];(),.:]/,"builtin":/(@(load(-(sigs|plugin))?|unload|prefixes|ifn?def|else|(end)?if|DIR|FILENAME))|(&?(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column))/,"constant":{pattern:/const [a-zA-Z0-9_]+/i,inside:{keyword:/const/}},};
\ No newline at end of file
+Prism.languages.bro={comment:{pattern:/(^|[^\\$])#.*/,lookbehind:!0,inside:{italic:/\b(TODO|FIXME|XXX)\b/}},string:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"boolean":/\b(T|F)\b/,"function":{pattern:/(?:function|hook|event) [a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)?/,inside:{keyword:/^(?:function|hook|event)/}},variable:{pattern:/(?:global|local) [a-zA-Z0-9_]+/i,inside:{keyword:/(?:global|local)/}},builtin:/(@(load(-(sigs|plugin))?|unload|prefixes|ifn?def|else|(end)?if|DIR|FILENAME))|(&?(redef|priority|log|optional|default|add_func|delete_func|expire_func|read_expire|write_expire|create_expire|synchronized|persistent|rotate_interval|rotate_size|encrypt|raw_output|mergeable|group|error_handler|type_column))/,constant:{pattern:/const [a-zA-Z0-9_]+/i,inside:{keyword:/const/}},keyword:/\b(break|next|continue|alarm|using|of|add|delete|export|print|return|schedule|when|timeout|addr|any|bool|count|double|enum|file|int|interval|pattern|opaque|port|record|set|string|subnet|table|time|vector|for|if|else|in|module|function)\b/,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&|\|\|?|\?|\*|\/|~|\^|%/,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,punctuation:/[{}[\];(),.:]/};
\ No newline at end of file
diff --git a/examples/prism-bro.html b/examples/prism-bro.html
index cddf567e99..73f0ab75d4 100644
--- a/examples/prism-bro.html
+++ b/examples/prism-bro.html
@@ -19,6 +19,7 @@ 

Numbers

Misc


 @ifndef ourexp
+@load-sigs somesigs
 

Full example