9df9c7d28a
Use 'b' in fopen's mode string to force binary (untranslated) mode when reading or writing the pcap file. This is required on WIN32 and maybe on other non POSIX conforming systems. This fixes the mstsc internal error disconnect followed by a crash of the sample server when latter is used to serve a pcap file on WIN32.
222 lines
4.7 KiB
C
222 lines
4.7 KiB
C
/**
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
* pcap File Format Utils
|
|
*
|
|
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <winpr/crt.h>
|
|
|
|
#ifndef _WIN32
|
|
#include <sys/time.h>
|
|
#else
|
|
#include <time.h>
|
|
#include <sys/timeb.h>
|
|
#include <winpr/windows.h>
|
|
|
|
int gettimeofday(struct timeval* tp, void* tz)
|
|
{
|
|
struct _timeb timebuffer;
|
|
_ftime(&timebuffer);
|
|
tp->tv_sec = (long) timebuffer.time;
|
|
tp->tv_usec = timebuffer.millitm * 1000;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#include <freerdp/types.h>
|
|
#include <freerdp/utils/pcap.h>
|
|
|
|
#define PCAP_MAGIC 0xA1B2C3D4
|
|
|
|
void pcap_read_header(rdpPcap* pcap, pcap_header* header)
|
|
{
|
|
fread((void*) header, sizeof(pcap_header), 1, pcap->fp);
|
|
}
|
|
|
|
void pcap_write_header(rdpPcap* pcap, pcap_header* header)
|
|
{
|
|
fwrite((void*) header, sizeof(pcap_header), 1, pcap->fp);
|
|
}
|
|
|
|
void pcap_read_record_header(rdpPcap* pcap, pcap_record_header* record)
|
|
{
|
|
fread((void*) record, sizeof(pcap_record_header), 1, pcap->fp);
|
|
}
|
|
|
|
void pcap_write_record_header(rdpPcap* pcap, pcap_record_header* record)
|
|
{
|
|
fwrite((void*) record, sizeof(pcap_record_header), 1, pcap->fp);
|
|
}
|
|
|
|
void pcap_read_record(rdpPcap* pcap, pcap_record* record)
|
|
{
|
|
pcap_read_record_header(pcap, &record->header);
|
|
record->length = record->header.incl_len;
|
|
record->data = malloc(record->length);
|
|
fread(record->data, record->length, 1, pcap->fp);
|
|
}
|
|
|
|
void pcap_write_record(rdpPcap* pcap, pcap_record* record)
|
|
{
|
|
pcap_write_record_header(pcap, &record->header);
|
|
fwrite(record->data, record->length, 1, pcap->fp);
|
|
}
|
|
|
|
void pcap_add_record(rdpPcap* pcap, void* data, UINT32 length)
|
|
{
|
|
pcap_record* record;
|
|
struct timeval tp;
|
|
|
|
if (pcap->tail == NULL)
|
|
{
|
|
pcap->tail = (pcap_record*) malloc(sizeof(pcap_record));
|
|
ZeroMemory(pcap->tail, sizeof(pcap_record));
|
|
|
|
pcap->head = pcap->tail;
|
|
pcap->record = pcap->head;
|
|
record = pcap->tail;
|
|
}
|
|
else
|
|
{
|
|
record = (pcap_record*) malloc(sizeof(pcap_record));
|
|
ZeroMemory(record, sizeof(pcap_record));
|
|
|
|
pcap->tail->next = record;
|
|
pcap->tail = record;
|
|
}
|
|
|
|
if (pcap->record == NULL)
|
|
pcap->record = record;
|
|
|
|
record->data = data;
|
|
record->length = length;
|
|
record->header.incl_len = length;
|
|
record->header.orig_len = length;
|
|
|
|
gettimeofday(&tp, 0);
|
|
record->header.ts_sec = tp.tv_sec;
|
|
record->header.ts_usec = tp.tv_usec;
|
|
}
|
|
|
|
BOOL pcap_has_next_record(rdpPcap* pcap)
|
|
{
|
|
if (pcap->file_size - (ftell(pcap->fp)) <= 16)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL pcap_get_next_record_header(rdpPcap* pcap, pcap_record* record)
|
|
{
|
|
if (pcap_has_next_record(pcap) != TRUE)
|
|
return FALSE;
|
|
|
|
pcap_read_record_header(pcap, &record->header);
|
|
record->length = record->header.incl_len;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL pcap_get_next_record_content(rdpPcap* pcap, pcap_record* record)
|
|
{
|
|
fread(record->data, record->length, 1, pcap->fp);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL pcap_get_next_record(rdpPcap* pcap, pcap_record* record)
|
|
{
|
|
if (pcap_has_next_record(pcap) != TRUE)
|
|
return FALSE;
|
|
|
|
pcap_read_record(pcap, record);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
rdpPcap* pcap_open(char* name, BOOL write)
|
|
{
|
|
rdpPcap* pcap;
|
|
|
|
FILE* pcap_fp = fopen(name, write ? "w+b" : "rb");
|
|
|
|
if (pcap_fp == NULL)
|
|
{
|
|
perror("opening pcap dump");
|
|
return NULL;
|
|
}
|
|
|
|
pcap = (rdpPcap*) malloc(sizeof(rdpPcap));
|
|
|
|
if (pcap != NULL)
|
|
{
|
|
ZeroMemory(pcap, sizeof(rdpPcap));
|
|
|
|
pcap->name = name;
|
|
pcap->write = write;
|
|
pcap->record_count = 0;
|
|
pcap->fp = pcap_fp;
|
|
|
|
if (write)
|
|
{
|
|
pcap->header.magic_number = 0xA1B2C3D4;
|
|
pcap->header.version_major = 2;
|
|
pcap->header.version_minor = 4;
|
|
pcap->header.thiszone = 0;
|
|
pcap->header.sigfigs = 0;
|
|
pcap->header.snaplen = 0xFFFFFFFF;
|
|
pcap->header.network = 0;
|
|
pcap_write_header(pcap, &pcap->header);
|
|
}
|
|
else
|
|
{
|
|
fseek(pcap->fp, 0, SEEK_END);
|
|
pcap->file_size = (int) ftell(pcap->fp);
|
|
fseek(pcap->fp, 0, SEEK_SET);
|
|
pcap_read_header(pcap, &pcap->header);
|
|
}
|
|
}
|
|
|
|
return pcap;
|
|
}
|
|
|
|
void pcap_flush(rdpPcap* pcap)
|
|
{
|
|
while (pcap->record != NULL)
|
|
{
|
|
pcap_write_record(pcap, pcap->record);
|
|
pcap->record = pcap->record->next;
|
|
}
|
|
|
|
if (pcap->fp != NULL)
|
|
fflush(pcap->fp);
|
|
}
|
|
|
|
void pcap_close(rdpPcap* pcap)
|
|
{
|
|
pcap_flush(pcap);
|
|
|
|
if (pcap->fp != NULL)
|
|
fclose(pcap->fp);
|
|
}
|