Moduł ipt_account

Wersja 0.1.6

Piotr Gasidło

Każdy administrator wcześniej czy później stanie przed problemem sporządzenia statystyk ruchu dla sieci, którą administruje. Netfilter umożliwia w łatwy sposób tworzenie statystyk poprzez zastosowanie pustych (czyli nie posiadających celu) regułek, zliczających jedynie ruch z/do określonego IP. O ile rozwiązanie takie sprawdza się dla małych sieci, to w przypadku dużych, posiadających więcej niż kilkanaście hostów, rozwiązanie polegające na wpisywaniu kilkuset regułek jest dalekie od efektywności i przejrzystości. W tym celu powstał moduł ipt_account, umożliwiający przy pomocy zaledwie jednego wpisu gromadzić statatystyki dla całych sieci jednocześnie zapewniając łatwy do nich dostęp poprzez system plików procfs. Niniejsze opracowanie opisuje krok po kroku instalację, konfigurację i ostateczne zastosowanie przy generacji graficznych statystyk z wykorzystaniem modułu ipt_account.

Podpowiedź

English documentation can be found here.


Spis treści
1. Instalacja
1.1. Pobieranie plików
1.2. Kompilacja i instalacja
2. Zastoswanie
2.1. Dodawanie regułek
2.2. Przeglądanie statystyk
2.3. Zapisywanie i ładowanie liczników
3. Praktyczny przykład
Spis tabel
2-1. Zawartość pliku ze statystykami
Spis rysunków
3-1. Statystyki ruchu
3-2. Wykresy ruchu
Spis przykładów
2-1. Tworzenie regułek
2-2. Przeglądanie statystyk
2-3. Modyfikowanie liczników
2-4. Zapisywanie liczników
2-5. Ładowanie liczników
3-1. firewall.sh
3-2. rrdtool-create.sh
3-3. rrdtool-update.sh
3-4. rrdtool-graph.sh
3-5. Modyfikacja /etc/crontab
3-6. index.php
3-7. statistics.php

Rozdział 1. Instalacja

1.1. Pobieranie plików

Aby skorzystać z ipt_account konieczne jest pobranie następujących plików:

Notatka

Korzystając z CVS można pobrać patch-o-matic i iptables z najnowszą wersją ipt_account. W takim przypadku nakładanie powyższych łat jest zbyteczne.


1.2. Kompilacja i instalacja

Notatka

Niniejszy rozdział zawiera informacje jak krok-po-kroku przekompilować i zainstalować kernel i iptables obsługujące ipt_account. Komendy dotyczą instalacji ipt_account na jądrze w wersji 2.6.7. Instalacja modułu na innych jądrach (w szczególności gałęzi 2.4.x) może lekko się różnić.

W katalogu, w którym umieśliślmy ściągnięte w poprzednim rozdziale pliki należy wykonać kolejno poniższe polecenia:

# tar xvfj patch-o-matic-ng-20040621.tar.bz2
# cd patch-o-matic-ng*
# cat ../ipt_account-patch-o-matic-ng.diff | patch -p1
# cd ..
# tar xvfj iptables-1.2.11.tar.bz2
# tar xvfj linux-2.6.7.tar.bz2
# export KERNEL_DIR=`pwd`/linux-2.6.7
# export IPTABLES_DIR=`pwd`/iptables-1.2.11
# cd patch-o-matic-ng
# ./runme account
			
Akceptujemy instalacje ipt_account poprzez naciśnięcie y i zatwierdzenie klawiszem Enter.

Następnie przechodzimy do kompilacji jądra.

# cd linux-2.6.7
# make menuconfig
			
Z menu wybieramy kolejno:
Device Drivers  --->
  Networking support  --->
    Networking options  --->
      [*] Network packet filtering (replaces ipchains)  --->
        IP: Netfilter Configuration  --->
          <M> account match support
          [ ]   account debugging output        
			
Opcję account debugging output należy pozostawić niezaznaczoną (włącza ona generowanie nadmiarowych informacji potrzebnych jedynie przy odpluskwianiu modułu).

Po skonfigurowania jądra przechodzimy do jego kompilacji.

# make
# cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.7
# cp System.map /boot/System.map-2.6.7
# cd ..
			

WAŻNE

Po zainstalowaniu kernela należy odpowiednio zmodyfikować konfigurację bootladera (LILO lub GRUB).

Ostatecznie pozostaje nam już kompilacja i instalacja iptables. Moduły zostaną zainstalowane do /lib/iptables.

# cd iptables-1.2.11
# cat ../ipt-account-iptables.diff | patch -p1
# chmod +x extensions/.account-test
# make install KERNEL_DIR=../linux-2.6.7 PREFIX=
# cd ..
			
Na samym końcu restartujemy system i w bootloaderze wybieramy nowo skompilowane jądro z obsługą ipt_account.


Rozdział 2. Zastoswanie

2.1. Dodawanie regułek

W pierwszej kolejności należy stworzyć odpowiednie regułki zliczające ruch. Przyjmijmy, że chcemy gromadzić statystki ruchu dla sieci 192.168.0.0/16 przechodzącego przez router oraz statystyki dla 192.168.0.0/16 ruchu do/z serwera WWW umieszczonego na tymże routerze.

W tym celu wydajemy następujące polecenia:

Przykład 2-1. Tworzenie regułek

# iptables -A FORWARD -m account --aaddr 192.168.0.0/16 --aname mynetwork (1)
# iptables -A INPUT -p tcp --dport 80 -m account --aaddr 192.168.0.0/16 --aname myserver --ashort(2)
# iptables -A OUTPUT -p tcp --dport 80 -m account --aaddr 192.168.0.0/16 --aname myserver --ashort(3)
					
(1)
Gromadzenie statystk ruchu dla danych przechodzących przez router do/z komputerów o adresach z sieci 192.168.0.0/16. Statystyki zostaną zapisane do tabeli statystyki. Będą gromadzone szczegółowe statystyki (osobno protokoły TCP/UDP/ICMP/Inne).
(2)
Gromadzenie statystyk ruchu do serwera WWW postawionego na routerze z komputerów o adresach z sieci 192.168.0.0/16. Statystyki zostaną zapisane do tabeli www. Ze względu na użycie opcji --ashort Będą gromadzone skrócone statystyki (tylko całkowity ruchu).
(3)
Gromadzenie statystyk ruchu z serwera WWW postawionego na routerze do komputerów o adresach z sieci 192.168.0.0/16. Statystyki zostaną zapisane do tabeli www. Ponieważ tabela istnieje zostanie wykorzystana ponownie.

WAŻNE

W przypadku gdy chcemy wykorzystać tabelę przez kilka regułek ważne jest aby adres sieci/maska podana po parametrze --aaddr była taka sama dla wszystkich regułek z niej korzystających. W innym przypadku regułka nie zostanie utworzona.

W rezultacie w katalogu /proc/net/ipt_account pojawią się następujące wpisy:

# ls -laR /proc/net/ipt_account/
/proc/net/ipt_account/:
total 0
dr-xr-xr-x    2 root     root            0 Jul 17 19:28 .
dr-xr-xr-x    4 root     root            0 Jul 17 19:28 ..
-rw-r--r--    1 root     root            0 Jul 17 19:28 mynetwork
-rw-r--r--    1 root     root            0 Jul 17 19:28 myserver
			


2.2. Przeglądanie statystyk

Zawartość pliku /proc/net/ipt_account/mynetwork wygląda następująco:

Przykład 2-2. Przeglądanie statystyk

# cat /proc/net/ipt_account/mynetwork
ip = 192.168.0.0 bytes_src = 8009371355 7979197249 25417729 4756377 0 packets_src = 14844174 14600134 186011 58029 0 bytes_dest = 17568766197 17540073337 25092213 3600647 0 packets_dest = 17462235 17236701 182662 42872 0
ip = 192.168.0.1 bytes_src = 702 0 702 0 0 packets_src = 9 0 9 0 0 bytes_dest = 0 0 0 0 0 packets_dest = 0 0 0 0 0
ip = 192.168.0.2 bytes_src = 133164609 133071748 92441 420 0 packets_src = 2548317 2547888 422 7 0 bytes_dest = 7331211760 7331210800 540 420 0 packets_dest = 4928417 4928404 6 7 0
ip = 192.168.0.3 bytes_src = 0 0 0 0 0 packets_src = 0 0 0 0 0 bytes_dest = 0 0 0 0 0 packets_dest = 0 0 0 0 0
ip = 192.168.0.4 bytes_src = 168821 0 168821 0 0 packets_src = 2043 0 2043 0 0 bytes_dest = 180 0 180 0 0 packets_dest = 2 0 2 0 0
ip = 192.168.0.5 bytes_src = 147593 0 147593 0 0 packets_src = 1324 0 1324 0 0 bytes_dest = 0 0 0 0 0 packets_dest = 0 0 0 0 0
...
				

Tabela 2-1. Zawartość pliku ze statystykami

KolumnaZnaczenie
ipadres IP, którego dany wiersz ze statystykami dotyczy
bytes_src statystyki wysłanych bajtów przez komputer o danym IP. Znaczenie poszczególnych liczb jest następujące:

  • wszystkich pakietów,

  • pakietów protokołu TCP,

  • pakietów protokołu UDP,

  • protokołu ICMP,

  • pakietów pozostałych protokołów

packets_srcstatystyki wysłanych pakietów przez komputer o danym IP. Znaczenie poszczególnych liczb jak powyżej.
bytes_deststatystyki odebranych bajtów przez komputer o danym IP. Znaczenie poszczególnych liczb jak powyżej.
packets_deststatystyki odebranych pakietów przez komputer o danym IP. Znaczenie poszczególnych liczb jak powyżej.
timeczas ostatniej modyfikacji wiersza w sekundach

Notatka

W przypadku gdy tablica została stworzona z opcją --ashort wyświetlone zostaną tylko całkowite statystyki ruchu bez podziału na protokoły.

# cat /proc/net/ipt_account/myserver
ip = 192.168.0.0 bytes_src = 12309123 packets_src = 123145 bytes_dest = 3252355 packets_dest = 242132
...
					

Notatka

Pierwszy wiersz (z adresem sieci) zawiera sumę statystyk z całej tabeli.


2.3. Zapisywanie i ładowanie liczników

Moduł umożliwa ustawianie wartości dla poszczególnych liczników. Przykładowo, wydając następujące polecenie:

Przykład 2-3. Modyfikowanie liczników

# echo "ip = 192.168.0.251 bytes_src = 1 2 3 4 5 packets_src = 6 7 8 9 0 bytes_dest = 1 2 3 4 5 packets_dest = 6 7 8 9 0" > /proc/net/ipt_account/mynetwork
				

Powyższą funkcjonalność można wykorzystać w momencie gdy chcemy zrestartować serwer jednocześnie zachowując dotychczasowy stan liczników.

Przykład 2-4. Zapisywanie liczników

# cat /proc/net/ipt_account/myserver > myserver.save
				

WAŻNE

W przypadku tabel stworzonych z parametrem --ashort należy po każdej kategorii (bytes_src, packets_src ...) podać jedną liczbę, a nie pięć.

# echo "ip = 192.168.0.251 bytes_src = 1 packets_src = 2 bytes_dest = 3 packets_dest = 4" > /proc/net/ipt_account/myserver
					

Notatka

Kategoria time (ostatnia w tabeli ze statystykami) jest ignorowana.

Przykład 2-5. Ładowanie liczników

# while read line; do echo $line > /proc/net/ipt_account/myserver; done < myserver.save
				

WAŻNE

Należy ładować liczniki wiersz-po-wierszu. Wykonanie

# cat myserver.save > /proc/net/ipt_account/myserver
					
zakończy się niepowodzeniem.


Rozdział 3. Praktyczny przykład

W rozdziale przedstawiono jak w prosty sposób przy wykorzystaniu ipt_account, serwera Apache z obsługą PHP oraz narzędzia RRDTool stworzyć graficzne statystyki ruchu dostępne za pośrednictwem strony WWW.

Zakładam, że uzytkownik posiada już skonfigurowany serwer Apache z obsługą PHP. Zakładam ponadto, że jądro systyemu oraz narzędzie iptables obsługuje moduł ipt_account.

Naszym celem jest stworzenie statystyk ruchu przechodzącego przez router (na którym zainstalowany jest serwer Apache) dla sieci 192.168.0.0/24.

Na samym początku nalezy poprawnie skonfigurowac firewall. Skrypt firewall.sh tworzy nowy łańcuch użytkownika statistics. Skok do łańcucha jest wykonywany na samym początku łańcucha FORWARD. W nowym łańcuchu przy pomocy ipt_account zliczamy ruch z/do sieci 192.168.0.0/24. Tworzymy krótkie statystyki (bez podziału na protokoły).

Przykład 3-1. firewall.sh

#!/bin/bash

IPTABLES=/sbin/iptables

$IPTABLES -N statistics
$IPTABLES -A statistics -m account --aaddr 192.168.0.0/24 --aname mynetwork --ashort
$IPTABLES -I FORWARD -j statistics
			
Poprawność działania firewalla możemy przetestowac sprawdzając liczniki (iptables -L statistics -vn) oraz sprawdzając istnienie pliku /proc/net/ipt_account/mynetwork.

Następnie nalezy stworzyć bazy RRD oraz przy pomocy CRONa zapewnić ich aktualizację (w naszym przypadku będzie ona wykonywana co 5 minut). Skrypt tworzący bazy nazywa się create-rrdtool.sh. Skrypt należy umieścić w katalogu /var/lib/rrdtool (jeżeli taki katalog nie istnieje należy go utworzyć). Dodatkowo nalezy stworzyc katalog /var/lib/rrdtool/db, w którym będą trzymane bazy danych RRD. Przyjęto, że dla każdego IP zostanie stworzona pojedyńcza baza, w której będą trzymane statystyki w bajtach ruchu wejściowego i wyjściowego.

Przykład 3-2. rrdtool-create.sh

#!/bin/bash

RRDTOOL=/usr/bin/rrdtool
RRDDIR=/var/lib/rrdtool/db

function create_database(){
        rrdtool create $RRDDIR/$1 \
        DS:in:DERIVE:600:0:U \
        DS:out:DERIVE:600:0:U \
        RRA:AVERAGE:0.5:1:600 \
        RRA:AVERAGE:0.5:6:700 \
        RRA:AVERAGE:0.5:24:775 \
        RRA:AVERAGE:0.5:288:797 \
        RRA:MAX:0.5:1:600 \
        RRA:MAX:0.5:6:700 \
        RRA:MAX:0.5:24:775 \
        RRA:MAX:0.5:288:797 \
        RRA:MIN:0.5:1:600 \
        RRA:MIN:0.5:6:700 \
        RRA:MIN:0.5:24:775 \
        RRA:MIN:0.5:288:797 \
        RRA:LAST:0.5:1:600 \
        RRA:LAST:0.5:6:700 \
        RRA:LAST:0.5:24:775 \
        RRA:LAST:0.5:288:797
}

function u_int32_to_ip() {
        ip1=$((($1 >> 24) & 0xff))
        ip2=$((($1 >> 16) & 0xff))
        ip3=$((($1 >> 8) & 0xff))
        ip4=$(($1 & 0xff))
        echo -n "${ip1}.${ip2}.${ip3}.${ip4}"
}

# adres poczatkowy: 192.168.0.0
ip_begin=$((192 << 24 | 168 << 16 | 0 << 8 | 0))
# adres końcowy 192.168.0.255
ip_end=$((192 << 24 | 168<< 16 | 0 << 8 | 255))

for (( ip = ip_begin ; ip <= ip_end ; ip++ )); do
        ip_text=$( u_int32_to_ip ${ip} )
        create_database bits-${ip_text}.rrd
done

exit 0
			
Po wykonaniu powyższych czynności nalezy skrypt uruchomić. W efekcie w katalogu /var/lib/rrdtool/db powinno pojawić się 256 plików o nazwach stats-192.168.0.*.rrd.

WAŻNE

Skrypt należy uruchomić tylko raz. Ponowne uruchomienie skryptu spowoduje skasowanie statystyk zgromadzonych w bazach RRD.

Następnie należy w katalogu /var/lib/rrdtool/ umieścić skrypt rrdtool-update.sh.

Przykład 3-3. rrdtool-update.sh

#!/bin/bash

RRDUPDATE=/usr/bin/rrdupdate
RRDDIR=/var/lib/rrdtool/db

# polozenie pliku ze statystykami
ACCOUNT=/proc/net/ipt_account/mynetwork

# interesują nas wpisy aktualizowane nie przed 5 minutami
TIMEOUT=300

CAT=/bin/cat
AWK=/usr/bin/awk
ECHO=/bin/echo

# 1  2 3             4         5 6 7           8 9 10        111213           141516   1718
# ip = 192.168.0.255 bytes_src = 0 packets_src = 0 bytes_dest = 0 packets_dest = 0 time = 543

$CAT $ACCOUNT | $AWK -v TIMEOUT=$TIMEOUT -v RRDUPDATE=$RRDUPDATE -v RRDDIR=$RRDDIR '{ if (TIMEOUT - $18 > 0) system (RRDUPDATE " " RRDDIR "/bits-" $3 ".rrd" " N:" $6 ":" $12) }'

exit 0
			
Skrypt został tak zaprojektowany, aby aktualizować jedynie bazy dla tych IP, do/z których zarejestrowano ruch (kolumna time w pliku /proc/net/ipt_account/mynetwork ma wartość mniejszą niż 300).

Ostatnim krokiem konfiguracji rrdtool jest stworzenie skryptu generującego wykresy umieszczane na stronach WWW. Skrypt nosi nazwę rrdtool-graph.sh i podobnie jak resztę skryptów należy go umieścić w katalogu /var/lib/rrdtool.

Przykład 3-4. rrdtool-graph.sh

!/bin/bash

RRDTOOL=/usr/bin/rrdtool
RRDDIR=/var/lib/rrdtool/db
IMGDIR=/var/www/images

if [ ! -d $IMGDIR ]
then
        exit 1;
fi

if [ -z $1 ]
then
        exit 1;
fi

if [ ! -e $RRDDIR/bits-$1.rrd ]
then
        exit 1;
fi

RRDDB=$RRDDIR/bits-$1.rrd

create_graph() {
        $RRDTOOL graph $1 --lazy -s $2 -a PNG\
        -v "Bity na sekundę" \
        -r \
        -w 600 -h 300 \
        -l 0 \
        -t "Statystyki obejmujące $3" \
        DEF:out_bytes=${RRDDB}:out:AVERAGE \
        DEF:in_bytes=${RRDDB}:in:AVERAGE \
        CDEF:out_bits=out_bytes,8,* \
        CDEF:in_bits=in_bytes,8,* \
        COMMENT:"                   Maksymalnie      Średnio    Aktualnie\n" \
        AREA:in_bits#00cc00:"Ruch wchodzący " \
        GPRINT:in_bits:MAX:"%6.2lf %sbps" \
        GPRINT:in_bits:AVERAGE:"%6.2lf %sbps" \
        GPRINT:in_bits:LAST:"%6.2lf %sbps\n" \
        LINE1:out_bits#0000ff:"Ruch wychodzący" \
        GPRINT:out_bits:MAX:"%6.2lf %sbps" \
        GPRINT:out_bits:AVERAGE:"%6.2lf %sbps" \
        GPRINT:out_bits:LAST:"%6.2lf %sbps\n" \
        COMMENT:"ostatnia aktualizacja `date`\r"
}

create_graph $IMGDIR/bits-$1-last-day.png -1d 'ostatni dzień (24 godziny/próbkowanie co 5 minut)'
create_graph $IMGDIR/bits-$1-last-week.png -1w 'ostatni tydzień (7 dni/próbkowanie co 30 minut)'
create_graph $IMGDIR/bits-$1-last-month.png -1m 'ostatni miesiąc (4 tygodnie/próbkowanie co 2 godziny)'
create_graph $IMGDIR/bits-$1-last-year.png -1y 'ostatni rok (12 miesięcy/próbkowanie co 2 dni)'
			

WAŻNE

Prawa do tego skryptu powinny umożliwiać jego uruchomienie użytkownikowi, z którego prawami działa serwer Apache.

Skrypt będzie wywoływany przez CRONa. W tym celu nalezy zmodyfikować plik /etc/crontab i dopisać do niego natępującą linię:

Przykład 3-5. Modyfikacja /etc/crontab

*/5 * * * * root /var/lib/rrdtool/rrdtool-update.sh &> /dev/null
			

Kolejnym krokiem jest stworzenie strony WWW wyświetlającej zbiorcze statystyki ruchu. Przykładowa strona index.php została zaprezentowana poniżej.

Przykład 3-6. index.php

<html>
<head>
<title>Statystyki ruchu</title>
<style type="text/css">
	TD { font-family: arial, helvetica, sans-serif; }
</style>
</head>

<body bgcolor=#ffffff>

<?php

// funkcja odpowiedzialna za automatyczne dodawanie sufiksów do liczb
function print_sufix($number, $default = '') {
	switch($default) {
		case 'k':
			echo number_format($number/1024, 2), "k";
			break;
		case 'M':
			echo number_format($number/1024/1024, 2), "M";
			break;
		case 'G':
			echo number_format($number/1024/1024/1024, 2), "G";
			break;
		default:
			$sufix = '';
			if ($number > 1024) {
				$number /= 1024;
				$sufix = 'k';
			};
			if ($number > 1024) {
				$number /= 1024;
				$sufix = 'M';
			};
			if ($number > 1024) {
				$number /= 1024;
				$sufix = 'G';
			}
			echo number_format($number, 2), $sufix;
	}	
}

$statistics_file = "/proc/net/ipt_account/mynetwork";
$bar_width = 200;
$bar_height = 10;

// pobranie statystyk
if (file_exists($statistics_file)) {
	$statistics = file($statistics_file);
	for ($i = 0; $i < count($statistics); $i++) {
		$statistics[$i] = split(" ", $statistics[$i]);
	}
	$total_statistics = $statistics[0];
}

// funkcje sortujące
function cmp_wychodzacy($a, $b) {
	if ($a[5] == $b[5]) return 0;
	else if ($a[5] > $b[5]) return -1;
	else return 1;
}

function cmp_wchodzacy($a, $b) {
	if ($a[11] == $b[11]) return 0;
	else if ($a[11] > $b[11]) return -1;
	else return 1;
}

function cmp_stosunek($a, $b) {
	$sa = $a[5]/($a[11]+$a[5]+1);
	$sb = $b[5]/($b[11]+$b[5]+1);
	if ($sa == $sb) return 0;
	else if ($sa > $sb) return -1;
	else return 1;
}

// sortowanie
switch ($_REQUEST['sortuj']) {
	case 'wychodzacy':
		usort($statistics, 'cmp_wychodzacy');
		break;
	case 'stosunek':
		usort($statistics, 'cmp_stosunek');
		break;
	case 'wchodzacy':
	default:
		usort($statistics, 'cmp_wchodzacy');
}

?>

<center>
<h1>Statystyki ruchu dla komputerów z sieci 192.168.0.0/24</h1>
</center>

<form>
	<table align="center" bgcolor=black cellpadding="4">
		<tr bgcolor="#94ABC0" align=center><td colspan="5"><b>Parametry</b>
		<tr bgcolor="#EDEDED">
			<td>Sortuj według <select name="sortuj">
				<option value="wchodzacy" <?php if ($_REQUEST['sortuj'] == "wchodzacy") print "selected"?>>wchodzący</option>
				<option value="wychodzacy" <?php if ($_REQUEST['sortuj'] == "wychodzacy") print "selected"?>>wychodzący</option>
				<option value="stosunek" <?php if ($_REQUEST['sortuj'] == "stosunek") print "selected"?>>stosunek wychodzący : wchodzący
			</select>
			<td>Jednostki <select name="jednostki">
				<option value="">automatycznie</option>
				<option value="k" <?php if ($_REQUEST['jednostki'] == "k") print "selected"?>>kB</option>
				<option value="M" <?php if ($_REQUEST['jednostki'] == "M") print "selected"?>>MB</option>
				<option value="G" <?php if ($_REQUEST['jednostki'] == "G") print "selected"?>>GB</option>
			</select>
			<td><input type=submit value="OK!">
	</table>
</form>

<table align=center bgcolor=black cellpadding="4">
<tr bgcolor="#94ABC0" align=center><td><b>Pozycja</b><td><b>Komputer</b><td colspan=5><b>Statystyki ruchu</b>

<?php

$color = '#FFFFFF';

for ($i = 0, $pozycja = 0; $i < count($statistics); $i++) {
	if ($statistics[$i][5] > 0 && $statistics[$i][11] > 0) {
		if ($color == '#FFFFFF')
			$color = '#EDEDED';
		else
			$color = '#FFFFFF';
		echo '<tr bgcolor=',$color,'><td align=center rowspan=2>', ++$pozycja;

		if ($statistics[$i][2] != "192.168.0.0")
			echo '<td align=center rowspan=2>', $statistics[$i][2], '<br>(',gethostbyaddr($statistics[$i][2]),')';
		else
			echo '<td align=center rowspan=2>Wszystkie komputery';
		echo 
			'<td><img src="bar_green.png" height="',$bar_height,'" width="', (float)$statistics[$i][11]/(float)($total_statistics[11] + 1) * $bar_width, '"><td align=right>',print_sufix($statistics[$i][11],$_REQUEST['jednostki']), '<td align=right>[', number_format((float)$statistics[$i][11]/(float)($total_statistics[11] + 1) * 100, 2), '%]<td rowspan=2 align=center><img src="bar_green.png" height="',$bar_height,'" width="', (float)$statistics[$i][11]/(float)($statistics[$i][11] + $statistics[$i][5] + 1) * $bar_width, '"><img src="bar_blue.png" height="',$bar_height,'" width="', (float)$statistics[$i][5]/(float)($statistics[$i][11] + $statistics[$i][5] + 1) * $bar_width, '"><br>[',number_format((float)100 * $statistics[$i][11]/(float)($statistics[$i][11] + $statistics[$i][5] + 1),2),'% : ',number_format((float)100 * $statistics[$i][5]/(float)($statistics[$i][5] + $statistics[$i][11] + 1),2),'%]','<td rowspan=2><a href="statistics.php?host=',$statistics[$i][2],'">Wykres</a>',
			'<tr bgcolor=',$color,'><td><img src="bar_blue.png" height="',$bar_height,'" width="', (float)$statistics[$i][5]/(float)($total_statistics[5] + 1) * $bar_width, '"><td align=right>',print_sufix($statistics[$i][5],$_REQUEST['jednostki']), '<td align=right>[', number_format((float)$statistics[$i][5]/(float)($total_statistics[5] + 1) * 100, 2), '%]';
		echo "\n";
	}
}

echo '</table>', "\n";

?>

<br><br>
<table align=center>
<tr><td colspan=2 bgcolor="#94ABC0" align=center><b>Legenda</b></tr>
<tr><td align=center><img src="bar_green.png" height="10" width="30"><td align=left>ruch wchodziący</tr>
<tr><td align=center><img src="bar_blue.png" height="10" width="30"><td align=left>ruch wychodzący</tr>
</table>

</html>
</body>	
			
Stronę (wraz z obrazkami niebieski.png i zielony.png) należy umieścić w katalogu udostępnianym przez serwer WWW (przykładowo /var/www).

Następnie należy stworzyć skrypt statistics.php. Skrypt powinien być umieszczony w tym samym miejscu co index.php.

Przykład 3-7. statistics.php

<html>
<head>
<title>Statsystyki komputera</title>
<body>

	<center>
	<h1>Statystyki komputera <? print $_REQUEST['host'] ?></h1>
<?	
	system("/var/lib/rrdtool/rrdtool-graph.sh " . escapeshellarg($_REQUEST['host']) . " &> /dev/null");
	foreach(array("day", "week", "month", "year") as $czas) {
?>
	<p><img src="images/<?print "bits-$_REQUEST[host]-last-$czas.png" ?>">
<?
	}
?>	
	</center>

</body>
</html>
			

Ostatnim krokiem jest stworzenie w katalogu ze skryptami katalogu images.

WAŻNE

Należy pamiętać, aby nadać katalogowi prawa umożliwiające uzytkownikowi z jakim działa serwer WWW (np. www-data) swobodny zapis do tego katalogu.

To wszystko. W rezultacie otwierając stronę pod którą znajduje się skrypt index.php przeglądarka powinna wyświetlić stronę z wygenerowanymi statystykami. Wybierając odnośniki po prawej stronie każdego adresu uzyskamy szczegółowe dzienne, tygodniowe, miesięczne i roczne wykresy ruchu dla każdego IP.

Rysunek 3-1. Statystyki ruchu

Rysunek 3-2. Wykresy ruchu

Notatka

Dużą zaletą powyższego rozwiązania jest generowane wykresów ruchu jedynie na żądanie.

Notatka

Skrypty przedstawione w niniejszym rozdziale można znaleźć tutaj.