#!/usr/bin/perl # # Module: vyatta-delete-conntrack.pl # # **** License **** # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program 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. # # This code was originally developed by Vyatta, Inc. # Portions created by Vyatta are Copyright (C) 2010 Vyatta, Inc. # All Rights Reserved. # # Author: Gaurav Sinha # Date: Oct 2011 # Description: Script to delete conntrack entries based on the input # delete command. # # **** End License **** # use Getopt::Long; use warnings; use strict; use XML::Simple; use Data::Dumper; use POSIX; use lib "/opt/vyatta/share/perl5"; use Vyatta::Misc; use Sys::Syslog qw(:standard :macros); use Vyatta::TypeChecker; my $format = "%-10s %-22s %-22s %-12s\n"; my $format_IPv6 = "%-10s %-40s %-40s %-12s\n"; sub add_xml_root { my $xml = shift; $xml = "\n" . $xml . ''; return $xml; } sub print_data_from_xml { my ($data, $cache, $family, $quiet) = @_; my $flow = 0; my %flowh; my $tcount = 0; if (!(defined $quiet)) { print "Deleting the following conntrack table entries:\n\n"; if ($family eq 'ipv6') { printf($format_IPv6, 'CONN ID', 'Source', 'Destination', 'Protocol'); } else { printf($format, 'CONN ID', 'Source', 'Destination', 'Protocol'); } } #open syslog if (!(defined $quiet)) { openlog("vyatta-conntrack", "", LOG_USER); } while (1) { my $meta = 0; last if ! defined $data->{flow}[$flow]; my $flow_ref = $data->{flow}[$flow]; my $flow_type = $flow_ref->{type}; my (%src, %dst, %sport, %dport, %proto, %protonum, $timeout_ref, $connection_id_ref, $state_connection_ref); while (1) { my $meta_ref = $flow_ref->{meta}[$meta]; last if ! defined $meta_ref; my $dir = $meta_ref->{direction}; if ($dir eq 'original' or $dir eq 'reply') { my $l3_ref = $meta_ref->{layer3}[0]; my $l4_ref = $meta_ref->{layer4}[0]; if (defined $l3_ref) { $src{$dir} = $l3_ref->{src}[0]; $dst{$dir} = $l3_ref->{dst}[0]; if (defined $l4_ref) { $sport{$dir} = $l4_ref->{sport}[0]; $dport{$dir} = $l4_ref->{dport}[0]; $proto{$dir} = $l4_ref->{protoname}; $protonum{$dir} = $l4_ref->{protonum}; } } } elsif ($dir eq 'independent') { $timeout_ref = $meta_ref->{timeout}[0]; $connection_id_ref = $meta_ref->{id}[0]; $state_connection_ref = $meta_ref->{state}[0]; } $meta++; } my ($proto, $protonum, $in_src, $in_dst, $out_src, $out_dst, $connection_id, $timeout, $state_connection); $proto = $proto{original}; $protonum = $protonum{original}; if (( $family eq 'ipv6') and (defined $sport{original})) { $in_src = "\[$src{original}]:$sport{original}"; } else { $in_src = "$src{original}"; $in_src .= ":$sport{original}" if defined $sport{original}; } if (( $family eq 'ipv6') and (defined $dport{original})) { $in_dst = "\[$dst{original}]:$dport{original}"; } else { $in_dst = "$dst{original}"; $in_dst .= ":$dport{original}" if defined $dport{original}; } $connection_id = "$connection_id_ref"; $timeout = "$timeout_ref"; if ($state_connection_ref) { $state_connection = "$state_connection_ref"; } # not using these for now $out_src = "|$dst{reply}|"; $out_src .= ":$dport{reply}" if defined $dport{reply}; $out_dst = "|$src{reply}|"; $out_dst .= ":$sport{reply}" if defined $sport{reply}; my $protocol = $proto . ' [' . $protonum . ']'; if (!(defined $quiet)) { if ($family eq 'ipv6') { #IPv6 Addresses can be 39 chars long, so chose the format as per family printf($format_IPv6, $connection_id ,$in_src, $in_dst, $protocol); } else { printf($format, $connection_id ,$in_src, $in_dst, $protocol); } syslog ("info", "Deleting Conntrack entry:conn-id $connection_id, src. IP $in_src, dest. IP $in_dst, protocol $protocol"); } $flow++; } #close syslog if (!(defined $quiet)) { closelog(); } return $flow; } # # main # my ($sourceIP, $destIP, $family, $connection_ID, $quiet); GetOptions("source_IP=s" => \$sourceIP, "dest_IP=s" => \$destIP, "family=s" => \$family, "id=i" => \$connection_ID, "quiet=s" => \$quiet, ); my $xs = XML::Simple->new(ForceArray => 1, KeepRoot => 0); my ($xml1, $xml2, $data); my $command_prefix = "sudo conntrack -D"; my ($command, $sourcePort, $destPort); if ($family) { $command .= " --family $family"; } if (defined($connection_ID)) { $command .= " -i $connection_ID"; } if ($family eq "ipv4") { if ((defined $sourceIP) and $sourceIP =~ m/:/) { #IP address and port entered, are of the form IP:port my @address = split(/:/, $sourceIP); $sourceIP = $address[0]; $sourcePort = $address[1]; if ((defined $sourceIP) and ($sourceIP eq "any")) { $sourceIP = "0.0.0.0"; } #Validate the entered IP and port my( $success, $err ) = isValidPortNumber($sourcePort); if (!(isIpAddress($sourceIP))and !($sourceIP eq "0.0.0.0")) { if(!defined($success)) { #both IP and port are invalid die "Please enter a valid source IPv4 address and port \n"; } else { #only IP is invalid die "Please enter a valid source IPv4 address\n"; } } if(!defined($success)) { #port is invalid die "Please enter a valid source port \n"; } $command .= " --orig-port-src $sourcePort"; } if ((defined $destIP) and $destIP =~ m/:/) { my @address = split(/:/, $destIP); $destIP = $address[0]; $destPort = $address[1]; if ((defined $destIP) and ($destIP eq "any")) { $destIP = "0.0.0.0"; } #Validate the entered IP and port my( $success, $err ) = isValidPortNumber($destPort); if (!(isIpAddress($destIP))and !($destIP eq "0.0.0.0")) { if(!defined($success)) { #both IP and port are invalid die "Please enter a valid destination IPv4 address and port \n"; } else { #only IP is invalid die "Please enter a valid destination IPv4 address\n"; } } if(!defined($success)) { #port is invalid die "Please enter a valid destination port \n"; } $command .= " --orig-port-dst $destPort"; } #support any for 0.0.0.0 if ((defined $sourceIP) and ($sourceIP eq "any")) { $sourceIP = "0.0.0.0"; } if ((defined $destIP) and ($destIP eq "any")) { $destIP = "0.0.0.0"; } if ((defined $sourceIP) and !($sourceIP eq "0.0.0.0")) { # Check if IP address is a valid IPv4 address if (!(isIpAddress($sourceIP))) { die "Please enter a valid source IPv4 address\n"; } #If IP is any, do not add anything to command. $command .= " -s $sourceIP"; } if ((defined $destIP) and !($destIP eq "0.0.0.0")) { # Check if IP address is a valid IPv4 address if (!(isIpAddress($destIP))) { die "Please enter a valid destination IPv4 address\n"; } $command .= " -d $destIP"; } } else { #IPv6 code. if ((defined $sourceIP) and ($sourceIP ne "0:0:0:0:0:0:0:0")) { if ((($sourceIP =~ m/^\[/) and (!($sourceIP =~ m/]/))) or (!($sourceIP =~ m/^\[/) and (($sourceIP =~ m/]/)))) { die "Please use prescribed format for source IP: [IPv6-address]:port \n"; } if (($sourceIP =~ m/^\[/) and ($sourceIP =~ m/]/)) { # [IPv6-address]:port my @address = split(/]/, $sourceIP); if (@address) { if(!$address[0] or !$address[1]) { die "Please use prescribed format for source IP: [IPv6-address]:port \n"; } $sourceIP = substr($address[0], 1); $sourcePort = substr($address[1], 1); my( $success, $err ) = isValidPortNumber($sourcePort); if ($sourceIP ne "any") { if (validateType('ipv6', $sourceIP, 'quiet')) { if ($sourceIP =~ m/[^ABCDEFabcdef0123456789:\[\]]/) { die "Please enter a valid source IPv6 address\n"; } } else { if(!defined($success)) { die "Please enter a valid source IPv6 address and port \n"; } } } if(!defined($success)) { die "Please enter a valid source port \n"; } $command .= " --orig-port-src $sourcePort"; } } else { #IPv6-address without port if ($sourceIP ne "any") { if (validateType('ipv6', $sourceIP, 'quiet')) { if ($sourceIP =~ m/[^ABCDEFabcdef0123456789:\[\]]/) { die "Please enter a valid source IPv6 address\n"; } } else { die "Please enter a valid source IPv6 address\n"; } } } } if ((defined $destIP) and ($destIP ne "0:0:0:0:0:0:0:0")) { if ((($destIP =~ m/^\[/) and (!($destIP =~ m/]/))) or (!($destIP =~ m/^\[/) and (($destIP =~ m/]/)))) { die "Please use prescribed format for destination IP: [IPv6-address]:port \n"; } if (($destIP =~ m/^\[/) and ($destIP =~ m/]/)) { my @address = split(/]/, $destIP); if (@address) { $destIP = substr($address[0], 1); $destPort = substr($address[1], 1); my( $success, $err ) = isValidPortNumber($destPort); if ($destIP ne "any") { if (validateType('ipv6', $destIP, 'quiet')) { if ($destIP =~ m/[^ABCDEFabcdef0123456789:\[\]]/) { die "Please enter a valid destination IPv6 address\n"; } } else { if(!defined($success)) { die "Please enter a valid destination IPv6 address and port \n"; } } } if(!defined($success)) { die "Please enter a valid destination port \n"; } #$command .= " --orig-port-dst $destPort"; } } else { #IPv6-address without port if ($destIP ne "any") { if (validateType('ipv6', $destIP, 'quiet')) { if ($destIP =~ m/[^ABCDEFabcdef0123456789:\[\]]/) { die "Please enter a valid destination IPv6 address\n"; } } else { die "Please enter a valid destination IPv6 address\n"; } } } } # Support "any" keyword if ((defined $destIP) and ($destIP eq "any")) { $destIP = "0:0:0:0:0:0:0:0"; } if ((defined $sourceIP) and ($sourceIP eq "any")) { $sourceIP = "0:0:0:0:0:0:0:0"; } if (($sourceIP) and ($sourceIP ne "0:0:0:0:0:0:0:0")) { $command .= " -s $sourceIP"; } if (($destIP) and ($destIP ne "0:0:0:0:0:0:0:0")) { $command .= " -d $destIP"; } } if (defined ($quiet)) { openlog("vyatta-conntrack", "", LOG_USER); if ($connection_ID) { syslog ("info", "Deleting conntrack entry with connection-id: $connection_ID"); } else { if (!(defined $sourcePort)) { $sourcePort = "any-port"; } if (!(defined $destPort)) { $destPort = "any-port"; } if (!(defined $sourceIP)) { $sourceIP = "any"; } if (!(defined $destIP)) { $destIP = "any"; } syslog("info", "Deleting conntrack entries with parameters: Source IP $sourceIP, source port: $sourcePort, Destination IP $destIP, destination port: $destPort"); } closelog(); } $command .= " -o xml"; if ((defined($destPort)) or (defined($sourcePort))) { my $command_final = $command_prefix." -p tcp".$command; $xml1 = `$command_final 2> /dev/null`; #Execute the command for UDP as well. $command_final = $command_prefix." -p udp".$command; $xml2 = `$command_final 2> /dev/null`; } else { my $command_final = $command_prefix.$command; $xml1 = `$command_final 2> /dev/null`; } # print data received from conntrack command as xml. if ($xml1) { $xml1 = add_xml_root($xml1); $data = $xs->XMLin($xml1); print_data_from_xml($data, "", $family, $quiet); } if ($xml2) { $xml2 = add_xml_root($xml2); $data = $xs->XMLin($xml2); print_data_from_xml($data, "", $family, $quiet); } # end of file