| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <vector> |
| |
| #include <gtest/gtest.h> |
| |
| #include "smbprovider/netbios_packet_parser.h" |
| #include "smbprovider/smbprovider_test_helper.h" |
| |
| namespace smbprovider { |
| namespace { |
| |
| constexpr int kNonFileServerNodeType = 0x00; |
| |
| const std::vector<uint8_t> CreateName(const std::string& name) { |
| return std::vector<uint8_t>(name.begin(), name.end()); |
| } |
| |
| } // namespace |
| |
| class NetBiosPacketParserTest : public testing::Test { |
| public: |
| NetBiosPacketParserTest() = default; |
| NetBiosPacketParserTest(const NetBiosPacketParserTest&) = delete; |
| NetBiosPacketParserTest& operator=(const NetBiosPacketParserTest&) = delete; |
| |
| ~NetBiosPacketParserTest() override = default; |
| |
| protected: |
| const uint16_t transaction_id_ = 123; |
| }; |
| |
| // An empty packet returns no results. |
| TEST_F(NetBiosPacketParserTest, EmptyPacketReturnsNoResults) { |
| const std::vector<uint8_t> packet; |
| |
| const std::vector<std::string> results = |
| netbios::ParsePacket(packet, transaction_id_); |
| |
| EXPECT_TRUE(results.empty()); |
| } |
| |
| // A well-formed packet with no hostnames returns no results. |
| TEST_F(NetBiosPacketParserTest, NoHostnamesReturnsNoResults) { |
| const std::vector<uint8_t> name = CreateName("testname"); |
| const std::vector<std::vector<uint8_t>> hostnames; |
| |
| const std::vector<uint8_t> packet = CreateNetBiosResponsePacket( |
| hostnames, name, transaction_id_, 0x20 /* positive response */); |
| |
| const std::vector<std::string> results = |
| netbios::ParsePacket(packet, transaction_id_); |
| |
| EXPECT_TRUE(results.empty()); |
| } |
| |
| // A well-formed packet with one hostname parses successfully. |
| TEST_F(NetBiosPacketParserTest, OneHostnameSucceeds) { |
| const std::vector<uint8_t> name = CreateName("testname"); |
| const std::string hostname_1 = "hostname1"; |
| const std::vector<std::vector<uint8_t>> hostnames = { |
| CreateValidNetBiosHostname(hostname_1, netbios::kFileServerNodeType)}; |
| |
| const std::vector<uint8_t> packet = CreateNetBiosResponsePacket( |
| hostnames, name, transaction_id_, 0x20 /* positive response */); |
| |
| const std::vector<std::string> results = |
| netbios::ParsePacket(packet, transaction_id_); |
| |
| EXPECT_EQ(1, results.size()); |
| EXPECT_EQ(hostname_1, results[0]); |
| } |
| |
| // A well-formed packet with two hostnames parses successfully. |
| TEST_F(NetBiosPacketParserTest, TwoHostnamesSucceeds) { |
| const std::vector<uint8_t> name = CreateName("testname"); |
| const std::string hostname_1 = "hostname1"; |
| const std::string hostname_2 = "hostname2"; |
| const std::vector<std::vector<uint8_t>> hostnames = { |
| CreateValidNetBiosHostname(hostname_1, netbios::kFileServerNodeType), |
| CreateValidNetBiosHostname(hostname_2, netbios::kFileServerNodeType)}; |
| |
| const std::vector<uint8_t> packet = CreateNetBiosResponsePacket( |
| hostnames, name, transaction_id_, 0x20 /* positive response */); |
| |
| const std::vector<std::string> results = |
| netbios::ParsePacket(packet, transaction_id_); |
| |
| EXPECT_EQ(2, results.size()); |
| EXPECT_EQ(hostname_1, results[0]); |
| EXPECT_EQ(hostname_2, results[1]); |
| } |
| |
| // The parser does not return non-FileServer hostnames. |
| TEST_F(NetBiosPacketParserTest, NonShareDoesntReturn) { |
| const std::vector<uint8_t> name = CreateName("testname"); |
| const std::string hostname_1 = "hostname1"; |
| const std::string hostname_2 = "hostname2"; |
| const std::vector<std::vector<uint8_t>> hostnames = { |
| CreateValidNetBiosHostname(hostname_1, kNonFileServerNodeType), |
| CreateValidNetBiosHostname(hostname_2, netbios::kFileServerNodeType)}; |
| |
| const std::vector<uint8_t> packet = CreateNetBiosResponsePacket( |
| hostnames, name, transaction_id_, 0x20 /* positive response */); |
| |
| const std::vector<std::string> results = |
| netbios::ParsePacket(packet, transaction_id_); |
| |
| EXPECT_EQ(1, results.size()); |
| EXPECT_EQ(hostname_2, results[0]); |
| } |
| |
| // A well-formed negative response returns no results. |
| TEST_F(NetBiosPacketParserTest, NegativeResponseFails) { |
| const std::vector<uint8_t> name = CreateName("testname"); |
| const std::string hostname_1 = "hostname1"; |
| const std::vector<std::vector<uint8_t>> hostnames = { |
| CreateValidNetBiosHostname(hostname_1, netbios::kFileServerNodeType)}; |
| |
| const std::vector<uint8_t> packet = CreateNetBiosResponsePacket( |
| hostnames, name, transaction_id_, 0x00 /* negative response */); |
| |
| const std::vector<std::string> results = |
| netbios::ParsePacket(packet, transaction_id_); |
| |
| EXPECT_TRUE(results.empty()); |
| } |
| |
| // A mal-formed packet with a name that is too long returns no results. |
| TEST_F(NetBiosPacketParserTest, NameTooLongFails) { |
| const std::vector<uint8_t> name = CreateName("testname"); |
| const uint8_t name_length(150); |
| const std::string hostname_1 = "hostname1"; |
| const std::vector<std::vector<uint8_t>> hostnames = { |
| CreateValidNetBiosHostname(hostname_1, netbios::kFileServerNodeType)}; |
| |
| const std::vector<uint8_t> packet = |
| CreateNetBiosResponsePacket(hostnames, name_length, name, transaction_id_, |
| 0x20 /* positive response */); |
| |
| const std::vector<std::string> results = |
| netbios::ParsePacket(packet, transaction_id_); |
| |
| EXPECT_TRUE(results.empty()); |
| } |
| |
| // A mal-formed packet with incorrectly formed hostnames returns no results. |
| TEST_F(NetBiosPacketParserTest, MalformedHostnamesFails) { |
| const std::vector<uint8_t> name = CreateName("testname"); |
| const std::string bad_hostname = "tooooooolonggggghostnameeee"; |
| const std::vector<std::vector<uint8_t>> hostnames = { |
| std::vector<uint8_t>(bad_hostname.begin(), bad_hostname.end())}; |
| |
| const std::vector<uint8_t> packet = CreateNetBiosResponsePacket( |
| hostnames, name, transaction_id_, 0x20 /* positive response */); |
| |
| const std::vector<std::string> results = |
| netbios::ParsePacket(packet, transaction_id_); |
| |
| EXPECT_TRUE(results.empty()); |
| } |
| |
| // A well-formed packet with the transaction id that does not correspond to the |
| // broadcast returns no results. |
| TEST_F(NetBiosPacketParserTest, TestName) { |
| const std::vector<uint8_t> name = CreateName("testname"); |
| const std::string hostname_1 = "hostname1"; |
| const std::vector<std::vector<uint8_t>> hostnames = { |
| CreateValidNetBiosHostname(hostname_1, netbios::kFileServerNodeType)}; |
| |
| const std::vector<uint8_t> packet = CreateNetBiosResponsePacket( |
| hostnames, name, transaction_id_, 0x20 /* positive response */); |
| |
| const std::vector<std::string> results = |
| netbios::ParsePacket(packet, transaction_id_ + 1); |
| |
| EXPECT_TRUE(results.empty()); |
| } |
| |
| // A positive response with the NBSTAT signal (0x21) instead of NB (0x20) |
| // returns a result correctly. |
| TEST_F(NetBiosPacketParserTest, AlternatePositiveResponseSucceeds) { |
| const std::vector<uint8_t> name = CreateName("testname"); |
| const std::string hostname_1 = "hostname1"; |
| const std::vector<std::vector<uint8_t>> hostnames = { |
| CreateValidNetBiosHostname(hostname_1, netbios::kFileServerNodeType)}; |
| |
| const std::vector<uint8_t> packet = CreateNetBiosResponsePacket( |
| hostnames, name, transaction_id_, 0x21 /* positive response */); |
| |
| const std::vector<std::string> results = |
| netbios::ParsePacket(packet, transaction_id_); |
| |
| EXPECT_EQ(1, results.size()); |
| EXPECT_EQ(hostname_1, results[0]); |
| } |
| |
| } // namespace smbprovider |