Coverage Report

Created: 2025-08-26 07:54

/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