FHEM - Hausautomations-Systeme > Zigbee

[patch] [HUEBridge] proxy support for websockets

(1/1)

ruff:
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.


--- Code: ---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();

--- Ende Code ---

wiki only mentions this channel for patch submission so here we are.

ruff:
Sorry just realized it wasn't the latest version of the patch, here's the latest (and tested) one:

--- Code: ---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();

--- Ende Code ---

Navigation

[0] Themen-Index

Zur normalen Ansicht wechseln