121
ESTUDIOS DE INGENIERÍA DE TELECOMUNICACIÓN PROYECTO FIN DE CARRERA Desarrollo de un entorno para la inclusión de medidas de defensa frente a ataques de denegación de servicio basadas en políticas de gestión de colas. REALIZADO POR: Rafael Alejandro Rodríguez Gómez DIRIGIDO POR: Prof. Gabriel Maciá Fernández DEPARTAMENTO: Teoría de la Señal, Telemática y Comunicaciones Granada Septiembre, 2008

Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

ESTUDIOS DE INGENIERÍA

DE TELECOMUNICACIÓN

PROYECTO FIN DE CARRERA

Desarrollo de un entorno para la inclusión de

medidas de defensa frente a ataques de

denegación de servicio basadas en políticas de

gestión de colas.

REALIZADO POR:

Rafael Alejandro Rodríguez Gómez

DIRIGIDO POR:

Prof. Gabriel Maciá Fernández

DEPARTAMENTO:

Teoría de la Señal, Telemática y Comunicaciones

Granada

Septiembre, 2008

Page 2: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 3: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Desarrollo de un entorno para la inclusión de medidas

de defensa frente a ataques de denegación de servicio

basadas en políticas de gestión de colas.

Rodríguez Gómez, Rafael Alejandro

PALABRAS CLAVE: seguridad, denegación de servicio, gestión de colas,

conexión TCP.

Resumen

En este proyecto se ha estudiado la problemática de los ataques de

denegación de servicio y se ha propuesto como solución el uso de políticas de

gestión de colas en los buffers del establecimiento de la conexión para el

protocolo TCP. Con el fin de posibilitar la labor de implementación de estas

políticas de gestión de colas en un sistema real, se ha modificado la estructura

del sistema operativo Linux proporcionando un marco de trabajo que permite

de forma flexible y simplificada, la introducción del código que implementa

dichas políticas.

Se ha realizado un profundo análisis del código fuente de la sección del

núcleo de Linux que implementa el establecimiento de la conexión para el

protocolo TCP y para determinar los lugares en los que se aplican las

modificaciones en el núcleo.

Se ha propuesto una política de colas simple y se ha mostrado que su

implementación es factible en este núcleo modificado.

Por último se han realizado una serie de pruebas con dicha política de

gestión de colas. A la luz de los resultados obtenidos se ha comprobado que la

política implementada dificulta los efectos de los ataques DoS.

Page 4: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 5: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 6: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 7: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Development of a framework for the inclusion of denial of service

defense measures based on queue management policies

Rodríguez Gómez, Rafael Alejandro

KEYWORDS: security, denial of service, queue management, TCP

connections.

Abstract

This thesis is focused on the problem of denial of service (DoS) attacks. For

this problem, a solution based on the use of TCP establishment queue

management policies has been proposed. To ease the implementation of

these management policies in a real system, the structure of a Linux kernel

has been modified with the purpose of providing a framework aimed at

allowing the insertion, in a flexible and simplified way, of the code that

implements the policies.

A deep analysis of the Linux kernel source code that implements the

connection establishment for the TCP protocol has been carried out. This

analysis has allowed to choose the right positions in the kernel code to locate

the modifications proposed in this thesis.

Additionally, a simplified queue management policy has also been proposed

and implemented, and it has been shown that this implementation is feasible

and easy in the modified kernel.

Finally, a set of tests using the implemented policy has been carried out.

The results obtained show that the policy improves the behavior of the server

that is under DoS condition.

Page 8: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 9: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

D. Gabriel Maciá Fernández

Profesor del departamento de Teoría de la Señal, Telemática y

Comunicaciones de la universidad de Granada, como director del Proyecto Fin

de Carrera de D. Rafael Alejandro Rodríguez Gómez.

Informa:

que el presente trabajo titulado:

Desarrollo de un entorno para la inclusión de medidas de defensa frente

a ataques de denegación de servicio basadas en políticas de gestión de

colas.

Ha sido realizado por el mencionado alumno bajo nuestra supervisión y con

esta firma autorizo su presentación.

Granada, 14 de Septiembre de 2008

Firma:

Gabriel Maciá Fernández

Page 10: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 11: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Los abajo firmantes autorizan a que la presente copia de Proyecto Fin de

Carrera se ubique en la Biblioteca del Centro y/o departamento para ser

libremente consultada por las personas que lo deseen.

Nombre: Rafael Al. Rodríguez Gómez Nombre: Gabriel Maciá Fernández

DNI: DNI:

Firma: Firma:

Granada, 14 de Septiembre de 2008

Page 12: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 13: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Agradecimientos

La sonrisa es más barata que la luz e ilumina más

(Roberto Pettinato)

Este trabajo representa la finalización de una fase muy importante en mi

vida y aunque “gracias” a él he tenido más de un quebradero de cabeza ahora

observando el resultado me recorre un escalofrío desde los pies a la cabeza.

No sé si se debe a la alegría que me da el haberlo terminado o tal vez a que

en realidad pienso que he realizado un trabajo digno.

Si me siento orgulloso de este proyecto se lo debo en primer lugar a un

grandioso docente e investigador Gabriel Maciá, mi tutor, aunque ninguna de

estas virtudes es la que hace que lo admire realmente. Esta admiración se

deriva de la atención extrema que ha tenido y sigue teniendo conmigo, de

corazón gracias.

También se lo debo por supuesto a mi familia, papá, mamá y Patri, si

alguien ha tenido que sufrir el lado oscuro que tiene la realización de un

proyecto fin de carrera, esos habéis sido vosotros. Habéis aguantado todas

mis frustraciones: tras no comprender cómo en una tarde de trabajo no había

sido capaz de escribir más de una página de introducción, cómo podía pasar

días buscando una solución que estaba realmente tan cerca. Gracias por

apoyarme, soportarme y sobretodo por alentarme con vuestro amor.

Gracias a todos los que, en este fase de mi vida, me habéis acompañado y

os deseo a todos que

Seáis felices.

Page 14: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 15: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Índice de contenido

►Índice de contenido xv

►Índice de figuras XIX

►Capítulo 1: Presentación del problema y de la solución propuesta 1

►1.1 Introducción......................................................................................1

►1.2 Ataques de denegación de servicio (DoS)........................................2

►1.3 Ataques de denegación de servicio contra servidores.....................4

►1.3.1 Modelo del servidor........................................................................5►1.3.2 Ejecución del ataque de denegación de servicio contra servidores

.......................................................................................................7

►1.4 Solución propuesta...........................................................................8

►1.4.1 Políticas de gestión de colas..........................................................9►1.4.2 Ejemplo de una política de gestión de colas................................10

►1.5 Objetivo y alcance del proyecto.....................................................14

►Capítulo 2: Análisis de la implementación de TCP/IP en Linux 17

►2.1 Establecimiento de la conexión de TCP en el núcleo......................19

►2.1.1 Acceso a la cola de conexiones completadas desde la aplicación......................................................................................................24

►2.1.2 Acceso a la cola de conexiones completadas desde la red..........29

►2.2 Estudio de las estructuras software implicadas en la conexión TCP.

.......................................................................................................33

►2.2.1 Estructuras socket para la conexión............................................34►2.2.2 Estructura de la cola de peticiones completadas.........................40

►2.3 Conclusiones del capítulo...............................................................43

►Capítulo 3: Implementación del entorno para la inclusión de medidas

de defensa en el núcleo de Linux 45

►3.1 Núcleo y módulos del núcleo..........................................................46

►3.1.1 Compilación del núcleo................................................................47►3.1.2 Módulos del núcleo......................................................................48►3.1.3 Módulos vs implementación directa en el núcleo........................52

►3.2 Módulos de seguridad de Linux (LSM) y garfios..............................53

►3.2.1 Dificultad hallada en la implementación del módulo...................53►3.2.2 Solución encontrada: Garfio.........................................................54►3.2.3 Proceso de implementación de un garfio.....................................56

►3.3 Implementación de una política de gestión de colas......................62

Page 16: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 17: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

► Anexo 3.A: Códigos desarrollado para la generación del entorno.. 64

► Código del archivo hook.c............................................................64► Código del archivo rodgom.h.......................................................67► Código del archivo net/ipv4/tcp_ipv4.c........................................67► Código del archivo Makefile.........................................................69

►Capítulo 4: Evaluación de políticas de gestión de colas para la

defensa. 71

►4.1 Entorno de pruebas........................................................................72

►4.2 Modificaciones realizadas en el sistema.........................................75

►4.3 Resultados de las pruebas realizadas.............................................76

► Anexo 4.A Presentación del código del modelo cliente-servidor.. . .80

► Archivo servidor.cpp....................................................................80► Archivo cliente_bueno.cpp...........................................................82► Archivo cliente_malo.cpp.............................................................86

►Capítulo 5: Planificación del proyecto. 91

►5.1 Objetivos y tareas en las que se han dividido................................91

►5.2 Recursos utilizados.........................................................................93

►5.2.1 Recursos humanos.......................................................................93►5.2.2 Recursos materiales.....................................................................94

►5.3 Planificación temporal y diagrama de Gantt...................................95

►Capítulo 6: Conclusiones 97

►6.1 Conclusiones acerca del trabajo realizado.....................................97

►6.2 Líneas futuras.................................................................................98

►Bibliografía xcix

Page 18: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 19: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Índice de figuras

Índice de figurasFig. 1.1: Modelo del servidor tomada de [2].......................................................5

Fig. 1.2: Modelo de servidor con módulo de gestión..........................................9

Fig. 1.3: Diagrama de flujo de la política de gestión de colas..........................11

Fig. 2.1: Negociación en tres pasos..................................................................20

Fig. 2.2: Máquina de estados finitos para el establecimiento de conexión del

protocolo TCP...................................................................................................21

Fig. 2.3: Movimiento de las peticiones en las colas [4]....................................24

Fig. 2.4: Capas de la arquitectura de red TCP/IP..............................................25

Fig. 2.5: Extracción de una petición de la cola de conexiones completadas....25

Fig. 2.6: Camino seguido por una función que deba acceder al núcleo...........27

Fig. 2.7: Estructuras socket..............................................................................35

Fig. 2.8: Estructura de la cola de conexiones establecidas..............................40

Fig. 3.1: Esquema simplificado de la recompilación del núcleo.......................48

Fig. 3.2: Estructura básica de un módulo del núcleo........................................50

Fig. 3.3: Esquema de funcionamiento de un garfio..........................................55

Fig. 3.4: Funcionamiento de un garfio..............................................................57

Fig. 3.5: Estructura de rodgom.h......................................................................58

Fig. 3.6: Estructura de modificación del archivo del núcleo tcp_ipv4.c............59

Fig. 3.7: Estructura de creación del módulo del núcleo....................................60

Fig. 3.8: Diagrama de flujo de la política de gestión de colas ejemplo.............62

Fig. 4.1: Diagrama de flujo del cliente_bueno..................................................73

Fig. 4.2: Diagrama de flujo de cliente_malo.cpp..............................................74

Fig. 4.3: Representación de los resultados con backlog a 2 y sin aplicar la

política..............................................................................................................78

Fig. 4.4: Representación de los resultados con backlog a 2 y aplicando la

política..............................................................................................................78

XIX

Page 20: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Índice de figuras

Fig. 4.5: Representación de los resultados con backlog a 50 y sin política......79

Fig. 4.6: Representación de los resultados con backlog a 50 y aplicando la

política..............................................................................................................79

Fig. 5.1: Tabla resumen de la planificación temporal del proyecto..................95

Fig. 5.2: Diagrama de Gantt del proyecto........................................................96

XX

Page 21: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 1: Presentación del problema y de la solución propuesta

1.1 Introducción

Desde el inicio de la humanidad el hombre siempre ha necesitado mantener

a buen recaudo sus bienes personales. Para esto, en primera instancia, se

utilizaron los soldados que vigilaban las arcas reales. Actualmente, son

algunos complejos sistemas de seguridad los tienen la labor que antaño

llevaron a cabo las espadas. En la actualidad es innegable la creciente

importancia que está adquiriendo el tema de la seguridad en redes de

comunicación y esto se debe a este mismo motivo.

Hoy por hoy se realizan multitud de operaciones a través de Internet. Entre

ellas se puede destacar el comercio electrónico que implica el tránsito de

dinero y esto conlleva la necesidad de garantizar ciertos niveles de seguridad

para que los clientes quieran realizar dichas operaciones provechosas para el

sistema. Como es sabido por todos, no todo el mundo es bienintencionado y

en ésta, una nueva era, aparecieron nuevos ataques de seguridad.

De entre estos ataques hay un tipo concreto, en el que se centra el

presente proyecto, que es el de los llamados ataques de denegación de

servicio o también DoS (de las siglas en inglés: Denial of Service).

En la primera parte del presente capítulo se describe el funcionamiento a

grandes rasgos de los ataques DoS para posteriormente centrarnos en un tipo

de ataque DoS: el ataque DoS contra servidores. Este tipo de ataque es de

especial relevancia en este proyecto debido a que la solución que se presenta

en él está especialmente diseñada para este tipo de ataques. En la segunda

1

Page 22: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 1: Presentación del problema y de la solución propuesta

sección de este capítulo se da forma a la solución que, frente a la

problemática presentada en el primer punto, se ha estimado más oportuna. Se

ve necesario en esta sección exponer las bases teóricas sobre las que se

razonará en lo sucesivo.

Y por último, se resumen los objetivos de este proyecto con la intención de

determinar con claridad qué se pretende conseguir a lo largo del resto de este

documento.

1.2 Ataques de denegación de servicio (DoS)

El ataque DoS, en una red de comunicación, tiene como objetivo eliminar o

reducir la disponibilidad de un determinado activo mediante la ejecución de

determinadas acciones maliciosas dirigidas a la fuente de información, al

canal de comunicación o a ambos. Este tipo de ataques impide o inhibe el uso

normal o la gestión de recursos de comunicaciones.

La mayoría de los ataques a la seguridad de redes de comunicación tratan

de penetrar en un sistema y de este modo poder acceder a información

privada como pueden ser contraseñas de correo electrónico, información de

una investigación aún no patentada, número de cuenta bancaria, etc. En el

caso de los ataques DoS el objetivo es diferente; en este caso el ataque

consiste en evitar la ejecución de una actividad legítima, como puede ser

navegar por Internet, realizar un pedido a una tienda online o incluso transferir

dinero de una cuenta bancaria. Este tipo de ataques se consigue mediante el

envío de ciertos mensajes hacia uno de los destinatarios o el propio canal de

comunicación de modo que se impida de forma total o parcial el acceso al

servicio ofertado.

Existen dos métodos fundamentales para la realización de un ataque DoS:

la explotación de una vulnerabilidad (ataques de vulnerabilidad) y la

inundación con mensajes de apariencia legítima (ataques de inundación).

✗ Los ataques de vulnerabilidad consisten en enviar, a un equipo

remoto, una serie de mensajes construidos de manera que sean capaces

de aprovecharse de una vulnerabilidad existente en el equipo,

previamente conocida y estudiada. Estos mensajes suelen provocar el

paso por un estado del programa que su creador no había contemplado,

2

Page 23: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

1.2 Ataques de denegación de servicio (DoS)

de modo que generen un fallo como puede ser un bucle infinito en la

ejecución del programa, su parada o incluso el reinicio de la máquina

completa, etc.

✗ Los ataques de inundación consisten en el envío de un elevado número

de mensajes a un sistema, de modo que este proceso acaba por consumir

determinados recursos críticos del mismo, como pueden ser el tiempo de

CPU, el ancho de banda de la red del sistema atacado, etc. Como

consecuencia, la disponibilidad del sistema se reduce o desaparece por

completo.

Si bien los ataques de vulnerabilidad han tenido mucha importancia en un

cercano pasado, la mejora de los procesos de elaboración de software ha

reducido considerablemente su aparición. Sin embargo, han ido tomando más

importancia los ataques de inundación. Los ataques de inundación se basan en

la hipótesis de que el atacante dispone de unos recursos muy abundantes

para ejecutar el ataque. Ahora bien, puede suceder que el sistema atacado

tenga unos recursos abundantes y de este modo el ataque, desde una sola

máquina, sea ineficaz. El atacante utiliza entonces una estrategia diferente.

Debe conseguir el control de un conjunto de máquinas, llamadas agentes o

zombies, y sincronizarlas para conseguir un ataque masivo que consiga agotar

estos abundantes recursos. Los ataques que siguen esta estrategia se

denominan ataques distribuidos de denegación de servicio o DDoS [9], [10],

[11] (de las siglas en inglés: Distributed Denial of Service). Aunque para

ejecutar un DDoS se precisa un gran número de agentes el problema es la

facilidad con que los atacantes obtienen el control de un buen número de

ellos. Esto se debe a que un gran número de los usuarios de Internet no

poseen las nociones básicas de seguridad necesarias para evitar que su

máquina sea controlada por el atacante.

Otro dato que hace a los ataques DoS especialmente complejos de tratar es

que pueden utilizar tráfico similar o idéntico al legítimo, pero en cantidades

inaceptables para el sistema. Esto hace que sea muy complejo tomar medidas

contra este tipo de ataques sin que los usuarios legítimos se vean afectados.

Para mitigar este y otros problemas de seguridad en las redes de

comunicación se diseñaron unos sistemas destinados a proteger las redes de

los efectos nocivos de estos ataques. Estos dispositivos se denominan

3

Page 24: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 1: Presentación del problema y de la solución propuesta

sistemas de detección de intrusiones o IDS [12], [13] (del inglés: Intrusion

Detection System). Un IDS detecta tráfico malicioso o proveniente de un

atacante mediante la detección de anomalías probabilísticas en el tráfico de

una red de comunicaciones. Estos sistemas no tienen demasiado problema en

detectar un ataque DoS de alta tasa debido a que el tráfico generado por el

atacante es extremadamente superior al de un usuario común.

Para evitar la detección por parte de los IDS, además de para poder atacar

máquinas sin necesidad de un ordenador con unos recursos abundantes, los

atacantes diseñaron el ataque DoS a baja tasa. Este tipo de ataques DoS

utiliza la técnica de inundación pero con la gran diferencia de que no

necesitan una alta tasa de tráfico para saturar a la víctima del ataque.

Precisamente es esta tasa baja de tráfico la que convierte a este tipo de

ataques prácticamente en indetectables para los IDS.

El ataque de baja tasa es aquel que consigue saturar a la víctima del ataque

con una tasa de tráfico suficientemente baja para que no pueda ser detectado

por los sistemas de detección de intrusos que se basan en la observación de

anomalías estadísticas debidas a tasas de tráfico más elevadas de lo normal.

Esto tipo de ataques se basa en la explotación de una vulnerabilidad que

permite denegar el servicio a los clientes aún con baja tasa. Esto implica que

estos ataques pueden ser clasificados como de intrusión o de vulnerabilidad.

En un corto período de tiempo han sido desarrollados una serie de ataques de

este tipo, como son: el ataque Shrew [5], los ataques RoQ [6-8] (de reducción

de la calidad o en inglés Reduction of Quality), el ataque a baja tasa contra

servidores [1] [2], etc. En este proyecto se pretende abordar el problema de

seguridad generado por los ataques de DoS pero principalmente los generados

contra aplicaciones.

1.3 Ataques de denegación de servicio contra servidores

En este apartado se descubrirán los mecanismos para los ataques DoS contra

servidores. Para ello se propone en primer lugar un modelo de servidor para,

a continuación, ilustrar el proceso seguido por el atacante para llevar a cabo

este tipo de ataques.

4

Page 25: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

1.3 Ataques de denegación de servicio contra servidores

1.3.1 Modelo del servidor

En el ataque contra servidores, el modelo del servidor consiste en un

módulo que recibe mensajes o peticiones, los procesa y emite las respuestas

que sean necesarias. Los mensajes recibidos en este servidor pueden

proceder bien de los usuarios legítimos, bien de los usuarios

malintencionados. El servidor tiene dos tipos de respuestas: los eventos OK y

MO.

✗ Los eventos OK representan la respuesta que da el servidor a una

petición determinada de un cliente en un estado del sistema normal.

✗ Los eventos MO (de las siglas en inglés: Message Overflow) son la

respuesta que da el servidor a los clientes en un estado de sobrecarga de

las colas internas o de la memoria de la aplicación.

El modelo genérico viene descrito en la Fig. 1.1 y consta de las siguientes

secciones: un balanceador de carga1 y M máquinas servidoras, cada una de

ellas con una cola de servicio y un módulo de servicio.

1Balanceador de carga es un dispositivo encargado de distribuir el tráfico entrante entre sus salidas según una política de distribución.

5

Fig. 1.1: Modelo del servidor tomada de [2]

Cola de servicio 1

Módulo de servicio 1

MO

OK

Cola de servicio 

MMódulo de servicio M

MO

OK

∙∙∙ Máquina M

Máquina 1

Balanceador de carga

Page 26: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 1: Presentación del problema y de la solución propuesta

En la Fig. 1.1 las flechas indican en el camino que siguen las peticiones en

el modelo. La cola de servicio es el primer elemento que una petición

encuentra tras salir del balanceador de carga. Esta cola de servicio no es más

que una cola de longitud finita en la que las peticiones se almacenan hasta ser

requeridas por el modulo de servicio. En caso de estar completa la cola el

evento devuelto será MO y la petición se descartará. En los sistemas UNIX esta

cola esta implementada a través de las estructuras del tipo socket2, que

almacenan las peticiones entrantes para una determinada aplicación en un

puerto dado.

El siguiente elemento al que se dirige una petición tras haber sido

almacenada en la cola de servicio es el módulo de servicio. En éste es

procesada y se envía al cliente la consiguiente respuesta (evento OK).

El paso para la cola de servicio al módulo de servicio se realiza cuando el

módulo de servicio queda libre para aceptar una nueva petición. En el sistema

UNIX, este proceso es llevado a cabo mediante la implementación de la

llamada al sistema3 generada por la función accept, cuyo efecto es tomar una

conexión encolada y pasarla a la aplicación para su posterior manipulación.

En resumen, el camino que sigue una conexión entrante al servidor

presentado en la Fig. 1.1 es el siguiente:

1 La petición llega al balanceador de carga, que elige según su política

interna la máquina de entre las M posibles a la que la enviará,

exceptuando aquellas máquinas cuya cola se encuentre ocupada

completamente. En el caso de que todas las colas se hallen en esta

situación el balanceador decidirá aleatoriamente entre una ya que el

resultado será igualmente la devolución de un evento MO (de

sobrecarga).

2 La petición es encolada en la cola de servicio de la máquina elegida por el

balanceador de carga siempre y cuando quede alguna posición libre. En

caso contrario la petición se descarta y se envía un evento MO.

2Socket: es el elemento que permite el flujo de información entre dos puntos.3Llamada al sistema: mecanismo usado por una aplicación para solicitar un servicio al sistema operativo.

6

Page 27: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

1.3 Ataques de denegación de servicio contra servidores

3 Transcurrido el tiempo necesario en la cola, la petición pasa al módulo de

servicio en el que será procesada y tras lo cual se responderá al cliente

que inició la petición con un evento OK.

Se define ahora la estrategia seguida por los ataques de denegación a baja

tasa para, tras su conocimiento y estudio, poder así aportar una solución.

1.3.2 Ejecución del ataque de denegación de servicio contra servidores

Ya que el problema principal al que se pretende dar solución en este

documento es el de los ataques DoS, pero de una manera especial los

realizados a aplicaciones, es necesario estudiar este tipo de ataques para

conocer el problema profundamente. El objetivo básico de este tipo de

ataques consiste en evitar la disponibilidad del servidor, haciendo que el

tiempo en el que queda un espacio libre en alguna cola de servicio tienda a

cero. De este modo, la probabilidad de que los clientes realicen una conexión

en ese breve espacio de tiempo es mínima. El atacante estará consiguiendo

así que el servidor únicamente sirva sus peticiones y conseguirá, como

consecuencia de esto, denegar el servicio a todos los demás clientes.

En esta situación el servidor continúa trabajando con total normalidad

sirviendo los mensajes que tiene encolados, con la única salvedad de que

todos los mensajes que sirve son del mismo cliente: el atacante. Este

funcionamiento del servidor, en régimen de normalidad, hace aún más

compleja la detección de este tipo de ataques.

El proceso que sigue el atacante para realizar un ataque DoS a baja tasa

puede resumirse en los siguientes dos pasos:

1 Saturación de las colas de servicio. Este paso consiste en llenar todas

las colas de servicio de peticiones del atacante. La manera mediante la

que se realiza este proceso no será tratada en este proyecto y se dará por

supuesto que el atacante consigue este estado en las colas.

2 Captura del máximo número de posiciones posibles. La captura es el

acto de introducir una petición en el momento en el que se genera una

respuesta y por tanto, se libera una posición de alguna cola de servicio.

7

Page 28: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 1: Presentación del problema y de la solución propuesta

La captura es la que permite al atacante mantener el estado de

saturación de las colas de servicio a lo largo de un período de tiempo.

En las colas de servicio se libera una posición siempre y cuando el modulo

de servicio termine de procesar una petición y envíe el mensaje de respuesta.

Justo tras esta acción, el módulo de servicio que ha respondido extraerá la

siguiente conexión de su cola de servicio y generará una posición libre en ella.

A la hora de capturar el máximo número de posiciones posibles, en la cola

de servicio, el atacante puede escoger dos estrategias:

✗ Enviar una tasa de tráfico suficientemente alta de modo que la

probabilidad de capturar todas las posiciones tienda a uno. Esta estrategia

es la utilizada por los ataques DoS de tasa alta pero tiene el inconveniente

de que son relativamente sencillos de detectar por los sistemas de

seguridad.

✗ Explotar una vulnerabilidad que le permita averiguar, de algún modo, el

momento en el que alguno de los módulos de servicio llega al término del

procesamiento de una conexión y envía su respuesta. En estos instantes el

atacante envía la siguiente conexión y será también alta la probabilidad

de que ocupe el espacio libre que aparecerá en la cola de servicio. Los

detalles acerca del modo en que el atacante averigua dichos instantes

pueden consultarse en [1] [2]. En este caso el ataque DoS se hace a baja

tasa.

1.4 Solución propuesta

Conocida la problemática de los ataques DoS contra servidores y el modelo

del servidor, se plantea en este proyecto abordar una solución posible que

ayude a reducir los efectos de este tipo de ataques. La solución elegida se

basa en aplicar políticas de gestión de colas para mitigar los efectos del

ataque de denegación de servicio a baja tasa.

En este apartado se definirá primeramente qué es una política de gestión

de colas para poder plantear con base teórica la solución que se presenta.

También se explicará el funcionamiento general de estas políticas y se

concretará el funcionamiento general de las mismas en unos ejemplos que

pretenden clarificar su funcionamiento.

8

Page 29: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

1.4 Solución propuesta

Es importante aclarar en este punto que el objeto de este proyecto no es

desarrollar una solución completa al problema de los ataques DoS mediante el

desarrollo de políticas de gestión de colas. El objeto del proyecto es el

desarrollo de un entorno que permita la inclusión de cualquier política de

gestión de colas desarrollada como solución al problema. Por esta misma

razón en este apartado no se presentará la mejor política de gestión de colas

posible sino una que nos permita demostrar el funcionamiento de nuestro

entorno.

1.4.1 Políticas de gestión de colas

Se denomina política de gestión de colas a aquel mecanismo que realiza

un manejo de las colas de servicio con el fin de mitigar los efectos de los

ataques DoS. La política de gestión de colas consiste en descartar peticiones

de la cola de servicio ante la aparición de determinados estados en la misma y

eligiendo las peticiones según una estrategia determinada. Esta actuación

pretende conseguir justicia entre los usuarios evitando por tanto, que los

clientes maliciosos capturen más.

En el modelo de la Fig. 1.2 tan sólo se ilustra una de las M máquinas que

contiene el módulo servidor inicial. En este caso las M-1 máquinas restantes y

el balanceador de carga han sido obviadas por simplicidad.

9

Fig. 1.2: Modelo de servidor con módulo de gestión

Cola de servicio 1

Módulo deservicio 1

MO

OK

Máquina 1

Módulo degestión 1

Page 30: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 1: Presentación del problema y de la solución propuesta

En esta ocasión se ha incluido en el modelo del servidor un módulo

denominado módulo de gestión. Este módulo es el encargado de aplicar la

política de gestión de colas. Por tanto, se añade también un evento más a las

respuestas del servidor. Anteriormente se han descrito MO y OK y el evento

que se añade ahora es RCD (de las siglas en inglés Request Connection Drop).

Este evento se produce en el servidor cuando el módulo de gestión determina

que una conexión de las encoladas debe ser extraída de la cola y desechada.

El evento RCD podría dar como resultado el envío, al cliente correspondiente,

de un mensaje RCD. El envío de este mensaje es opcional y dependerá de la

política de gestión de colas el solicitar o no su envío. Es por esta razón por la

que la flecha que, en la Fig. 1.2, indica la expulsión de una petición encolada

con un envío de un RCD es punteada y no continua.

En resumen el funcionamiento del módulo de gestión consiste en

monitorizar la cola de servicio, de ahí la unión de éste con la cola. Tras la

recogida de cierta información de interés sobre el estado de la cola, el módulo

de gestión la procesa y actúa en consecuencia a su política interna.

La política interna que rige el módulo de gestión es la clave del éxito de

esta solución. Una buena política de gestión de colas será aquella que extraiga

de la cola el mayor número de peticiones malintencionadas del atacante,

eliminando en el camino el menor número de peticiones de los clientes

legítimos. Si se es capaz de conseguir que los clientes puedan seguir

realizando conexiones con normalidad se habrán logrado mitigar los efectos

del ataque DoS.

1.4.2 Ejemplo de una política de gestión de colas

El desarrollo de una política de gestión de colas eficiente para este tipo de

entornos es una tarea compleja y actualmente en investigación, lo que implica

que no se ha llegado a obtener una que solucione completamente la

problemática de los ataques DoS.

El motivo por el que se presenta un ejemplo de una política de gestión de

colas es el de aclarar el concepto definido en el apartado anterior, de modo

que se ilustren los detalles acerca del funcionamiento del módulo de gestión

en el servidor.

10

Page 31: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

1.4 Solución propuesta

Se podrían elegir muchas alternativas para las políticas. A modo de ejemplo,

se podría descartar una petición al azar de la cola al superar la ocupación de

ésta un umbral determinado, por ejemplo un porcentaje del tamaño máximo.

También se podrían descartar todas las peticiones existentes en la cola al

sobrepasar dicho umbral. Otra alternativa más compleja sería realizar un

análisis de la información de las peticiones encoladas determinando cuáles

son malintencionadas y descartándolas.

Se ha visto necesario implementar una política de gestión de colas

mediante la que poder probar el funcionamiento del entorno para la inclusión

de medidas de defensa frente a ataques DoS basadas en políticas de gestión

de colas. Por esta razón se ha elegido una política ejemplo sencilla en cuanto a

implementación a la par que eficaz en su funcionamiento.

Descripción del ejemplo:

Para realizar de una manera más sencilla la ilustración de este ejemplo, se

presenta seguidamente la notación que se va a utililzar. El número de

peticiones encoladas en la cola de servicio será representado por n_act, el

número de posiciones totales de la cola por n_max, el umbral de la cola a partir

del cual se aplicará una determinada estrategia de descarte por n_umb y N 

representará el número de posiciones que se descartarán de la cola.

11

Fig. 1.3: Diagrama de flujo de la política de

gestión de colas

 n_act>n_umb

Descartar Nal azar

Sí No hacer nada

Recogida del tamañode la cola (Monitorizar)

NoSi

Page 32: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 1: Presentación del problema y de la solución propuesta

La política elegida se basa en monitorizar la ocupación de la cola y cuando

ésta supere el umbral establecido, es decir, cuando n_act sea mayor que

n_umb, elegir N de las peticiones encoladas al azar y descartarlas. El umbral se

determina como una proporción del tamaño máximo de la cola. El proceso

seguido cuando se aplica la política se puede ver gráficamente en la Fig. 1.3,

en la que se presenta el diagrama de flujo de la misma.

Nótese que, en esta estrategia, la monitorización del estado de la cola se

basa exclusivamente en la observación del número de posiciones ocupadas en

cada instante. Sin embargo, podrían existir otras alternativas, como por

ejemplo, monitorizar el número de posiciones de un mismo usuario, el número

de posiciones de diferentes usuarios, etc.

Se realiza la explicación anterior ilustradándola en pseudo-código para ver

este proceso de una manera secuencial y simplificada.

repetir siempre{si n_act es mayor que n_umb{

elegir al azar N peticiones de entre las n_act;descartar la petición elegida al azar;

}}

Mitigación del efecto del ataque DoS

Hasta ahora se ha descrito un ejemplo de una política de gestión de colas

seguidamente, se pretende demostrar teóricamente cómo esta política influye

de una manera clara en la mitigación del efecto nocivo del ataque de DoS, es

decir, si tras la aplicación de la política de gestión de colas propuesta un

cliente legítimo puede acceder a los recursos del servidor con mayor

disponibilidad. Este análisis se llevará a cabo con mayor profundidad en el

Capítulo 4. Aún así ahora se explicarán las nociones básicas sin introducir

excesivos detalles.

Como se ha visto anteriormente el ataque DoS se basa en dos procesos

principalmente:

✗ Mantener las colas siempre saturadas, sin posibilidad de que nuevos

clientes puedan hacer conexiones.

✗ Capturar todas las posiciones que se habiliten en la cola mediante alta

tasa o baja tasa prediciendo los instantes en que éstas se generan.

12

Page 33: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

1.4 Solución propuesta

La política descrita con anterioridad ataca a ambos pilares: comenzando con

la saturación de las colas, esta tarea se hace mucho más compleja para el

atacante ya que la política determina un tamaño umbral a partir del cual

cuando el número de peticiones en cola lo supera un cierto número de

peticiones de las encoladas son expulsadas. De esta manera se dificulta la

tarea de mantener las colas siempre saturadas, ya que el servidor libera

posiciones siempre que se supere el umbral.

Esta política también dificulta la captura de posiciones en la cola por parte

del atacante, ya que aunque éste pueda predecir los instantes en que el

servidor envía respuestas a los clientes y, por tanto, las posiciones de la cola

liberadas de una manera normal por el servidor, no sucede lo mismo para las

peticiones que son expulsadas por la política de gestión de colas ya que esta

expulsión genera una posición libre en la cola, pero no del modo que el

atacante espera. Esto implica que no afectaría la vulnerabilidad que está

atacando el cliente malicioso gracias a la cual puede conocer la liberación de

una posición de la cola y adelantarse a los clientes legítimos en la captura de

posiciones.

En resumen, el que haya un umbral permite a los clientes legítimos ocupar

una posición de la cola de servicio ya que ésta no se encuentra saturada.

Posteriormente la política de gestión de colas liberará una petición si se ha

superado el umbral pero al elegirse aleatoriamente podrá ser tanto del

atacante como del cliente legítimo. El otro camino para que el cliente legítimo

consiga realizar una conexión es que la política de gestión de colas libere una

posición de la cola y ésta sea ocupada por el cliente. Como se ha dicho la

liberación de esta posición de la cola es invisible al atacante de modo que

genera una posición que un cliente no tendrá dificultad en ocupar.

Intuitivamente se prevé que esta sencilla política de gestión de colas es

capaz de hacerle frente a complejos mecanismos utilizados por los atacantes

para predecir el momento en el que una posición será liberada de la cola. En

los resultados mostrados en el Capítulo 4 se mostrará que, efectivamente, el

efecto del ataque DoS se reduce considerablemente.

En nuestros días existen líneas de investigación trabajando en el desarrollo

de políticas de gestión de colas para mitigar los efectos de ataques DoS. Cada

una de estas políticas pretende aportar una solución a los ataques contra los

13

Page 34: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 1: Presentación del problema y de la solución propuesta

que esté diseñada. El problema será entonces determinar si funcionan como

se planteó en teoría. También será importante determinar cual de ellas es más

eficaz. En conclusión todas ellas necesitarán evaluar su buen funcionamiento y

ser implementadas en un entorno real. Esta necesidad existente y creciente es

la que este proyecto pretende cubrir, desarrollando un marco que permita de

forma flexible implementar cualquier política de gestión de colas desarrolladas

con el objetivo de mitigar los efectos de los ataques DoS. Este entorno podrá

ser utilizado en beneficio de toda aquella investigación que lo requiera.

1.5 Objetivo y alcance del proyecto

El objetivo principal de este proyecto es desarrollar un entorno para la

inclusión de medidas de defensa frente a ataques DoS basadas en políticas de

gestión de colas. Se ha intentado que el entorno sea:

✗ Flexible de modo que quepan en él cualquier tipo de implementaciones

de políticas de gestión de colas.

✗ Proporciona una interfaz clara y cerrada para introducir nuevo código y

modificaciones.

Para presentar este entorno de la manera más sencilla posible se ha

dividido la información en los siguientes capítulos:

✗ En el segundo capítulo se realiza un análisis del núcleo de Linux para

determinar y estudiar las estructuras que intervendrán en la gestión de la

cola de servicio (del modelo del servidor). Todo este análisis está

encaminado a determinar las posiciones en el núcleo en las que hay que

insertar el nuevo código para la implementación del entorno objetivo. Para

de este modo llegar a determinar la ubicación en el núcleo del entorno a

desarrollar.

✗ El capítulo tercero muestra el proceso seguido para realizar la

modificación en el núcleo de Linux encaminada al desarrollo del entorno

para la implementación de políticas. Se indicarán alternativas de diseño

para de realizar dicha modificación razonándose el porqué de la elección

realizada. Se mostrará, en este mismo capítulo, una descripción detallada

de la modificación realizada para posibilitar la inclusión de las políticas de

gestión de colas.

14

Page 35: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

1.5 Objetivo y alcance del proyecto

✗ El cuarto capítulo está destinado a probar el funcionamiento del entorno

desarrollado mediante la implementación de una política de gestión de

colas de prueba.

✗ En el quinto capítulo se indica la planificación temporal llevada a cabo

durante la ejecución del proyecto ilustrándola con un diagrama de Gantt.

También se describen en éste los recursos tanto humanos como

materiales que han sido necesarios para la consecución de los objetivos

planteados.

✗ El sexto capítulo es en el que se recogen las conclusiones finales que se

extraen de la realización de este proyecto. Se detallan, además, unas

líneas de posibles trabajos futuros tomando como base el entorno

desarrollado en este proyecto.

15

Page 36: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 37: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

En este capítulo se estudia el modo en el que el núcleo del sistema

operativo Linux lleva a cabo el establecimiento de conexión para el protocolo

TCP. El estudio de esta sección del núcleo de Linux se ha visto necesario para

poder determinar el lugar en el que se implementará el entorno que posibilite

la inclusión de políticas de gestión de colas en este sistema. Los

conocimientos aquí presentados pueden ser útiles en el proceso de generación

de políticas de gestión de colas.

Se elige el estudio de la arquitectura de red TCP/IP por ser la más utilizada

en la actualidad y concretamente el de la conexión porque es en este proceso

en el que se añaden y extraen peticiones a las colas de servicio, como se las

llamaba en el capítulo anterior.

Otra elección realizada es la de trabajar con el núcleo del Sistema Operativo

Linux. El núcleo es el software encargado de posibilitar el acceso seguro al

hardware del ordenador o también es el que se encarga de gestionar los

recursos a través de llamadas al sistema. El núcleo también es el que decide

el tiempo que cada proceso tendrá el recurso deseado.

La razón por la que se propone la modificación del núcleo del Sistema

Operativo Linux se debe a que Linux es un sistema operativo de software libre.

El software libre es aquel que se distribuye sin coste alguno aparte de permitir

su modificación al usuario. El hecho de que se permita su modificación es el

que ha posibilitado que se disponga del código fuente del núcleo necesario

para su estudio en profundidad.

17

Page 38: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

Ahora que ya se conoce la problemática a la que se enfrenta este proyecto,

los ataques DoS y más concretamente los DoS a baja tasa, se está en

disposición de profundizar en el estudio del marco de pruebas experimentales

a desarrollar. Para comprender el funcionamiento de este marco de pruebas,

antes de especificar los detalles relativos a su ejecución, es necesario aportar

alguna información adicional.

En primer lugar, se ilustran una serie de conceptos básicos relativos al

proceso seguido para el establecimiento de conexiones en el protocolo TCP.

Posteriormente se concreta cómo se realiza este establecimiento de la

conexión en el núcleo del sistema operativo Linux, más específicamente en su

versión 2.6.24 por ser ésta la más actual en el momento de inicio del presente

proyecto. Por último, se detallan las estructuras de datos más importantes

cuyo conocimiento permitirá entender con mayor profundidad el

funcionamiento del núcleo de Linux en el establecimiento de conexión.

El capítulo está estructurado en dos partes, de la siguiente forma: En la

primera parte se describe de manera general cómo realiza la conexión el

protocolo TCP/IP incluyendo la descripción de las colas que se utilizan para

almacenar las conexiones. Estas colas son las equivalentes a la cola de

servicio en el módulo del servidor mostrado en la Fig. 1.1. Posteriormente se

describen detalladamente los dos procesos seguidos para acceder a la cola de

servicio, uno desde la red, momento en el que se añade la conexión a la cola y

otro desde el espacio de usuario, desde donde la aplicación servidora extrae

conexiones de la cola. Para ilustrar más claramente este hecho se muestra el

código de las funciones del núcleo que intervienen en este proceso.

En la segunda parte del capítulo se pasa de una descripción a alto nivel a

mostrar más detalladamente qué estructuras de datos intervienen en los

procesos antes mencionados. Se divide también en dos partes. En la primera

se describenlas estructuras socket que se utilizan en la conexión del protocolo

TCP, siendo un socket una abstracción software que permite el flujo de

información entre dos puntos. Un socket de Internet contiene básicamente las

direcciones de los participantes en la comunicación, el protocolo utilizado y el

número de puerto. En la segunda parte se muestra en detalle la estructura de

la implementación en Linux de la cola de conexiones establecidas, que es en

la que se centra este trabajo.

18

Page 39: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

Este capítulo pretende también servir de guía para el estudio del núcleo del

sistema operativo Linux. Como se ha dicho, se estudia en él el establecimiento

de la conexión del protocolo TCP. Pero el proceso que se ha seguido para su

estudio y la estructura son comunes a otras secciones del núcleo con lo que

puede ser de utilidad para aquél que pretenda enfrentarse al estudio de otra

sección.

2.1 Establecimiento de la conexión de TCP en el núcleo.

Para comprender cómo realiza el núcleo las conexiones del protocolo TCP es

necesario primero ilustrar cómo se realiza la conexión en general en dicho

protocolo.

El protocolo TCP es un protocolo orientado a conexión, lo que quiere decir

que requiere de la realización de una conexión para poder crear un flujo de

información entre los dos puntos finales de una comunicación. Este protocolo

se compone de tres fases: establecimiento de la conexión, transmisión de

datos y finalización de la conexión. La fase interesante para este proyecto es

la de establecimiento de la conexión que se detalla a continuación.

Esta primera fase se realiza mediante la llamada negociación en tres pasos

(o en inglés: three-way handshake). Consiste en una apertura activa del

cliente, que envía un segmento SYN al servidor dirigido a un determinado

puerto. Si el servidor está escuchando en este puerto y todo es correcto

responde enviando un segmento SYN+ACK al cliente y éste termina la fase de

establecimiento de la conexión respondiendo con un ACK.

En la Fig. 2.1 se puede observar gráficamente el proceso anteriormente

descrito. Además se ve que en los mensajes viaja información referente al

número de secuencia (identificada como seq). El número de secuencia es un

valor que cliente y servidor intercambian para que el protocolo pueda

asegurar que ningún mensaje se ha perdido y que todos han llegado en el

orden correcto. Por ejemplo, el cliente inicializa con un número de secuencia

al azar (x) y el servidor debe responder incrementando en uno este número de

secuencia (x+1) y enviando un nuevo número de secuencia (y) también

inicializado al azar. Por último el cliente responde incrementando el número de

secuencia que el servidor le envió (y+1). Este proceso de números de

19

Page 40: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

secuencia pretende también dificultar una posible suplantación o spoofing,

esto es, que un usuario responda al servidor haciéndose pasar por otro cliente.

Si el atacante no conoce el número de secuencia que el servidor envió al

cliente legítimo no puede incrementarlo en uno estableciendo así la conexión

y suplantando al legítimo.

Es interesante indicar cuales son los estados por los que se pasa en el

proceso de establecimiento de la conexión para, de esta forma, poder

comprender más fácilmente las explicaciones futuras. La Fig. 2.2 representa la

máquina de estados finitos del protocolo TCP para el establecimiento de la

conexión. Esta máquina de estados finitos nos es más que una ilustración en la

que se resume gráficamente el comportamiento del protocolo en el

establecimiento.

El estado indica en qué situación se encuentra en ese momento la conexión.

Hay dos puntos de vista desde los que se puede observar una conexión. Uno

es el del cliente, que inicia activamente la comunicación, y otro es el del

servidor, que se mantiene a la escucha. De este modo, el cliente no tiene

porqué ver la conexión en el mismo estado en el que la ve el servidor.

20

Fig. 2.1: Negociación en tres pasos

Page 41: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.1 Establecimiento de la conexión de TCP en el núcleo.

Se comienza estudiando el proceso desde el punto de vista del cliente:

1 Comienza en el estado CLOSED (cerrado). Realiza una apertura activa

enviando un SYN y pasa al estado SYN_SENT (syn_enviado).

2 Tras recibir el SYN+ACK del servidor envía un ACK pasando a estado

ESTABLISHED (establecida).

Se ve ahora este mismo proceso desde el punto de vista del servidor:

1 Comienza con una apertura pasiva pasando del estado CLOSED (cerrado)

al estado LISTEN (escucha).

2 Tras recibir SYN y enviar SYN+ACK pasa al estado SYN_RCVD

(syn_recibido).

3 Si recibe el ACK correcto proveniente del cliente el estado de la conexión

será ESTABLISHED (establecida).

21

Fig. 2.2: Máquina de estados finitos para el establecimiento de conexión del protocolo TCP

Page 42: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

Una vez que ambos extremos están en el estado ESTABLECIDA pueden

transferir información por la conexión establecida entre ellos.

Concepto de socket

Es obvio que para que dos aplicaciones puedan comunicarse entre sí es

necesario que se cumplan ciertos requisitos:

✗ Que una aplicación sea capaz de localizar a la otra.

✗ Que ambos sean capaces de intercambiarse cualquier secuencia de

octetos, es decir, datos relevantes a su finalidad.

Para ello son necesarios tres recursos que originan el concepto de socket:

• Un protocolo de comunicaciones, que permite el intercambio de octetos.

• Una dirección del protocolo de red (dirección IP, cuando consideramos el

protocolo IP), que identifica un ordenador.

• Un número de puerto, que identifica a una aplicación dentro de un

ordenador.

Los sockets permiten implementar una arquitectura cliente-servidor. La

comunicación ha de ser iniciada por uno de los programas, que se denomina

programa cliente. El segundo programa espera a que el otro inicie la

comunicación, por este motivo se denomina programa servidor.

Un socket es una abstracción software en la máquina cliente y en la

máquina servidora, que sirve, en última instancia, para que el programa

servidor y el cliente lean y escriban la información. Esta información será la

transmitida por las diferentes capas de red.

Colas de servicio existentes en Linux

Hasta ahora se ha visto el proceso de establecimiento de la conexión en el

protocolo TCP. Un servidor recibirá peticiones de múltiples clientes que

pasarán por estados diferentes. El servidor necesita un tiempo para procesar

estas peticiones y, por tanto, no podrá atender a todos los clientes a la vez.

Para solventar esta situación, el módulo servidor (Fig. 1.1) contiene colas de

servicio en las que se almacenarán estas peticiones. La implementación de la

cola de servicio y su modo de funcionamiento dependen del sistema operativo

22

Page 43: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.1 Establecimiento de la conexión de TCP en el núcleo.

considerado e incluso del núcleo concreto. Como se dijo en la introducción, en

este proyecto se considera el núcleo del sistema operativo Linux en su versión

más actual, en el inicio de este proyecto, la v. 2.6.24.

En el caso del núcleo 2.6.24 de Linux la implementación de la cola de

servicio para conexiones TCP se divide en dos colas diferentes [3]: una para

las peticiones SYN recibidas del cliente y otra para las conexiones

completadas:

1 Cola de conexiones incompletas. Tiene una entrada por cada cliente

que ha enviado un SYN. Para estas conexiones el servidor se encuentra en

el estado SYN_RCVD.

2 Cola de conexiones completadas. En ésta se encuentra una entrada

por cada cliente que ha completado la negociación en tres pasos, con lo

que se encuentran en el estado ESTABLECIDA.

Cuando el servidor recibe un SYN correcto almacena esta petición en la cola

de conexiones incompletas, enviando posteriormente un SYN+ACK. Tras la

recepción del correcto ACK de respuesta, pasa esta petición de la cola de

peticiones incompletas a la última posición de la cola de peticiones

completadas, modificando su estado a ESTABLECIDA. Es decir, al completarse

correctamente el establecimiento de conexión se introduce la petición en la

cola de completadas.

La manera en la que se extraen conexiones de la cola de peticiones

completadas es recibiendo la llamada desde la aplicación de la función accept 

y pasando al espacio de usuario la primera petición en la cola de peticiones

completadas. De esto se deriva que la cola de peticiones completadas sigue

una distribución FIFO (First Input First Output), lo que quiere decir que la

primera conexión en entrar a la cola será la primera conexión en ser servida.

En la Fig. 2.4 podemos ver este proceso gráficamente.

Estas colas, como en el caso del modelo del servidor descrito en el Capítulo

1, tienen un tamaño finito. El tamaño de la cola de conexiones completadas,

en el caso del núcleo de Linux, viene determinada por la variable backlog. Es

siempre una unidad superior a ésta.

23

Page 44: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

Si bien la cola de conexiones incompletas afecta al comportamiento de la

entrada de las conexiones a la aplicación, la implementación que realmente

corresponde a la cola de servicio del modelo del servidor es la de conexiones

completadas. Por esta razón, interesa el comportamiento de esta cola, a la

que se accede de dos formas:

✗ Se añaden conexiones a la cola de conexiones completadas al pasar del

estado SYN_RCVD al estado ESTABLISHED y esto se produce al recibir el

ACK como respuesta final de la negociación en tres pasos y siempre y

cuando quedase espacio en esa cola (acceso desde la red).

✗ Se extraen peticiones cuando la aplicación llama a la función accept. En

este caso la primera conexión de la cola pasa al espacio de usuario

(acceso desde la aplicación).

Existen, por tanto, dos posibilidades para modificar la cola de conexiones

completadas que se pueden describir, también, desde la visión de capas de la

arquitectura de red TCP/IP:

24

Fig. 2.3: Movimiento de las peticiones en las colas [4]

Servidor

Negociación en tres pasos completada

Cola de conexionescompletadas.Estado: ESTABLISHED

Cola de conexionesincompletas.Estado: SYN_RCVD

Llegada de un SYN

Page 45: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.1 Establecimiento de la conexión de TCP en el núcleo.

✗ 1º Desde la capa de aplicación:

La aplicación le pide a la capa de Transporte

que acepte la conexión de la cola de

conexiones completadas.

✗ 2º Desde la capa de red:

A través de la capa Física llega el ACK que

finaliza la negociación en tres pasos y consigue

pasar la petición a la cola de conexiones

completadas.

A continuación se ilustran los detalles de estos dos caminos.

2.1.1 Acceso a la cola de conexiones completadas desde la aplicación.

En este punto se ilustra la sección de código en el núcleo destinada a

extraer una petición de la cola de peticiones completadas. Como se ha

explicado anteriormente el acceso a la cola de peticiones completadas desde

la aplicación se realiza para extraer de ésta la primera petición encolada y

pasarla al espacio de usuario (Fig. 2.5).

Para explicar el modo en el que esta operación es realizada en el núcleo, se

continúa el proceso de búsqueda que se realizó en su momento. Se adopta

esta estrategia por considerarse la más clara para el lector, de este modo

podrá seguir la cadena de razonamientos que en su momento fue necesario

desarrollar. Para aclarar esto del mejor modo posible se incluyen secciones de

código que confirman las suposiciones presentadas. Estas secciones vendrán

siempre delimitadas con dos líneas, una al inicio y otra al final. En el extremo

25

Fig. 2.5: Extracción de una petición de la cola de

conexiones completadas

Fig. 2.4: Capas de la

arquitectura de red TCP/IP

APLICACIÓN

TRANSPORTE

RED

ENLACE

Cola de conexionesestablecidas

socketaccept()

Page 46: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

derecho de esta línea se indicará la ruta del archivo del que se está

extrayendo el código. El código contendrá el número de línea que ocupa en el

archivo origen al inicio de la misma. Si se pretende consultar el archivo

completo se puede descargar el código fuente del núcleo de Linux de la

página oficial http://www.kernel.org/ y recordar que la versión utilizada es la

2.6.24.

En este momento es importante determinar los diferentes modos de

ejecución que provee el sistema operativo Linux, entendiéndose por ello: la

manera en la que al proceso concreto que ocupa la CPU le está permitido

ejecutarse. En el sistema operativo Linux existen dos modos de ejecución:

1 Modo usuario: permite la ejecución de instrucciones que no afectan a

otros procesos. Se ejecuta en el espacio de usuario.

2 Modo privilegiado: permite la ejecución de todas las instrucciones. Se

ejecuta en el espacio de núcleo.

Para localizar el código en el que se extrae una petición de la cola de

peticiones completadas se sigue el camino que realiza la función accept. La

función accept está en la librería libc, y desde ella se solicita al núcleo al

núcleo que ejecute las instrucciones que en el espacio de usuario están

restringidas. La petición al núcleo se realiza mediante una llamada al sistema.

Las llamadas al sistema son las encargadas de comunicar los espacios de

núcleo y de usuario.

El camino teórico que sigue la función accept puede verse en la Fig. 2.6. La

aplicación llama a la función accept y ésta necesita ejecutar operaciones en

modo privilegiado. Al no poder hacerlo, ya que se encuentra en el espacio de

usuario recurre a una llamada al sistema. La llamada al sistema accede al

núcleo y le pide que ejecute la tarea que en este caso necesitara realizar

accept. El núcleo entonces realiza la operación solicitada devolviendo el

resultado.

El siguiente paso es descubrir como se implementa una llamada al sistema

de red en Linux. Concretamente nos interesa ver la implementación de accept 

para el protocolo TCP. El prototipo de accept (en el espacio de usuario) es:

#include <sys/types.h> #include <sys/socket.h> int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

26

Page 47: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.1 Establecimiento de la conexión de TCP en el núcleo.

La llamada al sistema que se genera con esta función se llama:

sys_socketcall.

                                                                        arch/m32r/kernel/syscall_table.S

1ENTRY(sys_call_table)2        .long sys_restart_syscall/* 0  ­  old "setup()" system call*/...104        .long sys_socketcall

                                                                        arch/m32r/kernel/syscall_table.S

Ésta es una llamada al sistema que engloba a todas las llamadas a

funciones de la librería de sockets. En función de un parámetro de dicha

llamada al sistema se ejecutará una función u otra. A continuación se presenta

la implementación:

27

Fig. 2.6: Camino seguido por una función que deba acceder al núcleo

aplicación

hardware

núcleo

librería

Interacción mediante llamadas al sistema

Interacción mediante llamadas a funciones

Page 48: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

                                                                                            net/socket.c

2007asmlinkage long sys_socketcall(int call, unsigned long __user *args)2008{2009        unsigned long a[6];2010        unsigned long a0, a1;2011        int err;...2040        case SYS_ACCEPT:2041                err =2042                    sys_accept(a0, (struct sockaddr __user *)a1,2043                               (int __user *)a[2]);2044                break;

                                                                                            net/socket.c

En dicha implementación, según el parámetro de la llamada al sistema

llamado call, se llama a una función u otra. En nuestro caso de estudio,

cuando call = SYS_ACCEPT, se llama a la función sys_accept, definida también

en socket.c.

La función sys_accept realiza varias funciones y finalmente llama a la

función del listening socket (el socket que recibe las conexiones y las

establece hasta que se llama a accept), denominado sock, mediante la

invocación:

                                                                                            net/socket.c1421        err = sock­>ops­>accept(sock, newsock, sock­>file­>f_flags);

                                                                                            net/socket.c

Hay que notar que ops es una estructura del tipo proto_ops, la cual tiene un

puntero a función que se llama accept.

                                                                                     include/linux/net.h 135struct proto_ops { 136        int             family;... 147        int             (*accept)    (struct socket *sock, 148                                      struct socket *newsock, int flags);

                                                                                     include/linux/net.h

Este puntero se inicializa a la función que implementa la llamada accept 

cuando se crea el socket, de modo que, dependiendo del tipo de socket que se

crea, la implementación de la función es diferente. En nuestro caso de estudio,

el protocolo es TCP y se supone IPv4, por lo que la asignación de la función se

realiza en el siguiente código:

                                                                                          net/tcp_ipv4.c 2414struct proto tcp_prot = { ... 2420        .accept                 = inet_csk_accept,

                                                                                          net/tcp_ipv4.c

28

Page 49: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.1 Establecimiento de la conexión de TCP en el núcleo.

Por tanto, la implementación de la llamada accept es la función

inet_csk_accept, cuya implementación se presenta a continuación:

                                                                         net/ipv4/inet_connection_sock.c/* 210 * This will accept the next outstanding connection. 211 */ 212struct sock *inet_csk_accept(struct sock *sk, int flags, int *err) 213{ 214        struct inet_connection_sock *icsk = inet_csk(sk); 215        struct sock *newsk; 216        int error; 217 218        lock_sock(sk); 219 220        /* We need to make sure that this socket is listening, 221         * and that it has something pending. 222         */ 223        error = ­EINVAL; 224        if (sk­>sk_state != TCP_LISTEN) 225                goto out_err; 226 227        /* Find already established connection */ 228        if (reqsk_queue_empty(&icsk­>icsk_accept_queue)) {... 241        newsk = reqsk_queue_get_child(&icsk­>icsk_accept_queue, sk); 242        BUG_TRAP(newsk­>sk_state != TCP_SYN_RECV);... 250}

                                                                         net/ipv4/inet_connection_sock.c

Primero se bloquea el socket para posteriormente asegurarnos de que se

encuentra en el estado LISTEN. Es interesante recordar que el socket de

escucha, el que se encuentra en el servidor, debe estar en el estado LISTEN

para poder recibir peticiones. Tras esto en la línea 228 se revisa si la cola está

vacía con la función reqsk_queue_empty. Esta cola es la cola de peticiones

establecidas, ya que es la que hay que comprobar en accept si tiene alguna

posición ocupada para poder extraerla. Nótese también que en la línea 241, la

función reqsk_queue_get_child utiliza de nuevo esta cola; veamos qué se hace

en esta función:

                                                                         net/ipv4/inet_connection_sock.c

 183static inline struct sock *reqsk_queue_get_child(struct  184                      request_sock_queue *queue,struct sock *parent) 185{ 186        struct request_sock *req = reqsk_queue_remove(queue); 187        struct sock *child = req­>sk; 188 189        BUG_TRAP(child != NULL); 190 191        sk_acceptq_removed(parent); 192        __reqsk_free(req); 193        return child; 194}                                                                         net/ipv4/inet_connection_sock.c

29

Page 50: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

Como vemos la cola pasada como argumento, queue, es una estructura del

tipo request_sock_queue, cuya estructura se explicará en la Apartado 2.2.2.

Dentro de esta función se llama (línea 186) a la función reqsk_queue_remove,

que es la encargada de extraer el socket que ocupa la primera posición de la

cola de peticiones establecidas (llamado child) para más tarde devolverlo

(línea 193).

Así pues del análisis de este código podemos deducir por tanto que la cola

de peticiones establecidas es la icsk­>icsk_accept_queue, la cual se estudiará

más adelante en profundidad.

2.1.2 Acceso a la cola de conexiones completadas desde la red.

Ahora veremos el otro camino para acceder a la cola de peticiones

completadas. Buscamos la implementación de este proceso en el núcleo

sabiendo que la sección que nos interesa especialmente se encuentra en el

término de la negociación en tres pasos, momento en el que el núcleo extrae

la petición de la cola de conexiones incompletas y la añade a la cola de

conexiones completadas.

En la Apartado 2.2.1, describiremos la estructura

inet_connection_sock_af_ops en la que se encontrarán diferentes punteros a

funciones de TCP y en el siguiente punto se presentarán sus correspondencias

a las funciones para el caso de IPv4.

Buscando en el archivo en el que se definen dichas funciones

(net/ipv4/tcp_ipv4.c) se puede encontrar la función tcp_v4_syn_recv_sock  (el

puntero a función del que viene es syn_recv_sock). A continuación se describe

en mayor profundidad esta función ya que será de gran interés más adelante.

                                                                                     net/ipv4/tcp_ipv4.c1411/*1412 * The three way handshake has completed ­ we got a valid synack ­1413 * now create the new socket.1414 */1415struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,1416                                  struct request_sock *req,1417                                  struct dst_entry *dst)1418{

                                                                                     net/ipv4/tcp_ipv4.c

30

Page 51: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.1 Establecimiento de la conexión de TCP en el núcleo.

El comentario que encontramos al inicio de esta función ya nos indica que

estamos ante la función buscada. Nos comenta que la negociación en tres

pasos ha sido terminada y tenemos un synack válido lo que implica que

debemos crear el nuevo socket. Con el nuevo socket se refiere al que será

añadido a la cola de peticiones completadas.

                                                                                     net/ipv4/tcp_ipv4.c1419        struct inet_request_sock *ireq;1420        struct inet_sock *newinet;1421        struct tcp_sock *newtp;1422        struct sock *newsk;1423#ifdef CONFIG_TCP_MD5SIG1424        struct tcp_md5sig_key *key;1425#endif14261427        if (sk_acceptq_is_full(sk))1428                goto exit_overflow;14291430        if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL)1431                goto exit;14321433        newsk = tcp_create_openreq_child(sk, req, skb);1434        if (!newsk)1435                goto exit;1436

                                                                                     net/ipv4/tcp_ipv4.c

En esta primera parte de la función se definen las variables a utilizar y se

comprueban varias condiciones de error para, en caso de cumplirse alguna,

salir de la función. Además se crea el socket newsk con la función

tcp_create_openreq_child. Ésta crea un socket con todos los parámetros por

defecto.                                                                                     net/ipv4/tcp_ipv4.c1437        newsk­>sk_gso_type = SKB_GSO_TCPV4;1438        sk_setup_caps(newsk, dst);14391440        newtp                 = tcp_sk(newsk);1441        newinet               = inet_sk(newsk);1442        ireq                  = inet_rsk(req);1443        newinet­>daddr        = ireq­>rmt_addr;1444        newinet­>rcv_saddr    = ireq­>loc_addr;...1449        newinet­>mc_ttl       = ip_hdr(skb)­>ttl;1450        inet_csk(newsk)­>icsk_ext_hdr_len = 0;                                                                                     net/ipv4/tcp_ipv4.c

En esta sección del código se rellenan los campos específicos del socket con

la información pasada como argumento a la función.                                                                                     net/ipv4/tcp_ipv4.c1451        if (newinet­>opt)1452                inet_csk(newsk)­>icsk_ext_hdr_len = newinet­>opt­>optlen;1453        newinet­>id = newtp­>write_seq ^ jiffies;14541455        tcp_mtup_init(newsk);1456        tcp_sync_mss(newsk, dst_mtu(dst));

31

Page 52: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

1457        newtp­>advmss = dst_metric(dst, RTAX_ADVMSS);1458        tcp_initialize_rcv_mss(newsk);...1479        return newsk;14801481exit_overflow:1482        NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);1483exit:1484        NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);1485        dst_release(dst);1486        return NULL;1487}                                                                                     net/ipv4/tcp_ipv4.c

Por último, se realizan unas comprobaciones y se devuelve el socket

creado o NULL si el código ha devuelto alguna condición de error. Si esta

función devuelve NULL la función en la que se utiliza y a la que le llegará este

valor nulo entenderá esto como un listen_overflow. En el siguiente extracto

de código de la función tcp_check_req se ve un claro ejemplo de esto:

                                                                                net/ipv4/tcp_minisocks.c 488struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, 489                           struct request_sock *req, 490                           struct request_sock **prev) 491{... 651                child = inet_csk(sk)­>icsk_af_ops­>syn_recv_sock(sk, skb, 652                                                                 req, NULL); 653                if (child == NULL) 654                        goto listen_overflow;... 681                inet_csk_reqsk_queue_removed(sk, req); 682 683                inet_csk_reqsk_queue_add(sk, req, child); 684                return child; 685 686        listen_overflow: 687                if (!sysctl_tcp_abort_on_overflow) {...

                                                                                net/ipv4/tcp_minisocks.c

Como se puede ver (línea 653 se) comprueba si child, el socket devuelto

por la función syn_recv_sock, analizada anteriormente, es igual a NULL. En caso

de serlo la línea 654 se ejecutaría y por tanto se envía a la línea 686 que como

ya sabíamos indica listen_overflow.

Como ya se ha explicado la función syn_recv_sock es la que devuelve el

socket que debe ser incluido en la cola de peticiones completadas. Pero la

función que la añade es la resaltada en gris en la sección de código anterior

inet_csk_reqsk_queue_add. Es importante comprender el funcionamiento de

esta función para así comprender en última instancia el funcionamiento de la

cola de peticiones aceptadas.

32

Page 53: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.1 Establecimiento de la conexión de TCP en el núcleo.

✗ La función inet_csk_reqsk_queue_add llama a su vez a la función

reqsk_queue_add que se desarrolla tras ésta.                                                                      include/net/inet_connection_sock.h 255static inline void inet_csk_reqsk_queue_add(struct sock *sk, 256                                            struct request_sock *req, 257                                            struct sock *child) 258{ 259        reqsk_queue_add(&inet_csk(sk)­>icsk_accept_queue, req, sk, child); 260}                                                                      include/net/inet_connection_sock.h

✗ La función reqsk_queue_add añade el socket child, pasado como

argumento, a la cola request_sock_queue (llamada queue).

                                                                              include/net/request_sock.h 169static inline void reqsk_queue_add(struct request_sock_queue *queue, 170                                   struct request_sock *req, 171                                   struct sock *parent, 172                                   struct sock *child) 173{ 174        req­>sk = child; 175        sk_acceptq_added(parent); 176 177        if (queue­>rskq_accept_head == NULL) 178                queue­>rskq_accept_head = req; 179        else 180                queue­>rskq_accept_tail­>dl_next = req; 181 182        queue­>rskq_accept_tail = req; 183        req­>dl_next = NULL; 184}

                                                                              include/net/request_sock.h

Si nos fijamos en la función inet_csk_reqsk_queue_add la cola que en esta

función llamamos queue es la cola asociada a sk. Habiendo sido sk pasado

como argumento a esta función en la que adopta el nombre de parent. Este

socket (sk en inet_csk_reqsk_queue_add  o parent en reqsk_queue_add) es el

que tiene la información de la conexión como es: la cola de peticiones

establecidas, objeto de nuestro estudio.

La manera de añadir el socket child es incluirlo en el request_sock (llamado

req). El siguiente paso es añadirlo a la lista enlazada4 de modo que se debe

apuntar la última posición de queue a éste, ocupando por tanto la última

posición de la cola. Por último, se ha de apuntar el siguiente de req (es decir

dl_next) a NULL  debido a que req es ahora el último de la cola y no tiene

ninguna petición tras él. Como vemos las nuevas peticiones se incluyen en la

última posición de la cola.

4Lista enlazada: es una cola cuyos elementos apuntan todos ellos al siguiente exceptuando al último ya que éste no tiene sucesor.

33

Page 54: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

Se elige la función tcp_v4_syn_recv_sock para añadir en ella el código

necesario que permita desarrollar el marco para la inclusión de políticas de

gestión de colas como acción para mitigar los efectos de los ataques DoS, que

es el objeto de este proyecto. La razón por la cual es ésta la función elegida se

debe a que es por esta función por la que se pasa tras el término correcto de

la negociación en tres pasos. Esta función devuelve el nuevo socket que será

añadido a la cola de peticiones completadas. Es esta función un lugar

estratégico desde el que se puede monitorizar perfectamente la cola de

conexiones establecidas y tomar, dependiendo de la política de gestión de

colas que se haya implementado, una decisión u otra.

2.2 Estudio de las estructuras software implicadas en la conexión TCP.

Una vez descrito a alto nivel el proceso del establecimiento de conexión y

concretado en los dos caminos que se siguen en el núcleo para acceder a la

cola de conexiones establecidas estamos en disposición de ahondar en el

conocimiento de las estructuras que intervienen en este proceso.

En la primera parte de esta sección se explicarán las estructuras socket que

intervienen en el establecimiento de conexión de TCP. En la segunda y última

parte de esta sección se profundizará en el conocimiento de la estructura de la

cola de conexiones establecidas y de las estructuras de las que ésta hace uso.

2.2.1 Estructuras socket para la conexión.

Para la definición completa de todas las estructuras que intervienen en el

establecimiento de conexión para el núcleo 2.6 de Linux partiremos de la más

general para, paso a paso, llegar hasta la más particular. El siguiente esquema

nos muestra gráficamente la organización de estas estructuras:

En la Fig. 2.7 podemos observar cómo cada estructura aparte de contener a

la general del nivel superior añade unas particularidades no especificadas en

la imagen. Por ejemplo: el nivel superior (más general) lo forma la estructura

sock_common y la estructura sock contiene a la sock_common y añade unas

particularidades que detallaremos a continuación.

34

Page 55: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.2 Estudio de las estructuras software implicadas en la conexión TCP.

Para explicar la función de cada estructura y la información que añaden

unas con respecto a otras se ha visto conveniente mostrar el código de cada

una de ellas para desde éste poder fundamentar las explicaciones realizadas.

En el código presentado generalmente no se muestra la estructura completa

sino las partes importantes o que serán de utilidad en explicaciones futuras.

Se resaltará en cada estructura la información interesante para la

comprensión completa del trabajo realizado en este proyecto.

✗ Estructura sock_common:

                                                                                      include/net/sock.h 112struct sock_common { 113        unsigned short          skc_family; 114        volatile unsigned char  skc_state; 115        unsigned char           skc_reuse; 116        int                     skc_bound_dev_if; 117        struct hlist_node       skc_node; 118        struct hlist_node       skc_bind_node; 119        atomic_t                skc_refcnt; 120        unsigned int            skc_hash; 121        struct proto            *skc_prot; 122};

                                                                                      include/net/sock.h

35

Fig. 2.7: Estructuras socket

sock_common

sock

inet_sock

inet_connection_sock

Page 56: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

Esta estructura es la representación mínima de los socket de la capa de red.

Con esto queremos decir que esta mínima representación se utiliza para

conectar dos puntos de una red. Esta comunicación puede ser entre dos

procesos dentro de una misma máquina, o entre dos procesos en máquinas

distintas. Si se produce en la misma máquina el dominio de comunicación será

AF_UNIX y si la comunicación se realiza entre máquinas distintas el dominio de

comunicación será AF_INET. En esta estructura encontramos básicamente:

• Las características generales de los socket de red (familia, estado,

nodo, etc.).

✗ Estructura sock:

                                                                                      include/net/sock.h 183struct sock { 184        /* 185        * Now struct inet_timewait_sock also uses sock_common, so please just 186         * don't add nothing before this first member (__sk_common) ­­acme 187         */ 188        struct sock_common      __sk_common; 189#define sk_family               __sk_common.skc_family... 201        unsigned char           sk_protocol; 202        unsigned short          sk_type;... 210        struct { 211                struct sk_buff *head; 212                struct sk_buff *tail; 213        } sk_backlog;... 259        int                     (*sk_backlog_rcv)(struct sock *sk, 260                                                  struct sk_buff *skb);   261        void                    (*sk_destruct)(struct sock *sk); 262};

                                                                                      include/net/sock.h

Esta estructura representa los socket de red y en ella encontramos

básicamente:

• La estructura sock_common (llamada sk_common) definida en el punto

anterior.

36

sock_common

sock

inet_sock

Page 57: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.2 Estudio de las estructuras software implicadas en la conexión TCP.

• Las características generales de los socket de red como son familia,

estado, etc. (extraídas de sk_common)

• Una estructura sk_backlog que es la encargada de almacenar los datos

enviados por el enlace TCP.

• Otras características más concretas de los socket de red como puede

ser sk_type que indica el tipo de socket STREAM, DATAGRAM o RAW.

Los socket STREAM son utilizados para el protocolo TCP que es orientado a

conexión y que implica, como hemos visto, un establecimiento de la

conexión.

Los socket DATAGRAM para el protocolo UDP. Lo que implica que son no

orientados a conexión así que no requieren establecimiento de conexión.

Los socket RAW se utilizan para el desarrollo de nuevos protocolos o para

hacer uso de funcionalidades ocultas en los protocolos existentes.

• Punteros a funciones como son las mostradas en el código

(sk_backlog_rcv, sk_destruct) y otras que no mostramos.

✗ Estructura inet_sock:

                                                                                 include/net/inet_sock.h 107struct inet_sock { 108/* sk and pinet6 has to be the first two members of inet_sock */ 109        struct sock             sk; 110#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 111        struct ipv6_pinfo       *pinet6; 112#endif 113        /* Socket demultiplex comparisons on incoming packets. */ 114        __be32                  daddr; 115        __be32                  rcv_saddr; 116        __be16                  dport;

                                                                                 include/net/inet_sock.h

37

sock_common

sock

inet_sock

inet_connection_sock

Page 58: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

Esta estructura representa los socket de red del tipo INET que son aquellos

cuyo dominio de comunicación es del tipo AF_INET. Esto quiere decir que los

procesos que están siendo comunicados están en diferentes sistemas unidos

por una red TCP/IP. Estos son los utilizados para comunicarse en Internet. En

esta estructura encontramos básicamente:

• La estructura sock (llamado sk) descrita en el punto anterior.

• Los datos de la conexión: puerto de destino (dport), dirección de destino

(daddr), etc. Útiles en para obtener información de los clientes al

monitorizar la cola.

• Una estructura ip_options con las opciones del protocolo IP. Desde esta

estructura podremos consultar las opciones del protocolo IP para una

conexión concreta.

✗ Estructura inet_connection_sock:

                                                                      include/net/inet_connection_sock.h

  84struct inet_connection_sock {  85        /* inet_sock has to be the first member! */  86        struct inet_sock          icsk_inet;  87        struct request_sock_queue icsk_accept_queue;...  94        const struct tcp_congestion_ops *icsk_ca_ops;  95        const struct inet_connection_sock_af_ops *icsk_af_ops;...  97        __u8                      icsk_ca_state;                                                                      include/net/inet_connection_sock.h

Esta estructura define los socket de red INET más concretamente los

orientados a conexión que son los implicados en este proyecto ya que nos

basamos en el protocolo TCP que es, a su vez, orientado a conexión. En esta

estructura encontramos básicamente:

38

sock_common

sock

inet_sock

inet_connection_sock

Page 59: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.2 Estudio de las estructuras software implicadas en la conexión TCP.

• La estructura inet_sock que se describe en el punto anterior.

• La cola de conexiones establecidas (icsk_accept_queue) cuya estructura

definiremos más adelante.

• Una serie de datos de la conexión como son el estado de control de

congestión (icsk_ca_state).

• Una estructura tcp_congestion_ops con punteros a función para

gestionar la congestión.

• La estructura inet_connection_sock_af_ops que estudiamos en el

siguiente punto.

Hasta aquí el estudio de las estructuras socket que intervienen en el

establecimiento de conexión. Es interesante estudiar antes de pasar al

siguiente punto las estructuras ops para mostrar el lugar en el que

encontramos la función tcp_v4_syn_recv_sock. Que como ya se ha comentado ha

sido trascendental en la elaboración de este proyecto.

✗ Estructura inet_connection_sock_af_ops:

                                                                      include/net/inet_connection_sock.h

  39struct inet_connection_sock_af_ops {...  45        struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb,  46                                      struct request_sock *req,  47                                      struct dst_entry *dst);  48        int         (*remember_stamp)(struct sock *sk);

                                                                      include/net/inet_connection_sock.h

Esta estructura contiene:

• Punteros a función que gobiernan el proceso de la conexión TCP como la

función que se utiliza al finalizarse la negociación en tres pasos

(syn_recv_sock). Estas funciones fueron estudiadas hasta dar con la

comentada en el apartado 2.1.2 Desde la red por ser ésta la más apta

para la consecución de nuestro objetivo como se comentó al término de

este apartado. Como dijimos el puntero a función no es más que una

dirección donde empieza a definirse la función. Dependiendo del

protocolo IP que se esté utilizando estos punteros apuntarán a una u

otra definición. Para el caso de IP versión 4 (la más utilizada ahora

mismo en Internet) el siguiente archivo indica las funciones a las que

estos punteros a función deben apuntar.

39

Page 60: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

✗ Funciones de inet_connection_sock_af_ops en el caso de Ipv4:                                                                                     net/ipv4/tcp_ipv4.c1812struct inet_connection_sock_af_ops ipv4_specific = {1813        .queue_xmit        = ip_queue_xmit,1814        .send_check        = tcp_v4_send_check,1815        .rebuild_header    = inet_sk_rebuild_header,1816        .conn_request      = tcp_v4_conn_request,1817        .syn_recv_sock     = tcp_v4_syn_recv_sock,                                                                                     net/ipv4/tcp_ipv4.c

Para ver esta compleja operación de un modo más sencillo

particularizaremos la cuestión en un único puntero a función syn_recv_sock.

Éste para el caso de Ipv4, como vemos en la sección de código superior en la

línea 1817, apunta a la función tcp_v4_syn_recv_sock. La definición de esta

función será la que se utilizará en caso de usar el puntero a función indicado y

en el caso de estar en el protocolo Ipv4.

2.2.2 Estructura de la cola de peticiones completadas.

Este proyecto se centra en la intervención sobre la cola de peticiones

completadas que se describe en las primeras páginas de este capítulo. Esta

cola es icsk_accept_queue y por esta razón se ha visto necesario crear un

apartado exclusivo para describirla en profundidad.

Dentro de la estructura inet_connection_sock encontramos la cola

icsk_accept_queue es una estructura del tipo request_sock_queue y como se ha

comentado el objeto de nuestro estudio. Se presenta un esquema útil para su

comprensión en la Fig. 2.8. Para estudiarla en profundidad, por tanto, hemos

de conocer el funcionamiento de la estructura request_sock_queue. Aquí

presentamos la sección del núcleo en la que esta estructura queda definida:

                                                                              include/net/request_sock.h 115struct request_sock_queue { 116        struct request_sock     *rskq_accept_head; 117        struct request_sock     *rskq_accept_tail; 118        rwlock_t                syn_wait_lock; 119        u8                      rskq_defer_accept; 120        /* 3 bytes hole, try to pack */ 121        struct listen_sock      *listen_opt; 122};

                                                                              include/net/request_sock.h

40

Page 61: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.2 Estudio de las estructuras software implicadas en la conexión TCP.

Sus características principales son:

• Contiene una cabeza y una cola que son, a su vez, estructuras del tipo

request_sock (esta estructura es la que hay en cada posición de la cola).

• Y una estructura listen_sock (llamada listen_opt). Que tratamos a

continuación.

✗ Estructura listen_opt:

                                                                              include/net/request_sock.h

  86 * @max_qlen_log ­ log_2 of maximal queued SYNs/REQUESTs  87 */  88struct listen_sock {  89        u8                      max_qlen_log;  90        /* 3 bytes hole, try to use */  91        int                     qlen;  92        int                     qlen_young;  93        int                     clock_hand;  94        u32                     hash_rnd;  95        u32                     nr_table_entries;  96        struct request_sock     *syn_table[0];  97};

                                                                              include/net/request_sock.h

41

Fig. 2.8: Estructura de la cola de conexiones establecidas

request_sock_queue

request_sock head

request_sock tail

. . .

request_sock request_sock request_sock

socket sk1

dl_next dl_next

socket sk2 socket sk3

dl_next

NULL

. . .. . . . . .

Page 62: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 2: Análisis de la implementación de TCP/IP en Linux

Define características del estado de la escucha, entre las que destacamos,

por su utilidad en los siguientes capítulos, max_qlen_log que representa el

logaritmo en base 2 del máximo de solicitudes/syn que pueden ser encoladas

y qlen que son el número de solicitudes /syn encoladas.

✗ Estructura request_sock:

                                                                              include/net/request_sock.h

  45struct request_sock {  46        struct request_sock             *dl_next; /* Must be first member! */  47        u16                             mss;  48        u8                              retrans;  49        u8                              __pad;  50        /* The following two fields can be easily recomputed I think ­AK */  51        u32                             window_clamp;  52        u32                             rcv_wnd;           53        u32                             ts_recent;  54        unsigned long                   expires;  55        const struct request_sock_ops   *rsk_ops;  56        struct sock                     *sk;  57        u32                             secid;  58        u32                             peer_secid;  59};                                                                              include/net/request_sock.h

Esta estructura es un mini sock que representa una solicitud de conexión,

es un miembro de la lista enlazada (request_sock_queue) y básicamente

contiene:

• Un puntero al socket siguiente.

• Una serie de características de la solicitud de conexión.

• Un puntero a una estructura constante del tipo request_sock_ops que se

definirá a continuación.

• Un puntero a la estructura sock que es la que lleva la información de la

conexión, como ya se ha visto.

✗ Estructura request_sock_ops:                                                                              include/net/request_sock.h  29struct request_sock_ops {  30        int             family;  31        int             obj_size;  32        struct kmem_cache       *slab;  33        int             (*rtx_syn_ack)(struct sock *sk,  34                                       struct request_sock *req,  35                                       struct dst_entry *dst);  36        void            (*send_ack)(struct sk_buff *skb,  37                                    struct request_sock *req);  38        void            (*send_reset)(struct sock *sk,  39                                      struct sk_buff *skb);  40        void            (*destructor)(struct request_sock *req);  41};                                                                              include/net/request_sock.h

42

Page 63: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

2.2 Estudio de las estructuras software implicadas en la conexión TCP.

Esta estructura contiene:

– Punteros a función cuya implementación hemos de encontrar para el caso

de Ipv4.

✗ De la misma forma que encontramos la implementación de accept 

encontramos también la de los punteros a función de request_sock_ops:                                                                                     net/ipv4/tcp_ipv4.c1235struct request_sock_ops tcp_request_sock_ops __read_mostly = {1236        .family         =       PF_INET,1237        .obj_size       =       sizeof(struct tcp_request_sock),1238        .rtx_syn_ack    =       tcp_v4_send_synack,1239        .send_ack       =       tcp_v4_reqsk_send_ack,1240        .destructor     =       tcp_v4_reqsk_destructor,1241        .send_reset     =       tcp_v4_send_reset,1242};                                                                                     net/ipv4/tcp_ipv4.c

Estas funciones son las que rigen el envío de los posibles mensajes del

establecimiento de conexión de TCP.

2.3 Conclusiones del capítulo.

Como resumen del presente capítulo y con objeto de hacer especial

hincapié en las cuestiones más importantes, se presentan a continuación las

principales conclusiones obtenidas en este capítulo:

✗ Se han analizado las estructuras que se han considerado interesantes para

ilustrar el funcionamiento del establecimiento de conexión del protocolo

TCP, y el de la cola de conexiones establecidas, en el núcleo de Linux.

✗ Se ha identificado la función tcp_ipv4_syn_recv como la idónea para

introducir en ella las modificaciones que permitirán el desarrollo del marco

para la inclusión de medidas de defensa frente a ataques DoS basados en

políticas de gestión de colas.

43

Page 64: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 65: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleo de Linux

En el Capítulo 1 en el se ha determinado cómo actúan los ataques DoS y,

más concretamente, los ataques DoS contra servidores. Para este tipo de

ataques se propuso una solución consistente en aplicar una política de gestión

de colas que imposibilitara o dificultara en cierta medida la efectividad de este

tipo de ataques. Posteriormente, en el segundo capítulo, se ha ilustrado el

mecanismo de establecimiento de la conexión del protocolo TCP. Se han

identificado también las estructuras que intervienen en este proceso en el

núcleo del sistema operativo Linux y se ha mostrado que la cola de peticiones

establecidas será la que nuestro módulo de gestión monitorice. Se ha

localizado además la sección del código de Linux en que se debe insertar el

código encargado de la gestión de las colas.

Partiendo del desarrollo de políticas de gestión de colas para mitigar el

problema de los ataques DoS, en este proyecto se plantea la necesidad de

implementarlas en un entorno real. La manera en la que se ha propuesto

solventar esta necesidad es generando un entorno flexible para la inclusión de

medidas de defensa contra ataques DoS basadas en gestión de colas en el

núcleo del Sistema Operativo Linux. Este marco pretende ser una herramienta

para todo aquel que pretenda el desarrollo de una política de gestión de colas

para mitigar el problema derivado de los ataques DoS. Esta herramienta debe

permitir, de la manera más sencilla posible, incluir cualquier política de

gestión de colas en el núcleo de Linux y poder comprobar cómo se comporta

en un entorno real.

45

Page 66: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

Es éste, por tanto, el capítulo destinado a mostrar cómo ha sido el desarrollo

del ya mencionado entorno para la inclusión de medidas de defensa para

ataques DoS. El capítulo se encuentra dividido en tres partes bien

diferenciadas. La primera es la encargada de profundizar en el concepto de

núcleo de un sistema operativo y en el desarrollo de módulos del núcleo o

simplemente módulo. Se explicará la manera en la que el núcleo de Linux

puede ser modificado, ya sea mediante modificación directa, incluyendo

código en él o mediante el uso de módulos del núcleo. Por último se explicarán

los motivos que nos guiaron a realizar la modificación del núcleo con el apoyo

de módulos del núcleo. En la segunda parte del capítulo se identifican las

dificultades encontradas al intentar modificar el núcleo mediante módulos, y

se ilustra la medida adoptada finalmente: la utilización de garfios (en inglés

hook [2]). La tercera y última parte de este tema está destinada a ilustrar el

mecanismo de creación de módulos utilizando hooks. Este proceso se ilustrará

mediante la explicación del módulo generado para implementar el entorno

comentado. También se descubrirá la implementación de una política de

gestión de colas que permite probar el funcionamiento del marco de pruebas

generado.

3.1 Núcleo y módulos del núcleo

El sistema operativo Linux es un sistema operativo de código libre. Esto

quiere decir no solamente que su distribución es por completo legal y gratuita,

sino mucho más. Lo que implica también es que el código fuente que lo

compone esta a disposición de todo el que quiera descargarlo. Este hecho nos

entrega una herramienta extremadamente poderosa gracias a la cual ha sido

posible realizar este proyecto. Nos brinda la posibilidad de introducir cambios,

a nuestro antojo, en el funcionamiento de todo el sistema. Precisamente ese

tema es el trata de aclarar esta sección, el de introducir cambios en el sistema

operativo.

El núcleo del sistema operativo Linux está organizado siguiendo una

arquitectura monolítica, en la cual, todas sus partes (sistemas de ficheros,

manejadores de dispositivos, protocolos de red, etc.) están enlazadas como

una sola imagen que es la que se carga y ejecuta en el arranque del sistema.

Esta estructura lo hace bastante eficiente, ya que disminuye los cambios de

46

Page 67: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

3.1 Núcleo y módulos del núcleo

contexto, es decir, los cambios de espacio de direcciones de usuario a núcleo,

para poder ejecutar instrucciones en modo privilegiado. Por contra, el ser un

sistema monolítico implica también que existe una menor fiabilidad. A modo

de ejemplo la gestión de ficheros del sistema puede tener acceso a la gestión

de la tarjeta de red y esto podría ser nefasto e incluso constituir una

vulnerabilidad a explotar desde el punto de vista de un posible atacante.

También podría dar lugar a un sistema poco flexible, ya que cualquier

funcionalidad que se le quisiera añadir al núcleo del sistema requeriría una

recompilación completa del mismo. Como veremos en el Apartado 3.1.2 esta

flexibilidad ha sido mejorada en sucesivas versiones de Linux.

3.1.1 Compilación del núcleo

El primer procedimiento para modificar el núcleo de Linux es muy directo.

Consiste en modificar el código directamente sobre el código fuente de Linux.

Tras esta modificación debe compilarse el núcleo para obtener el objeto

imagen que deberá ser cargado para que se pueda ejecutar el nuevo núcleo.

El proceso de compilación del núcleo es costoso tanto en tiempo como en

recursos del sistema. Esto implica que la compilación completa del sistema

podría llevar alrededor de 3 horas dependiendo del ordenador utilizado en el

proceso. Para entender este mecanismo de la manera más sencilla posible

supongamos que el núcleo no es más que un programa, de dimensiones

desproporcionadas y complejidad extrema, pero un programa al fin y al cabo.

Suponiendo esto el proceso para obtener la imagen de este programa pasaría

por compilarlo y enlazarlo.

En resumen estas son las operaciones realizadas en el proceso de

compilación (Fig. 3.1). Generalmente a la imagen obtenida se le asigna el

nombre de vmlinuz y a continuación la versión del núcleo compilado.

Una vez se ha obtenido la imagen del nuevo núcleo lo único que ha de

conseguirse es que el sistema cargue esta imagen y no la antigua. La

consecución de este objetivo pasa por modificar el archivo menu.lst que se

encuentra en el directorio /boot/grub/ si se usa el gestor de arranque Grub. Se

podría decir que en este archivo se le indica al gestor de arranque Grub el

conjunto de núcleos de los que dispone y entre los que el usuario, al iniciar el

sistema, elegirá.

47

Page 68: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

Una vez realizada por primera vez la compilación del núcleo las sucesivas

ocasiones no requerirán que se compile de nuevo todo el código fuente sino

solamente aquél al cual la modificación realizada le afecte. A este proceso de

posteriores compilaciones se le denomina recompilación y aunque no requiere

tanto tiempo sí que implica un necesario reinicio del sistema para que los

nuevos cambios entren en vigor.

3.1.2 Módulos del núcleo

La limitación que impone la engorrosa tarea de reiniciar cada vez que

necesitamos aplicar un nuevo cambio a nuestra modificación del núcleo

desapareció con la incorporación, en la versión 1.2 de Linux, del soporte para

la carga dinámica de módulos en el núcleo (en inglés Loadable Kernel Module 

LKM). Este nuevo avance permitió la incorporación de una modificación al

núcleo sin la necesidad de reiniciar el sistema completo. Lo que implica que si

necesitamos realizar cualquier cambio en un módulo esto sólo tomará el

tiempo necesario para recompilar el código y recargar el módulo, proceso que

consiste en la simple ejecución de dos instrucciones, tal y como se explicará

más adelante.

48

Fig. 3.1: Esquema simplificado de la recompilación del núcleo

Page 69: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

3.1 Núcleo y módulos del núcleo

¿Qué es un módulo del núcleo?

Los módulos son programas escritos en el lenguaje de programación del

núcleo, ANSI C. La característica peculiar que tienen estos programas es la

capacidad de, una vez obtenida su imagen, ser cargados en tiempo de

ejecución, es decir, sin necesidad de reiniciar el sistema y pasar a formar

parte del núcleo con toda su capacidad. Existe la desventaja de no poder

utilizar ninguna función de las que se implementan en las librerías

convencionales como puede ser printf(), o rand(), etc. Deberemos utilizar las

funciones propias del núcleo como son printk(), get_random_byte(), etc. Esta

desventaja implica un tiempo importante de análisis del código del núcleo

para así hallar la función requerida. Sin embargo, se podrá ejecutar el código

en modo privilegiado, lo que da control sobre todas las funciones del sistema

y, más aún, sobre el hardware del mismo.

Por tanto, un módulo es un fichero o conjunto de ficheros con extensión .c 

que, al ser compilados con las opciones correspondientes, producen una

imagen con extensión .ko que puede ser cargada en tiempo de ejecución del

sistema.

Estructura de un módulo del núcleo

Un módulo del núcleo debe cumplir ciertos requisitos que le permitirán ser

insertado en el núcleo. El módulo tendrá una estructura determinada para que

su compilación sea exitosa y se pueda cargar con éxito tras ella.

La estructura puede resumirse en las siguientes secciones (Fig. 3.2):

✗ Cabeceras necesarias. Necesitaremos, al menos, las cabeceras de

kernel.h que nos indica que trabajamos en relación al núcleo y module.h 

que implica que el código que realizamos no es sólo relativo al núcleo sino

que es un módulo del núcleo.

✗ Funciones init_module y cleanup_module. Estas funciones son las

encargadas de cargar el módulo en el sistema y de descargarlo ambas a

petición del usuario con las sentencias que se indicarán más adelante en

esta sección.

49

Page 70: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

✗ Funciones auxiliares. Funciones que realicen las operaciones deseadas

y que serán utilizadas en el interior de init_module o de cleanup_module.

Estas funciones no es obligatorio que aparezcan en el código pero es

común utilizar en programación la política de “Divide y vencerás” que

consiste en dividir un problema en secciones a las se les da solución con

una función. Posteriormente todas ellas son encuadradas en una misma.

Una vez cargado el módulo la única diferencia entre su código y el código

del núcleo es la posibilidad de poder ser extraído a petición del usuario. Al

realizar esta extracción se liberarán todos los recursos que el módulo hubiera

utilizado, según se indique en la función cleanup_module.

La manera en la que el módulo puede ejecutar funciones del núcleo sin

haber sido enlazado en tiempo de compilación con él, consiste en que las

referencias a las funciones del núcleo utilizadas no están resueltas. Para que

estas referencias queden configuradas de una manera correcta, el proceso de

inserción de un módulo debe seguir una rutina muy específica:

1 Obtener las referencias a las funciones del módulo.

2 Incluir dichas referencias al núcleo. Siendo éstas temporales para que al

ser liberado el módulo desaparezcan.

50

Fig. 3.2: Estructura básica de un

módulo del núcleo

Page 71: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

3.1 Núcleo y módulos del núcleo

3 Hallar las referencias a las funciones no resueltas en el módulo. Que son:

las funciones propias del núcleo o las funciones exportadas por otros

módulos.

4 Incluir el módulo en el espacio de memoria reservado al núcleo para que

pueda ejecutarse en modo privilegiado.

5 Por último, invocar a la función init_module del nuevo módulo.

Para extraer el módulo también es necesario realizar una rutina concreta.

Ésta realiza los mismos primeros cuatro pasos, en orden inverso, y el quinto

consiste en invocar a la función cleanup_module.

Proceso de carga y descarga de un módulo del núcleo

Para la carga y la descarga de módulos del núcleo se utilizan las funciones

insmod y rmmod. Para realizar cualquiera de estas operaciones debemos ser

superusuarios así que se ejecutarán precedidas por sudo5. Un módulo es

cargado ejecutando la sentencia sudo insmod seguida del nombre de la imagen

del núcleo que como ya se ha mencionado tiene extensión .ko.

sudo insmod hook.ko

El módulo es descargado ejecutando sudo rmmod y añadiendo el nombre del

módulo cargado que, a menos de haber sido cambiado voluntariamente, será

igual que la imagen exceptuando su extensión.

sudo rnmod hook

Para ver si un módulo ha sido correctamente cargado se puede consultar la

lista de módulos cargados en el sistema esto se lleva a cabo consultando el

archivo modules en el directorio /proc/.

cat /proc/modules

Ejecutando esta orden en una terminal Linux se podrá visualizar el

contenido del archivo modules. También se puede realizar esta consulta con el

comando lsmod que lista la información contenida en el archivo /proc/modules 

de una manera más ordenada. Escribiendo lsmod en la termina se obtiene una

salida de cuatro columnas.

5Sudo es una orden de la shell de Linux que da permisos de superusuario para ejecutar la orden que le siga.

51

Page 72: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

Module                 Size  Used by af_packet              23812  2 l2cap                  25728  13 rfcomm 

✗ La primera muestra el nombre del módulo. Generalmente es el mismo

nombre que el archivo que se carga pero sin la extensión .ko.

✗ La segunda indica el número de memoria en bytes que ocupa el módulo.

✗ La tercera el número de instancias de este módulo que actualmente están

lanzadas. Un valor de 0 indica que puedes descargar el módulo.

✗ La cuarta columna representa los módulos en los que éste es utilizado.

3.1.3 Módulos vs implementación directa en el núcleo

En el presente proyecto se ha optado por la implementación mediante el

uso de módulos. Las razones por las que se elige realizar la modificación del

núcleo mediante un módulo y no mediante la modificación directa sobre el

núcleo son varias y se detallan a continuación:

✗ El proceso de implementación de cualquier programa pasa por una fase de

constantes modificaciones en las que se va depurando el código hasta

obtener el resultado deseado. Si este proceso lo realizáramos modificando

directamente sobre el núcleo tras cada variación de la implementación

necesitaríamos un reinicio del sistema y esto conllevaría grandes tiempos

de espera.

✗ La fase de pruebas del entorno para una política concreta dada necesita

someter el sistema a las mismas condiciones aplicando la política y sin

aplicarla, y esto de nuevo conllevaría un gran número de reinicios del

sistema.

✗ El realizar esta modificación mediante un módulo del núcleo permite

presentar una interfaz gracias a la cual el usuario no debe introducir el

código en un archivo del núcleo y dentro de él en una función concreta.

Este interfaz ofrece un nivel de abstracción más por el que no es necesario

modificar los archivos con el código fuente del núcleo para poder incluir

una política de gestión de colas.

52

Page 73: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

3.2 Módulos de seguridad de Linux (LSM) y garfios.

3.2 Módulos de seguridad de Linux (LSM) y garfios.

En esta sección se describen las dificultades encontradas al tratar de

implementar, en un módulo del núcleo, el entorno que posibilita la inclusión de

políticas de gestión de colas en el núcleo de Linux, descrito en la Apartado

3.2.1. Posteriormente se muestra la solución encontrada a dichas dificultades:

los garfios, descrita en la Apartado 3.2.2. Por último se muestra cómo se ha

realizado una modificación en el núcleo de Linux utilizando garfios, descrito en

la Apartado 3.2.3.

3.2.1 Dificultad hallada en la implementación del módulo.

Ya se ha comentado que los módulos del núcleo son realmente útiles y esto se

debe, en gran parte, a su peculiar característica de poder ser cargados en

tiempo de ejecución, siendo innecesario el reinicio del sistema. Son utilizados

típicamente en tres escenarios:

✗ Driver para dispositivos. Un driver para dispositivos es diseñado para

una sección específica del hardware. El núcleo los utiliza para comunicarse

con la sección de hardware sin tener que conocer ningún detalle acerca de

cómo funciona.

✗ Driver para sistemas de ficheros. Este tipo de drivers interpreta el

contenido de un sistema de almacenamiento de información como

ficheros y directorios. Hay muchos caminos diferentes de almacenar

ficheros. Por ejemplo, el sistema de ficheros utilizado universalmente por

Linux es ext2, y Windows utiliza NTFS o FAT32. Para manejarlos

necesitamos los driver para esos sistemas de ficheros.

✗ Llamadas al sistema. Los programas del espacio de usuario utilizan las

llamadas al sistema para solicitar servicios al núcleo. Por ejemplo, la

llamada al sistema mencionada en el Apartado 2.1.1 sys_socketcall que

solicita servicios relacionados con la tarjeta de red.

El núcleo está preparado para insertar módulos en los escenarios descritos

pero realizar modificaciones en otro sentido, como por ejemplo, en un lugar

concreto del núcleo requiere de un análisis exhaustivo del código. En el caso

53

Page 74: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

del presente proyecto es necesario modificar el núcleo en un punto concreto,

como se dijo en el Apartado 2.1.2, en la función  tcp_v4_syn_recv_sock. Por

esta razón el hecho de aplicar los módulos del núcleo como hasta ahora se

han explicado se hace complejo. La solución escogida es una adaptación de un

modo concreto de modificación mediante módulos descrito en [2]. Esta

modificación es posible gracias a los garfios (hooks) utilizados en los módulos

de seguridad de Linux o LSM (del inglés: Linux Security Modules) que se

describen en el próximo apartado. La utilización de los garfios en el trabajo

citado se hace de una manera excesivamente compleja y hace uso de una

llamada al sistema creada para este fin y de unas librerías que no son

necesarias para la modificación que se persigue en este proyecto. Por este

motivo ha sido necesario adaptar el método de modificación utilizado en LSM

para satisfacer las necesidades de este proyecto.

3.2.2 Solución encontrada: Garfio.

El objetivo de los LSM es dar solución al problema que se encontró al

descubrir que los mecanismos de control de acceso de los principales sistemas

operativos eran inadecuados. Debido a que los sistemas operativos deben

satisfacer un amplio rango de requerimientos de los usuarios, es necesario,

del mismo modo, que cualquier mecanismo de control de acceso instalado en

el sistema sea capaz de soportar una multitud de modelos de control de

acceso diferentes. Para este fin se desarrolló un marco para el núcleo de Linux

que permite una gran variedad de modelos de control de acceso para ser

implementados en el sistema como módulos del núcleo.

La creación de LSM perseguía un objetivo similar al que se propone en este

proyecto, que ciertas políticas de seguridad fueran aplicadas en puntos

concretos del núcleo en los que se comprobarían, en caso de estar cargado el

núcleo, una serie de condiciones para permitir el acceso o no de esta petición.

Es por este motivo por el que se presenta, someramente, la idea con la que el

proyecto LSM consiguió aplicar dichas modificaciones en lugares específicos

del código fuente de Linux.

54

Page 75: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

3.2 Módulos de seguridad de Linux (LSM) y garfios.

LSM permite el acceso a los objetos del núcleo incluyendo trozos de código

denominados garfios. Justo antes de que el núcleo tenga acceso a un objeto

interno, un garfio realiza la operación de llamar a la función que el módulo

LSM debe proveer. Se podría decir que el garfio pregunta a la función que

implementa la política de control de acceso (en el caso de LSM) si puede darle

el control del objeto requerido (Fig. 3.3). La política implementada en el

módulo LSM analiza la información que tiene y determina si permite o no el

acceso respondiendo en consecuencia. Una adaptación de este mecanismo se

puede aplicar perfectamente para la creación de la modificación concreta en

la función tcp_v4_syn_recv_sock.

En resumen el objetivo de un garfio es el de, en el punto concreto del

código en el que se incluya, llamar a la función del módulo que analiza el

estado de la información del núcleo y decide si pasa o no la política de control

de acceso. La ventaja encontrada para la modificación del núcleo mediante

garfios es precisamente la que hizo que se la adoptara como método para la

generación del entorno objeto de este proyecto. Los garfios permiten

modificar el núcleo en puntos concretos de su código y como se ha comentado

en el inicio de este punto ésta era precisamente la necesidad que se había

detectado.

55

Fig. 3.3: Esquema de funcionamiento de un garfio

Espacio de usuario

Espacio de núcleo

Nivel de proceso de usuario

Llamada al sistema

Garfio

Acceso al objeto

Examina si pasala política

Módulo LSM

Sí o No

¿Puedo?

Page 76: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

3.2.3 Proceso de implementación de un garfio.

Para que el garfio desarrollado funcione correctamente es necesario que

éste actúe, como es lógico, sobre el núcleo y sobre el módulo, por esto mismo

se comentó que esta solución era intermedia entre los módulos del núcleo y la

modificación directa sobre él. De esta forma este punto se divide en dos

partes: laparte describe la implementación necesaria en el núcleo y la

siguiente en el módulo.

Para ilustrar de un modo más concreto cómo se realiza una modificación en

el núcleo mediante un módulo del núcleo ayudado de un garfio, en los

siguientes puntos se describen, sin profundizar en detalles minuciosos, las

secciones más interesantes del código desarrollado para la creación del

entorno para la inclusión de medidas de defensa frente a ataques DoS.

Implementación en el núcleo

El elemento de programación que realizará la función de garfio será una

estructura denominada access_control_rodgom. Cuando se hable de una

instanciación concreta de dicha estructura se la llamará access_cont.

El contenido de esta estructura es de un único elemento: un puntero a

función. Este puntero a función es la clave del éxito de la modificación

mediante garfios, es el encargado de apuntar a la función_inútil, que no

aplica ninguna política, hasta que el módulo es cargado momento en el que

pasa a apuntar a la función descrita en el módulo que implementa la política

de gestión de colas (Fig. 3.4).

Para la correcta utilización del mecanismo de los garfios debe crearse un

archivo que es denominado de definición y cuya extensión es .h que

concretamente ha sido almacenado como rodgom.h. La estructura del archivo

de definición debe ser la siguiente:

✗ La primera parte incluye las cabeceras que son necesarias para la

ejecución del código posterior.

//Cabecera que nos permite utilizar la estructura sock entre otras.#include <net/sock.h> 

56

Page 77: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

3.2 Módulos de seguridad de Linux (LSM) y garfios.

✗ Debe contener la definición de la estructura access_control_rodgom que

debe formar parte del núcleo. En cuyo interior se encuentra el puntero a

función.

//Definición de la estructura struct access_control_rodgom { 

int (*modificacion) (struct sock *sk,struct sock *newsk); 

};

✗ Una función con el mismo formato que el puntero a función de la

estructura access_control_rodgom, es decir, con el mismo tipo de dato en

su devolución y los mismos argumentos. Esta función será la llamada

función inútil y será a la que llame el garfio mientras el módulo esté

descargado. Para que el núcleo continúe con su ejecución normal, sin

ningún tipo de modificación, mientras el módulo está descargado, es

necesario que esta función no realice ninguna operación.

57

Fig. 3.4: Funcionamiento de un garfio

Puntero a función

Estructura access_control_rodgom

Función inútil {   No hacer nada}

Función inútil

Modificación del núcleo

Modificación del módulo

Función útil {   Política de gestión de      colas}

Función útil

access_cont

Page 78: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

inline int modificacion_tonta(struct sock *sk,struct sock *newsk){ 

printk(KERN_ALERT "Estoy pasando por tontolandia\n"); return 0; 

}

Otra cuestión a tener en cuenta es que este archivo de definición debe

ubicarse en un lugar lógico dentro de la estructura compleja del código fuente

del núcleo Linux y al tratarse un de un archivo .h y tratar del tema de red el

lugar propuesto es include/net/rodgom.h. La estructura esquematizada de la

cabecera rodgom.h se encuentra en la Fig. 3.5.

La otra modificación que es necesaria para el funcionamiento del módulo se

realiza en el archivo .c del núcleo en el que se pretende incluir la modificación.

En nuestro caso comentamos que la función en la que incluiríamos la

modificación era tcp_v4_syn_recv_sock y ésta se encuentra definida en el

archivo net/ipv4/tcp_ipv4.c que será el citado archivo en el que se habrá de

incluir la modificación explicada a continuación. Para su conveniente

localización, todas las secciones de código incluidas por este proyecto están

precedidas y seguidas de la cadena //rodgom. La estructura de esta

modificación es la siguiente:

58

Fig. 3.5: Estructura de rodgom.h

Archivo de definición rodgom.h

estructura access_control_rodgom {

Puntero a función

}

Definición de la función inútil {

No hacer nada

}

Cabeceras .h

Page 79: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

3.2 Módulos de seguridad de Linux (LSM) y garfios.

✗ Lo primero que ha hecho es incluir en las cabeceras una entrada para el

archivo de definición sin el cual no se reconocerá la nueva estructura

access_control_rodgom.

70#include <net/rodgom.h> //Siempre que el archivo esté en include/net/

✗ El paso siguiente consiste en definir e inicializar una instancia de la

estructura en la sección de las variables globales de este archivo para

poder utilizarla en cualquiera de sus funciones. También debe estar

colocada en la sección de las variables globales para poder exportarla y

que posteriormente el módulo del núcleo pueda reconocerla. La

incialización pretende apuntar el puntero a función que contiene en su

interior a la función inútil que definimos en el fichero de definición

(modificación_tonta). En la Fig.3.6 se encuentra un resumen del proceso

que está siendo descrito.

90 struct access_control_rodgom access_cont = { 9192 .modificacion=modificacion_tonta, 9394 };9596 EXPORT_SYMBOL(access_cont);

59

Fig. 3.6: Estructura de modificación del archivo del núcleo

tcp_ipv4.c

Archivo del núcleo tcp_ipv4.c

#Inclusión del archivo de definición rodgom.h...En la declaración de las variables globales:1 Declaramos una estructura access_cont2 La definimos apuntando su función la inútil3 Exportamos dicha estructura...En el espacio a incluir la modificación:1 Llamamos a la función de la estructura

Page 80: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

✗ Por último se incluye la llamada al puntero a función a través de la

estructura definida al inicio del archivo (access_cont) en el punto en el que

se pretende que el garfio actúe, es decir, en la línea de código en la que la

política de gestión de colas debe entrar en funcionamiento. A esta función

deben pasársele los argumentos necesarios que serán la información de la

que dispondrá el módulo de gestión para monitorizar la cola de servicio.

1480 access_cont.modificacion(sk,newsk);

Implementación del módulo

El módulo en sí debe estar estructurado de una manera en particular que

pasamos a detallar (Fig. 3.7):

✗ Debe incluir el archivo de definición de extensión .h en el que se define la

estructura access_control_rodgom, aparte de las cabeceras propias de los

módulos (kernel.h y module.h) y las necesarias para el funcionamiento de

la política de gestión de colas.

#include <linux/kernel.h> #include <linux/module.h> ...#include <net/rodgom.h> #include <linux/random.h>

60

Fig. 3.7: Estructura de creación del módulo del núcleo

Módulo hook.c

Cabeceras .hextern de access_contfunción útil {

política de gestión de colas}init_module{

guardamos el estado de access_contsu puntero a función lo apuntamos a la últil

}cleanup_module{

devolvemos a su estado anterior a access_cont}

Page 81: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

3.2 Módulos de seguridad de Linux (LSM) y garfios.

✗ En el espacio destinado a la definición de las variables globales debe

definirse la estructura access_cont. Para que esta definición se reconozca

como el mismo objeto que se exportó desde el archivo del núcleo de

extensión .c deben cumplirse estos dos requisitos:

□ La definición debe ser precedida de la palabra clave extern.

□ Debe denominarse exactamente de la misma forma que se hizo en

el archivo del núcleo desde el que se exportó. En este caso en el

archivo net/ipv4/tcp_ipv4.c se define con el nombre de

access_cont de modo que este debe ser el nombre otorgado en el

módulo.

extern struct access_control_rodgom access_cont;

✗ Tras esta definición y las de las variables globales en general deberá

presentarse la declaración de la función que en su interior contiene la

ejecución de la política de gestión de colas. Esta función debe tener el

mismo formato que la definida en el archivo de definición en el interior de

la estructura access_control_rodgom.

int modificacion_real(struct sock *sk, struct sock *newsk) {      IMPLEMENTACIÓN DE LA POLÍTICA DE GESTIÓN DE COLAS}

✗ El módulo desarrollado, por mucho se trate de un módulo que es llamado

a través de un garfio, sigue siendo un módulo y por tanto debe contener

las funciones int_module y cleanup_module:

□ La función init_module debe encargarse de almacenar una copia

de la de la estructura access_cont, para en la descarga del módulo

poder restaurarla a su valor anterior y también de apuntar el

puntero a función del interior de la estructura a la función de este

módulo que implementa la política de gestión de colas.

□ La función cleanup_module se encarga para apuntar de nuevo la

estructura access_cont al valor que tenía antes de que se llamara

al módulo dejando de esta forma el núcleo exactamente igual a

como estaba antes de ser cargada la política de gestión de colas.

61

Page 82: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

int init_module(){     access_cont_backup=access_cont;     access_cont.modificacion=&modificacion_real;     printk(KERN_ERR "Se feliz\n");     return 0; } 

void cleanup_module() {     access_cont=access_cont_backup;     printk(KERN_ERR "Nos vamos ya sea contentos o descontentos\n"); }

3.3 Implementación de una política de gestión de colas.

Como se comentó en el primer capítulo, en este proyecto se pretende

también es necesario generar una política de gestión de colas básica para

demostrar que el entorno presentado es capaz de incluir estas políticas en el

núcleo de Linux. A continuación se ilustrará la implementación ejemplo de

política de gestión de colas que se comentó en el Apartado 1.4.2.

Se presenta la Fig. 3.8 en la que se apoyará la explicación de la política de

gestión desarrollada.

62

Fig. 3.8: Diagrama de flujo de la política de

gestión de colas ejemplo

 n_act>n_umb

Descartar Nal azar

Sí No hacer nada

Recogida del tamañode la cola (Monitorizar)

NoSi

Page 83: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

3.3 Implementación de una política de gestión de colas.

✗ La información necesaria para realizar la monitorización de la cola de

servicio, que en este caso consiste en controlar el número de conexiones

encoladas, se consigue a través de los argumentos de la función

modificación_real.

✗ El siguiente punto es comprobar si el tamaño actual de la cola supera al

del umbral. En nuestro código el umbral es establecido al tamaño máximo

de la cola menos uno. De este modo la política es llevada a cabo cuando la

última posición de la cola de conexiones establecidas va a ser ocupada.

      //Recogemos el tamaño actual de la cola      sk_ack_backlog = sk­>sk_ack_backlog;       //Recogemos el tamaño máximo de la cola      sk_max_ack_backlog = sk­>sk_max_ack_backlog; 

//El umbral es el tamaño máximo de la cola menos uno tam_max= sk_max_ack_backlog­1; if(sk_ack_backlog>tam_max){

          SE LLEVA A CABO EL DESCARTE DE N CONEXIONES AL AZAR      }

✗ El último paso consiste en no hacer nada si aún no se ha superado el

umbral o descartar N conexiones al alzar si esta condición se ha cumplido.

for (i=0;i<N;i++){            //Recogemos el tamaño actual de la cola            sk_ack_backlog = sk­>sk_ack_backlog;            //Generamos un número aleatorio de entre las conexiones 

buffer=&tam_max; get_random_bytes((void *)buffer, 4); buffer=(unsigned int *)buffer; posicion=*buffer; posicion=posicion%sk_ack_backlog + 1; 

            //Obtenemos el socket elegido con una función que puede            //consultarse en el Anexo C

child=obtener_socket(sk,queue,posicion); if(child==NULL) { 

printk(KERN_ERR "Es NULL\n"); } else {

                  //Si se devuelve el socket de la posición elegida                   //se cierra esa conexión con tcp_close.

tcp_close(child,0); printk(KERN_ERR "Tiro una conexion: Se feliz\n");

 }

     }

63

Page 84: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

El uso de tcp_close, implica un envío de un segmento Fin tras el cual se

inicia el cierre de conexión. De la misma forma que se ha utilizado esta

función en la política diseñada, otra distinta podría descartar la conexión de la

cola sin comunicárselo al cliente. El código completo de los archivos

implicados en la creación del módulo se encuentra en el Anexo A.

Anexo 3.A: Códigos desarrollado para la generación del entorno.

Código del archivo hook.c#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/tcp.h> #include <net/ip.h> #include <net/inet_connection_sock.h> #include <net/rodgom.h> #include <linux/random.h> 

MODULE_LICENSE("Dual BSD/GPL"); 

//Estructura que contiene el garfio extern struct access_control_rodgom access_cont; static struct access_control_rodgom access_cont_secundaria; //Función utilizada para cerrar la conexión o conexiones que //determine la política de gestión de colas extern void tcp_close(struct sock *sk,long timeout); //Función utilizada para elegir un número aleatorio. extern void get_random_bytes(void *buf, int nbytes); 

/* Función obtener_socket.  * Esta función está destinada a devolver el socket que se encuentra  * en el interior de la peticion almacenada en la posición (posicion)  * dentro de la lista enlazada queue  */ static struct sock *obtener_socket(struct sock *sk,struct request_sock_queue *queue, int posicion) { 

//Entero i que controlará la búsqueda en la lista enlazada que forman las peticiones. 

int i; //Punteros a la estructuras request_sock gracias a los que 

recogeremos la petición elegida. struct request_sock *elegido, *anterior;  struct inet_sock* inet; struct sock *child; 

        __u16 lport;         __be16 rport;         __be16 sport; 

//Nos colocamos al inicio de la cola de peticiones (en la cabeza) 

64

Page 85: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Anexo 3.A: Códigos desarrollado para la generación del entorno.

elegido = queue­>rskq_accept_head;  for(i=1;i<posicion;i++){ 

//Si elegido es NULL estamos ante un error así que salimos ç //del método indicándolo if(elegido!=NULL){ 

//printk(KERN_ERR "Antes de dl_next\n"); anterior = elegido; elegido = anterior­>dl_next; 

else{ printk(KERN_ERR "Devolvemos NULL\n"); return NULL; 

} } if(posicion == 1){ 

//Si el elegido es la cabeza. La cabeza la apuntamos al siguiente del elegido 

queue­>rskq_accept_head=elegido­>dl_next; } else{ 

//Apuntamos dl_next del anterior al siguiente del elegido anterior­>dl_next=elegido­>dl_next; 

} inet = inet_sk(elegido­>sk); lport = inet­>num; rport = inet­>dport; sport = inet­>sport; 

        printk(KERN_ERR "La conexion numero: %d tiene lport: %d rport: %d sport: %d\n",i,lport,rport,sport); 

child=elegido­>sk; sk_acceptq_removed(sk); __reqsk_free(elegido);  

return child; } 

int modificacion_real(struct sock *sk, struct sock *newsk) {  

int sk_ack_backlog, sk_max_ack_backlog,qlen,error,tam_max,r;  unsigned int *buffer; unsigned int posicion; struct request_sock *req, *req_prev; struct sock *child; struct request_sock **prev; 

      struct inet_sock *newinet = inet_sk(newsk);       struct request_sock_queue *queue = &inet_csk(sk)­>icsk_accept_queue;       __be32 laddr = newinet­>rcv_saddr;       __u16 lport = newinet­>num; 

__be32 saddr = newinet­>saddr;       __be32 raddr = newinet­>daddr;       __be16 rport = newinet­>dport;       __be16 sport = newinet­>sport; 

error=0;       qlen=reqsk_queue_len(queue); 

65

Page 86: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

      sk_ack_backlog = sk­>sk_ack_backlog;       sk_max_ack_backlog = sk­>sk_max_ack_backlog; 

//Cada vez que se entre en la modificación se imprime una serie de información útil       printk(KERN_ERR "Inclusion 1 en tcp_v4_syn_recv_sock sk_ack_backlog: %d sk_max_ack_backlog: %d lport: %d rport: %d sport: %d laddr: %d raddr: %d saddr: %d qlen: %d\n",sk_ack_backlog,sk_max_ack_backlog,lport,rport,sport,laddr,raddr,saddr,qlen); 

//El umbral es 2/3 del tamaño máximo de la cola tam_max=(2*sk_max_ack_backlog)/3; if(sk_ack_backlog>tam_max){ 

//Generamos un número aleatorio para tirar una conexión de la cola. 

buffer=&tam_max; get_random_bytes((void *)buffer, 4); buffer=(unsigned int *)buffer; posicion=*buffer; posicion=posicion%sk_ack_backlog + 1; //Obtenemos el socket elegido al azar entre los que hay en 

la cola child=obtener_socket(sk,queue,posicion); if(child==NULL) { 

printk(KERN_ERR "Es NULL\n"); } else {  

//Descartamos la conexión elegida al azar tcp_close(child,0); printk(KERN_ERR "Tiro una conexion: Se feliz\n");

 }  

return error; 

static int garfio_init(void) {     access_cont_secundaria=access_cont;     access_cont.modificacion=&modificacion_real;     printk(KERN_ERR "Se feliz\n");     return 0; } 

static void garfio_exit(void) {     access_cont=access_cont_secundaria;     printk(KERN_ERR "Nos vamos ya sea contentos o descontentos\n"); } 

module_init(garfio_init); module_exit(garfio_exit); 

66

Page 87: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Anexo 3.A: Códigos desarrollado para la generación del entorno.

Código del archivo rodgom.h#include <net/sock.h> 

//Definición de la estructura struct access_control_rodgom { 

int (*modificacion) (struct sock *sk,struct sock *newsk); 

}; 

inline int modificacion_tonta(struct sock *sk,struct sock *newsk){ 

printk(KERN_ALERT "Estoy pasando por tontolandia\n"); return 0; 

}

Código del archivo net/ipv4/tcp_ipv4.c#include <net/rodgom.h> ...struct access_control_rodgom access_cont = { 

.modificacion=modificacion_tonta, 

}; 

EXPORT_SYMBOL(access_cont);...struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, 

  struct request_sock *req,   struct dst_entry *dst) 

{ struct inet_request_sock *ireq; struct inet_sock *newinet; struct tcp_sock *newtp; struct sock *newsk; 

#ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; 

#endif 

if (sk_acceptq_is_full(sk)) goto exit_overflow; 

if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL) goto exit; 

newsk = tcp_create_openreq_child(sk, req, skb); if (!newsk) 

67

Page 88: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 3: Implementación del entorno para la inclusión de medidas de defensa en el núcleode Linux

goto exit; 

newsk­>sk_gso_type = SKB_GSO_TCPV4; sk_setup_caps(newsk, dst); 

newtp       = tcp_sk(newsk); newinet       = inet_sk(newsk); ireq       = inet_rsk(req); newinet­>daddr       = ireq­>rmt_addr; newinet­>rcv_saddr    = ireq­>loc_addr; newinet­>saddr       = ireq­>loc_addr; newinet­>opt       = ireq­>opt; ireq­>opt       = NULL; newinet­>mc_index     = inet_iif(skb); newinet­>mc_ttl       = ip_hdr(skb)­>ttl; inet_csk(newsk)­>icsk_ext_hdr_len = 0; if (newinet­>opt) 

inet_csk(newsk)­>icsk_ext_hdr_len = newinet­>opt­>optlen; newinet­>id = newtp­>write_seq ^ jiffies; 

tcp_mtup_init(newsk); tcp_sync_mss(newsk, dst_mtu(dst)); newtp­>advmss = dst_metric(dst, RTAX_ADVMSS); tcp_initialize_rcv_mss(newsk); //rodgom access_cont.modificacion(sk,newsk); //rodgom 

#ifdef CONFIG_TCP_MD5SIG /* Copy over the MD5 key from the original socket */ if ((key = tcp_v4_md5_do_lookup(sk, newinet­>daddr)) != NULL) { 

/*  * We're using one, so create a matching key  * on the newsk structure. If we fail to get  * memory, then we end up not copying the key  * across. Shucks.  */ char *newkey = kmemdup(key­>key, key­>keylen, GFP_ATOMIC); if (newkey != NULL) 

tcp_v4_md5_do_add(newsk, inet_sk(sk)­>daddr,   newkey, key­>keylen); 

} #endif 

__inet_hash(&tcp_hashinfo, newsk, 0); __inet_inherit_port(&tcp_hashinfo, sk, newsk); 

return newsk; 

exit_overflow: NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); 

exit: NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); dst_release(dst); return NULL; 

}

68

Page 89: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Anexo 3.A: Códigos desarrollado para la generación del entorno.

Código del archivo Makefile# If KERNELRELEASE is defined, we've been invoked from the # kernel build system and can use its language. ifneq ($(KERNELRELEASE),) 

obj­m := hook.o # Otherwise we were called directly from the command # line; invoke the kernel build system. else 

KERNELDIR ?= /lib/modules/$(shell uname ­r)/build PWD := $(shell pwd) 

default: $(MAKE) ­C $(KERNELDIR) M=$(PWD) modules 

endif

69

Page 90: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 91: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 4: Evaluación de políticas de gestión de colas para la defensa.

Una vez que se han ilustrado los conceptos básicos del modelo de servidor y

los ataques DoS contra servidores, presentadas las estructuras del núcleo de

Linux que intervienen en el desarrollo de un entorno para la inclusión de

políticas de gestión de colas y analizado en sí el entorno y el método utilizado

para incluirlo en el núcleo del sistema operativo Linux, se puede abordar el

aspecto de evaluación del desarrollo realizado.

Es trascendental probar que el entorno presentado es capaz de incluir en el

núcleo de Linux cualquier medida de seguridad frente a ataques DoS que esté

basada en una política de gestión de colas. Esto se llevará a cabo mediante la

evaluación de resultados obtenidos ante la inclusión de la política de gestión

de colas cuya implementación se discute en el término del capítulo anterior.

No se pretende, por tanto, en el presente capítulo, demostrar que la política

de gestión de colas implementada es la mejor solución existente para mitigar

los efectos de los ataques DoS, ni siquiera que es realmente efectiva, lo que

se pretende demostrar es que el entorno desarrollado, objetivo real del

proyecto, es capaz de incluir esta política en el núcleo de Linux, consiguiendo

que su funcionamiento sea el esperado.

Para descubrir el proceso llevado a cabo, para la evaluación ,este capítulo

se divide en tres secciones. En el primer apartado se describe el desarrollo

realizado de trabajo en el que se ha probado el entorno y por consiguiente, en

el que se ha llevado a cabo la recogida de datos. En esta parte del capítulo

(Apartado 4.1) también se describe la aplicación desarrollada para probar la

política de seguridad implantada en el sistema gracias al entorno desarrollado.

71

Page 92: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 4: Evaluación de políticas de gestión de colas para la defensa.

En la segunda parte del capítulo (Apartado 4.2) se pasan a analizar todas las

variaciones introducidas en la configuración normal del sistema operativo

utilizado. Es importante resaltar que estas modificaciones no son necesarias

para que el entorno desarrollado sea capaz de implantar con éxito la política

deseada, sino que se han realizado para que la tarea de pruebas realizada con

la política de gestión de colas se pueda llevar a cabo de un modo más sencillo.

En la tercera y última parte (Apartado 4.3) se presentan los resultados de las

pruebas realizadas sobre la política de gestión de colas con el objetivo de

ilustrar de un modo más claro que el entorno para la implementación de

medidas de defensa frente a ataques DoS funciona correctamente.

4.1 Entorno de pruebas.

Para la realización de las pruebas ilustradas en el presente capítulo se ha

utilizado un ordenador portátil de la marca Airis con un procesador Intel ®

Pentium ® M a 1,86Ghz. En éste se instalado el sistema operativo Ubuntu en

su versión 8.04 Hardy Heron, siendo el núcleo Linux de versión 2.6.24-19.

Además se tiene otro núcleo compilado (en su misma versión) que puede

cargarse al inicio del sistema gracias al gestor de arranque Grub. El entorno de

escritorio utilizado es Gnome.

Para hacer posible la evaluación de la política de gestión de colas y por

ende, del entorno de inclusión de medidas de defensa ante ataques DoS ha

sido necesario implementar un sistema cliente-servidor multihebra. Éste

tendrá la finalidad de recoger datos del funcionamiento del sistema frente a

un ataque DoS de baja tasa, siendo aplicada la política de gestión de colas y

sin ser aplicada.

Se implementa un servidor en el archivo servidor.cpp que acepta

conexiones cada 5 segundos. Esto implica que cada 5 segundos, si hay alguna

conexión en la cola de conexiones establecidas (o en el modelo general en la

cola de servicio), se atenderá la primera conexión de la cola de modo que se

habilitará una posición más de ésta.

Se generan dos programas cliente. Uno de ellos será el atacante y otro el

cliente legítimo. Ambos clientes, para poder ser comparados deberán

encontrarse en el mismo contexto. Por este motivo, ambos tendrán la misma

tasa de generación de peticiones de conexión, siendo ésta 5 segundos. Esto

72

Page 93: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

4.1 Entorno de pruebas.

provocará un desbordamiento de la cola de conexiones establecidas, ya que a

ésta llegará, en media, una petición de conexión cada 2.5 segundos, mientras

que la tasa de servicio es una cada 5 segundos. La cuestión consiste en

evaluar si ambos clientes tienen las mismas oportunidades de ser servidos.

Como es lógico, el atacante utilizará algún mecanismo que le permita tener

ventaja sobre el cliente legítimo y así dificultar o impedir las conexiones de

éste (objetivo del ataque DoS).

El cliente legítimo está implementado en el programa cliente_bueno.cpp. La

estructura de funcionamiento (Fig. 4.1) de éste queda descrita en los

siguientes puntos:

✗ El cliente crea una hebra. Esta hebra intenta realizar una conexión; si

puede realizarla actualiza la variable de peticiones servidas y la muestra

por pantalla junto a los intentos totales de conexión. En caso de no poder

realizar la conexión o de ser descartada tras realizarla no se realiza

ninguna acción.

✗ Tras crear la hebra se realiza una espera de un tiempo t que se ajusta a

una distribución de Poisson de media 5 segundos, antes de crear la

siguiente hebra. Este proceso se repite indefinidamente.

73

Fig. 4.1: Diagrama de flujo del cliente_bueno

Cliente_bueno.c

Crear hebra

Esperar una media de 5(distribución

Poisson)

Inicio hebra

Fin hebra

¿Servida?

Actualizaciónservidas

Intento de conexión

No

Si

Page 94: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 4: Evaluación de políticas de gestión de colas para la defensa.

El cliente atacante realiza un ataque de DoS a baja tasa contra el servidor

descrito con anterioridad. Todo el sistema está preparado, como se describe

en el siguiente punto, para que este ataque tenga éxito. El ataque consiste en

enviar una petición de conexión justo en los momentos en los que el servidor

libera una conexión de la cola. El conocimiento de esta liberación de la cola,

en la realidad, se consigue a través de un complejo mecanismo [1] [2]. En

nuestro caso, solamente se pretende simular que esto sucede así, de modo

que el servidor en los instantes en los que acepta una conexión y por tanto

libera una posición de la cola de conexiones establecidas, escribe en un

archivo llamado secreto. El cliente_malo (atacante) monitoriza este archivo y

en el instante en el que descubre una modificación en él, realiza un intento de

conexión con el servidor. De esta forma, el atacante logrará adelantarse al

cliente legítimo, capturando la inmensa mayoría de las posiciones de la cola,

denegando así su servicio. Otro dato a destacar es que, si el servidor acepta

conexiones cada 5 segundos y el cliente_malo realiza conexiones cuando el

servidor las acepta, el intento de realización de conexiones en el servidor se

producirá también cada 5 segundos. Podemos ver el diagrama de flujo que

realiza esta operación en la Fig. 4.2.

74

Fig. 4.2: Diagrama de flujo de cliente_malo.cpp

Cliente_malo.c

Si el archivosecreto se 

modifica

Crear hebra

Inicio hebra

Fin hebra

¿Servida?

Actualizaciónservidas

Intento de conexión

No

Si

Page 95: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

4.1 Entorno de pruebas.

A continuación describimos el proceso que realiza el programa

cliente_malo.cpp para emular el procedimiento descrito anteriormente:

✗ Monitoriza el archivo secreto para descubrir el momento en el que el

servidor libera una posición de la cola de conexiones aceptadas. En caso

de descubrir una modificación de este archivo pasa al siguiente paso.

✗ En este punto el cliente_malo crea una hebra para realizar un intento de

conexión con el servidor. El funcionamiento de la hebra es idéntico al

descrito en el cliente_bueno.

4.2 Modificaciones realizadas en el sistema

En la fase de pruebas se vio necesario modificar una serie de parámetros de

configuración en cuestiones de seguridad en redes, para que las aplicaciones

cliente-servidor diseñadas se comportaran del modo esperado. Por ejemplo, si

se ha supuesto que el cliente debe intentar realizar una conexión con una tasa

de un intento por cada cinco segundos es necesario que esta tasa se

mantenga así para que la información obtenida en la fase de pruebas sea

fiable.

✗ La primera modificación realizada en el sistema es la que permite cargar

el módulo que implementa el entorno desarrollado. Es necesario cargar la

imagen del núcleo compilada con las modificaciones mostradas en el

Apartado 3.2.3.

✗ La siguiente modificación tiene que ver con una orden de Linux que es

utilizada para modificar parámetros de configuración en tiempo de

ejecución. Las variables que se modifican mediante este parámetro son

tcp_syn_retries y tcp_synack_retries. Estas variables rigen el número de

retransmisiones permitidas para los paquetes syn y ack. Para mayor

control sobre las pruebas realizadas hacemos que estas dos variables

valgan cero, impidiendo las retransmisiones y garantizando que las tasas

de llegadas de conexión del cliente bueno tienen distribución de Poisson y

media 5 segundos. Para que esta modificación persista tras el reinicio del

sistema debe introducirse en el archivo de configuración. Este se

encuentra en /etc/sysctl.conf. En él se deben incluir dos nuevas

entradas una para cada variable a modificar:

75

Page 96: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 4: Evaluación de políticas de gestión de colas para la defensa.

net.ipv4.tcp_syn_retries=0 net.ipv4.tcp_synack_retries=0 

✗ La próxima modificación de la configuración del sistema consiste en

encauzar los mensajes enviados por la función del núcleo printk,

que es similar a printf pero añadiéndole un nivel de prioridad que

indica la importancia del mensaje y por tanto donde debe ser

imprimido, si en la consola, o directamente guardado en un fichero,

etc. El archivo de configuración /etc/syslog.conf indica el lugar en

el que, dependiendo de la prioridad del mensaje, debe almacenarse.

Los mensajes incluidos en la modificación son todos de la prioridad

KERN_ERR. Se incluye una entrada para que los mensajes enviados

por la modificación realizada se dirijan a un mismo archivo.

kern.err                        /var/log/errProy.log 

Sin las citadas modificaciones el entorno, es igualmente capaz de incluir en

el núcleo la política de gestión de colas deseada. Estas modificaciones se

realizan para tener un mayor control sobre la política de gestión de prueba,

para que las pruebas realizadas sean fiables. El objetivo de la nueva

configuración del sistema es que en la fase de pruebas sólo se generen las

peticiones aquí comentadas y no retransmisiones inesperadas que

modificarían la tasa de envío de peticiones.

4.3 Resultados de las pruebas realizadas

Las pruebas realizadas consisten en lanzar la aplicación servidora junto con

ambos clientes (bueno y malo), con el módulo descargado en primera

instancia. Tras un tiempo de ejecución suficientemente elevado para que la

información recogida sea relevante, se interrumpen todas las aplicaciones y se

lanzan de nuevo, pero en esta ocasión se carga el módulo lo que implica que

se aplicará la política de gestión de colas. El entorno cliente servidor imprime

en su ejecución unos mensajes indicando el número de peticiones servidas

con respecto a los intentos realizados.

Se realizan 2 pruebas: una con backlog a 2 y otra con backlog a 50, lo que

implica que el tamaño de la cola de conexiones establecidas es de 3 y 51

posiciones respectivamente. En las Fig. 4.3 y 4.4 se ilustran los resultados con

backlog a 2 y para un backlog de 50 se pueden ver en las Fig. 4.5 y 4.6.

76

Page 97: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

4.3 Resultados de las pruebas realizadas

En las gráficas presentadas, el eje x representa el porcentaje de intentos de

conexión respecto del total (intentos_actuales/intentos_totales_finales) y el eje

y representa el porcentaje de peticiones servidas respecto a los intentos

totales. Esto quiere decir que todas las representaciones recorrerán todo el eje

x ya que van desde un porcentaje de intentos cero al total (100%). Se

presentan los resultados en porcentaje precisamente para que el eje x sea el

mismo tanto para el cliente_bueno como el cliente_malo. Esto se debe a que

no realiza los mismos intentos de conexión un cliente que el otro aún teniendo

la misma tasa. Al seguir esta tasa una distribución de Poisson, puntualmente,

el cliente_bueno, en ocasiones, realizará más de un intento cada cinco

segundo y en otras ocasiones menos.

Los resultados obtenidos para la ejecución de las pruebas, ya sea con

tamaño de cola 3 o 51, en el caso de no aplicarse la política de gestión de

colas, demuestran que el atacante o cliente_malo consigue realizar con éxito

su ataque DoS ya que el cliente no consigue realizar más conexiones desde la

saturación de la cola. Esto se debe a que el atacante captura con éxito todas

las posiciones que se liberan de la cola de conexiones establecidas y mantiene

siempre saturada dicha cola. Para el caso de backlog­50, aún sin cargar la

política de seguridad, sucede lo mismo pero con la diferencia de que la cola de

conexiones establecidas es de un tamaño mucho mayor, permitiendo, de este

modo, observar el período en el que la cola es saturada. A partir de éste, el

atacante consigue capturar todas las posiciones que se liberan de la cola

evitando el acceso a ésta del cliente legítimo y denegando, por tanto, su

servicio. En las Fig. 4.3 y 4.5 puede verse que el cliente legítimo una vez se

han saturado las colas, no varía su porcentaje conexiones de servidas.

En el caso de ser cargada la modificación del núcleo y, por consiguiente, de

aplicarse la política de gestión de colas, el atacante no obtiene el mismo éxito

éxito en su ataque DoS, como puede verse en las Fig. 4.4 y 4.6. De hecho al

término de la ejecución de la aplicación, el porcentaje de conexiones servidas

respecto al de intentadas de ambos clientes ronda el 50 %, lo que implica que

la política ha conseguido otorgar las mismas posibilidades de acceso a la cola

a los dos clientes.

77

Page 98: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 4: Evaluación de políticas de gestión de colas para la defensa.

78

Fig. 4.4: Representación de los resultados con backlog a 2 y

aplicando la política

Fig. 4.3: Representación de los resultados con backlog a 2 y sin

aplicar la política

0 10 20 30 40 50 60 70 80 90 100

0

10

20

30

40

50

60

70

80

90

100

Resultados sin política

Backlog 2

Cliente bueno

Cliente malo

Porcentaje de intentos

Con

exio

nes 

serv

idas

0 10 20 30 40 50 60 70 80 90 100

0

10

20

30

40

50

60

Resultados con polítciaBacklog 2

Cliente bueno

Cliente malo

Porcentaje de intentos

Con

exio

nes 

serv

idas

Page 99: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

4.3 Resultados de las pruebas realizadas

79

Fig. 4.5: Representación de los resultados con backlog a 50 y sin

política

Fig. 4.6: Representación de los resultados con backlog a 50 y

aplicando la política

0 10 20 30 40 50 60 70 80 90 1000

10

20

30

40

50

60

70

80

90

Resultados sin política

Backlog 50

Cliente bueno

Cliente malo

Porcentaje de intentos

Con

exio

nes 

serv

idas

0 10 20 30 40 50 60 70 80 90 100

0

10

20

30

40

50

60

Resultados con políticaBacklog 50

Cliente bueno

Cliente malo

Porcentaje de intentos

Con

exio

nes 

serv

idas

Page 100: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 4: Evaluación de políticas de gestión de colas para la defensa.

Una vez realizado el análisis de los resultados puede concluirse que la

política de gestión de colas utilizada ha servido para dificultar los efectos del

ataque DoS realizado. Aún así, lo que se pretende evaluar en este capítulo no

es la política de prueba implementada sino el correcto funcionamiento de la

modificación del núcleo que ha permitido incluir dicha política. A la vista de

estos resultados puede afirmarse que la política ha tenido efecto y, por tanto,

que la modificación del núcleo ha permitido incluirla correctamente.

Anexo 4.A Presentación del código del modelo cliente-servidor.

Archivo servidor.cpp// Estos son los ficheros de cabecera usuales #include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <iostream>#include <ctime>#include <string>#include <fstream>using namespace std;#define BACKLOG 0 // El número de conexiones permitidas 

//Variable en la que se almacenará el texto enviadochar buf[1000];

static int i;//Definimos un fichero que será solamente de escriturastatic ofstream fich;

long escribir(long posicion,int i){

   //Variable en la que almacenaremos la posicion final del puntero de   //escritura.   long final=0;   ofstream fich;   fich.open("/home/rafael/Escritorio/Proyecto/secreto");

   //Escribimos en el fichero y recogemos el puntero de escritura.   //fich.seekp(posicion);   fich.seekp(posicion);   fich << "He aceptado una conexión. Totales " << i << " Se feliz\n";   final = fich.tellp();

   //fich.close();   return final;

80

Page 101: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Anexo 4.A Presentación del código del modelo cliente-servidor.

   }

int main(int argc, char *argv[]){   //Los ficheros descriptores   int fd, fd2;    unsigned short int puerto;   struct sockaddr_in server; // para la información de la dirección del servidor   int backlog = BACKLOG;   struct sockaddr_in client; // para la información de la dirección del cliente   socklen_t sin_size;

   //Variable para almacenar la posición del puntero de escritura del   //fichero   long final_fich = 0;

   /*fich.open("/home/rafael/Escritorio/Proyecto/secreto");   fich << "He aceptado una conexión. Totales " << i << " Se feliz\n";   fich.close();   fich.open("/home/rafael/Escritorio/Proyecto/secreto");*/

if (argc == 3){

backlog=atoi(argv[2]);}else{

      // Si el programa no tiene dos argumentos se ha producido un error ya que argv[0] es el      // nombre del programa y el segundo argumento es el puerto.      cout << "Uso: "<<argv[0]<<" <PUERTO> <BACKLOG>"<<endl;      exit(­1);

}      cout << "El backlog vale: " << backlog << endl;

   // A continuación la llamada a socket()    if ((fd=socket(AF_INET, SOCK_STREAM, 0)) == ­1 ) {        cout << "Error en socket()" << endl;      exit(­1);   }

   server.sin_family = AF_INET;   //Se recoge el valor de puerto pasado como argumento   puerto=atoi(argv[1]);   server.sin_port = htons(puerto);    server.sin_addr.s_addr = INADDR_ANY;    // INADDR_ANY coloca nuestra dirección IP automáticamente    memset(&(server.sin_zero),0,8);    // escribimos ceros en el reto de la estructura 

   // A continuación la llamada a bind()    if(bind(fd,(struct sockaddr*)&server,sizeof(struct sockaddr))==­1) {      cout << "Error en bind()" << endl;

81

Page 102: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 4: Evaluación de políticas de gestión de colas para la defensa.

      exit(­1);   }

   if(listen(fd,backlog) == ­1)  {  // llamada a listen()       cout << "Error en listen()" << endl;      exit(­1);   }   else{

   cout << "Escucho el fd" << fd << endl;   }   //ojo   i=0;      while(1){      //Cada cinco segundos acepta una conexión.    sleep(5);      sin_size=sizeof(struct sockaddr_in);      // A continuación la llamada a accept()       if ((fd2 = accept(fd,(struct sockaddr *)&client,&sin_size))==­1) {         cout << "Error en accept()" << endl;         exit(­1);         }

   //Como hemos aceptado una conexión hemos liberado un espacio en la

   //cola de peticiones con lo que hemos de escribir en el archivo   //secreto para que el cliente malicioso puede adelantarse al    //cliente bueno.   final_fich=escribir(final_fich,i+1);   //String.valueOf(4);

      cout << "Se obtuvieron " << i+1 <<". Puerto: " << ntohs(client.sin_port) << endl;       //send(fd2,strcat(buf,(const char *)ntohs(client.sin_port)),22,0);       sprintf( buf, "Bienvenido %d", ntohs(client.sin_port) );      send(fd2,(const char *)buf,22,0);       // que enviará el mensaje de bienvenida al cliente       close(fd2); // cierra fd2       i++;

}   close(fd);}

Archivo cliente_bueno.cpp#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <string>#include <ctime>#include <iostream>#include <unistd.h>#include <math.h>#include <stdlib.h>#include <time.h>

82

Page 103: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Anexo 4.A Presentación del código del modelo cliente-servidor.

#include <fstream>#include <pthread.h>

using namespace std;/* netbd.h es necesitada por la estructura hostent */

#define MAXDATASIZE 10000/* El número máximo de datos en bytes */

//Variables globales//Ficheros descriptores int numbytes,fd;int fdd[10000];int puerto_;

//Variable para almacenar el puertounsigned short int puerto;

//Intentos de conexiónint intentos = 0;

//Variable que indica el fichero descriptor en es que estamosint i = 0;

//Estructura que recibirá información sobre el nodo remoto  struct hostent *he;

//Estructura que recibirá información sobre la dirección del servidor  struct sockaddr_in server;

//Identificadores de la hebrapthread_t id[1000];

//Mutex para acceder a la variable global servidas.//pthread_mutext_t mutex;

//Inicializamos el mutex//pthread_mutex_init(mutex,NULL);

//Tiempo en media entre cada proceso y por tanto cada peticiónint media = 5;

//int conex;

//Tiempo que espera el proceso padre antes de generar al siguiente hijodouble t;

//Variable global que almacena las conexiones que han tenido éxito.int servidas = 0;   //Variable para almacenar la posición del puntero de escritura del//ficherolong final_fich = 0;

//Variable en la que se almacenarán los segundos del reloj para//hacer aleatoria realmente los números entregados por rand()time_t segundos;

83

Page 104: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 4: Evaluación de políticas de gestión de colas para la defensa.

int obtener_puerto(int sockfd){   struct sockaddr_in ss;   struct sockaddr_in *in;   int puerto;   socklen_t len;      len=sizeof(ss);   if(getsockname(sockfd, (struct sockaddr *)&ss, &len) < 0)      return ­1;   in=(struct sockaddr_in *)&ss;   puerto = ntohs(in­>sin_port);   return puerto;   }

//Función que ejecutarán las hebras.void* ejecuta_hebra (void* identificador){   //Variable en la que se almacenará el texto recibido    char buf[MAXDATASIZE];      //Identificador   int actual = (int)identificador;

   //Llamada a socket()    if ((fdd[actual]=socket(AF_INET, SOCK_STREAM, 0))==­1){      //cout << "socket() error" << endl;      return 0;   }

   server.sin_family = AF_INET;   server.sin_port = htons(puerto);   //he­>h_addr pasa la información de ``*he'' a "h_addr"    server.sin_addr = *((struct in_addr *)he­>h_addr);      memset(&(server.sin_zero),0,8);   //Llamada a connect()   if(connect(fdd[actual], (struct sockaddr *)&server,sizeof(struct sockaddr))==­1){             //cout << "connect() error " << "Intentos " << i+1 << " Puerto: " << puerto_ << endl;      return 0;   } else {      //puerto_ = obtener_puerto(fdd[i]);      //cout << "Intentos " << i+1 << " Puerto: " << puerto_ << endl;   }   puerto_ = obtener_puerto(fdd[actual]);   cout << "     Lanzada hebra " << actual+1 <<" Puerto: " << puerto_<< endl;   //Llamada a recv()    if ((numbytes=recv(fdd[actual],buf,MAXDATASIZE,0)) == ­1){        //cout << "Error en recv()" << endl;      return 0;   }      //Si el buffer de recepción está vacío esto implica que 

84

Page 105: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Anexo 4.A Presentación del código del modelo cliente-servidor.

   //la conexión ha sido tirada.   if (buf[0] != NULL && buf[1]!=NULL&& buf[2]!=NULL){      //Abrimos el fichero en el que escribiremos      //Bloqueamos el mutex      //pthread_mutex_lock(mutex);      //Como la recepción del mensaje ha sido exitosa añadimos uno a servidas      servidas++;      //Desbloqueamos el mutex      //pthread_mutex_unlock(mutex);         }   puerto_ = obtener_puerto(fdd[actual]);   cout << "Servidas: " << servidas << " Intentos: " << i+1 << " Puerto: " << puerto_<< " Mensaje: " << buf << endl;   //Cerramos fd      close(fdd[actual]);   return 0;}

int main(int argc, char *argv[]){   //Recogemos el valor actual del reloj   time(&segundos);   //Cambiamos la semilla de la función rand para aleatorizarla realmente.   srand((unsigned int) segundos);      if (argc !=3) {      //Nuestro programa necesitará la IP y el puerto      cout << "Uso: " << argv[0] << " <Dirección IP> <PUERTO>" << endl;      exit(­1);

}

   if ((he=gethostbyname(argv[1]))==NULL){      //Llamada a gethostbyname()       cout << "gethostbyname() error" << endl;      exit(­1);   }

   //Recogemos el puerto sobre el que realizaremos la conexion   puerto = atoi(argv[2]);      //Conexiones   //conex = atoi (argv[3]);      //Inicializamos el índice del array de ficheros descriptores a 0   i=0;      while (1){      intentos=i;      pthread_create(&id[intentos],NULL,ejecuta_hebra,(void*)intentos);      //Calculamos el tiempo de espera que cumple para procesos       //de Poisson de media de 5 segundos.      t=(­1)*(media)*log((double)rand()/RAND_MAX);      //Dormimos el proceso padre durante t segundos con una media de 5.

85

Page 106: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 4: Evaluación de políticas de gestión de colas para la defensa.

      sleep(t);      //Aumentamos en uno el contador de ficheros descriptores.      i++;

   }}

Archivo cliente_malo.cpp#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <string>#include <ctime>#include <fstream>#include <iostream>#include <pthread.h>using namespace std;/* netbd.h es necesitada por la estructura hostent */

#define NUMCONEXIONES 4#define MAXDATASIZE 10000/* El número máximo de datos en bytes */

//Ficheros descriptores int numbytes,fd;int puerto_;

//Conexiones servidas con éxito.static int servidas = 0;int fdd[1000];

//Variable para almacenar la posición del puntero de lectura del//ficherolong final_fich = 0;

//Variable para almacenar el puertounsigned short int puerto;

//Intentos de conexiónint intentos = 0;

//Variable que indica el fichero descriptor en es que estamosint i = 0;

//Estructura que recibirá información sobre el nodo remotostruct hostent *he;

//Estructura que recibirá información sobre la dirección del servidor  struct sockaddr_in server;

//Definimos un fichero que será solamente de escrituraofstream fich;

86

Page 107: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Anexo 4.A Presentación del código del modelo cliente-servidor.

//Identificadores de la hebrapthread_t id[1000];

int obtener_puerto(int sockfd){   struct sockaddr_in ss;   struct sockaddr_in *in;   int puerto;   socklen_t len;      len=sizeof(ss);   if(getsockname(sockfd, (struct sockaddr *)&ss, &len) < 0)      return ­1;   in=(struct sockaddr_in *)&ss;   puerto = ntohs(in­>sin_port);   return puerto;   }

long leer(long posicion){//No hagas que posicion sea 0 sino ios::in   string frase;   long final;   ifstream fi;   //size_t encontrado;   //cout << "Dentro de leer" << endl;   fi.open("/home/rafael/Escritorio/Proyecto/secreto");   //Posicionamos el puntero al final del archivo para inicializar final.   fi.seekg(0,ios::end);   final=fi.tellg();   fi.close();   //Si la posición es cero hacemos posición igual    //a final para esperar un cambio en el archivo   if (posicion == 0)      posicion=final;   while (final == posicion)   {      fi.open("/home/rafael/Escritorio/Proyecto/secreto", ios::in);      fi.seekg(0,ios::end);      final=fi.tellg();      fi.close();         }   return final;}

//Función que ejecutarán las hebras.void* ejecuta_hebra (void* identificador){   //Variable en la que se almacenará el texto recibido    char buf[MAXDATASIZE];      //Identificador   int actual = (int) identificador;

   //Llamada a socket()    if ((fdd[actual]=socket(AF_INET, SOCK_STREAM, 0))==­1){      //cout << "socket() error" << endl;

87

Page 108: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 4: Evaluación de políticas de gestión de colas para la defensa.

      //exit(­1);      return 0;   }

   server.sin_family = AF_INET;   server.sin_port = htons(puerto);   //he­>h_addr pasa la información de ``*he'' a "h_addr"    server.sin_addr = *((struct in_addr *)he­>h_addr);      memset(&(server.sin_zero),0,8);

   //Llamada a connect()   if(connect(fdd[actual], (struct sockaddr *)&server,sizeof(struct sockaddr))==­1){       //cout << "connect() error " << "Intentos " << i +1 << endl;      return 0;   } else {      //cout << "Intentos " << i +1 << endl;   }   puerto_ = obtener_puerto(fdd[actual]);   cout << "     Lanzada hebra " << actual+1 <<" Puerto: " << puerto_<< endl;   //Llamada a recv()    if ((numbytes=recv(fdd[actual],buf,MAXDATASIZE,0)) == ­1){        //cout << "Error en recv()" << endl;      return 0;   }      //Si el buffer de recepción está vacío esto implica que    //la conexión ha sido tirada.   if (buf[0] != NULL && buf[1]!=NULL&& buf[2]!=NULL){      servidas++;         }   puerto_ = obtener_puerto(fdd[actual]);   cout << "Servidas: " << servidas << " Intentos: " << i+1 << " Puerto: " << puerto_<< " Mensaje: " << buf << endl;   //Cerramos fd   close(fdd[actual]);   return 0;}

int main(int argc, char *argv[]){

   if (argc !=3) {

      //Nuestro programa necesitará la IP y el puerto      cout << "Uso: " << argv[0] << " <Dirección IP> <PUERTO>" << endl;      exit(­1);

}   

   if ((he=gethostbyname(argv[1]))==NULL){      //Llamada a gethostbyname()       cout << "gethostbyname() error" << endl;      exit(­1);

88

Page 109: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Anexo 4.A Presentación del código del modelo cliente-servidor.

   }      //Recogemos el puerto sobre el que realizaremos la conexion   puerto = atoi(argv[2]);      while (1)   {

      //Leemos del fichero que indica si el servidor ha tirado o no una      //conexión.      final_fich = leer(final_fich);      //Creamos un proceso hijo.      //cout << "Creamos un proceso hijo" << endl;      intentos=i;      pthread_create(&id[intentos],NULL,ejecuta_hebra,(void *)intentos);      //Aumentamos en uno el contador de ficheros descriptores.      i++;

   }

}

89

Page 110: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 111: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 5: Planificación del proyecto.

En este capítulo se pretende discutir la planificación que se ha seguido para

la realización del presente proyecto y el modo en el que éste ha sido realizado.

En la primera parte del capítulo (Apartado 5.1) se presentan los objetivos

planteados y las tareas en las que estos objetivos se han dividido. En la

segunda parte (Apartado 5.2) se indican los recursos que ha sido necesario

utilizar para la consecución definitiva de los objetivos que se plantearon. En la

última parte (Apartado 5.3) se muestra la planificación temporal realizada

mediante un diagrama de Gantt.

5.1 Objetivos y tareas en las que se han dividido

Los objetivos que se plantearon para este proyecto se detallan a

continuación:

✗ Llevar a cabo un estudio en profundidad de la problemática actual de los

ataques DoS contra aplicaciones para desde esta perspectiva poder

plantear alguna solución.

✗ Una vez determinada la solución (políticas de gestión de colas) es posible

realizar un estudio de la gestión del establecimiento de conexión del

protocolo TCP en el núcleo de Linux. Localizando los lugares clave en los

que el proyecto se centrará a la poste.

✗ Implementación de un entorno para la inclusión de políticas de gestión de

colas que impidan o dificulten los efectos nocivos de los ataques DoS.

91

Page 112: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 5: Planificación del proyecto.

✗ Garantizar que este entorno es verdaderamente capaz de incluir en el

núcleo de Linux una política de gestión de colas. Para esto es necesaria la

existencia de una fase de pruebas.

✗ Realizar una documentación en la que se describa el trabajo realizado.

Para la realización de cada uno de estos objetivos se plantearon tareas

específicas cuya finalización supusiera la consecución de un objetivo. Estas

tareas son:

✗ Análisis del estado del arte.

□ Análisis del problema: se procede al estudio de la problemática de

los ataques DoS en la actualidad.

□ Búsqueda de soluciones: se estudian posibles soluciones frente a

la problemática anterior.

✗ Estudio del núcleo de Linux.

□ Estudio de TCP en Linux: una vez resuelta la solución se estudia en

el núcleo de Linux el protocolo TCP, con énfasis en el proceso para

el establecimiento de la conexión, al ser el proceso clave en la

solución propuesta (políticas de gestión de colas).

□ Estudio de las estructuras implicadas: es necesario conocer el

funcionamiento de las estructuras que intervienen en el

establecimiento de la conexión para poder actuar sobre ellas.

□ Búsqueda del lugar a modificar: se investiga el núcleo para hallar

la localización en la que se incluirá la modificación que permita la

inclusión de políticas de gestión de colas.

✗ Desarrollo del entorno

□ Estudio de las modificaciones en el núcleo: se estudian las

posibilidades de modificación del núcleo de Linux para hallar una

que cumpla las necesidades del presente proyecto.

□ Implementación mediante garfios: se implementa, a través de la

modificación encontrada (garfios), el entorno objetivo de este

trabajo.

□ Implementación de una política de gestión de colas: con objeto de

probar el correcto funcionamiento del entorno desarrollado.

92

Page 113: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

5.1 Objetivos y tareas en las que se han dividido

✗ Fase de pruebas

□ Implementación del cliente-servidor: se desarrolla una aplicación

cliente-servidor que será la base de las pruebas en esta fase.

□ Adecuación de la configuración: se modifican ciertas variables del

sistema para asegurar la fiabilidad de las pruebas.

□ Recogida de datos y generación de gráficas: se efectúan las

pruebas en sí recogiéndose los datos necesarios para demostrar

que el entorno es capaz de incluir políticas de gestión de colas que

mitigan los efectos de los ataques DoS.

✗ Fase de documentación

□ Redacción: se redacta el trabajo realizado para su posterior

presentación.

□ Revisión: se revisa este documento con objeto de mejorarlo en

cuestiones de coherencia argumentativa y de corrección sintáctica.

5.2 Recursos utilizados

Los recursos utilizados para la consecución de los objetivos citados en el

apartado anterior se han dividido en dos: recursos humanos y recursos

materiales.

5.2.1 Recursos humanos

En este proyecto los recursos humanos utilizados se resumen en dos

personas principalmente:

✗ Un director del proyecto y persona que ha guiado el proceso de

organización de tareas y planificación temporal. También ha sido el

creador de la idea desarrollada y se ha encargado de revisar la presente

memoria.

✗ Un alumno se ha encargado de investigar el camino para conseguir los

objetivos planteados, es autor de la solución propuesta y de la presente

memoria.

93

Page 114: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 5: Planificación del proyecto.

5.2.2 Recursos materiales

Para la ejecución del presente proyecto se ha necesitado unos recursos

materiales que se pueden agrupar en dos tipos: hardware y software.

Recursos hardware

El hardware utilizado en este proyecto ha consistido en un ordenador

portátil de la marca Airis con las siguientes características:

✗ Procesador Intel ® Pentium ® M a 1,86Ghz.

✗ Sistema operativo Ubuntu en su versión 8.04 Hardy Heron.

✗ Contiene dos imágenes del núcleo Linux de versión 2.6.24-19. Una

compilada con las modificaciones planteadas en el proyecto y la otra

instalada por los mecanismos tradicionales.

Recursos software

Los programas utilizados para el desarrollo del proyecto completo,

incluyendo, por tanto, esta memoria son:

✗ Geany: un editor de textos utilizado para todas las tareas de

programación.

✗ vim: es un editor de textos que carga el texto en la terminal. Se ha

utilizado para visualizar el contenido de archivos del núcleo con mayor

agilidad y para modificar los parámetros de configuración en

/etc/syslog.conf y /etc/sysctl.conf.

✗ OpenOffice 2.4 Writer: se ha utilizado este software para redactar la

memoria del proyecto.

✗ OpenOffice 2.4 Impress: esta herramienta ha sido utilizada para la

creación de las imágenes presentes en este documento.

✗ OpenOffice 2.4 Calc: este programa se ha utilizado en la creación de las

gráficas ilustradas en el Capítulo 4.

✗ Planner 0.14.2: utilizado para generar la planificación temporal.

94

Page 115: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

5.2 Recursos utilizados

✗ Wireshark 1.0: esta herramienta ha hecho posible analizar el tráfico de red

generado en la fase de pruebas para de esta forma contrastar que todo

funcionaba de la manera esperada.

5.3 Planificación temporal y diagrama de Gantt

Una vez se han presentado los objetivos y sus respectivas tareas y los

recursos que se han utilizado para llevarlas a cabo, se puede presentar la

organización temporal que se ha seguido. Para esto se ha visto útil presentar

el diagrama de Gantt realizado.

Se presenta una tabla resumen con la información detallada en el diagrama

de Gantt (Fig. 5.1).

95

Page 116: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 5: Planificación del proyecto.

96

Fig. 5.2: Diagrama de Gantt del proyecto

Page 117: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 6: Conclusiones

En este capítulo se presentan las principales conclusiones que se derivan de

su realización. Puede entenderse como un resumen de los conceptos y

resultados más importantes que se han ilustrado en los capítulos anteriores.

En la primer lugar (Apartado 6.1) se muestran las principales conclusiones que

se derivan de los capítulos precedentes. Para finalizar (Apartado 6.2), se

ilustran las líneas de posibles trabajos futuros que puedan continuar con el

realizado en este proyecto fin de carrera.

6.1 Conclusiones acerca del trabajo realizado.

Las conclusiones extraídas de la realización de este proyecto son las

siguientes:

✗ Se ha propuesto un modelo de servidor modificado con respecto al

propuesto en [2]. La modificación consiste en la adicción de un módulo

nuevo que realiza la tarea de gestionar las colas de servicio.

✗ Se ha propuesto una solución para la problemática asociada a los ataques

DoS contra aplicaciones: las políticas de gestión de colas.

✗ Un entorno de trabajo flexible en el cual es posible implementar cualquier

medida de defensa frente a ataques DoS basada en políticas de gestión de

colas.

✗ Se ha diseñado la arquitectura software para la implementación. Para ello

se ha propuesto el uso de módulos del núcleo, apoyados en la utilización

de los llamados garfios [2].

97

Page 118: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Capítulo 6: Conclusiones

✗ Se ha ilustrado el funcionamiento de la implementación del entorno,

detallando todos sus aspectos de funcionamiento y justificando las

decisiones de diseño adoptadas.

✗ En la búsqueda del lugar en el código del núcleo de Linux en el que

realizar los desarrollos que han permitido la implementación del citado

entorno se ha ilustrado de forma detallada la manera en que el núcleo

gestiona el establecimiento de conexiones TCP.

✗ Para probar el entorno implementado se ha propuesto una política de

gestión de colas básica, que ha sido utilizada para la evaluacióndel

funcionamiento del desarrollo realizado.

✗ Se ha presentado un conjunto de resultados con los que se muestra que la

política de gestión de colas probada mejora el comportamiento del

servidor los efectos de los ataques DoS. Pero sobretodo estos resultados

demuestran que el marco desarrollado posibilita la inclusión de políticas

de gestión de colas en el núcleo.

6.2 Líneas futuras

Durante el desarrollo de este proyecto se han descubierto caminos para la

realización de avances interesantes en las que se tiene como base el trabajo

realizado en este proyecto.

✗ Adaptación del entorno para la inclusión de medidas de defensa frente a

ataque DoS basadas en políticas de gestión de colas a otros sistemas

operativos de código abierto como puede ser OpenBSD.

✗ Generación de políticas de seguridad que introduzcan probabilidades de

descarte en casos concretos, que utilicen mecanismos de detección de

atacantes para realizar el descarte de la conexión, etc. Evaluación de

estas políticas para determinar aquella que dificulte de la mejor forma

posible los efectos de la realización de un ataque DoS.

98

Page 119: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

Bibliografía

[1] Maciá Fernández, G., Díaz-Verdejo, J.E., García-Teodoro, P., Evaluation of a Low-Rate DoS

Attack Against Application Servers, Aceptado en Computers & Security, 2008.

[2] Maciá-Fernández G., Díaz-Verdejo JE., García-Teodoro P., Evaluation of a low-rate DoS attack

against iterative servers. Computer Networks 2007;51(4):1013-30

[3] Wright, C., Cowan, C., Morris, J., Smalley, S., Kroah-Hartman, G., Linux security modules:

General security support for the linux kernel proceeding of the 11th USENIX Security Symposium

[4] Stevens, W.R., Fenner, B., and Rudoff, A. M., (2004) UNIX Network Programming, the sockets

networking API, Volume 1. Addison-Wesley Professional, 3 edition, ISBN: 0-13-141155-1.

[5] Kuzmanovic, A., Knightly E., Low-rate TCP-targeted denial of service attacks and counter

strategies. IEEE/ACM Trans Network August 2006;14(4):683-96

[6] Guirguis M, Bestavros A, Matta I, Zhang Y. Reduction of quality (RoQ) attacks on internet

end-systems, INFOCOM 2005. In: 24th Annual joint conference of the IEEE computer and

communications societies; 2005, p. 1362-72

[7] Guirguis M., Bestavros A., Matta I., Zhang Y., Reduction of quality (RoQ) attacks on dynamic

load balancers: vulnerability assessment and design tradeoffs, INFOCOM 2007. In: 26th IEEE

international conference on computer communications; 2007, p. 857-65

[8] Guirguis M., Bestavros A., Matta I., Explaining the transients of adaptation for RoQ attacks on

internet resources. Proceedings of International Conference on Network Protocols 2004: 184-95.

[9] J. Mirkovic, P., Reiher, A taxonomy of DdoS attack and DdoS defense mechanisms, ACM

SIGCOMM Computer Communication Review 34 (2) (2004) 312-321

[10] Geng X, Whinston AB. Defeating distributed denial of service attacks, IEEE IT Professional

2000;2(4):36-42

[11] C. Douligeris, A. Mitrokotsa, DdoS attacks and defense mechanisms: classification and

state-of-the-art, Computer Networks 44 (2004) 643-646

[12] X. Geneng, A.B. Whinston, Defeating Distributed Denial of Service attacks, IEEE IT

Professional 2 (4) (200) 36-42

[13] S. Axelsson, Intrusion detection systems: a survey and taxonomy, Department of Computer

Engineering, Chalmers University, Goteborg, Sweden, Technical Report 99-15

Page 120: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el
Page 121: Desarrollo de un entorno para la inclusión de medidas de ...dtstc.ugr.es/it/pfc/proyectos_realizados/downloads/... · denegación de servicio y se ha propuesto como solución el

ACTA DE VALORACIÓN DEL PROYECTO

El tribunal constituido para la evaluación del PFC titulado:

DESARROLLO DE UN ENTORNO PARA LA INCLUSIÓN DE MEDIDAS

DE DEFENSA FRENTE A ATAQUES DE DENEGACIÓN DE SERVICIO

BASADAS EN POLÍTICAS DE GESTIÓN DE COLAS.

Relizado por el alumno: Rafael Alejandro Rodríguez Gómez

Y dirigido por el tutor: Gabriel Maciá Fernández

Ha resuelto asignarle la calificación de:

SOBRESALIENTE (9 - 10 puntos)

NOTABLE (7 - 8.9 puntos)

APROBADO (5 - 6.9 puntos)

SUSPENSO

Con la nota1: puntos

El Presidente:______________________________

El Secretario:______________________________

El Vocal:___________________________________

Granada, a __ de ___________ de 200__

1 Solamente con un decimal