mirror of
https://github.com/itflow-org/itflow
synced 2026-11-11 15:07:24 +00:00
487 lines
19 KiB
PHP
487 lines
19 KiB
PHP
<?php
|
|
|
|
/*
|
|
* ITFlow - GET/POST request handler for asset interfaces
|
|
*
|
|
* The ports and network cards of an asset (functions/asset_interface.php):
|
|
* checked by interfaceFormSet() - an address inside its network, a MAC that is
|
|
* one, a network of the asset's client - and connected one-to-one by
|
|
* interfaceConnect(). The asset's own form keeps its primary interface in step
|
|
* (agent/post/asset.php).
|
|
*/
|
|
|
|
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
|
|
|
|
/** What saving an interface says - its name, and anything worth knowing (the address is on another device too). */
|
|
function interfaceSavedMessage($verb, $name, $warnings) {
|
|
if ($warnings) {
|
|
flashAlert("Interface <strong>$name</strong> $verb - " . implode('; ', $warnings) . '.', 'warning');
|
|
} else {
|
|
flashAlert("Interface <strong>$name</strong> $verb");
|
|
}
|
|
}
|
|
|
|
if (isset($_POST['add_asset_interface'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$asset = interfaceAssetForRequest($_POST['asset_id'] ?? 0, 2);
|
|
$asset_id = intval($asset['asset_id']);
|
|
|
|
$error = '';
|
|
$warnings = [];
|
|
$set = interfaceFormSet($_POST, $asset, 0, $error, $warnings);
|
|
if ($set === '') {
|
|
flashAlert($error, 'error');
|
|
redirect();
|
|
}
|
|
|
|
mysqli_query($mysqli, "INSERT INTO asset_interfaces SET $set, interface_asset_id = $asset_id");
|
|
$interface_id = mysqli_insert_id($mysqli);
|
|
|
|
// The first one is the primary whether it is ticked or not
|
|
$has_primary = mysqli_num_rows(mysqli_query($mysqli, "SELECT 1 FROM asset_interfaces WHERE interface_asset_id = $asset_id AND interface_primary = 1 AND interface_archived_at IS NULL"));
|
|
if (!empty($_POST['primary_interface']) || !$has_primary) {
|
|
interfaceMakePrimary($interface_id, $asset_id);
|
|
}
|
|
|
|
$connect_to = interfaceConnectTarget($_POST['connected_to'] ?? 0, $client_id, $asset_id);
|
|
if ($connect_to) {
|
|
interfaceConnect($interface_id, $connect_to);
|
|
}
|
|
|
|
$name = trim($_POST['name']);
|
|
logAudit("Asset Interface", "Create", "$session_name created interface " . escapeSql($name) . " on asset " . escapeSql($asset['asset_name']), $client_id, $asset_id);
|
|
|
|
interfaceSavedMessage('created', $name, $warnings);
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_POST['edit_asset_interface'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$row = interfaceForRequest($_POST['interface_id'] ?? 0, 2);
|
|
$interface_id = intval($row['interface_id']);
|
|
$asset_id = intval($row['asset_id']);
|
|
|
|
$error = '';
|
|
$warnings = [];
|
|
$set = interfaceFormSet($_POST, $row, $interface_id, $error, $warnings);
|
|
if ($set === '') {
|
|
flashAlert($error, 'error');
|
|
redirect();
|
|
}
|
|
|
|
mysqli_query($mysqli, "UPDATE asset_interfaces SET $set WHERE interface_id = $interface_id");
|
|
|
|
if (!empty($_POST['primary_interface'])) {
|
|
interfaceMakePrimary($interface_id, $asset_id);
|
|
}
|
|
|
|
// What it is plugged into - moved, or let go when emptied
|
|
if (isset($_POST['connected_to'])) {
|
|
$connect_to = interfaceConnectTarget($_POST['connected_to'], $client_id, $asset_id);
|
|
$current = intval($row['link']['interface_id'] ?? 0);
|
|
if ($connect_to !== $current) {
|
|
if ($current) {
|
|
interfaceConnect($interface_id, 0);
|
|
}
|
|
if ($connect_to) {
|
|
interfaceConnect($interface_id, $connect_to);
|
|
}
|
|
}
|
|
}
|
|
|
|
$name = trim($_POST['name']);
|
|
logAudit("Asset Interface", "Edit", "$session_name edited interface " . escapeSql($name) . " on asset " . escapeSql($row['asset_name']), $client_id, $asset_id);
|
|
|
|
interfaceSavedMessage('saved', $name, $warnings);
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_GET['disconnect_asset_interface'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$row = interfaceForRequest($_GET['disconnect_asset_interface'], 2);
|
|
|
|
if ($row['link']) {
|
|
interfaceConnect($row['interface_id'], 0);
|
|
logAudit("Asset Interface", "Edit", "$session_name disconnected interface " . escapeSql($row['interface_name']) . " on asset " . escapeSql($row['asset_name']) . " from " . escapeSql($row['link']['asset_name'] . ' ' . $row['link']['interface_name']), $client_id, intval($row['asset_id']));
|
|
}
|
|
|
|
flashAlert("<strong>" . $row['asset_name'] . ' ' . $row['interface_name'] . "</strong> disconnected");
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_GET['primary_asset_interface'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$row = interfaceForRequest($_GET['primary_asset_interface'], 2);
|
|
|
|
interfaceMakePrimary($row['interface_id'], $row['asset_id']);
|
|
|
|
logAudit("Asset Interface", "Edit", "$session_name made interface " . escapeSql($row['interface_name']) . " the primary of asset " . escapeSql($row['asset_name']), $client_id, intval($row['asset_id']));
|
|
|
|
flashAlert("<strong>" . $row['interface_name'] . "</strong> is the primary interface of " . $row['asset_name']);
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_GET['delete_asset_interface'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$row = interfaceForRequest($_GET['delete_asset_interface'], 2);
|
|
|
|
// Its connection goes with it (ON DELETE CASCADE)
|
|
mysqli_query($mysqli, "DELETE FROM asset_interfaces WHERE interface_id = " . intval($row['interface_id']));
|
|
|
|
logAudit("Asset Interface", "Delete", "$session_name deleted interface " . escapeSql($row['interface_name']) . " from asset " . escapeSql($row['asset_name']), $client_id, intval($row['asset_id']));
|
|
|
|
flashAlert("Interface <strong>" . $row['interface_name'] . "</strong> deleted", 'error');
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
// A run of ports - "Gi1/0/" 1 to 24, "eth" 0 to 3
|
|
if (isset($_POST['add_asset_multiple_interfaces'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$asset = interfaceAssetForRequest($_POST['asset_id'] ?? 0, 2);
|
|
$asset_id = intval($asset['asset_id']);
|
|
|
|
$count = intval($_POST['interfaces'] ?? 0);
|
|
if ($count < 1 || $count > 128) {
|
|
flashAlert('Add from 1 to 128 interfaces at a time.', 'error');
|
|
redirect();
|
|
}
|
|
$names = interfaceSeriesNames(trim((string) ($_POST['name_prefix'] ?? '')), $_POST['interface_start'] ?? 1, $count, $_POST['pad'] ?? 0);
|
|
|
|
$type = escapeSql(mb_substr(trim((string) ($_POST['type'] ?? '')), 0, 50));
|
|
$network_id = intval(assetClientOwnedId('network', $_POST['network_id'] ?? 0, $client_id));
|
|
$vlans = escapeSql(interfaceVlansText($_POST['vlans'] ?? ''));
|
|
$notes = escapeSql(trim((string) ($_POST['notes'] ?? '')));
|
|
|
|
$existing = [];
|
|
$sql = mysqli_query($mysqli, "SELECT interface_name FROM asset_interfaces WHERE interface_asset_id = $asset_id AND interface_archived_at IS NULL");
|
|
while ($row = mysqli_fetch_row($sql)) {
|
|
$existing[mb_strtolower($row[0])] = true;
|
|
}
|
|
|
|
$added = 0;
|
|
$skipped = 0;
|
|
foreach ($names as $name) {
|
|
if (isset($existing[mb_strtolower($name)])) {
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
mysqli_query($mysqli, "INSERT INTO asset_interfaces SET interface_name = '" . escapeSql(mb_substr($name, 0, 200)) . "', interface_type = '$type',
|
|
interface_vlans = '$vlans', interface_notes = '$notes', interface_network_id = $network_id, interface_asset_id = $asset_id");
|
|
$added++;
|
|
}
|
|
|
|
logAudit("Asset Interface", "Bulk Create", "$session_name created $added interface(s) " . escapeSql($names[0] . ' - ' . end($names)) . " on asset " . escapeSql($asset['asset_name']), $client_id, $asset_id);
|
|
|
|
flashAlert("Added <strong>$added</strong> interface" . ($added === 1 ? '' : 's') . " to <strong>" . $asset['asset_name'] . "</strong>" . ($skipped ? " - $skipped already there" : ''));
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_POST['bulk_edit_asset_interface_type'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$type = mb_substr(trim((string) ($_POST['bulk_type'] ?? '')), 0, 50);
|
|
|
|
$count = 0;
|
|
foreach (interfacesForBulk(2) as $interface_id => $row) {
|
|
mysqli_query($mysqli, "UPDATE asset_interfaces SET interface_type = '" . escapeSql($type) . "' WHERE interface_id = $interface_id");
|
|
logAudit("Asset Interface", "Edit", "$session_name set the type of interface " . escapeSql($row['interface_name']) . " on asset " . escapeSql($row['asset_name']) . " to " . escapeSql($type ?: 'none'), intval($row['asset_client_id']), intval($row['asset_id']));
|
|
$count++;
|
|
}
|
|
|
|
flashAlert("Type set to <strong>" . ($type ?: 'none') . "</strong> on <strong>$count</strong> interface" . ($count === 1 ? '' : 's'));
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_POST['bulk_edit_asset_interface_network'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$network_id = intval($_POST['bulk_network'] ?? 0);
|
|
$network = $network_id ? networkRow($network_id) : null;
|
|
if ($network_id && !$network) {
|
|
flashAlert('That network no longer exists.', 'error');
|
|
redirect();
|
|
}
|
|
|
|
$count = 0;
|
|
$outside = 0;
|
|
foreach (interfacesForBulk(2) as $interface_id => $row) {
|
|
// The network must be the interface's client's
|
|
if ($network && intval($network['network_client_id']) !== intval($row['asset_client_id'])) {
|
|
continue;
|
|
}
|
|
mysqli_query($mysqli, "UPDATE asset_interfaces SET interface_network_id = $network_id WHERE interface_id = $interface_id");
|
|
$ip = normalizeIpAddress((string) $row['interface_ip']);
|
|
if ($network && $ip !== false && !isIpInSubnet($ip, $network['network'])) {
|
|
$outside++;
|
|
}
|
|
logAudit("Asset Interface", "Edit", "$session_name set the network of interface " . escapeSql($row['interface_name']) . " on asset " . escapeSql($row['asset_name']) . " to " . escapeSql($network['network_name'] ?? 'none'), intval($row['asset_client_id']), intval($row['asset_id']));
|
|
$count++;
|
|
}
|
|
|
|
// The network is named once an interface took it - one that fits none of them may be a client this agent can't see
|
|
$network_label = !$network ? 'none' : ($count ? escapeHtml($network['network_name']) : 'that network');
|
|
flashAlert("Network set to <strong>$network_label</strong> on <strong>$count</strong> interface" . ($count === 1 ? '' : 's')
|
|
. ($outside ? " - $outside ha" . ($outside === 1 ? 's an address' : 've addresses') . " outside " . escapeHtml($network['network']) : ''), $outside ? 'warning' : 'success');
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_POST['bulk_edit_asset_interface_ip_dhcp'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$count = 0;
|
|
foreach (interfacesForBulk(2) as $interface_id => $row) {
|
|
mysqli_query($mysqli, "UPDATE asset_interfaces SET interface_ip = 'DHCP' WHERE interface_id = $interface_id");
|
|
logAudit("Asset Interface", "Edit", "$session_name set interface " . escapeSql($row['interface_name']) . " on asset " . escapeSql($row['asset_name']) . " to DHCP", intval($row['asset_client_id']), intval($row['asset_id']));
|
|
$count++;
|
|
}
|
|
|
|
flashAlert("Set <strong>$count</strong> interface" . ($count === 1 ? '' : 's') . " to <strong>DHCP</strong>");
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_POST['bulk_edit_asset_interface_vlans'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$vlans = interfaceVlansText($_POST['bulk_vlans'] ?? '');
|
|
|
|
$count = 0;
|
|
foreach (interfacesForBulk(2) as $interface_id => $row) {
|
|
mysqli_query($mysqli, "UPDATE asset_interfaces SET interface_vlans = '" . escapeSql($vlans) . "' WHERE interface_id = $interface_id");
|
|
logAudit("Asset Interface", "Edit", "$session_name set the VLANs of interface " . escapeSql($row['interface_name']) . " on asset " . escapeSql($row['asset_name']) . " to " . escapeSql($vlans ?: 'none'), intval($row['asset_client_id']), intval($row['asset_id']));
|
|
$count++;
|
|
}
|
|
|
|
flashAlert("VLANs set to <strong>" . ($vlans ?: 'none') . "</strong> on <strong>$count</strong> interface" . ($count === 1 ? '' : 's'));
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_POST['bulk_disconnect_asset_interfaces'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$count = 0;
|
|
foreach (interfacesForBulk(2) as $interface_id => $row) {
|
|
if ($row['link']) {
|
|
interfaceConnect($interface_id, 0);
|
|
logAudit("Asset Interface", "Edit", "$session_name disconnected interface " . escapeSql($row['interface_name']) . " on asset " . escapeSql($row['asset_name']), intval($row['asset_client_id']), intval($row['asset_id']));
|
|
$count++;
|
|
}
|
|
}
|
|
|
|
flashAlert("Disconnected <strong>$count</strong> interface" . ($count === 1 ? '' : 's'));
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_POST['bulk_delete_asset_interfaces'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$count = 0;
|
|
foreach (interfacesForBulk(2) as $interface_id => $row) {
|
|
mysqli_query($mysqli, "DELETE FROM asset_interfaces WHERE interface_id = $interface_id");
|
|
logAudit("Asset Interface", "Delete", "$session_name deleted interface " . escapeSql($row['interface_name']) . " from asset " . escapeSql($row['asset_name']), intval($row['asset_client_id']), intval($row['asset_id']));
|
|
$count++;
|
|
}
|
|
|
|
flashAlert("Deleted <strong>$count</strong> interface" . ($count === 1 ? '' : 's'), 'error');
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
// The import's columns - an export opens straight back in, VLANs last and optional
|
|
const INTERFACE_CSV_COLUMNS = ['Name', 'Description', 'Type', 'MAC', 'IP', 'NAT IP', 'IPv6', 'Network', 'VLANs'];
|
|
|
|
if (isset($_POST['import_client_asset_interfaces_csv'])) {
|
|
|
|
validateCSRFToken();
|
|
|
|
$asset = interfaceAssetForRequest($_POST['asset_id'] ?? 0, 2);
|
|
$asset_id = intval($asset['asset_id']);
|
|
|
|
if (empty($_FILES['file']['tmp_name'])) {
|
|
flashAlert("Please select a file to upload.", 'error');
|
|
redirect();
|
|
}
|
|
if (strtolower(pathinfo((string) $_FILES['file']['name'], PATHINFO_EXTENSION)) !== 'csv') {
|
|
flashAlert("Bad file extension - only .csv files are accepted.", 'error');
|
|
redirect();
|
|
}
|
|
if ($_FILES['file']['size'] < 1) {
|
|
flashAlert("Bad file size (empty file?).", 'error');
|
|
redirect();
|
|
}
|
|
|
|
$file = fopen($_FILES['file']['tmp_name'], 'r');
|
|
$header = fgetcsv($file, 1000, ',');
|
|
if (!is_array($header) || !in_array(count($header), [8, 9], true)) {
|
|
fclose($file);
|
|
flashAlert("Bad column count - use the template: " . implode(', ', INTERFACE_CSV_COLUMNS) . " (VLANs may be left off).", 'error');
|
|
redirect();
|
|
}
|
|
|
|
// The client's networks, by name and by subnet
|
|
$networks = [];
|
|
$sql = mysqli_query($mysqli, "SELECT network_id, network_name, network FROM networks WHERE network_client_id = $client_id AND network_archived_at IS NULL");
|
|
while ($row = mysqli_fetch_assoc($sql)) {
|
|
$networks[mb_strtolower($row['network_name'])] = intval($row['network_id']);
|
|
$networks[mb_strtolower($row['network'])] = intval($row['network_id']);
|
|
}
|
|
|
|
$row_count = 0;
|
|
$duplicate_count = 0;
|
|
$problems = [];
|
|
$line = 1;
|
|
while (($column = fgetcsv($file, 1000, ',')) !== false) {
|
|
$line++;
|
|
$column = array_pad($column, 9, '');
|
|
$name = trim((string) $column[0]);
|
|
if ($name === '') {
|
|
continue;
|
|
}
|
|
$post = [
|
|
'name' => $name, 'description' => $column[1], 'type' => $column[2], 'mac' => $column[3], 'ip' => trim((string) $column[4]),
|
|
'nat_ip' => $column[5], 'ipv6' => $column[6], 'network_id' => $networks[mb_strtolower(trim((string) $column[7]))] ?? 0, 'vlans' => $column[8],
|
|
];
|
|
$error = '';
|
|
$warnings = [];
|
|
$set = interfaceFormSet($post, $asset, 0, $error, $warnings);
|
|
if ($set === '') {
|
|
if (strpos($error, 'already has an interface') !== false) {
|
|
$duplicate_count++;
|
|
} else {
|
|
$problems[] = "line $line ($name): " . strip_tags($error);
|
|
}
|
|
continue;
|
|
}
|
|
mysqli_query($mysqli, "INSERT INTO asset_interfaces SET $set, interface_asset_id = $asset_id");
|
|
$row_count++;
|
|
}
|
|
fclose($file);
|
|
|
|
logAudit("Asset Interface", "Import", "$session_name imported $row_count interface(s) to asset " . escapeSql($asset['asset_name']) . " via CSV file", $client_id, $asset_id);
|
|
|
|
$message = "<strong>$row_count</strong> interface" . ($row_count === 1 ? '' : 's') . " added to <strong>" . $asset['asset_name'] . "</strong>";
|
|
if ($duplicate_count) {
|
|
$message .= ", <strong>$duplicate_count</strong> already there";
|
|
}
|
|
if ($problems) {
|
|
$message .= ". Not imported - " . implode('; ', array_slice($problems, 0, 3)) . (count($problems) > 3 ? '; and ' . (count($problems) - 3) . ' more' : '');
|
|
}
|
|
flashAlert($message, $problems ? 'warning' : 'success');
|
|
|
|
redirect();
|
|
|
|
}
|
|
|
|
if (isset($_GET['download_client_asset_interfaces_csv_template'])) {
|
|
|
|
enforceUserPermission('module_support');
|
|
|
|
$asset_id = intval($_GET['download_client_asset_interfaces_csv_template']);
|
|
$client_id = intval(getFieldById('assets', $asset_id, 'asset_client_id'));
|
|
enforceClientAccess();
|
|
$asset_name = getFieldById('assets', $asset_id, 'asset_name');
|
|
|
|
$f = fopen('php://memory', 'w');
|
|
fputcsv($f, INTERFACE_CSV_COLUMNS, ',', '"', '\\');
|
|
fputcsv($f, ['Gi1/0/1', 'Uplink to firewall', 'Ethernet', '', '', '', '', '', 'Trunk 1, 10, 20'], ',', '"', '\\');
|
|
fputcsv($f, ['eth0', 'Management', 'Ethernet', '00:1A:2B:3C:4D:5E', 'DHCP', '', '', 'Office LAN', ''], ',', '"', '\\');
|
|
fseek($f, 0);
|
|
|
|
header('Content-Type: text/csv');
|
|
header('Content-Disposition: attachment; filename="' . toAlphanumeric($asset_name) . '-Asset-Interfaces-Template.csv";');
|
|
|
|
fpassthru($f);
|
|
exit;
|
|
|
|
}
|
|
|
|
if (isExportRequest('export_asset_interfaces')) {
|
|
|
|
validateCSRFToken();
|
|
|
|
// Exports are reads - see CONTRIBUTING.md
|
|
enforceUserPermission('module_support');
|
|
|
|
$format = resolveExportFormat($_POST['export_asset_interfaces']);
|
|
|
|
$asset_id = intval($_POST['asset_id']);
|
|
$client_id = intval(getFieldById('assets', $asset_id, 'asset_client_id'));
|
|
enforceClientAccess();
|
|
$asset_name = getFieldById('assets', $asset_id, 'asset_name');
|
|
|
|
// Scoped to the one asset, so no page filters apply
|
|
$rows = [];
|
|
$sql = mysqli_query($mysqli, "SELECT asset_interfaces.*, network_name, network FROM asset_interfaces
|
|
LEFT JOIN networks ON network_id = interface_network_id AND interface_network_id > 0
|
|
WHERE interface_asset_id = $asset_id AND interface_archived_at IS NULL");
|
|
while ($row = mysqli_fetch_assoc($sql)) {
|
|
$rows[intval($row['interface_id'])] = $row;
|
|
}
|
|
$links = interfaceLinks(array_keys($rows));
|
|
interfaceSort($rows);
|
|
|
|
$num_rows = count($rows);
|
|
|
|
guardExportHasRows($num_rows, 'interfaces');
|
|
|
|
if ($num_rows > 0) {
|
|
|
|
guardExportPdfRowCount($format, $num_rows);
|
|
|
|
$export = beginExport('asset_interfaces', $format, toAlphanumeric($asset_name) . '-Interfaces', "$asset_name - Interfaces", '');
|
|
|
|
foreach ($rows as $row) {
|
|
$link = $links[intval($row['interface_id'])] ?? null;
|
|
$row['connected_to'] = $link ? $link['asset_name'] . ' ' . $link['interface_name'] : '';
|
|
addExportRow($export, $row);
|
|
}
|
|
|
|
finishExport($export);
|
|
}
|
|
|
|
logAudit("Asset Interface", "Export", "$session_name exported $num_rows interface(s) of asset " . escapeSql($asset_name) . " to a " . strtoupper($format) . " file", $client_id, $asset_id);
|
|
|
|
exit;
|
|
|
|
}
|