X-Git-Url: https://ruderich.org/simon/gitweb/?a=blobdiff_plain;f=src%2Fconnection.c;h=291bbfae35e441b1eec4c660ac408fdafd7fd1f6;hb=50ea3161c83c2d0a7599530cca7986d9fb03262f;hp=ed1bc63c6e030c5349f9d2aa46a179c8d60bf2f9;hpb=a84000d1d2806c296bfc0fa4b505b5d5ef750715;p=tlsproxy%2Ftlsproxy.git diff --git a/src/connection.c b/src/connection.c index ed1bc63..291bbfa 100644 --- a/src/connection.c +++ b/src/connection.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -58,6 +59,10 @@ static int initialize_tls_session_client(int peer_socket, static int initialize_tls_session_server(int peer_socket, gnutls_session_t *session, gnutls_certificate_credentials_t *x509_cred); +static int initialize_tls_session_both(int flags, + int peer_socket, + gnutls_session_t *session, + gnutls_certificate_credentials_t *x509_cred); static int fdopen_read_write(int socket, FILE **read_fd, FILE **write_fd); static int read_http_request(FILE *client_fd, char *request, size_t length); @@ -105,7 +110,7 @@ void handle_connection(int client_socket) { * certificate. */ int validation_failed; - LOG(DEBUG, "new connection"); + LOG(DEBUG1, "new connection"); server_socket = -1; client_fd_read = NULL; @@ -133,7 +138,7 @@ void handle_connection(int client_socket) { send_bad_request(client_fd_write); goto out; } else if (result == -3) { - LOG(DEBUG, "read_http_request(): proxy authentication failed"); + LOG(DEBUG1, "read_http_request(): proxy authentication failed"); send_authentication_required(client_fd_write); goto out; } @@ -144,19 +149,19 @@ void handle_connection(int client_socket) { goto out; } - LOG(DEBUG, "target: %s:%s (HTTP 1.%d)", host, port, version_minor); + LOG(DEBUG1, "target: %s:%s (HTTP 1.%d)", host, port, version_minor); /* Connect to proxy server or directly to server. */ if (global_proxy_host != NULL && global_proxy_port != NULL) { - LOG(DEBUG, "connecting to %s:%s", global_proxy_host, - global_proxy_port); + LOG(DEBUG1, "connecting to %s:%s", global_proxy_host, + global_proxy_port); server_socket = connect_to_host(global_proxy_host, global_proxy_port); } else { - LOG(DEBUG, "connecting to %s:%s", host, port); + LOG(DEBUG1, "connecting to %s:%s", host, port); server_socket = connect_to_host(host, port); } - if (server_socket == -1) { + if (server_socket < 0) { LOG(WARNING, "failed to connect to server"); send_forwarding_failure(client_fd_write); goto out; @@ -193,7 +198,7 @@ void handle_connection(int client_socket) { } } - LOG(DEBUG, "connection to server established"); + LOG(DEBUG1, "connection to server established"); /* If the -u option is used and we don't know this hostname's server * certificate then just pass through the connection and let the client @@ -208,13 +213,13 @@ void handle_connection(int client_socket) { fprintf(client_fd_write, "\r\n"); fflush(client_fd_write); - LOG(DEBUG, "transferring data"); + LOG(DEBUG1, "transferring data"); /* Proxy data between client and server until one side is done * (EOF or error). */ transfer_data(client_socket, server_socket); - LOG(DEBUG, "finished transferring data"); + LOG(DEBUG1, "finished transferring data"); goto out; } @@ -234,19 +239,19 @@ void handle_connection(int client_socket) { } server_session_init = 1; - LOG(DEBUG, "starting server TLS handshake"); + LOG(DEBUG1, "starting server TLS handshake"); /* Try to establish TLS handshake between us and server. */ result = gnutls_handshake(server_session); if (result != GNUTLS_E_SUCCESS) { LOG(WARNING, "server TLS handshake failed: %s", - gnutls_strerror(result)); + gnutls_strerror(result)); send_forwarding_failure(client_fd_write); goto out; } server_session_started = 1; - LOG(DEBUG, "server TLS handshake finished"); + LOG(DEBUG1, "server TLS handshake finished"); /* Make sure the server certificate is valid and known. */ if (verify_tls_connection(server_session, host) != 0) { @@ -277,19 +282,19 @@ void handle_connection(int client_socket) { fprintf(client_fd_write, "\r\n"); fflush(client_fd_write); - LOG(DEBUG, "starting client TLS handshake"); + LOG(DEBUG1, "starting client TLS handshake"); /* Try to establish TLS handshake between client and us. */ result = gnutls_handshake(client_session); if (result != GNUTLS_E_SUCCESS) { LOG(WARNING, "client TLS handshake failed: %s", - gnutls_strerror(result)); + gnutls_strerror(result)); send_forwarding_failure(client_fd_write); goto out; } client_session_started = 1; - LOG(DEBUG, "client TLS handshake finished"); + LOG(DEBUG1, "client TLS handshake finished"); /* Tell the client that the verification failed. Shouldn't be necessary as * the client should terminate the connection because he received the @@ -299,20 +304,29 @@ void handle_connection(int client_socket) { goto out; } - LOG(DEBUG, "transferring TLS data"); + LOG(DEBUG1, "transferring TLS data"); /* Proxy data between client and server until one side is done (EOF or * error). */ transfer_data_tls(client_socket, server_socket, client_session, server_session); - LOG(DEBUG, "finished transferring TLS data"); + LOG(DEBUG1, "finished transferring TLS data"); out: /* Close TLS sessions if necessary. Use GNUTLS_SHUT_RDWR so the data is * reliable transmitted. */ if (server_session_started) { - gnutls_bye(server_session, GNUTLS_SHUT_RDWR); + /* Recent gnutls-serv (used in the test-suite) won't terminate the + * connection when gnutls_bye(session, GNUTLS_SHUT_RDWR) is used + * before any other data was received. If the validation failed just + * close the connection without waiting for data, we won't read it + * anyway. + * + * For verified connections GNUTLS_SHUT_RDWR is important or we might + * lose data. */ + gnutls_bye(server_session, validation_failed ? GNUTLS_SHUT_WR + : GNUTLS_SHUT_RDWR); } if (client_session_started) { gnutls_bye(client_session, GNUTLS_SHUT_RDWR); @@ -337,7 +351,7 @@ out: } else if (server_socket != -1) { close(server_socket); } - LOG(DEBUG, "connection to server closed"); + LOG(DEBUG1, "connection to server closed"); /* Close connection to client. */ if (client_fd_read != NULL) { if (client_fd_write != NULL) { @@ -347,9 +361,9 @@ out: } else { close(client_socket); } - LOG(DEBUG, "connection to client closed"); + LOG(DEBUG1, "connection to client closed"); - LOG(DEBUG, "connection finished"); + LOG(DEBUG1, "connection finished"); } @@ -367,16 +381,16 @@ static int initialize_tls_session_client(int peer_socket, if (proxy_certificate_path(hostname, path, sizeof(path)) != 0) { LOG(ERROR, - "initialize_tls_session_client(): \ -failed to get proxy certificate path"); + "initialize_tls_session_client(): " + "failed to get proxy certificate path"); return -1; } result = gnutls_certificate_allocate_credentials(x509_cred); if (result != GNUTLS_E_SUCCESS) { LOG(ERROR, - "initialize_tls_session_client(): \ -gnutls_certificate_allocate_credentials(): %s", + "initialize_tls_session_client(): " + "gnutls_certificate_allocate_credentials(): %s", gnutls_strerror(result)); return -1; } @@ -412,8 +426,8 @@ gnutls_certificate_allocate_credentials(): %s", } if (result != GNUTLS_E_SUCCESS) { LOG(ERROR, - "initialize_tls_session_client(): \ -can't read server certificate ('%s') or key file ('%s'): %s", + "initialize_tls_session_client(): " + "can't read server certificate ('%s') or key file ('%s'): %s", path, PROXY_KEY_FILE, gnutls_strerror(result)); gnutls_certificate_free_credentials(*x509_cred); /* Could be a missing certificate. */ @@ -422,37 +436,8 @@ can't read server certificate ('%s') or key file ('%s'): %s", gnutls_certificate_set_dh_params(*x509_cred, global_tls_dh_params); - result = gnutls_init(session, GNUTLS_SERVER); - if (result != GNUTLS_E_SUCCESS) { - LOG(ERROR, - "initialize_tls_session_client(): gnutls_init(): %s", - gnutls_strerror(result)); - gnutls_certificate_free_credentials(*x509_cred); - return -1; - } - result = gnutls_priority_set(*session, global_tls_priority_cache); - if (result != GNUTLS_E_SUCCESS) { - LOG(ERROR, - "initialize_tls_session_client(): gnutls_priority_set(): %s", - gnutls_strerror(result)); - gnutls_deinit(*session); - gnutls_certificate_free_credentials(*x509_cred); - return -1; - } - result = gnutls_credentials_set(*session, - GNUTLS_CRD_CERTIFICATE, *x509_cred); - if (result != GNUTLS_E_SUCCESS) { - LOG(ERROR, - "initialize_tls_session_client(): gnutls_credentials_set(): %s", - gnutls_strerror(result)); - gnutls_deinit(*session); - gnutls_certificate_free_credentials(*x509_cred); - return -1; - } - - gnutls_transport_set_ptr(*session, (gnutls_transport_ptr_t)peer_socket); - - return 0; + return initialize_tls_session_both(GNUTLS_SERVER, + peer_socket, session, x509_cred); } static int initialize_tls_session_server(int peer_socket, gnutls_session_t *session, @@ -462,16 +447,25 @@ static int initialize_tls_session_server(int peer_socket, result = gnutls_certificate_allocate_credentials(x509_cred); if (result != GNUTLS_E_SUCCESS) { LOG(ERROR, - "initialize_tls_session_server(): \ -gnutls_certificate_allocate_credentials(): %s", + "initialize_tls_session_server(): " + "gnutls_certificate_allocate_credentials(): %s", gnutls_strerror(result)); return -1; } - result = gnutls_init(session, GNUTLS_CLIENT); + return initialize_tls_session_both(GNUTLS_CLIENT, + peer_socket, session, x509_cred); +} +static int initialize_tls_session_both(int flags, + int peer_socket, + gnutls_session_t *session, + gnutls_certificate_credentials_t *x509_cred) { + int result; + + result = gnutls_init(session, flags); if (result != GNUTLS_E_SUCCESS) { LOG(ERROR, - "initialize_tls_session_server(): gnutls_init(): %s", + "initialize_tls_session_both(): gnutls_init(): %s", gnutls_strerror(result)); gnutls_certificate_free_credentials(*x509_cred); return -1; @@ -479,7 +473,7 @@ gnutls_certificate_allocate_credentials(): %s", result = gnutls_priority_set(*session, global_tls_priority_cache); if (result != GNUTLS_E_SUCCESS) { LOG(ERROR, - "initialize_tls_session_server(): gnutls_priority_set(): %s", + "initialize_tls_session_both(): gnutls_priority_set(): %s", gnutls_strerror(result)); gnutls_deinit(*session); gnutls_certificate_free_credentials(*x509_cred); @@ -489,7 +483,7 @@ gnutls_certificate_allocate_credentials(): %s", GNUTLS_CRD_CERTIFICATE, *x509_cred); if (result != GNUTLS_E_SUCCESS) { LOG(ERROR, - "initialize_tls_session_server(): gnutls_credentials_set(): %s", + "initialize_tls_session_both(): gnutls_credentials_set(): %s", gnutls_strerror(result)); gnutls_deinit(*session); gnutls_certificate_free_credentials(*x509_cred); @@ -528,6 +522,7 @@ static int read_http_request(FILE *client_fd, char *request, size_t length) { char buffer[MAX_REQUEST_LINE]; int found_proxy_authorization; + assert(length <= INT_MAX); if (fgets(request, (int)length, client_fd) == NULL) { if (ferror(client_fd)) { LOG_PERROR(WARNING, "read_http_request(): fgets()"); @@ -616,6 +611,8 @@ static void transfer_data(int client, int server) { fds[1].events = POLLIN | POLLPRI | POLLHUP | POLLERR; fds[1].revents = 0; + LOG(DEBUG1, "transfer_data(): %d -> %d", client, server); + for (;;) { int result = poll(fds, 2 /* fd count */, -1 /* no timeout */); if (result < 0) { @@ -656,8 +653,6 @@ static int read_from_write_to(int from, int to) { ssize_t size_written; char buffer[4096]; - LOG(DEBUG, "read_from_write_to(): %d -> %d", from, to); - size_read = read(from, buffer, sizeof(buffer)); if (size_read < 0) { LOG_PERROR(WARNING, "read_from_write_to(): read()"); @@ -674,7 +669,7 @@ static int read_from_write_to(int from, int to) { } if (size_read != size_written) { LOG(ERROR, "read_from_write_to(): only written %ld of %ld bytes!", - (long int)size_written, (long int)size_read); + (long int)size_written, (long int)size_read); return -1; } @@ -701,8 +696,8 @@ static void transfer_data_tls(int client, int server, if (gnutls_record_get_max_size(server_session) < buffer_size) { buffer_size = gnutls_record_get_max_size(server_session); } - LOG(DEBUG, "transfer_data_tls(): suggested buffer size: %ld", - (long int)buffer_size); + LOG(DEBUG1, "transfer_data_tls(): suggested buffer size: %ld", + (long int)buffer_size); for (;;) { int result = poll(fds, 2 /* fd count */, -1 /* no timeout */); @@ -748,15 +743,15 @@ static int read_from_write_to_tls(gnutls_session_t from, char buffer[16384]; if (buffer_size > sizeof(buffer)) { + LOG(WARNING, "read_from_write_to_tls(): reduced buffer size to %ld", + (long int)(sizeof(buffer))); buffer_size = sizeof(buffer); } - LOG(DEBUG, "read_from_write_to_tls(): used buffer size: %ld", - (long int)buffer_size); size_read = gnutls_record_recv(from, buffer, buffer_size); if (size_read < 0) { LOG(WARNING, "read_from_write_to_tls(): gnutls_record_recv(): %s", - gnutls_strerror((int)size_read)); + gnutls_strerror((int)size_read)); return -1; /* EOF */ } else if (size_read == 0) { @@ -766,12 +761,12 @@ static int read_from_write_to_tls(gnutls_session_t from, size_written = gnutls_record_send(to, buffer, (size_t)size_read); if (size_written < 0) { LOG(WARNING, "read_from_write_to_tls(): gnutls_record_send(): %s", - gnutls_strerror((int)size_written)); + gnutls_strerror((int)size_written)); return -1; } if (size_read != size_written) { LOG(ERROR, "read_from_write_to_tls(): only written %ld of %ld bytes!", - (long int)size_written, (long int)size_read); + (long int)size_written, (long int)size_read); return -1; } @@ -805,7 +800,7 @@ static int connect_to_host(const char *hostname, const char *port) { LOG_PERROR(WARNING, "connect_to_host(): getaddrinfo()"); } else { LOG(WARNING, "connect_to_host(): getaddrinfo(): %s", - gai_strerror(gai_return)); + gai_strerror(gai_return)); } return -1; } @@ -816,15 +811,15 @@ static int connect_to_host(const char *hostname, const char *port) { server_socket = socket(server->ai_family, server->ai_socktype, server->ai_protocol); - if (server_socket == -1) { - LOG_PERROR(DEBUG, "connect_to_host(): socket(), trying next"); + if (server_socket < 0) { + LOG_PERROR(DEBUG1, "connect_to_host(): socket(), trying next"); continue; } - if (connect(server_socket, server->ai_addr, server->ai_addrlen) != -1) { + if (connect(server_socket, server->ai_addr, server->ai_addrlen) == 0) { break; } - LOG_PERROR(DEBUG, "connect_to_host(): connect(), trying next"); + LOG_PERROR(DEBUG1, "connect_to_host(): connect(), trying next"); close(server_socket); }