iptables (e / ou netfilter) tem vários ganchos na pilha de roteamento. Quando um pacote passa por uma certa etapa na pilha de roteamento, se houver um gancho do iptables, o hook do iptables é executado. É claro que, se o pacote não atingir tal passo, nenhum gancho do iptables será executado. Se não houver "rota para hospedar", a pilha de roteamento desistirá mais cedo e não atingirá essas etapas. Isso é o que está acontecendo no seu exemplo depois que você excluiu as rotas (da tabela principal) e deixou uma tabela de roteamento que depende do uso do iptables. Esse é um problema de galinha e ovo, mas não precisa ser feito desse jeito. Você só precisa de uma rota, qualquer rota, para que suas regras sejam acionadas e alterem essa rota.
Eu corri o seu script e fiquei com minhas configurações:
# ip route
(nothing)
# ip route show table 4
default via 10.0.3.1 dev eth0
10.0.3.0/24 dev eth0 proto kernel scope link src 10.0.3.66
Adicionadas as regras de OUTPUT:
iptables -t mangle -A OUTPUT -p udp -m udp --dport 53 -j MARK --set-xmark 0x4/0xffffffff
iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 53 -j MARK --set-xmark 0x4/0xffffffff
iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 443 -j MARK --set-xmark 0x4/0xffffffff
iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 80 -j MARK --set-xmark 0x4/0xffffffff
Nada funciona.
Adicionada a rota da LAN e um falso gateway errado 10.0.3.9 que não existe:
# ip route
default via 10.0.3.9 dev eth0
10.0.3.0/24 dev eth0 scope link
# ip neigh flush dev eth0
# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
^C
--- 8.8.8.8 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1006ms
# ip neigh
10.0.3.9 dev eth0 FAILED
# ip neigh del 10.0.3.9 dev eth0
# dig +short @8.8.8.8 google.com.
172.217.22.142
# ip neigh
10.0.3.1 dev eth0 lladdr fe:d6:50:75:27:c9 REACHABLE
Observe que agora a rota da tabela 4 foi usada. Mas precisava de uma rota de trabalho primeiro ("no papel", mesmo que não funcionasse realmente), senão a decisão de roteamento sozinha teria impedido que a regra OUTPUT fosse usada. Você pode ver com iptables-save -c
para ver contadores.