webfs: implement CONNECT method for https connections over proxy
when using a http proxy, establish secure tls connection to the other end with the CONNECT method so the proxy.
This commit is contained in:
parent
e87bbc878e
commit
482694b72a
1 changed files with 88 additions and 28 deletions
|
@ -25,6 +25,7 @@ struct Hconn
|
||||||
int ctl;
|
int ctl;
|
||||||
int keep;
|
int keep;
|
||||||
int cancel;
|
int cancel;
|
||||||
|
int tunnel;
|
||||||
int len;
|
int len;
|
||||||
char addr[128];
|
char addr[128];
|
||||||
char buf[8192+2];
|
char buf[8192+2];
|
||||||
|
@ -60,12 +61,40 @@ static Hauth *hauth;
|
||||||
|
|
||||||
static void hclose(Hconn *h);
|
static void hclose(Hconn *h);
|
||||||
|
|
||||||
|
static int
|
||||||
|
tlstrace(char *fmt, ...)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
va_list a;
|
||||||
|
va_start(a, fmt);
|
||||||
|
r = vfprint(2, fmt, a);
|
||||||
|
va_end(a);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tlswrap(int fd)
|
||||||
|
{
|
||||||
|
TLSconn conn;
|
||||||
|
|
||||||
|
memset(&conn, 0, sizeof(conn));
|
||||||
|
if(debug)
|
||||||
|
conn.trace = tlstrace;
|
||||||
|
if((fd = tlsClient(fd, &conn)) < 0){
|
||||||
|
if(debug) fprint(2, "tlsClient: %r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(conn.cert);
|
||||||
|
free(conn.sessionID);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
static Hconn*
|
static Hconn*
|
||||||
hdial(Url *u)
|
hdial(Url *u)
|
||||||
{
|
{
|
||||||
char addr[128];
|
char addr[128];
|
||||||
Hconn *h, *p;
|
Hconn *h, *p;
|
||||||
int fd, ofd, ctl;
|
int fd, ctl;
|
||||||
|
|
||||||
snprint(addr, sizeof(addr), "tcp!%s!%s", u->host, u->port ? u->port : u->scheme);
|
snprint(addr, sizeof(addr), "tcp!%s!%s", u->host, u->port ? u->port : u->scheme);
|
||||||
|
|
||||||
|
@ -83,38 +112,42 @@ hdial(Url *u)
|
||||||
}
|
}
|
||||||
hpool.active++;
|
hpool.active++;
|
||||||
qunlock(&hpool);
|
qunlock(&hpool);
|
||||||
|
|
||||||
if(debug)
|
if(debug)
|
||||||
fprint(2, "hdial [%d] %s\n", hpool.active, addr);
|
fprint(2, "hdial [%d] %s\n", hpool.active, addr);
|
||||||
|
|
||||||
if((fd = dial(addr, 0, 0, &ctl)) < 0)
|
if(proxy)
|
||||||
return nil;
|
snprint(addr, sizeof(addr), "tcp!%s!%s",
|
||||||
if(strcmp(u->scheme, "https") == 0){
|
proxy->host, proxy->port ? proxy->port : proxy->scheme);
|
||||||
char err[ERRMAX];
|
|
||||||
TLSconn conn;
|
|
||||||
|
|
||||||
strcpy(err, "tls error");
|
if((fd = dial(addr, 0, 0, &ctl)) >= 0){
|
||||||
memset(&conn, 0, sizeof(conn));
|
if(proxy){
|
||||||
if((fd = tlsClient(ofd = fd, &conn)) < 0)
|
if(strcmp(proxy->scheme, "https") == 0)
|
||||||
errstr(err, sizeof(err));
|
fd = tlswrap(fd);
|
||||||
free(conn.cert);
|
} else {
|
||||||
free(conn.sessionID);
|
if(strcmp(u->scheme, "https") == 0)
|
||||||
if(fd < 0){
|
fd = tlswrap(fd);
|
||||||
close(ofd);
|
|
||||||
close(ctl);
|
|
||||||
if(debug) fprint(2, "tlsClient: %s\n", err);
|
|
||||||
errstr(err, sizeof(err));
|
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(fd < 0){
|
||||||
|
close(ctl);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
h = emalloc(sizeof(*h));
|
h = emalloc(sizeof(*h));
|
||||||
h->next = nil;
|
h->next = nil;
|
||||||
h->time = 0;
|
h->time = 0;
|
||||||
h->cancel = 0;
|
h->cancel = 0;
|
||||||
|
h->tunnel = 0;
|
||||||
h->keep = 1;
|
h->keep = 1;
|
||||||
h->len = 0;
|
h->len = 0;
|
||||||
h->fd = fd;
|
h->fd = fd;
|
||||||
h->ctl = ctl;
|
h->ctl = ctl;
|
||||||
|
|
||||||
|
if(proxy){
|
||||||
|
h->tunnel = strcmp(u->scheme, "https") == 0;
|
||||||
|
snprint(addr, sizeof(addr), "tcp!%s!%s", u->host, u->port ? u->port : u->scheme);
|
||||||
|
}
|
||||||
nstrcpy(h->addr, addr, sizeof(h->addr));
|
nstrcpy(h->addr, addr, sizeof(h->addr));
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
|
@ -143,7 +176,7 @@ hclose(Hconn *h)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qlock(&hpool);
|
qlock(&hpool);
|
||||||
if(h->keep && h->fd >= 0){
|
if(!h->tunnel && h->keep && h->fd >= 0){
|
||||||
for(n = 0, i = 0, t = nil, x = hpool.head; x; x = x->next){
|
for(n = 0, i = 0, t = nil, x = hpool.head; x; x = x->next){
|
||||||
if(strcmp(x->addr, h->addr) == 0)
|
if(strcmp(x->addr, h->addr) == 0)
|
||||||
if(++n > hpool.peer)
|
if(++n > hpool.peer)
|
||||||
|
@ -299,9 +332,12 @@ hline(Hconn *h, char *data, int len, int cont)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(h->len >= sizeof(h->buf))
|
n = sizeof(h->buf) - h->len;
|
||||||
|
if(n <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
if((n = read(h->fd, h->buf + h->len, sizeof(h->buf) - h->len)) <= 0){
|
if(h->tunnel)
|
||||||
|
n = 1; /* do not read beyond header */
|
||||||
|
if((n = read(h->fd, h->buf + h->len, n)) <= 0){
|
||||||
hhangup(h);
|
hhangup(h);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -502,6 +538,7 @@ http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost)
|
||||||
fd = -1;
|
fd = -1;
|
||||||
|
|
||||||
h = nil;
|
h = nil;
|
||||||
|
cfd = -1;
|
||||||
pid = 0;
|
pid = 0;
|
||||||
host = nil;
|
host = nil;
|
||||||
needlength = 0;
|
needlength = 0;
|
||||||
|
@ -570,12 +607,12 @@ http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost)
|
||||||
free(host);
|
free(host);
|
||||||
host = smprint("%H", u->host);
|
host = smprint("%H", u->host);
|
||||||
|
|
||||||
if(proxy){
|
if(proxy && strcmp(u->scheme, "https") != 0){
|
||||||
ru = *u;
|
ru = *u;
|
||||||
ru.host = host;
|
ru.host = host;
|
||||||
ru.fragment = nil;
|
ru.fragment = nil;
|
||||||
} else {
|
} else {
|
||||||
memset(&ru, 0, sizeof(tu));
|
memset(&ru, 0, sizeof(ru));
|
||||||
ru.path = Upath(u);
|
ru.path = Upath(u);
|
||||||
ru.query = u->query;
|
ru.query = u->query;
|
||||||
}
|
}
|
||||||
|
@ -587,11 +624,15 @@ http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost)
|
||||||
}
|
}
|
||||||
if(h == nil){
|
if(h == nil){
|
||||||
alarm(timeout);
|
alarm(timeout);
|
||||||
if((h = hdial(proxy ? proxy : u)) == nil)
|
if((h = hdial(u)) == nil)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if(h->tunnel){
|
||||||
if((cfd = open("/mnt/webcookies/http", ORDWR)) >= 0){
|
n = snprint(buf, sizeof(buf), "CONNECT %s:%s HTTP/1.1\r\nHost: %s:%s\r\n",
|
||||||
|
host, u->port ? u->port : "443",
|
||||||
|
host, u->port ? u->port : "443");
|
||||||
|
}
|
||||||
|
else if((cfd = open("/mnt/webcookies/http", ORDWR)) >= 0){
|
||||||
/* only scheme, host and path are relevant for cookies */
|
/* only scheme, host and path are relevant for cookies */
|
||||||
memset(&tu, 0, sizeof(tu));
|
memset(&tu, 0, sizeof(tu));
|
||||||
tu.scheme = u->scheme;
|
tu.scheme = u->scheme;
|
||||||
|
@ -617,8 +658,12 @@ http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(k = shdr; k; k = k->next)
|
for(k = shdr; k; k = k->next){
|
||||||
|
/* only send proxy headers when establishing tunnel */
|
||||||
|
if(h->tunnel && cistrncmp(k->key, "Proxy-", 6) != 0)
|
||||||
|
continue;
|
||||||
n += snprint(buf+n, sizeof(buf)-2 - n, "%s: %s\r\n", k->key, k->val);
|
n += snprint(buf+n, sizeof(buf)-2 - n, "%s: %s\r\n", k->key, k->val);
|
||||||
|
}
|
||||||
n += snprint(buf+n, sizeof(buf)-n, "\r\n");
|
n += snprint(buf+n, sizeof(buf)-n, "\r\n");
|
||||||
if(debug)
|
if(debug)
|
||||||
fprint(2, "-> %.*s", n, buf);
|
fprint(2, "-> %.*s", n, buf);
|
||||||
|
@ -628,7 +673,7 @@ http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost)
|
||||||
goto Retry;
|
goto Retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(qpost){
|
if(qpost && !h->tunnel){
|
||||||
h->cancel = 0;
|
h->cancel = 0;
|
||||||
if((pid = rfork(RFMEM|RFPROC)) <= 0){
|
if((pid = rfork(RFMEM|RFPROC)) <= 0){
|
||||||
int ifd;
|
int ifd;
|
||||||
|
@ -832,6 +877,8 @@ http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost)
|
||||||
case 202: /* Accepted */
|
case 202: /* Accepted */
|
||||||
case 203: /* Non-Authoritative Information */
|
case 203: /* Non-Authoritative Information */
|
||||||
case 206: /* Partial Content */
|
case 206: /* Partial Content */
|
||||||
|
if(h->tunnel)
|
||||||
|
break;
|
||||||
qbody->url = u; u = nil;
|
qbody->url = u; u = nil;
|
||||||
qbody->hdr = rhdr; rhdr = nil;
|
qbody->hdr = rhdr; rhdr = nil;
|
||||||
if(nobody)
|
if(nobody)
|
||||||
|
@ -853,6 +900,19 @@ http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost)
|
||||||
shdr = delkey(shdr, "Proxy-Authorization");
|
shdr = delkey(shdr, "Proxy-Authorization");
|
||||||
shdr = delkey(shdr, "Authorization");
|
shdr = delkey(shdr, "Authorization");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* when 2xx response is given for the CONNECT request
|
||||||
|
* then the proxy server has established the connection.
|
||||||
|
*/
|
||||||
|
if(h->tunnel && !retry && (i/100) == 2){
|
||||||
|
if((h->fd = tlswrap(h->fd)) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* proceed to the original request */
|
||||||
|
h->tunnel = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(!chunked && length == NOLENGTH)
|
if(!chunked && length == NOLENGTH)
|
||||||
h->keep = 0;
|
h->keep = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue