danrulz98
Posts: 24
Joined: Sun May 24, 2015 7:35 pm

The Trollspot - A battery powered WiFi Captive Portal

Mon Oct 03, 2016 1:27 am

Hello all!
My posts don't get a whole lot of replies, but I hope they are helpful to people.
Again, I wanted to do what seemed on the surface to be a simple project, but no one tutorial got me to where I wanted to be.
... on top of there being a bunch of other issues that I'll get into.

I’m basing a lot of this off of a previous thread I did: viewtopic.php?t=152490

And making a few improvements.

What I wanted:
A wireless access point that, when connected, would direct you to a page with some helpful information, a guestbook, a web based group chat, and a link that says "Access the internet" that full screen autoplays a certain Rick Astley music video.
This ran form a USB power bank in my backpack as I wandered around a convention. 4 people signed the guestbook, but I never saw anyone in the web chat. I'll discuss the nature of wireless and antennas in a bit...

The con in question did not have free wifi. The wifi provided by the convention center was $12 for "guest access" (3Mb!) for the day or $50 for "Business access" (10Mb). So an open access point that looks like it might take you to the internet is tempting.

Where to start? Well, what guides I could find that did kind of similar things. First off, we need to get our Pi all set up and installed.
What Pi to use though? Hmm... Well, we can look at the power consumption and go from there: https://www.raspberrypi.org/help/faqs/#powerReqs

We can see that a Pi A will use the least power, but we also have to keep in mind...
https://www.raspberrypi.org/magpi/raspb ... enchmarks/

The A+ is just painfully underpowered for what we're going to be asking it to do. Could you do it? Yes. It just won't be that great of a user experience. I just don’t really like using anything less than a Pi 2, but that’s just me.

So I went with a Pi 2B. A nice balance between power consumption and horsepower. I'm using a 16,000 mAh USB power bank to drive it and I calculated that I should get a minimum of something around 30 hours out of it. This is absurd, and turned out to be a pretty conservative estimate, as being around the con for 8 hours didn't even bring this beast of a battery down to 75%. Note: I did not buy the power bank for this project, it's one that I had that I use elsewhere on a regular basis. You could use something MUCH smaller.

As of September 2016: There's some things that are going kinda screwy with Raspian, I had to figure out some ways around it. I'll discuss how things should work first, then my workarounds. Further messing about showed a Pi 3 to be a bit more reliable, so I think that's where the development focus of Raspian is at the moment. Nothing official, just observations by me.

Once you've picked your Pi, install Raspian in your preferred way. We want to set up our local keymap and have it boot to the command line. We'll be running headless so a graphical interface is not needed. I also set the GPU memory to a minimum so we can give our applications the most RAM. We'll also want SSH enabled. There's lots of tutorials on this if you're not already familiar with setting up Raspian.

Pro tip: At this point, SSH into your Pi so you can copy and paste stuff from this thread into the terminal.

Once SSH'd in, become root

Code: Select all

sudo -i
Then, we'll update everything.

Code: Select all

apt-get update & apt-get upgrade -y & apt-get dist-upgrade -y
After this, reboot and become root again.

And we'll get everything we need installed

Code: Select all

apt-get install php5-common php5-cgi php5 lighttpd hostapd  dnsmasq ngircd
Perhaps some explanation here:
* php5 stuff is all php modules we’ll need for our web stuff.
* lighttpd is going to be our web server
* hostapd is going to give us our access point
* dnsmasq gives us DNS and DHCP servers
* ngircd is the backend of our web chat. However, this is pretty optional, as you’ll see in a bit.

Lighttpd Setup

We're going to get started with Lighttpd since it's one of the core components of this, and something that we want to test before we mess around with the networking.

We'll get some group and user permissions rolling, as per previous threads I've made:

Code: Select all

chown www-data:www-data /var/www
chmod 775 /var/www
usermod -a -G www-data pi
And install PHP for Lighttpd

Code: Select all

lighty-enable-mod fastcgi-php 
Make it work!

Code: Select all

service lighttpd force-reload 
We'll give Lighttpd something to serve other than what it came with

Code: Select all

cd /var/www/html
rm -rf index.lighttpd.html 
Web Page Setup

Code: Select all

nano index.html
I’m not going to get super into HTML, but just a basic page will work:

Code: Select all

<html>
<head><title>The Wandering Guest</title>
</head>
<body>
<a href=”index.html”>Home</a>
<br />
<a href=”comment.php”>Guestbook</a>
<br />
<a href=”cgi-bin/irc/irc.cgi”>Chat</a>
<br />
<a href=”internet.html”>Access the Internet</a>
<br />
Welcome to the Wandering Guest System. Please choose a link above
</body>
</html>
I populated this page with a simple HTML template. I don't think I have the ability to re-distribute it, so I'll just link it: http://www.quackit.com/html/templates/d ... t_menu.cfm

I went to the Con's website and saved a bunch of the pages as PDF files using Google Chrome's "print to PDF" function, so I could serve up offline versions of the con map, panel schedule, and so on. Only to later realize that the con started using a Guidebook-made mobile app that did this a lot better than printed PDFs.

You’ll want your landing page to link to all of the other pages you create, and your web chat. The other pages you create should all link together and use the same style, so it all looks like one website.

Guestbook

The second part of this was to be a guestbook. I wanted something drop dead simple, didn't care about XSS or spamming or any of that, and didn't want to use a database. Turns out, easier said than done, as even the most basic scripts want to use a database and implement an admin page and logins and AAAHRG no.
Then I found this: http://www.sitepoint.com/forums/showthr ... tbook-Code
and that works fine.
Where it says "header("Location: comment.php");" the "comment.php" part needs to match whatever your original filename is. For me, I made this guestbook.php. On the display page (which is this comment.php file), I removed the part that displays a commenter's email address.
Any files that contain php code need to be saved as a .php file. Should go without saying, but otherwise your code will not be executed.
You should be able to put the code into your web template that you use for the other pages.

RickRoll’d

Now, for one of the more simpler and more hilarious parts: the trolling internet access.
But first, a caveat: MacOS and iOS treat captive portals with a special minimalized browser rather than prompting you to open your default browser (Windows) or the system browser (Android). This minimalized browser does not support HTML5 <video>. If you have a solution around this, please let me know and I’ll update this.

We’ll need to (questionably) legally obtain a copy of the famed music video from Mr. Astley. I used a service called “keepvid” you can find that on google. But we’ll need a .webm format and a .mp4 format video.
Get those into your html folder and make an html file with the following code:

Code: Select all

<html>
<head><title>RickRoll'd</title></head>
<body>
<video style="width: 100%; height: 100%" autoplay loop>
        <source src="upload.webm" type="video/webm">
  <source src="upload.mp4" type="video/mp4">
</video>
</body>
</html>
Group Web Chat

Next, possibly one of the more challenging bits, getting a group web chat. Now, there's lots of scripts out there for doing this. Most of them were just overkill on the complexity, offering user accounts, email verification, databases, and everything else. I tried to use PHPFreeChat which looked really promising, but I just couldn't get it to work. What I ended up doing was running NGIRCD in combination with CGI:IRC. Which a lot of folks would look to that as being massively overkill, which it is. Luckilly, NGIRCD was pretty easy to deal with, but CGI:IRC is in that sweet spot of a software's life where it works on everything, is used by loads of people, but hasn't been updated in ages and is generally regarded not being great. I don't mind it personally, it works well enough. I could have used KiwiIRC and in the end I kind of wish I did since it's backend daemon requires some stuff that I didn't want to do but ended up having to do anyway... It was a mess.
But back to business.
If you can get PHPFreeChat to work just use that and ignore this. More power to ya.

NGIRCd

First let's configure NGIRCD so we have something to connect to.

Code: Select all

nano /etc/ngircd/ngircd.conf
It should look something like this

Code: Select all

[Global]
        # The [Global] section of this file is used to define the main
        # configuration of the server, like the server name and the ports
        # on which the server should be listening.
        # These settings depend on your personal preferences, so you should
        # make sure that they correspond to your installation and setup!

        # Server name in the IRC network, must contain at least one dot
        # (".") and be unique in the IRC network. Required!
        Name = TheWandering.Guest

        # Information about the server and the administrator, used by the
        # ADMIN command. Not required by server but by RFC!
        AdminInfo1 = Debian User
        AdminInfo2 = Debian City
        AdminEMail = [email protected]

        # Info text of the server. This will be shown by WHOIS and
        # LINKS requests for example.
        Info = Yet another IRC Server running on Debian GNU/Linux

        # Comma separated list of IP addresses on which the server should
        # listen. Default values are:
        # "0.0.0.0" or (if compiled with IPv6 support) "::,0.0.0.0"
        # so the server listens on all IP addresses of the system by default.
        ;Listen = 127.0.0.1,192.168.0.1

        # Text file with the "message of the day" (MOTD). This message will
        # be shown to all users connecting to the server:
        MotdFile = /etc/ngircd/ngircd.motd

        # A simple Phrase (<256 chars) if you don't want to use a motd file.
        ;MotdPhrase = "Hello. This is the Debian default MOTD sentence"

        # The name of the IRC network to which this server belongs. This name
        # is optional, should only contain ASCII characters, and can't contain
        # spaces. It is only used to inform clients. The default is empty,
        # so no network name is announced to clients.
        ;Network = aIRCnetwork

        # Global password for all users needed to connect to the server.
        # (Default: not set)
        ;Password = wealllikedebian

        # This tells ngIRCd to write its current process ID to a file.
        # Note that the pidfile is written AFTER chroot and switching the
        # user ID, e.g. the directory the pidfile resides in must be
        # writable by the ngIRCd user and exist in the chroot directory.
        # Keep this setting in sync with PIDFILE in /etc/init.d/ngircd
        PidFile = /var/run/ngircd/ngircd.pid

        # Ports on which the server should listen. There may be more than
        # one port, separated with ",". (Default: 6667)
        ;Ports = 6667, 6668, 6669

        # Group ID under which the ngIRCd should run; you can use the name
        # of the group or the numerical ID. ATTENTION: For this to work the
        # server must have been started with root privileges!
        # Keep this setting in sync with DAEMONUSER in /etc/init.d/ngircd
        ServerGID = irc

        # User ID under which the server should run; you can use the name
        # of the user or the numerical ID. ATTENTION: For this to work the
        # server must have been started with root privileges! In addition,
        # the configuration and MOTD files must be readable by this user,
        # otherwise RESTART and REHASH won't work!
        # Keep this setting in sync with DAEMONUSER in /etc/init.d/ngircd
        ServerUID = irc

[Limits]
        # Define some limits and timeouts for this ngIRCd instance. Default
        # values should be safe, but it is wise to double-check :-)

        # The server tries every <ConnectRetry> seconds to establish a link
        # to not yet (or no longer) connected servers.
        ConnectRetry = 60

        # Number of seconds after which the whole daemon should shutdown when
        # no connections are left active after handling at least one client
        # (0: never, which is the default).
        # This can be useful for testing or when ngIRCd is started using
        # "socket activation" with systemd(8), for example.
        ;IdleTimeout = 0

        # Maximum number of simultaneous in- and outbound connections the
        # server is allowed to accept (0: unlimited):
        MaxConnections = 500

        # Maximum number of simultaneous connections from a single IP address
        # the server will accept (0: unlimited):
        MaxConnectionsIP = 0

        # Maximum number of channels a user can be member of (0: no limit):
        MaxJoins = 10

        # Maximum length of an user nickname (Default: 9, as in RFC 2812).
        # Please note that all servers in an IRC network MUST use the same
        # maximum nickname length!
        ;MaxNickLength = 9

        # Maximum number of channels returned in response to a /list
        # command (0: unlimited):
        ;MaxListSize = 100

        # After <PingTimeout> seconds of inactivity the server will send a
        # PING to the peer to test whether it is alive or not.
        PingTimeout = 120

        # If a client fails to answer a PING with a PONG within <PongTimeout>
        # seconds, it will be disconnected by the server.
        PongTimeout = 20

[Options]
        # Optional features and configuration options to further tweak the
        # behavior of ngIRCd. If you want to get started quickly, you most
        # probably don't have to make changes here -- they are all optional.

        # List of allowed channel types (channel prefixes) for newly created
        # channels on the local server. By default, all supported channel
        # types are allowed. Set this variable to the empty string to disallow
        # creation of new channels by local clients at all.
        ;AllowedChannelTypes = #&+

        # Are remote IRC operators allowed to control this server, e.g.
        # use commands like CONNECT, SQUIT, DIE, ...?
        ;AllowRemoteOper = no

        # A directory to chroot in when everything is initialized. It
        # doesn't need to be populated if ngIRCd is compiled as a static
        # binary. By default ngIRCd won't use the chroot() feature.
        # ATTENTION: For this to work the server must have been started
        # with root privileges!
        ;ChrootDir = /var/empty

        # Set this hostname for every client instead of the real one.
        # Use %x to add the hashed value of the original hostname.
        ;CloakHost = cloaked.host

        # Use this hostname for hostname cloaking on clients that have the
        # user mode "+x" set, instead of the name of the server.
        # Use %x to add the hashed value of the original hostname.
        ;CloakHostModeX = cloaked.user

        # The Salt for cloaked hostname hashing. When undefined a random
        # hash is generated after each server start.
        ;CloakHostSalt = abcdefghijklmnopqrstuvwxyz

        # Set every clients' user name to their nickname
        ;CloakUserToNick = yes

        # Try to connect to other IRC servers using IPv4 and IPv6, if possible.
        ;ConnectIPv6 = yes
        ;ConnectIPv4 = yes

        # Default user mode(s) to set on new local clients. Please note that
        # only modes can be set that the client could set using regular MODE
        # commands, you can't set "a" (away) for example! Default: none.
        ;DefaultUserModes = i

        # Do DNS lookups when a client connects to the server.
        ;DNS = yes

        # Do IDENT lookups if ngIRCd has been compiled with support for it.
        # Users identified using IDENT are registered without the "~" character
        # prepended to their user name.
        ;Ident = yes

        # Directory containing configuration snippets (*.conf), that should
        # be read in after parsing this configuration file.
        ;IncludeDir = /etc/ngircd/conf.d

        # Enhance user privacy slightly (useful for IRC server on TOR or I2P)
        # by censoring some information like idle time, logon time, etc.
        ;MorePrivacy = no

        # Normally ngIRCd doesn't send any messages to a client until it is
        # registered. Enable this option to let the daemon send "NOTICE AUTH"
        # messages to clients while connecting.
        ;NoticeAuth = no

        # Should IRC Operators be allowed to use the MODE command even if
        # they are not(!) channel-operators?
        OperCanUseMode = yes

        # Should IRC Operators get AutoOp (+o) in persistent (+P) channels?
        ;OperChanPAutoOp = yes

        # Mask IRC Operator mode requests as if they were coming from the
        # server? (This is a compatibility hack for ircd-irc2 servers)
        ;OperServerMode = no

        # Use PAM if ngIRCd has been compiled with support for it.
        # Users identified using PAM are registered without the "~" character
        # prepended to their user name.
        PAM = no

        # When PAM is enabled, all clients are required to be authenticated
        # using PAM; connecting to the server without successful PAM
        # authentication isn't possible.
        # If this option is set, clients not sending a password are still
        # allowed to connect: they won't become "identified" and keep the "~"
        # character prepended to their supplied user name.
        # Please note: To make some use of this behavior, it most probably
        # isn't useful to enable "Ident", "PAM" and "PAMIsOptional" at the
        # same time, because you wouldn't be able to distinguish between
        # Ident'ified and PAM-authenticated users: both don't have a "~"
        # character prepended to their respective user names!
        ;PAMIsOptional = no

        # Let ngIRCd send an "authentication PING" when a new client connects,
        # and register this client only after receiving the corresponding
        # "PONG" reply.
        ;RequireAuthPing = no

        # Silently drop all incoming CTCP requests.
        ;ScrubCTCP = no

        # Syslog "facility" to which ngIRCd should send log messages.
        # Possible values are system dependent, but most probably auth, daemon,
        # user and local1 through local7 are possible values; see syslog(3).
        # Default is "local5" for historical reasons, you probably want to
        # change this to "daemon", for example.
        SyslogFacility = local1

        # Password required for using the WEBIRC command used by some
        # Web-to-IRC gateways. If not set/empty, the WEBIRC command can't
        # be used. (Default: not set)
        ;WebircPassword = xyz

[SSL]
        # SSL-related configuration options.

        # SSL Server Key Certificate
        ;CertFile = /etc/ssl/certs/server.crt

        # Select cipher suites allowed for SSL/TLS connections. This defaults
        # to HIGH:!aNULL:@STRENGTH (OpenSSL) or SECURE128 (GnuTLS).
        # See 'man 1ssl ciphers' (OpenSSL) or 'man 3 gnutls_priority_init'
        # (GnuTLS) for details.
        # For OpenSSL:
        ;CipherList = HIGH:!aNULL:@STRENGTH:!SSLv3
        # For GnuTLS (this Debian package was linked against GnuTLS):
        CipherList = SECURE128:-VERS-SSL3.0

        # Diffie-Hellman parameters
        ;DHFile = /etc/ngircd/dhparams.pem

        # SSL Server Key
        ;KeyFile = /etc/ssl/private/server.key

        # password to decrypt SSLKeyFile (OpenSSL only)
        # Note that this Debian package is linked against GnuTLS so this
        # option has no effect.
        ;KeyFilePassword = secret

        # Additional Listen Ports that expect SSL/TLS encrypted connections
        ;Ports = 6697, 9999

[Operator]
        # [Operator] sections are used to define IRC Operators. There may be
        # more than one [Operator] block, one for each local operator.

        # ID of the operator (may be different of the nickname)
        ;Name = TheOper

        # Password of the IRC operator
        ;Password = ThePwd

        # Optional Mask from which /OPER will be accepted
        ;Mask = *[email protected]

[Operator]
        # More [Operator] sections, if you like ...

[Server]
        # Other servers are configured in [Server] sections. If you
        # configure a port for the connection, then this ngircd tries to
        # connect to to the other server on the given port; if not it waits
        # for the other server to connect.
        # There may be more than one server block, one for each server.
        #
        # Server Groups:
        # The ngIRCd allows "server groups": You can assign an "ID" to every
        # server with which you want this ngIRCd to link. If a server of a
        # group won't answer, the ngIRCd tries to connect to the next server
        # in the given group. But the ngircd never tries to connect to two
        # servers with the same group ID.

        # IRC name of the remote server, must match the "Name" variable in
        # the [Global] section of the other server (when using ngIRCd).
        ;Name = irc2.example.net

        # Internet host name or IP address of the peer (only required when
        # this server should establish the connection).
        ;Host = connect-to-host.example.net

        # IP address to use as _source_ address for the connection. if
        # unspecified, ngircd will let the operating system pick an address.
        ;Bind = 10.0.0.1

        # Port of the server to which the ngIRCd should connect. If you
        # assign no port the ngIRCd waits for incoming connections.
        ;Port = 6667

        # Own password for the connection. This password has to be configured
        # as "PeerPassword" on the other server.
        ;MyPassword = MySecret

        # Foreign password for this connection. This password has to be
        # configured as "MyPassword" on the other server.
        ;PeerPassword = PeerSecret

        # Group of this server (optional)
        ;Group = 123

        # Set the "Passive" option to "yes" if you don't want this ngIRCd to
        # connect to the configured peer (same as leaving the "Port" variable
        # empty). The advantage of this option is that you can actually
        # configure a port an use the IRC command CONNECT more easily to
        # manually connect this specific server later.
        ;Passive = no

        # Connect to the remote server using TLS/SSL (Default: false)
        ;SSLConnect = yes

        # Define a (case insensitive) list of masks matching nicknames that
        # should be treated as IRC services when introduced via this remote
        # server, separated by commas (",").
        # REGULAR SERVERS DON'T NEED this parameter, so leave it empty
        # (which is the default).
        # When you are connecting IRC services which mask as a IRC server
        # and which use "virtual users" to communicate with, for example
        # "NickServ" and "ChanServ", you should set this parameter to
        # something like "*Serv" or "NickServ,ChanServ,XyzServ".
        ;ServiceMask = *Serv,Global

[Server]
        # More [Server] sections, if you like ...

[Channel]
        # Pre-defined channels can be configured in [Channel] sections.
        # Such channels are created by the server when starting up and even
        # persist when there are no more members left.
        # Persistent channels are marked with the mode 'P', which can be set
        # and unset by IRC operators like other modes on the fly.
        # There may be more than one [Channel] block, one for each channel.

        # Name of the channel
        Name = #TheWanderingChat

        # Topic for this channel
        ;Topic = Our ngircd testing channel

        # Initial channel modes
        ;Modes = tnk

        # initial channel password (mode k)
        ;Key = Secret

        # Key file, syntax for each line: "<user>:<nick>:<key>".
        # Default: none.
        ;KeyFile = /etc/ngircd/#chan.key

        # maximum users per channel (mode l)
        ;MaxUsers = 23

[Channel]
        # More [Channel] sections, if you like ...
The reason I post this whole thing is you can copy and paste this and it'll work, and it will make a presistant channel called #TheWanderingChat

I do want to draw special attention to

Code: Select all

MaxConnectionsIP = 0
It's fairly important that this parameter is set to 0 as all of the connections from CGI:IRC will appear to be coming from 127.0.0.1, and not the client's actual IP address.

You should be able to start the IRCd at this point and test it by connecting with your favorite IRC client. If you don’t have one of those, you can wait until we get CGI:IRC running.

Code: Select all

service ngircd start
And we can make this start on boot

Code: Select all

update-rc.d ngircd defaults
CGI:IRC

Then we can move on to CGI:IRC

There’s probably a package for this, but we’re going to compile it from source. If you’ve used CGI:IRC you’re probably thinking “What? It’s PERL, you don’t compile it!” Well, perl isn’t very efficient, and a compiled C component is provided, so we’re going to use that.

First, let’s get some stuff set up with Lighttpd, since CGI:IRC is going to rely pretty heavilly on that.

Code: Select all

nano /etc/lighttpd/lighttpd.conf
Under the line that says “mod_rewrite”, we’re going to add the following two lines

Code: Select all

 “mod_cgi”,
“mod_fastcgi”,
And at the bottom of the file, we’re going to add the following:

Code: Select all

$HTTP["url"] =~ "/cgi-bin/" {
        cgi.assign = ( "" => "" )
}

cgi.assign      = (
        ".cgi"  => ""
)
At this point, your lighttpd.conf should look exactly like this:

Code: Select all

server.modules = (
        "mod_access",
        "mod_alias",
        "mod_compress",
        "mod_redirect",
#       "mod_rewrite",
        "mod_cgi",
        "mod_fastcgi",

)

server.document-root        = "/var/www/html"
server.upload-dirs          = ( "/var/cache/lighttpd/uploads" )
server.errorlog             = "/var/log/lighttpd/error.log"
server.pid-file             = "/var/run/lighttpd.pid"
server.username             = "www-data"
server.groupname            = "www-data"
server.port                 = 80


index-file.names            = ( "index.php", "index.html", "index.lighttpd.html" )
url.access-deny             = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )

compress.cache-dir          = "/var/cache/lighttpd/compress/"
compress.filetype           = ( "application/javascript", "text/css", "text/html", "text/plain" )

# default listening port for IPv6 falls back to the IPv4 port
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
$HTTP["url"] =~ "/cgi-bin/" {
        cgi.assign = ( "" => "" )
}

cgi.assign      = (
        ".cgi"  => ""
)
Now let’s go back to our web directory

Code: Select all

cd /var/www/html
And make this cgi-bin folder

Code: Select all

mkdir cgi-bin
And enter it

Code: Select all

cd cgi-bin
We’ll download the latest version of CGI:IRC

Code: Select all

wget http://cgiirc.org/releases/cgiirc-0.5.11.tar.gz 
And extract it

Code: Select all

tar zxvf cgiirc-0.5.11.tar.gz
And rename the generated file to something more friendly

Code: Select all

mv cgiirc-0.5.11 irc
You should now have a folder called “irc” that contains all of the CGI:IRC files. So let’s go there!

Code: Select all

cd irc
We’ll want to change a couple things in cgiirc.config so let’s open that up

Code: Select all

nano cgiirc.config
Some things we need to change:

Code: Select all

default_server = 127.0.0.1

Code: Select all

default_channel = #TheWanderingChat

(or whatever channel you want to use, this is the channel that I set in the ngircd.conf file)

Code: Select all

image_path = ../../images

Code: Select all

script_form = client.cgi
Save that! But our web chat isn’t ready yet. You see what we need to do with that images folder?

Code: Select all

mv images/ ../../images
And we want to do something a bit more advanced with CGI:IRC that is in their documentation and that the script_form parameter accommodates for.

Code: Select all

gcc -o client.cgi client.c
At this point, we actually need to restart lighttpd to make CGI stuff work

Code: Select all

service lighttpd force-reload
And now you should be able to go to http://your-pi-IP-address/cgi-bin/irc/irc.cgi and see the CGI:IRC login form. If you click “Login” it should connect to ngircd and join you to your channel.

DNSMasq and HostAPd

Well, now we’re getting into the stuff that can mess up your connection to the Pi if you’re using WiFi. If you haven’t already, switch to using a wired connection or start doing this on the Pi its self if that’s not an option… or plug in a second WiFi adapter. If you’re using a Pi 3, I’d suggest plugging in a second wifi adapter then using wlan1 as your access point. While the Pi 3 does have onboard wifi that works pretty well for all of this, we want a nice big antenna!
I ended up buying… a few different wireless adapters to try for this. I ended up using a Panda Wireless PAU04 which worked pretty well. I went for the cheaper option because I was buying 3 different ones to find one that would work the best.. There was a more generic Ralink one I tried as well, but it performed very poorly, as if the antenna connector wasn’t even connected to anything internally. I also tried a very generic Realtek based one, but it turned out to be one of the more obscure chipsets that has 0 Linux support. The major drawback of the Panda Wireless unit was that the antenna is not removable! I think next time I’d go with the PAU06. I belive a TP-Link TL-WN722N will also work.

A note for the Raspberry Pi 4: I know Wireless AC is probably out of the question at the target pricepoint, but can we please at least get 300Mb N? Because of how WiFi works, it can only run as fast as the slowest device, and its a real bummer to drag my entire network down to 150Mbps when my Pi connects. (also I know the wifi chip on the Pi 3 has an FM radio in it, it would have been cool if that was connected and able to do some SDR stuff. But that is a topic for another day!)

Since the Panda Wireless unit is based around a Ralink chip, the support for it is pretty good! Of course, check out the specs on whatever wireless module you decide to use.

DNSMasq

First, we need to set a static IP on our wireless adapter.

Code: Select all

nano /etc/dhcpcd.conf
And add the following lines

Code: Select all

interface wlan0
static ip_address=192.168.2.1/24
static routers=192.168.2.1
static domain_name_servers=192.168.2.1
Save and exit.

Then we’ll want to restart dhcpcd and reinitialize our wireless adapter.

Code: Select all

service dhcpcd restart
ifdown wlan0
ifup wlan0
Then we’ll want to configure dnsmasq.
We’re going to be using a much simpler file than what it comes with, so let’s move the old one aside so we can make a new one.

Code: Select all

mv /etc/dnsmasq.conf /etc/dnsmasq.conf.old
And make a new config file

Code: Select all

nano /etc/dnsmasq.conf
And populate it

Code: Select all

interface=wlan0      # Use interface wlan0
listen-address=192.168.2.1 # Explicitly specify the address to listen on
bind-interfaces      # Bind to the interface to make sure we aren't sending things elsewhere
domain-needed        # Don't forward short names
bogus-priv           # Never forward addresses in the non-routed address spaces.
dhcp-range=192.168.2.50,192.168.2.150,5m # Assign IP addresses between 192.168.2.50 and 192.192.2.150 with a 5m lease time
address=/#/192.168.2.1  #Forward everything to the Pi
HostAPd

First let’s make a hostapd config file:

Code: Select all

nano /etc/hostapd/hostapd.conf
And populate it. Make sure you actually read this file and make changes to the ssid.

Code: Select all


# This is the name of the WiFi interface we configured above
interface=wlan0

# Use the nl80211 driver with the brcmfmac driver
driver=nl80211

# This is the name of the network
ssid=TheWandering_Guest

# Use the 2.4GHz band
hw_mode=g

# Use channel 6
channel=6

# Enable 802.11n
ieee80211n=1

# Enable WMM
wmm_enabled=1

# Enable 40MHz channels with 20ns guard interval
ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]

# Accept all MAC addresses
macaddr_acl=0

# Use WPA authentication
#auth_algs=1

# Require clients to know the network name
ignore_broadcast_ssid=0

# Use WPA2
#wpa=2

# Use a pre-shared key
#wpa_key_mgmt=WPA-PSK

# The network passphrase
#wpa_passphrase=raspberry

# Use AES, instead of TKIP
rsn_pairwise=CCMP
Now, to test it

Code: Select all

/usr/sbin/hostapd /etc/hostapd/hostapd.conf
You might notice this either works, or it returns the following error:

Code: Select all

root@RPI2:~# /usr/sbin/hostapd /etc/hostapd/hostapd.conf
Configuration file: /etc/hostapd/hostapd.conf
nl80211: Could not configure driver mode
nl80211 driver initialization failed.
hostapd_free_hapd_data: Interface wlan0 wasn't started
Now, this error could mean that the nl80211 driver module doesn’t support your adapter, which may very well be the case for a Realtek based adapter. However, if you’re using that Panda wireless adapter I mentioned, or any Ralink adapter for that matter, you’ll want to take note of this line in the hostpad.conf file

Code: Select all

# Enable 40MHz channels with 20ns guard interval
ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]
And just delete it or comment it out. Ralink cards do not support this option. I don’t think Atheros cards do either, which is why I started going crazy trying to find a wireless card that would work. I originally was going to use the TP-Link adapter that I mentioned previously, and I was running into another issue with that that I’ll get into.

Once that’s working correctly, we can close hostapd by hitting Ctrl+C.

Let’s make it load that config file by default!

Code: Select all

nano /etc/default/hostapd
And look for the line
#DAEMON_CONF=

Erase the # and add in the path to our config file. Your line should now look like this

Code: Select all

DAEMON_CONF="/etc/hostapd/hostapd.conf"
Save this, and we’ll move on to making hostapd and dnsmasq start on boot.

Code: Select all

update-rc.d dnsmasq defaults
update-rc.d hostapd defaults
Reboot, and everything should work!

Code: Select all

reboot
Fixing an issue

At this point, you should see your wifi network and be able to connect to it.
For me, this worked without problem on a Pi 3. However, on a Pi 2, hostapd, dnsmasq and ngircd would either hang on startup or not start up at all.

If this is happening to you, here’s a quick&dirty way we can fix it.
SSH back into your Pi and become root again, then we’ll make a script.

Code: Select all

nano /usr/bin/enableAP.sh
and populate this file

Code: Select all

#!/bin/sh
/bin/sleep 30
/usr/sbin/service hostapd stop
/usr/sbin/service dnsmasq stop
/usr/sbin/service ngircd stop
/bin/sleep 10
/sbin/ifdown wlan0
/bin/sleep 10
/usr/sbin/service hostapd start
/usr/sbin/service dnsmasq start
/usr/sbin/service ngircd start
Then we need to make sure this file is executable

Code: Select all

chmod +x /usr/bin/enableAP.sh
And we need to make sure this file runs on startup. Which, caused another point of confusion for me. We’re going to add this to two contrabs, and you need to add it to both.
First, the system crontab.

Code: Select all

nano /etc/crontab
and add this to the bottom of the file

Code: Select all

@reboot /usr/bin/enableAP.sh > /dev/null 2>&1
Then as the root crontab

Code: Select all

crontab -e
And add the same line to this file as well.

In my experience: adding this script to the system crontab resulted in it being run once. Then never again. Adding it to the root crontab resulted in it never being run at all. Adding it to both resulted in it being run every time. Someone smarter than me, please explain why.

There was a thread on the Ubuntu forums about this, and I can’t find it now. But the main thing I got from it is the fact that Cron will not follow relative locations, which is why we’re using the full path to that services program.

Captive portal, for real this time

Loosely going off of this: http://blog.tonybox.net/blog/2013/03/31 ... ve-portal/

Now you might notice that if you go to google.com your device tries to load google while not successfully getting there. We need to configure Lighttpd again to make our portal truly captive. I did this last because it interferes with testing everything else.

So let’s get into Lighttpd again

Code: Select all

nano /etc/lighttpd/lighttpd.conf
Under the server.port option, add the following

Code: Select all

$HTTP["host"] != "thewandering.guest" {
url.redirect = (
        "^/(.*)$" => "http://thewandering.guest/"
)
}
Your lighttpd.conf file should now look like this

Code: Select all

server.modules = (
        "mod_access",
        "mod_alias",
        "mod_compress",
        "mod_redirect",
#       "mod_rewrite",
        "mod_cgi",
        "mod_fastcgi",
)

server.document-root        = "/var/www/html"
server.upload-dirs          = ( "/var/cache/lighttpd/uploads" )
server.errorlog             = "/var/log/lighttpd/error.log"
server.pid-file             = "/var/run/lighttpd.pid"
server.username             = "www-data"
server.groupname            = "www-data"
server.port                 = 80
$HTTP["host"] != "thewandering.guest" {
url.redirect = (
        "^/(.*)$" => "http://thewandering.guest/"
)
}


index-file.names            = ( "index.php", "index.html", "index.lighttpd.html" )
url.access-deny             = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi", ".cgi" )

compress.cache-dir          = "/var/cache/lighttpd/compress/"
compress.filetype           = ( "application/javascript", "text/css", "text/html", "text/plain" )

# default listening port for IPv6 falls back to the IPv4 port
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
$HTTP["url"] =~ "/cgi-bin/" {
        cgi.assign = ( "" => "" )
}

cgi.assign      = (
        ".cgi"  => ""
)
In this example, my website is http://thewandering.guest. You can change this to whatever you want, I like using things that wouldn’t actually work outside of our little LAN as that prevents issues with caching. This will cause Lighttpd to redirect all traffic to you except Https, because there’s no way to really intercept that. This change will also now make clients do the whole “you must authenticate with this access point” thing.

Reload lighttpd

Code: Select all

service lighttpd force-reload


At this point, you can poweroff your Pi, secure it to your battery pack with a rubber band or velcro, and go around your convention with your very own Trollspot.

Image

Image
Last edited by danrulz98 on Fri Oct 07, 2016 5:03 pm, edited 1 time in total.

Phaidonas
Posts: 11
Joined: Tue Jan 05, 2016 5:43 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Tue Oct 04, 2016 10:14 am

hello,i folowed this tutorial for the access point http://elinux.org/RPI-Wireless-Hotspot.Then i follow your captive portal tutorial,i didnt want any irc, only the page.Now at the step ifdown wlan0 and ifup wlan0, it gives me too many parameters in /etc/network/interfaces.And the final step doesnt work.

Phaidonas
Posts: 11
Joined: Tue Jan 05, 2016 5:43 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Tue Oct 04, 2016 12:33 pm

Can you show me how the /etc/network/interfaces should look?

danrulz98
Posts: 24
Joined: Sun May 24, 2015 7:35 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Tue Oct 04, 2016 11:28 pm

Phaidonas wrote:hello,i folowed this tutorial for the access point http://elinux.org/RPI-Wireless-Hotspot.Then i follow your captive portal tutorial,i didnt want any irc, only the page.Now at the step ifdown wlan0 and ifup wlan0, it gives me too many parameters in /etc/network/interfaces.And the final step doesnt work.
Since we're talking about Debian Jessie, /etc/network/interfaces is actually untouched from stock. Instead we're using the DHCP client daemon (dhcpcd.conf) to configure the static IP and such. If you read near the end of my thread, I go into the whole AP setup :)

Code: Select all


pi@rPi3:~ $ cat /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

iface eth0 inet manual

allow-hotplug wlan0
iface wlan0 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

allow-hotplug wlan1
iface wlan1 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

Phaidonas
Posts: 11
Joined: Tue Jan 05, 2016 5:43 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Wed Oct 05, 2016 10:01 am

It keeps giving me the same error about the driver,i have a raspberry pi B and a wifi module RT5370.With the tutorial that i send you about AP it was working

danrulz98
Posts: 24
Joined: Sun May 24, 2015 7:35 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Wed Oct 05, 2016 11:15 pm

Try bringing down the wifi adapter then running hostapd

Code: Select all

ifdown wlan0
/usr/sbin/hostapd /etc/hostapd/hostapd.conf
If that works, then look at where I made a startup script for the whole thing :)

If that's still giving you an issue, comment out this line in your hostapd.conf file

Code: Select all

ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]
It seems like this option doesn't work with a number of wireless adapters.

Phaidonas
Posts: 11
Joined: Tue Jan 05, 2016 5:43 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Thu Oct 06, 2016 10:33 am

ok,i did what you said,but at the final step it gives me the error job for lighttpd.service failed. See 'systemctl status lighttpd.service' and 'journalctl -xn' for details.I typed the first and gives the error "Failed to start lighttpd DAEMON"

Phaidonas
Posts: 11
Joined: Tue Jan 05, 2016 5:43 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Thu Oct 06, 2016 1:47 pm

i started from the beginn,i gives some errors in the first update,and then in th lighttpd enable fastcgi

danrulz98
Posts: 24
Joined: Sun May 24, 2015 7:35 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Thu Oct 06, 2016 1:51 pm

Systemctl? You must be using Fedora or Arch. The instructions for those will be a bit different since each flavor uses slightly different packages.

Phaidonas
Posts: 11
Joined: Tue Jan 05, 2016 5:43 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Thu Oct 06, 2016 2:50 pm

i started again from the beggining i manage to go untill the point that it works with ifdown wlan0.But it stucks in AP enabled.i did the script,I dont think it is only this line that make the problem.I am using rasbian jessie.I install them 3-4 days before.And as i said you with other guide worked perfectly,the transmitting part.the hosttapd.conf file was much simpler only
"interface=wlan0
ssid=My_AP
hw_mode=g
channel=6
auth_algs=1
wmm_enabled=0
"
The differences where that he made the static ip in the /etc/network/interfaces and after that he was doing something like port forwarding that i dont understand,like this:

Code: Select all

sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
To set this up automatically on boot, edit the file /etc/sysctl.conf and add the following line to the bottom of the file:

Code: Select all

net.ipv4.ip_forward=1
Second, to enable NAT in the kernel, run the following commands:

Code: Select all

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
These instructions don't give a good solution for rerouting https and for URLs referring to a page inside a domain, like www.nu.nl/38274.htm. The user will see a 404 error. Your Pi is now NAT-ing. To make this permanent so you don't have to run the commands after each reboot, run the following command:

Code: Select all

sudo sh -c "iptables-save > /etc/iptables.ipv4.nat"
Now edit the file /etc/network/interfaces and add the following line to the bottom of the file:

Code: Select all

up iptables-restore < /etc/iptables.ipv4.nat
Is any way to implement his guide with your guide?
And second you define in the lighttpd.conf

Code: Select all

$HTTP["host"] != "thewandering.guest" {
url.redirect = (
        "^/(.*)$" => "http://thewandering.guest/"
)
}
thewandering.guest.What is this.the url that appears in the page?Because you didnt define it anywhere else.How it is connect with the page that you made before the guestbook?

danrulz98
Posts: 24
Joined: Sun May 24, 2015 7:35 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Thu Oct 06, 2016 4:07 pm

Ah yes.
So the deal with this tutorial, and I'll be making another one here soon that's more to what you're trying to do, is my setup here wasn't meant to direct traffic outside of the box, so all content is hosted locally.
Because of what I made this for (trolling people at a convention) I didn't need to direct traffic elsewhere and in fact could not without either violating the AUP on the very expensive WiFi the con provided or by linking up to a 4G Hotspot which could have potentially been very expensive as well.
That's why you don't see the iptables configuration in this thread.

TheWandering.guest was used as the domain to avoid issues with caching, since .guest isn't exactly a valid domain outside of the local network you'd be setting up here. This domain could be anything you wanted.

Https is another issue all together, since browsers will tend to refuse connections if the certificates don't match up,which captive portals intentionally break. This is why operating systems will issue notifications to the user that they need to deal with the captive portal before doing much else.

I'm at work right now, when I get home I'll try to reproduce the error you're getting and see if I can fix it. I believe I have a wireless adapter based on the same chip somewhere...

Phaidonas
Posts: 11
Joined: Tue Jan 05, 2016 5:43 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Thu Oct 06, 2016 4:17 pm

I want to do the same as you did,i dont want to have internet access,just when the user log to the wifi transmitted from the pi,to redirected to the page,which will be a somehow trollpage because it will be for a presentation in a museum.The place that the raspberry will be installed will have no wifi and no internet.but i found it will be easy if i make it to transimit,without internet,to make a redirection to a certain page.

danrulz98
Posts: 24
Joined: Sun May 24, 2015 7:35 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Thu Oct 06, 2016 4:22 pm

Yeah, you don't need iptables for that. Just dnsmasq and the redirect in lighttpd will do.

I will investigate the issue though. You're using a Pi 1 B+?

Phaidonas
Posts: 11
Joined: Tue Jan 05, 2016 5:43 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Thu Oct 06, 2016 4:35 pm

Im using a pi 2 B,i dont know if it is +,it doesnt write anything in the box

danrulz98
Posts: 24
Joined: Sun May 24, 2015 7:35 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Thu Oct 06, 2016 11:35 pm

Ah, I alright. Pi 2s only came in the B+ configuration, while the original Pis had a few different options so I was just wondering exactly what you had. ;)

So in the Elinux setup the hostapd.conf file is a lot simpler, and you could try using just that. You might want to add:

Code: Select all

ieee80211n=1
to it in order to get N speeds out of your adapter, make things a little smoother.

The thing I notice is that he's setting up an access point, one that's intended to make a wireless network that takes you directly to the internet, and that's what all the stuff with IPTables is for. So for hosting stuff locally, you don't need to mess with that.

Do you mind posting your lighttpd.conf and hostapd.conf files? You can PM them to me if you don't want them public.
If possible, could you copy and paste the exact error?

I looked and the Panda Wireless adapter that I used is an RT5370, so I know my hostapd.conf file should work with that line commented out.

danrulz98
Posts: 24
Joined: Sun May 24, 2015 7:35 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Fri Oct 07, 2016 12:01 am

So I think I misread your post...

When you're starting hostapd manually, with

Code: Select all

sudo /usr/sbin/hostapd /etc/hostapd/hostapd.conf
It will stop at saying "AP-ENABLED". Ralink adapters will NOT have an indicator light in AP mode.

This status message is actually a success. So when it starts as a daemon with:

Code: Select all

service hostapd start
it will run correctly (assuming wlan0 is downed first).

Now most operating systems won't actually connect to it at this point because that doesn't start dnsmasq, which is what hands out IP addresses.

Phaidonas
Posts: 11
Joined: Tue Jan 05, 2016 5:43 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Fri Oct 07, 2016 7:23 am

ok,when i reboot my pi and i type service hostapd start,the pi start transmits but no redirection when i log in from my laptop

Phaidonas
Posts: 11
Joined: Tue Jan 05, 2016 5:43 pm

Re: The Trollspot - A battery powered WiFi Captive Portal

Fri Oct 07, 2016 1:15 pm

ok,i think im in a good way.Your post is very good but i think the problem is,that i didnt want all the irc stuff,so i passed them until the dndmasq configuration.I think there is a point that i have to add the cgi and fastcgi.Is that usefull for the final result or it is only for the irc?Now the pi transmits after reboot but still no redirection.Should i put the cgi php also in the lighttpd.cong?

Return to “Networking and servers”