Commit ad276991 authored by Ad Schellevis's avatar Ad Schellevis

code styling fixes (PSR) for captive new captive portal code

parent 6e46796a
......@@ -172,7 +172,7 @@ function portal_allow($clientip,$clientmac,$username,$password = null, $attribut
}
$sessionid = $cpc->portal_allow($cpzone,$clientip,$clientmac,$username,$password,$bw_up,$bw_down,$radiusctx,$session_timeout,$idle_timeout,$session_terminate_time,$interim_interval);
$sessionid = $cpc->portalAllow($cpzone,$clientip,$clientmac,$username,$password,$bw_up,$bw_down,$radiusctx,$session_timeout,$idle_timeout,$session_terminate_time,$interim_interval);
if (isset($config['captiveportal'][$cpzone]['radacct_enable']) && !empty($radiusservers[$radiusctx])) {
$acct_val = RADIUS_ACCOUNTING_START($pipeno, $username, $sessionid, $radiusservers[$radiusctx], $clientip, $clientmac);
......@@ -699,11 +699,11 @@ function captiveportal_prune_old() {
$cpcfg = $config['captiveportal'][$cpzone];
if ( !isset($cpcfg['radacct_enable'])) {
// cleanup session (default)
$cpc->portal_cleanup_sessions($cpzone);
$cpc->portalCleanupSessions($cpzone);
}else{
// cleanup sessions if radius accounting is enable
// TODO: this code needs a rewrite, probably the easiest thing todo is update the zone administration and run
// the normal cleanup (portal_cleanup_sessions) to detach both processes
// the normal cleanup (portalCleanupSessions) to detach both processes
//
$vcpcfg = $config['voucher'][$cpzone];
......
......@@ -41,7 +41,7 @@ class ARP
* pointer to shell object
* @var \Core\Shell
*/
private $shell ;
private $shell;
/**
* construct new ARP table handlers
......@@ -59,11 +59,9 @@ class ARP
public 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));
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));
}
}
}
......@@ -72,41 +70,46 @@ class ARP
* drop static arp entry
* @param $ipaddress hosts ipaddress
*/
function dropStatic($ipaddress){
public 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) );
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(){
public 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 ) ;
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 ;
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);
if (preg_match('/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/', trim($mac))) {
$result[$mac] = array('ip' => $ipaddress);
}
}
}
}
return $result;
}
}
......@@ -34,6 +34,8 @@
namespace OPNsense\CaptivePortal;
use \Phalcon\Logger\Adapter\Syslog;
use \Phalcon\DI\FactoryDefault;
use \OPNsense\Core;
/**
......@@ -41,14 +43,13 @@ use \OPNsense\Core;
* // TODO: CARP interfaces are probably not handled correctly
* @package CaptivePortal
*/
class CPClient {
class CPClient
{
/**
* config handle
* @var Core_Config
*/
private $config = null;
private $config = null;
/**
* ipfw rule object
......@@ -63,92 +64,53 @@ class CPClient {
private $shell = null;
/**
* send message to syslog
*
* @param $status
* @param $user
* @param $mac
* @param $ip
* @param string $message
*/
private function logportalauth($cpzonename, $user, $mac, $ip, $status, $message=""){
$message = trim($message);
$message = "Zone : {$cpzonename} {$status}: {$user}, {$mac}, {$ip}, {$message}";
$logger = new \Phalcon\Logger\Adapter\Syslog("logportalauth", array(
'option' => LOG_PID,
'facility' => LOG_LOCAL4
));
$logger->info($message);
}
/**
* Request new pipeno
* @return int
* Constructor
*/
private function new_ipfw_pipeno(){
// TODO: implement global pipe number assigment
return 999;
public function __construct()
{
// Request handle to configuration
$this->config = Core\Config::getInstance();
// generate new ruleset
$this->rules = new Rules();
// keep a link to the shell object
$this->shell = new Core\Shell();
}
/**
* reset bandwidth, if the current bandwidth is unchanged, do nothing
* reset traffic counters
*
* @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
* @param null $rulenum
*/
private function _disconnect($cpzonename,$sessionid){
$zoneid = -1;
foreach($this->config->object()->captiveportal->children() as $zone => $zoneobj){
if ($zone == $cpzonename) $zoneid = $zoneobj->zoneid;
public function zeroCounters($rulenum = null)
{
if ($rulenum != null and is_numeric($rulenum)) {
$this->shell->exec("/sbin/ipfw zero " . $rulenum);
} elseif ($rulenum == null) {
$this->shell->exec("/sbin/ipfw zero ");
}
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[0]->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);
}
}
/**
* load accounting rules into ruleset, used for reinitialisation of the ruleset.
* triggers add_accounting() for all active clients in all zones
* Reconfigure zones ( generate and load ruleset )
*/
private function loadAccounting()
public function reconfigure()
{
foreach ($this->config->object()->captiveportal->children() as $cpzonename => $zone)
{
$db = new DB($cpzonename);
foreach ($db->listClients(array()) as $client)
{
$this->add_accounting($zone->zoneid, $client->ip) ;
}
unset($db);
if ($this->isEnabled()) {
$ruleset_filename = 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();
// after reinit all accounting rules are vanished, reapply them for active sessions
$this->loadAccounting();
} else {
// captiveportal is disabled, flush all rules to be sure
$this->shell->exec("/sbin/ipfw -f flush");
}
}
......@@ -172,154 +134,31 @@ class CPClient {
}
}
/**
*
* @param $zoneid
* @param $ip
*/
public function add_accounting($zoneid,$ip){
// TODO: check processing 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);
}
}
/**
* list (ipfw) accounting information
* @return array (key = hosts ip)
*/
public function list_accounting($ipaddr=null){
$filter_cmd = "";
$result = array();
$shell_output = array();
if ( $ipaddr != null ) $filter_cmd =" | /usr/bin/grep ' " . $ipaddr ." '" ;
if ( $this->shell->exec("/sbin/ipfw -aT list ".$filter_cmd,false,false,$shell_output) == 0 ){
foreach( $shell_output as $line) {
if (strpos($line, ' count ip from') !== false) {
$parts = preg_split('/\s+/', $line);
if (count($parts) > 8 && $parts[7] != 'any' and strlen($parts[7]) > 5) {
$result[$parts[7]] = array(
"rulenum" => $parts[0],
"last_accessed" => (int)$parts[3],
"idle_time" => time() - (int)$parts[3],
"out_packets" => (int)$parts[1],
"in_packets" => (int)$parts[2]
);
}
}
}
}
return $result;
}
/**
* reset traffic counters
*
* @param null $rulenum
*/
public function zero_counters($rulenum=null){
if ( $rulenum != null and is_numeric($rulenum) ){
$this->shell->exec("/sbin/ipfw zero " . $rulenum );
}
elseif ( $rulenum == null ){
$this->shell->exec("/sbin/ipfw zero " );
}
}
/**
* Constructor
*/
function __construct() {
// Request handle to configuration
$this->config = Core\Config::getInstance();
// generate new ruleset
$this->rules = new Rules();
// keep a link to the shell object
$this->shell = new Core\Shell();
}
/**
* Reconfigure zones ( generate and load ruleset )
*/
public function reconfigure()
{
if ( $this->isEnabled() ) {
$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();
// after reinit all accounting rules are vanished, reapply them for active sessions
$this->loadAccounting();
} else {
// captiveportal is disabled, flush all rules to be sure
$this->shell->exec("/sbin/ipfw -f flush" );
}
}
/**
* 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);
public function update($zone = null)
{
$this->refreshAllowedIPs($zone);
$this->refreshAllowedMACs($zone);
}
/**
* refresh allowed ip's for defined zone ( null for all zones )
* @param string $zone
* @param string $cpzone
*/
public function refresh_allowed_ips($cpzone=null){
public function refreshAllowedIPs($cpzone = null)
{
$handled_addresses = array();
foreach( $this->config->object()->captiveportal->children() as $cpzonename => $zone ) {
foreach ($this->config->object()->captiveportal->children() as $cpzonename => $zone) {
// search requested zone (id)
if ( $cpzonename == $cpzone || $zone->zoneid == $cpzone || $cpzone == null ) {
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 );
$ipfw_tables = $this->rules->getAuthIPTables($zone->zoneid);
foreach ($zone->children() as $tagname => $tagcontent) {
$ip = $tagcontent->ip->__toString();
......@@ -328,25 +167,27 @@ class CPClient {
$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) ){
if (!array_key_exists($ip, $db_iplist)) {
// only insert new values
$pipeno_in = $this->new_ipfw_pipeno() ;
$pipeno_out = $this->new_ipfw_pipeno() ;
$pipeno_in = $this->newIPFWpipeno() ;
$pipeno_out = $this->newIPFWpipeno() ;
$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,
"/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);
$this->shell->exec($exec_commands, false, false);
// update administration
$db->upsertFixedIP($ip,$pipeno_in,$pipeno_out);
$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_out"] = $pipeno_out ;
} else {
//
$handled_addresses[$ip]["pipeno_in"] = $db_iplist[$ip]->pipeno_in ;
$handled_addresses[$ip]["pipeno_out"] = $db_iplist[$ip]->pipeno_out ;
......@@ -357,26 +198,28 @@ class CPClient {
// Cleanup deleted addresses
foreach($db_iplist as $ip => $record){
if (!array_key_exists($ip,$handled_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() ,
"/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);
$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"]);
foreach ($handled_addresses as $mac => $record) {
if (array_key_exists("pipeno_in", $record)) {
$this->resetBandwidth($record["pipeno_in"], $record["bw_down"]);
$this->resetBandwidth($record["pipeno_out"], $record["bw_up"]);
}
}
......@@ -386,13 +229,37 @@ class CPClient {
}
/**
* Request new pipeno
* @return int
*/
private function newIPFWpipeno()
{
// 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
* @return status
*/
private function resetBandwidth($pipeno, $bw)
{
//TODO : setup bandwidth for sessions ( check changed )
//#pipe 2000 config bw 2000Kbit/s
return false;
}
/**
* 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
* @param string $cpzone zone name or number
*/
public function refresh_allowed_mac($cpzone=null){
public function refreshAllowedMACs($cpzone = null)
{
// read ARP table
$arp= new ARP();
......@@ -400,8 +267,8 @@ class CPClient {
// 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 ) {
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();
......@@ -420,44 +287,59 @@ class CPClient {
// 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) ) {
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'] ) {
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,
"/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,
"/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);
$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
$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 {
} 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() ;
$pipeno_in = $this->newIPFWpipeno() ;
$pipeno_out = $this->newIPFWpipeno() ;
// 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,
"/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);
$this->shell->exec($exec_commands, false, false);
$db->upsertPassthruMAC($tagcontent->mac,$arp_maclist[$mac]['ip'],$pipeno_in,$pipeno_out);
$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 ;
......@@ -471,24 +353,26 @@ class CPClient {
//
// cleanup old addresses
//
foreach($db_maclist as $mac => $record){
if ( !array_key_exists($mac,$handled_mac_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,
"/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);
$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"]);
foreach ($handled_mac_addresses as $mac => $record) {
if (array_key_exists("pipeno_in", $record)) {
$this->resetBandwidth($record["pipeno_in"], $record["bw_down"]);
$this->resetBandwidth($record["pipeno_out"], $record["bw_up"]);
}
}
......@@ -499,18 +383,97 @@ class CPClient {
}
/**
* load accounting rules into ruleset, used for reinitialisation of the ruleset.
* triggers addAccounting() for all active clients in all zones
*/
private function loadAccounting()
{
foreach ($this->config->object()->captiveportal->children() as $cpzonename => $zone) {
$db = new DB($cpzonename);
foreach ($db->listClients(array()) as $client) {
$this->addAccounting($zone->zoneid, $client->ip) ;
}
unset($db);
}
}
/**
* add accounting rules for ip
* @param int $zoneid zone
* @param string $ip ip address
*/
public function addAccounting($zoneid, $ip)
{
// TODO: check processing 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);
}
}
/**
* unlock host for captiveportal use
*
* @param string $cpzonename
* @param string $clientip
* @param string $clientmac
* @param string $username
* @param string $password
* @param string $attributes
* @param string $bw_up
* @param string $bw_down
* @param string $radiusctx
* @param int $session_timeout
* @param int $idle_timeout
* @param int $session_terminate_time
* @param int $interim_interval
* @return bool|string
*/
public function portal_allow($cpzonename,$clientip,$clientmac,$username,$password = null,$bw_up=null,$bw_down=null, $radiusctx = null,$session_timeout=null,$idle_timeout=null,$session_terminate_time=null,$interim_interval=null){
public function portalAllow(
$cpzonename,
$clientip,
$clientmac,
$username,
$password = null,
$bw_up = null,
$bw_down = null,
$radiusctx = null,
$session_timeout = null,
$idle_timeout = null,
$session_terminate_time = null,
$interim_interval = null
) {
// defines
$exec_commands = array() ;
$db = new DB($cpzonename);
......@@ -518,27 +481,35 @@ class CPClient {
// find zoneid for this named zone
$zoneid = -1;
foreach($this->config->object()->captiveportal->children() as $zone => $zoneobj){
if ($zone == $cpzonename) $zoneid = $zoneobj->zoneid;
foreach ($this->config->object()->captiveportal->children() as $zone => $zoneobj) {
if ($zone == $cpzonename) {
$zoneid = $zoneobj->zoneid;
}
}
if ($zoneid == -1) return; // not a valid zone, bailout
if ($zoneid == -1) {
return false; // 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 ) ){
$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 $cp_table[0]->sessionid;
} elseif ( sizeof($cp_table) > 0) {
} 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)
// 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;
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;
......@@ -546,26 +517,25 @@ class CPClient {
// 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);
if (sizeof($remove_sessions)) {
$db->removeSession($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));
$db->updateSession($current_session->sessionid, array("ip"=>$clientip, "mac"=>$clientmac));
// preserve session for response
$sessionid = $current_session->sessionid;
} else
{
} else {
// new session, allocate new dummynet pipes and generate a unique id
$pipeno_in = $this->new_ipfw_pipeno();
$pipeno_out = $this->new_ipfw_pipeno();
$pipeno_in = $this->newIPFWpipeno();
$pipeno_out = $this->newIPFWpipeno();
// construct session data
$session_data=Array();
$session_data=array();
$session_data["ip"]=$clientip;
$session_data["mac"]=$clientmac;
$session_data["pipeno_in"] = $pipeno_in;
......@@ -580,27 +550,27 @@ class CPClient {
$session_data["allow_time"] = time(); // allow time is actual starting time of this session
$sessionid = uniqid() ;
$db->insert_session($sessionid, $session_data );
$db->insertSession($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);
$this->shell->exec($exec_commands, false, false);
// lock the user/ip to it's MAC address using arp
$arp->setStatic($clientip,$clientmac);
$arp->setStatic($clientip, $clientmac);
// add accounting rule
$this->add_accounting($zoneid,$clientip);
$this->addAccounting($zoneid, $clientip);
// set bandwidth restrictions
$this->reset_bandwidth($pipeno_in,$bw_up);
$this->reset_bandwidth($pipeno_in,$bw_down);
$this->resetBandwidth($pipeno_in, $bw_up);
$this->resetBandwidth($pipeno_in, $bw_down);
// log
$this->logportalauth($cpzonename, $username, $clientmac, $clientip, $status="LOGIN");
$this->logportalauth($cpzonename, $username, $clientmac, $clientip, $status = "LOGIN");
// cleanup
unset($db);
......@@ -609,42 +579,49 @@ class CPClient {
}
/**
* disconnect a session or a list of sessions depending on the parameter
* @param string $cpzonename zone name or id
* @param $sessionid
* send message to syslog
* @param string $cpzonename
* @param string $user
* @param string $mac
* @param string $ip
* @param string $status
* @param string $message
*/
public function disconnect($cpzonename,$sessionid){
if ( is_array($sessionid)){
foreach($sessionid as $sessid ){
$this->_disconnect($cpzonename,$sessid);
}
}
else{
$this->_disconnect($cpzonename,$sessionid);
}
private function logportalauth($cpzonename, $user, $mac, $ip, $status, $message = "")
{
$message = trim($message);
$message = "Zone : {$cpzonename} {$status}: {$user}, {$mac}, {$ip}, {$message}";
$logger = new Syslog("logportalauth", array(
'option' => LOG_PID,
'facility' => LOG_LOCAL4
));
$logger->info($message);
}
/**
* flush zone (null flushes all zones)
* @param null $zone
* @param string $zone zone name or id
*/
function flush($zone=null){
if ( $zone == null ) {
public function flush($zone = null)
{
if ($zone == null) {
$shell = new Core\Shell();
$shell->exec("/sbin/ipfw -f table all flush");
}
else{
} else {
// find zoneid for this named zone
if (preg_match("/^[0-9]{1,2}$/", trim($zone)) ) {
if (preg_match("/^[0-9]{1,2}$/", trim($zone))) {
$zoneid = $zone;
}else {
} else {
$zoneid = -1;
foreach ($this->config->object()->captiveportal->children() as $zonenm => $zoneobj) {
if ($zonenm == $zone) $zoneid = $zoneobj->zoneid;
if ($zonenm == $zone) {
$zoneid = $zoneobj->zoneid;
}
}
}
if ( $zoneid != -1 ){
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",
......@@ -654,18 +631,20 @@ class CPClient {
"/sbin/ipfw -f table ".$this->rules->getAuthMACTables($zoneid)["out"]." flush",
"/sbin/ipfw delete set ".$zoneid,
);
$this->shell->exec($exec_commands, false,false);
$this->shell->exec($exec_commands, false, false);
}
}
}
/**
* cleanup portal sessions
* @param $cpzone zone name
*/
function portal_cleanup_sessions($cpzone=null){
$acc_list = $this->list_accounting();
foreach($this->config->object()->captiveportal->children() as $cpzonename => $zoneobj){
if ( $cpzone == null || $cpzone == $cpzonename ) {
public function portalCleanupSessions($cpzone = null)
{
$acc_list = $this->listAccounting();
foreach ($this->config->object()->captiveportal->children() as $cpzonename => $zoneobj) {
if ($cpzone == null || $cpzone == $cpzonename) {
$db = new DB($cpzonename);
$clients = $db->listClients(array(), null, null);
......@@ -677,10 +656,16 @@ class CPClient {
}
// if session timeout is reached, disconnect
if (is_numeric($client->session_timeout) && $client->session_timeout > 0 ) {
if (is_numeric($client->session_timeout) && $client->session_timeout > 0) {
if (((time() - $client->allow_time) ) > $client->session_timeout) {
$this->disconnect($cpzonename, $client->sessionid);
$this->logportalauth($cpzonename, $client->username, $client->mac, $client->ip, $status="SESSION TIMEOUT");
$this->logportalauth(
$cpzonename,
$client->username,
$client->mac,
$client->ip,
$status = "SESSION TIMEOUT"
);
continue;
}
}
......@@ -689,15 +674,29 @@ class CPClient {
if (is_numeric($client->idle_timeout) && $client->idle_timeout > 0 && $idle_time > 0) {
if ($idle_time > $client->idle_timeout) {
$this->disconnect($cpzonename, $client->sessionid);
$this->logportalauth($cpzonename, $client->username, $client->mac, $client->ip, $status="IDLE TIMEOUT");
$this->logportalauth(
$cpzonename,
$client->username,
$client->mac,
$client->ip,
$status = "IDLE TIMEOUT"
);
continue;
}
}
// disconnect on session terminate time
if ( is_numeric($client->session_terminate_time) && $client->session_terminate_time > 0 && $client->session_terminate_time < time()) {
if (is_numeric($client->session_terminate_time) &&
$client->session_terminate_time > 0 &&
$client->session_terminate_time < time()) {
$this->disconnect($cpzonename, $client->sessionid);
$this->logportalauth($cpzonename, $client->username, $client->mac, $client->ip, $status="TERMINATE TIME REACHED");
$this->logportalauth(
$cpzonename,
$client->username,
$client->mac,
$client->ip,
$status = "TERMINATE TIME REACHED"
);
continue;
}
}
......@@ -710,5 +709,92 @@ class CPClient {
}
/**
* list (ipfw) accounting information
* @param string $ipaddr ip address
* @return array (key = hosts ip)
*/
public function listAccounting($ipaddr = null)
{
$filter_cmd = "";
$result = array();
$shell_output = array();
if ($ipaddr != null) {
$filter_cmd =" | /usr/bin/grep ' " . $ipaddr ." '" ;
}
if ($this->shell->exec("/sbin/ipfw -aT list ".$filter_cmd, false, false, $shell_output) == 0) {
foreach ($shell_output as $line) {
if (strpos($line, ' count ip from') !== false) {
$parts = preg_split('/\s+/', $line);
if (count($parts) > 8 && $parts[7] != 'any' and strlen($parts[7]) > 5) {
$result[$parts[7]] = array(
"rulenum" => $parts[0],
"last_accessed" => (int)$parts[3],
"idle_time" => time() - (int)$parts[3],
"out_packets" => (int)$parts[1],
"in_packets" => (int)$parts[2]
);
}
}
}
}
return $result;
}
/**
* disconnect a session or a list of sessions depending on the parameter
* @param string $cpzonename zone name or id
* @param string $sessionid
*/
public function disconnect($cpzonename, $sessionid)
{
if (is_array($sessionid)) {
foreach ($sessionid as $sessid) {
$this->disconnectSession($cpzonename, $sessid);
}
} else {
$this->disconnectSession($cpzonename, $sessionid);
}
}
/**
* @param string $cpzonename zone name
* @param string $sessionid session id
* @return boolean false for invalid request
*/
private function disconnectSession($cpzonename, $sessionid)
{
$zoneid = -1;
foreach ($this->config->object()->captiveportal->children() as $zone => $zoneobj) {
if ($zone == $cpzonename) {
$zoneid = $zoneobj->zoneid;
}
}
if ($zoneid == -1) {
// not a valid zone
return false;
}
$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[0]->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->removeSession($sessionid);
}
return true;
}
}
......@@ -33,23 +33,28 @@
namespace OPNsense\CaptivePortal;
use \Phalcon\DI\FactoryDefault;
use \Phalcon\Db\Adapter\Pdo\Sqlite;
use \Phalcon\Logger\Adapter\Syslog;
/**
* Class DB, handles captive portal zone's adminstration
* @package CaptivePortal
*/
class DB {
class DB
{
/**
* zone name
* @var string
*/
private $zone = null ;
private $zone = null;
/**
* database handle
* @var SQLite3
*/
private $handle = null ;
private $handle = null;
/**
* datatypes for captive portal table
......@@ -68,44 +73,48 @@ class DB {
"idle_timeout" => \PDO::PARAM_INT,
"session_terminate_time" => \PDO::PARAM_INT,
"interim_interval" => \PDO::PARAM_INT,
"radiusctx" => \PDO::PARAM_STR);
"radiusctx" => \PDO::PARAM_STR
);
/**
* datatypes for captive portal mac table
* @var array
*/
private $captiveportal_mac_types=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);
"last_checked" => \PDO::PARAM_INT
);
/**
* datatypes for captive portal ip table
* @var array
*/
private $captiveportal_ip_types=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);
"last_checked" => \PDO::PARAM_INT
);
/**
* open / create new captive portal database for zone
* @param $zone zone name
*/
function __construct($zone)
public function __construct($zone)
{
$this->zone = $zone ;
$this->zone = $zone;
$this->open();
}
/**
* destruct, close sessions
*/
function __destruct() {
if ( $this->handle != null){
public function __destruct()
{
if ($this->handle != null) {
$this->handle->close();
}
}
......@@ -115,46 +124,49 @@ class DB {
* creates structure needed for this captiveportal zone
* @return SQLite3
*/
function open(){
public function open()
{
// open database
$db_path = \Phalcon\DI\FactoryDefault::getDefault()->get('config')->globals->vardb_path ."/captiveportal".$this->zone.".db" ;
$db_path = FactoryDefault::getDefault()->get('config')->globals->vardb_path .
"/captiveportal" . $this->zone . ".db";
try {
$this->handle = new \Phalcon\Db\Adapter\Pdo\Sqlite(array("dbname" => $db_path));
$this->handle = new 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
$sql = "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
"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
"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) "
)
) {
"CREATE UNIQUE INDEX IF NOT EXISTS idx_ip ON captiveportal_ip (ip) " ;
$logger = new \Phalcon\Logger\Adapter\Syslog("logportalauth", array(
if (! $this->handle->execute($sql)) {
$logger = new 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 ;
$msg = "Error during table {$this->zone} creation. Error message: {$this->handle->lastErrorMsg()}";
$logger->error($msg);
$this->handle = null;
}
}catch (\Exception $e) {
$logger = new \Phalcon\Logger\Adapter\Syslog("logportalauth", array(
} catch (\Exception $e) {
$logger = new Syslog("logportalauth", array(
'option' => LOG_PID,
'facility' => LOG_LOCAL4
));
$logger->error("Error opening database for zone " . $this->zone . " : ".$e->getMessage()." ");
$this->handle = null ;
$logger->error("Error opening database for zone " . $this->zone . " : " . $e->getMessage() . " ");
$this->handle = null;
}
return $this->handle;
......@@ -165,18 +177,26 @@ class DB {
* 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);
public function removeSession($sessionids)
{
if ($this->handle != null) {
if (is_array($sessionids)) {
$tmpids = $sessionids;
} else {
$tmpids = array($sessionids);
}
$this->handle->begin() ;
$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));
foreach ($tmpids as $session) {
$this->handle->executePrepared(
$stmt,
array('sessionid' => $session),
array("sessionid" => \PDO::PARAM_STR)
);
$stmt->execute();
}
$this->handle->commit() ;
$this->handle->commit();
}
}
......@@ -186,15 +206,18 @@ class DB {
* @param string $sessionid session id
* @param Array() $content data to alter ( fields from "captiveportal")
*/
function update_session($sessionid,$content){
if ( $this->handle != null ) {
public function updateSession($sessionid, $content)
{
if ($this->handle != null) {
$query = "update captiveportal set ";
$bind_values = Array("sessionid" => $sessionid);
$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." ";
if (sizeof($bind_values) > 1) {
$query .= " , ";
}
$query .= $fieldname . " = " . " :" . $fieldname . " ";
$bind_values[$fieldname] = $fieldvalue;
}
}
......@@ -202,11 +225,12 @@ class DB {
try {
$this->handle->execute($query, $bind_values, $this->captiveportal_types);
} catch (\Exception $e) {
$logger = new \Phalcon\Logger\Adapter\Syslog("logportalauth", array(
$logger = new Syslog("logportalauth", array(
'option' => LOG_PID,
'facility' => LOG_LOCAL4
));
$logger->error("Trying to modify DB returned error (zone = " . $this->zone . " ) : " . $e->getMessage() . " ");
$msg = "Trying to modify DB returned error (zone = " . $this->zone . " ) : " . $e->getMessage() . " ";
$logger->error($msg);
}
}
}
......@@ -217,10 +241,11 @@ class DB {
* @param string $sessionid unique session id
* @param Array() field content ( defined fields in "captiveportal")
*/
function insert_session($sessionid,$content){
if ( $this->handle != null ) {
public function insertSession($sessionid, $content)
{
if ($this->handle != null) {
// construct insert query, using placeholders for bind variables
$bind_values = Array("sessionid" => $sessionid);
$bind_values = array("sessionid" => $sessionid);
$query = "insert into captiveportal (sessionid ";
$query_values = "values (:sessionid ";
foreach ($content as $fieldname => $fieldvalue) {
......@@ -235,35 +260,39 @@ class DB {
try {
$this->handle->execute($query, $bind_values, $this->captiveportal_types);
} catch (\Exception $e) {
$logger = new \Phalcon\Logger\Adapter\Syslog("logportalauth", array(
$logger = new Syslog("logportalauth", array(
'option' => LOG_PID,
'facility' => LOG_LOCAL4
));
$logger->error("Trying to modify DB returned error (zone = " . $this->zone . " ) : " . $e->getMessage() . " ");
$msg = "Trying to modify DB returned error (zone = " . $this->zone . " ) : " . $e->getMessage() . " ";
$logger->error($msg);
}
}
}
/**
* get captive portal clients
* @param Array() $args
* @param array() $qryargs query filters (named array)
* @param string $operator choose and/or
* @param string $order_by sort order
*/
function listClients($qryargs,$operator="and",$order_by=null){
public function listClients($qryargs, $operator = "and", $order_by = null)
{
// construct query, only parse fields defined by $this->captiveportal_types
$qry_tag = "where " ;
$qry_tag = "where ";
$query = "select * from captiveportal ";
$query_order_by = "" ;
foreach ( $qryargs as $fieldname => $fieldvalue ){
if ( array_key_exists($fieldname,$this->captiveportal_types) ){
$query .= $qry_tag . $fieldname." = "." :".$fieldname." ";
$qry_tag = " ".$operator." ";
$query_order_by = "";
foreach ($qryargs as $fieldname => $fieldvalue) {
if (array_key_exists($fieldname, $this->captiveportal_types)) {
$query .= $qry_tag . $fieldname . " = " . " :" . $fieldname . " ";
$qry_tag = " " . $operator . " ";
}
}
// apply ordering to result, validate fields
if (is_array($order_by)){
foreach ( $order_by as $fieldname ){
if ( is_array($order_by) && in_array($fieldname,$order_by) ) {
if (is_array($order_by)) {
foreach ($order_by as $fieldname) {
if (is_array($order_by) && in_array($fieldname, $order_by)) {
if ($query_order_by != "") {
$query_order_by .= " , ";
}
......@@ -272,7 +301,9 @@ class DB {
}
}
if ( $query_order_by != "" ) $query .= " order by " . $query_order_by;
if ($query_order_by != "") {
$query .= " order by " . $query_order_by;
}
$resultset = $this->handle->query($query, $qryargs, $this->captiveportal_types);
......@@ -281,17 +312,20 @@ class DB {
return $resultset->fetchAll();
}
/**
*
* @param array $qryargs query filters (named array)
* @param string $operator and/or
* @return mixed number of connected users/clients
*/
function countClients($qryargs=array(),$operator="and"){
public function countClients($qryargs = array(), $operator = "and")
{
$query = "select count(*) cnt from captiveportal ";
$qry_tag = "where " ;
foreach ( $qryargs as $fieldname => $fieldvalue ){
if ( array_key_exists($fieldname,$this->captiveportal_types) ){
$query .= $qry_tag . $fieldname." = "." :".$fieldname." ";
$qry_tag = " ".$operator." ";
$qry_tag = "where ";
foreach ($qryargs as $fieldname => $fieldvalue) {
if (array_key_exists($fieldname, $this->captiveportal_types)) {
$query .= $qry_tag . $fieldname . " = " . " :" . $fieldname . " ";
$qry_tag = " " . $operator . " ";
}
}
......@@ -307,9 +341,10 @@ class DB {
*
* @return Array()
*/
function listFixedIPs(){
public function listFixedIPs()
{
$result = array();
if ($this->handle != null ) {
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);
......@@ -324,21 +359,35 @@ class DB {
/**
* insert new passthru mac address
* @param $ip hosts ip address
* @param int $pipeno_in
* @param int $pipeno_out
*/
function upsertFixedIP($ip,$pipeno_in=null,$pipeno_out=null){
public 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);
$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
);
$sql ="update captiveportal_ip set ip=:ip, last_checked=:last_checked, ".
"pipeno_in = :pipeno_in, pipeno_out = :pipeno_out where ip =:ip ";
$this->handle->execute($sql, $params, $this->captiveportal_ip_types);
}
/**
* drop address from administration (captiveportal_ip)
* @param $mac physical address
* @param $ip ip address
*/
function dropFixedIP($ip){
$this->handle->execute("delete from captiveportal_ip where ip =:ip ", array("ip"=>$ip),$this->captiveportal_ip_types);
public function dropFixedIP($ip)
{
$this->handle->execute(
"delete from captiveportal_ip where ip =:ip ",
array("ip" => $ip),
$this->captiveportal_ip_types
);
}
/**
......@@ -346,9 +395,10 @@ class DB {
*
* @return Array()
*/
function listPassthruMacs(){
public function listPassthruMacs()
{
$result = array();
if ($this->handle != null ) {
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);
......@@ -364,24 +414,41 @@ class DB {
* insert new passthru mac address
* @param $mac physical address
* @param $ip hosts ip address
* @param null $pipeno_in
* @param null $pipeno_out
*/
function upsertPassthruMAC($mac,$ip,$pipeno_in=null,$pipeno_out=null){
public 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);
$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
);
$sql = "update captiveportal_mac set ip=:ip, last_checked=:last_checked, ".
"pipeno_in = :pipeno_in, pipeno_out = :pipeno_out where mac =:mac " ;
$this->handle->execute($sql, $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);
public function dropPassthruMAC($mac)
{
$this->handle->execute(
"delete from captiveportal_mac where mac =:mac ",
array("mac" => $mac),
$this->captiveportal_mac_types
);
}
}
......@@ -39,11 +39,11 @@ use OPNsense\Core;
* Class Rules
* @package CaptivePortal
*/
class Rules {
class Rules
{
/**
* config handle
* @var Core_Config
* @var Core\Config
*/
private $config = null;
......@@ -57,7 +57,7 @@ class Rules {
/**
*
*/
function __construct()
public function __construct()
{
// Request handle to configuration
$this->config = Core\Config::getInstance();
......@@ -66,28 +66,31 @@ class Rules {
/**
* get ipfw tables for authenticated users ( in/out )
* @param $zoneid zoneid (number)
* @param int $zoneid zoneid (number)
* @return array
*/
function getAuthUsersTables($zoneid){
public 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)
* @param int $zoneid zoneid (number)
* @return array
*/
function getAuthIPTables($zoneid){
public 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)
* @param int $zoneid zoneid (number)
* @return array
*/
function getAuthMACTables($zoneid){
public function getAuthMACTables($zoneid)
{
return array("in"=>(6*($zoneid-1) )+5,"out"=>(6*($zoneid-1) )+6);
}
......@@ -96,16 +99,17 @@ class Rules {
* default rules
* rule number range 1..1000
*/
private function generate_default_rules(){
private function generateDefaultRules()
{
// define general purpose rules, rule number 1 .... 1000
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "#======================================================================================";
$this->rules[] = "# flush ruleset ";
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "#======================================================================================";
$this->rules[] = "flush" ;
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "#======================================================================================";
$this->rules[] = "# general purpose rules 1...1000 ";
$this->rules[] = "#=========================================================================================================";
$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";
......@@ -123,20 +127,26 @@ class Rules {
* Always allow traffic to our own host ( all static addresses from configuration )
* rule number range 1001..1999
*/
private function generate_this_host_rules(){
private function generateThisHostRules()
{
// search all static / non wan addresses and add rules to $this->rules
$rulenum = 1001 ;
$this->rules[] = "#=========================================================================================================";
$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[] = "#======================================================================================";
foreach ($this->config->object()->interfaces->children() as $interface => $content) {
if ($interface != "wan" && $content->ipaddr != "dhcp") {
// only keep state of dns traffic to prevent dns resolver failures
$this->rules[] = "add ".$rulenum++." allow udp from any to ".$content->ipaddr." dst-port 53 keep-state in";
$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";
$this->rules[] = "add ".$rulenum++." allow udp from any to ".
$content->ipaddr." dst-port 53 keep-state in";
$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";
}
}
}
......@@ -159,55 +169,80 @@ class Rules {
*
* rule number ranges 3001..3999, 10000...50000
*/
private function generate_zones(){
foreach( $this->config->object()->captiveportal->children() as $cpzonename => $zone ) {
if ( isset( $zone->enable) ) {
private function generateZones()
{
foreach ($this->config->object()->captiveportal->children() as $cpzonename => $zone) {
if (isset($zone->enable)) {
// search interface
$interface = $zone->interface->xpath("//" . $zone->interface);
// allocate tables for captive portal
$table_id = (6 * ($zone->zoneid - 1));
$this->rules[] = "#=========================================================================================================";
$this->rules[] = "#===================================================================================";
$this->rules[] = "# zone " . $cpzonename . " (" . $zone->zoneid . ") configuration";
$this->rules[] = "#=========================================================================================================";
$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;
$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;
$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;
$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 ;
// $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 ;
// $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 ;
// $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;
$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;
$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;
}
}
......@@ -219,20 +254,23 @@ class Rules {
* Forward all non authenticated traffic from captive portal zones
* rule number range 5001..5999
*/
private function generate_reflect_rules(){
private function generateReflectRules()
{
$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 ){
$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) {
if (isset($zone->enable)) {
// search interface
$interface = $zone->interface->xpath("//".$zone->interface);
if (count($interface) > 0){
if (count($interface) > 0) {
$interface = $interface[0] ;
if ($interface->ipaddr != null){
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;
$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;
}
}
......@@ -244,11 +282,12 @@ class Rules {
* for accounting statistics we setup a separate section in our config
* rule number range 30000..65500
*/
private function generate_accounting_section(){
$this->rules[] = "#=========================================================================================================";
private function generateAccountingSection()
{
$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[] = "#======================================================================================";
$this->rules[] = "add 30000 set 0 count ip from any to any ";
$this->rules[] = "add 65500 pass ip from any to any ";
}
......@@ -257,10 +296,11 @@ class Rules {
* generate closure tag, block all traffic coming from captiveportal interfaces
* rule number range 6001..6999
*/
private function generate_closure(){
private function generateClosure()
{
$cpinterfaces = [];
# find all cp interfaces
foreach( $this->config->object()->captiveportal->children() as $cpzonename => $zone ) {
foreach ($this->config->object()->captiveportal->children() as $cpzonename => $zone) {
if (isset($zone->enable)) {
// search interface
$interface = $zone->interface->xpath("//" . $zone->interface);
......@@ -274,11 +314,11 @@ class Rules {
// generate accept rules for every interface not in captive portal
$ruleid = 6001 ;
$this->rules[] = "#=========================================================================================================";
$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[] = "#======================================================================================";
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 ;
}
}
......@@ -296,8 +336,10 @@ class Rules {
/**
* load ruleset
* @param string $filename target filename
*/
public function generate($filename){
public function generate($filename)
{
/*
* reset rules
*/
......@@ -306,24 +348,25 @@ class 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();
$this->generateDefaultRules();
$this->generateThisHostRules();
$this->generateZones();
$this->generateReflectRules();
$this->generateAccountingSection();
$this->generateClosure();
// ruleset array -> text
$ruleset_txt = "";
$prev_rule = "#";
foreach($this->rules as $rule){
if (trim($rule)[0] == '#' && trim($prev_rule)[0] != "#" ) $ruleset_txt .= "\n";
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);
file_put_contents($filename, $ruleset_txt);
}
}
......@@ -34,17 +34,14 @@
namespace OPNsense\Core;
/**
* Class ConfigException
* @package Core
*/
class ConfigException extends \Exception { }
use \Phalcon\DI\FactoryDefault;
/**
* Class Config
* @package Core
*/
class Config extends Singleton {
class Config extends Singleton
{
/**
* config file location ( path + name )
......@@ -68,32 +65,52 @@ class Config extends Singleton {
* status field: valid config loaded
* @var bool
*/
private $isValid = False;
private $isValid = false;
/**
* Load config file
* print config xml in dot notation
* @param DOMNode $node
* @param string $nodename
* @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') ;
public function dump($node = null, $nodename = "")
{
$this->checkvalid();
// root node
if ($node == null) {
$node = $this->configxml;
}
$this->configxml = new \DOMDocument;
$this->configxml->loadXML($xml);
$this->simplexml = simplexml_import_dom($this->configxml);
$this->isValid = true;
$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);
}
}
}
/**
* @throws ConfigException
*/
private function checkvalid(){
if ( !$this->isValid ) throw new ConfigException('no valid config loaded') ;
private function checkvalid()
{
if (!$this->isValid) {
throw new ConfigException('no valid config loaded') ;
}
}
/*
......@@ -102,41 +119,23 @@ class Config extends Singleton {
* @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);
}
}
public function xpath($query)
{
$this->checkvalid();
$xpath = new \DOMXPath($this->configxml);
return $xpath->query($query);
}
/*
* 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 ;
}
public function object()
{
$this->checkvalid();
return $this->simplexml;
}
/*
......@@ -145,10 +144,16 @@ class Config extends Singleton {
* @return \DOMNodeList
* @throws ConfigException
*/
function xpath($query){
$this->checkvalid();
$xpath = new \DOMXPath($this->configxml);
return $xpath->query($query);
protected function init()
{
$this->config_file = FactoryDefault::getDefault()->get('config')->globals->config_path . "config.xml";
try {
$this->load();
} catch (\Exception $e) {
$this->configxml = null ;
}
}
/*
......@@ -156,9 +161,26 @@ class Config extends Singleton {
* @return SimpleXML
* @throws ConfigException
*/
function object(){
$this->checkvalid();
return $this->simplexml;
}
/**
* 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;
}
}
<?php
/**
* Created by PhpStorm.
* User: ad
* Date: 04-01-15
* Time: 20:06
*/
namespace app\models\OPNsense\Core;
/**
* Class ConfigException
* @package Core
*/
class ConfigException extends \Exception
{
}
......@@ -33,6 +33,7 @@
namespace OPNsense\Core;
use \Phalcon\DI\FactoryDefault;
class Shell
{
......@@ -52,11 +53,31 @@ class Shell
/**
* new shell object
*/
function __construct()
public 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;
$this->simulate = FactoryDefault::getDefault()->get('config')->globals->simulate_mode;
$this->debug = FactoryDefault::getDefault()->get('config')->globals->debug;
}
/**
* execute command or list of commands
*
* @param string/Array() $command command to execute
* @param bool $mute
* @param bool $clearsigmask
* @param Array() &$output
*/
public function exec($command, $mute = false, $clearsigmask = false, &$output = null)
{
if (is_array($command)) {
foreach ($command as $comm) {
$this->execSingle($comm, $mute, $clearsigmask, $output);
}
} else {
$this->execSingle($command, $mute, $clearsigmask, $output);
}
}
......@@ -65,8 +86,11 @@ class Shell
* @param string $command command to execute
* @param bool $mute
* @param bool $clearsigmask
* @param Array() &$output
* @return int
*/
private function _exec($command, $mute = false, $clearsigmask = false,&$output=null){
private function execSingle($command, $mute = false, $clearsigmask = false, &$output = null)
{
$oarr = array();
$retval = 0;
......@@ -82,10 +106,11 @@ class Shell
pcntl_sigprocmask(SIG_SETMASK, array(), $oldset);
}
$garbage = exec("$command 2>&1", $output, $retval);
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);
//log_error(sprintf(gettext("The command '%1\$s'
// returned exit code '%2\$d', the output was '%3\$s' "), implode(" ", $output);
// TODO: log
unset($output);
}
......@@ -101,26 +126,4 @@ class Shell
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);
}
}
}
......@@ -33,11 +33,6 @@
namespace OPNsense\Core;
/**
* Class Singleton
* @package Core
*/
/**
* Class Singleton
* @package Core
......@@ -65,7 +60,7 @@ abstract class Singleton
*/
final private function __clone()
{
throw new \Exception("An instance of ".get_called_class()." cannot be cloned.");
throw new \Exception("An instance of " . get_called_class() . " cannot be cloned.");
}
/**
......@@ -76,7 +71,7 @@ abstract class Singleton
{
$className = get_called_class();
if(isset(self::$instances[$className]) == false) {
if (isset(self::$instances[$className]) == false) {
self::$instances[$className] = new static();
}
return self::$instances[$className];
......@@ -88,6 +83,7 @@ abstract class Singleton
* so an extended class could simply
* specify its own init
*/
protected function init(){}
protected function init()
{
}
}
......@@ -79,7 +79,7 @@ if (!empty($cpzone)) {
$cpdb = $cpdb_handle->listClients(array(),"and",array($order) ) ;
if ($_GET['showact']) {
$accounting_info = $cpclient_handle->list_accounting();
$accounting_info = $cpclient_handle->listAccounting();
}
else {
$accounting_info = array() ;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment