/src/PcapPlusPlus/Packet++/src/TcpLayer.cpp
Line | Count | Source |
1 | 0 | #define LOG_MODULE PacketLogModuleTcpLayer |
2 | | |
3 | | #include "EndianPortable.h" |
4 | | #include "TcpLayer.h" |
5 | | #include "IPv4Layer.h" |
6 | | #include "IPv6Layer.h" |
7 | | #include "PayloadLayer.h" |
8 | | #include "HttpLayer.h" |
9 | | #include "SSLLayer.h" |
10 | | #include "SipLayer.h" |
11 | | #include "BgpLayer.h" |
12 | | #include "SSHLayer.h" |
13 | | #include "DnsLayer.h" |
14 | | #include "DoIpLayer.h" |
15 | | #include "TelnetLayer.h" |
16 | | #include "TpktLayer.h" |
17 | | #include "FtpLayer.h" |
18 | | #include "SomeIpLayer.h" |
19 | | #include "SmtpLayer.h" |
20 | | #include "LdapLayer.h" |
21 | | #include "PostgresLayer.h" |
22 | | #include "MySqlLayer.h" |
23 | | #include "GtpLayer.h" |
24 | | #include "ModbusLayer.h" |
25 | | #include "PacketUtils.h" |
26 | | #include "Logger.h" |
27 | | #include "DeprecationUtils.h" |
28 | | #include "SystemUtils.h" |
29 | | #include <sstream> |
30 | | |
31 | | namespace pcpp |
32 | | { |
33 | | constexpr uint8_t TcpOptionDummy = 0xff; |
34 | | |
35 | | static constexpr const char* tcpOptionTypeToString(TcpOptionEnumType type) |
36 | 0 | { |
37 | 0 | switch (type) |
38 | 0 | { |
39 | 0 | case TcpOptionEnumType::Eol: |
40 | 0 | return "Eol"; |
41 | 0 | case TcpOptionEnumType::Nop: |
42 | 0 | return "Nop"; |
43 | 0 | case TcpOptionEnumType::Mss: |
44 | 0 | return "Mss"; |
45 | 0 | case TcpOptionEnumType::Window: |
46 | 0 | return "Window"; |
47 | 0 | case TcpOptionEnumType::SackPerm: |
48 | 0 | return "SackPerm"; |
49 | 0 | case TcpOptionEnumType::Sack: |
50 | 0 | return "Sack"; |
51 | 0 | case TcpOptionEnumType::Echo: |
52 | 0 | return "Echo"; |
53 | 0 | case TcpOptionEnumType::EchoReply: |
54 | 0 | return "EchoReply"; |
55 | 0 | case TcpOptionEnumType::Timestamp: |
56 | 0 | return "Timestamp"; |
57 | 0 | case TcpOptionEnumType::Cc: |
58 | 0 | return "Cc"; |
59 | 0 | case TcpOptionEnumType::CcNew: |
60 | 0 | return "CcNew"; |
61 | 0 | case TcpOptionEnumType::CcEcho: |
62 | 0 | return "CcEcho"; |
63 | 0 | case TcpOptionEnumType::Md5: |
64 | 0 | return "Md5"; |
65 | 0 | case TcpOptionEnumType::MpTcp: |
66 | 0 | return "MpTcp"; |
67 | 0 | case TcpOptionEnumType::Scps: |
68 | 0 | return "Scps"; |
69 | 0 | case TcpOptionEnumType::Snack: |
70 | 0 | return "Snack"; |
71 | 0 | case TcpOptionEnumType::RecBound: |
72 | 0 | return "RecBound"; |
73 | 0 | case TcpOptionEnumType::CorrExp: |
74 | 0 | return "CorrExp"; |
75 | 0 | case TcpOptionEnumType::Qs: |
76 | 0 | return "Qs"; |
77 | 0 | case TcpOptionEnumType::UserTo: |
78 | 0 | return "UserTo"; |
79 | 0 | case TcpOptionEnumType::ExpFd: |
80 | 0 | return "ExpFd"; |
81 | 0 | case TcpOptionEnumType::ExpFe: |
82 | 0 | return "ExpFe"; |
83 | 0 | case TcpOptionEnumType::RvbdProbe: |
84 | 0 | return "RvbdProbe"; |
85 | 0 | case TcpOptionEnumType::RvbdTrpy: |
86 | 0 | return "RvbdTrpy"; |
87 | 0 | case TcpOptionEnumType::Unknown: |
88 | 0 | default: |
89 | 0 | return "Unknown"; |
90 | 0 | } |
91 | 0 | } |
92 | | |
93 | | /// ~~~~~~~~~~~~~~~~ |
94 | | /// TcpOptionBuilder |
95 | | /// ~~~~~~~~~~~~~~~~ |
96 | | |
97 | | TcpOptionBuilder::TcpOptionBuilder(NopEolOptionTypes optionType) |
98 | 0 | { |
99 | 0 | switch (optionType) |
100 | 0 | { |
101 | 0 | case EOL: |
102 | 0 | init(static_cast<uint8_t>(PCPP_TCPOPT_EOL), nullptr, 0); |
103 | 0 | break; |
104 | 0 | case NOP: |
105 | 0 | default: |
106 | 0 | init(static_cast<uint8_t>(PCPP_TCPOPT_NOP), nullptr, 0); |
107 | 0 | break; |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | TcpOptionBuilder::TcpOptionBuilder(const NopEolOptionEnumType optionType) |
112 | 0 | { |
113 | 0 | switch (optionType) |
114 | 0 | { |
115 | 0 | case NopEolOptionEnumType::Eol: |
116 | 0 | init(static_cast<uint8_t>(TcpOptionEnumType::Eol), nullptr, 0); |
117 | 0 | break; |
118 | 0 | case NopEolOptionEnumType::Nop: |
119 | 0 | default: |
120 | 0 | init(static_cast<uint8_t>(TcpOptionEnumType::Nop), nullptr, 0); |
121 | 0 | break; |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | | TcpOption TcpOptionBuilder::build() const |
126 | 0 | { |
127 | 0 | uint8_t recType = static_cast<uint8_t>(m_RecType); |
128 | 0 | size_t optionSize = m_RecValueLen + 2 * sizeof(uint8_t); |
129 | |
|
130 | 0 | if (recType == static_cast<uint8_t>(TcpOptionEnumType::Eol) || |
131 | 0 | recType == static_cast<uint8_t>(TcpOptionEnumType::Nop)) |
132 | 0 | { |
133 | 0 | if (m_RecValueLen != 0) |
134 | 0 | { |
135 | 0 | PCPP_LOG_ERROR( |
136 | 0 | "TCP NOP and TCP EOL options are 1-byte long and don't have option value. Tried to set option value of size " |
137 | 0 | << m_RecValueLen); |
138 | 0 | return TcpOption(nullptr); |
139 | 0 | } |
140 | | |
141 | 0 | optionSize = 1; |
142 | 0 | } |
143 | | |
144 | 0 | uint8_t* recordBuffer = new uint8_t[optionSize]; |
145 | 0 | memset(recordBuffer, 0, optionSize); |
146 | 0 | recordBuffer[0] = recType; |
147 | 0 | if (optionSize > 1) |
148 | 0 | { |
149 | 0 | recordBuffer[1] = static_cast<uint8_t>(optionSize); |
150 | 0 | if (optionSize > 2 && m_RecValue != nullptr) |
151 | 0 | memcpy(recordBuffer + 2, m_RecValue, m_RecValueLen); |
152 | 0 | } |
153 | |
|
154 | 0 | return TcpOption(recordBuffer); |
155 | 0 | } |
156 | | |
157 | | /// ~~~~~~~~ |
158 | | /// TcpLayer |
159 | | /// ~~~~~~~~ |
160 | | |
161 | | uint16_t TcpLayer::getSrcPort() const |
162 | 0 | { |
163 | 0 | return be16toh(getTcpHeader()->portSrc); |
164 | 0 | } |
165 | | |
166 | | uint16_t TcpLayer::getDstPort() const |
167 | 0 | { |
168 | 0 | return be16toh(getTcpHeader()->portDst); |
169 | 0 | } |
170 | | |
171 | | TcpOption TcpLayer::getTcpOption(const TcpOptionEnumType option) const |
172 | 0 | { |
173 | 0 | return m_OptionReader.getTLVRecord(static_cast<uint8_t>(option), getOptionsBasePtr(), |
174 | 0 | getHeaderLen() - sizeof(tcphdr)); |
175 | 0 | } |
176 | | |
177 | | TcpOption TcpLayer::getFirstTcpOption() const |
178 | 0 | { |
179 | 0 | return m_OptionReader.getFirstTLVRecord(getOptionsBasePtr(), getHeaderLen() - sizeof(tcphdr)); |
180 | 0 | } |
181 | | |
182 | | TcpOption TcpLayer::getNextTcpOption(TcpOption& tcpOption) const |
183 | 0 | { |
184 | 0 | TcpOption nextOpt = |
185 | 0 | m_OptionReader.getNextTLVRecord(tcpOption, getOptionsBasePtr(), getHeaderLen() - sizeof(tcphdr)); |
186 | 0 | if (nextOpt.isNotNull() && nextOpt.getType() == TcpOptionDummy) |
187 | 0 | return TcpOption(nullptr); |
188 | | |
189 | 0 | return nextOpt; |
190 | 0 | } |
191 | | |
192 | | size_t TcpLayer::getTcpOptionCount() const |
193 | 0 | { |
194 | 0 | return m_OptionReader.getTLVRecordCount(getOptionsBasePtr(), getHeaderLen() - sizeof(tcphdr)); |
195 | 0 | } |
196 | | |
197 | | TcpOption TcpLayer::addTcpOption(const TcpOptionBuilder& optionBuilder) |
198 | 0 | { |
199 | 0 | return addTcpOptionAt(optionBuilder, getHeaderLen() - m_NumOfTrailingBytes); |
200 | 0 | } |
201 | | |
202 | | TcpOption TcpLayer::insertTcpOptionAfter(const TcpOptionBuilder& optionBuilder, |
203 | | const TcpOptionEnumType prevOptionType) |
204 | 0 | { |
205 | 0 | int offset = 0; |
206 | |
|
207 | 0 | if (prevOptionType == TcpOptionEnumType::Unknown) |
208 | 0 | { |
209 | 0 | offset = sizeof(tcphdr); |
210 | 0 | } |
211 | 0 | else |
212 | 0 | { |
213 | 0 | const TcpOption prevOpt = getTcpOption(prevOptionType); |
214 | 0 | if (prevOpt.isNull()) |
215 | 0 | { |
216 | 0 | PCPP_LOG_ERROR("Previous option of type " << static_cast<int>(prevOptionType) |
217 | 0 | << " not found, cannot add a new TCP option"); |
218 | 0 | return TcpOption(nullptr); |
219 | 0 | } |
220 | | |
221 | 0 | offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data; |
222 | 0 | } |
223 | | |
224 | 0 | return addTcpOptionAt(optionBuilder, offset); |
225 | 0 | } |
226 | | |
227 | | bool TcpLayer::removeTcpOption(const TcpOptionEnumType optionType) |
228 | 0 | { |
229 | 0 | const TcpOption opt = getTcpOption(optionType); |
230 | 0 | if (opt.isNull()) |
231 | 0 | { |
232 | 0 | return false; |
233 | 0 | } |
234 | | |
235 | | // calculate total TCP option size |
236 | 0 | TcpOption curOpt = getFirstTcpOption(); |
237 | 0 | size_t totalOptSize = 0; |
238 | 0 | while (!curOpt.isNull()) |
239 | 0 | { |
240 | 0 | totalOptSize += curOpt.getTotalSize(); |
241 | 0 | curOpt = getNextTcpOption(curOpt); |
242 | 0 | } |
243 | 0 | totalOptSize -= opt.getTotalSize(); |
244 | |
|
245 | 0 | int offset = opt.getRecordBasePtr() - m_Data; |
246 | |
|
247 | 0 | if (!shortenLayer(offset, opt.getTotalSize())) |
248 | 0 | { |
249 | 0 | return false; |
250 | 0 | } |
251 | | |
252 | 0 | adjustTcpOptionTrailer(totalOptSize); |
253 | |
|
254 | 0 | m_OptionReader.changeTLVRecordCount(-1); |
255 | |
|
256 | 0 | return true; |
257 | 0 | } |
258 | | |
259 | | bool TcpLayer::removeAllTcpOptions() |
260 | 0 | { |
261 | 0 | const int offset = sizeof(tcphdr); |
262 | |
|
263 | 0 | if (!shortenLayer(offset, getHeaderLen() - offset)) |
264 | 0 | return false; |
265 | | |
266 | 0 | getTcpHeader()->dataOffset = sizeof(tcphdr) / 4; |
267 | 0 | m_NumOfTrailingBytes = 0; |
268 | 0 | m_OptionReader.changeTLVRecordCount(0 - getTcpOptionCount()); |
269 | 0 | return true; |
270 | 0 | } |
271 | | |
272 | | TcpOption TcpLayer::addTcpOptionAt(const TcpOptionBuilder& optionBuilder, const int offset) |
273 | 0 | { |
274 | 0 | TcpOption newOption = optionBuilder.build(); |
275 | 0 | if (newOption.isNull()) |
276 | 0 | return newOption; |
277 | | |
278 | | // calculate total TCP option size |
279 | 0 | TcpOption curOpt = getFirstTcpOption(); |
280 | 0 | size_t totalOptSize = 0; |
281 | 0 | while (!curOpt.isNull()) |
282 | 0 | { |
283 | 0 | totalOptSize += curOpt.getTotalSize(); |
284 | 0 | curOpt = getNextTcpOption(curOpt); |
285 | 0 | } |
286 | 0 | totalOptSize += newOption.getTotalSize(); |
287 | |
|
288 | 0 | size_t sizeToExtend = newOption.getTotalSize(); |
289 | |
|
290 | 0 | if (!extendLayer(offset, sizeToExtend)) |
291 | 0 | { |
292 | 0 | PCPP_LOG_ERROR("Could not extend TcpLayer in [" << sizeToExtend << "] bytes"); |
293 | 0 | newOption.purgeRecordData(); |
294 | 0 | return TcpOption(nullptr); |
295 | 0 | } |
296 | | |
297 | 0 | memcpy(m_Data + offset, newOption.getRecordBasePtr(), newOption.getTotalSize()); |
298 | |
|
299 | 0 | newOption.purgeRecordData(); |
300 | |
|
301 | 0 | adjustTcpOptionTrailer(totalOptSize); |
302 | |
|
303 | 0 | m_OptionReader.changeTLVRecordCount(1); |
304 | |
|
305 | 0 | uint8_t* newOptPtr = m_Data + offset; |
306 | |
|
307 | 0 | return TcpOption(newOptPtr); |
308 | 0 | } |
309 | | |
310 | | void TcpLayer::adjustTcpOptionTrailer(const size_t totalOptSize) |
311 | 0 | { |
312 | 0 | int newNumberOfTrailingBytes = 0; |
313 | 0 | while ((totalOptSize + newNumberOfTrailingBytes) % 4 != 0) |
314 | 0 | newNumberOfTrailingBytes++; |
315 | |
|
316 | 0 | if (newNumberOfTrailingBytes < m_NumOfTrailingBytes) |
317 | 0 | shortenLayer(sizeof(tcphdr) + totalOptSize, m_NumOfTrailingBytes - newNumberOfTrailingBytes - 1); |
318 | 0 | else if (newNumberOfTrailingBytes > m_NumOfTrailingBytes) |
319 | 0 | extendLayer(sizeof(tcphdr) + totalOptSize, newNumberOfTrailingBytes - m_NumOfTrailingBytes); |
320 | |
|
321 | 0 | m_NumOfTrailingBytes = newNumberOfTrailingBytes; |
322 | |
|
323 | 0 | for (int i = 0; i < m_NumOfTrailingBytes; i++) |
324 | 0 | m_Data[sizeof(tcphdr) + totalOptSize + i] = TcpOptionDummy; |
325 | |
|
326 | 0 | getTcpHeader()->dataOffset = (sizeof(tcphdr) + totalOptSize + m_NumOfTrailingBytes) / 4; |
327 | 0 | } |
328 | | |
329 | | uint16_t TcpLayer::calculateChecksum(const bool writeResultToPacket) |
330 | 0 | { |
331 | 0 | tcphdr* tcpHdr = getTcpHeader(); |
332 | 0 | uint16_t checksumRes = 0; |
333 | 0 | const uint16_t currChecksumValue = tcpHdr->headerChecksum; |
334 | |
|
335 | 0 | if (m_PrevLayer != nullptr) |
336 | 0 | { |
337 | 0 | tcpHdr->headerChecksum = 0; |
338 | 0 | PCPP_LOG_DEBUG("TCP data len = " << m_DataLen); |
339 | |
|
340 | 0 | if (m_PrevLayer->getProtocol() == IPv4) |
341 | 0 | { |
342 | 0 | const IPv4Address srcIP = static_cast<IPv4Layer*>(m_PrevLayer)->getSrcIPv4Address(); |
343 | 0 | const IPv4Address dstIP = static_cast<IPv4Layer*>(m_PrevLayer)->getDstIPv4Address(); |
344 | |
|
345 | 0 | checksumRes = |
346 | 0 | pcpp::computePseudoHdrChecksum(reinterpret_cast<uint8_t*>(tcpHdr), getDataLen(), |
347 | 0 | IPAddress::IPv4AddressType, PACKETPP_IPPROTO_TCP, srcIP, dstIP); |
348 | |
|
349 | 0 | PCPP_LOG_DEBUG("calculated IPv4 TCP checksum = 0x" << std::uppercase << std::hex << checksumRes); |
350 | 0 | } |
351 | 0 | else if (m_PrevLayer->getProtocol() == IPv6) |
352 | 0 | { |
353 | 0 | const IPv6Address srcIP = static_cast<IPv6Layer*>(m_PrevLayer)->getSrcIPv6Address(); |
354 | 0 | const IPv6Address dstIP = static_cast<IPv6Layer*>(m_PrevLayer)->getDstIPv6Address(); |
355 | |
|
356 | 0 | checksumRes = computePseudoHdrChecksum(reinterpret_cast<uint8_t*>(tcpHdr), getDataLen(), |
357 | 0 | IPAddress::IPv6AddressType, PACKETPP_IPPROTO_TCP, srcIP, dstIP); |
358 | |
|
359 | 0 | PCPP_LOG_DEBUG("calculated IPv6 TCP checksum = 0xX" << std::uppercase << std::hex << checksumRes); |
360 | 0 | } |
361 | 0 | } |
362 | |
|
363 | 0 | if (writeResultToPacket) |
364 | 0 | tcpHdr->headerChecksum = htobe16(checksumRes); |
365 | 0 | else |
366 | 0 | tcpHdr->headerChecksum = currChecksumValue; |
367 | |
|
368 | 0 | return checksumRes; |
369 | 0 | } |
370 | | |
371 | | void TcpLayer::initLayer() |
372 | 0 | { |
373 | 0 | allocData(sizeof(tcphdr)); |
374 | |
|
375 | 0 | m_Protocol = TCP; |
376 | 0 | m_NumOfTrailingBytes = 0; |
377 | 0 | getTcpHeader()->dataOffset = sizeof(tcphdr) / 4; |
378 | 0 | } |
379 | | |
380 | | TcpLayer::TcpLayer(uint8_t* data, const size_t dataLen, Layer* prevLayer, Packet* packet) |
381 | 0 | : Layer(data, dataLen, prevLayer, packet, TCP) |
382 | 0 | { |
383 | 0 | m_NumOfTrailingBytes = 0; |
384 | 0 | } |
385 | | |
386 | | TcpLayer::TcpLayer() |
387 | 0 | { |
388 | 0 | initLayer(); |
389 | 0 | } |
390 | | |
391 | | TcpLayer::TcpLayer(const uint16_t portSrc, const uint16_t portDst) |
392 | 0 | { |
393 | 0 | initLayer(); |
394 | 0 | getTcpHeader()->portDst = htobe16(portDst); |
395 | 0 | getTcpHeader()->portSrc = htobe16(portSrc); |
396 | 0 | } |
397 | | |
398 | | void TcpLayer::copyLayerData(const TcpLayer& other) |
399 | 0 | { |
400 | 0 | m_OptionReader = other.m_OptionReader; |
401 | 0 | m_NumOfTrailingBytes = other.m_NumOfTrailingBytes; |
402 | 0 | } |
403 | | |
404 | 0 | TcpLayer::TcpLayer(const TcpLayer& other) : Layer(other) |
405 | 0 | { |
406 | 0 | copyLayerData(other); |
407 | 0 | } |
408 | | |
409 | | TcpLayer& TcpLayer::operator=(const TcpLayer& other) |
410 | 0 | { |
411 | 0 | Layer::operator=(other); |
412 | |
|
413 | 0 | copyLayerData(other); |
414 | |
|
415 | 0 | return *this; |
416 | 0 | } |
417 | | |
418 | | void TcpLayer::parseNextLayer() |
419 | 0 | { |
420 | 0 | const size_t headerLen = getHeaderLen(); |
421 | 0 | if (m_DataLen <= headerLen) |
422 | 0 | return; |
423 | | |
424 | 0 | uint8_t* payload = m_Data + headerLen; |
425 | 0 | const size_t payloadLen = m_DataLen - headerLen; |
426 | 0 | const uint16_t portDst = getDstPort(); |
427 | 0 | const uint16_t portSrc = getSrcPort(); |
428 | 0 | const char* payloadChar = reinterpret_cast<const char*>(payload); |
429 | |
|
430 | 0 | if (HttpMessage::isHttpPort(portDst) && |
431 | 0 | HttpRequestFirstLine::parseMethod(payloadChar, payloadLen) != HttpRequestLayer::HttpMethodUnknown) |
432 | 0 | { |
433 | 0 | constructNextLayer<HttpRequestLayer>(payload, payloadLen, getAttachedPacket()); |
434 | 0 | } |
435 | 0 | else if (HttpMessage::isHttpPort(portSrc) && |
436 | 0 | HttpResponseFirstLine::parseVersion(payloadChar, payloadLen) != HttpVersion::HttpVersionUnknown && |
437 | 0 | !HttpResponseFirstLine::parseStatusCode(payloadChar, payloadLen).isUnsupportedCode()) |
438 | 0 | { |
439 | 0 | constructNextLayer<HttpResponseLayer>(payload, payloadLen, getAttachedPacket()); |
440 | 0 | } |
441 | 0 | else if (SSLLayer::IsSSLMessage(portSrc, portDst, payload, payloadLen)) |
442 | 0 | { |
443 | 0 | constructNextLayerFromFactory(SSLLayer::createSSLMessage, payload, payloadLen); |
444 | 0 | } |
445 | 0 | else if (SipLayer::isSipPort(portDst) || SipLayer::isSipPort(portSrc)) |
446 | 0 | { |
447 | 0 | if (SipRequestFirstLine::parseMethod(payloadChar, payloadLen) != SipRequestLayer::SipMethodUnknown) |
448 | 0 | { |
449 | 0 | constructNextLayer<SipRequestLayer>(payload, payloadLen, getAttachedPacket()); |
450 | 0 | } |
451 | 0 | else if (SipResponseFirstLine::parseStatusCode(payloadChar, payloadLen) != |
452 | 0 | SipResponseLayer::SipStatusCodeUnknown) |
453 | 0 | { |
454 | 0 | constructNextLayer<SipResponseLayer>(payload, payloadLen, getAttachedPacket()); |
455 | 0 | } |
456 | 0 | else |
457 | 0 | { |
458 | 0 | constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket()); |
459 | 0 | } |
460 | 0 | } |
461 | 0 | else if (BgpLayer::isBgpPort(portSrc, portDst)) |
462 | 0 | { |
463 | 0 | tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(BgpLayer::parseBgpLayer, payload, payloadLen); |
464 | 0 | } |
465 | 0 | else if (SSHLayer::isSSHPort(portSrc, portDst)) |
466 | 0 | { |
467 | 0 | constructNextLayerFromFactory(SSHLayer::createSSHMessage, payload, payloadLen); |
468 | 0 | } |
469 | 0 | else if (DnsLayer::isDataValid(payload, payloadLen, true) && |
470 | 0 | (DnsLayer::isDnsPort(portDst) || DnsLayer::isDnsPort(portSrc))) |
471 | 0 | { |
472 | 0 | constructNextLayer<DnsOverTcpLayer>(payload, payloadLen, getAttachedPacket()); |
473 | 0 | } |
474 | 0 | else if (TelnetLayer::isDataValid(payload, payloadLen) && |
475 | 0 | (TelnetLayer::isTelnetPort(portDst) || TelnetLayer::isTelnetPort(portSrc))) |
476 | 0 | { |
477 | 0 | constructNextLayer<TelnetLayer>(payload, payloadLen, getAttachedPacket()); |
478 | 0 | } |
479 | 0 | else if (FtpLayer::isFtpPort(portSrc) && FtpLayer::isDataValid(payload, payloadLen)) |
480 | 0 | { |
481 | 0 | constructNextLayer<FtpResponseLayer>(payload, payloadLen, getAttachedPacket()); |
482 | 0 | } |
483 | 0 | else if (FtpLayer::isFtpPort(portDst) && FtpLayer::isDataValid(payload, payloadLen)) |
484 | 0 | { |
485 | 0 | constructNextLayer<FtpRequestLayer>(payload, payloadLen, getAttachedPacket()); |
486 | 0 | } |
487 | 0 | else if (FtpLayer::isFtpDataPort(portSrc) || FtpLayer::isFtpDataPort(portDst)) |
488 | 0 | { |
489 | 0 | constructNextLayer<FtpDataLayer>(payload, payloadLen, getAttachedPacket()); |
490 | 0 | } |
491 | 0 | else if ((DoIpLayer::isDoIpPort(portSrc) || DoIpLayer::isDoIpPort(portDst)) && |
492 | 0 | (DoIpLayer::isDataValid(payload, payloadLen))) |
493 | 0 | { |
494 | 0 | tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(DoIpLayer::parseDoIpLayer, payload, payloadLen); |
495 | 0 | } |
496 | 0 | else if (SomeIpLayer::isSomeIpPort(portSrc) || SomeIpLayer::isSomeIpPort(portDst)) |
497 | 0 | { |
498 | 0 | constructNextLayerFromFactory(SomeIpLayer::parseSomeIpLayer, payload, payloadLen); |
499 | 0 | } |
500 | 0 | else if (TpktLayer::isDataValid(payload, payloadLen) && TpktLayer::isTpktPort(portSrc, portDst)) |
501 | 0 | { |
502 | 0 | constructNextLayer<TpktLayer>(payload, payloadLen, getAttachedPacket()); |
503 | 0 | } |
504 | 0 | else if (SmtpLayer::isSmtpPort(portSrc) && SmtpLayer::isDataValid(payload, payloadLen)) |
505 | 0 | { |
506 | 0 | constructNextLayer<SmtpResponseLayer>(payload, payloadLen, getAttachedPacket()); |
507 | 0 | } |
508 | 0 | else if (SmtpLayer::isSmtpPort(portDst) && SmtpLayer::isDataValid(payload, payloadLen)) |
509 | 0 | { |
510 | 0 | constructNextLayer<SmtpRequestLayer>(payload, payloadLen, getAttachedPacket()); |
511 | 0 | } |
512 | 0 | else if (LdapLayer::isLdapPort(portDst) || LdapLayer::isLdapPort(portSrc)) |
513 | 0 | { |
514 | 0 | tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(LdapLayer::parseLdapMessage, payload, |
515 | 0 | payloadLen); |
516 | 0 | } |
517 | 0 | else if (PostgresLayer::isPostgresPort(portDst)) |
518 | 0 | { |
519 | 0 | tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(PostgresLayer::parsePostgresFrontendMessages, |
520 | 0 | payload, payloadLen); |
521 | 0 | } |
522 | 0 | else if (PostgresLayer::isPostgresPort(portSrc)) |
523 | 0 | { |
524 | 0 | tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(PostgresLayer::parsePostgresBackendMessages, |
525 | 0 | payload, payloadLen); |
526 | 0 | } |
527 | 0 | else if (MySqlLayer::isMySqlPort(portSrc)) |
528 | 0 | { |
529 | 0 | tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(MySqlLayer::parseMySqlServerMessage, payload, |
530 | 0 | payloadLen); |
531 | 0 | } |
532 | 0 | else if (MySqlLayer::isMySqlPort(portDst)) |
533 | 0 | { |
534 | 0 | tryConstructNextLayerFromFactoryWithFallback<PayloadLayer>(MySqlLayer::parseMySqlClientMessage, payload, |
535 | 0 | payloadLen); |
536 | 0 | } |
537 | 0 | else if ((GtpV2Layer::isGTPv2Port(portDst) || GtpV2Layer::isGTPv2Port(portSrc)) && |
538 | 0 | GtpV2Layer::isDataValid(payload, payloadLen)) |
539 | 0 | { |
540 | 0 | constructNextLayer<GtpV2Layer>(payload, payloadLen, getAttachedPacket()); |
541 | 0 | } |
542 | 0 | else if (ModbusLayer::isModbusPort(portDst) && ModbusLayer::isDataValid(payload, payloadLen)) |
543 | 0 | { |
544 | 0 | constructNextLayer<ModbusLayer>(payload, payloadLen, getAttachedPacket()); |
545 | 0 | } |
546 | 0 | else |
547 | 0 | { |
548 | 0 | constructNextLayer<PayloadLayer>(payload, payloadLen, getAttachedPacket()); |
549 | 0 | } |
550 | 0 | } |
551 | | |
552 | | void TcpLayer::computeCalculateFields() |
553 | 0 | { |
554 | 0 | tcphdr* tcpHdr = getTcpHeader(); |
555 | |
|
556 | 0 | tcpHdr->dataOffset = getHeaderLen() >> 2; |
557 | 0 | calculateChecksum(true); |
558 | 0 | } |
559 | | |
560 | | std::string TcpLayer::toString() const |
561 | 0 | { |
562 | 0 | const tcphdr* hdr = getTcpHeader(); |
563 | 0 | std::string result = "TCP Layer, "; |
564 | 0 | if (hdr->synFlag) |
565 | 0 | { |
566 | 0 | if (hdr->ackFlag) |
567 | 0 | result += "[SYN, ACK], "; |
568 | 0 | else |
569 | 0 | result += "[SYN], "; |
570 | 0 | } |
571 | 0 | else if (hdr->finFlag) |
572 | 0 | { |
573 | 0 | if (hdr->ackFlag) |
574 | 0 | result += "[FIN, ACK], "; |
575 | 0 | else |
576 | 0 | result += "[FIN], "; |
577 | 0 | } |
578 | 0 | else if (hdr->ackFlag) |
579 | 0 | result += "[ACK], "; |
580 | |
|
581 | 0 | std::ostringstream srcPortStream; |
582 | 0 | srcPortStream << getSrcPort(); |
583 | 0 | std::ostringstream dstPortStream; |
584 | 0 | dstPortStream << getDstPort(); |
585 | 0 | result += "Src port: " + srcPortStream.str() + ", Dst port: " + dstPortStream.str(); |
586 | |
|
587 | 0 | return result; |
588 | 0 | } |
589 | | |
590 | | /// ~~~~~~~~ |
591 | | /// TcpLayer Deprecated Code |
592 | | /// ~~~~~~~~ |
593 | | |
594 | | DISABLE_WARNING_PUSH |
595 | | DISABLE_WARNING_DEPRECATED |
596 | | TcpOption TcpLayer::addTcpOptionAfter(const TcpOptionBuilder& optionBuilder, TcpOptionType prevOptionType) |
597 | 0 | { |
598 | 0 | int offset = 0; |
599 | |
|
600 | 0 | if (prevOptionType == TcpOptionType::TCPOPT_Unknown) |
601 | 0 | { |
602 | 0 | offset = sizeof(tcphdr); |
603 | 0 | } |
604 | 0 | else |
605 | 0 | { |
606 | 0 | TcpOption prevOpt = getTcpOption(prevOptionType); |
607 | 0 | if (prevOpt.isNull()) |
608 | 0 | { |
609 | 0 | PCPP_LOG_ERROR("Previous option of type " << static_cast<int>(prevOptionType) |
610 | 0 | << " not found, cannot add a new TCP option"); |
611 | 0 | return TcpOption(nullptr); |
612 | 0 | } |
613 | | |
614 | 0 | offset = prevOpt.getRecordBasePtr() + prevOpt.getTotalSize() - m_Data; |
615 | 0 | } |
616 | | |
617 | 0 | return addTcpOptionAt(optionBuilder, offset); |
618 | 0 | } |
619 | | |
620 | | TcpOption TcpLayer::getTcpOption(TcpOptionType option) const |
621 | 0 | { |
622 | 0 | return m_OptionReader.getTLVRecord(static_cast<uint8_t>(option), getOptionsBasePtr(), |
623 | 0 | getHeaderLen() - sizeof(tcphdr)); |
624 | 0 | } |
625 | | |
626 | | bool TcpLayer::removeTcpOption(TcpOptionType optionType) |
627 | 0 | { |
628 | 0 | TcpOption opt = getTcpOption(optionType); |
629 | 0 | if (opt.isNull()) |
630 | 0 | { |
631 | 0 | return false; |
632 | 0 | } |
633 | | |
634 | | // calculate total TCP option size |
635 | 0 | TcpOption curOpt = getFirstTcpOption(); |
636 | 0 | size_t totalOptSize = 0; |
637 | 0 | while (!curOpt.isNull()) |
638 | 0 | { |
639 | 0 | totalOptSize += curOpt.getTotalSize(); |
640 | 0 | curOpt = getNextTcpOption(curOpt); |
641 | 0 | } |
642 | 0 | totalOptSize -= opt.getTotalSize(); |
643 | |
|
644 | 0 | int offset = opt.getRecordBasePtr() - m_Data; |
645 | |
|
646 | 0 | if (!shortenLayer(offset, opt.getTotalSize())) |
647 | 0 | { |
648 | 0 | return false; |
649 | 0 | } |
650 | | |
651 | 0 | adjustTcpOptionTrailer(totalOptSize); |
652 | |
|
653 | 0 | m_OptionReader.changeTLVRecordCount(-1); |
654 | |
|
655 | 0 | return true; |
656 | 0 | } |
657 | | DISABLE_WARNING_POP |
658 | | |
659 | | const FieldDescriptor TcpLayer::SerializedFields::SrcPort{ Layer::SerializedFields::MaxID + 1, "srcPort" }; |
660 | | const FieldDescriptor TcpLayer::SerializedFields::DstPort{ Layer::SerializedFields::MaxID + 2, "dstPort" }; |
661 | | const FieldDescriptor TcpLayer::SerializedFields::SequenceNumber{ Layer::SerializedFields::MaxID + 3, |
662 | | "sequenceNumber" }; |
663 | | const FieldDescriptor TcpLayer::SerializedFields::TcpFlags{ Layer::SerializedFields::MaxID + 4, "tcpFlags" }; |
664 | | const FieldDescriptor TcpLayer::SerializedFields::TcpFlag{ 0, "tcpFlag" }; |
665 | | const FieldDescriptor TcpLayer::SerializedFields::WindowSize{ Layer::SerializedFields::MaxID + 5, "windowSize" }; |
666 | | const FieldDescriptor TcpLayer::SerializedFields::Checksum{ Layer::SerializedFields::MaxID + 6, "checksum" }; |
667 | | const FieldDescriptor TcpLayer::SerializedFields::Options{ Layer::SerializedFields::MaxID + 7, "options" }; |
668 | | const FieldDescriptor TcpLayer::SerializedFields::Option{ 0, "option" }; |
669 | | |
670 | | void TcpLayer::serializeLayer(ObjectScope& serializer) const |
671 | 0 | { |
672 | 0 | auto* header = getTcpHeader(); |
673 | 0 | serializer.writeField(SerializedFields::SrcPort, netToHost16(header->portSrc)); |
674 | 0 | serializer.writeField(SerializedFields::DstPort, netToHost16(header->portDst)); |
675 | 0 | serializer.writeField(SerializedFields::SequenceNumber, netToHost32(header->sequenceNumber)); |
676 | 0 | { |
677 | 0 | auto tcpFlagsArray = serializer.writeArray(SerializedFields::TcpFlags); |
678 | 0 | if (header->finFlag) |
679 | 0 | { |
680 | 0 | tcpFlagsArray.writeField(SerializedFields::TcpFlag, "FIN"); |
681 | 0 | } |
682 | 0 | if (header->synFlag) |
683 | 0 | { |
684 | 0 | tcpFlagsArray.writeField(SerializedFields::TcpFlag, "SYN"); |
685 | 0 | } |
686 | 0 | if (header->rstFlag) |
687 | 0 | { |
688 | 0 | tcpFlagsArray.writeField(SerializedFields::TcpFlag, "RST"); |
689 | 0 | } |
690 | 0 | if (header->pshFlag) |
691 | 0 | { |
692 | 0 | tcpFlagsArray.writeField(SerializedFields::TcpFlag, "PSH"); |
693 | 0 | } |
694 | 0 | if (header->ackFlag) |
695 | 0 | { |
696 | 0 | tcpFlagsArray.writeField(SerializedFields::TcpFlag, "ACK"); |
697 | 0 | } |
698 | 0 | if (header->urgFlag) |
699 | 0 | { |
700 | 0 | tcpFlagsArray.writeField(SerializedFields::TcpFlag, "URG"); |
701 | 0 | } |
702 | 0 | if (header->eceFlag) |
703 | 0 | { |
704 | 0 | tcpFlagsArray.writeField(SerializedFields::TcpFlag, "ECE"); |
705 | 0 | } |
706 | 0 | if (header->cwrFlag) |
707 | 0 | { |
708 | 0 | tcpFlagsArray.writeField(SerializedFields::TcpFlag, "CWR"); |
709 | 0 | } |
710 | 0 | } |
711 | 0 | serializer.writeField(SerializedFields::WindowSize, netToHost16(header->windowSize)); |
712 | 0 | serializer.writeHexField(SerializedFields::Checksum, netToHost16(header->headerChecksum)); |
713 | 0 | { |
714 | 0 | auto options = serializer.writeArray(SerializedFields::Options); |
715 | 0 | for (auto option = getFirstTcpOption(); option.isNotNull(); option = getNextTcpOption(option)) |
716 | 0 | { |
717 | 0 | options.writeField(SerializedFields::Option, tcpOptionTypeToString(option.getTcpOptionEnumType())); |
718 | 0 | } |
719 | 0 | } |
720 | 0 | } |
721 | | } // namespace pcpp |