Using Pi-Hole to implement DNS Captive Portal
Motivation
I recognize there are a few reasons to want a captive portal. I received an Amazon Echo Show which I'd like to customize to show my own landing page (I want to put a to-do list, upcoming nearby public transit times, etc). Someone on redit showed that the Echo Show works nicely with captive portal. If I can design my own web page and use it as the captive portal landing page, I think I'll have free reign on the device's displays. It has the happy side effect of disabling all amazon tracking.
Background
Captive portal can be implemented via HTTP redirects or by DNS redirects. With the tools at my disposal, only DNS redirection works on my home network. I thought I was going to have to write my own feature to implement captive portal on pi-hole, since I couldn't find any articles on the web about it. (That's the main motivation for writing this little blog post, in case others have similar desires). I spent a few days reading through the FTL code, debugged a bit, and was just getting ready to make some changes when a few out-of-the-box configuration settings I'd seen floating around fell into place and I realized no new features would be required.
Configuration
The missing piece for me was the Groups section, which I'd somehow never noticed. I needed two behaviors (an inescapable captive portal and normal ad-blocking DNS), and splitting my network into groups was precisely the tool for this task. Towards this end, I created a CaptivePortal group.
The next piece is IP blocking (where a blocked domain responds with the Pi-Hole's IP address). I prefer the NULL for general blocking, so I used the regex blocking extension to craft the following rule and apply it only to the CaptivePortal group: *;reply=IP
(if the web page is hosted on the pi-hole machine) or *;reply=W.X.Y.Z
for an arbitrary captive portal page IP. I'm not at home and can't test on the Echo Show yet, but I think it'll work.
The webpage itself isn't written yet. I'm thinking to hijack the pi-hole index.html
page ("Did you mean to go to the admin panel?"), since the IP redirect won't include a route. In the same vein, there might be some complexity with getting the index page to show up, as I have no idea what route (if any) will be requested by the operating system when it detects a captive portal.
Caveats
DNS captive portal has some limits. The Echo Show runs android, if I'm not mistaken, and so it ought to be performing the expected HTTP lookups (which should trigger the built-in captive portal behavior). If it doesn't, this won't work so well: when I tried using it from my computer, I ran into some problems mentioned in the linked page. Specifically, sites that use HTTPS will show the error page (not great) and require manual intervention to continue due to certificate issues (since the requested domain and the returned domain differ). Sites that enable HTST will completely fail to load. Recall that, since this is DNS redirection and not HTTP redirection, the browser still thinks it's loading the requested site.
Conclusion
I think implementing captive portal via HTTP redirect would be better. The DNS hijacking solution means that mismatches in the expected and actual website can trigger security warnings (for good reason). I'll update this post once I can test with my device, and also would also be curious to hear about other solutions (for example, that might avoid the mentioned HTST and HTTPS issues) to the same problem.