diff --git a/app/event_guard/app_config.php b/app/event_guard/app_config.php index 2158456e60..88326d1297 100644 --- a/app/event_guard/app_config.php +++ b/app/event_guard/app_config.php @@ -1,11 +1,11 @@ domain_uuid = $setting_array['domain_uuid'] ?? $_SESSION['domain_uuid'] ?? ''; $this->user_uuid = $setting_array['user_uuid'] ?? $_SESSION['user_uuid'] ?? ''; - //set objects + // Set the objects $this->database = $setting_array['database'] ?? database::new(); - //assign the variables + // Assign the variables $this->name = 'event_guard_log'; $this->table = 'event_guard_logs'; $this->toggle_field = ''; @@ -110,11 +110,11 @@ class event_guard { public function delete($records) { if (permission_exists($this->name . '_delete')) { - //add multi-lingual support + // Add multi-lingual support $language = new text; $text = $language->get(); - //validate the token + // Validate the token $token = new token; if (!$token->validate($_SERVER['PHP_SELF'])) { message::add($text['message-invalid_token'], 'negative'); @@ -122,27 +122,27 @@ class event_guard { exit; } - //delete multiple records + // Delete multiple records if (is_array($records) && @sizeof($records) != 0) { - //build the delete array + // Build the delete array $x = 0; foreach ($records as $record) { - //add to the array + // Add to the array if ($record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { $array[$this->table][$x]['event_guard_log_uuid'] = $record['event_guard_log_uuid']; } - //increment the id + // Increment the id $x++; } - //delete the checked rows + // Delete the checked rows if (is_array($array) && @sizeof($array) != 0) { - //execute delete + // Execute delete $this->database->delete($array); unset($array); - //set message + // Set the message message::add($text['message-delete']); } unset($records); @@ -160,11 +160,11 @@ class event_guard { public function unblock($records) { if (permission_exists($this->name . '_unblock')) { - //add multi-lingual support + // Add multi-lingual support $language = new text; $text = $language->get(); - //validate the token + // Validate the token $token = new token; if (!$token->validate($_SERVER['PHP_SELF'])) { message::add($text['message-invalid_token'], 'negative'); @@ -172,7 +172,7 @@ class event_guard { exit; } - //delete multiple records + // Delete multiple records if (is_array($records) && @sizeof($records) != 0) { //build the delete array $x = 0; @@ -187,23 +187,23 @@ class event_guard { $x++; } - //delete the checked rows + // Delete the checked rows if (is_array($array) && @sizeof($array) != 0) { - //execute delete + // Execute delete $this->database->save($array); unset($array); - //initialize the settings object + // Initialize the settings object $setting = new settings(["category" => 'switch']); - //send unblock event - $cmd = "sendevent CUSTOM\n"; - $cmd .= "Event-Name: CUSTOM\n"; - $cmd .= "Event-Subclass: event_guard:unblock\n"; - $esl = event_socket::create(); + // Send unblock event + $cmd = "sendevent CUSTOM\n"; + $cmd .= "Event-Name: CUSTOM\n"; + $cmd .= "Event-Subclass: event_guard:unblock\n"; + $esl = event_socket::create(); $switch_result = event_socket::command($cmd); - //set message + // Set the message message::add($text['message-delete']); } unset($records); @@ -223,11 +223,11 @@ class event_guard { public function toggle($records) { if (permission_exists($this->name . '_edit')) { - //add multi-lingual support + // Add multi-lingual support $language = new text; $text = $language->get(); - //validate the token + // Validate the token $token = new token; if (!$token->validate($_SERVER['PHP_SELF'])) { message::add($text['message-invalid_token'], 'negative'); @@ -235,9 +235,9 @@ class event_guard { exit; } - //toggle the checked records + // Toggle the checked records if (is_array($records) && @sizeof($records) != 0) { - //get current toggle state + // Get current toggle state foreach ($records as $record) { if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { $uuids[] = "'" . $record['event_guard_log_uuid'] . "'"; @@ -255,25 +255,24 @@ class event_guard { unset($sql, $parameters, $rows, $row); } - //build update array + // Build update array $x = 0; foreach ($states as $uuid => $state) { - //create the array + // Create the array $array[$this->table][$x][$this->name . '_uuid'] = $uuid; $array[$this->table][$x][$this->toggle_field] = $state == $this->toggle_values[0] ? $this->toggle_values[1] : $this->toggle_values[0]; - //increment the id + // Increment the id $x++; } - //save the changes + // Save the changes if (is_array($array) && @sizeof($array) != 0) { - //save the array - + // Save the array $this->database->save($array); unset($array); - //set message + // Set the message message::add($text['message-toggle']); } unset($records, $states); @@ -293,11 +292,11 @@ class event_guard { public function copy($records) { if (permission_exists($this->name . '_add')) { - //add multi-lingual support + // Add multi-lingual support $language = new text; $text = $language->get(); - //validate the token + // Validate the token $token = new token; if (!$token->validate($_SERVER['PHP_SELF'])) { message::add($text['message-invalid_token'], 'negative'); @@ -305,17 +304,17 @@ class event_guard { exit; } - //copy the checked records + // Copy the checked records if (is_array($records) && @sizeof($records) != 0) { - //get checked records + // Get checked records foreach ($records as $record) { if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['event_guard_log_uuid'])) { $uuids[] = "'" . $record['event_guard_log_uuid'] . "'"; } } - //create the array from existing data + // Create the array from existing data if (is_array($uuids) && @sizeof($uuids) != 0) { $sql = "select * from v_" . $this->table . " "; $sql .= "where event_guard_log_uuid in (" . implode(', ', $uuids) . ") "; @@ -323,7 +322,7 @@ class event_guard { if (is_array($rows) && @sizeof($rows) != 0) { $x = 0; foreach ($rows as $row) { - //convert boolean values to a string + // Convert boolean values to a string foreach ($row as $key => $value) { if (gettype($value) == 'boolean') { $value = $value ? 'true' : 'false'; @@ -331,32 +330,30 @@ class event_guard { } } - //copy data + // Copy data $array[$this->table][$x] = $row; - //add copy to the description + // Add copy to the description $array[$this->table][$x]['event_guard_log_uuid'] = uuid(); - //increment the id + // Increment the id $x++; } } unset($sql, $parameters, $rows, $row); } - //save the changes and set the message + // Save the changes and set the message if (is_array($array) && @sizeof($array) != 0) { - //save the array - + // Save the array $this->database->save($array); unset($array); - //set message + // Set the message message::add($text['message-copy']); } unset($records); } } } - } diff --git a/app/event_guard/resources/classes/event_guard_iptables.php b/app/event_guard/resources/classes/event_guard_iptables.php new file mode 100644 index 0000000000..d9781a4134 --- /dev/null +++ b/app/event_guard/resources/classes/event_guard_iptables.php @@ -0,0 +1,128 @@ +settings = $settings; + + // Set the database object from the settings object + $this->database = $settings->database(); + + // Set firewall path + $this->firewall_path = trim(shell_exec('command -v iptables')); + + // Create a chain array + $chains[] = 'sip-auth-ip'; + $chains[] = 'sip-auth-fail'; + foreach ($chains as $chain) { + shell_exec($this->firewall_path.' --new ' . $chain . ' >/dev/null 2>&1 &'); + shell_exec($this->firewall_path.' -I INPUT -j '.$chain . ' >/dev/null 2>&1 &'); + } + } + + /** + * Execute a block command for iptables + * + * @param string $ip_address The IP address to block + * @param string $filter The filter name for nftables, iptables or pf + * @param array $event The event data containing 'to-user' and 'to-host' + * + * @return boolean True if the block command was executed successfully, false otherwise + */ + public function block_add(string $ip_address, string $filter) : bool { + + // Invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + // Run the block command for iptables + // Example: iptables -I INPUT -s 127.0.0.1 -j DROP + $command = $this->firewall_path.' -I '.$filter.' -s '.$ip_address.' -j DROP'; + $result = shell_exec($command); + if (!empty($result)) { + return false; + } + + // Return success + return true; + } + + /** + * Unblock a specified IP address from a firewall. + * + * @param string $ip_address The IP address to unblock. + * @param string $filter The filter name used in the firewall configuration. + * + * @return bool True if the IP address was successfully unblocked, false otherwise. + */ + public function block_delete(string $ip_address, string $filter) : bool { + // Invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + // Unblock the address + $command = $this->firewall_path.' -L '.$filter.' -n --line-numbers | grep "'.$ip_address.' " | cut -d " " -f1'; + $line_number = trim(shell_exec($command)); + echo "\n". $command . " line ".__line__."\n"; + if (is_numeric($line_number)) { + //$result = shell_exec('iptables -D INPUT '.$line_number); + $command = $this->firewall_path.' -D '.$filter.' '.$line_number; + $result = shell_exec($command); + if (!empty($result)) { + return false; + } + echo "Unblock address ".$ip_address ." line ".$line_number." command ".$command." result ".$result."\n"; + } + + // Return success + return true; + } + + /** + * Check if an IP address is blocked in the configured firewall. + * + * @param string $ip_address The IP address to check + * + * @return bool True if the address is blocked, False otherwise + */ + public function block_exists(string $ip_address, string $filter) : bool { + // Determine whether to return true or false + // Check to see if the address is blocked + $command = $this->firewall_path.' -L -n --line-numbers | grep '.$ip_address; + $result = shell_exec($command); + if (!empty($result) && strlen($result) > 3) { + return true; + } + + // Return the result + return false; + } +} \ No newline at end of file diff --git a/app/event_guard/resources/classes/event_guard_nftables.php b/app/event_guard/resources/classes/event_guard_nftables.php new file mode 100644 index 0000000000..c74b5e147d --- /dev/null +++ b/app/event_guard/resources/classes/event_guard_nftables.php @@ -0,0 +1,129 @@ +settings = $settings; + + // Set the database object from the settings object + $this->database = $settings->database(); + + // Set firewall path + $this->firewall_path = trim(shell_exec('command -v nft')); + + // Create a chain array + $chains[] = 'sip-auth-ip'; + $chains[] = 'sip-auth-fail'; + foreach ($chains as $chain) { + shell_exec($this->firewall_path.' add chain inet filter ' . $chain . ' { type filter hook input priority -50 \; }'); // >/dev/null 2>&1 &'); + } + } + + /** + * Execute a block command for iptables + * + * @param string $ip_address The IP address to block + * @param string $filter The filter name for nftables, iptables or pf + * @param array $event The event data containing 'to-user' and 'to-host' + * + * @return boolean True if the block command was executed successfully, false otherwise + */ + public function block_add(string $ip_address, string $filter) : bool { + // Invalid IP address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + // Run the block command for nftables + // Example: nft add element inet filter sip-auth-ip { 192.168.1.100 } + $command = $this->firewall_path.' add rule inet filter '.$filter.' ip saddr '.$ip_address.' counter drop'; + $result = shell_exec($command); + if (!empty($result) && strlen($result) > 3) { + return false; + } + + // Return success + return true; + } + + /** + * Unblock a specified IP address from a firewall. + * + * @param string $ip_address The IP address to unblock. + * @param string $filter The filter name used in the firewall configuration. + * + * @return bool True if the IP address was successfully unblocked, false otherwise. + */ + public function block_delete(string $ip_address, string $filter) : bool { + // Invalid IP address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + // Command used to get the handle + $command = $this->firewall_path.' -a list chain inet filter '.$filter.' | grep '.$ip_address; + echo $command."\n"; + $result = trim(shell_exec($command)); + $rows = explode("\n", $result); + + // Unblock the address + foreach ($rows as $row) { + $handle = trim(explode("#", $row)[1] ?? ''); + $command = $this->firewall_path.' delete rule inet filter '.$filter.' '.$handle; + echo $command."\n"; + $result = shell_exec($command); + } + if (!empty($result)) { + return false; + } + + // Return success + return true; + } + + /** + * Check if an IP address is blocked in the configured firewall. + * + * @param string $ip_address The IP address to check + * + * @return bool True if the address is blocked, False otherwise + */ + public function block_exists(string $ip_address, string $filter) : bool { + // Determine whether to return true or false + // Check to see if the address is blocked + $command = $this->firewall_path.' list chain inet filter input | grep "ip saddr '.$ip_address.'"'; + $result = shell_exec($command); + if (!empty($result) && strlen($result) > 3) { + return true; + } + + // Return failed + return false; + } +} \ No newline at end of file diff --git a/app/event_guard/resources/classes/event_guard_pf.php b/app/event_guard/resources/classes/event_guard_pf.php new file mode 100644 index 0000000000..20b345f51f --- /dev/null +++ b/app/event_guard/resources/classes/event_guard_pf.php @@ -0,0 +1,114 @@ +settings = $settings; + + // Set the database object from the settings object + $this->database = $settings->database(); + + // Set firewall path + $this->firewall_path = trim(shell_exec('command -v pfctl')); + } + + /** + * Execute a block command for iptables + * + * @param string $ip_address The IP address to block + * @param string $filter The filter name for nftables, iptables or pf + * @param array $event The event data containing 'to-user' and 'to-host' + * + * @return boolean True if the block command was executed successfully, false otherwise + */ + public function block_add(string $ip_address, string $filter) : bool { + + // Invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + // Run the block command for pf + // Example: pfctl -t sip-auth-ip -T add 127.0.0.5 + $command = $this->firewall_path.' -t '.$filter.' -T add '.$ip_address; + $result = shell_exec($command); + if (!empty($result)) { + return false; + } + + // Return success + return true; + } + + /** + * Unblock a specified IP address from a firewall. + * + * @param string $ip_address The IP address to unblock. + * @param string $filter The filter name used in the firewall configuration. + * + * @return bool True if the IP address was successfully unblocked, false otherwise. + */ + public function block_delete(string $ip_address, string $filter) : bool { + // Invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + // Unblock the address + // Example: pfctl -t sip-auth-ip -T delete 127.0.0.5 + $command = $this->firewall_path.' -t '.$filter.' -T delete '.$ip_address; + $result = shell_exec($command); + if (!empty($result)) { + return false; + } + + // Return success + return true; + } + + /** + * Check if an IP address is blocked in the configured firewall. + * + * @param string $ip_address The IP address to check + * + * @return bool True if the address is blocked, False otherwise + */ + public function block_exists(string $ip_address, string $filter) : bool { + // Determine whether to return true or false + // Check to see if the address is blocked + $command = $this->firewall_path.' -t ".$filter." -Ts | grep '.$ip_address; + $result = shell_exec($command); + if (!empty($result) && strlen($result) > 3) { + return true; + } + + // Return the result + return false; + } +} \ No newline at end of file diff --git a/app/event_guard/resources/classes/event_guard_service.php b/app/event_guard/resources/classes/event_guard_service.php new file mode 100644 index 0000000000..1b9c0a2bc1 --- /dev/null +++ b/app/event_guard/resources/classes/event_guard_service.php @@ -0,0 +1,517 @@ +read(); + + // Connect to the database + $this->database = new database(['config' => parent::$config]); + + // Get the settings using global defaults + $this->settings = new settings(['database' => $this->database]); + + // Set the php operating system + $php_os = strtolower(PHP_OS); + + // Set the firewall name + if ($php_os == 'freebsd') { + $firewall_name = $this->settings->get('system','firewall_name', 'pf'); + } + if ($php_os == 'linux') { + $firewall_name = $this->settings->get('system','firewall_name', 'nftables'); + } + if (empty($firewall_name)) { + throw new Exception("No firewall name specified in settings"); + } + + // Get the settings using global defaults + $class_name = 'event_guard_'.$firewall_name; + $this->firewall = new $class_name($this->settings); + if (!($this->firewall instanceof event_guard_interface)) { + throw new Exception("Must be an event_guard_interface firewall"); + } + + // Get the hostname + $this->hostname = gethostname(); + + // Connect to event socket + $this->socket = new event_socket; + if ($this->socket->connect()) { + // Loop through the switch events + $cmd = "event json ALL"; + $result = $this->socket->request($cmd); + $this->debug('subscribe to ALL events '. print_r($result, true)); + + // Filter for specific events + $cmd = "filter Event-Name CUSTOM"; + $result = $this->socket->request($cmd); + $this->debug('subscribe to CUSTOM events '. print_r($result, true)); + } + else { + $this->warning('Unable to connect to event socket'); + } + } + + public function run(): int { + // Reload the settings + $this->reload_settings(); + + // Service work is handled here + while ($this->running) { + + // Initialize the array for switch events + $json_array = []; + + // Make sure the database connection is available + while (!$this->database->is_connected()) { + // Connect to the database + $this->database->connect(); + + // Reload settings after connection to the database + $this->settings = new settings(['database' => $this->database]); + + // Sleep for a moment + sleep(1); + } + + // Reconnect to event socket + if (!$this->socket->connected()) { + $this->warning('Not connected to even socket'); + if ($this->socket->connect()) { + $cmd = "event json ALL"; + $result = $this->socket->request($cmd); + $this->debug('subscribe to ALL events '. print_r($result, true)); + + $cmd = "filter Event-Name CUSTOM"; + $result = $this->socket->request($cmd); + $this->debug('subscribe to CUSTOM events '. print_r($result, true)); + $this->info('Re-connected to event socket'); + } + else { + // Unable to connect to event socket + $this->warning('Unable to connect to event socket'); + + // Sleep and then attempt to reconnect + sleep(1); + continue; + } + } + + // Read the socket + $json_response = $this->socket->read_event(); + + // Decode the response + if (isset($json_response) && $json_response != '') { + $json_array = json_decode($json_response['$'], true); + unset($json_response); + } + + // Debug the event array + $this->debug('Event array '. print_r($json_array, true)); + + // Registration failed - block IP address unless they are registered + if (is_array($json_array) && $json_array['Event-Subclass'] == 'sofia::register_failure') { + //not registered so block the address + if (!$this->allow_access($json_array['network-ip'])) { + $this->block_add($json_array['network-ip'], 'sip-auth-fail', $json_array); + } + } + + // Sendevent CUSTOM event_guard:unblock + if (is_array($json_array) && $json_array['Event-Subclass'] == 'event_guard:unblock') { + //check the database for pending requests + $sql = "select event_guard_log_uuid, log_date, filter, ip_address, extension, user_agent "; + $sql .= "from v_event_guard_logs "; + $sql .= "where log_status = 'pending' "; + $sql .= "and hostname = :hostname "; + //$this->debug($sql." ".$this->hostname); + $parameters['hostname'] = $this->hostname; + $event_guard_logs = $this->database->select($sql, $parameters, 'all'); + if (is_array($event_guard_logs)) { + $x = 0; + foreach($event_guard_logs as $row) { + //unblock the ip address + $this->block_delete($row['ip_address'], $row['filter']); + + //debug info + $this->info("unblocked: [ip_address: ".$row['ip_address'].", filter: ".$row['filter'].", to-user: ".$row['extension'].", to-host: ".$row['hostname'].", line: ".__line__); + + //log the blocked ip address to the database + $array['event_guard_logs'][$x]['event_guard_log_uuid'] = $row['event_guard_log_uuid']; + $array['event_guard_logs'][$x]['log_date'] = 'now()'; + $array['event_guard_logs'][$x]['log_status'] = 'unblocked'; + $x++; + } + if (is_array($array)) { + $p = permissions::new(); + $p->add('event_guard_log_edit', 'temp'); + $this->database->save($array, false); + $p->delete('event_guard_log_edit', 'temp'); + unset($array); + } + } + } + + // Registration to the IP address + if (is_array($json_array) && $json_array['Event-Subclass'] == 'sofia::pre_register') { + if (isset($json_array['to-host'])) { + $is_valid_ip = filter_var($json_array['to-host'], FILTER_VALIDATE_IP); + if ($is_valid_ip) { + //if not registered block the address + if (!$this->allow_access($json_array['network-ip'])) { + $this->block_add($json_array['network-ip'], 'sip-auth-ip', $json_array); + } + + //debug info + $this->debug("network-ip ".$json_array['network-ip'].", to-host ".$json_array['to-host']); + } + } + } + + // Debug information + //if (($json_array['Event-Subclass'] == 'sofia::register_failure' || $json_array['Event-Subclass'] == 'sofia::pre_register')) { + //echo "\n"; + //print_r($json_array); + + //echo "event_name: ".$json_array['Event-Name']."\n"; + //echo "event_type: ".$json_array['event_type']."\n"; + //echo "event_subclass: ".$json_array['Event-Subclass']."\n"; + //echo "status: ".$json_array['status']."\n"; + //echo "network_ip: ".$json_array['network-ip']."\n"; + //echo "channel_state: ".$json_array['Channel-State']."\n"; + //echo "channel_call_state: ".$json_array['Channel-Call-State']."\n"; + //echo "call_direction: ".$json_array['Call-Direction']."\n"; + //echo "channel_call_uuid: ".$json_array['Channel-Call-UUID']."\n"; + //echo "answer_state: ".$json_array['Answer-State']."\n"; + //echo "hangup_cause: ".$json_array['Hangup-Cause']."\n"; + //echo "to-host: $json_array['to-host']\n"; + //echo "\n"; + //} + + // Sleep for 100 ms + usleep(100000); + } + return 0; + } + + protected static function display_version(): void { + echo "1.1\n"; + } + + protected static function set_command_options() { + + } + + /** + * Execute a block command for nftables, iptables or pf based on the firewall type. + * + * @param string $ip_address The IP address to block + * @param string $filter The filter name for nftables, iptables or pf + * @param array $event The event data containing 'to-user' and 'to-host' + * + * @return boolean True if the block command was executed successfully, false otherwise + */ + public function block_add(string $ip_address, string $filter, array $event) : bool { + //invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + //block the IP address + $result = $this->firewall->block_add($ip_address, $filter); + if ($result) { + //log the blocked ip address to the log + $this->warning("blocked: [ip_address: ".$ip_address.", filter: ".$filter.", to-user: ".$event['to-user'].", to-host: ".$event['to-host'].", line: ".__line__."]"); + + //log the blocked ip address to the database + $array = []; + $array['event_guard_logs'][0]['event_guard_log_uuid'] = uuid(); + $array['event_guard_logs'][0]['hostname'] = gethostname(); + $array['event_guard_logs'][0]['log_date'] = 'now()'; + $array['event_guard_logs'][0]['filter'] = $filter; + $array['event_guard_logs'][0]['ip_address'] = $ip_address; + $array['event_guard_logs'][0]['extension'] = $event['to-user'].'@'.$event['to-host']; + $array['event_guard_logs'][0]['user_agent'] = $event['user-agent']; + $array['event_guard_logs'][0]['log_status'] = 'blocked'; + $p = permissions::new(); + $p->add('event_guard_log_add', 'temp'); + $this->database->save($array, false); + $p->delete('event_guard_log_add', 'temp'); + + //send debug information to the console + $this->info("blocked address " . $ip_address . ", line " . __line__); + } + + //return the result + return $result; + } + + public function block_delete(string $ip_address, string $filter) : bool { + //invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + //unblock the IP address + $result = $this->firewall->block_delete($ip_address, $filter); + if ($result) { + //send debug information to the console + $this->info("Unblock address " . $ip_address . ", line " . __line__); + } + + //return the result + return $result; + } + + public function block_exists(string $ip_address, string $filter) : bool { + //invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + //check if the address is blocked + $result = $this->firewall->block_exists($ip_address, $filter); + + //send debug information to the console + $this->debug("Address Exists " . $ip_address . ", line " . __line__); + + //return the result + return $result; + } + + /** + * Determine if access is allowed for a given IP address. + * + * This method checks the IP address is inside the cache, user logs, event guard logs, access controls, + * and registration to determine if access should be allowed. If the IP address is found + * in the access control list, user logs with result success, or valid registrations + * is found then the address is automatically allowed. + * + * @param string $ip_address The IP address to check for access. + * + * @return boolean True if access is allowed, false otherwise. + */ + private function allow_access($ip_address) { + + //invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + //check the cache to see if the address is allowed + $cache = new cache; + if ($cache->get("switch:allowed:".$ip_address) === 'true') { + //debug info + $this->debug("address: ".$ip_address." allowed by: cache"); + + //return boolean true + return true; + } + + //allow access for addresses with authentication status success + if ($this->allow_user_log_success($ip_address)) { + //save address to the cache as allowed + $cache->set("switch:allowed:".$ip_address, 'true'); + + //debug info + $this->debug("address: ".$ip_address." allowed by: user logs"); + + //return boolean true + return true; + } + + //allow access for addresses that have been unblocked + /* + if (event_guard_log_allowed($ip_address)) { + //save address to the cache as allowed + $cache->set("switch:allowed:".$ip_address, 'true'); + + //debug info + $this->debug("address: ".$ip_address." allowed by: unblocked"); + + //return boolean true + return true; + } + */ + + //allow access if the cidr address is allowed + if ($this->allow_access_control($ip_address)) { + //save address to the cache as allowed + $cache->set("switch:allowed:".$ip_address, 'true'); + + //debug info + $this->debug("address: ".$ip_address." allowed by: access controls"); + + //return boolean true + return true; + } + + //allow if there is a registration from the same IP address + if ($this->allow_registered($ip_address)) { + //save address to the cache as allowed + $cache->set("switch:allowed:".$ip_address, 'true'); + + //debug info + $this->debug("address: ".$ip_address." allowed by: registration"); + + //return boolean true + return true; + } + + //return + return false; + } + + /** + * Checks if the given IP address is authorized by any access control node. + * + * @param string $ip_address The IP address to check for authorization. + * + * @return bool True if the IP address is authorized, false otherwise. + */ + private function allow_access_control($ip_address) { + + //invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + //get the access control allowed nodes + $sql = "select access_control_node_uuid, access_control_uuid, node_cidr, node_description "; + $sql .= "from v_access_control_nodes "; + $sql .= "where node_type = 'allow' "; + $sql .= "and length(node_cidr) > 0 "; + $parameters = null; + $allowed_nodes = $this->database->select($sql, $parameters, 'all'); + + //default authorized to false + $allowed = false; + + //use the ip address to get the authorized nodes + if (is_array($allowed_nodes)) { + foreach($allowed_nodes as $row) { + if (check_cidr($row['node_cidr'], $ip_address)) { + //debug info + // print_r($row); + // $this->debug("Authorized: ".$ip_address); + + //set the allowed to true + $allowed = true; + + //exit the loop + break; + } + } + } + + //return + return $allowed; + } + + /** + * Determines if a user's IP address is allowed based on their login history. + * + * @param string $ip_address The IP address to check for access. + * + * @return bool True if the IP address is allowed, false otherwise. + */ + private function allow_user_log_success($ip_address) { + + //invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + //check to see if the address was authenticated successfully + $sql = "select count(user_log_uuid) "; + $sql .= "from v_user_logs "; + $sql .= "where remote_address = :remote_address "; + $sql .= "and result = 'success' "; + $sql .= "and timestamp > NOW() - INTERVAL '8 days' "; + $parameters['remote_address'] = $ip_address; + $user_log_count = $this->database->select($sql, $parameters, 'column'); + + //debug info + $this->debug("address ".$ip_address." count ".$user_log_count); + + //default authorized to false + $allowed = false; + + //use the ip address to get the authorized nodes + if (!empty($user_log_count) && $user_log_count > 0) { + $allowed = true; + } + + //return + return $allowed; + } + + /** + * Checks if the given IP address is registered on the network. + * + * @param string $ip_address The IP address to check for registration. + * + * @return bool True if the IP address is registered, false otherwise. + */ + private function allow_registered($ip_address) { + //invalid ip address + if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { + return false; + } + + $registered = false; + $command = "fs_cli -x 'show registrations as json' "; + $result = shell_exec($command); + $array = json_decode($result, true); + if (is_array($array['rows'])) { + foreach ($array['rows'] as $row) { + if ($row['network_ip'] == $ip_address) { + $registered = true; + } + } + } + + //return registered boolean + return $registered; + } +} diff --git a/app/event_guard/resources/interfaces/event_guard_interface.php b/app/event_guard/resources/interfaces/event_guard_interface.php new file mode 100644 index 0000000000..550cc72fd0 --- /dev/null +++ b/app/event_guard/resources/interfaces/event_guard_interface.php @@ -0,0 +1,11 @@ + - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. +require_once dirname(__DIR__, 4) . '/resources/require.php'; - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ +try { + // Create the service + $service = event_guard_service::create(); -//check the permission - if (defined('STDIN')) { - //includes files - require_once dirname(__DIR__, 4) . "/resources/require.php"; - } - else { - //only allow running this from command line - exit; - } + // Exit using the status run method returns + exit($service->run()); +} catch (Throwable $ex) { + // Show the details of the error + echo "Error occurred in " . $ex->getFile() . ' (' . $ex->getLine() . '):' . $ex->getMessage(); -//increase limits - set_time_limit(0); - ini_set('max_execution_time', 0); - ini_set('memory_limit', '256M'); - -//save the arguments to variables - $script_name = $argv[0]; - if (!empty($argv[1])) { - parse_str($argv[1], $_GET); - } - -//set the variables - if (!empty($_GET['hostname'])) { - $hostname = urldecode($_GET['hostname']); - } - $debug = false; - if (!empty($_GET['debug'])) { - if (is_numeric($_GET['debug'])) { - $debug_level = $_GET['debug']; - } - $debug = true; - } - -//get the hostname - if (empty($hostname)) { - $hostname = gethostname(); - } - -//set the php operating system - $php_os = strtolower(PHP_OS); - -//define the firewall command - if ($php_os == 'freebsd') { - $firewall_name = 'pf'; - if (file_exists('/sbin/pfctl')) { - $firewall_path = '/sbin'; - } - } - if ($php_os == 'linux') { - $firewall_name = 'iptables'; - - //find the firewall path - if (file_exists('/usr/sbin/iptables')) { - $firewall_path = '/usr/sbin'; - } - if (empty($firewall_path) && file_exists('/sbin/iptables')) { - $firewall_path = '/sbin'; - } - } - -//check if the firewall command was found - if (empty($firewall_path)) { - echo $firewall_name." command not found\n"; - exit; - } - -//add pf tables into your pf.conf file - //if ($firewall_name == 'pf') { - // table persist - // table persist - // block in quick from - // block in quick from - //} - -//add the iptables chains - if ($firewall_name == 'iptables') { - //create a chain array - $chains[] = 'sip-auth-ip'; - $chains[] = 'sip-auth-fail'; - - //loop through the chains - if (is_array($chains)) { - foreach ($chains as $chain) { - iptables_chain_add($chain); - } - } - } - -//define the process id file - $pid_file = "/var/run/fusionpbx/".basename($argv[0], ".php") .".pid"; - echo "pid_file: ".$pid_file."\n"; - -//function to check if the process exists - /** - * Checks if a process exists. - * - * @param string $file Path to the file containing the process ID (PID) - * - * @return bool True if the process exists, false otherwise - */ - function process_exists($file) { - - //set the default exists to false - $exists = false; - - //check to see if the process is running - if (file_exists($file)) { - $pid = file_get_contents($file); - if (function_exists('posix_getsid')) { - if (posix_getsid($pid) === false) { - //process is not running - $exists = false; - } - else { - //process is running - $exists = true; - } - } - else { - if (file_exists('/proc/'.$pid)) { - //process is running - $exists = true; - } - else { - //process is not running - $exists = false; - } - } - } - - //return the result - return $exists; - } - -//check to see if the process exists - $pid_exists = process_exists($pid_file); - -//prevent the process running more than once - if ($pid_exists) { - echo "Cannot lock pid file {$pid_file}\n"; - exit; - } - else { - echo "pid file exists\n"; - } - -//create the process id file if the process doesn't exist - if (!$pid_exists) { - //remove the old pid file - if (file_exists($pid_file)) { - unlink($pid_file); - } - - //show the details to the user - if (isset($debug) && $debug == true) { - echo "\n"; - echo "Service: ".basename( $argv[0], ".php")."\n"; - echo "Process ID: ".getmypid()."\n"; - echo "PID File: ".$pid_file."\n"; - } - - //save the pid file - file_put_contents($pid_file, getmypid()); - } - -//connect to the database - $database = database::new(); - -//test a specific address - //$ip_address = '10.7.0.253'; - //$result = access_allowed($ip_address); - -//connect to event socket - $socket = new event_socket; - if (!$socket->connect()) { - echo "Unable to connect to event socket\n"; - } - -//preset values - //$interval_seconds = 30; - //$previous_time = time() - $interval_seconds; - -//loop through the switch events - $cmd = "event json ALL"; - $result = $socket->request($cmd); - if ($debug) { print_r($result); } - - //filter for specific events - $cmd = "filter Event-Name CUSTOM"; - $result = $socket->request($cmd); - if ($debug) { print_r($result); } - - while (true) { - - //check pending unblock requests - /* - if ((time() - $previous_time) > $interval_seconds) { - //debug info - if ($debug) { - echo "time difference: ". (time() - $previous_time)."\n"; - } - - //update the time - $previous_time = time(); - } - */ - - //reconnect to event socket - if (!$socket->connected()) { - //echo "Not connected to even socket\n"; - if ($socket->connect()) { - $cmd = "event json ALL"; - $result = $socket->request($cmd); - if ($debug) { print_r($result); } - - $cmd = "filter Event-Name CUSTOM"; - $result = $socket->request($cmd); - if ($debug) { print_r($result); } - echo "Re-connected to event socket\n"; - } - else { - //unable to connect to event socket - echo "Unable to connect to event socket\n"; - - //sleep and then attempt to reconnect - sleep(1); - continue; - } - } - - //read the socket - $json_response = $socket->read_event(); - - //decode the response - if (isset($json_response) && $json_response != '') { - $json_array = json_decode($json_response['$'], true); - unset($json_response); - } - - //debug info - //if ($debug) { - // print_r($json_array); - //} - - //registration failed - block IP address unless they are registered - if (is_array($json_array) && $json_array['Event-Subclass'] == 'sofia::register_failure') { - //not registered so block the address - if (!access_allowed($json_array['network-ip'])) { - block($json_array['network-ip'], 'sip-auth-fail', $json_array); - } - } - - //sendevent CUSTOM event_guard:unblock - if (is_array($json_array) && $json_array['Event-Subclass'] == 'event_guard:unblock') { - //check the database for pending requests - $sql = "select event_guard_log_uuid, log_date, filter, ip_address, extension, user_agent "; - $sql .= "from v_event_guard_logs "; - $sql .= "where log_status = 'pending' "; - $sql .= "and hostname = :hostname "; - //if ($debug) { echo $sql." ".$hostname."\n"; } - $parameters['hostname'] = $hostname; - $event_guard_logs = $database->select($sql, $parameters, 'all'); - if (is_array($event_guard_logs)) { - foreach($event_guard_logs as $row) { - //unblock the ip address - unblock($row['ip_address'], $row['filter']); - - //log the blocked ip address to the syslog - openlog("fusionpbx", LOG_PID | LOG_PERROR, LOG_AUTH); - syslog(LOG_WARNING, "fusionpbx: unblocked: [ip_address: ".$row['ip_address'].", filter: ".$row['filter'].", to-user: ".$row['extension'].", to-host: ".$row['hostname'].", line: ".__line__."]"); - closelog(); - - //debug info - if ($debug) { - echo "unblocked: [ip_address: ".$row['ip_address'].", filter: ".$row['filter'].", to-user: ".$row['extension'].", to-host: ".$row['hostname'].", line: ".__line__."]\n"; - } - - //log the blocked ip address to the database - $array['event_guard_logs'][$x]['event_guard_log_uuid'] = $row['event_guard_log_uuid']; - $array['event_guard_logs'][$x]['log_date'] = 'now()'; - $array['event_guard_logs'][$x]['log_status'] = 'unblocked'; - $x++; - } - if (is_array($array)) { - $p = permissions::new(); - $p->add('event_guard_log_edit', 'temp'); - $database->app_name = 'event guard'; - $database->app_uuid = 'c5b86612-1514-40cb-8e2c-3f01a8f6f637'; - $database->save($array, false); - //$message = $database->message; - $p->delete('event_guard_log_edit', 'temp'); - unset($array); - } - } - } - - //registration to the IP address - if (is_array($json_array) && $json_array['Event-Subclass'] == 'sofia::pre_register') { - if (isset($json_array['to-host'])) { - $is_valid_ip = filter_var($json_array['to-host'], FILTER_VALIDATE_IP); - if ($is_valid_ip) { - //if not registered block the address - if (!access_allowed($json_array['network-ip'])) { - block($json_array['network-ip'], 'sip-auth-ip', $json_array); - } - - //debug info - if ($debug) { - echo "network-ip ".$json_array['network-ip']."\n"; - echo "to-host ".$json_array['to-host']."\n"; - echo "\n"; - } - } - } - } - - //debug information - //if ($debug && ($json_array['Event-Subclass'] == 'sofia::register_failure' || $json_array['Event-Subclass'] == 'sofia::pre_register')) { - - //echo "\n"; - //print_r($json_array); - - //echo "event_name: ".$json_array['Event-Name']."\n"; - //echo "event_type: ".$json_array['event_type']."\n"; - //echo "event_subclass: ".$json_array['Event-Subclass']."\n"; - //echo "status: ".$json_array['status']."\n"; - //echo "network_ip: ".$json_array['network-ip']."\n"; - //echo "channel_state: ".$json_array['Channel-State']."\n"; - //echo "channel_call_state: ".$json_array['Channel-Call-State']."\n"; - //echo "call_direction: ".$json_array['Call-Direction']."\n"; - //echo "channel_call_uuid: ".$json_array['Channel-Call-UUID']."\n"; - //echo "answer_state: ".$json_array['Answer-State']."\n"; - //echo "hangup_cause: ".$json_array['Hangup-Cause']."\n"; - //echo "to-host: $json_array['to-host']\n"; - //echo "\n"; - //} - - //unset the array - if (is_array($json_array)) { - unset($json_array); - } - - //debug info - if ($debug && $debug_level == '2') { - //current memory - $memory_usage = memory_get_usage(); - - //peak memory - $memory_peak = memory_get_peak_usage(); - echo "\n"; - echo 'Current memory: ' . round($memory_usage / 1024) . " KB\n"; - echo 'Peak memory: ' . round($memory_peak / 1024) . " KB\n\n"; - echo "\n"; - } - - } - -//run command and capture standard output - /** - * Execute a shell command and capture its output. - * - * @param string $command The shell command to execute - * - * @return string The output of the executed command - */ - function shell($command) { - ob_start(); - $result = system($command); - ob_get_clean(); - return $result; - } - -//block an ip address - /** - * Execute a block command for iptables or pf based on the firewall type. - * - * @param string $ip_address The IP address to block - * @param string $filter The filter name for iptables or pf - * @param array $event The event data containing 'to-user' and 'to-host' - * - * @return boolean True if the block command was executed successfully, false otherwise - */ - function block($ip_address, $filter, $event) { - //define the global variables - global $database, $debug, $firewall_path, $firewall_name; - - //invalid ip address - if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { - return false; - } - - //run the block command for iptables - if ($firewall_name == 'iptables') { - //example: iptables -I INPUT -s 127.0.0.1 -j DROP - $command = $firewall_path.'/./iptables -I '.$filter.' -s '.$ip_address.' -j DROP'; - $result = shell($command); - } - - //run the block command for pf - if ($firewall_name == 'pf') { - //example: pfctl -t sip-auth-ip -T add 127.0.0.5 - $command = $firewall_path.'/pfctl -t '.$filter.' -T add '.$ip_address; - $result = shell($command); - } - - //log the blocked ip address to the syslog - openlog("fusionpbx", LOG_PID | LOG_PERROR, LOG_AUTH); - syslog(LOG_WARNING, "fusionpbx: blocked: [ip_address: ".$ip_address.", filter: ".$filter.", to-user: ".$event['to-user'].", to-host: ".$event['to-host'].", line: ".__line__."]"); - closelog(); - - //log the blocked ip address to the database - $array = []; - $array['event_guard_logs'][0]['event_guard_log_uuid'] = uuid(); - $array['event_guard_logs'][0]['hostname'] = gethostname(); - $array['event_guard_logs'][0]['log_date'] = 'now()'; - $array['event_guard_logs'][0]['filter'] = $filter; - $array['event_guard_logs'][0]['ip_address'] = $ip_address; - $array['event_guard_logs'][0]['extension'] = $event['to-user'].'@'.$event['to-host']; - $array['event_guard_logs'][0]['user_agent'] = $event['user-agent']; - $array['event_guard_logs'][0]['log_status'] = 'blocked'; - $p = permissions::new(); - $p->add('event_guard_log_add', 'temp'); - $database->app_name = 'event guard'; - $database->app_uuid = 'c5b86612-1514-40cb-8e2c-3f01a8f6f637'; - $database->save($array, false); - $p->delete('event_guard_log_add', 'temp'); - - //send debug information to the console - if ($debug) { - echo "blocked address ".$ip_address .", line ".__line__."\n"; - } - - } - -//unblock the ip address - /** - * Unblock a specified IP address from a firewall. - * - * @param string $ip_address The IP address to unblock. - * @param string $filter The filter name used in the firewall configuration. - * - * @return bool True if the IP address was successfully unblocked, false otherwise. - */ - function unblock($ip_address, $filter) { - //define the global variables - global $debug, $firewall_path, $firewall_name; - - //invalid ip address - if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { - return false; - } - - //unblock the address - if ($firewall_name == 'iptables') { - $command = $firewall_path.'/./iptables -L '.$filter.' -n --line-numbers | grep "'.$ip_address.' " | cut -d " " -f1'; - $line_number = trim(shell($command)); - echo "\n". $command . " line ".__line__."\n"; - if (is_numeric($line_number)) { - //$result = shell('iptables -D INPUT '.$line_number); - $command = $firewall_path.'/./iptables -D '.$filter.' '.$line_number; - $result = shell($command); - echo "Unblock address ".$ip_address ." line ".$line_number." command ".$command." result ".$result."\n"; - } - } - - //unblock the address - if ($firewall_name == 'pf') { - //example: pfctl -t sip-auth-ip -T delete 127.0.0.5 - $command = $firewall_path.'/pfctl -t '.$filter.' -T delete '.$ip_address; - $result = shell($command); - } - - //send debug information to the console - if ($debug) { - echo "Unblock address ".$ip_address ."\n"; - } - } - -//is the ip address blocked - /** - * Check if an IP address is blocked in the configured firewall. - * - * @param string $ip_address The IP address to check - * - * @return bool True if the address is blocked, False otherwise - */ - function is_blocked($ip_address) { - //define the global variables - global $firewall_path, $firewall_name; - - //invalid ip address - if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { - return false; - } - - //determine whether to return true or false - if ($firewall_name == 'iptables') { - //check to see if the address is blocked - $command = $firewall_path.'/./iptables -L -n --line-numbers | grep '.$ip_address; - $result = shell($command); - if (!empty($result) && strlen($result) > 3) { - return true; - } - } - elseif ($firewall_name == 'pf') { - //check to see if the address is blocked - $command = $firewall_path.'/pfctl -t ".$filter." -Ts | grep '.$ip_address; - $result = shell($command); - if (!empty($result) && strlen($result) > 3) { - return true; - } - } - else { - return false; - } - } - -//determine if the IP address has been allowed by the access control list node cidr - /** - * Determine if access is allowed for a given IP address. - * - * This method checks the cache, user logs, event guard logs, access controls, - * and registration to determine if access should be granted. If no valid reason - * is found to deny access, it will be automatically allowed. - * - * @param string $ip_address The IP address to check for access. - * - * @return boolean True if access is allowed, false otherwise. - */ - function access_allowed($ip_address) { - //define global variables - global $debug; - - //invalid ip address - if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { - return false; - } - - //check the cache to see if the address is allowed - $cache = new cache; - if ($cache->get("switch:allowed:".$ip_address) === 'true') { - //debug info - if ($debug) { - echo "address: ".$ip_address." allowed by: cache\n"; - } - - //return boolean true - return true; - } - - //allow access for addresses with authentication status success - if (user_log_allowed($ip_address)) { - //save address to the cache as allowed - $cache->set("switch:allowed:".$ip_address, 'true'); - - //debug info - if ($debug) { - echo "address: ".$ip_address." allowed by: user logs\n"; - } - - //return boolean true - return true; - } - - //allow access for addresses that have been unblocked - /* - if (event_guard_log_allowed($ip_address)) { - //save address to the cache as allowed - $cache->set("switch:allowed:".$ip_address, 'true'); - - //debug info - if ($debug) { - echo "address: ".$ip_address." allowed by: unblocked\n"; - } - - //return boolean true - return true; - } - */ - - //allow access if the cidr address is allowed - if (access_control_allowed($ip_address)) { - //save address to the cache as allowed - $cache->set("switch:allowed:".$ip_address, 'true'); - - //debug info - if ($debug) { - echo "address: ".$ip_address." allowed by: access controls\n"; - } - - //return boolean true - return true; - } - - //auto allow if there is a registration from the same IP address - if (is_registered($ip_address)) { - //save address to the cache as allowed - $cache->set("switch:allowed:".$ip_address, 'true'); - - //debug info - if ($debug) { - echo "address: ".$ip_address." allowed by: registration\n"; - } - - //return boolean true - return true; - } - - //return - return false; - } - -//is the ip address registered - /** - * Checks if the given IP address is registered on the network. - * - * @param string $ip_address The IP address to check for registration. - * - * @return bool True if the IP address is registered, false otherwise. - */ - function is_registered($ip_address) { - //invalid ip address - if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { - return false; - } - - $registered = false; - $command = "fs_cli -x 'show registrations as json' "; - $result = shell($command); - $array = json_decode($result, true); - if (is_array($array['rows'])) { - foreach ($array['rows'] as $row) { - if ($row['network_ip'] == $ip_address) { - $registered = true; - } - } - } - - //return registered boolean - return $registered; - } - -//determine if the IP address has been allowed by the access control list node cidr - /** - * Checks if the given IP address is authorized by any access control node. - * - * @param string $ip_address The IP address to check for authorization. - * - * @return bool True if the IP address is authorized, false otherwise. - */ - function access_control_allowed($ip_address) { - - global $database; - - //invalid ip address - if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { - return false; - } - - //get the access control allowed nodes - $sql = "select access_control_node_uuid, access_control_uuid, node_cidr, node_description "; - $sql .= "from v_access_control_nodes "; - $sql .= "where node_type = 'allow' "; - $sql .= "and length(node_cidr) > 0 "; - $parameters = null; - $allowed_nodes = $database->select($sql, $parameters, 'all'); - - //default authorized to false - $allowed = false; - - //use the ip address to get the authorized nodes - if (is_array($allowed_nodes)) { - foreach($allowed_nodes as $row) { - if (check_cidr($row['node_cidr'], $ip_address)) { - //debug info - //if ($debug) { - // print_r($row); - // echo $ip_address."\n"; - //} - - //set the allowed to true - $allowed = true; - - //exit the loop - break; - } - } - } - - //return - return $allowed; - } - -//determine if the IP address has been allowed by a successful authentication - /** - * Determines if a user's IP address is allowed based on their login history. - * - * @param string $ip_address The IP address to check for access. - * - * @return bool True if the IP address is allowed, false otherwise. - */ - function user_log_allowed($ip_address) { - - global $database, $debug; - - //invalid ip address - if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { - return false; - } - - //check to see if the address was authenticated successfully - $sql = "select count(user_log_uuid) "; - $sql .= "from v_user_logs "; - $sql .= "where remote_address = :remote_address "; - $sql .= "and result = 'success' "; - $sql .= "and timestamp > NOW() - INTERVAL '8 days' "; - $parameters['remote_address'] = $ip_address; - $user_log_count = $database->select($sql, $parameters, 'column'); - - //debug info - if ($debug) { - echo "address ".$ip_address." count ".$user_log_count."\n"; - } - - //default authorized to false - $allowed = false; - - //use the ip address to get the authorized nodes - if (!empty($user_log_count) && $user_log_count > 0) { - $allowed = true; - } - - //return - return $allowed; - } - -//determine if the IP address has been unblocked in the event guard log - /** - * Determines if an IP address is allowed based on event guard logs. - * - * @param string $ip_address The IP address to check for access. - * - * @return bool True if the IP address is allowed, false otherwise. - */ - function event_guard_log_allowed($ip_address) { - - global $database, $debug; - - //invalid ip address - if (!filter_var($ip_address, FILTER_VALIDATE_IP)) { - return false; - } - - //get the access control allowed nodes - $sql = "select count(event_guard_log_uuid) "; - $sql .= "from v_event_guard_logs "; - $sql .= "where ip_address = :ip_address "; - $sql .= "and log_status = 'unblocked' "; - $parameters['ip_address'] = $ip_address; - $user_log_count = $database->select($sql, $parameters, 'column'); - - //debug info - if ($debug) { - echo "address ".$ip_address." count ".$user_log_count."\n"; - } - - //default authorized to false - $allowed = false; - - //use the ip address to get the authorized nodes - if ($user_log_count > 0) { - $allowed = true; - } - - //return - return $allowed; - } - -//check if the iptables chain exists - /** - * Determines if a pf table exists in the firewall configuration. - * - * @param string $table The name of the pf table to check for existence. - * - * @return bool True if the pf table exists, false otherwise. - */ - function pf_table_exists($table) { - //define the global variables - global $firewall_path, $firewall_name; - - //build the command to check if the pf table exists - $command = $firewall_path."/./pfctl -t ".$table." -T show | grep error"; - //if ($debug) { echo $command."\n"; } - $response = shell($command); - if (!empty($response)) { - return true; - } - else { - return false; - } - } - -//add IP table chains - /** - * Adds a new IPtables chain and inserts it into the INPUT table. - * - * @param string $chain The name of the IPtables chain to add. - * - * @return bool True if the chain was successfully added, false otherwise. - */ - function iptables_chain_add($chain) { - //define the global variables - global $firewall_path; - - //if the chain exists return true - if (iptables_chain_exists($chain)) { - echo "IPtables ".$chain." chain already exists\n"; - return true; - } - - //log info to the console - echo "Add iptables ".$chain." chain\n"; - - //add the chain - system($firewall_path.'/./iptables --new '.$chain); - system($firewall_path.'/./iptables -I INPUT -j '.$chain); - - //check if the chain exists - if (iptables_chain_exists($chain)) { - return true; - } - else { - sleep(1); - iptables_chain_add($chain); - } - } - -//check if the iptables chain exists - /** - * Determines if a specified iptables chain exists. - * - * @param string $chain The name of the iptables chain to check for existence. - * - * @return bool True if the iptables chain exists, false otherwise. - */ - function iptables_chain_exists($chain) { - //define the global variables - global $firewall_path; - - //build the command to check if the iptables chain exists - $command = $firewall_path."/./iptables --list INPUT --numeric | grep ".$chain." | awk '{print \$1}' | sed ':a;N;\$!ba;s/\\n/,/g' "; - //if ($debug) { echo $command."\n"; } - $response = shell($command); - if (in_array($chain, explode(",", $response))) { - return true; - } - else { - return false; - } - } + // Exit with error code + exit($ex->getCode()); +}