/src/PcapPlusPlus/Packet++/src/SipLayer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | 906 | #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 <algorithm> |
9 | | #include <exception> |
10 | | #include <utility> |
11 | | #include <unordered_map> |
12 | | |
13 | | namespace pcpp |
14 | | { |
15 | | |
16 | | const std::string SipMethodEnumToString[14] = { "INVITE", "ACK", "BYE", "CANCEL", "REGISTER", |
17 | | "PRACK", "OPTIONS", "SUBSCRIBE", "NOTIFY", "PUBLISH", |
18 | | "INFO", "REFER", "MESSAGE", "UPDATE" }; |
19 | | |
20 | | const std::unordered_map<std::string, SipRequestLayer::SipMethod> SipMethodStringToEnum{ |
21 | | { "INVITE", SipRequestLayer::SipMethod::SipINVITE }, |
22 | | { "ACK", SipRequestLayer::SipMethod::SipACK }, |
23 | | { "BYE", SipRequestLayer::SipMethod::SipBYE }, |
24 | | { "CANCEL", SipRequestLayer::SipMethod::SipCANCEL }, |
25 | | { "REGISTER", SipRequestLayer::SipMethod::SipREGISTER }, |
26 | | { "PRACK", SipRequestLayer::SipMethod::SipPRACK }, |
27 | | { "OPTIONS", SipRequestLayer::SipMethod::SipOPTIONS }, |
28 | | { "SUBSCRIBE", SipRequestLayer::SipMethod::SipSUBSCRIBE }, |
29 | | { "NOTIFY", SipRequestLayer::SipMethod::SipNOTIFY }, |
30 | | { "PUBLISH", SipRequestLayer::SipMethod::SipPUBLISH }, |
31 | | { "INFO", SipRequestLayer::SipMethod::SipINFO }, |
32 | | { "REFER", SipRequestLayer::SipMethod::SipREFER }, |
33 | | { "MESSAGE", SipRequestLayer::SipMethod::SipMESSAGE }, |
34 | | { "UPDATE", SipRequestLayer::SipMethod::SipUPDATE }, |
35 | | }; |
36 | | |
37 | | // -------- Class SipLayer ----------------- |
38 | | |
39 | | int SipLayer::getContentLength() const |
40 | 51.2k | { |
41 | 51.2k | std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD); |
42 | 51.2k | std::transform(contentLengthFieldName.begin(), contentLengthFieldName.end(), contentLengthFieldName.begin(), |
43 | 51.2k | ::tolower); |
44 | 51.2k | HeaderField* contentLengthField = getFieldByName(contentLengthFieldName); |
45 | 51.2k | if (contentLengthField != nullptr) |
46 | 49.0k | return atoi(contentLengthField->getFieldValue().c_str()); |
47 | 2.21k | return 0; |
48 | 51.2k | } |
49 | | |
50 | | HeaderField* SipLayer::setContentLength(int contentLength, const std::string& prevFieldName) |
51 | 3.20k | { |
52 | 3.20k | std::ostringstream contentLengthAsString; |
53 | 3.20k | contentLengthAsString << contentLength; |
54 | 3.20k | std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD); |
55 | 3.20k | HeaderField* contentLengthField = getFieldByName(contentLengthFieldName); |
56 | 3.20k | if (contentLengthField == nullptr) |
57 | 0 | { |
58 | 0 | HeaderField* prevField = getFieldByName(prevFieldName); |
59 | 0 | contentLengthField = insertField(prevField, PCPP_SIP_CONTENT_LENGTH_FIELD, contentLengthAsString.str()); |
60 | 0 | } |
61 | 3.20k | else |
62 | 3.20k | contentLengthField->setFieldValue(contentLengthAsString.str()); |
63 | | |
64 | 3.20k | return contentLengthField; |
65 | 3.20k | } |
66 | | |
67 | | void SipLayer::parseNextLayer() |
68 | 57.4k | { |
69 | 57.4k | if (getLayerPayloadSize() == 0) |
70 | 10.2k | return; |
71 | | |
72 | 47.1k | size_t headerLen = getHeaderLen(); |
73 | 47.1k | std::string contentType; |
74 | 47.1k | if (getContentLength() > 0) |
75 | 32.4k | { |
76 | 32.4k | HeaderField* contentTypeField = getFieldByName(PCPP_SIP_CONTENT_TYPE_FIELD); |
77 | 32.4k | if (contentTypeField != nullptr) |
78 | 30.2k | contentType = contentTypeField->getFieldValue(); |
79 | 32.4k | } |
80 | | |
81 | 47.1k | if (contentType.find("application/sdp") != std::string::npos) |
82 | 29.8k | { |
83 | 29.8k | m_NextLayer = new SdpLayer(m_Data + headerLen, m_DataLen - headerLen, this, m_Packet); |
84 | 29.8k | } |
85 | 17.3k | else |
86 | 17.3k | { |
87 | 17.3k | m_NextLayer = new PayloadLayer(m_Data + headerLen, m_DataLen - headerLen, this, m_Packet); |
88 | 17.3k | } |
89 | 47.1k | } |
90 | | |
91 | | void SipLayer::computeCalculateFields() |
92 | 5.40k | { |
93 | 5.40k | HeaderField* contentLengthField = getFieldByName(PCPP_SIP_CONTENT_LENGTH_FIELD); |
94 | 5.40k | if (contentLengthField == nullptr) |
95 | 514 | return; |
96 | | |
97 | 4.89k | size_t headerLen = getHeaderLen(); |
98 | 4.89k | if (m_DataLen > headerLen) |
99 | 4.09k | { |
100 | 4.09k | int currentContentLength = getContentLength(); |
101 | 4.09k | if (currentContentLength != static_cast<int>(m_DataLen - headerLen)) |
102 | 3.20k | setContentLength(m_DataLen - headerLen); |
103 | 4.09k | } |
104 | 4.89k | } |
105 | | |
106 | | // -------- Class SipRequestFirstLine ----------------- |
107 | | |
108 | 50.6k | SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest) : m_SipRequest(sipRequest) |
109 | 50.6k | { |
110 | 50.6k | m_Method = parseMethod(reinterpret_cast<char*>(m_SipRequest->m_Data), m_SipRequest->getDataLen()); |
111 | 50.6k | if (m_Method == SipRequestLayer::SipMethodUnknown) |
112 | 0 | { |
113 | 0 | m_UriOffset = -1; |
114 | 0 | PCPP_LOG_DEBUG("Couldn't resolve SIP request method"); |
115 | 0 | } |
116 | 50.6k | else |
117 | 50.6k | m_UriOffset = SipMethodEnumToString[m_Method].length() + 1; |
118 | | |
119 | 50.6k | parseVersion(); |
120 | | |
121 | 50.6k | char* endOfFirstLine; |
122 | 50.6k | if ((endOfFirstLine = |
123 | 50.6k | static_cast<char*>(memchr(reinterpret_cast<char*>(m_SipRequest->m_Data + m_VersionOffset), '\n', |
124 | 50.6k | m_SipRequest->m_DataLen - static_cast<size_t>(m_VersionOffset)))) != nullptr) |
125 | 50.5k | { |
126 | 50.5k | m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast<char*>(m_SipRequest->m_Data) + 1; |
127 | 50.5k | m_IsComplete = true; |
128 | 50.5k | } |
129 | 83 | else |
130 | 83 | { |
131 | 83 | m_FirstLineEndOffset = m_SipRequest->getDataLen(); |
132 | 83 | m_IsComplete = false; |
133 | 83 | } |
134 | | |
135 | 50.6k | if (Logger::getInstance().isDebugEnabled(PacketLogModuleSipLayer)) |
136 | 0 | { |
137 | 0 | std::string method = |
138 | 0 | (m_Method == SipRequestLayer::SipMethodUnknown ? "Unknown" : SipMethodEnumToString[m_Method]); |
139 | 0 | PCPP_LOG_DEBUG("Method='" << method << "'; SIP version='" << m_Version << "'; URI='" << getUri() << "'"); |
140 | 0 | } |
141 | 50.6k | } |
142 | | |
143 | | SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest, SipRequestLayer::SipMethod method, |
144 | | const std::string& version, const std::string& uri) |
145 | 0 | try // throw(SipRequestFirstLineException) |
146 | 0 | { |
147 | 0 | if (method == SipRequestLayer::SipMethodUnknown) |
148 | 0 | { |
149 | 0 | m_Exception.setMessage("Method supplied was SipMethodUnknown"); |
150 | 0 | throw m_Exception; |
151 | 0 | } |
152 | | |
153 | 0 | if (version == "") |
154 | 0 | { |
155 | 0 | m_Exception.setMessage("Version supplied was empty string"); |
156 | 0 | throw m_Exception; |
157 | 0 | } |
158 | | |
159 | 0 | m_SipRequest = sipRequest; |
160 | |
|
161 | 0 | m_Method = method; |
162 | 0 | m_Version = version; |
163 | |
|
164 | 0 | std::string firstLine = SipMethodEnumToString[m_Method] + " " + uri + " " + version + "\r\n"; |
165 | |
|
166 | 0 | m_UriOffset = SipMethodEnumToString[m_Method].length() + 1; |
167 | 0 | m_FirstLineEndOffset = firstLine.length(); |
168 | 0 | m_VersionOffset = m_UriOffset + uri.length() + 6; |
169 | |
|
170 | 0 | m_SipRequest->m_DataLen = firstLine.length(); |
171 | 0 | m_SipRequest->m_Data = new uint8_t[m_SipRequest->m_DataLen]; |
172 | 0 | memcpy(m_SipRequest->m_Data, firstLine.c_str(), m_SipRequest->m_DataLen); |
173 | |
|
174 | 0 | m_IsComplete = true; |
175 | 0 | } |
176 | 0 | catch (const SipRequestFirstLineException&) |
177 | 0 | { |
178 | 0 | throw; |
179 | 0 | } |
180 | 0 | catch (...) |
181 | 0 | { |
182 | 0 | std::terminate(); |
183 | 0 | } |
184 | | |
185 | | SipRequestLayer::SipMethod SipRequestFirstLine::parseMethod(const char* data, size_t dataLen) |
186 | 111k | { |
187 | 111k | if (!data || dataLen < 4) |
188 | 10 | { |
189 | 10 | return SipRequestLayer::SipMethodUnknown; |
190 | 10 | } |
191 | | |
192 | 111k | size_t spaceIndex = 0; |
193 | 936k | while (spaceIndex < dataLen && data[spaceIndex] != ' ') |
194 | 824k | { |
195 | 824k | spaceIndex++; |
196 | 824k | } |
197 | | |
198 | 111k | if (spaceIndex == 0 || spaceIndex == dataLen) |
199 | 96 | { |
200 | 96 | return SipRequestLayer::SipMethodUnknown; |
201 | 96 | } |
202 | | |
203 | 111k | auto methodAdEnum = SipMethodStringToEnum.find(std::string(data, data + spaceIndex)); |
204 | 111k | if (methodAdEnum == SipMethodStringToEnum.end()) |
205 | 10.4k | { |
206 | 10.4k | return SipRequestLayer::SipMethodUnknown; |
207 | 10.4k | } |
208 | 101k | return methodAdEnum->second; |
209 | 111k | } |
210 | | |
211 | | void SipRequestFirstLine::parseVersion() |
212 | 50.6k | { |
213 | 50.6k | if (m_SipRequest->getDataLen() < static_cast<size_t>(m_UriOffset)) |
214 | 0 | { |
215 | 0 | m_Version = ""; |
216 | 0 | m_VersionOffset = -1; |
217 | 0 | return; |
218 | 0 | } |
219 | | |
220 | 50.6k | char* data = reinterpret_cast<char*>(m_SipRequest->m_Data + m_UriOffset); |
221 | 50.6k | char* verPos = cross_platform_memmem(data, m_SipRequest->getDataLen() - m_UriOffset, " SIP/", 5); |
222 | 50.6k | if (verPos == nullptr) |
223 | 5.51k | { |
224 | 5.51k | m_Version = ""; |
225 | 5.51k | m_VersionOffset = -1; |
226 | 5.51k | return; |
227 | 5.51k | } |
228 | | |
229 | | // verify packet doesn't end before the version, meaning still left place for " SIP/x.y" (7 chars) |
230 | 45.1k | if (static_cast<uint16_t>(verPos + 7 - reinterpret_cast<char*>(m_SipRequest->m_Data)) > |
231 | 45.1k | m_SipRequest->getDataLen()) |
232 | 0 | { |
233 | 0 | m_Version = ""; |
234 | 0 | m_VersionOffset = -1; |
235 | 0 | return; |
236 | 0 | } |
237 | | |
238 | | // skip the space char |
239 | 45.1k | verPos++; |
240 | | |
241 | 45.1k | int endOfVerPos = 0; |
242 | 970k | while (((verPos + endOfVerPos) < reinterpret_cast<char*>(m_SipRequest->m_Data + m_SipRequest->m_DataLen)) && |
243 | 970k | ((verPos + endOfVerPos)[0] != '\r') && ((verPos + endOfVerPos)[0] != '\n')) |
244 | 925k | endOfVerPos++; |
245 | | |
246 | 45.1k | m_Version = std::string(verPos, endOfVerPos); |
247 | | |
248 | 45.1k | m_VersionOffset = verPos - reinterpret_cast<char*>(m_SipRequest->m_Data); |
249 | 45.1k | } |
250 | | |
251 | | bool SipRequestFirstLine::setMethod(SipRequestLayer::SipMethod newMethod) |
252 | 0 | { |
253 | 0 | if (newMethod == SipRequestLayer::SipMethodUnknown) |
254 | 0 | { |
255 | 0 | PCPP_LOG_ERROR("Requested method is SipMethodUnknown"); |
256 | 0 | return false; |
257 | 0 | } |
258 | | |
259 | | // extend or shorten layer |
260 | 0 | int lengthDifference = SipMethodEnumToString[newMethod].length() - SipMethodEnumToString[m_Method].length(); |
261 | 0 | if (lengthDifference > 0) |
262 | 0 | { |
263 | 0 | if (!m_SipRequest->extendLayer(0, lengthDifference)) |
264 | 0 | { |
265 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
266 | 0 | return false; |
267 | 0 | } |
268 | 0 | } |
269 | 0 | else if (lengthDifference < 0) |
270 | 0 | { |
271 | 0 | if (!m_SipRequest->shortenLayer(0, 0 - lengthDifference)) |
272 | 0 | { |
273 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
274 | 0 | return false; |
275 | 0 | } |
276 | 0 | } |
277 | | |
278 | 0 | if (lengthDifference != 0) |
279 | 0 | { |
280 | 0 | m_SipRequest->shiftFieldsOffset(m_SipRequest->getFirstField(), lengthDifference); |
281 | 0 | m_SipRequest->m_FieldsOffset += lengthDifference; |
282 | 0 | } |
283 | |
|
284 | 0 | memcpy(m_SipRequest->m_Data, SipMethodEnumToString[newMethod].c_str(), |
285 | 0 | SipMethodEnumToString[newMethod].length()); |
286 | |
|
287 | 0 | m_UriOffset += lengthDifference; |
288 | 0 | m_VersionOffset += lengthDifference; |
289 | 0 | m_FirstLineEndOffset += lengthDifference; |
290 | |
|
291 | 0 | m_Method = newMethod; |
292 | |
|
293 | 0 | return true; |
294 | 0 | } |
295 | | |
296 | | std::string SipRequestFirstLine::getUri() const |
297 | 0 | { |
298 | 0 | std::string result; |
299 | 0 | if (m_UriOffset != -1 && m_VersionOffset != -1) |
300 | 0 | result.assign(reinterpret_cast<char*>(m_SipRequest->m_Data + m_UriOffset), |
301 | 0 | m_VersionOffset - 1 - m_UriOffset); |
302 | | |
303 | | // else first line is illegal, return empty string |
304 | |
|
305 | 0 | return result; |
306 | 0 | } |
307 | | |
308 | | bool SipRequestFirstLine::setUri(const std::string& newUri) |
309 | 0 | { |
310 | 0 | if (newUri == "") |
311 | 0 | { |
312 | 0 | PCPP_LOG_ERROR("URI cannot be empty"); |
313 | 0 | return false; |
314 | 0 | } |
315 | | |
316 | | // extend or shorten layer |
317 | 0 | std::string currentUri = getUri(); |
318 | 0 | int lengthDifference = newUri.length() - currentUri.length(); |
319 | 0 | if (lengthDifference > 0) |
320 | 0 | { |
321 | 0 | if (!m_SipRequest->extendLayer(m_UriOffset, lengthDifference)) |
322 | 0 | { |
323 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
324 | 0 | return false; |
325 | 0 | } |
326 | 0 | } |
327 | 0 | else if (lengthDifference < 0) |
328 | 0 | { |
329 | 0 | if (!m_SipRequest->shortenLayer(m_UriOffset, 0 - lengthDifference)) |
330 | 0 | { |
331 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
332 | 0 | return false; |
333 | 0 | } |
334 | 0 | } |
335 | | |
336 | 0 | if (lengthDifference != 0) |
337 | 0 | { |
338 | 0 | m_SipRequest->shiftFieldsOffset(m_SipRequest->getFirstField(), lengthDifference); |
339 | 0 | m_SipRequest->m_FieldsOffset += lengthDifference; |
340 | 0 | } |
341 | |
|
342 | 0 | memcpy(m_SipRequest->m_Data + m_UriOffset, newUri.c_str(), newUri.length()); |
343 | |
|
344 | 0 | m_VersionOffset += lengthDifference; |
345 | 0 | m_FirstLineEndOffset += lengthDifference; |
346 | |
|
347 | 0 | return true; |
348 | 0 | } |
349 | | |
350 | | // -------- Class SipRequestLayer ----------------- |
351 | | |
352 | | SipRequestLayer::SipRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
353 | 50.6k | : SipLayer(data, dataLen, prevLayer, packet, SIPRequest) |
354 | 50.6k | { |
355 | 50.6k | m_FirstLine = new SipRequestFirstLine(this); |
356 | 50.6k | m_FieldsOffset = m_FirstLine->getSize(); |
357 | 50.6k | parseFields(); |
358 | 50.6k | } |
359 | | |
360 | | SipRequestLayer::SipRequestLayer(SipMethod method, const std::string& requestUri, const std::string& version) |
361 | 0 | { |
362 | 0 | m_Protocol = SIPRequest; |
363 | 0 | m_FirstLine = new SipRequestFirstLine(this, method, version, requestUri); |
364 | 0 | m_FieldsOffset = m_FirstLine->getSize(); |
365 | 0 | } |
366 | | |
367 | 0 | SipRequestLayer::SipRequestLayer(const SipRequestLayer& other) : SipLayer(other) |
368 | 0 | { |
369 | 0 | m_FirstLine = new SipRequestFirstLine(this); |
370 | 0 | } |
371 | | |
372 | | SipRequestLayer& SipRequestLayer::operator=(const SipRequestLayer& other) |
373 | 0 | { |
374 | 0 | SipLayer::operator=(other); |
375 | |
|
376 | 0 | if (m_FirstLine != nullptr) |
377 | 0 | delete m_FirstLine; |
378 | |
|
379 | 0 | m_FirstLine = new SipRequestFirstLine(this); |
380 | |
|
381 | 0 | return *this; |
382 | 0 | } |
383 | | |
384 | | SipRequestLayer::~SipRequestLayer() |
385 | 50.6k | { |
386 | 50.6k | delete m_FirstLine; |
387 | 50.6k | } |
388 | | |
389 | | std::string SipRequestLayer::toString() const |
390 | 9.19k | { |
391 | 9.19k | static const int maxLengthToPrint = 120; |
392 | 9.19k | std::string result = "SIP request, "; |
393 | 9.19k | int size = m_FirstLine->getSize() - 2; // the -2 is to remove \r\n at the end of the first line |
394 | 9.19k | if (size <= 0) |
395 | 0 | { |
396 | 0 | result += std::string("CORRUPT DATA"); |
397 | 0 | return result; |
398 | 0 | } |
399 | 9.19k | if (size <= maxLengthToPrint) |
400 | 8.62k | { |
401 | 8.62k | char* firstLine = new char[size + 1]; |
402 | 8.62k | strncpy(firstLine, reinterpret_cast<char*>(m_Data), size); |
403 | 8.62k | firstLine[size] = 0; |
404 | 8.62k | result += std::string(firstLine); |
405 | 8.62k | delete[] firstLine; |
406 | 8.62k | } |
407 | 570 | else |
408 | 570 | { |
409 | 570 | char firstLine[maxLengthToPrint + 1]; |
410 | 570 | strncpy(firstLine, reinterpret_cast<char*>(m_Data), maxLengthToPrint - 3); |
411 | 570 | firstLine[maxLengthToPrint - 3] = '.'; |
412 | 570 | firstLine[maxLengthToPrint - 2] = '.'; |
413 | 570 | firstLine[maxLengthToPrint - 1] = '.'; |
414 | 570 | firstLine[maxLengthToPrint] = 0; |
415 | 570 | result += std::string(firstLine); |
416 | 570 | } |
417 | | |
418 | 9.19k | return result; |
419 | 9.19k | } |
420 | | |
421 | | // -------- Class SipResponseLayer ----------------- |
422 | | |
423 | | const std::string StatusCodeEnumToString[77] = { "Trying", |
424 | | "Ringing", |
425 | | "Call is Being Forwarded", |
426 | | "Queued", |
427 | | "Session in Progress", |
428 | | "Early Dialog Terminated", |
429 | | "OK", |
430 | | "Accepted", |
431 | | "No Notification", |
432 | | "Multiple Choices", |
433 | | "Moved Permanently", |
434 | | "Moved Temporarily", |
435 | | "Use Proxy", |
436 | | "Alternative Service", |
437 | | "Bad Request", |
438 | | "Unauthorized", |
439 | | "Payment Required", |
440 | | "Forbidden", |
441 | | "Not Found", |
442 | | "Method Not Allowed", |
443 | | "Not Acceptable", |
444 | | "Proxy Authentication Required", |
445 | | "Request Timeout", |
446 | | "Conflict", |
447 | | "Gone", |
448 | | "Length Required", |
449 | | "Conditional Request Failed", |
450 | | "Request Entity Too Large", |
451 | | "Request-URI Too Long", |
452 | | "Unsupported Media Type", |
453 | | "Unsupported URI Scheme", |
454 | | "Unknown Resource-Priority", |
455 | | "Bad Extension", |
456 | | "Extension Required", |
457 | | "Session Interval Too Small", |
458 | | "Interval Too Brief", |
459 | | "Bad Location Information", |
460 | | "Bad Alert Message", |
461 | | "Use Identity Header", |
462 | | "Provide Referrer Identity", |
463 | | "Flow Failed", |
464 | | "Anonymity Disallowed", |
465 | | "Bad Identity-Info", |
466 | | "Unsupported Certificate", |
467 | | "Invalid Identity Header", |
468 | | "First Hop Lacks Outbound Support", |
469 | | "Max-Breadth Exceeded", |
470 | | "Bad Info Package", |
471 | | "Consent Needed", |
472 | | "Temporarily Unavailable", |
473 | | "Call_Transaction Does Not Exist", |
474 | | "Loop Detected", |
475 | | "Too Many Hops", |
476 | | "Address Incomplete", |
477 | | "Ambiguous", |
478 | | "Busy Here", |
479 | | "Request Terminated", |
480 | | "Not Acceptable Here", |
481 | | "Bad Event", |
482 | | "Request Pending", |
483 | | "Undecipherable", |
484 | | "Security Agreement Required", |
485 | | "Server Internal Error", |
486 | | "Not Implemented", |
487 | | "Bad Gateway", |
488 | | "Service Unavailable", |
489 | | "Server Timeout", |
490 | | "Version Not Supported", |
491 | | "Message Too Large", |
492 | | "Push Notification Service Not Supported", |
493 | | "Precondition Failure", |
494 | | "Busy Everywhere", |
495 | | "Decline", |
496 | | "Does Not Exist Anywhere", |
497 | | "Not Acceptable", |
498 | | "Unwanted", |
499 | | "Rejected" }; |
500 | | |
501 | | const int StatusCodeEnumToInt[77] = { 100, 180, 181, 182, 183, 199, 200, 202, 204, 300, 301, 302, 305, |
502 | | 380, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, |
503 | | 412, 413, 414, 415, 416, 417, 420, 421, 422, 425, 423, 424, 428, |
504 | | 429, 430, 433, 436, 437, 438, 439, 440, 469, 470, 480, 481, 482, |
505 | | 483, 484, 485, 486, 487, 488, 489, 491, 493, 494, 500, 501, 502, |
506 | | 503, 504, 505, 513, 555, 580, 600, 603, 604, 606, 607, 608 }; |
507 | | |
508 | | const std::unordered_map<std::string, SipResponseLayer::SipResponseStatusCode> StatusCodeStringToEnumMap{ |
509 | | { "100", SipResponseLayer::SipResponseStatusCode::Sip100Trying }, |
510 | | { "180", SipResponseLayer::SipResponseStatusCode::Sip180Ringing }, |
511 | | { "181", SipResponseLayer::SipResponseStatusCode::Sip181CallisBeingForwarded }, |
512 | | { "182", SipResponseLayer::SipResponseStatusCode::Sip182Queued }, |
513 | | { "183", SipResponseLayer::SipResponseStatusCode::Sip183SessioninProgress }, |
514 | | { "199", SipResponseLayer::SipResponseStatusCode::Sip199EarlyDialogTerminated }, |
515 | | { "200", SipResponseLayer::SipResponseStatusCode::Sip200OK }, |
516 | | { "202", SipResponseLayer::SipResponseStatusCode::Sip202Accepted }, |
517 | | { "204", SipResponseLayer::SipResponseStatusCode::Sip204NoNotification }, |
518 | | { "300", SipResponseLayer::SipResponseStatusCode::Sip300MultipleChoices }, |
519 | | { "301", SipResponseLayer::SipResponseStatusCode::Sip301MovedPermanently }, |
520 | | { "302", SipResponseLayer::SipResponseStatusCode::Sip302MovedTemporarily }, |
521 | | { "305", SipResponseLayer::SipResponseStatusCode::Sip305UseProxy }, |
522 | | { "380", SipResponseLayer::SipResponseStatusCode::Sip380AlternativeService }, |
523 | | { "400", SipResponseLayer::SipResponseStatusCode::Sip400BadRequest }, |
524 | | { "401", SipResponseLayer::SipResponseStatusCode::Sip401Unauthorized }, |
525 | | { "402", SipResponseLayer::SipResponseStatusCode::Sip402PaymentRequired }, |
526 | | { "403", SipResponseLayer::SipResponseStatusCode::Sip403Forbidden }, |
527 | | { "404", SipResponseLayer::SipResponseStatusCode::Sip404NotFound }, |
528 | | { "405", SipResponseLayer::SipResponseStatusCode::Sip405MethodNotAllowed }, |
529 | | { "406", SipResponseLayer::SipResponseStatusCode::Sip406NotAcceptable }, |
530 | | { "407", SipResponseLayer::SipResponseStatusCode::Sip407ProxyAuthenticationRequired }, |
531 | | { "408", SipResponseLayer::SipResponseStatusCode::Sip408RequestTimeout }, |
532 | | { "409", SipResponseLayer::SipResponseStatusCode::Sip409Conflict }, |
533 | | { "410", SipResponseLayer::SipResponseStatusCode::Sip410Gone }, |
534 | | { "411", SipResponseLayer::SipResponseStatusCode::Sip411LengthRequired }, |
535 | | { "412", SipResponseLayer::SipResponseStatusCode::Sip412ConditionalRequestFailed }, |
536 | | { "413", SipResponseLayer::SipResponseStatusCode::Sip413RequestEntityTooLarge }, |
537 | | { "414", SipResponseLayer::SipResponseStatusCode::Sip414RequestURITooLong }, |
538 | | { "415", SipResponseLayer::SipResponseStatusCode::Sip415UnsupportedMediaType }, |
539 | | { "416", SipResponseLayer::SipResponseStatusCode::Sip416UnsupportedURIScheme }, |
540 | | { "417", SipResponseLayer::SipResponseStatusCode::Sip417UnknownResourcePriority }, |
541 | | { "420", SipResponseLayer::SipResponseStatusCode::Sip420BadExtension }, |
542 | | { "421", SipResponseLayer::SipResponseStatusCode::Sip421ExtensionRequired }, |
543 | | { "422", SipResponseLayer::SipResponseStatusCode::Sip422SessionIntervalTooSmall }, |
544 | | { "423", SipResponseLayer::SipResponseStatusCode::Sip423IntervalTooBrief }, |
545 | | { "424", SipResponseLayer::SipResponseStatusCode::Sip424BadLocationInformation }, |
546 | | { "425", SipResponseLayer::SipResponseStatusCode::Sip425BadAlertMessage }, |
547 | | { "428", SipResponseLayer::SipResponseStatusCode::Sip428UseIdentityHeader }, |
548 | | { "429", SipResponseLayer::SipResponseStatusCode::Sip429ProvideReferrerIdentity }, |
549 | | { "430", SipResponseLayer::SipResponseStatusCode::Sip430FlowFailed }, |
550 | | { "433", SipResponseLayer::SipResponseStatusCode::Sip433AnonymityDisallowed }, |
551 | | { "436", SipResponseLayer::SipResponseStatusCode::Sip436BadIdentityInfo }, |
552 | | { "437", SipResponseLayer::SipResponseStatusCode::Sip437UnsupportedCertificate }, |
553 | | { "438", SipResponseLayer::SipResponseStatusCode::Sip438InvalidIdentityHeader }, |
554 | | { "439", SipResponseLayer::SipResponseStatusCode::Sip439FirstHopLacksOutboundSupport }, |
555 | | { "440", SipResponseLayer::SipResponseStatusCode::Sip440MaxBreadthExceeded }, |
556 | | { "469", SipResponseLayer::SipResponseStatusCode::Sip469BadInfoPackage }, |
557 | | { "470", SipResponseLayer::SipResponseStatusCode::Sip470ConsentNeeded }, |
558 | | { "480", SipResponseLayer::SipResponseStatusCode::Sip480TemporarilyUnavailable }, |
559 | | { "481", SipResponseLayer::SipResponseStatusCode::Sip481Call_TransactionDoesNotExist }, |
560 | | { "482", SipResponseLayer::SipResponseStatusCode::Sip482LoopDetected }, |
561 | | { "483", SipResponseLayer::SipResponseStatusCode::Sip483TooManyHops }, |
562 | | { "484", SipResponseLayer::SipResponseStatusCode::Sip484AddressIncomplete }, |
563 | | { "485", SipResponseLayer::SipResponseStatusCode::Sip485Ambiguous }, |
564 | | { "486", SipResponseLayer::SipResponseStatusCode::Sip486BusyHere }, |
565 | | { "487", SipResponseLayer::SipResponseStatusCode::Sip487RequestTerminated }, |
566 | | { "488", SipResponseLayer::SipResponseStatusCode::Sip488NotAcceptableHere }, |
567 | | { "489", SipResponseLayer::SipResponseStatusCode::Sip489BadEvent }, |
568 | | { "491", SipResponseLayer::SipResponseStatusCode::Sip491RequestPending }, |
569 | | { "493", SipResponseLayer::SipResponseStatusCode::Sip493Undecipherable }, |
570 | | { "494", SipResponseLayer::SipResponseStatusCode::Sip494SecurityAgreementRequired }, |
571 | | { "500", SipResponseLayer::SipResponseStatusCode::Sip500ServerInternalError }, |
572 | | { "501", SipResponseLayer::SipResponseStatusCode::Sip501NotImplemented }, |
573 | | { "502", SipResponseLayer::SipResponseStatusCode::Sip502BadGateway }, |
574 | | { "503", SipResponseLayer::SipResponseStatusCode::Sip503ServiceUnavailable }, |
575 | | { "504", SipResponseLayer::SipResponseStatusCode::Sip504ServerTimeout }, |
576 | | { "505", SipResponseLayer::SipResponseStatusCode::Sip505VersionNotSupported }, |
577 | | { "513", SipResponseLayer::SipResponseStatusCode::Sip513MessageTooLarge }, |
578 | | { "555", SipResponseLayer::SipResponseStatusCode::Sip555PushNotificationServiceNotSupported }, |
579 | | { "580", SipResponseLayer::SipResponseStatusCode::Sip580PreconditionFailure }, |
580 | | { "600", SipResponseLayer::SipResponseStatusCode::Sip600BusyEverywhere }, |
581 | | { "603", SipResponseLayer::SipResponseStatusCode::Sip603Decline }, |
582 | | { "604", SipResponseLayer::SipResponseStatusCode::Sip604DoesNotExistAnywhere }, |
583 | | { "606", SipResponseLayer::SipResponseStatusCode::Sip606NotAcceptable }, |
584 | | { "607", SipResponseLayer::SipResponseStatusCode::Sip607Unwanted }, |
585 | | { "608", SipResponseLayer::SipResponseStatusCode::Sip608Rejected }, |
586 | | }; |
587 | | |
588 | | SipResponseLayer::SipResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
589 | 6.75k | : SipLayer(data, dataLen, prevLayer, packet, SIPResponse) |
590 | 6.75k | { |
591 | 6.75k | m_FirstLine = new SipResponseFirstLine(this); |
592 | 6.75k | m_FieldsOffset = m_FirstLine->getSize(); |
593 | 6.75k | parseFields(); |
594 | 6.75k | } |
595 | | |
596 | | SipResponseLayer::SipResponseLayer(SipResponseLayer::SipResponseStatusCode statusCode, std::string statusCodeString, |
597 | | const std::string& sipVersion) |
598 | 0 | { |
599 | 0 | m_Protocol = SIPResponse; |
600 | 0 | m_FirstLine = new SipResponseFirstLine(this, sipVersion, statusCode, std::move(statusCodeString)); |
601 | 0 | m_FieldsOffset = m_FirstLine->getSize(); |
602 | 0 | } |
603 | | |
604 | | SipResponseLayer::~SipResponseLayer() |
605 | 6.75k | { |
606 | 6.75k | delete m_FirstLine; |
607 | 6.75k | } |
608 | | |
609 | 0 | SipResponseLayer::SipResponseLayer(const SipResponseLayer& other) : SipLayer(other) |
610 | 0 | { |
611 | 0 | m_FirstLine = new SipResponseFirstLine(this); |
612 | 0 | } |
613 | | |
614 | | SipResponseLayer& SipResponseLayer::operator=(const SipResponseLayer& other) |
615 | 0 | { |
616 | 0 | SipLayer::operator=(other); |
617 | |
|
618 | 0 | if (m_FirstLine != nullptr) |
619 | 0 | delete m_FirstLine; |
620 | |
|
621 | 0 | m_FirstLine = new SipResponseFirstLine(this); |
622 | |
|
623 | 0 | return *this; |
624 | 0 | } |
625 | | |
626 | | std::string SipResponseLayer::toString() const |
627 | 1.61k | { |
628 | 1.61k | static const int maxLengthToPrint = 120; |
629 | 1.61k | std::string result = "SIP response, "; |
630 | 1.61k | int size = m_FirstLine->getSize() - 2; // the -2 is to remove \r\n at the end of the first line |
631 | 1.61k | if (size <= 0) |
632 | 0 | { |
633 | 0 | result += std::string("CORRUPT DATA"); |
634 | 0 | return result; |
635 | 0 | } |
636 | 1.61k | if (size <= maxLengthToPrint) |
637 | 1.42k | { |
638 | 1.42k | char* firstLine = new char[size + 1]; |
639 | 1.42k | strncpy(firstLine, reinterpret_cast<char*>(m_Data), size); |
640 | 1.42k | firstLine[size] = 0; |
641 | 1.42k | result += std::string(firstLine); |
642 | 1.42k | delete[] firstLine; |
643 | 1.42k | } |
644 | 192 | else |
645 | 192 | { |
646 | 192 | char firstLine[maxLengthToPrint + 1]; |
647 | 192 | strncpy(firstLine, reinterpret_cast<char*>(m_Data), maxLengthToPrint - 3); |
648 | 192 | firstLine[maxLengthToPrint - 3] = '.'; |
649 | 192 | firstLine[maxLengthToPrint - 2] = '.'; |
650 | 192 | firstLine[maxLengthToPrint - 1] = '.'; |
651 | 192 | firstLine[maxLengthToPrint] = 0; |
652 | 192 | result += std::string(firstLine); |
653 | 192 | } |
654 | | |
655 | 1.61k | return result; |
656 | 1.61k | } |
657 | | |
658 | | // -------- Class SipResponseFirstLine ----------------- |
659 | | |
660 | | int SipResponseFirstLine::getStatusCodeAsInt() const |
661 | 0 | { |
662 | 0 | return StatusCodeEnumToInt[m_StatusCode]; |
663 | 0 | } |
664 | | |
665 | | std::string SipResponseFirstLine::getStatusCodeString() const |
666 | 0 | { |
667 | 0 | std::string result; |
668 | 0 | const int statusStringOffset = 12; |
669 | 0 | if (m_StatusCode != SipResponseLayer::SipStatusCodeUnknown) |
670 | 0 | { |
671 | 0 | int statusStringEndOffset = m_FirstLineEndOffset - 2; |
672 | 0 | if ((*(m_SipResponse->m_Data + statusStringEndOffset)) != '\r') |
673 | 0 | statusStringEndOffset++; |
674 | 0 | result.assign(reinterpret_cast<char*>(m_SipResponse->m_Data + statusStringOffset), |
675 | 0 | statusStringEndOffset - statusStringOffset); |
676 | 0 | } |
677 | | |
678 | | // else first line is illegal, return empty string |
679 | |
|
680 | 0 | return result; |
681 | 0 | } |
682 | | |
683 | | bool SipResponseFirstLine::setStatusCode(SipResponseLayer::SipResponseStatusCode newStatusCode, |
684 | | std::string statusCodeString) |
685 | 0 | { |
686 | 0 | if (newStatusCode == SipResponseLayer::SipStatusCodeUnknown) |
687 | 0 | { |
688 | 0 | PCPP_LOG_ERROR("Requested status code is SipStatusCodeUnknown"); |
689 | 0 | return false; |
690 | 0 | } |
691 | | |
692 | | // extend or shorten layer |
693 | | |
694 | 0 | size_t statusStringOffset = 12; |
695 | 0 | if (statusCodeString == "") |
696 | 0 | statusCodeString = StatusCodeEnumToString[newStatusCode]; |
697 | 0 | int lengthDifference = statusCodeString.length() - getStatusCodeString().length(); |
698 | |
|
699 | 0 | if (lengthDifference > 0) |
700 | 0 | { |
701 | 0 | if (!m_SipResponse->extendLayer(statusStringOffset, lengthDifference)) |
702 | 0 | { |
703 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
704 | 0 | return false; |
705 | 0 | } |
706 | 0 | } |
707 | 0 | else if (lengthDifference < 0) |
708 | 0 | { |
709 | 0 | if (!m_SipResponse->shortenLayer(statusStringOffset, 0 - lengthDifference)) |
710 | 0 | { |
711 | 0 | PCPP_LOG_ERROR("Cannot change layer size"); |
712 | 0 | return false; |
713 | 0 | } |
714 | 0 | } |
715 | | |
716 | 0 | if (lengthDifference != 0) |
717 | 0 | { |
718 | 0 | m_SipResponse->shiftFieldsOffset(m_SipResponse->getFirstField(), lengthDifference); |
719 | 0 | m_SipResponse->m_FieldsOffset += lengthDifference; |
720 | 0 | } |
721 | | |
722 | | // copy status string |
723 | 0 | memcpy(m_SipResponse->m_Data + statusStringOffset, statusCodeString.c_str(), statusCodeString.length()); |
724 | | |
725 | | // change status code |
726 | 0 | std::ostringstream statusCodeAsString; |
727 | 0 | statusCodeAsString << StatusCodeEnumToInt[newStatusCode]; |
728 | 0 | memcpy(m_SipResponse->m_Data + 8, statusCodeAsString.str().c_str(), 3); |
729 | |
|
730 | 0 | m_StatusCode = newStatusCode; |
731 | 0 | m_FirstLineEndOffset += lengthDifference; |
732 | |
|
733 | 0 | return true; |
734 | 0 | } |
735 | | |
736 | | void SipResponseFirstLine::setVersion(const std::string& newVersion) |
737 | 0 | { |
738 | 0 | if (newVersion == "") |
739 | 0 | return; |
740 | | |
741 | 0 | if (newVersion.length() != m_Version.length()) |
742 | 0 | { |
743 | 0 | PCPP_LOG_ERROR("Expected version length is " << m_Version.length() |
744 | 0 | << " characters in the format of SIP/x.y"); |
745 | 0 | return; |
746 | 0 | } |
747 | | |
748 | 0 | char* verPos = reinterpret_cast<char*>(m_SipResponse->m_Data); |
749 | 0 | memcpy(verPos, newVersion.c_str(), newVersion.length()); |
750 | 0 | m_Version = newVersion; |
751 | 0 | } |
752 | | |
753 | | SipResponseLayer::SipResponseStatusCode SipResponseFirstLine::parseStatusCode(const char* data, size_t dataLen) |
754 | 17.3k | { |
755 | | // minimum data should be 12B long: "SIP/x.y XXX " |
756 | 17.3k | if (!data || dataLen < 12) |
757 | 16 | { |
758 | 16 | return SipResponseLayer::SipStatusCodeUnknown; |
759 | 16 | } |
760 | | |
761 | 17.2k | const char* statusCodeData = data + 8; |
762 | 17.2k | if (statusCodeData[3] != ' ') |
763 | 2.42k | { |
764 | 2.42k | return SipResponseLayer::SipStatusCodeUnknown; |
765 | 2.42k | } |
766 | | |
767 | 14.8k | auto codeAsEnum = StatusCodeStringToEnumMap.find(std::string(statusCodeData, 3)); |
768 | 14.8k | if (codeAsEnum == StatusCodeStringToEnumMap.end()) |
769 | 441 | { |
770 | 441 | return SipResponseLayer::SipStatusCodeUnknown; |
771 | 441 | } |
772 | 14.4k | return codeAsEnum->second; |
773 | 14.8k | } |
774 | | |
775 | 6.75k | SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse) : m_SipResponse(sipResponse) |
776 | 6.75k | { |
777 | 6.75k | m_Version = parseVersion(reinterpret_cast<char*>(m_SipResponse->m_Data), m_SipResponse->getDataLen()); |
778 | 6.75k | if (m_Version == "") |
779 | 0 | { |
780 | 0 | m_StatusCode = SipResponseLayer::SipStatusCodeUnknown; |
781 | 0 | } |
782 | 6.75k | else |
783 | 6.75k | { |
784 | 6.75k | m_StatusCode = parseStatusCode(reinterpret_cast<char*>(m_SipResponse->m_Data), m_SipResponse->getDataLen()); |
785 | 6.75k | } |
786 | | |
787 | 6.75k | char* endOfFirstLine; |
788 | 6.75k | if ((endOfFirstLine = static_cast<char*>( |
789 | 6.75k | memchr(reinterpret_cast<char*>(m_SipResponse->m_Data), '\n', m_SipResponse->m_DataLen))) != nullptr) |
790 | 6.75k | { |
791 | 6.75k | m_FirstLineEndOffset = endOfFirstLine - reinterpret_cast<char*>(m_SipResponse->m_Data) + 1; |
792 | 6.75k | m_IsComplete = true; |
793 | 6.75k | } |
794 | 6 | else |
795 | 6 | { |
796 | 6 | m_FirstLineEndOffset = m_SipResponse->getDataLen(); |
797 | 6 | m_IsComplete = false; |
798 | 6 | } |
799 | | |
800 | 6.75k | if (Logger::getInstance().isDebugEnabled(PacketLogModuleSipLayer)) |
801 | 0 | { |
802 | 0 | int statusCode = |
803 | 0 | (m_StatusCode == SipResponseLayer::SipStatusCodeUnknown ? 0 : StatusCodeEnumToInt[m_StatusCode]); |
804 | 0 | PCPP_LOG_DEBUG("Version='" << m_Version << "'; Status code=" << statusCode << " '" << getStatusCodeString() |
805 | 0 | << "'"); |
806 | 0 | } |
807 | 6.75k | } |
808 | | |
809 | | SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse, const std::string& version, |
810 | | SipResponseLayer::SipResponseStatusCode statusCode, |
811 | | std::string statusCodeString) |
812 | 0 | { |
813 | 0 | if (statusCode == SipResponseLayer::SipStatusCodeUnknown) |
814 | 0 | { |
815 | 0 | m_Exception.setMessage("Status code supplied was SipStatusCodeUnknown"); |
816 | 0 | throw m_Exception; |
817 | 0 | } |
818 | | |
819 | 0 | if (version == "") |
820 | 0 | { |
821 | 0 | m_Exception.setMessage("Version supplied was unknown"); |
822 | 0 | throw m_Exception; |
823 | 0 | } |
824 | | |
825 | 0 | m_SipResponse = sipResponse; |
826 | |
|
827 | 0 | m_StatusCode = statusCode; |
828 | 0 | m_Version = version; |
829 | |
|
830 | 0 | std::ostringstream statusCodeAsString; |
831 | 0 | statusCodeAsString << StatusCodeEnumToInt[m_StatusCode]; |
832 | 0 | if (statusCodeString == "") |
833 | 0 | statusCodeString = StatusCodeEnumToString[m_StatusCode]; |
834 | 0 | std::string firstLine = m_Version + " " + statusCodeAsString.str() + " " + statusCodeString + "\r\n"; |
835 | |
|
836 | 0 | m_FirstLineEndOffset = firstLine.length(); |
837 | |
|
838 | 0 | m_SipResponse->m_DataLen = firstLine.length(); |
839 | 0 | m_SipResponse->m_Data = new uint8_t[m_SipResponse->m_DataLen]; |
840 | 0 | memcpy(m_SipResponse->m_Data, firstLine.c_str(), m_SipResponse->m_DataLen); |
841 | |
|
842 | 0 | m_IsComplete = true; |
843 | 0 | } |
844 | | |
845 | | std::string SipResponseFirstLine::parseVersion(const char* data, size_t dataLen) |
846 | 14.4k | { |
847 | 14.4k | if (!data || dataLen < 8) // "SIP/x.y " |
848 | 0 | { |
849 | 0 | PCPP_LOG_DEBUG("SIP response length < 8, cannot identify version"); |
850 | 0 | return ""; |
851 | 0 | } |
852 | | |
853 | 14.4k | if (data[0] != 'S' || data[1] != 'I' || data[2] != 'P' || data[3] != '/') |
854 | 906 | { |
855 | 906 | PCPP_LOG_DEBUG("SIP response does not begin with 'SIP/'"); |
856 | 906 | return ""; |
857 | 906 | } |
858 | | |
859 | 13.5k | const char* nextSpace = static_cast<const char*>(memchr(data, ' ', dataLen)); |
860 | 13.5k | if (nextSpace == nullptr) |
861 | 0 | return ""; |
862 | | |
863 | 13.5k | return std::string(data, nextSpace - data); |
864 | 13.5k | } |
865 | | |
866 | | } // namespace pcpp |