Skip to main content

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

Nathan Harrington, Programmer, IBM
Nathan Harrington
Nathan Harrington is a programmer working with Linux at IBM. Check out his recently published articles.

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

Date:  21 Oct 2008
Level:  Introductory
Activity:  3167 views

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

DescriptionNameSizeDownload method
Sample codeos-automatic-shutdown-inactiveShutdown_0.1.zip3KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Nathan Harrington

Nathan Harrington is a programmer working with Linux at IBM. Check out his recently published articles.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

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
author1-email=harrington.nathan_@gmail.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers