20 Aug 2024
/*
* parse.h
*
* Copyright (c) 2024 fbmnn
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
typedef struct {
uint32_t magic;
uint16_t major_version;
uint16_t minor_version;
uint32_t reserved1;
uint32_t reserved2;
uint32_t snap_len;
uint32_t link_type;
} pcap_header;
typedef struct {
uint32_t timestamp_s;
uint32_t timestamp_ms;
uint32_t cap_len;
uint32_t orig_len;
} pcap_record;
typedef struct {
uint16_t sll_family;
uint16_t sll_protocol;
uint32_t sll_ifindex;
uint16_t sll_hatype;
unsigned char sll_pkttype;
unsigned char sll_halen;
unsigned char sll_addr[8];
} sockaddr_ll;
typedef struct {
unsigned char version;
unsigned char dsfield;
uint16_t len;
uint16_t id;
uint16_t flags;
uint16_t ttl;
unsigned char proto;
uint16_t checksum;
uint32_t s_addr;
uint32_t d_addr;
} ipv4;
typedef struct {
uint8_t type;
uint8_t code;
uint16_t checksum;
uint16_t identifier;
uint16_t sequence_nr;
} icmp_echo_reply;
// parser functions
int parse_pcap_header(pcap_header *pkg_struct, FILE *fp);
void parse_pcap_record(pcap_record *pkg_struct, FILE *fp);
int parse_sockaddr_ll(sockaddr_ll *pkg_struct, unsigned char *data);
int parse_ipv4(ipv4 *pkg_struct, unsigned char *data);
int parse_icmp_echo_reply(icmp_echo_reply *pkg_struct, unsigned char *data);
// print functions
void print_pcap_head(pcap_header *pkg_struct);
void print_pcap_record_meta(pcap_record *pkg_struct);
void print_sll(sockaddr_ll *pkg_struct);
void print_ipv4(ipv4 *pkg_struct);
void print_icmp4(icmp_echo_reply *pkg_struct);
// util functions
void hex_dump(unsigned char *buf, uint32_t cap_len);
void fmt_mac_address(unsigned char *buf, unsigned char *hex_data);
void fmt_pcap_timestamp_s(unsigned char *buf, uint32_t timestamp_s);
/*
* parse.c
*
* Copyright (c) 2024 fbmnn
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#include "parse.h"
int parse_pcap_header(pcap_header *pkg_struct, FILE *fp) {
fread(&(*pkg_struct).magic, 4, 1, fp);
fread(&(*pkg_struct).major_version, 2, 1, fp);
fread(&(*pkg_struct).minor_version, 2, 1, fp);
fread(&(*pkg_struct).reserved1, 4, 1, fp);
fread(&(*pkg_struct).reserved2, 4, 1, fp);
fread(&(*pkg_struct).snap_len, 4, 1, fp);
fread(&(*pkg_struct).link_type, 4, 1, fp);
pkg_struct->snap_len = __builtin_bswap32(pkg_struct->snap_len);
if ((pkg_struct->magic == 0xa1b2c3d4) ||
(pkg_struct->magic == 0xa1b23c4d))
return true;
return false;
}
void parse_pcap_record(pcap_record *pkg_struct, FILE *fp) {
fread(&(*pkg_struct).timestamp_s, 4, 1, fp);
fread(&(*pkg_struct).timestamp_ms, 4, 1, fp);
fread(&(*pkg_struct).cap_len, 4, 1, fp);
fread(&(*pkg_struct).orig_len, 4, 1, fp);
}
int parse_sockaddr_ll(sockaddr_ll *pkg_struct, unsigned char *data) {
char *data_pos = data;
memcpy(&(*pkg_struct).sll_family, data_pos, 2);
data_pos += 2;
memcpy(&(*pkg_struct).sll_protocol, data_pos, 2);
data_pos += 2;
memcpy(&(*pkg_struct).sll_ifindex, data_pos, 4);
data_pos += 4;
memcpy(&(*pkg_struct).sll_hatype, data_pos, 2);
data_pos += 2;
memcpy(&(*pkg_struct).sll_pkttype, data_pos, 1);
data_pos ++;
memcpy(&(*pkg_struct).sll_halen, data_pos, 1);
data_pos ++;
memcpy(&(*pkg_struct).sll_addr, data_pos, 8);
pkg_struct->sll_family = __builtin_bswap16(pkg_struct->sll_family);
pkg_struct->sll_protocol = __builtin_bswap16(pkg_struct->sll_protocol);
pkg_struct->sll_ifindex = __builtin_bswap32(pkg_struct->sll_ifindex);
pkg_struct->sll_hatype = __builtin_bswap16(pkg_struct->sll_hatype);
return 20;
}
int parse_ipv4(ipv4 *pkg_struct, unsigned char *data) {
char *data_pos = data;
memcpy(&(*pkg_struct).version, data_pos, 1);
data_pos++;
memcpy(&(*pkg_struct).dsfield, data_pos, 1);
data_pos++;
memcpy(&(*pkg_struct).len, data_pos, 2);
data_pos += 2;
memcpy(&(*pkg_struct).id, data_pos, 2);
data_pos += 2;
memcpy(&(*pkg_struct).flags, data_pos, 2);
data_pos += 2;
memcpy(&(*pkg_struct).ttl, data_pos, 1);
data_pos++;
memcpy(&(*pkg_struct).proto, data_pos, 1);
data_pos++;
memcpy(&(*pkg_struct).checksum, data_pos, 2);
data_pos += 2;
memcpy(&(*pkg_struct).s_addr, data_pos, 4);
data_pos += 4;
memcpy(&(*pkg_struct).d_addr, data_pos, 4);
pkg_struct->len = __builtin_bswap16(pkg_struct->len);
pkg_struct->id = __builtin_bswap16(pkg_struct->id);
pkg_struct->flags = __builtin_bswap16(pkg_struct->flags);
pkg_struct->checksum = __builtin_bswap16(pkg_struct->checksum);
pkg_struct->d_addr = __builtin_bswap32(pkg_struct->d_addr);
pkg_struct->s_addr = __builtin_bswap32(pkg_struct->s_addr);
return 20;
}
int parse_icmp_echo_reply(icmp_echo_reply *pkg_struct, unsigned char *data) {
char *data_pos = data;
memcpy(&(*pkg_struct).type, data_pos, 1);
data_pos++;
memcpy(&(*pkg_struct).code, data_pos, 1);
data_pos++;
memcpy(&(*pkg_struct).checksum, data_pos, 2);
data_pos += 2;
memcpy(&(*pkg_struct).identifier, data_pos, 2);
data_pos += 2;
memcpy(&(*pkg_struct).sequence_nr, data_pos, 2);
pkg_struct->checksum = __builtin_bswap16(pkg_struct->checksum);
pkg_struct->identifier = __builtin_bswap16(pkg_struct->identifier);
pkg_struct->sequence_nr = __builtin_bswap16(pkg_struct->sequence_nr);
return 8;
}
void fmt_mac_address(unsigned char *buf, unsigned char *hex_data) {
snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x", hex_data[0], hex_data[1],
hex_data[2], hex_data[3], hex_data[4], hex_data[5]);
}
void fmt_pcap_timestamp_s(unsigned char *buf, uint32_t timestamp_s) {
time_t ts_s = timestamp_s;
struct tm ts = *localtime(&ts_s);
if (!strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &ts))
puts("error while converting timestamp.");
}
void print_pcap_head(pcap_header *pkg_struct) {
printf("##### parsed pcap header #####\n");
printf("magic | major | minor | r1 | r2 | snap_len | link_type\n");
printf("%x | %x | %x | %x | %x | %x | %x\n",
pkg_struct->magic,
pkg_struct->major_version,
pkg_struct->minor_version,
pkg_struct->reserved1,
pkg_struct->reserved2,
pkg_struct->snap_len,
pkg_struct->link_type);
printf("##### parsed pcap header #####\n");
}
void print_pcap_record_meta(pcap_record *pkg_struct) {
printf("#### begin pcap_record #####\n");
printf("s, cap_len: %i, %i\n", pkg_struct->timestamp_s, pkg_struct->cap_len);
}
void hex_dump(unsigned char *buf, uint32_t cap_len) {
printf("##### hex dump #####\n");
for(int i=0; i<cap_len; i++) {
printf("%02x", buf[i]);
if ((i+1) % 4 == 0) {
if ((i+1) % 32 == 0) {
printf("\n");
}
else {
printf(" ");
}
}
}
printf("\n");
printf("##### hex dump #####\n");
}
void print_sll(sockaddr_ll *pkg_struct) {
printf("##### sll data #####\n");
printf("family | protocol | ifindex | hatype | pkttype | halen\n");
printf("%x | %x | %x | %x | %x | %x\n", pkg_struct->sll_family,
pkg_struct->sll_protocol,
pkg_struct->sll_ifindex,
pkg_struct->sll_hatype,
pkg_struct->sll_pkttype,
pkg_struct->sll_halen);
unsigned char mac_address[19] = {0};
fmt_mac_address(mac_address, pkg_struct->sll_addr);
printf("addr: %s\n", mac_address);
printf("##### sll data #####\n");
}
void print_ipv4(ipv4 *pkg_struct) {
printf("##### ipv4 data #####\n");
printf("version | dsfield | len | id | flags | ttl | proto | checksum | s_addr | d_addr\n");
printf("%x | %x | %x | %x | %x | %x | %x | %x | %x | %x\n",
pkg_struct->version,
pkg_struct->dsfield,
pkg_struct->len,
pkg_struct->id,
pkg_struct->flags,
pkg_struct->ttl,
pkg_struct->proto,
pkg_struct->checksum,
pkg_struct->s_addr,
pkg_struct->d_addr);
printf("##### ipv4 data #####\n");
}
void print_icmp4(icmp_echo_reply *pkg_struct) {
// type: 8 = echo, 0 = echo reply
printf("##### icmp echo reply data #####\n");
printf("type | code | checksum | identifier | sequence number\n");
printf("%x | %x | %x | %x | %x\n", pkg_struct->type,
pkg_struct->code,
pkg_struct->checksum,
pkg_struct->identifier,
pkg_struct->sequence_nr);
printf("##### icmp echo reply data #####\n");
}
static FILE *fp;
void free_all() {
fclose(fp);
}
int main() {
atexit(free_all);
fp = fopen("./dump.pcap", "r");
char ch;
pcap_header pkg_head;
pcap_record pkg_record;
if (!parse_pcap_header(&pkg_head, fp))
exit(EXIT_FAILURE);
parse_pcap_record(&pkg_record, fp);
print_pcap_head(&pkg_head);
print_pcap_record_meta(&pkg_record);
// alloc char array with cap_len
unsigned char *packet = malloc(sizeof(char)*pkg_record.cap_len);
unsigned char *packet_orig = packet;
fread(packet, pkg_record.cap_len, 1, fp);
hex_dump(packet, pkg_record.cap_len);
unsigned char buf[20] = {0};
fmt_pcap_timestamp_s(buf, pkg_record.timestamp_s);
puts(buf);
int bytes_parsed = 0;
int bytes_read;
sockaddr_ll pkg_sockaddr_ll;
ipv4 pck_ipv4;
icmp_echo_reply pkg_icmp_echo;
bytes_read = parse_sockaddr_ll(&pkg_sockaddr_ll, packet);
bytes_parsed += bytes_read;
if (bytes_parsed < pkg_record.cap_len)
packet = &packet[bytes_read];
else
exit(EXIT_FAILURE);
print_sll(&pkg_sockaddr_ll);
bytes_read = parse_ipv4(&pck_ipv4, packet);
bytes_parsed += bytes_read;
if (bytes_parsed < pkg_record.cap_len)
packet = &packet[bytes_read];
else
exit(EXIT_FAILURE);
print_ipv4(&pck_ipv4);
bytes_read = parse_icmp_echo_reply(&pkg_icmp_echo, packet);
bytes_parsed += bytes_read;
if (bytes_parsed < pkg_record.cap_len)
packet = &packet[bytes_read];
else
exit(EXIT_FAILURE);
print_icmp4(&pkg_icmp_echo);
printf("\n\n\n");
puts("New packet:");
parse_pcap_record(&pkg_record, fp);
print_pcap_record_meta(&pkg_record);
free(packet_orig);
packet = malloc(sizeof(char)*pkg_record.cap_len);
packet_orig = packet;
fread(packet, pkg_record.cap_len, 1, fp);
hex_dump(packet, pkg_record.cap_len);
memset(buf, 0, sizeof(buf));
fmt_pcap_timestamp_s(buf, pkg_record.timestamp_s);
puts(buf);
bytes_parsed = 0;
bytes_read = parse_sockaddr_ll(&pkg_sockaddr_ll, packet);
bytes_parsed += bytes_read;
if (bytes_parsed < pkg_record.cap_len)
packet = &packet[bytes_read];
else
exit(EXIT_FAILURE);
print_sll(&pkg_sockaddr_ll);
bytes_read = parse_ipv4(&pck_ipv4, packet);
bytes_parsed += bytes_read;
if (bytes_parsed < pkg_record.cap_len)
packet = &packet[bytes_read];
else
exit(EXIT_FAILURE);
print_ipv4(&pck_ipv4);
bytes_read = parse_icmp_echo_reply(&pkg_icmp_echo, packet);
bytes_parsed += bytes_read;
if (bytes_parsed < pkg_record.cap_len)
packet = &packet[bytes_read];
else
exit(EXIT_FAILURE);
print_icmp4(&pkg_icmp_echo);
exit(0);
}