Incrementare la banda a disposizione & aggirare limitazioni di banda

14Mag11

Disclaimer: L’autore non si assume nessuna responsabilità in merito all’utilizzo illecito delle istruzioni tecniche riportate qui di seguito.

Navigare ed essere collegati, al giorno d’oggi, diventa sempre più importante e si discute di rendere la connessione ad Internet un diritto fondamentale umano. Essere collegati ad una rete unica che collega l’intero pianeta e permette a miliardi di persone di comunicare in ogni momento è semplicemente fantastico, tuttavia a livello utente il discorso “banda” si fa spesso sentire, specie a “livello programmatore” direi 🙂 ..

Bonding di rete

Navigare in rete con 1Mbit/s (125kB/s) può essere ancora accettabile, quando andiamo intorno ai 50kB/s la faccenda inizia a diventare fastidiosa, specialmente se dobbiamo fare una videochiamata o scaricare degli aggiornamenti.
Un caso poco frequente ma che aiuta a far comprendere il seguito è questo:
Immaginiamo di avere un computer con due schede di rete da 10Mb/s ed un router/switch/hub con tante porte da 100Mb/s. Trasmettere e ricevere con un ordine di grandezza in meno per la velocità potrebbe rivelarsi alquanto fastidioso. In alcune situazioni potrebbe dover servire giusto poco più di 10Mb/s e sarebbe alquanto triste non poterli avere.

Fortunatamente all’interno dei moduli di Linux, ne esiste uno chiamato bonding, che permette di ovviare a problemi come questo.

Con il modulo del kernel bonding, è infatti possibile riunire più interfacce di rete in un gruppo, trattandole astrattamente come se fossero una interfaccia unica con un nuovo nome, come ad esempio bond0. Tutto il traffico diretto a bond0 verrà inviato al modulo bonding, che deciderà come dividerlo sulle interfacce del gruppo, idem il viceversa. Una delle politiche per “dividere” il traffico più comuni (e che utilizzerò qua nel seguito) è quella di round-robin, cioè la equa suddivisione del traffico inviando e ricevendo un equo numero di pacchetti da ogni interfaccia. In realtà il modulo bonding permette anche altre configurazioni, che risultano molto utili per server di produzione, dove anche se una interfaccia si guasta o è in sovraccarico, il modulo bonding decide autonomamente di utilizzare una interfaccia di “backup” per risolvere il problema. Quest’ultimo aspetto non sarà comunque di nostro interesse ora.
Dal punto di vista di protocollo di rete, quando più schede vengono unite in una unica bond0, l’indirizzo mac e ip che prima erano diversi per ogni interfaccia, diventano uno solo, associato a bond0. Le interfacce che mettiamo in bonding cessano di avere ip o mac address associati.
Dal punto di vista “teorico” e poi in base a quanto appena detto nella “pratica”, risulta evidente che non sarà possibile utilizzare il bonding con schede collegate a due reti diverse, cioè a reti che utilizzano indirizzi diversi, o comunque in generale dove gli stessi pacchetti non possono arrivare su entrambe le interfacce indistintamente. Vedremo in seguito che questo problema può essere comunque aggirato con un po’ di “fatica”.
Supponiamo ad esempio che le due schede sul nostro computer siano eth0 e eth1; con le poche righe di codice seguenti sarà possibile riunirle in una unica interfaccia bond0 che avrà dunque il doppio della banda: 20Mb/s

modprobe bonding mode=0 miimon=100

ifconfig eth0 down
ifconfig eth1 down

ifconfig bond0 hw ether 00:11:22:33:44:55
ifconfig bond0 192.168.55.55 up

ifenslave bond0 eth0
ifenslave bond0 eth1

Rivediamo i passi: nel modprobe viene abilitato il modulo di bonding, specificando il mode, cioè la politica per dividere i pacchetti. In questo caso 0 è la mode per abilitare il round-robin sopra citato. Dopo aver caricato il modulo, la prima cosa da fare è disattivare le due interfacce di rete eth0  e eth1. A questo punto possiamo configurare la nostra interfaccia bond0, che è stata creata nel momento in cui abbiamo abilitato il modulo di bonding. Come primo passo impostiamo il suo mac address e poi il suo indirizzo IP. Come abbiamo detto prima infatti, le schede unite con bonding cessano di avere ip e mac address e solo la scheda virtuale che le riunisce avrà un indirizzo IP ed un mac address. Assicuriamoci che gli indirizzi impostati siano validi per la nostra rete.
A questo punto l’interfaccia di bonding è pronta, resta solo da dirgli quali interfacce riunire. Questo viene fatto mediante il comando ifenslave, il cui nome richiama il fatto che vengono aggiunte interfacce “schiave”.

Una cosa divertente che si nota da questo esempio, è che l’aggiunta di interfacce da mettere in bonding può essere fatta in tempo reale utilizzando il comando ifenslave! Può sembrare banale, ma la cosa è invece molto interessante. Pensate all’esempio precedente e supponiamo di collegare una scheda di rete usb da 10Mb/s al computer mentre sta lavorando con eth0 e eth1 in bonding. Posto che il kernel riconosca la scheda usb ci basterà collegarla e digitare:

 ifenslave bond0

per vedere subito la velocità delle nostre connessioni aumentare, ed il tutto senza interrompere nessuna connessione in corso!

È sottointeso che tutti i comandi precedenti vanno eseguiti da utente root.

Attenzione! Tutte le volte che facciamo bonding dobbiamo assicurarci di non avere l’opzione rp_filter attivata sul kernel. Se attivata, questa opzione fa sì che il kernel tracci le connessioni in ingresso e rifiuti connessioni dirette ad un indirzzo diverso da quello dell’interfaccia su cui viene ricevuta la connessione. Su alcune distribuzioni (ad esempio ArchLinux) l’rp_filter è disattivato di default, su altre (ad esempio Ubuntu) è attivato di default.. quindi ci conviene controllare.
Possiamo disabilitare l’rp_filter per tutto il sistema con:

echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter

Oppure possiamo disabilitarlo sulle singole interfacce, facendo riferimento all’esempio di prima:

echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter

Interfacce virtuali wireless

Passiamo a parlare d’altro ora.

Vi è mai capitato di avere a disposizione due o più reti wireless, ad esempio da 10Mb/s ciascuna e avere la copertura di entrambe dal punto in cui vi trovate con il vostro pc/portatile?
Sarebbe bello riunirle insieme in qualche modo per ottenere il doppio della banda come prima!
Iniziamo con questo esempio: dal vostro portatile riuscite a connettervi a due access point che però hanno appunto un “collo di bottiglia” da 10Mb/s nella banda a disposizione ciascuno. La rete a cui sono collegati questi due access point ha però una ampiezza di banda molto più elevata!

Ok, le reti wireless sono due, però alla fine la rete è la stessa: ci verranno dati indirizzi IP nella stessa sottorete e tutto il resto. Allora ci serve solo capire come collegarci ad entrambe.

Avete mai visto che ci sono access points in grado di mostrarvi due reti wireless anche se in realtà la scheda fisica è la stessa (ad esempio questo accade con la fonera, per chi la conosce)? Beh, anche il contrario è possibile, cioè sostanzialmente è possibile suddividere una interfaccia wireless in un insieme di schede wireless virtuali e far collegare ciascuna di esse ad una rete diversa.

Per fare questo avete bisogno di due cose: una scheda wireless che supporta le “virtual interfaces” (VLANs o VIF) ed un kernel linux 2.6.37 (la cosa dovrebbe funzionare anche da kernel precedenti ma c’era qualche dettaglio ancora non funzionante).
Per quanto riguarda la scheda wireless che supporta le VLANs, questo è vero per praticamente tutte le schede Atheros (quelle che utilizzano i driver ath5k e ath9k) e forse anche per altre schede (in via teorica controllando con il comando “iw list” si dovrebbe riuscire a capire se una scheda può farlo).
C’è un piccolo prezzo da pagare per avere queste VLANs: se ci stiamo collegando a reti protette (come nella maggior parte dei casi), sarà necessario caricare il modulo ath5k o ath9k con un parametro nohwcrypt=1. Perché? Il discorso è che la scheda wireless effettua “in hardware” la cifratura dei dati trasmessi e ricevuti. Questo inizia a diventare un problema se deve farlo per due reti,che quasi sicuramente devono cifrare i dati in modo diverso. Dunque il prezzo da pagare è che le cifrature non potranno essere fatte sulla scheda ma dal nostro processore.

Supponiamo di avere una scheda che usa driver ath5k, vediamo quali passi seguire (sono gli stessi anche per le schede con driver ath9k):

modprobe -r ath5k

modprobe ath5k nohwcrypt=1

Così abbiamo disattivato il driver della scheda e lo abbiamo riabilitato con l’opzione per disabilitare la cifratura hardware.

iw phy phy0 interface add wlan1 type station

In questo modo abbiamo aggiunto un’altra interfaccia oltre alla già presente wlan0. Il mac address della interfaccia generata wlan1 sarà uguale a quello dell’altra. La cosa non ci piace ovviamente e vogliamo che le due schede abbiano due mac address differenti, di modo da apparire esattamente come se fossero due schede di due computer diversi. Per ovviare al problema possiamo usare ifconfig come prima:

ifconfig wlan1 hw ether 00:11:22:33:44:55

Oppure se vogliamo evitare di doverci inventare un mac address al volo possiamo usare macchanger (non è incluso di default in quasi nessuna distribuzione Linux):

macchanger -A wlan1

In questo modo il mac address impostato sarà casuale (ma non così casuale da rendere evidente che si tratti di un mac address falso).

Ok, abbiamo le nostre due interfacce virtuali wireless. Supponiamo che le reti necessitino autenticazione WPA.

iwconfig wlan0 essid “Rete1”
wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant_rete1.conf &
dhclient wlan0
iwconfig wlan1 essid “Rete2”
wpa_supplicant -Dwext -iwlan1 -c/etc/wpa_supplicant_rete2.conf  &
dhclient wlan1

Ora saremo collegati ad entrambe le reti. Nota: su altre distribuzioni potrebbe essere necessario utilizzare dhcpcd al posto di dhclient.

Ed ora come prima procediamo al bonding delle interfacce:

modprobe bonding mode=0 miimon=100

ifconfig wlan0 down
ifconfig wlan1 down

ifconfig bond0 hw ether 00:11:22:33:44:55
ifconfig bond0 192.168.55.55 up

ifenslave bond0 wlan0
ifenslave bond0 wlan1

Esattamente come prima.

Questo esempio non l’ho provato personalmente e potrebbe esserci qualche problema con wpa_supplicant quando le interfacce vengono spente. Tuttavia ho voluto comunque mostrarlo giusto per dare un’idea di quello che bisogna fare e per introdurre al prossimo passo.

Ricordiamoci sempre:

echo 0 > /proc/sys/net/ipv4/conf/wlan0/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/wlan1/rp_filter

Reti wireless completamente separate o rete unica limitata

Come detto prima, il fatto di avere una linea a monte veloce e solo “colli di bottiglia” sugli access points è una cosa abbastanza rara. Solitamente se siamo in una situazione del genere è perché dal nostro computer possiamo collegarci a due reti wireless diverse, collegate a due linee completamente separate tra loro e con indirizzi diversi (magari nella stessa sottorete locale 192.168.0.x, però comunque i dati dell’una non transitano sull’altra e viceversa).
Situazione leggermente diversa ma completamente analoga dal punto di vista tecnico è invece quando siamo collegati ad un unico access point che ci immette in una rete dove la banda è limitata per ogni indirizzo ip o mac address e non possiamo ricevere i pacchetti degli altri host. In una rete del genere, a differenza del caso precedente, non possiamo fare bonding perché comunque riunendo le interfacce in una unica l’ip e il mac address sarebbero unici, rendendo vana l’operazione di bonding (permane la limitazione di banda).

Un modo leggermente complicato ma funzionante che ho personalmente escogitato a seguito di una serie di tentativi è quello che vi spiegherò qui di seguito.

L’idea principale è: ok, non possiamo in nessun modo fare bonding sulla rete perché sono separate tra di loro e hanno indirizzi diversi etc.., però se io in qualche modo riesco a collegarmi ad entrambe e quindi ad aprire una VPN su ciascuna delle due, e la VPN è di tipo TAP (simula completamente il protocollo ethernet), ed è unificata come indirzzi etc.. Posso in linea teorica mettere in bonding non le interfacce wireless ma le interfacce TAP della VPN e aumentare la banda. Ovviamente questo ha il “costo” di dover avere un server OpenVPN raggiungibile da entrambe le reti. Se le reti sono collegate entrambe ad Internet ci basta avere un server OpenVpn accessibile direttamente da Internet.

Riprendiamo l’esempio di prima e supponiamo che le reti “Rete1” e “Rete2”  siano totalmente scorrelatte tra loro. Se troviamo un modo per aprire un processo di openvpn su wlan0 (che si collega a “Rete1”) e un altro processo di openvpn (che si collega a “Rete2”) avremo due interfacce di tipo TAP chiamate ad esempio tap0 e tap1.
Le vpn avviate sono due istanze della stessa.

Il fatto di mettere in bonding tap0 e tap1 implica che esse perderanno il proprio ip della vpn (ad esempio 10.0.0.2 e 10.0.0.3) per conferire un unico indirizzo a bond0 (ad esempio 10.0.0.4) ed un unico mac address. Questo non è un problema dal momento che stiamo usando interfacce di tipo TAP, infatti TAP simula ethernet e dunque la situazione dal punto di vista del bonding sarà esattamente la stessa del primo esempio che abbiamo visto con la rete cablata!

Come detto prima lo stesso esempio è valido anche per reti a banda limitata. Supponiamo ci sia una rete chiamata “Rete1” a cui ci colleghiamo con entrambe le interfacce wifi. La limitazione ci viene applicata in base all’ip e/o mac address oppure anche a livello di certificato/password di autenticazione. Nessun problema:in ogni caso ci colleghiamo due volte con le due interfacce alla stessa rete ed abbiamo due ip e due mac address distinti (chi controlla la rete wireless non riuscirà a capire che la connessione avviene dallo stesso computer) e apriamo due VPN, poi mettiamo in bonding le interfacce della VPN e abbiamo raddoppiato la banda! Magari la rete ci limita tanto ma ha grande banda in realtà.. Dunque nessuno ci vieta di creare 30 interfacce wireless virtuali e 30 vpn, una per ciascuna interfaccia wireless virtuale, e poi mettere in bonding le 30 vpn. In linea teorica possiamo proseguire all’infinito, supposto che il server della VPN abbia ovviamente più banda di quella che ci viene limitata.. Se il serve della vpn è collegato ad internet con una linea da 1Mb/s, sicuramente in ogni caso con questo metodo non potremo superare quella velocità. Comunque dimenticando questo piccolo dettaglio (se come server VPN usiamo un server hostato in qualche serverfarm avremo probabilmente una linea da 100Mb/s) il numero di interfacce wifi virtuali è potenzialmente illimitato!
Ovviamente dopo un certo numero di interfacce inizieremo ad avere un carico del sistema esagerato e forse non riusciremo più ad aumentare la banda a causa del casino di pacchetti in gioco.. Però non ho dati per confermarlo.

È vero: sembra tutto molto facile, però c’è un dettaglio su cui ho puntato poco l’attenzione. Abbiamo detto che per poter fare tutta questa bellezza è necessario avviare diversi processi di openvpn che “escano” ciascuno su una interfaccia wireless diversa. La cosa non è per niente banale, infatti nella configurazione di OpenVpn non è possibile specificare una interfaccia di rete da cui collegarsi (come in nessun altro programma, a meno che utilizzi socket raw), inoltre per come sono strutturate le tabelle di routing, esiste sempre una ed una sola regola per decidere come indirizzare il traffico, la così detta “route default”, quindi tutti gli openvpn andrebbero ad uscire dalla stessa scheda, lasciando inutilizzate le altre. Non è quello che vogliamo noi!

Ma non disperate, c’è un hack anche per questo!

In iptables, il gestore delle tabelle di netfilter (il modulo del kernel Linux che si occupa della rete, firewalling etc..), esiste una “tabella” chiamata “mangle” che permette di applicare dei marcatori a dei pacchetti sotto alcune condizioni. Inoltre tramite il comando “ip”, che gestisce il routing del sistema, è possibile creare delle tabelle di routing “alternative” se il pacchetto in arrivo è stato marcato dalla tabella mangle.
Uno dei metodi che supporta iptables per marcare i pacchetti è quello di guardare il GID (Group ID), cioè il gruppo a cui appartiene il processo che ha originato il pacchetto.

Beh ma allora è fatta! I passi che dovremo seguire sono questi: avviamo ogni processo di OpenVpn con un gruppo diverso (il comando sg cioè “Set Group” permette di impostare il gruppo a cui appartiene un certo processo da eseguire), poi impostiamo iptables mangle di modo che quando vede un pacchetto in uscita proveniente da un certo gruppo assegna un certo marcatore. Infine facciamo in modo (mediante il comando ip per gestire le tabelle di routing), che quando c’è un pacchetto in uscita con un certo marcatore applicato, venga utilizzata una certa regola di routing e che esca quindi su una certa interfaccia di rete specifica! È fatta! Possiamo far uscire ogni processo di OpenVpn da una interfaccia virtuale diversa! Ricordiamoci alla fine di tutto di impostare il gateway di default nuovo che sarà il server della vpn (che deve essere abilitato per fare masquerading). Ovviamente ci sono tanti altri piccoli dettagli in più, li vediamo ora.

Riassumiamo i vari comandi principali da eseguire nel caso di due interfacce virtuali, due gruppi wifi0 e wifi1 esistenti nel sistema:

modprobe -r ath5k
modprobe ath5k nohwcrypt=1

iw phy phy0 interface add wlan1 type station

echo 0 > /proc/sys/net/ipv4/wlan0/rp_filter
echo 0 > /proc/sys/net/ipv4/wlan1/rp_filter

macchanger -A wlan1

ifconfig wlan0 up
iwconfig wlan0 essid “Rete”
wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf &
dhcpcd -p wlan0
killall dhcpcd

ifconfig wlan1 up
iwconfig wlan1 essid “Rete”
wpa_supplicant -Dwext -iwlan1 -c/etc/wpa_supplicant.conf &
dhcpcd -p wlan1
killall dhcpcd

iptables -t mangle -A OUTPUT -m owner –gid-owner wifi0 -j MARK –set-mark 1
iptables -t mangle -A OUTPUT -m owner –gid-owner wifi1 -j MARK –set-mark 2

iptables -t nat -A POSTROUTING -o wlan0 -m mark –mark 01 -j SNAT –to-source  IP_DI_WLAN0
iptables -t nat -A POSTROUTING -o wlan1 -m mark –mark 02 -j SNAT –to-source  IP_DI_WLAN1

ip rule add fwmark 1 table 1
ip rule add fwmark 2 table 2

ip route add default via GATEWAY__DEFAULT_DI_WLAN0 dev wlan0 table 1
ip route add default via GATEWAY__DEFAULT_DI_WLAN1 dev wlan1 table 2

sg wifi0 -c “openvpn –config /etc/openvpn/client.conf” –ifconfig 10.0.0.2 255.255.255.0″
sg wifi0 -c “openvpn –config /etc/openvpn/client.conf” –ifconfig 10.0.0.3 255.255.255.0″

modprobe bonding miimon=100 mode=0

ifconfig tap0 down
ifconfig tap1 down

ifconfig bond0 hw ether 00:22:13:72:A1:5A
ifconfig bond0 10.0.0.4 up

ifenslave bond0 tap0
ifenslave bond0 tap1

route del default dev wlan0
route del default dev wlan1

route add default gw 10.0.0.1 dev bond0
echo “nameserver 208.67.222.222” > /etc/resolv.conf

Ancora come prima sorridiamo all’idea che utilizzando questa configurazione non solo aumentiamo la banda, ma possiamo garantirci sempre la connettività se una delle due reti dovesse “cadere” e possiamo inoltre aggiungere altre in tempo reale con relativamente poche operazioni!

Per altri dettagli sul modulo bonding vi rimando a questa pagina di documentazione.



4 Responses to “Incrementare la banda a disposizione & aggirare limitazioni di banda”

  1. 1 Alex

    Articolo fantastico. Premetto di essere un totale noob, vorrei chiederti aiuto. A casa, sulla mia linea ho una adsl teletu, con router tp-link e mio zio che abita accanto ha alice. Il mio pc tramite wirless prende il segnale sia del mio tp-link (ovviamente XD) che di mio zio e lui mi ha dato la WPA che sta sotto il router di alice, per accedere alla sua linea (teletu ogni tanto si disconnette ed è un po’ una rogna). Ciò che vorrei sapere è: posso quindi sommare, quindi fare il bond delle due linee per andare un po’ più veloce col mio pc? Vorrei guadagnare in download. Dal tuo articolo ho capito che posso, facendo diventare le due connessioni di tipo TAP in modo da fare il bounding come se fossero due schede di rete, quelle del primo caso che hai elencato.
    Siccome io so poco di linux, lo uso abbastanza da noob per fare cose semplici, saresti così gentile da riassumermi cosa dovrei fare e magari i comandi che devo digitare?

    Hai la mia stima per la tua competenza. =)

    Grazie per avermi dedicato un po’ di tempo.

    Alex

    • Ciao,
      grazie per essere passato sul mio blog.
      La mia soluzione è un “hack” e richiede l’utilizzo di un server esterno alla tua rete (che immagino non hai).
      La mia soluzione ti permette di aumentare la banda di una singola connessione. Se non hai un server esterno, l’unica cosa che puoi fare è una sorta di balacing delle connessioni in uscita. Intendo dire che puoi far sì che aprendo due connessioni in uscita, una vada su una ADSL e la successiva vada su un’altra ADSL.
      Per fare ciò puoi seguire le istruzioni in questo tutorial:
      http://lartc.org/howto/lartc.rpdb.multiple-links.html
      Comunque se ti colleghi via wireless dovrai anche avere una scheda wifi che supporta il collegamento a più reti wireless in contemporanea (atheros e diverse intel lo fanno) e quindi avviare delle interfaccie virtuali così come ho illustrato qua.

      • 3 Alex

        Grazie per la risposta, adesso mi è tutto più chiaro.


  1. 1 Routing “ad-hoc” per alcuni programmi « Otacon22 blog – オタコン22 ブログ

Lascia un commento