Virtualization Pro

Dec 20 2007   1:40PM GMT

Layer-2 network security with .NET and Perl

Kutz Profile: Akutz

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, — 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.  −−server vcms.lostcreations.local −−username akutz
       −−password mypassword −−ipAddress

       Connect a VM’s guest’s NIC whose IP address has changed.  −−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
# 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 = '';
my $str_vmreconfig_xsd_url = '';
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.",


# Logon and save the session token to a file.
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_address\n" );
        if ( $str_vm_name )
                Util::trace(0, "Finding VM by name: $str_vm_name\n" );
                $o_entity_view = Vim::find_entity_view( view_type => $str_entity_type, filter => { '' => $str_vm_name });
                if ( !$o_entity_view ) { Util::trace(0, "Could not find VM by name: $str_vm_name\n" ); }

# 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_name\n");

        # 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_start\n");

        # 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;

        # 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( " " .
                "--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.

If you have any questions about the script feel free to e-mail me. Hope this helps!

 Comment on this Post

There was an error processing your information. Please try again later.
Thanks. We'll let you know when a new response is added.
Send me notifications when other members comment.

Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to:

Share this item with your network: