WARNUNG: Tunneldigger Bug im usage

Moin,

@Fungur und ich haben heute Abend einen Bug im Tunneldigger entdeckt.

Das usage-Feature hat eine Macke. Wenn man mehr als zwei Broker aktiviert, klappt aus bisher unbekanntem Grund die Übermittlung der „usage“ nicht. Alle Gegenstellen (Broker) erhalten 65535 (Integer Maximum) für die Variable „usage“. Für den Fall, dass alle Gegenstellen dieselbe Zahl übermitteln, bleibt es bei der ersten Verbindung (best = 0). Es wird also das erste eingetragene Ziel ohne jegliche Überprüfung auf Verfügbarkeit verwendet, die IP muss nichtmals pingbar sein.

Wenn man also mehr als zwei Gateways in seiner site.conf hat, wird also nur noch das erste Gateway verwendet und wenn dieses dann ausfällt, sind alle Knoten offline.

Ich hab einen kleinen Patch eingereicht, der als Ausweichlösung für den Fall, dass das erste Gateway nicht erreichbar ist, dann einfach den Algorithmus „first_available“ ausführt (Fallback).

https://github.com/ffrl/tunneldigger/pull/2

Grüße
Matthias

2 Likes

@CyrusFox
Magst Du mal das hineinnehmen.
Danke.

(Das Szenario hatte ich nämlich leider schon und merke jetzt, dass das wohl dieses gewesen ist, was dafür gesorgt hat, dass die Nodes nicht umgeschwitched sind.)

@adorfer
Ist drin, aber vorerst nur im master zweig für testing :slight_smile:

1 Like

Haben wir schon gehabt ;(

Ist bei mir halt leider nie aufgefallen weil wir nie mehr als zwei Supernodes verwenden. Aber wenn demnächst Babel soweit ist werden wir komplett darauf wechseln sobald es stabil genug ist. Dann werden wir wohl auch keine Netsplits mehr brauchen und größere Communities betreiben können.

1 Like

Ich denke unabhängig von der Babel-Entwicklung sollten wir das reparieren.

Gibt es irgendwo eine Doku dazu, was da in dem UDP-Paket eigentlich übermittelt wird? Wir können uns das bisher nur als zeitliches Problem (Stichwort race condition) vorstellen, da der Code nicht so ausgelegt ist, dass er auf zwei Gegenstellen beschränkt ist.

Wir haben versucht da die Abläufe etwas zu verstehen. Also scheinbar wird eine Art Tunnel aufgebaut und wenn dieser ausgewählt wird, bleibt er bestehen, wird ein anderer gewählt, wird er wieder abgebaut. Haben wir das richtig verstanden?

Was wir nicht verstanden haben ist, warum die Verfügbarkeit (standby_available) korrekt ermittelt wird, aber die „usage“ nicht. Das müsste eigentlich im selben Paket enthalten sein. Oder werden da mehrere Statuspakete gesendet?

1 Like

Hat auch keiner gesagt, aber ich habe meist leider nur Zeit für die Integration in Gluon.
Daher wäre es nicht schlecht wenn jemand mit C Kenntnissen sich daran versucht.

In dem UDP Paket wird nur ein Integer von 0 bis 65535 übertragen, der Bug ist im Client selbst und nicht in der Übertragung der UDP Pakete.

Es besteht eine Kontrol-Verbindung, kein Tunnel. Darüber werden die Informationen für den L2TP Tunnel übertragen, abgebaut wird nichts dynamisch außer der Broker oder Client trennt die Verbindung. Es wird also nicht automatisch auf den zweiten Broker gewechselt.

Ein „Standby“ Paket existiert nicht, dies ist nur ein Kontext im Client selbst der mit den verfügbaren Brokern gefüllt wird.

Die folgenden Pakettypen existieren (Aus dem Quellcode des Brokers entnommen):

Unreliable messages (0x00 - 0x7F).

CONTROL_TYPE_COOKIE = 0x01
CONTROL_TYPE_PREPARE = 0x02
CONTROL_TYPE_ERROR = 0x03
CONTROL_TYPE_TUNNEL = 0x04
CONTROL_TYPE_KEEPALIVE = 0x05
CONTROL_TYPE_PMTUD = 0x06
CONTROL_TYPE_PMTUD_ACK = 0x07
CONTROL_TYPE_REL_ACK = 0x08
CONTROL_TYPE_PMTU_NTFY = 0x09
CONTROL_TYPE_USAGE = 0x0A

Reliable messages (0x80 - 0xFF).

MASK_CONTROL_TYPE_RELIABLE = 0x80
CONTROL_TYPE_LIMIT = 0x80

Die Struktur eines Pakete ist wie folgt:

magic1, magic2, version, msg_type, msg_length, data[6:6 + msg_length]

Das Parsing selbst sieht so aus:

def parse_message(data):
    """
    Parses a tunneldigger control message.
    :param data: Raw data
    :return: A tuple (type, payload) containing the message type and payload
    """

    if len(data) < 6:
        return INVALID_MESSAGE

    # Parse header.
    magic1, magic2, version, msg_type, msg_length = struct.unpack('!BHBBB', data[0:6])
    if magic1 != 0x80 or magic2 != 0x73A7:
        return INVALID_MESSAGE

    if version != 1:
        return INVALID_MESSAGE

    try:
        return msg_type, data[6:6 + msg_length]
    except IndexError:
        return INVALID_MESSAGE

Weißt du, wofür genau der Typ Cookie steht? Also für eine etablierte Kontrollverbindung z. B.?

Gleiches gilt für PMTUD, REL_ACK und PMTU_NTFY. Darauf konnte ich mir bisher noch keinen Reim machen, falls du dazu noch Wissen hast, wäre das praktisch.

Der Cookie wird beim aufbauen der Verbindung vom Broker vergeben um die Verbindung selbst zu identifizieren.

PMTUD und PMTU_NTFY sind für die dynamische Berechung der Path MTU. Diese verwenden wir aber nicht da Batman kein dynamisches ändern der MTU erlaubt.

REL_ACK ist für die Reliable Messages und dient zum bestätigen eines solchen Kontrol-Paketes.

Edit: Am besten mal über den Broker Source lesen, dort ist zumindest alles mit Comments versehen:
https://github.com/ffrl/tunneldigger/blob/master/broker/l2tp_broker.py

1 Like

Deswegen hatte ich bei uns die max. Tunneldiggerinstanzen vor Zeiten bereits auf zwei reduziert.
Mehr sind ja eigentlich nicht nötig.

Jetzt braucht der Tunneldigger nur noch IPv6 Support und alles wird gut.

2 Likes

4 Beiträge wurden in ein neues Thema verschoben: Tunneldigger IPv6 support

Hi zusammen,

Der Bug ist nun gefixt.
@Fungur war so nett einen Patch für den Tunneldigger Client zu schreiben , ich habe dies auch schon lokal verifiziert.

Release für Gluon 2016.1.4:

Sowie für Gluon 2016.1.3:

1 Like