[ previous ] [ next ] [ threads ]
 From:  Manuel Kasper <mk at neon1 dot net>
 To:  m0n0wall dash dev at lists dot m0n0 dot ch
 Cc:  mm2001 at pobox dot com
 Subject:  Captive portal support!
 Date:  Sun, 09 May 2004 22:15:08 +0200
Hi guys,

since the weather was so bad this weekend in Switzerland, I got bored
and decided to give the captive portal issue a stab. I'm happy to
announce that m0n0wall 1.1b7 is now available and includes captive
portal support that fulfills all of the criteria given on
<http://socalfreenet.org/book/view/58>. It works quite well already,
but there may be some bugs left of course.

You can get it at:

net45xx: http://m0n0.ch/wall/download.php?file=net45xx-1.1b7.img
net48xx: http://m0n0.ch/wall/download.php?file=net48xx-1.1b7.img
generic-pc: http://m0n0.ch/wall/download.php?file=generic-pc-1.1b7.img
cdrom: http://m0n0.ch/wall/download.php?file=cdrom-1.1b7.iso
wrap: http://m0n0.ch/wall/download.php?file=wrap-1.1b7.img

I'm eager to hear your comments!

A few notes on the implementation...

- true to the spirit of m0n0wall, the captive portal has been done
(almost ;) without any C coding - it's all in PHP, and I tried to
keep it as simple as possible

- the captive portal can be used on LAN or an optional interface and
uses ipfw2 (with some clever rule/set number juggling to allow it to
coexist with the traffic shaper). MAC address filtering is in place
as well

- unknown/new clients are redirected (by means of an ipfw fwd rule)
to a local instance of mini_httpd (port 8000)

- the DNS forwarder must be running for DNS lookups by
unauthenticated clients to work properly

- I have hacked mini_httpd to add a new option that makes it ignore
the actual path requested by the client. Instead it always executes
the same "CGI" script (a PHP script in this case) and passes the
original path to the script in an environment variable

- the PHP script shows the AUP page, and if the user clicks the
agree/continue button, ipfw rules to permit his IP and MAC address
are added and the time/ipfw rule number/IP/MAC is recorded in a
simple text file database. Then, the user is redirected to the page
(host/path) that (s)he originally requested (seems to work fine for
me with Mac OS X and Windows).

- PHP is invoked every minute (by means of a simple "minicron"
program that I wrote in a jiffy) to check for expired clients. It
deletes any that were found (ipfw rules are removed and the database
entry is deleted).

- The captive portal can be enabled/configured via the webGUI. The
HTML for the body of the AUP page can be entered literally; the
"continue/agree" button is added automatically (the label can be

- A separate status page shows all the active clients (with IP
address, MAC address and session start time) and allows for
individual clients to be disconnected (of course they can reconnect
immediately by accepting the AUP again)

- Caveat: because ipfw2 doesn't allow one to find out whether it was
called from ether_demux or bdg_forward in the ruleset, no interfaces
can be bridged while the captive portal is enabled. I think this is a
small tradeoff.

- If some day we can get a concurrency/connection limit in
mini_httpd, that would be nice (for some basic DoS protection).

- The DHCP default/max lease time should be greater than the captive
portal timeout to prevent problems when an IP address is assigned to
a new client before the captive portal rules have expired.

- The captive portal rules expire after the timeout has elapsed,
regardless of client activity (this is not an idle timeout).


- Manuel