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