From 60214d3fbc561fd4937a42c6e7e7f3a9319e03bc Mon Sep 17 00:00:00 2001 From: Deon George Date: Sat, 26 Oct 2024 12:15:53 +1100 Subject: [PATCH] Update HAPROXY process to understand v1 --- .env.example | 1 + app/Classes/Sock/SocketClient.php | 169 +++++++++++++++++++----------- 2 files changed, 111 insertions(+), 59 deletions(-) diff --git a/.env.example b/.env.example index b4af561..d947380 100644 --- a/.env.example +++ b/.env.example @@ -49,6 +49,7 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" FIDO_DIR=fido FIDO_PACKET_KEEP= FIDO_STRICT=false +FIDO_HAPROXY=false FILESYSTEM_DISK=s3 AWS_ACCESS_KEY_ID= diff --git a/app/Classes/Sock/SocketClient.php b/app/Classes/Sock/SocketClient.php index 1b2aa50..b2b38b6 100644 --- a/app/Classes/Sock/SocketClient.php +++ b/app/Classes/Sock/SocketClient.php @@ -59,80 +59,131 @@ final class SocketClient { if ((! $originate) && 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") + if (($x=$this->read(5,6)) === 'PROXY ') + $vers = 1; + + elseif (($x === "\x0d\x0a\x0d\x0a\x00\x0d") && ($this->read('5,6') === "\x0aQUIT\x0a")) + $vers = 2; + + else throw new HAproxyException('Failed to initialise HAPROXY connection'); - // Version/Command - $vc = $this->read_ch(5); - - if (($x=($vc>>4)&0x7) !== 2) - throw new HAproxyException(sprintf('Unknown HAPROXY version [%d]',$x)); - - switch ($x=($vc&0x7)) { - // HAPROXY internal - case 0: - throw new HAproxyException('HAPROXY internal health-check'); - - // PROXY connection + switch ($vers) { case 1: + // Protocol/Address Family + switch ($x=$this->read(5,5)) { + case 'TCP4 ': + $p = 4; + break; + case 'TCP6 ': + $p = 6; + break; + + default: + throw new HAproxyException(sprintf('HAPROXY protocol [%d] is not handled',$x)); + } + + $read = $this->read(5,104-11); + + // IPv4 + if (($p === 4) || ($p === 6)) { + $parse = collect(sscanf($read,'%s %s %s %s')); + + $src = Arr::get($parse,0); + $dst = Arr::get($parse,1); + $src_port = (int)Arr::get($parse,2); + $dst_port = (int)Arr::get($parse,3); + $len = $parse->map(fn($item)=>strlen($item))->sum()+3; + + // The last 2 chars should be "\r\n" + if (($x=substr($read,$len)) !== "\r\n") + throw new HAproxyException(sprintf('HAPROXY parsing failed for version [%d] [%s] (%s)',$p,$read,hex_dump($x))); + + } else { + throw new HAproxyException(sprintf('HAPROXY version [%d] is not handled [%s]',$p,$read)); + } + + $this->port_remote = $src_port; + + break; + + case 2: + // Version/Command + $vc = $this->read_ch(5); + + if (($x=($vc>>4)&0x7) !== 2) + throw new HAproxyException(sprintf('Unknown HAPROXY version [%d]',$x)); + + switch ($x=($vc&0x7)) { + // HAPROXY internal + case 0: + throw new HAproxyException('HAPROXY internal health-check'); + + // PROXY connection + case 1: + break; + + default: + throw new HAproxyException(sprintf('HAPROXY command [%d] is not handled',$x)); + } + + // Protocol/Address Family + $pa = $this->read_ch(5); + + switch ($x=($pa>>4)&0x7) { + case 1: // AF_INET + $p = 4; + break; + + case 2: // AF_INET6 + $p = 6; + break; + + + } + + switch ($x=($pa&0x7)) { + case 1: // STREAM + break; + + default: + throw new HAproxyException(sprintf('HAPROXY address family [%d] is not handled',$x)); + } + + $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 { + throw new HAproxyException(sprintf('HAPROXY address len [%d:%d] is not handled',$p,$len)); + } + + $src_port = unpack('n',$this->read(5,2)); + $dst_port = Arr::get(unpack('n',$this->read(5,2)),1); + + $this->port_remote = Arr::get($src_port,1); + break; default: - throw new HAproxyException(sprintf('HAPROXY command [%d] is not handled',$x)); + throw new HAproxyException('Failed to initialise HAPROXY connection'); } - // 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: - throw new HAproxyException(sprintf('HAPROXY protocol [%d] is not handled',$x)); - } - - switch ($x=($pa&0x7)) { - case 1: // STREAM - break; - - default: - throw new HAproxyException(sprintf('HAPROXY address family [%d] is not handled',$x)); - } - - $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 { - throw new HAproxyException(sprintf('HAPROXY address len [%d:%d] is not handled',$p,$len)); - } - - $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::debug(sprintf('%s:- HAPROXY src [%s:%d] dst [%s:%d]', self::LOGKEY, $this->address_remote, $this->port_remote, $dst, - Arr::get($dst_port,1), + $dst_port, )); }