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