$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;
}
?>