Traffic forwarded between disallowed zones

This is a strange issue I’m facing and I can’t quite understand what or how it’s happening, so please bear with me.

I run pi-hole in an LXC container, on IP 192.168.1.11. I serve that as DNS to my regular LAN clients using DHCP option 6,192.168.1.11 to the LAN interface and that works well.

I have other interfaces mapped to specific zones, pi-hole is configured with interfaces connecting to each of them and they get their IPs correctly and it all works.

I have recently introduced a new set of interfaces to route certain traffic through a VPN. I’m running OpenVPN client on the router and creating a specific route table for it whilst removing any routing via the VPN on the default table.

I have a vpn_wan interface that attaches to tun0:

config interface 'vpn_wan'
	option proto 'none'
	option ifname 'tun0'

I have a vpn_lan interface configured like so:

config interface 'vpn_lan'
	option proto 'static'
	option ipaddr '172.60.0.1'
	option netmask '255.255.255.0'
	option dns '1.1.1.1 1.0.0.1'
	option delegate '0'
	option type 'bridge'
	option ifname 'lan2 lan4.15'

lan4.15 is for traffic coming from a home server I run where I create a vlan interface with 802.1Q ID 15. The default interface routes through the normal untagged LAN traffic on physical port 4.

This is the entirety of my /etc/firewall in what affects the vpn_lan and vpn_wan interfaces:

config zone
	option name 'vpn_wan'
	option network 'vpn_wan'
	option masq '1'
	option mtu_fix '1'
	option forward 'REJECT'
	option input 'REJECT'
	option output 'ACCEPT'

config zone
	option name 'vpn_lan'
	option network 'vpn_lan'
	option forward 'REJECT'
	option input 'REJECT'
	option output 'ACCEPT'

config rule
	option target 'ACCEPT'
	option proto 'udp'
	option dest_port '67-68'
	option name 'Allow-vpn-DHCP'
	option src 'vpn_lan'

config forwarding
	option dest 'vpn_wan'
	option src 'vpn_lan'

The idea is that clients on the vpn_lan zone can only get DHCP information from the router and forward to vpn_wan but do nothing else. One of the reasons is so VPN traffic doesn’t leak anything - including DNS.

What I’m puzzled about is that when I send a DNS request to 192.168.1.11 on VLAN 15 I still get a reply:

root@headquarters:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
11: enp2s0.15@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 9c:b6:54:07:e3:f1 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.60.0.15/24 brd 172.60.0.255 scope global dynamic enp2s0.15
       valid_lft 40787sec preferred_lft 40787sec
    inet6 fe80::9eb6:54ff:fe07:e3f1/64 scope link
       valid_lft forever preferred_lft forever
root@headquarters:~# dig vitrines.globo.com @192.168.1.11

; <<>> DiG 9.11.5-P4-5.1ubuntu2-Ubuntu <<>> vitrines.globo.com @192.168.1.11
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31626
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 763c4f5149d462b052717e4f5db5a85532cd9a690f43d6ae (good)
;; QUESTION SECTION:
;vitrines.globo.com.		IN	A

;; ANSWER SECTION:
vitrines.globo.com.	120	IN	A	186.192.81.168

;; AUTHORITY SECTION:
globo.com.		111620	IN	NS	ns02.globo.com.
globo.com.		111620	IN	NS	ns01.globo.com.
globo.com.		111620	IN	NS	ns04.globo.com.
globo.com.		111620	IN	NS	ns03.globo.com.

;; Query time: 224 msec
;; SERVER: 192.168.1.11#53(192.168.1.11)
;; WHEN: Sun Oct 27 14:23:17 UTC 2019
;; MSG SIZE  rcvd: 167

Note that this is from a network namespace where the only non-loopback interface is the VLAN one.

This is what I see on the router from that request:

turris# tcpdump -Snei any udp port 53 and host 192.168.1.11
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
13:55:49.315483   P 9c:b6:54:07:e3:f1 ethertype 802.1Q (0x8100), length 107: vlan 15, p 0, ethertype IPv4, 172.60.0.15.41718 > 192.168.1.11.53: 47376+ [1au] A? vitrines.globo.com. (59)
13:55:49.315483   P 9c:b6:54:07:e3:f1 ethertype IPv4 (0x0800), length 103: 172.60.0.15.41718 > 192.168.1.11.53: 47376+ [1au] A? vitrines.globo.com. (59)
13:55:49.315483  In 9c:b6:54:07:e3:f1 ethertype IPv4 (0x0800), length 103: 172.60.0.15.41718 > 192.168.1.11.53: 47376+ [1au] A? vitrines.globo.com. (59)
13:55:49.315565 Out ethertype IPv4 (0x0800), length 103: 10.16.0.8.41718 > 192.168.1.11.53: 47376+ [1au] A? vitrines.globo.com. (59)
13:55:49.322069  In ethertype IPv4 (0x0800), length 211: 192.168.1.11.53 > 10.16.0.8.41718: 47376 1/4/1 A 186.192.81.168 (167)
13:55:49.322108 Out d8:58:d7:00:9e:6d ethertype IPv4 (0x0800), length 211: 192.168.1.11.53 > 172.60.0.15.41718: 47376 1/4/1 A 186.192.81.168 (167)
13:55:49.322116 Out d8:58:d7:00:9e:6d ethertype IPv4 (0x0800), length 211: 192.168.1.11.53 > 172.60.0.15.41718: 47376 1/4/1 A 186.192.81.168 (167)

So it comes in via the VLAN, gets sent to the pi-hole which in turn seemingly routes it via the VPN IP 10.16.0.8, then back to the VLAN interface on the host.

Note that the pi-hole is not configured to talk to that VPN address at all.

What’s interesting is that this particular host is blacklisted on the pi-hole, so should have resolved to 0.0.0.0 instead of the actual IP.

If I do the same query over a regular LAN client, that’s what I get:

cassiano@headquarters:~$ dig vitrines.globo.com @192.168.1.11

; <<>> DiG 9.11.5-P4-5.1ubuntu2-Ubuntu <<>> vitrines.globo.com @192.168.1.11
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9489
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;vitrines.globo.com.		IN	A

;; ANSWER SECTION:
vitrines.globo.com.	2	IN	A	0.0.0.0

;; Query time: 3 msec
;; SERVER: 192.168.1.11#53(192.168.1.11)
;; WHEN: Sun Oct 27 14:28:24 UTC 2019
;; MSG SIZE  rcvd: 63

And the tcpdump output for this query:

turris# tcpdump -Snei any udp port 53 and host 192.168.1.11
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
14:28:24.013948   P 9c:b6:54:07:e3:f1 ethertype IPv4 (0x0800), length 103: 192.168.1.15.40826 > 192.168.1.11.53: 9489+ [1au] A? vitrines.globo.com. (59)
14:28:24.014024 Out 9c:b6:54:07:e3:f1 ethertype IPv4 (0x0800), length 103: 192.168.1.15.40826 > 192.168.1.11.53: 9489+ [1au] A? vitrines.globo.com. (59)
14:28:24.013948   P 9c:b6:54:07:e3:f1 ethertype IPv4 (0x0800), length 103: 192.168.1.15.40826 > 192.168.1.11.53: 9489+ [1au] A? vitrines.globo.com. (59)
14:28:24.014782   P 62:f0:75:3d:ac:ca ethertype IPv4 (0x0800), length 107: 192.168.1.11.53 > 192.168.1.15.40826: 9489* 1/0/1 A 0.0.0.0 (63)
14:28:24.014806 Out 62:f0:75:3d:ac:ca ethertype IPv4 (0x0800), length 107: 192.168.1.11.53 > 192.168.1.15.40826: 9489* 1/0/1 A 0.0.0.0 (63)
14:28:24.014814 Out 62:f0:75:3d:ac:ca ethertype IPv4 (0x0800), length 107: 192.168.1.11.53 > 192.168.1.15.40826: 9489* 1/0/1 A 0.0.0.0 (63)
14:28:24.014782   P 62:f0:75:3d:ac:ca ethertype IPv4 (0x0800), length 107: 192.168.1.11.53 > 192.168.1.15.40826: 9489* 1/0/1 A 0.0.0.0 (63)

So in this case everything looks normal and as expected.

Can someone help me understand what’s actually happening here?

Thanks!

I don’t think that’s pi-hole answering (another hint is the A not being 0.0.0.0, etc.) but I can’t see who it is. Omnia’s default also won’t return a cookie.

Thanks, @vcunat.

I am not using knot on this router because I had some trouble with it and its interactions with pi-hole before, and it was just easier to disable it altogether. I might come back to it at some point but at present I have more pressing issues to resolve.

dnsmasq is running on the router but that doesn’t seem to set a cookie either…