OpenWRT w pigułce (konfiguracja w oparciu o TL-WR1043ND oraz Archer C7)

Spis treści:
0. Zmiana firmware

  1. Dostęp do routera
    1.1 SSH (/etc/config/dropbear)
    1.2 SSHFS
    1.3 Tryb failsafe
    1.4 Firstboot

  2. Menadżer pakietów (opkg)

  3. Narzędzie sysupgrade
    3.1 Backup konfiguracji
    3.2 Aktualizacja firmware
    3.3 Przywracanie oryginalnego firmware

  4. Skrypty startowe

  5. Konfiguracja systemu routera (/etc/config/system)
    5.1 Nazwa hosta
    5.2 Strefa czasowa i czas na routerze
    5.3 Czas sieciowy
    5.4 Logi systemowe
    5.5 LEDy

  6. Konfiguracja przycisków

  7. Konfiguracja interfejsów sieciowych (/etc/config/network)
    7.1 Interfejs lo
    7.2 Interfejs lan
    7.3 Interfejs wan
    7.4 Spoofowanie (klonowanie) adresów MAC
    7.5 Switch i VLANy

  8. Konfiguracja dnsmasq (/etc/config/dhcp)
    8.1 DNS
    8.2 DHCP
    8.3 Statyczne lease DHCP

  9. Konfiguracja WiFi (/etc/config/wireless)
    9.1 RADIO
    9.1.1 Pasmo 2,4GHz
    9.1.1.1 Szerokość kanałów
    9.1.1.2 Kanały 12 i 13
    9.1.2 Pasmo 5 GHz
    9.1.2.1 Szerokość kanałów
    9.1.2.2 Dostępne kanały
    9.1.3 Moc transmisyjna

    9.2 Tryb AP
    9.2.1 WPA2 Personal
    9.2.2 WPA2 Enterprise
    9.2.3 Ukrycie sieci
    9.2.3 Filtrowanie adresów MAC
    9.2.4 WPS
    9.3 Tryb STA
    9.4 Tryb MONITOR
    9.5 Tryb WDS (most bezprzewodowy)

  10. Nośniki wymienne (/etc/config/fstab)
    10.1 Partycjonowanie dysku i tworzenie systemu plików
    10.2 Block-mount
    10.3 Dyski/Pendrive
    10.4 Extroot/Fullroot
    10.5 SWAP
    10.6 Partycja /dev/mtdblock3
    10.7 Katalog /tmp/

  11. Filtr pakietów sieciowych (/etc/config/firewall)
    11.1 Własny filtr iptables
    11.2 Ustawianie odpowiedniego TTL dla pakietów

  12. Dodatkowe usługi
    12.1 Serwer wydruku (/etc/config/p910nd)
    12.2 Wake-On-LAN (/etc/config/etherwake)
    12.3 NFS
    12.4 FTP
    12.5 Statystyki
    13 QoS (Quality of Service)

OpenWRT to dość złożony system, mimo, że zajmuje 8-16MiB. W porównaniu do windowsa jest to naprawdę niewiele. Niemniej jednak, by robić pewne niestandardowe rzeczy, trzeba dysponować określoną wiedzą by komfortowo operować na OpenWRT.
Przede wszystkim przydałoby się opanować obsługę edytora vi. Nie jest on znowu aż tak skomplikowany jak się może wydawać z początku -- wystarczy go zacząć używać, a parę dni później człowiek sam się nauczy z niego korzystać.

Druga sprawa to umiejętność używania terminala -- to przy jego pomocy będziemy się logować to routera i przy tym znikną wszelkie panele webowe. Oczywiście nic nie stoi na przeszkodzie by doinstalować sobie odpowiednie skrypty i zarządzać routerem z poziomu GUI przez www. Ja jednak nie będę poruszał tych tematów i skupię się tylko na opisaniu konfiguracji przy pomocy czystej konsoli, bo to wcale nie jest takie trudne, wymaga tylko uzupełnienia wiadomości i chęci poznania nowych rzeczy, a zwłaszcza tego jak działają systemy i sieci komputerowe.

W OpenWRT jest mechanizm konfiguracyjny zwany Unified Configuration Interface , w skrócie UCI, to przy jego udziale jest konfigurowana większość usług systemowych. Ja jednak nigdy z tego całego UCI nie korzystałem -- wolę zwykłą edycję plików tekstowych, na których się UCI opiera. Dlatego też w swoich howto nie będę używał UCI i zamiast niego skupię się na edycji plików.

Dobrze jest także poznać filtr pakietów iptables oraz zaznajomić się z jego modułami, może nie wszystkie trzeba od razu znać na pamięć ale przydałoby się prześledzić je i wiedzieć miej więcej do czego można owe moduły zastosować. Sporo informacji na temat samego iptables można znaleźć na http://pl.wikibooks.org/wiki/Sieci_w_Linuksie/Netfilter/iptables oraz w dokumentacji pod adresem http://www.iptables.info/ . Z kolei lista dodatkowych modułów jest przystępnie opisana na http://ipset.netfilter.org/iptables-extensions.man.html

OpenWRT w dużej mierze przypomina linuxa i szereg poleceń jest w tych dwóch systemach taki sam. Jedynie co, to z powodu dość ograniczonego miejsca, większość programów w OpenWRT została okrojona dość solidnie, zostawiając przy tym tylko niezbędną funkcjonalność. Pod tym linkiem znajduje się dobra rozpiska podstawowych poleceń linuxowych . Część z nich nie będzie działać z powyżej opisanego powodu i jeśli nie wiemy jaką funkcjonalnością dysponuje dany program, zawsze możemy skorzystać z pomocy wpisując w terminalu nazwę programu i parametr --help (ewentualnie -h).

0. Zmiana firmware

Przed przystąpieniem do jakichkolwiek prac, musimy się upewnić, że router, który posiadamy, jest obsługiwany przez firmware OpenWRT. Lista dostępnych urządzeń znajduje się pod tym linkiem: http://wiki.openwrt.org/toh/start#tp-link . Ten tutorial jest pisany w oparciu o dwa routery -- TL-WR1043N/ND v2.1 oraz o Archer C7 v2.0 . Trzeba dobrze czytać adnotacje, bo nie zawsze dany router jest obsługiwany przez ten otwarty firmware w pełni. Z powyższymi modelami nie powinno być większego kłopotu.

Obrazy z firmware możemy pobrać z kilku źródeł. Pierwszym z nich jest oczywiście oficjalna strona OpenWRT: https://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/ . Domyślne obrazy nie posiadają standardowo pewnych pakietów, a to przeszkadza części społeczności, dlatego też sporo osób buduje sobie nieco zmienione obrazy i czasem też są one udostępniane szerszemu gronu odbiorców. Jednym z miejsc gdzie można spotkać zmodyfikowane wersje OpenWRT, to http://dl.eko.one.pl/barrier_breaker/ar71xx/ i ja z tych obrazów korzystałem podczas pisania tego artykułu.

Upgrade firmware nie powinien być przeprowadzany za pośrednictwem WiFi, dlatego też powinniśmy podpiąć się pod router przewodowo i jeśli upewniliśmy się już, że nasz router jest wspierany, pobieramy plik obrazu zawierający w nazwie factory , np. openwrt-ar71xx-generic-archer-c7-v2-squashfs-factory.bin , po czym przechodzimy do panelu www routera (adres 192.168.0.1) i wgrywamy firmware:

I po chwili operacja powinna zakończyć się powodzeniem:

Po zakończeniu powyższego procesu, restartujemy router (via przycisk zasilania). Restartujemy także połączenie sieciowe na komputerze podłączonym do routera:

root:~# /etc/init.d/networking stop
root:~# /etc/init.d/networking start
Configuring network interfaces...Internet Systems Consortium DHCP Client 4.3.1
Copyright 2004-2014 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/
Listening on LPF/bond0/3c:4a:92:00:4c:5b
Sending on   LPF/bond0/3c:4a:92:00:4c:5b
Sending on   Socket/fallback
DHCPDISCOVER on bond0 to 255.255.255.255 port 67 interval 7
DHCPDISCOVER on bond0 to 255.255.255.255 port 67 interval 8
DHCPREQUEST on bond0 to 255.255.255.255 port 67
DHCPOFFER from 192.168.1.1
DHCPACK from 192.168.1.1
bound to 192.168.1.185 -- renewal in 18374 seconds.

I jak widzimy powyżej, hostowi został przydzielony adres IP via DHCP, zatem wgranie firmware OpenWRT zakończyło się powodzeniem.

2. Menadżer pakietów (opkg)

W OpenWRT do zarządzania pakietami wykorzystywane jest narzędzie opkg. To przy jego pomocy instalujemy, usuwamy i robimy wszelkie inne rzeczy dotyczące operacji na pakietach. Jedyny problem z opkg jest taki, że jego wyjście prezentowane na konsoli, np. przy przeszukiwaniu pakietów, jest dość nieczytelne. By poprawić nieco przejrzystość, tak by np. nazwy pakietów odróżniały się nieco od ich opisów, możemy dodać poniższy blok kodu do /etc/profile :

# Written by Gordio <me@gordio.pp.ua>
# Licence: MIT
opkg () {
	BOLD=$(echo -e '\033[1m');
	NORM=$(echo -e '\033[0m');
	COL="no";
	for arg in $*; do
		if [ $arg == "whatdepends" -o $arg == "list" \
		-o $arg == "list-installed" -o $arg == "list-upgradable" \
		-o $arg == "list-changed-conffiles" -o $arg == "status" \
		-o $arg == "info" -o $arg == "find" ]; then
			COL="yes";
			break;
		fi
	done
	if [ $COL == "yes" ]; then
		# (|\t*) added for 'whatdepends'
		/bin/opkg $* | sed -re "s/^(|\t*)[a-z0-9-]*/$BOLD&$NORM/g";
	else
		/bin/opkg $*;
	fi
}
# vim: set fdm=marker ts=4 sw=4 tw=80 fo-=t ff=unix:

By zmiany weszły w życie, musimy się, albo przelogować, albo wpisać w terminalu poniższe polecenie:

# source /etc/profile

Od tego momentu konsola powinna być nieco bardziej czytelna:

Jednym z najczęściej wydawanych poleceń jakie będziemy wpisywać w ekranie terminala na routerze, to:

# opkg update

Pobiera ono listy pakietów ze zdefiniowanych repozytoriów, a te są umieszczone w pliku /etc/opkg.conf , przykładowo:

src/gz barrier_breaker_base http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/base
src/gz barrier_breaker_luci http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/luci
src/gz barrier_breaker_management http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/management
src/gz barrier_breaker_oldpackages http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/oldpackages
src/gz barrier_breaker_packages http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/packages
src/gz barrier_breaker_routing http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/routing
src/gz barrier_breaker_telephony http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/packages/telephony
src/gz eko1 http://dl.eko.one.pl/barrier_breaker/ar71xx/packages

Pobrane listy pakietów znajdują się w /tmp/opkg-lists/ i jako, że jest to katalog tymczasowy i do tego trzymany w pamięci RAM, a nie na flashu routera, będzie on czyszczony po każdym zresetowaniu urządzenia. Dlatego też po załadowaniu się do systemu, będziemy musieli pobierać listy pakietów praktycznie bez przerwy.
Jeśli dokonujemy zmian w pliku /etc/opkg.conf , przed dokonaniem opkg update dobrze jest usunąć zawartość katalogu /tmp/opkg-lists/ przy pomocy poniższego polecenia:

# rm /tmp/opkg-lists/*

W przypadku gdy chcemy odnaleźć interesujące nas pakiety ale nie mamy pojęcia pod jakimi nazwami one figurują w repozytoriach, możemy przeszukać listy pod względem dopasowań przy pomocy opkg list , przekierowując przy tym wyjście do narzędzia grep
:
# opkg list | grep iptables

Możemy także przeszukać te pakiety, które mamy zainstalowane już w systemie:

# opkg list-installed | grep iptables

By zainstalować pakiet z repozytorium, po pobraniu listy pakietów, wpisujemy:

# opkg install iptables

Możemy wpisać szereg pakietów jeden za drugim oddzielając je od siebie spacją.
Jeśli chcemy sprawdzić jakie pliki dany pakiet wgrał na router, wpisujemy:

# opkg files iptables
Package iptables (1.4.21-1) is installed on root and has the following files:
/usr/sbin/xtables-multi
/usr/sbin/iptables-save
/usr/sbin/iptables-restore
/usr/sbin/iptables

By usunąć pakiet z systemu, korzystamy z:

# opkg remove iptables

Czasami pewne pakiety do prawidłowego działania wymagają innych pakietów i te ostatnie są pociągane do instalacji jako zależności. Gdy w późniejszym czasie zachodzi potrzeba usunięcia tego głównego pakietu, przydałoby się także usunąć jego zależności by nie zajmowały jakże potrzebnego nam miejsca. Możemy to osiągnąć przez wydanie poniższego polecenia:

# opkg --autoremove remove iptables

Narzędzie opkg potrafi także aktualizować pakiety, tylko z tą opcją trzeba uważać, bo nie zawsze wszystkie pakiety nadają się do aktualizacji, szczególnie te zawierające moduły kernela, bo mogą przy tym powiesić router. I tu taka uwaga jeszcze -- nie należy mieszać modułów kernela, które są dostępne w różnych repozytoriach, tj. jeśli dwa osobne moduły występują każdy w innym repo, nie powinniśmy instalować ich obu. Poza tym, trzeba także mieć na względzie to, że każdy zaktualizowany pakiet będzie zajmował dwa razy tyle miejsca na nośniku -- bazowy system OpenWRT jest tylko do odczytu i nie można w nim wprowadzać zmian. Dlatego też, zamiast aktualizacji pakietów, zaleca się wgranie nowszej wersji firmware.

W każdym razie, listę pakietów, których nowsze wersje znajdują się w repo możemy sprawdzić przez:

# opkg list-upgradable
openssl-util - 1.0.1i-1 - 1.0.1j-1
base-files - 156-r42742 - 156-r42943
hostapd-utils - 2014-06-03-1 - 2014-06-03.1-1
odhcp6c - 2014-09-27-3e52a1448eee0fbf7ff67c123265bedcbc9c26d0 - 2014-10-12-c52296c48abe2025abab03cea98f52a654b92ee2
wpad - 2014-06-03-1 - 2014-06-03.1-1
libopenssl - 1.0.1i-1 - 1.0.1j-1

Pakiety aktualizujemy w poniższy sposób:

# opkg upgrade wpad hostapd-utils

W przypadku gdy przeprowadzamy wiele zmian w konfiguracji routera, czasami możemy zapomnieć o pewnych plikach, w których to dokonaliśmy jakichś tam zmian. Narzędzie opkg może w oparciu o sumy kontrolne wylistować nam wszystkie pliki, które zmienialiśmy, przykładowo:

# opkg list-changed-conffiles
/etc/group
/etc/passwd
/etc/shadow
/etc/profile
/etc/sysctl.conf
/etc/rc.local
/etc/sysupgrade.conf
/etc/config/system
/etc/collectd.conf
/etc/config/dnscrypt-proxy
/etc/config/dhcp
/etc/dropbear/dropbear_rsa_host_key
/etc/dropbear/dropbear_dss_host_key
/etc/config/dropbear
/etc/config/etherwake
/etc/config/firewall
/etc/firewall.user
/etc/freeradius2/clients.conf
/etc/freeradius2/radiusd.conf
/etc/freeradius2/sites/default
/etc/freeradius2/eap.conf
/etc/freeradius2/users
/etc/freeradius2/modules/logintime
/etc/freeradius2/sql.conf
/etc/exports
/etc/ssl/openssl.cnf
/etc/opkg.conf
/etc/config/p910nd
/etc/syslog-ng.conf
/etc/tor/torrc
/etc/config/uhttpd
/etc/vsftpd.conf

Oczywiście na powyższej liście nie ma plików, które sami stworzyliśmy.

3. Narzędzie sysupgrade

3.1 Backup konfiguracji

Te powyższe pliki przydałoby się uwzględnić w konfiguracji narzędzia sysupgrade , które to tworzy backup plików konfiguracyjnych w oparciu o wpisy w pliku /etc/sysupgrade.conf .

Definiujemy w nim kolejno jeden pod drugim pliki i katalogi, których backup chcemy utworzyć. Na ich podstawie zostanie stworzona paczka tar.gz , która może posłużyć do przywracania konfiguracji, np po ponownym flashowaniu routera. Jeśli chcemy dokonać backupu całej konfiguracji routera, możemy skorzystać z parametru -c . By stworzyć taką paczkę, wydajemy poniższe polecenie:

# sysupgrade -c -b config.tar.gz
Saving config files...

Tak stworzony backup, kopiujemy przy pomocy scp z routera na dysk lokalny.
By odtworzyć konfigurację, wgrywamy pierw plik wcześniej utworzonego backupu przez scp na router, po czym wydajemy poniższe polecenie:

# sysupgrade -r config.tar.gz
Saving config files...

3.2 Aktualizacja firmware

Przy pomocy narzędzia sysupgrade możemy także przeprowadzać aktualizację firmware do nowszej wersji. Ja przy każdej aktualizacji zawsze zgrywam sobie konfigurację routera przed i po flashowaniu. Po co to? Po wypakowaniu tych dwóch paczek, mogę porównać oba katalogi przy pomocy narzędzia meld -- listuje ono zmiany w plikach/katalogach i na podstawie tych zmian mogę stwierdzić, czy utworzony przeze mnie backup nadaje się do wgrania na router. W przypadku gdy nowsza wersja firmware wprowadziła jakieś zmiany w konfiguracji, mogę zwyczajnie przenieść je do swoich plików, tak by nie nadpisać zmian wprowadzonych przeze mnie i po zakończeniu stworzyć nową paczkę i to ją wgrać na router.

By zaktualizować firmware OpenWRT do nowszej wersji, pobieramy plik, który ma w nazwie sysupgrade , np. openwrt-ar71xx-generic-archer-c7-v2-squashfs-sysupgrade.bin i wgrywamy go przy pomocy scp na router do katalogu /tmp/ , np. pod nazwą obraz.bin . Jeśli byśmy próbowali zapisać ten plik na flashu routera, może nam braknąć miejsca, dlatego wgrywamy go do katalogu /tmp/ , bo jest on zamontowany w pamięci operacyjnej, której zwykle mamy więcej. Mając już wgrany obraz na router, wydajemy jedno z tych dwóch poniższych poleceń:

# sysupgrade -n /tmp/obraz.bin
# sysupgrade /tmp/obraz.bin

Różnią się one jedynie opcją -n , która, jeśli użyta, wyczyści całą konfigurację routera przy wgrywaniu nowego firmware. Gdy dokonujemy aktualizacji z dość starej wersji firmware, nie zaleca się zachowywania konfiguracji przy przejściu, bo mogą z tego wyniknąć problemy z działaniem routera.

Poniżej jest zobrazowany proces upgrade firmware:

root@red_viper:/tmp# sysupgrade -n obraz.bin
killall: watchdog: no process killed
Sending TERM to remaining processes ... logd netifd odhcpd crond p910nd dnscrypt-proxy dnsmasq ntpd ubusd askfirst
Sending KILL to remaining processes ... askfirst
Switching to ramdisk...
Performing system upgrade...
Unlocking firmware ...
Writing from <stdin> to firmware ...
Upgrade completed
Rebooting system...
Write failed: Broken pipe

W tym momencie, po pomyślnym wgraniu nowego firmware, nastąpi reset routera. Po jego starcie logujemy się do systemu via telnet:

morfik:~$ telnet 192.168.1.1
Trying 192.168.1.1...
Connected to 192.168.1.1.
Escape character is '^]'.
 === IMPORTANT ============================
  Use 'passwd' to set your login password
  this will disable telnet and enable SSH
 ------------------------------------------

BusyBox v1.22.1 (2014-10-17 21:31:57 CEST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

        _______                     ________        __
       |       |.-----.-----.-----.|  |  |  |.----.|  |_
       |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
       |_______||   __|_____|__|__||________||__|  |____|
                |__| W I R E L E S S   F R E E D O M
 ----------------------------------------------------------------
 |                                                              |
 | OpenWrt Barrier Breaker (r42943)                             |
 | Build time: 2014-10-17 21:58 CEST                            |
 |                                                              |
 | Cezary Jackiewicz (obsy), http://eko.one.pl                  |
 |                                                              |
 ----------------------------------------------------------------
 | Machine: TP-Link TL-WR1043N/ND v2                            |
 | Uptime: 0d, 00:01:26                                         |
 | Load: 0.75 0.35 0.13                                         |
 | Flash: total: 4.4MB, free: 4.2MB, used: 6%                   |
 | Memory: total: 59.9MB, free: 47.6MB, used: 20%               |
 | WAN: 11.22.33.44, proto: dhcp                                |
 | LAN: 192.168.1.1                                             |
 ----------------------------------------------------------------

Zgodnie z sugestią wyżej, ustawiamy hasło dla konta root:

root@OpenWrt:/# passwd
Changing password for root
New password:
Retype password:
Password for root changed by root
root@OpenWrt:/# exit
Connection closed by foreign host.

Po wylogowaniu i próbie zalogowania się przez ssh, dostaniemy poniższy komunikat:

morfik:~$ ssh root@192.168.1.1
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
3a:60:bf:95:8e:19:39:35:85:9a:7b:19:02:57:52:4a.
Please contact your system administrator.
Add correct host key in /home/morfik/.ssh/known_hosts to get rid of this message.
Offending RSA key in /home/morfik/.ssh/known_hosts:16
  remove with: ssh-keygen -f "/home/morfik/.ssh/known_hosts" -R 192.168.1.1
RSA host key for 192.168.1.1 has changed and you have requested strict checking.
Host key verification failed.

Ostrzega on nas, że odcisk klucza się zmienił, co jest normalne przy flashowaniu routera i by móc się zalogować musimy usunąć stary klucz z listy:

morfik:~$  ssh-keygen -f "/home/morfik/.ssh/known_hosts" -R 192.168.1.1
# Host 192.168.1.1 found: line 16 type RSA
/home/morfik/.ssh/known_hosts updated.
Original contents retained as /home/morfik/.ssh/known_hosts.old

Ponawiamy próbę logowania do routera. Tym razem zostanie wyrzucony komunikat o niemożności zweryfikowania klucza oraz pytanie czy chcemy tego hosta dodać do zaufanych. Po dodaniu, zostaniemy poproszeni o wcześniej ustawione hasło i po jego podaniu, zalogowani do systemu:

morfik:~$ ssh root@192.168.1.1
The authenticity of host '192.168.1.1 (192.168.1.1)' can't be established.
RSA key fingerprint is 3a:60:bf:95:8e:19:39:35:85:9a:7b:19:02:57:52:4a.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.1' (RSA) to the list of known hosts.
root@192.168.1.1's password:

3.3 Przywracanie oryginalnego firmware

W przypadku gdy chcemy powrócić do firmware producenta naszego routera, musimy pobrać obraz ze strony http://dl.eko.one.pl/orig/ . Są tam pliki do różnych modeli i w tym przypadku cały proces powrotu do oryginalnego firmware został przeprowadzony w oparciu o router TL-WR1043ND v2.1 . Wchodzimy zatem na w/w link i pobieramy plik wr1043v2_en_3_15_31_up(130925).bin . Przy czym, trzeba zwrócić uwagę na nazwę -- pliki z oryginalnym firmware mają zwykle nazwę podobną do tej wr1043v2_en_3_17_38_up_[b]boot/b.bin . Te dwa różnią się miedzy sobą frazą boot , no i numerkiem firmware ale mniejsza o to. W każdym razie, potrzebny jest nam plik, który nie zawiera słówka boot.

Po pobraniu obrazu, kopiujemy go przy pomocy scp na router do katalogu /tmp/ :

morfik:~/Desktop$ scp wr1043v2_en_3_15_31_up\(130925\).bin root@192.168.1.1:/tmp/firmware.bin
wr1043v2_en_3_15_31_up(130925).bin                            100% 7936KB   3.9MB/s   00:02

Logujemy się teraz na router via SSH:

morfik:~$ ssh root@192.168.1.1

BusyBox v1.22.1 (2014-10-17 21:31:57 CEST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

        _______                     ________        __
       |       |.-----.-----.-----.|  |  |  |.----.|  |_
       |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
       |_______||   __|_____|__|__||________||__|  |____|
                |__| W I R E L E S S   F R E E D O M
 ----------------------------------------------------------------
 |                                                              |
 | OpenWrt Barrier Breaker (r42943)                             |
 | Build time: 2014-10-17 21:58 CEST                            |
 |                                                              |
 | Cezary Jackiewicz (obsy), http://eko.one.pl                  |
 |                                                              |
 ----------------------------------------------------------------
 | Machine: TP-Link TL-WR1043N/ND v2                            |
 | Uptime: 0d, 00:00:32                                         |
 | Load: 1.17 0.27 0.09                                         |
 | Flash: total: 4.4MB, free: 1.5MB, used: 66%                  |
 | Memory: total: 59.9MB, free: 44.6MB, used: 25%               |
 | WAN: 192.168.10.211, proto: dhcp                              |
 | LAN: 192.168.1.1                                             |
 | WLAN: mode: ap, ssid: Winter Is Coming, channel: 8           |
 ----------------------------------------------------------------
 
root@red-viper:~#

Przechodzimy do katalogu /tmp/ i przy pomocy polecenia sysupgrade wgrywamy firmware:

root@red-viper:~# cd /tmp
root@red-viper:/tmp# sysupgrade firmware.bin
Saving config files...
killall: watchdog: no process killed
Sending TERM to remaining processes ... netifd odhcpd crond p910nd dnscrypt-proxy ntpd dnsmasq ubusd askfirst logd
Sending KILL to remaining processes ... askfirst
Switching to ramdisk...
Performing system upgrade...
Unlocking firmware ...
Writing from <stdin> to firmware ...
Upgrade completed
Rebooting system...

Po chwili router powinien się zresetować. U mnie w logu został także złapany komunikat wysłany na broadcast przez router podczas jego startu:

Oct 26 22:49:26 morfikownia kernel: [ 4089.784250] * IPTABLES: UDP * IN=bond0 OUT= MAC=ff:ff:ff:ff:ff:ff:e8:94:f6:68:79:f0:08:00 SRC=192.168.0.1 DST=255.25
5.255.255 LEN=36 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=UDP SPT=42760 DPT=7437 LEN=16

Także, wygląda na to, że router się odpalił, a jego adres to 192.168.0.1 . Resetujemy zatem połączenie sieciowe:

root:~# /etc/init.d/networking stop
Deconfiguring network interfaces...done.
root:~# /etc/init.d/networking start
Configuring network interfaces...Internet Systems Consortium DHCP Client 4.3.1
Copyright 2004-2014 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/
Listening on LPF/bond0/3c:4a:92:00:4c:5b
Sending on   LPF/bond0/3c:4a:92:00:4c:5b
Sending on   Socket/fallback
DHCPDISCOVER on bond0 to 255.255.255.255 port 67 interval 5
DHCPDISCOVER on bond0 to 255.255.255.255 port 67 interval 13
DHCPREQUEST on bond0 to 255.255.255.255 port 67
DHCPOFFER from 192.168.0.1
DHCPACK from 192.168.0.1
bound to 192.168.0.100 -- renewal in 3300 seconds.

Adres został przypisany via DHCP, także proces przebieg pomyślnie.
Teraz jeszcze odwiedzamy adres http://192.168.0.1/ w przeglądarce:

4. Skrypty startowe

System OpenWRT działa w oparciu o wywoływanie skryptów startowych i musi to robić odpowiedniej kolejności. Wszystkie skrypty startowe zlokalizowane są w katalogu /etc/init.d/ . Każdy z umieszczonych tam plików można wywołać z pewnymi opcjami. By się dowiedzieć jakie to opcje, możemy wywołać przykładowy skrypt nie podając przy tym żadnego parametru:

# /etc/init.d/firewall 
Syntax: /etc/init.d/firewall [command]
Available commands:
    start   Start the service
    stop    Stop the service
    restart Restart the service
    reload  Reload configuration files (or restart if that fails)
    enable  Enable service autostart
    disable Disable service autostart

Przy pomocy start/stop startujemy/zatrzymujemy daną usługę. Z kolei restart to stop+start. Nie każda usługa posiada opcję reload, która to wczytuje zmiany dokonane w konfiguracji danej usługi. Natomiast wszystkie z nich posiadają opcje enable i disable, które decydują o tym, czy jakiś skrypt będzie odpalany na starcie systemu czy też nie.

Opcje enable/disable zalezą od nagłówka skryptu, a tam mamy przykładowo:

# head /etc/init.d/dropbear 
#!/bin/sh /etc/rc.common
...
START=50
STOP=50
...

Parametr STOP jest opcjonalny. Jeśli wywołamy skrypt z opcją enable, w katalogu /etc/rc.d/ zostaną utworzone dowiązania do tego skryptu, przykładowo:

# ls -al /etc/rc.d/*dropbear
lrwxrwxrwx    1 root     root            18 Oct 17 22:01 /etc/rc.d/K50dropbear -> ../init.d/dropbear
lrwxrwxrwx    1 root     root            18 Oct 17 22:01 /etc/rc.d/S50dropbear -> ../init.d/dropbear

Nazwa linku jest taka sama jak nazwa skryptu, z tą różnicą, że mamy tam dodatkowo S albo K i jakiś numer . Skrypty, które mają linki zaczynające się od S będą ładowane przy starcie systemu. Natomiast te, które mają dowiązania zaczynające się od K , będą wykonywane przy restarcie czy wyłączeniu (via poweroff) routera. Z kolei liczba, np. 50, to wartość wpisana w parametrze START/STOP w samym skrypcie, tak jak to widać na powyższym wycinku i oznacza ona pozycję w kolejce. Każdy skrypt ma jakiś numer i te, które mają mniejsze numerki są wykonywane przed tymi co mają większe. W przypadku gdy dwa skrypty mają taki sam numer, nie ma znaczenia, który się wykona jako pierwszy gdy przyjdzie pora na odpalenie ich.

Skrypty w /etc/init.d/ muszą się zaczynać od linijki:

#!/bin/sh /etc/rc.common

Dodatkowo, każdy skrypt musi posiadać przynajmniej dwa bloki kodu, po jednym dla akcji start i stop:

start() {                            
...
}
stop() {                            
...
}

To w nich umieszczamy instrukcje, na podstawie, których system wie co ma robić przy przetwarzaniu konkretnego skryptu.

5. Konfiguracja systemu routera (/etc/config/system)

5.1 Nazwa hosta

Każda maszyna w sieci powinna mieć jakąś w miarę łatwo zapamiętywalną nazwę, tak by nie było potrzeby ciągłego wpisywania adresów IP. By ustawić taką nazwę naszemu routerowi, musimy edytować plik /etc/config/system i zmienić w nim poniższą linijkę:

config system   
    ...
    option hostname 'the-mountain'    

5.2 Strefa czasowa i czas na routerze

Musimy także zmienić strefę czasową, tak by odpowiadała lokalizacji, w której znajduje się router. Robimy to przez ustawienie poniższych dwóch parametrów.

config system
    ...
    option timezone 'CET-1CEST,M3.5.0/2,M10.5.0/3'
    option zonename 'Europe/Warsaw'    

Druga linijka jest raczej zrozumiała. Problematyczna może okazać się ta pierwsza. Poniżej jest wyjaśnienie sprecyzowanego tam szyfru:

CET	- to standardowy czas środkowoeuropejski (Central European Time) , w chwili gdy nie obowiązuje czas letni.
-1	- to przesunięcie czasu w godzinach. Negatywna wartość oznacza 1 godzinę na wschód.
CEST	- to czas letni (Central European Summer Time)
,	- jako, że nie ma sprecyzowanej żadnej wartości między CEST oraz przecinkiem, używana jest standardowa
          wartość 1 godziny do przodu przy przechodzeniu na czas letni.
M3.5.0	- określa kiedy czas letni się rozpoczyna. W tym przypadku M3 to miesiąc 3, czyli marzec. Z kolei .5 to
          ostatni tydzień miesiąca, a .0 to niedziela.
/2,	- godzina czasu lokalnego, o której następuje zmiana czasu na letni
M10.5.0	- precyzuje kiedy czas letni się kończy. W tym przypadku M10 to miesiąc 10, czyli październik. Z kolei .5 to
          ostatni tydzień miesiąca, a .0 to niedziela.
/3,	- godzina czasu lokalnego, o której następuje cofnięcie czasu.  

5.3 Czas sieciowy

Niskobudżetowe routery nie posiadają zwykle zegara czasu rzeczywistego (RTC), tak jak to mają w standardzie zwykłe komputery domowe i jeśli podczas startu nie są podłączone do sieci, będą wskazywać rok 1970, czyli początek epoki linuxa (Unix Epoch). Przynajmniej tak to wyglądało do wypuszczenia OpenWRT Barrier Breaker, gdzie wprowadzono skrypt /etc/init.d/sysfixtime , który to skanuje katalog /etc/ w poszukiwaniu czasów modyfikacji plików w nim zawartych i ten, który ma najnowszą datę jest brany pod uwagę i to na jego podstawie jest ustawiany nowy czas systemowy. Oczywiście, to tylko na wypadek braku łączności z siecią.

Rozbieżności w czasie mogą przysporzyć szereg problemów, dlatego też czas na routerze trzeba ciągle synchronizować z serwerami czasu dostępnymi w internecie. Możemy sprecyzować kilka takich serwerów, tak by nasz router miał zawsze aktualny czas.

config timeserver 'ntp'
    list server '0.pl.pool.ntp.org'
    list server '1.pl.pool.ntp.org'
    list server '2.pl.pool.ntp.org'
    list server '3.pl.pool.ntp.org'
    option enabled '1'
    option enable_server '1'
    option interface 'br-lan'    

Jeśli opcja enabled jest ustawiona na 1, wtedy router będzie synchronizował czas z tymi serwerami określonymi w list server . Jeśli do tego zostanie ustawiona opcja enable_server , maszyny lokalne będą mogły przesyłać zapytania do routera (port 123) i synchronizować czas w oparciu o dane z routera -- nie ma potrzeby ponownego odpytywania globalnych serwerów NTP o aktualny czas.

5.4 Logi systemowe

Logi routera to bardzo ważna rzecz. Jeśli coś dolega naszemu małemu przyjacielowi, to jest pierwsze miejsce gdzie musimy poszukać informacji na temat tego co może go boleć. Logi odczytujemy przy pomocy polecenia logread wpisując je w okno terminala po zalogowaniu się do systemu via SSH.

Każda usługa przesyła logi, które są zbierane przez daemon logowania, do którego mamy dostęp przy pomocy powyższego narzędzia. Jeśli mamy problem z wifi i z jakiegoś powodu nie działa nam połączenie, powinniśmy poszukać w logu wpisów dotyczących wifi i prześledzić je pod kątem słów takich jak ERROR czy FAILED. Dodatkowo, jeśli obawiamy się o bezpieczeństwo routera, np. mając stały zewnętrzny adres IP, możemy włączyć zapisywanie logów do pliku na zewnętrznym nośniku. Dzięki temu rozwiązaniu, jeśli ktoś nieuprawniony wbije do naszego routera z poza sieci, będziemy mieć kopie logów z tego zdarzenia na innej maszynie i będziemy mogli podjąć ewentualne kroki by tą osobę namierzyć. Poniżej jest konfiguracja logowania do pliku:

config system
    ...
    option log_type 'file'
    option log_file '/var/log/messages'
    option log_size '64'    

Oczywiście, trzeba dostosować odpowiednio ścieżkę do pliku, w którym to log ma być zapisywany.

Istnieje także możliwość przesłania logów przez sieć do określonego hosta. Nie wiem czy te logi można przesłać do maszyn mających na pokładzie windowsa, natomiast bez problemu ten mechanizm współpracuje z linuxami. Poniżej konfiguracja:

config system   
...
    #option log_type 'file'
    #option log_file '/var/log/messages'
    #option log_size '64'
    option log_ip   '192.168.1.170'
    option log_port '514'
    option log_proto 'tcp'
    option log_prefix 'router '    

Trzeba mieć na uwadze, że te logi są przesyłane w formie niezaszyfrowanej i standardowa konfiguracja OpenWRT nie daje możliwości zaszyfrowania przesyłanych logów. W innym howto opisałem jak zabezpieczyć przesyłanie takich logów przez sieć przy pomocy tunelu TLS.

5.5 LEDy

Dalej w pliku mamy możliwość skonfigurowania diod routera. To jakie LEDy ma nasz sprzęt, możemy odczytać przeszukując katalog /sys/class/leds . Przykładowo na moim Archer C7 v2 mam poniższy listing:

# ls -al /sys/class/leds
drwxr-xr-x    2 root     root             0 Jan  1  1970 .
drwxr-xr-x   22 root     root             0 Jan  1  1970 ..
lrwxrwxrwx    1 root     root             0 Oct 21 03:52 ath9k-phy1 -> ../../devices/platform/qca955x_wmac/leds/ath9k-phy1
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:blue:lan1 -> ../../devices/virtual/leds/tp-link:blue:lan1
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:blue:lan2 -> ../../devices/virtual/leds/tp-link:blue:lan2
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:blue:lan3 -> ../../devices/virtual/leds/tp-link:blue:lan3
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:blue:lan4 -> ../../devices/virtual/leds/tp-link:blue:lan4
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:blue:qss -> ../../devices/platform/leds-gpio/leds/tp-link:blue:qss
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:blue:system -> ../../devices/platform/leds-gpio/leds/tp-link:blue:system
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:blue:wan -> ../../devices/virtual/leds/tp-link:blue:wan
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:blue:wlan2g -> ../../devices/platform/leds-gpio/leds/tp-link:blue:wlan2g
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:blue:wlan5g -> ../../devices/platform/leds-gpio/leds/tp-link:blue:wlan5g
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:green:usb1 -> ../../devices/platform/leds-gpio/leds/tp-link:green:usb1
lrwxrwxrwx    1 root     root             0 Jan  1  1970 tp-link:green:usb2 -> ../../devices/platform/leds-gpio/leds/tp-link:green:usb2    

Nazwa dowiązania odpowiada nazwie producenta (ew. modelu) urządzenia (tp-link), następnie mamy kolor diody (blue/green). Kolejny człon nazwy to etykieta takiej diody. W tym przypadku wszystkie LEDy z przodu na panelu są zielone (choć pokazuje, że powinny być niebieskie) i zbytnio nie da się zrobić wymyślnych kombinacji, które by reagowały na pewne określone zdarzenia. Gdyby były tam dostępne inne kolorki, można by przypisać np. portowi WAN, by przy pakiecie inicjującym połączenie SSH, zapalał diodę na np. czerwono.

Jeśli chodzi o router Archer C7 v2 , mamy zdefiniowanych kilka diod:

config led 'led_usb1'
    option name 'USB1'
    option sysfs 'tp-link:green:usb1'
    option trigger 'usbdev'
    option dev '1-1'
    option interval '50'
config led 'led_usb2'
    option name 'USB2'
    option sysfs 'tp-link:green:usb2'
    option trigger 'usbdev'
    option dev '2-1'
    option interval '50'
config led 'led_wlan2g'
    option name 'WLAN2G'
    option sysfs 'tp-link:blue:wlan2g'
    option trigger 'phy0tpt'    

Diody są zapalane i gaszone w oparciu o pewne moduły, które nimi sterują. Jest to definiowane w opcji trigger . Moduły można doinstalować i tym samym rozbudować nieco możliwości sygnalizacyjne naszego routera. Pełna lista modułów jest dostępna na wiki OpenWRT, pod linkiem http://wiki.openwrt.org/doc/uci/system#leds .

To jakie moduły mamy dostępne w systemie, można podejrzeć przez plik trigger w dowolnej diodzie, przykładowo:

# cat /sys/class/leds/tp-link\:blue\:wlan5g/trigger
[none] switch0 timer default-on netdev heartbeat usbdev phy0rx phy0tx phy0assoc phy0radio phy1rx phy1tx phy1assoc phy1radio phy1tpt    

Moduł ujęty w [] jest aktywny.

W moim TL-WR1043nd v2 nie ma problemów z diodami, natomiast ma je Archer C7 v2 -- nie zapalają się diody od WiFi, bo nie ma zdefiniowanego bloku od led_wlan5g , a z kolei w led_wlan2g nie ma dostępnego triggera phy0tpt .

W moim routerze nie ma zbytniego pola manewru jeśli chodzi o LEDy ale jest jedna dioda, która w sumie nic nie robi, tylko ciągle się świeci. Chodzi o diodę system. Można ją jednak zaprogramować tak, by migała w tempie zależnym od loadavg routera (do wglądu w /proc/loadavg). Jeśli router jest w spoczynku, to ma niski loadavg, jeśli pracuje pod solidnym obciążeniem, to loadavg mu wzrasta. Dzięki takiej zależności możemy obserwować diodę na obudowie routera i wiedzieć przy tym czy coś urządzeniu dolega.
By wdrożyć u siebie taką funkcjonalność, musimy doinstalować pakiet kmod-ledtrig-heartbeat :

# opkg update
# opkg install kmod-ledtrig-heartbeat    

Potrzebujemy także dopisać odpowiednią sekcję w pliku /etc/config/system :

config led 'led_system'
    option name 'SYSTEM'
    option sysfs 'tp-link:green:system'
    option trigger 'heartbeat'    

Kluczowe jest dobranie sysfs -- trzeba zidentyfikować diodę w /sys/class/leds by uzupełnić wartość tego parametru. Trigger ustawiamy na heartbeat . Teraz wystarczy zresetować już router.

6. Konfiguracja przycisków

Każdy router ma przyciski, a te można odpowiednio zaprogramować. W przypadku mojego routera TL-WR1043N/ND v2 , niestety nie działa jeden przycisk -- ten od włączania/wyłączania wifi. Niemniej jednak, działa drugi z przycisków -- reset. Jeśli chodzi o Archera C7 v2, to jest jeszcze gorzej, bo nawet reset nie działa. Konfiguracja przycisków trzymana jest w katalogu /etc/rc.button/ w odpowiednich plikach, zwykle nazwa określa przycisk, który dany plik konfiguruje.

Zanim jednak przejdziemy do konfiguracji przycisków, musimy sprawdzić jak rozpoznaje je router. W tym celu tworzymy skrypt, który zidentyfikuje nam owe przyciski po ich przyciśnięciu:

# mkdir -p /etc/hotplug.d/button
# touch /etc/hotplug.d/button/buttons
# chmod +x /etc/hotplug.d/button/buttons    

I do tak utworzonego pliku, dodajemy poniższą zawartość:

#!/bin/sh
logger $BUTTON
logger $ACTION    

Teraz kolejno wciskamy przyciski na routerze. W przypadku przycisku reset, dobrze jest przytrzymać go kilka sekund, tak by urządzenie się nie zresetowało po jego przyciśnięciu. W logu (logread) powinniśmy zaobserwować pojawienie się wpisów podobnych do tych poniżej:

user.notice root: wps
user.notice root: pressed
user.notice root: wps
user.notice root: released    

Nazwa, która widnieje wyżej identyfikuje wciśnięty przycisk. No to już wiem czemu przycisk reset nie działa -- bo ten jest wykrywany jako wps. By poprawić tę niedogodność, kopiujemy skrypt reset i zapisujemy go pod nazwą wps :

# cd /etc/rc.button/
# cp reset wps    

Po skopiowaniu, router powinien się zresetować bez problemu po wciśnięciu przycisku.
OpenWRT poza możliwością logowania akcji wciśnięcia czy puszczenia przycisku, pozwala także na zalogowanie czasu trzymania przycisku. W powyższym przykładzie przycisk został przyciśnięty i od razu puszczony. Niemniej jednak, przycisk można też trzymać parę sekund i w oparciu o ten czas, dopisać jakiś blok z regułami do plików w katalogu /etc/rc.button/ .

7. Konfiguracja interfejsów sieciowych (/etc/config/network)

W pliku /etc/config/network trzymana jest wszelka konfiguracja dotycząca interfejsów sieciowych, zarówno tych, które umożliwiają połączenie się z internetem, jak i tych obsługujących sieć lokalną. W powyższym pliku mamy sprecyzowanych kilka bloków, które zostaną poniżej opisane, z tym, że w domyślnej konfiguracji OpenWRT może brakować pewnych linijek, dlatego też jeśli czegoś nie posiadamy, to wystarczy zwyczajnie dany parametr dopisać.

7.1 Interfejs lo

Pierwszy blok odpowiada za konfigurację pętli zwrotnej oznaczonej interfejsem lo . Każda maszyna by realizować komunikację wewnątrz procesową musi posiadać skonfigurowany taki interfejs.

config interface 'loopback'
    option ifname 'lo'
    option proto 'static'
    option ipaddr '127.0.0.1'
    option netmask '255.0.0.0'

Powyżej mamy określony adres statyczny dla interfejsu lo jako 127.0.0.1 .

7.2 Interfejs lan

Następny blok definiuje konfigurację interfejsu odpowiedzialnego za komunikację wewnątrz sieci LAN:

config interface 'lan'
    option ifname 'eth1'
    option force_link '1'
#	option macaddr ''
    option type 'bridge'
    option proto 'static'
    option ipaddr '192.168.1.1'
    option netmask '255.255.255.0'
#	option broadcast '192.168.1.255'

Ten interfejs (eth1) jest zmostkowany (type 'bridge'), co oznacza, że sam w sobie nie posiada adresu IP -- posiada go mostek. Dzięki czemu można spiąć kilka różnych interfejsów sieciowych w jeden i nadać im ten sam adres IP. Podobnie jak w przypadku interfejsu lo, powyższy interfejs posiada stały adres IP 192.168.1.1 oraz na podstawie maski 255.255.255.0 została określona sieć, w skrócie 192.168.1.0/24 . Interfejs z tymi parametrami będzie obsługiwał tylko te maszyny, które posiadają adresy ip z puli 192.168.1.1-192.168.1.254. Adres 192.168.1.255 to broadcast dla sieci, dzięki któremu dany host w sieci może wysłać pakiety do wszystkich znajdującej się w niej maszyn, np. w przypadku poszukiwania serwera DHCP. Z tym, że nie trzeba go definiować. Wszelkie usługi udostępniane przez router w sieci domowej będą widziane pod adresem tego interfejsu.

7.3 Interfejs wan

Dalej w pliku /etc/config/network mamy konfigurację interfejsu WAN:

config interface 'wan'
    option ifname 'eth0'
#	option macaddr '3c:4a:92:00:4c:5b'
    option proto 'static'
#	option proto 'dhcp'
    option ipaddr '160.14.60.12'
    option netmask '255.255.255.0'
    option gateway '160.14.60.253'
#	option broadcast '160.14.60.255'
    option peerdns '0'                        
    option dns '208.67.220.220 208.67.222.222'

Jeśli pobieramy konfigurację z serwera DHCP od naszego ISP, to przestawiamy proto na dhcp. Jeśli mamy statyczną konfigurację dla routera, proto ustawiamy na static i definiujemy kolejne cztery parametry: ipaddr, netmask, gateway, broadcast. Broadcast jest opcjonalny i zwykle jest automatycznie dobierany, także nie trzeba go ustawiać. Natomiast ważne jest by wpisać odpowiedni adres dla bramy sieciowej. Bez tego nasz router nie będzie wiedział gdzie przesłać pakiety, co zaowocuje brakiem internetu.

Większość ISP posiada także serwery DNS, jeśli opcja peerdns jest ustawiona na 0, router nie będzie z nich korzystał. Jeśli zdecydujemy się na korzystanie z alternatywnych serwerów DNS, np OpenDNS, musimy dodać do konfiguracji opcję dns i ustawić odpowiednie adresy. Po zresetowaniu routera, pojawią się one w pliku /tmp/resolv.conf.auto :

# cat /tmp/resolv.conf.auto 
# Interface wan
nameserver 208.67.220.220
nameserver 208.67.222.222

Jeśli chodzi o serwery DNS dla hostów znajdujących się w sieci lokalnej, to takim serwerem jest sam router -- wszystkie zapytania DNS z sieci wędrują do niego (lub pod adres określony w pliku /tmp/resolv.conf), a ten przesyła je do upstreamowych serwerów DNS, tych określonych w pliku powyżej. Możemy oczywiście ustawić by zapytania szły bezpośrednio do serwerów google czy OpenDNS w ten sam sposób co w przypadku interfejsu WAN, z tym, że wtedy tracimy możliwość buforowania zapytań, co trochę spowalnia rozwiązywanie nazw.

7.4 Spoofowanie (klonowanie) adresów MAC

Każde urządzenie sieciowe ma inny adres MAC i przy rozbudowie sieci domowej, tam gdzie do tej pory był jeden komputer wpięty bezpośrednio do łącza ISP, zaistnieją problemy po podłączeniu routera, bo zmienił się adres MAC. ISP ma powiązane adresy MAC z adresami IP i nowo wpięty router nie otrzyma adresu IP, bo ma nieautoryzowany MAC. W takiej sytuacji zwykle wystarczy telefon do ISP z prośbą przepisania adresu MAC, niemniej jednak, czasami ISP każą sobie dodatkowo płacić za tę czynność. Jeśli jesteśmy postawieni w takiej sytuacji, możemy zespoofować (sklonować) sobie adres MAC tej maszyny, która wcześniej była wpięta do internetu i wpisać tego MACa w miejsce macaddr w bloku wan :

option macaddr '3c:4a:92:00:4c:5b'

7.5 Switch i VLANy

Oprogramowanie OpenWRT umożliwia także dość swobodną konfigurację przełącznika, który znajduje się w routerze. Opis jego konfiguracji jak i tworzenie VLANów zostało opisane w tym wątku.

8. Konfiguracja dnsmasq (/etc/config/dhcp)

8.1 DNS

Konfiguracja dnsmasq trzymana jest pliku /etc/config/dhcp . Poniżej prześledzimy opcje, które możemy ustawić w tym pliku, tak by skonfigurować DHCP/DNS według naszych potrzeb.

Poniższe dwie opcje odfiltrowują zapytania, na które nie potrafią odpowiedzieć publiczne serwery DNS. Pierwsza z nich nie forwarduje nazw bez kropek (bez części domeny), zaś druga nie zezwala na przekazywanie adresów z prywatnej przestrzeni adresowej.

option domainneeded		'1'
option boguspriv		'1'

Poniższe dwie opcje określają domenę lokalną -- tę, która zostanie dopisana (.lan) do hostów sprecyzowanych w pliku /etc/hosts .

option local			'/lan/'
option domain			'lan'

Przykładowy wpis w /etc/host wygląda następująco:

192.168.1.150 red-viper

Zatem host w tej sieci będzie identyfikowany jako red-viper.lan i będziemy mogli się łączyć z odpowiadającym mu adresem IP zarówno przez wpisanie samego red-viper jak i red-viper.lan .

Narzędzie dnsmasq potrafi czytać wpisy w pliku /etc/hosts . Jeśli chcemy skorzystać z tej funkcjonalności, możemy to określić w parametrze:

option nohosts '0'

Opcja expandhosts dodaje końcówkę domeny do nazw sprecyzowanych w pliku /etc/hosts .

option expandhosts '1'

Pierwsza z opcji odrzuca upstreamowe serwery DNS, które posiadają prywatne adresy IP blokując w ten sposób pewne ataki, np. przeglądarka za firewallem, odwiedzając pewne strony, mogłaby zostać użyta do próbkowania sieci lokalnej. Z kolei druga opcja zezwala na odpowiedzi z 127.0.0.0/8 , czyli pętli zwrotnej, która również należy do klasy prywatnej.

option rebind_protection '1' option rebind_localhost '1'

W przypadku nieudanego rozwiązania nazwy na adres IP, zapytanie może być buforowane i zajmować miejsce w pamięci. Poniższa opcja wyłączy dodawanie do cache tego typu nierozwiązywalnych wpisów:

option nonegcache '1'

Zapytania DNS zajmują trochę czasu i w przypadku gdy odwiedzamy jedną stronę kilka razy, za każdym razem trzeba rozwiązać jej nazwę na adres IP. Co prawda, nie trwa to długo ale zawsze jest to parę ms. W tym celu stworzono mechanizm, który buforuje zapytania DNS i w przypadku gdy odwiedzamy ponownie ten sam adres, nazwa nie jest rozwiązywana, tylko brana bezpośrednio z cache.

Możemy sobie dostosować ilość adresów w cache dla zapytań DNS zmieniając poniższą linijkę:

option cachesize '1000'

Nie należy jednak z wartością tego parametru przesadzać, bowiem każdy wpis zjada trochę pamięci RAM routera.

Dodatkowo możemy logować zapytania DNS, ustawiając:

option logqueries '1'

Możemy także określić plik, w którym to będą znajdować się wpisy z adresami serwerów DNS -- standardowo taki plik jest generowany automatycznie przy starcie routera i trzymany w katalogu /tmp/ :

option resolvfile '/tmp/resolv.conf.auto'

Możemy także zrezygnować z czytania przez dnsmasq pliku /etc/resolv.conf (podlinkowany do /tmp/resolv.conf) . Jeśli się na to zdecydujemy, trzeba zadbać o ręczne skonfigurowanie adresów IP upstreamowych serwerów DNS:

option noresolv			'1'
list server				'208.67.222.222'
list server				'208.67.220.220'

8.2 DHCP

W dnsmasq nie tylko mamy sprecyzowaną konfigurację dotyczącą rozwiązywania nazw na adresy IP, są tam także wpisy konfigurujące serwer DHCP.

Jeśli mamy tylko jeden router i nie ma w sieci więcej serwerów świadczących usługi DHCP, dobrze jest przestawić dnsmasq w tryb authoritative , co zaowocuje przyśpieszeniem przydzielania lease DHCP.

option authoritative '1'

Poniższa opcja przeszukuje plik /etc/ethers , w którym to znajdują się baza adresów MAC wraz z przypisanymi im adresami IP (statyczne lease DHCP).

option readethers '0'

Kolejny parametr określa maksymalną ilość lease DHCP. Dobrze jest ten parametr skontrastować z pulą adresów, którą dysponuje serwer DHCP.

option dhcpleasemax '150'

Trzeba jeszcze określić zakres adresów IP przydzielanych lokalnym maszynom przez serwer DHCP na routerze:

config dhcp 'lan'
    option interface 'lan'
    option start '100'
    option limit '150'
    option leasetime '24h'
config dhcp 'wan'
    option interface 'wan'
    option ignore '1'

Przy czym, interesuje nas jedynie interfejs lan, dlatego też interfejs wan ma ustawioną flagę ignore -- tym interfejsem zajmuje się serwer DHCP naszego ISP.
Nasza sieć to 192.168.1.0/24 , zatem według opcji start , pierwszy adres IP otrzymany via DHCP będzie miał numer 192.168.1.100 . Z kolei opcja limit, określa ile adresów może być do dyspozycji serwera, w tym wypadku 150, czyli pula adresów przydzielana przez serwer DHCP to 192.168.1.100-192.168.1.249. Możemy także określić ważność lease DHCP -- jako, że są to komputery w sieci domowej, możemy ten parametr ustawić na 24 godziny. Po tym jak lease straci ważność, host ponownie odpyta serwer DHCP i poprosi o konfigurację sieci.

Dodatkowo możemy zdefiniować opcje, które będą wędrować do hostów w sieci w konfiguracji DHCP. Pełną listę wszystkich dostępnych parametrów można znaleźć np. tutaj.

config dhcp 'lan'
    ...
    list 'dhcp_option' '3,192.168.1.1'
    list 'dhcp_option' '6,192.168.1.1'
    list 'dhcp_option' '6,208.67.222.222,208.67.220.220'
    list 'dhcp_option' '6,8.8.8.8,8.8.4.4'

Powyżej mamy dwie opcje, z których pierwsza posiada numer 3 i odpowiada za ustawienie adresu bramy sieciowej na hostach -- przydatna opcja w przypadku gdy maszyna z serwerem DHCP nie jest jednocześnie bramą sieciową. Pozostałe trzy opcje z numerami 6 (do wyboru jedna z nich), określają adresy serwerów DNS, które powinny zostać ustawione na hostach pobierających lease DHCP. Standardowo router uzupełnia to pole wpisując swój własny adres, po czym wszystkie zapytania DNS skierowane do niego są forwardowane do upstreamowych serwerów DNS, czy to opendns/google, czy naszego ISP.

8.3 Statyczne lease DHCP

Dalej w pliku /etc/config/dhcp możemy definiować statyczne lease DHCP i robimy to przez dodawanie bloków podobnych do tego poniżej:

config host
    option ip       '192.168.1.166'
    option mac      '00:16:e6:34:c4:e0'
    option name     'the-hound'

Z tym, że jeśli chodzi o statyczne lease DHCP, może nam do tego posłużyć także plik /etc/ethers . Ja jednak wolę mieć wszystko w jednym miejscu, dlatego też korzystam z powyższego pliku . W obu przypadkach format wpisów się różni i jeśli chcemy wykorzystać plik /etc/ethers , dodajemy w nim wpisy w poniższej formie:

# the hound
00:16:e6:34:c4:e0       192.168.1.166

No i także trzeba pamiętać by ustawić odpowiednią opcję w bloku dnsmasq w pliku /etc/config/dhcp :

option readethers '1'

9. Konfiguracja WiFi (/etc/config/wireless)

Sieć bezprzewodowa w dzisiejszych czasach to podstawa. Z reguły routery posiadają jedno radio operujące na częstotliwości 2,4GHz. Te nieco nowsze (i droższe) modele mają do dyspozycji dwa radia -- jedno 2,4GHz, drugie 5GHz. Poniżej postaramy się skonfigurować oba z nich.

9.1 RADIO

Po wgraniu oprogramowania OpenWRT, WiFi jest domyślnie wyłączone:

# wifi staus
'radio0' is disabled
'radio1' is disabled

By je włączyć i ustawić szereg opcji, musimy edytować plik /etc/config/wireless . Przy czym, taka uwaga jeszcze -- jeśli z jakichś powodów rozsypie się nam konfiguracja i będziemy chcieli przywrócić ją do ustawień domyślnych, możemy usunąć plik /etc/config/wireless i skorzystać z polecenia wifi detect . Plik nie może istnieć w chwili wydawania tego polecenia, inaczej zostanie zwrócony pusty wynik:

# rm /etc/config/wireless
# wifi detect > /etc/config/wireless

Jeśli mamy dwa radia, dobrze jest pierw rzucić okiem na wynik polecenia iwinfo :

# iwinfo 
wlan0     ESSID: unknown
          Access Point: 00:00:00:00:00:00
          Mode: Client  Channel: unknown (unknown)
          Tx-Power: 0 dBm  Link Quality: unknown/70
          Signal: unknown  Noise: unknown
          Bit Rate: unknown
          Encryption: unknown
          Type: nl80211  HW Mode(s): 802.11nac
          Hardware: 168C:003C 0000:0000 [Generic MAC80211]
          TX power offset: unknown
          Frequency offset: unknown
          Supports VAPs: yes  PHY name: phy0
wlan1     ESSID: unknown
          Access Point: 00:00:00:00:00:00
          Mode: Client  Channel: unknown (unknown)
          Tx-Power: 0 dBm  Link Quality: unknown/70
          Signal: unknown  Noise: unknown
          Bit Rate: unknown
          Encryption: unknown
          Type: nl80211  HW Mode(s): 802.11bgn
          Hardware: unknown [Generic MAC80211]
          TX power offset: unknown
          Frequency offset: unknown
          Supports VAPs: yes  PHY name: phy1

Na podstawie interfejsów wlan0 i wlan1 określane są opcje wifi-device w pliku /etc/config/wireless . Z godnie z powyższym logiem, radio 5GHz ma interfejs wlan0, zatem wifi-device to radio0 . Podobnie z radiem 2,4GHz.

9.1.1 Pasmo 2,4GHz

Pasmo 2,4GHz w Polsce jest podzielone na 13 kanałów. Każdy z nich jest przesunięty o 5MHz, czyli kanał pierwszy ma częstotliwość 2412MHz, kanał drugi 2417MHz, kanał trzeci 2422MHz i tak dalej do kanału 13 o częstotliwości 2472MHz. Poniżej fotka:

Routery w tym paśmie domyślnie mają ustawioną szerokość kanałów na 20MHz, zatem zakłócają sobie transmisję dość w znacznym stopniu i tylko na trzech z tych kanałów ta transmisja może odbywać się bez problemów i, jak widzimy wyżej, są to kanały 1, 6 oraz 11 (ewentualnie 12, 13). Zakłócenia stają się jeszcze większym problemem gdy naszemu routerowi zmienimy szerokość kanałów na 40MHz , co prawda szersze kanały zapewniają większy transfer ale też zajmują pół dostępnego pasma dla wszystkich kanałów i jeśli mamy w okolicy sporo sieci bezprzewodowych, to przy zwiększonej szerokości kanału zamiast polepszyć sobie transfer, tylko go pogorszymy.
Standardowa konfiguracja radia dla routerów zdolnych operować na paśmie 2,4GHz wygląda mniej więcej tak jak poniżej:

config wifi-device 'radio1'
    option type 'mac80211'
    option channel '8'
    option hwmode '11g'
    option path 'platform/qca955x_wmac'
    option disabled '0'
    option log_level '2'

Linijka z wifi-device precyzuje, którego radia dotyczy powyższy blok. Typ (druga linijka) jest wykrywany podczas pierwszego uruchomienia routera (firstboot) i nie wymaga ręcznego dostosowania. Następnie jest określony kanał, do którego będzie podpięta nasza sieć WiFi. Można sprecyzować tam kanały statyczne od 1-14 (w zależności od kraju), lub też możemy wybrać tryb auto, który przeskanuje sieć w poszukiwaniu ewentualnych zakłóceń i podłączy nas do najlepszego z dostępnych kanałów. Linijka z hwmode określa z jakiego pasma korzystamy -- 11g jest dla 2.4GHz. Opcja disabled definiuje czy radio ma być włączone czy wyłączone. Kolejna opcja (log_level) odpowiada za poziom logowania zdarzeń. Im niższy numerek, ty więcej logów będzie notowanych -- dostępne wartości od 0-4.

9.1.1.1 Szerokość kanałów

Dalej w pliku mamy możliwość ustawienia htmode , który to określa szerokość kanałów:

config wifi-device 'radio1'
    ...
    option htmode 'HT20'
    option noscan '0'

Można sprecyzować tutaj HT20 dla pojedynczego kanału 20MHz , lub też HT40- / HT40+ dla dwóch kanałów, każdy po 20MHz. Jeśli planujemy umieścić sieć WiFi na jednym z kanałów 5-13, wybieramy HT40- , z kolei jeśli chcemy umiejscowić się na kanale 1-9, ustawiamy HT40+ . Jeśli chodzi o samą możliwość nadawania na HT40[+-], to nie zawsze jest taka opcja. Router potrafi przebadać pasmo i oszacować czy nadaje się ono na nadawanie w nim z większą prędkością. Niemniej jednak, pasmo 2,4GHz jest mocno zapchane i mi się nigdy nie udało ustawić sieci WiFi tak by to działało na HT40+ albo HT40-. Istnieje jednak opcja noscan , która po przestawieniu na 1 w powyższym configu, nie będzie skanować dostępnego pasma i bez problemu podłączy się na HT40[+-] . Nie jest jednak zalecane korzystać z tej opcji.

9.1.1.2 Kanały 12 i 13

Domyślne ustawienia routera są określone pod kątem USA, a tam nie ma możliwości używania kanałów o numerach większych niż 11. W Polsce mamy możliwość korzystania z kanału 12 i 13 i by móc ich używać, musimy określić odpowiedni kod kraju, w którym nadaje router:

config wifi-device 'radio1'
    ...
    option country 'PL'
    option country_ie 'PL'

9.1.2 Pasmo 5GHz

W przypadku pasm 2,4GHz, na których operuje większość routerów, mamy jeszcze ten problem, że część zakłóceń, która pogarsza jakość sygnału WiFi jest generowana przez pewne sprzęty gospodarstwa domowego oraz przez sprzęt elektroniczny inny niż bezprzewodowe routery czy karty WiFi, np. mikrofalówki, czy bezprzewodowe myszy albo klawiatury. Tego typu zakłóceń jest sporo mniej w paśmie 5GHz. Dodatkowo, szerokość kanałów uległa zwiększeniu.

Poniżej znajduje się standardowa konfiguracja radia routera operującego na częstotliwości 5GHz:

config wifi-device  'radio0'
    option type     'mac80211'
    option channel  '36'
    option hwmode   '11a'
    option path     'pci0000:01/0000:01:00.0'
    option disabled '1'
    option country 'PL'
    option country_ie 'PL'

Podobnie jak w przypadku radia 2,4GHz określamy urządzenie (wifi-device). Z kolei kanały w paśmie 5GHz są trochę inne. W Europie, w tym też i w Polsce, mamy możliwość skorzystania z kanałów 36 do 64 oraz 100-140 z tym, że każdy kolejny kanał począwszy od 36 i 100 ma numer o 4 większy, zatem 36, 40, 44, 100, 104, 108, itd. W przypadku pasma 2,4GHz, kolejne kanały różniły się między sobą jedynie o 5MHz, zaś kanały w paśmie 5GHz mają częstotliwość większą o 20MHz. Zatem, kanał 36 ma 5180MHz, kanał 40 ma 5200, i tak dalej. Na dobrą sprawę, to dalej te kanały mają szerokość 5MHz, tylko, że tylko niektóre z nich są używane.

Dalej mamy określone pasmo dla radia -- to ta linijka z hwmode i 11a oznacza pracę w paśmie 5GHz. Możemy także wyłączyć radio 5GHz przy pomocy opcji disabled. Ostatnie dwa parametry określają kraj. Trzeba przy tym pamiętać, że nie wszystkie kanały są dostępne w określonych państwach.

9.1.2.1 Szerokość kanałów

W paśmie 5GHz mamy do wyboru nieco inne wartości dotyczące określenia szerokości kanałów. Są to VHT20 , VHT40 , VHT80 oraz VHT160 odpowiednio dla 20MHz, 40MHz, 80MHz i 160MHz -- te dwa ostatnie dla standardu ac. Nie określamy przy tym + albo - , tak jak to ma miejsce w przypadku radia 2,4GHz -- dodatkowe kanały są dobierane automatycznie.

config wifi-device 'radio1'
    ...
    option htmode 'VHT80'
    option noscan '0'

9.1.3 Moc transmisyjna

W obu przypadkach, użytecznymi opcjami mogą się także okazać distance i txpower :

config wifi-device 'radio1'
    ...
#	option distance '5'
    option txpower '10'
config wifi-device 'radio0'
    ...
#	option distance '5'
    option txpower '10'

To za ich pomocą możemy regulować moc nadawania fal radiowych. Dystans jest określany w metrach, natomiast txpower w dBm .

9.2 Tryb AP

Mając skonfigurowane radio, możemy przejść do ustawienia parametrów sieci WiFi. Przede wszystkim, w zależności od tego co tak naprawdę chcemy osiągnąć i jakiej funkcjonalności potrzebujemy, musimy dobrze dobrać pakiety pod konfigurację naszego routera. Jeśli zamierzamy korzystać z WPS, to niestety musimy wyrzucić domyślnie instalowany pakiet wpad-mini i zainstalować na jego miejsce pełną wersję tego pakietu:

# opkg update
# opkg remove wpad-mini
# opkg install wpad hostapd-utils

9.2.1 WPA2 Personal

Najpopularniejszym schematem sieciowym WiFi w domu jest WPA2 Personal (WPA2-PSK), w którym to wszyscy użytkownicy sieci i ich urządzenia mają jedno i to samo hasło dostępowe. Jest kilka różnych ustawień, które możemy zaaplikować naszemu routerowi i poniżej opiszę to najbardziej bezpieczne i nie koniecznie przy tym łagodne dla urządzenia jeśli chodzi o wydajność. Poniżej jest blok kodu, który musimy dodać do pliku /etc/config/wireless :

config wifi-iface
    option device 'radio0'
    option network 'lan'
    option mode 'ap'
    option ssid 'Ever_Vigilant'
    option key '141fc9d993132ca1fed53612119d26f117a9eafd739a4064eb32ef7f09c482f4'
    option encryption 'psk2+aes'
    option disabled '0'
    option isolate '0'
    option maxassoc '50'

Opcja device określa radio, którego będą się tyczyć ustawienia sprecyzowany w powyższym bloku. Dalej mamy network określający logiczny interfejs. Następnie mamy tryb kontrolera sieci bezprzewodowej, ustawiony w tym przypadku na ap, co daje możliwość ustanowienia połączenia z innymi urządzeniami posiadającymi karty bezprzewodowe. By takie połączenie mogło się odbyć, jedna z kart musi być w trybie ap. Jeśli żadna z kart go nie obsługuje, nie da rady zastawić połączenia. Wszystkie karty wifi w routerach posiadają ten tryb, w końcu to routery bezprzewodowe. Kolejne dwa parametry -- ssid oraz key -- to dane dostępowe określające odpowiednio nazwę sieci i hasło do niej. Każda sieć musi posiadać unikalny identyfikator sieci (ssid). By się połączyć z siecią o danym ssid, trzeba znać hasło (psk), oczywiście tylko w przypadku gdy sieć jest zabezpieczona. Jako, że jest to hasło do naszej sieci, powinno być ono możliwe długie i skomplikowane, bo od niego, w głównej mierze, zależeć będzie bezpieczeństwo sieci.

Mamy do wyboru dwa rodzaje haseł. Jednym z nich jest hasło w postaci czystego tekstu i musi ono posiadać 8-63 znaków. Drugim typem hasła jest ciąg hexalny o długości 64 znaków. Nikomu za bardzo nie chce się wymyślać długich i skomplikowanych haseł ale istnieje narzędzie, które może wygenerować hasło szesnastkowe w oparciu o nazwę sesji (ssid) oraz o jakąś frazę, dajmy na to faktyczne hasło. Nie wiem czy tego typu funkcjonalność jest dostępna pod windowsem, w każdym razie my na linuxie mamy do dyspozycji wpa_passphrase . Poniżej przykład jego wykorzystania:

# wpa_passphrase "Moja siec" "Moje haslo"
network={
        ssid="Moja siec"
        #psk="Moje haslo"
        psk=811339fbba9c799a6216ec3390bd1ae84680242fc0fcc918b0636a3dbe0fd310
}

I w ten sposób, mając słabe hasło, można dość solidnie zabezpieczyć swoją sieć. Przy czym trzeba pamiętać, że ten ciąg zawsze będzie taki sam o ile ssid i hasło nie zostaną zmienione i każdy kto zna te dwie wartości może wygenerować sobie ten 64 znakowy ciąg.

Następna opcja w pliku to encryption . Określa ona sposób zabezpieczenia sieci. Wszystkie dostępne wartości, można znaleźć na http://wiki.openwrt.org/doc/uci/wireless#wpa.modes . Im więcej różnych typów zabezpieczeń określimy, tym więcej urządzeń będziemy mogli podłączyć do sieci -- nie wszystkie z nich, szczególnie te starsze, potrafią obsługiwać obecne standardy szyfrowania. Trzeba także pamiętać o tym, że stosowanie słabszych szyfrów może i odciąży nieco router i da możliwość na podłączenie się większej ilości urządzeń, to jakby nie patrzeć obniża bezpieczeństwo sieci. Jeśli ktoś potrzebuje dobrze zabezpieczyć swoją sieć, to nie ma innego wyboru poza ustawieniem encryption na psk2+aes .

W pliku /etc/config/wireless możemy sprecyzować wiele bloków wifi-iface i nie zawsze wszystkie z nich muszą być aktywne -- możemy je zwyczajnie wyłączyć przy pomocy opcji disabled . Z kolei opcja isolate ma na celu odizolowanie poszczególnych klientów sieci WiFi od siebie, tak by nie mogły się połączyć via WLAN. Ostatnia opcja to maxassoc , która określa ilość klientów, które AP może obsłużyć.
Poniżej jest wynik iwinfo po pomyślnym skonfigurowaniu wifi na routerze Archer C7 v2:

root@the-mountain:~# iwinfo
wlan0     ESSID: "Valar_Morghulis"
          Access Point: C4:6E:1F:95:EF:FC
          Mode: Master  Channel: 36 (5.180 GHz)
          Tx-Power: 10 dBm  Link Quality: unknown/70
          Signal: unknown  Noise: -102 dBm
          Bit Rate: unknown
          Encryption: WPA2 PSK (CCMP)
          Type: nl80211  HW Mode(s): 802.11nac
          Hardware: 168C:003C 0000:0000 [Generic MAC80211]
          TX power offset: unknown
          Frequency offset: unknown
          Supports VAPs: yes  PHY name: phy0
wlan1     ESSID: "Ever_Vigilant"
          Access Point: C4:6E:1F:95:EF:FD
          Mode: Master  Channel: 8 (2.447 GHz)
          Tx-Power: 10 dBm  Link Quality: unknown/70
          Signal: unknown  Noise: -95 dBm
          Bit Rate: unknown
          Encryption: WPA2 PSK (CCMP)
          Type: nl80211  HW Mode(s): 802.11bgn
          Hardware: unknown [Generic MAC80211]
          TX power offset: unknown
          Frequency offset: unknown
          Supports VAPs: yes  PHY name: phy1

9.2.2 WPA2 Enterprise

Jeśli interesują nas bardziej zaawansowane konfiguracje sieci i WPA2 Persolnal nie spełnia naszych oczekiwań, możemy pokusić się do skonfigurowanie naszego routera tak by korzystał z WPA2 Enterprise. Poniżej zostanie opisana jedynie konfiguracja samego AP, wszelkie inne rzeczy związane z postawieniem serwera RADIUS, czy to na routerze, czy na zewnętrznej maszynie, to materiał na inne howto.

Poniżej znajduje się blok kodu, który trzeba dodać do pliku /etc/config/wireless :

config wifi-iface
    option device 'radio0'
    option network 'lan'
    option mode 'ap'
    option ssid 'Winter Is Coming'
    option encryption 'wpa2+aes'
    option key '1846445a84caa742f091efed78e786d9f475cc2538d9315873a920b9c4ffadd1'
    option server '192.168.1.180'
#	option server '127.0.0.1'
    option port '1812'
    option disabled '1'
    option isolate '0'

Większość powyższych opcji jest podobna i pełni takie same funkcje co w przypadku konfiguracji WPA2 Personal, za wyjątkiem opcji key, która w tym przypadku nie określa hasła jako takiego, tylko sekret współdzielony z serwerem RADIUS -- bez niego wszelkie próby przesyłania zapytań od klientów sieci WiFi do RADIUSa będą przez serwer zrzucane. Dodatkowo, musimy zmienić encryption na wpa2+aes . By móc weryfikować zapytania przesyłane do naszego AP, musimy sprecyzować dodatkowo adres IP serwera RADIUS oraz jego port. Jeśli na routerze doinstalujemy odpowiednie oprogramowanie realizujące funkcje RADIUSa, trzeba będzie przekierować zapytania na pętle zwrotną routera (127.0.0.1), na której będzie nasłuchiwał sam RADIUS. W każdym innym przypadku, podajemy adres IP zewnętrznego serwera.

9.2.3 Ukrycie sieci

Część z osób jednak chciałoby także ukryć swoją sieć przed ludźmi, których mają w swoim zasięgu. Generalnie nie da się ukryć sieci, bo bez problemu można ją wykryć i nie trzeba być przy tym specem od WiFi. W każdym razie, w oprogramowaniu OpenWRT jest też dostępna opcja ukrycia sieci, którą możemy dodać do powyższego configu w pliku /etc/config/wireless :

config wifi-iface
    ...
    option hidden '0'

9.2.3 Filtrowanie adresów MAC

Innym pseudo zabezpieczeniem jest filtr adresów MAC. Teoretycznie każde urządzenie sieciowe ma mieć inny adres MAC, tylko co z tego, skoro taki MAC można bez problemu zespoofować? W każdym razie OpenWRT daje też możliwość zdefiniowania adresów MAC, którym należy blokować lub też i zezwalać na dostęp do sieci. Jeśli chcemy korzystać z tego mechanizmu, dopisujemy do pliku /etc/config/wireless te dwie poniższe linijki:

config wifi-iface
    ...
    option macfilter 'disable'
    option maclist '3c:4a:92:00:4c:5b 40:2b:a1:4d:50:7f'

Opcja macfilter może przyjąć trzy wartości: deny, allow oraz disable. W zależności od tego, którą z nich wybierzemy, adresy określone w maclist będą blokowane, dopuszczane lub też ignorowane.

9.2.4 WPS

Wi-Fi Protected Setup (WPS) powstał w celu ułatwienia konfiguracji urządzeń w sieci wifi -- zamiast mozolnie przepisywać 64 znakowe hashe (czy co tam mamy za hasło) i uzupełniać ręcznie pozostałe parametry połączenia, wystarczy wcisnąć dwa przyciski i urządzenie się skonfiguruje samo. Niemniej jednak, wszędzie gdzie nie spojrzeć, ludzie rozpisują się na temat tego jakim to niebezpieczeństwem jest włączenie w routerach wifi opcji WPS. O tych zagrożeniach, jeśli kogoś interesują, można poczytać np. na http://dankaminsky.com/2012/01/26/wps2/ . W skrócie, chodzi o wadliwy pin, który może i ma 8 cyfer ale z racji swojego zaimplementowania, by go złamać potrzeba maks 11000 prób, co można zrobić w parę godzin, najwyżej kilka dni.

Jako radę na całe WPSowskie zło, ludzie radzą wyłączenie tego ficzera zupełnie. Czy to aby nie przesada? Mało się mówi, że ten pin, który narobił tyle zamieszania, nie jest jedyną opcją, która może zostać użyta w setupie WPS -- innym mechanizmem jest PBC (Push Button Connect), czyli przyciśnięcie przycisków na obudowie routera i karcie wifi, o ile te urządzenia są wyposażone we wspomniane przyciski -- nawet jeśli ich nie posiadają, to nie stanowi żadnej przeszkody by zaimplementować funkcjonalny WPS/PBC i uprościć sobie życie w wielu przypadkach.

WPS jest dostępny tylko w konfiguracji WPA2 Personal (PSK) i jeśli chcemy zaimplementować sobie jego obsługę, musimy dopisać poniższy blok do konfiguracji sieci wifi w pliku /etc/config/wireless :

option wps_pushbutton '1'
option wps_device_type '6-0050F204-1'
option wps_config 'push_button'
option wps_device_name 'the-mountain'

Opcja wps_pushbutton aktywuje WPS na routerze -- jeśli sparowaliśmy wszystkie urządzenia, możemy tę funkcjonalność po prostu wyłączyć przestawiając wartość z 1 na 0. Dalej mamy opcję wps_device_type , która określa typ urządzenia i tu mamy do wyboru 1-0050F204-1 (Computer / PC), 1-0050F204-2 (Computer / Server), 5-0050F204-1 (Storage / NAS), 6-0050F204-1 (Network Infrastructure / AP). Kolejną opcją jest metoda użyta przy parowaniu urządzeń -- w tym przypadku trzeba wcisnąć przyciski na obu maszynach. Ostatnia opcja to opis urządzenia.

W przypadku mojego routera, jeden przycisk ma realizować funkcje reset/WPS , z tym że przy domyślnej konfiguracji, na obu moich routerach nie działa opcja WPS. Dlatego też trzeba nieco przeprogramować ten przycisk, tak by WPS w nim został uwzględniony.
Powyższy blok trzeba dopisać do jednego z plików w /etc/rc.button/ , w zależności od tego pod jaką nazwą przycisk jest wykrywany przez router. Sama instrukcja działa w następujący sposób:

Jako, że kolor i nazwa diody WPS może się zmieniać, trzeba ustalić, którą diodę zapalać/gasić. Następnie sprawdzane są warunki -- w zależności od konfiguracji możemy mieć kilka interfejsów, na których życzymy sobie obsługę WPS. W przypadku gdy WPS jest włączony w konfiguracji WiFi w pliku /etc/config/wireless , zostaje on aktywowany i zapalana jest dioda WPS na routerze. Następnie przez 15s w odstępach co 1s sprawdzana jest aktywność WPS. Można sobie dostosować zarówno interwał jak i długość okresu ale nie więcej niż 120s. Po tym jak WPS został aktywowany, mogą wystąpić dwa zdarzenia, albo WPS przejdzie w stan spoczynku z powodu timeouta, bo urządzenie się nie zdąży sprawować w czasie przeznaczonym dla tego procesu, albo też parowanie urządzeń przebiegnie w krótszym czasie niż 15s. W obu przypadkach, nie potrzebujemy już dłużej WPS i może zostać on zdeaktywowany. Następnie gaszona jest również dioda sygnalizując tym samym, że WPS nie jest już dłużej aktywny. Powyższy skrypt działa zarówno na TL-WR1043nd v2 jak i na Archer C7 v2 i pewnie na pozostałych routerach też.

9.3 Tryb STA

Karty WiFi w routerach można także przełączyć w stan STA (station) i uczynić z nich zwykłego klienta sieci WiFi. Nie wszystkie sterowniki potrafią obsługiwać jednocześnie kilka i w tym różnych trybów pracy urządzenia. Opis jak zrobić z routera klienta WiFi oraz jak udostępniać internet hostom nie mając przewodowego połączenia z innym routerem, zostanie opisane w innym howto.

9.4 Tryb MONITOR

Jeśli chcemy przebadać pasmo sieci bezprzewodowej w naszej okolicy, możemy przestawić kartę WiFi routera w tryb monitoringu. W tym celu dopisujemy poniższe linijki do pliku /etc/config/wireless :

config wifi-iface
    option device 'radio0'
    option network 'monitor'
    option mode 'monitor'
    option disabled '0'

Wyżej określone opcje mówią raczej same za siebie i nie trzeba ich dodatkowo opisywać. Dobrze jest jednak mieć w zanadrzu powyższy blok na wypadek gdyby nasza karta WiFi w laptopie czy PC nie potrafiła przełączyć się w tryb monitor. W tym stanie karty, możemy dokonać szeregu testów bezpieczeństwa pod adresem naszej sieci domowej. Dlatego też, jeśli mamy dwa routery i nie posiadamy przy tym innych kart WiFi obsługujących tryb monitor, możemy kartę jednego z routerów przełączyć w ten stan i przebadać w ten sposób naszą sieć. Tylko trzeba będzie doinstalować kilka dodatkowych pakietów dostarczających oprogramowanie realizujące określone funkcje, np. reaver czy aircrack-ng .

9.5 Tryb WDS (most bezprzewodowy)

Ten tryb został dokładnie opisany w osobnym howto, który dostępny jest w tym wątku.

10. Nośniki wymienne (/etc/config/fstab)

Czym by był router bez portów USB? Obecnie chyba wszystkie routery posiadają przy najmniej jeden taki port, co umożliwia podłączenie pendrive, dysku USB, drukarki i innych urządzeń posiadających końcówki USB. W przypadku gdy posiadamy jedn Port USB i chcemy podłączyć dwa (lub więcej) urządzenia, musimy skorzystać z hubów USB. Ja w przypadku swojego routera TP-Link TL-WR1043N/ND v2 mam zastosowane właśnie takie rozwiązanie -- potrzebuję minimum dwa porty USB, a ten router ma tylko jeden.

Trzeba mieć jedną rzecz na uwadze -- jeśli zamontujemy na routerze jakąś partycję, nie możemy wyłączać routera via przycisk na obudowie, czy wyciągać wtyczki z kontaktu. Tego typu akcje mogą uszkodzić dane na tym zewnętrznym nośniku, a już na pewno stracimy część plików w przypadku gdy odłączymy zasilanie podczas dokonywania zapisu danych. Router niczym się praktycznie nie różni w działaniu od zwykłego PC, jest tylko nieco mniejszy i nie ma tych wszystkich podzespołów, które mają standardowe komputery, dlatego też trzeba postępować z nim podobnie jak z PC, a tych nie wyłączamy via przycisk na zasilaczu. Jeśli jednak zapomnimy zdemontować podmontowany system plików, w skrajnych przypadkach może to nawet doprowadzić do uszkodzenia się partycji i trzeba będzie ponownie zakładać nowy system plików, co wyczyści wszelkie dane zgromadzone na tej partycji.

Nie ma się co jednak zniechęcać. Routery nie pobierają znowu aż tak dużo prądu -- jest to wielkość rzędu 3-4W i nawet jeśli chodzą nonstop, nie podniosą znacząco rachunku za prąd. W przypadku gdy chcemy wyłączyć router, możemy to zrobić logując się przez ssh, po czym wpisać w terminalu polecenie poweroff , które to zatrzyma system tego urządzenia -- LED system przestanie migać. Potem możemy wyłączyć router przyciskiem albo przez wyciągnięcie wtyczki.

10.1 Partycjonowanie dysku i tworzenie systemu plików

Windowsy nie dają takiego pola manewru w dzieleniu dysku czy pendrive na partycje jakie dają standardowo wszystkie dystrybucje linuxa. Jeśli potrzebujemy podzielić dysk na partycje, np. pod extroot, czy z jakiegokolwiek innego powodu, możemy to przeprowadzić z poziomu routera. Trzeba tylko doinstalować pakiet fdisk oraz narzędzia, w przypadku ext2,3,4 jest to pakiet e2fsprogs :

# opkg update
# opkg install fdisk e2fsprogs

Odpalmy zatem fdisk i spróbujmy prześledzić proces tworzenia/usuwania partycji. Wpisujemy zatem w terminalu:

# fdisk /dev/sda
Welcome to fdisk (util-linux 2.24.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): m
Help:
  DOS (MBR)
   a   toggle a bootable flag
   b   edit nested BSD disklabel
   c   toggle the dos compatibility flag
  Generic
   d   delete a partition
   l   list known partition types
   n   add a new partition
   p   print the partition table
   t   change a partition type
   v   verify the partition table
  Misc
   m   print this menu
   u   change display/entry units
   x   extra functionality (experts only)
  Save & Exit
   w   write table to disk and exit
   q   quit without saving changes
  Create a new label
   g   create a new empty GPT partition table
   G   create a new empty SGI (IRIX) partition table
   o   create a new empty DOS partition table
   s   create a new empty Sun partition table

Jeśli mamy nowy dysk i nie posiada on jeszcze taliby partycji może ją utworzyć. W zależności od tego czy chcemy tablicę ms-dos czy gpt, wpisujemy odpowiednio o albo g :

Command (m for help): o
Created a new DOS disklabel with disk identifier 0x8c6857e2.
Command (m for help): g
Created a new GPT disklabel (GUID: 304344BE-DF9C-4D9F-BA09-6E661E3FB44A).
By podejrzeć aktualną strukturę dysku wpisujemy [b]p[/b] :
Command (m for help): p
Disk /dev/sda: 14.5 GiB, 15513354240 bytes, 30299520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0005c7f0
Device    Boot     Start       End  Blocks  Id System
/dev/sda1           2048   6293503 3145728  83 Linux
/dev/sda2        6293504  10487807 2097152  83 Linux
/dev/sda3       10487808  26259455 7885824  83 Linux
/dev/sda4       26259456  30298111 2019328   5 Extended
/dev/sda5       26261504  29702143 1720320  83 Linux
/dev/sda6       29704192  30298111  296960  82 Linux swap / Solaris

By skasować partycje, wpisujemy d po czym numer danej partycji:

Command (m for help): d
Partition number (1-6, default 6): 1
Partition 1 has been deleted.
Command (m for help): d   
Partition number (2-6, default 6): 2
Partition 2 has been deleted.
Command (m for help): d
Partition number (3-6, default 6): 3
Partition 3 has been deleted.
Command (m for help): d
Partition number (4-6, default 6): 4
Partition 4 has been deleted.
Command (m for help): p
Disk /dev/sda: 14.5 GiB, 15513354240 bytes, 30299520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0005c7f0

By stworzyć nowe partycje wpisujemy n i uzupełniamy odpowiednio poszczególne parametry:

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-30299519, default 2048): 
Last sector, +sectors or +size{K,M,G,T,P} (2048-30299519, default 30299519): +5G
Command (m for help): p
Disk /dev/sda: 14.5 GiB, 15513354240 bytes, 30299520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0005c7f0
Device    Boot Start       End  Blocks  Id System
/dev/sda1       2048  10487807 5242880  83 Linux

Powyżej stworzyliśmy jedną podstawową partycję o rozmiarze 5GiB.
By zapisać zmiany w tablicy partycji, wpisujemy w . Jeśli z jakichś powodów się pomylimy w obliczeniach, czy zwyczajnie skasujemy nie tę partycję co trzeba, możemy wcisnąć q i zmiany nie zostaną zachowane.

Samo stworzenie partycji to nie wszystko, musimy jeszcze stworzyć system plików na tej partycji. W tym celu odpalamy mkfs.ext4 :

# mkfs.ext4 -m 0 -L extroot /dev/sda5

Standardowo wszystkie linuxy rezerwują 5% wolnego miejsca na partycji na potrzeby użytkownika root. Opcja -m 0 wyłącza rezerwację. Z kolei opcja -L extroot nadaje temu systemu plików odpowiednią etykietę.

Jeśli nie czujemy się komfortowo w operowaniu na konsolowych narzędziach partycjonujących dyski, możemy także dociągnąć pierwszą lepszą dystrybucję linuxa w formie obrazu live, wgrać ten obraz na płytkę albo pendrive, po czym odpalić go i stworzyć potrzebne partycje przy pomocy narzędzi GUI, np. gparted .

Na dysku/pendrive posiadamy partycje mające różne systemy plików, np. ext4 . By móc wejść z nimi w interakcję, musimy doinstalować dodatkowe pakiety. Poniżej znajduje się lista modułów kernela wraz z odpowiadającymi im systemami plików:

# opkg list | grep kmod-fs
kmod-fs-afs - 3.10.49-1 - Kernel module for Andrew FileSystem client support
kmod-fs-autofs4 - 3.10.49-1 - Kernel module for AutoFS4 support
kmod-fs-btrfs - 3.10.49-1 - Kernel module for BTRFS support
kmod-fs-cifs - 3.10.49-1 - Kernel module for CIFS support
kmod-fs-configfs - 3.10.49-1 - Kernel module for configfs support
kmod-fs-cramfs - 3.10.49-1 - Kernel module for cramfs support
kmod-fs-exportfs - 3.10.49-1 - Kernel module for exportfs. Needed for some other modules.
kmod-fs-ext4 - 3.10.49-1 - Kernel module for EXT4 filesystem support
kmod-fs-fscache - 3.10.49-1 - General filesystem local cache manager
kmod-fs-hfs - 3.10.49-1 - Kernel module for HFS filesystem support
kmod-fs-hfsplus - 3.10.49-1 - Kernel module for HFS+ filesystem support
kmod-fs-isofs - 3.10.49-1 - Kernel module for ISO9660 filesystem support
kmod-fs-jfs - 3.10.49-1 - Kernel module for JFS support
kmod-fs-minix - 3.10.49-1 - Kernel module for Minix filesystem support
kmod-fs-msdos - 3.10.49-1 - Kernel module for MSDOS filesystem support
kmod-fs-nfs - 3.10.49-1 - Kernel module for NFS support
kmod-fs-nfs-common - 3.10.49-1 - Common NFS filesystem modules
kmod-fs-nfsd - 3.10.49-1 - Kernel module for NFS kernel server support
kmod-fs-ntfs - 3.10.49-1 - Kernel module for NTFS filesystem support
kmod-fs-reiserfs - 3.10.49-1 - Kernel module for ReiserFS support
kmod-fs-udf - 3.10.49-1 - Kernel module for UDF filesystem support
kmod-fs-vfat - 3.10.49-1 - Kernel module for VFAT filesystem support
kmod-fs-xfs - 3.10.49-1 - Kernel module for XFS support

W przypadku gdy mamy do czynienia z partycjami ext4, to instalujemy pakiet kmod-fs-ext4 , jeśli zaś mamy ntfs, dociągamy kmod-fs-ntfs i tak dalej.

10.2 Block-mount

Jeśli chcemy montować różne dyski czy pendrive w OpenWRT automatycznie, musimy mieć zainstalowany w systemie pakiet block-mount :

# opkg update
# opkg install block-mount

Edytujemy teraz plik /etc/config/fstab -- nie musimy pisać ręcznie całego pliku i uzupełniać wpisów dla każdego podłączonego urządzenia. Możemy wygenerować sobie konfigurację dla podpiętych urządzeń przy pomocy block detect i jego wynik przekierować do pliku /etc/config/fstab :

# block detect > /etc/config/fstab

W przypadku gdy już mamy jakieś wpisy w powyższym pliku, przekierowanie wyjścia block detect nadpisze obecną konfigurację, dlatego też trzeba uważać z tym poleceniem. Możemy też wyświetlić konfigurację urządzeń bez wpisywania ich do pliku, wystarczy usunąć przekierowanie, a wszystko to, co by powędrowało do pliku, zostanie wypisane na konsoli. Jeśli natomiast chcemy sprawdzić UUID oraz typy partycji, możemy to zrobić przez block info :

# block info
/dev/mtdblock2: UUID="d0f4dc60-ed98f2c9-a8662f93-f457db81" VERSION="4.0" TYPE="squashfs"
/dev/mtdblock3: TYPE="jffs2"
/dev/sda1: UUID="6bf4d915-2b62-444e-a2c8-16307769b5c2" LABEL="DEBIAN_LIVE" NAME="EXT_JOURNAL" VERSION="1.0" TYPE="ext4"
/dev/sda3: UUID="738b09f9-e8eb-4332-87a1-0908b3674f5e" LABEL="linux" NAME="EXT_JOURNAL" VERSION="1.0" TYPE="ext4"
/dev/sda5: UUID="9365d879-1715-4346-8fc0-7674684765e7" LABEL="extroot" NAME="EXT_JOURNAL" VERSION="1.0" TYPE="ext4"
/dev/sda6: UUID="1bd99fa0-bba9-453e-b042-1e593082f88e" VERSION="2" TYPE="swap"

Teraz możemy wyedytować plik /etc/config/fstab i wprowadzić małe poprawki co do tego, które partycje mają być montowane automatycznie po wsadzeniu pendrive/dysku do portu USB routera. Te partycje zostaną także zamontowane na przy startowaniu routera.
W pliku /etc/config/fstab mamy sekcję globalną oraz bloki dla poszczególnych partycji/urządzeń, które chcemy montować na routerze. Poniżej są wpisy globalne:

config 'global'
    option  anon_swap       '0'
    option  anon_mount      '0'
    option  auto_swap       '1'
    option  auto_mount      '1'
    option  delay_root      '5'
    option  check_fs        '1'

Opcja anon_swap określa czy montować automatycznie partycje wymiany (SWAP) jeśli te nie są skonfigurowane w powyższym pliku w odpowiednich do tego sekcjach. Czyli jeśli system wykryje partycję SWAP, zamontuje ją automatycznie. Z kolei anon_mount ma podobne znaczenie, z tym, że odnosi się do wszystkich pozostałych typów partycji. Dalej mamy auto_swap oraz auto_mount , które odpowiada za automatyczne montowanie partycji zdefiniowanych w powyższym pliku. Następnie mamy delay_root , który mówi systemowi ile sekund ma czekać by spróbować zamontować partycję z extrootem podczas startu systemu. Na różnych routerach może to zając więcej lub mniej czasu. Jeśli partycja nie zostanie wykryta, system załaduje się z flasha routera. Jeśli jesteśmy pewni, że przeprowadziliśmy konfigurację prawidłowo i nadal extroot nie może się zamontować przy starcie systemu, trzeba zwiększyć wartość tego parametru. Ostatnia opcja to check_fs, która ma za zadanie sprawdzić system plików w poszukiwaniu ewentualnych błędów na partycjach podczas startu systemu.

10.3 Dyski/Pendrive

Bloki dla urządzeń definiujemy w poniższy sposób:

config 'mount'
    option target '/mnt/ftp/sda3'
#   option device '/dev/sda3'
    option uuid '738b09f9-e8eb-4332-87a1-0908b3674f5e'
    option fstype 'ext4'
    option enabled '1'

Punkt montowania określany jest w opcji target. Katalog nie musi istnieć i zostanie stworzony automatycznie podczas montowania zasobu. Następnie wskazujemy systemowi, którą partycję chcemy tam zamontować -- możemy to zrobić, albo przez podanie ścieżki do urządzenia w postaci /dev/sda5 , albo przez podanie UUID. Każde urządzenie czy partycja posiada inny numer identyfikacyjny i w przypadku gdybyśmy wybrali identyfikację na podstawie ścieżek w katalogu /dev/ , kilka różnych urządzeń może zostać zamontowanych w ten sam sposób, co nie zawsze jest pożądanym działaniem. Opcja enabled ustawiona na 0 sprawia, że blok będzie ignorowany.

10.4 Extroot/Fullroot

By rozbudować funkcjonalność routera, potrzebne jest oprogramowanie, a to z kolei zajmuje miejsce. Nie są to może tony GiB jak w przypadku windowsa ale też ciężko jest się czasem zmieścić na 8/16MiB flashu gdzie sporą jego część zajmują preinstalowane pakiety OpenWRT. Jeśli brakuje nam miejsca i mamy przy tym co najmniej jeden wolny port USB, możemy pokusić się o zrobienie extroota.

Extroot pozwala na przeniesienie części (lub całego) systemu routera na zewnętrzny nośnik, np. pendrive. Jak sama nazwa mówi EXTroot posiada system plików z rodziny ext -- domyślny system plików stosowany na linuxach, zatem na pewno będziemy musieli doinstalować pakiety opisane wyżej.

Wpis dla extroot w pliku /etc/config/fstab wygląda następująco:

config 'mount'
#       option target '/'
        option target '/overlay'
#       option device '/dev/sda5'
        option uuid '9365d879-1715-4346-8fc0-7674684765e7'
        option fstype 'ext4'
        option enabled '1'

Opcja target określa gdzie zamontować daną partycję. Jeśli wskażemy /overlay , wtedy wszelkie zmiany jakich dokonujemy w systemie, będą zapisywane na tej partycji. Normalnie były by zapisywane w wolnej przestrzeni flash. Jeśli określimy samo / , wtedy cały system zostanie utworzony na dysku zewnętrznym. Generalnie wystarczy sprecyzować jedynie /overlay . Następnie wskazujemy systemowi, którą partycję chcemy przeznaczyć pod extroot/fullroot . I podobnie jak w przypadku zwykłych partycji, możemy to zrobić przez określenie ścieżek, np. /dev/sda5 lub też przez podanie UUID. Opcja enabled ustawiona na 0 wyłącza extroota.

Extroot ma tę zaletę, że jeśli coś pochrzanimy w konfiguracji, możemy wyciągnąć pendrive z portu USB i załadować funkcjonalny system z flasha routera. Dodatkowo, możemy ten pendrive podmontować na PC w celu przebadania co poszło źle oraz cofnąć określone zmiany -- podobnie jak w przypadku trybu failsafe, z tym, że podczas tej operacji, nasz router posiada całą funkcjonalność, którą mu do tej pory ustawiliśmy. W przypadku failsafe, część usług nie będzie działać. Zatem jeśli przeprowadzamy jakieś eksperymenty z nowym oprogramowaniem, dobrze jest pierw to robić na extroot, jeśli wszystko będzie w porządku, możemy tę funkcjonalność zaimplementować na flashu routera.

Trzeba pamiętać też o kilku ważnych rzeczach jeśli chodzi jeszcze o extroot. Po pierwsze, przy tworzeniu nowego extroota, po zresetowaniu systemu, mamy kompletnie świeży system -- tak jakbyśmy go co dopiero flashowali i całą konfigurację trzeba ustawiać od początku. Druga ważna sprawa to upgrade firmware -- jeśli mamy zamiar dokonać aktualizacji, musimy odłączyć pendrive i uruchomić system z flasha routera i dopiero wtedy przeprowadzić aktualizację. Ostatnia rzecz, to UUID extroota. Narzędzie block-mount tworzy plik /etc/.extroot-uuid na partycji extroot, w którym to umieszcza UUID partycji mtd zawierającej rootfs (jednej z partycji routera). W fazie boot, podczas ładowania extroota, block-mount próbuje sprawdzić aktualną wartość UUID partycji mtd i porównuje ją z tą w pliku /etc/.extroot-uuid i jeśli się różnią, extroot nie zostanie zamontowany. I jeśli chcemy korzystać ze starego extroota po flashowaniu routera, musimy ten plik pierw skasować.

10.5 SWAP

Jeśli mamy na pendrive/dysku partycję wymiany (SWAP) możemy dopisać do /etc/config/fstab odpowiedni wpis, który zamontuje nam tę partycję. W takim przypadku, jeśli router będzie cierpiał na zbyt małą ilość dostępnej pamięci operacyjnej RAM, zamiast się powiesić czy zabijać określone procesy, zacznie zrzucać dane na dysk.

Poniżej przykładowy wpis:

config 'swap'
    option device '/dev/sda3'
    option  uuid    '1bd99fa0-bba9-453e-b042-1e593082f88e'
    option  enabled '1'

Przestrzeń wymiany również możemy określić przez podanie ścieżki do urządzenia w katalogu /dev/ albo po UUID. Możemy także wyłączyć ten blok przez ustawienie opcji enabled na 0.

W przypadku gdy włączymy SWAP, trzeba rozważyć przestawienie jednego parametru kernela. Mowa o /proc/sys/vm/swappiness . Domyślna wartość w tym pliku to 60. Zakres na jakim możemy operować to od 0-100. Im większa wartość tym kernel chętniej zrzuca dane z RAM na dysk. Parametry kernela ustawiamy w pliku /etc/sysctl.conf i dopisujemy tam poniższą linijkę:

vm.swappiness = 30

Aplikujemy zmiany przez wpisanie w terminalu:

# sysctl -p

Oraz sprawdzamy czy zmiany weszły w życie.

# sysctl -a | grep swap vm.swappiness = 30

Od tej pory ten parametr zawsze będzie ustawiany na 30 z każdym startem systemu.

10.6 Partycja /dev/mtdblock3

Mamy także możliwość zamontowania systemu plików routera mając załadowany system z extroota. Dobrze jest pierw sprawdzić w /proc/mtd , która to jest partycja. W przypadku mojego routera wynik prezentuje się następująco:

# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00020000 00010000 "u-boot"
mtd1: 0010e254 00010000 "kernel"
mtd2: 00ec1dac 00010000 "rootfs"
mtd3: 00c40000 00010000 "rootfs_data"
mtd4: 00010000 00010000 "art"
mtd5: 00fd0000 00010000 "firmware"

Interesuje nas rootfs_data , bo to na niej trzymane są wszelkie zmiany, które wprowadzamy w systemie zlokalizowanym na flashu routera. Jeśli chcemy dokonać edycji pliku czy wgrać coś bezpośrednio na flash, możemy zamontować sobie tę partycję i operować na niej jak na każdym innym urządzeniu. Poniżej jest blok, który trzeba dodać do /etc/config/fstab :

config 'mount'
    option target '/overlay-boot'
    option device '/dev/mtdblock3'
    option fstype 'jffs2'
    option enabled '1'

Powyższe opcje powinny być już stosunkowo jasne, zatem nie ma potrzeby ich po raz kolejny opisywać

10.7 Katalog /tmp/

Jako, że router ma niewielki flash, zwykle 8MiB, ciężko jest wyskrobać trochę miejsca na pliki tymczasowe, a tych może być sporo. Dlatego też cały katalog /tmp/ jest zamontowany w pamięci RAM. Dodatkowo szereg plików konfiguracyjnych różnych aplikacji jest dynamicznie tworzonych przy starcie routera i one także wędrują do RAMu by odciążyć możliwie w największym stopniu flash routera, tak by zostało jak najwięcej miejsca pod instalowanie pakietów.

Taki katalog tymczasowy ma rozmiar 50% ilości dostępnej pamięci operacyjnej. Jeśli nam nie odpowiada ta wartość, możemy ją zmienić przez dopisanie do pliku /etc/rc.local poniższej linijki:

mount -t tmpfs -o remount,rw,nosuid,nodev,noatime,size=32M tmpfs /tmp

Skrypt rc.local jest wywoływany na końcu procesu boot routera. To taki swojego rodzaju autostart. Wyżej umieściliśmy wpis, który ma na celu przemontować katalog /tmp/ i ustawić mu rozmiar na 32MiB. To właśnie zmieniając parametr size , możemy manipulować rozmiarem katalogu tymczasowego.

11. Filtr pakietów sieciowych (/etc/config/firewall)

Router posiada wbudowany firewall broniący bezpieczeństwa naszej sieci domowej. Zapora ta realizuje z grubsza trzy rzeczy. Pierwszą z nich jest udostępnianie połączenia sieciowego wielu maszynom wewnątrz sieci domowej. Drugim jej celem jest przepuszczanie ruchu w obu kierunkach do określonych hostów i na określony porty. No i ostatnia sprawa to forwardowanie połączeń pochodzących z internetu, do określonych hostów lokalnych. Wszystkie te trzy zadania realizowane są przez iptables.
System OpenWRT posiada domyślnie skonfigurowany firewall, który przepuszcza wszystko z sieci do internetu, natomiast niekoniecznie to działa tak samo w drugą stronę. Jeśli posiadamy routowalny (zewnętrzny) adres IP, jesteśmy widoczni w internecie i każdy, kto zechce, może się z nami połączyć i tu właśnie do gry wchodzi iptables uniemożliwiając temu komuś na takie zachowanie.

Wszelkie reguły dotyczące zachowania się zapory definiujemy w pliku /etc/config/firewall . Ja orientuję się trochę w samym filtrze iptables, a mimo to miałem (i dalej) mam problemy z ogarnięciem reguł stworzony przez skrypty OpenWRT. Dlatego też znalazłem się w sytuacji, w której musiałem dokonać wyboru -- albo poświęcę mnóstwo czasu na analizę i interpretację tego co wyrzuca polecenie iptables -nvL (dla każdej z 4 tablic), albo zwyczajnie zaimplementować sobie własny filtr, który stworzę od 0. Na to drugie rozwiązanie się zdecydowałem i nie będę tutaj opisywał pliku /etc/config/firewall . Zamiast tego, opiszę procedurę stworzenia własnego filtra, oraz po trochu jego zasadę działania

11.1 Własny filtr iptables

Jak już zapewne zdążyliśmy wyczytać, potrzebny będzie nam dodatkowy skrypt startowy, który załaduje nasz filtr podczas startu routera. Tworzymy zatem pusty plik, do którego będziemy dodawać poniżej opisane reguły. Skryptowi musimy nadać także prawa wykonywania:

touch /etc/init.d/fw
chmod +x /etc/init.d/fw

Edytujemy teraz ten plik i wklejamy do niego standardową zawartość skryptu startowego:

#!/bin/sh /etc/rc.common
START=17
start() {
}
stop() {
}

Kluczową sprawą jest dobór wartości parametru START -- musimy tak ustawić naszą zaporę by załadowała się przed poniesieniem sieci (skrypt /etc/init.d/network). Listując katalog /etc/rc.d/ , możemy zaobserwować, że skrypt od sieci ma numerek 20, zatem nagłówek naszego pliku musi mieć numer niższy, w tym wypadku ustawiliśmy 17. Bloki start() oraz stop() będą wykonywane przy odpalaniu skryptu z opcją start/stop.

Iptables składa się z kilku tablic. Do naszej dyspozycji są: raw, magnle, nat i filter. Ponadto, każda z tablic ma pewien zestaw łańcuchów, w których skład mogą wchodzić: INPUT, OUTPUT, FORWARD, PREROUTING oraz POSTROUTING. Pakiety przychodzące, wychodzące i przechodzące przez router, robią to w ściśle określonej kolejności, którą obrazuje poniższa fotka:

To, którym pakietom zezwolimy na wejście oraz wyjście do/z routera, będziemy określać w tablicy filter, w łańcuchach INPUT oraz OUTPUT. Wszystko co będzie przechodzić przez router, będziemy regulować w łańcuchu FORWARD, też w tej tablicy. Natomiast wszystko to, co związane jest z translacją adresów, będziemy wpisywać do tablicy nat, odpowiednio do łańcuchów PREROUTING/POSTROUTING.

Na każdej maszynie, która ma dostęp do internetu, firewall buduje się w ten sam sposób -- najpierw blokujemy cały ruch pochodzący z zewnątrz sieci do, w tym przypadku, routera. Dodatkowo, blokujemy pakiety przechodzące przez router, czyli te, których przeznaczeniem nie jest ta konkretna maszyna. Z kolei pakiety generowane przez router powinny bez problemu mieć wyjście na świat, także nie ma potrzeby ustawiać domyślnej polityki dla pakietów wychodzących, chyba, że projektujemy jakiś wymyślny serwer, który będzie nadawał tylko na określonych portach, lub mamy niezaufaną sieć domową. Tak czy inaczej, my skupimy się na zbudowaniu zapory, która zabezpieczy dostęp do sieci domowej z zewnątrz.

Ustawiamy domyślną politykę dla łańcuchów:

iptables -t filter -F
iptables -t filter -X
iptables -t filter -P INPUT DROP
iptables -t filter -P FORWARD DROP
iptables -t filter -P OUTPUT ACCEPT

Oczywiście, powyższe linijki wpisujemy do pliku, a nie do terminala, bo to by zaowocowało zerwaniem połączenia.

Zanim nauczymy nasz router forwardować zapytania, musimy go pierw nauczyć jak przetwarzać pakiety, które w ogóle do niego docierają, a te mogą trafić do niego mając określone stany połączenia: NEW, ESTABLISHED i RELATED. Stan NEW identyfikuje pakiety rozpoczynające nowe połączenie, stan ESTABLISHED identyfikuje te pakiety, które należą już do istniejących połączeń, z kolei stan RELATED określa pakiety, które nie są bezpośrednio powiązane już z istniejącymi połączeniami, np. przy protokole FTP. Cała magia dotycząca śledzenia połączeń odbywa się w pliku /proc/net/nf_conntrack i to na podstawie tych wpisów kernel wie, które pakiety odnoszą się do konkretnych połączeń.

Każdy pakiet TCP ma dodatkowo ustawione flagi, które określają dokładnie co to jest za rodzaj pakietu, np. czy ma on na celu otwarcie nowego połączenia czy też np. jest to potwierdzenie przesłania pewnej ilości danych z jednego hosta do drugiego. Są pewne określone sekwencje flag, które umożliwiają komunikację sieciową, niemniej jednak, można tymi flagami dowolnie manipulować i takimi wykutymi pakietami można dokonywać skanowania portów w poszukiwaniu usług sieciowych, np. SSH, co zwykle może się skończyć atakiem, w przypadku gdy określona usługa zostanie przez atakującego wykryta. Na szczęście istnieje jeden pseudo stan pakietu -- INVALID , w którym to są zdefiniowane wszystkie nieprawidłowe kombinacje flag. Dzięki takiej opcji, mamy możliwość odfiltrować tego typu pakiety. Niemniej jednak, stan INVALID nie zabezpieczy nas całkowicie przed skanami portów.

Reasumując, musimy zezwolić na przetwarzanie pakietów w stanie ESTABLISHED oraz RELATED , zrzucać pakiety w stanie INVALID i manipulować pakietami w stanie NEW . Zatem dopisujemy poniższe linijki do pliku zapory:

iptables -t filter -N tcp
iptables -t filter -N udp
iptables -t filter -N icmp_in
iptables -t filter -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -t filter -A INPUT -m conntrack --ctstate INVALID -j DROP
iptables -t filter -A INPUT -i lo -j ACCEPT
iptables -t filter -A INPUT -p icmp -m conntrack --ctstate NEW -j icmp_in
iptables -t filter -A INPUT -p udp -m conntrack --ctstate NEW -j udp
iptables -t filter -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j tcp
iptables -t filter -A INPUT -p tcp -j REJECT --reject-with tcp-reset
iptables -t filter -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
iptables -t filter -A INPUT -j REJECT --reject-with icmp-proto-unreachable

Powyżej została też uwzględniona pętla zwrotna (to ta linijka z "-i lo"), której komunikację trzeba przepuścić -- są to pakiety lokalne, które nie wychodzą poza router. Jeśli jakaś usługa nasłuchuje na 127.0.0.0/8 , żaden inny host, za wyjątkiem localhosta, nie może z nią nawiązać połączenia. W przypadku gdybyśmy zablokowali ten ruch, pewne procesy systemowe mogą przestać działać.

Stworzyliśmy także sobie trzy nowe łańcuchy: tcp, udp i icmp_in -- po jednym dla tych ważniejszych protokołów i odpowiednio przekierowaliśmy do nich ruch.

Ostatnie trzy reguły zajmują się zwracaniem odpowiednich komunikatów hostom, które próbowały się połączyć z jakąś usługą nasłuchującą na naszym routerze ale jej nie zastały -- być może była wyłączona, być może nigdy nie istniała i dostaliśmy zwykły skan portu.
Zwykle routery mają kilka interfejsów sieciowych, w tym przypadku mam do dyspozycji jeden WAN (eth0) oraz jeden LAN (br-lan). Usługi dla tych interfejsów trzeba konfigurować osobno, tj. jeśli jakaś usługa, np. SSH ma być widoczna w internecie, trzeba uwzględnić w konfiguracji iptables -i eth0 , natomiast jeśli będziemy się łączyć do shella tylko lokalnie, wtedy precyzujemy opcję -i br-lan. Z kolei, jeśli jakaś usługa ma być dostępna zarówno w internecie jak i na lanie, ten parametr możemy pominąć.

Jako, że w założeniu mamy iż sieć domowa jest zaufana, zezwolimy wszystkim jej maszynom na dostęp do routera do wszystkich usług, w tym też i do SSH:

iptables -t filter -A icmp_in -p icmp -i br-lan -s 192.168.1.0/24 -j ACCEPT
iptables -t filter -A tcp -p tcp -i br-lan -s 192.168.1.0/24 -j ACCEPT
iptables -t filter -A udp -p udp -i br-lan -s 192.168.1.0/24 -j ACCEPT

Przy czym, trzeba zauważyć, że powyższe reguły przepuszczają pakiety w stanie NEW. Pozostała komunikacja z routerem odbywa się za pomocą wcześniej sprecyzowanej reguły, czyli -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT . Pakiety w stanie NEW pochodzące z innego interfejsu niż br-lan w dalszym ciągu są blokowane, a bez nich nie da rady otworzyć połączenia, tak by pakiety w stanach RELATED i ESTABLISHED mogły zostać przesłane.

Jeśli byśmy chcieli zezwolić na ping routera lub też jeśli chcielibyśmy mieć możliwość logowania się na shella spoza sieci domowej, możemy dopisać poniższe linijki:

iptables -t filter -A icmp_in -p icmp -i eth0 -j ACCEPT
iptables -t filter -A tcp -p tcp -i eth0 -m tcp --dport 22 -j ACCEPT

Gdybyśmy wystartowali teraz nasz skrypt, mielibyśmy dostęp tylko do routera. Nie działa jeszcze forwardowanie pakietów -- zarówno od/do tych maszyn znajdujących się za routerem, jak i również między dwoma hostami samej sieci domowej.

By połączyć się z internetem z maszyny znajdującej się za routerem, musimy nakazać naszemu routerowi, by w miejsce adresu w nagłówku pakietu wpisywał swój adres jako adres źródłowy ale tylko w przypadku gdy pakiety nie są adresowane bezpośrednio do niego. W tym celu możemy użyć, albo -j SNAT , albo -j MASQUERADE . Pierwszy z nich powinien być używany w przypadku jeśli router ma stały adres IP, drugi zaś jeśli to IP się zmienia. Choć można używać także MASQUERADE ze stałym IP. Poniżej przykład zastosowania obu z nich, musimy wybrać jeden, w zależności od konfiguracji routera:

iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 -j SNAT --to-source 22.33.44.55
iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 -j MASQUERADE

Kluczowe w ustawianiu translacji adresów jest określenie interfejsu, przez który pakiety mają wychodzić do internetu, w tym przypadku jest to interfejs WAN (eth0). Jeśli korzystamy z -j SNAT, ustawiamy zewnętrzny adres, który został przypisany interfejsowi eth0.

By móc się połączyć ze światem oraz z innymi komputerami w sieci, musimy jeszcze dodać odpowiednie wpisy w łańcuchu FORWARD, w tablicy filter w pliku zapory:

iptables -t filter -N fw-interfaces
iptables -t filter -N fw-open
iptables -t filter -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -t filter -A FORWARD -m conntrack --ctstate INVALID -j DROP
iptables -t filter -A FORWARD -m conntrack --ctstate NEW -j fw-interfaces 
iptables -t filter -A FORWARD -m conntrack --ctstate NEW -j fw-open
iptables -t filter -A FORWARD -j REJECT --reject-with icmp-host-unreachable

Podobnie jak w przypadku łańcuchu INPUT, pozwalamy przechodzić pakietom w stanie RELATED i ESTABLISHED, zrzucamy pakiety w stanie INVALID i manipulujemy pakietami w stanie NEW. Ten ruch w stanie NEW, przechodzi odpowiednio dwa inne łańcuchy: fw-interfaces oraz fw-open . W pierwszym z nich są definiowane interfejsy routera, między którymi pakiety mogą przechodzić, np. z br-lan do eth0 lub, co zapewni łączność z internetem oraz komunikację między hostami w sieci domowej. W drugim łańcuchu zaś są definiowane regułki przekierowujące ruch do określonych maszyn za routerem.

Dodajemy do łańcucha fw-interfaces w pliku firewalla poniższą linijkę:

iptables -t filter -A fw-interfaces -i br-lan -s 192.168.1.0/24 -j ACCEPT

Teraz już powinien działać zarówno internet jak i komunikacja pomiędzy hostami w sieci. By zweryfikować czy aby faktycznie wszystko działa jak należy, przy pomocy polecenia ping odpytujemy jakiś host w internecie oraz host w naszej sieci. Dobrze jest to robić po adresie IP, by wyeliminować ewentualne problemy związane z rozwiązywaniem nazw (DNS).

Jeśli będziemy chcieli przekierować ruch z internetu na maszynę za routerem, możemy to zrobić posługując się -j DNAT. W tym celu do pliku firewalla dodajemy poniższe wpisy:

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 22222 -j DNAT --to-destination 192.168.1.150:22222
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 22222 -j DNAT --to-destination 192.168.1.150:22222
iptables -t filter -A fw-open -i eth0 -o br-lan -d 192.168.1.150 -p tcp --dport 22222 -j ACCEPT
iptables -t filter -A fw-open -i eth0 -o br-lan -d 192.168.1.150 -p udp --dport 22222 -j ACCEPT

Adres określony w --to-destination , to oczywiście adres maszyny, do której mają trafić pakiety po przekierowaniu. Z kolei, port widniejący po dwukropku, to port na hoście docelowym, na którym nasłuchuje jakaś usługa. W pierwszych dwóch linijkach mamy także opcje --dport 22222 określającą na jaki port w routerze będą przychodzić pakiety z internetu, które trzeba będzie przesłać do maszyny za routerem. Z kolei dwie ostatnie linijki umożliwiają przejście tym pakietom z interfejsu eth0 na br-lan .

Porty w --dport i --to-destination w pierwszych dwóch linijkach nie koniecznie muszą być takie same. Natomiast wartość określona w --to-destination musi być taka sama co w --dport w dwóch ostatnich linijkach. W przypadku braku zdefiniowania portu po dwukropku (po adresie) w pierwszych dwóch linijkach, zostanie ustawiony taki sam port jak w opcji --dport .

Konfiguracja maszyny otrzymywana od ISP zwykle jest przesyłana za pomocą protokołu DHCP, musimy zatem też zezwolić na komunikację z upstreamowym serwerem DHCP, jeśli nie znamy jego adresu IP, to wystarczy dopisać poniższe linijki:

iptables -t filter -A udp -p udp --sport 68 --dport 67 -s 0.0.0.0 -d 255.255.255.255 -j ACCEPT -m comment --comment "DHCP-broadcast"
iptables -t filter -A udp -p udp --dport 68 -j ACCEPT -m comment --comment "Allow-DHCP-Renew"

Jeśli znamy adres serwera DHCP, możemy dodatkowo posłużyć się parametrem -s i uwzględnić w tych regułach adres źródłowy, co dodatkowo zwiększy bezpieczeństwo sieci.

Reasumując powyższe informacje, potrzebny nam skrypt powinien się prezentować mniej więcej tak:

#!/bin/sh /etc/rc.common
START=17
start() {
    iptables -t filter -F
    iptables -t filter -X
    iptables -t filter -P INPUT DROP
    iptables -t filter -P FORWARD DROP
    iptables -t filter -P OUTPUT ACCEPT
    iptables -t filter -N tcp
    iptables -t filter -N udp
    iptables -t filter -N icmp_in
    iptables -t filter -N fw-interfaces
    iptables -t filter -N fw-open
    iptables -t filter -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    iptables -t filter -A INPUT -m conntrack --ctstate INVALID -j DROP
    iptables -t filter -A INPUT -i lo -j ACCEPT
    iptables -t filter -A INPUT -p icmp -m conntrack --ctstate NEW -j icmp_in
    iptables -t filter -A INPUT -p udp -m conntrack --ctstate NEW -j udp
    iptables -t filter -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j tcp
    iptables -t filter -A INPUT -p tcp -j REJECT --reject-with tcp-reset
    iptables -t filter -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
    iptables -t filter -A INPUT -j REJECT --reject-with icmp-proto-unreachable
    iptables -t filter -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    iptables -t filter -A FORWARD -m conntrack --ctstate INVALID -j DROP
    iptables -t filter -A FORWARD -m conntrack --ctstate NEW -j fw-interfaces 
    iptables -t filter -A FORWARD -m conntrack --ctstate NEW -j fw-open
    iptables -t filter -A FORWARD -j REJECT --reject-with icmp-host-unreachable
    iptables -t filter -A icmp_in -p icmp -i br-lan -s 192.168.1.0/24 -j ACCEPT
    
    iptables -t filter -A tcp -p tcp -i br-lan -s 192.168.1.0/24 -j ACCEPT
    
    iptables -t filter -A udp -p udp -i br-lan -s 192.168.1.0/24 -j ACCEPT
    iptables -t filter -A udp -p udp --sport 68 --dport 67 -s 0.0.0.0 -d 255.255.255.255 -j ACCEPT -m comment --comment "DHCP-broadcast"
    iptables -t filter -A udp -p udp --dport 68 -j ACCEPT -m comment --comment "Allow-DHCP-Renew"
    iptables -t filter -A fw-interfaces -i br-lan -s 192.168.1.0/24 -j ACCEPT
#	iptables -t filter -A fw-open -i eth0 -o br-lan -d 192.168.1.150 -p tcp --dport 22222 -j ACCEPT
#	iptables -t filter -A fw-open -i eth0 -o br-lan -d 192.168.1.150 -p udp --dport 22222 -j ACCEPT
#	iptables -t filter -A icmp_in -p icmp -i eth0 -j ACCEPT
#	iptables -t filter -A tcp -p tcp -i eth0 -m tcp --dport 22 -j ACCEPT
    iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 -j SNAT --to-source 22.33.44.55
#	iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 -j MASQUERADE
#	iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 22222 -j DNAT --to-destination 192.168.1.150
#	iptables -t nat -A PREROUTING -i eth0 -p udp --dport 22222 -j DNAT --to-destination 192.168.1.150
}
stop() {
}

Znak # na początku linii oznacza komentarz, czyli, że dana reguła nie zostanie dodawana do filtra przy wywołaniu skryptu -- dostosować według potrzeb.

Blok start() mamy z głowy, teraz jeszcze przydałoby się coś naskrobać w bloku stop(). Musimy tak zaprojektować iptables, by przy wywoływaniu skryptu z opcją stop, komunikacja została przerwana ale bez tracenia bezpośredniego połączenia z routerem. Nic trudnego, wystarczy usunąć wszystkie niestandardowe reguły, a te podstawowe przepisać na interfejs br-lan , przykładowo:

stop() {
    for TABLE in \
        "-t raw" \
        "-t mangle" \
        "-t filter" \
        "-t nat"
    do
        iptables $TABLE -F
        iptables $TABLE -X
    done
    iptables -t filter -N tcp
    iptables -t filter -N udp
    iptables -t filter -P INPUT DROP
    iptables -t filter -P FORWARD DROP
    iptables -t filter -A INPUT -i br-lan -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    iptables -t filter -A INPUT -i lo -j ACCEPT
    iptables -t filter -A INPUT -i br-lan -p icmp -m conntrack --ctstate NEW -j ACCEPT
    iptables -t filter -A INPUT -i br-lan -p udp -m conntrack --ctstate NEW -j ACCEPT
    iptables -t filter -A INPUT -i br-lan -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j ACCEPT
    iptables -t filter -A INPUT -p tcp -j REJECT --reject-with tcp-reset
    iptables -t filter -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
    iptables -t filter -A INPUT -j REJECT --reject-with icmp-proto-unreachable
}

I w taki sposób mamy dwa bloki potrzebne skryptowi startowemu do prawidłowego działania. Z tym, że OpenWRT ma swój domyślny filtr pakietów w /etc/init.d/firewall i trzeba ten skrypt wyłączyć z autostartu routera, w przeciwnym razie, nasze ustawienia mogą zostać nadpisane. Skrypt wyłączamy przez:

# /etc/init.d/firewall disable

Dodajemy teraz nasz skrypt, który będzie ustawiał regułki za każdym razem gdy router będzie się budził do życia:

# /etc/init.d/fw enable

Jeśli wszystko przeprowadziliśmy zgodnie z powyższym opisem, router powinien się załadować po zresetowaniu. Komunikacja między hostami w sieci powinna działać, tak samo jak i internet powinien.

11.2 Ustawianie odpowiedniego TTL dla pakietów

Czasem niektórzy ISP z jakiegoś bliżej nieokreślonego powodu blokują dostęp do internetu hostom zlokalizowanym za routerem. Z grubsza, ISP blokuje, albo konkretny TTL pochodzący od hostów w sieci, albo ogranicza TTL do jednego hopa wszystkim pakietom dochodzącym do routera z jego strony. Jeśli mamy nieszczęście trafić na takiego ISP, możemy przy pomocy iptables ustawić/podbić/zmniejszyć TTL pakietów, które docierają do routera zarówno od strony LAN jak i WAN i tym samym bez większego trudu sobie poradzić tą blokadą.

Każdy system operacyjny ma skonfigurowaną domyślną wartość TTL dla wszystkich pakietów tworzonych na obsługiwanym przez ten system maszynie. Dla windowsów jest to 128, a dla linuxów, w tym też i OpenWRT, jest to 64. Tą wartość możemy oczywiście zweryfikować wydając na routerze poniższe polecenie:

# sysctl -a | grep ttl
net.ipv4.ip_default_ttl = 64

Niemniej jednak, powyższe ustawienie dotyczy wyłącznie pakietów tworzonych na routerze i nie ma wpływu na pakiety przechodzące przez niego z/do sieci/internetu.
W przypadku forwardowania pakietów, routery zmniejszają wartość TTL o 1, czyli otrzymując pakiet od maszyny linuxowej, po przetworzeniu go, będzie on wysłany do następnego routera czy hosta z TTL=63. W przypadku ISP obniżających TTL do 1, router otrzyma pakiet z TTL=1, po czym obniży wartość tego pola do 0 i jeśli pakiet nie jest przeznaczony dla routera, ten musi go zniszczyć.

By poradzić sobie z tą niedogodnością, musimy doinstalować dodatkowy moduł iptables:

# opkg update
# opkg install iptables-mod-ipopt kmod-ipt-ipopt

Edytujemy teraz wcześniej stworzony skrypt firewalla i dodajemy do niego poniższe linijki w bloku start() :

iptables -t mangle -I PREROUTING -i eth0 -m ttl --ttl-lt 2 -j TTL --ttl-inc 1
iptables -t mangle -I PREROUTING -i br-lan -m ttl --ttl-eq 64 -j TTL --ttl-inc 1
iptables -t mangle -I PREROUTING -i br-lan -m ttl --ttl-eq 128 -j TTL --ttl-inc 1

Pierwsza linijka sprawdza wszystkie pakiety przychodzące z internetu (interfejs eth0) i próbuje je dopasować w oparciu o pole TTL w nagłówku IP. Jeśli TTL jest ustawiony na mniejszy od 2 (-m ttl --ttl-lt 2), to pole zostanie przepisane i zwiększony zostanie numerek o 1 (-j TTL --ttl-inc 1).

Pozostałe dwie linijki sprawdzają pakiety pochodzące z sieci lokalnej (interfejs br-lan) pod kątem standardowych TTL dla systemów operacyjnych (-m ttl --ttl-eq 64, dla linuxa oraz -m ttl --ttl-eq 128 dla windowsa) i podobnie jak wyżej, w przypadku dopasowania, TTL jest zwiększany o 1.

Potrzebujemy, albo pierwszej, albo dwóch ostatnich linijek i to, która znajdzie zastosowanie w naszym wypadku możemy sprawdzić przez dodanie pierwszej z nich do iptables -- jeśli pakiety będą uderzać w tą regułę, znaczy, że ISP obniżył TTL do wartości 1. W przeciwnym wypadku, musimy skorzystać z pozostałych wpisów.

12. Dodatkowe usługi

OpenWRT, poza standardowymi pakietami, daje możliwość doinstalowania całej masy innych aplikacji. Poniżej zostanie opisanych kilka tych bardziej użytecznych.

12.1 Serwer wydruku (/etc/config/p910nd)

Jeśli posiadamy drukarkę, z tym, że taką której nie można podłączyć do sieci i wymaga ona obecności jakiegoś komputera, który ją w tej sieci dopiero udostępni, możemy skorzystać z oprogramowania routera i jednego z jego portów USB, by wyeliminować potrzebę posiadania dedykowanego PC udostępniającego drukarkę -- od tej pory będzie to robił router.

Aby wdrożyć u siebie taką funkcjonalność, musimy doinstalować odpowiednie pakiety -- p910nd, kmod-usb-printer oraz kmod-usb-uhci :

# opkg update
# opkg install p910nd kmod-usb-printer kmod-usb-uhci

Konfiguracja serwera p910nd odbywa się przez plik /etc/config/p910nd i nie mamy tam zbytnio wiele do roboty. Poniżej zawartość tego pliku:

config p910nd
    option device        /dev/usb/lp0
# port 9100 + the following number 
    option port          0
    option bidirectional 1
    option enabled       1

Teraz wystarczy wystartować skrypt startowy i włączyć drukarkę. W logu routera (odczytany przez logread albo dmesg) powinniśmy zanotować wpis podobny do tego poniżej:

[ 1990.870000] usb 1-1.2: new full-speed USB device number 4 using ehci-platform
[ 1991.010000] usblp 1-1.2:1.0: usblp0: USB Bidirectional printer dev 4 if 0 alt 0 proto 2 vid 0x04B8 pid 0x0005

Jeśli mamy dostęp do urządzenia /dev/usb/lp0 , oznacza to, że drukarka została wykryta przez router. By coś za jej pomocą wydrukować, na hoście w sieci trzeba ją pierw dodać.
Na linuxach standardowo jest dostępny CUPS, który udostępnia panel www, przez który to można dodać i skonfigurować drukarkę. Standardowo adres tego panelu jest dostępny pod localhost:631 . Odpalamy zatem przeglądarkę i przechodzimy pod wskazany adres.

Klikamy na zakładkę administracji i dodajemy nową drukarkę:

Wybieramy opcję AppSocket/HP JetDirect:

I w wpisujemy socket://192.168.1.1:9100 .

Opisujemy drukarkę:

Wybieramy producenta drukarki:

oraz jej model:

Ustawiamy także domyślne opcje dla wydruku:

I po chwili drukarka powinna być gotowa do pracy:

Jeśli chcemy przetestować czy wszystko działa jak należy, odpalamy jakiś edytor tekstu i z menu wybieramy "drukuj":

Jak widzimy wyżej, drukarka została odnaleziona, a po ikonce z lewej strony możemy stwierdzić, że jest to drukarka sieciowa.

Drukujemy przykładowy dokument:

Powyżej widzimy, że plik został zakolejkowany i jest aktualnie przetwarzany przez drukarkę. Po chwili zadanie zostanie ukończone i drukarka wypluje zadrukowaną kartkę:

12.2 Wake-On-LAN (/etc/config/etherwake)

Nasz router potrafi także wybudzać maszyny w swojej sieci. Wake-On-LAN nie działa przez internet, jedynie, jak sama nazwa sugeruje, w sieci LAN, a to z tego względu, że potrzebny jest broadcast, a routery nie forwardują pakietów rozgłoszeniowych. Oczywiście, nic nie stoi na przeszkodzie by zalogować się na router via SSH i wybudzić jakąś maszynę z poziomu routera. Wszystkie komputery, które chcemy budzić muszą mieć odpowiednią płytę główną i prawdopodobnie wszystkie nowsze płyty już taką właściwość posiadają. Dodatkowo, trzeba w BIOSie ustawić odpowiednie opcje. Ważną rzeczą jest by nie wyłączać PC przyciskiem w obudowie (lub na zasilaczu), bo wtedy nie będzie możliwe wybudzenie maszyny, nawet po dostarczeniu zasilania. Wyłączenia maszyny musimy dokonać z poziomu systemu operacyjnego, tylko wtedy WOL zadziała.
Mając przygotowany hardware oraz BIOS, możemy przejść do oprogramowania. Instalujemy zatem na routerze etherwake.

# opkg update
# opkg install etherwake

Konfiguracja powyższego narzędzia znajduje się w pliku /etc/config/etherwake . Nas głównie interesują poniższe wpisy:

config 'etherwake' 'setup'
    option 'interface' 'br-lan'
    option 'broadcast' 'off'
config 'target'
        option 'name' 'the-mountain'
        option 'mac' '00:16:e6:34:c4:e0'
#       option 'password' 'AABBCCDDEEFF'
        option 'wakeonboot' 'off'

Przy pomocy opcji interface określamy interfejs, przez który router będzie wysyłał pakiety budzące maszyny -- ustawiamy go na lokalny. Dalej niby jest linijka z broadcast ale tak na dobrą sprawę to nikt nie wie co ona robi -- bez znaczenia czy jest on czy off i tak pakiety będą wysyłane na adres rozgłoszeniowy 255.255.255.255. Możemy także zdefiniować wiele bloków target i w każdym z nich, w opcji mac podajemy adres MAC maszyny, którą chcemy wybudzić. Z kolei zaś name ułatwi nam wybudzanie przy pomocy skryptu:

# /etc/init.d/etherwake start the-mountain
/etc/init.d/etherwake: Waking up the-mountain via /usr/bin/etherwake -i br-lan -b 00:16:e6:34:c4:e0

Opcja wakeonboot umożliwia budzenie konkretnej maszyn wraz z startowaniem routera.

Jeśli chcemy budzić maszyny wraz ze wstawaniem routera, dodajemy skrypt do autostartu:

# /etc/init.d/etherwake enable

12.3 NFS

Za pomocą sieciowego systemu plików NFS (Network File System) maszyny mające na pokładzie linuxa, w tym tez OpenWRT, są w stanie udostępniać w sieci różne zasoby. Z tym, że ten system plików, to głównie domena linuxów -- do windowsów jest SAMBA. Udostępnianie zasobów via NFS jest bardzo podobne do opisanego na początku SSHFS, z tym, że określamy hosty/sieci, którym zezwalamy na możliwość montowania konkretnych katalogów routera. NFS nie jest w żaden sposób szyfrowany i by zabezpieczyć transmisję, to albo trzeba skorzystać z SSHFS, albo opakować NFS w SSH ale o tym kiedy indziej.

By nasz router mógł stać się serwerem NFS, trzeba doinstalować poniższy pakiet:

# opkg update
# opkg install nfs-kernel-server

NFS wykorzystuje do swojego działania portmap (jest pociągany w zależnościach), zatem by nam to poprawnie działało musimy włączyć dwie usługi:

# /etc/init.d/portmap enable
# /etc/init.d/nfsd enable

Zasoby, które użytkownicy będą mogli u siebie na komputerach montować, precyzujemy w pliku /etc/exports w postaci:

/mnt/ftp/sda3 192.168.1.0/24(rw,no_subtree_check,all_squash,anongid=1000,anonuid=1000)

Każda zmiana tego pliku musi zostać zaaplikowana na serwerze nfsd przez przeładowanie konfiguracji via:

# exportfs -ar

W powyższej linijce najpierw określamy katalog do udostępnienia (/mnt/ftp/sda3), następnie mamy sprecyzowaną sieć (192.168.1.0/24), której maszyny będą mieć prawo zamontować ten zasób. Wszystko co w nawiasie, to opcje montowania.
Opcja rw oznacza, że dany katalog po zamontowaniu może być zapisywany przez hosty. Można zamiast rw określić ro, za sprawą którego zasób zostanie udostępniony w trybie tylko do odczytu. Można także sprecyzować opcję sync , z tym, że czasem transfer może być katastrofalnie wolny, tak jak to ma miejsce w moim przypadku, dlatego też nie korzystam z tego parametru. Dalej mamy no_subtree_check, który to przyśpiesza operacje w przypadku gdy cały zasób zostaje podmontowany na maszynie klienckiej. Z kolei opcje all_squash,anongid=1000,anonuid=1000 odpowiadają za mapowanie numerków użytkownika/grupy. Jeśli system plików został zamontowany z uwzględnieniem tych 3 opcji, wszystkie nowo utworzone pliki/katalogi na kliencie, po przemapowaniu będą miały odpowiednio ustawiony UID/GID na routerze, w tym przypadku 1000. W systemach linuxowych ten ID oznacza pierwszego zwykłego użytkownika, utworzonego przy instalowaniu systemu operacyjnego. Zatem jeśli pliki na routerze zostaną przemapowane na numerki 1000/1000 , mój użytkownik na linuxie będzie miał do nich swobodny dostęp za każdym razem gdy podmontuje ten katalog routera u siebie na PC.

By zamontować zasób NFS na kliencie, potrzebne są prawa roota, chyba, że korzystamy z pakietu udevil lub innych podobnych, które obchodzą te restrykcje i umożliwiają zwykłemu użytkownikowi podmontowanie katalogów sieciowych. W każdym razie, montowanie odbywa się w poniższy sposób:

# mount -t nfs 192.168.1.1:/mnt/ftp/sda3 /media/ftp/
$ udevil mount -t nfs 192.168.1.1:/mnt/ftp/sda3 /media/ftp/

12.4 FTP

Usługa FTP jest wygodniejszym rozwiązaniem w przypadku gdy chcemy korzystać z zasobów udostępnianych przez router zarówno na linuxach jak i na windowsach. Jedyne czego potrzebujemy to kawałek przeglądarki albo innego klienta ftp. Nie ma też przy tym znaczenia system plików udostępnianych via protokół FTP. Jedyne co nas interesuje, to postawienie serwera na routerze i podanie klientom namiarów na niego. Trzeba tylko pamiętać o tym, że serwer FTP może przyjmować połączenia w trybie aktywnym i pasywnym -- równice między tymi dwoma są dokładnie opisane na http://www.eioba.pl/a/1mof/aktywny-i-pasywny-tryb-ftp .

Instalujemy pierw pakiet vsftpd , ewentualnie vsftpd-tls , który posiada obsługę szyfrowanego kanału TLS. Niemniej jednak, szyfrowany ftp to zagadnienie na osobny howto.

# opkg update
# opkg install vsftpd

Konfiguracja vsftpd jest trzymana w pliku /etc/vsftpd.conf i domyślnie mamy już określonych kilka opcji. Musimy nieco przerobić ten config, tak by praca z vsftpd była nieco prostsza. Zanim jednak przejdziemy do edycji głównego pliku konfiguracyjnego, utwórzmy kilka innych plików i katalogów:

# mkdir /etc/vsftpd/
# mkdir /etc/vsftpd/secure_chroot
# mkdir /etc/vsftpd/users
# touch /etc/vsftpd/userlist
# touch /etc/vsftpd/users/anonymous
# touch /etc/vsftpd/users/ftp
# touch /etc/vsftpd/users/morfik

Uzupełniamy te pliki odpowiednio, tak by ich zawartość prezentowała się w poniższy sposób:

# cat /etc/vsftpd/userlist 
morfik
ftp
anonymous
# cat /etc/vsftpd/users/anonymous 
write_enable=no
# cat /etc/vsftpd/users/ftp 
write_enable=no
# cat /etc/vsftpd/users/morfik 
write_enable=yes

Czyścimy główny plik konfiguracyjny serwera (/etc/vsftpd.conf) i dopisujemy tam poniższe parametry:

secure_chroot_dir=/etc/vsftpd/secure_chroot
userlist_enable=yes
userlist_deny=no
userlist_file=/etc/vsftpd/userlist
user_config_dir=/etc/vsftpd/users

Parametr secure_chroot_dir określa pusty katalog, do którego będą chrootowani użytkownicy w momencie gdy vsftpd nie będzie potrzebował dostępu do systemu plików. Dodatkowo ten katalog nie może być zapisywalny przez użytkownika ftp (o nim będzie nieco niżej). Dalej mamy 3 opcje z userlist. Pierwsze dwie (userlist_enable oraz userlist_deny) definiują zachowanie listy sprecyzowanej w pliku określonym przez opcję userlist_file . Jeśli userlist_deny zostanie ustawiony na NO, wtedy lista posłuży jako loginy, za pomocą których będzie można się logować do ftpa. Jeśli ta opcja zostanie ustawiona na YES, wtedy loginy znajdujące się na tej liście będą odrzucane z automatu. Ostatnia opcja (user_config_dir) określa katalog z plikami konfiguracyjnymi poszczególnych loginów. Powyżej sprecyzowaliśmy 3 loginy: anonymous, ftp oraz morfik. Konfiguracja w tych plikach nadpisze odpowiednie opcje w globalnym pliku konfiguracyjnym ale tylko dla tych określonych loginów.
W plikach loginów mamy póki co wpisaną jedną opcję write_enable . Określa ona czy dany login po zalogowaniu się na ftpa ma przyznane prawa do zapisu. Loginy ftp oraz anonymous tych praw są pozbawione.

Definiujemy także parametry dla połączenia:

listen=yes
background=yes
listen_address=192.168.1.1
listen_port=21
pasv_min_port=50990
pasv_max_port=50999
max_clients=20
max_per_ip=2
idle_session_timeout=300
connect_from_port_20=yes
port_enable=no
#local_max_rate=
#anon_max_rate=

Pierwsze cztery parametry ustawiają nasłuchującego daemona vsftpd na adresie 192.168.1.1:21 , czyli wszyscy z sieci lokalnej będą mieli możliwość wbić na tego ftpa. Kolejne dwa parametry (pasv_min_port oraz pasv_max_port) określają zakresy portów, z których może skorzystać serwer w trybie pasywnym. Jeśli chcemy ograniczyć maksymalną ilość połączeń jaką może utrzymywać serwer ftp, ustawiamy max_clients , dodatkowo możemy także wprowadzić restrykcje co do ilości połączeń z jednego adresu IP via max_per_ip . Następny parametr (idle_session_timeout) definiuje czas pomiędzy poleceniami, który zdalny użytkownik może spędzić bez rozłączania go -- po 300 sekundach bezczynności, takie połączenie zostanie zakończone. Dalej mamy connect_from_port_20 , który to określa port dla transferu danych po stronie serwera FTP. W przypadku ustawienia tej opcji na NO, daemon jest odpalony z nieco mniejszymi uprawnieniami, co zwiększa trochę bezpieczeństwo samego serwera. Z kolei opcja port_enable definiuje czy klienci mogą się łączyć w trybie aktywnym do serwera FTP. Jeśli ustawimy ją na NO, wtedy pozostanie im jedynie tryb pasywny połączenia. Ostatnie dwa parametry ograniczają transfer dla użytkowników lokalnych (local_max_rate) i anonimowych (anon_max_rate), przy tym te parametry są definiowane w bajtach na sekundę i nie ma możliwości określenia K,M,G.

Ustawiamy również logowanie zdarzeń:

syslog_enable=yes
log_ftp_protocol=yes

Musimy także określić domyślne uprawnienia dla tworzonych na ftpie plików:

file_open_mode=0666
anon_umask=0000
local_umask=0022

Domyślną maską dla wszystkich plików przesyłanych na ftp jest 0666 i od tego odpowiednio odejmujemy 0000 i 0022 otrzymując w ten sposób prawa do nowych plików 666 oraz 644 dla anonimowych i lokalnych użytkowników.

Poniższy blok dotyczy konfiguracji użytkowników anonimowych:

anonymous_enable=yes
ftp_username=ftp
anon_root=/mnt/ftp
anon_mkdir_write_enable=no
anon_other_write_enable=no
anon_upload_enable=no
anon_world_readable_only=no
no_anon_password=yes

Przy pomocy opcji anonymous_enable możemy wyłączyć możliwość logowania użytkownikom anonimowym -- ftp oraz anonymous . Jeśli zezwolimy im na dostęp do ftpa, będą oni rozpoznawani w systemie jako użytkownik ftp. Po zalogowaniu, zostaną także przeniesieni do katalogu określonego w anon_root . Opcja anon_mkdir_write_enable określa czy użytkownik anonimowy będzie miał możliwość tworzenia katalogów na ftpie -- by to zadziałało, musi być włączona opcja write_enable (w plikach loginów). Z kolei parametr anon_other_write_enable precyzuje możliwość usuwania plików z ftpa i zmieniania ich nazw. Dalej mamy anon_upload_enable , przy pomocy którego możemy zezwolić użytkownikom anonimowym na wysyłanie plików na ftp -- działa gdy write_enable jest ustawiony oraz wymagane są prawa zapisu dla użytkownika ftp do pożądanych katalogów. Kolejny parametr to anon_world_readable_only i określa on czy anonimowi użytkownicy będą widzieć pliki, których atrybut odczytu nie jest ustawiony globalnie. Ostatni parametr wyłącza pytanie o hasło w przypadku anonimowych użytkowników.

Poniżej mamy konfigurację użytkowników lokalnych, tych dostępnych na routerze:

local_enable=yes
chroot_local_user=no
check_shell=no

Parametr local_enable określa czy loginy lokalnych użytkowników (tych określonych w /etc/passwd) mogą być wykorzystane do zalogowania się na ftpa -- ta opcja musi być włączona nawet w przypadku korzystania z userlist . Z kolei chroot_local_user chrootuje lokalnych użytkowników i zamyka ich w katalogach domowych, co niesie ze sobą sporo problemów z bezpieczeństwem w przypadku gdy mają oni prawa do umieszczania plików na ftpie albo dostęp do shella, dlatego też lepiej jest ustawić tę opcję na NO. W przypadku ustawienia parametru check_shell na NO, plik /etc/shells nie zostanie przeszukany w celu odnalezienia poprawnych powłok systemowych i za sprawą tego rozwiązania, użytkownicy systemowi, którzy posiadają shella ustawionego na /bin/false (lub podobnego), będą mogli się zalogować na ftpie -- poprawia to trochę bezpieczeństwo samego serwera, bo użytkownicy wykorzystywani do logowania się na ftpie, nie mogą poruszać się w systemie routera nie mając przy tym ustawionego poprawnego shella.

W pliku konfiguracyjnym możemy sprecyzować jeszcze wiele opcji, poniżej zaś są te częściej spotykane:

download_enable=yes
chmod_enable=yes
dirlist_enable=yes
dirmessage_enable=yes
#message_file=
hide_ids=no
ftpd_banner=ftp server ready
#banner_file=
use_localtime=yes

Opcja download_enable włącza możliwość pobierania plików z ftpa, a przy pomocy parametru chmod_enable możemy zmieniać uprawnienia do plików -- anonimowi użytkownicy nigdy z tej opcji skorzystać nie będą mogli. Przy pomocy parametru dirlist_enable możemy przeglądać pliki i katalogi na serwerze. Z kolei dirmessage_enable daje możliwość wyświetlenia wiadomości przy przechodzeniu do określonych folderów w drzewie katalogów na ftpie. Taki katalog jest przeszukiwany pod kątem pliku .message i to jego treść jest wyświetlana klientowi. Jeśli nam nie odpowiada domyślna nazwa pliku .message , możemy ją zmienić przez wpisanie nowej nazwy w parametrze message_file . Opcja hide_ids , jeśli ustawiona na YES, ukrywa UID/GID plików przy listowaniu katalogów -- ustawia je na ftp/ftp. Dwie kolejne opcje ustawiają banner, który jest wyświetlany klientowi przy podłączeniu do serwera. Możemy napisać kilka słów w opcji ftpd_banner albo też oddelegować do tego zadania plik określony w parametrze banner_file. Ostatnia opcja ustawia w logu listingu katalogów czas strefy lokalnej systemu, zamiast czasu UTC.

Katalogi, które chcemy udostępnić pod ftp określonym użytkownikom definiujemy w pliku /etc/passwd w poniższy sposób:

# cat /etc/passwd
ftp:*:55:55:ftp:/mnt/ftp:/bin/false
morfik:*:1000:1000:morfik:/mnt/ftp:/bin/false

Dla wszystkich dodatkowych użytkowników, musimy określić hasło dostępu -- trzeba je ustawić w systemie routera. Hashe haseł będą przechowywane w pliku /etc/passwd . By je dodatkowo zabezpieczyć (chodzi o prawa odczytu pliku z hasłami) musimy odpowiednio edytować plik /etc/shadow i dodać tam wpis z loginem od ftpa:

# cat /etc/shadow
ftp:*:0:0:99999:7:::
morfik:*:0:0:99999:7:::

Powyższy krok nie jest jednak wymagany.
Dodajemy także poniższy wpis do pliku /etc/group :

morfik:x:1000:

Teraz już tylko ustawiamy hasło:

root@the-mountain:~# passwd  morfik
Changing password for morfik
New password:
Retype password:
Password for morfik changed by root

W moim przypadku zarówno użytkownicy anonimowi jak i wszyscy dodatkowi użytkownicy będą operować na katalogu /mnt/ftp -- to jest główny katalog mojego serwera. Jeśli chcemy oddelegować inny katalog dla użytkowników anonimowych możemy określić jeden z podkatalogów via parametr anon_root , np. anon_root=/mnt/ftp/anon .

Zapisujemy konfigurację i startujemy serwer:

# /etc/init.d/vsftpd start

Teraz już potrzebujemy jedynie odpalić klienta ftp i spróbować podłączyć się do serwera w celu sprawdzenia czy konfiguracja jest poprawna. Ja korzystałem z programu filezilla :

Użytkownik anonimowy zdaje się logować bez problemu. Możemy również przetestować usuwanie/dodawanie plików, zmiany nazw i inne ustawienia, które precyzowaliśmy wyżej, by się upewnić czy aby na pewno użytkownik anonimowy ma minimum praw.
Sprawdzamy także login ustawiony w pliku /etc/vsftpd/userlist :

Login morfik również działa. Jeśli wszystko zostało poprawnie skonfigurowane, ten użytkownik ma prawo usuwać pliki, zmieniać ich nazwy i wgrywać pliki na ftp.
Wszelkie komunikaty z przeprowadzanych operacji możemy odczytać w logread, bo mamy ustawione opcje logowania. Również klienty ftp udostępniają część z tych wiadomości. Zatem jeśli są problemy to wystarczy prześledzić log by namierzyć ich przyczynę.

Jeśli wszystko działa jak należy, parametry syslog_enable oraz log_ftp_protocol możemy zahashować w pliku /etc/vsftpd.conf by nie obciążać dodatkowo bez potrzeby samego routera.

12.5 Statystyki

Generowanie statystyk funkcji życiowych routera (i nie tylko), zostało dokładnie opisane w tym poście.

13 QoS (Quality of Service)

Każdy chyba spotkał się z sytuacją, w której chciał sobie w spokoju przeglądać strony w internecie i z jakiegoś powodu nie było mu to dane. Generalnie rzecz biorąc, w olbrzymiej części przypadków winna jest sieć p2p, bo albo to my pobieramy coś na torrencie i dlatego mamy problemy z przeglądaniem internetu, albo ktoś inny z sieci akurat w tej chwili pobiera/wysyła jakieś pliki. Oczywiście nie musi to być wina tylko i wyłącznie programów torrentowych. Gdy sami korzystamy z łącza, to nie stanowi większego problemu -- odpalamy torrenta gdy nie przeglądamy stron na necie, a w przypadku gdy zachodzi potrzeba wejścia na fejsa, to wyłączamy odpowiednie programy by zminimalizować opóźnienia.

Jak zatem ograniczyć problemy związane z siecią p2p? Możemy na routerze zaimplementować QoS (Qality of Service), czyli nadać pewnym usługom odpowiednie priorytety. Obecnie w OpenWRT nie ma prostego sposobu na wdrożenie QoSa. Wcześniej były do dyspozycji interfejsy IMQ ale te zostały zastąpione przez interfejsy IFB. Jest też do dyspozycji inne rozwiązanie ale to z kolei wymaga nowszego kernela, którego nie ma póki co w BB. Także pozostaje nam jedynie zabawa z interfejsami IFB. By zorganizować całe przedsięwzięcie, potrzebny nam będzie także własny filtr iptables, którego stworzenie od podstaw opisałem tutaj

Mając już przygotowany firewall, przechodzimy do instalacji potrzebnych pakietów:

# opkg update
# opkg install tc iptables-mod-conntrack-extra kmod-ipt-conntrack-extra iptables-mod-extra kmod-sched kmod-ifb

Teraz musimy stworzyć skrypt startowy, dokładny opis jak to zrobić,został umieszczony tutaj. Poniżej jest szkielet pliku, który wykorzystamy:

#!/bin/sh /etc/rc.common
START=17
EXTRA_COMMANDS="status"
IF_WAN="eth0" 
status() {
}
start() {
}
stop() {
}

W każdym z tych trzech bloków musimy umieścić odpowiednie wpisy. Poniżej znajduje się blok status:

status() {
    echo "### Statistics ###"
    echo "# qdiscs $IF_WAN #"
    tc -s qdisc show dev $IF_WAN
    echo "# qdiscs ifb0 #"
    tc -s qdisc show dev $IF_WAN
    echo "# qdiscs ifb1 #"
    tc -s qdisc show dev $IF_WAN
    
    echo "# class $IF_WAN #"
    tc -s class show dev $IF_WAN
    echo "# class ifb0 (out) #"
    tc -s class show dev ifb0
    echo "# class ifb1 (in) #"
    tc -s class show dev ifb1
 
    echo "# filter #"
    tc -s filter show dev $IF_WAN root
    tc -s filter show dev $IF_WAN parent 1:
    tc -s filter show dev $IF_WAN parent 11:
    echo "# filter ifb0 #"
    tc -s filter show dev ifb0
    echo "# filter ifb1 #"
    tc -s filter show dev ifb1
}

Są to generalnie statystyki i inne informacje przydatne przy diagnozowaniu konfiguracji QoS, którą stworzyliśmy.

Poniżej znajduje się blok stop :

stop() {
    tc qdisc del dev $IF_WAN root 2>&1
    tc qdisc del dev ifb0 root 2>&1
    tc qdisc del dev ifb1 root 2>&1
    tc qdisc del dev $IF_WAN ingress 2>&1
    ifconfig ifb0 down
    ifconfig ifb1 down
    iptables -t mangle -D POSTROUTING -j CONNMARK --restore-mark
    iptables -t mangle -D POSTROUTING -m mark ! --mark 0 -j ACCEPT
    iptables -t mangle -D POSTROUTING -o eth0 -j qos_egress
    iptables -t mangle -D POSTROUTING -j CONNMARK --save-mark
    iptables -t mangle -F qos_egress
    iptables -t mangle -X qos_egress
}

Ma on za zadanie wyczyścić całą konfigurację stworzoną przy pomocy narzędzia tc oraz również usuwa wpisy dodane przez blok start.

Niżej zostaną opisane linijki wykorzystane w bloku start. Oczywiście kształt tego bloku może się różnić w zależności od gabarytów łącza oraz od tego jakie jego proporcje chcemy oddać do dyspozycji pod określone usługi. Trzeba także będzie określić politykę QoS, tj. czy chcemy aby każdy z użytkowników naszej sieci miał do dyspozycji określony limit łącza poza który nie może wyjść, czy też skupimy się na nadaniu priorytetów określonym usługom i ten drugi model właśnie zostanie zaprezentowany tutaj.

Kolejki na interfejsach

Na sam początek musimy przygotować interfejs. Każdy interfejs ma dwie kolejki -- jedną na pakiety przychodzące i drugą na pakiety wychodzące. Problem z tym całym QoS jest taki, że możemy jedynie efektywnie kontrolować kolejkę wychodzącą i zbytnio nie mamy wpływu na to ile pakietów z zewnątrz ktoś nam przysyła. W tym drugim przypadku, to jaki transfer zostanie ustalony zależy od protokołu TCP, który przy utracie pakietów informuje drugą stronę by ta zmniejszyła tempo nadawania. Niemniej jednak, nie mamy kontroli nad tym, które pakiety trafią jako pierwsze do kolejki przychodzącej na interfejsie.
Poniższe wpisy tworzą dwa interfejsy wirtualne i są one doczepione do interfejsu WAN, bo to ten ruch chcemy poddać obróbce:

tc qdisc add dev $IF_WAN parent root handle 1:0 htb
tc filter add dev $IF_WAN parent 1:0 protocol ip prio 10 u32 match ip dst 0.0.0.0/0 flowid 1:1 action mirred egress redirect dev ifb0
tc qdisc add dev $IF_WAN handle ffff: ingress
tc filter add dev $IF_WAN parent ffff: protocol ip prio 10 u32 match ip src 0.0.0.0/0 flowid 2:1 action mirred egress redirect dev ifb1

Ruch wychodzący z routera został przekierowany do interfejsu ifb0 , natomiast wszystko co będzie docierać z internetu do routera, trafi do interfejsu ifb1 .
Następnie tworzymy kolejki dla obu powyższych interfejsów. Ja stworzyłem bliźniacze kolejki tak by ich konfiguracja była nieco prostsza. Jedynie co, to różnią się numerkami oraz oczywiście przepustowością, bo moje łącze to 15/1mbit.

tc qdisc add dev ifb0 root handle 1:0 htb default 40 r2q 10
    tc class add dev ifb0 parent 1:0 classid 1:1 htb rate 980kbit ceil 980kbit
        tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 480kbit ceil 980kbit prio 0
        tc class add dev ifb0 parent 1:1 classid 1:20 htb rate 200kbit ceil 980kbit prio 2
        tc class add dev ifb0 parent 1:1 classid 1:30 htb rate 150kbit ceil 980kbit prio 4
        tc class add dev ifb0 parent 1:1 classid 1:40 htb rate 150kbit ceil 980kbit prio 5
tc qdisc add dev ifb1 root handle 2:0 htb default 40 r2q 100
    tc class add dev ifb1 parent 2:0 classid 2:1 htb rate 14800kbit ceil 14800kbit
        tc class add dev ifb1 parent 2:1 classid 2:10 htb rate 3500kbit ceil 14800kbit prio 0
        tc class add dev ifb1 parent 2:1 classid 2:20 htb rate 3000kbit ceil 14800kbit prio 2
        tc class add dev ifb1 parent 2:1 classid 2:30 htb rate 5800kbit ceil 14800kbit prio 4
        tc class add dev ifb1 parent 2:1 classid 2:40 htb rate 2500kbit ceil 14800kbit prio 5

Jak widzimy wyżej, na każdym z interfejsów została utworzona kolejka główna opiewająca na 980kbit w przypadku uploadu oraz 14800kbit downloadu. Powyżej wspomniałem, że mam łącze 15/1mbit ale takiej prędkości nigdy nie uzyskam, a to przez specyfikację drugiej warstwy module OSI, która dodaje nagłówki do przesyłanych danych i jest tego około 2,5% przesyłanego payloadu. Zatem jeśli mamy łącze 100mbitów, wartość, którą musimy wziąć pod uwagę to około 97mbitów i to tę liczbę trzeba wpisać w odpowiednie miejsce w kolejce głównej. Kolejka, którą utworzymy, musi być najwęższym ogniwem w procesie przesyłu informacji. Tylko w taki sposób będą się u nas zbiera pakiety na interfejsach. Jeśli dokonamy złych obliczeń i ustawimy zbyt wielkie wartości, kolejki będą się tworzyć na interfejsach u naszego ISP i to on będzie zarządzał ruchem a nie nasz router, a chcemy przecie osiągnąć coś zupełnie przeciwnego. Zatem 15/1mbitów to odpowiednio 15360 i 1024kbity i ja ustawiłem kolejki główne na nieco niższe wartości niż po odjęciu tych domyślnych 2,5%.

Następnie dla każdej kolejki głównej tworzymy, w tym przypadku, cztery pomniejsze kolejki i to one zajmą się ogarnianiem określonego ruchu. Każda kolejka (klasa) ma numer identyfikacyjny (classid) i jest do czegoś przyporządkowana (parent). Kolejki można zagnieżdżać, tak jak to zostało zrobione wyżej. Numery są dowolne, z tym, że nie mogą się powtarzać. Parametr rate ustala gwarantowaną przepustowość dla konkretnej kolejki. Suma tego parametru ze wszystkich klas podrzędnych nie może przekraczać wartości określonej w głównej kolejce, co jest oczywiste. Parametr ceil z kolei określa ile dana kolejka może sobie zapożyczyć w przypadku gdy inne kolejki nie są obciążone. Jeśli wartości rate i ceil wynoszą tyle samo, kolejka nie będzie pożyczać. Opcja prio określa pierwszeństwo kolejek przy uzyskiwaniu nowego przydziału w przypadku gdy zezwalamy na pożyczanie, tj. ta kolejka, która ma niższy numer prio będzie bardziej uprzywilejowana. Opcja default, określona w głównej kolejce, definiuje gdzie zostaną przesłane pakiety, które nie zostały przypisane do żadnej z klas, tj. ruch, który nie złapie się na kolejki 1:10, 1:20, 1:30, zostanie przesłany do kolejki 1:40.

Oznaczanie i kierowanie ruchu wychodzącego

Mamy zatem podzielony interfejs i utworzone klasy. Teraz musimy jakoś skierować ruch do tych kolejek. Jeśli chodzi o ruch wychodzący, to mamy do dyspozycji cały szereg opcji i możemy oznaczać ruch przez iptables i jego odpowiednie moduły. Natomiast jeśli chodzi o ruch przychodzący, to jedyne co to pozostaje nam selektor u32, który nie jest zbyt user friendly.

Na początek zajmijmy się oznaczeniem ruchu wychodzącego. tworzymy zatem szereg linijek dla filtra iptables:

iptables -t mangle -N qos_egress
iptables -t mangle -A POSTROUTING -j CONNMARK --restore-mark
iptables -t mangle -A POSTROUTING -m mark ! --mark 0 -j ACCEPT
iptables -t mangle -A POSTROUTING -o eth0 -j qos_egress
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark
iptables -t mangle -A qos_egress -p tcp -m multiport --dports 80,443 -j MARK --set-mark 1
iptables -t mangle -A qos_egress -p tcp -m multiport --dports 80,443 -j RETURN
iptables -t mangle -A qos_egress -p tcp -m multiport --dports 993,143,465,5222,5223 -j MARK --set-mark 2
iptables -t mangle -A qos_egress -p tcp -m multiport --dports 993,143,465,5222,5223 -j RETURN
iptables -t mangle -A qos_egress -p udp -m multiport --dports 37,123,53 -j MARK --set-mark 3
iptables -t mangle -A qos_egress -p udp -m multiport --dports 37,123,53 -j RETURN
iptables -t mangle -A qos_egress -p icmp -j MARK --set-mark 3
iptables -t mangle -A qos_egress -p icmp -j RETURN 

Pierwsza linijka tworzy dodatkowy łańcuch w iptables, który zajmie się oznaczaniem pakietów. Następne dwie linijki odpowiadają za akceptowanie już oznaczonych pakietów, tak by nie przepisywać ich marków jeszcze raz, co zajmuje cenne zasoby. W przypadku gdy pakiet nie posiada ustawionego marka, czyli gdy ten wynosi 0, jest kierowany do łańcucha qos_egress i tam w zależności od ustawionych opcji, nadawane są stosowne oznaczenia. W tym przypadku ruch www (http, https) będzie oznaczony numerem 1. Ruch pocztowy oraz komunikator jabber zostaną oznaczone numerkiem 2. Z kolei wszystkie pakiety protokołu ICMP oraz ntp i dns zostaną oznaczone markiem 3. Po tym jak oznaczenie zostanie nadane pakietowi, ten zostanie zwrócony do łańcucha wyżej (linijka z -j RETURN) i tam zostanie zapisane to oznaczenie dla całego połączenia, tak by kolejne pakiety przypisane do tego połączenia zostały złapane przez drugą regułę i nie musiały dodatkowo oznaczać w iptables. Ja w tym przykładzie skorzystałem jedynie z -m multiport ale rozszerzeń w iptables są dziesiątki i każde z nich może posłużyć do oznaczenia pakietów.

Ruch wychodzący mamy oznaczony. Teraz musimy go przekierować do utworzonych wcześniej kolejek:

tc filter add dev ifb0 parent 1:0 prio 50 protocol ip handle 1 fw flowid 1:10
tc filter add dev ifb0 parent 1:0 prio 20 protocol ip handle 2 fw flowid 1:20
tc filter add dev ifb0 parent 1:0 prio 60 protocol ip handle 3 fw flowid 1:30

Jest wiele metod by przesłać pakiety do odpowiednich kolejek, w tym przypadku skorzystałem z filtra udostępnianego przez narzędzie tc. Kluczowe rolę odgrywa tutaj handle oraz flowid . Pierwszy z tych dwóch zajmuje się wyłapywaniem pakietów posiadających mark 1, 2, 3, etc, natomiast drugi z nich, kierowaniem tych pakietów do kolejek 1:10, 1:20, 1:30, etc i tam już te pakiety są odpowiednio kształtowane i upychane w kolejce wychodzącej na interfejsie WAN.

Oznaczanie i kierowanie ruchu przychodzącego

Ruch wychodzący mamy z głowy, nie było z nim praktycznie żadnego problemu. Natomiast ruch przychodzący już nam trochę trudności przysporzy. Pakiety, które docierają do naszego routera, będziemy kierować do odpowiednich kolejek bezpośrednio, bez oznaczania ich w iptables, bo tego nie da się zrobić wykorzystując interfejsy IFB. W tym przypadku zostanie wykorzystany selektor u32. Musimy zatem utworzyć reguły dla tych bardziej uprzywilejowanych portów:

tc filter add dev ifb1 parent 2:0 protocol ip prio 3 u32 match ip protocol 1 0xff flowid 2:30
tc filter add dev ifb1 parent 2:0 protocol ip prio 4 u32 match ip sport 53 0xff flowid 2:30
tc filter add dev ifb1 parent 2:0 protocol ip prio 5 u32 match ip sport 37 0xffff classid 2:30
tc filter add dev ifb1 parent 2:0 protocol ip prio 5 u32 match ip sport 123 0xffff classid 2:30
tc filter add dev ifb1 parent 2:0 protocol ip prio 20 u32 match ip sport 993 0xffff classid 2:20
tc filter add dev ifb1 parent 2:0 protocol ip prio 20 u32 match ip sport 143 0xffff classid 2:20
tc filter add dev ifb1 parent 2:0 protocol ip prio 20 u32 match ip sport 465 0xffff classid 2:20
tc filter add dev ifb1 parent 2:0 protocol ip prio 35 u32 match ip sport 5222 0xffff classid 2:20
tc filter add dev ifb1 parent 2:0 protocol ip prio 35 u32 match ip sport 5223 0xffff classid 2:20
tc filter add dev ifb1 parent 2:0 protocol ip prio 80 u32 match ip sport 80 0xffff classid 2:10
tc filter add dev ifb1 parent 2:0 protocol ip prio 80 u32 match ip sport 443 0xffff classid 2:10

Filter narzędzia tc ma do dyspozycji wiele dopasowań (match). Jeśli chcemy oznaczyć ruch danego protokołu, możemy wykorzystać ip protocol , podobnie postępujemy z portem źródłowym (ip sport), portem docelowym (ip dport), czy też adresem źródłowym (ip src) lub adresem docelowym (ip dst). Dopasowania można łączyć. Jeśli popatrzymy na powyższe regułki, wiemy, że ruch z protokołu ICMP, który będzie docierał do naszego routera, będzie szedł do kolejki 2:30, podobnie z ruchem ntp i dns. Z kolei ruch pocztowy i jabbera, zostanie przesłany do kolejki 2:20, i podobnie z ruchem www -- zostanie przesłany do kolejki 2:10. I to wszystko co możemy zrobić -- przez ograniczenie pasma, możemy poinformować tę drugą stronę by ograniczyła ilość pakietów, które przesyła do naszego routera. Przy czym, trzeba pamiętać, że nie mamy kontroli nad tym, które pakiety zostaną przepuszczone przez interfejs jako pierwsze. Dlatego też, możemy nieco przyciąć rozmiar kolejki na interfejsach. Ja zmieniłem również domyślną długość kolejki dla pakietów wychodzących:

ifconfig ifb0 txqueuelen 8
ifconfig ifb1 txqueuelen 8

Cały skrypt QoS, wygląda zatem tak:

#!/bin/sh /etc/rc.common
START=17
EXTRA_COMMANDS="status"
IF_WAN="eth0" 
status() {
    echo "### Statistics ###"
    echo "# qdiscs $IF_WAN #"
    tc -s qdisc show dev $IF_WAN
    echo "# qdiscs ifb0 #"
    tc -s qdisc show dev $IF_WAN
    echo "# qdiscs ifb1 #"
    tc -s qdisc show dev $IF_WAN
    
    echo "# class $IF_WAN #"
    tc -s class show dev $IF_WAN
    echo "# class ifb0 (out) #"
    tc -s class show dev ifb0
    echo "# class ifb1 (in) #"
    tc -s class show dev ifb1
 
    echo "# filter #"
    tc -s filter show dev $IF_WAN root
    tc -s filter show dev $IF_WAN parent 1:
    tc -s filter show dev $IF_WAN parent 11:
    echo "# filter ifb0 #"
    tc -s filter show dev ifb0
    echo "# filter ifb1 #"
    tc -s filter show dev ifb1
}
start() {
    ifconfig ifb0 up
    ifconfig ifb1 up
    
    ifconfig ifb0 txqueuelen 8
    ifconfig ifb1 txqueuelen 8
    iptables -t mangle -N qos_egress
    iptables -t mangle -A POSTROUTING -j CONNMARK --restore-mark
    iptables -t mangle -A POSTROUTING -m mark ! --mark 0 -j ACCEPT
    iptables -t mangle -A POSTROUTING -o eth0 -j qos_egress
    iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark
    iptables -t mangle -A qos_egress -p tcp -m multiport --dports 80,443 -j MARK --set-mark 1
    iptables -t mangle -A qos_egress -p tcp -m multiport --dports 80,443 -j RETURN
    iptables -t mangle -A qos_egress -p tcp -m multiport --dports 993,143,465,5222,5223 -j MARK --set-mark 2
    iptables -t mangle -A qos_egress -p tcp -m multiport --dports 993,143,465,5222,5223 -j RETURN
    iptables -t mangle -A qos_egress -p udp -m multiport --dports 37,123,53 -j MARK --set-mark 3
    iptables -t mangle -A qos_egress -p udp -m multiport --dports 37,123,53 -j RETURN
    iptables -t mangle -A qos_egress -p icmp -j MARK --set-mark 3
    iptables -t mangle -A qos_egress -p icmp -j RETURN
    tc qdisc add dev $IF_WAN parent root handle 1:0 htb
    tc filter add dev $IF_WAN parent 1:0 protocol ip prio 10 u32 match ip dst 0.0.0.0/0 flowid 1:1 action mirred egress redirect dev ifb0
    tc qdisc add dev $IF_WAN handle ffff: ingress
    tc filter add dev $IF_WAN parent ffff: protocol ip prio 10 u32 match ip src 0.0.0.0/0 flowid 2:1 action mirred egress redirect dev ifb1
    tc qdisc add dev ifb0 root handle 1:0 htb default 40 r2q 10
        tc class add dev ifb0 parent 1:0 classid 1:1 htb rate 980kbit ceil 980kbit
            tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 480kbit ceil 980kbit prio 0
            tc class add dev ifb0 parent 1:1 classid 1:20 htb rate 200kbit ceil 980kbit prio 2
            tc class add dev ifb0 parent 1:1 classid 1:30 htb rate 150kbit ceil 980kbit prio 4
            tc class add dev ifb0 parent 1:1 classid 1:40 htb rate 150kbit ceil 980kbit prio 5
    tc qdisc add dev ifb1 root handle 2:0 htb default 40 r2q 100
        tc class add dev ifb1 parent 2:0 classid 2:1 htb rate 14800kbit ceil 14800kbit
            tc class add dev ifb1 parent 2:1 classid 2:10 htb rate 3500kbit ceil 14800kbit prio 0
            tc class add dev ifb1 parent 2:1 classid 2:20 htb rate 3000kbit ceil 14800kbit prio 2
            tc class add dev ifb1 parent 2:1 classid 2:30 htb rate 5800kbit ceil 14800kbit prio 4
            tc class add dev ifb1 parent 2:1 classid 2:40 htb rate 2500kbit ceil 14800kbit prio 5
    tc filter add dev ifb0 parent 1:0 prio 50 protocol ip handle 1 fw flowid 1:10
    tc filter add dev ifb0 parent 1:0 prio 20 protocol ip handle 2 fw flowid 1:20
    tc filter add dev ifb0 parent 1:0 prio 60 protocol ip handle 3 fw flowid 1:30
    tc filter add dev ifb1 parent 2:0 protocol ip prio 3 u32 match ip protocol 1 0xff flowid 2:30
    tc filter add dev ifb1 parent 2:0 protocol ip prio 4 u32 match ip sport 53 0xff flowid 2:30
    tc filter add dev ifb1 parent 2:0 protocol ip prio 5 u32 match ip sport 37 0xffff classid 2:30
    tc filter add dev ifb1 parent 2:0 protocol ip prio 5 u32 match ip sport 123 0xffff classid 2:30
    tc filter add dev ifb1 parent 2:0 protocol ip prio 20 u32 match ip sport 993 0xffff classid 2:20
    tc filter add dev ifb1 parent 2:0 protocol ip prio 20 u32 match ip sport 143 0xffff classid 2:20
    tc filter add dev ifb1 parent 2:0 protocol ip prio 20 u32 match ip sport 465 0xffff classid 2:20
    tc filter add dev ifb1 parent 2:0 protocol ip prio 35 u32 match ip sport 5222 0xffff classid 2:20
    tc filter add dev ifb1 parent 2:0 protocol ip prio 35 u32 match ip sport 5223 0xffff classid 2:20
    tc filter add dev ifb1 parent 2:0 protocol ip prio 80 u32 match ip sport 80 0xffff classid 2:10
    tc filter add dev ifb1 parent 2:0 protocol ip prio 80 u32 match ip sport 443 0xffff classid 2:10
}
stop() {	
    tc qdisc del dev $IF_WAN root 2>&1
    tc qdisc del dev ifb0 root 2>&1
    tc qdisc del dev ifb1 root 2>&1
    tc qdisc del dev $IF_WAN ingress 2>&1
    
    ifconfig ifb0 down
    ifconfig ifb1 down
    iptables -t mangle -D POSTROUTING -j CONNMARK --restore-mark
    iptables -t mangle -D POSTROUTING -m mark ! --mark 0 -j ACCEPT
    iptables -t mangle -D POSTROUTING -o eth0 -j qos_egress
    iptables -t mangle -D POSTROUTING -j CONNMARK --save-mark
    iptables -t mangle -F qos_egress
    iptables -t mangle -X qos_egress
}

Testy

Przydałoby się jeszcze na własne oczy zobaczyć czy QoS działa. Odpaliłem zatem torrenta i wrzuciłem do pobierania kilka obrazów z linuxami, po chwili transfer osiągnął szczyt możliwości mojego łącza i powstałe w ten sposób opóźnienia zostały zobrazowane na fotce poniżej:

Pierwsze okienko obrazuje ping na maszynie klienckiej, drugie to podgląd interfejsów na kliencie, a ostatnie zaś to ssh do routera. Jak widać, pingi nie są zbytnio zadowalające -- kto chciałby przeglądać net czy grać w gry z takim lagiem? :smiley: Widzimy także, że pobieranych jest w tej chwili 1,8M/s i wysyłanych 156K/s, czyli bardziej rozciągnąć tego łącza się już nie da.

Aplikujemy teraz skrypt:

Wynik mówi raczej sam za siebie. Pingi by były oczywiście jeszcze niższe, gdyby pora przeprowadzania testu była nieco inna i zwykle u mnie ping nie jest większy niż 20ms i niby torrent pracuje na full, a praktycznie się tego nie odczuwa.