Coverage Report

Created: 2023-11-19 06:16

/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 <freerdp/log.h>
31
32
#define TAG FREERDP_TAG("utils")
33
34
#ifndef _WIN32
35
#include <sys/time.h>
36
#else
37
#include <time.h>
38
#include <sys/timeb.h>
39
#include <winpr/windows.h>
40
41
int gettimeofday(struct timeval* tp, void* tz)
42
{
43
  struct _timeb timebuffer;
44
  _ftime(&timebuffer);
45
  tp->tv_sec = (long)timebuffer.time;
46
  tp->tv_usec = timebuffer.millitm * 1000;
47
  return 0;
48
}
49
#endif
50
51
#include <freerdp/types.h>
52
#include <freerdp/utils/pcap.h>
53
54
0
#define PCAP_MAGIC 0xA1B2C3D4
55
56
struct rdp_pcap
57
{
58
  FILE* fp;
59
  char* name;
60
  BOOL write;
61
  INT64 file_size;
62
  size_t record_count;
63
  pcap_header header;
64
  pcap_record* head;
65
  pcap_record* tail;
66
  pcap_record* record;
67
};
68
69
static BOOL pcap_read_header(rdpPcap* pcap, pcap_header* header)
70
0
{
71
0
  WINPR_ASSERT(pcap);
72
0
  WINPR_ASSERT(header);
73
74
0
  return fread(header, sizeof(pcap_header), 1, pcap->fp) == 1;
75
0
}
76
77
static BOOL pcap_write_header(rdpPcap* pcap, const pcap_header* header)
78
0
{
79
0
  WINPR_ASSERT(pcap);
80
0
  WINPR_ASSERT(header);
81
82
0
  return fwrite(header, sizeof(pcap_header), 1, pcap->fp) == 1;
83
0
}
84
85
static BOOL pcap_read_record_header(rdpPcap* pcap, pcap_record_header* record)
86
0
{
87
0
  WINPR_ASSERT(pcap);
88
0
  WINPR_ASSERT(record);
89
90
0
  return fread(record, sizeof(pcap_record_header), 1, pcap->fp) == 1;
91
0
}
92
93
static BOOL pcap_write_record_header(rdpPcap* pcap, const pcap_record_header* record)
94
0
{
95
0
  WINPR_ASSERT(pcap);
96
0
  WINPR_ASSERT(record);
97
98
0
  return fwrite(record, sizeof(pcap_record_header), 1, pcap->fp) == 1;
99
0
}
100
101
static BOOL pcap_read_record(rdpPcap* pcap, pcap_record* record)
102
0
{
103
0
  WINPR_ASSERT(pcap);
104
0
  WINPR_ASSERT(record);
105
106
0
  if (!pcap_read_record_header(pcap, &record->header))
107
0
    return FALSE;
108
109
0
  record->length = record->header.incl_len;
110
0
  record->data = malloc(record->length);
111
0
  if (!record->data)
112
0
    return FALSE;
113
114
0
  if (fread(record->data, record->length, 1, pcap->fp) != 1)
115
0
  {
116
0
    free(record->data);
117
0
    record->data = NULL;
118
0
    return FALSE;
119
0
  }
120
0
  return TRUE;
121
0
}
122
123
static BOOL pcap_write_record(rdpPcap* pcap, const pcap_record* record)
124
0
{
125
0
  WINPR_ASSERT(pcap);
126
0
  WINPR_ASSERT(record);
127
128
0
  return pcap_write_record_header(pcap, &record->header) &&
129
0
         (fwrite(record->cdata, record->length, 1, pcap->fp) == 1);
130
0
}
131
132
BOOL pcap_add_record(rdpPcap* pcap, const void* data, size_t length)
133
0
{
134
0
  pcap_record* record;
135
0
  struct timeval tp;
136
137
0
  WINPR_ASSERT(pcap);
138
0
  WINPR_ASSERT(data || (length == 0));
139
0
  WINPR_ASSERT(length <= UINT32_MAX);
140
141
0
  record = (pcap_record*)calloc(1, sizeof(pcap_record));
142
0
  if (!record)
143
0
    return FALSE;
144
145
0
  record->cdata = data;
146
0
  record->length = length;
147
0
  record->header.incl_len = (UINT32)length;
148
0
  record->header.orig_len = (UINT32)length;
149
150
0
  gettimeofday(&tp, 0);
151
0
  record->header.ts_sec = (UINT32)tp.tv_sec;
152
0
  record->header.ts_usec = (UINT32)tp.tv_usec;
153
154
0
  if (pcap->tail == NULL)
155
0
  {
156
0
    pcap->tail = record;
157
0
    if (!pcap->tail)
158
0
      return FALSE;
159
160
0
    pcap->head = pcap->tail;
161
0
  }
162
0
  else
163
0
  {
164
0
    record->next = pcap->tail;
165
0
    pcap->tail = record;
166
0
  }
167
168
0
  if (pcap->record == NULL)
169
0
    pcap->record = record;
170
171
0
  return TRUE;
172
0
}
173
174
BOOL pcap_has_next_record(const rdpPcap* pcap)
175
0
{
176
0
  WINPR_ASSERT(pcap);
177
178
0
  if (pcap->file_size - (_ftelli64(pcap->fp)) <= 16)
179
0
    return FALSE;
180
181
0
  return TRUE;
182
0
}
183
184
BOOL pcap_get_next_record_header(rdpPcap* pcap, pcap_record* record)
185
0
{
186
0
  WINPR_ASSERT(pcap);
187
0
  WINPR_ASSERT(record);
188
189
0
  if (pcap_has_next_record(pcap) != TRUE)
190
0
    return FALSE;
191
192
0
  pcap_read_record_header(pcap, &record->header);
193
0
  record->length = record->header.incl_len;
194
195
0
  return TRUE;
196
0
}
197
198
BOOL pcap_get_next_record_content(rdpPcap* pcap, pcap_record* record)
199
0
{
200
0
  WINPR_ASSERT(pcap);
201
0
  WINPR_ASSERT(record);
202
203
0
  return fread(record->data, record->length, 1, pcap->fp) == 1;
204
0
}
205
206
BOOL pcap_get_next_record(rdpPcap* pcap, pcap_record* record)
207
0
{
208
0
  WINPR_ASSERT(pcap);
209
0
  WINPR_ASSERT(record);
210
211
0
  return pcap_has_next_record(pcap) && pcap_read_record(pcap, record);
212
0
}
213
214
rdpPcap* pcap_open(const char* name, BOOL write)
215
0
{
216
0
  rdpPcap* pcap;
217
218
0
  WINPR_ASSERT(name);
219
220
0
  pcap = (rdpPcap*)calloc(1, sizeof(rdpPcap));
221
0
  if (!pcap)
222
0
    goto fail;
223
224
0
  pcap->name = _strdup(name);
225
0
  pcap->write = write;
226
0
  pcap->record_count = 0;
227
0
  pcap->fp = winpr_fopen(name, write ? "w+b" : "rb");
228
229
0
  if (pcap->fp == NULL)
230
0
    goto fail;
231
232
0
  if (write)
233
0
  {
234
0
    pcap->header.magic_number = PCAP_MAGIC;
235
0
    pcap->header.version_major = 2;
236
0
    pcap->header.version_minor = 4;
237
0
    pcap->header.thiszone = 0;
238
0
    pcap->header.sigfigs = 0;
239
0
    pcap->header.snaplen = UINT32_MAX;
240
0
    pcap->header.network = 0;
241
0
    if (!pcap_write_header(pcap, &pcap->header))
242
0
      goto fail;
243
0
  }
244
0
  else
245
0
  {
246
0
    _fseeki64(pcap->fp, 0, SEEK_END);
247
0
    pcap->file_size = _ftelli64(pcap->fp);
248
0
    _fseeki64(pcap->fp, 0, SEEK_SET);
249
0
    if (!pcap_read_header(pcap, &pcap->header))
250
0
      goto fail;
251
0
  }
252
253
0
  return pcap;
254
255
0
fail:
256
0
  pcap_close(pcap);
257
0
  return NULL;
258
0
}
259
260
void pcap_flush(rdpPcap* pcap)
261
0
{
262
0
  WINPR_ASSERT(pcap);
263
264
0
  while (pcap->record != NULL)
265
0
  {
266
0
    pcap_write_record(pcap, pcap->record);
267
0
    pcap->record = pcap->record->next;
268
0
  }
269
270
0
  if (pcap->fp != NULL)
271
0
    fflush(pcap->fp);
272
0
}
273
274
void pcap_close(rdpPcap* pcap)
275
0
{
276
0
  if (!pcap)
277
0
    return;
278
279
0
  pcap_flush(pcap);
280
281
0
  if (pcap->fp != NULL)
282
0
    fclose(pcap->fp);
283
284
0
  free(pcap->name);
285
0
  free(pcap);
286
0
}