diff --git a/CHANGES b/CHANGES
index dea3e4b4a9..074ecf46b7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,8 @@
+3.2.0-dev.338 | 2020-04-02 18:29:23 -0700
+
+ * Add RDP over UDP analyzer (Anthony Kasza, Corelight)
+
3.2.0-dev.336 | 2020-04-02 15:03:04 -0700
* Fix uses of GetBool in bifs to use GetTrue/GetFalse (Tim Wojtulewicz, Corelight)
diff --git a/NEWS b/NEWS
index 6cc946381b..34c42b7ca7 100644
--- a/NEWS
+++ b/NEWS
@@ -12,16 +12,22 @@ New Functionality
- X509 Certificate caching:
Zeek now caches certificates if they have (by default) been encountered
- more than 10 times in 62 seconds. Information for cached certificates is
- retained; if the certificate is encountered again it does not have to
- be re-parsed and already existing information is used to raise the events.
+ more than 10 times in 62 seconds. Information for cached certificates is
+ retained; if the certificate is encountered again it does not have to
+ be re-parsed and already existing information is used to raise the events.
- This should especially help with performance in environments where the
- same certificates are seen very often.
+ This should especially help with performance in environments where the
+ same certificates are seen very often.
- Certificate caching is very configureable; it is possible to disable the
- feature, change the time intervals or even suppress X509 events.
- For details see ``scripts/base/files/x509/main.zeek``.
+ Certificate caching is very configureable; it is possible to disable the
+ feature, change the time intervals or even suppress X509 events.
+ For details see ``scripts/base/files/x509/main.zeek``.
+
+- Add parsing support for Remote Desktop Protocol UDP Transport Extension
+ (RDPEUDP versions 1 and 2). This primarily only adds "rdpeudp" to
+ connection record service fields when an RDPEUDP session handhake is
+ detected, but also provides a few other events related to the RDPEUDP
+ connection establishment.
Changed Functionality
---------------------
diff --git a/VERSION b/VERSION
index 715ee26f4d..60829bcd08 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.2.0-dev.336
+3.2.0-dev.338
diff --git a/doc b/doc
index fbbcdd345d..26b923f841 160000
--- a/doc
+++ b/doc
@@ -1 +1 @@
-Subproject commit fbbcdd345d275036384f20e2f11f7a9d6d26f9d2
+Subproject commit 26b923f841f98238f68756e91083bef7a3004b0c
diff --git a/scripts/base/protocols/rdp/dpd.sig b/scripts/base/protocols/rdp/dpd.sig
index f8ebff34b9..a4e6f237bb 100644
--- a/scripts/base/protocols/rdp/dpd.sig
+++ b/scripts/base/protocols/rdp/dpd.sig
@@ -10,3 +10,12 @@ signature dpd_rdp_server {
ip-proto == tcp
payload /(.{5}\xd0|.*McDn)/
}
+
+signature dpd_rdpeudp_syn {
+ ip-proto == udp
+ payload-size <= 1232
+ payload-size >= 1132
+ payload /^\xff{4}.{2}.{1}\x01/
+ enable "rdpeudp"
+}
+
diff --git a/scripts/base/protocols/rdp/main.zeek b/scripts/base/protocols/rdp/main.zeek
index 2d6fd833f7..993b6e1eb7 100644
--- a/scripts/base/protocols/rdp/main.zeek
+++ b/scripts/base/protocols/rdp/main.zeek
@@ -85,13 +85,15 @@ redef record connection += {
rdp: Info &optional;
};
-const ports = { 3389/tcp };
-redef likely_server_ports += { ports };
+const rdp_ports = { 3389/tcp };
+const rdpeudp_ports = { 3389/udp };
+redef likely_server_ports += { rdp_ports, rdpeudp_ports };
event zeek_init() &priority=5
{
Log::create_stream(RDP::LOG, [$columns=RDP::Info, $ev=log_rdp, $path="rdp"]);
- Analyzer::register_for_ports(Analyzer::ANALYZER_RDP, ports);
+ Analyzer::register_for_ports(Analyzer::ANALYZER_RDP, rdp_ports);
+ Analyzer::register_for_ports(Analyzer::ANALYZER_RDPEUDP, rdpeudp_ports);
}
function write_log(c: connection)
diff --git a/src/analyzer/protocol/rdp/CMakeLists.txt b/src/analyzer/protocol/rdp/CMakeLists.txt
index 67ad09c18c..7011373593 100644
--- a/src/analyzer/protocol/rdp/CMakeLists.txt
+++ b/src/analyzer/protocol/rdp/CMakeLists.txt
@@ -3,8 +3,9 @@ include(ZeekPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
zeek_plugin_begin(Zeek RDP)
- zeek_plugin_cc(RDP.cc Plugin.cc)
+ zeek_plugin_cc(RDPEUDP.cc RDP.cc Plugin.cc)
zeek_plugin_bif(events.bif)
zeek_plugin_bif(types.bif)
zeek_plugin_pac(rdp.pac rdp-analyzer.pac rdp-protocol.pac ../asn1/asn1.pac)
+ zeek_plugin_pac(rdpeudp.pac rdpeudp-analyzer.pac rdpeudp-protocol.pac)
zeek_plugin_end()
diff --git a/src/analyzer/protocol/rdp/Plugin.cc b/src/analyzer/protocol/rdp/Plugin.cc
index c4771d6a5e..7d07d4c564 100644
--- a/src/analyzer/protocol/rdp/Plugin.cc
+++ b/src/analyzer/protocol/rdp/Plugin.cc
@@ -1,4 +1,5 @@
#include "RDP.h"
+#include "RDPEUDP.h"
#include "plugin/Plugin.h"
#include "analyzer/Component.h"
@@ -10,6 +11,7 @@ public:
plugin::Configuration Configure() override
{
AddComponent(new ::analyzer::Component("RDP", ::analyzer::rdp::RDP_Analyzer::InstantiateAnalyzer));
+ AddComponent(new ::analyzer::Component("RDPEUDP", ::analyzer::rdpeudp::RDP_Analyzer::InstantiateAnalyzer));
plugin::Configuration config;
config.name = "Zeek::RDP";
diff --git a/src/analyzer/protocol/rdp/RDP.h b/src/analyzer/protocol/rdp/RDP.h
index a991e06921..99bad567a2 100644
--- a/src/analyzer/protocol/rdp/RDP.h
+++ b/src/analyzer/protocol/rdp/RDP.h
@@ -1,11 +1,8 @@
#pragma once
#include "events.bif.h"
-
-
#include "analyzer/protocol/tcp/TCP.h"
#include "analyzer/protocol/pia/PIA.h"
-
#include "rdp_pac.h"
namespace analyzer { namespace rdp {
diff --git a/src/analyzer/protocol/rdp/RDPEUDP.cc b/src/analyzer/protocol/rdp/RDPEUDP.cc
new file mode 100644
index 0000000000..3cedd1eaa2
--- /dev/null
+++ b/src/analyzer/protocol/rdp/RDPEUDP.cc
@@ -0,0 +1,37 @@
+#include "RDPEUDP.h"
+#include "Reporter.h"
+#include "events.bif.h"
+#include "rdpeudp_pac.h"
+
+using namespace analyzer::rdpeudp;
+
+RDP_Analyzer::RDP_Analyzer(Connection* c)
+ : analyzer::Analyzer("RDPEUDP", c)
+ {
+ interp = new binpac::RDPEUDP::RDPEUDP_Conn(this);
+ }
+
+RDP_Analyzer::~RDP_Analyzer()
+ {
+ delete interp;
+ }
+
+void RDP_Analyzer::Done()
+ {
+ Analyzer::Done();
+ }
+
+void RDP_Analyzer::DeliverPacket(int len, const u_char* data, bool orig,
+ uint64_t seq, const IP_Hdr* ip, int caplen)
+ {
+ Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
+
+ try
+ {
+ interp->NewData(orig, data, data + len);
+ }
+ catch ( const binpac::Exception& e )
+ {
+ ProtocolViolation(fmt("Binpac exception: %s", e.c_msg()));
+ }
+ }
diff --git a/src/analyzer/protocol/rdp/RDPEUDP.h b/src/analyzer/protocol/rdp/RDPEUDP.h
new file mode 100644
index 0000000000..dc874ca783
--- /dev/null
+++ b/src/analyzer/protocol/rdp/RDPEUDP.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "events.bif.h"
+#include "analyzer/protocol/udp/UDP.h"
+#include "rdpeudp_pac.h"
+
+namespace analyzer { namespace rdpeudp {
+class RDP_Analyzer : public analyzer::Analyzer {
+
+public:
+ explicit RDP_Analyzer(Connection* conn);
+ ~RDP_Analyzer() override;
+
+ void Done() override;
+ void DeliverPacket(int len, const u_char* data, bool orig,
+ uint64_t seq, const IP_Hdr* ip, int caplen) override;
+ static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
+ { return new RDP_Analyzer(conn); }
+
+protected:
+ binpac::RDPEUDP::RDPEUDP_Conn* interp;
+};
+
+} }
diff --git a/src/analyzer/protocol/rdp/events.bif b/src/analyzer/protocol/rdp/events.bif
index 178860bd42..7ba5a6a35b 100644
--- a/src/analyzer/protocol/rdp/events.bif
+++ b/src/analyzer/protocol/rdp/events.bif
@@ -1,3 +1,31 @@
+## Generated for RDPEUDP SYN UDP Datagram
+##
+## c: The connection record for the underlying transport-layer session/flow.
+event rdpeudp_syn%(c: connection%);
+
+## Generated for RDPEUDP SYNACK UDP Datagram
+##
+## c: The connection record for the underlying transport-layer session/flow.
+event rdpeudp_synack%(c: connection%);
+
+## Generated when RDPEUDP connections are established (both sides SYN)
+##
+## c: The connection record for the underlying transport-layer session/flow.
+##
+## version: Whether the connection is RDPEUDP1 or RDPEUDP2
+event rdpeudp_established%(c: connection, version: count%);
+
+## Generated when for data messages exchanged after a RDPEUDP connection establishes
+##
+## c: The connection record for the underlying transport-layer session/flow.
+##
+## is_orig: Whether the data was sent by the originator or responder of the connection.
+##
+## version: Whether the connection is RDPEUDP1 or RDPEUDP2
+##
+## data: The payload of the packet. This is probably very non-performant.
+event rdpeudp_data%(c: connection, is_orig: bool, version: count, data: string%);
+
## Generated for each packet after RDP native encryption begins
##
## c: The connection record for the underlying transport-layer session/flow.
diff --git a/src/analyzer/protocol/rdp/rdpeudp-analyzer.pac b/src/analyzer/protocol/rdp/rdpeudp-analyzer.pac
new file mode 100644
index 0000000000..561107c012
--- /dev/null
+++ b/src/analyzer/protocol/rdp/rdpeudp-analyzer.pac
@@ -0,0 +1,119 @@
+refine connection RDPEUDP_Conn += {
+ %member{
+ enum RDPEUDP_STATE {
+ NEED_SYN = 0x1,
+ NEED_SYNACK = 0x2,
+ NED_ACK = 0x3,
+ ESTABLISHED = 0x4,
+ };
+
+ uint8 state_ = NEED_SYN;
+ bool orig_rdpeudp2_ = false;
+ bool resp_rdpeudp2_ = false;
+ bool orig_lossy_ = false;
+ bool resp_lossy_ = false;
+ %}
+
+ function get_state(): uint8
+ %{
+ return state_;
+ %}
+
+ function is_version2(): bool
+ %{
+ return (orig_rdpeudp2_ && resp_rdpeudp2_);
+ %}
+
+ function proc_rdpeudp_syn(is_orig: bool, uFlags: uint16, snSourceAck: uint32): bool
+ %{
+ if ( ! is_orig )
+ return false;
+
+ if ( (uFlags & 0x01) == 0 )
+ return false;
+
+ if ( snSourceAck != 0xffffffff )
+ return false;
+
+ if ( uFlags >= 0x1000 )
+ orig_rdpeudp2_ = true;
+
+ if ( (uFlags & 0x0200) == 0x0200 )
+ orig_lossy_ = true;
+
+ if ( rdpeudp_syn )
+ BifEvent::generate_rdpeudp_syn(bro_analyzer(), bro_analyzer()->Conn());
+
+ state_ = NEED_SYNACK;
+ return true;
+ %}
+
+ function proc_rdpeudp_synack(is_orig: bool, uFlags: uint16): bool
+ %{
+ if ( is_orig )
+ return false;
+
+ if ( (uFlags & 0x05) == 0 )
+ return false;
+
+ if ( rdpeudp_synack )
+ BifEvent::generate_rdpeudp_synack(bro_analyzer(), bro_analyzer()->Conn());
+
+ bro_analyzer()->ProtocolConfirmation();
+ state_ = NEED_ACK;
+
+ if ( uFlags >= 0x1000 )
+ resp_rdpeudp2_ = true;
+
+ if ( (uFlags & 0x0200) == 0x0200 )
+ resp_lossy_ = true;
+
+ return true;
+ %}
+
+ function proc_rdpeudp1_ack(is_orig: bool, data: bytestring): bool
+ %{
+ if ( state_ == NEED_ACK )
+ {
+ state_ = ESTABLISHED;
+
+ if ( rdpeudp_established )
+ BifEvent::generate_rdpeudp_established(bro_analyzer(), bro_analyzer()->Conn(), 1);
+ }
+
+ if ( state_ == ESTABLISHED && rdpeudp_data )
+ BifEvent::generate_rdpeudp_data(bro_analyzer(),
+ bro_analyzer()->Conn(),
+ is_orig,
+ 1,
+ bytestring_to_val(data)
+ );
+
+ return true;
+ %}
+
+ function proc_rdpeudp2_ack(is_orig: bool, pkt_type: uint8, data: bytestring): bool
+ %{
+ if ( pkt_type == 8 )
+ // This is a "dummy packet".
+ return false;
+
+ if ( state_ == NEED_ACK )
+ {
+ if ( rdpeudp_established )
+ BifEvent::generate_rdpeudp_established(bro_analyzer(), bro_analyzer()->Conn(), 2);
+
+ state_ = ESTABLISHED;
+ }
+
+ if ( state_ == ESTABLISHED && rdpeudp_data )
+ BifEvent::generate_rdpeudp_data(bro_analyzer(),
+ bro_analyzer()->Conn(),
+ is_orig,
+ 2,
+ bytestring_to_val(data)
+ );
+
+ return true;
+ %}
+};
diff --git a/src/analyzer/protocol/rdp/rdpeudp-protocol.pac b/src/analyzer/protocol/rdp/rdpeudp-protocol.pac
new file mode 100644
index 0000000000..4e3b175330
--- /dev/null
+++ b/src/analyzer/protocol/rdp/rdpeudp-protocol.pac
@@ -0,0 +1,221 @@
+# There are basically 5 PDU types for RDUEUDP1
+# 1. SYN - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeudp/066f9acf-fd57-4f95-ab3f-334e748bab10
+# 2. SYNACK - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeudp/96eaa81a-ff42-40a2-884c-96b3834db6c8
+# 3. ACK (bare) - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeudp/facb0b31-63c6-44f4-aeec-03b5163aedae
+# 4. ACK + FEC - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeudp/7eaacd17-7012-468f-aa00-6e629cb88df8
+# 5. ACK + Source - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeudp/427c5d29-6b08-4cdb-bbdf-a1ed09e76e2d
+# There is basically 1 PDU type for RDPEUDP2. It has a bunch of optional fields indicated by flags.
+
+
+enum RDPEUDP_STATE {
+ NEED_SYN = 0x1,
+ NEED_SYNACK = 0x2,
+ NEED_ACK = 0x3,
+ ESTABLISHED = 0x4,
+};
+
+type RDPEUDP_PDU(is_orig: bool) = record {
+ state: case $context.connection.get_state() of {
+ NEED_SYN -> need_syn: RDPEUDP_SYN(this, is_orig);
+ NEED_SYNACK -> need_synack: RDPEUDP_SYNACK(this, is_orig);
+ NEED_ACK -> need_ack: RDPEUDP_ACK(this, is_orig);
+ default -> established: RDPEUDP_ACK(this, is_orig);
+ };
+} &byteorder=bigendian;
+
+type RDPEUDP_SYN(pdu: RDPEUDP_PDU, is_orig: bool) = record {
+ fec_header: RDPUDP_FEC_HEADER;
+ syndata_payload: RDPUDP_SYNDATA_PAYLOAD;
+# TODO: parse the rest of the SYN pkt fields
+# RDPUDP_CORRELATION_ID_PAYLOAD
+# RDPUDP_SYNEX_PAYLOAD
+} &let {
+ proc_rdpeudp_syn: bool = $context.connection.proc_rdpeudp_syn(is_orig, fec_header.uFlags, fec_header.snSourceAck);
+};
+
+type RDPUDP_SYNDATA_PAYLOAD = record {
+ snInitialSequenceNumber: uint32;
+ uUpStreamMtu: uint16;
+ uDownStreamMtu: uint16;
+};
+
+type RDPEUDP_SYNACK(pdu: RDPEUDP_PDU, is_orig: bool) = record {
+ fec_header: RDPUDP_FEC_HEADER;
+} &let {
+ proc_rdpeudp_synack: bool = $context.connection.proc_rdpeudp_synack(is_orig, fec_header.uFlags);
+};
+
+enum RDPUDP_FLAG {
+ RDPUDP_FLAG_SYN = 0x0001,
+ RDPUDP_FLAG_FIN = 0x0002,
+ RDPUDP_FLAG_ACK = 0x0004,
+ RDPUDP_FLAG_DATA = 0x0008,
+ RDPUDP_FLAG_FEC = 0x0010,
+ RDPUDP_FLAG_CN = 0x0020,
+ RDPUDP_FLAG_CWR = 0x0040,
+ RDPUDP_FLAG_SACK_OPTION = 0x0080,
+ RDPUDP_FLAG_ACK_OF_ACKS = 0x0100,
+ RDPUDP_FLAG_SYNLOSSY = 0x0200,
+ RDPUDP_FLAG_ACKDELAYED = 0x0400,
+ RDPUDP_FLAG_CORRELATION_ID = 0x800,
+ RDPUDP_FLAG_SYNEX = 0x1000
+};
+
+type RDPEUDP_ACK(pdu: RDPEUDP_PDU, is_orig: bool) = record {
+ version: case ($context.connection.is_version2()) of {
+ true -> version2: RDPEUDP2_ACK(pdu, is_orig);
+ false -> version1: RDPEUDP1_ACK(pdu, is_orig);
+ };
+};
+
+type RDPEUDP1_ACK(pdu: RDPEUDP_PDU, is_orig: bool) = record {
+ fec_header: RDPUDP_FEC_HEADER;
+ ack_vec_header: RDPUDP_ACK_VECTOR_HEADER;
+ ack_of_ackvec_header: case fec_header.uFlags & RDPUDP_FLAG_ACK_OF_ACKS of {
+ RDPUDP_FLAG_ACK_OF_ACKS -> some: RDPUDP_ACK_OF_ACKVECTOR_HEADER;
+ default -> no_ack_of_ackvec_header: empty;
+ };
+ # This doesn't handle ACK+FEC packets, which have both RDPUDP_FLAG_DATA and RDPUDP_FLAG_FEC set
+ source_payload_header: case (fec_header.uFlags & RDPUDP_FLAG_DATA) of {
+ RDPUDP_FLAG_DATA -> some_source_payload: RDPUDP_SOURCE_PAYLOAD_HEADER;
+ default -> no_source_payload_header: empty;
+ };
+ data: bytestring &restofdata;
+} &let {
+ proc_rdpeudp1_ack: bool = $context.connection.proc_rdpeudp1_ack(is_orig, data);
+};
+
+type RDPUDP_SOURCE_PAYLOAD_HEADER = record {
+ snCoded: uint32;
+ snSourceStart: uint32;
+};
+
+type RDPUDP_ACK_OF_ACKVECTOR_HEADER = record {
+ snAckOfAcksSeqNum: uint32;
+};
+
+type RDPUDP_FEC_HEADER = record {
+ snSourceAck: uint32;
+ uReceiveWindowSize: uint16;
+ uFlags: uint16;
+};
+
+type RDPUDP_ACK_VECTOR_HEADER = record {
+ uAckVectorSize: uint16;
+ AckVectorElement: uint8[uAckVectorSize];
+ pad: padding align 4;
+};
+
+# version 2
+type RDPEUDP2_ACK(pdu: RDPEUDP_PDU, is_orig: bool) = record {
+ PacketPrefixByte: uint8;
+ header: RDPUDP2_PACKET_HEADER;
+# TODO:
+# ack_payload: case ((header.Flags & ACK) > 0) of {
+# true -> has_ack_p: RDPUDP2_ACK_PAYLOAD;
+# false -> has_no_ack_p: empty;
+# };
+# oversize_payload: case ((header.Flags & 0x040) > OVERHEADSIZE) of {
+# true -> has_oversize: RDPUDP2_OVERSIZE_PAYLOAD;
+# false -> has_no_oversize: empty;
+# };
+# delay_ack_info_payload: case ((header.Flags & DELAYACKINFO) > 0) of {
+# true -> has_ack_info_p: RDPUDP2_DELAYACKINFO_PAYLOAD;
+# false -> has_no_ack_info_p: empty;
+# };
+# ack_of_acks_payload: case ((header.Flags & AOA) > 0) of {
+# true -> has_aoa_p: RDPUDP2_ACKOFACKS_PAYLOAD;
+# false -> has_no_aoa_p: empty;
+# };
+# data_header_payload: case ((header.Flags & DATA) > 0) of {
+# true -> has_data_h: RDPUDP2_DATAHEADER_PAYLOAD;
+# false -> has_no_data_h: empty;
+# };
+# ack_vector_payload: case ((header.Flags & ACKVEC) > 0) of {
+# true -> has_av_p: RDPUDP2_ACKVECTOR_PAYLOAD;
+# false -> has_no_av_p: empty;
+# };
+# data_body_payload: case ((header.Flags & DATA) > 0) of {
+# true -> has_data_p: RDPUDP2_DATABODY_PAYLOAD;
+# false -> has_no_data_p: empty;
+# };
+# data_body_payload: RDPUDP2_DATABODY_PAYLOAD;
+ data: bytestring &restofdata;
+} &let {
+ Reserved: uint8 = PacketPrefixByte & 0x80;
+ Packet_Type_Index: uint8 = PacketPrefixByte & 0x78;
+ Short_Packet_Length: uint8 = PacketPrefixByte & 0x07;
+# proc_rdpeudp2_ack: bool = $context.connection.proc_rdpeudp2_ack(is_orig, Packet_Type_Index, data_body_payload.Data);
+ proc_rdpeudp2_ack: bool = $context.connection.proc_rdpeudp2_ack(is_orig, Packet_Type_Index, data);
+};
+
+type RDPUDP2_PACKET_HEADER = record {
+ everything: uint16;
+} &let {
+ Flags: uint16 = everything & 0xfff0; # The high 12
+ LogWindowSize: uint8 = everything & 0x000f; # The low 4
+};
+
+enum RDPUDP2_PACKET_HEADER_FLAGS {
+ ACK = 0x001,
+ DATA = 0x004,
+ ACKVEC = 0x008,
+ AOA = 0x010,
+ OVERHEADSIZE = 0x040,
+ DELAYACKINFO = 0x100
+};
+
+type RDPUDP2_ACK_PAYLOAD = record {
+ SeqNum: uint16;
+ tmp1: uint32;
+ tmp2: uint8;
+ delayAckTimeAdditions: uint8[numDelayedAcks];
+} &let {
+ receivedTS: uint8 = tmp1 & 0xffffff00;
+ sendAckTimeGap: uint8 = tmp1 & 0xff;
+ numDelayedAcks: uint8 = tmp2 & 0xf0; # top 4 bits
+ delayAckTimeScale: uint8 = tmp2 & 0x0f; # bottom 4 bits
+};
+
+type RDPUDP2_OVERSIZE_PAYLOAD = record{
+ OverheadSize: uint8;
+};
+
+type RDPUDP2_DATABODY_PAYLOAD = record {
+ ChannelSeqNum: uint16;
+ Data: bytestring &restofdata;
+};
+
+type RDPUDP2_ACKVECTOR_PAYLOAD = record {
+ BaseSeqNum: uint16;
+ tmp1: uint8;
+ TimeStamp_or_not: case TimeStampPresent of {
+ 0 -> none: empty;
+ default -> some: RDPUDP2_ACKVECTOR_PAYLOAD_TimeStamp;
+ } &requires(TimeStampPresent);
+ codedAckVector: uint8[codedAckVecSize];
+} &let {
+ codedAckVecSize: uint8 = tmp1 & 0xfe;
+ TimeStampPresent: uint8 = tmp1 & 0x01;
+};
+
+type RDPUDP2_ACKVECTOR_PAYLOAD_TimeStamp = record {
+ tmp1: uint8;
+ tmp2: uint8;
+ tmp3: uint8;
+} &let {
+ TimeStamp: uint32 = tmp3 | (tmp2 << 8) | (tmp1 << 16);
+};
+
+type RDPUDP2_DATAHEADER_PAYLOAD = record {
+ DataSeqNum: uint16;
+};
+
+type RDPUDP2_ACKOFACKS_PAYLOAD = record {
+ AckOfAcksSeqNum: uint16;
+};
+
+type RDPUDP2_DELAYACKINFO_PAYLOAD = record {
+ MaxDelayedAcks: uint8;
+ DelayedAckTimeoutInMs: uint16;
+};
diff --git a/src/analyzer/protocol/rdp/rdpeudp.pac b/src/analyzer/protocol/rdp/rdpeudp.pac
new file mode 100644
index 0000000000..525c3b05ee
--- /dev/null
+++ b/src/analyzer/protocol/rdp/rdpeudp.pac
@@ -0,0 +1,24 @@
+%include binpac.pac
+%include bro.pac
+
+%extern{
+ #include "events.bif.h"
+%}
+
+analyzer RDPEUDP withcontext {
+ connection: RDPEUDP_Conn;
+ flow: RDPEUDP_Flow;
+};
+
+connection RDPEUDP_Conn(bro_analyzer: BroAnalyzer) {
+ upflow = RDPEUDP_Flow(true);
+ downflow = RDPEUDP_Flow(false);
+};
+
+%include rdpeudp-protocol.pac
+
+flow RDPEUDP_Flow(is_orig: bool) {
+ datagram = RDPEUDP_PDU(is_orig) withcontext(connection, this);
+};
+
+%include rdpeudp-analyzer.pac
diff --git a/testing/btest/Baseline/core.print-bpf-filters/output2 b/testing/btest/Baseline/core.print-bpf-filters/output2
index 9f2e8a5002..7869f2a0fb 100644
--- a/testing/btest/Baseline/core.print-bpf-filters/output2
+++ b/testing/btest/Baseline/core.print-bpf-filters/output2
@@ -17,7 +17,7 @@
1 2811
1 3128
1 3306
-1 3389
+2 3389
1 3544
1 4011
2 443
@@ -56,8 +56,8 @@
1 992
1 993
1 995
-63 and
-62 or
-63 port
+64 and
+63 or
+64 port
42 tcp
-21 udp
+22 udp
diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output
index 032c79f025..3bb2f44cec 100644
--- a/testing/btest/Baseline/plugins.hooks/output
+++ b/testing/btest/Baseline/plugins.hooks/output
@@ -38,6 +38,7 @@
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_NTP, 123/udp)) ->
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_RADIUS, 1812/udp)) ->
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_RDP, 3389/tcp)) ->
+0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_RDPEUDP, 3389/udp)) ->
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_SIP, 5060/udp)) ->
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_SMB, 139/tcp)) ->
0.000000 MetaHookPost CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_SMB, 445/tcp)) ->
@@ -103,6 +104,7 @@
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_NTP, 123/udp)) ->
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_RADIUS, 1812/udp)) ->
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_RDP, 3389/tcp)) ->
+0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_RDPEUDP, 3389/udp)) ->
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_SIP, 5060/udp)) ->
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_SMB, 139/tcp)) ->
0.000000 MetaHookPost CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_SMB, 445/tcp)) ->
@@ -146,6 +148,7 @@
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_NTP, {123/udp})) ->
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_RADIUS, {1812/udp})) ->
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_RDP, {3389/tcp})) ->
+0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_RDPEUDP, {3389/udp})) ->
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_SIP, {5060/udp})) ->
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_SMB, {139<...>/tcp})) ->
0.000000 MetaHookPost CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_SMTP, {587<...>/tcp})) ->
@@ -279,7 +282,7 @@
0.000000 MetaHookPost CallFunction(Log::__create_stream, , (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])) ->
0.000000 MetaHookPost CallFunction(Log::__create_stream, , (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])) ->
0.000000 MetaHookPost CallFunction(Log::__create_stream, , (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])) ->
-0.000000 MetaHookPost CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1584045167.489534, node=zeek, filter=ip or not ip, init=T, success=T])) ->
+0.000000 MetaHookPost CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1585876138.391469, node=zeek, filter=ip or not ip, init=T, success=T])) ->
0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Broker::LOG)) ->
0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Cluster::LOG)) ->
0.000000 MetaHookPost CallFunction(Log::add_default_filter, , (Config::LOG)) ->
@@ -460,7 +463,7 @@
0.000000 MetaHookPost CallFunction(Log::create_stream, , (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])) ->
0.000000 MetaHookPost CallFunction(Log::create_stream, , (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])) ->
0.000000 MetaHookPost CallFunction(Log::create_stream, , (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])) ->
-0.000000 MetaHookPost CallFunction(Log::write, , (PacketFilter::LOG, [ts=1584045167.489534, node=zeek, filter=ip or not ip, init=T, success=T])) ->
+0.000000 MetaHookPost CallFunction(Log::write, , (PacketFilter::LOG, [ts=1585876138.391469, node=zeek, filter=ip or not ip, init=T, success=T])) ->
0.000000 MetaHookPost CallFunction(NetControl::check_plugins, , ()) ->
0.000000 MetaHookPost CallFunction(NetControl::init, , ()) ->
0.000000 MetaHookPost CallFunction(Notice::want_pp, , ()) ->
@@ -951,6 +954,7 @@
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_NTP, 123/udp))
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_RADIUS, 1812/udp))
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_RDP, 3389/tcp))
+0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_RDPEUDP, 3389/udp))
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_SIP, 5060/udp))
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_SMB, 139/tcp))
0.000000 MetaHookPre CallFunction(Analyzer::__register_for_port, , (Analyzer::ANALYZER_SMB, 445/tcp))
@@ -1016,6 +1020,7 @@
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_NTP, 123/udp))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_RADIUS, 1812/udp))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_RDP, 3389/tcp))
+0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_RDPEUDP, 3389/udp))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_SIP, 5060/udp))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_SMB, 139/tcp))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_port, , (Analyzer::ANALYZER_SMB, 445/tcp))
@@ -1059,6 +1064,7 @@
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_NTP, {123/udp}))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_RADIUS, {1812/udp}))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_RDP, {3389/tcp}))
+0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_RDPEUDP, {3389/udp}))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_SIP, {5060/udp}))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_SMB, {139<...>/tcp}))
0.000000 MetaHookPre CallFunction(Analyzer::register_for_ports, , (Analyzer::ANALYZER_SMTP, {587<...>/tcp}))
@@ -1192,7 +1198,7 @@
0.000000 MetaHookPre CallFunction(Log::__create_stream, , (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, , (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509]))
0.000000 MetaHookPre CallFunction(Log::__create_stream, , (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql]))
-0.000000 MetaHookPre CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1584045167.489534, node=zeek, filter=ip or not ip, init=T, success=T]))
+0.000000 MetaHookPre CallFunction(Log::__write, , (PacketFilter::LOG, [ts=1585876138.391469, node=zeek, filter=ip or not ip, init=T, success=T]))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Broker::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Cluster::LOG))
0.000000 MetaHookPre CallFunction(Log::add_default_filter, , (Config::LOG))
@@ -1373,7 +1379,7 @@
0.000000 MetaHookPre CallFunction(Log::create_stream, , (Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird]))
0.000000 MetaHookPre CallFunction(Log::create_stream, , (X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509]))
0.000000 MetaHookPre CallFunction(Log::create_stream, , (mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql]))
-0.000000 MetaHookPre CallFunction(Log::write, , (PacketFilter::LOG, [ts=1584045167.489534, node=zeek, filter=ip or not ip, init=T, success=T]))
+0.000000 MetaHookPre CallFunction(Log::write, , (PacketFilter::LOG, [ts=1585876138.391469, node=zeek, filter=ip or not ip, init=T, success=T]))
0.000000 MetaHookPre CallFunction(NetControl::check_plugins, , ())
0.000000 MetaHookPre CallFunction(NetControl::init, , ())
0.000000 MetaHookPre CallFunction(Notice::want_pp, , ())
@@ -1864,6 +1870,7 @@
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_NTP, 123/udp)
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_RADIUS, 1812/udp)
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_RDP, 3389/tcp)
+0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_RDPEUDP, 3389/udp)
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_SIP, 5060/udp)
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_SMB, 139/tcp)
0.000000 | HookCallFunction Analyzer::__register_for_port(Analyzer::ANALYZER_SMB, 445/tcp)
@@ -1929,6 +1936,7 @@
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_NTP, 123/udp)
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_RADIUS, 1812/udp)
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_RDP, 3389/tcp)
+0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_RDPEUDP, 3389/udp)
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_SIP, 5060/udp)
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_SMB, 139/tcp)
0.000000 | HookCallFunction Analyzer::register_for_port(Analyzer::ANALYZER_SMB, 445/tcp)
@@ -1972,6 +1980,7 @@
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_NTP, {123/udp})
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_RADIUS, {1812/udp})
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_RDP, {3389/tcp})
+0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_RDPEUDP, {3389/udp})
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_SIP, {5060/udp})
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_SMB, {139<...>/tcp})
0.000000 | HookCallFunction Analyzer::register_for_ports(Analyzer::ANALYZER_SMTP, {587<...>/tcp})
@@ -2104,7 +2113,7 @@
0.000000 | HookCallFunction Log::__create_stream(Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])
0.000000 | HookCallFunction Log::__create_stream(X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])
0.000000 | HookCallFunction Log::__create_stream(mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])
-0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1584045167.489534, node=zeek, filter=ip or not ip, init=T, success=T])
+0.000000 | HookCallFunction Log::__write(PacketFilter::LOG, [ts=1585876138.391469, node=zeek, filter=ip or not ip, init=T, success=T])
0.000000 | HookCallFunction Log::add_default_filter(Broker::LOG)
0.000000 | HookCallFunction Log::add_default_filter(Cluster::LOG)
0.000000 | HookCallFunction Log::add_default_filter(Config::LOG)
@@ -2285,7 +2294,7 @@
0.000000 | HookCallFunction Log::create_stream(Weird::LOG, [columns=Weird::Info, ev=Weird::log_weird, path=weird])
0.000000 | HookCallFunction Log::create_stream(X509::LOG, [columns=X509::Info, ev=X509::log_x509, path=x509])
0.000000 | HookCallFunction Log::create_stream(mysql::LOG, [columns=MySQL::Info, ev=MySQL::log_mysql, path=mysql])
-0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1584045167.489534, node=zeek, filter=ip or not ip, init=T, success=T])
+0.000000 | HookCallFunction Log::write(PacketFilter::LOG, [ts=1585876138.391469, node=zeek, filter=ip or not ip, init=T, success=T])
0.000000 | HookCallFunction NetControl::check_plugins()
0.000000 | HookCallFunction NetControl::init()
0.000000 | HookCallFunction Notice::want_pp()
@@ -2732,7 +2741,7 @@
0.000000 | HookLoadFile base<...>/xmpp
0.000000 | HookLoadFile base<...>/zeek.bif.zeek
0.000000 | HookLogInit packet_filter 1/1 {ts (time), node (string), filter (string), init (bool), success (bool)}
-0.000000 | HookLogWrite packet_filter [ts=1584045167.489534, node=zeek, filter=ip or not ip, init=T, success=T]
+0.000000 | HookLogWrite packet_filter [ts=1585876138.391469, node=zeek, filter=ip or not ip, init=T, success=T]
0.000000 | HookQueueEvent NetControl::init()
0.000000 | HookQueueEvent filter_change_tracking()
0.000000 | HookQueueEvent zeek_init()
diff --git a/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-fail/conn.log b/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-fail/conn.log
new file mode 100644
index 0000000000..1765803c64
--- /dev/null
+++ b/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-fail/conn.log
@@ -0,0 +1,10 @@
+#separator \x09
+#set_separator ,
+#empty_field (empty)
+#unset_field -
+#path conn
+#open 2020-04-03-01-14-11
+#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents
+#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string]
+1580420028.819704 CHhAvVGS1DHFjwGM9 192.168.38.1 63568 192.168.38.102 3389 udp - 6.226782 3696 0 S0 - - 0 D 3 3780 0 0 -
+#close 2020-04-03-01-14-11
diff --git a/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-fail/out b/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-fail/out
new file mode 100644
index 0000000000..ac74d8ba7c
--- /dev/null
+++ b/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-fail/out
@@ -0,0 +1 @@
+rdpeudp_syn, [orig_h=192.168.38.1, orig_p=63568/udp, resp_h=192.168.38.102, resp_p=3389/udp]
diff --git a/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-success/conn.log b/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-success/conn.log
new file mode 100644
index 0000000000..4e23c22e09
--- /dev/null
+++ b/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-success/conn.log
@@ -0,0 +1,10 @@
+#separator \x09
+#set_separator ,
+#empty_field (empty)
+#unset_field -
+#path conn
+#open 2020-04-03-01-14-12
+#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents
+#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string]
+1564522833.059088 CHhAvVGS1DHFjwGM9 ::1 61291 ::1 3389 udp rdpeudp 0.122551 1738 2655 SF - - 0 Dd 5 1978 5 2895 -
+#close 2020-04-03-01-14-12
diff --git a/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-success/out b/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-success/out
new file mode 100644
index 0000000000..f825baa964
--- /dev/null
+++ b/testing/btest/Baseline/scripts.base.protocols.rdp.rdpeudp-handshake-success/out
@@ -0,0 +1,2 @@
+rdpeudp_syn, [orig_h=::1, orig_p=61291/udp, resp_h=::1, resp_p=3389/udp]
+rdpeudp_synack, [orig_h=::1, orig_p=61291/udp, resp_h=::1, resp_p=3389/udp]
diff --git a/testing/btest/Traces/rdp/rdpeudp-handshake-fail.pcap b/testing/btest/Traces/rdp/rdpeudp-handshake-fail.pcap
new file mode 100644
index 0000000000..253367ac54
Binary files /dev/null and b/testing/btest/Traces/rdp/rdpeudp-handshake-fail.pcap differ
diff --git a/testing/btest/Traces/rdp/rdpeudp-handshake-success.pcap b/testing/btest/Traces/rdp/rdpeudp-handshake-success.pcap
new file mode 100644
index 0000000000..b6a984f1f5
Binary files /dev/null and b/testing/btest/Traces/rdp/rdpeudp-handshake-success.pcap differ
diff --git a/testing/btest/scripts/base/protocols/rdp/rdpeudp-handshake-fail.zeek b/testing/btest/scripts/base/protocols/rdp/rdpeudp-handshake-fail.zeek
new file mode 100644
index 0000000000..39c355e849
--- /dev/null
+++ b/testing/btest/scripts/base/protocols/rdp/rdpeudp-handshake-fail.zeek
@@ -0,0 +1,25 @@
+# @TEST-EXEC: zeek -r $TRACES/rdp/rdpeudp-handshake-fail.pcap %INPUT >out
+# @TEST-EXEC: btest-diff conn.log
+# @TEST-EXEC: btest-diff out
+
+@load base/protocols/rdp
+
+event rdpeudp_syn(c: connection)
+ {
+ print "rdpeudp_syn", c$id;
+ }
+
+event rdpeudp_synack(c: connection)
+ {
+ print "rdpeudp_synack", c$id;
+ }
+
+event rdpeudp_established(c: connection, version: count)
+ {
+ print "rdpeudp_established", c$id, version;
+ }
+
+event rdpeudp_data(c: connection, is_orig: bool, version: count, data: string)
+ {
+ print fmt("rdpeudp_data is_orig: %s, version %d, data: %s", is_orig, version, data);
+ }
diff --git a/testing/btest/scripts/base/protocols/rdp/rdpeudp-handshake-success.zeek b/testing/btest/scripts/base/protocols/rdp/rdpeudp-handshake-success.zeek
new file mode 100644
index 0000000000..1ab87bd5bc
--- /dev/null
+++ b/testing/btest/scripts/base/protocols/rdp/rdpeudp-handshake-success.zeek
@@ -0,0 +1,25 @@
+# @TEST-EXEC: zeek -r $TRACES/rdp/rdpeudp-handshake-success.pcap %INPUT >out
+# @TEST-EXEC: btest-diff conn.log
+# @TEST-EXEC: btest-diff out
+
+@load base/protocols/rdp
+
+event rdpeudp_syn(c: connection)
+ {
+ print "rdpeudp_syn", c$id;
+ }
+
+event rdpeudp_synack(c: connection)
+ {
+ print "rdpeudp_synack", c$id;
+ }
+
+event rdpeudp_established(c: connection, version: count)
+ {
+ print "rdpeudp_established", c$id, version;
+ }
+
+event rdpeudp_data(c: connection, is_orig: bool, version: count, data: string)
+ {
+ print fmt("rdpeudp_data is_orig: %s, version %d, data: %s", is_orig, version, data);
+ }