Guía de Ejercicios 4: Sockets en Rust
Ejercicio 1 - Introducción
Ítem A
Escribir un programa tal que el hilo main crea un thread hijo que actuará como cliente, mientras el padre actúa como servidor. La comunicación se establece para enviar y recibir un saludo, por ejemplo: Hola hijo y Buen día Papá.
Ítem B
Modificar el programa del ejercicio anterior para que el servidor pueda gestionar más de un cliente.
Ejercicio 2 - Mini Chat
Implementar un programa para armar una sala de chat.
El programa inicia y le pide un nickname al usuario. Luego, abre un socket servidor ligado a un puerto configurable. A continuación, realiza broadcasting del nickname a la subred, para después quedar escuchando mensajes.
Si recibe un mensaje de broadcast con un nickname, lo agrega a la lista de usuarios de la sala de chat, junto a la dirección IP de quien se lo envía.
Si recibe otro mensaje, se lo imprime por pantalla.
Para recibir un mensaje del usuario, se debe leer de la estrada estándar (stdin). Si se lo antecede con el nickname de destino, se lo envía a ese destinatario en particular. Con Enter, se transmite el mensaje.
Ejercicio 3 - FTP Honeypot
Introducción
Un honeypot es una aplicación que simula ser un servidor de otra aplicación mayor, para que cuando un usuario malicioso se conecte, ataque este servidor falso, permitiendo tomar registro de las técnicas de ataque que se utilizan en la red. En este trabajo práctico prototiparemos un honeypot de un servidor FTP.
Protocolo FTP
El protocolo FTP es un protocolo de texto, formado por mensajes delimitados por un salto de línea.
Los comandos son palabras en su mayoría de 4 letras, seguidos de un espacio que los separa de sus argumentos. El servidor responde con un código numérico y un texto descriptivo.
Cliente FTP
Los comandos que puede ejecutar el cliente son los siguientes
USER <username>
: Envía un nombre de usuario para realizar login.PASS <password>
: Envía un password para el usuario.SYST
: Consulta información del sistemaLIST
: Consulta los archivos contenidos en el directorio actualHELP
: Consulta los comandos disponiblesPWD
: Consulta el directorio actualMKD
: Crea un directorioRMD
: Elimina un directorio
Para simplificar el trabajo práctico, la transferencia de datos se realizará respondiendo en el mismo puerto por el cual se conectan inicialmente los clientes.
Esto implica que los comandos PASV
y PORT
no serán necesarios para transmitir información (por ejemplo con el comando LIST
).
Servidor FTP
El servidor FTP responde con los siguientes mensajes:
- Cuando un cliente recién se conecta:
220 <newClient>
- Cuando un cliente quiere operar sin haber hecho login:
530 <clientNotLogged>
- Luego de que un cliente envía un comando
USER
:331 <passRequired>
- Si el usuario envía un comando que no es
PASS
luego de un comandoUSER
:530 <clientNotLogged>
- Si el usuario realiza un login válido (el usuario enviado con
USER
y la contraseña enviada conPASS
son válidas, es decir, concuerdan con las configuradas):230 <loginSuccess>
- Si el usuario realiza un login inválido:
530 <loginFailed>
Una vez que el cliente realizó un login exitoso, se habilitan varios comandos al cliente:
- Si el usuario envía el comando
SYST
:215 <systemInfo>
- Si el usuario envía el comando
HELP
:214 <commands>
- Si el usuario envía el comando
LIST
, se realizará una respuesta en 3 partes
La primera línea será 150 <listBegin>
Luego enviará una línea por cada directorio cargado, con el siguiente formato:
drwxrwxrwx 0 1000 1000 4096 Sep 24 12:34 <nombre directorio>
Los directorios serán listados en orden alfabético.
Luego de enviar las líneas, enviará 226 <listEnd>
.
- Si el usuario envía el comando
PWD
:257 <currentDirectoryMsg>
- Si el usuario envía el comando
MKD <nombreDir>
, intenta agregar ````'' a la lista de directorios existentes responde: 257 "<nombreDir> <mkdSuccess>"
en caso de que el directorio no existía.550 <mkdFailed>
si ya existía
- Si el usuario envía el comando
RMD <nombreDir>
intenta remover"<nombreDir>"
de la lista de directorios y responde:250 <rmdSuccess>
si el directorio existe.550 <rmdFailed>
si no existía.
- Finalmente, el usuario puede pedirle al servidor que termine la conexión enviando la palabra
QUIT
. En tal caso el servidor responde con221 <quitSuccess>
y ambos cierran sus conexiones ordenadamente.
Cabe destacar que la entrada de comandos puede no terminar con QUIT
, debiendo el cliente cerrar su conexión al llegar al final del stream y el servidor liberar sus recursos adecuadamente.
Configuración de mensajes
El servidor FTP lee un archivo de configuración las siguientes variables
user
: Usuario para realizar loginpassword
: Password para realizar loginnewClient
: Mensaje enviado a un cliente recién conectadoclientNotLogged
: Mensaje enviado a un cliente que quiere operar sin haber hecho loginpassRequired
: Mensaje de solicitud de passwordloginSuccess
: Mensaje de password aceptadologinFailed
: Mensaje de password rechazadosystemInfo
: Mensaje de información del sistemacommands
: Mensaje con los comandos disponiblesunknownCommand
: Mensaje de comando inválidoquit
: Mensaje de desconexión del usuario
El archivo de configuración posee un formato ```clave=valor`'', y debe ser cargado al iniciar la aplicación. No se validará que se encuentren todas las claves necesarias, en caso de faltar una clave necesaria, es a decisión del desarrollador cómo contemplar este caso.
Formato de Línea de Comandos
Servidor
./server <puerto/servicio> <configuracion>
Donde <puerto/servicio>
es el puerto TCP (o servicio) en donde estará escuchando la conexiones entrantes, <configuracion>
el archivo con las variables del servidor.
Cliente
El cliente se ejecuta utilizando el siguiente formato de línea de comandos
./client <ip/hostname> <puerto/servicio>
El cliente se conectará al servidor corriendo en la máquina con dirección IP <ip>
(o <hostname>
), en el puerto (o servicio) TCP <puerto/servicio>
.
Requerimientos no funcionales
Los siguientes son los requerimientos no funcionales para la resolución de los ejercicios:
- El proyecto deberá ser desarrollado en lenguaje Rust, usando las herramientas de la biblioteca estándar.
- No se permite utilizar crates externos. El único crate autorizado a ser utilizado es rand en caso de que se quiera generar valores aleatorios.
- El código fuente debe compilarse en la versión stable del compilador y no se permite utilizar bloques unsafe.
- El código deberá funcionar en ambiente Unix / Linux.
- El programa deberá ejecutarse en la línea de comandos.
- La compilación no debe arrojar warnings del compilador, ni del linter clippy.
- Las funciones y los tipos de datos (struct) deben estar documentadas siguiendo el estándar de cargo doc.
- El código debe formatearse utilizando cargo fmt.
- Las funciones no deben tener una extensión mayor a 30 líneas. Si se requiriera una extensión mayor, se deberá particionarla en varias funciones.
- Cada tipo de dato implementado debe ser colocado en una unidad de compilación (archivo fuente) independiente.