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.

REGISTER or login:

Forgot Password?
By submitting you agree to receive email from TechTarget and its partners. If you reside outside of the United States, you consent to having your personal data transferred to and processed in the United States. Privacy

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: