socks5.c 13.6 KB
Newer Older
1 2 3
/*
 * This file is part of the Nice GLib ICE library.
 *
4 5 6
 * (C) 2008 Collabora Ltd.
 *  Contact: Youness Alaoui
 * (C) 2008 Nokia Corporation. All rights reserved.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Nice GLib ICE library.
 *
 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
 * Corporation. All Rights Reserved.
 *
 * Contributors:
24
 *   Youness Alaoui, Collabora Ltd.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 *
 * Alternatively, the contents of this file may be used under the terms of the
 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
 * case the provisions of LGPL are applicable instead of those above. If you
 * wish to allow use of your version of this file only under the terms of the
 * LGPL and not to allow others to use your version of this file under the
 * MPL, indicate your decision by deleting the provisions above and replace
 * them with the notice and other provisions required by the LGPL. If you do
 * not delete the provisions above, a recipient may use your version of this
 * file under either the MPL or the LGPL.
 */

/*
 * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
 */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "socks5.h"
46
#include "agent-priv.h"
47
#include "socket-priv.h"
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

#include <string.h>

#ifndef G_OS_WIN32
#include <unistd.h>
#endif

typedef enum {
  SOCKS_STATE_INIT,
  SOCKS_STATE_AUTH,
  SOCKS_STATE_CONNECT,
  SOCKS_STATE_CONNECTED,
  SOCKS_STATE_ERROR
} SocksState;

typedef struct {
  SocksState state;
  NiceSocket *base_socket;
  NiceAddress addr;
  gchar *username;
  gchar *password;
  GQueue send_queue;
} Socks5Priv;


static void socket_close (NiceSocket *sock);
74 75
static gint socket_recv_messages (NiceSocket *sock,
    NiceInputMessage *recv_messages, guint n_recv_messages);
76
static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to,
77
    const NiceOutputMessage *messages, guint n_messages);
78 79
static gint socket_send_messages_reliable (NiceSocket *sock,
    const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages);
80 81 82 83
static gboolean socket_is_reliable (NiceSocket *sock);


NiceSocket *
84
nice_socks5_socket_new (NiceSocket *base_socket,
85 86 87 88 89 90 91 92 93 94 95 96 97 98
    NiceAddress *addr, gchar *username, gchar *password)
{
  Socks5Priv *priv;
  NiceSocket *sock = NULL;

  if (addr) {
    sock = g_slice_new0 (NiceSocket);
    sock->priv = priv = g_slice_new0 (Socks5Priv);

    priv->base_socket = base_socket;
    priv->addr = *addr;
    priv->username = g_strdup (username);
    priv->password = g_strdup (password);

99
    sock->type = NICE_SOCKET_TYPE_SOCKS5;
100 101
    sock->fileno = priv->base_socket->fileno;
    sock->addr = priv->base_socket->addr;
102
    sock->send_messages = socket_send_messages;
103
    sock->send_messages_reliable = socket_send_messages_reliable;
104
    sock->recv_messages = socket_recv_messages;
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
    sock->is_reliable = socket_is_reliable;
    sock->close = socket_close;

    /* Send SOCKS5 handshake */
    {
      gchar msg[4];
      gint len = 3;

      msg[0] = 0x05; /* SOCKS version */
      msg[1] = 0x01; /* number of methods supported */
      msg[2] = 0x00; /* no authentication method*/

      g_debug ("user/pass : %s - %s", username, password);
      /* add support for authentication method */
      if (username || password) {
        msg[1] = 0x02; /* number of methods supported */
        msg[3] = 0x02; /* authentication method */
        len++;
      }

      /* We send 'to' NULL because it will always be to an already connected
       * TCP base socket, which ignores the destination */
127
      nice_socket_send_reliable (priv->base_socket, NULL, len, msg);
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
      priv->state = SOCKS_STATE_INIT;
    }
  }

  return sock;
}


static void
socket_close (NiceSocket *sock)
{
  Socks5Priv *priv = sock->priv;

  if (priv->base_socket)
    nice_socket_free (priv->base_socket);

  if (priv->username)
    g_free (priv->username);

  if (priv->password)
    g_free (priv->password);

150
  nice_socket_free_send_queue (&priv->send_queue);
151 152 153 154 155 156

  g_slice_free(Socks5Priv, sock->priv);
}


static gint
157 158
socket_recv_messages (NiceSocket *sock,
    NiceInputMessage *recv_messages, guint n_recv_messages)
159 160
{
  Socks5Priv *priv = sock->priv;
161 162
  guint i;
  gint ret = -1;
163

164 165
  switch (priv->state) {
    case SOCKS_STATE_CONNECTED:
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
      /* Common case: fast pass-through to the base socket once we’re
       * connected. */
      if (priv->base_socket) {
        ret = nice_socket_recv_messages (priv->base_socket,
            recv_messages, n_recv_messages);
      }

      if (ret <= 0)
        return ret;

      /* After successfully receiving into at least one NiceInputMessage,
       * update the from address in each valid NiceInputMessage. */
      for (i = 0; i < (guint) ret; i++) {
        if (recv_messages[i].from != NULL)
          *recv_messages[i].from = priv->addr;
      }

      return ret;

185 186
    case SOCKS_STATE_INIT:
      {
187 188 189
        guint8 data[2];
        GInputVector local_recv_buf = { data, sizeof (data) };
        NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
190 191 192

        nice_debug ("Socks5 state Init");

193 194 195 196
        if (priv->base_socket) {
          ret = nice_socket_recv_messages (priv->base_socket,
              &local_recv_message, 1);
        }
197 198 199

        if (ret <= 0) {
          return ret;
200
        } else if (ret == 1 && local_recv_buf.size == sizeof(data)) {
201 202 203 204 205 206 207 208 209 210 211
          if (data[0] == 0x05) {
            if (data[1] == 0x02) {
              gchar msg[515];
              gint len = 0;

              if (priv->username || priv->password) {
                gint ulen = 0;
                gint plen = 0;

                if (priv->username)
                  ulen = strlen (priv->username);
212 213 214 215
                if (ulen > 255) {
                  nice_debug ("Socks5 username length > 255");
                  goto error;
                }
216 217 218

                if (priv->password)
                  plen  = strlen (priv->password);
219 220 221 222
                if (plen > 255) {
                  nice_debug ("Socks5 password length > 255");
                  goto error;
                }
223 224 225

                msg[len++] = 0x01; /* auth version */
                msg[len++] = ulen; /* username length */
226 227
                if (ulen > 0)
                  memcpy (msg + len, priv->username, ulen); /* Username */
228 229
                len += ulen;
                msg[len++] = plen; /* Password length */
230 231
                if (plen > 0)
                  memcpy (msg + len, priv->password, plen); /* Password */
232 233
                len += plen;

234
                nice_socket_send_reliable (priv->base_socket, NULL, len, msg);
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
                priv->state = SOCKS_STATE_AUTH;
              } else {
                /* Authentication required but no auth info available */
                goto error;
              }
            } else if (data[1] == 0x00) {
              goto send_connect;
            } else {
              /* method not supported by socks server */
              goto error;
            }
          } else {
            /* invalid SOCKS server version */
            goto error;
          }
        } else {
          /* read error */
          goto error;
        }
      }
      break;
    case SOCKS_STATE_AUTH:
      {
258 259 260
        guint8 data[2];
        GInputVector local_recv_buf = { data, sizeof (data) };
        NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
261 262

        nice_debug ("Socks5 state auth");
263 264 265 266
        if (priv->base_socket) {
          ret = nice_socket_recv_messages (priv->base_socket,
              &local_recv_message, 1);
        }
267 268 269

        if (ret <= 0) {
          return ret;
270
        } else if (ret == 1 && local_recv_buf.size == sizeof(data)) {
271 272 273 274 275 276 277 278 279 280 281 282
          if (data[0] == 0x01 && data[1] == 0x00) {
            /* Authenticated */
            goto send_connect;
          } else {
            /* Authentication failed */
            goto error;
          }
        }
      }
      break;
    case SOCKS_STATE_CONNECT:
      {
283 284 285
        guint8 data[22];
        GInputVector local_recv_buf = { data, sizeof (data) };
        NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
286 287

        nice_debug ("Socks5 state connect");
288 289 290 291 292
        if (priv->base_socket) {
          local_recv_buf.size = 4;
          ret = nice_socket_recv_messages (priv->base_socket,
              &local_recv_message, 1);
        }
293 294 295

        if (ret <= 0) {
          return ret;
296
        } else if (ret == 1 && local_recv_buf.size == 4) {
297 298 299 300 301 302
          if (data[0] == 0x05) {
            switch (data[1]) {
              case 0x00:
                if (data[2] == 0x00) {
                  switch (data[3]) {
                    case 0x01: /* IPV4 bound address */
303 304 305 306
                      local_recv_buf.size = 6;
                      ret = nice_socket_recv_messages (priv->base_socket,
                          &local_recv_message, 1);
                      if (ret != 1 || local_recv_buf.size != 6) {
307 308 309 310 311
                        /* Could not read server bound address */
                        goto error;
                      }
                      break;
                    case 0x04: /* IPV6 bound address */
312 313 314 315
                      local_recv_buf.size = 18;
                      ret = nice_socket_recv_messages (priv->base_socket,
                          &local_recv_message, 1);
                      if (ret != 1 || local_recv_buf.size != 18) {
316 317 318 319 320 321 322 323
                        /* Could not read server bound address */
                        goto error;
                      }
                      break;
                    default:
                      /* Unsupported address type */
                      goto error;
                  }
324 325
                  nice_socket_flush_send_queue (priv->base_socket,
                      &priv->send_queue);
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
                  priv->state = SOCKS_STATE_CONNECTED;
                } else {
                  /* Wrong reserved value */
                  goto error;
                }
                break;
              case 0x01: /* general SOCKS server failure */
              case 0x02: /* connection not allowed by ruleset */
              case 0x03: /* Network unreachable */
              case 0x04: /* Host unreachable */
              case 0x05: /* Connection refused */
              case 0x06: /* TTL expired */
              case 0x07: /* Command not supported */
              case 0x08: /* Address type not supported */
              default: /* Unknown error */
                goto error;
                break;
            }
          } else {
            /* Wrong server version */
            goto error;
          }
        } else {
          /* Invalid data received */
          goto error;
        }
      }
      break;
354
    case SOCKS_STATE_ERROR:
355 356 357 358 359 360 361 362 363 364 365
    default:
      /* Unknown status */
      goto error;
  }

  return 0;

 send_connect:
  {
    gchar msg[22];
    gint len = 0;
366 367 368 369 370 371 372
    union {
      struct sockaddr_storage storage;
      struct sockaddr addr;
      struct sockaddr_in in;
      struct sockaddr_in6 in6;
    } name;
    nice_address_copy_to_sockaddr(&priv->addr, &name.addr);
373 374 375 376

    msg[len++] = 0x05; /* SOCKS version */
    msg[len++] = 0x01; /* connect command */
    msg[len++] = 0x00; /* reserved */
377
    if (name.storage.ss_family == AF_INET) {
378 379
      msg[len++] = 0x01; /* IPV4 address type */
      /* Address */
380
      memcpy (msg + len, &(&name.in)->sin_addr, 4);
381 382
      len += 4;
      /* Port */
383
      memcpy (msg + len, &(&name.in)->sin_port, 2);
384
      len += 2;
385
    } else if (name.storage.ss_family == AF_INET6) {
386 387
      msg[len++] = 0x04; /* IPV6 address type */
      /* Address */
388
      memcpy (msg + len, &(&name.in6)->sin6_addr, 16);
389 390
      len += 16;
      /* Port */
391
      memcpy (msg + len, &(&name.in6)->sin6_port, 2);
392 393 394
      len += 2;
    }

395
    nice_socket_send_reliable (priv->base_socket, NULL, len, msg);
396 397 398 399 400 401 402 403 404 405 406 407 408 409
    priv->state = SOCKS_STATE_CONNECT;

    return 0;
  }
 error:
  nice_debug ("Socks5 error");
  if (priv->base_socket)
    nice_socket_free (priv->base_socket);
  priv->base_socket = NULL;
  priv->state = SOCKS_STATE_ERROR;

  return -1;
}

410
static gint
411 412
socket_send_messages (NiceSocket *sock, const NiceAddress *to,
    const NiceOutputMessage *messages, guint n_messages)
413 414 415 416
{
  Socks5Priv *priv = sock->priv;

  if (priv->state == SOCKS_STATE_CONNECTED) {
417 418
    /* Fast path: pass through to the base socket once connected. */
    if (priv->base_socket == NULL)
419
      return FALSE;
420

421 422
    return nice_socket_send_messages (priv->base_socket, to, messages,
        n_messages);
423
  } else if (priv->state == SOCKS_STATE_ERROR) {
424
    return -1;
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
  } else {
    return 0;
  }
  return n_messages;
}


static gint
socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to,
    const NiceOutputMessage *messages, guint n_messages)
{
  Socks5Priv *priv = sock->priv;

  if (priv->state == SOCKS_STATE_CONNECTED) {
    /* Fast path: pass through to the base socket once connected. */
    if (priv->base_socket == NULL)
      return -1;

    return nice_socket_send_messages_reliable (priv->base_socket, to, messages,
        n_messages);
  } else if (priv->state == SOCKS_STATE_ERROR) {
    return -1;
447
  } else {
448
    nice_socket_queue_send (&priv->send_queue, to, messages, n_messages);
449
  }
450
  return n_messages;
451 452 453 454 455 456
}


static gboolean
socket_is_reliable (NiceSocket *sock)
{
457 458 459
  Socks5Priv *priv = sock->priv;

  return nice_socket_is_reliable (priv->base_socket);
460 461
}