X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=gateway.c;h=ae706cfad32acaccf3272bdd630aeebc3fc988be;hp=b3dff39406151f2c937c1ac69a1f167dc45dcb87;hb=8a8d5061c4646c704b2f247225ccb6cf80561bc2;hpb=05dd2cc7b727e9600f3808d9156d94d1a3396155 diff --git a/gateway.c b/gateway.c index b3dff394..ae706cfa 100644 --- a/gateway.c +++ b/gateway.c @@ -1,4 +1,4 @@ -const char gateway_rcs[] = "$Id: gateway.c,v 1.64 2009/10/03 10:37:49 fabiankeil Exp $"; +const char gateway_rcs[] = "$Id: gateway.c,v 1.91 2012/10/21 12:56:38 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/gateway.c,v $ @@ -68,7 +68,7 @@ const char gateway_rcs[] = "$Id: gateway.c,v 1.64 2009/10/03 10:37:49 fabiankeil #include "miscutil.h" #ifdef FEATURE_CONNECTION_KEEP_ALIVE #ifdef HAVE_POLL -#ifdef __GLIBC__ +#ifdef __GLIBC__ #include #else #include @@ -88,21 +88,24 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, int target_port, struct client_state *csp); +enum { + SOCKS4_REQUEST_GRANTED = 90, + SOCKS4_REQUEST_REJECT = 91, + SOCKS4_REQUEST_IDENT_FAILED = 92, + SOCKS4_REQUEST_IDENT_CONFLICT = 93 +}; -#define SOCKS_REQUEST_GRANTED 90 -#define SOCKS_REQUEST_REJECT 91 -#define SOCKS_REQUEST_IDENT_FAILED 92 -#define SOCKS_REQUEST_IDENT_CONFLICT 93 - -#define SOCKS5_REQUEST_GRANTED 0 -#define SOCKS5_REQUEST_FAILED 1 -#define SOCKS5_REQUEST_DENIED 2 -#define SOCKS5_REQUEST_NETWORK_UNREACHABLE 3 -#define SOCKS5_REQUEST_HOST_UNREACHABLE 4 -#define SOCKS5_REQUEST_CONNECTION_REFUSED 5 -#define SOCKS5_REQUEST_TTL_EXPIRED 6 -#define SOCKS5_REQUEST_PROTOCOL_ERROR 7 -#define SOCKS5_REQUEST_BAD_ADDRESS_TYPE 8 +enum { + SOCKS5_REQUEST_GRANTED = 0, + SOCKS5_REQUEST_FAILED = 1, + SOCKS5_REQUEST_DENIED = 2, + SOCKS5_REQUEST_NETWORK_UNREACHABLE = 3, + SOCKS5_REQUEST_HOST_UNREACHABLE = 4, + SOCKS5_REQUEST_CONNECTION_REFUSED = 5, + SOCKS5_REQUEST_TTL_EXPIRED = 6, + SOCKS5_REQUEST_PROTOCOL_ERROR = 7, + SOCKS5_REQUEST_BAD_ADDRESS_TYPE = 8 +}; /* structure of a socks client operation */ struct socks_op { @@ -209,7 +212,7 @@ void remember_connection(const struct reusable_connection *connection) if (!free_slot_found) { log_error(LOG_LEVEL_CONNECT, - "No free slots found to remembering socket for %s:%d. Last slot %d.", + "No free slots found to remember socket for %s:%d. Last slot %d.", connection->host, connection->port, slot); privoxy_mutex_unlock(&connection_reuse_mutex); close_socket(connection->sfd); @@ -217,18 +220,15 @@ void remember_connection(const struct reusable_connection *connection) } assert(NULL != connection->host); - reusable_connection[slot].host = strdup(connection->host); - if (NULL == reusable_connection[slot].host) - { - log_error(LOG_LEVEL_FATAL, "Out of memory saving socket."); - } + reusable_connection[slot].host = strdup_or_die(connection->host); reusable_connection[slot].sfd = connection->sfd; reusable_connection[slot].port = connection->port; reusable_connection[slot].in_use = 0; reusable_connection[slot].timestamp = connection->timestamp; - reusable_connection->request_sent = connection->request_sent; - reusable_connection->response_received = connection->response_received; + reusable_connection[slot].request_sent = connection->request_sent; + reusable_connection[slot].response_received = connection->response_received; reusable_connection[slot].keep_alive_timeout = connection->keep_alive_timeout; + reusable_connection[slot].requests_sent_total = connection->requests_sent_total; assert(reusable_connection[slot].gateway_host == NULL); assert(reusable_connection[slot].gateway_port == 0); @@ -239,11 +239,7 @@ void remember_connection(const struct reusable_connection *connection) reusable_connection[slot].forwarder_type = connection->forwarder_type; if (NULL != connection->gateway_host) { - reusable_connection[slot].gateway_host = strdup(connection->gateway_host); - if (NULL == reusable_connection[slot].gateway_host) - { - log_error(LOG_LEVEL_FATAL, "Out of memory saving gateway_host."); - } + reusable_connection[slot].gateway_host = strdup_or_die(connection->gateway_host); } else { @@ -253,11 +249,7 @@ void remember_connection(const struct reusable_connection *connection) if (NULL != connection->forward_host) { - reusable_connection[slot].forward_host = strdup(connection->forward_host); - if (NULL == reusable_connection[slot].forward_host) - { - log_error(LOG_LEVEL_FATAL, "Out of memory saving forward_host."); - } + reusable_connection[slot].forward_host = strdup_or_die(connection->forward_host); } else { @@ -270,7 +262,6 @@ void remember_connection(const struct reusable_connection *connection) #endif /* def FEATURE_CONNECTION_SHARING */ -#ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : mark_connection_closed @@ -293,13 +284,13 @@ void mark_connection_closed(struct reusable_connection *closed_connection) closed_connection->request_sent = 0; closed_connection->response_received = 0; closed_connection->keep_alive_timeout = 0; + closed_connection->requests_sent_total = 0; closed_connection->forwarder_type = SOCKS_NONE; freez(closed_connection->gateway_host); closed_connection->gateway_port = 0; freez(closed_connection->forward_host); closed_connection->forward_port = 0; } -#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ #ifdef FEATURE_CONNECTION_SHARING @@ -335,16 +326,12 @@ void forget_connection(jb_socket sfd) sfd, reusable_connection[slot].host, reusable_connection[slot].port, slot); mark_connection_closed(&reusable_connection[slot]); - privoxy_mutex_unlock(&connection_reuse_mutex); - - return; + break; } } - log_error(LOG_LEVEL_CONNECT, - "Socket %d already forgotten or never remembered.", sfd); - privoxy_mutex_unlock(&connection_reuse_mutex); + } #endif /* def FEATURE_CONNECTION_SHARING */ @@ -383,7 +370,9 @@ int connection_destination_matches(const struct reusable_connection *connection, && strcmpic(connection->gateway_host, fwd->gateway_host)) && (connection->gateway_host != fwd->gateway_host)) { - log_error(LOG_LEVEL_CONNECT, "Gateway mismatch."); + log_error(LOG_LEVEL_CONNECT, + "Gateway mismatch. Previous gateway: %s. Current gateway: %s", + connection->gateway_host, fwd->gateway_host); return FALSE; } @@ -392,7 +381,9 @@ int connection_destination_matches(const struct reusable_connection *connection, && strcmpic(connection->forward_host, fwd->forward_host)) && (connection->forward_host != fwd->forward_host)) { - log_error(LOG_LEVEL_CONNECT, "Forwarding proxy mismatch."); + log_error(LOG_LEVEL_CONNECT, + "Forwarding proxy mismatch. Previous proxy: %s. Current proxy: %s", + connection->forward_host, fwd->forward_host); return FALSE; } @@ -503,13 +494,14 @@ static jb_socket get_reusable_connection(const struct http_request *http, reusable_connection[slot].in_use = TRUE; sfd = reusable_connection[slot].sfd; log_error(LOG_LEVEL_CONNECT, - "Found reusable socket %d for %s:%d in slot %d. " - "Timestamp made %d seconds ago. Timeout: %d. Latency: %d.", + "Found reusable socket %d for %s:%d in slot %d. Timestamp made %d " + "seconds ago. Timeout: %d. Latency: %d. Requests served: %d", sfd, reusable_connection[slot].host, reusable_connection[slot].port, slot, time(NULL) - reusable_connection[slot].timestamp, reusable_connection[slot].keep_alive_timeout, (int)(reusable_connection[slot].response_received - - reusable_connection[slot].request_sent)); + reusable_connection[slot].request_sent), + reusable_connection[slot].requests_sent_total); break; } } @@ -652,7 +644,7 @@ jb_socket forwarded_connect(const struct forward_spec * fwd, default: /* Should never get here */ log_error(LOG_LEVEL_FATAL, - "SOCKS4 impossible internal error - bad SOCKS type."); + "Internal error in forwarded_connect(). Bad proxy type: %d", fwd->type); } if (JB_INVALID_SOCKET != sfd) @@ -721,7 +713,7 @@ static jb_socket socks4_connect(const struct forward_spec * fwd, if (err) { log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr); - csp->error_message = strdup(errstr); + csp->error_message = strdup(errstr); errno = EINVAL; return(JB_INVALID_SOCKET); } @@ -790,24 +782,20 @@ static jb_socket socks4_connect(const struct forward_spec * fwd, c->vn = 4; c->cd = 1; - c->dstport[0] = (unsigned char)((target_port >> 8 ) & 0xff); - c->dstport[1] = (unsigned char)((target_port ) & 0xff); - c->dstip[0] = (unsigned char)((web_server_addr >> 24 ) & 0xff); - c->dstip[1] = (unsigned char)((web_server_addr >> 16 ) & 0xff); - c->dstip[2] = (unsigned char)((web_server_addr >> 8 ) & 0xff); - c->dstip[3] = (unsigned char)((web_server_addr ) & 0xff); + c->dstport[0] = (unsigned char)((target_port >> 8 ) & 0xff); + c->dstport[1] = (unsigned char)((target_port ) & 0xff); + c->dstip[0] = (unsigned char)((web_server_addr >> 24) & 0xff); + c->dstip[1] = (unsigned char)((web_server_addr >> 16) & 0xff); + c->dstip[2] = (unsigned char)((web_server_addr >> 8) & 0xff); + c->dstip[3] = (unsigned char)((web_server_addr ) & 0xff); /* pass the request to the socks server */ sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp); if (sfd == JB_INVALID_SOCKET) { - /* - * XXX: connect_to should fill in the exact reason. - * Most likely resolving the IP of the forwarder failed. - */ - errstr = "connect_to failed: see logfile for details"; - err = 1; + /* The error an its reason have already been logged by connect_to() */ + return(JB_INVALID_SOCKET); } else if (write_socket(sfd, (char *)c, csiz)) { @@ -816,6 +804,20 @@ static jb_socket socks4_connect(const struct forward_spec * fwd, err = 1; close_socket(sfd); } + else if (!data_is_available(sfd, csp->config->socket_timeout)) + { + if (socket_is_still_alive(sfd)) + { + errstr = "SOCKS4 negotiation timed out"; + } + else + { + errstr = "SOCKS4 negotiation got aborted by the server"; + } + log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr); + err = 1; + close_socket(sfd); + } else if (read_socket(sfd, buf, sizeof(buf)) != sizeof(*s)) { errstr = "SOCKS4 negotiation read failed."; @@ -826,24 +828,24 @@ static jb_socket socks4_connect(const struct forward_spec * fwd, if (err) { - csp->error_message = strdup(errstr); + csp->error_message = strdup(errstr); return(JB_INVALID_SOCKET); } switch (s->cd) { - case SOCKS_REQUEST_GRANTED: + case SOCKS4_REQUEST_GRANTED: return(sfd); - case SOCKS_REQUEST_REJECT: + case SOCKS4_REQUEST_REJECT: errstr = "SOCKS request rejected or failed."; errno = EINVAL; break; - case SOCKS_REQUEST_IDENT_FAILED: + case SOCKS4_REQUEST_IDENT_FAILED: errstr = "SOCKS request rejected because " "SOCKS server cannot connect to identd on the client."; errno = EACCES; break; - case SOCKS_REQUEST_IDENT_CONFLICT: + case SOCKS4_REQUEST_IDENT_CONFLICT: errstr = "SOCKS request rejected because " "the client program and identd report " "different user-ids."; @@ -930,7 +932,7 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, { int err = 0; char cbuf[300]; - char sbuf[30]; + char sbuf[10]; size_t client_pos = 0; int server_size = 0; size_t hostlen = 0; @@ -986,6 +988,8 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, { errstr = "socks5 server unreachable"; log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr); + /* Free the generic error message provided by connect_to() */ + freez(csp->error_message); csp->error_message = strdup(errstr); return(JB_INVALID_SOCKET); } @@ -1004,7 +1008,20 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, return(JB_INVALID_SOCKET); } - if (read_socket(sfd, sbuf, sizeof(sbuf)) != 2) + if (!data_is_available(sfd, csp->config->socket_timeout)) + { + if (socket_is_still_alive(sfd)) + { + errstr = "SOCKS5 negotiation timed out"; + } + else + { + errstr = "SOCKS5 negotiation got aborted by the server"; + } + err = 1; + } + + if (!err && read_socket(sfd, sbuf, sizeof(sbuf)) != 2) { errstr = "SOCKS5 negotiation read failed"; err = 1; @@ -1053,7 +1070,7 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, if (write_socket(sfd, cbuf, client_pos)) { - errstr = "SOCKS5 negotiation read failed"; + errstr = "SOCKS5 negotiation write failed"; csp->error_message = strdup(errstr); log_error(LOG_LEVEL_CONNECT, "%s", errstr); close_socket(sfd); @@ -1062,38 +1079,28 @@ static jb_socket socks5_connect(const struct forward_spec *fwd, } server_size = read_socket(sfd, sbuf, sizeof(sbuf)); - if (server_size < 3) + if (server_size != sizeof(sbuf)) { 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')) - { - errstr = "SOCKS5 negotiation protocol version error"; - err = 1; - } - - if (!err && (sbuf[2] != '\x00')) - { - errstr = "SOCKS5 negotiation protocol error"; - err = 1; } - - if (!err) + else { - if (sbuf[1] == SOCKS5_REQUEST_GRANTED) + if (sbuf[0] != '\x05') + { + errstr = "SOCKS5 negotiation protocol version error"; + } + else if (sbuf[2] != '\x00') + { + errstr = "SOCKS5 negotiation protocol error"; + } + else if (sbuf[1] != SOCKS5_REQUEST_GRANTED) + { + errstr = translate_socks5_error(sbuf[1]); + } + else { return(sfd); } - errstr = translate_socks5_error(sbuf[1]); } assert(errstr != NULL);