Pre-allocate client/server/tmp/etc buffers with client structure
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run

This commit is contained in:
Vladimir Dubrovin 2026-10-12 17:19:55 +03:00
parent b9297dc4cf
commit a20f646169
36 changed files with 431 additions and 492 deletions

View File

@ -233,7 +233,7 @@ struct filter {
<p><code>filter_open</code> 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.</p>
<p><code>filter_client</code> 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.</p>
<p><code>filter_request, filter_header_cli, filter_header_srv, filter_data_cli, filter_data_srv</code> are used to process request and data received from client and server.</p>
<p><code>char ** buf_p</code> is a pointer to current buffer, <code>int * bufsize_p</code> 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 <code>pluginlink-&gt;myalloc</code>), copy data from old buffer, free old buffer (with <code>pluginlink-&gt;myfree</code>) and set new values for <code>*buf_p</code> and <code>*bufsize_p</code>.</p>
<p><code>char ** buf_p</code> is a pointer to current buffer, <code>int * bufsize_p</code> 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 <code>pluginlink-&gt;mallocfunc</code>), copy data from old buffer and set new values for <code>*buf_p</code> and <code>*bufsize_p</code>. 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 <code>pluginlink-&gt;freefunc</code>).</p>
<p><code>int offset</code> offset of the new data in the buffer, <code>int * length_p</code> length of all data in the buffer. You should filter only <code>(*length_p - *offset_p)</code> characters starting from <code>(*buf_p + *offset_p)</code>.</p>
<p><code>filter_clear</code> is called for each successfule filter_client and should be used to free allocated resources</p>
<p><code>filter_close</code> is called for each successful filter_open for the same reason</p>

View File

@ -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

View File

@ -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 *)&param->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(&param->req) || param->operation==BIND)) || (acentry->dstnames && param->hostname)) {
else if((acentry->dst && (!SAISNULL(&param->req) || param->operation==BIND)) || (acentry->dstnames && *param->hostname)) {
for(ipentry = acentry->dst; ipentry; ipentry = ipentry->next)
if(IPInentry((struct sockaddr *)&param->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]);
}

View File

@ -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(&param->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(&param->sinsl, 0, sizeof(param->sinsl));
*(SAFAMILY(&param->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(&param->sincr) == AF_INET
#ifndef NOIPV6
|| *SAFAMILY(&param->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: {

View File

@ -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;

View File

@ -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 *)"");

View File

@ -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(&param->req)? ntohs(*SAPORT(&param->req)) : port);
if(!*param->hostname && param->remsock == INVALID_SOCKET) return 2;
if(*param->hostname)parsehostname((char *)param->hostname, param, *SAPORT(&param->req)? ntohs(*SAPORT(&param->req)) : port);
return parseusername(username, param, extpasswd);
}
while ((se=strchr(sb+1, conf.delimchar)))sb=se;

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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(&param->sincr);
if((type & 16)) acllen = sizeof(param->srv->acl);
if((type & 64)) a2len = SAADDRLEN(&param->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(&param->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(&param->sincr), a1len); offset += a1len; }
if((type & 16)){ memcpy(hash + offset, &param->srv->acl, acllen); offset += acllen; }
if((type & 64)){ memcpy(hash + offset, SAADDR(&param->req), a2len); offset += a2len; }
if((type & 128)){ memcpy(hash + offset, SAPORT(&param->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, &param->operation, oplen); offset += oplen; }
if((type & 1024)){ memcpy(hash + offset, SAADDR(&param->srv->intsa), a3len); offset += a3len; }
if((type & 2048)){ memcpy(hash + offset, SAPORT(&param->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(&param->sincr), a1len);
if((type & 16))mdh_update(bctx, &param->srv->acl, acllen);
if((type & 64))mdh_update(bctx, SAADDR(&param->req), a2len);
if((type & 128))mdh_update(bctx, SAPORT(&param->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, &param->operation, sizeof(param->operation));
if((type & 1024))mdh_update(bctx, SAADDR(&param->srv->intsa), a3len);
if((type & 2048))mdh_update(bctx, SAPORT(&param->srv->intsa), 2);

View File

@ -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

View File

@ -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&&param->extusername) {
if(*param->hostname&&*param->extusername) {
sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, (*SAPORT(&param->sinsr)==143)?0:':', ntohs(*SAPORT(&param->sinsr)));
dolog(param, buf);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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 ---------------------- */

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -68,7 +68,7 @@ void * pop3pchild(struct clientparam* param) {
RETURN (mapsocket(param, 180));
CLEANRET:
if(param->hostname&&param->extusername) {
if(*param->hostname&&*param->extusername) {
sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, (*SAPORT(&param->sinsr)==110)?0:':', ntohs(*SAPORT(&param->sinsr)));
dolog(param, buf);
}

View File

@ -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, &param->clibuf, (int *)&param->clibufsize, 0, (int *)&param->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){

View File

@ -22,6 +22,7 @@
#endif
#endif
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
@ -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,

View File

@ -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(&param->req) = *SAFAMILY(&param->sinsl) = *SAFAMILY(&param->sinsr) = *SAFAMILY(&param->sincr) = *SAFAMILY(&param->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(&param->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; i<srv->nfilters; i++){
if(!srv->filter[i].filter_client)continue;
action = (*srv->filter[i].filter_client)(srv->filter[i].data, param, &param->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; i<param->nreqfilters; 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; i<param->nhdrfilterssrv; 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; i<cparam->ndatfilterscli ;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; i<cparam->ndatfilterssrv; 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;

View File

@ -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 *)&param->req, param->hostname);
res = clientnegotiate(redir, param, (struct sockaddr *)&param->req, *param->hostname? param->hostname : NULL);
if(res) parentfail(param, redir);
if(saved){
SOCKET s;

View File

@ -201,8 +201,8 @@ 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);
}

View File

@ -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, &param->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&&param->extusername) {
if(*param->hostname&&*param->extusername) {
sprintf((char *)buf, "%.128s@%.128s%c%hu", param->extusername, param->hostname, *SAPORT(&param->sinsr)==587?0:':',ntohs(*SAPORT(&param->sinsr)));
dolog(param, buf);
}

View File

@ -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 *)&param->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? &param->srvbuf : &param->clibuf;
unsigned char *own = which? param->srvbufdata : param->clibufdata;
unsigned *inbuf = which? &param->srvinbuf : &param->cliinbuf;
unsigned *offset = which? &param->srvoffset : &param->clioffset;
unsigned *bufsize = which? &param->srvbufsize : &param->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 *)&param->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 *)&param->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? &param->srvinbuf : &param->cliinbuf;
unsigned *offset = which? &param->srvoffset : &param->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 *)&param->sinsr, buf + *inbuf, (int)want, timeosec*1000)
: sockrecvfrom(param, param->clisock, (struct sockaddr *)&param->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 *)&param->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 *)&param->sinsr, param->srvbuf, param->srvbufsize, timeosec*1000 + timeousec))<=0) return EOF;
param->srvinbuf = len;
param->srvoffset = 1;

View File

@ -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;
}

View File

@ -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(&param->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 *) &param->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);
}

View File

@ -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;

View File

@ -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 {

View File

@ -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 *)&param->sinsr);
make_un(param->srv->target + 5, (struct sockaddr_un *)&param->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);
}

View File

@ -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? &param->cliinbuf : &param->srvinbuf;
unsigned *ooffset = which? &param->clioffset : &param->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);
}

View File

@ -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(&param->req), SAADDR(&param->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(&param->req), SAADDR(&param->req), (char *)param->hostname, sizeof(param->hostname));
param->sinsr = param->req;
return PASS;
}

View File

@ -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, &param, 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++){

View File

@ -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(&param->req), SAADDR(&param->req), (char *)buf + len, 64);
sprintf((char *)buf + len, ":%hu", ntohs(*SAPORT(&param->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;