Block direct access to public resolvers

Hi all,

Does anyone know how to block IOT’ direct access to public resolvers such as 8.8.8.8:53 etc? By doing that they bypass router’s dns and adblock.

I have something like below in my firewall but seems doesnt help.

config redirect 'dns_int_iot'
	option name 'Intercept-DNS_iot'
	option src 'iot'
	option src_dport '53'
	option proto 'tcp udp'
	option target 'DNAT'
	option family 'any'
config rule
        option dest_port '53 853'
        option src 'iot"
        option name 'Block google DNS'
        option dest 'wan'
        list dest_ip '8.8.8.8'
        list dest_ip '8.8.4.4'
        list dest_ip '2001:4860:4860::8888'
        list dest_ip '2001:4860:4860::8844'
        option target 'REJECT'

Try this

Actually I tried that also but without ‘list’ and didn’t work. Let me try again by listing servers.

config rule
        option dest_port '53 853'
        option name 'Block google DNS'
        option dest 'wan'
        list dest_ip '8.8.8.8'
        list dest_ip '8.8.4.4'
        list dest_ip '2001:4860:4860::8888'
        list dest_ip '2001:4860:4860::8844'
        option target 'REJECT'
        list proto 'tcp'
        list proto 'udp'
        list proto 'icmp'
        list proto 'igmp'

This will block it completely even from router

Many thanks.
If someone wants to try can prove like this:

root@turris:~# nslookup turris.cz 8.8.8.8
;; connection timed out; no servers could be reached

root@turris:~#

No I was wrong it will actually block it only for the router itself. You will have to add option src ‘iot’ for it to block in iot zone.
Or add two rules to block for the router and iot zone

I tried like this to make it for all zones.

config rule
	option dest_port '53 853'
	option target 'REJECT'
	list dest_ip '8.8.8.8'
	list dest_ip '8.8.4.4'
	list dest_ip '2001:4860:4860::8888'
	list dest_ip '2001:4860:4860::8844'
	option name 'Block Google DNS'
	option dest '*'
	list proto 'tcp'
	list proto 'udp'
	list proto 'icmp'
	list proto 'igmp'

and the iptables rule look like this

-A OUTPUT -d 8.8.8.8/32 -p tcp -m tcp --dport 53 -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.8.8/32 -p tcp -m tcp --dport 853 -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.4.4/32 -p tcp -m tcp --dport 53 -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.4.4/32 -p tcp -m tcp --dport 853 -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.8.8/32 -p udp -m udp --dport 53 -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.8.8/32 -p udp -m udp --dport 853 -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.4.4/32 -p udp -m udp --dport 53 -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.4.4/32 -p udp -m udp --dport 853 -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.8.8/32 -p icmp -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.4.4/32 -p icmp -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.8.8/32 -p igmp -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.8.8/32 -p igmp -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.4.4/32 -p igmp -m comment --comment "!fw3: Block Google DNS" -j reject
-A OUTPUT -d 8.8.4.4/32 -p igmp -m comment --comment "!fw3: Block Google DNS" -j reject

which looks OK, appending main OUTPUT chain.

Result:
It blocks from the router but the TV still able to make connection to 8.8.8.8:53.

Ok updating now the solutions I have which might help others also.

Solution 1:
My first post was about to do by port-forwarding without any reject.
Idea is to redirect external queries to the local dns, so I got it working by small addition.

When setting from Luci looks like below:

This example is for the lan subnet, redirecting to the that subnet’s dns, so the lan is 192.168.1.0/24 then redirecting to the 192.168.1.1:53 where dns listens.
For other subnets eg. iot (192.168.10.0/24) will be from iot to iot and to dns eg.192.168.10.1:53.

Additionally can be done manually by editing /etc/config/firewall:

config redirect 'dns_int_lan'
	option name 'Intercept-DNS_lan'
	option src 'lan'
	option src_dport '53'
	option proto 'tcp udp'
	option target 'DNAT'
	option family 'any'
	option dest_ip '192.168.1.1'
	option dest 'lan'
	option dest_port '53'

Solution 2:
Reject external queries, this may broke some functionality if the device insists on using external dns rather than the router’s one.

I realized that it should be forwarding rule but not output rule(my previous post).

Solution with logging(I want to believe if really rejected):

Adding custom rule to the /etc/firewall.user file or can be added in Luci Firewall Custom Rules tab.

if ! iptables -S|grep -q "\-N\ forward_log_and_reject"; then
    iptables -N forward_log_and_reject
    iptables -A forward_log_and_reject -m limit --limit 10/sec -m comment --comment "!log" -j LOG --log-prefix "FORWARD WAN REJECT: "
    iptables -A forward_log_and_reject -m comment --comment "!fw3" -j reject
fi

iptables -A forwarding_lan_rule -o eth2 -p tcp -m tcp --dport 53 -m comment --comment "!fw3: Block external DNS lan" -j forward_log_and_reject
iptables -A forwarding_lan_rule -o eth2 -p tcp -m tcp --dport 853 -m comment --comment "!fw3: Block external DNS lan" -j forward_log_and_reject
iptables -A forwarding_lan_rule -o eth2 -p udp -m udp --dport 53 -m comment --comment "!fw3: Block external DNS lan" -j forward_log_and_reject
iptables -A forwarding_lan_rule -o eth2 -p udp -m udp --dport 853 -m comment --comment "!fw3: Block external DNS lan" -j forward_log_and_reject

First creating new custom chain to log and reject.
Then adding rules to the already existing forwarding_lan_rule chain. Those last 4 lines can be repeated for each subnet, eg. forwarding_iot_rule, where iot is the subnet.

This will flood your logs so I split into separate log file by setting in /etc/syslog-ng.conf.
Surprised to see that the devices in your network don’t use router’s dns at all:

root@turris:~# cat /etc/syslog-ng.conf
#############################################################################
# OpenWrt syslog-ng.conf specific file
# which collects all local logs into a single file called /var/log/messages.
# More details about these settings can be found here:
# https://www.syslog-ng.com/technical-documents/list/syslog-ng-open-source-edition

@version: 3.35
@include "scl.conf"

options {
	chain_hostnames(no); # Enable or disable the chained hostname format.
	create_dirs(yes);
	keep_hostname(yes); # Enable or disable hostname rewriting.
	log_fifo_size(256); # The number of messages that the output queue can store.
	log_msg_size(1024); # Maximum length of a message in bytes.
	stats_freq(0); # The period between two STATS messages (sent by syslog-ng, containing statistics about dropped logs) in seconds.
	flush_lines(0); # How many lines are flushed to a destination at a time.
	use_fqdn(no); # Add Fully Qualified Domain Name instead of short hostname.
};

# syslog-ng gets messages from syslog-ng (internal) and from /dev/log

source src {
	internal();
	unix-dgram("/dev/log");
};

source net {
	network_localhost();
};

source s_network {
	default-network-drivers(
		# NOTE: TLS support
		#
		# the default-network-drivers() source driver opens the TLS
		# enabled ports as well, however without an actual key/cert
		# pair they will not operate and syslog-ng would display a
		# warning at startup.
		#
		#tls(key-file("/path/to/ssl-private-key") cert-file("/path/to/ssl-cert"))
	);
};

source kernel {
        file("/proc/kmsg" program_override("kernel"));
};

filter f_iptables_forward_wan_reject_not_match {
	not match(".*FORWARD WAN REJECT: .*" value(MESSAGE));
};

filter f_iptables_forward_wan_reject_match {
        match(".*FORWARD WAN REJECT: .*" value(MESSAGE));
};

filter f_not_cron {
	not program(".*cron.*");
};

filter f_cron {
	program(".*cron.*");
};

destination messages {
	file("/var/log/messages");
};

destination cron {
	file("/var/log/cron" suppress(5) template("${ISODATE} ${PRIORITY} ${PROGRAM}[${PID}]: ${MSGONLY}\n") log_fifo_size(256));
};

destination iptables_forward_wan_reject {
	file("/var/log/forwardwanreject" suppress(5) template("${ISODATE} ${PROGRAM}: ${MSGONLY}\n") log_fifo_size(256));
};

log {
	source(src);
	source(net);
        source(kernel);
	filter(f_iptables_forward_wan_reject_not_match);
	filter(f_not_cron);
	destination(messages);

	# uncomment this line to open port 514 to receive messages
	#source(s_network);
};

log {
	source(src);
	source(kernel);
	filter(f_cron);
	destination(cron);
};

log {
	source(src);
	source(kernel);
	filter(f_iptables_forward_wan_reject_match);
	destination(iptables_forward_wan_reject);
};

#
# Finally, include any user settings last so that s/he can override or
# supplement all "canned" settings inherited from the distribution.
#
@include "/etc/syslog-ng.d/" # Put any customization files in this directory

Solution without logging:
You can do it simply from Luci Firewall Traffic-Rules:

Or by editing /etc/config/firewall

config rule
	option dest_port '53 853'
	option target 'REJECT'
	option dest 'wan'
	option src 'lan'
	list proto 'tcp'
	list proto 'udp'
	option name 'Block external DNS lan'

This example is for lan subnet, can be repeated for other subnets.