Layer-2 network security with .NET and Perl
Posted by: Schley Andrew Kutz
I’ve written several articles on SearchServerVirtualization about the VI3 SDK and how to make the most of it with .NET. There is an as-yet unpublished article on how to implement Layer-2 network security with .NET using a program I wrote called gnicmod. Consider it part 4 in my series of leveraging the SDK with .NET. I will update this blog entry with a link to the article once it has been published. In the meantime, I wrote the same program again, but using Perl and the VI Perl Toolkit. I am going to start providing both .NET and Perl examples for all the programs and SDK articles I write in order to attempt to reach the widest audience (Java fans please forgive me).
Many information security and networking offices implement security at a Layer-2 level: they will shut networking ports off if they suspect abuse or have evidence of a compromised system. Like oil and water, Layer-2 security does not mix with virtualization, particularly with ESX and 802.1q and port groups. Shutting a single port off will simply result in VMs rearping on a new port, causing another port to be shut off, and so on. What is needed is the ability to shut off a VM’s virtual port. This blog details my Perl script, vmgnicmod.pl — a VI Perl utility designed to modify a VM’s virtual networking device’s connected and connectOnStart properties. The command is pretty simple. Per its documentation, here are some examples:
Disconnect a VM’s guest’s NIC and do not allow it to be connnected on
start.
vmgnicmod.pl −−server vcms.lostcreations.local −−username akutz
−−password mypassword −−ipAddress 192.168.0.111
Connect a VM’s guest’s NIC whose IP address has changed.
vmgnicmod.pl −−server vcms.lostcreations.local −−username akutz
−−password mypassword −−name purple.lostcreations.local −−connected
For a complete set of documentation you can take a look at the command’s man page. But enough of stuff documentation, let’s take a look at the script!
#!/usr/bin/perl -w
#
# Schley Andrew Kutz
#
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../";
use VMware::VIM2Runtime;
use VMware::VILib;
use XML::LibXML;
use AppUtil::XMLInputUtil;
use AppUtil::HostUtil;
use AppUtil::VMUtil;
# Get the necessary files from lostcreations.com
#
# I recommend that you download these files and edit this portion
# of the script so that you do not have to pull them from mys server
# every time.
my $str_vmreconfig_xml = '/tmp/vmreconfig.xml';
my $str_vmreconfig_xsd = '/tmp/vmreconfig.xsd';
my $str_vmreconfig_xml_url = 'http://www.lostcreations.com/~akutz/vmware/vmreconfig.xml';
my $str_vmreconfig_xsd_url = 'http://www.lostcreations.com/~akutz/vmware/vmreconfig.xsd';
if ( ! -e $str_vmreconfig_xml ) { system( "wget -qO $str_vmreconfig_xml $str_vmreconfig_xml_url" ); }
if ( ! -e $str_vmreconfig_xsd ) { system( "wget -qO $str_vmreconfig_xsd $str_vmreconfig_xsd_url" ); }
$Util::script_version = "1.0";
my %opts = (
ipAddress => {
type => "=s",
help => "The IP address of VM.",
required => 1,
},
name => {
type => "=s",
help => "The name of the VM.",
},
connected => {
type => "",
help => "This flag indicates that the network card should be in a connected state.",
},
connectOnStart => {
type => "",
help => "This flag indicate that the network card should be connected when the VM boots.",
},
);
Opts::add_options(%opts);
Opts::parse();
Opts::validate();
# Logon and save the session token to a file.
Util::connect();
my $str_session_file = ".vipersession" . rand(1000);
Vim::save_session ( session_file => $str_session_file );
# Don't let prying eyes have access to your session token!
system( "chmod 0400 $str_session_file" );
my $str_entity_type = 'VirtualMachine';
my $str_ip_address = Opts::get_option( 'ipAddress' );
my $str_vm_name = Opts::get_option( 'name' );
my $int_connected = Opts::option_is_set( 'connected' );
my $int_connect_on_start = Opts::option_is_set( 'connectOnStart' );
# Find the VM by its IP address
my $o_entity_view = Vim::find_entity_view( view_type => $str_entity_type, filter => { 'guest.ipAddress' => $str_ip_address });
# If the VM could not be found at all then let the user know
if ( !$o_entity_view )
{
Util::trace(0, "Could not find VM by IP address: $str_ip_addressn" );
if ( $str_vm_name )
{
Util::trace(0, "Finding VM by name: $str_vm_namen" );
$o_entity_view = Vim::find_entity_view( view_type => $str_entity_type, filter => { 'config.name' => $str_vm_name });
if ( !$o_entity_view ) { Util::trace(0, "Could not find VM by name: $str_vm_namen" ); }
}
}
# If the VM was found then let's configure its guest's NIC!
if ( $o_entity_view )
{
# Get the name of the VM.
my $str_vm_name = $o_entity_view->name;
Util::trace(0, "Found $str_entity_type: $str_vm_namen");
# Get the name of the ESX host that is running this VM.
my $o_esx_host = Vim::get_view( mo_ref=>$o_entity_view->summary->runtime->host );
my $str_esx_host_name = $o_esx_host->name;
# Report what this command is going to do.
Util::trace(0, "Setting NIC properties to connected=$int_connected and connectOnStart=$int_connect_on_startn");
# Loop through the VM guest's NICs in order to find
# the device ID of the NIC that has the IP address
# we want to turn off/on. Store a reference to that
# NIC's deviceConfigId so we can use it later to
# compare it to the VM guest's virtual devices.
my $arr_guest_nic_info = $o_entity_view->guest->net;
# If no IP address was found that matched then use the
# first IP address. This happens when the VM is already
# disconnected and has a private address that is not
# what the user specified from the command line, but
# the VM was discoveredy anyway because the user used
# the 'name' option.
my $int_device_id = @$arr_guest_nic_info[ 0 ]->deviceConfigId;
foreach ( @$arr_guest_nic_info )
{
if ( $_->ipAddress->[ 0 ] eq $str_ip_address )
{
$int_device_id = $_->deviceConfigId;
}
}
# Find the virtual device that has the same key value
# as that of the NIC which has the IP address we are
# looking for.
my $arr_vm_hardware_devices = $o_entity_view->config->hardware->device;
my $str_vm_guest_nic_name;
foreach ( @$arr_vm_hardware_devices )
{
if ( $_->key eq $int_device_id )
{
$str_vm_guest_nic_name = $_->deviceInfo->label;
last;
}
}
# Prepare the vmreconfig.xml file that will be used to change
# the VM guest's NIC proeprties.
my $str_vm_guest_nic_name_connect = $int_connected ? $str_vm_guest_nic_name : "";
my $str_vm_guest_nic_name_disconnect = $int_connected ? "" : $str_vm_guest_nic_name;
my $str_vm_guest_nic_name_power_on = $int_connect_on_start ? $str_vm_guest_nic_name : "";
my $str_vm_guest_nic_power_on_flag = $str_vm_guest_nic_name_power_on ? ( $int_connect_on_start ? "true" : "false" ) : "";
my $str_vmreconfig_xml_tmp = "/tmp/vmreconfig.xml" . rand(1000);
system( "sed " .
"-e 's/\$str_vm_name/$str_vm_name/g' " .
"-e 's/\$str_host_name/$str_esx_host_name/g' " .
"-e 's/\$str_vm_guest_nic_name_connect/$str_vm_guest_nic_name_connect/g' " .
"-e 's/\$str_vm_guest_nic_name_disconnect/$str_vm_guest_nic_name_disconnect/g' " .
"-e 's/\$str_vm_guest_nic_name_power_on/$str_vm_guest_nic_name_power_on/g' " .
"-e 's/\$str_vm_guest_nic_power_on_flag/$str_vm_guest_nic_power_on_flag/g' " .
"$str_vmreconfig_xml > $str_vmreconfig_xml_tmp" );
# Reconfigure the VM
system( "vmreconfig.pl " .
"--server " . Opts::get_option( 'server' ) . " " .
"--sessionfile $str_session_file " .
"--filename $str_vmreconfig_xml_tmp " .
"--schema $str_vmreconfig_xsd" );
# Delete the temporary XML config file.
unlink $str_vmreconfig_xml_tmp;
}
# Delete the session token file.
unlink $str_session_file;
# Logout of the session. This also invalidates the VM session token, FYI.
Util::disconnect();
If you have any questions about the script feel free to e-mail me. Hope this helps!



You must be logged-in to post a comment. Log-in/Register