Unschöne Einschränkung bei Sockets von FHEMWEB

Begonnen von alanblack, 25 Februar 2022, 15:58:38

Vorheriges Thema - Nächstes Thema

alanblack

Hallo zusammen,

ich bin über eine unschöne Einschränkung bei der Definition einer FHEMWEB-Instanz gestolpert:
ZitatIPV6: Can't open server port at 8084: Address already in use
Die Fehlermeldung kommt aus
defmod IPV6 FHEMWEB IPV6:8084
Vom Text an sich ist die Aussage auch insoweit korrekt, als dass es eine IPv4-Instanz vom FHEMWEB gibt, die am Port 8084 lauscht. Jedoch ist der Socket [ipv6]:8084 bis dato nicht belegt.
Ein
netstat -anlp | grep 8084
ergibt auch zutreffender Weise
tcp        0      0 127.0.0.1:8084          0.0.0.0:*               LISTEN      -
nur einen offenen Port auf IPv4.

Daher die Frage: ist das halbwegs einfach zu lösen? Ich habe schon in 01_FHEMWEB und in TcpServerUtils::TcpServer_Open() versucht, den Fehler zu erkennen, komme aber nicht darauf.

Ich könnte sonst als Workaround einen anderen Port nehmen; mit bspw. "8086 global" geht der Zugriff per IPv6. Nur ist es meiner Ansicht nach unschön, wenn ich schauen muss, ob ich nun per IPv4 oder IPv6 zugreife, damit ich dann den richtigen Port angebe.

Grüße
FHEM 6.0 auf raspi3&ODROID XU4 mit HMLAN und HM-MOD-RPI-PCB, LaCrosse via JeeLink, COC868 und CUL433, Xiaomi Aqara+div. Zigbee via deCONZ, Dooya via SIGNALDuino, ZWave mit Danalock
Jeder Witz kann ein Einzeiler sein mit genügend Semikolons

justme1968

#1
das kann ich zumindest unter mac os nicht bestätigen.

ich kann wie von dir beschrieben eine eine instanz für ipv6 unter dem gleichen 8083 port anlegen, mit safari auf http://127.0.0.1:8083/fhem für ipv4, auf http://[::1]:8083/fhem für ipv6 und mit localhost zufällig auf eine von beiden (d.h. wer gerade schneller ist) zugreifen.

edit: unter linux geht es bei mir ebenfalls.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

alanblack

Zitat von: justme1968 am 25 Februar 2022, 16:10:38
das kann ich zumindest unter mac os nicht bestätigen.
[...]
edit: unter linux geht es bei mir ebenfalls.

Danke für die schnelle Rückmeldung! Also muss der Fehler woanders liegen...

...

Jepp! Gefunden! Wenn ein Socket "global" ist, muss der Socket im anderen Stack auch "global"sein - bzw. beides "nicht global".

Ich hatte angenommen, dass ich das auf IPv4 fertige Konstrukt mit FHEM, nginx und Paketfilter stückweise auf IPv6 erweitern kann. Aber da muss dann wohl einiges "gleichzeitig" passieren. Auch ok!

Nochmal, danke!

Grüße
FHEM 6.0 auf raspi3&ODROID XU4 mit HMLAN und HM-MOD-RPI-PCB, LaCrosse via JeeLink, COC868 und CUL433, Xiaomi Aqara+div. Zigbee via deCONZ, Dooya via SIGNALDuino, ZWave mit Danalock
Jeder Witz kann ein Einzeiler sein mit genügend Semikolons

rudolfkoenig

Komischerweise geht unter Linux Folgendes nicht:
define w1 FHEMWEB IPV6:8083 global
define w2 FHEMWEB 8083 global


Folgendes aber schon:
define w1 FHEMWEB IPV6:8083 2001:X:f05e
define w2 FHEMWEB 8083 192.168.178.Y
und auch
define w1 FHEMWEB IPV6:8083
define w2 FHEMWEB 8083


Offensichtlich belegt global irgendwie beide Protokolle, auch wenn "8083 global" oder "IPV6:8083 global" in der lsof Ausgabe jeweils nur eine LISTEN-Zeile mit dem richtigen Protokoll (IPv4 bzw IPv6) erzeugt.

alanblack

#4
Zitat von: rudolfkoenig am 25 Februar 2022, 18:05:49
Komischerweise geht unter Linux Folgendes nicht:
define w1 FHEMWEB IPV6:8083 global
define w2 FHEMWEB 8083 global

[...]
Offensichtlich belegt global irgendwie beide Protokolle, auch wenn "8083 global" oder "IPV6:8083 global" in der lsof Ausgabe jeweils nur eine LISTEN-Zeile mit dem richtigen Protokoll (IPv4 bzw IPv6) erzeugt.
Ich habe hier doch noch einmal "aufgemacht"...
@rudolfkoenig
Mein Verdacht geht jetzt in Richtung Zeile 30 von TcpServerUtils.pm:
    Domain    => ($hash->{IPV6} ? AF_INET6() : AF_UNSPEC), # Linux bug
Abgesehen davon dass laut https://metacpan.org/pod/IO::Socket::INET6 die Nutzung von"IO::Socket::INET6" veraltet ("deprecated") ist, dürfte das Öffnen von Sockets einmal mit AF_UNSPEC und einmal mit AF_INET6 mit dem selben Port sich ausschließen. Der Linux-Bug, der im Kommentar angesprochen wird, müsste der hier sein https://linux.debian.bugs.dist.narkive.com/mxpXjFVa/bug-522478-libio-socket-inet6-perl-af-unspec-fails-for-ipv6-hosts, richtig? Dann ist die Unterscheidung in AF_UNSPEC und AF_INET6 nicht zweckdienlich. Dann wäre es besser, eindeutig zu werden und
    Domain    => ($hash->{IPV6} ? AF_INET6() : AF_INET), # Linux bug
zu nutzen. Oder?
Ich habe diese Änderung mal gemacht. Jetzt geht zumindest mal IPv4 global mit IPv6 (nicht global). Wenn ich es andersherum versuche, - also IPv4 (nicht global) und IPv6 global, bekomme ich die Meldung
ZitatIPV6: Can't open server port at 8084: Address already in use
Da finde ich die Ursache noch nicht.

Grüße

Nachtrag: ich hatte überlesen, dass der besagte Bug 2009 gemeldet wurde. Ist der überhaupt noch existent? Wäre er dann der Grund, warum IPv4 (nicht global) und IPv6 global nicht funktioniert?
FHEM 6.0 auf raspi3&ODROID XU4 mit HMLAN und HM-MOD-RPI-PCB, LaCrosse via JeeLink, COC868 und CUL433, Xiaomi Aqara+div. Zigbee via deCONZ, Dooya via SIGNALDuino, ZWave mit Danalock
Jeder Witz kann ein Einzeiler sein mit genügend Semikolons

alanblack

Zitat von: alanblack am 26 Februar 2022, 11:15:51
Nachtrag: ich hatte überlesen, dass der besagte Bug 2009 gemeldet wurde. Ist der überhaupt noch existent? Wäre er dann der Grund, warum IPv4 (nicht global) und IPv6 global nicht funktioniert?
Muss mir mal selbst antworten:
Wenn ich den o.g. Bug richtig verstehe, dürfte IPv6 global gar nicht gehen. Das habe ich gerade noch ausprobiert: geht!

Grüße
FHEM 6.0 auf raspi3&ODROID XU4 mit HMLAN und HM-MOD-RPI-PCB, LaCrosse via JeeLink, COC868 und CUL433, Xiaomi Aqara+div. Zigbee via deCONZ, Dooya via SIGNALDuino, ZWave mit Danalock
Jeder Witz kann ein Einzeiler sein mit genügend Semikolons

rudolfkoenig

ZitatIch habe diese Änderung mal gemacht. Jetzt geht zumindest mal IPv4 global mit IPv6 (nicht global).
Danke fuer die Recherche.

Gibt es parktische Probleme, wo diese Aenderung hilft?
Ich will Nebeneffekte vermeiden, wenn man keine klaren Vorteile hat.

alanblack

Zitat von: rudolfkoenig am 26 Februar 2022, 11:36:00
Danke fuer die Recherche.
Gerne!

Zitat
Gibt es parktische Probleme, wo diese Aenderung hilft?
Ich bin dabei, mein Heimnetz zunächst auf vollständig Dualstack aufzurüsten, um im nächsten Schritt dann (in unbestimmter Zukunft) eventuell IPv4 abzuschalten. IPv6 hat halt einen Haufen Vorteile, die ich aktuell verstehen lerne, um sie dann auch zu nutzen.

Jedenfalls bräuchte ich dafür derzeit ein IPv6 global - was ja leider noch nicht geht. Ich werde zwar nginx, welches auf IPv4 schon davor hängt, auch auf IPv6 davor hängen, muss dort aber mehr Änderungen vorwärts und rückwärts machen, wenn ich jetzt für IPv4 und IPv6 unterschiedliche Ports nutze. Wenn ich jetzt mit IPv6 global testen kann und dann etwas nicht funktioniert, kann ich FHEM immer als Ursache schnell ausschließen.

Zitat
Ich will Nebeneffekte vermeiden, wenn man keine klaren Vorteile hat.
Verstehe ich voll.
Ich schaue mir nebenbei die Änderungen an, die für den Umstieg IO::Socket::INET6 auf IO::Socket::IP erforderlich sind. Die braucht FHEM ja eh in absehbarer Zeit. Wenn damit dann IPv4 (nicht global) mit IPv6 (global) geht, hätten wir zwei Fliegen mit einer Klappe geschlagen.

Grüße
FHEM 6.0 auf raspi3&ODROID XU4 mit HMLAN und HM-MOD-RPI-PCB, LaCrosse via JeeLink, COC868 und CUL433, Xiaomi Aqara+div. Zigbee via deCONZ, Dooya via SIGNALDuino, ZWave mit Danalock
Jeder Witz kann ein Einzeiler sein mit genügend Semikolons

rudolfkoenig

ZitatJedenfalls bräuchte ich dafür derzeit ein IPv6 global - was ja leider noch nicht geht.
Ich habe kein Problem mit IPv6 global, nur zusammen mit IPv4 global geht das nicht.
Und ich meinte, ob sowas wie "IPv6 global + IPv4 (ohne global)" einen praktischen Nutzen hat.

alanblack

Zeile 7:
use IO::Socket; nach
use IO::Socket::IP -register;

Zeilen 17-24:
    eval "require IO::Socket::INET6; use Socket6;";
    if($@) {
      Log3 $hash, 1, $@;
      Log3 $hash, 1, "$name: Can't load INET6, falling back to IPV4";
    } else {
      $hash->{IPV6} = 1;
    }
nach

#    eval "require IO::Socket::INET6; use Socket6;";
#    if($@) {
#      Log3 $hash, 1, $@;
#      Log3 $hash, 1, "$name: Can't load INET6, falling back to IPV4";
#    } else {
      $hash->{IPV6} = 1;
#    }

(testhalber auskommentiert! kann evtl. gelöscht oder gänzlich vereinfacht werden)

Zeile 30:
Domain    => ($hash->{IPV6} ? AF_INET6() : AF_UNSPEC), # Linux bug nach
Domain    => ($hash->{IPV6} ? PF_INET6() : PF_INET),

Zeile 38-40:
  $hash->{SERVERSOCKET} = $hash->{IPV6} ?
        IO::Socket::INET6->new(@opts) :
        IO::Socket::INET->new(@opts);
nach
  $hash->{SERVERSOCKET} = IO::Socket::IP->new(@opts);


Geänderte TcpServerUtils.pm angehängt.

Damit startet FHEM auf meinem raspi fehlerfrei. Wenn ich aber dann ein
defmod IPV6 FHEMWEB IPV6:8084 global mache, läuft FHEM in Zeile 60
  my @clientinfo = $hash->{SERVERSOCKET}->accept();
wohl auf einen Fehler und meldet x-fach pro Sekunde
Log3 $name, 1, "Accept failed ($name: $!)" if($! != EAGAIN);. Da muss ich nochmal schauen, warum.

Bitte sonst gerne mal testen - vielleicht nicht auf einem Produktivsystem - und Rückinfo geben. Danke!

Grüße
FHEM 6.0 auf raspi3&ODROID XU4 mit HMLAN und HM-MOD-RPI-PCB, LaCrosse via JeeLink, COC868 und CUL433, Xiaomi Aqara+div. Zigbee via deCONZ, Dooya via SIGNALDuino, ZWave mit Danalock
Jeder Witz kann ein Einzeiler sein mit genügend Semikolons

alanblack

Zitat von: rudolfkoenig am 26 Februar 2022, 12:55:21
Ich habe kein Problem mit IPv6 global, nur zusammen mit IPv4 global geht das nicht.
Hast Du mal IPv4 (ohne global) und dann ein IPv6 global auf den selben Port getestet?

ZitatUnd ich meinte, ob sowas wie "IPv6 global + IPv4 (ohne global)" einen praktischen Nutzen hat.
Dazu schrieb ich:
ZitatIch werde zwar nginx, welches auf IPv4 schon davor hängt, auch auf IPv6 davor hängen, muss dort aber mehr Änderungen vorwärts und rückwärts machen, wenn ich jetzt für IPv4 und IPv6 unterschiedliche Ports nutze. Wenn ich jetzt mit IPv6 global testen kann und dann etwas nicht funktioniert, kann ich FHEM immer als Ursache schnell ausschließen.

Grüße
FHEM 6.0 auf raspi3&ODROID XU4 mit HMLAN und HM-MOD-RPI-PCB, LaCrosse via JeeLink, COC868 und CUL433, Xiaomi Aqara+div. Zigbee via deCONZ, Dooya via SIGNALDuino, ZWave mit Danalock
Jeder Witz kann ein Einzeiler sein mit genügend Semikolons

rudolfkoenig

ZitatHast Du mal IPv4 (ohne global) und dann ein IPv6 global auf den selben Port getestet?
Ja, in der aktuell eingecheckten Version geht das nicht. Ich verstehe nur nicht, wem das helfen soll, auch nachdem ich dein Text dreimal gelesen habe :) Ich kann Szenarien fuer beides lokal oder beides global vorstellen, aber nicht so recht Welche fuer die gemischte Variante.

alanblack

Zitat von: rudolfkoenig am 26 Februar 2022, 13:09:39
Ich kann Szenarien fuer beides lokal oder beides global vorstellen, aber nicht so recht Welche fuer die gemischte Variante.
Mein aktuelles Szenario ist, dass ich plane von einem Dualstack-Inet Anschluss zu einem mit Dualstack mit CGNAT zu wechseln. Dabei habe ich bei IPv4 mit SSL, Letsencrypt, Paketfilter und nginx und das Loch für den Zugriff von außen auf FHEM so klein wie möglich gemacht. Zumindest haben zwei IT-Kollegen keine Lücke mehr gefunden.
Jetzt möchte ich ein zweites Loch öffnen - das Gleiche nur halt in IPv6. Wenn das auch geht, kann ich mit
1. Änderung von FHEMWEB von IPv6 global auf "nicht-global"
2. Änderung im Paketfilter
3. Änderung des DNS-Records
das zweite Loch aktivieren... und ggf. das "alte" gleich schließen.
Wenn zwischenzeitlich etwas nicht geht, kann ich mit [FHEMIPv6]:8083 die Ursache für den Fehler dort schnell ausschließen.

Grüße
FHEM 6.0 auf raspi3&ODROID XU4 mit HMLAN und HM-MOD-RPI-PCB, LaCrosse via JeeLink, COC868 und CUL433, Xiaomi Aqara+div. Zigbee via deCONZ, Dooya via SIGNALDuino, ZWave mit Danalock
Jeder Witz kann ein Einzeiler sein mit genügend Semikolons