aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2013-05-31 17:45:18 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2013-05-31 17:45:18 +0100
commit8cc2aee8859731ee2fe280070423f79e7d009ca3 (patch)
tree76951e59a1285c02ae50a89cbf69fcbb11f89b6b
parent7b3682ce3c78d26dd75782f931611bd09bcc76a5 (diff)
downloadrspamd-8cc2aee8859731ee2fe280070423f79e7d009ca3.tar.gz
rspamd-8cc2aee8859731ee2fe280070423f79e7d009ca3.zip
Use getaddrinfo when opening sockets.
-rw-r--r--src/lua/lua_http.c4
-rw-r--r--src/map.c35
-rw-r--r--src/map.h2
-rw-r--r--src/util.c167
-rw-r--r--src/util.h4
5 files changed, 108 insertions, 104 deletions
diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c
index 73d916244..8fc5c3e2c 100644
--- a/src/lua/lua_http.c
+++ b/src/lua/lua_http.c
@@ -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);
diff --git a/src/map.c b/src/map.c
index 912604118..fde6a3de9 100644
--- 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;
}
diff --git a/src/map.h b/src/map.h
index 8623e6845..ec35f8486 100644
--- 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;
diff --git a/src/util.c b/src/util.c
index 9c4d8bf4c..8d7bf69ad 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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;
}
}
}
diff --git a/src/util.h b/src/util.h
index 6bec21f46..3dfa851bc 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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
*/