/src/PcapPlusPlus/Packet++/src/SipLayer.cpp
Line | Count | Source |
1 | 5.82k | #define LOG_MODULE PacketLogModuleSipLayer |
2 | | |
3 | | #include "SipLayer.h" |
4 | | #include "SdpLayer.h" |
5 | | #include "PayloadLayer.h" |
6 | | #include "Logger.h" |
7 | | #include "GeneralUtils.h" |
8 | | #include <array> |
9 | | #include <string> |
10 | | #include <algorithm> |
11 | | #include <exception> |
12 | | #include <utility> |
13 | | #include <unordered_map> |
14 | | |
15 | | namespace pcpp |
16 | | { |
17 | | namespace |
18 | | { |
19 | | constexpr uint32_t pack4(const char* data, size_t len) |
20 | 124k | { |
21 | 124k | return ((len > 0 ? static_cast<uint32_t>(data[0]) << 24 : 0) | |
22 | 124k | (len > 1 ? static_cast<uint32_t>(data[1]) << 16 : 0) | |
23 | 124k | (len > 2 ? static_cast<uint32_t>(data[2]) << 8 : 0) | |
24 | 124k | (len > 3 ? static_cast<uint32_t>(data[3]) : 0)); |
25 | 124k | } |
26 | | |
27 | | constexpr uint32_t operator""_packed4(const char* str, size_t len) |
28 | 3.65k | { |
29 | 3.65k | return pack4(str, len); |
30 | 3.65k | } |
31 | | |
32 | | const std::array<std::string, 14> SipMethodEnumToString = { // |
33 | | "INVITE", "ACK", "BYE", "CANCEL", "REGISTER", "PRACK", "OPTIONS", |
34 | | "SUBSCRIBE", "NOTIFY", "PUBLISH", "INFO", "REFER", "MESSAGE", "UPDATE" |
35 | | }; |
36 | | |
37 | | const std::unordered_map<std::string, SipRequestLayer::SipMethod> SipMethodStringToEnum{ |
38 | | { "INVITE", SipRequestLayer::SipMethod::SipINVITE }, |
39 | | { "ACK", SipRequestLayer::SipMethod::SipACK }, |
40 | | { "BYE", SipRequestLayer::SipMethod::SipBYE }, |
41 | | { "CANCEL", SipRequestLayer::SipMethod::SipCANCEL }, |
42 | | { "REGISTER", SipRequestLayer::SipMethod::SipREGISTER }, |
43 | | { "PRACK", SipRequestLayer::SipMethod::SipPRACK }, |
44 | | { "OPTIONS", SipRequestLayer::SipMethod::SipOPTIONS }, |
45 | | { "SUBSCRIBE", SipRequestLayer::SipMethod::SipSUBSCRIBE }, |
46 | | { "NOTIFY", SipRequestLayer::SipMethod::SipNOTIFY }, |
47 | | { "PUBLISH", SipRequestLayer::SipMethod::SipPUBLISH }, |
48 | | { "INFO", SipRequestLayer::SipMethod::SipINFO }, |
49 | | { "REFER", SipRequestLayer::SipMethod::SipREFER }, |
50 | | { "MESSAGE", SipRequestLayer::SipMethod::SipMESSAGE }, |
51 | | { "UPDATE", SipRequestLayer::SipMethod::SipUPDATE }, |
52 | | }; |
53 | | } // namespace |
54 | | |
55 | | // -------- Class SipLayer ----------------- |
56 | | |
57 | | int SipLayer::getContentLength() const |
58 | 12.3k | { |
59 | 12.3k | std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD); |
60 | 12.3k | std::transform(contentLengthFieldName.begin(), contentLengthFieldName.end(), contentLengthFieldName.begin(), |
61 | 12.3k | ::tolower); |
62 | 12.3k | HeaderField* contentLengthField = getFieldByName(contentLengthFieldName); |
63 | 12.3k | if (contentLengthField != nullptr) |
64 | 8.68k | return atoi(contentLengthField->getFieldValue().c_str()); |
65 | 3.69k | return 0; |
66 | 12.3k | } |
67 | | |
68 | | HeaderField* SipLayer::setContentLength(int contentLength, const std::string& prevFieldName) |
69 | 832 | { |
70 | 832 | std::ostringstream contentLengthAsString; |
71 | 832 | contentLengthAsString << contentLength; |
72 | 832 | std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD); |
73 | 832 | HeaderField* contentLengthField = getFieldByName(contentLengthFieldName); |
74 | 832 | if (contentLengthField == nullptr) |
75 | 0 | { |
76 | 0 | HeaderField* prevField = getFieldByName(prevFieldName); |
77 | 0 | contentLengthField = insertField(prevField, PCPP_SIP_CONTENT_LENGTH_FIELD, contentLengthAsString.str()); |
78 | 0 | } |
79 | 832 | else |
80 | 832 | contentLengthField->setFieldValue(contentLengthAsString.str()); |
81 | | |
82 | 832 | return contentLengthField; |
83 | 832 | } |
84 | | |
85 | | void SipLayer::parseNextLayer() |
86 | 24.9k | { |
87 | 24.9k | if (getLayerPayloadSize() == 0) |
88 | 13.6k | return; |
89 | | |
90 | 11.2k | size_t headerLen = getHeaderLen(); |
91 | 11.2k | std::string contentType; |
92 | 11.2k | if (getContentLength() > 0) |
93 | 7.20k | { |
94 | 7.20k | HeaderField* contentTypeField = getFieldByName(PCPP_SIP_CONTENT_TYPE_FIELD); |
95 | 7.20k | if (contentTypeField != nullptr) |
96 | 6.25k | contentType = contentTypeField->getFieldValue(); |
97 | 7.20k | } |
98 | | |
99 | 11.2k | auto payload = m_Data + headerLen; |
100 | 11.2k | auto payloadLen = m_DataLen - headerLen; |
101 | | |
102 | 11.2k | if (contentType.find("application/sdp") != std::string::npos) |
103 | 5.43k | { |
104 | 5.43k | constructNextLayer<SdpLayer>(payload, payloadLen); |
105 | 5.43k | } |
106 | 5.86k | else |
107 | 5.86k | { |
108 | 5.86k | constructNextLayer<PayloadLayer>(payload, payloadLen); |
109 | 5.86k | } |
110 | 11.2k | } |
111 | | |
112 | | void SipLayer::computeCalculateFields() |
113 | 3.92k | { |
114 | 3.92k | HeaderField* contentLengthField = getFieldByName(PCPP_SIP_CONTENT_LENGTH_FIELD); |
115 | 3.92k | if (contentLengthField == nullptr) |
116 | 1.65k | return; |
117 | | |
118 | 2.27k | size_t headerLen = getHeaderLen(); |
119 | 2.27k | if (m_DataLen > headerLen) |
120 | 1.08k | { |
121 | 1.08k | int currentContentLength = getContentLength(); |
122 | 1.08k | if (currentContentLength != static_cast<int>(m_DataLen - headerLen)) |
123 | 832 | setContentLength(m_DataLen - headerLen); |
124 | 1.08k | } |
125 | 2.27k | } |
126 | | |
127 | | SipLayer::SipParseResult SipLayer::detectSipMessageType(const uint8_t* data, size_t dataLen) |
128 | 117k | { |
129 | 117k | if (!data || dataLen < 3) |
130 | 204 | { |
131 | 204 | return SipLayer::SipParseResult::Unknown; |
132 | 204 | } |
133 | | |
134 | 117k | uint32_t key = pack4(reinterpret_cast<const char*>(data), dataLen); |
135 | | |
136 | 117k | switch (key) |
137 | 117k | { |
138 | 1.15k | case "INVI"_packed4: // INVITE |
139 | 1.68k | case "ACK "_packed4: // ACK |
140 | 1.68k | case "BYE "_packed4: // BYE |
141 | 1.72k | case "CANC"_packed4: // CANCEL |
142 | 1.81k | case "REGI"_packed4: // REGISTER |
143 | 1.81k | case "PRAC"_packed4: // PRACK |
144 | 1.82k | case "OPTI"_packed4: // OPTIONS |
145 | 1.85k | case "SUBS"_packed4: // SUBSCRIBE |
146 | 2.42k | case "NOTI"_packed4: // NOTIFY |
147 | 2.43k | case "PUBL"_packed4: // PUBLISH |
148 | 2.43k | case "INFO"_packed4: // INFO |
149 | 2.44k | case "REFE"_packed4: // REFER |
150 | 2.44k | case "MESS"_packed4: // MESSAGE |
151 | 2.47k | case "UPDA"_packed4: // UPDATE |
152 | 2.47k | return SipLayer::SipParseResult::Request; |
153 | | |
154 | 3.65k | case "SIP/"_packed4: |
155 | 3.65k | return SipLayer::SipParseResult::Response; |
156 | | |
157 | 110k | default: |
158 | 110k | return SipLayer::SipParseResult::Unknown; |
159 | 117k | } |
160 | 117k | } |
161 | | |
162 | | SipLayer* SipLayer::parseSipLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, uint16_t srcPort, |
163 | | uint16_t dstPort) |
164 | 30.8k | { |
165 | 30.8k | if (!(SipLayer::isSipPort(srcPort) || SipLayer::isSipPort(dstPort))) |
166 | 0 | { |
167 | 0 | return nullptr; |
168 | 0 | } |
169 | | |
170 | 30.8k | if (SipRequestFirstLine::parseMethod(reinterpret_cast<char*>(data), dataLen) != |
171 | 30.8k | SipRequestLayer::SipMethodUnknown) |
172 | 7.82k | { |
173 | 7.82k | return new SipRequestLayer(data, dataLen, prevLayer, packet); |
174 | 7.82k | } |
175 | | |
176 | 23.0k | if (SipResponseFirstLine::parseStatusCode(reinterpret_cast<char*>(data), dataLen) != |
177 | 23.0k | SipResponseLayer::SipStatusCodeUnknown && |
178 | 16.7k | !SipResponseFirstLine::parseVersion(reinterpret_cast<char*>(data), dataLen).empty()) |
179 | 12.6k | { |
180 | 12.6k | return new SipResponseLayer(data, dataLen, prevLayer, packet); |
181 | 12.6k | } |
182 | | |
183 | 10.3k | return nullptr; |
184 | 23.0k | } |
185 | | |
186 | | SipLayer* SipLayer::parseSipLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
187 | 117k | { |
188 | 117k | SipLayer::SipParseResult sipParseResult = detectSipMessageType(data, dataLen); |
189 | | |
190 | 117k | if (sipParseResult == SipLayer::SipParseResult::Unknown) |
191 | 111k | { |
192 | 111k | return nullptr; |
193 | 111k | } |
194 | | |
195 | 6.13k | if (sipParseResult == SipLayer::SipParseResult::Request) |
196 | 2.47k | { |
197 | 2.47k | if (SipRequestFirstLine::parseFirstLine(reinterpret_cast<char*>(data), dataLen).first) |
198 | 1.13k | { |
199 | 1.13k | return new SipRequestLayer(data, dataLen, prevLayer, packet); |
200 | 1.13k | } |
201 | 1.34k | return nullptr; |
202 | 2.47k | } |
203 | | |
204 | 3.65k | if (SipResponseFirstLine::parseFirstLine(reinterpret_cast<char*>(data), dataLen).first) |
205 | 3.30k | { |
206 | 3.30k | return new SipResponseLayer(data, dataLen, prevLayer, packet); |
207 | 3.30k | } |
208 | 358 | return nullptr; |
209 | 3.65k | } |
210 | | |
211 | | // -------- Class SipRequestFirstLine ----------------- |
212 | | |
213 | 8.95k | SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest) : m_SipRequest(sipRequest) |
214 | 8.95k | { |
215 | 8.95k | m_Method = parseMethod(reinterpret_cast<char*>(m_SipRequest->m_Data), m_SipRequest->getDataLen()); |
216 | 8.95k | if (m_Method == SipRequestLayer::SipMethodUnknown) |
217 | 0 | { |
218 | 0 | m_UriOffset = -1; |
219 | 0 | PCPP_LOG_DEBUG("Couldn't resolve SIP request method"); |
220 | 0 | } |
221 | 8.95k | else |
222 | 8.95k | m_UriOffset = SipMethodEnumToString[m_Method].length() + 1; |
223 | | |
224 | 8.95k | parseVersion(); |
225 | | |
226 | 8.95k | char* endOfFirstLine; |
227 | 8.95k | if ((endOfFirstLine = |
228 | 8.95k | static_cast<char*>(memchr(reinterpret_cast<char*>(m_SipRequest->m_Data + m_VersionOffset), '\n', |
229 | 8.95k | m_SipRequest->m_DataLen - static_cast<size_t>(m_VersionOffset)))) != nullptr) |
230 | 8.22k | { |
231 | 8.22k | m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast<char*>(m_SipRequest->m_Data) + 1; |
232 | 8.22k | m_IsComplete = true; |
233 | 8.22k | } |
234 | 724 | else |
235 | 724 | { |
236 | 724 | m_FirstLineEndOffset = m_SipRequest->getDataLen(); |
237 | 724 | m_IsComplete = false; |
238 | 724 | } |
239 | | |
240 | 8.95k | if (Logger::getInstance().isDebugEnabled(PacketLogModuleSipLayer)) |
241 | 0 | { |
242 | 0 | std::string method = |
243 | 0 | (m_Method == SipRequestLayer::SipMethodUnknown ? "Unknown" : SipMethodEnumToString[m_Method]); |
244 | 0 | PCPP_LOG_DEBUG("Method='" << method << "'; SIP version='" << m_Version << "'; URI='" << getUri() << "'"); |
245 | 0 | } |
246 | 8.95k | } |
247 | | |
248 | | SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest, SipRequestLayer::SipMethod method, |
249 | | const std::string& version, const std::string& uri) |
250 | 0 | try // throw(SipRequestFirstLineException) |
251 | 0 | { |
252 | 0 | if (method == SipRequestLayer::SipMethodUnknown) |
253 | 0 | { |
254 | 0 | m_Exception.setMessage("Method supplied was SipMethodUnknown"); |
255 | 0 | throw m_Exception; |
256 | 0 | } |
257 | | |
258 | 0 | if (version == "") |
259 | 0 | { |
260 | 0 | m_Exception.setMessage("Version supplied was empty string"); |
261 | 0 | throw m_Exception; |
262 | 0 | } |
263 | | |
264 | 0 | m_SipRequest = sipRequest; |
265 | |
|
266 | 0 | m_Method = method; |
267 | 0 | m_Version = version; |
268 | |
|
269 | 0 | std::string firstLine = SipMethodEnumToString[m_Method] + " " + uri + " " + version + "\r\n"; |
270 | |
|
271 | 0 | m_UriOffset = SipMethodEnumToString[m_Method].length() + 1; |
272 | 0 | m_FirstLineEndOffset = firstLine.length(); |
273 | 0 | m_VersionOffset = m_UriOffset + uri.length() + 6; |
274 | |
|
275 | 0 | m_SipRequest->m_DataLen = firstLine.length(); |
276 | 0 | m_SipRequest->m_Data = new uint8_t[m_SipRequest->m_DataLen]; |
277 | 0 | memcpy(m_SipRequest->m_Data, firstLine.c_str(), m_SipRequest->m_DataLen); |
278 | |
|
279 | 0 | m_IsComplete = true; |
280 | 0 | } |
281 | 0 | catch (const SipRequestFirstLineException&) |
282 | 0 | { |
283 | 0 | throw; |
284 | 0 | } |
285 | 0 | catch (...) |
286 | 0 | { |
287 | 0 | std::terminate(); |
288 | 0 | } |
289 | | |
290 | | SipRequestLayer::SipMethod SipRequestFirstLine::parseMethod(const char* data, size_t dataLen) |
291 | 40.5k | { |
292 | 40.5k | if (!data || dataLen < 4) |
293 | 218 | { |
294 | 218 | return SipRequestLayer::SipMethodUnknown; |
295 | 218 | } |
296 | | |
297 | 40.3k | size_t spaceIndex = 0; |
298 | 704k | while (spaceIndex < dataLen && data[spaceIndex] != ' ') |
299 | 664k | { |
300 | 664k | spaceIndex++; |
301 | 664k | } |
302 | | |
303 | 40.3k | if (spaceIndex == 0 || spaceIndex == dataLen) |
304 | 3.62k | { |
305 | 3.62k | return SipRequestLayer::SipMethodUnknown; |
306 | 3.62k | } |
307 | | |
308 | 36.7k | auto methodAdEnum = SipMethodStringToEnum.find(std::string(data, data + spaceIndex)); |
309 | 36.7k | if (methodAdEnum == SipMethodStringToEnum.end()) |
310 | 19.9k | { |
311 | 19.9k | return SipRequestLayer::SipMethodUnknown; |
312 | 19.9k | } |
313 | 16.7k | return methodAdEnum->second; |
314 | 36.7k | } |
315 | | |
316 | | std::pair<bool, SipRequestFirstLine::SipFirstLineData> SipRequestFirstLine::parseFirstLine(const char* data, |
317 | | size_t dataLen) |
318 | 2.47k | { |
319 | 2.47k | SipFirstLineData result = { "", "", "" }; |
320 | | |
321 | 2.47k | if (data == nullptr || dataLen == 0) |
322 | 0 | { |
323 | 0 | PCPP_LOG_DEBUG("Empty data in SIP request line"); |
324 | 0 | return { false, result }; |
325 | 0 | } |
326 | | |
327 | | // Find first space (end of METHOD) |
328 | 2.47k | size_t firstSpaceIndex = 0; |
329 | 41.0k | while (firstSpaceIndex < dataLen && data[firstSpaceIndex] != ' ') |
330 | 38.5k | { |
331 | 38.5k | firstSpaceIndex++; |
332 | 38.5k | } |
333 | | |
334 | 2.47k | if (firstSpaceIndex == 0 || firstSpaceIndex == dataLen) |
335 | 42 | { |
336 | 42 | PCPP_LOG_DEBUG("Invalid METHOD in SIP request line"); |
337 | 42 | return { false, result }; |
338 | 42 | } |
339 | | |
340 | | // Validate method exists in SipMethodStringToEnum |
341 | 2.43k | std::string methodStr{ data, firstSpaceIndex }; |
342 | 2.43k | if (SipMethodStringToEnum.find(methodStr) == SipMethodStringToEnum.end()) |
343 | 186 | { |
344 | 186 | PCPP_LOG_DEBUG("Unknown SIP method"); |
345 | 186 | return { false, result }; |
346 | 186 | } |
347 | | |
348 | | // Find second space (end of URI) |
349 | 2.24k | size_t secondSpaceIndex = firstSpaceIndex + 1; |
350 | 131k | while (secondSpaceIndex < dataLen && data[secondSpaceIndex] != ' ') |
351 | 128k | secondSpaceIndex++; |
352 | | |
353 | 2.24k | if (secondSpaceIndex == dataLen) |
354 | 107 | { |
355 | 107 | PCPP_LOG_DEBUG("No space before version"); |
356 | 107 | return { false, result }; |
357 | 107 | } |
358 | | |
359 | 2.14k | size_t uriLen = secondSpaceIndex - firstSpaceIndex - 1; |
360 | 2.14k | if (uriLen == 0) |
361 | 13 | { |
362 | 13 | PCPP_LOG_DEBUG("Empty URI"); |
363 | 13 | return { false, result }; |
364 | 13 | } |
365 | | |
366 | | // Find end of line |
367 | 2.12k | size_t lineEnd = secondSpaceIndex + 1; |
368 | 67.8k | while (lineEnd < dataLen && data[lineEnd] != '\r' && data[lineEnd] != '\n') |
369 | 65.6k | lineEnd++; |
370 | | |
371 | | // Minimum length for "SIP/x.y" |
372 | 2.12k | size_t versionLen = lineEnd - secondSpaceIndex - 1; |
373 | 2.12k | if (versionLen < 7) |
374 | 131 | { |
375 | 131 | PCPP_LOG_DEBUG("Version too short"); |
376 | 131 | return { false, result }; |
377 | 131 | } |
378 | | |
379 | 1.99k | const char* versionStart = data + secondSpaceIndex + 1; |
380 | 1.99k | if (versionStart[0] != 'S' || versionStart[1] != 'I' || versionStart[2] != 'P' || versionStart[3] != '/') |
381 | 865 | { |
382 | 865 | PCPP_LOG_DEBUG("Invalid SIP version format"); |
383 | 865 | return { false, result }; |
384 | 865 | } |
385 | | |
386 | | // All validations passed |
387 | 1.13k | result.method = std::move(methodStr); |
388 | 1.13k | result.uri = std::string{ data + firstSpaceIndex + 1, uriLen }; |
389 | 1.13k | result.version = std::string{ versionStart, versionLen }; |
390 | | |
391 | 1.13k | return { true, result }; |
392 | 1.99k | } |
393 | | |
394 | | void SipRequestFirstLine::parseVersion() |
395 | 8.95k | { |
396 | 8.95k | if (m_SipRequest->getDataLen() < static_cast<size_t>(m_UriOffset)) |
397 | 0 | { |
398 | 0 | m_Version = ""; |
399 | 0 | m_VersionOffset = -1; |
400 | 0 | return; |
401 | 0 | } |
402 | | |
403 | 8.95k | char* data = reinterpret_cast<char*>(m_SipRequest->m_Data + m_UriOffset); |
404 | 8.95k | char* verPos = cross_platform_memmem(data, m_SipRequest->getDataLen() - m_UriOffset, " SIP/", 5); |
405 | 8.95k | if (verPos == nullptr) |
406 | 1.09k | { |
407 | 1.09k | m_Version = ""; |
408 | 1.09k | m_VersionOffset = -1; |
409 | 1.09k | return; |
410 | 1.09k | } |
411 | | |
412 | | // verify packet doesn't end before the version, meaning still left place for " SIP/x.y" (7 chars) |
413 | 7.86k | if (static_cast<uint16_t>(verPos + 7 - reinterpret_cast<char*>(m_SipRequest->m_Data)) > |
414 | 7.86k | m_SipRequest->getDataLen()) |
415 | 20 | { |
416 | 20 | m_Version = ""; |
417 | 20 | m_VersionOffset = -1; |
418 | 20 | return; |
419 | 20 | } |
420 | | |
421 | | // skip the space char |
422 | 7.84k | verPos++; |
423 | | |
424 | 7.84k | int endOfVerPos = 0; |
425 | 120k | while (((verPos + endOfVerPos) < reinterpret_cast<char*>(m_SipRequest->m_Data + m_SipRequest->m_DataLen)) && |
426 | 120k | ((verPos + endOfVerPos)[0] != '\r') && ((verPos + endOfVerPos)[0] != '\n')) |
427 | 112k | endOfVerPos++; |
428 | | |
429 | 7.84k | m_Version = std::string(verPos, endOfVerPos); |
430 | | |
431 | 7.84k | m_VersionOffset = verPos - reinterpret_cast<char*>(m_SipRequest->m_Data); |
432 | 7.84k | } |
433 | | |
434 | | bool SipRequestFirstLine::setMethod(SipRequestLayer::SipMethod newMethod) |
435 | 0 | { |
436 | 0 | if (newMethod == SipRequestLayer::SipMethodUnknown) |
437 | 0 | { |
438 | 0 | PCPP_LOG_ERROR("Requested method is SipMethodUnknown"); |
439 | 0 | return false; |
440 | 0 | } |
441 | | |
442 | | // extend or shorten layer |
443 | 0 | int lengthDifference = SipMethodEnumToString[newMethod].length() - SipMethodEnumToString[m_Method].length(); |
444 | 0 | if (lengthDifference > 0) |
445 | 0 | { |
446 | 0 | if (!m_SipRequest->extendLayer(0, lengthDifference)) |
447 | 0 | { |
448 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
449 | 0 | return false; |
450 | 0 | } |
451 | 0 | } |
452 | 0 | else if (lengthDifference < 0) |
453 | 0 | { |
454 | 0 | if (!m_SipRequest->shortenLayer(0, 0 - lengthDifference)) |
455 | 0 | { |
456 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
457 | 0 | return false; |
458 | 0 | } |
459 | 0 | } |
460 | | |
461 | 0 | if (lengthDifference != 0) |
462 | 0 | { |
463 | 0 | m_SipRequest->shiftFieldsOffset(m_SipRequest->getFirstField(), lengthDifference); |
464 | 0 | m_SipRequest->m_FieldsOffset += lengthDifference; |
465 | 0 | } |
466 | |
|
467 | 0 | memcpy(m_SipRequest->m_Data, SipMethodEnumToString[newMethod].c_str(), |
468 | 0 | SipMethodEnumToString[newMethod].length()); |
469 | |
|
470 | 0 | m_UriOffset += lengthDifference; |
471 | 0 | m_VersionOffset += lengthDifference; |
472 | 0 | m_FirstLineEndOffset += lengthDifference; |
473 | |
|
474 | 0 | m_Method = newMethod; |
475 | |
|
476 | 0 | return true; |
477 | 0 | } |
478 | | |
479 | | std::string SipRequestFirstLine::getUri() const |
480 | 0 | { |
481 | 0 | std::string result; |
482 | 0 | if (m_UriOffset != -1 && m_VersionOffset != -1) |
483 | 0 | result.assign(reinterpret_cast<char*>(m_SipRequest->m_Data + m_UriOffset), |
484 | 0 | m_VersionOffset - 1 - m_UriOffset); |
485 | | |
486 | | // else first line is illegal, return empty string |
487 | |
|
488 | 0 | return result; |
489 | 0 | } |
490 | | |
491 | | bool SipRequestFirstLine::setUri(const std::string& newUri) |
492 | 0 | { |
493 | 0 | if (newUri == "") |
494 | 0 | { |
495 | 0 | PCPP_LOG_ERROR("URI cannot be empty"); |
496 | 0 | return false; |
497 | 0 | } |
498 | | |
499 | | // extend or shorten layer |
500 | 0 | std::string currentUri = getUri(); |
501 | 0 | int lengthDifference = newUri.length() - currentUri.length(); |
502 | 0 | if (lengthDifference > 0) |
503 | 0 | { |
504 | 0 | if (!m_SipRequest->extendLayer(m_UriOffset, lengthDifference)) |
505 | 0 | { |
506 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
507 | 0 | return false; |
508 | 0 | } |
509 | 0 | } |
510 | 0 | else if (lengthDifference < 0) |
511 | 0 | { |
512 | 0 | if (!m_SipRequest->shortenLayer(m_UriOffset, 0 - lengthDifference)) |
513 | 0 | { |
514 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
515 | 0 | return false; |
516 | 0 | } |
517 | 0 | } |
518 | | |
519 | 0 | if (lengthDifference != 0) |
520 | 0 | { |
521 | 0 | m_SipRequest->shiftFieldsOffset(m_SipRequest->getFirstField(), lengthDifference); |
522 | 0 | m_SipRequest->m_FieldsOffset += lengthDifference; |
523 | 0 | } |
524 | |
|
525 | 0 | memcpy(m_SipRequest->m_Data + m_UriOffset, newUri.c_str(), newUri.length()); |
526 | |
|
527 | 0 | m_VersionOffset += lengthDifference; |
528 | 0 | m_FirstLineEndOffset += lengthDifference; |
529 | |
|
530 | 0 | return true; |
531 | 0 | } |
532 | | |
533 | | // -------- Class SipRequestLayer ----------------- |
534 | | |
535 | | SipRequestLayer::SipRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
536 | 8.95k | : SipLayer(data, dataLen, prevLayer, packet, SIPRequest) |
537 | 8.95k | { |
538 | 8.95k | m_FirstLine = new SipRequestFirstLine(this); |
539 | 8.95k | m_FieldsOffset = m_FirstLine->getSize(); |
540 | 8.95k | parseFields(); |
541 | 8.95k | } |
542 | | |
543 | | SipRequestLayer::SipRequestLayer(SipMethod method, const std::string& requestUri, const std::string& version) |
544 | 0 | { |
545 | 0 | m_Protocol = SIPRequest; |
546 | 0 | m_FirstLine = new SipRequestFirstLine(this, method, version, requestUri); |
547 | 0 | m_FieldsOffset = m_FirstLine->getSize(); |
548 | 0 | } |
549 | | |
550 | 0 | SipRequestLayer::SipRequestLayer(const SipRequestLayer& other) : SipLayer(other) |
551 | 0 | { |
552 | 0 | m_FirstLine = new SipRequestFirstLine(this); |
553 | 0 | } |
554 | | |
555 | | SipRequestLayer& SipRequestLayer::operator=(const SipRequestLayer& other) |
556 | 0 | { |
557 | 0 | SipLayer::operator=(other); |
558 | |
|
559 | 0 | if (m_FirstLine != nullptr) |
560 | 0 | delete m_FirstLine; |
561 | |
|
562 | 0 | m_FirstLine = new SipRequestFirstLine(this); |
563 | |
|
564 | 0 | return *this; |
565 | 0 | } |
566 | | |
567 | | SipRequestLayer::~SipRequestLayer() |
568 | 8.95k | { |
569 | 8.95k | delete m_FirstLine; |
570 | 8.95k | } |
571 | | |
572 | | std::string SipRequestLayer::toString() const |
573 | 3.30k | { |
574 | 3.30k | static const int maxLengthToPrint = 120; |
575 | 3.30k | std::string result = "SIP request, "; |
576 | 3.30k | int size = m_FirstLine->getSize() - 2; // the -2 is to remove \r\n at the end of the first line |
577 | 3.30k | if (size <= 0) |
578 | 4 | { |
579 | 4 | result += std::string("CORRUPT DATA"); |
580 | 4 | return result; |
581 | 4 | } |
582 | 3.30k | if (size <= maxLengthToPrint) |
583 | 2.82k | { |
584 | 2.82k | char* firstLine = new char[size + 1]; |
585 | 2.82k | strncpy(firstLine, reinterpret_cast<char*>(m_Data), size); |
586 | 2.82k | firstLine[size] = 0; |
587 | 2.82k | result += std::string(firstLine); |
588 | 2.82k | delete[] firstLine; |
589 | 2.82k | } |
590 | 482 | else |
591 | 482 | { |
592 | 482 | char firstLine[maxLengthToPrint + 1]; |
593 | 482 | strncpy(firstLine, reinterpret_cast<char*>(m_Data), maxLengthToPrint - 3); |
594 | 482 | firstLine[maxLengthToPrint - 3] = '.'; |
595 | 482 | firstLine[maxLengthToPrint - 2] = '.'; |
596 | 482 | firstLine[maxLengthToPrint - 1] = '.'; |
597 | 482 | firstLine[maxLengthToPrint] = 0; |
598 | 482 | result += std::string(firstLine); |
599 | 482 | } |
600 | | |
601 | 3.30k | return result; |
602 | 3.30k | } |
603 | | |
604 | | // -------- Class SipResponseLayer ----------------- |
605 | | |
606 | | namespace |
607 | | { |
608 | | const std::array<std::string, 77> StatusCodeEnumToString = { // format override comment |
609 | | "Trying", |
610 | | "Ringing", |
611 | | "Call is Being Forwarded", |
612 | | "Queued", |
613 | | "Session in Progress", |
614 | | "Early Dialog Terminated", |
615 | | "OK", |
616 | | "Accepted", |
617 | | "No Notification", |
618 | | "Multiple Choices", |
619 | | "Moved Permanently", |
620 | | "Moved Temporarily", |
621 | | "Use Proxy", |
622 | | "Alternative Service", |
623 | | "Bad Request", |
624 | | "Unauthorized", |
625 | | "Payment Required", |
626 | | "Forbidden", |
627 | | "Not Found", |
628 | | "Method Not Allowed", |
629 | | "Not Acceptable", |
630 | | "Proxy Authentication Required", |
631 | | "Request Timeout", |
632 | | "Conflict", |
633 | | "Gone", |
634 | | "Length Required", |
635 | | "Conditional Request Failed", |
636 | | "Request Entity Too Large", |
637 | | "Request-URI Too Long", |
638 | | "Unsupported Media Type", |
639 | | "Unsupported URI Scheme", |
640 | | "Unknown Resource-Priority", |
641 | | "Bad Extension", |
642 | | "Extension Required", |
643 | | "Session Interval Too Small", |
644 | | "Interval Too Brief", |
645 | | "Bad Location Information", |
646 | | "Bad Alert Message", |
647 | | "Use Identity Header", |
648 | | "Provide Referrer Identity", |
649 | | "Flow Failed", |
650 | | "Anonymity Disallowed", |
651 | | "Bad Identity-Info", |
652 | | "Unsupported Certificate", |
653 | | "Invalid Identity Header", |
654 | | "First Hop Lacks Outbound Support", |
655 | | "Max-Breadth Exceeded", |
656 | | "Bad Info Package", |
657 | | "Consent Needed", |
658 | | "Temporarily Unavailable", |
659 | | "Call_Transaction Does Not Exist", |
660 | | "Loop Detected", |
661 | | "Too Many Hops", |
662 | | "Address Incomplete", |
663 | | "Ambiguous", |
664 | | "Busy Here", |
665 | | "Request Terminated", |
666 | | "Not Acceptable Here", |
667 | | "Bad Event", |
668 | | "Request Pending", |
669 | | "Undecipherable", |
670 | | "Security Agreement Required", |
671 | | "Server Internal Error", |
672 | | "Not Implemented", |
673 | | "Bad Gateway", |
674 | | "Service Unavailable", |
675 | | "Server Timeout", |
676 | | "Version Not Supported", |
677 | | "Message Too Large", |
678 | | "Push Notification Service Not Supported", |
679 | | "Precondition Failure", |
680 | | "Busy Everywhere", |
681 | | "Decline", |
682 | | "Does Not Exist Anywhere", |
683 | | "Not Acceptable", |
684 | | "Unwanted", |
685 | | "Rejected" |
686 | | }; |
687 | | |
688 | | const std::array<int, 77> StatusCodeEnumToInt = { |
689 | | 100, 180, 181, 182, 183, 199, 200, 202, 204, 300, 301, 302, 305, 380, 400, 401, 402, 403, 404, 405, |
690 | | 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 420, 421, 422, 425, 423, 424, 428, 429, |
691 | | 430, 433, 436, 437, 438, 439, 440, 469, 470, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 491, |
692 | | 493, 494, 500, 501, 502, 503, 504, 505, 513, 555, 580, 600, 603, 604, 606, 607, 608 |
693 | | }; |
694 | | |
695 | | // Parses the SIP status code from raw data. The data must point to the beginning of the status code. |
696 | | SipResponseLayer::SipResponseStatusCode parseStatusCodePure(const char* data, size_t dataLen) |
697 | 35.1k | { |
698 | 35.1k | if (data == nullptr || dataLen < 3) |
699 | 0 | { |
700 | 0 | return SipResponseLayer::SipStatusCodeUnknown; |
701 | 0 | } |
702 | | |
703 | 35.1k | uint16_t code = 0; |
704 | 35.1k | code += (static_cast<uint16_t>(data[0]) - '0') * 100; |
705 | 35.1k | code += (static_cast<uint16_t>(data[1]) - '0') * 10; |
706 | 35.1k | code += (static_cast<uint16_t>(data[2]) - '0'); |
707 | | |
708 | 35.1k | switch (code) |
709 | 35.1k | { |
710 | | // 1xx: Informational |
711 | 4.51k | case 100: |
712 | 4.51k | return SipResponseLayer::SipResponseStatusCode::Sip100Trying; |
713 | 704 | case 180: |
714 | 704 | return SipResponseLayer::SipResponseStatusCode::Sip180Ringing; |
715 | 82 | case 181: |
716 | 82 | return SipResponseLayer::SipResponseStatusCode::Sip181CallisBeingForwarded; |
717 | 107 | case 182: |
718 | 107 | return SipResponseLayer::SipResponseStatusCode::Sip182Queued; |
719 | 114 | case 183: |
720 | 114 | return SipResponseLayer::SipResponseStatusCode::Sip183SessioninProgress; |
721 | 816 | case 199: |
722 | 816 | return SipResponseLayer::SipResponseStatusCode::Sip199EarlyDialogTerminated; |
723 | | // 2xx: Success |
724 | 14.0k | case 200: |
725 | 14.0k | return SipResponseLayer::SipResponseStatusCode::Sip200OK; |
726 | 379 | case 202: |
727 | 379 | return SipResponseLayer::SipResponseStatusCode::Sip202Accepted; |
728 | 759 | case 204: |
729 | 759 | return SipResponseLayer::SipResponseStatusCode::Sip204NoNotification; |
730 | | // 3xx: Redirection |
731 | 1.18k | case 300: |
732 | 1.18k | return SipResponseLayer::SipResponseStatusCode::Sip300MultipleChoices; |
733 | 89 | case 301: |
734 | 89 | return SipResponseLayer::SipResponseStatusCode::Sip301MovedPermanently; |
735 | 46 | case 302: |
736 | 46 | return SipResponseLayer::SipResponseStatusCode::Sip302MovedTemporarily; |
737 | 62 | case 305: |
738 | 62 | return SipResponseLayer::SipResponseStatusCode::Sip305UseProxy; |
739 | 74 | case 380: |
740 | 74 | return SipResponseLayer::SipResponseStatusCode::Sip380AlternativeService; |
741 | | // 4xx: Client Failure |
742 | 171 | case 400: |
743 | 171 | return SipResponseLayer::SipResponseStatusCode::Sip400BadRequest; |
744 | 3.70k | case 401: |
745 | 3.70k | return SipResponseLayer::SipResponseStatusCode::Sip401Unauthorized; |
746 | 513 | case 402: |
747 | 513 | return SipResponseLayer::SipResponseStatusCode::Sip402PaymentRequired; |
748 | 822 | case 403: |
749 | 822 | return SipResponseLayer::SipResponseStatusCode::Sip403Forbidden; |
750 | 81 | case 404: |
751 | 81 | return SipResponseLayer::SipResponseStatusCode::Sip404NotFound; |
752 | 81 | case 405: |
753 | 81 | return SipResponseLayer::SipResponseStatusCode::Sip405MethodNotAllowed; |
754 | 73 | case 406: |
755 | 73 | return SipResponseLayer::SipResponseStatusCode::Sip406NotAcceptable; |
756 | 517 | case 407: |
757 | 517 | return SipResponseLayer::SipResponseStatusCode::Sip407ProxyAuthenticationRequired; |
758 | 723 | case 408: |
759 | 723 | return SipResponseLayer::SipResponseStatusCode::Sip408RequestTimeout; |
760 | 207 | case 409: |
761 | 207 | return SipResponseLayer::SipResponseStatusCode::Sip409Conflict; |
762 | 81 | case 410: |
763 | 81 | return SipResponseLayer::SipResponseStatusCode::Sip410Gone; |
764 | 82 | case 411: |
765 | 82 | return SipResponseLayer::SipResponseStatusCode::Sip411LengthRequired; |
766 | 82 | case 412: |
767 | 82 | return SipResponseLayer::SipResponseStatusCode::Sip412ConditionalRequestFailed; |
768 | 84 | case 413: |
769 | 84 | return SipResponseLayer::SipResponseStatusCode::Sip413RequestEntityTooLarge; |
770 | 107 | case 414: |
771 | 107 | return SipResponseLayer::SipResponseStatusCode::Sip414RequestURITooLong; |
772 | 105 | case 415: |
773 | 105 | return SipResponseLayer::SipResponseStatusCode::Sip415UnsupportedMediaType; |
774 | 79 | case 416: |
775 | 79 | return SipResponseLayer::SipResponseStatusCode::Sip416UnsupportedURIScheme; |
776 | 85 | case 417: |
777 | 85 | return SipResponseLayer::SipResponseStatusCode::Sip417UnknownResourcePriority; |
778 | 68 | case 420: |
779 | 68 | return SipResponseLayer::SipResponseStatusCode::Sip420BadExtension; |
780 | 85 | case 421: |
781 | 85 | return SipResponseLayer::SipResponseStatusCode::Sip421ExtensionRequired; |
782 | 81 | case 422: |
783 | 81 | return SipResponseLayer::SipResponseStatusCode::Sip422SessionIntervalTooSmall; |
784 | 83 | case 423: |
785 | 83 | return SipResponseLayer::SipResponseStatusCode::Sip423IntervalTooBrief; |
786 | 99 | case 424: |
787 | 99 | return SipResponseLayer::SipResponseStatusCode::Sip424BadLocationInformation; |
788 | 74 | case 425: |
789 | 74 | return SipResponseLayer::SipResponseStatusCode::Sip425BadAlertMessage; |
790 | 72 | case 428: |
791 | 72 | return SipResponseLayer::SipResponseStatusCode::Sip428UseIdentityHeader; |
792 | 78 | case 429: |
793 | 78 | return SipResponseLayer::SipResponseStatusCode::Sip429ProvideReferrerIdentity; |
794 | 84 | case 430: |
795 | 84 | return SipResponseLayer::SipResponseStatusCode::Sip430FlowFailed; |
796 | 80 | case 433: |
797 | 80 | return SipResponseLayer::SipResponseStatusCode::Sip433AnonymityDisallowed; |
798 | 50 | case 436: |
799 | 50 | return SipResponseLayer::SipResponseStatusCode::Sip436BadIdentityInfo; |
800 | 85 | case 437: |
801 | 85 | return SipResponseLayer::SipResponseStatusCode::Sip437UnsupportedCertificate; |
802 | 81 | case 438: |
803 | 81 | return SipResponseLayer::SipResponseStatusCode::Sip438InvalidIdentityHeader; |
804 | 86 | case 439: |
805 | 86 | return SipResponseLayer::SipResponseStatusCode::Sip439FirstHopLacksOutboundSupport; |
806 | 124 | case 440: |
807 | 124 | return SipResponseLayer::SipResponseStatusCode::Sip440MaxBreadthExceeded; |
808 | 34 | case 469: |
809 | 34 | return SipResponseLayer::SipResponseStatusCode::Sip469BadInfoPackage; |
810 | 31 | case 470: |
811 | 31 | return SipResponseLayer::SipResponseStatusCode::Sip470ConsentNeeded; |
812 | 109 | case 480: |
813 | 109 | return SipResponseLayer::SipResponseStatusCode::Sip480TemporarilyUnavailable; |
814 | 76 | case 481: |
815 | 76 | return SipResponseLayer::SipResponseStatusCode::Sip481Call_TransactionDoesNotExist; |
816 | 77 | case 482: |
817 | 77 | return SipResponseLayer::SipResponseStatusCode::Sip482LoopDetected; |
818 | 81 | case 483: |
819 | 81 | return SipResponseLayer::SipResponseStatusCode::Sip483TooManyHops; |
820 | 107 | case 484: |
821 | 107 | return SipResponseLayer::SipResponseStatusCode::Sip484AddressIncomplete; |
822 | 79 | case 485: |
823 | 79 | return SipResponseLayer::SipResponseStatusCode::Sip485Ambiguous; |
824 | 79 | case 486: |
825 | 79 | return SipResponseLayer::SipResponseStatusCode::Sip486BusyHere; |
826 | 83 | case 487: |
827 | 83 | return SipResponseLayer::SipResponseStatusCode::Sip487RequestTerminated; |
828 | 73 | case 488: |
829 | 73 | return SipResponseLayer::SipResponseStatusCode::Sip488NotAcceptableHere; |
830 | 67 | case 489: |
831 | 67 | return SipResponseLayer::SipResponseStatusCode::Sip489BadEvent; |
832 | 37 | case 491: |
833 | 37 | return SipResponseLayer::SipResponseStatusCode::Sip491RequestPending; |
834 | 83 | case 493: |
835 | 83 | return SipResponseLayer::SipResponseStatusCode::Sip493Undecipherable; |
836 | 72 | case 494: |
837 | 72 | return SipResponseLayer::SipResponseStatusCode::Sip494SecurityAgreementRequired; |
838 | | // 5xx: Server Failure |
839 | 133 | case 500: |
840 | 133 | return SipResponseLayer::SipResponseStatusCode::Sip500ServerInternalError; |
841 | 169 | case 501: |
842 | 169 | return SipResponseLayer::SipResponseStatusCode::Sip501NotImplemented; |
843 | 46 | case 502: |
844 | 46 | return SipResponseLayer::SipResponseStatusCode::Sip502BadGateway; |
845 | 320 | case 503: |
846 | 320 | return SipResponseLayer::SipResponseStatusCode::Sip503ServiceUnavailable; |
847 | 45 | case 504: |
848 | 45 | return SipResponseLayer::SipResponseStatusCode::Sip504ServerTimeout; |
849 | 33 | case 505: |
850 | 33 | return SipResponseLayer::SipResponseStatusCode::Sip505VersionNotSupported; |
851 | 78 | case 513: |
852 | 78 | return SipResponseLayer::SipResponseStatusCode::Sip513MessageTooLarge; |
853 | 33 | case 555: |
854 | 33 | return SipResponseLayer::SipResponseStatusCode::Sip555PushNotificationServiceNotSupported; |
855 | 109 | case 580: |
856 | 109 | return SipResponseLayer::SipResponseStatusCode::Sip580PreconditionFailure; |
857 | | // 6xx: Global Failure |
858 | 116 | case 600: |
859 | 116 | return SipResponseLayer::SipResponseStatusCode::Sip600BusyEverywhere; |
860 | 97 | case 603: |
861 | 97 | return SipResponseLayer::SipResponseStatusCode::Sip603Decline; |
862 | 83 | case 604: |
863 | 83 | return SipResponseLayer::SipResponseStatusCode::Sip604DoesNotExistAnywhere; |
864 | 67 | case 606: |
865 | 67 | return SipResponseLayer::SipResponseStatusCode::Sip606NotAcceptable; |
866 | 33 | case 607: |
867 | 33 | return SipResponseLayer::SipResponseStatusCode::Sip607Unwanted; |
868 | 68 | case 608: |
869 | 68 | return SipResponseLayer::SipResponseStatusCode::Sip608Rejected; |
870 | 839 | default: |
871 | 839 | return SipResponseLayer::SipStatusCodeUnknown; |
872 | 35.1k | } |
873 | 35.1k | } |
874 | | } // namespace |
875 | | |
876 | | SipResponseLayer::SipResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
877 | 15.9k | : SipLayer(data, dataLen, prevLayer, packet, SIPResponse) |
878 | 15.9k | { |
879 | 15.9k | m_FirstLine = new SipResponseFirstLine(this); |
880 | 15.9k | m_FieldsOffset = m_FirstLine->getSize(); |
881 | 15.9k | parseFields(); |
882 | 15.9k | } |
883 | | |
884 | | SipResponseLayer::SipResponseLayer(SipResponseLayer::SipResponseStatusCode statusCode, std::string statusCodeString, |
885 | | const std::string& sipVersion) |
886 | 0 | { |
887 | 0 | m_Protocol = SIPResponse; |
888 | 0 | m_FirstLine = new SipResponseFirstLine(this, sipVersion, statusCode, std::move(statusCodeString)); |
889 | 0 | m_FieldsOffset = m_FirstLine->getSize(); |
890 | 0 | } |
891 | | |
892 | | SipResponseLayer::~SipResponseLayer() |
893 | 15.9k | { |
894 | 15.9k | delete m_FirstLine; |
895 | 15.9k | } |
896 | | |
897 | 0 | SipResponseLayer::SipResponseLayer(const SipResponseLayer& other) : SipLayer(other) |
898 | 0 | { |
899 | 0 | m_FirstLine = new SipResponseFirstLine(this); |
900 | 0 | } |
901 | | |
902 | | SipResponseLayer& SipResponseLayer::operator=(const SipResponseLayer& other) |
903 | 0 | { |
904 | 0 | SipLayer::operator=(other); |
905 | |
|
906 | 0 | if (m_FirstLine != nullptr) |
907 | 0 | delete m_FirstLine; |
908 | |
|
909 | 0 | m_FirstLine = new SipResponseFirstLine(this); |
910 | |
|
911 | 0 | return *this; |
912 | 0 | } |
913 | | |
914 | | std::string SipResponseLayer::toString() const |
915 | 4.54k | { |
916 | 4.54k | static const int maxLengthToPrint = 120; |
917 | 4.54k | std::string result = "SIP response, "; |
918 | 4.54k | int size = m_FirstLine->getSize() - 2; // the -2 is to remove \r\n at the end of the first line |
919 | 4.54k | if (size <= 0) |
920 | 0 | { |
921 | 0 | result += std::string("CORRUPT DATA"); |
922 | 0 | return result; |
923 | 0 | } |
924 | 4.54k | if (size <= maxLengthToPrint) |
925 | 4.43k | { |
926 | 4.43k | char* firstLine = new char[size + 1]; |
927 | 4.43k | strncpy(firstLine, reinterpret_cast<char*>(m_Data), size); |
928 | 4.43k | firstLine[size] = 0; |
929 | 4.43k | result += std::string(firstLine); |
930 | 4.43k | delete[] firstLine; |
931 | 4.43k | } |
932 | 118 | else |
933 | 118 | { |
934 | 118 | char firstLine[maxLengthToPrint + 1]; |
935 | 118 | strncpy(firstLine, reinterpret_cast<char*>(m_Data), maxLengthToPrint - 3); |
936 | 118 | firstLine[maxLengthToPrint - 3] = '.'; |
937 | 118 | firstLine[maxLengthToPrint - 2] = '.'; |
938 | 118 | firstLine[maxLengthToPrint - 1] = '.'; |
939 | 118 | firstLine[maxLengthToPrint] = 0; |
940 | 118 | result += std::string(firstLine); |
941 | 118 | } |
942 | | |
943 | 4.54k | return result; |
944 | 4.54k | } |
945 | | |
946 | | // -------- Class SipResponseFirstLine ----------------- |
947 | | |
948 | | int SipResponseFirstLine::getStatusCodeAsInt() const |
949 | 0 | { |
950 | 0 | return StatusCodeEnumToInt[m_StatusCode]; |
951 | 0 | } |
952 | | |
953 | | std::string SipResponseFirstLine::getStatusCodeString() const |
954 | 0 | { |
955 | 0 | std::string result; |
956 | 0 | const int statusStringOffset = 12; |
957 | 0 | if (m_StatusCode != SipResponseLayer::SipStatusCodeUnknown) |
958 | 0 | { |
959 | 0 | int statusStringEndOffset = m_FirstLineEndOffset - 2; |
960 | 0 | if ((*(m_SipResponse->m_Data + statusStringEndOffset)) != '\r') |
961 | 0 | statusStringEndOffset++; |
962 | 0 | result.assign(reinterpret_cast<char*>(m_SipResponse->m_Data + statusStringOffset), |
963 | 0 | statusStringEndOffset - statusStringOffset); |
964 | 0 | } |
965 | | |
966 | | // else first line is illegal, return empty string |
967 | |
|
968 | 0 | return result; |
969 | 0 | } |
970 | | |
971 | | bool SipResponseFirstLine::setStatusCode(SipResponseLayer::SipResponseStatusCode newStatusCode, |
972 | | std::string statusCodeString) |
973 | 0 | { |
974 | 0 | if (newStatusCode == SipResponseLayer::SipStatusCodeUnknown) |
975 | 0 | { |
976 | 0 | PCPP_LOG_ERROR("Requested status code is SipStatusCodeUnknown"); |
977 | 0 | return false; |
978 | 0 | } |
979 | | |
980 | | // extend or shorten layer |
981 | | |
982 | 0 | size_t statusStringOffset = 12; |
983 | 0 | if (statusCodeString == "") |
984 | 0 | statusCodeString = StatusCodeEnumToString[newStatusCode]; |
985 | 0 | int lengthDifference = statusCodeString.length() - getStatusCodeString().length(); |
986 | |
|
987 | 0 | if (lengthDifference > 0) |
988 | 0 | { |
989 | 0 | if (!m_SipResponse->extendLayer(statusStringOffset, lengthDifference)) |
990 | 0 | { |
991 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
992 | 0 | return false; |
993 | 0 | } |
994 | 0 | } |
995 | 0 | else if (lengthDifference < 0) |
996 | 0 | { |
997 | 0 | if (!m_SipResponse->shortenLayer(statusStringOffset, 0 - lengthDifference)) |
998 | 0 | { |
999 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
1000 | 0 | return false; |
1001 | 0 | } |
1002 | 0 | } |
1003 | | |
1004 | 0 | if (lengthDifference != 0) |
1005 | 0 | { |
1006 | 0 | m_SipResponse->shiftFieldsOffset(m_SipResponse->getFirstField(), lengthDifference); |
1007 | 0 | m_SipResponse->m_FieldsOffset += lengthDifference; |
1008 | 0 | } |
1009 | | |
1010 | | // copy status string |
1011 | 0 | memcpy(m_SipResponse->m_Data + statusStringOffset, statusCodeString.c_str(), statusCodeString.length()); |
1012 | | |
1013 | | // change status code |
1014 | 0 | std::ostringstream statusCodeAsString; |
1015 | 0 | statusCodeAsString << StatusCodeEnumToInt[newStatusCode]; |
1016 | 0 | memcpy(m_SipResponse->m_Data + 8, statusCodeAsString.str().c_str(), 3); |
1017 | |
|
1018 | 0 | m_StatusCode = newStatusCode; |
1019 | 0 | m_FirstLineEndOffset += lengthDifference; |
1020 | |
|
1021 | 0 | return true; |
1022 | 0 | } |
1023 | | |
1024 | | void SipResponseFirstLine::setVersion(const std::string& newVersion) |
1025 | 0 | { |
1026 | 0 | if (newVersion == "") |
1027 | 0 | return; |
1028 | | |
1029 | 0 | if (newVersion.length() != m_Version.length()) |
1030 | 0 | { |
1031 | 0 | PCPP_LOG_ERROR("Expected version length is " << m_Version.length() |
1032 | 0 | << " characters in the format of SIP/x.y"); |
1033 | 0 | return; |
1034 | 0 | } |
1035 | | |
1036 | 0 | char* verPos = reinterpret_cast<char*>(m_SipResponse->m_Data); |
1037 | 0 | memcpy(verPos, newVersion.c_str(), newVersion.length()); |
1038 | 0 | m_Version = newVersion; |
1039 | 0 | } |
1040 | | |
1041 | | SipResponseLayer::SipResponseStatusCode SipResponseFirstLine::parseStatusCode(const char* data, size_t dataLen) |
1042 | 39.7k | { |
1043 | | // minimum data should be 12B long: "SIP/x.y XXX " |
1044 | 39.7k | if (!data || dataLen < 12) |
1045 | 2.97k | { |
1046 | 2.97k | return SipResponseLayer::SipStatusCodeUnknown; |
1047 | 2.97k | } |
1048 | | |
1049 | 36.7k | const char* statusCodeData = data + 8; |
1050 | 36.7k | if (statusCodeData[3] != ' ') |
1051 | 5.09k | { |
1052 | 5.09k | return SipResponseLayer::SipStatusCodeUnknown; |
1053 | 5.09k | } |
1054 | | |
1055 | 31.6k | return parseStatusCodePure(statusCodeData, 3); |
1056 | 36.7k | } |
1057 | | |
1058 | 15.9k | SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse) : m_SipResponse(sipResponse) |
1059 | 15.9k | { |
1060 | 15.9k | m_Version = parseVersion(reinterpret_cast<char*>(m_SipResponse->m_Data), m_SipResponse->getDataLen()); |
1061 | 15.9k | if (m_Version == "") |
1062 | 28 | { |
1063 | 28 | m_StatusCode = SipResponseLayer::SipStatusCodeUnknown; |
1064 | 28 | } |
1065 | 15.9k | else |
1066 | 15.9k | { |
1067 | 15.9k | m_StatusCode = parseStatusCode(reinterpret_cast<char*>(m_SipResponse->m_Data), m_SipResponse->getDataLen()); |
1068 | 15.9k | } |
1069 | | |
1070 | 15.9k | char* endOfFirstLine; |
1071 | 15.9k | if ((endOfFirstLine = static_cast<char*>( |
1072 | 15.9k | memchr(reinterpret_cast<char*>(m_SipResponse->m_Data), '\n', m_SipResponse->m_DataLen))) != nullptr) |
1073 | 15.4k | { |
1074 | 15.4k | m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast<char*>(m_SipResponse->m_Data) + 1; |
1075 | 15.4k | m_IsComplete = true; |
1076 | 15.4k | } |
1077 | 563 | else |
1078 | 563 | { |
1079 | 563 | m_FirstLineEndOffset = m_SipResponse->getDataLen(); |
1080 | 563 | m_IsComplete = false; |
1081 | 563 | } |
1082 | | |
1083 | 15.9k | if (Logger::getInstance().isDebugEnabled(PacketLogModuleSipLayer)) |
1084 | 0 | { |
1085 | 0 | int statusCode = |
1086 | 0 | (m_StatusCode == SipResponseLayer::SipStatusCodeUnknown ? 0 : StatusCodeEnumToInt[m_StatusCode]); |
1087 | 0 | PCPP_LOG_DEBUG("Version='" << m_Version << "'; Status code=" << statusCode << " '" << getStatusCodeString() |
1088 | 0 | << "'"); |
1089 | 0 | } |
1090 | 15.9k | } |
1091 | | |
1092 | | SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse, const std::string& version, |
1093 | | SipResponseLayer::SipResponseStatusCode statusCode, |
1094 | | std::string statusCodeString) |
1095 | 0 | { |
1096 | 0 | if (statusCode == SipResponseLayer::SipStatusCodeUnknown) |
1097 | 0 | { |
1098 | 0 | m_Exception.setMessage("Status code supplied was SipStatusCodeUnknown"); |
1099 | 0 | throw m_Exception; |
1100 | 0 | } |
1101 | | |
1102 | 0 | if (version == "") |
1103 | 0 | { |
1104 | 0 | m_Exception.setMessage("Version supplied was unknown"); |
1105 | 0 | throw m_Exception; |
1106 | 0 | } |
1107 | | |
1108 | 0 | m_SipResponse = sipResponse; |
1109 | |
|
1110 | 0 | m_StatusCode = statusCode; |
1111 | 0 | m_Version = version; |
1112 | |
|
1113 | 0 | std::ostringstream statusCodeAsString; |
1114 | 0 | statusCodeAsString << StatusCodeEnumToInt[m_StatusCode]; |
1115 | 0 | if (statusCodeString == "") |
1116 | 0 | statusCodeString = StatusCodeEnumToString[m_StatusCode]; |
1117 | 0 | std::string firstLine = m_Version + " " + statusCodeAsString.str() + " " + statusCodeString + "\r\n"; |
1118 | |
|
1119 | 0 | m_FirstLineEndOffset = firstLine.length(); |
1120 | |
|
1121 | 0 | m_SipResponse->m_DataLen = firstLine.length(); |
1122 | 0 | m_SipResponse->m_Data = new uint8_t[m_SipResponse->m_DataLen]; |
1123 | 0 | memcpy(m_SipResponse->m_Data, firstLine.c_str(), m_SipResponse->m_DataLen); |
1124 | |
|
1125 | 0 | m_IsComplete = true; |
1126 | 0 | } |
1127 | | |
1128 | | std::string SipResponseFirstLine::parseVersion(const char* data, size_t dataLen) |
1129 | 32.7k | { |
1130 | 32.7k | if (!data || dataLen < 8) // "SIP/x.y " |
1131 | 0 | { |
1132 | 0 | PCPP_LOG_DEBUG("SIP response length < 8, cannot identify version"); |
1133 | 0 | return ""; |
1134 | 0 | } |
1135 | | |
1136 | 32.7k | if (data[0] != 'S' || data[1] != 'I' || data[2] != 'P' || data[3] != '/') |
1137 | 4.12k | { |
1138 | 4.12k | PCPP_LOG_DEBUG("SIP response does not begin with 'SIP/'"); |
1139 | 4.12k | return ""; |
1140 | 4.12k | } |
1141 | | |
1142 | 28.6k | const char* nextSpace = static_cast<const char*>(memchr(data, ' ', dataLen)); |
1143 | 28.6k | if (nextSpace == nullptr) |
1144 | 0 | return ""; |
1145 | | |
1146 | 28.6k | return std::string(data, nextSpace - data); |
1147 | 28.6k | } |
1148 | | |
1149 | | std::pair<bool, SipResponseFirstLine::FirstLineData> SipResponseFirstLine::parseFirstLine(const char* data, |
1150 | | size_t dataLen) |
1151 | 3.65k | { |
1152 | 3.65k | std::pair<bool, FirstLineData> result{}; // initialize to false and empty strings |
1153 | | |
1154 | | // Minimum data should be 12 bytes long: "SIP/x.y XXX " |
1155 | 3.65k | if (data == nullptr || dataLen < 12) |
1156 | 5 | { |
1157 | 5 | PCPP_LOG_DEBUG("SIP response length < 12, cannot parse first line"); |
1158 | 5 | return result; |
1159 | 5 | } |
1160 | | |
1161 | 3.65k | if (pack4(data, 4) != "SIP/"_packed4) |
1162 | 0 | { |
1163 | 0 | PCPP_LOG_DEBUG("SIP response does not begin with 'SIP/'"); |
1164 | 0 | return result; |
1165 | 0 | } |
1166 | | |
1167 | 3.65k | const auto dataEndIt = data + dataLen; |
1168 | | // Find first space (end of version) |
1169 | 3.65k | auto firstSpaceIt = std::find(data + 4, dataEndIt, ' '); |
1170 | 3.65k | if (firstSpaceIt == dataEndIt) |
1171 | 76 | { |
1172 | 76 | PCPP_LOG_DEBUG("No space after version in SIP response line"); |
1173 | 76 | return result; |
1174 | 76 | } |
1175 | | |
1176 | | // Status code is strictly 3 characters followed by a space |
1177 | 3.57k | auto statusCodeIt = firstSpaceIt + 1; |
1178 | 3.57k | auto statusCodeEndIt = statusCodeIt + 3; |
1179 | 3.57k | if (*statusCodeEndIt != ' ') |
1180 | 116 | { |
1181 | 116 | PCPP_LOG_DEBUG("No space after status code in SIP response line"); |
1182 | 116 | return result; |
1183 | 116 | } |
1184 | | |
1185 | 3.46k | auto statusCode = parseStatusCodePure(statusCodeIt, 3); |
1186 | 3.46k | if (statusCode == SipResponseLayer::SipStatusCodeUnknown) |
1187 | 161 | { |
1188 | 161 | PCPP_LOG_DEBUG("Unknown SIP status code"); |
1189 | 161 | return result; |
1190 | 161 | } |
1191 | | |
1192 | | // Write parsed values to result |
1193 | 3.30k | result.first = true; |
1194 | 3.30k | result.second.version = std::string(data, firstSpaceIt); |
1195 | 3.30k | result.second.statusCode = statusCode; |
1196 | 3.30k | return result; |
1197 | 3.46k | } |
1198 | | |
1199 | | } // namespace pcpp |