通用 TUN/TAP 裝置驅動程式

版權所有 © 1999-2000 Maxim Krasnyansky <max_mk@yahoo.com>

Linux、Solaris 驅動程式 版權所有 © 1999-2000 Maxim Krasnyansky <max_mk@yahoo.com>

FreeBSD TAP 驅動程式 版權所有 © 1999-2000 Maksim Yevmenkin <m_evmenkin@yahoo.com>

本文件 2002 年修訂版 Florian Thiel <florian.thiel@gmx.net>

1. 描述

TUN/TAP 為使用者空間程式提供資料包接收和傳輸。它可以被看作是一個簡單的點對點或乙太網裝置,它不是從物理介質接收資料包,而是從使用者空間程式接收資料包,並且不是透過物理介質傳送資料包,而是將資料包寫入使用者空間程式。

為了使用該驅動程式,程式必須開啟 /dev/net/tun 併發出相應的 ioctl() 來向核心註冊網路裝置。 網路裝置將顯示為 tunXX 或 tapXX,具體取決於選擇的選項。 當程式關閉檔案描述符時,網路裝置和所有相應的路由將消失。

根據選擇的裝置型別,使用者空間程式必須讀取/寫入 IP 資料包(使用 tun)或乙太網幀(使用 tap)。 具體使用哪種取決於 ioctl() 中給出的標誌。

來自 http://vtun.sourceforge.net/tun 的軟體包包含兩個如何使用 tun 和 tap 裝置的簡單示例。 這兩個程式都像兩個網路介面之間的橋樑。 br_select.c - 基於 select 系統呼叫的橋接。 br_sigio.c - 基於非同步 io 和 SIGIO 訊號的橋接。 然而,最好的例子是 VTun http://vtun.sourceforge.net :))

2. 配置

建立裝置節點

mkdir /dev/net (if it doesn't exist already)
mknod /dev/net/tun c 10 200

設定許可權

e.g. chmod 0666 /dev/net/tun

允許非 root 使用者訪問裝置沒有壞處,因為建立網路裝置或連線到不屬於相關使用者的網路裝置需要 CAP_NET_ADMIN。 如果您想建立持久裝置並將它們的所有權授予非特權使用者,那麼您需要 /dev/net/tun 裝置可供這些使用者使用。

驅動模組自動載入

確保您的核心中啟用了“核心模組載入器” - 模組自動載入支援。 核心應該在第一次訪問時載入它。

手動載入

手動插入模組

modprobe tun

如果您以後者的方式進行操作,則每次需要時都必須載入模組,如果您以前者的方式進行操作,則在開啟 /dev/net/tun 時會自動載入該模組。

3. 程式介面

3.1 網路裝置分配

char *dev 應該是具有格式字串的裝置名稱(例如“tun%d”),但(就我所見)這可以是任何有效的網路裝置名稱。 請注意,字元指標會被實際裝置名稱覆蓋(例如“tun0”)

#include <linux/if.h>
#include <linux/if_tun.h>

int tun_alloc(char *dev)
{
    struct ifreq ifr;
    int fd, err;

    if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )
       return tun_alloc_old(dev);

    memset(&ifr, 0, sizeof(ifr));

    /* Flags: IFF_TUN   - TUN device (no Ethernet headers)
     *        IFF_TAP   - TAP device
     *
     *        IFF_NO_PI - Do not provide packet information
     */
    ifr.ifr_flags = IFF_TUN;
    if( *dev )
       strscpy_pad(ifr.ifr_name, dev, IFNAMSIZ);

    if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
       close(fd);
       return err;
    }
    strcpy(dev, ifr.ifr_name);
    return fd;
}

3.2 幀格式

如果未設定標誌 IFF_NO_PI,則每個幀格式為

Flags [2 bytes]
Proto [2 bytes]
Raw protocol(IP, IPv6, etc) frame.

3.3 多佇列 tuntap 介面

從 3.8 版本開始,Linux 支援多佇列 tuntap,它可以使用多個檔案描述符(佇列)來並行傳送或接收資料包。 裝置分配與之前相同,如果使用者想要建立多個佇列,則必須多次呼叫帶有 IFF_MULTI_QUEUE 標誌的 TUNSETIFF,並使用相同的裝置名稱。

char *dev 應該是裝置的名稱,queues 是要建立的佇列數,fds 用於儲存和返回建立給呼叫者的檔案描述符(佇列)。 每個檔案描述符都用作佇列的介面,使用者空間可以透過該介面訪問。

#include <linux/if.h>
#include <linux/if_tun.h>

int tun_alloc_mq(char *dev, int queues, int *fds)
{
    struct ifreq ifr;
    int fd, err, i;

    if (!dev)
        return -1;

    memset(&ifr, 0, sizeof(ifr));
    /* Flags: IFF_TUN   - TUN device (no Ethernet headers)
     *        IFF_TAP   - TAP device
     *
     *        IFF_NO_PI - Do not provide packet information
     *        IFF_MULTI_QUEUE - Create a queue of multiqueue device
     */
    ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_MULTI_QUEUE;
    strcpy(ifr.ifr_name, dev);

    for (i = 0; i < queues; i++) {
        if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
           goto err;
        err = ioctl(fd, TUNSETIFF, (void *)&ifr);
        if (err) {
           close(fd);
           goto err;
        }
        fds[i] = fd;
    }

    return 0;
err:
    for (--i; i >= 0; i--)
        close(fds[i]);
    return err;
}

引入了一個新的 ioctl(TUNSETQUEUE) 來啟用或停用佇列。 使用 IFF_DETACH_QUEUE 標誌呼叫它時,佇列將被停用。 使用 IFF_ATTACH_QUEUE 標誌呼叫它時,佇列將被啟用。 透過 TUNSETIFF 建立佇列後,預設情況下會啟用佇列。

fd 是我們想要啟用或停用的檔案描述符(佇列),當 enable 為 true 時,我們啟用它,否則我們停用它

#include <linux/if.h>
#include <linux/if_tun.h>

int tun_set_queue(int fd, int enable)
{
    struct ifreq ifr;

    memset(&ifr, 0, sizeof(ifr));

    if (enable)
       ifr.ifr_flags = IFF_ATTACH_QUEUE;
    else
       ifr.ifr_flags = IFF_DETACH_QUEUE;

    return ioctl(fd, TUNSETQUEUE, (void *)&ifr);
}

通用 TUN/TAP 裝置驅動程式 常見問題解答

  1. TUN/TAP 驅動程式支援哪些平臺?

目前驅動程式已為 3 個 Unix 編寫

  • Linux 核心 2.2.x、2.4.x

  • FreeBSD 3.x、4.x、5.x

  • Solaris 2.6、7.0、8.0

  1. TUN/TAP 驅動程式用於什麼?

如上所述,TUN/TAP 驅動程式的主要目的是隧道。 VTun 使用它 (http://vtun.sourceforge.net)。

使用 TUN/TAP 的另一個有趣的應用程式是 pipsecd (http://perso.enst.fr/~beyssac/pipsec/),這是一個使用者空間 IPSec 實現,可以使用完整的核心路由(與 FreeS/WAN 不同)。

  1. 虛擬網路裝置實際上是如何工作的?

虛擬網路裝置可以被視為一個簡單的點對點或乙太網裝置,它不是從物理介質接收資料包,而是從使用者空間程式接收資料包,並且不是透過物理介質傳送資料包,而是將資料包傳送到使用者空間程式。

假設您在 tap0 上配置了 IPv6,那麼每當核心向 tap0 傳送 IPv6 資料包時,它都會傳遞給應用程式(例如 VTun)。 該應用程式加密、壓縮並透過 TCP 或 UDP 將其傳送到另一端。 另一端的應用程式解壓縮和解密接收到的資料,並將資料包寫入 TAP 裝置,核心處理該資料包,就像它來自真正的物理裝置一樣。

  1. TUN 驅動程式和 TAP 驅動程式有什麼區別?

TUN 使用 IP 幀。 TAP 使用乙太網幀。

這意味著使用 tun 時必須讀取/寫入 IP 資料包,使用 tap 時必須讀取/寫入乙太網幀。

  1. BPF 和 TUN/TAP 驅動程式有什麼區別?

BPF 是一個高階資料包過濾器。 它可以附加到現有的網路介面。 它不提供虛擬網路介面。 TUN/TAP 驅動程式確實提供了虛擬網路介面,並且可以將 BPF 附加到此介面。

  1. TAP 驅動程式是否支援核心乙太網橋接?

是的。 Linux 和 FreeBSD 驅動程式支援乙太網橋接。