A filtering DNS forwarder – proof of concept
I have been looking for a good web filter for my family. I’m not running a school, library, or any public facility – my use is just a filter for my family. Thanks to the wonderful pfSense project, I first tried Squid with DansGuardian and Squid Guard. However, with more and more sites using SSL you have to use the SSLbump feature (essentially a man in the middle attack). It worked, but I’m not very comfortable with the SSLbump. I want to teach my family members about SSL and the things they should look at to make sure they are secure (especially when doing any banking). Also, Google has blocked SSLbumping if you use the Chrome browser, plus a few other issues with the SSlbump. So, this led me to try filtering with DNS.
The best free filtering DNS forwarder that I’ve found is nxfilter (www.nxfilter.org). Jahastech has done some wonderful work with this product. It has most of the features offered with the proxy filters, but since it’s all done with DNS there is no problem with SSL, as well as no configuration needed on the clients. Jahastech has done a great job and I think this product could benefit a lot of families. Of course, since it is DNS filtering there are a few features that you loose. First, you can’t filter based on key words. So, you either allow a site, or you block a site, but you can’t filter part of a site (or stop the kids from searching about bypassing DNS filtering). Relying on SafeSearch is our only option here. Second, if the kids can enter the IP address directly, of course the DNS filter won’t help. I’m not sure the kids can really use direct IP addresses. I tried that with a few websites and it didn’t work very well. However, I didn’t spend much time on this, so it needs more testing. If it is a problem there might be an option to use pfblocker somehow (it's just an idea floating around in my head, I haven't thought it through). These are the only deficiencies I currently see verses the proxy filtering. Since this is a DNS forwarded running locally, I have a firewall rule to block port 53 requests except those that come from nxfilter, so everyone is locked into the filter. Since there was no configuration on the client side, it was a joy to see it “just work”.
As a proof of concept, I installed nxfilter on pfsense (this way it replaces DNSmasq). I haven’t done any of the work to package this for pfsense, right now I just did the work to prove nxfilter can run on the pfsense box. The biggest thing that stopped me from moving any further than a simple proof of concept is the fact that nxfilter is a java application. I’m not sure it’s a good idea to run java on my production firewall in the first place, however, since pfsense 2.1.5 is using FreeBSD 8.3, the only java package I could find was a VERY old package. If running Java on the firewall makes me a little nervous, running an old version is a non-starter. If this goes anywhere, getting a current version of Java will be a requirement (and having someway to update it). Maybe, when pfSense 2.2 is released and we have access to FreeBSD 10.1 it will make more sense to look into running nxfilter as the DNS forwarded on the pfSense box.
If anyone is interested in this, below are the steps I followed to install this.
- turn off DNSmasq or any other DNS server you are running on the pfSense box.
- Change the pfSense Web UI to use port 444 (or any other port you choose). Nxfilter needs port 80 on the box so it can show the block web page without any setup on the client side.
System/Advanced – TCP Port
Also, turn on “Disable webConfigurator redirect rule”
- Install Java from the FreeBSD packages
pkg_add –r http://ftp-archive.freebsd.org/pub/FreeBSD-Archive/ports/i386/packages-8.3-release/java/openjdk-7.2.13.tbz
- After the packages are loaded test java by running ‘java –version’
- Download the code in the zip file from nxfilter.org
- Create the nxfilter installation directory
- copy the nxfilter.zip file to the /nxfilter directory
- Extract the nxfilter application
unzip – tar zxvf nxfilter-2.5.3.zip
- Change the permission on the scripts so they are executable
chmod +x *.sh
- Bind nxfilter to only the LAN interface (you don’t want this on the WAN interface)
You can bind NxFilter to a specific IP address using 'listen_ip' parameter in '/nxfilter/conf/cfg.properties' file. If you set it to '0.0.0.0' NxFilter will listen to all the IP addresses of the system but if you set it to a specific IP address NxFilter will listen to the specified IP address.
From here you can use the scripts in /nxfilter/bin to ‘startup.sh –d’ and ‘shutdown.sh’ the nxfilter application for testing.
Start nxfilter at boot:
This script will need more work, but for now I used a very simple script so nxfilter will start and stop automatically as pfsense boots, and shutdown.
a. Create a file /usr/local/etc/rc.d/nxfilter.sh
b. The contents of the file should be:
case $1 in
c. After the script file is created change the permission so it’s executable.
Chmod 777 nxfilter.sh
After this nxfilter worked really well for me. I really liked the authentication feature and setting up different policies for different groups. I think this has potential. Hopefully this information is useful for others that are trying to solve the same problem.
I've created what I believe is the ultimate home filtering solution. It is a customized version of pfSense that I've rebranded as "Integrity Home Router". On my public dropbox I have install scripts, a demo virtual machine and the beginnings of a manual. The manual is a little out of date (I've further simplified the screens and reorganized some things) and not 100% complete, but if you want to see what it does you can look here… https://www.dropbox.com/sh/y3qoeiyxnvxl8c1/AAAn5sXHs02PvKyTz-3p34PAa?dl=0
BTW, I see no reason to use a DNS filtering solution locally vs. something like OpenDNS. However, I did create a DNS block page and allow use of the built-in DNS forwarder to block sites (the block redirects to a custom block page similar to OpenDNS).
Key features of Integrity…
Forces DNS filtering via OpenDNS or Norton
Local DNS blocking and redirect to a block page
Redirect to Dansguardian for content filtering
Custom filter bypassing with password (pfSense admin or setup other ID's) for time period (complete removes filter for the source IP)
Grouping of MAC addresses to control whether devices are filtered (or not) and time restrict with custom, simple admin screens
MAC checking to make sure no one hijacks an unfiltered MAC
DNS overrides for Google to force non-SSL search and Auto update of IP addresses
DNS blocks for other encrypted search engines
The limitations - I've created a bunch of custom screens that assume a very specific setup. The primary constraint is a single LAN interface and single WAN interface. However, all of the original pfSense screens are still available and could be used to alter the config.
rjcrowder, I downloaded your documentation. I think you have done a good job (you are very good at writing documentation). For an average family your solution will help them a lot (most families have no filtering at all). However, I do have a few comments/recommendations for your solution. I hope you accept these as discussion items, not criticism of the work you’ve done to this point… I think the best way to explain my comments to you is to give you the history of my filtering exploits. There will be a lot below so I hope you stay with me and read it.
I started filtering by using OpenDNS. It is a good solution and fulfilled my feeds for many years. However, as the years progressed, my needs have grown beyond a solution OpenDNS alone could handle. Today my family has many different devices that all use the Internet in some way. Everything from the Wii, PS4, tablets, Roku streamers, picture frames, smart light bulbs, etc… It’s amazing the number of computers a family can attach to their network these days. However, even though we have all of these devices, we don’t have a device per person, these devices are all shared. Of course, each person has different requirements when they use the device. For example, when my spouse uses the table one set of sites should be allowed, but a different set of sites for the 16 year old, another set of sites for the 11 year old, and another set of sites for the 5 year old. I started assigning different DNS servers to different devices (for example the kids would use OpenDNS filtering, but my machine would use Norton DNS), but that only got me so far. With that solution the tablet is locked to a certain level for all of us, verses the laptop, verses the PS4, etc. Of course, everyone figured out quickly that if they just grabbed mom’s laptop they could get to everything. Also, bypassing the security of this by just manually setting the IP address of mom’s laptop was WAY too easy (some devices have no local security at all). I needed something else. That’s why I started looking at the Proxy filters (I already used pfsense for my firewall, so it was a logical next step). The proxy filters actually solved a lot of problems. However, as we all know, the weakness of the proxy is SSL. With more and more sites moving to SSL the proxy server became less and less effective. The new SSLbump feature helps, but it isn’t very clean. Before SSL I just used the transparent proxy so it just worked. However, with SSLbump setup becomes a problem to manage on each device (or, doing transparent with SSL bump can cause even more issues). Also, since it is doing a man in the middle attack, there are a lot of cases when things didn’t work quite right (as well as the security issue of breaking SSL). Again, I needed something better…
That’s when I discovered nxfilter. Nxfilter is a DNS filter (it does have some proxy capabilities, but I haven’t explored those features). However, the big feature that makes my life easier is the per user/per device rule sets along with the authentication capabilities. I can setup different rules for each person and even set different rules per device (so my 15 year old can look at one set of web sites when using a device on the living room TV – in front of everyone. But, a different set of web sites when on the tablet). This means that when my spouse grabs the tablet they have one set of sites, verses the 15 year old, verses the 5 year old, even though they are sharing the same tablet. Another feature I love is the reporting with nxfilter. I can get a list of all DNS queries by person/device. Combine this with the logs in pfsense and there isn’t anything that happens on the network that I don’t know about. I would highly recommend you check out nxfilter. I think you would be amazed at it’s features and would be a great addition to your project.
Now, as I said in my first post, nxfilter does have a weakness and that’s java. Currently I am using nxfilter, but I’m not running it on my pfsense box. I setup a small machine running Tiny Core OS just for it. With Tiny Core I can download the linux version of java straight from Oracle so it’s easy to stay up with the java security patches. Plus this machine sits behind the firewall, so the odds of someone attacking java on it are remote. I’m not 100% happy with this solution because it means another box that I have to maintain, plus it feels like a waste to run a whole machine just for a DNS forwarder. That’s why I explored the possibility of running nxfilter on the pfsense firewall. It does run, but as I stated above, I’m not comfortable with it so I’m going to just run it with Tiny Core for now. Once a solution is found to update java on the pfsense box, I would be highly interested in moving nxfilter to it. However, until that time, Tiny Core is doing a great job for me.
One other suggestion I have for your project (other than looking at nxfilter), is to look at adding pfblocker to your pfsense firewall. This is a WONDERFUL package. There are some countries that my computers just don’t need to connect to. Also, I really like some of the other lists people are providing to add additional security. The lists I use are ZeusIPBlock, CIArmy, malc0de, SpamhausDROP, DShield, and TOR&Proxy from I-Blocklist.com). If I’m going to all this trouble to setup networking filtering, I don’t need a TOR or Proxy service to circumvent me. There is a lot of information available for pfblocker so you can decide what would benefit your users, but it is a package I think would be a great addition to your project.
So, that’s my thoughts and experience with filtering. I'm not an expert regarding filtering, so I'm sure there are things I'm missing. But, so far this package is working well for me, and I think it's helping my family. It just works and I don't get a lot of "support calls", so that alone is valuable (with the SSLbump feature I got a lot of "support calls"). I posted my work about running nxfilter on pfsense incase someone decided to pick up the project someday. Also, I hoped to get a few comments from people regarding running java on the pfsense box. I know there are experts in this forum that would know a lot more about that subject then me. Lastly, if it isn’t a huge security concern then maybe someone with knowledge of building the java packages on FreeBSD 8.3 would take an interest and provide an updated package. However, if none of that happens that’s ok. I am happy with my setup right now. If this information is just useful to others in anyway, that would be ok too…
First of all… thanks for spending the time to provide such detailed feedback.
I think the most pertinent point you make - which I hadn't considered - is the ability to do DNS filtering by device or groups of devices. Integrity will allow you to create create groups that can be configured to go to Dans or not... but of course Dans is not configured to filter or blacklist SSL sites. As you know, Dans can do blacklisting without man-in-the-middle, but you can't transparently redirect SSL to it (requires either explicit proxy config or wpad file which is a pain).
The bottom line... I'll take a look at NXfilter... I can see the advantage. I'm not sure I'm really ready to give up on dynamic content filtering for non-encrypted sites though... a blacklist based blocking mechanism will never be as good as a solution that also includes some type of dynamic filtering.
Thanks again for the feedback though... I'll take a look at nxfilter. If you're interested, I updated the manual to have screenshots of the new menus. Also added a bunch of screenshots.
I will take a look at your updated documentation. You’ve put a lot of time into your product and I think it will be great for a lot of families (giving them a real firewall instead of just using the NAT device they get from their ISP is a great first step). Putting all of this together can be complex so it’s great that you are making it easy for people.
A few points I want to clarify. First, I don’t think you have to give up on dynamic content filtering. There is some value there, even if I don’t use it. Since nxfilter is a DNS forwarding service, it could live beside, and compliment, DansGuardian nicely. Instead of using DNSmasq for your DNS, you would just use nxfilter and it adds to your functionality (there is no need to take away things that you have already built). Also, as a forwarding service it relies on a DNS server so you can continue to use Norton DNS, or OpenDNS, so nxfilter would truly just compliment everything you are already doing. I have nxfilter using the Norton DNS servers, so it’s just providing a more granular filter on top of the base filtering Norton is doing.
Second, I want to make sure you understand the biggest feature that I use in nxfilter… Yes, I do DNS filtering by device, or groups of devices. However, more importantly I also do filtering by user. This is the feature that has really sold me on nxfilter. To better explain this I’ll give you a use case. We have a tablet that is shared by the whole family (it lives in the living room). So, I have the IP of that tablet set to my default policy (this is the policy appropriate for the 5 year old). Now, when my 16 year old wants to use the tablet they would see the block page for a site, but they can enter their username and password on the block page and now their policy becomes active and they can browse sites appropriate for them. I think this is a great feature and has allowed filtering to work well for my family. We don’t have enough money to give everyone their own device, so sharing devices is a reality we have to live with in my family (even if you did have enough money, I’m not sure what policy you would assign to devices connected to the TV).
After you evaluate nxfilter I would love to hear your thoughts. I’m not an expert on filtering so there is a good chance I’m missing something. I can only compare it to the other solutions I’ve tried, in the context of my family. Getting the opinion of someone else looking at it from a different perspective is always valuable, and a great opportunity to learn something.
Wow nxfilter.org got a face lift!! Its not left in the 90s anymore…
I played with nxfilter a year or so ago. I was able to get it to work somewhat. I used Arch Linux on a RaspberryPI..
For the most part it blocked sites and reporting was great while testing it. But I couldn't get the block page to display, would get page can not be found...
Maybe I'll re-visit this down the road and see what has change.
Yesterday I performed the setup and I have to say nxfilter is running pretty well on my PFSense box. The instructions above are outdated. This is how the installation is performed (on latest PFSense version)
General > Advanced
- Disable HSTS
- Disable WebConfig redirect
- TCP port
- Disable DNS Resolver
- Change PFSense Port
#FreeBSD 11 repos is found on
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/wget-1.19.2.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/alsa-lib-1.1.2.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/freetype2-2.8_1.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/fontconfig-2.12.1,1.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/xproto-7.0.31.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libfontenc-1.1.3_1.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/mkfontscale-1.1.2.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/mkfontdir-1.0.7.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/dejavu-2.37.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/giflib-5.1.4.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/java-zoneinfo-2017.c.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/javavmwrapper-2.6.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libX11-1.6.5,1.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/kbproto-1.0.7.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libXau-1.0.8_3.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libXdmcp-1.1.2.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libxcb-1.12_2.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libpthread-stubs-0.4.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/xextproto-7.3.0.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libXext-1.3.3_1,1.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/fixesproto-5.0.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libXfixes-5.0.3.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/inputproto-2.3.2.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libXi-1.7.9,1.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/renderproto-0.11.1.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libXrender-0.9.10.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libICE-1.0.9_1,1.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libSM-1.2.2_3,1.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libXt-1.1.5,1.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/recordproto-1.14.2.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/libXtst-1.2.3.txz
pkg add http://pkg.freebsd.org/freebsd:11:x86:64/latest/All/openjdk8-8.152.16_3.txz
tar xzvf nxfilter-4.2.1-p1.zip
chmod +x *.sh
- configuration -
listen_ip = xxx.xxx.xxx.xxx
http_port = 80
https_port = 4443
start_tomcat = 1
cluster_mode = 0
blacklist_type = 5
Then you can fire up your config with startup.sh -d or use the script in this post.