Coverage Report

Created: 2024-09-08 06:20

/src/FreeRDP/winpr/libwinpr/utils/wlog/PacketMessage.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * WinPR Logger
4
 *
5
 * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2015 Thincast Technologies GmbH
7
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <winpr/config.h>
23
24
#include "wlog.h"
25
26
#include "PacketMessage.h"
27
28
#include <winpr/wtypes.h>
29
#include <winpr/crt.h>
30
#include <winpr/file.h>
31
#include <winpr/stream.h>
32
#include <winpr/sysinfo.h>
33
34
#include "../../log.h"
35
#define TAG WINPR_TAG("utils.wlog")
36
37
static BOOL Pcap_Read_Header(wPcap* pcap, wPcapHeader* header)
38
0
{
39
0
  if (pcap && pcap->fp && fread((void*)header, sizeof(wPcapHeader), 1, pcap->fp) == 1)
40
0
    return TRUE;
41
0
  return FALSE;
42
0
}
43
44
/* currently unused code */
45
#if 0
46
static BOOL Pcap_Read_RecordHeader(wPcap* pcap, wPcapRecordHeader* record)
47
{
48
  if (pcap && pcap->fp && (fread((void*) record, sizeof(wPcapRecordHeader), 1, pcap->fp) == 1))
49
    return TRUE;
50
  return FALSE;
51
}
52
53
static BOOL Pcap_Read_Record(wPcap* pcap, wPcapRecord* record)
54
{
55
  if (pcap && pcap->fp)
56
  {
57
    if (!Pcap_Read_RecordHeader(pcap, &record->header))
58
      return FALSE;
59
    record->length = record->header.incl_len;
60
    record->data = malloc(record->length);
61
    if (!record->data)
62
      return FALSE;
63
    if (fread(record->data, record->length, 1, pcap->fp) != 1)
64
    {
65
      free(record->data);
66
      record->length = 0;
67
      record->data = NULL;
68
      return FALSE;
69
    }
70
  }
71
  return TRUE;
72
}
73
74
static BOOL Pcap_Add_Record(wPcap* pcap, void* data, UINT32 length)
75
{
76
  wPcapRecord* record = NULL;
77
78
  if (!pcap->tail)
79
  {
80
    pcap->tail = (wPcapRecord*) calloc(1, sizeof(wPcapRecord));
81
    if (!pcap->tail)
82
      return FALSE;
83
    pcap->head = pcap->tail;
84
    pcap->record = pcap->head;
85
    record = pcap->tail;
86
  }
87
  else
88
  {
89
    record = (wPcapRecord*) calloc(1, sizeof(wPcapRecord));
90
    if (!record)
91
      return FALSE;
92
    pcap->tail->next = record;
93
    pcap->tail = record;
94
  }
95
96
  if (!pcap->record)
97
    pcap->record = record;
98
99
  record->data = data;
100
  record->length = length;
101
  record->header.incl_len = length;
102
  record->header.orig_len = length;
103
104
  UINT64 ns = winpr_GetUnixTimeNS();
105
  record->header.ts_sec = WINPR_TIME_NS_TO_S(ns);
106
  record->header.ts_usec = WINPR_TIME_NS_REM_US(ns);
107
  return TRUE;
108
}
109
110
static BOOL Pcap_HasNext_Record(wPcap* pcap)
111
{
112
  if (pcap->file_size - (_ftelli64(pcap->fp)) <= 16)
113
    return FALSE;
114
115
  return TRUE;
116
}
117
118
static BOOL Pcap_GetNext_RecordHeader(wPcap* pcap, wPcapRecord* record)
119
{
120
  if (!Pcap_HasNext_Record(pcap) || !Pcap_Read_RecordHeader(pcap, &record->header))
121
    return FALSE;
122
123
  record->length = record->header.incl_len;
124
  return TRUE;
125
}
126
127
static BOOL Pcap_GetNext_RecordContent(wPcap* pcap, wPcapRecord* record)
128
{
129
  if (pcap && pcap->fp && fread(record->data, record->length, 1, pcap->fp) == 1)
130
    return TRUE;
131
132
  return FALSE;
133
}
134
135
static BOOL Pcap_GetNext_Record(wPcap* pcap, wPcapRecord* record)
136
{
137
  if (!Pcap_HasNext_Record(pcap))
138
    return FALSE;
139
140
  return Pcap_Read_Record(pcap, record);
141
}
142
#endif
143
144
static BOOL Pcap_Write_Header(wPcap* pcap, wPcapHeader* header)
145
0
{
146
0
  if (pcap && pcap->fp && fwrite((void*)header, sizeof(wPcapHeader), 1, pcap->fp) == 1)
147
0
    return TRUE;
148
0
  return FALSE;
149
0
}
150
151
static BOOL Pcap_Write_RecordHeader(wPcap* pcap, wPcapRecordHeader* record)
152
0
{
153
0
  if (pcap && pcap->fp && fwrite((void*)record, sizeof(wPcapRecordHeader), 1, pcap->fp) == 1)
154
0
    return TRUE;
155
0
  return FALSE;
156
0
}
157
158
static BOOL Pcap_Write_RecordContent(wPcap* pcap, wPcapRecord* record)
159
0
{
160
0
  if (pcap && pcap->fp && fwrite(record->data, record->length, 1, pcap->fp) == 1)
161
0
    return TRUE;
162
0
  return FALSE;
163
0
}
164
165
static BOOL Pcap_Write_Record(wPcap* pcap, wPcapRecord* record)
166
0
{
167
0
  return Pcap_Write_RecordHeader(pcap, &record->header) && Pcap_Write_RecordContent(pcap, record);
168
0
}
169
170
wPcap* Pcap_Open(char* name, BOOL write)
171
0
{
172
0
  wPcap* pcap = NULL;
173
0
  FILE* pcap_fp = winpr_fopen(name, write ? "w+b" : "rb");
174
175
0
  if (!pcap_fp)
176
0
  {
177
0
    WLog_ERR(TAG, "opening pcap file");
178
0
    return NULL;
179
0
  }
180
181
0
  pcap = (wPcap*)calloc(1, sizeof(wPcap));
182
183
0
  if (!pcap)
184
0
    goto out_fail;
185
186
0
  pcap->name = name;
187
0
  pcap->write = write;
188
0
  pcap->record_count = 0;
189
0
  pcap->fp = pcap_fp;
190
191
0
  if (write)
192
0
  {
193
0
    pcap->header.magic_number = PCAP_MAGIC_NUMBER;
194
0
    pcap->header.version_major = 2;
195
0
    pcap->header.version_minor = 4;
196
0
    pcap->header.thiszone = 0;
197
0
    pcap->header.sigfigs = 0;
198
0
    pcap->header.snaplen = 0xFFFFFFFF;
199
0
    pcap->header.network = 1; /* ethernet */
200
0
    if (!Pcap_Write_Header(pcap, &pcap->header))
201
0
      goto out_fail;
202
0
  }
203
0
  else
204
0
  {
205
0
    if (_fseeki64(pcap->fp, 0, SEEK_END) < 0)
206
0
      goto out_fail;
207
0
    pcap->file_size = (SSIZE_T)_ftelli64(pcap->fp);
208
0
    if (pcap->file_size < 0)
209
0
      goto out_fail;
210
0
    if (_fseeki64(pcap->fp, 0, SEEK_SET) < 0)
211
0
      goto out_fail;
212
0
    if (!Pcap_Read_Header(pcap, &pcap->header))
213
0
      goto out_fail;
214
0
  }
215
216
0
  return pcap;
217
218
0
out_fail:
219
0
  if (pcap_fp)
220
0
    (void)fclose(pcap_fp);
221
0
  free(pcap);
222
0
  return NULL;
223
0
}
224
225
void Pcap_Flush(wPcap* pcap)
226
0
{
227
0
  if (!pcap || !pcap->fp)
228
0
    return;
229
230
0
  while (pcap->record)
231
0
  {
232
0
    if (!Pcap_Write_Record(pcap, pcap->record))
233
0
      return;
234
0
    pcap->record = pcap->record->next;
235
0
  }
236
237
0
  (void)fflush(pcap->fp);
238
0
}
239
240
void Pcap_Close(wPcap* pcap)
241
0
{
242
0
  if (!pcap || !pcap->fp)
243
0
    return;
244
245
0
  Pcap_Flush(pcap);
246
0
  (void)fclose(pcap->fp);
247
0
  free(pcap);
248
0
}
249
250
static BOOL WLog_PacketMessage_Write_EthernetHeader(wPcap* pcap, wEthernetHeader* ethernet)
251
0
{
252
0
  wStream* s = NULL;
253
0
  wStream sbuffer = { 0 };
254
0
  BYTE buffer[14] = { 0 };
255
0
  BOOL ret = TRUE;
256
257
0
  if (!pcap || !pcap->fp || !ethernet)
258
0
    return FALSE;
259
260
0
  s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
261
0
  if (!s)
262
0
    return FALSE;
263
0
  Stream_Write(s, ethernet->Destination, 6);
264
0
  Stream_Write(s, ethernet->Source, 6);
265
0
  Stream_Write_UINT16_BE(s, ethernet->Type);
266
0
  if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
267
0
    ret = FALSE;
268
269
0
  return ret;
270
0
}
271
272
static UINT16 IPv4Checksum(const BYTE* ipv4, int length)
273
0
{
274
0
  UINT16 tmp16 = 0;
275
0
  long checksum = 0;
276
277
0
  while (length > 1)
278
0
  {
279
0
    tmp16 = *((UINT16*)ipv4);
280
0
    checksum += tmp16;
281
0
    length -= 2;
282
0
    ipv4 += 2;
283
0
  }
284
285
0
  if (length > 0)
286
0
    checksum += *ipv4;
287
288
0
  while (checksum >> 16)
289
0
    checksum = (checksum & 0xFFFF) + (checksum >> 16);
290
291
0
  return (UINT16)(~checksum);
292
0
}
293
294
static BOOL WLog_PacketMessage_Write_IPv4Header(wPcap* pcap, wIPv4Header* ipv4)
295
0
{
296
0
  wStream* s = NULL;
297
0
  wStream sbuffer = { 0 };
298
0
  BYTE buffer[20] = { 0 };
299
0
  int ret = TRUE;
300
301
0
  if (!pcap || !pcap->fp || !ipv4)
302
0
    return FALSE;
303
304
0
  s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
305
0
  if (!s)
306
0
    return FALSE;
307
0
  Stream_Write_UINT8(s, (ipv4->Version << 4) | ipv4->InternetHeaderLength);
308
0
  Stream_Write_UINT8(s, ipv4->TypeOfService);
309
0
  Stream_Write_UINT16_BE(s, ipv4->TotalLength);
310
0
  Stream_Write_UINT16_BE(s, ipv4->Identification);
311
0
  Stream_Write_UINT16_BE(s, (ipv4->InternetProtocolFlags << 13) | ipv4->FragmentOffset);
312
0
  Stream_Write_UINT8(s, ipv4->TimeToLive);
313
0
  Stream_Write_UINT8(s, ipv4->Protocol);
314
0
  Stream_Write_UINT16(s, ipv4->HeaderChecksum);
315
0
  Stream_Write_UINT32_BE(s, ipv4->SourceAddress);
316
0
  Stream_Write_UINT32_BE(s, ipv4->DestinationAddress);
317
0
  ipv4->HeaderChecksum = IPv4Checksum((BYTE*)buffer, 20);
318
0
  Stream_Rewind(s, 10);
319
0
  Stream_Write_UINT16(s, ipv4->HeaderChecksum);
320
321
0
  if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
322
0
    ret = FALSE;
323
324
0
  return ret;
325
0
}
326
327
static BOOL WLog_PacketMessage_Write_TcpHeader(wPcap* pcap, wTcpHeader* tcp)
328
0
{
329
0
  wStream* s = NULL;
330
0
  wStream sbuffer = { 0 };
331
0
  BYTE buffer[20] = { 0 };
332
0
  BOOL ret = TRUE;
333
334
0
  if (!pcap || !pcap->fp || !tcp)
335
0
    return FALSE;
336
337
0
  s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
338
0
  if (!s)
339
0
    return FALSE;
340
0
  Stream_Write_UINT16_BE(s, tcp->SourcePort);
341
0
  Stream_Write_UINT16_BE(s, tcp->DestinationPort);
342
0
  Stream_Write_UINT32_BE(s, tcp->SequenceNumber);
343
0
  Stream_Write_UINT32_BE(s, tcp->AcknowledgementNumber);
344
0
  Stream_Write_UINT8(s, (tcp->Offset << 4) | tcp->Reserved);
345
0
  Stream_Write_UINT8(s, tcp->TcpFlags);
346
0
  Stream_Write_UINT16_BE(s, tcp->Window);
347
0
  Stream_Write_UINT16_BE(s, tcp->Checksum);
348
0
  Stream_Write_UINT16_BE(s, tcp->UrgentPointer);
349
350
0
  if (pcap->fp)
351
0
  {
352
0
    if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
353
0
      ret = FALSE;
354
0
  }
355
356
0
  return ret;
357
0
}
358
359
static UINT32 g_InboundSequenceNumber = 0;
360
static UINT32 g_OutboundSequenceNumber = 0;
361
362
BOOL WLog_PacketMessage_Write(wPcap* pcap, void* data, size_t length, DWORD flags)
363
0
{
364
0
  wTcpHeader tcp;
365
0
  wIPv4Header ipv4;
366
0
  wPcapRecord record;
367
0
  wEthernetHeader ethernet;
368
0
  ethernet.Type = 0x0800;
369
370
0
  if (!pcap || !pcap->fp)
371
0
    return FALSE;
372
373
0
  if (flags & WLOG_PACKET_OUTBOUND)
374
0
  {
375
    /* 00:15:5D:01:64:04 */
376
0
    ethernet.Source[0] = 0x00;
377
0
    ethernet.Source[1] = 0x15;
378
0
    ethernet.Source[2] = 0x5D;
379
0
    ethernet.Source[3] = 0x01;
380
0
    ethernet.Source[4] = 0x64;
381
0
    ethernet.Source[5] = 0x04;
382
    /* 00:15:5D:01:64:01 */
383
0
    ethernet.Destination[0] = 0x00;
384
0
    ethernet.Destination[1] = 0x15;
385
0
    ethernet.Destination[2] = 0x5D;
386
0
    ethernet.Destination[3] = 0x01;
387
0
    ethernet.Destination[4] = 0x64;
388
0
    ethernet.Destination[5] = 0x01;
389
0
  }
390
0
  else
391
0
  {
392
    /* 00:15:5D:01:64:01 */
393
0
    ethernet.Source[0] = 0x00;
394
0
    ethernet.Source[1] = 0x15;
395
0
    ethernet.Source[2] = 0x5D;
396
0
    ethernet.Source[3] = 0x01;
397
0
    ethernet.Source[4] = 0x64;
398
0
    ethernet.Source[5] = 0x01;
399
    /* 00:15:5D:01:64:04 */
400
0
    ethernet.Destination[0] = 0x00;
401
0
    ethernet.Destination[1] = 0x15;
402
0
    ethernet.Destination[2] = 0x5D;
403
0
    ethernet.Destination[3] = 0x01;
404
0
    ethernet.Destination[4] = 0x64;
405
0
    ethernet.Destination[5] = 0x04;
406
0
  }
407
408
0
  ipv4.Version = 4;
409
0
  ipv4.InternetHeaderLength = 5;
410
0
  ipv4.TypeOfService = 0;
411
0
  ipv4.TotalLength = (UINT16)(length + 20 + 20);
412
0
  ipv4.Identification = 0;
413
0
  ipv4.InternetProtocolFlags = 0x02;
414
0
  ipv4.FragmentOffset = 0;
415
0
  ipv4.TimeToLive = 128;
416
0
  ipv4.Protocol = 6; /* TCP */
417
0
  ipv4.HeaderChecksum = 0;
418
419
0
  if (flags & WLOG_PACKET_OUTBOUND)
420
0
  {
421
0
    ipv4.SourceAddress = 0xC0A80196;      /* 192.168.1.150 */
422
0
    ipv4.DestinationAddress = 0x4A7D64C8; /* 74.125.100.200 */
423
0
  }
424
0
  else
425
0
  {
426
0
    ipv4.SourceAddress = 0x4A7D64C8;      /* 74.125.100.200 */
427
0
    ipv4.DestinationAddress = 0xC0A80196; /* 192.168.1.150 */
428
0
  }
429
430
0
  tcp.SourcePort = 3389;
431
0
  tcp.DestinationPort = 3389;
432
433
0
  if (flags & WLOG_PACKET_OUTBOUND)
434
0
  {
435
0
    tcp.SequenceNumber = g_OutboundSequenceNumber;
436
0
    tcp.AcknowledgementNumber = g_InboundSequenceNumber;
437
0
    g_OutboundSequenceNumber += length;
438
0
  }
439
0
  else
440
0
  {
441
0
    tcp.SequenceNumber = g_InboundSequenceNumber;
442
0
    tcp.AcknowledgementNumber = g_OutboundSequenceNumber;
443
0
    g_InboundSequenceNumber += length;
444
0
  }
445
446
0
  tcp.Offset = 5;
447
0
  tcp.Reserved = 0;
448
0
  tcp.TcpFlags = 0x0018;
449
0
  tcp.Window = 0x7FFF;
450
0
  tcp.Checksum = 0;
451
0
  tcp.UrgentPointer = 0;
452
0
  record.data = data;
453
0
  record.length = length;
454
0
  const size_t offset = 14 + 20 + 20;
455
0
  WINPR_ASSERT(record.length <= UINT32_MAX - offset);
456
0
  record.header.incl_len = (UINT32)record.length + offset;
457
0
  record.header.orig_len = (UINT32)record.length + offset;
458
0
  record.next = NULL;
459
460
0
  UINT64 ns = winpr_GetUnixTimeNS();
461
0
  record.header.ts_sec = WINPR_TIME_NS_TO_S(ns);
462
0
  record.header.ts_usec = WINPR_TIME_NS_REM_US(ns);
463
464
0
  if (!Pcap_Write_RecordHeader(pcap, &record.header) ||
465
0
      !WLog_PacketMessage_Write_EthernetHeader(pcap, &ethernet) ||
466
0
      !WLog_PacketMessage_Write_IPv4Header(pcap, &ipv4) ||
467
0
      !WLog_PacketMessage_Write_TcpHeader(pcap, &tcp) || !Pcap_Write_RecordContent(pcap, &record))
468
0
    return FALSE;
469
0
  (void)fflush(pcap->fp);
470
0
  return TRUE;
471
0
}