This commit is contained in:
devdatt 2025-12-16 11:02:36 +05:30
parent 891d84085a
commit c56b96aa8d
8 changed files with 324 additions and 552 deletions

View File

@ -1,510 +1,188 @@
<?php include 'header.php' ?>
<?php <?php
/******************************************************
* firewall_manager.php
* Simple web UI to manage UFW firewall rules.
*
* IMPORTANT:
* - Protect this file (HTTP auth / VPN / IP allowlist).
* - PHP must run as root OR allow ufw in sudoers, e.g.:
* www-data ALL=(ALL) NOPASSWD:/usr/sbin/ufw
******************************************************/
// If ufw is not in this path, adjust: $file = __DIR__ . '/firewall.json';
define('UFW_BIN', '/usr/sbin/ufw'); $rules = [];
// Set to true to only preview commands and not actually run them if (file_exists($file)) {
$DRY_RUN = false; $json = file_get_contents($file);
$rules = json_decode($json, true) ?: [];
$messages = [];
$errors = [];
/**
* Validate port number (165535). Returns int or null.
*/
function sanitize_port($port) {
$port = trim($port);
if ($port === '') return null;
if (!ctype_digit($port)) return null;
$p = (int)$port;
if ($p < 1 || $p > 65535) return null;
return $p;
} }
/**
* Very basic CIDR/subnet validation.
* Accepts forms like:
* 10.0.0.0/24
* 192.168.1.5
*/
function sanitize_subnet($subnet) {
$subnet = trim($subnet);
if ($subnet === '') return null;
// allow plain IP
if (filter_var($subnet, FILTER_VALIDATE_IP)) {
return $subnet;
}
// allow IP/CIDR
$parts = explode('/', $subnet);
if (count($parts) === 2) {
[$ip, $mask] = $parts;
$ip = trim($ip);
$mask = trim($mask);
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
return null;
}
if (!ctype_digit($mask)) {
return null;
}
$m = (int)$mask;
if ($m < 0 || $m > 32) {
return null;
}
return $ip . '/' . $m;
}
return null;
}
/**
* Run a UFW command and capture output.
*/
function run_ufw_command($cmd, $dryRun = false) {
$cmdline = UFW_BIN . ' ' . $cmd;
if ($dryRun) {
return [
'cmd' => $cmdline,
'output' => ['[DRY RUN] Command not executed'],
'exit_code' => 0,
];
}
$output = [];
$ret = 0;
exec($cmdline . ' 2>&1', $output, $ret);
return [
'cmd' => $cmdline,
'output' => $output,
'exit_code' => $ret,
];
}
// Handle POST
if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? ''; $rules = [];
if ($action === 'apply_firewall') { if (!empty($_POST['ip_version'])) {
$globalPorts = $_POST['global_ports'] ?? []; foreach ($_POST['ip_version'] as $i => $v) {
$restrictedPorts = $_POST['restricted_port'] ?? []; $rules[] = [
$restrictedSubnets = $_POST['restricted_subnet'] ?? []; 'ip_version' => $_POST['ip_version'][$i] ?? '',
$dryRunChecked = isset($_POST['dry_run']) && $_POST['dry_run'] === '1'; 'ip_address' => $_POST['ip_address'][$i] ?? '',
'port' => $_POST['port'][$i] ?? '',
$didAnything = false; 'protocol' => $_POST['protocol'][$i] ?? '',
'description' => $_POST['description'][$i] ?? ''
// 1) Open ports for all IP (allow) ];
foreach ($globalPorts as $rawPort) {
$rawPort = trim($rawPort);
if ($rawPort === '') {
continue;
}
$port = sanitize_port($rawPort);
if ($port === null) {
$errors[] = "Invalid open port: " . htmlspecialchars($rawPort);
continue;
}
$didAnything = true;
$res = run_ufw_command('allow ' . (int)$port, $dryRunChecked || $DRY_RUN);
if ($res['exit_code'] !== 0) {
$errors[] = "Failed to allow port {$port}: " . implode(" ", $res['output']);
} else {
$messages[] = "Allowed port {$port} for all IPs.";
} }
} }
// 2) Restricted ports with subnets file_put_contents($file, json_encode($rules, JSON_PRETTY_PRINT));
// Model: Deny port globally, then allow from specified subnets.
$count = max(count($restrictedPorts), count($restrictedSubnets));
for ($i = 0; $i < $count; $i++) {
$rawPort = $restrictedPorts[$i] ?? '';
$rawSubnet = $restrictedSubnets[$i] ?? '';
$rawPort = trim($rawPort);
$rawSubnet = trim($rawSubnet);
if ($rawPort === '' || $rawSubnet === '') {
continue;
}
$port = sanitize_port($rawPort);
$subnet = sanitize_subnet($rawSubnet);
if ($port === null) {
$errors[] = "Invalid restricted port: " . htmlspecialchars($rawPort);
continue;
}
if ($subnet === null) {
$errors[] = "Invalid subnet/CIDR for port {$port}: " . htmlspecialchars($rawSubnet);
continue;
}
$didAnything = true;
// Deny port from everywhere
$denyRes = run_ufw_command('deny ' . (int)$port, $dryRunChecked || $DRY_RUN);
if ($denyRes['exit_code'] !== 0) {
$errors[] = "Failed to deny port {$port}: " . implode(" ", $denyRes['output']);
} else {
$messages[] = "Denied port {$port} for all IPs.";
}
// Allow from subnet
$allowCmd = 'allow from ' . escapeshellarg($subnet) . ' to any port ' . (int)$port;
// We used escapeshellarg() here, but run_ufw_command expects only the ufw arguments,
// so we need to build carefully:
// Rebuild without full path:
$allowCmdForRun = 'allow from ' . $subnet . ' to any port ' . (int)$port;
$allowRes = run_ufw_command($allowCmdForRun, $dryRunChecked || $DRY_RUN);
if ($allowRes['exit_code'] !== 0) {
$errors[] = "Failed to allow port {$port} from {$subnet}: " . implode(" ", $allowRes['output']);
} else {
$messages[] = "Allowed port {$port} only from {$subnet}.";
}
}
if (!$didAnything) {
$errors[] = "No valid firewall rules submitted.";
}
// Optional: reload or enable ufw here
// $reload = run_ufw_command('reload', $dryRunChecked || $DRY_RUN);
}
}
// Get current UFW status
$currentStatus = [];
$statusExit = 0;
if (file_exists(UFW_BIN)) {
exec(UFW_BIN . ' status numbered 2>&1', $currentStatus, $statusExit);
} else {
$currentStatus[] = "UFW binary not found at " . UFW_BIN;
$statusExit = 1;
} }
?> ?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Firewall Rule Manager</title>
<style> <style>
body { body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-family: Arial, sans-serif;
background: #f4f5f7; background: #f5f7fa;
margin: 0;
padding: 0;
}
.page {
max-width: 1100px;
margin: 24px auto;
padding: 0 16px 32px;
}
h1 {
margin-bottom: 4px;
}
.subtitle {
color: #555;
margin-bottom: 16px;
font-size: 14px;
}
.card {
background: #ffffff;
border-radius: 8px;
padding: 20px; padding: 20px;
margin-bottom: 20px;
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.12);
} }
.card h2 {
margin-top: 0; .container {
font-size: 18px; max-width: 1100px;
margin-bottom: 8px; margin: auto;
} background: #fff;
.card p { padding: 20px;
margin-top: 0; border-radius: 8px;
font-size: 13px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
color: #555;
}
.messages {
margin-bottom: 16px;
}
.msg {
padding: 8px 10px;
border-radius: 4px;
margin-bottom: 6px;
font-size: 13px;
}
.msg.success {
background: #e6f4ea;
border: 1px solid #9ad0a6;
color: #225c2e;
}
.msg.error {
background: #fdecea;
border: 1px solid #f5c2c0;
color: #611a15;
} }
table { table {
width: 100%;
border-collapse: collapse; border-collapse: collapse;
width: 100%;
margin-top: 8px;
margin-bottom: 8px;
} }
th, td {
border-bottom: 1px solid #e2e8f0; th,
padding: 6px 8px; td {
text-align: left; padding: 10px;
font-size: 13px; border-bottom: 1px solid #ddd;
} }
th { th {
background: #f9fafb; background: #f0f2f5;
font-weight: 600;
} }
input[type="text"],
input[type="number"] { input,
select {
width: 100%; width: 100%;
box-sizing: border-box; padding: 6px;
padding: 6px 8px;
font-size: 13px;
border: 1px solid #cbd5e1;
border-radius: 4px;
} }
input[type="checkbox"] {
transform: scale(1.1); button {
}
.btn {
display: inline-block;
padding: 6px 12px; padding: 6px 12px;
font-size: 13px;
border-radius: 4px;
border: none; border: none;
border-radius: 4px;
cursor: pointer; cursor: pointer;
background: #2563eb;
color: #ffffff;
} }
.btn.secondary {
background: #e2e8f0; .btn-add {
color: #111827; background: #2e7d32;
color: #fff;
} }
.btn.sm {
padding: 4px 10px; .btn-remove {
font-size: 12px; background: #c62828;
color: #fff;
} }
.btn + .btn {
margin-left: 6px; .btn-save {
background: #1565c0;
color: #fff;
margin-top: 15px;
} }
.row-actions {
.actions {
text-align: right; text-align: right;
} }
pre {
background: #0b1120;
color: #e2e8f0;
padding: 10px;
border-radius: 4px;
font-size: 12px;
overflow-x: auto;
}
.flex {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.flex-right {
margin-left: auto;
}
.small-note {
font-size: 12px;
color: #64748b;
margin-top: 6px;
}
.section-header {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 8px;
}
</style> </style>
</head> <div class="containerindex">
<body> <div class="grid">
<div class="page"> <h2>Firewall Rules</h2>
<h1>Firewall Rule Manager</h1>
<div class="subtitle">
Configure simple UFW rules to open ports for all IPs and restrict ports to specific subnets.
Ensure this interface is accessible only to trusted administrators.
</div>
<div class="messages">
<?php foreach ($messages as $m): ?>
<div class="msg success"><?php echo htmlspecialchars($m); ?></div>
<?php endforeach; ?>
<?php foreach ($errors as $e): ?>
<div class="msg error"><?php echo htmlspecialchars($e); ?></div>
<?php endforeach; ?>
</div>
<form method="post"> <form method="post">
<input type="hidden" name="action" value="apply_firewall"> <table id="rulesTable">
<div class="card">
<div class="section-header">
<h2>Open Ports (All IPs)</h2>
<button type="button" class="btn sm secondary" onclick="addGlobalPortRow()">+ Add Port</button>
</div>
<p>Ports in this list will be <strong>allowed from any IP</strong>.</p>
<table id="globalPortsTable">
<thead> <thead>
<tr> <tr>
<th style="width: 140px;">Port</th> <th>IP Version</th>
<th>Comment (optional)</th> <th>IP Address</th>
<th style="width: 80px;"></th> <th>Port</th>
<th>Protocol</th>
<th>Description</th>
<th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<!-- Default rows (80, 443, 1935) -->
<?php if ($rules): foreach ($rules as $r): ?>
<tr> <tr>
<td><input type="number" name="global_ports[]" value="80" min="1" max="65535"></td> <td>
<td><input type="text" name="global_comment[]" placeholder="HTTP"></td> <select name="ip_version[]">
<td class="row-actions"> <option value="ipv4" <?= $r['ip_version'] == 'ipv4' ? 'selected' : '' ?>>IPv4</option>
<button type="button" class="btn sm secondary" onclick="removeRow(this)">Remove</button> <option value="ipv6" <?= $r['ip_version'] == 'ipv6' ? 'selected' : '' ?>>IPv6</option>
</select>
</td>
<td><input type="text" name="ip_address[]" value="<?= htmlspecialchars($r['ip_address']) ?>"></td>
<td><input type="number" name="port[]" value="<?= htmlspecialchars($r['port']) ?>"></td>
<td>
<select name="protocol[]">
<option value="tcp" <?= $r['protocol'] == 'tcp' ? 'selected' : '' ?>>TCP</option>
<option value="udp" <?= $r['protocol'] == 'udp' ? 'selected' : '' ?>>UDP</option>
<option value="any" <?= $r['protocol'] == 'any' ? 'selected' : '' ?>>ANY</option>
</select>
</td>
<td><input type="text" name="description[]" value="<?= htmlspecialchars($r['description']) ?>"></td>
<td class="actions">
<button type="button" class="btn-remove" onclick="removeRow(this)">Remove</button>
</td> </td>
</tr> </tr>
<?php endforeach;
else: ?>
<tr> <tr>
<td><input type="number" name="global_ports[]" value="443" min="1" max="65535"></td> <td>
<td><input type="text" name="global_comment[]" placeholder="HTTPS"></td> <select name="ip_version[]">
<td class="row-actions"> <option value="ipv4">IPv4</option>
<button type="button" class="btn sm secondary" onclick="removeRow(this)">Remove</button> <option value="ipv6">IPv6</option>
</td> </select>
</tr> </td>
<tr> <td><input type="text" name="ip_address[]" placeholder="192.168.1.10 or 2001:db8::1"></td>
<td><input type="number" name="global_ports[]" value="1935" min="1" max="65535"></td> <td><input type="number" name="port[]" placeholder="1-65535"></td>
<td><input type="text" name="global_comment[]" placeholder="RTMP"></td> <td>
<td class="row-actions"> <select name="protocol[]">
<button type="button" class="btn sm secondary" onclick="removeRow(this)">Remove</button> <option value="tcp">TCP</option>
<option value="udp">UDP</option>
<option value="any">ANY</option>
</select>
</td>
<td><input type="text" name="description[]"></td>
<td class="actions">
<button type="button" class="btn-remove" onclick="removeRow(this)">Remove</button>
</td> </td>
</tr> </tr>
<?php endif; ?>
</tbody> </tbody>
</table> </table>
<br>
<div class="small-note"> <button type="button" class="btn-add" onclick="addRow()">Add Rule</button>
Example: 80, 443, 1935, 22 etc. Empty rows will be ignored. <br><br>
</div> <button type="submit" class="btn-save">Save Rules</button>
</div> <br><br>
<br><br>
<div class="card">
<div class="section-header">
<h2>Restricted Ports (Only From Subnets)</h2>
<button type="button" class="btn sm secondary" onclick="addRestrictedRow()">+ Add Restricted Rule</button>
</div>
<p>
For each row: port is first globally <strong>denied</strong>, then <strong>allowed only from the subnet</strong>.
Typical use: restrict 8080/8443 to internal networks.
</p>
<table id="restrictedTable">
<thead>
<tr>
<th style="width: 140px;">Port</th>
<th>Subnet / CIDR (e.g. 192.168.1.0/24)</th>
<th style="width: 80px;"></th>
</tr>
</thead>
<tbody>
<!-- Example rows -->
<tr>
<td><input type="number" name="restricted_port[]" value="8080" min="1" max="65535"></td>
<td><input type="text" name="restricted_subnet[]" value="192.168.0.0/16"></td>
<td class="row-actions">
<button type="button" class="btn sm secondary" onclick="removeRow(this)">Remove</button>
</td>
</tr>
<tr>
<td><input type="number" name="restricted_port[]" value="8443" min="1" max="65535"></td>
<td><input type="text" name="restricted_subnet[]" value="10.0.0.0/8"></td>
<td class="row-actions">
<button type="button" class="btn sm secondary" onclick="removeRow(this)">Remove</button>
</td>
</tr>
</tbody>
</table>
<div class="small-note">
Subnet examples: <code>192.168.1.0/24</code>, <code>10.0.0.0/8</code>, or a single IP like <code>203.0.113.5</code>.
</div>
</div>
<div class="card">
<div class="flex">
<label>
<input type="checkbox" name="dry_run" value="1">
Preview only (do not execute commands)
</label>
<div class="flex-right">
<button type="submit" class="btn">Apply Firewall Rules</button>
</div>
</div>
<div class="small-note">
Use preview first to verify behaviour. Always test on a non-production system before applying to live servers.
</div>
</div>
</form> </form>
<br><br>
<div class="card">
<h2>Current UFW Status</h2>
<p>Output of <code>ufw status numbered</code>:</p>
<pre><?php echo htmlspecialchars(implode("\n", $currentStatus)); ?></pre>
</div> </div>
</div> </div>
<script> <script>
function removeRow(button) { function addRow() {
const tr = button.closest('tr'); const tbody = document.querySelector('#rulesTable tbody');
const tbody = tr.parentNode; const row = tbody.rows[0].cloneNode(true);
tbody.removeChild(tr); row.querySelectorAll('input').forEach(i => i.value = '');
row.querySelectorAll('select').forEach(s => s.selectedIndex = 0);
tbody.appendChild(row);
} }
function addGlobalPortRow() { function removeRow(btn) {
const tableBody = document.querySelector('#globalPortsTable tbody'); const tbody = document.querySelector('#rulesTable tbody');
const tr = document.createElement('tr'); if (tbody.rows.length > 1) {
tr.innerHTML = ` btn.closest('tr').remove();
<td><input type="number" name="global_ports[]" min="1" max="65535" placeholder="Port"></td>
<td><input type="text" name="global_comment[]" placeholder="Comment (optional)"></td>
<td class="row-actions">
<button type="button" class="btn sm secondary" onclick="removeRow(this)">Remove</button>
</td>
`;
tableBody.appendChild(tr);
} }
function addRestrictedRow() {
const tableBody = document.querySelector('#restrictedTable tbody');
const tr = document.createElement('tr');
tr.innerHTML = `
<td><input type="number" name="restricted_port[]" min="1" max="65535" placeholder="Port"></td>
<td><input type="text" name="restricted_subnet[]" placeholder="192.168.1.0/24"></td>
<td class="row-actions">
<button type="button" class="btn sm secondary" onclick="removeRow(this)">Remove</button>
</td>
`;
tableBody.appendChild(tr);
} }
</script> </script>
</body> <?php include 'footer.php' ?>
</html>

View File

@ -13,11 +13,15 @@ switch ($_POST['action']) {
unlink($file); unlink($file);
} }
} }
deleteDir('/var/www/encoder/setup');
break; break;
case 'reboot': case 'reboot':
exec('sudo reboot'); exec('sudo reboot');
break; break;
} }
$board_id = trim(@file_get_contents('/sys/class/dmi/id/board_serial'));
?> ?>
<script> <script>
function confirmReboot() { function confirmReboot() {
@ -41,7 +45,11 @@ switch ($_POST['action']) {
<div class="containerindex"> <div class="containerindex">
<div class="grid"> <div class="grid">
<div class="card wide"> <div class="card wide">
Currunt Firmware Version :- 1.0 Device Licence Info :- <br>
Device ID :- <?php global $board_id;
echo $board_id ?><br>
Reseller ID :- <br>
Project Name :- <br>
</div> </div>
<div class="card wide"> <div class="card wide">
<form method="post" class="form-center" enctype="multipart/form-data" <form method="post" class="form-center" enctype="multipart/form-data"

View File

@ -449,6 +449,7 @@
<a href="input.php">Input</a> <a href="input.php">Input</a>
<a href="output.php">Output</a> <a href="output.php">Output</a>
<a href="network.php">Network</a> <a href="network.php">Network</a>
<a href="firewall.php">Firewall</a>
<a href="firmware.php">Firmware</a> <a href="firmware.php">Firmware</a>
</nav> </nav>
</header> </header>

View File

@ -172,6 +172,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
</select> </select>
</div> </div>
</div> </div>
<br>
<br>
<div class="input-group"> <div class="input-group">
<input type="text" id="hdmi_video_delay" name="hdmi_video_delay" value="<?php echo htmlspecialchars($data['hdmi']['video_delay']); ?>" placeholder=" "> <input type="text" id="hdmi_video_delay" name="hdmi_video_delay" value="<?php echo htmlspecialchars($data['hdmi']['video_delay']); ?>" placeholder=" ">
<label for="hdmi_video_delay">Video Delay in ms : </label> <label for="hdmi_video_delay">Video Delay in ms : </label>

View File

@ -8,7 +8,6 @@ $defaults = [
'mode' => 'dhcp', 'mode' => 'dhcp',
'modev6' => 'auto', 'modev6' => 'auto',
'network_primary_ip' => '', 'network_primary_ip' => '',
'network_primary_subnet' => '',
'network_primary_gateway' => '', 'network_primary_gateway' => '',
'network_primary_vlan' => '', 'network_primary_vlan' => '',
'network_primary_dns1' => '', 'network_primary_dns1' => '',
@ -24,7 +23,6 @@ $defaults = [
'mode' => 'disabled', 'mode' => 'disabled',
'modev6' => 'disabled', 'modev6' => 'disabled',
'network_secondary_ip' => '', 'network_secondary_ip' => '',
'network_secondary_subnet' => '',
'network_secondary_gateway' => '', 'network_secondary_gateway' => '',
'network_secondary_vlan' => '', 'network_secondary_vlan' => '',
'network_secondary_dns1' => '', 'network_secondary_dns1' => '',
@ -164,6 +162,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$data = $new; $data = $new;
$success = 'Saved.'; $success = 'Saved.';
} }
update_network();
} }
} }
?> ?>
@ -187,13 +187,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
</div> </div>
<br> <br>
<div class="input-group"> <div class="input-group">
<input type="text" id="network_primary_ip" name="network_primary_ip" placeholder="Address" pattern="^(?:(?:25[0-5]|2[0-4]\d|1?\d{1,2})\.){3}(?:25[0-5]|2[0-4]\d|1?\d{1,2})$" value="<?php echo htmlspecialchars($data['primary']['ip']); ?>"> <input
type="text"
id="network_primary_ip"
name="network_primary_ip"
placeholder="192.168.2.111/24"
pattern="^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\/(?:8|16|20|24|28)$"
value="<?php echo htmlspecialchars($data['primary']['ip']); ?>">
<label for="network_primary_ip">Address</label> <label for="network_primary_ip">Address</label>
</div> </div>
<div class="input-group">
<input type="text" id="network_primary_subnet" name="network_primary_subnet" pattern="^([0-9]|[12][0-9]|3[0-2])$|^((25[0-5]|2[0-4]\d|1?\d{1,2})\.){3}(25[0-5]|2[0-4]\d|1?\d{1,2})$" placeholder="255.255.255.0" value="<?php echo htmlspecialchars($data['primary']['subnet']); ?>">
<label for="network_primary_subnet">Subnet</label>
</div>
<div class="input-group"> <div class="input-group">
<input type="text" id="network_primary_gateway" name="network_primary_gateway" pattern="^([0-9a-fA-F]{1,4}:){2,7}[0-9a-fA-F]{1,4}$" placeholder="Gateway" value="<?php echo htmlspecialchars($data['primary']['gateway']); ?>"> <input type="text" id="network_primary_gateway" name="network_primary_gateway" pattern="^([0-9a-fA-F]{1,4}:){2,7}[0-9a-fA-F]{1,4}$" placeholder="Gateway" value="<?php echo htmlspecialchars($data['primary']['gateway']); ?>">
<label for="network_primary_gateway">Gateway</label> <label for="network_primary_gateway">Gateway</label>
@ -263,27 +265,29 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
</div> </div>
<br> <br>
<div class="input-group"> <div class="input-group">
<input type="text" id="network_secondary_ip" name="network_secondary_ip" placeholder="Address" pattern="^(?:(?:25[0-5]|2[0-4]\d|1?\d{1,2})\.){3}(?:25[0-5]|2[0-4]\d|1?\d{1,2})$" value="<?php echo htmlspecialchars($data['primary']['ip']); ?>"> <input
type="text"
id="network_secondary_ip"
name="network_secondary_ip"
placeholder="192.168.1.111/24"
pattern="^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\/(?:8|16|20|24|28)$"
value="<?php echo htmlspecialchars($data['secondary']['ip']); ?>">
<label for="network_secondary_ip">Address</label> <label for="network_secondary_ip">Address</label>
</div> </div>
<div class="input-group"> <div class="input-group">
<input type="text" id="network_secondary_subnet" name="network_secondary_subnet" pattern="^([0-9]|[12][0-9]|3[0-2])$|^((25[0-5]|2[0-4]\d|1?\d{1,2})\.){3}(25[0-5]|2[0-4]\d|1?\d{1,2})$" placeholder="255.255.255.0" value="<?php echo htmlspecialchars($data['primary']['subnet']); ?>"> <input type="text" id="network_secondary_gateway" name="network_secondary_gateway" pattern="^([0-9a-fA-F]{1,4}:){2,7}[0-9a-fA-F]{1,4}$" placeholder="Gateway" value="<?php echo htmlspecialchars($data['secondary']['gateway']); ?>">
<label for="network_secondary_subnet">Subnet</label>
</div>
<div class="input-group">
<input type="text" id="network_secondary_gateway" name="network_secondary_gateway" pattern="^([0-9a-fA-F]{1,4}:){2,7}[0-9a-fA-F]{1,4}$" placeholder="Gateway" value="<?php echo htmlspecialchars($data['primary']['gateway']); ?>">
<label for="network_secondary_gateway">Gateway</label> <label for="network_secondary_gateway">Gateway</label>
</div> </div>
<div class="input-group"> <div class="input-group">
<input type="number" min="1" max="4094" id="network_secondary_vlan" name="network_secondary_vlan" placeholder="Vlan" value="<?php echo htmlspecialchars($data['primary']['vlan']); ?>"> <input type="number" min="1" max="4094" id="network_secondary_vlan" name="network_secondary_vlan" placeholder="Vlan" value="<?php echo htmlspecialchars($data['secondary']['vlan']); ?>">
<label for="network_secondary_vlan">Vlan</label> <label for="network_secondary_vlan">Vlan</label>
</div> </div>
<div class="input-group"> <div class="input-group">
<input type="text" id="network_secondary_dns1" name="network_secondary_dns1" placeholder="1.1.1.1" value="<?php echo htmlspecialchars($data['primary']['vlan']); ?>"> <input type="text" id="network_secondary_dns1" name="network_secondary_dns1" placeholder="1.1.1.1" value="<?php echo htmlspecialchars($data['secondary']['vlan']); ?>">
<label for="network_secondary_dns1">DNS1</label> <label for="network_secondary_dns1">DNS1</label>
</div> </div>
<div class="input-group"> <div class="input-group">
<input type="text" id="network_secondary_dns2" name="network_secondary_dns2" placeholder="8.8.8.8" value="<?php echo htmlspecialchars($data['primary']['vlan']); ?>"> <input type="text" id="network_secondary_dns2" name="network_secondary_dns2" placeholder="8.8.8.8" value="<?php echo htmlspecialchars($data['secondary']['vlan']); ?>">
<label for="network_secondary_dns2">DNS2</label> <label for="network_secondary_dns2">DNS2</label>
</div> </div>
<div class="dropdown-container"> <div class="dropdown-container">
@ -324,58 +328,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<br> <br>
</div> </div>
</div> </div>
<div class="card wide">
<h3>Firewall</h3>
<br>
<div class="dropdown-container">
<span class="dropdown-label">Service Status :</span>
<div class="dropdown">
<select name="service_firewall" id="display">
<option value="enable" <?php if ($data['service_firewall'] == 'enable') echo 'selected'; ?>>Enable</option>
<option value="disable" <?php if ($data['service_firewall'] == 'disable') echo 'selected'; ?>>Disable</option>
</select>
</div>
</div>
<br>
<br>
<div class="input-group">
<input type="text" id="ip1" name="ip1" placeholder="IP1" value="<?php echo htmlspecialchars($data['ips'][0] ?? ''); ?>">
<label for="ip1">IP1</label>
</div>
<div class="input-group">
<input type="text" id="ip2" name="ip2" placeholder="IP2" value="<?php echo htmlspecialchars($data['ips'][1] ?? ''); ?>">
<label for="ip2">IP2</label>
</div>
<div class="input-group">
<input type="text" id="ip3" name="ip3" placeholder="IP3" value="<?php echo htmlspecialchars($data['ips'][2] ?? ''); ?>">
<label for="ip3">IP3</label>
</div>
<div class="input-group">
<input type="text" id="ip4" name="ip4" placeholder="IP4" value="<?php echo htmlspecialchars($data['ips'][3] ?? ''); ?>">
<label for="ip4">IP4</label>
</div>
<div class="input-group">
<input type="text" id="ip5" name="ip5" placeholder="IP5" value="<?php echo htmlspecialchars($data['ips'][4] ?? ''); ?>">
<label for="ip5">IP5</label>
</div>
<div class="input-group">
<input type="text" id="ip6" name="ip6" placeholder="IP6" value="<?php echo htmlspecialchars($data['ips'][4] ?? ''); ?>">
<label for="ip6">IP6</label>
</div>
<div class="input-group">
<input type="text" id="ip7" name="ip7" placeholder="IP7" value="<?php echo htmlspecialchars($data['ips'][4] ?? ''); ?>">
<label for="ip7">IP7</label>
</div>
</div>
<div style="text-align:center; width:100%; margin-top:12px;"> <div style="text-align:center; width:100%; margin-top:12px;">
<button type="submit" style="background:#c00;color:#fff;padding:10px 20px;border:none;font-weight:bold;border-radius:6px;">Save</button> <button type="submit" style="background:#c00;color:#fff;padding:10px 20px;border:none;font-weight:bold;border-radius:6px;">Save</button>
</div> </div>
<br> <br>
<br> <br>
<br> <br>
<br>
<br>
</div> </div>
</form> </form>

View File

@ -0,0 +1,36 @@
<?php
$ethInterfaces = [];
foreach (scandir('/sys/class/net') as $iface) {
if ($iface === '.' || $iface === '..' || $iface === 'lo') {
continue;
}
$base = "/sys/class/net/$iface";
// Must be physical hardware
if (!is_dir("$base/device")) {
continue;
}
// Exclude wireless
if (is_dir("$base/wireless")) {
continue;
}
// Must be Ethernet
$type = @file_get_contents("$base/type");
if (trim($type) !== '1') {
continue;
}
$ethInterfaces[] = $iface;
}
$ethInterface = "";
$ethInterfaces
? $ethInterface = $ethInterfaces[0]
: 'No physical wired Ethernet NIC found';

View File

@ -26,6 +26,20 @@ function adelayFromMs($ms, $channels = 2)
return 'adelay=' . $pattern; return 'adelay=' . $pattern;
} }
function deleteDir(string $dir): void
{
if (!is_dir($dir)) return;
$it = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($files as $file) {
$file->isDir() ? rmdir($file->getRealPath()) : unlink($file->getRealPath());
}
rmdir($dir);
}
function update_service($which_service) function update_service($which_service)
{ {
@ -650,7 +664,87 @@ function update_service($which_service)
function update_firewall() {} function update_firewall() {}
function update_network() {} function update_network()
{
$ethInterfaces = [];
$jsonFile = __DIR__ . '/network.json';
$ethInterface = "";
foreach (scandir('/sys/class/net') as $iface) {
if ($iface === '.' || $iface === '..' || $iface === 'lo') {
continue;
}
$base = "/sys/class/net/$iface";
// Must be physical hardware
if (!is_dir("$base/device")) {
continue;
}
// Exclude wireless
if (is_dir("$base/wireless")) {
continue;
}
// Must be Ethernet
$type = @file_get_contents("$base/type");
if (trim($type) !== '1') {
continue;
}
$ethInterfaces[] = $iface;
}
$ethInterfaces
? $ethInterface = $ethInterfaces[0]
: 'No physical wired Ethernet NIC found';
if ($ethInterface != "") {
$defaults = [
'primary' => [
'mode' => 'dhcp',
'modev6' => 'auto',
'network_primary_ip' => '',
'network_primary_subnet' => '',
'network_primary_gateway' => '',
'network_primary_vlan' => '',
'network_primary_dns1' => '',
'network_primary_dns2' => '',
'network_primary_ipv6' => '',
'network_primary_ipv6_prefix' => '',
'network_primary_ipv6_gateway' => '',
'network_primary_ipv6_vlan' => '',
'network_primary_ipv6_dns1' => '',
'network_primary_ipv6_dns2' => '',
],
'secondary' => [
'mode' => 'disabled',
'modev6' => 'disabled',
'network_secondary_ip' => '',
'network_secondary_gateway' => '',
'network_secondary_vlan' => '',
'network_secondary_dns1' => '',
'network_secondary_dns2' => '',
'network_secondary_ipv6' => '',
'network_secondary_ipv6_prefix' => '',
'network_secondary_ipv6_gateway' => '',
'network_secondary_ipv6_vlan' => '',
'network_secondary_ipv6_dns1' => '',
'network_secondary_ipv6_dns2' => '',
],
'firewall' => 'disable',
'ips' => ['', '', '', '', '']
];
if (file_exists($jsonFile)) {
$raw = file_get_contents($jsonFile);
$data = json_decode($raw, true);
}
}
}
function update_firmware() {} function update_firmware() {}