Servidor Linux com Proxy e Controle de Banda – Parte 2

Linux

Introdução

Nessa segunda parte do artigo vou mostrar como criar um shell script usando o iptables para filtragem de pacotes e CBQ para controle de banda.
O script está fácil de entender e sua utilização é bem simples. É necessário criar um arquivo texto contento informações sobre cada máquina cliente que possui acesso à internet. Informações como IP, MAC, Download, Upload, se vai passar pelo Squid e se está bloqueado o acesso. Com base nestas informações, o script cria as regras no firewall bloqueando ou liberando acessos, amarrando IP ao endereço MAC, faz proxy transparente e determina qual a velocidade de download e upload para cada um. Fora isso, é criado o arquivo /etc/dhcpd.con usado pelo servidor DHCP associando o IP ao seu MAC, fazendo com que um cliente obtenha sempre o mesmo IP.

Firewall e Controle de Banda

É recomendado um conhecimento básico sobre Linux e Shell Script para bom entendimento do código.

#!/bin/bash
 
ARQUIVO="/var/www/bandcontrol/scripts/pontosderede.txt"     # Contem os pontos de rede cadastrados
 
MOD=$(which modprobe)                        # Comando para carregar modulos do kernel
IPT=$(which iptables)                        # Caminho do iptables
TC=$(which tc)                               # tc (pacote iproute2)
 
I_WAN="eth0"                                 # Interface internet
I_LAN1="eth1"                                # Interface Rede local
 
GATEWAY_IP="192.168.254.254"
NETMASK="255.255.255.0"
CLASSE_LAN1="192.168.254"                    # Classe de IP utilizada na rede local. Ex.: 10.0
PROXY_SERVER="$GATEWAY_IP:3128"              # O proprio gateway tambem roda o Squid na porta 3128
 
DHCPD_DAEMON="/etc/init.d/dhcp3-server"      # Executavel do dhcpd server
DHCPDCONF="/etc/dhcp3/dhcpd.conf"            # Arquivo de configuracao do dhcpd
DOMINIO="gustavohenrique.net"                # Dominio ao qual a rede faz parte
DNS_SERVERS="$GATEWAY_IP, 8.8.8.8, 4.2.2.2"  # Servidores DNS. O primeiro é o próprio gateway
 
# Remove o controle de banda
function parar_controle_de_banda {
    $TC qdisc del dev $I_LAN1 root
    $TC qdisc del dev $I_WAN root
}
 
# Cria as regras iniciais para controle de banda
function iniciar_controle_de_banda {
    # Remove as regras do controle de banda
    parar_controle_de_banda
 
    # Download
    $TC qdisc add dev $I_LAN1 root handle 1 cbq bandwidth 100Mbit avpkt 1000 cell 8
    $TC class change dev $I_LAN1 root cbq weight 10Mbit allot 1514
 
    # Upload
    $TC qdisc add dev $I_WAN root handle 1 cbq bandwidth 100Mbit avpkt 1000 cell 8
    $TC class change dev $I_WAN root cbq weight 10Mbit allot 1514
 
    # Cache Full. Pacotes marcados com TOS 60 vao para a classe 1:9999 cuja banda é 100 Mbit (rede ethernet)
    $TC class add dev $I_LAN1 parent 1: classid 1:9999 cbq bandwidth 100Mbit rate 100Mbit weight 10Mbit prio 4 allot 1514 cell 8 maxburst 20 avpkt 1000 bounded
    $TC filter add dev $I_LAN1 parent 1:0 protocol ip prio 3 u32 match ip protocol 0x6 0xff match ip tos 60 0xff classid 1:9999  
}
 
 
# Limpa o firewall
function parar_firewall() {
    # Configura a politca padrao para aceitar tudo
    $IPT -P INPUT ACCEPT
    $IPT -P OUTPUT ACCEPT
    $IPT -P FORWARD ACCEPT
    $IPT -t nat -P PREROUTING ACCEPT
 
    # Limpa a tabela netfilter
    $IPT -F
    $IPT -X
    $IPT -t nat -F
    $IPT -t nat -X
    $IPT -t mangle -F
    $IPT -t mangle -X
}
 
 
# Cria as regras de firewall
function iniciar_firewall() {
 
    # Finaliza o script se nao existir o arquivo contendo os pontos de rede
    if [ ! -f $ARQUIVO ]; then
        echo "Arquivo contendo os pontos de rede ($ARQUIVO) nao existe.";
        exit 0
    fi
 
    # Carrega modulos do iptables
    $MOD ip_tables
    $MOD iptable_nat
    $MOD ipt_MASQUERADE
    $MOD ipt_LOG
    $MOD ipt_REJECT
    $MOD ip_conntrack_ftp
    $MOD ip_nat_ftp
 
    # Limpa todas as regras do firewall
    parar_firewall
 
    # Recria as regras para controle de banda
    iniciar_controle_de_banda
 
    # Por padrao bloqueia tudo que for entrar no firewall
    $IPT -P INPUT DROP
    $IPT -t nat -P PREROUTING DROP
 
    # Habilita redirecionamento de pacotes para compartilhar internet
    echo 1 > /proc/sys/net/ipv4/ip_forward
 
    # Aumenta o limite do nf_conntrack_max
    echo 99999 > /proc/sys/net/netfilter/nf_conntrack_max
 
    # Libera acesso para pacotes vindos da internet (CUIDADO)
    $IPT -t nat -A PREROUTING -s 0/0 -i $I_WAN -p all -j ACCEPT
    $IPT -A INPUT -i $I_WAN -j ACCEPT
 
    # Cria uma nova chain para tratar do proxy transparente
    $IPT -t nat -N proxy
        # O software conectividade social da Caixa Economica nao funciona se
        # estiver passando pelo proxy. Tudo que for destinado ao IP da Caixa
        # nao vai passar pelo proxy
        $IPT -t nat -A proxy -p tcp -d 200.201.174.0/16 --dport 80 -j ACCEPT
        $IPT -t nat -A proxy -p tcp -d 200.201.173.0/16 --dport 80 -j ACCEPT
        $IPT -t nat -A proxy -p tcp -d 200.201.0.0/16 --dport 80 -j ACCEPT
        $IPT -t nat -A proxy -p tcp -d 200.201.174.207 --dport 80 -j ACCEPT
 
        # Internet Caixa nao passa pelo proxy
        $IPT -t nat -A proxy -p tcp -d 200.201.169.0/8 --dport 80 -j ACCEPT
        $IPT -t nat -A proxy -p tcp -d 200.201.169.69 --dport 80 -j ACCEPT
 
        # Esse servidor tambem roda o Apache na port 80. Nao quero que as
        # paginas locais passem pelo proxy, pois assim posso controlar a banda
        # de pacotes vindos do apache definindo a velocidade máxima da rede
        $IPT -t nat -A proxy -p tcp -d $GATEWAY_IP --dport 80 -j ACCEPT
 
        # Proxy transparente redirecionando os pacotes para a porta do Squid
        $IPT -t nat -A proxy -s 0/0 -p tcp --dport 80 -j DNAT --to-dest $PROXY_SERVER
 
        # Se o pacote nao for pra porta 80 (não é navegação), deixa passar
        $IPT -t nat -A proxy -i $I_LAN1 -j ACCEPT
 
 
    # Libera o IP abaixo sem amarrar com MAC e sem passar pelo proxy
    #$IPT -t nat -A PREROUTING -i $I_LAN1 -s 192.168.254.2 -j ACCEPT
 
    # Configuracao inicial do dhcpd.conf. Distribuicao de IPs na faixa 192.168.254.80 a 192.168.254.90
    echo "# Arquivo dhcpd.conf criado pelo BandControl" > $DHCPDCONF
    echo "ddns-update-style none;" >> $DHCPDCONF
    echo "option domain-name \"$DOMINIO\";" >> $DHCPDCONF
    echo "option domain-name-servers $DNS_SERVERS;" >> $DHCPDCONF
    echo "default-lease-time 600;" >> $DHCPDCONF
    echo "max-lease-time 7200;" >> $DHCPDCONF
    echo "authoritative;" >> $DHCPDCONF
    echo "shared-network 0-2 {" >> $DHCPDCONF
    echo "  subnet $CLASSE_LAN1"."0 netmask $NETMASK { range $CLASSE_LAN1.80 $CLASSE_LAN1.90; }" >> $DHCPDCONF
    echo "}" >> $DHCPDCONF
 
    # Inicio do loop para liberacao e bloqueio de clientes.
    # O formato do arquivo é: codigo_identificador-descricao-ip-mac-download-upload-liberado-proxy
    # Ex.: 1-gustavo_henrique_notebook-192.168.254.10-512-256-S-S
    # Acesso liberado e uso do proxy sao valores que devem ser True ou False
    for i in `cat $ARQUIVO`; do
        CODIGO=$(echo $i | awk -F "-" {'print $1'})                  # Numero usado como identificador no controle de banda
        IP=$(echo $i | awk -F "-" {'print $3'})                      # IP
        MAC=$(echo $i | awk -F "-" {'print $4'})                     # MAC em letras minusculas e separado por dois pontos (:)
        DOWNLOAD=$(echo $i | awk -F "-" {'print $5'})                # Numero correspondente a velocidade de download em Kbit
        UPLOAD=$(echo $i | awk -F "-" {'print $6'})                  # Numero correspondente a velocidade de upload em Kbit
        POSSUI_ACESSO_LIBERADO=$(echo $i | awk -F "-" {'print $7'})  # True para sim, False para bloquear o acesso
        VAI_USAR_PROXY=$(echo $i | awk -F "-" {'print $8'})          # True para usar o proxy, False para não usar
 
        # Configurar dhcpd para associar IP ao MAC
        if [ "$MAC" != "" ]; then
          LINHA="host $CODIGO { hardware ethernet $MAC; fixed-address $IP; option subnet-mask $NETMASK; option routers $GATEWAY_IP; option domain-name-servers $DNS_SERVERS; }"
          echo $LINHA >> $DHCPDCONF
        fi
 
        # Se o IP nao esta liberado, bloqueia no firewall
        if [ "$POSSUI_ACESSO_LIBERADO" == "False" ]; then
            EXECUTAR_REGRA="$IPT -t nat -A PREROUTING -p tcp -i $I_LAN1 -s $IP -j DROP"
        else
            if [ "$VAI_USAR_PROXY" == "True" ]; then
                EXECUTAR_REGRA="$IPT -t nat -A PREROUTING -i $I_LAN1 -s $IP -m mac --mac-source $MAC -j proxy"
            else
                EXECUTAR_REGRA="$IPT -t nat -A PREROUTING -i $I_LAN1 -s $IP -j ACCEPT"
            fi
        fi
 
        # Executa a regra referente ao IP dentro do loop
        $EXECUTAR_REGRA
 
 
        # Aplica o controle de banda ao IP. Para cada IP é criada uma classe de download e upload.
        WEIGHT_DOWN=$(expr $DOWNLOAD / 10)
        ID_DOWN=1"$CODIGO"
        $TC class add dev $I_LAN1 parent 1: classid 1:$ID_DOWN cbq bandwidth 10Mbit rate "$DOWNLOAD"Kbit weight "$WEIGHT_DOWN"Kbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000 bounded
        $TC filter add dev $I_LAN1 parent 1:0 protocol ip prio 100 u32 match ip dst $IP classid 1:$ID_DOWN
 
        WEIGHT_UP=$(expr $UPLOAD / 10)
        ID_UP=2"$CODIGO"
        $TC class add dev $I_WAN parent 1: classid 1:$ID_UP cbq bandwidth 10Mbit rate "$UPLOAD"Kbit weight "$WEIGHT_UP"Kbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000 bounded
        $TC qdisc add dev $I_WAN parent 1:$ID_UP handle $ID_UP tbf rate "$UPLOAD"Kbit buffer 10Kb/8 limit 15Kb mtu 1500
        $TC filter add dev $I_WAN parent 1:0 protocol ip prio 100 u32 match ip src $IP classid 1:$ID_UP
 
    done
 
    # Aplica o TOS 60 nas portas utilizadas por outros serviços. Assim é usado a velocidade total da rede
    # para acesso ao SSH, Apache e Samba
    $IPT -t mangle -A OUTPUT -p tcp --sport 22 -j TOS --set-tos 60
    $IPT -t mangle -A OUTPUT -p tcp --sport 80 -j TOS --set-tos 60
 
    $IPT -t mangle -A OUTPUT -p tcp --sport 137:139 -j TOS --set-tos 60
    $IPT -t mangle -A OUTPUT -p udp --sport 137:139 -j TOS --set-tos 60
    $IPT -t mangle -A INPUT -p tcp --dport 137:139 -j TOS --set-tos 60
    $IPT -t mangle -A INPUT -p udp --dport 137:139 -j TOS --set-tos 60
 
    # Compartilha a internet
    $IPT -t nat -A POSTROUTING -o $I_WAN -j MASQUERADE
 
    # Bloqueio contra Scanners Ocultos (Shealt Scan)
    $IPT -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j DROP
 
    # Libera ping (CUIDADO com ataques ddos)
    $IPT -A INPUT -i $I_LAN1 -p icmp -j ACCEPT
    $IPT -A INPUT -i $I_WAN -p icmp -j ACCEPT
 
    # Libera acesso para o proprio gateway
    $IPT -A INPUT -i lo -j ACCEPT
    $IPT -A FORWARD -i lo -j ACCEPT
 
    # Libera acesso ao Apache
    $IPT -A INPUT -p tcp --dport 80 -j ACCEPT
    $IPT -A INPUT -p tcp --dport 443 -j ACCEPT
 
    # Libera acesso ao Squid
    $IPT -A INPUT -p tcp --dport 3128 -j ACCEPT
 
    # Libera acesso ao SSH
    $IPT -A INPUT -p tcp --dport 22 -j ACCEPT
 
    # Libera acesso ao DNS
    $IPT -A INPUT -p udp --dport 53 -j ACCEPT
 
    # Libera acesso aos compartilhamentos do Samba
    $IPT -A INPUT -p tcp --dport 137:139 -j ACCEPT
    $IPT -A INPUT -p udp --dport 137:139 -j ACCEPT
 
    # Libera acesso ao SNMP
    #$IPT -A INPUT -p udp --dport 160:162 -j ACCEPT
 
    # Tratamento de conexoes TCP
    $IPT -A INPUT -p tcp --syn -j DROP
    $IPT -A INPUT -p tcp -m state --state ESTABLISHED,RELATED,NEW -j ACCEPT
    $IPT -A INPUT -m limit --limit 3/minute --limit-burst 3 -j DROP
 
    # Bloqueando pacotes estranhos
    $IPT -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
    $IPT -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
    $IPT -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
    $IPT -A INPUT -p tcp --tcp-flags ALL FIN -j DROP
    $IPT -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
    $IPT -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
    $IPT -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
 
    echo "Firewall iniciado"
}
 
 
case $1 in
    # Inicia o firewall e o dhcpd
    start) iniciar_firewall; $DHCPD_DAEMON stop; $DHCPD_DAEMON start; exit ;;
 
    # Finaliza o firewall sem parar o dhcp
    stop) parar_firewall; exit ;;
 
    # Inicia o firewall sem reiniciar o dhcpd
    only) iniciar_firewall; exit ;;
 
    # Finaliza o controle de banda
    fast) parar_controle_de_banda; exit ;;
 
    # Se nenhum parametro for passado, mostra a ajuda abaixo
    *) echo "Use assim: $0 start|stop|only|fast"; exit 1;;
esac

Conclusão

Com o término da segunda parte do artigo é possível colocar um servidor Linux funcionando com eficiência, segurança e estabilidade para compartilhar uma conexão de internet. É uma ótima solução custo/benefício para micro e pequenas empresas.
Na próxima parte vou mostrar como desenvolver uma interface web para gerenciar melhor os pontos de rede. Isso dá mais agilidade ao trabalhar com muitas máquinas na rede.

Algumas considerações:

  • Tomem cuidado na configuração do firewall. Esse é um script simples que serve não deve ser tomado como solução definitiva.
  • Há outra alternativa para controle de banda chamada HTB. Pessoalmente prefiro o CBQ, o mesmo utilizado nesse script, mas vale a pena dar uma estudada.
  • Usar um arquivo texto contendo os dados dos pontos de rede para ser lido pelo shell script foi a idéia mais simples e não a de melhor desempenho. Também fiz o script fazer consultas ao MySQL mas não senti diferença na velocidade comparado com a leitura de um arquivo de texto.

Bom, a parte 3 do artigo só em 2010. Nesse momento já estou em algum lugar sem internet e talvez sem celular. :D
Feliz ano novo à todos!

You can leave a response, or trackback from your own site.

Leave a Reply

Powered by WordPress | Shop the Best Verizon Wireless Deals. | Thanks to Best CD Rates, Credit Cards and Credit card