diff --git a/osect_sensor/Infrastructure/edge_cron/Dockerfile b/osect_sensor/Infrastructure/edge_cron/Dockerfile index bfabad0..a3dec6a 100755 --- a/osect_sensor/Infrastructure/edge_cron/Dockerfile +++ b/osect_sensor/Infrastructure/edge_cron/Dockerfile @@ -213,10 +213,11 @@ RUN mkdir /opt/ot_tools \ && cp -p ot_tools/broscript/ns.zeek /opt/zeek/share/zeek/site/ \ && cp -p ot_tools/broscript/main_bacnet.zeek /opt/zeek/share/zeek/site/ \ && cp -p ot_tools/broscript/consts_bacnet.zeek /opt/zeek/share/zeek/site/ \ + && cp -p ot_tools/broscript/dns.zeek /opt/zeek/share/zeek/base/protocols/dns/main.zeek \ && cp -p ot_tools/*.sh /opt/ot_tools/ \ && cp -p ot_tools/tsharkfields2bacnetservicelog_dict.awk /opt/ot_tools/ \ && cp -p ot_tools/yaf.awk /opt/ot_tools/ \ - && cp -pr ot_tools/p0f /opt/ + && cp -pr ot_tools/p0f /opt/ # 環境変数 RUN printenv | grep -e https_proxy -e HTTPS_PROXY -e http_proxy -e HTTP_PROXY -e no_proxy -e NO_PROXY| awk '{print "export " $1}' > /opt/ot_tools/proxy_env.txt \ diff --git a/osect_sensor/Infrastructure/edge_cron/work/ot_tools/broscript/arp.zeek b/osect_sensor/Infrastructure/edge_cron/work/ot_tools/broscript/arp.zeek index 6139634..67607c5 100755 --- a/osect_sensor/Infrastructure/edge_cron/work/ot_tools/broscript/arp.zeek +++ b/osect_sensor/Infrastructure/edge_cron/work/ot_tools/broscript/arp.zeek @@ -6,7 +6,7 @@ export { redef enum Log::ID += { LOG }; type Info: record { - ts: time &optional &log; + ts: time &log &optional; orig_mac: string &log &optional; orig_ip: addr &log &optional; resp_mac: string &log &optional; diff --git a/osect_sensor/Infrastructure/edge_cron/work/ot_tools/broscript/dns.zeek b/osect_sensor/Infrastructure/edge_cron/work/ot_tools/broscript/dns.zeek new file mode 100755 index 0000000..01179e5 --- /dev/null +++ b/osect_sensor/Infrastructure/edge_cron/work/ot_tools/broscript/dns.zeek @@ -0,0 +1,915 @@ +##! Base DNS analysis script which tracks and logs DNS queries along with +##! their responses. + +@load base/utils/queue +@load ./consts +@load base/protocols/conn/removal-hooks + +module DNS; + +export { + ## The DNS logging stream identifier. + redef enum Log::ID += { LOG }; + + ## A default logging policy hook for the stream. + global log_policy: Log::PolicyHook; + + ## The record type which contains the column fields of the DNS log. + type Info: record { + ## The earliest time at which a DNS protocol message over the + ## associated connection is observed. + ts: time &log &optional; + ## A unique identifier of the connection over which DNS messages + ## are being transferred. + uid: string &log &optional; + ## The connection's 4-tuple of endpoint addresses/ports. + id: conn_id &log &optional; + ## The transport layer protocol of the connection. + proto: transport_proto &log &optional; + ## A 16-bit identifier assigned by the program that generated + ## the DNS query. Also used in responses to match up replies to + ## outstanding queries. + trans_id: count &log &optional; + ## Round trip time for the query and response. This indicates + ## the delay between when the request was seen until the + ## answer started. + rtt: interval &log &optional; + ## The domain name that is the subject of the DNS query. + query: string &log &optional; + ## The QCLASS value specifying the class of the query. + qclass: count &log &optional; + ## A descriptive name for the class of the query. + qclass_name: string &log &optional; + ## A QTYPE value specifying the type of the query. + qtype: count &log &optional; + ## A descriptive name for the type of the query. + qtype_name: string &log &optional; + ## The response code value in DNS response messages. + rcode: count &log &optional; + ## A descriptive name for the response code value. + rcode_name: string &log &optional; + ## The Authoritative Answer bit for response messages specifies + ## that the responding name server is an authority for the + ## domain name in the question section. + AA: bool &log &default=F; + ## The Truncation bit specifies that the message was truncated. + TC: bool &log &default=F; + ## The Recursion Desired bit in a request message indicates that + ## the client wants recursive service for this query. + RD: bool &log &default=F; + ## The Recursion Available bit in a response message indicates + ## that the name server supports recursive queries. + RA: bool &log &default=F; + ## A reserved field that is usually zero in + ## queries and responses. + Z: count &log &default=0; + ## The set of resource descriptions in the query answer. + answers: vector of string &log &optional; + ## The caching intervals of the associated RRs described by the + ## *answers* field. + TTLs: vector of interval &log &optional; + ## The DNS query was rejected by the server. + rejected: bool &log &default=F; + pkts: int &log &optional; + + ## The total number of resource records in a reply message's + ## answer section. + total_answers: count &optional; + ## The total number of resource records in a reply message's + ## answer, authority, and additional sections. + total_replies: count &optional; + + ## Whether the full DNS query has been seen. + saw_query: bool &default=F; + ## Whether the full DNS reply has been seen. + saw_reply: bool &default=F; + }; + + ## An event that can be handled to access the :zeek:type:`DNS::Info` + ## record as it is sent to the logging framework. + global log_dns: event(rec: Info); + + ## This is called by the specific dns_*_reply events with a "reply" + ## which may not represent the full data available from the resource + ## record, but it's generally considered a summarization of the + ## responses. + ## + ## c: The connection record for which to fill in DNS reply data. + ## + ## msg: The DNS message header information for the response. + ## + ## ans: The general information of a RR response. + ## + ## reply: The specific response information according to RR type/class. + global do_reply: hook(c: connection, msg: dns_msg, ans: dns_answer, reply: string); + + ## A hook that is called whenever a session is being set. + ## This can be used if additional initialization logic needs to happen + ## when creating a new session value. + ## + ## c: The connection involved in the new session. + ## + ## msg: The DNS message header information. + ## + ## is_query: Indicator for if this is being called for a query or a response. + global set_session: hook(c: connection, msg: dns_msg, is_query: bool); + + ## Yields a queue of :zeek:see:`DNS::Info` objects for a given + ## DNS message query/transaction ID. + type PendingMessages: table[count] of Queue::Queue; + + ## Give up trying to match pending DNS queries or replies for a given + ## query/transaction ID once this number of unmatched queries or replies + ## is reached (this shouldn't happen unless either the DNS server/resolver + ## is broken, Zeek is not seeing all the DNS traffic, or an AXFR query + ## response is ongoing). + option max_pending_msgs = 50; + + ## Give up trying to match pending DNS queries or replies across all + ## query/transaction IDs once there is at least one unmatched query or + ## reply across this number of different query IDs. + option max_pending_query_ids = 50; + + ## A record type which tracks the status of DNS queries for a given + ## :zeek:type:`connection`. + type State: record { + ## A single query that hasn't been matched with a response yet. + ## Note this is maintained separate from the *pending_queries* + ## field solely for performance reasons -- it's possible that + ## *pending_queries* contains further queries for which a response + ## has not yet been seen, even for the same transaction ID. + pending_query: Info &optional; + + ## Indexed by query id, returns Info record corresponding to + ## queries that haven't been matched with a response yet. + pending_queries: PendingMessages &optional; + + ## Indexed by query id, returns Info record corresponding to + ## replies that haven't been matched with a query yet. + pending_replies: PendingMessages &optional; + }; + + ## DNS finalization hook. Remaining DNS info may get logged when it's called. + global finalize_dns: Conn::RemovalHook; + + ## log aggregation by zheng + type AggregationData: record { + uid: string &log &optional; + id: conn_id &log &optional; + proto: transport_proto &log &optional; + trans_id: count &log &optional; + rtt: interval &log &optional; + query: string &log &optional; + qclass: count &log &optional; + qclass_name: string &log &optional; + qtype: count &log &optional; + qtype_name: string &log &optional; + rcode: count &log &optional; + rcode_name: string &log &optional; + AA: bool &log &default=F; + TC: bool &log &default=F; + RD: bool &log &default=F; + RA: bool &log &default=F; + Z: count &log &default=0; + answers: vector of string &log &optional; + TTLs: vector of interval &log &optional; + rejected: bool &log &default=F; + }; + + type Ts_num: record { + ts_s: time &log; + num: int &log; + ts_e: time &log &optional; + }; + + function insert_log(res_aggregationData: table[AggregationData] of Ts_num, idx: AggregationData): interval + { + local info_insert: Info = []; + info_insert$ts = res_aggregationData[idx]$ts_s; + if ( idx?$uid ){ + info_insert$uid = idx$uid; + } + if ( idx?$id ){ + info_insert$id = idx$id; + } + if ( idx?$proto ){ + info_insert$proto = idx$proto; + } + if ( idx?$trans_id ){ + info_insert$trans_id = idx$trans_id; + } + if ( idx?$rtt ){ + info_insert$rtt = idx$rtt; + } + if ( idx?$query ){ + info_insert$query = idx$query; + } + if ( idx?$qclass ){ + info_insert$qclass = idx$qclass; + } + if ( idx?$qclass_name ){ + info_insert$qclass_name = idx$qclass_name; + } + if ( idx?$qtype ){ + info_insert$qtype = idx$qtype; + } + if ( idx?$qtype_name ){ + info_insert$qtype_name = idx$qtype_name; + } + if ( idx?$rcode ){ + info_insert$rcode = idx$rcode; + } + if ( idx?$rcode_name ){ + info_insert$rcode_name = idx$rcode_name; + } + if ( idx?$AA ){ + info_insert$AA = idx$AA; + } + if ( idx?$TC ){ + info_insert$TC = idx$TC; + } + if ( idx?$RD ){ + info_insert$RD = idx$RD; + } + if ( idx?$RA ){ + info_insert$RA = idx$RA; + } + if ( idx?$Z ){ + info_insert$Z = idx$Z; + } + if ( idx?$answers ){ + info_insert$answers = idx$answers; + } + if ( idx?$TTLs ){ + info_insert$TTLs = idx$TTLs; + } + if ( idx?$rejected ){ + info_insert$rejected = idx$rejected; + } + # if ( res_aggregationData[idx]?$ts_e ){ + # info_insert$ts_end = res_aggregationData[idx]$ts_e; + # } + if ( res_aggregationData[idx]?$num ){ + info_insert$pkts = res_aggregationData[idx]$num; + } + # print res_aggregationData; + # print info; + Log::write(DNS::LOG, info_insert); + # res_aggregationData = {}; + return 0secs; + } + + global res_aggregationData: table[AggregationData] of Ts_num &create_expire=60sec &expire_func=insert_log; +} + +function create_aggregationData(info: Info): AggregationData + { + local aggregationData: AggregationData; + + if ( info?$uid ){ + aggregationData$uid = info$uid; + } + if ( info?$id ){ + aggregationData$id = info$id; + } + if ( info?$proto ){ + aggregationData$proto = info$proto; + } + if ( info?$trans_id ){ + aggregationData$trans_id = info$trans_id; + } + if ( info?$rtt ){ + aggregationData$rtt = info$rtt; + } + if ( info?$query ){ + aggregationData$query = info$query; + } + if ( info?$qclass ){ + aggregationData$qclass = info$qclass; + } + if ( info?$qclass_name ){ + aggregationData$qclass_name = info$qclass_name; + } + if ( info?$qtype ){ + aggregationData$qtype = info$qtype; + } + if ( info?$qtype_name ){ + aggregationData$qtype_name = info$qtype_name; + } + if ( info?$rcode ){ + aggregationData$rcode = info$rcode; + } + if ( info?$rcode_name ){ + aggregationData$rcode_name = info$rcode_name; + } + if ( info?$AA ){ + aggregationData$AA = info$AA; + } + if ( info?$TC ){ + aggregationData$TC = info$TC; + } + if ( info?$RD ){ + aggregationData$RD = info$RD; + } + if ( info?$RA ){ + aggregationData$RA = info$RA; + } + if ( info?$Z ){ + aggregationData$Z = info$Z; + } + if ( info?$answers ){ + aggregationData$answers = info$answers; + } + if ( info?$TTLs ){ + aggregationData$TTLs = info$TTLs; + } + if ( info?$rejected ){ + aggregationData$rejected = info$rejected; + } + + return aggregationData; + } + +function insert_res_aggregationData(aggregationData: AggregationData, info: Info): string + { + if (aggregationData in res_aggregationData){ + res_aggregationData[aggregationData]$num = res_aggregationData[aggregationData]$num + 1; + res_aggregationData[aggregationData]$ts_e = info$ts; + } else { + res_aggregationData[aggregationData] = [$ts_s = info$ts, $num = 1, $ts_e = info$ts]; + } + + return "done"; + } + + +redef record connection += { + dns: Info &optional; + dns_state: State &optional; +}; + +const ports = { 53/udp, 53/tcp, 137/udp, 5353/udp, 5355/udp }; +redef likely_server_ports += { ports }; + +event zeek_init() &priority=5 + { + Log::create_stream(DNS::LOG, [$columns=Info, $ev=log_dns, $path="dns", $policy=log_policy]); + Analyzer::register_for_ports(Analyzer::ANALYZER_DNS, ports); + } + +function new_session(c: connection, trans_id: count): Info + { + local info: Info; + info$ts = network_time(); + info$id = c$id; + info$uid = c$uid; + info$proto = get_port_transport_proto(c$id$resp_p); + info$trans_id = trans_id; + return info; + } + +function log_unmatched_msgs_queue(q: Queue::Queue) + { + local infos: vector of Info; + local aggregationData: AggregationData; + Queue::get_vector(q, infos); + + for ( i in infos ) + { + # Log::write(DNS::LOG, infos[i]); + aggregationData = create_aggregationData(infos[i]); + insert_res_aggregationData(aggregationData, infos[i]); + } + } + +function log_unmatched_msgs(msgs: PendingMessages) + { + for ( trans_id, q in msgs ) + { + log_unmatched_msgs_queue(q); + } + + clear_table(msgs); + } + +function enqueue_new_msg(msgs: PendingMessages, id: count, msg: Info) + { + if ( id !in msgs ) + { + if ( |msgs| > max_pending_query_ids ) + { + # Throw away all unmatched on assumption they'll never be matched. + log_unmatched_msgs(msgs); + } + + msgs[id] = Queue::init(); + } + else + { + if ( Queue::len(msgs[id]) > max_pending_msgs ) + { + log_unmatched_msgs_queue(msgs[id]); + # Throw away all unmatched on assumption they'll never be matched. + msgs[id] = Queue::init(); + } + } + + Queue::put(msgs[id], msg); + } + +function pop_msg(msgs: PendingMessages, id: count): Info + { + local rval: Info = Queue::get(msgs[id]); + + if ( Queue::len(msgs[id]) == 0 ) + delete msgs[id]; + + return rval; + } + +hook set_session(c: connection, msg: dns_msg, is_query: bool) &priority=5 + { + if ( ! c?$dns_state ) + { + local state: State; + c$dns_state = state; + Conn::register_removal_hook(c, finalize_dns); + } + + if ( is_query ) + { + if ( c$dns_state?$pending_replies && msg$id in c$dns_state$pending_replies && + Queue::len(c$dns_state$pending_replies[msg$id]) > 0 ) + { + # Match this DNS query w/ what's at head of pending reply queue. + c$dns = pop_msg(c$dns_state$pending_replies, msg$id); + } + else + { + # Create a new DNS session and put it in the query queue so + # we can wait for a matching reply. + c$dns = new_session(c, msg$id); + + if( ! c$dns_state?$pending_query ) + c$dns_state$pending_query = c$dns; + else + { + if( !c$dns_state?$pending_queries ) + c$dns_state$pending_queries = table(); + + enqueue_new_msg(c$dns_state$pending_queries, msg$id, c$dns); + } + } + } + else + { + if ( c$dns_state?$pending_query && c$dns_state$pending_query$trans_id == msg$id ) + { + c$dns = c$dns_state$pending_query; + delete c$dns_state$pending_query; + + if ( c$dns_state?$pending_queries ) + { + # Popping off an arbitrary, unpaired query to set as the + # new fastpath is necessary in order to preserve the overall + # queuing order of any pending queries that may share a + # transaction ID. If we didn't fill c$dns_state$pending_query + # back in, then it's possible a new query would jump ahead in + # the queue of some other pending query since + # c$dns_state$pending_query is filled first if available. + + if ( msg$id in c$dns_state$pending_queries && + Queue::len(c$dns_state$pending_queries[msg$id]) > 0 ) + # Prioritize any pending query with matching ID to the one + # that just got paired with a response. + c$dns_state$pending_query = pop_msg(c$dns_state$pending_queries, msg$id); + else + { + # Just pick an arbitrary, unpaired query. + local tid: count &is_assigned; + local found_one = F; + + for ( trans_id, q in c$dns_state$pending_queries ) + if ( Queue::len(q) > 0 ) + { + tid = trans_id; + found_one = T; + break; + } + + if ( found_one ) + c$dns_state$pending_query = pop_msg(c$dns_state$pending_queries, tid); + } + } + } + else if ( c$dns_state?$pending_queries && msg$id in c$dns_state$pending_queries && + Queue::len(c$dns_state$pending_queries[msg$id]) > 0 ) + { + # Match this DNS reply w/ what's at head of pending query queue. + c$dns = pop_msg(c$dns_state$pending_queries, msg$id); + } + else + { + # Create a new DNS session and put it in the reply queue so + # we can wait for a matching query. + c$dns = new_session(c, msg$id); + + if( ! c$dns_state?$pending_replies ) + c$dns_state$pending_replies = table(); + + enqueue_new_msg(c$dns_state$pending_replies, msg$id, c$dns); + } + } + + if ( ! is_query ) + { + c$dns$rcode = msg$rcode; + c$dns$rcode_name = base_errors[msg$rcode]; + + if ( ! c$dns?$total_answers ) + c$dns$total_answers = msg$num_answers; + + if ( ! c$dns?$total_replies ) + c$dns$total_replies = msg$num_answers + msg$num_addl + msg$num_auth; + + if ( msg$rcode != 0 && msg$num_queries == 0 ) + c$dns$rejected = T; + } + } + +event dns_message(c: connection, is_orig: bool, msg: dns_msg, len: count) &priority=5 + { + if ( msg$opcode != 0 ) + # Currently only standard queries are tracked. + return; + + hook set_session(c, msg, ! msg$QR); + } + +hook DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &priority=5 + { + if ( msg$opcode != 0 ) + # Currently only standard queries are tracked. + return; + + if ( ! msg$QR ) + # This is weird: the inquirer must also be providing answers in + # the request, which is not what we want to track. + return; + + if ( ans$answer_type == DNS_ANS ) + { + if ( ! c$dns?$query ) + c$dns$query = ans$query; + + c$dns$AA = msg$AA; + c$dns$RA = msg$RA; + + if ( ! c$dns?$rtt ) + { + c$dns$rtt = network_time() - c$dns$ts; + # This could mean that only a reply was seen since + # we assume there must be some passage of time between + # request and response. + if ( c$dns$rtt == 0secs ) + delete c$dns$rtt; + } + + if ( reply != "" ) + { + if ( ! c$dns?$answers ) + c$dns$answers = vector(); + c$dns$answers += reply; + + if ( ! c$dns?$TTLs ) + c$dns$TTLs = vector(); + c$dns$TTLs += ans$TTL; + } + } + } + +event dns_end(c: connection, msg: dns_msg) &priority=5 + { + if ( ! c?$dns ) + return; + + if ( msg$QR ) + c$dns$saw_reply = T; + else + c$dns$saw_query = T; + } + +event dns_end(c: connection, msg: dns_msg) &priority=-5 + { + local aggregationData: AggregationData; + if ( c?$dns && c$dns$saw_reply && c$dns$saw_query ) + { + # Log::write(DNS::LOG, c$dns); + aggregationData = create_aggregationData(c$dns); + insert_res_aggregationData(aggregationData, c$dns); + delete c$dns; + } + } + +event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count) &priority=5 + { + if ( msg$opcode != 0 ) + # Currently only standard queries are tracked. + return; + + c$dns$RD = msg$RD; + c$dns$TC = msg$TC; + c$dns$qclass = qclass; + c$dns$qclass_name = classes[qclass]; + c$dns$qtype = qtype; + c$dns$qtype_name = query_types[qtype]; + c$dns$Z = msg$Z; + + # Decode netbios name queries + # Note: I'm ignoring the name type for now. Not sure if this should be + # worked into the query/response in some fashion. + if ( c$id$resp_p == 137/udp ) + { + local decoded_query = decode_netbios_name(query); + + if ( |decoded_query| != 0 ) + query = decoded_query; + + if ( c$dns$qtype_name == "SRV" ) + { + # The SRV RFC used the ID used for NetBios Status RRs. + # So if this is NetBios Name Service we name it correctly. + c$dns$qtype_name = "NBSTAT"; + } + } + c$dns$query = query; + } + + +event dns_unknown_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5 + { + hook DNS::do_reply(c, msg, ans, fmt("", ans$qtype)); + } + +event dns_A_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5 + { + hook DNS::do_reply(c, msg, ans, fmt("%s", a)); + } + +event dns_TXT_reply(c: connection, msg: dns_msg, ans: dns_answer, strs: string_vec) &priority=5 + { + local txt_strings: string = ""; + + for ( i in strs ) + { + if ( i > 0 ) + txt_strings += " "; + + txt_strings += fmt("TXT %d %s", |strs[i]|, strs[i]); + } + + hook DNS::do_reply(c, msg, ans, txt_strings); + } + +event dns_SPF_reply(c: connection, msg: dns_msg, ans: dns_answer, strs: string_vec) &priority=5 + { + local spf_strings: string = ""; + + for ( i in strs ) + { + if ( i > 0 ) + spf_strings += " "; + + spf_strings += fmt("SPF %d %s", |strs[i]|, strs[i]); + } + + hook DNS::do_reply(c, msg, ans, spf_strings); + } + +event dns_AAAA_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5 + { + hook DNS::do_reply(c, msg, ans, fmt("%s", a)); + } + +event dns_A6_reply(c: connection, msg: dns_msg, ans: dns_answer, a: addr) &priority=5 + { + hook DNS::do_reply(c, msg, ans, fmt("%s", a)); + } + +event dns_NS_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string) &priority=5 + { + hook DNS::do_reply(c, msg, ans, name); + } + +event dns_CNAME_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string) &priority=5 + { + hook DNS::do_reply(c, msg, ans, name); + } + +event dns_MX_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string, + preference: count) &priority=5 + { + hook DNS::do_reply(c, msg, ans, name); + } + +event dns_PTR_reply(c: connection, msg: dns_msg, ans: dns_answer, name: string) &priority=5 + { + hook DNS::do_reply(c, msg, ans, name); + } + +event dns_SOA_reply(c: connection, msg: dns_msg, ans: dns_answer, soa: dns_soa) &priority=5 + { + hook DNS::do_reply(c, msg, ans, soa$mname); + } + +event dns_WKS_reply(c: connection, msg: dns_msg, ans: dns_answer) &priority=5 + { + hook DNS::do_reply(c, msg, ans, ""); + } + +event dns_SRV_reply(c: connection, msg: dns_msg, ans: dns_answer, target: string, priority: count, weight: count, p: count) &priority=5 + { + hook DNS::do_reply(c, msg, ans, target); + } + +# TODO: figure out how to handle these +#event dns_EDNS(c: connection, msg: dns_msg, ans: dns_answer) +# { +# +# } +# +#event dns_EDNS_addl(c: connection, msg: dns_msg, ans: dns_edns_additional) +# { +# +# } +# event dns_EDNS_ecs(c: connection, msg: dns_msg, opt: dns_edns_ecs) +# { +# +# } +# +#event dns_TSIG_addl(c: connection, msg: dns_msg, ans: dns_tsig_additional) +# { +# +# } + +event dns_RRSIG(c: connection, msg: dns_msg, ans: dns_answer, rrsig: dns_rrsig_rr) &priority=5 + { + local s: string; + s = fmt("RRSIG %s %s", rrsig$type_covered, + rrsig$signer_name == "" ? "" : rrsig$signer_name); + hook DNS::do_reply(c, msg, ans, s); + } + +event dns_DNSKEY(c: connection, msg: dns_msg, ans: dns_answer, dnskey: dns_dnskey_rr) &priority=5 + { + local s: string; + s = fmt("DNSKEY %s", dnskey$algorithm); + hook DNS::do_reply(c, msg, ans, s); + } + +event dns_NSEC(c: connection, msg: dns_msg, ans: dns_answer, next_name: string, bitmaps: string_vec) &priority=5 + { + hook DNS::do_reply(c, msg, ans, fmt("NSEC %s %s", ans$query, next_name)); + } + +event dns_NSEC3(c: connection, msg: dns_msg, ans: dns_answer, nsec3: dns_nsec3_rr) &priority=5 + { + hook DNS::do_reply(c, msg, ans, "NSEC3"); + } + +event dns_NSEC3PARAM(c: connection, msg: dns_msg, ans: dns_answer, nsec3param: dns_nsec3param_rr) &priority=5 + { + hook DNS::do_reply(c, msg, ans, "NSEC3PARAM"); + } + +event dns_DS(c: connection, msg: dns_msg, ans: dns_answer, ds: dns_ds_rr) &priority=5 + { + local s: string; + s = fmt("DS %s %s", ds$algorithm, ds$digest_type); + hook DNS::do_reply(c, msg, ans, s); + } + +event dns_BINDS(c: connection, msg: dns_msg, ans: dns_answer, binds: dns_binds_rr) &priority=5 + { + hook DNS::do_reply(c, msg, ans, "BIND9 signing signal"); + } + +event dns_SSHFP(c: connection, msg: dns_msg, ans: dns_answer, algo: count, fptype: count, fingerprint: string) &priority=5 + { + local s: string; + s = fmt("SSHFP: %s", bytestring_to_hexstr(fingerprint)); + hook DNS::do_reply(c, msg, ans, s); + } + +event dns_LOC(c: connection, msg: dns_msg, ans: dns_answer, loc: dns_loc_rr) &priority=5 + { + local s: string; + s = fmt("LOC: %d %d %d", loc$size, loc$horiz_pre, loc$vert_pre); + hook DNS::do_reply(c, msg, ans, s); + } + +event dns_rejected(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count) &priority=5 + { + if ( c?$dns ) + c$dns$rejected = T; + } + +hook finalize_dns(c: connection) + { + local aggregationData: AggregationData; + if ( ! c?$dns_state ) + return; + + # If Zeek is expiring state, we should go ahead and log all unmatched + # queries and replies now. + if( c$dns_state?$pending_query ) + # Log::write(DNS::LOG, c$dns_state$pending_query); + aggregationData = create_aggregationData(c$dns_state$pending_query); + insert_res_aggregationData(aggregationData, c$dns_state$pending_query); + + if( c$dns_state?$pending_queries ) + log_unmatched_msgs(c$dns_state$pending_queries); + + if( c$dns_state?$pending_replies ) + log_unmatched_msgs(c$dns_state$pending_replies); + } + +# # 集約 local debug用 +# event zeek_done() +# { +# print "zeek_done()"; +# print res_aggregationData; +# for ( i in res_aggregationData ){ +# local info: Info = []; +# info$ts = res_aggregationData[i]$ts_s; +# if ( i?$uid ){ +# info$uid = i$uid; +# } +# if ( i?$id ){ +# info$id = i$id; +# } +# if ( i?$proto ){ +# info$proto = i$proto; +# } +# if ( i?$trans_id ){ +# info$trans_id = i$trans_id; +# } +# if ( i?$rtt ){ +# info$rtt = i$rtt; +# } +# if ( i?$query ){ +# info$query = i$query; +# } +# if ( i?$qclass ){ +# info$qclass = i$qclass; +# } +# if ( i?$qclass_name ){ +# info$qclass_name = i$qclass_name; +# } +# if ( i?$qtype ){ +# info$qtype = i$qtype; +# } +# if ( i?$qtype_name ){ +# info$qtype_name = i$qtype_name; +# } +# if ( i?$rcode ){ +# info$rcode = i$rcode; +# } +# if ( i?$rcode_name ){ +# info$rcode_name = i$rcode_name; +# } +# if ( i?$AA ){ +# info$AA = i$AA; +# } +# if ( i?$TC ){ +# info$TC = i$TC; +# } +# if ( i?$RD ){ +# info$RD = i$RD; +# } +# if ( i?$RA ){ +# info$RA = i$RA; +# } +# if ( i?$Z ){ +# info$Z = i$Z; +# } +# if ( i?$answers ){ +# info$answers = i$answers; +# } +# if ( i?$TTLs ){ +# info$TTLs = i$TTLs; +# } +# if ( i?$rejected ){ +# info$rejected = i$rejected; +# } +# # if ( res_aggregationData[i]?$ts_e ){ +# # info$ts_end = res_aggregationData[i]$ts_e; +# # } +# if ( res_aggregationData[i]?$num ){ +# info$pkts = res_aggregationData[i]$num; +# } +# # print res_aggregationData; +# # print info; +# Log::write(DNS::LOG, info); +# } +# }