From 89b45b1b2aa6086931145fcbb969037a16c1811d Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Sat, 15 Mar 2025 15:54:29 +0300 Subject: [PATCH] Support HAProxy proxy v1 protocol Added: -H option - expect HAProxy proxy v1 header, e.g. `proxy -H` parent ha type - send HAProxy proxy v1 header (must be last in redirection), e.g. allow * parent 1000 ha parent 1000 proxy 1.2.3.4 3128 socks --- src/auth.c | 46 +++++++++++++++++++++++++++------------------- src/conf.c | 48 +++++++++++++++++++++++++++++++----------------- src/datatypes.c | 22 +++++----------------- src/proxymain.c | 34 ++++++++++++++++++++++++++++++++++ src/structures.h | 16 ++++++++++++++-- 5 files changed, 111 insertions(+), 55 deletions(-) diff --git a/src/auth.c b/src/auth.c index 4e1e363..eadcc74 100644 --- a/src/auth.c +++ b/src/auth.c @@ -222,6 +222,7 @@ int handleredirect(struct clientparam * param, struct ace * acentry){ int weight = 1000; int res; int done = 0; + int ha = 0; struct chain * cur; struct chain * redir = NULL; int r2; @@ -278,6 +279,7 @@ int handleredirect(struct clientparam * param, struct ace * acentry){ return 0; } else if(SAISNULL(&cur->addr) && !*SAPORT(&cur->addr)){ + int i; if(cur->extuser){ if(param->extusername) myfree(param->extusername); @@ -289,27 +291,18 @@ int handleredirect(struct clientparam * param, struct ace * acentry){ } if(*cur->extuser == '*' && !param->username) return 4; } - switch(cur->type){ - case R_POP3: - param->redirectfunc = pop3pchild; - break; - case R_FTP: - param->redirectfunc = ftpprchild; - break; - case R_ADMIN: - param->redirectfunc = adminchild; - break; - case R_SMTP: - param->redirectfunc = smtppchild; - break; - case R_TLS: - param->redirectfunc = tlsprchild; - break; - default: - param->redirectfunc = proxychild; + + for(i=0; redirs[i].name; i++){ + if(cur->type == redirs[i].redir) { + param->redirectfunc = redirs[i].func; + break; + } + } + if(cur->type == R_HA){ + ha = 1; } if(cur->next)continue; - return 0; + if(!ha) return 0; } else if(!*SAPORT(&cur->addr) && !SAISNULL(&cur->addr)) { unsigned short port = *SAPORT(¶m->sinsr); @@ -324,6 +317,21 @@ int handleredirect(struct clientparam * param, struct ace * acentry){ if((res = alwaysauth(param))){ return (res >= 10)? res : 60+res; } + if(ha) { + char buf[128]; + int len; + len = sprintf(buf, "PROXY %s ", + *SAFAMILY(¶m->sincr) == AF_INET6 ? "TCP6" : "TCP4"); + len += myinet_ntop(*SAFAMILY(¶m->sincr), SAADDR(¶m->sincr), buf+len, sizeof(param->sincr)); + buf[len++] = ' '; + len += myinet_ntop(*SAFAMILY(¶m->sincl), SAADDR(¶m->sincl), buf+len, sizeof(param->sincl)); + len += sprintf(buf + len, " %hu %hu\r\n", + ntohs(*SAPORT(¶m->sincr)), + ntohs(*SAPORT(¶m->sincl)) + ); + if(socksend(param, param->remsock, (unsigned char *)buf, len, conf.timeouts[CHAIN_TO])!=len) return 39; + return 0; + } } else { res = (redir)?clientnegotiate(redir, param, (struct sockaddr *)&cur->addr, cur->exthost):0; diff --git a/src/conf.c b/src/conf.c index 2f353b9..2a39aad 100644 --- a/src/conf.c +++ b/src/conf.c @@ -729,10 +729,34 @@ static int h_monitor(int argc, unsigned char **argv){ return 0; } + +struct redirdesc redirs[] = { + {R_TCP, "tcp", tcppmchild}, + {R_CONNECT, "connect", proxychild}, + {R_SOCKS4, "socks4", sockschild}, + {R_SOCKS5, "socks5", sockschild}, + {R_HTTP, "http", proxychild}, + {R_POP3, "pop3", pop3pchild}, + {R_SMTP, "smtp", smtppchild}, + {R_FTP, "ftp", ftpprchild}, + {R_CONNECTP, "connect+", proxychild}, + {R_SOCKS4P, "socks4+", sockschild}, + {R_SOCKS5P, "socks5+", sockschild}, + {R_SOCKS4B, "socks4b", sockschild}, + {R_SOCKS5B, "socks5b", sockschild}, + {R_ADMIN, "admin", adminchild}, + {R_EXTIP, "extip", NULL}, + {R_TLS, "tls", tlsprchild}, + {R_HA, "ha", NULL}, + {R_DNS, "dns", dnsprchild}, + {0, NULL, NULL} +}; + static int h_parent(int argc, unsigned char **argv){ struct ace *acl = NULL; struct chain *chains; char * cidr; + int i; acl = conf.acl; while(acl && acl->next) acl = acl->next; @@ -752,23 +776,13 @@ static int h_parent(int argc, unsigned char **argv){ fprintf(stderr, "Chaining error: bad chain weight %u line %d\n", chains->weight, linenum); return(3); } - if(!strcmp((char *)argv[2], "tcp"))chains->type = R_TCP; - else if(!strcmp((char *)argv[2], "http"))chains->type = R_HTTP; - else if(!strcmp((char *)argv[2], "connect"))chains->type = R_CONNECT; - else if(!strcmp((char *)argv[2], "socks4"))chains->type = R_SOCKS4; - else if(!strcmp((char *)argv[2], "socks5"))chains->type = R_SOCKS5; - else if(!strcmp((char *)argv[2], "connect+"))chains->type = R_CONNECTP; - else if(!strcmp((char *)argv[2], "socks4+"))chains->type = R_SOCKS4P; - else if(!strcmp((char *)argv[2], "socks5+"))chains->type = R_SOCKS5P; - 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], "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], "admin"))chains->type = R_ADMIN; - else if(!strcmp((char *)argv[2], "extip"))chains->type = R_EXTIP; - else if(!strcmp((char *)argv[2], "smtp"))chains->type = R_SMTP; - else { + for(i = 0; redirs[i].name ; i++){ + if(!strcmp((char *)argv[2], redirs[i].name)) { + chains->type = redirs[i].redir; + break; + } + } + if(!redirs[i].name) { fprintf(stderr, "Chaining error: bad chain type (%s)\n", argv[2]); return(4); } diff --git a/src/datatypes.c b/src/datatypes.c index 0d991c6..38dee90 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -325,24 +325,12 @@ static void * ef_chain_next(struct node * node){ } static void * ef_chain_type(struct node * node){ - switch (((struct chain *)node->value) -> type) { - case R_TCP: - return "tcp"; - case R_CONNECT: - return "connect"; - case R_SOCKS4: - return "socks4"; - case R_SOCKS5: - return "socks5"; - case R_HTTP: - return "http"; - case R_FTP: - return "ftp"; - case R_POP3: - return "pop3"; - default: - return ""; + int i; + + for(i=0; redirs[i].name; i++){ + if(((struct chain *)node->value) -> type == redirs[i].redir) return redirs[i].name; } + return ""; } static void * ef_chain_addr(struct node * node){ diff --git a/src/proxymain.c b/src/proxymain.c index e0612cd..e7014f6 100644 --- a/src/proxymain.c +++ b/src/proxymain.c @@ -74,6 +74,37 @@ void * threadfunc (void *p) { #endif #endif + if(param->srv->haproxy){ + char buf[128]; + int i; + i = sockgetlinebuf(param, CLIENT, (unsigned char *)buf, sizeof(buf)-1, '\n', conf.timeouts[STRING_S]); + if(i > 12 && !strncasecmp(buf, "PROXY TCP", 9)){ + char *token, *token2=NULL; + unsigned short u1=0, u2=0; + buf[i] = 0; + token = strchr(buf, ' '); + if(token) token = strchr(token+1, ' '); + if(token) token++; + if(token) token2 = strchr(token+1, ' '); + if(token2) { + *token2 = 0; + getip46(46, (unsigned char*) token, (struct sockaddr *)¶m->sincr); + token = token2+1; + token2 = strchr(token, ' '); + } + if(token2) { + *token2 = 0; + getip46(46, (unsigned char *) token, (struct sockaddr *)¶m->sincl); + token = token2+1; + token2 = strchr(token, ' '); + } + if(token){ + sscanf(token,"%hu%hu", &u1, &u2); + if(u1) *SAPORT(¶m->sincr) = htons(u1); + if(u2) *SAPORT(¶m->sincl) = htons(u1); + } + } + } ((struct clientparam *) p)->srv->pf((struct clientparam *)p); } #ifdef _WIN32 @@ -417,6 +448,9 @@ int MODULEMAINFUNC (int argc, char** argv){ case 'h': hostname = argv[i] + 2; break; + case 'H': + srv.haproxy=1; + break; case 'c': srv.requirecert = 1; if(isdigit(argv[i][2])) srv.requirecert = atoi(argv[i]+2); diff --git a/src/structures.h b/src/structures.h index a2f5ba7..34ff581 100644 --- a/src/structures.h +++ b/src/structures.h @@ -266,7 +266,7 @@ struct passwords { }; typedef enum { - R_TCP, + R_TCP = 1, R_CONNECT, R_SOCKS4, R_SOCKS5, @@ -281,9 +281,20 @@ typedef enum { R_SOCKS5B, R_ADMIN, R_EXTIP, - R_TLS + R_TLS, + R_HA, + R_DNS } REDIRTYPE; +struct redirdesc { + REDIRTYPE redir; + char * name; + void * (*func)(struct clientparam *); +}; + +extern struct redirdesc redirs[]; + + struct chain { struct chain * next; int type; @@ -490,6 +501,7 @@ struct srvparam { int clisockopts, srvsockopts, lissockopts, cbcsockopts, cbssockopts; int gracetraf, gracenum, gracedelay; int requirecert; + int haproxy; #ifdef WITHSPLICE int usesplice; #endif