Folklore von Programmierern und Ingenieuren (Teil 3)





Der letzte Teil einer Sammlung von Geschichten aus dem Internet darüber, wie Fehler manchmal völlig unglaubliche Erscheinungsformen haben. Teil eins , Teil zwei .



Kleine SSH, die (manchmal) nicht konnte



Dies ist eine Geschichte über eine der aufregendsten Insektenjagden, an denen ich das Glück hatte, teilnehmen zu können.



Bei AdGear Technologies Inc., wo ich arbeitete, wurde alles auf SSH gehalten. Wir haben es für die Verwaltung, Überwachung, Bereitstellung, Protokollsammlung und sogar für das Live-Streaming verwendet. Dieses Protokoll ist robust und zuverlässig, hat die Vorhersagbarkeit eines nativen Unix-Tools und funktioniert einfach.



Aber einmal sagten uns Briefe ohne bestimmte Zeit oder Host-Referenz, dass das Protokoll nicht funktionierte.



Auszeit



Die Maschinen in unserem Londoner Rechenzentrum hatten zufällige Abstürze beim Senden von Protokolldateien an das Rechenzentrum von Montreal. Diese Aufgabe wurde regelmäßig von Cron ausgeführt, und der Fehler zeigte sich folgendermaßen:



  • Cron-E-Mails meldeten Probleme mit SSH.

    • Manchmal friert es ein.
    • Manchmal wird es ohne Timeout-Fehler beendet.
  • Bei einem internen Gesundheitscheck warnt Nagios vor fehlenden Daten in Montreal.


Wir haben uns bei den Londoner Autos angemeldet, den Befehl manuell gestartet pushund er hat erfolgreich funktioniert. Wir haben es auf ein vorübergehendes Netzwerkproblem zurückgeführt.



Zeitüberschreitungen



Aber die Abstürze wiederholten sich immer wieder zufällig. Einmal am Tag, ein paar Mal am Tag, Freitagmorgen, mehrmals in der Stunde. Es war klar, dass es schlimmer wurde. Wir haben weiterhin manuell Dateien gepusht, bis wir herausgefunden haben, wo das Problem liegt.



Es gab 17 Hopfen zwischen London und Montreal. Wir haben ein Paketverzögerungs- und Verlustprofil erstellt. Es stellte sich heraus, dass 1-3% der Pakete bei ein paar Sprüngen verloren gingen. Zusammen mit der Betriebsabteilung des Londoner Rechenzentrums haben wir eine Umleitung beantragt.



Während die Londoner die Informationen zum Paketverlust überprüften, suchten wir auf dem Weg von London zu unserem zweiten nach zufälligen ZeitüberschreitungenRechenzentrum in Montreal. Die Sprünge auf dieser Route waren unterschiedlich, nicht diejenigen, die Pakete verloren haben. Wir entschieden, dass der Verlust nicht das Hauptproblem war, und außerdem berichteten die Londoner, dass sie den Verlust von Paketen oder Timeouts nicht reproduzieren konnten und dass auf ihrer Seite alles gut aussah.



Apokalypse



Beim manuellen Weiterleiten fehlerhafter Cron-E-Mails haben wir ein interessantes Muster festgestellt. Die Dateien wurden entweder erfolgreich mit hoher Geschwindigkeit übertragen oder sie wurden überhaupt nicht übertragen und hingen beim Timeout. Es gab keine Fälle, in denen Dateien mit niedriger Geschwindigkeit erfolgreich heruntergeladen wurden.



Durch Entfernen der meisten Daten aus der Gleichung konnten wir das Skript mit einfachem Vanilla-SSH neu erstellen. Im Londoner Rechenzentrum hat der Server "SSH mtl-machine" die Aufgabe entweder sofort abgeschlossen oder ist hängen geblieben und konnte keine Verbindung herstellen. Die Überraschung begann zu wachsen.



Wohin gingen die Pakete?



Wir haben die Konfiguration und die Systeme des SSH-Servers in Montreal dreimal überprüft:



  • DNS-Server reagierten schnell.
  • Die Reverse-DNS-Suchzone wurde deaktiviert.
  • Die maximale Anzahl von Clientverbindungen war hoch genug.
  • Wir wurden nicht angegriffen.
  • Der Kanal war nicht verstopft.


Selbst wenn etwas nicht funktioniert, würden wir bei der Arbeit mit zwei verschiedenen Rechenzentren in Montreal ein Einfrieren beobachten. Darüber hinaus haben unsere Rechenzentren außerhalb Londons erfolgreich mit Montreal kommuniziert. Das heißt, das Problem hing mit London zusammen.



Wir haben tcpdump ausgeführt und uns die Pakete angesehen. Wir waren an der allgemeinen Dynamik und den Daten interessiert, die mit Pcaps erhalten und in Wireshark geladen wurden. Wir sahen Anzeichen von Paketverlust und erneutem Senden, aber alles war minimal und kein Grund zur Sorge.



Anschließend analysierten wir die gesamte Verbindung in Situationen, in denen die SSH-Kommunikation erfolgreich hergestellt wurde, und dann - Verbindungen in Situationen, in denen die SSH-Kommunikation unterbrochen war.



Als die Verbindung von London nach Montreal feststeckte, kamen wir zu folgenden Schlussfolgerungen:



  • Das Herstellen einer TCP-Verbindung verlief einwandfrei.
  • Service-SSH-Informationen wurden hin und her gesendet. Bei Bedarf gab es normale TCP-Bestätigungspakete.
  • Ein bestimmtes Paket wurde aus London verschickt und in Montreal empfangen.
  • Das gleiche Paket wurde mehrmals aus London erneut verschickt und in Montreal empfangen.
  • Montreal antwortet einfach nicht darauf!


Es war nicht klar, warum Montreal nicht reagierte (aus diesem Grund sendet London erneut Daten). Die Verbindung blieb hängen, weil das Layer 4-Protokoll hängen blieb. Noch aufregender war die Tatsache, dass es erfolgreich funktioniert, wenn Sie das wiederholte Senden von SSH in London unterbrechen und sofort neu starten. In diesem Fall gab tcpdump an, dass Montreal das Paket erhalten und darauf geantwortet hat, und die Arbeit wurde fortgesetzt.



Auf dem SSH-Client in London haben wir das ausführliche Debugging ( -vvv) aktiviert , und nach diesen Protokolleinträgen blieb die Verbindung hängen:



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


Wir haben "SSH hang SSH2_MSG_KEX_DH_GEX_GROUP" gegoogelt und viele Ergebnisse erzielt, von Wi-Fi-Problemen über TCP-Fehler in Windows bis hin zu fehlerhaften Routern, die TCP-Fragmente verlieren. Eine der Lösungen für das LAN bestand darin, die MSS des Pfads zu berechnen und diesen Wert an beiden Enden der Route als MTU festzulegen.



Ich habe die MTU auf dem Londoner Server von 1500 auf 1500 verringert - es hat nicht geholfen, bis ich den magischen Wert von 576 erreicht habe. Danach hing SSH nicht mehr. Ich habe ein Skript mit einer SSH-Schleife ausgeführt. Falls gewünscht, konnte ich Zeitüberschreitungen verursachen, indem ich die MTU auf 1500 zurücksetzte oder sie durch Festlegen von 576 beseitigte. Leider handelt es sich um öffentliche Ad-Server, und die globale Zuweisung einer MTU von 1500 löst das Problem nicht. Es wurde jedoch bereits oben erwähnt, dass der Prozess der Fragmentierung oder des Zusammenbaus von Paketen wahrscheinlich irgendwo unterbrochen ist.



Kehren wir zur Überprüfung der empfangenen Pakete mit tcpdump zurück: Es gab keine Anzeichen einer Fragmentierung. Die Größe des empfangenen Pakets entsprach vollständig der Größe des gesendeten Pakets. Wenn etwas das Paket auf Byte 576+ fragmentiert hat, wurde es erfolgreich wieder zusammengesetzt.



Twinkle Twinkle, Kurvenstern



Als ich mich eingehender mit der Analyse befasste, betrachtete ich vollständige Paket-Dumps ( tcpdump -s 0 -X), nicht nur Header. Beim Vergleich des magischen Pakets von einem erfolgreichen Sendevorgang mit einem Paket von einem fehlgeschlagenen Sendevorgang stellte ich mit Ausnahme der TCP / IP-Header fast keinen Unterschied fest. Es war jedoch klar, dass dies das erste Paket auf einer TCP-Verbindung war, das genügend Daten enthielt, um die 576-Byte-Marke zu überschreiten. Alle vorherigen Pakete waren viel kleiner.



Beim Vergleich des gleichen Pakets aus dem fehlgeschlagenen Versand in der Form, in der es London verließ und nach Montreal kam, fiel mir etwas auf. Für etwas Feines, und ich winkte es wegen Müdigkeit ab (es war später Freitagabend). Aber nach mehreren Updates und Vergleichen habe ich mir das nicht mehr vorgestellt.



So sah das Paket nach dem Verlassen von London aus (abzüglich der ersten Bytes, die die IP-Adressen identifizieren)
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            ............




Und so sah das gleiche Paket aus, als es in Montreal ankam
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            ............




Hast du etwas bemerkt? Wenn nicht, ist das okay. Sie können in einem Texteditor in zwei Fenster kopieren und schnell zwischen diesen wechseln, um die Symboländerungen zu sehen.



So so. Dies ist kein Paketverlust, sondern eine Paketbeschädigung! Sehr wenig, sehr vorhersehbarer Schaden. Interessante Beobachtungen:



  • Der erste Teil des Pakets (<576 Bytes) ist intakt.
  • Jedes 15. von 16 Bytes wird beschädigt.
  • Der Schaden ist vorhersehbar. Alle hwurden x, alle cwurden s.


Möglicherweise haben Sie bereits die ASCII-Tabelle konsultiert und festgestellt, dass ein Bit auf dem Wert steckt 1. Wenn Sie sich 1in einem Byte in das vierte Bit verwandeln, werden die vorherigen Buchstaben links mit den Werten rechts verdorben.



Die offensichtlichen Schuldigen in unserem Sichtfeld (NICs, die Server akzeptieren) stehen außer Verdacht, da der Fehler ein Muster aufweist (mehrere Londoner Maschinen → mehrere Rechenzentren und Maschinen in Montreal). Der Grund muss auf der Strecke und näher an London liegen.



Die Situation begann Sinn zu machen. Ich habe auch einen kleinen Hinweis im ausführlichen tcpdump-Modus bemerkt (tcp cksum bad), was ich vorher nicht bemerkt hatte. Der Montreal-Server hat ein Paket auf Kernel-Ebene verworfen, als er feststellte, dass es beschädigt war, und das Paket nicht an den SSH-Daemon im Benutzerbereich weitergeleitet. Dann schickte London das Paket erneut, es wurde erneut beschädigt und Montreal verwarf es stillschweigend. Aus Sicht von SSH und SSHd bleibt die Verbindung hängen. Aus Sicht von tcpdump gab es keinen Verlust und die Montreal-Server ignorieren die Daten einfach.



Wir haben unsere Ergebnisse der Betriebsabteilung des Londoner Rechenzentrums gemeldet und in wenigen Minuten ihre ausgehenden Routen dramatisch geändert. Der erste und die meisten nachfolgenden Sprünge waren unterschiedlich. Das Einfrierproblem ist weg.



Korrekturen am späten Freitagabend sind nett, denn am Wochenende kann man sich entspannen und nicht an Probleme und Unterstützung denken :)



Wo ist Wally?



Ich war froh, dass wir nicht mehr unter diesem Problem litten und unsere Systeme aufholten, und entschied mich, das Gerät zu finden, das für diese Paketbeschädigung verantwortlich ist.



Durch die Aktualisierung der Londoner Routen, um den Verkehr von der alten Route fernzuhalten, konnte ich das Problem nicht einfach reproduzieren. In Montreal fand ich einen Freund mit einer geeigneten FreeBSD-Maschine, die über die alten Strecken von London aus erhältlich war.



Ich wollte sicherstellen, dass der Schaden auch ohne SSH vorhersehbar war. Ich habe das mit ein paar Pipelines problemlos geschafft.



In Montreal:



nc -l -p 4000 > /dev/null


Dann in London:



cat /dev/zero | nc mtl 4000


Angesichts des Zufallsfaktors und der Optimierung im Wiederholungszyklus erhielt ich mehrere Pakete, die Zweifel an den vorherigen Schlussfolgerungen zerstreuten. Hier ist ein Teil eines der Pakete:



Wir haben gerade ein Paket mit Nullen gesendet
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  .....




Als ich den Fehler reproduzierte, musste ich den einen der 17 Hopfen finden, bei denen der Schaden auftrat. Ich konnte nicht einfach die Anbieter aller Cluster anrufen und sie bitten, ihre Systeme zu überprüfen.



Ich habe beschlossen, jeden Router nacheinander zu pingen, es könnte helfen. Schrieb spezielle ICMP-Pakete, die groß genug waren, um die Sicherheitsgrenze von 576 Byte zu überschreiten, und füllte sie mit Nullen. Dann habe ich mit Hilfe dieser Pakete den Montreal-Server von London aus angerufen.



Pakete intakt zurückgegeben.



Ich habe jede Kombination aus Geschwindigkeit, Inhalt und Größe ausprobiert - ohne Erfolg. Ich habe keine Schäden in den zurückgegebenen ICMP-Ping-Paketen gefunden.



In Netcat-Pipelines habe ich TCP durch UDP ersetzt. Wieder kein Schaden.



Es brauchte TCP, um den Schaden zu reproduzieren, und TCP benötigte zwei kommunizierende Endpunkte. Ich habe vergeblich versucht herauszufinden, ob alle Router einen offenen TCP-Port haben, mit dem ich direkt kommunizieren kann.



Es schien unmöglich, den fehlerhaften Sprung von außen zu identifizieren. Oder ist es möglich?



Spieglein Spieglein an der Wand



Um festzustellen, ob ein Schaden auftritt, musste eines der folgenden Szenarien verwendet werden:



  • Überprüfen Sie das Paket am Ziel über den TCP-Knoten, mit dem es kommuniziert.

    • Nicht im Benutzerbereich, wo das Paket im Falle eines Fehlers während der Prüfsummenüberprüfung nicht zugestellt wird, sondern das empfangene Paket mit root und tcpdump auf Beschädigungen überprüft.
  • Überprüfen Sie das Paket auf dem sendenden Knoten, indem Sie einen TCP-Knoten verwenden, der als Echoserver fungiert und die empfangenen Daten zurückspiegelt.


Es stellte sich plötzlich heraus, dass uns ein zweiter Messpunkt zur Verfügung steht. Nicht direkt verfügbar, aber dennoch: Beim ersten Ansatz zur Lösung des Problems haben wir festgestellt, dass SSH-Clients bei der Kommunikation mit SSH-Servern über einen beschädigenden Hop hängen bleiben. Dies ist ein gutes passives Signal, das anstelle des aktiven "Echo" -Signals verwendet werden kann.



Dabei können uns zahlreiche offene SSH-Server im Internet helfen.



Wir benötigen keine Girokonten auf diesen Servern. Wir müssen lediglich eine SSH-Verbindung herstellen, um festzustellen, ob die Verschlüsselungsaustauschphase erfolgreich ist (mit einer angemessenen Anzahl von Wiederholungsversuchen, um den versehentlichen Schaden zu berücksichtigen).



Der Plan war folgender:



  • Verwenden Sie das wunderbare nmap- Tool im "Random IP" -Modus, um eine Liste der geografisch verteilten offenen SSH-Server zu erstellen.
  • :

    • , → .
    • N- → «».
    • telltale N- → «».
  • «» «».


Ich dachte so: In den Spuren aller "schlechten" Server werden mehrere der gleichen Hops verwendet. Wir werden in der Lage sein, verdächtige Hops zu isolieren und diejenigen zu identifizieren, die in den Spuren "guter" Server verwendet werden. In der Hoffnung, dass einer oder zwei bleiben.



Nachdem ich eine Stunde damit verbracht hatte, die Server manuell zu klassifizieren, hörte ich auf, die Daten zu untersuchen. Ich hatte 16 "schlechte" und 25 "gute" Server.



Der erste Schritt bestand darin, eine Liste der Hops zu erstellen, die in allen Spuren der "schlechten" Server erscheinen. Nachdem ich die Liste bereinigt hatte, wurde mir klar, dass ich nicht einmal zur Liste der "guten" gehen muss, um falsch positive Hopfen zu entfernen. Die Bösen hatten nur einen gemeinsamen Sprung.



Davor gab es jedoch zwei Anbieter: London → N springt stromaufwärts1 → Y springt stromaufwärts2.



Dies war der erste der Y-Sprünge in Upstream2, direkt an der Grenze zwischen Upstream1 und Upstream2. Es beschädigte zufällige TCP-Pakete, was zu zahlreichen Neuübertragungen führte und abhängig von den Besonderheiten des Protokolldatenaustauschs einfrierte oder das Übertragungsvolumen reduzierte.



Zusammen mit der Londoner Abteilung für den Betrieb von Rechenzentren haben wir die IP-Adresse dieses Hops verfolgt. Ich hatte gehofft, dass durch ihre direkte Verbindung zu Upstream1 Korrekturen erzwungen werden können.



Über Upstream1 erhielt ich die Bestätigung, dass der von mir angegebene Hop (der erste in Upstream2) einen internen "Steuermodulfehler" aufwies, der sich auf BGP und das Routing zwischen den beiden internen Netzwerken auswirkte. Sie haben das fehlerhafte Gerät umgeleitet und es bis zum Austausch ausgeschaltet.



Rockmusikfilter



Ich habe einem Benutzer einer Audio-Streaming-Anwendung geholfen, ein LAN-Erlebnis einzurichten. Der Benutzer spielte nur klassische Musik, keine Rockmusik. Ernsthaft. Klassiker wurden nahtlos gestreamt, und beim Versuch, Rockmusik zu streamen, wurde die Verbindung nach einigen Minuten unterbrochen.



Die App empfing Audioblöcke, komprimierte sie mit einem verlustfreien Komprimierungscodec und sendete dann jeden Block in einem separaten UDP-Paket an den Endpunkt. Wann immer möglich, versuchte die Anwendung, IPv6 zu verwenden, da es zuverlässiger als die LAN-Umgebung war, obwohl es bei Bedarf über IPv4 funktionieren konnte.



Nach einer endlosen und langwierigen Suche nach der Ursache des Problems fand ich endlich heraus, was los war. Irgendwie hat der Benutzer die MTU in der Netzwerkschnittstelle auf 1200 Bytes eingestellt. Und IPv6 fragmentiert Pakete nicht automatisch auf IP-Ebene, wenn die MTU unter 1280 Byte liegt, sodass größere Pakete einfach nicht gesendet werden können. Die Streaming-Anwendung versucht, Audiopakete mit mehr als 1200 Byte zu senden, einen Fehler zu empfangen und die Verbindung zu trennen.



Warum geschah das nur mit Rockmusik? Es ist einfach. Verlustfreie Codecs verwenden eine variable Bitrate, und klassische Musik wird besser komprimiert als Rockmusik. Beim Streaming von Klassikern wurde Audio konsistent in Pakete mit weniger als 1200 Byte komprimiert, und Pakete mit Rockmusik haben diesen Schwellenwert zufällig überschritten.



Der Benutzer wusste nicht, warum seine MTU reduziert wurde, er brauchte sie nicht, also haben wir den Wert erhöht und alles hat gut funktioniert.



Selbst verschwindende Internetstörung



Als ich 1999 an die Universität kam, lebte ich in einem alten und heruntergekommenen Studentenwohnheim, weil ich mir nichts Besseres leisten konnte. Aber zumindest gab es im Hostel ein ziemlich anständiges Internet, das in meinem Land noch nicht weit verbreitet war. Und da es verboten war, das Gebäude zu wechseln, wurden Netzwerkkabel (immer noch koaxial) nach einem vorübergehenden Schema geschieden. Sie wurden hinter Zwischendecken in Korridoren versteckt und durch Türen in Räume gezogen, in denen sie einfach auf dem Boden lagen. Jede Unterbrechung der Kommunikation könnte dazu führen, dass eine ganze Etage ohne Netzwerk bleibt. Seit ich an der Fakultät für Informatik studiert habe, habe ich mich schnell und unfreiwillig in eine Person auf meiner Etage verwandelt, die ziemlich häufige Ausfälle behebt, obwohl ich überhaupt keine Erfahrung mit Netzwerken hatte.



Manchmal war die Unterbrechung auf der Seite des Anbieters, manchmal hing das Problem mit unserem Proxy zusammen, aber meistens zog jemand einfach ein Kabel ab und steckte keinen Terminator hinein.



Eines Abends ging das Internet aus, aber nur für ein paar Minuten. Dann tauchte er wieder auf, also dachte ich nicht viel darüber nach. Aber am nächsten Tag wiederholte sich die kurze Unterbrechung und auch am dritten Tag. Normalerweise passierte es ungefähr 20 Stunden, die genaue Zeit schwebte und manchmal war es überhaupt nicht. Aber jedes Mal, wenn das Netzwerk ausfiel, klingelte mein Telefon vor Ort und die Leute ärgerten sich zunehmend über diese wiederholten Unterbrechungen.



Da jede Unterbrechung nur wenige Minuten dauerte, konnte ich keinen bestimmten Ort bestimmen, bevor das Netzwerk wieder angezeigt wurde. Ich versuchte über den Boden zu rennen und an alle Türen zu klopfen und fragte, ob jemand ein Kabel herausgezogen oder etwas damit gemacht habe, aber die Idee half nicht. Schließlich beschloss ich, mit meinem zuverlässigen Multimeter in der Hand auf die tägliche Unterbrechung zu warten. Innerhalb einer Woche habe ich einen Raum nach dem anderen von Verdächtigen ausgeschlossen. Schließlich bemerkte ich in einem der Raumkabel einen Widerstandsschub bei der nächsten Unterbrechung.



Ich habe geklopft, aber sie haben es nicht geöffnet. Das Schloss war verschlossen. Aber wenn sich niemand im Raum befindet, um etwas mit dem Computer oder Kabel zu tun, warum wird dann die Verbindung unterbrochen? Und warum erholt es sich? Am nächsten Tag passierte alles wieder, sie öffneten die Tür nicht wieder. Ich beschloss, diesen Raum komplett auszuschalten, damit das Internet auf dem Rest der Etage funktioniert.



Am nächsten Morgen teilten mir die Mieter dieses Zimmers mit, dass ihr Internet nicht funktioniere. Ich ging zu ihnen und maß den Widerstand in allen Kabeln, überprüfte alle Verbindungen und Abschlusswiderstände. Alle Kabel haben null Ohm, alles ist in perfekter Ordnung. Ich habe den Typen gefragt, was er letzte Nacht gemacht hat. Ich habe vor den Prüfungen Lehrbücher gelesen, nichts mit dem Computer zu tun, antwortete er. Ich habe alles ein zweites und drittes Mal überprüft, aber keine Probleme gefunden. Ich hätte fast aufgegeben, und dann bemerkte ich: Das Kabel war unter dem Bett befestigt. Natürlich war der Kupferkern des Kabels genau an dieser Stelle gebrochen, aber er wurde fest von der Hülle gehalten, so dass unter normalen Bedingungen der Kontakt auch dann erhalten blieb, wenn Sie auf dem Bett saßen. Aber als ich anfing zu schwingen, verschwand der Kontakt bei jedem Druck für einige Sekunden.



Sie selbst können erraten, was jeden Abend einige Minuten lang auf diesem Bett passiert ist, hinter einer verschlossenen Tür und ohne Antwort auf ein Klopfen.



Mels Geschichte



Echte Programmierer schreiben in Fortran



Dies mag jetzt in der dekadenten Ära von alkoholfreiem Bier, Taschenrechnern und "benutzerfreundlichen" Anwendungen der Fall sein, aber in der guten alten Zeit, als der Begriff "Software" lustig klang und Real Computer aus Magnettrommeln und Funkröhren hergestellt wurden, schrieb Real Programmers Maschinensprache. Nicht bei FORTRAN. Nicht auf RATFOR. Nicht einmal Assemblersprache. Im Maschinencode. Auf realen, schmucklosen, unverständlichen Hexadezimalzahlen. Genau so. Mehrere Generationen von Programmierern sind aufgewachsen, ohne etwas über diese glorreiche Vergangenheit zu wissen, und ich glaube, ich sollte versuchen, die Generationslücke zu schließen und darüber zu sprechen, wie ein echter Programmierer Code geschrieben hat. Ich werde ihn Mel nennen, weil das sein Name war.



Ich habe Mel kennengelernt, als ich einen Job bei Royal McBee Computer Corp. bekam, einer inzwischen aufgelösten Tochtergesellschaft eines Schreibmaschinenherstellers. Die Firma stellte den LGP-30 her - einen kleinen und nach heutigen Maßstäben billigen Drum-Computer - und hatte gerade damit begonnen, den RPC-4000, ebenfalls auf Drum-Speicher, deutlich verbessert, größer und schneller zu machen. Magnetkerne waren zu teuer und konnten der Konkurrenz nicht standhalten (weshalb Sie noch nichts von dieser Firma oder ihren Computern gehört haben). Ich wurde beauftragt, einen FORTRAN-Compiler für dieses neue Wunder zu schreiben, und Mel war mein Leitfaden für seine Fähigkeiten. Mel missbilligte Compiler. "Was nützt es, dass ein Programm seinen eigenen Code nicht umschreiben kann?", Fragte er. Mel schrieb das beliebteste Programm des Unternehmens in hex.Sie arbeitete für das LGP-30 und spielte Blackjack mit potenziellen Käufern auf Computershows. Es hat immer einen dramatischen Effekt gehabt. Auf jeder Messe wurde ein LGP-30-Stand ausgestellt, und IBM-Anbieter versammelten sich und sprachen miteinander. Hat es geholfen, Computer zu verkaufen? Wir haben dieses Problem nie diskutiert.



Mels Aufgabe war es, das Blackjack-Programm für RPC-4000 neu zu schreiben. (Portierung? Was ist das?) Der neue Computer hatte ein Eins-plus-Eins-Adressierungsschema: Zusätzlich zum Opcode und der Adresse des erforderlichen Operanden hatte jeder Maschinenbefehl auch eine zweite Adresse, die zeigte, wo der nächste Befehl auf eine rotierende Magnettrommel geschrieben wurde ... Das heißt, nach jeder Anweisung ging GO TO! Füllen Sie dies in eine Pascal-Pfeife und rauchen Sie es.



Mel liebte den RPC-4000, weil er seinen Code optimieren konnte: Platzieren Sie Anweisungen auf der Rolle, sodass sich der zweite sofort nach dem Abschluss unmittelbar unter dem "Lesekopf" befindet und sofort ausgeführt werden kann. Zu diesem Zweck wurde ein Programm geschrieben, das den Assembler optimiert, aber Mel weigerte sich, es zu verwenden. "Sie wissen nie, wo die Daten abgelegt werden", erklärte er, "also müssen Sie separate Konstanten verwenden." Ich habe die Essenz dieses Satzes viel später verstanden. Da Mel die numerischen Werte aller Betriebscodes kannte und seine eigenen Adressen im Trommelspeicher zuordnete, konnte jeder von ihm geschriebene Befehl als numerische Konstante betrachtet werden. Zum Beispiel könnte er eine frühere Anweisung zum Hinzufügen auswählen und mit dieser multiplizieren, wenn sie einen geeigneten numerischen Wert hätte. Nur sehr wenige Leute konnten den Code ändern.Ich habe Mels manuell optimierte Programme mit demselben Code verglichen, der vom optimierenden Assembler verarbeitet wurde, und Mels Code lief immer schneller. Tatsache ist, dass die Top-Down-Methode der Gebäudearchitektur noch nicht erfunden wurde und Mal sie sowieso nicht verwendet hätte. Zuerst schrieb er die inneren Teile seiner Programmierschleifen so, dass sie als erste die optimalen Adressen auf der Rolle erhielten. Und der optimierende Assembler war dazu nicht in der Lage. Mel hat nie zeitverzögerte Schleifen geschrieben, selbst wenn der riesige Flexowriter eine Verzögerung zwischen den Zeichenausgaben benötigte. Mel legte die Anweisungen einfach auf die Rolle, damit sie beim Lesen der nächsten Anweisung durchlaufen wurdendass die Top-Down-Architekturmethode noch nicht erfunden wurde und Mel sie sowieso nicht verwendet hätte. Zuerst schrieb er die inneren Teile seiner Programmierschleifen so, dass sie als erste die optimalen Adressen auf der Rolle erhielten. Und der optimierende Assembler war dazu nicht in der Lage. Mel hat nie zeitverzögerte Schleifen geschrieben, selbst wenn der riesige Flexowriter eine Verzögerung zwischen den Zeichenausgaben benötigte. Mel legte die Anweisungen einfach auf die Rolle, damit sie, wenn die nächste Anweisung gelesen werden musste, durchlaufen wurdendass die Top-Down-Architekturmethode noch nicht erfunden wurde und Mel sie sowieso nicht verwendet hätte. Zuerst schrieb er die inneren Teile seiner Programmierschleifen so, dass sie als erste die optimalen Adressen auf der Rolle erhielten. Und der optimierende Assembler war dazu nicht in der Lage. Mel hat nie zeitverzögerte Schleifen geschrieben, selbst wenn der riesige Flexowriter eine Verzögerung zwischen den Zeichenausgaben benötigte. Mel legte die Anweisungen einfach auf die Rolle, damit sie, wenn die nächste Anweisung gelesen werden musste, durchlaufen wurdenselbst wenn der riesige Flexowriter eine Verzögerung zwischen den Zeichenausgaben benötigte. Mel legte die Anweisungen einfach auf die Rolle, damit sie, wenn die nächste Anweisung gelesen werden musste, durchlaufen wurdenselbst wenn der riesige Flexowriter eine Verzögerung zwischen den Zeichenausgaben benötigte. Mel legte die Anweisungen einfach auf die Rolle, damit sie, wenn die nächste Anweisung gelesen werden musste, durchlaufen wurdenhinter dem Lesekopf, und die Trommel müsste eine weitere Umdrehung machen, um sie zu finden. Mel fand einen unnachahmlichen Begriff für dieses Verfahren. Das Wort "optimal" (optimal) hat eine absolute Bedeutung sowie "einzigartig", so dass sie in der Umgangssprache oft relativiert wurden: "nicht ganz optimal" oder "weniger optimal" oder "nicht sehr optimal". Mel nannte die Stellen auf der Trommel mit der längsten Verzögerungszeit "das pessimum" ( Pessimum - die schlechtesten vom Körper tolerierten Umgebungsbedingungen ).



Nachdem Mel die Arbeit am Blackjack-Programm beendet und ausgeführt hatte („Auch der Initialisierer ist optimiert“, sagte er stolz), erhielt er eine Anfrage von der Verkaufsabteilung, Änderungen vorzunehmen. Ein eleganter (optimierter) Zufallszahlengenerator war für das Mischen der Karten und den Handel vom Deck im Programm verantwortlich. Und einige der Verkäufer fanden es zu ehrlich, weil die Käufer manchmal verloren. Sie baten Mel, das Programm zu ändern, damit der Touch-Schalter auf der Konsole die Gewinnchancen des Spielers ändern und den Käufer gewinnen lassen konnte. Mel lehnte ab. Er hielt es für unehrlich - es war so - und dass es in die Moral seines Programmierers eingriff - es war so -, also weigerte er sich, daran teilzunehmen. Mel wurde vom Leiter der Verkaufsabteilung, Big Boss und anderen Programmierern auf Drängen des Chefs überzeugt. Schließlich gab Mel auf und schrieb den CodeAber hat der Cheat umgekehrt überprüft: Wenn der Schalter eingeschaltet war, hat das Programm geschummelt und immer gewonnen. Mel war begeistert von seiner Entscheidung. Er behauptete, sein Unterbewusstsein habe eine unkontrollierbare Ethik gezeigt und sich rundweg geweigert, das Programm zu korrigieren. Als Mel das Unternehmen verließ, um ein höheres Einkommen zu erzielen, bat mich Big Boss, mir den Code anzusehen und mir zu sagen, ob ich einen Validator finden und die Funktionsweise ändern könnte. Ich stimmte widerwillig zu.Kann ich das Überprüfungsmodul finden und die Funktionsweise ändern? Ich stimmte widerwillig zu.Kann ich das Verifizierungsmodul finden und die Funktionsweise ändern? Ich stimmte widerwillig zu.



Der Umgang mit Mels Code war ein echtes Abenteuer. Es schien mir oft, dass Programmieren eine Kunstform ist, deren wirklicher Wert nur von denen geschätzt werden kann, die diese mysteriöse Kunst verstehen. Es enthält echte Juwelen und brillante Bewegungen, die durch die Natur des Prozesses, manchmal für immer, vor menschlichen Augen und Bewunderung verborgen sind. Sie können viel über eine Person lernen, indem Sie ihren Code lesen, sogar hexadezimal. Ich denke, Mel war ein nicht anerkanntes Genie. Der vielleicht stärkste Schock war der unschuldige Zyklus, in dem es keine betrügerische Überprüfung gab. Keine Überprüfung. Nein .



Der gesunde Menschenverstand diktierte, dass dies ein geschlossener Kreislauf sein sollte, in dem das Programm für immer und endlos zirkuliert. Die Softwaresteuerung wurde jedoch erfolgreich durchlaufen und auf der anderen Seite sicher beendet. Ich habe zwei Wochen gebraucht, um das herauszufinden. Der RPC-4000 war mit einem modernen Gerät ausgestattet - einem Indexregister. Es erlaubte das Schreiben von Programmschleifen, in denen indizierte Anweisungen verwendet wurden. Jedes Mal, wenn es die Schleife durchlief, wurde der Befehlsadresse eine Nummer aus dem Register hinzugefügt, so dass sie auf die nächste Position in der Reihe verweist. Alles, was blieb, war, das Indexregister mit jedem Durchgang zu erhöhen. Mel nutzte dies nicht aus. Stattdessen zog er die Anweisung in das Maschinenregister, fügte eine zu ihrer Adresse hinzu und speicherte sie zurück. Und dann hat es den modifizierten Befehl direkt aus dem Register ausgeführt.Der Zyklus wurde unter Berücksichtigung der zusätzlichen Ausführungszeit geschrieben: Sobald der Befehl abgeschlossen war, erschien der nächste unter dem Lesekopf der Trommel. Aber es gab keine Schurkenprüfung in der Schleife. Der sichere Hinweis war, dass ein Bit im Indexregister aktiviert war - es befand sich im Befehlscode zwischen der Adresse und dem Betriebscode. Mel verwendete das Indexregister jedoch nicht und beließ es bei Null.



Als meine Offenbarung kam, wurde ich fast blind. Die Daten, an denen er arbeitete, befanden sich in der Nähe der hohen Speicherebenen - den größten Adressen, auf die Anweisungen verweisen konnten -, die Mel so angeordnet hatte, dass nach dem Verarbeiten der letzten Position das Erhöhen der Anweisungsadresse einen Überlauf verursachen würde. Während der Übertragung wurde einer zum Betriebscode hinzugefügt und in den folgenden Code im Satz geändert: die Sprunganweisung. Natürlich befand sich diese nächste Anweisung an der Adresse Null, und das Programm ging glücklich dorthin. Ich habe nicht mit Mel gesprochen und ich weiß nicht, ob er angesichts der Flut des Wandels, die seitdem die Programmierung überflutet hat, aufgegeben hat. Ich denke lieber, ich habe nicht aufgegeben. Ich war so beeindruckt, dass ich aufhörte, nach einem Cheat-Check zu suchen, und Big Boss sagte, ich könne ihn nicht finden. Er war nicht überrascht. Als ich die Firma verließDas Blackjack-Programm hat immer noch geschummelt, wenn der rechte Schalter eingeschaltet war, und das zu Recht, denke ich. Ich mochte es nicht, den Code eines echten Programmierers zu hacken.



Ausnahmsweise USB-Problem



Gleich nach dem College trat ich einer Firma bei und arbeitete fünf Monate lang an einem Verbrauchergerät, bevor es der Öffentlichkeit gezeigt wurde. Auf dem Gerät wurde Linux ausgeführt. Und während ich mich an die Idee gewöhnte, mich im Kernelraum verwöhnen zu lassen, wurde ich zu einem Meeting gerissen, um Fehler zu priorisieren. Zahlreiche Bugs. Hunderte von Fehlern. Jeder von ihnen liest: "Das ist unmöglich, wie ist das passiert?"



Sie riefen: "Gedächtnisschaden!" Ich dachte: "Hospadi, behebe deine Fehler." Als wir uns die Crash Dumps anschauten, sahen wir ... was ist das? Das Programm führte die verbotene Anweisung aus, indem es die beiden Zeichenfolgen mit einer Funktion aus der Standardbibliothek verkettete. Hmm, komisch ... Nächstes Protokoll: Ich kann keine Seite aus einer Auslagerungsdatei auf einem Gerät abrufen, dem überhaupt kein Speicherplatz für Auslagerungsdateien zugewiesen ist (ich glaube, ich verstehe, warum wir keine Seite abrufen konnten!).



Ich habe einmal ein kurzes Programm geschrieben. Es hat 80% des Systemspeichers für ein Array zugewiesen und sequentielle Ganzzahlen darauf geschrieben. Dann wartete ich darauf, dass die Eingabetaste gedrückt wurde, und überprüfte, ob sich der Inhalt des Arrays geändert hatte. Jetzt habe ich dieses Programm heruntergeladen, 30 Sekunden gewartet und dann die Prüfung durchgeführt. Keine Probleme. Ich habe es noch ein paar Mal versucht - ha, ich wusste, dass es keinen Gedächtnisschaden gab! Ich zog das Debug-Kabel (USB) heraus, nach 10 Sekunden steckte ich es schnell ein und zog es heraus, dann steckte ich es wieder ein. Bam! 90 Fehler.



Deine.



Okay, ich muss am USB-Anschluss basteln. Das Problem hängt also mit ihm zusammen? Der USB-Treiber scheint keinen Magic Bit Fairy-Algorithmus zu implementieren, der zufällig Bitfehler herumwirft. Wahrscheinlich ein Problem mit der Hardware? Nein, nicht bei ihm, aber das hat uns nicht davon abgehalten, mit dem USB-Anschluss allerlei Unanständigkeit zu tun. Sie haben Ingenieure hinzugezogen, die vor langer Zeit auf ein anderes Produkt umgestellt hatten, und jetzt rätselten sie über das Problem. Ich kann mich nicht erinnern, wie viel Zeit wir damit verbracht haben, uns selbst zu beweisen, dass die Hardware vollständig, vollständig und oooooo in Ordnung war. Die Erdung war in Ordnung, die Spannung war stabil, die Uhr lief genau und die DDR-Leitungen waren so perfekt, dass Sie vor Glück geweint hätten, wenn Sie sie gesehen hätten.



Geräte, die von Ingenieuren getestet wurden, wurden immer instabiler. Ich ging davon aus, dass der Computer Daten in den Speicher laden, Bitfehler abrufen und dann wieder in den Flash-Speicher kopieren kann, möglicherweise sogar an der falschen Stelle (die Seitentabelle wurde häufig beschädigt, sodass davon ausgegangen werden kann, dass dies auch bei Dateiverfolgungsstrukturen der Fall ist Inhalte könnten an die falschen Stellen geschrieben werden und Dateisystemstrukturen könnten kaputt gehen usw.) Im Laufe der Zeit wurden Geräte so stark beeinträchtigt, dass sie nicht mehr zuverlässig gestartet werden konnten. Schließlich brach einer der Ingenieure zusammen und überschrieb das Bild auf seinem Laptop. Dieses Bild war relativ alt.



- Kumpel. Es geht um die Software.



- Was?!?!?! Ich versichere Ihnen, wir haben kein bisschen Fee geschrieben!



Nein, er hat vor drei Monaten eine Baugruppe hochgeladen und das Problem ist behoben. In diesem Moment fühlte ich mich dafür verantwortlich, eine Reihe von Leuten in ein sehr langes und bedeutungsloses Unterfangen verwickelt zu haben. Deshalb blieb ich über Nacht und durchsuchte in den letzten Monaten alle Patches binär (es dauerte länger, bis ich alle Baugruppen des gesamten Betriebssystems studiert hatte, als ich wollte ...).



Was war das für ein magischer Fleck? Jemand hat dem Kernel einen Treiber für den von uns analysierten Chip hinzugefügt. Dieser Chip war nicht im Gerät.



Ha! Wir haben eine Hexe gefunden! VERBRENNEN SIE ES!



Viele kündigten an, dass das Problem gelöst sei. Sie waren froh, dass sie in der nächsten Version den Patch zurücksetzen und weitermachen konnten. Wir rollten es mit äußerster Sorgfalt zurück, stellten ein Bild zusammen, testeten es, alles war in Ordnung. Wir haben nicht erwartet, dass in wenigen Tagen derselbe Defekt im Kern auftritt.



Warten. Wenn der Chip nicht auf dem Board war, wie hat uns der Fahrer daran gehindert? Ich habe lsmod ausgeführt, der Treiber wurde nicht geladen ... „Wie auch immer, was ist der Unterschied, löschen Sie die Moduldatei und laden Sie sie neu. Nifiga, das Problem bleibt. Das ist nicht normal..."



Jetzt war ich allein und sah zu, wie die Teufelei weiterging. Ich begann den Patch sorgfältig zu analysieren. Es war eine schöne 10K-Line-C-Datei, die vom Chiphersteller zur Verfügung gestellt wurde. Es wäre zu herablassend, es mit dem Wort "Chaos" zu beschreiben (fairerweise schickten sie uns nach ein paar Wochen einen viel nachdenklicheren Fahrer). Nachdem ich ein bisschen herumgegraben hatte, entschied ich, dass der Fahrer kein Bit-Jonglieren zum Spaß implementierte. Also, was ist der Deal? 48 Bytes aus fünf Codezeilen. Eine kleine Struktur in der Boot-Datei, die angibt, welche Busadresse nach dem Chip gesucht werden soll. Ich habe den größten Teil des Treibers entfernt, aber eine andere Struktur darin belassen. Das Problem ist nicht verschwunden.



Also Jungs und Mädels, wir haben ein Ausrichtungsproblem! Irgendwie bewegt diese 48-Byte-Struktur etwas im Speicher und das führt zu Fehlern. Ich habe herausgefunden, dass das Problem auftritt, wenn Sie etwas größer als 32 und kleiner als 64 Byte in eine Datei einfügen. Dieses Wissen hat nicht viel geholfen, aber zumindest ein Gefühl des Fortschritts geschaffen.



Die Kernel-Kompilierung erzeugte eine ordentliche System.map-Datei. Es wurde aufgelistet, wo sich im virtuellen Adressraum des Kernels alle im Kernel kompilierten Variablen befinden. Ich fand heraus, dass sich meine kleine Struktur in der Mitte des Abschnitts ".data" befindet. Dieser Abschnitt ist mit initialisierten Variablen gefüllt, sodass beim Entpacken der Kernel-Binärdatei in den Speicher alle diese Variablen aus dem kompilierten Image geschrieben werden. Mit System.map als Referenz habe ich eine ziemlich doofe binäre Suche implementiert. Zum größten Teil habe ich die Linker verschiedener C-Dateien durchsucht. Ich habe eine Variable gefunden, mit der ich vergleichen kann. hat die Kernel-Datei gefunden, die sie enthält; Lege meine magische Struktur neben mich in eine zufällige Datei und beginne zu sehen, ob das Problem erneut auftritt.



Die Suche ging zu den letzten .data-Elementen über und kam mit leeren Händen zurück. Es waren keine Daten im Speicher mit initialisierten Variablen erforderlich. Beim Durchblättern der System.map-Datei stellte ich fest, dass ich nicht auf den gesamten .bss-Abschnitt geachtet hatte, der nicht initialisierte Variablen enthielt. Aus Fehlern der Vergangenheit gelernt, habe ich zuerst den Anfang und das Ende überprüft. Natürlich führte eine nicht initialisierte Variable am Anfang eines Abschnitts zu Fehlern, während eine Variable am Ende eines Abschnitts dies nicht tat. Den Täter zu finden war nur eine Frage der Zeit. Die Variable, deren Bewegung das Problem verursachte, war ...



Funktionszeiger ?!



Wie zum Teufel stürzt die Funktionszeigerausrichtung unser System ab? In der ARM-Architektur können Sie beim Zugriff ohne Ausrichtung keine Wörter lesen. Das heißt, jede 32-Bit-Variable muss an einer Adresse gespeichert werden, die ein Vielfaches von 4 ist. Ein Funktionszeiger ist keine Ausnahme, er erhält immer die Mindestadresse. Es stellt sich heraus, dass in unserer Problemsituation die Adresse ein Vielfaches von 2 n war , größer oder gleich 64. Jeder Wert unter diesem Schwellenwert - und das Problem verschwand. Es gab auch Ordnung mit Zeigerausrichtung.



Es gibt keine gute Ausrichtung. Zumindest nicht bevor dieser Fehler auftrat.



Dieser Funktionszeiger war kein "Großvater" -Zeiger. Er bezog sich auf etwas Besonderes. Es gab einen Bereich im Prozessor-SRAM, den wir für lastbezogene Aufgaben verwenden konnten, wenn wir keinen RAM verwenden konnten. Um im Leerlauf Energie zu sparen, haben wir eine Unterroutine in diesen Bereich kopiert, einen speziellen Zeiger gesetzt, der darauf verweist, und sie dann aufgerufen. Was machte das Unterprogramm? Werfen wir einen Blick auf den Assembler. Ich bin kein ARM-Assembler-Experte, aber die Kommentare waren ziemlich beredt.



//       ... 
... 
//       LPDDR   


Was machen sie?! Sie sind schnell von den grundlegenden Registeroperationen zum Deaktivieren des Speichercontrollers übergegangen. Ich schickte eine E-Mail an den Hersteller, der das Unterprogramm schrieb und fragte, ob ihm etwas fehlte.



Drei Tage später erhielt ich eine Antwort im Stil von "Oh ja, es muss eine Gedächtnisbarriere geben." Es stellt sich heraus, dass sie aufgrund der Struktur ihres L2-Cache zusätzlich TLB unterstützen müssten, wenn wir versehentlich ein Vielfaches von 64 in die Speicheradresse geschrieben hätten. In solchen Fällen können wir den RAM weiterhin verwenden, wenn der Controller ausgeschaltet ist.



In Anbetracht der Tatsache, dass die Variablenausrichtung eine minimale Multiplizität von 4 erfordert und dass der letzte Datensatz keine Multiplizität von 64 oder mehr aufweisen kann, war bei jeder Zusammenstellung ein Sechzehntel der Daten für das System vollständig unbrauchbar.



Am Ende haben wir ein zuverlässiges Produkt mit einer Speicherbarriere ausgeliefert, und die Kunden waren begeistert. Ja, und falls Sie sich fragen, konnte ich es mit dem USB-Kabel nicht bemerken, da wir aufgrund der USB-Nutzung nicht in den Energiesparmodus wechseln konnten. Dies ist ein reines USB-Problem.



Ungültige Fehlermeldung



In den letzten Stunden des 17. September 1996, einen Tag vor dem geplanten Start des WebTV-Dienstes, versammelte sich unsere Gruppe im Betriebszentrum in Palo Alto. In der Nähe hingen eine Menge Netzwerksystemadministratoren und Entwickler von Service-Software, um den offiziellen Start mitzuerleben.



Als die festgelegte Stunde schlug, begann sich einer der Netzwerker auf seinem WebTV-Gerät zu registrieren. Wir haben verstanden, dass gute Spitznamen schnell enden würden, daher war es wichtig, sich zu registrieren, bevor Benutzer damit beginnen. Außerdem war es schön, unter den Ersten zu sein, die sich für den ersten "echten" Dienst anmeldeten. Zuvor waren alle Konten "einmalige" Testkonten.



Mehrere Leute drängten sich herum, beobachteten ihn beim Tippen auf der Tastatur und fühlten sich schwindelig vor Vorfreude und Schlafmangel. Bryce gab seinen Namen, seine Adresse und andere Informationen ein und begann dann, einen Spitznamen einzugeben. Das war sein Name für eine E-Mail-Adresse. Er tippte "Jazz", was bedeutet, dass seine Mail "jazz@webtv.net" sein sollte. Als er auf der drahtlosen Tastatur die Eingabetaste drückte, hörten wir ein deutliches Geräusch, das auf das Auftreten einer Fehlermeldung hinwies. Alle schauten auf den Bildschirm.



Um zu verstehen, was als nächstes passiert ist, ist es wichtig, ein oder zwei Dinge über den Service zu wissen. WebTV wurde als Familienfernsehgerät positioniert, daher musste nach unlauterer Sprache gesucht und Benutzernamen und andere Informationen herausgefiltert werden, die für Benutzer sichtbar waren. Es ist unmöglich, alles zu fangen, aber es ist nicht schwierig, die offensichtlichen Dinge herauszufiltern.



Die benutzerdefinierten Namen wurden mit einer Liste regulärer Ausdrücke verglichen, sodass sie mit einem Muster abgeglichen werden konnten. Zum Beispiel wird "fu. * Bar" mit allen Namen verglichen, die mit "fu" beginnen und mit "bar" enden. Wenn Sie Ihre Muster sorgfältig auswählen, können Sie ungeheure Variationen wie "Shitake" und "Matsushita", in die Flüche eingebaut sind, fangen und ablehnen.



Der gleiche Mechanismus wurde verwendet, um zu verhindern, dass Benutzer "verbotene" Namen wie "Postmaster", "Root", "Admin" und "Hilfe" auswählen. Wir hatten eine Textdatei wie diese:



admin.*
      "admin".
postmaster
  postmaster.
poop
  .
weenie
  .


Jeder Eintrag bestand aus zwei Zeilen. Der erste war der reguläre Ausdruck, mit dem verglichen werden soll, und die zweite Zeile war die Fehlermeldung, die dem Benutzer angezeigt wurde. Das System las die Datei zwei Zeilen gleichzeitig und als der Benutzer den Namen eingab, wurde sie mit allen regulären Ausdrücken verglichen. Für die erste gefundene Übereinstimmung wurde eine Fehlermeldung angezeigt. Wenn keine Übereinstimmung gefunden wurde, wurde der benutzerdefinierte Name akzeptiert.



Der Code, der die Datei las, wusste, wie man Kommentare überspringt. Aber er wusste nicht, wie er mit leeren Zeilen umgehen sollte.



Jemand nahm Änderungen an der Schimpfdatei vor und fügte dabei eine leere Zeile nach den "reservierten" Namen und vor den Schimpfwörtern hinzu. Wenn der Code die Liste liest, wird die leere Zeichenfolge als regulärer Ausdruck und das darauf folgende Wort als Fehlermeldung verwendet. Ein leerer Zeichenfolgenausdruck stimmt mit allem überein.



Mitternacht. Wir sind alle ein bisschen nervös. Bryce schreibt den Namen und das System antwortet mit einer einfachen Nachricht:





Wir fingen hysterisch an zu lachen. Andere kamen auf uns zu, um herauszufinden, was los war. Wir haben es dem Bildschirm gezeigt. Sie begannen hysterisch zu lachen.



Zu diesem Zeitpunkt saß Mark Armstrong (verantwortlich für die Qualitätssicherung) zusammen mit Bruce Leek (einem der Gründer des Unternehmens) in einem anderen Gebäude vor einem Schalter mit 16 WebTV-Set-Top-Boxen. Dieses Rack mit dem Spitznamen "Racksville" wurde über einen Videomultiplexer an einen großen Fernseher angeschlossen, auf dem Bilder aus allen 16 Boxen gleichzeitig angezeigt wurden. Mark und Bruce begannen, die Set-Top-Boxen über eine Tastatur mit einem Infrarotsender zu registrieren. Wir haben sie über die Gegensprechanlage angerufen:



- Wie läuft es?



- Alles in Ordnung ist.



- Oh gut. Möglicherweise haben Sie bei der Registrierung einige Dinge bemerkt.



- Ja? Wir haben nichts Seltsames bemerkt.



- Beachten.



- Okay. Postleitzahl eingeben ... bisher ist alles in Ordnung. OGO !!!



Auf Bildern von allen 16 Konsolen erschien eine freundliche Nachricht. Die Chefs schlugen vor, dass wir diesen Fehler möglicherweise so schnell wie möglich beheben müssen. Dies schien uns eine großartige Idee zu sein.



Wir haben die Datei repariert und dem Code beigebracht, leere Zeilen zu erkennen und zu ignorieren. Soweit ich weiß, hat WebTV keinem Kunden "f - k" gesagt.



Xbox-Absturzproblem



Zu dieser Zeit arbeitete das Team an einem der ersten Spiele für eine brandneue Konsole namens Xbox. Als die endgültigen Tests beschleunigt wurden, startete QA drei Set-Top-Boxen aus dem Installationsstapel, um nachts automatisierte Tests durchzuführen. Wenn der gestrige Build des Spiels am Morgen noch getestet wurde, zeigte dies seine Stabilität an.



Leider stürzte morgens eine der Konsolen ab. Abstürze sind immer schlimm, aber es war ein äußerst schlimmer Fall: Etwas, das von der Grafikkarte ausgeführt wurde, stürzte das gesamte System ab. Die Diagnose von Grafikkartenproblemen ist schwierig: keine Debugger, keine Stack-Traces, kein Debuggen mit printf. Sie können nur den Code lesen und experimentieren.



So begann die Bug Hunt. Jeden Tag überprüften die leitenden Ingenieure die verfügbaren Beweise, stellten Hypothesen auf und schlossen Möglichkeiten aus. Jede Nacht bekam die Qualitätssicherung ohne Grund einen "zufälligen" Rückgang. "Das ist unmöglich", "Wie passiert das?", "Vielleicht ist das ein Fehler im Compiler?" - alle beliebtesten Hits.



Auf dem Auto der Ingenieure funktionierte das Spiel viele Tage lang perfekt. Dies war jedoch kein Trost, da sich die Frist für den Versand des Spiels zum Drucken und den Versand an die Geschäfte näherte.



Glücklicherweise fanden wir bald ein Muster, wenn auch ein ziemlich seltsames. Das Spiel stürzte nur nachts und nur auf einer der drei Konsolen ab. Wir suchten nach Unterschieden zwischen ihnen. Es ging nicht um das Stromkabel. Nicht in Controllern. DVD nicht in Ordnung. Übertragen Sie die Konsole auf Ihren Tisch - sie fällt nicht herunter. Leg es zurück - es fällt. Es ging um einen bestimmten Stand, den die Qualitätssicherung verwendete.



Nun ist der Prozess des Ausschlusses von Faktoren erforderlich, um alle Variablen auszuschließen. Am Ende versuchte der Ingenieur verzweifelt, die Tischzubehörteile auszutauschen.



Es stellte sich heraus, dass es sich nicht um ein bestimmtes Präfix handelte, das nicht funktionierte. Jedes Präfix auf dieser Tabelle fiel. Mitten in der Nacht. Manchmal muss man sich aus wissenschaftlichen Gründen seltsam verhalten, und dies war einer dieser Fälle. Der Ingenieur setzte sich stoisch auf einen Stuhl, der mit Red Bull-Dosen überzogen war, und Bug Hunt verwandelte sich in Bug Watching. Der Ingenieur schwor, dass er automatisierte Tests auf den Konsolen dieses verdammten Tisches beobachten würde, bis er den Fehler mit eigenen Augen sah.



Die Nacht verging langsam, dann schnell und schließlich brach die Morgendämmerung an. Das Spiel lief weiter. Es war inspirierend. Die Sonne ging auf.



Und dann passierte endlich etwas Interessantes: Ein Strahl der aufgehenden Sonne fiel auf den Tisch. Minute für Minute kroch der Strahl über den Tisch zu den Aufsätzen, sein warmes Leuchten hüllte leise die schwarze Kuppel des Aufsatzes ein.



Welches fiel schnell.



Die erste Xbox hatte ein Problem: Die Grafikkarte könnte fehlerhaft funktionieren, wenn die Temperatur der Konsole einen bestimmten Wert erreicht. Die Software hatte nichts damit zu tun. Ein Hardwareproblem wurde gemeldet, das Spiel wurde veröffentlicht und Red Bull wurde durch Bier ersetzt. Okay, seien wir ehrlich, für Whisky. Eins: Null für die Wissenschaft.



All Articles