Coverage Report

Created: 2026-08-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/PostgresLayer.cpp
Line
Count
Source
1
#include "PostgresLayer.h"
2
#include "EndianPortable.h"
3
#include "GeneralUtils.h"
4
#include <algorithm>
5
#include <cstring>
6
#include <unordered_set>
7
8
#pragma pack(push, 1)
9
namespace internal
10
{
11
  struct PostgresColumnFixedData
12
  {
13
    uint32_t tableOID;
14
    uint16_t columnIndex;
15
    uint32_t typeOID;
16
    int16_t typeSize;
17
    int32_t typeModifier;
18
    uint16_t formatCode;
19
  };
20
}  // namespace internal
21
#pragma pack(pop)
22
23
static_assert(sizeof(::internal::PostgresColumnFixedData) == 18, "PostgresColumnFixedData must be 18 bytes");
24
25
namespace pcpp
26
{
27
  constexpr char PostgresMessage_0 = '\0';
28
  constexpr char PostgresBackendMessage_R = 'R';
29
  constexpr char PostgresBackendMessage_K = 'K';
30
  constexpr char PostgresBackendMessage_2 = '2';
31
  constexpr char PostgresBackendMessage_3 = '3';
32
  constexpr char PostgresBackendMessage_S = 'S';
33
  constexpr char PostgresBackendMessage_Z = 'Z';
34
  constexpr char PostgresBackendMessage_C = 'C';
35
  constexpr char PostgresBackendMessage_d = 'd';
36
  constexpr char PostgresBackendMessage_c = 'c';
37
  constexpr char PostgresBackendMessage_G = 'G';
38
  constexpr char PostgresBackendMessage_H = 'H';
39
  constexpr char PostgresBackendMessage_W = 'W';
40
  constexpr char PostgresBackendMessage_D = 'D';
41
  constexpr char PostgresBackendMessage_I = 'I';
42
  constexpr char PostgresBackendMessage_E = 'E';
43
  constexpr char PostgresBackendMessage_V = 'V';
44
  constexpr char PostgresBackendMessage_v = 'v';
45
  constexpr char PostgresBackendMessage_n = 'n';
46
  constexpr char PostgresBackendMessage_N = 'N';
47
  constexpr char PostgresBackendMessage_A = 'A';
48
  constexpr char PostgresBackendMessage_t = 't';
49
  constexpr char PostgresBackendMessage_1 = '1';
50
  constexpr char PostgresBackendMessage_s = 's';
51
  constexpr char PostgresBackendMessage_T = 'T';
52
  constexpr char PostgresFrontendMessage_Q = 'Q';
53
  constexpr char PostgresFrontendMessage_P = 'P';
54
  constexpr char PostgresFrontendMessage_B = 'B';
55
  constexpr char PostgresFrontendMessage_E = 'E';
56
  constexpr char PostgresFrontendMessage_C = 'C';
57
  constexpr char PostgresFrontendMessage_D = 'D';
58
  constexpr char PostgresFrontendMessage_F = 'F';
59
  constexpr char PostgresFrontendMessage_H = 'H';
60
  constexpr char PostgresFrontendMessage_S = 'S';
61
  constexpr char PostgresFrontendMessage_d = 'd';
62
  constexpr char PostgresFrontendMessage_c = 'c';
63
  constexpr char PostgresFrontendMessage_f = 'f';
64
  constexpr char PostgresFrontendMessage_X = 'X';
65
66
  const std::unordered_set<uint8_t> validErrorFieldTypes = { 'S', 'V', 'C', 'M', 'D', 'H', 'P', 'p', 'q',
67
                                                           'W', 's', 't', 'c', 'd', 'n', 'F', 'L', 'R' };
68
69
  constexpr uint32_t PostgresFrontendTag_SSLRequest = 80877103;
70
  constexpr uint32_t PostgresFrontendTag_GSSENCRequest = 80877104;
71
  constexpr uint32_t PostgresFrontendTag_CancelRequest = 80877102;
72
  constexpr uint32_t PostgresFrontendTag_StartupMessage = 196608;
73
74
  char PostgresMessageType::toChar() const
75
0
  {
76
0
    switch (m_Value)
77
0
    {
78
    // Frontend message types
79
0
    case Frontend_Query:
80
0
      return PostgresFrontendMessage_Q;
81
0
    case Frontend_Parse:
82
0
      return PostgresFrontendMessage_P;
83
0
    case Frontend_Bind:
84
0
      return PostgresFrontendMessage_B;
85
0
    case Frontend_Execute:
86
0
      return PostgresFrontendMessage_E;
87
0
    case Frontend_Close:
88
0
      return PostgresFrontendMessage_C;
89
0
    case Frontend_Describe:
90
0
      return PostgresFrontendMessage_D;
91
0
    case Frontend_FunctionCall:
92
0
      return PostgresFrontendMessage_F;
93
0
    case Frontend_Flush:
94
0
      return PostgresFrontendMessage_H;
95
0
    case Frontend_Sync:
96
0
      return PostgresFrontendMessage_S;
97
0
    case Frontend_CopyData:
98
0
      return PostgresFrontendMessage_d;
99
0
    case Frontend_CopyDone:
100
0
      return PostgresFrontendMessage_c;
101
0
    case Frontend_CopyFail:
102
0
      return PostgresFrontendMessage_f;
103
0
    case Frontend_Terminate:
104
0
      return PostgresFrontendMessage_X;
105
    // Backend message types
106
0
    case Backend_AuthenticationOk:
107
0
    case Backend_AuthenticationMD5Password:
108
0
    case Backend_AuthenticationSASL:
109
0
    case Backend_AuthenticationSASLContinue:
110
0
    case Backend_AuthenticationSASLFinal:
111
0
      return PostgresBackendMessage_R;
112
0
    case Backend_BackendKeyData:
113
0
      return PostgresBackendMessage_K;
114
0
    case Backend_BindComplete:
115
0
      return PostgresBackendMessage_2;
116
0
    case Backend_CloseComplete:
117
0
      return PostgresBackendMessage_3;
118
0
    case Backend_CommandComplete:
119
0
      return PostgresBackendMessage_C;
120
0
    case Backend_CopyData:
121
0
      return PostgresBackendMessage_d;
122
0
    case Backend_CopyDone:
123
0
      return PostgresBackendMessage_c;
124
0
    case Backend_CopyInResponse:
125
0
      return PostgresBackendMessage_G;
126
0
    case Backend_CopyOutResponse:
127
0
      return PostgresBackendMessage_H;
128
0
    case Backend_CopyBothResponse:
129
0
      return PostgresBackendMessage_W;
130
0
    case Backend_DataRow:
131
0
      return PostgresBackendMessage_D;
132
0
    case Backend_EmptyQueryResponse:
133
0
      return PostgresBackendMessage_I;
134
0
    case Backend_ErrorResponse:
135
0
      return PostgresBackendMessage_E;
136
0
    case Backend_FunctionCallResponse:
137
0
      return PostgresBackendMessage_V;
138
0
    case Backend_NegotiateProtocolVersion:
139
0
      return PostgresBackendMessage_v;
140
0
    case Backend_NoData:
141
0
      return PostgresBackendMessage_n;
142
0
    case Backend_NoticeResponse:
143
0
      return PostgresBackendMessage_N;
144
0
    case Backend_NotificationResponse:
145
0
      return PostgresBackendMessage_A;
146
0
    case Backend_ParameterDescription:
147
0
      return PostgresBackendMessage_t;
148
0
    case Backend_ParameterStatus:
149
0
      return PostgresBackendMessage_S;
150
0
    case Backend_ParseComplete:
151
0
      return PostgresBackendMessage_1;
152
0
    case Backend_PortalSuspended:
153
0
      return PostgresBackendMessage_s;
154
0
    case Backend_ReadyForQuery:
155
0
      return PostgresBackendMessage_Z;
156
0
    case Backend_RowDescription:
157
0
      return PostgresBackendMessage_T;
158
0
    default:
159
0
      return '\0';
160
0
    }
161
0
  }
162
163
  std::string PostgresMessageType::toString() const
164
0
  {
165
0
    switch (m_Value)
166
0
    {
167
    // Frontend message types
168
0
    case Frontend_StartupMessage:
169
0
      return "Frontend_StartupMessage";
170
0
    case Frontend_SSLRequest:
171
0
      return "Frontend_SSLRequest";
172
0
    case Frontend_CancelRequest:
173
0
      return "Frontend_CancelRequest";
174
0
    case Frontend_GSSENCRequest:
175
0
      return "Frontend_GSSENCRequest";
176
0
    case Frontend_Query:
177
0
      return "Frontend_Query";
178
0
    case Frontend_Parse:
179
0
      return "Frontend_Parse";
180
0
    case Frontend_Bind:
181
0
      return "Frontend_Bind";
182
0
    case Frontend_Execute:
183
0
      return "Frontend_Execute";
184
0
    case Frontend_Close:
185
0
      return "Frontend_Close";
186
0
    case Frontend_Describe:
187
0
      return "Frontend_Describe";
188
0
    case Frontend_FunctionCall:
189
0
      return "Frontend_FunctionCall";
190
0
    case Frontend_Flush:
191
0
      return "Frontend_Flush";
192
0
    case Frontend_Sync:
193
0
      return "Frontend_Sync";
194
0
    case Frontend_CopyData:
195
0
      return "Frontend_CopyData";
196
0
    case Frontend_CopyDone:
197
0
      return "Frontend_CopyDone";
198
0
    case Frontend_CopyFail:
199
0
      return "Frontend_CopyFail";
200
0
    case Frontend_Terminate:
201
0
      return "Frontend_Terminate";
202
0
    case Frontend_Unknown:
203
0
      return "Frontend_Unknown";
204
    // Backend message types
205
0
    case Backend_AuthenticationOk:
206
0
      return "Backend_AuthenticationOk";
207
0
    case Backend_AuthenticationKerberosV4:
208
0
      return "Backend_AuthenticationKerberosV4";
209
0
    case Backend_AuthenticationKerberosV5:
210
0
      return "Backend_AuthenticationKerberosV5";
211
0
    case Backend_AuthenticationCleartextPassword:
212
0
      return "Backend_AuthenticationCleartextPassword";
213
0
    case Backend_AuthenticationMD5Password:
214
0
      return "Backend_AuthenticationMD5Password";
215
0
    case Backend_AuthenticationGSS:
216
0
      return "Backend_AuthenticationGSS";
217
0
    case Backend_AuthenticationGSSContinue:
218
0
      return "Backend_AuthenticationGSSContinue";
219
0
    case Backend_AuthenticationSSPI:
220
0
      return "Backend_AuthenticationSSPI";
221
0
    case Backend_AuthenticationSASL:
222
0
      return "Backend_AuthenticationSASL";
223
0
    case Backend_AuthenticationSASLContinue:
224
0
      return "Backend_AuthenticationSASLContinue";
225
0
    case Backend_AuthenticationSASLFinal:
226
0
      return "Backend_AuthenticationSASLFinal";
227
0
    case Backend_BackendKeyData:
228
0
      return "Backend_BackendKeyData";
229
0
    case Backend_BindComplete:
230
0
      return "Backend_BindComplete";
231
0
    case Backend_CloseComplete:
232
0
      return "Backend_CloseComplete";
233
0
    case Backend_CommandComplete:
234
0
      return "Backend_CommandComplete";
235
0
    case Backend_CopyData:
236
0
      return "Backend_CopyData";
237
0
    case Backend_CopyDone:
238
0
      return "Backend_CopyDone";
239
0
    case Backend_CopyInResponse:
240
0
      return "Backend_CopyInResponse";
241
0
    case Backend_CopyOutResponse:
242
0
      return "Backend_CopyOutResponse";
243
0
    case Backend_CopyBothResponse:
244
0
      return "Backend_CopyBothResponse";
245
0
    case Backend_DataRow:
246
0
      return "Backend_DataRow";
247
0
    case Backend_EmptyQueryResponse:
248
0
      return "Backend_EmptyQueryResponse";
249
0
    case Backend_ErrorResponse:
250
0
      return "Backend_ErrorResponse";
251
0
    case Backend_FunctionCallResponse:
252
0
      return "Backend_FunctionCallResponse";
253
0
    case Backend_NegotiateProtocolVersion:
254
0
      return "Backend_NegotiateProtocolVersion";
255
0
    case Backend_NoData:
256
0
      return "Backend_NoData";
257
0
    case Backend_NoticeResponse:
258
0
      return "Backend_NoticeResponse";
259
0
    case Backend_NotificationResponse:
260
0
      return "Backend_NotificationResponse";
261
0
    case Backend_ParameterDescription:
262
0
      return "Backend_ParameterDescription";
263
0
    case Backend_ParameterStatus:
264
0
      return "Backend_ParameterStatus";
265
0
    case Backend_ParseComplete:
266
0
      return "Backend_ParseComplete";
267
0
    case Backend_PortalSuspended:
268
0
      return "Backend_PortalSuspended";
269
0
    case Backend_ReadyForQuery:
270
0
      return "Backend_ReadyForQuery";
271
0
    case Backend_RowDescription:
272
0
      return "Backend_RowDescription";
273
0
    case Backend_Unknown:
274
0
      return "Backend_Unknown";
275
0
    default:
276
0
      return "Unknown";
277
0
    }
278
0
  }
279
280
  PostgresMessageOrigin PostgresMessageType::getOrigin() const
281
0
  {
282
0
    switch (m_Value)
283
0
    {
284
0
    case Frontend_StartupMessage:
285
0
    case Frontend_SSLRequest:
286
0
    case Frontend_CancelRequest:
287
0
    case Frontend_GSSENCRequest:
288
0
    case Frontend_Query:
289
0
    case Frontend_Parse:
290
0
    case Frontend_Bind:
291
0
    case Frontend_Execute:
292
0
    case Frontend_Close:
293
0
    case Frontend_Describe:
294
0
    case Frontend_FunctionCall:
295
0
    case Frontend_Flush:
296
0
    case Frontend_Sync:
297
0
    case Frontend_CopyData:
298
0
    case Frontend_CopyDone:
299
0
    case Frontend_CopyFail:
300
0
    case Frontend_Terminate:
301
0
    case Frontend_Unknown:
302
0
      return PostgresMessageOrigin::Frontend;
303
0
    default:
304
0
      return PostgresMessageOrigin::Backend;
305
0
    }
306
0
  }
307
308
  std::unique_ptr<PostgresMessage> PostgresMessage::parsePostgresBackendMessage(const uint8_t* data, size_t dataLen)
309
6
  {
310
6
    if (data == nullptr || dataLen < 1)
311
0
    {
312
0
      return nullptr;
313
0
    }
314
315
6
    if (dataLen < 5)
316
5
    {
317
5
      return std::unique_ptr<PostgresMessage>(
318
5
          new PostgresMessage(data, dataLen, PostgresMessageType::Backend_Unknown));
319
5
    }
320
321
1
    auto messageLength = be32toh(*reinterpret_cast<const uint32_t*>(data + 1));
322
1
    if (dataLen < messageLength + 1)
323
1
    {
324
1
      return std::unique_ptr<PostgresMessage>(
325
1
          new PostgresMessage(data, dataLen, PostgresMessageType::Backend_Unknown));
326
1
    }
327
328
0
    auto messageTypeValue = data[0];
329
0
    auto messageType = PostgresMessageType::Backend_Unknown;
330
331
0
    switch (messageTypeValue)
332
0
    {
333
0
    case PostgresBackendMessage_R:
334
0
    {
335
0
      uint32_t authType = be32toh(*reinterpret_cast<const uint32_t*>(data + 5));
336
0
      switch (authType)
337
0
      {
338
0
      case 0:
339
0
      {
340
0
        messageType = PostgresMessageType::Backend_AuthenticationOk;
341
0
        break;
342
0
      }
343
0
      case 1:
344
0
      {
345
0
        messageType = PostgresMessageType::Backend_AuthenticationKerberosV4;
346
0
        break;
347
0
      }
348
0
      case 2:
349
0
      {
350
0
        messageType = PostgresMessageType::Backend_AuthenticationKerberosV5;
351
0
        break;
352
0
      }
353
0
      case 3:
354
0
      {
355
0
        messageType = PostgresMessageType::Backend_AuthenticationCleartextPassword;
356
0
        break;
357
0
      }
358
0
      case 5:
359
0
      {
360
0
        messageType = PostgresMessageType::Backend_AuthenticationMD5Password;
361
0
        break;
362
0
      }
363
0
      case 7:
364
0
      {
365
0
        messageType = PostgresMessageType::Backend_AuthenticationGSS;
366
0
        break;
367
0
      }
368
0
      case 8:
369
0
      {
370
0
        messageType = PostgresMessageType::Backend_AuthenticationGSSContinue;
371
0
        break;
372
0
      }
373
0
      case 9:
374
0
      {
375
0
        messageType = PostgresMessageType::Backend_AuthenticationSSPI;
376
0
        break;
377
0
      }
378
0
      case 10:
379
0
      {
380
0
        messageType = PostgresMessageType::Backend_AuthenticationSASL;
381
0
        break;
382
0
      }
383
0
      case 11:
384
0
      {
385
0
        messageType = PostgresMessageType::Backend_AuthenticationSASLContinue;
386
0
        break;
387
0
      }
388
0
      case 12:
389
0
      {
390
0
        messageType = PostgresMessageType::Backend_AuthenticationSASLFinal;
391
0
        break;
392
0
      }
393
0
      default:
394
0
      {
395
0
        break;
396
0
      }
397
0
      }
398
0
      break;
399
0
    }
400
0
    case PostgresBackendMessage_K:
401
0
    {
402
0
      messageType = PostgresMessageType::Backend_BackendKeyData;
403
0
      break;
404
0
    }
405
0
    case PostgresBackendMessage_2:
406
0
    {
407
0
      messageType = PostgresMessageType::Backend_BindComplete;
408
0
      break;
409
0
    }
410
0
    case PostgresBackendMessage_3:
411
0
    {
412
0
      messageType = PostgresMessageType::Backend_CloseComplete;
413
0
      break;
414
0
    }
415
0
    case PostgresBackendMessage_S:
416
0
    {
417
0
      return std::make_unique<PostgresParameterStatus>(data, messageLength + 1);
418
0
    }
419
0
    case PostgresBackendMessage_Z:
420
0
    {
421
0
      messageType = PostgresMessageType::Backend_ReadyForQuery;
422
0
      break;
423
0
    }
424
0
    case PostgresBackendMessage_C:
425
0
    {
426
0
      messageType = PostgresMessageType::Backend_CommandComplete;
427
0
      break;
428
0
    }
429
0
    case PostgresBackendMessage_d:
430
0
    {
431
0
      messageType = PostgresMessageType::Backend_CopyData;
432
0
      break;
433
0
    }
434
0
    case PostgresBackendMessage_c:
435
0
    {
436
0
      messageType = PostgresMessageType::Backend_CopyDone;
437
0
      break;
438
0
    }
439
0
    case PostgresBackendMessage_G:
440
0
    {
441
0
      messageType = PostgresMessageType::Backend_CopyInResponse;
442
0
      break;
443
0
    }
444
0
    case PostgresBackendMessage_H:
445
0
    {
446
0
      messageType = PostgresMessageType::Backend_CopyOutResponse;
447
0
      break;
448
0
    }
449
0
    case PostgresBackendMessage_W:
450
0
    {
451
0
      messageType = PostgresMessageType::Backend_CopyBothResponse;
452
0
      break;
453
0
    }
454
0
    case PostgresBackendMessage_D:
455
0
    {
456
0
      return std::make_unique<PostgresDataRowMessage>(data, messageLength + 1);
457
0
    }
458
0
    case PostgresBackendMessage_I:
459
0
    {
460
0
      messageType = PostgresMessageType::Backend_EmptyQueryResponse;
461
0
      break;
462
0
    }
463
0
    case PostgresBackendMessage_E:
464
0
    {
465
0
      return std::make_unique<PostgresErrorResponseMessage>(data, messageLength + 1);
466
0
    }
467
0
    case PostgresBackendMessage_V:
468
0
    {
469
0
      messageType = PostgresMessageType::Backend_FunctionCallResponse;
470
0
      break;
471
0
    }
472
0
    case PostgresBackendMessage_v:
473
0
    {
474
0
      messageType = PostgresMessageType::Backend_NegotiateProtocolVersion;
475
0
      break;
476
0
    }
477
0
    case PostgresBackendMessage_n:
478
0
    {
479
0
      messageType = PostgresMessageType::Backend_NoData;
480
0
      break;
481
0
    }
482
0
    case PostgresBackendMessage_N:
483
0
    {
484
0
      messageType = PostgresMessageType::Backend_NoticeResponse;
485
0
      break;
486
0
    }
487
0
    case PostgresBackendMessage_A:
488
0
    {
489
0
      messageType = PostgresMessageType::Backend_NotificationResponse;
490
0
      break;
491
0
    }
492
0
    case PostgresBackendMessage_t:
493
0
    {
494
0
      messageType = PostgresMessageType::Backend_ParameterDescription;
495
0
      break;
496
0
    }
497
0
    case PostgresBackendMessage_1:
498
0
    {
499
0
      messageType = PostgresMessageType::Backend_ParseComplete;
500
0
      break;
501
0
    }
502
0
    case PostgresBackendMessage_s:
503
0
    {
504
0
      messageType = PostgresMessageType::Backend_PortalSuspended;
505
0
      break;
506
0
    }
507
0
    case PostgresBackendMessage_T:
508
0
    {
509
0
      return std::make_unique<PostgresRowDescriptionMessage>(data, messageLength + 1);
510
0
    }
511
0
    default:
512
0
    {
513
0
      break;
514
0
    }
515
0
    }
516
517
0
    return std::unique_ptr<PostgresMessage>(new PostgresMessage(data, messageLength + 1, messageType));
518
0
  }
519
520
  std::unique_ptr<PostgresMessage> PostgresMessage::parsePostgresFrontendMessage(const uint8_t* data, size_t dataLen)
521
10
  {
522
10
    if (data == nullptr || dataLen < 1)
523
0
    {
524
0
      return nullptr;
525
0
    }
526
527
10
    uint8_t messageTypeValue = data[0];
528
10
    if (messageTypeValue == PostgresMessage_0)
529
3
    {
530
3
      if (dataLen < 8)
531
0
      {
532
0
        return std::unique_ptr<PostgresMessage>(
533
0
            new PostgresMessage(data, dataLen, PostgresMessageType::Frontend_Unknown));
534
0
      }
535
536
3
      auto messageLength = be32toh(*reinterpret_cast<const uint32_t*>(data));
537
3
      if (messageLength > dataLen)
538
2
      {
539
2
        return std::unique_ptr<PostgresMessage>(
540
2
            new PostgresMessage(data, dataLen, PostgresMessageType::Frontend_Unknown));
541
2
      }
542
543
1
      auto messageTag = be32toh(*reinterpret_cast<const uint32_t*>(data + 4));
544
1
      auto messageType = PostgresMessageType::Frontend_Unknown;
545
546
1
      switch (messageTag)
547
1
      {
548
0
      case PostgresFrontendTag_StartupMessage:
549
0
      {
550
0
        return std::make_unique<PostgresStartupMessage>(data, messageLength);
551
0
      }
552
0
      case PostgresFrontendTag_SSLRequest:
553
0
      {
554
0
        messageType = PostgresMessageType::Frontend_SSLRequest;
555
0
        break;
556
0
      }
557
0
      case PostgresFrontendTag_CancelRequest:
558
0
      {
559
0
        messageType = PostgresMessageType::Frontend_CancelRequest;
560
0
        break;
561
0
      }
562
0
      case PostgresFrontendTag_GSSENCRequest:
563
0
      {
564
0
        messageType = PostgresMessageType::Frontend_GSSENCRequest;
565
0
        break;
566
0
      }
567
1
      default:
568
1
      {
569
1
        break;
570
0
      }
571
1
      }
572
573
1
      return std::unique_ptr<PostgresMessage>(new PostgresMessage(data, messageLength, messageType));
574
1
    }
575
576
7
    if (dataLen < 5)
577
2
    {
578
2
      return std::unique_ptr<PostgresMessage>(
579
2
          new PostgresMessage(data, dataLen, PostgresMessageType::Frontend_Unknown));
580
2
    }
581
582
5
    auto messageLength = be32toh(*reinterpret_cast<const uint32_t*>(data + 1));
583
5
    if (dataLen < messageLength + 1)
584
4
    {
585
4
      return std::unique_ptr<PostgresMessage>(
586
4
          new PostgresMessage(data, dataLen, PostgresMessageType::Frontend_Unknown));
587
4
    }
588
589
1
    auto messageType = PostgresMessageType::Frontend_Unknown;
590
1
    switch (messageTypeValue)
591
1
    {
592
0
    case PostgresFrontendMessage_Q:
593
0
    {
594
0
      return std::make_unique<PostgresQueryMessage>(data,
595
0
                                                    (std::min)(static_cast<size_t>(messageLength) + 1, dataLen));
596
0
    }
597
0
    case PostgresFrontendMessage_P:
598
0
    {
599
0
      messageType = PostgresMessageType::Frontend_Parse;
600
0
      break;
601
0
    }
602
0
    case PostgresFrontendMessage_B:
603
0
    {
604
0
      messageType = PostgresMessageType::Frontend_Bind;
605
0
      break;
606
0
    }
607
0
    case PostgresFrontendMessage_E:
608
0
    {
609
0
      messageType = PostgresMessageType::Frontend_Execute;
610
0
      break;
611
0
    }
612
0
    case PostgresFrontendMessage_C:
613
0
    {
614
0
      messageType = PostgresMessageType::Frontend_Close;
615
0
      break;
616
0
    }
617
0
    case PostgresFrontendMessage_D:
618
0
    {
619
0
      messageType = PostgresMessageType::Frontend_Describe;
620
0
      break;
621
0
    }
622
0
    case PostgresFrontendMessage_F:
623
0
    {
624
0
      messageType = PostgresMessageType::Frontend_FunctionCall;
625
0
      break;
626
0
    }
627
0
    case PostgresFrontendMessage_H:
628
0
    {
629
0
      messageType = PostgresMessageType::Frontend_Flush;
630
0
      break;
631
0
    }
632
0
    case PostgresFrontendMessage_S:
633
0
    {
634
0
      messageType = PostgresMessageType::Frontend_Sync;
635
0
      break;
636
0
    }
637
0
    case PostgresFrontendMessage_d:
638
0
    {
639
0
      messageType = PostgresMessageType::Frontend_CopyData;
640
0
      break;
641
0
    }
642
0
    case PostgresFrontendMessage_c:
643
0
    {
644
0
      messageType = PostgresMessageType::Frontend_CopyDone;
645
0
      break;
646
0
    }
647
0
    case PostgresFrontendMessage_f:
648
0
    {
649
0
      messageType = PostgresMessageType::Frontend_CopyFail;
650
0
      break;
651
0
    }
652
0
    case PostgresFrontendMessage_X:
653
0
    {
654
0
      messageType = PostgresMessageType::Frontend_Terminate;
655
0
      break;
656
0
    }
657
1
    default:
658
1
    {
659
1
      break;
660
0
    }
661
1
    }
662
663
1
    return std::unique_ptr<PostgresMessage>(new PostgresMessage(data, messageLength + 1, messageType));
664
1
  }
665
666
  uint32_t PostgresMessage::getMessageLength() const
667
0
  {
668
0
    if (m_Data == nullptr || m_DataLen < 5)
669
0
    {
670
0
      return 0;
671
0
    }
672
673
0
    const auto offset = (m_Data[0] == 0) ? 0 : 1;
674
0
    return be32toh(*reinterpret_cast<const uint32_t*>(m_Data + offset));
675
0
  }
676
677
  std::vector<uint8_t> PostgresMessage::getRawPayload() const
678
0
  {
679
0
    const size_t offset = (m_Data[0] == 0) ? 0 : 1;
680
0
    if (m_DataLen < offset + 4)
681
0
    {
682
0
      return {};
683
0
    }
684
0
    return { m_Data + offset + 4, m_Data + m_DataLen };
685
0
  }
686
687
  std::string PostgresParameterStatus::getParameterName() const
688
0
  {
689
0
    constexpr size_t headerLen = 5;
690
691
0
    if (m_DataLen < headerLen + 1)
692
0
    {
693
0
      return {};
694
0
    }
695
696
0
    const auto* start = reinterpret_cast<const char*>(m_Data + headerLen);
697
0
    const auto* end = start + m_DataLen - headerLen;
698
0
    end = std::find(start, end, '\0');
699
700
0
    return { start, end };
701
0
  }
702
703
  std::string PostgresParameterStatus::getParameterValue() const
704
0
  {
705
0
    constexpr size_t headerLen = 5;
706
707
0
    if (m_DataLen < headerLen + 1)
708
0
    {
709
0
      return "";
710
0
    }
711
712
0
    const char* base = reinterpret_cast<const char*>(m_Data) + headerLen;
713
0
    const char* baseEnd = base + m_DataLen - headerLen;
714
715
0
    const char* nameEnd = std::find(base, baseEnd, '\0');
716
0
    if (nameEnd >= baseEnd || nameEnd + 1 >= baseEnd)
717
0
    {
718
0
      return "";
719
0
    }
720
721
0
    const char* valueStart = nameEnd + 1;
722
0
    const char* valueEnd = std::find(valueStart, baseEnd, '\0');
723
724
0
    return { valueStart, valueEnd };
725
0
  }
726
727
  std::string PostgresQueryMessage::getQuery() const
728
0
  {
729
0
    constexpr size_t headerLen = 5;
730
731
0
    if (m_DataLen < headerLen + 1)
732
0
    {
733
0
      return "";
734
0
    }
735
736
0
    const char* queryStart = reinterpret_cast<const char*>(m_Data) + headerLen;
737
0
    const char* queryEnd = queryStart + m_DataLen - headerLen;
738
0
    queryEnd = std::find(queryStart, queryEnd, '\0');
739
0
    return { queryStart, queryEnd };
740
0
  }
741
742
  std::vector<PostgresRowDescriptionMessage::PostgresColumnInfo> PostgresRowDescriptionMessage::getColumnInfos() const
743
0
  {
744
0
    std::vector<PostgresColumnInfo> columns;
745
746
0
    constexpr size_t headerLen = 7;
747
0
    if (m_DataLen < headerLen)
748
0
      return columns;
749
750
0
    uint16_t numFields = be16toh(*reinterpret_cast<const uint16_t*>(m_Data + 5));
751
0
    if (numFields > 10000)
752
0
      return columns;
753
754
0
    const char* iter = reinterpret_cast<const char*>(m_Data) + headerLen;
755
0
    const char* end = reinterpret_cast<const char*>(m_Data) + m_DataLen;
756
757
0
    for (uint16_t i = 0; i < numFields; ++i)
758
0
    {
759
0
      if (iter >= end)
760
0
        break;
761
762
0
      PostgresColumnInfo column;
763
764
0
      const char* nameEnd = std::find(iter, end, '\0');
765
0
      if (nameEnd == end)
766
0
      {
767
0
        break;
768
0
      }
769
770
0
      column.name.assign(iter, nameEnd);
771
772
      // +1 offset because the nameEnd is currently at the null terminator of column name.
773
0
      if (end - nameEnd < static_cast<std::ptrdiff_t>(sizeof(::internal::PostgresColumnFixedData) + 1))
774
0
      {
775
0
        columns.push_back(column);
776
0
        break;
777
0
      }
778
779
0
      iter = nameEnd + 1;
780
781
0
      const auto* fixedData = reinterpret_cast<const ::internal::PostgresColumnFixedData*>(iter);
782
0
      column.tableOID = be32toh(fixedData->tableOID);
783
0
      column.columnIndex = be16toh(fixedData->columnIndex);
784
0
      column.typeOID = be32toh(fixedData->typeOID);
785
0
      column.typeSize = be16toh(fixedData->typeSize);
786
0
      column.typeModifier = be32toh(fixedData->typeModifier);
787
0
      auto formatCode = be16toh(fixedData->formatCode);
788
0
      column.format =
789
0
          formatCode < 2 ? static_cast<PostgresColumnFormat>(formatCode) : PostgresColumnFormat::Unknown;
790
791
0
      iter += sizeof(::internal::PostgresColumnFixedData);
792
0
      columns.push_back(column);
793
0
    }
794
795
0
    return columns;
796
0
  }
797
798
  std::vector<PostgresDataRowMessage::ColumnData> PostgresDataRowMessage::getDataRow() const
799
0
  {
800
0
    constexpr size_t headerLen = 7;
801
0
    if (m_DataLen < headerLen)
802
0
    {
803
0
      return {};
804
0
    }
805
806
0
    uint16_t numColumns = be16toh(*reinterpret_cast<const uint16_t*>(m_Data + 5));
807
0
    if (numColumns > 10000)
808
0
    {
809
0
      return {};
810
0
    }
811
812
0
    std::vector<ColumnData> rowData;
813
814
0
    size_t offset = headerLen;
815
816
0
    for (uint16_t i = 0; i < numColumns; ++i)
817
0
    {
818
0
      if (offset + 4 > m_DataLen)
819
0
      {
820
0
        if (offset < m_DataLen)
821
0
        {
822
0
          rowData.emplace_back(nullptr, 0);
823
0
        }
824
0
        break;
825
0
      }
826
827
0
      const auto colLength = be32toh(*reinterpret_cast<const uint32_t*>(m_Data + offset));
828
0
      offset += 4;
829
830
0
      if (colLength == 0 || colLength == 0xffffffff)
831
0
      {
832
0
        rowData.emplace_back(nullptr, 0);
833
0
        continue;
834
0
      }
835
836
0
      if (offset + colLength > m_DataLen)
837
0
      {
838
0
        break;
839
0
      }
840
841
0
      rowData.emplace_back(m_Data + offset, colLength);
842
0
      offset += colLength;
843
0
    }
844
845
0
    return rowData;
846
0
  }
847
848
  std::string PostgresDataRowMessage::ColumnData::toHexString() const
849
0
  {
850
0
    return byteArrayToHexString(m_Data, m_DataLen);
851
0
  }
852
853
  std::string PostgresDataRowMessage::ColumnData::toString() const
854
0
  {
855
0
    if (m_Data == nullptr || m_DataLen == 0)
856
0
    {
857
0
      return "";
858
0
    }
859
860
0
    return { m_Data, m_Data + m_DataLen };
861
0
  }
862
863
  const PostgresErrorResponseMessage::FieldMap& PostgresErrorResponseMessage::getFields() const
864
0
  {
865
0
    if (m_FieldsParsed)
866
0
    {
867
0
      return m_Fields;
868
0
    }
869
870
0
    constexpr auto headerLen = static_cast<size_t>(5);
871
0
    if (m_DataLen < headerLen)
872
0
    {
873
0
      m_FieldsParsed = true;
874
0
      return m_Fields;
875
0
    }
876
877
0
    auto offset = headerLen;
878
0
    while (offset < m_DataLen)
879
0
    {
880
0
      auto fieldTypeValue = m_Data[offset];
881
0
      if (fieldTypeValue == 0)
882
0
      {
883
0
        break;
884
0
      }
885
886
0
      const bool isKnownField = validErrorFieldTypes.find(fieldTypeValue) != validErrorFieldTypes.end();
887
888
0
      offset++;
889
0
      if (offset >= m_DataLen)
890
0
      {
891
0
        break;
892
0
      }
893
894
0
      auto* valueStart = reinterpret_cast<const char*>(m_Data) + offset;
895
0
      auto remaining = m_DataLen - offset;
896
0
      auto* nullPos = static_cast<const char*>(memchr(valueStart, '\0', remaining));
897
898
0
      std::string fieldValue;
899
0
      if (nullPos != nullptr)
900
0
      {
901
0
        fieldValue.assign(valueStart, nullPos - valueStart);
902
0
        offset = static_cast<size_t>(nullPos - reinterpret_cast<const char*>(m_Data)) + 1;
903
0
      }
904
0
      else
905
0
      {
906
0
        fieldValue.assign(valueStart, remaining);
907
0
        break;
908
0
      }
909
910
0
      if (isKnownField)
911
0
      {
912
0
        const auto fieldType = static_cast<ErrorField>(fieldTypeValue);
913
0
        m_Fields[fieldType] = std::move(fieldValue);
914
0
      }
915
0
    }
916
917
0
    m_FieldsParsed = true;
918
0
    return m_Fields;
919
0
  }
920
921
  uint32_t PostgresStartupMessage::getProtocolVersion() const
922
0
  {
923
0
    if (m_DataLen < MinStartupMessageLength)
924
0
    {
925
0
      return 0;
926
0
    }
927
0
    return *reinterpret_cast<const uint32_t*>(m_Data + ProtocolVersionOffset);
928
0
  }
929
930
  uint16_t PostgresStartupMessage::getProtocolMajorVersion() const
931
0
  {
932
0
    return be16toh(*reinterpret_cast<const uint16_t*>(m_Data + ProtocolVersionOffset));
933
0
  }
934
935
  uint16_t PostgresStartupMessage::getProtocolMinorVersion() const
936
0
  {
937
0
    return be16toh(*reinterpret_cast<const uint16_t*>(m_Data + ProtocolVersionOffset + 2));
938
0
  }
939
940
  std::string PostgresStartupMessage::readString(size_t offset) const
941
0
  {
942
0
    if (offset >= m_DataLen)
943
0
    {
944
0
      return "";
945
0
    }
946
947
0
    const auto* strStart = m_Data + offset;
948
0
    const auto* dataEnd = m_Data + m_DataLen;
949
950
0
    const uint8_t* nullPos = std::find(strStart, dataEnd, uint8_t{ 0 });
951
952
0
    if (nullPos == strStart)
953
0
    {
954
0
      return "";
955
0
    }
956
957
0
    return { strStart, nullPos };
958
0
  }
959
960
  const PostgresStartupMessage::ParameterMap& PostgresStartupMessage::getParameters() const
961
0
  {
962
0
    if (m_ParametersParsed)
963
0
    {
964
0
      return m_Parameters;
965
0
    }
966
967
0
    if (m_DataLen < MinStartupMessageLength)
968
0
    {
969
0
      m_ParametersParsed = true;
970
0
      return m_Parameters;
971
0
    }
972
973
0
    size_t offset = MinStartupMessageLength;
974
0
    while (offset < m_DataLen)
975
0
    {
976
0
      auto name = readString(offset);
977
0
      if (name.empty())
978
0
      {
979
0
        break;
980
0
      }
981
0
      offset += name.length() + 1;
982
983
0
      if (offset >= m_DataLen)
984
0
      {
985
0
        break;
986
0
      }
987
0
      auto value = readString(offset);
988
0
      offset += value.length() + 1;
989
990
0
      m_Parameters.emplace(std::move(name), std::move(value));
991
0
    }
992
993
0
    m_ParametersParsed = true;
994
0
    return m_Parameters;
995
0
  }
996
997
  std::string PostgresStartupMessage::getParameter(const std::string& name) const
998
0
  {
999
0
    auto parameters = getParameters();
1000
0
    auto it = parameters.find(name);
1001
0
    if (it != parameters.end())
1002
0
    {
1003
0
      return it->second;
1004
0
    }
1005
0
    return "";
1006
0
  }
1007
1008
  PostgresLayer* PostgresLayer::parsePostgresBackendMessages(uint8_t* data, size_t dataLen, Layer* prevLayer,
1009
                                                             Packet* packet)
1010
30
  {
1011
30
    return new PostgresLayer(data, dataLen, prevLayer, packet, PostgresMessageOrigin::Backend);
1012
30
  }
1013
1014
  PostgresLayer* PostgresLayer::parsePostgresFrontendMessages(uint8_t* data, size_t dataLen, Layer* prevLayer,
1015
                                                              Packet* packet)
1016
41
  {
1017
41
    return new PostgresLayer(data, dataLen, prevLayer, packet, PostgresMessageOrigin::Frontend);
1018
41
  }
1019
1020
  const PointerVector<PostgresMessage>& PostgresLayer::getPostgresMessages() const
1021
28
  {
1022
28
    if (!m_MessagesInitialized)
1023
14
    {
1024
14
      auto parseFunc = (m_MessageOrigin == PostgresMessageOrigin::Backend)
1025
14
                           ? &PostgresMessage::parsePostgresBackendMessage
1026
14
                           : &PostgresMessage::parsePostgresFrontendMessage;
1027
1028
14
      auto data = m_Data;
1029
14
      auto dataLen = m_DataLen;
1030
1031
30
      while (dataLen > 0)
1032
16
      {
1033
16
        auto curMessage = parseFunc(data, dataLen);
1034
16
        if (curMessage == nullptr)
1035
0
        {
1036
0
          break;
1037
0
        }
1038
1039
16
        dataLen -= curMessage->getTotalMessageLength();
1040
16
        data += curMessage->getTotalMessageLength();
1041
16
        m_Messages.pushBack(std::move(curMessage));
1042
16
      }
1043
1044
14
      m_MessagesInitialized = true;
1045
14
    }
1046
1047
28
    return m_Messages;
1048
28
  }
1049
1050
  const PostgresMessage* PostgresLayer::getPostgresMessage(const PostgresMessageType& messageType) const
1051
0
  {
1052
0
    const auto& messages = getPostgresMessages();
1053
0
    auto it = std::find_if(messages.begin(), messages.end(), [&messageType](const PostgresMessage* message) {
1054
0
      return message->getMessageType() == messageType;
1055
0
    });
1056
1057
0
    return it != messages.end() ? *it : nullptr;
1058
0
  }
1059
1060
  std::string PostgresLayer::toString() const
1061
28
  {
1062
28
    const auto& messages = getPostgresMessages();
1063
28
    return std::string("PostgreSQL ") +
1064
28
           (m_MessageOrigin == PostgresMessageOrigin::Frontend ? "Frontend" : "Backend") + " Layer, " +
1065
28
           std::to_string(messages.size()) + " message(s)";
1066
28
  }
1067
}  // namespace pcpp