/src/PcapPlusPlus/Packet++/src/IcmpV6Layer.cpp
Line | Count | Source |
1 | | #define LOG_MODULE PacketLogModuleIcmpV6Layer |
2 | | |
3 | | #include "IcmpV6Layer.h" |
4 | | #include "EndianPortable.h" |
5 | | #include "IPv4Layer.h" |
6 | | #include "IPv6Layer.h" |
7 | | #include "NdpLayer.h" |
8 | | #include "PacketUtils.h" |
9 | | #include "PayloadLayer.h" |
10 | | #include <sstream> |
11 | | |
12 | | // IcmpV6Layer |
13 | | |
14 | | namespace pcpp |
15 | | { |
16 | | |
17 | | Layer* IcmpV6Layer::parseIcmpV6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
18 | 0 | { |
19 | 0 | if (dataLen < sizeof(icmpv6hdr)) |
20 | 0 | return new PayloadLayer(data, dataLen, prevLayer, packet); |
21 | | |
22 | 0 | icmpv6hdr* hdr = (icmpv6hdr*)data; |
23 | 0 | ICMPv6MessageType messageType = static_cast<ICMPv6MessageType>(hdr->type); |
24 | |
|
25 | 0 | switch (messageType) |
26 | 0 | { |
27 | 0 | case ICMPv6MessageType::ICMPv6_ECHO_REQUEST: |
28 | 0 | case ICMPv6MessageType::ICMPv6_ECHO_REPLY: |
29 | 0 | return new ICMPv6EchoLayer(data, dataLen, prevLayer, packet); |
30 | 0 | case ICMPv6MessageType::ICMPv6_NEIGHBOR_SOLICITATION: |
31 | 0 | return new NDPNeighborSolicitationLayer(data, dataLen, prevLayer, packet); |
32 | 0 | case ICMPv6MessageType::ICMPv6_NEIGHBOR_ADVERTISEMENT: |
33 | 0 | return new NDPNeighborAdvertisementLayer(data, dataLen, prevLayer, packet); |
34 | 0 | case ICMPv6MessageType::ICMPv6_UNKNOWN_MESSAGE: |
35 | 0 | return new PayloadLayer(data, dataLen, prevLayer, packet); |
36 | 0 | default: |
37 | 0 | return new IcmpV6Layer(data, dataLen, prevLayer, packet); |
38 | 0 | } |
39 | 0 | } |
40 | | |
41 | | IcmpV6Layer::IcmpV6Layer(ICMPv6MessageType msgType, uint8_t code, const uint8_t* data, size_t dataLen) |
42 | 0 | { |
43 | 0 | m_DataLen = sizeof(icmpv6hdr) + dataLen; |
44 | 0 | m_Data = new uint8_t[m_DataLen]; |
45 | 0 | memset(m_Data, 0, m_DataLen); |
46 | 0 | m_Protocol = ICMPv6; |
47 | |
|
48 | 0 | icmpv6hdr* hdr = (icmpv6hdr*)m_Data; |
49 | 0 | hdr->type = static_cast<uint8_t>(msgType); |
50 | 0 | hdr->code = code; |
51 | |
|
52 | 0 | if (data != nullptr && dataLen > 0) |
53 | 0 | memcpy(m_Data + sizeof(icmpv6hdr), data, dataLen); |
54 | 0 | } |
55 | | |
56 | | ICMPv6MessageType IcmpV6Layer::getMessageType() const |
57 | 0 | { |
58 | 0 | return static_cast<ICMPv6MessageType>(getIcmpv6Header()->type); |
59 | 0 | } |
60 | | |
61 | | uint8_t IcmpV6Layer::getCode() const |
62 | 0 | { |
63 | 0 | return getIcmpv6Header()->code; |
64 | 0 | } |
65 | | |
66 | | uint16_t IcmpV6Layer::getChecksum() const |
67 | 0 | { |
68 | 0 | return be16toh(getIcmpv6Header()->checksum); |
69 | 0 | } |
70 | | |
71 | | void IcmpV6Layer::computeCalculateFields() |
72 | 0 | { |
73 | 0 | calculateChecksum(); |
74 | 0 | } |
75 | | |
76 | | void IcmpV6Layer::calculateChecksum() |
77 | 0 | { |
78 | | // Pseudo header of 40 bytes which is composed as follows(in order): |
79 | | // - 16 bytes for the source address |
80 | | // - 16 bytes for the destination address |
81 | | // - 4 bytes big endian payload length(the same value as in the IPv6 header) |
82 | | // - 3 bytes zero + 1 byte nextheader( 58 decimal) big endian |
83 | |
|
84 | 0 | getIcmpv6Header()->checksum = 0; |
85 | |
|
86 | 0 | if (m_PrevLayer != nullptr) |
87 | 0 | { |
88 | 0 | ScalarBuffer<uint16_t> vec[2]; |
89 | |
|
90 | 0 | vec[0].buffer = (uint16_t*)m_Data; |
91 | 0 | vec[0].len = m_DataLen; |
92 | |
|
93 | 0 | const unsigned int pseudoHeaderLen = 40; |
94 | 0 | const unsigned int bigEndianLen = htobe32(m_DataLen); |
95 | 0 | const unsigned int bigEndianNextHeader = htobe32(PACKETPP_IPPROTO_ICMPV6); |
96 | |
|
97 | 0 | uint16_t pseudoHeader[pseudoHeaderLen / 2]; |
98 | 0 | ((IPv6Layer*)m_PrevLayer)->getSrcIPv6Address().copyTo((uint8_t*)pseudoHeader); |
99 | 0 | ((IPv6Layer*)m_PrevLayer)->getDstIPv6Address().copyTo((uint8_t*)(pseudoHeader + 8)); |
100 | 0 | memcpy(&pseudoHeader[16], &bigEndianLen, sizeof(uint32_t)); |
101 | 0 | memcpy(&pseudoHeader[18], &bigEndianNextHeader, sizeof(uint32_t)); |
102 | 0 | vec[1].buffer = pseudoHeader; |
103 | 0 | vec[1].len = pseudoHeaderLen; |
104 | | |
105 | | // Calculate and write checksum |
106 | 0 | getIcmpv6Header()->checksum = htobe16(computeChecksum(vec, 2)); |
107 | 0 | } |
108 | 0 | } |
109 | | |
110 | | std::string IcmpV6Layer::toString() const |
111 | 0 | { |
112 | 0 | std::ostringstream typeStream; |
113 | 0 | typeStream << (int)getMessageType(); |
114 | 0 | return "ICMPv6 Layer, Message type: " + typeStream.str(); |
115 | 0 | } |
116 | | |
117 | | // |
118 | | // ICMPv6EchoLayer |
119 | | // |
120 | | |
121 | | ICMPv6EchoLayer::ICMPv6EchoLayer(ICMPv6EchoType echoType, uint16_t id, uint16_t sequence, const uint8_t* data, |
122 | | size_t dataLen) |
123 | 0 | { |
124 | 0 | m_DataLen = sizeof(icmpv6_echo_hdr) + dataLen; |
125 | 0 | m_Data = new uint8_t[m_DataLen]; |
126 | 0 | memset(m_Data, 0, m_DataLen); |
127 | 0 | m_Protocol = ICMPv6; |
128 | |
|
129 | 0 | icmpv6_echo_hdr* header = getEchoHeader(); |
130 | |
|
131 | 0 | switch (echoType) |
132 | 0 | { |
133 | 0 | case REPLY: |
134 | 0 | header->type = static_cast<uint8_t>(ICMPv6MessageType::ICMPv6_ECHO_REPLY); |
135 | 0 | break; |
136 | 0 | case REQUEST: |
137 | 0 | default: |
138 | 0 | header->type = static_cast<uint8_t>(ICMPv6MessageType::ICMPv6_ECHO_REQUEST); |
139 | 0 | break; |
140 | 0 | } |
141 | | |
142 | 0 | header->code = 0; |
143 | 0 | header->checksum = 0; |
144 | 0 | header->id = htobe16(id); |
145 | 0 | header->sequence = htobe16(sequence); |
146 | |
|
147 | 0 | if (data != nullptr && dataLen > 0) |
148 | 0 | memcpy(getEchoDataPtr(), data, dataLen); |
149 | 0 | } |
150 | | |
151 | | uint16_t ICMPv6EchoLayer::getIdentifier() const |
152 | 0 | { |
153 | 0 | return be16toh(getEchoHeader()->id); |
154 | 0 | } |
155 | | |
156 | | uint16_t ICMPv6EchoLayer::getSequenceNr() const |
157 | 0 | { |
158 | 0 | return be16toh(getEchoHeader()->sequence); |
159 | 0 | } |
160 | | |
161 | | std::string ICMPv6EchoLayer::toString() const |
162 | 0 | { |
163 | 0 | std::ostringstream typeStream; |
164 | 0 | typeStream << (int)getMessageType(); |
165 | 0 | return "ICMPv6 Layer, Echo Request/Reply Message (type: " + typeStream.str() + ")"; |
166 | 0 | } |
167 | | |
168 | | } // namespace pcpp |