From b1719517b754aa0a098ee0f9c59e8babaf8df384 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 8 Dec 2012 23:03:28 +0100 Subject: [PATCH] BUG/MEDIUM: tcp: process could theorically crash on lack of source ports When connect() fails with EAGAIN or EADDRINUSE, an error message is sent to logs and uses srv->id to indicate the server name (this is very old code). Since version 1.4, it is possible to have srv == NULL, so the message could cause a crash when connect() returns EAGAIN or EADDRINUSE. However in practice this does not happen because on lack of source ports, EADDRNOTAVAIL is returned instead, so this code is never called. This fix consists in not displaying the server name anymore, and in adding the test for EADDRNOTAVAIL. Also, the log level was lowered from LOG_EMERG to LOG_ERR in order not to spam all consoles when source ports are missing for a given target. This fix should be backported to 1.4. --- src/proto_tcp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 0df4abadb..8c6cf7757 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -437,20 +437,18 @@ int tcp_connect_server(struct connection *conn, int data, int delack) if ((connect(fd, (struct sockaddr *)&conn->addr.to, get_addr_len(&conn->addr.to)) == -1) && (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) { - if (errno == EAGAIN || errno == EADDRINUSE) { + if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) { char *msg; - if (errno == EAGAIN) /* no free ports left, try again later */ + if (errno == EAGAIN || errno == EADDRNOTAVAIL) msg = "no free ports"; else msg = "local address already in use"; - qfprintf(stderr,"Cannot connect: %s.\n",msg); + qfprintf(stderr,"Connect() failed for backend %s: %s.\n", be->id, msg); port_range_release_port(fdinfo[fd].port_range, fdinfo[fd].local_port); fdinfo[fd].port_range = NULL; close(fd); - send_log(be, LOG_EMERG, - "Connect() failed for server %s/%s: %s.\n", - be->id, srv->id, msg); + send_log(be, LOG_ERR, "Connect() failed for backend %s: %s.\n", be->id, msg); return SN_ERR_RESOURCE; } else if (errno == ETIMEDOUT) { //qfprintf(stderr,"Connect(): ETIMEDOUT");