$process_time_limit) { $pid = exec("cat ".$filename); exec("kill -9 ".$pid); exec("rm -f ".$filename); exec("echo ".getmypid()." > ".$filename); // убивает все процессы, которых нет в .pid файлах kill_zombie_process(); if (scanner()) { sleep(rand(3,7)); exec("rm -f ".$filename); goto start; } } else { continue; } } else { // если файл отсутствует пишем pid процесса и запускаем скрипт exec("echo ".getmypid()." > ".$filename); // убивает все процессы, которых нет в .pid файлах kill_zombie_process(); if (scanner()) { sleep(rand(3,7)); exec("rm -f ".$filename); goto start; } } } // сканирует домены function scanner() { // получаем с master список доменов в виде XML $result = domain_list("https://whois.domengood.ru/bots/whoisbot/whois-export.php",""); // если пришёл пустой результат if (trim($result) == "") { return true; } // принимаем запрос как XML $xml_client = new SimpleXMLElement(trim($result)); // получаем параметры $array_items = count($xml_client->item); $scan_status = trim($xml_client->server->scan); $process_id = trim($xml_client->server->process_id); // если с master передан статус "off" - прекращаем сканирование if ($scan_status == "off") { return true; } // подгружаем файл с данными whois $whois_json = file_get_contents("/home/scanner/includes/json/whois.json"); $whois_arr = json_decode($whois_json, true); // пакуем для ответа master'у $data = ' '.IPAddress.' '.$process_id.' '; // имя временного файла с данными сканирования $process_file_name = '/home/scanner/whois-fail-data/'.$process_id.'-'.$array_items.'-'.date("d-m-Y").'.data'; shell_exec("echo \"".$process_id."\" > ".$process_file_name); for ($t=0; $t<$array_items; $t++) { $id = $xml_client->item[$t]->id; $domain_name = $xml_client->item[$t]->domain_name; // начальные значения $answer_type = ''; $registrar = ''; $registar_iana_id = ''; $created = ''; $expires = ''; $free_rule = ''; // получам данные whois $zone = return_domain_piece($domain_name, "domainarea"); $whois_server = $whois_arr[$zone]["WhoisServer"]; $free_domain_answer = implode(";", $whois_arr[$zone]["FreeDomainAnswer"]); $stop_phrase = implode(";", $whois_arr[$zone]["StopPhrase"]); $rdap_server = $whois_arr[$zone]["RDAPServer"]; // получаем whois if (empty($rdap_server)) { $answer = whois_info($domain_name, $free_domain_answer, $stop_phrase, $whois_server); $answer_type = $answer[2]; $registrar_data = domain_date_scanner($domain_name, $answer[3]); $registrar = $registrar_data["registrar"]; $registar_iana_id = $registrar_data["registar_iana_id"]; $created = $registrar_data["created"]; $expires = $registrar_data["expires"]; $free_rule = $registrar_data["free_rule"]; } else { $domain_name = mb_strtolower($domain_name, "utf-8"); $rdap_url = $rdap_server."domain/".$domain_name; if ($rdap_arr = get_rdap_whois_data($rdap_url)) { // если домен свободен if(isset($rdap_arr["answer_type"]) && $rdap_arr["answer_type"] == "free-phrase") { $answer_type = $rdap_arr["answer_type"]; } if (isset($rdap_arr["registrar"])) { $registrar = $rdap_arr["registrar"]; } if (isset($rdap_arr["registar_iana_id"])) { $registar_iana_id = $rdap_arr["registar_iana_id"]; } if (isset($rdap_arr["created"])) { $created = $rdap_arr["created"]; } if (isset($rdap_arr["expires"])) { $expires = $rdap_arr["expires"]; } if (isset($rdap_arr["free_rule"])) { $free_rule = $rdap_arr["free_rule"]; } } } // перекодируем в UTF-8 // закоментировал переконвертацию 12.10.2023 из китайских названий, которые не перекодировались //$registrar = mb_convert_encoding($registrar_data["registrar"], "UTF-8"); //$owner = mb_convert_encoding($registrar_data["owner"], "UTF-8"); if (strlen($registrar) > 150) { $registrar = ''; } // формируем очередной блок для отправки на master $data .= ' '.$id.' '.$answer_type.' '.$registar_iana_id.' '.$created.' '.$expires.' '.$free_rule.' '; // блок формирует файл с данными сканирования. В случае, если сканирование проходит не полностью, скрипт достаёт данные из этого файла и отправляет на master // блок должен быть копией $data $to_fail_folder = ' '.$id.' '.$answer_type.' '.$registar_iana_id.' '.$created.' '.$expires.' '.$free_rule.' '; $to_fail_folder = preg_replace('/ {2,}/', ' ', trim($to_fail_folder)); $to_fail_folder = str_replace("\t", "", $to_fail_folder); shell_exec("echo \"".$to_fail_folder."\" >> ".$process_file_name); // произвольная задержка sleep(1); } $data .= ''; // отправляем данные в виде XML на master domain_list("https://whois.domengood.ru/bots/whoisbot/whois-import.php", $data); fail_sender(); return true; } // отправляет домены из логов процессов, которые неудачно завершились function fail_sender() { // читаем папку с файлами $folder_name = "/home/scanner/whois-fail-data/"; exec("ls ".$folder_name, $folder_arr); // смотрим файлы старше 55 минут foreach ($folder_arr as $filename) { $file_path = $folder_name.$filename; if (!file_exists($file_path)) { continue; } $filetime = filemtime($file_path); $diff = time() - $filetime; $minute = $diff / 60; $minute = ceil($minute); // если файл существует больше n-минут отсылаем данные на master if ($minute > 40) { $content = shell_exec("cat ".$file_path); $data = ''.trim($content).''; // проверяем валидность XML if (!xmlvalid($data)) { unlink($file_path); continue; } // отправляем данные на master и удаляем файл domain_list("https://whois.domengood.ru/bots/whoisbot/whois-import.php", $data); unlink($file_path); } } } // функция посылает запрос к API domengood.ru, папка /slave/ // $url - URL скрипта // $data - данные передаваемые POST function domain_list($url,$data) { // инициализируем сессию curl if ($ch = curl_init ()) { curl_setopt($ch, CURLOPT_URL,$url); // указываем URL, куда отправлять POST-запрос //curl_setopt($ch, CURLOPT_USERPWD, "domengood:SeaieQ5s185V"); // авторизация в запароленой .htpasswd директории curl_setopt($ch, CURLOPT_FAILONERROR, 1); curl_setopt($ch, CURLOPT_USERAGENT, 'Scanner whois.domengood.ru '.IPAddress); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// разрешаем перенаправление curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // указываем, что результат запроса следует передать в переменную, а не вывести на экран curl_setopt($ch, CURLOPT_TIMEOUT, 120); // таймаут соединения curl_setopt($ch, CURLOPT_POST, 1); // указываем, что данные надо передать именно методом POST curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_POSTFIELDS, "slaveip=".IPAddress."&data=".urlencode($data)); // добавляем данные POST-запроса // выполняем запрос $result = curl_exec($ch); curl_close($ch); // завершаем сессию return $result; } } // чистим старые файлы и процессы, которые остаются из-за снижения количества потоков function clean_old_pid($process_time_limit) { for ($i=0; $i<100; $i++) { $filename = "/home/scanner/whois-slave-".$i.".pid"; // если файл с pid процесса существует проверяем его возраст в минутах if (file_exists($filename)) { $pid_file_age = ceil((time() - filemtime($filename)) / 60); // если файл существует больше ($process_time_limit * 2) минут, убиваем процесс if ($pid_file_age > ($process_time_limit * 2)) { $pid = exec("cat ".$filename); exec("kill -9 ".$pid); exec("rm -f ".$filename); } } } } // сравнивает PID процессов в .pid файлах и PID реально запущенных процессов // убивает все процессы, которых нет в .pid файлах function kill_zombie_process() { $file_pid_arr = array(); // делаем массив PID процессов в .pid файлах // берём только 10 файлов for ($i=0; $i<10; $i++) { $filename = "/home/scanner/whois-slave-".$i.".pid"; if (file_exists($filename)) { $file_pid_arr[] = trim(shell_exec("cat ".$filename)); } } // scanner 1947 0.2 4.0 500428 29176 ? Ss 19:39 0:06 /usr/bin/php /home/scanner/dns-slave.php exec("ps aux | grep /home/scanner/whois-slave.php", $matches); foreach ($matches as $process_string) { // пропусаем лишние процессы if (strpos($process_string, "sh -c ps aux") || strpos($process_string, "grep")) { continue; } $string = preg_replace('/\s{2,}/', ' ', $process_string); $string_explode = explode(" ", $string); $pid = $string_explode[1]; if (in_array($pid, $file_pid_arr)) { continue; } exec("kill -9 ".$pid); usleep(100000); } return true; } ?>