Interrogating a Linux Machine
The other day, a client called upon me to perform a hardware and software inventory on all of the computers on his network. There weren't that many machines to inventory, but we needed to gather quite a bit of information about each one. The client was a Microsoft shop and so I had to deal with about an even mix of Windows XP and Vista with a few Windows 95, 98, and ME machines thrown in for good measure.
So off I went, with an Excel spreadsheet in hand. I visited each machine in person. For each machine, I wanted the network configuration, the workgroup configuration, and the hardware configuration. We also wanted to know what software was installed as well as which drivers were being used. Bonus points for being able to determine what USB devices were being used.
Needless to say, this was tedious work. Some of the data, such as the network configuration, was available in the same place on each platform, the command line. Other information was only available at various control panels, and they varied by platform.
Granted, things might have been easier if I was a bit more proficient in using Windows. But it got me to thinking. How would I do this job if I were working in a Linux shop? How much of this information could I gather? Where would I look? How hard would it be?
It turns out that Linux keeps most of this information in fairly standardized locations. The rest of the information, such as installed software, can be had with just a few platform-specific commands.
I'm fond of telling people that “everything is easier in Linux.” This statement stems from the fact that I don't find myself “hunting” for just the right menu or GUI widget that I need to get a task done. Now sure, I'm demonstrating a bias that I have formed based on years of experience with Linux. But by the end of this article, I hope you see how easy it is to interrogate a machine with just a few commands.
Now let's get started.
First, we need to get the complete network configuration. Once we log in, we see the machine's hostname as part of our shell prompt. We can take a quick look at the DNS configuration with “cat /etc/resolv.conf”. Before going on, we'll simply verify that the DNS configuration looks right. Then we'll get a list of network interfaces, as well as their IP and MAC addresses with “ifconfig -a”.
eth0 Link encap:Ethernet HWaddr 00:17:31:64:B0:BD inet addr:10.0.1.56 Bcast:10.0.1.255 Mask:255.255.255.0 inet6 addr: fe80::217:31ff:fe64:b0bd/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:127554145 errors:255 dropped:0 overruns:0 frame:255 TX packets:84151845 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:3916476961 (3735.0 Mb) TX bytes:4229971584 (4034.0 Mb) Interrupt:16 Base address:0x6000 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:68839 errors:0 dropped:0 overruns:0 frame:0 TX packets:68839 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:2933412 (2.7 Mb) TX bytes:2933412 (2.7 Mb)
From this, we can gleen the IP address as well as the MAC address of the Ethernet interface. We'll ignore the Loopback interface.
We can take a quick look at the routing table to make sure there's nothing strange going on with the “route -n” command.
Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 10.0.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo 0.0.0.0 10.0.1.1 0.0.0.0 UG 0 0 0 eth0
The default gateway, 10.0.1.1, looks right, so we move on.
Well, that's the network configuration, but what kind of machine is this? We can gather a lot of information from the /proc filesystem. For example, we can find out what kind of CPU is installed with the “cat /proc/cpuinfo” command.
processor : 0 vendor_id : AuthenticAMD cpu family : 15 model : 35 model name : AMD Athlon(tm) 64 X2 Dual Core Processor 4200+ stepping : 2 cpu MHz : 2200.000 cache size : 512 KB physical id : 0 siblings : 2 core id : 0 cpu cores : 2 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 1 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt lm 3dnowext 3dnow pni lahf_lm cmp_legacy ts fid vid ttp bogomips : 4425.38 processor : 1 vendor_id : AuthenticAMD cpu family : 15 model : 35 model name : AMD Athlon(tm) 64 X2 Dual Core Processor 4200+ stepping : 2 cpu MHz : 2200.000 cache size : 512 KB physical id : 0 siblings : 2 core id : 1 cpu cores : 2 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 1 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt lm 3dnowext 3dnow pni lahf_lm cmp_legacy ts fid vid ttp bogomips : 4422.96
As you can see, I'm using an AMD Athlon 64 (4200+) with 2 cores. You can even see that Linux checks for some of the Intel/AMD CPU bugs that have been found over the years, as well some of the special instruction sets that have evolved, such as MMX or 3dnow.
We can determine how much memory is installed by looking at the size of /proc/kcore with the “ls -lah /proc/kcore” command, which will print the file size in human-friendly format.
-r-------- 1 root root 897M Oct 15 12:31 /proc/kcore
We'll just round that 897M up to 1G, since the kernel uses some of the installed memory.
It sure would be nice to find out what hardware is installed without having to open the chassis. This is as easy as using the lspci command.
00:00.0 Memory controller: nVidia Corporation CK804 Memory Controller (rev a3) 00:01.0 ISA bridge: nVidia Corporation CK804 ISA Bridge (rev a3) 00:01.1 SMBus: nVidia Corporation CK804 SMBus (rev a2) 00:02.0 USB Controller: nVidia Corporation CK804 USB Controller (rev a2) 00:02.1 USB Controller: nVidia Corporation CK804 USB Controller (rev a3) 00:04.0 Multimedia audio controller: nVidia Corporation CK804 AC'97 Audio Controller (rev a2) 00:06.0 IDE interface: nVidia Corporation CK804 IDE (rev f2) 00:07.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev f3) 00:08.0 IDE interface: nVidia Corporation CK804 Serial ATA Controller (rev f3) 00:09.0 PCI bridge: nVidia Corporation CK804 PCI Bridge (rev a2) 00:0a.0 Bridge: nVidia Corporation CK804 Ethernet Controller (rev a3) 00:0b.0 PCI bridge: nVidia Corporation CK804 PCIE Bridge (rev a3) 00:0c.0 PCI bridge: nVidia Corporation CK804 PCIE Bridge (rev a3) 00:0d.0 PCI bridge: nVidia Corporation CK804 PCIE Bridge (rev a3) 00:0e.0 PCI bridge: nVidia Corporation CK804 PCIE Bridge (rev a3) 00:18.0 Host bridge: Advanced Micro Devices [AMD] K8 [Athlon64/Opteron] HyperTransport Technology Configuration 00:18.1 Host bridge: Advanced Micro Devices [AMD] K8 [Athlon64/Opteron] Address Map 00:18.2 Host bridge: Advanced Micro Devices [AMD] K8 [Athlon64/Opteron] DRAM Controller 00:18.3 Host bridge: Advanced Micro Devices [AMD] K8 [Athlon64/Opteron] Miscellaneous Control 05:06.0 VGA compatible controller: nVidia Corporation NV34 [GeForce FX 5200] (rev a1)
As you can see, I've got an nVidia GeForce FX 5200 video card and nVidia CK804 AC'97 soundcard on my system's motherboard. You can also see that I've got USB. More on that in a moment. Not every Linux distribution installs lspci by default; you should do this anytime you build a new machine, though.
Sometimes you get called upon to fix a hardware problem where the device just doesn't seem to work right. Soundcards are the typical example and the problem is usually caused by an IRQ conflict or having an IRQ shared with another busy device such as the hard drive or network interface. We can tell what interrupts are being used by what with the “cat /proc/interrupts” command
CPU0 CPU1 0: 220186162 56790290 IO-APIC-edge timer 1: 0 2 IO-APIC-edge i8042 8: 1 1 IO-APIC-edge rtc 9: 0 0 IO-APIC-fasteoi acpi 12: 0 4 IO-APIC-edge i8042 14: 1375087 2345774 IO-APIC-edge ide0 15: 9971601 12 IO-APIC-edge ide1 16: 173144676 152683932 IO-APIC-fasteoi ohci_hcd:usb2, eth0 17: 0 0 IO-APIC-fasteoi libata, NVIDIA nForce Audio 18: 0 0 IO-APIC-fasteoi libata 19: 242148 231918 IO-APIC-fasteoi ehci_hcd:usb1 20: 93937183 75701777 IO-APIC-fasteoi nvidia NMI: 0 0 LOC: 276981218 276986794 ERR: 0 MIS: 0
We can quickly assess our hard drive configuration with the “fdisk -l /dev/?d?” command.
Disk /dev/hda: 320.0 GB, 320072933376 bytes 255 heads, 63 sectors/track, 38913 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/hda1 1 13 104391 83 Linux /dev/hda2 14 76 506047+ 82 Linux swap / Solaris /dev/hda3 77 3812 30009420 83 Linux /dev/hda4 3813 38913 281948782+ 83 Linux Disk /dev/hdb: 250.0 GB, 250059350016 bytes 255 heads, 63 sectors/track, 30401 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/hdb1 1 30401 244196001 83 Linux Disk /dev/hdc: 251.0 GB, 251000193024 bytes 255 heads, 63 sectors/track, 30515 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/hdc1 1 30515 245111706 83 Linux
Here you can see that I've got 3 IDE drives. Using the “?” wildcard in the command line makes this go much faster.
By the way, if you wanted to know what type of hard drive /dev/hda was, you could ask with this command, “cat /proc/ide/hda/model”
The results of this command on my machine are “WDC WD3200JB-00KFA0,” which indicates that my /dev/hda is a Western Digital Caviar 320Gb. This is a case where Google is your friend.
Speaking of harddrives, we can determine which filesystems our system supports by looking at the /proc/filesystems file. The results are intuitive, so I'll leave it as an exercise for the reader.
If the kernel was configured to support it, the /proc/config.gz file is a compressed file that contains the configuration of the currently running kernel. This file, once uncompressed, is suitable for use as the .config file found in the root of the Linux Kernel source tree. By capturing this file, you can reproduce, and make changes to the current kernel configuration.
Of course many of the device drivers in the Linux Kernel load as dynamically loaded modules. We can determine which drivers are loaded this way by using the lsmod command.
Module Size Used by nvidia 7096684 48 vboxdrv 66928 0
Sometimes a driver requires another driver in order to operate. This situation would be indicated in the “Used by” column.
Remember earlier when I said we'd get bonus points for identifying what was plugged into the USB ports? Well we can easily do this with the lsusb command.
Bus 001 Device 001: ID 0000:0000 Bus 002 Device 002: ID 413c:1002 Dell Computer Corp. Keyboard Hub Bus 002 Device 004: ID 413c:2002 Dell Computer Corp. SK-8125 Keyboard Bus 002 Device 001: ID 0000:0000
And finally, we need to get a list of the installed software. RPM-based distributions give us this information with the “rpm -qa” command. I don't use Debian, but I'm told you can use the “dpkg -l” command to get a list of installed packages. Under Gentoo, I'd use “emerge --pretend --emptytree world” or install the qpkg tool.
At this point, we know almost everything there is to know about the machine. The Linux Kernel has other secrets though, and I encourage you to poke around in the /proc and /sys filesystems to find them.
Though some of these commands require root privilege, none of them required a GUI, a mouse, or even physical access to the machine. If you had a login and root password, you could do all of this remotely and even automate it with a script. See, I told you it would be easy!