в Разработки

Однажды я уже писал об этом, но с того момента над скриптом было проведено не мало работы. Скажу более — он был переписан чуть менее чем полностью, и как следствие — выяснились некоторые очень «интересные» моменты. Один из них заключается в том, что старая версия скрипта хоть и работала, но совсем не так, как надо.

Если подробнее — то она не подходила для версий антивируса старше четвертой. Как оказалось — нод не умеет самостоятельно определять под-директорию из которой ему следует обновиться, и как следствие все пытались обновиться из корня — и как следствие обновлялась только «четверка». Далее — старая версия не умела обновлять компоненты антивируса. Далее — в итоговое зеркало не попадали все необходимые «модули». Ещё — был чертовски кривой веб-интерфейс.

Так же просмотрел значительное количество решений других разработчиков. Забавно то, что 90% из них написаны на php, и состоят из одного файла с лютым хардкодом всего что можно, и чего нельзя. Да и не поддерживаются совсем.

А что же теперь? А теперь мне удалось избавиться и от этих проблем, и попутно (с момента публикации этого поста уже произошли какие-то изменения, однозначно) повысить стабильность. Не получилось пока реализовать авто-обновление, но я над этим думаю. Традиционно скрипт умеет сам искать ключи.

nod32mirror-console-screenshot

Расписывать здесь о том как его установить и настроить смысла не вижу, так как это уже расписано в ридмишке репозитория. Если у тебя появятся какие-либо проблемы — смело сообщай об этом здесь. Ссылки на крайнюю версию и, собственно, сам репозиторий:

Репозиторий на GitHub Скачать zip

Но это не всё. Здесь я бы хотел рассказать чуть подробнее о результатах анализа алгоритмов работы и некоторых практиках, к которым в итоге пришел.

Общий подход

Повторное использование кода даже в bash-скриптах — это очень хорошая практика. Разнесение функций по логически разделенным файлам — добро. Если у тебя есть необходимость скачивать файлы из сети — создай отдельный файл, назови его, скажем — network.sh, и всё что связано с работой по сети — пиши в нем. В итоге все вызовы curl/wget у тебя сосредоточены в одном месте, и ты не паришься.

Именования функций с префиксом имени файла — что-то в роде namespace-ов — добро. Если ты видишь функцию, например, ui_message — то сразу понимаешь что её описание находится в файле ui.sh.

npp-nod32mirror-screenshot

Используй boostrap-файл. Это отдельный скрипт, подключая который ты инициализируешь все необходимые переменные и подключаешь все требуемые файлы, вынося в него весь общий код инициализации. В последствии если тебе (или другому разработчику) потребуется создать что-то своё — он просто подключает bootstrap-файл и получает в своё распоряжение весь функционал и готовое окружение. Да что я тебе рассказываю..

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

Инициализируй критичные переменные принудительно.

Не стесняйся ставить точки с запятой после операции/метода/языковой конструкции там, где это возможно. Так ты даешь явное указание что это является её завершением, да и код становится читабельнее.

Пиши комментарии по необходимости, пиши их на английском языке и только, не стесняйся давать полные названия переменным. На счет крайнего — я серьезно. Не описывай переменную «tes» подразумевая «Temporary echo result». Пиши «temporary_echo_result». Через день ты забудешь что имел в виду так её называя, а другим разобраться в твоем коде станет ой как не просто.

И ещё раз — повторное использование кода. Не надо делать 10 вызовов echo — сделай одну функцию ui_message, и всё выводи ей. В итоге если тебе надо будет переформатировать вывод — ты не будешь судорожно искать «так, а где у меня выводится этот текст?», ты будешь просто фильтровать вывод в одной функции. Очень удобно.

О том как работает Nod32

Как уже говорил выше — нод не умеет брать обновления из директорий v1, v2, nod_upd что расположены в корне твоего зеркала. Вот просто не умеет. Для того чтоб он «пятерка» брала обновления из директории v5, необходимо её туда перенаправить. Как? Смотри, User-Agent’ы у нода (четверки) такие:

ESS Update (Windows; U; 32bit; VDB 29908; BPC 4.2.71.3; OS: 6.2.9200 SP 0.0 NT; TDB 29908; CH 0.0; LNG 1049; x64c; APP essbe; BEO 1; ASP 0.0; FW 0.4; PX 0; PUA 0; RA 0; PEV 29480)
ESS Update (Windows; U; 32bit; VDB 21093; BPC 4.2.71.3; OS: 5.1.2600 SP 3.0 NT; TDB 21093; CH 1.1; LNG 1049; x32c; APP eav; BEO 1; ASP 0.10; FW 0.0; PX 0; PUA 1; RA 0)
"ESS Update (Windows; U; 32bit; VDB 22122; BPC 4.2.71.3; OS: 6.1.7600 SP 0.0 NT; TDB 22122; CH 1.1; LNG 1049; x32c; APP essbe; BEO 1; ASP 0.0; FW 0.0; PX 0; PUA 1; RA 0)

Что их объединяет? Правильно: BPC 4.*. А какие у пятерки?

ESS Update (Windows; U; 32bit; PVT F; VDB 30070; BPC 5.0.95.0; OS: 6.1.7601 SP 1.0 NT; TDB 30070; CL 0.0.0; LNG 1049; x64c; APP eav; BEO 1; ASP 0.10; FW 0.0; PX 0; PUA 1; RA 0; PEV 29837)
ESS Update (Windows; U; 32bit; PVT F; VDB 22122; BPC 5.0.2228.1; OS: 5.2.3790 SP 2.0 NT; TDB 22122; CL 1.1.1; LNG 1049; x32s; APP eea; BEO 3; ASP 0.10; FW 0.0; PX 0; PUA 0; RA 0; HWF: 0100AA70-13A2-F3BB-DEE3-D2ABBCF7E297)
ESS Update (Windows; U; 32bit; PVT F; VDB 22122; BPC 5.0.95.0; OS: 6.1.7600 SP 0.0 NT; TDB 22122; CL 0.0.0; LNG 1049; x64s; APP eavbe; BEO 1; ASP 0.10; FW 0.0; PX 0; PUA 0; RA 0)

Логично предположить, что у «шестерки» это BPC 6.*. Что мы делаем? Мы регуляркой находим значение версии в user-agent’е, проверяем наличие нужной под-директории, и если всё хорошо — то 301 редиректом перенаправляем Nod32 в нужную под-директорию. Да, нод понимает редиректы. Пример конфига:

  # Redirect request to correct update.ver file, based on nod32 user-agent version
  location ~* "^(?/update\.ver)$" {
    if ($http_user_agent ~* "BPC (?[\d]{1,2})\.") {
      set $new_location "v$version$file_url";
    }
    if (-f $document_root/$new_location) {
      return 301 $scheme://$server_name/$new_location;
    }
  }

Да, if-зло, но без него здесь ну никак. Если знаешь как реализовать лучше — дай знать в комментариях к этому посту.

Как дебажить запросы Nod32?

Я дебажил с помощью прозрачного прокси-сервера Charlies. Запускаешь его, вырубаешь всё остальное что ломится в сеть, и нажимаешь «Обновить базу данных сигнатур вирусов» в Nod32. В итоге можешь наблюдать что и куда отправляется, какие заголовки, какие ответы. Ахуенно, в общем. Всегда его использовал для этого:

charlies-screenshot

На этом, пожалуй, и всё. Если есть какие-либо вопросы — пиши в комментарии, постараюсь ответить.

Бабахнуть комментарий

Комментарии

38 Комментариев

  1. К сведению уважаемого разработчика: начиная с версии 9.х антивирусные продукты ESET не поддерживают обновления баз с неофициальных серверов. Следовательно, создание зеркала для этих версий лишено смысла.

  2. А это нормально что при канале 20 Мб/с (не занятом) первоначальное скачивание pcu+5 rus происходит около 3 часов (всего 76 файлов) ?

  3. Добрый День, а как можно добавить несколько ссылок для скачивание? больше 2. Попробовал так: но не работает
    {bitOS: 64, title: ‘Eng 64-bit version’, uri: ‘/download/NOD32_Antivirus_64_bit-eng.msi’},
    {bitOS: 32, title: ‘Eng 32-bit version’, uri: ‘/download/NOD32_Antivirus_32_bit-eng.msi’},
    {bitOS: 64, title: ‘Ru 64-bit version’, uri: ‘/download/NOD32_Antivirus_64_bit-ru.msi’},
    {bitOS: 32, title: ‘Ru 32-bit version’, uri: ‘/download/NOD32_Antivirus_64_bit-ru.msi’}

  4. Добрый день.
    Уважаемый разработчик данного скрипта.
    У Вас случайно нет возможности, времени и желания сделать утилиту на подобии NOD32 Update Viewer.
    С каким нибудь минимальным интерфейсом и чтобы запускалось не из под linux или из под чего его нужно запускать. А из под Windows.
    Я далёкий от всех этих командных строк и т.д.
    Очень был бы признателен. Да и не только я.
    Можно было вернуть на форум ру-борда тему по альтернативному обновлению антивирусных программ от Eset.
    Я уверен что можно создать тему на ру-борде и развивать её.
    Заранее Вас спасибо.

      • Интересная реакция :)
        А что я такого написал, вроде на понятном русском языке ???
        Писал как понимаю, если что не так, то не обессудьте.
        Попробую повторить проще, можете сделать утилиту на подобии NOD32 Update Viewer, которая предназначена для альтернативного выкачивания баз с серверов eset с помощью логина/пароля. Ссылка на утилиту, если поняли о чём я спрашивал http://nodview.125mb.com и что имел в виду.

        • Зачем делать утилиту па подобии (даже без указаний о том, какими киллер-фичами она должна обладать), если уже есть оригинал? Зачем под Windows, если оригинал уже под ней и работает, а под *nix наверняка прекрасно работает из под wine-а? Зачем писать об этом под постом о том что вы не понимаете ничего в скриптах под проектом, написанном на этих самых скриптах? Сколько вопросов.. :)

          • Почему просил именно под Windows т.к. виндовых машин у людей полно и похожей на NOD32 Update Viewer, потому-что я не разбираюсь в скриптах и у неё более понятный интерфейс чем у срипта и т.д.
            И проект NOD32 Update Viewer перестал поддерживаться разработчиком, дальше проект не развивается. Потому и возник такой вопрос и просьба.
            Пока NOD32 Update Viewer работает но ему не долго осталось т.к. эсетовцы выпускают версию за версией антивирусов с нововведениями и новшествами с которыми данная утилита не может работать.
            Если бы я разбирался в том что Вы смастерили, то таких вопросов просто не возникло. Но я к сожалению или к счастью в этом дуб дерево хвойное.
            Нужна утилита интуитивно понятная как например NOD32 Update Viewer.

  5. Привет! Можно ли каким образом заставить работать данный скрипт на raspberry pi с debian 8 на борту? Не получается, unrar не встает… Не могли бы вы помоч?

  6. Здравствуйте! при обновление баз выходит сообщение под каждой ссылкой Error =(

    Wget debug info:
    
    Setting --user-agent (useragent) to ESS Update (Windows; U; 32bit; VDB 11049; BPC 7.0.549.0; OS: 5.1.2600 SP 3.0 NT; CH 1.1; LNG 1049; x32c; APP eavbe; BEO 1; ASP 0.10; FW 0.0; PX 0; PUA 0; RA 0)
    Setting --http-user (httpuser) to EAV-0169426161
    Setting --http-password (httppassword) to t6jjjdfusn
    Setting --limit-rate (limitrate) to 1024k
    Setting robots (robots) to off
    Setting --wait (wait) to 3
    Setting --random-wait (randomwait) to 1
    Setting --directory-prefix (dirprefix) to /var/www/html/
    DEBUG output created by Wget 1.17.1 on linux-gnu.
    
    Reading HSTS entries from /home/igor/.wget-hsts
    URI encoding = 'ANSI_X3.4-1968'
    converted 'http://update.eset.com/v3-rel-sta/mod_000_loader_1108/em000_32_l0.nup' (ANSI_X3.4-1968) -> 'http://update.eset.com/v3-rel-sta/mod_000_loader_1108/em000_32_l0.nup' (UTF-8)
    --2016-11-13 16:41:13--  http://update.eset.com/v3-rel-sta/mod_000_loader_1108/em000_32_l0.nup
    Host 'update.eset.com' has not issued a general basic challenge.
    Resolving update.eset.com (update.eset.com)... 38.90.226.36
    Caching update.eset.com => 38.90.226.36
    Connecting to update.eset.com (update.eset.com)|38.90.226.36|:80... connected.
    Created socket 3.
    Releasing 0x81dc03a8 (new refcount 1).
    
    ---request begin---
    GET /v3-rel-sta/mod_000_loader_1108/em000_32_l0.nup HTTP/1.1
    Cache-Control: no-cache, must-revalidate
    Pragma: no-cache
    If-Modified-Since: Thu, 30 Jun 2016 00:00:00 GMT
    User-Agent: ESS Update (Windows; U; 32bit; VDB 11049; BPC 7.0.549.0; OS: 5.1.2600 SP 3.0 NT; CH 1.1; LNG 1049; x32c; APP eavbe; BEO 1; ASP 0.10; FW 0.0; PX 0; PUA 0; RA 0)
    Accept: */*
    Accept-Encoding: identity
    Host: update.eset.com
    Connection: Keep-Alive
    
    ---request end---
    HTTP request sent, awaiting response...
    ---response begin---
    HTTP/1.1 401 Unauthorized
    Server: nginx
    Date: Sun, 13 Nov 2016 08:41:14 GMT
    Content-Type: text/html
    Content-Length: 188
    Connection: keep-alive
    WWW-Authenticate: Basic realm="NOD32 Engine Updates"
    
    ---response end---
    401 Unauthorized
    Registered socket 3 for persistent reuse.
    Skipping 188 bytes of body: [
    401 Authorization Required
    
    401 Authorization Required
    nginx
    
    
    ] done.
    Auth scheme found 'Basic'
    Auth param list ' realm="NOD32 Engine Updates"'
    Auth param realm=NOD32 Engine Updates
    Authentication selected: Basic realm="NOD32 Engine Updates"
    Inserted 'update.eset.com' into basic_authed_hosts
    Reusing existing connection to update.eset.com:80.
    Reusing fd 3.
    
    ---request begin---
    GET /v3-rel-sta/mod_000_loader_1108/em000_32_l0.nup HTTP/1.1
    Cache-Control: no-cache, must-revalidate
    Pragma: no-cache
    If-Modified-Since: Thu, 30 Jun 2016 00:00:00 GMT
    User-Agent: ESS Update (Windows; U; 32bit; VDB 11049; BPC 7.0.549.0; OS: 5.1.2600 SP 3.0 NT; CH 1.1; LNG 1049; x32c; APP eavbe; BEO 1; ASP 0.10; FW 0.0; PX 0; PUA 0; RA 0)
    Accept: */*
    Accept-Encoding: identity
    Host: update.eset.com
    Connection: Keep-Alive
    Authorization: Basic RUFWLTAxNjk0MjYxNjE6dDZqampkZnVzbg==
    
    ---request end---
    HTTP request sent, awaiting response...
    ---response begin---
    HTTP/1.1 304 Not Modified
    Server: nginx
    Date: Sun, 13 Nov 2016 08:41:15 GMT
    Last-Modified: Thu, 30 Jun 2016 00:00:00 GMT
    Connection: keep-alive
    ETag: "57746100-e434"
    
    ---response end---
    304 Not Modified
    File '/var/www/html/em000_32_l0.nup' not modified on server. Omitting download.
    
    Saving HSTS entries to /home/igor/.wget-hsts
  7. Еще раз приветствую!

    Нашел в чем была трабла:
    … толи файл на сервере обновляется слишком часто, толи скачивается с ошибкой (для меня этот момент не принципиален), но проверка «свежести» в заголовке всегда возвращает, что на зеркале файл «свежий» и как следствие — «Skipped».
    Добавил еще одну проверку, после которой было заменено порядка 40 файликов и процесс обновления возобновился… Мой метод топорный, но я буду рад если вы его усовершенствуете и внедрите…
    Спасибо за сервис!

    # version 1.0.1.8 network.sh line: 147

    ### >>> Go
    local remote_file_size=»$( echo $result | tr -s ‘\r\n’ ‘ ‘ | sed ‘s/.*Content-Length:\s*//’ | sed ‘s/ >> End

  8. Спасибо за труды!
    Есть вопрос, не совсем понятна логика обновления, не расковыривал еще, но замечены странности:
    скрипт запускается в начале часа, и к 10 минутам уже отписывается что закончил… Пробую обновляться — ESET ругается на критическую ошибку и прочее бла-бла.. смотрим лог nginx и что запрашивал ESET…
    УДАЛЕМ все запрашиваемые файлы из директории, и снова запускаем скрипт… он скачивает их и ESET блаженно обновляется…
    Из этого следует что скрипт не проверяет «свежесть» файла…
    Можно сделать чтоб он скачивал файлы в темп, потом менял их в нужной директории и ток потом заменял файл update.ver чтоб антивирь не истерил?
    Или как его заставить проверять «свежесть» файла?

    • Сперва, как вы говорите, «расковыряйте», а после уже делайте какие-либо выводы о проверке на свежесть. Более того — есть тикеты на гитхабе — если возникают какие-либо проблемы — пишите там.
      Ранее работал через темп, но отказался от этой идеи по причине того что не критично, если антивирь не обновится во время обновления зеркала. Обновится через 5 минут после этого — это же не страшно.

  9. Возник вопрос; Если у меня используются версии Nod32 EAV 8.x и Nod32 Endpoint 5.х, то какие базы мне нужны для их обновлений ибо качать все существующие на сервере к себе и долго да и незачем.

  10. если порт для обновления не стандартный 80-й, типа 192.168.1.1:1234 то есть проблема: редирект работает на 192.168.1.1/v6/update.ver, вместо 192.168.1.1:1234/v6/update.ver.

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

      • Да у меня там грубый напильник, изящно как сделать я пока не разобрался:

        server {
          listen      1234;
          server_name 192.168.1.1;
          root        /opt/nod32mirror;
          index       index.html;
          autoindex   on;
          access_log  off;
        

        и ниже в одной строке правка:

        return 301 $scheme://$server_name:1234/$new_location;

        если вместо 1234 вставить $listen, то не работает, nginx -t жалуется на ошибку в конфиге, переменная не определена. не разобрался где оно задается.

      • Автору большое спасибо.
        Есть дополнение: в том случае, если нет доступа к конфигу сервера, и сервер apache, поможет .htaccess

        Что-то вида:

            RewriteEngine on
            Options +FollowSymlinks
            RewriteCond %{HTTP_USER_AGENT} *BPC.3
            RewriteRule ^update.ver$ /eset_upd/update.ver
            RewriteCond %{HTTP_USER_AGENT} *BPC.4
            RewriteRule ^update.ver$ /eset_upd/v4/update.ver
            RewriteCond %{HTTP_USER_AGENT} *BPC.5
            RewriteRule ^update.ver$ /eset_upd/v5/update.ver
            RewriteCond %{HTTP_USER_AGENT} *BPC.6
            RewriteRule ^update.ver$ /eset_upd/v6/update.ver
            RewriteCond %{HTTP_USER_AGENT} *BPC.7
            RewriteRule ^update.ver$ /eset_upd/v7/update.ver
            RewriteCond %{HTTP_USER_AGENT} *BPC.8
            RewriteRule ^update.ver$ /eset_upd/v8/update.ver
            RewriteCond %{HTTP_USER_AGENT} *BPC.9
            RewriteRule ^update.ver$ /eset_upd/v9/update.ver
        
            • Очень просто найти информацию по этому поводу. Если же вкратце — то apache это скорее пережиток прошлого, а поддержка хостингами его — не желание терять тех клиентов, которые всё ещё не перешли на nginx. nginx имеет совершенно иную архитектуру, потребляет в разы меньше ресурсов, бережнее относится к памяти, стабильнее, и может всё, что может apache — только на несколько порядков лучше, надо лишь научиться конфиги писать.
              Если хостинг не предоставляет его поддержку или возможности его установки — думаю, есть смысл посмотреть в сторону lowcost-vps, коих сейчас более чем достаточно.

              • Под Freebsd 10 скрипт в1.0.1.8 тестился?
                А то что-то у меня не завелось :(
                Боюсь есть какая то несовместимость конфигов для Линуx и Фреебсд.
                Спасибо за труды.

  11. Все конечно хорошо но есть пару моментов о которых вроде не где не написано. Во всяком случае у меня без них не заработало.
    1. В файле nod32mirror.conf
    Пришлось закоментить:

      # Enable checking username/password for updates files access
      location ~* ^.+\.nup$ {
        allow all;
        auth_basic "Enter login:password for getting access";
        auth_basic_user_file $document_root/.htpasswd;
      }

    2. Что бы пошли обновления в клиенте пришлось прописать http://айпи адрес сервера:2221/v4 (для каждой версии нода походу нужно указывать свой каталог) хотя очень долго думал что должно работать без /v4