image

Эта тривиальная задача возникла в один из пятничных дней и должна была занять 2-3 минуты времени. В общем, как всегда.

Коллега попросил поправить скрипт у него на сервере. Сделал, сдал ему и обронил ненароком: «Время спешит на 5 минут». Сервер его, пусть сам и разбирается с синхронизацией. Полчаса, час прошел, а он всё пыхтит и тихо матерится.

«Бестолочь! — подумал я, переключаясь в консоль сервера — ну ладно оторвусь ещё на пару минут.»

Смотрим, ntp, rdate, sdwdate не установлены, timesyncd отключен и не запущен.

# timedatectl
      Local time: Sun 2019-08-25 20:44:39 +03
  Universal time: Sun 2019-08-25 17:44:39 UTC
        RTC time: Sun 2019-08-25 17:39:52
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: no
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

Здесь сразу отмечу, что аппаратное время верное: по нему будет легче ориентироваться дальше.

Отсюда и началась череда ошибок.

Ошибка первая. Самоуверенность


Клац-клац…

# systemctl enable systemd-timesyncd.service && systemctl start systemd-timesyncd.service && ntpdate 0.ru.pool.ntp.org && timedatectl set-ntp on && timedatectl
25 Aug 21:00:10 ntpdate[28114]: adjust time server 195.210.189.106 offset -249.015251 sec
      Local time: Sun 2019-08-25 21:00:10 +03
  Universal time: Sun 2019-08-25 18:00:10 UTC
        RTC time: Sun 2019-08-25 18:00:10
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/a

Всё отлично, время синхронизировалось, системное совпадает с аппаратным. «Забирай», — обронил я и вернулся к своим делам.

«Что забирай? — возмутился коллега. — Время прежнее!»

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

# timedatectl
      Local time: Sun 2019-08-25 21:09:15 +03
  Universal time: Sun 2019-08-25 18:09:15 UTC
        RTC time: Sun 2019-08-25 18:05:04
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

Системное время снова неправильное.

Попробуем ещё раз:

# ntpdate 0.ru.pool.ntp.org && timedatectl && sleep 1 && timedatectl
25 Aug 21:07:37 ntpdate[30350]: step time server 89.175.20.7 offset -249.220828 sec
      Local time: Sun 2019-08-25 21:07:37 +03
  Universal time: Sun 2019-08-25 18:07:37 UTC
        RTC time: Sun 2019-08-25 18:07:37
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/a
      Local time: Sun 2019-08-25 21:11:46 +03
  Universal time: Sun 2019-08-25 18:11:46 UTC
        RTC time: Sun 2019-08-25 18:07:37
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

Давайте по-другому:

# date -s "2019-08-25 21:10:30" && date && sleep 1 && timedatectl
Sun Aug 25 21:10:30 +03 2019
Sun Aug 25 21:10:30 +03 2019
      Local time: Sun 2019-08-25 21:14:36 +03
  Universal time: Sun 2019-08-25 18:14:36 UTC
        RTC time: Sun 2019-08-25 18:10:30
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

А вот так:

# hwclock --hctosys && timedatectl && sleep 1 && timedatectl
      Local time: Sun 2019-08-25 21:11:31 +03
  Universal time: Sun 2019-08-25 18:11:31 UTC
        RTC time: Sun 2019-08-25 18:11:31
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/a
      Local time: Sun 2019-08-25 21:15:36 +03
  Universal time: Sun 2019-08-25 18:15:36 UTC
        RTC time: Sun 2019-08-25 18:11:32
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

Время устанавливается на долю секунды, и тут же начинает «спешить» вновь.

При этом в логах, на момент такой ручной смены, видим лишь отчёты системы, о том, что время изменилось, соответственно в правильную/неправильную стороны и изредка Resyncing от systemd-timesyncd.

Aug 25 21:18:51 wisi systemd[1]: Time has been changed
Aug 25 21:18:51 wisi systemd-timesyncd[29258]: System time changed. Resyncing.
Aug 25 21:18:51 wisi systemd[1187]: Time has been changed
Aug 25 21:18:51 wisi systemd[1]: Time has been changed
Aug 25 21:18:51 wisi systemd[1187]: Time has been changed

здесь

# ps afx | grep "[1]187"
 1187 ?        Ss     0:02 /lib/systemd/systemd --user

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

# timedatectl set-ntp off && systemctl stop systemd-timesyncd.service
# hwclock --hctosys && timedatectl && sleep 1 && timedatectl
      Local time: Sun 2019-08-25 21:25:40 +03
  Universal time: Sun 2019-08-25 18:25:40 UTC
        RTC time: Sun 2019-08-25 18:25:40
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: no
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a
      Local time: Sun 2019-08-25 21:29:31 +03
  Universal time: Sun 2019-08-25 18:29:31 UTC
        RTC time: Sun 2019-08-25 18:25:41
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: no
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

и в логах

Aug 25 21:25:40 wisi systemd[1]: Time has been changed
Aug 25 21:25:40 wisi systemd[1187]: Time has been changed
Aug 25 21:29:30 wisi systemd[1]: Time has been changed
Aug 25 21:29:30 wisi systemd[1187]: Time has been changed

Resyncing пропал и в остальном логи девственно чисты.

Проверяем выводы tcpdump по 123-му порту на всех интерфейсах. Никаких запросов нет, но время всё также «убегает».

Ошибка вторая. Спешка


До конца рабочей недели остаётся час, а уходить на выходные с плёвой нерешенной задачей не хочется (не обращайте внимания на время в коде, статья писалась в последующие дни).
И тут вновь вместо того чтобы искать причину я начал пытаться придумать объяснение результата. Я говорю «придумать», потому что не смотря на то, какими бы не были логичными объяснения результата, это ошибочный подход решения проблемы.

Данный сервер является стримминговым и преобразовывает поток DVB-S2 в IP. В потоке DVB-S присутствуют метки времени, поэтому приемники, мультиплексоры, скремблеры и телевизоры часто используют их для синхронизации системных часов. Драйвера DVB-S плат вкомпилены в ядро, поэтому самый быстрый способ гарантированно убрать DVB-S2-поток — это отключить кабели идущие с «тарелок». Благо сервер за стенкой, посему так тому и быть.

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

Ну и раз мы уже удалили все спутниковые сигналы удалим и наземные — попутно выдергиваем все сетевые кабеля. Сервер становится отрезанным от внешнего мира и работает абсолютно автономно, но системные часы всё также спешат.

Рабочая неделя окончена, а сам вопрос даты/времени на нем не критичен, поэтому можно просто пойти домой, но тут я делаю новую промашку.

Ошибка третья. Советчики


Никогда! Никогда не задавайте вопросы на форумах и общеспециализированных (а-ля stackoverflow) сайтах, если ответ на него требует больше чем изучение выдачи первой страницы гугла и прочитки одной страницы man'а.

Вас пошлют обратно в google, почитать всё тот же man и популярно объяснят правила форума/сайта, но не дадут ответа.

Здесь есть как объективные факторы:

  • никто кроме вас не может знать проблему также хорошо;
  • никто не может провести тесты в таких же как у вас условиях

так и субъективные:
  • вы можете не выдать всех вводных для решения задачи, потому что уже придумали «правильное» направление и излагаете суть вопроса упирая на него;
  • старшина (модератор, старожил, админ) всегда прав, если старшина не прав… ну вы знаете...

Если при ответных комментариях вы остались в рамках цензурной лексики, значит у вас крепкие нервы.

Решение


Не нужно делить задачи на простые и сложные.

Перестаём полагаться на свой опыт, статистику, советчиков и начинаем не «объяснять» конечный результат, а последовательно искать причину.

Раз некто устанавливает время значит должен произойти соответствующий системный вызов.

Как в документации софта лучшие доки — это исходники, так в системном администрировании лучший помощник — это аудит, в нашем случае auditd.

Минутка сомнения
Я пробежался по манам, но не был до конца уверен, что время в Linux может устанавливаться только clock_settime и settimeofday, поэтому для первого теста выбрал все «подходящие» вызовы:

# man syscalls | col | grep -F '(2)' | grep -vE '(:|;)' | grep -E '(time|date|clock)' | sed "s/(2).*//" | xargs -I SYSCALL echo "-S SYSCALL " | xargs echo
-S adjtimex -S clock_adjtime -S clock_getres -S clock_gettime -S clock_nanosleep -S clock_settime -S futimesat -S getitimer -S gettimeofday -S mq_timedreceive -S mq_timedsend -S rt_sigtimedwait -S s390_runtime_instr -S setitimer -S settimeofday -S stime -S time -S timer_create -S timer_delete -S timer_getoverrun -S timer_gettime -S timer_settime -S timerfd_create -S timerfd_gettime -S timerfd_settime -S times -S utime -S utimensat -S utimes

и отбросив s390_runtime_instr, stime, timerfd_create, которых auditctl не признал, изначально запустил аудит в виде:

auditctl -a exit,always -S adjtimex -S clock_adjtime -S clock_getres -S clock_nanosleep -S clock_settime -S futimesat -S getitimer -S gettimeofday -S mq_timedreceive -S mq_timedsend -S rt_sigtimedwait -S semtimedop -S setitimer -S settimeofday -S time -S timer_create -S timer_delete -S timer_getoverrun -S timer_gettime -S timer_settime -S timerfd_gettime -S timerfd_settime -S times -S utime -S utimensat -S utimes

Убедившись, что в интересующих меня местах логов нет других syscalls кроме этих двух далее использовал только их.

Запускаем аудит системных вызовов clock_settime и settimeofday и пробуем сменить дату:

# auditctl -a exit,always -S clock_settime -S settimeofday && date -s "2019-08-22 12:10:00" && sleep 5 && auditctl -D

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

Смотрим отчет:

# aureport -s -i

Syscall Report
=======================================
# date time syscall pid comm auid event
=======================================
Warning - freq is non-zero and incremental flushing not selected.
1. 08/22/2019 12:10:00 settimeofday 3088 chkcache_proces root 479630
2. 08/26/2019 09:37:06 clock_settime 1538 date root 479629

Здесь мы видим наш date и неизвестный нам chkcache_proces. Он оказался в отчете выше, так как aureport отсортировал вывод по дате при преобразовании из бинарного вида, а событие произошло в установленное нами время date -s «2019-08-22 12:10:00».
Кто же его породил?

# ausearch -sc settimeofday --comm "chkcache_proces"
----
time->Thu Aug 22 12:10:00 2019
type=PROCTITLE msg=audit(1566465000.000:479630): proctitle="/usr/local/bin/oscam"
type=SYSCALL msg=audit(1566465000.000:479630): arch=c000003e syscall=164 success=yes exit=0 a0=7fde0dfc6e60 a1=0 a2=136cf a3=713ba56 items=0 ppid=3081 pid=3088 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts20 ses=68149 comm="chkcache_proces" exe="/usr/local/bin/oscam" key=(null)

/usr/local/bin/oscam — наш паразит найден. Несмотря на его «зловредное» поведение отказаться от системы условного доступа нельзя, но всё же хотелось бы знать, oscam, WTF?

Ответ быстро найден в исходниках:

#if defined(CLOCKFIX)
if (tv.tv_sec > lasttime.tv_sec || (tv.tv_sec == lasttime.tv_sec && tv.tv_usec >= lasttime.tv_usec)) // check for time issues!
{
  lasttime = tv; // register this valid time
}
  else
{
  tv = lasttime;
  settimeofday(&tv, NULL); // set time back to last known valid time
  //fprintf(stderr, "*** WARNING: BAD TIME AFFECTING WHOLE OSCAM ECM HANDLING, SYSTEMTIME SET TO LAST KNOWN VALID TIME **** \n");
}

Как же мило здесь смотрится закомментированная строчка warning'a

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


  1. questor
    26.08.2019 13:30
    +2

    Статья интересная, но такое впечатление, что автору всё-таки надо было уйти на выходные и он не дописал статью оборвав на самом интересном ме...


    1. DDoSInsurance
      26.08.2019 21:10
      +3

      Вероятно, Вы не поняли, сарказма последней фразы соотнесенной с закомментированным выводом в stderr, о чем дважды было упомянуто в статье.
      Если бы не этот двойной слеш этой истории не было бы вообще.


  1. amarao
    26.08.2019 13:38
    +4

    Спасибо за байки. Очень полезно. Насчёт SO...


    Никогда! Никогда не задавайте вопросы на форумах и общеспециализированных (а-ля stackoverflow) сайтах, если ответ на него требует больше чем изучение выдачи первой страницы гугла и прочитка одной страницы man'а..


    Иногда в ответ прилетает сакральное (теоретическое) знание или фундаментальный вопрос на который трудно ответить (и ответ на который содержит всё). А ещё сокращённое изложение проблемы для SO с minimal reproducable — отличный метод отладки. Другими словами, если ничерта не понятно, то описать что именно ничерта не понятно так, чтобы другие люди поняли что именно не понятно — это полезно.


    1. akdes
      26.08.2019 14:34

      именно так и решаются мои проблемы в основном, т.к. для написания вопроса, мало того, что необходимо «переписать» вопрос из головы на более понятный язык, в процессе чего сам начинаешь понимать проблему, так ещё постоянно, за место того, что бы запостить «кто-то насрал, как исправить?» — делаешь анализ проблемы и в моём случае, в 55% проблема была не том, и в 40% она решалась во время анализа или описания. Ну а 4% шли на отдых и смену обстановки — утро вечера мудренее и 1% когда проблема реально существовала и не решалась собственными усилиями.

      Однако не редкость, что в проблемах 1% нужно действительно действовать по «Никогда! Никогда..!» Ибо в основном в проблемах такого характера никто не захочет лазить дальше посыла в гугл и мануалов.


    1. mOlind
      26.08.2019 14:58
      +1

      Rubber duck debugging. Пока рассказывал в чем проблема, сам понял из-за чего так происходит.


    1. Delsian
      26.08.2019 15:16
      +4

      В 90% случаев после написания вопроса на форуме в голове щелкает и ты через 5 минут понимаешь, где ошибка.
      Но обязательно надо нажать кнопку «Отправить» — без нее эта магия не срабатывает!


      1. ky0
        26.08.2019 15:32
        +1

        А потом ответить самому себе и отметить как решение. Постойте-ка, да это же Тостер во плоти!


        1. tangro
          27.08.2019 10:12
          +2

          Не, потом надо написать «А, всё, разобрался сам» и закрыть без объяснения :)


          1. river-fall
            27.08.2019 13:08
            -1

            «Нашёл остроумное решение теоремы, но поля книги слишком маленькие для его изложения»


      1. sim2q
        26.08.2019 20:46
        +1

        Интересное наблюдение, думал только у меня так


        1. ogost
          27.08.2019 09:20

          Правильно заданный вопрос содержит половину ответа.


    1. ThunderCat
      26.08.2019 16:55

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

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


  1. Alexey2005
    26.08.2019 16:21

    В Linux ситуация, когда какая-то сука раз за разом сбивает нужные настройки, встречается удивительно часто. Это касается любых настроек: DNS, маршрутизация, звук, cron, системное время и много всего прочего.
    После очередной пары-тройки часов, проведённых за «перетряхиванием» системы в поисках виновного, начинаешь задаваться вопросом: а для разработчиков Linux'ового софта вообще существуют правила хорошего тона, или каждое приложение «думает», что кроме него на машине больше ничего не запускается?


    1. mayorovp
      26.08.2019 16:49

      Это общая беда для любых ОС. В linux, на самом деле, всё куда лучше чем в альтернативах — потому что обычно всё-таки можно найти сбивальщика и отключить.


      1. usheynet
        28.08.2019 00:14

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


    1. Murimonai
      26.08.2019 16:57
      +1

      Если установленные приблуды работают не от рута — такой проблемы скорее всего не возникнет. Потому что почитать конфиг файл — максимум дозволенного, править или запускать — error: permission denied ?\_(?)_/?


    1. lorc
      26.08.2019 19:40

      Вообще правила хорошего тона есть. И мейнтейнеры дистрибутивов стараются за этим следить. Но как вы могли заметить, этот процесс запускался из /usr/local/bin. Что автоматически превращает проблему в локальную для конкретной машины. Да и вообще: софт, в исходниках которого есть закоментированный код — попахивает, скажем так.


    1. vitaly_il1
      27.08.2019 08:10

      ИМХО, это проблема последних 10 лет, когда появились всякие надстройки — networkd+NetworkManager+NetPlan, вместо systemV комбинация systemd+upstart и т.д.


      1. mayorovp
        27.08.2019 08:39

        Ну, если говорить о надстройках — то проблема всё-таки не в них, а в устаревшей документации.


        У того же networkd есть свои конфиги, лежащие в /etc/systemd/network — но если знать только про /etc/network/interfaces (или вообще только ifconfig), то поведение системы сразу же становится очень загадочным.


        1. vitaly_il1
          27.08.2019 08:52

          Если бы старую систему заменили на новую, это еще полбеды. Проблема что все живет вместе, в разных комбинациях, и надо разбираться что и когда из этого зоопарка активно в каждой дистро.
          Даже с десятком разных Юниксов двадцать лет назад было проще. Или моложе был :-)


  1. mikeus
    26.08.2019 19:18

    Не всяк админ полезет копаться с аудитом системных вызовов ядра — поучительно. Теперь же предусмотрительный, он должен пытаться настроить время на сервере только предварительно отключив всю периферию, все интерфейсы, и заглушив все сервисы в single user mode. Или для пущей верности — загрузившись в emergency mode и перемонтировав потом корень в rw.

    Не понятно только, как дальше будет жить автоматическая подстройка времени из systemd-timesyncd или chrony с такими соседствующими пакостниками.


  1. Kwisatz
    26.08.2019 19:52

    И тут вновь вместо того чтобы искать причину я начал пытаться придумать объяснение результата.

    А у меня ровно наоборот. Я теперь даже в квиз играть не способен. Ибо каждый раз, когда я пытался обращаться с некой системой или библиотекой так, как оно должно быть или кажется, что должно, возникали очень большие проблемы.

    Никогда не задавайте вопросы на форумах и общеспециализированных (а-ля stackoverflow) сайтах

    С определенного момента это становиться истиной почти для всего. Если проблема еще не описана есть очевидный для всех нюанс (дико бесит) либо на планете 2.5 человека, разбирающихся в предмете.


  1. puyol_dev2
    26.08.2019 21:21
    -4

    Ну что тут сказать… говнософт. Меня удивляют люди, которые чуть ли не обожествляют Линукс. Вы посмотрите сначала, кто пишет и как пишет в тех же исходниках. Нередко это просто тихий ужас, настоящий код made in India


    1. realimba
      26.08.2019 23:02
      -4

      по крайней мере у него есть шанс потихоньку стать нормальным, в отличии от гвн блобов от m$ и друзей..


    1. citius
      27.08.2019 12:07
      +1

      Причем тут вообще линукс?
      Есть гарантия, что этот же самый продукт, написанный этим же самым автором под винду вел бы себя иначе?

      Опыт общения с крутыми и дорогими софтверными продуктами вроде Cisco Unified Communications показывает, что там внутри зачастую гораздо более жуткий бардак и нагромождение дичайших костылей.


      1. puyol_dev2
        27.08.2019 13:55

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


        1. eumorozov
          28.08.2019 10:18

          Я люблю, потому что так же, как у автора в статье, всегда есть возможность докопаться в исходниках до первопричины и исправить. Пускай это требуется лишь раз в 10 лет, но все равно. На самом деле, чаще. Я хоть и не имею времени серьезно контрибьютить в open source, но на самом деле за год создаю как минимум пару пулл-реквестов на github к популярным проектам.


  1. Nokse
    26.08.2019 21:26

    simpleadmin спасибо за то, что поделились интересной информацией. Добавил статью в закладки.

    <оффтопик> вот кто-бы мне помог разобраться с двумя интересными вещами, с которыми я так и не управился…
    1. Не синхронизируется время в Вин 10 (LTSB). Ни в какую. Перекурил уже все возможные мануалы (которые либо бесполезны вообще, либо переписаны друг у друга и сводятся к одному), но время по прежнему не хочет синхронизироваться…
    2. На этой самой винде периодически самопроизвольно разлогинивается Скайп… И при каждом запуске просит залогиниться… На линуксе всё ок, на телефоне всё ок, и только на винде непонятная ерунда с недержанием сессии. Ничего внятного вообще не нашел…
    </оффтопик>


    1. Kwisatz
      26.08.2019 23:25
      +1

      Первое знакомо, бился сам с этим делом очень долго. Не смог победить вообще никак. Отрезал к чертям синхронизацию, поменял батарейку на маме и выставил часики.


    1. darthslider
      27.08.2019 10:20

      «Не хочет синхронизироваться» это что значит? Ошибка какая-то есть?
      Попробуйте перерегистрировать сервис:
      Net Stop W32time
      W32tm.exe /unregister
      W32tm.exe /register
      Net Start W32time


  1. Miiihus
    27.08.2019 10:11

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


    1. lex-tsy
      28.08.2019 13:17

      Для этого есть опция: «Не синхронизировать время с гипервизором»