Доработка парсера логов Squid для корректного просмотра посещенных HTTPS ресурсов

  • Tutorial
Всем привет! Я получал, и получаю множество писем от людей с вопросами по 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>";
}

Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 46

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

      0
      Я ожидал подобный комментарий. К сожалению, пока это единственный способ…
        0
        С чего такая уверенность?

        http://www.squid-cache.org/Doc/config/logformat/
        Changes to logformat in Squid-3.5:
        New format code %credentials to log the client credentials token.

        New format code %ssl::>sni to TLS client SNI sent to Squid.


        В итоге

        root@sar-proxy-01 squid]# cat squid.conf|grep log
        logformat squid %ts.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %[un %Sh/%<a %mt %ssl::>sni


        и получаем в итоге чтото вроде этого
        Заголовок спойлера



        И просто парсер рихтуем, без хуизов и прочего
          0
          $re = "/(?<date>\\d+\\.\\d+)\\s+(?<responce_time>\\d+)\\s+(?<client>\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+(?<miss>\\w+)\\/(?<code>\\d+)\\s+(?<size>\\d+)\\s+(?<method>\\w+)\\s+(?<url>[^\\s]*)\\s+(?<user>[^\\s]+)\\s+(?<hier>[^\\s]+)\\s+(?<mime>[^\\s]+)\\s+(?<sni>[^\\s]+)/m";  
          preg_match_all($re, $log_file, $m);
          
            0
            А ничего, что у Вас в логах будет куча пробелов вместо доменных имен? Проверено на версии 3.5.8 еще в то время, когда статья про прозрачное проксирование не была выложена мной на Хабр
              0
              Почитай на досуге про регулярные выражения, и почему данная регулярка

              \s*(\d)\s+(\d)


              корректно выдернет числа из следующих записей

              с пробелами и табуляцией
                    2            4  
              

              и без лишних пробелов
              2 5
              

              и в таком виде
              2            2
              


                0
                https://regex101.com/r/mR7iO2/1
                  0
                  если соединение было http, то там будет прочерк, в случае ssl — имя_хоста
                    0
                    да дело не в этом… многие ssl дают тоже прочерк. Ну это в моем случае. И не только у меня. И это именно с 3.5.8.
                      0
                      значит на хосте только один ssl сайт
                        0
                        Маленький патч для sams2
                        diff squidlogline.cpp ../squidlogline.cpp
                        225c225
                        < if (cnt_fields < 11)
                        ---
                        > if (cnt_fields < 10)
                        230c230
                        < if (cnt_fields > 11)
                        ---
                        > if (cnt_fields > 10)
                        257,266d256
                        < if (fields[10] == "-")
                        < {
                        < _url = fields[6];
                        <
                        < }
                        < else
                        < {
                        < if(cnt_fields==11)
                        < _url = fields[10];
                        < }



                        и sams2 нормально парсит логи
                          0
                          спасибо! срок голосования кончился, плюсанул бы
              0
              Огромное спасибо за данный комментарий. Исправил статистику на squidanalyzer подставив
              logformat squid %ts.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ssl::>sni %[un %Sh/%<a %mt

              теперь все красиво

          0
          Странные люди сисадмины :)
          Сначала изобретают SSL и прочих что бы скрыть то куда они ходят.
          А потом изобретают вот такое :)
            +1
            Ну, не совсем) мне не хочется знать, что там было внутри туннеля, а вот куда юзер заходил, очень даже хочется
              0
              Не скромный вопрос: для чего?
              Все 'нормальные ' пользователи ходят по нужным сайтам с мобил планшетов.
                +2
                Не у всех есть смартфон, планшет тем более. У нас целевая, так сказать, аудитория — именно такие люди, но все любят использовать корпоративный Интернет в личных целях. Это необходимо отслеживать. И это не прихоть сисадмина…
              0
              В свете последних законов — эта штука очень нужна, как бы не хотелось этим заниматься.
              0
              агент от DLP системы на компьютере пользователя решит проблемы с https, но естественно за деньги.
                0
                Речь идёт, во первых, о Squid, при чем здесь dlp? Тем более, что агенты ставятся на каждый пк, и довольно тормозят сам пк, и сеть. Во вторых, какие проблемы он решит?
                  –1
                  агент будет получать данные до их шифрования
                  к тому же у вас основная цель, как я понял, узнать кто куда ходил, а не поиграться со squid…
                    +1
                    А кто ему эти не шифрованные данные отдаст? Браузер?
                      0
                      Основная цель — узнать, кто куда ходил, и предотвратить дальнейшее посещение этих ресурсов. Поскольку, Squid настроен на прозрачное проксирование HTTPS, пользователи не могут влиять на мои наблюдения. Плюс ко всему, ПК лишний раз не нагружаются. Плюс ко всему, DLP вещь не дешевая, учитывая, сколько у меня в конторе ПК используется.
                      К тому же, разве DLP не использует MITM для HTTPS?
                        0
                        К тому же, разве DLP не использует MITM для HTTPS?

                        Это факт. FalconGaze делает именно так.
                        0
                        проверил на примере MyDLP. Как и все другие системы, оно требует, чтобы оно было шлюзом для клиентов, и использует MITM для контроля HTTPS сайтов, что не тру. Так что, данные системы — слишком жирно для того, чтобы отслеживать и блокировать HTTPS ресурсы. К тому же, цель — прозрачное проксирование без установки всяких агентов и т.п. И вообще, данная статья не про Squid, а про парсинг его логов
                  • НЛО прилетело и опубликовало эту надпись здесь
                      0
                      LightSquid не такой удобный, как Screen Squid. Сарг лично мне не нравится по многим причинам. По поводу Вашего способа блокировки. ДНС неплохо, но я для себя выбрал Squid = )
                      Плюс ко всему, у меня несколько контор завязаны между собой, и Кальмар здесь мне удобнее. У каждого свои предпочтения.
                      Но за коммент спасибо, как-нибудь попробую Ваш способ
                      +1
                      Вместо whois используйте jwhois, а если все равно много проверок IP в сутки, то используйте whois.cymru.com.
                        0
                        Спасибо, попробуем!
                        0
                        Вопрос не по теме, но в прошлую тему «Прозрачный Squid» я не успел написать. Возможно как то задать правила no_proxy для squid. Нигде нормальной информации я так и не нашел. А то приходится вручную писать в браузере и софтинах no_proxy параметр.
                          0
                          Что Вы имеете в виду? Вы хотите, чтобы браузер и софтины ходили минуя прокси, который настроен на работу в прозрачном режиме?
                            0
                            задать правила по которым он на определенные адреса ходил бы не через прокси, например к адресам по локальной сети. Нет, браузер у меня смотрит на прокси от скивида, но чтобы он заходил на адреса локальной сети нужно дописывать --no_proxy=«patterns». Возможно ли задать их в правилах самого скида, а не для каждой программы, которая обращается к локальному сквиду?
                              0
                              А в чем проблема добавить всю Вашу подсеть в «белый список» и не применять ограничения? Для чего нужно то, о чем Вы написали?
                                0
                                вот, именно это и нужно, как добавить подсеть в белый список, а все что не находится в ней, пускать через прокси.
                                  0
                                  как организована Ваша локальная сеть? дело в том, что в Кальмаре нужно в начале настроек указывать обслуживаемые подсети. Укажите отдельно ту, которую нужно пускать без ограничений, и ограничьте применение правил прокси только на ту подсеть, к которой ограничения применять НУЖНО
                                    0
                                    Обычно белый список настраивается в броузере, чтобы БРОУЗЕР туда не ходит для local.loc & 10.0.0.0/8 а не на проксе
                                      0
                                      а теперь смотрите, у меня 9 приложений, требующих одних и тех же no-proxy адресов, что лучше, поменять в одном месте, либо лезть в настройки к каждому приложению?
                                        0

                                        Не понял, перефразируйте, плз

                            +1
                            Мы не принадлежность IP к сети смотрим, а тянем (по запросу) сертификат и смотрим его CN и Altnames. Все-таки эта информация точнее.
                              0
                              я бы тоже хотел получать более точную информацию, ведь Кальмар ее «выковыривает» (SNI server_name). Проблема в том, что он их не логирует, а при включении соответствующей опции в логформате, логирует не все, а только то, что блокирует. Остальное (splice) он не логирует в виде нормальных имен сервера, а оставляет прочерки. Это исправлено в более новых версиях… Но не могу, к сожалению, добавить изменения в исходники версии 3.5.8. А как у вас организовано «тянем (по запросу) сертификат и смотрим его CN и Altnames»?
                                0
                                Перловый скрипт на коленке, который прикручен к lightsquid. Надо посмотреть, что скрывается за IP — нажимаем. Т.е. в lightsquid-овских отчетах фигурирует IP адрес.
                                  0
                                  ясно, нам так не подходит… КОгда требуется множество отчетов в СБ сдавать, причем готовых…
                              0
                              Обновил статью! Теперь можно получать более корректную статистику за счет получения информации о сертификате https хоста
                                +1
                                Попробуйте 3.5.13 https://habrahabr.ru/post/267851/#comment_8793751 Работает полгода, не падает, в логах всё отрезолвлено, кроме сайтов из чёрного списка.
                                  0
                                  Черт возьми, я забыл про тот комментарий. Надо будет попробовать, я так думаю, крахи Кальмара исчезли именно из-за наложения патчей?
                                    0
                                    Не скажу про крахи, а вот вместо гуглопереводчика частенько выдавало белый лист плюс страшную запись в логе. Может, ещё дело в разрядности: у меня старенький пенёк х86, а у вас вроде 64.

                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                Самое читаемое