diff --git a/src/TunnelEncapsulation.cc b/src/TunnelEncapsulation.cc index 3bd503a85a..8fd1041ff6 100644 --- a/src/TunnelEncapsulation.cc +++ b/src/TunnelEncapsulation.cc @@ -3,6 +3,7 @@ #include "zeek/TunnelEncapsulation.h" #include "zeek/Conn.h" +#include "zeek/Reporter.h" #include "zeek/util.h" namespace zeek @@ -56,4 +57,15 @@ bool operator==(const EncapsulationStack& e1, const EncapsulationStack& e2) return true; } +void EncapsulationStack::Pop() + { + if ( Depth() == 0 ) + { + reporter->InternalWarning("Attempted to pop from empty EncapsulationStack\n"); + return; + } + + conns->pop_back(); + } + } // namespace zeek diff --git a/src/TunnelEncapsulation.h b/src/TunnelEncapsulation.h index 88258e297f..2702131441 100644 --- a/src/TunnelEncapsulation.h +++ b/src/TunnelEncapsulation.h @@ -249,6 +249,11 @@ public: return nullptr; } + /** + * Pops the last element off the encapsulation stack. + */ + void Pop(); + protected: std::vector* conns; }; diff --git a/src/packet_analysis/protocol/ieee802_11/IEEE802_11.cc b/src/packet_analysis/protocol/ieee802_11/IEEE802_11.cc index c0969ee2e0..e7e80a2545 100644 --- a/src/packet_analysis/protocol/ieee802_11/IEEE802_11.cc +++ b/src/packet_analysis/protocol/ieee802_11/IEEE802_11.cc @@ -17,6 +17,7 @@ bool IEEE802_11Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* } u_char fc_80211 = data[0]; // Frame Control field + bool is_amsdu = false; // Skip non-data frame types (management & control). if ( ! ((fc_80211 >> 2) & 0x02) ) @@ -33,9 +34,9 @@ bool IEEE802_11Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* // Look for the QoS indicator bit. if ( (fc_80211 >> 4) & 0x08 ) { - // Skip in case of A-MSDU subframes indicated by QoS control field. - if ( data[len_80211] & 0x80 ) - return false; + // Store off whether this is an A-MSDU header, which indicates that there are + // mulitple packets following the 802.11 header. + is_amsdu = (data[len_80211] & 0x80) == 0x80; // Check for the protected bit. This means the data is encrypted and we can't // do anything with it. @@ -75,13 +76,78 @@ bool IEEE802_11Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* break; } - // skip 802.11 data header + // skip the 802.11 data header data += len_80211; + len -= len_80211; - len_80211 += 8; - if ( len_80211 >= len ) + if ( ! is_amsdu ) { - Weird("truncated_802_11_header", packet); + return HandleInnerPacket(len, data, packet); + } + else + { + size_t amsdu_padding = 0; + size_t encap_index = packet->encap ? packet->encap->Depth() : 0; + + while ( len > 0 ) + { + if ( len < 14 ) + { + Weird("truncated_802_11_amsdu_header", packet); + return false; + } + + // This is the length of everything after the A-MSDU subframe header. + size_t amsdu_len = (data[12] << 8) + data[13]; + if ( len < amsdu_len ) + { + Weird("truncated_802_11_amsdu_packet", packet); + return false; + } + + // Skip the A-MSDU subframe header. This should place us at the start of an LLC header. + data += 14; + len -= 14; + + if ( ! HandleInnerPacket(amsdu_len, data, packet) ) + { + Weird("invalid_802_11_amsdu_inner_packet", packet); + return false; + } + + data += amsdu_len; + len -= amsdu_len; + + // Each A-MSDU subframe is padded by up to 3 bytes to make a multiple of 4. This padding + // isn't included in the length field value. The padding also doesn't happen with the + // last subframe, so check to see that we can even subtract it. Unfortunately, there + // isn't a frame counter in the header so we just have trust that it all works out. + amsdu_padding = amsdu_len % 4; + if ( len >= amsdu_padding ) + { + data += amsdu_padding; + len -= amsdu_padding; + } + + // Pop encapsuations back up to the level where we started processing so that the next + // subframe gets the same encapsulation stack. + if ( packet->encap ) + { + while ( packet->encap->Depth() > encap_index ) + packet->encap->Pop(); + } + } + + return true; + } + } + +bool IEEE802_11Analyzer::HandleInnerPacket(size_t len, const uint8_t* data, Packet* packet) const + { + // Make sure there's room for an LLC header. + if ( len < 8 ) + { + Weird("truncated_802_11_llc_header", packet); return false; } @@ -92,6 +158,7 @@ bool IEEE802_11Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* data[5] == 0 ) { data += 6; + len -= 6; } else { @@ -100,11 +167,13 @@ bool IEEE802_11Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* return false; } + // Get the protocol and skip the rest of the LLC header. uint32_t protocol = (data[0] << 8) + data[1]; data += 2; + len -= 2; if ( packet->tunnel_type == BifEnum::Tunnel::NONE ) - return ForwardPacket(len - len_80211, data, packet, protocol); + return ForwardPacket(len, data, packet, protocol); else { // For tunneled packets, reset the packet's protocol based on the one in the LLC header. @@ -114,6 +183,6 @@ bool IEEE802_11Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* else if ( protocol == 0x86DD ) packet->proto = IPPROTO_IPV6; - return ForwardPacket(len - len_80211, data, packet, packet->proto); + return ForwardPacket(len, data, packet, packet->proto); } } diff --git a/src/packet_analysis/protocol/ieee802_11/IEEE802_11.h b/src/packet_analysis/protocol/ieee802_11/IEEE802_11.h index 282c76bbaf..23307c3d27 100644 --- a/src/packet_analysis/protocol/ieee802_11/IEEE802_11.h +++ b/src/packet_analysis/protocol/ieee802_11/IEEE802_11.h @@ -20,6 +20,9 @@ public: { return std::make_shared(); } + +private: + bool HandleInnerPacket(size_t len, const uint8_t* data, Packet* packet) const; }; } diff --git a/testing/btest/Baseline/core.tunnels.gre-aruba-amsdu/conn.log b/testing/btest/Baseline/core.tunnels.gre-aruba-amsdu/conn.log new file mode 100644 index 0000000000..66e2c52380 --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre-aruba-amsdu/conn.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path conn +#open XXXX-XX-XX-XX-XX-XX +#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] +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 157.240.18.16 443 149.159.130.184 49392 tcp - - - - OTH F F 0 D 2 356 0 0 CHhAvVGS1DHFjwGM9 +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/core.tunnels.gre-aruba-amsdu/tunnel.log b/testing/btest/Baseline/core.tunnels.gre-aruba-amsdu/tunnel.log new file mode 100644 index 0000000000..a1529d17cf --- /dev/null +++ b/testing/btest/Baseline/core.tunnels.gre-aruba-amsdu/tunnel.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path tunnel +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p tunnel_type action +#types time string addr port addr port enum enum +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.226.22.9 0 10.102.16.187 0 Tunnel::GRE Tunnel::DISCOVER +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/tunnels/gre-aruba-amsdu.pcap b/testing/btest/Traces/tunnels/gre-aruba-amsdu.pcap new file mode 100644 index 0000000000..064d87bcc8 Binary files /dev/null and b/testing/btest/Traces/tunnels/gre-aruba-amsdu.pcap differ diff --git a/testing/btest/core/tunnels/gre-aruba-amsdu.zeek b/testing/btest/core/tunnels/gre-aruba-amsdu.zeek new file mode 100644 index 0000000000..975c96a871 --- /dev/null +++ b/testing/btest/core/tunnels/gre-aruba-amsdu.zeek @@ -0,0 +1,7 @@ +# @TEST-DOC: Tests a GRE ARUBA trace that contains IEEE 802.11 QoS A-MSDU headers. This is testing that the tunnel is detected and that the conn byte size contains both A-MSDU subframe packets. +# @TEST-EXEC: zeek -C -b -r $TRACES/tunnels/gre-aruba-amsdu.pcap %INPUT +# @TEST-EXEC: btest-diff tunnel.log +# @TEST-EXEC: btest-diff conn.log + +@load base/protocols/conn +@load base/frameworks/tunnels