diff --git a/src/analyzer/protocol/ntp/CMakeLists.txt b/src/analyzer/protocol/ntp/CMakeLists.txt index ae26c7cdcd..14fe87470d 100644 --- a/src/analyzer/protocol/ntp/CMakeLists.txt +++ b/src/analyzer/protocol/ntp/CMakeLists.txt @@ -1,12 +1,10 @@ -# Generated by binpac_quickstart include(BroPlugin) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) bro_plugin_begin(Bro NTP) - bro_plugin_cc(NTP.cc Plugin.cc) - bro_plugin_bif(types.bif) - bro_plugin_bif(events.bif) - bro_plugin_pac(ntp.pac ntp-analyzer.pac ntp-mode7.pac ntp-protocol.pac) +bro_plugin_cc(NTP.cc Plugin.cc) +bro_plugin_bif(types.bif events.bif) +bro_plugin_pac(ntp.pac ntp-analyzer.pac ntp-mode7.pac ntp-protocol.pac) bro_plugin_end() diff --git a/src/analyzer/protocol/ntp/NTP.cc b/src/analyzer/protocol/ntp/NTP.cc index 6918578a02..9a88138206 100644 --- a/src/analyzer/protocol/ntp/NTP.cc +++ b/src/analyzer/protocol/ntp/NTP.cc @@ -1,5 +1,3 @@ -// Generated by binpac_quickstart - #include "NTP.h" #include "Reporter.h" @@ -9,12 +7,9 @@ using namespace analyzer::NTP; NTP_Analyzer::NTP_Analyzer(Connection* c) - -: analyzer::Analyzer("NTP", c) - + : analyzer::Analyzer("NTP", c) { interp = new binpac::NTP::NTP_Conn(this); - } NTP_Analyzer::~NTP_Analyzer() @@ -24,13 +19,11 @@ NTP_Analyzer::~NTP_Analyzer() void NTP_Analyzer::Done() { - Analyzer::Done(); - } void NTP_Analyzer::DeliverPacket(int len, const u_char* data, - bool orig, uint64 seq, const IP_Hdr* ip, int caplen) + bool orig, uint64 seq, const IP_Hdr* ip, int caplen) { Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen); diff --git a/src/analyzer/protocol/ntp/NTP.h b/src/analyzer/protocol/ntp/NTP.h index f7d9912131..c155fb3135 100644 --- a/src/analyzer/protocol/ntp/NTP.h +++ b/src/analyzer/protocol/ntp/NTP.h @@ -1,5 +1,3 @@ -// Generated by binpac_quickstart - #ifndef ANALYZER_PROTOCOL_NTP_NTP_H #define ANALYZER_PROTOCOL_NTP_NTP_H @@ -12,29 +10,23 @@ namespace analyzer { namespace NTP { -class NTP_Analyzer - -: public analyzer::Analyzer { - +class NTP_Analyzer : public analyzer::Analyzer { public: - NTP_Analyzer(Connection* conn); - virtual ~NTP_Analyzer(); + explicit NTP_Analyzer(Connection* conn); + ~NTP_Analyzer() override; // Overriden from Analyzer. - virtual void Done(); - - virtual void DeliverPacket(int len, const u_char* data, bool orig, - uint64 seq, const IP_Hdr* ip, int caplen); - + void Done() override; + void DeliverPacket(int len, const u_char* data, bool orig, + uint64 seq, const IP_Hdr* ip, int caplen) override; - static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn) + static analyzer::Analyzer* Instantiate(Connection* conn) { return new NTP_Analyzer(conn); } protected: binpac::NTP::NTP_Conn* interp; - }; -} } // namespace analyzer::* +} } // namespace analyzer::* #endif diff --git a/src/analyzer/protocol/ntp/Plugin.cc b/src/analyzer/protocol/ntp/Plugin.cc index 2ff9d52d66..6a742b9fcc 100644 --- a/src/analyzer/protocol/ntp/Plugin.cc +++ b/src/analyzer/protocol/ntp/Plugin.cc @@ -1,4 +1,4 @@ -// Generated by binpac_quickstart +// See the file in the main distribution directory for copyright. #include "plugin/Plugin.h" @@ -11,15 +11,14 @@ class Plugin : public plugin::Plugin { public: plugin::Configuration Configure() { - AddComponent(new ::analyzer::Component("NTP", - ::analyzer::NTP::NTP_Analyzer::InstantiateAnalyzer)); + AddComponent(new ::analyzer::Component("NTP", ::analyzer::NTP::NTP_Analyzer::Instantiate)); plugin::Configuration config; config.name = "Bro::NTP"; - config.description = "Network Time Protocol analyzer"; + config.description = "NTP analyzer"; return config; } } plugin; } -} \ No newline at end of file +} diff --git a/src/analyzer/protocol/ntp/events.bif b/src/analyzer/protocol/ntp/events.bif index 3d864fc89a..b9f66a1160 100644 --- a/src/analyzer/protocol/ntp/events.bif +++ b/src/analyzer/protocol/ntp/events.bif @@ -1,9 +1,15 @@ -## Generated for NTP time synchronization messages +## Generated for all NTP messages. Different from many other of Bro's events, +## this one is generated for both client-side and server-side messages. ## -## For more information about NTP, refer to :rfc:`5905` +## See `Wikipedia `__ for +## more information about the NTP protocol. ## -## c: The connection +## c: The connection record describing the corresponding UDP flow. ## -## msg: The NTP message record +## is_orig: +## +## msg: The parsed NTP message. +## +## .. zeek:see:: ## event ntp_message%(c: connection, is_orig: bool, msg: NTP::Message%); diff --git a/src/analyzer/protocol/ntp/ntp-analyzer.pac b/src/analyzer/protocol/ntp/ntp-analyzer.pac index 61a7472a49..e061439360 100644 --- a/src/analyzer/protocol/ntp/ntp-analyzer.pac +++ b/src/analyzer/protocol/ntp/ntp-analyzer.pac @@ -1,91 +1,131 @@ + %extern{ -#include -#define FRAC_16 pow(2,-16) -#define FRAC_32 pow(2,-32) -// NTP defines the epoch from 1900, not 1970 -#define EPOCH_OFFSET -2208988800 + #include + #define FRAC_16 pow(2,-16) + #define FRAC_32 pow(2,-32) + // NTP defines the epoch from 1900, not 1970 + #define EPOCH_OFFSET -2208988800 %} %header{ -Val* proc_ntp_short(const NTP_Short_Time* t); -Val* proc_ntp_timestamp(const NTP_Time* t); + Val* proc_ntp_short(const NTP_Short_Time* t); + Val* proc_ntp_timestamp(const NTP_Time* t); %} %code{ -Val* proc_ntp_short(const NTP_Short_Time* t) + Val* proc_ntp_short(const NTP_Short_Time* t) { - if ( t->seconds() == 0 && t->fractions() == 0 ) - return new Val(0.0, TYPE_INTERVAL); - return new Val(t->seconds() + t->fractions()*FRAC_16, TYPE_INTERVAL); + if ( t->seconds() == 0 && t->fractions() == 0 ) + return new Val(0.0, TYPE_INTERVAL); + return new Val(t->seconds() + t->fractions()*FRAC_16, TYPE_INTERVAL); } -Val* proc_ntp_timestamp(const NTP_Time* t) - { - if ( t->seconds() == 0 && t->fractions() == 0) - return new Val(0.0, TYPE_TIME); - return new Val(EPOCH_OFFSET + t->seconds() + (t->fractions()*FRAC_32), TYPE_TIME); - } + Val* proc_ntp_timestamp(const NTP_Time* t) + { + if ( t->seconds() == 0 && t->fractions() == 0) + return new Val(0.0, TYPE_TIME); + return new Val(EPOCH_OFFSET + t->seconds() + (t->fractions()*FRAC_32), TYPE_TIME); + } %} refine flow NTP_Flow += { - function proc_ntp_association(msg: NTP_Association): bool - %{ - RecordVal* rv = new RecordVal(BifType::Record::NTP::Message); - rv->Assign(0, new Val(${msg.version}, TYPE_COUNT)); - rv->Assign(1, new Val(${msg.mode}, TYPE_COUNT)); - rv->Assign(2, new Val(${msg.stratum}, TYPE_COUNT)); - rv->Assign(3, new Val(pow(2, ${msg.poll}), TYPE_INTERVAL)); - rv->Assign(4, new Val(pow(2, ${msg.precision}), TYPE_INTERVAL)); - rv->Assign(5, proc_ntp_short(${msg.root_delay})); - rv->Assign(6, proc_ntp_short(${msg.root_dispersion})); - switch ( ${msg.stratum} ) - { - case 0: - // unknown stratum => kiss code - rv->Assign(7, bytestring_to_val(${msg.reference_id})); - break; - case 1: - // reference clock => ref clock string - rv->Assign(8, bytestring_to_val(${msg.reference_id})); - break; - default: - // TODO: Check for v4/v6 - const uint8* d = ${msg.reference_id}.data(); - rv->Assign(9, new AddrVal(IPAddr(IPv4, (const uint32*) d, IPAddr::Network))); - break; - } + # This builds the standard msg record + function BuildNTPStdMsg(nsm: NTP_std_msg): BroVal + %{ + RecordVal* rv = new RecordVal(BifType::Record::NTP::std); - rv->Assign(11, proc_ntp_timestamp(${msg.reference_ts})); - rv->Assign(12, proc_ntp_timestamp(${msg.origin_ts})); - rv->Assign(13, proc_ntp_timestamp(${msg.receive_ts})); - rv->Assign(14, proc_ntp_timestamp(${msg.transmit_ts})); + rv->Assign(0, new Val(${nsm.stratum}, TYPE_COUNT)); + rv->Assign(1, new Val(pow(2, ${nsm.poll}), TYPE_INTERVAL)); + rv->Assign(2, new Val(pow(2, ${nsm.precision}), TYPE_INTERVAL)); + rv->Assign(3, proc_ntp_short(${nsm.root_delay})); + rv->Assign(4, proc_ntp_short(${nsm.root_dispersion})); - rv->Assign(17, new Val((uint32) ${msg.extensions}->size(), TYPE_COUNT)); + switch ( ${nsm.stratum} ) + { + case 0: + // unknown stratum => kiss code + rv->Assign(7, bytestring_to_val(${nsm.reference_id})); + break; + case 1: + // reference clock => ref clock string + rv->Assign(8, bytestring_to_val(${nsm.reference_id})); + break; + default: + // TODO: Check for v4/v6 + const uint8* d = ${nsm.reference_id}.data(); + rv->Assign(9, new AddrVal(IPAddr(IPv4, (const uint32*) d, IPAddr::Network))); + break; + } - BifEvent::generate_ntp_message(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - is_orig(), rv); - return true; - %} + rv->Assign(9, proc_ntp_timestamp(${nsm.reference_ts})); + rv->Assign(10, proc_ntp_timestamp(${nsm.origin_ts})); + rv->Assign(11, proc_ntp_timestamp(${nsm.receive_ts})); + rv->Assign(12, proc_ntp_timestamp(${nsm.transmit_ts})); - function proc_ntp_mode6(msg: NTP_Mode6): bool - %{ - BifEvent::generate_ntp_mode6_message(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - is_orig(), ${msg.opcode}); - return true; - %} + rv->Assign(15, new Val((uint32) ${nsm.extensions}->size(), TYPE_COUNT)); - function proc_ntp_mode7(msg: NTP_Mode7): bool - %{ - BifEvent::generate_ntp_mode7_message(connection()->bro_analyzer(), - connection()->bro_analyzer()->Conn(), - is_orig(), ${msg.request_code}); - return true; - %} + return rv; + %} + + # This builds the control msg record + function BuildNTPControlMsg(ncm: NTP_control_msg): BroVal + %{ + RecordVal* rv = new RecordVal(BifType::Record::NTP::control); + + rv->Assign(0, new Val(${ncm.OpCode}, TYPE_COUNT)); + rv->Assign(1, new Val(${ncm.R}, TYPE_BOOL)); + rv->Assign(2, new Val(${ncm.E}, TYPE_BOOL)); + rv->Assign(3, new Val(${ncm.M}, TYPE_BOOL)); + rv->Assign(4, new Val(${ncm.sequence}, TYPE_COUNT)); + rv->Assign(5, new Val(${ncm.status}, TYPE_COUNT)); + rv->Assign(6, new Val(${ncm.association_id}, TYPE_COUNT)); + rv->Assign(7, new Val(${ncm.offs}, TYPE_COUNT)); + rv->Assign(8, new Val(${ncm.c}, TYPE_COUNT)); + rv->Assign(9, bytestring_to_val(${ncm.data})); + + return rv; + %} + + # This builds the mode7 msg record + function BuildNTPMode7Msg(m7: NTP_mode7_msg): BroVal + %{ + RecordVal* rv = new RecordVal(BifType::Record::NTP::mode7); + + rv->Assign(0, new Val(${m7.request_code}, TYPE_COUNT)); + rv->Assign(1, new Val(${m7.auth_bit}, TYPE_BOOL)); + rv->Assign(2, new Val(${m7.sequence}, TYPE_COUNT)); + rv->Assign(3, new Val(${m7.implementation}, TYPE_COUNT)); + rv->Assign(4, new Val(${m7.error_code}, TYPE_COUNT)); + rv->Assign(5, bytestring_to_val(${m7.data})); + + return rv; + %} + + + function proc_ntp_message(msg: NTP_PDU): bool + %{ + + RecordVal* rv = new RecordVal(BifType::Record::NTP::Message); + + rv->Assign(0, new Val(${msg.version}, TYPE_COUNT)); + rv->Assign(1, new Val(${msg.mode}, TYPE_COUNT)); + + // The standard record + if ( ${msg.mode}>0 && ${msg.mode}<6 ) { + rv->Assign(2, BuildNTPStdMsg(${msg.std})); + } else if ( ${msg.mode}==6 ) { + rv->Assign(3, BuildNTPControlMsg(${msg.control})); + } else if ( ${msg.mode}==7 ) { + rv->Assign(4, BuildNTPMode7Msg(${msg.mode7})); + } + + BifEvent::generate_ntp_message(connection()->bro_analyzer(), connection()->bro_analyzer()->Conn(), is_orig(), rv); + return true; + %} }; -refine typeattr NTP_Association += &let { - proc: bool = $context.flow.proc_ntp_association(this); +refine typeattr NTP_PDU += &let { + proc: bool = $context.flow.proc_ntp_message(this); }; + diff --git a/src/analyzer/protocol/ntp/ntp-protocol.pac b/src/analyzer/protocol/ntp/ntp-protocol.pac index cbac2ee09d..4a1e8af22b 100644 --- a/src/analyzer/protocol/ntp/ntp-protocol.pac +++ b/src/analyzer/protocol/ntp/ntp-protocol.pac @@ -1,49 +1,71 @@ + +# This is the common part in the header format. +# See RFC 5905 for details type NTP_PDU(is_orig: bool) = record { - first_byte : uint8; - - # Modes 1-5 are standard NTP time sync - mode_chk_1 : case (mode>=1 && mode<=5) of { - true -> msg: NTP_Association(first_byte, mode, version); - false -> unk: empty; - } &requires(version); - - mode_chk_2 : case (mode) of { - 6 -> ctl_msg : NTP_Mode6(first_byte, version) &restofdata; - 7 -> mode_7 : NTP_Mode7(first_byte, version) &restofdata; - default -> unknown: bytestring &restofdata; - } &requires(version); - + # The first byte of the NTP header contains the leap indicator, + # the version and the mode + first_byte : uint8; + # Modes 1-5 are standard NTP time sync + standard_modes : case (mode>=1 && mode<=5) of { + true -> std : NTP_std_msg; + false -> emp : empty; + }; + modes_6_7 : case (mode) of { + # mode 6 is for control messages (format is different from modes 6-7) + 6 -> control : NTP_control_msg; + # mode 7 is reserved or private (and implementation dependent). For example used for some commands such as MONLIST + 7 -> mode7 : NTP_mode7_msg; + default -> unknown : bytestring &restofdata; + }; } &let { - mode: uint8 = (first_byte & 0x7); # Bytes 6-8 of 8-byte value - version: uint8 = (first_byte & 0x38) >> 3; # Bytes 3-5 of 8-byte value -} &byteorder=bigendian; + leap: uint8 = (first_byte & 0xc0)>>6; # First 2 bits of 8-bits value + version: uint8 = (first_byte & 0x38)>>3; # Bits 3-5 of 8-bits value + mode: uint8 = (first_byte & 0x07); # Bits 6-8 of 8-bits value +} &byteorder=bigendian &exportsourcedata; -type NTP_Association(first_byte: uint8, mode: uint8, version: uint8) = record { - stratum : uint8; - poll : int8; - precision : int8; - - root_delay : NTP_Short_Time; - root_dispersion: NTP_Short_Time; - reference_id : bytestring &length=4; - reference_ts : NTP_Time; - - origin_ts : NTP_Time; - receive_ts : NTP_Time; - transmit_ts : NTP_Time; +# This is the most common type of message, corresponding to modes 1-5 +# This kind of msg are used for normal operation of syncronization +# See RFC 5905 for details +type NTP_std_msg = record { + stratum : uint8; + poll : int8; + precision : int8; - extensions : Extension_Field[] &until($input.length() <= 18); - have_mac : case (offsetof(have_mac) < length) of { - true -> mac : NTP_MAC; - false -> nil : empty; - } &requires(length); + root_delay : NTP_Short_Time; + root_dispersion: NTP_Short_Time; + reference_id : bytestring &length=4; + reference_ts : NTP_Time; + + origin_ts : NTP_Time; + receive_ts : NTP_Time; + transmit_ts : NTP_Time; + extensions : Extension_Field[] &until($input.length() <= 18); + have_mac : case (offsetof(have_mac) < length) of { + true -> mac : NTP_MAC; + false -> nil : empty; + } &requires(length); } &let { - leap: bool = (first_byte & 0xc0); # First 2 bytes of 8-byte value - leap_61: bool = (leap & 0x40) > 0; # leap_indicator == 1 - leap_59: bool = (leap & 0x80) > 0; # leap_indicator == 2 - leap_unk: bool = (leap & 0xc0) > 0; # leap_indicator == 3 - length = sourcedata.length(); -} &exportsourcedata; + length = sourcedata.length(); +} &byteorder=bigendian &exportsourcedata; + +# This format is for mode==6, control msg +# See RFC 1119 for details +type NTP_control_msg = record { + second_byte : uint8; + sequence : uint16; + status : uint16; #TODO: this must be further specified + association_id : uint16; + offs : uint16; + c : uint16; + data : bytestring &restofdata; + #auth : #TODO +} &let { + R: bool = (second_byte & 0x80) > 0; # First bit of 8-bits value + E: bool = (second_byte & 0x40) > 0; # Second bit of 8-bits value + M: bool = (second_byte & 0x20) > 0; # Third bit of 8-bits value + OpCode: uint8 = (second_byte & 0x1F); # Last 5 bits of 8-bits value +} &byteorder=bigendian &exportsourcedata; + type NTP_MAC = record { key_id: uint32; @@ -51,37 +73,17 @@ type NTP_MAC = record { } &length=18; type Extension_Field = record { - field_type: uint16; - length : uint16; - data : bytestring &length=length-4; + field_type: uint16; + length : uint16; + data : bytestring &length=length-4; }; type NTP_Short_Time = record { - seconds: int16; - fractions: int16; + seconds: int16; + fractions: int16; }; type NTP_Time = record { - seconds: uint32; - fractions: uint32; -}; - - -# From RFC 1305, Appendix B: -type NTP_Mode6(first_byte: uint8, version: uint8) = record { - rem_op : uint8; - sequence: uint16; - status : uint16; - assoc_id: uint16; - offset : uint16; - count : uint16; - data : bytestring &length=count; - pad : padding[pad_length]; - opt_auth: bytestring &restofdata; -} &let { - response_bit: bool = (rem_op & 0x80) > 0; - error_bit : bool = (rem_op & 0x40) > 0; - more_bit : bool = (rem_op & 0x20) > 0; - opcode : uint8 = (rem_op & 0x1f); - pad_length : uint8 = (count % 32 == 0) ? 0 : 32 - (count % 32); + seconds: uint32; + fractions: uint32; }; diff --git a/src/analyzer/protocol/ntp/types.bif b/src/analyzer/protocol/ntp/types.bif index 1a5fd07faa..513bd4dbae 100644 --- a/src/analyzer/protocol/ntp/types.bif +++ b/src/analyzer/protocol/ntp/types.bif @@ -1,5 +1,6 @@ module NTP; +type NTP::std: record; +type NTP::control: record; +type NTP::mode7: record; type NTP::Message: record; - -module GLOBAL; \ No newline at end of file