mirror of
https://github.com/lucaspalomodevelop/core.git
synced 2026-03-13 08:09:41 +00:00
dhcp: migrate leases page to MVC (#6643)
- reworks the get_leases.py script to accomodate the "last declaration is the current one" logic from dhcpd.leases(5). (neither core nor plugins is currently using this action) - includes binding states for failover setups in dhcpd.py lease file parsing. These are included in the leases page if show inactive is selected. - adds small utility function in Firewall/Utility to check wheter a given IP (4 or 6) is within the bounds of a given CIDR block. Needed to bind a lease declaration to an interface in the front end. - remove dhcpleaseinlocaltime property from services_dhcp.php. dhcpd.py works with epochs, so we only need to convert to a sensible local date in the controller. - implements multiselect lease deletion - implements multiselect interface filtering - does not yet hook into ApiMutableServiceControllerBase, since the legacy configuration makes it a bit tricky.
This commit is contained in:
parent
6bc025af17
commit
4b7a1ce85b
5
plist
5
plist
@ -281,6 +281,9 @@
|
||||
/usr/local/opnsense/mvc/app/controllers/OPNsense/Cron/IndexController.php
|
||||
/usr/local/opnsense/mvc/app/controllers/OPNsense/Cron/ItemController.php
|
||||
/usr/local/opnsense/mvc/app/controllers/OPNsense/Cron/forms/dialogEdit.xml
|
||||
/usr/local/opnsense/mvc/app/controllers/OPNsense/DHCP/Api/Leases4Controller.php
|
||||
/usr/local/opnsense/mvc/app/controllers/OPNsense/DHCP/Api/ServiceController.php
|
||||
/usr/local/opnsense/mvc/app/controllers/OPNsense/DHCP/Leases4Controller.php
|
||||
/usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/ActivityController.php
|
||||
/usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/ActivityController.php
|
||||
/usr/local/opnsense/mvc/app/controllers/OPNsense/Diagnostics/Api/DnsController.php
|
||||
@ -711,6 +714,7 @@
|
||||
/usr/local/opnsense/mvc/app/views/OPNsense/Core/reboot.volt
|
||||
/usr/local/opnsense/mvc/app/views/OPNsense/Core/service.volt
|
||||
/usr/local/opnsense/mvc/app/views/OPNsense/Cron/index.volt
|
||||
/usr/local/opnsense/mvc/app/views/OPNsense/DHCP/leases4.volt
|
||||
/usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/arp.volt
|
||||
/usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/dns_diagnostics.volt
|
||||
/usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/fw_log.volt
|
||||
@ -2007,7 +2011,6 @@
|
||||
/usr/local/www/services_ntpd_pps.php
|
||||
/usr/local/www/services_opendns.php
|
||||
/usr/local/www/services_router_advertisements.php
|
||||
/usr/local/www/status_dhcp_leases.php
|
||||
/usr/local/www/status_dhcpv6_leases.php
|
||||
/usr/local/www/status_habackup.php
|
||||
/usr/local/www/status_interfaces.php
|
||||
|
||||
@ -1856,7 +1856,7 @@ function dhcpd_dhcrelay6_configure($verbose = false)
|
||||
service_log("done.\n", $verbose);
|
||||
}
|
||||
|
||||
function dhcpd_staticmap($domain_fallback = 'not.found', $ifconfig_details = null, $valid_addresses = true, $proto = null)
|
||||
function dhcpd_staticmap($proto = null, $domain_fallback = 'not.found', $ifconfig_details = null, $valid_addresses = true)
|
||||
{
|
||||
$staticmap = [];
|
||||
foreach (empty($proto) ? [4, 6] : [$proto] as $inet) {
|
||||
|
||||
@ -258,7 +258,7 @@ function _dnsmasq_add_host_entries()
|
||||
$domain = $config['dnsmasq']['regdhcpdomain'];
|
||||
}
|
||||
|
||||
foreach (plugins_run('static_mapping', [$domain, legacy_interfaces_details()]) as $map) {
|
||||
foreach (plugins_run('static_mapping', [null, $domain, legacy_interfaces_details()]) as $map) {
|
||||
foreach ($map as $host) {
|
||||
if (empty($host['hostname'])) {
|
||||
/* cannot register without a hostname */
|
||||
|
||||
@ -544,7 +544,7 @@ function unbound_add_host_entries($ifconfig_details)
|
||||
}
|
||||
|
||||
if (!empty($general['regdhcpstatic'])) {
|
||||
foreach (plugins_run('static_mapping', [$config['system']['domain'], $ifconfig_details]) as $map) {
|
||||
foreach (plugins_run('static_mapping', [null, $config['system']['domain'], $ifconfig_details]) as $map) {
|
||||
foreach ($map as $host) {
|
||||
if (empty($host['hostname'])) {
|
||||
/* cannot register without a hostname */
|
||||
|
||||
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 Deciso B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\DHCP\Api;
|
||||
|
||||
use OPNsense\Base\ApiControllerBase;
|
||||
use OPNsense\Core\Backend;
|
||||
use OPNsense\Core\Config;
|
||||
use OPNsense\Firewall\Util;
|
||||
|
||||
class Leases4Controller extends ApiControllerBase
|
||||
{
|
||||
public function searchLeaseAction()
|
||||
{
|
||||
$this->sessionClose();
|
||||
$inactive = $this->request->get('inactive');
|
||||
$selected_interfaces = $this->request->get('selected_interfaces');
|
||||
$backend = new Backend();
|
||||
$config = Config::getInstance()->object();
|
||||
$online = [];
|
||||
|
||||
/* get ARP data to match on */
|
||||
$arp_data = json_decode($backend->configdRun('interface list arp json'), true);
|
||||
|
||||
foreach ($arp_data as $arp_entry) {
|
||||
if (!$arp_entry['expired']) {
|
||||
array_push($online, $arp_entry['mac'], $arp_entry['ip']);
|
||||
}
|
||||
}
|
||||
|
||||
/* get configured static leases */
|
||||
$sleases = json_decode($backend->configdRun('dhcpd list static 4'), true);
|
||||
|
||||
/* include inactive leases if requested */
|
||||
$leases = json_decode($backend->configdpRun('dhcpd list leases', [$inactive]), true);
|
||||
foreach ($leases as $idx => $lease) {
|
||||
/* set defaults */
|
||||
$leases[$idx]['type'] = 'dynamic';
|
||||
$leases[$idx]['status'] = 'offline';
|
||||
$leases[$idx]['descr'] = '';
|
||||
$leases[$idx]['mac'] = '';
|
||||
$leases[$idx]['starts'] = '';
|
||||
$leases[$idx]['ends'] = '';
|
||||
$leases[$idx]['hostname'] = '';
|
||||
$leases[$idx]['state'] = $lease['binding'] == 'free' ? 'expired' : $lease['binding'];
|
||||
|
||||
if (array_key_exists('hardware', $lease)) {
|
||||
$mac = $lease['hardware']['mac-address'];
|
||||
$leases[$idx]['mac'] = $mac;
|
||||
$leases[$idx]['status'] = in_array(strtolower($lease['address']), $online) ? 'online' : 'offline';
|
||||
unset($leases[$idx]['hardware']);
|
||||
}
|
||||
|
||||
if (array_key_exists('starts', $lease)) {
|
||||
$leases[$idx]['starts'] = date('Y/m/d H:i:s', $lease['starts']);
|
||||
}
|
||||
|
||||
if (array_key_exists('ends', $lease)) {
|
||||
$leases[$idx]['ends'] = date('Y/m/d H:i:s', $lease['ends']);
|
||||
}
|
||||
|
||||
if (array_key_exists('client-hostname', $lease)) {
|
||||
$leases[$idx]['hostname'] = $lease['client-hostname'];
|
||||
}
|
||||
}
|
||||
|
||||
/* handle static leases */
|
||||
$statics = [];
|
||||
foreach ($sleases["dhcpd"] as $slease) {
|
||||
$static = [];
|
||||
$static['address'] = $slease['ipaddr'];
|
||||
$static['type'] = 'static';
|
||||
$static['mac'] = $slease['mac'];
|
||||
$static['starts'] = '';
|
||||
$static['ends'] = '';
|
||||
$static['hostname'] = $slease['hostname'];
|
||||
$static['descr'] = $slease['descr'];
|
||||
$static['state'] = 'active';
|
||||
$static['status'] = in_array(strtolower($static['mac']), $online) ? 'online' : 'offline';
|
||||
$statics[] = $static;
|
||||
}
|
||||
|
||||
$leases = array_merge($leases, $statics);
|
||||
|
||||
$mac_man = json_decode($backend->configdRun('interface list macdb json'), true);
|
||||
$interfaces = [];
|
||||
foreach ($leases as $idx => $lease) {
|
||||
/* include manufacturer info */
|
||||
$leases[$idx]['man'] = '';
|
||||
if ($lease['mac'] != '') {
|
||||
$mac_hi = strtoupper(substr(str_replace(':', '', $lease['mac']),0, 6));
|
||||
$leases[$idx]['man'] = $mac_man[$mac_hi];
|
||||
}
|
||||
|
||||
/* include interface */
|
||||
$leases[$idx]['if_descr'] = '';
|
||||
$leases[$idx]['if'] = '';
|
||||
foreach ($config->dhcpd->children() as $dhcpif => $dhcpifconf) {
|
||||
$if = $config->interfaces->$dhcpif;
|
||||
if (!empty((string)$if->ipaddr) && Util::isIpAddress((string)$if->ipaddr)) {
|
||||
if (Util::isIPInCIDR($lease['address'], (string)$if->ipaddr . '/' . (string)$if->subnet)) {
|
||||
$intf = (string)$if->descr;
|
||||
$leases[$idx]['if_descr'] = $intf;
|
||||
$leases[$idx]['if'] = $dhcpif;
|
||||
|
||||
if (!array_key_exists($dhcpif, $interfaces)) {
|
||||
$interfaces[$dhcpif] = $intf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response = $this->searchRecordsetBase($leases, null, 'address', function ($key) use ($selected_interfaces) {
|
||||
if (empty($selected_interfaces) || in_array($key['if'], $selected_interfaces)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
/* present relevant interfaces to the view so they can be sorted on */
|
||||
$response['interfaces'] = $interfaces;
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function delLeaseAction($ip)
|
||||
{
|
||||
$result = ["result" => "failed"];
|
||||
|
||||
if ($this->request->isPost()) {
|
||||
$this->sessionClose();
|
||||
$response = json_decode((new Backend())->configdpRun("dhcpd remove lease", [$ip]), true);
|
||||
if ($response["removed_leases"] != "0") {
|
||||
$result["result"] = "deleted";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 Deciso B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\DHCP\Api;
|
||||
|
||||
use OPNsense\Base\ApiControllerBase;
|
||||
use OPNsense\Core\Backend;
|
||||
|
||||
class ServiceController extends ApiControllerBase
|
||||
{
|
||||
/**
|
||||
* XXX most of this logic can be replaced when appropriate start/stop/restart/status
|
||||
* hooks are provided to fit into an ApiMutableServiceControllerBase class. dhcpd being
|
||||
* 'enabled' isn't as straight-forward however with current legacy config format.
|
||||
*/
|
||||
public function statusAction()
|
||||
{
|
||||
$response = trim((new Backend())->configdRun('service status dhcpd'));
|
||||
|
||||
if (strpos($response, 'is running') > 0) {
|
||||
$status = 'running';
|
||||
} elseif (strpos($response, 'not running') > 0) {
|
||||
$status = 'stopped';
|
||||
} else {
|
||||
$status = 'disabled';
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => $status,
|
||||
'widget' => [
|
||||
'caption_stop' => gettext("stop service"),
|
||||
'caption_start' => gettext("start service"),
|
||||
'caption_restart' => gettext("restart service")
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function startAction()
|
||||
{
|
||||
$result = ['status' => 'failed'];
|
||||
|
||||
if ($this->request->isPost()) {
|
||||
$this->sessionClose();
|
||||
$response = trim((new Backend())->configdRun('service start dhcpd'));
|
||||
return ['status' => $response];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function stopAction()
|
||||
{
|
||||
$result = ['status' => 'failed'];
|
||||
|
||||
if ($this->request->isPost()) {
|
||||
$this->sessionClose();
|
||||
$response = trim((new Backend())->configdRun('service stop dhcpd'));
|
||||
return ['status' => $response];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function restartAction()
|
||||
{
|
||||
$result = ['status' => 'failed'];
|
||||
|
||||
if ($this->request->isPost()) {
|
||||
$this->sessionClose();
|
||||
$response = trim((new Backend())->configdRun('service restart dhcpd'));
|
||||
return ['status' => $response];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 Deciso B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace OPNsense\DHCP;
|
||||
|
||||
use OPNsense\Base\IndexController;
|
||||
|
||||
class Leases4Controller extends IndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->pick('OPNsense/DHCP/leases4');
|
||||
}
|
||||
}
|
||||
@ -339,6 +339,59 @@ class Util
|
||||
return md5(json_encode($rule));
|
||||
}
|
||||
|
||||
private static function isIPv4InCIDR($ip, $cidr)
|
||||
{
|
||||
list ($subnet, $bits) = explode('/', $cidr);
|
||||
if ($bits === null) {
|
||||
$bits = 32;
|
||||
}
|
||||
$ip = ip2long($ip);
|
||||
$subnet = ip2long($subnet);
|
||||
$mask = -1 << (32 - $bits);
|
||||
$subnet &= $mask;
|
||||
return ($ip & $mask) == $subnet;
|
||||
}
|
||||
|
||||
private static function isIPv6InCIDR($ip, $cidr)
|
||||
{
|
||||
$inet_to_bits = function($ip) {
|
||||
$split = str_split($ip);
|
||||
$bin_ip = '';
|
||||
foreach ($split as $char) {
|
||||
$bin_ip .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT);
|
||||
}
|
||||
return $bin_ip;
|
||||
};
|
||||
|
||||
$in_addr = inet_pton($ip);
|
||||
$bin_ip = $inet_to_bits($in_addr);
|
||||
|
||||
list ($net, $maskbits) = explode('/', $cidr);
|
||||
$net = inet_pton($net);
|
||||
$bin_net = $inet_to_bits($net);
|
||||
|
||||
$ip_net_bits = substr($bin_ip, 0, $maskbits);
|
||||
$net_bits = substr($bin_net, 0, $maskbits);
|
||||
|
||||
return $ip_net_bits === $net_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns whether a given IP (v4 or v6) is in a CIDR block
|
||||
*/
|
||||
public static function isIPInCIDR($ip, $cidr)
|
||||
{
|
||||
if (!self::isIpAddress($ip)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (str_contains($ip, ':')) {
|
||||
return self::isIPv6InCIDR($ip, $cidr);
|
||||
}
|
||||
|
||||
return self::isIPv4InCIDR($ip, $cidr);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert ipv4 cidr to netmask e.g. 24 --> 255.255.255.0
|
||||
* @param int $bits ipv4 bits
|
||||
|
||||
@ -455,6 +455,13 @@
|
||||
<pattern>services_dhcp.php*</pattern>
|
||||
</patterns>
|
||||
</page-services-dhcpserver>
|
||||
<page-services-dhcpserver-leases>
|
||||
<name>Services: DHCP Server: Leases</name>
|
||||
<patterns>
|
||||
<pattern>ui/dhcp/leases4</pattern>
|
||||
<pattern>api/dhcp/leases4/*</pattern>
|
||||
</patterns>
|
||||
</page-services-dhcpserver-leases>
|
||||
<page-services-dhcpv6relay>
|
||||
<name>Services: DHCPv6 Relay</name>
|
||||
<patterns>
|
||||
|
||||
@ -186,9 +186,7 @@
|
||||
<Services order="60" cssClass="fa fa-cog">
|
||||
<DHCPv4 cssClass="fa fa-bullseye fa-fw">
|
||||
<Relay order="200" url="/services_dhcp_relay.php"/>
|
||||
<Leases order="300" url="/status_dhcp_leases.php">
|
||||
<Details url="/status_dhcp_leases.php?*" visibility="hidden"/>
|
||||
</Leases>
|
||||
<Leases order="300" url="/ui/dhcp/leases4"/>
|
||||
<LogFile VisibleName="Log File" order="400" url="/ui/diagnostics/log/core/dhcpd"/>
|
||||
</DHCPv4>
|
||||
<DHCPv6 cssClass="fa fa-bullseye fa-fw">
|
||||
|
||||
173
src/opnsense/mvc/app/views/OPNsense/DHCP/leases4.volt
Normal file
173
src/opnsense/mvc/app/views/OPNsense/DHCP/leases4.volt
Normal file
@ -0,0 +1,173 @@
|
||||
{#
|
||||
# Copyright (c) 2023 Deciso B.V.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# 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.
|
||||
#}
|
||||
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
let show_inactive = false;
|
||||
let selected_interfaces = [];
|
||||
|
||||
if (window.localStorage) {
|
||||
if (window.localStorage.getItem("api.dhcp.leases.inactive") !== null) {
|
||||
show_inactive = window.localStorage.getItem("api.dhcp.leases.inactive") == 'true'
|
||||
$("#show-inactive").prop('checked', show_inactive);
|
||||
}
|
||||
}
|
||||
|
||||
$("#show-inactive").change(function() {
|
||||
show_inactive = this.checked;
|
||||
if (window.localStorage) {
|
||||
window.localStorage.setItem("api.dhcp.leases.inactive", show_inactive);
|
||||
}
|
||||
|
||||
$("#grid-leases").bootgrid('reload');
|
||||
});
|
||||
|
||||
$("#interface-selection").on("changed.bs.select", function (e) {
|
||||
selected_interfaces = $(this).val();
|
||||
$("#grid-leases").bootgrid('reload');
|
||||
})
|
||||
|
||||
$("#grid-leases").UIBootgrid({
|
||||
search:'/api/dhcp/leases4/searchLease/',
|
||||
del:'/api/dhcp/leases4/delLease/',
|
||||
options: {
|
||||
multiSelect: true,
|
||||
useRequestHandlerOnGet: true,
|
||||
requestHandler: function(request) {
|
||||
request['inactive'] = show_inactive;
|
||||
request['selected_interfaces'] = selected_interfaces;
|
||||
return request;
|
||||
},
|
||||
responseHandler: function (response) {
|
||||
if (response.hasOwnProperty('interfaces')) {
|
||||
for ([intf, descr] of Object.entries(response['interfaces'])) {
|
||||
let exists = false;
|
||||
$('#interface-selection option').each(function() {
|
||||
if (this.value == intf) {
|
||||
exists = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!exists) {
|
||||
$("#interface-selection").append($('<option>', {
|
||||
value: intf,
|
||||
text: descr
|
||||
}));
|
||||
}
|
||||
}
|
||||
$("#interface-selection").selectpicker('refresh');
|
||||
}
|
||||
return response;
|
||||
},
|
||||
formatters: {
|
||||
"macformatter": function (column, row) {
|
||||
if (row.man != '') {
|
||||
return row.mac + '<br/>' + '<small><i>' + row.man + '</i></small>';
|
||||
}
|
||||
return row.mac;
|
||||
},
|
||||
"statusformatter": function (column, row) {
|
||||
let connected = row.status == 'offline' ? 'text-danger' : 'text-success';
|
||||
return '<i class="fa fa-plug ' + connected +'" title="' + row.status + '" data-toggle="tooltip"></i>'
|
||||
},
|
||||
"commands": function (column, row) {
|
||||
/* we override the default commands data formatter in order to utilize
|
||||
* two different types of data keys for two different actions. The mapping
|
||||
* action needs a MAC address, while the delete action requires an IP address.
|
||||
*/
|
||||
if (row.type == 'static') {
|
||||
return '';
|
||||
}
|
||||
|
||||
let static_map = '<a class="btn btn-default btn-xs" href="/services_dhcp_edit.php?if=' + row.if +
|
||||
'&mac=' + row.mac + '&hostname=' + row["hostname"] + '">' +
|
||||
'<i class="fa fa-plus fa-fw act-map" data-value="' + row.mac + '" data-toggle="tooltip" ' +
|
||||
'title="{{lang._("Add a static mapping for this MAC address")}}"></i>' +
|
||||
'</a>';
|
||||
|
||||
/* The delete action can be hooked up to the default bootgrid behaviour */
|
||||
let deleteip = '<button type="button" class="btn btn-xs btn-default bootgrid-tooltip command-delete"' +
|
||||
'data-row-id="' + row.address + '" data-action="deleteSelected">' +
|
||||
'<i class="fa fa-trash fa-fw"></i>' +
|
||||
'</a>';
|
||||
|
||||
return static_map + ' ' + deleteip;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$("#inactive-selection-wrapper").detach().prependTo('#grid-leases-header > .row > .actionBar');
|
||||
$("#interface-selection-wrapper").detach().prependTo('#grid-leases-header > .row > .actionBar > .actions');
|
||||
|
||||
updateServiceControlUI('dhcp');
|
||||
});
|
||||
</script>
|
||||
|
||||
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs"></ul>
|
||||
<div class="tab-content content-box col-xs-12 __mb">
|
||||
<div id="dot" class="tab-pane fade in active">
|
||||
<div id="inactive-selection-wrapper" style="float: left;">
|
||||
<label>
|
||||
<input id="show-inactive" type="checkbox"/>
|
||||
{{ lang._('Show inactive') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="btn-group" id="interface-selection-wrapper">
|
||||
<select class="selectpicker" multiple="multiple" data-live-search="true" id="interface-selection" data-width="auto" title="All Interfaces">
|
||||
</select>
|
||||
</div>
|
||||
<table id="grid-leases" class="table table-condensed table-hover table-striped table-responsive">
|
||||
<tr>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="if_descr" data-type="string">{{ lang._('Interface') }}</th>
|
||||
<th data-column-id="address" data-identifier="true" data-type="string">{{ lang._('IP Address') }}</th>
|
||||
<th data-column-id="mac" data-type="string" data-formatter="macformatter">{{ lang._('MAC Address') }}</th>
|
||||
<th data-column-id="hostname" data-type="string">{{ lang._('Hostname') }}</th>
|
||||
<th data-column-id="descr" data-type="string">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="starts" data-type="string">{{ lang._('Start') }}</th>
|
||||
<th data-column-id="ends" data-type="string">{{ lang._('End') }}</th>
|
||||
<th data-column-id="status" data-type="string" data-formatter="statusformatter">{{ lang._('Status') }}</th>
|
||||
<th data-column-id="state" data-type="string">{{ lang._('State') }}</th>
|
||||
<th data-column-id="type" data-type="string">{{ lang._('Lease Type') }}</th>
|
||||
<th data-column-id="commands" data-formatter="commands", data-sortable="false"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-fw fa-trash-o"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@ -38,10 +38,15 @@ import ujson
|
||||
app_params = {'inactive': '0'}
|
||||
params.update_params(app_params)
|
||||
|
||||
last_leases = dict()
|
||||
result = list()
|
||||
dhcpdleases = watchers.dhcpd.DHCPDLease()
|
||||
for lease in dhcpdleases.watch():
|
||||
if 'ends' not in lease or lease['ends'] is None or lease['ends'] > time.time() or app_params['inactive'] != '0':
|
||||
# only the last entries for a given IP are relevant
|
||||
last_leases[lease['address']] = lease
|
||||
|
||||
for lease in last_leases.values():
|
||||
if ('ends' in lease and lease['ends'] is not None and lease['ends'] > time.time()) or app_params['inactive'] != '0':
|
||||
result.append(lease)
|
||||
|
||||
print (ujson.dumps(result))
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
[list.leases]
|
||||
command:/usr/local/opnsense/scripts/dhcp/get_leases.py /inactive %s
|
||||
parameters:%s
|
||||
command:/usr/local/opnsense/scripts/dhcp/get_leases.py
|
||||
parameters:/inactive %s
|
||||
type:script_output
|
||||
message:list dhcp leases %s
|
||||
|
||||
[list.static]
|
||||
command:/usr/local/sbin/pluginctl -r static_mapping
|
||||
parameters:%s
|
||||
type:script_output
|
||||
message: list dhcp static mappings %s
|
||||
|
||||
[update.prefixes]
|
||||
command:/usr/local/opnsense/scripts/dhcp/prefixes.php
|
||||
parameters:
|
||||
|
||||
@ -76,6 +76,8 @@ class DHCPDLease(object):
|
||||
field_value = parts[1].split('"')[1]
|
||||
elif field_name == 'set' and len(parts) >= 4 and parts[1] == 'hostname-override' and parts[3].find('"') > -1:
|
||||
hostname_override = parts[3].split('"')[1]
|
||||
elif field_name == 'binding' and len(parts) >= 3 and parts[1] == 'state':
|
||||
field_value = parts[2].strip(';')
|
||||
|
||||
if field_value is not None:
|
||||
lease[field_name] = field_value
|
||||
|
||||
@ -55,7 +55,7 @@ function reconfigure_dhcpd()
|
||||
clear_subsystem_dirty('staticmaps');
|
||||
}
|
||||
|
||||
$config_copy_fieldsnames = array('enable', 'staticarp', 'failover_peerip', 'failover_split', 'dhcpleaseinlocaltime','descr',
|
||||
$config_copy_fieldsnames = array('enable', 'staticarp', 'failover_peerip', 'failover_split', 'descr',
|
||||
'defaultleasetime', 'maxleasetime', 'gateway', 'domain', 'domainsearchlist', 'denyunknown','ignoreuids', 'ddnsdomain',
|
||||
'ddnsdomainprimary', 'ddnsdomainkeyname', 'ddnsdomainkey', 'ddnsdomainalgorithm', 'ddnsupdate', 'mac_allow',
|
||||
'mac_deny', 'tftp', 'bootfilename', 'ldap', 'netboot', 'nextserver', 'filename', 'filename32', 'filename64',
|
||||
@ -869,19 +869,6 @@ include("head.inc");
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a id="help_for_failover_dhcpleaseinlocaltime" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Time format change"); ?></td>
|
||||
<td>
|
||||
<input name="dhcpleaseinlocaltime" type="checkbox" id="dhcpleaseinlocaltime" value="yes" <?= !empty($pconfig['dhcpleaseinlocaltime']) ? "checked=\"checked\"" : ""; ?> />
|
||||
<strong><?=gettext("Change DHCP display lease time from UTC to local time."); ?></strong>
|
||||
|
||||
<div class="hidden" data-for="help_for_failover_dhcpleaseinlocaltime">
|
||||
<?=gettext("Warning: By default DHCP leases are displayed in UTC time. By checking this " .
|
||||
"box DHCP lease time will be displayed in local time and set to time zone selected. This " .
|
||||
"will be used for all DHCP interfaces lease time."); ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endif; ?>
|
||||
<tr>
|
||||
|
||||
@ -1,445 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014-2021 Deciso B.V.
|
||||
* Copyright (C) 2004-2009 Scott Ullrich <sullrich@gmail.com>
|
||||
* Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
require_once("guiconfig.inc");
|
||||
require_once("config.inc");
|
||||
require_once("interfaces.inc");
|
||||
require_once("plugins.inc.d/dhcpd.inc");
|
||||
|
||||
function adjust_utc($dt)
|
||||
{
|
||||
foreach (config_read_array('dhcpd') as $dhcpd) {
|
||||
if (!empty($dhcpd['dhcpleaseinlocaltime'])) {
|
||||
/* we want local time, so specify this is actually UTC */
|
||||
return strftime('%Y/%m/%d %H:%M:%S', strtotime("{$dt} UTC"));
|
||||
}
|
||||
}
|
||||
|
||||
/* lease time is in UTC, here just pretend it's the correct time */
|
||||
return strftime('%Y/%m/%d %H:%M:%S UTC', strtotime($dt));
|
||||
}
|
||||
|
||||
function remove_duplicate($array, $field)
|
||||
{
|
||||
foreach ($array as $sub) {
|
||||
$cmp[] = $sub[$field];
|
||||
}
|
||||
$unique = array_unique(array_reverse($cmp,true));
|
||||
foreach ($unique as $k => $rien) {
|
||||
$new[] = $array[$k];
|
||||
}
|
||||
return $new;
|
||||
}
|
||||
|
||||
$interfaces = legacy_config_get_interfaces(array('virtual' => false));
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$leases_content = dhcpd_leases(4);
|
||||
$leases_count = count($leases_content);
|
||||
|
||||
exec("/usr/sbin/arp -an", $rawdata);
|
||||
$arpdata_ip = array();
|
||||
$arpdata_mac = array();
|
||||
foreach ($rawdata as $line) {
|
||||
$elements = explode(' ',$line);
|
||||
if ($elements[3] != "(incomplete)") {
|
||||
$arpent = array();
|
||||
$arpdata_ip[] = trim(str_replace(array('(',')'),'',$elements[1]));
|
||||
$arpdata_mac[] = strtolower(trim($elements[3]));
|
||||
}
|
||||
}
|
||||
unset($rawdata);
|
||||
$pools = array();
|
||||
$leases = array();
|
||||
$i = 0;
|
||||
$l = 0;
|
||||
$p = 0;
|
||||
|
||||
// Put everything together again
|
||||
foreach($leases_content as $lease) {
|
||||
/* split the line by space */
|
||||
$data = explode(" ", $lease);
|
||||
/* walk the fields */
|
||||
$f = 0;
|
||||
$fcount = count($data);
|
||||
/* with less then 20 fields there is nothing useful */
|
||||
if ($fcount < 20) {
|
||||
$i++;
|
||||
continue;
|
||||
}
|
||||
while($f < $fcount) {
|
||||
switch($data[$f]) {
|
||||
case "failover":
|
||||
$pools[$p]['name'] = trim($data[$f+2], '"');
|
||||
$pools[$p]['name'] = "{$pools[$p]['name']} (" . convert_friendly_interface_to_friendly_descr(substr($pools[$p]['name'], 5)) . ")";
|
||||
$pools[$p]['mystate'] = $data[$f+7];
|
||||
$pools[$p]['peerstate'] = $data[$f+14];
|
||||
$pools[$p]['mydate'] = $data[$f+10];
|
||||
$pools[$p]['mydate'] .= " " . $data[$f+11];
|
||||
$pools[$p]['peerdate'] = $data[$f+17];
|
||||
$pools[$p]['peerdate'] .= " " . $data[$f+18];
|
||||
$p++;
|
||||
$i++;
|
||||
continue 3;
|
||||
case "lease":
|
||||
$leases[$l]['ip'] = $data[$f+1];
|
||||
$leases[$l]['type'] = "dynamic";
|
||||
$f = $f+2;
|
||||
break;
|
||||
case "starts":
|
||||
$leases[$l]['start'] = $data[$f+2];
|
||||
$leases[$l]['start'] .= " " . $data[$f+3];
|
||||
$f = $f+3;
|
||||
break;
|
||||
case "ends":
|
||||
$leases[$l]['end'] = $data[$f+2];
|
||||
$leases[$l]['end'] .= " " . $data[$f+3];
|
||||
$f = $f+3;
|
||||
break;
|
||||
case "tstp":
|
||||
$f = $f+3;
|
||||
break;
|
||||
case "tsfp":
|
||||
$f = $f+3;
|
||||
break;
|
||||
case "atsfp":
|
||||
$f = $f+3;
|
||||
break;
|
||||
case "cltt":
|
||||
$f = $f+3;
|
||||
break;
|
||||
case "binding":
|
||||
switch($data[$f+2]) {
|
||||
case "active":
|
||||
$leases[$l]['act'] = "active";
|
||||
break;
|
||||
case "free":
|
||||
$leases[$l]['act'] = "expired";
|
||||
$leases[$l]['online'] = "offline";
|
||||
break;
|
||||
case "backup":
|
||||
$leases[$l]['act'] = "reserved";
|
||||
$leases[$l]['online'] = "offline";
|
||||
break;
|
||||
}
|
||||
$f = $f+1;
|
||||
break;
|
||||
case "next":
|
||||
/* skip the next binding statement */
|
||||
$f = $f+3;
|
||||
break;
|
||||
case "rewind":
|
||||
/* skip the rewind binding statement */
|
||||
$f = $f+3;
|
||||
break;
|
||||
case "hardware":
|
||||
$leases[$l]['mac'] = $data[$f+2];
|
||||
/* check if it's online and the lease is active */
|
||||
if (in_array($leases[$l]['ip'], $arpdata_ip)) {
|
||||
$leases[$l]['online'] = 'online';
|
||||
} else {
|
||||
$leases[$l]['online'] = 'offline';
|
||||
}
|
||||
$f = $f+2;
|
||||
break;
|
||||
case "client-hostname":
|
||||
if ($data[$f + 1] != '') {
|
||||
$leases[$l]['hostname'] = preg_replace('/"/','',$data[$f + 1]);
|
||||
} else {
|
||||
$hostname = gethostbyaddr($leases[$l]['ip']);
|
||||
if ($hostname != '') {
|
||||
$leases[$l]['hostname'] = $hostname;
|
||||
}
|
||||
}
|
||||
$f = $f+1;
|
||||
break;
|
||||
case "uid":
|
||||
$f = $f+1;
|
||||
break;
|
||||
}
|
||||
$f++;
|
||||
}
|
||||
$l++;
|
||||
$i++;
|
||||
/* slowly chisel away at the source array */
|
||||
array_shift($leases_content);
|
||||
}
|
||||
/* remove the old array */
|
||||
unset($lease_content);
|
||||
|
||||
if (count($leases) > 0) {
|
||||
$leases = remove_duplicate($leases,"ip");
|
||||
}
|
||||
|
||||
if (count($pools) > 0) {
|
||||
$pools = remove_duplicate($pools,"name");
|
||||
asort($pools);
|
||||
}
|
||||
|
||||
$macs = [];
|
||||
foreach ($leases as $i => $this_lease) {
|
||||
if (!empty($this_lease['mac'])) {
|
||||
if (!isset($macs[$this_lease['mac']])) {
|
||||
$macs[$this_lease['mac']] = [];
|
||||
}
|
||||
$macs[$this_lease['mac']][] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (dhcpd_staticmap("not.found", legacy_interfaces_details(), false, 4) as $static) {
|
||||
$slease = [];
|
||||
$slease['ip'] = $static['ipaddr'];
|
||||
$slease['type'] = 'static';
|
||||
$slease['mac'] = $static['mac'];
|
||||
$slease['start'] = '';
|
||||
$slease['end'] = '';
|
||||
$slease['hostname'] = $static['hostname'];
|
||||
$slease['descr'] = $static['descr'];
|
||||
$slease['act'] = 'static';
|
||||
$slease['online'] = in_array(strtolower($slease['mac']), $arpdata_mac) ? 'online' : 'offline';
|
||||
|
||||
if (isset($macs[$slease['mac']])) {
|
||||
/* update lease with static data */
|
||||
foreach ($slease as $key => $value) {
|
||||
if (!empty($value)) {
|
||||
foreach ($macs[$slease['mac']] as $idx) {
|
||||
$leases[$idx][$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$leases[] = $slease;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['order']) && in_array($_GET['order'], ['int', 'ip', 'mac', 'hostname', 'descr', 'start', 'end', 'online', 'act'])) {
|
||||
$order = $_GET['order'];
|
||||
} else {
|
||||
$order = 'ip';
|
||||
}
|
||||
|
||||
usort($leases,
|
||||
function ($a, $b) use ($order) {
|
||||
$cmp = ($order === 'ip') ? 0 : strnatcasecmp($a[$order], $b[$order]);
|
||||
if ($cmp === 0) {
|
||||
$cmp = ipcmp($a['ip'], $b['ip']);
|
||||
}
|
||||
return $cmp;
|
||||
}
|
||||
);
|
||||
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (!empty($_POST['deleteip']) && is_ipaddr($_POST['deleteip'])) {
|
||||
configdp_run('dhcpd remove lease', [$_POST['deleteip']]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
$service_hook = 'dhcpd';
|
||||
|
||||
include("head.inc");
|
||||
|
||||
$leases_count = 0;
|
||||
|
||||
foreach ($leases as $data) {
|
||||
if (!($data['act'] == 'active' || $data['act'] == 'static' || $_GET['all'] == 1)) {
|
||||
continue;
|
||||
}
|
||||
$leases_count++;
|
||||
}
|
||||
|
||||
$gentitle_suffix = " ($leases_count)";
|
||||
legacy_html_escape_form_data($leases);
|
||||
|
||||
?>
|
||||
<body>
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
$(".act_delete").click(function(){
|
||||
$.post(window.location, {deleteip: $(this).data('deleteip')}, function(data) {
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
// keep sorting in place.
|
||||
$(".act_sort").click(function(){
|
||||
var all = <?=!empty($_GET['all']) ? 1 : 0;?> ;
|
||||
document.location = document.location.origin + window.location.pathname +"?all="+all+"&order="+$(this).data('field');
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
<?php include("fbegin.inc"); ?>
|
||||
|
||||
<section class="page-content-main">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<?php
|
||||
/* only print pool status when we have one */
|
||||
legacy_html_escape_form_data($pools);
|
||||
if (count($pools) > 0):?>
|
||||
<section class="col-xs-12">
|
||||
<div class="content-box">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?=gettext("Failover Group"); ?></th>
|
||||
<th><?=gettext("My State"); ?></th>
|
||||
<th><?=gettext("Since"); ?></th>
|
||||
<th><?=gettext("Peer State"); ?></th>
|
||||
<th><?=gettext("Since"); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ($pools as $data):?>
|
||||
<tr>
|
||||
<td><?=$data['name'];?></td>
|
||||
<td><?=$data['mystate'];?></td>
|
||||
<td><?=adjust_utc($data['mydate']);?></td>
|
||||
<td><?=$data['peerstate'];?></td>
|
||||
<td><?=adjust_utc($data['peerdate']);?></td>
|
||||
</tr>
|
||||
<?php
|
||||
endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php
|
||||
endif;?>
|
||||
|
||||
<section class="col-xs-12">
|
||||
<div class="content-box">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="act_sort" data-field="int"><?=gettext("Interface"); ?></td>
|
||||
<td class="act_sort" data-field="ip"><?=gettext("IP address"); ?></td>
|
||||
<td class="act_sort" data-field="mac"><?=gettext("MAC address"); ?></td>
|
||||
<td class="act_sort" data-field="hostname"><?=gettext("Hostname"); ?></td>
|
||||
<td class="act_sort" data-field="descr"><?=gettext("Description"); ?></td>
|
||||
<td class="act_sort" data-field="start"><?=gettext("Start"); ?></td>
|
||||
<td class="act_sort" data-field="end"><?=gettext("End"); ?></td>
|
||||
<td class="act_sort" data-field="online"><?=gettext("Status"); ?></td>
|
||||
<td class="act_sort" data-field="act"><?=gettext("Lease type"); ?></td>
|
||||
<td class="text-nowrap"></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
// Load MAC-Manufacturer table
|
||||
$mac_man = json_decode(configd_run("interface list macdb json"), true);
|
||||
foreach ($leases as $data):
|
||||
if (!($data['act'] == "active" || $data['act'] == "static" || $_GET['all'] == 1)) {
|
||||
continue;
|
||||
}
|
||||
$dhcpd = array();
|
||||
if (isset($config['dhcpd'])) {
|
||||
$dhcpd = $config['dhcpd'];
|
||||
}
|
||||
|
||||
$lip = ip2ulong($data['ip']);
|
||||
foreach ($dhcpd as $dhcpif => $dhcpifconf) {
|
||||
if (!empty($interfaces[$dhcpif]['ipaddr'])) {
|
||||
$ip_min = gen_subnet($interfaces[$dhcpif]['ipaddr'], $interfaces[$dhcpif]['subnet']);
|
||||
$ip_max = gen_subnet_max($interfaces[$dhcpif]['ipaddr'], $interfaces[$dhcpif]['subnet']);
|
||||
if ($lip >= ip2ulong($ip_min) && $lip <= ip2ulong($ip_max)) {
|
||||
$data['int'] = htmlspecialchars($interfaces[$dhcpif]['descr']);
|
||||
$data['if'] = $dhcpif;
|
||||
}
|
||||
}
|
||||
}
|
||||
$mac_hi = strtoupper($data['mac'][0] . $data['mac'][1] . $data['mac'][3] . $data['mac'][4] . $data['mac'][6] . $data['mac'][7]);
|
||||
?>
|
||||
<tr>
|
||||
<td><?=$data['int'];?></td>
|
||||
<td><?=$data['ip'];?></td>
|
||||
<td>
|
||||
<?=$data['mac'];?><br />
|
||||
<small><i><?= !empty($mac_man[$mac_hi]) ? $mac_man[$mac_hi] : '' ?></i></small>
|
||||
</td>
|
||||
<td><?=$data['hostname'];?></td>
|
||||
<td><?=$data['descr'];?></td>
|
||||
<td><?= !empty($data['start']) ? adjust_utc($data['start']) : '' ?></td>
|
||||
<td><?= !empty($data['end']) ? adjust_utc($data['end']) : '' ?></td>
|
||||
<td>
|
||||
<i class="fa fa-<?=$data['online']=='online' ? 'signal' : 'ban';?>" title="<?=$data['online'];?>" data-toggle="tooltip"></i>
|
||||
</td>
|
||||
<td><?=$data['act'];?></td>
|
||||
<td class="text-nowrap">
|
||||
<?php if (!empty($data['if'])): ?>
|
||||
<?php if ($data['type'] == 'dynamic'): ?>
|
||||
<a class="btn btn-default btn-xs" href="services_dhcp_edit.php?if=<?=$data['if'];?>&mac=<?=$data['mac'];?>&hostname=<?=$data['hostname'];?>">
|
||||
<i class="fa fa-plus fa-fw" data-toggle="tooltip" title="<?=gettext("add a static mapping for this MAC address");?>"></i>
|
||||
</a>
|
||||
<?php if ($data['online'] != 'online'):?>
|
||||
|
||||
<a class="act_delete btn btn-default btn-xs" href="#" data-deleteip="<?=$data['ip'];?>">
|
||||
<i class="fa fa-trash fa-fw" title="<?= html_safe(gettext('Delete')) ?>" data-toggle="tooltip"></i>
|
||||
</a>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="col-xs-12">
|
||||
<form method="get">
|
||||
<input type="hidden" name="order" value="<?=htmlspecialchars($_GET['order']);?>" />
|
||||
<?php
|
||||
if (!empty($_GET['all'])): ?>
|
||||
<input type="hidden" name="all" value="0" />
|
||||
<input type="submit" class="btn btn-default" value="<?= html_safe(gettext('Show active and static leases only')) ?>" />
|
||||
<?php
|
||||
else: ?>
|
||||
<input type="hidden" name="all" value="1" />
|
||||
<input type="submit" class="btn btn-default" value="<?= html_safe(gettext('Show all configured leases')) ?>" />
|
||||
<?php
|
||||
endif; ?>
|
||||
</form>
|
||||
<?php if ($leases == 0): ?>
|
||||
<p><?=gettext("No leases file found. Is the DHCP server active?") ?></p>
|
||||
<?php endif ?>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php
|
||||
|
||||
include("foot.inc");
|
||||
@ -256,7 +256,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
}
|
||||
}
|
||||
|
||||
foreach (dhcpd_staticmap("not.found", legacy_interfaces_details(), false, 6) as $static) {
|
||||
foreach (dhcpd_staticmap(6, "not.found", legacy_interfaces_details(), false) as $static) {
|
||||
$slease = [];
|
||||
$slease['ip'] = $static['ipaddrv6'];
|
||||
$slease['if'] = $static['interface'];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user