FHEM Forum

FHEM - Hausautomations-Systeme => Zigbee => Thema gestartet von: ruff am 03 Oktober 2021, 23:14:16

Titel: [patch] [HUEBridge] proxy support for websockets
Beitrag von: ruff am 03 Oktober 2021, 23:14:16
Hi,
I'm using deconz+conbee2 but in zero-trust setup hence all networks interfaces are firewalled off and proxy whitelist is used for web policy. And while fhem speaks ok via proxy for rest api, websockets are failing due to trying to make direct connection bypassing proxy.
Hence I came up with this little patch to make use of HttpUtils for socket opening which enables proxy support.


Index: FHEM/30_HUEBridge.pm
===================================================================
--- FHEM/30_HUEBridge.pm        (Revision 25044)
+++ FHEM/30_HUEBridge.pm        (Arbeitskopie)
@@ -371,6 +371,43 @@
   HUEBridge_closeWebsocket($hash);

   my ($host,undef) = split(':',$hash->{host},2);
+
+  if( my $proxy = AttrVal("global", "proxy", undef) ) {
+    $hash->{url} = "http://$host:$hash->{websocketport}/";
+    $hash->{noConnect2} = 1;
+    $hash->{callback} = sub($) {
+      $hash->{conn}->blocking(1);
+      my $pw = AttrVal("global", "proxyAuth", "");                           
+      $pw = "Proxy-Authorization: Basic $pw\r\n" if($pw);                     
+      my $hdr = "CONNECT $host:$hash->{websocketport} HTTP/1.0\r\nUser-Agent: fhem\r\n$pw\r\n";                               
+      syswrite $hash->{conn}, $hdr;
+      my $buf;
+      my $len = sysread($hash->{conn},$buf,65536);
+      if(!defined($len) || $len <= 0 || $buf !~ m/HTTP.*200/) {
+        HttpUtils_Close($hash);
+        Log3 $name, 2, "$name: failed to open websocket via proxy";
+        return;
+      }
+
+      $hash->{CD} = $hash->{conn};
+      delete $hash->{conn};
+      $hash->{PORT} = $hash->{websocketport};
+      my $ret = "GET ws://$host:$hash->{websocketport} HTTP/1.1\r\n";
+      $ret .= HUEBridge_hash2header( {                  'Host' => "$host:$hash->{websocketport}",
+                                                     'Upgrade' => 'websocket',
+                                                  'Connection' => 'Upgrade',
+                                                      'Pragma' => 'no-cache',
+                                               'Cache-Control' => 'no-cache',
+                                           'Sec-WebSocket-Key' => 'RkhFTQ==',
+                                       'Sec-WebSocket-Version' => '13',
+                                     } );
+      $ret .= "\r\n";
+      syswrite($hash->{CD}, $ret );
+    };
+    HttpUtils_Connect($hash);
+    return;
+  }
+
   if( my $socket = IO::Socket::INET->new(PeerAddr=>"$host:$hash->{websocketport}", Timeout=>2, Blocking=>1, ReuseAddr=>1) ) {
     $hash->{CD}    = $socket;
     $hash->{FD}    = $socket->fileno();


wiki only mentions this channel for patch submission so here we are.
Titel: Antw:[patch] [HUEBridge] proxy support for websockets
Beitrag von: ruff am 04 Oktober 2021, 08:07:03
Sorry just realized it wasn't the latest version of the patch, here's the latest (and tested) one:

Index: FHEM/30_HUEBridge.pm
===================================================================
--- FHEM/30_HUEBridge.pm        (Revision 25044)
+++ FHEM/30_HUEBridge.pm        (Arbeitskopie)
@@ -371,6 +371,44 @@
   HUEBridge_closeWebsocket($hash);

   my ($host,undef) = split(':',$hash->{host},2);
+
+  if( my $proxy = AttrVal("global", "proxy", undef) ) {
+    my $h = { %$hash };
+    $h->{url} = "http://$host:$hash->{websocketport}/";
+    $h->{noConn2} = 1;
+    $h->{callback} = sub($) {
+      my ($h) = @_;
+      $h->{conn}->blocking(1);
+      my $pw = AttrVal("global", "proxyAuth", "");                           
+      $pw = "Proxy-Authorization: Basic $pw\r\n" if($pw);                     
+      my $hdr = "CONNECT $host:$hash->{websocketport} HTTP/1.0\r\nUser-Agent: fhem\r\n$pw\r\n";                               
+      syswrite $h->{conn}, $hdr;
+      my $buf;
+      my $len = sysread($h->{conn},$buf,65536);
+      if(!defined($len) || $len <= 0 || $buf !~ m/HTTP.*200/) {
+        HttpUtils_Close($h);
+        Log3 $name, 2, "$name: failed to open websocket via proxy";
+        return;
+      }
+
+      $hash->{CD} = $h->{conn};
+      $hash->{PORT} = $hash->{websocketport};
+      my $ret = "GET ws://$host:$hash->{websocketport} HTTP/1.1\r\n";
+      $ret .= HUEBridge_hash2header( {                  'Host' => "$host:$hash->{websocketport}",
+                                                     'Upgrade' => 'websocket',
+                                                  'Connection' => 'Upgrade',
+                                                      'Pragma' => 'no-cache',
+                                               'Cache-Control' => 'no-cache',
+                                           'Sec-WebSocket-Key' => 'RkhFTQ==',
+                                       'Sec-WebSocket-Version' => '13',
+                                     } );
+      $ret .= "\r\n";
+      syswrite($hash->{CD}, $ret );
+    };
+    HttpUtils_Connect($h);
+    return;
+  }
+
   if( my $socket = IO::Socket::INET->new(PeerAddr=>"$host:$hash->{websocketport}", Timeout=>2, Blocking=>1, ReuseAddr=>1) ) {
     $hash->{CD}    = $socket;
     $hash->{FD}    = $socket->fileno();