added captive portal model and some plumming for future use

This commit is contained in:
Ad Schellevis 2014-12-09 15:48:03 +01:00
parent b7905f6d03
commit 6f8cea824e
18 changed files with 1731 additions and 0 deletions

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Phalcon PHP Framework</title>
</head>
<body>
<?php echo $this->getContent(); ?>
</body>
</html>

View File

@ -0,0 +1,3 @@
<h1>Congratulations!</h1>
<p>You're now flying with Phalcon. Great things are about to happen!</p>

View File

@ -0,0 +1,28 @@
<?php
return new \Phalcon\Config(array(
'database' => array(
'adapter' => 'Mysql',
'host' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'test',
),
'application' => array(
'controllersDir' => __DIR__ . '/../../app/controllers/',
'modelsDir' => __DIR__ . '/../../app/models/',
'viewsDir' => __DIR__ . '/../../app/views/',
'pluginsDir' => __DIR__ . '/../../app/plugins/',
'libraryDir' => __DIR__ . '/../../app/library/',
'cacheDir' => __DIR__ . '/../../app/cache/',
'baseUri' => '/opnsense_gui/',
),
'globals' => array(
'config_path' => '/conf/',
'temp_path' => '/tmp/',
'vardb_path' => '/var/db/',
'debug' => true,
'simulate_mode' => false
)
));

View File

@ -0,0 +1,13 @@
<?php
$loader = new \Phalcon\Loader();
/**
* We're a registering a set of directories taken from the configuration file
*/
$loader->registerDirs(
array(
$config->application->controllersDir,
$config->application->modelsDir
)
)->register();

View File

@ -0,0 +1,83 @@
<?php
use Phalcon\DI\FactoryDefault;
use Phalcon\Mvc\View;
use Phalcon\Mvc\Url as UrlResolver;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
use Phalcon\Mvc\View\Engine\Volt as VoltEngine;
use Phalcon\Mvc\Model\Metadata\Memory as MetaDataAdapter;
use Phalcon\Session\Adapter\Files as SessionAdapter;
/**
* The FactoryDefault Dependency Injector automatically register the right services providing a full stack framework
*/
$di = new FactoryDefault();
/**
* The URL component is used to generate all kind of urls in the application
*/
$di->set('url', function () use ($config) {
$url = new UrlResolver();
$url->setBaseUri($config->application->baseUri);
return $url;
}, true);
/**
* Setting up the view component
*/
$di->set('view', function () use ($config) {
$view = new View();
$view->setViewsDir($config->application->viewsDir);
$view->registerEngines(array(
'.volt' => function ($view, $di) use ($config) {
$volt = new VoltEngine($view, $di);
$volt->setOptions(array(
'compiledPath' => $config->application->cacheDir,
'compiledSeparator' => '_'
));
return $volt;
},
'.phtml' => 'Phalcon\Mvc\View\Engine\Php'
));
return $view;
}, true);
/**
* Database connection is created based in the parameters defined in the configuration file
*/
$di->set('db', function () use ($config) {
return new DbAdapter(array(
'host' => $config->database->host,
'username' => $config->database->username,
'password' => $config->database->password,
'dbname' => $config->database->dbname
));
});
/**
* If the configuration specify the use of metadata adapter use it or use memory otherwise
*/
$di->set('modelsMetadata', function () {
return new MetaDataAdapter();
});
/**
* Start the session the first time some component request the session service
*/
$di->set('session', function () {
$session = new SessionAdapter();
$session->start();
return $session;
});
$di->set('config',$config);

View File

@ -0,0 +1,8 @@
<?php
use Phalcon\Mvc\Controller;
class ControllerBase extends Controller
{
}

View File

@ -0,0 +1,12 @@
<?php
class IndexController extends ControllerBase
{
public function indexAction()
{
}
}

View File

@ -0,0 +1,82 @@
<?php
/**
* User: ad
* Date: 09-12-14
* Time: 16:26
*/
namespace Captiveportal;
class ARP {
/**
* pointer to shell object
* @var \Core\Shell
*/
private $shell ;
/**
* construct new ARP table handlers
*/
function __construct()
{
$this->shell = new \Core\Shell();
}
/**
* set static arp entry
* @param $ipaddress hosts ipaddress
* @param $mac hosts physical address
*/
function setStatic($ipaddress,$mac){
// validate input, only set static entries for valid addresses
if (preg_match('/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/', trim($mac))){
if ( filter_var($ipaddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4|FILTER_FLAG_IPV6) ){
$this->shell->exec("/usr/sbin/arp -s ".trim($ipaddress)." ".trim($mac));
}
}
}
/**
* drop static arp entry
* @param $ipaddress hosts ipaddress
*/
function dropStatic($ipaddress){
// validate input, drop arp entry
if ( filter_var($ipaddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4|FILTER_FLAG_IPV6) ){
$this->shell->exec("/usr/sbin/arp -d ".trim($ipaddress) );
}
}
/**
* Return arp table hashed by mac address
*/
function getMACs(){
$result = array();
$shell_output = array();
// execute arp shell command and collect (only valid) info into named array
if ($this->shell->exec("arp -an",false,false,$shell_output) == 0 ){
foreach($shell_output as $line){
$line_parts = explode(" ",$line) ;
if ( sizeof($line_parts) >= 4 ) {
$ipaddress = substr($line_parts[1],1,strlen($line_parts[1])-2 ) ;
// reformat mac addresses, sometimes arp return segments without trailing zero's
$mac_raw = strtolower($line_parts[3]);
$mac = "";
foreach(explode(":",$mac_raw) as $segment ){
if ( $mac != "") $mac .= ":";
if (strlen($segment) == 1) $mac .= "0".$segment;
else $mac .= $segment ;
}
if (preg_match('/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/', trim($mac))){
$result[$mac]= array('ip'=>$ipaddress);
}
}
}
}
return $result;
}
}

View File

@ -0,0 +1,500 @@
<?php namespace Captiveportal;
/**
* Class CPClient
* // TODO: CARP interfaces are probably not handled correctly
* @package Captiveportal
*/
class CPClient {
/**
* config handle
* @var Core_Config
*/
private $config = null;
/**
* ipfw rule object
* @var \Captiveportal\Rules
*/
private $rules = null;
/**
* link to shell object
* @var \Core\Shell
*/
private $shell = null;
/**
* Request new pipeno
* @return int
*/
private function new_ipfw_pipeno(){
// TODO: implement global pipe number assigment
return 999;
}
/**
* reset bandwidth, if the current bandwidth is unchanged, do nothing
*
* @param int $pipeno system pipeno
* @param int $bw bandwidth in Kbit/s
*/
private function reset_bandwidth($pipeno,$bw){
//TODO : setup bandwidth for sessions ( check changed )
//#pipe 2000 config bw 2000Kbit/s
return;
}
/**
* @param $cpzonename zone name
* @param $sessionid session id
*/
private function _disconnect($cpzonename,$sessionid){
$zoneid = -1;
foreach($this->config->object()->captiveportal->children() as $zone => $zoneobj){
if ($zone == $cpzonename) $zoneid = $zoneobj->zoneid;
}
if ($zoneid == -1) return; // not a valid zone
$db = new DB($cpzonename);
$db_clients = $db->listClients(array("sessionid"=>$sessionid));
$ipfw_tables = $this->rules->getAuthUsersTables($zoneid);
if ( sizeof($db_clients) > 0 ){
if ($db_clients->ip != null ) {
// only handle disconnect if we can find a client in our database
$exec_commands[] = "/sbin/ipfw table " . $ipfw_tables["in"] . " delete " . $db_clients[0]->ip;
$exec_commands[] = "/sbin/ipfw table " . $ipfw_tables["out"] . " delete " . $db_clients[0]->ip;
$this->shell->exec($exec_commands, false, false);
// TODO: cleanup dummynet pipes $db_clients[0]->pipeno_in/out
// TODO: log removal ( was : captiveportal_logportalauth($cpentry[4], $cpentry[3], $cpentry[2], "DISCONNECT");)
}
$db->remove_session($sessionid);
}
}
/**
*
* @param $zoneid
* @param $ip
*/
public function add_accounting($zoneid,$ip){
// TODO: check speed, this might need some improvement
// check if our ip is already in the list and collect first free rule number to place it there if necessary
$shell_output=array();
$this->shell->exec("/sbin/ipfw show",false,false,$shell_output);
$prev_id = 0;
$new_id = null;
foreach($shell_output as $line){
// only trigger on counter rules and last item in the list
if ( strpos($line," count " ) !== false || strpos($line,"65535 " )!== false ) {
if ( strpos($line," ".$ip." " ) !== false ) {
// already in table... exit
return;
}
$this_line_id = (int) (explode(" ",$line)[0]) ;
if ( $this_line_id > 30000 and ($this_line_id -1) > $prev_id and $new_id == null) {
// new id found
if ( $this_line_id == 65535 ) $new_id = $prev_id+1;
else $new_id = $this_line_id-1;
}
$prev_id = $this_line_id;
}
}
if ( $new_id != null ) {
$exec_commands = array(
"/sbin/ipfw add " . $new_id . " set " . $zoneid . " count ip from " . $ip . " to any ",
"/sbin/ipfw add " . $new_id . " set " . $zoneid . " count ip from any to " . $ip,
);
// execute all ipfw actions
$this->shell->exec($exec_commands, false, false);
}
}
/**
* Constructor
*/
function __construct() {
// Request handle to configuration
$this->config = \Core\Config::getInstance();
// generate new ruleset
$this->rules = new \Captiveportal\Rules();
// keep a link to the shell object
$this->shell = new \Core\Shell();
}
/**
* Reconfigure zones ( generate and load ruleset )
*/
public function reconfigure(){
$ruleset_filename = \Phalcon\DI\FactoryDefault::getDefault()->get('config')->globals->temp_path."/ipfw.rules";
$this->rules->generate($ruleset_filename);
// load ruleset
$this->shell->exec("/sbin/ipfw -f ".$ruleset_filename);
// update tables
$this->update_config();
}
/**
* update zone(s) with new configuration data
* @param string $zone
*/
public function update($zone=null){
$this->refresh_allowed_ips($zone);
$this->refresh_allowed_mac($zone);
}
/**
* refresh allowed ip's for defined zone ( null for all zones )
* @param string $zone
*/
public function refresh_allowed_ips($cpzone=null){
$handled_addresses = array();
foreach( $this->config->object()->captiveportal->children() as $cpzonename => $zone ) {
// search requested zone (id)
if ( $cpzonename == $cpzone || $zone->zoneid == $cpzone || $cpzone == null ) {
$db = new DB($cpzonename);
$db_iplist = $db->listFixedIPs();
// calculate table numbers for this zone
$ipfw_tables = $this->rules->getAuthIPTables($zone->zoneid );
foreach ($zone->children() as $tagname => $tagcontent) {
$ip = $tagcontent->ip->__toString();
if ($tagname == 'allowedip') {
$handled_addresses[$ip] = array();
$handled_addresses[$ip]["bw_up"] = $tagcontent->bw_up->__toString() ;
$handled_addresses[$ip]["bw_down"] = $tagcontent->bw_down->__toString() ;
if ( !array_key_exists($ip,$db_iplist) ){
// only insert new values
$pipeno_in = $this->new_ipfw_pipeno() ;
$pipeno_out = $this->new_ipfw_pipeno() ;
$exec_commands = array(
# insert new ip address
"/sbin/ipfw table ". $ipfw_tables["in"] ." add " . $ip . "/" . $tagcontent->sn->__toString() . " " . $pipeno_in,
"/sbin/ipfw table ". $ipfw_tables["out"] ." add " . $ip . "/" . $tagcontent->sn->__toString() . " " . $pipeno_out,
);
// execute all ipfw actions
$this->shell->exec($exec_commands, false,false);
// update administration
$db->upsertFixedIP($ip,$pipeno_in,$pipeno_out);
// save bandwidth data
$handled_addresses[$ip]["pipeno_in"] = $pipeno_in ;
$handled_addresses[$ip]["pipeno_out"] = $pipeno_out ;
}else{
//
$handled_addresses[$ip]["pipeno_in"] = $db_iplist[$ip]->pipeno_in ;
$handled_addresses[$ip]["pipeno_out"] = $db_iplist[$ip]->pipeno_out ;
}
}
}
// Cleanup deleted addresses
foreach($db_iplist as $ip => $record){
if (!array_key_exists($ip,$handled_addresses)){
$exec_commands = array(
# insert new ip address
"/sbin/ipfw table ". $ipfw_tables["in"] ." del " . $ip . "/" . $tagcontent->sn->__toString() ,
"/sbin/ipfw table ". $ipfw_tables["out"] ." del " . $ip . "/" . $tagcontent->sn->__toString() ,
);
// execute all ipfw actions
$this->shell->exec($exec_commands, false,false);
// TODO : cleanup $record->pipeno_in, $record->pipeno_out ;
$db->dropFixedIP($ip);
}
}
// reset bandwidth,
foreach($handled_addresses as $mac => $record){
if (array_key_exists("pipeno_in",$record) ){
$this->reset_bandwidth($record["pipeno_in"],$record["bw_down"]);
$this->reset_bandwidth($record["pipeno_out"],$record["bw_up"]);
}
}
unset($db);
}
}
}
/**
* To be able to grant access to physical pc's, we need to do some administration.
* Our captive portal database keeps a list of every used address and last know mac address
*
* @param String $zone zone name or number
*/
public function refresh_allowed_mac($cpzone=null){
// read ARP table
$arp= new ARP();
$arp_maclist = $arp->getMACs();
// keep a list of handled addresses, so we can cleanup the rest and keep track of needed bandwidth restrictions
$handled_mac_addresses = array();
foreach( $this->config->object()->captiveportal->children() as $cpzonename => $zone ) {
if ( $cpzonename == $cpzone || $zone->zoneid == $cpzone || $cpzone == null ) {
// open administrative database for this zone
$db = new DB($cpzonename);
$db_maclist = $db->listPassthruMacs();
$ipfw_tables = $this->rules->getAuthMACTables($zone->zoneid);
foreach ($zone->children() as $tagname => $tagcontent) {
$mac = trim(strtolower($tagcontent->mac));
if ($tagname == 'passthrumac') {
// only accept valid macaddresses
if (preg_match('/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/', $mac)) {
if ($tagcontent->action == "pass") {
$handled_mac_addresses[$mac] = array("action"=>"skipped" );
$handled_mac_addresses[$mac]["bw_up"] = $tagcontent->bw_up ;
$handled_mac_addresses[$mac]["bw_down"] = $tagcontent->bw_down ;
// only handle addresses we know of
if (array_key_exists($mac, $arp_maclist)) {
// if the address is already in our database, check if it has changed
if ( array_key_exists($mac,$db_maclist) ) {
// save pipe numbers for bandwidth restriction
$handled_mac_addresses[$mac]["pipeno_in"] = $db_maclist[$mac]->pipeno_in ;
$handled_mac_addresses[$mac]["pipeno_out"] = $db_maclist[$mac]->pipeno_out ;
if ($db_maclist[$mac]->ip != $arp_maclist[$mac]['ip'] ) {
// handle changed ip,
$handled_mac_addresses[$mac]["action"] = "changed ip";
$exec_commands = array(
# delete old ip address
"/sbin/ipfw table ". $ipfw_tables["in"] ." delete ". $db_maclist[$mac]->ip,
"/sbin/ipfw table ". $ipfw_tables["out"] ." delete ". $db_maclist[$mac]->ip,
# insert new ip address
"/sbin/ipfw table ". $ipfw_tables["in"] ." add " . $arp_maclist[$mac]['ip']. " " . $db_maclist[$mac]->pipeno_in,
"/sbin/ipfw table ". $ipfw_tables["out"] ." add " . $arp_maclist[$mac]['ip']. " " . $db_maclist[$mac]->pipeno_out,
);
// execute all ipfw actions
$this->shell->exec($exec_commands, false,false);
// update administration
$db->upsertPassthruMAC($tagcontent->mac,$arp_maclist[$mac]['ip'],$db_maclist[$mac]->pipeno_in,$db_maclist[$mac]->pipeno_out); // new ip according to arp table
}
}
else {
// new host, not seen it yet
$handled_mac_addresses[$mac]["action"] = "new";
$pipeno_in = $this->new_ipfw_pipeno() ;
$pipeno_out = $this->new_ipfw_pipeno() ;
// execute all ipfw actions
$exec_commands = array(
# insert new ip address
"/sbin/ipfw table ". $ipfw_tables["in"] ." add " . $arp_maclist[$mac]['ip']. " " . $pipeno_in,
"/sbin/ipfw table ". $ipfw_tables["out"] ." add " . $arp_maclist[$mac]['ip']. " " . $pipeno_out,
);
$this->shell->exec($exec_commands, false,false);
$db->upsertPassthruMAC($tagcontent->mac,$arp_maclist[$mac]['ip'],$pipeno_in,$pipeno_out);
// save pipe numbers for bandwidth restriction
$handled_mac_addresses[$mac]["pipeno_in"] = $pipeno_in ;
$handled_mac_addresses[$mac]["pipeno_out"] = $pipeno_out ;
}
}
}
}
}
}
//
// cleanup old addresses
//
foreach($db_maclist as $mac => $record){
if ( !array_key_exists($mac,$handled_mac_addresses) ){
# delete old ip address, execute all actions
$exec_commands = array(
"/sbin/ipfw table ". $ipfw_tables["in"] ." delete ". $db_maclist[$mac]->ip,
"/sbin/ipfw table ". $ipfw_tables["out"] ." delete ". $db_maclist[$mac]->ip,
);
$this->shell->exec($exec_commands, false,false);
// TODO : cleanup $record->pipeno_in, $record->pipeno_out ;
$db->dropPassthruMAC($mac);
}
}
// reset bandwidth
foreach($handled_mac_addresses as $mac => $record){
if (array_key_exists("pipeno_in",$record) ){
$this->reset_bandwidth($record["pipeno_in"],$record["bw_down"]);
$this->reset_bandwidth($record["pipeno_out"],$record["bw_up"]);
}
}
unset($db);
}
}
}
/**
* @param string $cpzonename
* @param string $clientip
* @param string $clientmac
* @param string $username
* @param string $password
* @param string $attributes
* @param string $radiusctx
*/
public function portal_allow($cpzonename,$clientip,$clientmac,$username,$password = null,$bw_up=null,$bw_down=null, $attributes = null, $radiusctx = null){
// defines
$exec_commands = array() ;
$db = new DB($cpzonename);
$arp= new ARP();
// find zoneid for this named zone
$zoneid = -1;
foreach($this->config->object()->captiveportal->children() as $zone => $zoneobj){
if ($zone == $cpzonename) $zoneid = $zoneobj->zoneid;
}
if ($zoneid == -1) return; // not a valid zone, bailout
// grap needed data to generate our rules
$ipfw_tables = $this->rules->getAuthUsersTables($zoneid);
$cp_table = $db->listClients(array("mac"=>$clientmac,"ip"=>$clientip),"or");
if ( sizeof($cp_table) > 0 && ($cp_table[0]->ip == $clientip && $cp_table[0]->mac == $clientmac ) ){
// nothing (important) changed here... move on
return;
} elseif ( sizeof($cp_table) > 0) {
// something changed...
// prevent additional sessions to popup, one MAC should have only one active session, remove the rest (if any)
$cnt = 0;
$remove_sessions = array();
foreach($cp_table as $record){
if ( $cnt >0) $remove_sessions[] = $record->sessionid;
else $current_session = $record;
$cnt++;
// prepare removal for all ip addresses belonging to this host
$exec_commands[] = "/sbin/ipfw table ". $ipfw_tables["in"] ." delete ". $record->ip;
$exec_commands[] = "/sbin/ipfw table ". $ipfw_tables["out"] ." delete ". $record->ip;
// TODO: if for some strange reason there is more than one session, we are failing to drop the pipes
$exec_commands[] = "/usr/sbin/arp -d ".trim($record->ip); // drop static arp entry (prevent MAC change)
}
if (sizeof($remove_sessions)){
$db->remove_session($remove_sessions);
}
// collect pipe numbers for dummynet
$pipeno_in = $current_session->pipeno_in;
$pipeno_out = $current_session->pipeno_out;
$db->update_session($current_session->sessionid,array("ip"=>$clientip,"mac"=>$clientmac));
} else
{
// new session, allocate new dummynet pipes and generate a unique id
$pipeno_in = $this->new_ipfw_pipeno();
$pipeno_out = $this->new_ipfw_pipeno();
// construct session data
$session_data=Array();
$session_data["ip"]=$clientip;
$session_data["mac"]=$clientmac;
$session_data["pipeno_in"] = $pipeno_in;
$session_data["pipeno_out"] = $pipeno_out;
$session_data["username"]=\SQLite3::escapeString($username);
$session_data["bpassword"] =base64_encode($password);
$session_data["session_timeout"] = -1;
$session_data["idle_timeout"] = -1;
$session_data["session_terminate_time"] = -1;
$session_data["interim_interval"] = -1;
$session_data["radiusctx"] = $radiusctx;
$session_data["allow_time"] = time(); // allow time is actual starting time of this session
$sessionid = uniqid() ;
$db->insert_session($sessionid, $session_data );
}
// add commands for access tables, and execute all collected
$exec_commands[] = "/sbin/ipfw table ". $ipfw_tables["in"] ." add ". $clientip . " ".$pipeno_in;
$exec_commands[] = "/sbin/ipfw table ". $ipfw_tables["out"] ." add ". $clientip . " ".$pipeno_out;
$this->shell->exec($exec_commands, false,false);
// lock the user/ip to it's MAC address using arp
$arp->setStatic($clientip,$clientmac);
// add accounting rule
$this->add_accounting($zoneid,$clientip);
// cleanup
unset($db);
}
/**
* disconnect a session or a list of sessions depending on the parameter
* @param string $cpzonename zone name or id
* @param $sessionid
*/
public function disconnect($cpzonename,$sessionid){
if ( is_array($sessionid)){
foreach($sessionid as $sessid ){
$this->_disconnect($cpzonename,$sessid);
}
}
else{
$this->_disconnect($cpzonename,$sessionid);
}
}
/**
* flush zone (null flushes all zones)
* @param null $zone
*/
function flush($zone=null){
if ( $zone == null ) {
$shell = new \Core\Shell();
$shell->exec("/sbin/ipfw -f table all flush");
}
else{
// find zoneid for this named zone
if (preg_match("/^[0-9]{1,2}$/", trim($zone)) ) {
$zoneid = $zone;
}else {
$zoneid = -1;
foreach ($this->config->object()->captiveportal->children() as $zonenm => $zoneobj) {
if ($zonenm == $zone) $zoneid = $zoneobj->zoneid;
}
}
if ( $zoneid != -1 ){
$exec_commands= array(
"/sbin/ipfw -f table ".$this->rules->getAuthUsersTables($zoneid)["in"]." flush",
"/sbin/ipfw -f table ".$this->rules->getAuthUsersTables($zoneid)["out"]." flush",
"/sbin/ipfw -f table ".$this->rules->getAuthIPTables($zoneid)["in"]." flush",
"/sbin/ipfw -f table ".$this->rules->getAuthIPTables($zoneid)["out"]." flush",
"/sbin/ipfw -f table ".$this->rules->getAuthMACTables($zoneid)["in"]." flush",
"/sbin/ipfw -f table ".$this->rules->getAuthMACTables($zoneid)["out"]." flush",
"/sbin/ipfw delete set ".$zoneid,
);
$this->shell->exec($exec_commands, false,false);
}
}
}
}

View File

@ -0,0 +1,327 @@
<?php
/**
* User: ad
* Date: 08-12-14
* Time: 18:11
*/
namespace Captiveportal;
/**
* Class DB, handles captive portal zone's adminstration
* @package Captiveportal
*/
class DB {
/**
* zone name
* @var string
*/
private $zone = null ;
/**
* database handle
* @var SQLite3
*/
private $handle = null ;
/**
* datatypes for captive portal table
* @var array
*/
private $captiveportal_types = array(
"allow_time" => \PDO::PARAM_INT,
"pipeno_in" => \PDO::PARAM_INT,
"pipeno_out" => \PDO::PARAM_INT,
"ip" => \PDO::PARAM_STR,
"mac" => \PDO::PARAM_STR,
"username" => \PDO::PARAM_STR,
"sessionid" => \PDO::PARAM_STR,
"bpassword" => \PDO::PARAM_STR,
"session_timeout" => \PDO::PARAM_INT,
"idle_timeout" => \PDO::PARAM_INT,
"session_terminate_time" => \PDO::PARAM_INT,
"interim_interval" => \PDO::PARAM_INT,
"radiusctx" => \PDO::PARAM_STR);
/**
* datatypes for captive portal mac table
* @var array
*/
private $captiveportal_mac_types=array(
"mac" => \PDO::PARAM_STR,
"ip" => \PDO::PARAM_STR,
"pipeno_in" => \PDO::PARAM_INT,
"pipeno_out" => \PDO::PARAM_INT,
"last_checked" => \PDO::PARAM_INT);
/**
* datatypes for captive portal ip table
* @var array
*/
private $captiveportal_ip_types=array(
"ip" => \PDO::PARAM_STR,
"pipeno_in" => \PDO::PARAM_INT,
"pipeno_out" => \PDO::PARAM_INT,
"last_checked" => \PDO::PARAM_INT);
/**
* open / create new captive portal database for zone
* @param $zone zone name
*/
function __construct($zone)
{
$this->zone = $zone ;
$this->open();
}
/**
* destruct, close sessions
*/
function __destruct() {
if ( $this->handle != null){
$this->handle->close();
}
}
/**
* open database, on failure send message tot syslog
* creates structure needed for this captiveportal zone
* @return SQLite3
*/
function open(){
// open database
$db_path = \Phalcon\DI\FactoryDefault::getDefault()->get('config')->globals->vardb_path ."/captiveportal".$this->zone.".db" ;
try {
$this->handle = new \Phalcon\Db\Adapter\Pdo\Sqlite(array("dbname" => $db_path));
// create structure on new database
if (!$this->handle->execute("CREATE TABLE IF NOT EXISTS captiveportal (" . # table used for authenticated users
"allow_time INTEGER, pipeno_in INTEGER, pipeno_out INTEGER, ip TEXT, mac TEXT, username TEXT, " .
"sessionid TEXT, bpassword TEXT, session_timeout INTEGER, idle_timeout INTEGER, " .
"session_terminate_time INTEGER, interim_interval INTEGER, radiusctx TEXT); " .
"CREATE UNIQUE INDEX IF NOT EXISTS idx_active ON captiveportal (sessionid, username); " .
"CREATE INDEX IF NOT EXISTS user ON captiveportal (username); " .
"CREATE INDEX IF NOT EXISTS ip ON captiveportal (ip); " .
"CREATE INDEX IF NOT EXISTS starttime ON captiveportal (allow_time);".
"CREATE TABLE IF NOT EXISTS captiveportal_mac (" . # table used for static mac's
"mac TEXT, ip TEXT,pipeno_in INTEGER, pipeno_out INTEGER, last_checked INTEGER );" .
"CREATE UNIQUE INDEX IF NOT EXISTS idx_mac ON captiveportal_mac (mac) ;".
"CREATE TABLE IF NOT EXISTS captiveportal_ip (" . # table used for static ip's
"ip TEXT,pipeno_in INTEGER, pipeno_out INTEGER, last_checked INTEGER );" .
"CREATE UNIQUE INDEX IF NOT EXISTS idx_ip ON captiveportal_ip (ip) "
)
) {
$logger = new \Phalcon\Logger\Adapter\Syslog("logportalauth", array(
'option' => LOG_PID,
'facility' => LOG_LOCAL4
));
$logger->error("Error during table {$this->zone} creation. Error message: {$this->handle->lastErrorMsg()}");
$this->handle = null ;
}
}catch (\Exception $e) {
$logger = new \Phalcon\Logger\Adapter\Syslog("logportalauth", array(
'option' => LOG_PID,
'facility' => LOG_LOCAL4
));
$logger->error("Error opening database for zone " . $this->zone . " : ".$e->getMessage()." ");
$this->handle = null ;
}
return $this->handle;
}
/**
* remove session(s) from database
* @param $sessionids session ids ( or id )
*/
function remove_session($sessionids){
if ( $this->handle != null ){
if ( is_array($sessionids) ) $tmpids = $sessionids;
else $tmpids = array($sessionids);
$this->handle->begin() ;
$stmt = $this->handle->prepare('DELETE FROM captiveportal WHERE sessionid = :sessionid');
foreach( $tmpids as $session ) {
$this->handle->executePrepared($stmt, array('sessionid' => $session),array("sessionid"=>\PDO::PARAM_STR));
$stmt->execute();
}
$this->handle->commit() ;
}
}
/**
*
* @param string $sessionid session id
* @param Array() $content data to alter ( fields from "captiveportal")
*/
function update_session($sessionid,$content){
if ( $this->handle != null ) {
$query = "update captiveportal set ";
$bind_values = Array("sessionid" => $sessionid);
foreach ($content as $fieldname => $fieldvalue) {
// you may not alter data not described in $this->captiveportal_types
if (array_key_exists($fieldname, $this->captiveportal_types)) {
if (sizeof($bind_values) > 1) $query .= " , ";
$query .= $fieldname." = "." :".$fieldname." ";
$bind_values[$fieldname] = $fieldvalue;
}
}
$query .= " where sessionid = :sessionid ";
try {
$this->handle->execute($query, $bind_values, $this->captiveportal_types);
} catch (\Exception $e) {
$logger = new \Phalcon\Logger\Adapter\Syslog("logportalauth", array(
'option' => LOG_PID,
'facility' => LOG_LOCAL4
));
$logger->error("Trying to modify DB returned error (zone = " . $this->zone . " ) : " . $e->getMessage() . " ");
}
}
}
/**
* insert new session information into this zone's database
*
* @param string $sessionid unique session id
* @param Array() field content ( defined fields in "captiveportal")
*/
function insert_session($sessionid,$content){
if ( $this->handle != null ) {
// construct insert query, using placeholders for bind variables
$bind_values = Array("sessionid" => $sessionid);
$query = "insert into captiveportal (sessionid ";
$query_values = "values (:sessionid ";
foreach ($content as $fieldname => $fieldvalue) {
// you may not alter data not described in $this->captiveportal_types
if (array_key_exists($fieldname, $this->captiveportal_types)) {
$query .= "," . $fieldname . " ";
$query_values .= ", :" . $fieldname;
$bind_values[$fieldname] = $fieldvalue;
}
}
$query .= " ) " . $query_values . ") ";
try {
$this->handle->execute($query, $bind_values, $this->captiveportal_types);
} catch (\Exception $e) {
$logger = new \Phalcon\Logger\Adapter\Syslog("logportalauth", array(
'option' => LOG_PID,
'facility' => LOG_LOCAL4
));
$logger->error("Trying to modify DB returned error (zone = " . $this->zone . " ) : " . $e->getMessage() . " ");
}
}
}
/**
* get captive portal clients
* @param Array() $args
*/
function listClients($qryargs,$operator="and"){
// construct query, only parse fields defined by $this->captiveportal_types
$qry_tag = "where " ;
$query = "select * from captiveportal ";
foreach ( $qryargs as $fieldname => $fieldvalue ){
if ( array_key_exists($fieldname,$this->captiveportal_types) ){
$query .= $qry_tag . $fieldname." = "." :".$fieldname." ";
$qry_tag = " ".$operator." ";
}
}
$resultset = $this->handle->query($query, $qryargs, $this->captiveportal_types);
$resultset->setFetchMode(\Phalcon\Db::FETCH_OBJ);
return $resultset->fetchAll();
}
/**
* list all fixed ip addresses for this zone
*
* @return Array()
*/
function listFixedIPs(){
$result = array();
if ($this->handle != null ) {
$resultset = $this->handle->query("select ip,pipeno_in,pipeno_out,last_checked from captiveportal_ip");
$resultset->setFetchMode(\Phalcon\Db::FETCH_OBJ);
foreach ($resultset->fetchAll() as $record) {
$result[$record->ip] = $record;
}
}
return $result;
}
/**
* insert new passthru mac address
* @param $ip hosts ip address
*/
function upsertFixedIP($ip,$pipeno_in=null,$pipeno_out=null){
// perform an upsert to update the data for this physical host.
// unfortunately this costs an extra write io for the first record, but provides cleaner code
$params = array("ip"=>$ip,"pipeno_in"=>$pipeno_in,"pipeno_out"=>$pipeno_out,"last_checked"=>time());
$this->handle->execute("insert or ignore into captiveportal_ip(ip) values (:ip)", array("ip"=>$ip),$this->captiveportal_ip_types);
$this->handle->execute("update captiveportal_ip set ip=:ip, last_checked=:last_checked, pipeno_in = :pipeno_in, pipeno_out = :pipeno_out where ip =:ip ", $params,$this->captiveportal_ip_types);
}
/**
* drop address from administration (captiveportal_ip)
* @param $mac physical address
*/
function dropFixedIP($ip){
$this->handle->execute("delete from captiveportal_ip where ip =:ip ", array("ip"=>$ip),$this->captiveportal_ip_types);
}
/**
* list all passthru mac addresses for this zone
*
* @return Array()
*/
function listPassthruMacs(){
$result = array();
if ($this->handle != null ) {
$resultset = $this->handle->query("select mac,ip,last_checked,pipeno_in,pipeno_out from captiveportal_mac");
$resultset->setFetchMode(\Phalcon\Db::FETCH_OBJ);
foreach ($resultset->fetchAll() as $record) {
$result[$record->mac] = $record;
}
}
return $result;
}
/**
* insert new passthru mac address
* @param $mac physical address
* @param $ip hosts ip address
*/
function upsertPassthruMAC($mac,$ip,$pipeno_in=null,$pipeno_out=null){
// perform an upsert to update the data for this physical host.
// unfortunately this costs an extra write io for the first record, but provides cleaner code
$params = array("mac"=>$mac,"ip"=>$ip,"pipeno_in"=>$pipeno_in,"pipeno_out"=>$pipeno_out,"last_checked"=>time());
$this->handle->execute("insert or ignore into captiveportal_mac(mac) values (:mac)", array("mac"=>$mac),$this->captiveportal_mac_types);
$this->handle->execute("update captiveportal_mac set ip=:ip, last_checked=:last_checked, pipeno_in = :pipeno_in, pipeno_out = :pipeno_out where mac =:mac ", $params,$this->captiveportal_mac_types);
}
/**
* drop address from administration (captiveportal_mac)
* @param $mac physical address
*/
function dropPassthruMAC($mac){
$this->handle->execute("delete from captiveportal_mac where mac =:mac ", array("mac"=>$mac),$this->captiveportal_mac_types);
}
}

View File

@ -0,0 +1,296 @@
<?php
/**
* Created by PhpStorm.
* User: ad
* Date: 05-12-14
* Time: 11:28
*/
namespace Captiveportal;
/**
* Class Rules
* @package Captiveportal
*/
class Rules {
/**
* config handle
* @var Core_Config
*/
private $config = null;
/**
* generated ruleset
* @var array
*/
private $rules = [] ;
/**
*
*/
function __construct()
{
// Request handle to configuration
$this->config = \Core\Config::getInstance();
}
/**
* get ipfw tables for authenticated users ( in/out )
* @param $zoneid zoneid (number)
* @return array
*/
function getAuthUsersTables($zoneid){
return array("in"=>(6*($zoneid-1) )+1,"out"=>(6*($zoneid-1) )+2);
}
/**
* get ipfw tables for authenticated hosts ( in/out )
* @param $zoneid zoneid (number)
* @return array
*/
function getAuthIPTables($zoneid){
return array("in"=>(6*($zoneid-1) )+3,"out"=>(6*($zoneid-1) )+4);
}
/**
* get ipfw tables used for authenticated physical addresses
* @param $zoneid zoneid (number)
* @return array
*/
function getAuthMACTables($zoneid){
return array("in"=>(6*($zoneid-1) )+5,"out"=>(6*($zoneid-1) )+6);
}
/**
* default rules
* rule number range 1..1000
*/
private function generate_default_rules(){
// define general purpose rules, rule number 1 .... 1000
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "# flush ruleset ";
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "flush" ;
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "# general purpose rules 1...1000 ";
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "add 100 allow pfsync from any to any";
$this->rules[] = "add 110 allow carp from any to any";
$this->rules[] = "# layer 2: pass ARP";
$this->rules[] = "add 120 pass layer2 mac-type arp,rarp";
$this->rules[] = "# OPNsense requires for WPA";
$this->rules[] = "add 130 pass layer2 mac-type 0x888e,0x88c7";
$this->rules[] = "# PPP Over Ethernet Session Stage/Discovery Stage";
$this->rules[] = "add 140 pass layer2 mac-type 0x8863,0x8864";
$this->rules[] = "# layer 2: block anything else non-IP(v4/v6)";
$this->rules[] = "add 150 deny layer2 not mac-type ip,ipv6";
}
/**
* Always allow traffic to our own host ( all static addresses from configuration )
* rule number range 1001..1999
*/
private function generate_this_host_rules(){
// search all static / non wan addresses and add rules to $this->rules
$rulenum = 1001 ;
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "# Allow traffic to this hosts static ip's ( 1001..1999 ) ";
$this->rules[] = "#=========================================================================================================";
foreach( $this->config->object()->interfaces->children() as $interface => $content ){
if ( $interface != "wan" && $content->ipaddr != "dhcp" ){
$this->rules[] = "add ".$rulenum++." allow ip from any to { 255.255.255.255 or ".$content->ipaddr." } in";
$this->rules[] = "add ".$rulenum++." allow ip from { 255.255.255.255 or ".$content->ipaddr." } to any out";
$this->rules[] = "add ".$rulenum++." allow icmp from { 255.255.255.255 or ".$content->ipaddr." } to any out icmptypes 0";
$this->rules[] = "add ".$rulenum++." allow icmp from any to { 255.255.255.255 or ".$content->ipaddr." } in icmptypes 8";
}
}
}
/**
* generate zone rules, 4 ipfw tables per zone ( in/out, by host or address )
* The tables are calculcated by zoneid using the getAuthxxxTables methods :
* 1. authenticated users in
* 2. authenticated users out
* 3. allowed ip's in
* 4. allowed ip's out
* 5. allowed mac addresses in ( table contains corresponding ip's )
* 6. allowed mac addresses out ( table contains corresponding ip's )
*
* A pipe to dummynet is automatically created for every stream
*
* Every zone receives it's own ruleset range of max 998 rules, defined by a starting position of 10.000
* ( for example: zone 2 starts @ 12000 )
*
* rule number ranges 3001..3999, 10000...50000
*/
private function generate_zones(){
foreach( $this->config->object()->captiveportal->children() as $cpzonename => $zone ) {
// search interface
$interface = $zone->interface->xpath("//" . $zone->interface);
// allocate tables for captive portal
$table_id = (6*($zone->zoneid-1) );
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "# zone " . $cpzonename . " (".$zone->zoneid.") configuration";
$this->rules[] = "#=========================================================================================================";
if (count($interface) > 0) {
$interface = $interface[0];
// authenticated users ( table 1 + 2 )
$this->rules[] = "add ".(3000+($zone->zoneid*10)+1)." skipto ".((($zone->zoneid*1000)+10000)+1)." ip from table(".$this->getAuthUsersTables($zone->zoneid)["in"].") to any via ".$interface->if ;
$this->rules[] = "add ".(3000+($zone->zoneid*10)+2)." skipto ".((($zone->zoneid*1000)+10000)+1)." ip from any to table(".$this->getAuthUsersTables($zone->zoneid)["in"].") via ".$interface->if ;
// authenticated hosts ( table 3 + 4 )
$this->rules[] = "add ".(3000+($zone->zoneid*10)+3)." skipto ".((($zone->zoneid*1000)+10000)+1)." ip from table(".$this->getAuthIPTables($zone->zoneid)["in"].") to any via ".$interface->if ;
$this->rules[] = "add ".(3000+($zone->zoneid*10)+4)." skipto ".((($zone->zoneid*1000)+10000)+1)." ip from any to table(".$this->getAuthIPTables($zone->zoneid)["in"].") via ".$interface->if ;
// authenticated mac addresses ( table 5 + 6 )
$this->rules[] = "add ".(3000+($zone->zoneid*10)+5)." skipto ".((($zone->zoneid*1000)+10000)+1)." ip from table(".$this->getAuthMACTables($zone->zoneid)["in"].") to any via ".$interface->if ;
$this->rules[] = "add ".(3000+($zone->zoneid*10)+6)." skipto ".((($zone->zoneid*1000)+10000)+1)." ip from any to table(".$this->getAuthMACTables($zone->zoneid)["in"].") via ".$interface->if ;
// TODO: solve dummynet kernel issue on outgoing traffic
// // dummynet 1,2
// $this->rules[] = "add ".((($zone->zoneid*1000)+10000)+1)." pipe tablearg ip from table(".($table_id+1).") to any in via ".$interface->if ;
// $this->rules[] = "add ".((($zone->zoneid*1000)+10000)+2)." pipe tablearg ip from any to table(".($table_id+2).") out via ".$interface->if ;
//
// // dummynet 3,4
// $this->rules[] = "add ".((($zone->zoneid*1000)+10000)+3)." pipe tablearg ip from table(".($table_id+3).") to any in via ".$interface->if ;
// $this->rules[] = "add ".((($zone->zoneid*1000)+10000)+4)." pipe tablearg ip from table(".($table_id+3).") to any out via ".$interface->if ;
// $this->rules[] = "add ".((($zone->zoneid*1000)+10000)+5)." pipe tablearg ip from any to table(".($table_id+4).") in via ".$interface->if ;
// $this->rules[] = "add ".((($zone->zoneid*1000)+10000)+6)." pipe tablearg ip from any to table(".($table_id+4).") out via ".$interface->if ;
// // dummynet 5,6
// $this->rules[] = "add ".((($zone->zoneid*1000)+10000)+7)." pipe tablearg ip from table(".($table_id+5).") to any in via ".$interface->if ;
// $this->rules[] = "add ".((($zone->zoneid*1000)+10000)+8)." pipe tablearg ip from table(".($table_id+5).") to any out via ".$interface->if ;
// $this->rules[] = "add ".((($zone->zoneid*1000)+10000)+9)." pipe tablearg ip from any to table(".($table_id+6).") in via ".$interface->if ;
// $this->rules[] = "add ".((($zone->zoneid*1000)+10000)+10)." pipe tablearg ip from any to table(".($table_id+6).") out via ".$interface->if ;
// statistics for this zone, placeholder to jump to
$this->rules[] = "add ".((($zone->zoneid*1000)+10000)+1)." count ip from any to any via ".$interface->if ;
// jump to accounting section
$this->rules[] = "add ".((($zone->zoneid*1000)+10000)+998)." skipto 30000 all from any to any via ".$interface->if ;
$this->rules[] = "add ".((($zone->zoneid*1000)+10000)+999)." deny all from any to any not via ".$interface->if ;
}
}
}
/**
* Forward all non authenticated traffic from captive portal zones
* rule number range 5001..5999
*/
private function generate_reflect_rules(){
$forward_port = 8000 ;
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "# redirect non-authenticated clients to captive portal @ local port ".$forward_port." + zoneid ";
$this->rules[] = "#=========================================================================================================";
foreach( $this->config->object()->captiveportal->children() as $cpzonename => $zone ){
// search interface
$interface = $zone->interface->xpath("//".$zone->interface);
if (count($interface) > 0){
$interface = $interface[0] ;
if ($interface->ipaddr != null){
// add forward rule to this zone's http instance @ $forward_port + $zone->zoneid
$this->rules[] ="add ".(5000+$zone->zoneid)." fwd 127.0.0.1,".($forward_port + $zone->zoneid )." tcp from any to any dst-port 80 in via ".$interface->if;
}
}
}
}
/**
* for accounting statistics we setup a separate section in our config
* rule number range 30000..65500
*/
private function generate_accounting_section(){
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "# setup accounting section, first rule is counting all CP traffic ";
$this->rules[] = "# rule 65500 unlocks the traffic already authorized from a CP zone";
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "add 30000 set 0 count ip from any to any ";
$this->rules[] = "add 65500 pass ip from any to any ";
}
/**
* generate closure tag, block all traffic coming from captiveportal interfaces
* rule number range 6001..6999
*/
private function generate_closure(){
$cpinterfaces = [];
# find all cp interfaces
foreach( $this->config->object()->captiveportal->children() as $cpzonename => $zone ) {
// search interface
$interface = $zone->interface->xpath("//" . $zone->interface);
if (count($interface) > 0) {
$interface = $interface[0];
$cpinterfaces[$interface->if->__toString()] = 1;
}
}
// generate accept rules for every interface not in captive portal
$ruleid = 6001 ;
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "# accept traffic from all interfaces not used by captive portal (5001..5999) ";
$this->rules[] = "#=========================================================================================================";
foreach( $this->config->object()->interfaces->children() as $interface => $content ){
if ( !isset($cpinterfaces[$content->if->__toString()])){
$this->rules[] = "add ".($ruleid++)." allow all from any to any via ".$content->if ;
}
}
$this->rules[] = "# let the responses from the captive portal web server back out";
$this->rules[] = "add ".($ruleid++)." pass tcp from any to any out";
// block every thing else (not mentioned before)
$this->rules[] = "# block everything else";
$this->rules[] = "add ".($ruleid)." skipto 65534 all from any to any";
$this->rules[] = "add 65534 deny all from any to any";
}
/**
* load ruleset
*/
public function generate($filename){
/*
* reset rules
*/
$this->rules = [] ;
/*
* generate new
*/
$this->generate_default_rules();
$this->generate_this_host_rules();
$this->generate_zones();
$this->generate_reflect_rules();
$this->generate_accounting_section();
$this->generate_closure();
// ruleset array -> text
$ruleset_txt = "";
$prev_rule = "#";
foreach($this->rules as $rule){
if (trim($rule)[0] == '#' && trim($prev_rule)[0] != "#" ) $ruleset_txt .= "\n";
$ruleset_txt .= $rule."\n";
$prev_rule = $rule ;
}
// write to file
file_put_contents($filename,$ruleset_txt);
}
}

View File

@ -0,0 +1,130 @@
<?php namespace Core;
/**
* Class ConfigException
* @package Core
*/
class ConfigException extends \Exception { }
/**
* Class Config
* @package Core
*/
class Config extends \Core\Singleton {
/**
* config file location ( path + name )
* @var string
*/
private $config_file = "";
/**
* XMLDocument type reference to config
* @var XMLDocument
*/
private $configxml = null ;
/**
* SimpleXML type reference to config
* @var SimpleXML
*/
private $simplexml = null;
/**
* status field: valid config loaded
* @var bool
*/
private $isValid = False;
/**
* Load config file
* @throws ConfigException
*/
private function load(){
// exception handling
if ( !file_exists($this->config_file) ) throw new ConfigException('file not found') ;
$xml = file_get_contents($this->config_file);
if (trim($xml) == '') {
throw new ConfigException('empty file') ;
}
$this->configxml = new \DOMDocument;
$this->configxml->loadXML($xml);
$this->simplexml = simplexml_import_dom($this->configxml);
$this->isValid = true;
}
/**
* @throws ConfigException
*/
private function checkvalid(){
if ( !$this->isValid ) throw new ConfigException('no valid config loaded') ;
}
/*
* parse configuration and dump to std output (test)
* @param DOMElement $node
* @param string $nodename
* @throws ConfigException
*/
public function dump($node=null,$nodename=""){
$this->checkvalid();
// root node
if ($node == null ) $node = $this->configxml;
$subNodes = $node->childNodes ;
foreach($subNodes as $subNode){
if ( $subNode->nodeType == XML_TEXT_NODE &&(strlen(trim($subNode->wholeText))>=1)) {
print($nodename.".". $node->tagName." " .$subNode->nodeValue ."\n");
}
if ( $subNode->hasChildNodes() ){
if ( $nodename != "" ) $tmp = $nodename.".".$node->tagName;
elseif ($node != $this->configxml) $tmp = $node->tagName;
else $tmp = "";
$this->dump($subNode,$tmp);
}
}
}
/*
* init new config object, try to load current configuration
* (executed via Singleton)
*/
protected function init() {
$this->config_file = \Phalcon\DI\FactoryDefault::getDefault()->get('config')->globals->config_path . "config.xml";
try {
$this->load();
} catch (\Exception $e){
$this->configxml = null ;
}
}
/*
* Execute a xpath expression on config.xml
* @param $query
* @return \DOMNodeList
* @throws ConfigException
*/
function xpath($query){
$this->checkvalid();
$xpath = new \DOMXPath($this->configxml);
return $xpath->query($query);
}
/*
* object representation of xml document via simplexml, references the same underlying model
* @return SimpleXML
* @throws ConfigException
*/
function object(){
$this->checkvalid();
return $this->simplexml;
}
}

View File

@ -0,0 +1,101 @@
<?php
/**
* Created by PhpStorm.
* User: ad
* Date: 08-12-14
* Time: 08:41
*/
namespace Core;
class Shell
{
/**
* simulation mode, only print commands, dom not execute
* @var bool
*/
private $simulate = false;
/**
* debug mode
* @var bool
*/
private $debug = false;
/**
* new shell object
*/
function __construct()
{
// init, set simulation mode / debug autoput
$this->simulate = \Phalcon\DI\FactoryDefault::getDefault()->get('config')->globals->simulate_mode;
$this->debug = \Phalcon\DI\FactoryDefault::getDefault()->get('config')->globals->debug;
}
/**
* execute shell command
* @param string $command command to execute
* @param bool $mute
* @param bool $clearsigmask
*/
private function _exec($command, $mute = false, $clearsigmask = false,&$output=null){
$oarr = array();
$retval = 0;
// debug output
if ($this->debug) {
print("Shell->exec : " . $command . " \n");
}
// only execute actual command if not in simulation mode
if (!$this->simulate) {
if ($clearsigmask) {
$oldset = array();
pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
}
$garbage = exec("$command 2>&1", $output, $retval);
if (($retval <> 0) && ($mute === false)) {
//log_error(sprintf(gettext("The command '%1\$s' returned exit code '%2\$d', the output was '%3\$s' "), implode(" ", $output);
// TODO: log
unset($output);
}
if ($clearsigmask) {
pcntl_sigprocmask(SIG_SETMASK, $oldset);
}
unset($oarr);
return $retval;
}
return null;
}
/**
* execute command or list of commands
*
* @param string/Array() $command command to execute
* @param bool $mute
* @param bool $clearsigmask
* @param Array() &$output
*/
function exec($command, $mute = false, $clearsigmask = false,&$output=null)
{
if (is_array($command)){
foreach($command as $comm ){
$this->_exec($comm,$mute, $clearsigmask ,$output);
}
}
else{
$this->_exec($command,$mute, $clearsigmask ,$output);
}
}
}

View File

@ -0,0 +1,68 @@
<?php
/**
* Created by PhpStorm.
* User: ad
* Date: 05-12-14
* Time: 10:35
*/
namespace Core;
/**
* Class Singleton
* @package Core
*/
/**
* Class Singleton
* @package Core
*/
abstract class Singleton
{
/**
* holder for singleton objects
* @var static
*/
private static $instances;
/**
* Cannot construct Singleton, use getInstance instead
*/
final private function __construct()
{
// call init on newly created object
static::init();
}
/**
* Do not clone
* @throws Exception
*/
final private function __clone()
{
throw new \Exception("An instance of ".get_called_class()." cannot be cloned.");
}
/**
* get (new) instance
* @return object
*/
public static function getInstance()
{
$className = get_called_class();
if(isset(self::$instances[$className]) == false) {
self::$instances[$className] = new static();
}
return self::$instances[$className];
}
/**
* by default there must be an inherited init method
* so an extended class could simply
* specify its own init
*/
protected function init(){}
}

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Phalcon PHP Framework</title>
</head>
<body>
{{ content() }}
</body>
</html>

View File

@ -0,0 +1,3 @@
<h1>Congratulations!</h1>
<p>You're now flying with Phalcon. Great things are about to happen!</p>

View File

@ -0,0 +1,21 @@
<?php
/**
* User: ad
* Date: 08-12-14
* Time: 20:23
*/
use Phalcon\DI\FactoryDefault;
use Phalcon\Loader;
$di = new FactoryDefault();
$config = include_once(__DIR__."/../app/config/config.php");
$loader = new Loader();
$loader->registerDirs(
array(
$config->application->controllersDir,
$config->application->modelsDir
)
)->register();
$di->set('config',$config);

View File

@ -0,0 +1,38 @@
<?php
require_once("load_falcon.php");
$cpc = new Captiveportal\CPClient();
//$cpc->portal_allow("test","10.211.55.101","00:1C:42:49:B7:B2","Fritsx");
$cpc->disconnect("test",array("5489714eba263","gdsajhgadsjhg"));
//$cpc->reconfigure();
//$cpc->refresh_allowed_mac();
//$cpc->refresh_allowed_ips();
//$db = new Captiveportal\DB("test");
//$db->remove_session("XXX");
//$db->insert_session(100,1,"10.211.55.101","00:1C:42:49:B7:B2","frits","XXX","aksjdhaskjh", null,null, null,null, null);
//
//$clients = $db->listClients( array("sessionid" => "XXX") );
//
//foreach($clients as $client ){
// print($client->pipeno) ;
//}
//$arp = new \Captiveportal\ARP();
//$arp->setStatic("172.20.0.1",'00:1c:42:49:b7:b1');
//$arp->dropStatic("172.20.0.1");
//$config = \Core\Core\Config::getInstance();
//$config->dump();
//print_r($config->xpath('//pfsense/interfaces/*') );
//$rules= new \Core\Captiveportal\Rules();