srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_arp.cpp
blob: 247782b84da12443074ea35eb3fdfbe0536e0f35 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <doctest/doctest.h>

#include <vector>

#include "packeteer/net/arp.hpp"

using namespace packeteer::net;

namespace {

std::vector<unsigned char> arp_request() {
    return {
        0x00, 0x01,                          // hardware type = Ethernet
        0x08, 0x00,                          // protocol type = IPv4
        0x06,                                // hardware len = 6
        0x04,                                // protocol len = 4
        0x00, 0x01,                          // opcode = request
        0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x01,  // sender MAC
        10, 0, 0, 1,                          // sender IP
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // target MAC (unknown, all zero)
        10, 0, 0, 2,                          // target IP
    };
}

std::vector<unsigned char> arp_reply() {
    return {
        0x00, 0x01,
        0x08, 0x00,
        0x06,
        0x04,
        0x00, 0x02,                          // opcode = reply
        0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x02,  // sender MAC (the one who was asked)
        10, 0, 0, 2,                          // sender IP
        0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x01,  // target MAC (the original requester)
        10, 0, 0, 1,                          // target IP
    };
}

}  // namespace

TEST_CASE("parse_arp decodes a request with Ethernet/IPv4 addressing") {
    auto arp = parse_arp(arp_request());
    REQUIRE(arp.has_value());
    CHECK(arp->header.opcode == kArpOpRequest);
    REQUIRE(arp->sender_ip.has_value());
    REQUIRE(arp->sender_mac.has_value());
    REQUIRE(arp->target_ip.has_value());
    CHECK(arp->sender_ip->bytes == std::array<unsigned char, 4>{10, 0, 0, 1});
    CHECK(arp->target_ip->bytes == std::array<unsigned char, 4>{10, 0, 0, 2});
    CHECK(arp->sender_mac->bytes == std::array<unsigned char, 6>{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x01});
}

TEST_CASE("parse_arp decodes a reply") {
    auto arp = parse_arp(arp_reply());
    REQUIRE(arp.has_value());
    CHECK(arp->header.opcode == kArpOpReply);
    REQUIRE(arp->sender_ip.has_value());
    CHECK(arp->sender_ip->bytes == std::array<unsigned char, 4>{10, 0, 0, 2});
}

TEST_CASE("parse_arp rejects a truncated header") {
    std::vector<unsigned char> bytes(5, 0);
    CHECK_FALSE(parse_arp(bytes).has_value());
}

TEST_CASE("parse_arp decodes the header but skips addresses for non-Ethernet/IPv4") {
    std::vector<unsigned char> bytes = {
        0x00, 0x06,  // hardware type = IEEE 802 (arbitrary, just not the common case)
        0x08, 0x00,
        0x08,  // hardware len = 8, not 6
        0x04,
        0x00, 0x01,
    };
    auto arp = parse_arp(bytes);
    REQUIRE(arp.has_value());
    CHECK(arp->header.hardware_len == 8);
    CHECK_FALSE(arp->sender_ip.has_value());
    CHECK_FALSE(arp->sender_mac.has_value());
}

TEST_CASE("parse_arp treats a header claiming Ethernet/IPv4 but too short to hold it as header-only") {
    std::vector<unsigned char> bytes = {
        0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01,
        0xaa, 0xbb, 0xcc,  // truncated sender MAC
    };
    auto arp = parse_arp(bytes);
    REQUIRE(arp.has_value());
    CHECK_FALSE(arp->sender_ip.has_value());
}