]> ruderich.org/simon Gitweb - tlsproxy/tlsproxy.git/blobdiff - src/connection.c
sem.c: Fix P() for negative start values.
[tlsproxy/tlsproxy.git] / src / connection.c
index f608339f8014ba0427f515c36a14f1d29a51e894..f7e9a97425626bb2e393f5478168c2bc3dcb5f56 100644 (file)
@@ -58,6 +58,7 @@ static int initialize_tls_session_server(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);
 static void send_bad_request(FILE *client_fd);
 static void send_forwarding_failure(FILE *client_fd);
@@ -79,13 +80,13 @@ static int parse_request(const char *buffer, char *host, char *port,
 
 void handle_connection(int client_socket) {
     int server_socket;
-    FILE *client_fd, *server_fd;
+    FILE *client_fd_read, *client_fd_write, *server_fd_read, *server_fd_write;
 
     char buffer[MAX_REQUEST_LINE];
     char host[MAX_REQUEST_LINE];
     char port[5 + 1];
 
-    int version_minor; /* HTTP/1.x */
+    int version_minor; /* x in HTTP/1.x */
     int result;
 
     /* client_x509_cred is used when talking to the client (acting as a TSL
@@ -105,36 +106,35 @@ void handle_connection(int client_socket) {
     LOG(LOG_DEBUG, "new connection");
 
     server_socket = -1;
-    client_fd = NULL;
-    server_fd = NULL;
+    client_fd_read = NULL;
+    client_fd_write = NULL;
+    server_fd_read = NULL;
+    server_fd_write = NULL;
     client_session_init = 0;
     server_session_init = 0;
     client_session_started = 0;
     server_session_started = 0;
     validation_failed = 0;
 
-    client_fd = fdopen(client_socket, "a+");
-    if (client_fd == NULL) {
-        LOG_PERROR(LOG_WARNING, "fdopen(): client failed");
+    if (fdopen_read_write(client_socket, &client_fd_read,
+                                         &client_fd_write) != 0) {
         goto out;
     }
 
     /* Read request line (CONNECT ..) and headers (they are discarded). */
-    result = read_http_request(client_fd, buffer, sizeof(buffer));
+    result = read_http_request(client_fd_read, buffer, sizeof(buffer));
     if (result == -1) {
-        /* Read error. */
         LOG(LOG_WARNING, "read_http_request(): client read error");
         goto out;
     } else if (result == -2) {
-        /* EOF */
         LOG(LOG_WARNING, "read_http_request(): client EOF");
-        send_bad_request(client_fd);
+        send_bad_request(client_fd_write);
         goto out;
     }
 
     if (parse_request(buffer, host, port, &version_minor) != 0) {
         LOG(LOG_WARNING, "bad request: %s", buffer);
-        send_bad_request(client_fd);
+        send_bad_request(client_fd_write);
         goto out;
     }
 
@@ -152,39 +152,37 @@ void handle_connection(int client_socket) {
 
     if (server_socket == -1) {
         LOG(LOG_WARNING, "failed to connect to server");
-        send_forwarding_failure(client_fd);
+        send_forwarding_failure(client_fd_write);
         goto out;
     }
-    server_fd = fdopen(server_socket, "a+");
-    if (server_fd == NULL) {
-        LOG_PERROR(LOG_WARNING, "fdopen(): server failed");
-        send_forwarding_failure(client_fd);
+    if (fdopen_read_write(server_socket, &server_fd_read,
+                                         &server_fd_write) != 0) {
+        send_forwarding_failure(client_fd_write);
         goto out;
     }
 
     /* Connect to proxy if requested (command line option). */
     if (global_proxy_host != NULL && global_proxy_port != NULL) {
-        fprintf(server_fd, "CONNECT %s:%s HTTP/1.0\r\n", host, port);
-        fprintf(server_fd, "\r\n");
+        fprintf(server_fd_write, "CONNECT %s:%s HTTP/1.0\r\n", host, port);
+        fprintf(server_fd_write, "\r\n");
+        fflush(server_fd_write);
 
         /* Read response line from proxy server. */
-        result = read_http_request(server_fd, buffer, sizeof(buffer));
+        result = read_http_request(server_fd_read, buffer, sizeof(buffer));
         if (result == -1) {
-            /* Read error. */
             LOG(LOG_WARNING, "read_http_request(): proxy read error");
-            send_forwarding_failure(client_fd);
+            send_forwarding_failure(client_fd_write);
             goto out;
         } else if (result == -2) {
-            /* EOF */
             LOG(LOG_WARNING, "read_http_request(): proxy EOF");
-            send_forwarding_failure(client_fd);
+            send_forwarding_failure(client_fd_write);
             goto out;
         }
 
         /* Check response of proxy server. */
         if (strncmp(buffer, "HTTP/1.0 200", 12)) {
             LOG(LOG_WARNING, "bad proxy response: %s", buffer);
-            send_forwarding_failure(client_fd);
+            send_forwarding_failure(client_fd_write);
             goto out;
         }
     }
@@ -200,9 +198,9 @@ void handle_connection(int client_socket) {
 
         if (server_certificate_file(&file, host, path, sizeof(path)) == -2) {
             /* We've established a connection, tell the client. */
-            fprintf(client_fd, "HTTP/1.0 200 Connection established\r\n");
-            fprintf(client_fd, "\r\n");
-            fflush(client_fd);
+            fprintf(client_fd_write, "HTTP/1.0 200 Connection established\r\n");
+            fprintf(client_fd_write, "\r\n");
+            fflush(client_fd_write);
 
             LOG(LOG_DEBUG, "transferring data");
 
@@ -225,7 +223,7 @@ void handle_connection(int client_socket) {
                                                           &server_x509_cred);
     if (result != 0) {
         LOG(LOG_WARNING, "initialize_tls_session_server() failed");
-        send_forwarding_failure(client_fd);
+        send_forwarding_failure(client_fd_write);
         goto out;
     }
     server_session_init = 1;
@@ -237,7 +235,7 @@ void handle_connection(int client_socket) {
     if (result != GNUTLS_E_SUCCESS) {
         LOG(LOG_WARNING, "server TLS handshake failed: %s",
                          gnutls_strerror(result));
-        send_forwarding_failure(client_fd);
+        send_forwarding_failure(client_fd_write);
         goto out;
     }
     server_session_started = 1;
@@ -247,7 +245,7 @@ void handle_connection(int client_socket) {
     /* Make sure the server certificate is valid and known. */
     if (verify_tls_connection(server_session, host) != 0) {
         LOG(LOG_ERROR, "server certificate validation failed!");
-        /* We send the error message over our TLS connection to the client,
+        /* We'll send the error message over our TLS connection to the client,
          * but with an invalid certificate. No data is transfered from/to the
          * target server. */
         validation_failed = 1;
@@ -263,15 +261,15 @@ void handle_connection(int client_socket) {
                                            &client_x509_cred);
     if (result != 0) {
         LOG(LOG_WARNING, "initialize_tls_session_client() failed");
-        send_forwarding_failure(client_fd);
+        send_forwarding_failure(client_fd_write);
         goto out;
     }
     client_session_init = 1;
 
     /* We've established a connection, tell the client. */
-    fprintf(client_fd, "HTTP/1.0 200 Connection established\r\n");
-    fprintf(client_fd, "\r\n");
-    fflush(client_fd);
+    fprintf(client_fd_write, "HTTP/1.0 200 Connection established\r\n");
+    fprintf(client_fd_write, "\r\n");
+    fflush(client_fd_write);
 
     LOG(LOG_DEBUG, "starting client TLS handshake");
 
@@ -280,7 +278,7 @@ void handle_connection(int client_socket) {
     if (result != GNUTLS_E_SUCCESS) {
         LOG(LOG_WARNING, "client TLS handshake failed: %s",
                          gnutls_strerror(result));
-        send_forwarding_failure(client_fd);
+        send_forwarding_failure(client_fd_write);
         goto out;
     }
     client_session_started = 1;
@@ -325,15 +323,21 @@ out:
     }
 
     /* Close connection to server/proxy. */
-    if (server_fd != NULL) {
-        fclose(server_fd);
+    if (server_fd_read != NULL) {
+        if (server_fd_write != NULL) {
+            fclose(server_fd_write);
+        }
+        fclose(server_fd_read);
     } else if (server_socket != -1) {
         close(server_socket);
     }
     LOG(LOG_DEBUG, "connection to server closed");
     /* Close connection to client. */
-    if (client_fd != NULL) {
-        fclose(client_fd);
+    if (client_fd_read != NULL) {
+        if (client_fd_write != NULL) {
+            fclose(client_fd_write);
+        }
+        fclose(client_fd_read);
     } else {
         close(client_socket);
     }
@@ -492,6 +496,24 @@ gnutls_certificate_allocate_credentials(): %s",
 }
 
 
+static int fdopen_read_write(int socket, FILE **read_fd, FILE **write_fd) {
+    *read_fd = fdopen(socket, "r");
+    if (*read_fd == NULL) {
+        LOG_PERROR(LOG_WARNING, "fdopen_read_write(): fdopen(\"r\") failed");
+        return -1;
+    }
+
+    *write_fd = fdopen(dup(socket), "w");
+    if (*write_fd == NULL) {
+        LOG_PERROR(LOG_WARNING, "fdopen_read_write(): fdopen(\"w\") failed");
+        fclose(*read_fd);
+        *read_fd = NULL; /* "tell" caller read_fd is already closed */
+        return -1;
+    }
+
+    return 0;
+}
+
 /* Read HTTP request line and headers (ignored).
  *
  * On success 0 is returned, -1 on client error, -2 on unexpected EOF.
@@ -504,7 +526,7 @@ static int read_http_request(FILE *client_fd, char *request, size_t length) {
             LOG_PERROR(LOG_WARNING, "read_http_request(): fgets()");
             return -1;
         }
-
+        /* EOF */
         return -2;
     }
 
@@ -528,6 +550,7 @@ static void send_bad_request(FILE *client_fd) {
     fprintf(client_fd, HTTP_RESPONSE_FORMAT,
                        RESPONSE_ERROR, RESPONSE_ERROR, RESPONSE_ERROR,
                        RESPONSE_MSG);
+    fflush(client_fd);
 #undef RESPONSE_ERROR
 #undef RESPONSE_MSG
 }
@@ -537,6 +560,7 @@ static void send_forwarding_failure(FILE *client_fd) {
     fprintf(client_fd, HTTP_RESPONSE_FORMAT,
                        RESPONSE_ERROR, RESPONSE_ERROR, RESPONSE_ERROR,
                        RESPONSE_MSG);
+    fflush(client_fd);
 #undef RESPONSE_ERROR
 #undef RESPONSE_MSG
 }
@@ -584,7 +608,7 @@ static void transfer_data(int client, int server) {
     fds[1].revents = 0;
 
     for (;;) {
-        int result = poll(fds, 2, -1 /* no timeout */);
+        int result = poll(fds, 2 /* fd count */, -1 /* no timeout */);
         if (result < 0) {
             LOG_PERROR(LOG_ERROR, "transfer_data(): poll()");
             return;
@@ -629,9 +653,8 @@ static int read_from_write_to(int from, int to) {
     if (size_read < 0) {
         LOG_PERROR(LOG_WARNING, "read_from_write_to(): read()");
         return -1;
-    }
     /* EOF */
-    if (size_read == 0) {
+    } else if (size_read == 0) {
         return -1;
     }
 
@@ -673,7 +696,7 @@ static void transfer_data_tls(int client, int server,
                    (long int)buffer_size);
 
     for (;;) {
-        int result = poll(fds, 2, -1 /* no timeout */);
+        int result = poll(fds, 2 /* fd count */, -1 /* no timeout */);
         if (result < 0) {
             LOG_PERROR(LOG_ERROR, "transfer_data(): poll()");
             return;
@@ -726,9 +749,8 @@ static int read_from_write_to_tls(gnutls_session_t from,
         LOG(LOG_WARNING, "read_from_write_to_tls(): gnutls_record_recv(): %s",
                          gnutls_strerror((int)size_read));
         return -1;
-    }
     /* EOF */
-    if (size_read == 0) {
+    } else if (size_read == 0) {
         return -1;
     }