Alterando a Rota Padrão do Squid com Iptables

Category : Linux, Roteamento

Hoje resolvi sujar as mãos um pouquinho e resolver um problema pertinente lá na empresa: fazer com que o Squid utilize uma rota alternativa a rota padrão do gateway. Temos dois links de internet conectados ao gateway e queriamos definir as rotas de acordo com o tráfego. O problema era o tráfego gerado pelo próprio gateway, como o Proxy, DNS e Atualização do DNS dinâmico com ddclient.

Vasculhando um pouco pelo google achei uma alternativa interessante, que seria usar o módulo owner do iptables para marcar o tráfego vindo do usuário proxy (usamos Debian no gateway) para uma tabela de roteamento alternativa.

Diagrama do Gateway

Diagrama do Gateway

O script requer o pacote iproute2 instalado, bem como o Squid já configurado.

A tabela de Roteamento

Nosso gateway padrão atualmente é 192.168.15.254, na subrede 192.168.15.0/24. Com a função set_route() é criada uma nova tabela de roteamento com identificação numérica armazenada na variável $TABELA.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
declare LAN="192.168.1.0/24"
declare WAN="10.0.0.0/24"
declare IFLAN="eth0"
declare IFWAN="eth2"
declare GATEWAY="10.0.0.254"
declare TABELA="100"

declare IPROUTE="/sbin/ip route"

#Cria a tabela de roteamento alternativa com o iproute
function set_route() {
    $IPROUTE add $LAN dev $IFLAN table $TABELA
    $IPROUTE add $WAN dev $IFWAN table $TABELA
    $IPROUTE add default via $GATEWAY dev $IFWAN table $TABELA
    $IPROUTE flush cache
}

As Regras de Roteamento

A função set_rule() primeiro marca os pacotes oriundos do usuário proxy usando os matchers MARK e CONMARK. Em seguida é criada uma regra de roteamento para capturar os pacotes marcados e roteá-los através da nova tabela.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
declare IPTABLES="/sbin/iptables"
declare IPRULE="/sbin/ip rule"

#Cria as regras para o trafego que utilizara a tabela de roteamento alternativa
function set_rule() {
    $IPTABLES -t mangle -A PREROUTING -j CONNMARK --restore-mark   

    #A regra que marca o trafego gerado pelo usuario do proxy
    $IPTABLES -t mangle -A OUTPUT -m owner --uid-owner proxy -j MARK --set-mark $TABELA

    $IPTABLES -t mangle -A POSTROUTING -o $IFWAN -j MARK --set-mark $TABELA
    $IPTABLES -t mangle -A POSTROUTING -j CONNMARK --save-mark

    #A regra que captura os pacotes marcados e os insere na nova tabela
    $IPRULE add fwmark $TABELA table $TABELA
}

Você pode ampliar as regras como, por exemplo, fazer com que todo tráfego pop3 e smtp sejam roteados através da nova tabela.

1
2
    $IPTABLES -t mangle -A PREROUTING -p TCP --dport smtp -j MARK --set-mark $TABELA
    $IPTABLES -t mangle -A PREROUTING -p TCP --dport pop3 -j MARK --set-mark $TABELA

Juntando tudo

Se você já possui mais de uma tabela de roteamento configurada com o iproute basta adaptar o script conforme a sua necessidade.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/bin/bash
# Desctiption: Script de roteamendo avancado
# Author: Fabiano Sobreira

#Variaveis
declare LAN="192.168.1.0/24"
declare WAN="10.0.0.0/24"
declare IFLAN="eth0"
declare IFWAN="eth2"
declare GATEWAY="10.0.0.254"
declare TABELA="100"

declare IPTABLES="/sbin/iptables"
declare IPROUTE="/sbin/ip route"
declare IPRULE="/sbin/ip rule"

#Cria a tabela de roteamento alternativa com o iproute
function set_route() {
    $IPROUTE add $LAN dev $IFLAN table $TABELA
    $IPROUTE add $WAN dev $IFWAN table $TABELA
    $IPROUTE add default via $GATEWAY dev $IFWAN table $TABELA
    $IPROUTE flush cache
}

function unset_route() {
    $IPROUTE flush table $TABELA
}

#Cria as regras para o trafego que utilizara a tabela de roteamento alternativa
function set_rule() {
    $IPTABLES -t mangle -A PREROUTING -j CONNMARK --restore-mark   

    #A regra que marca o trafego gerado pelo usuario do proxy
    $IPTABLES -t mangle -A OUTPUT -m owner --uid-owner proxy -j MARK --set-mark $TABELA

    #Regras que marcam o trafego smtp e pop3
    $IPTABLES -t mangle -A PREROUTING -p TCP --dport smtp -j MARK --set-mark $TABELA
    $IPTABLES -t mangle -A PREROUTING -p TCP --dport pop3 -j MARK --set-mark $TABELA

    $IPTABLES -t mangle -A POSTROUTING -o $IFWAN -j MARK --set-mark $TABELA
    $IPTABLES -t mangle -A POSTROUTING -j CONNMARK --save-mark

    #A regra que captura os pacotes marcados e os insere na nova tabela
    $IPRULE add fwmark $TABELA table $TABELA
}

function unset_rule() {
    $IPTABLES -t mangle -D PREROUTING -j CONNMARK --restore-mark
    $IPTABLES -t mangle -D OUTPUT -m owner --uid-owner proxy -j MARK --set-mark $TABELA
    $IPTABLES -t mangle -D PREROUTING -p TCP --dport smtp -j MARK --set-mark $TABELA
    $IPTABLES -t mangle -D PREROUTING -p TCP --dport pop3 -j MARK --set-mark $TABELA
    $IPTABLES -t mangle -D PREROUTING -p TCP --dport imap -j MARK --set-mark $TABELA
    $IPTABLES -t mangle -D POSTROUTING -o $IFWAN -j MARK --set-mark $TABELA
    $IPTABLES -t mangle -D POSTROUTING -j CONNMARK --save-mark
    $IPRULE del fwmark $TABELA table $TABELA
}

function do_start() {
    set_route
    set_rule
}

function do_stop() {
    unset_rule
    unset_route
}

case $1 in
    start)
        printf "%s\n" "Iniciando o roteamento"
        do_start
        exit
    ;;
    stop)
        printf "%s\n" "Parando o roteamento"
        do_stop
        exit
    ;;
    restart)
        printf "%s\n" "Reiniciando o roteamento"
        do_stop
        do_start
        exit
    ;;
    *)
        printf "%s\n" "Uso: ${SCRIPT} (start|stop|restart)"
        exit
    ;;
esac

Links Sobre o Assunto

Linux Advanced Routing & Traffic Control
Linux Packet Filtering and Iptables