Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/roundcube/roundcubemail.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Mollekopf <mollekopf@apheleia-it.ch>2022-07-14 16:04:16 +0300
committerChristian Mollekopf <mollekopf@apheleia-it.ch>2022-07-22 11:32:50 +0300
commit76154d27f2a3bf47480ade51ff1bba43403871cc (patch)
tree1b45de0effac3ce3503d4277b804e0243f71e069
parent38bf246b0d1e35078558f4267791d1cd22f782f0 (diff)
Introduce optional support to inject PROXY protocol headers after
opening IMAP TCP streams. Version 1 (text based) and version 2 (binary) protocol header types are supported. Supports both IPv4 and IPv6 style headers. http://www.haproxy.org/download/1.6/doc/proxy-protocol.txt
-rw-r--r--config/defaults.inc.php10
-rw-r--r--program/lib/Roundcube/rcube_imap_generic.php8
-rw-r--r--program/lib/Roundcube/rcube_utils.php79
3 files changed, 97 insertions, 0 deletions
diff --git a/config/defaults.inc.php b/config/defaults.inc.php
index 904524896..0feaa2ae4 100644
--- a/config/defaults.inc.php
+++ b/config/defaults.inc.php
@@ -155,12 +155,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'] = [
// 'ssl' => [
// 'verify_peer' => true,
// 'verify_depth' => 3,
// 'cafile' => '/etc/openssl/certs/ca.crt',
// ],
+// 'proxy_protocol' => 1 | 2 | [ // 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 59119547e..ca909d8be 100644
--- a/program/lib/Roundcube/rcube_imap_generic.php
+++ b/program/lib/Roundcube/rcube_imap_generic.php
@@ -1070,6 +1070,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 04b17f22e..50e090918 100644
--- a/program/lib/Roundcube/rcube_utils.php
+++ b/program/lib/Roundcube/rcube_utils.php
@@ -1672,4 +1672,83 @@ class rcube_utils
return trim($subject);
}
+
+ /**
+ * 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_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 "";
+ }
}