1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004-2005 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@videolan.org>
8 * RĂ©mi Denis-Courmont <rem # videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
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 General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
37 #ifdef HAVE_SYS_TIME_H
38 # include <sys/time.h>
41 #if defined( WIN32 ) || defined( UNDER_CE )
42 # if defined(UNDER_CE) && defined(sockaddr_storage)
43 # undef sockaddr_storage
45 # include <winsock2.h>
46 # include <ws2tcpip.h>
48 # include <sys/socket.h>
49 # include <netinet/in.h>
50 # ifdef HAVE_ARPA_INET_H
51 # include <arpa/inet.h>
63 # define INADDR_ANY 0x00000000
66 # define INADDR_NONE 0xFFFFFFFF
69 static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
70 char *psz_socks_user, char *psz_socks_passwd );
71 static int SocksHandshakeTCP( vlc_object_t *,
72 int fd, int i_socks_version,
73 char *psz_socks_user, char *psz_socks_passwd,
74 const char *psz_host, int i_port );
76 static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
81 fd = socket( i_family, i_socktype, i_protocol );
84 #if defined(WIN32) || defined(UNDER_CE)
85 msg_Warn( p_this, "cannot create socket (%i)",
88 msg_Warn( p_this, "cannot create socket (%s)",
94 /* Set to non-blocking */
95 #if defined( WIN32 ) || defined( UNDER_CE )
97 unsigned long i_dummy = 1;
98 if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
99 msg_Err( p_this, "cannot set socket to non-blocking mode" );
102 if( ( ( i_val = fcntl( fd, F_GETFL, 0 ) ) < 0 ) ||
103 ( fcntl( fd, F_SETFL, i_val | O_NONBLOCK ) < 0 ) )
104 msg_Err( p_this, "cannot set socket to non-blocking mode (%s)",
109 setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
114 * Accepts only IPv6 connections on IPv6 sockets
115 * (and open an IPv4 socket later as well if needed).
116 * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets,
117 * so this allows for more uniform handling across platforms. Besides,
118 * it makes sure that IPv4 addresses will be printed as w.x.y.z rather
119 * than ::ffff:w.x.y.z
121 if( i_family == AF_INET6 )
122 setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val,
126 #if defined( WIN32 ) || defined( UNDER_CE )
127 # ifdef IPV6_PROTECTION_LEVEL
128 if( i_family == AF_INET6 )
130 i_val = PROTECTION_LEVEL_UNRESTRICTED;
131 setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &i_val,
135 # warning You are using outdated headers for Winsock !
141 /*****************************************************************************
143 *****************************************************************************
144 * Open a TCP connection and return a handle
145 *****************************************************************************/
146 int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
148 struct addrinfo hints, *res, *ptr;
149 const char *psz_realhost;
151 int i_realport, i_val, i_handle = -1;
154 i_port = 80; /* historical VLC thing */
156 memset( &hints, 0, sizeof( hints ) );
157 hints.ai_socktype = SOCK_STREAM;
159 psz_socks = var_CreateGetString( p_this, "socks" );
160 if( *psz_socks && *psz_socks != ':' )
162 char *psz = strchr( psz_socks, ':' );
167 psz_realhost = psz_socks;
168 i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
170 msg_Dbg( p_this, "net: connecting to '%s:%d' for '%s:%d'",
171 psz_realhost, i_realport, psz_host, i_port );
175 psz_realhost = psz_host;
178 msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_realhost,
182 i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
185 msg_Err( p_this, "cannot resolve '%s:%d' : %s", psz_realhost,
186 i_realport, vlc_gai_strerror( i_val ) );
191 for( ptr = res; (ptr != NULL) && (i_handle == -1); ptr = ptr->ai_next )
195 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
200 if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
202 socklen_t i_val_size = sizeof( i_val );
206 #if defined( WIN32 ) || defined( UNDER_CE )
207 if( WSAGetLastError() != WSAEWOULDBLOCK )
209 msg_Warn( p_this, "connection to %s:%d failed (%d)", psz_host,
210 i_port, WSAGetLastError( ) );
215 if( errno != EINPROGRESS )
217 msg_Warn( p_this, "connection to %s:%d : %s", psz_host,
218 i_port, strerror( errno ) );
224 var_Create( p_this, "ipv4-timeout",
225 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
226 var_Get( p_this, "ipv4-timeout", &timeout );
227 if( timeout.i_int < 0 )
229 msg_Err( p_this, "invalid negative value for ipv4-timeout" );
232 d = div( timeout.i_int, 100 );
234 msg_Dbg( p_this, "connection in progress" );
241 msg_Dbg( p_this, "connection aborted" );
243 vlc_freeaddrinfo( res );
248 /* Initialize file descriptor set */
252 /* We'll wait 0.1 second if nothing happens */
254 tv.tv_usec = (d.quot > 0) ? 100000 : (1000 * d.rem);
256 i_val = select( fd + 1, NULL, &fds, NULL, &tv );
260 msg_Dbg( p_this, "connection timed out" );
268 while( ( i_val == 0 ) || ( ( i_val < 0 ) &&
269 #if defined( WIN32 ) || defined( UNDER_CE )
270 ( WSAGetLastError() == WSAEWOULDBLOCK )
277 continue; /* timeout */
281 msg_Warn( p_this, "connection aborted (select failed)" );
286 #if !defined( SYS_BEOS ) && !defined( UNDER_CE )
287 if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val,
288 &i_val_size ) == -1 || i_val != 0 )
291 msg_Warn( p_this, "connection to %s:%d failed (%d)", psz_host,
292 i_port, WSAGetLastError( ) );
294 msg_Warn( p_this, "connection to %s:%d : %s", psz_host,
295 i_port, strerror( i_val ) );
302 i_handle = fd; /* success! */
305 vlc_freeaddrinfo( res );
307 if( *psz_socks && *psz_socks != ':' )
309 char *psz_user = var_CreateGetString( p_this, "socks-user" );
310 char *psz_pwd = var_CreateGetString( p_this, "socks-pwd" );
312 if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd,
315 msg_Err( p_this, "failed to use the SOCKS server" );
316 net_Close( i_handle );
329 /*****************************************************************************
331 *****************************************************************************
332 * Open TCP passive "listening" socket(s)
333 * This function returns NULL in case of error.
334 *****************************************************************************/
335 int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
337 struct addrinfo hints, *res, *ptr;
338 int i_val, *pi_handles, i_size;
340 memset( &hints, 0, sizeof( hints ) );
341 hints.ai_socktype = SOCK_STREAM;
342 hints.ai_flags = AI_PASSIVE;
344 msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
346 i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
349 msg_Err( p_this, "cannot resolve '%s:%d' : %s", psz_host, i_port,
350 vlc_gai_strerror( i_val ) );
357 for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
361 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
366 /* Bind the socket */
367 if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) )
369 #if defined(WIN32) || defined(UNDER_CE)
370 msg_Warn( p_this, "cannot bind socket (%i)", WSAGetLastError( ) );
372 msg_Warn( p_this, "cannot bind socket (%s)", strerror( errno ) );
379 if( listen( fd, 100 ) == -1 )
381 #if defined(WIN32) || defined(UNDER_CE)
382 msg_Err( p_this, "cannot bring socket in listening mode (%i)",
385 msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
392 newpi = (int *)realloc( pi_handles, (++i_size) * sizeof( int ) );
400 newpi[i_size - 2] = fd;
405 vlc_freeaddrinfo( res );
407 if( pi_handles != NULL )
408 pi_handles[i_size - 1] = -1;
412 /*****************************************************************************
414 *****************************************************************************
415 * Accept a connection on a set of listening sockets and return it
416 *****************************************************************************/
417 int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
419 vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
421 while( p_this->b_die == b_die )
423 int i_val = -1, *pi, *pi_end;
424 struct timeval timeout;
429 /* Initialize file descriptor set */
433 for( pi = pi_fd; *pi != -1; pi++ )
440 FD_SET( i_fd, &fds_r );
441 FD_SET( i_fd, &fds_e );
446 timeout.tv_usec = b_block ? 500000 : i_wait;
448 i_val = select( i_val + 1, &fds_r, NULL, &fds_e, &timeout );
449 if( ( ( i_val < 0 ) && ( errno == EINTR ) ) || i_val == 0 )
458 #if defined(WIN32) || defined(UNDER_CE)
459 msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
461 msg_Err( p_this, "network select error (%s)", strerror( errno ) );
466 for( pi = pi_fd; *pi != -1; pi++ )
470 if( !FD_ISSET( i_fd, &fds_r ) && !FD_ISSET( i_fd, &fds_e ) )
473 i_val = accept( i_fd, NULL, 0 );
476 #if defined(WIN32) || defined(UNDER_CE)
477 msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
479 msg_Err( p_this, "accept failed (%s)", strerror( errno ) );
485 * This round-robin trick ensures that the first sockets in
486 * pi_fd won't prevent the last ones from getting accept'ed.
489 memmove( pi, pi + 1, pi_end - pi );
499 /*****************************************************************************
501 *****************************************************************************
502 * Open a UDP connection and return a handle
503 *****************************************************************************/
504 int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
505 char *psz_server, int i_server )
510 char *psz_network = "";
511 network_socket_t sock;
515 /* Check if we have force ipv4 or ipv6 */
516 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
517 var_Get( p_this, "ipv4", &val );
520 psz_network = "ipv4";
523 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
524 var_Get( p_this, "ipv6", &val );
527 psz_network = "ipv6";
529 if( psz_server == NULL ) psz_server = "";
530 if( psz_bind == NULL ) psz_bind = "";
532 /* Prepare the network_socket_t structure */
533 sock.psz_bind_addr = psz_bind;
534 sock.i_bind_port = i_bind;
535 sock.psz_server_addr = psz_server;
536 sock.i_server_port = i_server;
539 msg_Dbg( p_this, "net: connecting to '%s:%d@%s:%d'",
540 psz_server, i_server, psz_bind, i_bind );
541 private = p_this->p_private;
542 p_this->p_private = (void*)&sock;
543 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
545 msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed",
546 psz_server, i_server, psz_bind, i_bind );
549 module_Unneed( p_this, p_network );
550 p_this->p_private = private;
552 return sock.i_handle;
555 /*****************************************************************************
557 *****************************************************************************
558 * Close a network handle
559 *****************************************************************************/
560 void net_Close( int fd )
563 CloseHandle( (HANDLE)fd );
564 #elif defined( WIN32 )
571 void net_ListenClose( int *pi_fd )
577 for( pi = pi_fd; *pi != -1; pi++ )
583 /*****************************************************************************
585 *****************************************************************************
586 * Read from a network socket
587 * If b_rety is true, then we repeat until we have read the right amount of
589 *****************************************************************************/
590 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
591 uint8_t *p_data, int i_data, vlc_bool_t b_retry )
593 struct timeval timeout;
598 vlc_bool_t b_die = p_this->b_die;
604 if( p_this->b_die != b_die )
609 /* Initialize file descriptor set */
611 FD_SET( fd, &fds_r );
613 FD_SET( fd, &fds_e );
615 /* We'll wait 0.5 second if nothing happens */
617 timeout.tv_usec = 500000;
619 } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
620 || ( i_ret < 0 && errno == EINTR ) );
624 #if defined(WIN32) || defined(UNDER_CE)
625 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
627 msg_Err( p_this, "network select error (%s)", strerror(errno) );
629 return i_total > 0 ? i_total : -1;
632 if( ( i_recv = (p_vs != NULL)
633 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
634 : recv( fd, p_data, i_data, 0 ) ) < 0 )
636 #if defined(WIN32) || defined(UNDER_CE)
637 if( WSAGetLastError() == WSAEWOULDBLOCK )
639 /* only happens with p_vs (SSL) - not really an error */
643 /* On win32 recv() will fail if the datagram doesn't fit inside
644 * the passed buffer, even though the buffer will be filled with
645 * the first part of the datagram. */
646 if( WSAGetLastError() == WSAEMSGSIZE )
648 msg_Err( p_this, "recv() failed. "
649 "Increase the mtu size (--mtu option)" );
652 else if( WSAGetLastError() == WSAEINTR ) continue;
653 else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
655 /* EAGAIN only happens with p_vs (SSL) and it's not an error */
656 if( errno != EAGAIN )
657 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
659 return i_total > 0 ? i_total : -1;
661 else if( i_recv == 0 )
663 /* Connection closed */
678 /*****************************************************************************
679 * __net_ReadNonBlock:
680 *****************************************************************************
681 * Read from a network socket, non blocking mode (with timeout)
682 *****************************************************************************/
683 int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
684 uint8_t *p_data, int i_data, mtime_t i_wait)
686 struct timeval timeout;
691 /* Initialize file descriptor set */
693 FD_SET( fd, &fds_r );
695 FD_SET( fd, &fds_e );
698 timeout.tv_usec = i_wait;
700 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
702 if( i_ret < 0 && errno == EINTR )
708 #if defined(WIN32) || defined(UNDER_CE)
709 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
711 msg_Err( p_this, "network select error (%s)", strerror(errno) );
721 #if !defined(UNDER_CE)
722 if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
724 if( ( i_recv = (p_vs != NULL)
725 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
726 : recv( fd, p_data, i_data, 0 ) ) <= 0 )
728 #if defined(WIN32) || defined(UNDER_CE)
730 /* On win32 recv() will fail if the datagram doesn't fit inside
731 * the passed buffer, even though the buffer will be filled with
732 * the first part of the datagram. */
733 if( WSAGetLastError() == WSAEMSGSIZE )
735 msg_Err( p_this, "recv() failed. "
736 "Increase the mtu size (--mtu option)" );
738 else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
740 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
745 return i_recv ? i_recv : -1; /* !i_recv -> connection closed if tcp */
748 /* We will never be here */
752 /*****************************************************************************
754 *****************************************************************************
755 * Read from several sockets (with timeout). Takes data from the first socket
757 *****************************************************************************/
758 int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
759 int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
761 struct timeval timeout;
768 /* Initialize file descriptor set */
772 for( i = 0 ; i < i_fd ; i++)
774 if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
775 FD_SET( pi_fd[i], &fds_r );
776 FD_SET( pi_fd[i], &fds_e );
780 timeout.tv_usec = i_wait;
782 i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
784 if( i_ret < 0 && errno == EINTR )
790 msg_Err( p_this, "network select error (%s)", strerror(errno) );
793 else if( i_ret == 0 )
799 for( i = 0 ; i < i_fd ; i++)
801 if( FD_ISSET( pi_fd[i], &fds_r ) )
803 i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
804 ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
805 : recv( pi_fd[i], p_data, i_data, 0 );
810 /* On win32 recv() will fail if the datagram doesn't
811 * fit inside the passed buffer, even though the buffer
812 * will be filled with the first part of the datagram. */
813 if( WSAGetLastError() == WSAEMSGSIZE )
815 msg_Err( p_this, "recv() failed. "
816 "Increase the mtu size (--mtu option)" );
818 else msg_Err( p_this, "recv failed (%i)",
821 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
831 /* We will never be here */
836 /* Write exact amount requested */
837 int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
838 uint8_t *p_data, int i_data )
840 struct timeval timeout;
846 vlc_bool_t b_die = p_this->b_die;
852 if( p_this->b_die != b_die )
857 /* Initialize file descriptor set */
859 FD_SET( fd, &fds_w );
861 FD_SET( fd, &fds_e );
863 /* We'll wait 0.5 second if nothing happens */
865 timeout.tv_usec = 500000;
867 } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
868 || ( i_ret < 0 && errno == EINTR ) );
872 #if defined(WIN32) || defined(UNDER_CE)
873 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
875 msg_Err( p_this, "network select error (%s)", strerror(errno) );
877 return i_total > 0 ? i_total : -1;
880 if( ( i_send = (p_vs != NULL)
881 ? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
882 : send( fd, p_data, i_data, 0 ) ) < 0 )
884 /* XXX With udp for example, it will issue a message if the host
886 /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
887 return i_total > 0 ? i_total : -1;
897 char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
899 char *psz_line = NULL, *ptr = NULL;
900 size_t i_line = 0, i_max = 0;
905 if( i_line == i_max )
908 psz_line = realloc( psz_line, i_max );
909 ptr = psz_line + i_line;
912 if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
931 if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
937 int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
938 const char *psz_fmt, ... )
942 va_start( args, psz_fmt );
943 i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
949 int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
950 const char *psz_fmt, va_list args )
955 vasprintf( &psz, psz_fmt, args );
956 i_size = strlen( psz );
957 i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
966 /*****************************************************************************
968 *****************************************************************************
969 * Negociate authentication with a SOCKS server.
970 *****************************************************************************/
971 static int SocksNegociate( vlc_object_t *p_obj,
972 int fd, int i_socks_version,
973 char *psz_socks_user,
974 char *psz_socks_passwd )
976 uint8_t buffer[128+2*256];
978 vlc_bool_t b_auth = VLC_FALSE;
980 if( i_socks_version != 5 )
983 /* We negociate authentication */
985 if( psz_socks_user && psz_socks_passwd &&
986 *psz_socks_user && *psz_socks_passwd )
989 buffer[0] = i_socks_version; /* SOCKS version */
992 buffer[1] = 2; /* Number of methods */
993 buffer[2] = 0x00; /* - No auth required */
994 buffer[3] = 0x02; /* - USer/Password */
999 buffer[1] = 1; /* Number of methods */
1000 buffer[2] = 0x00; /* - No auth required */
1004 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1005 return VLC_EGENERIC;
1006 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
1007 return VLC_EGENERIC;
1009 msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
1011 if( buffer[1] == 0x00 )
1013 msg_Dbg( p_obj, "socks: no authentication required" );
1015 else if( buffer[1] == 0x02 )
1017 int i_len1 = __MIN( strlen(psz_socks_user), 255 );
1018 int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
1019 msg_Dbg( p_obj, "socks: username/password authentication" );
1021 /* XXX: we don't support user/pwd > 255 (truncated)*/
1022 buffer[0] = i_socks_version; /* Version */
1023 buffer[1] = i_len1; /* User length */
1024 memcpy( &buffer[2], psz_socks_user, i_len1 );
1025 buffer[2+i_len1] = i_len2; /* Password length */
1026 memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
1028 i_len = 3 + i_len1 + i_len2;
1030 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1031 return VLC_EGENERIC;
1033 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
1034 return VLC_EGENERIC;
1036 msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
1037 if( buffer[1] != 0x00 )
1039 msg_Err( p_obj, "socks: authentication rejected" );
1040 return VLC_EGENERIC;
1046 msg_Err( p_obj, "socks: unsupported authentication method %x",
1049 msg_Err( p_obj, "socks: authentification needed" );
1050 return VLC_EGENERIC;
1056 /*****************************************************************************
1057 * SocksHandshakeTCP:
1058 *****************************************************************************
1059 * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
1060 *****************************************************************************/
1061 static int SocksHandshakeTCP( vlc_object_t *p_obj,
1063 int i_socks_version,
1064 char *psz_socks_user, char *psz_socks_passwd,
1065 const char *psz_host, int i_port )
1067 uint8_t buffer[128+2*256];
1069 if( i_socks_version != 4 && i_socks_version != 5 )
1071 msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
1072 i_socks_version = 5;
1075 if( i_socks_version == 5 &&
1076 SocksNegociate( p_obj, fd, i_socks_version,
1077 psz_socks_user, psz_socks_passwd ) )
1078 return VLC_EGENERIC;
1080 if( i_socks_version == 4 )
1082 struct addrinfo hints = { 0 }, *p_res;
1084 /* v4 only support ipv4 */
1085 hints.ai_family = AF_INET;
1086 if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) )
1087 return VLC_EGENERIC;
1089 buffer[0] = i_socks_version;
1090 buffer[1] = 0x01; /* CONNECT */
1091 SetWBE( &buffer[2], i_port ); /* Port */
1092 memcpy( &buffer[4], /* Address */
1093 &((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
1094 vlc_freeaddrinfo( p_res );
1096 buffer[8] = 0; /* Empty user id */
1098 if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
1099 return VLC_EGENERIC;
1100 if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
1101 return VLC_EGENERIC;
1103 msg_Dbg( p_obj, "socks: v=%d cd=%d",
1104 buffer[0], buffer[1] );
1106 if( buffer[1] != 90 )
1107 return VLC_EGENERIC;
1109 else if( i_socks_version == 5 )
1111 int i_hlen = __MIN(strlen( psz_host ), 255);
1114 buffer[0] = i_socks_version; /* Version */
1115 buffer[1] = 0x01; /* Cmd: connect */
1116 buffer[2] = 0x00; /* Reserved */
1117 buffer[3] = 3; /* ATYP: for now domainname */
1120 memcpy( &buffer[5], psz_host, i_hlen );
1121 SetWBE( &buffer[5+i_hlen], i_port );
1123 i_len = 5 + i_hlen + 2;
1126 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1127 return VLC_EGENERIC;
1129 /* Read the header */
1130 if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
1131 return VLC_EGENERIC;
1133 msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
1134 buffer[0], buffer[1], buffer[3] );
1136 if( buffer[1] != 0x00 )
1138 msg_Err( p_obj, "socks: CONNECT request failed\n" );
1139 return VLC_EGENERIC;
1142 /* Read the remaining bytes */
1143 if( buffer[3] == 0x01 )
1145 else if( buffer[3] == 0x03 )
1146 i_len = buffer[4] + 2;
1147 else if( buffer[3] == 0x04 )
1150 return VLC_EGENERIC;
1152 if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )
1153 return VLC_EGENERIC;
1159 /*****************************************************************************
1161 *****************************************************************************
1162 * Check that a given IP is within a set of IP/netmask.
1163 *****************************************************************************/
1164 int __net_CheckIP( vlc_object_t *p_this, char *psz_ip, char **ppsz_hosts,
1170 if( (ip.s_addr = inet_addr( psz_ip )) == INADDR_NONE )
1172 return VLC_EGENERIC;
1175 for( i = 0; i < i_hosts; i++ )
1177 struct in_addr base, mask;
1178 char *psz_host = strdup( ppsz_hosts[i] );
1179 char *p = strchr( psz_host, '/' );
1186 if( i_mask < 0 || i_mask > 32 )
1188 msg_Err( p_this, "invalid netmask %s", p );
1189 mask.s_addr = INADDR_NONE;
1191 else if( i_mask == 0 )
1192 mask.s_addr = INADDR_ANY;
1194 mask.s_addr = htonl( ntohl(INADDR_NONE) << (32 - i_mask) );
1197 mask.s_addr = INADDR_NONE;
1199 if( (base.s_addr = inet_addr( psz_host )) == INADDR_NONE )
1201 msg_Err( p_this, "invalid base address %s", psz_host );
1207 if( !((ip.s_addr ^ base.s_addr) & mask.s_addr) )