任务越简单,我就越容易犯错误

任务越简单,我就越容易犯错误

这项琐碎的任务发生在一个星期五下午,本应花费 2-3 分钟的时间。 总的来说,一如既往。

一位同事要求我修复他服务器上的脚本。 我做了,递给他,无意中说道:“时间快了5分钟。” 让服务器自己处理同步。 半个小时,一个小时过去了,他依然气喘吁吁,小声咒骂。

“愚蠢的! — 我想,切换到服务器控制台 — 好吧,我再休息几分钟。”

ntp、rdate、sdwdate 未安装 时间同步 已禁用且未运行。

# 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

时间定为一瞬间,立刻又开始“奔腾”。

同时,在日志中,在进行此类手动更改时,我们仅看到系统报告时间已分别以正确/错误的方向更改,以及偶尔更改 重新同步 来自 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

重新同步 消失了,否则日志是原始的。

检查结论 转储 在所有接口的端口 123 上。 没有人提出要求,但时间仍在流逝。

错误二。 匆忙

距离工作周结束还剩一个小时,我不想带着一个没有解决的琐碎问题去周末(不要注意代码中的时间,文章是在接下来的几天里写的) )。
在这里,我不再寻找原因,而是开始尝试对结果做出解释。 我说“发明”是因为无论对结果的解释多么合乎逻辑,这都是解决问题的有缺陷的方法。

该服务器是流媒体服务器,并将 DVB-S2 流转换为 IP。 DVB-S 流包含时间戳,因此接收器、复用器、加扰器和电视经常使用它们来同步系统时钟。 DVB-S 板驱动程序内置于内核中,因此确保删除 DVB-S2 流的最快方法是断开来自“板”的电缆。 幸好服务器在墙后,也就这样吧。

当然,如果日志包含了应该存在的内容,这种情况就不会发生,但更多内容将在文章末尾再次介绍。

好吧,既然我们已经删除了所有卫星信号,我们也将删除地面信号 - 同时我们拔掉所有网络电缆。 服务器与外界隔绝,完全自主工作,但系统时钟仍然很匆忙。

工作周结束了,日期/时间问题本身并不重要,所以你可以回家了,但在这里我犯了一个新的错误。

错误三。 顾问

绝不! 如果问题的答案需要的不仅仅是研究谷歌的第一页和阅读一个手册页,那么永远不要在论坛和一般专业(la stackoverflow)网站上提问。

他们会把你送回谷歌,阅读同一个人并通俗地解释论坛/网站的规则,但不会给你答案。

以下是一些客观因素:

  • 除了你之外没有人能知道问题所在;
  • 没有人可以在与您相同的条件下进行测试

和主观:

  • 你可能不会为解决问题提供所有的投入,因为你已经提出了“正确”的方向,并且正在围绕它提出问题的本质;
  • 领班(主持人、老前辈、管理员)总是对的,如果领班错了……好吧,你知道……

如果在回复评论时,您仍然处于经过审查的词汇范围内,那么您就很紧张。

没有必要将任务分为简单和复杂。

我们不再依赖我们的经验、统计数据、顾问,并开始不“解释”最终结果,而是不断寻找原因。

既然有人设置了时间,那么必然会发生相应的系统调用。

正如在软件文档中最好的文档是来源一样,在系统管理中最好的助手是审计,在我们的例子中 审核.

一瞬间的疑惑我查了一下法力,但不完全确定Linux中的时间只能设置 时钟设置时间 и 设置时间,所以对于第一个测试,我选择了所有“合适”的调用:

# 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 -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

确保日志位置中没有我感兴趣的其他日志后 系统调用 除了这两个之外,我只进一步使用了它们。

运行系统调用审核 时钟设置时间 и 设置时间 并尝试更改日期:

# 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

在这里我们看到我们的 日期 而我们不知道 chkcache_进程。 它最终出现在上面的报告中,因为 aureport 在从二进制转换时按日期对输出进行排序,并且事件发生在我们设置的时间 日期-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 - 我们的寄生虫被发现了。 尽管其行为“恶意”,但无法拒绝条件接收系统,但我仍然想知道 欧司康,什么鬼?

很快就能找到答案 来源:

#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");
}

这里看起来多么可爱 注释掉了 线 警告...

来源: habr.com

添加评论