diff --git a/ctrl/sbbs.ini b/ctrl/sbbs.ini index a211078726d359ce1c57c6214f91214d5571d4be..0a717ce8c7ba306018b27ebcf7424c52b03ca0d7 100644 --- a/ctrl/sbbs.ini +++ b/ctrl/sbbs.ini @@ -137,6 +137,7 @@ ; NO_RECYCLE ; GET_IDENT ; MUTE +; HAPROXY_PROTO Options = XTRN_MINIMIZED | ALLOW_RLOGIN | ALLOW_SSH [Mail] SMTP/POP3 Mail Server diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp index 499f6670ece3a5d1696d75e771e39c045fce78c5..b5db52142dbbfe8ebb1d017499563a3d9b6b4f59 100644 --- a/src/sbbs3/main.cpp +++ b/src/sbbs3/main.cpp @@ -4933,6 +4933,9 @@ static void cleanup(int code) void DLLCALL bbs_thread(void* arg) { + struct addrinfo *res; + unsigned char hapstr[108]; + char host_name[256]; char* identity; char* p; @@ -4942,7 +4945,7 @@ void DLLCALL bbs_thread(void* arg) union xp_sockaddr client_addr; socklen_t client_addr_len; SOCKET client_socket=INVALID_SOCKET; - int i; + int i,l; int file; int result; time_t t; @@ -5449,7 +5452,132 @@ NO_SSH: } char host_ip[INET6_ADDRSTRLEN]; - inet_addrtop(&client_addr, host_ip, sizeof(host_ip)); + // Set host_ip from haproxy protocol, if its used + // http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt + if(startup->options&BBS_OPT_HAPROXY_PROTO) { + lprintf(LOG_INFO,"%04d Working out client address from HAPROXY PROTO",client_socket); + memset(hapstr,'\0',sizeof(hapstr)); + memset(host_ip,'\0',sizeof(host_ip)); + + // Read the first 5 chars to work out what we are dealing with + recv(client_socket,hapstr,5,0); + lprintf(LOG_DEBUG,"%04d * GOT (%s) [%x]",client_socket,hapstr,i); + + if (strcmp((char *)hapstr,"PROXY") == 0) { + lprintf(LOG_DEBUG,"%04d * HAPROXY PROTO v1",client_socket); + recv(client_socket,hapstr,1,0); // \x20 + + // Get Protocol + memset(hapstr,'\0',sizeof(hapstr)); + recv(client_socket,hapstr,4,0); + lprintf(LOG_DEBUG,"%04d * GOT (%s) [%x]",client_socket,hapstr,i); + + // IPV4 + if (strcmp((char *)hapstr,"TCP4") == 0) { + lprintf(LOG_DEBUG,"%04d * Proto [%s]",client_socket,hapstr); + recv(client_socket,hapstr,1,0); // \x20 + + // Source Address + recv(client_socket,hapstr,16,0); + + // IPV6 + } else if (strcmp((char *)hapstr,"TCP6") == 0) { + lprintf(LOG_DEBUG,"%04d * Proto %s",client_socket,hapstr); + i=recv(client_socket,hapstr,1,0); // \x20 + + // Source Address + recv(client_socket,hapstr,40,0); + + // Unknown? + } else if (strcmp((char *)hapstr,"UNKN") == 0) { + lprintf(LOG_DEBUG,"%04d * Unknown Protocol",client_socket); + close_socket(client_socket); + continue; + } + + // Look for the space between the next IP + for(i=0;i<sizeof(hapstr);i++) { + if (hapstr[i] == 0x20) + break; + } + + hapstr[i]='\0'; + memcpy(host_ip,hapstr,i); + + } else if (strcmp((char *)hapstr,"\x0d\x0a\x0d\x0a\x00") == 0) { + lprintf(LOG_DEBUG,"%04d * HAPROXY PROTO v2",client_socket); + recv(client_socket,hapstr,7,0); // \x0d\x0aQUIT\x0a + memset(hapstr,'\0',sizeof(hapstr)); + + // Command and Version + recv(client_socket,hapstr,1,0); + i = hapstr[0]; + lprintf(LOG_DEBUG,"%04d * Version [%x]",client_socket,(i>>0)&((1<<4)-1)); //Should be 2 + lprintf(LOG_DEBUG,"%04d * Command [%x]",client_socket,(i>>4)&((1<<4)-1)); //0=Local/1=Proxy + + // Protocol and Family + recv(client_socket,hapstr,1,0); + i = hapstr[0]; + lprintf(LOG_DEBUG,"%04d * Protocol [%x]",client_socket,(i>>0)&((1<<4)-1)); //0=Unspec/1=AF_INET/2=AF_INET6/3=AF_UNIX + l = (i>>4)&((1<<4)-1); + lprintf(LOG_DEBUG,"%04d * Family [%x]",client_socket,l); //0=UNSPEC/1=STREAM/2=DGRAM + + // Address Length + recv(client_socket,hapstr,2,0); + sscanf((char *)hapstr,"%x",&i); + lprintf(LOG_DEBUG,"%04d * Address Length [%d]",client_socket,i); + + recv(client_socket,hapstr,i,0); + + switch (l) { + // IPv4 - AF_INET + case 0x1: + sprintf(host_ip,"%d.%d.%d.%d",hapstr[0],hapstr[1],hapstr[2],hapstr[3]); + break; + + // IPv6 - AF_INET6 + case 0x2: + // IPv4 address in IPv6 ::ffff:n.n.n.n + // 0000:0000:0000:0000:0000:ffff:0a01:039c + for(i=0;i<10;i++) { + if (hapstr[i] != 0x00) + break; + } + + if ((i==10) && (hapstr[i] == 0xff) && (hapstr[i+1] == 0xff)) { + sprintf(host_ip,"%d.%d.%d.%d",hapstr[12],hapstr[13],hapstr[14],hapstr[15]); + lprintf(LOG_DEBUG,"%04d * IPv4 address in IPv6 [%s]",client_socket,host_ip); + + } else { + sprintf(host_ip,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + hapstr[0],hapstr[1],hapstr[2],hapstr[3], + hapstr[4],hapstr[5],hapstr[6],hapstr[7], + hapstr[8],hapstr[9],hapstr[10],hapstr[11], + hapstr[12],hapstr[13],hapstr[14],hapstr[15] + ); + } + break; + + default: + lprintf(LOG_DEBUG,"%04d * Unknown Family",client_socket); + close_socket(client_socket); + continue; + } + + + } else { + lprintf(LOG_ERR,"%04d Unknown HAProxy Initialisation - is HAProxy used?",client_socket); + close_socket(client_socket); + continue; + } + + lprintf(LOG_DEBUG,"%04d * Source [%s]",client_socket,host_ip); + getaddrinfo(host_ip,NULL,NULL,&res); + client_addr.addr = *res->ai_addr; + + } else { + inet_addrtop(&client_addr, host_ip, sizeof(host_ip)); + } if(trashcan(&scfg,host_ip,"ip-silent")) { close_socket(client_socket); diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c index 14aa6c479235a0cbb8b7ea81d62cd86ca4091bb4..03ac2d844c47b1a75f8ab5a989b8ef6c9eb04f4b 100644 --- a/src/sbbs3/services.c +++ b/src/sbbs3/services.c @@ -2129,6 +2129,12 @@ void DLLCALL services_thread(void* arg) } inet_addrtop(&client_addr, host_ip, sizeof(host_ip)); + // Set host_ip from haproxy protocol, if its used + if(startup->options&BBS_OPT_HAPROXY_PROTO) { + lprintf(LOG_INFO,"** Working out address from HAPROXY PROTO"); + } + lprintf(LOG_INFO,"** Startup options %d (%d)",startup->options,BBS_OPT_HAPROXY_PROTO); + if(trashcan(&scfg,host_ip,"ip-silent")) { FREE_AND_NULL(udp_buf); close_socket(client_socket); diff --git a/src/sbbs3/startup.h b/src/sbbs3/startup.h index 6d3a205a05d4ee37f51634c98e6674d377bfb167..877f8f811c600d7f4937ace7e8c2b3bb3b32dc99 100644 --- a/src/sbbs3/startup.h +++ b/src/sbbs3/startup.h @@ -190,6 +190,7 @@ static struct init_field { #define BBS_OPT_ALLOW_SSH (1<<12) /* Allow logins via BSD SSH */ #define BBS_OPT_NO_DOS (1<<13) /* Don't attempt to run 16-bit DOS programs */ #define BBS_OPT_NO_NEWDAY_EVENTS (1<<14) /* Don't check for a new day in event thread */ +#define BBS_OPT_HAPROXY_PROTO (1<<26) /* Incoming requests are via HAproxy */ #define BBS_OPT_NO_RECYCLE (1<<27) /* Disable recycling of server */ #define BBS_OPT_GET_IDENT (1<<28) /* Get Identity (RFC 1413) */ #define BBS_OPT_NO_JAVASCRIPT (1<<29) /* JavaScript disabled */ @@ -197,7 +198,7 @@ static struct init_field { /* bbs_startup_t.options bits that require re-init/recycle when changed */ #define BBS_INIT_OPTS (BBS_OPT_ALLOW_RLOGIN|BBS_OPT_ALLOW_SSH|BBS_OPT_NO_EVENTS|BBS_OPT_NO_SPY_SOCKETS \ - |BBS_OPT_NO_JAVASCRIPT) + |BBS_OPT_NO_JAVASCRIPT|BBS_OPT_HAPROXY_PROTO) #if defined(STARTUP_INI_BITDESC_TABLES) static ini_bitdesc_t bbs_options[] = { @@ -218,6 +219,7 @@ static ini_bitdesc_t bbs_options[] = { { BBS_OPT_NO_RECYCLE ,"NO_RECYCLE" }, { BBS_OPT_GET_IDENT ,"GET_IDENT" }, { BBS_OPT_NO_JAVASCRIPT ,"NO_JAVASCRIPT" }, + { BBS_OPT_HAPROXY_PROTO ,"HAPROXY_PROTO" }, { BBS_OPT_MUTE ,"MUTE" }, /* terminator */ { 0 ,NULL }