[git] Assuan - branch, master, updated. libassuan-2.3.0-3-g4061ac5

by Werner Koch cvs at cvs.gnupg.org
Mon Oct 26 14:40:20 CET 2015


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "IPC library used by GnuPG".

The branch, master has been updated
       via  4061ac57ca84a1e0ed779096897a160d49b50c03 (commit)
      from  85ece74a11718338dcd76d6e43ea8100183df02f (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 4061ac57ca84a1e0ed779096897a160d49b50c03
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Oct 26 14:35:41 2015 +0100

    Support hostname based SOCKS5 connection.
    
    * src/assuan.h.in (ASSUAN_SOCK_SOCKS): New.
    (ASSUAN_SOCK_TOR): New.
    (assuan_sock_connect_byname): New.
    * src/libassuan.def, src/libassuan.vers: Add that function.
    
    * src/assuan-socket.c (socks5_connect): Add args socksport,
    credentials, hostname, and hostport.  Implement user/password
    authentication and domainname address type.  Change callers
    accordingly.
    (_assuan_sock_connect_byname): New.
    (assuan_sock_connect_byname): New.
    
    * tests/socks5.c (main): Add options --byname, --user, and --pass.
    --
    
    The assuan_sock_connect_byname may eventually be extended to work
    without Tor or SOCKS by using getaddrinfo.  Or we move that all to
    libgpgrt (aka libgpg-error).
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index 934feda..01fa3b6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,18 @@
-Noteworthy changes in version 2.3.1 (unreleased) [C6/A6/R_]
+Noteworthy changes in version 2.4.0 (unreleased) [C6/A6/R_]
 ------------------------------------------------
 
+ * New flags "socks" and "tor-mode" for assuan_sock_{set,get}_flag.
+
+ * New function assuan_sock_connect_byname.
+
+ * Interface changes relative to the 2.3.0 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ assuan_sock_connect_byname    NEW.
+ ASSUAN_SOCK_TOR               NEW.
+ ASSUAN_SOCK_SOCKS             NEW.
+ assuan_sock_set_flag          EXTENDED.
+ assuan_sock_get_flag          EXTENDED.
+
 
 Noteworthy changes in version 2.3.0 (2015-08-28) [C6/A6/R0]
 ------------------------------------------------
diff --git a/doc/assuan.texi b/doc/assuan.texi
index 9161f0b..8445eb4 100644
--- a/doc/assuan.texi
+++ b/doc/assuan.texi
@@ -1979,6 +1979,22 @@ details on the redirection file format.
 @end deftypefun
 
 
+ at deftypefun int assuan_sock_connect_byname (@w{const char * @var{host}}, @
+         @w{unsigned short @var{port}}, @
+         @w{int @var{reserved}}, @
+         @w{const char *@var{credentials}}, @
+         @w{unsigned int @var{flags}})
+
+Directly connect to @var{port} on @var{host} given as a name.  The
+current implementation requires that @var{flags} has either
+ at code{ASSUAN_SOCK_SOCKS} or @code{ASSUAN_SOCK_TOR} set.  On success a
+new TCP STREAM socket is returned; on error @code{ASSUAN_INVALID_FD}
+and ERRNO set.  If @var{credentials} is not @code{NULL}, it is a
+string used for password based SOCKS authentication.  Username and
+password are separated by a colon. @var{reserved} should be 0.
+ at end deftypefun
+
+
 @deftypefun int assuan_sock_bind ( @
         @w{assuan_fd_t @var{sockfd}}, @
         @w{struct sockaddr *@var{addr}}, @
diff --git a/src/assuan-socket.c b/src/assuan-socket.c
index 9a6ee66..12e9e38 100644
--- a/src/assuan-socket.c
+++ b/src/assuan-socket.c
@@ -657,9 +657,11 @@ do_writen (assuan_context_t ctx, assuan_fd_t sockfd,
 }
 
 
-/* Connect using the SOCKS5 protocol.  */
+/* Connect using the SOCKS5 protocol. */
 static int
-socks5_connect (assuan_context_t ctx, int sock,
+socks5_connect (assuan_context_t ctx, int sock, unsigned short socksport,
+                const char *credentials,
+                const char *hostname, unsigned short hostport,
                 struct sockaddr *addr, socklen_t length)
 {
   int ret;
@@ -669,16 +671,36 @@ socks5_connect (assuan_context_t ctx, int sock,
   size_t proxyaddrlen;
   struct sockaddr_in6 *addr_in6;
   struct sockaddr_in  *addr_in;
-  unsigned char buffer[22];
-  size_t buflen;
+  unsigned char buffer[22+512]; /* The extra 512 gives enough space
+                                   for username/password or the
+                                   hostname. */
+  size_t buflen, hostnamelen;
+  int method;
 
   /* memset (&proxyaddr_in6, 0, sizeof proxyaddr_in6); */
   memset (&proxyaddr_in, 0, sizeof proxyaddr_in);
 
+  /* Either HOSTNAME or ADDR may be given.  */
+  if (hostname && addr)
+    {
+      gpg_err_set_errno (EINVAL);
+      return -1;
+    }
+
+  /* If a hostname is given it must fit into our buffer and it must be
+     less than 256 so that its length can be encoded in one byte.  */
+  hostnamelen = hostname? strlen (hostname) : 0;
+  if (hostnamelen > 255)
+    {
+      gpg_err_set_errno (ENAMETOOLONG);
+      return -1;
+    }
+
   /* Connect to local host.  */
-  /* Fixme: First try to use IPv6.  */
+  /* Fixme: First try to use IPv6 but note that
+     _assuan_sock_connect_byname created the socket with AF_INET.  */
   proxyaddr_in.sin_family = AF_INET;
-  proxyaddr_in.sin_port = htons (tor_mode);
+  proxyaddr_in.sin_port = htons (socksport);
   proxyaddr_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
   proxyaddr = (struct sockaddr *)&proxyaddr_in;
   proxyaddrlen = sizeof proxyaddr_in;
@@ -687,7 +709,11 @@ socks5_connect (assuan_context_t ctx, int sock,
     return ret;
   buffer[0] = 5; /* RFC-1928 VER field.  */
   buffer[1] = 1; /* NMETHODS */
-  buffer[2] = 0; /* Method: No authentication required. */
+  if (credentials)
+    method = 2; /* Method: username/password authentication. */
+  else
+    method = 0; /* Method: No authentication required. */
+  buffer[2] = method;
 
   /* Negotiate method.  */
   ret = do_writen (ctx, sock, buffer, 3);
@@ -696,7 +722,7 @@ socks5_connect (assuan_context_t ctx, int sock,
   ret = do_readn (ctx, sock, buffer, 2);
   if (ret)
     return ret;
-  if (buffer[0] != 5 || buffer[1] != 0 )
+  if (buffer[0] != 5 || buffer[1] != method )
     {
       /* Socks server returned wrong version or does not support our
          requested method.  */
@@ -704,11 +730,70 @@ socks5_connect (assuan_context_t ctx, int sock,
       return -1;
     }
 
+  if (credentials)
+    {
+      const char *password;
+      int ulen, plen;
+
+      password = strchr (credentials, ':');
+      if (!password)
+        {
+          gpg_err_set_errno (EINVAL); /* No password given.  */
+          return -1;
+        }
+      ulen = password - credentials;
+      password++;
+      plen = strlen (password);
+      if (!ulen || ulen > 255 || !plen || plen > 255)
+        {
+          gpg_err_set_errno (EINVAL);
+          return -1;
+        }
+
+      buffer[0] = 1; /* VER of the sub-negotiation. */
+      buffer[1] = ulen;
+      buflen = 2;
+      memcpy (buffer+buflen, credentials, ulen);
+      buflen += ulen;
+      buffer[buflen++] = plen;
+      memcpy (buffer+buflen, password, plen);
+      buflen += plen;
+      ret = do_writen (ctx, sock, buffer, buflen);
+      wipememory (buffer, buflen);
+      if (ret)
+        return ret;
+      ret = do_readn (ctx, sock, buffer, 2);
+      if (ret)
+        return ret;
+      if (buffer[0] != 1)
+        {
+          /* SOCKS server returned wrong version.  */
+          gpg_err_set_errno (EPROTO);
+          return -1;
+        }
+      if (buffer[1])
+        {
+          /* SOCKS server denied access.  */
+          gpg_err_set_errno (EACCES);
+          return -1;
+        }
+    }
+
   /* Send request details (rfc-1928, 4).  */
   buffer[0] = 5; /* VER  */
   buffer[1] = 1; /* CMD = CONNECT  */
   buffer[2] = 0; /* RSV  */
-  if (addr->sa_family == AF_INET6)
+  if (hostname)
+    {
+      buffer[3] = 3; /* ATYP = DOMAINNAME */
+      buflen = 4;
+      buffer[buflen++] = hostnamelen;
+      memcpy (buffer+buflen, hostname, hostnamelen);
+      buflen += hostnamelen;
+      buffer[buflen++] = (hostport >> 8); /* DST.PORT */
+      buffer[buflen++] = hostport;
+    }
+  else if (addr->sa_family == AF_INET6)
     {
       addr_in6 = (struct sockaddr_in6 *)addr;
 
@@ -729,7 +814,7 @@ socks5_connect (assuan_context_t ctx, int sock,
   ret = do_writen (ctx, sock, buffer, buflen);
   if (ret)
     return ret;
-  ret = do_readn (ctx, sock, buffer, buflen);
+  ret = do_readn (ctx, sock, buffer, 10 /* Length for IPv4 */);
   if (ret)
     return ret;
   if (buffer[0] != 5 || buffer[2] != 0 )
@@ -743,10 +828,10 @@ socks5_connect (assuan_context_t ctx, int sock,
     {
       switch (buffer[1])
         {
-        case 0x01: /* general SOCKS server failure.  */
+        case 0x01: /* General SOCKS server failure.  */
           gpg_err_set_errno (ENETDOWN);
           break;
-        case 0x02: /* connection not allowed by ruleset.  */
+        case 0x02: /* Connection not allowed by ruleset.  */
           gpg_err_set_errno (EACCES);
           break;
         case 0x03: /* Network unreachable */
@@ -770,6 +855,15 @@ socks5_connect (assuan_context_t ctx, int sock,
         }
       return -1;
     }
+  if (buffer[3] == 4)
+    {
+      /* ATYP indicates a v6 address.  We need to read the remaining
+         12 bytes.  */
+      ret = do_readn (ctx, sock, buffer+10, 12);
+      if (ret)
+        return ret;
+    }
+
   /* FIXME: We have not way to store the actual address used by the
      server.  */
 
@@ -779,7 +873,7 @@ socks5_connect (assuan_context_t ctx, int sock,
 
 
 /* Return true if SOCKS shall be used.  This is the case if tor_mode
-   is enabled and and the desired address is not the loopback
+   is enabled and the desired address is not the loopback
    address.  */
 static int
 use_socks (struct sockaddr *addr)
@@ -874,7 +968,8 @@ _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
     }
   else if (use_socks (addr))
     {
-      return socks5_connect (ctx, HANDLE2SOCKET (sockfd), addr, addrlen);
+      return socks5_connect (ctx, HANDLE2SOCKET (sockfd), tor_mode,
+                             NULL, NULL, 0, addr, addrlen);
     }
   else
     {
@@ -916,7 +1011,8 @@ _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
 
   if (use_socks (addr))
     {
-      return socks5_connect (ctx, sockfd, addr, addrlen);
+      return socks5_connect (ctx, sockfd, tor_mode,
+                             NULL, NULL, 0, addr, addrlen);
     }
   else
     {
@@ -926,6 +1022,48 @@ _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd,
 }
 
 
+/* Connect to HOST specified as host name on PORT.  The current
+   implementation requires that either the flags ASSUAN_SOCK_SOCKS or
+   ASSUAN_SOCK_TOR are give in FLAGS.  On success a new socket is
+   returned; on error ASSUAN_INVALID_FD is returned and ERRNO set.  If
+   CREDENTIALS is not NULL, it is a string used for password based
+   authentication.  Username and password are separated by a
+   colon.  RESERVED must be 0. */
+assuan_fd_t
+_assuan_sock_connect_byname (assuan_context_t ctx, const char *host,
+                             unsigned short port, int reserved,
+                             const char *credentials, unsigned int flags)
+{
+  int fd;
+  unsigned short socksport;
+
+  if ((flags & ASSUAN_SOCK_TOR))
+    socksport = TOR_PORT;
+  else if ((flags & ASSUAN_SOCK_SOCKS))
+    socksport = SOCKS_PORT;
+  else
+    {
+      gpg_err_set_errno (ENOTSUP);
+      return ASSUAN_INVALID_FD;
+    }
+
+  fd = _assuan_sock_new (ctx, AF_INET, SOCK_STREAM, 0);
+  if (fd == ASSUAN_INVALID_FD)
+    return fd;
+
+  if (socks5_connect (ctx, fd, socksport,
+                      credentials, host, port, NULL, 0))
+    {
+      int save_errno = errno;
+      assuan_sock_close (fd);
+      gpg_err_set_errno (save_errno);
+      return -1;
+    }
+
+  return fd;
+}
+
+
 int
 _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd,
 		   struct sockaddr *addr, int addrlen)
@@ -1257,6 +1395,15 @@ assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
   return _assuan_sock_connect (sock_ctx, sockfd, addr, addrlen);
 }
 
+assuan_fd_t
+assuan_sock_connect_byname (const char *host, unsigned short port,
+                            int reserved, const char *credentials,
+                            unsigned int flags)
+{
+  return _assuan_sock_connect_byname (sock_ctx,
+                                      host, port, reserved, credentials, flags);
+}
+
 int
 assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
 {
diff --git a/src/assuan.h.in b/src/assuan.h.in
index b26fa3b..67a1c20 100644
--- a/src/assuan.h.in
+++ b/src/assuan.h.in
@@ -461,6 +461,14 @@ gpg_error_t assuan_set_error (assuan_context_t ctx, gpg_error_t err,
 
 /*-- assuan-socket.c --*/
 
+/* This flag is used with assuan_sock_connect_byname to
+   connect via SOCKS.  */
+#define ASSUAN_SOCK_SOCKS   1
+/* This flag is used with assuan_sock_connect_byname to force a
+   connection via Tor even if the socket subsystem has not been
+   swicthed into Tor mode.  This flags overrides ASSUAN_SOCK_SOCKS. */
+#define ASSUAN_SOCK_TOR     2
+
 /* These are socket wrapper functions to support an emulation of Unix
    domain sockets on Windows W32.  */
 gpg_error_t assuan_sock_init (void);
@@ -471,6 +479,10 @@ int assuan_sock_set_flag (assuan_fd_t sockfd, const char *name, int value);
 int assuan_sock_get_flag (assuan_fd_t sockfd, const char *name, int *r_value);
 int assuan_sock_connect (assuan_fd_t sockfd,
                          struct sockaddr *addr, int addrlen);
+assuan_fd_t assuan_sock_connect_byname (const char *host, unsigned short port,
+                                        int reserved,
+                                        const char *credentials,
+                                        unsigned int flags);
 int assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen);
 int assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr,
                                  int *r_redirected);
diff --git a/src/libassuan.def b/src/libassuan.def
index 9f31c31..c320151 100644
--- a/src/libassuan.def
+++ b/src/libassuan.def
@@ -114,6 +114,7 @@ EXPORTS
     assuan_sock_set_sockaddr_un         @93
     assuan_sock_set_flag                @94
     assuan_sock_get_flag                @95
+    assuan_sock_connect_byname          @96
 
 ; END
 
diff --git a/src/libassuan.vers b/src/libassuan.vers
index 2b2389d..37c0131 100644
--- a/src/libassuan.vers
+++ b/src/libassuan.vers
@@ -104,6 +104,7 @@ LIBASSUAN_1.0 {
     assuan_sock_set_sockaddr_un;
     assuan_sock_set_flag;
     assuan_sock_get_flag;
+    assuan_sock_connect_byname;
 
     __assuan_close;
     __assuan_pipe;
diff --git a/tests/socks5.c b/tests/socks5.c
index c179108..7aa2b71 100644
--- a/tests/socks5.c
+++ b/tests/socks5.c
@@ -63,6 +63,9 @@ main (int argc, char **argv)
   int only_v4 = 0;
   int use_tor = 0;
   int disable_socks = 0;
+  int opt_byname = 0;
+  const char *user = NULL;
+  const char *pass = NULL;
   assuan_fd_t sock = ASSUAN_INVALID_FD;
   estream_t infp, outfp;
   int c;
@@ -83,15 +86,18 @@ main (int argc, char **argv)
       else if (!strcmp (*argv, "--help"))
         {
           puts (
-"usage: ./socks5 [options] HOST PORT\n"
-"\n"
-"Options:\n"
-"  --verbose        Show what is going on\n"
-"  --use-tor        Use port 9050 instead of 1080\n"
-"  --inet6-only     Use only IPv6\n"
-"  --inet4-only     Use only IPv4\n"
-"  --disable-socks  Connect w/o SOCKS\n"
-);
+                "usage: ./socks5 [options] HOST PORT\n"
+                "\n"
+                "Options:\n"
+                "  --verbose        Show what is going on\n"
+                "  --use-tor        Use port 9050 instead of 1080\n"
+                "  --inet6-only     Use only IPv6\n"
+                "  --inet4-only     Use only IPv4\n"
+                "  --disable-socks  Connect w/o SOCKS\n"
+                "  --byname         Use assuan_sock_connect_byname\n"
+                "  --user STRING    Use STRING as user for authentication\n"
+                "  --pass STRING    Use STRING as password for authentication\n"
+                );
           exit (0);
         }
       if (!strcmp (*argv, "--verbose"))
@@ -124,6 +130,29 @@ main (int argc, char **argv)
           disable_socks = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--byname"))
+        {
+          opt_byname = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--user"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              user = *argv;
+              argc--; argv++;
+            }
+        }
+      else if (!strcmp (*argv, "--pass"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              pass = *argv;
+              argc--; argv++;
+            }
+        }
       else if (!strncmp (*argv, "--", 2))
         {
           log_error ("unknown option '%s'\n", *argv);
@@ -153,60 +182,86 @@ main (int argc, char **argv)
                  use_tor? "TOR": "SOCKS", gpg_strerror (err));
     }
 
-  {
-    struct addrinfo hints, *res, *ai;
-    int ret;
-    int anyok = 0;
-
-    memset (&hints, 0, sizeof (hints));
-    hints.ai_socktype = SOCK_STREAM;
-    ret = getaddrinfo (argv[0], argv[1], &hints, &res);
-    if (ret)
-      {
-        log_error ("error resolving '%s': %s\n", argv[0], gai_strerror (ret));
+  if (opt_byname)
+    {
+      unsigned short port;
+      char *cred;
+
+      if (user || pass)
+        cred = xstrconcat (user?user:"", ":", pass, NULL);
+      else
+        cred = NULL;
+
+      port = strtoul (argv[1], NULL, 10);
+      if (port < 0 || port > 65535)
+        log_fatal ("port number out of range\n");
+
+      sock = assuan_sock_connect_byname (argv[0], port, 0, cred,
+                                         ASSUAN_SOCK_TOR);
+      if (sock == ASSUAN_INVALID_FD)
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("assuan_sock_connect_byname (%s) failed: %s\n",
+                     argv[0], gpg_strerror (err));
+          exit (1);
+        }
+      xfree (cred);
+    }
+  else
+    {
+      struct addrinfo hints, *res, *ai;
+      int ret;
+      int anyok = 0;
+
+      memset (&hints, 0, sizeof (hints));
+      hints.ai_socktype = SOCK_STREAM;
+      ret = getaddrinfo (argv[0], argv[1], &hints, &res);
+      if (ret)
+        {
+          log_error ("error resolving '%s': %s\n", argv[0], gai_strerror (ret));
+          exit (1);
+        }
+
+      for (ai = res; ai; ai = ai->ai_next)
+        {
+          if (ai->ai_family == AF_INET && only_v6)
+            continue;
+          if (ai->ai_family == AF_INET6 && only_v4)
+            continue;
+
+          if (sock != ASSUAN_INVALID_FD)
+            assuan_sock_close (sock);
+          sock = assuan_sock_new (ai->ai_family, ai->ai_socktype,
+                                  ai->ai_protocol);
+          if (sock == ASSUAN_INVALID_FD)
+            {
+              err = gpg_error_from_syserror ();
+              log_error ("error creating socket: %s\n", gpg_strerror (err));
+              freeaddrinfo (res);
+              exit (1);
+            }
+
+          if (assuan_sock_connect (sock,  ai->ai_addr, ai->ai_addrlen))
+            {
+              err = gpg_error_from_syserror ();
+              log_error ("assuan_sock_connect (%s) failed: %s\n",
+                         ai->ai_family == AF_INET6? "v6" :
+                         ai->ai_family == AF_INET ? "v4" : "?",
+                         gpg_strerror (err));
+            }
+          else
+            {
+              log_info ("assuan_sock_connect succeeded (%s)\n",
+                        ai->ai_family == AF_INET6? "v6" :
+                        ai->ai_family == AF_INET ? "v4" : "?");
+              anyok = 1;
+              break;
+            }
+        }
+      freeaddrinfo (res);
+      if (!anyok)
         exit (1);
-      }
-
-    for (ai = res; ai; ai = ai->ai_next)
-      {
-        if (ai->ai_family == AF_INET && only_v6)
-          continue;
-        if (ai->ai_family == AF_INET6 && only_v4)
-          continue;
-
-        if (sock != ASSUAN_INVALID_FD)
-          assuan_sock_close (sock);
-        sock = assuan_sock_new (ai->ai_family, ai->ai_socktype,
-                                ai->ai_protocol);
-        if (sock == ASSUAN_INVALID_FD)
-          {
-            err = gpg_error_from_syserror ();
-            log_error ("error creating socket: %s\n", gpg_strerror (err));
-            freeaddrinfo (res);
-            exit (1);
-          }
-
-        if (assuan_sock_connect (sock,  ai->ai_addr, ai->ai_addrlen))
-          {
-            err = gpg_error_from_syserror ();
-            log_error ("assuan_sock_connect (%s) failed: %s\n",
-                       ai->ai_family == AF_INET6? "v6" :
-                       ai->ai_family == AF_INET ? "v4" : "?",
-                       gpg_strerror (err));
-          }
-        else
-          {
-            log_info ("assuan_sock_connect succeeded (%d)\n",
-                      ai->ai_family == AF_INET6? "v6" :
-                      ai->ai_family == AF_INET ? "v4" : "?");
-            anyok = 1;
-            break;
-          }
-      }
-    freeaddrinfo (res);
-    if (!anyok)
-      exit (1);
-  }
+    }
 
   infp = es_fdopen_nc (sock, "rb");
   if (!infp)
@@ -220,8 +275,8 @@ main (int argc, char **argv)
     {
       err = gpg_error_from_syserror ();
       es_fclose (infp);
-        assuan_sock_close (sock);
-        log_fatal ("opening outbound stream failed: %s\n", gpg_strerror (err));
+      assuan_sock_close (sock);
+      log_fatal ("opening outbound stream failed: %s\n", gpg_strerror (err));
     }
 
   es_fputs ("HEAD / HTTP/1.0\r\n\r\n", outfp);

-----------------------------------------------------------------------

Summary of changes:
 NEWS                |  14 +++-
 doc/assuan.texi     |  16 +++++
 src/assuan-socket.c | 177 +++++++++++++++++++++++++++++++++++++++++++++-----
 src/assuan.h.in     |  12 ++++
 src/libassuan.def   |   1 +
 src/libassuan.vers  |   1 +
 tests/socks5.c      | 183 ++++++++++++++++++++++++++++++++++------------------
 7 files changed, 324 insertions(+), 80 deletions(-)


hooks/post-receive
-- 
IPC library used by GnuPG
http://git.gnupg.org




More information about the Gnupg-commits mailing list