Shut down idle computers on your network automatically

Save electricity, bandwidth, and wear by detecting inactive systems on your network and shutting them down automatically

Learn how to use Argus and client/server Perl code to monitor your network connections and shut down machines no longer in use.

Share:

Recent pushes for "green" technology focus mostly on talk, with little action for the typical home- or small-office environment. Many users leave their systems online continuously through laziness or ignorance, resulting in a significant source of power consumption, as well as an additional vector for malware propagation. The tools and code presented here allow you to find those inactive systems and securely start the shutdown process. With a Linux® box monitoring your network connections using Argus and some custom Perl code, any system that supports Perl can be set to be remotely shut down when a centralized set of inactivity rules are met.

Hardware requirements

Although the control code for securely communicating and shutting down systems is cross-platform, you'll need hardware capable of running Linux for the monitoring computer, which we'll call the control node. Such a node could be a Linksys NSLU2 or similar low-wattage device running Linux. The control node needs a method for monitoring network connections throughout your entire network. Minimal processing power, RAM, and storage are required, unless you intend to monitor hundreds of machines on a high-bandwidth pipe. Virtually any PC manufactured after 2000 with an appropriate network adapter and the capability to run Linux should provide enough capacity to monitor a small office or home network. One network adapter for the control node will suffice in low-traffic settings, but two is better on busy networks. See the "Hardware placement" section for suggestions on where to place your selected system.


Software requirements

Snort, Tcpdump, or a number of network monitoring software packages will work in theory for measuring usage. This article uses a combination of Argus and racluster (an Argus client) due to its simplicity and light weight for tracking connection status. In addition to the heavy lifting done by Argus, you'll need Perl and the associated modules for network communications, random string generation, and encryption. These modules are POE, String::MkPasswd, and Crypt::Blowfish, respectively. See Resources for details on finding and installing these modules.

Hardware placement

Selecting an appropriate location for a full-network monitoring connection point is a complex topic with many variables dependent on specific network attributes. A certain amount of familiarity with network topologies is assumed, as well as the ability to identify the upstream connection point all network traffic flows through.

For example, consider a typical home network with four computers connected to a wireless access point (WAP) or router with an outbound connection through a cable or DSL modem. (I realize using the term "modem" here is inaccurate, but since the industry latched onto the misnomer, I'll use it, too — albeit reluctantly.) Placing the control node network connection between the WAP and the modem allows monitoring of all connections to the Internet from any machine on network. Alternatively, many home-office WAPs are also routers with wired Ethernet ports, so connecting to the WAP's wired port directly may suffice.

Keep in mind that the correct placement of the control node (with the appropriate network interface) and the associated configuration of the network adapter or adapters on the control node may present a formidable challenge for the casual reader. See Resources for tutorials and research materials to help you get started in network monitoring.

Argus setup on the control node

Providing simple measurements of network connection attributes with minimal resource consumption is ideal for this article. Instead of writing Snort rules or analyzing Tcpdump output, use Argus and some command-line switches to provide a minimal list of network connections. On the control node, install Argus and run the following command.

Listing 1. Argus command on control node
argus -w /tmp/argusOutput -i eth0

Transaction records recorded by Argus are appended to the /tmp/argusOutput file, and the eth0 interface is assigned to sniff packets in promiscuous mode. Now that Argus is set up to monitor the connections for each host on the network, use one of the many Argus clients to print out information about those connections. Use the command racluster -L0 -M -u -r /tmp/argusOutput tcp to show the current connections on the network, including information like total bytes transferred and connection start times. Note that this command may produce a great deal of information, so consider isolating the most active connections with the command racluster -L0 -M -u -r /tmp/argusOutput tcp -w - | rasort -m bytes | head.

rasort combined with head will produce a list of the top 10 connections by the number of bytes transferred.

Note that the Argus and process_racluster.pl program (listed below) need to be run as a user with appropriate privileges for accessing the network adapter in promiscuous mode. In most cases, this is the root user.


Selecting machines and bandwidth usage

Each machine to be monitored for inactivity needs to have an identifier, a number of bytes indicating inactivity, and a command to run when inactivity is detected. Listing 2 shows an example activityRules file.

Listing 2. Example activityRules file
192.168.1.30_#_10_#_xmessage "Elena's laptop inactive"
192.168.1.35_#_400_#_xmessage "Alexander's desktop inactive"

Note that these numbers are examples only and need to be tuned for the specific usage of machines on the network. The first line will pop up a message on the control nodes' display (if X Window System is active), letting the user know that the laptop is inactive and needs to be powered down.


process_racluster.pl for inactivity monitoring

Reading the activityRules file, processing racluster output and executing commands is performed by the process_racluster.pl program. Listing 3 lists the first part of process_racluster.pl.

Listing 3. process_racluster.pl part 1
#!/usr/bin/perl -w
# process_racluster.pl - run commands if inactivity conditions are met
use strict;

my $sleepTime     = 600; # seconds between network activity reads
my $argusFile     = "/tmp/argusOutput";
my $raclusterFile = "/tmp/raclusterOutput";
my %rules         = (); # store commands, thresholds for each ip

open( INFILE, "activityRules" )  or die "can't open rules file";
  while(my $line = <INFILE> )
  {
    my( $ip, $threshold, $command ) = split "_#_", $line;
    $rules{ $ip }{ threshold } = $threshold;
    $rules{ $ip }{ command   } = $command;

  }#while in file

close( INFILE );

After variable declaration and reading the activityRules file, the next step is the main logic loop.

Listing 4. process_racluster.pl part 2
while( 1 )
{
  # check if Argus is running 
  my $cmd = qq{ps -aef | grep argus | wc -l };
  die "argus no longer running" unless ( `$cmd` ne "1\n" );

  # transform the argus data into human readable form
  $cmd = qq{racluster -L0 -M -u  -r $argusFile tcp > $raclusterFile};
  $cmd = `$cmd`;

  my %hosts = ();
  open( INFILE, "$raclusterFile" ) or die "can't open argus output file";
    while(my $line = <INFILE> )
    {
      # grab destination addr, port, total packets, bytes, connection status
      $line = substr($line,68);
   
      my( $ipAndPort, undef, $bytes ) = split " ", $line;
      my @parts = split '\.', $ipAndPort;

      # skip if there is no port associated (probably not tcp)
      next unless( $#parts  == 4 );
  
      # get just the ip address 
      my $ip = substr($ipAndPort, 0, rindex($ipAndPort,".") );
   
      $hosts{$ip} += $bytes;
    
    }#while linein
  close(INFILE);

At each pass of the main logic, a simple process check is run to make sure the Argus network connection monitor is active. If so, the racluster command described above is run, and the IP address and associated byte count for all connections to that address is recorded in the %hosts hash. Listing 5 shows the remainder of the main logic loop.

Listing 5. process_racluster.pl part 3
  for my $key( keys %rules )
  {
    my $foundKey = 0;
    $foundKey = 1 if( ! exists($hosts{$key}) );

    if( exists($hosts{$key}) && ($hosts{$key} < $rules{$key}{threshold})  )
    {
      $foundKey = 1;
    }#if key is not found

    next unless ( $foundKey == 1 );

    # run the command, remove the entry from processing
    system( $rules{$key}{command} );
    delete $rules{$key};

  }#for each key in the rules

  # delete the processed files, wait for next pass
  $cmd = qq{ rm $argusFile $raclusterFile };
  $cmd = `$cmd`;

  sleep($sleepTime);

}#while 1 loop

Each defined IP in the rule dataset is checked for existence in the %hosts hash. If the IP is not found, or the byte threshold is less than that specified in the rules file, the inactive command is run. After an inactive state has been found, the entry in the rule dataset is removed to prevent further processing of an already-inactive host. /tmp/argusOutput is deleted to reset the recorded connection status, and the temporary racluster output file is deleted to save space. After sleeping for 10 minutes, the process repeats.

To begin the inactivity processing, run the command perl process_racluster.pl with the same privileges as the ID that ran Argus (usually root). As the "laptop" and "desktop" systems move to inactive states, you'll see a pop-up message on the control node showing you which person to give the Kermit guilt trip ("It's not easy being green").


Remote shutdown of systems

Providing a method for remotely shutting down systems is a great way to open doors for control and abuse. To prevent some of these simpler attacks, the following client and server implement a simple challenge-response system. This approach helps ensure that systems will only respond to the shutdown command if the correct encryption key is used.

Listen for shutdown requests: shutdownListener.pl

Each system that will respond to remote shutdown requests needs to run the shutdownListener.pl program.

Listing 6. shutdownListener.pl
#!/usr/bin/perl -w
# shutdownListener.pl - manage challenge/response, shutdown if authenticated
use strict;
use POE qw(Component::Server::TCP Filter::Reference);
use Crypt::Blowfish;
use String::MkPasswd qw(mkpasswd);

my $key = "<enter your key of choice here>";
my $random = substr(mkpasswd,0,8);
my $cipher = new Crypt::Blowfish $key;
my $cipherText = "";

# heavily influenced by the POE cookbook:
POE::Component::Server::TCP->new
  ( Alias => "shutdownListener",
    Port         => 11211,
    ClientFilter => "POE::Filter::Reference",
    ClientInput  => sub {
        my ( $sender, $heap, $input ) = @_[ SESSION, HEAP, ARG0 ];

        if( $cipherText eq "" )
        { 
          # send the challenge text back to client
          $heap->{client}->put( \$random );
          $cipherText = $cipher->encrypt( $random );

        }elsif( $cipherText eq $$input )
        { 
          print "challenge response match, shutting down\n";
          # uncomment this line to actually shutdown the system
          # system(`shutdown -h now`);   # linux
          # system(`shutdown -s -t 01`); # windows
          exit(0);
        }else
        { 
          print "challenge response does not match, exiting server";
          exit(1);
        }#if cipher text not generated
    },
  );

$poe_kernel->run();
exit 0;

The POE module provides one of the easiest ways to create bidirectional TCP communications using Perl. When a shutdown request is received, the current random string is sent back to the client. If the client's encrypted return string and the locally encrypted string match, the shutdown command is run. Note that you should replace the key with a unique value that matches the key defined in clientShutdown.pl below. In addition to shutting down the system, the shutdownListener.pl will terminate its execution if the challenge response is not met to deter repeated connection attempts.

Save the shutdownListener.pl code on each machine that should enable remote shutdowns. shutdownListener.pl should be run as a user with appropriate privileges to shutdown the machine and access the port selected.


Send shutdown requests: clientShutdown.pl

Each machine to be shut down listens to the control node for shutdown connection requests. These requests come from the clientShutdown.pl program.

Listing 7. clientShutdown.pl
#!/usr/bin/perl -w
# clientShutdown.pl - compute challenge request, send response
use strict;
use POE qw( Component::Client::TCP Filter::Reference);
use Crypt::Blowfish;

die "specify hostname " unless @ARGV == 1;

my $host    = $ARGV[0];
my $key     = "<enter your key of choice here>";
my $cipher  = new Crypt::Blowfish $key;
my $port    = 11211;
my $sendStr = "getChallenge";

# heavily influenced by the POE cookbook:
POE::Component::Client::TCP->new
  ( RemoteAddress => $host,
    RemotePort    => $port,
    Filter        => "POE::Filter::Reference",
    Connected     => sub {
        $_[HEAP]->{server}->put( \$sendStr );
    },
    ConnectError => sub {
        die "could not connect to $host:$port ...\n";
    },
    ServerInput => sub {

      # get the server response
      my ( $input ) = @_[ ARG0 ];

      # encrypt the response, send back
      my $cipherText = $cipher->encrypt( $$input );
      $_[HEAP]->{server}->put( \$cipherText );

    },
  );
$poe_kernel->run();
exit 0;

Similar to shutdownListener.pl, the clientShutdown.pl program connects to the machine to be shut down, retrieves the random text, encrypts it with the shared key, and returns the encrypted text. Again, the encryption key needs to match between the client and server. Modify the activityRules file by inserting the line shown in Listing 8.

Listing 8. Remote shutdown in activityRules
192.168.1.33_#_5555554_#_perl clientShutdown.pl 192.168.1.33

Now when process_racluster.pl is restarted and the total network usage for the 192.168.1.33 machine drops below approximately 5.5 MB over 10 minutes, the shutdown command will be sent.


Usage

To recap the usage instructions: Modify the activityRules file to run the appropriate commands for each machine. Start shutdownListener.pl on any machine that should be remotely shut down. Start Argus and the process_racluster.pl program on the control node.

Conclusion, further examples

With the tools and code in this article, you can set up a network monitor to track the total usage of specific machines on your network. Use the programs presented herein to enforce an automatic shutdown when systems become inactive on the network. Consider modifying Argus to search for specific connection types or hosts. Shut down systems when only 15-minute e-mail checks are active, or when a streaming audio connection is left playing in mute for hours. Monitor the protocol used or the connection start times to further enhance the detection of inactivity that triggers a shutdown.


Download

DescriptionNameSize
Sample codeos-automatic-shutdown-inactiveShutdown_0.1.zip3KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=346055
ArticleTitle=Shut down idle computers on your network automatically
publish-date=10212008