/src/PcapPlusPlus/Packet++/src/DhcpV6Layer.cpp
Line | Count | Source |
1 | 0 | #define LOG_MODULE PacketLogModuleDhcpV6Layer |
2 | | |
3 | | #include "DhcpV6Layer.h" |
4 | | #include "Logger.h" |
5 | | #include "GeneralUtils.h" |
6 | | #include "EndianPortable.h" |
7 | | |
8 | | namespace pcpp |
9 | | { |
10 | | |
11 | | DhcpV6OptionType DhcpV6Option::getType() const |
12 | 10.5k | { |
13 | 10.5k | if (m_Data == nullptr) |
14 | 0 | return DhcpV6OptionType::DHCPV6_OPT_UNKNOWN; |
15 | | |
16 | 10.5k | uint16_t optionType = be16toh(m_Data->recordType); |
17 | 10.5k | if (optionType <= 62 && optionType != 10 && optionType != 35 && optionType != 57 && optionType != 58) |
18 | 6.78k | { |
19 | 6.78k | return static_cast<DhcpV6OptionType>(optionType); |
20 | 6.78k | } |
21 | 3.71k | if (optionType == 65 || optionType == 66 || optionType == 68 || optionType == 79 || optionType == 112) |
22 | 1.14k | { |
23 | 1.14k | return static_cast<DhcpV6OptionType>(optionType); |
24 | 1.14k | } |
25 | | |
26 | 2.57k | return DHCPV6_OPT_UNKNOWN; |
27 | 3.71k | } |
28 | | |
29 | | std::string DhcpV6Option::getValueAsHexString() const |
30 | 3.54k | { |
31 | 3.54k | if (m_Data == nullptr) |
32 | 0 | return ""; |
33 | | |
34 | 3.54k | return byteArrayToHexString(m_Data->recordValue, getDataSize()); |
35 | 3.54k | } |
36 | | |
37 | | size_t DhcpV6Option::getTotalSize() const |
38 | 116k | { |
39 | 116k | if (m_Data == nullptr) |
40 | 0 | return 0; |
41 | | |
42 | 116k | return 2 * sizeof(uint16_t) + be16toh(m_Data->recordLen); |
43 | 116k | } |
44 | | |
45 | | size_t DhcpV6Option::getDataSize() const |
46 | 3.54k | { |
47 | 3.54k | if (m_Data == nullptr) |
48 | 0 | return 0; |
49 | | |
50 | 3.54k | return static_cast<size_t>(be16toh(m_Data->recordLen)); |
51 | 3.54k | } |
52 | | |
53 | | DhcpV6Option DhcpV6OptionBuilder::build() const |
54 | 0 | { |
55 | 0 | if (m_RecType == 0) |
56 | 0 | return DhcpV6Option(nullptr); |
57 | | |
58 | 0 | size_t optionSize = 2 * sizeof(uint16_t) + m_RecValueLen; |
59 | 0 | uint8_t* recordBuffer = new uint8_t[optionSize]; |
60 | 0 | uint16_t optionTypeVal = htobe16(static_cast<uint16_t>(m_RecType)); |
61 | 0 | uint16_t optionLength = htobe16(static_cast<uint16_t>(m_RecValueLen)); |
62 | 0 | memcpy(recordBuffer, &optionTypeVal, sizeof(uint16_t)); |
63 | 0 | memcpy(recordBuffer + sizeof(uint16_t), &optionLength, sizeof(uint16_t)); |
64 | 0 | if (optionSize > 0 && m_RecValue != nullptr) |
65 | 0 | memcpy(recordBuffer + 2 * sizeof(uint16_t), m_RecValue, m_RecValueLen); |
66 | |
|
67 | 0 | return DhcpV6Option(recordBuffer); |
68 | 0 | } |
69 | | |
70 | | DhcpV6Layer::DhcpV6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
71 | 18.9k | : Layer(data, dataLen, prevLayer, packet, DHCPv6) |
72 | 18.9k | {} |
73 | | |
74 | | DhcpV6Layer::DhcpV6Layer(DhcpV6MessageType messageType, uint32_t transactionId) |
75 | 0 | { |
76 | 0 | allocData(sizeof(dhcpv6_header)); |
77 | 0 | m_Protocol = DHCPv6; |
78 | |
|
79 | 0 | setMessageType(messageType); |
80 | 0 | setTransactionID(transactionId); |
81 | 0 | } |
82 | | |
83 | | DhcpV6MessageType DhcpV6Layer::getMessageType() const |
84 | 7.33k | { |
85 | 7.33k | uint8_t messageType = getDhcpHeader()->messageType; |
86 | 7.33k | if (messageType > 13) |
87 | 858 | { |
88 | 858 | return DHCPV6_UNKNOWN_MSG_TYPE; |
89 | 858 | } |
90 | | |
91 | 6.47k | return static_cast<DhcpV6MessageType>(messageType); |
92 | 7.33k | } |
93 | | |
94 | | std::string DhcpV6Layer::getMessageTypeAsString() const |
95 | 7.33k | { |
96 | 7.33k | DhcpV6MessageType messageType = getMessageType(); |
97 | 7.33k | switch (messageType) |
98 | 7.33k | { |
99 | 32 | case DHCPV6_SOLICIT: |
100 | 32 | return "Solicit"; |
101 | 0 | case DHCPV6_ADVERTISE: |
102 | 0 | return "Advertise"; |
103 | 74 | case DHCPV6_REQUEST: |
104 | 74 | return "Request"; |
105 | 0 | case DHCPV6_CONFIRM: |
106 | 0 | return "Confirm"; |
107 | 224 | case DHCPV6_RENEW: |
108 | 224 | return "Renew"; |
109 | 32 | case DHCPV6_REBIND: |
110 | 32 | return "Rebind"; |
111 | 1.02k | case DHCPV6_REPLY: |
112 | 1.02k | return "Reply"; |
113 | 0 | case DHCPV6_RELEASE: |
114 | 0 | return "Release"; |
115 | 0 | case DHCPV6_DECLINE: |
116 | 0 | return "Decline"; |
117 | 858 | case DHCPV6_RECONFIGURE: |
118 | 858 | return "Reconfigure"; |
119 | 3.27k | case DHCPV6_INFORMATION_REQUEST: |
120 | 3.27k | return "Information-Request"; |
121 | 0 | case DHCPV6_RELAY_FORWARD: |
122 | 0 | return "Relay-Forward"; |
123 | 32 | case DHCPV6_RELAY_REPLY: |
124 | 32 | return "Relay-Reply"; |
125 | 1.77k | default: |
126 | 1.77k | return "Unknown"; |
127 | 7.33k | } |
128 | 7.33k | } |
129 | | |
130 | | void DhcpV6Layer::setMessageType(DhcpV6MessageType messageType) |
131 | 0 | { |
132 | 0 | getDhcpHeader()->messageType = static_cast<uint8_t>(messageType); |
133 | 0 | } |
134 | | |
135 | | uint32_t DhcpV6Layer::getTransactionID() const |
136 | 3.66k | { |
137 | 3.66k | dhcpv6_header* hdr = getDhcpHeader(); |
138 | 3.66k | uint32_t result = hdr->transactionId1 << 16 | hdr->transactionId2 << 8 | hdr->transactionId3; |
139 | 3.66k | return result; |
140 | 3.66k | } |
141 | | |
142 | | void DhcpV6Layer::setTransactionID(uint32_t transactionId) const |
143 | 0 | { |
144 | 0 | dhcpv6_header* hdr = getDhcpHeader(); |
145 | 0 | hdr->transactionId1 = (transactionId >> 16) & 0xff; |
146 | 0 | hdr->transactionId2 = (transactionId >> 8) & 0xff; |
147 | 0 | hdr->transactionId3 = transactionId & 0xff; |
148 | 0 | } |
149 | | |
150 | | DhcpV6Option DhcpV6Layer::getFirstOptionData() const |
151 | 3.54k | { |
152 | 3.54k | return m_OptionReader.getFirstTLVRecord(getOptionsBasePtr(), getHeaderLen() - sizeof(dhcpv6_header)); |
153 | 3.54k | } |
154 | | |
155 | | DhcpV6Option DhcpV6Layer::getNextOptionData(DhcpV6Option dhcpv6Option) const |
156 | 8.21k | { |
157 | 8.21k | return m_OptionReader.getNextTLVRecord(dhcpv6Option, getOptionsBasePtr(), |
158 | 8.21k | getHeaderLen() - sizeof(dhcpv6_header)); |
159 | 8.21k | } |
160 | | |
161 | | DhcpV6Option DhcpV6Layer::getOptionData(DhcpV6OptionType option) const |
162 | 3.54k | { |
163 | 3.54k | return m_OptionReader.getTLVRecord(static_cast<uint32_t>(option), getOptionsBasePtr(), |
164 | 3.54k | getHeaderLen() - sizeof(dhcpv6_header)); |
165 | 3.54k | } |
166 | | |
167 | | size_t DhcpV6Layer::getOptionCount() const |
168 | 15.4k | { |
169 | 15.4k | return m_OptionReader.getTLVRecordCount(getOptionsBasePtr(), getHeaderLen() - sizeof(dhcpv6_header)); |
170 | 15.4k | } |
171 | | |
172 | | DhcpV6Option DhcpV6Layer::addOptionAt(const DhcpV6OptionBuilder& optionBuilder, int offset) |
173 | 0 | { |
174 | 0 | DhcpV6Option newOpt = optionBuilder.build(); |
175 | 0 | if (newOpt.isNull()) |
176 | 0 | { |
177 | 0 | PCPP_LOG_ERROR("Cannot build new option"); |
178 | 0 | return DhcpV6Option(nullptr); |
179 | 0 | } |
180 | | |
181 | 0 | size_t sizeToExtend = newOpt.getTotalSize(); |
182 | |
|
183 | 0 | if (!extendLayer(offset, sizeToExtend)) |
184 | 0 | { |
185 | 0 | PCPP_LOG_ERROR("Could not extend DhcpLayer in [" << newOpt.getTotalSize() << "] bytes"); |
186 | 0 | newOpt.purgeRecordData(); |
187 | 0 | return DhcpV6Option(nullptr); |
188 | 0 | } |
189 | | |
190 | 0 | memcpy(m_Data + offset, newOpt.getRecordBasePtr(), newOpt.getTotalSize()); |
191 | |
|
192 | 0 | uint8_t* newOptPtr = m_Data + offset; |
193 | |
|
194 | 0 | m_OptionReader.changeTLVRecordCount(1); |
195 | |
|
196 | 0 | newOpt.purgeRecordData(); |
197 | |
|
198 | 0 | return DhcpV6Option(newOptPtr); |
199 | 0 | } |
200 | | |
201 | | DhcpV6Option DhcpV6Layer::addOption(const DhcpV6OptionBuilder& optionBuilder) |
202 | 0 | { |
203 | 0 | return addOptionAt(optionBuilder, getHeaderLen()); |
204 | 0 | } |
205 | | |
206 | | DhcpV6Option DhcpV6Layer::addOptionAfter(const DhcpV6OptionBuilder& optionBuilder, DhcpV6OptionType optionType) |
207 | 0 | { |
208 | 0 | int offset = 0; |
209 | |
|
210 | 0 | DhcpV6Option prevOpt = getOptionData(optionType); |
211 | |
|
212 | 0 | if (prevOpt.isNull()) |
213 | 0 | { |
214 | 0 | PCPP_LOG_ERROR("Option type " << optionType << " doesn't exist in layer"); |
215 | 0 | return DhcpV6Option(nullptr); |
216 | 0 | } |
217 | 0 | offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data; |
218 | 0 | return addOptionAt(optionBuilder, offset); |
219 | 0 | } |
220 | | |
221 | | DhcpV6Option DhcpV6Layer::addOptionBefore(const DhcpV6OptionBuilder& optionBuilder, DhcpV6OptionType optionType) |
222 | 0 | { |
223 | 0 | int offset = 0; |
224 | |
|
225 | 0 | DhcpV6Option nextOpt = getOptionData(optionType); |
226 | |
|
227 | 0 | if (nextOpt.isNull()) |
228 | 0 | { |
229 | 0 | PCPP_LOG_ERROR("Option type " << optionType << " doesn't exist in layer"); |
230 | 0 | return DhcpV6Option(nullptr); |
231 | 0 | } |
232 | | |
233 | 0 | offset = nextOpt.getRecordBasePtr() - m_Data; |
234 | 0 | return addOptionAt(optionBuilder, offset); |
235 | 0 | } |
236 | | |
237 | | bool DhcpV6Layer::removeOption(DhcpV6OptionType optionType) |
238 | 0 | { |
239 | 0 | DhcpV6Option optToRemove = getOptionData(optionType); |
240 | 0 | if (optToRemove.isNull()) |
241 | 0 | { |
242 | 0 | return false; |
243 | 0 | } |
244 | | |
245 | 0 | int offset = optToRemove.getRecordBasePtr() - m_Data; |
246 | |
|
247 | 0 | if (!shortenLayer(offset, optToRemove.getTotalSize())) |
248 | 0 | { |
249 | 0 | return false; |
250 | 0 | } |
251 | | |
252 | 0 | m_OptionReader.changeTLVRecordCount(-1); |
253 | 0 | return true; |
254 | 0 | } |
255 | | |
256 | | bool DhcpV6Layer::removeAllOptions() |
257 | 0 | { |
258 | 0 | int offset = sizeof(dhcpv6_header); |
259 | |
|
260 | 0 | if (!shortenLayer(offset, getHeaderLen() - offset)) |
261 | 0 | return false; |
262 | | |
263 | 0 | m_OptionReader.changeTLVRecordCount(0 - getOptionCount()); |
264 | 0 | return true; |
265 | 0 | } |
266 | | |
267 | | std::string DhcpV6Layer::toString() const |
268 | 7.33k | { |
269 | 7.33k | return "DHCPv6 Layer, " + getMessageTypeAsString() + " message"; |
270 | 7.33k | } |
271 | | |
272 | | } // namespace pcpp |