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.
![]() | English documentation can be found here. |
Aby skorzystać z ipt_account konieczne jest pobranie następujących plików:
łatka na patch-o-matic-ng (ipt_account-patch-o-matic-ng.diff)
łatka na iptables (ipt_account-iptables.diff)
patch-o-matic-ng(patch-o-matic-ng-20040621.tar.bz2)
źródła iptables (iptables-1.2.11.tar.bz2)
![]() | 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. |
![]() | 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 accountAkceptujemy 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 menuconfigZ 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 ..
![]() | 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.
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# iptables -A INPUT -p tcp --dport 80 -m account --aaddr 192.168.0.0/16 --aname myserver --ashort
# iptables -A OUTPUT -p tcp --dport 80 -m account --aaddr 192.168.0.0/16 --aname myserver --ashort
![]()



![]() | 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
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
| Kolumna | Znaczenie |
|---|---|
| ip | adres 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:
|
| packets_src | statystyki wysłanych pakietów przez komputer o danym IP. Znaczenie poszczególnych liczb jak powyżej. |
| bytes_dest | statystyki odebranych bajtów przez komputer o danym IP. Znaczenie poszczególnych liczb jak powyżej. |
| packets_dest | statystyki odebranych pakietów przez komputer o danym IP. Znaczenie poszczególnych liczb jak powyżej. |
| time | czas ostatniej modyfikacji wiersza w sekundach |
![]() | 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 ... |
![]() | Pierwszy wiersz (z adresem sieci) zawiera sumę statystyk z całej tabeli. |
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.
![]() | 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 |
![]() | 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
![]() | Należy ładować liczniki wiersz-po-wierszu. Wykonanie # cat myserver.save > /proc/net/ipt_account/myserverzakończy się niepowodzeniem. |
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
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
![]() | 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
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)'
![]() | 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>
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.
![]() | 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.
![]() | Dużą zaletą powyższego rozwiązania jest generowane wykresów ruchu jedynie na żądanie. |
![]() | Skrypty przedstawione w niniejszym rozdziale można znaleźć tutaj. |