Dual-tls - split management of TLS into in- and out-bound connection-handling.
[exim.git] / src / src / ip.c
index be4511dfa514d21caf7eb7e0b97b1b353b70e50e..b0c98878b6736b9f3365129d50a11ee10a22af4a 100644 (file)
@@ -347,8 +347,10 @@ for (;;)
 close down of the connection), set errno to zero; otherwise leave it alone. */
 
 #ifdef SUPPORT_TLS
-if (tls_active == sock)
-  rc = tls_read(buffer, buffsize);
+if (tls_out.active == sock)
+  rc = tls_read(FALSE, buffer, buffsize);
+else if (tls_in.active == sock)
+  rc = tls_read(TRUE, buffer, buffsize);
 else
 #endif
   rc = recv(sock, buffer, buffsize, 0);
@@ -361,6 +363,37 @@ return -1;
 
 
 
+/*************************************************
+*    Lookup address family of potential socket   *
+*************************************************/
+
+/* Given a file-descriptor, check to see if it's a socket and, if so,
+return the address family; detects IPv4 vs IPv6.  If not a socket then
+return -1.
+
+The value 0 is typically AF_UNSPEC, which should not be seen on a connected
+fd.  If the return is -1, the errno will be from getsockname(); probably
+ENOTSOCK or ECONNRESET.
+
+Arguments:     socket-or-not fd
+Returns:       address family or -1
+*/
+
+int
+ip_get_address_family(int fd)
+{
+struct sockaddr_storage ss;
+socklen_t sslen = sizeof(ss);
+
+if (getsockname(fd, (struct sockaddr *) &ss, &sslen) < 0)
+  return -1;
+
+return (int) ss.ss_family;
+}
+
+
+
+
 /*************************************************
 *       Lookup DSCP settings for a socket        *
 *************************************************/
@@ -400,7 +433,11 @@ static int dscp_table_size =
   sizeof(dscp_table) / sizeof(struct dscp_name_tableentry);
 
 /* DSCP values change by protocol family, and so do the options used for
-setsockopt(); this utility does all the lookups.
+setsockopt(); this utility does all the lookups.  It takes an unexpanded
+option string, expands it, strips off affix whitespace, then checks if it's
+a number.  If all of what's left is a number, then that's how the option will
+be parsed and success/failure is a range check.  If it's not all a number,
+then it must be a supported keyword.
 
 Arguments:
   dscp_name   a string, so far unvalidated
@@ -410,14 +447,17 @@ Arguments:
   dscp_value  value for dscp_name
 
 Returns: TRUE if okay to setsockopt(), else FALSE
+
+*level and *optname may be set even if FALSE is returned
 */
 
 BOOL
 dscp_lookup(const uschar *dscp_name, int af,
     int *level, int *optname, int *dscp_value)
 {
-uschar *dscp_lookup;
+uschar *dscp_lookup, *p;
 int first, last;
+long rawlong;
 
 if (af == AF_INET)
   {
@@ -445,6 +485,27 @@ dscp_lookup = expand_string(US dscp_name);
 if (dscp_lookup == NULL || *dscp_lookup == '\0')
   return FALSE;
 
+p = dscp_lookup + Ustrlen(dscp_lookup) - 1;
+while (isspace(*p)) *p-- = '\0';
+while (isspace(*dscp_lookup) && dscp_lookup < p) dscp_lookup++;
+if (*dscp_lookup == '\0')
+  return FALSE;
+
+rawlong = Ustrtol(dscp_lookup, &p, 0);
+if (p != dscp_lookup && *p == '\0')
+  {
+  /* We have six bits available, which will end up shifted to fit in 0xFC mask.
+  RFC 2597 defines the values unshifted. */
+  if (rawlong < 0 || rawlong > 0x3F)
+    {
+    DEBUG(D_transport)
+      debug_printf("DSCP value %ld out of range, ignored.\n", rawlong);
+    return FALSE;
+    }
+  *dscp_value = rawlong << 2;
+  return TRUE;
+  }
+
 first = 0;
 last = dscp_table_size;
 while (last > first)