My Quest for (CPU) Power



This glab post is essentially about running a certain shell command remotely on multiple systems within a network that has been set up for public-key authentication. It's a standard task for experienced system administrators I am sure, but for me it was a little adventure in bash scripting — and I wanted to share it with you. I am on a large network. It's one of those large university networks with public-key authentication. So everyone has his own computer, but you can login to a bunch of machines, even the ones in other peoples' offices. Over night, many of my colleagues do not need their computer. Me on the other hand, I need to crunch some numbers every now and then. My mission: Find all the machines that I have access to and list the number of CPUs they have.

List all computers

First, let's list all computers on the network. Easy enough, grab nmap and put the following into quest.sh:
nmap -sL $1 | egrep "for.*\(" | sed "s/.*for \([^\\( ]*\).*$/\1/" > netmap
A simple call to quest.sh 192.168.*.* will give you all the hosts that are around you. You can give it any IP range1. What does it do? It first uses nmap host discovery to make a list of hosts. The list looks a little something like this:
rattle@discovery1[~]$ nmap -sL 192.168.2.10-23

Starting Nmap 6.25 ( http://nmap.org ) at 2013-05-09 18:37 CEST
Nmap scan report for 192.168.2.10
Nmap scan report for 192.168.2.11
Nmap scan report for saturn.yournetwork.com (192.168.2.12)
Nmap scan report for jupiter.yournetwork.com (192.168.2.13)
Nmap scan report for 192.168.2.14
Nmap scan report for 192.168.2.15
Nmap scan report for 192.168.2.16
Nmap scan report for 192.168.2.17
Nmap scan report for uranus.yournetwork.com (192.168.2.18)
Nmap scan report for neptune.yournetwork.com (192.168.2.19)
Nmap scan report for 192.168.2.20
Nmap scan report for 192.168.2.21
Nmap scan report for 192.168.2.22
Nmap scan report for pluto.yournetwork.com (192.168.2.23)
Nmap done: 14 IP addresses (0 hosts up) scanned in 0.01 seconds
The pipe through egrep reduces it to the following:
rattle@discovery1[~]$ nmap -sL 192.168.2.10-23 | egrep "for.*\("
Nmap scan report for saturn.yournetwork.com (192.168.2.12)
Nmap scan report for jupiter.yournetwork.com (192.168.2.13)
Nmap scan report for uranus.yournetwork.com (192.168.2.18)
Nmap scan report for neptune.yournetwork.com (192.168.2.19)
Nmap scan report for pluto.yournetwork.com (192.168.2.23)
And finally, the call to sed will cut out only the hostnames.

Probe your targets

For each host on the network, we want to know if we have access to it. If that is the case, I also find it quite relevant how many CPU kernels it has. It's essentially a simple loop: For each host which was detected by the nmap run, we attempt to execute a command remotely on the host which counts the number of CPUs.
for host in $(cat netmap); do
 count=$(ssh -oConnectTimeout=2 -oBatchMode=yes $host \
   "cat /proc/cpuinfo" 2>&1 | grep proc | wc -l)
 if [ "$count" != "0" ]; then echo $host \($count CPUs\); fi
done
The most important ingredient to this script is this question on serverfault, which makes the script completely non-interactive.

Scan Subnet by default

Finally, I wanted the script to be more fancy. It now grabs my own IP address and the subnet mask from ifconfig and scans the current subnet by default. This is what I ended up with:
if [ -n "$1" ]; then a="$1"; else
 a=$(/sbin/ifconfig eth0 | perl -nle"/dr:(\S+)/ && print $1")
 m=$(/sbin/ifconfig eth0 | perl -nle"/sk:(\S+)/ && print $1")
 m=$(python -c"print(32-sum(bin(int(x)^255).count('1') for x in '$m'.split('.')))")
 a="$a/$m"
fi
for host in $(nmap -sL $a |egrep "for.*\(" |sed "s/.*for \([^\\( ]*\).*$/\1/"); do
 count=$(ssh -oConnectTimeout=2 -oBatchMode=yes $host \
   "cat /proc/cpuinfo" 2>&1 | grep proc | wc -l)
 if [ "$count" != "0" ]; then echo $host \($count CPUs\); fi
done
It works like a charm and can easily be modified to extract lots of other information. Oh right, I almost forgot. Commandlinefu is an awesome website, check it out if you do shell scripting.
  1. If you do not know the network you are on, you should probably not be doing this anyway - still, call /sbin/ifconfig to get your own IP address and the network you are on. []

Leave a Reply

Your email address will not be published. Required fields are marked *