"Fossies" - the Fresh Open Source Software Archive

Member "msmtp-1.8.5/src/net.c" (6 Jun 2019, 27316 Bytes) of package /linux/privat/msmtp-1.8.5.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 latest Fossies "Diffs" side-by-side code changes report: 1.8.4_vs_1.8.5.

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