{
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;
}
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)) {
}
else {
/* Default http port */
+ rspamd_snprintf (portbuf, sizeof (portbuf), "80");
hdata->port = 80;
/* Now separate host from path */
if ((p = strchr (def, '/')) == NULL) {
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;
}
}
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
{
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);
}
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;
}
}
}