Memoria del proyecto - Departamento de Teoría de la Señal
Transcripción
Memoria del proyecto - Departamento de Teoría de la Señal
Caracterización de anomalías en tráco P2P mediante autómatas de estados nitos Departamento de Teoría de la Señal, Telemática y Comunicaciones Proyecto Fin de Carrera Jesús Javier Nuño García Directores: Jesús Esteban Díaz Verdejo Gabriel Maciá Fernández D. Jesús Esteban Díaz Verdejo y D. Gabriel Maciá Fernández, profesores de la Escuela Técnica Superior de Ingenierías Informática y Telecomunicación del Departamento de Teoría de la Señal, Telemática y Comunicaciones, como Directores del Proyecto Fin de Carrera de D. Jesús Javier Nuño García DECLARAN que este trabajo, con título Caracterización de anomalías en tráco P2P con autómatas de estados nitos , ha sido elaborado por el alumno mencionado bajo nuestra supervisión y autorizamos su defensa ante el tribunal que corresponda. Y para que conste, rmamos el presente documento, en Granada, a 1 de septiembre de 2009. D. Jesús Esteban Díaz Verdejo D. Gabriel Maciá Fernández i ii Jesús Javier Nuño García, con DNI n º 75.144.433-Y, alumno de Ingeniería Informá- tica de la Escuela Técnica Superior de Ingenierías Informática y Telecomunicación de la Universidad de Granada, autoriza que se expida una copia del presente documento de Proyecto Fin de Carrera a la biblioteca del Centro, a n de poder ser consultada o referenciada por aquellas personas que lo deseen. Granada, a 1 de septiembre de 2009 Jesús Javier Nuño García iii iv Caracterización de anomalías en tráco P2P mediante autómatas de estados nitos Jesús Javier Nuño García Palabras clave: Protocolo eDonkey, anomalía, autómata de estados nitos, IDS, P2P. Resumen: El popular protocolo para redes peer-to-peer `eDonkey', dene un modo de intercambio de mensajes entre ciertas entidades involucradas en una comunicación. En particular, establece la secuencia y tipo de tramas intercambiadas entre dos nodos (peers ) de la red P2P. Para cada situación, este protocolo tiene denido una serie de intercambios de mensajes consecutivos. Para cada uno de estos escenarios se puede denir un autómata de estados nitos que modele el comportamiento del protocolo. Mediante el desarrollo de una aplicación con conocimiento acerca de estos autómatas, se puede analizar el comportamiento de las entidades en el uso del protocolo. A partir de los resultados obtenidos, estos comportamientos se podrán clasicar como permitidos o no, dependiendo de si han seguido la especicación del protocolo instanciada en los autómatas. Los comportamientos no acordes a dichos autómatas podrán, consecuentemente, clasicarse como anómalos desde el punto de vista de la seguridad de los sistemas. En este proyecto se modela e implementa un entorno de análisis que permite evaluar las posibles anomalías existentes en el protocolo `eDonkey' mediante autómatas de estados nitos. Adicionalmente, se diseñan y realizan una serie de pruebas de evaluación para comprobar el correcto funcionamiento de la aplicación, así como su rendimiento. v vi Anomaly characterization in P2P trac with nite-state machines Jesús Javier Nuño García Keywords: eDonkey protocol, anomaly, nite-state machine, IDS, P2P. Abstract: The popular peer-to-peer protocol `eDonkey', denes message exchange between certain entities involved in a communication. In particular, it establishes the sequence and type of frames exchanged between two P2P network nodes (peers). For every possible situation, this protocol denes a series of consecutive message exchange. For each of these scenarios, a nite-state machine can be dened to model the protocol's behavior. By developing an application with information about these nite-state machines, the behavior of the communication entities, related to the use of the protocol, can be analyzed. From the results obtained, these behaviors may be classied as allowed or not, depending on whether they have followed the protocol specication as instantiated in nite-state machines. Those behaviors not coherent with these nite-state machines can be consequently classied as abnormal from a system security point of view. In this project, an environment is modeled and implemented. It makes it possible to evaluate possible anomalies in `eDonkey' protocol by nite-state machines. In order to check the correct implementation of the application, as well as its performance, a series of tests are designed, being their result clearly discussed. vii viii Agradecimientos Estoy especialmente agradecido a mis padres y mi hermana, por el apoyo incondicional que me han dado durante toda mi carrera. Especial agradecimiento a mis compañeros, por su ayuda, dedicación, buen hacer y compañerismo, dado que gracias a ellos he conseguido aprender mucho más de lo imaginable. Y por último, dar innitas gracias a mis directores D. Jesús Esteban Díaz Verdejo y D. Gabriel Maciá Fernández por el interés, la motivación y el apoyo que me han prestado durante tanto tiempo. Gracias a todos. ix x Licencia © <Caracterización de anomalías en tráco P2P mediante autómatas de estados nitos> Copyright <2009> <Jesús Javier Nuño García> Este Programa es Software Libre: usted puede redistribuirlo y/o modicarlo bajo los ª términos de la Licencia Publica General GNU como es publicada por la Fundacion de Software Libre; en la 3 versión de la licencia, o (a su opción) cualquier versión posterior. Este programa es distribuido con la esperanza de que sea útil, pero SIN GARANTÍA ALGUNA; sin siquiera la garantía implícita de VALOR COMERCIAL o FORMADO PARA UN PROPÓSITO EN PARTICULAR. Vea la Licencia Publica General GNU para más detalles. Usted debe haber recibido una copia de la Licencia Publica General GNU junto con este programa. Si no, vaya a <http://www.gnu.org/licenses/>. xi xii Índice general 0. Descripción del problema y especicaciones 1 1. Introducción 3 1.1. Las redes en la actualidad . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2. ¾Qué son las redes P2P y por qué son importantes? . . . . . . . . . . . . . 5 1.3. El protocolo `eDonkey' . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4. Justicación del proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . . 2. Fundamentos tecnológicos 8 16 19 2.1. Teoría de autómatas de estados nitos . . . . . . . . . . . . . . . . . . . . 2.2. Paradigma cliente-servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.3. Modelado de protocolos con autómatas de estados nitos . . . . . . . . . . 25 2.4. Herramientas y utilidades 27 . . . . . . . . . . . . . . . . . . . . . . . . . . . 3. Análisis 19 37 3.1. Procedimientos en el protocolo `eDonkey' . . . . . . . . . . . . . . . . . . 3.2. Análisis de requisitos y funcionalidades de la aplicación . . . . . . . . . . . 59 3.3. Discusión del análisis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 4. Diseño e implementación 37 65 4.1. Estructura modular de la aplicación . . . . . . . . . . . . . . . . . . . . . 65 4.2. Descripción de las estructuras de datos utilizadas . . . . . . . . . . . . . . 74 5. Evaluación 81 5.1. Diseño de las pruebas de evaluación . . . . . . . . . . . . . . . . . . . . . . 81 5.2. Evaluación de la funcionalidad de la aplicación . . . . . . . . . . . . . . . 88 5.3. Evaluación del rendimiento de la aplicación . . . . . . . . . . . . . . . . . 94 6. Planicación y estimación de recursos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 6.1. Planicación 6.2. Recursos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 xv 97 Índice general 6.3. Estudio económico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 7. Logros y conclusiones 103 7.1. Logros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 7.2. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 Bibliografía 105 Apéndice 107 A. Descripción de los métodos utilizados 107 xvi Índice de guras 1.1. 1.2. Millones de usuarios conectados a Internet (enero de 2009). . . . . . . . . 3 Porcentaje de población que se conecta a Internet en los quince países más poblados (enero 2009). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.3. Distribución porcentual del tráco de Internet en Alemania en 2007. . . . 4 1.4. Interfaz del cliente `eMule'. . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.5. Porcentaje de uso de protocolos P2P en Alemania en 2007 (véase [2]). . . 9 1.6. Estructura de la red `eMule' (protocolo `eDonkey'). . . . . . . . . . . . . . 11 1.7. Estructura de una trama del protocolo `eDonkey'. . . . . . . . . . . . . . . 16 2.1. Autómata de ejemplo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.2. Autómata de ejemplo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.3. Ejemplo de AFD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.4. Ejemplo de AFND. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.5. Ejemplo de conexión entre dos computadores cualesquiera. . . . . . . . . . 24 2.6. Ejemplo de intercambio de paquetes entre dos nodos de una red P2P. . . . 26 2.7. Ejemplo de información extraída en el intercambio de tramas entre dos nodos en la red. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.8. Información extraída de tres tramas. . . . . . . . . . . . . . . . . . . . . . 27 2.9. Ejemplo de modelado de protocolo con un autómata. . . . . . . . . . . . . 27 2.10. Conexión entre los tres elementos principales de la STL. 2.11. Costes en tiempo (aproximados) para fork() . . . . . . . . . . pthread_create(). 28 . . . . . . 33 . . . . . . . . . . . . . . . . . . . . 34 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 2.12. Grupos funcionales de rutinas Pthread. y 3.1. Conexión con ID alto. 3.2. Conexión con ID bajo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 3.3. Conexión rechazada. 40 3.4. Establecimiento de conexión modelado con autómata de estados nitos. 3.5. Secuencia de mensajes al inicio de la conexión. 3.6. Secuencia de mensajes al inicio de la conexión modelada con autómata de estados nitos. 3.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 . . . . . . . . . . . . . . . 42 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Secuencia de mensajes de búsqueda de archivos. . . . . . . . . . . . . . . . 43 xvii Índice de guras 3.8. Autómata de estados nitos para la búsqueda de archivos. . . . . . . . . . 3.9. Secuencia de mensajes para el mecanismo de 3.10. Secuencia de mensajes para el mecanismo de callback. . . . . . . . . . . . callback modelada con auto- mata de estados nitos (Cliente A). . . . . . . . . . . . . . . . . . . . . . . 3.11. Secuencia de mensajes para el mecanismo de mata de estados nitos (Servidor). callback callback 44 45 modelada con auto- . . . . . . . . . . . . . . . . . . . . . . 3.12. Secuencia de mensajes para el mecanismo de 44 45 modelada con auto- mata de estados nitos (Cliente B). . . . . . . . . . . . . . . . . . . . . . . keep-alive UDP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . keep-alive UDP. . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.15. Secuencia keep-alive UDP modelada con autómata de estados nitos. . . . 3.16. Handshake inicial de los clientes `eMule'. . . . . . . . . . . . . . . . . . . . 3.17. Handshake inicial de los clientes `eMule' modelado con autómata de esta- 45 3.13. Ciclo de 46 3.14. Secuencia 46 dos nitos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 48 48 3.18. Identicación segura. `A' no tiene la clave pública de `B'. . . . . . . . . . . 49 3.19. Identicación segura. `A' tiene la clave pública de `B'. . . . . . . . . . . . 49 3.20. Identicación segura modelada con autómata de estados nitos. . . . . . . 50 3.21. Solicitud de chero. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 3.22. Solicitud de archivo fallida. Archivo no encontrado. . . . . . . . . . . . . . 51 3.23. Solicitud de chero modelada con autómata de estados nitos. . . . . . . . 51 3.24. Cola de espera para una solicitud de un archivo. . . . . . . . . . . . . . . . 52 3.25. Cola de espera para una solicitud de un archivo modelada con autómata de estados nitos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.26. Descarga de un archivo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.27. Descarga de un archivo modelada con autómata de estados nitos. 3.28. Detalles del mensaje de la parte de un archivo. 53 53 . . . . 54 . . . . . . . . . . . . . . . 54 3.29. Detalles del mensaje de la parte de un archivo modelado con autómata de estados nitos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.30. Intercambio de fragmentos de archivo. . . . . . . . . . . . . . . . . . . . . 55 55 3.31. Intercambio de fragmentos de archivo modelado con autómata de estados nitos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.32. Solicitud de vista de archivos compartidos. . . . . . . . . . . . . . . . . . . 56 3.33. Consulta de archivos y carpetas compartidos. . . . . . . . . . . . . . . . . 3.34. Solicitudes de vista de archivos y carpetas denegadas. . . . . . . . . . . . 57 57 3.35. Vista de archivos y carpetas compartidos modelada con autómata de estados nitos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . hash de fragmento de archivo. . de hash de fragmento de archivo 3.36. Solicitud de 3.37. Solicitud estados nitos. . . . . . . . . . . . . . . . . . 58 58 modelada con autómata de . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.38. Obtención de la previsualización de un archivo. . . . . . . . . . . . . . . . 58 59 3.39. Obtención de la previsualización de un archivo modelada con autómata de estados nitos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.40. Mensaje de re-solicitud de archivo. . . . . . . . . . . . . . . . . . . . . . . 59 60 3.41. Mensaje de re-solicitud de archivo modelado con autómata de estados nitos. 60 xviii Índice de guras 3.42. Estructura principal del programa. . . . . . . . . . . . . . . . . . . . . . . 4.1. Estructura en módulos del programa principal. 4.2. 4.3. 61 . . . . . . . . . . . . . . . 66 Autómata de ejemplo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Autómata de ejemplo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 4.4. Esquema de un objeto de la clase `estado'. . . . . . . . . . . . . . . . . . . 75 4.5. Autómata con un estado. . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 4.6. Objeto `estado' para el estado de la Figura 4.5.. . . . . . . . . . . . . . . . 76 4.7. Autómata con un estado. 76 4.8. Objeto `estado' para el estado de la Figura 4.7. 4.9. Autómata con tres estados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 . . . . . . . . . . . . . . . . . . . . . . . . . . 76 4.10. Objeto `estado' para el estado de la Figura 4.9. . . . . . . . . . . . . . . . 77 . . . . . . . . . . . . . . 79 4.12. Relaciones entre las clases diseñadas. . . . . . . . . . . . . . . . . . . . . . 79 4.13. Diagrama de clases de diseño para la aplicación desarrollada. . . . . . . . 80 5.1. Estadísticas generales de los cheros de prueba. . . . . . . . . . . . . . . . 82 5.2. Estadísticas del uso de protocolos para el chero de pruebas n 1. . . . . . 82 5.3. Estadísticas del uso de protocolos para el chero de pruebas n 2. . . . . . 83 5.4. Estadísticas del uso de protocolos para el chero de pruebas n 3. . . . . . 83 5.5. Estadísticas del uso de protocolos para el chero de pruebas n 4. . . . . . 84 5.6. Autómata correspondiente a Búsqueda de archivos. . . . . . . . . . . . . 84 5.7. Autómata correspondiente a Establecimiento de conexión. . . . . . . . . 84 5.8. Autómata correspondiente a Secuencia de inicio de conexión. . . . . . . . 85 5.9. Autómata correspondiente a Búsqueda de archivos. . . . . . . . . . . . . 4.11. Estructura de un objeto de la clase `datosFlujo'. º º º º 5.10. Autómata correspondiente a Establecimiento de conexión. 85 . . . . . . . . 86 5.11. Autómata correspondiente a Secuencia de inicio de conexión. . . . . . . . 86 5.12. Autómata correspondiente a Búsqueda de archivos. . . . . . . . . . . . . 86 5.13. Autómata correspondiente a Handshake inicial. 86 . . . . . . . . . . . . . . 5.14. Autómata correspondiente a Nueva secuencia de inicio de conexión. . . . 87 5.15. Autómata correspondiente a Ofrecer cheros. . . . . . . . . . . . . . . . 87 5.16. Muestra de una trama `eDonkey' con Wireshark. . . . . . . . . . . . . . . 90 5.17. Salida observada para la Prueba 5. . . . . . . . . . . . . . . . . . . . . . . 92 5.18. Salida observada para la Prueba 6. . . . . . . . . . . . . . . . . . . . . . . 93 5.19. Salida observada para la Prueba 7. . . . . . . . . . . . . . . . . . . . . . . 93 5.20. Tiempos de ejecución de las pruebas realizadas. . . . . . . . . . . . . . . . 95 5.21. Actividad del grafo de llamadas. . . . . . . . . . . . . . . . . . . . . . . . 95 5.22. Mediciones de tiempos para algunos métodos de la aplicación. . . . . . . . 95 6.1. Esquema de las tareas inicialmente planicadas. . . . . . . . . . . . . . . . 98 6.2. Diagrama de Gantt. 99 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.1. Ejemplo de estado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 A.2. Ejemplo de estado tras la llamada a `setMensaje'. . . . . . . . . . . . . . . 109 A.3. Ejemplo de estado con un mensaje. . . . . . . . . . . . . . . . . . . . . . . 109 xix Índice de guras A.4. Ejemplo de estado con un mensaje tras la llamada a `setMensaje'. . . . . . 109 xx Capı́tulo 0 Descripción del problema y especicaciones Descripción del problema En la actual sociedad de la información, existe un gran número de usuarios con acceso a Internet. Gran parte del uso que se hace de Internet, está asociado debido a las redes peer-to-peer, las que, de manera supercial, se pueden denir como redes formadas por una serie de nodos interconectados entre sí, en los que cada uno de ellos puede actuar como cliente y como servidor al mismo tiempo. Actualmente existen un gran número de aplicaciones compatibles con este tipo de redes. Dichas aplicaciones funcionan gracias a un protocolo subyacente, el cual controla el funcionamiento de estas redes. Existen múltiples protocolos P2P a día de hoy; uno de los más conocidos y extendidos es el protocolo `eDonkey'. Dentro del comportamiento habitual de este protocolo, existen una serie de acciones básicas que se pueden clasicar según la naturaleza de la conexión: cliente-cliente o cliente-servidor. Se pretende detectar el mal uso del protocolo con la nalidad de intentar detectar potenciales problemas de seguridad (ataques, vulnerabilidades, etc.). Por ello, se propone el desarrollo de una aplicación capaz de analizar los ujos producidos por este protocolo y clasicarlos en acordes a la especicación o no. En este último caso se dirá que son ujos anómalos y, en consecuencia, requieren un análisis de seguridad. Especicaciones de la aplicación Debe detectar ujos anómalos en el protocolo P2P `eDonkey'. Debe ser exible, es decir, debe tener la capacidad de ser modicada por terceros sin excesiva dicultad. Debe ser extensible respecto a otros protocolos. 1 0. Descripción del problema y especicaciones Debe estar desarrollada en el lenguaje ANSI C++. Debe aceptar, para su análisis, cheros con tramas o bien analizar un protocolo en vivo a través de una interfaz de red. La especicación/denición de los autómatas debe ser sencilla e independiente del programa principal. 2 Capı́tulo 1 Introducción 1.1. Las redes en la actualidad Las redes de comunicaciones constituyen una parte importante de la comunicación en la actual sociedad de la información. Años atrás, estas sólo estaban al alcance de algunos pocos, como organismos ociales y al ámbito militar. Pero la losofía de compartir información, tan de moda en la actualidad, ha hecho que las redes de comunicaciones se expandan (y sigan haciéndolo) a gran velocidad, de modo que permiten estar comunicado con el resto del mundo. Una prueba de ello es la gran cantidad de usuarios con acceso a Internet. En la Figura 1.1 se muestra la cantidad de usuarios con acceso a Internet de los quince países más poblados, como se puede consultar en [2]. La imagen no ofrece demasiada precisión, ya que muestra las cantidades en millones de usuarios pero no indica cuántos habitantes tiene cada uno de los países mostrados ya que, por ejemplo, China está más poblada que Italia. Por ello se muestra en la Figura 1.2 la relación habitantes/usuarios con acceso a Internet. Figura 1.1: Millones de usuarios conectados a Internet (enero de 2009). 3 1. Introducción Figura 1.2: Porcentaje de población que se conecta a Internet en los quince países más poblados (enero 2009). En la Figura 1.2 se puede apreciar mejor la proporción de usuarios con acceso a Internet, en especial en los países más desarrollados, como Reino Unido o Corea del Sur, en los que la mayor parte de la población dispone de dicho acceso. Sin embargo, India es justamente el punto opuesto, incluso siendo el segundo país más poblado del planeta. Internet ofrece a día de hoy una ingente cantidad de usos y servicios, como por ejemplo: FTP, mensajería instantánea, streaming, redes P2P, correo electrónico, tráco HTTP, etc. Esto hace que existan millones de usuarios con acceso a la Red y que los servicios sean cada vez más demandados. El tráco existente en Internet corresponde mayoritariamente a redes P2P, como se explica en [2], como evidencia el estudio realizado por la compañía `iPoque' en 2007 en Alemania (véase la Figura 1.3). Como se puede apreciar, las redes P2P tienen una gran aceptación entre la comunidad de usuarios que conforma Internet, ya que el tráco producido por este tipo de redes es muy superior al resto de tráco en Internet. Ni siquiera el tráco HTTP o de Streaming puede compararse en la actualidad con el generado por las redes P2P. Figura 1.3: Distribución porcentual del tráco de Internet en Alemania en 2007. 4 1. Introducción 1.2. ¾Qué son las redes P2P y por qué son importantes? Existen múltiples deniciones que de las redes P2P. Una de ellas, de acuerdo a [3], es: Las redes peer-to-peer (P2P) son unas redes en las que existe como prin- cipio básico la compartición de recursos entre computadoras. Tales recursos incluyen procesamiento, conocimiento, almacenamiento de datos e información de bases de datos distribuidas. En los últimos años, se ha invertido aproximadamente medio billón de dólares en compañías dedicadas al desarrollo de sistemas P2P. Este interés es debido al éxito de muchas aplicaciones, como, por ejemplo, `Napster' (hoy en día ya desaparecida) o `eMule'. El concepto de compartición de recursos no es totalmente nuevo, ya que los sistemas P2P son una evolución natural en la arquitectura de sistemas. Lo que caracteriza a una red P2P es que la relación es directa entre los equipos que actúan como iguales, ya que los computadores pueden actuar como clientes y servidores al mismo tiempo. El comportamiento de dichas computadoras se determinará dependiendo de los requerimientos del sistema en cada momento. Por ejemplo, un computador `A' envía una solicitud de un chero a un computador `B'. En este momento, el computador `B' estaría actuando de servidor y el `A' sería el cliente. Poco después, es el computador `B' el que envía una solicitud de archivo al computador `A', por lo que, en este caso el comportamiento es justo el contrario, ya que `A' sería el servidor y `B' el cliente. Las redes peer-to-peer permiten a los usuarios hacer uso de toda la información dispo- nible en la red, ayudan a realizar grandes trabajos computacionales que antes no eran posibles y, además, su implementación no tiene un gran coste para pequeñas compañías e incluso, para uso particular. Estas redes cuentan con la ventaja de tener acceso distribuido a determinados recursos. En denitiva, una red P2P tiene grandes benecios en costes y un procesamiento veloz. Existen una serie de características comunes ampliamente aceptadas en relación a los sistemas P2P: Un peer es cada uno de los nodos que forma parte de una red P2P, siendo habi- tualmente un computador que puede actuar tanto de cliente como de servidor. Este comportamiento se determinará por los requerimientos del sistema en un momento concreto. En algunos sistemas P2P, un peer puede actuar como cliente y como servidor al mismo tiempo. Una red P2P consiste en, al menos, dos o más Los peers peers. son capaces de intercambiar recursos directamente entre ellos, como ar- chivos, información, procesamiento, etc. Los servidores dedicados puede que estén o no presentes en un sistema P2P, dependiendo de la naturaleza de las aplicaciones. Sin embargo, el comportamiento de la mayoría de estos servidores se limita a permitir a los peers descubrirse los unos a los otros. Dicho de otra manera, asumen el papel de agentes. 5 1. Introducción Los peers pueden entrar o abandonar un sistema con total libertad. Los peers pueden pertenecer a diferentes usuarios. Lo normal en un sistema P2P es tener millones de usuarios. 1.2.1. Ventajas de un sistema P2P La mayoría de los sistemas P2P tienen las siguientes ventajas: La carga de trabajo se reparte entre todos los peers. Es posible que existan millones de computadores en una red P2P que proporcionen grandes cantidades de datos y procesamiento. Muchos computadores tienen recursos que no se usan. Por ejemplo, en una ocina, los computadores no se usan durante un determinado horario (normalmente por la noche). Un sistema P2P puede utilizar estos computadores con sus recursos correspondientes, para así maximizar el uso. Ciertas empresas podrían ahorrar mucho dinero mediante una buena utilización de las instalaciones que existen, en lo que a sistemas P2P se reere. No se necesita un control centralizado ni un riguroso manejo de una red P2P. La escalabilidad en una red P2P se hace evidente debido a que, si existen nuevos peers, pueden unirse al sistema P2P de una manera muy sencilla. Una red P2P funcionará incluso si algunos de sus peers no funcionan correctamente. De esta manera, se hace más tolerante a fallos que otros sistemas. Los usuarios de una red P2P pueden entrar y salir cuando quieran. Así, dichos usuarios pueden mantener el control de sus recursos. 1.2.2. Inconvenientes de un sistema P2P Aunque los sistemas P2P proporcionan grandes benecios, no son sistemas infalibles. Una red P2P puede no ser la herramienta apropiada para determinadas tareas. A continuación se muestra una serie de desventajas de estos sistemas: Las redes P2P pueden ser utilizadas con nes maliciosos, como pueden ser ataques de denegación de servicio contra un sitio web concreto. Establecer estándares en un sistema P2P es una tarea compleja. Para algunas tareas especícas, la carga de trabajo no se puede compartir entre los peers. Resulta una tarea complicada que los usuarios de un sistema lleguen a obtener benecios económicos de una red P2P. 6 1. Introducción Un peer abandona el sistema de acuerdo a lo que haga su propietario con él. Por eso, no se puede garantizar que un recurso en particular esté disponible siempre, exceptuando algunas redes P2P diseñadas a tal n. Por ejemplo, el propietario puede apagar su computador o borrar un archivo. Por tanto, es difícil predecir el rendimiento total del sistema. También es una tarea complicada prevenir el intercambio ilegal de material con copyright. Los sistemas P2P más populares pueden generar una gran cantidad de tráco en la red. Por eso, por ejemplo, no se suele permitir el uso de este tipo de programas en algunas facultades, ya que el rendimiento de la red descendería en gran medida. 1.2.3. Clientes de redes P2P De acuerdo a [4, 5], uno de los clientes P2P más populares en la actualidad es `eMule'. Ya que las diversas redes P2P de compartición de archivos existentes no son capaces de comunicarse entre sí, es necesario ser cuidadoso con el cliente que se elige. Se puede optar por escoger un cliente el cual disponga de acceso a una red muy grande, o algún cliente que sea capaz de conectarse a varias redes al mismo tiempo. Algunos de los clientes P2P más populares en la actualidad son `Gnutella', `Bittorrent', o `eMule', aunque existen otros muchos clientes más. Es necesario destacar que es el cliente el que se conecta a la red P2P, pero esto no signica que sea el único que pueda hacerlo. En otras palabras y, poniendo de base un ejemplo, existen varios programas cliente que son capaces de conectarse a la red `Gnutella'; estos pueden ser, por ejemplo, `Morpheus', `BearShare', `LimeWire', etc. Aquí es donde juega un papel fundamental el cliente `eMule'. Dicho cliente no es más que una interfaz que hace uso de la red P2P `eDonkey'. Al igual que otros clientes, es capaz de buscar archivos, descargárselos y poder compartirlos con los demás miembros de dicha red. Asimismo, permite al usuario ser un miembro más de la extensa red P2P de la cual `eMule' hace uso. Como se puede ver en la Figura 1.4, `eMule' proporciona una interfaz en la que sus funciones principales se aprecian con facilidad. Es por ello que, en la actualidad, sea uno de los clientes más aceptados y utilizados por los usuarios de la red `eDonkey'. Aunque otros protocolos han ido ganando terreno con el paso de los años, es innegable que el protocolo `eDonkey' sigue siendo ampliamente utilizado. Por tanto, dada su gran extensión, sería interesante disponer de un detector de anomalías que fuera capaz de mostrar cualquier comportamiento extraño que pudiera producirse en el uso de protocolos P2P. De esta manera, se podrían evaluar dichos comportamientos y tomar decisiones acerca de la vulnerabilidad de un determinado computador ante dichos comportamientos. 7 1. Introducción Figura 1.4: Interfaz del cliente `eMule'. Aquí es donde juega un importante papel la aplicación a desarrollar. Esta aplicación se centra en el protocolo `eDonkey' que, como se ha detallado, es uno de los más utilizados en la actualidad. Dicho programa debe ser capaz de tomar como entrada ujos de información en Internet, evaluar si pertenecen al protocolo `eDonkey' o no, y juzgar su buen funcionamiento, tomando decisiones de si está funcionando con normalidad o no. El objetivo es prevenir a las redes peer-to-peer de usos no autorizados. 1.3. El protocolo `eDonkey' De acuerdo a [6, 7], el protocolo de compartición de cheros `eDonkey' es uno de los protocolos para redes P2P más conocidos. En un principio se usó para el cliente llamado `eDonkey2000' y, además, por algunos otros clientes de código abierto (open source ) como, por ejemplo, `mldonkey'. En algunos países, el protocolo `eDonkey' es el protocolo P2P de compartición de archivos más popular entre todos los usuarios. Muestra de ello son los resultados del estudio realizado en Alemania en 2007 por la compañía `iPoque', que se puede consultar en [2], la cual obtuvo los resultados mostrados en la Figura 1.5 acerca del porcentaje de uso de protocolos peer-to-peer. Básicamente, la red `eDonkey' es una red de compartición de archivos peer-to-peer que usa aplicaciones cliente ejecutándose en los sistemas nales que están conectados a una red distribuida o a servidores dedicados. El protocolo `eDonkey' no está completamente descentralizado, ya que usa servidores que ofrecen mecanismos para la comunicación. 8 1. Introducción Figura 1.5: Porcentaje de uso de protocolos P2P en Alemania en 2007 (véase [2]). A diferencia de otros protocolos P2P, la red `eDonkey' tiene una estructura basada en el paradigma cliente/servidor (véase Capítulo 2). Los servidores no comparten ningún archivo. El papel que juegan es manejar la distribución de la ubicación de la información y operar con unos diccionarios centrales, que almacenan la información acerca de los cheros que se comparten y sus respectivas localizaciones en los clientes. En la red `eDonkey' los clientes son los únicos nodos que comparten recursos. Sus archivos se indexan mediante los servidores. Si un cliente quiere descargarse un archivo o parte de él, primero se debe conectar vía TCP a un servidor o enviar una petición de búsqueda vía UDP a uno o más servidores para obtener la información necesaria acerca de qué clientes ofrecen el archivo que se solicita. La red `eDonkey' usa un hash MD4 de 16 bytes para identicar unívocamente a los ar- hashing no es infalible (puede hash implica que, en una búsque- chivos, independientemente de su nombre. El algoritmo de haber colisiones), pero ofrece una alta abilidad. Este da, son necesarios un par de pasos previos. Primero, se le envía al servidor una orden de búsqueda completa de texto con el nombre del archivo. La correspondiente respuesta incluye aquellos archivos que tienen un nombre asociado el cual coincide completamente con el texto que se mandó buscar. En segundo lugar, el cliente solicita las fuentes al servidor para un determinado hash de un archivo. Finalmente, el cliente se conecta a las fuentes indicadas para solicitar la transferencia del archivo. La transferencia de dicho archivo tiene lugar directamente entre los dos clientes participantes, sin involucrar a los servidores, para así minimizar el coste de la operación. Un cliente que use el protocolo `eDonkey' es capaz de transferirse un único archivo de múltiples fuentes, lo cual provoca que se mejore la velocidad de transferencia y se reduzca el riesgo de quedarse con archivos sin transferirse del todo. Los archivos se transeren en trozos de 9,28 MB. Los archivos que se transeren parcialmente también son compartidos por el cliente y pueden transferirse a otros usuarios. El hash MD4 permite identicar si un determinado chero es el que se está solicitando o no. Como en el protocolo `eDonkey' se comparten los trozos de un archivo por separado, se pueden llegar a identicar aquellos que están corruptos. Todas estas características hacen que el uso de este protocolo sea ideal para transferir archivos grandes, como por ejemplo, archivos de vídeo. 9 1. Introducción A continuación, se muestra una descripción general del funcionamiento del protocolo `eDonkey'. 1.3.1. Descripción general del protocolo `eDonkey' Tal y como se dene en [9], la red `eDonkey' está formada por varios cientos de servidores y millones de clientes. Cada cliente está precongurado con una lista de servidores y una lista de archivos compartidos en su sistema de archivos local y usa una única conexión a uno de los servidores mencionados para obtener información acerca del archivo deseado y otros clientes disponibles. Dicho cliente `eMule' también puede utilizar varios cientos de conexiones TCP a otros clientes los cuales suelen subir y bajar determinados archivos. Cada uno de ellos mantiene una cola de subida para cada uno de los archivos que comparte. Así, los clientes que deseen descargar algún tipo de archivo se unen a la cola y se colocan al nal de esta, y van avanzando gradualmente hasta que alcanzan la primera posición, que es cuando comienzan a descargar el archivo. Un cliente puede descargar el mismo archivo de varios clientes `eMule', obteniendo así diferentes fragmentos de cada uno de ellos, y también puede subir un trozo de un archivo que aún no se ha terminado de descargar. Finalmente, `eMule' amplía las capacidades de `eDonkey' y permite a los clientes intercambiar información acerca de los servidores, de otros clientes y de archivos. Nótese que ambos, cliente y servidor, se comunican mediante TCP. El servidor emplea una base de datos interna en la cual almacena información acerca de clientes y archivos. Un servidor `eMule' no almacena ningún archivo, sino que actúa como una ocina de interconexión de clientes `eMule'. Una función adicional del servidor, la cual se está volviendo obsoleta, es hacer un puente entre dos clientes que se conectan a través de un cortafuegos y no son capaces de aceptar conexiones entrantes. La funcionalidad de este puente incrementa considerablemente la carga en el servidor. `eMule' usa UDP para mejorar las capacidades del cliente frente al servidor y otros clientes. La habilidad de los clientes para enviar y recibir mensajes UDP no siempre está disponible, ya que no es obligatoria para que dichos clientes funcionen correctamente. Por ello, uno de estos clientes funcionaría perfectamente aunque un cortafuegos le impida enviar y recibir estos mensajes UDP. A continuación se mostrará una descripción detallada del proceso seguido en las conexiones realizadas por el protocolo `eDonkey' entre cliente-servidor y entre cliente-cliente. Conexión cliente-servidor Al inicio, el cliente se conecta a un servidor `eMule' usando una conexión TCP. El servidor proporciona al cliente un ID de cliente que es válido sólo durante el tiempo de vida de la conexión cliente-servidor. Siguiendo el establecimiento de la conexión, el cliente envía al servidor su lista de archivos compartidos. El servidor almacena la lista en su base de datos interna, la cual normalmente contiene cientos de miles de archivos disponibles en sus clientes activos. El cliente `eMule' también envía su lista de descarga que contiene los archivos que desea descargar en ese momento. La red mostrada en la Figura 1.6 esquematiza la estructura de red que sigue `eMule', 10 1. Introducción la cual no sigue la topología de una red convencional, sino que se trata de una red lógica situada por encima de la red física (overlay network ). Los nodos están conectados entre sí por enlaces lógicos, cada uno de los cuales está implementado por un camino a través de enlaces físicos en la red subyacente. Cada cierto tiempo, el cliente envía solicitudes de búsqueda de archivos que son respondidas mediante una búsqueda de resultados. Una transacción de búsqueda normalmente va seguida de una petición de fuentes para un archivo especíco. Esta petición es contestada mediante una lista de fuentes (IP y puerto) de las que el solicitante puede descargar el archivo. Después de establecer la conexión, el servidor `eMule' envía al cliente una lista de otros clientes que tienen los archivos que desea descargar el cliente que se conecta (dichos clientes son llamados `fuentes'). Desde este punto, el cliente `eMule' comienza a establecer conexiones con otros clientes. Nótese que la conexión TCP cliente-servidor se mantiene abierta durante toda la sesión del cliente. Después del intercambio inicial (handshake ), las transacciones son provocadas principalmente por la actividad de los usuarios. El protocolo UDP se usa para comunicaciones con otros servidores que no son el servidor al cual está conectado el cliente en ese momento. El propósito de los mensajes UDP es la mejora de la búsqueda de archivos, la mejora de la búsqueda de fuentes y, nalmente, el envío de mensajes keep-alive (asegurarse de que todos los servidores `eMule' de la lista de servidores del cliente son válidos). Figura 1.6: Estructura de la red `eMule' (protocolo `eDonkey'). 11 1. Introducción Conexión cliente-cliente Un cliente `eMule' se conecta a otro (una fuente) con la nalidad de descargar un archivo, el cual está dividido en partes fragmentadas. Dicho cliente puede descargarse el mismo archivo de varios clientes, obteniendo así distintos fragmentos de cada uno. Cuando dos clientes se conectan, intercambian información de capacidad y negocian el comienzo de una descarga (o subida, depende de la perspectiva). Cada cliente tiene una cola de subida en la cual mantiene una lista de clientes que están esperando para descargar determinados archivos. Cuando esta cola está vacía, una petición de descarga dará como resultado más probable un comienzo de descarga inmediato (a menos que, por ejemplo, el solicitante esté prohibido). Pero cuando la cola de descarga no está vacía, la solicitud de descarga dará como resultado la adición del cliente solicitante a la cola. Sólo se da servicio a unos pocos clientes en un momento dado, proporcionando para cada uno de ellos un ancho de banda mínimo de 2.4 KB/seg. Uno de los clientes que esté descargando un archivo puede ser reemplazado por otro cliente que estaba esperando y que tenga un mayor ranking en la cola que él. Cuando un cliente que desea descargar algún chero alcanza la primera posición de la cola, el cliente que posee dicho chero inicia una conexión con él, con el n de enviarle las partes del archivo que necesita. Un cliente `eMule' puede estar al mismo tiempo esperando en las colas de otros clientes para descargar las mismas partes del archivo de cada uno de ellos. Cuando el cliente solicitante termina de descargarse las partes correspondientes (de uno de los otros clientes), no le notica al resto que le eliminen de sus colas; lo que hace es, simplemente, rechazar que le envíen el archivo cuando alcance la primera posición en las otras colas. `eMule' emplea un sistema de crédito con el n de promover las subidas de archivos. Para evitar la suplantación de identidad, `eMule' asegura el sistema de crédito usando criptografía de clave pública RSA. Las conexiones de los clientes pueden usar un conjunto de mensajes no denidos por el protocolo `eDonkey'. Dichos mensajes son una ampliación del protocolo. El protocolo extendido se usa para la implementación del sistema de crédito, para intercambio general de información (tales como actualización de la lista de servidores y fuentes) y para mejorar el rendimiento mediante el envío y la recepción de fragmentos de archivo comprimidos. La conexión del cliente `eMule' utiliza UDP de una manera limitada para, periódicamente, comprobar el estado del cliente en la cola de subida de sus clientes peer mientras está esperando para descargarse un archivo. 1.3.2. ID del cliente El ID del cliente es un identicador de 4 bytes que es proporcionado por el servidor cuando realizan un intercambio de tramas con el objetivo de ponerse de acuerdo (conocido como handshake ). Este ID es válido sólo durante el tiempo de vida de una conexión TCP cliente-servidor aunque, en el caso de que el cliente tenga un ID alto, todos los servidores le asignarán el mismo ID, a no ser que cambie su IP. Los ID de los clientes están divididos en ID bajos e ID altos. El servidor `eMule' típicamente asignará a un 12 1. Introducción cliente un ID bajo cuando este no pueda aceptar conexiones entrantes. Tener un ID bajo restringe el uso que hace el cliente de la red `eMule' y podría resultar en que el servidor rechazara la conexión del cliente. Un ID alto se calcula en base a la dirección IP de un cliente, tal y como se describe a continuación. Un ID alto se le da a los clientes que permiten a otros clientes conectarse libremente al puerto TCP de `eMule' de su host. Un cliente con un ID alto no tiene restricciones en el uso de la red `eMule'. Cuando el servidor no puede establecer una conexión TCP con el puerto del cliente de `eMule', entonces a este cliente se le asigna un ID bajo, lo que suele ocurrir principalmente con los clientes que tienen un cortafuegos que restringe las conexiones entrantes. Un cliente también puede recibir un ID bajo en los siguientes casos: Cuando el cliente está conectado a través de NAT o un servidor proxy. Cuando el servidor al que se conecta el cliente está muy ocupado (provocando así que el contador de reconexión con el servidor expire). Los ID altos se calculan de la siguiente manera: si se asume que la dirección IP del host es X.Y.Z.W, entonces su ID será X + 2^8 * Y + 2^16 * Z + 2^24 * W (representación big endian). Un ID bajo es siempre menor que la cifra 16777216 (0x1000000). Un cliente con un ID bajo no tiene IP pública a la cual se puedan conectar otros clientes, por lo que todas las conexiones se deben realizar a través del servidor `eMule', es decir, el servidor indica al cliente con ID bajo que realice una conexión saliente con el otro cliente que desea conectar con él. Esto aumenta la carga computacional del servidor y provoca que no suelan aceptar clientes con un ID bajo. Además, esto signica que un cliente con un ID bajo no puede conectarse con otro cliente que también tenga ID bajo y que esté en otro servidor. Para que en `eMule' se soportaran los clientes con ID bajo, se introdujo un mecanismo de callback. Mediante este mecanismo, un cliente con ID alto solicita, a través del servidor `eMule', que un cliente con ID bajo se conecte a él, con el n de intercambiar determinados archivos, ya un cliente con ID bajo no admite conexiones entrantes (véase Apartado 3.1.1). 1.3.3. ID del usuario `eMule' soporta un sistema de crédito con el n de animar a los usuarios a compartir archivos. Cuantos más archivos transera un usuario a otros usuarios, más créditos recibirá y más rápido ascenderá en las colas de espera de otros clientes. º º El ID de usuario es un GUID de 16 bytes (128 bits) que se crea concatenando números aleatorios. El 6 y el 15 no son aleatorios; sus valores son 14 y 111 respectivamente. Mientras que un ID de cliente es válido sólo durante una sesión de un cliente con un servidor especíco, un ID de usuario (también llamado hash de usuario) es único y se usa para identicar a un cliente a través de diferentes sesiones (el ID de usuario identica la estación de trabajo). Este ID juega un papel importante en el sistema de crédito; esta característica proporciona a los hackers una motivación para suplantar la identidad de otros usuarios con el n de adquirir sus privilegios, obtenidos gracias a sus créditos. 13 1. Introducción `eMule' soporta un esquema de cifrado que se diseñó para prevenir fraudes y suplantaciones de identidad de otros usuarios. La implementación es un simple intercambio de reto-respuesta que tiene un cifrado RSA de clave pública/privada. Cuando un cliente envía un chero a su peer, el cliente que descarga el archivo actualiza su sistema de crédito de acuerdo a la cantidad de datos transmitidos. Nótese que el sistema de crédito no es global; el crédito de una transferencia lo mantiene localmente el cliente que descarga, y se tendrá en cuenta únicamente cuando el cliente que envía el archivo (el que gana el crédito) realiza una petición de descarga a ese cliente especíco. El crédito se calcula como el mínimo entre: 1. 2. totalsubido∗2 totalbajado . Cuando la descarga es cero, a la expresión se le asigna el valor 10. √ totalsubido + 2. Cuando el total de subida sea menor que 1 MB, la expresión toma el valor 1. La cantidad de subida o bajada se calcula en megabytes. En cualquier caso, el crédito no puede exceder de 10 ni ser menor que 1. 1.3.4. ID del archivo Los ID de los archivos se usan tanto para identicar unívocamente archivos en la red, como para detectar y recuperar archivos corruptos. Nótese que `eDonkey' no utiliza el nombre del archivo para identicarlo unívocamente y catalogarlo; un archivo se identica con un ID único creado mediante el hashing de su contenido. Los ID se utilizan principalmente por dos motivos: Generar un ID único para el archivo. Detección y recuperación de partes corruptas. Los archivos están identicados unívocamente por un hash GUID de 128 bits, calculado por el cliente y basado en el contenido del chero. Este GUID se calcula aplicando el algoritmo MD4 a los datos de los archivos. Cuando se calcula el ID del archivo, dicho archivo se divide en partes, cada una de 9.28 MB. Se calcula un GUID por separado de cada parte y luego todos los hash se combinan para obtener un ID de archivo único. Cuando un cliente que está descargando algo completa la descarga de una parte del archivo, calcula el ha enviado su hash peer. de esta parte y lo compara con el hash de esa parte que le Si la parte está corrupta, entonces el cliente intentará recuperarla sustituyendo bits gradualmente (180 KB) hasta que los El hash hash sean los mismos. principal (raíz) se calcula con cada parte del chero, usando el algoritmo SHA- 1, basado en bloques de 180 KB de tamaño. Proporciona un nivel mayor de abilidad y recuperación de fallos. 1.3.5. Límites blandos y duros La conguración del servidor incluye dos tipos de límites en el número de usuarios activos, los llamados límites blandos y límites duros . El límite duro es mayor o igual al 14 1. Introducción límite blando. Cuando el número de usuarios activos alcanza el límite blando, el servidor deja de aceptar clientes nuevos si tienen un ID bajo. Cuando la cuenta de usuarios alcanza el límite duro, entonces el servidor está completo y no acepta la conexión de ningún cliente más. 1.3.6. ¾Cómo selecciona `eMule' qué parte de archivo descargar? `eMule' selecciona selectivamente el orden en el que se descargan las partes con el objetivo de maximizar la tasa de transferencia global y los archivos compartidos. Cada archivo está dividido en partes de 9.28 MB y cada parte está dividida en bloques de 180 KB. El orden en el que se descargan las partes lo determina el cliente que descarga, el cual envía mensajes de solicitudes de partes concretas del archivo. Dicho cliente puede descargar una única parte de cada fuente en un momento determinado, y todos los bloques que son solicitados de la misma fuente residen en la misma parte. La prioridad (o rating) de descarga de las partes sigue los siguientes principios (en el orden en que aparecen): 1. La frecuencia de los trozos (disponibilidad), ya que los trozos más raros se descargan lo más rápidamente posible para ser una nueva fuente disponible. 2. Las partes que se usan para la previsualización (primer y último trozo), comprobación de un chero (p. ej., mp3, película). 3. Solicitud de estado (con una descarga en proceso), se intenta solicitar a cada fuente un trozo diferente. Así se extienden las solicitudes entre todas las fuentes. 4. Completitud (el más inminente en completarse), los trozos recuperados parcialmente deberían completarse antes de comenzar a descargar uno nuevo. El criterio de frecuencia dene tres zonas: común, raro y muy raro. Dentro de cada zona, el criterio tiene un peso especíco, usado para calcular los Las partes con menos de rating 0-9999 rating ratings de las partes. se descargan primero. La siguiente lista especica los rangos de los archivos, de acuerdo a los principios denidos más arriba: partes muy raras no solicitadas o solicitadas. 10000-19999 previsualizaciones de partes y partes raras no solicitadas. 20000-29999 la mayoría de las partes comunes no solicitadas y completas. 30000-39999 previsualizaciones de partes y partes raras solicitadas. 40000-49999 partes comunes no completadas y solicitadas. Este algoritmo normalmente selecciona primero las partes más raras. Sin embargo, las partes parcialmente completadas que están cerca de completarse pueden ser seleccionadas preferentemente también. Para las partes comunes, las descargas se extienden entre fuentes diferentes. 15 1. Introducción 1.3.7. Características generales de la codicación de mensajes del protocolo `eDonkey' Todos los mensajes se codican como little-endian y no en big-endian, aunque este último sea el orden convencional de bytes en redes. Esto se puede explicar sencillamente por el hecho de que los clientes y/o servidores son aplicaciones basadas en Windows y corriendo en procesadores Intel. Microsoft Todos los mensajes tienen, al menos, 6 bytes de cabecera. Algunos tendrán bytes adicionales conteniendo cierta información, dependiendo del tipo de mensaje que contienen. La cabecera sigue la siguiente estructura (véase Figura 1.7): Protocolo: Un único byte indicando el ID del protocolo, que es 0xE3 para `eDonkey' y 0xC5 para `eMule'. Tamaño: cuatro bytes indicando el tamaño del mensaje, sin incluir la cabecera. Por ejemplo, en caso de que el mensaje no incluya carga útil (payload ) entonces el tamaño será cero. Tipo: Un byte indicando el tipo. Un único mensaje con un ID. 1.4. Justicación del proyecto En los apartados anteriores se ha puesto de maniesto que las redes P2P son ampliamente utilizadas en la actualidad, ya que poseen ciertas propiedades que una red convencional no tiene. También se ha hecho mención al protocolo para redes peer-to-peer `eDonkey', uno de los más ampliamente utilizados en este tipo de redes, así como sus características principales y su funcionamiento general. Resulta evidente que garantizar la seguridad en las redes de comunicación es uno de los puntos más importantes que las conciernen. Por ello, es necesario aportar mecanismos de seguridad tales como contraseñas, cortafuegos o control de los registros de acceso a las mismas ya que, sin estas medidas, gran cantidad de información se podría ver comprometida. Figura 1.7: Estructura de una trama del protocolo `eDonkey'. Una de las herramientas existentes en la actualidad que forman parte de la seguridad en redes de comunicación son los llamados Sistemas de Detección de Intrusiones (IDS, Intrusion Detection Systems ), como se puede consultar en [8]. Dichos sistemas se utilizan para detectar accesos no autorizados a una red o a un computador en particular. Los IDS de red incorporan mecanismos para analizar el tráco de la red o de un sistema en concreto y alertar cuando se produce algún tipo de comportamiento extraño. Una de las categorías en las que se pueden dividir los IDS de acuerdo a su modelo de detección es aquella en la que se detecta un comportamiento anómalo dentro del 16 1. Introducción tráco analizado (detección de anomalías). Para ello, este tipo de IDS obtiene estadísticas sobre el tráco típico en la red, se detectan cambios en los patrones de utilización o comportamiento del sistema y se utilizan modelos estadísticos y se buscan desviaciones estadísticas signicantes. Sería, por tanto, una herramienta útil un IDS que sea capaz de analizar tráco P2P y que fuera del tipo de IDS que alerten de alguna clase de anomalía cuando sea detectada. De esta manera, se está alertando al usuario cuando se detecta en dicho tráco un comportamiento no habitual. El objetivo de este proyecto es el desarrollo de una aplicación que haga las funciones de un IDS capaz de detectar anomalías en tráco peer-to-peer y mostrar resultados acerca del tráco no reconocido. Dado el amplio uso del protocolo `eDonkey' en la actualidad, se ha decidido centrar el IDS en dicho protocolo. Para implementar los mecanismos de detección de anomalías, se ha optado por el uso de técnicas basadas en autómatas de estados nitos, que se describen en el Capítulo 2. La memoria seguirá la siguiente estructura: Capítulo 2: Se describirán los fundamentos tecnológicos necesarios para conocer cómo funcionan los autómatas de estados nitos, ya que son utilizados en el modelado del protocolo `eDonkey'. También se explicará en qué consiste el paradigma clienteservidor, puesto que es este paradigma el utilizado en el protocolo mencionado. Por último, se detallará cómo realizar el modelado de protocolos con autómatas de estados nitos y una serie de herramientas y utilidades adicionales que serán prácticas de cara a la elaboración de la aplicación. Capítulo 3: En este capítulo se describirá la estructura general y las funcionalidades que ha de tener la aplicación a desarrollar para poder detectar anomalías en un protocolo P2P. Asimismo, se mostrará el análisis del funcionamiento del protocolo `eDonkey' y se realizará su modelado con autómatas de estados nitos, puesto que la aplicación necesitará esta información para poder funcionar correctamente. Capítulo 4: Se describirá la estructura de la aplicación con un nivel de detalle mayor, para poder comprender su funcionamiento. Se desglosará dicha estructura en módulos y se explicará la misión de cada uno de ellos, así como el funcionamiento global de la aplicación mediante dichos módulos. Se detallará también la jerarquía de clases utilizadas, que han hecho posible la elaboración de los módulos ya mencionados. Capítulo 5: Aquí se realizará la evaluación de la aplicación en dos bloques. El primero de ellos será la comprobación del buen funcionamiento de la aplicación mediante cheros con trazas de tráco, los cuales han sido adquiridos en diferentes escenarios pertenecientes al protocolo `eDonkey'. El segundo bloque verica la eciencia de la aplicación, mediante diferentes mediciones de tiempos y análisis de los cuellos de botella de la aplicación. Capítulo 6: Se mostrará la planicación inicial que se realizó al inicio del proyecto y el desglose de tareas a llevar a cabo. También se mostrará la evaluación de costes 17 1. Introducción asociados al desarrollo de la aplicación. Capítulo 7: Por último, se mostrarán una serie de conclusiones y logros nales, a los cuales se ha llegado durante el desarrollo y estudio de la aplicación. 18 Capı́tulo 2 Fundamentos tecnológicos Tal y como se ha comentado en el Capítulo 1, en este proyecto se aborda la implementación de un sistema de detección de intrusiones (IDS) diseñado para la detección de anomalías en protocolos P2P y, más concretamente, para el protocolo `eDonkey'. Aunque existen numerosas técnicas disponibles para este tipo de análisis, se ha optado por la utilización de autómatas de estados nitos con el n de explorar sus posibilidades en este campo. Para realizar esta tarea, es necesario conocer ciertos fundamentos de teoría de autómatas de estados nitos y también del paradigma cliente-servidor, ya que éste es intrínseco al protocolo que se va a estudiar y a todos los protocolos P2P en general. También se incluye una sección que ayuda a entender cómo se puede realizar un modelado del comportamiento del protocolo mediante autómatas de estados nitos. Por último, se muestra una sección de herramientas y utilidades, en la cual se exponen las bibliotecas más relevantes, de las cuales hará uso la aplicación, y otros programas útiles. 2.1. Teoría de autómatas de estados nitos El diagrama de transición de un autómata de estados nitos es un grafo en el que los nodos representan los distintos estados y los arcos las transiciones entre los estados. Un autómata está formado por uno o más estados. Cada arco va etiquetado con un símbolo asociado a dicha transición. Para facilitar la visualización del diagrama de transición, el estado inicial y los nales vienen señalados de forma especial (por ejemplo, con un ángulo el estado inicial y con un doble círculo los nales). En cada paso, el autómata lee un símbolo de entrada y, según el estado en que se encuentre, cambia de estado y pasa a leer el siguiente símbolo. Así sucesivamente hasta que termine de leer todos los símbolos de entrada. Si en ese momento la máquina alcanza un estado nal, se dice que el autómata acepta la secuencia de símbolos de entrada. Si no está en un estado nal, la rechaza. Para claricarlo, en la Figura 2.1 se muestra un ejemplo de autómata para crear frases sencillas. Los estados son los círculos y las transiciones son las echas que los unen. Las 19 2. Fundamentos tecnológicos transiciones están nombradas con el valor que debe recibir el autómata para transitar de un estado a otro. Es decir: Artículo: El, la, los, las, un, una, unos, unas. Nombre: Cualquier nombre común. Verbo: Cualquier verbo. Adjetivo: Cualquier adjetivo. Si, por ejemplo, se recibe la frase el coche es azul , este autómata la aceptaría, ya que, el es un artículo, por lo que transitaría de q0 a q1 (q0 está marcado como estado inicial); coche es un nombre común, por lo que transitaría de así que se transitaría de de q3 a q4 , q2 a q3 ; y, por último, azul q1 a q2 ; es es un verbo, es un adjetivo, por lo que transitaría que es un estado nal (marcado con un círculo doble), concluyéndose que el autómata acepta la frase. Una palabra es cada uno de los términos de la frase que puede hacer transitar a un autómata de un estado a otro. Se pueden elaborar autómatas más complejos. Se muestra uno en la Figura 2.2, con un bucle. Este aceptaría, por ejemplo, la frase: el coche es azul y está rayado , ya que, en q4 aceptaría la conjunción y y transitaría de q4 a q2 ; y está rayado son un verbo y un adjetivo, que le harían llegar al estado nal (puede haber más de uno). Como se puede apreciar, los autómatas son útiles para modelar un determinado comportamiento. Por ello, se pueden utilizar como herramienta para modelar protocolos, ya que se puede representar este comportamiento. Figura 2.1: Autómata de ejemplo. Figura 2.2: Autómata de ejemplo. 20 2. Fundamentos tecnológicos 2.1.1. Autómatas de estados nitos determinísticos Como se explica en [10], un autómata de estados nitos determinístico (AFD) es aquel cuyo estado nal está determinado unívocamente por el estado inicial y los símbolos observados por el autómata. Está formado por una quíntupla M = (Q, A, δ, q0 , F ) en la que: Q es un conjunto nito llamado conjunto de estados. A es un alfabeto (conjunto de símbolos observables) llamado alfabeto de entrada. δ es una aplicación δ(Q) : Q × A → Q q0 llamada función de transición: es un elemento de Q, llamado estado inicial. F es un subconjunto de Q, llamado conjunto de estados nales. Un ejemplo de autómata nito determinista es el mostrado en la Figura 2.3, en el que los elementos de la quíntupla serían los siguientes: Q = {q0 , q1 , q2 } A = {a, b} Función de transición: δ(q0 , a) = q0 δ(q0 , b) = q1 δ(q1 , a) = q2 δ(q1 , b) = q1 δ(q2 , a) = q2 δ(q2 , b) = q2 Estado inicial = q0 F = {q0 , q1 } 2.1.2. Autómatas de estados nitos no determinísticos Un autómata nito no determinístico (AFND) es aquel en el que existe al menos un estado en el que es posible más de una transición para el mísmo símbolo. Dicho de otra forma, un AFND es aquel en el que, dada una secuencia de símbolos observables, el estado nal y/o la secuencia de estados seguidos por el autómata no es predecible (unívoca). Queda denido por una quíntupla M = (Q, A, δ, q0 , F ) en que: Q es un conjunto nito llamado conjunto de estados. A es un alfabeto (conjunto de símbolos observables) llamado alfabeto de entrada. 21 2. Fundamentos tecnológicos Figura 2.3: Ejemplo de AFD. δ es una aplicación llamada δ(Q) : Q × A → ℘(Q × A) q0 función de transición: es un elemento de Q, llamado estado inicial. Puede haber varios estados iniciales. F es un subconjunto de Q, llamado conjunto de estados nales. Una secuencia de observaciones se dice aceptada por un AFND si, siguiendo en cada momento alguna de las opciones posibles, se llega a un estado nal. En la Figura 2.4 se muestra un ejemplo de AFND. Por ejemplo, en q0 se puede recibir el símbolo `a' y llevar a varios estados diferentes según la función de transición δ. Los elementos de la quíntupla serían los siguientes: Q = {q0 , q1 , q2 } A = {a, b, c} Función de transición: δ(q0 , a) = {q0 , q1 , q2 } δ(q0 , b) = {q1 , q2 } δ(q0 , c) = {q2 } δ(q1 , a) = Ø δ(q1 , b) = {q1 , q2 } δ(q1 , c) = {q2 } δ(q2 , a) = Ø δ(q2 , b) = Ø δ(q2 , c) = {q2 } Estado inicial = q0 F = {q0 , q1 , q2 } 22 2. Fundamentos tecnológicos Figura 2.4: Ejemplo de AFND. 2.2. Paradigma cliente-servidor La comunicación entre cliente y servidor se puede realizar con el protocolo TCP o con UDP, mediante el establecimiento de una conexión. Mediante una conexión, dos entidades se ponen de acuerdo para realizar un determinado intercambio de datos, como se verá más adelante. Es necesario destacar que este concepto sólo es aplicable al protocolo TCP, ya que UDP es no orientado a conexión y, por tanto, no se necesita una conexión previa. Sin embargo, de aquí en adelante, en el contexto UDP se entenderá que dos entidades intercambiarán información dentro de una conexión. Para poder analizar los mensajes intercambiados en el protocolo, es necesario extraerlos primero, de modo que, la forma de observar estos mensajes P2P entre dos peers, consiste en extraer los datos de la conexión mediante la identicación de las duplas IP/puerto. El peer que inicie la conexión será el cliente y el que recibe esta conexión entrante será el servidor. Este es el procedimiento utilizado en este proyecto para extraer los mensajes. Una comunicación TCP o UDP está determinada por los siguientes elementos: IP origen. IP destino. Puerto origen. Puerto destino. Dentro de una comunicación TCP o UDP existen ujos de información, producto del diálogo entre dos peers. Un ujo es el intercambio de información que realizan dos entidades, dentro de una conexión. Nótese que dentro de una misma conexión pueden aparecer varios ujos diferentes, debido a los mensajes intercambiados entre los dos peers. Para claricar estos conceptos, supóngase la situación de la Figura 2.5. En ella se muestra una supuesta conexión entre dos computadores. Para cada uno de ellos, se muestra la IP y el puerto. 23 2. Fundamentos tecnológicos Figura 2.5: Ejemplo de conexión entre dos computadores cualesquiera. Supóngase ahora que los computadores mostrados en la Figura 2.5 son un cliente y un servidor en una red P2P, que intercambian cierta información. Considérese que la conexión entre los dos computadores permanece abierta durante un tiempo prolongado. Durante este tiempo, el cliente y el servidor pueden intercambiar, por ejemplo, la información correspondiente a un establecimiento de conexión. Dicho establecimiento de conexión se correspondería con un ujo de información. De la misma manera, durante esta conexión, posteriormente puede haber un intercambio de información correspondiente a una búsqueda de archivos, que se correspondería con otro ujo. Por tanto, durante la conexión, ha habido dos ujos de información. Dada la naturaleza P2P del protocolo `eDonkey', es obvio que hace uso del modelo cliente-servidor. Un servidor es una aplicación que permite el acceso remoto a ciertos recursos software o hardware que existen en un host determinado, como se explica en [11]. Una aplicación servidora se caracteriza por encontrarse inicialmente en un estado latente de escucha sin realizar ninguna función, hasta que recibe una solicitud remota para desarrollar un servicio ofertado por parte de un cliente. Un cliente es una aplicación a través de la cual un usuario contacta con un servidor con el n de llevar a cabo el desarrollo de un servicio concreto que se oferta. Es a través de la consideración del estado de escucha de la parte servidora cómo el paradigma cliente-servidor permite resolver de forma sencilla el problema conocido como rendez-vous, el cual hace referencia a la sincronización a priori necesaria en la inicialización de dos aplicaciones de usuario para hacer posible la comunicación entre ellas. Un servicio que sigue el modelo cliente-servidor se desarrolla en los siguientes pasos: Inicialmente debe ejecutarse la aplicación servidora, pasando esta a modo de escucha y quedando a la espera de recibir solicitudes de servicio. Es lo que se conoce como puesta en marcha pasiva del servicio. La ejecución de la aplicación cliente dará lugar al envío de una solicitud de servicio hacia el servidor. Esto supone una puesta en marcha activa del servicio. El servidor responderá a dicha solicitud de acuerdo con la aplicación desarrollada, llevándose a cabo el intercambio de información necesario para hacer efectivo el servicio. Tras el desarrollo de dicho servicio, el servidor volverá al estado de escucha a la espera de nuevas solicitudes. Por otro lado, el cliente nalizará su ejecución. 24 2. Fundamentos tecnológicos Características del cliente: Los clientes comparten una serie de características, las cuales son: Son invocados por el usuario. Inician el contacto con el servidor. Pueden comunicarse con: Varios servidores alternativamente. Varios servidores simultáneamente. El mismo servidor concurrentemente. Características del servidor: Los servidores también tienen una serie de propiedades comunes: Esperan pasivamente la llegada de peticiones de clientes. Pueden gestionar peticiones simultáneas de varios clientes, aunque no siempre es así. En la misma máquina pueden estar funcionando varios servidores de diferentes servicios. 2.3. Modelado de protocolos con autómatas de estados nitos El comportamiento de protocolos puede ser modelado sin ambigüedad mediante las indicaciones realizadas a continuación en esta sección y haciendo uso de las herramientas anteriormente expuestas. A modo de ejemplo, se supondrá el intercambio de tramas del protocolo `eDonkey' de la Figura 2.6. En ella se puede apreciar que existen dos nodos en la red, con direcciones IP1 e IP2 , que intercambian tres tramas durante una conexión. Para poder modelar este comportamiento mediante autómatas de estados nitos, se ha de conocer el alfabeto a utilizar. Este alfabeto estará determinado por un campo denominado tipo , existente en las tramas pertenecientes al protocolo `eDonkey'. Dicho campo está formado por dos dígitos en hexadecimal, los cuales identican unívocamente el tipo o naturaleza del mensaje. Por tanto, el intercambio de mensajes quedaría reducido, por ejemplo, a lo mostrado en la Figura 2.7 y, en este caso, la información extraída de las tramas intercambiadas (secuencia observable) es la mostrada en la Figura 2.8. 25 2. Fundamentos tecnológicos Figura 2.6: Ejemplo de intercambio de paquetes entre dos nodos de una red P2P. Figura 2.7: Ejemplo de información extraída en el intercambio de tramas entre dos nodos en la red. Entonces es posible que el intercambio de mensajes mostrado tenga algún signicado concreto dentro del protocolo analizado. Por ejemplo, que impliquen un establecimiento de conexión o una determinada solicitud propia del protocolo examinado. Con el objetivo de comprobarlo, se puede elaborar un autómata asociado a ese ujo de información, como se muestra en la Figura 2.9. En dicha Figura se puede observar cómo los mensajes intercambiados entre los dos peers provocan que el autómata transite de un estado a otro, hasta alcanzar un estado nal. Siguiendo el procedimiento mostrado en este ejemplo, se podría modelar el comportamiento de cualquier protocolo y, en particular, los protocolos P2P, mediante autómatas de estados nitos. En este proyecto se ha utilizado esta técnica para modelar el comportamiento del protocolo `eDonkey'. El análisis pertinente para derivar los correspondientes autómatas se detalla en el Capítulo 3. 26 2. Fundamentos tecnológicos 2.4. Herramientas y utilidades A continuación se muestran una serie de herramientas necesarias en el desarrollo de la aplicación. Se han utilizado recursos disponibles para algunas de las funcionalidades necesarias. Del conjunto de bibliotecas de funciones utilizadas en la aplicación, se muestran a continuación las más destacadas, así como una serie de programas prácticos. Figura 2.8: Información extraída de tres tramas. Figura 2.9: Ejemplo de modelado de protocolo con un autómata. 2.4.1. Standard Template Library ' Biblioteca ` Esta biblioteca ha sido utilizada debido a las múltiples estructuras de datos que proporciona. Dichas estructuras de datos han resultado de utilidad en el desarrollo de los autómatas de estados nitos, así como del almacén/clasicador de ujos utilizado (véase Capítulo 4). Como se indica en [13, 14], la Standard Template Library, también conocida como STL, es una colección de estructuras de datos genéricas y algoritmos escritos en C++. La STL no es la primera de tales bibliotecas, ya que la mayoría de los compiladores de C++ proporcionan bibliotecas de funciones con una intención similar, y también están disponibles muchas de ellas de tipo comercial. Uno de los problemas de las bibliotecas de diferentes vendedores es que son incompatibles entre ellas, por lo que los programadores están estudiando continuamente nuevas, y migrando de un proyecto a otro, y de un compilador a otro. La STL ha sido adoptada como un estándar por la International Standards Organization, International Electrotechnical Commission (ISO/IEC) y por la American National Standards Institute (ANSI), lo que signica que la STL es una extensión del lenguaje que todos los compiladores soportan y está fácilmente disponible. El concepto de STL está basado en la separación de datos y operaciones. Los datos están manejados por clases de contenedores, mientras que las operaciones están denidas por algoritmos congurables. Los iteradores son la unión entre estos dos componentes, ya que permiten a los algoritmos interactuar con cualquier contenedor, tal y como se ilustra en la Figura 2.10. 27 2. Fundamentos tecnológicos Figura 2.10: Conexión entre los tres elementos principales de la STL. En cierto modo, el concepto de STL contradice la idea original de la programación orientada a objetos: la STL separa los datos y los algoritmos en vez de combinarlos. En principio, se puede combinar todo tipo de contenedores con todo tipo de algoritmos, por lo que el resultado es una extensión exible pero aún pequeña. 2.4.2. Libpcap ' Biblioteca ` Mediante esta biblioteca ha sido posible la captura de tráco de un chero con trazas de tráco o de una interfaz de red, así como el procesamiento de cada trama (véase Capítulo 4). La biblioteca de funciones `libpcap' (o `pcap'), como se detalla en [15], es un conjunto de funciones de código abierto escritas en C con el objetivo de ofrecer al programador una interfaz desde donde es posible capturar paquetes de la interfaz de red. `Libpcap' tiene la ventaja de ser portable entre diferentes sistemas operativos y, además, ofrece una serie de funciones sencillas de utilizar que cubren todos los requisitos deseables respecto de la captura y gestión de tramas. A continuación se muestran una serie de estructuras y métodos relevantes para el manejo de esta biblioteca, que se utilizarán en la aplicación. Principales estructuras utilizadas y funcionalidades Información de interfaces. lazada de estructuras La llamada a pcap_if (pcap_if pcap_findalldevs, pcap_if_t), en la = construye una lista encual se recoge toda la información de cada una de las interfaces de red instaladas. struct pcap_if { struct pcap_if * next; //enlace a la interfaz char * name; //nombre de la interfaz char * description; //descripción de struct pcap_addr * addresses;//lista siguiente definición de (eth0, wlan0...) la interfaz o NULL enlazada de direcciones 28 2. Fundamentos tecnológicos }; asociadas a esta interfaz u_int flags; //PCAP_IF_ interface flags Una interfaz puede tener varias direcciones. Para contenerlas todas se crear una lista con una estructura pcap_addr por cada una. struct pcap_addr { struct pcap_addr * next; //enlace a la siguiente dirección struct sockaddr * addr; //dirección struct sockaddr * netmask; //máscara de red struct sockaddr * broadaddr; //dirección de broadcast para esa dirección struct sockaddr * dstaddr; // dirección de destino }; Estadísticas. Mediantes la llamada a pcap_stats se obtiene la siguiente estructura con información estadística. struct pcap_stat { u_int ps_recv; //número de paquetes recibidos u_int ps_drop; //número de paquetes no procesados u_int ps_ifdrop; //paquetes no procesados por cada interfaz (aún no soportado) }; Paquetes. Cada paquete del dump_file (archivo donde se encuentran tramas almace- nadas) va precedido por esta cabecera genérica, de modo que un mismo chero puede contener paquetes heterogéneos. struct pcap_pkthdr { struct timeval ts; //timestamp (marca de tiempo) bpf_u_int32 caplen; //tamaño del paquete al ser capturado bpf_u_int32 len; //tamaño real del paquete en el fichero; }; struct pcap_file_header { bpf_u_int32 magic; u_short version_major; u_short version_minor; bpf_int32 thiszone; //correción de GMT a local 29 2. Fundamentos tecnológicos }; bpf_u_int32 sigfigs; //precisión de los timestamps bpf_u_int32 snaplen; //tamaño máximo salvado de cada paquete bpf_u_int32 linktype; //tipo de dataLink La estructura `pcap_t'. La estructura pcap_t, que aparece en numerosas funciones, es una estructura opaca para el usuario. Por lo tanto no es necesario detallar el contenido; sólo es necesario conocer que `libpcap' almacena en este tipo de estructura el valor de ciertas variables internas. Métodos para obtener información del sistema int pcap_lookupnet(char * device, bpf_u_int32 * netp, bpf_u_int32 * maskp, char * errbuf) Una vez obtenido el nombre de una interfaz válida, es posible consultar su dirección de red (diferente a su dirección IP) y su máscara de subred. El parámetro device es un puntero a un vector de caracteres que contiene el nombre de una interfaz de red válida, netp y maskp son dos punteros a bpf_u_int32 en los que la función escribirá la dirección de red y la máscara respectivamente. En caso de error la función devuelve -1 y una descripción del error en errbuf. Métodos para capturar paquetes Existen varias funciones para capturar paquetes. Las principales diferencias entre ellas son: el número de paquetes que se desea capturar, el modo de captura (normal o promiscuo) y la manera en que se denen sus funciones de llamada o callbacks (la función invocada cada vez que se captura un paquete). pcap_t * pcap_open_live(char * device, int snaplen, int promisc, int to_ms, char * errbuf) Antes de entrar en el bucle de captura hay que obtener un descriptor de tipo para lo cual se emplea esta función. El primer parámetro (char pcap_t, * device) es el nombre ANY o NULL fuerzan del dispositivo de red en el que se desea iniciar la captura (los valores la captura en todos los dispositivos disponibles). El segundo argumento (int El argumento promisc snaplen) especica el número máximo de bytes a capturar. 0 iniciara la 0 para modo normal. indica el modo de apertura: un valor distinto de captura en modo promiscuo, Los programas basados en `libpcap' se ejecutan en la zona de usuario pero la captura en sí se realiza en la zona del núcleo. Se hace por lo tanto necesario un cambio de área. Estos cambios son muy costosos y es necesario evitarlos si se quiere optimizar el rendimiento, por eso esta función permite especicar mediante el parámetro to_ms 30 2. Fundamentos tecnológicos cuántos milisegundos se desea que el núcleo agrupe paquetes antes de pasarlos todos NULL, errbuf. simultáneamente a la zona de usuario. Si la función devuelve un error y puede encontrarse una descripción del mismo en se habrá producido int pcap_loop(pcap_t * p, int cnt, pcap_handler callback, u_char * user) Esta función se utiliza para capturar y procesar los paquetes. El parámetro dica el número máximo de paquetes a procesar antes de salir; capturar indenidamente. El siguiente parámetro, callback, cnt = -1 cnt in- se usa para es un puntero a la función que será invocada para procesar el paquete. Para que un puntero a función sea de tipo pcap_handler, debe recibir unos parámetros: u_char: Puntero Estructura Es un puntero al propio paquete. pcap_pkthdr. -1 en caso de error, en cuyo pcap_geterr() para mostrar un La función devuelve el número de paquetes capturados o caso se puede emplear las funciones pcap_perror() y mensaje más descriptivo de dicho error. En caso de error se devolverá un número negativo o 0 si el número de paquetes especicados por cnt se ha completado con éxito. Métodos para manejar ltros Un ltro es una cadena que dene los paquetes que va a capturar y procesar la interfaz de red. Su principal uso es para librar al núcleo (kernel ) de carga de trabajo. int pcap_compile(pcap_t * p, struct bpf_program * fp, char * str, int optimize, bpf_u_int32 netmask) Esta función se emplea para compilar un programa de ltrado (char BPF equivalente (bpf_u_int32 netmask). * str) en su Es posible que durante la compilación, el programa original se modique para optimizarlo. El parámetro netmask es la máscara de la red local, que puede obtenerse llamando a pcap_lookupnet. En caso de que la función devuelva -1, se habrá producido un error. Para una descripción más detallada de lo sucedido se puede emplear la función pcap_geterr(). int pcap_setfilter(pcap_t * p, struct bpf_program * fp) Una vez compilado el ltro sólo es necesario aplicarlo; para ello es suciente pasar como parámetro a esta función el resultado de compilar el ltro con En caso de error la función devolverá llada del error con pcap_geterr(). -1 pcap_compile. y puede obtenerse una descripción más deta- 31 2. Fundamentos tecnológicos Métodos para manejar cheros relacionados con la captura de tráco pcap_open_offline(filename, errbuf) Este método sirve para abrir un chero con paquetes ya guardados en formato tcpdump en modo lectura. filename Los parámetros son: 2.4.3. NULL en errbuf. para indicar la ruta del chero, devuelve de que la función falle. Para consultar la descripción del error, se utiliza caso Pthread ' Biblioteca ` Mediante esta biblioteca de funciones, ha sido posible la programación multihebrada de la aplicación, permitiendo concurrentemente analizar ujos de varios cheros de red, así como de interfaces de red. También ha sido fundamental para la extracción de ujos del almacén/clasicador de ujos implementado, realizando esta tarea entre varias hebras para liberar de carga a la hebra principal (véase Capítulo 4). En arquitecturas de multiprocesadores con memoria compartida, tales como los SMP, las hebras se pueden utilizar para implementar paralelismo, como se puede consultar en [19]. Históricamente, los fabricantes de hardware tenían implementadas sus propias versiones de hebras, convirtiendo así la portabilidad en un problema que concernía a los desarrolladores de software. En los sistemas UNIX, se ha especicado una interfaz de programación de hebras estandarizada en lenguaje C, mediante el estándar IEEE POSIX 1003.1c. Las implementaciones adheridas a este estándar se conocen como hebras POSIX o Pthreads. ¾Por qué usar `Pthreads' ? La principal motivación para usar Pthreads es para realizar programas con una gran ganancia en rendimiento. Cuando se compara con el coste de crear y mantener un proceso, una hebra puede generarse con mucha menos sobrecarga por parte del sistema operativo. Por ejemplo, la tabla mostrada en la Figura 2.11 compara los resultados en tiempo fork() (crear un proceso hijo) y para la subrutina pthread_create() (crear una hebra). Los tiempos reejan las creaciones de 50000 procesos/hebras, que se midieron mediante la utilidad time, en segundos, sin ningún de cómputo para la subrutina tipo de optimización. Todas las hebras de un proceso comparten el mismo espacio de direcciones. La intercomunicación entre hebras es más eciente en muchos casos y más fácil de usar que la intercomunicación entre procesos. Las aplicaciones programadas mediante hebras ofrecen una potencial ganancia en rendimiento y ventajas frente a las aplicaciones sin hebras de otras maneras: 32 2. Fundamentos tecnológicos Plataforma real sys pthread_create() real user sys AMD 2.4 GHz Opteron (8 cpu/nodo) 41.07 60.08 9.01 0.66 0.19 0.43 IBM 1.9 GHz POWER5 p5-575 (8 cpu/nodo) 64.24 30.78 27.68 1.75 0.69 1.10 IBM 1.5 GHz POWER4 (8 cpu/nodo) 104.05 48.64 47.21 2.01 1.00 1.52 INTEL 2.4 GHz Xeon (2 cpu/nodo) 54.95 1.54 20.78 1.64 0.67 0.90 INTEL 1.4 GHz Itanium2 (4 cpu/nodo) 54.54 1.07 22.22 2.03 1.26 0.67 Figura 2.11: Costes en tiempo (aproximados) para fork() user fork() y pthread_create(). Solapamiento de trabajo de la CPU con entrada/salida: Por ejemplo, un programa puede tener secciones donde se lleve a cabo una larga operación de entrada/salida. Mientras una hebra está esperando una llamada al sistema de entrada/salida para completarse, el trabajo intensivo de la CPU lo pueden realizar otras hebras. Programación con prioridades y/o en tiempo real: Las tareas que son más importantes pueden ser programadas para reemplazar o interrumpir otras tareas con menor prioridad. Manejo de eventos asíncronos: Las tareas cuyos eventos (de frecuencia y duración indeterminada) pueden estar entremezclados. Por ejemplo, un servidor web puede transferir datos de una solicitud previa y manejar solicitudes nuevas al mismo tiempo. El motivo principal para considerar el uso de Pthreads en una arquitectura SMP es para conseguir un rendimiento óptimo. La API Pthread La API Pthread se dene en el estándar ANSI/IEEE POSIX 1003.1 - 1995. Las subrutinas que comprenden la API Pthread pueden agruparse informalmente en tres clases principales: Manejo de hebras: La primera clase de estas funciones trabaja directamente con las hebras (creándolas, uniéndolas, etc.). También incluyen funciones para establecer o consultar algún atributo de la hebra. Mutexes: La segunda clase de estas funciones están relacionadas con la sincronización. El nombre es mutex debido a la abreviatura de mutual exclusion. Las funciones mutex proporcionan funcionalidades para crear, destruir, bloquear y desbloquear mutexes. También existen funciones relacionadas con los atributos de dichos mutexes, las cuales pueden establecer un atributo nuevo o modicarlo. Variables de condición: La tercera clase de funciones manejan comunicaciones entre hebras que comparten un mutex. Están basadas en condiciones especicadas por el programador. Esta clase incluye funciones para crear, destruir, 33 2. Fundamentos tecnológicos bloquear y desbloquear hebras en base a valores de variables especicados. También se incluyen funciones para consultar o establecer atributos en las variables de condición. Convenciones de nombrado: Como se muestra en la tabla de la Figura 2.12, todos los identicadores de la biblioteca de hebras comienzan por La API Pthread contiene más de 60 subrutinas. Debido a la portabilidad, la cabecera pthread.h pthread_. se debe incluir en cada chero fuente que utilice la biblioteca Pthread. El estándar POSIX actual está denido en lenguaje C. 2.4.4. Wireshark Como se puede consultar en [17], wireshark es un analizador de paquetes de la red. Un analizador de este tipo intentará capturar los paquetes de la red y mostrar los datos de dichos paquetes lo más detalladamente posible. Se podría decir que un analizador de paquetes de la red es un dispositivo medidor que se usa para examinar qué está pasando dentro de un cable de red. Algunos usos de Wireshark son: Buscar problemas en la red por los administradores de redes. Examinar problemas de seguridad por ingenieros en este campo. Depurar implementaciones de protocolos por desarrolladores de software. Estudiar el funcionamiento de un protocolo de red. En este proyecto, esta herramienta será útil para analizar el funcionamiento del protocolo `eDonkey'. Prejo de las rutinas pthread_ pthread_attr_ pthread_mutex_ pthread_mutexattr_ pthread_cond_ pthread_condattr_ pthread_key_ Grupo funcional Las propias hebras y subrutinas generales Atributos de las hebras Mutexes Atributos de los mutexes Variables de condición Atributos de las condiciones Claves de datos especícos de las hebras Figura 2.12: Grupos funcionales de rutinas Pthread. 34 2. Fundamentos tecnológicos 2.4.5. Doxygen Doxygen, como se puede consultar en [20], es un generador de documentación que se utiliza para documentar múltiples lenguajes de programación, como pueden ser C++, Java o Python, entre otros. Como es fácilmente adaptable, funciona en varias plataformas. Doxygen es una herramienta para escribir documentación de referencia en el software. Esta documentación se escribe aparte del código, y es relativamente fácil mantenerla actualizada. Doxygen puede crear referencias cruzadas entre el código y la documentación, por lo que un lector de documentos puede desplazarse fácilmente hacia el código. 35 2. Fundamentos tecnológicos 36 Capı́tulo 3 Análisis En este capítulo se aborda el análisis del proyecto. En él se detalla el modelado del protocolo `eDonkey' mediante autómatas de estados nitos, ya que es una parte fundamental en el funcionamiento de la aplicación. También se detallan los requisitos y funcionalidades de dicha aplicación, así como su estructura principal. 3.1. Procedimientos en el protocolo `eDonkey' A continuación se detallan los procedimientos más relevantes del protocolo `eDonkey' en base al intercambio de mensajes, con todos los diálogos mostrados, como se detalla en [9]. El objetivo es derivar los autómatas de estados nitos correspondientes a cada uno de los procedimientos del protocolo. Dichos procedimientos o diálogos se dividen en: Comunicación TCP entre el cliente y el servidor: Establecimiento de conexión. Intercambio de mensajes al inicio de la conexión. Búsqueda de archivos. Mecanismo de callback. Comunicación UDP entre el cliente y el servidor: Keep-alive del servidor. Información de estado. Comunicación TCP entre dos clientes: Handshake inicial. Identicación segura del usuario. Solicitud de cheros. Transferencia de datos. 37 3. Análisis Consulta de los archivos y carpetas compartidos. Intercambio de los hash de fragmentos de archivos. Obtención de la previsualización de un archivo. Comunicación UDP entre dos clientes. Uso del protocolo UDP en escenarios relacionados con la descarga de archivos. En todos los diálogos posibles existen escenarios (situaciones donde se producen intercambios de mensajes) entre el cliente y el servidor o entre dos clientes. Dichos escenarios, que no son más que un intercambio de mensajes a lo largo del tiempo, pueden modelarse mediante autómatas de estados nitos, siguiendo el procedimiento mostrado en el Capítulo 2. A continuación se recorren los posibles diálogos más destacados, con los escenarios más importantes conocidos para dichos diálogos y con el intercambio de mensajes correspondiente y su modelado mediante un autómata de estados nitos. 3.1.1. Comunicación TCP cliente-servidor Cada cliente se conecta exactamente a un servidor usando una conexión TCP. El servidor asigna al cliente un ID, que será usado para identicarle durante toda la sesión con ese servidor (un cliente con ID alto lo ha obtenido siempre a partir de su dirección IP, como se explica en la sección 1.3.2). Para poder operar, el cliente `eMule' requiere siempre que se establezca una conexión con un servidor. Dicho cliente no puede estar conectado a varios servidores al mismo tiempo ni tampoco cambiar de uno a otro de manera dinámica sin la intervención directa del usuario. Establecimiento de conexión Cuando se establece la conexión con un servidor, el cliente intenta conectar con varios servidores en paralelo, pero abandona todos los intentos una vez se haya conectado exitosamente a uno. Existen tres posibles casos de establecimiento de conexión: Conexión con ID alto: El servidor asigna un ID alto al cliente que se conecta. Conexión con ID bajo: El servidor asigna un ID bajo al cliente que se conecta. Sesión rechazada: El servidor rechaza al cliente. Existe, por supuesto, el caso trivial en el que el servidor está caído o es inalcanzable. La Figura 3.1 describe la secuencia de mensajes que da lugar a una conexión con ID alto. En este caso, el cliente establece una conexión TCP con el servidor y le envía un login. El servidor se conecta al cliente usando otra conexión TCP y realiza handshake cliente-cliente para asegurarse de que el cliente al que se conecta tiene la capacidad de aceptar conexiones de otros clientes `eMule'. Tras completar el handshake el servidor termina la segunda conexión y completa el handshake cliente-servidor enviando mensaje de un 38 3. Análisis un mensaje de cambio de ID (`ID change'). El mensaje de `eMule' info está representado en la Figura con color gris por el hecho de pertenecer a una extensión del protocolo, que es parte de `eDonkey'. La Figura 3.2 describe la secuencia de mensajes que dan lugar a una conexión con ID bajo. En este caso, el servidor falla al intentar conectarse al cliente que se conecta a él, por lo que se le asigna un ID bajo. El servidor suele enviar un mensaje de precaución, de la forma: Warning [detalles del servidor] You have a low ID. Please review your network cong and/or your settings . Los handshake correspondientes a conexiones tanto de ID alto como de ID bajo, nal- mente se completan con el mensaje de cambio de ID, el cual asigna al cliente un ID para su conexión con el servidor. La Figura 3.3 describe la secuencia de mensajes que se suceden para una conexión rechazada por el servidor. Dicho servidor podría actuar así debido a que el cliente tiene un ID bajo o cuando alcanzan su capacidad máxima. El mensaje del servidor contendrá una breve cadena que describe el motivo del rechazo. Figura 3.1: Conexión con ID alto. 39 3. Análisis Figura 3.2: Conexión con ID bajo. El modelado de los tres tipos de conexiones con un autómata daría lugar a lo mostrado en la Figura 3.4, en la que se representa el intercambio de mensajes que se producen entre cliente y servidor. La sintaxis seguida por el mensaje que acompaña a la echa es mensaje del cliente/mensaje del servidor , ya que los autómatas están diseñados de cara a considerarlos como si se vieran desde el propio cliente. Por ejemplo, para llegar al q q q escenario nal en el que al cliente se le asigna un ID bajo, primero el cliente se conecta mediante TCP al servidor (q0 servidor (q1 q 1 ); tras esto, el cliente envía un mensaje de login al 2 ); entonces el servidor se conecta con este cliente para vericar que q acepta conexiones entrantes ( 2 mensaje del servidor (q3 ID (q9 q 3 ); al comprobar que no puede, el cliente recibe un 9 ); por último, el cliente recibe un mensaje de cambio de 10 ). Es en este punto donde se llega a la conclusión de que al cliente se le ha asignado un ID bajo. Figura 3.3: Conexión rechazada. 40 3. Análisis Figura 3.4: Establecimiento de conexión modelado con autómata de estados nitos. Es viable unir los tres posibles escenarios en un solo autómata, ya que comparten parte de los mensajes intercambiados y la utilización y gestión de este autómata no es compleja. En realidad, sería posible denir un único autómata capaz de modelar todo el protocolo considerando todos los escenarios posibles. Sin embargo, por razones operativas y de escalabilidad, se usarán autómatas parciales, correspondientes a escenarios concretos. En el caso de considerar un único autómata, resultaría muy complejo analizar el protocolo y modelar nuevos escenarios y añadirlos a la especicación. Análogamente en este caso, los tres escenarios se podían haber modelado con tres autómatas más pequeños, que son, en realidad, tres sub-autómatas del mostrado en la Figura 3.4. Sin embargo, como se ha comentado, el autómata nal resultante no es tan complejo como para dividirlo. Además, los tres sub-autómatas forman parte del establecimiento de conexión entre cliente y servidor (mismo escenario). Intercambio de mensajes al inicio de la conexión Tras un establecimiento de conexión exitoso, el cliente y el servidor intercambian algunos mensajes. El propósito de estos mensajes es actualizar ambas partes, contemplando el estado de los peers. El cliente comienza ofreciendo al servidor una lista con sus archivos compartidos y luego realiza una petición de actualización de su lista de servidores. El servidor le envía su estado y su versión y luego la lista de todos los servidores `eMule' que conoce, junto con algunos detalles más del propio servidor. Finalmente, el cliente realiza una petición de fuentes (es decir, otros clientes a los que pueda acceder que contengan partes de archivos en su lista de descarga) y el servidor le contesta con una serie de mensajes, uno por cada archivo de la lista de descarga del cliente. La Figura 3.5 ilustra esta secuencia. 41 3. Análisis Figura 3.5: Secuencia de mensajes al inicio de la conexión. El modelado de la serie de mensajes expuestos en la Figura 3.5 se correspondería con el autómata de la Figura 3.6. Búsqueda de archivos La búsqueda de archivos la inicia el usuario. La operación es simple: se envía una solicitud de búsqueda al servidor y este contesta con un resultado. Cuando existen múltiples resultados, el mensaje con el resultado de la búsqueda se comprime. Tras esto, el usuario decide descargar uno o más archivos, por lo que envía peticiones de búsqueda de fuentes para cada uno de estos archivos y el servidor contesta con una lista de fuentes para cada uno de dichos archivos. El servidor puede enviar un mensaje de estado opcional, antes de la respuesta con las fuentes encontradas. Figura 3.6: Secuencia de mensajes al inicio de la conexión modelada con autómata de estados nitos. 42 3. Análisis El mensaje de estado contiene información acerca del número de usuarios y archivos soportados por el servidor. Es importante señalar que también existe una secuencia de mensajes UDP para mejorar la habilidad de un cliente para localizar fuentes en las búsquedas de archivos. Tras vericar que las fuentes obtenidas son nuevas, el cliente `eMule' inicia un intento de conexión y las añade a su lista de fuentes. El orden en el que se contacta con las fuentes es el orden con el que el cliente las recibió. El cliente `eMule' se va conectando a las fuentes en el orden en el que están en su lista de fuentes. No hay ningún mecanismo de prioridad para decidir a qué fuente conectar, pero sí existe un complicado articio para resolver situaciones donde se le pueden enviar múltiples solicitudes a una misma fuente porque esta posea varios de los archivos de la lista de descarga del cliente (nótese que `eMule' sólo permite una única conexión entre clientes). El algoritmo de selección está basado en las especicaciones de prioridad del usuario pero, si no existen, por defecto se atiende al orden alfabético. La Figura 3.7 muestra este mecanismo, mientras que la Figura 3.8 muestra el autómata resultante. Mecanismo de callback El mecanismo de callback se diseñó para superar la incapacidad de los clientes con ID bajo de aceptar conexiones entrantes y, así, poder compartir sus archivos con otros clientes. El mecanismo es simple: en el caso de que `A' y `B' estén conectados al mismo servidor `eMule' y `A' necesite un archivo que posee `B', pero `B' tenga un ID bajo, entonces `A' puede enviar al servidor una solicitud de callback al servidor, para que este le solicite a `B' que se conecte con `A'. El servidor, que ya tiene una conexión TCP establecida con `B', le envía a `B' un mensaje de callback con la dirección IP y puerto de `A'. Entonces `B' ya puede conectarse con `A' y enviarle el archivo que le falta, sin más sobrecarga en el servidor. Obviamente, sólo un cliente con ID alto puede realizar solicitudes de callback hacia clientes con ID bajo (un cliente con ID bajo no puede aceptar conexiones entrantes). La Figura 3.9 describe esta secuencia. Figura 3.7: Secuencia de mensajes de búsqueda de archivos. 43 3. Análisis Figura 3.8: Autómata de estados nitos para la búsqueda de archivos. Existe también una característica que permite a dos clientes con ID bajo intercambiar archivos a través de la conexión que tienen con el servidor, utilizándola como una pasarela. Pero la mayoría de servidores no soportan esta opción ya que produce una gran sobrecarga en ellos. Los autómatas que modelan este intercambio de mensajes se muestran en las Figuras 3.10, 3.11 y 3.12. El motivo de denir, en este caso, tres autómatas es porque existen tres entidades que participan en el proceso. Si se considerara solamente una de ellas, no se podrían apreciar todos los intercambios de mensajes, porque siempre hay alguno que involucra a una tercera entidad no representada. Figura 3.9: Secuencia de mensajes para el mecanismo de callback. 44 3. Análisis Figura 3.10: Secuencia de mensajes para el mecanismo de callback modelada con auto- callback modelada con auto- callback modelada con auto- mata de estados nitos (Cliente A). Figura 3.11: Secuencia de mensajes para el mecanismo de mata de estados nitos (Servidor). Figura 3.12: Secuencia de mensajes para el mecanismo de mata de estados nitos (Cliente B). 3.1.2. Comunicación UDP cliente-servidor El cliente `eMule' y el servidor usan el protocolo no able UDP para keep-alive y para mejoras en las búsquedas. La cantidad de paquetes UDP que genera un cliente `eMule' puede alcanzar el 5 % del total de paquetes, pero depende del número de servidores en la lista del cliente, del número de fuentes para cada archivo de su lista de descarga y del número de búsquedas realizadas por el usuario. Estos paquetes se van enviando de acuerdo con un contador que expira cada 100 ms. Si se tiene en cuenta que sólo existe una hebra responsable del tráco UDP saliente, se obtiene una tasa máxima de 10 paquetes/seg. Keep-alive del servidor e información de estado El cliente comprueba, periódicamente, el estado de los servidores de su lista de servidores. Esta comprobación se realiza usando los mensajes de solicitud de estado del servidor UDP y de solicitud de descripción del servidor UDP. El esquema keep-alive que se des- cribe a continuación no genera más de una docena de paquetes por hora. En cualquier caso, la tasa máxima es de 0.2 paquetes/seg (o un paquete cada 5 segundos). Cuando se comprueba el estado de un servidor, el cliente primero envía un mensaje de solicitud de estado y posteriormente, sólo una vez cada dos intentos, una solicitud de descripción del servidor, tal y como se muestra en la Figura 3.13. 45 3. Análisis Figura 3.13: Ciclo de keep-alive UDP. El mensaje de solicitud de estado incluye un número aleatorio que el servidor incluye en su mensaje de respuesta. En caso de que el número que envíe el servidor sea diferente al reto del cliente, el mensaje se descartará. Cada vez que el cliente envía un mensaje de este tipo, incrementa en una unidad un contador de intentos. Cualquier mensaje recibido por parte del servidor (incluyendo resultados de búsquedas, etc), pone a cero dicho contador. Cuando este contador alcanza un número límite, el cual es congurable, el servidor se considera muerto y se quita de la lista de servidores del cliente. Las respuestas proporcionadas por un servidor incluyen varios tipos de datos. La respuesta a una solicitud de estado incluye el número actual de usuarios y archivos en el servidor y también los límites blandos y duros (descritos anteriormente). La respuesta a una solicitud de descripción del servidor incluye el nombre de este y una cadena de texto con una breve descripción. La Figura 3.14 ilustra el intercambio de mensajes en una secuencia keep-alive completa entre un cliente y un servidor y el modelado resultante se encuentra en la Figura 3.15. Figura 3.14: Secuencia keep-alive UDP. 46 3. Análisis Figura 3.15: Secuencia keep-alive UDP modelada con autómata de estados nitos. En esta situación, se han podido unir los dos escenarios en un mismo autómata. Esto es porque en el primer escenario sólo se indicaban las solicitudes que realizaba el cliente al servidor y la frecuencia con las que las realizaba. Sin embargo, en el segundo escenario, se muestran las solicitudes junto con sus respuestas, por lo que existe una parte común entre los dos escenarios que se pueden resumir en un solo autómata sencillo. 3.1.3. Comunicación TCP cliente-cliente Tras registrarse en el servidor y enviarle solicitudes de archivos y fuentes, el cliente `eMule' necesita contactar con otros clientes con el objetivo de descargarse los cheros que desee. Así, se crea una conexión TCP dedicada para cada par {archivo, cliente}. Las conexiones se cierran cuando no hay actividad en un determinado (40 segundos por defecto) o cuando el peer socket durante un tiempo cierra la conexión. Con el objetivo de proporcionar tasas de descarga razonables, `eMule' no permite a un cliente comenzar la descarga de un archivo hasta que no pueda ofrecerle una tasa mínima (la cual es 2.4 KB/seg). Handshake El inicial handshake inicial es simétrico, ya que ambas partes se envían la misma informa- ción. Los clientes intercambian información acerca del otro, la cual incluye identicación, versión e información acerca de determinadas capacidades. Participan dos tipos de mensajes: el mensaje de `Hello' y el mensaje de información acerca del `eMule'. El primero de ellos es parte del protocolo `eDonkey' y es compatible con los clientes. El segundo es parte del protocolo extendido del cliente, el cual es único en `eMule'. En la Figura 3.16 se muestra este funcionamiento, y su autómata correspondiente es el de la Figura 3.17. 47 3. Análisis Figura 3.16: Figura 3.17: Handshake Handshake inicial de los clientes `eMule'. inicial de los clientes `eMule' modelado con autómata de estados nitos. En este autómata se incluyen tanto los mensajes intercambiados del protocolo `eDonkey', como la extensión del protocolo proporcionada por `eMule'. Como se puede apreciar, no es necesario disponer de la extensión de `eMule' para poder satisfacer este escenario. Identicación segura del usuario En el Apartado 1.3.3 se describió brevemente los ID del usuario y la motivación que pueden tener otros para suplantar la identidad de un determinado usuario. La identicación segura es parte de la extensión de `eMule'. En el caso de que los clientes soporten este tipo de identicación, esta tiene lugar justo después del handshake inicial. El propó- sito de la identicación segura es prevenir la suplantación de identidad. Es un esquema simple basado en RSA. Cuando se aplica dicha identicación, suponiendo dos clientes `A' y `B', tienen lugar los siguientes pasos: 1. En el handshake inicial, `B' indica que soporta la identicación segura y que desea utilizarla. 2. El cliente `A' reacciona enviando un mensaje de identicación segura, el cual indica si `A' necesita la clave pública de `B' o no, y que también contiene un reto de 4 bytes que `B' tiene que rmar. 48 3. Análisis 3. En el caso de que `A' haya indicado que necesita la clave pública de `B', entonces `B' se la envía. 4. `B' envía un mensaje rmado que se crea usando el reto recibido y una palabra doble adicional que es la dirección IP de `A', en el caso de que `B' tenga un ID bajo, o el ID de `B' en el caso de que tenga ID alto. Las Figuras 3.18 y 3.19 ilustran dicha secuencia de mensajes. El autómata se muestra en la Figura 3.20. En este caso se muestra un autómata único en el que ha sido posible unir varios escenarios debido a su sencillez y al hecho de compartir mensajes entre ellos. Solicitud de cheros Como ya se describió, se crea una conexión para cada par {cliente, chero}. Inmediatamente después del establecimiento de conexión, el cliente envía varios mensajes indicando el archivo que desea descargar (Figura 3.21). Existen varios casos en la solicitud de cheros y se describen a continuación. Figura 3.18: Identicación segura. `A' no tiene la clave pública de `B'. Figura 3.19: Identicación segura. `A' tiene la clave pública de `B'. 49 3. Análisis Figura 3.20: Identicación segura modelada con autómata de estados nitos. Figura 3.21: Solicitud de chero. Intercambio básico de mensajes. Está compuesto por cuatro mensajes. En primer lugar, `A' envía un mensaje de solicitud de archivo e inmediatamente después, otro con el ID del archivo que se solicita. `B' responde a la solicitud de archivo con una solicitud de respuesta de archivo. Al mensaje con el ID del archivo solicitado contesta con un mensaje de estado del chero. El protocolo extendido añade dos mensajes a esta secuencia: una solicitud de fuentes y una respuesta a esta solicitud. Esta extensión se utiliza para transmitir las fuentes de `B' (en el caso de que `B' sea el cliente que descarga) a `A'. No existe ningún requerimiento que establezca que `B' necesite descargar el archivo completo para poder compartir partes con otros clientes, por lo que `B' puede enviar a `A' otros fragmentos del chero que tenga completos. Escenario de archivo no encontrado. Se produce cuando `A' solicita un archivo a `B' pero `B' no disponga de dicho archivo en su lista de archivos compartidos. `B' no envía la respuesta de solicitud de archivo, sino que envía un mensaje de archivo no encontrado, inmediatamente después de recibir el mensaje con el ID del archivo que se solicita (Figura 3.22). Asimismo, el autómata que modela tanto la solicitud de un chero como el escenario de un chero no encontrado es el de la Figura 3.23. 50 3. Análisis Figura 3.22: Solicitud de archivo fallida. Archivo no encontrado. Figura 3.23: Solicitud de chero modelada con autómata de estados nitos. En este caso, se ha podido, una vez más, unir varios escenarios dentro de un mismo autómata. La parte inicial corresponde a la búsqueda de archivos en ambos casos, pero se diferencia en la parte nal en caso de que el archivo no se haya encontrado, o bien en el caso de que sí se haya encontrado. Adición de archivos a la cola de subida. En el caso de que `B' disponga de un determi- nado archivo que se le ha solicitado y su cola de subida no esté vacía, signica que existen clientes que se están descargando archivos de él y probablemente existirán también otros clientes en cola. `A' y `B' realizan el handshake completo, pero cuando `A' solicita a `B' la descarga de un archivo, `B' le añade a la cola de subida y le envía un mensaje de ranking, el cual contiene la posición de `A' en la cola. Gestión de la cola de subida. Para cada archivo enviado, el cliente mantiene una cola de subida con prioridad. La prioridad de cada cliente en dicha cola se calcula en base 51 3. Análisis al tiempo que lleva el cliente en la cola y un modicador de prioridad, llamado rating (Figura 3.24). En la cabeza de la cola están los clientes que tienen la puntuación más alta. Dicha puntuación se calcula usando la siguiente fórmula: puntuacion = rating×segundosEnLaCola 100 Puede ser innito en caso de que el cliente que descarga esté denido como amigo. El valor del rating rating inicial es 100, excepto para los usuarios prohibidos (expulsados), cuyo es 0 (y así se evita que alcancen la cabeza de la cola). El rating es modicado o bien por el crédito del cliente que descarga (cuyo rango es del 1 al 10) o por la prioridad del archivo que se envía (0.2 1.8) el cual lo modica el cliente que lo envía. Cuando la puntuación de un cliente es mayor que la del resto de los clientes de la cola, entonces comienza la descarga del archivo. El cliente estará descargando dicho archivo a no ser que se dé una de las siguientes situaciones: 1. El usuario desconecta al cliente que envía el archivo. 2. El cliente que descarga tiene todas las partes que necesita. 3. El cliente que descarga es adelantado por otro que tiene más prioridad que él. Con el objetivo de permitir a un cliente que acaba de comenzar a descargar archivos obtener algunos megabytes antes de ser adelantado por otro, `eMule' impulsa el rating inicial del cliente que descarga a 200 durante los primeros 15 minutos. El autómata que modela el escenario de la Figura 3.24 es el de la Figura 3.25. Figura 3.24: Cola de espera para una solicitud de un archivo. 52 3. Análisis Figura 3.25: Cola de espera para una solicitud de un archivo modelada con autómata de estados nitos. Alcanzando el inicio de la cola de subida. subida de `B', `B' se conecta a `A', realiza el Cuando `A' alcanza el inicio de la cola de handshake inicial y luego envía un mensaje de aceptación para la cola de subida. `A' puede ahora elegir entre continuar y comenzar a descargar el archivo enviando una solicitud, o bien cancelar la descarga (en caso de que ya tenga el fragmento de otra fuente) enviando un mensaje de cancelación de transferencia. La Figura 3.26 ilustra estas opciones y el autómata correspondiente se muestra en la Figura 3.27. Debido a que los dos escenarios sólo se diferencian en el mensaje nal, es posible aunarlos en un mismo autómata, claricando en el estado nal las dos posibles transiciones. Figura 3.26: Descarga de un archivo. 53 3. Análisis Figura 3.27: Descarga de un archivo modelada con autómata de estados nitos. Transferencia de datos El paquete de datos. El envío y recepción de fragmentos de archivos es la mayor parte de la actividad de la red `eMule'. El tamaño de un fragmento enviado puede variar entre 5000 y 15000 bytes (dependiendo también de la compresión). Con el objetivo de evitar la fragmentación, los mensajes de partes de cheros se envían en trozos y cada trozo en un paquete TCP por separado. En la versión 0.30e de `eMule', el tamaño máximo de una pieza es de 1300 bytes (nótese que este número se reere únicamente a la carga útil del paquete TCP). En otras palabras, mientras cada mensaje de control se envía en un único paquete TCP, a veces, junto con otro mensaje, los mensajes de datos están divididos en varios paquetes TCP. El primer paquete contiene la cabecera del mensaje de la parte del archivo que se envía. El resto de los paquetes contienen sólo datos. En caso de que el paquete se divida, en el primero de ellos se envía un recordatorio (el que lleva el mensaje de cabecera) que lo indica. Los detalles se muestran en la Figura 3.28, y el autómata que lo modela es el de la Figura 3.29. Figura 3.28: Detalles del mensaje de la parte de un archivo. 54 3. Análisis Figura 3.29: Detalles del mensaje de la parte de un archivo modelado con autómata de estados nitos. Secuencia de transferencia de datos. Una secuencia de transferencia de una parte con- creta puede comenzar inmediatamente después de la respuesta a la solicitud del archivo. El cliente que descarga, `A', envía una solicitud de comienzo de envío, la cual se responde mediante otro mensaje de aceptación. Inmediatamente después de esto, `A' comienza a solicitar fragmentos de archivo y `B' contesta enviando las partes solicitadas. Cuando ambos clientes soportan el protocolo extendido, los fragmentos del archivo se pueden enviar comprimidos. Dicho protocolo también soporta un mensaje adicional de información que puede ser enviado justo antes del mensaje de aceptación de envío. Esta secuencia está ilustrada en la Figura 3.30 y el autómata que lo modela es el de la Figura 3.31. Figura 3.30: Intercambio de fragmentos de archivo. 55 3. Análisis Figura 3.31: Intercambio de fragmentos de archivo modelado con autómata de estados nitos. Consulta de los archivos y carpetas compartidos Hay dos tipos de mensajes que manejan la visualización de los archivos y carpetas compartidas por los clientes peer. El primero es el mensaje de visualización de archivos compartidos, el cual se envía justo tras el handshake inicial. Este mensaje siempre es contestado por otro de respuesta. Cuando el cliente que contesta desea esconder su lista de archivos compartidos, la respuesta no contendrá ningún archivo (en vez de enviar un mensaje que signique que el acceso ha sido denegado). La Figura 3.32 muestra la secuencia de mensajes. El segundo mensaje comienza con una solicitud de vista de la lista de las carpetas compartidas, el cual es respondido con la lista de las carpetas y, tras esto, para cada carpeta del mensaje de respuesta, un mensaje para mostrar el contenido de la misma. Cada uno de estos mensajes es contestado con una lista de contenidos. Se puede comprobar en la Figura 3.33. En caso de que el cliente esté congurado para bloquear las solicitudes de archivos y carpetas compartidos, contesta con un mensaje de denegación, como se muestra en la Figura 3.34. Los intercambios de mensajes pueden modelarse con el autómata de la Figura 3.35. Dado que los escenarios se sitúan en el mismo contexto, se puede elaborar un autómata con tan sólo ocho estados que sea capaz de recoger los cuatro escenarios. Figura 3.32: Solicitud de vista de archivos compartidos. 56 3. Análisis Figura 3.33: Consulta de archivos y carpetas compartidos. Figura 3.34: Solicitudes de vista de archivos y carpetas denegadas. Intercambio de los hash de fragmentos de archivo Con el objetivo de obtener los hash de partes de archivo, se envía una solicitud, a la cual el cliente contestará con un mensaje de respuesta de hash, que contendrá dicho hash del fragmento del archivo. La Figura 3.36 ilustra este hecho y el autómata que lo modela es el de la Figura 3.37. Obtención de la previsualización de un archivo El cliente puede pedir a su peer obtener la previsualización de un archivo descarga- do. Las previsualizaciones dependen de las aplicaciones y de los tipos de archivos. Las versiones más antiguas de `eMule' (0.30e) soportan la previsualización de imágenes. El escenario se detalla en la Figura 3.38 y el autómata correspondiente en la Figura 3.39. 57 3. Análisis Figura 3.35: Vista de archivos y carpetas compartidos modelada con autómata de estados nitos. Figura 3.36: Solicitud de Figura 3.37: Solicitud de hash hash de fragmento de archivo. de fragmento de archivo modelada con autómata de esta- dos nitos. 58 3. Análisis Figura 3.38: Obtención de la previsualización de un archivo. Figura 3.39: Obtención de la previsualización de un archivo modelada con autómata de estados nitos. 3.1.4. Comunicación UDP cliente-cliente El cliente `eMule' envía periódicamente mensajes usando el protocolo UDP. En la versión de `eMule' 0.30e, los mensajes UDP se usan únicamente para que el cliente pregunte a su peer la posición en la que está en la cola de descarga. El esquema simple solicitud- respuesta se inicia con un mensaje de re-solicitud de un chero concreto. Existen tres posibles respuestas para este mensaje: 1. Posición en la cola: La posición del cliente en la cola del que envía. 2. Cola completa: La cola del cliente que envía está llena. 3. Archivo no encontrado: El cliente no tiene el archivo solicitado en su lista. El mensaje de re-solicitud se envía en intervalos de aproximadamente 20 minutos para cada cliente que el peer que envía haya añadido a su cola de descarga (Figura 3.40). El autómata que lo modela es el de la Figura 3.41. 3.2. Análisis de requisitos y funcionalidades de la aplicación En base a lo detallado hasta este punto, resulta sencillo evidenciar que la aplicación a desarrollar necesita una determinada información para poder funcionar correctamente, por lo que los elementos a considerar serían: Información de entrada a la aplicación acerca de los autómatas. Ficheros con trazas de tráco a analizar también como bloque de entrada, o bien una interfaz de red para realizar una captura en vivo. Es decir, un sensor que proporcione información acerca del tráco a analizar. 59 3. Análisis Figura 3.40: Mensaje de re-solicitud de archivo. Figura 3.41: Mensaje de re-solicitud de archivo modelado con autómata de estados nitos. Un programa principal que construya los autómatas y analice las trazas de tráco proporcionado. Una salida que proporcione información acerca del tráco analizado. Por tanto, la estructura principal del programa, que cumpla estos requisitos, sigue la estructura mostrada en la Figura 3.42. En dicha gura, pueden observarse los siguientes bloques, los cuales se detallan a continuación. Sensor El sensor de entrada es el bloque que proporciona datos acerca del tráco que se quiere analizar en busca de un determinado comportamiento. Este sensor puede ofrecer el tráco a la aplicación de dos posibles tipos de fuentes de tráco. La primera de ellas es un chero con trazas de tráco. La segunda es indicar una interfaz de red para realizar una captura 60 3. Análisis de tráco en vivo e introducirla en la aplicación sin necesidad de almacenar los datos en un chero. Los cheros con trazas de tráco deben estar en formato pcap, ya que la biblioteca utilizada en la aplicación (véase Apartado 2.4.2) es capaz de trabajar con este tipo de cheros de manera sencilla. Por tanto, la funcionalidad principal de este sensor es ofrecer a la aplicación información acerca del tráco. Autómatas Tal y como se ha detallado anteriormente, el modelado del protocolo con autómatas de estados nitos es fundamental para comprobar su funcionamiento. Ya que se necesita analizar tráco en busca de determinados patrones de comportamiento, es necesario introducir a la aplicación un almacén de datos con información acerca de los autómatas que modelan el protocolo. Es decir, el objetivo es proporcionar al programa la descripción de los autómatas denidos previamente. Dicha información estará almacenada en un chero. El principal motivo de ser una entrada externa a la aplicación es la exibilidad, ya que las modicaciones sobre estos autómatas pueden ser continuas y variar con el paso del tiempo. De esta manera, se evita la potencial necesidad de modicar el código fuente. Si no se proporcionaran de esta manera, sería una tarea tediosa realizar dichas modicaciones. Para ello es necesario conocer en detalle el protocolo a analizar y poder derivar de él los autómatas de estados nitos correspondientes. Una vez se introduzca esta información en el mencionado chero (véase Sección 4.1.7), la aplicación construirá en memoria la estructura de estos autómatas y ya dispondrá de información suciente como para evaluar el tráco de entrada. Programa principal La funcionalidad básica del programa principal es tomar toda la información de la que dispone en los bloques de entrada, construir los autómatas que se le indican y analizar el tráco para, nalmente, mostrar una salida con determinados resultados. Figura 3.42: Estructura principal del programa. 61 3. Análisis En base al tráco proporcionado, este bloque también debe clasicar los ujos de información reconocidos. Un ujo es el intercambio de datos entre dos determinadas entidades (peers en este caso) durante un tiempo. A grandes rasgos, el programa principal tomará todo el tráco y lo clasicará en ujos de información en base a las características propias de una conexión, estas son, IP y puerto origen y destino. Dado que durante una conexión pueden haber varios ujos, se utilizarán parámetros adicionales para distinguir entre ellos. Como en el protocolo UDP no existen conexiones, el programa principal utilizará otros criterios para poder detectar los ujos de información, como se explicará más adelante. En su labor de análisis del tráco (parsing ) el programa principal puede mostrar, para cada ujo analizado, uno de los siguientes resultados: El ujo de información está siguiendo un comportamiento esperado, ya que se ha logrado modelar mediante uno de los autómatas denidos. Por tanto, se mostrará un mensaje indicando que el ujo responde a un autómata. No existe denido ningún autómata que sea capaz de modelar la información contenida en el ujo que se está examinando. Por tanto, es posible que no estén todos los autómatas que modelan el protocolo, o bien que sí estén todos pero que no logren explicar adecuadamente el ujo observado. Se mostrará un mensaje indicando que el ujo analizado no se ha reconocido. Es posible que un ujo de datos esté incompleto, y que le falte muy poca información para ser modelado mediante un autómata pero que, por alguna razón, este ujo está truncado. Esto se reejará en la aplicación mostrando un mensaje de autómata incompleto. Se considera que un autómata está incompleto cuando se reconocen más del 80 % de los estados, pero no en su totalidad. Este umbral es simplemente orientativo y puede ser congurable por el usuario. Salida El bloque de salida es el que toma los resultados que proporciona el programa principal acerca del tráco analizado. Este bloque representa de forma esquematizada los ujos detectados en el tráco analizado, su correspondencia con autómatas denidos y unas estadísticas globales acerca de las detecciones realizadas. Más concretamente, la información mostrada detallará todas las propiedades de todas las conexiones detectadas con sus ujos de información asociados: IP origen, IP destino, puerto origen y puerto destino; también mostrará la información que se ha intercambiado entre los dos peers a lo largo de esa conexión y, por último, si el ujo de información ha sido reconocido en base a los autómatas introducidos en el archivo de datos de entrada. Asimismo, muestra unas estadísticas sobre el porcentaje de ujos reconocidos, no reconocidos e incompletos. Por tanto, es el bloque que muestra las conclusiones acerca de toda la tarea realizada por el programa principal y es el encargado de clasicar los ujos en acordes a la especicación de autómatas o no. 62 3. Análisis 3.3. Discusión del análisis Tras el estudio del protocolo `eDonkey', así de como el de la extensión proporcionada por `eMule', se ha propuesto un modelado para los diferentes escenarios posibles en dicho protocolo. Dichos escenarios corresponden a diálogos tanto TCP como UDP entre clientes y servidores. Como se comentó anteriormente, los autómatas representan partes o interacciones entre dos determinados peers que usan el protocolo. Por tanto, es necesario establecer un alineamiento entre los eventos que tienen lugar en un ujo de información y los autómatas asociados. Un autómata sucede a otro. Es decir, todos los autómatas están unidos mediante algún punto común. Por ejemplo, el realizado para el establecimiento de conexión entre cliente y servidor (que ya recogía tres posibles escenarios) le sucede el que representa los mensajes intercambiados al inicio de la conexión entre el mismo cliente y servidor. La razón de separarlos es por motivos de complejidad y escalabilidad. Es necesario tener en cuenta que el comportamiento del protocolo va variando con el tiempo, y con él, van surgiendo nuevas versiones que proporcionan nuevos escenarios o modican los ya existentes. Si fuera necesario añadir nuevos autómatas, en esta situación sería sencillo. Sin embargo, si se unica todo en un gran autómata general, la tarea sería mucho más compleja. Una buena propuesta para no tener que actualizar la aplicación sería un nuevo módulo que sea capaz de generar automáticamente modelados en base a la observación del comportamiento del protocolo. Pero sería necesario hacer distinción de lo que es un comportamiento correcto y uno anómalo mediante el aprendizaje de la aplicación en un entorno controlado en el que solamente se produzcan diálogos libres de anomalías, ya que, si no fuera así, cualquier comportamiento sería susceptible de ser catalogado como normal. 63 3. Análisis 64 Capı́tulo 4 Diseño e implementación En este capítulo se detalla la arquitectura de la aplicación, así como de su estructura en módulos y los elementos necesarios para construirlos. Está destinado a explicar detalles de la implementación y diseño del software. 4.1. Estructura modular de la aplicación Una vez se ha propuesto el modelado mediante autómatas de estados nitos en el Capítulo 3 para los diferentes escenarios, en esta sección se analiza la estructura detallada de la aplicación, así como las principales dicultades en su diseño, para poder denir las soluciones propuestas. Más concretamente, se detallan cada una de las partes del programa principal, bloque fundamental denido en la Sección 3.2. Para conseguir implementar el modelado del protocolo `eDonkey' y comprobar su correcto funcionamiento, el programa principal debe tener una estructura muy denida y basada en módulos, para proporcionar al núcleo información suciente para cumplir los requisitos propuestos. Dichos módulos y estructuras se dividirán en las siguientes categorías: Módulo de preprocesamiento. Módulo de detección de ujos. Almacén/clasicador de ujos. Módulo de extracción y análisis de ujos. De esta manera, se utilizará la estructura mostrada en la Figura 4.1, en la cual se detalla en profundidad la estructura interna del programa principal. Como se muestra en la Figura 4.1, la aplicación principal está dividida en una serie de módulos. Los módulos de preprocesamiento y detección de ujos se ejecutan para cada trama analizada, mientras que el módulo de extracción y análisis lo hace paralelamente al resto. Dichos módulos se detallan a continuación. 65 4. Diseño e implementación Figura 4.1: Estructura en módulos del programa principal. 4.1.1. Preprocesamiento Este módulo es el encargado de tomar como entrada el tráco que le proporciona el sensor de manera externa. En esta primera fase se preparan las tramas antes de enviarlas al siguiente módulo. La misión principal del módulo de preprocesamiento es realizar un ltrado en el que solamente pasan tramas útiles de cara al análisis. Este tipo de tramas son aquellas que contienen segmentos TCP y UDP. De esta manera, se ahorra carga computacional a otros módulos, ya que el tráco entrante está siendo limitado a aquel que contiene información relevante para su análisis. Este módulo también realiza una distinción de las tramas que tienen carga útil (pay- load ) con las que no, ya que pueden ser interpretadas de manera errónea por el módulo de detección de ujos. Por tanto, el módulo de preprocesamiento examina tanto las cabeceras de las tramas entrantes para poder ltrarlas en base a una determinada regla establecida (en este caso, segmentos TCP y UDP), así como la carga útil de dichas tramas, para descartar aquellas que no tengan un tamaño acorde con el esperado. 4.1.2. Detección de ujos El módulo detector de ujos es uno de los más importantes y es donde reside una de las partes más importantes de la aplicación. Es el encargado de clasicar las tramas recibidas por el módulo de preprocesamiento en ujos de información en base a alguna conexión entre dos peers. Clasicar estos ujos no es una tarea sencilla ya que existen determinados escenarios que es necesario contemplar. Por tanto, los escenarios contemplados son los siguientes: Que en una conexión entre dos peers se produzcan varios ujos de información. Por ejemplo, un cliente y un servidor pueden intercambiar, durante una misma conexión, varios ujos pertenecientes a búsquedas de archivos. 66 4. Diseño e implementación Que se produzcan varias conexiones en paralelo, ya que el sensor puede proporcionar información de varias fuentes al mismo tiempo. Que un mensaje `eDonkey' esté separado en varias tramas. Que una trama contenga más de un mensaje del protocolo. El módulo de preprocesamiento detallado anteriormente, ayuda a la detección de ujos mediante una tarea adicional. Esta es la de noticar la nalización de un ujo, por haber nalizado la conexión entre dos peers. Esto lo realiza mediante la recepción de segmentos TCP cuyo bit de cabecera FIN esté activo. En ese caso, signicará la nalización de una conexión y, por tanto, de su ujo (o ujos) asociado (nótese que, como se detalló en 2.2, dentro de ese ujo aparente pueden existir varios de ellos). En este momento envía al módulo de extracción y análisis dicho ujo para su examen. Mediante esta tarea, se evita enviar al módulo de extracción y análisis tráco innecesario ya que, debido a que se ha detectado el nal de un ujo, evita realizar esta tarea al módulo siguiente. Esto es sólo aplicable al protocolo TCP. Para el UDP se utilizará el procedimiento de ujos antiguos detallado en 4.1.4. El módulo de detección de ujos resuelve la tarea de separar los mensajes intercambiados entre dos peers y clasicarlos en ujos. Sin embargo, no contempla que, dentro de la conexión analizada, pueden existir varios ujos de información, como se explicó anteriormente. Por lo que dentro de lo que en este módulo se considera un ujo, pueden existir realmente varios de ellos. Pero este problema lo resuelve el módulo de extracción y análisis, como se explicará más adelante. Como estas situaciones anteriores, pueden producirse muchos casos, producto de las combinaciones de tráco proporcionadas por el sensor y de la actividad que tenga el protocolo en un momento determinado. Es decir, numerosos mensajes de numerosas conexiones pueden aparecer entremezclados. Por tanto, la detección de ujos de información no es una tarea sencilla. La detección de ujos sigue los siguientes pasos: 1. En el caso del protocolo `eDonkey', los mensajes intercambiados entre los peers tienen un campo protocolo, el cual almacena una determinada información característica del protocolo. En protocolo `eDonkey', dicho campo toma el valor 0xE3. Como se ha visto en el Capítulo 3, `eMule' proporciona una serie de funcionalidades adicionales al protocolo `eDonkey'. Los mensajes pertenecientes a estas extensiones toman el valor 0xC5 en el campo protocolo mencionado. Por tanto, las tramas recibidas del módulo de preprocesamiento son examinadas en busca de características propias del protocolo P2P que se está analizando. En este caso, se busca que el campo protocolo tome los valores mencionados. En cierto modo, este paso realiza un ltrado de las tramas que únicamente pertenecen al protocolo analizado. 2. Para cada una de las tramas seleccionadas, se buscan en ellas los rasgos característicos de una determinada conexión, es decir, la IP origen y destino, y los puertos origen y destino. Para ello, se accede a la cabecera de dichas tramas, en busca de la información mencionada. 67 4. Diseño e implementación 3. Una vez llegado a este punto, se puede crear una estructura de datos que almacene un ujo de información, ya que se dispone de datos sucientes. A este ujo se le añade una marca de tiempo, que se corresponde con el instante en el que se recibió el primer paquete de dicho ujo entre los dos peers. Las tramas llegadas hasta este punto (las pertenecientes a `eDonkey' o su extensión `eMule') poseen un campo tipo que almacena una cifra en hexadecimal que indica qué tipo de mensaje es (establecimiento de conexión, búsqueda de archivos, etc.). La información contenida en este campo se añadirá a la estructura de datos que conforma un ujo de información. El campo tipo puede aparecer más de una vez dentro de la misma trama. En ese caso se añadirá, de la misma manera que se indicó anteriormente, a la estructura de datos que almacena información acerca del ujo. 4. Por último, se busca en el almacén/clasicador global si existe algún ujo de información con las mismas características del obtenido en el paso 3 (mismas IP y mismos puertos). En caso armativo, signica que ya existía una conexión idéntica, por lo que los datos obtenidos en el paso 3 son datos nuevos pertenecientes a una conexión que ya estaba contemplada. Por tanto, todos los campos tipo recopilados en el paso anterior, se añaden junto con los ya existentes en la estructura de datos dentro del almacén/clasicador de ujos. En caso contrario, signica que se han obtenido datos de una conexión nueva, por lo que se añade un ujo nuevo al almacén/clasicador de ujos. El problema de detectar varios subujos dentro de un ujo de información concreto se resuelve como se explica a continuación. Cuando se extrae un ujo del almacén/clasicador, se envía a analizar (parsing ) como se verá más adelante. Si el módulo de extracción y análisis, al comparar el ujo con los autómatas, llega a un estado nal sin haber terminado de examinar todos los mensajes del ujo, entonces se entiende que dentro de ese ujo había otro más pequeño, por lo que el resto de mensajes que no se han examinado se vuelven a incluir en el almacén/clasicador. 4.1.3. Almacén/clasicador de ujos El almacén/clasicador de ujos es una estructura de datos global a toda la aplicación. Su funcionalidad básica es servir de almacén para los ujos que le proporciona el módulo de detección de ujos. Es un contenedor en el que se almacenan estructuras de datos que se corresponderían con contenido acerca de conexiones y ujos de información. Aunque puedan analizarse varios ujos simultáneamente, hay que tener en cuenta que esta estructura es global a toda la aplicación, por lo que habrá que tomar precauciones para evitar problemas de inconsistencia, como se verá más adelante. Este almacén/clasicador es utilizado por dos módulos, ya que el de detección de ujos inserta nuevos elementos, mientras que el módulo de extracción y análisis, como su propio nombre indica, extrae ujos para posteriormente analizarlos. 68 4. Diseño e implementación 4.1.4. Extracción y análisis El último de los módulos es el de extracción y análisis, que lleva a cabo la tarea de comparar los ujos del almacén/clasicador con la estructura de autómatas existente en la aplicación. Denominamos a esta tarea como parsing. Para cumplir esta funcionalidad, este módulo debe considerar cuándo un ujo está listo para ser analizado, por lo que se plantea el problema de saber si una conexión se da por terminada o, por el contrario, va a seguir añadiendo información al ujo del almacén/clasicador. Para resolver este problema, este módulo extrae los ujos considerados como antiguos y los analiza. Un ujo se considera antiguo cuando lleva un determinado tiempo sin actualizarse. Este tiempo es congurable y por defecto está establecido a 5 segundos. Por este motivo, todos los ujos del almacén/clasicador llevan una marca de tiempo. El criterio utilizado para la consideración de ujos antiguos se detalla a continuación, aunque se plantean dos problemas principales: 1. Como se explicó anteriormente, el sensor puede proporcionar trazas de tráco tanto de un chero estático como de una captura en vivo, procedente de una interfaz de red. El análisis de un chero almacenado en disco se lleva a cabo relativamente rápido si es comparada con una captura en vivo. En esta última, no se puede saber a priori con qué velocidad se van a capturar las tramas, puesto que la actividad entre dos determinados peers en una conexión depende en parte del usuario, ya que puede provocar voluntariamente una determinada actividad. Por ejemplo, puede existir una conexión entre cliente y servidor abierta durante mucho tiempo y, sin embargo, no existir ningún tipo de actividad. 2. Es necesario considerar que una conexión entre dos peers puede haber nalizado y la aplicación no ser consciente de ello, debido a que el tipo de conexión sea UDP, puesto que nunca se recibe una trama de nalización de conexión, como se explicó en la Sección 2.2. En ambos casos es importante considerar el criterio de ujo antiguo: Se establece una variable global que indica un umbral de tiempo máximo. Si un ujo lleva sin actualizarse igual o más tiempo del indicado en este umbral, se considera una conexión terminada, por lo que se extrae del almacén/clasicador y se analiza. Para proporcionar exibilidad a la aplicación, este umbral puede ser modicado sin repercutir negativamente en otros módulos. Por tanto, la tarea principal del módulo de extracción y análisis es examinar el almacén/clasicador en busca de ujos antiguos. Cuando encuentre un ujo apto para ser examinado, lo extrae del almacén/clasicador y proceda a su análisis. 4.1.5. Justicación de los módulos La estructura modular de la aplicación está diseñada de manera que aporte exibilidad. Los módulos podrían modicarse sin excesiva dicultad con el objetivo de ser útiles en 69 4. Diseño e implementación el análisis de otros protocolos. El módulo de preprocesamiento realiza un ltrado de tramas y libera de carga al núcleo de la aplicación, por lo que su funcionalidad se hace evidente. El módulo de detección de ujos es fundamental a la hora de encontrar, parcialmente, los ujos de información dentro de varias conexiones. El almacén/clasicador es una estructura intermediaria entre dos módulos. Es esencial disponer de una estructura de este tipo para poder almacenar información acerca de los ujos y conexiones detectadas. Por último, el módulo de extracción y análisis realiza la tarea nal, en la que extrae ujos según un determinado criterio y realiza el parsing de estos, proporcionando unos resultados ya visibles. 4.1.6. Diseño global de la implementación El programa se ha diseñado de manera multihebrada. Es posible ejecutarlo para varios cheros e interfaces de red al mismo tiempo, los cuales se analizarán concurrentemente para, nalmente, mostrar un resultado global. Por cada chero con trazas o interfaz a analizar, se crea una hebra inicial que se encarga de procesar su información por separado. En la aplicación, la estructura del almacén/clasicador de ujos es global a todas las hebras. Sin embargo, el módulo de preprocesamiento y parte del de detección de ujos los ejecutan cada hebra independientemente de las demás. El motivo de esto es que una parte del módulo de detección de ujos accede al almacén/clasicador como se puede ver en la Figura 4.1. Como esta es una estructura global, es necesario controlar las hebras para no crear problemas de inconsistencia. Debido al diseño multihebrado, es necesario considerar el problema de la exclusión mutua, ya que existen secciones críticas que pueden ser ejecutadas por varias hebras a la vez, pudiendo producir un resultado inconsistente. La sección crítica sería, en este caso, los accesos al almacén/clasicador de tramas, ya que está siendo actualizado por múltiples hebras que analizan los módulos de entrada. Por tanto, es necesario garantizar que no se produce un acceso simultáneo al almacén/clasicador de ujos por varias hebras. Mediante el uso de mutexes de la biblioteca `Pthread' (véase Sección 2.4.3) se logra este objetivo. Al mismo tiempo que la ejecución del módulo de preprocesamiento y detección de ujos, existe inicialmente otra hebra independiente que ejecuta el módulo de extracción y análisis de ujos del almacén/clasicador. Esta hebra se encarga de revisar este almacén/clasicador y comprobar periódicamente si existen ujos antiguos. El problema de este modo de procesamiento es que podrían existir múltiples hebras añadiendo ujos al almacén/clasicador mientras que sólo una se encargaría de la extracción y análisis; es decir, podría producir un desbordamiento del almacén/clasicador si aumenta demasiado de tamaño. Esto se soluciona mediante otro diseño multihebrado: el hilo que controla el módulo de extracción y análisis comprueba periódicamente el tamaño del almacén/clasicador; si el tamaño es mayor que un umbral establecido, genera otras hebras que ayudan a liberar carga de la principal. Cuando estas hebras nalizan su trabajo, mueren automáticamente y permanece la principal que controlaba este módulo. 70 4. Diseño e implementación Esta solución multihebrada del módulo de extracción y análisis plantea nuevamente un problema: el acceso en exclusión mutua al almacén/clasicador. Pero se soluciona de la misma manera que anteriormente, ya que se usan mutexes que garantizan la exclusión mutua. 4.1.7. Formato del chero de autómatas Un usuario con algunas nociones acerca del funcionamiento de la aplicación podría introducir información acerca de nuevos autómatas, modicar los ya existentes, o eliminar alguno de ellos. En denitiva, es capaz de manejar la información que tiene la aplicación acerca del protocolo. Para hacer posible esto, se ha denido un tipo de lenguaje en el que escribir los autómatas. Estos residen en un chero, el cual se puede editar para modicar dicha información. Las características principales de la sintaxis de este chero son las siguientes: El carácter ` %' indica un comentario. Se deben comentar líneas completas, siendo este carácter el primero de la línea. No se admiten líneas en blanco en el chero, ya que se entiende que no están comentadas y, por lo tanto, tienen algún signicado. Todos los estados que conforman todos los autómatas se consideran un solo conjunto y siguen una numeración. Es decir, si se escribe un autómata con cinco estados, se numerarán 0, 1, 2, 3 y 4. Si luego se escribe otro autómata con tres estados, aunque sea independiente del anterior, la numeración de los estados será 5, 6 y 7. Y así sucesivamente. El nal de línea se indica con el carácter `$' o bien con el carácter `*' si es el estado nal, en el cual el autómata deberá llevar un nombre. El formato de las líneas de descripción de un autómata es: NUM_ESTADO S/N S/N [# CADENA NUM_ESTADO_DESTINO [# ... ]] $ [NOMBRE_AUTOMATA *] 1. NUM_ESTADO 2. S/N indica el número del estado. Por ejemplo, 0 o 1. indica si el estado es inicial o no, en el primer caso. En el segundo caso indica si el estado es nal o no. 3. # CADENA NUM_ESTADO_DESTINO indica la relación de transiciones. Es decir, hace referencia a la cadena asociada a la transición y al número del estado al que se transita. Puede haber tantas cadenas como se desee. Se indica que no hay más transiciones con 4. $ NOMBRE_AUTOMATA indica el nombre del autómata. Es necesario indicarlo cuando el estado es nal. 71 4. Diseño e implementación Se muestra el proceso de creación del archivo de descripción del autómata representado en la Figura 4.2. Si se quisiera escribir con la sintaxis indicada en este autómata, sería necesario seguir los siguientes pasos: El estado q0 se nombrará como `0', suponiendo que sea el primer estado del chero de autómatas. Si no es así, se continuará la numeración del último estado que hay. q1 De la misma manera, el estado se nombrará como `1' y el estado q2 se nombrará como `2'. Tras el número identicador del estado, se ha de indicar si los estados son iniciales y/o nales. Por tanto, para el estado es nal. Para el estado q1 por último, para el estado q0 se indicará `S' y `N' ya que es inicial y no se indicará `N' y `N', ya que ni es inicial ni es nal. Y q2 se indicará `N' y `S' ya que no es inicial y es nal. Tras esto, se añaden unos separadores para indicar las posibles transiciones hacia otros estados. Para el estado transición hacia el estado q1 . q0 , se añadirá el separador `#', ya que tiene una Para el estado tiene una transición hacia el estado q2 . q1 se añadirá el separador `#', ya que Por último, para el estado q2 se añadirá el separador `$', ya que no tiene transiciones hacia ningún otro estado. Tras indicar los separadores, es necesario mostrar las transiciones. Para el estado q0 , se debería indicar `AA 1' ya que, si recibe el mensaje `AA' transita al estado numerado como `1'. Para el estado q2 se ha de indicar `BB 2', ya que, si recibe el mensaje `BB' transita al estado numerado como `2'. Para el estado q2 no se escribiría nada, ya que no tiene transiciones. El siguiente paso es indicar que los autómatas no tienen ninguna transición más. Para esto, en el estado q0 se escribirá el carácter `$' para indicar que no tiene más transiciones. Para el estado q1 también se escribirá el carácter `$' por el mismo motivo. El último paso es indicar el nombre del autómata. Hasta este punto, las descripciones de todos los estados terminan con el carácter `$'. Para el estado q2 , que es el estado nal, se ha de indicar el nombre. Para ello, tras el carácter `$' se escribe el nombre y se indica que el autómata llega a su n con el carácter `*'. El resultado nal para el autómata de la Figura 4.2 sería un archivo con el siguiente contenido: Figura 4.2: Autómata de ejemplo. 72 4. Diseño e implementación % 0 1 2 Sintaxis del autómata de la Figura 4.2 S N # AA 1 $ N N # BB 2 $ N S $ Ejemplo * Se muestra ahora un ejemplo más complejo en la Figura 4.3. Se supondrá que el autómata de la Figura 4.3 se quiere añadir a continuación del autómata de la Figura 4.2. Los pasos a seguir son: El estado q0 se nombrará como `3', ya que el último estado del autómata de la Figura 4.2 es el estado `2'. Siguiendo esta misma regla, los estados q1 , q2 y q3 se numerarán como `4', `5' y `6' respectivamente. Los siguientes caracteres para los estados q0 , q1 , q2 y q3 serán `S N', `N N', `N N' y `N S' respectivamente, siguiendo la regla de estados iniciales y nales. Los separadores para q0 , q1 , q2 y q3 son `#', `#', `# y `$' respectivamente, siguiendo la norma del carácter añadido si tienen transiciones o no. Los siguientes caracteres para q0 serán: `AA 4', separador `#', `CC 6', separador `#', `DD 5', indicador de n de transiciones `$'. Los siguientes caracteres para q1 serían: `BB 6', indicador de n de transiciones `$'. Los siguientes caracteres para q2 serían: `EE 6', indicador de n de transiciones `$'. El siguiente carácter para q3 Por último, en el estado nal sería: indicador de n de transiciones `$'. q3 se añadiría: `Ejemplo 2 *', para indicar el nombre del autómata y su n. El chero resultante sería el siguiente: Figura 4.3: Autómata de ejemplo. 73 4. Diseño e implementación % 0 1 2 % % % % 3 4 5 6 Sintaxis del autómata de la Figura 4.2 S N # AA 1 $ N N # BB 2 $ N S $ Ejemplo * Sintaxis del autómata de la Figura 4.3 S N # AA 4 # CC 6 # DD 5 $ N N # BB 6 $ N N # EE 6 $ N S $ Ejemplo 2 * Como se puede apreciar, es sencillo añadir autómatas nuevos en la especicación. Sólo es necesario continuar las numeraciones de los estados, y añadir, para cada uno de ellos, sus propiedades y transiciones en una sola línea. 4.2. Descripción de las estructuras de datos utilizadas En base a la Figura 4.1, la aplicación está construida mediante diversos módulos de procesamiento, cada uno de ellos destinado a realizar una tarea independiente. El diseño especíco de la aplicación se corresponde con el detallado en los siguientes apartados. 4.2.1. Diseño de los estados de los autómatas Los autómatas de estados nitos están divididos en uno o más estados. Como se explicó en 2.1, se puede transitar de un estado a otro teniendo en cuenta una serie de palabras aceptadas. Para realizar el diseño de los estados que componen un autómata, se ha denido una clase a tal efecto. La clase `estado' es la base del funcionamiento de la aplicación. Agrupa todas las funciones para el manejo de estados de un autómata. Un estado se considera un conjunto de elementos y está diseñado, en base a sus funcionalidades, de la siguiente manera: Un identicador (un número entero) único globalmente. Es decir, dado un identicador, se puede conocer con certeza a qué estado pertenece. Una variable booleana que indica si el estado es inicial. Una variable booleana que indica si el estado es nal. Un nombre que proporciona una descripción de ese estado (una cadena de caracteres). Un puntero a una estructura `mensaje' (se detalla a continuación). 74 4. Diseño e implementación Una estructura `mensaje', la cual indica las posibles transiciones que tiene un estado hacia otros estados y los motivos por los cuales transitaría. Dicha estructura está compuesta por: Un motivo por el cual transitaría a otro estado (una cadena de caracteres). En este caso, un motivo es la recepción de determinados mensajes en el protocolo. Un puntero a otro mensaje siguiente (puede haberlo o no). Un puntero hacia el estado al cual transitaría en el caso de que se veriquen ciertas condiciones relacionadas con un determinado mensaje. Lo que se implementa es una lista enlazada con los diferentes mensajes que pueden aparecer en cada estado. De forma esquemática, un estado se asemeja a la estructura mostrada en la Figura 4.4. A continuación se muestran una serie de ejemplos para ilustrar el funcionamiento de la clase `estado'. Ejemplo 1: Se muestra un autómata con un solo estado. En la Figura 4.5 se muestra el autómata en cuestión y en la Figura 4.6 se muestra la correspondencia de dicho autómata con la estructura de datos utilizada. Ejemplo 2: Autómata con un solo estado. Acepta un número indeterminado de mensajes identicados con el tipo `44' (Figuras 4.7 y 4.8). Ejemplo 3: Autómata con tres estados (Figura 4.9). Se muestra el objeto `estado' para el estado q0 en la Figura 4.10. Figura 4.4: Esquema de un objeto de la clase `estado'. Figura 4.5: Autómata con un estado. 75 4. Diseño e implementación Figura 4.6: Objeto `estado' para el estado de la Figura 4.5.. Figura 4.7: Autómata con un estado. Figura 4.8: Objeto `estado' para el estado de la Figura 4.7. Figura 4.9: Autómata con tres estados. 76 4. Diseño e implementación Figura 4.10: Objeto `estado' para el estado de la Figura 4.9. Los métodos que se implementan en esta clase se detallan en el Apéndice A. 4.2.2. Diseño de los autómatas Como se explicó en la Sección 2.1, un autómata está formado por uno o más estados. En base a la especicación de los autómatas indicada en el archivo de entrada del programa principal, pueden existir cero o más autómatas en la aplicación. La clase `automatas' alberga todos los que se han denido. Es decir, esta clase contendrá un conjunto de estados entrelazados entre sí mediante punteros. Es por esto que la clase `estado' es una generalización de `automatas' o, dicho de otra manera, se dice que la clase `automatas' hereda (o es una especicación) de la clase `estado'. El motivo de esto es, como se ha explicado, que la clase `automatas' está compuesta por un número determinado de estados. Por tanto, esta clase debe tener conocimiento de cómo es un objeto `estado', así como de todas sus funciones, para poder manejarlo con otras funciones más especícas y poder proporcionar un nivel de encapsulado mayor. Una instanciación de la clase `automatas' está compuesta simplemente por un vector dinámico, en el que cada casilla alberga un objeto `estado'. El desplazamiento de un estado a otro mediante los punteros que se encuentran dentro de sus mensajes equivaldría a moverse a través de las casillas de este vector dinámico. Por tanto, con un objeto de la clase `automatas' se puede representar por completo un conjunto de autómatas reales y comprobar su funcionamiento. Los métodos pertenecientes a esta clase se detallan en el Apéndice A. 4.2.3. Diseño de un ujo de información Como se explicó en la Sección 2.2, una conexión entre dos peers se identica median- te cuatro elementos: Las IP origen y destino y los puertos origen y destino. La clase `datosFlujo' se basa en la existencia de ujos de información dentro de una conexión entre cliente y servidor, o bien entre dos clientes. En el protocolo UDP, también existen estas características, pero no se necesita un establecimiento de conexión previo ni una nalización como ocurre en el contexto TCP. Por tanto, la estructura de datos es igualmente válida para los dos protocolos. Mediante estos ujos, los peers intercambian cierta cantidad de información relacionada con el protocolo. 77 4. Diseño e implementación La clase `datosFlujo' incluirá la información de dichos ujos, junto con otra añadida ya que, como se explicará más adelante, es necesario tener en cuenta el momento en el que ocurren cambios en el ujo de información y qué información se está intercambiando. Por lo tanto, esta clase tendrá los siguientes elementos: Una cadena de caracteres donde se almacenará la IP origen. Una cadena de caracteres donde se almacenará la IP destino. Un número entero indicando el puerto origen. Un número entero indicando el puerto destino. Una variable en coma otante de doble precisión para indicar el momento (times- tamp ) en el que suceden cambios en un determinado ujo de información. Estos cambios se reeren a la adición de información nueva a un objeto de esta clase; en el momento en el que se añada algún dato nuevo, se considerará que se ha producido un cambio y se actualizará el timestamp. Esta variable es útil para determinar cuándo un ujo es antiguo y puede ser analizado. Un vector de cadenas de caracteres en el que se almacenará, con el paso del tiempo, la información intercambiada entre dos peers dentro de la misma conexión, es decir, contendrá determinados datos del protocolo. Estos datos son los tipos de los mensajes intercambiados. Por tanto, la estructura de un objeto de la clase `datosFlujo' será la de la Figura 4.11. Los métodos pertenecientes a esta clase se detallan en el Apéndice A. 4.2.4. Diseño del almacén/clasicador de ujos Como en el tráco proporcionado por el sensor es muy probable que existan numerosas conexiones (y por tanto, numerosos ujos de información), es necesario un almacén/clasicador de ujos global que almacene toda esta información. La clase `clasicadorFlujos' se ha diseñado con tal n, ya que es capaz de almacenar un conjunto de objetos de la clase `datosFlujo'. Es decir, la clase `clasicadorFlujos' tiene una sola variable miembro, consistente en un vector dinámico (es decir, que varía su tamaño dinámicamente) en el que en cada casilla almacena un objeto de la clase `datosFlujo'. Esto explica la herencia entre estas dos clases: la clase `datosFlujo' es una generalización de la clase `clasicadorFlujos', ya que esta última está formada por un número determinado de objetos de la clase `datosFlujo'. Por ello, es necesario que sepa manejarlos, conozca todas sus funciones y sus variables miembro, ya que va a necesitar modicarlos para darle una estructura de un almacén/clasicador aparente, y mostrar un mayor grado de encapsulado y simplicidad a la hora de utilizar un objeto de esta clase. También existe una relación de agregación de composición entre la clase `autómatas' y la clase `clasicadorFlujos', ya que la primera está compuesta de elementos de la clase `clasicadorFlujos', aunque sólo está formado por uno. Es decir, la relación básica entre las clases sería la mostrada en la Figura 4.12. 78 4. Diseño e implementación Figura 4.11: Estructura de un objeto de la clase `datosFlujo'. Figura 4.12: Relaciones entre las clases diseñadas. 4.2.5. Diagrama de clases Partiendo de las estructuras de datos detalladas anteriormente, se puede elaborar un diagrama completo que muestre los métodos y las relaciones entre las clases. En la Figura 4.13 se muestra el diagrama detallado el cual representa la elaboración de clases dentro de la aplicación que se ha desarrollado. En él se pueden distinguir varios elementos: las clases diseñadas, las relaciones entre ellas, las variables miembro y los métodos implementados en cada una de ellas. Existen dos relaciones de herencia principales, las cuales se ven reejadas en el diagrama de clases de diseño: La primera de ellas es una generalización de la clase `automatas' a la clase `estado' y la segunda es una generalización de la clase `clasicadorFlujos' a la clase `datosFlujo'. La segunda de las relaciones es una agregación de composición, o solamente composición entre la clase `clasicadorFlujos' y `automatas'. El motivo de eso es que la clase `automatas' está compuesta por elementos del tipo `clasicadorFlujos'. La multiplicidad de los extremos indica que debe existir un objeto de la clase `automatas' para que exista un objeto de la clase `clasicadorFlujos', y sólo existirá uno. 79 4. Diseño e implementación Figura 4.13: Diagrama de clases de diseño para la aplicación desarrollada. 80 Capı́tulo 5 Evaluación El objetivo de este capítulo es comprobar el buen funcionamiento de la aplicación. Para ello, primero se muestran una serie de pruebas a ejecutar, que vericarán su buen funcionamiento. Por último, se realizarán pruebas para medir la velocidad y el rendimeinto de la aplicación. 5.1. Diseño de las pruebas de evaluación Con el objetivo de facilitar la evaluación de la aplicación, se han elaborado una serie de chas de pruebas para la aplicación, las cuales se detallan a continuación. Las pruebas se han diseñado de manera que pueda probarse las funcionalidad de la aplicación. Por ello, se comienza con pruebas simples para avanzar en pruebas de mayor complejidad, que requieran más carga computacional. Con las pruebas propuestas se pretende evaluar el buen funcionamiento de la aplicación, es decir, comprobar que, para una serie de cheros con trazas de tráco, es capaz de reconocer ujos de información acordes con la especicación de autómatas introducida. En las pruebas propuestas se muestra la conguración del chero de autómatas y se introducirán cheros con trazas de tráco, adquiridos en situaciones controladas, por lo que también se detallará el resultado esperado. Asimismo, se muestra el contenido de los cheros con trazas de tráco, para poder comprender mejor los resultados obtenidos. Es muy importante destacar que las versiones de los autómatas realizados son una mera referencia, puesto que la versión indicada puede no coincidir con la actual. La especicación de autómatas está escrita para versiones del cliente `eMule' del año 2008, aunque también incluye algunas del año 2009. Los cheros de prueba son los siguientes: 1. 1-establecimiento_conexion.pcap. 2. 2-buscar.pcap. 3. 3-cliente_cliente.pcap. 81 5. Evaluación 4. 4-de_todo.pcap. En la Figura 5.1 se muestra una tabla con un resumen estadístico de los cheros de prueba. 5.1.1. Ficheros de trazas Son cheros con trazas de tráco que se han obtenido en determinadas situaciones. Para ello, se ha hecho uso de la aplicación `wireshark' y `eMule' (véase Capítulo 2). Fichero 1 Este chero contiene los mensajes intercambiados entre dos peers cliente y servidor, los cuales realizan un establecimiento de conexión. En la Figura 5.2 se muestran las estadísticas del uso de protocolos en el chero. En este chero existen ujos asociados con el establecimiento de conexión entre un cliente y un servidor. Fichero 2 El segundo de los cheros de prueba se corresponde con el tráco producido entre un cliente y un servidor con motivo de una búsqueda de archivos, por lo que existirán ujos asociados con las búsquedas de archivos. En la Figura 5.3 se muestran estadísticas en el uso de protocolos. Fichero Tiempo entre el primer Bytes totales y el último paquete transmitidos 18 0.368 s. 2306 2 4 2.161 s. 345 3 180 2.560 s. 19984 4 4959 232.919 s. 1672320 1 Paquetes capturados Figura 5.1: Estadísticas generales de los cheros de prueba. º Figura 5.2: Estadísticas del uso de protocolos para el chero de pruebas n 1. 82 5. Evaluación º Figura 5.3: Estadísticas del uso de protocolos para el chero de pruebas n 2. Fichero 3 El tercer chero corresponde con el tráco producido en una conexión entre dos clientes. Es algo más complejo, puesto que contiene más cantidad de tráco que los ejemplos anteriores. En él existen ujos asociados a la conexión entre dos clientes, como puede ser handshakes iniciales. En la Figura 5.4, al igual que en los ejemplos anteriores, se muestra las estadísticas del uso de protocolos. Fichero 4 Para nalizar, el último de los cheros contiene una gran cantidad de trazas de tráco, ya que contiene mensajes de todo tipo, tanto de cliente-cliente, como de cliente-servidor, por lo que existen ujos de todo tipo, estos pueden ser, establecimiento de conexión, secuencia de inicio de conexión, etc. En la Figura 5.5 las estadísticas del uso de protocolos. 5.1.2. Prueba 1 º La prueba se realizará con el chero n 2. El archivo de descripción de autómatas contiene el autómata correspondiente a Búsqueda de archivos mostrado en la Figura 5.6, por lo que el contenido del chero es el siguiente: º Figura 5.4: Estadísticas del uso de protocolos para el chero de pruebas n 3. 83 5. Evaluación º Figura 5.5: Estadísticas del uso de protocolos para el chero de pruebas n 4. Figura 5.6: Autómata correspondiente a Búsqueda de archivos. % 0 1 2 % Búsqueda de archivos S N # 16 1 $ N N # 33 2 $ N S $ Busqueda de archivos * Como se puede ver, en la especicación de autómatas se ha incluido información suciente como para que el contenido del chero de trazas sea reconocido, por lo que se espera que se reconozcan todos los ujos. 5.1.3. Prueba 2 En esta prueba se incluirán en la especicación de autómatas algunos nuevos. Estos º son, Establecimiento de conexión, Secuencia de inicio de conexión y Búsqueda de archivos. Se ejecutará con el chero n 1. Los autómatas introducidos son en el chero de especicación son los mostrados en las Figuras 5.7, 5.8 y 5.9, por lo que el contenido del chero es el siguiente: Figura 5.7: Autómata correspondiente a Establecimiento de conexión. 84 5. Evaluación Figura 5.8: Autómata correspondiente a Secuencia de inicio de conexión. Figura 5.9: Autómata correspondiente a Búsqueda de archivos. % Establecimiento de conexión 0 S N # 01 1 $ 1 N N # 40 2 $ 2 N N # 34 3 $ 3 N S $ Establecimiento de conexion * % % % Secuencia de inicio de conexión 4 S N # 14 5 $ 5 N N # 32 6 $ 6 N N # 41 7 $ 7 N S $ Secuencia de inicio de conexion * % % % Handshake inicial 8 S N # 01 9 $ 9 N N # 4C 10 $ 10 N S $ Handshake inicial * % % Según la especicación indicada, el resultado esperado es que se reconozcan todos los ujos que existe en las trazas de tráco, ya que la especicación de los autómatas supuestamente incluye información suciente. 5.1.4. Prueba 3 Se tomará el chero de pruebas y la misma especicación de autómatas que en la Prueba 2, con una modicación, ya que en el chero de trazas de tráco se borrará uno de los mensajes. Este mensaje será aquel que contiene los mensajes con campo tipo con los valores `32' y `41' correspondientes a la Figura 5.8. El resultado esperado es que el ujo correspondiente a este autómata no se reconozca. No se mostrará como incompleto porque no se cumple el requisito de reconocer el 80 % de los mensajes. 85 5. Evaluación 5.1.5. Prueba 4 En esta prueba se utilizará también el mismo procedimiento que en la Prueba 3, pero en este caso se desea comprobar el reconocimiento de los ujos incompletos. En el código fuente está indicado que un autómata se considera incompleto cuando se reconocen más del 80 % de los estados. Para poder probar esto, este dato sufrirá una modicación y se disminuirá al 30 %. De esta manera, el ujo que en la Prueba 4 no se reconocía, ahora se espera que se muestre como incompleto, en lugar de no reconocido. 5.1.6. Prueba 5 Ahora la especicación de autómatas es algo más completa, ya que su contenido será el mostrado en las Figuras 5.10, 5.11, 5.12, 5.13, 5.14 y 5.15. Los autómatas añadidos han sido Búsqueda de archivos, Nueva secuencia de inicio de conexión y Ofrecer cheros. Por tanto, el contenido del chero es el siguiente: Figura 5.10: Autómata correspondiente a Establecimiento de conexión. Figura 5.11: Autómata correspondiente a Secuencia de inicio de conexión. Figura 5.12: Autómata correspondiente a Búsqueda de archivos. Figura 5.13: Autómata correspondiente a Handshake inicial. 86 5. Evaluación Figura 5.14: Autómata correspondiente a Nueva secuencia de inicio de conexión. Figura 5.15: Autómata correspondiente a Ofrecer cheros. % Establecimiento de conexión 0 S N # 01 1 $ 1 N N # 40 2 $ 2 N N # 34 3 $ 3 N S $ Establecimiento de conexion * % % % Secuencia de inicio de conexión 4 S N # 14 5 $ 5 N N # 32 6 $ 6 N N # 41 7 $ 7 N S $ Secuencia de inicio de conexion * % % % Búsqueda de archivos 8 S N # 16 9 $ 9 N N # 33 10 $ 10 N S $ Busqueda de archivos * % % % Handshake inicial 11 S N # 01 12 $ 12 N N # 4C 13 $ 13 N S $ Handshake inicial * % % % Nueva secuencia de inicio de conexión 14 S N # 38 15 $ 15 N N # 14 16 $ 16 N N # 32 17 $ 87 5. Evaluación 17 N N # 41 18 $ 18 N S $ Nueva secuencia de inicio de conexion * % % % Ofrecer ficheros 19 S N # 15 20 $ 20 N S $ Ofrecer ficheros * % º El chero utilizado en este caso es el n 3. Ya que el contenido del chero es bastante amplio y no se conoce a priori la cantidad de ujos existentes, se espera que se reconozcan los ujos asociados con los autómatas especicados, ya que, en el escenario contemplado en el chero de pruebas, se intercambia bastante información. De toda esta información, el chero de autómatas sólo la contiene parcialmente. 5.1.7. Prueba 6 º En esta prueba se utilizará la misma especicación de autómatas que en la Prueba 5. En este caso, el chero utilizado es el n 4, el cual contiene trazas de tráco de todo tipo. En este caso, tampoco se conoce a priori su contenido pero, dada la especicación de los autómatas, se considera que se reconocerán los ujos existentes que se correspondan º con la especicación en el chero de autómatas. De la misma manera que en la Prueba 5, en el chero n 4 se intercambia gran cantidad de información, de la cual sólo se especica una parte de ella en el chero de especicación de autómatas. 5.1.8. Prueba 7 º º º º Con el n de comprobar el buen funcionamiento de la concurrencia de la aplicación, se realizará la evaluación de la aplicación para los cheros n 1, n 2, n 3 y n 4 al mismo tiempo. El contenido del chero de autómatas es el mismo que en la Prueba 5. El resultado debe ser unas estadísticas generales de la unión de todos los cheros por separado. 5.2. Evaluación de la funcionalidad de la aplicación En esta sección se ha evaluado la funcionalidad de la aplicación para cada una de las chas de prueba elaboradas anteriormente. 5.2.1. Resultados para la Prueba 1 En este caso, el resultado mostrado por la aplicación es el siguiente: IP origen: 192.168.1.4 IP destino: 87.230.83.44 Puerto origen: 34763 88 5. Evaluación Puerto destino: 4661 Flujo observado: 16 33 Flujo reconocido: Busqueda de archivos --------------------------------------------------------------------Numero de flujos totales: 1 Porcentaje de flujos reconocidos: 100 % Porcentaje de flujos no reconocidos: 0 % Porcentaje de flujos incompletos: 0 % --------------------------------------------------------------------5.2.2. Resultados para la Prueba 2 Ahora, el resultado mostrado por la aplicación para esta prueba es el siguiente: IP origen: 87.230.83.44 IP destino: 192.168.1.4 Puerto origen: 34648 Puerto destino: 36121 Flujo observado: 01 4C Flujo reconocido: Handshake inicial ---------------IP origen: 192.168.1.4 IP destino: 87.230.83.44 Puerto origen: 43742 Puerto destino: 4661 Flujo observado: 01 40 34 Flujo reconocido: Establecimiento de conexion ---------------IP origen: 192.168.1.4 IP destino: 87.230.83.44 Puerto origen: 43742 Puerto destino: 4661 Flujo observado: 14 32 41 Flujo reconocido: Secuencia de inicio de conexion --------------------------------------------------------------------Numero de flujos totales: 3 Porcentaje de flujos reconocidos: 100 % Porcentaje de flujos no reconocidos: 0 % Porcentaje de flujos incompletos: 0 % --------------------------------------------------------------------Como se puede observar, cuanto más grande es el chero y más paquetes contiene, más ujos son detectados en su interior. En esta prueba, se han reconocido todos los ujos observados en el chero de trazas. Se puede comprobar que un establecimiento de 89 5. Evaluación conexión implica tres ujos de información y, por tanto, tres autómatas ya modelados anteriormente. A modo ilustrativo, en la Figura 5.16 se puede observar con wireshark, como se puede ver en [17] el contenido de una trama de este chero, cuyo campo tipo es `01'. 5.2.3. Resultados para la Prueba 3 En este caso, la salida de la aplicación muestra lo siguiente: IP origen: 87.230.83.44 IP destino: 192.168.1.4 Puerto origen: 34648 Puerto destino: 36121 Flujo observado: 01 4C Flujo reconocido: Handshake inicial ---------------IP origen: 192.168.1.4 IP destino: 87.230.83.44 Puerto origen: 43742 Puerto destino: 4661 Flujo observado: 01 40 34 Flujo reconocido: Establecimiento de conexion ---------------IP origen: 192.168.1.4 Figura 5.16: Muestra de una trama `eDonkey' con Wireshark. 90 5. Evaluación IP destino: 87.230.83.44 Puerto origen: 43742 Puerto destino: 4661 Flujo observado: 14 Flujo no reconocido --------------------------------------------------------------------Numero de flujos totales: 3 Porcentaje de flujos reconocidos: 66.6667 % Porcentaje de flujos no reconocidos: 33.3333 % Porcentaje de flujos incompletos: 0 % --------------------------------------------------------------------La ejecución de la aplicación ha mostrado los resultados esperados. La traza borrada, como se puede comprobar, contenía dos mensajes `eDonkey': uno con tipo `32' y otro con tipo `41'. Por tanto, el ujo no es reconocido, ya que no hay información suciente, y el resultado es el esperado. 5.2.4. Resultados para la Prueba 4 Para ejecutar esta prueba, se modicará el porcentaje que establece cuándo un autómata es incompleto al 30 %. De manera que, utilizando el chero de pruebas indicado, el resultado es el siguiente: IP origen: 87.230.83.44 IP destino: 192.168.1.4 Puerto origen: 34648 Puerto destino: 36121 Flujo observado: 01 4C Flujo reconocido: Handshake inicial ---------------IP origen: 192.168.1.4 IP destino: 87.230.83.44 Puerto origen: 43742 Puerto destino: 4661 Flujo observado: 01 40 34 Flujo reconocido: Establecimiento de conexion ---------------IP origen: 192.168.1.4 IP destino: 87.230.83.44 Puerto origen: 43742 Puerto destino: 4661 Flujo observado: 14 Flujo incompleto --------------------------------------------------------------------- 91 5. Evaluación Numero de flujos totales: 3 Porcentaje de flujos reconocidos: 66.6667 % Porcentaje de flujos no reconocidos: 0 % Porcentaje de flujos incompletos: 33.3333 % --------------------------------------------------------------------Como se puede observar, la salida muestra un resultado esperado ya que, cambiando el criterio de ujos incompletos, se ha conseguido que se reconozca la modicación realizada en el chero de trazas. 5.2.5. Resultados para la Prueba 5 En este caso, se mostrará sólo el resultado de las estadísticas de la salida del programa, ya que el resto del contenido es bastante extenso, del cual se muestra un resumen en le Figura 5.17: --------------------------------------------------------------------Numero de flujos totales: 18 Porcentaje de flujos reconocidos: 44.4444 % Porcentaje de flujos no reconocidos: 55.5556 % Porcentaje de flujos incompletos: 0 % --------------------------------------------------------------------Como se puede observar, el resultado es aproximado al esperado. Con una especicación de autómatas simple, se han logrado reconocer el 44.44 % de los ujos observados, todos ellos relacionados con el chero de especicación de autómatas. 5.2.6. Resultados para la Prueba 6 Una vez más, se muestran sólo los resultados estadísticos de la salida, puesto que los ujos observados en el chero de trazas es extenso. Los resultados son los siguientes, y un resumen de la salida es el mostrado en la Figura 5.18: --------------------------------------------------------------------Numero de flujos totales: 200 Porcentaje de flujos reconocidos: 50 % Autómata Handshake inicial Flujos no reconocidos Número de veces observado 8 10 Figura 5.17: Salida observada para la Prueba 5. 92 5. Evaluación Autómata Handshake inicial Número de veces observado 92 Establecimiento de conexión 3 Secuencia de inicio de conexión 3 Búsqueda de archivos 2 Flujos no reconocidos 100 Figura 5.18: Salida observada para la Prueba 6. Porcentaje de flujos no reconocidos: 50 % Porcentaje de flujos incompletos: 0 % --------------------------------------------------------------------Como se puede observar, la cantidad de ujos observados es considerable. El resultado mostrado en la salida era predecible, ya que, de un chero extenso, se reconocen los ujos que se corresponden con los autómatas especicados. Estos son el 50 % de todos los ujos observados en el chero de pruebas. 5.2.7. Resultados para la Prueba 7 En esta última prueba, los resultados han sido los siguientes, y un resumen de la salida observada se muestra en la Figura 5.19: --------------------------------------------------------------------Numero de flujos totales: 222 Porcentaje de flujos reconocidos: 50.4505 % Porcentaje de flujos no reconocidos: 49.5495 % Porcentaje de flujos incompletos: 0 % --------------------------------------------------------------------Prestando atención al número de ujos totales, se puede vericar que coincide con la suma de los ujos observados de los cheros analizados por separado. Las estadísticas son globales a todos los ujos, por lo que la concurrencia de la aplicación funciona tal y como se esperaba. Autómata Handshake inicial Número de veces observado 101 Establecimiento de conexión 4 Secuencia de inicio de conexión 4 Búsqueda de archivos 3 Flujos no reconocidos 110 Figura 5.19: Salida observada para la Prueba 7. 93 5. Evaluación 5.2.8. Conclusiones de la evaluación de funcionalidades Salvo la prueba 1 (y en parte la prueba 2) los resultados de la aplicación son bastante positivos. En una situación real de tráco P2P producido por el protocolo `eDonkey' se han reconocido el 50'4505 % (analizando todos los cheros de trazas de prueba con un número reducido de autómatas) de los autómatas, que es prácticamente la mitad. Teniendo en cuenta que el chero de especicación de autómatas contenía solamente detalles de seis de ellos, el porcentaje de reconocimiento es bastante alto. Completando el chero de especicación se lograría un comportamiento mucho más able. El principal inconveniente de la especicación de autómatas es la continua actualización del protocolo `eDonkey', que convierte dichas especicaciones en obsoletas en relativamente poco tiempo. Por tanto, sería interesante un módulo en la aplicación que fuera capaz de deducir el comportamiento del protocolo `eDonkey' simplemente en base a su funcionamiento, de manera que pudiera elaborar los patrones de reconocimiento por sí solo. 5.3. Evaluación del rendimiento de la aplicación A continuación, se muestran medidas del rendimiento de la aplicación. Para poder medir tiempos de ejecución, se ha utilizado la herramienta time de Linux, la cual ofrece información precisa de los tiempos de ejecución de los programas. En la Figura 5.20 se muestra una tabla en la que se miden los tiempos de ejecución de cada una de las pruebas. Como se puede observar, los tiempos mostrados son bastante bajos, incluso con los cuatro cheros de prueba ejecutándose simultáneamente. Esto prueba la eciencia de las hebras ya que, incluso con cheros grandes, los resultados en tiempo son buenos. Otra de las medidas de rendimiento realizadas con la aplicación, es el análisis de los cuellos de botella existentes. Conociendo este dato, se podría realizar una mejora que disminuyera los tiempos de ejecución. En la Figura 5.21 se muestra un árbol de llamadas, realizado mediante VTune, como se puede consultar en [16], con la actividad que producen dichas llamadas que se hacen durante la ejecución de la aplicación. Las pruebas se han realizado para la ejecución del programa con los datos de la cha de la Prueba 8, ya que contiene un gran número de trazas y las llamadas se realizan de manera multihebrada, por lo que proporciona unas mejores estimaciones en los resultados. En el grafo de la Figura 5.21 se muestra el árbol de llamadas resultado de la ejecución de la aplicación. La función que más llamadas produce es pthread_join(), función que se utiliza para unir hebras. Dada la naturaleza multihebrada del programa y de la cha de prueba utilizada, es lógico vericar este hecho. Asimismo, se muestran enmarcadas en rojo las funciones que más tiempo consumen del total de la ejecución del programa. En la Figura 5.22 se muestra el porcentaje de ticks de reloj que consumen determina- das llamadas al programa. Como se puede apreciar en dicha gura, la función que más ticks consume está relacionada con el almacén/clasicador existente, debido a que esta estructura es utilizada por varios módulos y está siendo continuamente actualizada, como se vio anteriormente. También se proporciona un detalle preciso del porcentaje de ticks 94 5. Evaluación de reloj que ha ejecutado cada procesador del computador en el que se ejecuta. Prueba Tiempo de ejecución 1 0.004 s. 2 0.004 s. 3 0.004 s. 4 0.004 s. 5 0.004 s. 6 0.012 s. 7 0.472 s. 8 0.536 s. Figura 5.20: Tiempos de ejecución de las pruebas realizadas. Figura 5.21: Actividad del grafo de llamadas. Figura 5.22: Mediciones de tiempos para algunos métodos de la aplicación. 95 5. Evaluación 5.3.1. Conclusiones de la evaluación del rendimiento Como se ha mostrado anteriormente, se han realizado una serie de pruebas de rendimiento a la aplicación desarrollada. Analizando los cuellos de botella de la aplicación, se puede concluir que una posible optimización residiría en tratar de reducir el número de hebras utilizadas en el almacén/clasicador general, ya que es la parte que más tiempo consume. Por otro lado, resulta inevitable constatar que, si se reduce el número de hebras, probablemente aumentaría la carga de trabajo de otros módulos. Por lo tanto, aunque las hebras consuman una gran cantidad de tiempo de la ejecución del programa, la programación multihebrada es una buena solución. Los buenos tiempos mostrados se deben, en parte, a optimizaciones del compilador realizadas. 96 Capı́tulo 6 Planicación y estimación de recursos En este capítulo se mostrará la planicación inicial que se hizo para el proyecto, así como los recursos utilizados en él. Por último, se muestra un estudio económico realizado. 6.1. Planicación Para poder calcular la duración del proyecto, inicialmente se dividió en una serie de tareas con una duración aproximada. Las tareas se dividen en las siguientes: Planicación: En ella se realizaba una planicación inicial de la duración estimada del proyecto. No es una tarea sencilla calcular a priori dicha duración, por lo que se incluye un punto de replanicación, en el que se replanteaban objetivos y se modicaban las asignaciones de tiempo. Estudio del arte: En este estudio, el objetivo es familiarizarse con el proyecto y las materias relacionadas. Por ello, es necesario realizar un estudio de estos puntos y, al nal, entregar una parte de documentación referente a lo estudiado. Desarrollo y análisis: En esta sección se realiza el análisis del protocolo `eDonkey', así como el diseño de la solución propuesta. Realización de una parte de la documentación con esta información detallada. Programación de la aplicación. Pruebas: Fase en la que se realiza la evaluación de la aplicación desarrollada, a n de vericar su funcionamiento e ilustrarlo mediante algunos ejemplos. Documentación: Capítulo nal en el que se documenta debidamente los pasos seguidos y la motivación para el desarrollo del proyecto. Entrega de la documentación nal. En la Figura 6.1 se muestran estas tareas, mientras que en la Figura 6.2 se muestran el diagrama de Gantt correspondiente. 97 6. Planicación y estimación de recursos Figura 6.1: Esquema de las tareas inicialmente planicadas. 98 6. Planicación y estimación de recursos Figura 6.2: Diagrama de Gantt. 99 6. Planicación y estimación de recursos 6.2. Recursos Los recursos utilizados se pueden clasicar en tres bloques, atendiendo a su naturaleza. 6.2.1. Recursos software Sistema operativo Ubuntu 8.04 Hardy Heron. Editor de imágenes GIMP. Gestor de proyectos Planner. Editor para L TEX: LYX 1.6.3. Microsoft Oce 2007. Wireshark (véase [17]). Cliente eMule (véase [18]). Herramienta para documentación de código Doxygen (véase [20]). Herramienta para dibujar diagramas estructurados Dia 0.96.1. Editor de textos KWrite. Compilador gcc. Herramienta de creación de autómatas JFlap. A 6.2.2. Recursos hardware PC con procesador Intel Centrino Duo 2 GHz con 1GB de memoria principal y 200 GB de disco duro. Tarjeta de red Intel ipw3945abg. 6.2.3. Recursos humanos Dos profesores del Departamento de Teoría de la Señal, Telemática y Comunicaciones de la Escuela Técnica Superior de Ingenierías Informática y Telecomunicación de la Universidad de Granada, como directores del proyecto. Un alumno de Ingeniería Informática de la Escuela Técnica Superior de Ingenierías Informática y Telecomunicación de la Universidad de Granada, como desarrollador del proyecto. 6.3. Estudio económico A continuación se muestra un análisis de costes asociado al desarrollo de la aplicación. 100 6. Planicación y estimación de recursos 6.3.1. Costes asociados a los materiales Respecto a los costes de los materiales, será necesario incluir los costes asociado al equipo informático utilizado en la realización del proyecto. Este se calculará mediante el prorrateo del coste del propio equipo entre un tiempo, el cual se ha estimado que sean cuatro años, ya que se trata de un equipo informático que se calcula se volverá obsoleto tras ese período. Por tanto, sabiendo que el equipo informático tuvo un precio original de 200 ¿ ¿ , y teniendo en cuenta que la duración de la realización del proyecto es de, aproximadamente, 300 días, esto sumaría un total de 410.51 ¿ a abonar en concepto de materiales. Adicionalmente, se incluyen los gastos correspondientes a licencias software, los cuales sumarían un total de 1000 6.3.2. . Costes de mano de obra La estimación de los costes se calculará en base al tiempo aproximado empleado en la realización del proyecto. En España, cada día tiene disponibles 8 horas laborables y esto es lo que consideraremos. A continuación se detallan todas las fases del proyecto, cada una con el tiempo estimado de duración: Planicación: Planicación inicial: 72 horas. Corrección de la planicación: 40 horas. Elaboración de presupuesto: 56 horas. Estudio del arte: Estudio de los protocolos implicados: 136 horas. Elección de las aplicaciones a estudiar y justicación: 56 horas. Estudio del funcionamiento de las aplicaciones elegidas: 280 horas. Desarrollo y análisis: Captura de tráco P2P: 56 horas. Estudio del tráco generado por aplicaciones estudiadas en base al tráco capturado: 264 horas. Establecimiento de patrones en función del funcionamiento de las aplicaciones P2P: 240 horas. Pruebas: Vericación del funcionamiento de la aplicación desarrollada: 640 horas. Documentación: 101 6. Planicación y estimación de recursos Descripción del funcionamiento de los protocolos propios de la arquitectura TCP/IP: 80 horas. Descripción del funcionamiento de las aplicaciones elegidas en base a sus protocolos: 120 horas. Descripción del funcionamiento de las aplicaciones elegidas en base al tráco que generan: 160 horas. Descripción de los patrones elaborados en base al tráco de las aplicaciones: 120 horas. Estudio económico: 80 horas. Total: 2400 horas. ¿ Teniendo en cuenta la duración considerada del proyecto, el precio total correspondiente a la mano de obra, sería de 120000 6.3.3. . Otros costes Se incluirán los costes asociados a reuniones con el cliente, tanto para comprender las especicaciones iniciales del proyecto, como para dialogar con el susodicho cliente acerca del transcurso del proyecto para la resolución de posibles dudas y/o potenciales mejoras. Se calcula que, a lo largo del tiempo estimado de realización del proyecto, se realizarán 15 reuniones, cada una de 1 hora de duración. ¿ Dado que se estima que el precio de trabajo de una hora es de 50 coste asociado a las reuniones sería de 750 6.3.4. . Total La suma total correspondería a un total de 120750 ¿ , la suma total del ¿ . 102 Capı́tulo 7 Logros y conclusiones En esta sección se indican los logros obtenidos mediante la realización del proyecto, así como las conclusiones a las que se ha podido llegar. 7.1. Logros Comprender el funcionamiento del protocolo `eDonkey'. Entender el funcionamiento de las redes Entender el funcionamiento de los autómatas de estados nitos. Aprender a modelar comportamientos de protocolos mediante autómatas de estados peer-to-peer. nitos. Lograr diseñar una aplicación que sea capaz de realizar un proceso de determinada información mediante autómatas de estados nitos. Conocer el funcionamiento de la aplicación Wireshark, y cómo trata cada tipo de trama. Comprender el funcionamiento de la herramienta VTune para la realización de análisis de rendimiento de aplicaciones. Aprender cómo afrontar un proyecto de cierta envergadura y realizar una buena documentación. 7.2. Conclusiones Las herramientas de modelado de protocolos mediante autómatas de estados nitos son ecaces para la detección de anomalías en dichos protocolos. Sin embargo, es una tarea complicada denir completamente todo el comportamiento (diseñar los autómatas). 103 7. Logros y conclusiones El protocolo `eDonkey' es un protocolo difícil de modelar, ya que surgen versiones nuevas con el paso de los meses. Por ello, una determinada especicación podría quedar obsoleta en poco tiempo. Una posible mejora sería, como se comentó anteriormente, un módulo capaz de aprender por sí mismo el comportamiento de un determinado protocolo, para evitar el trabajo de la especicación de autómatas. 104 Bibliografía [1] http://www.techcrunch.com/2009/01/23/comscore-internet-population-passes-onebillion-top-15-countries/ [2] http://www.ipoque.com/resources/internet-studies/internet-study-2007. [3] Wai-Sing Loo, A. (2007): Peer-to-peer Web Technologies . Springer. ISBN: 1846283817, 9781846283819. [4] Wang, W. (2004): Steal sharing . Computing: Building Supercomputers with this le sharing book: what they won't tell you about le No Starch Press. ISBN: 159327050X, 9781593270506. [5] Millán Tejedor, R. J. (2006): Las redes P2P (peer to peer) . Creaciones Copyright. ISBN: 849630020X, 9788496300200. [6] Hemmje, M.; Neuhold, E. J.; Niederee, C; Risse, T. (2005): From integrated publication and information systems to virtual information and knowledge environments . Springer. ISBN: 3540245510, 9783540245513. [7] Asensio Asensio, G. (2006): Seguridad en Internet . Ediciones Nowtilus S.L. ISBN: 8497632931, 9788497632935. [8] Barnard, R. L. (1988): Intrusion Detection Systems . Gulf Professional Publishing. ISBN: 0750694270, 9780750694278. [9] Kulbak, Y.; Bickson, D; Kirkpatrick, S. (2004): The eMule protocol specication . School of Computer Science and Engineering.The Hebrew University of Jerusalem, Jerusalem. [10] http://decsai.ugr.es/%7Esmc/docencia/mci/automata.pdf [11] García Teodoro, P.; Díaz Verdejo, J. E.; López Soler, J. M. (2003): Transmisión Datos y Redes de Computadores . [12] Larman, C. (2006): UML Prentice Hall. ISBN: 9788420539195. y Patrones . Prentice Hall. ISBN: 8420534382. 105 de Bibliografía [13] Robson, R. (2000): Using the STL: the C++ standard template library . Springer. ISBN: 0387988572, 9780387988573. [14] Josuttis, N. M. (2002): The C++ Standard Library: A Tutorial and Reference . Addison-Wesley. ISBN: 0201379260, 9780201379266. [15] López Monge, A. (2005): Aprendiendo a programar con Libpcap . URL: http://www.e-ghost.deusto.es/docs/2005/conferencias/pcap.pdf. [16] http://software.intel.com/en-us/intel-vtune/ [17] http://www.wireshark.org/ [18] http://www.emule-project.net/ [19] https://computing.llnl.gov/tutorials/pthreads/ [20] http://www.doxygen.org/ 106 Apéndice A Descripción de los métodos utilizados En esta sección se incluyen la descripción del funcionamiento de los métodos de las clases detalladas en el Capítulo 4. También se incluye al nal unos detalles generales acerca del uso de la aplicación. Métodos de la clase `estado' Los métodos principales de la clase estado son los siguientes: estado() Constructor por defecto de la clase. Inicializa: 0. Identicador a Estado inicial a Estado nal a Puntero a mensaje a false. false. null. estado(const estado & orig) Constructor de copias de la clase. Copia el objeto de la clase estado parámetro en el objeto implícito el cual llama al constructor de copias. eliminar(mensaje * p) Libera la memoria asociada a una lista enlazada de elementos virtual ~estado() Destructor de la clase. 107 mensaje. pasado por A. Descripción de los métodos utilizados void setID(const int & a) Establece el valor del identicador propio de cada estado al valor entero que se pasa por parámetro a este procedimiento. int getID() Obtiene el valor del identicador del estado implícito que llama a la función, y lo devuelve. void setInicial(const bool & a) Modica la variable booleana de un estado que indica si dicho estado es inicial o no, y la cambia al valor a pasado por parámetro. bool getInicial() Obtiene el valor booleano del objeto estado implícito que indica si dicho estado es inicial o no y lo devuelve. void setFinal(const bool & a) Modica la variable miembro de un estado que indica si dicho estado es nal o no y la establece al valor pasado por parámetro. bool getFinal() Devuelve el valor de la variable miembro final que indica si el estado implícito es nal o no. void setMensaje(const string & mot, estado * nxt) Este procedimiento añade un nuevo mensaje a la lista de mensajes del estado. En su interior, pueden ocurrir dos situaciones: Que no exista ningún mensaje para ese estado: actualiza el valor del puntero del estado y añade un mensaje nuevo. Es decir, a modo de ejemplo: Se parte del estado de la Figura A.1. Si se realiza la llamada a este procedimiento con el argumento primero con valor `B7' y el segundo es un puntero al estado 0, entonces resultaría el estado de la Figura A.2. Que ya existan mensajes: En este caso habría que recorrer la lista de todos los mensajes existentes y añadir uno nuevo al nal. Es decir, siguiendo con el ejemplo: Se parte del estado de la Figura A.3. Si ahora se realiza la llamada al procedimiento, con parámetros `47' y un puntero a un hipotético estado q2 , entonces resultaría lo mostrado en la Figura A.4. 108 A. Descripción de los métodos utilizados Figura A.1: Ejemplo de estado. Figura A.2: Ejemplo de estado tras la llamada a `setMensaje'. Figura A.3: Ejemplo de estado con un mensaje. Figura A.4: Ejemplo de estado con un mensaje tras la llamada a `setMensaje'. 109 A. Descripción de los métodos utilizados mensaje * getMensaje() Devuelve el valor del puntero al primer mensaje del objeto implícito estado que realiza la llamada a esta función. string getNombre() Obtiene la descripción (en caso de haber alguna) del objeto implícito que hace la llamada, y lo devuelve. void setNombre(const string & nombre) Establece el valor de la descripción de un objeto de la clase estado al valor concreto que se pasa como parámetro del procedimiento. void setNull() Modica, para un objeto y lo cambia a valor null. estado implícito, el valor de su puntero a la lista de mensajes, int numeroMensajes() Cuenta el número de mensajes que tiene un objeto estado y lo devuelve como pará- metro. En el ejemplo de la Figura A.4 devolvería 2. friend ostream & operator(ostream & fo, estado & e) Sobrecarga del operador `<<' para permitirle mostrar por pantalla todas las variables miembro de un estado, incluyendo la lista de mensajes que tiene con el detalle de cada uno de ellos. estado & operator=(const estado & orig) Sobrecarga del operador `=' para permitir a un estado poder igualarlo a otro. Tiene la misma funcionalidad que el constructor de copias de la clase, pero este requiere más simplicidad a la hora de utilizarlo. Métodos de la clase `automatas' Los principales métodos de esta clase se detallan a continuación: automatas() Constructor por defecto de la clase. Se inicializan las variables estadísticas a cero. También se inicializan los mutexes. 110 A. Descripción de los métodos utilizados automatas(const automatas & orig) Constructor de copias de la clase. Para copiar un vector a otro, sólo es necesario utilizar el operador de asignación, ya que se encuentra sobrecargado y se puede utilizar con sencillez gracias al encapsulado proporcionado por las clases. virtual ~automatas() Destructor de la clase. No es necesario liberar memoria, ya que esta función se encuentra integrada en la clase vector. Se destruyen los mutexes. void setTamanio(const int & n) Aunque el vector utilizado como variable miembro de la clase es dinámico, sí es necesario inicializar dicho vector a un tamaño inicial. Con este procedimiento se logra ese objetivo, estableciendo el tamaño del vector al parámetro entero del módulo. void muestraV() Procedimiento de ayuda el cual solamente muestra el contenido de cada casilla del vector del objeto clase estado, automatas. Gracias a que el operador `<<' está sobrecargado en la es posible realizar esta operación, ya que en cada casilla del vector se encuentra un elemento de este tipo. vector<estado> devuelveV() Devuelve el vector que forma parte de un objeto de la clase automatas, el cual llama a esta función. extraeFlujosAntiguos() Procedimiento de la hebra encargada de la extracción y análisis. Comprueba periódicamente si existen ujos antiguos que extraer del almacén/clasicador. Si el almacén/clasicador tiene un tamaño mayor que un umbral, se crean hebras que ayudan a liberar carga de la hebra principal. void leerAutomatas(const char * nombre) Lee una serie de autómatas contenidos en un chero. La utilidad de este procedimiento reside en construir el vector de objetos estado a partir de información contenida en un chero de texto. Esta información está relacionada con el funcionamiento del protocolo que se quiere examinar, en este caso `eDonkey'. Se establece un tamaño inicial para el vector de objetos estado. Cada casilla del vector se rellena con los datos del chero, estableciendo las variables miembro a un valor adecuado para su posterior vericación. 111 A. Descripción de los métodos utilizados int leerTramas(const int & modo, const char * nombre) Otra de las funciones destacadas la que lee un chero de tramas almacenado en disco o abre una interfaz de red para un modo de captura en vivo. El formato del chero de tramas debe ser pcap, ya que la biblioteca utilizada trabaja con este tipo de cheros (véase Sección 2.4.2). En esta función se observan dos funcionalidades principales: modo Si el argumento es igual a 0: Signica que se ha llamado al programa con la intención de examinar si un determinado chero de tramas almacenado cumple una serie de patrones de funcionamiento. En este modo, el parámetro nombre es el nombre del chero pcap que contiene las tramas a examinar. Si el argumento modo es igual a 1: En este caso se ha elegido la opción de abrir una interfaz de red para hacer un análisis en vivo de un determinado protocolo P2P. En este modo se establece la captura de tráco en modo promiscuo y se indica un ltro, ya que realiza una captura de tráco más eciente debido a que ahorra coste computacional. El ltro establecido por defecto es tcp. En este modo, el parámetro nombre es el nombre de la interfaz de red para la captura en vivo. La función devuelve un código de error (EXIT_FAILURE) en caso de que se produzca algún error, o un valor de retorno indicando éxito (EXIT_SUCCESS) en caso de que se ejecute con normalidad. muestraEstadisticas() Muestra las estadísticas correspondientes de los resultados del análisis de los ujos detectados. bool comparaAutomata(datosFlujo datos) Realiza el parsing de un autómata. Es decir, en base a todos los autómatas construidos a partir de un chero dado de autómatas, los cuales proporcionan información acerca de un determinad protocolo (en este caso, el protocolo `eDonkey'), comprueba si un ujo está siguiendo el patrón denido en alguno de estos autómatas. Mediante este procedimiento se llega a la conclusión de si el funcionamiento del protocolo se modela mediante los autómatas denidos o no. El parámetro datos se corresponde con el ujo de información determinado que se va a analizar para ver si cumple o no con ciertos patrones de funcionamiento. La función devuelve true en caso de poder modelar el ujo observado mediante un autómata, o estar este ujo incompleto, y false en caso contrario. void comparaTodo() 112 A. Descripción de los métodos utilizados Extrae todos los ujos de información existentes en el almacén/clasicador. Se realiza el parsing de cada uno de los ujos extraídos. operator=(const automatas & orig) Sobrecarga del operador `=' de la clase. int getNumeroEstados(vector <estado> V, const int & i) estado Devuelve, para un vector de objetos dado y una posición dentro de ese vector, el número de posiciones (o estados) que restan hasta encontrar un estado nal. Funciones auxiliares Funciones que no forman parte de la clase, pero son necesarias por proporcionar algunas funcionalidades imprescindibles para manejar un objeto de la clase automatas. inline int hex2int(const char * cadena) Convierte una cadena de caracteres pasada por parámetro que contiene un número en hexadecimal en el número entero correspondiente. void parsingAutomata(datosFlujo datos) Realiza el parsing de un autómata. Es decir, en base a todos los autómatas construidos a partir de un chero dado de autómatas, los cuales proporcionan información acerca de un determinad protocolo (en este caso, el protocolo `eDonkey'), comprueba si un ujo está siguiendo el patrón denido en alguno de estos autómatas. Mediante este procedimiento se llega a la conclusión de si el funcionamiento del protocolo se modela mediante los autómatas denidos o no. El parámetro datos se corresponde con el ujo de información determinado que se va a analizar para ver si cumple o no con ciertos patrones de funcionamiento. La función devuelve true en caso de poder modelar el ujo observado mediante un autómata, o estar este ujo incompleto, y false en caso contrario. Esta función no pertenece a la clase. liberarCarga(void * arg) Función de las hebras encargadas de liberar la carga de la hebra principal del módulo de extracción y análisis. El parámetro arg indica la cantidad de trabajo que tendrán las nuevas hebras creadas. void evaluaFinFlujo(const string & IPorigen, const string & IPdestino, const int & puertoOrigen, const int & puertoDestino, const bool & finTCP) 113 A. Descripción de los métodos utilizados Uno de los procedimientos principales de la aplicación es aquel que determina cuándo es el inicio y cuándo el n de un determinado ujo de información. Esta función se llama para cada trama TCP o UDP que no tenga carga útil. Dentro de ella, se comprueba que la trama sea TCP y tenga el bit FIN activado. En este caso, signicará que se ha recibido una trama de nalización de una conexión, por lo que, desde que se inició la transmisión de datos hasta ese punto, se considera un ujo. En ese caso, se ha de examinar a cuál de todos los ujos existentes corresponde esa trama de nalización de conexión TCP. Cuando se encuentre una coincidencia, se extraerá dicho ujo del almacén/clasicador y se analizará para vericar si coincide con alguno de los autómatas conocidos. void rellenaClasificadorFlujos(const string & IPorigen, const string & IPdestino, const int & puertoOrigen, const int & puertoDestino, const char * payload) Mediante este procedimiento, correspondiente al módulo de detección de ujos detallado en el Apartado 4.1.2, se clasican las tramas leídas en ujos de información. Dicho procedimiento puede ser modicado para la compatibilidad con otros protocolos ya que es en él donde se realizan las funciones intrínsecas al protocolo `eDonkey'. Para ello, se lee la carga útil de la trama antes de operar con ella, ya que los datos de la cabecera se incluyen en los parámetros de este procedimiento. Los pasos que se siguen son los siguientes: Se comprueba que la trama tenga una carga útil lo sucientemente grande como para ser examinada. Si los datos de la trama tienen un tamaño inferior a 11 caracteres, no se considerará. Se comprueba que la trama pertenezca al protocolo `eDonkey' o a la extensión del protocolo proporcionada por `eMule'. Esto se conoce gracias a un parámetro tipo el cual es `E3' en el caso de que la trama pertenezca a `eDonkey' o `C5' si pertenece a `eMule'. Se examina el tamaño de la carga útil mediante un parámetro existente a tal efecto. Si el tamaño es superior a 100000 bytes, se considera que la información es errónea y se descarta la trama, ya que no existen tramas tan grandes. Dependiendo del tamaño del almacén/clasicador de ujos: Si el almacén/clasicador no contiene ningún ujo de información, se creará uno nuevo y se introducirán los datos referentes a la trama que se está examinando en él. Si el almacén/clasicador ya tiene otros ujos anteriores, se comprobará cada uno de ellos para vericar si la trama que se está examinando pertenece a un ujo de información ya existente. En el caso de no haber ninguna coincidencia, se creará uno nuevo. 114 A. Descripción de los métodos utilizados El proceso se repite tantas veces como existan datos referentes al protocolo `eDonkey'. Esto sucede ya que, en una misma trama, pueden aparecer de manera encadenada, varias subtramas pertenecientes al protocolo `eDonkey'. void my_callback(u_char * args, const struct pcap_pkthdr * header, const u_char * packet) Este procedimiento corresponde con el módulo de preprocesamiento explicado en el pcap, llamada pcap_loop. pcap_loop, por lo que dentro Apartado 4.1.1, y está ligado a la función de la biblioteca Dicho procedimiento se ejecuta para cada trama leída con se puede escribir el código que se desee. Una de las funciones básicas que se ha implementado dentro de este procedimiento, es el ltrado de tramas que no se necesitan evaluar. Conforme se van leyendo estas tramas, se accede a los distintos niveles de información de la cabecera. De esta manera, se pueden desechar las tramas que no pertenezcan ni al protocolo TCP ni al UDP, puesto que son únicamente las que proporcionan información relevante para la evaluación con los autómatas. La segunda y última de las funciones destacadas dentro de este módulo es el tratamiento de la carga útil de la trama leída. Dado que no todos los caracteres leídos tienen por qué ser ASCII, entonces no todos pueden ser representados por algún carácter que pueda ser leído e interpretado por un lector cualquiera. Para un mejor tratamiento de la información contenida en las cargas útiles, la opción tomada es realizar una conversión de todos los caracteres a base hexadecimal. Con esta transformación es posible identicar los protocolos a los que pertenece cada trama, así como otro tipo de información relevante para la construcción de las diferentes estructuras que conforman la aplicación. Una vez realizada la conversión mencionada, la trama se envía para incluirla dentro del almacén/clasicador de ujos, en caso de que tenga carga útil, o bien es examinada para comprobar si proporciona algún tipo de información referente al nal de un ujo de información, en caso de no tener carga útil. Métodos de la clase `datosFlujo' Esta clase tiene los siguientes métodos: datosFlujo() Constructor por defecto de la clase. No es necesario inicializar ninguna variable miembro del objeto, pues ni las cadenas, ni los números enteros, ni los vectores necesitan inicializarse. datosFlujo(const datosFlujo & orig) Constructor de copias de la clase. Realiza una copia simple de todos los elementos del objeto orig pasado por parámetro al objeto implícito. 115 A. Descripción de los métodos utilizados virtual ~datosFlujo() Destructor de la clase. No realiza liberación de memoria de ningún tipo puesto que no es necesario reservar memoria para crear un objeto de la clase. Todas las variables miembro son objetos ya encapsulados que incorporan sus propios destructores. string getIPorigen() Devuelve el valor de la variable miembro que almacena la IP origen para el objeto que llama a esta función. void setIPorigen(const string & IP) Establece el valor de la variable que almacena la IP origen del objeto que llama a la función al valor pasado por parámetro, IP. string getIPdestino() Obtiene el valor de la variable miembro que almacena la IP destino del objeto implícito y la devuelve. void setIPdestino(const string & IP) Establece el valor de la variable IP destino del objeto implícito al valor que se le pasa por parámetro a la función. int getPuertoOrigen() Esta función toma el valor del puerto origen del objeto implícito que la llama, y lo devuelve. void setPuertoOrigen(const int & puerto) Establece el valor de la variable miembro que almacena el puerto origen al valor indicado en el parámetro de la función. int getPuertoDestino() Devuelve el valor de la variable miembro que almacena el puerto destino para el objeto implícito que llama a la función. void setPuertoDestino(const int & puerto) Establece el valor del puerto destino del objeto que realiza la llamada al valor del parámetro de la función. int getTimestamp() 116 A. Descripción de los métodos utilizados Obtiene el valor de la variable miembro que almacena la marca de tiempo (timestamp ) y la devuelve. void setTimestamp(const int & timestamp) Establece el valor del timestamp de un objeto de la clase datosFlujo al valor que se le pasa por parámetro al procedimiento. vector<string> getTypes() Devuelve, para el objeto implícito que realiza la llamada a la función, un vector de cadenas que contiene la información propia del protocolo transmitida entre dos peers. void setTypes(const string & type) Mediante este procedimiento se añade al nal del vector de cadenas que forma parte de las variables miembro, la información contenida en el parámetro de la función. friend ostream & operator(ostream & fo, datosFlujo & d) Sobrecarga del operador `<<' para un objeto de la clase datosFlujo. Mediante este operador se puede mostrar por pantalla toda la información de las variables miembro del objeto implícito. Métodos de la clase `clasicadorFlujos' Las funciones y procedimientos de esta clase son los siguientes: clasificadorFlujos() Constructor de la clase. Dado que la única variable miembro de un objeto de esta clase es un vector de la STL, se inicializa dicho vector un una función diseñada a tal efecto. clasificadorFlujos(const clasificadorFlujos & orig) Constructor de copias de la clase. Ya que sólo está compuesta por un vector, sólo es necesario copiar el contenido de este. virtual ~clasificadorFlujos() Destructor de la clase. Ya que está formada por un objeto de la STL, no es necesario implementar un destructor, puesto que la STL ya implementa funciones a tal efecto. int tamClasificador() Para un objeto de la clase clasificadorFlujos determinado, devuelve el tamaño del vector de ese objeto. 117 A. Descripción de los métodos utilizados datosFlujo getPosicion(const int & i) Para un objeto implícito que llama a esta función, devuelve el contenido (es decir, un objeto datosFlujo) que se encuentra en la posición que indica el parámetro i. void setPosicion(const datosFlujo & nueva) Añade un nuevo ujo de datos, es decir, un nuevo objeto de la clase datosFlujo, al clasicador de ujos. string getIPorigen(const int & i) Devuelve el valor de la IP origen del objeto i datosFlujo que se encuentra en la posición del objeto que llama a la función. void setIPorigen(const int & i, const string & str) Establece el valor de la IP origen de un objeto de la clase posición i al valor str datosFlujo situado en la pasado por parámetro. string getIPdestino(const int & i) Devuelve el valor de la IP destino del objeto i datosFlujo que se encuentra en la posición del objeto que llama a la función. void setIPdestino(const int & i, const string & str) Establece el valor de la IP destino de un objeto de la clase posición i al valor str datosFlujo situado en la pasado por parámetro. int getPuertoOrigen(const int & i) Devuelve el valor del puerto origen del objeto posición i datosFlujo que se encuentra en la del objeto que llama a la función. void setPuertoOrigen(const int & i, const int & puerto) Establece el valor del puerto origen de un objeto de la clase posición i al valor puerto datosFlujo situado en la pasado por parámetro. int getPuertoDestino(const int & i) Devuelve el valor del puerto destino del objeto posición i datosFlujo que se encuentra en la del objeto que llama a la función. void setPuertoDestino(const int & i, const int & puerto) 118 A. Descripción de los métodos utilizados Establece el valor del puerto destino de un objeto de la clase la posición i al valor puerto datosFlujo situado en pasado por parámetro. double getTimestamp(const int & i) Devuelve el valor de la marca de tiempo del objeto la posición i datosFlujo que se encuentra en del objeto que llama a la función. void setTimestamp(const int & i, const double & _timestamp) Establece el valor de la marca de tiempo de un objeto de la clase en la posición i al valor _timestamp datosFlujo situado pasado por parámetro. vector<string> getTypes(const int & i) Devuelve el vector de cadenas situado en la posición almacena la información del protocolo para dos peers i del almacén/clasicador, que determinados. void setTypes(const int & i, const string & str) Añade en el vector de cadenas situado en la posición i del almacén/clasicador, con información del protocolo y las tramas intercambiadas entre dos parámetro str. peers la información del datosFlujo BorrarElemento(const int & i) Para un objeto de la clase clasificadorFlujos determinado, borra el objeto datosFlujo (es decir, borra toda la información referente a un ujo de datos) situado en la posición i del almacén/clasicador. Finalmente, devuelve este elemento. Detalles generales del uso de la aplicación A modo de ayuda, se muestran una serie de pautas en la utilización de la aplicación: La aplicación ya está compilada. En caso de que se desee compilar de nuevo, tan sólo es necesario ejecutar la orden make. No requiere ningún tipo de instalación. ./bin/. El ejecutable del programa se encuentra en el directorio El chero de autómatas se encuentra en Todo el código está documentado con la herramienta Doxygen (véase Sección ./dat/automatas.dat. 2.4.5). Se puede acceder a esta documentación mediante el HTML Los archivos de cabeceras se encuentran en ./doc/index.html. ./include/. Existe un manual de referencia con la documentación del código, en formato Dicho manual se encuentra en ./latex/refman.pdf. pdf. 119 A. Descripción de los métodos utilizados Se ha creado una biblioteca con la estructura de la aplicación, con el n de facilitar su uso en el futuro. Dicha biblioteca se encuentra en Los cheros objeto producto de la compilación de la aplicación se encuentran en ./obj/. ./lib/libpfc.a. Para borrarlos, es necesario ejecutar la orden En el directorio ./pcap/ ./make clean. se incluyen algunos cheros de ejemplo con trazas de tráco. Los resultados de la ejecución de estos cheros se muestran, a modo de ejemplo, en el directorio ./resultados/. ./src/. Los cheros con el código fuente se encuentran en A continuación se muestra un ejemplo de uso de la aplicación. Si se deseara ejecutar dicha aplicación para dos cheros del directorio denominada eth0, ./pcap/ y para una interfaz de red la llamada sería la siguiente (es necesario otorgar permisos de superusuario si se desea analizar una interfaz de red): ./bin/p2pdetector -f ./pcap/1-establecimiento_conexion.pcap -f ./pcap/2-buscar.pcap -i eth0 120