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_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 => { 'config.name' => $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; 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