Ticket #62: openvpn-socks-auth.patch

File openvpn-socks-auth.patch, 7.4 KB (added by delroth, 12 years ago)

Adds support of SOCKS plain text authentication to OpenVPN

  • init.c

    diff --git a/init.c b/init.c
    index a46fbde..f84fd35 100644
    a b init_proxy_dowork (struct context *c) 
    417417    {
    418418      c->c1.socks_proxy = socks_proxy_new (c->options.ce.socks_proxy_server,
    419419                                           c->options.ce.socks_proxy_port,
     420                                           c->options.ce.socks_proxy_authfile,
    420421                                           c->options.ce.socks_proxy_retry,
    421422                                           c->options.auto_proxy_info);
    422423      if (c->c1.socks_proxy)
  • options.c

    diff --git a/options.c b/options.c
    index 5f1efc5..ae4eafb 100644
    a b static const char usage_message[] = 
    120120  "                  AGENT user-agent\n"
    121121#endif
    122122#ifdef ENABLE_SOCKS
    123   "--socks-proxy s [p]: Connect to remote host through a Socks5 proxy at address\n"
    124   "                  s and port p (default port = 1080).\n"
     123  "--socks-proxy s [p] [up] : Connect to remote host through a Socks5 proxy at\n"
     124  "                  address s and port p (default port = 1080).\n"
     125  "                  If proxy authentication is required,\n"
     126  "                  up is a file containing username/password on 2 lines, or\n"
     127  "                  'stdin' to prompt for console.\n"
    125128  "--socks-proxy-retry : Retry indefinitely on Socks proxy errors.\n"
    126129#endif
    127130  "--resolv-retry n: If hostname resolve fails for --remote, retry\n"
    add_option (struct options *options, 
    44714474          options->ce.socks_proxy_port = 1080;
    44724475        }
    44734476      options->ce.socks_proxy_server = p[1];
     4477      options->ce.socks_proxy_authfile = p[3]; /* might be NULL */
    44744478    }
    44754479  else if (streq (p[0], "socks-proxy-retry"))
    44764480    {
  • options.h

    diff --git a/options.h b/options.h
    index fc5db58..c1e6d6d 100644
    a b struct connection_entry 
    9595#ifdef ENABLE_SOCKS
    9696  const char *socks_proxy_server;
    9797  int socks_proxy_port;
     98  const char *socks_proxy_authfile;
    9899  bool socks_proxy_retry;
    99100#endif
    100101
  • socks.c

    diff --git a/socks.c b/socks.c
    index 0c1bb3e..94fe1f9 100644
    a b  
    3838#include "win32.h"
    3939#include "socket.h"
    4040#include "fdmisc.h"
     41#include "misc.h"
    4142#include "proxy.h"
    4243
    4344#include "memdbg.h"
    4445
     46#define UP_TYPE_SOCKS           "SOCKS Proxy"
    4547
    4648void
    4749socks_adjust_frame_parameters (struct frame *frame, int proto)
    socks_adjust_frame_parameters (struct frame *frame, int proto) 
    5355struct socks_proxy_info *
    5456socks_proxy_new (const char *server,
    5557                 int port,
     58                 const char *authfile,
    5659                 bool retry,
    5760                 struct auto_proxy_info *auto_proxy_info)
    5861{
    socks_proxy_new (const char *server, 
    7780
    7881  strncpynt (p->server, server, sizeof (p->server));
    7982  p->port = port;
     83
     84  if (authfile)
     85    strncpynt (p->authfile, authfile, sizeof (p->authfile));
     86  else
     87    p->authfile[0] = 0;
     88
    8089  p->retry = retry;
    8190  p->defined = true;
    8291
    socks_proxy_close (struct socks_proxy_info *sp) 
    9099}
    91100
    92101static bool
    93 socks_handshake (socket_descriptor_t sd, volatile int *signal_received)
     102socks_username_password_auth (struct socks_proxy_info *p,
     103                              socket_descriptor_t sd,
     104                              volatile int *signal_received)
     105{
     106  char to_send[516];
     107  char buf[2];
     108  int len = 0;
     109  const int timeout_sec = 5;
     110  struct user_pass creds;
     111  ssize_t size;
     112
     113  creds.defined = 0;
     114
     115  get_user_pass (&creds, p->authfile, UP_TYPE_SOCKS, GET_USER_PASS_MANAGEMENT);
     116  snprintf (to_send, sizeof (to_send), "\x01%c%s%c%s", strlen(creds.username),
     117            creds.username, strlen(creds.password), creds.password);
     118  size = send (sd, to_send, strlen(to_send), MSG_NOSIGNAL);
     119
     120  if (size != strlen (to_send))
     121    {
     122      msg (D_LINK_ERRORS | M_ERRNO_SOCK, "socks_username_password_auth: TCP port write failed on send()");
     123      return false;
     124    }
     125
     126  while (len < 2)
     127    {
     128      int status;
     129      ssize_t size;
     130      fd_set reads;
     131      struct timeval tv;
     132      char c;
     133
     134      FD_ZERO (&reads);
     135      FD_SET (sd, &reads);
     136      tv.tv_sec = timeout_sec;
     137      tv.tv_usec = 0;
     138
     139      status = select (sd + 1, &reads, NULL, NULL, &tv);
     140
     141      get_signal (signal_received);
     142      if (*signal_received)
     143        return false;
     144
     145      /* timeout? */
     146      if (status == 0)
     147        {
     148          msg (D_LINK_ERRORS | M_ERRNO_SOCK, "socks_username_password_auth: TCP port read timeout expired");
     149          return false;
     150        }
     151
     152      /* error */
     153      if (status < 0)
     154        {
     155          msg (D_LINK_ERRORS | M_ERRNO_SOCK, "socks_username_password_auth: TCP port read failed on select()");
     156          return false;
     157        }
     158
     159      /* read single char */
     160      size = recv(sd, &c, 1, MSG_NOSIGNAL);
     161
     162      /* error? */
     163      if (size != 1)
     164        {
     165          msg (D_LINK_ERRORS | M_ERRNO_SOCK, "socks_username_password_auth: TCP port read failed on recv()");
     166          return false;
     167        }
     168
     169      /* store char in buffer */
     170      buf[len++] = c;
     171    }
     172
     173  if (buf[0] != 5 && buf[1] != 0)
     174  {
     175    msg (D_LINK_ERRORS, "socks_username_password_auth: server refused the authentication");
     176    return false;
     177  }
     178
     179  return true;
     180}
     181
     182static bool
     183socks_handshake (struct socks_proxy_info *p,
     184                 socket_descriptor_t sd,
     185                 volatile int *signal_received)
    94186{
    95187  char buf[2];
    96188  int len = 0;
    97189  const int timeout_sec = 5;
    98190
    99   /* VER = 5, NMETHODS = 1, METHODS = [0] */
    100   const ssize_t size = send (sd, "\x05\x01\x00", 3, MSG_NOSIGNAL);
    101   if (size != 3)
     191  /* VER = 5, NMETHODS = 2, METHODS = [0 (no auth), 2 (plain login)] */
     192  const ssize_t size = send (sd, "\x05\x02\x00\x02", 4, MSG_NOSIGNAL);
     193  if (size != 4)
    102194    {
    103195      msg (D_LINK_ERRORS | M_ERRNO_SOCK, "socks_handshake: TCP port write failed on send()");
    104196      return false;
    socks_handshake (socket_descriptor_t sd, volatile int *signal_received) 
    151243      buf[len++] = c;
    152244    }
    153245
    154   /* VER == 5 && METHOD == 0 */
    155   if (buf[0] != '\x05' || buf[1] != '\x00')
     246  /* VER == 5 */
     247  if (buf[0] != '\x05')
    156248    {
    157249      msg (D_LINK_ERRORS, "socks_handshake: Socks proxy returned bad status");
    158250      return false;
    159251    }
    160252
     253  /* select the appropriate authentication method */
     254  switch (buf[1])
     255    {
     256    case 0: /* no authentication */
     257      break;
     258
     259    case 2: /* login/password */
     260      if (!p->authfile[0])
     261      {
     262        msg(D_LINK_ERRORS, "socks_handshake: server asked for username/login auth but we were "
     263                           "not provided any credentials");
     264        return false;
     265      }
     266
     267      if (!socks_username_password_auth(p, sd, signal_received))
     268        return false;
     269
     270      break;
     271
     272    default: /* unknown auth method */
     273      msg(D_LINK_ERRORS, "socks_handshake: unknown SOCKS auth method");
     274      return false;
     275    }
     276
    161277  return true;
    162278}
    163279
    establish_socks_proxy_passthru (struct socks_proxy_info *p, 
    281397  char buf[128];
    282398  size_t len;
    283399
    284   if (!socks_handshake (sd, signal_received))
     400  if (!socks_handshake (p, sd, signal_received))
    285401    goto error;
    286402
    287403  /* format Socks CONNECT message */
    establish_socks_proxy_udpassoc (struct socks_proxy_info *p, 
    328444                                struct openvpn_sockaddr *relay_addr,
    329445                                volatile int *signal_received)
    330446{
    331   if (!socks_handshake (ctrl_sd, signal_received))
     447  if (!socks_handshake (p, ctrl_sd, signal_received))
    332448    goto error;
    333449
    334450  {
  • socks.h

    diff --git a/socks.h b/socks.h
    index 702aa06..b748bb3 100644
    a b struct socks_proxy_info { 
    4343
    4444  char server[128];
    4545  int port;
     46  char authfile[256];
    4647};
    4748
    4849void socks_adjust_frame_parameters (struct frame *frame, int proto);
    4950
    5051struct socks_proxy_info *socks_proxy_new (const char *server,
    5152                                          int port,
     53                                          const char *authfile,
    5254                                          bool retry,
    5355                                          struct auto_proxy_info *auto_proxy_info);
    5456