Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/utils/pcap.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * pcap File Format Utils
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <freerdp/config.h>
21
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
26
#include <winpr/wtypes.h>
27
#include <winpr/assert.h>
28
#include <winpr/file.h>
29
#include <winpr/crt.h>
30
#include <winpr/sysinfo.h>
31
#include <freerdp/log.h>
32
33
#define TAG FREERDP_TAG("utils")
34
35
#include <freerdp/types.h>
36
#include <freerdp/utils/pcap.h>
37
38
0
#define PCAP_MAGIC 0xA1B2C3D4
39
40
struct rdp_pcap
41
{
42
  FILE* fp;
43
  char* name;
44
  BOOL write;
45
  INT64 file_size;
46
  size_t record_count;
47
  pcap_header header;
48
  pcap_record* head;
49
  pcap_record* tail;
50
  pcap_record* record;
51
};
52
53
static BOOL pcap_read_header(rdpPcap* pcap, pcap_header* header)
54
0
{
55
0
  WINPR_ASSERT(pcap);
56
0
  WINPR_ASSERT(header);
57
58
0
  return fread(header, sizeof(pcap_header), 1, pcap->fp) == 1;
59
0
}
60
61
static BOOL pcap_write_header(rdpPcap* pcap, const pcap_header* header)
62
0
{
63
0
  WINPR_ASSERT(pcap);
64
0
  WINPR_ASSERT(header);
65
66
0
  return fwrite(header, sizeof(pcap_header), 1, pcap->fp) == 1;
67
0
}
68
69
static BOOL pcap_read_record_header(rdpPcap* pcap, pcap_record_header* record)
70
0
{
71
0
  WINPR_ASSERT(pcap);
72
0
  WINPR_ASSERT(record);
73
74
0
  return fread(record, sizeof(pcap_record_header), 1, pcap->fp) == 1;
75
0
}
76
77
static BOOL pcap_write_record_header(rdpPcap* pcap, const pcap_record_header* record)
78
0
{
79
0
  WINPR_ASSERT(pcap);
80
0
  WINPR_ASSERT(record);
81
82
0
  return fwrite(record, sizeof(pcap_record_header), 1, pcap->fp) == 1;
83
0
}
84
85
static BOOL pcap_read_record(rdpPcap* pcap, pcap_record* record)
86
0
{
87
0
  WINPR_ASSERT(pcap);
88
0
  WINPR_ASSERT(record);
89
90
0
  if (!pcap_read_record_header(pcap, &record->header))
91
0
    return FALSE;
92
93
0
  record->length = record->header.incl_len;
94
0
  record->data = malloc(record->length);
95
0
  if (!record->data)
96
0
    return FALSE;
97
98
0
  if (fread(record->data, record->length, 1, pcap->fp) != 1)
99
0
  {
100
0
    free(record->data);
101
0
    record->data = NULL;
102
0
    return FALSE;
103
0
  }
104
0
  return TRUE;
105
0
}
106
107
static BOOL pcap_write_record(rdpPcap* pcap, const pcap_record* record)
108
0
{
109
0
  WINPR_ASSERT(pcap);
110
0
  WINPR_ASSERT(record);
111
112
0
  return pcap_write_record_header(pcap, &record->header) &&
113
0
         (fwrite(record->cdata, record->length, 1, pcap->fp) == 1);
114
0
}
115
116
BOOL pcap_add_record(rdpPcap* pcap, const void* data, size_t length)
117
0
{
118
0
  WINPR_ASSERT(pcap);
119
0
  WINPR_ASSERT(data || (length == 0));
120
0
  WINPR_ASSERT(length <= UINT32_MAX);
121
122
0
  pcap_record* record = (pcap_record*)calloc(1, sizeof(pcap_record));
123
0
  if (!record)
124
0
    return FALSE;
125
126
0
  record->cdata = data;
127
0
  record->length = length;
128
0
  record->header.incl_len = (UINT32)length;
129
0
  record->header.orig_len = (UINT32)length;
130
131
0
  const UINT64 ns = winpr_GetUnixTimeNS();
132
133
0
  record->header.ts_sec = WINPR_TIME_NS_TO_S(ns);
134
0
  record->header.ts_usec = WINPR_TIME_NS_REM_US(ns);
135
136
0
  if (pcap->tail == NULL)
137
0
  {
138
0
    pcap->tail = record;
139
0
    if (!pcap->tail)
140
0
      return FALSE;
141
142
0
    pcap->head = pcap->tail;
143
0
  }
144
0
  else
145
0
  {
146
0
    record->next = pcap->tail;
147
0
    pcap->tail = record;
148
0
  }
149
150
0
  if (pcap->record == NULL)
151
0
    pcap->record = record;
152
153
0
  return TRUE;
154
0
}
155
156
BOOL pcap_has_next_record(const rdpPcap* pcap)
157
0
{
158
0
  WINPR_ASSERT(pcap);
159
160
0
  if (pcap->file_size - (_ftelli64(pcap->fp)) <= 16)
161
0
    return FALSE;
162
163
0
  return TRUE;
164
0
}
165
166
BOOL pcap_get_next_record_header(rdpPcap* pcap, pcap_record* record)
167
0
{
168
0
  WINPR_ASSERT(pcap);
169
0
  WINPR_ASSERT(record);
170
171
0
  if (pcap_has_next_record(pcap) != TRUE)
172
0
    return FALSE;
173
174
0
  pcap_read_record_header(pcap, &record->header);
175
0
  record->length = record->header.incl_len;
176
177
0
  return TRUE;
178
0
}
179
180
BOOL pcap_get_next_record_content(rdpPcap* pcap, pcap_record* record)
181
0
{
182
0
  WINPR_ASSERT(pcap);
183
0
  WINPR_ASSERT(record);
184
185
0
  return fread(record->data, record->length, 1, pcap->fp) == 1;
186
0
}
187
188
BOOL pcap_get_next_record(rdpPcap* pcap, pcap_record* record)
189
0
{
190
0
  WINPR_ASSERT(pcap);
191
0
  WINPR_ASSERT(record);
192
193
0
  return pcap_has_next_record(pcap) && pcap_read_record(pcap, record);
194
0
}
195
196
rdpPcap* pcap_open(const char* name, BOOL write)
197
0
{
198
0
  rdpPcap* pcap = NULL;
199
200
0
  WINPR_ASSERT(name);
201
202
0
  pcap = (rdpPcap*)calloc(1, sizeof(rdpPcap));
203
0
  if (!pcap)
204
0
    goto fail;
205
206
0
  pcap->name = _strdup(name);
207
0
  pcap->write = write;
208
0
  pcap->record_count = 0;
209
0
  pcap->fp = winpr_fopen(name, write ? "w+b" : "rb");
210
211
0
  if (pcap->fp == NULL)
212
0
    goto fail;
213
214
0
  if (write)
215
0
  {
216
0
    pcap->header.magic_number = PCAP_MAGIC;
217
0
    pcap->header.version_major = 2;
218
0
    pcap->header.version_minor = 4;
219
0
    pcap->header.thiszone = 0;
220
0
    pcap->header.sigfigs = 0;
221
0
    pcap->header.snaplen = UINT32_MAX;
222
0
    pcap->header.network = 0;
223
0
    if (!pcap_write_header(pcap, &pcap->header))
224
0
      goto fail;
225
0
  }
226
0
  else
227
0
  {
228
0
    _fseeki64(pcap->fp, 0, SEEK_END);
229
0
    pcap->file_size = _ftelli64(pcap->fp);
230
0
    _fseeki64(pcap->fp, 0, SEEK_SET);
231
0
    if (!pcap_read_header(pcap, &pcap->header))
232
0
      goto fail;
233
0
  }
234
235
0
  return pcap;
236
237
0
fail:
238
0
  pcap_close(pcap);
239
0
  return NULL;
240
0
}
241
242
void pcap_flush(rdpPcap* pcap)
243
0
{
244
0
  WINPR_ASSERT(pcap);
245
246
0
  while (pcap->record != NULL)
247
0
  {
248
0
    pcap_write_record(pcap, pcap->record);
249
0
    pcap->record = pcap->record->next;
250
0
  }
251
252
0
  if (pcap->fp != NULL)
253
0
    fflush(pcap->fp);
254
0
}
255
256
void pcap_close(rdpPcap* pcap)
257
0
{
258
0
  if (!pcap)
259
0
    return;
260
261
0
  pcap_flush(pcap);
262
263
0
  if (pcap->fp != NULL)
264
0
    fclose(pcap->fp);
265
266
0
  free(pcap->name);
267
0
  free(pcap);
268
0
}