Discussion:
servidor ftp
(demasiado antiguo para responder)
aioritos
2005-09-12 09:57:13 UTC
Permalink
Hola!

Tengo un servidor ftp, que haciendo pruebas localmente, consigo
conectarme, enviar y recoger datos, y desconectarme.

Pero cuando intento hacer la prueba desde otro ordenador (con el mismo
o distinto S.O.) ocurre lo siguiente:

--- Si puedo conectarme al servidor
--- No puedo hacer put ni get porque me salta lo siguiente:

200 PORT command successful.
425 Data port connection failure.

Por qué localmente no me ocurre esto y si desde otro equipo ?
Miguel Angel Rodriguez Jodar
2005-09-12 12:28:53 UTC
Permalink
Post by aioritos
--- Si puedo conectarme al servidor
200 PORT command successful.
425 Data port connection failure.
Por qué localmente no me ocurre esto y si desde otro equipo ?
Porque seguramente tengas un firewall en el ordenador desde el cual estás
haciendo la prueba. Prueba a quitar todo tipo de firewalls en los dos PC's,
o bien quítalos en el PC donde tengas el servidor de FTP y usa el modo de
transferencia pasivo (el que estás usando ahora es el activo, con PORT)
Oscar Garcia
2005-09-12 17:20:14 UTC
Permalink
Post by aioritos
--- Si puedo conectarme al servidor
200 PORT command successful.
425 Data port connection failure.
Tal y como te dice Miguel Angel deberías usar el modo pasivo para
compatibilidad con routers y dispositivos de acceso a Internet
compartidos sin soporte para seguimiento de conexiones como los que
tiene un router basado en Linux.

En Linux basta con activar los módulos de seguimiento de conexiones
(casi siempre están activados los básicos por defecto, pero debemos
activar unos cuantos extra):

modprobe ip_conntrack
modprobe ip_conntrack_ftp
modprobe ip_nat_ftp

Con eso activarás el seguimiento de conexiones (en general), el
específico para conexiones activas y pasivas de ftp y por último la
conversión de IPs privadas a públicas transparente (para soportar modo
pasivo y activo aunque sea una conexión compartida).

Muchos routers basados en núcleos Linux (como algunos linksys) por
defecto tienen estos módulos ya activados (para ftp, irc, h323
-videocnoferencia-, etc), pero por lo que veo no usas ni una ni otra
solución.

Dejando ya de lado activar el soporte de seguimiento de conexiones y
nat para ftp veamos cómo funciona el modo pasivo (pasv) y el modo
activo (port):

Modo activo (PORT):
1.- Creamos un puerto a la escucha.
2.- Obtenemos los datos de ese puerto local y lo enviamos en un
mensaje PORT ip1,ip2,ip3,ip4,puerto1,puerto2
3.- Tras la respuesta 200 ya podemos realizar un listado o
transferencia de archivos tras los comandos TYPE y MODE para dicha
conexión.
4.- Justo tras enviar el comando (GET, PUT, LIST, etc) el servidor
establecerá una conexión con nuestra máquina (o creo que antes, pero
como estamos usando colas de espera no importará que sea antes o
después).

El problema con la mayoría de los routers es que la conexión se queda
en el router y no es enviada a la IP privada de la máquina que está
realizando la petición.

Modo pasivo (PASV):
1.- Enviamos una petición de modo pasivo (PASV).
2.- Se nos devuelve una IP y un puerto en el formato que usamos
normalmente para PORT: 227 Entering Passive Mode
(ip1,ip2,ip3,ip4,puerto1,puerto2).
3.- Establecemos una conexión con el servidor y la mantenemos abierta.
4.- Realizamos la petición (GET, PUT, etc).
5.- Obtenemos el resultado por la conexión establecida.

En este caso nuestro equipo establece una conexión con el servidor. La
mayoría de los servidores de Internet usan IP públicas y no tienen
problemas de NAT o bien usan routers NAT con seguimiento de conexiones
y nat para ftp.

En el caso de que sea el PC de un amigo y que también tenga router
entonces estás en el caso de la típica ID baja de los programas P2P.
Ni tú puedes establecer conexión con el equipo remoto ni el remoto
contigo, porque en ambos casos se queda la conexión en el router.

Este caso es peor, porque en el caso de que incluso redireccionemos
los puertos, el servidor FTP (o bien el cliente) envía en el modo PORT
o PASV la información de la IP local y no de la IP pública (a no ser
que tengamos seguimiento de conexiones y nat para ftp).

En resumen:
Procura usar siempre que te sea posible el modo pasivo para maximizar
la cmopatibilidad de tu aplicación con los routers que hoy en día
abundan tanto por casa como por empresas.

Un saludo.
P.D.: Como siempre, un enlace al RFC para que te lo leas bien ya que
es la biblia para todo programador de aplicaciones basadas en FTP:
http://www.faqs.org/rfcs/rfc959.html
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
aioritos
2005-09-13 07:43:10 UTC
Permalink
Gracias por vuestras respuestas.

Intentaré adaptar el modo pasivo, y si eso no me resulta miraré el
resto.
aioritos
2005-09-13 09:46:16 UTC
Permalink
Bueno, tal y como me recomendasteis, miré lo de los firewalls, y no es
el problema por que no hay. Tambien decir que es una comunicación
directa entre cliente - servidor (sin NAT de por medio).
Post by Oscar Garcia
1.- Enviamos una petición de modo pasivo (PASV).
2.- Se nos devuelve una IP y un puerto en el formato que usamos
normalmente para PORT: 227 Entering Passive Mode
(ip1,ip2,ip3,ip4,puerto1,puerto2).
3.- Establecemos una conexión con el servidor y la mantenemos abierta.
4.- Realizamos la petición (GET, PUT, etc).
5.- Obtenemos el resultado por la conexión establecida.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
El cliente envía el comando "PASV" a secas, sin nada más.
El servidor o recibe, y... aparte de decirle "227 Entering Passive Mode
(ip1,ip2,ip3,ip4,puerto1,puerto2)", que más debería hacer? Me he
puesto a buscar algún ejemplo de código pero no he visto nada, solo
tutoriales que me dicen lo que me has puesto arriba.
Oscar Garcia
2005-09-13 22:34:26 UTC
Permalink
Post by aioritos
El cliente envía el comando "PASV" a secas, sin nada más.
El servidor o recibe, y... aparte de decirle "227 Entering Passive Mode
(ip1,ip2,ip3,ip4,puerto1,puerto2)", que más debería hacer? Me he
puesto a buscar algún ejemplo de código pero no he visto nada, solo
tutoriales que me dicen lo que me has puesto arriba.
Conectarte al host ip1.ip2.ip3.ip4 al puerto (puerto1*256+puerto2).

Puedes hacerlo tras enviar un comando GET, PUT o LIST sin problemas.

Otro día que tenga más tiempo te pongo un ejemplo.

Un saludo.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
aioritos
2005-09-14 07:36:01 UTC
Permalink
De acuerdo gracias.
aioritos
2005-09-16 07:49:31 UTC
Permalink
Oye Óscar, no es por ser un pesado ni nada, porque seguro que tendrás
trabajo y essas cosas, pero podrás darme una respuesta para el Lunes?
porque de 4 o 5 foros en los que he pedido ayuda tu eres la unica
esperanza....

Saludos.
Jose Miguel Pérez
2005-09-16 11:23:52 UTC
Permalink
Post by aioritos
Oye Óscar, no es por ser un pesado ni nada, porque seguro que tendrás
trabajo y essas cosas, pero podrás darme una respuesta para el Lunes?
porque de 4 o 5 foros en los que he pedido ayuda tu eres la unica
esperanza....
Qué problema tienes ahora realmente? Oscar te ha puesto todas las
indicaciones pertinentes para que ahora seas tú quien revise el código y
puedas realizar una transferencia PASV.

Si tienes problemas para leer un RFC en inglés (Ya te han dicho que el RFC
del protocolo FTP es el RFC959), aquí te paso un enlace para leer el RFC-959
en español:

PROTOCOLO DE TRANSFERENCIA DE FICHEROS (FTP)
http://www.rfc-es.org/rfc/rfc0959-es.txt

Ahí tienes todo lo necesario para hacer un cliente o un servidor FTP, pero
claro, no esperes en un RFC un ejemplo de código que puedas cortar y pegar y
que funcione.

En cuanto a no encontrar código fuente de un cliente FTP, me parece extraño,
porque debe ser el trozo de código más extendido de la red, ya que este
protocolo es de los más antiguos. Es más, haciendo una búsqueda correcta en
Google, puedes darle al botón "I'm feeling lucky!" porque el primer enlace
ya te devuelve resultados apetitosos:

Google -> Buscar: "FTP client source code"

Te aparece como primer enlace lo siguiente:

"The FTP Protocol Resource Center"
http://war.jgaa.com/ftp/?cmd=src

Que creo que es más o menos lo que tu buscas, código fuente de varios
clientes y servidores FTP.

Saludos,
Jose Miguel.
Oscar Garcia
2005-09-16 11:50:18 UTC
Permalink
Post by aioritos
Oye Óscar, no es por ser un pesado ni nada, porque seguro que tendrás
trabajo y essas cosas, pero podrás darme una respuesta para el Lunes?
porque de 4 o 5 foros en los que he pedido ayuda tu eres la unica
esperanza....
Marchando una de prueba de FTP (vaya mañanita :):

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stropts.h>

//typedef unsigned short ushort;
//typedef unsigned int uint;

int conectar (char *servidor, ushort puerto) {
int sock, errorlevel;
struct hostent *host;
struct sockaddr_in nombre;

fprintf(stderr, "Conectando a %s (puerto %u)\n", servidor,
(uint)puerto);

host = gethostbyname(servidor);
if (host == NULL) {
fprintf(stderr, "Error: No se puede resolver %s.\n",
servidor);
return -1;
} else {
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) {
fprintf(stderr, "Error: No pude crear el
socket.\n");
return -1;
} else {
nombre.sin_family = host->h_addrtype;
nombre.sin_port = htons(puerto);
memcpy((char *) &nombre.sin_addr.s_addr,
host->h_addr_list[0], host->h_length);
errorlevel = connect(sock, (struct sockaddr *)
&nombre, sizeof(nombre));
if (errorlevel == -1) {
fprintf(stderr, "Error al conectar al
servidor.\n");
close(sock);
return -1;
} else {
fprintf(stderr, "Conexion a %s
abierta.\n", host->h_name);
}
}
}
return sock;
}

int obtener_respuesta (int sock, char *buffer, int lon) {
char codigo[4] = "\0\0\0";
int errorlevel;

// ¡¡Cuidadito que no compruebo si devuelve un error!!
errorlevel = recv(sock, buffer, lon, 0);
strncpy(codigo, buffer, 3);
// ¡¡Cuidadin que no se comprueba el límite del buffer!!
while (ioctl(sock, I_PEEK) == 1) {
errorlevel += recv(sock, buffer + errorlevel, lon, 0);
}
*(buffer + errorlevel) = 0;
return atoi(codigo);
}

int enviar(char *mensaje, int sock) {
send(sock, mensaje, strlen(mensaje), 0);
}

void obtener_enteros (char *cadena, int *enteros) {
char temporal, *inicio = cadena, *fin, estado = 0, pos = 0;
while (*inicio) {
switch (estado) {
case 0:
if ((*inicio) >= '0' && (*inicio) <= '9') {
estado = 1;
fin = inicio;
} else {
inicio++;
}
break;
case 1:
if ((*fin) < '0' || (*fin) > '9') {
estado = 0;
temporal = *fin;
*fin = 0;
*(enteros++) = atoi(inicio);
*fin = temporal;
inicio = fin;
} else {
fin++;
}
break;
}
}
}

int main (void) {
int sock, pasivo, respuesta;
char buffer[32000];
char host[128];
int datos[7];

sock = conectar("servidor", 21);
respuesta = obtener_respuesta(sock, buffer, sizeof(buffer));
printf("Respuesta %d - %s", respuesta, buffer);
enviar("USER usuario\r\n", sock);
respuesta = obtener_respuesta(sock, buffer, sizeof(buffer));
printf("Respuesta %d - %s", respuesta, buffer);
enviar("PASS clave\r\n", sock);
respuesta = obtener_respuesta(sock, buffer, sizeof(buffer));
printf("Respuesta %d - %s", respuesta, buffer);
enviar("PASV\r\n", sock);
respuesta = obtener_respuesta(sock, buffer, sizeof(buffer));
printf("Respuesta %d - %s", respuesta, buffer);
obtener_enteros(buffer, (int*)&datos);
printf("Datos (%d - %d,%d,%d,%d,%d,%d)\n",
datos[0], datos[1], datos[2], datos[3],
datos[4], datos[5], datos[6]);
sprintf(host, "%d.%d.%d.%d", datos[1], datos[2], datos[3],
datos[4]);
pasivo = conectar(host, (datos[5]<<8) + datos[6]);
enviar("LIST\r\n", sock);
respuesta = obtener_respuesta(sock, buffer, sizeof(buffer));
printf("Respuesta %d - %s", respuesta, buffer);
while ((respuesta = recv(pasivo, buffer, 32000, 0)) > 0) {
*(buffer + respuesta) = 0;
printf("%s", buffer);
}
close(pasivo);
puts("Conexion pasiva cerrada");
respuesta = obtener_respuesta(sock, buffer, sizeof(buffer));
printf("Respuesta %d - %s", respuesta, buffer);
enviar("QUIT\r\n", sock);
respuesta = obtener_respuesta(sock, buffer, sizeof(buffer));
printf("Respuesta %d - %s", respuesta, buffer);
close(sock);
return 0;
}

Ale, ¡que sea de provecho!.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
McLeod / IdeaFix
2005-09-16 13:45:24 UTC
Permalink
Post by aioritos
trabajo y essas cosas, pero podrás darme una respuesta para el Lunes?
Oye... que si lo que quieres es acabar esa práctica de programación para
el lunes, ya podrías haber estudiado en verano en lugar de gorronearle a
la gente que postea por aquí.

Te han dado todos los pasos, RFC's, etc... BUSCATE LA VIDA, lee y haz
pruebas. Será por documentación? Será por código fuente publicado?

Es que hay que tener cara, amos...
aioritos
2005-09-19 08:09:59 UTC
Permalink
Gracias Oscar, la verdad es que no esperaba este ejemplo, sino solo las
lineas sobre como uso de pasv, pero esto esta bastante bien.

Gracias.

(Espero no tener que decir nada mas por aqui....)
Oscar Garcia
2005-09-19 09:09:11 UTC
Permalink
Post by aioritos
Gracias Oscar, la verdad es que no esperaba este ejemplo, sino solo las
lineas sobre como uso de pasv, pero esto esta bastante bien.
Gracias.
De nada.
Post by aioritos
(Espero no tener que decir nada mas por aqui....)
Procura responder a los mensajes correctos para que se queden
almacenados de forma ordenada en los archivos históricos del grupo de
news.

Este mensaje ha sido respondido a McLeod.

Un saludo y hasta pronto. Por mi parte no tendré ningún problema en
ponerte otros ejemplos o echarte una mano para lograr hacer algo.

Por otro lado te recuerdo que siempre hace mucho herramientas del tipo
"packet sniffer" para estudiar los protocolos sobre la marcha.
--
Óscar Javier García Baudet
LinaresDigital
http://redstar.linaresdigital.com/
aioritos
2005-09-19 08:22:08 UTC
Permalink
Post by McLeod / IdeaFix
Oye... que si lo que quieres es acabar esa práctica de programación para
el lunes, ya podrías haber estudiado en verano en lugar de gorronearle a
la gente que postea por aquí.
Te han dado todos los pasos, RFC's, etc... BUSCATE LA VIDA, lee y haz
pruebas. Será por documentación? Será por código fuente publicado?
Es que hay que tener cara, amos...
1º.- Yo ya he acabado mis estudios en Julio.
2º.- gorronear?? No habia visto en mi vida nada acerca de servidores
ni de ftp, y llevo BASTANTE TIEMPO leyendome manuales y RFC's,
buscando codigos hechos colgados en la web, y seguia sin verlo claro.
3º.- YA TENIA HECHO EL CLIENTE Y EL SERVIDOR FTP ANTES DE PUBLICAR
ESTE TEMA.
Pero supongo que un capullo como tu no sabe leer los primeros mensajes.
4º.- No toda la gente es tan lista como tu y a veces necesita de un
pequeño empujon para empezar a andar....

5º.- Tener cara habria sido pedir sin tener nada hecho, sin dar las
gracias, y ver problemas de los demas y pasar de ellos. Te crees que yo
solo voy preguntando por los foros??? YO tambien intento ayudar a la
gente con sus dudas (en parte gracias a oscar, pq el fue quien me
animo..) y se que es tener cara y que no lo es, y tu no estas en
ninguna posicion de decirme a mi que le hecho cara.
6º.- BUSCATE LA VIDA?? Y QUE COJONES TE CREES QUE HAGO TODOS LOS
DIAS??







Siento acabar asi este tema pero desde luego no me iba a quedar sin
decirle nada a este tipo.
Loading...