]> ruderich.org/simon Gitweb - tlsproxy/tlsproxy.git/commitdiff
Don't use fdopen(socket, "a+").
authorSimon Ruderich <simon@ruderich.org>
Sun, 28 Jul 2013 11:52:11 +0000 (13:52 +0200)
committerSimon Ruderich <simon@ruderich.org>
Sun, 28 Jul 2013 11:52:11 +0000 (13:52 +0200)
Using it with sockets is undefined behaviour as correct usage of a+
requires seeking which is not possible on sockets. Instead use separate
read and write FILE *.

src/connection.c

index 82b13bf0d04f5a316968bb18577378a2d47f8c47..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,7 +80,7 @@ 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];
@@ -105,34 +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) {
         LOG(LOG_WARNING, "read_http_request(): client read error");
         goto out;
     } else if (result == -2) {
         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;
     }
 
@@ -150,38 +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");
-        fflush(server_fd);
+        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) {
             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) {
             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;
         }
     }
@@ -197,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");
 
@@ -222,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;
@@ -234,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;
@@ -260,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");
 
@@ -277,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;
@@ -322,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);
     }
@@ -489,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.