From a7a6e67e87c2a9e48148b569d794030d61b444f7 Mon Sep 17 00:00:00 2001
From: PipoCanaja <38363551+PipoCanaja@users.noreply.github.com>
Date: Wed, 24 Jan 2024 09:15:40 +0100
Subject: [PATCH] NAC - Improve search in WebUI - Keep Historical data (#15629)
* search improvement for PortNac
* rename func
* style
* DB migration for timestamps
* style
* rules
* fix manually db_schema
* remove vlan only search for now
* add a bool column to ident historical nac entries
* add columns to the table
* queryByOui renamed everywhere
* age value instead of delete
* style
* style
* use Illuminate\Support\Facades\DB;
* tests fix
* module_tables.yaml
* dump model instead of tests/module_tables.yaml
* tests
* testVrp
* daily
* config
* display historical NAC entries in global view
* same for NAC device page
* nac tab on device/port view
* and display the tab link if necessary
* filter by port as well
* historical data in port tab
* formatters
---
LibreNMS/Modules/Nac.php | 30 +-
.../Controllers/Table/PortNacController.php | 103 ++-
app/Models/PortsNac.php | 2 +-
daily.php | 7 +
daily.sh | 1 +
...10_130000_historical_data_to_ports_nac.php | 34 +
doc/Support/Cleanup-options.md | 1 +
includes/html/pages/device/port.inc.php | 5 +
includes/html/pages/device/port/nac.inc.php | 140 ++++
lang/en/settings.php | 4 +
lang/fr/settings.php | 4 +
lang/it/settings.php | 4 +
misc/config_definitions.json | 8 +
misc/db_schema.yaml | 3 +
resources/views/device/tabs/nac.blade.php | 26 +-
resources/views/nac.blade.php | 28 +-
tests/data/ios_nac.json | 5 +
tests/data/vrp_nac.json | 648 +++++++++++++++++-
18 files changed, 1033 insertions(+), 20 deletions(-)
create mode 100644 database/migrations/2023_12_10_130000_historical_data_to_ports_nac.php
create mode 100644 includes/html/pages/device/port/nac.inc.php
diff --git a/LibreNMS/Modules/Nac.php b/LibreNMS/Modules/Nac.php
index 95564f9f6e..3195ae0f04 100644
--- a/LibreNMS/Modules/Nac.php
+++ b/LibreNMS/Modules/Nac.php
@@ -28,6 +28,7 @@ namespace LibreNMS\Modules;
use App\Models\Device;
use App\Models\PortsNac;
use App\Observers\ModuleModelObserver;
+use Illuminate\Support\Facades\DB;
use LibreNMS\Interfaces\Data\DataStorageInterface;
use LibreNMS\Interfaces\Module;
use LibreNMS\Interfaces\Polling\NacPolling;
@@ -79,22 +80,37 @@ class Nac implements Module
ModuleModelObserver::observe(PortsNac::class);
$nac_entries = $os->pollNac()->keyBy('mac_address');
- $existing_entries = $os->getDevice()->portsNac->keyBy('mac_address');
+ //filter out historical entries
+ $existing_entries = $os->getDevice()->portsNac->keyBy('mac_address')->filter(function ($value, $key) {
+ if ($value['historical'] == 0) {
+ return $value;
+ }
+ });
// update existing models
foreach ($nac_entries as $nac_entry) {
if ($existing = $existing_entries->get($nac_entry->mac_address)) {
- $nac_entries->put($nac_entry->mac_address, $existing->fill($nac_entry->attributesToArray()));
+ // we have the same mac_address once again. Let's decide if we should keep the existing as history or not.
+ if (($nac_entry->port_id == $existing->port_id) ||
+ ($nac_entry->method == $existing->method) ||
+ ($nac_entry->vlan == $existing->vlan) ||
+ ($nac_entry->authz_by == $existing->authz_by) ||
+ ($nac_entry->authz_status == $existing->authz_status) ||
+ ($nac_entry->ip_address == $existing->ip_address) ||
+ ($nac_entry->username == $existing->username)) {
+ // if everything is similar, we update current entry. If not, we duplicate+history
+ $nac_entries->put($nac_entry->mac_address, $existing->fill($nac_entry->attributesToArray()));
+ }
}
}
// persist to DB
$os->getDevice()->portsNac()->saveMany($nac_entries);
- $delete = $existing_entries->diffKeys($nac_entries)->pluck('ports_nac_id');
- if ($delete->isNotEmpty()) {
- $count = PortsNac::query()->whereIntegerInRaw('ports_nac_id', $delete)->delete();
- d_echo('Deleted ' . $count, str_repeat('-', $count));
+ $age = $existing_entries->diffKeys($nac_entries)->pluck('ports_nac_id');
+ if ($age->isNotEmpty()) {
+ $count = PortsNac::query()->whereIntegerInRaw('ports_nac_id', $age)->update(['historical' => true, 'updated_at' => DB::raw('updated_at')]);
+ d_echo('Aged ' . $count, str_repeat('-', $count));
}
}
}
@@ -117,7 +133,7 @@ class Nac implements Module
'ports_nac' => $device->portsNac()->orderBy('ports.ifIndex')->orderBy('mac_address')
->leftJoin('ports', 'ports_nac.port_id', 'ports.port_id')
->select(['ports_nac.*', 'ifIndex'])
- ->get()->map->makeHidden(['ports_nac_id', 'device_id', 'port_id']),
+ ->get()->map->makeHidden(['ports_nac_id', 'device_id', 'port_id', 'updated_at', 'created_at']),
];
}
}
diff --git a/app/Http/Controllers/Table/PortNacController.php b/app/Http/Controllers/Table/PortNacController.php
index 83892812b7..c9d4e0b4ed 100644
--- a/app/Http/Controllers/Table/PortNacController.php
+++ b/app/Http/Controllers/Table/PortNacController.php
@@ -25,7 +25,11 @@
namespace App\Http\Controllers\Table;
+use App\Models\Port;
use App\Models\PortsNac;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\DB;
use LibreNMS\Util\Mac;
use LibreNMS\Util\Url;
@@ -34,7 +38,8 @@ class PortNacController extends TableController
public function rules()
{
return [
- 'device_id' => 'int',
+ 'device_id' => 'nullable|integer',
+ 'searchby' => 'in:mac,ip,description,vendor,',
];
}
@@ -62,6 +67,8 @@ class PortNacController extends TableController
'authc_status',
'authz_status',
'method',
+ 'created_at',
+ 'updated_at',
];
}
@@ -73,13 +80,53 @@ class PortNacController extends TableController
*/
public function baseQuery($request)
{
- return PortsNac::select('device_id', 'port_id', 'mac_address', 'ip_address', 'vlan', 'domain', 'host_mode', 'username', 'authz_by', 'timeout', 'time_elapsed', 'time_left', 'authc_status', 'authz_status', 'method')
+ return PortsNac::select('device_id', 'port_id', 'mac_address', 'ip_address', 'vlan', 'domain', 'host_mode', 'username', 'authz_by', 'timeout', 'time_elapsed', 'time_left', 'authc_status', 'authz_status', 'method', 'created_at', 'updated_at', 'historical')
->when($request->device_id, fn ($q, $id) => $q->where('device_id', $id))
+ ->when($request->port_id, fn ($q, $id) => $q->where('port_id', $id))
+ ->when($request->showHistorical != 'true', fn ($q, $h) => $q->where('historical', 0))
->hasAccess($request->user())
->with('port')
->with('device');
}
+ /**
+ * @param string $search
+ * @param Builder $query
+ * @param array $fields
+ * @return Builder|\Illuminate\Database\Query\Builder
+ */
+ protected function search($search, $query, $fields = [])
+ {
+ if ($search = trim(\Request::get('searchPhrase') ?? '')) {
+ $mac_search = '%' . str_replace([':', ' ', '-', '.', '0x'], '', $search) . '%';
+
+ switch (\Request::get('searchby') ?? '') {
+ case 'mac':
+ return $query->where('ports_nac.mac_address', 'like', $search);
+ case 'ip':
+ return $query->whereIn('ports_nac.ip_address', $search);
+ case 'description':
+ return $query->whereIntegerInRaw('ports_nac.port_id', $this->findPorts($search));
+ case 'vendor':
+ $vendor_ouis = $this->ouisFromVendor($search);
+
+ return $this->queryByOui($vendor_ouis, $query);
+ default:
+ return $query->where(function ($query) use ($search, $mac_search) {
+ $vendor_ouis = $this->ouisFromVendor($search);
+ $this->queryByOui($vendor_ouis, $query)
+ ->orWhereIntegerInRaw('ports_nac.port_id', $this->findPorts($search))
+ ->orWhere('ports_nac.vlan', 'like', '%' . $search . '%')
+ ->orWhere('ports_nac.mac_address', 'like', $mac_search)
+ ->orWhere('ports_nac.username', 'like', '%' . $search . '%')
+ ->orWhere('ports_nac.ip_address', 'like', '%' . $search . '%');
+ });
+ }
+ }
+
+ return $query;
+ }
+
/**
* @param PortsNac $nac
*/
@@ -87,12 +134,62 @@ class PortNacController extends TableController
{
$item = $nac->toArray();
$mac = Mac::parse($item['mac_address']);
+ $item['updated_at'] = $nac->updated_at ? ($item['historical'] == 0 ? $nac->updated_at->diffForHumans() : $nac->updated_at->toDateTimeString()) : '';
+ $item['created_at'] = $nac->created_at ? $nac->created_at->toDateTimeString() : '';
$item['port_id'] = Url::portLink($nac->port, $nac->port->getShortLabel());
$item['mac_oui'] = $mac->vendor();
$item['mac_address'] = $mac->readable();
- $item['port'] = null; //free some unused data to be sent to the browser
$item['device_id'] = Url::deviceLink($nac->device);
+ unset($item['device']); //avoid sending all device data in the JSON reply
+ unset($item['port']); //free some unused data to be sent to the browser
return $item;
}
+
+ /**
+ * @param string $ifAlias
+ * @return Collection
+ */
+ protected function findPorts($ifAlias): Collection
+ {
+ $port_id = \Request::get('port_id');
+ $device_id = \Request::get('device_id');
+
+ return Port::where('ifAlias', 'like', "%$ifAlias%")
+ ->when($device_id, function ($query) use ($device_id) {
+ return $query->where('device_id', $device_id);
+ })
+ ->when($port_id, function ($query) use ($port_id) {
+ return $query->where('port_id', $port_id);
+ })
+ ->pluck('port_id');
+ }
+
+ /**
+ * Get the OUI list for a specific vendor
+ *
+ * @param string $vendor
+ * @return array
+ */
+ protected function ouisFromVendor(string $vendor): array
+ {
+ return DB::table('vendor_ouis')
+ ->where('vendor', 'LIKE', '%' . $vendor . '%')
+ ->pluck('oui')
+ ->toArray();
+ }
+
+ /**
+ * filter $query from vendor OUIs
+ */
+ protected function queryByOui(array $vendor_ouis, Builder $query): Builder
+ {
+ $query->where(function (Builder $query) use ($vendor_ouis) {
+ foreach ($vendor_ouis as $oui) {
+ $query->orWhere('ports_nac.mac_address', 'LIKE', "$oui%");
+ }
+ });
+
+ return $query; // Return the query builder instance
+ }
}
diff --git a/app/Models/PortsNac.php b/app/Models/PortsNac.php
index eb42ba96d5..c02eeac568 100644
--- a/app/Models/PortsNac.php
+++ b/app/Models/PortsNac.php
@@ -31,7 +31,7 @@ class PortsNac extends PortRelatedModel
{
protected $table = 'ports_nac';
protected $primaryKey = 'ports_nac_id';
- public $timestamps = false;
+ public $timestamps = true;
protected $fillable = [
'auth_id',
'device_id',
diff --git a/daily.php b/daily.php
index 5bc5fc2aac..ce0f3d9217 100644
--- a/daily.php
+++ b/daily.php
@@ -111,10 +111,17 @@ if ($options['f'] === 'ports_fdb') {
$ret = lock_and_purge('ports_fdb', 'updated_at < DATE_SUB(NOW(), INTERVAL ? DAY)');
exit($ret);
}
+
+if ($options['f'] === 'ports_nac') {
+ $ret = lock_and_purge('ports_nac', 'updated_at < DATE_SUB(NOW(), INTERVAL ? DAY)');
+ exit($ret);
+}
+
if ($options['f'] === 'route') {
$ret = lock_and_purge('route', 'updated_at < DATE_SUB(NOW(), INTERVAL ? DAY)');
exit($ret);
}
+
if ($options['f'] === 'eventlog') {
$ret = lock_and_purge('eventlog', 'datetime < DATE_SUB(NOW(), INTERVAL ? DAY)');
exit($ret);
diff --git a/daily.sh b/daily.sh
index f6b790fd51..4dfe541b82 100755
--- a/daily.sh
+++ b/daily.sh
@@ -387,6 +387,7 @@ main () {
"alert_log"
"rrd_purge"
"ports_fdb"
+ "ports_nac"
"route"
"ports_purge")
call_daily_php "${options[@]}"
diff --git a/database/migrations/2023_12_10_130000_historical_data_to_ports_nac.php b/database/migrations/2023_12_10_130000_historical_data_to_ports_nac.php
new file mode 100644
index 0000000000..368f8103a7
--- /dev/null
+++ b/database/migrations/2023_12_10_130000_historical_data_to_ports_nac.php
@@ -0,0 +1,34 @@
+timestamps();
+ $table->boolean('historical')->default(0);
+ });
+ DB::table('ports_nac')->update(['created_at' => \Carbon\Carbon::now()]);
+ DB::table('ports_nac')->update(['updated_at' => \Carbon\Carbon::now()]);
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down(): void
+ {
+ Schema::table('ports_nac', function (Blueprint $table) {
+ $table->dropColumn(['created_at', 'updated_at', 'historical']);
+ });
+ }
+};
diff --git a/doc/Support/Cleanup-options.md b/doc/Support/Cleanup-options.md
index d772af128a..1dcdf0c411 100644
--- a/doc/Support/Cleanup-options.md
+++ b/doc/Support/Cleanup-options.md
@@ -16,6 +16,7 @@ These options rely on ```daily.sh``` running from cron as per the installation i
lnms config:set alert_log_purge 365
lnms config:set authlog_purge 30
lnms config:set ports_fdb_purge 10
+ lnms config:set ports_nac_purge 10
lnms config:set device_perf_purge 7
lnms config:set rrd_purge 0
lnms config:set ports_purge true
diff --git a/includes/html/pages/device/port.inc.php b/includes/html/pages/device/port.inc.php
index cfec5dc91c..995092ea1f 100644
--- a/includes/html/pages/device/port.inc.php
+++ b/includes/html/pages/device/port.inc.php
@@ -2,6 +2,7 @@
use App\Models\Port;
use App\Models\PortAdsl;
+use App\Models\PortsNac;
use App\Models\PortVdsl;
use App\Plugins\Hooks\PortTabHook;
use LibreNMS\Util\Rewrite;
@@ -95,6 +96,10 @@ if (PortAdsl::where('port_id', $port->port_id)->exists()) {
$menu_options['xdsl'] = 'xDSL';
}
+if (PortsNac::where('port_id', $port->port_id)->exists()) {
+ $menu_options['nac'] = 'NAC';
+}
+
if (DeviceCache::getPrimary()->ports()->where('pagpGroupIfIndex', $port->ifIndex)->exists()) {
$menu_options['pagp'] = 'PAgP';
}
diff --git a/includes/html/pages/device/port/nac.inc.php b/includes/html/pages/device/port/nac.inc.php
new file mode 100644
index 0000000000..4b752df202
--- /dev/null
+++ b/includes/html/pages/device/port/nac.inc.php
@@ -0,0 +1,140 @@
+
+
+
+
+ Ports |
+ Mac Address |
+ Vendor |
+ IP Address |
+ Vlan |
+ Domain |
+ Host Mode |
+ Username |
+ Auth By |
+ Timeout |
+ Time Elapsed |
+ Time Left |
+ NAC Authc |
+ NAC Authz |
+ NAC Method |
+ First seen |
+ Last seen |
+
+
+
+
+
+
+
diff --git a/lang/en/settings.php b/lang/en/settings.php
index f5c51cd64d..e3a4302f3d 100644
--- a/lang/en/settings.php
+++ b/lang/en/settings.php
@@ -1260,6 +1260,10 @@ return [
'description' => 'Port FDB entries older than',
'help' => 'Cleanup done by daily.sh',
],
+ 'ports_nac_purge' => [
+ 'description' => 'Port NAC entries older than',
+ 'help' => 'Cleanup done by daily.sh',
+ ],
'ports_purge' => [
'description' => 'Purge ports deleted',
'help' => 'Cleanup done by daily.sh',
diff --git a/lang/fr/settings.php b/lang/fr/settings.php
index 0741182745..0064ff74c9 100644
--- a/lang/fr/settings.php
+++ b/lang/fr/settings.php
@@ -917,6 +917,10 @@ return [
'description' => 'Table port FDB, entrées plus anciennes que',
'help' => 'Nettoyage effectué par daily.sh',
],
+ 'ports_nac_purge' => [
+ 'description' => 'Table port NAC, entrées plus anciennes que',
+ 'help' => 'Nettoyage effectué par daily.sh',
+ ],
'ports_purge' => [
'description' => 'Purger les ports supprimés',
'help' => 'Nettoyage effectué par daily.sh',
diff --git a/lang/it/settings.php b/lang/it/settings.php
index f8b91b4dc0..b893c32b0b 100644
--- a/lang/it/settings.php
+++ b/lang/it/settings.php
@@ -1177,6 +1177,10 @@ return [
'description' => 'Port FDB entries older than',
'help' => 'Cleanup done by daily.sh',
],
+ 'ports_nac_purge' => [
+ 'description' => 'Port NAC entries older than',
+ 'help' => 'Cleanup done by daily.sh',
+ ],
'ports_purge' => [
'description' => 'Elimina le porte',
'help' => 'Cleanup done by daily.sh',
diff --git a/misc/config_definitions.json b/misc/config_definitions.json
index 962c67e7d0..8cf3d6ad9e 100644
--- a/misc/config_definitions.json
+++ b/misc/config_definitions.json
@@ -5154,6 +5154,14 @@
"order": 5,
"type": "integer"
},
+ "ports_nac_purge": {
+ "default": 10,
+ "units": "days",
+ "group": "system",
+ "section": "cleanup",
+ "order": 6,
+ "type": "integer"
+ },
"ports_page_default": {
"default": "details",
"type": "select",
diff --git a/misc/db_schema.yaml b/misc/db_schema.yaml
index f931e3296c..f6d304e988 100644
--- a/misc/db_schema.yaml
+++ b/misc/db_schema.yaml
@@ -1600,6 +1600,9 @@ ports_nac:
- { Field: time_left, Type: varchar(50), 'Null': true, Extra: '' }
- { Field: vlan, Type: 'int unsigned', 'Null': true, Extra: '' }
- { Field: time_elapsed, Type: varchar(50), 'Null': true, Extra: '' }
+ - { Field: created_at, Type: timestamp, 'Null': true, Extra: '' }
+ - { Field: updated_at, Type: timestamp, 'Null': true, Extra: '' }
+ - { Field: historical, Type: tinyint, 'Null': false, Extra: '', Default: '0' }
Indexes:
PRIMARY: { Name: PRIMARY, Columns: [ports_nac_id], Unique: true, Type: BTREE }
ports_nac_device_id_index: { Name: ports_nac_device_id_index, Columns: [device_id], Unique: false, Type: BTREE }
diff --git a/resources/views/device/tabs/nac.blade.php b/resources/views/device/tabs/nac.blade.php
index 9d7841bbad..ecf70e1207 100644
--- a/resources/views/device/tabs/nac.blade.php
+++ b/resources/views/device/tabs/nac.blade.php
@@ -24,7 +24,8 @@
{{ __('NAC Authc') }} |
{{ __('NAC Authz') }} |
{{ __('NAC Method') }} |
-
+ {{ __('First seen') }} |
+ {{ __('Last seen') }} |
@@ -43,7 +44,15 @@
rowCount: [25, 50, 100, -1],
url: "{{ route('table.port-nac') }}",
post: function () {
+ var check_showHistorical = document.getElementById('check_showHistorical');
+ if (check_showHistorical) {
+ var showHistorical = check_showHistorical.checked;
+ } else {
+ var showHistorical = false;
+ }
+
return {
+ showHistorical: showHistorical,
device_id: '{{ $device->device_id }}',
};
},
@@ -117,7 +126,22 @@
}
}
});
+ var add = $(".actionBar").append(
+ '' +
+ '' +
+ '' +
+ ' Include historical NAC entries' +
+ '
');
+ $("#check_showHistorical").bootstrapSwitch({
+ 'onSwitchChange': function(event, state){
+ updateTable();
+ }
+ });
+
+ function updateTable() {
+ $('#nac-grid').bootgrid('reload');
+ };
});
@endpush
diff --git a/resources/views/nac.blade.php b/resources/views/nac.blade.php
index 4cd5495791..764a33e2dc 100644
--- a/resources/views/nac.blade.php
+++ b/resources/views/nac.blade.php
@@ -28,7 +28,8 @@
{{ __('NAC Authc') }} |
{{ __('NAC Authz') }} |
{{ __('NAC Method') }} |
-
+ {{ __('First seen') }} |
+ {{ __('Last seen') }} |
@@ -48,12 +49,20 @@
@push('scripts')
@endpush
diff --git a/tests/data/ios_nac.json b/tests/data/ios_nac.json
index a07ccdcd64..67f174e886 100644
--- a/tests/data/ios_nac.json
+++ b/tests/data/ios_nac.json
@@ -2427,6 +2427,7 @@
"time_left": "32",
"vlan": 0,
"time_elapsed": null,
+ "historical": 0,
"ifIndex": 10001
},
{
@@ -2444,6 +2445,7 @@
"time_left": "43",
"vlan": 0,
"time_elapsed": null,
+ "historical": 0,
"ifIndex": 10001
},
{
@@ -2461,6 +2463,7 @@
"time_left": "23",
"vlan": 0,
"time_elapsed": null,
+ "historical": 0,
"ifIndex": 10002
},
{
@@ -2478,6 +2481,7 @@
"time_left": "0",
"vlan": 0,
"time_elapsed": null,
+ "historical": 0,
"ifIndex": 10003
},
{
@@ -2495,6 +2499,7 @@
"time_left": "12",
"vlan": 0,
"time_elapsed": null,
+ "historical": 0,
"ifIndex": 10003
}
]
diff --git a/tests/data/vrp_nac.json b/tests/data/vrp_nac.json
index 3d8b556e92..fdc08dde74 100644
--- a/tests/data/vrp_nac.json
+++ b/tests/data/vrp_nac.json
@@ -26737,8 +26737,8 @@
"ifName": "InLoopBack0",
"portName": null,
"ifIndex": 1,
- "ifSpeed": 0,
- "ifSpeed_prev": null,
+ "ifSpeed": null,
+ "ifSpeed_prev": 0,
"ifConnectorPresent": null,
"ifOperStatus": "up",
"ifOperStatus_prev": "up",
@@ -26837,8 +26837,8 @@
"ifName": "NULL0",
"portName": null,
"ifIndex": 2,
- "ifSpeed": 0,
- "ifSpeed_prev": null,
+ "ifSpeed": null,
+ "ifSpeed_prev": 0,
"ifConnectorPresent": null,
"ifOperStatus": "up",
"ifOperStatus_prev": "up",
@@ -26937,8 +26937,8 @@
"ifName": "Console9/0/0",
"portName": null,
"ifIndex": 3,
- "ifSpeed": 0,
- "ifSpeed_prev": null,
+ "ifSpeed": null,
+ "ifSpeed_prev": 0,
"ifConnectorPresent": null,
"ifOperStatus": "up",
"ifOperStatus_prev": "up",
@@ -53429,5 +53429,641 @@
}
]
}
+ },
+ "nac": {
+ "poller": {
+ "ports_nac": [
+ {
+ "auth_id": "436",
+ "domain": "ACME",
+ "username": "host/PC5778.int.ACME.test",
+ "mac_address": "702084041dae",
+ "ip_address": "10.11.2.10",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "145802",
+ "historical": 0,
+ "ifIndex": 7
+ },
+ {
+ "auth_id": "240",
+ "domain": "ACME",
+ "username": "host/LT5221.int.ACME.test",
+ "mac_address": "0050b6cd5372",
+ "ip_address": "10.11.2.178",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "1869785",
+ "historical": 0,
+ "ifIndex": 11
+ },
+ {
+ "auth_id": "563",
+ "domain": "ACME",
+ "username": "host/PC5721.int.ACME.test",
+ "mac_address": "6c0b84e236d6",
+ "ip_address": "10.11.1.15",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "1869752",
+ "historical": 0,
+ "ifIndex": 14
+ },
+ {
+ "auth_id": "113",
+ "domain": "ACME",
+ "username": "host/PC5719.int.ACME.test",
+ "mac_address": "6c0b84e236d7",
+ "ip_address": "10.11.1.32",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "141526",
+ "historical": 0,
+ "ifIndex": 20
+ },
+ {
+ "auth_id": "513",
+ "domain": "ACME",
+ "username": "host/LT5697.int.ACME.test",
+ "mac_address": "0050b666e3f8",
+ "ip_address": "10.11.1.177",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "27778",
+ "historical": 0,
+ "ifIndex": 23
+ },
+ {
+ "auth_id": "319",
+ "domain": "ACME",
+ "username": "host/PC5784.int.ACME.test",
+ "mac_address": "309c2337f197",
+ "ip_address": "10.11.1.176",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "1869325",
+ "historical": 0,
+ "ifIndex": 25
+ },
+ {
+ "auth_id": "541",
+ "domain": "ACME",
+ "username": "host/LT5195.int.ACME.test",
+ "mac_address": "0050b6c5501b",
+ "ip_address": "10.11.1.17",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "30384",
+ "historical": 0,
+ "ifIndex": 26
+ },
+ {
+ "auth_id": "334",
+ "domain": "ACME",
+ "username": "host/PC5787.int.ACME.test",
+ "mac_address": "309c23367a1f",
+ "ip_address": "10.11.1.183",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "116888",
+ "historical": 0,
+ "ifIndex": 27
+ },
+ {
+ "auth_id": "305",
+ "domain": "ACME",
+ "username": "host/PC5805.int.ACME.test",
+ "mac_address": "309c2350d064",
+ "ip_address": "10.11.1.28",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "144551",
+ "historical": 0,
+ "ifIndex": 28
+ },
+ {
+ "auth_id": "441",
+ "domain": "ACME",
+ "username": "host/PC5718.int.ACME.test",
+ "mac_address": "6c0b84e2375c",
+ "ip_address": "10.11.1.173",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "1869746",
+ "historical": 0,
+ "ifIndex": 36
+ },
+ {
+ "auth_id": "957",
+ "domain": "ACME",
+ "username": "host/PC5722.int.ACME.test",
+ "mac_address": "6c0b84e236fb",
+ "ip_address": "10.11.1.181",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "141709",
+ "historical": 0,
+ "ifIndex": 37
+ },
+ {
+ "auth_id": "997",
+ "domain": "ACME",
+ "username": "host/PC5720.int.ACME.test",
+ "mac_address": "6c0b84e237bf",
+ "ip_address": "10.11.1.23",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "494722",
+ "historical": 0,
+ "ifIndex": 38
+ },
+ {
+ "auth_id": "451",
+ "domain": "ACME",
+ "username": "host/LT5813.int.ACME.test",
+ "mac_address": "0050b692bb25",
+ "ip_address": "10.11.1.25",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "28485",
+ "historical": 0,
+ "ifIndex": 42
+ },
+ {
+ "auth_id": "613",
+ "domain": "ACME",
+ "username": "host/PC5782.int.ACME.test",
+ "mac_address": "309c2336799e",
+ "ip_address": "10.11.1.29",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "143678",
+ "historical": 0,
+ "ifIndex": 44
+ },
+ {
+ "auth_id": "544",
+ "domain": "ACME",
+ "username": "host/PC5788.int.ACME.test",
+ "mac_address": "309c2337f18d",
+ "ip_address": "10.11.1.180",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "1869330",
+ "historical": 0,
+ "ifIndex": 49
+ },
+ {
+ "auth_id": "428",
+ "domain": "ACME",
+ "username": "host/PC5277.int.ACME.test",
+ "mac_address": "d8cb8a8aa832",
+ "ip_address": "10.11.2.28",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "128457",
+ "historical": 0,
+ "ifIndex": 58
+ },
+ {
+ "auth_id": "453",
+ "domain": "ACME",
+ "username": "host/PC5094.int.ACME.test",
+ "mac_address": "4439c453d053",
+ "ip_address": "10.11.2.24",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "495085",
+ "historical": 0,
+ "ifIndex": 59
+ },
+ {
+ "auth_id": "192",
+ "domain": "ACME",
+ "username": "host/PC5713.int.ACME.test",
+ "mac_address": "6c0b84e234df",
+ "ip_address": "10.11.2.11",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "143869",
+ "historical": 0,
+ "ifIndex": 63
+ },
+ {
+ "auth_id": "590",
+ "domain": "ACME",
+ "username": "host/PC5767.int.ACME.test",
+ "mac_address": "7020840420ef",
+ "ip_address": "10.11.2.21",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "1614917",
+ "historical": 0,
+ "ifIndex": 64
+ },
+ {
+ "auth_id": "139",
+ "domain": "ACME",
+ "username": "host/PC5061.int.ACME.test",
+ "mac_address": "4439c453d066",
+ "ip_address": "10.11.2.15",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "1871293",
+ "historical": 0,
+ "ifIndex": 65
+ },
+ {
+ "auth_id": "316",
+ "domain": "ACME",
+ "username": "host/PC5714.int.ACME.test",
+ "mac_address": "6c0b84e2274d",
+ "ip_address": "10.11.1.22",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "1869739",
+ "historical": 0,
+ "ifIndex": 66
+ },
+ {
+ "auth_id": "585",
+ "domain": "ACME",
+ "username": "host/PC5712.int.ACME.test",
+ "mac_address": "6c0b84e237ba",
+ "ip_address": "10.11.1.24",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "1869750",
+ "historical": 0,
+ "ifIndex": 69
+ },
+ {
+ "auth_id": "742",
+ "domain": "ACME",
+ "username": "host/PC5679.int.ACME.test",
+ "mac_address": "4ccc6aa7705f",
+ "ip_address": "10.11.2.22",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "1604770",
+ "historical": 0,
+ "ifIndex": 70
+ },
+ {
+ "auth_id": "321",
+ "domain": "ACME",
+ "username": "host/PC5783.int.ACME.test",
+ "mac_address": "309c2337f192",
+ "ip_address": "10.11.1.27",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "142463",
+ "historical": 0,
+ "ifIndex": 72
+ },
+ {
+ "auth_id": "169",
+ "domain": "ACME",
+ "username": "host/PC5710.int.ACME.test",
+ "mac_address": "6c0b84e2442e",
+ "ip_address": "10.11.2.175",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "490548",
+ "historical": 0,
+ "ifIndex": 74
+ },
+ {
+ "auth_id": "1022",
+ "domain": "ACME",
+ "username": "host/PC5689.int.ACME.test",
+ "mac_address": "4ccc6aa77523",
+ "ip_address": "10.11.2.27",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "974609",
+ "historical": 0,
+ "ifIndex": 75
+ },
+ {
+ "auth_id": "249",
+ "domain": "ACME",
+ "username": "host/PC5717.int.ACME.test",
+ "mac_address": "6c0b84e24429",
+ "ip_address": "10.11.1.174",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "138942",
+ "historical": 0,
+ "ifIndex": 81
+ },
+ {
+ "auth_id": "867",
+ "domain": "ACME",
+ "username": "host/LT5731.int.ACME.test",
+ "mac_address": "0050b68aae3d",
+ "ip_address": "10.11.2.18",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "376109",
+ "historical": 0,
+ "ifIndex": 84
+ },
+ {
+ "auth_id": "185",
+ "domain": "ACME",
+ "username": "host/PC5231.int.ACME.test",
+ "mac_address": "002324ac0ed2",
+ "ip_address": "10.11.1.30",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "490234",
+ "historical": 0,
+ "ifIndex": 97
+ },
+ {
+ "auth_id": "757",
+ "domain": "ACME",
+ "username": "host/PC5368.int.ACME.test",
+ "mac_address": "002324bcffa1",
+ "ip_address": "10.13.1.23",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 331,
+ "time_elapsed": "39895",
+ "historical": 0,
+ "ifIndex": 175
+ },
+ {
+ "auth_id": "618",
+ "domain": "ACME",
+ "username": "host/PC5680.int.ACME.test",
+ "mac_address": "4ccc6aa77530",
+ "ip_address": "10.11.2.16",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "402193",
+ "historical": 0,
+ "ifIndex": 195
+ },
+ {
+ "auth_id": "626",
+ "domain": "ACME",
+ "username": "host/LT5730.int.ACME.test",
+ "mac_address": "0050b68b75cf",
+ "ip_address": "10.11.2.26",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "1869777",
+ "historical": 0,
+ "ifIndex": 203
+ },
+ {
+ "auth_id": "64",
+ "domain": "ACME",
+ "username": "host/PC5059.int.ACME.test",
+ "mac_address": "4439c453cd32",
+ "ip_address": "10.11.2.19",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 312,
+ "time_elapsed": "147961",
+ "historical": 0,
+ "ifIndex": 225
+ },
+ {
+ "auth_id": "411",
+ "domain": "ACME",
+ "username": "host/PC5709.int.ACME.test",
+ "mac_address": "6c0b84e21fe2",
+ "ip_address": "10.11.1.178",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "143380",
+ "historical": 0,
+ "ifIndex": 239
+ },
+ {
+ "auth_id": "90",
+ "domain": "ACME",
+ "username": "host/PC5708.int.ACME.test",
+ "mac_address": "6c0b84e21fb3",
+ "ip_address": "10.11.1.171",
+ "host_mode": "default",
+ "authz_status": "sussess",
+ "authz_by": "eap",
+ "authc_status": "radius",
+ "method": "dot1x",
+ "timeout": "7200",
+ "time_left": null,
+ "vlan": 311,
+ "time_elapsed": "144268",
+ "historical": 0,
+ "ifIndex": 240
+ }
+ ]
+ }
}
}