tlspr (SNI proxy) implemented

Options -cN - level of TLS check
default - allow non-TLS traffic
1 - require TLS, only check client HELLO packet
2 - require TLS, check both client and server HELLO
3 - require TLS, check server send certificate (not compatible with TLS 1.3)
4 - require mutual TLS, check server send certificate request and client sends certificate (not compatible with TLS 1.3)
-P - default port

examples:

1.
tlspr -p1443 -P443 -c1
(port 1443 may be used to redirect traffic to destination port 143). SNI is used to find destination host

2.
allow * * * 80
parent 1000 http 0.0.0.0 0
allow * * * * CONNECT
parent 1000 tls 0.0.0.0 0
deny * * some.not.allowed.host
allow *
socks

attempts to take destination hostname from SNI in SOCKS
This commit is contained in:
Vladimir Dubrovin 2024-05-20 13:01:38 +03:00
parent 29ef226b3c
commit 013d4bc333
10 changed files with 343 additions and 16 deletions

BIN
bin/tlspr Normal file

Binary file not shown.

View File

@ -2,7 +2,7 @@
# 3 proxy common Makefile # 3 proxy common Makefile
# #
all: $(BUILDDIR)3proxy$(EXESUFFICS) $(BUILDDIR)mycrypt$(EXESUFFICS) $(BUILDDIR)pop3p$(EXESUFFICS) $(BUILDDIR)smtpp$(EXESUFFICS) $(BUILDDIR)ftppr$(EXESUFFICS) $(BUILDDIR)tcppm$(EXESUFFICS) $(BUILDDIR)udppm$(EXESUFFICS) $(BUILDDIR)socks$(EXESUFFICS) $(BUILDDIR)proxy$(EXESUFFICS) allplugins all: $(BUILDDIR)3proxy$(EXESUFFICS) $(BUILDDIR)mycrypt$(EXESUFFICS) $(BUILDDIR)pop3p$(EXESUFFICS) $(BUILDDIR)smtpp$(EXESUFFICS) $(BUILDDIR)ftppr$(EXESUFFICS) $(BUILDDIR)tcppm$(EXESUFFICS) $(BUILDDIR)tlspr$(EXESUFFICS) $(BUILDDIR)udppm$(EXESUFFICS) $(BUILDDIR)socks$(EXESUFFICS) $(BUILDDIR)proxy$(EXESUFFICS) allplugins
sockmap$(OBJSUFFICS): sockmap.c proxy.h structures.h sockmap$(OBJSUFFICS): sockmap.c proxy.h structures.h
@ -41,6 +41,10 @@ ftppr$(OBJSUFFICS): ftppr.c proxy.h structures.h proxymain.c
tcppm$(OBJSUFFICS): tcppm.c proxy.h structures.h proxymain.c tcppm$(OBJSUFFICS): tcppm.c proxy.h structures.h proxymain.c
$(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)PORTMAP tcppm.c $(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)PORTMAP tcppm.c
tlspr$(OBJSUFFICS): tlspr.c proxy.h structures.h proxymain.c
$(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)PORTMAP tlspr.c
socks$(OBJSUFFICS): socks.c proxy.h structures.h proxymain.c socks$(OBJSUFFICS): socks.c proxy.h structures.h proxymain.c
$(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)NOPORTMAP socks.c $(CC) $(CFLAGS) $(DEFINEOPTION)WITHMAIN $(DEFINEOPTION)NOPORTMAP socks.c
@ -68,6 +72,9 @@ $(BUILDDIR)socks$(EXESUFFICS): sockmap$(OBJSUFFICS) socks$(OBJSUFFICS) sockgetch
$(BUILDDIR)tcppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) $(BUILDDIR)tcppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)tcppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)tcppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tcppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
$(BUILDDIR)tlspr$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)tlspr$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) tlspr$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
$(BUILDDIR)udppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) $(BUILDDIR)udppm$(EXESUFFICS): sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS)
$(LN) $(LNOUT)$(BUILDDIR)udppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)udppm$(EXESUFFICS) $(LDFLAGS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) udppm$(OBJSUFFICS) log$(OBJSUFFICS) common$(OBJSUFFICS) $(LIBS)
@ -91,6 +98,9 @@ srvftppr$(OBJSUFFICS): ftppr.c proxy.h structures.h
srvtcppm$(OBJSUFFICS): tcppm.c proxy.h structures.h srvtcppm$(OBJSUFFICS): tcppm.c proxy.h structures.h
$(CC) $(COUT)srvtcppm$(OBJSUFFICS) $(CFLAGS) tcppm.c $(CC) $(COUT)srvtcppm$(OBJSUFFICS) $(CFLAGS) tcppm.c
srvtlspr$(OBJSUFFICS): tlspr.c proxy.h structures.h
$(CC) $(COUT)srvtlspr$(OBJSUFFICS) $(CFLAGS) tlspr.c
srvauto$(OBJSUFFICS): auto.c proxy.h structures.h srvauto$(OBJSUFFICS): auto.c proxy.h structures.h
$(CC) $(COUT)srvauto$(OBJSUFFICS) $(CFLAGS) auto.c $(CC) $(COUT)srvauto$(OBJSUFFICS) $(CFLAGS) auto.c
@ -146,6 +156,6 @@ ntlm$(OBJSUFFICS): ntlm.c
stringtable$(OBJSUFFICS): stringtable.c stringtable$(OBJSUFFICS): stringtable.c
$(CC) $(COUT)stringtable$(OBJSUFFICS) $(CFLAGS) stringtable.c $(CC) $(COUT)stringtable$(OBJSUFFICS) $(CFLAGS) stringtable.c
$(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) auth$(OBJSUFFICS) authradius$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) mycrypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) smbdes$(OBJSUFFICS) ntlm$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(COMPATLIBS) $(VERSIONDEP) $(BUILDDIR)3proxy$(EXESUFFICS): 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) auth$(OBJSUFFICS) authradius$(OBJSUFFICS) conf$(OBJSUFFICS) log$(OBJSUFFICS) datatypes$(OBJSUFFICS) md4$(OBJSUFFICS) md5$(OBJSUFFICS) mycrypt$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) smbdes$(OBJSUFFICS) ntlm$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(COMPATLIBS) $(VERSIONDEP)
$(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) auth$(OBJSUFFICS) authradius$(OBJSUFFICS) conf$(OBJSUFFICS) datatypes$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) mycrypt$(OBJSUFFICS) md5$(OBJSUFFICS) md4$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) smbdes$(OBJSUFFICS) ntlm$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(COMPATLIBS) $(LIBS) $(LN) $(LNOUT)$(BUILDDIR)3proxy$(EXESUFFICS) $(LDFLAGS) $(VERFILE) 3proxy$(OBJSUFFICS) mainfunc$(OBJSUFFICS) auth$(OBJSUFFICS) authradius$(OBJSUFFICS) conf$(OBJSUFFICS) datatypes$(OBJSUFFICS) srvauto$(OBJSUFFICS) srvproxy$(OBJSUFFICS) srvpop3p$(OBJSUFFICS) srvsmtpp$(OBJSUFFICS) srvftppr$(OBJSUFFICS) srvsocks$(OBJSUFFICS) srvtcppm$(OBJSUFFICS) srvtlspr$(OBJSUFFICS) srvudppm$(OBJSUFFICS) sockmap$(OBJSUFFICS) sockgetchar$(OBJSUFFICS) common$(OBJSUFFICS) log$(OBJSUFFICS) mycrypt$(OBJSUFFICS) md5$(OBJSUFFICS) md4$(OBJSUFFICS) base64$(OBJSUFFICS) ftp$(OBJSUFFICS) smbdes$(OBJSUFFICS) ntlm$(OBJSUFFICS) stringtable$(OBJSUFFICS) srvwebadmin$(OBJSUFFICS) srvdnspr$(OBJSUFFICS) plugins$(OBJSUFFICS) $(COMPATLIBS) $(LIBS)

View File

@ -302,6 +302,9 @@ int handleredirect(struct clientparam * param, struct ace * acentry){
case R_SMTP: case R_SMTP:
param->redirectfunc = smtppchild; param->redirectfunc = smtppchild;
break; break;
case R_TLS:
param->redirectfunc = tlsprchild;
break;
default: default:
param->redirectfunc = proxychild; param->redirectfunc = proxychild;
} }

View File

@ -238,6 +238,13 @@ static int h_proxy(int argc, unsigned char ** argv){
childdef.service = S_TCPPM; childdef.service = S_TCPPM;
childdef.helpmessage = ""; childdef.helpmessage = "";
} }
else if(!strcmp((char *)argv[0], "tlspr")) {
childdef.pf = tlsprchild;
childdef.port = 1443;
childdef.isudp = 0;
childdef.service = S_TLSPR;
childdef.helpmessage = "";
}
else if(!strcmp((char *)argv[0], "udppm")) { else if(!strcmp((char *)argv[0], "udppm")) {
childdef.pf = udppmchild; childdef.pf = udppmchild;
childdef.port = 0; childdef.port = 0;
@ -756,6 +763,7 @@ static int h_parent(int argc, unsigned char **argv){
else if(!strcmp((char *)argv[2], "socks4b"))chains->type = R_SOCKS4B; else if(!strcmp((char *)argv[2], "socks4b"))chains->type = R_SOCKS4B;
else if(!strcmp((char *)argv[2], "socks5b"))chains->type = R_SOCKS5B; else if(!strcmp((char *)argv[2], "socks5b"))chains->type = R_SOCKS5B;
else if(!strcmp((char *)argv[2], "pop3"))chains->type = R_POP3; else if(!strcmp((char *)argv[2], "pop3"))chains->type = R_POP3;
else if(!strcmp((char *)argv[2], "tls"))chains->type = R_TLS;
else if(!strcmp((char *)argv[2], "ftp"))chains->type = R_FTP; else if(!strcmp((char *)argv[2], "ftp"))chains->type = R_FTP;
else if(!strcmp((char *)argv[2], "admin"))chains->type = R_ADMIN; else if(!strcmp((char *)argv[2], "admin"))chains->type = R_ADMIN;
else if(!strcmp((char *)argv[2], "extip"))chains->type = R_EXTIP; else if(!strcmp((char *)argv[2], "extip"))chains->type = R_EXTIP;
@ -1618,8 +1626,9 @@ struct commands commandhandlers[]={
{commandhandlers+63, "parentretries", h_parentretries, 2, 2}, {commandhandlers+63, "parentretries", h_parentretries, 2, 2},
{commandhandlers+64, "auto", h_proxy, 1, 0}, {commandhandlers+64, "auto", h_proxy, 1, 0},
{commandhandlers+65, "backlog", h_backlog, 2, 2}, {commandhandlers+65, "backlog", h_backlog, 2, 2},
{commandhandlers+66, "tlspr", h_proxy, 1, 0},
#ifndef NORADIUS #ifndef NORADIUS
{commandhandlers+66, "radius", h_radius, 3, 0}, {commandhandlers+67, "radius", h_radius, 3, 0},
#endif #endif
{specificcommands, "", h_noop, 1, 0} {specificcommands, "", h_noop, 1, 0}
}; };

View File

@ -68,13 +68,15 @@ struct symbol symbols[] = {
{symbols+41, "admin", (void *) adminchild}, {symbols+41, "admin", (void *) adminchild},
{symbols+42, "ftppr", (void *) ftpprchild}, {symbols+42, "ftppr", (void *) ftpprchild},
{symbols+43, "smtpp", (void *) smtppchild}, {symbols+43, "smtpp", (void *) smtppchild},
{symbols+44, "authfuncs", (void *) &authfuncs}, {symbols+44, "auto", (void *) smtppchild},
{symbols+45, "commandhandlers", (void *) &commandhandlers}, {symbols+45, "tlspr", (void *) smtppchild},
{symbols+46, "decodeurl", (void *) decodeurl}, {symbols+46, "authfuncs", (void *) &authfuncs},
{symbols+47, "parsestr", (void *) parsestr}, {symbols+47, "commandhandlers", (void *) &commandhandlers},
{symbols+48, "make_ace", (void *) make_ace}, {symbols+48, "decodeurl", (void *) decodeurl},
{symbols+49, "freeacl", (void *) freeacl}, {symbols+49, "parsestr", (void *) parsestr},
{symbols+50, "handleredirect", (void *) handleredirect}, {symbols+50, "make_ace", (void *) make_ace},
{symbols+51, "freeacl", (void *) freeacl},
{symbols+52, "handleredirect", (void *) handleredirect},
{NULL, "", NULL} {NULL, "", NULL}
}; };

View File

@ -297,6 +297,7 @@ void * autochild(struct clientparam * param);
void * udppmchild(struct clientparam * param); void * udppmchild(struct clientparam * param);
void * adminchild(struct clientparam * param); void * adminchild(struct clientparam * param);
void * ftpprchild(struct clientparam * param); void * ftpprchild(struct clientparam * param);
void * tlsprchild(struct clientparam * param);
struct datatype; struct datatype;

View File

@ -383,6 +383,9 @@ int MODULEMAINFUNC (int argc, char** argv){
case 'p': case 'p':
*SAPORT(&srv.intsa) = htons(atoi(argv[i]+2)); *SAPORT(&srv.intsa) = htons(atoi(argv[i]+2));
break; break;
case 'P':
srv.targetport = ntohs(atoi(argv[i]+2));
break;
case '4': case '4':
case '6': case '6':
srv.family = atoi(argv[i]+1); srv.family = atoi(argv[i]+1);
@ -414,6 +417,10 @@ int MODULEMAINFUNC (int argc, char** argv){
case 'h': case 'h':
hostname = argv[i] + 2; hostname = argv[i] + 2;
break; break;
case 'c':
srv.requirecert = 1;
if(isdigit(argv[i][2])) srv.requirecert = atoi(argv[i]+2);
break;
case 'r': case 'r':
cbc_string = (unsigned char *)mystrdup(argv[i] + 2); cbc_string = (unsigned char *)mystrdup(argv[i] + 2);
iscbc = 1; iscbc = 1;

View File

@ -18,7 +18,7 @@ unsigned char * commands[] = {(unsigned char *)"UNKNOWN", (unsigned char *)"CONN
static void printcommand(unsigned char * buf, int command, struct clientparam *param){ static void printcommand(unsigned char * buf, int command, struct clientparam *param){
sprintf((char *)buf, "%s ", commands[command]); sprintf((char *)buf, "%s ", commands[command]);
if(param->hostname){ if(param->hostname){
sprintf((char *)buf + strlen((char *)buf), "%.265s", param->hostname); sprintf((char *)buf + strlen((char *)buf), "%.256s", param->hostname);
} }
else else
myinet_ntop(*SAFAMILY(&param->req), SAADDR(&param->req), (char *)buf + strlen((char *)buf), 64); myinet_ntop(*SAFAMILY(&param->req), SAADDR(&param->req), (char *)buf + strlen((char *)buf), 64);

View File

@ -168,10 +168,10 @@ typedef enum {
typedef enum { typedef enum {
S_NOSERVICE, S_NOSERVICE = 0,
S_PROXY, S_PROXY,
S_TCPPM, S_TCPPM,
S_POP3P, S_POP3P = 3,
S_SOCKS4 = 4, /* =4 */ S_SOCKS4 = 4, /* =4 */
S_SOCKS5 = 5, /* =5 */ S_SOCKS5 = 5, /* =5 */
S_UDPPM, S_UDPPM,
@ -184,7 +184,8 @@ typedef enum {
S_REVLI, S_REVLI,
S_REVCO, S_REVCO,
S_ZOMBIE, S_ZOMBIE,
S_AUTO S_AUTO,
S_TLSPR
}PROXYSERVICE; }PROXYSERVICE;
struct clientparam; struct clientparam;
@ -279,7 +280,8 @@ typedef enum {
R_SOCKS4B, R_SOCKS4B,
R_SOCKS5B, R_SOCKS5B,
R_ADMIN, R_ADMIN,
R_EXTIP R_EXTIP,
R_TLS
} REDIRTYPE; } REDIRTYPE;
struct chain { struct chain {
@ -487,6 +489,7 @@ struct srvparam {
int anonymous; int anonymous;
int clisockopts, srvsockopts, lissockopts, cbcsockopts, cbssockopts; int clisockopts, srvsockopts, lissockopts, cbcsockopts, cbssockopts;
int gracetraf, gracenum, gracedelay; int gracetraf, gracenum, gracedelay;
int requirecert;
#ifdef WITHSPLICE #ifdef WITHSPLICE
int usesplice; int usesplice;
#endif #endif

292
src/tlspr.c Normal file
View File

@ -0,0 +1,292 @@
/*
3APA3A simpliest proxy server
(c) 2002-2021 by Vladimir Dubrovin <3proxy@3proxy.org>
please read License Agreement
*/
#include "proxy.h"
#ifndef PORTMAP
#define PORTMAP
#endif
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
unsigned size16(unsigned char *buf){
unsigned res;
res = (((unsigned)buf[0]) << 8) + +buf[1];
return res;
}
int readtls(struct clientparam *param, int direction, unsigned char *buf, int bufsize){
int res = 0;
int len;
if(bufsize < 3) return -1;
res = sockgetlinebuf(param, direction, buf, 3, EOF, conf.timeouts[STRING_S]);
if(res !=3 || buf[0] != 22 || buf[1] != 3) return -2;
len = size16(buf+3);
if((len+3) > bufsize) return -3;
res = sockgetlinebuf(param, direction, buf+3, len, EOF, conf.timeouts[STRING_S]);
if(res != len) return -4;
return len+3;
}
#define BSIZE (4096)
#define SNILEN (256)
#define PROTOLEN (32)
int parsehello(int type, unsigned char *hello, int len, unsigned char *sni, int *lv, unsigned char * proto){
int hlen;
unsigned offset;
int slen;
int cslen;
int elen;
int snllen, snlen, alpnlen;
int snifound=0;
if(len < 64) return -1;
if(hello[5] != type) return -2;
if(hello[6] != 0) return -3;
hlen = size16(hello+7);
if((hlen+9) != len) return -4;
offset = 9;
if(hello[offset] != 3) return -5;
*lv = hello[offset+1];
offset += 34;
slen = hello[offset];
if((offset + slen + 3) > len) return -6;
offset += (slen+1);
if(type == 1){
cslen = size16(hello+offset);
if((offset + cslen + 3) > len) return -7;
offset += (cslen+2);
cslen = hello[offset];
if((offset + cslen + 3) > len) return -8;
offset += (cslen+1);
}
else if(type == 2){
offset += 3;
}
elen = size16(hello+offset);
offset += 2;
if(elen+offset != len) return -9;
while(elen > 1){
int xlen;
xlen = size16(hello+offset+2);
if(xlen+4 > elen) return -10;
if(type == 1 && hello[offset] == 0 && hello[offset+1] == 0){
snllen=size16(hello+offset+4);
if(snllen>3){
if(snllen+2 != xlen) return -12;
if(hello[offset+6] != 0) return -13;
snlen=size16(hello+offset+7);
if(snlen + 3 > snllen) return -14;
if(snlen+1 > SNILEN) return -15;
memcpy(sni, hello + offset + 9, snlen);
sni[snlen] = 0;
snifound = snlen;
}
}
else if(hello[offset] == 0 && hello[offset+1] == 43){
if(xlen>2){
*lv = hello[offset+6];
}
else if(xlen==2){
*lv = hello[offset+5];
}
}
else if(hello[offset] == 0 && hello[offset+1] == 16){
alpnlen=hello[offset+6];
if(alpnlen+7>elen) return -16;
if(alpnlen+1>PROTOLEN) return -17;
memcpy(proto, hello+offset+7, alpnlen);
proto[alpnlen] = 0;
}
offset += (xlen+4);
elen -= (xlen+4);
}
return snifound;
}
int tlstobufcli(struct clientparam *param, int offset){
int len, newlen;
if(!param->clibuf){
if(!(param->clibuf = myalloc(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 len;
}
int tlstobufsrv(struct clientparam *param, int offset){
int 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 = myalloc(SRVBUFSIZE))) return -1;
param->srvbufsize = SRVBUFSIZE;
param->srvoffset = param->srvinbuf = 0;
}
len = sockfillbuffsrv(param, offset+5, conf.timeouts[STRING_S]);
if(len < offset+5) return -3;
if(param->srvbuf[offset+1] != 3) {
return -4;
}
else {
len = offset + 5 + size16(param->srvbuf+offset+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;
}
}
return len-offset;
}
void * tlsprchild(struct clientparam* param) {
int res;
unsigned char sni[SNILEN];
char req[SNILEN+PROTOLEN+16];
int lv=-1;
unsigned char proto[PROTOLEN]="-";
res = tlstobufcli(param, 0);
if(res <= 0 || param->clibuf[0] != 22){
if(param->srv->requirecert)RETURN(300-res);
}
else {
lv = param->clibuf[2];
res = parsehello(1, param->clibuf, res, sni, &lv, proto);
if(res > 0){
if(param->hostname){
myfree(param->hostname);
param->hostname = NULL;
}
else if (parsehostname(sni, param, param->srv->targetport? param->srv->targetport:443)) RETURN (100);
if (!param->hostname)param->hostname = mystrdup((char *)sni);
}
else if (res < 0 && param->srv->requirecert) RETURN(310-res);
}
param->operation = CONNECT;
param->redirectfunc = NULL;
res = (*param->srv->authfunc)(param);
if(res) {RETURN(res);}
if (param->npredatfilters){
int action;
action = handlepredatflt(param);
if(action == HANDLED){
RETURN(0);
}
if(action != PASS) RETURN(19);
}
if(param->redirectfunc && param->redirectfunc != tlsprchild){
return (*param->redirectfunc)(param);
}
if(param->srv->requirecert > 1){
res = tlstobufsrv(param, 0);
if(res <= 0 || param->srvbuf[0] != 22) RETURN(340-res);
lv = param->srvbuf[2];
res = parsehello(2, param->srvbuf, res, sni, &lv, proto);
if (res < 0) RETURN(350-res);
}
if(param->srv->requirecert > 2){
if(lv > 3) RETURN(370);
int srvcert=0, clicert=0, reqcert=0, len, rlen, done;
for(done=0;!done;) {
len = param->srvinbuf;
if(socksend(param, param->clisock, param->srvbuf,len, conf.timeouts[STRING_S]) != len) RETURN(371);
param->srvinbuf = 0;
res = tlstobufsrv(param, 0);
if(res <= 0) RETURN(380-res);
if(param->srvbuf[0]!= 22) break;
switch(param->srvbuf[5]){
case 11:
/* process server certificates here */
if(param->srvbuf[6]||param->srvbuf[7]||param->srvbuf[8]>64) srvcert = 1;
break;
case 13:
reqcert = 1;
break;
case 14:
done = 1;
break;
default:
break;
}
}
if(!srvcert) RETURN(373);
if(param->srv->requirecert > 3){
if(!reqcert) RETURN(374);
for(done=0;!done;) {
res = tlstobufcli(param, 0);
if(res <= 0) RETURN(390-res);
len = res;
if(param->clibuf[0]!= 22) break;
switch(param->clibuf[5]){
case 11:
/* process client certificates here */
if(param->clibuf[6]||param->clibuf[7]||param->clibuf[8]>64)clicert = 1;
break;
case 14:
done = 1;
break;
default:
break;
}
if(done) break;
if(socksend(param, param->remsock, param->clibuf,len, conf.timeouts[STRING_S]) != len) RETURN(375);
param->cliinbuf = 0;
}
if(!clicert) RETURN(375);
}
}
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?param->hostname:"-", proto);
dolog(param, req);
freeparam(param);
return (NULL);
}
#ifdef WITHMAIN
struct proxydef childdef = {
tlsprchild,
1443,
0,
S_TLSPR,
""
};
#include "proxymain.c"
#endif