Skip to content

Instantly share code, notes, and snippets.

@ryo
Created February 21, 2022 02:40
Show Gist options
  • Save ryo/5faf4d75bf4f8045a63c19baabb11f6a to your computer and use it in GitHub Desktop.
Save ryo/5faf4d75bf4f8045a63c19baabb11f6a to your computer and use it in GitHub Desktop.
#!/usr/local/bin/perl
use strict;
use warnings;
use Getopt::Std;
sub usage {
die <<__USAGE__
tcpdump_dd2h [options]
-c output C format
-v verbose
e.g.)
tcpdump -dd port 0x1234 | tcpdump_dd2h
__USAGE__
}
getopts('cv', my $opts = {}) || usage();
my $BPF_CLASS_MASK = 0x07;
my %BPF_CLASS = (
0x00 => 'BPF_LD',
0x01 => 'BPF_LDX',
0x02 => 'BPF_ST',
0x03 => 'BPF_STX',
0x04 => 'BPF_ALU',
0x05 => 'BPF_JMP',
0x06 => 'BPF_RET',
0x07 => 'BPF_MISC'
);
my $BPF_SIZE_MASK = 0x18;
my %BPF_SIZE = (
0x00 => 'BPF_W',
0x08 => 'BPF_H',
0x10 => 'BPF_B'
);
my $BPF_MODE_MASK = 0xe0;
my %BPF_MODE = (
0x00 => 'BPF_IMM',
0x20 => 'BPF_ABS',
0x40 => 'BPF_IND',
0x60 => 'BPF_MEM',
0x80 => 'BPF_LEN',
0xa0 => 'BPF_MSH'
);
my $BPF_OP_MASK = 0xf0;
my %BPF_OP = (
0x00 => 'BPF_ADD',
0x10 => 'BPF_SUB',
0x20 => 'BPF_MUL',
0x30 => 'BPF_DIV',
0x40 => 'BPF_OR',
0x50 => 'BPF_AND',
0x60 => 'BPF_LSH',
0x70 => 'BPF_RSH',
0x80 => 'BPF_NEG',
0x00 => 'BPF_JA',
0x10 => 'BPF_JEQ',
0x20 => 'BPF_JGT',
0x30 => 'BPF_JGE',
0x40 => 'BPF_JSET'
);
my $BPF_SRC_MASK = 0x08;
my %BPF_SRC = (
0x00 => 'BPF_K',
0x08 => 'BPF_X'
);
my $BPF_RVAL_MASK = 0x18;
my %BPF_RVAL = (
0x00 => 'BPF_K',
0x08 => 'BPF_X',
0x10 => 'BPF_A'
);
my $BPF_MISCOP_MASK = 0xf8;
my %BPF_MISCOP = (
0x00 => 'BPF_TAX',
0x80 => 'BPF_TXA'
);
my $RE_NUM = qr/((0x[\da-f]+)|(0[0-7]*)|([1-9][\d]*))/;
#
# parse output of "tcpdump -dd ..."
# e.g.) { 0x6, 0, 0, 0x00000000 },
#
my @code;
while (<>) {
chop;
my $line = $_;
if (m/^{\s*$RE_NUM\s*,\s*$RE_NUM\s*,\s*$RE_NUM\s*,\s*$RE_NUM\s*},$/) {
s/,$//;
tr/{}/()/;
push(@code, [ $line, eval($_) ]);
} else {
warn "unrecognized input: $_\n";
}
}
my $lineno = 0;
for my $insnref (@code) {
my ($line, $code, $jt, $jf, $k) = @$insnref;
my @result;
if (exists $opts->{c}) {
if ($lineno == 0) {
print "struct bpf_insn insns[] = {\n";
}
unless (exists $opts->{v}) {
print "\t";
}
}
if (exists $opts->{v}) {
if ($lineno == 0) {
print "/* Line: code jt(#) jf(#) k struct bpf_insn[] */\n";
print "/* ---- ---- -------- -------- ---------- ---------------------------- */\n";
}
printf("/* %4s: 0x%02x, %3d%5s, %3d%5s, 0x%08x */ ",
"#" . $lineno,
$code,
$jt, (($jt + $jt) == 0) ? "" : "(#" . ($jt + $lineno) . ")",
$jf, (($jt + $jt) == 0) ? "" : "(#" . ($jf + $lineno) . ")",
$k);
}
$lineno++;
$_ = $BPF_CLASS{$code & $BPF_CLASS_MASK};
push(@result, $_);
if (m/_LD/) {
$_ = $BPF_SIZE{$code & $BPF_SIZE_MASK};
push(@result, $_);
$_ = $BPF_MODE{$code & $BPF_MODE_MASK};
push(@result, $_);
} elsif (m/_(JMP|ALU)/) {
$_ = $BPF_OP{$code & $BPF_OP_MASK};
push(@result, $_);
$_ = $BPF_SRC{$code & $BPF_SRC_MASK};
push(@result, $_);
} elsif (m/_RET/) {
$_ = $BPF_RVAL{$code & $BPF_RVAL_MASK};
push(@result, $_);
} elsif (m/_MISC/) {
$_ = $BPF_MISCOP{$code & $BPF_MISCOP_MASK};
push(@result, $_);
} else {
die "$line\n";
}
if ($result[0] =~ m/_JMP/) {
print "BPF_JUMP(";
print join(" + ", @result);
printf ", 0x%08x", $k;
printf ", %d, %d),", $jt, $jf;
} else {
print "BPF_STMT(";
print join(" + ", @result);
printf ", 0x%08x),", $k;
}
print "\n";
}
if (exists $opts->{c}) {
print "};\n";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment