Configuración y desarrollo del Protocolo IP versión 6
Transcripción
Configuración y desarrollo del Protocolo IP versión 6
Protocolo de Internet versión 6 Configuración y Desarrollo Pablo Carmona Amigo – Renato Ulloa Sepúlveda Ingenierı́a Civil Electrónica Universidad de La Frontera 24 de julio de 2002 Resumen Este informe pretende mostrar a grandes rasgos el trabajo de investigación, configuración y programación en el nuevo protocolo que regirá Internet en un futuro cercano, esto es IPv6 (Protocolo Internet versión 6). A través del presente trabajo se pretenden mostrar básicamente dos cosas. Por un lado, ver todo lo referente a configuración de equipos GNU/Linux, (como router y cliente) y la configuración de un cliente Windows 2000 para formar parte de una red LAN. En tanto por otro lado se aborda el tema de la programación de redes usando los llamados Sockets. Este último es un medio para conectar los programas a la red, pudiendo de esta forma enviar y recibir los mensajes. Esta no pretende ser una guı́a completa referente al tema, más bien es dar un vistazo a algunos aspectos del trabajo necesario para poder hacer uso de redes basadas en IPv6. Índice 1. Introducción a IPv6 2 2. Caracterı́sticas de IPv6 2 2.1. Aumento del espacio de direcciones . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2.2. Autoconfiguración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.3. Seguridad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.4. Calidad de Servicio (QoS) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.5. Enrutamiento Jerárquico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 3. Configuración general 5 3.1. Habilitación de IPv6 en los equipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 3.1.1. Computador con GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1 3.1.2. Computador con Windows 2000 . . . . . . . . . . . . . . . . . . . . . . . . . 8 3.2. Configuración del router . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 3.2.1. Túneles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 3.2.2. Zebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.3. Configuración de los clientes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.3.1. Configuración en Debian GNU/Linux . . . . . . . . . . . . . . . . . . . . . . 13 3.3.2. Configuración en Windows 2000 . . . . . . . . . . . . . . . . . . . . . . . . . 14 3.4. Pruebas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 4. Programación de aplicaciones para IPv6 16 4.1. Sockets IPv6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 4.2. Ejemplos de cliente y servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 4.2.1. Cliente TCP6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 4.2.2. Servidor TCP6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 4.2.3. Pruebas del cliente y el servidor . . . . . . . . . . . . . . . . . . . . . . . . . 23 1. Introducción a IPv6 El Protocolo de Internet versión 6, conocido por sus siglas IPv6, es el nuevo protocolo que se utilizará en Internet dentro de los próximos años. Su aplicación se debe a que el reducido espacio de direcciones que ofrece la versión 4 del Protocolo de Internet (IPv4) ya está alcanzando su lı́mite. IPv6 ofrece un número muy superior de direcciones (del orden de 10 ) dado que la dirección se representa con 128 bits. Se recomienda revisar [3] y [5] para mayores detalles. 2. Caracterı́sticas de IPv6 Antes de comenzar con la caracterización del nuevo protocolo se debe mencionar por qué fue necesario el replanteamiento del ya acostumbrado IPv4, tratando de solventar todas las falencias, debilidades y además agregar caracterı́sticas propias que harán que con esta versión por fin se de solución a todas las necesidades de las redes, ya sea desde una simple LAN hasta la red de redes, la Internet. De las caracterı́sticas que vienen a dar solución se puede mencionar al aumento del espacio de direcciones, autoconfiguración, seguridad y calidad de servicio (QoS). 2.1. Aumento del espacio de direcciones En IPv4 se tiene una estructura de direcciones de 32 bits, agrupado en 4 octetos separados por un punto (.); lo que da 4,29x10 direcciones posibles. Dado el agotamiento de las direcciones 2 ruteables en Internet1 , fue necesario recurrir a la denominada NAT2 , para de esta forma dar acceso a la red pública a hosts que utilizan direcciones privadas. Con este método bastaba sólo una dirección válida y tras ella el resto de hosts con direcciones reservadas. Esto ya no será necesario porque se produce el cambio de 32 bits a 128 bits trayendo consigo el gigantesco aumento de direcciones posibles. Si se toman estos 128 bits de la longitud de la dirección, se hacen 8 grupos de 16 bits separados por dos puntos(:), y si se agrupa cada bloque de 16 bits en 4 bloques de 4 bits se podrá pasar 3 de notación binaria a hexadecimal para hacerlas más comprensibles y recordables. De esta es tructura se obtendrán 3,4x10 direcciones. La mencionada escritura en hexadecimal se hace necesaria porque serı́a imposible manejar una dirección como: 0011111111111110:1000000001110000:0001000000001100:0000101100000110: 0000000000000000:0000000000000000:0000000000000001:0000000000000001 Resulta más práctico escribirlo como: 3ffe:8070:100c:0b06:0000:0000:0001:0001 Sin embargo, esto es aún muy largo y engorroso, es por esto que se utiliza la llamada compresión de ceros, que dice lo siguiente: Se pueden reemplazar secuencias contiguas de ceros con “::”. Esto es posible solamente una vez en toda la dirección y teniendo siempre cuidado de tomar bloques completos de 16 bits. Los ceros a la izquierda de cada bloque de 16 bits se pueden quitar. Es decir, si se aplican estas reglas a la dirección anterior, quedarı́a de la forma: 3ffe:8070:100c:b06::1:1 Ésta es por cierto la dirección que tiene asignado el Router. Como se ve, dada la complejidad de las direcciones respecto de las IPv4 se hace necesario (más bien crı́tico) el uso del servicio DNS4 más que en la versión anterior del protocolo. Para mayor información acerca de DNS en IPv6 se recomienda [13]. 1 Es decir, excluyendo las direcciones de uso privado, por ejemplo: 10.0.0.0/8, 192.168.0.0./16 Del inglés Network Address Translation 3 En base 16, es decir, los números van de 0. . . 9, A, B, C, D, E, F (0 a 15 decimal) 4 Del inglés Domain Name Service, permite asociar un nombre con una dirección IP y viceversa. 2 3 2.2. Autoconfiguración Esto se refiere básicamente al concepto de conectar y comenzar a usar. Es decir, cuando algún nodo o host se conecte a una red, éste recibe datos del router para comenzar a comunicarse: una dirección IPv6, máscara de red y rutas a utilizar. Lo que se trata de lograr es similar al DHCP 5 usado comúnmente en IPv4. En este punto existen básicamente dos métodos: Un proceso de asignación de direcciones en base a la direccion MAC de la tarjeta de red o bien mediante DHCPv6, que es un servicio que asigna una dirección al equipo, controlando de este modo el rango de direcciones con que se trabaja. Este último en realidad es algo controlado por el administrador de red, lo que quizás no podrı́a ser considerado como autoconfiguración. Existen variantes para la asignación de direcciones, que serán vistas más adelante en el capı́tulo 3 en la página 5. Se pueden obtener detalles en [14]. 2.3. Seguridad Éste es quizás uno de los principales requerimientos a la hora de plantear esta versión del protocolo, beneficiando a las aplicaciones en cuanto a autenticación y encriptación de datos en forma transparente. Cabe señalar que IPv4 no poseı́a seguridad ni menos encriptación de datos, para ello era necesario usar software de encriptación basados en varios estándares, uno de los más utilizados fue IPSec. Es precisamente en éste que se basa la encriptación incluı́da en IPv6. 2.4. Calidad de Servicio (QoS) Si bien es cierto que en IPv4 existı́an algunos bits en la cabecera para el control del Tipo de Servicio (ToS6 ), en IPv6 se disponen de campos más amplios para definir prioridad y flujo de cada paquete a ser transportado. Estos campos son leı́dos por los routers y de acuerdo a ellos se les debe dar un trato especial. Por ejemplo, si un paquete va marcado como flujo de video, resulta evidente que debe ser enviado con prioridad sobre paquetes que podrı́an estar marcados como correo electrónico. Si un e-mail se demora 2 ó 10 segundos es casi imperceptible, en cambio en una videoconferencia esto es inaceptable. A esto se le denominda QoS7 . Más información en [7]. 2.5. Enrutamiento Jerárquico El ruteo en IPv6 es jerárquico y sin las clases que existı́an en IPv4. De esta forma se logra que las tablas de ruta no crezcan más allá de lo necesario8 . Junto con disminuir los tamaños de las tablas de rutas se simplifica el ruteo en sı́, haciendo que los routers sean más eficientes. 5 Del inglés Dynamic Host Configuration Protocol Del inglés Type of Service 7 Del inglés Quality of Service 8 En IPv4 las tablas de ruta han crecido de tal forma que se han convertido en inmensos archivos que sólo son manejables con poderosos servidores dedicados 6 4 3. Configuración general Se realizó la configuración en un servidor corriendo Red Hat Linux 7.3 que trabaja principalmente como router, y otro corriendo Debian GNU/Linux Sid y que se configuró como un cliente. También se configuraron otros dos clientes usando Windows 2000 Professional. El objetivo a conseguir en cuanto a la creación, configuración y mantención de túneles se puede sintetizar en la figura 1 en la página 6. Como se ve, se cuenta con un túnel hacia la Universidad Austral de Chile (UACH) desde el Departamento Ingenierı́a Eléctrica (DIE) de la Universidad de La Frontera y otro hacia el Instituto de Informática Educativa (IIE), que también se encuentra en esta universidad. Este último posee una subred de la división del rango de direcciones dadas por la UACH. Obviamente se tiene salida a través de la UACH hacia el 6 BONE 9 . Las direcciones asignadas a la UFRO, tanto para red como para el túnel son las siguientes: Red disponible para la UFRO: 3ffe:8070:100c:b06::/64 Túnel dado por la UACH: Extremo UACH: 3ffe:8070:100c:2b02::a/64 Extremo UFRO: 3ffe:8070:100c:2b02::b/64 Número autónomo ASN: UACH: 45333 UFRO: 45348 Es con estos valores (o derivados de ellos) que se realiza la configuración de los túneles, router y equipos clientes. En particular se subdividió la red 3ffe:8070:100c:b06::/64 de la siguiente forma: Red DIE: 3ffe:8070:100c:b06::1:0/112 Red IIE: 3ffe:8070:100c:b06::2:0/112 Red para túnel con IIE: 3ffe:8070:100c:b06::ffff:0/112 3.1. Habilitación de IPv6 en los equipos Antes de comenzar la configuración particular de los equipos es necesario hacer alcances de la configuración básica y necesaria para poder trabajar con el protocolo en máquinas Linux y Windows. Las configuraciones que vienen a continuación pueden ser revisadas en [1], [2], [4], [8] y [9]. Si bien no todos ellos son especı́ficos de IPv6 también esclarecen situaciones y configuraciones que se realizan de forma similar en IPv4. 9 Mayores consultas en www.6bone.net 5 Figura 1: Esquema de túneles de la Universidad de La Frontera 6 3.1.1. Computador con GNU/Linux Antes de cualquier uso del protocolo en el S.O. GNU/Linux se necesita cargar el módulo ipv6, para esto existen varias formas de hacerlo: En forma manual: esto quiere decir que una vez que se inició Linux, se abre una consola y como root se escribe: [root@ipv6 root]# modprobe ipv6 Con esto se carga el módulo y ya es posible comenzar a utilizar el protocolo, ya sea asignar direcciones, configuraciones, etc. Usando un archivo de inicio: esto se consigue mediante la creación de un archivo que contenga la lı́nea: modprobe ipv6 luego se agrega el nombre de este archivo en /etc/rc.d/rc.local10. Incluso se puede escribir esto directamente en /etc/rc.d/rc.local. Con este método es necesario reiniciar para que la configuración se haga efectiva. Modificando archivos del Network (Red Hat 7.x): este es el método recomendado, ya que es el que viene con la distribución. Para esto debemos editar varios archivos, comenzando con /etc/sysconfig/network, cuyo contenido es similar a esto: NETWORKING=yes HOSTNAME=ipv6 GATEWAY=146.83.206.254 Tras esta última lı́nea debemos agregar lo siguiente: NETWORKING_IPV6=yes Ahora tenemos que editar el archivo de configuración /etc/sysconfig/network-scripts/ ifcfg-ethx11 y agregar la lı́nea: IPV6INIT=yes Una vez hecho esto guardamos los cambios y ahora es necesario reiniciar el network mediante el comando /etc/init.d/network restart, una vez hecho esto ya tenemos habilitado el protocolo. Esto se hace en forma automática cada vez que se inicia el equipo, por lo que esto sólo se hace cuando recién hemos modificado el archivo. Una vez echo esto ya se está en condiciones de continuar con la configuración de cualquier tipo. Podrı́amos por ejemplo hacer un /sbin/ifconfig y se deberı́a obtener algo como: 10 11 La ubicación puede variar dependiendo de la distribución. Esto es válido para Red Hat 7.x Puede ser eth0, eth1 según corresponda. 7 eth0 Link encap:Ethernet HWaddr 00:04:75:81:26:45 inet addr:146.83.206.114 Bcast:146.83.206.255 Mask:255.255.255.0 inet6 addr: fe80::204:75ff:fe81:2645/10 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:3019997 errors:0 dropped:0 overruns:30 frame:0 TX packets:1570211 errors:0 dropped:0 overruns:0 carrier:0 collisions:157201 txqueuelen:100 RX bytes:439717982 (419.3 Mb) TX bytes:885637606 (844.6 Mb) Interrupt:10 Base address:0xbc00 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:19604 errors:0 dropped:0 overruns:0 frame:0 TX packets:19604 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:2998019 (2.8 Mb) TX bytes:2998019 (2.8 Mb) En este ejemplo podemos apreciar la existencia de una dirección IPv6 del tipo fe80::204:75ff:fe81:2645/10 Que es del tipo de autoconfiguración, esto quiere decir que de forma automática se ha asignado esta dirección. También se ven las direcciones de loopback: 127.0.0.1 en IPv4. ::1/128 en IPv6. 3.1.2. Computador con Windows 2000 Se debe decir que la configuración de los clientes Windows 2000 es bastante simple, pero poco clara. Se debe bajar desde el sitio de Microsoft en Internet el archivo tpipv6-version.exe 12 , éste se descomprime al ejecutarlo y posteriormente hay que buscar el archivo setup.exe en el directorio donde se descomprimió para ejecutarlo y terminar con la instalación del protocolo. 3.2. Configuración del router Una vez pasada la etapa de inicialización del protocolo, se puede asignar una dirección IPv6 del rango dado a este equipo13 . Para esto se abre una consola como root y se escribe: # ip -f inet6 address add 3ffe:8070:100c:b06::1:1/112 dev eth0 En donde: ip -f inet6 le dice al comando ip que lo que viene a continuación es de la familia IPv6. 12 13 Se puede encontrar en http://msdn.microsoft.com/downloads/sdks/platform/tpipv6.asp Esto es válido también para los clientes Linux. 8 address add indica que se tiene que manejar una dirección, añadir una especı́ficamente. dirección/prefijo dev eth0 aquı́ se le da la dirección que se ha elegido y la interfaz a la que se le quiere asignar dicha dirección. En este caso es eth0. Esta es sólo una de las formas de realizar esta configuración, la otra es editando el archivo se ve como éste: /etc/sysconfig/network-scripts/ifcfg-eth0 que DEVICE=eth0 BOOTPROTO=static BROADCAST=146.83.206.255 IPADDR=146.83.206.114 NETMASK=255.255.255.0 NETWORK=146.83.206.0 ONBOOT=yes IPV6INIT=yes y se agrega la lı́nea: IPV6ADDR="3ffe:8070:100c:b06::1:1/112" Una vez guardado este cambio se reinicia el network ejecutando /etc/init.d/network restart, luego de esto ya se cuenta con la dirección en la interfaz eth0. Cabe señalar que se pueden tener múltiples direcciones en una misma interfaz de red, añadiendo en el mismo archivo una lı́nea similar a esta: IPV6ADDR_SECONDARIES="3ffe:8070:100c:b06::1:2/112 3ffe:8070:100c:b06::1:3/112" Con esto ya se tienen 3 direcciones en la interfaz eth0. No olvidar reiniciar el network. Se recomienda [1], [2] y [4]. 3.2.1. Túneles Para poder manejar tráfico IPv6 en redes separadas por routers IPv4 se debe recurrir a los llamados T ÚNELES. A través de ellos se envı́an los paquetes IPv6 encapsulados en paquetes IPv4 hacia otra red que maneje también el protocolo. Con esto se logra unir nubes IPv6, pero inmersos en redes del tipo IPv4. Antes de la creación de los túneles se necesitan varios datos: Dirección IPv4 de nuestro Router: 146.83.206.114 Dirección IPv4 del router remoto14 : 146.83.248.2 Dirección IPv6 para el túnel: 3ffe:8070:100c:2b02::a/64 para el equipo remoto. 3ffe:8070:100c:2b02::b/64 para el equipo local. Para la creación de ellos existen variadas formas: 14 Con quien se quiere establecer el túnel. 9 A través de la consola: ip ip ip ip tunnel add UACH mode sit remote 146.83.248.2 local 146.83.206.114 ttl 64 link set UACH up address add 3ffe:8070:100c:2b02::b/64 dev UACH route add 3ffe:8070:100c:2b02::a/64 dev UACH Con esto se ha creado la interfaz de túnel UACH, en modo sit, es decir, IPv6 en IPv4. Luego se activa la interfaz, se asigna el extremo local del túnel y se añade el extremo remoto. Hecho esto ya se puede comenzar a probar la conexión, por ejemplo con un ping6 al otro extremo: root@ipv6 root# ping6 -c4 3ffe:8070:100c:2b02::a PING 3ffe:8070:100c:2b02::a(3ffe:8070:100c:2b02::a) from 3ffe:8070:100c:2b02::b : 56 data bytes 64 bytes from 3ffe:8070:100c:2b02::a: icmp_seq=1 ttl=64 time=31.3 ms 64 bytes from 3ffe:8070:100c:2b02::a: icmp_seq=2 ttl=64 time=10.4 ms 64 bytes from 3ffe:8070:100c:2b02::a: icmp_seq=3 ttl=64 time=12.5 ms 64 bytes from 3ffe:8070:100c:2b02::a: icmp_seq=4 ttl=64 time=20.1 ms --- 3ffe:8070:100c:2b02::b ping statistics --4 packets transmitted, 4 received, 0% loss, time 3000ms rtt min/avg/max/mdev = 0.009/0.029/0.071/0.025 ms Está funcionando. Mediante un archivo de inicio: Al igual que se hizo para cargar el módulo ipv6, ahora se pueden escribir estos mismos comandos en un archivo y luego incluir el nombre de ese archivo (con su ruta por cierto) en /etc/rc.d/rc.local. Utilizando la herramienta de Red Hat: Este método es el que finalmente se utilizó. Consiste en la creación del archivo ifcfg-uach en el directorio /etc/sysconfig/network-scripts/ y cuyo contenido es el siguiente: DEVICE=uach BOOTPROTO=none ONBOOT=yes IPV6INIT=yes IPV6TUNNELIPV4=146.83.248.2 IPV6ADDR=3ffe:8070:100c:2b02::b/64 IPV6_DEFAULTGW=3ffe:8070:100c:2b02::a IPV6_DEFAULTDEV=uach En él se especifican la dirección IPv4 remota, el extremo local del túnel, el gateway por defecto y el dispositivo por defecto15 . Una vez guardado esto, se ingresan los siguientes comandos en la consola: root@ipv6 root# ln -s ifup-sit ifup-uach root@ipv6 root# ln -s ifdown-sit ifdown-uach 15 Estas dos últimas variables sólo son leı́das en la versión 7.3 de Red Hat. 10 Con esto se crea un enlace simbólico hacia los archivos donde están las funciones necesarias para subir y bajar el túnel. Luego de hecho esto, se reinicia el network con el correspondiente /etc/init.d/network restart. Con esto, ya se tiene un túnel cuyo nombre será uach. Podemos hacer un ifconfig y se verá el dispositivo del túnel: uach Link encap:IPv6-in-IPv4 inet6 addr: 3ffe:8070:100c:2b02::b/64 Scope:Global inet6 addr: fe80::9253:ce72/10 Scope:Link inet6 addr: fe80::a00:1/10 Scope:Link UP POINTOPOINT RUNNING NOARP MTU:1480 Metric:1 RX packets:692080 errors:0 dropped:0 overruns:0 frame:0 TX packets:692944 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:113649875 (108.3 Mb) TX bytes:60870452 (58.0 Mb) En forma opcional se puede subir el túnel ejecutando simplemente: root@ipv6 root# ifup uach o bien para bajar: root@ipv6 root# ifdown uach 3.2.2. Zebra Para que una red de redes funcione hace falta que los routers tengan mapas (totales o parciales) de la red. Estos mapas pueden generarse manualmente mediante rutas estáticas o automáticamente mediante protocolos de ruteo. En la isla que se trabajó, bastó con rutas estáticas, sin embargo, dado que se está experimentando es conveniente hacerlo también con los nuevos protocolos de ruteo y generar estos mapas automáticamente de ser posible. Se llama sistema autónomo a “alguna red”, esto es, a una red o conjunto de redes controladas por una única entidad administrativa. Cada sistema autónomo decide cómo manejar sus redes internas independientemente de cualquier otro, y se conecta a otros sistemas autónomos por medio de protocolos de ruteo externos. El protocolo de ruteo externo más común es el BGP16 . Este protocolo se maneja en base a números de sistema autónomo (ASN). Básicamente, lo que hace BGP es establecer una relación de pares entre dos routers que pertenecen a distintos sistemas autónomos y esos routers se informan entre sı́ acerca de a qué redes conocen como hacer llegar paquetes, con lo que pueden formarse los mapas de los que hablabamos antes. Para el ruteo del tráfico de la red se usó el administrador de protocolos de ruteo Zebra17 versión 0.91a y el protocolo BGP-418 . Para usar este software se puede conseguir en el CD de la distribución o bien bajarlo de Internet, de www.zebra.org por ejemplo. Una vez instalado se necesitan básicamente dos archivos de configuración: zebra.conf y bgpd.conf; ambos ubicados en /etc/zebra/. El contenido de zebra.conf es: ! ! Zebra configuration saved from vty 16 Se recomienda [6] y [11] Más información en www.zebra.org 18 Border Gateway Protocol 17 11 ! 2002/06/26 16:15:57 ! hostname zebra password clave1 enable password clave2 ! interface lo ! interface sit0 ! interface eth0 ipv6 nd send-ra ipv6 nd prefix-advertisement 3ffe:8070:100c:b06::1:0/112 ! interface tunl0 ! Interesan el hostname, las claves y las lı́neas que comienzan con ipv6. Mediante la lı́nea ipv6 nd send-ra se le está diciendo a Zebra que haga anuncio de router19 y con ipv6 nd prefix advertisement 3ffe:8070:100c:b06::1:0/112 se especifica la red y el prefijo a anunciar. En cuanto a las claves, éstas son necesarias para la intervención en la consola del bgpd. Esta configuración se logra creando este archivo en forma manual y luego iniciando Zebra de la forma service zebra start. Una vez hecho esto se debe configurar el bgpd.conf. También se edita el archivo y se incluye algo como: ! ! Zebra configuration saved from vty ! 2002/06/26 16:25:20 ! hostname bgpd password ****** enable password ****** log file /var/log/zebra/bgpd.log ! router bgp 45348 ipv6 bgp network 3ffe:8070:100c:b06::/64 ipv6 bgp neighbor 3ffe:8070:100c:2b02::a remote-as 45333 ipv6 bgp neighbor 3ffe:8070:100c:2b02::a interface uach ipv6 bgp neighbor 3ffe:8070:100c:2b02::a description TunelUACH ipv6 bgp neighbor 3ffe:8070:100c:2b02::a next-hop-self ipv6 bgp neighbor 3ffe:8070:100c:b06::ffff:2 remote-as 64512 ipv6 bgp neighbor 3ffe:8070:100c:b06::ffff:2 interface iie ipv6 bgp neighbor 3ffe:8070:100c:b06::ffff:2 description TunelIIE ipv6 bgp neighbor 3ffe:8070:100c:b06::ffff:2 next-hop-self ! line vty ! En él se aprecian las configuraciones de las redes involucradas en el ruteo, primero se define la red local, luego se da el extremo remoto del túnel asociado a ciertos parámetos: ASN remoto, interfaz, una descripción y el next-hop-self. Aquı́ se muestra la configuración del túnel con la UACH y con el Instituto Informática Educativa. Esta última isla está usando un ASN privado. Creado este archivo se debe iniciar el bgpd mediante service bgpd start y deberı́a tomar la 19 Es decir que anuncia la red correspondiente. 12 configuración que se indica en el archivo modificado. Para asegurarse se podrı́a reiniciar el Zebra mediante service zebra restart y luego iniciar el bgpd. Una forma de confirmar la configuración es haciendo un telnet al puerto 2605 (bgpd) de la forma: root@ipv6 root# telnet 127.0.0.1 2605 Debiendo realizar la siguiente secuencia: Hello, this is zebra (version 0.91a). Copyright 1996-2001 Kunihiro Ishiguro. User Access Verification Password: bgpd> ena Password: bgpd# show ipv6 bgp summary BGP router identifier 146.83.206.114, local AS number 45348 275 BGP AS-PATH entries 0 BGP community entries Neighbor AS MsgRcvd MsgSent Up/Down State/PfxRcd 3ffe:8070:100c:b06::ffff:2 64512 508 38738 00:00:49 Connect Description: TunelIIE 3ffe:8070:100c:2b02::a 45333 934898 12682 5d09h32m 344 Description: TunelUACH Total number of neighbors 2 Aquı́ se muestra la configuración correcta de acuerdo a lo ingresado en el archivo bgpd.conf. Con esto ya basta para que se realice el trabajo de ruteo, ahora sólo se necesita agregar clientes a esta red que ya cuenta con un router BGP-4. Una vez hecho esto y después de innumerables pruebas del sistema, se ha observado que el anuncio de router es válido solamente si el prefijo es de 64 bits, ya que la MAC de la tarjeta es usada siempre para configurar la dirección IPv6. Esto quiere decir, que se podrı́a usar este método siempre y cuando se cuente con un prefijo menor o igual a 64, de otro modo se debe configurar a mano cada equipo (que es precisamente lo que finalmente se hizo). Por lo investigado, la forma de hacer una real configuración automática apegándose a la red designada serı́a usando DHCPv6, que actualmente se encuentra en desarrollo y sólo hay paquetes de prueba, los que no se quisieron probar por ahora. Para mayores detalles respecto de la creación de túneles y configuración de routers se recomienda [1] y [8]. 3.3. Configuración de los clientes A continuación se presenta la forma de configurar dos equipos que corren sistemas operativos diferentes. Primero se configura un equipo con Debian GNU/Linux para posteriormente hacerlo con uno corriendo Windows 2000. 3.3.1. Configuración en Debian GNU/Linux En esta distribución la carga del módulo ipv6 se puede hacer usando /etc/modules. Solamente hay que agregar el nombre ipv6 al final de este archivo para que Debian lo cargue en la partida. 13 Las direcciones, prefijos y gateways de las diferentes interfaces de red del equipo se configuran en el archivo /etc/network/interfaces, que son utilizados por los programas ifup e ifdown para levantar y bajar las interfaces de red. # /etc/network/interfaces -- configuration file for ifup(8), ifdown(8) # The loopback interface auto lo iface lo inet loopback auto eth0 iface eth0 inet static address 146.83.206.112 netmask 255.255.255.0 broadcast 146.83.206.255 network 146.83.206.0 gateway 146.83.206.254 iface eth0 inet6 static address 3ffe:8070:100c:b06::1:2 netmask 112 gateway 3ffe:8070:100c:b06::1:1 En este archivo conviven todas las configuraciones, ya sean de IPv4 o IPv6. Para asignar una dirección estática de IPv6 a la tarjeta ethernet se usa una declaración del tipo iface eth0 inet6 static Después de esta lı́nea se puede agregar la dirección asignada al equipo. Usando address, netmask y gateway se designa la dirección, prefijo de red y puerta de enlace. Hay que tener en cuenta que en netmask se pone el número de bits de red, no una máscara de red. address 3ffe:8070:100c:b06::1:2 netmask 112 gateway 3ffe:8070:100c:b06::1:1 En este ejemplo, el equipo con Debian tiene asignada la dirección 3ffe:8070:100c:b06::1:2/112 y el router de salida es 3ffe:8070:100c:b06::1:1. Las lı́neas del archivo que comienzan con auto indican que la interfaz que se nombra a continuación será configurada al iniciarse el sistema. Para mayor información se puede recurrir a la página de manual de interfaces, sección 5, con el comando man interfaces. También se puede consultar la página de manual de los programas ifup e ifdown con man ifup o man ifdown respectivamente. 3.3.2. Configuración en Windows 2000 La instalación del protocolo se hace como se explicó en la sección 3.1.2 en la página 8. Para agregar direcciones, prefijo y router por defecto se deben ejecutar los siguientes comandos en una ventana de DOS. 14 ipv6 adu 4/3ffe:8070:100c:b06::1:2 ipv6 rtu 3ffe:8070:100c:b06::1:0/112 4 ipv6 rtu ::/0 4/3ffe:8070:100c:b06::1:1 En la primera lı́nea se agrega la dirección, en la segunda se le da la red a la que pertenece la dirección junto con el prefijo y la interfaz. Finalmente se establece el router por defecto a través de la interfaz correspondiente, en este caso 4. Al hacerlo de esta forma se pierde la configuración cuando se reinicie el equipo. La manera de hacer permanente esta configuración es crear un archivo con extensión .cmd que contenga estas instrucciones y posteriormente añadirlo en el Programador de Tareas para que sea ejecutado cada vez que se inicia el equipo. Una vez hecho esto ya está configurado el equipo correctamente para comenzar a usar el protocolo. Están disponibles por ejemplo las herramientas comunes como ping6, tracert6, etc. 3.4. Pruebas En esta sección se muestra una prueba del funcionamiento de la red. A continuación se presenta el resultado de ping6, tracert6 desde el cliente Windows 2000. Se opta por esto dado que la prueba desde el mismo router puede no necesariamente provenir de una correcta configuración y funcionamiento de Zebra. Primero el ping6: C:\>ping6 www.6bone.net Pinging 6bone.net [3ffe:b00:c18:1::10] with 32 bytes of data: Reply Reply Reply Reply from from from from 3ffe:b00:c18:1::10: 3ffe:b00:c18:1::10: 3ffe:b00:c18:1::10: 3ffe:b00:c18:1::10: bytes=32 bytes=32 bytes=32 bytes=32 time=739ms time=737ms time=736ms time=736ms C:\> En este ping6 se pone el nombre del sitio dado que en la UACH están resolviendo nombres. No es necesario escribir la dirección en hexadecimal. Ahora se presenta un tracert6 para mostrar la ruta seguida por los paquetes hacia el 6 BONE. C:\>tracert6 www.6bone.net Tracing route to 6bone.net [3ffe:b00:c18:1::10] over a maximum of 30 hops: 1 2 3 4 5 6 <1 5 469 603 737 738 ms ms ms ms ms ms <1 5 468 601 737 737 ms ms ms ms ms ms <1 5 468 603 737 737 ms ms ms ms ms ms 3ffe:8070:100c:b06::1:1 3ffe:8070:100c:2b02::a 3ffe:8240:800d::1 3ffe:8280:0:2000::8 rap.ipv6.viagenie.qc.ca[3ffe:b00:c18:1:290:27ff:fe17:fc0f] www.6bone.net [3ffe:b00:c18:1::10] Trace complete. 15 C:\> Viendo la salida del comando anterior, se aprecia que primero se envı́a el tráfico hasta el router local (3ffe:8070:100c:b06::1:1), posteriormente se va al extremo del túnel en la UACH y ası́ continúa por otros nodos hasta llegar al destino, que es el 6 BONE [3ffe:b00:c18:1::10]. Con esto se da por entendido que ahora sólo resta comenzar a levantar servicios que soporten el protocolo, por ejemplo DNS, SMTP y WWW para comenzar. Todas estas implementaciones se podrı́an realizar más tarde, de tal forma de probar el funcionamiento de los servicios habituales con el nuevo protocolo. 4. Programación de aplicaciones para IPv6 La programación de redes se hace con Sockets, que es un medio que permite a los programas conectarse a la red y poder enviar y recibir mensajes. La API (interfaz de programa de aplicación) de Sockets ofrece estructuras de datos y funciones que permiten abstraerse de la red, puesto que en el envı́o y recepción de la información no hay que preocuparse de cabeceras del paquete ni de otras cosas relacionadas con la comunicación. Esto permite al programador preocuparse más del tratamiento de los datos que de la comunicación en sı́. El importante cambio introducido por IPv6 en el tamaño de las direcciones, hace que los programas hechos para operar con la versión actual del protocolo IP no puedan funcionar con la versión 6. Sin embargo, la conversión de los programas a IPv6 no es muy complicada, por lo ya descrito anteriormente. Los cambios radican principalmente en las entructuras de datos utilizadas, las que se tuvieron que adaptar a las nuevas exigencias del protocolo. No se tratará con profundidad la programación de sockets para no extenderse demasiado. Las explicaciones centrarán su atención en los sockets IPv6 principalmente. En todo el desarrollo que se hará de programas de red basados en IPv6, se utilizarán los Sockets de Linux, un sistema operativo libre y que provee todas las herramientas necesarias para un desarrollo completo. Si se desea aprender más acerca de la programación de sockets en Linux, puede consultar [15]. 4.1. Sockets IPv6 Se utilizan las mismas funciones para la programación de sockets IPv4 utilizando C, con la diferencia de que cambia la familia de protocolos por PF INET6 y la familia de direcciones por AF INET6, las que se usan en la llamada socket y en la estructura socket. La declaración de la función socket deberı́a ser de la forma: sd = socket (PF_INET6, SOCK_STREAM, 0); sd = socket (PF_INET6, SOCK_DGRAM, 0); sd = socket (PF_INET6, SOCK_RAW, 0); /* si se usa TCP */ /* si se usa UDP */ /* si se usa ICMP o Raw */ Todas devuelven un descriptor de socket para ser utilizado por otras funciones relacionadas con la comunicación. 16 También cambia la estructura socket de sockaddr in a sockaddr in6, y ésta es la que se utiliza en las llamadas a las funciones accept, bind y connect. La estructura socket, que está ampliamente explicada en [10], contiene las siguientes variables: struct sockaddr_in6 uint8_t sa_family_t in_port_t uint32_t struct in6_addr uint32_t }; { sin6_len; sin6_family; sin6_port; sin6_flowinfo; sin6_addr; sin6_scope_id; /* /* /* /* /* /* length of this struct */ AF_INET6 */ transport layer port # */ IPv6 flow information */ IPv6 address */ set of interfaces for a scope */ Los miembros sin6 family, sin6 port y sin6 addr deben ser definidos antes de pasar la estructura a la funciones accept, bind o connect. Por ejemplo, si se crea una variable con la estructura socket llamado destino con la declaración struct sockaddr_in6 destino; se podrı́an llenar los datos de la siguiente forma: bzero (&destino, sizeof (destino)); destino.sin6_family = AF_INET6; destino.sin6_port = htons (PORT); La primera lı́nea usa la función bzero para poner a cero la estructura con el fin de agregar datos. Luego se asigna la familia de direcciones con AF INET6 y finalmente se incluye el puerto. Aquı́ se utiliza la función htons para convertir el valor del puerto a un número en bytes de red, utilizado por el sistema operativo para la comunicación. Se puede encontrar más información en [15]. Para agregar la información de la dirección se utiliza la función inet pton que transforma la dirección alfanumérica a binario ordenado en bytes de red. Su utilización puede ser la siguiente: if ( inet_pton (AF_INET6, "3ffe:8070:100c:b06::1:1", &destino.sin6_addr) == -1 ) perror ("Error en inet_pton"); El resto de la programación es igual que siempre, salvo que para obtener la dirección de una cierta estructura socket se debe utilizar la función inet ntop, que realiza lo inverso a lo que hace inet pton. Se podrı́a utilizar la siguiente forma para almacenar el valor devuelto en una variable de cadena y utilizarla para enviarla a la salida estándar. char direccion_destino[INET6_ADDRSTRLEN]; inet_ntop (AF_INET6, &destino.sin6_addr, direccion_destino, INET6_ADDRSTRLEN); printf ("Intentando conectar a [%s]:%d...\n", direccion_destino, ntohs (destino.sin6_port)); Se usa INET6 ADDRSTRLEN para asignar espacio suficiente para almacenar una dirección IPv6 en una variable de cadena. 17 4.2. Ejemplos de cliente y servidor Se presenta a continuación los dos programas sencillos de cliente y servidor TCP para IPv6. La forma de programar protocolos UDP e ICMP no son tratados aquı́. Puede consultar [15] para obtener información acerca de eso. 4.2.1. Cliente TCP6 Todo cliente funciona de la siguiente manera: Crear un socket. Crear una dirección destino para el servidor. Conectar con el servidor. Leer y visualizar cualquier mensaje. Cerrar la conexión. Para conectar con el servidor se utiliza la función connect, a la cual se le pasa el descriptor del socket creado (sd), la estructura socket (destino) y su tamaño. connect (sd, (struct sockaddr *) &destino, sizeof (destino)); Devuelve cero si no hay errores en la conexión y distinto de cero cuando los hay. Se puede diagnosticar el error usando, por ejemplo, la función perror para obtener un mensaje descriptivo del error producido. Para enviar un mensaje al servidor remoto se puede utilizar la función send, que necesita como parámetros el descriptor de socket, el búfer (o mensaje) a enviar, el tamaño de éste y unas opciones del tipo de envı́o, que normalmente se dejan a 0. Para mayor información consulte [15]. send (sd, peticion, sizeof (peticion), 0); Devuelve un valor menor que cero si se produce algún error. Luego de enviar datos al servidor se puede recibir la respuesta de éste. Esto se hacer con la función recv. Tiene como parámetros al descriptor del socket, un búfer donde almacenar los datos recibidos, el tamaño máximo de ese búfer y finalmente opciones para la recepción. Tiene la misma salida que la función send. if ( send (sd, peticion, sizeof (peticion), 0) < 0 ) perror ("No se pudo enviar petición"); Finalmente queda cerrar la conexión, lo que se realiza con la llamada a close usando como parámetro al descriptor de socket. close (sd); 18 De esta forma, se puede formular el siguiente programa para el cliente. #include #include #include #include #include #include #include <sys/socket.h> <sys/types.h> <resolv.h> <arpa/inet.h> <unistd.h> <stdlib.h> <string.h> #define MSG_MAX 32768 int main ( int argc, char **argv ) { int sd; struct sockaddr_in6 destino; char peticion[] = "Aqui cliente IPv6 :-)"; char respuesta[MSG_MAX]; char direccion_destino[INET6_ADDRSTRLEN]; printf ("Prueba sencilla de un cliente IPv6\n"); if ( argc < 3 ) { printf ("Uso: cliente6 <direccion IPv6> <puerto>\n"); exit (EXIT_FAILURE); } printf ("Intentado abrir un socket...\n"); if ( (sd = socket (PF_INET6, SOCK_STREAM, 0)) < 0 ) { perror ("No se pudo crear el socket"); exit (EXIT_FAILURE); } else printf ("Socket %d creado\n", sd); bzero (&destino, sizeof (destino)); destino.sin6_family = AF_INET6; destino.sin6_port = htons (atoi (argv[2])); if ( inet_pton (AF_INET6, argv[1], &destino.sin6_addr) == -1 ) { perror ("Error en inet_pton"); exit (EXIT_FAILURE); } inet_ntop (AF_INET6, &destino.sin6_addr, direccion_destino, INET6_ADDRSTRLEN); printf ("Intentando conectar a [%s]:%d...\n", direccion_destino, ntohs (destino.sin6_port)); if ( connect (sd, (struct sockaddr *) &destino, sizeof (destino)) != 0 ) { perror ("No se pudo conectar al host"); exit (EXIT_FAILURE); } else { inet_ntop (AF_INET6, &destino.sin6_addr, direccion_destino, INET6_ADDRSTRLEN); printf ("Conectado al host [%s]:%d\n", direccion_destino, ntohs (destino.sin6_port)); 19 } printf ("Enviando peticion...\n"); if ( send (sd, peticion, sizeof (peticion), 0) < 0 ) { perror ("No se pudo enviar peticion"); exit (EXIT_FAILURE); } else printf ("Peticion enviada\n"); printf ("Esperando respuesta...\n"); if ( recv (sd, respuesta, MSG_MAX, 0) < 0 ) { perror ("No se obtuvo respuesta"); exit (EXIT_FAILURE); } else printf ("Respuesta recibida:\n%s\n", respuesta); printf ("Cerrando la conexion...\n"); if ( close (sd) ) { perror ("Problemas al cerrar el socket"); exit (EXIT_FAILURE); } else printf ("Socket cerrado\n"); printf ("Saliendo\n"); return EXIT_SUCCESS; } 4.2.2. Servidor TCP6 El servidor tiene una forma distinta de conectarse a la red respecto del cliente. Necesita asociar un puerto al socket y escuchar por él las conexiones que llegarán. Para asociar un puerto con el socket ya iniciado se utiliza la función bind. Ésta recibe el descriptor del socket, la estructura y su tamaño. La estructura se forma con: servidor.sin6_family = AF_INET6; servidor.sin6_addr = in6addr_any; servidor.sin6_port = htons (PUERTO); Aquı́ el valor in6addr any se usa para asociar el socket con cualquier dirección, es decir, escuchar por todas las interfaces. La llamada para asociar el puerto serı́a ası́: if ( bind (sd, (struct sockaddr *) &servidor, sizeof (servidor)) != 0 ) perror ("No se puede asociar puerto"); Las lı́neas anteriores generarı́an un mensaje en caso de error. Luego de asociar el socket con el puerto hay que crear una cola de espera para sockets con el fin de atender varias solicitudes remotas. Esto se consigue con la función listen que necesita el descriptor de socket y el número de espacios para espera. 20 if ( listen (sd, 10) != 0 ) perror ("No se puede escuchar por el puerto"); En el ejemplo anterior se genera una cola de 10 conexiones en caso de éxito, si no, se presenta un mensaje de error. Luego de esto, se está en condiciones de aceptar conexiones remotas. Para hacerlo, se llama a la función accept. Es necesario pasar como parámetros el descriptor de socket, una estructura de socket vacı́a y su tamaño. Esta estructura es llenada con los datos de la conexión entrante y puede ser usada más adelante. sd_tmp = accept (sd, (struct sockaddr *) &destino, &tamano); Si la llamada es exitosa, devuelve un descriptor de socket para usarlo temporalmente y rellena los datos de la estructura. El socket devuelto se usa para comunicarse con el cliente usando las llamadas anteriormente descritas send y recv. Esta interacción puede hacerse en un bucle condicional hasta que el usuario envı́e algún comando tipo QUIT. Finalmente, el código fuente del servidor es el siguiente: #include #include #include #include #include #include #include #include #include #include <sys/socket.h> <sys/types.h> <resolv.h> <netinet/in.h> <arpa/inet.h> <unistd.h> <stdio.h> <stdlib.h> <string.h> <time.h> #define MSG_MAX 32768 #define PUERTO 7777 int main ( int argc, char **argv ) { int sd, sd_tmp, tamano; struct sockaddr_in6 servidor, destino; char recibido[MSG_MAX]; char direccion_destino[INET6_ADDRSTRLEN]; char *respuesta; time_t tiempo; respuesta = calloc (MSG_MAX + 10, sizeof (char)); printf ("Prueba sencilla de un servidor IPv6\n"); printf ("Intentado abrir un socket...\n"); if ( (sd = socket (PF_INET6, SOCK_STREAM, 0)) < 0 ) { perror ("No se pudo crear el socket"); exit (EXIT_FAILURE); } else printf ("Socket %d creado\n", sd); 21 bzero (&servidor, sizeof (servidor)); bzero (&destino, sizeof (destino)); servidor.sin6_family = AF_INET6; servidor.sin6_addr = in6addr_any; servidor.sin6_port = htons (PUERTO); if ( bind (sd, (struct sockaddr *) &servidor, sizeof (servidor)) != 0 ) { perror ("No se puede asociar puerto"); exit (EXIT_FAILURE); } else printf ("Socket asociado al puerto %d\n", PUERTO); if ( listen (sd, 10) != 0 ) { perror ("No se puede escuchar por el puerto"); exit (EXIT_FAILURE); } else printf ("Aceptando conexiones en el puerto %d\n", PUERTO); while ( 1 ) { tamano = sizeof (destino); sd_tmp = accept (sd, (struct sockaddr *) &destino, &tamano); if ( sd_tmp < 0 ) { perror ("Problemas al aceptar conexion\n"); exit (EXIT_FAILURE); } else { inet_ntop (AF_INET6, &destino.sin6_addr, direccion_destino, INET6_ADDRSTRLEN); time (&tiempo); printf ("\n%sConexion desde [%s]:%d\n", ctime (&tiempo), direccion_destino, ntohs (destino.sin6_port)); } bzero (&recibido, sizeof (recibido)); if ( recv (sd_tmp, recibido, MSG_MAX, 0) < 0 ) { perror ("Error al recibir datos del cliente"); exit (EXIT_FAILURE); } snprintf (respuesta, MSG_MAX + 10, "Ud. dijo: %s", recibido); printf ("Mensaje recibido:\n%s\nEnviando respuesta\n", recibido); if ( send (sd_tmp, respuesta, strlen (respuesta), 0) < 0 ) { perror ("No se pudo enviar respuesta"); exit (EXIT_FAILURE); } else printf ("Respuesta enviada\n"); printf ("Cerrando la conexion...\n"); if ( close (sd_tmp) ) { perror ("Problemas al cerrar el socket"); exit (EXIT_FAILURE); 22 } else printf ("Socket cerrado\n"); } free (respuesta); close (sd); return EXIT_SUCCESS; } 4.2.3. Pruebas del cliente y el servidor Si se dispone de dos consolas gráficas, se puede correr el servidor en una y el cliente en otra. El servidor es el primer programa que se ejecuta. Como el servidor usa el puerto 7777 no es necesario tener privilegios de root para ejecutarlo. [pablo@ipv6 pruebas]$ ./servidor6 Prueba sencilla de un servidor IPv6 Intentado abrir un socket... Socket 3 creado Socket asociado al puerto 7777 Aceptando conexiones en el puerto 7777 Si se ejecuta el cliente en la otra consola, se obtiene una salida parecida a ésta: [pablo@ipv6 pruebas]$ ./cliente6 ::1 7777 Prueba sencilla de un cliente IPv6 Intentado abrir un socket... Socket 3 creado Intentando conectar a [::1]:7777... Conectado al host [::1]:7777 Enviando peticion... Peticion enviada Esperando respuesta... Respuesta recibida: Ud. dijo: Aqui cliente IPv6 :-) Cerrando la conexion... Socket cerrado Saliendo El cliente recibe como parámetros la dirección IPv6 y el puerto para realizar la conexión. En el ejemplo anterior se probó con la dirección local ::1 aunque también se podrı́a haber probado con la dirección global que tiene asignado el computador, que para este caso serı́a 3ffe:8070:100c:b06::1:1. Si se observa la consola donde está corriendo el servidor, se verá que quedó registrada una conexión, con una salida parecida a ésta: Wed Jul 24 00:09:14 2002 Conexion desde [::1]:33651 Mensaje recibido: Aqui cliente IPv6 :-) Enviando respuesta 23 Respuesta enviada Cerrando la conexion... Socket cerrado Lo que se ha intentado hasta aquı́ es mostrar un poco la programación de sockets orientada a IPv6. Se espera que con estos dos ejemplos sencillos se halla demostrado que no es difı́cil portar a IPv6 programas que ya están hechos para IPv4. Para mayor información acerca de sockets IPv6 consulte las referencias [10] y [12]. Referencias [1] Peter Bieringer. IPv6-HOWTO. http://www.bieringer.de/linux/IPv6/. [2] Eric Van Buggenhaut. Routing Avanzado con el Núcleo Linux. http://congreso.hispalinux.es/ congreso2001/actividades/ponencias/eric/. [3] S. Deering and R. Hinden. Request for Comments 2460: Internet Protocol, Version 6 (IPv6) Specification. The Internet Society, December 1998. [4] Bert Hubert et al. Linux Advanced Routing and Traffic Control HOWTO. http://www.tldp.org/ HOWTO/Adv-Routing-HOWTO.html. [5] R. Hinden and S. Deering. Request for Comments 2373: IP Version 6 Addressing Architecture. The Internet Society, July 1998. [6] P. Marques and F. Dupont. Request for Comments 2545: Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing. The Internet Society, March 1999. [7] C. Partridge. Request for Comments 1809: Using the Flow Label Field in IPv6, June 1995. [8] Horacio Peña. Creación de una isla IPv6 y conexión al 6bone. http://www.uninet.edu/6fevu/ text/isla6bone.html. [9] Luis Peralta. IPv6 @ UJI, Febrero 2002. http://spisa.act.uji.es/ peralta/ipv6/. [10] J. Bound R. Gilligan, S. Thomson and W. Stevens. Request for Comments 2553: Basic Socket Interface Extensions for IPv6. The Internet Society, March 1999. [11] Y. Rekhter and T. Li. Request for Comments 1771: A Border Gateway Protocol 4 (BGP-4), March 1995. [12] W. Stevens and M. Thomas. Request for Comments 2292: Advanced Sockets API for IPv6. The Internet Society, February 1998. [13] S. Thomson and T. Narten. Request for Comments 1886: DNS Extensions to support IP version 6. The Internet Society, December 1998. [14] S. Thomson and T. Narten. Request for Comments 2462: IPv6 Stateless Address Autoconfiguration. The Internet Society, December 1998. [15] Sean Walton. Programación de Socket Linux. Pearson Educación, 2001. 24