FreeRDP
PacketMessage.c
1 
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 {
39  if (pcap && pcap->fp && fread((void*)header, sizeof(wPcapHeader), 1, pcap->fp) == 1)
40  return TRUE;
41  return FALSE;
42 }
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 {
146  if (pcap && pcap->fp && fwrite((void*)header, sizeof(wPcapHeader), 1, pcap->fp) == 1)
147  return TRUE;
148  return FALSE;
149 }
150 
151 static BOOL Pcap_Write_RecordHeader(wPcap* pcap, wPcapRecordHeader* record)
152 {
153  if (pcap && pcap->fp && fwrite((void*)record, sizeof(wPcapRecordHeader), 1, pcap->fp) == 1)
154  return TRUE;
155  return FALSE;
156 }
157 
158 static BOOL Pcap_Write_RecordContent(wPcap* pcap, wPcapRecord* record)
159 {
160  if (pcap && pcap->fp && fwrite(record->data, record->length, 1, pcap->fp) == 1)
161  return TRUE;
162  return FALSE;
163 }
164 
165 static BOOL Pcap_Write_Record(wPcap* pcap, wPcapRecord* record)
166 {
167  return Pcap_Write_RecordHeader(pcap, &record->header) && Pcap_Write_RecordContent(pcap, record);
168 }
169 
170 wPcap* Pcap_Open(char* name, BOOL write)
171 {
172  wPcap* pcap = NULL;
173  FILE* pcap_fp = winpr_fopen(name, write ? "w+b" : "rb");
174 
175  if (!pcap_fp)
176  {
177  WLog_ERR(TAG, "opening pcap file");
178  return NULL;
179  }
180 
181  pcap = (wPcap*)calloc(1, sizeof(wPcap));
182 
183  if (!pcap)
184  goto out_fail;
185 
186  pcap->name = name;
187  pcap->write = write;
188  pcap->record_count = 0;
189  pcap->fp = pcap_fp;
190 
191  if (write)
192  {
193  pcap->header.magic_number = PCAP_MAGIC_NUMBER;
194  pcap->header.version_major = 2;
195  pcap->header.version_minor = 4;
196  pcap->header.thiszone = 0;
197  pcap->header.sigfigs = 0;
198  pcap->header.snaplen = 0xFFFFFFFF;
199  pcap->header.network = 1; /* ethernet */
200  if (!Pcap_Write_Header(pcap, &pcap->header))
201  goto out_fail;
202  }
203  else
204  {
205  if (_fseeki64(pcap->fp, 0, SEEK_END) < 0)
206  goto out_fail;
207  pcap->file_size = (SSIZE_T)_ftelli64(pcap->fp);
208  if (pcap->file_size < 0)
209  goto out_fail;
210  if (_fseeki64(pcap->fp, 0, SEEK_SET) < 0)
211  goto out_fail;
212  if (!Pcap_Read_Header(pcap, &pcap->header))
213  goto out_fail;
214  }
215 
216  return pcap;
217 
218 out_fail:
219  if (pcap_fp)
220  (void)fclose(pcap_fp);
221  free(pcap);
222  return NULL;
223 }
224 
225 void Pcap_Flush(wPcap* pcap)
226 {
227  if (!pcap || !pcap->fp)
228  return;
229 
230  while (pcap->record)
231  {
232  if (!Pcap_Write_Record(pcap, pcap->record))
233  return;
234  pcap->record = pcap->record->next;
235  }
236 
237  (void)fflush(pcap->fp);
238 }
239 
240 void Pcap_Close(wPcap* pcap)
241 {
242  if (!pcap || !pcap->fp)
243  return;
244 
245  Pcap_Flush(pcap);
246  (void)fclose(pcap->fp);
247  free(pcap);
248 }
249 
250 static BOOL WLog_PacketMessage_Write_EthernetHeader(wPcap* pcap, wEthernetHeader* ethernet)
251 {
252  wStream* s = NULL;
253  wStream sbuffer = { 0 };
254  BYTE buffer[14] = { 0 };
255  BOOL ret = TRUE;
256 
257  if (!pcap || !pcap->fp || !ethernet)
258  return FALSE;
259 
260  s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
261  if (!s)
262  return FALSE;
263  Stream_Write(s, ethernet->Destination, 6);
264  Stream_Write(s, ethernet->Source, 6);
265  Stream_Write_UINT16_BE(s, ethernet->Type);
266  if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
267  ret = FALSE;
268 
269  return ret;
270 }
271 
272 static UINT16 IPv4Checksum(const BYTE* ipv4, int length)
273 {
274  long checksum = 0;
275 
276  while (length > 1)
277  {
278  const UINT16 tmp16 = *((const UINT16*)ipv4);
279  checksum += tmp16;
280  length -= 2;
281  ipv4 += 2;
282  }
283 
284  if (length > 0)
285  checksum += *ipv4;
286 
287  while (checksum >> 16)
288  checksum = (checksum & 0xFFFF) + (checksum >> 16);
289 
290  return (UINT16)(~checksum);
291 }
292 
293 static BOOL WLog_PacketMessage_Write_IPv4Header(wPcap* pcap, wIPv4Header* ipv4)
294 {
295  wStream* s = NULL;
296  wStream sbuffer = { 0 };
297  BYTE buffer[20] = { 0 };
298  int ret = TRUE;
299 
300  if (!pcap || !pcap->fp || !ipv4)
301  return FALSE;
302 
303  s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
304  if (!s)
305  return FALSE;
306  Stream_Write_UINT8(s, (BYTE)((ipv4->Version << 4) | ipv4->InternetHeaderLength));
307  Stream_Write_UINT8(s, ipv4->TypeOfService);
308  Stream_Write_UINT16_BE(s, ipv4->TotalLength);
309  Stream_Write_UINT16_BE(s, ipv4->Identification);
310  Stream_Write_UINT16_BE(s, (UINT16)((ipv4->InternetProtocolFlags << 13) | ipv4->FragmentOffset));
311  Stream_Write_UINT8(s, ipv4->TimeToLive);
312  Stream_Write_UINT8(s, ipv4->Protocol);
313  Stream_Write_UINT16(s, ipv4->HeaderChecksum);
314  Stream_Write_UINT32_BE(s, ipv4->SourceAddress);
315  Stream_Write_UINT32_BE(s, ipv4->DestinationAddress);
316  ipv4->HeaderChecksum = IPv4Checksum((BYTE*)buffer, 20);
317  Stream_Rewind(s, 10);
318  Stream_Write_UINT16(s, ipv4->HeaderChecksum);
319 
320  if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
321  ret = FALSE;
322 
323  return ret;
324 }
325 
326 static BOOL WLog_PacketMessage_Write_TcpHeader(wPcap* pcap, wTcpHeader* tcp)
327 {
328  wStream* s = NULL;
329  wStream sbuffer = { 0 };
330  BYTE buffer[20] = { 0 };
331  BOOL ret = TRUE;
332 
333  if (!pcap || !pcap->fp || !tcp)
334  return FALSE;
335 
336  s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
337  if (!s)
338  return FALSE;
339  Stream_Write_UINT16_BE(s, tcp->SourcePort);
340  Stream_Write_UINT16_BE(s, tcp->DestinationPort);
341  Stream_Write_UINT32_BE(s, tcp->SequenceNumber);
342  Stream_Write_UINT32_BE(s, tcp->AcknowledgementNumber);
343  Stream_Write_UINT8(s, (UINT8)((tcp->Offset << 4) | (tcp->Reserved & 0xF)));
344  Stream_Write_UINT8(s, tcp->TcpFlags);
345  Stream_Write_UINT16_BE(s, tcp->Window);
346  Stream_Write_UINT16_BE(s, tcp->Checksum);
347  Stream_Write_UINT16_BE(s, tcp->UrgentPointer);
348 
349  if (pcap->fp)
350  {
351  if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
352  ret = FALSE;
353  }
354 
355  return ret;
356 }
357 
358 static UINT32 g_InboundSequenceNumber = 0;
359 static UINT32 g_OutboundSequenceNumber = 0;
360 
361 BOOL WLog_PacketMessage_Write(wPcap* pcap, void* data, size_t length, DWORD flags)
362 {
363  wTcpHeader tcp;
364  wIPv4Header ipv4;
365  wPcapRecord record;
366  wEthernetHeader ethernet;
367  ethernet.Type = 0x0800;
368 
369  if (!pcap || !pcap->fp)
370  return FALSE;
371 
372  if (flags & WLOG_PACKET_OUTBOUND)
373  {
374  /* 00:15:5D:01:64:04 */
375  ethernet.Source[0] = 0x00;
376  ethernet.Source[1] = 0x15;
377  ethernet.Source[2] = 0x5D;
378  ethernet.Source[3] = 0x01;
379  ethernet.Source[4] = 0x64;
380  ethernet.Source[5] = 0x04;
381  /* 00:15:5D:01:64:01 */
382  ethernet.Destination[0] = 0x00;
383  ethernet.Destination[1] = 0x15;
384  ethernet.Destination[2] = 0x5D;
385  ethernet.Destination[3] = 0x01;
386  ethernet.Destination[4] = 0x64;
387  ethernet.Destination[5] = 0x01;
388  }
389  else
390  {
391  /* 00:15:5D:01:64:01 */
392  ethernet.Source[0] = 0x00;
393  ethernet.Source[1] = 0x15;
394  ethernet.Source[2] = 0x5D;
395  ethernet.Source[3] = 0x01;
396  ethernet.Source[4] = 0x64;
397  ethernet.Source[5] = 0x01;
398  /* 00:15:5D:01:64:04 */
399  ethernet.Destination[0] = 0x00;
400  ethernet.Destination[1] = 0x15;
401  ethernet.Destination[2] = 0x5D;
402  ethernet.Destination[3] = 0x01;
403  ethernet.Destination[4] = 0x64;
404  ethernet.Destination[5] = 0x04;
405  }
406 
407  ipv4.Version = 4;
408  ipv4.InternetHeaderLength = 5;
409  ipv4.TypeOfService = 0;
410  ipv4.TotalLength = (UINT16)(length + 20 + 20);
411  ipv4.Identification = 0;
412  ipv4.InternetProtocolFlags = 0x02;
413  ipv4.FragmentOffset = 0;
414  ipv4.TimeToLive = 128;
415  ipv4.Protocol = 6; /* TCP */
416  ipv4.HeaderChecksum = 0;
417 
418  if (flags & WLOG_PACKET_OUTBOUND)
419  {
420  ipv4.SourceAddress = 0xC0A80196; /* 192.168.1.150 */
421  ipv4.DestinationAddress = 0x4A7D64C8; /* 74.125.100.200 */
422  }
423  else
424  {
425  ipv4.SourceAddress = 0x4A7D64C8; /* 74.125.100.200 */
426  ipv4.DestinationAddress = 0xC0A80196; /* 192.168.1.150 */
427  }
428 
429  tcp.SourcePort = 3389;
430  tcp.DestinationPort = 3389;
431 
432  if (flags & WLOG_PACKET_OUTBOUND)
433  {
434  tcp.SequenceNumber = g_OutboundSequenceNumber;
435  tcp.AcknowledgementNumber = g_InboundSequenceNumber;
436  g_OutboundSequenceNumber += length;
437  }
438  else
439  {
440  tcp.SequenceNumber = g_InboundSequenceNumber;
441  tcp.AcknowledgementNumber = g_OutboundSequenceNumber;
442  g_InboundSequenceNumber += length;
443  }
444 
445  tcp.Offset = 5;
446  tcp.Reserved = 0;
447  tcp.TcpFlags = 0x0018;
448  tcp.Window = 0x7FFF;
449  tcp.Checksum = 0;
450  tcp.UrgentPointer = 0;
451  record.data = data;
452  record.length = length;
453  const size_t offset = 14 + 20 + 20;
454  WINPR_ASSERT(record.length <= UINT32_MAX - offset);
455  record.header.incl_len = (UINT32)record.length + offset;
456  record.header.orig_len = (UINT32)record.length + offset;
457  record.next = NULL;
458 
459  UINT64 ns = winpr_GetUnixTimeNS();
460  record.header.ts_sec = (UINT32)WINPR_TIME_NS_TO_S(ns);
461  record.header.ts_usec = WINPR_TIME_NS_REM_US(ns);
462 
463  if (!Pcap_Write_RecordHeader(pcap, &record.header) ||
464  !WLog_PacketMessage_Write_EthernetHeader(pcap, &ethernet) ||
465  !WLog_PacketMessage_Write_IPv4Header(pcap, &ipv4) ||
466  !WLog_PacketMessage_Write_TcpHeader(pcap, &tcp) || !Pcap_Write_RecordContent(pcap, &record))
467  return FALSE;
468  (void)fflush(pcap->fp);
469  return TRUE;
470 }