1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4 
5 /* Copyright (c) University of Cambridge 1995 - 2018 */
6 /* Copyright (c) The Exim Maintainers 2020 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 
9 /* Functions for doing things with sockets. With the advent of IPv6 this has
10 got messier, so that it's worth pulling out the code into separate functions
11 that other parts of Exim can call, especially as there are now several
12 different places in the code where sockets are used. */
13 
14 
15 #include "exim.h"
16 
17 
18 #if defined(TCP_FASTOPEN)
19 # if defined(MSG_FASTOPEN) || defined(EXIM_TFO_CONNECTX) || defined(EXIM_TFO_FREEBSD)
20 #  define EXIM_SUPPORT_TFO
21 # endif
22 #endif
23 
24 /*************************************************
25 *             Create a socket                    *
26 *************************************************/
27 
28 /* Socket creation happens in a number of places so it's packaged here for
29 convenience.
30 
31 Arguments:
32   type       SOCK_DGRAM or SOCK_STREAM
33   af         AF_INET or AF_INET6
34 
35 Returns:     socket number or -1 on failure
36 */
37 
38 int
ip_socket(int type,int af)39 ip_socket(int type, int af)
40 {
41 int sock = socket(af, type, 0);
42 if (sock < 0)
43   log_write(0, LOG_MAIN, "IPv%c socket creation failed: %s",
44     (af == AF_INET6)? '6':'4', strerror(errno));
45 return sock;
46 }
47 
48 
49 
50 
51 #if HAVE_IPV6
52 /*************************************************
53 *      Convert printing address to numeric       *
54 *************************************************/
55 
56 /* This function converts the textual form of an IP address into a numeric form
57 in an appropriate structure in an IPv6 environment. The getaddrinfo() function
58 can (apparently) handle more complicated addresses (e.g. those containing
59 scopes) than inet_pton() in some environments. We use hints to tell it that the
60 input must be a numeric address.
61 
62 However, apparently some operating systems (or libraries) don't support
63 getaddrinfo(), so there is a build-time option to revert to inet_pton() (which
64 does not support scopes).
65 
66 Arguments:
67   address     textual form of the address
68   addr        where to copy back the answer
69 
70 Returns:      nothing - failure provokes a panic-die
71 */
72 
73 static void
ip_addrinfo(const uschar * address,struct sockaddr_in6 * saddr)74 ip_addrinfo(const uschar *address, struct sockaddr_in6 *saddr)
75 {
76 #ifdef IPV6_USE_INET_PTON
77 
78   if (inet_pton(AF_INET6, CCS address, &saddr->sin6_addr) != 1)
79     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "unable to parse \"%s\" as an "
80       "IP address", address);
81   saddr->sin6_family = AF_INET6;
82 
83 #else
84 
85   int rc;
86   struct addrinfo hints, *res;
87   memset(&hints, 0, sizeof(hints));
88   hints.ai_family = AF_INET6;
89   hints.ai_socktype = SOCK_STREAM;
90   hints.ai_flags = AI_NUMERICHOST;
91   if ((rc = getaddrinfo(CCS address, NULL, &hints, &res)) != 0 || res == NULL)
92     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "unable to parse \"%s\" as an "
93       "IP address: %s", address,
94       (rc == 0)? "NULL result returned" : gai_strerror(rc));
95   memcpy(saddr, res->ai_addr, res->ai_addrlen);
96   freeaddrinfo(res);
97 
98 #endif
99 }
100 #endif  /* HAVE_IPV6 */
101 
102 
103 /*************************************************
104 *         Bind socket to interface and port      *
105 *************************************************/
106 
107 int
ip_addr(void * sin_,int af,const uschar * address,int port)108 ip_addr(void * sin_, int af, const uschar * address, int port)
109 {
110 union sockaddr_46 * sin = sin_;
111 memset(sin, 0, sizeof(*sin));
112 
113 /* Setup code when using an IPv6 socket. The wildcard address is ":", to
114 ensure an IPv6 socket is used. */
115 
116 #if HAVE_IPV6
117 if (af == AF_INET6)
118   {
119   if (address[0] == ':' && address[1] == 0)
120     {
121     sin->v6.sin6_family = AF_INET6;
122     sin->v6.sin6_addr = in6addr_any;
123     }
124   else
125     ip_addrinfo(address, &sin->v6);  /* Panic-dies on error */
126   sin->v6.sin6_port = htons(port);
127   return sizeof(sin->v6);
128   }
129 else
130 #endif    /* HAVE_IPV6 */
131 
132 /* Setup code when using IPv4 socket. The wildcard address is "". */
133 
134   {
135   sin->v4.sin_family = AF_INET;
136   sin->v4.sin_port = htons(port);
137   sin->v4.sin_addr.s_addr = address[0] == 0
138     ? (S_ADDR_TYPE)INADDR_ANY
139     : (S_ADDR_TYPE)inet_addr(CS address);
140   return sizeof(sin->v4);
141   }
142 }
143 
144 
145 
146 /* This function binds a socket to a local interface address and port. For a
147 wildcard IPv6 bind, the address is ":".
148 
149 Arguments:
150   sock           the socket
151   af             AF_INET or AF_INET6 - the socket type
152   address        the IP address, in text form
153   port           the IP port (host order)
154 
155 Returns:         the result of bind()
156 */
157 
158 int
ip_bind(int sock,int af,uschar * address,int port)159 ip_bind(int sock, int af, uschar *address, int port)
160 {
161 union sockaddr_46 sin;
162 int s_len = ip_addr(&sin, af, address, port);
163 return bind(sock, (struct sockaddr *)&sin, s_len);
164 }
165 
166 
167 
168 /*************************************************
169 *        Connect socket to remote host           *
170 *************************************************/
171 
172 /* This function connects a socket to a remote address and port. The socket may
173 or may not have previously been bound to a local interface. The socket is not
174 closed, even in cases of error. It is expected that the calling function, which
175 created the socket, will be the one that closes it.
176 
177 Arguments:
178   sock        the socket
179   af          AF_INET6 or AF_INET for the socket type
180   address     the remote address, in text form
181   port        the remote port
182   timeout     a timeout (zero for indefinite timeout)
183   fastopen_blob    non-null iff TCP_FASTOPEN can be used; may indicate early-data to
184 		be sent in SYN segment.  Any such data must be idempotent.
185 
186 Returns:      0 on success; -1 on failure, with errno set
187 */
188 
189 int
ip_connect(int sock,int af,const uschar * address,int port,int timeout,const blob * fastopen_blob)190 ip_connect(int sock, int af, const uschar *address, int port, int timeout,
191   const blob * fastopen_blob)
192 {
193 struct sockaddr_in s_in4;
194 struct sockaddr *s_ptr;
195 int s_len, rc, save_errno;
196 
197 /* For an IPv6 address, use an IPv6 sockaddr structure. */
198 
199 #if HAVE_IPV6
200 struct sockaddr_in6 s_in6;
201 if (af == AF_INET6)
202   {
203   memset(&s_in6, 0, sizeof(s_in6));
204   ip_addrinfo(address, &s_in6);   /* Panic-dies on error */
205   s_in6.sin6_port = htons(port);
206   s_ptr = (struct sockaddr *)&s_in6;
207   s_len = sizeof(s_in6);
208   }
209 else
210 #endif    /* HAVE_IPV6 */
211 
212 /* For an IPv4 address, use an IPv4 sockaddr structure, even on a system with
213 IPv6 support. */
214 
215   {
216   memset(&s_in4, 0, sizeof(s_in4));
217   s_in4.sin_family = AF_INET;
218   s_in4.sin_port = htons(port);
219   s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(CCS address);
220   s_ptr = (struct sockaddr *)&s_in4;
221   s_len = sizeof(s_in4);
222   }
223 
224 /* If no connection timeout is set, just call connect() without setting a
225 timer, thereby allowing the inbuilt OS timeout to operate. */
226 
227 callout_address = string_sprintf("[%s]:%d", address, port);
228 sigalrm_seen = FALSE;
229 if (timeout > 0) ALARM(timeout);
230 
231 #ifdef EXIM_SUPPORT_TFO
232 /* TCP Fast Open, if the system has a cookie from a previous call to
233 this peer, can send data in the SYN packet.  The peer can send data
234 before it gets our ACK of its SYN,ACK - the latter is useful for
235 the SMTP banner.  Other (than SMTP) cases of TCP connections can
236 possibly use the data-on-syn, so support that too. */
237 
238 if (fastopen_blob && f.tcp_fastopen_ok)
239   {
240 # ifdef MSG_FASTOPEN
241   /* This is a Linux implementation. */
242 
243   if ((rc = sendto(sock, fastopen_blob->data, fastopen_blob->len,
244 		    MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) >= 0)
245 	/* seen for with-data, experimental TFO option, with-cookie case */
246 	/* seen for with-data, proper TFO opt, with-cookie case */
247     {
248     DEBUG(D_transport|D_v)
249       debug_printf(" TFO mode connection attempt to %s, %lu data\n",
250 	address, (unsigned long)fastopen_blob->len);
251     /*XXX also seen on successful TFO, sigh */
252     tcp_out_fastopen = fastopen_blob->len > 0 ?  TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA;
253     }
254   else switch (errno)
255     {
256     case EINPROGRESS:	/* expected if we had no cookie for peer */
257 	/* seen for no-data, proper TFO option, both cookie-request and with-cookie cases */
258 	/*  apparently no visibility of the diffference at this point */
259 	/* seen for with-data, proper TFO opt, cookie-req */
260 	/*   with netwk delay, post-conn tcp_info sees unacked 1 for R, 2 for C; code in smtp_out.c */
261 	/* ? older Experimental TFO option behaviour ? */
262       DEBUG(D_transport|D_v) debug_printf(" TFO mode sendto, %s data: EINPROGRESS\n",
263 	fastopen_blob->len > 0 ? "with"  : "no");
264       if (!fastopen_blob->data)
265 	{
266 	tcp_out_fastopen = TFO_ATTEMPTED_NODATA;		/* we tried; unknown if useful yet */
267 	rc = 0;
268 	}
269       else					/* queue unsent data */
270 	rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
271       break;
272 
273     case EOPNOTSUPP:
274       DEBUG(D_transport)
275 	debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n");
276       goto legacy_connect;
277 
278     case EPIPE:
279       DEBUG(D_transport)
280 	debug_printf("Tried TCP Fast Open but kernel too old to support it\n");
281       goto legacy_connect;
282     }
283 
284 # elif defined(EXIM_TFO_FREEBSD)
285   /* Re: https://people.freebsd.org/~pkelsey/tfo-tools/tfo-client.c */
286 
287   if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &on, sizeof(on)) < 0)
288     {
289     DEBUG(D_transport)
290       debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n");
291     goto legacy_connect;
292     }
293   if ((rc = sendto(sock, fastopen_blob->data, fastopen_blob->len, 0,
294 		    s_ptr, s_len)) >= 0)
295     {
296     DEBUG(D_transport|D_v)
297       debug_printf(" TFO mode connection attempt to %s, %lu data\n",
298 	address, (unsigned long)fastopen_blob->len);
299     tcp_out_fastopen = fastopen_blob->len > 0 ?  TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA;
300     }
301 
302 # elif defined(EXIM_TFO_CONNECTX)
303   /* MacOS */
304   sa_endpoints_t ends = {
305     .sae_srcif = 0, .sae_srcaddr = NULL, .sae_srcaddrlen = 0,
306     .sae_dstaddr = s_ptr, .sae_dstaddrlen = s_len };
307   struct iovec iov = {
308     .iov_base = fastopen_blob->data, .iov_len = fastopen_blob->len };
309   size_t len;
310 
311   if ((rc = connectx(sock, &ends, SAE_ASSOCID_ANY,
312 	     CONNECT_DATA_IDEMPOTENT, &iov, 1, &len, NULL)) == 0)
313     {
314     DEBUG(D_transport|D_v)
315       debug_printf(" TFO mode connection attempt to %s, %lu data\n",
316 	address, (unsigned long)fastopen_blob->len);
317     tcp_out_fastopen = fastopen_blob->len > 0 ?  TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA;
318 
319     if (len != fastopen_blob->len)
320       DEBUG(D_transport|D_v)
321 	debug_printf(" only queued %lu data!\n", (unsigned long)len);
322     }
323   else if (errno == EINPROGRESS)
324     {
325     DEBUG(D_transport|D_v) debug_printf(" TFO mode connectx, %s data: EINPROGRESS\n",
326       fastopen_blob->len > 0 ? "with"  : "no");
327     if (!fastopen_blob->data)
328       {
329       tcp_out_fastopen = TFO_ATTEMPTED_NODATA;		/* we tried; unknown if useful yet */
330       rc = 0;
331       }
332     else	/* assume that no data was queued; block in send */
333       rc = send(sock, fastopen_blob->data, fastopen_blob->len, 0);
334     }
335 # endif
336   }
337 else
338 #endif	/*EXIM_SUPPORT_TFO*/
339   {
340 #if defined(EXIM_SUPPORT_TFO) && !defined(EXIM_TFO_CONNECTX)
341 legacy_connect:
342 #endif
343 
344   DEBUG(D_transport|D_v) if (fastopen_blob)
345     debug_printf(" non-TFO mode connection attempt to %s, %lu data\n",
346       address, (unsigned long)fastopen_blob->len);
347   if ((rc = connect(sock, s_ptr, s_len)) >= 0)
348     if (  fastopen_blob && fastopen_blob->data && fastopen_blob->len
349        && send(sock, fastopen_blob->data, fastopen_blob->len, 0) < 0)
350 	rc = -1;
351   }
352 
353 save_errno = errno;
354 ALARM_CLR(0);
355 
356 /* There is a testing facility for simulating a connection timeout, as I
357 can't think of any other way of doing this. It converts a connection refused
358 into a timeout if the timeout is set to 999999. */
359 
360 if (f.running_in_test_harness  && save_errno == ECONNREFUSED && timeout == 999999)
361   {
362   rc = -1;
363   save_errno = EINTR;
364   sigalrm_seen = TRUE;
365   }
366 
367 /* Success */
368 
369 if (rc >= 0)
370   return 0;
371 
372 /* A failure whose error code is "Interrupted system call" is in fact
373 an externally applied timeout if the signal handler has been run. */
374 
375 errno = save_errno == EINTR && sigalrm_seen ? ETIMEDOUT : save_errno;
376 return -1;
377 }
378 
379 
380 
381 /*************************************************
382 *    Create connected socket to remote host      *
383 *************************************************/
384 
385 /* Create a socket and connect to host (name or number, ipv6 ok)
386    at one of port-range.
387 
388 Arguments:
389   type          SOCK_DGRAM or SOCK_STREAM
390   af            AF_INET6 or AF_INET for the socket type
391   hostname	host name, or ip address (as text)
392   portlo,porthi the remote port range
393   timeout       a timeout
394   connhost	if not NULL, host_item to be filled in with connection details
395   errstr        pointer for allocated string on error
396   fastopen_blob	with SOCK_STREAM, if non-null, request TCP Fast Open.
397 		Additionally, optional idempotent early-data to send
398 
399 Return:
400   socket fd, or -1 on failure (having allocated an error string)
401 */
402 int
ip_connectedsocket(int type,const uschar * hostname,int portlo,int porthi,int timeout,host_item * connhost,uschar ** errstr,const blob * fastopen_blob)403 ip_connectedsocket(int type, const uschar * hostname, int portlo, int porthi,
404       int timeout, host_item * connhost, uschar ** errstr, const blob * fastopen_blob)
405 {
406 int namelen;
407 host_item shost;
408 int af = 0, fd, fd4 = -1, fd6 = -1;
409 
410 shost.next = NULL;
411 shost.address = NULL;
412 shost.port = portlo;
413 shost.mx = -1;
414 
415 namelen = Ustrlen(hostname);
416 
417 /* Anything enclosed in [] must be an IP address. */
418 
419 if (hostname[0] == '[' &&
420     hostname[namelen - 1] == ']')
421   {
422   uschar * host = string_copyn(hostname+1, namelen-2);
423   if (string_is_ip_address(host, NULL) == 0)
424     {
425     *errstr = string_sprintf("malformed IP address \"%s\"", hostname);
426     return -1;
427     }
428   shost.name = shost.address = host;
429   }
430 
431 /* Otherwise check for an unadorned IP address */
432 
433 else if (string_is_ip_address(hostname, NULL) != 0)
434   shost.name = shost.address = string_copyn(hostname, namelen);
435 
436 /* Otherwise lookup IP address(es) from the name */
437 
438 else
439   {
440   shost.name = string_copyn(hostname, namelen);
441   if (host_find_byname(&shost, NULL, HOST_FIND_QUALIFY_SINGLE,
442       NULL, FALSE) != HOST_FOUND)
443     {
444     *errstr = string_sprintf("no IP address found for host %s", shost.name);
445     return -1;
446     }
447   }
448 
449 /* Try to connect to the server - test each IP till one works */
450 
451 for (host_item * h = &shost; h; h = h->next)
452   {
453   fd = Ustrchr(h->address, ':') != 0
454     ? fd6 < 0 ? (fd6 = ip_socket(type, af = AF_INET6)) : fd6
455     : fd4 < 0 ? (fd4 = ip_socket(type, af = AF_INET )) : fd4;
456 
457   if (fd < 0)
458     {
459     *errstr = string_sprintf("failed to create socket: %s", strerror(errno));
460     goto bad;
461     }
462 
463   for (int port = portlo; port <= porthi; port++)
464     if (ip_connect(fd, af, h->address, port, timeout, fastopen_blob) == 0)
465       {
466       if (fd6 >= 0 && fd != fd6) close(fd6);
467       if (fd4 >= 0 && fd != fd4) close(fd4);
468       if (connhost)
469 	{
470 	h->port = port;
471 	*connhost = *h;
472 	connhost->next = NULL;
473 	}
474       return fd;
475       }
476   }
477 
478 *errstr = string_sprintf("failed to connect to any address for %s: %s",
479   hostname, strerror(errno));
480 
481 bad:
482   close(fd4); close(fd6); return -1;
483 }
484 
485 
486 /*XXX TFO? */
487 int
ip_tcpsocket(const uschar * hostport,uschar ** errstr,int tmo,host_item * connhost)488 ip_tcpsocket(const uschar * hostport, uschar ** errstr, int tmo,
489   host_item * connhost)
490 {
491 int scan;
492 uschar hostname[256];
493 unsigned int portlow, porthigh;
494 
495 /* extract host and port part */
496 scan = sscanf(CS hostport, "%255s %u-%u", hostname, &portlow, &porthigh);
497 if (scan != 3)
498   {
499   if (scan != 2)
500     {
501     *errstr = string_sprintf("invalid socket '%s'", hostport);
502     return -1;
503     }
504   porthigh = portlow;
505   }
506 
507 return ip_connectedsocket(SOCK_STREAM, hostname, portlow, porthigh,
508 			  tmo, connhost, errstr, NULL);
509 }
510 
511 int
ip_unixsocket(const uschar * path,uschar ** errstr)512 ip_unixsocket(const uschar * path, uschar ** errstr)
513 {
514 int sock;
515 struct sockaddr_un server;
516 
517 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
518   {
519   *errstr = US"can't open UNIX socket.";
520   return -1;
521   }
522 
523 callout_address = string_copy(path);
524 server.sun_family = AF_UNIX;
525 Ustrncpy(US server.sun_path, path, sizeof(server.sun_path)-1);
526 server.sun_path[sizeof(server.sun_path)-1] = '\0';
527 if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0)
528   {
529   int err = errno;
530   (void)close(sock);
531   *errstr = string_sprintf("unable to connect to UNIX socket (%s): %s",
532 		path, strerror(err));
533   return -1;
534   }
535 return sock;
536 }
537 
538 /* spec is either an absolute path (with a leading /), or
539 a host (name or IP) and port (whitespace-separated).
540 The port can be a range, dash-separated, or a single number.
541 
542 For a TCP socket, optionally fill in a  host_item.
543 */
544 int
ip_streamsocket(const uschar * spec,uschar ** errstr,int tmo,host_item * connhost)545 ip_streamsocket(const uschar * spec, uschar ** errstr, int tmo,
546   host_item * connhost)
547 {
548 return *spec == '/'
549   ? ip_unixsocket(spec, errstr) : ip_tcpsocket(spec, errstr, tmo, connhost);
550 }
551 
552 /*************************************************
553 *         Set keepalive on a socket              *
554 *************************************************/
555 
556 /* Can be called for both incoming and outgoing sockets.
557 
558 Arguments:
559   sock       the socket
560   address    the remote host address, for failure logging
561   torf       true for outgoing connection, false for incoming
562 
563 Returns:     nothing
564 */
565 
566 void
ip_keepalive(int sock,const uschar * address,BOOL torf)567 ip_keepalive(int sock, const uschar *address, BOOL torf)
568 {
569 int fodder = 1;
570 if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
571     US (&fodder), sizeof(fodder)) != 0)
572   log_write(0, LOG_MAIN, "setsockopt(SO_KEEPALIVE) on connection %s %s "
573     "failed: %s", torf? "to":"from", address, strerror(errno));
574 }
575 
576 
577 
578 /*************************************************
579 *         Receive from a socket with timeout     *
580 *************************************************/
581 
582 /*
583 Arguments:
584   fd          the file descriptor
585   timelimit   the timeout endpoint, seconds-since-epoch
586 Returns:      TRUE => ready for i/o
587               FALSE => timed out, or other error
588 */
589 BOOL
fd_ready(int fd,time_t timelimit)590 fd_ready(int fd, time_t timelimit)
591 {
592 int rc, time_left = timelimit - time(NULL);
593 
594 if (time_left <= 0)
595   {
596   errno = ETIMEDOUT;
597   return FALSE;
598   }
599 /* Wait until the socket is ready */
600 
601 do
602   {
603   /*DEBUG(D_transport) debug_printf("waiting for data on fd\n");*/
604   rc = poll_one_fd(fd, POLLIN, time_left * 1000);
605 
606   /* If some interrupt arrived, just retry. We presume this to be rare,
607   but it can happen (e.g. the SIGUSR1 signal sent by exiwhat causes
608   select() to exit).
609 
610   Aug 2004: Somebody set up a cron job that ran exiwhat every 2 minutes, making
611   the interrupt not at all rare. Since the timeout is typically more than 2
612   minutes, the effect was to block the timeout completely. To prevent this
613   happening again, we do an explicit time test and adjust the timeout
614   accordingly */
615 
616   if (rc < 0 && errno == EINTR)
617     {
618     DEBUG(D_transport) debug_printf("EINTR while waiting for socket data\n");
619 
620     /* Watch out, 'continue' jumps to the condition, not to the loops top */
621     if ((time_left = timelimit - time(NULL)) > 0) continue;
622     }
623 
624   if (rc <= 0)
625     {
626     errno = ETIMEDOUT;
627     return FALSE;
628     }
629 
630   /* Checking the FD_ISSET is not enough, if we're interrupted, the
631   select_inset may still contain the 'input'. */
632   }
633 while (rc < 0);
634 return TRUE;
635 }
636 
637 /* The timeout is implemented using select(), and we loop to cover select()
638 getting interrupted, and the possibility of select() returning with a positive
639 result but no ready descriptor. Is this in fact possible?
640 
641 Arguments:
642   cctx        the connection context (socket fd, possibly TLS context)
643   buffer      to read into
644   bufsize     the buffer size
645   timelimit   the timeout endpoint, seconds-since-epoch
646 
647 Returns:      > 0 => that much data read
648               <= 0 on error or EOF; errno set - zero for EOF
649 */
650 
651 int
ip_recv(client_conn_ctx * cctx,uschar * buffer,int buffsize,time_t timelimit)652 ip_recv(client_conn_ctx * cctx, uschar * buffer, int buffsize, time_t timelimit)
653 {
654 int rc;
655 
656 if (!fd_ready(cctx->sock, timelimit))
657   return -1;
658 
659 /* The socket is ready, read from it (via TLS if it's active). On EOF (i.e.
660 close down of the connection), set errno to zero; otherwise leave it alone. */
661 
662 #ifndef DISABLE_TLS
663 if (cctx->tls_ctx)					/* client TLS */
664   rc = tls_read(cctx->tls_ctx, buffer, buffsize);
665 else if (tls_in.active.sock == cctx->sock)		/* server TLS */
666   rc = tls_read(NULL, buffer, buffsize);
667 else
668 #endif
669   rc = recv(cctx->sock, buffer, buffsize, 0);
670 
671 if (rc > 0) return rc;
672 if (rc == 0) errno = 0;
673 return -1;
674 }
675 
676 
677 
678 
679 /*************************************************
680 *    Lookup address family of potential socket   *
681 *************************************************/
682 
683 /* Given a file-descriptor, check to see if it's a socket and, if so,
684 return the address family; detects IPv4 vs IPv6.  If not a socket then
685 return -1.
686 
687 The value 0 is typically AF_UNSPEC, which should not be seen on a connected
688 fd.  If the return is -1, the errno will be from getsockname(); probably
689 ENOTSOCK or ECONNRESET.
690 
691 Arguments:     socket-or-not fd
692 Returns:       address family or -1
693 */
694 
695 int
ip_get_address_family(int fd)696 ip_get_address_family(int fd)
697 {
698 struct sockaddr_storage ss;
699 socklen_t sslen = sizeof(ss);
700 
701 if (getsockname(fd, (struct sockaddr *) &ss, &sslen) < 0)
702   return -1;
703 
704 return (int) ss.ss_family;
705 }
706 
707 
708 
709 
710 /*************************************************
711 *       Lookup DSCP settings for a socket        *
712 *************************************************/
713 
714 struct dscp_name_tableentry {
715   const uschar *name;
716   int value;
717 };
718 /* Keep both of these tables sorted! */
719 static struct dscp_name_tableentry dscp_table[] = {
720 #ifdef IPTOS_DSCP_AF11
721     { CUS"af11", IPTOS_DSCP_AF11 },
722     { CUS"af12", IPTOS_DSCP_AF12 },
723     { CUS"af13", IPTOS_DSCP_AF13 },
724     { CUS"af21", IPTOS_DSCP_AF21 },
725     { CUS"af22", IPTOS_DSCP_AF22 },
726     { CUS"af23", IPTOS_DSCP_AF23 },
727     { CUS"af31", IPTOS_DSCP_AF31 },
728     { CUS"af32", IPTOS_DSCP_AF32 },
729     { CUS"af33", IPTOS_DSCP_AF33 },
730     { CUS"af41", IPTOS_DSCP_AF41 },
731     { CUS"af42", IPTOS_DSCP_AF42 },
732     { CUS"af43", IPTOS_DSCP_AF43 },
733     { CUS"ef", IPTOS_DSCP_EF },
734 #endif
735 #ifdef IPTOS_LOWCOST
736     { CUS"lowcost", IPTOS_LOWCOST },
737 #endif
738     { CUS"lowdelay", IPTOS_LOWDELAY },
739 #ifdef IPTOS_MINCOST
740     { CUS"mincost", IPTOS_MINCOST },
741 #endif
742     { CUS"reliability", IPTOS_RELIABILITY },
743     { CUS"throughput", IPTOS_THROUGHPUT }
744 };
745 static int dscp_table_size =
746   sizeof(dscp_table) / sizeof(struct dscp_name_tableentry);
747 
748 /* DSCP values change by protocol family, and so do the options used for
749 setsockopt(); this utility does all the lookups.  It takes an unexpanded
750 option string, expands it, strips off affix whitespace, then checks if it's
751 a number.  If all of what's left is a number, then that's how the option will
752 be parsed and success/failure is a range check.  If it's not all a number,
753 then it must be a supported keyword.
754 
755 Arguments:
756   dscp_name   a string, so far unvalidated
757   af          address_family in use
758   level       setsockopt level to use
759   optname     setsockopt name to use
760   dscp_value  value for dscp_name
761 
762 Returns: TRUE if okay to setsockopt(), else FALSE
763 
764 *level and *optname may be set even if FALSE is returned
765 */
766 
767 BOOL
dscp_lookup(const uschar * dscp_name,int af,int * level,int * optname,int * dscp_value)768 dscp_lookup(const uschar *dscp_name, int af,
769     int *level, int *optname, int *dscp_value)
770 {
771 uschar *dscp_lookup, *p;
772 int first, last;
773 long rawlong;
774 
775 if (af == AF_INET)
776   {
777   *level = IPPROTO_IP;
778   *optname = IP_TOS;
779   }
780 #if HAVE_IPV6 && defined(IPV6_TCLASS)
781 else if (af == AF_INET6)
782   {
783   *level = IPPROTO_IPV6;
784   *optname = IPV6_TCLASS;
785   }
786 #endif
787 else
788   {
789   DEBUG(D_transport)
790     debug_printf("Unhandled address family %d in dscp_lookup()\n", af);
791   return FALSE;
792   }
793 if (!dscp_name)
794   {
795   DEBUG(D_transport)
796     debug_printf("[empty DSCP]\n");
797   return FALSE;
798   }
799 dscp_lookup = expand_string(US dscp_name);
800 if (dscp_lookup == NULL || *dscp_lookup == '\0')
801   return FALSE;
802 
803 p = dscp_lookup + Ustrlen(dscp_lookup) - 1;
804 while (isspace(*p)) *p-- = '\0';
805 while (isspace(*dscp_lookup) && dscp_lookup < p) dscp_lookup++;
806 if (*dscp_lookup == '\0')
807   return FALSE;
808 
809 rawlong = Ustrtol(dscp_lookup, &p, 0);
810 if (p != dscp_lookup && *p == '\0')
811   {
812   /* We have six bits available, which will end up shifted to fit in 0xFC mask.
813   RFC 2597 defines the values unshifted. */
814   if (rawlong < 0 || rawlong > 0x3F)
815     {
816     DEBUG(D_transport)
817       debug_printf("DSCP value %ld out of range, ignored.\n", rawlong);
818     return FALSE;
819     }
820   *dscp_value = rawlong << 2;
821   return TRUE;
822   }
823 
824 first = 0;
825 last = dscp_table_size;
826 while (last > first)
827   {
828   int middle = (first + last)/2;
829   int c = Ustrcmp(dscp_lookup, dscp_table[middle].name);
830   if (c == 0)
831     {
832     *dscp_value = dscp_table[middle].value;
833     return TRUE;
834     }
835   else if (c > 0)
836     first = middle + 1;
837   else
838     last = middle;
839   }
840 return FALSE;
841 }
842 
843 void
dscp_list_to_stream(FILE * stream)844 dscp_list_to_stream(FILE *stream)
845 {
846 for (int i = 0; i < dscp_table_size; ++i)
847   fprintf(stream, "%s\n", dscp_table[i].name);
848 }
849 
850 
851 /* End of ip.c */
852 /* vi: aw ai sw=2
853 */
854