Java – Kill FINished sockets (using libpcap – tcpdump/tcpkill)

javapcapperltcpdump

I'm trying to create a small service that monitors and kills sockets which have the FIN flag. I can get them with tcpdump (I also tried tcp[13] & 1):

tcpdump "tcp[tcpflags] & tcp-fin != 0"

tcpkill is suppose to use the same interface as tcpdump, but it isn't working the same. I've tried a bunch of commands, but it should just be (-i eth0 optional):

tcpkill -9 "tcp[tcpflags] & tcp-fin != 0"

Which says (but nothing else, successful tcpkill outputs data):

tcpkill: listening on eth0 [tcp[tcpflags] & tcp-fin != 0]

Looking at the source, it should be passing the correct filter to pcap (between the [ ] brackets). Using a perl script with Net::Pcap I can determine the filter works fine. I don't know what I'm doing wrong, or if it's an older version of tcpkill/pcap that's an issue. Any help with tcpkill or help using perl's Net::Pcap to kill sockets would be appreciated. Thanks!

#!/usr/bin/perl

use strict;
use warnings;

use Net::Pcap;

my $err = '';
my $dev = 'eth0';

my ($address, $netmask);
Net::Pcap::lookupnet($dev, \$address, \$netmask, \$err);

my $pcap = Net::Pcap::open_live($dev, 1500, 1, 0, \$err);

my $filter;
Net::Pcap::compile($pcap, \$filter, "tcp[tcpflags] & tcp-fin != 0", 0, $netmask);
Net::Pcap::setfilter($pcap, $filter);

while(1)
{
 Net::Pcap::loop($pcap, 1, \&process_packet, "packet found");
}

Net::Pcap::close($pcap);

sub process_packet
{
 my($user_data, $header, $packet) = @_;
 print "$user_data\n";
}

exit 0;

Best Answer

Looking at the source code for tcpkill, it uses libnet to generate a RST packet(s) to kill a given TCP connection. I'm not sure why it's not working (though verifying the PCAP version it was built against is a great place to start). You can also use tcpdump to look for the RST packets it should be sending out.

Regarding implementing the equivalent in Perl, I once had to do something sort of similar. Below is (untested!) code which might point you in the right direction.

use NetPacket::Ethernet;
use NetPacket::IP;
use NetPacket::TCP;
use Net::RawIP;

... (the rest of your script) ...

sub process_packet {
    my ($user_data,$header,$packet) = @_;

    my $ethernet_frame = NetPacket::Ethernet::strip($packet);
    my $ip_packet = NetPacket::IP->decode($ethernet_frame);
    my $tcp = NetPacket::TCP->decode($ip_packet->{data});

    my $reset_packet = new Net::RawIP;

    $reset_packet->set({
        ip => {
            saddr => $ip_packet->{dest_ip},
            daddr => $ip_packet->{src_ip}
        },
        tcp => {
            source => $tcp->{dest_port},
            dest => $tcp->{src_port}
        },
        rst => 1,
        seq => $ip->{acknum},
        data => 'access denied'
    });

    $reset_packet->send();
}

tcpkill is more refined in terms of attempting to figure out the correct sequence number, which is what the -1..9 flags are for. Have you tried using different values for that flag?