2009-06-16 14 views
13

Me está costando resolver este problema, estoy intentando escribir un programa que interactúe con el controlador de túnel de Linux. En un nivel muy básico, simplemente quiero crear una aplicación que pueda transferir datos a través de un túnel de red. Sin embargo, estoy completamente perdido en cómo configurar correctamente el controlador del túnel para lograr esto.Cómo hacer interfaz con el controlador tun de Linux

Estoy desarrollando en Ubuntu 9.04, y tengo el módulo del kernel del controlador del túnel cargado.

Existe el dispositivo /dev/net/tun, sin embargo, no hay dispositivos /dev/tunX. Soy incapaz de crear estos dispositivos usando ifconfig - cada vez que corro /sbin/ifconfig tun0 up, por ejemplo, me sale el siguiente error:

tun0: ERROR while getting interface flags: No such device.

Si intento mirar el dispositivo /dev/net/tun, se presenta el siguiente error:

cat: /dev/net/tun: File descriptor in bad state.

al intentar abrir /dev/tunX a través de un pequeño programa, básicamente, un simple

tun_fd = open("/dev/tun0", O_RDWR) 

retu rns -1: la aplicación se está ejecutando como raíz y todavía no puede abrir este dispositivo de túnel. Es posible abrir /dev/net/tun, sin embargo, esto no parece generar un nuevo dispositivo /dev/tunX para usar en su lugar.

Así que, en resumen, ¿cómo se hace para escribir una aplicación que desea utilizar el controlador de túnel de Linux? Cualquier idea sería muy apreciada.

Gracias; ~ Robert

Respuesta

13

Lee /usr/src/linux/Documentation/networking/tuntap.txt.

Se supone que usted debe open el dispositivo /dev/net/tun. Un ioctl posterior en el fd abierto creará la interfaz de red tun0 (o como quieras). Las interfaces de red de Linux no se corresponden con ningún dispositivo /dev/*.

+0

@rmrobins; ¿Qué hiciste para que realmente funcionara? Creo que tengo un problema muy similar a tu pregunta original. Tengo el dispositivo/dev/net/tun visible, pero al abrir esto no aparece una interfaz de red. He estado tratando de usar los ejemplos br_select.c y br_sigio.c. – simon

+0

Como se mencionó anteriormente, abra/dev/net/tun. Luego, se usará un ioctl para crear la interfaz real. El ioctl se llama TUNSETIFF, y el argumento es de tipo struct ifreq. Los indicadores de la estructura ifreq deben establecerse en IFF_TUN. Una vez que el ioctl ha regresado, el campo ifr_name de la estructura ifreq se establecerá con el nombre de la interfaz abierta. ¡Espero que esto ayude! – rmrobins

0
+2

He pasado mucho tiempo mirando estos ejemplos, ¡pero en realidad no funcionan! Intentan abrir directamente los dispositivos/dev/tunX, lo cual es incorrecto (como se muestra en el enlace provisto por ephemient). Esto realmente causó mucha confusión. – rmrobins

10

No hay archivos de dispositivo /dev/tunX. En su lugar, abre el /dev/net/tun y lo configura mediante ioctl() para "apuntar" al tun0. Para mostrar el procedimiento básico, crearé la interfaz TUN usando la herramienta de línea de comando ip tun tap y luego mostraré el código C para leer desde ese dispositivo TUN. Así que para crear la interfaz de línea de comandos a través de tun:

sudo ip tuntap add mode tun dev tun0 
ip addr add 10.0.0.0/24 dev tun0 # give it an ip 
ip link set dev tun0 up # bring the if up 
ip route get 10.0.0.2 # check that packets to 10.0.0.x are going through tun0 
ping 10.0.0.2 # leave this running in another shell to be able to see the effect of the next example 

Ahora hemos creado tun0.Para leer/escribir paquetes en esta interfaz desde un programa de espacio de usuario, necesita interactuar con el archivo de dispositivo /dev/net/tun usando ioctl(). Aquí hay un ejemplo que leerá los paquetes que lleguen a la interfaz tun0 e imprimir el tamaño:

#include <fcntl.h> /* O_RDWR */ 
#include <string.h> /* memset(), memcpy() */ 
#include <stdio.h> /* perror(), printf(), fprintf() */ 
#include <stdlib.h> /* exit(), malloc(), free() */ 
#include <sys/ioctl.h> /* ioctl() */ 

/* includes for struct ifreq, etc */ 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <linux/if.h> 
#include <linux/if_tun.h> 

int tun_open(char *devname) 
{ 
    struct ifreq ifr; 
    int fd, err; 

    if ((fd = open("/dev/net/tun", O_RDWR)) == -1) { 
     perror("open /dev/net/tun");exit(1); 
    } 
    memset(&ifr, 0, sizeof(ifr)); 
    ifr.ifr_flags = IFF_TUN; 
    strncpy(ifr.ifr_name, devname, IFNAMSIZ); // devname = "tun0" or "tun1", etc 

    /* ioctl will use ifr.if_name as the name of TUN 
    * interface to open: "tun0", etc. */ 
    if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) == -1) { 
    perror("ioctl TUNSETIFF");close(fd);exit(1); 
    } 

    /* After the ioctl call the fd is "connected" to tun device specified 
    * by devname ("tun0", "tun1", etc)*/ 

    return fd; 
} 


int main(int argc, char *argv[]) 
{ 
    int fd, nbytes; 
    char buf[1600]; 

    fd = tun_open("tun0"); /* devname = ifr.if_name = "tun0" */ 
    printf("Device tun0 opened\n"); 
    while(1) { 
    nbytes = read(fd, buf, sizeof(buf)); 
    printf("Read %d bytes from tun0\n", nbytes); 
    } 
    return 0; 
} 
Cuestiones relacionadas