Subject: | Dissect function for tcp options |
Hi,
I didn't find any perl code anywhere to dissect the tcp options header,
which I needed. So I wrote a function myself which seems to work (tested
on production traffic).
You can find it attached.
The implementation may be not the best and maybe not the fastest one. So
feel free to optimize it. The function takes the option header returned
by $tcp->{options} as an argument and returns a hash containing the
options. I only implemented well known and widely used options. If
packets occur which contain options unknown to the function it may fail.
You may include the function into the ::TCP module if you like.
Thanks in advance,
Tom
Subject: | dissect-tcp-options.pl |
sub parse_tcp_opts {
#
# dissect tcp options header. see:
# http://www.networksorcery.com/enp/protocol/tcp.htm#Options
#
# we create an byte array from the options header
# and iterate through that. If we find an option
# kind number we act accordingly (sometimes it has
# a fixed length, sometimes a variable one).
# once we've got the option stored, we shift the
# bytes we fetched away from the byte array and
# re-enter the loop.
my $opts = shift;
my @bytes = split //, $opts;
my %options;
my $size;
ENTRY:
$size = $#bytes;
foreach my $byte (@bytes) {
my $kind = unpack('C', $byte);
if($kind == 2) {
# MSS.
# next byte is size, set to 4
# next 2 bytes are mss value 16 bit unsigned short
$options{mss} = unpack('S', $bytes[2] . $bytes[3]);
shift @bytes;
shift @bytes;
shift @bytes;
shift @bytes;
goto ENTRY;
}
elsif ($kind == 1) {
# a noop
shift @bytes;
goto ENTRY;
}
elsif ($kind == 3) {
# Windows Scale Factor
# next byte is size, set to 3
# next byte is shift count, 8 bit unsigned
$options{ws} = unpack('C', $bytes[2]);
shift @bytes;
shift @bytes;
shift @bytes;
goto ENTRY;
}
elsif ($kind == 4) {
# SACK Permitted
# next byte is length
$options{sack} = unpack('C', $bytes[1]);
shift @bytes;
shift @bytes;
goto ENTRY;
}
elsif ($kind == 8) {
# timestamp
# next byte is length, set to 10
# next 4 byte is timestamp, 32 bit unsigned int
# next 4 byte is timestamp echo reply, 32 bit unsigned int
$options{ts} = unpack('L', join '', @bytes[2,3,4,5]);
$options{er} = unpack('L', join '', @bytes[6,7,8,9]);
shift @bytes;
shift @bytes;
shift @bytes;
shift @bytes;
shift @bytes;
shift @bytes;
shift @bytes;
shift @bytes;
shift @bytes;
shift @bytes;
goto ENTRY;
}
}
return %options;
}