Compare commits

..

3 Commits

Author SHA1 Message Date
bee7e5d64a Set default example mail server to smtp
All checks were successful
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 1m22s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 1m53s
Create Docker Image / Final Docker Image Manifest (push) Successful in 9s
2024-10-26 12:19:45 +11:00
60214d3fbc Update HAPROXY process to understand v1 2024-10-26 12:19:45 +11:00
9aecd61a2f Add configuration items to determine DNS records returned and sort order 2024-10-26 12:19:45 +11:00
3 changed files with 137 additions and 64 deletions

View File

@ -31,7 +31,7 @@ REDIS_PASSWORD=
REDIS_PORT=6379 REDIS_PORT=6379
MAIL_DRIVER=smtp MAIL_DRIVER=smtp
MAIL_HOST=mail.dege.lan MAIL_HOST=smtp
MAIL_PORT=25 MAIL_PORT=25
MAIL_USERNAME= MAIL_USERNAME=
MAIL_PASSWORD= MAIL_PASSWORD=
@ -49,6 +49,7 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
FIDO_DIR=fido FIDO_DIR=fido
FIDO_PACKET_KEEP= FIDO_PACKET_KEEP=
FIDO_STRICT=false FIDO_STRICT=false
FIDO_HAPROXY=false
FILESYSTEM_DISK=s3 FILESYSTEM_DISK=s3
AWS_ACCESS_KEY_ID= AWS_ACCESS_KEY_ID=
@ -61,3 +62,9 @@ AWS_USE_PATH_STYLE_ENDPOINT=true
MATRIX_SERVER= MATRIX_SERVER=
MATRIX_AS_TOKEN= MATRIX_AS_TOKEN=
MATRIX_HS_TOKEN= MATRIX_HS_TOKEN=
FIDO_DNS_NS=
FIDO_IP_AAAA=
FIDO_AAAA_ORDER=
FIDO_IP_A=
FIDO_A_ORDER=

View File

@ -59,80 +59,131 @@ final class SocketClient {
if ((! $originate) && config('fido.haproxy')) { 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)); 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'); throw new HAproxyException('Failed to initialise HAPROXY connection');
// Version/Command switch ($vers) {
$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: 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; break;
default: 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->address_remote = $src;
$this->port_remote = Arr::get($src_port,1);
Log::debug(sprintf('%s:- HAPROXY src [%s:%d] dst [%s:%d]', Log::debug(sprintf('%s:- HAPROXY src [%s:%d] dst [%s:%d]',
self::LOGKEY, self::LOGKEY,
$this->address_remote, $this->address_remote,
$this->port_remote, $this->port_remote,
$dst, $dst,
Arr::get($dst_port,1), $dst_port,
)); ));
} }
@ -190,7 +241,8 @@ final class SocketClient {
{ {
Log::info(sprintf('%s:+ Creating connection to [%s:%d]',self::LOGKEY,$address,$port)); Log::info(sprintf('%s:+ Creating connection to [%s:%d]',self::LOGKEY,$address,$port));
$sort = collect(['AAAA','A']); $type = collect(config('fido.ip'))
->filter(fn($item)=>$item['enabled']);
if (filter_var($address,FILTER_VALIDATE_IP)) if (filter_var($address,FILTER_VALIDATE_IP))
$resolved = collect([[ $resolved = collect([[
@ -199,9 +251,9 @@ final class SocketClient {
]]); ]]);
else else
// We only look at AAAA/A records // We only look at AAAA/A records
$resolved = collect(dns_get_record($address,DNS_AAAA|DNS_A)) $resolved = collect(dns_get_record($address,$type->map(fn($item)=>$item['type'])->sum()))
->filter(function($item) use ($sort) { return $sort->search(Arr::get($item,'type')) !== FALSE; }) ->filter(fn($item)=>$type->has(Arr::get($item,'type')))
->sort(function($item) use ($sort) { return $sort->search(Arr::get($item,'type')); }); ->sort(fn($a,$b)=>$type->get(Arr::get($a,'type'))['order'] < $type->get(Arr::get($b,'type'))['order']);
if (! $resolved->count()) if (! $resolved->count())
throw new SocketException(SocketException::CANT_CONNECT,sprintf('%s doesnt resolved to an IPv4/IPv6 address',$address)); throw new SocketException(SocketException::CANT_CONNECT,sprintf('%s doesnt resolved to an IPv4/IPv6 address',$address));

View File

@ -43,4 +43,18 @@ return [
'down' => 35, 'down' => 35,
'delist' => 45, 'delist' => 45,
], ],
// IP Address Resolution preferences
'ip' => [
'AAAA' => [
'enabled' => env('FIDO_IP_AAAA',false),
'order' => env('FIDO_AAAA_ORDER',2),
'type' => DNS_AAAA,
],
'A' => [
'enabled' => env('FIDO_IP_A',TRUE),
'order' => env('FIDO_A_ORDER',1),
'type' => DNS_A,
],
],
]; ];