PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/src/network/tcp.c

https://github.com/mstorsjo/vlc
C | 296 lines | 206 code | 49 blank | 41 comment | 71 complexity | 25d12b9c6ca02f87945dcc4b19152957 MD5 | raw file
  1. /*****************************************************************************
  2. * tcp.c:
  3. *****************************************************************************
  4. * Copyright (C) 2004-2005 VLC authors and VideoLAN
  5. * Copyright (C) 2005-2006 Rémi Denis-Courmont
  6. *
  7. * Authors: Laurent Aimar <fenrir@videolan.org>
  8. * Rémi Denis-Courmont <rem # videolan.org>
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU Lesser General Public License as published by
  12. * the Free Software Foundation; either version 2.1 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public License
  21. * along with this program; if not, write to the Free Software Foundation,
  22. * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23. *****************************************************************************/
  24. /*****************************************************************************
  25. * Preamble
  26. *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <vlc_common.h>
  31. #include <unistd.h>
  32. #include <vlc_network.h>
  33. #include <vlc_interrupt.h>
  34. /*****************************************************************************
  35. * SocksNegotiate:
  36. *****************************************************************************
  37. * Negotiate authentication with a SOCKS server.
  38. *****************************************************************************/
  39. static int SocksNegotiate( vlc_object_t *p_obj,
  40. int fd, int i_socks_version,
  41. const char *psz_socks_user,
  42. const char *psz_socks_passwd )
  43. {
  44. uint8_t buffer[128+2*256];
  45. int i_len;
  46. bool b_auth = false;
  47. if( i_socks_version != 5 )
  48. return VLC_SUCCESS;
  49. /* We negotiate authentication */
  50. buffer[0] = i_socks_version; /* SOCKS version */
  51. if( psz_socks_user != NULL && psz_socks_passwd != NULL )
  52. {
  53. buffer[1] = 2; /* Number of methods */
  54. buffer[2] = 0x00; /* - No auth required */
  55. buffer[3] = 0x02; /* - USer/Password */
  56. i_len = 4;
  57. b_auth = true;
  58. }
  59. else
  60. {
  61. buffer[1] = 1; /* Number of methods */
  62. buffer[2] = 0x00; /* - No auth required */
  63. i_len = 3;
  64. }
  65. if( net_Write( p_obj, fd, buffer, i_len ) != i_len )
  66. return VLC_EGENERIC;
  67. if( net_Read( p_obj, fd, buffer, 2) != 2 )
  68. return VLC_EGENERIC;
  69. msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
  70. if( buffer[1] == 0x00 )
  71. {
  72. msg_Dbg( p_obj, "socks: no authentication required" );
  73. }
  74. else if( buffer[1] == 0x02 )
  75. {
  76. if( psz_socks_user == NULL || psz_socks_passwd == NULL )
  77. {
  78. msg_Err( p_obj, "socks: server mandates authentication but "
  79. "a username and/or password was not supplied" );
  80. return VLC_EGENERIC;
  81. }
  82. int const i_user = strlen( psz_socks_user );
  83. int const i_pasw = strlen( psz_socks_passwd );
  84. if( i_user > 255 || i_pasw > 255 )
  85. {
  86. msg_Err( p_obj, "socks: rejecting username and/or password due to "
  87. "violation of RFC1929 (longer than 255 bytes)" );
  88. return VLC_EGENERIC;
  89. }
  90. msg_Dbg( p_obj, "socks: username/password authentication" );
  91. buffer[0] = i_socks_version; /* Version */
  92. buffer[1] = i_user; /* User length */
  93. memcpy( &buffer[2], psz_socks_user, i_user );
  94. buffer[2+i_user] = i_pasw; /* Password length */
  95. memcpy( &buffer[2+i_user+1], psz_socks_passwd, i_pasw );
  96. i_len = 3 + i_user + i_pasw;
  97. if( net_Write( p_obj, fd, buffer, i_len ) != i_len )
  98. return VLC_EGENERIC;
  99. if( net_Read( p_obj, fd, buffer, 2 ) != 2 )
  100. return VLC_EGENERIC;
  101. msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
  102. if( buffer[1] != 0x00 )
  103. {
  104. msg_Err( p_obj, "socks: authentication rejected" );
  105. return VLC_EGENERIC;
  106. }
  107. }
  108. else
  109. {
  110. if( b_auth )
  111. msg_Err( p_obj, "socks: unsupported authentication method %x",
  112. buffer[0] );
  113. else
  114. msg_Err( p_obj, "socks: authentication needed" );
  115. return VLC_EGENERIC;
  116. }
  117. return VLC_SUCCESS;
  118. }
  119. /*****************************************************************************
  120. * SocksHandshakeTCP:
  121. *****************************************************************************
  122. * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
  123. *****************************************************************************/
  124. static int SocksHandshakeTCP( vlc_object_t *p_obj,
  125. int fd,
  126. int i_socks_version,
  127. const char *psz_user, const char *psz_passwd,
  128. const char *psz_host, int i_port )
  129. {
  130. uint8_t buffer[128+2*256];
  131. if( i_socks_version != 4 && i_socks_version != 5 )
  132. {
  133. msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
  134. i_socks_version = 5;
  135. }
  136. if( i_socks_version == 5 &&
  137. SocksNegotiate( p_obj, fd, i_socks_version,
  138. psz_user, psz_passwd ) )
  139. return VLC_EGENERIC;
  140. if( i_socks_version == 4 )
  141. {
  142. /* v4 only support ipv4 */
  143. static const struct addrinfo hints = {
  144. .ai_family = AF_INET,
  145. .ai_socktype = SOCK_STREAM,
  146. .ai_protocol = IPPROTO_TCP,
  147. .ai_flags = AI_IDN,
  148. };
  149. struct addrinfo *res;
  150. if (vlc_getaddrinfo_i11e(psz_host, 0, &hints, &res))
  151. return VLC_EGENERIC;
  152. buffer[0] = i_socks_version;
  153. buffer[1] = 0x01; /* CONNECT */
  154. SetWBE( &buffer[2], i_port ); /* Port */
  155. memcpy (&buffer[4], /* Address */
  156. &((struct sockaddr_in *)(res->ai_addr))->sin_addr, 4);
  157. freeaddrinfo (res);
  158. buffer[8] = 0; /* Empty user id */
  159. if( net_Write( p_obj, fd, buffer, 9 ) != 9 )
  160. return VLC_EGENERIC;
  161. if( net_Read( p_obj, fd, buffer, 8 ) != 8 )
  162. return VLC_EGENERIC;
  163. msg_Dbg( p_obj, "socks: v=%d cd=%d",
  164. buffer[0], buffer[1] );
  165. if( buffer[1] != 90 )
  166. return VLC_EGENERIC;
  167. }
  168. else if( i_socks_version == 5 )
  169. {
  170. int i_hlen = __MIN(strlen( psz_host ), 255);
  171. int i_len;
  172. buffer[0] = i_socks_version; /* Version */
  173. buffer[1] = 0x01; /* Cmd: connect */
  174. buffer[2] = 0x00; /* Reserved */
  175. buffer[3] = 3; /* ATYP: for now domainname */
  176. buffer[4] = i_hlen;
  177. memcpy( &buffer[5], psz_host, i_hlen );
  178. SetWBE( &buffer[5+i_hlen], i_port );
  179. i_len = 5 + i_hlen + 2;
  180. if( net_Write( p_obj, fd, buffer, i_len ) != i_len )
  181. return VLC_EGENERIC;
  182. /* Read the header */
  183. if( net_Read( p_obj, fd, buffer, 5 ) != 5 )
  184. return VLC_EGENERIC;
  185. msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
  186. buffer[0], buffer[1], buffer[3] );
  187. if( buffer[1] != 0x00 )
  188. {
  189. msg_Err( p_obj, "socks: CONNECT request failed" );
  190. return VLC_EGENERIC;
  191. }
  192. /* Read the remaining bytes */
  193. if( buffer[3] == 0x01 )
  194. i_len = 4-1 + 2;
  195. else if( buffer[3] == 0x03 )
  196. i_len = buffer[4] + 2;
  197. else if( buffer[3] == 0x04 )
  198. i_len = 16-1+2;
  199. else
  200. return VLC_EGENERIC;
  201. if( net_Read( p_obj, fd, buffer, i_len ) != i_len )
  202. return VLC_EGENERIC;
  203. }
  204. return VLC_SUCCESS;
  205. }
  206. int (net_ConnectTCP)(vlc_object_t *obj, const char *host, int serv)
  207. {
  208. const char *realhost;
  209. int realserv;
  210. char *socks = var_InheritString(obj, "socks");
  211. if (socks != NULL)
  212. {
  213. realhost = socks;
  214. char *p = strchr(socks, ':');
  215. if (p != NULL)
  216. {
  217. *(p++) = '\0';
  218. realserv = atoi(p);
  219. }
  220. else
  221. realserv = 1080;
  222. msg_Dbg(obj, "net: connecting to %s port %d (SOCKS) "
  223. "for %s port %d", realhost, realserv, host, serv);
  224. }
  225. else
  226. {
  227. msg_Dbg(obj, "net: connecting to %s port %d", host, serv);
  228. realhost = host;
  229. realserv = serv;
  230. }
  231. int fd = net_Connect(obj, realhost, realserv, SOCK_STREAM, IPPROTO_TCP);
  232. if (socks != NULL && fd != -1)
  233. {
  234. /* NOTE: psz_socks already free'd! */
  235. char *user = var_InheritString(obj, "socks-user");
  236. char *pwd = var_InheritString(obj, "socks-pwd");
  237. if (SocksHandshakeTCP(obj, fd, 5, user, pwd, host, serv))
  238. {
  239. msg_Err(obj, "SOCKS handshake failed");
  240. net_Close(fd);
  241. fd = -1;
  242. }
  243. free(pwd);
  244. free(user);
  245. }
  246. return fd;
  247. }