Control de Tráfico P2P usando HTB + tcng + ipp2p

Este foro es para todo lo relacionado con la documentación, artículos de ayuda, Wikis, tips & hints y las traducciones de Arch (tanto en progreso como las finalizadas).
Responder
bimbo
Novato
Mensajes: 19
Registrado: 12 Jun 2005, 09:48
Ubicación: México

Control de Tráfico P2P usando HTB + tcng + ipp2p

Mensaje por bimbo » 28 Jun 2005, 22:20

Control de Tráfico P2P usando HTB + tcng + ipp2p

Este howto tiene como finalidad mostrar al usuario lo fácil que es controlar el tráfico p2p usando el qdisc HTB, la utilidad tcng (como reemplazo de tc) e ipp2p, un módulo que se agrega al kernel y al iptables. Se usara la configuración con kernel 2.6, ya que no uso 2.4 además de que se recomienda cambiar lo antes posible de 2.4.x a 2.6, ya que este ya es estable y tiene varias ventajas sobre el vieja 2.4.
Nota: Este howto puede parecer largo, pero es sólo por los scripts que se postean, los cuáles solo hay q copiar y pegar en nuestra computadora, darles permiso de ejecución y listo.

ACTUALIZACIONES
02/07/2005 - Agregado "prioridades" a la configuración tcng (para tener el ancho de banda disponible siempre para cualquier aplicación no p2p)
06/07/2005 - Actualmente hay un problema moldeando el tráfico de bittorrent, consultando con LARTC mailing list por una posible solución

Configuración en 3 pasos

* Configurando el kernel
* Instalando tcng e ipp2p, y script para tcng
* Controlando el tráfico

Lo que no se va a tratar aquí­ es ¿qué es HTB (a profundidad, sólo una breve descripción)?, formas complejas de usar estas aplicaciones antes listadas.

Configurando el kernel
El HTB es un planificador de paquetes (packet scheduler), lo uso en este tutorial ya que se dice trabajar mejor que el viejo CBQ, y con el paso del tiempo se ha hecho más robusto y estable.
Para poder usar este HTB y tcng, hace falta hacer unos cambios al kernel, necesariamente habrá q recompilar y reiniciar, ya que algunas opciones sólo se pueden compilar nativamente, no como módulos. Esto es lo necesario:

Código: Seleccionar todo

Device Drivers  --->
 Networking support  --->
  Networking options  --->
   [*] Network packet filtering (replaces ipchains)  --->
    IP: Netfilter Configuration  --->
     [*] Connection mark tracking support
     <M>   netfilter MARK match support
     <M>   Packet mangling
     <M>     MARK target support                                                      
     <M>     CLASSIFY target support                                                                         
     <M>     CONNMARK target support
   QoS and/or fair queueing  --->
    [*] QoS and/or fair queueing
     <M>   HTB packet scheduler
     <M>   SFQ queue
     <M>   Diffserv field marker
     [*]   Packet classifier API
     <M>     TC index classifier
     <M>     Routing table based classifier
     <M> U32 classifier
     [*] Traffic policing (needed for in/egress)
Asumo que saben recompilar su kernel y saben las opciones necesarias para su configuración cuando usen iptables. Después solo basta hacer: make && make modules_install; shutdown -r now (para reiniciar).

Instalando tcng e ipp2p
A partir de aquí­ el trabajo es muy sencillo, y todaví­a más porque estos dos los he subido al AUR http://aur.archlinux.org , y los pueden encontrar escribiendo en la barra de search: "tcng" e "ipp2p", sólo falta hacer un makepkg (si no sabes usar el AUR te recomiendo leer el wiki, es muy fácil y lo considerarí­a casi necesario para el uso de archlinux ya que todaví­a no se dispone de un repositorio tan grande como el de distros gentoo o debian).
Nota: Es necesario que leas el PKGBUILD del ipp2p, ya que es posible que tengas que editarlo.
Una vez instalados es hora de instalar este script que he modificado del original ubicado en http://linux-ip.net/code/tcng/tcng.init, para que pueda ser usado "a la primera" en archlinux, guardarlo como tcng en /etc/rc.d/tcng y darle permisos de ejecución con chmod +x (chmod +x /etc/rc.d/tcng)

Código: Seleccionar todo

 #! /bin/bash




























gripe  () { echo "[email protected]" >&2;       }
abort  () { gripe "[email protected]"; exit 1;  }
inform () { test "$tcdebug" -ge "$INFORM" && gripe "[email protected]" ; }
debug  () { test "$tcdebug" -ge "$DEBUG"  && gripe "[email protected]" ; }



DEBUG=2
INFORM=1





tc=$( which tc )


tcc=/usr/local/bin/tcc




sysconfig=/etc/sysconfig/tcng
. $sysconfig



tcstats=${tcstats:-no}



tcdebug=${tcdebug:-0}

test "$tcstats" = "yes"  && stats="-s"

debug "About to test configuration file specifications"
test ! -z "$TCCONF" || abort "\$TCCONF must contain path to config; got $TCCONF."
test -r "$TCCONF"   || abort "\$TCCONF must be readable: $TCCONF is not."

offMsg=OFF
onMsg=ON


. /etc/rc.d/functions


  isup () {





  local d=$1
  local qtype=$2
  if test "$qtype" = "ingress" ; then
    $tc qdisc show dev $d 2>/dev/null | grep -q $qtype && return 1
    # -- no ingress qdisc, return safely
    return 0
  fi
  #
  # -- sadly, we break our nice symmetry, because the "root" qdisc
  #    can sometimes be a dsmark qdisc....so; let's account for it
  #
  $tc qdisc show dev $d 2>/dev/null | grep -q root   && return 1
  $tc qdisc show dev $d 2>/dev/null | grep -q dsmark && return 1
  #
  # -- Yowza!  Found no qdiscs.
  #
  return 0 ;
  #
}


  exists_qdisc () {       # -- ingress or root qdisc exist?  return 1


  local d=$1
  isup $d ingress
  test "$?" -gt "0" && return 1
  isup $d root
  test "$?" -gt "0" && return 1
  return 0 ;
}


  clearqdisc () {





  local d=$1
  local qtype=$2
  isup $d $qtype
  if test "$?" -eq "1" ; then
    inform "Removing $qtype qdisc: $d"
    $tc qdisc del dev $d $qtype 2>/dev/null
  else
    inform "No $qtype qdisc running on device: $d"
  fi
}


  clearingress () {       # -- remove an ingress qdisc


  local d=$1
  clearqdisc $d ingress
}


  clearroot () {          # -- remove a root qdisc


  local d=$1
  clearqdisc $d root
}


  start () {




    test "$#" -ne "0" && local [email protected]
    stat_busy "Starting tcng services"
    #
    # -- first, make sure that the configuration makes sense to tcc
    #
    debug "About to check syntax on tcng config file ${TCCONF##*/}"
    #
    # -- then, make sure no traffic control is currently in use on
    #    any devices specified in the tcng configuration
    #
    debug "About to test for active qdiscs on devices in ${TCCONF##*/}"
    for d in $( $tcc $TCCONF | awk '/^tc/{ print $5 }' | sort | uniq ) ; do
      exists_qdisc $d
      if test "$?" -ne "0" ; then
        gripe "Found active traffic control on device $d."
        gripe "Device $d is used in $TCCONF."
        gripe "Remove traffic control with \"$0 stop $d\"."
        abort "Consider also \"$0 restart\" or \"$0 flush\"."
      fi
    done
    #
    # -- now, actually parse the tcng config file and spit it through
    #    a little loop, which executes the tc commands one at a time
    #
    $tcc $TCCONF | grep -Ev "^#|^$" | sed -e "s/^tc//" | {
      while read cmd ; do
        #
        # -- inform the user we are adding qdiscs to devices when new
	#    devices are found
        #
        thisdev=$( echo $cmd | awk '/root/{print $4}' )
        test "$thisdev" = "" || inform "Adding root qdisc to $thisdev"
        thisdev=$( echo $cmd | awk '/ingress/{print $4}' )
        test "$thisdev" = "" || inform "Adding ingress qdisc to $thisdev"
        #
        # -- debug, if necessary...this will print the command just prior
        #    to execution.
        #
        debug "Executing: $cmd"
        $tc $cmd
      done
    }
    stat_done  # -- this is sort of silly, but some people like the pretty
             #    green "OK" to make them feel warm and fuzzy at night
}



  stop () {


  test "$#" -ne "0" && local [email protected]
  stat_busy "Stopping tcng services"
  for d in $devs; do
    inform "Stopping traffic control on: $d"
    clearingress  $d
    clearroot     $d
  done	
  stat_done
}



  status () {


  if [ "$1" ]; then devs=$*; fi	
  for d in $devs; do
    exists_qdisc $d
    if test "$?" -gt "0" ; then
      gripe "traffic control on $d: [$onMsg]" ;
    else
      gripe "traffic control on $d: [$offMsg]" ;
    fi
  done		
}


  show () {


  what=all
  if test "$#" -gt "0" ; then
    case "$1" in
      qdisc|class|filter) what=$1 ; shift  ;;
    esac
    test "$#" -gt "0" && local [email protected]
  fi
  for d in $devs; do
    isup $d root
    if test "$?" -gt "0" ; then
      for OBJ in qdisc class filter ; do
        test "$what" = "all" || test "$what" = "$OBJ" \
          && $tc $stats $OBJ show dev $d
      done
    fi
  done ;
}





devs=$( ifconfig -a | awk '/^\w+:/ || /^lo/ {next}; /^[a-z]/{print $1}' )
command=$1
shift;

case "$command" in
  start)         start         ;;
  flush|panic)	 stop   $devs  ;;   # -- stop ALL traffic control
  stop)	         stop   [email protected]     ;;
  status)        status [email protected]     ;;
  show)          show   [email protected]     ;;	
  restart)       stop   [email protected]
	         start  [email protected]     ;;
  *)
	gripe "Usage: ${0##*/}"
	gripe "  ${0##*/} {start|stop|status|restart} [ device [ ... ] ]"
	abort "  ${0##*/} show [ qdisc|class|filter ] [ device [ ...] ]"
	abort "  ${0##*/} show [ device [ ...] ]"
esac

exit 0
Para poder usar este script es necesario crear el directorio /etc/sysconfig (o modificar el script, que tardarí­as más, pero si tienes una razón fuerte para hacer esto, adelante), después de crear ese directorio, debemos hacer dos cosas, la primera es agregar este archivo (abajo), y la segunda crear el directorio /etc/sysconfig/config. Aquí­ el próximo archivo que debemos guardar como "tcng":

Código: Seleccionar todo










TCCONFBASEDIR=${TCCONFBASEDIR:-/etc/sysconfig/config}






TCCONF=${TCCONF:-$TCCONFBASEDIR/tcrules.tcc}

tcstats=${tcstats:-no}   # -- will suppress statistical output
tcstats=${tcstats:-yes}  # -- will throw the "-s" option to tc

tcdebug=${tcdebug:-0}    # -- for typical startup script usage
tcdebug=${tcdebug:-1}    # -- for a bit of information about what's happening
tcdebug=${tcdebug:-2}    # -- for debugging information









Entenderás el porque de esto ahora que viene el paso 3

Controlando el tráfico
Ahora sí­, a lo que es la configuración con ipp2p y tcng usando HTB; tcng es un reemplazo de tc, éste tiene una sintaxis muy arcaica y difí­cil, lo cuál tcng no, ya que tiene una sintaxis tipo C, más ordenado y sin tanta complicación. Antes de usar iptables con ipp2p, voy a presentar ahora una configuración (que es la que yo uso en este momento, sólo para moldear el tráfico p2p) muy sencilla, que puedes usar si lo único que quieres es moldear el tráfico p2p:

Código: Seleccionar todo

/* Ejemplo de configuración de tcng usando HTB */


dev UPLOAD {
    egress { (3)

        /* Aqui definimos el nombre de nuestra clase */ 

        class ( <$p2p> ) ;
        class ( <$other> )  if 1 ; 

        /* Aquí­ configuramos cuánto ancho de banda se deja para cada clase */ 

        htb () {
            class ( rate 22kBps, ceil 22kBps ) {
                $p2p   = class ( prio 2, rate  6kBps, ceil 10kBps ) { sfq; } ; 
                $other = class ( prio 1, rate 8kBps, ceil 22kBps ) { sfq; } ;
            }
        }
    }
}
Explicaré brevemente el código: definí­ la macro UPLOAD, ya que sólo se puede moldear el tráfico saliente, el entrante sólo si se está detrás de una NAT, se moldea el tráfico hacia los clientes del servidor. Teniendo la configuración de servidor con NAT, la interface UPLOAD serí­a la interface interna; después se definen 2 clases, p2p y other, p2p se define así­, sin nada más, ya que es sólo para dar un class id (cuando se convierte al lenguaje de tc) que luego será usada por iptables con ipp2p para moldear el tráfico, other se refiere al tráfico que no se haya especificado antes (osea una clase default), después en la función htb() se definen el ancho de banda disponible para cada clase, en kilobytes/s, siendo rate el ancho de banda actual permitido, y ceil hasta donde puede tomar prestado esa clase de otras que no estén siendo usadas. La opción "prio" es muy importante, algunas veces aunq se libere al modem de tener una queue, aún es difí­cil navegar y poder ejecutar otras apliaciones de red (yo lo experimenté con bittorrent), es neccesario agregar esta opción para evitar este problema.
Esta configuración se debe guardar con el nombre "tcrules.tcc" en /etc/sysconfig/config/ , con esa extensión ya que lo que hace el script tcng es ejecutar /usr/local/bin/tcc (se instala con tcng) y necesita tener esa extensión. Después de esto solo queda ejecutar el nuevo script que hemos guardado en /etc/rc.d/, dando un /etc/rc.d/tcng start (es conveniente agregar este script al arreglo DAEMONS en /etc/rc.conf para que se inicie con cada reiniciada). Una vez terminada la parte de tcng, sólo quedan las reglas de iptables para que el tráfico se cheque con ipp2p para ver si contiene tráfico p2p y actuar con las reglas de htb.
Aquí­ posteo mis reglas de iptables para controlar el tráfico:

Código: Seleccionar todo

iptables -t mangle -A PREROUTING -p tcp -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -p tcp -m mark ! --mark 0 -j ACCEPT
iptables -t mangle -A PREROUTING -p tcp -m ipp2p --ipp2p -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp -m mark --mark 1 -j CONNMARK --save-mark
iptables -t mangle -A POSTROUTING -o eth1 -m mark --mark 1 -j CLASSIFY --set-class 2:2
Sólo explicaré lo que hace las reglas número 3 y 5, para no extender más el howto, la explicación de cada regla y algunos otros ejemplos (al ugual que documentación para ipp2p) se encuentran en http://www.ipp2p.org . En la regla 3 se utiliza la librerí­a ipp2p (la cuál necesita que se cargue el módulo ipt_ipp2p, que se instala con el paquete ipp2p: modprobe ipt_ipp2p) -m ipp2p, justo después se especifica --ipp2p, este parámetro es lo mismo que escribir --edk --kazaa --gnu --dc --bit, que son los protocolos mejor manejados por ipp2p, aunque creo que el manejo de paquetes de bittorrent es mejor en la versión "testing", pero de igual forma tiene un problema q no se si esté en mi configuración o en el ipp2p mismo, luego haré más pruebas y actualizaré el tutorial. De la regla 5 sólo hablaré de la parte --set-class 2:2, ésta clase es la que me da tc (en lugar de tener el nombre p2p de tcng, tcc lo convierte a lenguaje tc, por lo tanto dándome 2:2 en lugar de p2p), ésto se puede checar con el script, si le damos /etc/rc.d/tcng show class, ahí­ puedes checar el número que te dió (si usaste todo como yo lo puse sin modificar nada, debe ser la misma 2:2).

Esto es todo por este howto, he demostrado lo sencillo que es moldear el tráfico p2p, aunque parezca un howto extenso es sólo por los scripts y archivos de configuración que aquí­ se encuentran, espero les sirva y lean un poco más acerca de estas poderosas herramientas.

BIMBO

Responder