الجزء الأخير من مجموعة القصص من الإنترنت حول كيف يكون للبق أحيانًا مظاهر مذهلة تمامًا. الجزء الأول ، الجزء الثاني .
القليل من SSH الذي (في بعض الأحيان) لا يمكن
هذه قصة عن واحدة من أكثر عمليات صيد الحشرات إثارة التي كنت محظوظًا بما يكفي للمشاركة فيها.
في AdGear Technologies Inc. ، حيث عملت ، تم الاحتفاظ بكل شيء على SSH. لقد استخدمناه للإدارة والمراقبة والنشر وجمع السجلات ، حتى للبث المباشر. هذا البروتوكول قوي وموثوق ، ولديه إمكانية التنبؤ بأداة Unix الأصلية ، ويعمل فقط.
ولكن بمجرد أن أخبرتنا الرسائل دون أي وقت محدد أو مرجع مضيف أن البروتوكول لا يعمل.
نفذ الوقت
تعرضت الأجهزة الموجودة في مركز بيانات لندن الخاص بنا إلى أعطال عشوائية عند إرسال ملفات السجل إلى مركز بيانات مونتريال. تم تشغيل هذه المهمة بشكل دوري من Cron ، وتجلى الفشل على النحو التالي:
- أبلغت رسائل البريد الإلكتروني Cron عن مشاكل في SSH.
- في بعض الأحيان يتجمد.
- في بعض الأحيان يتم الخروج بدون خطأ المهلة.
- في فحص طبي داخلي ، يحذر Nagios من فقدان البيانات في مونتريال.
لقد سجلنا الدخول إلى سيارات لندن ، وأطلقنا الأمر يدويًا
pushوعمل بنجاح. قمنا بإصلاحها على أنها مشكلة مؤقتة في الشبكة.
المهلات
لكن الحوادث ظلت تتكرر بشكل عشوائي. مرة في اليوم ، عدة مرات في اليوم ، صباح الجمعة ، عدة مرات في الساعة. كان من الواضح أن الأمور كانت تسوء. واصلنا دفع الملفات يدويًا حتى اكتشفنا ماهية المشكلة.
كانت هناك 17 قفزة بين لندن ومونتريال. لقد أنشأنا تأخيرًا للحزمة وملف تعريف خسارة. اتضح أن 1-3٪ من الحزم قد ضاعت في بضع قفزات. بالاشتراك مع قسم العمليات في مركز بيانات لندن ، تقدمنا بطلب لإعادة التوجيه.
بينما كان سكان لندن يتحققون من معلومات فقدان الحزمة ، بدأنا في البحث عن مهلات عشوائية في الطريق من لندن إلى الثانيةمركز البيانات في مونتريال. كانت القفزات على هذا الطريق مختلفة ، وليست تلك التي فقدت الحزم. قررنا أن الخسارة لم تكن المشكلة الرئيسية ، وإلى جانب سكان لندن أفادوا أنهم لا يستطيعون إعادة إنتاج الحزم المفقودة أو المهلات ، وأن كل شيء بدا جيدًا من جانبهم.
نهاية العالم
أثناء إعادة توجيه رسائل البريد الإلكتروني السيئة من Cron يدويًا ، لاحظنا نمطًا مثيرًا للاهتمام. تم نقل الملفات إما بنجاح بسرعة عالية ، أو لم يتم نقلها على الإطلاق وتم تعليقها في الوقت المحدد. لم تكن هناك حالات تم فيها تنزيل الملفات بنجاح بسرعات منخفضة.
من خلال إزالة معظم البيانات من المعادلة ، تمكنا من إعادة إنشاء البرنامج النصي باستخدام Vanilla SSH البسيط. في مركز بيانات لندن ، أكمل خادم "SSH mtl-machine" المهمة على الفور أو تم تعليقه ولم يتمكن من إنشاء اتصال. بدأت المفاجأة في النمو.
أين ذهبت الحزم؟
فحصنا تكوين وأنظمة خادم SSH في مونتريال ثلاث مرات:
- استجابت خوادم DNS بسرعة.
- تم تعطيل منطقة البحث العكسي DNS.
- كان الحد الأقصى لعدد اتصالات العميل كبيرًا بدرجة كافية.
- لم نتعرض للهجوم.
- لم تكن القناة مسدودة.
بالإضافة إلى ذلك ، حتى إذا كان هناك شيء لا يعمل ، فسنلاحظ التجميد عند العمل مع مركزي بيانات مختلفين في مونتريال. علاوة على ذلك ، نجحت مراكز البيانات التابعة لنا خارج لندن في التواصل مع مونتريال. أي أن المشكلة كانت مرتبطة بلندن.
قمنا بتشغيل tcpdump وشاهدنا الحزم. كنا مهتمين بالديناميكيات العامة والبيانات التي تم الحصول عليها باستخدام Pcaps وتحميلها في Wireshark. لقد رأينا علامات على فقدان الحزمة وإعادة الإرسال ، ولكن كل شيء كان ضئيلاً ولم يكن مدعاة للقلق.
ثم قمنا بتحليل الاتصال بالكامل في المواقف التي تم فيها إنشاء اتصال SSH بنجاح ، ثم - الاتصالات في المواقف التي كان اتصال SSH فيها معلقًا.
عندما توقف الاتصال من لندن إلى مونتريال ، توصلنا إلى الاستنتاجات التالية:
- سارت عملية إنشاء اتصال TCP بشكل جيد
- تم إرسال معلومات خدمة SSH ذهابًا وإيابًا. عند الضرورة ، كانت هناك حزم TCP ack عادية.
- تم إرسال طرد محدد من لندن واستلامه في مونتريال.
- أعيد إرسال نفس الحزمة عدة مرات من لندن واستلمت في مونتريال.
- مونتريال ببساطة لا تجيب على هذا!
لم يكن من الواضح سبب عدم استجابة مونتريال (ولهذا السبب ، ترسل لندن البيانات مرة أخرى). تم تعليق الاتصال على هذا لأن بروتوكول الطبقة 4 كان معلقًا. الأمر الأكثر إثارة هو حقيقة أنك إذا قاطعت إرسال SSH المتكرر في لندن وأعدت تشغيله على الفور ، فسوف يعمل بنجاح. في هذه الحالة ، أشارت tcpdump إلى أن مونتريال استلمت الحزمة واستجابت لها ، واستمر العمل.
على عميل SSH في لندن ، قمنا بتمكين التصحيح المطول (
-vvv) ، وبعد إدخالات السجل هذه ، توقف الاتصال:
debug2: kex_parse_kexinit: first_kex_follows 0
debug2: kex_parse_kexinit: reserved 0
debug2: mac_setup: found hmac-md5
debug1: kex: server->client aes128-ctr hmac-md5 none
debug2: mac_setup: found hmac-md5
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP
لقد بحثنا في Google عن "SSH hang SSH2_MSG_KEX_DH_GEX_GROUP" وحصلنا على الكثير من النتائج ، من مشكلات Wi-Fi إلى أخطاء TCP في Windows وأجهزة التوجيه التي تجرها الدواب التي تفقد أجزاء TCP. كان أحد حلول LAN هو حساب MSS للمسار وتعيين هذه القيمة على أنها MTU في كلا طرفي المسار.
ظللت أخفض MTU على خادم لندن من 1500 - لم يساعد ذلك حتى وصلت إلى القيمة السحرية البالغة 576. بعد ذلك ، لم يتوقف SSH مرة أخرى. كنت أقوم بتشغيل برنامج نصي مع حلقة SSH ، وإذا رغبت في ذلك ، فقد أتسبب في انقضاء المهلات عن طريق إعادة MTU إلى 1500 ، أو التخلص منها من خلال ضبط 576. لسوء الحظ ، هذه خوادم إعلانات عامة ، ولن يحل تعيين MTU على الصعيد العالمي من 1500 مشكلة. ومع ذلك ، فقد سبق ذكره أعلاه أن عملية تجزئة أو إعادة تجميع الحزم ربما تكون معطلة في مكان ما.
دعنا نعود لفحص الحزم المستلمة باستخدام tcpdump: لم تكن هناك علامات تجزئة. حجم الحزمة المستلمة يتوافق تمامًا مع حجم الحزمة المرسلة. إذا أدى شيء ما إلى تجزئة الحزمة على البايت 576+ ، فهذا يعني أن شيئًا ما كان يعيد تجميعها بنجاح.
وميض وميض ، نجمة منحنى
عندما تعمقت في التحليل ، نظرت إلى تفريغ الحزم الكامل (
tcpdump -s 0 -X) ، وليس فقط العناوين. عند مقارنة الحزمة السحرية من الإرسال الناجح مع الحزمة من الإرسال الفاشل ، لم أجد أي فرق تقريبًا ، باستثناء رؤوس TCP / IP. ولكن كان من الواضح أن هذه كانت الحزمة الأولى في اتصال TCP التي تحتوي على بيانات كافية لتجاوز علامة 576 بايت. كانت جميع الحزم السابقة أصغر بكثير.
بمقارنة نفس الحزمة من الإرسالية الفاشلة ، بالشكل الذي غادرت به لندن ووصلت إلى مونتريال ، لفت انتباهي شيئًا ما. لشيء خفي ، ولوح به بسبب التعب (كان ذلك في وقت متأخر من مساء الجمعة). لكن بعد عدة تحديثات ومقارنات ، لم أعد أتخيل.
هذا ما بدت عليه الحزمة بعد مغادرة لندن (مطروحًا منها البايتات القليلة الأولى التي تحدد عناوين IP)
0x0040: 0b7c aecc 1774 b770 ad92 0000 00b7 6563 .|...t.p......ec
0x0050: 6468 2d73 6861 322d 6e69 7374 7032 3536 dh-sha2-nistp256
0x0060: 2c65 6364 682d 7368 6132 2d6e 6973 7470 ,ecdh-sha2-nistp
0x0070: 3338 342c 6563 6468 2d73 6861 322d 6e69 384,ecdh-sha2-ni
0x0080: 7374 7035 3231 2c64 6966 6669 652d 6865 stp521,diffie-he
0x0090: 6c6c 6d61 6e2d 6772 6f75 702d 6578 6368 llman-group-exch
0x00a0: 616e 6765 2d73 6861 3235 362c 6469 6666 ange-sha256,diff
0x00b0: 6965 2d68 656c 6c6d 616e 2d67 726f 7570 ie-hellman-group
0x00c0: 2d65 7863 6861 6e67 652d 7368 6131 2c64 -exchange-sha1,d
0x00d0: 6966 6669 652d 6865 6c6c 6d61 6e2d 6772 iffie-hellman-gr
0x00e0: 6f75 7031 342d 7368 6131 2c64 6966 6669 oup14-sha1,diffi
0x00f0: 652d 6865 6c6c 6d61 6e2d 6772 6f75 7031 e-hellman-group1
0x0100: 2d73 6861 3100 0000 2373 7368 2d72 7361 -sha1...#SSH-rsa
0x0110: 2c73 7368 2d64 7373 2c65 6364 7361 2d73 ,SSH-dss,ecdsa-s
0x0120: 6861 322d 6e69 7374 7032 3536 0000 009d ha2-nistp256....
0x0130: 6165 7331 3238 2d63 7472 2c61 6573 3139 aes128-ctr,aes19
0x0140: 322d 6374 722c 6165 7332 3536 2d63 7472 2-ctr,aes256-ctr
0x0150: 2c61 7263 666f 7572 3235 362c 6172 6366 ,arcfour256,arcf
0x0160: 6f75 7231 3238 2c61 6573 3132 382d 6362 our128,aes128-cb
0x0170: 632c 3364 6573 2d63 6263 2c62 6c6f 7766 c,3des-cbc,blowf
0x0180: 6973 682d 6362 632c 6361 7374 3132 382d ish-cbc,cast128-
0x0190: 6362 632c 6165 7331 3932 2d63 6263 2c61 cbc,aes192-cbc,a
0x01a0: 6573 3235 362d 6362 632c 6172 6366 6f75 es256-cbc,arcfou
0x01b0: 722c 7269 6a6e 6461 656c 2d63 6263 406c r,rijndael-cbc@l
0x01c0: 7973 6174 6f72 2e6c 6975 2e73 6500 0000 ysator.liu.se...
0x01d0: 9d61 6573 3132 382d 6374 722c 6165 7331 .aes128-ctr,aes1
0x01e0: 3932 2d63 7472 2c61 6573 3235 362d 6374 92-ctr,aes256-ct
0x01f0: 722c 6172 6366 6f75 7232 3536 2c61 7263 r,arcfour256,arc
0x0200: 666f 7572 3132 382c 6165 7331 3238 2d63 four128,aes128-c
0x0210: 6263 2c33 6465 732d 6362 632c 626c 6f77 bc,3des-cbc,blow
0x0220: 6669 7368 2d63 6263 2c63 6173 7431 3238 fish-cbc,cast128
0x0230: 2d63 6263 2c61 6573 3139 322d 6362 632c -cbc,aes192-cbc,
0x0240: 6165 7332 3536 2d63 6263 2c61 7263 666f aes256-cbc,arcfo
0x0250: 7572 2c72 696a 6e64 6165 6c2d 6362 6340 ur,rijndael-cbc@
0x0260: 6c79 7361 746f 722e 6c69 752e 7365 0000 lysator.liu.se..
0x0270: 00a7 686d 6163 2d6d 6435 2c68 6d61 632d ..hmac-md5,hmac-
0x0280: 7368 6131 2c75 6d61 632d 3634 406f 7065 sha1,umac-64@ope
0x0290: 6e73 7368 2e63 6f6d 2c68 6d61 632d 7368 nSSH.com,hmac-sh
0x02a0: 6132 2d32 3536 2c68 6d61 632d 7368 6132 a2-256,hmac-sha2
0x02b0: 2d32 3536 2d39 362c 686d 6163 2d73 6861 -256-96,hmac-sha
0x02c0: 322d 3531 322c 686d 6163 2d73 6861 322d 2-512,hmac-sha2-
0x02d0: 3531 322d 3936 2c68 6d61 632d 7269 7065 512-96,hmac-ripe
0x02e0: 6d64 3136 302c 686d 6163 2d72 6970 656d md160,hmac-ripem
0x02f0: 6431 3630 406f 7065 6e73 7368 2e63 6f6d d160@openSSH.com
0x0300: 2c68 6d61 632d 7368 6131 2d39 362c 686d ,hmac-sha1-96,hm
0x0310: 6163 2d6d 6435 2d39 3600 0000 a768 6d61 ac-md5-96....hma
0x0320: 632d 6d64 352c 686d 6163 2d73 6861 312c c-md5,hmac-sha1,
0x0330: 756d 6163 2d36 3440 6f70 656e 7373 682e umac-64@openSSH.
0x0340: 636f 6d2c 686d 6163 2d73 6861 322d 3235 com,hmac-sha2-25
0x0350: 362c 686d 6163 2d73 6861 322d 3235 362d 6,hmac-sha2-256-
0x0360: 3936 2c68 6d61 632d 7368 6132 2d35 3132 96,hmac-sha2-512
0x0370: 2c68 6d61 632d 7368 6132 2d35 3132 2d39 ,hmac-sha2-512-9
0x0380: 362c 686d 6163 2d72 6970 656d 6431 3630 6,hmac-ripemd160
0x0390: 2c68 6d61 632d 7269 7065 6d64 3136 3040 ,hmac-ripemd160@
0x03a0: 6f70 656e 7373 682e 636f 6d2c 686d 6163 openSSH.com,hmac
0x03b0: 2d73 6861 312d 3936 2c68 6d61 632d 6d64 -sha1-96,hmac-md
0x03c0: 352d 3936 0000 0015 6e6f 6e65 2c7a 6c69 5-96....none,zli
0x03d0: 6240 6f70 656e 7373 682e 636f 6d00 0000 b@openSSH.com...
0x03e0: 156e 6f6e 652c 7a6c 6962 406f 7065 6e73 .none,zlib@opens
0x03f0: 7368 2e63 6f6d 0000 0000 0000 0000 0000 sh.com..........
0x0400: 0000 0000 0000 0000 0000 0000 ............
وهذا ما بدت عليه نفس الحزمة عندما وصلت إلى مونتريال
0x0040: 0b7c aecc 1774 b770 ad92 0000 00b7 6563 .|...t.p......ec
0x0050: 6468 2d73 6861 322d 6e69 7374 7032 3536 dh-sha2-nistp256
0x0060: 2c65 6364 682d 7368 6132 2d6e 6973 7470 ,ecdh-sha2-nistp
0x0070: 3338 342c 6563 6468 2d73 6861 322d 6e69 384,ecdh-sha2-ni
0x0080: 7374 7035 3231 2c64 6966 6669 652d 6865 stp521,diffie-he
0x0090: 6c6c 6d61 6e2d 6772 6f75 702d 6578 6368 llman-group-exch
0x00a0: 616e 6765 2d73 6861 3235 362c 6469 6666 ange-sha256,diff
0x00b0: 6965 2d68 656c 6c6d 616e 2d67 726f 7570 ie-hellman-group
0x00c0: 2d65 7863 6861 6e67 652d 7368 6131 2c64 -exchange-sha1,d
0x00d0: 6966 6669 652d 6865 6c6c 6d61 6e2d 6772 iffie-hellman-gr
0x00e0: 6f75 7031 342d 7368 6131 2c64 6966 6669 oup14-sha1,diffi
0x00f0: 652d 6865 6c6c 6d61 6e2d 6772 6f75 7031 e-hellman-group1
0x0100: 2d73 6861 3100 0000 2373 7368 2d72 7361 -sha1...#SSH-rsa
0x0110: 2c73 7368 2d64 7373 2c65 6364 7361 2d73 ,SSH-dss,ecdsa-s
0x0120: 6861 322d 6e69 7374 7032 3536 0000 009d ha2-nistp256....
0x0130: 6165 7331 3238 2d63 7472 2c61 6573 3139 aes128-ctr,aes19
0x0140: 322d 6374 722c 6165 7332 3536 2d63 7472 2-ctr,aes256-ctr
0x0150: 2c61 7263 666f 7572 3235 362c 6172 6366 ,arcfour256,arcf
0x0160: 6f75 7231 3238 2c61 6573 3132 382d 6362 our128,aes128-cb
0x0170: 632c 3364 6573 2d63 6263 2c62 6c6f 7766 c,3des-cbc,blowf
0x0180: 6973 682d 6362 632c 6361 7374 3132 382d ish-cbc,cast128-
0x0190: 6362 632c 6165 7331 3932 2d63 6263 2c61 cbc,aes192-cbc,a
0x01a0: 6573 3235 362d 6362 632c 6172 6366 6f75 es256-cbc,arcfou
0x01b0: 722c 7269 6a6e 6461 656c 2d63 6263 406c r,rijndael-cbc@l
0x01c0: 7973 6174 6f72 2e6c 6975 2e73 6500 0000 ysator.liu.se...
0x01d0: 9d61 6573 3132 382d 6374 722c 6165 7331 .aes128-ctr,aes1
0x01e0: 3932 2d63 7472 2c61 6573 3235 362d 6374 92-ctr,aes256-ct
0x01f0: 722c 6172 6366 6f75 7232 3536 2c61 7263 r,arcfour256,arc
0x0200: 666f 7572 3132 382c 6165 7331 3238 2d63 four128,aes128-c
0x0210: 6263 2c33 6465 732d 6362 632c 626c 6f77 bc,3des-cbc,blow
0x0220: 6669 7368 2d63 6263 2c63 6173 7431 3238 fish-cbc,cast128
0x0230: 2d63 6263 2c61 6573 3139 322d 6362 632c -cbc,aes192-cbc,
0x0240: 6165 7332 3536 2d63 6263 2c61 7263 666f aes256-cbc,arcfo
0x0250: 7572 2c72 696a 6e64 6165 6c2d 6362 7340 ur,rijndael-cbs@
0x0260: 6c79 7361 746f 722e 6c69 752e 7365 1000 lysator.liu.se..
0x0270: 00a7 686d 6163 2d6d 6435 2c68 6d61 732d ..hmac-md5,hmas-
0x0280: 7368 6131 2c75 6d61 632d 3634 406f 7065 sha1,umac-64@ope
0x0290: 6e73 7368 2e63 6f6d 2c68 6d61 632d 7368 nSSH.com,hmac-sh
0x02a0: 6132 2d32 3536 2c68 6d61 632d 7368 7132 a2-256,hmac-shq2
0x02b0: 2d32 3536 2d39 362c 686d 6163 2d73 7861 -256-96,hmac-sxa
0x02c0: 322d 3531 322c 686d 6163 2d73 6861 322d 2-512,hmac-sha2-
0x02d0: 3531 322d 3936 2c68 6d61 632d 7269 7065 512-96,hmac-ripe
0x02e0: 6d64 3136 302c 686d 6163 2d72 6970 756d md160,hmac-ripum
0x02f0: 6431 3630 406f 7065 6e73 7368 2e63 7f6d d160@openSSH.c.m
0x0300: 2c68 6d61 632d 7368 6131 2d39 362c 786d ,hmac-sha1-96,xm
0x0310: 6163 2d6d 6435 2d39 3600 0000 a768 7d61 ac-md5-96....h}a
0x0320: 632d 6d64 352c 686d 6163 2d73 6861 312c c-md5,hmac-sha1,
0x0330: 756d 6163 2d36 3440 6f70 656e 7373 782e umac-64@openssx.
0x0340: 636f 6d2c 686d 6163 2d73 6861 322d 3235 com,hmac-sha2-25
0x0350: 362c 686d 6163 2d73 6861 322d 3235 362d 6,hmac-sha2-256-
0x0360: 3936 2c68 6d61 632d 7368 6132 2d35 3132 96,hmac-sha2-512
0x0370: 2c68 6d61 632d 7368 6132 2d35 3132 3d39 ,hmac-sha2-512=9
0x0380: 362c 686d 6163 2d72 6970 656d 6431 3630 6,hmac-ripemd160
0x0390: 2c68 6d61 632d 7269 7065 6d64 3136 3040 ,hmac-ripemd160@
0x03a0: 6f70 656e 7373 682e 636f 6d2c 686d 7163 openSSH.com,hmqc
0x03b0: 2d73 6861 312d 3936 2c68 6d61 632d 7d64 -sha1-96,hmac-}d
0x03c0: 352d 3936 0000 0015 6e6f 6e65 2c7a 7c69 5-96....none,z|i
0x03d0: 6240 6f70 656e 7373 682e 636f 6d00 0000 b@openSSH.com...
0x03e0: 156e 6f6e 652c 7a6c 6962 406f 7065 6e73 .none,zlib@opens
0x03f0: 7368 2e63 6f6d 0000 0000 0000 0000 0000 sh.com..........
0x0400: 0000 0000 0000 0000 0000 0000 ............
هل لاحظت أي شيء؟ إذا لم يكن كذلك ، فلا بأس بذلك. يمكنك النسخ في نافذتين في محرر نصوص والتبديل بينهما سريعًا لمشاهدة تغييرات الرمز.
حسنا حسنا. هذا ليس فقدان الحزم ، ولكن تلف الحزم! ضرر ضئيل للغاية يمكن التنبؤ به. ملاحظات مثيرة للاهتمام:
- الجزء الأولي من الحزمة (<576 بايت) سليم.
- كل 15 بايت من أصل 16 تالف.
- الضرر متوقع. كل
hأصبحxكلcأصبحs.
ربما تكون قد استشرت بالفعل جدول ASCII وخلصت إلى أن بت واحد عالق في القيمة
1. التحول إلى 1البتة الرابعة في البايت يفسد الحروف السابقة على اليسار إلى القيم الموجودة على اليمين.
الجناة الواضحون في مجال رؤيتنا (الخوادم التي تقبل بطاقات NIC) لا يرقى إليهم الشك لأن الفشل له نمط (عدة أجهزة لندن - عدة مراكز بيانات وآلات في مونتريال). يجب أن يكون السبب على الطريق وأقرب إلى لندن.
بدأ الوضع منطقيًا. لقد لاحظت أيضًا تلميحًا بسيطًا في وضع tcpdump المطول (
tcp cksum bad) ، وهو ما لم ألاحظه من قبل. أسقط خادم مونتريال حزمة على مستوى النواة عندما أدرك أنها تالفة ولم يقم بإعادة توجيه الحزمة إلى برنامج SSH الخفي في مساحة المستخدم. ثم أرسلت لندن الحزمة مرة أخرى ، فتضررت مرة أخرى ، وتجاهلتها مونتريال بصمت. من وجهة نظر SSH و SSHd ، توقف الاتصال. من وجهة نظر tcpdump ، لم تكن هناك خسارة وتتجاهل خوادم مونتريال البيانات ببساطة.
أبلغنا النتائج التي توصلنا إليها إلى قسم عمليات مركز بيانات لندن ، وفي غضون دقائق ، قاموا بتغيير طرق المغادرة بشكل كبير. كانت القفزة الأولى ومعظم القفزات اللاحقة مختلفة. لقد ولت مشكلة التجميد.
الإصلاحات في وقت متأخر من ليلة الجمعة رائعة ، لأنه في عطلات نهاية الأسبوع يمكنك الاسترخاء وعدم التفكير في المشاكل والدعم :)
اين والي؟
سعيد لأننا لم نعد نعاني من هذه المشكلة وأن أنظمتنا كانت تلحق بالركب ، قررت العثور على الجهاز المسؤول عن تلف الحزمة.
تحديث طرق لندن لإبقاء حركة المرور بعيدة عن الطريق القديم يعني أنه لا يمكنني بسهولة إعادة إظهار المشكلة. لقد وجدت صديقًا في مونتريال لديه آلة FreeBSD المناسبة التي كانت متوفرة من لندن عبر الطرق القديمة.
أردت التأكد من أن الضرر كان متوقعًا حتى بدون تدخل SSH. تمكنت من ذلك بسهولة مع عدد قليل من خطوط الأنابيب.
في مونتريال:
nc -l -p 4000 > /dev/null
ثم في لندن:
cat /dev/zero | nc mtl 4000
نظرًا لعامل العشوائية والتعديل في دورة إعادة المحاولة ، تلقيت العديد من الحزم التي بددت أي شكوك حول الاستنتاجات السابقة. هذا جزء من إحدى الحزم:
لقد أرسلنا للتو حزمة من الأصفار
0x0210 .....
0x0220 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0230 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0240 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0250 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0260 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0270 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0280 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0290 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02a0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02b0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02c0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02d0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02e0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02f0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0300 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0310 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0320 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0330 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0340 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0350 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0360 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0370 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0380 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0390 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x03a0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x03b0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x03c0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x03d0 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x03e0 .....
إعادة إنتاج الخطأ ، كنت بحاجة إلى العثور على إحدى القفزات السبعة عشر التي حدث بها الضرر. لم أستطع الاتصال بموفري جميع المجموعات واطلب منهم التحقق من أنظمتهم.
قررت إجراء اختبار ping لكل جهاز توجيه بشكل تسلسلي ، فقد يساعد ذلك. كتب حزم ICMP خاصة كبيرة بما يكفي لتتجاوز الحد الآمن البالغ 576 بايت وملأها بالأصفار. ثم بمساعدة هذه الحزم ، قمت بإجراء اختبار على خادم مونتريال من لندن.
عادت الطرود سليمة.
لقد جربت كل مجموعة من السرعة والمحتوى والحجم - ولكن دون جدوى. لم أجد أي ضرر في حزم ping التي تم إرجاعها لـ ICMP.
في خطوط أنابيب netcat ، قمت باستبدال TCP بـ UDP. مرة أخرى ، لا ضرر.
لقد احتاج إلى TCP لإعادة إنتاج الضرر ، وكان TCP بحاجة إلى نقطتي نهاية متصلين. حاولت دون جدوى معرفة ما إذا كانت جميع أجهزة التوجيه بها منفذ TCP مفتوح يمكنني الاتصال به مباشرة.
بدا من المستحيل تحديد القفزة الخاطئة من الخارج. أم أنه ممكن؟
مرآة، مرآة على الحائط
لتحديد ما إذا كان الضرر قد حدث أم لا ، يجب استخدام أحد السيناريوهات التالية:
- تحقق من الحزمة في الوجهة عبر عقدة TCP التي تتصل بها.
- ليس في مساحة المستخدم ، حيث لن يتم تسليم الحزمة في حالة حدوث خطأ أثناء التحقق من المجموع الاختباري ، ولكن تحقق من الحزمة المستلمة بحثًا عن التلف باستخدام الجذر و tcpdump.
- باستخدام عقدة TCP التي تعمل كخادم صدى وتعكس البيانات المستلمة مرة أخرى ، تحقق من الحزمة على عقدة الإرسال.
اتضح فجأة أن نقطة قياس ثانية متاحة لنا. غير متوفر بشكل مباشر ، ولكن لا يزال: في النهج الأول لحل المشكلة ، لاحظنا أن عملاء SSH يتعطلون عند الاتصال بخوادم SSH من خلال قفزة ضارة. هذه إشارة سلبية جيدة يمكن استخدامها بدلاً من إشارة "الصدى" النشطة.
وفي هذا يمكن مساعدتنا من خلال العديد من خوادم SSH المفتوحة على الإنترنت.
لا نحتاج إلى حسابات جارية على هذه الخوادم ، نحتاج فقط إلى بدء اتصال SSH ، ومعرفة ما إذا كانت مرحلة تبادل الشفرات ستنجح (مع عدد معقول من عمليات إعادة المحاولة لمراعاة الضرر العرضي).
كانت الخطة كما يلي:
- استخدم أداة nmap الرائعة في وضع "IP العشوائي" لتجميع قائمة بخوادم SSH المفتوحة الموزعة جغرافيًا.
- :
- , → .
- N- → «».
- telltale N- → «».
- «» «».
فكرت على هذا النحو: في آثار جميع الخوادم "السيئة" ، سيتم استخدام عدة قفزات متطابقة. سنكون قادرين على تحديد القفزات المشبوهة وتحديد تلك التي تستخدم في تتبع الخوادم "الجيدة". على أمل أن يبقى واحد أو اثنان.
بعد قضاء ساعة في تصنيف الخوادم يدويًا ، توقفت عن استكشاف البيانات. كان لدي 16 خادمًا "سيئًا" و 25 خادمًا "جيدًا".
كانت الخطوة الأولى هي عمل قائمة بالقفزات الموجودة في جميع آثار الخوادم السيئة. بعد تنظيف القائمة ، أدركت أنني لست بحاجة للذهاب إلى قائمة "الجيدة" لإزالة القفزات الإيجابية الخاطئة. كان لدى الأشرار قفزة واحدة مشتركة.
ومع ذلك ، كان هناك مزودان قبل ذلك: London → N hops upstream1 → Y hops upstream2.
كانت هذه أول قفزات Y في المنبع 2 ، مباشرة على الحدود بين upstream1 و upstream2. لقد أتلف حزم TCP العشوائية ، مما أدى إلى العديد من عمليات إعادة الإرسال ، واعتمادًا على خصوصيات تبادل بيانات البروتوكول ، يتجمد أو يقلل أحجام الإرسال.
بالتعاون مع قسم عمليات مركز بيانات لندن ، قمنا بتتبع عنوان IP لهذه القفزة. كنت آمل أنه من خلال اتصالهم المباشر بـ upstream1 سيكون من الممكن فرض التصحيحات.
من خلال upstream1 ، تلقيت تأكيدًا بأن القفزة التي حددتها (الأولى في upstream2) بها "عطل في وحدة التحكم" الداخلية كان يؤثر على BGP والتوجيه بين الشبكتين الداخليتين. قاموا بإعادة توجيه الجهاز المعيب وأوقفوا استبداله المعلق.
مرشح موسيقى الروك
لقد ساعدت مستخدمًا لتطبيق دفق الصوت في إعداد تجربة LAN. لعب المستخدم الموسيقى الكلاسيكية فقط ، وليس موسيقى الروك. بجدية. تم بث الكلاسيكيات بسلاسة ، وعند محاولة بث موسيقى الروك ، انقطع الاتصال بعد بضع دقائق.
تلقى التطبيق أجزاء من الصوت وضغطها باستخدام برنامج ترميز ضغط بدون فقد ، ثم أرسل كل جزء في حزمة UDP منفصلة إلى نقطة النهاية. كلما كان ذلك ممكنًا ، حاول التطبيق استخدام IPv6 ، لأنه كان أكثر موثوقية من بيئة LAN ، على الرغم من أنه يمكن أن يعمل عبر IPv4 إذا لزم الأمر.
بعد بحث لا نهاية له وشاق عن سبب المشكلة ، اكتشفت أخيرًا ما كان الأمر. بطريقة ما ، قام المستخدم بتعيين MTU إلى 1200 بايت في واجهة الشبكة. ولن يقوم IPv6 تلقائيًا بتجزئة الحزم على مستوى IP عندما تكون MTU أقل من 1280 بايت ، لذلك لا يمكن ببساطة إرسال الحزم الأكبر. سيحاول تطبيق البث إرسال حزم صوتية يزيد حجمها عن 1200 بايت ، وسيتلقى خطأ ويفصل الاتصال.
لماذا حدث هذا فقط مع موسيقى الروك؟ انه سهل. تستخدم برامج الترميز بدون فقد معدل بت متغير ، ويتم ضغط الموسيقى الكلاسيكية بشكل أفضل من موسيقى الروك. عند دفق الكلاسيكيات ، كان يتم ضغط الصوت باستمرار في حزم أقل من 1200 بايت ، وتجاوزت حزم موسيقى الروك هذه العتبة بشكل عشوائي.
لم يكن المستخدم يعرف سبب تخفيض MTU الخاص به ، ولم يكن في حاجة إليها ، لذلك قمنا بزيادة القيمة وعمل كل شيء بشكل جيد.
تعطيل الإنترنت الاختفاء الذاتي
عندما دخلت الجامعة عام 1999 ، كنت أعيش في عنبر طلابي قديم ومتهدم لأنني لم أستطع تحمل تكلفة أفضل. ولكن على الأقل كان هناك إنترنت لائق جدًا في النزل ، والذي لم يكن منتشرًا بعد في بلدي. وبما أنه كان ممنوعًا تغيير المبنى ، فقد تم فصل كابلات الشبكة (التي لا تزال متحدة المحور) وفقًا لمخطط مؤقت. تم إخفاؤهم خلف الأسقف المعلقة في الممرات وتم اقتحامهم عبر المداخل إلى الغرف حيث تم وضعهم على الأرض. أي انقطاع في الاتصال يمكن أن يؤدي إلى حقيقة أن الطابق بأكمله بقي بدون شبكة. منذ أن درست في كلية علوم الكمبيوتر ، تحولت بسرعة وبشكل لا إرادي إلى شخص على أرضيتي يقوم بإصلاح الانقطاعات المتكررة إلى حد ما ، على الرغم من عدم وجود خبرة في الشبكات على الإطلاق.
في بعض الأحيان كان الانقطاع من جانب المزود ، وفي بعض الأحيان كانت المشكلة متعلقة بالوكيل الخاص بنا ، ولكن في كثير من الأحيان قام شخص ما بفصل بعض الكابلات ولم يقم بإدخال فاصل فيه.
في إحدى الأمسيات ، انقطعت الإنترنت ، ولكن لبضع دقائق فقط. ثم عاد للظهور مرة أخرى ، لذلك لم أفكر كثيرًا في ذلك. لكن في اليوم التالي تكررت المقاطعة القصيرة وفي اليوم الثالث أيضًا. عادة ما يحدث ذلك حوالي 20 ساعة ، مع مرور الوقت المحدد ، وفي بعض الأحيان لم يكن الأمر كذلك على الإطلاق. ولكن في كل مرة تعطلت فيها الشبكة ، بدأ هاتفي في الموقع بالرنين ، وكان الناس ينزعجون بشكل متزايد من هذه الانقطاعات المتكررة.
نظرًا لأن كل انقطاع استمر بضع دقائق فقط ، لم أتمكن من تحديد موقع محدد قبل ظهور الشبكة مرة أخرى. حاولت أن أجري على الأرض وأطرق على جميع الأبواب ، وسألني عما إذا كان أحدهم قد سحب كابلًا أو فعل شيئًا به ، لكن الفكرة لم تساعد. أخيرًا قررت انتظار المقاطعة اليومية مع جهاز القياس المتعدد الموثوق به في يدي. في غضون أسبوع ، قمت بطرد غرفة تلو الأخرى من المشتبه بهم. أخيرًا ، في أحد كبلات الغرفة ، لاحظت ارتفاعًا في المقاومة أثناء الانقطاع التالي.
طرقت الباب لكنهم لم يفتحوه. كانت القلعة مقفلة. ولكن إذا لم يكن هناك أحد في الغرفة للقيام بشيء ما بالكمبيوتر أو الكابل ، فلماذا يتم قطع الاتصال؟ ولماذا تتعافى؟ في اليوم التالي حدث كل شيء مرة أخرى ، لم يفتحوا الباب مرة أخرى. قررت إغلاق هذه الغرفة تمامًا حتى يعمل الإنترنت على بقية الأرضية.
في صباح اليوم التالي ، أبلغني المستأجرون في تلك الغرفة أن الإنترنت الخاص بهم لا يعمل. ذهبت إليهم وقمت بقياس المقاومة في جميع الكابلات ، وفحصت جميع التوصيلات وأجهزة الإنهاء. جميع الكابلات لها صفر أوم ، كل شيء في حالة ممتازة. سألت الرجل ماذا كان يفعل الليلة الماضية؟ أجابني: قرأت الكتب المدرسية قبل الامتحانات ، لا شيء يتعلق بالحاسوب. أعدت فحص كل شيء للمرة الثانية والثالثة ، لكن لم أجد أي مشاكل. كدت أستسلم ، ثم لاحظت: تم تثبيت الكابل أسفل السرير. بالطبع ، تم كسر النواة النحاسية للكابل في هذا المكان تمامًا ، ولكن تم تثبيتها بإحكام بواسطة الغلاف بحيث يتم الحفاظ على الاتصال في ظل الظروف العادية حتى لو جلست على السرير. لكن عندما بدأت في تأرجحها ، اختفت جهة الاتصال لبضع ثوان مع كل دفعة.
يمكنك أن تخمن بنفسك ما حدث على هذا السرير لعدة دقائق كل مساء ، خلف باب مغلق ودون إجابة للطرق.
قصة ميل
المبرمجون الحقيقيون يكتبون بلغة فورتران
قد يكون هذا هو الحال الآن ، في عصر الجعة غير الكحولية والآلات الحاسبة والتطبيقات "سهلة الاستخدام" ، ولكن في الأيام الخوالي ، عندما بدا مصطلح "البرامج" مضحكا وصُنعت أجهزة الكمبيوتر الحقيقية من براميل مغناطيسية وأنابيب راديو ، كتب Real Programmers في كود الآلة. ليس في FORTRAN. ليس على RATFOR. ولا حتى لغة التجميع. في كود الجهاز. على أرقام سداسية عشرية حقيقية وغير مزخرفة وغير مفهومة. مثل هذا تماما. نشأت عدة أجيال من المبرمجين دون أن يعرفوا شيئًا عن هذا الماضي المجيد ، وأعتقد أنه يجب أن أحاول سد فجوة الأجيال والتحدث عن كيفية قيام مبرمج حقيقي بكتابة الكود. سأدعوه ميل لأن هذا كان اسمه.
قابلت ميل عندما حصلت على وظيفة في شركة Royal McBee Computer Corp. ، وهي شركة تابعة لمصنع آلة كاتبة انتهت صلاحيتها الآن. كانت الشركة تبني LGP-30 - كمبيوتر أسطوانة صغير ورخيص (وفقًا لمعايير اليوم) - وكانت قد بدأت للتو في إنتاج RPC-4000 ، أيضًا على ذاكرة الأسطوانة ، وقد تحسن كثيرًا وأكبر وأسرع. كانت النوى المغناطيسية باهظة الثمن ، ولم تستطع تحمل المنافسة (ولهذا لم تسمع عن هذه الشركة أو أجهزة الكمبيوتر الخاصة بها). تم تعييني لكتابة مترجم FORTRAN لهذه المعجزة الجديدة ، وكان Mel هو دليلي لقدراتها. رفض ميل المترجمين. وتساءل: "ما الفائدة من عدم قدرة البرنامج على إعادة كتابة الكود الخاص به؟" كتب ميل البرنامج الأكثر شعبية للشركة باللون السداسي.عملت في LGP-30 ولعبت لعبة البلاك جاك مع المشترين المحتملين في عروض الكمبيوتر. لطالما كان لها تأثير كبير. تم عرض كشك LGP-30 في كل معرض تجاري ، وتجمع مندوبي مبيعات IBM حولهم وتحدثوا مع بعضهم البعض. هل ساعدت في بيع أجهزة الكمبيوتر؟ لم نناقش هذه المسألة ابدا.
كانت مهمة ميل إعادة كتابة برنامج البلاك جاك لـ RPC-4000. (Porting؟ ما هو؟) كان للكمبيوتر الجديد مخطط عنونة واحد زائد واحد: بالإضافة إلى كود التشغيل وعنوان المعامل المطلوب ، كان لكل تعليمات آلة أيضًا عنوانًا ثانيًا ، والذي يوضح مكان كتابة التعليمات التالية على أسطوانة مغناطيسية دوارة ... هذا هو ، بعد كل تعليمات ذهب
GO TO! ضع هذا في أنبوب باسكال ودخنه.
أحب Mel RPC-4000 لأنه كان بإمكانه تحسين الكود الخاص به: ضع التعليمات على البكرة بحيث بمجرد اكتمال أحدهما ، يكون الثاني على الفور تحت "رأس القراءة" ويكون جاهزًا للتنفيذ الفوري. للقيام بذلك ، تمت كتابة برنامج يعمل على تحسين المجمّع ، لكن ميل رفض استخدامه. وأوضح "لا تعرف أبدًا أين ستضع البيانات ، لذلك عليك استخدام ثوابت منفصلة." لقد فهمت جوهر هذه العبارة في وقت لاحق. نظرًا لأن ميل كان يعرف القيم العددية لجميع رموز التشغيل وخصص عناوينه الخاصة في ذاكرة الأسطوانة ، يمكن اعتبار كل تعليمة يكتبها ثابتًا رقميًا. على سبيل المثال ، يمكنه تحديد تعليمة "إضافة" سابقة وضربها إذا كانت لها قيمة رقمية مناسبة. قلة قليلة من الناس يمكن أن تغير رمزها.لقد قارنت برامج Mel المُحسّنة يدويًا بنفس الكود الذي تمت معالجته بواسطة مُجمع التحسين ، ودائمًا ما يعمل كود Mel بشكل أسرع. الحقيقة هي أن أسلوب البناء الهيكلي لم يتم اختراعه بعد ، ولن يستخدمه مال على أي حال. أولاً ، كتب الأجزاء الداخلية من حلقات البرمجة الخاصة به بحيث كانوا أول من يحصل على العناوين المثلى على البكرة. ولم يكن المجمّع الأمثل قادرًا على ذلك. لم يكتب ميل قط حلقات متأخرة زمنيًا ، حتى عندما تطلب أداة Flexowriter الضخمة تأخيرًا بين مخرجات الشخصية. قام ميل ببساطة بوضع التعليمات على البكرة بحيث يتم تنفيذ التعليمات التالية عند الحاجة إلى قراءة التعليمات التاليةأن أسلوب العمارة من أعلى إلى أسفل لم يتم اختراعه بعد ، ولن يستخدمه ميل على أي حال. أولاً ، كتب الأجزاء الداخلية من حلقات البرمجة الخاصة به بحيث كانوا أول من يحصل على العناوين المثلى على البكرة. ولم يكن المجمّع الأمثل قادرًا على ذلك. لم يكتب ميل أبدًا حلقات متأخرة زمنيًا ، حتى عندما تطلب أداة Flexowriter الضخمة تأخيرًا بين مخرجات الشخصية. قام ميل ببساطة بوضع التعليمات على البكرة بحيث يتم تنفيذ التعليمات التالية عند الحاجة إلى قراءة التعليمات التاليةأن أسلوب العمارة من أعلى إلى أسفل لم يتم اختراعه بعد ، ولن يستخدمه ميل على أي حال. أولاً ، كتب الأجزاء الداخلية من حلقات البرمجة الخاصة به حتى يكونوا أول من يحصل على العناوين المثلى على البكرة. ولم يكن المجمّع الأمثل قادرًا على ذلك. لم يكتب ميل قط حلقات متأخرة زمنيًا ، حتى عندما تطلب أداة Flexowriter الضخمة تأخيرًا بين مخرجات الشخصية. قام ميل ببساطة بوضع التعليمات على البكرة بحيث يتم تنفيذ التعليمات التالية عند الحاجة إلى قراءة التعليمات التاليةحتى عندما تتطلب أداة Flexowriter الضخمة تأخيرًا بين مخرجات الأحرف. قام ميل ببساطة بوضع التعليمات على البكرة بحيث يتم تنفيذ التعليمات التالية عند الحاجة إلى قراءة التعليمات التاليةحتى عندما تتطلب أداة Flexowriter الضخمة تأخيرًا بين مخرجات الأحرف. قام ميل ببساطة بوضع التعليمات على البكرة بحيث يتم تنفيذ التعليمات التالية عند الحاجة إلى قراءة التعليمات التاليةبعد رأس القراءة ، وسيتعين على الطبل إجراء ثورة أخرى للعثور عليه. وجد ميل مصطلحًا لا يضاهى لهذا الإجراء. كلمة "الأمثل" (الأمثل) لها معنى مطلق ، بالإضافة إلى "فريد" ، لذلك في اللغة العامية كانت غالبًا ما تكون نسبية: "ليست مثالية تمامًا" أو "أقل مثالية" أو "ليست مثالية للغاية". وصف ميل الأماكن الموجودة على الأسطوانة ذات أطول فترة تأخير بأنها "الأكثر تشاؤمًا" ( أسوأ الظروف البيئية التي يتحملها الجسم ).
بعد الانتهاء من العمل على برنامج البلاك جاك وتشغيله (قال بفخر "حتى المُهيئ تم تحسينه") ، تلقى ميل طلبًا من قسم المبيعات لإجراء تغييرات. كان مولد الأرقام العشوائي الأنيق (المحسن) مسؤولاً عن خلط البطاقات والتعامل من سطح السفينة في البرنامج. واعتقد بعض مندوبي المبيعات أنه كان صريحًا للغاية ، لأن المشترين خسروا في بعض الأحيان. طلبوا من ميل تغيير البرنامج بحيث يمكن لمفتاح اللمس الموجود على وحدة التحكم تغيير احتمالات اللاعب والسماح للمشتري بالفوز. رفض ميل. لقد اعتبرها غير شريفة - كانت كذلك - وأنها تعدت على أخلاق المبرمج - كان الأمر كذلك - لذلك رفض المشاركة. تم إقناع ميل من قبل رئيس قسم المبيعات ، و Big Boss ، وزملائه المبرمجين بإصرار من الرئيس. أخيرًا استسلم ميل وكتب الشفرةولكن تحقق الغش في الاتجاه المعاكس: عندما تم تشغيل المفتاح ، غش البرنامج وفاز دائمًا. كان ميل سعيدًا بقراره. جادل بأن عقله الباطن أظهر أخلاقًا لا يمكن السيطرة عليها ورفض رفضًا قاطعًا تصحيح البرنامج. عندما غادر ميل الشركة للحصول على دخل أعلى ، طلب مني Big Boss إلقاء نظرة على الكود وإخباري ما إذا كان بإمكاني العثور على مدقق وتغيير طريقة عمله. وافقت على مضض.هل يمكنني العثور على وحدة التحقق وتغيير طريقة عملها. وافقت على مضض.هل يمكنني العثور على وحدة التحقق وتغيير طريقة عملها. وافقت على مضض.
كان التعامل مع كود ميل مغامرة حقيقية. غالبًا ما بدا لي أن البرمجة هي شكل فني لا يمكن تقدير قيمته الحقيقية إلا من قبل أولئك الذين يفهمون هذا الفن الغامض. يحتوي على جواهر حقيقية وحركات رائعة ، مخفية عن أنظار الإنسان وإعجاب بطبيعة العملية ذاتها ، أحيانًا إلى الأبد. يمكنك معرفة الكثير عن الشخص بمجرد قراءة الكود ، حتى السداسي العشري. أعتقد أن ميل كان عبقريًا غير معروف. ربما كانت الصدمة الأقوى هي الحلقة البريئة التي وجدتها ، والتي لم يكن فيها تحقق احتيالي. لا تحقق. لا .
فرض الفطرة السليمة أن تكون هذه حلقة مغلقة ، يدور فيها البرنامج ، إلى الأبد ، إلى ما لا نهاية. ومع ذلك ، فقد مر عنصر التحكم في البرنامج بنجاح من خلاله وخرج بأمان على الجانب الآخر. استغرق الأمر أسبوعين لمعرفة ذلك. تم تجهيز RPC-4000 بجهاز حديث - سجل فهرس. سمح لكتابة حلقات البرنامج ، والتي تم استخدام التعليمات المفهرسة بداخلها. في كل مرة تمر عبر الحلقة ، تمت إضافة رقم من السجل إلى عنوان التعليمات بحيث يشير إلى الموضع التالي في السلسلة. كل ما تبقى هو زيادة سجل الفهرس مع كل تمريرة. لم يستغل ميل هذا. بدلاً من ذلك ، قام بسحب التعليمات إلى سجل الجهاز ، وإضافة واحدة إلى عنوانها ، وحفظها مرة أخرى. ثم نفذت التعليمات المعدلة مباشرة من السجل.تمت كتابة الدورة مع مراعاة وقت التنفيذ الإضافي: بمجرد اكتمال التعليمات ، ظهرت الدورة التالية تحت رأس قراءة الأسطوانة. لكن لم يكن هناك تدقيق مارق في الحلقة. كان دليل الحفظ هو أنه تم تشغيل جزء صغير في سجل الفهرس - كان موجودًا في رمز الأمر بين العنوان ورمز التشغيل. ومع ذلك ، لم يستخدم ميل سجل الفهرس ، وتركه عند الصفر.
عندما جاء عيد الغطاس ، كدت أعمى. البيانات التي كان يعمل عليها بالقرب من المستويات العالية من الذاكرة - وهي أكبر العناوين التي يمكن أن تشير إليها التعليمات - رتبها ميل بحيث بعد معالجة الموضع الأخير ، قد تؤدي زيادة عنوان التعليمات إلى تجاوز. أثناء النقل ، تمت إضافة واحد إلى رمز التشغيل ، وتغييره إلى الكود التالي في المجموعة: تعليمات القفز. بالطبع ، هذه التعليمات التالية كانت موجودة في العنوان صفر ، وذهب البرنامج إلى هناك بسعادة. لم أتحدث إلى ميل ولا أعرف ما إذا كان قد استسلم في مواجهة فيضان التغيير الذي غمر البرمجة منذ ذلك الحين. أفضل أن أعتقد أنني لم أستسلم. لقد تأثرت جدًا لدرجة أنني توقفت عن البحث عن شيك غش وأخبرت Big Boss أنني لم أجده. لم يكن متفاجئا. عندما غادرت الشركةكان برنامج البلاك جاك لا يزال يغش إذا تم تشغيل المفتاح الصحيح ، وهذا صحيح ، على ما أعتقد. لم أحب اختراق كود مبرمج حقيقي.
قضية USB استثنائية
بعد تخرجي من الكلية مباشرة ، انضممت إلى شركة وعملت على جهاز المستهلك لمدة خمسة أشهر قبل أن يتم عرضه على الجمهور. كان الجهاز يعمل بنظام Linux. وبينما كنت معتادًا على فكرة التدليل في مساحة النواة ، كنت منجذبًا إلى اجتماع لتحديد أولويات الأخطاء. العديد من البق. مئات من البق. يقرأ كل منهم: "هذا مستحيل ، كيف حدث هذا؟"
صاحوا: "تلف الذاكرة!" فكرت ، "Hospadi ، أصلح الحشرات الخاصة بك." بالنظر إلى مقالب التصادم ، رأينا ... ما هذا؟ نفذ البرنامج التعليمات المحظورة عن طريق ربط السلسلتين باستخدام وظيفة من المكتبة القياسية. حسنًا ، غريب ... السجل التالي: لا يمكن إحضار صفحة من ملف ترحيل صفحات على جهاز ليس به مساحة ملف ترحيل صفحات مخصصة على الإطلاق (أعتقد أنني أفهم سبب عدم تمكننا من جلب صفحة!).
لقد كتبت مرة برنامج قصير. خصصت 80٪ من ذاكرة النظام لصفيف واحد وكتبت أعداد صحيحة متتالية لها. ثم انتظرت حتى يتم الضغط على Enter والتحقق منها لمعرفة ما إذا كانت محتويات المصفوفة قد تغيرت. الآن قمت بتنزيل هذا البرنامج ، وانتظرت 30 ثانية ثم قمت بإجراء الفحص. ليس هناك أى مشكلة. حاولت عدة مرات - ها ، كنت أعلم أنه لم يكن هناك تلف في الذاكرة! لقد قمت بسحب كابل التصحيح (USB) ، بعد 10 ثوانٍ قمت بإدخاله وسحبه بسرعة ، ثم أعد إدخاله. بام! 90 خطأ.
لك.
حسنًا ، سأضطر إلى العبث بمنفذ USB. إذن المشكلة مرتبطة به؟ لا يبدو أن برنامج تشغيل USB يطبق خوارزمية خرافية بت سحرية تلقي بشكل عشوائي أخطاء بت. ربما مشكلة في الجهاز؟ لا ، ليس معه ، لكن هذا لم يمنعنا من القيام بكل أنواع البذاءة باستخدام منفذ USB. لقد استدعوا المهندسين الذين تحولوا إلى منتج آخر منذ وقت طويل ، والآن كانوا في حيرة من أمرهم بشأن المشكلة. لا أتذكر مقدار الوقت الذي قضيناه في إثبات لأنفسنا أن الجهاز كان في حالة تامة وكاملة. كان التأريض بالترتيب ، والجهد ثابتًا ، وكانت الساعة تعمل بدقة ، وكانت خطوط DDR مثالية لدرجة أنك كنت ستبكي بسعادة عندما تراها.
أصبحت الأجهزة التي تم اختبارها من قبل المهندسين غير مستقرة بشكل متزايد. افترضت أن الجهاز يمكنه تحميل البيانات في الذاكرة ، والحصول على أخطاء بت ، ثم تفريغها مرة أخرى في ذاكرة فلاش ، وربما حتى في المكان الخطأ (غالبًا ما كان جدول الصفحات تالفًا ، لذلك يمكن افتراض أن هذا يحدث أيضًا مع هياكل تتبع الملفات يمكن كتابة المحتوى في أماكن خاطئة ، ويمكن أن تتعطل هياكل نظام الملفات ، وما إلى ذلك) بمرور الوقت ، تدهورت الأجهزة كثيرًا بحيث لم يعد بإمكانها التمهيد بشكل موثوق. أخيرًا ، قام أحد المهندسين بتعطيل وكتابة الصورة التي كانت على جهاز الكمبيوتر المحمول الخاص به. كانت هذه الصورة قديمة نسبيًا.
- يا صديق. إنه يتعلق بالبرنامج.
- ماذا؟!؟!؟! أؤكد لكم أننا لم نكتب قليلا الجنية!
لا: قام بتحميل تجميع قبل ثلاثة أشهر واختفت المشكلة. في تلك اللحظة ، شعرت بالمسؤولية عن إشراك مجموعة من الأشخاص في مشروع طويل جدًا ولا معنى له ، لذلك بقيت بين عشية وضحاها وأجريت بحثًا ثنائيًا من خلال جميع التصحيحات على مدار الأشهر الماضية (استغرق الأمر وقتًا أطول لدراسة التجميعات الكاملة لنظام التشغيل بأكمله مما أود ...).
إذن ما كانت تلك الرقعة السحرية؟ أضاف شخص ما برنامج تشغيل للرقاقة التي قمنا بتحليلها إلى النواة. هذه الشريحة لم تكن في الجهاز.
ها! وجدنا ساحرة! أحرقه!
أعلن الكثير أن المشكلة قد تم حلها. كانوا سعداء لأنه في الإصدار التالي يمكنهم التراجع عن التصحيح والمضي قدمًا. لقد قمنا بإعادتها إلى الوراء بإنتقاء شديد ، وقمنا بتجميع صورة ، واختبرناها ، وكان كل شيء على ما يرام. لم نتوقع ظهور نفس الخلل في النواة في غضون أيام قليلة.
انتظر. إذا لم تكن الشريحة على السبورة فكيف منعنا السائق؟ قمت بتشغيل lsmod ، لم يتم تحميل برنامج التشغيل ... "على أي حال ، ما الفرق ، احذف ملف الوحدة النمطية وأعد التحميل. Nifiga ، لا تزال المشكلة. هذا ليس طبيعيا ... "
الآن كنت وحدي وشاهدت الشيطان يحدث. بدأت في تحليل الرقعة بعناية. لقد كان ملفًا لطيفًا بحجم 10 كيلو سطر C قدمته الشركة المصنعة للرقاقة. سيكون من التنازل وصفه بكلمة "فوضى" (في الإنصاف ، أرسلوا لنا سائقًا أكثر تفكيرًا بعد بضعة أسابيع). بعد التنقيب قليلاً ، قررت أن السائق لم ينفذ لعبة bit-juggling-for-fun. إذن ما هو الاتفاق؟ 48 بايت من خمسة أسطر من التعليمات البرمجية. هيكل صغير في ملف التمهيد يوضح عنوان الناقل للبحث عن الشريحة. أزلت معظم السائق ، لكنني تركت هيكلًا مختلفًا فيه. استمرت المشكلة.
أيها الأولاد والبنات ، لدينا مشكلة محاذاة! بطريقة ما هذه البنية المكونة من 48 بايت تنقل شيئًا ما في الذاكرة وهذا يؤدي إلى حدوث أخطاء. اكتشفت أن المشكلة تحدث عندما تضع أي شيء أكبر من 32 وأقل من 64 بايت في ملف. لم تساعد هذه المعرفة كثيرًا ، لكنها على الأقل خلقت إحساسًا بالتقدم.
أنتج تجميع النواة ملف System.map أنيق. تم سردها حيث توجد جميع المتغيرات المجمعة في kernel في مساحة العنوان الافتراضية للنواة. اكتشفت أن هيكلي الصغير يقع في منتصف قسم ". البيانات". هذا القسم مليء بالمتغيرات التي تمت تهيئتها ، بحيث عندما يتم فك حزمة النواة الثنائية في الذاكرة ، ستكتب كل هذه المتغيرات من الصورة المجمعة. باستخدام System.map كمرجع ، قمت بتنفيذ بحث ثنائي أخرق. بالنسبة للجزء الأكبر ، بحثت في روابط ملفات C المختلفة. لقد وجدت متغيرًا للمقارنة به ؛ العثور على ملف kernel الذي يحتوي عليه ؛ ضع هيكلي السحري جنبًا إلى جنب في ملف عشوائي وبدأ في معرفة ما إذا كانت المشكلة قد عادت للظهور.
استمر البحث إلى آخر عناصر بيانات قليلة وعاد خالي الوفاض. لا توجد بيانات مطلوبة في الذاكرة بمتغيرات تمت تهيئتها. أثناء التمرير عبر ملف System.map ، رأيت أنني لم أهتم بقسم .bss بأكمله ، والذي يحتوي على متغيرات غير مهيأة. تعلمت من أخطاء الماضي ، وتحققت أولاً من البداية والنهاية. بالطبع ، المتغير غير المهيأ في بداية القسم نتج عنه أخطاء ، بينما المتغير في نهاية القسم لم يحدث. كان العثور على الجاني مسألة وقت فقط. المتغير الذي تسببت حركته في المشكلة كان ...
مؤشر الوظيفة؟!
كيف تعمل محاذاة مؤشر الوظيفة على تدمير نظامنا؟ في بنية ARM ، لا يمكنك قراءة الكلمات عند الوصول بدون محاذاة ، أي أنه يجب وضع كل متغير 32 بت في الذاكرة على عنوان مضاعف 4. مؤشر الوظيفة ليس استثناءً ، فهو يحصل دائمًا على الحد الأدنى من العنوان. اتضح أنه في وضع مشكلتنا ، كان العنوان مضاعفًا لـ 2 n ، أكبر من أو يساوي 64. أي قيمة أقل من هذه العتبة - واختفت المشكلة. كان هناك أيضًا ترتيب بمحاذاة المؤشر.
ليس هناك محاذاة جيدة. على الأقل ليس قبل حدوث هذا الخطأ.
الآن لم يكن مؤشر الوظيفة هذا مؤشر "الجد". كان يشير إلى شيء خاص. كانت هناك منطقة في المعالج SRAM يمكننا استخدامها للمهام ذات الصلة بالتحميل إذا لم نتمكن من استخدام ذاكرة الوصول العشوائي. لتوفير الطاقة أثناء الخمول ، قمنا بنسخ روتين فرعي في هذه المنطقة ، وقمنا بتعيين مؤشر خاص يشير إليه ، ثم أطلقنا عليه. ماذا كان يفعل الروتين الفرعي؟ دعونا نلقي نظرة على المجمع. أنا لست خبيرًا في مجمع ARM ، لكن التعليقات كانت بليغة تمامًا.
// ...
...
// LPDDR
ماذا تفعل؟! لقد انتقلت بسرعة من عمليات التسجيل الأساسية إلى تعطيل وحدة التحكم في الذاكرة. لقد أرسلت بريدًا إلكترونيًا إلى الشركة المصنعة التي كتبت الإجراء الفرعي وسألت عما إذا كان هناك شيء مفقود.
بعد ثلاثة أيام ، تلقيت إجابة بأسلوب "أوه نعم ، يجب أن يكون هناك حاجز للذاكرة". اتضح أنه نظرًا لهيكل ذاكرة التخزين المؤقت L2 الخاصة بهم ، سيتعين عليهم دعم TLB بشكل إضافي إذا كتبنا بطريق الخطأ مضاعف 64 إلى عنوان الذاكرة.في مثل هذه الحالات ، لا يزال بإمكاننا استخدام ذاكرة الوصول العشوائي عند إيقاف تشغيل وحدة التحكم.
بالنظر إلى أن المحاذاة المتغيرة تتطلب حدًا أدنى من التعددية 4 ، وأن السجل الأخير لا يمكن أن يحتوي على تعدد 64 أو أكثر ، في كل تجميع ، كان سادس عشر من البيانات غير قابل للاستخدام تمامًا من قبل النظام.
في النهاية ، قمنا بشحن منتج موثوق به مع حاجز ذاكرة ، وقد أحب العملاء ذلك. نعم ، وفي حال كنت تتساءل ، لم أتمكن من ملاحظة ذلك باستخدام كبل USB ، لأننا لم نتمكن من الدخول في وضع الطاقة المنخفضة بسبب استخدام USB. هذه مشكلة USB بحتة.
رسالة خطأ غير صالحة
في الساعات الأخيرة من يوم 17 سبتمبر 1996 ، أي قبل يوم من الإطلاق المقرر لخدمة WebTV ، اجتمعت مجموعتنا في مركز العمليات في بالو ألتو. تجمهر حشد من مسؤولي نظام الشبكة ومطوري برامج الخدمة في مكان قريب لمشاهدة الإطلاق الرسمي.
عندما حلت الساعة المحددة ، بدأ أحد المسوقين الشبكيين بالتسجيل على جهاز WebTV الخاص به. لقد فهمنا أن الأسماء المستعارة الجيدة ستنتهي بسرعة ، لذا كان من المهم التسجيل قبل أن يبدأ المستخدمون في فعل ذلك. بالإضافة إلى ذلك ، كان من الجيد أن أكون من بين أول من سجل في الخدمة "الحقيقية" الأولى. قبل ذلك ، كانت جميع الحسابات حسابات اختبارية "لمرة واحدة".
احتشد العديد من الناس حوله ، يشاهدونه يكتب على لوحة المفاتيح ، ويشعرون بالدوار من الترقب وقلة النوم. أدخل برايس اسمه وعنوانه ومعلومات أخرى ، ثم بدأ في كتابة لقب. كان هذا اسمه لعنوان بريد إلكتروني. كتب "جاز" ، مما يعني أن بريده يجب أن يكون "jazz@webtv.net". عندما ضغط على مفتاح الإدخال (Enter) بلوحة المفاتيح اللاسلكية ، سمعنا صوتًا مميزًا يشير إلى ظهور رسالة خطأ. نظر الجميع إلى الشاشة.
لفهم ما حدث بعد ذلك ، من المهم معرفة شيء أو شيئين عن الخدمة. تم وضع WebTV كجهاز تلفزيون عائلي ، لذلك كان من الضروري التحقق من اللغة البذيئة وتصفية أسماء المستخدمين والمعلومات الأخرى المرئية للمستخدمين. من المستحيل التقاط كل شيء ، لكن ليس من الصعب تصفية الأشياء الواضحة.
تمت مقارنة الأسماء المخصصة بقائمة من التعبيرات العادية ، مما سمح لها بمطابقتها مع نمط. على سبيل المثال ، ستتم مقارنة "fu. * Bar" بجميع الأسماء التي تبدأ بـ "fu" وتنتهي بـ "bar". إذا اخترت الأنماط الخاصة بك بعناية ، فيمكنك التقاط ورفض الاختلافات الفاضحة مثل "shitake" و "matsushita" ، والتي تحتوي على لعنات مدمجة.
تم استخدام نفس الآلية لمنع المستخدمين من اختيار أسماء "ممنوعة" مثل "postmaster" و "root" و "admin" و "help". كان لدينا ملف نصي مثل هذا:
admin.*
"admin".
postmaster
postmaster.
poop
.
weenie
.
كل إدخال يتكون من سطرين. الأول هو التعبير العادي المراد المقارنة معه ، والسطر الثاني هو رسالة الخطأ التي تم عرضها للمستخدم. يقوم النظام بقراءة الملف من سطرين في المرة الواحدة ، وعندما يقوم المستخدم بإدخال الاسم تمت مقارنته بجميع التعبيرات النمطية. تم عرض رسالة خطأ لأول مباراة تم العثور عليها. إذا لم يكن هناك تطابق ، تم قبول الاسم المخصص.
عرف الكود الذي قرأ الملف كيفية تخطي التعليقات. لكنه لم يعرف كيف يتعامل مع الخطوط الفارغة.
قام شخص ما بإجراء تغييرات على ملف القسم ، مع إضافة سطر فارغ واحد بعد الأسماء "المحجوزة" وقبل الكلمات البذيئة. عندما تقرأ الشفرة القائمة ، تأخذ السلسلة الفارغة كتعبير عادي ، والكلمة التي تليها كرسالة خطأ. تعبير سلسلة فارغ يطابق أي شيء.
منتصف الليل. نحن جميعا على حافة الهاوية قليلا. يكتب برايس الاسم ، ويستجيب النظام برسالة بسيطة:

بدأنا نضحك بشكل هيستيري. جاء إلينا آخرون لمعرفة ما يجري. عرضناه على الشاشة. بدأوا يضحكون بشكل هستيري.
في ذلك الوقت ، في مبنى آخر ، جلس مارك أرمسترونج (المسؤول عن ضمان الجودة) ، جنبًا إلى جنب مع بروس ليك (أحد مؤسسي الشركة) ، أمام عداد ستة عشر وحدة تحكم WebTV. تم توصيل هذا الرف ، الملقب بـ "racksville" ، عبر مُضاعِف فيديو بجهاز تلفزيون كبير ، لعرض الصور من جميع الصناديق الستة عشر في وقت واحد. بدأ مارك وبروس في تسجيل أجهزة الاستقبال باستخدام لوحة مفاتيح مزودة بجهاز إرسال يعمل بالأشعة تحت الحمراء. اتصلنا بهم على جهاز الانتركم:
- كيف الحال؟
- كل شيء على ما يرام.
- جيد. ربما لاحظت بعض الأشياء عند التسجيل.
- نعم؟ لم نلاحظ أي شيء غريب.
- تنويه.
- حسنا. إدخال الرمز البريدي ... كل شيء على ما يرام حتى الآن. OGO !!!
ظهرت رسالة ودية على الصور من جميع وحدات التحكم الستة عشر. اقترح الرؤساء أننا قد نحتاج إلى إصلاح هذا الخلل في أسرع وقت ممكن. بدت هذه فكرة رائعة بالنسبة لنا.
أصلحنا الملف وعلمنا الكود التعرف على الأسطر الفارغة وتجاهلها. على حد علمي ، لم يقل WebTV كلمة "f - k" لأي عميل.
مشكلة تعطل Xbox
في ذلك الوقت ، كان الفريق يعمل على واحدة من الألعاب الأولى لوحدة تحكم جديدة تمامًا تسمى Xbox. عندما تم تسريع الاختبار النهائي ، أطلقت QA ثلاثة أجهزة فك التشفير من مجموعة التثبيت لإجراء اختبارات آلية في الليل. إذا كان بناء اللعبة أمس لا يزال قيد الاختبار في الصباح ، فهذا يدل على استقرارها.
لسوء الحظ ، تحطمت إحدى لوحات المفاتيح في الصباح. دائمًا ما تكون الأعطال سيئة ، لكنها كانت حالة سيئة للغاية: شيء ما تم تنفيذه بواسطة بطاقة الفيديو أدى إلى تعطل النظام بأكمله. يعد تشخيص مشكلات بطاقة الرسومات أمرًا صعبًا: لا توجد مصححات ، ولا آثار مكدس ، ولا تصحيح أخطاء باستخدام
printf. يمكنك فقط قراءة الكود والتجربة.
هكذا بدأت Bug Hunt. قام المهندسون الرئيسيون كل يوم بمراجعة الأدلة المتاحة وافترضوا واستبعدوا الاحتمالات. كل ليلة ، حصلت QA على انخفاض "عشوائي" بدون سبب. "هذا مستحيل" ، "كيف يحدث هذا؟" ، "ربما هذا خطأ في المترجم؟" - كل الأغاني الأكثر شعبية.
على سيارة المهندسين ، عملت اللعبة بشكل مثالي لعدة أيام. لكن هذا لم يكن عزاءًا كبيرًا ، لأن الموعد النهائي لإرسال اللعبة للطباعة والشحن إلى المتاجر كان قريبًا.
لحسن الحظ ، سرعان ما وجدنا نمطًا ، وإن كان غريبًا نوعًا ما. اللعبة تحطمت فقط في الليل وفقط على واحد من ثلاثة لوحات المفاتيح. بدأنا في البحث عن الاختلافات بينهما. لم يكن الأمر متعلقًا بكابل الطاقة. ليس في وحدات التحكم. حرق DVD خارج الترتيب. نقل وحدة التحكم إلى طاولتك - لا تسقط. أعده - يسقط. كان الأمر يتعلق بموقف معين استخدمته وكالة الجودة.
الآن تتطلب عملية استبعاد العوامل استبعاد جميع المتغيرات. في النهاية ، وفي حالة من اليأس ، حاول المهندس تبديل مرفقات الطاولة.
اتضح أنه لم يكن هناك خلل في البادئة المحددة. سقطت أي بادئة في هذا الجدول. في منتصف الليل. في بعض الأحيان من أجل العلم عليك أن تتصرف بغرابة ، وكانت هذه إحدى تلك الحالات. جلس المهندس برزانة على كرسي ، وسكب علب ريد بول ، وأصبح بوج هانت Bug Watch. تعهد المهندس بأنه سيشاهد الاختبارات الآلية تعمل على لوحات المفاتيح على هذه الطاولة اللعينة حتى يرى الفشل بأم عينيه.
مر الليل ببطء ، ثم بسرعة ، وفي النهاية جاء الفجر. استمرت اللعبة في الجري. لقد كان ملهماً. بدأت الشمس تشرق.
ثم حدث شيء مثير للاهتمام أخيرًا: سقط شعاع من شروق الشمس على الطاولة. دقيقة بعد دقيقة ، تسلل الشعاع عبر الطاولة إلى الملحقات ، وغطّى توهجه الدافئ بهدوء القبة السوداء للملحق.
الذي سقط بسرعة.
واجه جهاز Xbox الأول مشكلة: فقد تتعطل بطاقة الفيديو إذا وصلت درجة حرارة وحدة التحكم إلى قيمة معينة. البرنامج ليس له علاقة به. تم الإبلاغ عن مشكلة في الأجهزة ، وتم إصدار اللعبة ، وتم استبدال Red Bull بالبيرة. حسنًا ، لنكن صادقين ، بالنسبة للويسكي. واحد: صفر للعلم.