2009-06-16 61 views
13

我很難找出這個問題 - 我試圖編寫一個程序,它將與Linux隧道驅動程序交互。在一個非常基礎的層面上,我只是想創建一個能夠通過網絡隧道傳輸數據的應用程序。但是,我完全不知道如何正確設置隧道驅動程序來完成這一任務。如何與Linux tun驅動程序接口

我在Ubuntu 9.04上開發,我加載了隧道驅動程序內核模塊。

存在着設備/dev/net/tun,但是沒有/dev/tunX設備。我無法用ifconfig創建這些設備 - 每當我跑/sbin/ifconfig tun0 up,例如,我得到以下錯誤:

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

如果我嘗試看看/dev/net/tun裝置,提出了以下錯誤:

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

試圖通過一個小程序打開/dev/tunX,基本上,一個簡單的

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

換貨政... rns -1:應用程序以root身份運行,但仍無法打開此隧道設備。可以打開/dev/net/tun,但這似乎不會生成新的/dev/tunX設備來代替。

因此,簡言之 - 一個人如何去寫希望使用Linux的隧道司機的應用程序?任何見解將不勝感激。

謝謝; 〜羅伯特

回答

13

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

你都應該open/dev/net/tun設備。後續的ioctl在打開的fd將創建tun0(或任何你想命名它)網絡接口。 Linux的網絡接口不對應任何/dev/*設備。

+0

@rmrobins;你做了什麼才能真正做到這一點?我相信我有一個和你原來的問題非常相似的問題。我有/ dev/net/tun設備可見,但是打開它不會產生網絡接口。我一直在嘗試使用br_select.c和br_sigio.c示例。 – simon 2009-11-16 15:40:18

+0

如上所述,打開/ dev/net/tun。然後,一個ioctl將被用來創建實際的接口本身。 ioctl被稱爲TUNSETIFF,參數的類型爲struct ifreq。 ifreq結構的標誌應該設置爲IFF_TUN。一旦ioctl返回,ifreq結構的ifr_name字段將被設置爲打開的接口的名稱。希望這可以幫助! – rmrobins 2009-11-24 06:45:28

10

沒有/dev/tunX設備文件。相反,您打開/dev/net/tun,並通過ioctl()將其配置爲「指向」tun0。爲了顯示基本過程,我將使用命令行工具ip tun tap創建TUN界面,然後顯示從該TUN設備讀取的C代碼。因此,通過命令行創建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 

現在我們創建了tun0。要從用戶空間程序讀取/寫入此接口的數據包,您需要使用ioctl()/dev/net/tun設備文件進行交互。這裏是一個例子,它將讀取到達tun0接口的數據包並打印出大小:

#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; 
}