Avanti Indietro Indice

10. Classificatori

10.1 Introduzione

Per specificare come indirizzare i pacchetti nelle classi corrispondenti è possibile utilizzare i filtri o classificatori. Ogni pacchetto che arriva è sottoposto ai filtri che decidono, in base alle indicazioni fornite, in quale classe/coda devono essere collocati.

Riprendendo il grafico precedente e aggiungendo i filtri si completa la realizzazione del tc basato su CBQ:


             +------------------- QDISC CBQ -------------------+
             |+--------------- CLASSE CBQ ROOT ---------------+|                  ______
             ||                                               ||                 /      \
             ||          +-CLASSE A 8Mbit prio 3 ---+         ||                |  ROOT  |
             ||    +---+ |    +----------------+    |         ||                 \______/
Pacchetto -->==--+-|F1 |-= -> | SFQ            |--> = ---+    ||                  /10:1\           
             ||  | +---+ |    +----------------+    |    |    ||           8Mbit /      \ 2Mbit
             ||  |       +--------------------------+    |    ||           ______       ______
             ||  |                                       +--> ==--->      /      \     /      \
             ||  |       +-CLASSE B 2Mbit prio 2 ---+    |    ||         |CLASSE A|   |CLASSE B|
             ||  | +---+ |    +--------------+      |    |    ||          \______/     \______/
             ||  +-|F2 |-= -> | FIFO         | ---> = ---+    ||           10:100       10:200
             ||    +---+ |    +--------------+      |         ||
             ||          +--------------------------+         ||
             |+-----------------------------------------------+|
             +-------------------------------------------------+

F1 e F2 sono i due filtri che in base alle impostazioni fornite provvedono a smistare i pacchetti nelle classi previste.

Per creare, rimuove, cambiare un filtro è necessario utilizzare, in modo simile alle discipline, il comando tc filter:

# tc filter help
Usage: tc filter [ add | del | change | get ] dev STRING
       [ pref PRIO ] [ protocol PROTO ]
       [ estimator INTERVAL TIME_CONSTANT ]
       [ root | classid CLASSID ] [ handle FILTERID ]
       [ [ FILTER_TYPE ] [ help | OPTIONS ] ]

       tc filter show [ dev STRING ] [ root | parent CLASSID ]
Where:
FILTER_TYPE := { rsvp | u32 | fw | route | etc. }
FILTERID := ... format depends on classifier, see there
OPTIONS := ... try tc filter add <desired FILTER_KIND> help

dev:      si deve specificare l'interfaccia/dispositivo su cui si desidera controllare 
          il traffico. (es. dev eth0).
pref:     priorità associata alla disciplina
protocol: protocollo dei pacchetti che devono essere filtrati (es. protocol ip)
estimator:estimatore
handle:   identificatore della classe verso cui devono essere inviati i pacchetti filtrati
          con successo
FILTER_TYPE: filtro che si intende utilizzare (rsvp, route, fw, ...)

10.2 Filtri

Si possono utilizzare diversi filtri, alcuni anche molto complessi e completi:

Tabella di routing

Utilizzando il programma ip, presente nel paccheto iproute2, è possibile associare ad ogni instradamento un "identificatore" che lo contraddistingua. Attraverso tc è possibile poi definire un filtro in cui si può specificare verso quale classe/coda deve essere inviato un pacchetto in base all'identificatore assegnato.

# tc filter add route help

Usage: ... route [ from REALM | fromif TAG ] [ to REALM ]
                [ flowid CLASSID ] [ police POLICE_SPEC ]
       POLICE_SPEC := ... look at TBF
       CLASSID := X:Y

from:   provenienza dei pacchetti (REALM è il valore associato ad un instradamento con ip)
to:     destinazione dei pacchetti 
flowid: flusso, classe dove dirigere i pacchetti   
police: serve a specificare in determinati casi (numero eccessivo di pacchetti/bytes, 
        raggiungimento limiti) l'azione (riclassifica, scarta, continua) 
        da intraprendere.

        police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]
                [ peakrate BPS ] [ avrate BPS ]
                [ ACTION ]
              Where: ACTION := reclassify | drop | continue 

Esempio:
--------

# ------------------------------------------------------------------------------------------
# Aggiungiamo un instradamento che diriga i pacchetti destinati all'indirizzo 192.168.0.0/24 
# verso l'instradamento di default 192.168.0.1 interfaccia eth1, inoltre gli associamo il 
# valore identificativo 1 
# ------------------------------------------------------------------------------------------
ip route add 192.168.0.0/24 via 192.168.0.1 dev eth1 realm 1

# ------------------------------------------------------------------------------------------
# I pacchetti destinati all'indirizzo 192.168.0.0/24 (to 1) sono diretti alla classe 1:10
# 'to 1' si riferisce all'instradamento indicato con ip route precedentemente (...realm 1)
# ------------------------------------------------------------------------------------------
tc filter add dev eth1 parent 1:0 protocol ip prio 10 route to 1 classid 1:10

# ------------------------------------------------------------------------------------------
# I pacchetti provenienti dall'indirizzo 192.168.0.0/24 (from 1) sono diretti alla classe 1:10
# ------------------------------------------------------------------------------------------
tc filter add dev eth1 parent 1:0 protocol ip prio 10 route from 1 classid 1:10
Firewall

Netfilter/iptables consentono di manipolare i pacchetti e in particolare di contrassegnarli con un numero utilizzando l'obiettivo -j MARK. Attraverso questo numero è possibile poi indicare a tc come trattare il pacchetto, verso quale classe indirizzarlo. E' probabilmente la soluzione più semplice ma non la più efficiente.

# tc filter add fw help

Usage: ... fw [ classid CLASSID ] [ police POLICE_SPEC ]
       POLICE_SPEC := ... look at TBF
       CLASSID := X:Y

classid: id (identificatore) della classe a cui inviare i pacchetti (es. 10:1)
police:  vedi sopra


Esempio:
--------

# ------------------------------------------------------------------------------------------
# impostiamo una variabile MAIL a cui associamo il valore 1
# ------------------------------------------------------------------------------------------
MAIL=1

# ------------------------------------------------------------------------------------------
# con iptables impostiamo una regola che modifichi i pacchetti destinati alla porta smtp 
# (--dport smtp) "marcandoli" con il valore MAIL (=1) (--setmark $MAIL). 
# ------------------------------------------------------------------------------------------
iptables -I PREROUTING -t mangle -p tcp -d ... --dport smtp -j MARK --setmark $MAIL

# ------------------------------------------------------------------------------------------
# Aggiungiamo e associamo un filtro all'interfaccia eth1 (dev eth1) che per i pacchetti con 
# protocollo ip (protocol ip) e marcati con MAIL ossia 1 (handle $MAIL) provveda a inviarli
# alla classe 1:1 (classid 1:1)
# ------------------------------------------------------------------------------------------
tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle $MAIL fw classid 1:1
U32

Questa tecnica permette di filtrare i pacchetti in base al contenuto delle intestazioni (IP/TCP/...), quindi può permettere un'ottimo controllo. Permette inoltre di evitare l'utilizzo del filtraggio dei pacchetti (firewall) e in particolare l'utilizzo del marcamento dei pacchetti garantendo così maggior efficienza. Per ragioni di comodità è possibile utilizzare anche u16 o u8.

tc filter add u32 help
Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]
               [ police POLICE_SPEC ] [ offset OFFSET_SPEC ]
               [ ht HTID ] [ hashkey HASHKEY_SPEC ]
               [ sample SAMPLE ]
or         u32 divisor DIVISOR

Where: SELECTOR := SAMPLE SAMPLE ...
       SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} } SAMPLE_ARGS
       FILTERID := X:Y:Z

match: lunghezza del pattern espressa in numero di bit (u32 = 32 bit, u16 = 16 bit, ...)
link:
classid: id (identificatore) della classe a cui inviare i pacchetti (es. 10:1)
police:  vedi sopra
offset:  scostamento in bytes (1 bytes = 8 bit), permette di "saltare" alcuni bytes
ht:      hash table
hashkey: ...
sample:  ...

Il selettore U32 consente di specificare precisamente quali bits si desidera consultare nelle intestazioni. u32 specifica che il pattern deve essere di 32 bit, si può utilizzare se più comodo anche un patern da 16 bit (u16) o 8 bit (u8). Nel caso di pacchetti IP e TCP sono ad esempio consultabili i seguenti campi:


    1 byte = 8 bit

   +    1mo byte   +  2do byte     +     3zo  byte +     4to byte  +        
                                                            
    0 1 2 3 4 5 6 7|8 9 0 1 2 3 4 5|6 7 8 9 0 1 2 3|4 5 6 7 8 9 0 1 
   -----------------------------------------------------------------
   |Version|  IHL  |Type of Service|          Total Length         | = 4 byte = 32 bit 
   -----------------------------------------------------------------
   |         Identification        |Flags|      Fragment Offset    | = 4 byte 
   -----------------------------------------------------------------
   |  Time to Live |    Protocol   |         Header Checksum       | = ...
   -----------------------------------------------------------------
   |                       Source Address                          |
   -----------------------------------------------------------------
   |                    Destination Address                        |
   -----------------------------------------------------------------
   |                    Options                    |    Padding    |
   -----------------------------------------------------------------
                         
                         [INTESTAZIONE IP totale 20 byte]

    0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
   -----------------------------------------------------------------
   |          Source Port          |       Destination Port        |
   -----------------------------------------------------------------
   |                        Sequence Number                        |
   -----------------------------------------------------------------
   |                    Acknowledgment Number                      |
   -----------------------------------------------------------------
   |  Data |           |U|A|P|R|S|F|                               |
   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   |       |           |G|K|H|T|N|N|                               |
   -----------------------------------------------------------------
   |           Checksum            |         Urgent Pointer        |
   -----------------------------------------------------------------

                        [INTESTAZIONE TCP]

Per identificare i campi è necessario indicare il PATTERN (valore da confrontare) e la MASK (gruppo di bit interessati). Opzionalmente è possibile inoltre specificare uno scostamento (OFFSET) e l'intestazione (IP/TCP) che si desidera esaminare. I pacchetti TCP, UDP e ICMP sono incapsulati in pacchetti IP.

bit 0 1 2 3|4 5 6 7|8 9 0 1|2 3 4 5|6 7 8 9|0 1 2 3|4 5 6 7|8 9 0 1 
   -----------------------------------------------------------------
   |Version|  IHL  |Type of Service|          Total Length         | = 4 byte = 32 bit 
   -----------------------------------------------------------------
   \__ ____/\___ __/
       \         \______
        \               |
         -------------v V  
protocol ip u32 match 0 0 00 0000 
                      ^ ^ ^^ ^^^^
                      | | |    '> 16 bit = Total lenght 
                      | | '> 8 bit = TOS  
                      | '> 4 bit = IHL
                      '> 4 bit = version

Per specificare TOS dovremo allora utilizzare come MASK 0 0 FF 0000.
Per specificare IHL dovremo utilizzare come MASK        0 F 00 0000.
Per specificare Total length ....                       0 0 00 FFFF.

Per spostarci sulla seconda linea è necessario usare l'OFFSET (scostamento) espresso in byte:

bit 0 1 2 3|4 5 6 7|8 9 0 1|2 3 4 5|6 7 8 9|0 1 2 3|4 5 6 7|8 9 0 1 
   -----------------------------------------------------------------
   |         Identification        |Flags|      Fragment Offset    | = 4 byte 
   -----------------------------------------------------------------
   \______________________________/
                   \                  
                    \__ 
                       v  
protocol ip u32 match 0000 0000 at 4
                      ^^^^      ^^^^
                       |         '> scostamento OFFSET 4 byte
                       '> 16 bit = Identification

Per spostarci all'intestazione successiva è necessario utilizzare l'opzione nexthdr
(eventualmente si può indicare anche un offset).
protocol ip u32 match ........ at nexthdr+0

Questo metodo non è molto intuitivo per cui è stata aggiunta la possibilità di utilizzare al posto dei numeri delle stringhe:

 ----------------------------------------------------------------------
| Protocollo  |  Selettore  |   Parametri  |  Descrizione             |
|             |             | pattern mask |                          |
 ---------------------------------------------------------------------- 
| match ip    |             |              |                          |
|             |  src        |  prefix/32   | indirizzo IP sorgente    |
|             |  dst        |  prefix/32   | indirizzo IP destinazione|  
|             |  tos        |  tos u8      | TOS (Type Of Service)    |
|             |  dsfield    |  tos u8      |        " (sinonimo)      |
|             |  precedence |  tos u8      |        " (sinonimo)      |
|             |  ihl        |  ihl u8      | campo IP Total Lenght    |
|             |  protocol   |  prot u8     | campo IP protocol        |
|             |  nofrag     |              | pacchetto non frammentato|  
|             |  firstfrag  |              | pacchetto primo frammento|  
|             |  df         |              | Don't Fragment impostato | 
|             |  mf         |              | More Fragments impostato | 
|             |  sport      | port u16     | Porta sorgente  (tcp/udp)|  
|             |  dport      | port u16     | Porta destinazione (")   |
|             |  icmp_type  | type u8      | tipo   pacchetto ICMP    |
|             |  icmp_code  | code u8      | codice pacchetto ICMP    |
|match ip6    |             |              |                          |
|             |  src        | prefix/128   | indirizzo IPv6 sorgente  |
|             |  dst        | prefix/128   | indirizzo IPv6 dest.     |
|             |  flowlabel  | flow u32     | IPv6 flow label          |
|match udp,tcp|             |              |                          |
|             |  src        | src u16      | porta sorgente           |
|             |  dst        | dst u16      | porta destinazione       |
|match icmp   |             |              |                          |
|             |  type       | type u8      | tipo   pacchetto ICMP    |
|             |  code       | code u8      | codice pacchetto ICMP    |
|_____________|_____________|______________|__________________________|

u8  = 0xff
u16 = 0xffff
u32 = 0xffffffff

USO
---                           protocollo  selettore  PATTERN (www)  MASK (u16)
                             /           /          /              /
tc filter add ... u32 match tcp         dst        80           0xffff 


tc filter add ... u32 match ip  dst      192.168.0.1/24
                      match ip  protocol 6     0xff
                      match ip  tos      0x10  0xff


Esempi:
--------

# ------------------------------------------------------------------------------------------
# Crea un filtro che identifichi i pacchetti ip con bit tos pari a 0x10 e li invii alla 
# classe 1:4. 0xff è la maschera ossia i bit da controllare.
# ------------------------------------------------------------------------------------------
tc filter add dev eth0 parent 1:10 prio 10 u32 match ip tos 0x10 0xff flowid 1:4


# ------------------------------------------------------------------------------------------
# Crea un filtro che identifichi i pacchetti tcp (campo Protocol presente nell'intestazione 
# ip impostato a tcp ossia 0x6) con porta destinazione (presente nell'intestazione tcp) 
# pari a 80 (www) e li invii alla classe 1:3. 0xffff e 0xff sono le maschera.
# ------------------------------------------------------------------------------------------
tc filter add dev eth0 parent 1:10 prio 10 u32 match tcp dport 80 0xffff
          match ip protocol 0x6 0xff flowid 1:3


rsvp

rsvp presenta i seguenti parametri:

tc filter add rsvp help
Usage: ... rsvp ipproto PROTOCOL session DST[/PORT | GPI ]
                [ sender SRC[/PORT | GPI ]
                [ classid CLASSID ] [ police POLICE_SPEC ]
                [ tunnelid ID ] [ tunnel ID skip NUMBER ]
Where: GPI := { flowlabel NUMBER | spi/ah SPI | spi/esp SPI |
                u{8|16|32} NUMBER mask MASK at OFFSET}
       POLICE_SPEC := ... look at TBF
       FILTERID := X:Y

ipproto: protocollo
session: indirizzo destinazione ed eventuale porta
sender:  indirizzo sorgente e porta
classid: identificatore della classe
police:  ...

es.:  tc filter add dev eth0 parent 1:10 protocol ip rsvp ipproto udp session 
         10.0.0.1 flowid 1:200


Avanti Indietro Indice