"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.11/socket.c" (8 Aug 2018, 22276 Bytes) of package /linux/misc/s-nail-14.9.11.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 "socket.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.9.10_vs_14.9.11.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Socket operations.
    3  *
    4  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    5  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    6  * SPDX-License-Identifier: BSD-3-Clause
    7  */
    8 /*
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 #undef n_FILE
   34 #define n_FILE socket
   35 
   36 #ifndef HAVE_AMALGAMATION
   37 # include "nail.h"
   38 #endif
   39 
   40 EMPTY_FILE()
   41 #ifdef HAVE_SOCKETS
   42 # ifdef HAVE_NONBLOCKSOCK
   43 /*#  include <sys/types.h>*/
   44 #  include <sys/select.h>
   45 /*#  include <sys/time.h>*/
   46 #  include <arpa/inet.h>
   47 /*#  include <netinet/in.h>*/
   48 /*#  include <errno.h>*/
   49 /*#  include <fcntl.h>*/
   50 /*#  include <stdlib.h>*/
   51 /*#  include <unistd.h>*/
   52 # endif
   53 
   54 #include <sys/socket.h>
   55 
   56 #include <netdb.h>
   57 
   58 #include <netinet/in.h>
   59 
   60 #ifdef HAVE_ARPA_INET_H
   61 # include <arpa/inet.h>
   62 #endif
   63 
   64 #ifdef HAVE_XTLS
   65 # include <openssl/err.h>
   66 # include <openssl/rand.h>
   67 # include <openssl/ssl.h>
   68 # include <openssl/x509v3.h>
   69 # include <openssl/x509.h>
   70 #endif
   71 
   72 /* */
   73 static bool_t a_socket_open(struct sock *sp, struct url *urlp);
   74 
   75 /* */
   76 static int a_socket_connect(int fd, struct sockaddr *soap, size_t soapl);
   77 
   78 /* Write to socket fd, restarting on EINTR, unless anything is written */
   79 static long a_socket_xwrite(int fd, char const *data, size_t sz);
   80 
   81 static sigjmp_buf __sopen_actjmp; /* TODO someday, we won't need it no more */
   82 static int        __sopen_sig; /* TODO someday, we won't need it no more */
   83 static void
   84 __sopen_onsig(int sig) /* TODO someday, we won't need it no more */
   85 {
   86    NYD_X; /* Signal handler */
   87    if (__sopen_sig == -1) {
   88       fprintf(n_stderr, _("\nInterrupting this operation may turn "
   89          "the DNS resolver unusable\n"));
   90       __sopen_sig = 0;
   91    } else {
   92       __sopen_sig = sig;
   93       siglongjmp(__sopen_actjmp, 1);
   94    }
   95 }
   96 
   97 static bool_t
   98 a_socket_open(struct sock *sp, struct url *urlp) /* TODO sigstuff; refactor */
   99 {
  100 # ifdef HAVE_SO_XTIMEO
  101    struct timeval tv;
  102 # endif
  103 # ifdef HAVE_SO_LINGER
  104    struct linger li;
  105 # endif
  106 # ifdef HAVE_GETADDRINFO
  107 #  ifndef NI_MAXHOST
  108 #   define NI_MAXHOST 1025
  109 #  endif
  110    char hbuf[NI_MAXHOST];
  111    struct addrinfo hints, *res0 = NULL, *res;
  112 # else
  113    struct sockaddr_in servaddr;
  114    struct in_addr **pptr;
  115    struct hostent *hp;
  116    struct servent *ep;
  117 # endif
  118    sighandler_type volatile ohup, oint;
  119    char const * volatile serv;
  120    int volatile sofd = -1, errval;
  121    NYD2_ENTER;
  122 
  123    memset(sp, 0, sizeof *sp);
  124    n_UNINIT(errval, 0);
  125 
  126    serv = (urlp->url_port != NULL) ? urlp->url_port : urlp->url_proto;
  127 
  128    if (n_poption & n_PO_D_V)
  129       n_err(_("Resolving host %s:%s ... "), urlp->url_host.s, serv);
  130 
  131    /* Signal handling (in respect to __sopen_sig dealing) is heavy, but no
  132     * healing until v15.0 and i want to end up with that functionality */
  133    hold_sigs();
  134    __sopen_sig = 0;
  135    ohup = safe_signal(SIGHUP, &__sopen_onsig);
  136    oint = safe_signal(SIGINT, &__sopen_onsig);
  137    if (sigsetjmp(__sopen_actjmp, 0)) {
  138 jpseudo_jump:
  139       n_err("%s\n",
  140          (__sopen_sig == SIGHUP ? _("Hangup") : _("Interrupted")));
  141       if (sofd >= 0) {
  142          close(sofd);
  143          sofd = -1;
  144       }
  145       goto jjumped;
  146    }
  147    rele_sigs();
  148 
  149 # ifdef HAVE_GETADDRINFO
  150    for (;;) {
  151       memset(&hints, 0, sizeof hints);
  152       hints.ai_socktype = SOCK_STREAM;
  153       __sopen_sig = -1;
  154       errval = getaddrinfo(urlp->url_host.s, serv, &hints, &res0);
  155       if (__sopen_sig != -1) {
  156          __sopen_sig = SIGINT;
  157          goto jpseudo_jump;
  158       }
  159       __sopen_sig = 0;
  160       if (errval == 0)
  161          break;
  162 
  163       if (n_poption & n_PO_D_V)
  164          n_err(_("failed\n"));
  165       n_err(_("Lookup of %s:%s failed: %s\n"),
  166          urlp->url_host.s, serv, gai_strerror(errval));
  167 
  168       /* Error seems to depend on how "smart" the /etc/service code is: is it
  169        * "able" to state whether the service as such is NONAME or does it only
  170        * check for the given ai_socktype.. */
  171       if (errval == EAI_NONAME || errval == EAI_SERVICE) {
  172          if (serv == urlp->url_proto &&
  173                (serv = n_servbyname(urlp->url_proto, NULL)) != NULL &&
  174                *serv != '\0') {
  175             n_err(_("  Trying standard protocol port %s\n"), serv);
  176             n_err(_("  If that succeeds consider including the "
  177                "port in the URL!\n"));
  178             continue;
  179          }
  180          if (serv != urlp->url_port)
  181             n_err(_("  Including a port number in the URL may "
  182                "circumvent this problem\n"));
  183       }
  184       assert(sofd == -1);
  185       errval = 0;
  186       goto jjumped;
  187    }
  188    if (n_poption & n_PO_D_V)
  189       n_err(_("done\n"));
  190 
  191    for (res = res0; res != NULL && sofd < 0; res = res->ai_next) {
  192       if (n_poption & n_PO_D_V) {
  193          if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof hbuf,
  194                NULL, 0, NI_NUMERICHOST))
  195             memcpy(hbuf, "unknown host", sizeof("unknown host"));
  196          n_err(_("%sConnecting to %s:%s ... "),
  197                (res == res0 ? n_empty : "\n"), hbuf, serv);
  198       }
  199 
  200       sofd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  201       if(sofd >= 0 &&
  202             (errval = a_socket_connect(sofd, res->ai_addr, res->ai_addrlen)
  203                ) != n_ERR_NONE)
  204          sofd = -1;
  205    }
  206 
  207 jjumped:
  208    if (res0 != NULL) {
  209       freeaddrinfo(res0);
  210       res0 = NULL;
  211    }
  212 
  213 # else /* HAVE_GETADDRINFO */
  214    if (serv == urlp->url_proto) {
  215       if ((ep = getservbyname(n_UNCONST(serv), "tcp")) != NULL)
  216          urlp->url_portno = ntohs(ep->s_port);
  217       else {
  218          if (n_poption & n_PO_D_V)
  219             n_err(_("failed\n"));
  220          if ((serv = n_servbyname(urlp->url_proto, &urlp->url_portno)) != NULL)
  221             n_err(_("  Unknown service: %s\n"), urlp->url_proto);
  222             n_err(_("  Trying standard protocol port %s\n"), serv);
  223             n_err(_("  If that succeeds consider including the "
  224                "port in the URL!\n"));
  225          else {
  226             n_err(_("  Unknown service: %s\n"), urlp->url_proto);
  227             n_err(_("  Including a port number in the URL may "
  228                "circumvent this problem\n"));
  229             assert(sofd == -1 && errval == 0);
  230             goto jjumped;
  231          }
  232       }
  233    }
  234 
  235    __sopen_sig = -1;
  236    hp = gethostbyname(urlp->url_host.s);
  237    if (__sopen_sig != -1) {
  238       __sopen_sig = SIGINT;
  239       goto jpseudo_jump;
  240    }
  241    __sopen_sig = 0;
  242 
  243    if (hp == NULL) {
  244       char const *emsg;
  245 
  246       if (n_poption & n_PO_D_V)
  247          n_err(_("failed\n"));
  248       switch (h_errno) {
  249       case HOST_NOT_FOUND: emsg = N_("host not found"); break;
  250       default:
  251       case TRY_AGAIN:      emsg = N_("(maybe) try again later"); break;
  252       case NO_RECOVERY:    emsg = N_("non-recoverable server error"); break;
  253       case NO_DATA:        emsg = N_("valid name without IP address"); break;
  254       }
  255       n_err(_("Lookup of %s:%s failed: %s\n"),
  256          urlp->url_host.s, serv, V_(emsg));
  257       goto jjumped;
  258    } else if (n_poption & n_PO_D_V)
  259       n_err(_("done\n"));
  260 
  261    pptr = (struct in_addr**)hp->h_addr_list;
  262    if ((sofd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  263       n_perr(_("could not create socket"), 0);
  264       assert(sofd == -1 && errval == 0);
  265       goto jjumped;
  266    }
  267 
  268    memset(&servaddr, 0, sizeof servaddr);
  269    servaddr.sin_family = AF_INET;
  270    servaddr.sin_port = htons(urlp->url_portno);
  271    memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
  272    if (n_poption & n_PO_D_V)
  273       n_err(_("%sConnecting to %s:%d ... "),
  274          n_empty, inet_ntoa(**pptr), (int)urlp->url_portno);
  275    if((errval = a_socket_connect(sofd, (struct sockaddr*)&servaddr,
  276          sizeof servaddr)) != n_ERR_NONE)
  277       sofd = -1;
  278 jjumped:
  279 # endif /* !HAVE_GETADDRINFO */
  280 
  281    hold_sigs();
  282    safe_signal(SIGINT, oint);
  283    safe_signal(SIGHUP, ohup);
  284    rele_sigs();
  285 
  286    if (sofd < 0) {
  287       if (errval != 0) {
  288          n_perr(_("Could not connect"), errval);
  289          n_err_no = errval;
  290       }
  291       goto jleave;
  292    }
  293 
  294    sp->s_fd = sofd;
  295    if (n_poption & n_PO_D_V)
  296       n_err(_("connected.\n"));
  297 
  298    /* And the regular timeouts XXX configurable */
  299 # ifdef HAVE_SO_XTIMEO
  300    tv.tv_sec = 42;
  301    tv.tv_usec = 0;
  302    (void)setsockopt(sofd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
  303    (void)setsockopt(sofd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
  304 # endif
  305 # ifdef HAVE_SO_LINGER
  306    li.l_onoff = 1;
  307    li.l_linger = 42;
  308    (void)setsockopt(sofd, SOL_SOCKET, SO_LINGER, &li, sizeof li);
  309 # endif
  310 
  311    /* SSL/TLS upgrade? */
  312 # ifdef HAVE_TLS
  313    hold_sigs();
  314 
  315 #  if defined HAVE_GETADDRINFO && defined SSL_CTRL_SET_TLSEXT_HOSTNAME /* TODO
  316       * TODO the SSL_ def check should NOT be here */
  317    if(urlp->url_flags & n_URL_TLS_MASK){
  318       memset(&hints, 0, sizeof hints);
  319       hints.ai_family = AF_UNSPEC;
  320       hints.ai_flags = AI_NUMERICHOST;
  321       res0 = NULL;
  322       if(getaddrinfo(urlp->url_host.s, NULL, &hints, &res0) == 0)
  323          freeaddrinfo(res0);
  324       else
  325          urlp->url_flags |= n_URL_HOST_IS_NAME;
  326    }
  327 #  endif
  328 
  329    if (urlp->url_flags & n_URL_TLS_REQUIRED) {
  330       ohup = safe_signal(SIGHUP, &__sopen_onsig);
  331       oint = safe_signal(SIGINT, &__sopen_onsig);
  332       if (sigsetjmp(__sopen_actjmp, 0)) {
  333          n_err(_("%s during SSL/TLS handshake\n"),
  334             (__sopen_sig == SIGHUP ? _("Hangup") : _("Interrupted")));
  335          goto jsclose;
  336       }
  337       rele_sigs();
  338 
  339       if(!n_tls_open(urlp, sp)){
  340 jsclose:
  341          sclose(sp);
  342          sofd = -1;
  343       }else if(urlp->url_cproto == CPROTO_CERTINFO)
  344          sclose(sp);
  345 
  346       hold_sigs();
  347       safe_signal(SIGINT, oint);
  348       safe_signal(SIGHUP, ohup);
  349    }
  350 
  351    rele_sigs();
  352 # endif /* HAVE_TLS */
  353 
  354 jleave:
  355    /* May need to bounce the signal to the go.c trampoline (or wherever) */
  356    if (__sopen_sig != 0) {
  357       sigset_t cset;
  358       sigemptyset(&cset);
  359       sigaddset(&cset, __sopen_sig);
  360       sigprocmask(SIG_UNBLOCK, &cset, NULL);
  361       n_raise(__sopen_sig);
  362    }
  363    NYD2_LEAVE;
  364    return (sofd >= 0);
  365 }
  366 
  367 static int
  368 a_socket_connect(int fd, struct sockaddr *soap, size_t soapl){
  369    int rv;
  370    NYD_ENTER;
  371 
  372 #ifdef HAVE_NONBLOCKSOCK
  373    rv = fcntl(fd, F_GETFL, 0);
  374    if(rv != -1 && !fcntl(fd, F_SETFL, rv | O_NONBLOCK)){
  375       fd_set fdset;
  376       struct timeval tv; /* XXX configurable */
  377       socklen_t sol;
  378       int i, soe;
  379 
  380       if(connect(fd, soap, soapl) && (i = n_err_no) != n_ERR_INPROGRESS){
  381          rv = i;
  382          goto jerr_noerrno;
  383       }
  384 
  385       FD_ZERO(&fdset);
  386       FD_SET(fd, &fdset);
  387       if(n_poption & n_PO_D_V){
  388          i = 21;
  389          tv.tv_sec = 2;
  390       }else{
  391          i = 1;
  392          tv.tv_sec = 42;
  393       }
  394       tv.tv_usec = 0;
  395 jrewait:
  396       if((soe = select(fd + 1, NULL, &fdset, NULL, &tv)) == 1){
  397          i = rv;
  398          sol = sizeof rv;
  399          getsockopt(fd, SOL_SOCKET, SO_ERROR, &rv, &sol);
  400          fcntl(fd, F_SETFL, i);
  401          if(n_poption & n_PO_D_V)
  402             n_err(" ");
  403       }else if(soe == 0){
  404          if((n_poption & n_PO_D_V) && --i > 0){
  405             n_err(".");
  406             tv.tv_sec = 2;
  407             tv.tv_usec = 0;
  408             goto jrewait;
  409          }
  410          n_err(_(" timeout\n"));
  411          close(fd);
  412          rv = n_ERR_TIMEDOUT;
  413       }else
  414          goto jerr;
  415    }else
  416 #endif /* HAVE_NONBLOCKSOCK */
  417 
  418          if(!connect(fd, soap, soapl))
  419       rv = n_ERR_NONE;
  420    else{
  421 #ifdef HAVE_NONBLOCKSOCK
  422 jerr:
  423 #endif
  424       rv = n_err_no;
  425 #ifdef HAVE_NONBLOCKSOCK
  426 jerr_noerrno:
  427 #endif
  428       n_perr(_("connect(2) failed:"), rv);
  429       close(fd);
  430    }
  431    NYD_LEAVE;
  432    return rv;
  433 }
  434 
  435 static long
  436 a_socket_xwrite(int fd, char const *data, size_t sz)
  437 {
  438    long rv = -1, wo;
  439    size_t wt = 0;
  440    NYD_ENTER;
  441 
  442    do {
  443       if ((wo = write(fd, data + wt, sz - wt)) < 0) {
  444          if (n_err_no == n_ERR_INTR)
  445             continue;
  446          else
  447             goto jleave;
  448       }
  449       wt += wo;
  450    } while (wt < sz);
  451    rv = (long)sz;
  452 jleave:
  453    NYD_LEAVE;
  454    return rv;
  455 }
  456 
  457 FL int
  458 sclose(struct sock *sp)
  459 {
  460    int i;
  461    NYD_ENTER;
  462 
  463    i = sp->s_fd;
  464    sp->s_fd = -1;
  465    /* TODO NOTE: we MUST NOT close the descriptor 0 here...
  466     * TODO of course this should be handled in a VMAILFS->open() .s_fd=-1,
  467     * TODO but unfortunately it isn't yet */
  468    if (i <= 0)
  469       i = 0;
  470    else {
  471       if (sp->s_onclose != NULL)
  472          (*sp->s_onclose)();
  473       if (sp->s_wbuf != NULL)
  474          n_free(sp->s_wbuf);
  475 # ifdef HAVE_XTLS
  476       if (sp->s_use_tls) {
  477          void *s_tls = sp->s_tls;
  478 
  479          sp->s_tls = NULL;
  480          sp->s_use_tls = 0;
  481          while (!SSL_shutdown(s_tls)) /* XXX proper error handling;signals! */
  482             ;
  483          SSL_free(s_tls);
  484       }
  485 # endif
  486       i = close(i);
  487    }
  488    NYD_LEAVE;
  489    return i;
  490 }
  491 
  492 FL enum okay
  493 swrite(struct sock *sp, char const *data)
  494 {
  495    enum okay rv;
  496    NYD2_ENTER;
  497 
  498    rv = swrite1(sp, data, strlen(data), 0);
  499    NYD2_LEAVE;
  500    return rv;
  501 }
  502 
  503 FL enum okay
  504 swrite1(struct sock *sp, char const *data, int sz, int use_buffer)
  505 {
  506    enum okay rv = STOP;
  507    int x;
  508    NYD2_ENTER;
  509 
  510    if (use_buffer > 0) {
  511       int di;
  512 
  513       if (sp->s_wbuf == NULL) {
  514          sp->s_wbufsize = 4096;
  515          sp->s_wbuf = n_alloc(sp->s_wbufsize);
  516          sp->s_wbufpos = 0;
  517       }
  518       while (sp->s_wbufpos + sz > sp->s_wbufsize) {
  519          di = sp->s_wbufsize - sp->s_wbufpos;
  520          sz -= di;
  521          if (sp->s_wbufpos > 0) {
  522             memcpy(sp->s_wbuf + sp->s_wbufpos, data, di);
  523             rv = swrite1(sp, sp->s_wbuf, sp->s_wbufsize, -1);
  524          } else
  525             rv = swrite1(sp, data, sp->s_wbufsize, -1);
  526          if (rv != OKAY)
  527             goto jleave;
  528          data += di;
  529          sp->s_wbufpos = 0;
  530       }
  531       if (sz == sp->s_wbufsize) {
  532          rv = swrite1(sp, data, sp->s_wbufsize, -1);
  533          if (rv != OKAY)
  534             goto jleave;
  535       } else if (sz) {
  536          memcpy(sp->s_wbuf+ sp->s_wbufpos, data, sz);
  537          sp->s_wbufpos += sz;
  538       }
  539       rv = OKAY;
  540       goto jleave;
  541    } else if (use_buffer == 0 && sp->s_wbuf != NULL && sp->s_wbufpos > 0) {
  542       x = sp->s_wbufpos;
  543       sp->s_wbufpos = 0;
  544       if ((rv = swrite1(sp, sp->s_wbuf, x, -1)) != OKAY)
  545          goto jleave;
  546    }
  547    if (sz == 0) {
  548       rv = OKAY;
  549       goto jleave;
  550    }
  551 
  552 # ifdef HAVE_XTLS
  553    if (sp->s_use_tls) {
  554 jssl_retry:
  555       x = SSL_write(sp->s_tls, data, sz);
  556       if (x < 0) {
  557          switch (SSL_get_error(sp->s_tls, x)) {
  558          case SSL_ERROR_WANT_READ:
  559          case SSL_ERROR_WANT_WRITE:
  560             goto jssl_retry;
  561          }
  562       }
  563    } else
  564 # endif
  565    {
  566       x = a_socket_xwrite(sp->s_fd, data, sz);
  567    }
  568    if (x != sz) {
  569       char o[512];
  570 
  571       snprintf(o, sizeof o, "%s write error",
  572          (sp->s_desc ? sp->s_desc : "socket"));
  573 # ifdef HAVE_XTLS
  574       if (sp->s_use_tls)
  575          ssl_gen_err("%s", o);
  576       else
  577 # endif
  578          n_perr(o, 0);
  579       if (x < 0)
  580          sclose(sp);
  581       rv = STOP;
  582       goto jleave;
  583    }
  584    rv = OKAY;
  585 jleave:
  586    NYD2_LEAVE;
  587    return rv;
  588 }
  589 
  590 FL bool_t
  591 sopen(struct sock *sp, struct url *urlp){
  592    char const *cp;
  593    bool_t rv;
  594    NYD_ENTER;
  595 
  596    rv = FAL0;
  597 
  598    /* We may have a proxy configured */
  599    if((cp = xok_vlook(socks_proxy, urlp, OXM_ALL)) == NULL)
  600       rv = a_socket_open(sp, urlp);
  601    else{
  602       ui8_t pbuf[4 + 1 + 255 + 2];
  603       size_t i;
  604       char const *emsg;
  605       struct url url2;
  606 
  607       if(!url_parse(&url2, CPROTO_SOCKS, cp)){
  608          n_err(_("Failed to parse *socks-proxy*: %s\n"), cp);
  609          goto jleave;
  610       }
  611       if(urlp->url_host.l > 255){
  612          n_err(_("*socks-proxy*: hostname too long: %s\n"),
  613             urlp->url_input);
  614          goto jleave;
  615       }
  616 
  617       if (n_poption & n_PO_D_V)
  618          n_err(_("Connecting via *socks-proxy* to %s:%s ...\n"),
  619             urlp->url_host.s,
  620             (urlp->url_port != NULL ? urlp->url_port : urlp->url_proto));
  621 
  622       if(!a_socket_open(sp, &url2)){
  623          n_err(_("Failed to connect to *socks-proxy*: %s\n"), cp);
  624          goto jleave;
  625       }
  626 
  627       /* RFC 1928: version identifier/method selection message */
  628       pbuf[0] = 0x05; /* VER: protocol version: X'05' */
  629       pbuf[1] = 0x01; /* NMETHODS: 1 */
  630       pbuf[2] = 0x00; /* METHOD: X'00' NO AUTHENTICATION REQUIRED */
  631       if(write(sp->s_fd, pbuf, 3) != 3){
  632 jerrsocks:
  633          n_perr("*socks-proxy*", 0);
  634 jesocks:
  635          sclose(sp);
  636          goto jleave;
  637       }
  638 
  639       /* Receive greeting */
  640       if(read(sp->s_fd, pbuf, 2) != 2)
  641          goto jerrsocks;
  642       if(pbuf[0] != 0x05 || pbuf[1] != 0x00){
  643 jesocksreply:
  644          emsg = N_("unexpected reply\n");
  645 jesocksreplymsg:
  646          /* I18N: error message and failing URL */
  647          n_err(_("*socks-proxy*: %s: %s\n"), V_(emsg), cp);
  648          goto jesocks;
  649       }
  650 
  651       /* RFC 1928: CONNECT request */
  652       pbuf[0] = 0x05; /* VER: protocol version: X'05' */
  653       pbuf[1] = 0x01; /* CMD: CONNECT X'01' */
  654       pbuf[2] = 0x00; /* RESERVED */
  655       pbuf[3] = 0x03; /* ATYP: domain name */
  656       pbuf[4] = (ui8_t)urlp->url_host.l;
  657       memcpy(&pbuf[i = 5], urlp->url_host.s, urlp->url_host.l);
  658       /* C99 */{
  659          ui16_t x;
  660 
  661          x = htons(urlp->url_portno);
  662          memcpy(&pbuf[i += urlp->url_host.l], (ui8_t*)&x, sizeof x);
  663          i += sizeof x;
  664       }
  665       if(write(sp->s_fd, pbuf, i) != (ssize_t)i)
  666          goto jerrsocks;
  667 
  668       /* Connect result */
  669       if((i = read(sp->s_fd, pbuf, 4)) != 4)
  670          goto jerrsocks;
  671       /* Version 5, reserved must be 0 */
  672       if(pbuf[0] != 0x05 || pbuf[2] != 0x00)
  673          goto jesocksreply;
  674       /* Result */
  675       switch(pbuf[1]){
  676       case 0x00: emsg = NULL; break;
  677       case 0x01: emsg = N_("SOCKS server failure"); break;
  678       case 0x02: emsg = N_("connection not allowed by ruleset"); break;
  679       case 0x03: emsg = N_("network unreachable"); break;
  680       case 0x04: emsg = N_("host unreachable"); break;
  681       case 0x05: emsg = N_("connection refused"); break;
  682       case 0x06: emsg = N_("TTL expired"); break;
  683       case 0x07: emsg = N_("command not supported"); break;
  684       case 0x08: emsg = N_("address type not supported"); break;
  685       default: emsg = N_("unknown SOCKS error code"); break;
  686       }
  687       if(emsg != NULL)
  688          goto jesocksreplymsg;
  689 
  690       /* Address type variable; read the BND.PORT with it.
  691        * This is actually false since RFC 1928 says that the BND.ADDR reply to
  692        * CONNECT contains the IP address, so only 0x01 and 0x04 are allowed */
  693       switch(pbuf[3]){
  694       case 0x01: i = 4; break;
  695       case 0x03: i = 1; break;
  696       case 0x04: i = 16; break;
  697       default: goto jesocksreply;
  698       }
  699       i += sizeof(ui16_t);
  700       if(read(sp->s_fd, pbuf, i) != (ssize_t)i)
  701          goto jerrsocks;
  702       if(i == 1 + sizeof(ui16_t)){
  703          i = pbuf[0];
  704          if(read(sp->s_fd, pbuf, i) != (ssize_t)i)
  705             goto jerrsocks;
  706       }
  707       rv = TRU1;
  708    }
  709 jleave:
  710    NYD_LEAVE;
  711    return rv;
  712 }
  713 
  714 FL int
  715 (sgetline)(char **line, size_t *linesize, size_t *linelen, struct sock *sp
  716    n_MEMORY_DEBUG_ARGS)
  717 {
  718    int rv;
  719    size_t lsize;
  720    char *lp_base, *lp;
  721    NYD2_ENTER;
  722 
  723    lsize = *linesize;
  724    lp_base = *line;
  725    lp = lp_base;
  726 
  727    if (sp->s_rsz < 0) {
  728       sclose(sp);
  729       rv = sp->s_rsz;
  730       goto jleave;
  731    }
  732 
  733    do {
  734       if (lp_base == NULL || PTRCMP(lp, >, lp_base + lsize - 128)) {
  735          size_t diff = PTR2SIZE(lp - lp_base);
  736          *linesize = (lsize += 256); /* XXX magic */
  737          *line = lp_base = (n_realloc)(lp_base, lsize n_MEMORY_DEBUG_ARGSCALL);
  738          lp = lp_base + diff;
  739       }
  740 
  741       if (sp->s_rbufptr == NULL ||
  742             PTRCMP(sp->s_rbufptr, >=, sp->s_rbuf + sp->s_rsz)) {
  743 # ifdef HAVE_XTLS
  744          if (sp->s_use_tls) {
  745 jssl_retry:
  746             sp->s_rsz = SSL_read(sp->s_tls, sp->s_rbuf, sizeof sp->s_rbuf);
  747             if (sp->s_rsz <= 0) {
  748                if (sp->s_rsz < 0) {
  749                   char o[512];
  750 
  751                   switch(SSL_get_error(sp->s_tls, sp->s_rsz)) {
  752                   case SSL_ERROR_WANT_READ:
  753                   case SSL_ERROR_WANT_WRITE:
  754                      goto jssl_retry;
  755                   }
  756                   snprintf(o, sizeof o, "%s",
  757                      (sp->s_desc ?  sp->s_desc : "socket"));
  758                   ssl_gen_err("%s", o);
  759                }
  760                break;
  761             }
  762          } else
  763 # endif
  764          {
  765 jagain:
  766             sp->s_rsz = read(sp->s_fd, sp->s_rbuf, sizeof sp->s_rbuf);
  767             if (sp->s_rsz <= 0) {
  768                if (sp->s_rsz < 0) {
  769                   char o[512];
  770 
  771                   if (n_err_no == n_ERR_INTR)
  772                      goto jagain;
  773                   snprintf(o, sizeof o, "%s",
  774                      (sp->s_desc ?  sp->s_desc : "socket"));
  775                   n_perr(o, 0);
  776                }
  777                break;
  778             }
  779          }
  780          sp->s_rbufptr = sp->s_rbuf;
  781       }
  782    } while ((*lp++ = *sp->s_rbufptr++) != '\n');
  783    *lp = '\0';
  784    lsize = PTR2SIZE(lp - lp_base);
  785 
  786    if (linelen)
  787       *linelen = lsize;
  788    rv = (int)lsize;
  789 jleave:
  790    NYD2_LEAVE;
  791    return rv;
  792 }
  793 #endif /* HAVE_SOCKETS */
  794 
  795 /* s-it-mode */