Pfsense captive portal voucher generation without need to login into firewall

Alexander Guerrero picture Alexander Guerrero · Mar 8, 2016 · Viewed 8.1k times · Source

I would like to know if there is any method that can be used to generate vouchers redeemable in the Pfsense captive portal. Basically I have a firewall which feeds internet to a wifi router for guests. I would like to have some form of interface for a worker to be able to create vouchers and give them to customers without having to log in to the wifi. I found two leads online, https://sourceforge.net/projects/vouchergen/ and https://github.com/jpardobl/pfsense_vouchers_rest but they no longer work. Any advice? Thanks in advance.

Answer

Josue picture Josue · Sep 13, 2016

I just finished writing a simple php page to do that. It works with a mysql database, which has only two tables, one for vouchers and another for IP addresses which I want to grant access to this page.

Once the user chooses a voucher type (minutes) and hit "Generate" then it picks any valid voucher in the local database and marks it as used.

Here is the code:

<!DOCTYPE html>
<html>
    <head>   
        <meta charset="UTF-8">
        <title>Vouchers DSA</title>
    </head>
    <body> 
        <?php
        function gera_form(){
            ?>
            <style>
            table {
                font-family: arial, sans-serif;
                border-collapse: collapse;
                width: 100%;
            }
            td, th {
                border: 1px solid #dddddd;
                text-align: left;
                padding: 8px;
            }
            tr:nth-child(even) {
                background-color: #dddddd;
            }
        </style>
        <?php
            echo '<h2 align="center">Gerador de vouchers para WiFi</center></h2>';
            echo '<p align="center">Selecione a duração desejada e clique em "Gerar Voucher"</center></p>';
            echo '<br><br>';
            echo '<div align="center">';
            echo '<form method="POST">';
            echo '<select name="state">'; 
            echo '<option value="--">Duração</option>';
            echo '<option value="30">1/2 hora</option>';
            echo '<option value="60">1 hora</option>';
            echo '<option value="120">2 horas</option>';
            echo '<option value="1440">1 dia</option>';
            echo '<option value="43200">1 mês</option>';
            echo '</select>';
            echo '<br><br><input type="submit" value="Gerar Voucher">';
            echo '</form> </center>';
            echo '</div>';  
        }    
        $ip=get_client_ip();
        $hostname="localhost";  
        $username="root";  
        $password="771477";  
        $db = "banco_voucher";  
        $dbh = new PDO("mysql:host=$hostname;dbname=$db", $username, $password);       
        function get_client_ip() {
            $ipaddress = '';
            if (getenv('HTTP_CLIENT_IP'))
                $ipaddress = getenv('HTTP_CLIENT_IP');
            else if(getenv('HTTP_X_FORWARDED_FOR'))
                $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
            else if(getenv('HTTP_X_FORWARDED'))
                $ipaddress = getenv('HTTP_X_FORWARDED');
            else if(getenv('HTTP_FORWARDED_FOR'))
                $ipaddress = getenv('HTTP_FORWARDED_FOR');
            else if(getenv('HTTP_FORWARDED'))
               $ipaddress = getenv('HTTP_FORWARDED');
            else if(getenv('REMOTE_ADDR'))
                $ipaddress = getenv('REMOTE_ADDR');
            else
                $ipaddress = 'UNKNOWN';
            return $ipaddress;
        }
        function get_voucher($valor, $ip, $dbh){       
            $hostname="localhost";  
            $username="root";  
            $password="771477";  
            $db = "banco_voucher";  
            $dbh = new PDO("mysql:host=$hostname;dbname=$db", $username, $password);    
            foreach($dbh->query("update vouchers 
                                    set solicitado_por = 
                                    (select id_usuario from usuarios where ip_maquina = '$ip'), 
                                    solicitado_em = now(), 
                                    validade = 0
                                    where validade != 0 and minutos = '$valor'
                                    limit 1;" ) as $row);
        }
        function get_time($minutos){
            $dur = "";
            if ($minutos == 30) {
                $dur = "1/2 hora";
            } else if ($minutos == 60) {
                $dur = "1 hora";
            } else if ($minutos == 120) {
                $dur = "2 horas";
            } else if ($minutos == 1440) {
                $dur = "1 dia";
            } else if ($minutos == 43200) {
                $dur = "1 mes";
            } else {
                $dur = "desconhecida";
            }
            return $dur;
        }
        function gera_tabela($ip){
            $hostname="localhost";  
            $username="root";  
            $password="771477";  
            $db = "banco_voucher";  
            $dbh = new PDO("mysql:host=$hostname;dbname=$db", $username, $password);      
            $historico = array("<table>
                                <tr>
                                <th>Departamento</th>
                                <th>Voucher</th>
                                <th>Duracao</th>
                                <th>Data</th>
                                </tr>",);
            $teste = array ("a");
            try {
                $select = $dbh->query("select b.departamento, 
                                        a.cod_voucher, a.minutos, 
                                        date_format(a.solicitado_em, '%d/%c/%Y - %H:%i:%s') as stamp 
                                        from vouchers as a
                                        right join usuarios as b on (solicitado_por = id_usuario)
                                        where ip_maquina = '$ip' and cod_voucher is not null
                                        order by stamp desc limit 10;");
            } catch (Exception $exc) {
                echo $exc->getTraceAsString();
            }
            $result = $select->fetchAll();
            echo "<br><br>";
            echo $historico[0];
            $i = 0;
            foreach($result as $row){
                $dur = get_time($row['minutos']);        
                array_push($historico, "<tr><td>".$row['departamento']."</td>"
                        . "<td>".$row['cod_voucher']."</td>"
                        . "<td>".$dur."</td>"
                        . "<td>".$row['stamp']."</td>"
                        . "</tr>");
                $i++;
                echo $historico[$i];       
            }
            echo "</table>";
        }
        foreach($dbh->query("select-count(ip_maquina) as ip from usuarios where ip_maquina = '$ip';") as $row){
            if($row['ip'] == 0){
                echo "<h1>Acesso negado</h1>";
                echo "<p>Sua estação de trabalho não tem as permissões de acesso necessárias."
                        . "<br>Contate a equipe de TI para mais informações.</p><hr>";
                echo "<address>Gestão de vouchers - Divisão Sul Americana da IASD</address>";
            }
            else if($row['ip'] != 0){
                gera_form();
                get_voucher($_POST['state'], $ip);
                gera_tabela($ip);
                if(isset($_POST['state'])){
                    header("Location:SandBox.php");
                    unset($_POST['state']);
                    if($_POST['state']=="--"){
                        echo "Escolha um tempo apropriado para a validade do voucher.";
                    }
                }
            }     
    }
        ?>
    </body>
</html>

As it is my first php page, it might be a disaster in an experienced php programmer's eyes, however it is quite functional and does right what you seem to need.

Just copy the code above into a file named SandBox.php and place in your Apache /www/html folder.

The tables in mysql can be created using these codes:

For vouchers:

CREATE TABLE `vouchers` (
  `id_voucher` int(11) NOT NULL AUTO_INCREMENT,
  `cod_voucher` varchar(10) DEFAULT NULL,
  `validade` bit(1) DEFAULT NULL,
  `solicitado_em` varchar(20) DEFAULT NULL,
  `solicitado_por` varchar(15) DEFAULT NULL,
  `minutos` int(11) DEFAULT NULL,
  PRIMARY KEY (`id_voucher`)
) ENGINE=InnoDB AUTO_INCREMENT=131073 DEFAULT CHARSET=utf8;

You must do a manual update in the column 'validade' to set the value '1' [meaning valid] for all vouchers. After picked by the page, it will be updated into '0' [meaning used].

update vouchers set validade = 1;

For IP addresses which will be allowed to access the page:

CREATE TABLE `usuarios` (
  `id_usuario` int(11) NOT NULL AUTO_INCREMENT,
  `ip_maquina` varchar(15) DEFAULT NULL,
  `departamento` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id_usuario`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

You must do manual inserts in this table, parsing the IP address of the management machine and it's name/location/label/whatever you want to use as a human readable ID.

insert into usuarios(ip_maquina, departamento) values ('10.91.198.12', 'Cyber Cafe');

PS.: The field names are in portuguese.

To load the .csv file from PfSense into the local database:

LOAD DATA LOCAL INFILE '/home/infra/Downloads/vouchers.csv' 
INTO TABLE vouchers
LINES TERMINATED BY '\n' (cod_voucher);

Hope it may help you.