mirror of
https://github.com/zeek/zeek.git
synced 2025-10-10 02:28:21 +00:00
Merge branch 'mount-protocol' of https://github.com/dtrejod/bro
* 'mount-protocol' of https://github.com/dtrejod/bro: Add unit tests for new MOUNT events -- mount_proc_mnt, mount_proc_umnt, mount_proc_umnt_all, mount_proc_not_implemented. Add mount_proc_null, mount_proc_mnt, mount_proc_umnt, mount_proc_umnt_all, mount_proc_not_implemented, mount_reply_status.
This commit is contained in:
commit
35fa1261f3
13 changed files with 627 additions and 2 deletions
8
CHANGES
8
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
|
2.5-402 | 2018-02-05 10:43:59 -0600
|
||||||
|
|
||||||
* Fix (unlikely) memory leak in nb_dns.c (Corelight)
|
* Fix (unlikely) memory leak in nb_dns.c (Corelight)
|
||||||
|
|
9
NEWS
9
NEWS
|
@ -45,6 +45,15 @@ New Functionality
|
||||||
- HTTP now recognizes and skips upgraded/websocket connections. A new event,
|
- HTTP now recognizes and skips upgraded/websocket connections. A new event,
|
||||||
http_connection_upgrade, is raised in such cases.
|
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
|
Changed Functionality
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
2.5-402
|
2.5-405
|
||||||
|
|
|
@ -2350,6 +2350,71 @@ export {
|
||||||
};
|
};
|
||||||
} # end 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;
|
module Threading;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|
|
@ -4,6 +4,6 @@ include(BroPlugin)
|
||||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
bro_plugin_begin(Bro RPC)
|
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_bif(events.bif)
|
||||||
bro_plugin_end()
|
bro_plugin_end()
|
||||||
|
|
301
src/analyzer/protocol/rpc/MOUNT.cc
Normal file
301
src/analyzer/protocol/rpc/MOUNT.cc
Normal file
|
@ -0,0 +1,301 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
55
src/analyzer/protocol/rpc/MOUNT.h
Normal file
55
src/analyzer/protocol/rpc/MOUNT.h
Normal file
|
@ -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
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "RPC.h"
|
#include "RPC.h"
|
||||||
#include "NFS.h"
|
#include "NFS.h"
|
||||||
|
#include "MOUNT.h"
|
||||||
#include "Portmap.h"
|
#include "Portmap.h"
|
||||||
|
|
||||||
namespace plugin {
|
namespace plugin {
|
||||||
|
@ -15,6 +16,7 @@ public:
|
||||||
plugin::Configuration Configure()
|
plugin::Configuration Configure()
|
||||||
{
|
{
|
||||||
AddComponent(new ::analyzer::Component("NFS", ::analyzer::rpc::NFS_Analyzer::Instantiate));
|
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("Portmapper", ::analyzer::rpc::Portmapper_Analyzer::Instantiate));
|
||||||
AddComponent(new ::analyzer::Component("Contents_RPC", 0));
|
AddComponent(new ::analyzer::Component("Contents_RPC", 0));
|
||||||
AddComponent(new ::analyzer::Component("Contents_NFS", 0));
|
AddComponent(new ::analyzer::Component("Contents_NFS", 0));
|
||||||
|
|
|
@ -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
|
## call to :bro:see:`Analyzer::register_for_ports` or a DPD payload
|
||||||
## signature.
|
## signature.
|
||||||
event rpc_reply%(c: connection, xid: count, status: rpc_status, reply_len: count%);
|
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%);
|
||||||
|
|
|
@ -13,6 +13,43 @@ enum rpc_status %{
|
||||||
RPC_UNKNOWN_ERROR,
|
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;
|
module NFS3;
|
||||||
|
|
||||||
enum proc_t %{ # NFSv3 procedures
|
enum proc_t %{ # NFSv3 procedures
|
||||||
|
|
|
@ -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=<uninitialized>, vlan=<uninitialized>, inner_vlan=<uninitialized>]\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=<uninitialized>, vlan=<uninitialized>, inner_vlan=<uninitialized>]\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
|
BIN
testing/btest/Traces/mount/mount_base.pcap
Normal file
BIN
testing/btest/Traces/mount/mount_base.pcap
Normal file
Binary file not shown.
31
testing/btest/scripts/base/protocols/mount/basic.test
Normal file
31
testing/btest/scripts/base/protocols/mount/basic.test
Normal file
|
@ -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));
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue