/ Zope / Apsis / Pound Mailing List / Archive / 2004 / 2004-01 / Wishlist: Rewrite/Set of Host-Header per UrlGroup

[ << ] [ >> ]

[ out of files (sockets) problem / Dennis Allison ... ] [ alerting admin on failover / "Jason ... ]

Wishlist: Rewrite/Set of Host-Header per UrlGroup
Roland <pound(at)gmx.net>
2004-01-13 18:47:55 [ SNIP ]
Some domains/hosts/custmers on Apache name-based hosts want their
websites or part of to be reachable via one shared ssl-certificate
to implement ssl-protected forms.

Practical example: https://ssl.isp.dom/proxy/customer.dom/
passes the request via mod_proxy to http://www.customer.dom/ssl/

This works here since about three years with mod_ssl, mod_rewrite
and mod_proxy, dynamically redirecting based on parts of the path
while ipfw prevents the anonymized abuse of non-local domains.
But I'd rather implement this with Pound and already 'poundified'
some of the applications in use here...

With Pound the only solution are to setup a second VirtualHost on
a dedicated Port (127.0.0.1 works fine) for each customer.

The basic problem with Pound are the Host-Headers in the request,
something mod_ssl already does by default.
If Pound would allow to set a Host-Header per UrlGroup the issue
would be mostly solved.

Example:

Request received by Pound:

CONNECT ssl.isp.dom:443
GET /customer/
Host: ignore.me

UrlGroup "/customer/.*"
HostRewrite "customer.dom"
Backend ip.of.customer.dom,80,1
EndGroup

Request received by Apache:

CONNECT ip.of.customer.dom:80
GET /customer/
Host: customer.dom

This simple feature would basically allow for virtual ssl as long as
the first part of the path are unique, and the same path also exists
on the target VirtualHost, but thats ok for security.
This would be easy to implement, maybe as 'HeadSet Host "customer.dom"'
per UrlGroup.

Of course Pound could also turn the first part of the path (=hostname)
into a Host-Header, strip or rewrite this in the request string, and
even allow the backend to be set to the same value as the hostname,
but thats not really required and might be overkill.

Another nice feature could be a gzip-engine in the addition to the
ssl-engine, but mod_gzip already does this very well...

Roland


Re: Wishlist: Rewrite/Set of Host-Header per UrlGroup
Robert Segall <roseg(at)apsis.ch>
2004-01-14 13:14:56 [ SNIP ]
On Tue, 2004-01-13 at 18:47, Roland wrote:
> Some domains/hosts/custmers on Apache name-based hosts want their
> websites or part of to be reachable via one shared ssl-certificate
> to implement ssl-protected forms.
> 
> Practical example: https://ssl.isp.dom/proxy/customer.dom/
> passes the request via mod_proxy to http://www.customer.dom/ssl/
> 
> This works here since about three years with mod_ssl, mod_rewrite
> and mod_proxy, dynamically redirecting based on parts of the path
> while ipfw prevents the anonymized abuse of non-local domains.
> But I'd rather implement this with Pound and already 'poundified'
> some of the applications in use here...
> 
> With Pound the only solution are to setup a second VirtualHost on
> a dedicated Port (127.0.0.1 works fine) for each customer.
> 
> The basic problem with Pound are the Host-Headers in the request,
> something mod_ssl already does by default.
> If Pound would allow to set a Host-Header per UrlGroup the issue
> would be mostly solved.
> 
> Example:
> 
> Request received by Pound:
> 
> CONNECT ssl.isp.dom:443
> GET /customer/
> Host: ignore.me
> 
> UrlGroup "/customer/.*"
> HostRewrite "customer.dom"
> Backend ip.of.customer.dom,80,1
> EndGroup
> 
> Request received by Apache:
> 
> CONNECT ip.of.customer.dom:80
> GET /customer/
> Host: customer.dom
> 
> This simple feature would basically allow for virtual ssl as long as
> the first part of the path are unique, and the same path also exists
> on the target VirtualHost, but thats ok for security.
> This would be easy to implement, maybe as 'HeadSet Host "customer.dom"'
> per UrlGroup.
> 
> Of course Pound could also turn the first part of the path (=hostname)
> into a Host-Header, strip or rewrite this in the request string, and
> even allow the backend to be set to the same value as the hostname,
> but thats not really required and might be overkill.
> 
> Another nice feature could be a gzip-engine in the addition to the
> ssl-engine, but mod_gzip already does this very well...
> 
> Roland

I'll put this on the wish-list, but don't hold your breath: we would
very much like to keep Pound transparent (ideally neither the client nor
the back-end server should know that it is there at all). That means
gzip is probably out and request/header rewriting is some way off...
-- 
Robert Segall
Apsis GmbH
Postfach, Uetikon am See, CH-8707
Tel: +41-1-920 4904


Re: Wishlist: Rewrite/Set of Host-Header per UrlGroup
Roland <pound(at)gmx.net>
2004-01-15 09:52:53 [ SNIP ]
--On Mittwoch, 14. Januar 2004 13:14 +0100 Robert Segall <roseg(at)apsis.ch>
wrote:

> I'll put this on the wish-list, but don't hold your breath: we would
> very much like to keep Pound transparent (ideally neither the client nor
> the back-end server should know that it is there at all). That means
> gzip is probably out and request/header rewriting is some way off...

I know about gzip, it just would nicely fit into the functionality...

However, I was a bit under pressure, had to reimplement the 'Virtual SSL
Proxy' on a new server, did not want to use Apache again and here are the
first (currently live working...) version as a 'proof of concept'.

New keyword per UrlGroup:

	HostRewrite STATIC "example.com"

Will set the Host:-header to example.com for use with name-based VirtualHost.

Now the Apache-backend does not only not know its there, Apache also knows
where to route the ssl-proxied request ;)

All new code is embedded within #ifdef, no existing code changed else and
it will be easy to keep the patch out of the distribution.

I also planned to implement some kind of dynamic rewriting, but failed with
the regex-stuff and wont have time for the next couple of weeks.

Roland


--- ./Pound-current.orig/pound.h	2003-12-12 10:17:31.000000000 +0100
+++ ./Pound-current/pound.h	2004-01-15 09:26:31.000000000 +0100
(at)(at) -292,6 +292,9 (at)(at)
 #define N_RSA_KEYS  11
 #define T_RSA_KEYS  300
 
+/* PATCH: enable 'HostRewrite STATIC "example.com:80"' per UrlGroup */
+#define HOST_REWRITE	1
+
 /* Backend definition */
 typedef struct {
     struct sockaddr_in  addr;       /* address */
(at)(at) -315,6 +318,10 (at)(at)
 
 typedef enum    { SessNONE, SessIP, SessURL, SessCOOKIE, SessBASIC }
SESS_TYPE;
 
+#ifdef HOST_REWRITE
+typedef enum	{ HostNONE, HostSTATIC } HOST_TYPE;
+#endif	/* HOST_REWRITE */
+
 /* URL group definition */
 typedef struct _group {
     regex_t         url_pat;            /* pattern to match the URL against
*/
(at)(at) -327,6 +334,11 (at)(at)
     SESS_TYPE       sess_type;          /* session type: IP, URL or COOKIE */
     regex_t         sess_pat;           /* pattern to match the session id */
     int             sess_to;            /* session timeout */
+#ifdef HOST_REWRITE
+    HOST_TYPE	host_type;
+    // regex_t	host_pat;
+    char	*host_string;
+# endif	/* HOST_REWRITE */
     pthread_mutex_t mut;                /* group mutex */
     SESS            *sessions;          /* session tree root */
 }   GROUP;
--- ./Pound-current.orig/config.c	2003-12-12 10:17:31.000000000 +0100
+++ ./Pound-current/config.c	2004-01-15 09:26:31.000000000 +0100
(at)(at) -186,8 +186,11 (at)(at)
     char                lin[MAXBUF], pat[MAXBUF];
     regex_t             Empty, Comment, ListenHTTP, ListenHTTPS,
HTTPSHeaders, MaxRequest, HeadRemove,
                         SSL_CAlist, SSLEngine, SessionIP, SessionURL,
SessionCOOKIE, SessionBASIC, NO11SSL,
+#ifdef HOST_REWRITE
+			HostRewrite,
+#endif	/* HOST_REWRITE */
                         User, Group, RootJail, ExtendedHTTP, WebDAV,
LogLevel, Alive, Server,
-                        Client, UrlGroup, HeadRequire, HeadDeny, BackEnd,
BackEndHA, EndGroup,
+                        Client, UrlGroup, HeadRequire, HeadDeny ,BackEnd,
BackEndHA, EndGroup,
                         Err500, Err501, Err503, CheckURL, CS_SEGMENT,
CS_PARM, CS_QID, CS_QVAL, CS_FRAG;
     regex_t             *req, *deny;
     regmatch_t          matches[5];
(at)(at) -213,6 +216,10 (at)(at)
         REG_ICASE | REG_NEWLINE | REG_EXTENDED)
     || regcomp(&SessionBASIC, "^[ \t]*Session[ \t]+Basic[
\t]+([0-9-][0-9]*)[ \t]*$",
         REG_ICASE | REG_NEWLINE | REG_EXTENDED)
+#ifdef HOST_REWRITE
+    || regcomp(&HostRewrite, "^[ \t]*HostRewrite[ \t]+STATIC[
\t]+\"([-a-z0-9.:]+)\"[ \t]*$",
+	REG_ICASE | REG_NEWLINE | REG_EXTENDED)
+#endif	/* HOST_REWRITE */
     || regcomp(&User, "^[ \t]*User[ \t]+([^ \t]+)[ \t]*$", REG_ICASE |
REG_NEWLINE | REG_EXTENDED)
     || regcomp(&Group, "^[ \t]*Group[ \t]+([^ \t]+)[ \t]*$", REG_ICASE |
REG_NEWLINE | REG_EXTENDED)
     || regcomp(&RootJail, "^[ \t]*RootJail[ \t]+([^ \t]+)[ \t]*$", REG_ICASE
| REG_NEWLINE | REG_EXTENDED)
(at)(at) -271,6 +278,7 (at)(at)
             tot_req++;
         else if(!regexec(&HeadDeny, lin, 4, matches, 0))
             tot_deny++;
+	
     }
     rewind(fconf);
 
(at)(at) -483,8 +491,8 (at)(at)
                 exit(1);
             }
             lin[matches[1].rm_eo] = '\0';
-            if(regcomp(&groups[tot_groups]->url_pat, lin + matches[1].rm_so,
REG_ICASE | REG_EXTENDED | REG_NOSUB)) {
-                logmsg(LOG_ERR, "UrlGroup bad pattern \"%s\" - aborted", lin
+ matches[1].rm_so);
+	    if(regcomp(&groups[tot_groups]->url_pat, lin + matches[1].rm_so,
REG_ICASE | REG_EXTENDED | REG_NOSUB)) {
+		logmsg(LOG_ERR, "UrlGroup bad pattern \"%s\" - aborted", lin +
matches[1].rm_so);
                 exit(1);
             }
             pthread_mutex_init(&groups[tot_groups]->mut, NULL);
(at)(at) -492,6 +500,10 (at)(at)
             groups[tot_groups]->tot_pri = 0;
             groups[tot_groups]->sess_type = SessNONE;
             groups[tot_groups]->sess_to = 300;
+#ifdef HOST_REWRITE
+	    groups[tot_groups]->host_type = HostNONE;
+	    groups[tot_groups]->host_string = NULL;	// safety
+#endif	/* HOST_REWRITE */
             tot_req = tot_deny = j = 0;
         } else if(in_group && !regexec(&BackEnd, lin, 4, matches, 0)) {
             memset(&addr, 0, sizeof(addr));
(at)(at) -582,6 +594,32 (at)(at)
             }
             if((groups[tot_groups]->sess_to = atoi(lin + matches[2].rm_so))
<= 0)
                 logmsg(LOG_ERR, "no sticky session for Session Cookie -
aborted");
+
+#ifdef HOST_REWRITE
+
+	}
+	else if(in_group && !regexec(&HostRewrite, lin, 4, matches, 0))
+	{
+	    if(groups[tot_groups]->host_type != HostNONE)
+	    {
+	        logmsg(LOG_ERR, "Multiple HostRewrite types defined in a Group -
aborted");
+	        exit(1);
+	    }
+
+	    /* only STATIC "string" supported for now */
+	    groups[tot_groups]->host_type = HostSTATIC;
+
+	    lin[matches[1].rm_eo] = '\0';
+	    if((groups[tot_groups]->host_string = strdup(lin + matches[1].rm_so))
== NULL)
+	    {
+		logmsg(LOG_ERR, "HostRewrite config: out of memory - aborted");
+		exit(1);
+	    }
+
+	    logmsg(LOG_WARNING, "DEBUG config.c: HostRewrite STATIC \"%s\"\n",
groups[tot_groups]->host_string);
+
+#endif	/* HOST_REWRITE */
+
         } else if(in_group && !regexec(&HeadRequire, lin, 4, matches, 0)) {
             lin[matches[1].rm_eo] = lin[matches[2].rm_eo] = '\0';
             snprintf(pat, MAXBUF - 1, "^%s: *%s$", lin + matches[1].rm_so,
lin + matches[2].rm_so);
(at)(at) -654,6 +692,9 (at)(at)
     regfree(&SessionURL);
     regfree(&SessionCOOKIE);
     regfree(&SessionBASIC);
+#ifdef HOST_REWRITE
+    regfree(&HostRewrite);
+#endif	/* HOST_REWRITE */
     regfree(&User);
     regfree(&Group);
     regfree(&RootJail);
--- ./Pound-current.orig/http.c	2003-12-12 10:17:31.000000000 +0100
+++ ./Pound-current/http.c	2004-01-15 09:26:31.000000000 +0100
(at)(at) -634,10 +634,15 (at)(at)
             switch(check_header(headers[n], buf)) {
             case HEADER_HOST:
                 strcpy(v_host, buf);
-                if((mh = add_port(buf, &to_host)) != NULL) {
-                    free(headers[n]);
-                    headers[n] = mh;
-                }
+#ifdef HOST_REWRITE
+// logmsg(LOG_WARNING, "DEBUG http.c: v_host=\"%s\"\n", v_host);
+		headers_ok[n] = 0;	// suppress
+#else	/* original code */
+		if((mh = add_port(buf, &to_host)) != NULL) {
+		    free(headers[n]);
+		    headers[n] = mh;
+		}
+#endif	/* HOST_REWRITE */
                 break;
             case HEADER_REFERER:
                 strcpy(referer, buf);
(at)(at) -748,6 +753,7 (at)(at)
         for(n = 0; n < MAXHEADERS && headers[n]; n++) {
             if(!headers_ok[n])
                 continue;
+
             if(BIO_printf(be, "%s\r\n", headers[n]) <= 0) {
                 logmsg(LOG_WARNING, "error write to %s:%hd: %s",
                     inet_ntoa(srv->sin_addr), ntohs(srv->sin_port),
strerror(errno));
(at)(at) -759,6 +765,43 (at)(at)
         }
         free_headers(headers);
 
+#ifdef HOST_REWRITE 
+
+	/* only STATIC "string" supported for now */
+	if(grp->host_type == HostSTATIC)
+	{
+logmsg(LOG_WARNING, "DEBUG http.c: HostRewrite STATIC \"%s\"\n",
grp->host_string);
+	    if(BIO_printf(be, "Host: %s\r\n", grp->host_string) <= 0)
+	    {
+		logmsg(LOG_WARNING, "error write to %s:%hd: %s",
+		    inet_ntoa(srv->sin_addr), ntohs(srv->sin_port), strerror(errno));
+		err_reply(cl, h500, e500);
+		free_headers(headers);
+		clean_all();
+		pthread_exit(NULL);
+	    }
+	}
+	else
+	{
+	    /* todo: insert mh = add_port(v_host, &to_host) here if it does not
break anything */
+	    // if((mh = add_port(buf, &to_host)) != NULL) {
+	    // free(headers[n]);
+	    // headers[n] = mh;
+	    // }
+// logmsg(LOG_WARNING, "DEBUG http.c: Host send \"Host: %s\"\n", v_host);
+	    // if(BIO_printf(be, "Host: %s\r\n", mh) <= 0)
+	    if(BIO_printf(be, "Host: %s\r\n", v_host) <= 0)
+	    {
+		logmsg(LOG_WARNING, "error write to %s:%hd: %s",
+		    inet_ntoa(srv->sin_addr), ntohs(srv->sin_port), strerror(errno));
+		err_reply(cl, h500, e500);
+		free_headers(headers);
+		clean_all();
+		pthread_exit(NULL);
+	    }
+	}
+#endif  /* HOST_REWRITE 
+
         /* if SSL put additional headers for client certificate */
         if(ctx != NULL) {
             SSL_CIPHER  *cipher;



MailBoxer