"Fossies" - the Fresh Open Source Software Archive

Member "msmtp-1.8.17/src/net.c" (16 Dec 2020, 28854 Bytes) of package /linux/privat/msmtp-1.8.17.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "net.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.8.13_vs_1.8.14.

    1 /*
    2  * net.c
    3  *
    4  * This file is part of msmtp, an SMTP client, and of mpop, a POP3 client.
    5  *
    6  * Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2012, 2014, 2015,
    7  * 2018, 2019, 2020
    8  * Martin Lambers <marlam@marlam.de>
    9  *
   10  *   This program is free software; you can redistribute it and/or modify
   11  *   it under the terms of the GNU General Public License as published by
   12  *   the Free Software Foundation; either version 3 of the License, or
   13  *   (at your option) any later version.
   14  *
   15  *   This program is distributed in the hope that it will be useful,
   16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18  *   GNU General Public License for more details.
   19  *
   20  *   You should have received a copy of the GNU General Public License
   21  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   22  */
   23 
   24 
   25 #ifdef HAVE_CONFIG_H
   26 # include "config.h"
   27 #endif
   28 
   29 #ifdef W32_NATIVE
   30 # define WIN32_LEAN_AND_MEAN    /* do not include more than necessary */
   31 # define _WIN32_WINNT 0x0601    /* Windows 7 or later */
   32 # include <winsock2.h>
   33 # include <ws2tcpip.h>
   34 #endif
   35 #include <stdlib.h>
   36 #include <stdint.h>
   37 #include <string.h>
   38 #include <limits.h>
   39 #include <unistd.h>
   40 #include <fcntl.h>
   41 #include <errno.h>
   42 #include <sys/time.h>
   43 #ifdef HAVE_SYS_SELECT_H
   44 # include <sys/select.h>
   45 #endif
   46 #ifdef HAVE_SYS_SOCKET_H
   47 # include <sys/socket.h>
   48 # include <sys/un.h>
   49 #endif
   50 #ifdef HAVE_NETINET_IN_H
   51 # include <netinet/in.h>
   52 #endif
   53 #ifdef HAVE_ARPA_INET_H
   54 # include <arpa/inet.h>
   55 #endif
   56 #ifdef HAVE_NETDB_H
   57 # include <netdb.h>
   58 #endif
   59 
   60 #ifdef HAVE_LIBIDN
   61 # include <idn2.h>
   62 #endif
   63 
   64 #ifdef HAVE_LIBRESOLV
   65 # include <arpa/nameser.h>
   66 # include <resolv.h>
   67 #endif
   68 
   69 #include "gettext.h"
   70 #define _(string) gettext(string)
   71 
   72 #include "xalloc.h"
   73 #include "readbuf.h"
   74 #include "tools.h"
   75 #include "net.h"
   76 
   77 
   78 /*
   79  * [Windows only] wsa_strerror()
   80  *
   81  * This function translates WSA error codes to strings.
   82  * It should translate all codes that could be caused by the Windows socket
   83  * functions used in this file:
   84  * WSAStartup, getaddrinfo() or gethostbyname(), socket(), connect(),
   85  * recv(), send()
   86  */
   87 
   88 #ifdef W32_NATIVE
   89 const char *wsa_strerror(int error_code)
   90 {
   91     switch (error_code)
   92     {
   93         case WSA_NOT_ENOUGH_MEMORY:
   94             return _("not enough memory");
   95 
   96         case WSAEINTR:
   97             return _("operation aborted");
   98 
   99         case WSAEINVAL:
  100             return _("invalid argument");
  101 
  102         case WSATYPE_NOT_FOUND:
  103             return _("class type not found");
  104 
  105         case WSAENETDOWN:
  106             return _("the network subsystem has failed");
  107 
  108         case WSAHOST_NOT_FOUND:
  109             return _("host not found (authoritative)");
  110 
  111         case WSATRY_AGAIN:
  112             return _("host not found (nonauthoritative) or server failure");
  113 
  114         case WSANO_RECOVERY:
  115             return _("nonrecoverable error");
  116 
  117         case WSANO_DATA:
  118             return _("valid name, but no data record of requested type");
  119 
  120         case WSAEAFNOSUPPORT:
  121             return _("address family not supported");
  122 
  123         case WSAEMFILE:
  124             return _("no socket descriptors available");
  125 
  126         case WSAENOBUFS:
  127             return _("no buffer space available");
  128 
  129         case WSAEPROTONOSUPPORT:
  130             return _("protocol not supported");
  131 
  132         case WSAEPROTOTYPE:
  133             return _("wrong protocol type for this socket");
  134 
  135         case WSAESOCKTNOSUPPORT:
  136             return _("socket type is not supported in this address family");
  137 
  138         case WSAEADDRNOTAVAIL:
  139             return _("remote address is not valid");
  140 
  141         case WSAECONNREFUSED:
  142             return _("connection refused");
  143 
  144         case WSAENETUNREACH:
  145             return _("network unreachable");
  146 
  147         case WSAETIMEDOUT:
  148             return _("timeout");
  149 
  150         case WSAENOTCONN:
  151             return _("socket not connected");
  152 
  153         case WSAESHUTDOWN:
  154             return _("the socket was shut down");
  155 
  156         case WSAEHOSTUNREACH:
  157             return _("host unreachable");
  158 
  159         case WSAECONNRESET:
  160             return _("connection reset by peer");
  161 
  162         case WSASYSNOTREADY:
  163             return _("the underlying network subsystem is not ready");
  164 
  165         case WSAVERNOTSUPPORTED:
  166             return _("the requested version is not available");
  167 
  168         case WSAEINPROGRESS:
  169             return _("a blocking operation is in progress");
  170 
  171         case WSAEPROCLIM:
  172             return _("limit on the number of tasks has been reached");
  173 
  174         case WSAEFAULT:
  175             return _("invalid request");
  176 
  177         default:
  178             return _("unknown error");
  179     }
  180 }
  181 #endif /* W32_NATIVE */
  182 
  183 
  184 /*
  185  * Wrapper function for recv() that sets an error string on failure.
  186  */
  187 
  188 int net_recv(int fd, void *buf, size_t len, char **errstr)
  189 {
  190     int r = recv(fd, buf, len, 0);
  191     if (r < 0)
  192     {
  193 #ifdef W32_NATIVE
  194         int e = WSAGetLastError();
  195         if (e == WSAETIMEDOUT)
  196         {
  197             *errstr = xasprintf(_("network read error: %s"),
  198                     _("the operation timed out"));
  199         }
  200         else
  201         {
  202             *errstr = xasprintf(_("network read error: %s"),
  203                     wsa_strerror(e));
  204         }
  205 #else /* !W32_NATIVE */
  206         if (errno == EINTR)
  207         {
  208             *errstr = xasprintf(_("operation aborted"));
  209         }
  210         else if (errno == EAGAIN)
  211         {
  212             *errstr = xasprintf(_("network read error: %s"),
  213                     _("the operation timed out"));
  214         }
  215         else
  216         {
  217             *errstr = xasprintf(_("network read error: %s"),
  218                     strerror(errno));
  219         }
  220 #endif
  221         return -1;
  222     }
  223     return r;
  224 }
  225 
  226 
  227 /*
  228  * Wrapper function for send() that sets an error string on failure.
  229  */
  230 
  231 int net_send(int fd, const void *buf, size_t len, char **errstr)
  232 {
  233 #ifdef W32_NATIVE
  234     int ret;
  235 #else /* !W32_NATIVE */
  236     ssize_t ret;
  237 #endif
  238     if ((ret = send(fd, buf, len, 0)) < 0)
  239     {
  240 #ifdef W32_NATIVE
  241         int e = WSAGetLastError();
  242         if (e == WSAETIMEDOUT)
  243         {
  244             *errstr = xasprintf(_("network write error: %s"),
  245                     _("the operation timed out"));
  246         }
  247         else
  248         {
  249             *errstr = xasprintf(_("network write error: %s"),
  250                     wsa_strerror(e));
  251         }
  252 #else /* !W32_NATIVE */
  253         if (errno == EINTR)
  254         {
  255             *errstr = xasprintf(_("operation aborted"));
  256         }
  257         else if (errno == EAGAIN)
  258         {
  259             *errstr = xasprintf(_("network write error: %s"),
  260                     _("the operation timed out"));
  261         }
  262         else
  263         {
  264             *errstr = xasprintf(_("network write error: %s"),
  265                     strerror(errno));
  266         }
  267 #endif
  268     }
  269     return ret;
  270 }
  271 
  272 
  273 /*
  274  * net_lib_init()
  275  *
  276  * see net.h
  277  */
  278 
  279 int net_lib_init(char **errstr)
  280 {
  281 #ifdef W32_NATIVE
  282     WORD wVersionRequested;
  283     WSADATA wsaData;
  284     int error_code;
  285 
  286     wVersionRequested = MAKEWORD(2, 0);
  287     if ((error_code = WSAStartup(wVersionRequested, &wsaData)) != 0)
  288     {
  289         *errstr = xasprintf("%s", wsa_strerror(error_code));
  290         return NET_ELIBFAILED;
  291     }
  292     else
  293     {
  294         return NET_EOK;
  295     }
  296 #else /* noone else needs this... */
  297     (void)errstr;
  298     return NET_EOK;
  299 #endif
  300 }
  301 
  302 
  303 /*
  304  * net_close_socket()
  305  *
  306  * This function is needed because Windows cannot just close() a socket.
  307  *
  308  * see net.h
  309  */
  310 
  311 void net_close_socket(int fd)
  312 {
  313 #ifdef W32_NATIVE
  314     (void)closesocket(fd);
  315 #else
  316     (void)close(fd);
  317 #endif
  318 }
  319 
  320 
  321 /*
  322  * net_bind_source_ip_to_socket()
  323  *
  324  * This function binds a source IP (in string representation, either IPv6 or IPv4)
  325  * to a socket. It behaves like bind() in terms of return value and errno.
  326  */
  327 
  328 int net_bind_source_ip_to_socket(int fd, const char *source_ip)
  329 {
  330     struct sockaddr_in6 sa6;
  331     struct sockaddr_in sa4;
  332 
  333     memset(&sa6, 0, sizeof(sa6));
  334     if (inet_pton(AF_INET6, source_ip, &sa6.sin6_addr) != 0)
  335     {
  336         sa6.sin6_family = AF_INET6;
  337         return bind(fd, (struct sockaddr *)&sa6, sizeof(sa6));
  338     }
  339     else
  340     {
  341         memset(&sa4, 0, sizeof(sa4));
  342         if (inet_pton(AF_INET, source_ip, &sa4.sin_addr) != 0)
  343         {
  344             sa4.sin_family = AF_INET;
  345             return bind(fd, (struct sockaddr *)&sa4, sizeof(sa4));
  346         }
  347         else
  348         {
  349 #ifdef W32_NATIVE
  350             WSASetLastError(WSAEINVAL);
  351 #else
  352             errno = EINVAL;
  353 #endif
  354             return -1;
  355         }
  356     }
  357 }
  358 
  359 
  360 /*
  361  * net_connect()
  362  *
  363  * connect() with timeout.
  364  *
  365  * This function is equivalent to connect(), except that a connection attempt
  366  * times out after 'timeout' seconds instead of the OS dependant default value.
  367  * A 'timeout' <= 0 will be ignored.
  368  */
  369 
  370 int net_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen,
  371         int timeout)
  372 {
  373 #ifdef W32_NATIVE
  374     u_long flags;
  375     DWORD err;
  376     int optlen;
  377     fd_set eset;
  378 #else
  379     int flags;
  380     int err;
  381     socklen_t optlen;
  382 #endif
  383     struct timeval tv;
  384     fd_set wset;
  385 
  386     if (timeout <= 0)
  387     {
  388         return connect(fd, serv_addr, addrlen);
  389     }
  390     else
  391     {
  392         /* make socket non-blocking */
  393 #ifdef W32_NATIVE
  394         flags = 1;
  395         if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR)
  396 #else
  397         flags = fcntl(fd, F_GETFL, 0);
  398         if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
  399 #endif
  400         {
  401             return -1;
  402         }
  403 
  404         /* start connect */
  405         if (connect(fd, serv_addr, addrlen) < 0)
  406         {
  407 #ifdef W32_NATIVE
  408             if (WSAGetLastError() != WSAEWOULDBLOCK)
  409 #else
  410             if (errno != EINPROGRESS)
  411 #endif
  412             {
  413                 return -1;
  414             }
  415 
  416             tv.tv_sec = timeout;
  417             tv.tv_usec = 0;
  418             FD_ZERO(&wset);
  419             FD_SET(fd, &wset);
  420 #ifdef W32_NATIVE
  421             FD_ZERO(&eset);
  422             FD_SET(fd, &eset);
  423 #endif
  424 
  425             /* wait for connect() to finish */
  426 #ifdef W32_NATIVE
  427             /* In case of an error on connect(), eset will be affected instead
  428              * of wset (on Windows only). */
  429             if ((err = select(fd + 1, NULL, &wset, &eset, &tv)) <= 0)
  430 #else
  431             if ((err = select(fd + 1, NULL, &wset, NULL, &tv)) <= 0)
  432 #endif
  433             {
  434                 /* errno is already set if err < 0 */
  435                 if (err == 0)
  436                 {
  437 #ifdef W32_NATIVE
  438                     WSASetLastError(WSAETIMEDOUT);
  439 #else
  440                     errno = ETIMEDOUT;
  441 #endif
  442                 }
  443                 return -1;
  444             }
  445 
  446             /* test for success, set errno */
  447             optlen = sizeof(err);
  448             if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen) < 0)
  449             {
  450                 return -1;
  451             }
  452             if (err != 0)
  453             {
  454 #ifdef W32_NATIVE
  455                 WSASetLastError(err);
  456 #else
  457                 errno = err;
  458 #endif
  459                 return -1;
  460             }
  461         }
  462 
  463         /* restore blocking mode */
  464 #ifdef W32_NATIVE
  465         flags = 0;
  466         if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR)
  467 #else
  468         if (fcntl(fd, F_SETFL, flags) == -1)
  469 #endif
  470         {
  471             return -1;
  472         }
  473 
  474         return 0;
  475     }
  476 }
  477 
  478 
  479 /*
  480  * net_set_io_timeout()
  481  *
  482  * Sets a timeout for inout/output operations on the given socket.
  483  */
  484 
  485 void net_set_io_timeout(int socket, int seconds)
  486 {
  487 #ifdef W32_NATIVE
  488     DWORD milliseconds;
  489 
  490     if (seconds > 0)
  491     {
  492         milliseconds = seconds * 1000;
  493         (void)setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &milliseconds, sizeof(int));
  494         (void)setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &milliseconds, sizeof(int));
  495     }
  496 #else /* UNIX */
  497     struct timeval tv;
  498 
  499     if (seconds > 0)
  500     {
  501         tv.tv_sec = seconds;
  502         tv.tv_usec = 0;
  503         (void)setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
  504         (void)setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
  505     }
  506 #endif
  507 }
  508 
  509 
  510 /*
  511  * open_socket()
  512  *
  513  * see net.h
  514  */
  515 
  516 int net_socks5_connect(int fd, const char *hostname, int port, char **errstr)
  517 {
  518     /* maximum size of a SOCKS5 message (send or receive) */
  519     unsigned char buffer[1 + 1 + 1 + 1 + 1 + 255 + 2];
  520     size_t hostname_len = strlen(hostname);
  521     uint16_t nport = htons(port);
  522     size_t len;
  523     int ret;
  524 
  525     if (hostname_len > 0xff)
  526     {
  527         /* this hostname cannot be sent in a SOCKS5 message */
  528         *errstr = xasprintf(_("proxy failure: %s"), _("host name too long"));
  529         return NET_EPROXY;
  530     }
  531 
  532     /* Send greeting */
  533     buffer[0] = 0x05;   /* SOCKS5 */
  534     buffer[1] = 0x01;   /* one auth method supported: */
  535     buffer[2] = 0x00;   /* no authentication */
  536     if ((ret = net_send(fd, buffer, 3, errstr)) < 0)
  537     {
  538         return NET_EIO;
  539     }
  540     else if (ret < 3)
  541     {
  542         *errstr = xasprintf(_("network write error"));
  543         return NET_EIO;
  544     }
  545     /* Receive greeting */
  546     if ((ret = net_recv(fd, buffer, 2, errstr)) < 0)
  547     {
  548         return NET_EIO;
  549     }
  550     else if (ret < 2)
  551     {
  552         *errstr = xasprintf(_("network read error"));
  553         return NET_EIO;
  554     }
  555     if (buffer[0] != 0x05               /* SOCKS5 */
  556             || buffer[1] != 0x00)       /* no authentication */
  557     {
  558         *errstr = xasprintf(_("proxy failure: %s"), _("unexpected reply"));
  559         return NET_EPROXY;
  560     }
  561     /* Send CONNECT request */
  562     buffer[0] = 0x05;   /* SOCKS5 */
  563     buffer[1] = 0x01;   /* CONNECT */
  564     buffer[2] = 0x00;   /* reserved */
  565     buffer[3] = 0x03;   /* Domain name follows */
  566     buffer[4] = hostname_len;
  567     memcpy(buffer + 5, hostname, hostname_len);
  568     memcpy(buffer + 5 + hostname_len, &nport, 2);
  569     len = 5 + hostname_len + 2;
  570     if ((ret = net_send(fd, buffer, len, errstr)) < 0)
  571     {
  572         return NET_EIO;
  573     }
  574     else if ((size_t)ret < len)
  575     {
  576         *errstr = xasprintf(_("network write error"));
  577         return NET_EIO;
  578     }
  579     /* Receive answer */
  580     if ((ret = net_recv(fd, buffer, 5, errstr)) < 0)
  581     {
  582         return NET_EIO;
  583     }
  584     else if (ret < 5)
  585     {
  586         *errstr = xasprintf(_("network read error"));
  587         return NET_EIO;
  588     }
  589     if (buffer[0] != 0x05               /* SOCKS5 */
  590             || buffer[2] != 0x00        /* reserved */
  591             || (buffer[3] != 0x01 && buffer[3] != 0x03 && buffer[3] != 0x04))
  592     {
  593         *errstr = xasprintf(_("proxy failure: %s"), _("unexpected reply"));
  594         return NET_EPROXY;
  595     }
  596     if (buffer[3] == 0x01)
  597     {
  598         len = 4 - 1;    /* IPv4 */
  599     }
  600     else if (buffer[3] == 0x04)
  601     {
  602         len = 16 - 1;   /* IPv6 */
  603     }
  604     else /* Domain name */
  605     {
  606         len = buffer[4];
  607     }
  608     len += 2;   /* port number */
  609     if ((ret = net_recv(fd, buffer + 5, len, errstr)) < 0)
  610     {
  611         return NET_EIO;
  612     }
  613     else if ((size_t)ret < len)
  614     {
  615         *errstr = xasprintf(_("network read error"));
  616         return NET_EIO;
  617     }
  618     /* Interpret SOCKS5 status */
  619     switch (buffer[1])
  620     {
  621     case 0x00:
  622         return NET_EOK;
  623     case 0x01:
  624         *errstr = xasprintf(_("proxy failure: %s"), _("general server failure"));
  625         return NET_EPROXY;
  626     case 0x02:
  627         *errstr = xasprintf(_("proxy failure: %s"), _("connection not allowed"));
  628         return NET_EPROXY;
  629     case 0x03:
  630         *errstr = xasprintf(_("proxy failure: %s"), _("network unreachable"));
  631         return NET_EPROXY;
  632     case 0x04:
  633         *errstr = xasprintf(_("proxy failure: %s"), _("host unreachable"));
  634         return NET_EPROXY;
  635     case 0x05:
  636         *errstr = xasprintf(_("proxy failure: %s"), _("connection refused"));
  637         return NET_EPROXY;
  638     case 0x06:
  639         *errstr = xasprintf(_("proxy failure: %s"), _("time-to-live expired"));
  640         return NET_EPROXY;
  641     case 0x07:
  642         *errstr = xasprintf(_("proxy failure: %s"), _("command not supported"));
  643         return NET_EPROXY;
  644     case 0x08:
  645         *errstr = xasprintf(_("proxy failure: %s"), _("address type not supported"));
  646         return NET_EPROXY;
  647     default:
  648         *errstr = xasprintf(_("proxy failure: %s"), _("unknown error"));
  649         return NET_EPROXY;
  650     }
  651 }
  652 
  653 int net_open_socket(
  654         const char *socketname,
  655         const char *proxy_hostname, int proxy_port,
  656         const char *hostname, int port,
  657         const char *source_ip,
  658         int timeout,
  659         int *ret_fd, char **canonical_name, char **address,
  660         char **errstr)
  661 {
  662     int fd;
  663     char *port_string;
  664     struct addrinfo hints;
  665     struct addrinfo *res0;
  666     struct addrinfo *res;
  667     int error_code;
  668     int failure_errno;
  669     int cause;
  670     char nameinfo_buffer[NI_MAXHOST];
  671     char *idn_hostname = NULL;
  672 
  673     if (socketname)
  674     {
  675 #ifdef W32_NATIVE
  676         *errstr = xasprintf(_("cannot connect to %s: %s"), socketname,
  677                 wsa_strerror(WSAESOCKTNOSUPPORT));
  678         return NET_ELIBFAILED;
  679 #else
  680         struct sockaddr_un addr;
  681         if (strlen(socketname) + 1 > sizeof(addr.sun_path))
  682         {
  683             *errstr = xasprintf(_("cannot connect to %s: %s"), socketname,
  684                     _("invalid argument"));
  685             return NET_EIO;
  686         }
  687         if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
  688         {
  689             *errstr = xasprintf(_("cannot create socket: %s"), strerror(errno));
  690             return NET_ESOCKET;
  691         }
  692         memset(&addr, 0, sizeof(addr));
  693         addr.sun_family = AF_UNIX;
  694         strcpy(addr.sun_path, socketname);
  695         if (net_connect(fd, (struct sockaddr *)&addr, sizeof(addr), timeout) < 0)
  696         {
  697             net_close_socket(fd);
  698             *errstr = xasprintf(_("cannot connect to %s: %s"), socketname, strerror(errno));
  699             return NET_ECONNECT;
  700         }
  701         *ret_fd = fd;
  702         if (canonical_name)
  703         {
  704             *canonical_name = NULL;
  705         }
  706         if (address)
  707         {
  708             *address = NULL;
  709         }
  710         return NET_EOK;
  711 #endif
  712     }
  713 
  714     if (proxy_hostname)
  715     {
  716         error_code = net_open_socket(NULL, NULL, -1, proxy_hostname, proxy_port,
  717                 source_ip, timeout, &fd, NULL, NULL, errstr);
  718         if (error_code != NET_EOK)
  719         {
  720             return error_code;
  721         }
  722         error_code = net_socks5_connect(fd, hostname, port, errstr);
  723         if (error_code != NET_EOK)
  724         {
  725             return error_code;
  726         }
  727         *ret_fd = fd;
  728         if (canonical_name)
  729         {
  730             *canonical_name = NULL;
  731         }
  732         if (address)
  733         {
  734             *address = NULL;
  735         }
  736         return NET_EOK;
  737     }
  738 
  739     hints.ai_family = PF_UNSPEC;
  740     hints.ai_socktype = SOCK_STREAM;
  741     hints.ai_flags = 0;
  742     hints.ai_protocol = 0;
  743     hints.ai_addrlen = 0;
  744     hints.ai_canonname = NULL;
  745     hints.ai_addr = NULL;
  746     hints.ai_next = NULL;
  747     port_string = xasprintf("%d", port);
  748 #ifdef HAVE_GAI_IDN
  749 # ifdef AI_IDN
  750     hints.ai_flags |= AI_IDN;
  751 # endif
  752 #elif defined(HAVE_LIBIDN)
  753     idn2_to_ascii_lz(hostname, &idn_hostname, IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
  754 #endif
  755     error_code = getaddrinfo(idn_hostname ? idn_hostname : hostname,
  756             port_string, &hints, &res0);
  757     free(idn_hostname);
  758     free(port_string);
  759     if (error_code)
  760     {
  761 #ifdef W32_NATIVE
  762         *errstr = xasprintf(_("cannot locate host %s: %s"),
  763                 hostname, wsa_strerror(WSAGetLastError()));
  764 #else
  765         if (error_code == EAI_SYSTEM && errno == EINTR)
  766         {
  767             *errstr = xasprintf(_("operation aborted"));
  768         }
  769         else
  770         {
  771             *errstr = xasprintf(_("cannot locate host %s: %s"), hostname,
  772                     error_code == EAI_SYSTEM ? strerror(errno)
  773                     : gai_strerror(error_code));
  774         }
  775 #endif
  776         return NET_EHOSTNOTFOUND;
  777     }
  778 
  779     fd = -1;
  780     cause = 0;
  781     failure_errno = 0;
  782     for (res = res0; res; res = res->ai_next)
  783     {
  784         fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  785         if (fd < 0)
  786         {
  787             cause = 1;
  788 #ifdef W32_NATIVE
  789             failure_errno = WSAGetLastError();
  790 #else
  791             failure_errno = errno;
  792 #endif
  793             continue;
  794         }
  795         if (source_ip && net_bind_source_ip_to_socket(fd, source_ip) != 0)
  796         {
  797             cause = 2;
  798 #ifdef W32_NATIVE
  799             failure_errno = WSAGetLastError();
  800 #else
  801             failure_errno = errno;
  802 #endif
  803             net_close_socket(fd);
  804             fd = -1;
  805             continue;
  806         }
  807         if (net_connect(fd, res->ai_addr, res->ai_addrlen, timeout) < 0)
  808         {
  809             cause = 3;
  810 #ifdef W32_NATIVE
  811             if (WSAGetLastError() != WSAENETUNREACH)
  812             {
  813                 failure_errno = WSAGetLastError();
  814             }
  815 #else
  816             if (errno != ENETUNREACH)
  817             {
  818                 failure_errno = errno;
  819             }
  820 #endif
  821             net_close_socket(fd);
  822             fd = -1;
  823             continue;
  824         }
  825         break;
  826     }
  827 
  828     if (fd >= 0)
  829     {
  830         if (canonical_name)
  831         {
  832             if (getnameinfo(res->ai_addr, res->ai_addrlen, nameinfo_buffer,
  833                         sizeof(nameinfo_buffer), NULL, 0, NI_NAMEREQD) == 0)
  834             {
  835                 *canonical_name = xstrdup(nameinfo_buffer);
  836             }
  837             else
  838             {
  839                 *canonical_name = NULL;
  840             }
  841         }
  842         if (address)
  843         {
  844             if (getnameinfo(res->ai_addr, res->ai_addrlen, nameinfo_buffer,
  845                         sizeof(nameinfo_buffer), NULL, 0, NI_NUMERICHOST) == 0)
  846             {
  847                 *address = xstrdup(nameinfo_buffer);
  848             }
  849             else
  850             {
  851                 *address = NULL;
  852             }
  853         }
  854     }
  855 
  856     freeaddrinfo(res0);
  857 
  858     if (fd < 0)
  859     {
  860         if (cause == 1)
  861         {
  862             *errstr = xasprintf(_("cannot create socket: %s"),
  863 #ifdef W32_NATIVE
  864                     wsa_strerror(failure_errno)
  865 #else
  866                     strerror(failure_errno)
  867 #endif
  868                     );
  869             return NET_ESOCKET;
  870         }
  871         else if (cause == 2)
  872         {
  873             *errstr = xasprintf(_("cannot bind source ip %s: %s"), source_ip,
  874 #ifdef W32_NATIVE
  875                     wsa_strerror(failure_errno)
  876 #else
  877                     strerror(failure_errno)
  878 #endif
  879                     );
  880             return NET_ESOCKET;
  881         }
  882         else /* cause == 3 */
  883         {
  884 #ifdef W32_NATIVE
  885             if (failure_errno == 0)
  886             {
  887                 failure_errno = WSAENETUNREACH;
  888             }
  889             *errstr = xasprintf(_("cannot connect to %s, port %d: %s"),
  890                     hostname, port, wsa_strerror(failure_errno));
  891 #else
  892             if (failure_errno == EINTR)
  893             {
  894                 *errstr = xasprintf(_("operation aborted"));
  895             }
  896             else
  897             {
  898                 if (failure_errno == 0)
  899                 {
  900                     failure_errno = ENETUNREACH;
  901                 }
  902                 *errstr = xasprintf(_("cannot connect to %s, port %d: %s"),
  903                         hostname, port, strerror(failure_errno));
  904             }
  905 #endif
  906             return NET_ECONNECT;
  907         }
  908     }
  909 
  910     net_set_io_timeout(fd, timeout);
  911     *ret_fd = fd;
  912     return NET_EOK;
  913 }
  914 
  915 
  916 /*
  917  * net_readbuf_read()
  918  *
  919  * Wraps read() to provide buffering for net_gets().
  920  */
  921 
  922 int net_readbuf_read(int fd, readbuf_t *readbuf, char *ptr,
  923         char **errstr)
  924 {
  925     if (readbuf->count <= 0)
  926     {
  927         readbuf->count = net_recv(fd, readbuf->buf, sizeof(readbuf->buf), errstr);
  928         if (readbuf->count < 0)
  929         {
  930             return -1;
  931         }
  932         else if (readbuf->count == 0)
  933         {
  934             return 0;
  935         }
  936         readbuf->ptr = readbuf->buf;
  937     }
  938     readbuf->count--;
  939     *ptr = *((readbuf->ptr)++);
  940     return 1;
  941 }
  942 
  943 
  944 /*
  945  * net_gets()
  946  *
  947  * see net.h
  948  */
  949 
  950 int net_gets(int fd, readbuf_t *readbuf,
  951         char *str, size_t size, size_t *len, char **errstr)
  952 {
  953     char c;
  954     size_t i;
  955     int ret;
  956 
  957     i = 0;
  958     while (i + 1 < size)
  959     {
  960         if ((ret = net_readbuf_read(fd, readbuf, &c, errstr)) == 1)
  961         {
  962             str[i++] = c;
  963             if (c == '\n')
  964             {
  965                 break;
  966             }
  967         }
  968         else if (ret == 0)
  969         {
  970             break;
  971         }
  972         else
  973         {
  974             return NET_EIO;
  975         }
  976     }
  977     str[i] = '\0';
  978     *len = i;
  979     return NET_EOK;
  980 }
  981 
  982 
  983 /*
  984  * net_puts()
  985  *
  986  * see net.h
  987  */
  988 
  989 int net_puts(int fd, const char *s, size_t len, char **errstr)
  990 {
  991     int ret;
  992 
  993     if (len < 1)
  994     {
  995         return NET_EOK;
  996     }
  997     if ((ret = net_send(fd, s, len, errstr)) < 0)
  998     {
  999         return NET_EIO;
 1000     }
 1001     else if ((size_t)ret == len)
 1002     {
 1003         return NET_EOK;
 1004     }
 1005     else /* 0 <= ret < len */
 1006     {
 1007         *errstr = xasprintf(_("network write error"));
 1008         return NET_EIO;
 1009     }
 1010 }
 1011 
 1012 
 1013 /*
 1014  * net_get_canonical_hostname()
 1015  *
 1016  * see net.h
 1017  */
 1018 
 1019 char *net_get_canonical_hostname(const char *hostname)
 1020 {
 1021     char buf[256];
 1022     char *canonname = NULL;
 1023     struct addrinfo hints;
 1024     struct addrinfo *res0;
 1025 
 1026     if (!hostname)
 1027     {
 1028         if (gethostname(buf, 256) == 0)
 1029         {
 1030             /* Make sure the hostname is NUL-terminated. */
 1031             buf[255] = '\0';
 1032             hostname = buf;
 1033         }
 1034     }
 1035     if (hostname)
 1036     {
 1037         hints.ai_family = PF_UNSPEC;
 1038         hints.ai_socktype = 0;
 1039         hints.ai_flags = AI_CANONNAME;
 1040         hints.ai_protocol = 0;
 1041         hints.ai_addrlen = 0;
 1042         hints.ai_canonname = NULL;
 1043         hints.ai_addr = NULL;
 1044         hints.ai_next = NULL;
 1045         if (getaddrinfo(hostname, NULL, &hints, &res0) == 0)
 1046         {
 1047             if (res0->ai_canonname)
 1048             {
 1049                 canonname = xstrdup(res0->ai_canonname);
 1050             }
 1051             freeaddrinfo(res0);
 1052         }
 1053     }
 1054     if (!canonname && hostname)
 1055     {
 1056         canonname = xstrdup(hostname);
 1057     }
 1058     if (!canonname)
 1059     {
 1060         canonname = xstrdup("localhost");
 1061     }
 1062 
 1063     return canonname;
 1064 }
 1065 
 1066 
 1067 /*
 1068  * net_get_srv_query()
 1069  *
 1070  * see net.h
 1071  */
 1072 char* net_get_srv_query(const char *domain, const char *service)
 1073 {
 1074     size_t domain_len = strlen(domain);
 1075     size_t service_len = strlen(service);
 1076     size_t query_len = 1 /* '_' */ + service_len + 6 /* "._tcp." */ + domain_len;
 1077     char* query = xmalloc(query_len + 1);
 1078     query[0] = '_';
 1079     strncpy(query + 1, service, service_len);
 1080     strncpy(query + 1 + service_len, "._tcp.", 6);
 1081     strcpy(query + 1 + service_len + 6, domain);
 1082     return query;
 1083 }
 1084 
 1085 
 1086 /*
 1087  * net_get_srv()
 1088  *
 1089  * see net.h
 1090  */
 1091 int net_get_srv_record(const char* query, char **hostname, int *port)
 1092 {
 1093 #ifdef HAVE_LIBRESOLV
 1094 
 1095     unsigned char buffer[NS_PACKETSZ];
 1096     int response_len;
 1097     ns_msg msg;
 1098     int i;
 1099     int current_prio = INT_MAX;
 1100     int current_weight = -1;
 1101     char *current_hostname = NULL;
 1102     int current_port = 0;
 1103 
 1104     response_len = res_query(query, ns_c_in, ns_t_srv, buffer, sizeof(buffer));
 1105     if (response_len < 0) {
 1106         return NET_ESRVNOTFOUND;
 1107     }
 1108 
 1109     ns_initparse(buffer, response_len, &msg);
 1110 
 1111     for (i = 0; i < ns_msg_count(msg, ns_s_an); i++) {
 1112         ns_rr rr;
 1113         if (ns_parserr(&msg, ns_s_an, i, &rr))
 1114             continue; /* don't know what's wrong; ignore this part */
 1115         if (ns_rr_type(rr) == ns_t_srv) {
 1116             char name[NI_MAXHOST];
 1117             int prio, weight;
 1118             if (dn_expand(ns_msg_base(msg), ns_msg_end(msg), ns_rr_rdata(rr) + 6, name, sizeof(name)) < 0)
 1119                 continue; /* don't know what's wrong; ignore this part */
 1120             if (name[0] == '\0')
 1121                 continue; /* empty host name; ignore this part */
 1122             prio = ntohs(*((unsigned short*)ns_rr_rdata(rr) + 0));
 1123             weight = ntohs(*((unsigned short*)ns_rr_rdata(rr) + 1));
 1124             if (prio < current_prio || (prio == current_prio && weight > current_weight)) {
 1125                 free(current_hostname);
 1126                 current_hostname = xstrdup(name);
 1127                 current_port = ntohs(*((unsigned short*)ns_rr_rdata(rr) + 2));
 1128                 current_prio = prio;
 1129                 current_weight = weight;
 1130             }
 1131         }
 1132     }
 1133     if (!current_hostname) {
 1134         /* the loop finished but we did not find usable information */
 1135         return NET_EIO;
 1136     } else {
 1137         *hostname = current_hostname;
 1138         *port = current_port;
 1139         return NET_EOK;
 1140     }
 1141 
 1142 #else
 1143 
 1144     return NET_ELIBFAILED;
 1145 
 1146 #endif
 1147 }
 1148 
 1149 
 1150 /*
 1151  * net_lib_deinit()
 1152  *
 1153  * see net.h
 1154  */
 1155 
 1156 void net_lib_deinit(void)
 1157 {
 1158 #ifdef W32_NATIVE
 1159     (void)WSACleanup();
 1160 #endif
 1161 }
 1162 
 1163 
 1164 /*
 1165  * net_exitcode()
 1166  *
 1167  * see net.h
 1168  */
 1169 
 1170 int net_exitcode(int net_error_code)
 1171 {
 1172     switch (net_error_code)
 1173     {
 1174         case NET_EHOSTNOTFOUND:
 1175             return EX_NOHOST;
 1176         case NET_ESOCKET:
 1177             return EX_OSERR;
 1178         case NET_ECONNECT:
 1179             return EX_TEMPFAIL;
 1180         case NET_EIO:
 1181             return EX_IOERR;
 1182         case NET_EPROXY:
 1183             return EX_UNAVAILABLE;
 1184         case NET_ELIBFAILED:
 1185         default:
 1186             return EX_SOFTWARE;
 1187     }
 1188 }