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