Skip to content

Instantly share code, notes, and snippets.

@mildsunrise
Created February 27, 2024 23:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mildsunrise/b1da7a49c6b267e5968186372478532f to your computer and use it in GitHub Desktop.
Save mildsunrise/b1da7a49c6b267e5968186372478532f to your computer and use it in GitHub Desktop.
converts an SLLv2 pcap into an SLL one (because tools like tcpflow and tcpreplay lack support for SLLv2 and it's maddening)
// compile with: clang -Wpedantic -Wall -Wextra $(pkg-config --cflags libpcap) sllv2tosll.c $(pkg-config --libs libpcap) -o sllv2tossl
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <pcap/pcap.h>
char error_buffer[PCAP_ERRBUF_SIZE];
pcap_t *handle, *out_handle;
pcap_dumper_t *out_dump;
long iface_index;
struct __attribute__((__packed__)) sll_header {
uint16_t packet_type;
uint16_t aphrd_type;
uint16_t lladdr_len;
uint64_t lladdr;
uint16_t protocol_type;
};
struct __attribute__((__packed__)) sllv2_header {
uint16_t protocol_type;
uint16_t _reserved;
uint32_t iface_index;
uint16_t aphrd_type;
uint8_t packet_type;
uint8_t lladdr_len;
uint64_t lladdr;
};
void handle_packet(
u_char *args,
const struct pcap_pkthdr *header,
const u_char *packet
) {
struct sllv2_header phdr;
if (header->caplen < sizeof(phdr)) {
fprintf(stderr, "error: packet is shorter than SLLv2 header\n");
pcap_breakloop(handle);
return;
}
memcpy(&phdr, packet, sizeof(phdr));
if (ntohl(phdr.iface_index) != iface_index)
return;
if (phdr._reserved)
fprintf(stderr, "warning: reserved field set to %u\n", phdr._reserved);
struct sll_header phdr_new = {
.aphrd_type = phdr.aphrd_type,
.packet_type = htons(phdr.packet_type),
.protocol_type = phdr.protocol_type,
.lladdr_len = htons(phdr.lladdr_len),
.lladdr = phdr.lladdr,
};
struct pcap_pkthdr header_new = *header;
header_new.caplen = header->caplen - sizeof(phdr) + sizeof(phdr_new);
u_char packet_new [header_new.caplen];
memcpy(packet_new, &phdr_new, sizeof(phdr_new));
memcpy(packet_new + sizeof(phdr_new), packet + sizeof(phdr), header->caplen - sizeof(phdr));
pcap_dump((u_char*) out_dump, &header_new, packet_new);
}
int main(int argc, char *argv[]) {
char *endptr;
if (argc < 2 || (iface_index = strtol(argv[1], &endptr, 10)) < 0 || *endptr || iface_index > UINT32_MAX) {
fprintf(stderr, "Usage: %s <interface ID>\n", argv[0]);
return 3;
}
// FIXME: this doesn't preserve the timestamp precision of the capture,
// and looking at libpcap it just doesn't seem to be possible to
// open a capture with its original timestamp type
handle = pcap_fopen_offline(stdin, error_buffer);
if (handle == NULL) {
fprintf(stderr, "could not open input: %s\n", error_buffer);
return 2;
}
if (pcap_datalink(handle) != DLT_LINUX_SLL2) {
fprintf(stderr, "input capture is not SLL2\n");
return 2;
}
out_handle = pcap_open_dead_with_tstamp_precision(
DLT_LINUX_SLL,
pcap_snapshot(handle),
pcap_get_tstamp_precision(handle));
if (handle == NULL) {
fprintf(stderr, "could not open output handle\n");
return 2;
}
out_dump = pcap_dump_fopen(out_handle, stdout);
if (out_dump == NULL) {
fprintf(stderr, "could not open output\n");
return 2;
}
int err = pcap_loop(handle, 0, handle_packet, NULL);
if (err) {
fprintf(stderr, "could not process capture: %s\n", pcap_strerror(err));
return 1;
}
pcap_dump_close(out_dump);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment