diff --git a/docker/kolab/utils/patches/0003-PROXY-protocol-support.patch b/docker/kolab/utils/patches/0003-PROXY-protocol-support.patch index 3f5e96a9..913aba37 100644 --- a/docker/kolab/utils/patches/0003-PROXY-protocol-support.patch +++ b/docker/kolab/utils/patches/0003-PROXY-protocol-support.patch @@ -1,148 +1,148 @@ From f044424f99b8e33dbed1a00127bfcc5ad121d610 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 14 Jul 2022 15:04:16 +0200 Subject: [PATCH 3/3] PROXY protocol support --- config/defaults.inc.php | 10 +++ program/lib/Roundcube/rcube_imap_generic.php | 8 ++ program/lib/Roundcube/rcube_utils.php | 79 ++++++++++++++++++++ 3 files changed, 97 insertions(+) diff --git a/config/defaults.inc.php b/config/defaults.inc.php index 20c1c6fd3..f705a47e8 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -157,12 +157,22 @@ $config['imap_auth_type'] = null; // IMAP socket context options // See http://php.net/manual/en/context.ssl.php // The example below enables server certificate validation +// +// proxy_protocol is used to inject HAproxy style headers in the TCP stream +// See http://www.haproxy.org/download/1.6/doc/proxy-protocol.txt //$config['imap_conn_options'] = array( // 'ssl' => array( // 'verify_peer' => true, // 'verify_depth' => 3, // 'cafile' => '/etc/openssl/certs/ca.crt', // ), +// 'proxy_protocol' => 1 | 2 | array ( // required (either version number (1|2) or array with 'version' key) +// 'version' => 1 | 2, // required, if array +// 'remote_addr' => $_SERVER['REMOTE_ADDR'], +// 'remote_port' => $_SERVER['REMOTE_PORT'], +// 'local_addr' => $_SERVER['SERVER_ADDR'], +// 'local_port' => $_SERVER['SERVER_PORT'], +// ), // ); // Note: These can be also specified as an array of options indexed by hostname $config['imap_conn_options'] = null; diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 9a398cdca..270be1201 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -1035,6 +1035,14 @@ class rcube_imap_generic return false; } + // insert proxy protocol header, if enabled + if (!empty($this->prefs['socket_options'])) { + $proxy_protocol_header = rcube_utils::proxy_protocol_header($this->prefs['socket_options'], $this->fp); + if (strlen($proxy_protocol_header) > 0) { + fwrite($this->fp, $proxy_protocol_header); + } + } + if ($this->prefs['timeout'] > 0) { stream_set_timeout($this->fp, $this->prefs['timeout']); } diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php index d4273526b..3ad6422cb 100644 --- a/program/lib/Roundcube/rcube_utils.php +++ b/program/lib/Roundcube/rcube_utils.php @@ -1458,4 +1458,83 @@ class rcube_utils return $temp_path; } + + /** + * When proxy_protocol is configured for a connection type, + * generate the HAproxy style PROXY protocol header for injection + * into the TCP stream. + * http://www.haproxy.org/download/1.6/doc/proxy-protocol.txt + * + * PROXY protocol headers must be sent before any other data is sent on the TCP socket. + * + * @param array $conn_options preferences array which may contain proxy_protocol (generally {driver}_conn_options) + * + * @return string proxy protocol header data, if enabled, otherwise empty string + */ + public static function proxy_protocol_header($conn_options = null) + { + if ($conn_options === null) + { + return ""; + } + // verify that proxy_protocol option is present + if (is_array($conn_options) && array_key_exists('proxy_protocol', $conn_options)) { + if (is_array($conn_options['proxy_protocol'])) { + $proxy_protocol_version = $conn_options['proxy_protocol']['version']; + $proxy_protocol_options = $conn_options['proxy_protocol']; + } + else { + $proxy_protocol_version = $conn_options['proxy_protocol']; + $proxy_protocol_options = null; + } + -+ $proxy_protocol_remote_addr = (array_key_exists('remote_addr', $proxy_protocol_options) ? $proxy_protocol_options['remote_addr'] : $_SERVER['REMOTE_ADDR'] ); ++ $proxy_protocol_remote_addr = (array_key_exists('remote_addr', $proxy_protocol_options) ? $proxy_protocol_options['remote_addr'] : self::remote_addr() ); + $proxy_protocol_remote_port = (array_key_exists('remote_port', $proxy_protocol_options) ? $proxy_protocol_options['remote_port'] : $_SERVER['REMOTE_PORT'] ); + $proxy_protocol_local_addr = (array_key_exists('local_addr' ,$proxy_protocol_options) ? $proxy_protocol_options['local_addr'] : $_SERVER['SERVER_ADDR'] ); + $proxy_protocol_local_port = (array_key_exists('local_port', $proxy_protocol_options) ? $proxy_protocol_options['local_port'] : $_SERVER['SERVER_PORT'] ); + $proxy_protocol_ip_version = (strpos($proxy_protocol_remote_addr, ":") === false ? 4 : 6); + + if ($proxy_protocol_version === 1) { + // text based PROXY protocol + + // PROXY protocol does not support dual IPv6+IPv4 type addresses, e.g. ::127.0.0.1 + if ($proxy_protocol_ip_version === 6 && strpos($proxy_protocol_remote_addr, ".") !== false) { + $proxy_protocol_remote_addr = inet_ntop(inet_pton($proxy_protocol_remote_addr)); + } + if ($proxy_protocol_ip_version === 6 && strpos($proxy_protocol_local_addr, ".") !== false) { + $proxy_protocol_local_addr = inet_ntop(inet_pton($proxy_protocol_local_addr)); + } + + $proxy_protocol_text = "PROXY " . // protocol header + ($proxy_protocol_ip_version === 6 ? "TCP6 " : "TCP4 ") . // IP version type + $proxy_protocol_remote_addr . + " " . + $proxy_protocol_local_addr . + " " . + $proxy_protocol_remote_port . + " " . + $proxy_protocol_local_port . + "\r\n"; + return $proxy_protocol_text; + } + else if ($proxy_protocol_version === 2) { + // binary PROXY protocol + $proxy_protocol_bin = pack("H*", "0D0A0D0A000D0A515549540A" . // protocol header + "21" . // protocol version and command + ($proxy_protocol_ip_version === 6 ? "2" : "1") . // IP version type + "1"); // TCP + $proxy_protocol_addr = inet_pton($proxy_protocol_remote_addr) . + inet_pton($proxy_protocol_local_addr) . + pack("n", $proxy_protocol_remote_port) . + pack("n", $proxy_protocol_local_port); + $proxy_protocol_bin .= pack("n", strlen($proxy_protocol_addr)) . $proxy_protocol_addr; + return $proxy_protocol_bin; + } + else { + // unknown proxy protocol version + return ""; + } + } + return ""; + } } -- 2.35.3