Jak zrobić dzielenie łącza pod Linux'em - wersja dla iptables (CBQ)
(dla zaawansowanych!)

UWAGA
Projekt ten jest już od dawna nie rozwijany. Obecnie pracuję nad bardziej uniwersalnym shaperem (nazywa się shaperd), pracującym zarówno na ipchains jak i na iptables. Dlatego zalecam instalowanie daemona shaperd.


UWAGA
Dzielenie łącza to uproszczona nazwa określająca różne metody regulowania szybkości pobierania danych z internetu przez użytkowików. Dzielenie łącza nie ma nic wspólnego z udostępnianiem łącza czyli z umożliwieniem użytkownikom wewnątrz sieci łączenia się z internetem za pośrednictwem serwera. Udostępnianie jest osobnym zagadnieniem i nie jest omówione na tej stronie (szukaj na wyszukiwarkach hasła: maskarada, masquerade, nat, firewall)

Uwaga
Jeśli nie potrafisz się posługiwać iptables, o samodzielnym pisaniu skryptów w shellu nawet nie wspomnę - to nie masz tu czego szukać. Nie będę pomagał instalować ten skrypt ludziom, którzy nie mają pojęcia o podstawach. Jak ktoś się nie czuje na siłach a mieszka w Krakowie to nie ma problemu - zainstaluję mu to osobiście (pewnie nie za darmo ;-) Reszta musi sobie radzić sama. Jeśli komuś nie pasuje ten skrypt z powodu założeń to wolna droga - proszę sobie go przerobić. Nie mam czasu na pisanie ludziom skryptów pod kątem ich potrzeb - przykro mi bardzo.


historia:

Na wstępie chciałbym zaznaczyć, że skrypt ten jest w wersji beta a to znaczy, że jest niedostatecznie przetestowany i może sprawiać nijakie problemy. Należy się spodziewać, że będzie jeszcze nie raz uaktualniany.

Zasada działania
Po włączeniu się w sieć nowego użytkownika i rozpoczęciu transmisji z internetem (lokalne połączenia nie rezerwują łącza), skrypt testuje czy użytkownik nie łączy się przypadkiem z jednym z adresów ip lub portów wpisanych w liście wyjątków (plik /etc/shaper/ignore). Jeśli nie znajdzie takiego wyjątku to przydziela część łącza wynikającą z prostego podziału szybkości maksymalnej łącza przez ilość aktualnie przez nie pracujących komputerów.
Po określonym czasie (zależnie od ustawienia w cronie) - np. po 1 minucie - shaper sprawdza, czy użytkownik wykorzystał co najmniej 50% z przydzielonego łącza. Jeśli nie wykorzystał to zostaje mu przydział zmniejszony o 25%. Jeśli użytkownik wykorzystuje przydział w granicach 50%-75% to skrypt niczego nie zmienia a jeśli wykorzystuje więcej od 75% to shaper zwiększa mu transfer o minimalny transfer (np o 8000 czyli 1KBajt) - pod warunkiem, że coś jeszcze zostało do przydzielenia. Zasada jest taka, że w pierwszej części skrypt sprawdza, komu można obciąć a dopiero na samym końcu z tego co zostanie z przydzielania szybkości dodaje tym co dużo ciągną.
Dzięki temu skrypt zapobiega przejęciu całkowitej kontroli nad łączem przez jednego nawiedzonego maniaka programów P2P lub idioty otwierającego kilkadziesiąt sesji WWW. Skrypt reguluje tylko transfer przychodzący z internetu do użytkowników.

Uwaga
Istnieje, jak na razie nie rozwiązany, bład w iptables polegający na tym iż niektóre połącznia wiszą ma maskaradzie przez 5 dni pomimo tego, że komputer, dla którego je utworzono nie był od kilku dni włączony w sieć. W skrajnych przypadkach takie wiszące połączenia mogą spowodować komunikat: ip_conntrack: maximum limit of XXX entries exceeded i brak możliwości zestawienia nowych połączeń. W przypadku shapera problem wiszących połączeń obszedłem ignorując połączenia z czasem wygaśnięcia większym niż 300 sekund).

OSTRZEŻENIE
Autor tego oprogramowania nie bierze odpowiedzialności za jakiekolwiek błedy, awarie i uszkodzenia wywołane przez działanie tego skryptu. Wszystko co robisz - robisz na własną odpowiedzialność.
Skrypt ten testowany jest na systemach opartych na jądrze 2.4.8, 2.4.12, 2.4.18 oraz Mandrake 8.1 (Vitamin) łączach SDI oraz 1Mbit dzierżawione od ISP.


Pobierz shaper_cbq_iptables.tar.gz (5.01-03.05.2002)

Aby wogóle dzielenie łącza pod Linuxem zaczęło działać to musi być spełnione wiele warunków:
  1. zainstalowany pakiet iproute2
  2. przekompilowane jądro aby obsługiwało CBQ (nie wiem jak jest z innymi dystrybucjami ale w Mandrake 8.1 CBQ (QoS) było wkompilowane standardowo przez dystrybutora więc nic nie musiałem kompilować.
    Jeśli nie wiesz, co ustawić do kompilacji to zaglądnij tutaj.
  3. Skrypt korzysta z iptables. Wersja dla ipchains jest opisana tutaj. Potrzebne jest dopisanie kilku regułek do iptables aby umożliwić skryptowi kontrolę wykorzystania łącza.
    Przykład takiej regułki:
    iptables -N ppp0-in
    iptables -A INPUT -i ppp0 -j ppp0-in
    
    iptables -A FORWARD -i ppp0 -s ! 192.168.1.1 -d 192.168.1.2 -j RETURN
    iptables -A FORWARD -i ppp0 -s ! 192.168.1.1 -d 192.168.1.3 -j RETURN
    iptables -A FORWARD -i ppp0 -s ! 192.168.1.1 -d 192.168.1.4 -j RETURN
    
    Gdzie:
    192.168.1.1 to numer ip bramki (lokalny)
    192.168.1.2-255 to numery ip komputerów w sieci
    ppp0 nazwa interfejsu z internetem (inaczej niż w wersji dla ipchains)
    Takie regułki rejestrują ilość danych pobraną z internetu przez poszczególnych użytkowników (z jednego interfejsu).
    Aby sprawdzić, czy te regułki rejestrują prawidłowo ilość pobranych danych wystarczy wklepać:
    iptables -vxL FORWARD -n | awk '{print $9,$2}'
    Co powinno wyświetlić mniej wiecej coś takiego:
     FORWARD               
    destination bytes      
    192.168.1.2 299202 
    192.168.1.3 4929737
    192.168.1.4 2467405
    192.168.1.5 208488 
    192.168.1.6 4215400
    192.168.1.7 1439977
    192.168.1.8 139236 
    
    Jeśli regułki nie rejestrują żadnego ruchu przychodzącego (są same zera) to poczytaj sobie man do iptables. Pewnie wcześniej w regułkach masz wpisane coś, co spełnia wszystkie warunki dla każdego numeru ip np.:
    iptables -A FORWARD -i ppp0 -j ACCEPT
    Jeśli masz kilka interfejsów i dużo userów to może być troche kłopotliwe wpisywanie ręczne tylu regułek. Dlatego do archiwum shaper_cbq_iptables dołączyłem skrypt ipallow w wersji dla iptables obsługującej wiele lokalnych interfejsów i korzystającego częściowo z konfiguracji shapera_cbq. Jedyne co w skrypcie ipallow trzeba skonfigurować to zmienić nazwę interfejsu który jest dołączony do internetu w linijce:
    internet_iface="ppp0"
    Na stronie Maskarada jest opis skryptu ipallow - niestety - jak na razie tylko do wersji na ipchains - zasady działania są jednak podobne.
  4. Jeśli używasz na serwerze squida to niestety - skrypt dla niego nie przydzieli szybkości i może się okazać, że łącze będzie zapychane nie przez użytkowników, ale przez squida. Na razie nie mam rozwiązania tego problemu i dlatego trzeba się zdecydować co używać: albo shaper albo squid. Jedno trzeba wyłączyć.
  5. Aby przetestować jądro pod kątem zgodności z CBQ trzeba zainstalować iproute2 (na Mandrake 8.1 iproute2 jest instalowane domyślnie) i wpisać komendę:
  6. tc -d qdisc
    Jeśli w wyniku jej działania pojawi się jakiś komunikat typu RTNETLINK error to jądro nie obsługuje CBQ (lub nie ma załadowanego modułu).
    Jeśli jest gotowe to ta komenda nic nie wyświetli (lub wyświetli przydzielone widełki).
  7. Skrypt shaper działa przy pewnych założeniach:
    • parametry łącz lokalnych w sieci należy wpisać do pliku konfiguracyjnego /etc/shaper/shaper.cfg
      Przykładowy plik konfiguracyjny dla serwera z 1 interfejscem lokalnym eth0 o przepustowości 10Mbit. Używam go dla SDI i normalnej dzierżawki.
      mainip=212.17.14.118
      high_start_speed=1
      local_int=eth0;10485760;192.168.0.0/16;192.168.1.0/24;10
      
      Gdzie:
      • mainip numer ip zewnętrzny serwera
      • local_int parametry lokalnych interfejsów
      • eth0 - nazwa interfejsu. Nie wpisuj tutaj interfejsu łączącego z internetem!
      • 10485760 - szybkośc interfejsu w bitach/sek (10MBit=10*1024*1024 bit)
      • 192.168.0.0/16 - numer ip interfejsu (w tym przypadku jest to maska sieci klasy C co powoduje, że wszystkie transfery od numerów ip pasujących do tej maski nie będą miały ograniczeń. Chodzi o to aby transfer lokalny z serwera bądź rutowany przez interfejsy od ludzi lokalnych w sieci nie był przycinany).
      • 192.168.1.0/24 - numer ip docelowy z maską dla którego stosowany jest shaper (czyli maska podsieci stosowana na danym interfejsie - np eth0 może mieć 192.168.1.0/24 a eth1 192.168.2.0/24 - nuery ip w podsieci to 192.168.2.0-255)
      • 10 - identyfikator klasy (starszy bajt) (dla każdego interfejsu musi być inny - najlepiej kolejny po 10).
      • high_start_speed - sposób przydzielania łącza przy pojawieniu się nowego numeru ip. Dla 1 początkowa szybkość jest równą częścią szybkości łącza wynikłą z podziału szybkości przez ilość userów aktualnie z niego korzystających (np. dla SDI z 5 pracującymi userami = 100000/5 czyli 20000 (kbitów)). Dla 0 przydzielona szybkość jest minimalna (taka jak podana w parametrze przy uruchomieniu shapera).

    • Przykładowy plik konfiguracyjny dla serwera z 2 interfejsami lokalnymi eth0 i eth1 o przepustowości 10Mbit i 100Mbit.
      mainip=212.17.14.118
      high_start_speed=1
      local_int=eth0;10485760;192.168.0.0/16;192.168.1.0/24;10
      local_int=eth1;104857600;192.168.0.0/16;192.168.2.0/24;11
      

      Przykładowy plik konfiguracyjny dla serwera z 3 interfejsami lokalnymi eth0, eth1, ppp1 (łącze dzierżawione miedzy np dwoma budynkami) o przepustowości 10Mbit, 100Mbit i 768Kbit (dla tego interfejsu ograniczamy transfery również lokalne).
      mainip=212.17.14.118
      high_start_speed=1
      local_int=eth0;10485760;192.168.0.0/16;192.168.1.0/24;10
      local_int=eth1;104857600;192.168.0.0/16;192.168.2.0/24;11
      local_int=ppp1;786432;192.168.3.1/32;192.168.3.0/24;12
      
    • W przypadku, gdy w lokalnej sieci używamy innej klasy numerów niż 192.168.0.0 - 192.168.255.255 lub jeśli nasza bramka (serwer) ma inny numer ip niż 192.168.1.1 - należy wyedytować pliki: /sbin/shaper i /root/shaper_test (minimalna różnica ale zasada jest taka sama), w których znajdziemy taką linijkę:
      masq=`/root/natstat | \
      
      i dopisać numery ip podsieci i bramki:
      masq=`/root/natstat 10. 10.1.1.1 | \
      
      Gdzie:
      • 10. numer ip podsieci - w tym przypadku odpowiada to zapisowi 10.0.0.0/255.0.0.0
      • 10.1.1.1 numer ip bramki.

      Dla wersji PHP znajdź linijkę:
      $natstat_exec=    "/root/natstat";
      i dopisz numery ip jak w przykładzie powyżej np:
      $natstat_exec=    "/root/natstat 10. 10.1.1.1";
    • W chwili obecnej tylko taki dość niewygodny sposób jest możliwy. Spowodowane to jest brakiem możliwości podglądnięcia przy pomocy iptables (lub netstat) aktualnych połączeń na maskaradzie. Jedyne co można zobaczyć to zawartość pliku /proc/net/ip_conntrack, który zawiera wiele innych zbędnych w tym przypadku informacji. Dlatego też napisałem natstat dla shapera. W archiwum znajduje się skompilowana wersja natstat dla procesorów seri x86 i kod źródłowy w C. Aby go samemu skompilować należy napisać:
      gcc /root/natstat.c -o /root/natstat
      
    • Należy wklepać wszystkie lokalne numery ip i obok nazwy interfejsów przez które te numery pracują (nie chciało mi się robić rozpoznawania w skrypcie po maskaradzie ;-) w pliku /etc/shaper/iplist.Przykład:
      192.168.1.2=eth0
      192.168.1.3=eth0
      192.168.1.4=eth0
      192.168.1.5=eth0
      192.168.2.2=eth1
      192.168.2.3=eth1
      192.168.2.4=eth1
      192.168.2.5=eth1
      
    • Prędkość łącza internetowego (nazwa jest nie ważna byle tylko było) jest podawana jako argument skryptu np.
      /sbin/shaper 115200 8000
      lub dla wersji PHP
      /usr/bin/php -q /sbin/shaper.php 100000 8000
      gdzie 115200 to maksymalnie 115kbit a 8000 to 8kbit czyli minimalny przydział dla użytkownika (podzielić sobie szybkość na ilość użytkowników sieci). Dobrze jest podawać szybkość nie deklarowaną a rzeczywistą, jaką udaje się uzyskać ciągnąc coś przez dłuższy czas przez to łącze w kierunku z internetu do sieci. Inaczej dzielenie wirtualnej szybkości mija się z celem. Łącze SDI nie pracuje z szybkością 115kbit tylko 96kbit (w jedną stronę) więc wpisywanie większych wartości powoduje tylko tyle, że ktoś dostanie w sieci przydział szybkości, którego nigdy nie uda mu się osiągnąć. Po co więc kogoś oszukiwać. Ja dla SDI daję 100000.
    • Jeśli CBQ jest w modułach to przy starcie systemu trzeba wrzucić następujące moduły:
      modprobe sch_cbq
      modprobe sch_tbf
      modprobe cls_u32
      
  8. Skrypt musi działać na prawach root i mieć możliwość zapisu do katalogu /var/shaper. Katalog taki trzeba założyć z właścicielem root i prawami 755
  9. Skrypt najlepiej dopisać do crona np. w pliku /etc/crontab dopisać taką linijkę:
    */1 * * * * root /sbin/shaper 115200 8000
    
    UWAGA Dla wersji PHP uruchamiam go tak:
    */1 * * * * root /usr/bin/php -q /sbin/shaper.php 100000 8000 > /dev/null
    
    ale można i tak:
    */1 * * * * root /sbin/shaper.php 100000 8000 > /dev/null
    
  10. W /etc/shaper sa wpisane wyjątki dla których shaper nie rezerwuje łącza. Mogą to być przykładowo:
    217.96.55.5 411 - numer ip i port 411
    213.180.130.190 - numer ip i kazdy port
    22$ - każdy numer ip i port 22 (telnet)
    Zrobione jest to po to, żeby skrypt nie rezerwował łącza na transmisje nie generujące praktycznie ruchu (np. GaduGadu, IRC, telnet, Chaty itp). Aktualną listę branych pod uwagę numerów ip i portów na maskaradzie można podglądnąć skryptem:
    shaper_test
  11. W katalogu /var/shaper generowane są przez skrypt pliki robocze:
    • bitrate_user.tmp - zawiera listę numerów ip i ilość pobranych z internetu danych w bajtach. Aby był właściwy musza być prawidłowo dokonane wpisy iptables. Tak to wygląda u mnie:
      192.168.1.2 441127061 1008227523
      192.168.1.3 0 1008227523        
      192.168.1.4 0 1008227523        
      192.168.1.5 93120766 1008227523 
      192.168.1.6 304302374 1008227523
      192.168.1.7 51299622 1008227523 
      192.168.1.9 373967723 1008227523
      
    • /var/shaper/bitrate_user_sh.old - zawiera numery ip oraz przydzielone widełki. Można to wykorzystać do wizualizacji na stronie www - przykład użycia. A może wyglądać tak:
      192.168.1.2 40000
      192.168.1.9 58000
      
    • /var/shaper/bitrate_user_out_sh.old - obecnie nie używany.
    • /var/shaper/masq.tmp - spis numerów ip którym są przydzielane widełki. Może wyglądać tak:
      192.168.1.5
      192.168.1.9
      
  12. W katalogu /root znajdują się dodatkowe skrypty używane przez shapera. Są to:
    • ckspeed - skrypt wykorzystywany przez shapera do obliczania transferu (nie dotyczy wersji PHP)
    • ckbitrate_user - pokazuje aktualny wykorzystywany transfer (w bit/sek) przez dany numer ip. Przykład:
      ckbitrate_user 192.168.1.2
      
    • ckbitrate_user_last - pokazuje ostatni przydzielony transfer (w bit/sek) dla danego numeru ip. Przykład:
      ckbitrate_user_last 192.168.1.2
      
    • shaper_test - pokazuje wszystkie maskowane numery ip brane pod uwage przy dzieleniu łącza. Przykład:
      shaper_test
      
    • shaper_test - pokazuje wszystkie maskowane numery ip brane pod uwage przy dzieleniu łącza. Przykład:
      shaper_test
      
    • shaper_test_dns - pokazuje wszystkie maskowane numery ip brane pod uwage przy dzieleniu łącza (i zamienia je na domeny - dla czytelnosci). Przykład:
      shaper_test_dns 192.168.1.2
      
    • shaper_off - usuwa przydziały łącz (służy jedynie do testów). Jak skrypt jest uruchamiany przez crona to i tak za chwile się włączy. Przykład:
      shaper_off
      
  13. Jeśli w sieci jest dużo użytkowników to czas uruchamiania skryptu może się tak wydłużyć, że dłużej będzie się uruchamiał niż działał. Należy wtedy zmniejszyć częstotliwość uruchamiania skryptu na rzadziej np co 2 lub 3 minuty. Skrypt bardzo obciąża system.
  14. Zalecam uruchamianie shapera etapami a nie rzucanie się na głęboką wodę. Zalecana kolejność:
    • zrobienia regułek iptables i sprawdzenia czy działają
    • test programu /root/natstat np:
      /root/natstat 192.168. 192.168.1.1
      wyświetli coś mniejwięcej takiego (dotyczy sieci pracujących z numerami IP klasy C):
      192.168.1.24 64.245.59.88 21   
      192.168.1.24 65.33.78.195 41007
      192.168.1.24 150.254.29.66 4444
      192.168.1.24 208.185.211.71 80 
      192.168.1.24 217.17.41.83 8074 
      
    • ręczne uruchomienie shapera:
      /sbin/shaper 100000 8000
      W wyniku działania tej komendy nie powinien pojawić się na ekranie żaden komunikat (wszystkie wyniki są generowane do plików i robione są widełki).

      Ręczne uruchomienie shapera - wersja PHP:
      /usr/bin/php -q /sbin/shaper.php 100000 8000
      wynik działania może wyglądać tak:
      IP=192.168.1.2, band_new=16000, usage=148, rate=11866, band_old=8000
      IP=192.168.1.6, band_new=8000, usage=-100, rate=5319, band_old=-1
      Total band used=24000
      
      Po uruchomieniu sprawdzić pliki bitrate_user_sh.old, bitrate_user.tmp, masq.tmp pod kątem prawidłowej zawartości.
    • sprawdzić działanie ckbitrate_user i ckbitrate_user_last
    • Jak wszystko powyżej poszło jak należy to dopiero można shapera dopisać do crona
  15. Warto sprawdzić jak skrypt działa dajac komendę:
    tc -s qdisc
    
    Wyniki jej działania mogą wygladac tak:
     qdisc tbf d09f: dev eth0 rate 5430bps burst 10Kb lat 1.2s              
     Sent 108930 bytes 73 pkts (dropped 0, overlimits 0)                   
                                                                           
     qdisc tbf d09e: dev eth0 rate 5430bps burst 10Kb lat 1.2s             
     Sent 126618 bytes 89 pkts (dropped 0, overlimits 0)                   
                                                                           
     qdisc tbf d09d: dev eth0 rate 1638bps burst 10Kb lat 3.8s             
     Sent 54699 bytes 65 pkts (dropped 0, overlimits 321)                  
     backlog 6110b 5p                                                      
                                                                           
     qdisc tbf d09c: dev eth0 rate 10Mbit burst 10Kb lat 4.8ms             
     Sent 0 bytes 0 pkts (dropped 0, overlimits 0)                         
                                                                           
     qdisc tbf d09b: dev eth0 rate 10Mbit burst 10Kb lat 4.8ms             
     Sent 5690 bytes 53 pkts (dropped 0, overlimits 0)                     
                                                                           
     qdisc cbq 10: dev eth0 rate 10Mbit (bounded,isolated) prio no-transmit
     Sent 310829 bytes 302 pkts (dropped 0, overlimits 1555)               
     backlog 5p                                                            
      borrowed 0 overactions 0 avgidle 624 undertime 0
    
    Nalezy zwrócić szczególną uwagę na linie z rate innym niż 10Mbit (lub innym w przypadku posiadania łącza lokalnego o innej szybkości maksymalnej). W tym przypadku trzy pierwsze klasy obrazują transfery trzech różnych komputerów w sieci lokalnej. Należy zwrócić uwagę, czy rejestrowane są wielkości wysłanych danych Sent i czy pojawiają się jakieś wartości przy dropped i overlimits. Jeśli tak to znaczy, że CBQ działa i obcina transfer przekraczający widełki.
  16. W razie wystąpienia problemów przy uruchomieniu skryptu, zanim do mnie napiszesz - postaraj się przeczytać ten opis jeszcze raz i sprawdź, czy nie popełniłeś gdzieś błedu. Potem dopiero możesz pisać do mnie. Ze względu na brak czasu moja pomoc może być trochę opóżniona więc polecam zaglądnięcie do Księgi gości. Może ktoś z wpisanych tam adminów zechce pomóc wcześniej niż ja będę w stanie to zrobić.
  17. Jeśli przebrniesz przez instalację i uda Ci się skonfigurować ten skrypt na swoim serwerze, może zechcesz się wpisać do Księgi gości. Proszę, podaj w niej:
    • Opis systemu na serwerze (dystrybucja, wersja kernela, inne uwagi)
    • swój e-mail kontaktowy (możesz go zakończyć jakimś "ściemniaczem anyspamowym" ;) typu .NOSPAM)
    • url strony www (jesli isnieje) serwera
    Może pomożesz innym w instalacji tego skryptu a mnie trochę odciążysz. Będę bardzo wdzięczny.
  18. Będzie mi miło, jeśli jakiś szczęśliwy administrator wrzuci gdzieś na swoją stronę sieciową ten mały banerek:

    Powered by Shaper CBQ

    A tutaj jest kod html do wklejenia:
    <p><a href="http://sp9wun.republika.pl/">
    <img src="http://sp9wun.republika.pl/linux/pics/shaper.png" border="0" 
    width="89" height="32" alt="Powered by Shaper CBQ"></a></p>
Zobacz skrypt CGI kto.cgi lub PHP kto.php (dodtakowy skrypt ckwintalk do kontroli wintalka - u mnie w sieci wintalk jest obowiązkowy) do generowania listy aktywnych komputerów wraz z przydzielonymi im widełkami przez shaper'a. Skrypt trzeba wyedytować i powpisywać dane ze swojej sieci. Wywołuje się go odwołując się do kto.cgi?60 (lub kto.php - dla PHP)
60 - oznacza, że skrypt będzie odświerzany co 60 sekund. Skrypt wymaga skonfigurowania DNSa dla lokalnych numerów ip. Ponadto mogą wystąpić błędy z niektórymi wersjami binda. Trzeba się pobawić w przerabianie.



Powrót Linux
@
Webmaster Grzegorz Fitrzyk