Всем привет! Я получал, и получаю множество писем от людей с вопросами по Squid, который работает на основе моей статьи. Наиболее часто возникает вопрос про просмотр логов Squid каким-либо парсером. Проблема в том, что версия Squid 3.5.8 с настроенным прозрачным проксированием HTTPS логирует посещаемые HTTPS ресурсы не в виде доменных имен, а в виде IP адресов с портами (прим. 164.16.43.56:443). Соответственно, при просмотре статистики посещений вместо человеческой информации проскакивают эти самые IP адреса. Собирать статистику с такими данными довольно сложно. Я связывался с разработчиками Squid по этому поводу, но внятного ответа так и не получил. Единственное, что я выяснил, нормальное логирование работает в более новых версиях Squid, но на них прозрачное проксирование лично у меня так и не заработало должным образом. Поэтому возник вопрос о том, как сделать резолв IP адресов в самом парсере логов.

Лично я пользуюсь парсером Screen Squid, и именно в нем я решил попробовать сделать нужные изменения. Так как мне подобный резолв бывает нужен просто при работе в терминале с Bash, я решил весь процесс резолва сделать в виде скрипта на Bash, а в Screen Squid уже средствами PHP его использовать, когда это будет нужно.

Итак, для всего задуманного нам нужны:

  1. собственно, сам парсер Screen Squid (инструкцию по его установке печатать не буду, все есть на оф.сайте).
  2. Grep
  3. Sed
  4. Nslookup
  5. Whois
  6. Прямые руки

Сам Bash-скрипт представляет из себя следующее:

#!/bin/bash

#Единственный входной параметр - ip адрес, запишем его в переменную
IP="$1";

#Пробуем резолвить IP адрес с помощью NSLOOKUP, применяя GREP и SED
#для извлечение из результата нужной нам информации
hostname=$(nslookup $IP | grep -m 1 "name"  | sed 's|.*= ||'|sed -r 's/ Auth.+//' | sed 's/^[ \t]*//;s/[ \t]*$//' );

#Если попытка резолва с помощью NSLOOKUP не удалась, 
#то узнаем информацию об IP адресе с помощью whois, опять же
#применяя GREP и SED для извлечение из результата нужной нам информации
if [[ "$hostname" == '' ]]; then
	hostname=$(whois $IP | grep -m 1 "owner\|OrgName\|orgname\|NetName\|netname\|origin" | sed 's|.*: ||'|sed -r 's/. Auth.+//' | sed 's/^[ \t]*//;s/[ \t]*$//')
fi

#Выводим на экран результат резолва
echo "$hostname"

exit 0;

В принципе, он уже откомментирован, описывать здесь особенно и нечего. Мы получаем информацию об IP адресе сначала с помощью Nslookup, параллельно фильтруя вывод команды с помощью grep и sed, чтобы исключить ненужную информацию. Дабы не писать кучу строк, были использованы возможности grep по включению нескольких условий для выборки (символы "\|"). Сохраняйте скрипт в любом удобном месте, назначайте ему права на выполнение. Допустим, он сохранен в /usr/bin под именем gethost.sh.

Скрипт можно использовать просто из терминала:

gethost.sh ip_address 

Далее расскажу, как этот скрипт прикрутить к Screen Squid. Допустим, что установлен он в /var/www/html. В этой папке будет подпапка reports, где находится файл reports.php. Вот именно в нем необходимо сделать изменения. В этом файле необходимо найти строки:

$result=mysql_query($queryOneIpaddressTraffic) or die (mysql_error());
$numrow=1;
$totalmb=0;
while ($line = mysql_fetch_array($result,MYSQL_NUM)) {
echo "<tr>";
echo "<td>".$numrow."</td>";

if($enableUseiconv==1)
$line[0]=iconv("CP1251","UTF-8",urldecode($line[0]));

echo "<td><a href='http://".$line[0]."' target=blank>".$line[0]."</a></td>";

И вместо последней строки вставить следующее:

//Проверяем, HTTPS ресурс в строке или нет (по наличию символа ':')
//Если символа нет, значит это HTTP ресурс, сразу отображаем на страницу
$dv=strpos($line[0], ":") ;
if ($dv < 1) {
echo "<td><a href='http://".$line[0]."' target=blank>".$line[0]."</a></td>";
} else 
{

// Если же все таки символ ':' присутствует, следовательно это HTTPS ресурс, значит
// производим "колдовские" действия...

// Отделяем IP адрес от всей строки, т.е. все символы до ':'
$str1=strpos($line[0], ":");
$row1=substr($line[0], 0, $str1);
$ipaddress = ltrim($ipaddress);
$ipaddress = $row1;

// Производим резолв IP адреса с помощью скрипта gethost.sh
$hostname = shell_exec('/usr/bin/gethost.sh ' . $ipaddress);

// Выводим в таблицу полученную информацию об IP адресе
echo "<td><a href='https://".$ipaddress."' target=blank>".$hostname."</a></td>";
}

Код писАлся на скорую руку, но вполне работает. А срабатывает он, когда открывается просмотр отчета «Трафик пользователей IP адреса», лично мне по большей части необходим только такой отчет. При желании, можно добавить подобный код на любые другие отчеты.

Сам код довольно прост: сначала определяется, какой в данный момент ресурс выводится на экран в таблицу: HTTP или HTTPS, и если это HTTPS (определяется по наличию символа ":"), то отделяем IP адрес от порта, передаем IP адрес в скрипт gethost.sh, получаем вывод скрипта в виде информации об IP адресе, и выводим на экран.

Были мысли заносить в БД сразу нужные данные, но резолв вышеуказанным образом на этапе заполнения БД приводит к длительному процессу распития кофейных напитков, поэтому я от него отказался.

Ах да, чуть не забыл, скрипт должен быть на том же сервере, где расположен парсер Screen Squid. Ну это так, к слову.

Если есть предложения по улучшению, доработке, переделке данного скрипта, буду рад выслушать.

Дополнения:

Сделал немного по-другому, мне кажется более информативно, как здесь верно подметил товарищ kbool. Можно получить данные SSL сертификата нужного хоста прямо из PHP, считав оттуда интересующую информацию. Ниже код, который надо вставить в reports.php вместо вышепредложенного:

//Проверяем, HTTPS ресурс в строке или нет (по наличию символа ':')
//Если символа нет, значит это HTTP ресурс, сразу отображаем на страницу
$dv=strpos($line[0], ":") ;
if ($dv < 1) {
echo "<td><a href='http://".$line[0]."' target=blank>".$line[0]."</a></td>";
} else 
{

// Если же все таки символ ':' присутствует, следовательно это HTTPS ресурс, значит
// производим "колдовские" действия...

// Отделяем IP адрес от всей строки, т.е. все символы до ':'
$str1=strpos($line[0], ":");
$row1=substr($line[0], 0, $str1);
$ipaddress = ltrim($ipaddress);
$ipaddress = $row1;
// Производим резолв IP адреса 
///////////////////////////////////////////////////////////
$options = array( 
        "ssl" => array(
        "capture_peer_cert"       => true,
        "capture_peer_chain"      => true,
        "capture_peer_cert_chain" => false, 
        "verify_peer"             => false,
        "verify_peer_name"        => false, 
        "allow_self_signed"       => false )
);

$get = stream_context_create($options);
$read = stream_socket_client("ssl://".$ipaddress.":443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $get);
$cert = stream_context_get_params($read);
$certinfo = openssl_x509_parse($cert['options']['ssl']['peer_certificate']);
$certinfo = $certinfo['name'];
$CN=strpos($certinfo,"CN=")+3;
$CN_end=strlen($certinfo);
$hostname = substr($certinfo, $CN, $CN_end);
////////////////////////////////////////////////////////////
// Выводим в таблицу полученную информацию об IP адресе
echo "<td><a href='https://".$ipaddress."' target=blank>".$hostname."</a></td>";
}

Поделиться с друзьями
-->

Комментарии (28)


  1. vikarti
    14.08.2016 06:25
    +1

    хоть какое то решение но…
    первая же в нем проверка… не учитывает что вообще то — на одном IP может быть более одного SSL-сайта (SNI в том числе для того и придуман), используют shared-хостинги и CDN
    вторая же — в случае если сайт за CDN — даст ошибку
    как пример — допустим у вас в логах посещение https://test.anatra.me/ — ваш скрипт скажет что это CloudFlare и все. а какой именно сайт воспользовался этой CDN — не скажет.


    1. nagibat0r
      14.08.2016 09:25

      Я ожидал подобный комментарий. К сожалению, пока это единственный способ…


  1. wispoz
    14.08.2016 09:18

    Странные люди сисадмины :)
    Сначала изобретают SSL и прочих что бы скрыть то куда они ходят.
    А потом изобретают вот такое :)


    1. nagibat0r
      14.08.2016 09:27
      +1

      Ну, не совсем) мне не хочется знать, что там было внутри туннеля, а вот куда юзер заходил, очень даже хочется


      1. wispoz
        14.08.2016 09:29

        Не скромный вопрос: для чего?
        Все 'нормальные ' пользователи ходят по нужным сайтам с мобил планшетов.


        1. nagibat0r
          14.08.2016 09:36
          +2

          Не у всех есть смартфон, планшет тем более. У нас целевая, так сказать, аудитория — именно такие люди, но все любят использовать корпоративный Интернет в личных целях. Это необходимо отслеживать. И это не прихоть сисадмина…


  1. pha
    14.08.2016 11:52

    агент от DLP системы на компьютере пользователя решит проблемы с https, но естественно за деньги.


    1. nagibat0r
      14.08.2016 11:54

      Речь идёт, во первых, о Squid, при чем здесь dlp? Тем более, что агенты ставятся на каждый пк, и довольно тормозят сам пк, и сеть. Во вторых, какие проблемы он решит?


      1. pha
        14.08.2016 12:29
        -1

        агент будет получать данные до их шифрования
        к тому же у вас основная цель, как я понял, узнать кто куда ходил, а не поиграться со squid…


        1. splav_asv
          14.08.2016 12:48
          +1

          А кто ему эти не шифрованные данные отдаст? Браузер?


        1. nagibat0r
          14.08.2016 12:49

          Основная цель — узнать, кто куда ходил, и предотвратить дальнейшее посещение этих ресурсов. Поскольку, Squid настроен на прозрачное проксирование HTTPS, пользователи не могут влиять на мои наблюдения. Плюс ко всему, ПК лишний раз не нагружаются. Плюс ко всему, DLP вещь не дешевая, учитывая, сколько у меня в конторе ПК используется.
          К тому же, разве DLP не использует MITM для HTTPS?


          1. JTProg
            15.08.2016 21:30

            К тому же, разве DLP не использует MITM для HTTPS?

            Это факт. FalconGaze делает именно так.


        1. nagibat0r
          17.08.2016 07:41

          проверил на примере MyDLP. Как и все другие системы, оно требует, чтобы оно было шлюзом для клиентов, и использует MITM для контроля HTTPS сайтов, что не тру. Так что, данные системы — слишком жирно для того, чтобы отслеживать и блокировать HTTPS ресурсы. К тому же, цель — прозрачное проксирование без установки всяких агентов и т.п. И вообще, данная статья не про Squid, а про парсинг его логов


  1. Ivan_83
    15.08.2016 01:19
    +1

    Есть же лайтсквид, и вроде сарг был, хотя за давностью лет может и путаю.
    Думаю при желании и awstats и тому подобное можно прикрутить.

    Касательно самого процесса, можно было сделать намного изящнее и не заниматься сексом с кальмаром.
    Достаточно завернуть все днс на свой сервер, логировать ответы и выставлять в ответах ttl в 5-10 секунд.
    Дальше собирается обычный netflow.
    Потом некоторая софтина распарсивает лог днс и нетфлоу и делает вполне обоснованные предположения о том куда кто ходил.
    Всё это на скорости порта, без падений кальмара и приключений со сборкой.

    По поводу блокировки — опять же днс.
    Ставим unbound, заворачиваем всё что 53 тцп/юдп идёт из локалки в инет на него и всё.
    Правила пишутся типа так:
    local-zone: «doubleclick.net» static
    local-zone: «google-analytics.com» static
    local-zone: «google-analyzing.com» static
    local-zone: «googleadservices.com» static
    Те теперь doubleclick.net и *.doubleclick.net не резолвятся и клиент получает моментальный ответ что адреса нет.

    Сквид очень хорош только в одном — это кеширование.
    Ещё у него относительно неплохо с возможностями по прописыванию 100500 апсрим прокси на 1000050000 случаев жизни.

    Сейчас для себя использую nginx в качестве прокси, который:
    — немного фильтрует сайты+урлы на них (где совсем уже достало)
    — когда сайт возвращает 403 и заглушку ркн он запоминает и впредь ходит на такие сайты через прокси

    Весь список плохих доменов скормил в unbound, ибо тот же даблклик запарил пролазить по https.

    PS:
    "$hostname = shell_exec('/usr/bin/gethost.sh '. $ipaddress);" — а что помешает юзеру запросить у вашего прокси адрес вида «127.0.0.1 & rm -rf /:443»? :)


    1. nagibat0r
      15.08.2016 06:37

      LightSquid не такой удобный, как Screen Squid. Сарг лично мне не нравится по многим причинам. По поводу Вашего способа блокировки. ДНС неплохо, но я для себя выбрал Squid = )
      Плюс ко всему, у меня несколько контор завязаны между собой, и Кальмар здесь мне удобнее. У каждого свои предпочтения.
      Но за коммент спасибо, как-нибудь попробую Ваш способ


  1. click0
    15.08.2016 08:52
    +1

    Вместо whois используйте jwhois, а если все равно много проверок IP в сутки, то используйте whois.cymru.com.


    1. nagibat0r
      15.08.2016 09:48

      Спасибо, попробуем!


  1. bustEXZ
    15.08.2016 13:20

    Вопрос не по теме, но в прошлую тему «Прозрачный Squid» я не успел написать. Возможно как то задать правила no_proxy для squid. Нигде нормальной информации я так и не нашел. А то приходится вручную писать в браузере и софтинах no_proxy параметр.


    1. nagibat0r
      15.08.2016 14:26

      Что Вы имеете в виду? Вы хотите, чтобы браузер и софтины ходили минуя прокси, который настроен на работу в прозрачном режиме?


      1. bustEXZ
        15.08.2016 15:00

        задать правила по которым он на определенные адреса ходил бы не через прокси, например к адресам по локальной сети. Нет, браузер у меня смотрит на прокси от скивида, но чтобы он заходил на адреса локальной сети нужно дописывать --no_proxy=«patterns». Возможно ли задать их в правилах самого скида, а не для каждой программы, которая обращается к локальному сквиду?


        1. nagibat0r
          15.08.2016 21:27

          А в чем проблема добавить всю Вашу подсеть в «белый список» и не применять ограничения? Для чего нужно то, о чем Вы написали?


          1. bustEXZ
            16.08.2016 08:16

            вот, именно это и нужно, как добавить подсеть в белый список, а все что не находится в ней, пускать через прокси.


            1. nagibat0r
              16.08.2016 09:52

              как организована Ваша локальная сеть? дело в том, что в Кальмаре нужно в начале настроек указывать обслуживаемые подсети. Укажите отдельно ту, которую нужно пускать без ограничений, и ограничьте применение правил прокси только на ту подсеть, к которой ограничения применять НУЖНО


  1. kbool
    15.08.2016 14:21
    +1

    Мы не принадлежность IP к сети смотрим, а тянем (по запросу) сертификат и смотрим его CN и Altnames. Все-таки эта информация точнее.


    1. nagibat0r
      15.08.2016 14:25

      я бы тоже хотел получать более точную информацию, ведь Кальмар ее «выковыривает» (SNI server_name). Проблема в том, что он их не логирует, а при включении соответствующей опции в логформате, логирует не все, а только то, что блокирует. Остальное (splice) он не логирует в виде нормальных имен сервера, а оставляет прочерки. Это исправлено в более новых версиях… Но не могу, к сожалению, добавить изменения в исходники версии 3.5.8. А как у вас организовано «тянем (по запросу) сертификат и смотрим его CN и Altnames»?


      1. kbool
        15.08.2016 14:39

        Перловый скрипт на коленке, который прикручен к lightsquid. Надо посмотреть, что скрывается за IP — нажимаем. Т.е. в lightsquid-овских отчетах фигурирует IP адрес.


        1. nagibat0r
          15.08.2016 14:44

          ясно, нам так не подходит… КОгда требуется множество отчетов в СБ сдавать, причем готовых…


  1. nagibat0r
    22.08.2016 10:43

    Обновил статью! Теперь можно получать более корректную статистику за счет получения информации о сертификате https хоста