From a7e8cc75685c59b542626e69a32c574b81894b3a Mon Sep 17 00:00:00 2001 From: Deon George Date: Thu, 12 Oct 2023 21:29:02 +1100 Subject: [PATCH] Implement HAPROXY proto support --- app/Classes/Sock/SocketClient.php | 93 +++++++++++++++++++++++++++++++ app/Classes/Sock/SocketServer.php | 3 +- config/fido.php | 3 + 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/app/Classes/Sock/SocketClient.php b/app/Classes/Sock/SocketClient.php index 8a8626d..a8a7aae 100644 --- a/app/Classes/Sock/SocketClient.php +++ b/app/Classes/Sock/SocketClient.php @@ -52,6 +52,99 @@ final class SocketClient { if ($this->type === SOCK_STREAM) { socket_getsockname($connection,$this->address_local,$this->port_local); socket_getpeername($connection,$this->address_remote,$this->port_remote); + + // If HAPROXY is used, work get the clients address + if (config('fido.haproxy')) { + Log::debug(sprintf('%s:+ HAPROXY connection host [%s] on port [%d] (%s)',self::LOGKEY,$this->address_remote,$this->port_remote,$this->type)); + + if ($this->read(5,12) !== "\x0d\x0a\x0d\x0a\x00\x0d\x0aQUIT\x0a") { + Log::error(sprintf('%s:! Failed to initialise HAPROXY connection',self::LOGKEY)); + throw new SocketException(SocketException::CANT_CONNECT,'Failed to initialise HAPROXY connection'); + } + + // Version/Command + $vc = $this->read_ch(5); + + if (($x=($vc>>4)&0x7) !== 2) { + Log::error(sprintf('%s:! HAPROXY version [%d] is not handled',self::LOGKEY,$x)); + + throw new SocketException(SocketException::CANT_CONNECT,'Unknown HAPROXY version'); + } + + switch ($x=($vc&0x7)) { + // HAPROXY internal + case 0: + Log::debug(sprintf('%s:! HAPROXY internal health-check',self::LOGKEY)); + throw new SocketException(SocketException::CANT_CONNECT,'Healthcheck'); + + // PROXY connection + case 1: + break; + + default: + Log::error(sprintf('%s:! HAPROXY command [%d] is not handled',self::LOGKEY,$x)); + + throw new SocketException(SocketException::CANT_CONNECT,'Unknown HAPROXY command'); + } + + // Protocol/Address Family + $pa = $this->read_ch(5); + $p = NULL; + + switch ($x=($pa>>4)&0x7) { + case 1: // AF_INET + $p = 4; + break; + + case 2: // AF_INET6 + $p = 6; + break; + + default: + Log::error(sprintf('%s:! HAPROXY protocol [%d] is not handled',self::LOGKEY,$x)); + throw new SocketException(SocketException::CANT_CONNECT,'Unknown HAPROXY protocol'); + } + + switch ($x=($pa&0x7)) { + case 1: // STREAM + break; + + default: + Log::error(sprintf('%s:! HAPROXY address family [%d] is not handled',self::LOGKEY,$x)); + throw new SocketException(SocketException::CANT_CONNECT,'Unknown HAPROXY address family'); + } + + $len = Arr::get(unpack('n',$this->read(5,2)),1); + + // IPv4 + if (($p === 4) && ($len === 12)) { + $src = inet_ntop($this->read(5,4)); + $dst = inet_ntop($this->read(5,4)); + + } elseif (($p === 6) && ($len === 36)) { + $src = inet_ntop($this->read(5,16)); + $dst = inet_ntop($this->read(5,16)); + + } else { + Log::error(sprintf('%s:! HAPROXY address len [%d:%d] is not handled',self::LOGKEY,$p,$len)); + throw new SocketException(SocketException::CANT_CONNECT,'Unknown HAPROXY address length'); + } + + $src_port = unpack('n',$this->read(5,2)); + $dst_port = unpack('n',$this->read(5,2)); + + $this->address_remote = $src; + $this->port_remote = Arr::get($src_port,1); + + Log::info(sprintf('%s:! HAPROXY src [%s:%d] dst [%s:%d]', + self::LOGKEY, + $this->address_remote, + $this->port_remote, + $dst, + Arr::get($dst_port,1), + )); + } + Log::info(sprintf('%s:+ Connection host [%s] on port [%d] (%s)',self::LOGKEY,$this->address_remote,$this->port_remote,$this->type)); } } diff --git a/app/Classes/Sock/SocketServer.php b/app/Classes/Sock/SocketServer.php index 3715a10..7529f16 100644 --- a/app/Classes/Sock/SocketServer.php +++ b/app/Classes/Sock/SocketServer.php @@ -128,8 +128,9 @@ final class SocketServer { try { $r = new SocketClient($accept); - } catch (\ErrorException $e) { + } catch (\Exception $e) { Log::error(sprintf('%s:! Creating Socket client failed? [%s]',self::LOGKEY,$e->getMessage())); + socket_close($accept); continue; } diff --git a/config/fido.php b/config/fido.php index b8138a4..7e169b8 100644 --- a/config/fido.php +++ b/config/fido.php @@ -13,6 +13,9 @@ return [ // Our Storage::disk() for files storage 'file_disk' => env('FIDO_DIR_FILES', 's3'), + // Do our BINKP/EMSI connections come via haproxy and haproxy protocol + 'haproxy' => env('FIDO_HAPROXY', FALSE), + // Our Storage::disk() for locally stored data 'local_disk' => env('FIDO_LOCAL_DIR','local'),