SOCKS: as a client, talk SMTP via a socks5 proxy. Bug 1590
[exim.git] / src / src / ip.c
index 91b74e20ed0b95898152295efcc6fcf1ba14af4c..83c8d167bb57fef8a4c542f96360923f12b88d40 100644 (file)
@@ -97,24 +97,11 @@ ip_addrinfo(const uschar *address, struct sockaddr_in6 *saddr)
 *         Bind socket to interface and port      *
 *************************************************/
 
-/* This function binds a socket to a local interface address and port. For a
-wildcard IPv6 bind, the address is ":".
-
-Arguments:
-  sock           the socket
-  af             AF_INET or AF_INET6 - the socket type
-  address        the IP address, in text form
-  port           the IP port (host order)
-
-Returns:         the result of bind()
-*/
-
 int
-ip_bind(int sock, int af, uschar *address, int port)
+ip_addr(void * sin_, int af, const uschar * address, int port)
 {
-int s_len;
-union sockaddr_46 sin;
-memset(&sin, 0, sizeof(sin));
+union sockaddr_46 * sin = sin_;
+memset(sin, 0, sizeof(sin));
 
 /* Setup code when using an IPv6 socket. The wildcard address is ":", to
 ensure an IPv6 socket is used. */
@@ -124,15 +111,13 @@ if (af == AF_INET6)
   {
   if (address[0] == ':' && address[1] == 0)
     {
-    sin.v6.sin6_family = AF_INET6;
-    sin.v6.sin6_addr = in6addr_any;
+    sin->v6.sin6_family = AF_INET6;
+    sin->v6.sin6_addr = in6addr_any;
     }
   else
-    {
-    ip_addrinfo(address, &sin.v6);  /* Panic-dies on error */
-    }
-  sin.v6.sin6_port = htons(port);
-  s_len = sizeof(sin.v6);
+    ip_addrinfo(address, &sin->v6);  /* Panic-dies on error */
+  sin->v6.sin6_port = htons(port);
+  return sizeof(sin->v6);
   }
 else
 #else     /* HAVE_IPv6 */
@@ -142,17 +127,34 @@ af = af;  /* Avoid compiler warning */
 /* Setup code when using IPv4 socket. The wildcard address is "". */
 
   {
-  sin.v4.sin_family = AF_INET;
-  sin.v4.sin_port = htons(port);
-  s_len = sizeof(sin.v4);
-  if (address[0] == 0)
-    sin.v4.sin_addr.s_addr = (S_ADDR_TYPE)INADDR_ANY;
-  else
-    sin.v4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(CS address);
+  sin->v4.sin_family = AF_INET;
+  sin->v4.sin_port = htons(port);
+  sin->v4.sin_addr.s_addr = address[0] == 0
+    ? (S_ADDR_TYPE)INADDR_ANY
+    : (S_ADDR_TYPE)inet_addr(CS address);
+  return sizeof(sin->v4);
   }
+}
+
+
+
+/* This function binds a socket to a local interface address and port. For a
+wildcard IPv6 bind, the address is ":".
 
-/* Now we can call the bind() function */
+Arguments:
+  sock           the socket
+  af             AF_INET or AF_INET6 - the socket type
+  address        the IP address, in text form
+  port           the IP port (host order)
 
+Returns:         the result of bind()
+*/
+
+int
+ip_bind(int sock, int af, uschar *address, int port)
+{
+union sockaddr_46 sin;
+int s_len = ip_addr(&sin, af, address, port);
 return bind(sock, (struct sockaddr *)&sin, s_len);
 }
 
@@ -337,7 +339,8 @@ for (h = &shost; h != NULL; h = h->next)
       {
       if (fd != fd6) close(fd6);
       if (fd != fd4) close(fd4);
-      if (connhost) {
+      if (connhost)
+       {
        h->port = port;
        *connhost = *h;
        connhost->next = NULL;
@@ -354,6 +357,58 @@ bad:
 }
 
 
+int
+ip_tcpsocket(const uschar * hostport, uschar ** errstr, int tmo)
+{
+  int scan;
+  uschar hostname[256];
+  unsigned int portlow, porthigh;
+
+  /* extract host and port part */
+  scan = sscanf(CS hostport, "%255s %u-%u", hostname, &portlow, &porthigh);
+  if ( scan != 3 ) {
+    if ( scan != 2 ) {
+      *errstr = string_sprintf("invalid socket '%s'", hostport);
+      return -1;
+    }
+    porthigh = portlow;
+  }
+
+  return ip_connectedsocket(SOCK_STREAM, hostname, portlow, porthigh,
+                           tmo, NULL, errstr);
+}
+
+int
+ip_unixsocket(const uschar * path, uschar ** errstr)
+{
+  int sock;
+  struct sockaddr_un server;
+
+  if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+    *errstr = US"can't open UNIX socket.";
+    return -1;
+  }
+
+  server.sun_family = AF_UNIX;
+  Ustrncpy(server.sun_path, path, sizeof(server.sun_path)-1);
+  server.sun_path[sizeof(server.sun_path)-1] = '\0';
+  if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
+    int err = errno;
+    (void)close(sock);
+    *errstr =  string_sprintf("unable to connect to UNIX socket (%s): %s",
+                 path, strerror(err));
+    return -1;
+    }
+  return sock;
+}
+
+int
+ip_streamsocket(const uschar * spec, uschar ** errstr, int tmo)
+{
+  return *spec == '/'
+    ? ip_unixsocket(spec, errstr) : ip_tcpsocket(spec, errstr, tmo);
+}
+
 /*************************************************
 *         Set keepalive on a socket              *
 *************************************************/
@@ -369,7 +424,7 @@ Returns:     nothing
 */
 
 void
-ip_keepalive(int sock, uschar *address, BOOL torf)
+ip_keepalive(int sock, const uschar *address, BOOL torf)
 {
 int fodder = 1;
 if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
@@ -668,3 +723,5 @@ for (i=0; i < dscp_table_size; ++i)
 
 
 /* End of ip.c */
+/* vi: aw ai sw=2
+*/