كلما كانت المهمة أبسط ، غالبًا ما أكون مخطئًا

صورة

نشأت هذه المهمة البسيطة في أحد أيام الجمعة وكان يجب أن تستغرق 2-3 دقائق. بشكل عام ، كما هو الحال دائما.

طلب مني أحد الزملاء إصلاح البرنامج النصي على خادمه. لقد فعل ذلك ، وسلّمه إليه وسقطه عن غير قصد: "الوقت في عجلة من أمره لمدة 5 دقائق". خادمه ، حتى لو كان يفهم التزامن. نصف ساعة ، مرت ساعة ، وهو ينفخ ويقسم بهدوء.

"الدمية! - لقد فكرت ، بالانتقال إلى وحدة التحكم بالخادم - حسنًا ، سوف أتوقف لبضع دقائق أخرى. "

نحن ننظر ، NTP ، rdate ، sdwdate لم يتم تثبيت ، تم تعطيل timyncd وليس قيد التشغيل.

# 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 

هنا ألاحظ على الفور أن وقت الجهاز صحيح: سيكون من الأسهل التنقل فيه.

من هنا بدأت سلسلة من الأخطاء.

الخطأ الأول. الثقة بالنفس


Klats-klats ...

 # 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 

ذهب resyncing وبقية سجلات البكر.

نتحقق من مخرجات tcpdump على المنفذ 123 على جميع الواجهات. لا توجد طلبات ، لكن الوقت ينفد أيضًا.

الخطأ الثاني. تسرع


هناك ساعة متبقية حتى نهاية أسبوع العمل ، لكنك لا ترغب في المغادرة لقضاء عطلة نهاية الأسبوع بمهمة سيئة (لا تنتبه إلى الوقت في الكود ، فقد كتبت المقالة في الأيام التالية).
وهنا مرة أخرى ، بدلاً من البحث عن سبب ، بدأت أحاول تقديم شرح للنتيجة. أنا أقول "ابتكار" ، لأنه بغض النظر عن مدى منطقية التفسيرات للنتيجة ، هذا هو نهج خاطئ لحل المشكلة.

هذا الخادم يتدفق ويحول دفق DVB-S2 إلى IP. هناك طوابع زمنية في دفق DVB-S ، لذلك غالبًا ما تستخدمها أجهزة الاستقبال ومضاعفات الإرسال وأجهزة التخليط وأجهزة التلفزيون لمزامنة ساعة النظام. يتم تجميع برامج تشغيل لوحات DVB-S في النواة ، وبالتالي فإن أسرع طريقة لضمان دفق DVB-S2 نظيف هي فصل الكابلات التي تأتي من "اللوحات". لحسن الحظ ، يكون الخادم وراء الحائط ، فليكن الأمر كذلك.

بالطبع ، إذا كان لدى السجلات ما يجب أن يكون هناك ، فلن يحدث هذا ، لكن المزيد حول هذا الموضوع ، مرة أخرى ، في نهاية المقالة.

حسنًا ، نظرًا لأننا حذفنا بالفعل جميع إشارات الأقمار الصناعية ، سنقوم أيضًا بإزالة الإشارات الأرضية - على طول الطريق الذي نسحب به جميع كبلات الشبكة. يصبح الخادم معزولًا عن العالم الخارجي ويعمل بشكل مستقل تمامًا ، لكن ساعة النظام لا تزال في عجلة من أمرنا.

لقد انتهى أسبوع العمل ، ولم يعد السؤال عن التاريخ / الوقت حرجًا ، لذا يمكنك العودة إلى المنزل ، لكنني ارتكبت خطأً جديدًا.

الخطأ الثالث. المستشارين


أبدا! لا تطرح أبدًا أسئلة على المنتديات والمواقع المتخصصة عمومًا (a la stackoverflow) إذا كانت الإجابة عليها تتطلب أكثر من دراسة إصدار الصفحة الأولى من Google وقراءة صفحة واحدة من man'a.

سيتم إعادتك إلى google وقراءة نفس الرجل وشرح قواعد المنتدى / الموقع بشكل شائع ، لكنك لن تقدم إجابة.

هناك كل من العوامل الموضوعية:

  • لا أحد إلا يمكنك معرفة المشكلة كذلك ؛
  • لا أحد يستطيع اختبار في نفس الظروف مثلك

وذاتي:
  • لا يجوز لك إعطاء جميع المدخلات لحل المشكلة ، لأنك توصلت بالفعل إلى الاتجاه "الصحيح" وحددت جوهر المشكلة من خلال التعويل عليها ؛
  • فورمان (المشرف ، الموقت القديم ، المشرف) يكون دائمًا على صواب إذا كان فورمان مخطئًا ... حسنًا ، أنت تعرف ...

إذا بقيت ردًا على التعليقات في إطار مفردات الرقابة ، عندها لديك أعصاب قوية.

قرار


لا حاجة لتقسيم المهام إلى بسيطة ومعقدة.

نتوقف عن الاعتماد على خبرتنا والإحصاءات والمستشارين ، ولا نبدأ في "توضيح" النتيجة النهائية ، ولكننا نبحث باستمرار عن السبب.

بمجرد قيام شخص ما بضبط الوقت ، يجب إجراء مكالمة نظام مناسبة.

كما هو الحال في توثيق البرامج ، فإن أفضل الموانئ هي المصادر ، لذلك في إدارة النظام ، أفضل مساعد هو التدقيق ، في تدقيقنا في حالتنا .

لحظة الشك
ركضت عبر الرجال ، لكنني لم أكن متأكدًا تمامًا من أنه لا يمكن ضبط الساعة في نظام 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 

بعد التأكد من أنه في أماكن السجلات التي تهمني ، لا توجد أنظمة أخرى غير هذين النوعين ، لقد استخدمتهما فقط.

نبدأ في مراجعة مكالمات النظام 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 

هنا نرى تاريخنا وغير معروف لنا chkcache_proces . اتضح أنه موجود في التقرير أعلاه ، نظرًا لأن aureport رتب المخرجات حسب التاريخ عند التحويل من العرض الثنائي ، وحدث الحدث في الوقت الذي حددنا فيه التاريخ "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"); } 

كم هو لطيف يبدو خط التحذير المعلق هنا ...

Source: https://habr.com/ru/post/ar464951/


All Articles