From a20f6461691b333014165213590edb4f1019f4aa Mon Sep 17 00:00:00 2001
From: Vladimir Dubrovin <3proxy@3proxy.ru>
Date: Mon, 12 Oct 2026 17:19:55 +0300
Subject: [PATCH] Pre-allocate client/server/tmp/etc buffers with client
structure
---
doc/html/devel/devref.html | 2 +-
man/3proxy.cfg.5 | 5 +-
src/acl.c | 6 +-
src/auth.c | 37 ++--
src/authradius.c | 6 +-
src/auto.c | 7 +-
src/common.c | 48 +++--
src/conf.c | 2 +-
src/ftp.c | 7 +-
src/ftppr.c | 8 +-
src/hashtables.c | 18 +-
src/httpsrv.c | 68 +++----
src/imapp.c | 4 +-
src/log.c | 16 +-
src/pcre.c | 5 +-
src/plugins/LdapPlugin/ldapauth.c | 2 +-
src/plugins/PamAuth/pamauth.c | 2 +-
.../WindowsAuthentication.c | 2 +-
src/plugins/utf8tocp1251/utf8tocp1251.c | 2 +-
src/pop3p.c | 2 +-
src/proxy.c | 56 +++---
src/proxy.h | 30 ++--
src/proxymain.c | 87 ++++-----
src/redirect.c | 33 +---
src/resolve.c | 6 +-
src/smtpp.c | 54 +++---
src/sockgetchar.c | 166 ++++++++++--------
src/sockmap.c | 15 +-
src/socks.c | 43 ++---
src/ssl.c | 10 +-
src/structures.h | 50 ++++--
src/tcppm.c | 6 +-
src/tlspr.c | 94 +++-------
src/transparent.c | 6 +-
src/udppm.c | 4 -
src/udpsockmap.c | 14 +-
36 files changed, 431 insertions(+), 492 deletions(-)
diff --git a/doc/html/devel/devref.html b/doc/html/devel/devref.html
index 58d51aa..a19ae7e 100644
--- a/doc/html/devel/devref.html
+++ b/doc/html/devel/devref.html
@@ -233,7 +233,7 @@ struct filter {
filter_open must always be defined, if you want filter to be ever used. It's called then new service is created and is given "data" from struct filter and struct srvparam (parsed service configuration). If filter_open for some filter returns NULL, filter will not be used for this service. Non-NULL return value will be used as "fo" parameter for every call to filter_client.
filter_client is called upon client connect (before any data is sent/received). It's good place to filter client by IP (and is not good place to filter it by hostname, because this operation takes a long time, 3proxy will not be able to accept new connection). fo is a data pointer received from filter_open, param – newly created clientparam structure, fc is return parameter filter_open must initialize, it will be used as an argument to FILTER_BUFFER functions. PASS return value means this filter will be used for this client request. CONTINUE says to install filters. On different values client connection is closed and no client thread is created.
filter_request, filter_header_cli, filter_header_srv, filter_data_cli, filter_data_srv are used to process request and data received from client and server.
- char ** buf_p is a pointer to current buffer, int * bufsize_p is a pointer to it's size. In case you change some data and it doesn't fit to current buffer, you may allocate new buffer (with pluginlink->myalloc), copy data from old buffer, free old buffer (with pluginlink->myfree) and set new values for *buf_p and *bufsize_p.
+ char ** buf_p is a pointer to current buffer, int * bufsize_p is a pointer to it's size. In case you change some data and it doesn't fit to current buffer, you may allocate new buffer (with pluginlink->mallocfunc), copy data from old buffer and set new values for *buf_p and *bufsize_p. Do not free the buffer you were given: it may not be heap memory, and 3proxy frees it itself when it was. A buffer you allocated and then replaced again within the same call is yours to free (with pluginlink->freefunc).
int offset offset of the new data in the buffer, int * length_p length of all data in the buffer. You should filter only (*length_p - *offset_p) characters starting from (*buf_p + *offset_p).
filter_clear is called for each successfule filter_client and should be used to free allocated resources
filter_close is called for each successful filter_open for the same reason
diff --git a/man/3proxy.cfg.5 b/man/3proxy.cfg.5
index c6819a4..77850bb 100644
--- a/man/3proxy.cfg.5
+++ b/man/3proxy.cfg.5
@@ -1436,7 +1436,10 @@ as
.br
If Content-length (or another data length) is greater than the given value, no
data filtering will be performed through filtering plugins to avoid data
-corruption and/or Content-Length changing. Default is 1MB (1048576).
+corruption and/or Content-Length changing. A body up to this size is read
+whole into memory and filtered at once. 0 removes the limit, but then a body
+is only filtered whole if it fits in the connection's 16K buffer.
+Default is 1MB (1048576).
.SH SSL/TLS SUPPORT
SSL/TLS support is built into 3proxy (since 0.9.7) when compiled with OpenSSL
diff --git a/src/acl.c b/src/acl.c
index 719cb37..d094754 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -280,7 +280,7 @@ int ACLmatches(struct ace* acentry, struct clientparam * param){
int dstdep = 0;
int preauth = (param->preauth == 1 && acentry->action <= REDIRECT);
- username = param->username?param->username:(unsigned char *)"-";
+ username = *param->username?param->username:(unsigned char *)"-";
if(acentry->src) {
for(ipentry = acentry->src; ipentry; ipentry = ipentry->next)
if(IPInentry((struct sockaddr *)¶m->sincr, ipentry)) {
@@ -291,13 +291,13 @@ int ACLmatches(struct ace* acentry, struct clientparam * param){
if(preauth && (acentry->dst || acentry->dstnames)) {
dstdep = 1;
}
- else if((acentry->dst && (!SAISNULL(¶m->req) || param->operation==BIND)) || (acentry->dstnames && param->hostname)) {
+ else if((acentry->dst && (!SAISNULL(¶m->req) || param->operation==BIND)) || (acentry->dstnames && *param->hostname)) {
for(ipentry = acentry->dst; ipentry; ipentry = ipentry->next)
if(IPInentry((struct sockaddr *)¶m->req, ipentry)) {
break;
}
if(!ipentry) {
- if(acentry->dstnames && param->hostname){
+ if(acentry->dstnames && *param->hostname){
for(i=0; param->hostname[i]; i++){
param->hostname[i] = tolower(param->hostname[i]);
}
diff --git a/src/auth.c b/src/auth.c
index e37c783..a1192af 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -83,8 +83,8 @@ int cacheauth(struct clientparam * param){
if(
- ((type & 2) && !param->username) ||
- ((type & 4) && !param->password) ||
+ ((type & 2) && !*param->username) ||
+ ((type & 4) && !*param->password) ||
(
(type & 1) && *SAFAMILY(¶m->sincr) != AF_INET
#ifndef NOIPV6
@@ -100,10 +100,7 @@ int cacheauth(struct clientparam * param){
return 10;
}
- if(!(type&2) && *ac.username){
- if(param->username) free(param->username);
- param->username = (unsigned char *)strdup((char *)ac.username);
- }
+ if(!(type&2) && *ac.username && PARAMSTR(param, username, ac.username)) return 4;
if((type & 32)){
memset(¶m->sinsl, 0, sizeof(param->sinsl));
*(SAFAMILY(¶m->sinsl)) = ac.sinsl_family;
@@ -125,13 +122,11 @@ int doauth(struct clientparam * param){
if(authfuncs->authorize &&
(res = (*authfuncs->authorize)(param)))
return res;
- if(param->srv->authcachetype && authfuncs->authenticate && authfuncs->authenticate != cacheauth && param->username && (!(param->srv->authcachetype&4) || (!param->pwtype && param->password))){
+ if(param->srv->authcachetype && authfuncs->authenticate && authfuncs->authenticate != cacheauth && *param->username && (!(param->srv->authcachetype&4) || (!param->pwtype && *param->password))){
struct authcache ac={.username=""};
- if(param->username) {
- strncpy((char *)ac.username, (char *)param->username, 64);
- ac.username[63] = 0;
- }
+ strncpy((char *)ac.username, (char *)param->username, 64);
+ ac.username[63] = 0;
if(*SAFAMILY(¶m->sincr) == AF_INET
#ifndef NOIPV6
|| *SAFAMILY(¶m->sincr) == AF_INET6
@@ -158,7 +153,7 @@ int doauth(struct clientparam * param){
}
if(!res){
ret = (param->preauth == 2)? 0 : alwaysauth(param);
- if (param->afterauthfilters){
+ if (param->nafterauthfilters){
FILTER_ACTION action;
action = handleafterauthflt(param);
@@ -173,16 +168,18 @@ int doauth(struct clientparam * param){
int ipauth(struct clientparam * param){
int res;
- unsigned char *username;
- username = param->username;
- param->username = NULL;
+ unsigned char c;
+
+ /* the rules are matched as if no name had been given */
+ c = *param->username;
+ *param->username = 0;
res = checkACL(param);
- param->username = username;
+ *param->username = c;
return res;
}
int userauth(struct clientparam * param){
- return (param->username)? 0:4;
+ return (*param->username)? 0:4;
}
int dnsauth(struct clientparam * param){
@@ -221,7 +218,7 @@ int dnsauth(struct clientparam * param){
return 3;
}
- return param->username? 0:3;
+ return *param->username? 0:3;
}
static int ctmemcmp(const void *a, const void *b, size_t len){
@@ -246,8 +243,8 @@ int strongauth(struct clientparam * param){
unsigned char buf[256];
char pass[256] = {0};
- if (!param->username) return 4;
- if (!param->pwtype && param->password) {
+ if (!*param->username) return 4;
+ if (!param->pwtype && *param->password) {
if (pwl_table.ihashtable && hashresolv(&pwl_table, param->username, pass, NULL)) {
switch(pass[0]){
case CL: {
diff --git a/src/authradius.c b/src/authradius.c
index 1234596..c66586c 100644
--- a/src/authradius.c
+++ b/src/authradius.c
@@ -401,7 +401,7 @@ int radsend(struct clientparam * param, int auth, int stop){
total_length += (2+len);
/* Called-Station-ID */
- if(param->hostname){
+ if(*param->hostname){
*ptr++ = PW_CALLED_STATION_ID;
len = strlen((char *)param->hostname);
if(len > 253) len = 253;
@@ -443,7 +443,7 @@ int radsend(struct clientparam * param, int auth, int stop){
/* Username */
- if(param->username){
+ if(*param->username){
len = strlen((char *)param->username);
if(len>128)len=128;
*ptr++ = PW_USER_NAME;
@@ -502,7 +502,7 @@ int radsend(struct clientparam * param, int auth, int stop){
total_length+=6;
}
- if(auth && param->password){
+ if(auth && *param->password){
len = strlen((char *)param->password);
if(len > 128) len = 128;
*ptr++ = PW_PASSWORD;
diff --git a/src/auto.c b/src/auto.c
index e3dd5b8..3e3d093 100644
--- a/src/auto.c
+++ b/src/auto.c
@@ -12,12 +12,7 @@
void * autochild(struct clientparam* param) {
int len;
- if(!param->clibuf){
- if(!(param->clibuf = malloc(SRVBUFSIZE))) return 0;
- param->clibufsize = SRVBUFSIZE;
- param->clioffset = param->cliinbuf = 0;
- }
- len = sockfillbuffcli(param, 1, CONNECTION_S);
+ len = sockfillbuf(param, CLIENT, 1, CONNECTION_S);
if (len != 1){
param->res = 801;
dolog(param, (unsigned char *)"");
diff --git a/src/common.c b/src/common.c
index 8fa14bb..c39ba67 100644
--- a/src/common.c
+++ b/src/common.c
@@ -561,9 +561,10 @@ int parsehostname(char *hostname, struct clientparam *param, uint16_t port){
if(sp) *sp = ':';
return 1;
}
- if(hostname != (char *)param->hostname){
- if(param->hostname) free(param->hostname);
- param->hostname = (unsigned char *)strdup(hostname + (se!=0));
+ if(PARAMSTR(param, hostname, hostname + (se!=0))){
+ if(se) *se = ']';
+ if(sp) *sp = ':';
+ return 1;
}
if(sp){
port = atoi(sp+1);
@@ -576,6 +577,22 @@ int parsehostname(char *hostname, struct clientparam *param, uint16_t port){
return ret;
}
+/* Copies a string into one of a connection's fixed fields. One too long for
+ it is refused rather than cut short, which could name another host or
+ another user; NULL empties it. The string may be part of the field. */
+int paramstr(unsigned char *field, size_t size, const unsigned char *s){
+ size_t len;
+
+ if(!s){
+ *field = 0;
+ return 0;
+ }
+ len = strlen((const char *)s);
+ if(len >= size) return 1;
+ memmove(field, s, len + 1);
+ return 0;
+}
+
int parseusername(char *username, struct clientparam *param, int extpasswd){
char *sb = NULL, *se = NULL, *sp = NULL;
@@ -584,13 +601,12 @@ int parseusername(char *username, struct clientparam *param, int extpasswd){
*sb = 0;
*se = 0;
if(sp) *sp = 0;
- if(*(sb+1)) {
- if(param->password) free(param->password);
- param->password = (unsigned char *)strdup(sb+1);
- }
- if(*username) {
- if(param->username) free(param->username);
- param->username = (unsigned char *)strdup(username);
+ if((*(sb+1) && PARAMSTR(param, password, sb+1)) ||
+ (*username && PARAMSTR(param, username, username))){
+ *sb = ':';
+ *se = ':';
+ if(sp) *sp = ':';
+ return 1;
}
username = se+1;
}
@@ -598,24 +614,22 @@ int parseusername(char *username, struct clientparam *param, int extpasswd){
if(!sp) sp = strchr(username, ':');
if(sp){
*sp = 0;
- if(param->extpassword) free(param->extpassword);
- param->extpassword = (unsigned char *) strdup(sp+1);
+ if(PARAMSTR(param, extpassword, sp+1)) extpasswd = -1;
}
}
- if(param->extusername) free(param->extusername);
- param->extusername = (unsigned char *)strdup(username);
+ if(extpasswd < 0 || PARAMSTR(param, extusername, username)) extpasswd = -1;
if(sb) *sb = ':';
if(se) *se = ':';
if(sp) *sp = ':';
- return 0;
+ return extpasswd < 0;
}
int parseconnusername(char *username, struct clientparam *param, int extpasswd, uint16_t port){
char *sb, *se;
if(!username || !*username) return 1;
if ((sb=strchr(username, conf.delimchar)) == NULL){
- if(!param->hostname && param->remsock == INVALID_SOCKET) return 2;
- if(param->hostname)parsehostname((char *)param->hostname, param, *SAPORT(¶m->req)? ntohs(*SAPORT(¶m->req)) : port);
+ if(!*param->hostname && param->remsock == INVALID_SOCKET) return 2;
+ if(*param->hostname)parsehostname((char *)param->hostname, param, *SAPORT(¶m->req)? ntohs(*SAPORT(¶m->req)) : port);
return parseusername(username, param, extpasswd);
}
while ((se=strchr(sb+1, conf.delimchar)))sb=se;
diff --git a/src/conf.c b/src/conf.c
index bf5f769..8ca5b53 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -162,7 +162,7 @@ int start_proxy_thread(struct child * chp){
#endif
if((res = mainprepare(chp->argc, (char **)chp->argv, &service))) {
- fprintf(stderr, "Service not started on line: %d%s\n", linenum, res == 2? ": insufficient memory":"");
+ fprintf(stderr, "Service not started on line: %d%s\n", linenum, res == 2? ": insufficient memory": res == 3? ": too many filters":"");
return(40);
}
_3proxy_mutex_lock(&runningservices_mutex);
diff --git a/src/ftp.c b/src/ftp.c
index 94cda64..997286a 100644
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -41,7 +41,7 @@ int ftplogin(struct clientparam *param, char *nbuf, int *innbuf) {
*innbuf = i;
return 702;
}
- sprintf(buf, "USER %.128s\r\n", param->extusername?param->extusername:(unsigned char *)"anonymous");
+ sprintf(buf, "USER %.128s\r\n", *param->extusername?param->extusername:(unsigned char *)"anonymous");
if((int)socksend(param, param->remsock, (unsigned char *)buf, (int)strlen(buf), conf.timeouts[STRING_S]) != (int)strlen(buf)){
return 703;
}
@@ -53,10 +53,7 @@ int ftplogin(struct clientparam *param, char *nbuf, int *innbuf) {
res = atoi(buf)/100;
if(res == 3){
sprintf(buf, "PASS %.128s\r\n",
- param->extusername?
- (param->extpassword?
- param->extpassword:(unsigned char *)"")
- :(unsigned char *)"3proxy@");
+ *param->extusername? param->extpassword : (unsigned char *)"3proxy@");
res = (int)strlen(buf);
if((int)socksend(param, param->remsock, (unsigned char *)buf, res, conf.timeouts[STRING_S]) != (int)strlen(buf)){
return 705;
diff --git a/src/ftppr.c b/src/ftppr.c
index e6f8d42..ff64d9b 100644
--- a/src/ftppr.c
+++ b/src/ftppr.c
@@ -28,7 +28,7 @@ void * ftpprchild(struct clientparam* param) {
#endif
struct pollfd fds;
- if(!(buf = malloc(BUFSIZE))) RETURN(876);
+ buf = param->tmpbuf; /* a filter may replace it with one of its own */
param->ctrlsock = param->clisock;
param->operation = CONNECT;
#ifndef _WIN32
@@ -73,11 +73,11 @@ void * ftpprchild(struct clientparam* param) {
/* The user name carries the server to log in to, and it arrives
with USER. Without it there is nothing to log in to, and what
follows would read the name and the host as if there were. */
- if(!param->hostname || !param->extusername){
+ if(!*param->hostname || !*param->extusername){
socksend(param, param->ctrlsock, (unsigned char *)"503 Login with USER first\r\n", 27, conf.timeouts[STRING_S]);
RETURN(805);
}
- param->extpassword = (unsigned char *)strdup((char *)buf+5);
+ if(PARAMSTR(param, extpassword, buf+5)){RETURN(806);}
inbuf = BUFSIZE;
res = ftplogin(param, (char *)buf, &inbuf);
param->res = res;
@@ -341,7 +341,7 @@ CLEANRET:
dolog(param, (unsigned char *)((req && (param->res > 802))? req:NULL));
}
if(req) free(req);
- if(buf) free(buf);
+ if(buf != param->tmpbuf) free(buf);
return (NULL);
}
diff --git a/src/hashtables.c b/src/hashtables.c
index 4a7563d..f52b8c9 100644
--- a/src/hashtables.c
+++ b/src/hashtables.c
@@ -31,13 +31,13 @@ void param2hash_search(const struct hashtable *ht, void *index, uint8_t *hash){
int oplen = 0, acllen = 0, ulen = 0, plen = 0, hlen = 0, a1len = 0, a2len = 0, a3len = 0, p1len=0, p2len = 0;
- if((type & 2) && param->username) ulen = strlen((const char *)param->username) + 1;
- if((type & 4) && param->password) plen = strlen((const char *)param->password) + 1;
+ if((type & 2) && *param->username) ulen = strlen((const char *)param->username) + 1;
+ if((type & 4) && *param->password) plen = strlen((const char *)param->password) + 1;
if((type & 1) && !(type & 8)) a1len = SAADDRLEN(¶m->sincr);
if((type & 16)) acllen = sizeof(param->srv->acl);
if((type & 64)) a2len = SAADDRLEN(¶m->req);
if((type & 128)) p1len = 2 ;
- if((type & 256) && param->hostname) hlen = strlen((const char *)param->hostname) + 1;
+ if((type & 256) && *param->hostname) hlen = strlen((const char *)param->hostname) + 1;
if((type & 512)) oplen = sizeof(param->operation);
if((type & 1024)) a3len = SAADDRLEN(¶m->srv->intsa);
if((type & 2048)) p2len = 2;
@@ -45,13 +45,13 @@ void param2hash_search(const struct hashtable *ht, void *index, uint8_t *hash){
memset(hash, 0, ht->hash_size);
if(ulen + plen + a1len + acllen + a2len + p1len + hlen + oplen + a3len + p2len <= ht->hash_size){
int offset = 0;
- if((type & 2) && param->username){ memcpy(hash + offset, param->username, ulen); offset += ulen; }
- if((type & 4) && param->password){ memcpy(hash + offset, param->password, plen); offset += plen; }
+ if((type & 2) && *param->username){ memcpy(hash + offset, param->username, ulen); offset += ulen; }
+ if((type & 4) && *param->password){ memcpy(hash + offset, param->password, plen); offset += plen; }
if((type & 1) && !(type & 8)){ memcpy(hash + offset, SAADDR(¶m->sincr), a1len); offset += a1len; }
if((type & 16)){ memcpy(hash + offset, ¶m->srv->acl, acllen); offset += acllen; }
if((type & 64)){ memcpy(hash + offset, SAADDR(¶m->req), a2len); offset += a2len; }
if((type & 128)){ memcpy(hash + offset, SAPORT(¶m->req), p1len); offset += 2; }
- if((type & 256) && param->hostname){ memcpy(hash + offset, param->hostname, hlen); offset += hlen; }
+ if((type & 256) && *param->hostname){ memcpy(hash + offset, param->hostname, hlen); offset += hlen; }
if((type & 512)){ memcpy(hash + offset, ¶m->operation, oplen); offset += oplen; }
if((type & 1024)){ memcpy(hash + offset, SAADDR(¶m->srv->intsa), a3len); offset += a3len; }
if((type & 2048)){ memcpy(hash + offset, SAPORT(¶m->srv->intsa), p2len); offset += 2; }
@@ -60,13 +60,13 @@ void param2hash_search(const struct hashtable *ht, void *index, uint8_t *hash){
mdh_ctx *bctx = mdh_init(MDH_BLAKE2, ht->hash_size);
unsigned int blen = ht->hash_size;
if(!bctx) { memcpy(param->hash, hash, ht->hash_size); return; }
- if((type & 2) && param->username)mdh_update(bctx, param->username, ulen);
- if((type & 4) && param->password)mdh_update(bctx, param->password, plen);
+ if((type & 2) && *param->username)mdh_update(bctx, param->username, ulen);
+ if((type & 4) && *param->password)mdh_update(bctx, param->password, plen);
if((type & 1) && !(type & 8))mdh_update(bctx, SAADDR(¶m->sincr), a1len);
if((type & 16))mdh_update(bctx, ¶m->srv->acl, acllen);
if((type & 64))mdh_update(bctx, SAADDR(¶m->req), a2len);
if((type & 128))mdh_update(bctx, SAPORT(¶m->req), 2);
- if((type & 256) && param->hostname)mdh_update(bctx, param->hostname, hlen);
+ if((type & 256) && *param->hostname)mdh_update(bctx, param->hostname, hlen);
if((type & 512))mdh_update(bctx, ¶m->operation, sizeof(param->operation));
if((type & 1024))mdh_update(bctx, SAADDR(¶m->srv->intsa), a3len);
if((type & 2048))mdh_update(bctx, SAPORT(¶m->srv->intsa), 2);
diff --git a/src/httpsrv.c b/src/httpsrv.c
index ab16f17..9e1065d 100644
--- a/src/httpsrv.c
+++ b/src/httpsrv.c
@@ -54,8 +54,6 @@
after it should be tried again. */
#define HTTPSRV_REWRITTEN 2
#define HTTPSRV_MAXBODY 1048576
-/* the most of a request this server keeps in case it hands it on */
-#define HTTPSRV_MAXRAW 65536
/* lengths a reply is written with: a count, or one of these */
#define HTTPSRV_LEN_CHUNKED (-1)
#define HTTPSRV_LEN_NONE (-2)
@@ -582,7 +580,7 @@ static const char * contenttype(const char *path)
static int sendfilecontent(struct httpreq *r, int fd, uint64_t size)
{
struct clientparam *param = r->param;
- char buf[HTTPSRV_BLOCK];
+ char *buf = (char *)param->tmpbuf;
uint64_t sent = 0;
#ifdef HTTPSRV_SENDFILE
@@ -627,7 +625,7 @@ static int sendfilecontent(struct httpreq *r, int fd, uint64_t size)
if(lseek(fd, (off_t)sent, SEEK_SET) == (off_t)-1) return 1;
while(sent < size){
uint64_t left = size - sent;
- int want = left > (uint64_t)sizeof(buf)? (int)sizeof(buf) : (int)left;
+ int want = left > (uint64_t)HTTPSRV_BLOCK? (int)HTTPSRV_BLOCK : (int)left;
int got;
got = (int)read(fd, buf, want);
@@ -988,7 +986,7 @@ static int op_echo(struct httpreq *r, const unsigned char *params)
Produces exactly N bytes of body. */
static int op_data(struct httpreq *r, const unsigned char *params)
{
- char buf[HTTPSRV_BLOCK];
+ char *buf = (char *)r->param->tmpbuf;
int64_t size, block, delay, status;
int chunked;
uint64_t sent = 0;
@@ -1141,11 +1139,12 @@ int httpopbyname(const unsigned char *name)
*/
static void httpsrv_drain(struct clientparam *param, uint64_t len)
{
- char buf[HTTPSRV_BLOCK];
+ char *buf = (char *)param->tmpbuf;
+ param->climark = -1; /* answered here: the request is not needed again */
if(len > HTTPSRV_MAXBODY) len = HTTPSRV_MAXBODY;
while(len){
- int want = (len > (uint64_t)sizeof(buf))? (int)sizeof(buf) : (int)len;
+ int want = (len > (uint64_t)HTTPSRV_BLOCK)? (int)HTTPSRV_BLOCK : (int)len;
int got = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, want, EOF,
conf.timeouts[STRING_S]);
@@ -1162,7 +1161,7 @@ static void httpsrv_drain(struct clientparam *param, uint64_t len)
and amount, which is what lets the answer be read. */
static void httpsrv_linger(struct clientparam *param)
{
- char buf[HTTPSRV_BLOCK];
+ char *buf = (char *)param->tmpbuf;
struct pollfd fd;
uint64_t left = HTTPSRV_MAXBODY;
time_t deadline = time(NULL) + conf.timeouts[LINGER_TO];
@@ -1179,33 +1178,12 @@ static void httpsrv_linger(struct clientparam *param)
fd.events = POLLIN;
if(param->srv->so._poll(param->sostate, &fd, 1, timeo * 1000) <= 0) break;
got = (int)param->srv->so._recv(param->sostate, param->clisock, buf,
- (left > sizeof(buf))? (int)sizeof(buf) : (int)left, 0);
+ (left > HTTPSRV_BLOCK)? (int)HTTPSRV_BLOCK : (int)left, 0);
if(got <= 0) break;
left -= (uint64_t)got;
}
}
-/* Keeps the request as the client wrote it. Only what a handoff needs: the
- request line and the headers, exactly as they came, since the proxy code
- reads them again from the beginning. */
-static int rawkeep(struct httpreq *r, const char *line, int len)
-{
- if(r->rawlen + len + 3 > r->rawsize){
- int want = r->rawsize? r->rawsize * 2 : 2048;
- unsigned char *grown;
-
- while(want < r->rawlen + len + 3) want *= 2;
- if(want > HTTPSRV_MAXRAW) return 1;
- grown = realloc(r->raw, (size_t)want);
- if(!grown) return 1;
- r->raw = grown;
- r->rawsize = want;
- }
- memcpy(r->raw + r->rawlen, line, (size_t)len);
- r->rawlen += len;
- return 0;
-}
-
/* Hands the request to the proxy code, which reads it again from the client
buffer and answers it as a proxy would, asking for its own credentials if
the configuration wants them. The connection stays with this service. */
@@ -1220,7 +1198,7 @@ static int proxypass(struct clientparam *param, struct httpreq *r)
a request already being answered on behalf of another child is never
handed on again. */
if(param->onerequest) return 1;
- if(!r->raw || rawkeep(r, "\r\n", 2)) return 1; /* the end of the headers */
+ if(param->climark < 0) return 1; /* the request is no longer there */
/* What is open towards the server belongs to the request before this
one. It is no use for this request if it went somewhere else, and no
@@ -1255,7 +1233,9 @@ static int proxypass(struct clientparam *param, struct httpreq *r)
r->lasthost[255] = 0;
}
- if(pushbackcli(param, r->raw, r->rawlen)) return 1;
+ /* the proxy reads the request from where it began */
+ param->clioffset = (unsigned)param->climark;
+ param->climark = -1;
param->onerequest = 1;
next = proxychild(param);
@@ -1283,11 +1263,15 @@ static int httpsrv_request(struct clientparam *param, struct httpreq *r)
struct httprule *rule;
int i, hdrs = 0;
+ /* The request is kept in the client buffer as it is read, so that one
+ handed to the proxy can be read there again from the start. One which
+ does not fit in the buffer is not answered. */
+ param->climark = (int)param->clioffset;
i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, sizeof(buf) - 1, '\n',
conf.timeouts[STRING_S]);
if(i <= 0 && !r->first) return 0; /* the client is done with us */
+ if(param->climark == -2) RETURN(710);
if(i < 5) RETURN(701);
- if(rawkeep(r, buf, i)) RETURN(710);
buf[i] = 0;
sp = strchr(buf, ' ');
@@ -1368,7 +1352,6 @@ static int httpsrv_request(struct clientparam *param, struct httpreq *r)
(i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, sizeof(buf) - 1,
'\n', conf.timeouts[STRING_S])) > 2){
hdrs++;
- if(rawkeep(r, buf, i)) RETURN(710);
buf[i] = 0;
if(!strncasecmp(buf, "host:", 5) && !r->proxy){
sp = buf + 5;
@@ -1393,13 +1376,10 @@ static int httpsrv_request(struct clientparam *param, struct httpreq *r)
creds[clen] = 0;
q = strchr(creds, ':');
- if(q){
- *q = 0;
- if(param->password) free(param->password);
- param->password = (unsigned char *)strdup(q + 1);
- }
- if(param->username) free(param->username);
- param->username = (unsigned char *)strdup(creds);
+ if(q) *q = 0;
+ /* credentials too long to keep are no credentials */
+ if((q && PARAMSTR(param, password, q + 1)) || PARAMSTR(param, username, creds))
+ *param->username = *param->password = 0;
}
else if(!strncasecmp(buf, "connection:", 11)){
sp = buf + 11;
@@ -1422,6 +1402,7 @@ static int httpsrv_request(struct clientparam *param, struct httpreq *r)
}
}
+ if(param->climark == -2) RETURN(710);
/* The headers ran past what this server reads, so the rest of the request
is still in the stream and there is no answering it: what follows would
be read as the request after this one. */
@@ -1453,8 +1434,7 @@ static int httpsrv_request(struct clientparam *param, struct httpreq *r)
if(colon) *colon = 0;
}
- if(param->hostname) free(param->hostname);
- param->hostname = (unsigned char *)strdup(host);
+ if(PARAMSTR(param, hostname, host)) RETURN(706);
}
/* The request is answered here, so the address it was sent to is the
@@ -1594,7 +1574,7 @@ void * httpsrvchild(struct clientparam *param)
answered = httpsrv_request(param, &r);
handoff = r.handoff;
- if(r.raw) free(r.raw);
+ param->climark = -1;
if(!answered) break;
/* Log the request the way the proxy does: the parameters decide
diff --git a/src/imapp.c b/src/imapp.c
index c3f3b0d..2d3d1d8 100644
--- a/src/imapp.c
+++ b/src/imapp.c
@@ -152,7 +152,7 @@ void * imappchild(struct clientparam* param) {
socksend(param, param->clisock, buf, (int)strlen((char *)buf), conf.timeouts[STRING_S]);
}
if(parseconnusername((char *)ub, param, 0, 143)){RETURN(694);}
- if(*pb && !param->password) param->password = (unsigned char *)strdup((char *)pb);
+ if(*pb && !*param->password && PARAMSTR(param, password, pb)){RETURN(694);}
param->operation = CONNECT;
res = (*param->srv->authfunc)(param);
if(res) {RETURN(res);}
@@ -227,7 +227,7 @@ void * imappchild(struct clientparam* param) {
RETURN (mapsocket(param, 180));
CLEANRET:
- if(param->hostname&¶m->extusername) {
+ if(*param->hostname&&*param->extusername) {
sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, (*SAPORT(¶m->sinsr)==143)?0:':', ntohs(*SAPORT(¶m->sinsr)));
dolog(param, buf);
}
diff --git a/src/log.c b/src/log.c
index 6749f25..74dd645 100644
--- a/src/log.c
+++ b/src/log.c
@@ -155,7 +155,7 @@ int dobuf2(struct clientparam * param, unsigned char * buf, const unsigned char
i+=5;
break;
case 'U':
- if(param->username && *param->username){
+ if(*param->username){
for(len = 0; i< 4000 && param->username[len]; len++){
buf[i] = param->username[len];
if(param->srv->nonprintable && (buf[i] < 0x20 || strchr((char *)param->srv->nonprintable, buf[i]))) buf[i] = param->srv->replace;
@@ -171,7 +171,7 @@ int dobuf2(struct clientparam * param, unsigned char * buf, const unsigned char
}
break;
case 'n':
- len = param->hostname? (int)strlen((char *)param->hostname) : 0;
+ len = (int)strlen((char *)param->hostname);
if (len > 0 && !strchr((char *)param->hostname, ':')) for(len = 0; param->hostname[len] && i < 4000; len++, i++){
buf[i] = param->hostname[len];
if(param->srv->nonprintable && (buf[i] < 0x20 || strchr((char *)param->srv->nonprintable, buf[i]))) buf[i] = param->srv->replace;
@@ -338,10 +338,12 @@ void lognone(struct clientparam * param, const unsigned char *s) {
clearstat(param);
}
-NOINLINE void logstdout(struct clientparam * param, const unsigned char *s) {
+void logstdout(struct clientparam * param, const unsigned char *s) {
FILE *log;
- unsigned char tmpbuf[8192];
+ unsigned char *tmpbuf;
+ /* with no connection, an error from the main thread */
+ tmpbuf = param? param->tmpbuf : logparam.tmpbuf;
dobuf(param, tmpbuf, s, NULL);
log = (param && param->srv && param->srv->stdlog)?param->srv->stdlog:conf.stdlog?conf.stdlog:stdout;
if(!param || !param->nolog)if(fprintf(log, "%s\n", tmpbuf) < 0) {
@@ -351,10 +353,8 @@ NOINLINE void logstdout(struct clientparam * param, const unsigned char *s) {
}
#ifndef _WIN32
void logsyslog(struct clientparam * param, const unsigned char *s) {
-
- unsigned char tmpbuf[8192];
- dobuf(param, tmpbuf, s, NULL);
- if(!param->nolog)syslog(LOG_INFO, "%s", tmpbuf);
+ dobuf(param, param->tmpbuf, s, NULL);
+ if(!param->nolog)syslog(LOG_INFO, "%s", param->tmpbuf);
}
#endif
diff --git a/src/pcre.c b/src/pcre.c
index 9c2fdc5..d98d78d 100644
--- a/src/pcre.c
+++ b/src/pcre.c
@@ -276,6 +276,7 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
int replen, num;
char * replace;
char * tmpbuf, *target, *newbuf;
+ unsigned char *given = *buf_p;
int nreplaces=0;
#define pcrefd ((struct pcre_filter_data *)fc)
@@ -358,7 +359,9 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
return CONTINUE;
}
memcpy(newbuf, *buf_p, ovector[0]);
- pl->freefunc(*buf_p);
+ /* The buffer given is the caller's to free; only one
+ made by an earlier replacement here is ours. */
+ if(*buf_p != given) pl->freefunc(*buf_p);
*buf_p = (unsigned char *)newbuf;
*bufsize_p = newsize;
}
diff --git a/src/plugins/LdapPlugin/ldapauth.c b/src/plugins/LdapPlugin/ldapauth.c
index c9ee40e..750f6e5 100644
--- a/src/plugins/LdapPlugin/ldapauth.c
+++ b/src/plugins/LdapPlugin/ldapauth.c
@@ -151,7 +151,7 @@ static int ldapfunc(struct clientparam *param)
char escuser[512];
/* test proxy user auth ------------------------*/
- if(!param->username || !param->password) return 4;
+ if(!*param->username || !*param->password) return 4;
if(strlen(param->password)==0) return 4;
/* init ldap ---------------------- */
diff --git a/src/plugins/PamAuth/pamauth.c b/src/plugins/PamAuth/pamauth.c
index 2430bd4..8ad1069 100644
--- a/src/plugins/PamAuth/pamauth.c
+++ b/src/plugins/PamAuth/pamauth.c
@@ -78,7 +78,7 @@ static int pamfunc(struct clientparam *param)
NULL };
/* test proxy user auth ------------------------*/
- if(!param->username || !param->password) return 4;
+ if(!*param->username || !*param->password) return 4;
/*if(strlen(param->password)==0) return 4;*/
#ifdef USERCASE
diff --git a/src/plugins/WindowsAuthentication/WindowsAuthentication.c b/src/plugins/WindowsAuthentication/WindowsAuthentication.c
index 7cd8994..2e42636 100644
--- a/src/plugins/WindowsAuthentication/WindowsAuthentication.c
+++ b/src/plugins/WindowsAuthentication/WindowsAuthentication.c
@@ -31,7 +31,7 @@ extern "C" {
PTOKEN_GROUPS ptg = (PTOKEN_GROUPS)tokenbuf;
- if(!param->username || !param->password || param->pwtype != 0) return 4;
+ if(!*param->username || !*param->password || param->pwtype != 0) return 4;
dom = strchr((char *)param->username, '\\');
if(dom)*dom++=0;
if(!LogonUser( dom?dom:(char *)param->username,
diff --git a/src/plugins/utf8tocp1251/utf8tocp1251.c b/src/plugins/utf8tocp1251/utf8tocp1251.c
index ba5ae18..fd24f63 100644
--- a/src/plugins/utf8tocp1251/utf8tocp1251.c
+++ b/src/plugins/utf8tocp1251/utf8tocp1251.c
@@ -54,7 +54,7 @@ unsigned char * conv_utf8_to_cp1251(unsigned char *s){
static int aufunc(struct clientparam *param){
- if(!param->username || !param->password || param->pwtype != 0) return 4;
+ if(!*param->username || !*param->password || param->pwtype != 0) return 4;
conv_utf8_to_cp1251(param->username);
conv_utf8_to_cp1251(param->password);
return 4;
diff --git a/src/pop3p.c b/src/pop3p.c
index ccd3a08..c915601 100644
--- a/src/pop3p.c
+++ b/src/pop3p.c
@@ -68,7 +68,7 @@ void * pop3pchild(struct clientparam* param) {
RETURN (mapsocket(param, 180));
CLEANRET:
- if(param->hostname&¶m->extusername) {
+ if(*param->hostname&&*param->extusername) {
sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, (*SAPORT(¶m->sinsr)==110)?0:':', ntohs(*SAPORT(¶m->sinsr)));
dolog(param, buf);
}
diff --git a/src/proxy.c b/src/proxy.c
index c8e7183..072c2cd 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -157,9 +157,11 @@ static int send_st(struct clientparam *param, int idx){
return socksend(param, param->clisock, (unsigned char *)proxy_stringtable[idx], pst_len(idx), conf.timeouts[STRING_S]);
}
+#ifndef WITHMAIN
/* Makes room in a buffer whose size is tracked. A filter may hand back one
holding exactly what it produced, so nothing may be added to it without
- asking for the room first. Returns 1 when the room cannot be had. */
+ asking for the room first; without filters, as in a proxy built on its
+ own, there is nothing to ask. Returns 1 when the room cannot be had. */
static int growbuf(unsigned char **buf, int *bufsize, int need){
unsigned char *newbuf;
@@ -171,6 +173,16 @@ static int growbuf(unsigned char **buf, int *bufsize, int need){
return 0;
}
+/* Reads a body of a known length into one buffer, to be filtered whole.
+ One bigger than the connection's own is had for it, up to filtermaxsize;
+ with no limit set a body is only read whole if it fits the buffer.
+ Returns how much is there, less than len if the body did not all come. */
+static uint64_t fillwhole(struct clientparam *param, DIRECTION which, uint64_t len){
+ if(conf.filtermaxsize && bufroom(param, which, (unsigned long)len)) return 0;
+ return sockfillbuf(param, which, (unsigned long)len, CONNECTION_S);
+}
+#endif
+
static void freeptr(void *p){
void **pp = (void **)p;
if(*pp) { free(*pp); *pp = NULL; }
@@ -467,16 +479,11 @@ for(;;){
sb = (unsigned char *)strchr((char *)username, ':');
if(sb){
*sb = 0;
- if(param->password)free(param->password);
- param->password = (unsigned char *)strdup((char *)sb+1);
param->pwtype = 0;
}
- else if(param->password){
- free(param->password);
- param->password = NULL;
- }
- if(param->username)free(param->username);
- param->username = (unsigned char *)strdup((char *)username);
+ /* credentials too long to keep are no credentials */
+ if(PARAMSTR(param, password, sb? sb+1 : NULL) || PARAMSTR(param, username, username))
+ *param->username = *param->password = 0;
continue;
}
}
@@ -512,11 +519,10 @@ for(;;){
c = *se;
*se = 0;
}
- if(param->hostname && (!*param->hostname || isnumber(param->hostname[strlen((char *)param->hostname) - 1]))){
- free(param->hostname);
- param->hostname = NULL;
+ if(*param->hostname && isnumber(param->hostname[strlen((char *)param->hostname) - 1])){
+ *param->hostname = 0;
}
- if(!param->hostname){
+ if(!*param->hostname){
if(parsehostname((char *)sb, param, 80)) RETURN(100);
}
newbuf = malloc(strlen((char *)req) + strlen((char *)(buf+inbuf)) + 8);
@@ -543,17 +549,9 @@ for(;;){
if(i<=0)continue;
username[i] = 0;
sb = (unsigned char *)strchr((char *)username, ':');
- if(sb){
- *sb = 0;
- if(param->extpassword)free(param->extpassword);
- param->extpassword = (unsigned char *)strdup((char *)sb+1);
- }
- else if(param->extpassword){
- free(param->extpassword);
- param->extpassword = NULL;
- }
- if(param->extusername)free(param->extusername);
- param->extusername = (unsigned char *)strdup((char *)username);
+ if(sb) *sb = 0;
+ if(PARAMSTR(param, extpassword, sb? sb+1 : NULL) || PARAMSTR(param, extusername, username))
+ *param->extusername = *param->extpassword = 0;
continue;
}
}
@@ -606,7 +604,7 @@ for(;;){
#endif
- if(param->srv->needuser > 1 && !param->username) {RETURN(4);}
+ if(param->srv->needuser > 1 && !*param->username) {RETURN(4);}
if((res = (*param->srv->authfunc)(param))) {
if (res <= 10 || haveconnection || param->transparent) RETURN(res);
param->srv->so._closesocket(param->sostate, param->remsock);
@@ -698,7 +696,7 @@ for(;;){
}
else if(param->ndatfilterscli > 0 && contentlength64 > 0 && contentlength64 == (uint64_t)(unsigned long)contentlength64){
uint64_t newlen64;
- newlen64 = (uint64_t) sockfillbuffcli(param, (unsigned long)contentlength64, CONNECTION_S);
+ newlen64 = fillwhole(param, CLIENT, contentlength64);
if(newlen64 == contentlength64) {
action = handledatfltcli(param, ¶m->clibuf, (int *)¶m->clibufsize, 0, (int *)¶m->cliinbuf);
if(action == HANDLED){
@@ -1025,9 +1023,9 @@ for(;;){
if(keepalive <= 1) {
hlen += sprintf((char*)buf + hlen, "Connection: %s\r\n", keepalive? "keep-alive":"close");
}
- if(param->extusername){
+ if(*param->extusername){
hlen += sprintf((char*)buf + hlen, "%s: Basic ", (redirect)?"Proxy-Authorization":"Authorization");
- sprintf((char*)username, "%.128s:%.128s", param->extusername, param->extpassword?param->extpassword:(unsigned char*)"");
+ sprintf((char*)username, "%.128s:%.128s", param->extusername, param->extpassword);
if(!(sb = en64(username, buf + hlen, (int)strlen((char *)username), bufsize - hlen))) {RETURN(21);}
hlen = (int)(sb - buf);
hlen += sprintf((char*)buf + hlen, "\r\n");
@@ -1198,7 +1196,7 @@ for(;;){
}
else if(param->ndatfilterssrv > 0 && contentlength64 > 0 && contentlength64 == (uint64_t)(unsigned long)contentlength64 && param->operation != HTTP_HEAD && res != 204 && res != 304){
uint64_t newlen;
- newlen = (uint64_t)sockfillbuffsrv(param, (unsigned long) contentlength64, CONNECTION_S);
+ newlen = fillwhole(param, SERVER, contentlength64);
if(newlen == contentlength64) {
action = handlepredatflt(param);
if(action == HANDLED){
diff --git a/src/proxy.h b/src/proxy.h
index 1197254..8e0e88a 100644
--- a/src/proxy.h
+++ b/src/proxy.h
@@ -22,6 +22,7 @@
#endif
#endif
#include
+#include
#include
#include
#include
@@ -36,8 +37,9 @@
#define MAXNSERVERS 5
#define DEFAULT_MAXCHILD 500
-#define TCPBUFSIZE 65536
-#define SRVBUFSIZE (param->srv->bufsize?param->srv->bufsize:((param->service == S_UDPPM)?UDPBUFSIZE:TCPBUFSIZE))
+/* How much of a connection's buffer is read into at once: all of it, or
+ less if the service was told so with -b. */
+#define SRVBUFSIZE(srv) (((srv)->bufsize > 0 && (srv)->bufsize < CLIENTBUFSIZE)? (unsigned)(srv)->bufsize : CLIENTBUFSIZE)
#ifdef _WIN32
@@ -116,17 +118,6 @@ void daemonize(void);
#endif
#endif
-/* Keeps a callee with a large frame out of the caller's frame, e.g. the
- 8K log buffer of logstdout() out of dolog(), which calls it in a branch
- taken only when there is no service.
- */
-#if defined(__GNUC__)
-#define NOINLINE __attribute__((noinline))
-#elif defined(_MSC_VER)
-#define NOINLINE __declspec(noinline)
-#else
-#define NOINLINE
-#endif
/* Thread stack size, stacksize command value is added to it. BSD libc uses
significantly more stack, e.g. in vfprintf() called by syslog().
@@ -258,8 +249,12 @@ int sockrecvfrom(struct clientparam *param, SOCKET sock, struct sockaddr * sin,
int sockgetcharcli(struct clientparam * param, int timeosec, int timeousec);
int sockgetcharsrv(struct clientparam * param, int timeosec, int timeousec);
-unsigned long sockfillbuffcli(struct clientparam * param, unsigned long size, int timeosec);
-unsigned long sockfillbuffsrv(struct clientparam * param, unsigned long size, int timeosec);
+unsigned long sockfillbuf(struct clientparam * param, DIRECTION which, unsigned long size, int timeosec);
+int bufroom(struct clientparam * param, DIRECTION which, unsigned long size);
+int paramstr(unsigned char *field, size_t size, const unsigned char *s);
+/* sets one of a connection's names or credentials; 1 if it is too long */
+#define PARAMSTR(p, f, s) paramstr((p)->f, sizeof((p)->f), (const unsigned char *)(s))
+void bufrelease(struct clientparam * param, DIRECTION which);
int sockgetlinebuf(struct clientparam * param, DIRECTION which, unsigned char * buf, int bufsize, int delim, int to);
int getmultiline(struct clientparam * param, DIRECTION which, unsigned char * buf, int bufsize, const char *cap, int *found);
@@ -272,7 +267,7 @@ void dolog(struct clientparam * param, const unsigned char *s);
int dobuf(struct clientparam * param, unsigned char * buf, const unsigned char *s, const unsigned char * doublec);
int dobuf2(struct clientparam * param, unsigned char * buf, const unsigned char *s, const unsigned char * doublec, struct tm* tm, char * format);
extern FILE * stdlog;
-NOINLINE void logstdout(struct clientparam * param, const unsigned char *s);
+void logstdout(struct clientparam * param, const unsigned char *s);
void logsyslog(struct clientparam * param, const unsigned char *s);
void lognone(struct clientparam * param, const unsigned char *s);
void logradius(struct clientparam * param, const unsigned char *s);
@@ -387,7 +382,7 @@ void freefilter(struct filter *filter);
void freeconf(struct extparam *confp);
struct passwords * copypwl (struct passwords *pwl);
void freepwl(struct passwords *pw);
-void copyfilter(struct filter *, struct srvparam *srv);
+int copyfilter(struct filter *, struct srvparam *srv);
FILTER_ACTION makefilters (struct srvparam *srv, struct clientparam *param);
FILTER_ACTION handlereqfilters(struct clientparam *param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p);
FILTER_ACTION handleconnectflt(struct clientparam *param);
@@ -417,7 +412,6 @@ void pcre_pattern_free(void *re);
int pcre_pattern_match(void *re, const unsigned char *subject, struct capture *caps, int maxcaps);
#endif
-int pushbackcli(struct clientparam * param, const unsigned char * data, int len);
int parsepattern(struct hostname *h, unsigned char *arg);
int parsepathpattern(struct hostname *h, unsigned char *arg);
int patternmatchcaps(const struct hostname *h, const unsigned char *str,
diff --git a/src/proxymain.c b/src/proxymain.c
index d5904ce..e4b5934 100644
--- a/src/proxymain.c
+++ b/src/proxymain.c
@@ -312,7 +312,6 @@ struct srvstart {
/* Releases what the preparation and the run took, s itself excepted. */
static void srvdiscard(struct srvstart *s){
srvfree(&s->srv);
- if(s->defparam.hostname) free(s->defparam.hostname);
if(s->cbc_string) free(s->cbc_string);
if(s->cbl_string) free(s->cbl_string);
if(s->fp) fclose(s->fp);
@@ -751,7 +750,7 @@ static int srvprepare(struct srvstart *s, int argc, char **argv){
#ifndef STDMAIN
- copyfilter(conf.filters, srv);
+ if((error = copyfilter(conf.filters, srv))) return error;
#endif
return 0;
}
@@ -1055,8 +1054,10 @@ static int srvspawn(struct srvstart *s, SOCKET client_sock){
usleep(SLEEPTIME);
return 1;
};
- *newparam = *defparam;
- if(defparam->hostname)newparam->hostname=(unsigned char *)strdup((char *)defparam->hostname);
+ memcpy(newparam, defparam, offsetof(struct clientparam, filters));
+ newparam->clibuf = newparam->clibufdata;
+ newparam->srvbuf = newparam->srvbufdata;
+ newparam->clibufsize = newparam->srvbufsize = SRVBUFSIZE(srv);
clearstat(newparam);
if(!s->isudp) newparam->clisock = client_sock;
newparam->prev = newparam->next = NULL;
@@ -1431,6 +1432,7 @@ void srvinit(struct srvparam * srv, struct clientparam *param){
param->paused = srv->paused;
param->remsock = param->clisock = param->ctrlsock = param->ctrlsocksrv = INVALID_SOCKET;
param->pipecli[0] = param->pipecli[1] = param->pipesrv[0] = param->pipesrv[1] = -1;
+ param->climark = -1;
*SAFAMILY(¶m->req) = *SAFAMILY(¶m->sinsl) = *SAFAMILY(¶m->sinsr) = *SAFAMILY(¶m->sincr) = *SAFAMILY(¶m->sincl) = AF_INET;
_3proxy_mutex_init(&srv->counter_mutex);
(void)_3proxy_sem_init_timed(srv->childslots, srv->maxchild, srv->maxchild);
@@ -1551,8 +1553,8 @@ void freeparam(struct clientparam * param) {
}
#endif
}
- if(param->clibuf) free(param->clibuf);
- if(param->srvbuf) free(param->srvbuf);
+ if(param->clibuf != param->clibufdata) free(param->clibuf);
+ if(param->srvbuf != param->srvbufdata) free(param->srvbuf);
#ifdef WITHSPLICE
if(param->pipecli[0] >= 0) close(param->pipecli[0]);
if(param->pipecli[1] >= 0) close(param->pipecli[1]);
@@ -1590,21 +1592,11 @@ void freeparam(struct clientparam * param) {
param->srv->so._closesocket(param->sostate, param->clisock);
}
}
- if(param->datfilterssrv) free(param->datfilterssrv);
#ifndef STDMAIN
- if(param->reqfilters) free(param->reqfilters);
- if(param->connectfilters) free(param->connectfilters);
- if(param->afterauthfilters) free(param->afterauthfilters);
- if(param->hdrfilterscli) free(param->hdrfilterscli);
- if(param->hdrfilterssrv) free(param->hdrfilterssrv);
- if(param->predatfilters) free(param->predatfilters);
- if(param->datfilterscli) free(param->datfilterscli);
- if(param->filters){
- if(param->nfilters)while(param->nfilters--){
- if(param->filters[param->nfilters].filter->filter_clear)
- (*param->filters[param->nfilters].filter->filter_clear)(param->filters[param->nfilters].data);
- }
- free(param->filters);
+ while(param->nfilters > 0){
+ param->nfilters--;
+ if(param->filters[param->nfilters].filter->filter_clear)
+ (*param->filters[param->nfilters].filter->filter_clear)(param->filters[param->nfilters].data);
}
if(param->connlim) stopconnlims(param);
#endif
@@ -1629,11 +1621,6 @@ void freeparam(struct clientparam * param) {
}
_3proxy_mutex_unlock(¶m->srv->counter_mutex);
}
- if(param->hostname) free(param->hostname);
- if(param->username) free(param->username);
- if(param->password) free(param->password);
- if(param->extusername) free(param->extusername);
- if(param->extpassword) free(param->extpassword);
free(param);
}
@@ -1651,6 +1638,18 @@ FILTER_ACTION handleconnectflt(struct clientparam *cparam){
}
+/* A buffer filter given a buffer too small for what it makes of it hands
+ back one of its own, allocated with malloc, and leaves the one it was given
+ alone: nothing refers to that one any more, so it is freed here, unless it
+ is one of the connection's own buffers. The caller owns whatever *buf_p
+ points to on return. */
+static void filterswap(struct clientparam *param, unsigned char **cur, unsigned char *now){
+ if(now != *cur){
+ if(*cur != param->clibufdata && *cur != param->srvbufdata && *cur != param->tmpbuf) free(*cur);
+ *cur = now;
+ }
+}
+
#ifndef STDMAIN
static void * itcopy (void * from, size_t size){
void * ret;
@@ -1817,18 +1816,25 @@ ERRORNEXT:
}
-void copyfilter (struct filter *filter, struct srvparam *srv){
+/* Returns 2 when out of memory, 3 when there are more filters than a
+ connection has room for: a service started without some of its filters
+ could pass what one of them was there to stop. */
+int copyfilter (struct filter *filter, struct srvparam *srv){
int nfilters = 0;
- if(!filter) return;
+ if(!filter) return 0;
for(srv->filter = filter; srv->filter; srv->filter = srv->filter->next) nfilters++;
srv->filter = malloc(sizeof(struct filter) * nfilters);
- if(!srv->filter) return;
+ if(!srv->filter) return 2;
for(; filter; filter = filter->next){
void *data = NULL;
if(!filter->filter_open || !(data = (*filter->filter_open)(filter->data, srv))) continue;
+ if(srv->nfilters >= MAX_FILTERS){
+ if(filter->filter_close) (*filter->filter_close)(data);
+ return 3;
+ }
srv->filter[srv->nfilters] = *filter;
srv->filter[srv->nfilters].data = data;
@@ -1843,6 +1849,7 @@ void copyfilter (struct filter *filter, struct srvparam *srv){
if(filter->filter_data_srv)srv->ndatfilterssrv++;
if(filter->filter_data_cli)srv->ndatfilterscli++;
}
+ return 0;
}
FILTER_ACTION makefilters (struct srvparam *srv, struct clientparam *param){
@@ -1852,20 +1859,6 @@ FILTER_ACTION makefilters (struct srvparam *srv, struct clientparam *param){
if(!srv->nfilters) return PASS;
- if(!(param->filters = malloc(sizeof(struct filterp) * srv->nfilters)) ||
- (srv->nreqfilters && !(param->reqfilters = malloc(sizeof(struct filterp *) * srv->nreqfilters))) ||
- (srv->nconnectfilters && !(param->connectfilters = malloc(sizeof(struct filterp *) * srv->nconnectfilters))) ||
- (srv->nafterauthfilters && !(param->afterauthfilters = malloc(sizeof(struct filterp *) * srv->nafterauthfilters))) ||
- (srv->nhdrfilterssrv && !(param->hdrfilterssrv = malloc(sizeof(struct filterp *) * srv->nhdrfilterssrv))) ||
- (srv->nhdrfilterscli && !(param->hdrfilterscli = malloc(sizeof(struct filterp *) * srv->nhdrfilterscli))) ||
- (srv->npredatfilters && !(param->predatfilters = malloc(sizeof(struct filterp *) * srv->npredatfilters))) ||
- (srv->ndatfilterssrv && !(param->datfilterssrv = malloc(sizeof(struct filterp *) * srv->ndatfilterssrv))) ||
- (srv->ndatfilterscli && !(param->datfilterscli = malloc(sizeof(struct filterp *) * srv->ndatfilterscli)))
- ){
- param->res = 21;
- return REJECT;
- }
-
for(i=0; infilters; i++){
if(!srv->filter[i].filter_client)continue;
action = (*srv->filter[i].filter_client)(srv->filter[i].data, param, ¶m->filters[param->nfilters].data);
@@ -1937,9 +1930,11 @@ FILTER_ACTION handleafterauthflt(struct clientparam *cparam){
FILTER_ACTION handlereqfilters(struct clientparam *param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){
FILTER_ACTION action;
int i;
+ unsigned char *cur = *buf_p;
for(i=0; inreqfilters; i++){
action = (*param->reqfilters[i]->filter->filter_request)(param->reqfilters[i]->data, param, buf_p, bufsize_p, offset, length_p);
+ filterswap(param, &cur, *buf_p);
if(action!=CONTINUE) return action;
}
return PASS;
@@ -1948,9 +1943,11 @@ FILTER_ACTION handlereqfilters(struct clientparam *param, unsigned char ** buf_p
FILTER_ACTION handlehdrfilterssrv(struct clientparam *param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){
FILTER_ACTION action;
int i;
+ unsigned char *cur = *buf_p;
for(i=0; inhdrfilterssrv; i++){
action = (*param->hdrfilterssrv[i]->filter->filter_header_srv)(param->hdrfilterssrv[i]->data, param, buf_p, bufsize_p, offset, length_p);
+ filterswap(param, &cur, *buf_p);
if(action!=CONTINUE) return action;
}
return PASS;
@@ -1959,9 +1956,11 @@ FILTER_ACTION handlehdrfilterssrv(struct clientparam *param, unsigned char ** bu
FILTER_ACTION handlehdrfilterscli(struct clientparam *param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){
FILTER_ACTION action;
int i;
+ unsigned char *cur = *buf_p;
for(i = 0; i < param->nhdrfilterscli; i++){
action = (*param->hdrfilterscli[i]->filter->filter_header_cli)(param->hdrfilterscli[i]->data, param, buf_p, bufsize_p, offset, length_p);
+ filterswap(param, &cur, *buf_p);
if(action!=CONTINUE) return action;
}
return PASS;
@@ -1988,9 +1987,11 @@ FILTER_ACTION handledatfltcli(struct clientparam *cparam, unsigned char ** buf_p
#ifndef STDMAIN
FILTER_ACTION action;
int i;
+ unsigned char *cur = *buf_p;
for(i=0; indatfilterscli ;i++){
action = (*cparam->datfilterscli[i]->filter->filter_data_cli)(cparam->datfilterscli[i]->data, cparam, buf_p, bufsize_p, offset, length_p);
+ filterswap(cparam, &cur, *buf_p);
if(action!=CONTINUE) return action;
}
#endif
@@ -2000,9 +2001,11 @@ FILTER_ACTION handledatfltcli(struct clientparam *cparam, unsigned char ** buf_p
FILTER_ACTION handledatfltsrv(struct clientparam *cparam, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){
FILTER_ACTION action;
int i;
+ unsigned char *cur = *buf_p;
for(i=0; indatfilterssrv; i++){
action = (*cparam->datfilterssrv[i]->filter->filter_data_srv)(cparam->datfilterssrv[i]->data, cparam, buf_p, bufsize_p, offset, length_p);
+ filterswap(cparam, &cur, *buf_p);
if(action!=CONTINUE) return action;
}
return PASS;
diff --git a/src/redirect.c b/src/redirect.c
index bb98534..955a8f6 100644
--- a/src/redirect.c
+++ b/src/redirect.c
@@ -26,16 +26,11 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc
user = redir->extuser;
pass = redir->extpass;
- if (!param->srvbufsize){
- param->srvbufsize = SRVBUFSIZE;
- param->srvbuf = malloc(param->srvbufsize);
- if(!param->srvbuf) return 21;
- }
buf = param->srvbuf;
username = buf + 2048;
if(user) {
if (*user == '*') {
- if(!param->username) return 4;
+ if(!*param->username) return 4;
user = param->username;
pass = param->password;
}
@@ -415,15 +410,9 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
else if(SAISNULL(&cur->addr) && !*SAPORT(&cur->addr)){
int i;
if(cur->extuser){
- if(param->extusername)
- free(param->extusername);
- param->extusername = (unsigned char *)strdup((char *)((*cur->extuser == '*' && param->username)? param->username : cur->extuser));
- if(cur->extpass){
- if(param->extpassword)
- free(param->extpassword);
- param->extpassword = (unsigned char *)strdup((char *)((*cur->extuser == '*' && param->password)?param->password : cur->extpass));
- }
- if(*cur->extuser == '*' && !param->username) return 4;
+ if(*cur->extuser == '*' && !*param->username) return 4;
+ if(PARAMSTR(param, extusername, (*cur->extuser == '*')? param->username : cur->extuser)) return 21;
+ if(cur->extpass && PARAMSTR(param, extpassword, (*cur->extuser == '*' && *param->password)?param->password : cur->extpass)) return 21;
}
for(i=0; redirs[i].name; i++){
@@ -490,15 +479,9 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
param->redirtype = redir->type;
if(redir->type == R_TCP || redir->type ==R_HTTP) {
if(cur->extuser){
- if(*cur -> extuser == '*' && !param->username) return 4;
- if(param->extusername)
- free(param->extusername);
- param->extusername = (unsigned char *)strdup((char *)((*cur->extuser == '*' && param->username)? param->username : cur->extuser));
- if(cur->extpass){
- if(param->extpassword)
- free(param->extpassword);
- param->extpassword = (unsigned char *)strdup((char *)((*cur->extuser == '*' && param->password)?param->password : cur->extpass));
- }
+ if(*cur -> extuser == '*' && !*param->username) return 4;
+ if(PARAMSTR(param, extusername, (*cur->extuser == '*')? param->username : cur->extuser)) return 21;
+ if(cur->extpass && PARAMSTR(param, extpassword, (*cur->extuser == '*' && *param->password)?param->password : cur->extpass)) return 21;
}
if(redir->secure) return ssl_parent(param);
return 0;
@@ -507,7 +490,7 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
}
if(!connected || !redir) return 0;
- res = clientnegotiate(redir, param, (struct sockaddr *)¶m->req, param->hostname);
+ res = clientnegotiate(redir, param, (struct sockaddr *)¶m->req, *param->hostname? param->hostname : NULL);
if(res) parentfail(param, redir);
if(saved){
SOCKET s;
diff --git a/src/resolve.c b/src/resolve.c
index 5b9da88..4b296a8 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -201,9 +201,9 @@ uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_
s2 = s1;
}
*s2 = 0;
- if(param->username)free(param->username);
- param->username = (unsigned char *)strdup ((char *)buf + k + 13);
-
+ /* a name longer than the field is no name to authenticate */
+ if(PARAMSTR(param, username, buf + k + 13)) return 0;
+
return udpresolve(af,param->username, value, NULL, NULL, 2);
}
}
diff --git a/src/smtpp.c b/src/smtpp.c
index 6bde921..dfb3d26 100644
--- a/src/smtpp.c
+++ b/src/smtpp.c
@@ -33,26 +33,26 @@ int readreply (struct clientparam* param) {
unsigned char * buf;
int res, i, bufsize = 640;
- if(!(buf = malloc(bufsize))) return 0;
+ buf = param->tmpbuf; /* a filter may replace it with one of its own */
do {
i = sockgetlinebuf(param, SERVER, buf, bufsize-1, '\n', conf.timeouts[STRING_L]);
if(i < 1) break;
#ifndef WITHMAIN
res = handlehdrfilterssrv(param, &buf, &bufsize, 0, &i);
if(res != PASS) {
- free(buf);
+ if(buf != param->tmpbuf) free(buf);
return -1;
}
#endif
socksend(param, param->clisock, buf, i, conf.timeouts[STRING_S]);
} while (i > 3 && buf[3] == '-');
if(i < 3) {
- free(buf);
+ if(buf != param->tmpbuf) free(buf);
return 0;
}
buf[i] = 0;
res = atoi((char *)buf);
- free(buf);
+ if(buf != param->tmpbuf) free(buf);
return res;
}
@@ -64,14 +64,14 @@ int readcommand (struct clientparam* param) {
#endif
int ret = 1;
- if(!(buf = malloc(bufsize))) return 0;
+ buf = param->tmpbuf; /* a filter may replace it with one of its own */
i = sockgetlinebuf(param, CLIENT, buf, bufsize-1, '\n', conf.timeouts[STRING_L]);
if(i < 4) return 0;
#ifndef WITHMAIN
if(!strncasecmp((char *)buf, "MAIL", 4) || !strncasecmp((char *)buf, "RCPT", 4) || !strncasecmp((char *)buf, "STARTTLS", 8) || !strncasecmp((char *)buf, "TURN", 4)){
res = handlehdrfilterscli(param, &buf, &bufsize, 0, &i);
if(res != PASS) {
- free(buf);
+ if(buf != param->tmpbuf) free(buf);
if(res == HANDLED) return 2;
return -1;
}
@@ -81,7 +81,7 @@ int readcommand (struct clientparam* param) {
if(!strncasecmp((char *)buf, "STARTTLS", 8) || !strncasecmp((char *)buf, "TURN", 4)){
ret = 22;
}
- free(buf);
+ if(buf != param->tmpbuf) free(buf);
return ret;
}
@@ -92,12 +92,12 @@ int readdata (struct clientparam* param) {
int res;
#endif
- if(!(buf = malloc(bufsize))) return 0;
+ buf = param->tmpbuf; /* a filter may replace it with one of its own */
while ((i = sockgetlinebuf(param, CLIENT, buf, bufsize-1, '\n', conf.timeouts[STRING_L])) > 0 && !(i==3 && buf[0] == '.')){
#ifndef WITHMAIN
res = handledatfltcli(param, &buf, &bufsize, 0, &i);
if(res != PASS) {
- free(buf);
+ if(buf != param->tmpbuf) free(buf);
if(res == HANDLED) return 1;
return -1;
}
@@ -105,11 +105,11 @@ int readdata (struct clientparam* param) {
socksend(param, param->remsock, buf, i, conf.timeouts[STRING_S]);
}
if(i < 1) {
- free(buf);
+ if(buf != param->tmpbuf) free(buf);
return 0;
}
socksend(param, param->remsock, buf, i, conf.timeouts[STRING_S]);
- free(buf);
+ if(buf != param->tmpbuf) free(buf);
return 1;
}
@@ -143,7 +143,7 @@ void * smtppchild(struct clientparam* param) {
return (void *)tlsprchild;
}
#endif
- else if(!param->hostname) socksend(param, param->clisock, (unsigned char *)"571 need AUTH first\r\n", 22, conf.timeouts[STRING_S]);
+ else if(!*param->hostname) socksend(param, param->clisock, (unsigned char *)"571 need AUTH first\r\n", 22, conf.timeouts[STRING_S]);
else {
login = -1;
buf[i] = 0;
@@ -172,8 +172,7 @@ void * smtppchild(struct clientparam* param) {
i = de64(buf,username,255);
if(i < 0) {RETURN(666);}
username[i] = 0;
- if(param->extpassword) free(param->extpassword);
- param->extpassword = (unsigned char *)strdup((char *)username);
+ if(PARAMSTR(param, extpassword, username)) {RETURN(666);}
}
else if(login == 2){
if(i > 13) {
@@ -192,16 +191,23 @@ void * smtppchild(struct clientparam* param) {
if(parseconnusername((char *)username+1, param, 0, 587)) {RETURN(670);}
res = (int)strlen((char *)username+1) + 2;
if(res < i){
- if(param->extpassword) free(param->extpassword);
- param->extpassword = (unsigned char *)strdup((char *)username + res);
+ if(PARAMSTR(param, extpassword, username + res)) {RETURN(670);}
}
}
#ifndef WITHMAIN
{
+ /* the host is filtered as a request, in the scratch buffer, where a
+ filter may also hand back a buffer of its own */
int action, reqbufsize, reqsize;
- reqbufsize = reqsize = (int)strlen((char *)param->hostname) + 1;
- action = handlereqfilters(param, ¶m->hostname, &reqbufsize, 0, &reqsize);
+ unsigned char *req = param->tmpbuf;
+
+ reqsize = (int)strlen((char *)param->hostname) + 1;
+ reqbufsize = CLIENTTMPBUFSIZE;
+ memcpy(req, param->hostname, reqsize);
+ action = handlereqfilters(param, &req, &reqbufsize, 0, &reqsize);
+ if(action == PASS && PARAMSTR(param, hostname, req)) action = REJECT;
+ if(req != param->tmpbuf) free(req);
if(action == HANDLED){
RETURN(0);
}
@@ -232,8 +238,8 @@ void * smtppchild(struct clientparam* param) {
} while (i > 3 && buf[3] == '-');
if(i<3) {RETURN(672);}
- if(!command || (param->extusername && param->extpassword)){
- if(!param->extusername || !*param->extusername || !param->extpassword || !*param->extpassword || !login){
+ if(!command || (*param->extusername && *param->extpassword)){
+ if(!*param->extusername || !*param->extpassword || !login){
socksend(param, param->clisock, (unsigned char *)"235 auth required\r\n", 19,conf.timeouts[STRING_S]);
}
if ((login & 1)) {
@@ -285,9 +291,9 @@ void * smtppchild(struct clientparam* param) {
res = 1;
#ifndef WITHMAIN
if(!strncasecmp(command, "MAIL", 4) || !strncasecmp(command, "RCPT", 4) || !strncasecmp(command, "STARTTLS", 8) || !strncasecmp(command, "TURN", 4)){
- res = (int)strlen(command);
- command[res] = 0;
- res = handlehdrfilterscli(param, (unsigned char **)&command, &res, 0, &res);
+ int clen = (int)strlen(command), csize = clen + 1;
+
+ res = handlehdrfilterscli(param, (unsigned char **)&command, &csize, 0, &clen);
if(res != PASS) {
if(res == HANDLED) res = 2;
else RETURN(677);
@@ -321,7 +327,7 @@ void * smtppchild(struct clientparam* param) {
CLEANRET:
- if(param->hostname&¶m->extusername) {
+ if(*param->hostname&&*param->extusername) {
sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, *SAPORT(¶m->sinsr)==587?0:':',ntohs(*SAPORT(¶m->sinsr)));
dolog(param, buf);
}
diff --git a/src/sockgetchar.c b/src/sockgetchar.c
index 076cb51..4e18630 100644
--- a/src/sockgetchar.c
+++ b/src/sockgetchar.c
@@ -70,112 +70,122 @@ int sockrecvfrom(struct clientparam *param, SOCKET sock, struct sockaddr * sin,
return res;
}
-int sockgetcharcli(struct clientparam * param, int timeosec, int timeousec){
- int len;
-
- if(!param->clibuf){
- if(!(param->clibuf = malloc(SRVBUFSIZE))) return 0;
- param->clibufsize = SRVBUFSIZE;
- param->clioffset = param->cliinbuf = 0;
+/* Starts an empty buffer over from its beginning, and goes back to the
+ connection's own buffer if a filter needed a bigger one. Does nothing
+ while anything is left unread. */
+void bufrelease(struct clientparam * param, DIRECTION which){
+ if(which){
+ if(param->srvinbuf != param->srvoffset) return;
+ param->srvinbuf = param->srvoffset = 0;
+ if(param->srvbuf == param->srvbufdata) return;
+ free(param->srvbuf);
+ param->srvbuf = param->srvbufdata;
+ param->srvbufsize = SRVBUFSIZE(param->srv);
}
- if(param->cliinbuf && param->clioffset < param->cliinbuf){
- return (int)param->clibuf[param->clioffset++];
+ else {
+ if(param->cliinbuf != param->clioffset) return;
+ param->cliinbuf = param->clioffset = 0;
+ if(param->clibuf == param->clibufdata) return;
+ free(param->clibuf);
+ param->clibuf = param->clibufdata;
+ param->clibufsize = SRVBUFSIZE(param->srv);
}
- param->clioffset = param->cliinbuf = 0;
- if ((len = sockrecvfrom(param, param->clisock, (struct sockaddr *)¶m->sincr, param->clibuf, param->clibufsize, timeosec*1000 + timeousec))<=0) return EOF;
- param->cliinbuf = len;
- param->clioffset = 1;
- return (int)*param->clibuf;
}
-/* Put bytes back in front of whatever the client has not been read yet, so a
- service which has already taken a request off the socket can hand it to
- another one, which reads it the way it reads anything else. */
-int pushbackcli(struct clientparam * param, const unsigned char * data, int len){
- unsigned left = 0;
- unsigned need;
+/* Makes room for size bytes from the start of what is unread, which is
+ moved there: a body to be filtered whole is read into one buffer, which
+ may have to be bigger than the connection's own. Returns 1 when that
+ much cannot be had. */
+int bufroom(struct clientparam * param, DIRECTION which, unsigned long size){
+ unsigned char **buf = which? ¶m->srvbuf : ¶m->clibuf;
+ unsigned char *own = which? param->srvbufdata : param->clibufdata;
+ unsigned *inbuf = which? ¶m->srvinbuf : ¶m->cliinbuf;
+ unsigned *offset = which? ¶m->srvoffset : ¶m->clioffset;
+ unsigned *bufsize = which? ¶m->srvbufsize : ¶m->clibufsize;
+ unsigned left = *inbuf - *offset;
+ unsigned char *nb;
- if(len <= 0) return 0;
- if(param->clibuf) left = param->cliinbuf - param->clioffset;
- need = (unsigned)len + left;
-
- if(!param->clibuf){
- if(!(param->clibuf = malloc(need > SRVBUFSIZE? need : SRVBUFSIZE))) return 1;
- param->clibufsize = need > SRVBUFSIZE? need : SRVBUFSIZE;
+ if(*offset){
+ memmove(*buf, *buf + *offset, left);
+ *inbuf = left;
+ *offset = 0;
}
- else if(param->clibufsize < need){
- unsigned char *nb = realloc(param->clibuf, need);
-
- if(!nb) return 1;
- param->clibuf = nb;
- param->clibufsize = need;
- }
- if(left) memmove(param->clibuf + len, param->clibuf + param->clioffset, left);
- memcpy(param->clibuf, data, (size_t)len);
- param->clioffset = 0;
- param->cliinbuf = need;
+ if(size <= *bufsize) return 0;
+ if((unsigned long)(unsigned)size != size || !(nb = malloc(size))) return 1;
+ memcpy(nb, *buf, left);
+ if(*buf != own) free(*buf);
+ *buf = nb;
+ *bufsize = (unsigned)size;
return 0;
}
-unsigned long sockfillbuffcli(struct clientparam * param, unsigned long size, int timeosec){
+int sockgetcharcli(struct clientparam * param, int timeosec, int timeousec){
int len;
+ unsigned keep = 0;
- if(!param->clibuf) return 0;
- if(param->cliinbuf == param->clioffset){
- param->cliinbuf = param->clioffset = 0;
+ if(param->cliinbuf && param->clioffset < param->cliinbuf){
+ return (int)param->clibuf[param->clioffset++];
}
- else if(param->clioffset){
- memmove(param->clibuf, param->clibuf + param->clioffset, param->cliinbuf - param->clioffset);
- param->cliinbuf -= param->clioffset;
- param->clioffset = 0;
+ if(param->climark == -2) return EOF; /* nothing more until it is cleared */
+ if(param->climark >= 0){
+ /* what was read since the mark stays, moved to the start */
+ keep = param->cliinbuf - (unsigned)param->climark;
+ if(param->climark) memmove(param->clibuf, param->clibuf + param->climark, keep);
+ param->climark = 0;
+ param->clioffset = param->cliinbuf = keep;
+ if(keep >= param->clibufsize){
+ param->climark = -2;
+ return EOF;
+ }
}
- if(size <= param->cliinbuf) return size;
- size -= param->cliinbuf;
- if((len = sockrecvfrom(param, param->clisock, (struct sockaddr *)¶m->sincr, param->clibuf + param->cliinbuf, (param->clibufsize - param->cliinbuf) < size? param->clibufsize - param->cliinbuf:size, timeosec*1000)) > 0){
- param->cliinbuf += len;
- }
- return param->cliinbuf;
+ else bufrelease(param, CLIENT);
+ if ((len = sockrecvfrom(param, param->clisock, (struct sockaddr *)¶m->sincr, param->clibuf + keep, param->clibufsize - keep, timeosec*1000 + timeousec))<=0) return EOF;
+ param->cliinbuf = keep + len;
+ param->clioffset = keep + 1;
+ return (int)param->clibuf[keep];
}
-unsigned long sockfillbuffsrv(struct clientparam * param, unsigned long size, int timeosec){
+/* Waits until size bytes are in the buffer, from its start, without taking
+ them: for a look at what comes before it is read the usual way, or for
+ something which has to be had whole. Stops short at the end of the
+ buffer, at the end of the stream, or when nothing comes in time; returns
+ how much is there, at most size. */
+unsigned long sockfillbuf(struct clientparam * param, DIRECTION which, unsigned long size, int timeosec){
+ unsigned char *buf = which? param->srvbuf : param->clibuf;
+ unsigned *inbuf = which? ¶m->srvinbuf : ¶m->cliinbuf;
+ unsigned *offset = which? ¶m->srvoffset : ¶m->clioffset;
+ unsigned bufsize = which? param->srvbufsize : param->clibufsize;
+ unsigned want;
int len;
- if(!param->srvbuf) return 0;
- if(param->srvinbuf == param->srvoffset){
- param->srvinbuf = param->srvoffset = 0;
+ if(*offset){
+ memmove(buf, buf + *offset, *inbuf - *offset);
+ *inbuf -= *offset;
+ *offset = 0;
}
- else if(param->srvoffset){
- memmove(param->srvbuf, param->srvbuf + param->srvoffset, param->srvinbuf - param->srvoffset);
- param->srvinbuf -= param->srvoffset;
- param->srvoffset = 0;
+ while(*inbuf < size && *inbuf < bufsize){
+ want = (size - *inbuf < bufsize - *inbuf)? (unsigned)(size - *inbuf) : bufsize - *inbuf;
+ len = which?
+ sockrecvfrom(param, param->remsock, (struct sockaddr *)¶m->sinsr, buf + *inbuf, (int)want, timeosec*1000)
+ : sockrecvfrom(param, param->clisock, (struct sockaddr *)¶m->sincr, buf + *inbuf, (int)want, timeosec*1000);
+ if(len <= 0) break;
+ *inbuf += len;
+ if(which){
+ param->nreads++;
+ param->statssrv64 += len;
+ }
}
- if(size <= param->srvinbuf) return size;
- size -= param->srvinbuf;
- if((len = sockrecvfrom(param, param->remsock, (struct sockaddr *)¶m->sinsr, param->srvbuf + param->srvinbuf, (param->srvbufsize - param->srvinbuf) < size? param->srvbufsize - param->srvinbuf:size, timeosec*1000)) > 0){
- param->srvinbuf += len;
- param->nreads++;
- param->statssrv64 += len;
- }
- return param->srvinbuf;
+ return *inbuf < size? *inbuf : size;
}
int sockgetcharsrv(struct clientparam * param, int timeosec, int timeousec){
int len;
- int bufsize;
- if(!param->srvbuf){
- bufsize = SRVBUFSIZE;
- if(param->ndatfilterssrv > 0 && bufsize < 32768) bufsize = 32768;
- if(!(param->srvbuf = malloc(bufsize))) return 0;
- param->srvbufsize = bufsize;
- param->srvoffset = param->srvinbuf = 0;
-
- }
if(param->srvinbuf && param->srvoffset < param->srvinbuf){
return (int)param->srvbuf[param->srvoffset++];
}
- param->srvoffset = param->srvinbuf = 0;
+ bufrelease(param, SERVER);
if ((len = sockrecvfrom(param, param->remsock, (struct sockaddr *)¶m->sinsr, param->srvbuf, param->srvbufsize, timeosec*1000 + timeousec))<=0) return EOF;
param->srvinbuf = len;
param->srvoffset = 1;
diff --git a/src/sockmap.c b/src/sockmap.c
index 6813833..99e017d 100644
--- a/src/sockmap.c
+++ b/src/sockmap.c
@@ -141,13 +141,6 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
if(autosplice && allowsrv && param->waitserver64 && fromserver > inserverbuf && fromserver - inserverbuf >= SPLICE_MIN) splicesrv = 1;
if(autosplice && allowcli && param->waitclient64 && fromclient > inclientbuf && fromclient - inclientbuf >= SPLICE_MIN) splicecli = 1;
#endif
- /* a spliced direction needs no buffer, only what was read before */
- if(!splicesrv && fromserver && !param->srvbuf && (!(param->srvbuf=malloc(SRVBUFSIZE)) || !(param->srvbufsize = SRVBUFSIZE))){
- RETURN (21);
- }
- if(!splicecli && fromclient && !param->clibuf && (!(param->clibuf=malloc(SRVBUFSIZE)) || !(param->clibufsize = SRVBUFSIZE))){
- RETURN (21);
- }
if(param->srvinbuf == param->srvoffset) param->srvinbuf =param->srvoffset = 0;
if(param->cliinbuf == param->clioffset) param->cliinbuf =param->clioffset = 0;
if(param->clibufsize == param->cliinbuf) TOCLIENTBUF = 0;
@@ -268,7 +261,7 @@ log("done send to server from buf");
inclientbuf -= res;
fromclient -= res;
param->clioffset += res;
- if(param->clioffset == param->cliinbuf)param->clioffset = param->cliinbuf = 0;
+ bufrelease(param, CLIENT);
if(param->cliinbuf < param->clibufsize) TOCLIENTBUF = 1;
if(param->bandlimfunc) {
int sl1;
@@ -314,7 +307,7 @@ log("done send to client from buf");
inserverbuf -= res;
fromserver -= res;
param->srvoffset += res;
- if(param->srvoffset == param->srvinbuf)param->srvoffset = param->srvinbuf =0;
+ bufrelease(param, SERVER);
if(param->srvinbuf < param->srvbufsize) TOSERVERBUF = 1;
needaction = 0;
continue;
@@ -324,12 +317,10 @@ log("done send to client from buf");
/* a direction going back to copying does once its pipe is empty */
if(wantbufcli && !inclientpipe){
splicecli = wantbufcli = streakcli = 0;
- if(!param->clibuf && (!(param->clibuf=malloc(SRVBUFSIZE)) || !(param->clibufsize = SRVBUFSIZE))) RETURN (21);
if(param->cliinbuf < param->clibufsize) TOCLIENTBUF = 1;
}
if(wantbufsrv && !inserverpipe){
splicesrv = wantbufsrv = streaksrv = 0;
- if(!param->srvbuf && (!(param->srvbuf=malloc(SRVBUFSIZE)) || !(param->srvbufsize = SRVBUFSIZE))) RETURN (21);
if(param->srvinbuf < param->srvbufsize) TOSERVERBUF = 1;
}
{
@@ -409,7 +400,6 @@ log("read from client to pipe");
if(pipecli[0] < 0 && pipe2(pipecli, O_NONBLOCK) < 0){
/* no pipe to be had: copy instead */
allowcli = splicecli = TOCLIENTPIPE = FROMCLIENTPIPE = 0;
- if(!param->clibuf && (!(param->clibuf=malloc(SRVBUFSIZE)) || !(param->clibufsize = SRVBUFSIZE))) RETURN (21);
if(param->cliinbuf < param->clibufsize) TOCLIENTBUF = 1;
continue;
}
@@ -459,7 +449,6 @@ log("read from server to pipe\n");
#endif
if(pipesrv[0] < 0 && pipe2(pipesrv, O_NONBLOCK) < 0){
allowsrv = splicesrv = TOSERVERPIPE = FROMSERVERPIPE = 0;
- if(!param->srvbuf && (!(param->srvbuf=malloc(SRVBUFSIZE)) || !(param->srvbufsize = SRVBUFSIZE))) RETURN (21);
if(param->srvinbuf < param->srvbufsize) TOSERVERBUF = 1;
continue;
}
diff --git a/src/socks.c b/src/socks.c
index c39ffab..77ecc6c 100644
--- a/src/socks.c
+++ b/src/socks.c
@@ -21,7 +21,7 @@ char tracebuf[256];
static void printcommand(unsigned char * buf, int command, struct clientparam *param){
sprintf((char *)buf, "%s ", commands[command]);
- if(param->hostname){
+ if(*param->hostname){
sprintf((char *)buf + strlen((char *)buf), "%.256s", param->hostname);
}
else
@@ -37,7 +37,11 @@ void * sockschild(struct clientparam* param) {
unsigned size;
SASIZETYPE sasize;
uint16_t port = 0;
- unsigned char * buf=NULL;
+ /* a filter may hand back a buffer of its own in place of this one */
+ unsigned char * buf = param->tmpbuf;
+ /* the line logged, made apart from buf: logging makes its own line in
+ the scratch buffer */
+ unsigned char logline[340];
unsigned char c;
unsigned char command=0;
struct pollfd fds[3];
@@ -48,7 +52,6 @@ void * sockschild(struct clientparam* param) {
param->service = S_SOCKS;
- if(!(buf = malloc(BUFSIZE))) {RETURN(21);}
memset(buf, 0, BUFSIZE);
if ((ver = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5 && ver != 4) {
RETURN(401);
@@ -73,16 +76,14 @@ void * sockschild(struct clientparam* param) {
if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(451);}
if (i && (res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != (int)i) {RETURN(441);}
buf[i] = 0;
- if(!param->username) {
- param->username = (unsigned char *)strdup((char *)buf);
- if(!param->username){RETURN(21);}
+ if(!*param->username) {
+ if(PARAMSTR(param, username, buf)){RETURN(21);}
}
if ((i = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(445);}
if (i && (res = sockgetlinebuf(param, CLIENT, buf, i, 0, conf.timeouts[STRING_S])) != (int)i) {RETURN(441);}
buf[i] = 0;
- if(!param->password) {
- param->password = (unsigned char *)strdup((char *)buf);
- if(!param->password){RETURN(21);}
+ if(!*param->password) {
+ if(PARAMSTR(param, password, buf)){RETURN(21);}
}
buf[0] = 1;
buf[1] = 0;
@@ -137,9 +138,7 @@ void * sockschild(struct clientparam* param) {
default:
RETURN(997);
}
- if(param->hostname)free(param->hostname);
- param->hostname = (unsigned char *)strdup((char *)buf);
- if(!param->hostname){RETURN(21);}
+ if(PARAMSTR(param, hostname, buf)){RETURN(21);}
if (ver == 5) {
if ((res = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) == EOF) {RETURN(441);}
buf[0] = (unsigned char) res;
@@ -151,17 +150,14 @@ void * sockschild(struct clientparam* param) {
else {
if(sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]) < 0) {RETURN(441);}
buf[127] = 0;
- if(param->srv->needuser && *buf && !param->username) {
- param->username = (unsigned char *)strdup((char *)buf);
- if(!param->username){RETURN(21);}
+ if(param->srv->needuser && *buf && !*param->username) {
+ if(PARAMSTR(param, username, buf)){RETURN(21);}
}
if(!memcmp(SAADDR(¶m->req), "\0\0\0", 3)){
param->service = S_SOCKS45;
if(sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 1, 0, conf.timeouts[STRING_S]) < 0) {RETURN(441);}
buf[127] = 0;
- if(param->hostname)free(param->hostname);
- param->hostname = (unsigned char *)strdup((char *)buf);
- if(!param->hostname){RETURN(21);}
+ if(PARAMSTR(param, hostname, buf)){RETURN(21);}
if(!getip46(param->srv->family, buf, (struct sockaddr *) ¶m->req)) RETURN(100);
param->sinsr = param->req;
}
@@ -346,7 +342,7 @@ fflush(stderr);
switch(command) {
case 1:
if(param->redirectfunc){
- if(buf)free(buf);
+ if(buf != param->tmpbuf) free(buf);
return (void *)param->redirectfunc;
}
param->res = mapsocket(param, conf.timeouts[CONNECTION_L]);
@@ -421,12 +417,9 @@ fflush(stderr);
}
if(command > 3) command = 0;
- if(buf){
- printcommand(buf, command, param);
-
- dolog(param, buf);
- free(buf);
- }
+ printcommand(logline, command, param);
+ dolog(param, logline);
+ if(buf != param->tmpbuf) free(buf);
return (NULL);
}
diff --git a/src/ssl.c b/src/ssl.c
index 3b2a19f..264cab8 100644
--- a/src/ssl.c
+++ b/src/ssl.c
@@ -453,11 +453,13 @@ int docli(struct clientparam* param){
SSL_CONN ServerConn;
SSL_CERT ServerCert=NULL;
- unsigned char *hostname;
- hostname = param->hostname;
- param->hostname = (unsigned char *)PCONF->client_sni;
+ unsigned char hostname[HOSTNAMELEN];
+
+ /* the name given to the server is the configured one, if any */
+ memcpy(hostname, param->hostname, sizeof(hostname));
+ if(PARAMSTR(param, hostname, PCONF->client_sni)) *param->hostname = 0;
ServerConn = dosrvcon(param, &ServerCert);
- param->hostname = hostname;
+ memcpy(param->hostname, hostname, sizeof(hostname));
_ssl_cert_free(ServerCert);
if(!ServerConn) return 1;
diff --git a/src/structures.h b/src/structures.h
index 2c261a8..c89143d 100644
--- a/src/structures.h
+++ b/src/structures.h
@@ -199,6 +199,12 @@ int
#define MAX_HASH_SIZE (64)
#define UDPBUFSIZE 16384
+/* A connection's buffer for each side: 16K, and the 5 byte header of a TLS
+ record that big, which tlspr reads whole. */
+#define CLIENTBUFSIZE (16384 + 64)
+#define CLIENTTMPBUFSIZE 8192
+#define HOSTNAMELEN 256
+#define USERNAMELEN 128
extern char* NULLADDR;
typedef enum {
@@ -396,8 +402,6 @@ struct httpreq {
int proxy; /* the client asked the way it asks a proxy */
int connect; /* and asked for a tunnel */
int mayproxy; /* an access rule sent this to the local proxy */
- unsigned char *raw; /* the request as it arrived, for handing on */
- int rawlen, rawsize;
int drained; /* the body has been read and thrown away */
char *lasthost; /* where the last request on this connection went */
void *handoff; /* a child which takes the connection over */
@@ -527,7 +531,7 @@ struct filterp {
void *data;
};
-#define MAX_FILTERS 16
+#define MAX_FILTERS 256
/* Socket options for one kind of socket, -oc and the like: which of
sockopts[] are given, by their index there, and the value of each. */
@@ -688,11 +692,6 @@ struct clientparam {
TRAFCOUNTFUNC trafcountfunc;
- struct filterp *filters,
- **reqfilters, **connectfilters, **afterauthfilters,
- **hdrfilterscli, **hdrfilterssrv,
- **predatfilters, **datfilterscli, **datfilterssrv;
-
PROXYSERVICE service;
PROXYSERVICE clientstarttls;
@@ -735,12 +734,7 @@ struct clientparam {
preauth,
dstindep;
- unsigned char *hostname,
- *username,
- *password,
- *extusername,
- *extpassword,
- *clibuf,
+ unsigned char *clibuf,
*srvbuf;
/* splice() pipes for the client's and the server's data, -1 until
@@ -791,6 +785,34 @@ struct clientparam {
member is only reached once every weighted one is in here. */
struct chain *failedparents[MAXFAILEDPARENTS];
int nfailedparents;
+ /* Where in clibuf a request being read began, -1 when nothing is to be
+ kept, -2 once a request was too big for the buffer. While it is set,
+ refilling the buffer keeps everything from there on instead of
+ starting over, so the request can be read again from the buffer. */
+ int climark;
+ /* Names and credentials, empty when there are none. A value too long
+ for its field is refused, never cut short: set them with PARAMSTR. */
+ unsigned char hostname[HOSTNAMELEN],
+ username[USERNAMELEN],
+ password[USERNAMELEN],
+ extusername[USERNAMELEN],
+ extpassword[USERNAMELEN];
+ /* The filters this connection runs, which a new connection makes for
+ itself: the service's are not copied to it. Ordered for each stage. */
+ struct filterp filters[MAX_FILTERS],
+ *reqfilters[MAX_FILTERS], *connectfilters[MAX_FILTERS],
+ *afterauthfilters[MAX_FILTERS],
+ *hdrfilterscli[MAX_FILTERS], *hdrfilterssrv[MAX_FILTERS],
+ *predatfilters[MAX_FILTERS], *datfilterscli[MAX_FILTERS],
+ *datfilterssrv[MAX_FILTERS];
+ /* The connection's scratch buffer, for a log line and the like: for
+ something done at once, never for what has to outlive a call into
+ anything that could log. */
+ unsigned char tmpbuf[CLIENTTMPBUFSIZE];
+ /* Each side's data buffer, which clibuf and srvbuf point to unless a
+ filter needed a bigger one. */
+ unsigned char clibufdata[CLIENTBUFSIZE],
+ srvbufdata[CLIENTBUFSIZE];
};
struct filemon {
diff --git a/src/tcppm.c b/src/tcppm.c
index bbd4f52..98a5fd7 100644
--- a/src/tcppm.c
+++ b/src/tcppm.c
@@ -16,12 +16,12 @@
void * tcppmchild(struct clientparam* param) {
int res;
- if(!param->hostname){
+ if(!*param->hostname){
#ifdef WITH_UN
if(!strncmp((char *)param->srv->target, "unix:", 5)){
make_un(param->srv->target + 5, (struct sockaddr_un *)¶m->sinsr);
make_un(param->srv->target + 5, (struct sockaddr_un *)¶m->req);
- param->hostname = (unsigned char *)strdup((char *)param->srv->target);
+ if(PARAMSTR(param, hostname, param->srv->target)) RETURN(100);
} else
#endif
if(
@@ -46,7 +46,7 @@ void * tcppmchild(struct clientparam* param) {
RETURN (mapsocket(param, conf.timeouts[CONNECTION_L]));
CLEANRET:
- dolog(param, param->hostname);
+ dolog(param, *param->hostname? param->hostname : NULL);
return (NULL);
}
diff --git a/src/tlspr.c b/src/tlspr.c
index c6c343e..c0d35c6 100644
--- a/src/tlspr.c
+++ b/src/tlspr.c
@@ -266,64 +266,30 @@ int parsehello(int type, unsigned char *hello, unsigned len, char *sni, int * sn
return snifound;
}
-int tlstobufcli(struct clientparam *param){
- unsigned long len, newlen;
- if(!param->clibuf){
- if(!(param->clibuf = malloc(SRVBUFSIZE))) return -1;
- param->clibufsize = SRVBUFSIZE;
- param->clioffset = param->cliinbuf = 0;
- }
- if(param->srvinbuf != param->srvoffset){
- len = socksend(param, param->clisock, param->srvbuf+param->srvoffset,param->srvinbuf-param->srvoffset, conf.timeouts[STRING_S]);
- if(len != param->srvinbuf-param->srvoffset){
- return -2;
- }
- param->srvinbuf = param->srvoffset = 0;
- }
- len = sockfillbuffcli(param, 5, conf.timeouts[STRING_S]);
- if(len < 5) return -2;
- if(param->clibuf[1] != 3) {
- return -3;
- }
- else {
- len = 5 + size16(param->clibuf+3);
- if(len > param->clibufsize) return -4;
- for(newlen=param->cliinbuf; newlen < len; newlen=param->cliinbuf){
- sockfillbuffcli(param, len, conf.timeouts[STRING_S]);
- if(param->cliinbuf <= newlen) return -5;
- }
- }
- return (int)len;
-}
+/* Has one whole TLS record from one side at the start of its buffer, once
+ whatever is still buffered from the other side is passed on. Returns its
+ length, or less than 0; the server's codes are one further on than the
+ client's, as the log has always had them. */
+static int tlstobuf(struct clientparam *param, DIRECTION which){
+ unsigned *oinbuf = which? ¶m->cliinbuf : ¶m->srvinbuf;
+ unsigned *ooffset = which? ¶m->clioffset : ¶m->srvoffset;
+ unsigned char *obuf = which? param->clibuf : param->srvbuf;
+ unsigned char *buf;
+ int e = which? 1 : 0;
+ unsigned long len;
-int tlstobufsrv(struct clientparam *param){
- unsigned long len, newlen;
-
- if(param->cliinbuf != param->clioffset){
- len = socksend(param, param->remsock, param->clibuf+param->clioffset,param->cliinbuf-param->clioffset, conf.timeouts[STRING_S]);
- if(len != param->cliinbuf-param->clioffset){
- return -1;
- }
- param->cliinbuf = param->clioffset = 0;
- }
- if(!param->srvbuf){
- if(!(param->srvbuf = malloc(SRVBUFSIZE))) return -1;
- param->srvbufsize = SRVBUFSIZE;
- param->srvoffset = param->srvinbuf = 0;
- }
- len = sockfillbuffsrv(param, 5, conf.timeouts[STRING_S]);
- if(len < 5) return -3;
- if(param->srvbuf[1] != 3) {
- return -4;
- }
- else {
- len = 5 + size16(param->srvbuf+3);
- if(len > param->srvbufsize) return -5;
- for(newlen=param->srvinbuf; newlen < len; newlen=param->srvinbuf){
- sockfillbuffsrv(param, len, conf.timeouts[STRING_S]);
- if(param->srvinbuf <= newlen) return -6;
- }
+ if(*oinbuf != *ooffset){
+ len = *oinbuf - *ooffset;
+ if((unsigned long)socksend(param, which? param->remsock : param->clisock, obuf + *ooffset, (int)len, conf.timeouts[STRING_S]) != len)
+ return which? -1 : -2;
+ *oinbuf = *ooffset = 0;
}
+ if(sockfillbuf(param, which, 5, conf.timeouts[STRING_S]) < 5) return -2 - e;
+ buf = which? param->srvbuf : param->clibuf;
+ if(buf[1] != 3) return -3 - e;
+ len = 5 + size16(buf + 3);
+ if(len > (which? param->srvbufsize : param->clibufsize)) return -4 - e;
+ if(sockfillbuf(param, which, len, conf.timeouts[STRING_S]) < len) return -5 - e;
return (int)len;
}
@@ -343,7 +309,7 @@ void * tlsprchild(struct clientparam* param) {
if(res < 0) RETURN(0);
}
- res = tlstobufcli(param);
+ res = tlstobuf(param, CLIENT);
if(res <= 0 || param->clibuf[0] != 22){
if(param->srv->requirecert)RETURN(300-res);
}
@@ -351,12 +317,10 @@ void * tlsprchild(struct clientparam* param) {
lv = param->clibuf[2];
res = parsehello(1, param->clibuf, (unsigned)res, sni, &snipos, &lv, proto);
if(res > 0){
- if(param->hostname){
- free(param->hostname);
- param->hostname = NULL;
+ if(*param->hostname){
+ if(PARAMSTR(param, hostname, sni)) RETURN (100);
}
else if (parsehostname(sni, param, param->srv->targetport? ntohs(param->srv->targetport):starttlsport(stlsproto))) RETURN (100);
- if (!param->hostname)param->hostname = (unsigned char *)strdup(sni);
if(param->srv->s_option && snipos && res > 1){
int len;
@@ -395,7 +359,7 @@ void * tlsprchild(struct clientparam* param) {
}
if(param->srv->requirecert > 1){
- res = tlstobufsrv(param);
+ res = tlstobuf(param, SERVER);
if(res <= 0 || param->srvbuf[0] != 22) RETURN(340-res);
lv = param->srvbuf[2];
res = parsehello(2, param->srvbuf, (unsigned)res, sni, &snipos, &lv, proto);
@@ -408,7 +372,7 @@ void * tlsprchild(struct clientparam* param) {
len = param->srvinbuf;
if(socksend(param, param->clisock, param->srvbuf,len, conf.timeouts[STRING_S]) != len) RETURN(371);
param->srvinbuf = 0;
- res = tlstobufsrv(param);
+ res = tlstobuf(param, SERVER);
if(res <= 0) RETURN(380-res);
if(param->srvbuf[0]!= 22) break;
switch(param->srvbuf[5]){
@@ -430,7 +394,7 @@ void * tlsprchild(struct clientparam* param) {
if(param->srv->requirecert > 3){
if(!reqcert) RETURN(374);
for(done=0;!done;) {
- res = tlstobufcli(param);
+ res = tlstobuf(param, CLIENT);
if(res <= 0) RETURN(390-res);
len = res;
if(param->clibuf[0]!= 22) break;
@@ -456,7 +420,7 @@ void * tlsprchild(struct clientparam* param) {
RETURN (mapsocket(param, conf.timeouts[CONNECTION_L]));
CLEANRET:
- sprintf(req, "%sv%d.%d %s %s", lv<0?"NONE":lv?"TLS":"SSL", lv<0?0:lv?1:3, lv<0?0:lv?lv-1:0, param->hostname?(char *)param->hostname:"-", proto);
+ sprintf(req, "%sv%d.%d %s %s", lv<0?"NONE":lv?"TLS":"SSL", lv<0?0:lv?1:3, lv<0?0:lv?lv-1:0, *param->hostname?(char *)param->hostname:"-", proto);
dolog(param, (unsigned char *)req);
return (NULL);
}
diff --git a/src/transparent.c b/src/transparent.c
index 01809a0..c5bebdf 100644
--- a/src/transparent.c
+++ b/src/transparent.c
@@ -142,7 +142,6 @@ static void* transparent_filter_open(void * idata, struct srvparam * param){
static FILTER_ACTION transparent_filter_client(void *fo, struct clientparam * param, void** fc){
- char addrbuf[64];
int res = 1;
#ifdef WITH_NETFILTER
@@ -164,9 +163,8 @@ static FILTER_ACTION transparent_filter_client(void *fo, struct clientparam * pa
service decides as it would without the command. */
if(res) return PASS;
- pl->myinet_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)addrbuf, sizeof(addrbuf));
- if(param->hostname) pl->freefunc(param->hostname);
- param->hostname = (unsigned char *)pl->strdupfunc(addrbuf);
+ /* an address always fits the field */
+ pl->myinet_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)param->hostname, sizeof(param->hostname));
param->sinsr = param->req;
return PASS;
}
diff --git a/src/udppm.c b/src/udppm.c
index a0567c0..28a3752 100644
--- a/src/udppm.c
+++ b/src/udppm.c
@@ -50,10 +50,6 @@ void * udppmchild(struct clientparam* param) {
if(authres) { RETURN(authres); }
if((authres = udpbind(param))) { RETURN(authres); }
if(!param->srv->s_option)hashadd(&udp_table, param, ¶m, MAX_COUNTER_TIME);
- if(!param->srvbuf){
- if(!(param->srvbuf = malloc(UDPBUFSIZE)))RETURN(11);
- param->srvbufsize = UDPBUFSIZE;
- }
if(!param->bandlimfunc || !(*param->bandlimfunc)(param, 0, param->srv->udplen)){
if(param->udp_nhops){
for(i=1; i < param->udp_nhops; i++){
diff --git a/src/udpsockmap.c b/src/udpsockmap.c
index ff84a7d..05cdd12 100644
--- a/src/udpsockmap.c
+++ b/src/udpsockmap.c
@@ -93,7 +93,7 @@ static void udplog(struct clientparam *param)
if(!param->srv->logfunc) return;
len = sprintf((char *)buf, "UDPMAP ");
- if(param->hostname) len += sprintf((char *)buf + len, "%.256s", param->hostname);
+ if(*param->hostname) len += sprintf((char *)buf + len, "%.256s", param->hostname);
else len += myinet_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)buf + len, 64);
sprintf((char *)buf + len, ":%hu", ntohs(*SAPORT(¶m->req)));
param->srv->logfunc(param, buf);
@@ -208,12 +208,6 @@ int udpsockmap(struct clientparam *param, int timeo)
char lastname[256] = "";
struct ace *lastace = NULL;
- if (param->srvbufsize < UDPBUFSIZE) {
- unsigned char *newbuf = realloc(param->srvbuf, UDPBUFSIZE);
- if (!newbuf) return 21;
- param->srvbuf = newbuf;
- param->srvbufsize = UDPBUFSIZE;
- }
cliaddr = param->sincr;
if(param->ctrlsock != INVALID_SOCKET){
sasize = sizeof(cliaddr);
@@ -313,13 +307,11 @@ int udpsockmap(struct clientparam *param, int timeo)
PROXYSOCKADDRTYPE newdst = dst;
param->req = lastdst;
- if (param->hostname) free(param->hostname);
- param->hostname = *lastname? (unsigned char *)strdup(lastname) : NULL;
+ if (PARAMSTR(param, hostname, lastname)) *param->hostname = 0;
udplog(param);
dst = newdst;
}
- if (param->hostname) free(param->hostname);
- param->hostname = dstname? (unsigned char *)strdup(dstname) : NULL;
+ if (PARAMSTR(param, hostname, dstname)) *param->hostname = 0;
param->req = dst;
if (!nhops) param->sinsr = dst;