From 74392a5491ca8938a68d94440488bc303bd31ac8 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Sun, 15 Aug 2010 14:56:46 +0200 Subject: [PATCH] Use getaddrinfo instead of gethostbyname Patches conky to use getaddrinfo instead of gethostbyname everywhere. gethostbyname is rather flawed and doesn't support IPv6 properly. Patch contributed by Pascal Bleser --- src/apcupsd.c | 53 ++++++++++++------------- src/mail.c | 106 ++++++++++++++++++++++--------------------------- src/read_tcp.c | 32 ++++++++++----- 3 files changed, 94 insertions(+), 97 deletions(-) diff --git a/src/apcupsd.c b/src/apcupsd.c index 2e23bf74..c7a40c9c 100644 --- a/src/apcupsd.c +++ b/src/apcupsd.c @@ -164,44 +164,41 @@ int update_apcupsd(void) { memcpy(apc.items[i], "N/A", 4); // including \0 do { - struct hostent* he = 0; - struct sockaddr_in addr; + struct addrinfo hints; + struct addrinfo *ai, *rp; + int res; short sz = 0; -#ifdef HAVE_GETHOSTBYNAME_R - struct hostent he_mem; - int he_errno; - char hostbuff[2048]; -#endif + char portbuf[8]; // // connect to apcupsd daemon // - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - perror("socket"); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + snprintf(portbuf, 8, "%d", info.apcupsd.port); + res = getaddrinfo(info.apcupsd.host, portbuf, &hints, &ai); + if (res != 0) { + NORM_ERR("APCUPSD getaddrinfo: %s", gai_strerror(res)); break; } -#ifdef HAVE_GETHOSTBYNAME_R - if (gethostbyname_r(info.apcupsd.host, &he_mem, hostbuff, sizeof(hostbuff), &he, &he_errno) || !he ) { - NORM_ERR("APCUPSD gethostbyname_r: %s", hstrerror(h_errno)); - break; + for (rp = ai; rp != NULL; rp = rp->ai_next) { + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sock == -1) { + continue; + } + if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) { + break; + } + close(sock); } -#else /* HAVE_GETHOSTBYNAME_R */ - he = gethostbyname(info.apcupsd.host); - if (!he) { - herror("gethostbyname"); - break; - } -#endif /* HAVE_GETHOSTBYNAME_R */ - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = info.apcupsd.port; - memcpy(&addr.sin_addr, he->h_addr, he->h_length); - if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)) < 0) { + freeaddrinfo(ai); + if (rp == NULL) { // no error reporting, the daemon is probably not running break; } - + // // send status request - "status" - 6B // diff --git a/src/mail.c b/src/mail.c index ab2bc476..2d91c626 100644 --- a/src/mail.c +++ b/src/mail.c @@ -659,14 +659,13 @@ static void *imap_thread(void *arg) unsigned long old_unseen = ULONG_MAX; unsigned long old_messages = ULONG_MAX; struct stat stat_buf; - struct hostent he, *he_res = 0; - int he_errno; - char hostbuff[2048]; - struct sockaddr_in their_addr; // connector's address information struct mail_s *mail = (struct mail_s *)arg; int has_idle = 0; int threadfd = timed_thread_readfd(mail->p_timed_thread); char resolved_host = 0; + struct addrinfo hints; + struct addrinfo *ai, *rp; + char portbuf[8]; while (fail < mail->retries) { struct timeval fetchtimeout; @@ -674,19 +673,19 @@ static void *imap_thread(void *arg) fd_set fdset; if (!resolved_host) { -#ifdef HAVE_GETHOSTBYNAME_R - if (gethostbyname_r(mail->host, &he, hostbuff, sizeof(hostbuff), &he_res, &he_errno)) { // get the host info - NORM_ERR("IMAP gethostbyname_r: %s", hstrerror(h_errno)); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + snprintf(portbuf, 8, "%lu", mail->port); + + res = getaddrinfo(mail->host, portbuf, &hints, &ai); + if (res != 0) { + NORM_ERR("IMAP getaddrinfo: %s", gai_strerror(res)); fail++; break; } -#else /* HAVE_GETHOSTBYNAME_R */ - if ((he_res = gethostbyname(mail->host)) == NULL) { // get the host info - herror("gethostbyname"); - fail++; - break; - } -#endif /* HAVE_GETHOSTBYNAME_R */ resolved_host = 1; } if (fail > 0) { @@ -694,22 +693,18 @@ static void *imap_thread(void *arg) mail->user, mail->host, fail + 1, mail->retries); } do { - if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { - perror("socket"); - fail++; - break; + for (rp = ai; rp != NULL; rp = rp->ai_next) { + sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sockfd == -1) { + continue; + } + if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) != -1) { + break; + } + close(sockfd); } - - // host byte order - their_addr.sin_family = AF_INET; - // short, network byte order - their_addr.sin_port = htons(mail->port); - their_addr.sin_addr = *((struct in_addr *) he_res->h_addr); - // zero the rest of the struct - memset(&(their_addr.sin_zero), '\0', 8); - - if (connect(sockfd, (struct sockaddr *) &their_addr, - sizeof(struct sockaddr)) == -1) { + freeaddrinfo(ai); + if (rp == NULL) { perror("connect"); fail++; break; @@ -1012,31 +1007,30 @@ static void *pop3_thread(void *arg) unsigned int fail = 0; unsigned long old_unseen = ULONG_MAX; struct stat stat_buf; - struct hostent he, *he_res = 0; - int he_errno; - char hostbuff[2048]; - struct sockaddr_in their_addr; // connector's address information struct mail_s *mail = (struct mail_s *)arg; char resolved_host = 0; + struct addrinfo hints; + struct addrinfo *ai, *rp; + char portbuf[8]; while (fail < mail->retries) { struct timeval fetchtimeout; int res; fd_set fdset; if (!resolved_host) { -#ifdef HAVE_GETHOSTBYNAME_R - if (gethostbyname_r(mail->host, &he, hostbuff, sizeof(hostbuff), &he_res, &he_errno)) { // get the host info - NORM_ERR("POP3 gethostbyname_r: %s", hstrerror(h_errno)); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + snprintf(portbuf, 8, "%lu", mail->port); + + res = getaddrinfo(mail->host, portbuf, &hints, &ai); + if (res != 0) { + NORM_ERR("POP3 getaddrinfo: %s", gai_strerror(res)); fail++; break; } -#else /* HAVE_GETHOSTBYNAME_R */ - if ((he_res = gethostbyname(mail->host)) == NULL) { // get the host info - herror("gethostbyname"); - fail++; - break; - } -#endif /* HAVE_GETHOSTBYNAME_R */ resolved_host = 1; } if (fail > 0) { @@ -1044,22 +1038,18 @@ static void *pop3_thread(void *arg) mail->user, mail->host, fail + 1, mail->retries); } do { - if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { - perror("socket"); - fail++; - break; + for (rp = ai; rp != NULL; rp = rp->ai_next) { + sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sockfd == -1) { + continue; + } + if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) != -1) { + break; + } + close(sockfd); } - - // host byte order - their_addr.sin_family = AF_INET; - // short, network byte order - their_addr.sin_port = htons(mail->port); - their_addr.sin_addr = *((struct in_addr *) he_res->h_addr); - // zero the rest of the struct - memset(&(their_addr.sin_zero), '\0', 8); - - if (connect(sockfd, (struct sockaddr *) &their_addr, - sizeof(struct sockaddr)) == -1) { + freeaddrinfo(ai); + if (rp == NULL) { perror("connect"); fail++; break; diff --git a/src/read_tcp.c b/src/read_tcp.c index c2111803..dd935c58 100644 --- a/src/read_tcp.c +++ b/src/read_tcp.c @@ -66,28 +66,38 @@ void parse_read_tcp_arg(struct text_object *obj, const char *arg, void *free_at_ void print_read_tcp(struct text_object *obj, char *p, int p_max_size) { int sock, received; - struct sockaddr_in addr; - struct hostent* he; fd_set readfds; struct timeval tv; struct read_tcp_data *rtd = obj->data.opaque; + struct addrinfo hints; + struct addrinfo* airesult, *rp; + char portbuf[8]; if (!rtd) return; - if (!(he = gethostbyname(rtd->host))) { + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + snprintf(portbuf, 8, "%d", rtd->port); + if (getaddrinfo(rtd->host, portbuf, &hints, &airesult)) { NORM_ERR("read_tcp: Problem with resolving the hostname"); return; } - if ((sock = socket(he->h_addrtype, SOCK_STREAM, 0)) == -1) { - NORM_ERR("read_tcp: Couldn't create a socket"); - return; + for (rp = airesult; rp != NULL; rp = rp->ai_next) { + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sock == -1) { + continue; + } + if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) { + break; + } + close(sock); } - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = rtd->port; - memcpy(&addr.sin_addr, he->h_addr, he->h_length); - if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)) != 0) { + freeaddrinfo(airesult); + if (rp == NULL) { NORM_ERR("read_tcp: Couldn't create a connection"); return; }