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