Last active
August 9, 2022 13:08
-
-
Save netravnen/afef18a4bc644b837df85c1f8b2a24de to your computer and use it in GitHub Desktop.
The C program has been modified to be able to compile on Ubuntu 22.04 LTS with `clang -Wall` - Original copyright holder is user @tobez
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ---------------------------------------------------------------------------- | |
* "THE BEER-WARE LICENSE" (Revision 42) | |
* <[email protected]> wrote this file. As long as you retain this notice you | |
* can do whatever you want with this stuff. If we meet some day, and you think | |
* this stuff is worth it, you can buy me a beer in return. Anton Berezin | |
* ---------------------------------------------------------------------------- | |
*/ | |
/* | |
* $Id: pcaptail.c,v 1.1 2006/08/21 11:51:17 tobez Exp $ | |
*/ | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <pcap.h> | |
int debug = 0; | |
/* XXX handle different endianness ! */ | |
unsigned int | |
looks_like_packet( | |
struct pcap_pkthdr *hdr, | |
struct timeval *ts, | |
unsigned int snaplen, | |
int swap) | |
{ | |
if (hdr->ts.tv_usec > 1000000) { | |
if (debug) fprintf(stderr, "Cannot have %d microseconds\n", hdr->ts.tv_usec); | |
return 0; /* cannot have that many microseconds */ | |
} | |
if (hdr->ts.tv_sec < ts->tv_sec) { | |
if (debug) fprintf(stderr, "Decreasing seconds: %d, was %d\n", hdr->ts.tv_sec, ts->tv_sec); | |
return 0; /* seconds are non-decreasing */ | |
} | |
if (hdr->ts.tv_sec == ts->tv_sec && hdr->ts.tv_usec < ts->tv_usec) { | |
if (debug) fprintf(stderr, "Decreasing time: %d.%d, was %d.%d\n", | |
hdr->ts.tv_sec, hdr->ts.tv_usec, | |
hdr->ts.tv_usec, ts->tv_usec); | |
return 0; /* time is non-decreasing */ | |
} | |
if (hdr->caplen > snaplen) { | |
if (debug) fprintf(stderr, "caplen %u > snaplen %u\n", hdr->caplen, snaplen); | |
return 0; /* cannot have more than snaplen here */ | |
} | |
if (hdr->len < hdr->caplen) | |
return 0; /* packet length cannot be smaller then recorder portion */ | |
if (hdr->len > hdr->caplen && hdr->caplen != snaplen) | |
/* Packet length can only be larger than the recorded portion | |
* if we have the full snaplen recorded. */ | |
return 0; | |
/* Ok, so far it looks like a packet to us, | |
* return the full length to skip, including the | |
* header size. */ | |
return sizeof(*hdr) + hdr->caplen; | |
} | |
unsigned int | |
get_file_header(FILE *dump, struct pcap_file_header *fhdr) | |
{ | |
size_t read; | |
read = fread(fhdr, sizeof *fhdr, 1, dump); | |
if (read != 1) { | |
perror("reading pcap header"); | |
exit(1); | |
} | |
if (fhdr->magic != 0xa1b2c3d4) { | |
fprintf(stderr, "not a recognized pcap file\n"); | |
exit(1); | |
} | |
return fhdr->snaplen; | |
} | |
off_t | |
seek_to_last_sequentially( | |
FILE *dump, off_t pos, off_t size, | |
struct timeval *ts, unsigned int snaplen, int *np) | |
{ | |
struct pcap_pkthdr hdr; | |
unsigned int skip; | |
int n = 0; | |
while (pos + sizeof hdr < size) { | |
if (fseeko(dump, pos, SEEK_SET) != 0) | |
return -1; | |
if (fread(&hdr, sizeof hdr, 1, dump) != 1) | |
return -1; | |
skip = looks_like_packet(&hdr, ts, snaplen, 0); | |
if (skip <= sizeof hdr) | |
return -1; | |
n++; | |
if (pos + skip >= size) { | |
if (np) *np = n; | |
return pos; | |
} | |
pos += skip; | |
} | |
if (np) *np = n; | |
return pos; | |
} | |
off_t | |
try_to_get_packets(FILE *dump, off_t pos, off_t size, | |
struct timeval *ts0, unsigned int snaplen) | |
{ | |
struct timeval ts; | |
off_t npos; | |
int cnt; | |
while (pos + sizeof(struct pcap_pkthdr) < size) { | |
ts = *ts0; | |
npos = seek_to_last_sequentially(dump, pos, size, &ts, snaplen, &cnt); | |
if (npos > 0 && cnt >= 10) { | |
// fprintf(stderr, "Hooray(%d:%lld)!\n", cnt, npos); | |
return npos; | |
} | |
pos++; | |
} | |
return -1; | |
} | |
off_t | |
get_size(FILE *dump) | |
{ | |
if (fseeko(dump, 0, SEEK_END) != 0) | |
return -1; | |
return ftello(dump); | |
} | |
off_t | |
find_last_packet(FILE *dump, unsigned int snaplen, struct timeval *created) | |
{ | |
off_t cur_size, r; | |
size_t chunk_size = 20000; | |
struct stat sb; | |
if (fstat(fileno(dump), &sb) != 0) { | |
perror("cannot stat pcap file"); | |
exit(1); | |
} | |
created->tv_sec = sb.st_birthtime; | |
created->tv_usec = 0; | |
cur_size = get_size(dump); | |
if (cur_size < sizeof(struct pcap_file_header)) { | |
fprintf(stderr, "pcap file is too small\n"); | |
exit(1); | |
} | |
while (chunk_size < snaplen * 10 * 2) { | |
if (cur_size < chunk_size) | |
return seek_to_last_sequentially(dump, sizeof(struct pcap_file_header), cur_size, created, snaplen, NULL); | |
r = try_to_get_packets(dump, cur_size - chunk_size, cur_size, created, snaplen); | |
if (r > 0) | |
return r; | |
chunk_size *= 2; | |
} | |
/* fall back to the worst case */ | |
return seek_to_last_sequentially(dump, sizeof(struct pcap_file_header), cur_size, created, snaplen, NULL); | |
} | |
int | |
do_tail(FILE *dump, off_t pos, unsigned int snaplen, struct timeval *ts) | |
{ | |
off_t size; | |
struct pcap_pkthdr hdr; | |
unsigned int skip; | |
unsigned char *buf; | |
for (;;) { | |
size = get_size(dump); | |
if (size < pos) | |
return -1; | |
if (size < pos + sizeof hdr) { | |
usleep(100000); | |
continue; | |
} | |
// fprintf(stderr, "new packet at %lld\n", pos); | |
if (fseeko(dump, pos, SEEK_SET) != 0) { | |
perror("seek error"); | |
return -1; | |
} | |
if (fread(&hdr, sizeof hdr, 1, dump) != 1) { | |
perror("read error"); | |
return -1; | |
} | |
skip = looks_like_packet(&hdr, ts, snaplen, 0); | |
if (skip <= sizeof hdr) { | |
perror("corrupted pcap stream"); | |
return -1; | |
} | |
full_packet_here: | |
if (pos + skip >= size) { | |
usleep(100000); | |
size = get_size(dump); | |
if (size < pos) { | |
perror("seek error"); | |
return -1; | |
} | |
goto full_packet_here; | |
} | |
/* print hdr + packet */ | |
buf = malloc(skip); | |
if (!buf) { | |
perror("cannot allocate buffer"); | |
return -1; | |
} | |
if (fseeko(dump, pos, SEEK_SET) != 0) { | |
perror("seek error"); | |
return -1; | |
} | |
if (fread(buf, 1, skip, dump) != skip) { | |
perror("read error"); | |
return -1; | |
} | |
fwrite(buf, 1, skip, stdout); | |
free(buf); | |
// fprintf(stderr, "full packet at %lld, skip: %u\n", pos, skip); | |
pos += skip; | |
} | |
return 0; | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
struct pcap_file_header fhdr; | |
unsigned int snaplen; | |
FILE *dump; | |
off_t pos; | |
struct timeval ts; | |
if (argc != 2 || !argv[1]) { | |
fprintf(stderr, "usage:\n\t%s pcapfile\n", argv[0]); | |
return 1; | |
} | |
dump = fopen(argv[1], "r"); | |
snaplen = get_file_header(dump, &fhdr); | |
if (snaplen == 0) | |
return 1; | |
pos = find_last_packet(dump, snaplen, &ts); | |
if (pos <= 0) { | |
fprintf(stderr, "unable to find the last packet\n"); | |
exit(1); | |
} | |
setvbuf(stdout, NULL, _IONBF, 0); | |
fwrite(&fhdr, sizeof fhdr, 1, stdout); | |
do_tail(dump, pos, snaplen, &ts); | |
exit(1); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ---------------------------------------------------------------------------- | |
* "THE BEER-WARE LICENSE" (Revision 42) | |
* <[email protected]> wrote this file. As long as you retain this notice you | |
* can do whatever you want with this stuff. If we meet some day, and you think | |
* this stuff is worth it, you can buy me a beer in return. Anton Berezin | |
* ---------------------------------------------------------------------------- | |
*/ | |
/* | |
* $Id: pcaptail.c,v 1.1 2006/08/21 11:51:17 tobez Exp $ | |
*/ | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <pcap.h> | |
int debug = 0; | |
/* XXX handle different endianness ! */ | |
unsigned int | |
looks_like_packet( | |
struct pcap_pkthdr *hdr, | |
struct timeval *ts, | |
unsigned int snaplen, | |
int swap) | |
{ | |
if (hdr->ts.tv_usec > 1000000) { | |
if (debug) fprintf(stderr, "Cannot have %ld microseconds\n", hdr->ts.tv_usec); | |
return 0; /* cannot have that many microseconds */ | |
} | |
if (hdr->ts.tv_sec < ts->tv_sec) { | |
if (debug) fprintf(stderr, "Decreasing seconds: %ld, was %ld\n", hdr->ts.tv_sec, ts->tv_sec); | |
return 0; /* seconds are non-decreasing */ | |
} | |
if (hdr->ts.tv_sec == ts->tv_sec && hdr->ts.tv_usec < ts->tv_usec) { | |
if (debug) fprintf(stderr, "Decreasing time: %ld.%ld, was %ld.%ld\n", | |
hdr->ts.tv_sec, hdr->ts.tv_usec, | |
hdr->ts.tv_usec, ts->tv_usec); | |
return 0; /* time is non-decreasing */ | |
} | |
if (hdr->caplen > snaplen) { | |
if (debug) fprintf(stderr, "caplen %u > snaplen %u\n", hdr->caplen, snaplen); | |
return 0; /* cannot have more than snaplen here */ | |
} | |
if (hdr->len < hdr->caplen) | |
return 0; /* packet length cannot be smaller then recorder portion */ | |
if (hdr->len > hdr->caplen && hdr->caplen != snaplen) | |
/* Packet length can only be larger than the recorded portion | |
* if we have the full snaplen recorded. */ | |
return 0; | |
/* Ok, so far it looks like a packet to us, | |
* return the full length to skip, including the | |
* header size. */ | |
return sizeof(*hdr) + hdr->caplen; | |
} | |
unsigned int | |
get_file_header(FILE *dump, struct pcap_file_header *fhdr) | |
{ | |
size_t read; | |
read = fread(fhdr, sizeof *fhdr, 1, dump); | |
if (read != 1) { | |
perror("reading pcap header"); | |
exit(1); | |
} | |
if (fhdr->magic != 0xa1b2c3d4) { | |
fprintf(stderr, "not a recognized pcap file\n"); | |
exit(1); | |
} | |
return fhdr->snaplen; | |
} | |
off_t | |
seek_to_last_sequentially( | |
FILE *dump, off_t pos, off_t size, | |
struct timeval *ts, unsigned int snaplen, int *np) | |
{ | |
struct pcap_pkthdr hdr; | |
unsigned int skip; | |
int n = 0; | |
while (pos + sizeof hdr < size) { | |
if (fseeko(dump, pos, SEEK_SET) != 0) | |
return -1; | |
if (fread(&hdr, sizeof hdr, 1, dump) != 1) | |
return -1; | |
skip = looks_like_packet(&hdr, ts, snaplen, 0); | |
if (skip <= sizeof hdr) | |
return -1; | |
n++; | |
if (pos + skip >= size) { | |
if (np) *np = n; | |
return pos; | |
} | |
pos += skip; | |
} | |
if (np) *np = n; | |
return pos; | |
} | |
off_t | |
try_to_get_packets(FILE *dump, off_t pos, off_t size, | |
struct timeval *ts0, unsigned int snaplen) | |
{ | |
struct timeval ts; | |
off_t npos; | |
int cnt; | |
while (pos + sizeof(struct pcap_pkthdr) < size) { | |
ts = *ts0; | |
npos = seek_to_last_sequentially(dump, pos, size, &ts, snaplen, &cnt); | |
if (npos > 0 && cnt >= 10) { | |
// fprintf(stderr, "Hooray(%d:%lld)!\n", cnt, npos); | |
return npos; | |
} | |
pos++; | |
} | |
return -1; | |
} | |
off_t | |
get_size(FILE *dump) | |
{ | |
if (fseeko(dump, 0, SEEK_END) != 0) | |
return -1; | |
return ftello(dump); | |
} | |
off_t | |
find_last_packet(FILE *dump, unsigned int snaplen, struct timeval *created) | |
{ | |
off_t cur_size, r; | |
size_t chunk_size = 20000; | |
struct stat sb; | |
if (fstat(fileno(dump), &sb) != 0) { | |
perror("cannot stat pcap file"); | |
exit(1); | |
} | |
// error: no member named 'st_birthtime' in 'struct stat' | |
// st_birthtime exists on *BSD and OS X | |
// https://github.com/cython/cython/issues/3024 | |
// https://stackoverflow.com/a/5929466 | |
created->tv_sec = sb.st_mtime; | |
created->tv_usec = 0; | |
cur_size = get_size(dump); | |
if (cur_size < sizeof(struct pcap_file_header)) { | |
fprintf(stderr, "pcap file is too small\n"); | |
exit(1); | |
} | |
while (chunk_size < snaplen * 10 * 2) { | |
if (cur_size < chunk_size) | |
return seek_to_last_sequentially(dump, sizeof(struct pcap_file_header), cur_size, created, snaplen, NULL); | |
r = try_to_get_packets(dump, cur_size - chunk_size, cur_size, created, snaplen); | |
if (r > 0) | |
return r; | |
chunk_size *= 2; | |
} | |
/* fall back to the worst case */ | |
return seek_to_last_sequentially(dump, sizeof(struct pcap_file_header), cur_size, created, snaplen, NULL); | |
} | |
int | |
do_tail(FILE *dump, off_t pos, unsigned int snaplen, struct timeval *ts) | |
{ | |
off_t size; | |
struct pcap_pkthdr hdr; | |
unsigned int skip; | |
unsigned char *buf; | |
for (;;) { | |
size = get_size(dump); | |
if (size < pos) | |
return -1; | |
if (size < pos + sizeof hdr) { | |
usleep(100000); | |
continue; | |
} | |
// fprintf(stderr, "new packet at %lld\n", pos); | |
if (fseeko(dump, pos, SEEK_SET) != 0) { | |
perror("seek error"); | |
return -1; | |
} | |
if (fread(&hdr, sizeof hdr, 1, dump) != 1) { | |
perror("read error"); | |
return -1; | |
} | |
skip = looks_like_packet(&hdr, ts, snaplen, 0); | |
if (skip <= sizeof hdr) { | |
perror("corrupted pcap stream"); | |
return -1; | |
} | |
full_packet_here: | |
if (pos + skip >= size) { | |
usleep(100000); | |
size = get_size(dump); | |
if (size < pos) { | |
perror("seek error"); | |
return -1; | |
} | |
goto full_packet_here; | |
} | |
/* print hdr + packet */ | |
buf = malloc(skip); | |
if (!buf) { | |
perror("cannot allocate buffer"); | |
return -1; | |
} | |
if (fseeko(dump, pos, SEEK_SET) != 0) { | |
perror("seek error"); | |
return -1; | |
} | |
if (fread(buf, 1, skip, dump) != skip) { | |
perror("read error"); | |
return -1; | |
} | |
fwrite(buf, 1, skip, stdout); | |
free(buf); | |
// fprintf(stderr, "full packet at %lld, skip: %u\n", pos, skip); | |
pos += skip; | |
} | |
return 0; | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
struct pcap_file_header fhdr; | |
unsigned int snaplen; | |
FILE *dump; | |
off_t pos; | |
struct timeval ts; | |
if (argc != 2 || !argv[1]) { | |
fprintf(stderr, "usage:\n\t%s pcapfile\n", argv[0]); | |
return 1; | |
} | |
dump = fopen(argv[1], "r"); | |
snaplen = get_file_header(dump, &fhdr); | |
if (snaplen == 0) | |
return 1; | |
pos = find_last_packet(dump, snaplen, &ts); | |
if (pos <= 0) { | |
fprintf(stderr, "unable to find the last packet\n"); | |
exit(1); | |
} | |
setvbuf(stdout, NULL, _IONBF, 0); | |
fwrite(&fhdr, sizeof fhdr, 1, stdout); | |
do_tail(dump, pos, snaplen, &ts); | |
exit(1); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment