diff --git a/CHANGES b/CHANGES index 5decf23fc5..1ab67688c3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,12 @@ +2.5-405 | 2018-02-05 13:29:39 -0600 + + * Add MOUNT3 protocol parser. + + It's not activated by default. New events available: mount_proc_null, + mount_proc_mnt, mount_proc_umnt, mount_proc_umnt_all, + mount_proc_not_implemented, mount_reply_status. (Devin Trejo) + 2.5-402 | 2018-02-05 10:43:59 -0600 * Fix (unlikely) memory leak in nb_dns.c (Corelight) diff --git a/NEWS b/NEWS index e359cf63b8..067a469c62 100644 --- a/NEWS +++ b/NEWS @@ -45,6 +45,15 @@ New Functionality - HTTP now recognizes and skips upgraded/websocket connections. A new event, http_connection_upgrade, is raised in such cases. +- Added a MOUNT3 protocol parser + + - This is not enabled by default (no ports are registered and no + DPD signatures exist, so no connections will end up attaching the + new Mount analyzer). If it were to be activated by users, the + following events are available: mount_proc_null, mount_proc_mnt, + mount_proc_umnt, mount_proc_umnt_all, mount_proc_not_implemented, + mount_reply_status. + Changed Functionality --------------------- diff --git a/VERSION b/VERSION index 29dcd1f939..17b1b172ab 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.5-402 +2.5-405 diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index f2ea2ed29a..c192f25ed9 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -2350,6 +2350,71 @@ export { }; } # end export + +module MOUNT3; +export { + + ## Record summarizing the general results and status of MOUNT3 + ## request/reply pairs. + ## + ## Note that when *rpc_stat* or *mount_stat* indicates not successful, + ## the reply record passed to the corresponding event will be empty and + ## contain uninitialized fields, so don't use it. Also note that time + # and duration values might not be fully accurate. For TCP, we record + # times when the corresponding chunk of data is delivered to the + # analyzer. Depending on the reassembler, this might be well after the + # first packet of the request was received. + # + # .. bro:see:: mount_proc_mnt mount_proc_dump mount_proc_umnt + # mount_proc_umntall mount_proc_export mount_proc_not_implemented + type info_t: record { + ## The RPC status. + rpc_stat: rpc_status; + ## The MOUNT status. + mnt_stat: status_t; + ## The start time of the request. + req_start: time; + ## The duration of the request. + req_dur: interval; + ## The length in bytes of the request. + req_len: count; + ## The start time of the reply. + rep_start: time; + ## The duration of the reply. + rep_dur: interval; + ## The length in bytes of the reply. + rep_len: count; + ## The user id of the reply. + rpc_uid: count; + ## The group id of the reply. + rpc_gid: count; + ## The stamp of the reply. + rpc_stamp: count; + ## The machine name of the reply. + rpc_machine_name: string; + ## The auxiliary ids of the reply. + rpc_auxgids: index_vec; + }; + + ## MOUNT *mnt* arguments. + ## + ## .. bro:see:: mount_proc_mnt + type dirmntargs_t : record { + dirname: string; ##< Name of directory to mount + }; + + ## MOUNT lookup reply. If the mount failed, *dir_attr* may be set. If the + ## mount succeeded, *fh* is always set. + ## + ## .. bro:see:: mount_proc_mnt + type mnt_reply_t: record { + dirfh: string &optional; ##< Dir handle + auth_flavors: vector of auth_flavor_t &optional; ##< Returned authentication flavors + }; + +} # end export + + module Threading; export { diff --git a/src/analyzer/protocol/rpc/CMakeLists.txt b/src/analyzer/protocol/rpc/CMakeLists.txt index 5696a74cd6..c71c6ddd9a 100644 --- a/src/analyzer/protocol/rpc/CMakeLists.txt +++ b/src/analyzer/protocol/rpc/CMakeLists.txt @@ -4,6 +4,6 @@ include(BroPlugin) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) bro_plugin_begin(Bro RPC) -bro_plugin_cc(RPC.cc NFS.cc Portmap.cc XDR.cc Plugin.cc) +bro_plugin_cc(RPC.cc NFS.cc MOUNT.cc Portmap.cc XDR.cc Plugin.cc) bro_plugin_bif(events.bif) bro_plugin_end() diff --git a/src/analyzer/protocol/rpc/MOUNT.cc b/src/analyzer/protocol/rpc/MOUNT.cc new file mode 100644 index 0000000000..9ec35ef4ab --- /dev/null +++ b/src/analyzer/protocol/rpc/MOUNT.cc @@ -0,0 +1,301 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include +#include + +#include "bro-config.h" + +#include "NetVar.h" +#include "XDR.h" +#include "MOUNT.h" +#include "Event.h" + +#include "events.bif.h" + +using namespace analyzer::rpc; + +int MOUNT_Interp::RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n) + { + if ( c->Program() != 100005 ) + Weird(fmt("bad_RPC_program (%d)", c->Program())); + + uint32 proc = c->Proc(); + // The call arguments, depends on the call type obviously ... + Val *callarg = 0; + + switch ( proc ) { + case BifEnum::MOUNT3::PROC_NULL: + break; + + case BifEnum::MOUNT3::PROC_MNT: + callarg = mount3_dirmntargs(buf, n); + break; + + case BifEnum::MOUNT3::PROC_UMNT: + callarg = mount3_dirmntargs(buf, n); + break; + + case BifEnum::MOUNT3::PROC_UMNT_ALL: + callarg = mount3_dirmntargs(buf, n); + break; + + default: + callarg = 0; + if ( proc < BifEnum::MOUNT3::PROC_END_OF_PROCS ) + { + // We know the procedure but haven't implemented it. + // Otherwise DeliverRPC would complain about + // excess_RPC. + n = 0; + } + else + Weird(fmt("unknown_MOUNT_request(%u)", proc)); + + // Return 1 so that replies to unprocessed calls will still + // be processed, and the return status extracted. + return 1; + } + + if ( ! buf ) + { + // There was a parse error while trying to extract the call + // arguments. However, we don't know where exactly it + // happened and whether Vals where already allocated (e.g., a + // RecordVal was allocated but we failed to fill it). So we + // Unref() the call arguments, and we are fine. + Unref(callarg); + callarg = 0; + return 0; + } + + c->AddVal(callarg); // It's save to AddVal(0). + + return 1; + } + +int MOUNT_Interp::RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status rpc_status, + const u_char*& buf, int& n, double start_time, + double last_time, int reply_len) + { + EventHandlerPtr event = 0; + Val* reply = 0; + BifEnum::MOUNT3::status_t mount_status = BifEnum::MOUNT3::MNT3_OK; + bool rpc_success = ( rpc_status == BifEnum::RPC_SUCCESS ); + + // Reply always starts with the MOUNT status. + if ( rpc_success ) + { + if ( n >= 4 ) + mount_status = (BifEnum::MOUNT3::status_t)extract_XDR_uint32(buf, n); + else + mount_status = BifEnum::MOUNT3::MOUNT3ERR_UNKNOWN; + } + + if ( mount_reply_status ) + { + val_list* vl = event_common_vl(c, rpc_status, mount_status, + start_time, last_time, reply_len); + analyzer->ConnectionEvent(mount_reply_status, vl); + } + + if ( ! rpc_success ) + { + // We set the buffer to NULL, the function that extract the + // reply from the data stream will then return empty records. + // + buf = NULL; + n = 0; + } + + switch ( c->Proc() ) { + case BifEnum::MOUNT3::PROC_NULL: + event = mount_proc_null; + break; + + case BifEnum::MOUNT3::PROC_MNT: + reply = mount3_mnt_reply(buf, n, mount_status); + event = mount_proc_mnt; + break; + + case BifEnum::MOUNT3::PROC_UMNT: + reply = 0; + n = 0; + mount_status = BifEnum::MOUNT3::MNT3_OK; + event = mount_proc_umnt; + break; + + case BifEnum::MOUNT3::PROC_UMNT_ALL: + reply = 0; + n = 0; + mount_status = BifEnum::MOUNT3::MNT3_OK; + event = mount_proc_umnt; + break; + + default: + if ( c->Proc() < BifEnum::MOUNT3::PROC_END_OF_PROCS ) + { + // We know the procedure but haven't implemented it. + // Otherwise DeliverRPC would complain about + // excess_RPC. + n = 0; + reply = new EnumVal(c->Proc(), BifType::Enum::MOUNT3::proc_t); + event = mount_proc_not_implemented; + } + else + return 0; + } + + if ( rpc_success && ! buf ) + { + // There was a parse error. We have to unref the reply. (see + // also comments in RPC_BuildCall. + Unref(reply); + reply = 0; + return 0; + } + + // Note: if reply == 0, it won't be added to the val_list for the + // event. While we can check for that on the policy layer it's kinda + // ugly, because it's contrary to the event prototype. But having + // this optional argument to the event is really helpful. Otherwise I + // have to let reply point to a RecordVal where all fields are + // optional and all are set to 0 ... + if ( event ) + { + val_list* vl = event_common_vl(c, rpc_status, mount_status, + start_time, last_time, reply_len); + + Val *request = c->TakeRequestVal(); + + if ( request ) + vl->append(request); + + if ( reply ) + vl->append(reply); + + analyzer->ConnectionEvent(event, vl); + } + else + Unref(reply); + return 1; + } + +val_list* MOUNT_Interp::event_common_vl(RPC_CallInfo *c, + BifEnum::rpc_status rpc_status, + BifEnum::MOUNT3::status_t mount_status, + double rep_start_time, + double rep_last_time, int reply_len) + { + // Returns a new val_list that already has a conn_val, and mount3_info. + // These are the first parameters for each mount_* event ... + val_list *vl = new val_list; + vl->append(analyzer->BuildConnVal()); + VectorVal* auxgids = new VectorVal(internal_type("index_vec")->AsVectorType()); + + for (size_t i = 0; i < c->AuxGIDs().size(); ++i) + { + auxgids->Assign(i, new Val(c->AuxGIDs()[i], TYPE_COUNT)); + } + + RecordVal* info = new RecordVal(BifType::Record::MOUNT3::info_t); + info->Assign(0, new EnumVal(rpc_status, BifType::Enum::rpc_status)); + info->Assign(1, new EnumVal(mount_status, BifType::Enum::MOUNT3::status_t)); + info->Assign(2, new Val(c->StartTime(), TYPE_TIME)); + info->Assign(3, new Val(c->LastTime() - c->StartTime(), TYPE_INTERVAL)); + info->Assign(4, new Val(c->RPCLen(), TYPE_COUNT)); + info->Assign(5, new Val(rep_start_time, TYPE_TIME)); + info->Assign(6, new Val(rep_last_time - rep_start_time, TYPE_INTERVAL)); + info->Assign(7, new Val(reply_len, TYPE_COUNT)); + info->Assign(8, new Val(c->Uid(), TYPE_COUNT)); + info->Assign(9, new Val(c->Gid(), TYPE_COUNT)); + info->Assign(10, new Val(c->Stamp(), TYPE_COUNT)); + info->Assign(11, new StringVal(c->MachineName())); + info->Assign(12, auxgids); + + vl->append(info); + return vl; + } + +EnumVal* MOUNT_Interp::mount3_auth_flavor(const u_char*& buf, int& n) + { + BifEnum::MOUNT3::auth_flavor_t t = (BifEnum::MOUNT3::auth_flavor_t)extract_XDR_uint32(buf, n); + return new EnumVal(t, BifType::Enum::MOUNT3::auth_flavor_t); + } + +StringVal* MOUNT_Interp::mount3_fh(const u_char*& buf, int& n) + { + int fh_n; + const u_char* fh = extract_XDR_opaque(buf, n, fh_n, 64); + + if ( ! fh ) + return 0; + + return new StringVal(new BroString(fh, fh_n, 0)); + } + +StringVal* MOUNT_Interp::mount3_filename(const u_char*& buf, int& n) + { + int name_len; + const u_char* name = extract_XDR_opaque(buf, n, name_len); + + if ( ! name ) + return 0; + + return new StringVal(new BroString(name, name_len, 0)); + } + +RecordVal* MOUNT_Interp::mount3_dirmntargs(const u_char*& buf, int& n) + { + RecordVal* dirmntargs = new RecordVal(BifType::Record::MOUNT3::dirmntargs_t); + dirmntargs->Assign(0, mount3_filename(buf, n)); + return dirmntargs; + } + +RecordVal* MOUNT_Interp::mount3_mnt_reply(const u_char*& buf, int& n, + BifEnum::MOUNT3::status_t status) + { + RecordVal* rep = new RecordVal(BifType::Record::MOUNT3::mnt_reply_t); + + if ( status == BifEnum::MOUNT3::MNT3_OK ) + { + rep->Assign(0, mount3_fh(buf,n)); + + int auth_flavors_count = extract_XDR_uint32(buf, n); + VectorType* enum_vector = new VectorType(base_type(TYPE_ENUM)); + VectorVal* auth_flavors = new VectorVal(enum_vector); + Unref(enum_vector); + + for (int i = 0; i < auth_flavors_count; i++) + { + auth_flavors->Assign(auth_flavors->Size(), mount3_auth_flavor(buf, n)); // authentication + } + + rep->Assign(1, auth_flavors); + } + else + { + rep->Assign(0, 0); + rep->Assign(1, 0); + } + + return rep; + } + +MOUNT_Analyzer::MOUNT_Analyzer(Connection* conn) + : RPC_Analyzer("MOUNT", conn, new MOUNT_Interp(this)) + { + orig_rpc = resp_rpc = 0; + } + +void MOUNT_Analyzer::Init() + { + RPC_Analyzer::Init(); + + if ( Conn()->ConnTransport() == TRANSPORT_TCP ) + { + orig_rpc = new Contents_RPC(Conn(), true, interp); + resp_rpc = new Contents_RPC(Conn(), false, interp); + AddSupportAnalyzer(orig_rpc); + AddSupportAnalyzer(resp_rpc); + } + } diff --git a/src/analyzer/protocol/rpc/MOUNT.h b/src/analyzer/protocol/rpc/MOUNT.h new file mode 100644 index 0000000000..ed0c8fc9fc --- /dev/null +++ b/src/analyzer/protocol/rpc/MOUNT.h @@ -0,0 +1,55 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#ifndef ANALYZER_PROTOCOL_RPC_MOUNT_H +#define ANALYZER_PROTOCOL_RPC_MOUNT_H + +#include "RPC.h" +#include "XDR.h" +#include "Event.h" + +namespace analyzer { namespace rpc { + +class MOUNT_Interp : public RPC_Interpreter { +public: + MOUNT_Interp(analyzer::Analyzer* arg_analyzer) : RPC_Interpreter(arg_analyzer) { } + +protected: + int RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n); + int RPC_BuildReply(RPC_CallInfo* c, BifEnum::rpc_status rpc_status, + const u_char*& buf, int& n, double start_time, + double last_time, int reply_len); + + // Returns a new val_list that already has a conn_val, rpc_status and + // mount_status. These are the first parameters for each mount_* event + // ... + val_list* event_common_vl(RPC_CallInfo *c, BifEnum::rpc_status rpc_status, + BifEnum::MOUNT3::status_t mount_status, + double rep_start_time, double rep_last_time, + int reply_len); + + // These methods parse the appropriate MOUNTv3 "type" out of buf. If + // there are any errors (i.e., buffer to short, etc), buf will be set + // to 0. However, the methods might still return an allocated Val * ! + // So, you might want to Unref() the Val if buf is 0. Method names + // are based on the type names of RFC 1813. + EnumVal* mount3_auth_flavor(const u_char*& buf, int& n); + StringVal* mount3_fh(const u_char*& buf, int& n); + RecordVal* mount3_dirmntargs(const u_char*&buf, int &n); + StringVal* mount3_filename(const u_char*& buf, int& n); + + RecordVal* mount3_mnt_reply(const u_char*& buf, int& n, BifEnum::MOUNT3::status_t status); +}; + +class MOUNT_Analyzer : public RPC_Analyzer { +public: + MOUNT_Analyzer(Connection* conn); + virtual void Init(); + + static analyzer::Analyzer* Instantiate(Connection* conn) + { return new MOUNT_Analyzer(conn); } +}; + + +} } // namespace analyzer::* + +#endif diff --git a/src/analyzer/protocol/rpc/Plugin.cc b/src/analyzer/protocol/rpc/Plugin.cc index 15337f2d6e..abc2f679f2 100644 --- a/src/analyzer/protocol/rpc/Plugin.cc +++ b/src/analyzer/protocol/rpc/Plugin.cc @@ -5,6 +5,7 @@ #include "RPC.h" #include "NFS.h" +#include "MOUNT.h" #include "Portmap.h" namespace plugin { @@ -15,6 +16,7 @@ public: plugin::Configuration Configure() { AddComponent(new ::analyzer::Component("NFS", ::analyzer::rpc::NFS_Analyzer::Instantiate)); + AddComponent(new ::analyzer::Component("MOUNT", ::analyzer::rpc::MOUNT_Analyzer::Instantiate)); AddComponent(new ::analyzer::Component("Portmapper", ::analyzer::rpc::Portmapper_Analyzer::Instantiate)); AddComponent(new ::analyzer::Component("Contents_RPC", 0)); AddComponent(new ::analyzer::Component("Contents_NFS", 0)); diff --git a/src/analyzer/protocol/rpc/events.bif b/src/analyzer/protocol/rpc/events.bif index 881faface1..792eb39b60 100644 --- a/src/analyzer/protocol/rpc/events.bif +++ b/src/analyzer/protocol/rpc/events.bif @@ -765,3 +765,118 @@ event rpc_call%(c: connection, xid: count, prog: count, ver: count, proc: count, ## call to :bro:see:`Analyzer::register_for_ports` or a DPD payload ## signature. event rpc_reply%(c: connection, xid: count, status: rpc_status, reply_len: count%); + +## Generated for MOUNT3 request/reply dialogues of type *null*. The event is +## generated once we have either seen both the request and its corresponding +## reply, or an unanswered request has timed out. +## MOUNT is a service running on top of RPC. +## +## c: The RPC connection. +## +## info: Reports the status of the dialogue, along with some meta information. +## +## .. bro:see:: mount_proc_mnt mount_proc_dump mount_proc_umnt +## mount_proc_umntall mount_proc_export mount_proc_not_implemented +## +## .. todo:: Bro's current default configuration does not activate the protocol +## analyzer that generates this event; the corresponding script has not yet +## been ported to Bro 2.x. To still enable this event, one needs to +## register a port for it or add a DPD payload signature. +event mount_proc_null%(c: connection, info: MOUNT3::info_t%); + +## Generated for MOUNT3 request/reply dialogues of type *mnt*. The event is +## generated once we have either seen both the request and its corresponding +## reply, or an unanswered request has timed out. +## MOUNT is a service running on top of RPC. +## +## c: The RPC connection. +## +## info: Reports the status of the dialogue, along with some meta information. +## +## req: The arguments passed in the request. +## +## rep: The response returned in the reply. The values may not be valid if the +## request was unsuccessful. +## +## .. bro:see:: mount_proc_mnt mount_proc_dump mount_proc_umnt +## mount_proc_umntall mount_proc_export mount_proc_not_implemented +## +## .. todo:: Bro's current default configuration does not activate the protocol +## analyzer that generates this event; the corresponding script has not yet +## been ported to Bro 2.x. To still enable this event, one needs to +## register a port for it or add a DPD payload signature. +event mount_proc_mnt%(c: connection, info: MOUNT3::info_t, req: MOUNT3::dirmntargs_t, rep: MOUNT3::mnt_reply_t%); + +## Generated for MOUNT3 request/reply dialogues of type *umnt*. The event is +## generated once we have either seen both the request and its corresponding +## reply, or an unanswered request has timed out. +## MOUNT is a service running on top of RPC. +## +## c: The RPC connection. +## +## info: Reports the status of the dialogue, along with some meta information. +## +## req: The arguments passed in the request. +## +## .. bro:see:: mount_proc_mnt mount_proc_dump mount_proc_umnt +## mount_proc_umntall mount_proc_export mount_proc_not_implemented +## +## .. todo:: Bro's current default configuration does not activate the protocol +## analyzer that generates this event; the corresponding script has not yet +## been ported to Bro 2.x. To still enable this event, one needs to +## register a port for it or add a DPD payload signature. +event mount_proc_umnt%(c: connection, info: MOUNT3::info_t, req: MOUNT3::dirmntargs_t%); + +## Generated for MOUNT3 request/reply dialogues of type *umnt_all*. The event is +## generated once we have either seen both the request and its corresponding +## reply, or an unanswered request has timed out. +## MOUNT is a service running on top of RPC. +## +## c: The RPC connection. +## +## info: Reports the status of the dialogue, along with some meta information. +## +## req: The arguments passed in the request. +## +## .. bro:see:: mount_proc_mnt mount_proc_dump mount_proc_umnt +## mount_proc_umntall mount_proc_export mount_proc_not_implemented +## +## .. todo:: Bro's current default configuration does not activate the protocol +## analyzer that generates this event; the corresponding script has not yet +## been ported to Bro 2.x. To still enable this event, one needs to +## register a port for it or add a DPD payload signature. +event mount_proc_umnt_all%(c: connection, info: MOUNT3::info_t, req: MOUNT3::dirmntargs_t%); + +## Generated for MOUNT3 request/reply dialogues of a type that Bro's MOUNTv3 +## analyzer does not implement. +## +## c: The RPC connection. +## +## info: Reports the status of the dialogue, along with some meta information. +## +## proc: The procedure called that Bro does not implement. +## +## .. bro:see:: mount_proc_mnt mount_proc_dump mount_proc_umnt +## mount_proc_umntall mount_proc_export mount_proc_not_implemented +## +## .. todo:: Bro's current default configuration does not activate the protocol +## analyzer that generates this event; the corresponding script has not yet +## been ported to Bro 2.x. To still enable this event, one needs to +## register a port for it or add a DPD payload signature. +event mount_proc_not_implemented%(c: connection, info: MOUNT3::info_t, proc: MOUNT3::proc_t%); + +## Generated for each MOUNT3 reply message received, reporting just the +## status included. +## +## n: The connection. +## +## info: Reports the status included in the reply. +## +## .. bro:see:: mount_proc_mnt mount_proc_dump mount_proc_umnt +## mount_proc_umntall mount_proc_export mount_proc_not_implemented +## +## .. todo:: Bro's current default configuration does not activate the protocol +## analyzer that generates this event; the corresponding script has not yet +## been ported to Bro 2.x. To still enable this event, one needs to +## register a port for it or add a DPD payload signature. +event mount_reply_status%(n: connection, info: MOUNT3::info_t%); diff --git a/src/types.bif b/src/types.bif index 20995ef105..91daeebba9 100644 --- a/src/types.bif +++ b/src/types.bif @@ -13,6 +13,43 @@ enum rpc_status %{ RPC_UNKNOWN_ERROR, %} +module MOUNT3; + +enum proc_t %{ # MOUNT3 procedures + PROC_NULL = 0, # done + PROC_MNT = 1, # done + PROC_DUMP = 2, # not implemented + PROC_UMNT = 3, # done + PROC_UMNT_ALL = 4, # done + PROC_EXPORT = 5, # not implemented + PROC_END_OF_PROCS = 6, # not implemented +%} + +enum status_t %{ # MOUNT3 return status + MNT3_OK = 0, + MNT3ERR_PERM = 1, + MNT3ERR_NOENT = 2, + MNT3ERR_IO = 5, + MNT3ERR_ACCES = 13, + MNT3ERR_NOTDIR = 20, + MNT3ERR_INVAL = 22, + MNT3ERR_NAMETOOLONG = 63, + MNT3ERR_NOTSUPP = 10004, + MNT3ERR_SERVERFAULT = 10006, + MOUNT3ERR_UNKNOWN = 0xffffffff, +%} + +enum auth_flavor_t %{ # MOUNT3 auth flavors + AUTH_NULL = 0, + AUTH_UNIX = 1, + AUTH_SHORT = 2, + AUTH_DES = 3, +%} + +type info_t: record; +type mnt_reply_t: record; +type dirmntargs_t: record; + module NFS3; enum proc_t %{ # NFSv3 procedures diff --git a/testing/btest/Baseline/scripts.base.protocols.mount.basic/.stdout b/testing/btest/Baseline/scripts.base.protocols.mount.basic/.stdout new file mode 100644 index 0000000000..b3e377595b --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.mount.basic/.stdout @@ -0,0 +1,2 @@ +mount_proc_mnt: [id=[orig_h=10.111.131.18, orig_p=765/udp, resp_h=10.111.131.132, resp_p=20048/udp], orig=[size=144, state=1, num_pkts=2, num_bytes_ip=200, flow_label=0, l2_addr=00:50:56:b2:4e:d3], resp=[size=84, state=1, num_pkts=1, num_bytes_ip=52, flow_label=0, l2_addr=00:50:56:b2:78:69], start_time=1514568131.621984, duration=0.000553, service={\x0a\x0a}, history=Dd, uid=CHhAvVGS1DHFjwGM9, tunnel=, vlan=, inner_vlan=]\x0a\x09[rpc_stat=RPC_SUCCESS, mnt_stat=MOUNT3::MNT3_OK, req_start=1514568131.62212, req_dur=0.0, req_len=96, rep_start=1514568131.622537, rep_dur=0.0, rep_len=52, rpc_uid=0, rpc_gid=0, rpc_stamp=19078341, rpc_machine_name=pddevbal802, rpc_auxgids=[0, 5, 10, 24]]\x0a\x09[dirname=/pddevbal801]\x0a\x09[dirfh=\x01\x00\x06\x00\xea,\xbbJ\x9e\xf7I\x95\xa56V(\xce\xda`\xa2, auth_flavors=[MOUNT3::AUTH_UNIX]]\x0a +mount_proc_umnt: [id=[orig_h=10.111.131.18, orig_p=1016/udp, resp_h=10.111.131.132, resp_p=20048/udp], orig=[size=92, state=1, num_pkts=1, num_bytes_ip=120, flow_label=0, l2_addr=00:50:56:b2:4e:d3], resp=[size=24, state=1, num_pkts=0, num_bytes_ip=0, flow_label=0, l2_addr=00:50:56:b2:78:69], start_time=1514568131.665918, duration=0.000266, service={\x0a\x0a}, history=Dd, uid=ClEkJM2Vm5giqnMf4h, tunnel=, vlan=, inner_vlan=]\x0a\x09[rpc_stat=RPC_SUCCESS, mnt_stat=MOUNT3::MNT3_OK, req_start=1514568131.665918, req_dur=0.0, req_len=84, rep_start=1514568131.666184, rep_dur=0.0, rep_len=16, rpc_uid=0, rpc_gid=0, rpc_stamp=1514568131, rpc_machine_name=pddevbal802, rpc_auxgids=[0]]\x0a\x09[dirname=/pddevbal801]\x0a diff --git a/testing/btest/Traces/mount/mount_base.pcap b/testing/btest/Traces/mount/mount_base.pcap new file mode 100644 index 0000000000..0d71878424 Binary files /dev/null and b/testing/btest/Traces/mount/mount_base.pcap differ diff --git a/testing/btest/scripts/base/protocols/mount/basic.test b/testing/btest/scripts/base/protocols/mount/basic.test new file mode 100644 index 0000000000..8576874ce3 --- /dev/null +++ b/testing/btest/scripts/base/protocols/mount/basic.test @@ -0,0 +1,31 @@ +# @TEST-EXEC: bro -b -r $TRACES/mount/mount_base.pcap %INPUT +# @TEST-EXEC: btest-diff .stdout + +global mount_ports: set[port] = { 635/tcp, 635/udp, 20048/tcp, 20048/udp } &redef; +redef ignore_checksums = T; + +event bro_init() + { + Analyzer::register_for_ports(Analyzer::ANALYZER_MOUNT, mount_ports); + Analyzer::enable_analyzer(Analyzer::ANALYZER_MOUNT); + } + +event mount_proc_mnt(c: connection, info: MOUNT3::info_t, req: MOUNT3::dirmntargs_t, rep: MOUNT3::mnt_reply_t) + { + print(fmt("mount_proc_mnt: %s\n\t%s\n\t%s\n\t%s\n", c, info, req, rep)); + } + +event mount_proc_umnt(c: connection, info: MOUNT3::info_t, req: MOUNT3::dirmntargs_t) + { + print(fmt("mount_proc_umnt: %s\n\t%s\n\t%s\n", c, info, req)); + } + +event mount_proc_umnt_all(c: connection, info: MOUNT3::info_t, req: MOUNT3::dirmntargs_t) + { + print(fmt("mount_proc_umnt_all: %s\n\t%s\n\t%s\n", c, info, req)); + } + +event mount_proc_not_implemented(c: connection, info: MOUNT3::info_t, proc: MOUNT3::proc_t) + { + print(fmt("mount_proc_not_implemented: %s\n\t%s\n\t%s\n", c, info, proc)); + }