blog.tomoyat.dev

TUN/TAPのメモ

2023-06-17

TUN/TAPについて勉強したのでそれのメモ

tun/tapは仮想的なnetworkスタックでEthernet framesやip packetsをプログラムから扱うことができる。

dockerを使う場合はrunする場合に--privilegedをつけないと動かない。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_tun.h>

int main() {

    char dev_name[IFNAMSIZ] = "test_device";

    struct ifreq ifr;
    int fd;

    if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
        perror("Opening /dev/net/tun");
        exit(1);
    }

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

    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;

    strncpy(ifr.ifr_name, dev_name, IFNAMSIZ);

    if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
        perror("ioctl(TUNSETIFF)");
        exit(1);
    }


    printf("Successfully allocated interface %s\n", dev_name);
    char buffer[BUFSIZ];
    while (1) {
        int nread = read(fd, buffer, BUFSIZ);
        if (nread < 0) {
            perror("reading from interface");
            close(fd);
            exit(1);
        }

        printf("Read %d bytes from interface %s \n", nread, buffer);

        for (int i = 0; i < nread; i++) {
            printf("%02X ", (unsigned char)buffer[i]);
        }
        printf("\n");
    }
}

上記のプログラムを実行するとネットワークインタフェースができている。

$ ip link show  | grep test_device
4: test_device: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000

状態がdownなので、コマンドでネットワークインターフェースを起こす。

$ ip link set test_device up

これで使えるようになった。pingでこのデバイスにパケットを送るためにルーティングテーブルを設定する。

$ ip addr add 10.0.0.1/24 dev test_device

これで10.0.0.2とかにpingするとさっきのプログラムの出力にきたEthernetのframeが流れる。多分ARPのリクエスト。だけど、10.0.0.1に送るとカーネルが処理をしてしまうので、ネットマスクの範囲のルーティングされるアドレスに送る必要がある。

参考になった記事: https://backreference.org/2010/03/26/tuntap-interface-tutorial/index.html