Coverage Report

Created: 2025-07-01 06:46

/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
static BOOL Pcap_Write_Header(wPcap* pcap, wPcapHeader* header)
45
0
{
46
0
  if (pcap && pcap->fp && fwrite((void*)header, sizeof(wPcapHeader), 1, pcap->fp) == 1)
47
0
    return TRUE;
48
0
  return FALSE;
49
0
}
50
51
static BOOL Pcap_Write_RecordHeader(wPcap* pcap, wPcapRecordHeader* record)
52
0
{
53
0
  if (pcap && pcap->fp && fwrite((void*)record, sizeof(wPcapRecordHeader), 1, pcap->fp) == 1)
54
0
    return TRUE;
55
0
  return FALSE;
56
0
}
57
58
static BOOL Pcap_Write_RecordContent(wPcap* pcap, wPcapRecord* record)
59
0
{
60
0
  if (pcap && pcap->fp && fwrite(record->data, record->length, 1, pcap->fp) == 1)
61
0
    return TRUE;
62
0
  return FALSE;
63
0
}
64
65
static BOOL Pcap_Write_Record(wPcap* pcap, wPcapRecord* record)
66
0
{
67
0
  return Pcap_Write_RecordHeader(pcap, &record->header) && Pcap_Write_RecordContent(pcap, record);
68
0
}
69
70
wPcap* Pcap_Open(char* name, BOOL write)
71
0
{
72
0
  wPcap* pcap = NULL;
73
0
  FILE* pcap_fp = winpr_fopen(name, write ? "w+b" : "rb");
74
75
0
  if (!pcap_fp)
76
0
  {
77
0
    WLog_ERR(TAG, "opening pcap file");
78
0
    return NULL;
79
0
  }
80
81
0
  pcap = (wPcap*)calloc(1, sizeof(wPcap));
82
83
0
  if (!pcap)
84
0
    goto out_fail;
85
86
0
  pcap->name = name;
87
0
  pcap->write = write;
88
0
  pcap->record_count = 0;
89
0
  pcap->fp = pcap_fp;
90
91
0
  if (write)
92
0
  {
93
0
    pcap->header.magic_number = PCAP_MAGIC_NUMBER;
94
0
    pcap->header.version_major = 2;
95
0
    pcap->header.version_minor = 4;
96
0
    pcap->header.thiszone = 0;
97
0
    pcap->header.sigfigs = 0;
98
0
    pcap->header.snaplen = 0xFFFFFFFF;
99
0
    pcap->header.network = 1; /* ethernet */
100
0
    if (!Pcap_Write_Header(pcap, &pcap->header))
101
0
      goto out_fail;
102
0
  }
103
0
  else
104
0
  {
105
0
    if (_fseeki64(pcap->fp, 0, SEEK_END) < 0)
106
0
      goto out_fail;
107
0
    pcap->file_size = (SSIZE_T)_ftelli64(pcap->fp);
108
0
    if (pcap->file_size < 0)
109
0
      goto out_fail;
110
0
    if (_fseeki64(pcap->fp, 0, SEEK_SET) < 0)
111
0
      goto out_fail;
112
0
    if (!Pcap_Read_Header(pcap, &pcap->header))
113
0
      goto out_fail;
114
0
  }
115
116
0
  return pcap;
117
118
0
out_fail:
119
0
  if (pcap_fp)
120
0
    (void)fclose(pcap_fp);
121
0
  free(pcap);
122
0
  return NULL;
123
0
}
124
125
void Pcap_Flush(wPcap* pcap)
126
0
{
127
0
  if (!pcap || !pcap->fp)
128
0
    return;
129
130
0
  while (pcap->record)
131
0
  {
132
0
    if (!Pcap_Write_Record(pcap, pcap->record))
133
0
      return;
134
0
    pcap->record = pcap->record->next;
135
0
  }
136
137
0
  (void)fflush(pcap->fp);
138
0
}
139
140
void Pcap_Close(wPcap* pcap)
141
0
{
142
0
  if (!pcap || !pcap->fp)
143
0
    return;
144
145
0
  Pcap_Flush(pcap);
146
0
  (void)fclose(pcap->fp);
147
0
  free(pcap);
148
0
}
149
150
static BOOL WLog_PacketMessage_Write_EthernetHeader(wPcap* pcap, wEthernetHeader* ethernet)
151
0
{
152
0
  wStream* s = NULL;
153
0
  wStream sbuffer = { 0 };
154
0
  BYTE buffer[14] = { 0 };
155
0
  BOOL ret = TRUE;
156
157
0
  if (!pcap || !pcap->fp || !ethernet)
158
0
    return FALSE;
159
160
0
  s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
161
0
  if (!s)
162
0
    return FALSE;
163
0
  Stream_Write(s, ethernet->Destination, 6);
164
0
  Stream_Write(s, ethernet->Source, 6);
165
0
  Stream_Write_UINT16_BE(s, ethernet->Type);
166
0
  if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
167
0
    ret = FALSE;
168
169
0
  return ret;
170
0
}
171
172
static UINT16 IPv4Checksum(const BYTE* ipv4, int length)
173
0
{
174
0
  long checksum = 0;
175
176
0
  while (length > 1)
177
0
  {
178
0
    const UINT16 tmp16 = *((const UINT16*)ipv4);
179
0
    checksum += tmp16;
180
0
    length -= 2;
181
0
    ipv4 += 2;
182
0
  }
183
184
0
  if (length > 0)
185
0
    checksum += *ipv4;
186
187
0
  while (checksum >> 16)
188
0
    checksum = (checksum & 0xFFFF) + (checksum >> 16);
189
190
0
  return (UINT16)(~checksum);
191
0
}
192
193
static BOOL WLog_PacketMessage_Write_IPv4Header(wPcap* pcap, wIPv4Header* ipv4)
194
0
{
195
0
  wStream* s = NULL;
196
0
  wStream sbuffer = { 0 };
197
0
  BYTE buffer[20] = { 0 };
198
0
  int ret = TRUE;
199
200
0
  if (!pcap || !pcap->fp || !ipv4)
201
0
    return FALSE;
202
203
0
  s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
204
0
  if (!s)
205
0
    return FALSE;
206
0
  Stream_Write_UINT8(s, (BYTE)((ipv4->Version << 4) | ipv4->InternetHeaderLength));
207
0
  Stream_Write_UINT8(s, ipv4->TypeOfService);
208
0
  Stream_Write_UINT16_BE(s, ipv4->TotalLength);
209
0
  Stream_Write_UINT16_BE(s, ipv4->Identification);
210
0
  Stream_Write_UINT16_BE(s, (UINT16)((ipv4->InternetProtocolFlags << 13) | ipv4->FragmentOffset));
211
0
  Stream_Write_UINT8(s, ipv4->TimeToLive);
212
0
  Stream_Write_UINT8(s, ipv4->Protocol);
213
0
  Stream_Write_UINT16(s, ipv4->HeaderChecksum);
214
0
  Stream_Write_UINT32_BE(s, ipv4->SourceAddress);
215
0
  Stream_Write_UINT32_BE(s, ipv4->DestinationAddress);
216
0
  ipv4->HeaderChecksum = IPv4Checksum((BYTE*)buffer, 20);
217
0
  Stream_Rewind(s, 10);
218
0
  Stream_Write_UINT16(s, ipv4->HeaderChecksum);
219
220
0
  if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
221
0
    ret = FALSE;
222
223
0
  return ret;
224
0
}
225
226
static BOOL WLog_PacketMessage_Write_TcpHeader(wPcap* pcap, wTcpHeader* tcp)
227
0
{
228
0
  wStream* s = NULL;
229
0
  wStream sbuffer = { 0 };
230
0
  BYTE buffer[20] = { 0 };
231
0
  BOOL ret = TRUE;
232
233
0
  if (!pcap || !pcap->fp || !tcp)
234
0
    return FALSE;
235
236
0
  s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
237
0
  if (!s)
238
0
    return FALSE;
239
0
  Stream_Write_UINT16_BE(s, tcp->SourcePort);
240
0
  Stream_Write_UINT16_BE(s, tcp->DestinationPort);
241
0
  Stream_Write_UINT32_BE(s, tcp->SequenceNumber);
242
0
  Stream_Write_UINT32_BE(s, tcp->AcknowledgementNumber);
243
0
  Stream_Write_UINT8(s, (UINT8)((tcp->Offset << 4) | (tcp->Reserved & 0xF)));
244
0
  Stream_Write_UINT8(s, tcp->TcpFlags);
245
0
  Stream_Write_UINT16_BE(s, tcp->Window);
246
0
  Stream_Write_UINT16_BE(s, tcp->Checksum);
247
0
  Stream_Write_UINT16_BE(s, tcp->UrgentPointer);
248
249
0
  if (pcap->fp)
250
0
  {
251
0
    if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
252
0
      ret = FALSE;
253
0
  }
254
255
0
  return ret;
256
0
}
257
258
static UINT32 g_InboundSequenceNumber = 0;
259
static UINT32 g_OutboundSequenceNumber = 0;
260
261
BOOL WLog_PacketMessage_Write(wPcap* pcap, void* data, size_t length, DWORD flags)
262
0
{
263
0
  wTcpHeader tcp;
264
0
  wIPv4Header ipv4;
265
0
  wPcapRecord record;
266
0
  wEthernetHeader ethernet;
267
0
  ethernet.Type = 0x0800;
268
269
0
  if (!pcap || !pcap->fp)
270
0
    return FALSE;
271
272
0
  if (flags & WLOG_PACKET_OUTBOUND)
273
0
  {
274
    /* 00:15:5D:01:64:04 */
275
0
    ethernet.Source[0] = 0x00;
276
0
    ethernet.Source[1] = 0x15;
277
0
    ethernet.Source[2] = 0x5D;
278
0
    ethernet.Source[3] = 0x01;
279
0
    ethernet.Source[4] = 0x64;
280
0
    ethernet.Source[5] = 0x04;
281
    /* 00:15:5D:01:64:01 */
282
0
    ethernet.Destination[0] = 0x00;
283
0
    ethernet.Destination[1] = 0x15;
284
0
    ethernet.Destination[2] = 0x5D;
285
0
    ethernet.Destination[3] = 0x01;
286
0
    ethernet.Destination[4] = 0x64;
287
0
    ethernet.Destination[5] = 0x01;
288
0
  }
289
0
  else
290
0
  {
291
    /* 00:15:5D:01:64:01 */
292
0
    ethernet.Source[0] = 0x00;
293
0
    ethernet.Source[1] = 0x15;
294
0
    ethernet.Source[2] = 0x5D;
295
0
    ethernet.Source[3] = 0x01;
296
0
    ethernet.Source[4] = 0x64;
297
0
    ethernet.Source[5] = 0x01;
298
    /* 00:15:5D:01:64:04 */
299
0
    ethernet.Destination[0] = 0x00;
300
0
    ethernet.Destination[1] = 0x15;
301
0
    ethernet.Destination[2] = 0x5D;
302
0
    ethernet.Destination[3] = 0x01;
303
0
    ethernet.Destination[4] = 0x64;
304
0
    ethernet.Destination[5] = 0x04;
305
0
  }
306
307
0
  ipv4.Version = 4;
308
0
  ipv4.InternetHeaderLength = 5;
309
0
  ipv4.TypeOfService = 0;
310
0
  ipv4.TotalLength = (UINT16)(length + 20 + 20);
311
0
  ipv4.Identification = 0;
312
0
  ipv4.InternetProtocolFlags = 0x02;
313
0
  ipv4.FragmentOffset = 0;
314
0
  ipv4.TimeToLive = 128;
315
0
  ipv4.Protocol = 6; /* TCP */
316
0
  ipv4.HeaderChecksum = 0;
317
318
0
  if (flags & WLOG_PACKET_OUTBOUND)
319
0
  {
320
0
    ipv4.SourceAddress = 0xC0A80196;      /* 192.168.1.150 */
321
0
    ipv4.DestinationAddress = 0x4A7D64C8; /* 74.125.100.200 */
322
0
  }
323
0
  else
324
0
  {
325
0
    ipv4.SourceAddress = 0x4A7D64C8;      /* 74.125.100.200 */
326
0
    ipv4.DestinationAddress = 0xC0A80196; /* 192.168.1.150 */
327
0
  }
328
329
0
  tcp.SourcePort = 3389;
330
0
  tcp.DestinationPort = 3389;
331
332
0
  if (flags & WLOG_PACKET_OUTBOUND)
333
0
  {
334
0
    tcp.SequenceNumber = g_OutboundSequenceNumber;
335
0
    tcp.AcknowledgementNumber = g_InboundSequenceNumber;
336
0
    WINPR_ASSERT(length + g_OutboundSequenceNumber <= UINT32_MAX);
337
0
    g_OutboundSequenceNumber += WINPR_ASSERTING_INT_CAST(uint32_t, length);
338
0
  }
339
0
  else
340
0
  {
341
0
    tcp.SequenceNumber = g_InboundSequenceNumber;
342
0
    tcp.AcknowledgementNumber = g_OutboundSequenceNumber;
343
344
0
    WINPR_ASSERT(length + g_InboundSequenceNumber <= UINT32_MAX);
345
0
    g_InboundSequenceNumber += WINPR_ASSERTING_INT_CAST(uint32_t, length);
346
0
  }
347
348
0
  tcp.Offset = 5;
349
0
  tcp.Reserved = 0;
350
0
  tcp.TcpFlags = 0x0018;
351
0
  tcp.Window = 0x7FFF;
352
0
  tcp.Checksum = 0;
353
0
  tcp.UrgentPointer = 0;
354
0
  record.data = data;
355
0
  record.length = length;
356
0
  const size_t offset = 14 + 20 + 20;
357
0
  WINPR_ASSERT(record.length <= UINT32_MAX - offset);
358
0
  const uint32_t rloff = WINPR_ASSERTING_INT_CAST(uint32_t, record.length + offset);
359
0
  record.header.incl_len = rloff;
360
0
  record.header.orig_len = rloff;
361
0
  record.next = NULL;
362
363
0
  UINT64 ns = winpr_GetUnixTimeNS();
364
0
  record.header.ts_sec = (UINT32)WINPR_TIME_NS_TO_S(ns);
365
0
  record.header.ts_usec = WINPR_TIME_NS_REM_US(ns);
366
367
0
  if (!Pcap_Write_RecordHeader(pcap, &record.header) ||
368
0
      !WLog_PacketMessage_Write_EthernetHeader(pcap, &ethernet) ||
369
0
      !WLog_PacketMessage_Write_IPv4Header(pcap, &ipv4) ||
370
0
      !WLog_PacketMessage_Write_TcpHeader(pcap, &tcp) || !Pcap_Write_RecordContent(pcap, &record))
371
0
    return FALSE;
372
0
  (void)fflush(pcap->fp);
373
0
  return TRUE;
374
0
}