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

Search

Search for "NAT" returned 27 matches

Datenfluss visualisiert

24/09/2018 4:41 pm Lutz Donnerhacke Tags: Internet , Dokumentation 3

Wenn ein ISP über seine Außenanbindungen Traffic schaufelt, dann ist es oft Glückssache, welches Leitung wieviel Daten abbekommt. Natürlich wird man gezielt versuchen einige Teilnetze nur auf einigen bestimmten Upstreams zu announcieren, damit genau dort der Traffic auch rein kommt. Aber das Finetuning ist sehr schwer. Man müßte ziemlich genau wissen, welcher Datenstrom zu welcher Zeit auf welchem Weg durchläuft, um die Änderung planen zu können.

Details bitte

Kürzlich hatte ich über Netflow geschrieben. Dort wurden die Datenströme nach Quell- und Ziel-AS summiert. jetzt will ich es detaillierter haben.

Weiterhin benötigt werden nun:

  • Der Router, der die Daten einsammelt.
  • Das Peer-ASN mit dem der Router direkt redet.
  • Der Netzblock, der im globalen Routing auftauchen wird.
  • Und der Schönheit wegen, der lokale Dienst, der den Traffic abbekommt oder initiiert.

Um nicht sämtliche IP Adressen als relevant ansehen zu müssen, definiere ich mir einen neuen Flow pro Richtung:

flow record in
 match routing source as 4-octet
 match routing source as peer 4-octet
 match routing destination as 4-octet
 match ipv4 destination address
 match ipv6 destination address
 collect timestamp sys-uptime first
 collect timestamp sys-uptime last
 collect counter bytes long
 collect counter packets long
flow record out
 match routing source as 4-octet
 match routing destination as 4-octet
 match routing destination as peer 4-octet
 match ipv4 source address
 match ipv6 source address
 collect timestamp sys-uptime first
 collect timestamp sys-uptime last
 collect counter bytes long
 collect counter packets long

Zusätzlich zu den Quell- und Ziel-ASNs nehme ich nun auch noch das Peer-ASN und die Quell- oder Ziel-IP dazu.

So beschränke ich mich auf die IP-Adressen im lokalen Netz (oder halt Transit) und aggregiere auf dem Router schon über die unbekannten externen IPs. Es wäre denkbar, auch IP-Prefixe statt der Adresse zu nehmen, aber ich habe Routing-Objekte, die kleiner sind als einige Prefixe. Also bleibt es bei den Adressen.

IPv4 und IPv6 sind zusammengefaßt, eine von beiden Werten wird schon relevant sein.

Als erste Überraschung präsentiert mir die Ausgabe Peer-ASN an Routern, die gar keine direkte Verbindung zu diesem AS haben!

Es stellt sich heraus, daß das Peer-AS ein abgeleiteter Wert ist, der durch ein Blick in die Routing-Tabelle ermittelt wird. Es zeigt also immer auf das Peer-AS, das der Router genommen hätte, wenn er das Paket jetzt in diese Richtung routen müßte.

Logischerweise ist also das Source-Peer-ASN i.d.R. falsch. Aber auch das Destination-Peer-ASN kann falsch sein, wenn es mehrere gleichberechtigte Wege gibt. Es ist durchaus möglich, das Pakete zum Peer 1 zu schicken und Peer 2 im Netflow zu hinterlegen.

Also stelle ich erstmal auf incoming und outgoing Interface um. Unglücklicherweise kann der Netflow-Collector überhaupt nicht damit umgehen, nur ein Interface zu bekommen. In der Annahme es gäbe beide Interfaces im Flow werden einfach die nächsten zwei Byte nach dem ersten Interface als das fehlende Interface angesehen. Alle anderen Felder werden danach mit einem Offset von zwei völlig fehlerhaft geparst. Also bekommt der Collector seinen Willen und das fehlende Interface (aber nur collected).

flow record in
 match routing source as 4-octet
 match routing destination as 4-octet
 match interface input
 match ipv4 destination address
 match ipv6 destination address
 collect timestamp sys-uptime first
 collect timestamp sys-uptime last
 collect counter bytes long
 collect counter packets long
 collect interface output
flow record out
 match routing source as 4-octet
 match routing destination as 4-octet
 match ipv4 source address
 match ipv6 source address
 match interface output
 collect timestamp sys-uptime first
 collect timestamp sys-uptime last
 collect counter bytes long
 collect counter packets long
 collect interface input

Achja, die Router-IP. Der nfcapd hat mehrere Module, die man getrennt aktivieren muß. Das Modul 13 schreibt die IP-Adresse des Netflow-Sensors (des Routers) mit.

Damit sind die Werte erst einmal erfaßt.

Mach mal bunt

Da mich aktuell nur IPv4 interessiert genügt es für die Auswertung sich darauf zu konzentrieren:

nfdump -r ... -q -N -A srcip4/26,srcas,inif,router,outif,dstas,dstip4/26 -O bps

Dieses Kommando aggregiert auf Basis von /26er Netzen, für die ich händisch im Auswertescript hinterlegt habe, welches Routing-Object und welcher Zweck gemeint sind.

Das Script schreibt die aggregierten Daten alle fünf Minuten in ein Logfile. Es ersetzt dabei die Interfaces pro Router mit den Peer-AS-Werten anhand einer manuellen Zuordnungstabelle.

Das Script versucht des weiteren, Flows von Transit-Traffic korrekt zuzuordnen. Wenn Quell- und Ziel-ASN ungleich Null sind, habe ich Transit.

Sind auf einem Router Quell- und Ziel-Interface einem Peer zugeordnet ist es einfach, wenn nicht muß man den eingehenden Flow einem Ausgehenden zuordnen, der die gleichen Quell- und Ziel-ASNs aufweist. Dabei kann es passieren, daß der Traffic aufspaltet. In dem Fall entnehme ich das Minimum an übereinstimmenden Traffic und ordne den Rest solange weiter zu, bis der Resttraffic unter der Nachweisgrenze verschwindet.

Im Ergebnis entstehen Einträge der Form:

DHCP 91.137.60.0/22 rudo5 8220 other 94
2906 8220 rudo5 178.19.237.0/24 NAT 86
other 196714 rudo7 178.19.228.0/22 NAT 85
2906 8220 rudo8 rudo6 196714 196714 83

Der Flow ist von links nach rechts zu lesen und die letzte Zahl ist der Traffic in Mbps.

Aus diesen Angaben generiert sich mit Javascript ein SVG.

SVG deswegen, weil es interaktiv ist:

  • Man kann die Daten in fünf-Minuten-Schritten auswählen.
  • Fährt man mit der Maus über eine Kurve, so wird diese hervorgehoben und der Eintrag erscheint als Tooltip.
  • Fährt man mit der Maus über ein Rechteck (Router, Peer, Netz, ...) werden alle durchlaufenden Kurven hervorgehoben und man bekommt die Summenbandbreite als Tooltip.
2018-09-24-163642_1280x1024_scrot

Grün ist eingehender Traffic, blau ausgehender und rot ist Transit. Die Dicke der Linie und die Größe der Rechtecke geht linear mit dem Traffic. Router und Peers haben die Größe der maximalen Kapazität. so sieht man den Auslastungsstand.

Mit dieser Darstellung kann ich nachträglich mir anschauen, was zu bestimmten Stoßzeiten im Netz los war. Ich sehe, welche Routing-Objekte evtl. besser über einen anderen Upstream announciert werden könnten. Auf diese Weise kann ich sehr fein abstimmen, wieviel Traffic auf welcher Leitung herein kommt und muß erst wesentlich später neue Bandbreite zukaufen.

Das Aggregationsschema führt allerdings auch in die Irre. Es ist nicht unterscheidbar, ob es 5000 Flows mit 1 Mbps gab oder 10 Flows mit 500 Mbps: Angezeigt werden 5 Gbps. Das fiel auch erst spät auf, als ein Scan über alle IP Adressen trotz nur wenig Mbps sich zu einem gewaltigen Strom aufplusterte. Aber damit muß man aktuell leben.

Performance Probleme mit NAT

26/07/2018 5:44 pm Lutz Donnerhacke Tags: BSD 0

Nach dem Wechsel auf neuere Hardware (10G) und damit verbunden auch auf den aktuellsten Softwarestand von FreeBSD haben die NAT Kisten sporadisch massive Probleme. Ein glücklicher Zufall gestattete zuerst die Diagnose und dann die Lösung des Problems. CPU Last fällt von 90% (pro Prozeß) auf einstellige Werte.

Spikes

Immer wieder kommt es auf einer NAT Kiste zu akuten Performance-Problemen. Dabei bricht der maximal erreichbare Durchsatz pro TCP-Session auf unter 10Mbps zusammen. Oft ist der Gesamtdurchsatz des Systems auf knapp 200Mbps begrenzt, obwohl da drei mal 10G anstecken. (Für den Anschluß des vierten Interfaces fehlt aktuell ein Rack.)

Im CPU Graphen schaut das dann so aus.

stats-thread-peak

Um kurz nach 18 Uhr hatte die betreffende Maschine ein Lastproblem. Allerdings war es schon nach wenigen Minuten wieder weg.

In den meisten Fällen bisher waren die Lastspitzen noch deutlich kürzer, so daß man sie in diesem Graphen nicht mal richtig sieht.

Da allerdings das Problem nur sporadisch auftritt, nicht reproduzierbar ist, und die Beeinträchtigung der Kunden auch nicht lange genug anhält, um zu spezifischen Störungsmeldungen zu führen, war bisher eine Fehlersuche ergebnislos.

Glückliche Zufälle

Gestern erst hatte ich im Zusammenhang mit FreeBSD ein WTF-Erlebnis, das mit NAT zusammenhängt.

Und heute zeigte eine Maschine erstmals einen stabilen Fehlerzustand.

stats-thread-bummer

Wow, was für ein gewaltiger Vorfall! Endlich mal Zeit zum Debuggen.

Mit dem Hintergedanken des gestrigen Erlebnisses im Kopf fiel irgendwann in einem glücklichen Mitschnitt auf, daß es Pakete gibt, bei denen Quell- und Ziel-IP gleich sind. Noch dazu sind diese IPs auch die öffentlichen IPs des NAT.

Ganz offensichtlich kommt es vor, daß irgendein kruder Netzscanner Pakete schickt, die das NAT als gültig ansieht und nattet. Dabei entstehen Pakete, bei denen Quell- und Ziel-IP gleich sind. Und diese landen dann wieder beim NAT. Dabei entstehen Pakete, bei denen Quell- und Ziel-IP gleich sind. Und diese landen dann wieder beim NAT. Dabei entstehen Pakete, bei denen Quell- und Ziel-IP gleich sind. Und diese landen dann wieder beim NAT. Ähm, das Prinzip sollte klar sein.

Also kurz eine Firewallregel hinzugefügt, die Pakete von NAT-IPs an NAT-IPs verwirft.

Jul 26 17:13:37 server12 kernel: ipfw: 2 Deny UDP 178.19.233.4:63647 178.19.233.4:57691 in via vlan94
Jul 26 17:13:37 server12 kernel: ipfw: 2 Deny UDP 178.19.233.4:64584 178.19.233.4:57691 in via vlan94
Jul 26 17:13:37 server12 kernel: ipfw: 2 Deny TCP 91.137.21.7:42512 91.137.21.7:3888 in via vlan94
Jul 26 17:13:37 server12 kernel: ipfw: 2 Deny UDP 178.19.233.4:62012 178.19.233.4:49655 in via vlan94
Jul 26 17:13:37 server12 kernel: ipfw: 2 Deny UDP 178.19.233.4:6763 178.19.233.4:57691 in via vlan94
Jul 26 17:13:37 server12 kernel: ipfw: 2 Deny TCP 91.137.17.4:14938 91.137.17.4:64906 in via vlan94

Und schon fällt die CPU Last der Netzwerk-Interrupts auf einstellige Prozentzahlen.

Fazit

Ursächlich für den Vorfall ist ein Wechsel von quagga zu bird.

Früher mußten die einzelnen NAT-IPs lokal geroutet werden, nun genügt es, die betreffenden Netze im OSPF zu announcen und sie per ipfw auf den Uplinkports abzugreifen. Eine lokale Route gibt es also nicht mehr.

Sollten solche Pakete trotzdem lokal erzeugt werden, verlassen sie das Gerät und kommen vom nächsten Router wieder zurück. Dabei werden sie wieder dem NAT vorgeworfen.

Es ist zwei glücklichen Zufällen zu verdanken, dieses Problem überhaupt finden zu können: Weil es lange genug andauerte und das betreffende Muster gerade frisch bekannt war.

Und nun können die Kisten endlich mal richtig Last aufnehmen. Ich bin gespannt.

Wenn der Traceroute Kreise tanzt

25/07/2018 1:24 pm 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™.

ASA Konfigs auf Konsistenz prüfen

11/01/2018 11:25 am Lutz Donnerhacke Tags: IPv6 , Cisco , Sicherheit , Dokumentation 0

Wir haben eine Reihe von ASAs im Einsatz, die auf Kundenwunsch gepflegt werden. Wie immer betreffen Änderungswünsche nur die Einrichtung von Freischaltungen, aber nie das Wegräumen von Altlasten. Für diesen Fall gibt es zwei Tools, die ich vorstellen möchte.

Information des Kunden

Zunächst ist es wichtig, den Kunden regelmäßig über die aktuelle Konfiguration zu informieren. Trivialerweise würde man ihm die Konfiguration zugänglich machen.

Aber das ist eine schlechte Idee, da die ASAs einiges an Konfiguration enthalten, die man nicht ständig durch die Gegend reichen möchte. Es gibt auch genug Fälle, wo eine ASA mehrere Kunden bedient (z.B. mehrere Hosting-VLANs). Dann darf natürlich keine Information über die Konfiguration für andere Kunden leaken.

Es ist also notwendig, sich auf die wesentlichen und interessanten Teile zu beschränken. In diesem Fall interessiert den Kunden, welche ACLs und welche NAT Regeln für ihn aktiv sind. Was den Kunden interessiert, hängt von den Interfaces ab, die ihm zugeordnet sind.

Das Script mkacl-from-asaconfig.pl liest auf Standardeingabe eine komplette abgespeicherte ASA-Konfig ein, erwartet als Argument die Liste der interessanten Interfaces (nameif) und gibt aus:

  • die den Interfaces zugeordneten access-groupKommandos
  • die den access-group zugeordneten access-list Einträge
  • die den Interfaces zugeordneten nat Kommandos
  • die dabei referenzierten object-group Definitionen
  • die dabei referenzierten object Definitionen

Ganz praktisch sieht das dann so aus:

$ zcat /archiv/cf.asa.20180111.gz | mkacl-from-asaconfig.pl iks-lab
: Written by enable_15 at 11:13:55.766 CET Thu Jan 11 2018
!
!!!!!!
! active ACLs at interfaces
!!!!!
access-group to_lab out interface iks-lab
!!!!!
! ACLs
!!!!!
access-list to_lab extended permit ip object-group iks any 
access-list to_lab extended permit tcp any object obj-lab1 object-group http_s 
access-list to_lab extended permit tcp any object obj-lab2 object-group http_s 
!
!!!!!!
! extra NATs
!!!!!
!!!!!
! Object groups
!!!!!
object-group network iks
 network-object object o4-iks
 network-object object o6-iks
!
object-group service http_s tcp
 port-object eq www
 port-object eq https
!
!!!!!
! Objects
!!!!!
object network obj-lab1
 host 192.168.91.10
 nat (iks-lab,outside) static o4-lab1-public
!
object network obj-lab2
 host 192.168.91.11
 nat (iks-lab,outside) static o4-lab2-public
!
...
!
!!!!!
! Generated at Thu, 11 Jan 2018 13:35:03 +0100

Diese Auszüge können dem Kunden auf definiertem Wege (z.B. Kundenportal) zur Verfügung gestellt werden.

Es gestattet dem Kunden, sich selbst die aktuelle Konfiguration anzusehen und entlastet die Hotline bei uns.

Inkonsistenzen

Ein ganz anderer Teil des Problem sind Inkonsistenzen und Altlasten. Die Definition eines Objektes, das nicht verwendet wird, ist eine Inkonsistenz. Die Verwendung einer IP Adresse, die nicht mehr in Benutzung ist, ist eine Altlast. Beides soll gefunden werden.

Wie eine Konfiguration auszusehen hat, ist selbstverständlich Ansichtssache. Bei uns hat es sich als günstig herausgestellt, sämtliche IP Adressen in Objekten und Objektgruppen zu sammeln, damit diese schon allein anhand ihrer Benennung oder description auch noch Jahre später zugeordnet werden können. Nur mit klarer Zuordnung ist ein späterer Rückbau überhaupt möglich.

Das Script clean-asa-config.pl liest von der Standardeingabe eine komplette Konfigurationsdatei und listet auf, was unstimmig erscheint:

  • Nicht mehr benutzte access-list, object, object-group. name, tunnel-group, class-map, transform-set, crypto map, ...
  • Elemente, die verwendet werden, aber nicht definiert wurden, werden aufgelistet.
  • Es wird das Anlegen von object oder name Definitionen empfohlen, wenn IPs direkt in der Konfiguration stehen.
  • Ist bei Objekten ein DNS-Name zur IP hinterlegt, so wird geprüft, ob der Name noch zu dieser IP auflöst. Es ist nicht empfehlenswert, direkt mit fqdn statt host zu arbeiten, wenn man feststellen will, ob die intendierte Eintragung noch korrekt ist. fqdn sollte man nur bei dynamischen IPs benutzen.
  • Bei name Definitionen wird geprüft, oben IP und Name noch per DNS zusammen passen.
  • Da name Definitionen agnostisch gegenüber der Protokollfamilie sind, wird für IPv4 ein trailing dot am Namen empfohlen, bei IPv6 nicht.
  • Ausgelaufene Zertifikate führen zur Empfehlung, den trust-point zu löschen.
  • Ebenso soll man unvollständige crypto map Einträge löschen.

Die Ausgabe enthält:

  • die Empfehlung incl, Begründung
  • die direkt ausführbaren Kommandos, um die Empfehlung umzusetzen, ohne den Betrieb zu gefährden
  • alle anderen Verwendungen des Namens oder der IP in der Konfiguration

Wenn Euch etwas auffällt, was man noch testen sollte oder könnte ...

ASA mit mehrfacher Default Route

29/11/2017 4:28 pm Lutz Donnerhacke Tags: Cisco , WTF 0

Eine Appliance, die in einer fremden Umgebung Daten einsammelt, soll von extern angesprochen werden. Zum einen muss der Hersteller Fernwartung machen und zum anderen gibt es eine Gruppe von Stellen, die auf die gesammelten Daten zugreifen sollen. Völlig unerwartet wird das geschützte Netzwerk dieser Stellen ebenfalls mit öffentlichen IP Adressen betrieben, so dass für beide Zwecke eine Default Route benötigt wird. Das Ganze soll trotzdem nur mit einer ASA funktionieren. Eine Aufsplittung in mehrere Kontexte (ASA-Virtualisierung) scheitert am fehlenden Support für Remote-Access. Es muss also anders gehen.

Aufgabenstellung

Die Appliance arbeitet in einem anderen, größeren Netzwerk und benutzt selbst nur private IP Adressen (hier 192.0.2.x). Um alle Messstellen erreichen zu können, zeigt die Default Route dieses Gerätes in das fremde Netzwerk (hier grau).

Der Remote-Access Teil (hier grün) ist ein einfaches Setup. Um die vorab unbekannten Clients erreichen zu können, muss die Default Route ins Internet zeigen. Dieser Uplink der ASA benutzt öffentliche IPs (PA-space, hier 189.51.100.x). Die Remote-Access Clients bekommen aus einem Adresspool des lokalen Netzes IPs, so dass sie ohne weiteres Routing auf die Appliance zugreifen können. Von Seiten der Appliance aus erscheint der Client im LAN.

Die ursprüngliche Annahme war, dass die abfragenden Stellen, die über ein extra gesichertes Netzwerk zugeführt werden, ebenfalls in koordinierter Weise mit nicht-öffentlichen Adressen arbeiten würden. In diesem Fall hätte eine spezifische Route zu all diesen Netzen genügt. Allerdings haben die Planer dieses Netzes den Koordinationsaufwand gescheut und verlangen stattdessen, öffentliche IP-Adressen aus dem lokalen PA-Space zu benutzen, der auch normal über Internet erreichbar ist.

ASA multiple default routes

Die Gegenstellen hinter dem geschützten Netzwerk (hier rot) sind vorab ebenso wenig bekannt, wie die Fernwartungs-Clients (grün). In dem hier skizzierten Bild, soll eine solche Gegenstelle eine ganz andere öffentliche IP Adresse haben (hier 203.0.113.133). Um solche Adressen zu erreichen, müsste eine Default Route ins rote Netz gesetzt werden.

Angefasst werden darf nur die ASA, alle anderen Geräte unterliegen fremder Verfügungsgewalt.

Remote-Access

Die Konfiguration für das Remote-Access VPN gemäß Lehrbuch:

interface Ethernet0/0
 nameif green
 security-level 0
 ip address 198.51.100.25 255.255.255.192
!
interface Ethernet0/1
 nameif gray
 security-level 100
 ip address 192.0.2.5 255.255.255.0
!
route green 0.0.0.0 0.0.0.0 198.51.100.1 1
!
ip local pool vpnippool 192.0.2.101-192.0.2.102 mask 255.255.255.0
!
crypto map vpn_outside 999 ipsec-isakmp dynamic vpn_dyn
crypto map vpn_outside interface green
...

Erwartungsgemäß tut das seinen Dienst:

  • Der entfernte Supportmitarbeiter kann per Default Route erreicht werden.
  • Der entfernte Supportmitarbeiter bekommt über das VPN eine IP aus dem inside-LAN.
  • Die Appliance redet mit ihm über das lokale Netzwerk. Extra Routen werden nicht benötigt.

Einmal hin ...

Um die Stellen, die mit öffentlichen IP Adressen aus dem geschützten Netz kommen, versorgen zu können, sind einige Überlegungen notwendig.

Zuerst fällt auf, dass der Verbindungsaufbau bei unbekannten Gegenstellen nur von extern kommen kann. Die Clients werden ausschließlich eine öffentliche IP au dem Netz 198.51.100.248/29 zugreifen können. Von dem privaten Netz hinter der ASA wissen sie nichts.

Damit die Appliance nichts von den fremden Adressen merkt, braucht es eine Doppel-NAT:

interface Ethernet0/2
 nameif red
 security-level 0
 ip address 198.51.100.254 255.255.255.248
!
object network o-server
 host 192.0.2.4
!
nat (red,green) source dynamic any interface destination static interface o-server

Eingehende Pakete über das rote Interface von beliebiger Quelle an die Interface-IP werden so genanntet, dass die Quell-IP zur grünen Interface-Adresse und die Zieladresse, die der Appliance wird. Damit sieht die Appliance nur Anfragen aus ihrem LAN.

Um zu testen, dass diese Idee auch tut, wird ein Testaufbau erstellt:

ASA multiple default routes Test

Anstelle des roten Netzwerkes, steht ein Linux-Rechner, den man passend konfiguriert:

# ip addr add 198.51.100.254/29 dev eth_rot
# ip addr show eth_rot
1: eth_rot: <BROADCAST,MULTICAST,UP,10000>
    inet 198.51.100.254/29 scope global eth_rot
       valid_lft forever preferred_lft forever 

Zusätzlich bekommt er die fremde IP Adresse. Damit er diese auch als Quelladresse benutzt, gibt es eine spezielle extra Route:

# ip addr add 203.0.113.133/32 dev lo
# ip route add 198.51.100.249/32 src 203.0.113.133 dev eth_rot

Wenn man testweise versucht eine Verbindung zur Appliance herzustellen, scheint es erst einmal zu tun.

# ssh 198.51.100.249
15:42:02  IP 203.0.113.133.35158 > 198.51.100.249.22: S 3034099253:3034099253(0)
15:42:03  IP 203.0.113.133.35158 > 198.51.100.249.22: S 3034099253:3034099253(0)
15:42:05  IP 203.0.113.133.35158 > 198.51.100.249.22: S 3034099253:3034099253(0)

Wie man sieht, geht die Anfrage mit der richtigen Absende-IP raus.

Allerdings kommt keine Antwort zurück. Aber warum?

... und zurück

Ein Blick auf die ASA zeigt, das die Datenpakete korrekt nattet und sogar Antworten bekommt.

 16: 15:42:02   192.0.2.5.35158 > 192.0.2.4.22: S 3034099253:3034099253(0) win 14600
 17: 15:42:02   192.0.2.4.22 > 192.0.2.5.35158: S 2009198346:2009198346(0) ack 3034099253 win 14480
 18: 15:42:03   192.0.2.5.35158 > 192.0.2.4.22: S 3034099253:3034099253(0) win 14600
 19: 15:42:03   192.0.2.4.22 > 192.0.2.5.35158: S 2009198346:2009198346(0) ack 3034099253 win 14480
 20: 15:42:05   192.0.2.5.35158 > 192.0.2.4.22: S 3034099253:3034099253(0) win 14600
 21: 15:42:05   192.0.2.4.22 > 192.0.2.5.35158: S 2009198346:2009198346(0) ack 3034099253 win 14480

Warum kommen die Datenpakete nicht wieder zurück? Weil die Default Route fehlt!

Glücklicherweise ist die ASA kein Router. Genauer gesagt die Routingentscheidung wird in zwei Schritten vorgenommen:

  • Steht das ausgehende Interface nicht fest, so wird die generische Routingtabelle befragt, um das Interface zu ermitteln.
  • Ist allerdings klar, auf welchem Bein ausgesendet werden muss, so wird nur der Teil der Routingtabelle betrachtet, der diesem Interface zugeordnet ist.

Eine der Konsequenzen aus diesem Ansatz erklärt die seltsame Anforderung, bei jeder statische konfigurierten Route immer das Interface mit angeben zu müssen: Um so eine schräge Logik umsetzen zu können, muss man erst mal die Angaben dafür haben.

In diesem Fall genügt es also eine weitere Default Route einzutragen, die eine höhere Metrik hat. Dies stellt sicher, dass die ASA keine zwei gleichberechtigten Routen erhält, mit denen sie nicht umgehen kann. Die Situation für die ASA bleibt also eindeutig.

(conf)# route red 0.0.0.0 0.0.0.0 198.51.100.254 2

An der Standard-Routingtabelle ändert sich damit ja nichts:

C    198.51.100.248 255.255.255.248 is directly connected, red
C    198.51.100.0 255.255.255.192 is directly connected, green
C    192.0.2.0 255.255.255.0 is directly connected, gray
S*   0.0.0.0 0.0.0.0 [1/0] via 198.51.100.1, green

Ganz anders ist nun aber die Situation für die Pakete dar, die aus dem (reverse)-NAT heraus fallen.

  • Der NAT Eintrag enthält die Quell- und Ziel-Interfaces, sowie die IP-Adressen und Ports.
  • Pakete bestehender Flows werden also nicht normal behandelt, sondern anhand des vorhandenen NAT-Eintrags.
  • Damit umgehen sie sämtliches konfiguriertes Routing, ACLs etc. insbesondere die Standard-Routingtabelle.
  • Da das Zielinterface fest steht, greift nur noch die Routingtabelle dieses Interfaces, also die niedrig priorisierte Default Route.

Und siehe an:

# ssh  198.51.100.249 
16:38:20  IP 203.0.113.133.51310 > 198.51.100.249.22: S 3979383937:3979383937(0)
16:38:20  IP 198.51.100.249.22 > 203.0.113.133.51310: S 3186400021:3186400021(0) ack 3979383938
16:38:20  IP 203.0.113.133.51310 > 198.51.100.249.22: . ack 1 win 115
16:38:20  IP 198.51.100.249.22 > 203.0.113.133.51310: P 1:22(21) ack 1 win 114
16:38:20  IP 203.0.113.133.51310 > 198.51.100.249.22: . ack 22 win 115
16:38:20  IP 203.0.113.133.51310 > 198.51.100.249.22: P 1:21(20) ack 22 win 115
16:38:20  IP 198.51.100.249.22 > 203.0.113.133.51310: . ack 21 win 114
 136: 16:38:20    192.0.2.5.51310 > 192.0.2.4.22: S 1381971035:1381971035(0) win 14600
 137: 16:38:20    arp who-has 192.0.2.5 tell 192.0.2.4 
 138: 16:38:20    arp reply 192.0.2.5 is-at e8:b7:48:fd:89:81 
 139: 16:38:20    192.0.2.4.22 > 192.0.2.5.51310: S 2009198346:2009198346(0) ack 1381971036 win 14480
 140: 16:38:20    192.0.2.5.51310 > 192.0.2.4.22: . ack 2009198347 win 115
 141: 16:38:20    192.0.2.4.22 > 192.0.2.5.51310: P 2009198347:2009198368(21) ack 1381971036 win 114
 142: 16:38:20    192.0.2.5.51310 > 192.0.2.4.22: . ack 2009198368 win 115
 143: 16:38:20    192.0.2.5.51310 > 192.0.2.4.22: P 1381971036:1381971056(20) ack 2009198368 win 115
 144: 16:38:20    192.0.2.4.22 > 192.0.2.5.51310: . ack 1381971056 win 114
 145: 16:38:20    192.0.2.5.51310 > 192.0.2.4.22: P 1381971056:1381971848(792) ack
 146: 16:38:20    192.0.2.4.22 > 192.0.2.5.51310: . ack 1381971848 win 126

Hurra!

Spiele mit DirectAccess

18/05/2017 3:11 pm Lutz Donnerhacke Tags: IPv6 , Microsoft , Windows 0

Über DirectAccess hatte ich schon einiges erzählt, und natürlich auch ausprobiert. Was ich aber noch nie angesehen habe, war DirectAccess ohne IPv6 im inneren oder äußeren Netz, also total legacy. In der Schulung habe ich die Gelegenheit dazu und möchte die Ergebnisse nicht vorenthalten.

IPv4 only Lab

Nachdem der DirectAccess Client in die weite Welt verschwunden ist, und er voller Verzweiflung nach Hause telefoniert hat, bietet sich folgendes Bild.

C:\> ipconfig
Ethernet adapter Ethernet 2:
   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::a19f:cc85:1320:8c4%5
   IPv4 Address. . . . . . . . . . . : 131.107.0.2
   Subnet Mask . . . . . . . . . . . : 255.255.0.0
   Default Gateway . . . . . . . . . :
Tunnel adapter iphttpsinterface:
   Connection-specific DNS Suffix  . :
   IPv6 Address. . . . . . . . . . . : 2002:836b:c8:1000:1934:30a2:9e84:cdf4
   Temporary IPv6 Address. . . . . . : 2002:836b:c8:1000:f037:3b8d:cabc:bfcb
   Link-local IPv6 Address . . . . . : fe80::1934:30a2:9e84:cdf4%24
   Default Gateway . . . . . . . . . :

Es gibt also ein Interface im Internet mit öffentlichen Adressen ohne IPv6 Versorgung. Und dann gibt es den Tunnel nach Hause. Da sowohl Client als auch der DirectAccess Server öffentliche IPs haben, wurde der Tunnel mit 6to4-Adressen aufgebaut.

In den Schulungsunterlagen steht Notice the IP address for Tunnel Adapter is IPHTTPSInterface starting with 2002. This is an IP-HTTPS address. (Fehler sind so übernommen)

Nein, Microsoft! Es ist eine 6to4 Adresse. Offenbar habt Ihr wirklich keine praktische Erfahrungen mit IPv6.

Die zugehörige Routingtabelle zeigt:

c:\> route print -6
===========================================================================
Interface List
  5...00 15 5d 64 4d 4d ......Microsoft Hyper-V Network Adapter #2
  1...........................Software Loopback Interface 1
 24...00 00 00 00 00 00 00 e0 iphttpsinterface
===========================================================================
IPv6 Route Table
===========================================================================
Active Routes:
 If Metric Network Destination      Gateway
  1    331 ::1/128                  On-link
 24   4171 2002::/16                fe80::d92f:34d4:3add:e715
 24    331 2002:836b:c8::/48        fe80::d92f:34d4:3add:e715
 24    331 2002:836b:c8::/64        fe80::d92f:34d4:3add:e715
 24    331 2002:836b:c8:1::/64      fe80::d92f:34d4:3add:e715
 24    331 2002:836b:c8:5::/64      fe80::d92f:34d4:3add:e715
 24    331 2002:836b:c8:1000::/64   On-link
 24    331 2002:836b:c8:1000:1934:30a2:9e84:cdf4/128
                                    On-link
 24    331 2002:836b:c8:1000:f037:3b8d:cabc:bfcb/128
                                    On-link
 24    331 fd68:d6bf:56b6:7777::/96 fe80::d92f:34d4:3add:e715
  5    271 fe80::/64                On-link
 24    331 fe80::/64                On-link
 24    331 fe80::1934:30a2:9e84:cdf4/128
                                    On-link
  5    271 fe80::a19f:cc85:1320:8c4/128
                                    On-link
  1    331 ff00::/8                 On-link
  5    271 ff00::/8                 On-link
 24    331 ff00::/8                 On-link
===========================================================================
Persistent Routes:
  None

Das Routingziel ist eine Link-Local-Adresse, wie es sich für IPv6 gehört. Prima! Und die Adresse ist auch über den Tunnel erreichbar.

C:\>netsh int ipv6 sho nei 24
Internet Address                              Physical Address   Type
--------------------------------------------  -----------------  -----------
2002:836b:c8:1000:d92f:34d4:3add:e715                            Reachable (Router)
fe80::d92f:34d4:3add:e715                                        Reachable (Router)

Spielt man nun mit Browser und Explorer im Netz rum, gibt es offene Verbindungen:

C:\> netstat -n
Active Connections
  Proto  Local Address          Foreign Address        State
  TCP    131.107.0.2:49782      131.107.0.200:443      ESTABLISHED
  TCP    [2002:836b:c8:1000:f037:3b8d:cabc:bfcb]:49785  [fd68:d6bf:56b6:7777::ac10:c8]:80  ESTABLISHED
  TCP    [2002:836b:c8:1000:f037:3b8d:cabc:bfcb]:61893  [fd68:d6bf:56b6:7777::ac10:b]:80  ESTABLISHED

Die Verbindungen sind also offenbar über IPv6 zu einem ULA-Ziel (bäh!).

Das DirectAccess-Gateway macht noch NAT64, bettet also die IPv4 Adressen der LAN-Geräte ins IPv6 ein. Sieht man deutlich.

Dazu muss das Gateway offenbar auch DNS64 machen, um die DNS Antworten umzubiegen. Das sieht man leicht:

c:\>ipconfig /displaydns
Windows IP Configuration
    directaccess-webprobehost.adatum.com
    ----------------------------------------
    Record Name . . . . . : directaccess-WebProbeHost.Adatum.com
    Record Type . . . . . : 28
    Time To Live  . . . . : 213
    Data Length . . . . . : 16
    Section . . . . . . . : Answer
    AAAA Record . . . . . : fd68:d6bf:56b6:7777::ac10:c8

Aber warum macht der Client das? Der hat doch einen ganz anderen DNS Server?

C:\>netsh name show eff
DNS Effective Name Resolution Policy Table Settings

Settings for .Adatum.com
----------------------------------------------------------------------
DirectAccess (Certification Authority)  :
DirectAccess (IPsec)                    : disabled
DirectAccess (DNS Servers)              : 2002:836b:c8:3333::1
DirectAccess (Proxy Settings)           : Bypass Proxy

Settings for DirectAccess-NLS.Adatum.com
----------------------------------------------------------------------
DirectAccess (Certification Authority)  :
DirectAccess (IPsec)                    : disabled
DirectAccess (DNS Servers)              :
DirectAccess (Proxy Settings)           : Use default browser settings

Der Client hat also eine Policy für die Namensauflösung, die bei bestimmten Domains einen anderen DNS Server befragt. Genau, das Gateway.

C:\> ping lon-svr1.adatum.com
Pinging lon-svr1.adatum.com [fd68:d6bf:56b6:7777::ac10:b] with 32 bytes of data:
Reply from fd68:d6bf:56b6:7777::ac10:b: time=4ms
Reply from fd68:d6bf:56b6:7777::ac10:b: time=10ms
Reply from fd68:d6bf:56b6:7777::ac10:b: time=1ms
Ping statistics for fd68:d6bf:56b6:7777::ac10:b:
    Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 1ms, Maximum = 10ms, Average = 5ms

Allerdings funktioniert das nur, wenn diese Policy Regeln auch von der Applikation berücksichtigt werden:

C:\> nslookup lon-svr1.adatum.com
Server:  UnKnown
Address:  131.107.0.100

DNS request timed out.
    timeout was 2 seconds.
*** Request to UnKnown timed-out

Fragt man den richtigen Server, gibt es ganz andere Antworten:

C:\> nslookup lon-svr1.adatum.com 2002:836b:c8:3333::1
Server:  UnKnown
Address:  2002:836b:c8:3333::1

Non-authoritative answer:
Name:    lon-svr1.adatum.com
Addresses:  fd68:d6bf:56b6:7777::ac10:b
          172.16.0.11

All das ist mir all die Jahre verborgen geblieben, weil ich IPv6 ausgerollt hatte.

Ich vermisse nichts.

Was IPv6 ändert

Wird auf dem Außeninterface natives IPv6 eingesetzt, verschwinden sofort die 2002-er 6to4 Adressen. Dazu ist anzumerken:

  • Das im Lab die Kommunikation geklappt hatte, liegt daran, dass Microsoft das 2002:836b:c8:1000::/64 auf dem Interface betreibt.
  • Um mit 6to4 Adressen zu kommunizieren, muss man sich auf externe 6to4 Gateways verlassen. Dies kommt ins Spiel, weil der DNS Server 2002:836b:c8:3333::1 angesprochen wird.
  • Da beide Hosts über den IPv4-HTTPS-Tunnel IPv6 im externen Routing komplett umgehen, benötigen sie keine 6to4 Router im Internet.
  • Da beide Server extern öffentliche IPv4 Adressen haben, wird überhaupt 6to4 benutzt. Steht ein Gerät hinter NAT wird es auf Teredo zurück fallen.
  • Teredo funktioniert nicht mit allen NAT-Typen, speziell gibt es Probleme, wenn die öffentliche NAT-IP nicht stabil ist (z.B. bei Carrier Grade NAT oder Large Scale NAT)
  • Mit RFC 6540 ist IPv6 auf den Außeninterfaces Pflicht für die ISPs.

Wird IPv6 im LAN eingesetzt, verschwindet sofort das fc00::/7 ULA Netz. Stattdessen bekommen die Clients die gleiche IP, wie sie auch im LAN hätten. Das hat folgende Implikationen:

  • Der Client ist intern, wie extern unter der gleichen IP ansprechbar.
  • Die Fernwartung wird damit im Unternehmen unabhängig vom Aufenthaltsort des Clients.
  • Da Server und Clients IPv6 einsetzen, entfällt DNS64 und NAT64.
  • Applikationen können mit allen benötigten Ports Verbindungen in alle benötigten Richtungen ausführen. Es ist nicht notwendig im DirectAccess-Server NAT-Helper pro Protokoll zu haben.
  • Auf diese Weise funktionieren Protokolle wie Telefonie, Videokonferenzen, FTP, etc. pp. einfach auch extern.
  • Fremdapplikationen, die ihre eigene Namensauflösung fahren, funktionieren problemlos, weil sich nur das Routing zum DNS Server ändert. Es ist nicht länger notwendig, sich Domainabhängig an unterschiedliche DNS Server zu wenden.

Man sollte sich also wirklich überlegen, ob man weiter auf IPv6 verzichten will.

Lobotomie durch Microsoft DNS

17/05/2017 11:12 am Lutz Donnerhacke Tags: WTF , Microsoft , Windows 0

Aktuell lerne ich, was so alles bei Microsoft seit Windows NT neues dazu gekommen ist. Es ist der Updatekurs für Server 2016. Aktuell sind die Neuerungen im DNS dran. Wer bind kennt, weiss, wo die Worte her kommen. Allerdings ist das Zonenkonzept komplett unbenutzbar.

Aufgabe

Erstellen Sie für eine existierende Domain Einträge, die von einem anderen Netz aus andere Adressen zurück liefern.

Diese Aufgabe ist eine klassische Split-Brain Situation und kommt in der Praxis immer dann vor, wenn interne Server nach extern über NAT sichtbar gemacht werden sollen. Bei IPv6 gäbe es das Problem nicht, da würde eine Firewallfreigabe reichen.

Zuerst schauen wir von einem externes Gerät auf die DNS Auflösung:

PS extern> nslookup www.adatum.com
Address:  172.16.10.10

Non-authoritative answer:
Name:    www.adatum.com
Address:  172.16.0.10

Und nun ändern wir das auf dem DNS Server. Zuerst wird festgelegt, dass es einen neuen Scope (Bind sagt dazu View) überhaupt gibt.

PS dns> Add-DnsServerZoneScope -ZoneName adatum.com  -Name Trey

Innerhalb dieses Scopes soll es einen anderen DNS-Eintrag geben als in der Originalzone.

PS dns> Add-DnsServerResourceRecordA -ZoneName adatum.com -Name www -IPv4Address 1.2.3.4 -ZoneScope Trey

Als nächstes wird ein IP-Netz als Auswahlkriterium festgelegt.

 PS dns> Add-DnsServerClientSubnet -Name TreyNet -IPv4Subnet 172.16.10.0/24

Beides zusammen definiert nun das anzuwendende Abfrageregelwerk.

PS dns> Add-DnsServerQueryResolutionPolicy -Name SplitBrain -Action ALLOW -ClientSubnet "eq,TreyNet" -ZoneScope "Trey,1" -ZoneName adatum.com

Fragt man nun von extern den Namen erneut ab, klappt es wie gewünscht.

PS ext> Clear-DnsServerCache
Confirm
This will delete all the cached records on the server and might impact performance, do you want to continue?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): y
PS ext> Clear-DnsClientCache
PS ext> nslookup www.adatum.com
Server:  UnKnown
Address:  172.16.10.10

Non-authoritative answer:
Name:    www.adatum.com
Address:  1.2.3.4

Prima! Übung beendet.

Was wirklich passiert

Fragt man von extern mal andere Namen der Zone ab, so gibt es ausschließlich Fehlermeldungen:

*** UnKnown can't find lon-srv3.adatum.com: Non-existent domain

Ganz offenbar hat Microsoft mehr gemacht, als diesen einen Record zu überschreiben. Aber was genau?

Zuerst einmal fällt auf, dass es keinerlei Möglichkeit gibt, die Einträge des Scopes in der graphischen Oberfläche zu sehen. Dort schaut für den Administrator alles aus wie immer.

ms-dns-scope1

Man kann klicken, wo auch immer man will. Die eingerichteten Scopes und Policies bleiben unsichtbar. Das wird die Fehlersuche oder gar den operativen Betrieb sicher deutlich erschweren.

Also gehen wir per Powershell auf die Suche:

PS dns> Get-DnsServerZoneScope -ZoneName adatum.com
ZoneScope            FileName            
---------            --------            
Adatum.com                               
Trey                                    

Man muss also die Zone kennen, für die man die Scopes abfragen kann. Eine generelle Liste aller Scopes muss man sich zusammen bauen.

PS dns> Get-DnsServerQueryResolutionPolicy

Überraschung! Die generelle Liste aller Policies ist leer. Auch hier muss man wieder konkret fragen.

PS dns> Get-DnsServerQueryResolutionPolicy -ZoneName adatum.com
Name       ProcessingOrder IsEnabled Action
----       --------------- --------- ------
SplitBrain 1               True      Allow

Und was steht nun in der Policy genau drin? Das ist leider nicht auf diese Weise herauszubekommen!

Aber man kann wenigstens seine Kriterien auflisten.

PS dns> Get-DnsServerClientSubnet
Name    IPV4Subnet       IPV6Subnet
----    ----------       ----------
TreyNet {172.16.10.0/24}          

Nun steht der fehlersuchende Administrator belämmert da, weil er nicht heraus bekommt, was die Policy genau tut.

Aber man kann ja mal raten:

PS dns> Get-DnsServerResourceRecord -ZoneName adatum.com
HostName                  RecordType Type       Timestamp            TimeToLive      RecordData                      
--------                  ---------- ----       ---------            ----------      ----------                      
@                         A          1          5/17/2017 1:00:00 AM 00:10:00        172.16.0.10                     
@                         NS         2          0                    01:00:00        lon-dc1.adatum.com.             
@                         SOA        6          0                    01:00:00        [46][lon-dc1.adatum.com.][hos...
_msdcs                    NS         2          0                    01:00:00        lon-dc1.adatum.com.             
_gc._tcp.Default-First... SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][3268][LON-DC1.Adatum...
_kerberos._tcp.Default... SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][88][LON-DC1.Adatum.c...
_ldap._tcp.Default-Fir... SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][389][LON-DC1.Adatum....
_gc._tcp                  SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][3268][LON-DC1.Adatum...
_kerberos._tcp            SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][88][LON-DC1.Adatum.c...
_kpasswd._tcp             SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][464][LON-DC1.Adatum....
_ldap._tcp                SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][389][LON-DC1.Adatum....
_kerberos._udp            SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][88][LON-DC1.Adatum.c...
_kpasswd._udp             SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][464][LON-DC1.Adatum....
DomainDnsZones            A          1          5/17/2017 1:00:00 AM 00:10:00        172.16.0.10                     
_ldap._tcp.Default-Fir... SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][389][LON-DC1.Adatum....
_ldap._tcp.DomainDnsZones SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][389][LON-DC1.Adatum....
ForestDnsZones            A          1          5/17/2017 1:00:00 AM 00:10:00        172.16.0.10                     
_ldap._tcp.Default-Fir... SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][389][LON-DC1.Adatum....
_ldap._tcp.ForestDnsZones SRV        33         5/17/2017 1:00:00 AM 00:10:00        [0][100][389][LON-DC1.Adatum....
LON-CL1                   A          1          5/17/2017 1:00:00 AM 00:20:00        172.16.0.40                     
LON-CL2                   A          1          11/6/2016 2:00:00 AM 00:20:00        172.16.0.41                     
lon-dc1                   A          1          0                    01:00:00        172.16.0.10                     
LON-HOST1                 A          1          11/6/2016 9:00:00 AM 00:20:00        172.16.0.161                    
LON-HOST2                 A          1          11/6/2016 9:00:00 AM 00:20:00        172.16.0.162                    
LON-NVHOST3               A          1          11/6/2016 10:00:0... 00:20:00        172.16.0.163                    
LON-NVHOST4               A          1          11/6/2016 10:00:0... 00:20:00        172.16.0.164                    
LON-RTR                   A          1          11/6/2016 3:00:00 AM 00:20:00        172.16.0.200                    
LON-SVR1                  A          1          5/17/2017 1:00:00 AM 00:20:00        172.16.0.11                     
LON-SVR2                  A          1          5/17/2017 1:00:00 AM 00:20:00        172.16.0.12                     
LON-SVR3                  A          1          11/6/2016 2:00:00 AM 00:20:00        172.16.0.13                     
www                       A          1          0                    01:00:00        172.16.0.10                    

Das ist doch schon mal großartig! Die Zoneninhalte werden aufgelistet.

Dann kann man bestimmt auch die Zoneninhalte aus sich des anderen Scopes ausgeben, oder?

PS dns> Get-DnsServerResourceRecord -ZoneName adatum.com -ZoneScope Trey
HostName                  RecordType Type       Timestamp            TimeToLive      RecordData                      
--------                  ---------- ----       ---------            ----------      ----------                      
@                         NS         2          0                    01:00:00        lon-dc1.adatum.com.             
@                         SOA        6          0                    01:00:00        [2][lon-dc1.adatum.com.][host...
www                       A          1          0                    01:00:00        1.2.3.4                       

Ach, schau an! Es gibt also pro Scope eine komplett neue Zone.

Probleme

Die Konsequenzen sind offensichtlich: Wenn sich an der originalen Zone etwas ändert, muss der Administrator per PowerShell die entsprechenden Einträge in dem anderen Scope der Zone manuell nachpflegen. Er hat dafür keinerlei graphische Unterstützung.

Es ist sehr wahrscheinlich, dass diese Konfiguration innerhalb kürzester Zeit zu massiven Problemen führt.

Selbst für den erfahrenen Admin wird es schwierig herauszubekommen, was genau schief läuft, weil die Debuggingmöglichkeiten extrem eingeschränkt sind. Es ist mir bspw. nicht gelungen, die Konfiguration der Policies auszulesen.

PS C:\Users\Administrator> Get-DnsServerQueryResolutionPolicy -ZoneName "adatum.com" | Format-List *

Action                : Allow
AppliesOn             : QueryProcessing
Condition             : And
Content               : {DnsServerPolicyContent}
Criteria              : {DnsServerPolicyCriteria}
IsEnabled             : True
Level                 : Zone
Name                  : SplitBrain
ProcessingOrder       : 1
ZoneName              : adatum.com
PSComputerName        : 
CimClass              : root/Microsoft/Windows/DNS:DnsServerPolicy
CimInstanceProperties : {Action, AppliesOn, Condition, Content...}
CimSystemProperties   : Microsoft.Management.Infrastructure.CimSystemProperties

Wie man sieht, gibt es keine nutzbaren Details, selbst wenn man in die Tiefe geht. Ich erspare mir die ergebnislosen Versuche, die Felder Content und Criteria weiter auseinander zu dröseln.

Lösung

Aber wie geht es nun richtig?

Das Queryprocessing wird durch die Policies beeinflusst. Leider gibt es in dem betreffenden Scope nur den manuellen Eintrag in der Zone und sonst keine weiteren Einträge. Man darf also nur dann in den Scope dieser Zone wechseln, wenn man genau weiß, das diese konkrete Anfrage vorliegt.

Zuerst einmal wird die alte Policy entfernt.

PS dns> Remove-DnsServerQueryResolutionPolicy -Name SplitBrain -ZoneName adatum.com

Soweit so einfach. Und dann wird ganz überspezifisch festgelegt, was passieren soll:

PS dns> Add-DnsServerQueryResolutionPolicy -name SplitHost -ZoneName adatum.com -Fqdn "eq,www.adatum.com" -Action ALLOW -ClientSubnet "eq,TreyNet" -ZoneScope "Trey,1"

Damit wird nur dann in diesen Scope dieser Zone geschaut, wenn auch der Record genau dieser Zone von genau dem betroffenen Subnetz angefragt wird.

Und dann sollen die restlichen Einträge in dem anderen Scope der gleichen Zone abgefragt werden.

PS dns> Add-DnsServerQueryResolutionPolicy -name AllowOthers -ZoneName adatum.com -Action ALLOW -ClientSubnet "eq,TreyNet" -ZoneScope "adatum.com,2"

Die Nummer 2 gibt an, dass diese Regel als zweite auszuführen ist.

Und nun klappt es von extern auch:

PS ext> nslookup www.adatum.com
Server:  UnKnown
Address:  172.16.10.10

Non-authoritative answer:
Name:    www.adatum.com
Address:  1.2.3.4

PS ext> nslookup lon-svr3.adatum.com
Server:  UnKnown
Address:  172.16.10.10

Non-authoritative answer:
Name:    lon-svr3.adatum.com
Address:  172.16.0.13

Aber bitte, Kinder! Nicht zuhause nachmachen!

Die Nichtexistenz unsichtbarer Angriffe

12/01/2017 5:03 pm Lutz Donnerhacke Tags: Internet , Whois , WTF , Sicherheit 3

Es gibt Sicherheitsanbieter, die aus einer Mücke einen Elefanten machen, um damit Aufmerksamkeit zu erregen. Das Geschäftsmodell kann man verbessern, indem man als Betreiber einer Blockliste die Aufmerksamkeit der Betroffenen einfordert. Obendrauf kann man ein Zusatzgeschäft satteln, das das Streichen von der Liste entgeltpflichtig macht. Natürlich wird eine solche Liste perfekt und seriös gepflegt sein.

Die Warnung

Dear Provider,

I’m George Egri, the Co-Founder and CEO of BitNinja Server Security.
I’m writing to inform you that we have detected malicious requests
from the IP a.b.c.d directed at our clients’ servers.

As a result of these attacks, we have added your IP to our greylist
to prevent it from attacking our clients’ servers.

Servers are increasingly the target of botnet attacks and you might not be aware
that your server is being used as a “bot” to send malicious attacks over the Internet.

I've collected the 3 earliest logs below, and you can find the freshest 100,
that may help you disinfect your server, under the link.

http://bitninja.io/incidentReport.php?details=ABC...XYZ

Url: [www.rechtslexikon.net/d/rechtsmittelverzicht/rechtsmittelverzicht.htm]
Agent: [Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0]

Url: [www.rechtslexikon.net/d/rechtsmittelverzicht/img/logo.png]
Agent: [Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0]

Url: [www.rechtslexikon.net/d/rechtsmittelverzicht/css/style.css]
Agent: [Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0]

For more information on analyzing and understanding outbound traffic,
check out the guide that we’ve created. We’ve dedicated an entire site to helping people
prevent their server from sending malicious attacks: https://doc.bitninja.io/investigations.html

Our incident experts are also happy to help you and can provide detailed logs if needed.
Please feel free to connect me with the administrator or technical team responsible
for managing your server.

This is not the correct contact email?

Please provide us the e-mail address of the server administrator or the abuse department
of the server management company, so we can send the securityreport to them and
discuss the further steps needed to resolve this problem.
You can provide the e-mail address using a web form. 

Thank you for helping us make the Internet a safer place!

Regards,

George Egri
CEO at BitNinja.io

Selbstverständlich ist die E-Mail an den falschen Abuse-Kontakt  gegangen. Deren Whois-Abfrage beherrscht Abuse-C ala RIPE nicht. Das habe ich schon zig-mal mit denen durch dekliniert. Jedes Mal ohne Erfolg. Sie verstehen es nicht.

Und es fehlen die wichtigen Angaben im Report: Da es sich um die öffentliche-IP eines NAT-Pools ist, benötige ich die Portnummer, um überhaupt die Chance zu haben, den Verursacher zu identifizieren.

Der Vorfall

Aber nun, schauen wir mal wieviel Aufwand man rein stecken könnte, also welche Art von Schaden angerichtet wird.

2017-01-10 18:10:06

Url: [ho###er.com/default.php?os=wp&calling_app=9nblggh4p0vk]
Agent: [Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/8.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Lumia 950 XL) like Gecko]
Get data: [Array(
 [os] => wp
 [calling_app] => 9nblggh4p0vk)]
 

2017-01-08 12:49:16

Url: [www.softair.at/faq.html]
Agent: [Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0]

2017-01-02 20:14:58

Url: [fa###ng.###.com/Overload/?steamid=76561198141804145&map=ttt_rooftops_2016_v1]
Agent: [Mozilla/5.0 (Windows; Valve Source Client) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1003.1 Safari/535.19 Awesomium/1.#.#.1 GMod/13]
Get data: [Array(
 [steamid] => 76561198141804145
 [map] => ttt_rooftops_2016_v1)]

2017-01-02 20:08:44

Url: [fa###ng.###.com/Overload/?steamid=76561198141804145&map=ttt_rooftops_2016_v1]
Agent: [Mozilla/5.0 (Windows; Valve Source Client) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1003.1 Safari/535.19 Awesomium/1.#.#.1 GMod/13]
Get data: [Array(
 [steamid] => 76561198141804145
 [map] => ttt_rooftops_2016_v1)]

2016-12-28 22:31:07

Url: [tattoomodels.hol.es/gotham-suicide/]
Agent: [Mozilla/5.0 (Linux; Android 4.4.2; X7 Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.#.#.0 Safari/537.36]

2016-12-17 22:15:34

Url: [www.st-sebastian-bickenriede.hol.es/impressum.htm]
Agent: [Mozilla/5.0 (Linux; U; Android 4.3; de-de; HUAWEI G6-U10 Build/HuaweiG6-U10) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30]

2016-12-17 22:15:34

Url: [www.st-sebastian-bickenriede.hol.es/kontakt.htm]
Agent: [Mozilla/5.0 (Linux; U; Android 4.3; de-de; HUAWEI G6-U10 Build/HuaweiG6-U10) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30]

2016-12-17 22:15:02

Url: [www.st-sebastian-bickenriede.hol.es/Gottesdienste_Vermeldungen/aktuelle_gottesdienste_und_vermeldungen.pdf]
Agent: [Mozilla/5.0 (Linux; Android 4.3; HUAWEI G6-U10 Build/HuaweiG6-U10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.133 Mobile Safari/537.36]

2016-12-17 22:14:29

Url: [www.st-sebastian-bickenriede.hol.es/Gottesdienste_Vermeldungen/aktuelle_gottesdienste_und_vermeldungen.pdf]
Agent: [Mozilla/5.0 (Linux; Android 4.3; HUAWEI G6-U10 Build/HuaweiG6-U10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.133 Mobile Safari/537.36]

Das schaut aber nicht nach einem Angriff aus, sondern nach normaler Benutzung. Also stelle ich mal die explizite Rückfrage.

Can you please explain, what type of attack you are referring to?
I do only see valid web usage in your reports.

Der Abschluss

Die Antwort war ernsthaft überraschend:

Hello, 

Thank you for reaching out to us.
I checked the provided IP address and found nothing malicious in the recent,
therefore I delisted the mentioned IP address from our greylist.
If you have any more questions, do not hesitate to contact us.

Best Regards, 
Anita Batári
Incident Expert
https://bitninja.io

CARP bleibt hängen

11/02/2016 3:14 pm Lutz Donnerhacke Tags: Internet , WTF , BSD 0

CARP ist eine coole Lösung, wenn man mehrere Systeme hat, die sich eine IP teilen sollen. Aber von gestern zu heute war da ein Wurm drin. Ein Server hat sich geweigert, wieder seine Aufgabe als CARP-Master zu erfüllen. Ich stand kurz vor dem Reboot des Systems.

Aus und vorbei

netzplan-animiert

Beim Blick auf die Auslastung der Leitungen zeigte sich eine relativ hohe Last auf einem der Server des NAT-Clusters während eine andere Maschine es sich gemütlich machte.

Eigentlich war nichts auffällig. Der Teufel steckte offenbar im Detail.

Konnte es sein, dass sich die Balancierung des CARP verschoben hatte, so dass ein Teil der Kunden auf einen andere Maschine geleitet wurden?

Wenn ja, müsste sich das im CARP-Status der fraglichen Maschine zeigen.

# for i in 0 1 2 3; do ifconfig carp$i; done
carp0: flags=49<UP,LOOPBACK,RUNNING> metric 0 mtu 1500
        inet 100.100.0.1 netmask 0xffff8000 
        carp: BACKUP vhid 1 advbase 1 advskew 200
carp1: flags=49<UP,LOOPBACK,RUNNING> metric 0 mtu 1500
        inet 100.100.0.1 netmask 0xffff8000 
        carp: BACKUP vhid 2 advbase 1 advskew 100
carp2: flags=49<UP,LOOPBACK,RUNNING> metric 0 mtu 1500
        inet 100.100.0.1 netmask 0xffff8000 
        carp: BACKUP vhid 3 advbase 1 advskew 133
carp3: flags=49<UP,LOOPBACK,RUNNING> metric 0 mtu 1500
        inet 100.100.0.1 netmask 0xffff8000 
        carp: BACKUP vhid 4 advbase 1 advskew 166

Ja, die Kiste hat schlicht keinen Bock mehr. Aber warum?

Ich schaue mir mal den CARP-Status aller Maschinen des Clusters in der Übersicht an.

$ for i in 1 2 3 4; do
    echo server$i;
    ssh root@server$i sysctl net.inet.carp;
    for k in 0 1 2 3; do
      ssh root@server$i ifconfig carp$k | fgrep advbas;
    done;
  done

server1
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 1
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: MASTER vhid 1 advbase 1 advskew 100
        carp: MASTER vhid 2 advbase 1 advskew 133
        carp: BACKUP vhid 3 advbase 1 advskew 166
        carp: BACKUP vhid 4 advbase 1 advskew 200
server2
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 1
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 1
        carp: BACKUP vhid 1 advbase 1 advskew 200
        carp: BACKUP vhid 2 advbase 1 advskew 100
        carp: BACKUP vhid 3 advbase 1 advskew 133
        carp: BACKUP vhid 4 advbase 1 advskew 166
server3
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 1
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: BACKUP vhid 1 advbase 1 advskew 166
        carp: BACKUP vhid 2 advbase 1 advskew 200
        carp: MASTER vhid 3 advbase 1 advskew 100
        carp: BACKUP vhid 4 advbase 1 advskew 133
server4
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 1
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: BACKUP vhid 1 advbase 1 advskew 133
        carp: BACKUP vhid 2 advbase 1 advskew 166
        carp: BACKUP vhid 3 advbase 1 advskew 200
        carp: MASTER vhid 4 advbase 1 advskew 100

Die virtuelle Host-ID (vhid) zwei ist falsch. Server2 ist nicht für diese vhid zuständig, obwohl er eine kleinere advskew hat.

Ebenso auffällig ist die Aussage, das dieser Server2 suppress_preempt auf einem anderen Wert stehen hat. Dieser Wert gibt an, dass der Server glaubt, er sei nicht bereit CARP aktiv zu machen. Unglücklicherweise ist der Wertread-only.

Ursachenforschung

Server2 glaubt also in einem Fehlerzustand zu sein. Aber welcher kann das sein? Und wie kann man ihn aus dem Weg räumen?

Die Man-Page war jedenfalls nicht hilfreich. Sie sagt, ein Interface müsse down sein. Aber das ist offensichtlich nicht der Fall.

Eine Suche im Sourcecode offenbart, dass dieser Fehlerzustand ausschließlich in der Datei ip_carp.c existiert und nur dort behandelt wird.

[lutz@server2 /usr/src/sys]# fgrep -lR suppress_preempt .
./netinet/ip_carp.c

Das macht es schon einmal sehr einfach.

int carp_suppress_preempt = 0;
SYSCTL_INT(_net_inet_carp, OID_AUTO, suppress_preempt, CTLFLAG_RD,
    &carp_suppress_preempt, 0, "Preemption is suppressed");

Es gibt also eine globale Variable des Kernels, deren Wert per sysctl ausgelesen werden darf. Nach dem Booten ist die 0.

static void
carpdetach(struct carp_softc *sc, int unlock)
{
...
        if (sc->sc_suppress)
                carp_suppress_preempt--;
        sc->sc_suppress = 0;

        if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS)
                carp_suppress_preempt--;
        sc->sc_sendad_errors = 0;
...

Wenn ein CARP-Interface entfernt wird, wird der globale Zähler dekrementiert, wenn dieses Interface den Sperrzustand eingeleitet hatte.

static void
carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
{
...
        sc_tv.tv_sec = sc->sc_advbase;
        if (carp_suppress_preempt && sc->sc_advskew <  240)
                sc_tv.tv_usec = 240 * 1000000 / 256;
        else
                sc_tv.tv_usec = sc->sc_advskew * 1000000 / 256;
        ch_tv.tv_sec = ch->carp_advbase;
        ch_tv.tv_usec = ch->carp_advskew * 1000000 / 256;
...

Bei der Verarbeitung von CARP-Nachrichten wird jede CARP-Instanz als letztmöglicher Fallback angesehen, indem maximale Werte angenommen werden.

Das ist zwar beruhigend, aber ändert nichts an dem Wert selbst.

static void
carp_send_ad_locked(struct carp_softc *sc)
{
...
                advbase = sc->sc_advbase;
                if (!carp_suppress_preempt || sc->sc_advskew > 240)
                        advskew = sc->sc_advskew;
                else
                        advskew = 240;
                tv.tv_sec = advbase;
                tv.tv_usec = advskew * 1000000 / 256;
...

Bei der Generierung von CARP-Nachrichten an andere Systeme werden maximale Werte announciert, so eine Sperre vorliegt.

Damit wissen die anderen von den Problemen dieser Maschine.

...
                if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) {
                        SC2IFP(sc)->if_oerrors++;
                        if (sc->sc_sendad_errors < INT_MAX)
                                sc->sc_sendad_errors++;
                        if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) {
                                carp_suppress_preempt++;
                                if (carp_suppress_preempt == 1) {
                                        CARP_SCUNLOCK(sc);
                                        carp_send_ad_all();
                                        CARP_SCLOCK(sc);
                                }
                        }
                        sc->sc_sendad_success = 0;
                } else {
                        if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
                                if (++sc->sc_sendad_success >=
                                    CARP_SENDAD_MIN_SUCCESS) {
                                        carp_suppress_preempt--;
                                        sc->sc_sendad_errors = 0;
                                }
                        } else
                                sc->sc_sendad_errors = 0;
                }
...

Jetzt wird es interessant (und der IPv6 Teil ist identisch).

Wenn beim Aussenden der CARP-Nachricht ein Fehler auftritt, zählt er die Fehler hoch. Überschreiten diese die MAX-Grenze, geht der globale Block an. Funktioniert es dann wieder MIN-mal hintereinander, wird die Sperre wieder aufgehoben. Die Instanz selbst wird nicht als geblockt markiert.

Soweit so logisch.

static void
carp_sc_state_locked(struct carp_softc *sc)
{
...
        if (sc->sc_carpdev->if_link_state != LINK_STATE_UP ||
            !(sc->sc_carpdev->if_flags & IFF_UP)) {
...
                if (!sc->sc_suppress) {
                        carp_suppress_preempt++;
                        if (carp_suppress_preempt == 1) {
                                CARP_SCUNLOCK(sc);
                                carp_send_ad_all();
                                CARP_SCLOCK(sc);
                        }
                }
                sc->sc_suppress = 1;
        } else {
                SC2IFP(sc)->if_flags |= sc->sc_flags_backup;
                carp_set_state(sc, INIT);
                carp_setrun(sc, 0);
                if (sc->sc_suppress)
                        carp_suppress_preempt--;
                sc->sc_suppress = 0;
        }
...

Und schließlich noch: Wenn das zugehörige Interface den Link-Status ändert, dann blockiere ebenfalls die zugehörige CARP Instanz.

Außerdem soll global blockiert werden, damit ein System, dass nicht mehr volle Konnektivität hat, sich nicht mehr aktiv um die Verarbeitung von Kundendaten bemüht.

Soweit auch logisch.

Mir erscheint die Stelle mit dem CARP_SCUNLOCK gefolgt von carp_send_ad_all aber wie eine Racecondition. Schließlich greift die Senderoutine auf die gleichen Werte zu und die Blockierung der betroffenen Instanz erfolgt erst danach der Aussendung.

Das klingt irgendwie unlogisch. Vermutlich habe ich es schlicht falsch verstanden. Es ist aber auch ziemlich uninteressant, weil neuere Kernel den Code komplett anders haben.

Fehlerbehebung

Herausgekommen ist, dass der globale Zähler nur dann wieder verschwindet, wenn entweder die Zähler von allein zurück gehen, oder die Interfaces gelöscht werden.

Na da bleibt nicht viel: Alle Interfaces manuell löschen und händisch neu anlegen.

Bei der Gelegenheit wurde auch der CARP-Loglevel erhöht. So bleibt ein letzter Blick:

$ for i in 1 2 3 4; do
    echo server$i;
    ssh root@server$i sysctl net.inet.carp;
    for k in 0 1 2 3; do
      ssh root@server$i ifconfig carp$k | fgrep advbas;
    done;
  done

server1
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 2
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: MASTER vhid 1 advbase 1 advskew 100
        carp: BACKUP vhid 2 advbase 1 advskew 133
        carp: BACKUP vhid 3 advbase 1 advskew 166
        carp: BACKUP vhid 4 advbase 1 advskew 200
server2
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 2
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: BACKUP vhid 1 advbase 1 advskew 200
        carp: MASTER vhid 2 advbase 1 advskew 100
        carp: BACKUP vhid 3 advbase 1 advskew 133
        carp: BACKUP vhid 4 advbase 1 advskew 166
server3
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 2
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: BACKUP vhid 1 advbase 1 advskew 166
        carp: BACKUP vhid 2 advbase 1 advskew 200
        carp: MASTER vhid 3 advbase 1 advskew 100
        carp: BACKUP vhid 4 advbase 1 advskew 133
server4
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 2
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: BACKUP vhid 1 advbase 1 advskew 133
        carp: BACKUP vhid 2 advbase 1 advskew 166
        carp: BACKUP vhid 3 advbase 1 advskew 200
        carp: MASTER vhid 4 advbase 1 advskew 100

Prima!

Gefahren von local-proxy-arp

26/01/2016 9:07 am Lutz Donnerhacke Tags: Internet , Cisco , WTF , Broadband 2

Ein typisches DSL-Netzwerk verhindert am DSLAM die Querkommunikation zwischen den Teilnehmern. Allerdings wollen die Nutzer auch direkt miteinander kommunizieren können, besonders, wenn es sich um Firmen mit statischen IP Adressen handelt. Und das ist überraschend komplex. Beim Einsatz von DHCP in großen Layer2-Wolken, leidet darunter auch die Redundanz der Anbindung.

Problemstellung

In einem typischen Breitband-Anschluss-Netz werden die Endkunden mit einzelnen Leitungen an einen DLSAM geführt.

Typischerweise hat man alle diese Verbindungen per PPP an die zentralen Router geführt. Die entstehende Topologie sieht dann so aus. Die violetten Pfeile zeigen die Datenwege an. Eine Querkommunikation wird anhand des grünen Pfeils realisiert.

local proxy arp2

Auf diese Weise werden sämtliche Daten der Endkunden durch die zentrale Technik geschleift, die betreffende Technik muss dann entsprechend leistungsfähig sein.

Aus Abrechnungssicht ist dieser Aufbau vorteilhaft, weil es eine zentrale Erfassung sämtlicher Datenvolumina und Online-Zeiten ermöglicht. Damit sind die Geschäftsmodelle aus "Dial-Up"-Modem-Zeiten weiterhin umsetzbar.

Mittlerweile hat sich allerdings auch eine Anschlussart verbreitet, die wie ein großes Ethernet funktioniert. In diesem Fall werden die Kunden in eine gemeinsame große Layer2 Wolke gesetzt und können so mit der zentralen Technik kommunizieren.

Aber was ist mit dem Quertraffic? In der Regel wird dieser Quertraffic – wie bisher – durch die DSLAMs unterbunden. Ob der Quertraffic auch außerhalb der DSLAMs wirksam unterbunden wird, ist meist nicht klar und wird nicht geprüft. In diesem Fall nehmen ich an, dass die Sperre nur am DSLAM selbst umgesetzt wird. Damit gibt es verbotene (rot) und erlaubte (grün) Kommunikationswege.

local proxy arp1

Was muss nun passieren, wenn Kunden untereinander kommunizieren wollen?

Dies ist kein obskurer Anwendungsfall, denn alle Kunden nehmen am Internet teil und selbstverständlich können sie miteinander reden wollen. Besonders augenfällig ist der Fall, wenn ein Anschluss einer Firma gehört und ein anderer Anschluss einem Mitarbeiter daheim, von dem er per VPN in die Firma kommen möchte.

Tricks

Um also in einem Layer2-Netz, dass nicht komplett vermascht ist, kommuniziert werden soll, muss einer der beteiligten Systeme als Relay (Weiterleiter) agieren. Das kann uns soll sinnvollerweise nur die zentrale Routingtechnik sein.

local proxy arp3

Wie lenkt man nun im Schritt 1 den Ethernet-Frame zum zentralen Router um?

Der Client fragt nach per ARP nach der MAC des Zielsystems im gleichen logischen Netzsegment. Dieses ARP Paket kommt aber aufgrund der DSLAM-Sperre nicht beim gewünschten Ziel an. Also antwortet der zentrale Router im Namen des eigentlichen Ziels auf die ARP-Anfrage (ip local-proxy-arp). Der Client lernt nun die MAC-Adresse des zentralen Routers für diesen Kommunikationsweg und schickt alle Pakete dort hin.

Natürlich kann der Router damit nichts anfangen, aber er weiß, dass er als Stellvertreter die Pakete entgegennehmen und an das eigentliche Zielsystem weiter schicken soll. Dazu sendet er im Schritt 2 den gleichen Frame wieder aus, diesmal aber an die MAC des Zielsystems.

Problem gelöst!

Redundanz

Spannend ist die Frage, wie man mit Redundanz bzgl. des Routers umgeht. Es ist sicher keine gute Idee nur ein Stück Hardware zu haben, an der alle Kunden hängen. Also gut, GLBP an (was für Lastverteilung auf den Routern sorgt) und laufen lassen.

Anfangs geht es gut, dann kommt ein seltsamer Effekt auf. Die Clients sind von extern nicht mehr erreichbar.

Ein Traceroute offenbart eine Schleife:

...
3 router1 15ms 14ms 15ms
4 router2 15ms 15ms 15ms
5 router1 15ms 15ms 15ms
6 router2 15ms 16ms 16ms
...

Was ist denn hier passiert?

Router1 hat irgendwann einmal wissen wollen, wer denn für die Ziel-IP zuständig ist und Router2 antwortete viel schneller als das Kundengerät. So lernte Router1 die MAC von Router2 für diesen Kunden.

Irgendwann endete der ARP-Eintrag von Router2 für das Ziel und nun war Router2 an der MAC des Zielsystems interessiert. Diesmal konnte Router1 aushelfen, denn er hatte noch einen gültigen Eintrag im Cache.

Noch schlimmer wird es, wenn in diesem Netz weitere Router oder Server aktiv sein müssen. Sobald der Router, derlocal-proxy-arp aktiviert hat, einen ARP Eintrag um Cache hat, wird er diesen benutzen, um sich in den Verkehr zu drängeln. Da der Router nun selbst die gewünschten Ziele erreichen kann, schließlich ist das sein Job, entzieht er die Pakete der speziellen Verarbeitung, die von dem angeschlossenen System geleistet werden soll.

Besonders auffällig ist das, wenn bestimmte Endkunden nur lokal gültige Bereiche benutzen und die externe Kommunikation durch NAT-Gerät vermittelt werden muss. Wird derartiger Traffic dem NAT-Gerät entzogen, gehen die Datenpakete ungenattet in die weite Welt. Ergebnis: Der Kunde ist offline, da keine Antwortpakete mehr zu ihm zurück finden.

Es bleibt also vorerst dabei, die Redundanz vorzubereiten und bei Bedarf manuell zu aktivieren. Das ist kein ernsthaftes Problem, da die Zuführung ebenfalls nur über eine manuelle Redundanz verfügt und direkt auf dem Router terminiert, der das local-proxy-arp bedient.

Ausblick

Eine Lösung dieses Problems steht noch mit einem anderen Effekt in Zusammenhang. Ich stelle erst das andere Problem dar, dann komme ich zur Lösung.

Next » 1 2 3