Friday, March 16, 2012


  SNMP and MRTG on Sarge quick start

There appear to be no uncomplicated introductions to the subject of traffic monitoring on the internet anywhere. So here is one. The objective is to get traffic graphs for the primary interface on your server, workstation or firewall quickly and efficiently.
The system is fairly simple and consists of these parts:
  1. The SNMP server. This allows access via the SNMP protocol to the system's network interface statistics and other data.
  2. The MRTG (Multi router traffic grapher). This is a large Perl script which polls the SNMP server and accumulates information about network usage. This runs periodically from cron and generates graphs at defined intervals
Please note that you can collect and graph anything with these - they are not limited to network statistics. Not only that, you can manage many aspects of your server with SNMP.
Please make sure you have apache or apache2 installed for this to work.
SNMP server configuration
Firstly, you need an SNMP server to provide network interface statstics on demand:
# apt-get install snmpd
You need to edit the configuration for this as it does not allow any connections by default. With your favourite editor, edit:
/etc/snmp/snmpd.conf
Comment out the following (prefix with #):
com2sec paranoid default public
Insert the following underneath the commented out section:
com2sec readonly default public
That gives anyone with access to the SNMP server read-only access to the public community. This is the one that contains the interface statistics.
To apply the changes, restart snmpd:
/etc/init.d/snmpd restart
Make sure you firewall off any SNMP related ports so that you don't get any unwanted visitors (check netstat and /etc/services for port information).
Installation of MRTG
MRTG is the main collection and graphing component of the traffic monitoring solution I am presenting here. Firstly, install MRTG:
# apt-get install mrtg
You can manually or automatically generate the configuration file for mrtg. I would recommend doing it automatically as it is a lot easier. Issue the following command:
# cfgmaker --global 'WorkDir: /var/www/mrtg' \
    --output /etc/mrtg.cfg public@127.0.0.1
This will generate the configuration file. You then need to make an index file which contains a list of all of your interfaces. Issue the following command:
# indexmaker /etc/mrtg.cfg --columns=1 \
    --output /var/www/mrtg/index.html
You will now need to execute mrtg manually 3 times to create the required database files. Issue the following command 3 times sequentially. On the third run, you should see no errors being reported:
# mrtg
This is executed every 5 minutes by cron. The cron job was added by dpkg for you so you do not have to configure it.
Conclusion
Finally, inspect your results! You will not see any reasonable graphs for quite some time so sit back end relax for a bit!

Sunday, January 1, 2012

Setting Up Unison File Synchronization Between Two Servers On Debian Squeeze


This tutorial shows how to set up file synchronization between two Debian Squeeze servers with Unison. Unison is a file-synchronization tool similar to rsync, but the big difference is that it tracks/synchronizes changes in both directions, i.e., files changed on server1 will be replicated to server2 and vice versa.
I do not issue any guarantee that this will work for you!

1 Preliminary Note

In this tutorial I use the following two Debian Squeeze servers:
  • server1.example.com with the IP address 192.168.0.100
  • server2.example.com with the IP address 192.168.0.101
I want to synchronize the directory /var/www between the two servers. I will run Unison as the root user in this tutorial so that Unison has sufficient permissions to synchronize user and group permissions.

2 Installing Unison

server1/server2:
Unison has to be installed on server1 and server2; since we connect from server1 to server2 using SSH, we also need the SSH packages. This can be achieved as follows:
apt-get install unison openssh-server ssh

3 Creating A Private/Public Key Pair On server1

server1:
Now we create a private/public key pair on server1.example.com:
ssh-keygen -t dsa
root@server1:~# ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/root/.ssh/id_dsa):
 <-- ENTER
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
 <-- ENTER
Enter same passphrase again: <-- ENTER
Your identification has been saved in /root/.ssh/id_dsa.
Your public key has been saved in /root/.ssh/id_dsa.pub.
The key fingerprint is:
1b:95:bc:4a:f4:9f:d8:ea:24:31:0f:c9:72:d5:a7:80 root@server1.example.com
The key's randomart image is:
+--[ DSA 1024]----+
|                 |
|         o o     |
|        E * . .  |
|       o = o o   |
|      . S o .    |
|       + O + .   |
|        + + +    |
|         o .     |
|         .o      |
+-----------------+
root@server1:~#
It is important that you do not enter a passphrase otherwise the mirroring will not work without human interaction so simply hit ENTER!
Next, we copy our public key to server2.example.com:
ssh-copy-id -i $HOME/.ssh/id_dsa.pub root@192.168.0.101
root@server1:~# ssh-copy-id -i $HOME/.ssh/id_dsa.pub root@192.168.0.101
The authenticity of host '192.168.0.101 (192.168.0.101)' can't be established.
RSA key fingerprint is 25:d8:7a:ee:c2:4b:1d:92:a7:3d:16:26:95:56:62:4e.
Are you sure you want to continue connecting (yes/no)?
 <-- yes (you will see this only if this is the first time you connect to server2) 
Warning: Permanently added '192.168.0.101' (RSA) to the list of known hosts.
root@192.168.0.101's password:
 <-- server2 root password
Now try logging into the machine, with "ssh 'root@192.168.0.101'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

root@server1:~#
Now check on server2 if server1's public key has correctly been transferred:
server2:
cat $HOME/.ssh/authorized_keys
ssh-dss AAAAB3NzaC1kc3MAAACBAPhiAexgEBexnw0rFG8lXwAuIsca/V+lhmv5lhF3BqUfAbL7e2sWlQlGhxZ8I2UnzZK8Ypffq6Ks+lp46yOs7MMXLqb7JBP9gkgqxyEWqOoUSt5hTE9ghupcCvE7rRMhefY5shLUnRkVH6hnCWe6yXSnH+Z8lHbcfp864GHkLDK1AAAAFQDddQckbfRG4C6LOQXTzRBpIiXzoQAAAIEAleevPHwi+a3fTDM2+Vm6EVqR5DkSLwDM7KVVNtFSkAY4GVCfhLFREsfuMkcBD9Bv2DrKF2Ay3OOh39269Z1rgYVk+/MFC6sYgB6apirMlHj3l4RR1g09LaM1OpRz7pc/GqIGsDt74D1ES2j0zrq5kslnX8wEWSHapPR0tziin6UAAACBAJHxgr+GKxAdWpxV5MkF+FTaKcxA2tWHJegjGFrYGU8BpzZ4VDFMiObuzBjZ+LrUs57BiwTGB/MQl9FKQEyEV4J+AgZCBxvg6n57YlVn6OEA0ukeJa29aFOcc0inEFfNhw2jAXt5LRyvuHD/C2gG78lwb6CxV02Z3sbTBdc43J6y root@server1.example.com

4 Running Unison

server1:
We can now run Unison for the first time to synchronize the /var/www directory on both servers. On server1 run:
unison /var/www ssh://192.168.0.101//var/www
Output will be similar to this one - you might have to answer a few questions as this is the first time Unison is being run:
root@server1:~# unison /var/www ssh://192.168.0.101//var/www
Contacting server...
Connected [//server1.example.com//var/www -> //server2.example.com//var/www]
Looking for changes
Warning: No archive files were found for these roots, whose canonical names are:
        /var/www
        //server2.example.com//var/www
This can happen either
because this is the first time you have synchronized these roots,
or because you have upgraded Unison to a new version with a different
archive format.

Update detection may take a while on this run if the replicas are
large.

Unison will assume that the 'last synchronized state' of both replicas
was completely empty.  This means that any files that are different
will be reported as conflicts, and any files that exist only on one
replica will be judged as new and propagated to the other replica.
If the two replicas are identical, then no changes will be reported.

If you see this message repeatedly, it may be because one of your machines
is getting its address from DHCP, which is causing its host name to change
between synchronizations.  See the documentation for the UNISONLOCALHOSTNAME
environment variable for advice on how to correct this.

Donations to the Unison project are gratefully accepted:
http://www.cis.upenn.edu/~bcpierce/unison

  Waiting for changes from server| webalizer
Reconciling changes

local          server2.e...
dir      ---->            apps  [f]
file     ---->            index.html  [f]
link     ---->            ispconfig  [f]
dir      ---->            php-fcgi-scripts/apps  [f]
dir      ---->            webalizer  [f]
link     ---->            webmail  [f]

Proceed with propagating updates? []
 <-- y
Propagating updates


UNISON 2.32.52 started propagating changes at 14:25:02 on 26 Jul 2011
[BGN] Copying apps from /var/www to //server2.example.com//var/www
[BGN] Copying index.html from /var/www to //server2.example.com//var/www
[BGN] Copying ispconfig from /var/www to //server2.example.com//var/www
[BGN] Copying php-fcgi-scripts/apps from /var/www to //server2.example.com//var/www
[BGN] Copying webalizer from /var/www to //server2.example.com//var/www
[BGN] Copying webmail from /var/www to //server2.example.com//var/www
[END] Copying ispconfig
[END] Copying webmail
[END] Copying apps
[END] Copying webalizer
[END] Copying index.html
[END] Copying php-fcgi-scripts/apps
UNISON 2.32.52 finished propagating changes at 14:25:03 on 26 Jul 2011


Saving synchronizer state
Synchronization complete at 14:25:03  (6 items transferred, 0 skipped, 0 failed)
root@server1:~#
Check the /var/www directory on server1 and server2 now, and you should find that they are in sync now.
Of course, we don't want to run Unison interactively, therefore we can create a preferences file (/root/.unison/default.prf) that contains all settings that we otherwise would have to specify on the command line:
vi /root/.unison/default.prf
# Roots of the synchronization
root = /var/www
root = ssh://192.168.0.101//var/www

# Paths to synchronize
#path = current
#path = common
#path = .netscape/bookmarks.html

# Some regexps specifying names and paths to ignore
#ignore = Path stats    ## ignores /var/www/stats
#ignore = Path stats/*  ## ignores /var/www/stats/*
#ignore = Path */stats  ## ignores /var/www/somedir/stats, but not /var/www/a/b/c/stats
#ignore = Name *stats   ## ignores all files/directories that end with "stats"
#ignore = Name stats*   ## ignores all files/directories that begin with "stats"
#ignore = Name *.tmp    ## ignores all files with the extension .tmp

#          When set to true, this flag causes the user interface to skip
#          asking for confirmations on non-conflicting changes. (More
#          precisely, when the user interface is done setting the
#          propagation direction for one entry and is about to move to the
#          next, it will skip over all non-conflicting entries and go
#          directly to the next conflict.)
auto=true

#          When this is set to true, the user interface will ask no
#          questions at all. Non-conflicting changes will be propagated;
#          conflicts will be skipped.
batch=true

#          !When this is set to true, Unison will request an extra
#          confirmation if it appears that the entire replica has been
#          deleted, before propagating the change. If the batch flag is
#          also set, synchronization will be aborted. When the path
#          preference is used, the same confirmation will be requested for
#          top-level paths. (At the moment, this flag only affects the
#          text user interface.) See also the mountpoint preference.
confirmbigdel=true

#          When this preference is set to true, Unison will use the
#          modification time and length of a file as a `pseudo inode
#          number' when scanning replicas for updates, instead of reading
#          the full contents of every file. Under Windows, this may cause
#          Unison to miss propagating an update if the modification time
#          and length of the file are both unchanged by the update.
#          However, Unison will never overwrite such an update with a
#          change from the other replica, since it always does a safe
#          check for updates just before propagating a change. Thus, it is
#          reasonable to use this switch under Windows most of the time
#          and occasionally run Unison once with fastcheck set to false,
#          if you are worried that Unison may have overlooked an update.
#          The default value of the preference is auto, which causes
#          Unison to use fast checking on Unix replicas (where it is safe)
#          and slow checking on Windows replicas. For backward
#          compatibility, yes, no, and default can be used in place of
#          true, false, and auto. See the section "Fast Checking" for more
#          information.
fastcheck=true

#          When this flag is set to true, the group attributes of the
#          files are synchronized. Whether the group names or the group
#          identifiers are synchronizeddepends on the preference numerids.
group=true

#          When this flag is set to true, the owner attributes of the
#          files are synchronized. Whether the owner names or the owner
#          identifiers are synchronizeddepends on the preference
#          extttnumerids.
owner=true

#          Including the preference -prefer root causes Unison always to
#          resolve conflicts in favor of root, rather than asking for
#          guidance from the user. (The syntax of root is the same as for
#          the root preference, plus the special values newer and older.)
#          This preference is overridden by the preferpartial preference.
#          This preference should be used only if you are sure you know
#          what you are doing!
prefer=newer

#          When this preference is set to true, the textual user interface
#          will print nothing at all, except in the case of errors.
#          Setting silent to true automatically sets the batch preference
#          to true.
silent=true

#          When this flag is set to true, file modification times (but not
#          directory modtimes) are propagated.
times=true
The comments should make the file self-explaining, except for the path directives. If you specify no path directives, then the directories in the root directives will be synchronized. If you specify path directives, then the paths are relative to the root path (e.g. root = /var/www and path = current translates to /var/www/current), and only these subdirectories will be synchronized, not the whole directory specified in the root directive.
You can find out more about the available options by taking a look at Unison's man page:
man unison
Now that we have put all settings in a preferences file (especially the root (and optionally the path) directives), we can run Unison without any arguments:
unison

5 Creating A Cron Job

server1:
We want to automate synchronization, that is why we create a cron job for it on server1.example.com:
crontab -e
*/5 * * * * /usr/bin/unison &> /dev/null
This would run Unison every 5 minutes; adjust it to your needs (see
man 5 crontab
). I use the full path to unison here (/usr/bin/unison) just to go sure that cron knows where to find unison. Your unison location might differ. Run
which unison
to find out where yours is.

6 Links

Lan Management System (LMS) On Debian Squeeze


LMS (Lan Management System) is a good system for small ISPs made in Poland. Documentation for LMS GUI is available in english here. But installation, configuration and integration with firewall or traffic shaping mechanisms could take a lot of time. Here you can try my scripts for express-installation of LMS. The scripts were tested in several companies.
First download and install Debian Squeeze in netinstall version i386 or amd64. Install it with basic system only (no X GUI, no services except ssh). Choose eth0for your primary interface and configure network settings (IP address, netmask, gateway and DNS servers). Make sure you have a second interface described aseth1. Next log into your root account (via ssh by PuTTY or directly on the console) and type the magic three lines for i386 architecture:
wget http://files.v-smart.pl/v-smart-2.0/install-vsmart-2.0-en-32bit.sh
chmod +x install-vsmart-2.0-en-32bit.sh
./install-vsmart-2.0-en-32bit.sh
and for amd64 architecture:
wget http://files.v-smart.pl/v-smart-2.0/install-vsmart-2.0-en-64bit.sh
chmod +x install-vsmart-2.0-en-64bit.sh
./install-vsmart-2.0-en-64bit.sh
The scripts will download necessary packages from debian repositories and my deb packages:
  • linux kernel 2.6.32 with patches: layer-7, imq, esfq
  • iptables 1.4.8 with patches: layer-7 and imq
  • iproute 20101221 with esfq patch
  • ppp 2.4.3 with mppe and mppc
  • pppoe 3.10 with mppe, mppc and kernel plugin
  • pptpd 1.3.4 with mppe and mppc
All the packages are available for independent download from:
You may view the scripts before executing to see what they exactly do. You have to write down the MySQL root password and type it when the install script ask for. After reboot you can go to the router GUI via browser. Simply open the router IP address in the browser. First time LMS will ask you for creating an admin account. Don't forget to check full access option for admin. Example configuration is available for view after installation. You have to set up your WAN bandwidth in the /router/router.conf file in kilobits-per-second. Default is 10Mbps.
How does it work? Network administrator adds clients, computers and tariffs (download and upload speed) into LMS. There is my daemon running in the background which checks if something was changed in the GUI configuration. If so, the daemon will update the configuration file for the firewall (/router/lms.conf) and reload firewall, NAT and traffic shaping. Firewall scripts and configs are in the /router directory. LMS GUI is installed in the /var/www directory. Other stuff (messages, daemon, etc.) are in /var/v-smart directory. Network configuration you can find in /etc/rc.local script.
Installed LMS is pure and unmodified. In the database there is vsmart table with to-do records that are read by the daemon in 3-second period. I added MySQL triggers to follow changes in the LMS tables. The triggers will update to-do records when something is changed in customers' devices configuration. Then the daemon makes a decision about reloading firewall, traffic shaper and NAT. Finally - changes in LMS GUI are set in the router almost instantly. This is the main idea of my project.
In the crontab there are periodicaly run some LMS scripts (stats, payments, host alive checking and other). Feel free to view or adjust /etc/cron.d/vsmart file.
List of router main functions:
- Dynamic traffic shaping on WAN port using IMQ with HTB/esfq and service priority,
- Static traffic shaping on LAN port (LMS tariffs),
- MAC + IP authorization for clients,
- DHCP server,
- DNS server,
- PPPoE server,
- PPtP server (Windows VPN),
- Messages: payment reminder, total block, no authorization,
- LMS GUI - see manual,
- LMS functions: customers, computers, networks, network devices, network map, tariffs, invoices, helpdesk, calendar,
- LMS USERPANEL - access via http://router_ip/userpanel,
- Night tarrifs for LAN and WAN,
- Port forward (/router/forward.conf)
- local speedtest in http://router_ip/freemeter taken from http://speed-meter.net
Technical solutions
1. How to add new network(s) to my LAN?
Let us consider new LAN network: 192.168.102.0/24 with 192.168.102.254 gateway address on the eth1 interface. In LMS GUI (IP Networks -> New network) we add:
  • Network name: LAN2
  • Network addres/mask: 192.168.102.0 / 24 (256-addresses)
  • Interface: eth1
  • Gateway: 192.168.102.254
  • DNS servers: 192.168.102.254, 8.8.8.8
In the file /etc/rc.local we add before /usr/sbin/ip link set eth1 up:
/usr/sbin/ip a a 192.168.102.254/24 brd 192.168.102.255 dev eth1
In the file /etc/rc.local we add on the bottom:
/usr/sbin/pppoe-server -I eth1 -L 192.168.102.254 -N 1000 -k
In the file /router/router.conf we add  variable with value:
INTNET2=192.168.102.0/24
In the file /router/scripts/firewall.sh and /router/scripts/nat.sh we find all lines that include $INTNET1 variable and we copy them bellow changing $INTNET1 for $INTNET2. For example:
$IPTABLES -A INPUT -s $INTNET1 -m state --state NEW -p tcp --sport 1024: --dport 53 -j ACCEPT
$IPTABLES -A INPUT -s $INTNET2 -m state --state NEW -p udp --sport 1024: --dport 53 -j ACCEPT
etc.. 
Tip: If you want to use public subnet on LAN you have to comment MASQUERADE for this subnet in /router/scripts/nat.sh:
#$IPTABLES -t nat -A POSTROUTING -s $INTNET2 -o $EXTDEV -j MASQUERADE
After reboot everything should work fine.