|
|||||||||||||||
|
Hi. So here I will attempt to build us a nice sysadmin toolkit. What is that you ask? Let's say it is what your average system administrator should always be walking around with. It contains a slew of commands and utilities that are, in my opinion, indispensable to any sysadmin no matter what his/her area of expertise. This is an ambitious undertaking and I hope visitors will contribute some ideas of their own by emailing me.
I have partitioned this tutorial into three chunks:
The tools looked at will not be receiving a comprehensive treatment by any stretch of the imagination. The reader is urged to plumb the depths of those topics he/she finds interesting.
I will collectively refer to commands/tools usually provided with the base Unix installation as the standard toolset.
Here is a list of what we will see in this section:
cd, cp, mv, mkdir, rm, rmdir, cat, clear, less
RTFM!
These three utilities deal with space and memory.
df gives you an overview of the manner in which your hard disks are partitioned and how much space is used in each partition.
Typical usage:
$ df -h Filesystem Size Used Avail Capacity Mounted on /dev/wd0a 1006M 96.8M 859M 10% / /dev/wd1a 183G 32.0G 142G 18% /home /dev/wd0d 5.9G 4.8G 826M 86% /root /dev/wd0e 5.9G 2.4G 3.2G 43% /usr /dev/wd0f 2.0G 187M 1.7G 10% /tmp /dev/wd0h 87.9G 31.7G 51.8G 38% /var /dev/wd0g 78.7G 32.2M 74.8G 0% /var/log |
The du command displays the block system usage (greater than the actual file size) of a specified file or directory. If you specify a directory you will only get statistics on subdirectories. You must have the appropriate permissions to access the statistics.
An example where we want info on usage of a specified directory as well as the summary of the directory itself (the last line):
$ du -h /tmp/bnc 6.0K /tmp/bnc/help 2.0K /tmp/bnc/lang 2.0K /tmp/bnc/log 2.0K /tmp/bnc/menuconf/help 4.0K /tmp/bnc/menuconf 2.0K /tmp/bnc/motd 2.0K /tmp/bnc/scripts/example 4.0K /tmp/bnc/scripts 2.0K /tmp/bnc/src 2.0K /tmp/bnc/tools 250K /tmp/bnc |
The reason the last line (the directory) and the above lines (the subdirectories) do not add up is because there are some files under the directory that are not considered.
An example where we want system block usage of a directory only:
$ du -sh ~ 44.0K /home/petermatulis |
The third command is free. This is a very useful command but it is not native to FreeBSD or OpenBSD. It is a Linux thing. For something comparable, try the FreeBSD port for the muse utility:
$ muse -m |
The output (on my smashing new box I might add),
Active: 10.012 MB Inactive: 243.719 MB Wired: 114.566 MB Reserved: 1.617 MB Cache: 0.000 MB Kernel: 0.133 MB Interrupt: 0.008 MB Buffer: 111.234 MB Total: 997.223 MB Free: 628.379 MB |
The file program attempts to determine the nature of a file (its type). Possible types include:
In addition, the file command recognizes a plethora of well-known formats. It uses the /etc/magic file for this.
Syntax:
$ file some_file |
The whatis command will provide a very brief summary of the purpose of a command. Actually, it provides information available in the manual pages.
Syntax:
$ whatis some_command |
To get more details on a command, therefore, use the manual pages themselves via the man utility. The manual pages also contain information on non-executable files.
Syntax:
$ man some_file_or_some_command |
A useful feature of man is to have it search itself for manual entries matching a keyword:
$ man -k keyword |
Example:
$ man -k bash bash (1) - GNU Bourne-Again SHell bashbug (1) - report a bug in bash |
The find command is one command you need to have good control over to be an efficient sysadmin. I will give examples of some useful forms.
To find a file with the given pattern, below the /usr directory, owned by the root user, and give a long directory listing of the matches:
# find /usr -type f -name 'a*f*[sf]' -user root -ls |
To find a directory with the given pattern below the / directory, owned by group wheel, and apply the du command to the returned matches:
# find / -type d -name 'p*' -group wheel -exec du -sh {} \; |
The above could of been done by piping the results to the xargs command:
# find / -type d -name 'p*' -group wheel | xargs du -sh |
To find any type of file, below the /home directory, with a size greater than 256 kB, and with permissions 775:
# find /home -size +256000c -perm 775 |
To find a file below /usr/local, modified within the last 48 hours, but contained within 4 directory levels (/usr/local being the first level):
# find /usr/local -type f -mtime -2 -maxdepth 4 |
To find a file below the / directory, accessed within the last minute, but contained lower than 1 directory level (/ being the first level):
# find / -type f -amin -1 -mindepth 2 |
This utility searches files for lines containing a match to a given pattern. I am using grep (GNU grep) 2.4.1 here
To search for the pattern "LaserJet" in the file /etc/magic while ignoring the case of the pattern:
$ grep -i LaserJet /etc/magic |
To search for the pattern "LaserJet" in all files in the current directory and give just the number of matches found:
$ grep -c LaserJet * |
To search for the whole word "LaserJet" in the file /etc/magic and include the 2 preceeding lines and the 2 succeeding lines:
$ grep -2 -w LaserJet /etc/magic |
To search among multiple patterns (one per line) found in the file "grepstrings" in the file /etc/magic. Finding any one pattern will produce a match:
$ grep -f grepstrings /etc/magic |
To search for a string containing metacharacters in the file /etc/magic:
$ grep -F ok?*w /etc/magic |
To search for the string "LaserJet" in all files in the /etc directory (and its subdirectories) and include line numbers:
$ grep -n -r LaserJet /etc |
An inverse search. Only lines not containing the pattern "Laser Jet" in the file /etc/magic:
$ grep -v 'Laser Jet' /etc/magic |
GNU grep has powerful regular expression capabilities. Here are a few examples.
Two equivalent ways to search for lines beginning with a digit in the file /etc/magic:
$ grep ^[0-9] /etc/magic | $ grep ^[[:digit:]] /etc/magic |
To search for 5 characters in the file /etc/magic. The first character is alphanumeric at the beginning of a word, followed by any 2 characters, followed by the digit 4, followed by any character at the ending of the word:
$ grep '\<[[:alnum:]]..4.$' /etc/magic |
To search for a word in the file /etc/magic that begins with 7 or more digits in the range of 1 to 9:
$ grep '\<[1-9]\{7,\}' /etc/magic |
We can create a situation where one or more expressions finds a match. Below we search for the strings "$5000" and/or "$10000" in the file /etc/magic. Notice how we force grep to act as egrep by employing the '-E' switch. egrep is better suited for regular expressions:
$ grep -E '\$5000|\$10000' /etc/magic |
We can also use the output of another command as the input for grep using a pipe:
$ dmesg | grep 'isa\|irq' |
Above we're taking the output of the dmesg command and filtering it through to grep. Here, grep searches for any lines containing the strings "isa" and/or "irq". I use this one often when troubleshooting network interfaces and modems.
To specify that a line must contain both isa and irq we pipe into a second grep:
$ dmesg | grep isa | grep irq |
These three utilities are used to quickly locate files. Each one is implemented in slightly different ways.
locate searches a database (OpenBSD default is /var/db/locate.database but it can be specified with the "-d" switch) for all pathnames which match the specified pattern. The database is recomputed periodically (usually weekly or daily), and contains the pathnames of all files which are publicly accessible.
The simplified syntax for locate is:
$ locate pattern | This will be taken as '*pattern* ' |
Use locate for files that do not have the executable attribute or for strings found anywhere in the pathname.
For example,
$ locate ml/8 |
The output,
/usr/local/share/doc/aspell/man-html/8_How.html |
which takes a name (or list of names) and returns the absoulte filenames of commands that would be executed had these names been given as commands. This utility depends completely on the PATH environmental variable; if it is not defined then it will fail unless the name is given as a correct relative or absolute pathname. Only the paths found in this variable will be searched so there may well be executables on the filesystem that are not found. Also, only the first match in the PATH is given as output (use the "-a" switch to display all matches).
The simplified syntax for which is:
$ which name(s) |
Use which for files that have the executable attribute.
For example,
$ which man ls ps |
The output,
/usr/bin/man /bin/ls /bin/ps |
whereis performs the same task as which. The only difference is in the paths it searches. Whereas which uses the paths found in the PATH variable whereis uses those returned by the sysctl(8) utility for the "user.cs_path" string.
On a random system here are the differences in these paths:
$ sysctl -a user.cs_path user.cs_path=/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin $ echo $PATH /home/petermatulis/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/games:. |
A basic but indispensible command. I include it here because it is one of the first commands a new user encounters but then never bothers to learn any of its many useful options.
To show a long listing; show hidden (dot) files but supress the current and parent entries (. and ..); and apply the command to all subdirectories as well:
$ ls -lAR |
To show a long listing; show all hidden files; sort by size (largest first); and show size in "human readable" form:
$ ls -laSh |
Note: I found the "h" option available only with Red Hat.
To show a long listing; show all hidden files; show the time a file's status was last changed; and express user and group in numerical format:
$ ls -acn |
Notice how the "n" option implies a long listing.
To show a long listing; show all hidden files; show the time a file was last accessed; and reverse the sorting order (here it will show latest accessed file last):
$ ls -laur |
To show a long listing; show all hidden files; sort by modification time (latest first); and show in detailed time format:
$ ls -latT |
Note: Only on OpenBSD does the "T" switch assume the above meaning. On Red Hat, you specify "--full-time".
Determine how many excutables reside in the /usr directory (and its subdirectories):
$ ls -FR /usr | grep $'*' | wc -l |
Above, the files that have their executable bit set (by either owner, group, or other) are listed due to the "F" switch where such files are identified by a star (asterisk). The output to this command on my OpenBSD 3.3 system is:
10778 |
Other types of files are identifiable using the "F" switch. The OpenBSD man page:
-F Display a slash (`/') immediately after each pathname that is a directory, an asterisk (`*') after each that is executable, an at sign (`@') after each symbolic link, a percent sign (`%') after each whiteout, an equal sign (`=') after each socket, and a ver- tical bar (`|') after each that is a FIFO. |
Sed is known as a stream editor and is shipped with all Unix variants. Its chief purpose is to edit text files by performing deletions and substitutions. This editing is based on a rule (or rules) specified on the command line or in a file. This makes it a non-interactive editor. This also allows shell scripts to utilize sed to perform repetitive tasks. The input text is read from a file or a pipe (output from another command) and the modified results are sent to standard output or to a file.
Before getting bogged down in details let's look at sed in action:
$ cat file The fox jumped over the stream. $ sed -e 's/fox/horse/' file The horse jumped over the stream. $ sed -e 'd' file .............................. |
What we did there was replace the word "fox" with the word "horse" and the results were automatically sent to standard output (the screen). Then we deleted every line (there is only one) in the file so there is null as output (the last line is a blank line). An important point to note is that the original file remains unchanged. This is a trivial example. The power of sed becomes apparent when either mass editing of files is required or when editing of files (on any scale) is needed at predetermined times.
Sed syntax
There are four ways to invoke sed:
1. sed -e 'command1' -e 'command2' -e 'command3' file 2. {shell command} | sed -e 'command1' -e 'command2' 3. sed -f sedscript.sed file 4. {shell command} | sed -f sedscript.sed |
{ sed commands on the command line with input from a file } { sed commands on the command line with input from output of another command } { sed commands from a file with input from a file } { sed commands from a file with input from output of another command } |
Input is always processed line by line. So if the input is a file consisting of fifty lines then sed is applied fifty times (with each line being processed independently). And as explained above, the "command" may be a deletion or a substitution. When multiple commands are used each successive command acts upon the result of the preceeding command. The text that sed is currently working on is called the pattern space.
Deletion
The format of the delete command is as follows:
[address1[ , address2 ] ]d |
In sed, addresses represent lines. If one address is given, then the command is applied to lines containing that address. An address can be either a regular expression enclosed by forward slashes /regex/ , or a line number . The "$" symbol can be used in place of a line number to denote the last line. If two addresses are given, then the command is applied to all lines between the two lines that match the pattern.
Here we are deleting the first six lines of the file "test":
$ sed -e '1,6d' test |
Below we remove all lines ending with the string "taoist.". Notice that I escape the period. I do this to be explicit about the ending period because if I don't do this then "." will act as a regex (any one character):
$ sed -e '/taoist\.$/d' test |
We can only delete entire lines using the delete command. In order to delete parts of a line (like a word) you must use the substitution command and use a null character as the replacement.
Substitution
The format of the substitute command is as follows:
[address1[ ,address2]]s/pattern/replacement/[flags] |
The pattern (not the pattern space) is some regular expression (or simply a string or word) and the replacement is a string we want to replace the pattern with. sed regular expressions are essentially the same as those used with grep.
The flags can be any of the following:
For some reason we cannot use the "w" option with the delete command. If we want to send the results to a file we need to use redirection:
$ sed -e '/taoist\.$/d' test > test_modified |
This next example tells sed to operate on any line in the file "test" contaning the word "peter" and to erase the second instance of the word "This" (via the use of a null character):
$ sed -e '/peter/s/This//2' test |
This tells sed to operate on lines 3 through 15 (inclusive) in the file "test" and to replace all instances of the word "This" with the word "That" and send the results to the file "test_modified":
$ sed -e '3,15s/This/That/gw test_modified' test |
Let's move on to something more mature. My task is now to perform a mass substitution to all my HTML documents. For instance, I want to change an image that resides on all my pages, say, "email.jpg" to "email.gif". The first thing to notice is that I am now dealing with multiple files whereas before I always dealt with single files. In such a case I need to write a script (call it "replace.sh") that contains a reiteration (a loop):
#! /bin/sh TMP=/tmp/replace.sh.tmp find $1 -type f -name "*$2*" | while read i do cat $i | sed -e "s/$3/$4/g" > $TMP mv $TMP $i done |
I am employing four positional variables here. The second form of the sed syntax given earlier is being used. Also notice how I need to use double quotes in order to expand my variables.
Here is how I would invoke the script (assuming it resides in my PATH; that all HTML documents are stored under the /www directory; and that the documents contain the string "html" in their filenames):
$ replace.sh /www html email.jpg email.gif |
Caution: Before using a sed command on existing documents ensure you have done enough testing. This is especially true if you are working with multiple files.
More sed information:
I will collectively refer to commands/tools not necessarily provided with the base Unix installation as the custom toolset.
Here is a list of what we will see in this section:
GNU Screen is a handy tool for those people who find themselves with many (command line) terminals open simultaneously. It is also valuable if you run commands that a) take a long time to complete and b) produce output that you are interested in monitoring. It is the classic command-line geek tool.
The man page describes it like this:
Screen is a full-screen window manager that multiplexes a physical terminal between several processes (typically interactive shells).
It is also useful as an educative tool since multiple users can attach their login sessions to existing shells. The possibility of remote connections (typically via SSH) amplifies the power of this last feature which should naturally be dampened with the appropriate security measures.
It is invoked very simply:
$ screen |
At this point all commands used to control screen itself must be prepended with the default C-a (Ctrl-a) keystroke. Otherwise you can proceed as you normally would on the command line.
Basic usage
Here are some rudimentary commands to get you started. The commands provided below are the defaults for my installation. YMMV.
creating
The first action you will want to take is to create some extra screen windows. This is analogous to tabbed internet browsing. The command to create another window is c (create). Hence:
$ C-a c |
selecting
To select a window use n (next) and p (previous). Each window is also assigned a number that can be used instead. A third method is via a menu: ". Yet a fourth, and probably the easiest, way is <SPACE> (the SPACEBAR) which scrolls through the windows in order.
splitting
Another popular feature is to split the current window into two regions (horizontal splitting; one on top of the other). This is accomplished with the S (split) command:
$ C-a S |
To switch over to the other region use <TAB> (the TAB key). At first there will be nothing in the new region. Just use the selection commands to bring up a window once you're over there. As of April 2006, there is talk of implementing vertical splitting.
To remove the current region: X.
naming
It is useful to assign a name to each window. Do this with the A command.
locking
To lock your entire screen session do x. To unlock you will need to supply the account password of the user who first invoked screen.
closing
To close the current window do K.
quitting
To stop screen completely and kill all its windows and corresponding processes do \.
help
To get online help use ?.
Intermediate usage
detach
To detach the screen session the command is d. It is very important to realize that the session is still alive and all associated processes continue to run. This is true even after you log out.
attach
To attach to a screen session you obviously need one to attach to. To view current sessions use this command at a normal shell prompt:
$ screen -ls |
To attach to a single-existing session simply do:
$ screen -r |
You will need to specify which session you want to attach to if there are more than one. This is done by adding the argument [pid].tty.host to the above command.
To attach to an already attached session, that is, to share a session, use x instead of r.
copy, paste, and the scrollback buffer
One thing that may be seen as a hindrance is the fact that you lose your terminal's ability to scroll back to see previous console work. That is, you no longer have access to your terminal's scroll buffer. To turn on screen's buffer use [ and to turn it off use ]. Connected to this is screen's copy & paste ability. When the buffer is on use your vi skills to position the cursor at the beginning of the desired text and hit ENTER (no C-a required). Then move the cursor to the end of the desired text and hit ENTER again. Now when you are ready to paste simply turn off the buffer.
Configuration
Screen has a global configuration file and a user-based configuration file. Their default locations are /usr/local/etc/screenrc and ~/.screenrc respectively. Here is a sample:
# Turn off the splash screen startup_message off # Screen commands are now prefixed by the "`" character (not C-a) escape `` # Increase the default scrollback buffer from 100 to 3000 defscrollback 3000 # Set up a custom status line hardstatus alwayslastline hardstatus string '%{= wb}%-Lw%{= bw}%50> %n%f* %t%{= wb}%+Lw%< %{= bw}%-=%D, %M %d, %Y %c%{-}' # Remove (by null assignment) some default key bindings bind '\' bind 'k' # Create some custom key bindings bind 'q' quit # Quit Screen altogether (running programs are killed) # Start two windows screen -t SECOND 2 screen -t FIRST 1 |
Here is a screenshot of my terminal work where I am running the fluxbox window manager. Each tab on the left edge is a different host. The current host "sonata" has a screen session that was created with the above configuration. Note especially the status bar at the bottom. The "tab" of the current window is always blue-on-beige. The special screen command keystroke has been changed to " ` " (the back tick instead of C-a).
Here we will cover utilities pertaining to network matters. Some security software will be included here.
Here is a list of what we will see in this section:
The Address Resolution Protocol (ARP) is used by the network layer Internet Protocol (IP) to map IP addresses to hardware addresses used by a data link protocol.
The arp program displays and modifies the Internet-to-Ethernet address translation tables used by ARP. These tables are flushed regularly.
$ arp -a |
spider.pmatulis.homeunix.net (192.168.1.40) at 00:a0:4b:03:e0:1d on vr0 daffy.pmatulis.homeunix.net (192.168.1.70) at 00:c0:4f:94:64:10 on vr0 |
The arp utility does not actively seek out IP/MAC mappings. It merely displays its current information. The following tool makes up for that.
The arping utility allows one to easily determine a MAC address from an IP address. It does this by "pinging" a host on the local subnet by manually sending an ARP request message (who-is query ethernet broadcast). I say "manually" because the arp protocol is normally employed in an automatic fashion. This occurs whenever two hosts need to communicate. Either way, the result is always the MAC (or hardware) address of the specified host.
Here we specify raw output, the count, and which interface to use:
$ arping -r -c1 -i vr0 daffy |
00:c0:4f:94:64:10 |
The raw switch (r) is to display only the MAC address and nothing else.
You may also use this tool to ping a MAC address itself (in which case a directed broadcast ICMP Echo request is sent) to find the associated IP address:
$ arping -r -c1 -i vr0 00:c0:4f:94:64:10 |
192.168.1.70 |
Here I am using the Slackware 9.0 version of this utility.
Ifconfig is used to configure and inspect the status/configuration of network interfaces. It is launched automatically at boot time to set up interfaces as necessary.
This utility is indespensible. You will always use it as a network administrator.
The most basic usage is to view the current configuration of a (or all) network interface(s). Below we run ifconfig without any options (to display information for all interfaces):
$ ifconfig |
eth0 Link encap:Ethernet HWaddr 00:C0:4F:AC:12:3B inet addr:192.168.1.32 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:2062267 errors:12137 dropped:0 overruns:0 frame:22225 TX packets:1391100 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 RX bytes:651253275 (621.0 Mb) TX bytes:1151145914 (1097.8 Mb) Interrupt:11 Base address:0xdc80 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:503 errors:0 dropped:0 overruns:0 frame:0 TX packets:503 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:49818 (48.6 Kb) TX bytes:49818 (48.6 Kb) |
Let us bind a second IP address to our eth0 card:
$ ifconfig eth0:0 192.168.1.33 # route add -host 192.168.1.33 eth0:0 $ ifconfig |
eth0 Link encap:Ethernet HWaddr 00:C0:4F:AC:12:3B inet addr:192.168.1.32 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:2067418 errors:12139 dropped:0 overruns:0 frame:22229 TX packets:1393042 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 RX bytes:652603405 (622.3 Mb) TX bytes:1152071057 (1098.7 Mb) Interrupt:11 Base address:0xdc80 eth0:0 Link encap:Ethernet HWaddr 00:C0:4F:AC:12:3B inet addr:192.168.1.33 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 Interrupt:11 Base address:0xdc80 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:504 errors:0 dropped:0 overruns:0 frame:0 TX packets:504 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:49898 (48.7 Kb) TX bytes:49898 (48.7 Kb) |
Here we reconfigure the eth0 interface:
# ifconfig eth0 192.168.1.34 netmask 255.255.255.0 |
eth0 Link encap:Ethernet HWaddr 00:C0:4F:AC:12:3B inet addr:192.168.1.32 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:2062267 errors:12137 dropped:0 overruns:0 frame:22225 TX packets:1391100 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 RX bytes:651253275 (621.0 Mb) TX bytes:1151145914 (1097.8 Mb) Interrupt:11 Base address:0xdc80 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:503 errors:0 dropped:0 overruns:0 frame:0 TX packets:503 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:49818 (48.6 Kb) TX bytes:49818 (48.6 Kb) |
Now we view the new configuration of eth0 (notice how we specify this interface):
$ ifconfig eth0 |
eth0 Link encap:Ethernet HWaddr 00:C0:4F:AC:12:3B inet addr:192.168.1.34 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:2069039 errors:12143 dropped:0 overruns:0 frame:22235 TX packets:1394113 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 RX bytes:652998849 (622.7 Mb) TX bytes:1152333719 (1098.9 Mb) Interrupt:11 Base address:0xdc80 |
Finally, this is how we activate or shut down an interface:
$ ifconfig eth0:0 up | $ ifconfig eth0:0 down |
See my tutorial lftp: a better FTP client.
See my tutorial Using netcat on OpenBSD.
This command gives us a lot of information regarding our real-time network setup. Its strength is in the area of ports but it can also be used to display a host's routing table.
To view available and used services (connections):
$ netstat -an |
Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp 0 40 192.168.2.50.22 192.168.1.140.2052 ESTABLISHED tcp 0 0 *.22 *.* LISTEN tcp 0 0 *.3306 *.* LISTEN tcp 0 0 192.168.2.50.80 *.* LISTEN tcp 0 0 *.139 *.* LISTEN Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (state) udp 0 0 192.168.2.50.138 *.* udp 0 0 192.168.2.50.137 *.* udp 0 0 *.138 *.* udp 0 0 *.137 *.* udp 0 0 *.67 *.* udp 0 0 *.514 *.* |
This output tells us the following about the host:
TCP
UDP (does not use states)
More information on TCP states can be found in this Sysadmin Magazine article and by reading RFC 793.
Let's determine the system's routing table now:
# netstat -rn |
Routing tables Internet: Destination Gateway Flags Refs Use Mtu Interface default 192.168.1.200 UGS 0 14000 1500 xl1 127/8 127.0.0.1 UGRS 0 558 33224 lo0 127.0.0.1 127.0.0.1 UH 2 16684 33224 lo0 192.168.1/24 link#1 UC 0 0 1500 xl1 192.168.1.200 0:50:bd:2b:44:8f UHL 1 3542 1500 xl1 192.168.1.33 0:0:b4:b2:7:b8 UHL 0 10 1500 xl1 192.168.1.140 0:a0:4c:3:e0:1d UHL 5 59394 1500 xl1 192.168.2.50 127.0.0.1 UGHS 0 10251 33224 lo0 192.168.1.255 link#1 UHL 2 6319 1500 xl1 224/4 127.0.0.1 URS 0 0 33224 lo0 |
We can get statistics on individual interfaces:
# netstat -I xl1 |
Name Mtu Network Address Ipkts Ierrs Opkts Oerrs Colls xl1 1500 Link 00:c0:5f:94:63:10 136773 19 112584 0 2446 xl1 1500 192.168.1/2 daffy 136773 19 112584 0 2446 xl1 1500 fe80::/64 fe80::2d0:4fef:fe 136773 19 112584 0 2446 |
Here we are monitoring a lan PPPoE gateway (interface tun0) including dropped packets; using units of bytes, and updating every 3 seconds:
# netstat -I tun0 -w 3 -bd |
tun0 in tun0 out total in total out bytes bytes drops bytes bytes drops 302298299 13855178 0 635114664 340903093 0 0 0 0 413 220 0 0 0 0 60 182 0 0 0 0 120 220 0 |
We can get a summary of protocol activities. Below we request a report on TCP:
# netstat -p tcp -ss |
tcp: 97948 packets sent 61639 data packets (9859671 bytes) 883 data packets (1207136 bytes) retransmitted 2 fast retransmitted packets 8338 ack-only packets (47946 delayed) 675 window update packets 26426 control packets 118015 packets received 59000 acks (for 9559288 bytes) 620 duplicate acks 49421 packets (7159389 bytes) received in-sequence 54 completely duplicate packets (2157 bytes) 219 out-of-order packets (81514 bytes) 1 packet (0 bytes) of data after window 1524 window update packets 3 packets received after close 17085 connection requests 3274 connection accepts 3373 connections established (including accepts) 21084 connections closed (including 1335 drops) 6883 embryonic connections dropped 57513 segments updated rtt (of 75084 attempts) 6044 retransmit timeouts 1 connection dropped by rexmit timeout 145 keepalive timeouts 145 keepalive probes sent 1411 correct ACK header predictions 16753 correct data packet header predictions 23071 PCB cache misses |
nmap gives us similar information that netstat does. It can also scan remote hosts which makes it a popular tool with people who want to know something about another machine.
Let's begin by doing a typical TCP scan:
# nmap -sT 192.168.2.50 |
Starting nmap V. 2.54BETA25 ( www.insecure.org/nmap/ ) Interesting ports on daffy.pmatulis.homeunix.net (192.168.2.50): (The 1540 ports scanned but not shown below are in state: closed) Port State Service 22/tcp open ssh 80/tcp open http 139/tcp open netbios-ssn 3306/tcp open mysql Nmap run completed -- 1 IP address (1 host up) scanned in 18 seconds |
We can then scan the UDP ports:
# nmap -sU 192.168.2.50 |
Starting nmap V. 2.54BETA25 ( www.insecure.org/nmap/ ) Interesting ports on daffy.pmatulis.homeunix.net (192.168.2.50): (The 1449 ports scanned but not shown below are in state: closed) Port State Service 67/udp open bootps 137/udp open netbios-ns 138/udp open netbios-dgm 514/udp open syslog Nmap run completed -- 1 IP address (1 host up) scanned in 19 seconds |
Compare the output of the last two commands to that which we got for the first netstat command we used.
We can specify what ports we wish to scan. This greatly increases the speed of execution:
# nmap -sT -p 22,80,139,3306 192.168.2.50 |
The output is almost identical to our first TCP scan but it took only 1 second to be displayed whereas the wideopen scan took 18:
Starting nmap V. 2.54BETA25 ( www.insecure.org/nmap/ ) Interesting ports on daffy.pmatulis.homeunix.net (192.168.2.50): Port State Service 22/tcp open ssh 80/tcp open http 139/tcp open netbios-ssn 3306/tcp open mysql Nmap run completed -- 1 IP address (1 host up) scanned in 1 second |
Note: The speed difference is due to a wideopen scan involving all 65535 ports on a host.
Below we scan multiple hosts and send the output to a log file:
# nmap -sT -p 22,80,139,3306 -oN nmap_log_file 192.168.1.* |
In verbose mode, let's scan candyman on the ssh port and try to uncover what operating system it is running. We will use the stealth scan to avoid being detected:
# nmap -v -sS -O -p 22 candyman |
Starting nmap V. 2.54BETA25 ( www.insecure.org/nmap/ ) Host candyman.pmatulis.homeunix.net (192.168.1.52) appears to be up ... good. Initiating SYN Stealth Scan against candyman.pmatulis.homeunix.net (192.168.1.52) Adding TCP port 22 (state open). The SYN Stealth Scan took 0 seconds to scan 1 ports. Warning: OS detection will be MUCH less reliable because we did not find at least 1 open and 1 closed TCP port For OSScan assuming that port 22 is open and port 35565 is closed and neither are firewalled Interesting ports on candyman.pmatulis.homeunix.net (192.168.1.52): Port State Service 22/tcp open ssh Remote operating system guess: Linux Kernel 2.4.0 - 2.4.5 (X86) Uptime 26.143 days (since Fri Jul 5 12:23:39 2002) TCP Sequence prediction: Class=random positive increments Difficulty=1817165 (Good luck!) IPID Sequence Generation: All zeros Nmap run completed -- 1 IP address (1 host up) scanned in 11 seconds |
Now we scan a range of ports on daffy and slow down the scan to Sneaky level (15 second interval between sent packets):
# nmap -sT -T Sneaky -p 22-139 daffy |
Starting nmap V. 2.54BETA25 ( www.insecure.org/nmap/ ) Interesting ports on daffy.pmatulis.homeunix.net (192.168.2.50): (The 115 ports scanned but not shown below are in state: closed) Port State Service 22/tcp open ssh 80/tcp open http 139/tcp open netbios-ssn Nmap run completed -- 1 IP address (1 host up) scanned in 1772 seconds |
Whew, that took almost half an hour to complete.
Visit the nmap site or the man page for more info.
Another key utility for any admin. It shows or manipulates the IP routing table.
Again I will use the utility that comes with Slackware 9.0.
Let's first examine the routing table:
# route |
Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface candyman.pmatul * 255.255.255.255 UH 0 0 0 eth0 localnet * 255.255.255.0 U 0 0 0 eth0 loopback * 255.0.0.0 U 0 0 0 lo default dr_snuggles.pma 0.0.0.0 UG 1 0 0 eth0 |
Let us disable name resolution:
# route -n |
Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.1.32 0.0.0.0 255.255.255.255 UH 0 0 0 eth0 192.168.1.33 0.0.0.0 255.255.255.255 UH 0 0 0 eth0 192.168.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 192.168.1.30 0.0.0.0 UG 1 0 0 eth0 |
In OpenBSD we would use:
# route -n show -inet |
One important step when configuring a host is to setup its default gateway. Currently it is 192.168.1.30. Let us change it to 192.168.1.34:
# route add default gw 192.168.1.34 |
On OpenBSD I would use this slightly simpler command:
# route add default 192.168.1.34 |
To delete the original default gateway (apparently you cannot change a default gateway) simply substitute del (delete for OpenBSD) for add.
To set up a route for a network address space we would do the following:
# route add -net 192.168.2.0 netmask 255.255.255.0 gw 192.168.1.35 |
Omit the "gw" for OpenBSD.
Lastly, we delete a destination:
# route del 192.168.1.33 |
tcpd (tcp wrappers), tcpdmatch, tcpdchk
TCP Wrappers is an extra level of authentication control we can "wrap" around existing servers. An intermediary daemon, called tcpd, will intervene whenever inetd services are requested. tcpd will then consult two files, /etc/hosts.deny and /etc/hosts.allow. Through these, we can impose restrictions on the client's source address. Typically, we set up a default deny arrangement by having hosts.deny contain the following line:
ALL:ALL |
This says to deny access to all servers and from all clients. The syntax is server:ip address/netmask.
We then selectively allow clients access to a service defined and activated in /etc/inetd.conf. For example, if ftpd is available then hosts.allow may contain this line in order to give access to the 192.168.27.0 network:
ftpd: 192.168.27.0/255.255.255.0 |
We now need to modify our inetd.conf accordingly:
#ftp stream tcp nowait root /usr/libexec/ftpd ftpd -US ftp stream tcp nowait root /usr/libexec/tcpd ftpd -US |
So we're telling tcpd to start ftpd only if authentication clears.
Not well known is the ability to use tcp wrappers with SSH even if sshd is not run from inetd. To grant the single address 192.168.1.63 access to sshd add this line to hosts.allow:
sshd: 192.168.1.63/255.255.255.255 |
The corresponding line in inetd.conf would be:
ssh stream tcp nowait root /usr/libexec/tcpd sshd |
Note: inetd needs to be sent a HANGUP signal whenever either control files or inetd.conf are changed.
tcpdmatch is the "tcp wrapper oracle". It predicts how the tcp wrapper would handle a specific request for a service. Cool huh? Here is the basic syntax:
$ tcpdmatch <daemon > <client> |
Notice that we do not need superuser powers to run this. Here is a real example with output:
$ tcpdmatch sshd bureau |
client: hostname bureau.danville.ca client: address 192.168.1.63 server: process sshd access: granted |
Finally we have the tcpdchk tool. This is a kind of diagnostic tool that can identify problems with your tcpd configuration and suggest remedies. We have used very simple configuration so on a real system such a tool can become very useful. Here goes:
$ tcpdchk -v |
Using network configuration file: /etc/inetd.conf >>> Rule /etc/hosts.allow line 1: daemons: sshd clients: 192.168.1.63/255.255.255.255 access: granted >>> Rule /etc/hosts.deny line 1: daemons: ALL clients: ALL access: denied |
This output jives with the results we got back from the tcpdmatch command.
Telnet has been replaced by ssh for controlling a remote host. However, Telnet still serves a purpose. It is a fine debugging tool. You can troubleshoot SMTP, POP, and HTTP problems by connecting to the system running such services and issuing commands.
For instance, to see that a host is listening to port 80 (the HTTP port) we can do:
$ telnet 192.168.1.45 80 |
And we can do the same for any other port.
Telnet is often used to test and debug email installations. See my separate tutorial Introduction to Sendmail.
As for ssh, please see my separate tutorial Working with the OpenSSH Suite.
See my separate tutorials on tcpdump and snort.
Very well known, these are great network connnectivity utilities.
ping sends ICMP ECHO_REQUEST packets to a network host. Here we send twenty requests at a rate of one per second:
$ ping -c 20 -i 5 192.168.1.45 |
Now we send thirty requests. The first five are sent out as fast as possible while the remaining 25 are sent out at the default rate of one per second. All this in quiet mode:
$ ping -c 30 -l 5 -q candyman |
Note: most systems require root privilege for this last command.
traceroute utilizes the IP protocol `time to live' field and attempts to elicit an ICMP TIME_EXCEEDED response from each gateway along the path to some host:
$ traceroute canoe.ca |
Whatmask is a very handy utility when you are figuring out IP addresses, netmasks, subnet addresses, and broadcast addresses. It is a "subnet mask notation conversion tool".
Whatmask can work in two modes. The first mode is to invoke it with only a subnet mask as the argument. In this mode Whatmask will echo back the subnet mask in four formats, plus the number of useable addresses in the range.
Example:
$ whatmask /27 |
--------------------------------------------- TCP/IP SUBNET MASK EQUIVALENTS --------------------------------------------- CIDR = .....................: /27 Netmask = ..................: 255.255.255.224 Netmask (hex) = ............: 0xffffffe0 Wildcard Bits = ............: 0.0.0.31 Usable IP Addresses = ......: 30 |
So you can enter the netmask in either of the four formats to get its equivalent in the other three.
In the second mode, you include the IP address along with the netmask and it will echo back the following:
- The netmask in the following formats: CIDR, Netmask, Netmask (Hex), Wildcard Bits - The Network Address - The Broadcast Address - The number of Usable IP Addresses - The First Usable IP Address - The Last Usable IP Address |
Example:
$ whatmask 192.168.1.63/27 |
------------------------------------------------ TCP/IP NETWORK INFORMATION ------------------------------------------------ IP Entered = ..................: 192.168.1.63 CIDR = ........................: /27 Netmask = .....................: 255.255.255.224 Netmask (hex) = ...............: 0xffffffe0 Wildcard Bits = ...............: 0.0.0.31 ------------------------------------------------ Network Address = .............: 192.168.1.32 Broadcast Address = ...........: 192.168.1.63 Usable IP Addresses = .........: 30 First Usable IP Address = .....: 192.168.1.33 Last Usable IP Address = ......: 192.168.1.62 |
One nice feature (in either mode) is that you can specify the netmask in any of the four modes and the utility will figure everything out on its own. So the last command could have also been written in these forms to get identical output:
$ whatmask 192.168.1.63/255.255.255.224 |
$ whatmask 192.168.1.63/0xffffffe0 |
$ whatmask 192.168.1.63/0.0.0.31 |
whatmask can be downloaded here.
A very similar tool is cidr. It does the same thing as whatmask but its output only provides the netmask in dotted quad notation. Furthermore, if a non-CIDR netmask is entered as input the command requires explicit switches. What it can do extra is optionally print out all available addresses. As well, it allows the IP address to be specified in several forms (but who really writes their IP addresses in decimal, binary, or hex?).
Here are some forms to express the same last command:
$ cidr 192.168.1.63/27 | { short form } |
$ cidr -q 192.168.1.63 -q 255.255.255.224 |
$ cidr -b 11000000101010000000000100111111 -h 0xffffffe0 |
cidr does not accept the "Wildcard Bits" (or inverse netmask) format.
To get the address printout we tac on the "host" switch:
$ cidr 192.168.1.63/27 -H |
ip address..........: 192.168.1.63 netmask.............: 255.255.255.224 network address.....: 192.168.1.32 broadcast address...: 192.168.1.63 host addresses: 192.168.1.33 192.168.1.34 192.168.1.35 192.168.1.36 192.168.1.37 192.168.1.38 192.168.1.39 192.168.1.40 192.168.1.41 192.168.1.42 192.168.1.43 192.168.1.44 192.168.1.45 192.168.1.46 192.168.1.47 192.168.1.48 192.168.1.49 192.168.1.50 192.168.1.51 192.168.1.52 192.168.1.53 192.168.1.54 192.168.1.55 192.168.1.56 192.168.1.57 192.168.1.58 192.168.1.59 192.168.1.60 192.168.1.61 192.168.1.62 total host addresses: 30 |
cidr is a FreeBSD program. It has also been made available as an OpenBSD package (with 3.3 at least).
This third and last segment will focus on software I have found to be useful but which does not fit into the first two catagories.
Here is a list of what we will see in this section:
This is one of the best relatively unknown tools I've ever found. Unfortunatly, it does not run on OpenBSD. Supported platforms include Linux versions 2.0 and up, on Alpha, x86 PCs, PC98, Macintosh PowerPC, and Sun hardware.
This is a hard disk tool that allows one to copy, move, and resize partitions that are currently in use on a live system without disrupting associated data.
We begin by looking at the partition table of the first ide drive:
$ parted /dev/hda print |
Disk geometry for /dev/hda: 0.000-19092.937 megabytes Disk label type: msdos Minor Start End Type Filesystem Flags 1 0.031 23.532 primary ext2 boot 2 23.533 19092.875 extended 5 23.563 3098.474 logical ext2 6 3098.505 3616.193 logical ext2 7 3616.225 4133.913 logical linux-swap 8 4133.944 4392.773 logical ext2 9 4392.804 11750.668 logical ext2 10 11750.700 19092.875 logical ext2 |
As a trivial example, let's say we want to decrease the size of partition 9
The general syntax is as follows:
$ parted <device> resize <partition number> <start in MB> <end in MB> |
So the command could be:
# parted /dev/hda resize 9 4392.804 6392.804 |
Note: If you will be modifying the root parition or any swap spaces use a Parted boot floppy.
Parted is a GNU tool. More information can be found on its website
This utility lists information about the open files on a computer. It is versatile since almost everything on a UNIX system is a file.
Show files opened by MySQL:
# lsof -c mysq |
Note: Using this form, it is not necessary to type the exact command. Just enough to identify it.
Here is the output:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME mysqld 16863 mysqladm cwd VDIR 0,20 512 32950 /usr/local (/dev/wd1e) mysqld 16863 mysqladm txt VREG 0,20 1862568 28905 /usr/local (/dev/wd1e) mysqld 16863 mysqladm txt VREG 0,3 61440 149810 /usr/libexec/ld.so mysqld 16863 mysqladm txt VREG 0,4 4374 17285 /var/run/ld.so.hints mysqld 16863 mysqladm txt VREG 0,3 687426 182436 /usr (/dev/wd0d) mysqld 16863 mysqladm txt VREG 0,3 55094 182467 /usr (/dev/wd0d) mysqld 16863 mysqladm txt VREG 0,3 390677 182464 /usr (/dev/wd0d) mysqld 16863 mysqladm txt VREG 0,3 85720 182452 /usr (/dev/wd0d) mysqld 16863 mysqladm 0r VChr 2,2 0t0 12641 /dev/null mysqld 16863 mysqladm 1w VREG 0,20 5132 32970 /usr/local (/dev/wd1e) mysqld 16863 mysqladm 2w VREG 0,20 5132 32970 /usr/local (/dev/wd1e) mysqld 16863 mysqladm 3u IPv4 0xe065b408 0t0 TCP *:mysql (LISTEN) mysqld 16863 mysqladm 4u unix 0xe06438f0 0t0 /tmp/mysql.sock mysqld 16863 mysqladm 5u PIPE 0xeaa98214 16384 ->0xeaa981c8 mysqld 16863 mysqladm 6u PIPE 0xeaa981c8 16384 ->0xeaa98214 mysqld 16863 mysqladm 7w VREG 0,20 6949 32972 /usr/local (/dev/wd1e) mysqld 16863 mysqladm 9u VREG 0,20 2048 34795 /usr/local (/dev/wd1e) mysqld 16863 mysqladm 10u VREG 0,20 1756 34796 /usr/local (/dev/wd1e) mysqld 16863 mysqladm 11u VREG 0,20 2048 34792 /usr/local (/dev/wd1e) mysqld 16863 mysqladm 12u VREG 0,20 5624 34793 /usr/local (/dev/wd1e) |
Nice huh?
Now my ps command shows me the following line:
19195 C5 Is+ 0:00.01 /usr/libexec/getty Pc ttyC5 |
I want to know all the open files associated with this process so I take note of the PID:
# lsof -p 19195 |
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME getty 19195 root cwd VDIR 0,0 512 2 / getty 19195 root txt VREG 0,3 20480 149797 /usr (/dev/wd0d) getty 19195 root txt VREG 0,3 61440 149810 /usr/libexec/ld.so getty 19195 root txt VREG 0,4 4374 17285 /var/run/ld.so.hints getty 19195 root txt VREG 0,3 38246 182465 /usr (/dev/wd0d) getty 19195 root txt VREG 0,3 598961 182435 /usr/lib/libc.so.28.3 getty 19195 root 0u VChr 12,5 0t63 12507 /dev/ttyC5 getty 19195 root 1u VChr 12,5 0t63 12507 /dev/ttyC5 getty 19195 root 2u VChr 12,5 0t63 12507 /dev/ttyC5 |
Let's see what our old friend user bonehead is up to:
# lsof -u bonehead |
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sh 2646 bonehead cwd VDIR 0,5 512 113280 /home/bonehead sh 2646 bonehead txt VREG 0,0 307200 1938 /bin/sh sh 2646 bonehead 0u VChr 5,1 0t5058390 12528 /dev/ttyp1 sh 2646 bonehead 1u VChr 5,1 0t5058390 12528 /dev/ttyp1 sh 2646 bonehead 2u VChr 5,1 0t5058390 12528 /dev/ttyp1 sh 2646 bonehead 10u VChr 1,0 0t0 12640 /dev/tty vi 24825 bonehead cwd VDIR 0,5 512 113280 /home/bonehead vi 24825 bonehead txt VREG 0,3 282624 124863 /usr/bin/vi vi 24825 bonehead txt VREG 0,3 61440 149810 /usr/libexec/ld.so vi 24825 bonehead txt VREG 0,4 4374 17285 /var/run/ld.so.hints vi 24825 bonehead txt VREG 0,3 257069 182439 /usr/lib/libcurses.so.8.0 vi 24825 bonehead txt VREG 0,3 598961 182435 /usr/lib/libc.so.28.3 vi 24825 bonehead 0u VChr 5,1 0t5058390 12528 /dev/ttyp1 vi 24825 bonehead 1u VChr 5,1 0t5058390 12528 /dev/ttyp1 vi 24825 bonehead 2u VChr 5,1 0t5058390 12528 /dev/ttyp1 vi 24825 bonehead 3rW VREG 0,0 0 38402 /tmp/vi.W24825 vi 24825 bonehead 4u VREG 0,4 0 30722 /var/tmp/vi.recover/vi.y24825 vi 24825 bonehead 5u VREG 0,0 0 38403 / (/dev/wd0a) |
Heh heh, the little bugger is editing a file with vi.
Now we will get into networking. Yes, we can do this. Let's see the open internet socket files related to the TCP protocol without host name resolution:
# lsof -i tcp -n |
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sshd 1707 pmatulis 5u IPv4 0xe065b810 0t0 TCP 192.168.2.50:ssh->192.168.2.100:2372 (ESTABLISHED) smbd 2114 root 9u IPv4 0xe065b2b0 0t0 TCP *:netbios-ssn (LISTEN) httpd 2867 webadm 16u IPv4 0xe065b560 0t0 TCP 192.168.2.50:www (LISTEN) httpd 6642 webadm 16u IPv4 0xe065b560 0t0 TCP 192.168.2.50:www (LISTEN) httpd 7529 webadm 16u IPv4 0xe065b560 0t0 TCP 192.168.2.50:www (LISTEN) sshd 11303 root 3u IPv6 0xe065b000 0t0 TCP *:ssh (LISTEN) sshd 11303 root 4u IPv4 0xe065b158 0t0 TCP *:ssh (LISTEN) smbd 11990 pmatulis 12u IPv4 0xe065bc18 0t0 TCP 192.168.2.50:netbios-ssn->192.168.2.100:2247 (ESTABLISHED) httpd 12043 root 16u IPv4 0xe065b560 0t0 TCP 192.168.2.50:www (LISTEN) sshd 14823 root 5u IPv4 0xe065bac0 0t0 TCP 192.168.2.50:ssh->192.168.2.100:2052 (ESTABLISHED) mysqld 16863 mysqladm 3u IPv4 0xe065b408 0t0 TCP *:mysql (LISTEN) sshd 24081 pmatulis 5u IPv4 0xe065bac0 0t0 TCP 192.168.2.50:ssh->192.168.2.100:2052 (ESTABLISHED) httpd 27634 webadm 16u IPv4 0xe065b560 0t0 TCP 192.168.2.50:www (LISTEN) sshd 31884 root 5u IPv4 0xe065b810 0t0 TCP 192.168.2.50:ssh->192.168.2.100:2372 (ESTABLISHED) |
Below we ask for the open files associated with ports 22 to 139 of the TCP protocol and all ports of the UDP protocol (all still without host name resolution):
# lsof -i tcp:22-139 -i udp -n |
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sshd 1707 pmatulis 5u IPv4 0xe065b810 0t0 TCP 192.168.2.50:ssh->192.168.2.100:2372 (ESTABLISHED) smbd 2114 root 9u IPv4 0xe065b2b0 0t0 TCP *:netbios-ssn (LISTEN) httpd 2867 webadm 16u IPv4 0xe065b560 0t0 TCP 192.168.2.50:www (LISTEN) httpd 6642 webadm 16u IPv4 0xe065b560 0t0 TCP 192.168.2.50:www (LISTEN) httpd 7529 webadm 16u IPv4 0xe065b560 0t0 TCP 192.168.2.50:www (LISTEN) nmbd 7658 root 8u IPv4 0xe065c700 0t0 UDP *:netbios-ns nmbd 7658 root 9u IPv4 0xe065c600 0t0 UDP *:netbios-dgm nmbd 7658 root 10u IPv4 0xe065c400 0t0 UDP 192.168.2.50:netbios-ns nmbd 7658 root 11u IPv4 0xe065c300 0t0 UDP 192.168.2.50:netbios-dgm sshd 11303 root 3u IPv6 0xe065b000 0t0 TCP *:ssh (LISTEN) sshd 11303 root 4u IPv4 0xe065b158 0t0 TCP *:ssh (LISTEN) smbd 11990 root 5u IPv4 0xe0696800 0t0 UDP 127.0.0.1:43301 smbd 11990 root 12u IPv4 0xe065bc18 0t0 TCP 192.168.2.50:netbios-ssn->192.168.2.100:2247 (ESTABLISHED) httpd 12043 root 16u IPv4 0xe065b560 0t0 TCP 192.168.2.50:www (LISTEN) sshd 14823 root 5u IPv4 0xe065bac0 0t0 TCP 192.168.2.50:ssh->192.168.2.100:2052 (ESTABLISHED) dhcpd 18274 root 7u IPv4 0xe0649100 0t0 UDP *:bootps sshd 24081 pmatulis 5u IPv4 0xe065bac0 0t0 TCP 192.168.2.50:ssh->192.168.2.100:2052 (ESTABLISHED) httpd 27634 webadm 16u IPv4 0xe065b560 0t0 TCP 192.168.2.50:www (LISTEN) syslogd 29094 root 5u IPv4 0xe0645a00 0t0 UDP *:syslog sshd 31884 root 5u IPv4 0xe065b810 0t0 TCP 192.168.2.50:ssh->192.168.2.100:2372 (ESTABLISHED) |
Let's explicitly request info on port 22 (ssh) involving host daffy and turn off service name resolution (as well as host name resolution):
# lsof -i tcp@daffy:22 -n -P |
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sshd 1707 pmatulis 5u IPv4 0xe065b810 0t0 TCP 192.168.2.50:22->192.168.2.100:2372 (ESTABLISHED) sshd 14823 root 5u IPv4 0xe065bac0 0t0 TCP 192.168.2.50:22->192.168.2.100:2052 (ESTABLISHED) sshd 24081 pmatulis 5u IPv4 0xe065bac0 0t0 TCP 192.168.2.50:22->192.168.2.100:2052 (ESTABLISHED) sshd 31884 root 5u IPv4 0xe065b810 0t0 TCP 192.168.2.50:22->192.168.2.100:2372 (ESTABLISHED) |
What files do we have open in the /home directory?:
# lsof /home |
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME lsof 1758 root cwd VDIR 0,5 512 115217 /home (/dev/wd0f) sh 2902 pmatulis cwd VDIR 0,5 512 109440 /home (/dev/wd0f) lsof 10891 root cwd VDIR 0,5 512 115217 /home (/dev/wd0f) ksh 26362 root cwd VDIR 0,5 512 115217 /home (/dev/wd0f) sh 27635 pmatulis cwd VDIR 0,5 512 109440 /home (/dev/wd0f) |
We can also narrow down our requests by using the "-a" (AND) switch. Examine the following session where we pipe the output to a second command to count the number of lines:
# lsof -c httpd | wc -l 106 # lsof -c httpd -au root | wc -l 22 # lsof -c httpd -au root -a /usr | wc -l 9 |
So here is the output of that last command (we asked for open files associated with 1) the httpd process, 2) the superuser, and 3) that which reside in the /usr directory):
# lsof -c httpd -au root -a /usr |
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME httpd 12043 root txt VREG 0,3 61440 149810 /usr/libexec/ld.so httpd 12043 root txt VREG 0,3 820851 182459 /usr (/dev/wd0d) httpd 12043 root txt VREG 0,3 85720 182452 /usr (/dev/wd0d) httpd 12043 root txt VREG 0,3 598961 182435 /usr/lib/libc.so.28.3 httpd 12043 root txt VREG 0,3 38246 182465 /usr/lib/libutil.so.7.1 httpd 12043 root txt VREG 0,3 20663 69244 /usr (/dev/wd0d) httpd 12043 root txt VREG 0,3 135225 182725 /usr (/dev/wd0d) httpd 12043 root txt VREG 0,3 55094 182467 /usr (/dev/wd0d) |
One thing that I have always found extremely annoying is trying to unmount a partition (ex: cdrom drive) only to to be told that it is being used and will not unmount. Well we can now apply our lsof knowledge and request to be told what those files are that are stopping us:
# lsof /mnt/cdrom |
For more information visit the lsof man page. If you find it too dense I make available the lsof quick-start guide (also available with the source).
The pmtools suite was written by Tom Christiansen to help navigate and manage Perl module installations. You can obtain it here.
The suite consists of the following tools:
pmpath - show the module's full path pmvers - get a module version number pmdesc - get a module description pmall - get all installed modules pmdesc descriptions pmdirs - print the perl module path, newline separated plxload - show what files a given program loads at compile time pmload - show what files a given module loads at compile time pmexp - show a module's exports pminst - find what's installed pmeth - list a class's methods, recursively pmls - long list the module path pmcat - cat the module source through your pager pman - show the module's pod docs pmfunc - show a function source code from a module podgrep - grep in pods of a file pfcat - show pods from perlfunc podtoc - list table of contents of a podpage podpath - show full path of pod file pods - list all standard pods and module pods sitepods - list only pods in site_perl directories basepods - list only normal "man-page" style pods faqpods - list only faq pods modpods - all module pods, including site_perl ones stdpods - list standard pods, not site_perl ones |
It is especially helpful when you inherit a system and you want to determine its level of Perl configuration.
zap is the OpenBSD interactive process killer. The equivalent utility for Linux is killall.
Below we see partial output to the ps command. There is a user editing a file called "test" with the vi program. After you see that we shut down the editor using the killall command:
. . . 25728 ? S 0:00 /usr/sbin/sshd 25729 pts/0 S 0:00 -bash 25787 ? S 0:00 /usr/sbin/sshd 25788 pts/1 S 0:00 -bash 25798 pts/1 S 0:00 vi test 25799 pts/0 R 0:00 ps ax pmatulis@candyman:$ killall -i vi Kill vi(25798) ? (y/n) y |
Normally, using the kill command, we need to specify the actual PID (which is 25798). We used the 'i' switch to enter interactive mode.
The OpenBSD offering works in a similar fashion. Info on zap can be found here.
The script utility is useful for when you want to capture the standard output of a terminal session. It is very easy to use:
$ script -a /root/sessions/diagnostics_jan1_2004 |
Following the command all StdOUT is sent to the file /root/sessions/diagnostics_jan1_2004. Pressing "exit" (or Ctrl-D) ends the program (and the recording process). The resulting file can be viewed with any pager or text editor.
The tree utitlity is nice when you want to get a quick overview of a directory's structure.
tree -d /etc -L 2 |
This says to display the directories contained within the first two levels underneath the /etc directory. This is what I got on my system:
/etc |-- X11 | |-- app-defaults | |-- fs | |-- lbxproxy | |-- mwm | |-- proxymngr | |-- rstart | |-- twm | |-- xdm | |-- xinit | |-- xkb | |-- xserver | `-- xsm |-- acpi | `-- events |-- cron.daily |-- cron.hourly |-- cron.monthly |-- cron.weekly |-- cups |-- dhcpc |-- gtk |-- gtk-2.0 |-- hotplug | |-- pci | `-- usb |-- logrotate.d |-- mail |-- mutt |-- news |-- pango |-- ppp | `-- plugins |-- profile.d |-- rc.d |-- skel |-- ssh |-- ssl | |-- certs | |-- lib | |-- misc | `-- private |-- tin `-- vga |
This says to show all the files (whose filenames begin with the letter "a") within the first three levels underneath /home; print file sizes; and send the output to file treetest:
$ tree -P 'a*' -L 3 /home -s -o treetest |
Note that directories will always be shown and that the pattern feature cannot be used on them.