Wednesday, May 7, 2008

FreeNAS: a free Network-attached storage (NAS) server

It supports following protocols:
=> CIFS (Samba) - Mac / UNIX / Windows can use CIFS to store files
=> FTP
=> NFS
=> Rsync
=> AFP

You can use local user authentication, and software RAID (0,1,5), with a web-based configuration interface.
You can install software on hard disk or flash drive. A sample setup:
* Intel 1.7Ghz Celeron
* 1GB SDRam
* 3 x 80GB IDE Hard disk
* 10/100/1000 Mbps Lan Card
* Raid 5 with FreeNAS (Highest Read data transaction as I need to read lots of files such as MP3 / Photos and other data)
* BIOS is configured to boot from USB pen and w/o monitor / keyboard
* D-Link Gigabit Ethernet 8 Port Switche and Wireless AP router

FreeNAS is easy to use and perfect for building a low cost home file server, it can be used as:
=> Home Music / Media Server
=> Home Backup Server
=> Home Ftp Server
, etc.

Tuesday, May 6, 2008

Hidden switch: Display disk total statistics including time spent reading and writing data

Most Linux admins are not aware of vmstat's hidden switch (undocumented switch) called -D, which display a nice summery of disk I/O subsystem since boot time. Output includes total time spent reading and writing data, merged reads and merged writes (kernel disk i/o optimization technique) and other parameters.
$ vmstat -D
30 disks
8 partitions
13739406 total reads
3887474 merged reads
1180260353 read sectors
109630647 milli reading
118650080 writes
250115464 merged writes
2950543038 written sectors
2382220771 milli writing
0 inprogress IO
113832 milli spent IO

This is a backup server hosted at data center:
$ uptime
12:15:07 up 33 days, 9:15, 2 users, load average: 1.71, 1.49, 1.03

Since last 33 days the server spent total 1180260353 milliseconds reading disk. To get more detailed about disk I/O stats, use the -d option

Copy Set of Files to All Users Home Directory

First grab all user names from /etc/passwd:
cut -d: -f1 /etc/passwd

Next use a loop to apply copy and set the correct permissions on the file.

Finally, use id to obtain the correct user ID and group ID for each user.
USERS=$(cut -d':' -f1 /etc/passwd) # get list of all users
for u in $USERS
/bin/cp $FILE ${UHOME}/${u}
chown $(id -un $u):$(id -gn $u) /${UHOME}/${u}/${FILE}

You can also copy multiple files using inner and outer loop concept:
FILES="/etc/skel/.newconfig-file /etc/skek/.update-config /chroot/jail/.force.conf"
USERS=$(cut -d':' -f1 /etc/passwd) # get list of all users
for u in $USERS
for f in $FILES
/bin/cp ${f} ${UHOME}/${u}
chown $(id -un $u):$(id -gn $u) /${UHOME}/${u}/${f}

Add additional security check such as:
* User should be a normal user
* User must have a directory
* User must have a valid password / account.

Thursday, May 1, 2008

Setup, change and pimp out Linux / UNIX shell prompt

By default most distro displays hostname and current working directory. Prompt is control via a special shell variable. You need to set PS1, PS2, PS3 and PS4 variable. If set, the value is executed as a command prior to issuing each primary prompt.
* PS1 - The value is expanded and used as the primary prompt string. The default value is \s-\v\$ .
* PS2 - The value is expanded as with PS1 and used as the secondary prompt string. The default is >
* PS3 - The value is used as the prompt for the select command
* PS4 - The value expanded as with PS1 and the value is printed before each command bash displays during an execution trace. The first character of PS4 is replicated multiple times, as necessary, to indicate multiple levels of indirection. The default is +

To display current prompt setting:
$ echo $PS1

The prompt can be changed by assigning a new value to PS1.When executing interactively, bash displays the primary prompt PS1 when it is ready to read a command, and the secondary prompt PS2 when it needs more input to complete a command. Bash allows these prompt strings to be customized by inserting a number of backslash-escaped special characters that are decoded as follows:
* \a : an ASCII bell character (07)
* \d : the date in "Weekday Month Date" format (e.g., "Tue May 26")
* \D{format} : the format is passed to strftime(3) and the result is inserted into the prompt string; an empty format results in a locale-specific time representation. The braces are required
* \e : an ASCII escape character (033)

* \h : the hostname up to the first '.'
* \H : the hostname

* \j : the number of jobs currently managed by the shell
* \l : the basename of the shell’s terminal device name
* \n : newline
* \r : carriage return
* \s : the name of the shell, the basename of $0 (the portion following the final slash)
* \t : the current time in 24-hour HH:MM:SS format
* \T : the current time in 12-hour HH:MM:SS format
* \@ : the current time in 12-hour am/pm format
* \A : the current time in 24-hour HH:MM format
* \u : the username of the current user
* \v : the version of bash (e.g., 2.00)
* \V : the release of bash, version + patch level (e.g., 2.00.0)

* \w : the current working directory, with $HOME abbreviated with a tilde
* \W : the basename of the current working directory, with $HOME abbreviated with a tilde
* \! : the history number of this command
* \# : the command number of this command
* \$ : if the effective UID is 0, a #, otherwise a $
* \nnn : the character corresponding to the octal number nnn
* \\ : a backslash
* \[ : begin a sequence of non-printing characters, which could be used to embed a terminal control sequence into the prompt
* \] : end a sequence of non-printing characters

To display today’d date and hostname in the prompt:

PS1="\d \h $ "
Sat Jun 02 server $

Now setup prompt to display date/time, hostname and current directory:
$ PS1="[\d \t \u@\h:\w ]
$ "
[Sat Jun 02 14:24:12 vivek@server:~ ] $

To add colors to prompt. For example, open /etc/bashrc (Redhatish) / or /etc/bash.bashrc (Debian) or /etc/bash.bashrc.local (Suse) file and append following code:

# If id command returns zero, you’ve root access.
if [ $(id -u) -eq 0 ]; then # root goes red
PS1="\\[$(tput setaf 1)\\]\\u@\\h:\\w #\\[$(tput sgr0)\\]"
else # normal
PS1="[\\u@\\h:\\w] $"

Of course, you can include whatever you like in the prompt. For example, when I switch to root:

To add colors to the shell prompt use the following export command syntax:
'\e[x;ym $PS1 \e[m'

* \e[ Start color scheme

* x;y Color pair to use (x;y)
* $PS1 is your shell prompt
* \e[m Stop color scheme

To set a red color prompt:
$ export PS1="\e[0;31m[\u@\h \W]\$ \e[m "

Color Code
Black 0;30
Blue 0;34
Green 0;32
Cyan 0;36
Red 0;31
Purple 0;35
Brown 0;33

Replace digit 0 with 1 to get light color version.

To make the prompt setting permanent, add above export command to your .bash_profile file or .bashrc file.
export PS1="\e[0;31m[\u@\h \W]\$ \e[m"

You can also use tput command. For example display RED prompt use tput as follows:
export PS1="\[$(tput setaf 1)\]\u@\h:\w $ \[$(tput sgr0)\]"

handy tput commands:
* tput bold - Bold effect
* tput rev - Display inverse colors
* tput sgr0 - Reset everything
* tput setaf {CODE}- Set foreground color, see color {CODE} below
* tput setab {CODE}- Set background color, see color {CODE} below

Colors {code} code for tput command
0 Black
1 Red
2 Green
3 Yellow
4 Blue
5 Magenta
6 Cyan
7 White

Read the man page of bash and tput for more information.

Demilitarized Zone Ethernet Interface Requirements and Configuration

Demilitarized zone, or DMZ, is used to secure an internal network from external access. You can use Linux firewall to create one easily. There are many different ways to design a network with a DMZ. The basic method is to use a single Linux firewall with 3 Ethernet cards. The following simple example discusses DMZ setup and forwarding public traffic to internal servers.

Consider the following DMZ host with 3 NIC:
[a] eth0 with private IP address - Internal LAN ~ Desktop system
[b] eth1 with public IP address - WAN connected to ISP router
[c] eth2 with private IP address - DMZ connected to Mail / Web / DNS and other private servers

Routing traffic between public and DMZ server, to set a rule for routing all incoming SMTP requests to a dedicated Mail server at, NAT calls a PREROUTING table to forward the packets to the proper destination.

This can be done with appropriate IPTABLES firewall rule to route traffic between LAN to DMZ and public interface to DMZ.

### end init firewall .. Start DMZ stuff ####
# forward traffic between DMZ and LAN
iptables -A FORWARD -i eth0 -o eth2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i eth2 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

# forward traffic between DMZ and WAN servers SMTP, Mail etc
iptables -A FORWARD -i eth2 -o eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i eth1 -o eth2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# Route incoming SMTP (port 25 ) traffic to DMZ server
iptables -t nat -A PREROUTING -p tcp -i eth1 -d --dport 25 -j DNAT --to-destination
# Route incoming HTTP (port 80 ) traffic to DMZ server load balancer IP
iptables -t nat -A PREROUTING -p tcp -i eth1 -d --dport 80 -j DNAT --to-destination
# Route incoming HTTPS (port 443 ) traffic to DMZ server reverse load balancer IP
iptables -t nat -A PREROUTING -p tcp -i eth1 -d --dport 443 -j DNAT --to-destination
### End DMZ .. Add other rules ###

Multi port redirection, use multiport iptables module to matches a set of source or destination ports. Up to 15 ports can be specified. For example, route incoming HTTP (port 80 ) and HTTPS ( port 443) traffic to WAN server load balancer IP
iptables -t nat -A PREROUTING -p tcp -i eth1 -d -m multiport --dport 80,443 -j DNAT --to-destination

Above design has few pitfalls:
1. Single point of failure - The firewall becomes a single point of failure for the network.
2. Hardware - The firewall Host must be able to handle all of the traffic going to the DMZ as well as the internal network.

Set the DNS from the command line

Open /etc/resolv.conf and add the line:
nameserver {IP-OF-THE-DNS-1}
nameserver {IP-OF-THEISP-DNS-SERVER-2}

To test DNS configuration type any one of the following command:
$ host
$ dig
$ ping
$ nslookup

If you see valid output such as actual IP address or able to ping to remote server via hostname, it means that the dns is working for you. Also make sure you have valid default gateway setup, if you see the time out error.

Understanding the tr command

tr copies the given input to produced the output with substitution or deletion of selected characters. It is frequently used in shell scripts.

tr [options] "set1" "set2"
echo something | tr "set1" "set2"
tr "set1" "set2" < input.txt
tr "set1" "set2" <> output.txt

For example, translate 'linux' to upper-case:
$ echo 'linux' | tr "[:lower:]" "[:upper:]"
$ echo 'linux' | tr "a-z" "A-Z"
$ echo 'I LovE linuX. one is better Than 2' | tr "a-z" "A-Z"

Create a list of the words in /path/to/file, one per line:
$ tr -cs "[:alpha:]" "\n" < /path/to/file
* -c : Complement the set of characters in string1
* -s : Replace each input sequence of a repeated character that is listed in SET1 with a single occurrence of that character

In the following example user will get confirmation before deleting the file. If the user responds in lower case, tr will do nothing, but in upper case, the character will be changed to lower case. This will ensure that even if user responds with YES, YeS, YEs etc; script should remove file:
echo -n "Enter file name : "
read myfile
echo -n "Are you sure ( yes or no ) ? "
read confirmation
confirmation="$(echo ${confirmation} | tr 'A-Z' 'a-z')"
if [ "$confirmation" == "yes" ]; then
[ -f $myfile ] && /bin/rm $myfile || echo "Error - file $myfile not found"
: # do nothing

Remove all non-printable characters from myfile.txt
$ tr -cd "[:print:]" < myfile.txt

Remove all two more successive blank spaces from a copy of the text in a file called input.txt and save output to a new file called output.txt:
tr -s ' ' ' ' <> output.txt

The -d option is used to delete every instance of the string (i.e., sequence of characters) specified in set1. For example, the following would remove every instance of the word nameserver from a copy of the text in a file called /etc/resolv.conf and write the output to a file called ns.ipaddress.txt:
tr -d 'nameserver' < /etc/resolv.conf > ns.ipaddress.txt

Configure Jumbo Frames to Boost Network Performance / Throughput

Jumbo frames are Ethernet frames with more than 1500 bytes of payload MTU. Most modern Linux distros (Kernel 2.6.17+) support frames larger than 1500 bytes.

First, make sure your network driver supports custom MTU. Second you need to have a compatible gigabit NIC and switch (such as Cisco Catalyst 4000/4500 Switches with Supervisor III or Supervisor IV ) that is jumbo frame clean.

Jumbo frames can reduce server overhead such as a big decrease in CPU usage when transferring larger file. Also you should see some increase in network throughput.

Configure eth0 interface for Jumbo Frames. Warning! These examples depend upon a compatible network gear such gigabit Ethernet switches and gigabit Ethernet network interface cards.
# ifconfig eth0 mtu 9000

To make changes permanent, append the
directive into the network configuration file for eth0.
# vi /etc/sysconfig/network-script/ifcfg-eth0 # Redhat/CentOS/Fedora

# vi /etc/network/interfaces # Debian/Ubuntu

# /etc/init.d/networking restart

To confirm the MTU used between two specific devices:
# ip route get {IP-address}
# ip route get dev eth0 src
cache mtu 9000 advmss 1460 hoplimit 64

Application Protocol Tunning. You may need to tune the application/network protocol such as NFS and SMB to take advantage of Jumbo Frames.

Monitor and debug system calls using strace

strace is useful for diagnostic, instructional, and debugging. System admins, diagnosticians and troubleshooters will find it invaluable for solving problems with programs for which the source is not readily available.

strace for Linux, added many of the features of Solaris/FreeBSD's truss command from SVR4, and produced an strace that worked on both platforms.

$ strace -o /tmp/output.txt /bin/bash
$ grep '^open' /tmp/output.txt

To see only a trace of the open, close, read, and write system calls, enter:
$ strace -e trace=open,close,read,write df > output.txt

Another good option is ltrace - its use is very similar to strace command.