Commit c118781f authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Implement Extended passive mode

(RFC2428 - FTP Extensions for IPv6 and NATs) :
- explicitly NAT-friendly FTP (refs #66),
- IPv6 support (closes #130).
parent bd988556
...@@ -78,10 +78,12 @@ static int Control( access_t *, int, va_list ); ...@@ -78,10 +78,12 @@ static int Control( access_t *, int, va_list );
struct access_sys_t struct access_sys_t
{ {
vlc_url_t url; vlc_url_t url;
int fd_cmd; int fd_cmd;
int fd_data; int fd_data;
vlc_bool_t b_epsv;
}; };
static int ftp_SendCommand( access_t *, char *, ... ); static int ftp_SendCommand( access_t *, char *, ... );
...@@ -220,6 +222,20 @@ static int Open( vlc_object_t *p_this ) ...@@ -220,6 +222,20 @@ static int Open( vlc_object_t *p_this )
goto exit_error; goto exit_error;
} }
/* Extended passive mode */
if( ftp_SendCommand( p_access, "EPSV ALL" ) < 0 )
{
msg_Err( p_access, "cannot request extended passive mode" );
goto exit_error;
}
if( ftp_ReadCommand( p_access, &i_answer, NULL ) != 2 )
{
p_sys->b_epsv = VLC_FALSE;
msg_Warn( p_access, "Extended passive mode not supported" );
}
else
p_sys->b_epsv = VLC_TRUE;
/* binary mode */ /* binary mode */
if( ftp_SendCommand( p_access, "TYPE I" ) < 0 || if( ftp_SendCommand( p_access, "TYPE I" ) < 0 ||
ftp_ReadCommand( p_access, &i_answer, NULL ) != 2 ) ftp_ReadCommand( p_access, &i_answer, NULL ) != 2 )
...@@ -401,7 +417,6 @@ static int ftp_SendCommand( access_t *p_access, char *psz_fmt, ... ) ...@@ -401,7 +417,6 @@ static int ftp_SendCommand( access_t *p_access, char *psz_fmt, ... )
access_sys_t *p_sys = p_access->p_sys; access_sys_t *p_sys = p_access->p_sys;
va_list args; va_list args;
char *psz_cmd; char *psz_cmd;
int i_ret;
va_start( args, psz_fmt ); va_start( args, psz_fmt );
vasprintf( &psz_cmd, psz_fmt, args ); vasprintf( &psz_cmd, psz_fmt, args );
...@@ -491,33 +506,61 @@ static int ftp_StartStream( access_t *p_access, off_t i_start ) ...@@ -491,33 +506,61 @@ static int ftp_StartStream( access_t *p_access, off_t i_start )
{ {
access_sys_t *p_sys = p_access->p_sys; access_sys_t *p_sys = p_access->p_sys;
char psz_ip[1000]; char psz_ipv4[16], *psz_ip;
int i_answer; int i_answer;
char *psz_arg, *psz_parser; char *psz_arg, *psz_parser;
int a1,a2,a3,a4; unsigned a1, a2, a3, a4, p1, p2;
int p1,p2;
int i_port; int i_port;
if( ftp_SendCommand( p_access, "PASV" ) < 0 || if( ( ftp_SendCommand( p_access, p_sys->b_epsv ? "EPSV" : "PASV" ) < 0 )
ftp_ReadCommand( p_access, &i_answer, &psz_arg ) != 2 ) || ( ftp_ReadCommand( p_access, &i_answer, &psz_arg ) != 2 ) )
{ {
msg_Err( p_access, "cannot set passive transfer mode" ); msg_Err( p_access, "cannot set passive mode" );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
psz_parser = strchr( psz_arg, '(' ); psz_parser = strchr( psz_arg, '(' );
if( !psz_parser || if( psz_parser == NULL )
sscanf( psz_parser, "(%d,%d,%d,%d,%d,%d", &a1, &a2, &a3,
&a4, &p1, &p2 ) < 6 )
{ {
free( psz_arg ); free( psz_arg );
msg_Err( p_access, "cannot get ip/port for passive transfer mode" ); msg_Err( p_access, "cannot parse passive mode response" );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
if( p_sys->b_epsv )
{
char psz_fmt[7] = "(|||%u";
psz_fmt[1] = psz_fmt[2] = psz_fmt[3] = psz_parser[1];
if( sscanf( psz_parser, psz_fmt, &i_port ) < 1 )
{
free( psz_arg );
msg_Err( p_access, "cannot parse passive mode response" );
return VLC_EGENERIC;
}
/* FIXME: if psz_ip is a hostname/DNS to a cluster of FTP servers,
* this may fail because we'll end up on another server :(
* getpeername() + getnameinfo() should be used instead.
*/
psz_ip = p_sys->url.psz_host;
}
else
{
if( ( sscanf( psz_parser, "(%u,%u,%u,%u,%u,%u", &a1, &a2, &a3, &a4,
&p1, &p2 ) < 6 ) || ( a1 > 255 ) || ( a2 > 255 )
|| ( a3 > 255 ) || ( a4 > 255 ) || ( p1 > 255 ) || ( p2 > 255 ) )
{
free( psz_arg );
msg_Err( p_access, "cannot parse passive mode response" );
return VLC_EGENERIC;
}
sprintf( psz_ipv4, "%u.%u.%u.%u", a1, a2, a3, a4 );
psz_ip = psz_ipv4;
i_port = (p1 << 8) | p2;
}
free( psz_arg ); free( psz_arg );
sprintf( psz_ip, "%d.%d.%d.%d", a1, a2, a3, a4 );
i_port = p1 * 256 + p2;
msg_Dbg( p_access, "ip:%s port:%d", psz_ip, i_port ); msg_Dbg( p_access, "ip:%s port:%d", psz_ip, i_port );
if( ftp_SendCommand( p_access, "TYPE I" ) < 0 || if( ftp_SendCommand( p_access, "TYPE I" ) < 0 ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment