Fwd: Re: The --use-tor option

Werner Koch wk at gnupg.org
Tue Oct 20 17:46:52 CEST 2015


On Tue, 20 Oct 2015 15:41, twim at riseup.net said:

> Sad. I had a guess about Windows. For me it looks like we need some
> 'reference' implementation of this, a library (like Stem) to not to
> reimplement Tor support each time in each project, to be able to update

Accessing a SOCKS5 proxy (which is used to access tor) on the local
machine is actually quite simple because you only need to replaces the
connect call.  We already do something more complicated for Windows (to
emulate UnixDonain sockets).  See below for the code Dirmngr uses (from
Libassuan).  It is pretty straightforward unless you have to integrate
with non-blocking event driven code.


Salam-Shalom,

   Werner


===
static int
socks5_connect (assuan_context_t ctx, int sock,
                struct sockaddr *addr, socklen_t length)
{
  int ret;
  /* struct sockaddr_in6 proxyaddr_in6; */
  struct sockaddr_in  proxyaddr_in;
  struct sockaddr *proxyaddr;
  size_t proxyaddrlen;
  struct sockaddr_in6 *addr_in6;
  struct sockaddr_in  *addr_in;
  unsigned char buffer[22];
  size_t buflen;

  /* memset (&proxyaddr_in6, 0, sizeof proxyaddr_in6); */
  memset (&proxyaddr_in, 0, sizeof proxyaddr_in);

  /* Connect to local host.  */
  /* Fixme: First try to use IPv6.  */
  proxyaddr_in.sin_family = AF_INET;
  proxyaddr_in.sin_port = htons (tor_mode);
  proxyaddr_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
  proxyaddr = (struct sockaddr *)&proxyaddr_in;
  proxyaddrlen = sizeof proxyaddr_in;
  ret = _assuan_connect (ctx, sock, proxyaddr, proxyaddrlen);
  if (ret)
    return ret;
  buffer[0] = 5; /* RFC-1928 VER field.  */
  buffer[1] = 1; /* NMETHODS */
  buffer[2] = 0; /* Method: No authentication required. */

  /* Negotiate method.  */
  ret = do_writen (ctx, sock, buffer, 3);
  if (ret)
    return ret;
  ret = do_readn (ctx, sock, buffer, 2);
  if (ret)
    return ret;
  if (buffer[0] != 5 || buffer[1] != 0 )
    {
      /* Socks server returned wrong version or does not support our
         requested method.  */
      gpg_err_set_errno (ENOTSUP); /* Fixme: Is there a better errno? */
      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)
    {
      addr_in6 = (struct sockaddr_in6 *)addr;

      buffer[3] = 4; /* ATYP = IPv6 */
      memcpy (buffer+ 4, &addr_in6->sin6_addr.s6_addr, 16); /* DST.ADDR */
      memcpy (buffer+20, &addr_in6->sin6_port, 2);          /* DST.PORT */
      buflen = 22;
    }
  else
    {
      addr_in = (struct sockaddr_in *)addr;

      buffer[3] = 1; /* ATYP = IPv4 */
      memcpy (buffer+4, &addr_in->sin_addr.s_addr, 4); /* DST.ADDR */
      memcpy (buffer+8, &addr_in->sin_port, 2);        /* DST.PORT */
      buflen = 10;
    }
  ret = do_writen (ctx, sock, buffer, buflen);
  if (ret)
    return ret;
  ret = do_readn (ctx, sock, buffer, buflen);
  if (ret)
    return ret;
  if (buffer[0] != 5 || buffer[2] != 0 )
    {
      /* Socks server returned wrong version or the reserved field is
         not zero.  */
      gpg_err_set_errno (EPROTO);
      return -1;
    }
  if (buffer[1])
    {
      switch (buffer[1])
        {
        case 0x01: /* general SOCKS server failure.  */
          gpg_err_set_errno (ENETDOWN);
          break;
        case 0x02: /* connection not allowed by ruleset.  */
          gpg_err_set_errno (EACCES);
          break;
        case 0x03: /* Network unreachable */
          gpg_err_set_errno (ENETUNREACH);
          break;
        case 0x04: /* Host unreachable */
          gpg_err_set_errno (EHOSTUNREACH);
          break;
        case 0x05: /* Connection refused */
          gpg_err_set_errno (ECONNREFUSED);
          break;
        case 0x06: /* TTL expired */
          gpg_err_set_errno (ETIMEDOUT);
          break;
        case 0x08: /* Address type not supported */
          gpg_err_set_errno (EPROTONOSUPPORT);
          break;
        case 0x07: /* Command not supported */
        default:
          gpg_err_set_errno (ENOTSUP); /* Fixme: Is there a better errno? */
        }
      return -1;
    }
  /* FIXME: We have not way to store the actual address used by the
     server.  */


  return 0;
}

-- 
Die Gedanken sind frei.  Ausnahmen regelt ein Bundesgesetz.




More information about the Gnupg-devel mailing list