X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=gateway.c;h=b83d10d9ea8579e4be1f649560dde29006039f87;hp=2eec9956e9f5f5b3345e867acf78220a471f5901;hb=98680dd7a1a8ca55e4cd3228f3710cd136514be1;hpb=1a096731122473db56caec3c5170be99fcf8aa06 diff --git a/gateway.c b/gateway.c index 2eec9956..b83d10d9 100644 --- a/gateway.c +++ b/gateway.c @@ -1,4 +1,4 @@ -const char gateway_rcs[] = "$Id: gateway.c,v 1.21 2007/07/28 12:30:03 fabiankeil Exp $"; +const char gateway_rcs[] = "$Id: gateway.c,v 1.24 2008/02/04 14:56:29 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/gateway.c,v $ @@ -34,6 +34,16 @@ const char gateway_rcs[] = "$Id: gateway.c,v 1.21 2007/07/28 12:30:03 fabiankeil * * Revisions : * $Log: gateway.c,v $ + * Revision 1.24 2008/02/04 14:56:29 fabiankeil + * - Fix a compiler warning. + * - Stop assuming that htonl(INADDR_NONE) equals INADDR_NONE. + * + * Revision 1.23 2008/02/04 13:11:35 fabiankeil + * Remember the cause of the SOCKS5 error for the CGI message. + * + * Revision 1.22 2008/02/03 13:46:15 fabiankeil + * Add SOCKS5 support. Patch #1862863 by Eric M. Hopper with minor changes. + * * Revision 1.21 2007/07/28 12:30:03 fabiankeil * Modified patch from Song Weijia (#1762559) to * fix socks requests on big-endian platforms. @@ -305,7 +315,7 @@ static jb_socket socks4_connect(const struct forward_spec * fwd, int target_port, struct client_state *csp) { - int web_server_addr; + unsigned int web_server_addr; char buf[BUFFER_SIZE]; struct socks_op *c = (struct socks_op *)buf; struct socks_reply *s = (struct socks_reply *)buf; @@ -345,13 +355,17 @@ static jb_socket socks4_connect(const struct forward_spec * fwd, switch (fwd->type) { case SOCKS_4: - web_server_addr = htonl(resolve_hostname_to_ip(target_host)); + web_server_addr = resolve_hostname_to_ip(target_host); if (web_server_addr == INADDR_NONE) { errstr = "could not resolve target host"; log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s %s", errstr, target_host); err = 1; } + else + { + web_server_addr = htonl(web_server_addr); + } break; case SOCKS_4A: web_server_addr = 0x00000001; @@ -471,6 +485,45 @@ static jb_socket socks4_connect(const struct forward_spec * fwd, } +/********************************************************************* + * + * Function : translate_socks5_error + * + * Description : Translates a SOCKS errors to a string. + * + * Parameters : + * 1 : socks_error = The error code to translate. + * + * Returns : The string translation. + * + *********************************************************************/ +static const char *translate_socks5_error(int socks_error) +{ + switch (socks_error) + { + /* XXX: these should be more descriptive */ + case SOCKS5_REQUEST_FAILED: + return "SOCKS5 request failed"; + case SOCKS5_REQUEST_DENIED: + return "SOCKS5 request denied"; + case SOCKS5_REQUEST_NETWORK_UNREACHABLE: + return "SOCKS5 network unreachable"; + case SOCKS5_REQUEST_HOST_UNREACHABLE: + return "SOCKS5 host unreachable"; + case SOCKS5_REQUEST_CONNECTION_REFUSEDD: + return "SOCKS5 connection refused"; + case SOCKS5_REQUEST_TTL_EXPIRED: + return "SOCKS5 TTL expired"; + case SOCKS5_REQUEST_PROTOCOL_ERROR: + return "SOCKS5 client protocol error"; + case SOCKS5_REQUEST_BAD_ADDRESS_TYPE: + return "SOCKS5 domain names unsupported"; + case SOCKS5_REQUEST_GRANTED: + return "everything's peachy"; + default: + return "SOCKS5 negotiation protocol error"; + } +} /********************************************************************* * @@ -497,42 +550,53 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, struct client_state *csp) { int err = 0; - char cbuf[BUFFER_SIZE]; - char sbuf[BUFFER_SIZE]; + char cbuf[300]; + char sbuf[30]; size_t client_pos = 0; int server_size = 0; size_t hostlen = 0; jb_socket sfd; + const char *errstr = NULL; + assert(fwd->gateway_host); if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0')) { - log_error(LOG_LEVEL_CONNECT, "socks5_connect: NULL gateway host specified"); + errstr = "NULL gateway host specified"; err = 1; } if (fwd->gateway_port <= 0) { - log_error(LOG_LEVEL_CONNECT, "socks5_connect: invalid gateway port specified"); + /* + * XXX: currently this can't happen because in + * case of invalid gateway ports we use the defaults. + * Of course we really shouldn't do that. + */ + errstr = "invalid gateway port specified"; err = 1; } hostlen = strlen(target_host); if (hostlen > 255) { - log_error(LOG_LEVEL_CONNECT, "socks5_connect: target host name is longer than 255 characters."); + errstr = "target host name is longer than 255 characters"; err = 1; } if (fwd->type != SOCKS_5) { /* Should never get here */ - log_error(LOG_LEVEL_FATAL, "SOCKS5 impossible internal error - bad SOCKS type."); + log_error(LOG_LEVEL_FATAL, + "SOCKS5 impossible internal error - bad SOCKS type"); err = 1; } if (err) { errno = EINVAL; + assert(errstr != NULL); + log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr); + csp->error_message = strdup(errstr); return(JB_INVALID_SOCKET); } @@ -541,6 +605,9 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, if (sfd == JB_INVALID_SOCKET) { + errstr = "socks5 server unreachable"; + log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr); + csp->error_message = strdup(errstr); return(JB_INVALID_SOCKET); } @@ -551,37 +618,42 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, if (write_socket(sfd, cbuf, client_pos)) { - log_error(LOG_LEVEL_CONNECT, "SOCKS5 negotiation write failed..."); + errstr = "SOCKS5 negotiation write failed"; + csp->error_message = strdup(errstr); + log_error(LOG_LEVEL_CONNECT, "%s", errstr); close_socket(sfd); return(JB_INVALID_SOCKET); } if (read_socket(sfd, sbuf, sizeof(sbuf)) != 2) { - log_error(LOG_LEVEL_CONNECT, "SOCKS5 negotiation read failed..."); + errstr = "SOCKS5 negotiation read failed"; err = 1; } if (!err && (sbuf[0] != '\x05')) { - log_error(LOG_LEVEL_CONNECT, "SOCKS5 negotiation protocol version error"); + errstr = "SOCKS5 negotiation protocol version error"; err = 1; } if (!err && (sbuf[1] == '\xff')) { - log_error(LOG_LEVEL_CONNECT, "SOCKS5 authentication required"); + errstr = "SOCKS5 authentication required"; err = 1; } if (!err && (sbuf[1] != '\x00')) { - log_error(LOG_LEVEL_CONNECT, "SOCKS5 negotiation protocol error"); + errstr = "SOCKS5 negotiation protocol error"; err = 1; } if (err) { + assert(errstr != NULL); + log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr); + csp->error_message = strdup(errstr); close_socket(sfd); errno = EINVAL; return(JB_INVALID_SOCKET); @@ -593,14 +665,18 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, cbuf[client_pos++] = '\x00'; /* Reserved, must be 0x00 */ cbuf[client_pos++] = '\x03'; /* Address is domain name */ cbuf[client_pos++] = (char)(hostlen & 0xffu); - strncpy(cbuf + client_pos, target_host, 0xffu); + assert(sizeof(cbuf) - client_pos > 255); + /* Using strncpy because we really want the nul byte padding. */ + strncpy(cbuf + client_pos, target_host, sizeof(cbuf) - client_pos); client_pos += (hostlen & 0xffu); cbuf[client_pos++] = (char)((target_port >> 8) & 0xffu); cbuf[client_pos++] = (char)((target_port ) & 0xffu); if (write_socket(sfd, cbuf, client_pos)) { - log_error(LOG_LEVEL_CONNECT, "SOCKS5 negotiation write failed..."); + errstr = "SOCKS5 negotiation read failed"; + csp->error_message = strdup(errstr); + log_error(LOG_LEVEL_CONNECT, "%s", errstr); close_socket(sfd); errno = EINVAL; return(JB_INVALID_SOCKET); @@ -609,63 +685,47 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, server_size = read_socket(sfd, sbuf, sizeof(sbuf)); if (server_size < 3) { - log_error(LOG_LEVEL_CONNECT, "SOCKS5 negotiation read failed..."); + errstr = "SOCKS5 negotiation read failed"; err = 1; } + else if (server_size > 20) + { + /* This is somewhat unexpected but doesn't realy matter. */ + log_error(LOG_LEVEL_CONNECT, "socks5_connect: read %d bytes " + "from socks server. Would have accepted up to %d.", + server_size, sizeof(sbuf)); + } if (!err && (sbuf[0] != '\x05')) { - log_error(LOG_LEVEL_CONNECT, "SOCKS5 negotiation protocol version error"); + errstr = "SOCKS5 negotiation protocol version error"; err = 1; } if (!err && (sbuf[2] != '\x00')) { - log_error(LOG_LEVEL_CONNECT, "SOCKS5 negotiation protocol error"); + errstr = "SOCKS5 negotiation protocol error"; err = 1; } if (!err) { - switch (sbuf[1]) + if (sbuf[1] == SOCKS5_REQUEST_GRANTED) { - case SOCKS5_REQUEST_GRANTED: - return(sfd); - break; - case SOCKS5_REQUEST_FAILED: - log_error(LOG_LEVEL_CONNECT, "SOCKS5 request failed"); - break; - case SOCKS5_REQUEST_DENIED: - log_error(LOG_LEVEL_CONNECT, "SOCKS5 request denied"); - break; - case SOCKS5_REQUEST_NETWORK_UNREACHABLE: - log_error(LOG_LEVEL_CONNECT, "SOCKS5 request - network unreachable"); - break; - case SOCKS5_REQUEST_HOST_UNREACHABLE: - log_error(LOG_LEVEL_CONNECT, "SOCKS5 request - host unreachable"); - break; - case SOCKS5_REQUEST_CONNECTION_REFUSEDD: - log_error(LOG_LEVEL_CONNECT, "SOCKS5 request - connection refused"); - break; - case SOCKS5_REQUEST_TTL_EXPIRED: - log_error(LOG_LEVEL_CONNECT, "SOCKS5 request - TTL expired"); - break; - case SOCKS5_REQUEST_PROTOCOL_ERROR: - log_error(LOG_LEVEL_CONNECT, "SOCKS5 request - client protocol error"); - break; - case SOCKS5_REQUEST_BAD_ADDRESS_TYPE: - log_error(LOG_LEVEL_CONNECT, "SOCKS5 request - domain names unsupported"); - break; - default: - log_error(LOG_LEVEL_CONNECT, "SOCKS5 negotiation protocol error"); - break; + return(sfd); } + errstr = translate_socks5_error(sbuf[1]); err = 1; } + assert(errstr != NULL); + csp->error_message = strdup(errstr); + log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr); close_socket(sfd); errno = EINVAL; + return(JB_INVALID_SOCKET); + } /*