Package: stunnel4 Version: 2:4.070-2 Severity: wishlist Tags: patch
Hello, Included is the dunbar-proxy-connect patch updated against version 4.07. Could you include it in your debian package and forward it to upstream? Thanks in advance, Peter -- System Information: Debian Release: 3.1 APT prefers unstable APT policy: (990, 'unstable'), (500, 'testing') Architecture: i386 (i686) Kernel: Linux 2.6.10-my-2 Locale: [EMAIL PROTECTED], LC_CTYPE=it_IT (charmap=ISO-8859-1) Versions of packages stunnel4 depends on: ii libc6 2.3.2.ds1-20 GNU C Library: Shared libraries an ii libssl0.9.7 0.9.7e-3 SSL shared libraries ii libwrap0 7.6.dbs-6 Wietse Venema's TCP wrappers libra ii netbase 4.19 Basic TCP/IP networking system ii openssl 0.9.7e-3 Secure Socket Layer (SSL) binary a -- no debconf information
diff -ubdNr stunnel4-4.070-original/src/client.c stunnel4-4.070-patched/src/client.c --- stunnel4-4.070-original/src/client.c 2005-01-02 22:35:22.000000000 +0100 +++ stunnel4-4.070-patched/src/client.c 2005-01-18 11:52:39.000000000 +0100 @@ -75,6 +75,7 @@ static int connect_remote(CLI *c); static int connect_wait(int, int); static void reset(int, char *); +int connect_to_finaldest(CLI *c, int s); int max_clients; #ifndef USE_WIN32 @@ -952,7 +953,8 @@ s_ntop(c->connecting_address, &addr); s_log(LOG_DEBUG, "%s connecting %s", c->opt->servname, c->connecting_address); - if(!connect(s, &addr.sa, addr_len(addr))) + if(!connect(s, &addr.sa, addr_len(addr)) + && !connect_to_finaldest(c, s)) return s; /* no error -> success (should not be possible) */ error=get_last_socket_error(); if(error!=EINPROGRESS && error!=EWOULDBLOCK) { @@ -962,7 +964,11 @@ continue; /* next IP */ } if(!connect_wait(s, c->opt->timeout_connect)) + { + /* we got a connection */ + if (!connect_to_finaldest(c, s)) return s; /* success! */ + } closesocket(s); /* error -> next IP */ } return -1; @@ -1015,4 +1021,292 @@ log_error(LOG_DEBUG, get_last_socket_error(), txt); } +/* + * Base 64 encoding algorithm from: Bob Deblier <[EMAIL PROTECTED]> + * Modified by Daniel Savard <[EMAIL PROTECTED]> to accept char * + */ +static const char* to_b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +char* b64enc(const char* data) { + int divider = strlen(data) / 3; + int remainder = strlen(data) % 3; + int chars = divider*4 + remainder + 1; + char* string = (char*) malloc(chars + 1); + + if (string) { + register char* buf = string; + chars = 0; + while (divider > 0) { + buf[0] = to_b64[ (data[0] >> 2) & 0x3f]; + buf[1] = to_b64[((data[0] << 4) & 0x30) + ((data[1] >> 4) & 0xf)]; + buf[2] = to_b64[((data[1] << 2) & 0x3c) + ((data[2] >> 6) & 0x3)]; + buf[3] = to_b64[ data[2] & 0x3f]; + data += 3; + buf += 4; + divider--; + chars += 4; + } + + switch (remainder) { + case 2: + buf[0] = to_b64[ (data[0] >> 2) & 0x3f]; + buf[1] = to_b64[((data[0] << 4) & 0x30) + ((data[1] >> 4) & 0xf)]; + buf[2] = to_b64[ (data[1] << 2) & 0x3c]; + buf[3] = '='; + buf += 4; + chars += 4; + break; + case 1: + buf[0] = to_b64[ (data[0] >> 2) & 0x3f]; + buf[1] = to_b64[ (data[0] << 4) & 0x30]; + buf[2] = '='; + buf[3] = '='; + buf += 4; + chars += 4; + break; + } + + *buf = '\0'; + } + +return string; +} + +/* + * Base 64 decoding algorithm from: Bob Deblier <[EMAIL PROTECTED]> + * Modified by Daniel Savard <[EMAIL PROTECTED]> to return char * + */ +char* b64dec(const char* string) +{ + /* return a decoded char string, or a null pointer in case of failure */ + char* data = NULL; + + if (string) { + register int length = strlen(string); + + /* do a format verification first */ + if (length > 0) { + register int count = 0, rem = 0; + register const char* tmp = string; + + while (length > 0) { + register int skip = strspn(tmp, to_b64); + count += skip; + length -= skip; + tmp += skip; + if (length > 0) { + register int i, vrfy = strcspn(tmp, to_b64); + + for (i = 0; i < vrfy; i++) { + if (isspace(tmp[i])) + continue; + + if (tmp[i] == '=') { + /* we should check if we're close to the end of the string */ + rem = count % 4; + + /* rem must be either 2 or 3, otherwise no '=' should be here */ + if (rem < 2) + return NULL; + + /* end-of-message recognized */ + break; + } else { + /* Transmission error; RFC tells us to ignore this, but: + * - the rest of the message is going to even more corrupt since we're sliding bits out of place + * If a message is corrupt, it should be dropped. Period. + */ + return NULL; + } + } + + length -= vrfy; + tmp += vrfy; + } + } + + data = (unsigned char *)malloc((count / 4) * 3 + (rem ? (rem - 1) : 0)); + + if (data) { + if (count > 0) { + register int i, qw = 0, tw = 0; + + length = strlen(tmp = string); + + for (i = 0; i < length; i++) { + register char ch = string[i]; + register char bits = 0; + + if (isspace(ch)) + continue; + + if ((ch >= 'A') && (ch <= 'Z')) { + bits = (ch - 'A'); + } else if ((ch >= 'a') && (ch <= 'z')) { + bits = (ch - 'a' + 26); + } else if ((ch >= '0') && (ch <= '9')) { + bits = (ch - '0' + 52); + } else if (ch == '=') { + break; + } + + switch (qw++) { + case 0: + data[tw+0] = (bits << 2) & 0xfc; + break; + case 1: + data[tw+0] |= (bits >> 4) & 0x03; + data[tw+1] = (bits << 4) & 0xf0; + break; + case 2: + data[tw+1] |= (bits >> 2) & 0x0f; + data[tw+2] = (bits << 6) & 0xc0; + break; + case 3: + data[tw+2] |= bits & 0x3f; + break; + } + + if (qw == 4) { + qw = 0; + tw += 3; + } + } + + data[tw] = '\0'; + } + } + } + } + +return data; +} + +/* + * Original https proxy algorithm from: Tan Swee Heng <[EMAIL PROTECTED]> + * Modified by Daniel Savard <[EMAIL PROTECTED]> to support basic authentication + */ + int connect_to_finaldest(CLI *c, int s) { + char buff[STRLEN]; + int len, code,position,num; + char httpsproxy_auth[STRLEN] = ""; + char httpsproxy_useragent[STRLEN] = ""; + + if (!c->opt->option.httpsproxy) + return 0; + + if (c->opt->httpsproxy_auth != NULL) { + if (strchr(c->opt->httpsproxy_auth,':')) { + /* httpsproxy_auth in the form name:password' */ + char *base64_auth = b64enc(c->opt->httpsproxy_auth); + s_log(LOG_DEBUG,"proxy: authenticate with '%s' -> '%s'\n",c->opt->httpsproxy_auth,base64_auth); + sprintf(httpsproxy_auth,"Proxy-Authorization: Basic %s\r\n",base64_auth); + free(base64_auth); + } else { + /* httpsproxy_auth already base64 encoded */ + char *normal_auth = b64dec(c->opt->httpsproxy_auth); + s_log(LOG_DEBUG,"proxy: authenticate with '%s' -> '%s'\n",normal_auth,c->opt->httpsproxy_auth); + sprintf(httpsproxy_auth,"Proxy-Authorization: Basic %s\r\n",c->opt->httpsproxy_auth); + free(normal_auth); + } + } else { + s_log(LOG_DEBUG,"proxy: no authentication specified"); + } + + if (c->opt->httpsproxy_useragent != NULL) { + sprintf(httpsproxy_useragent,"User-Agent: %s\r\n",c->opt->httpsproxy_useragent); + s_log(LOG_DEBUG,"proxy: useragent '%s' -> '%s'\n",c->opt->httpsproxy_useragent,httpsproxy_useragent); + } else { + s_log(LOG_DEBUG,"proxy: no useragent specified"); + } + +#ifdef HAVE_SNPRINTF + len=snprintf(buff, STRLEN, +#else + len=sprintf(buff, +#endif + "CONNECT %s HTTP/1.0\r\n%s%s\r\n", + c->opt->httpsproxy_dest_address, + httpsproxy_auth, + httpsproxy_useragent); + + + s_log(LOG_DEBUG, "me ---> proxy: %s", buff); + for(position=0;position<len;) { + switch(num=writesocket(s, buff+position, len-position)) { + case -1: /* error */ + switch(get_last_socket_error()) { + case EINTR: + s_log(LOG_DEBUG, + "writesocket of proxy connect interrupted by a signal: retrying"); + break; + case EWOULDBLOCK: + s_log(LOG_NOTICE, "writesocket would block: retrying"); + break; + default: + sockerror("writesocket (httpsproxy)"); + closesocket(s); + return -1; + } + break; + case 0: + s_log(LOG_DEBUG, "No data written to the proxy socket: retrying"); + break; + default: + position+=num; + } + } + s_log(LOG_DEBUG, "done sending\n"); + + + if(connect_wait(s, c->opt->timeout_busy)) { + s_log(LOG_ERR,"timeout while wainting for reply to command '%s'\n", + buff); + return -1; + } + + + /* get a line */ + for(position=0; (position == 0) || (buff[position-1] != '\n');) { + switch(num=readsocket(s, buff+position, STRLEN-1-position)) { + case -1: + switch(get_last_socket_error()) { + case EINTR: + s_log(LOG_DEBUG, + "readsocket for proxy interrupted by a signal: retrying"); + break; + case EWOULDBLOCK: + buff[position+num]='\0'; + s_log(LOG_NOTICE, "readsocket for proxy would block: retrying, got: '%s'",buff); + break; + default: + sockerror("readsocket for proxy"); + closesocket(s); + return -1; + } + break; + case 0: /* close */ + s_log(LOG_DEBUG, "Socket closed on read for proxy"); + break; + default: + position+=num; + } + } + + buff[position]='\0'; + s_log(LOG_DEBUG, "proxy ---> me: %s", buff); + + code = 0; + if(sscanf(buff, "HTTP/%*s %d %*s", &code) != 1) { + s_log(LOG_ERR, "error: %s", buff); + return -1; + } + + if(code != 200) { + s_log(LOG_WARNING, "return code not 200: %s", buff); + return -1; + } + + return 0; +} + /* End of client.c */ diff -ubdNr stunnel4-4.070-original/src/options.c stunnel4-4.070-patched/src/options.c --- stunnel4-4.070-original/src/options.c 2004-12-31 09:53:40.000000000 +0100 +++ stunnel4-4.070-patched/src/options.c 2005-01-18 11:15:18.000000000 +0100 @@ -788,6 +788,84 @@ } #endif + /* Daniel Savard <[EMAIL PROTECTED]> + * httpsproxy_auth + * Optional parameter to httpsproxy_dest to specify authentication + * credential to the https proxy. Value must be in form name:password + * or the base64 encoded value of the preceding form. + */ + switch(cmd) { + case CMD_INIT: + section->httpsproxy_auth=NULL; + break; + case CMD_EXEC: + if(strcasecmp(opt, "httpsproxy_auth")) + break; + section->httpsproxy_auth=stralloc(arg); + return NULL; /* OK */ + case CMD_DEFAULT: + break; + case CMD_HELP: + log_raw("%-15s = authentication for 'httpsproxy' must be userid:password", + "httpsproxy_auth"); + break; + } + + /* Daniel Savard <[EMAIL PROTECTED]> + * httpsproxy_dest + * When specified, the connect parameter will specify the name of a https + * proxy server and this parameter will be the final destination. + */ + switch(cmd) { + case CMD_INIT: + section->option.httpsproxy=0; + section->httpsproxy_dest_address=NULL; + memset(§ion->httpsproxy_dest_names, 0, sizeof(SOCKADDR_LIST)); + section->httpsproxy_dest_names.addr[0].in.sin_family=AF_INET; + section->httpsproxy_dest_port=0; + break; + case CMD_EXEC: + if(strcasecmp(opt, "httpsproxy_dest")) + break; + section->option.httpsproxy=1; + section->httpsproxy_dest_address=stralloc(arg); + + if(!section->option.delayed_lookup && + !name2addrlist(§ion->httpsproxy_dest_names, arg, DEFAULT_LOOPBACK)) { + log_raw("Cannot resolve '%s' - delaying DNS lookup", arg); + section->option.delayed_lookup=1; + } + return NULL; /* OK */ + case CMD_DEFAULT: + break; + case CMD_HELP: + log_raw("%-15s = [host:]port https proxy connect destination host:port", + "httpsproxy_dest"); + break; + } + + /* Daniel Savard <[EMAIL PROTECTED]> + * httpsproxy_useragent + * Optional parameter to httpsproxy_dest. When specified, the specified + * user-agent will be sent to the proxy + */ + switch(cmd) { + case CMD_INIT: + section->httpsproxy_useragent=NULL; + break; + case CMD_EXEC: + if(strcasecmp(opt, "httpsproxy_useragent")) + break; + section->httpsproxy_useragent=stralloc(arg); + return NULL; /* OK */ + case CMD_DEFAULT: + break; + case CMD_HELP: + log_raw("%-15s = useragent for 'httpsproxy'", + "httpsproxy_useragent"); + break; + } + /* ident */ switch(cmd) { case CMD_INIT: diff -ubdNr stunnel4-4.070-original/src/prototypes.h stunnel4-4.070-patched/src/prototypes.h --- stunnel4-4.070-original/src/prototypes.h 2005-01-02 23:43:23.000000000 +0100 +++ stunnel4-4.070-patched/src/prototypes.h 2005-01-18 11:10:13.000000000 +0100 @@ -181,10 +181,12 @@ /* service-specific data for client.c */ int fd; /* file descriptor accepting connections for this service */ char *execname, **execargs; /* program name and arguments for local mode */ - SOCKADDR_LIST local_addr, remote_addr; + SOCKADDR_LIST local_addr, remote_addr, httpsproxy_dest_names; SOCKADDR_LIST source_addr; char *username; char *remote_address; + char *httpsproxy_auth, *httpsproxy_useragent, *httpsproxy_dest_address; + unsigned short httpsproxy_dest_port; int timeout_busy; /* Maximum waiting for data time */ int timeout_close; /* Maximum close_notify time */ int timeout_connect; /* Maximum connect() time */ @@ -198,6 +200,43 @@ unsigned int delayed_lookup:1; unsigned int accept:1; unsigned int remote:1; + unsigned int httpsproxy:1; #ifndef USE_WIN32 unsigned int program:1; unsigned int pty:1;