]> source.dussan.org Git - rspamd.git/commitdiff
Use getaddrinfo when opening sockets.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 31 May 2013 16:45:18 +0000 (17:45 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 31 May 2013 16:45:18 +0000 (17:45 +0100)
src/lua/lua_http.c
src/map.c
src/map.h
src/util.c
src/util.h

index 73d916244eb7d66738f847112319b9eeb16b5095..8fc5c3e2c353d44699cdb6cbb6d5fd3eba7c21c2 100644 (file)
@@ -302,7 +302,7 @@ lua_http_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
        elt = reply->elements->data;
        memcpy (&ina, &elt->a.addr[0], sizeof (struct in_addr));
 
-       ud->fd = make_tcp_socket (&ina, ud->port, FALSE, TRUE);
+       ud->fd = make_universal_stream_socket (inet_ntoa (ina), ud->port, TRUE, FALSE, FALSE);
 
        if (ud->fd == -1) {
                lua_http_push_error (450, ud);
@@ -473,7 +473,7 @@ lua_http_make_request_common_new (lua_State *L, struct rspamd_async_session *ses
                return 1;
        }
 
-       ud->fd = make_tcp_socket (&ina, ud->port, FALSE, TRUE);
+       ud->fd = make_universal_stream_socket (inet_ntoa (ina), ud->port, TRUE, FALSE, FALSE);
 
        if (ud->fd == -1) {
                luaL_unref (L, LUA_REGISTRYINDEX, cbref);
index 912604118bd3a7ac4fb19032a40b50a4f3b23ffe..fde6a3de99ba5d93213e17af3fd8467c2c8eb1b5 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -68,7 +68,7 @@ connect_http (struct rspamd_map *map, struct http_map_data *data, gboolean is_as
 {
        gint                            sock;
 
-       if ((sock = make_tcp_socket (&data->addr, data->port, FALSE, is_async)) == -1) {
+       if ((sock = make_tcp_socket (data->addr, FALSE, is_async)) == -1) {
                msg_info ("cannot connect to http server %s: %d, %s", data->host, errno, strerror (errno));
                return -1;
        }
@@ -1013,8 +1013,8 @@ add_map (struct config_file *cfg, const gchar *map_line, const gchar *descriptio
        struct file_map_data           *fdata;
        struct http_map_data           *hdata;
        gchar                           portbuf[6];
-       gint                            i, s;
-       struct hostent                 *hent;
+       gint                            i, s, r;
+       struct addrinfo                hints, *res;
 
        /* First of all detect protocol line */
        if (!check_map_proto (map_line, (int *)&proto, &def)) {
@@ -1075,6 +1075,7 @@ add_map (struct config_file *cfg, const gchar *map_line, const gchar *descriptio
                }
                else {
                        /* Default http port */
+                       rspamd_snprintf (portbuf, sizeof (portbuf), "80");
                        hdata->port = 80;
                        /* Now separate host from path */
                        if ((p = strchr (def, '/')) == NULL) {
@@ -1088,19 +1089,25 @@ add_map (struct config_file *cfg, const gchar *map_line, const gchar *descriptio
                hdata->path = memory_pool_strdup (cfg->map_pool, p);
                hdata->rlen = 0;
                /* Now try to resolve */
-               if (!inet_aton (hdata->host, &hdata->addr)) {
-                       /* Resolve using dns */
-                       hent = gethostbyname (hdata->host);
-                       if (hent == NULL) {
-                               msg_info ("cannot resolve: %s", hdata->host);
-                               return FALSE;
-                       }
-                       else {
-                               memcpy (&hdata->addr, hent->h_addr, sizeof (struct in_addr));
-                       }
+               memset (&hints, 0, sizeof (hints));
+               hints.ai_family = AF_UNSPEC;     /* Allow IPv4 or IPv6 */
+               hints.ai_socktype = SOCK_STREAM; /* Stream socket */
+               hints.ai_flags = 0;
+               hints.ai_protocol = 0;           /* Any protocol */
+               hints.ai_canonname = NULL;
+               hints.ai_addr = NULL;
+               hints.ai_next = NULL;
+
+               if ((r = getaddrinfo (hdata->host, portbuf, &hints, &res)) == 0) {
+                       hdata->addr = res;
+                       memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)freeaddrinfo, hdata->addr);
+               }
+               else {
+                       msg_err ("address resolution for %s failed: %s", hdata->host, gai_strerror (r));
+                       return FALSE;
                }
                /* Now try to connect */
-               if ((s = make_tcp_socket (&hdata->addr, hdata->port, FALSE, FALSE)) == -1) {
+               if ((s = make_tcp_socket (hdata->addr, FALSE, FALSE)) == -1) {
                        msg_info ("cannot connect to http server %s: %d, %s", hdata->host, errno, strerror (errno));
                        return FALSE;
                }
index 8623e68453733199bac2210a18e0aad4d1f85826..ec35f848628703eeba7224c5488e0dea8077e943 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -37,7 +37,7 @@ struct file_map_data {
  * Data specific to HTTP maps
  */
 struct http_map_data {
-       struct in_addr addr;
+       struct addrinfo *addr;
        guint16 port;
        gchar *path;
        gchar *host;
index 9c4d8bf4cf2577f48efd027563b2f1624446432f..8d7bf69adc548da56d6e4084a97f1a347d6aa610 100644 (file)
@@ -87,94 +87,88 @@ poll_sync_socket (gint fd, gint timeout, short events)
 }
 
 static gint
-make_inet_socket (gint family, struct in_addr *addr, u_short port, gboolean is_server, gboolean async)
+make_inet_socket (gint family, struct addrinfo *addr, gboolean is_server, gboolean async)
 {
        gint                            fd, r, optlen, on = 1, s_error;
-       gint                            serrno;
-       struct sockaddr_in              sin;
-
-       /* Create socket */
-       fd = socket (AF_INET, family, 0);
-       if (fd == -1) {
-               msg_warn ("socket failed: %d, '%s'", errno, strerror (errno));
-               return -1;
-       }
-
-       if (make_socket_nonblocking (fd) < 0) {
-               goto out;
-       }
-
-       /* Set close on exec */
-       if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
-               msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
-               goto out;
-       }
-
-       memset (&sin, 0, sizeof (sin));
-
-       /* Bind options */
-       sin.sin_family = AF_INET;
-       sin.sin_port = htons (port);
-       sin.sin_addr.s_addr = addr->s_addr;
+       struct addrinfo               *cur;
+
+       cur = addr;
+       while (cur) {
+               /* Create socket */
+               fd = socket (cur->ai_protocol, family, 0);
+               if (fd == -1) {
+                       msg_warn ("socket failed: %d, '%s'", errno, strerror (errno));
+                       goto out;
+               }
 
-       if (is_server) {
-               setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
-               r = bind (fd, (struct sockaddr *)&sin, sizeof (struct sockaddr_in));
-       }
-       else {
-               r = connect (fd, (struct sockaddr *)&sin, sizeof (struct sockaddr_in));
-       }
+               if (make_socket_nonblocking (fd) < 0) {
+                       goto out;
+               }
 
-       if (r == -1) {
-               if (errno != EINPROGRESS) {
-                       msg_warn ("bind/connect failed: %d, '%s'", errno, strerror (errno));
+               /* Set close on exec */
+               if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
+                       msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
                        goto out;
                }
-               if (!async) {
-                       /* Try to poll */
-                       if (poll_sync_socket (fd, CONNECT_TIMEOUT * 1000, POLLOUT) <= 0) {
-                               errno = ETIMEDOUT;
-                               msg_warn ("bind/connect failed: timeout");
+
+               if (is_server) {
+                       setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
+                       r = bind (fd, cur->ai_addr, cur->ai_addrlen);
+               }
+               else {
+                       r = connect (fd, cur->ai_addr, cur->ai_addrlen);
+               }
+
+               if (r == -1) {
+                       if (errno != EINPROGRESS) {
+                               msg_warn ("bind/connect failed: %d, '%s'", errno, strerror (errno));
                                goto out;
                        }
-                       else {
-                               /* Make synced again */
-                               if (make_socket_blocking (fd) < 0) {
+                       if (!async) {
+                               /* Try to poll */
+                               if (poll_sync_socket (fd, CONNECT_TIMEOUT * 1000, POLLOUT) <= 0) {
+                                       errno = ETIMEDOUT;
+                                       msg_warn ("bind/connect failed: timeout");
                                        goto out;
                                }
+                               else {
+                                       /* Make synced again */
+                                       if (make_socket_blocking (fd) < 0) {
+                                               goto out;
+                                       }
+                               }
                        }
                }
-       }
-       else {
-               /* Still need to check SO_ERROR on socket */
-               optlen = sizeof (s_error);
-               getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *)&s_error, &optlen);
-               if (s_error) {
-                       errno = s_error;
-                       goto out;
+               else {
+                       /* Still need to check SO_ERROR on socket */
+                       optlen = sizeof (s_error);
+                       getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *)&s_error, &optlen);
+                       if (s_error) {
+                               errno = s_error;
+                               goto out;
+                       }
+               }
+               break;
+out:
+               if (fd != -1) {
+                       close (fd);
                }
+               fd = -1;
+               cur = cur->ai_next;
        }
-
-
        return (fd);
-
-  out:
-       serrno = errno;
-       close (fd);
-       errno = serrno;
-       return (-1);
 }
 
 gint
-make_tcp_socket (struct in_addr *addr, u_short port, gboolean is_server, gboolean async)
+make_tcp_socket (struct addrinfo *addr, gboolean is_server, gboolean async)
 {
-       return make_inet_socket (SOCK_STREAM, addr, port, is_server, async);
+       return make_inet_socket (SOCK_STREAM, addr, is_server, async);
 }
 
 gint
-make_udp_socket (struct in_addr *addr, u_short port, gboolean is_server, gboolean async)
+make_udp_socket (struct addrinfo *addr, gboolean is_server, gboolean async)
 {
-       return make_inet_socket (SOCK_DGRAM, addr, port, is_server, async);
+       return make_inet_socket (SOCK_DGRAM, addr, is_server, async);
 }
 
 gint
@@ -304,9 +298,9 @@ make_universal_stream_socket (const gchar *credits, guint16 port, gboolean async
 {
        struct sockaddr_un              un;
        struct stat                     st;
-       struct in_addr                  in;
-       struct hostent                             *he;
-       gint                            r;
+       struct addrinfo                 hints, *res;
+       gint                             r;
+       gchar                            portbuf[8];
 
        if (*credits == '/') {
                r = stat (credits, &st);
@@ -340,25 +334,28 @@ make_universal_stream_socket (const gchar *credits, guint16 port, gboolean async
        }
        else {
                /* TCP related part */
-               if (inet_aton (credits, &in) == 0) {
-                       /* Try to resolve */
-                       if (try_resolve) {
-                               if ((he = gethostbyname (credits)) == NULL) {
-                                       errno = ENOENT;
-                                       return -1;
-                               }
-                               else {
-                                       memcpy (&in, he->h_addr, sizeof (struct in_addr));
-                                       return make_tcp_socket (&in, port, is_server, async);
-                               }
-                       }
-                       else {
-                               errno = ENOENT;
-                               return -1;
-                       }
+               memset (&hints, 0, sizeof (hints));
+               hints.ai_family = AF_UNSPEC;     /* Allow IPv4 or IPv6 */
+               hints.ai_socktype = SOCK_STREAM; /* Stream socket */
+               hints.ai_flags = is_server ? AI_PASSIVE : 0;
+               hints.ai_protocol = 0;           /* Any protocol */
+               hints.ai_canonname = NULL;
+               hints.ai_addr = NULL;
+               hints.ai_next = NULL;
+
+               if (!try_resolve) {
+                       hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
+               }
+
+               rspamd_snprintf (portbuf, sizeof (portbuf), "%d", (int)port);
+               if ((r = getaddrinfo (credits, portbuf, &hints, &res)) == 0) {
+                       r = make_tcp_socket (res, is_server, async);
+                       freeaddrinfo (res);
+                       return r;
                }
                else {
-                       return make_tcp_socket (&in, port, is_server, async);
+                       msg_err ("address resolution for %s failed: %s", credits, gai_strerror (r));
+                       return FALSE;
                }
        }
 }
index 6bec21f46cefc6f0af51cb57a7df41b7fb8024c6..3dfa851bc6b30625fef7443a4fbb9322f9a31c7d 100644 (file)
@@ -17,11 +17,11 @@ struct classifier_config;
 /*
  * Create socket and bind or connect it to specified address and port
  */
-gint make_tcp_socket (struct in_addr *, u_short, gboolean is_server, gboolean async);
+gint make_tcp_socket (struct addrinfo *, gboolean is_server, gboolean async);
 /*
  * Create socket and bind or connect it to specified address and port
  */
-gint make_udp_socket (struct in_addr *, u_short, gboolean is_server, gboolean async);
+gint make_udp_socket (struct addrinfo *, gboolean is_server, gboolean async);
 /*
  * Accept from socket
  */