Autor Thema: DevIo.pm IPv6 Support  (Gelesen 672 mal)

Offline dev0

  • Developer
  • Hero Member
  • ****
  • Beiträge: 2824
    • _.:|:._
DevIo.pm IPv6 Support
« am: 18 August 2017, 12:36:01 »
Mir ist gestern beim Testen eines neuen FHEM Commands aufgefallen, dass DevIo.pm kein IPv6 unterstützt. Wenn ich allerdings die IO::Socket::INET6 Doku richtig verstehe, dann sollte man ::INET durch ::INET6 ersetzen können und alles ist gut... Über diesen Weg lassen sich bei mir alle Varianten aufrufen: "hostname:port" mit A und/oder AAAA DNS Records als auch "IPv4:port" und "[IPv6]:port". Die Reihenfolge, ob IPv4 oder IPv6 zuerst, wird vom Betriebssystem vorgegeben. Bei einem halbwegs aktuellem OS ist das erst v6, dann v4.

In meiner Dual-Stack-Umgebung, mit aktueller IO::Socket::INET6 Version, funktioniert das auch ohne Probleme. Leider habe ich nur eine Versionshistorie zurück bis zur Version 2.53 aus dem Jahr 2008 gefunden. Der SVN Server, der die vollständige History liefern soll, ist nicht (mehr?) erreichbar. Daher prüft der angehangene Patch, ob ::INET6 geladen werden kann und dann noch, ob eine Verbindung mit ::INET6 hergestellt werden kann. Wenn nicht, dann Fallback auf ::INET (ohne IPv6 und ggf. eine Fehlermeldung, wenn der Host nur IPv6 'spricht').

Diese ganze Prüferei geht allerdings auch auf Kosten von max. dem 2-3 fachen blockierenden Timeout, wenn im Extremfall ::INET6 vorhanden, aber ggf. zu alt und dann noch ein A und AAAA DNS Record für einen Hostnamen existiert, der nicht antwortet.

Beim Anwender könnte sich theoretisch eine fehlerhafte IPv6 Konfigurationen, die durch die Verwendung von ::INET6 zum Tragen kommt, auswirken. Das sollte sich mMn aber auf ein verdoppeltes Timeout beschränken, wenn die, im DNS hinterlegte, IPv6 Adresse nicht erreichbar ist.

Den (zu teuren?) Patch bitte nur als Vorschlag/Entwurf/Demo verstehen. Vielleicht gibt es eine viel elegantere Möglichkeit IPv6 Unterstützung in DevIO einzubauen, die ich nicht sehe.

@Rudi: kannst Du Dir vorstellen so etwas in DevIo einzubauen?
@All: Meinungen, Vorschläge ? (wenn Rudi nicht ganz abgeneigt ist)

Sorry, falls zu viel Text ;)

Index: FHEM/DevIo.pm
===================================================================
--- FHEM/DevIo.pm (revision 14902)
+++ FHEM/DevIo.pm (working copy)
@@ -354,7 +354,21 @@
       return undef;     # no double callback: connect is running in bg now
 
     } else {
-      my $conn = IO::Socket::INET->new(PeerAddr => $dev, Timeout => $timeout);
+      my $conn;
+      my $l = $hash->{devioLoglevel};
+      eval "require IO::Socket::INET6";
+      if(!$@) {
+        $conn = IO::Socket::INET6->new(PeerAddr => $dev, Timeout => $timeout, Multihomed => 1);
+        if (!$conn) {
+          $conn = IO::Socket::INET->new(PeerAddr => $dev, Timeout => $timeout);
+          Log3 $name, ($l ? $l:5), "Perl module IO::Socket::INET6 found, but too old to handle IPv4.";
+        } else {
+          Log3 $name, ($l ? $l:5), "Perl module IO::Socket::INET6 found, new .";
+        }
+      } else {
+        $conn = IO::Socket::INET->new(PeerAddr => $dev, Timeout => $timeout);
+        Log3 $name, ($l ? $l:5), "Perl module IO::Socket::INET6 not installed, "."fallback to ::INET (IPv4 only).\n$@";
+      }
       return "" if(!&$doTcpTail($conn)); # no callback: no doCb
     }
« Letzte Änderung: 18 August 2017, 12:55:50 von dev0 »

Offline rudolfkoenig

  • Administrator
  • Hero Member
  • *****
  • Beiträge: 16902
Antw:DevIo.pm IPv6 Support
« Antwort #1 am: 18 August 2017, 13:22:59 »
Ich habe nichts gegen eine IPV6 Unterstuetzung.

Ich ueberlege, ob es nicht vertretbar ist, INET einfach durch INET6 zu ersetzen. Wenn das Modul nicht vorhanden ist, sollte der Benutzer es installieren, und wenn IPV6 falsch konfiguriert ist, dann gibt es mit FHEM noch ein Programm, das Probleme hat, man sollte es also richtig konfigurieren. Und wenn IPV6 nicht konfiguriert ist, sollte es auch nicht stoeren.

Warum ist Multihome notwendig?

Offline dev0

  • Developer
  • Hero Member
  • ****
  • Beiträge: 2824
    • _.:|:._
Antw:DevIo.pm IPv6 Support
« Antwort #2 am: 19 August 2017, 08:57:59 »
Zitat
Warum ist Multihome notwendig?
Multihomed ist nicht notwendig, ich hatte vergessen die Option aus dem Patch heraus zu nehmen. Da meine Internetanbindung Multihomed ist, werde ich ggf. noch einmal darauf zurück kommen, wenn ich es weiter getestet habe. Für die IPv6 Unterstützung ist das aber erst einmal nicht relevant.

Zitat
Ich ueberlege, ob es nicht vertretbar ist, INET einfach durch INET6 zu ersetzen.
Ich habe das gerade mal auf meinem produktiven System getestet:
- IO::Socket::INET6 muss in DevIo.pm via require/use geladen werden, was bei ::INET anscheinend nicht notwendig ist.
- Das Sonos Modul funktionierte nicht mehr. Auf den ersten Blick auch ohne einen Logeintrag dazu.
- Mit der Variante "if (!$conn) { $conn = IO::Socket::INET->new... }" funktioniert ersteinmal auch alles Weitere normal.

Mhh... Ich bin jetzt allerdings auch unsicher, ob diese if Variante auch alle anderen Fälle abdeckt, an die ich nicht gedacht habe bzw. nicht nutze.
Macht es vielleicht Sinn mit IO::Socket::IP zu testen? Gibt es damit schon Erfahrungen?

Edit: IO::Socket::IP funktioniert auch ohne Fallback auf ::INET mit dem Sonos Modul. Vermutlich wird aber kaum jemand das Perl Modul IO::Socket::IP installiert haben.
« Letzte Änderung: 19 August 2017, 09:39:17 von dev0 »

Offline rudolfkoenig

  • Administrator
  • Hero Member
  • *****
  • Beiträge: 16902
Antw:DevIo.pm IPv6 Support
« Antwort #3 am: 19 August 2017, 13:01:53 »
Zitat
- Das Sonos Modul funktionierte nicht mehr. Auf den ersten Blick auch ohne einen Logeintrag dazu.
Danke, damit ist die direkte Umstellung erstmal vom Tisch. Kannst du bitte versuchen rauszufinden, was die Ursache ist?

Ich wuerde gerne IPv6 fuer FHEM transparent einbauen, so dass der Benutzer (ausser IO::Socket::INET6 zu installieren) nichts machen muss. Dafuer muesste ich:
- DevIo und HttpUtils erweitern mit INET6
- HttpUtils_dnsParse AAAA beibringen
Und am Anfang muesste IPv6 per Attribut deaktiviert sein, fuer die Problemfaelle, wie bei Sonos.

Offline dev0

  • Developer
  • Hero Member
  • ****
  • Beiträge: 2824
    • _.:|:._
Antw:DevIo.pm IPv6 Support
« Antwort #4 am: 19 August 2017, 13:13:23 »
Zitat
Kannst du bitte versuchen rauszufinden, was die Ursache ist?
Kann ich versuchen, aber vielleicht Reinerlein schon eine Idee dazu?

IO::Socket::IP ist für Dich auch vom Tisch, weil vmtl. im FHEM-Umfeld kaum verbreitet? Wäre das dann nicht ggf. eine Möglichkeit für das nächste (Feature-)Release? Es soll angeblich ein Replacement für ::INET sein (habe ich im Hinterkopf, nicht konkret recherchiert).

Offline rudolfkoenig

  • Administrator
  • Hero Member
  • *****
  • Beiträge: 16902
Antw:DevIo.pm IPv6 Support
« Antwort #5 am: 19 August 2017, 13:35:10 »
Zitat
IO::Socket::IP ist für Dich auch vom Tisch,
Nicht unbedingt, hoere aber jetzt zum erstenmal davon, und traue dem deswegen noch nicht.
Laut Doku braucht man dafuer 5.14 (d.h. perl von 2011), oder die Installation wird komplizierter.
Das .deb Paket installiert z.Zt. auch nur INET6 aber nicht IP.
Bin noch unentschieden.

Offline dev0

  • Developer
  • Hero Member
  • ****
  • Beiträge: 2824
    • _.:|:._
Antw:DevIo.pm IPv6 Support
« Antwort #6 am: 20 August 2017, 07:16:51 »
Zitat
Das .deb Paket installiert z.Zt. auch nur INET6 aber nicht IP.
Bist Du sicher? Laut https://packages.debian.org/stretch/all/libio-socket-ip-perl/filelist wird IP.pm installiert. Ich kenne mich aber mit den verschiedenen Debian Versionen nicht so gut aus...

Das Sonos Modul scheint auch IO::Socket::IP zu nutzen (ohne es explizit zu laden?), vielleicht nur dann wenn es installiert ist, da es zumindest schon mal Fehlermeldungen diesbezüglich gab: https://forum.fhem.de/index.php?topic=47758 . Habe aber noch nicht tiefer in den Source geguckt.

Offline rudolfkoenig

  • Administrator
  • Hero Member
  • *****
  • Beiträge: 16902
Antw:DevIo.pm IPv6 Support
« Antwort #7 am: 20 August 2017, 16:25:45 »
Ich habe eine erste Version von INETv6 Support in DevIo.pm und HttpUtils.pm eingecheckt, die synchrone Verbindungen solten unterstuetzt werden, die asynchronen (wie dnsServer und HTTP_NonblockingGet) noch nicht, das ist aufwendiger, als ich dachte.

Zum aktivieren muss man "attr global useInet6" setzen, dann versucht fhem.pl IP:Socket::INET6 zu laden und zu verwenden.
Ich werde es erst dokumentieren, wenn etwas mehr Erfahrung damit vorliegt, und auch nonblocking implementiert ist.

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 13419
  • Das "S" in "IoT" steht für "Security"
Antw:DevIo.pm IPv6 Support
« Antwort #8 am: 20 August 2017, 16:34:22 »
Zum aktivieren muss man "attr global useInet6" setzen,

ist das wieder so ein Ding, wo ein Attribut nur vorhanden sein muss, um etwas zu bewirken oder wird explizit auf "1" geprüft?
Nächster Hamburg-Stammtisch: 15.12.2017

Offline rudolfkoenig

  • Administrator
  • Hero Member
  • *****
  • Beiträge: 16902
Antw:DevIo.pm IPv6 Support
« Antwort #9 am: 20 August 2017, 20:08:12 »
Es wird auf nicht 0 geprueft:
    if($val || !defined($val)) {

Offline rudolfkoenig

  • Administrator
  • Hero Member
  • *****
  • Beiträge: 16902
Antw:DevIo.pm IPv6 Support
« Antwort #10 am: 22 August 2017, 19:35:42 »
Ich habe in HttpUtils.pm das useInet6 global Attribut auch fuer nonblocking implementiert, inklusive aysnchrones DNS. Ich habe versucht die Aenderungen beim nicht gesetzten useInet6 zu minimieren, und habe viel getestet, bin aber nicht sicher, ob ich nicht etwas uebersehen habe. Mit gesetzten useInet6 wird zunaechst IPv6 versucht, und dann IPv4.

Was nicht geht: eine IPv6 Adresse direkt zu spezifizieren, da ich mit dem Regexp von Boris ueberfordert bin. Falls jemand helfen will, Folgendes muss angepasst werden:

  if($hash->{url} !~
           /^(http|https):\/\/(([^:\/]+):([^:\/]+)@)?([^:\/]+)(:\d+)?(\/.*)$/) {
    return "$hash->{displayurl}: malformed or unsupported URL";
  }

  my ($authstring,$user,$pwd,$port,$host);
  ($hash->{protocol},$authstring,$user,$pwd,$host,$port,$hash->{path})
        = ($1,$2,$3,$4,$5,$6,$7);
und so, dass man fuer $host auch sowas wie [::1] spezifizieren kann.

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 13419
  • Das "S" in "IoT" steht für "Security"
Antw:DevIo.pm IPv6 Support
« Antwort #11 am: 22 August 2017, 21:34:58 »
Schau Dir doch mal das perl Modul Regexp::IPv6 an. Das liefert genau, was Du suchst und es sind nur ein paar Zeilen Coding, die sich sicher auch direkt in FHEM unterbringen lassen. Das wäre sicher auch eine Funktionalität, die man an anderen Stellen innerhalb FHEM künftig noch öfters benötigen wird.

Nächster Hamburg-Stammtisch: 15.12.2017

Offline dev0

  • Developer
  • Hero Member
  • ****
  • Beiträge: 2824
    • _.:|:._
Antw:DevIo.pm IPv6 Support
« Antwort #12 am: 23 August 2017, 10:44:12 »
Mit folgender regex funktioniert auch die Schreibweise [IPv6] als host address, allerdings klemmt es danach noch irgendwo, da die IPv6 Adresse als Hostname interpretiert wird: "DNS: No A record found". Den 'auth string' Teil der Regex habe ich auch noch angepasst, da sonst keine [:/] im Passwort erlaubt waren, aber nur sehr kurz getestet. Die Regex kann man natürlich noch vereinfachen, wenn man nicht bis ins vorletzte Detail prüfen möchte.

  my $rAuth = "([^:\/]+):(.+)@";
  my $rV4   = "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
  my $rV6   = "(?:(?:[0-9a-f]{1,4}:){7,7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?:(?::[0-9a-f]{1,4}){1,6})|:(?:(?::[0-9a-f]{1,4}){1,7}|:)|fe80:(?::[0-9a-f]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|(?:[0-9a-f]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]))";
  my $rPort = "(?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])";
  my $rFqdn = "(?:[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*\.)+[A-Za-z]{2,}";
  my $rHost = "(?:[A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])";

  if($hash->{url} !~
           m/^(http|https):\/\/($rAuth)?($rV4|\[$rV6]|$rFqdn|$rHost)(:$rPort)?(\/.*)$/) {
    return "$hash->{displayurl}: malformed or unsupported URL";
  }

  my ($authstring,$user,$pwd,$port,$host);
  ($hash->{protocol},$authstring,$user,$pwd,$host,$port,$hash->{path})
        = ($1,$2,$3,$4,$5,$6,$7);

Die Variablen $1..$7 werden korrekt zugewiesen, zum Debuggen hatte folgende commands eingebaut:
Debug "url: $hash->{url}";
Debug "\$1 prot:$1"; 
Debug "\$2 auth:$2"; 
Debug "\$3 user:$3"; 
Debug "\$4 pass:$4"; 
Debug "\$5 host:$5"; 
Debug "\$6 port:$6"; 
Debug "\$7 path:$7"; 

Ergibt:
2017.08.23 10:08:32.078 1: DEBUG>url: https://ich:123@[2a01:488:66:1000:523:f4e2::1]:80/
2017.08.23 10:08:32.078 1: DEBUG>$1 prot:https
2017.08.23 10:08:32.079 1: DEBUG>$2 auth:ich:123@
2017.08.23 10:08:32.079 1: DEBUG>$3 user:ich
2017.08.23 10:08:32.079 1: DEBUG>$4 pass:123
2017.08.23 10:08:32.079 1: DEBUG>$5 host:[2a01:488:66:1000:523:f4e2::1]
2017.08.23 10:08:32.079 1: DEBUG>$6 port::80
2017.08.23 10:08:32.080 1: DEBUG>$7 path:/
2017.08.23 10:08:32.084 2: getURL ERROR: DNS: No A record found

Auch wenn man direkt nach der Regex die eckigen Klammern von der IPv6 Adresse entfernt, bleibt die Fehlermeldung identisch.
Ein IPv6 Request über DNS Namen funktioniert.
Nebenbei ist mir aufgefallen, dass Hostnamen aus /etc/hosts nicht aufgelöst werden, ob das vorher schon so war habe ich jetzt noch nicht getestet. Ich komme auch erst am WE wieder dazu...

Offline rudolfkoenig

  • Administrator
  • Hero Member
  • *****
  • Beiträge: 16902
Antw:DevIo.pm IPv6 Support
« Antwort #13 am: 23 August 2017, 15:01:02 »
Wenn der Regexp nur so kompliziert geht, dann muss ich selbst nachdenken, sowas spaeter debuggen kann ich nicht mehr.

Zitat
Hostnamen aus /etc/hosts nicht aufgelöst werden
Das stimmt, wenn dnsServer aktiv ist, da frage ich nur den DNS-Server.
Sonst sollte das funktionieren, da die OS-Routinen verwendet werden.

Offline dev0

  • Developer
  • Hero Member
  • ****
  • Beiträge: 2824
    • _.:|:._
Antw:DevIo.pm IPv6 Support
« Antwort #14 am: 23 August 2017, 16:07:01 »
Der Regex prüft ob IPs etc auch gültig sind. Wenn es Dir nur ums Splitten geht, dann kann man das vereinfachen.