[libvirt] [PATCH 0/3] test cases for spoofing prevention

The following patches add a set of test cases to verify that several spoofing attacks are prevented by the nwfilter subsystem. In order to have a well defined test machine a virtual disk is installed from scratch over the network. I am currently trying to find a suitable location for the kickstart file. -- Best regards, Gerhard Stenzel, ----------------------------------------------------------------------------------------------------------------------------------- IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martin Jetter Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

Add helper functions for network tests like retrieve MAC address of a domain, the IP address from the leases file and functions to create an installation disk. Signed-off-by: Gerhard Stenzel <gstenzel@linux.vnet.ibm.com> Index: libvirt-tck/lib/Sys/Virt/TCK/NetworkHelpers.pm =================================================================== --- /dev/null +++ libvirt-tck/lib/Sys/Virt/TCK/NetworkHelpers.pm @@ -0,0 +1,188 @@ +use XML::LibXML; +use utf8; +use strict; + + +sub get_first_macaddress { + my $dom = shift; + my $result = xpath($dom, "/domain/devices/interface/mac/\@address"); + my @macaddrs = map { $_->getNodeValue} $result->get_nodelist; +# we want the first mac + my $mac = $macaddrs[0]; + utf8::decode($mac); + return $mac; +} + +sub get_ip_from_leases{ + my $mac = shift; + my $tmp = `grep $mac /var/lib/dnsmasq/dnsmasq.leases`; + my @fields = split(/ /, $tmp); + my $ip = $fields[2]; + return $ip; +} + +sub build_and_boot_domain{ + my $tck = shift; + my $conn = shift; + my $disk_path = shift; + my $boot_from_disk = shift; + + my $install_guest; + my $mac = "52:54:00:11:11:11"; + my $model = "virtio"; + my $filterref = "no-spoofing"; + my $network = "network"; + my $source = "default"; + + # prepare to boot install kernel and do a network installation + if ($boot_from_disk == 0) { + $install_guest = $tck->generic_domain("tckinst"); + my $kickstart_file ="http://192.168.122.1/ks.cfg"; + my $cmdline = "ip=dhcp gateway=192.168.122.1 ks=${kickstart_file}"; + $install_guest->boot_cmdline($cmdline); + $install_guest->interface(type => $network, + source => $source, + model => $model, + mac => $mac); + } else { + # prepare to boot from disk + $install_guest = $tck->generic_domain("tckboot"); + $install_guest->clear_kernel_initrd_cmdline(); + $install_guest->interface(type => $network, + source => $source, + model => $model, + mac => $mac, + filterref => $filterref); + } + # common configuration + $install_guest->maxmem("524288"); + $install_guest->memory("524288"); + # replace disk from generic_domain with our own + $install_guest->rmdisk(); + $install_guest->disk(src => $disk_path, + dst => "sda", + type=> "file"); + $install_guest->graphics(type => "vnc", + port => "-1", + autoport => "yes", + listen => "127.0.0.1", + keymap => "de"); + + my $guest_xml = $install_guest->as_xml; + diag $guest_xml; + diag "defining guest"; + my $domtest = undef; + $domtest = $conn->define_domain($guest_xml); + my $xmltest = $domtest->get_xml_description; + diag $xmltest; + return $domtest; +} +sub shutdown_vm_gracefully{ + my $dom = shift; + + $dom->shutdown; + while($dom->is_active()) { + sleep(1); + diag ".. waiting for virtual machine to shutdown.. "; + } + sleep(1); + diag ".. shutdown complete.. "; +} + +sub prepare_test_disk_and_vm{ +my $tck = shift; +my $conn = shift; +my $domain_name = shift; +my $disk_size = "2147483648"; + +# find disk or create new one +my ($disk_path, $installed) = create_disk_if_not_exists($tck, $conn, "${domain_name}.img", $disk_size); + +# if it is new we have to install it +my $boot_from_disk = 0; +if($installed == 0) { + my $testdom = build_and_boot_domain($tck, $conn, $disk_path, $boot_from_disk); + $testdom->create(); + diag "wait for installation to finish .. "; + while($testdom->is_active()) { + sleep(10); + diag ".. to view progress connect to virtual machine ${domain_name} .. "; + } + # cleanup install domain + $testdom->undefine; + $testdom = undef; + sleep (10); + diag " .. done"; + } +# now the disk is installed and we can boot it +$boot_from_disk = 1; +my $testdom = build_and_boot_domain($tck, $conn, $disk_path, $boot_from_disk); +return $testdom; +} + +sub create_disk_if_not_exists{ + my $tck = shift; + my $conn = shift; + my $name = shift; + my $size = shift; + + my $dir = $tck->bucket_dir("nwfilter"); + my $target = catfile($dir, $name); + +# check for installation disk and build it if not exists + my $already_installed = 0; + my $pool_exists = 0; + my $poolname = "default"; + diag("searching pool name: ${poolname}"); + my $npools = $conn->num_of_storage_pools(); + diag("found pools: ${npools}"); + my @poolnames = $conn->list_storage_pool_names($npools); + my $pool; + + foreach (@poolnames){ + diag "pool: $_"; + if (/${poolname}/) { + $pool_exists = 1; + my $pool = $conn->get_storage_pool_by_name($_); + } + } + diag " ${poolname} exists: ${pool_exists}"; + if ($pool_exists == 0){ + diag "Creating pool: ${poolname}"; + my $poolxml = $tck->generic_pool("dir", $poolname)->as_xml; + diag $poolxml; + $pool = $conn->define_storage_pool($poolxml); + $pool->build(0); + $pool->create(); + } else { + $pool = $conn->get_storage_pool_by_name($poolname); + } + + my $nnames = $pool->num_of_storage_volumes(); + my @volNames = $pool->list_storage_vol_names($nnames); + my $vol; + foreach (@volNames){ + diag "volume: $_"; + if (/${name}/) { + $already_installed = 1; + $vol = $pool->get_volume_by_name($_); + diag $vol->get_path(); + } + } + + diag "${name} disk already installed ${already_installed}"; + if ($already_installed == 0){ + diag "Creating ${target}"; + my $volume = $tck->generic_volume($name, "raw", $size, "4", "5"); + $volume->allocation(4096); + my $volumexml = $volume->as_xml; + diag $volumexml; + + $vol = $pool->create_volume($volumexml) + } else { + diag "${target} already exists"; + } + return ($vol->get_path, $already_installed); +} + +1;

Extends domain builder with features like kernel and initrd command line parameter etc which are used in subsequent patches Signed-off-by: Gerhard Stenzel <gstenzel@linux.vnet.ibm.com> Index: libvirt-tck/lib/Sys/Virt/TCK/DomainBuilder.pm =================================================================== --- libvirt-tck.orig/lib/Sys/Virt/TCK/DomainBuilder.pm +++ libvirt-tck/lib/Sys/Virt/TCK/DomainBuilder.pm @@ -172,6 +172,34 @@ sub boot_init { return $self; } +sub boot_cmdline { + my $self = shift; + my $cmdline = shift; + + my $kernel = $self->{boot}->{kernel}; + my $initrd = $self->{boot}->{initrd}; + + $self->{boot} = { + type => "kernel", + kernel => $kernel, + initrd => $initrd, + cmdline => $cmdline + }; + + return $self; +} + +sub clear_kernel_initrd_cmdline { + my $self = shift; + + $self->{boot} = { + type => "kernel", + kernel => "", + initrd => "", + cmdline => "" + }; + return $self; +} sub on_reboot { my $self = shift; @@ -222,6 +250,12 @@ sub loader { } +sub rmdisk { + my $self = shift; + + return pop @{$self->{disks}}; +} + sub disk { my $self = shift; my %params = @_; @@ -235,6 +269,30 @@ sub disk { return $self; } +sub interface { + my $self = shift; + my %params = @_; + + die "type parameter is required" unless $params{type}; + die "source parameter is required" unless $params{source}; + die "model parameter is required" unless $params{model}; + + push @{$self->{interfaces}}, \%params; + + return $self; +} + +sub graphics { + my $self = shift; + my %params = @_; + + die "type parameter is required" unless $params{type}; + + push @{$self->{graphics}}, \%params; + + return $self; +} + sub filesystem { my $self = shift; @@ -344,6 +402,36 @@ sub as_xml { dir => $fs->{dst}); $w->endTag("filesystem"); } + foreach my $interface (@{$self->{interfaces}}) { + $w->startTag("interface", + type => $interface->{type}); + + $w->emptyTag("mac", + address => $interface->{mac}); + $w->emptyTag("source", + network => $interface->{source}); + $w->emptyTag("model", + type => $interface->{model}); + if( $interface->{filterref}) { + $w->emptyTag("filterref", + filter => $interface->{filterref}); + } + $w->endTag("interface"); + } + foreach my $graphic (@{$self->{graphics}}) { + $w->startTag("graphics", + type => $graphic->{type}); + + $w->emptyTag("port", + port => $graphic->{port}); + $w->emptyTag("autoport", + autoport => $graphic->{autoport}); + $w->emptyTag("listen", + listen => $graphic->{listen}); + $w->emptyTag("keymap", + keymap => $graphic->{keymap}); + $w->endTag("graphics"); + } $w->emptyTag("console", type => "pty"); $w->endTag("devices"); $w->endTag("domain");

Add test scripts for spoofing tests Signed-off-by: Gerhard Stenzel <gstenzel@linux.vnet.ibm.com> Index: libvirt-tck/scripts/network/README =================================================================== --- /dev/null +++ libvirt-tck/scripts/network/README @@ -0,0 +1,12 @@ + +Test cases: + +000-install-image.t creates and install a 2GB fedora virtual disk via kickstart file from the network +100-ping-still-working.t verifies the VM is pingable +210-no-mac-spoofing.t verifies mac spoofing is prevented +220-no-ip-spoofing.t verifies ip spoofing is prevented +230-no-mac-broadcast.t verifies mac broadcasting is prevented +240-no-arp-spoofing.t verifies arp spoofing is prevented + + + Index: libvirt-tck/scripts/network/000-install-image.t =================================================================== --- /dev/null +++ libvirt-tck/scripts/network/000-install-image.t @@ -0,0 +1,55 @@ +# -*- perl -*- +# +# Copyright (C) 2010 IBM Corp. +# +# This program is free software; You can redistribute it and/or modify +# it under the GNU General Public License as published by the Free +# Software Foundation; either version 2, or (at your option) any +# later version +# +# The file "LICENSE" distributed along with this file provides full +# details of the terms and conditions +# + +=pod + +=head1 NAME + +network/000-install-image.t - install network test image + +=head1 DESCRIPTION + +The test case creates and install a 2GB fedora virtual +disk via kickstart file from the network. + +=cut + +use strict; +use warnings; + +use Test::More tests => 1; + +use Sys::Virt::TCK; +use Sys::Virt::TCK::NetworkHelpers; + + +my $tck = Sys::Virt::TCK->new(); +my $conn = eval { $tck->setup(); }; +BAIL_OUT "failed to setup test harness: $@" if $@; +END { $tck->cleanup if $tck; } + +use File::Spec::Functions qw(catfile catdir rootdir); + +# variables which may need to be adapted +my $disk_name ="f12nwtest"; + +my $testdom = prepare_test_disk_and_vm($tck, $conn, "${disk_name}"); +$testdom->create(); +ok($testdom->get_id() > 0, "running domain has an ID > 0"); +sleep(20); + +shutdown_vm_gracefully($testdom); + +exit 0; + + Index: libvirt-tck/scripts/network/100-ping-still-working.t =================================================================== --- /dev/null +++ libvirt-tck/scripts/network/100-ping-still-working.t @@ -0,0 +1,83 @@ +# -*- perl -*- +# +# Copyright (C) 2010 IBM Corp. +# +# This program is free software; You can redistribute it and/or modify +# it under the GNU General Public License as published by the Free +# Software Foundation; either version 2, or (at your option) any +# later version +# +# The file "LICENSE" distributed along with this file provides full +# details of the terms and conditions +# + +=pod + +=head1 NAME + +network/100-ping-still-working.t - verify machines can be pinged from host + +=head1 DESCRIPTION + +The test case validates that it is possible to ping a guest machine from +the host. + +=cut + +use strict; +use warnings; + +use Test::More tests => 3; + +use Sys::Virt::TCK; +use Sys::Virt::TCK::NetworkHelpers; +use Test::Exception; +use Net::SSH::Perl; + +use File::Spec::Functions qw(catfile catdir rootdir); + +my $tck = Sys::Virt::TCK->new(); +my $conn = eval { $tck->setup(); }; +BAIL_OUT "failed to setup test harness: $@" if $@; +END { + $tck->cleanup if $tck; +} + +# create first domain and start it +diag "Trying domain lookup by name"; +my $dom1; +my $disk_name ="f12nwtest"; + +$dom1 = prepare_test_disk_and_vm($tck, $conn, "${disk_name}"); +$dom1->create(); + +my $xml = $dom1->get_xml_description; +diag $xml; +ok($dom1->get_id() > 0, "running domain has an ID > 0"); +#my $mac1 = get_macaddress($xml); +#diag $mac1; +#my $result = xpath($dom1, "/domain/devices/interface/mac/\@address"); +#my @macaddrs = map { $_->getNodeValue} $result->get_nodelist; +# we want the first mac +#my $mac1 = $macaddrs[0]; +my $mac1 = get_first_macaddress($dom1); +diag "mac is $mac1"; + +sleep(30); +my $guestip1 = get_ip_from_leases($mac1); +diag "ip is $guestip1"; + +# check ebtables entry +my $ebtable1 = `/sbin/ebtables -L;/sbin/ebtables -t nat -L`; +diag $ebtable1; +# fixme to include mac adress +ok($ebtable1 =~ "vnet0", "check ebtables entry"); + +# ping guest1 +my $ping1 = `ping -c 10 $guestip1`; +diag $ping1; +ok($ping1 =~ "10 received", "ping $guestip1 test"); + +shutdown_vm_gracefully($dom1); + +exit 0; Index: libvirt-tck/scripts/network/210-no-mac-spoofing.t =================================================================== --- /dev/null +++ libvirt-tck/scripts/network/210-no-mac-spoofing.t @@ -0,0 +1,119 @@ +# -*- perl -*- +# +# Copyright (C) 2010 IBM Corp. +# +# This program is free software; You can redistribute it and/or modify +# it under the GNU General Public License as published by the Free +# Software Foundation; either version 2, or (at your option) any +# later version +# +# The file "LICENSE" distributed along with this file provides full +# details of the terms and conditions +# + +=pod + +=head1 NAME + +network/210-no-mac-spoofing.t - verify MAC spoofing is prevented + +=head1 DESCRIPTION + +The test case validates that MAC spoofing is prevented + +=cut + +use strict; +use warnings; + +use Test::More tests => 4; + +use Sys::Virt::TCK; +use Sys::Virt::TCK::NetworkHelpers; +use Test::Exception; +use Net::SSH::Perl; +use XML::LibXML; + +use File::Spec::Functions qw(catfile catdir rootdir); + +my $tck = Sys::Virt::TCK->new(); +my $conn = eval { $tck->setup(); }; +BAIL_OUT "failed to setup test harness: $@" if $@; +END { + $tck->cleanup if $tck; +} + +# create first domain and start it + +my $disk_name ="f12nwtest"; + +my $dom1; +$dom1 = prepare_test_disk_and_vm($tck, $conn, "${disk_name}"); +$dom1->create(); +ok($dom1->get_id() > 0, "running domain has an ID > 0"); +my $xml = $dom1->get_xml_description; +diag $xml; + + +# ping guest1 first nic +my $mac1 = get_first_macaddress($dom1); +diag "mac is $mac1"; + +sleep(30); +my $guestip1 = get_ip_from_leases($mac1); +diag "ip is $guestip1"; + +# check ebtables entry +my $ebtable1 = `/sbin/ebtables -L;/sbin/ebtables -t nat -L`; +diag $ebtable1; +# ebtables shortens :00: to :0: so we need to do that too +$_ = $mac1; +s/00/0/g; +ok($ebtable1 =~ $_, "check ebtables entry"); + +my $gateway = "192.168.122.1"; +my $macfalse = "52:54:00:f9:21:22"; +my $ping1 = `ping -c 10 $guestip1`; +diag $ping1; +ok($ping1 =~ "10 received", "ping $guestip1 test"); + +# log into guest +my $ssh = Net::SSH::Perl->new($guestip1); +$ssh->login("root", "foobar"); + +# now bring eth0 down, change MAC and bring it up again +diag "fiddling with mac"; +my $cmdfile = "echo '" . + "/sbin/ifconfig eth0\n". + "/sbin/ifconfig eth0 down\n". + "/sbin/ifconfig eth0 hw ether ${macfalse}\n". + "/sbin/ifconfig eth0 up\n". + "/sbin/ifconfig eth0\n". + "ping -c 10 ${gateway}\n". + "/sbin/ifconfig eth0 down\n". + "/sbin/ifconfig eth0 hw ether ${mac1}\n". + "/sbin/ifconfig eth0 up\n". + "/sbin/ifconfig eth0\n". + "' > /test.sh"; +diag $cmdfile; +my ($stdout, $stderr, $exit) = $ssh->cmd($cmdfile); +diag $stdout; +diag $stderr; +diag $exit; +($stdout, $stderr, $exit) = $ssh->cmd("chmod +x /test.sh"); +diag $stdout; +diag $stderr; +diag $exit; +($stdout, $stderr, $exit) = $ssh->cmd("/test.sh > /test.log"); +diag $stdout; +diag $stderr; +diag $exit; +($stdout, $stderr, $exit) = $ssh->cmd("cat /test.log"); +diag $stdout; +diag $stderr; +diag $exit; +ok($stdout =~ "100% packet loss", "packet loss expected"); + +shutdown_vm_gracefully($dom1); + +exit 0; Index: libvirt-tck/scripts/network/230-no-mac-broadcast.t =================================================================== --- /dev/null +++ libvirt-tck/scripts/network/230-no-mac-broadcast.t @@ -0,0 +1,107 @@ +# -*- perl -*- +# +# Copyright (C) 2010 IBM Corp. +# +# This program is free software; You can redistribute it and/or modify +# it under the GNU General Public License as published by the Free +# Software Foundation; either version 2, or (at your option) any +# later version +# +# The file "LICENSE" distributed along with this file provides full +# details of the terms and conditions +# + +=pod + +=head1 NAME + +network/230-no-mac-broadcast.t - verify MAC broadcasts are prevented + +=head1 DESCRIPTION + +The test case validates that MAC broadcasts are prevented + +=cut + +use strict; +use warnings; + +use Test::More tests => 3; + +use Sys::Virt::TCK; +use Sys::Virt::TCK::NetworkHelpers; +use Test::Exception; +use Net::SSH::Perl; +use File::Spec::Functions qw(catfile catdir rootdir); + +my $tck = Sys::Virt::TCK->new(); +my $conn = eval { $tck->setup(); }; +BAIL_OUT "failed to setup test harness: $@" if $@; +END { + $tck->cleanup if $tck; +} + +# create first domain and start it +my $dom1; +my $disk_name ="f12nwtest"; + +$dom1 = prepare_test_disk_and_vm($tck, $conn, "${disk_name}"); +$dom1->create(); + +ok($dom1->get_id() > 0, "running domain has an ID > 0"); +my $xml = $dom1->get_xml_description; +diag $xml; +my $mac1 = get_first_macaddress($dom1); +diag "mac is $mac1"; + +sleep(30); +my $guestip1 = get_ip_from_leases($mac1); +diag "ip is $guestip1"; + +# check ebtables entry +my $ebtable1 = `/sbin/ebtables -L;/sbin/ebtables -t nat -L`; +diag $ebtable1; +# fixme to include mac adress +ok($ebtable1 =~ "vnet0", "check ebtables entry"); + +# prepare tcpdump +diag "prepare tcpdump"; +system("/usr/sbin/tcpdump -v -i virbr0 -n host 255.255.255.255 2> /tmp/tcpdump.log &"); + +# log into guest +my $ssh = Net::SSH::Perl->new($guestip1); +$ssh->login("root", "foobar"); + +# now generate a mac broadcast paket +diag "generate mac broadcast"; +my $cmdfile = "echo '" . + "/bin/ping -c 1 192.168.122.255 -b\n". + "' > /test.sh"; +diag $cmdfile; +my ($stdout, $stderr, $exit) = $ssh->cmd($cmdfile); +diag $stdout; +diag $stderr; +diag $exit; +($stdout, $stderr, $exit) = $ssh->cmd("chmod +x /test.sh"); +diag $stdout; +diag $stderr; +diag $exit; +($stdout, $stderr, $exit) = $ssh->cmd("/test.sh > /test.log"); +diag $stdout; +diag $stderr; +diag $exit; +($stdout, $stderr, $exit) = $ssh->cmd("cat /test.log"); +diag $stdout; +diag $stderr; +diag $exit; + +# now stop tcpdump and verify result +diag "stopping tcpdump"; +system("kill -15 `/sbin/pidof tcpdump`"); +my $tcpdumplog = `cat /tmp/tcpdump.log`; +diag($tcpdumplog); +ok($tcpdumplog =~ "0 packets captured", "tcpdump expected to capture no packets"); + +shutdown_vm_gracefully($dom1); + +exit 0; Index: libvirt-tck/scripts/network/240-no-arp-spoofing.t =================================================================== --- /dev/null +++ libvirt-tck/scripts/network/240-no-arp-spoofing.t @@ -0,0 +1,116 @@ +# -*- perl -*- +# +# Copyright (C) 2010 IBM Corp. +# +# This program is free software; You can redistribute it and/or modify +# it under the GNU General Public License as published by the Free +# Software Foundation; either version 2, or (at your option) any +# later version +# +# The file "LICENSE" distributed along with this file provides full +# details of the terms and conditions +# + +=pod + +=head1 NAME + +network/240-no-arp-spoofing.t - verify ARP spoofing is prevented + +=head1 DESCRIPTION + +The test case validates that ARP spoofing is prevented + +=cut + +use strict; +use warnings; + +use Test::More tests => 3; + +use Sys::Virt::TCK; +use Sys::Virt::TCK::NetworkHelpers; +use Test::Exception; +use Net::SSH::Perl; +use File::Spec::Functions qw(catfile catdir rootdir); + +my $spoofid = "192.168.122.183"; + +my $tck = Sys::Virt::TCK->new(); +my $conn = eval { $tck->setup(); }; +BAIL_OUT "failed to setup test harness: $@" if $@; +END { + $tck->cleanup if $tck; +} + +# creating domain +my $dom1; +my $disk_name ="f12nwtest"; + +$dom1 = prepare_test_disk_and_vm($tck, $conn, "${disk_name}"); +$dom1->create(); + +ok($dom1->get_id() > 0, "running domain has an ID > 0"); +my $xml = $dom1->get_xml_description; +diag $xml; +my $mac1 = get_first_macaddress($dom1); +diag "mac is $mac1"; + +sleep(30); +my $guestip1 = get_ip_from_leases($mac1); +diag "ip is $guestip1"; + +# check ebtables entry +my $ebtable1 = `/sbin/ebtables -L;/sbin/ebtables -t nat -L`; +diag $ebtable1; +# check if mac address is listed +ok($ebtable1 =~ "$guestip1", "check ebtables entry"); + +# prepare tcpdump +diag "prepare tcpdump"; +system("/usr/sbin/tcpdump -v -i virbr0 not ip > /tmp/tcpdump.log &"); + +# log into guest +my $ssh = Net::SSH::Perl->new($guestip1); +$ssh->login("root", "foobar"); + +# now generate a arp spoofing packets +diag "generate arpspoof"; +my $cmdfile = "echo '" . + "/usr/bin/yum -y install dsniff\n". + "/usr/sbin/arpspoof ${spoofid} &\n". + "/bin/sleep 10\n". + "kill -15 `/sbin/pidof arpspoof`\n". + "' > /test.sh"; +diag "content of cmdfile:"; +diag $cmdfile; +diag "creating cmdfile"; +my ($stdout, $stderr, $exit) = $ssh->cmd($cmdfile); +diag $stdout; +diag $stderr; +diag $exit; +($stdout, $stderr, $exit) = $ssh->cmd("chmod +x /test.sh"); +diag $stdout; +diag $stderr; +diag $exit; +diag "excuting cmdfile"; +($stdout, $stderr, $exit) = $ssh->cmd("/test.sh > /test.log"); +diag $stdout; +diag $stderr; +diag $exit; +($stdout, $stderr, $exit) = $ssh->cmd("echo test.log\ncat /test.log"); +diag $stdout; +diag $stderr; +diag $exit; + +# now stop tcpdump and verify result +diag "stopping tcpdump"; +system("kill -15 `/sbin/pidof tcpdump`"); +diag "tcpdump.log:"; +my $tcpdumplog = `cat /tmp/tcpdump.log`; +diag($tcpdumplog); +ok($tcpdumplog !~ "${spoofid} is-at", "tcpdump expected to capture no arp reply packets"); + +shutdown_vm_gracefully($dom1); + +exit 0; Index: libvirt-tck/scripts/network/220-no-ip-spoofing.t =================================================================== --- /dev/null +++ libvirt-tck/scripts/network/220-no-ip-spoofing.t @@ -0,0 +1,106 @@ +# -*- perl -*- +# +# Copyright (C) 2010 IBM Corp. +# +# This program is free software; You can redistribute it and/or modify +# it under the GNU General Public License as published by the Free +# Software Foundation; either version 2, or (at your option) any +# later version +# +# The file "LICENSE" distributed along with this file provides full +# details of the terms and conditions +# + +=pod + +=head1 NAME + +network/220-no-ip-spoofing.t - verify IP spoofing is prevented + +=head1 DESCRIPTION + +The test case validates that IP spoofing is prevented + +=cut + +use strict; +use warnings; + +use Test::More tests => 3; + +use Sys::Virt::TCK; +use Sys::Virt::TCK::NetworkHelpers; +use Test::Exception; +use Net::SSH::Perl; + +use File::Spec::Functions qw(catfile catdir rootdir); + +my $tck = Sys::Virt::TCK->new(); +my $conn = eval { $tck->setup(); }; +BAIL_OUT "failed to setup test harness: $@" if $@; +END { + $tck->cleanup if $tck; +} + +# looking up domain +my $dom1; +my $disk_name ="f12nwtest"; + +$dom1 = prepare_test_disk_and_vm($tck, $conn, "${disk_name}"); +$dom1->create(); + +ok($dom1->get_id() > 0, "running domain has an ID > 0"); +my $xml = $dom1->get_xml_description; +diag $xml; +my $mac1 = get_first_macaddress($dom1); +diag "mac is $mac1"; + +sleep(30); +my $guestip1 = get_ip_from_leases($mac1); +diag "ip is $guestip1"; + +# check ebtables entry +my $ebtable1 = `/sbin/ebtables -L;/sbin/ebtables -t nat -L`; +diag $ebtable1; +# check if IP address is listed +ok($ebtable1 =~ "$guestip1", "check ebtables entry"); + +# log into guest +my $ssh = Net::SSH::Perl->new($guestip1); +$ssh->login("root", "foobar"); + +# now bring eth0 down, change IP and bring it up again +diag "preparing ip spoof"; +my $cmdfile = "echo '" . + "/bin/sleep 1\n". + "/sbin/ifconfig eth0\n". + "/sbin/ifconfig eth0 down\n". + "/sbin/ifconfig eth0 192.168.122.183 netmask 255.255.255.0 up\n". + "/sbin/ifconfig eth0\n". + "/bin/sleep 1\n". + "/bin/ping -c 1 192.168.122.1\n". + "/sbin/ifconfig eth0 down\n". + "/sbin/ifconfig eth0 ${guestip1} netmask 255.255.255.0 up\n". + "/sbin/ifconfig eth0 \n". + "/bin/sleep 1\n". + "' > /test.sh"; +diag $cmdfile; +my ($stdout, $stderr, $exit) = $ssh->cmd($cmdfile); +diag $stdout; +diag $stderr; +diag $exit; +($stdout, $stderr, $exit) = $ssh->cmd("chmod +x /test.sh"); +diag $stdout; +diag $stderr; +diag $exit; +diag "running ip spoof"; +($stdout, $stderr, $exit) = $ssh->cmd("/test.sh"); +diag $stdout; +diag $stderr; +diag $exit; +diag "checking result"; +ok($stdout =~ "100% packet loss", "packet loss expected"); + +shutdown_vm_gracefully($dom1); + +exit 0;

On Wed, Jun 16, 2010 at 04:08:00PM +0200, gstenzel@linux.vnet.ibm.com wrote:
The following patches add a set of test cases to verify that several spoofing attacks are prevented by the nwfilter subsystem.
In order to have a well defined test machine a virtual disk is installed from scratch over the network. I am currently trying to find a suitable location for the kickstart file.
I've just remembered that actually anaconda can load a kickstart file from all sorts of interesting places.....including a file on a disk in the machine. So you could create a floppy disk image, containing the kickstart file, add it to the guest XML and boot with "ks=file:fd0/ks.cfg" thus avoiding any need to load it over the network I found this tip here: http://www.redhat.com/magazine/024oct06/features/kickstart/ I'm just trying to get my machines working again so I can actually try out your test cases myself...then i give any more feedback... Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Fri, 2010-06-18 at 18:29 +0100, Daniel P. Berrange wrote:
On Wed, Jun 16, 2010 at 04:08:00PM +0200, gstenzel@linux.vnet.ibm.com wrote:
The following patches add a set of test cases to verify that several spoofing attacks are prevented by the nwfilter subsystem.
In order to have a well defined test machine a virtual disk is installed from scratch over the network. I am currently trying to find a suitable location for the kickstart file.
I've just remembered that actually anaconda can load a kickstart file from all sorts of interesting places.....including a file on a disk in the machine. So you could create a floppy disk image, containing the kickstart file, add it to the guest XML and boot with "ks=file:fd0/ks.cfg" thus avoiding any need to load it over the network
I found this tip here:
http://www.redhat.com/magazine/024oct06/features/kickstart/
I'm just trying to get my machines working again so I can actually try out your test cases myself...then i give any more feedback...
Thanks, please find attached my ks.cfg
Regards, Daniel
-- Best regards, Gerhard Stenzel, ----------------------------------------------------------------------------------------------------------------------------------- IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martin Jetter Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

On Wed, Jun 16, 2010 at 04:08:00PM +0200, gstenzel@linux.vnet.ibm.com wrote:
The following patches add a set of test cases to verify that several spoofing attacks are prevented by the nwfilter subsystem.
In order to have a well defined test machine a virtual disk is installed from scratch over the network. I am currently trying to find a suitable location for the kickstart file.
Do you have the suitable 'ks.cfg' you used with these test scripts ? The test files look good to me and I'm going to commit them all now. We just need the ks.cfg so we can make it work - I'll make it pull it off a floppy disk image Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, 2010-09-09 at 14:48 +0100, Daniel P. Berrange wrote:
On Wed, Jun 16, 2010 at 04:08:00PM +0200, gstenzel@linux.vnet.ibm.com wrote:
The following patches add a set of test cases to verify that several spoofing attacks are prevented by the nwfilter subsystem.
In order to have a well defined test machine a virtual disk is installed from scratch over the network. I am currently trying to find a suitable location for the kickstart file.
Do you have the suitable 'ks.cfg' you used with these test scripts ? The test files look good to me and I'm going to commit them all now. We just need the ks.cfg so we can make it work - I'll make it pull it off a floppy disk image
Regards, Daniel
Here is the one I used. I could update it to a newer fedora version, if necessary: #version=F12 install text url --url=http://ftp-stud.hs-esslingen.de/Mirrors/fedora.redhat.com/linux/releases/12/... lang en_US.UTF-8 keyboard de-latin1-nodeadkeys network --device eth0 --bootproto dhcp rootpw --iscrypted $6$AHEMvpa2rx3n/DON $toWNA/ainpreIRC1g2L9yuil7bS.2hIf8DomTluFGulQtN3KstPeVrmwFMhkwhsW7ud7DANsWycGEL5ZOU50e. firewall --service=ssh authconfig --enableshadow --passalgo=sha512 --enablefingerprint selinux --enforcing timezone --utc Europe/Berlin bootloader --location=mbr --driveorder=sda --append=" LANG=en_US.UTF-8 SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=de-latin1-nodeadkeys rhgb quiet" # The following is the partition information you requested # Note that any partitions you deleted are not expressed # here so unless you clear all partitions first, this is # not guaranteed to work clearpart --all --drives=sda --initlabel part /boot --fstype=ext4 --size=200 part swap --grow --maxsize=256 --asprimary --size=1 part / --fstype=ext3 --grow --size=200 poweroff %packages @admin-tools @base @core #@editors #@fonts @hardware-support #@input-methods #@online-docs #@text-internet #gpgme #gnupg2 #hdparm #m17n-db-tamil #m17n-db-gujarati #m17n-db-kannada #m17n-db-hindi #m17n-db-oriya #m17n-db-bengali #m17n-contrib-sinhala #m17n-db-assamese #m17n-db-punjabi #iok #m17n-db-telugu #tm17n-db-malayalam -- Best regards, Gerhard Stenzel, ----------------------------------------------------------------------------------------------------------------------------------- IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martin Jetter Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

On Thu, Sep 09, 2010 at 03:59:30PM +0200, Gerhard Stenzel wrote:
On Thu, 2010-09-09 at 14:48 +0100, Daniel P. Berrange wrote:
On Wed, Jun 16, 2010 at 04:08:00PM +0200, gstenzel@linux.vnet.ibm.com wrote:
The following patches add a set of test cases to verify that several spoofing attacks are prevented by the nwfilter subsystem.
In order to have a well defined test machine a virtual disk is installed from scratch over the network. I am currently trying to find a suitable location for the kickstart file.
Do you have the suitable 'ks.cfg' you used with these test scripts ? The test files look good to me and I'm going to commit them all now. We just need the ks.cfg so we can make it work - I'll make it pull it off a floppy disk image
Regards, Daniel
Here is the one I used. I could update it to a newer fedora version, if necessary:
Thanks, this one worked fine for me. I've committed your patches to the GIT repository, and added a couple of follow on changes. I made it use virtio instead of scsi for the disk, since RHEL6 doesn't ship with SCSI enabled. I also use mkisofs to put the kickstart file into a tiny ISO image and then boot with ks=cdrom:/ks.cfg so we can avoid needing a web service in the host to provision it. I also changed the filter name from 'no-spoofing' to 'clean-traffic' since libvirt does not have any 'no-spoofing' filter by default & IIUC 'clean-traffic' should be suitable for your tests. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Fri, 2010-09-10 at 10:45 +0100, Daniel P. Berrange wrote:
Thanks, this one worked fine for me. I've committed your patches to the GIT repository, and added a couple of follow on changes. I made it use virtio instead of scsi for the disk, since RHEL6 doesn't ship with SCSI enabled. I also use mkisofs to put the kickstart file into a tiny ISO image and then boot with ks=cdrom:/ks.cfg so we can avoid needing a web service in the host to provision it. I also changed the filter name from 'no-spoofing' to 'clean-traffic' since libvirt does not have any 'no-spoofing' filter by default & IIUC 'clean-traffic' should be suitable for your tests.
Sounds good and I will give it a try ... In the meantime, I think your spec(.PL) file misses something like the following: diff --git a/perl-Sys-Virt-TCK.spec.PL b/perl-Sys-Virt-TCK.spec.PL index aaca325..ecc979c 100644 --- a/perl-Sys-Virt-TCK.spec.PL +++ b/perl-Sys-Virt-TCK.spec.PL @@ -118,6 +118,7 @@ rm -rf $RPM_BUILD_ROOT %{perlvendorlib}/Sys/Virt/TCK.pm %{perlvendorlib}/Sys/Virt/TCK/ %dir %{_localstatedir}/cache/libvirt-tck +/etc/libvirt-tck/ks.cfg %changelog * Fri Mar 24 2006 <berrange@redhat.com> - 0.0.1-1 -- Best regards, Gerhard Stenzel, ----------------------------------------------------------------------------------------------------------------------------------- IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martin Jetter Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

On Fri, Sep 10, 2010 at 04:02:16PM +0200, Gerhard Stenzel wrote:
On Fri, 2010-09-10 at 10:45 +0100, Daniel P. Berrange wrote:
Thanks, this one worked fine for me. I've committed your patches to the GIT repository, and added a couple of follow on changes. I made it use virtio instead of scsi for the disk, since RHEL6 doesn't ship with SCSI enabled. I also use mkisofs to put the kickstart file into a tiny ISO image and then boot with ks=cdrom:/ks.cfg so we can avoid needing a web service in the host to provision it. I also changed the filter name from 'no-spoofing' to 'clean-traffic' since libvirt does not have any 'no-spoofing' filter by default & IIUC 'clean-traffic' should be suitable for your tests.
Sounds good and I will give it a try ...
In the meantime, I think your spec(.PL) file misses something like the following:
diff --git a/perl-Sys-Virt-TCK.spec.PL b/perl-Sys-Virt-TCK.spec.PL index aaca325..ecc979c 100644 --- a/perl-Sys-Virt-TCK.spec.PL +++ b/perl-Sys-Virt-TCK.spec.PL @@ -118,6 +118,7 @@ rm -rf $RPM_BUILD_ROOT %{perlvendorlib}/Sys/Virt/TCK.pm %{perlvendorlib}/Sys/Virt/TCK/ %dir %{_localstatedir}/cache/libvirt-tck +/etc/libvirt-tck/ks.cfg
Yes, good point. I've added this. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Fri, 2010-09-10 at 16:02 +0200, Gerhard Stenzel wrote:
Sounds good and I will give it a try ...
All my tests worked except scripts/nwfilter/210-no-mac-spoofing.t, which failed with on Fedora 13: ... # ' > /test.sh input must be 8 bytes long at /usr/lib64/perl5/Crypt/DES.pm line 57. # Looks like you planned 4 tests but ran 3. ... Here is the patch, that fixes the problem for me: diff --git a/scripts/nwfilter/210-no-mac-spoofing.t b/scripts/nwfilter/210-no-mac-spoofing.t index df47fd7..2906e1f 100644 --- a/scripts/nwfilter/210-no-mac-spoofing.t +++ b/scripts/nwfilter/210-no-mac-spoofing.t @@ -25,6 +25,7 @@ The test case validates that MAC spoofing is prevented use strict; use warnings; +use utf8; use Test::More tests => 4; @@ -94,6 +95,7 @@ my $cmdfile = "echo '" . "/sbin/ifconfig eth0 up\n". "/sbin/ifconfig eth0\n". "' > /test.sh"; +utf8::encode ($cmdfile); diag $cmdfile; my ($stdout, $stderr, $exit) = $ssh->cmd($cmdfile); diag $stdout; -- Best regards, Gerhard Stenzel, ----------------------------------------------------------------------------------------------------------------------------------- IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martin Jetter Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

On Tue, Sep 14, 2010 at 02:52:13PM +0200, Gerhard Stenzel wrote:
On Fri, 2010-09-10 at 16:02 +0200, Gerhard Stenzel wrote:
Sounds good and I will give it a try ...
All my tests worked except scripts/nwfilter/210-no-mac-spoofing.t, which failed with on Fedora 13: ... # ' > /test.sh input must be 8 bytes long at /usr/lib64/perl5/Crypt/DES.pm line 57. # Looks like you planned 4 tests but ran 3. ...
Hmm, yes I see that same problem.
Here is the patch, that fixes the problem for me:
diff --git a/scripts/nwfilter/210-no-mac-spoofing.t b/scripts/nwfilter/210-no-mac-spoofing.t index df47fd7..2906e1f 100644 --- a/scripts/nwfilter/210-no-mac-spoofing.t +++ b/scripts/nwfilter/210-no-mac-spoofing.t @@ -25,6 +25,7 @@ The test case validates that MAC spoofing is prevented
use strict; use warnings; +use utf8;
use Test::More tests => 4;
@@ -94,6 +95,7 @@ my $cmdfile = "echo '" . "/sbin/ifconfig eth0 up\n". "/sbin/ifconfig eth0\n". "' > /test.sh"; +utf8::encode ($cmdfile);
This is bizarre - I don't see any characters in the $cmdfile string that are above ASCII-7 range, so should be identical whether its utf8 encoded or not !?!? Do you know why this makes it work correctly ? Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Tue, 2010-09-14 at 14:10 +0100, Daniel P. Berrange wrote:
This is bizarre - I don't see any characters in the $cmdfile string that are above ASCII-7 range, so should be identical whether its utf8 encoded or not !?!? Do you know why this makes it work correctly ?
The presence of ${mac1} in $cmdfile causes the problem. Eliminating $mac1 makes the problem go away. $mac1 is initialized like this: my $mac1 = get_first_macaddress($dom1); I guess, reading from the XML causes some sort of encoding problem. I googled for the error message and found similar problems which were fixed by using utf8::encode. -- Best regards, Gerhard Stenzel, ----------------------------------------------------------------------------------------------------------------------------------- IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martin Jetter Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294
participants (3)
-
Daniel P. Berrange
-
Gerhard Stenzel
-
gstenzel@linux.vnet.ibm.com