diff --git a/encoder/network.php b/encoder/network.php index 08d1c1c..f695890 100755 --- a/encoder/network.php +++ b/encoder/network.php @@ -1,7 +1,8 @@ + [ @@ -34,8 +35,6 @@ $defaults = [ 'network_secondary_ipv6_dns1' => '', 'network_secondary_ipv6_dns2' => '', ], - 'firewall' => 'disable', - 'ips' => ['', '', '', '', ''] ]; if (file_exists($jsonFile)) { @@ -152,8 +151,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { 'network_secondary_ipv6_dns1' => $secondary_vlan, 'network_secondary_ipv6_dns2' => $secondary_vlan ], - 'firewall' => 'disable', - 'ips' => ['', '', '', '', ''] ]; $json = json_encode($new, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); if (file_put_contents($jsonFile, $json, LOCK_EX) === false) { @@ -161,14 +158,134 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } else { $data = $new; $success = 'Saved.'; - } - update_network(); + $netplan = [ + 'network' => [ + 'version' => 2, + 'renderer' => 'networkd', + 'ethernets' => [ + $iface => [] + ], + 'vlans' => [] + ] + ]; + + /* ---------- helper to build IPv4/IPv6 ---------- */ + function build_interface(array $d, string $key): array + { + $cfg = []; + + /* IPv4 */ + switch ($d['mode']) { + case 'dhcp': + $cfg['dhcp4'] = true; + break; + + case 'static': + if (!empty($d["network_{$key}_ip"]) && !empty($d["network_{$key}_subnet"])) { + $cfg['addresses'][] = + $d["network_{$key}_ip"] . '/' . $d["network_{$key}_subnet"]; + } + if (!empty($d["network_{$key}_gateway"])) { + $cfg['routes'][] = [ + 'to' => 'default', + 'via' => $d["network_{$key}_gateway"] + ]; + } + break; + + case 'disabled': + $cfg['dhcp4'] = false; + break; + } + + /* IPv6 */ + switch ($d['modev6']) { + case 'auto': // SLAAC + $cfg['accept-ra'] = true; + $cfg['dhcp6'] = false; + break; + + case 'dhcp6': + $cfg['dhcp6'] = true; + $cfg['accept-ra'] = false; + break; + + case 'static': + if (!empty($d["network_{$key}_ipv6"]) && !empty($d["network_{$key}_ipv6_prefix"])) { + $cfg['addresses'][] = + $d["network_{$key}_ipv6"] . '/' . $d["network_{$key}_ipv6_prefix"]; + } + if (!empty($d["network_{$key}_ipv6_gateway"])) { + $cfg['routes'][] = [ + 'to' => '::/0', + 'via' => $d["network_{$key}_ipv6_gateway"] + ]; + } + $cfg['accept-ra'] = false; + break; + + case 'disabled': + $cfg['dhcp6'] = false; + $cfg['accept-ra'] = false; + break; + } + + /* DNS */ + $dns = array_filter([ + $d["network_{$key}_dns1"] ?? '', + $d["network_{$key}_dns2"] ?? '', + $d["network_{$key}_ipv6_dns1"] ?? '', + $d["network_{$key}_ipv6_dns2"] ?? '' + ]); + + if ($dns) { + $cfg['nameservers']['addresses'] = array_values($dns); + } + + return $cfg; + } + + /* ---------- VLAN detection ---------- */ + $primary_vlan = trim($data['primary']['network_primary_vlan'] ?? ''); + $secondary_vlan = trim($data['secondary']['network_secondary_vlan'] ?? ''); + + $uses_vlan = ($primary_vlan !== '' || $secondary_vlan !== ''); + + /* ---------- No VLAN: apply primary only ---------- */ + if (!$uses_vlan) { + $netplan['network']['ethernets'][$iface] = + build_interface($data['primary'], 'primary'); + } + /* ---------- VLAN mode ---------- */ else { + // base iface must exist but empty + $netplan['network']['ethernets'][$iface] = []; + + if ($primary_vlan !== '') { + $vif = "{$iface}.{$primary_vlan}"; + $netplan['network']['vlans'][$vif] = array_merge([ + 'id' => (int)$primary_vlan, + 'link' => $iface + ], build_interface($data['primary'], 'primary')); + } + + if ($secondary_vlan !== '') { + $vif = "{$iface}.{$secondary_vlan}"; + $netplan['network']['vlans'][$vif] = array_merge([ + 'id' => (int)$secondary_vlan, + 'link' => $iface + ], build_interface($data['secondary'], 'secondary')); + } + } + + /* ---------- write ---------- */ + $yaml = netplan_yaml($netplan); + file_put_contents('/var/www/50-cloud-init.yaml', $yaml); + } } } ?> -
diff --git a/encoder/static.php b/encoder/static.php index 15feac7..e68cd90 100755 --- a/encoder/static.php +++ b/encoder/static.php @@ -40,6 +40,71 @@ function deleteDir(string $dir): void rmdir($dir); } +function find_first_physical_ethernet(): ?string +{ + foreach (scandir('/sys/class/net') as $iface) { + if ($iface === '.' || $iface === '..' || $iface === 'lo') { + continue; + } + + $net = "/sys/class/net/$iface"; + + if (!is_link("$net/device")) { + continue; + } + + $type = @trim(file_get_contents("$net/type")); + if ($type !== '1') { + continue; + } + + if (is_dir("$net/wireless")) { + continue; + } + + if (is_dir("$net/bridge")) { + continue; + } + + $addrAssignType = @trim(file_get_contents("$net/addr_assign_type")); + if ($addrAssignType !== '0') { + continue; + } + return $iface; + } + return null; +} + +function netplan_yaml(array $data, int $indent = 0): string +{ + $yaml = ''; + $pad = str_repeat(' ', $indent); + + foreach ($data as $key => $value) { + if (is_array($value)) { + $is_list = array_keys($value) === range(0, count($value) - 1); + + if ($is_list) { + foreach ($value as $item) { + if (is_array($item)) { + $yaml .= "{$pad}-\n" . netplan_yaml($item, $indent + 1); + } else { + $yaml .= "{$pad}- {$item}\n"; + } + } + } else { + $yaml .= "{$pad}{$key}:\n" . netplan_yaml($value, $indent + 1); + } + } else { + if (is_bool($value)) { + $value = $value ? 'true' : 'false'; + } + $yaml .= "{$pad}{$key}: {$value}\n"; + } + } + + return $yaml; +} function update_service($which_service) {