mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 19:01:54 +00:00
dnsmasq binds the docker bridge address with the clearnet upstreams configured and the node's own .onion records loaded, and no rule covered port 53. Any source that could route a packet to that address got an open resolver plus the split-DNS records.c89ca42c46claimed local-service closed this;abb6f37297showed the keyword never took effect. The guard now carries two named sets instead of one plus a special case. 'containers' is the docker pool list, for tor's own transparent and DNS ports. 'internal' is NETWORK_INTERNAL_CIDRS, for the resolver and the SOCKS port. Every guarded entry names its set, which folds the hand-written SOCKS rule and its manual append into the same list the reverse-path sets are built from. The resolver takes the wider set deliberately: 'internal' is the list torrc.j2 already spends on SocksPolicy accept. The narrow set carries only 10.208.0.0/12 and 10.7.7.0/24 out of 10.0.0.0/8, which leaves out swarm's ingress network, every overlay docker allocates without an ipam block, and a node whose own address sits elsewhere in 10/8. A query bound to such an address was measured timing out against the narrow set. Guarding the resolver more strictly than the proxy beside it would refuse a name lookup to a source that is handed a full SOCKS proxy six lines earlier. NETWORK_DNS_PORT lives next to the other resolver constants rather than in meta/services.yml: ports.local describes host-bound container ports, where 53 collides with svc-dns-unbound and falls outside every PORT_BANDS band. Measured on the rendered artifact: the table loads and reloads with a byte-identical listing, every compose source of port 53 resolves inside 'internal' and every source of 9040/9053 inside 'containers', and a mistyped set name, an empty CIDR list or a missing admitted key each fail loudly at validate time. Port 53 newly passes a strict reverse-path check, so an asymmetrically routed client loses name resolution. test_fragments built its guard list from a fixture of three entries while the role shipped six, so it validated the template against a port list nobody deploys. It now takes the shape from the declaration and fills only the numbers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
53 lines
1.7 KiB
Django/Jinja
53 lines
1.7 KiB
Django/Jinja
{# Loaded by roles/svc-net-firewall into {{ FIREWALL_TABLE }}. #}
|
|
table inet {{ FIREWALL_TABLE }}
|
|
delete table inet {{ FIREWALL_TABLE }}
|
|
table inet {{ FIREWALL_TABLE }} {
|
|
set containers {
|
|
type ipv4_addr
|
|
flags interval
|
|
elements = { {{ TOR_EGRESS_CLIENT_CIDRS | join(', ') }} }
|
|
}
|
|
|
|
set internal {
|
|
type ipv4_addr
|
|
flags interval
|
|
elements = { {{ NETWORK_INTERNAL_CIDRS | join(', ') }} }
|
|
}
|
|
|
|
{% set _tcp_guarded = TOR_EGRESS_GUARDED_PORTS | selectattr('protocol', 'equalto', 'tcp') | map(attribute='port') | unique | list %}
|
|
{% set _udp_guarded = TOR_EGRESS_GUARDED_PORTS | selectattr('protocol', 'equalto', 'udp') | map(attribute='port') | unique | list %}
|
|
chain guard {
|
|
{% for entry in TOR_EGRESS_GUARDED_PORTS %}
|
|
ip saddr != @{{ entry.admitted }} {{ entry.protocol }} dport {{ entry.port }} drop
|
|
{% endfor %}
|
|
{% if _tcp_guarded | length > 0 %}
|
|
fib saddr . iif oif missing tcp dport { {{ _tcp_guarded | join(', ') }} } drop
|
|
{% endif %}
|
|
{% if _udp_guarded | length > 0 %}
|
|
fib saddr . iif oif missing udp dport { {{ _udp_guarded | join(', ') }} } drop
|
|
{% endif %}
|
|
}
|
|
|
|
chain input {
|
|
type filter hook input priority -10; policy accept;
|
|
jump guard
|
|
}
|
|
|
|
chain forward {
|
|
type filter hook forward priority -10; policy accept;
|
|
jump guard
|
|
}
|
|
|
|
chain output {
|
|
type nat hook output priority -150; policy accept;
|
|
ip daddr {{ TOR_EGRESS_VIRTUAL_NET_IPV4 }} meta l4proto tcp redirect to :{{ TOR_TRANS_PORT }}
|
|
}
|
|
{% if TOR_CONTAINER_DNS_HOST | length > 0 %}
|
|
|
|
chain prerouting {
|
|
type nat hook prerouting priority -150; policy accept;
|
|
ip daddr {{ TOR_EGRESS_VIRTUAL_NET_IPV4 }} meta l4proto tcp dnat ip to {{ TOR_CONTAINER_DNS_HOST }}:{{ TOR_TRANS_PORT }}
|
|
}
|
|
{% endif %}
|
|
}
|