PageRenderTime 58ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/Main/GStreamer/Source/ext/libnice/socket/socks5.c

https://github.com/zsx/ossbuild
C | 424 lines | 304 code | 60 blank | 60 comment | 72 complexity | d65fe593367a4edf55d871460f7be04f MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, LGPL-2.0, GPL-2.0
  1. /*
  2. * This file is part of the Nice GLib ICE library.
  3. *
  4. * (C) 2008 Collabora Ltd.
  5. * Contact: Youness Alaoui
  6. * (C) 2008 Nokia Corporation. All rights reserved.
  7. *
  8. * The contents of this file are subject to the Mozilla Public License Version
  9. * 1.1 (the "License"); you may not use this file except in compliance with
  10. * the License. You may obtain a copy of the License at
  11. * http://www.mozilla.org/MPL/
  12. *
  13. * Software distributed under the License is distributed on an "AS IS" basis,
  14. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  15. * for the specific language governing rights and limitations under the
  16. * License.
  17. *
  18. * The Original Code is the Nice GLib ICE library.
  19. *
  20. * The Initial Developers of the Original Code are Collabora Ltd and Nokia
  21. * Corporation. All Rights Reserved.
  22. *
  23. * Contributors:
  24. * Youness Alaoui, Collabora Ltd.
  25. *
  26. * Alternatively, the contents of this file may be used under the terms of the
  27. * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
  28. * case the provisions of LGPL are applicable instead of those above. If you
  29. * wish to allow use of your version of this file only under the terms of the
  30. * LGPL and not to allow others to use your version of this file under the
  31. * MPL, indicate your decision by deleting the provisions above and replace
  32. * them with the notice and other provisions required by the LGPL. If you do
  33. * not delete the provisions above, a recipient may use your version of this
  34. * file under either the MPL or the LGPL.
  35. */
  36. /*
  37. * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
  38. * http://en.wikipedia.org/wiki/Berkeley_sockets.)
  39. */
  40. #ifdef HAVE_CONFIG_H
  41. # include "config.h"
  42. #endif
  43. #include "socks5.h"
  44. #include <string.h>
  45. #ifndef G_OS_WIN32
  46. #include <unistd.h>
  47. #endif
  48. typedef enum {
  49. SOCKS_STATE_INIT,
  50. SOCKS_STATE_AUTH,
  51. SOCKS_STATE_CONNECT,
  52. SOCKS_STATE_CONNECTED,
  53. SOCKS_STATE_ERROR
  54. } SocksState;
  55. typedef struct {
  56. SocksState state;
  57. NiceSocket *base_socket;
  58. NiceAddress addr;
  59. gchar *username;
  60. gchar *password;
  61. GQueue send_queue;
  62. } Socks5Priv;
  63. struct to_be_sent {
  64. guint length;
  65. gchar *buf;
  66. NiceAddress to;
  67. };
  68. static void socket_close (NiceSocket *sock);
  69. static gint socket_recv (NiceSocket *sock, NiceAddress *from,
  70. guint len, gchar *buf);
  71. static gboolean socket_send (NiceSocket *sock, const NiceAddress *to,
  72. guint len, const gchar *buf);
  73. static gboolean socket_is_reliable (NiceSocket *sock);
  74. static void add_to_be_sent (NiceSocket *sock, const NiceAddress *to,
  75. const gchar *buf, guint len);
  76. static void free_to_be_sent (struct to_be_sent *tbs);
  77. NiceSocket *
  78. nice_socks5_socket_new (NiceSocket *base_socket,
  79. NiceAddress *addr, gchar *username, gchar *password)
  80. {
  81. Socks5Priv *priv;
  82. NiceSocket *sock = NULL;
  83. if (addr) {
  84. sock = g_slice_new0 (NiceSocket);
  85. sock->priv = priv = g_slice_new0 (Socks5Priv);
  86. priv->base_socket = base_socket;
  87. priv->addr = *addr;
  88. priv->username = g_strdup (username);
  89. priv->password = g_strdup (password);
  90. sock->fileno = priv->base_socket->fileno;
  91. sock->addr = priv->base_socket->addr;
  92. sock->send = socket_send;
  93. sock->recv = socket_recv;
  94. sock->is_reliable = socket_is_reliable;
  95. sock->close = socket_close;
  96. /* Send SOCKS5 handshake */
  97. {
  98. gchar msg[4];
  99. gint len = 3;
  100. msg[0] = 0x05; /* SOCKS version */
  101. msg[1] = 0x01; /* number of methods supported */
  102. msg[2] = 0x00; /* no authentication method*/
  103. g_debug ("user/pass : %s - %s", username, password);
  104. /* add support for authentication method */
  105. if (username || password) {
  106. msg[1] = 0x02; /* number of methods supported */
  107. msg[3] = 0x02; /* authentication method */
  108. len++;
  109. }
  110. /* We send 'to' NULL because it will always be to an already connected
  111. * TCP base socket, which ignores the destination */
  112. nice_socket_send (priv->base_socket, NULL, len, msg);
  113. priv->state = SOCKS_STATE_INIT;
  114. }
  115. }
  116. return sock;
  117. }
  118. static void
  119. socket_close (NiceSocket *sock)
  120. {
  121. Socks5Priv *priv = sock->priv;
  122. if (priv->base_socket)
  123. nice_socket_free (priv->base_socket);
  124. if (priv->username)
  125. g_free (priv->username);
  126. if (priv->password)
  127. g_free (priv->password);
  128. g_queue_foreach (&priv->send_queue, (GFunc) free_to_be_sent, NULL);
  129. g_queue_clear (&priv->send_queue);
  130. g_slice_free(Socks5Priv, sock->priv);
  131. }
  132. static gint
  133. socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
  134. {
  135. Socks5Priv *priv = sock->priv;
  136. switch (priv->state) {
  137. case SOCKS_STATE_CONNECTED:
  138. if (priv->base_socket)
  139. return nice_socket_recv (priv->base_socket, from, len, buf);
  140. break;
  141. case SOCKS_STATE_INIT:
  142. {
  143. gchar data[2];
  144. gint ret = -1;
  145. nice_debug ("Socks5 state Init");
  146. if (priv->base_socket)
  147. ret = nice_socket_recv (priv->base_socket, from, sizeof(data), data);
  148. if (ret <= 0) {
  149. return ret;
  150. } else if(ret == sizeof(data)) {
  151. if (data[0] == 0x05) {
  152. if (data[1] == 0x02) {
  153. gchar msg[515];
  154. gint len = 0;
  155. if (priv->username || priv->password) {
  156. gint ulen = 0;
  157. gint plen = 0;
  158. if (priv->username)
  159. ulen = strlen (priv->username);
  160. if (priv->password)
  161. plen = strlen (priv->password);
  162. msg[len++] = 0x01; /* auth version */
  163. msg[len++] = ulen; /* username length */
  164. memcpy (msg + len, priv->username, ulen); /* Username */
  165. len += ulen;
  166. msg[len++] = plen; /* Password length */
  167. memcpy (msg + len, priv->password, plen); /* Password */
  168. len += plen;
  169. nice_socket_send (priv->base_socket, NULL, len, msg);
  170. priv->state = SOCKS_STATE_AUTH;
  171. } else {
  172. /* Authentication required but no auth info available */
  173. goto error;
  174. }
  175. } else if (data[1] == 0x00) {
  176. goto send_connect;
  177. } else {
  178. /* method not supported by socks server */
  179. goto error;
  180. }
  181. } else {
  182. /* invalid SOCKS server version */
  183. goto error;
  184. }
  185. } else {
  186. /* read error */
  187. goto error;
  188. }
  189. }
  190. break;
  191. case SOCKS_STATE_AUTH:
  192. {
  193. gchar data[2];
  194. gint ret = -1;
  195. nice_debug ("Socks5 state auth");
  196. if (priv->base_socket)
  197. ret = nice_socket_recv (priv->base_socket, from, sizeof(data), data);
  198. if (ret <= 0) {
  199. return ret;
  200. } else if(ret == sizeof(data)) {
  201. if (data[0] == 0x01 && data[1] == 0x00) {
  202. /* Authenticated */
  203. goto send_connect;
  204. } else {
  205. /* Authentication failed */
  206. goto error;
  207. }
  208. }
  209. }
  210. break;
  211. case SOCKS_STATE_CONNECT:
  212. {
  213. gchar data[22];
  214. gint ret = -1;
  215. nice_debug ("Socks5 state connect");
  216. if (priv->base_socket)
  217. ret = nice_socket_recv (priv->base_socket, from, 4, data);
  218. if (ret <= 0) {
  219. return ret;
  220. } else if(ret == 4) {
  221. if (data[0] == 0x05) {
  222. switch (data[1]) {
  223. case 0x00:
  224. if (data[2] == 0x00) {
  225. struct to_be_sent *tbs = NULL;
  226. switch (data[3]) {
  227. case 0x01: /* IPV4 bound address */
  228. ret = nice_socket_recv (priv->base_socket, from, 6, data);
  229. if (ret != 6) {
  230. /* Could not read server bound address */
  231. goto error;
  232. }
  233. break;
  234. case 0x04: /* IPV6 bound address */
  235. ret = nice_socket_recv (priv->base_socket, from, 18, data);
  236. if (ret != 18) {
  237. /* Could not read server bound address */
  238. goto error;
  239. }
  240. break;
  241. default:
  242. /* Unsupported address type */
  243. goto error;
  244. }
  245. while ((tbs = g_queue_pop_head (&priv->send_queue))) {
  246. nice_socket_send (priv->base_socket, &tbs->to,
  247. tbs->length, tbs->buf);
  248. g_free (tbs->buf);
  249. g_slice_free (struct to_be_sent, tbs);
  250. }
  251. priv->state = SOCKS_STATE_CONNECTED;
  252. } else {
  253. /* Wrong reserved value */
  254. goto error;
  255. }
  256. break;
  257. case 0x01: /* general SOCKS server failure */
  258. case 0x02: /* connection not allowed by ruleset */
  259. case 0x03: /* Network unreachable */
  260. case 0x04: /* Host unreachable */
  261. case 0x05: /* Connection refused */
  262. case 0x06: /* TTL expired */
  263. case 0x07: /* Command not supported */
  264. case 0x08: /* Address type not supported */
  265. default: /* Unknown error */
  266. goto error;
  267. break;
  268. }
  269. } else {
  270. /* Wrong server version */
  271. goto error;
  272. }
  273. } else {
  274. /* Invalid data received */
  275. goto error;
  276. }
  277. }
  278. break;
  279. default:
  280. /* Unknown status */
  281. goto error;
  282. }
  283. return 0;
  284. send_connect:
  285. {
  286. gchar msg[22];
  287. gint len = 0;
  288. struct sockaddr_storage name;
  289. nice_address_copy_to_sockaddr(&priv->addr, (struct sockaddr *)&name);
  290. msg[len++] = 0x05; /* SOCKS version */
  291. msg[len++] = 0x01; /* connect command */
  292. msg[len++] = 0x00; /* reserved */
  293. if (name.ss_family == AF_INET) {
  294. msg[len++] = 0x01; /* IPV4 address type */
  295. /* Address */
  296. memcpy (msg + len, &((struct sockaddr_in *) &name)->sin_addr, 4);
  297. len += 4;
  298. /* Port */
  299. memcpy (msg + len, &((struct sockaddr_in *) &name)->sin_port, 2);
  300. len += 2;
  301. } else if (name.ss_family == AF_INET6) {
  302. msg[len++] = 0x04; /* IPV6 address type */
  303. /* Address */
  304. memcpy (msg + len, &((struct sockaddr_in6 *) &name)->sin6_addr, 16);
  305. len += 16;
  306. /* Port */
  307. memcpy (msg + len, &((struct sockaddr_in6 *) &name)->sin6_port, 2);
  308. len += 2;
  309. }
  310. nice_socket_send (priv->base_socket, NULL, len, msg);
  311. priv->state = SOCKS_STATE_CONNECT;
  312. return 0;
  313. }
  314. error:
  315. nice_debug ("Socks5 error");
  316. if (priv->base_socket)
  317. nice_socket_free (priv->base_socket);
  318. priv->base_socket = NULL;
  319. priv->state = SOCKS_STATE_ERROR;
  320. return -1;
  321. }
  322. static gboolean
  323. socket_send (NiceSocket *sock, const NiceAddress *to,
  324. guint len, const gchar *buf)
  325. {
  326. Socks5Priv *priv = sock->priv;
  327. if (priv->state == SOCKS_STATE_CONNECTED) {
  328. if (priv->base_socket)
  329. return nice_socket_send (priv->base_socket, to, len, buf);
  330. else
  331. return FALSE;
  332. } else if (priv->state == SOCKS_STATE_ERROR) {
  333. return FALSE;
  334. } else {
  335. add_to_be_sent (sock, to, buf, len);
  336. }
  337. return TRUE;
  338. }
  339. static gboolean
  340. socket_is_reliable (NiceSocket *sock)
  341. {
  342. return TRUE;
  343. }
  344. static void
  345. add_to_be_sent (NiceSocket *sock, const NiceAddress *to,
  346. const gchar *buf, guint len)
  347. {
  348. Socks5Priv *priv = sock->priv;
  349. struct to_be_sent *tbs = NULL;
  350. if (len <= 0)
  351. return;
  352. tbs = g_slice_new0 (struct to_be_sent);
  353. tbs->buf = g_memdup (buf, len);
  354. tbs->length = len;
  355. if (to)
  356. tbs->to = *to;
  357. g_queue_push_tail (&priv->send_queue, tbs);
  358. }
  359. static void
  360. free_to_be_sent (struct to_be_sent *tbs)
  361. {
  362. g_free (tbs->buf);
  363. g_slice_free (struct to_be_sent, tbs);
  364. }