mirror of https://github.com/dirtbags/fluffy.git
add zephyr's excellent pcat
This commit is contained in:
parent
249e959fcc
commit
718137b450
|
@ -0,0 +1,107 @@
|
||||||
|
.\" This manual is Copyright 2012 by pi-rho <ubuntu@tyr.cx>
|
||||||
|
.\"
|
||||||
|
.\" This program is free software: you can redistribute it and/or modify
|
||||||
|
.\" it under the terms of the GNU General Public License as published by
|
||||||
|
.\" the Free Software Foundation, either version 3 of the License, or
|
||||||
|
.\" (at your option) any later version.
|
||||||
|
.\"
|
||||||
|
.\" This package is distributed in the hope that it will be useful,
|
||||||
|
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
.\" GNU General Public License for more details.
|
||||||
|
.\"
|
||||||
|
.\" You should have received a copy of the GNU General Public License
|
||||||
|
.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
.\"
|
||||||
|
.\" On Debian systems, the complete text of the GNU General
|
||||||
|
.\" Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
||||||
|
.
|
||||||
|
.Dd May 23, 2012
|
||||||
|
.Dt PCAT 1
|
||||||
|
.Os "Network Reverse Engineering Toolkit" 1.1337
|
||||||
|
.
|
||||||
|
.Sh NAME
|
||||||
|
.Nm pcat
|
||||||
|
.Nd dump a packet capture in a line-based, parsable format
|
||||||
|
.
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm pcat
|
||||||
|
.Op Fl h | Fl v
|
||||||
|
.Nm pcat
|
||||||
|
.Op Fl o Ar output.txt
|
||||||
|
.Op Pa input.pcap
|
||||||
|
.
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
The basic concept for this utility is to dump the contents of a packet capture
|
||||||
|
in a line-based, parsable format. The general format is as follows:
|
||||||
|
.Pp
|
||||||
|
.D1 Sy TIMESTAMP PROTOCOL SOURCE DESTINATION PAYLOAD
|
||||||
|
.Pp
|
||||||
|
Each value may have attributes separated by commas.
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width "destination"
|
||||||
|
.It Sy TIMESTAMP
|
||||||
|
epoch,nanoseconds
|
||||||
|
.It Sy PROTOCOL
|
||||||
|
ARP, TCP4, UDP4, ICMP4, P# (where # is the IP protocol number)
|
||||||
|
.It Sy SOURCE
|
||||||
|
.Em ARP No \ : macaddress,ipaddress
|
||||||
|
.br
|
||||||
|
.Em ICMP4 : No ipaddress,type,code
|
||||||
|
.br
|
||||||
|
.Em TCP4 No : ipaddress,port,sequence
|
||||||
|
.br
|
||||||
|
.Em UDP4 No : ipaddress,port
|
||||||
|
.br
|
||||||
|
.Em P# No \ \ : ipaddress
|
||||||
|
.It Sy DESTINATION
|
||||||
|
.Em ARP No \ : macaddress,ipaddress
|
||||||
|
.br
|
||||||
|
.Em ICMP4 : No ipaddress
|
||||||
|
.br
|
||||||
|
.Em TCP4 No : ipaddress,port,ack
|
||||||
|
.br
|
||||||
|
.Em UDP4 No : ipaddress,port
|
||||||
|
.br
|
||||||
|
.Em P# No \ \ : ipaddress
|
||||||
|
.It Sy PAYLOAD
|
||||||
|
a hexadecimal representation of the protocol's payload, or '-' if there is no
|
||||||
|
payload
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The available options include:
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -compact -width "-o output.txt"
|
||||||
|
.It Fl h
|
||||||
|
usage information
|
||||||
|
.It Fl v
|
||||||
|
the program's version
|
||||||
|
.It Fl o Ar output.txt
|
||||||
|
sets the output filename to
|
||||||
|
.Pa output.txt
|
||||||
|
.Pq default: Dv stdout
|
||||||
|
.It Ar input.pcap
|
||||||
|
the packet capture to read
|
||||||
|
.Pq default: Dv stdin
|
||||||
|
.El
|
||||||
|
.
|
||||||
|
.Sh EXAMPLES
|
||||||
|
As a filter:
|
||||||
|
.D1 Ic $ Nm pmerge Pa one.pcap Pa two.pcap | Nm pcat > Pa output.txt
|
||||||
|
.Pp
|
||||||
|
In simple command form:
|
||||||
|
.D1 Ic $ Nm pcat Fl o Pa output.txt Pa one.pcap
|
||||||
|
.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr p4split 1 ,
|
||||||
|
.Xr puniq 1 ,
|
||||||
|
.Xr pmerge 1
|
||||||
|
.
|
||||||
|
.Sh AUTHORS
|
||||||
|
.An Zephyr Aq Ad zephyr@dirtbags.net ,
|
||||||
|
.An pi-rho Aq Ad pi-rho@tyr.cx
|
||||||
|
.
|
||||||
|
.Sh BUGS
|
||||||
|
Bugs may be submitted at
|
||||||
|
.Aq Ad https://bugs.launchpad.net/netre-tools
|
||||||
|
.\" vim:ft=mandoc
|
|
@ -0,0 +1,306 @@
|
||||||
|
/* ____ __ ____ ______
|
||||||
|
* | \ / ] / T| T
|
||||||
|
* | o )/ / Y o || |
|
||||||
|
* | _// / | |l_j l_j
|
||||||
|
* | | / \_ | _ | | |
|
||||||
|
* | | \ || | | | |
|
||||||
|
* l__j \____jl__j__j l__j
|
||||||
|
*
|
||||||
|
* dump a packet capture in a line-based, parsable format
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sysexits.h>
|
||||||
|
#include "netre.h"
|
||||||
|
#include "pcap.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#define IPPROTO_ICMP 1
|
||||||
|
#define IPPROTO_TCP 6
|
||||||
|
#define IPPROTO_UDP 17
|
||||||
|
#define ARP_REQ 0x01
|
||||||
|
#define ARP_REP 0x02
|
||||||
|
#define TH_FIN 0x01
|
||||||
|
#define TH_SYN 0x02
|
||||||
|
#define TH_RST 0x04
|
||||||
|
#define TH_PSH 0x08
|
||||||
|
#define TH_ACK 0x10
|
||||||
|
#define TH_URG 0x20
|
||||||
|
|
||||||
|
int version(bool error) {
|
||||||
|
fprintf(WHICHOUT(error), "pcat v.%s - %s\n\n", PACKAGE_VERSION,
|
||||||
|
"dump a packet capture in a line-based, parsable format");
|
||||||
|
return error ? EX_USAGE : EX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usage(bool error, char *prog) {
|
||||||
|
int retval = version(error);
|
||||||
|
fprintf(WHICHOUT(error), "Usage: %s [-o OUTPUT] [FILE]\n", prog);
|
||||||
|
fprintf(WHICHOUT(error), "\t-o OUTPUT file in which to write output; if not specified,\n");
|
||||||
|
fprintf(WHICHOUT(error), "\t output will be written to stdout\n");
|
||||||
|
fprintf(WHICHOUT(error), "\tFILE input pcap file\n");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac_addr(char *addr_s, uint16_t addr1, uint16_t addr2, uint16_t addr3) {
|
||||||
|
snprintf(addr_s, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
(addr1 >> 8) & 0xff,
|
||||||
|
(addr1 >> 0) & 0xff,
|
||||||
|
(addr2 >> 8) & 0xff,
|
||||||
|
(addr2 >> 0) & 0xff,
|
||||||
|
(addr3 >> 8) & 0xff,
|
||||||
|
(addr3 >> 0) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ip4_addr(char *addr_s, uint32_t addr) {
|
||||||
|
snprintf(addr_s, 16, "%u.%u.%u.%u",
|
||||||
|
(addr >> 24) & 0xff,
|
||||||
|
(addr >> 16) & 0xff,
|
||||||
|
(addr >> 8) & 0xff,
|
||||||
|
(addr >> 0) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_payload(struct stream *s, FILE *out) {
|
||||||
|
if (s->len == 0)
|
||||||
|
fprintf(out, "-");
|
||||||
|
else
|
||||||
|
while (s->len)
|
||||||
|
fprintf(out, "%02x", read_uint8(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_icmp(struct stream *s, char *saddr_s, char *daddr_s, FILE *out) {
|
||||||
|
uint8_t type = read_uint8(s);
|
||||||
|
uint8_t code = read_uint8(s);
|
||||||
|
uint16_t chksum = read_uint16be(s);
|
||||||
|
|
||||||
|
fprintf(out, "ICMP4 %s,%u,%u %s ", saddr_s, type, code, daddr_s);
|
||||||
|
|
||||||
|
if (false && chksum && false) {
|
||||||
|
/* Placate compiler */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_tcp(struct stream *s, char *saddr_s, char *daddr_s, FILE *out) {
|
||||||
|
uint16_t sport = read_uint16be(s);
|
||||||
|
uint16_t dport = read_uint16be(s);
|
||||||
|
uint32_t seq = read_uint32be(s);
|
||||||
|
uint32_t ack = read_uint32be(s);
|
||||||
|
uint8_t off = read_uint8(s);
|
||||||
|
uint8_t hlen = (off >> 4) * 4;
|
||||||
|
uint8_t flags = read_uint8(s);
|
||||||
|
uint16_t window = read_uint16be(s);
|
||||||
|
uint16_t chksum = read_uint16be(s);
|
||||||
|
uint16_t urgent = read_uint16be(s);
|
||||||
|
|
||||||
|
if (hlen < 20) printf("!");
|
||||||
|
|
||||||
|
fprintf(out, "TCP4 %s,%u,%u %s,%u,%u ", saddr_s, sport, seq, daddr_s, dport, ack);
|
||||||
|
|
||||||
|
if (false && urgent && chksum && window && flags && ack && seq && false) {
|
||||||
|
/* Placate compiler */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_udp(struct stream *s, char *saddr_s, char *daddr_s, FILE *out) {
|
||||||
|
uint16_t sport = read_uint16be(s);
|
||||||
|
uint16_t dport = read_uint16be(s);
|
||||||
|
uint16_t len = read_uint16be(s);
|
||||||
|
uint16_t chksum = read_uint16be(s);
|
||||||
|
|
||||||
|
fprintf(out, "UDP4 %s,%u %s,%u ", saddr_s, sport, daddr_s, dport);
|
||||||
|
|
||||||
|
if (false && len && chksum && false) {
|
||||||
|
/* Placate compiler */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_arp(struct stream *s, FILE *out) {
|
||||||
|
uint16_t htype = read_uint16be(s);
|
||||||
|
uint16_t ptype = read_uint16be(s);
|
||||||
|
uint8_t hlen = read_uint8(s);
|
||||||
|
uint8_t plen = read_uint8(s);
|
||||||
|
uint16_t op = read_uint16be(s);
|
||||||
|
|
||||||
|
uint16_t sha1 = read_uint16be(s);
|
||||||
|
uint16_t sha2 = read_uint16be(s);
|
||||||
|
uint16_t sha3 = read_uint16be(s);
|
||||||
|
uint32_t spa = read_uint32be(s);
|
||||||
|
|
||||||
|
uint16_t tha1 = read_uint16be(s);
|
||||||
|
uint16_t tha2 = read_uint16be(s);
|
||||||
|
uint16_t tha3 = read_uint16be(s);
|
||||||
|
uint32_t tpa = read_uint32be(s);
|
||||||
|
|
||||||
|
// 12:34:56:78:9A:BC
|
||||||
|
char sha_s[20];
|
||||||
|
char spa_s[20];
|
||||||
|
char tha_s[20];
|
||||||
|
char tpa_s[20];
|
||||||
|
|
||||||
|
mac_addr(sha_s, sha1, sha2, sha3);
|
||||||
|
ip4_addr(spa_s, spa);
|
||||||
|
mac_addr(tha_s, tha1, tha2, tha3);
|
||||||
|
ip4_addr(tpa_s, tpa);
|
||||||
|
|
||||||
|
switch(op) {
|
||||||
|
case ARP_REQ:
|
||||||
|
fprintf(out, "ARP? "); break;
|
||||||
|
case ARP_REP:
|
||||||
|
fprintf(out, "ARP. "); break;
|
||||||
|
default:
|
||||||
|
fprintf(out, "ARP! "); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(out, "%s,%s %s,%s -", sha_s, spa_s, tha_s, tpa_s);
|
||||||
|
|
||||||
|
if (false && htype && ptype && hlen && plen && false) {
|
||||||
|
/* Placate compiler */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_ip4(struct stream *s, FILE *out) {
|
||||||
|
uint8_t vhl = read_uint8(s);
|
||||||
|
uint8_t ihl = (vhl & 0x0f) * 4;
|
||||||
|
if (ihl < 20) ihl = 20;
|
||||||
|
uint8_t tos = read_uint8(s);
|
||||||
|
uint16_t length = read_uint16be(s);
|
||||||
|
uint16_t id = read_uint16be(s);
|
||||||
|
uint16_t off = read_uint16be(s);
|
||||||
|
uint8_t ttl = read_uint8(s);
|
||||||
|
uint8_t proto = read_uint8(s);
|
||||||
|
uint16_t chksum = read_uint16be(s);
|
||||||
|
uint32_t saddr = read_uint32be(s);
|
||||||
|
uint32_t daddr = read_uint32be(s);
|
||||||
|
|
||||||
|
char saddr_s[20];
|
||||||
|
char daddr_s[20];
|
||||||
|
|
||||||
|
ip4_addr(saddr_s, saddr);
|
||||||
|
ip4_addr(daddr_s, daddr);
|
||||||
|
|
||||||
|
DDUMP_d(ihl);
|
||||||
|
DDUMP_d(length);
|
||||||
|
|
||||||
|
// Ignore options
|
||||||
|
sskip(s, 20 - ihl);
|
||||||
|
|
||||||
|
// Force stream length to IP payload length
|
||||||
|
s->len = length - ihl;
|
||||||
|
|
||||||
|
DDUMP_d(proto);
|
||||||
|
switch (proto) {
|
||||||
|
case IPPROTO_ICMP:
|
||||||
|
process_icmp(s, saddr_s, daddr_s, out); break;
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
process_tcp( s, saddr_s, daddr_s, out); break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
process_udp( s, saddr_s, daddr_s, out); break;
|
||||||
|
default:
|
||||||
|
fprintf(out, "P%d %s %s ", proto, saddr_s, daddr_s); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_payload(s, out);
|
||||||
|
|
||||||
|
if (false && chksum && id && tos && ttl && off && false) {
|
||||||
|
/* Placate compiler */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_ethernet(struct stream *s, FILE *out) {
|
||||||
|
uint8_t saddr[6];
|
||||||
|
uint8_t daddr[6];
|
||||||
|
uint16_t vlan;
|
||||||
|
uint16_t ethertype;
|
||||||
|
|
||||||
|
sread(s, &saddr, sizeof(saddr));
|
||||||
|
sread(s, &daddr, sizeof(daddr));
|
||||||
|
ethertype = read_uint16be(s);
|
||||||
|
|
||||||
|
if (ethertype == 0x8100) { // VLAN
|
||||||
|
vlan = read_uint16be(s);
|
||||||
|
ethertype = read_uint16be(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ethertype) {
|
||||||
|
case 0x0806: // ARP
|
||||||
|
process_arp(s, out); break;
|
||||||
|
case 0x0800: // IPv4
|
||||||
|
default:
|
||||||
|
DDUMP_x(ethertype);
|
||||||
|
process_ip4(s, out); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false && vlan && false) {
|
||||||
|
/* Placate compiler */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_frame(struct pcap_pkthdr *hdr, char const *frame, int raw, FILE *out) {
|
||||||
|
struct stream streambuf;
|
||||||
|
struct stream *s = &streambuf;
|
||||||
|
|
||||||
|
sinit(s, frame, hdr->caplen);
|
||||||
|
fprintf(out, "%u.%6.6u ", hdr->ts.tv_sec, hdr->ts.tv_usec);
|
||||||
|
|
||||||
|
if (raw)
|
||||||
|
process_ip4(s, out);
|
||||||
|
else
|
||||||
|
print_ethernet(s, out);
|
||||||
|
|
||||||
|
fprintf(out, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int pcat(FILE *f, FILE *out) {
|
||||||
|
struct pcap_file p;
|
||||||
|
|
||||||
|
if (pcap_open_in(&p, f) == -1) {
|
||||||
|
return EX_IOERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
struct pcap_pkthdr hdr;
|
||||||
|
char frame[MAXFRAME];
|
||||||
|
|
||||||
|
if (pcap_read_pkthdr(&p, &hdr) == -1) break;
|
||||||
|
if (fread(frame, hdr.caplen, 1, f) != 1) break;
|
||||||
|
|
||||||
|
print_frame(&hdr, frame, p.raw, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int opt;
|
||||||
|
FILE *output = stdout;
|
||||||
|
FILE *input = stdin;
|
||||||
|
|
||||||
|
while ((opt = getopt(argc, argv, "hvo:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'o': /* output file */
|
||||||
|
output = fopen(optarg, "wb");
|
||||||
|
if (!output) {
|
||||||
|
perror("opening output");
|
||||||
|
return EX_OSFILE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'v': return version(false);
|
||||||
|
case 'h': return usage(false, argv[0]);
|
||||||
|
default: return usage(true, argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < argc) {
|
||||||
|
input = fopen(argv[optind], "rb");
|
||||||
|
if (!input) {
|
||||||
|
perror("opening input");
|
||||||
|
return EX_OSFILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pcat(input, output);
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
void sinit(struct stream *s, char const *buf, size_t buflen) {
|
||||||
|
s->buf = buf;
|
||||||
|
s->len = buflen;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sskip(struct stream *s, size_t count) {
|
||||||
|
if (count > s->len) {
|
||||||
|
s->len = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->buf += count;
|
||||||
|
s->len -= count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sread(struct stream *s, void *buf, size_t count) {
|
||||||
|
void const *d = s->buf;
|
||||||
|
|
||||||
|
if (!sskip(s, count)) return false;
|
||||||
|
memcpy(buf, d, count);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t read_uint8(struct stream *s) {
|
||||||
|
uint8_t *d = (uint8_t *)s->buf;
|
||||||
|
|
||||||
|
if (!sskip(s, 1)) return 0;
|
||||||
|
return d[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t read_uint16be(struct stream *s) {
|
||||||
|
uint8_t *d = (uint8_t *)s->buf;
|
||||||
|
|
||||||
|
if (!sskip(s, 2)) return 0;
|
||||||
|
return ((d[0] << 8) | (d[1] << 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t read_uint16le(struct stream *s) {
|
||||||
|
uint8_t *d = (uint8_t *)s->buf;
|
||||||
|
|
||||||
|
if (!sskip(s, 2)) return 0;
|
||||||
|
return ((d[0] << 0) | (d[1] << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t read_uint32be(struct stream *s) {
|
||||||
|
uint8_t *d = (uint8_t *)s->buf;
|
||||||
|
|
||||||
|
if (!sskip(s, 4)) return 0;
|
||||||
|
return ((d[0] << 24) | (d[1] << 16) | (d[2] << 8) | (d[3] << 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t read_uint32le(struct stream *s) {
|
||||||
|
uint8_t *d = (uint8_t *)s->buf;
|
||||||
|
|
||||||
|
if (!sskip(s, 4)) return 0;
|
||||||
|
return ((d[0] << 0) | (d[1] << 8) | (d[2] << 16) | (d[3] << 24));
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef _STREAM_H
|
||||||
|
#define _STREAM_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct stream {
|
||||||
|
char const *buf;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
void sinit(struct stream *s, char const *buf, size_t len);
|
||||||
|
bool sskip(struct stream *s, size_t count);
|
||||||
|
bool sread(struct stream *s, void *buf, size_t count);
|
||||||
|
uint8_t read_uint8(struct stream *s);
|
||||||
|
uint16_t read_uint16be(struct stream *s);
|
||||||
|
uint16_t read_uint16le(struct stream *s);
|
||||||
|
uint32_t read_uint32be(struct stream *s);
|
||||||
|
uint32_t read_uint32le(struct stream *s);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue