Thursday, March 30, 2006 

NFS between Solaris & Linux

If you receive error messages such as "unknown version" when attempting to mount a Linux based NFS server from Solaris, you probably have an incompatibility between the NFS versions
running on both of them. Linux uses version 2, while Solaris uses version 3. In order to get the machines to communicate, you have to use the vers option on the Solaris machine as follows:

mount -o vers=2 nfsserver:/remotedir /localdir

 

How To Set Up Database Replication In MySQL

This tutorial describes how to set up database replication in MySQL. MySQL replication allows you to have an exact copy of a database from a master server on another server (slave), and all updates to the database on the master server are immediately replicated to the database on the slave server so that both databases are in sync. This is not a backup policy because an accidentally issued DELETE command will also be carried out on the slave; but replication can help protect against hardware failures though.

In this tutorial I will show how to replicate the database exampledb from the master with the IP address 192.168.0.100 to a slave. Both systems (master and slave) are running Debian Sarge; however, the configuration should apply to almost all distributions with little or no modification.

Both systems have MySQL installed, and the database exampledb with tables and data is already existing on the master, but not on the slave.

I want to say first that this is not the only way of setting up such a system. There are many ways of achieving this goal but this is the way I take. I do not issue any guarantee that this will work for you!

1 Configure The Master

First we have to edit /etc/mysql/my.cnf. We have to enable networking for MySQL, and MySQL should listen on all IP addresses, therefore we comment out these lines (if existant):

#skip-networking
#bind-address = 127.0.0.1

Furthermore
we have to tell MySQL for which database it should write logs (these logs are used by the slave to see what has changed on the master),
which log file it should use, and we have to specify that this MySQL


log-bin = /var/log/mysql/mysql-bin.log
binlog-do-db=exampledb
server-id=1

Then we restart MySQL:

/etc/init.d/mysql restart

Then we log into the MySQL database as root and create a user with replication privileges:

mysql -u root -p
Enter password:

Now we are on the MySQL shell.

GRANT REPLICATION SLAVE ON *.* TO 'slave_user'@'%' IDENTIFIED BY ''; (Replace with a real password!)
FLUSH PRIVILEGES;

Next (still on the MySQL shell) do this:

USE exampledb;
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;

The last command will show something like this:

+---------------+----------+--------------+------------------+
| File | Position | Binlog_do_db | Binlog_ignore_db |
+---------------+----------+--------------+------------------+
| mysql-bin.006 | 183 | exampledb | |
+---------------+----------+--------------+------------------+
1 row in set (0.00 sec)

Write down this information, we will need it later on the slave!

Then leave the MySQL shell:

quit;


There are two possibilities to get the existing tables and data from exampledb from the master to the slave. The first one is to make a database dump, the second one is to use the LOAD DATA FROM MASTER; command on the slave. The latter has the disadvantage the the database on the master will be locked during this operation, so if you have a large database on a high-traffic production system, this is not what you want, and I recommend to follow the first method in this case. However, the latter method is very fast, so I will describe both here.

If you want to follow the first method, then do this:

mysqldump -u root -p --opt exampledb > exampledb.sql (Replace with the real password for the MySQL user root! Important: There is no space between -p and !)

This will create an SQL dump of exampledb in the file exampledb.sql. Transfer this file to your slave server!

If you want to go the LOAD DATA FROM MASTER; way then there is nothing you must do right now.


Finally we have to unlock the tables in exampledb:

mysql -u root -p
Enter password:
UNLOCK TABLES;
quit;

Now the configuration on the master is finished. On to the slave...

2 Configure The Slave

On the slave we first have to create the database exampledb:

mysql -u root -p
Enter password:
CREATE DATABASE exampledb;
quit;


If you have made an SQL dump of exampledb on the master and have transferred it to the slave, then it is time now to import the SQL dump into our newly created exampledb on the slave:

mysql -u root -p exampledb < /path/to/exampledb.sql (Replace with the real password for the MySQL user root! Important: There is no space between -p and !)

If you want to go the LOAD DATA FROM MASTER; way then there is nothing you must do right now.


Now we have to tell MySQL on the slave that it is the slave, that the master is 192.168.0.100, and that the master database to watch is exampledb. Therefore we add the following lines to /etc/mysql/my.cnf:

server-id=2
master-host=192.168.0.100
master-user=slave_user
master-password=secret
master-connect-retry=60
replicate-do-db=exampledb

Then we restart MySQL:

/etc/init.d/mysql restart


If you have not imported the master exampledb with the help of an SQL dump, but want to go the LOAD DATA FROM MASTER; way, then it is time for you now to get the data from the master exampledb:

mysql -u root -p
Enter password:
LOAD DATA FROM MASTER;
quit;

If you have phpMyAdmin installed on the slave you can now check if all tables/data from the master exampledb is also available on the slave exampledb.


Finally, we must do this:

mysql -u root -p
Enter password:
SLAVE STOP;

In the next command (still on the MySQL shell) you have to replace the values appropriately:

CHANGE MASTER TO MASTER_HOST='192.168.0.100', MASTER_USER='slave_user', MASTER_PASSWORD='', MASTER_LOG_FILE='mysql-bin.006', MASTER_LOG_POS=183;

  • MASTER_HOST is the IP address or hostname of the master (in this example it is 192.168.0.100).
  • MASTER_USER is the user we granted replication privileges on the master.
  • MASTER_PASSWORD is the password of MASTER_USER on the master.
  • MASTER_LOG_FILE is the file MySQL gave back when you ran SHOW MASTER STATUS; on the master.
  • MASTER_LOG_POS is the position MySQL gave back when you ran SHOW MASTER STATUS; on the master.

Now all that is left to do is start the slave. Still on the MySQL shell we run

START SLAVE;
quit;

That's it! Now whenever exampledb is updated on the master, all changes will be replicated to exampledb on the slave. Test it!

Links

Sunday, March 26, 2006 

My sysadmin toolbox

Torsmo

Torsmo is a desktop system monitoring tool, and one of the best I have ever used.

Torsmo differs from other system monitors, such as GKrellM, in that it does not spawn a new window, but instead renders text directly to your desktop. It can display almost anything about your system, including uptime, current CPU usage, network activity, hard drive usage, memory usage, and swap usage. The program's developers wrote it to use as little of your system's resources as possible, and it does a good job of this.

You can configure what torsmo displays through its configuration file, normally found in your home directory as .torsmorc. You can look at my configuration file at http://realfolkblues.org/torsmorc.

ImageMagick

ImageMagick makes it easy to perform many operations on images directly from the command line. Among its many useful tools, identify is used to display information about an image, import can save any window on an X server to an image file, and convert can convert an image to almost any format with a single command.

You can use identify to show detailed information about a photo or image by running identify imagename . For example:

jon@gimli:~$ identify /media/pics/Group-Photo.jpg
/media/pics/Group-Photo.jpg JPEG 819x614 DirectClass 371kb 0.050u 0:01

I often use import to take a screenshot of my desktop. For example, to save a screenshot of your desktop to your home directory as a PNG image named screenshot.png, run import -window root $HOME/screenshot.png. ImageMagick will save the screenshot in the image format specified by the file extension.

Using convert to convert an image from one format to another could not be easier -- just run convert imagename.png imagename.jpg . Again, ImageMagick takes the format from the extension, so you don't need to give it an additional option to specify the new format.

Aterm

While KDE and GNOME come with their own terminal applications, these applications do much more than I need. Aterm, on the other hand, is a simple terminal program with fewer features, so it appears almost instantly when you start it. Though it's not as bulky as other terminal emulators, Aterm does have many useful options, which you can read about by typing aterm --help at the command line.

I like to start Aterm with a black background, white text, a 1,000-line history buffer, and display all text using the font "drift" from the "artwiz" font family. To get this, use aterm -bg black -fg white -sl 1000 -fn "-artwiz-drift-*".

Root-tail

Sometimes I use tail -f to monitor logfiles for changes. While useful, it's awkward to have a terminal window open all the time to monitor a logfile. Root-tail provides an excellent alternative by displaying logfiles as text rendered on your desktop in whatever font and color you specify. It also updates the text on your desktop at the interval you specify.

To use root-tail, just run root-tail filename to monitor a file. Root-tail has many useful options, which you can see by typing root-tail --help, or just read its man page.

Quod Libet

Out of the hordes of music players available for Linux, Quod Libet is my favorite. One of the things I like about Quod Libet is its ability to make playlists based on regular expressions. You can operate the player from the command line by running the program with an argument, making it simple to set up hotkeys with KDE to control the player. For instance, if I go to the KDE Control Center hotkey section and add a hotkey such as Control-Alt-X to run the command quodlibet --play, I can then simply press Control-Alt-X to cause Quod Libet to play music. See all of the command line arguments that are available by running quodlibet --help.

Quod Libet has excellent ID3 tag editing, with the ability to edit tags based on the filenames of songs, rename files based on their tags, and change many files at once. Quod Libet also supports album cover art.

In addition to its native features, Quod Libet also has an extensive collection of plugins that can greatly extend its functionality. One particularly interesting plugin, Animated On-Screen Display, can display information about the music Quod Libet is playing. See the full list of plugins on the Quod Libet site.

Transmission

While I normally use Azureus as my BitTorrent client, it's fairly resource-intensive, and that makes it less appealing for me. In situations where I need a simple and fast client, I use Transmission. It handles torrents using a fraction of the memory and CPU time that Azureus uses. Unlike Azureus, it has the ability to run all of the torrents on a single port, removing the need to allow entire port ranges through a firewall in order to use the program.

Transmission is perfect for users who occasionally need to download a torrent. While Azureus uses Java to draw its interface, Transmission uses GTK+, helping it fit in perfectly with a GNOME desktop. Transmission also sports a command-line interface that is especially useful when you must run it in a remote environment.

 

Network Monitoring with Zabbix

The ZABBIX server requires the following system resources:



* 10 MB of disk space (100 MB recommended)
* 64 MB of RAM (128 MB recommended)
* MySQL or PostgreSQL as backend database


First we define 2 locations:

The Server, here comes all the info together and is processed in a database, note that the server can be monitored to so it runs an agent too.


The Agent, Information is gathered and polled by the server.



Setup of the Server:

http://prdownloads.sourceforge.net/zabbix/zabbix-1.1beta7.tar.gz?download



1 - Make the zabbix user and group

groupadd zabbix
useradd -c 'Zabbix' -d /home/zabbix -g zabbix -s /bin/bash zabbix


mkdir /home/zabbix
chown -R zabbix.zabbix /home/zabbix




2 - Untar the sources

cd /home/zabbix

tar zxvpf zabbix-1.1beta7.tar.gz

mv zabbix-1.1beta7 zabbix

cd zabbix

chown -R zabbix.zabbix .

su - zabbix





3 - Create a zabbix database and populate it

mysql -p -u root

create database zabbix;
quit;

cd create/mysql

mysql -u root -p zabbix < schema.sql

cd ../data

mysql -u root -p zabbix < data.sql
mysql -u root -p zabbix < images.sql

cd ../../




4 - Configure compile and install the server
We run an agent on the server to so we compile that too ;)

./configure --prefix=/usr --with-mysql --with-net-snmp --enable-server --enable-agent &&
make
su
make install
exit




5 - Prepare the rest of the system

As root edit

/etc/services

Add:

zabbix_agent 10050/tcp # Zabbix ports
zabbix_trap 10051/tcp




mkdir /etc/zabbix

cp misc/conf/zabbix_agentd.conf /etc/zabbix/
cp misc/conf/zabbix_server.conf /etc/zabbix/




Edit /etc/zabbix/zabbix_agentd.conf

make sure that the Server parameter points to the server addres,
for the agent that runs on the server its like this:

Server=127.0.0.1



Edit /etc/zabbix/zabbix_server.conf

For small sites this default file will do, however if you are into
tweaking your config for your 10+ hosts site, this is the place



Start the server

su - zabbix
zabbix_server
exit




Start the client:

su - zabbix
zabbix_agentd
exit




6 - Configure web interface

Edit frontends/php/include/db.inc.php:

$DB_TYPE ="MYSQL";
$DB_SERVER ="localhost";
$DB_DATABASE ="zabbix";
$DB_USER ="root";
$DB_PWD ="secret";


mkdir /home/zabbix/public_html
cp -R frontends/php/* /home/zabbix/html/




Edit /etc/apache/httpd.conf

Make this work:


AllowOverride FileInfo AuthConfig Limit Indexes
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec

Order allow,deny
Allow from all


Order deny,allow
Deny from all



/etc/init.d/apache restart


chown -R zabbix.zabbix public_html




Setup of an Agent

http://prdownloads.sourceforge.net/zabbix/zabbix-1.1beta7.tar.gz?download



1 - Make the zabbix user and group

groupadd zabbix
useradd -c 'Zabbix' -d /home/zabbix -g zabbix -s /bin/bash zabbix

mkdir /home/zabbix
chown -R zabbix.zabbix /home/zabbix




2 - Untar the sources

cd /home/zabbix

tar zxvpf zabbix-1.1beta7.tar.gz

mv zabbix-1.1beta7 zabbix

cd zabbix

chown -R zabbix.zabbix .

su - zabbix




3 - Configure compile and install the agent

./configure --prefix=/usr --with-mysql --with-net-snmp --enable-agent
make
su
make install
exit

mkdir /etc/zabbix
cp misc/conf/zabbix_agentd.conf /etc/zabbix/



Edit /etc/zabbix/zabbix_agentd.conf

make sure that the Server parameter points to the server addres

Server=xxx.xxx.xxx.xxx



4 - Prepare the rest of the system

Edit /etc/services

Add:

zabbix_agent 10050/tcp # Zabbix ports
zabbix_trap 10051/tcp





5 - Start the agent

su - zabbix
zabbix_agentd
exit





What Next ?

Now point your browser to:

http:www.example.com/~zabbix


Login with username: Admin
No Password

Here you can really knock your self out.
This howto intended to show you how to install this mother.
Configuring the monitoring functions is and whole other ballgame.

For now i leave you here with some pointers to documentation

http://www.zabbix.com/documentation.php
http://sourceforge.net/projects/zabbix
http://www.google.com/search?q=zabbix

Saturday, March 25, 2006 

Preventing SSH Dictionary Attacks With DenyHosts

In this HowTo I will show how to install and configure DenyHosts. DenyHosts is a tool that observes login attempts to SSH, and if it finds failed login attempts again and again from the same IP address, DenyHosts blocks further login attempts from that IP address by putting it into /etc/hosts.deny. DenyHosts can be run by cron or as a daemon. In this tutorial I will run DenyHosts as a daemon.

From the DenyHosts web site:

"DenyHosts is a script intended to be run by Linux system administrators to help thwart ssh server attacks.

If you've ever looked at your ssh log (/var/log/secure on Redhat, /var/log/auth.log on Mandrake, etc...) you may be alarmed to see how many hackers attempted to gain access to your server. Hopefully, none of them were successful (but then again, how would you know?). Wouldn't it be better to automatically prevent that attacker from continuing to gain entry into your system?

DenyHosts attempts to address the above... "

This tutorial is based on a Debian Sarge system, however, it should apply to other distributions with almost no modifications.

I want to say first that this is not the only way of setting up such a system. There are many ways of achieving this goal but this is the way I take. I do not issue any guarantee that this will work for you!

1 Installation

DenyHosts is written in Python, therefore we must install Python and also the Python development files first:

apt-get install python2.3-dev python2.3

Then we download and install DenyHosts like this:

cd /tmp
wget http://mesh.dl.sourceforge.net/sourceforge/denyhosts/DenyHosts-2.0.tar.gz
tar xvfz DenyHosts-2.0.tar.gz
cd DenyHosts-2.0
python setup.py install

This installs DenyHosts to /usr/share/denyhosts.

2 Configuration

Now we have to create the DenyHosts configuration file /usr/share/denyhosts/denyhosts.cfg. We can use the sample configuration file /usr/share/denyhosts/denyhosts.cfg-dist for this:

cd /usr/share/denyhosts
cp denyhosts.cfg-dist denyhosts.cfg

Then we must edit denyhosts.cfg with our favourite editor such as vi, for example. Mine looks like this:

 ############ THESE SETTINGS ARE REQUIRED ############

########################################################################
#
# SECURE_LOG: the log file that contains sshd logging info
# if you are not sure, grep "sshd:" /var/log/*
#
# The file to process can be overridden with the --file command line
# argument
#
# Redhat or Fedora Core:
#SECURE_LOG = /var/log/secure
#
# Mandrake, FreeBSD or OpenBSD:
SECURE_LOG = /var/log/auth.log
#
# SuSE:
#SECURE_LOG = /var/log/messages
#
########################################################################

########################################################################
# HOSTS_DENY: the file which contains restricted host access information
#
# Most operating systems:
HOSTS_DENY = /etc/hosts.deny
#
# Some BSD (FreeBSD) Unixes:
#HOSTS_DENY = /etc/hosts.allow
#
# Another possibility (also see the next option):
#HOSTS_DENY = /etc/hosts.evil
#######################################################################


########################################################################
# PURGE_DENY: removed HOSTS_DENY entries that are older than this time
# when DenyHosts is invoked with the --purge flag
#
# format is: i[dhwmy]
# Where 'i' is an integer (eg. 7)
# 'm' = minutes
# 'h' = hours
# 'd' = days
# 'w' = weeks
# 'y' = years
#
# never purge:
PURGE_DENY =
#
# purge entries older than 1 week
#PURGE_DENY = 1w
#
# purge entries older than 5 days
#PURGE_DENY = 5d
#######################################################################


#######################################################################
# BLOCK_SERVICE: the service name that should be blocked in HOSTS_DENY
#
# man 5 hosts_access for details
#
# eg. sshd: 127.0.0.1 # will block sshd logins from 127.0.0.1
#
# To block all services for the offending host:
#BLOCK_SERVICE = ALL
# To block only sshd:
BLOCK_SERVICE = sshd
# To only record the offending host and nothing else (if using
# an auxilary file to list the hosts). Refer to:
# http://denyhosts.sourceforge.net/faq.html#aux
#BLOCK_SERVICE =
#
#######################################################################


#######################################################################
#
# DENY_THRESHOLD_INVALID: block each host after the number of failed login
# attempts has exceeded this value. This value applies to invalid
# user login attempts (eg. non-existent user accounts)
#
DENY_THRESHOLD_INVALID = 5
#
#######################################################################

#######################################################################
#
# DENY_THRESHOLD_VALID: block each host after the number of failed
# login attempts has exceeded this value. This value applies to valid
# user login attempts (eg. user accounts that exist in /etc/passwd) except
# for the "root" user
#
DENY_THRESHOLD_VALID = 10
#
#######################################################################

#######################################################################
#
# DENY_THRESHOLD_ROOT: block each host after the number of failed
# login attempts has exceeded this value. This value applies to
# "root" user login attempts only.
#
DENY_THRESHOLD_ROOT = 5
#
#######################################################################


#######################################################################
#
# WORK_DIR: the path that DenyHosts will use for writing data to
# (it will be created if it does not already exist).
#
# Note: it is recommended that you use an absolute pathname
# for this value (eg. /home/foo/denyhosts/data)
#
WORK_DIR = /usr/share/denyhosts/data
#
#######################################################################

#######################################################################
#
# SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS
#
# SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES|NO
# If set to YES, if a suspicious login attempt results from an allowed-host
# then it is considered suspicious. If this is NO, then suspicious logins
# from allowed-hosts will not be reported. All suspicious logins from
# ip addresses that are not in allowed-hosts will always be reported.
#
SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES
######################################################################

######################################################################
#
# HOSTNAME_LOOKUP
#
# HOSTNAME_LOOKUP=YES|NO
# If set to YES, for each IP address that is reported by Denyhosts,
# the corresponding hostname will be looked up and reported as well
# (if available).
#
HOSTNAME_LOOKUP=YES
#
######################################################################


######################################################################
#
# LOCK_FILE
#
# LOCK_FILE=/path/denyhosts
# If this file exists when DenyHosts is run, then DenyHosts will exit
# immediately. Otherwise, this file will be created upon invocation
# and deleted upon exit. This ensures that only one instance is
# running at a time.
#
# Redhat/Fedora:
#LOCK_FILE = /var/lock/subsys/denyhosts
#
# Debian
LOCK_FILE = /var/run/denyhosts.pid
#
# Misc
#LOCK_FILE = /tmp/denyhosts.lock
#
######################################################################


############ THESE SETTINGS ARE OPTIONAL ############


#######################################################################
#
# ADMIN_EMAIL: if you would like to receive emails regarding newly
# restricted hosts and suspicious logins, set this address to
# match your email address. If you do not want to receive these reports
# leave this field blank (or run with the --noemail option)
#
ADMIN_EMAIL =
#
#######################################################################

#######################################################################
#
SMTP_HOST = localhost
SMTP_PORT = 25
SMTP_FROM = DenyHosts
SMTP_SUBJECT = DenyHosts Report
#SMTP_USERNAME=foo
#SMTP_PASSWORD=bar
#
#######################################################################

######################################################################
#
# ALLOWED_HOSTS_HOSTNAME_LOOKUP
#
# ALLOWED_HOSTS_HOSTNAME_LOOKUP=YES|NO
# If set to YES, for each entry in the WORK_DIR/allowed-hosts file,
# the hostname will be looked up. If your versions of tcp_wrappers
# and sshd sometimes log hostnames in addition to ip addresses
# then you may wish to specify this option.
#
#ALLOWED_HOSTS_HOSTNAME_LOOKUP=NO
#
######################################################################

######################################################################
#
# AGE_RESET_VALID: Specifies the period of time between failed login
# attempts that, when exceeded will result in the failed count for
# this host to be reset to 0. This value applies to login attempts
# to all valid users (those within /etc/passwd) with the
# exception of root. If not defined, this count will never
# be reset.
#
# See the comments in the PURGE_DENY section (above)
# for details on specifying this value or for complete details
# refer to: http://denyhosts.sourceforge.net/faq.html#timespec
#
AGE_RESET_VALID=5d
#
######################################################################

######################################################################
#
# AGE_RESET_ROOT: Specifies the period of time between failed login
# attempts that, when exceeded will result in the failed count for
# this host to be reset to 0. This value applies to all login
# attempts to the "root" user account. If not defined,
# this count will never be reset.
#
# See the comments in the PURGE_DENY section (above)
# for details on specifying this value or for complete details
# refer to: http://denyhosts.sourceforge.net/faq.html#timespec
#
AGE_RESET_ROOT=25d
#
######################################################################

######################################################################
#
# AGE_RESET_INVALID: Specifies the period of time between failed login
# attempts that, when exceeded will result in the failed count for
# this host to be reset to 0. This value applies to login attempts
# made to any invalid username (those that do not appear
# in /etc/passwd). If not defined, count will never be reset.
#
# See the comments in the PURGE_DENY section (above)
# for details on specifying this value or for complete details
# refer to: http://denyhosts.sourceforge.net/faq.html#timespec
#
AGE_RESET_INVALID=10d
#
######################################################################

######################################################################
#
# PLUGIN_DENY: If set, this value should point to an executable
# program that will be invoked when a host is added to the
# HOSTS_DENY file. This executable will be passed the host
# that will be added as it's only argument.
#
#PLUGIN_DENY=/usr/bin/true
#
######################################################################


######################################################################
#
# PLUGIN_PURGE: If set, this value should point to an executable
# program that will be invoked when a host is removed from the
# HOSTS_DENY file. This executable will be passed the host
# that is to be purged as it's only argument.
#
#PLUGIN_PURGE=/usr/bin/true
#
######################################################################

######################################################################
#
# USERDEF_FAILED_ENTRY_REGEX: if set, this value should contain
# a regular expression that can be used to identify additional
# hackers for your particular ssh configuration. This functionality
# extends the built-in regular expressions that DenyHosts uses.
# This parameter can be specified multiple times.
# See this faq entry for more details:
# http://denyhosts.sf.net/faq.html#userdef_regex
#
#USERDEF_FAILED_ENTRY_REGEX=
#
#
######################################################################




######### THESE SETTINGS ARE SPECIFIC TO DAEMON MODE ##########



#######################################################################
#
# DAEMON_LOG: when DenyHosts is run in daemon mode (--daemon flag)
# this is the logfile that DenyHosts uses to report it's status.
# To disable logging, leave blank. (default is: /var/log/denyhosts)
#
DAEMON_LOG = /var/log/denyhosts
#
# disable logging:
#DAEMON_LOG =
#
######################################################################

#######################################################################
#
# DAEMON_LOG_TIME_FORMAT: when DenyHosts is run in daemon mode
# (--daemon flag) this specifies the timestamp format of
# the DAEMON_LOG messages (default is the ISO8061 format:
# ie. 2005-07-22 10:38:01,745)
#
# for possible values for this parameter refer to: man strftime
#
# Jan 1 13:05:59
#DAEMON_LOG_TIME_FORMAT = %b %d %H:%M:%S
#
# Jan 1 01:05:59
#DAEMON_LOG_TIME_FORMAT = %b %d %I:%M:%S
#
######################################################################

#######################################################################
#
# DAEMON_LOG_MESSAGE_FORMAT: when DenyHosts is run in daemon mode
# (--daemon flag) this specifies the message format of each logged
# entry. By default the following format is used:
#
# %(asctime)s - %(name)-12s: %(levelname)-8s %(message)s
#
# Where the "%(asctime)s" portion is expanded to the format
# defined by DAEMON_LOG_TIME_FORMAT
#
# This string is passed to python's logging.Formatter contstuctor.
# For details on the possible format types please refer to:
# http://docs.python.org/lib/node357.html
#
# This is the default:
#DAEMON_LOG_MESSAGE_FORMAT = %(asctime)s - %(name)-12s: %(levelname)-8s %(message)s
#
#
######################################################################


#######################################################################
#
# DAEMON_SLEEP: when DenyHosts is run in daemon mode (--daemon flag)
# this is the amount of time DenyHosts will sleep between polling
# the SECURE_LOG. See the comments in the PURGE_DENY section (above)
# for details on specifying this value or for complete details
# refer to: http://denyhosts.sourceforge.net/faq.html#timespec
#
#
DAEMON_SLEEP = 30s
#
#######################################################################

#######################################################################
#
# DAEMON_PURGE: How often should DenyHosts, when run in daemon mode,
# run the purge mechanism to expire old entries in HOSTS_DENY
# This has no effect if PURGE_DENY is blank.
#
DAEMON_PURGE = 1h
#
#######################################################################


######### THESE SETTINGS ARE SPECIFIC TO ##########
######### DAEMON SYNCHRONIZATION ##########


#######################################################################
#
# Synchronization mode allows the DenyHosts daemon the ability
# to periodically send and receive denied host data such that
# DenyHosts daemons worldwide can automatically inform one
# another regarding banned hosts. This mode is disabled by
# default, you must uncomment SYNC_SERVER to enable this mode.
#
# for more information, please refer to:
# http:/denyhosts.sourceforge.net/faq.html#sync
#
#######################################################################


#######################################################################
#
# SYNC_SERVER: The central server that communicates with DenyHost
# daemons. Currently, denyhosts.net is the only available server
# however, in the future, it may be possible for organizations to
# install their own server for internal network synchronization
#
# To disable synchronization (the default), do nothing.
#
# To enable synchronization, you must uncomment the following line:
#SYNC_SERVER = http://xmlrpc.denyhosts.net:9911
#
#######################################################################

#######################################################################
#
# SYNC_INTERVAL: the interval of time to perform synchronizations if
# SYNC_SERVER has been uncommented. The default is 1 hour.
#
#SYNC_INTERVAL = 1h
#
#######################################################################


#######################################################################
#
# SYNC_UPLOAD: allow your DenyHosts daemon to transmit hosts that have
# been denied? This option only applies if SYNC_SERVER has
# been uncommented.
#
#SYNC_UPLOAD = no
#
# the default:
#SYNC_UPLOAD = yes
#
#######################################################################


#######################################################################
#
# SYNC_DOWNLOAD: allow your DenyHosts daemon to receive hosts that have
# been denied by others? This option only applies if SYNC_SERVER has
# been uncommented.
#
#SYNC_DOWNLOAD = no
#
# the default:
#SYNC_DOWNLOAD = yes
#
#######################################################################

#######################################################################
#
# SYNC_DOWNLOAD_THRESHOLD: If SYNC_DOWNLOAD is enabled this paramter
# filters the returned hosts to those that have been blocked this many
# times by others. That is, if set to 1, then if a single DenyHosts
# server has denied an ip address then you will receive the denied host.
#
#SYNC_DOWNLOAD_THRESHOLD = 10
#
# the default:
#SYNC_DOWNLOAD_THRESHOLD = 3
#
#######################################################################

Make sure you set SECURE_LOG and LOCK_FILE to the correct values for your distribution! For Debian, these are:

SECURE_LOG = /var/log/auth.log
LOCK_FILE = /var/run/denyhosts.pid

As we want to run DenyHosts as a daemon, we need the daemon control script /usr/share/denyhosts/daemon-control. Again, we can use the sample script /usr/share/denyhosts/daemon-control-dist to create the needed file:

cp daemon-control-dist daemon-control

Edit /usr/share/denyhosts/daemon-control and make sure you set the correct values for DENYHOSTS_BIN, DENYHOSTS_LOCK, and DENYHOSTS_CFG. For Debian, these are:

DENYHOSTS_BIN = "/usr/bin/denyhosts.py"
DENYHOSTS_LOCK = "/var/run/denyhosts.pid"
DENYHOSTS_CFG = "/usr/share/denyhosts/denyhosts.cfg"

So my /usr/share/denyhosts/daemon-control file looks like this:

#!/usr/bin/env python
# denyhosts Bring up/down the DenyHosts daemon
#
# chkconfig: 2345 98 02
# description: Activates/Deactivates the
# DenyHosts daemon to block ssh attempts
#
###############################################

###############################################
#### Edit these to suit your configuration ####
###############################################

DENYHOSTS_BIN = "/usr/bin/denyhosts.py"
DENYHOSTS_LOCK = "/var/run/denyhosts.pid"
DENYHOSTS_CFG = "/usr/share/denyhosts/denyhosts.cfg"


###############################################
#### Do not edit below ####
###############################################

import os, sys, signal, time

STATE_NOT_RUNNING = -1
STATE_LOCK_EXISTS = -2

def usage():
print "Usage: %s {start [args...] | stop | restart [args...] | status | debug | condrestart [args...] }" % sys.argv[0]
print
print "For a list of valid 'args' refer to:"
print "$ denyhosts.py --help"
print
sys.exit(0)


def getpid():
try:
fp = open(DENYHOSTS_LOCK, "r")
pid = int(fp.readline().rstrip())
fp.close()
except Exception, e:
return STATE_NOT_RUNNING

if os.access(os.path.join("/proc", str(pid)), os.F_OK):
return pid
else:
return STATE_LOCK_EXISTS


def start(*args):
cmd = "%s --daemon " % DENYHOSTS_BIN
if args: cmd += ' '.join(args)

print "starting DenyHosts: ", cmd

os.system(cmd)


def stop():
pid = getpid()
if pid >= 0:
os.kill(pid, signal.SIGTERM)
print "sent DenyHosts SIGTERM"
else:
print "DenyHosts is not running"

def debug():
pid = getpid()
if pid >= 0:
os.kill(pid, signal.SIGUSR1)
print "sent DenyHosts SIGUSR1"
else:
print "DenyHosts is not running"

def status():
pid = getpid()
if pid == STATE_LOCK_EXISTS:
print "%s exists but DenyHosts is not running" % DENYHOSTS_LOCK
elif pid == STATE_NOT_RUNNING:
print "Denyhosts is not running"
else:
print "DenyHosts is running with pid = %d" % pid


def condrestart(*args):
pid = getpid()
if pid >= 0:
restart(*args)


def restart(*args):
stop()
time.sleep(1)
start(*args)


if __name__ == '__main__':
cases = {'start': start,
'stop': stop,
'debug': debug,
'status': status,
'condrestart': condrestart,
'restart': restart}

try:
args = sys.argv[2:]
except:
args = []

try:
option = sys.argv[1]

if option in ('start', 'restart', 'condrestart'):
if '--config' not in args and '-c' not in args:
args.append("--config=%s" % DENYHOSTS_CFG)

cmd = cases[option]
apply(cmd, args)
except:
usage()

Next we have to make that file executable:

chown root daemon-control
chmod 700 daemon-control

Afterwards, we create the system bootup links for DenyHosts do that it is started automatically when the system is booted:

cd /etc/init.d
ln -s /usr/share/denyhosts/daemon-control denyhosts
update-rc.d denyhosts defaults

Finally, we start DenyHosts:

/etc/init.d/denyhosts start

DenyHosts logs to /var/log/denyhosts, if you are interested in the logs. The SSH daemon logs to /var/log/auth.log on Debian. You can watch both logs and try to log in with an invalid user or with a valid user and incorrect password, etc. via SSH and see what happens. After you have crossed the threshold of incorrect login attempts, the IP address from which you tried to connect should get listed in /etc/hosts.deny, like this:

# /etc/hosts.deny: list of hosts that are _not_ allowed to access the system.
# See the manual pages hosts_access(5), hosts_options(5)
# and /usr/doc/netbase/portmapper.txt.gz
#
# Example: ALL: some.host.name, .some.domain
# ALL EXCEPT in.fingerd: other.host.name, .other.domain
#
# If you're going to protect the portmapper use the name "portmap" for the
# daemon name. Remember that you can only use the keyword "ALL" and IP
# addresses (NOT host or domain names) for the portmapper. See portmap(8)
# and /usr/doc/portmap/portmapper.txt.gz for further information.
#
# The PARANOID wildcard matches any host whose name does not match its
# address.

# You may wish to enable this to ensure any programs that don't
# validate looked up hostnames still leave understandable logs. In past
# versions of Debian this has been the default.
# ALL: PARANOID
sshd: 192.168.0.203

This means that the system with the IP address 192.168.0.203 cannot connect anymore using SSH.

You can specify if/when IP addresses are removed again from /etc/hosts.deny - have a look at the PURGE_DENY variable in /usr/share/denyhosts/denyhosts.cfg. You must start DenyHosts with the --purge option to make the PURGE_DENY variable effective, like this:

/etc/init.d/denyhosts start --purge

However, you can also remove IP addresses manually from there, and as soon as they have got removed, these IP addresses can try to log in again via SSH.





Friday, March 24, 2006 

How do I scan my Linux system for rootkits, worms, trojans, etc.?

Either with ckrootkit or with rkhunter.

chkrootkit:

Either install the package that comes with your distribution (on Debian you would run

apt-get install chkrootkit

), or download the sources from www.chkrootkit.org and install manually:

wget --passive-ftp ftp://ftp.pangeia.com.br/pub/seg/pac/chkrootkit.tar.gz

tar xvfz chkrootkit.tar.gz

cd chkrootkit-/

make sense

Afterwards, you can move the chkrootkit directory somewhere else, e.g. /usr/local/chkrootkit:

cd ..

mv chkrootkit-/ /usr/local/chkrootkit

Now you can run chkrootkit manually:

cd /usr/local/chkrootkit

./chkrootkit

(if you installed a chkrootkit package coming with your distribution, your chkrootkit might be somewhere else).

You can even run chkrootkit by a cron job and get the results emailed to you:

Run

crontab -e

to create a cron job like this:

0 3 * * * (cd /usr/local/chkrootkit-; ./chkrootkit 2>&1 | mail -s "chkrootkit output my server" you@yourdomain.com)

That would run chkrootkit every night a 3.00h.

rkhunter:

Download the latest rkhunter sources from www.rootkit.nl:

wget http://downloads.rootkit.nl/rkhunter-1.2.7.tar.gz

tar xvfz rkhunter-1.2.7.tar.gz

cd rkhunter/

./installer.sh

This will install rkhunter to the directory /usr/local/rkhunter. Now run

rkhunter --update

to download the latest chkrootkit/trojan/worm signatures (you should do this regularly).

Now you can scan your system for malware by running

rkhunter -c

 

Convert man pages to text

There can often be times when you want man pages in print, or to simply save them to text for
something like HTML use. The common thing that people do is:

man lp > lp.txt

This will take the output of lp and put it to a file named lp.txt, but it will keep all the formatting
in the document. In order to get rid of those characters, do the following:

man lp | col -b > lp.txt

Create the text file both ways naming one of them "lp2.txt" and do a "diff" on them. You'll see the
difference then.

Thursday, March 23, 2006 

Poor Mans Raid & Clone Script Tutorial

POORMANS RAID & CLONE SCRIPT

1. Get yourself two hardives setup your first drive (HDA) with the your perfek system.
2. Power up your second drive (HDC)
3. Slice HDC up by using cfdisk (command is cfdisk /dev/hdc)

Hda1 - primary boot begining Label [ / ]
Hda5 - logical beginning [ /usr ]
Hda6 - logical beginning [ /var ]
Hda7 - logical beginning [ swap ]
Hda8 - logical beginning [ /tmp ]
Hda9 - logical beginning [ /home ]

To Setup your filesystem and your labels

Mkfs -t ext3 -L / dev/hdc1
Mkfs -t ext3 -L /usr dev/hdc5
Mkfs -t ext3 -L /var dev/hdc6
Mkfs -t ext3 -L /tmp dev/hdc8
Mkfs -t ext3 -L /home dev/hdc9

okay so you have sliced HDC and setup your filesystems with Labels.

Vi and copy the below script save a file called clone, make it chmod 777 and run it.

once copied run Grub
#grub --no-floppy
#grub>
# device (hd0) /dev/hdc
# root (hd0,0)
# setup (hd0)
# quit

Clone Script"make sure nothing is mounted in /mnt!"
echo "going to unmount /mnt"
/bin/umount /mnt

mount /dev/hdc1 /mnt
cd /
cp -ax / /mnt

mount /dev/hdc5 /mnt/usr
cd /usr
tar lcpBf - /usr | (cd /mnt; tar xBf -)

mount /dev/hdc9 /mnt/home
cd /home
tar lcpBf - /home | (cd /mnt; tar xBf -)

mount /dev/hdc8 /mnt/tmp
cd /tmp
tar lcpBf - /tmp | (cd /mnt; tar xBf -)

#Stop crtical services
/etc/init.d/mysql stop

mount /dev/hdc6 /mnt/var
cd /var
tar lcpBf - /var | (cd /mnt; tar xBf -)

#start all the services again
/etc/init.d/mysql start

echo "all copied"
exit 0

Monday, March 20, 2006 

Out-going admin cron jobs

As the In-Coming Sys Admin, one the checks you should never miss is to check all the Cron and at jobs during the handover period from the out-going Admin!

Try:
# crontab -u [user] -l

Manually change the user for of the users in /etc/passwd or script this substitution if the number of users on your system is worth the effort.

 

Who hits my website

This will generate a listing of all IPs that have accessed a specific directory of my website
(the /foo/ directory), and print a count (from greatest to least) next to the IP.

if you want to get a total listing for all directories of a domain, just omit the "grep -e /foo/" statement.

cat /home/server.com/logs/access_log |
grep -e /flesh/ |
sort |
uniq -w15 -c |
cut -f 1 -d- |
sort -r -g


Using this format for the apache log files:
63.26.57.218 - - [07/Mar/2001:21:12:15 -0500] "GET
/flesh/fleshpix/thumbs/facial2/poofylips.jpg_t.jpg HTTP/1.1" 200 4353


Sample output is:
123 62.155.255.18
123 216.17.9.140
121 62.98.129.125
120 66.32.16.55
120 216.196.144.202
119 194.100.2.65
116 194.170.1.68
114 62.155.255.21

 

Scripts for all occasions

Sun Microsystems has a great archive of useful scripts at:

http://www.sun.com/bigadmin/scripts/index.html

Check it out. You'll be glad you did!

 

Bash shell option

If you are using bash shell. There is a way to cd a particular directory even if you spelled incorrectly on the command line. Set the shell option to:

shopt -s cdspell

eg:-
Suppose you want to cd to "cd /tmp" and you have miss typed to "cd /pmp" still it will cd to "cd /tmp".

This setting will be very usefull if you have a long named directory.

 

Get the hidden files

A safe way of grabbing all "hidden" files is to use '.??*' rather than '.*' since this will only match 3 or more characters. Admittedly, this will miss any hidden files that are only a single character after the ., but it will always miss '.' & '..', which is probably more important...

 

Chrooted SSH HowTo

This tutorial describes how to install and configure OpenSSH so that it will allow chrooted sessions for users. With this setup, you can give your users shell access without having to fear that they can see your whole system. Your users will be jailed in a specific directory which they will not be able to break out of.

This setup is based on a Debian Sarge (Debian 3.1) system, and the chrooted SSH will be installed in such a way that it will still use the configuration files of the standard OpenSSH Debian package which are in /etc/ssh/, and you will be able to use the standard OpenSSH Debian init script /etc/init.d/ssh. Therefore you do not have to create your own init script and configuration file.

I want to say first that this is not the only way of setting up such a system. There are many ways of achieving this goal but this is the way I take. I do not issue any guarantee that this will work for you!

1 Install The Newest Zlib Version

Because there was a security hole in zlib-1.2.2 about which the chrooted SSH will complain when we try to compile it, we install the newest zlib version right now:

cd /tmp
wget http://www.zlib.net/zlib-1.2.3.tar.gz
tar xvfz zlib-1.2.3.tar.gz
cd zlib-1.2.3
make clean
./configure -s
make
make install

2 Install The Chrooted SSH

This is quite easy. We download the patched OpenSSH sources, and we configure them with /usr as directory for the SSH executable files, with /etc/ssh as directory where the chrooted SSH will look for configuration files, and we also allow PAM authentication:

cd /tmp
apt-get install libpam0g-dev openssl libcrypto++-dev libssl0.9.7 libssl-dev ssh
wget http://chrootssh.sourceforge.net/download/openssh-4.2p1-chroot.tar.gz
tar xvfz openssh-4.2p1-chroot.tar.gz
cd openssh-4.2p1-chroot
./configure --exec-prefix=/usr --sysconfdir=/etc/ssh --with-pam
make
make install

3 Create The Chroot Environment

Next I create a chroot environment under /home/chroot. This is the directory that all chrooted SSH users will get jailed in, i.e. they will not be able to see any files/directories outside /home/chroot.

I have to create some directories in /home/chroot, and I have to copy a few binaries like /bin/bash, /bin/ls, etc. as well as the libraries on which these binaries depend into the chroot environment so that they are available to any chrooted user.

mkdir /home/chroot/
mkdir /home/chroot/home/
cd /home/chroot
mkdir etc
mkdir bin
mkdir lib
mkdir usr
mkdir usr/bin
mkdir dev
mknod dev/null c 1 3
mknod dev/zero c 1 5

Now that we have created the necessary directories, we are goning to copy some binaries and all the libraries on which they depend into the chroot environment. This is an excerpt of a script that I found on http://mail.incredimail.com/howto/openssh/create_chroot_env that does this. Just copy and paste the following lines into your shell, and hit Return. If you want to make more programs available to your chrooted users, just add these programs to the APPS line:

APPS="/bin/bash /bin/ls /bin/mkdir /bin/mv /bin/pwd /bin/rm /usr/bin/id /usr/bin/ssh /bin/ping /usr/bin/dircolors"
for prog in $APPS; do
cp $prog ./$prog

# obtain a list of related libraries
ldd $prog > /dev/null
if [ "$?" = 0 ] ; then
LIBS=`ldd $prog | awk '{ print $3 }'`
for l in $LIBS; do
mkdir ./`dirname $l` > /dev/null 2>&1
cp $l ./$l
done
fi
done

Then we do this:

cp /lib/libnss_compat.so.2 /lib/libnsl.so.1 /lib/libnss_files.so.2 ./lib/
echo '#!/bin/bash' > usr/bin/groups
echo "id -Gn" >> usr/bin/groups
touch etc/passwd
grep /etc/passwd -e "^root" > etc/passwd

You should also copy the line of the group in which you will create new users from /etc/group to /home/chroot/etc/group. In this tutorial we will create users in the group users, so we do this:

grep /etc/group -e "^root" -e "^users" > etc/group

and restart SSH:

/etc/init.d/ssh restart

4 Create A Chrooted User

Even with the chrooted SSH that we have just installed you can log in without being chrooted (which makes sense if you log in as root, for example). Now, how does the chrooted SSH decide whom to chroot and whom not? That's easy: the chrooted SSH looks up the user who is trying to log in in /etc/passwd. If the user's home directory in /etc/passwd has a . in it, then the user is going to be chrooted.


Example (from /etc/passwd):

user_a:x:2002:100:User A:/home/user_a:/bin/bash

This user will not be chrooted.

user_b:x:2003:100:User B:/home/chroot/./home/user_b:/bin/bash

This user will be chrooted.


Now we create the user testuser with the home directory /home/chroot/./home/testuser and the group users (which is the default group for users on Debian so you do not have to specify it explicitly):

useradd -s /bin/bash -m -d /home/chroot/./home/testuser -c "testuser" -g users testuser

Then we give testuser a password:

passwd testuser

Finally, we have to copy the line for testuser in /etc/passwd to /home/chroot/etc/passwd:

grep /etc/passwd -e "^testuser" >> /home/chroot/etc/passwd

We have already copied the users group line from /etc/group to /home/chroot/etc/group so we do not have to do this here again. If you create a chrooted user in another group than users, add this group to /home/chroot/etc/group:

grep /etc/group -e "^othergroup" >> /home/chroot/etc/group

Now try to log in to SSH as testuser. You should be chrooted and not be able to browse files/directories outside /home/chroot.

Have fun!


Friday, March 17, 2006 

How to create IP-IP tunnel between FreeBSD and Linux

Sometimes, I need to connect remote Unix servers with tunnels to provide some specific services or to get access to some internal networks. I was very surprised, when my friend, young system administrator, asked me about how to bring up IP-IP tunnel between different Unix operating systems (FreeBSD and Linux in his case) and said, that he can’t find information about this configuration. As the result of my discovering, this HOWTO has been created.

Lets see to what we have and what we need to do.

We have 2 servers:

  • Server1:
    • OS: Linux
    • Network Interface: eth0
    • IP: 100.100.100.100
  • Server2:
    • OS: FreeBSD
    • Network Interface: fxp0
    • IP: 200.200.200.200

We need to get IPv4 over IPv4 tunnel with the following parameters between described servers:

  • Server1: 10.0.0.1 / 255.255.255.252
  • Server2: 10.0.0.2 / 255.255.255.252

To setup described configuration on Linux server we need to do following steps:

  • Create ipip tunnel interface:
    # ip tunnel add tun0 mode ipip > remote 200.200.200.200 local 100.100.100.100 dev eth0

  • Set interface IP addresses:
    # ifconfig tun0 10.0.0.1 netmask 255.255.255.252 > pointopoint 10.0.0.1

  • Set interface MTU and bring interface up:
    # ifconfig tun0 mtu 1500 up

Now we have following interface on the Linux server:

linux:~# ifconfig tun0
tun77 Link encap:IPIP Tunnel HWaddr
inet addr:10.0.0.1 P-t-P:10.0.0.2 Mask:255.255.255.252
UP POINTOPOINT RUNNING NOARP MTU:1500 Metric:1
RX packets:6 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:504 (504.0 b) TX bytes:624 (624.0 b)

Now, we need to create tunnel point at the FeeeBSD server:

  • Create gif tunnel interface:
    # # ifconfig gif0 create

  • Set interface transport IP addresses:
    # gifconfig gif0 inet 200.200.200.200 100.100.100.100

  • Set interface IP addresses:
    # ifconfig gif0 10.0.0.2 netmask 255.255.255.252 10.0.0.1

  • Set interface MTU and bring interface up:
    # ifconfig gif0 mtu 1500 up

The result at the FreeBSD side is following:

# ifconfig gif0
gif0: flags=8051 mtu 1500
tunnel inet 200.200.200.200 –> 100.100.100.100
inet 10.0.0.2 –> 10.0.0.1 netmask 0xfffffffc

To check the result we can use ping utility at linux side:

linux:~# ping -c 4 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.139 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.138 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.138 ms
64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=0.136 ms

— 172.17.0.1 ping statistics —
4 packets transmitted, 4 received, 0% packet loss, time 2997ms
rtt min/avg/max/mdev = 0.136/0.137/0.139/0.014 ms

That is all! Now we have “direct” connection between our two servers and we are able to do some routing via this link.

 

How can I have two default routes?

This is where advanced routing comes into play (finally!). With advanced routing, you can have as many routing tables as you need; in this case you need to add just one for the new DSL line.

First, add a name for the new routing table to the file /etc/iproute2/rt_tables. You can append it to the file with command "echo 2 dsl2 >> /etc/iproute2/rt_tables".

# echo 2 dsl2 >> /etc/iproute2/rt_tables
# cat /etc/iproute2/rt_tables list the file contents
#
# reserved values
#
255 local
254 main
253 default
0 unspec
#
# local
#
#1 inr.ruhep
2 dsl2 the line you just added

Earlier I mentioned that typing "ip route" is a shortcut for the longer command "ip route show table main". Well, to list the new routing table you have to use the long form: "ip route show table dsl2" If you enter this command right now, you will see the new table is empty.

You really only need to add the new default route to the new table; the old "main" table will continue to handle everything else. You will see why in a minute. Once again, here is the existing "main" table.

# ip route show table main
63.63.63.0/29 dev eth0 proto kernel scope link src 63.63.63.1
30.31.32.0/29 dev eth1 proto kernel scope link src 30.31.32.1
default via 63.63.63.6 dev eth0

Add the new default route to table dsl2 and then look at the (short) table.

# ip route add default via 30.31.32.6 dev eth1 table dsl2
# ip route show table dsl2

default via 30.31.32.6 dev eth1 the whole table is just one line

But the new table is not used yet!

You need to learn one more command, "ip rule"

A routing table tells where packets should go (its destination). You need to be able to tell the kernel to use a different table, based on where a packet is from (its source address).

The existing ip ruleset is very simple, look at it now.

# ip rule
0: from all lookup local
32766: from all lookup main
32767: from all lookup default

You need to add just one new rule:

# ip rule add from 30.31.32.1 lookup dsl2 prio 1000 

This command says "add a rule" to handle the case when a packet has a "from" pattern of "30.31.32.1"; use the routing table called "dsl2", and assign the rule a priority level of "1000". Now relist the rules. In this example, the "pattern" only needs to match one address but if you build a Linux router, you could set patterns that would match different sets of addresses.

# ip rule
0: from all lookup local
1000: from 30.31.32.1 lookup dsl2
32766: from all lookup main
32767: from all lookup default

The kernel searches the ip rules in order, starting with the lowest priority and continuing through each rule and routing table until the packet has been routed successfully.

Your default ruleset will always have a 'local' table with 'all' as the match pattern. The local table handles traffic that is supposed to stay on the local machine, and broadcast traffic.

Our new rule comes next, with a priority of 1000. I picked this number to make adding other rules before and after ours easy later on.

After our rule comes the 'main' table, which is the one that is manipulated by the old 'route' command. Finally comes the 'default' table. I don't know the official purpose of default, it's empty on all the systems I have set up. There is a 'default' route in the table 'main', so no traffic ever gets to the table 'detault'.

Caveats

When you are playing with multiple routing tables, you have to remember to add the 'table' portion to the command. I have only forgotten about 1000 times now. It can be mystifying when rules change in the wrong table (main). And of course, you are sure to confuse things when learning and lock yourself out if you are remotely logged in. The changes happen FAST. Use a console connection.

Another tip. Routes are cached. This means that if you update a routing table and nothing seems to happen, don't get frustrated, just flush the cache. You can make several changes at once and then flush the cache at the end so that the changes effectively all happen simultaneously. This is handy when working on a running router.

The flush command I use is "ip route flush table cache". Be very careful with the flush command!! Enter it wrong and you will remove all routing rules, instantly cutting off your networks.

 

Revealing your routing tables

From a command line on any Linux system, you can see the existing routing table by simply typing 'route' at the prompt. (Type '/sbin/route' if /sbin is not in your path.) Your routing table will be similar to this:
# route
destination gateway interface
63.63.63.0 * eth0
default 63.63.63.6 eth

Advanced routing commands are issued as arguments to the 'ip' command. To see the routing table with iproute2, you can use the long version "ip route show table main" or the shortcut version "ip route" like this:

# ip route
63.63.63.0/29 dev eth0 proto kernel scope link src 63.63.63.1
default via 63.63.63.6 dev eth0

Recall that in our simple example, all ip addresses are considered to be either 'local' or 'not local'. For this network, a local address will be in the range from 63.63.63.1 to 63.63.63.6. A non-local address is just anything else.* It's traditional to assign the router the highest address in the range (ending in 6 for this network).

The first line in the routing table says that if the address is local, your computer puts the packet right out onto the ethernet wire using interface /dev/eth0. The only other device on your local network right now is the DSL router at 63.63.63.6. You can probably use a browser to bring up the router's built-in web-based configuration interface by connecting to http://63.63.63.6/

When you want to surf over to linuxforums.org, the packets need to go to the Internet. You computer will use DNS to translate the name linuxforums.org into its IP address (67.15.52.42). Your computer sees that address is not local, so it uses teh 'default' entry in the routing table and sends the packet to your DSL router.

In turn, the DSL router looks at the destination address, and sees that the data is destined for somewhere on the Internet. The DSL router then pushes the packet out its DSL connection to the next router upstream which is at your ISP. Just as with the postcard analogy, it's now out of your hands; more upstream routers send it on its way to the linuxforums.org server.

When the response comes back from linuxforums.org, there is a destination address of 63.63.63.1 in the packet, so when it hits your DSL router it will pass the packet onto your LAN. Your desktop computer sees the packet on the LAN and picks it up. The round trip connection is now completed. It takes many such exchanges of packets to pass all the data required for just a single page.

If you have a web server running on your local computer, everything works pretty much the same way, but the traffic flows the other direction. Requests for pages come in from the Internet and your web server responds by sending pages back out via the DSL router. Usually you arrange to get your ip address into a DNS server somewhere so that you can publish a URL for your server with a friendly name like "http://myveryownserver.org" but you could just as easily not bother with that and just tell all your friends that your URL is http://63.63.63.1/.

When a friend surfs to http://63.63.63.1/, your web server will receive the request with a source address pointing back to your friend's computer. Thus the reply will be routed back out via your one and only default router.

* Yes, I know there is another internal network on the address 127.0.0.1. It's called the loopback interface /dev/lo. But let's not worry about it here, okay?

 

Where do the IP addresses come from?

You used to have to set up ip addresses, netmasks, gateways, and name resolvers all manually. Refer to any basic networking text to learn more about this aspect.

These days DHCP (Dynamic Host Control Protocol) is very popular. Let's assume that a DHCP server (typically inside your Cable/DSL modem) and issues all the network information required. The network engineer at your upstream provider has configured the modem for you so that it will work with their network.

With a typical home setup, you are assigned just one IP address and if you have more than one computer at home, you have to play games (NAT or MASQUERADE) to share the one IP address. A typical small business connection might have 5 IP addresses assigned statically so that you can publish them; a sixth address in the range lets you communicate with the router in your DSL modem.

For a 6 address block, you'd be assigned a netmask with 29 bits (255.255.255.248 in "dotted decimal" format). You don't need to know what a netmask is right now, but it divides the address into two parts, network and local. In the postcard analogy, a p.o. box number would be the local part of your address.

Let's say your first DSL provider gives you the address range from 63.63.63.1 to 63.63.63.6; your computer is at 63.63.63.1; your DSL router is at 63.63.63.6; and the remaining 4 addresses are currently unused.

 

Just what is routing?

I like to compare network packet routing with the post office. Let's say that you and a friend play chess by sending postcards to each other. Each postcard has a source and a destination address (From: and To: addresses) and a small amount of information, the next move in your game. You send a postcard with your move on it, then you wait for a reply to come back with your friend's next move. The game progresses as a series of transmissions and replies; the whole thing routed through any number of post offices without your knowledge. Under ordinary circumstances, to tap into this vast network, all you have to need to know are the addresses and how to find your mailbox.

Each postcard is like a network packet. With the postal system, you could send a letter if your information doesn't fit on a card. With a network, you just send more packets instead because you can't (normally) change the packet size; your operating system handles the task of breaking down large messages into small packets for transmission; likewise it reassembles incoming packets for you. This is what happens when you request a web page; you enter one address (the URL) and the network coordinates the exchange of hundreds of packets unbenownst to you. To learn about routing though, you can ignore this fact and concentrate only on the routing of a single packet.

After you drop your postcard into a mailbox, a system for routing it to its destination takes over; the reply comes back the same way. You only care about this routing mechanism when something changes, for example, if you move to a new address and want things forwarded. Otherwise it all remains invisible to you.

With the Internet, you normally only deal with one connection to this invisible network; the router provided to you by your Internet Service Provider (ISP) is your connection.

If you have one computer and one network connection, this is just about all you need to know about routing. Any packet leaving your computer heads out to the Internet, and any reply coming back from the Internet is destined for your one computer.

Continuing with the postal analogy, if you work in the mailroom for a large company, you still generally only have one connection to the outside world, but there is an internal mailbox for each employee. As the clerk in the mailroom, you decide based on the To: address to either route a letter internally (delivering it to its local mailbox) or as before, you throw it into an outgoing pile for your connection to the world.

When you add a second computer in your office, each of your computers will have addresses indicating they are connected to the same LAN (local area network). The routing table in each of your computers has to know the correct LAN address range so that they can talk to each other.

With additional equipment, network complexity grows and things become progressively more complicated and much more interesting (to me anyway); there can be many routes in your computer's routing table. We are not getting into that here.

In the simple set up we are doing here, you only have to recognize two types of address, internal (LAN) or external (Internet).