Логирование HTTP трафика для отладки запросов AJAX в Linux

Часто разработчику требуется видеть весь обмен трафиком между клиентом и сервером, не только заголовки HTTP, но и тело запроса и ответа. Я довольно долго разыскивал подходящий инструмент для этих целей. Но оказалось, что удобнее всего пользоваться не какими-то плагинами для браузера, а простейшим прокси и перехватом трафика с помощью tcpdump.

Выглядит это так:

1. В браузере прописываем использование прокси по адресу 127.0.0.1 порт 5678
2. В терминале открываем сессию ssh с локальным порт-форвардингом (можно и со сжатием трафика), например так:

$ ssh -C -D 5678 username@myhost.com

3. В другом терминале запускаем tcpdump и слушаем трафик на интерфейсе lo порт 5678:

# tcpdump -vvv -s0 ‘port 5678′ -w “/home/username/http.pcap” -i lo

Далее в браузере выполняем необходимые действия, после чего останавливаем tcpdump. Смотреть записанный трафик лучше всего с помощью strings:

$ strings /home/username/http.pcap

Иногда в выводе может быть немного мусора из-за keepalive запросов, но в целом видно все, что требовалось узнать.

Запуск джоба чаще, чем 1 раз в минуту

Старый добрый cron не позволял ставить в расписание задачи, которые бы запускались чаще, чем 1 раз в минуту. Приходилось решать подобные задачи совсем другими способами. Но теперь есть systemd, который умеет это делать.

Пример такой конфигурации:

server:/etc/systemd/system # cat my.service
[Unit]
Description=My Script

[Service]
Type=simple
ExecStart=/path/to/my/script.sh
StartLimitInterval=0
StartLimitBurst=0

server:/etc/systemd/system # cat my.timer
[Unit]
Description=Runs job every 10 seconds

[Timer]
OnBootSec=1sec
OnCalendar=*-*-* *:*:0,10,20,30,40,50
Unit=my.service

[Install]
WantedBy=multi-user.target

Запуск таймера:

# systemctl start my.timer

Добавление в автозагрузку:

# systemctl enable my.timer

Мониторинг работы:

# journalctl -f

Новый сервис: онлайн форматирование JSON

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

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

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

В качестве теста можно использовать строку JSON, например, такую:

{"data":[{"t1":"John","t2":"Doe"},{"t1":"Anna","t2":"Smith" },{"t1":"Peter" ,"t2":"Jones"}]}

На выходе будет удобно читаемый JSON:

{
   "data" : [
      {
         "t2" : "Doe",
         "t1" : "John"
      },
      {
         "t2" : "Smith",
         "t1" : "Anna"
      },
      {
         "t2" : "Jones",
         "t1" : "Peter"
      }
   ]
}

Обычным людям такой сервис вряд ли будет не нужен, но программистам – пригодится.

Как сделать скриншот страницы с нестандартным разрешением в Firefox

Однажды мне приспичило сделать скриншот очеь-очень длинной страницы, которая не влезала на экран. Если поискать, то для Firefox найдется куча говноплагинов, которые с этой задачей справляются на ура; но всегда есть способ лучше.

В меню заходим в Tools / Web Developer / Developer Toolbar (или жмем Shift + F2), и в консоли пишем:

resize to 1920 5000
screenshot /tmp/output.png

И все, в /tmp/output.png будет сохранен скриншот области Firefox разрешением 1920×5000

Xfce, screen lock и смена раскладок клавиатуры

Есть у меня одна многолетняя привычка — лочить консоль, если я куда-то отхожу от компьютера. Потом консоль можно разлочить, но вот в xfce обнаружилось одно маленькое неудобство, мешающее работать. Скрин локер в xfce не показывает текущую раскладку клавиатуры, поэтому промахнуться с раскладкой клавиатуры при наборе пароля — как два байта переслать. А при ошибке ввода пароля предстоит ужасно раздражающее 30-секундное ожидание, которое в некоторых ситуациях просто бесит.

И раз нельзя вывести текущую раскладку клавиатуры на скрин локер, то можно попытаться ее сбрасывать в известную раскладку при его запуске. В общем, проблему можно решить следующим образом:

  • Установить xkb-switch
  • Написать скрипт-обертку, подменяющий стандартный скрин локер:
  • > cat /usr/local/bin/xflock4
    #!/bin/bash
    /usr/local/bin/xkb-switch -s us
    /usr/bin/xflock4
    

    И все, проблема решена. При локе экрана теперь всегда пароль будет набираться в английской раскладке клавиатуры.

    OpenSuse и интернет через Bluetooth

    Nokia E5

    Я уже писал про использование телефона Nokia E5 в качестве модема, и даже приводил настройки интернета для черногорского оператора M-tel. Все это работает отлично, если бы не одно НО. Длинна USB кабеля для Nokia E5 меньше 10 сантиметров, и уж очень неудобно его крепить к ноутбуку. Телефон постоянно свешивается, дергается; связь может теряться в зоне неуверенного приема. И я решил попробовать использовать телефон в качестве модема при соединении через Bluetooth.

    Оказалось, все делается очень просто. Сначала надо сделать так, чтобы телефон и ноутбук снюхались по Bluetooth. Это делается очень просто — на телефоне разрешается соединение Bluetooth для всех, и с помощью апплета gnome-bluetooth находится телефон среди доступных. Далее следует обмен пин-кодами и вуаля, две железки снюхались.

    Затем надо посмотреть, какой канал модема используется в телефоне. Ищем адрес телефона:

    notebook:~ # hcitool scan
    Scanning ...
            04:A8:2A:93:CE:48       Nokia E5
    

    Далее выясняем номер канала модема:

    # sdptool browse 04:A8:2A:93:CE:48
    …
    Service Name: Dial-Up Networking
    Service RecHandle: 0x10009
    Service Class ID List:
      "Dialup Networking" (0x1103)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
      "RFCOMM" (0x0003)
        Channel: 5
    Language Base Attr List:
      code_ISO639: 0x454e
      encoding:    0x6a
      base_offset: 0x100
    Profile Descriptor List:
      "Dialup Networking" (0x1103)
        Version: 0x0100
    …
    

    В моем случае это Channel 5. Теперь надо настроить модем:

    # cat /etc/bluetooth/rfcomm.conf
    #
    # RFCOMM configuration file.
    #
    
    rfcomm0 {
            # Automatically bind the device at startup
            bind yes;
    
            # Bluetooth address of the device
            device 04:A8:2A:93:CE:48;
    
            # RFCOMM channel for the connection
            channel 5;
    
            # Description of the connection
            comment "Nokia E5 Bluetooth Modem";
    }
    

    Номер канала в настройках модема должен совпадать с номером обнаруженного канала, иначе модем работать не будет. После этого надо создать конфигурационный файл для «звонилки». Привожу свой конфиг для черногорского оператора T-mobile:

    # cat /etc/wvdial.conf
    [Dialer Defaults]
    Init1 = ATZ
    Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
    Init3 = AT+CGDCONT=1,"IP","tmcg-wnw"
    Modem = /dev/rfcomm0
    Phone = *99#
    Idle Seconds = 30000
    Modem Type = USB Modem
    Stupid Mode = 1
    Compuserve = 0
    Baud = 460800
    Auto DNS = on
    New PPPD = Yes
    Dial Command = ATDT
    Ask Password = 0
    ISDN = 0
    Password = 38167
    Username = 38167
    

    Ну и последний скрипт запуска «звонилки»:

    # cat start_internet_via_bluetooth.sh
    #!/bin/sh
    rfcomm release 0 # разрываем текущую связь устройства с модемом
    rfcomm bind 0 04:A8:2A:93:CE:48 5  # привязываем модем телефона на 5-м канале к устройству rfcomm0
    wvdial # набираем номер и подключаемся к интернету
    

    Вот теперь телефону не обязательно находиться рядом с ноутбуком. Его можно держать, например, на балконе (где уровень сигнала выше чем в помещении). Главное, чтобы ноутбук видел телефон, а телефон видел сеть. Скорости передачи данных более чем достаточно для голосовой связи по SIP или Skype.

    Про уродов и людей: как защититься от UDP флуда.

    Fail2ban очень хорош для блокирования нежелательных TCP-соединений, но для блокирования UDP флуда его применять нельзя. Дело в том, что протокол UDP не подразумевает проверки подлинности IP адреса отправителя, и очень часто его подделывают чужими адресами. Известны случаи, когда fail2ban блокировал по айпишнику вышестоящий роутер, и соединение с интернетом на сервере пропадало, поэтому просто так перекрывать трафик не стоит.

    Обычно флудят UDP сервера, которые отвечают на запросы и шлют ответы на подделанный IP адрес отправителя, усиливая атаку на жертву. И самый распространенный вариант атаки — это атака на DNS-сервера.

    Самый простой, но не самый правильный способ борьбы с UDP флудом — ограничить число принимаемых или отравляемых пакетов UDP в секунду с помощью iptables, примерно так:

    iptables -A INPUT -p UDP -m pkttype --pkt-type broadcast -j DROP
    iptables -A INPUT -p UDP -m limit --limit 3/s -j ACCEPT
    

    Этот способ работает надежно, но довольно грубо. Если мы говорим про флуд DNS-сервера, то указанный способ ограничит и легитимные запросы к моим доменам, и флуд на левые доменные имена. А правильный способ борьбы с флудом DNS выглядит так.

    1. Обновить bind до версии 9.9.3 (или до 9.9.2 с патчем для rate-limit)

    2. Запретить рекурсию для всех доменов и ограничить число ответов в секунду для «левых» доменов и для своих:

      options {
            recursion no;
            allow-query { none; };
            rate-limit {
                responses-per-second 10;
                errors-per-second 1;
                window 5;
            };
      };
    

    2. Для каждого домена в зону прописать allow-query { any; } :

    zone "mydomain.com"
    {
        type master;
        file "/path/to/file/mydomain.com";
        allow-query { any; };
    };
    

    Теперь ограничение стало более интеллектуальным, на правомерные запросы о моих доменах bind будет слать не более 10 ответов в секунду; а на запросы о левых доменах — максимум 1 запрос в секунду. С цифрами в настройках можно поиграться, и добиться желаемого результата.

    Логи bind в случае атаки будут выглядеть примерно так:

    Jul 18 17:30:54 named[24256]: client 188.40.25.2#34598 (help-u.ru): query (cache) 'help-u.ru/A/IN' denied
    Jul 18 17:30:54 named[24256]: client 188.40.25.2#37411 (ns.help-u.ru): query (cache) 'ns.help-u.ru/AAAA/IN' denied
    Jul 18 17:30:54 named[24256]: limit REFUSED responses to 188.40.25.0/24
    Jul 18 17:31:35 named[24256]: client 49.128.63.42#29236 (help-u.ru): query (cache) 'help-u.ru/MX/IN' denied
    Jul 18 17:32:02 named[24256]: stop limiting error responses to 188.40.25.0/24
    

    Т.е. если флудер обнаглел и шлет запросы слишком часто, сервер на какое-то время ограничивает число ответов на айпишк, с которого пришел запрос.

    Про уродов и людей: как защититься от подбора паролей по ssh.

    Сначала меня забавляли нелепые попытки подобрать пароли по ssh на некоторые мои сервера. Возможность зайти сразу под root у меня отключена (PermitRootLogin no в /etc/ssh/sshd_config), да и имя пользователя, которому разрешен su, тоже никто не знает. Но когда число попыток подбора паролей стало переваливать за 17к в сутки, я решил прекратить этот коммунизм и поставил fail2ban.

    Немного пошаманив с настройками, пришел к следующей конфигурации: 3 неверных попытки входа = бан айпишника на сутки. И, как говорят в Одессе, совсем другая картина маслом — нагрузка на сервер незначительно снизилась, и отчеты logwatch стали несколько короче.

    Однако, спустя неделю после эксплуатации fail2ban, обнаружилась неприятная особенность его работы. В дефолтной конфигурации fail2ban делает запросы whois об айпишнике, который банит. И если сервер whois не отвечает, то fail2ban становится немного не живой — виснет, зараза.

    Но если чуть-чуть подправить mail-whois.conf, mail-whois-lines.conf, sendmail-whois.conf и sendmail-whois-lines.conf в /etc/fail2ban/action.d и исключить обращения к whois, fail2ban перестает зависать.

    Про бэкапы и Яндекс.Диск

    Я довольно долго экспериментировал с хранением бэкапов разными способами, даже как-то баловался с GmailFS. Пару месяцев назад я попробовал Диск от Яндекса, и сейчас могу совершенно определенно сказать, что в кои-то веки Яндекс создал хоть что-то приличное. Уж не знаю, как позиционирует его сам Яндекс, но мне этот сервис приглянулся для хранения бэкапов. У меня оно работает примерно так:

    # cat /etc/davfs2/davfs2.conf 
    cache_dir       /var/cache/davfs2
    cache_size      50
    table_size      1024
    dir_refresh     60
    file_refresh    1
    delay_upload    0
    use_locks    0
    

    Файл /etc/davfs2/secrets содержит строчку с логином и паролем на Яндекс.Диск:
    https://webdav.yandex.ru topsecretlogin “topsecretpassword”

    В /etc/fstab прописывается строчка:
    https://webdav.yandex.ru /backup davfs rw,user,noauto 0 0

    Почти готово. Теперь Яндекс.Диск легко монтируется командой mount /backup без ввода пароля. На тот случай, если кто-то посторонний получит доступ к бэкапам, их по-хорошему следует зашифровать чем-нибудь криптостойким, например, gpg.

    Уже третий месяц сервис работает почти без нареканий, и бэкапы по расписанию аккуратно заливаются на Яндекс.Диск.

    Один недостаток я нашел, но он не имеет отношения к сервису Яндекса. Периодически в директории /var/cache/davfs2 накапливается довольно много файлов, которые davfs2 почему-то не удаляет при размонтировании директории /backup. Чтобы исключить переполнения раздела /var, я их чищу после размонтирования:
    /bin/rm -Rf /var/cache/davfs2/webdav.yandex.ru*

    Новый сервис – Аудиоредактор

    Я тут новый сервис наваял — Аудиоредактор. Он позволяет загружать аудио файлы на сервер, конвертировать их в AAC, M4R, MP3, OGG или WAV, а также вырезать выбранный интервал из трэка. Также можно добавить эффект приглушения звука в начале и в конце трэка (эффект fade), загружать аудио по прямым ссылкам.

    Есть и экспериментальная фича, можно вырезать звук из ролика в Youtube. Только честно скажу, это срабатывает не всегда: иногда youtube банит айпишник за слишком частое скачивание; иногда ругается на то, что в стране сервера просмотр ролика невозможен из-за ограничения авторских прав; могут быть и другие причины.

    Но в целом все работает, может кому-то будет интересно.