What's new

Does DNSFilter Support DoT?

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

For those that might be interested in doing the same thing, here's my final solution:

services-start script file copied to /jffs/scripts and made executable:

Code:
#!/bin/ash

# Wait 2.5 minutes for router and nodes to fully initialize
logger -t "services-start" "Waiting 2.5 minutes for router and node(s) to fully initialize ..."
sleep 150

# Start ctrld DNS server and restart it after 2 seconds if it exits with a non zero exit code
logger -t "services-start" "Starting ctrld DNS server ..."
until /jffs/scripts/ctrld run --config "/jffs/configs/ctrld.toml"
do
  logger -t "services-start" "ctrld DNS server stopped unexpectedly"
  sleep 2
  logger -t "services-start" "Restarting ctrld DNS server ..."
done &

service-event-end script file copied to /jffs/scripts and made executable:

Bash:
#!/bin/ash

# Check if the DNSFilter is being started or restarted
if [[ "$2" == "dnsfilter" ]] && [[ "$1" == "start" || "$1" == "restart" ]]
then
  # Update the log
  logger -t "service-event-end" "DNSFilter was started or restarted ..."

  # Declare and define variables
  lan_ip="$(nvram get lan_ipaddr)"
  custom_1="$(nvram get dnsfilter_custom1)"
  custom_2="$(nvram get dnsfilter_custom2)"
  custom_3="$(nvram get dnsfilter_custom3)"

  # Loop through the iptables rules in the nat table in the DNSFILTER chain
  # Note: some of the rule changes below could be done more efficiently by changing rules in the
  #       PREROUTING chain, however, it is safer to only change rules in the DNSFILTER chain which
  #       should get modified by the router only during the dnsfilter start or restart events
  rule_number=0
  iptables --table nat --list-rules DNSFILTER | while IFS="" read -r rule
  do
    # Add the table to the rule
    rule="-t nat $rule "

    # Check (by removing the substring being searched for from the rule and comparing the result
    #   against the original rule) if this rule is the new chain rule
    if [[ "${rule/ -N DNSFILTER}" != "$rule" ]]
    then
      # Increase the rule number counter
      rule_number=$(( rule_number + 1 ))

      # Continue to the next rule
      continue
    fi

    # Check (by removing the substring being searched for from the rule and comparing the result
    #   against the original rule) if this rule points to one of the DNSFilter custom DNS servers
    if [[ "${rule/ --to-destination $custom_1}" != "$rule" || \
      "${rule/ --to-destination $custom_2}" != "$rule" || \
      "${rule/ --to-destination $custom_3}" != "$rule" ]]
    then
      # Update the log
      logger -t "service-event-end" "Found iptables rule pointing to DNSFilter custom DNS server ..."

      # Modify the rule destination
      if [[ "${rule/ --to-destination $custom_1}" != "$rule" ]]
      then
        rule="${rule/ --to-destination $custom_1/ --to-destination $lan_ip:54}"
      fi
      if [[ "${rule/ --to-destination $custom_2}" != "$rule" ]]
      then
        rule="${rule/ --to-destination $custom_2/ --to-destination $lan_ip:55}"
      fi
      if [[ "${rule/ --to-destination $custom_3}" != "$rule" ]]
      then
        rule="${rule/ --to-destination $custom_3/ --to-destination $lan_ip:56}"
      fi
     
      # Replace the rule with a modified rule for the TCP protocol and for traffic destined to the
      #   router's LAN IP address
      # Note: specifying a protocol is required in order to use a port number and specifying a
      #       traffic destination allows a client to use a different DNS server and bypass this rule
      logger -t "service-event-end" \
        "Replacing rule with modified iptables tcp rule pointing to local ctrld DNS server ..."
      iptables ${rule/ -A DNSFILTER/ -R DNSFILTER $rule_number -p tcp -d $lan_ip}

      # Increase the rule number counter
      rule_number=$(( rule_number + 1 ))

      # Insert a modified rule for the UDP protocol and for traffic destined to the router's LAN IP
      #   address    
      # Note: specifying a protocol is required in order to use a port number and specifying a
      #       traffic destination allows a client to use a different DNS server and bypass this rule
      logger -t "service-event-end" \
        "Replacing rule with modified iptables udp rule pointing to local ctrld DNS server ..."
      iptables ${rule/ -A DNSFILTER/ -I DNSFILTER $rule_number -p udp -d $lan_ip}

      # Increase the rule number counter
      rule_number=$(( rule_number + 1 ))

      # Continue to the next rule
      continue
    fi

    # Update the log
    logger -t "service-event-end" "Found iptables rule pointing to DNSFilter preset DNS server ..."

    # Replace the rule with a modified rule for traffic destined to the router's LAN IP address
    # Note: specifying a traffic destination allows a client to use a different DNS server and
    #       bypass this rule
    logger -t "service-event-end" "Replacing rule with modified iptables rule ..."
    iptables ${rule/ -A DNSFILTER/ -R DNSFILTER $rule_number -d $lan_ip}

    # Increase the rule number counter
    rule_number=$(( rule_number + 1 ))
  done
fi

exit 0

ControlD ctrld utitlity copied to /jffs/scripts and made executable:


ctrld.toml file copied to /jffs/configs

Code:
[service]
  log_level = "warn"

[listener]

  [listener.0]
    ip = "192.168.50.1"
    port = 54

  [listener.1]
    ip = "192.168.50.1"
    port = 55

  [listener.2]
    ip = "192.168.50.1"
    port = 56

[upstream]

  [upstream.0]
    bootstrap_ip = "8.8.8.8"
    endpoint = "dns.google"
    timeout = 0
    type = "dot"

  [upstream.1]
    bootstrap_ip = "8.8.8.8"
    endpoint = "dns.google"
    timeout = 0
    type = "dot"

  [upstream.2]
    bootstrap_ip = "8.8.8.8"
    endpoint = "dns.google"
    timeout = 0
    type = "dot"

The scripts above redirect the 3 custom DNS Filter/Director entries and send them to the ctrld utility for processing. They also make DNS Filter/Director optional by only redirecting DNS traffic directed to the router ... if someone doesn't want that "feature" then simply take out a few lines of code and remove the "-d $lan_ip" portions of the modified iptables rules. It's also pretty trivial to redirect the various other preset DNS Filter/Director entries to ctrld if one wants to do that. Lastly the ctrld utility has additional functionality that can be specified in its config file. The config file shown is just a basic setup using the Google servers as examples.
 
For those that might be interested in doing the same thing, here's my final solution:


Thanks, but this seems too reliant on an external program, stubby could achieve running a second instance.

Just a few scripts to handle dnsmasq, stubby and iptables to achieve the same functionality.

I'll provide a proof-of-concept over the weekend, if I have time for a computer over the weekend.
 
  • Like
Reactions: Baf
Thanks, but this seems too reliant on an external program, stubby could achieve running a second instance.

Just a few scripts to handle dnsmasq, stubby and iptables to achieve the same functionality.

I'll provide a proof-of-concept over the weekend, if I have time for a computer over the weekend.
It's true this requires an external program but that external program seems way better equipped to accomplish what we're trying to accomplish so it only made sense to use it.

What if you had several dozen different servers your wanted to send traffic to? Having that many instances of stubby might not work out too well. The utility I'm using just needs one instance. What if the server you wanted to use only supports DNS over HTTPS? I don't believe stubby can do that. The utility I'm using can. There's probably several more reasons I could think of that makes this utility better than stubby.
 
It's true this requires an external program but that external program seems way better equipped to accomplish what we're trying to accomplish so it only made sense to use it.

What if you had several dozen different servers your wanted to send traffic to? Having that many instances of stubby might not work out too well. The utility I'm using just needs one instance. What if the server you wanted to use only supports DNS over HTTPS? I don't believe stubby can do that. The utility I'm using can. There's probably several more reasons I could think of that makes this utility better than stubby.
Yes, you're right, stubby does not support DoH. Anyway I'm glad this solved your needs.
 
@HarryMuscle

Thanks for the solution.

After doing everything and then getting spammed by "Starting ctrld DNS server" & "ctrld DNS server stopped unexpectedly" on syslog, I rolled back your scripts and tried to see if my router can run the ctrld utility.

However it appears ctrld utlity is either buggy or doesn't work on my RT-AC68U router.

I attempted to run the the ARM64 binary you have linked with the following command on Putty.

/jffs/scripts/ctrld run

This resulted in the following error:
/jffs/scripts/ctrld: line 1: syntax error: unexpected word (expecting ")")

Next, I tried the ARMv7 binary after realizing that RT-AC68U has 32-bit ARM v7 CPU.

However, this resulted in the following error in Putty.

Illegal instruction

The syslog also showed the following error

Jan 29 16:48:52 kernel: Pid: 6072, comm: ctrld
Jan 29 16:48:52 kernel: CPU: 0 Tainted: P (2.6.36.4brcmarm #1)
Jan 29 16:48:52 kernel: PC is at 0x5ee2c
Jan 29 16:48:52 kernel: LR is at 0x7d624
Jan 29 16:48:52 kernel: pc : [<0005ee2c>] lr : [<0007d624>] psr: 20000010
Jan 29 16:48:52 kernel: sp : bea43d08 ip : cafebabe fp : 00abd938
Jan 29 16:48:52 kernel: r10: 00abfb98 r9 : 00000000 r8 : 00abffd0
Jan 29 16:48:52 kernel: r7 : 00000014 r6 : 00000000 r5 : 00000000 r4 : 00000000
Jan 29 16:48:52 kernel: r3 : 00000000 r2 : 00000000 r1 : bea34148 r0 : 00000000
Jan 29 16:48:52 kernel: Flags: nzCv IRQs on FIQs on Mode USER_32 ISA ARM Segment user
Jan 29 16:48:52 kernel: Control: 10c53c7d Table: 9b02404a DAC: 00000015

The ARMv6 binary produced the same errors as the ARMv7 binary.

I have tried uninstalling all the scripts (Scribe, Diversion, YazFi, etc), and formatting JFFS, but have not been able to resolve the issue. I am now considering a factory reset.
 
@RT-N66U

Using a second stubby instance might work for you.

Reference here, @ColinTaylor provides almost all commands to achieve everything.

Before starting, you need to delete /var/run/stubby.pid file

Then copy /etc/stubby/stubby.yml and edit the file

Finally enable the second stubby instance /usr/sbin/stubby -g -C /etc/stubby2/stubby2.yml
 
@HarryMuscle

Thanks for the solution.

After doing everything and then getting spammed by "Starting ctrld DNS server" & "ctrld DNS server stopped unexpectedly" on syslog, I rolled back your scripts and tried to see if my router can run the ctrld utility.

However it appears ctrld utlity is either buggy or doesn't work on my RT-AC68U router.

I attempted to run the the ARM64 binary you have linked with the following command on Putty.



This resulted in the following error:


Next, I tried the ARMv7 binary after realizing that RT-AC68U has 32-bit ARM v7 CPU.

However, this resulted in the following error in Putty.



The syslog also showed the following error



The ARMv6 binary produced the same errors as the ARMv7 binary.

I have tried uninstalling all the scripts (Scribe, Diversion, YazFi, etc), and formatting JFFS, but have not been able to resolve the issue. I am now considering a factory reset.
You're right, I forgot to mention that you'll need to download the version that matches your CPU architecture.

Sounds like none of the precompiled ARM versions will run on your router though. I wonder if it requires newer routers to use the precompiled binaries. You'd probably have to compile the utility yourself with the correct options to work on your type of CPU.
 
Heya, I'm one of Control D staff, and ctrld utility is one of our projects. I've escalated this to the devs, we'll get it running on AC68U part of v1.2 which will have self-setup capabilities. v1.1 will be released shortly (lots of new features), but the fix for this won't make it in.
 
Heya, I'm one of Control D staff, and ctrld utility is one of our projects. I've escalated this to the devs, we'll get it running on AC68U part of v1.2 which will have self-setup capabilities. v1.1 will be released shortly (lots of new features), but the fix for this won't make it in.
Good to know. Thanks for letting us know.
 
specify upstream servers based on incoming client IP within the DNS function.
Can you provide further details? I checked the update log of 2.88 again, but I didn't find the function of specifying different upstream DNS servers for different DHCP clients.


The closest thing to what you're describing is this log, but that doesn't involve specifying a different DHCP client.
Allow domain names as well as IP addresses when specifying
upstream DNS servers. There are some gotchas associated with this
(it will mysteriously fail to work if the dnsmasq instance
being started is in the path from the system resolver to the DNS),
and a seemingly sensible configuration like
--server=domain.name@1.2.3.4 is unactionable if domain.name
only resolves to an IPv6 address). There are, however,
cases where is can be useful. Thanks to Dominik Derigs for
the patch.
 
Can you provide further details? I checked the update log of 2.88 again, but I didn't find the function of specifying different upstream DNS servers for different DHCP clients.
dnsmasq has no way of doing that. It was you that implied it could be done and Dave was asking you to explain what you meant.

The full sentence was:
I thought you were suggesting there was a new way in dnsmasq 2.88 to specify upstream servers based on incoming client IP within the DNS function.
 
dnsmasq has no way of doing that. It was you that implied it could be done and Dave was asking you to explain what you meant.

The full sentence was:
I've provided the method before, and I tested that it works, but this just pushes the DNS server to the client via DHCP, not forwarding upstream inside dnsmasq.

I just re-read the dnsmasq man page and it appears that forwarding is not really possible internally.

I want DNS traffic to go through dnsmasq first and then forward to a different upstream, because I have some custom hostnames configured in dnsmasq and I don't want to lose those.

Would iptables be a good way to do this? I don't think it can achieve the forwarding to 127.0.2.1 that stubby2 listens to as we discussed earlier

Code:
iptables -t nat -I PREROUTING -p udp -s 192.168.50.15 --dport 53 -j DNAT --to 127.0.2.1



So, I hope that DNS traffic must first be sent to dnsmasq to resolve the custom hostname, and then specify different upstream servers according to different clients.



EDIT:

Well, since this involves DNS caching, the best way to do this is to run two instances of dnsmasq, one listening on 192.168.50.1 and the other on 192.168.50.2 created by the virtual interface, then forward to different upstream stubby.
 
Last edited:
I've provided the method before, and I tested that it works, but this just pushes the DNS server to the client via DHCP, not forwarding upstream inside dnsmasq.
This is really no different than the option that already exists in the GUI (LAN - DHCP Server > Manually Assigned... > DNS Server (Optional)).

EDIT:

Well, since this involves DNS caching, the best way to do this is to run two instances of dnsmasq, one listening on 192.168.50.1 and the other on 192.168.50.2 created by the virtual interface, then forward to different upstream stubby.
I don't think there's a way of doing this that isn't a very narrow use case. Even is you had two dnsmasq servers how would you handle DHCP? What about clients that register their host names with dnsmasq #1? Those names would not be resolvable using dnsmasq #2. How would you integrate this with the exiting dnsmasq config files and the GUI?
 
I don't think there's a way of doing this that isn't a very narrow use case. Even is you had two dnsmasq servers how would you handle DHCP? What about clients that register their host names with dnsmasq #1? Those names would not be resolvable using dnsmasq #2. How would you integrate this with the exiting dnsmasq config files and the GUI?


A simple idea is that the client still gets DHCP through dnsmasq1, but dnsmasq1 replies with the DNS server address that dnsmasq2 listens on.

Code:
dhcp-option=tag:dns2,6,192.168.50.2
dhcp-host=XX:XX:XX:XX:XX:XX,set:dns2,192.168.50.15

dnsmasq2 (192.168.50.2) will only receive DNS requests and correctly forward them to the specified upstream server.

Code:
server=127.0.2.1


Of course, this also requires the filter list to be fully loaded into dnsmasq2's configuration file.

I admit, this is not an elegant solution, as two stubby is overkill and now there is a second instance of dnsmasq.


Well, I haven't tested it yet, I don't know what's going on with this, I need to test.


In addition, OVPN's Exclusive mode and DNS Director will bypass dnsmasq and lose the resolution of local hostnames and other functions that dnsmasq can bring.

I'll post back if I can figure this out, it will be an enhancement to DNS Director.
 
A simple idea is that the client still gets DHCP through dnsmasq1, but dnsmasq1 replies with the DNS server address that dnsmasq2 listens on.

Code:
dhcp-option=tag:dns2,6,192.168.50.2
dhcp-host=XX:XX:XX:XX:XX:XX,set:dns2,192.168.50.15
This still doesn't solve the problem with resolving local host names. Not unless you intend to statically assign every local device, which I don't regard as a viable solution.
 
@HarryMuscle

Thanks for the solution.

After doing everything and then getting spammed by "Starting ctrld DNS server" & "ctrld DNS server stopped unexpectedly" on syslog, I rolled back your scripts and tried to see if my router can run the ctrld utility.

However it appears ctrld utlity is either buggy or doesn't work on my RT-AC68U router.

I attempted to run the the ARM64 binary you have linked with the following command on Putty.



This resulted in the following error:


Next, I tried the ARMv7 binary after realizing that RT-AC68U has 32-bit ARM v7 CPU.

However, this resulted in the following error in Putty.



The syslog also showed the following error



The ARMv6 binary produced the same errors as the ARMv7 binary.

I have tried uninstalling all the scripts (Scribe, Diversion, YazFi, etc), and formatting JFFS, but have not been able to resolve the issue. I am now considering a factory reset.
We've done a series of tests, and it appears the arm v5 binary runs on your router, at least in our tests on an identical model. Not sure why, as armv7 is totally supported..... Try this exact version: https://github.com/Control-D-Inc/ctrld/releases/download/v1.1.0/ctrld_1.1.0_linux_armv5.tar.gz

This is a new release, v1.1, lot's of new stuff there (no automatic configuration yet). Check README for details if you'd like.
 
@yegor just wanted to give you a heads up that unfortunately the ctrld utility stops responding to DNS requests after a while. It's only happened to me once so far (but I've only been running it for about a week in production). Based on the GitHub Issues for this project, one other person reported a similar issue (although they also had some other configuration issues possibly) so there's definately something going on that needs to be fixed. Wish I could provide more details and help figure out why it stops working but unfortunately I rebooted the router before I copied any logs, etc. I'll have to switch over to running multiple stubby instances for the time being until ctrld is a bit more mature.
 
@yegor just wanted to give you a heads up that unfortunately the ctrld utility stops responding to DNS requests after a while. It's only happened to me once so far (but I've only been running it for about a week in production). Based on the GitHub Issues for this project, one other person reported a similar issue (although they also had some other configuration issues possibly) so there's definately something going on that needs to be fixed. Wish I could provide more details and help figure out why it stops working but unfortunately I rebooted the router before I copied any logs, etc. I'll have to switch over to running multiple stubby instances for the time being until ctrld is a bit more mature.
Hmmm, interesting. Can you email me your config file to yegor@controld.com, what physical device you ran this on, and approx. query volume you were sending?

Edit: I think we may have identified an issue. When default gateway changes, and changes back to the original one, the issue occurs. It can also happen when there is an IP stack change (v6 -> v4). We're resolving both in v1.1.1

Edit2: v1.1.1 is released, addressed several bugs including the one above.
 
Last edited:

Latest threads

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top