* @license https://files.froxlor.org/misc/COPYING.txt GPLv2 */ namespace Froxlor\Cli; use Froxlor\Database\Database; use PDO; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; final class SwitchServerIp extends CliCommand { protected function configure() { $this->setName('froxlor:switch-server-ip'); $this->setDescription('Easily switch IP addresses e.g. after server migration'); $this->addOption('switch', 's', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Switch IP-address pair. A pair is separated by comma. For example: --switch=A,B') ->addOption('list', 'l', InputOption::VALUE_NONE, 'List all IP addresses currently added for this server in froxlor'); } protected function execute(InputInterface $input, OutputInterface $output) { $result = self::SUCCESS; $result = $this->validateRequirements($input, $output); if ($result == self::SUCCESS && $input->getOption('list') == false && $input->getOption('switch') == false) { $output->writeln('Either --list or --switch option must be provided. Nothing to do, exiting.'); $result = self::INVALID; } $io = new SymfonyStyle($input, $output); if ($result == self::SUCCESS && $input->getOption('list')) { $sel_stmt = Database::prepare("SELECT * FROM panel_ipsandports ORDER BY ip ASC, port ASC"); Database::pexecute($sel_stmt); $ips = $sel_stmt->fetchAll(PDO::FETCH_ASSOC); $table_rows = []; foreach ($ips as $ipdata) { $table_rows[] = [$ipdata['id'], $ipdata['ip'], $ipdata['port']]; } $io->table( ['#', 'IP address', 'Port'], $table_rows ); } if ($result == self::SUCCESS && $input->getOption('switch')) { $result = $this->switchIPs($input, $output); } return $result; } private function switchIPs(InputInterface $input, OutputInterface $output): int { $ip_list = $input->getOption('switch'); $has_error = false; foreach ($ip_list as $ips_combo) { $ip_pair = explode(",", $ips_combo); if (count($ip_pair) != 2) { $output->writeln('Invalid option parameter, not a valid IP address pair.'); $has_error = true; } else { if (filter_var($ip_pair[0], FILTER_VALIDATE_IP) == false) { $output->writeln('Invalid source ip address: ' . $ip_pair[0] . ''); $has_error = true; } if (filter_var($ip_pair[1], FILTER_VALIDATE_IP) == false) { $output->writeln('Invalid target ip address: ' . $ip_pair[1] . ''); $has_error = true; } if ($ip_pair[0] == $ip_pair[1] && !$has_error) { $output->writeln('Source and target ip address are equal'); $has_error = true; } } $ips_to_switch[] = $ip_pair; } if ($has_error) { return self::FAILURE; } if (count($ips_to_switch) > 0) { $check_stmt = Database::prepare("SELECT `id` FROM panel_ipsandports WHERE `ip` = :newip"); $upd_stmt = Database::prepare("UPDATE panel_ipsandports SET `ip` = :newip WHERE `ip` = :oldip"); // system.ipaddress $check_sysip_stmt = Database::prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'system' and `varname` = 'ipaddress'"); $check_sysip = Database::pexecute_first($check_sysip_stmt); // system.mysql_access_host $check_mysqlip_stmt = Database::prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'system' and `varname` = 'mysql_access_host'"); $check_mysqlip = Database::pexecute_first($check_mysqlip_stmt); // system.axfrservers $check_axfrip_stmt = Database::prepare("SELECT `value` FROM `panel_settings` WHERE `settinggroup` = 'system' and `varname` = 'axfrservers'"); $check_axfrip = Database::pexecute_first($check_axfrip_stmt); foreach ($ips_to_switch as $ip_pair) { $output->writeln('Switching IP ' . $ip_pair[0] . ' to IP ' . $ip_pair[1] . ''); $ip_check = Database::pexecute_first($check_stmt, [ 'newip' => $ip_pair[1] ]); if ($ip_check) { $output->writeln('Note: ' . $ip_pair[0] . ' not updated to ' . $ip_pair[1] . ' - IP already exists in froxlor\'s database'); continue; } Database::pexecute($upd_stmt, [ 'newip' => $ip_pair[1], 'oldip' => $ip_pair[0] ]); $rows_updated = $upd_stmt->rowCount(); if ($rows_updated == 0) { $output->writeln('Note: ' . $ip_pair[0] . ' not updated to ' . $ip_pair[1] . ' (possibly no entry found in froxlor database. Use --list to see what IP addresses are added in froxlor'); continue; } // check whether the system.ipaddress needs updating if ($check_sysip['value'] == $ip_pair[0]) { $upd2_stmt = Database::prepare("UPDATE `panel_settings` SET `value` = :newip WHERE `settinggroup` = 'system' and `varname` = 'ipaddress'"); Database::pexecute($upd2_stmt, [ 'newip' => $ip_pair[1] ]); $output->writeln('Updated system-ipaddress from ' . $ip_pair[0] . ' to ' . $ip_pair[1] . ''); } // check whether the system.mysql_access_host needs updating if (strstr($check_mysqlip['value'], $ip_pair[0]) !== false) { $new_mysqlip = str_replace($ip_pair[0], $ip_pair[1], $check_mysqlip['value']); $upd2_stmt = Database::prepare("UPDATE `panel_settings` SET `value` = :newmysql WHERE `settinggroup` = 'system' and `varname` = 'mysql_access_host'"); Database::pexecute($upd2_stmt, [ 'newmysql' => $new_mysqlip ]); $output->writeln('Updated mysql_access_host from ' . $check_mysqlip['value'] . ' to ' . $new_mysqlip . ''); } // check whether the system.axfrservers needs updating if (strstr($check_axfrip['value'], $ip_pair[0]) !== false) { $new_axfrip = str_replace($ip_pair[0], $ip_pair[1], $check_axfrip['value']); $upd2_stmt = Database::prepare("UPDATE `panel_settings` SET `value` = :newaxfr WHERE `settinggroup` = 'system' and `varname` = 'axfrservers'"); Database::pexecute($upd2_stmt, [ 'newaxfr' => $new_axfrip ]); $output->writeln('Updated axfr-servers from ' . $check_axfrip['value'] . ' to ' . $new_axfrip . ''); } } } $output->writeln(""); $output->writeln("*** ATTENTION *** Remember to replace IP addresses in configuration files if used anywhere."); $output->writeln("IP addresses updated"); return self::SUCCESS; } }