A Working Method to Precisely Block Distracting Websites using a MikroTik Router
July 29, 2020
Introduction: Eliminating Distractions
I've recently been looking for ways to keep myself from getting sidetracked
during the day, and came across
this blog post
about blocking distracting websites using a MikroTik router. This solution
sounded perfect to me:
- It could be applied only during specified times, so my internet would
only be blocked during working hours leaving me free to watch youtube
videos in the evening.
- It could be applied to specified devices only, so other people or
devices on my network won't be affected.
So, I ordered a MikroTik router (specifically, the
RBD52G-5HacD2HnD-TC,
which seemed to be one of their cheaper offerings). Unfortunately, I quickly
came across many problems that many online blog posts fail to mention, despite
purportedly offering instructions on how to block websites on MikroTik routers.
In this post, I discuss the problems, and give my amended (and unfortunately
far more complicated) procedures to work around them.
The Problem
The problem with the blog post linked above quickly becomes apparent if you
want to block a "large" website, such as youtube: youtube.com
may
resolve to one of many IP addresses. An end user may never know all of these
IP addresses, so adding them to a block list is virtually impossible---block
one IP and you may simply be directed to a different, unblocked IP address next
time you try to visit the site. It's a simple problem, but not one with a
straightforward solution.
Proposed Approaches
Other websites and blogs often list different approaches for blocking websites
on a Mikrotik router. They're all garbage, and here's why:
- Block sites using the "TLS host" filter in the firewall rules:
This never worked at all for me. The firewall rule never matched a single
packet. It may have to do with the topic discussed in
this forum post.
However, no good solution was presented there, so I don't really care about
the underlying reason it didn't work.
- Block sites using Layer 7 protocols: Not only does the MikroTik
website say not to do this for efficiency reasons, it's not even
guaranteed to work, especially for encrypted (HTTPS) traffic.
- Block sites using a DNS black hole: This is at least feasible,
but there is one major problem: it affects all systems on the network.
Great for blocking ads, but not great if I want to prevent only myself
from listening to youtube livestreams while I'm supposed to be working.
On top of that it often doesn't even work! DNS-over-HTTPS prevents this
from working, and end users can easily bypass the restriction by changing
the DNS server in their computer's settings to point to something like
google (8.8.8.8) or cloudflare (1.1.1.1).
The Working Solution
The approach I settled on, and that is now working to my satisfaction, simply
builds on the block-list approach discussed in the original blog post I had
tried to follow. However, it requires a key additional step:
- Statically resolve DNS requests for websites I want to block to a single,
valid, IP address for that site.
This means that other users can continue to use the sites, but I can create a
firewall rule to block the specific, known, addresses on my own systems. If,
for some reason, the website's IP address changes, updating my static DNS rule
will be easy.
Unfortunately, carrying this out is deceptively complicated; it turns out that
modern computers can do all sorts of things to ignore your router's DNS
settings. Regardless, we'll cover those issues later. For now, it's probably
easier to just start with the steps:
- Pre-step: I'm assuming that your router is already working and you
are able to access the internet normally.
- Ensure that your router is acting as your DNS server:
- Go to the router's settings (I accessed mine just using the
"WebFig" interface at 192.168.88.1 by default).
- Under IP→DHCP Server, select the "Networks" tab and click on the
network under "defconf" to change its settings. Click the
arrow next to "DNS Servers", and put the router's IP address
(by default, 192.168.88.1) into the box. Click OK.
- Under IP→DNS, click on the down arrow next to "Servers"
and enter 1.1.1.1 into the box (cloudflare's default DNS server). You
can use different servers if you want. For example, if you have a
PiHole ad-blocking DNS server on your network then you'll need to put
its IP address in this field. (Though, if you have such a setup you
probably already have done so.) Make sure the "Allow remote
requests" box is checked. Click on "Apply".
- Under IP→DHCP Client, click on the first entry under
"defconf". Uncheck "Use Peer DNS" and click
"Apply". This should prevent the router from trying to use
your ISP's DNS servers. (This may not be necessary.)
- Make sure your devices have static IP addresses, and create a list of
devices:
- Under IP→DHCP Server, select the "Leases" tab. Look for
the device(s) for which you want to restrict access. Click on the
address for each device, then click on the "Make static"
button.
- Now that your devices will have static IP addresses, we'll add them
to a list that can be used later. Go to IP→Firewall, and click on
the "Address lists" tab. For each device from the previous step:
- Click on "Add New"
- In the "Name" box, enter the name of the list to create
(or select the name of the list if you've already registered at
least one address). I'll use "blocked_devices" for my list
name.
- In the "Address" box, enter the (now static) IP of the
device.
- Set static DNS rules for each website you want to block, and create a
list of website addresses: Important note: you may need to carry out
these steps for each subdomain, too, since subdomains may have different IP
addresses from the higher-level domains. For example, I carried out these
steps for both "youtube.com" and "www.youtube.com"--both
have different addresses, and you can't just block one of them and expect
it to work!
- Obtain the IP address of the domain you want to block. In my opinion,
the easiest way is just to use "ping" in a terminal (e.g.
ping www.youtube.com
). Copy the IP address.
- In the router's settings, go to IP→DNS, then click on the
"Static" button. Click on "Add New". Enter the
full domain (e.g. "www.youtube.com") in the "Name"
box, and the IP you copied in step 1 into the "Address" box.
Keep the "Type" option set to "A". Click on OK.
- We'll also create a list of restricted site addresses.
- Go to IP→Firewall, and click on the "Address lists"
tab again.
- Click on "Add New".
- In the "Name" box, enter the name of a different list
from the one you created for your devices. I'll use
"blocked_sites" for my list name here. (You should be
able to select the existing "blocked_sites" name if
you've already registered at least one address in this list.)
- In the "Address" box, enter the IP address you set for
the domain.
- Click "Ok".
In the future, if you want to add additional blocked sites, you only need to
follow the above steps in this section: set a DNS rule to supply a known IP
address, and then add that IP address to the block list. Additionally, if
you know that the site you wish to block only has a single IP address, you
don't need to add the DNS entry---just put the IP directly into the
"blocked_sites" address list.
- Quick aside: making sure we haven't broken anything yet: After
adding all of these addresses, but before adding any firewall rules, you
may want to test out your new DNS settings to make sure everything still
works and that your IP addresses are used properly. You may need to clear
several DNS caches:
- Clear the router's DNS cache: Go to IP→DNS, and click on the
"Cache" button. Then click "Flush cache".
- Clear your browser's DNS cache. This differs based on the browser,
you'll need to check online for instructions on how to do it in
yours.
- Clear your operating system's DNS cache. Once again, this may differ
on different systems, so I'd recommend searching online for how to do
it.
After this, restart your router. Once your computer is connected back to
the internet, try accessing the domains that you set the IP addresses for.
Since we haven't added any firewall rules yet, you still should be able to
access them. For sanity, check the IPs for each domain using
"ping" or whatever method you used earlier. (Don't use a browser
to test the IPs, since browsers may still be using DNS over HTTPS, which
we prevent in a later step.) If the IPs differ from the ones you statically
set in the router's DNS settings, then your computer is still not using
your router as a DNS server. If that happens, you may want to make sure
your computer hasn't been manually set to use a specific DNS server other
than your router.
- (Finally) Add a firewall rule to block the websites:
- In the router's settings, go to IP→Firewall. Click on "Add
New".
- Keep the "Chain" set to "Forward".
- Next to "Src. Address List", select
"blocked_devices" (or whatever you named your list of devices
to be restricted).
- Next to "Dst. Address List", select
"blocked_sites" (or whatever you named your list of addresses
to be blocked).
- Click the arrow next to "Time". Enter the start and stop
times that you want sites restricted. I wanted mine restricted from
8:00 AM until 6:30 PM, so my boxes contain "08:00:00" and
"18:30:00". Also select the days on which it applies.
- Next to "Action", select "drop".
- You may want to add a comment, like "block distracting
sites" to help you find the rule.
- Click "Ok".
- The new rule should now appear at the bottom of the list of rules.
However, we want it to apply before any rule that explicitly
allows anything. So, just use the mouse to drag the rule up the list,
above any rule that "accept"s anything.
- Preventing DNS over HTTPS, or accessing other DNS servers (at least
for Firefox, maybe others):
The problem with the system outlined
above is that it completely relies on the router's DNS server supplying
addresses for websites. If you have a browser, like firefox, using
DNS-over-HTTPS, then this bypasses traditional DNS resolution and obtains
IP addresses for websites regardless of what you set earlier. Obviously,
this is no good since most of the time you probably won't end up with the
static, blocked IP address set earlier.
You can just disable DNS over HTTPS in firefox's settings, but this is
useless for preventing distractions because it can be re-enabled with just
a single click. Supposedly, Firefox checks a "canary" URL to
disable DoH, but this is completely meaningless, as FF ignores the canary
in favor of the easily modified user setting. We need to do something a bit
stronger. So, here's what I did that finally worked:
- Block the site that firefox uses to carry out DNS over HTTPS. Go to
"about:config" (accept the warning; we won't change
anything), and search for "trr.uri". You should see a single
URL. For me, it was
https://mozilla.cloudflare-dns.com/dns-query
.
- We want to block the URL listed above, using the same steps as
before. First, use ping or any tool of your choice to look up the IP
address for
mozilla.cloudflare-dns.com
, as well as
cloudflare-dns.com
for good measure. (They have different
IP addresses.) If your "trr.uri" setting had a different
domain, then look up that domain instead.
- Add Static DNS rules in the router's IP→DNS→Static settings
to force the router to resolve these addresses to IPs you just looked
up. (We're doing the same thing as before with the blocked websites.)
- Add both of these IP addresses to a new "dns_servers"
address list. (You can name the list whatever you want.) Create and
add addresses to the address list the same way you did earlier, under
IP→Firewall→Address Lists.
- For good measure, also add google's and cloudflare's
"normal" DNS servers to the "dns_servers" address
list. The server addresses are 8.8.8.8, 8.8.4.4, 1.1.1.1, and 1.0.0.1.
Add any other DNS server addresses you want.
- Create a firewall rule to block any access to these DNS servers from
your restricted devices:
- Go to IP→Firewall, and click on "Add New" under the
"Filter" tab.
- Keep the "chain" setting set to "forward".
- For "Src. Address list", select
"blocked_devices" from earlier.
- For the "Dst. Address list", select the new
"dns_servers" list.
- Set "action" to "drop"
- Add a comment, if you want, like "block DNS
workarounds".
- Click "Ok"
- Drag the new rule to a position above the previous rule you
added, near the top of the list.
Now, firefox's DNS-over-HTTPS should fail and fall back to a different
option, regardless of whether it is enabled.
Should you find yourself trying to work around the blocking in the
future, hopefully preventing that is simply a matter of adding another DNS
server to the dns_servers list.
As a final step, repeat the procedure in section 4. above to
clear any cached DNS addresses. You may need to restart your web browsers
and your router before some of the changes take effect.
Conclusion
With this, your websites should be blocked. In summary, we:
- Forced the router to act as a DNS server.
- Assigned static IP addresses to each device to restrict, and added these
addresses to a list.
- Configured the router's DNS server to return only one IP address per site
to block.
- Added the site IP addresses to a separate list.
- Created a firewall rule to block traffic going from the addresses in the
device list to addresses in the site list.
- Prevented some methods for bypassing this, such as DNS over HTTPS or
manual DNS server settings.
Finally, when you have settings you are satisfied with, get someone you trust
to set the password on your router! We only should have added two firewall
rules, so to return everything to normal, you can disable or delete the rules,
and then disable or delete any static DNS settings you added.