From https://github.com/Castaglia/proftpd-mod_proxy/pull/232

commit f5763c50ae36ce1e96ae107750a0305e0a6b4ec6  Add ProxyForwardMethod user@sni-host.
commit ed874f585585efe587d047444102fa1ae9cd5da9  Fix user parsing.

Index: proftpd-mod-proxy-0.9.1/include/proxy/forward.h
===================================================================
--- proftpd-mod-proxy-0.9.1.orig/include/proxy/forward.h
+++ proftpd-mod-proxy-0.9.1/include/proxy/forward.h
@@ -48,6 +48,7 @@ int proxy_forward_handle_pass(cmd_rec *c
 #define PROXY_FORWARD_METHOD_USER_WITH_PROXY_AUTH		1
 #define PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH			2
 #define PROXY_FORWARD_METHOD_PROXY_USER_WITH_PROXY_AUTH		3
+#define PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH_SNI		4
 
 /* Return the method ID for the given string, or -1 if the given method
  * is not recognized/supported.
Index: proftpd-mod-proxy-0.9.1/lib/proxy/forward.c
===================================================================
--- proftpd-mod-proxy-0.9.1.orig/lib/proxy/forward.c
+++ proftpd-mod-proxy-0.9.1/lib/proxy/forward.c
@@ -38,11 +38,13 @@ static int forward_retry_count = PROXY_D
 /* handle_user_passthru flags */
 #define PROXY_FORWARD_USER_PASSTHRU_FL_PARSE_DSTADDR	0x001
 #define PROXY_FORWARD_USER_PASSTHRU_FL_CONNECT_DSTADDR	0x002
+#define PROXY_FORWARD_USER_PASSTHRU_FL_SNI_DSTADDR	0x004
 
 static const char *trace_channel = "proxy.forward";
 
 int proxy_forward_use_proxy_auth(void) {
-  if (proxy_method == PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH) {
+  if (proxy_method == PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH ||
+    proxy_method == PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH_SNI) {
     return FALSE;
   }
 
@@ -131,6 +133,7 @@ int proxy_forward_have_authenticated(cmd
 
   switch (proxy_method) {
     case PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH:
+    case PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH_SNI:
       authd = TRUE;
       break;
 
@@ -484,6 +487,46 @@ static int forward_cmd_parse_dst(pool *p
   return 0;
 }
 
+static int forward_cmd_sni_dst(pool *p, const struct proxy_conn **pconn) {
+
+  const char *default_port = NULL;
+  char * host = NULL, *hostport = NULL, *uri = NULL;
+
+  host = pr_env_get(p, "TLS_SERVER_NAME");
+  if (host == NULL) {
+      (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION,
+        "Server Name Information not provided from mod_tls");
+    return -1;
+  }
+
+  default_port = "21";
+
+  hostport = pstrcat(p, host, ":", default_port, NULL);
+  if (forward_dst_filter(p, hostport) < 0) {
+    return -1;
+  }
+
+  uri = pstrcat(p, "ftp://", hostport, NULL);
+
+  /* Note: We deliberately use proxy_pool, rather than the given pool, here
+   * so that the created structure (especially the pr_netaddr_t) are
+   * longer-lived.
+   */
+  *pconn = proxy_conn_create(proxy_pool, uri, 0);
+  if (*pconn == NULL) {
+    int xerrno = errno;
+
+    pr_trace_msg(trace_channel, 1,
+      "error handling URI '%.100s': %s", uri, strerror(xerrno));
+
+    errno = xerrno;
+    return -1;
+  }
+
+  return 0;
+
+}
+
 static int forward_handle_user_passthru(cmd_rec *cmd,
     struct proxy_session *proxy_sess, int *successful, int flags) {
   int res, xerrno;
@@ -492,15 +535,30 @@ static int forward_handle_user_passthru(
   pr_response_t *resp = NULL;
   unsigned int resp_nlines = 0;
 
-  if (flags & PROXY_FORWARD_USER_PASSTHRU_FL_PARSE_DSTADDR) {
+  if ((flags & PROXY_FORWARD_USER_PASSTHRU_FL_PARSE_DSTADDR) ||
+    (flags & PROXY_FORWARD_USER_PASSTHRU_FL_SNI_DSTADDR)) {
     const struct proxy_conn *pconn = NULL;
     const pr_netaddr_t *remote_addr = NULL;
     array_header *other_addrs = NULL;
 
-    res = forward_cmd_parse_dst(cmd->tmp_pool, cmd->arg, &user, &pconn);
-    if (res < 0) {
-      errno = EINVAL;
-      return -1;
+
+    if (flags & PROXY_FORWARD_USER_PASSTHRU_FL_PARSE_DSTADDR) {
+
+      res = forward_cmd_parse_dst(cmd->tmp_pool, cmd->arg, &user, &pconn);
+      if (res < 0) {
+        errno = EINVAL;
+        return -1;
+      }
+      /* Change the command so that it no longer includes the proxy info. */
+      user_cmd = pr_cmd_alloc(cmd->pool, 2, C_USER, user);
+      user_cmd->arg = user;
+    } else {
+      res = forward_cmd_sni_dst(cmd->tmp_pool, &pconn);
+      if (res < 0) {
+        errno = EINVAL;
+	return -1;
+      }
+      user_cmd = cmd;
     }
 
     remote_addr = proxy_conn_get_addr(pconn, &other_addrs);
@@ -525,9 +583,6 @@ static int forward_handle_user_passthru(
     proxy_sess->other_addrs = other_addrs;
     proxy_sess->dst_pconn = pconn;
 
-    /* Change the command so that it no longer includes the proxy info. */
-    user_cmd = pr_cmd_alloc(cmd->pool, 2, C_USER, user);
-    user_cmd->arg = user;
 
   } else {
     user_cmd = cmd;
@@ -710,6 +765,12 @@ int proxy_forward_handle_user(cmd_rec *c
         successful, block_responses);
       break;
 
+    case PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH_SNI: {
+      int flags = PROXY_FORWARD_USER_PASSTHRU_FL_SNI_DSTADDR|PROXY_FORWARD_USER_PASSTHRU_FL_CONNECT_DSTADDR;
+      res = forward_handle_user_passthru(cmd, proxy_sess, successful, flags);
+      break;
+    }
+
     default:
       errno = ENOSYS;
       res = -1;
@@ -825,6 +886,7 @@ int proxy_forward_handle_pass(cmd_rec *c
   /* Look at our proxy method to see what we should do here. */
   switch (proxy_method) {
     case PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH:
+    case PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH_SNI:
       res = forward_handle_pass_passthru(cmd, proxy_sess, successful);
       xerrno = errno;
       if (res == 1) {
@@ -873,6 +935,9 @@ int proxy_forward_get_method(const char
 
   } else if (strcasecmp(method, "proxyuser@host,user") == 0) {
     return PROXY_FORWARD_METHOD_PROXY_USER_WITH_PROXY_AUTH;
+
+  } else if (strcasecmp(method, "user@sni-host") == 0) {
+    return PROXY_FORWARD_METHOD_USER_NO_PROXY_AUTH_SNI;
   }
 
   errno = ENOENT;
