Ger ↴
  • Ger
  • Eng
  • Tag cloud
  • Site map
  • Login Login
    Forgot your password?
Lutz Donnerhacke
Navigation
  • Projekte
  • Veröffentlichungen
  • Blog
  • Impressum
  • Datenschutz
  • Suchen

Suche

Die Suche nach "7" ergab 24 Treffer

Patchwoche in Unternehmen

24.04.2025 19:42 Lutz Donnerhacke Tags: Microsoft , Ansible 0

Microsoft veröffentlich am zweiten Dienstag im Monat neue Patches. In größeren Unternehmen wird bei normalen Updates eine Woche auf Unverträglichkeiten getesten und dann die Patches unternehmensweit ausgerollt. In dieser "Patchwoche" sollen auch automatisch Updates ausgerollt werden, in anderen Wochen aber nicht.

Das Problem besteht offensichtlich darin, dass Patches, die auf einem Gerät am Mittwoch in der Patchwoche ausgerollt werden sollen, jeden Monat von Hand mit dem Datum verknüpft werden müssen. So kann der 1. des Monats ein Montag oder Dienstag sein, dann ist der relevante Tag der 16. oder 18. des Monats. Ist der 1. des Monats aber ein Mittwoch, so wäre der relevante Tag am 21. des Monats.

Wie automatisiert man sowas?

Offensichtlich ändert sich an der Situation nichts, wenn der Wochentag und gleichzeitig das Datum erhöht werden: Die gesuchte Woche ist charaterisiert durch die Differenz von Datum und Wochentag.

Diese Differenz bezieht sich auf den Montag (1) als Monatsanfang (1), denn da ist die Differenz 0. Nun soll der Wochenanfang so liegen, als sei der Dienstag der Wochenbeginn. Die Differenz ist für einen Dienstag (2) als Monatsanfang (1) aber -1. Um das wieder auf 0 zu bekommen, muss man diese 1 hinzu addieren.

Um die Woche zu ermitteln teilt man einfach durch 7 und verwirft den Rest. 0 ist dann die erste Woche, 1 die Woche, in der der Microsoft veröffentlicht und 2 die Woche, in der regulär gepatcht werden soll.

Die Formel lautet also: (Monatstag - Wochentag + 1)/7 == 2

Als Shellscript sieht das so aus:

$ cat patchwoche-mache
#! /usr/bin/bash

[ 2 -eq $[$(/usr/bin/date +'(%-d-%u+1)/7')] ] || exit
exec mache "$@"

Nun steht einem generischen Crontab nichts mehr im Wege:

# Daueraufgaben
0 2 * * 1      mache am montag
0 2 * * 2      mache am dienstag
0 2 * * 3      mache am mittwoch
0 2 * * 4      mache am donnerstag
0 2 * * 5      mache am freitag
...
0 2 * * 3      patchwoche-mache am mittwoch
...

Und tut.

Impfstopp - eIne politische Fehlentscheidung?

16.03.2021 13:45 Lutz Donnerhacke Tags: Corona 0

Wenig erfreulich sind die Meldungen der letzten Tage, die in einer bedauerlichen Entscheidung Gestern mündeten. Ein Impfstoff wurde ausgesetzt, so dass sehr viel Unsicherheit in die aktuellen Impfvorgänge kommt (Impfungen fallen aus, auch notwendige Zweitimpfungen). Der Grund für diese Vorsichtsmaßnahme sind ein ungewöhnliche Häufung einer sehr speziellen Erkrankung (Sinusvenenthrombose).

Der Normalfall (ohne Impfung) wird so beschrieben: Die genaue Häufigkeit von Sinusthrombosen ist unbekannt. Es wird geschätzt, dass jährlich 3–5 Neuerkrankungen pro 1 Million Einwohner auftreten. Frauen sind im Verhältnis 3:1 häufiger als Männer betroffen. Das mittlere Erkrankungsalter liegt bei 30–40 Jahren.

Die aktuelle Beobachtung (nach Impfung mit AstraZeneca) spricht von 7 Neuerkrankungen pro 1 Million Einwohner. Es sind 6 Frauen und 1 Mann betroffen. Das Erkrankungsalter liegt bei 25–40 Jahren. Kurz gesagt liegt das gleiche Bild vor, wie bei dem Fall ohne Impfung (auch das gleiche Verhältnis und die Altersgruppe) Allerdings halt in den Wochen, in denen geimpft wird, nicht übers ganze Jahr. Es kann natürlich auch daran liegen, dass man sich als Geimpfter etwas genauer selbst beobachtet und damit bislang unentdeckte Thrombosen zum Arzt gelangen. Ein Faktor zehn, der hier auftritt wäre so leicht zu erklären.

Wenn über Spätfolgen oder Langzeitfolgen von Impfungen gesprochen wird, ist genau das gemeint: Sehr selten auftretende Effekte kann man nur beobachten, wenn man sehr viele Personen impft. Der Effekt tritt also erst spät und lange nach Impfbeginn ein, für den betroffenen Einzelfall allerdings binnen weniger Tage. Wer eine Woche nach einer Impfung beschwerdefrei ist, hat nichts mehr zu befürchten, der Impfstoff ist dann nicht mehr im Körper und das Immunsystem ist trainiert. Das unterscheidet eine Impfung (einmalige Aktion) von einem Medikament (häufige, dauerhafte Anwendung). Impfungen haben keine individuellen Langzeitfolgen, wenn man von der erreichten Immunität gegen die Krankheit absieht.Kleiner Einschub: Wenn man noch etwas länger beobachtet, wie in Großbritannien, dann verschwinden die Auffälligkeiten im statistischen Mittel wieder. Es wird interessant sein, ob eine Nachprüfung dort etwas findet.

Soweit zum wissenschaftlichen Teil der Geschichte und damit zur Überlegung des Paul-Ehrlich-Institutes, die für die Impfstoffsicherheit zuständig sind. Man beobachtet ein Verstärktes Auftreten einer sehr seltene Krankheit und vermutet einen Zusammenhang mit einem Impfstoff. So hatte man schon länger von Thrombosen nach Impfungen (bei allen Impfstoffen) gehört und sich beim PEI sicher gedacht: "Das ist immer noch um den Faktor 1000 weniger Risiko als ein Urlaubsflug nach Malle." Erst als es die doch sehr seltenen Sinusthrombosen wurden, war es Zeit zum Handeln.

Aus rein wissenschaftlicher Sicht ist es jetzt an der Zeit, zu untersuchen, ob überhaupt eine Zusammenhang besteht, also ob die Sinusthrombosen AN oder MIT der Impfung auftraten. Dazu braucht man einige Tage. Es ist im Sinne eines wissenschaftlichen Experimentes nun sinnvoll, diese paar Tage mit dem Impfen aufzuhören und das Ergebnis (AN oder MIT) abzuwarten. Möglicherweise handelt es sich um eine hormonelle Abhängigkeit, die für ältere Männer gar nicht zu treffen kann. Man könnte dann also die entsprechende Risikogruppe (junge Frauen, die hormonell verhüten) mit einem anderen Impfstoff impfen. Solche spezifischen Empfehlungen für bestimmte Gruppen sind völlig normal. So ist beispielsweise der BioNtec Impfstoff nicht für schwere Allergiker geeignet.

Und wenn man schon mal dabei ist die Gruppe der hormonell verhütenden jungen Frauen anzuschauen, dann ist dort die Sinusthrombose-Wahrscheinlichkeit bei 30 pro Million und Jahr, was so ziemlich genau der Beobachtung mit dem Impfstoff entspricht. Dann wäre der Impfstoff nicht mal schuld. Er wäre nur das Auswahlkriterium bei der Betrachtung der sowieso erfolgten Krankheitsfälle. Muss man halt untersuchen.

Apropos BioNtec: Lust auf die Liste der beobachteten Auffälligkeiten AN oder MIT Impfstoffen? Hier lang (und dann den Rest des Blogs)

Jetzt aber zur politischen Diskussion, die das eigentliche Ärgernis darstellt. Bekommt ein Gesundheitspolitiker die Information aus der Wissenschaft, dass das was auffällig ist und man besser mal ein paar Tage zurück tritt, dann kann man durchaus einen generellen Impfstopp anordnen. Diese Entscheidungen sind aber immer eine politische Abwägung von verschiedenen Auswirkungen. Würde dei Politik wirklich auf die Wissenschaft hören, hätten wir schon Ende September einen harten, kurzen Lockdown gehabt und wären in ein glückliches virenfreies Weihnachtsgeschäft Anfang Dezember gegangen, die wir mit unbeschwerten Feiern in der Familie gekrönt hätten.

Zur politischen Entscheidung gehört also die Abwägung. Wie viel und welchen Schaden richtet diese Entscheidung, das Impfen auszusetzen an? Schließlich ist Impfstoff generell knapp und die 3. Welle nimmt richtig Fahrt auf. Bereits geimpfte Personen werden von der 3. Welle verschont (sowohl als Infektionstreiber als auch als Kranke). Und man macht einen Impfstoff, den man schon mehrfach durch fragwürdige Kommunikation grundlos in ein schlechtes Licht gerückt hat, für größere Teile der Bevölkerung völlig kaputt. Und das wegen ein paar Tagen?

Hier kommt ein zweiter Faktor ins Spiel, der ebenso ärgerlich ist. Die Medien (nicht nur die sozialen). Quotengeil und aufmerksamkeitshaschend bauscht unsere Medienlandschaft jeden Einzelfall zu einer nationalen Katastrophe auf, anstatt ihrem journalistischen Anspruch gerecht zu werden: Fakten recherieren, Gefahren in ein Gesamtbild einsortieren und die Bevölkerung aufzuklären.

PS: Wer Verschwörungstheorien kommentieren will, schaut sich bitte zuerst die Preispolitik von AstraZeneca an und dann die Sponsorenliste der großen Parteien, die über die Gesundheit maßgeblich entscheiden.

standort ospf 7

standort ospf 7

TCAM full - Überraschender Totalausfall

07.11.2020 09:52 Lutz Donnerhacke Tags: IPv6 , Internet , Cisco , WTF , Broadband , Multicast , QoS , ARP 5

Gestern gegen Mittag gab es bei einem Kunden eine großen Ausfall, drei zentrale Switche (von sechs) haben beinahe gleichzeitig nicht mehr ordnungsgemäß funktioniert. Es folgte stundenlange eine Odyssee, denn nach einem Reboot eines Switches hatte man knapp eine halbe Stunde bis er wieder ausfiel.

Ausgangslage

Nichts geht mehr. Spontan. Ohne Vorwarnung.

Alle Geräte, die hinter der Ausfallstelle sich befinden sind nicht mehr erreichbar. Kunden, Infrastruktur, Monitoring. Da auch DNS Server betroffen sind, gestaltet sich jeder Zugriff extrem zäh. Man wartet also teilweise eine Minute, bis man die Ergebnisse eines Kommandos zu Gesicht bekommt.

Eigentlich ist Redundanz gegeben: Wenn ein Gerät ausfällt, übernimmt ein anderes. Jetzt ist es aber anders. denn drei Geräte sind zeitgleich ausgefallen. Diese dienen dem Großteil der Infrastruktur als Uplink, was die Diagnosemöglichkeiten drastisch einschränkt.

In der Annahme, es handle sich um ein Problem, dass von einer defekten Komponente (z.B. ein Layer2-Loop) an einer Stelle eingespeist wird, wurde zunächst systematisch versucht, diese Stelle einzukreisen. Erfolglos.

Es blieb nichts weiter übrig, als einem der betroffenen Switche das Chassis stromlos zu machen, um Zugriff auf das Gerät zu bekommen und damit mehr Informationen zu erlangen. Vor einem solchen Hart-Reset scheut man normalerweise zurück, weil der komplette Reboot knapp 20 Minuten dauert.

Der Zugriff auf das frisch gebootet Gerät zeigt ... keine Auffälligkeiten. Das ist schlecht. Sehr schlecht. Denn damit gibt es keinen Ansatzpunkt, wo der Fehler her kommen könnte. Nach wenigen Minuten friert jedoch die Verbindung zum Gerät ein und es geht wieder nichts mehr.

In einer der Phasen gelingt es, Zugriff auf das Monitoring zu erlangen, dort findet sich ein erster Hinweis:

Nov  6 12:36:41 172.27.44.252 %C4K_L3HWFORWARDING-4-TCAMFULL: FLC Tcam full, packets will be forwarded in software at reduced rate.  Failure due to: add tcam space failed
Nov  6 12:38:41 172.27.44.254 %C4K_L3HWFORWARDING-4-TCAMFULL: FLC Tcam full, packets will be forwarded in software at reduced rate.  Failure due to: add tcam space failed
Nov  6 12:52:12 172.27.44.253 %C4K_L3HWFORWARDING-4-TCAMFULL: FLC Tcam full, packets will be forwarded in software at reduced rate.  Failure due to: add tcam space failed

Oops. Die Meldung besagt, dass eine Hardware-Komponente voll gelaufen ist und nun die gesamte Funktion des Gerätes durch Software emuliert werden muss. Dabei die die CPU des Gerätes für eine solche Last gar nicht ausgelegt, sie soll eigentlich nur die Hardware konfigurieren, so dass die Datenströme die CPU selbst nie treffen.

Das erklärt einige der Effekte: Zum einen fällt das Gerät selbst nicht aus, so dass die Umschaltung auf die Redundanztechnik nicht stattfinden kann. Zum anderen erfüllt es seine Funktion nicht mehr ausreichend. Wir haben Paketverluste von 99%, was einer Unbenutzbarkeit gleich kommt.

TCAM - ein teurer Spaß

Was ist nun dieses ominöse TCAM? TCAM ist im Endeffekt eine Hardware, in der Key-Value-Paare abgelegt werden können. Man kann direkt nach dem Schlüssel (Key) suchen und bekommt in einem Takt das Ergebnis aus dem TCAM ausgelesen. Das ist natürlich irre schnell.

Diese gute Einführung in die Funktion des TCAM enthält das schöne Funktionsbild:

cam-architecture

Auf einem TCAM Chip sind also Speicherzellen, die parallel die anliegende Datenanfrage mit den abgelegten Werten vergleichen und – wenn alles überein stimmt – die komplette Zeile aktivieren. Kann der Vergleicher nur 0/1, spricht man von CAM – Content Addressable Memory. Kann der Vergleicher auch den anliegenden Wert ignorieren, also einen dritten Zustand abbilden, so spricht man von TCAM – Tenary CAM.

Normalerweise müsste eine CPU den normalen Speicher nach dem Suchwert durchkämmen, um das Ergebnis zu ermitteln. Je nach Algorithmus dauert das, logarithmisches Wachstum der Suchzeit ist aber typisch. Dagegen hat der TCAM eine konstante Suchzeit von eins, das Ergebnis ist instantan verfügbar.

TCAM macht also die Geräte schnell, jedoch auch teuer. Deswegen versucht man den TCAM so effektiv wie möglich zu nutzen. Dabei trifft der Hersteller eine Reihe von Kompromissen.

Ein Teil des TCAM wird für QoS, ein Teil für ACLs, ein Teil für Layer2 (MAC Adressen), ein Teil für Layer3 (Routing), etc. pp, benutzt.

Wer hat meinen TCAM belegt?

Die Meldung im Log deutet darauf hin, dass der Layer3, also der Routing-Teil zu voll wird.

Das Datenblatt des Geräts schreibt:

  • 128,000 Flexible NetFlow entries in hardware
  • 64,000/32,000 IPv4/IPv6 routing entries for campus access and aggregation deployments
  • IPv6 in hardware, providing wire-rate forwarding for IPv6 networks and support for dual stack with innovative resource usage
  • Dynamic hardware forwarding-table allocations for ease of IPv4-to-IPv6 migration
  • Scalable routing (IPv4, IPv6, and multicast) tables, Layer 2 tables, and access-control-list (ACL) and quality-of-service (QoS) entries to make use of 8 queues per port and comprehensive security policies per port

All diese Punkte haben mit TCAM Kapazitäten zu tun.

Wir haben in dem Netz ca. 2500 IP4 Routen (meist für Kunden mit statischen IPs) und ca. 8000 IPv6 Routen (hauptsächlich IPv6-PD). Das liegt weit unter den Limits.

Wir haben pro Gerät höchstens 35k MAC Adressen, das haben wir aber schon lange im Blick und sorgen dafür, dass diese Werte nicht in kritische Bereiche ansteigen.

Wir haben NetFlow aktiv. Das ist verzichtbar, also wird das abgeschaltet. Keine Besserung.

Wir haben Multipath-Routing aktiv, um Datenpakete über mehrere Leitungswege zu verteilen. Das ist meist auch verzichtbar und wird dort abgeschaltet. Keine Besserung.

Wir haben anti-spoofing ACLs aktiv, die schon wichtig sind. Aber vor der Wahl – gar keine Funktion oder Bösewichter aufhalten – fällt die Entscheidung leicht, besonders, da wir es bisher nicht mit Bösewichtern zu tun hatten und es noch weitere Filter tiefer im Netz gibt. Allerdings auch wieder keine Besserung.

Was bleibt denn noch?

Schauen wir uns das TCAM für Layer3 mal genauer an:

#sh platform hardware ip route summary

block#  start   end     mode    entries used    free    group   type
0       80 Bit  0       4095    4096    4096    0       3       Dst
1       160 Bit 4096    8190    2048    104     1944    5       Dst
2       160 Bit 8192    12286   2048    439     1609    4       Dst
3       80 Bit  12288   16383   4096    4096    0       3       Dst
4       80 Bit  16384   20479   4096    4096    0       3       Dst
5       80 Bit  20480   24575   4096    4095    1       3       Dst
6       80 Bit  24576   28671   4096    4096    0       3       Dst
7       80 Bit  28672   32767   4096    4094    2       3       Dst
8       80 Bit  32768   36863   4096    4096    0       3       Dst
9       80 Bit  36864   40959   4096    3454    642     3       Dst
10      Unused  40960   45055   4096    0       4096    -       -
11      Unused  45056   49151   4096    0       4096    -       -
12      Unused  49152   53247   4096    0       4096    -       -
13      Unused  53248   57343   4096    0       4096    -       -
14      Unused  57344   61439   4096    0       4096    -       -
15      Unused  61440   65535   4096    0       4096    -       -

Das TCAM ist in 16 Blöcke unterteilt, von denen noch sechs Blöcke frei sind. Die anderen Blöcke sind entweder mit 80bit oder 160bit Schlüsselbreite konfiguriert und verschiedenen Funktionsgruppen zugeordnet. Sie liefern Ziele (vermutlich für Routingentscheidungen).

Auffällig ist, dass die 160bit Blöcke nur die Hälfte der Einträge fassen können, wie die 80bit Blöcke. Es ist jedoch nur logisch, da für die Schlüssel doppelt so viel Platz brauchen.

group#  inUse   mode    type      lookup  entries free    util%   rangeId
0       yes     80 Bit  uRPF Ipv4 Src     0       0       100     0
1       yes     160 Bit uRPF Ipv6 Src     0       0       100     1
2       yes     160 Bit SpecSrc   Src     0       0       100     255
3       yes     80 Bit  UC Ipv4   Dst     32768   645     98      0
4       yes     160 Bit MC Ipv4   Dst     2048    1609    21      1
5       yes     160 Bit UC Ipv6   Dst     2048    1944    5       2
6       yes     320 Bit MC Ipv6   Dst     0       0       100     3
7       yes     160 Bit SpecDst   Dst     0       0       100     255
8       yes     160 Bit OtherL3   Otr     0       0       100     4

        range
0       [ipv4: 0.0.0.0 - ipv4: 255.255.255.255]
1       [ipv6: :: - ipv6: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]
2       [null]
3       [ipv4: 0.0.0.0 - ipv4: 223.255.255.255]
4       [ipv4: 224.0.0.0 - ipv4: 239.255.255.255]
5       [ipv6: :: - ipv6: FEFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]
6       [ipv6: FF00:: - ipv6: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]
7       [null]
8       [ipv4: 0.0.0.0 - ipv6: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]

Hier haben wir die Verwendungszwecke der TCAM Blöcke. Für reverse Path Filtering (das jetzt abgeschaltet ist) wird also die Source-Adresse als Schlüssel verwendet. Für IPv4/v6 Routing wird die Zieladresse als Schlüssel benutzt. Soweit so wenig überraschend.

Eher überraschend ist, dass Multicast doppelte Breite benötigt. Multicast Routing funktioniert anhand der Zielgruppe (einer IP) und der Quell-IP (einer IP), es ist also doch keine Überraschung.

Was Spec und OtherL3 ist, weiß ich nicht. Das kommt hier schlicht nicht vor.

        blocks
0       (0)
1       (0)
2       (0)
3       (8)  0, 3, 4, 5, 6, 7, 8, 9
4       (1)  2
5       (1)  1
6       (0)
7       (0)
8       (0)

Auch die Zuordung der logischen Gruppen zu den physikalischen Blöcken ist nachvollziehbar. Es ist genau das, was bei der Auflistung der Blöcke schon stand.

entity        total     used      free      util%
Entries       61440     32639     28801     53
  uRPF Ipv4   0         0         0         0
  uRPF Ipv6   0         0         0         0
  UC Ipv4     32768     32091     677       97
  MC Ipv4     2048      438       1610      21
  UC Ipv6     2048      110       1938      5
  MC Ipv6     0         0         0         0
  SpecDst     0         0         0         0
  SpecSrc     0         0         0         0
  OtherL3     0         0         0         0
  unused      24576     24576     0         100

Diese Zusammenfassung zeigt die relevanten Kenngrößen.

  • Von den (80bit)-Einheiten des TCAM sind 53% belegt.
  • IPv4 Routing hat 32091 Einträge aktiv, damit sind von den aktuell allozierten Blöcken 97% belegt.
  • IPv4 Multicast hast 438 Einträge, was von dem einzigen allozierten Block 21% ausmacht.
  • IPv6 Routing belegt mit 110 Einträgen in dem einzigen allozierten Block 5%

Wesentlich ist hier fest zu halten, das die Aussage im Datenblatt etwas euphemistisch formuliert wurde. Das TCAM wird für alle Protokolle gemeinsam benutzt, dabei passen maximal 32k IPv6 Routen rein, wenn nichts anderes auf der Maschine läuft. 64k IPv4 Routen passen nur, wenn nichts anderes damit gemacht wird. Sobald IPv4 und IPv6 oder Multicast oder uRPF gemischt werden, sinken die entsprechenden freien Blöcke rasant.

Die relevante Kenntgröße zur Überwachung ist also die Prozentzahl rechts oben (53%) oder noch besser die Zahl der freien Blöcke (die man sich als unused/4096 berechnen muss).

Gestern sah das anders aus. Wir hatten über 20000 Einträge bei IPv6 Routing und dazu noch die uRPF Belegungen. Damit war der der TCAM erschöpft.

Weiter oben sprach ich von ca 2500 IPv4 Routen, hier stehen nun 32091. Warum? Mit IPv6 war es gestern ähnlich, warum?

#sh ip route summary
IP routing table name is default (0x0)
IP routing table maximum-paths is 8
Route Source    Networks    Subnets     Replicates  Overhead    Memory (bytes)
application     0           0           0           0           0
connected       0           50          0           3640        9200
static          2           525         0           40264       96968
ospf 1          2           2084        0           150192      392168
  Intra-area: 156 Inter-area: 68 External-1: 1565 External-2: 0
  NSSA External-1: 297 NSSA External-2: 0
internal        18                                              108332
Total           22          2659        0           194096      606668

Die 2681 passen gar nicht mit den 32091 zusammen. Was ist da los?

Der Catalyst routet nicht wie ein normaler Router, sondern ist ein Layer3-Switch. Er benutzt das TCAM, um in einem einzelnen Schritt, das Ziel eines eingehenden Paketes zu ermitteln. Das Verfahren nennt sich Cisco Express Forwarding und ist der Grund dafür, dass die Geräte ebenso schnell switchen wie routen.

#sh ip cef summary
IPv4 CEF is enabled for distributed and running
VRF Default
 32097 prefixes (32093/4 fwd/non-fwd)
 Table id 0x0
 Database epoch:        2 (32097 entries at this epoch)

Das passt sehr gut (die Werte sind dynamisch und der TCAM Wert zeigt nun 32124). Aber was enthält CEF nun genau?

# sh ip cef
Prefix               Next Hop             Interface
5.102.167.0/26       192.168.255.18       Vlan29
5.102.167.128/29     192.168.255.18       Vlan29
10.10.10.10/32       217.17.207.163       Vlan115
10.100.0.0/16        attached             Vlan142
10.100.0.0/32        receive              Vlan142
10.100.0.1/32        receive
10.100.0.3/32        receive              Vlan142
10.100.0.4/32        attached             Vlan142
10.100.0.5/32        attached             Vlan142
10.100.1.1/32        attached             Vlan142
10.100.1.2/32        attached             Vlan142
10.100.1.3/32        attached             Vlan142
10.100.1.7/32        attached             Vlan142
10.100.1.9/32        attached             Vlan142
...

Es enthält die Routing-Einträge (wie erwartet) und alle Nachbarschaftseinträge (unerwartet). Damit ist mit einem Lookup im TCAM sofort ein neuer Layer2-Header verfügbar, der an einem bestimmten Interface raus geblasen werden kann. Er verweist entweder direkt auf die MAC Adresse des Zieles oder auf die MAC Adresse des nächsten Routers.

Dazu kommt, dass diese CEF hier distriuted ist, d.h. die verschiedenen eingesteckten Line-Cards haben ihr eigenes TCAM, dass analog befüllt wurde. Im Idealfall verläßt also eine eingehendes Paket nicht mal die Linecard sondern geht direkt auf einem anderen Port der gleichen Karte wieder raus.

Da diese Einträge im CEF auch die MAC Adressen enthalten, haben sie direkt mit den ARP Tabellen zu tun.

#sh arp summary
Total number of entries in the ARP table: 29979.
Total number of Dynamic ARP entries: 29800.
Total number of Incomplete ARP entries: 143.
Total number of Interface ARP entries: 36.
Total number of Static ARP entries: 0.
Total number of Alias ARP entries: 0.
Total number of Simple Application ARP entries: 0.
Total number of Application Alias ARP entries: 0.
Total number of Application Timer ARP entries: 0.

Das passt also sehr gut zusammen.

Und wieder ist die Dokumentation zumindest ungenau. Es ist also nur dann 64k IPv4 Routen möglich, wenn die Ziele alle zu wenigen externen Geräte weiter geleitet werden müssen. Sobald es verschiedene Ziele für eine Route gibt, reicht das nicht mehr aus. Im Extremfall kann man also höchstens ein fast voll besetztes /16 lokal anbinden und schon geht gar nichts mehr.

Bei IPv6 halbieren sich die erreichbaren Zahlen. Bei Multicast noch einmal.

Ich bin solche Mogel-Aussagen von Cisco nicht gewöhnt. Ich bin ehrlichweise etwas ungehalten.

Lösung

Was nun tun?

Von den Kisten muss zuerst einmal das IPv6 runter. Große Layer2-Segmente mit SLAAC füllen das TCAM so schnell, dass es irgendwann platzt. Deswegen waren auch nur Geräte betroffen, die zwei solche Anbindungen versorgen. Mittlerweile ist die IPv6 Adoption der Endgeräte so weit angestiegen, dass es die TCAM Grenzen gerissen hat. Natürlich ist das allein kein Grund, dass alle drei Geräte gleichzeitig betroffen waren, sie waren aber alle in anderen Konstellationen kurz vor der Grenze und haben deswegen einen weiteren Anstieg anderswo im Netz nicht verkraftet.

IPv6 ist aktuell kein Vertragsbestandteil beim Kunden, deswegen muss für die IPv6-Versorgung eine andere Lösung gefunden werden, die nicht am TCAM knabbert. Wie genau die aussehen wird, ist noch nicht klar.

Nach einem beherzten "no ipv6 nd prefix ..." und einem "no ipv6 address 2a01:..../64" auf den dicken Kunden-Leitungen, ist Ruhe eingekehrt.

Und dabei bleibt es jetzt erst einmal.

Bleibt noch die Frage, ob sich das System selbst heilen kann. Was passiert also, wenn die TCAM-Blöcke nicht mehr von der zugeordneten Gruppe benötigt werden?

block#  start   end     mode    entries used    free    group   type
0       80 Bit  0       4095    4096    4096    0       3       Dst
1       160 Bit 4096    8190    2048    56      1992    5       Dst
2       160 Bit 8192    12286   2048    195     1853    4       Dst
3       80 Bit  12288   16383   4096    4094    2       3       Dst
4       80 Bit  16384   20479   4096    4096    0       3       Dst
5       80 Bit  20480   24575   4096    4092    4       3       Dst
6       80 Bit  24576   28671   4096    4019    77      3       Dst
7       160 Bit 28672   32766   2048    0       2048    5       Dst
8       80 Bit  32768   36863   4096    3383    713     3       Dst
9       160 Bit 36864   40958   2048    1       2047    5       Dst
10      160 Bit 40960   45054   2048    3       2045    5       Dst
11      160 Bit 45056   49150   2048    1       2047    5       Dst
12      160 Bit 49152   53246   2048    2       2046    5       Dst
13      Unused  53248   57343   4096    0       4096    -       -
14      Unused  57344   61439   4096    0       4096    -       -
15      Unused  61440   65535   4096    0       4096    -       -

Ganz einfach. Sie sind verloren.

Block 7 wurde für IPv6 Routing allokiert und nun nicht mehr benötigt. Er wird aber nicht als unbenutzt zurück gegeben. Er ist verloren. Ebenso wie die anderen Blöcke 9 bis 12.

Die einzige Möglichkeit TCAM wieder frei zu bekommen, ist also ein Reboot des Geräts. Das kann man aber planen.

Auch für die Kennzahlen der Überwachung ist dieser Zustand lehrreich:

entity        total     used      free      util%
Entries       51200     24004     27196     46
  uRPF Ipv4   0         0         0         0
  uRPF Ipv6   0         0         0         0
  UC Ipv4     24576     23767     809       96
  MC Ipv4     2048      174       1874      8
  UC Ipv6     12288     63        12225     0
  MC Ipv6     0         0         0         0
  SpecDst     0         0         0         0
  SpecSrc     0         0         0         0
  OtherL3     0         0         0         0
  unused      12288     12288     0         100

Mit 46% frei schaut es doch gar nicht so schlecht aus, oder? Aber es sind nur die Hälfte der Blöcke frei, wie beim anderen, weniger belasteten, Gerät.

Bandbreite im DHCP

09.10.2020 18:15 Lutz Donnerhacke Tags: Broadband 0

DHCP-Pakete, die über Broadband-Infrastruktur wie DSLAMs laufen, werden providerseitig mit Zusatzinformationen angereichert. Beispielsweise mit Angaben zur Leitungsqualität und Bandbreite. Diese Informationen auszulesen und ggfl. auch selbst setzen zu können ist entweder Bitpfriemelei oder eine Konfiguration des ICS DHCP-Servers.

Rohe Bits

Selbstverständlich ist es möglich, die Daten unterwegs mitzuschneiden und aus dem Binärblob zu extrahieren. RFC4243 definiert dazu die Suboption 9 in der DHCP Option (82) die für das DHCP-Relay zuständig ist. In dieser Option sind herstellerspezifische Dinge abgelegt.

Das Extrahieren per Perl ist einfach:

my $d = Net::DHCP::Packet->new($data);
die "Not a DHCP packet.\n" unless $d->isDhcp;

my $bbf;
my $o82 = $d->getOptionRaw(82);
if(defined $o82) {
    my %o = unpack('(CC/a)*', $o82);
    if(%o) {
        my $o9 = rfc4243($o{9});
        if(exists $o9->{3561}) {
            $bbf = BBF($o9->{3561});
        }
    }
}

sub rfc4243($) {
    local $_ = shift;
    my %r = unpack('(NC/a)*',$_);
    return \%r;
}

sub BBF($) {
    local $_ = shift;
    my %c = unpack('(CC/a)*',$_);

    foreach(keys %c) {
        if($_ >= 129 && $_ <= 142) {
            ($c{$_}) = unpack('N', $c{$_});
        } elsif($_ >= 155 && $_ <= 162) {
            ($c{$_}) = unpack('N', $c{$_});
        }
    }
    return \%c;
}

Im Ergebnis bekommt man einen Hash-Referenz in $bbf in die Hand, die die Angaben der eingefügten Optionen nach Broadbandforum (Vendor-ID 3561) enthält.

Im Einzelnen sind das:

my %bbfnames = (
    129 => 'Actual data rate Upstream in kbps',    # from client
    130 => 'Actual data rate Downstream in kbps',  # from client
    131 => 'Minimum Data Rate Upstream in kbps',
    132 => 'Minimum Data Rate Downstream in kbps',
    133 => 'Attainable Data Rate Upstream in kbps',
    134 => 'Attainable Data Rate Downstream in kbps',
    135 => 'Maximum Data Rate Upstream in kbps',   # from server
    136 => 'Maximum Data Rate Downstream in kbps', # from server
    137 => 'Minimum Data Rate Upstream in low power state in kbps',
    138 => 'Minimum Data Rate Downstream in low power state in kbps',
    139 => 'Maximum Interleaving Delay Upstream in milliseconds',
    140 => 'Actual interleaving Delay Upstream in milliseconds',
    141 => 'Maximum Interleaving Delay Downstream in milliseconds',
    142 => 'Actual interleaving Delay Downstream in milliseconds',

    155 => 'Expected throughput (ETR) upstream in kbps',
    156 => 'Expected throughput (ETR) downstream in kbps',
    157 => 'Attainable expected throughput (ATTETR) upstream in kbps',
    158 => 'Attainable expected throughput (ATTETR) downstream in kbps',
    159 => 'Gamma data rate (GDR) upstream in kbps',
    160 => 'Gamma data rate (GDR) downstream in kbps',
    161 => 'Attainable gamma data rate (ATTGDR) upstream in kbps',
    162 => 'Attainable gamma data rate (ATTGDR) downstream in kbps',
);

Man kann dann also über das Feld {130} der Variable $bbf auf die aktuelle Downloadgeschwindigkeit in kbps zugreifen.

ISC DHCP

Natürlich sind solche Programmierungen bei der Benutzung fertiger Software, wie dem DHCPD von ISC, nicht möglich. Hier muss mit Bordmitteln die Option auseinander genommen werden. Es ist nahezu unmöglich, die Substrukturen auf Bitebene selbst zu parsen, dass muss der Daemon schon allein hin bekommen. Aber dafür braucht er Hilfe.

Man muss der Software erklären, wie die Option strukturiert sind, damit sie die parsen kann. Zunächst einmal erkläre ich den RFC4243.

option space rfc4243 code width 4 length width 1 hash size 7;
option agent.vendor code 9 = encapsulate rfc4243;

Es wird eine neuer Optionsbereich definiert, der intern mit 32bit Codenummern arbeitet. Da ich nur eine Handvoll Codes auch real definieren will, lass ich die Hashtable auf einer kleinen Primzahl (hier 7) stehen, um RAM zu sparen.

Dieser Optionsbereich wird dann als Suboption 9 an die vordefinierte "agent" Option 82 eingehängt. Der Server weiß also bereits, wie Option 82 zu parsen ist, kennt nun auch die innere Struktur der Unteroption 9: Eine komplette eigene DHCP-Optionsstruktur mit eigenen Code- und Längenangaben.

Man sieht auch gleich, dass die Struktur (rfc4243) nicht den gleichen Namen haben muss wie die Option (vendor).

option space bbf code width 1 length width 1 hash size 257;
option rfc4243.bbf code 3561 = encapsulate bbf;

In analoger Weise wird die Substruktur des Vendors Broadbandforum definiert. Wenn in der Suboption 9 der (32bit) Code 3561 auftaucht, so ist der gesamte Datenbereich dieses Feldes wieder eine DHCP-Optionsstruktur mit 8bit-Code und 8bit-Länge. Diesmal will ich aber mehr Codes definieren, mache also die Hashtable größer.

option bbf.actual-up-rate code 129 = unsigned integer 32;
option bbf.actual-down-rate code 130 = unsigned integer 32;
option bbf.minimum-up-rate code 131 = unsigned integer 32;
option bbf.minimum-down-rate code 132 = unsigned integer 32;
option bbf.attainable-up-rate code 133 = unsigned integer 32;
option bbf.attainable-down-rate code 134 = unsigned integer 32;
option bbf.maximum-up-rate code 135 = unsigned integer 32;
option bbf.maximum-down-rate code 136 = unsigned integer 32;
option bbf.maximum-up-lowpower-rate code 137 = unsigned integer 32;
option bbf.maximum-down-lowpower-rate code 138 = unsigned integer 32;
option bbf.maximum-delay-up code 139 = unsigned integer 32;
option bbf.actual-delay-up code 140 = unsigned integer 32;
option bbf.maximum-delay-down code 141 = unsigned integer 32;
option bbf.actual-delay-down code 142 = unsigned integer 32;

option bbf.expected-throughput-up code 155 = unsigned integer 32;
option bbf.expected-throughput-down code 156 = unsigned integer 32;
option bbf.attainable-throughput-up code 157 = unsigned integer 32;
option bbf.attainable-throughput-down code 158 = unsigned integer 32;
option bbf.gamma-data-rate-up code 159 = unsigned integer 32;
option bbf.gamma-data-rate-down code 160 = unsigned integer 32;
option bbf.attainable-gamma-data-rate-up code 161 = unsigned integer 32;
option bbf.attainable-gamma-data-rate-down code 162 = unsigned integer 32;

Hier wurden die für mich interessanten Werte definiert. Der Server kann also beim Parsen der Unterstruktur anhand des (8bit) Codes erkennen, um welchen Wert es geht und wie dieser in interpretieren ist (als uint32 in Netzwerkbyteorder).

Und wie greift man auf die Werte zu?

log (info, concat("BBF: ",
            binary-to-ascii(16, 8, ":", hardware),
            " current speed ",
            binary-to-ascii(10, 32, ".", option bbf.actual-down-rate),
            "/",
            binary-to-ascii(10, 32, ".", option bbf.actual-up-rate)
          ));

Die Loganweisung an passender Stelle in der Konfig erzeugt dann eine Menge Einträge.

Oct  9 18:55:26 dhcpd: BBF: 1:e0:28:6d:aa:bb:cc current speed 5999/639
Oct  9 18:55:27 dhcpd: BBF: 1:34:31:c4:dd:ee:ff current speed 50000/9999
Oct  9 18:55:29 dhcpd: BBF: 1:38:10:d5:gg:hh:ii current speed 54999/11000 

Tut.

Selbstbau eines A10NSP Gateways

11.03.2020 21:58 Lutz Donnerhacke Tags: IPv6 , Internet , BSD , Dokumentation , CPE , Fernsehen , QoS 0

Ein Kunde wünscht eine bezahlbare, skalierbare Lösung für den Anschluss von xDSL-Kunden, die per L2-BSA von der DTAG zugeführt werden. Natürlich sollen die eigenen Produkte erhalten bleiben, die Kunden in ihrem Router - wie gewohnt - den richtigen Provider auswählen, kurz gesagt, ein Telekom-Anschluss soll so funktionieren wie ein direkt durch den Kunden betriebener DSL Zugang.

Aufgabenstellung

Der Anschluss beim Endkunden wird als Ethernet-Übergabe mit mehreren (einfach getaggten) VLANs ausgeführt. Der Kunde soll dort alle VLANs nutzen können, die auch sonst an einem direkt versorgten Anschluss zur Verfügung stehen.

Es soll Triple-Play möglich sein, also nennen wir die benötigten VLANs mal 140 für Internet, 141 für IPTV und 142 für VoIP. Die Nummern sind egal, es können auch 7, 18 und 4012 benutzt werden. Wichtig ist nur, dass alle Pakete am Anschluss nach einem festen Schema getaggt übergeben werden. Dieses Schema wird durch die Auswahl des Providers in der CPE (z.B. Fritzbox) des Endkunden festgelegt.

VLANs am Kundenanschluss
Payload (z.B. IP)
C-VLAN Tag
Source-MAC
Destination-MAC

Ein L2-BSA Zugang durch die DTAG sammelt nun die einfach getaggten Pakete (C(ustomer)-Tag) ein, versieht sie mit einem zusätzlichen VLAN-Tag (S(erviceprovider)-Tag), anhand dessen die Transporttechnik der DTAG den Endkundenport wieder identifizieren kann und übergibt die Pakete dann doppelt getaggt an uns. Umgekehrt erkennt die DTAG anhand des äußeren S-Tags, an welchen Kundenanschluss die Pakete raus fallen sollen. Das S-Tag wird entfernt und das C-Tag ist beim Kunden sichtbar.

VLANs am Übergabesanschluss
Payload (z.B. IP)
C-VLAN Tag
S-VLAN Tag
Source-MAC
Destination-MAC

Dieses Verfahren hat mehrere Konsequenzen:

  • Das S-Tag charakterisiert die Verbindung zwischen Kundenanschluss und Provider.
  • Hinter dem S-Tag stehende C-Tags, Protokolle oder gar MAC-Adressen sind dem Transportweg komplett egal.
  • Auf diese Weise können beliebig viele Endgeräte hinter einem Anschluss versorgt werden.
  • Es können auch beliebige Produkte (IPv4, IPv6, ...) angeboten werden.
  • Da sich die DTAG für die Inhalte der Pakete nicht interessiert, übernimmt sie auch keine Multicast-Replikation z.B. für IPTV. Wenn also fünf Teilnehmer einen Sender schauen, müssen die Pakete fünf mal (mit unterschiedlichen S-Tags) gesendet werden.
  • Pro Kundenanschluss benötigt man ein anderes, eindeutiges Tag. Dieses muss von dem Transportprovider, der DTAG, verwaltet werden.
  • Somit sind pro Übergabeanschluss (BNG) nur ca. 4000 Kundenanschlüsse möglich (Wertebereich von VLAN Tags)

Die DTAG behält sich vor, dass sie das S-Tag pro neuem Verbindungsaufbau (DSL-Sync) neu vergibt. Ist der Kunde also bisher unter dem S-Tag 432 sichtbar gewesen, so kann er nach einem Reset seines Routers oder einer Leitungsstörung spontan unter dem neuen S-VLAN 874 auftauchen. Pakete, die in Richtung Kunden mit dem S-Tag 432 geschickt werden, kommen also von jetzt auf gleich nicht mehr an.

VLANs am Übergabesanschluss
Payload (z.B. IP) Daten Daten
C-VLAN Tag 140 140
S-VLAN Tag 432 874
Source-MAC 01:02:03:04:05:06 01:02:03:04:05:06
Destination-MAC 01:02:03:07:08:09 01:02:03:07:08:09
  vorher nachher

Interessanterweise besteht die DTAG bei einer umgekehrten Versorgung mit L2-BSA durch ein Netz eines anderen Providers darauf, dass die S-Tags pro Kunde fix bleiben und sich nicht ändern dürfen.

Da bisher das Netz wie eine große L2-Wolke betrachtet wurde, sollen die neuen Anschlüsse ebenso funktionieren.

Darüber hinaus gibt es ein Problem durch die unterschiedlichen Anschlussbandbreiten. Die DTAG möchte keinesfalls bei Produktwechseln (andere Anschlussbandbreite) involviert sein, also:

  • handelt sie selbst in Richtung Endkunden die höchstmögliche Geschwindigkeit aus, die die Technik her gibt.
  • verpflichtet sie den Provider, nicht mehr Bandbreite dem Endkunden zur Verfügung zu stellen, wie dieser lt. Produktbeschreibung verkauft hat, auch wenn der Anschluss schneller synchronisierte.
  • verpflichtet die den Provider, nicht mehr Bandbreite zum Endkunden zu schicken, als dessen Anschluss auch real her gibt, selbst dann, wenn die verkaufte Bandbreite höher ist.
  • bietet sie dem Provider gewisse reservierte Bandbreiten mit besonderen QoS-Zusagen, z.B. geringer Jitter (für VoIP) oder minimaler Paketverlust (für IPTV).

Um den Provider zur Einhaltung dieser Regeln zu zwingen (und damit der Überlastung des eigenen Netzes entgegen zu wirken), sind Verletzungen dieser Regeln vertraglich strafbewehrt.

Von der Idee zur Umsetzung

Konzentriert man sich allein auf das S-Vlan Problem, so genügt es anhand der MAC Adresse herauszufinden auf welchem Weg das Paket ursprünglich herein gekommen war. Stellt man sich jedes S-Vlan als eigene Leitung vor, so würde ein Switch mit 4096 Ports die Aufteilung bestens erfüllen: Er lernt anhand der Source-MAC, auf welchem Interface das Paket rein kam, und schickt die Antworten (mit der Ziel-MAC) auch dahin zurück. Kommt die MAC mal von einem anderen Interface (geändertes S-Tag), lernt er um.

Natürlich stellt man sich nicht einen Switch mit derartig vielen Interfaces real hin. Schließlich kommen diese 4000 "Leitungen" pro Anschluss an einen BNG. Für ein kleines Bundesland wie Thüringen, sind das einige Hundert Zuleitungen, die wir aber nicht alle brauchen, weil wir ja selbst ein Netz haben. Die Überschlagsrechnung ergibt: 2,3 Mio Einwohner = 600k Haushalte = 150 BNGs (Minimum)

Anderseits sind sicher nicht alle Haushalte fest als Kunden zu planen, sondern nur ein kleiner Teil wird wechseln wollen. Von den potentiell 4000 "Leitungen" werden nur wenige belegt sein. Es wäre also völlig abstrus, hier dauerhaft alle möglichen Verbindungen offen zu halten. Dazu kommt, dass Broadcast-Traffic (z.B. ARP) an alle potentiellen Teilnehmer gesendet werden müssen. Hält man also alle potentiellen "Leitungen" offen verviertausendfacht man den Traffic. Unnötigerweise.

  1. Der erste Schritt war die Erstellung eines Testbeds, dass die verwendete Anschlusstechnik simulieren kann. Dies wird ausführlich in einem eigenen Artikel dargestellt.
  2. Da zur Terminierung keine realen Switche verwendet werden, sondern preisgünstige Server, landen mehrere BNG-Zuleitungen auf einem Server. Es ist sinnvoll, diese Zuleitungen zu aggregieren, um nicht für jede Zuleitung ein eigenes Terminierungsnetz verwalten zu müssen. Damit werden aus doppelt getaggten Paketen - dreifach getaggte. das zusätzliche A-Tag gibt an, welches Zuleitungs-Interface gerade angesprochen werden soll. Auch das wird in einem eigenen Artikel ausgeführt.

    VLANs nach Aggregation
    Payload (z.B. IP)
    C-VLAN Tag
    S-VLAN Tag
    A-VLAN Tag
    Source-MAC
    Destination-MAC
  3. Da in jedem C-Vlan die MAC-Adressen des Kunden gleich sein dürfen, ist für die weitere Verarbeitung eine Trennung nach C-Vlans nötig. Auch QoS-Einstellungen sind dienstabhängig. Die C-Vlans stehen aber ganz innen im VLAN-Stapel. Es war notwendig, den Stapel zur rotieren, so dass aus der Abfolge C/S/A-Vlan die Abfolge S/A/C-Vlan wird. Nach dieser Rotation steht das C-Vlan direkt zur Verfügung und es kann je nach Dienst getrennt verarbeitet werden. Ein entsprechendes Netgraph-Modul ng_vlan_rotate wurde erstellt.

    VLANs nach Rotation
    Payload (z.B. IP)
    S-VLAN Tag
    A-VLAN Tag
    C-VLAN Tag
    Source-MAC
    Destination-MAC
  4. Was nun noch bleibt, sollte eigentlich leicht sein: Die doppelt getaggten VLANs (außen A, innen S) müssen wieder auseinander genommen, und über ein Netgraph-Modul ng_bridge mit dem Ausgang zum Providernetz verbunden werden. Unglücklicherweise kann das Modul aber nur 32 Links verbinden, viel zu wenig! Aber wie verbindet man die Links nur bei Bedarf? Auch das wird in einem eigenen Artikel ausgeführt.

    VLANs pro Dienst
    Payload (z.B. IP)
    S-VLAN Tag
    A-VLAN Tag
    Source-MAC
    Destination-MAC
  5. Und woher kommen die QoS-Parameter, damit die Leitungen nicht überlastet werden? Die stehen in den DHCP-Paketen: Die DTAG schreibt in die Option82/9 die aktuelle Bandbreite rein. Das muss natürlich ausgewertet werden. Wenn man schon mal an der Stelle ist, kann man mit der Antwort vom DHCP-Server auf die gleiche Weise auch die verkaufte Produkt-Bandbreite übermitteln. Auch das wird in einem eigenen Artikel ausgeführt.

Alles zusammen genommen besteht das Netgraph Netzwerk aus folgenden Komponenten:

L2BSA Netgraph Übersicht

In den Tests zeigten sich dann weitere Probleme:

  • Die MAC-Adress-Tabelle der ng_bridge und die Anzahl der VLANs an einem ng_vlan wird schnell so groß, dass die Daten nicht mehr ausgewertet werden können.
  • Noch ein paar Daten mehr und sie passen nicht mal mehr durch die Kernel-API.
  • Natürlich ist es komplett sinnfrei, auf dem Uplink zum ISP hin die MAC Adressen zu lernen. Das entschärft einen Großteil der Probleme.

Und tut's?

Wie man mit tcpdump auf doppelt getagged Pakete prüft

20.02.2020 16:03 Lutz Donnerhacke Tags: BSD 0

Für einen bpf Filter benötige ich die Möglichkeit mehrfach mit VLANs getaggte Pakete zu erkennen und in deren Inhalt nach protokollspezifischen Werten zu durchsuchen. Natürlich möchte ich die binären Regeln nicht komplett von Hand schreiben.

Der einfache Ansatz ist sich das Regelwerk durch tcpdump selbst erzeugen zu lassen.

# tcpdump -s 0 -p -d 'ip and udp and src port 12345'
(000) ldh      [12]
(001) jeq      #0x800           jt 2    jf 10
(002) ldb      [23]
(003) jeq      #0x11            jt 4    jf 10
(004) ldh      [20]
(005) jset     #0x1fff          jt 10   jf 6
(006) ldxb     4*([14]&0xf)
(007) ldh      [x + 14]
(008) jeq      #0x3039          jt 9    jf 10
(009) ret      #262144
(010) ret      #0

Dieser Code macht folgendes:

  • Im Ethernet-Header (an Position 12) wird der Ethertype ermittelt.
  • Ist der IPv4 (0800), so geht's bei 2 weiter, anderenfalls Abbruch zu 10.
  • Im IP-Header (an Position 23 aus Sicht des kompletten Frames) steht die Protokollnummer.
  • Ist diese UDP (17 = 0x11), geht's weiter.
  • Nach dem variabel langen IP-Header (Länge in 32bit Worten an Position 14) folgt der UDP Header.
  • Dort steht an (der variablen) Position die Portnummer.
  • Entspricht die dem gewünschten Wert, gibt's einen positiven Rückgabewert (der i.d.R. die Länge der zu exahierenden Daten entspricht).
  • Anderenfalls gibt es den Fehlercode 0 zurück (oder auch 0 verwertbare Bytes).

Oder direkt binär, so wie ich es brauche:

# tcpdump -s 0 -p -ddd 'ip and udp and src port 12345'
11
40 0 0 12
21 0 8 2048
48 0 0 23
21 0 6 17
40 0 0 20
69 4 0 8191
177 0 0 14
72 0 0 14
21 0 1 12345
6 0 0 262144
6 0 0 0 

Dieser BPF Code nimmt an, dass das Paket direkt mit IP beginnt, es gibt keine VLAN Frames (die jeweils 4 Byte kosten).

Ich lönnte jetzt also an allen Stellen, wo auf eine Position im Paket Bezug genommen wird, einen entsprechenden Offset manuell hinzufügen. Dieses manuelle Nachpatchen ist jedoch nicht sonderlich wartungsfreundlich.

Nach einigem Suchen fand ich den undokumentierten Befehl vlan. Wenn man den vor den Ausdruck stellt, passt das tcpdump den BPF-Filter passend an.

# root@a10nsp:~ # tcpdump -s 0 -p -d 'vlan 123 and ip and udp and src port 12345'
(000) ldh      [12]
(001) jeq      #0x8100          jt 4    jf 2
(002) jeq      #0x88a8          jt 4    jf 3
(003) jeq      #0x9100          jt 4    jf 17
(004) ldh      [14]
(005) and      #0xfff
(006) jeq      #0x7b            jt 7    jf 17
(007) ldh      [16]
(008) jeq      #0x800           jt 9    jf 17
(009) ldb      [27]
(010) jeq      #0x11            jt 11   jf 17
(011) ldh      [24]
(012) jset     #0x1fff          jt 17   jf 13
(013) ldxb     4*([18]&0xf)
(014) ldh      [x + 18]
(015) jeq      #0x3039          jt 16   jf 17
(016) ret      #262144
(017) ret      #0 

Man sieht sehr schön, dass die Offsets für die Paketanalyse schön um vier Bytes verschoben wurden.

Gehen auch zwei VLANs?

# tcpdump -s 0 -p -d 'vlan 123 and vlan 456 and ip and udp and src port 12345'
(000) ldh      [12]
(001) jeq      #0x8100          jt 4    jf 2
(002) jeq      #0x88a8          jt 4    jf 3
(003) jeq      #0x9100          jt 4    jf 24
(004) ldh      [14]
(005) and      #0xfff
(006) jeq      #0x7b            jt 7    jf 24
(007) ldh      [16]
(008) jeq      #0x8100          jt 11   jf 9
(009) jeq      #0x88a8          jt 11   jf 10
(010) jeq      #0x9100          jt 11   jf 24
(011) ldh      [18]
(012) and      #0xfff
(013) jeq      #0x1c8           jt 14   jf 24
(014) ldh      [20]
(015) jeq      #0x800           jt 16   jf 24
(016) ldb      [31]
(017) jeq      #0x11            jt 18   jf 24
(018) ldh      [28]
(019) jset     #0x1fff          jt 24   jf 20
(020) ldxb     4*([22]&0xf)
(021) ldh      [x + 22]
(022) jeq      #0x3039          jt 23   jf 24
(023) ret      #262144
(024) ret      #0

Hervorragend: Nun werden doppelt getaggte Pakete ausgewertet. Allerdings muss man die VLAN Tags exakt kennen.

Ich möchte aber nur double tagged VLANs mit variablen VLAN-Nummern bearbeiten, kenne diese also nicht. Wie kann man das beschreiben? Vielleicht als Negation? Nicht VLAN 123? Gibt es eine VLAN Nummer die sicher nicht auftreten kann?

ja, die Null. Eine VLAN Header mit der VLAN-ID 0 ist definiert als untagged, gestattet aber QoS Parameter. Untagged will ich aber nicht, das ist also okay.

# tcpdump -s 0 -p -d 'not vlan 0 and not vlan 0 and ip and udp and src port 12345'
(000) ldh      [12]
(001) jeq      #0x8100          jt 4    jf 2
(002) jeq      #0x88a8          jt 4    jf 3
(003) jeq      #0x9100          jt 4    jf 6
(004) ldh      [14]
(005) jset     #0xfff           jt 6    jf 22
(006) ldh      [16]
(007) jeq      #0x8100          jt 10   jf 8
(008) jeq      #0x88a8          jt 10   jf 9
(009) jeq      #0x9100          jt 10   jf 12
(010) ldh      [18]
(011) jset     #0xfff           jt 12   jf 22
(012) ldh      [20]
(013) jeq      #0x800           jt 14   jf 22
(014) ldb      [31]
(015) jeq      #0x11            jt 16   jf 22
(016) ldh      [28]
(017) jset     #0x1fff          jt 22   jf 18
(018) ldxb     4*([22]&0xf)
(019) ldh      [x + 22]
(020) jeq      #0x3039          jt 21   jf 22
(021) ret      #262144
(022) ret      #0

Und tut!

Wenn der Traceroute Kreise tanzt

25.07.2018 13:24 Lutz Donnerhacke Tags: WTF , BSD 0

Manchmal überrascht einen eine Trivialität. Ich wollte das Routing einer Server-IP prüfen, aber der Trace wurde zu mir zurück reflektiert. Wie geht das?

Wunder

traceroute to 178.19.224.48 (178.19.224.48), 30 hops max, 40 byte packets
 1  switch1-9-4-1-vl52.net.iks-jena.de (217.17.197.11)  1.470 ms  1.372 ms  1.304 ms
 2  turm1-g001.net.iks-jena.de (217.17.197.49)  0.382 ms  0.438 ms  0.363 ms
 3  rudo8-t001-116.net.encoline.de (5.102.160.98)  0.613 ms  0.574 ms  0.566 ms
 4  switch3-v93.net.encoline.de (5.102.160.161)  1.465 ms  1.141 ms  1.170 ms
 5  server16-vlan58.net.encoline.de (5.102.160.132)  0.567 ms  0.538 ms  0.541 ms
 6  switch4-v94.net.encoline.de (5.102.160.178)  2.181 ms  1.469 ms  1.686 ms
 7  server16-vlan94.net.encoline.de (5.102.160.185)  0.641 ms  0.635 ms  0.575 ms
 8  switch2-v58.net.encoline.de (5.102.160.129)  9.887 ms  3.478 ms  1.380 ms
 9  rudo7-t000-123.net.encoline.de (5.102.160.90)  0.879 ms  0.740 ms  0.721 ms
10  turm1-g001-116.net.iks-jena.de (5.102.160.99)  0.991 ms  0.942 ms  1.012 ms
11  * * *
12  nat-178-19-224-48.net.encoline.de (178.19.224.48)  1.123 ms  1.052 ms  1.025 ms

Der Trace geht raus, kehrt um, kommt zurück und am Ende meint er das Ziel erreicht zu haben.

Dabei trifft er sogar bestimmte Router mehrfach. Das ist deswegen verwunderlich, weil doch die Router ihre Entscheidung allein anhand der Zieladresse fällen. Wie kann also das Paket in verschiedene Richtungen geroutet werden?

Zunächst erst einmal handelt es sich nicht um ein lokales Phänomen, sondern es funktioniert auch von anderen Quellen aus.

traceroute to 178.19.224.48 (178.19.224.48), 30 hops max, 60 byte packets
...
 4  inexio2.gw.network.manitu.net (89.238.127.62)  4.593 ms  4.594 ms  4.592 ms
 5  209-096-244-077.ip-addr.inexio.net (77.244.96.209)  7.633 ms  7.634 ms  7.642 ms
 6  DE-CIX1.de.lambdanet.net (80.81.193.74)  7.605 ms  7.358 ms  6.739 ms
 7  ae2.irt2.fra25.de.as13237.net (217.71.96.45)  7.881 ms  7.878 ms  7.584 ms
 8  ae5.irt1.han87.de.as13237.net (217.71.96.30)  13.407 ms  13.380 ms  13.390 ms
 9  ae7.irt1.ber02.de.as13237.net (217.71.96.133)  16.610 ms  16.613 ms  16.607 ms
10  bb-erf-02-loc.netz.netkom-line.net (109.73.31.198)  213.352 ms  213.364 ms  213.361 ms
11  tnk-ilm-001-loc.netz.netkom-line.net (109.73.31.195)  22.149 ms  20.946 ms  20.579 ms
12  109.73.31.141 (109.73.31.141)  147.983 ms  147.987 ms  147.974 ms
13  tnk-jen-001-loc.netz.netkom-line.net (109.73.31.193)  19.504 ms  19.453 ms  19.471 ms
14  tnk-jen-001-ipt.netz.netkom-line.net (109.73.31.194)  19.468 ms  19.468 ms  19.467 ms
15  rudo7-t010.net.encoline.de (5.102.160.105)  33.994 ms  34.003 ms  34.002 ms
16  switch2-v123.net.encoline.de (5.102.160.91)  34.350 ms  34.407 ms  34.573 ms
17  server16-vlan58.net.encoline.de (5.102.160.132)  33.875 ms  33.879 ms  33.866 ms
18  switch4-v94.net.encoline.de (5.102.160.178)  34.753 ms  35.605 ms  35.596 ms
19  server16-vlan94.net.encoline.de (5.102.160.185)  34.362 ms  34.259 ms  34.179 ms
20  switch2-v58.net.encoline.de (5.102.160.129)  34.800 ms  35.279 ms  34.905 ms
21  rudo7-t000-123.net.encoline.de (5.102.160.90)  34.440 ms  34.203 ms  34.452 ms
22  rudo5-t001-123.net.encoline.de (5.102.160.89)  34.228 ms  34.449 ms  34.435 ms
23  ar2.ber.de.colt.net (213.61.70.177)  55.706 ms  55.705 ms  55.674 ms
24  212.36.135.22 (212.36.135.22)  55.909 ms  56.438 ms  56.417 ms
25  212.36.135.22 (212.36.135.22)  55.398 ms  55.416 ms  55.389 ms
26  * * *
27  * * *
28  * * *
29  nat-178-19-224-48.net.encoline.de (178.19.224.48)  68.590 ms  68.544 ms  68.691 ms

Wow. Hin- und Rückrouting in einem Trace! Man sieht sehr schön den asymmetrischen Rouingweg.

Aber was passiert da?

Schnüffeln

Die Ursache sollte ausschließlich am angesprochenen Server zu suchen sein. Alles andere wäre eine grobe Überraschung, denn dann müßten die Geräte im Transportweg irgendeine Manipulation vorgenommen haben.

Also ein Mitschnitt auf den Außeninterfaces des betroffenen Servers aktiviert:

13:39:51.074580 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 13, length 20
13:39:51.074601 IP 5.102.160.132 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.077408 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 14, length 20
13:39:51.077414 IP 5.102.160.132 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.077939 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 15, length 20
13:39:51.077944 IP 5.102.160.132 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.078590 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 16, length 20
13:39:51.079237 IP 5.102.160.178 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.082388 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 17, length 20
13:39:51.084253 IP 5.102.160.178 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.084855 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 18, length 20
13:39:51.088146 IP 5.102.160.178 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.088802 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 19, length 20
13:39:51.088848 IP 5.102.160.185 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.092134 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 20, length 20
13:39:51.092176 IP 5.102.160.185 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.092892 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 21, length 20
13:39:51.092934 IP 5.102.160.185 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.093756 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 22, length 20
13:39:51.093774 IP 178.19.224.48 > 217.17.192.34: ICMP echo request, id 60099, seq 22, length 20
13:39:51.097201 IP 5.102.160.129 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.100803 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 23, length 20
13:39:51.100823 IP 178.19.224.48 > 217.17.192.34: ICMP echo request, id 60099, seq 23, length 20
13:39:51.101499 IP 5.102.160.129 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.102261 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 24, length 20
13:39:51.102280 IP 178.19.224.48 > 217.17.192.34: ICMP echo request, id 60099, seq 24, length 20
13:39:51.102924 IP 5.102.160.129 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.103742 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 25, length 20
13:39:51.103763 IP 178.19.224.48 > 217.17.192.34: ICMP echo request, id 60099, seq 25, length 20
13:39:51.103870 IP 5.102.160.90 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.106558 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 26, length 20
13:39:51.106577 IP 178.19.224.48 > 217.17.192.34: ICMP echo request, id 60099, seq 26, length 20
13:39:51.106687 IP 5.102.160.90 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.107389 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 27, length 20
13:39:51.107408 IP 178.19.224.48 > 217.17.192.34: ICMP echo request, id 60099, seq 27, length 20
13:39:51.107510 IP 5.102.160.90 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.108284 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 28, length 20
13:39:51.108302 IP 178.19.224.48 > 217.17.192.34: ICMP echo request, id 60099, seq 28, length 20
13:39:51.108652 IP 5.102.160.99 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.111847 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 29, length 20
13:39:51.111866 IP 178.19.224.48 > 217.17.192.34: ICMP echo request, id 60099, seq 29, length 20
13:39:51.112220 IP 5.102.160.99 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.113013 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 30, length 20
13:39:51.113032 IP 178.19.224.48 > 217.17.192.34: ICMP echo request, id 60099, seq 30, length 20
13:39:51.113386 IP 5.102.160.99 > 217.17.192.34: ICMP time exceeded in-transit, length 36
13:39:51.114062 IP 217.17.192.34 > 178.19.224.48: ICMP echo request, id 60099, seq 31, length 20
13:39:51.114080 IP 178.19.224.48 > 217.17.192.34: ICMP echo request, id 60099, seq 31, length 20
13:39:51.115606 IP 217.17.197.43 > 217.17.192.34: ICMP time exceeded in-transit, length 36

Man sieht sehr schön, wie anfangs die Echo-Pakete mit einem Timeout beantwortet werden.

Kurz darauf (ab Sequenznummer 22) tauchen plötzlich Echo-Pakete auf, bei denen Quell- und Ziel-Adresse vertauscht sind. Diese entstehen offenbar direkt nach dem Eingang des ersten Paketes.

Nun dient die Kiste ein (Carrier Grade)-NAT. Ihr Zweck ist es also Pakete umzuschreiben und zwar so, daß möglichst wenig Pakete verloren gehen. Schließlich dient NAT ja dazu, Verbindungen zu ermöglichen! Eine Firewall oder Paketfilter würde Pakete verwerfen. NAT dagegen muß so gut wie möglich raten, wo das Paket eigentlich hin soll.

In diesem Fall geht das NAT systematisch vor:

  • Es nattet die fremde Quell-Adresse auf die eigene öffentliche IP.
  • Und es nattet die eigene öffentliche Ziel-IP zu – tja wohin, achja, da ist ja ein ganz frischer Eintrag in der NAT Tabelle …

Fertig ist der Spiegel.

Gefährlich?

Kann man das mit allen Protokollen machen? Wenn ja, könnte man trivial unter falscher Flagge segeln, oder?

Tracing the path to 178.19.224.48 on TCP port 80, 30 hops max
 1  switch1-9-4-1-vl4.net.iks-jena.de (217.17.192.125)  6.742 ms  2.125 ms  1.139 ms
 2  turm2-g001-5.net.iks-jena.de (217.17.197.50)  0.228 ms
    turm1-g001.net.iks-jena.de (217.17.197.49)  0.350 ms
    turm2-g000-3.net.iks-jena.de (217.17.197.34)  0.265 ms
 3  rudo8-t001-116.net.encoline.de (5.102.160.98)  0.449 ms  0.468 ms  0.423 ms
 4  switch3-v93.net.encoline.de (5.102.160.161)  1.414 ms  1.570 ms  2.359 ms
 5  server16-vlan58.net.encoline.de (5.102.160.132)  0.489 ms  0.431 ms  0.418 ms
 6  switch4-v94.net.encoline.de (5.102.160.178)  1.443 ms  1.166 ms  1.921 ms
 7  server16-vlan94.net.encoline.de (5.102.160.185)  0.429 ms  0.473 ms  0.444 ms
 8  switch4-v94.net.encoline.de (5.102.160.178)  14.355 ms  2.695 ms  1.462 ms
 9  server16-vlan94.net.encoline.de (5.102.160.185)  0.473 ms  0.495 ms  0.465 ms
...

Nein, man kann nicht. Und das ist gut so™.

Outsourcing mit Hindernissen

20.04.2018 21:00 Lutz Donnerhacke Tags: DNSSEC , WTF 4

Beim Durchsehen der Logfiles stieß ich darauf, dass wiki.mozilla.org nicht erreichbar ist. Grund dafür ist ein externer Dienstleister und ein Fehler, über den sich die Experten uneinig sind. Natürlich hängt es mit DNSSEC zusammen.

$ host wiki.mozilla.org 100.100.100.100
Host wiki.mozilla.org not found: 2(SERVFAIL)

$ host wiki.mozilla.org 10.10.10.10
Host wiki.mozilla.org not found: 2(SERVFAIL)

$ host wiki.mozilla.org 8.8.8.8
wiki.mozilla.org is an alias for www.wiki.prod.core.us-west-2.appsvcs-generic.nubis.allizom.org.
www.wiki.prod.core.us-west-2.appsvcs-generic.nubis.allizom.org is an alias for wiki-prod-1394614349.us-west-2.elb.amazonaws.com.
wiki-prod-1394614349.us-west-2.elb.amazonaws.com has address 52.89.171.193
wiki-prod-1394614349.us-west-2.elb.amazonaws.com has address 34.213.203.225
wiki-prod-1394614349.us-west-2.elb.amazonaws.com has address 54.68.243.126

$ host wiki.mozilla.org 1.1.1.1
wiki.mozilla.org is an alias for www.wiki.prod.core.us-west-2.appsvcs-generic.nubis.allizom.org.
www.wiki.prod.core.us-west-2.appsvcs-generic.nubis.allizom.org is an alias for wiki-prod-1394614349.us-west-2.elb.amazonaws.com.
wiki-prod-1394614349.us-west-2.elb.amazonaws.com has address 34.213.203.225
wiki-prod-1394614349.us-west-2.elb.amazonaws.com has address 52.89.171.193
wiki-prod-1394614349.us-west-2.elb.amazonaws.com has address 54.68.243.126

$ host wiki.mozilla.org 9.9.9.9
Host wiki.mozilla.org not found: 2(SERVFAIL) 

Das ist ein Chaos, oder etwa nicht?

Was sagt denn DNSViz?

wiki.mozilla.org-2018-04-20-18_49_55-UTC

Die Erklärungen zu den Fehlerdreiecken umfassen:

  • Die Liste der Nameserver für allizom.org unterscheidet sich bei der Mutterzone "org" von der realen Zone. Dieser Glue-Mismatch ist aber nicht tragisch.
  • Bestimmte Antworten für SOA etc. werden bei der unsignierten Zone nicht beantwortet. Das wird als kritisch bewertet, ist es aber in der Regel nicht, da diese Anfragen für die Namensauflösung nicht notwendig sind.

Woran scheitert also ein Teil der Nameserver?

unbound info: validation failure <wiki.mozilla.org. A IN>:
 no NSEC3 closest encloser from 184.26.160.65 for DS nubis.allizom.org.
 while building chain of trust 

Was ist denn nubis?

wiki.mozilla.org.  CNAME  www.wiki.prod.core.us-west-2.appsvcs-generic.nubis.allizom.org.
;; Received 107 bytes from 2600:1401:2::f0#53(ns1-240.akam.net) in 16 ms 

Ahja, eine Zwischenzone auf dem Weg zum eigentlichen Ziel.

www.wiki.prod.core.us-west-2.appsvcs-generic.nubis.allizom.org.  CNAME  wiki-prod-1394614349.us-west-2.elb.amazonaws.com.
;; Received 275 bytes from 2600:9000:5302:cf00::1#53(ns-719.awsdns-25.net) in 17 ms 

Der entscheidende Teil ist, dass allizom.org signiert ist.

allizom.org.  SOA infoblox1.private.mdc2.mozilla.com. sysadmins.mozilla.org. 2018032753 180 180 1209600 3600
allizom.org.  RRSIG   SOA 7 2 3600 20180423125954 20180420115954 42215 allizom.org. E...
;; Received 563 bytes from 23.211.133.65#53(use4.akam.net) in 22 ms 

Allerdings scheint die Implementierung der beteiligten Nameserver (oder gar der Quelle, also der Infoblox) defekt zu sein, denn die notwendigen Nichtexistenzbeweise über die Abwesenheit einer sicheren Delegierung (also eine unsichere Delegierung) fehlen.

Genau genommen handelt es sich um ein empty non-terminal, also einen DNS-Namen, den der keine eigenen Datensätze enthält. Stattdessen existiert er ausschließlich virtuell. Denn die reale Delegierung lautet:

appsvcs-generic.nubis.allizom.org. NS   ns-795.awsdns-35.net.
appsvcs-generic.nubis.allizom.org. NS   ns-1743.awsdns-25.co.uk.
appsvcs-generic.nubis.allizom.org. NS   ns-426.awsdns-53.com.
appsvcs-generic.nubis.allizom.org. NS   ns-1109.awsdns-10.org.
;; Received 481 bytes from 2600:1401:2::f0#53(ns1-240.akam.net) in 16 ms

Der Name "nubis.allizom.org" entsteht ausschließlich durch die Verwendung von Punkten im längeren Namen.

DNSSEC ist das aber völlig egal: Der Name ist ein gültiger Name im DNS, also muss darüber eine Aussage her. Und wenn es ein Nichtexistenzbeweis ist. Deswegen verlangt DNSSEC, dass auch für derartige virtuellen "empty non-terminals" entsprechende DNSSEC Records erzeugt werden.

Und genau die fehlen hier.

nubis.allizom.org-2018-04-20-19_30_18-UTC-1

Damit kann ein validierender Resolver nicht beweisen, dass die unsichere Delegation der Zone "appsvcs-generic.nubis.allizom.org" korrekt ist. Es könnte ja ein Man in the Middle versuchen, die mögliche Existenz einer sicheren Delegierung für "nubis.allizom.org" auszufiltern!

An dieser Stelle unterscheiden sich die Implementierungen der DNS-Resolver.

  • Es gibt welche, die jedes noch so kleine Detail prüfen. Wie unbound, den ich für die Server 10.10.10.10 und 100.100.100.100 benutze. Oder knot, der bei 1.1.1.1 läuft.
  • Und es gibt welche, die nur dem eigentlichen Pfad folgen und sich für die Infrastruktur auf andere interne Mechanismen verlassen. Wie Google und Cloudflare.

Interessant ist, dass bei Cloudflare und Google eigene DNS-Implementierungen laufen, die nicht auf die klassischen Opensource-Produkte zurück greifen. Auch Infoblox fährt sein eigenen Süppchen. Und Route66 von Amazon ist auch eine Eigenentwicklung.

Ich bin sehr an einigen Details interessiert, warum die Eigenentwicklungen genau versagen: Die einen beim Erzeugen oder Verteilen, die anderen beim Validieren.

Merke, Mozilla: Größe ist nicht alles.

Vorzeichen oder nicht - das ist die C-Frage

18.09.2017 14:00 Lutz Donnerhacke Tags: WTF 4

Beim Erstellen eines Programms, das Daten aus einem Puffer kratzt, stolperte ich über einen sehr seltsamen Fehler in C. Es kostet mich ernstlich Mühe, das Problem auch nur zu verstehen.

Das Programm

Zuerst habe ich das Problem eingedampft auf ein minimales Beispiel:

#include <stdio.h>

int main(void) {
   int len, step;
   char data[5];

   for(len = 27; sizeof(data) < len; len -= step) {
      step = sizeof(data) + 2; 
      printf("len = %3d, taking %d away.\n", len, step);
   }
}

Was tut das Programm?

  • Es gibt einen Puffer mit einer initialen Länge von 27 Byte.
  • Passt die Struktur nicht mehr in den Restpuffer, brich ab.
  • Solange die gesuchte Struktur aber noch rein passt, verarbeite sie (fehlt im Beispiel).
  • Nach der Verarbeitung verkleinere die Rest-Datenmenge um die verarbeitete Struktur plus ein passendes Alignment (hier fest 2).

Der benutzte Puffer, das Verschieben des Arbeitszeigers und die eigentliche Datenverarbeitung sind in dem Beispiel entfallen.

Überraschung

Und hier die Ausgabe:

len =  27, taking 7 away.
len =  20, taking 7 away.
len =  13, taking 7 away.
len =   6, taking 7 away.
len =  -1, taking 7 away.
len =  -8, taking 7 away.
len = -15, taking 7 away.
len = -22, taking 7 away.
len = -29, taking 7 away.
len = -36, taking 7 away.

Wow! Warum beendet sich das Programm denn nicht?

Die Größe der Struktur ist "5". Das ist ganz bestimmt nicht kleiner als "-1", oder etwa doch?

Ganz offensichtlich ist der Vergleich "5" ist kleiner als  "-1" wahr, aber warum?

Evtl. hab' ich ja irgendwelche Warnungen des Compilers übersehen?

$ cc -O2 -Wall -o t t.c
[ ... nichts ... ]
$ cc --version
FreeBSD clang version 3.9.1 (tags/RELEASE_391/final 289601) (based on LLVM 3.9.1)
Target: x86_64-unknown-freebsd11.0
Thread model: posix
InstalledDir: /usr/bin

Nein, auch nicht.

Erklärung

Wenn der C-Compiler den Wert des "signed int" mit dem Namen "len" in einen "unsigned int" verwandeln würde, dann wäre das Ergebnis erklärt. Der Vergleichwert wäre dann also bei mehr als 4 Mrd., also deutlich größer als die Länge der Struktur.

Aber warum sollt der Compiler eine solche Umwandlung durchführen?

Es bleibt nur ein Blick in die Norm:

  • In 6.5.8 "Relational operators" heißt es: If both of the operands have arithmetic type, the usual arithmetic conversions are performed.
  • In 6.3.1.8 "Usual arithmetic conversions" heißt es: If the operand that has unsigned integer type has  rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with  unsigned integer type.
  • In 6.3.1.1 "Boolean, characters, and integers" heißt es: The rank of any unsigned integer type  shall equal the rank of the corresponding signed integer type.

Für den Vergleich zwischen zwei normalen Integer-Typen – der eine mit, der andere ohne Vorzeichen – gilt also, dass beide Operatoren nach unsigned konvertiert werden: In diesem Fall also von -1 auf 4 Mrd.

Voraussetzung für diese Interpretation ist allerdings, dass der sizeof-Operator einen vorzeichenlosen Integer-Typ liefert. Also wieder die Norm lesen:

  • In 6.5.3.4 "The sizeof operator" heißt es: The result is an integer constant. Huch? Keine Aussage zu Vorzeichen?
  • Etwas später liest man: The value of the result is implementation-defined, and its type (an unsigned integer type) is size_t.

Man müsste also das Spiel gewinnen, wenn man die Variable "len" einen größeren Rank verpasst. Leider klappt das weder mit "long" noch mit "long long".

Erst eine beherzter Cast des sizeof-Operators nach "int" löst das Problem:

#include <stdio.h>

int main(void) {
   int len, step;
   char data[5];
   
   for(len = 27; (int)sizeof(data) < len; len -= step) {
      step = sizeof(data) + 2; 
      printf("len = %3d, taking %d away.\n", len, step);
   }
}

Und das ergibt:

len =  27, taking 7 away.
len =  20, taking 7 away.
len =  13, taking 7 away.
len =   6, taking 7 away.

Ende der Geschichte.

Wer mag, kann mal herausbekommen, ob der Umgang des Compilers im Falle von "long" und "long long" standardkonform ist. Ich habe da meine Zweifel.

Weiter » 1 2 3