Blacklist all + explicit whitelisting -- multiple methods?

So this question is as much of a learning exercise for me as it is for real-world use (although it has been inspired by some 'real world' problems). Firstly, I've been using computers since Win98 / Pentium 2 days, Gentoo for the last 15 or so, and I've got a M.Eng (Electronic) so I'm hardly new at some things. In some respects I know a fair bit about computers, but in others (especially networking) I have absolutely no idea and need some hand-holding. I've researched a few answers to these questions already but some of what I've read either makes no sense or assumes too much prior knowledge on the part of the reader.

I've had an openwrt (well, LEDE, actually) image on an RPi3 for a year or so, and I want to use another spare RPi3 to create this system. Let's just assume for this question that I've got a PC, connected to an RPi3 running OpenWRT, connected to the internets. (It doesn't matter what the PC is running, win/lin etc, lets just assume that it has some software that is totally not under my control with regards to how / when it connects to the internet, but I'd like it to be reigned in using the external Pi router)

In short, I'm interested in the different ways of creating an automatically-blacklist-everything specific-whitelist openwrt router, which logs every request coming from the PC, allows me to read the logs to see what is being requested, so I can then whitelist those I wish to allow. I know there are a few ways this can be done, so I'll split everything into sections:
.

DNS Requests:
It's easy enough setting my PC (at least, on a system level, eg resolv.conf) to use my PiRouter as a DNS server, been doing that for years.

What I want to do for this system is to log (on my Pi) every request that comes from my PC and automatically blacklists everything (resolves to 127.0.0.1 or something like that?).

If a request comes from my PC for a whitelisted site (say openwrt.org), the Pi itself will do the DNS lookup (say from opendns' 208.67.222.222), and serve the resolved IP back to the PC (I'm pretty sure that this is already what happens under normal circumstances anyway).

But what I don't want to happen is a rogue application on my PC bypassing the system-wide DNS setting and trying to connect to a DNS server directly instead. Is there any way to intercept these if the PC tries to use a different DNS server other than the Pi? (besides blocking the IP address of whatever DNS server it's trying to use instead, as in the next section)

Preliminary reading suggests dnsmasq has something to do with this answer, but I'm not quite sure how to set it up yet.
.

IP Addresses:
Say some PC application has a hard-coded IP address for something, it won't need to do a DNS lookup and it'll just try to connect straight to that site. I want to, again, automatically block and log all outgoing connections, and explicitly only allow ones on a whitelist.

Obviously, connected with the above section, once I've allowed the DNS lookup of a site, I'll have to whitelist the IP address that it resolves to as well.

Also if, say, I block my PC from directly accessing, say, the google DNS server (8.8.8.8) (to stop the PC doing its own DNS lookups), will that also block my Pi from doing its own DNS lookups at that same 8.8.8.8 server?
.

Transports and Ports:
(this is where my knowledge of networking gets really fuzzy).

Say I want to only allow TCP traffic and deny all UDP traffic?

Say I only want to allow the browser on the PC to access the internets using port 443 (https) and block all port 80 (http) traffic?

Or specifically allow something (like a Steam game, for example) access through the router to the internets but block something else? (From a quick search for Steam ports, lets say enable UDP port 27015 for games but block UDP port 3478 for voice chat).

How about allow ssh access (TCP 22) from my PC into the Pi3 (for admin etc), but deny ssh from the PC through the Pi to a remote computer somewhere else on the internets?

Or how about block all IPv6 traffic and only allow IPv4 (or vice-versa)?
.

Anyway, so this is a bit of an open-ended question so I expect an open-ended answer. Like I said this is as much a learning exercise as anything else, I know it would be very clunky to implement on a daily basis but that's really not the point (so don't bother trying to talk me out of it).

Thanks in advance for help and suggestions.
.

(ps, I have investigated certain 'addons' and/or 'plugins' to openwrt, like adblock etc. But I'd prefer to stay away from too much automated stuff as much as possible and keep this as simple and manual as possible unless there really are no other ways to accomplish what i'm trying to achieve)
.

(pps, obviously I want to block everything coming in unsolicited from the internets back to the PC, proper firewall style, only allowing in pages that I've explicitly requested. I do hope that the default settings of OpenWRT work like this or I've been under the wrong impression for the year or two I've already been using it)

DNS blacklisting and logging -- look at unbound which has most of these features in-built. dnsmasq is intended to be lightweight and doesn't have the feature set for the flexibility and logging you want.

"Preventing rogue DNS" -- best you'll be able to do is block access to UDP 53 from your interior network to any outside network. Pretty useless these days, in my opinion, as VPN and DNS over TLS in all its variants go around this. It's about as "secure" as MAC-address filtering; might make you feel good, but trivial to circumvent.

"Transport and ports" -- Look into the firewall section of LuCI after you get an understanding of what you want to pass and why. That latter section is, past things that everyone should block (unroutable IP addresses, various nefarious routing on packets, malformed packets, packets arriving on the wrong interface, ...), it's all a mater of your personal choices on balance of use with security risks. Safest is "block everything", but that means you can't use the network.

Yes, as shipped, OpenWRT basically allow responses on connections that have been established from the router (directly or on behalf of clients behind it) to servers and ports, but not the reverse. Packets and pages are two entirely different things. Packets have to do with how some data is moved from point to point. That is what is typically firewalled. Pages are a construct of the application ("content") and are "just bits" to the transport-layer firewall.

Here is how I would accomplish something like this:

  1. Completely block all forwarding from your LAN to WAN by default
  2. Add a firewall rule to allow forwarding packets to a specific ipset
  3. Add a squid proxy to the RPi and force the LAN members to use the squid proxy for web pages
  4. Set up the squid proxy to allow only certain domains (this is the only way to go for web pages, because IP addresses can serve multiple domains, and domain names can point to multiple ip addresses)
  5. Use DHCP / DHCP6 / router advertisements to advertise the RPi as your DNS.
  6. DNAT the port 53 (DNS) packets to your Rpi anyway so that applications that hardwire DNS wind up talking to your Rpi
  7. If needed set up a SOCKS proxy on the Rpi as well (Dante is the one I use)

With these in place you should be pretty good to go. Any non-rogue device can't really get past this, and any rogue device that tries to do something like DNS over TLS will just stall since you'll be dropping all packets headed to WAN. For those few locations where a program isn't sophisticated enough to use a proxy, you can whitelist certain IPs through the ipset mechanism.

Once you understand the basics of firewall-based control, you might find it a lot easier to achieve reasonable goals by segregating your network.

Just as "general guidance" that I use to keep things under moderate control:

  • There are certain networks that I consider "trusted" -- my wired clients typically
  • There are certain networks that I consider "hostile"
    • Any IoT device, wired or wireless
    • "Guest" wireless
  • There are certain networks that I consider "marginally trustworthy" -- our known, personal phones and iPads

I keep each on their own VLAN, including segregating IoT devices by manufacturer.

Each VLAN gets its own DHCP and DNS, as well as firewall rules that define how they can (or can't) talk with the outside, and across VLANs, if at all.

For malware etc Jeff's scheme can be good, but there are cases where you want to lock down things even for trusted devices: schools, kids at home, defense contractors, time of use restrictions, public libraries, whatever... In those cases my suggestions may be needed even on trusted vlans

One simple way is to install luci-app-tinyproxy.

In Filtering and ACLs set allowed clients to your local IP address range such as 192.168.1.1/24, select [Default Deny] box (By default, the filter rules act as blacklist. Enable this option to only allow matched URLs or domain names), upload the list of allowed web sites, one site per line, in [Filter File]. As this blocks by matching DNS, both http and https web sites will be filtered. To allow Windows update, start with the Microsoft update sites listed in https://technet.microsoft.com/en-us/library/bb693717.aspx which can be added with only 2 sites: microsoft.com [new line] windowsupdate.com.

In the Windows 10 computers which should have the web sites restricted, click on Windows key + I, in Network & Internet, select [Proxy] at bottom, in [Manual proxy setup], turn on [Use a proxy server], enter the address of OpenWRT router in [Address] (e.g. 192.168.1.1), and in [Port] the [Listen port] chosen in [General Settings] (e.g. 8888).

Unfortunately, the Statistics page doesn't work presently. Look up the /var/log/tinyproxy.log via SSH to the router to see the urls visited, at what time, which url is rejected. This LogFile can get unwieldy over time so regular trimming is recommended. It can be done automatically via logrotate in a cron job.

Note that any savy person can bypass a proxy server.

Not if your firewall is blocking all outbound requests on port 80 and 443

25 years ago I was tunneling through telnet connections to get around port restrictions. Today all it takes is a VPN account and client on your machine.

There's always banning all outbound connections from the LAN if you really must :wink:

1 Like

Or route all port 80 and 443 traffic through the proxy server instead of having to go to each workstation and set it to use TinyProxy as per the 3rd paragraph, "In the Windows 10 computers which..." by adding the config redirect rule below in the firewall configuration located in /etc/config/firewall.
I am not sure if there is a way to add another rule to exclude some IP or MAC from this rule for the computers which should bypass the fitlering.

Transparent proxy rule (same host)
The rule below redirects all outgoing HTTP traffic from lan through a proxy server listening at port 8888 on the router itself.

config redirect
option src lan
option proto tcp
option src_dport 80, 443
option dest_port 8888
option dest_ip 192.168.1.1

Yes, but this doesn't work when you have ipv6. There may be a way to redirect ipv6 as well, but in general it's a more complicated issue. I far prefer non-transparent proxies. Systems that don't know they're talking to a proxy can fail when they talk to transparent ones that do things somewhat unexpected and it can become a debugging nightmare that far exceeds the cost of just going around and setting the proxy on all your machines.

So, I finally got around to doing something about this, and thanks for all the discussion and different suggestions thus far. The last few months got a bit busy and my shiny new Ryzen box has just been sitting around gathering dust, but I've been playing with it since last weekend. Anyway, from a basic wrt image with no extra packages installed except net-usb-asix and luci-ssl, things I've learnt so far:

The nooby stuff, like how to write firewall rules. So I've set it to block all outbound by default, and I'm writing individual rules to let little things through at a time (like starting with my upstream router webpages and ntp and pings and such).

DNS-request logging is actually easy with whatever is builtin (dnsmasq?), in luci there was an option to just log all requests to /var/log/syslog. And only allowing port 53 from lan->router, setting all upstream dns requests to go out at a single port like 55553, and another rule to only allow 55553 to a port 53 upstream was easy enough too.

A few disturbing things that I've found so far:

a) On my windows 7 installation I've got IPv6 disabled in the ethernet properties box. But occasionally it's still requesting AAAA (ipv6) DNS. I've also got all inbound and outbound ipv6 blocked at the firewall, but the firewall is still forwarding AAAA lookups to upstream DNS.

  • Question, is there a way to turn off forwarding of AAAA lookups completely? That windows still uses ipv6 even when told not to is very dodgy but not entirely unexpected, and part of the reason why I wanted to test things like this with the firewall.

b) My Windows 7 (not even Spyware Edition 10) has updates completely turned off (ie, to never check). But the first thing it does when I log on is to DNS-lookup windowsupdate.com. Also, when I start up firefox (which also has updates turned off / never check) it seriously spams (multiple per second) dns lookups to things like detectportal.firefox.com, mozaws.net, safebrowsing.googleapis.com, even occasionally google-analytics.com. These are precisely the things I want to block at the firewall level, which is easy enough in /etc/hosts, just resolve to 127.0.0.1 . But more importantly, now my syslog is just getting spam-filled with logs of these lookups (ie if I open firefox, go straight to my router, login to luci, go to the syslog-viewing page, in those few seconds there are a few hundred lines of DNS lookups in there).

  • So the question is, how can I suppress logging of lookups that are handled by /etc/hosts, but keep logging requests that get sent upstream? (does unbound as suggested handle it better?)

c) Another Windows thing is that it occasionally sent out DNS lookups for "wpad.mydomain". I've found that comes from the WPAD service on windows and disabled that, but that's not the problem. The problem was that my router was taking that "wpad.mydomain" request and forwarding it upstream, which is disturbing. I've got the 'filter useless' checkbox on the luci dns-settings page enabled, but it still got passed upstream.

  • How, why, and how do I stop it forwarding local-domain queries upstream? (bug?)

So then I set myself a little task as part of this learning exercise, which was to install Steam, download updates, install an MMO game, and see if I could play. Basically I looked at what DNS lookups were resolving to (seriously, it seems the entire internet cnames to something at Akamai), allowing that specific IP with a single rule (sometimes a few consecutive IPs that were all akamai because the DNS was serving multiple round-robin style). While it was downloading I could look to see if the download was going via a specific port and/or transport, and narrow down the firewall rule more specifically (ie, not just unblock the entire akamai IP because that could also be serving stuff I don't want, only unblock the single akamai IP at a single steam-update-specific port).

That was the easy part, and eventually (34 hours later at 700k/s) I'd downloaded a game. Then came the hard part, in that the game has multiple hard-coded IP addresses of its servers, ie it doesn't need to DNS-lookup for them (I was specifically wanting to encounter this hence using this game as a test)

  • So next question is: how / where can I log and view what requests are getting blocked by the firewall? (specifically the 'default deny' rule)?

Anyway, I cheated a bit, loaded the game on my older pc (which goes through a different rpi/wrt router) and looked at the active connections to get some idea of the server IPs and ports that it was using (and googling helped). Problem is, there are multiple IPs assigned to a single "game server" (I've found at least 6, but it still doesn't load all the time), and multiple ports possible (like a few hundred ports) at each IP address.
First thing I found is, if you try to wildcard writing firewall rules in luci, it goes red and won't let you. But if I edit /etc/config/firewall directly and put a * anywhere (like "config option dest_ip '10.1.2.*' ") it will just let the entire internet through. So that's no good.

  • So the next question is, how can I unblock a range of IPs and/or a range of ports? Currently I'm unblocking say 6 IPs manually, at all ports, with 6 separate rules. Alternatively, I could unblock all IPs at a hundred ports with a hundred rules (not practical, and a lot less safe). What I'd prefer is a range of IPs at a range of ports in a single rule, like '10.1.2.30 -> 10.1.2.40 at ports 50000 -> 50100'. Is this possible and how? (worst case I suppose I could live with whitelisting a whole /8 block) Can a proxy help with this kind of thing if it's hardcoded IP and dosen't go through DNS lookup?

  • And a final question (for now), the answer to which will probably involve the word 'proxy' (I just haven't gotten that far yet). Can I intercept/redirect/mangle/whatever all requests to http:80 pages, check whether the destination IP accepts https:443 connections (because some might not), turn it into an https:443 request, get the response, unmangle it, then send back the packet to my pc as the :80 response it requested? This may be too much processing power for a humble RPi2, but I'm just very disturbed at the amount of :80 stuff is still getting requested (come on guys, it's nearly 2019). https-everywhere works great as a firefox extension, but there's a lot of internet traffic that doesn't go through browsers still using :80

OK, I'll admit I skipped most of that and jumped to the end.

For logging on a Linux-based system, in my experience, you typically need to install, configure, and enable ulogd. It's not straightforward, unfortunately.

I'm not a big fan of trusting DNS for firewall rules, and it looks like you've got "hard" IPs to work with. For the acceptable patterns for matches, http://ipset.netfilter.org/iptables.man.html is a good reference.

A common pattern for firewalls I write, in pseudo code is

if packet is in generally interesting class
    if packet matches this good pattern
        continue
    if packet matches this other good pattern
        continue
    drop and maybe log all

if packet is in this other generally interesting class
    [...]

This kind of pattern also helps make the logs more understandable, especially if you are using rules that can "tag" ulog entries. The below example is for an idea of what can be done. It is from nftables, which is not the default firewall system of OpenWrt (iptables).

timestamp=2018/11/13-17:53:41,raw.pktlen=40,raw.pktcount=1,oob.prefix=DROP: PREROUTING PRE-NAT: ct state invalid: ,oob.time.sec=1542160421,oob.time.usec=835411,oob.mark=0,oob.ifindex_in=12,oob.hook=0,raw.mac_len=14,oob.family=2,oob.protocol=2048,raw.label=2,raw.type=1,raw.mac.addrlen=6, [...]

Certain firewall systems will also let you tee or divert packets to a socket, where they can be observed by wireshark or the like. Careful rule crafting is required so you don't get packet loops.


On redirects from 80 to 443 and HTTP-S, a well-configured web server will not only redirect the request, but also add a "Strict-Transport-Security" header with the browser will apply to subsequent requests. That header can be specified to include subdomains as well. Personally, I think your time is better spent elsewhere than trying to determine if you can proxy on behalf of your network's clients.

I think you should look in a couple directions. First: ipset based firewall rules and dnsmasq will fill up ipsets based on DNS lookups

Second: squid, which is the way to go for all port 80 and 443 filtering. Set it up as explicit proxy, because transparent is problematic. And ban all outbound port 80 and 443 connections so everyone goes through the proxy.

Good luck.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.