Controlar el ancho de banda por dirección IP en Linux

El problema

Se me planteó el de problema de intentar controlar el ancho de banda de cada uno de mis clientes de la red. De preferencia por dirección IP y me llevó algo de tiempo encontrar una solución.

El propósito es evitar que un cliente acapare de todo el ancho de banda disponible y anule o limite a los demás.

A lo mejor puede sonar algo trivial, considerando que actualmente existen proveedores de internet que pueden llegar a ofrecer 100 Mbps de descarga o cantidades así, pero en donde estoy solo disponemos de 3 Mbps que tengo que hacer rendir.

Lamentablemente por nuestra ubicación no tenemos otras opciones y si las hay son inestables o costosas, así que no queda más que leer para ver que se puede hacer.

IPCop como tal no ofrece ninguna opción similar, de hecho he considerado varias veces en cambiarme a pFsense, pero le tengo aprecio a esta herramienta, nunca me ha fallado y me parece un poco ingrato cambiarlo por otro software.

tc (traffic control)

Existe un programa en linux que se llama tc  que permite controlar el tráfico de paquetes que circula en una interfaz de red.

Haciendo un símil, imaginen que la tarjeta de red es una carretera, los automóviles son los paquetes que fluyen libremente intercambiando información entre su equipo y sus vecinos.

Básicamente tc permite establecer los mecanismos que controlan la transmisión y recepción de paquetes. Es como poner límites de velocidad a la carretera de la información.

controlar el ancho de banda por dirección IP en linux
Darle a cada usuario lo que necesita.

Mejor que eso, en lugar de establecer un ancho de banda máximo permitido en toda “la carretera”, se puede establecer un límite de velocidad dependiendo del destino al que quieren llegar los paquetes, de esta forma es posible controlar la cantidad de paquetes que consumen cada uno de los destinos (o clientes).

Creo que ni yo me entendí pero la idea es esa.

Instalación

Les recuerdo que utilizo Manjaro una distribución de linux basada en Arch. El paquete que contiene a tc se llama iproute2. IPCop lo tiene instalado por default y Manjaro también, así que probablemente ya lo tienen y ni cuenta se han dado.

El script

Leí mucho sobre el tema hasta que me encontré con un sencillo script en bash que hace lo que necesito en How can I do traffic shaping in Linux by IP?. Sólo tenía que hacerle algunos ajustes.

#! /bin/bash
NETCARD=eth0
MAXBANDWIDTH=100000

# reinit
tc qdisc del dev $NETCARD root handle 1
tc qdisc add dev $NETCARD root handle 1: htb default 9999

# create the default class
tc class add dev $NETCARD parent 1:0 classid 1:9999 htb rate $(( $MAXBANDWIDTH ))kbit ceil $(( $MAXBANDWIDTH ))kbit burst 5k prio 9999

# control bandwidth per IP
declare -A ipctrl

# define list of IP and bandwidth (in kilo bits per seconds) below
ipctrl[192.168.1.1]="256"
ipctrl[192.168.1.2]="256"
ipctrl[192.168.1.3]="256"
ipctrl[192.168.1.4]="256"
ipctrl[192.168.1.5]="256"
ipctrl[192.168.1.6]="256"
ipctrl[192.168.1.7]="256"
ipctrl[192.168.1.8]="256"
ipctrl[192.168.1.9]="256"
ipctrl[192.168.1.10]="256"
ipctrl[192.168.1.11]="256"
ipctrl[192.168.1.12]="256"
ipctrl[192.168.1.13]="256"
ipctrl[192.168.1.14]="256"
ipctrl[192.168.1.15]="256"
ipctrl[192.168.1.16]="256"
ipctrl[192.168.1.17]="256"
ipctrl[192.168.1.18]="256"
ipctrl[192.168.1.19]="256"
ipctrl[192.168.1.20]="256"
ipctrl[192.168.1.21]="256"
ipctrl[192.168.1.22]="256"
ipctrl[192.168.1.23]="256"
ipctrl[192.168.1.24]="256"
ipctrl[192.168.1.25]="256"
ipctrl[192.168.1.26]="256"
ipctrl[192.168.1.27]="256"
ipctrl[192.168.1.28]="256"
ipctrl[192.168.1.29]="256"
ipctrl[192.168.1.30]="256"
ipctrl[192.168.1.31]="256"
ipctrl[192.168.1.32]="256"
ipctrl[192.168.1.33]="256"
ipctrl[192.168.1.34]="256"
ipctrl[192.168.1.35]="256"
ipctrl[192.168.1.36]="256"
ipctrl[192.168.1.37]="256"
ipctrl[192.168.1.38]="256"
ipctrl[192.168.1.39]="256"
ipctrl[192.168.1.40]="256"
ipctrl[192.168.1.41]="256"
ipctrl[192.168.1.42]="256"
ipctrl[192.168.1.43]="256"
ipctrl[192.168.1.44]="256"
ipctrl[192.168.1.45]="256"
ipctrl[192.168.1.46]="256"
ipctrl[192.168.1.47]="256"
ipctrl[192.168.1.48]="256"
ipctrl[192.168.1.49]="256"
ipctrl[192.168.1.50]="256"
ipctrl[192.168.1.51]="256"
ipctrl[192.168.1.52]="256"
ipctrl[192.168.1.53]="256"
ipctrl[192.168.1.54]="256"
ipctrl[192.168.1.55]="256"
ipctrl[192.168.1.56]="256"
ipctrl[192.168.1.57]="256"
ipctrl[192.168.1.58]="256"
ipctrl[192.168.1.59]="256"
ipctrl[192.168.1.60]="256"
ipctrl[192.168.1.61]="256"
ipctrl[192.168.1.62]="256"
ipctrl[192.168.1.63]="256"
ipctrl[192.168.1.64]="256"
ipctrl[192.168.1.65]="256"
ipctrl[192.168.1.66]="256"
ipctrl[192.168.1.67]="256"
ipctrl[192.168.1.68]="256"
ipctrl[192.168.1.69]="256"
ipctrl[192.168.1.70]="256"
ipctrl[192.168.1.71]="256"
ipctrl[192.168.1.72]="256"
ipctrl[192.168.1.73]="256"
ipctrl[192.168.1.74]="256"
ipctrl[192.168.1.75]="256"
ipctrl[192.168.1.76]="256"
ipctrl[192.168.1.77]="256"
ipctrl[192.168.1.78]="256"
ipctrl[192.168.1.79]="256"
ipctrl[192.168.1.80]="256"
ipctrl[192.168.1.81]="256"
ipctrl[192.168.1.82]="256"
ipctrl[192.168.1.83]="256"
ipctrl[192.168.1.84]="256"
ipctrl[192.168.1.85]="256"
ipctrl[192.168.1.86]="256"
ipctrl[192.168.1.87]="256"
ipctrl[192.168.1.88]="256"
ipctrl[192.168.1.89]="256"
ipctrl[192.168.1.90]="256"
ipctrl[192.168.1.91]="256"
ipctrl[192.168.1.92]="256"
ipctrl[192.168.1.93]="256"
ipctrl[192.168.1.94]="256"
ipctrl[192.168.1.95]="256"
ipctrl[192.168.1.96]="256"
ipctrl[192.168.1.97]="256"
ipctrl[192.168.1.98]="256"
ipctrl[192.168.1.99]="256"
ipctrl[192.168.1.100]="256"
ipctrl[192.168.1.101]="256"
ipctrl[192.168.1.102]="256"
ipctrl[192.168.1.103]="256"
ipctrl[192.168.1.104]="256"
ipctrl[192.168.1.105]="256"
ipctrl[192.168.1.106]="256"
ipctrl[192.168.1.107]="256"
ipctrl[192.168.1.108]="256"
ipctrl[192.168.1.109]="256"
ipctrl[192.168.1.110]="256"
ipctrl[192.168.1.111]="256"
ipctrl[192.168.1.112]="256"
ipctrl[192.168.1.113]="256"
ipctrl[192.168.1.114]="256"
ipctrl[192.168.1.115]="256"
ipctrl[192.168.1.116]="256"
ipctrl[192.168.1.117]="256"
ipctrl[192.168.1.118]="256"
ipctrl[192.168.1.119]="256"
ipctrl[192.168.1.120]="256"
ipctrl[192.168.1.121]="256"
ipctrl[192.168.1.122]="256"
ipctrl[192.168.1.123]="256"
ipctrl[192.168.1.124]="256"
ipctrl[192.168.1.125]="256"
ipctrl[192.168.1.126]="256"
ipctrl[192.168.1.127]="256"
ipctrl[192.168.1.128]="256"
ipctrl[192.168.1.129]="256"
ipctrl[192.168.1.130]="256"
ipctrl[192.168.1.131]="256"
ipctrl[192.168.1.132]="256"
ipctrl[192.168.1.133]="256"
ipctrl[192.168.1.134]="256"
ipctrl[192.168.1.135]="256"
ipctrl[192.168.1.136]="256"
ipctrl[192.168.1.137]="256"
ipctrl[192.168.1.138]="256"
ipctrl[192.168.1.139]="256"
ipctrl[192.168.1.140]="256"
ipctrl[192.168.1.141]="256"
ipctrl[192.168.1.142]="256"
ipctrl[192.168.1.143]="256"
ipctrl[192.168.1.144]="256"
ipctrl[192.168.1.145]="256"
ipctrl[192.168.1.146]="256"
ipctrl[192.168.1.147]="256"
ipctrl[192.168.1.148]="256"
ipctrl[192.168.1.149]="256"
ipctrl[192.168.1.150]="256"
ipctrl[192.168.1.151]="256"
ipctrl[192.168.1.152]="256"
ipctrl[192.168.1.153]="256"
ipctrl[192.168.1.154]="256"
ipctrl[192.168.1.155]="256"
ipctrl[192.168.1.156]="256"
ipctrl[192.168.1.157]="256"
ipctrl[192.168.1.158]="256"
ipctrl[192.168.1.159]="256"
ipctrl[192.168.1.160]="256"
ipctrl[192.168.1.161]="256"
ipctrl[192.168.1.162]="256"
ipctrl[192.168.1.163]="256"
ipctrl[192.168.1.164]="256"
ipctrl[192.168.1.165]="256"
ipctrl[192.168.1.166]="256"
ipctrl[192.168.1.167]="256"
ipctrl[192.168.1.168]="256"
ipctrl[192.168.1.169]="256"
ipctrl[192.168.1.170]="256"
ipctrl[192.168.1.171]="256"
ipctrl[192.168.1.172]="256"
ipctrl[192.168.1.173]="256"
ipctrl[192.168.1.174]="256"
ipctrl[192.168.1.175]="256"
ipctrl[192.168.1.176]="256"
ipctrl[192.168.1.177]="256"
ipctrl[192.168.1.178]="256"
ipctrl[192.168.1.179]="256"
ipctrl[192.168.1.180]="256"
ipctrl[192.168.1.181]="256"
ipctrl[192.168.1.182]="256"
ipctrl[192.168.1.183]="256"
ipctrl[192.168.1.184]="256"
ipctrl[192.168.1.185]="256"
ipctrl[192.168.1.186]="256"
ipctrl[192.168.1.187]="256"
ipctrl[192.168.1.188]="256"
ipctrl[192.168.1.189]="256"
ipctrl[192.168.1.190]="256"
ipctrl[192.168.1.191]="256"
ipctrl[192.168.1.192]="256"
ipctrl[192.168.1.193]="256"
ipctrl[192.168.1.194]="256"
ipctrl[192.168.1.195]="256"
ipctrl[192.168.1.196]="256"
ipctrl[192.168.1.197]="256"
ipctrl[192.168.1.198]="256"
ipctrl[192.168.1.199]="256"
ipctrl[192.168.1.200]="256"
ipctrl[192.168.1.201]="256"
ipctrl[192.168.1.202]="256"
ipctrl[192.168.1.203]="256"
ipctrl[192.168.1.204]="256"
ipctrl[192.168.1.205]="256"
ipctrl[192.168.1.206]="256"
ipctrl[192.168.1.207]="256"
ipctrl[192.168.1.208]="256"
ipctrl[192.168.1.209]="256"
ipctrl[192.168.1.210]="256"
ipctrl[192.168.1.211]="256"
ipctrl[192.168.1.212]="256"
ipctrl[192.168.1.213]="256"
ipctrl[192.168.1.214]="256"
ipctrl[192.168.1.215]="256"
ipctrl[192.168.1.216]="256"
ipctrl[192.168.1.217]="256"
ipctrl[192.168.1.218]="256"
ipctrl[192.168.1.219]="256"
ipctrl[192.168.1.220]="256"
ipctrl[192.168.1.221]="256"
ipctrl[192.168.1.222]="256"
ipctrl[192.168.1.223]="256"
ipctrl[192.168.1.224]="256"
ipctrl[192.168.1.225]="256"
ipctrl[192.168.1.226]="256"
ipctrl[192.168.1.227]="256"
ipctrl[192.168.1.228]="256"
ipctrl[192.168.1.229]="256"
ipctrl[192.168.1.230]="256"
ipctrl[192.168.1.231]="256"
ipctrl[192.168.1.232]="256"
ipctrl[192.168.1.233]="256"
ipctrl[192.168.1.234]="256"
ipctrl[192.168.1.235]="256"
ipctrl[192.168.1.236]="256"
ipctrl[192.168.1.237]="256"
ipctrl[192.168.1.238]="256"
ipctrl[192.168.1.239]="256"
ipctrl[192.168.1.240]="256"
ipctrl[192.168.1.241]="256"
ipctrl[192.168.1.242]="256"
ipctrl[192.168.1.243]="256"
ipctrl[192.168.1.244]="256"
ipctrl[192.168.1.245]="256"
ipctrl[192.168.1.246]="256"
ipctrl[192.168.1.247]="256"
ipctrl[192.168.1.248]="256"
ipctrl[192.168.1.249]="256"
ipctrl[192.168.1.250]="256"
ipctrl[192.168.1.251]="256"
ipctrl[192.168.1.252]="256"
ipctrl[192.168.1.253]="256"
ipctrl[192.168.1.254]="256"

mark=0
for ip in "${!ipctrl[@]}"
do
    mark=$(( mark + 1 ))
    bandwidth=${ipctrl[$ip]}

    # traffic shaping rule
    tc class add dev $NETCARD parent 1:0 classid 1:$mark htb rate $(( $bandwidth ))kbit ceil $(( $bandwidth ))kbit burst 5k prio $mark

    # netfilter packet marking rule
    iptables -t mangle -A INPUT -i $NETCARD -s $ip -j CONNMARK --set-mark $mark

    # filter that bind the two
    tc filter add dev $NETCARD parent 1:0 protocol ip prio $mark handle $mark fw flowid 1:$mark

    echo "IP $ip is attached to mark $mark and limited to $bandwidth kbps"
done

#propagate netfilter marks on connections
iptables -t mangle -A POSTROUTING -j CONNMARK --restore-mark

Por ejemplo en donde dice, NETCARD no es eth0, IPCop lo llama lan-1. Luego en donde se define el array ipctrl lo ajuste a un valor adecuado de para mis direcciones IP, por ejemplo alguien tendrá direcciones del tipo 192.168.0.x o 192.168.1.x y en el ejemplo le di un valor por default de 256 kbps a cada uno, pero esto es lo bonito de este script, que se puede personalizar individualmente el ancho de banda y eso es una maravilla.

Claro que tiene que guardar el script en un archivo, darle permisos de ejecución, que se ejecute durante el arranque y todas esas cosas que hacemos los administradores de sistemas.

Conclusiones

Tengo algunos puntos de acceso inalámbricos a los que les voy a establecer un límite, total para mandar un mensaje por el Whatsapp no se requiere mucho ancho de banda ¿cierto?, pero una actualización de dispositivo (y si me refiero a tí Apple !!!)  eso es muy diferente ¿Ahora me entienden?.

Intento reservar el ancho de banda para donde lo creo más prioritario. De esa forma todos mis usuarios tiene internet, pero a distintas velocidades.

Como siempre, lo interesante de compartir estas ideas es la posibilidad de recibir sugerencias, señalar errores o analizar otros enfoques. Espero ansioso sus comentarios.

Referencias

30 comentarios en “Controlar el ancho de banda por dirección IP en Linux”

  1. de pronto con un Microtik es más fácil, digo yo, pero nunca está de más tener una alternativa (de las decenas que existen).

    Felicitaciones por el post, Saludos.

    Responder
    • Hola Iván,

      Tengo mucho tiempo escuchando sobre Mikrotik, que Mikrotik aquí, que Mikrotik allá, pero tiene el detalle de la licencia. A lo mejor exagero y la licencia no es muy cara, pero eso evita que me acerque a él. Ahora, si por alguna razón llegara a quitar IPCop (que no tiene para cuando morirse) lo más probable es que lo sustituya por pFsense, que no es linux pero hace bastante ruido :).

      Gracias por comentar 🙂

      Responder
      • claro, si instalas el software en un equipo, claro, es con licencia, pero yo siempre he comprado los dispositivos, hay desde USD$80 hacia arriba. La verdad es que son muy versátiles, los configuras a tu antojo y usan un transformador pequeño de 12V 2A, osea, el consumo es mínimo, incluso puedes configurar cache DNS, priorizar conexiones, bloquear sitios, incluso hay una nueva directiva para bloquear redes sociales y aplicaciones de mensajería como WhatsApp, Messenger y Telegram. O bien puedes permitir el uso, pero bloquear el envío/recepción de contenido multimedia (que es lo que realmente consume ancho de banda), te permite crear VLAN para visitas, uuffff, tienen un montón de aplicaciones y anda muy bien, incluso hay algunos rakeables. Los compro en esta tienda, http://linkstore.cl/#!/Producto=7754&hap-ac-lite-mikrotik-5-100-24ghz-2×2-5ghz-1×1-usb-l4-poe-in-out-rb952ui-5ac2nd al día de hoy, el USD cuesta CLP$660 (son como USD$92).

        Dale una vuelta, al principio también era reacio, pero una vez que los conoces, no tomas otras opciones, al menos en mi caso.

        Saludos.

        Responder
        • Gracias por tus comentarios Ivan,

          Ahora tengo un problema, me gustaría probar pfSense, pero no veo que este IPCop vaya a dejar de funcionar en poco tiempo y ahora que me dio la curiosidad por Mikrotik lo tengo que agregar a la lista.

          Quizás, pruebe algunos dispositivos que vi en la tienda en México, solo para no dejar.

          Saludos !!! 🙂

          Responder
  2. Muy bueno !!, en el define estaría padre poner un contador para la la IP ipctrl[$IP++] = $bw .. algo así no ? para automatizar y ya solo definir las IP que se ocupan por aparte 😛 !!

    Saludos lm4 !

    Responder
    • Y es una excelente recomendación Bucio !!!

      Pero no creas que escribí todas las líneas a mano, hice una pequeña hoja de calculo, concatené los textos y en un abrir y cerrar de hojas ya estaba lista la definición de las 254 IP’s 🙂

      Saludos 🙂

      Responder
  3. En lo personal uso tc tambien, tengo 3 miseros megas que me entrega Telmex y tengo que balancear lo que usa el Apple TV, mi esposa, el iPad de Sofia y mis dispositivos, obvio, dandole preferencia a mi computadora pues es con la que trabajo.

    Para esto defino clases, con esto puedo tener a mi hija en una clase, a mi esposa en otra, el Apple TV en otra, etc. Con esto logro que los dispositivos de una clase en particular tengan un ancho de banda limite, que se comparte de forma equitativa entre ellos (digamos, mis dispositivos) procurando no afectar a los demás.

    Esto lo acompaño con DHCP asociados por dirección MAC y con direcciones IP definidas (siempre son las mismas). Tal vez quieras echarle ojo a este script:

    https://github.com/markuz/scripts/blob/master/tclimit.sh y https://github.com/markuz/scripts/blob/master/rclocalvars

    Responder
    • Muy interesante mi estimado Marcus,

      Veo que hasta la impresora tiene su lugarcito en el script, pero ¿Telmex de 3 megas? conmigo lo entiendo, pero contigo ¿Cuál es su excusa? creo que el mínimo anda en 5 ¿o me equivoco?

      Saludos 🙂

      Responder
  4. Creo recordar que SmoothWall hacia justamente eso, te daba la opcion de controlar el ancho de banda por IP, por interface (GREEN), ademas de otras cosillas como poner horarios de disponibilidad a internet entre otras cosillas. Te hablo de hace mas de 3 años xDD

    Siempre es bueno tener opciones.

    Saludos!!

    Responder
    • Que tal César,

      Nunca conocí a Smoothwall, aunque creo que algunos plugins de las primeras versiones de IPCop se podían usar en ambas plataformas. Lo de los horarios creo que es en el proxy y también ipcop tiene algo similar.

      Supongo que se puede hacer algo parecido con un cron, y segun la hora del sistema aplicar unos u otros límites de velocidad.

      Saludirijillos. 🙂

      Responder
  5. Hola!

    Espero no sonar tan fresa, pero no hay alguna opción que conozcas para Mac? la verdad no tengo espacio para meter una una máquina virtual de Linux y hacer todos los pasos, por eso si de pura buena casualidad tienes una opción alternativa y nativa, te lo agradeceré.

    Saludos

    Responder
  6. hola amigo crees que funcione para limitar a usuarios de internet telmex,mi tarjeta de red no se llama eth0 tiene otro nombre ¿deberia poner ese en el script?

    Responder
  7. Genial esta herramienta, hace mucho tiempo que busco algo así pues tengo tu mismo problema de ancho de banda y actualizaciones de Windows 10 y Apple, solamente le alta poder declarar rangos de IP para hacerlo más sintético.
    Una pregunta, el MAXBANDWIDTH=100000 que significa? 100 megas? yo tengo un máximo de 4 megabits (500 kbytes) de internet. Qué número tendría que poner?

    Muy buena idea esa de hacerlo en hoja de cálculo, ya me estaba por sentar a escribir direcciones una por una…

    Graciasss!!

    Responder
  8. Y cómo se puede establecer un consumo diario de datos por usuario? Digamos que le asignas 1 GB de datos (subida + bajada) y si llega al límite lanza una alerta o bloquea la IP local?. Gracias

    Responder
    • Hola Alecbox,

      Pues la verdad no lo se, este artículo lo aplicaba cuando usaba ipcop, pero hace tiempo que dejé y en su lugar utilizo pfSense.

      pfSense tiene un traffic shaper, pero lo que tu quieres más bien suena como a quotas.

      Supongo que es posible, pero como nunca lo he utilizado, no tengo un consejo rápido para darte.

      En la documentación de pfSense mencionan Traffic Quota a lo mejor te sirve de algo esa información.

      Saludos !!!

      Responder

¡Me encantaría saber que opinas!

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.