`
haoningabc
  • 浏览: 1444556 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

建立tap设备的c的代码

 
阅读更多
tapper.c

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <err.h>
#include <arpa/inet.h> /* inet_addr() & co. */
#include <netinet/in.h> /* INET_ADDRSTRLEN */
/* for uint16_t */
#include <stdint.h>
#define ERR_CANT_TAP 1
#define ERR_OPEN_ERR 2
#define ERR_READ_ERR 3
#define ERR_WRITE_ERR 4
static int primary_fd; /* a copy of the filedescriptor for tap device */
static int enable_tuntap_headers = 0; /* CLI option - will we permit tuntap protocol headers */
static int enable_tapper_headers = 0; /* CLI option - will we enable tapper's headers */
static int enable_verbose = 0; /* CLI option - print out extra debug info on stderr */
//static const char DEFAULT_IP[] = "10.0.2.2";
static const char DEFAULT_IP[] = "10.0.2.1";
static const char DEFAULT_NETMASK[] = "255.255.0.0";
#define VERBOSE(x, ...) if(enable_verbose >= 1) { warnx("NOTE: " x, ##__VA_ARGS__); }
#define DEBUG(x, ...) if(enable_verbose >= 2) { warnx("DEBUG: " x, ##__VA_ARGS__); }
/* following function creates a tap device */
/* it also returns device name in 'newdev' */
int createTap(char *newdev, int bufferlen)
{
    struct ifreq ifr;
    int fd=open("/dev/net/tun", O_RDWR); /* open the tap device */
    if(fd<0) /* handle error */
        err(ERR_CANT_TAP, "Could not create a TAP device");
    memset(&ifr, 0, sizeof(ifr)); /* initialize the structure specifying data about net device */
    ifr.ifr_flags=IFF_TAP; /* we want a tap device, not a tun device */
    if(!enable_tuntap_headers)
        /* by default we won't include tuntap driver's headers */
        ifr.ifr_flags|=IFF_NO_PI;
    if((ioctl(fd, TUNSETIFF, (void*)&ifr))<0) /* tell our device what we want it to do */
    {
        close(fd); /* if we failed close and abort */
        err(ERR_CANT_TAP, "Could not create a TAP device because of ioctl()");
    }
    strncpy(newdev, ifr.ifr_name, bufferlen-1); /* return the generated device name */
    newdev[bufferlen-1] = '\0';
    return fd;
}
/* when we exit we want to clean up */
void atex(void)
{
    close(primary_fd); /* close the tap network device */
}
/* usage */
void usage(void)
{
    printf("usage:\n"
                   "\n"
                   "  ./tapper [--tuntap-headers] [--tapper-headers]"
                   "           [--ip-address %s] [--netmask %s] [--randomize-ip]"
                   "           [-v] [stdinfile stdoutfile]\n"
                   "\n",
           DEFAULT_IP, DEFAULT_NETMASK);
    exit(0);
}
int main(int argc, char ** argv)
{
#define BUFFERSIZE 2000 /* must be larger than MTU - 1500 */
#define DEVNAMESIZE 25
    int fd; /* file descriptor of the tap device; shorthand for primary_fd */
    char devname[DEVNAMESIZE]={0}; /* initialize device name (where we'll pick up the generated dev name)
                to zeros so it doesn't look like we're sending a device name in*/
    char buf[BUFFERSIZE]; /* buffer for receiving stuff */
    in_addr_t ip = inet_addr(DEFAULT_IP);
    in_addr_t netmask = inet_addr(DEFAULT_NETMASK);
    char ip_s[INET_ADDRSTRLEN];
    char netmask_s[INET_ADDRSTRLEN];
    int argoff; /* argument offset; used for parsing CLI */
    for(argoff = 1; argoff < argc; argoff++)
    {
        if(!strcmp(argv[argoff], "-h"))
            usage();
        else if(!strcmp(argv[argoff], "--tuntap-headers"))
            enable_tuntap_headers = 1;
        else if(!strcmp(argv[argoff], "--tapper-headers"))
            enable_tapper_headers = 1;
        else if(!strcmp(argv[argoff], "-v"))
            enable_verbose++;
        else if(!strcmp(argv[argoff], "--ip-address")){
            if(argoff == argc-1)
                usage();
            ip = inet_addr(argv[++argoff]);
            if(ip == INADDR_NONE)
                errx(12, "%s: malformed ip address", argv[argoff]);
            DEBUG("ip address: %s", inet_ntoa(*(struct in_addr*)&ip));
        }else if(!strcmp(argv[argoff], "--netmask")){
            if(argoff == argc-1)
                usage();
            netmask = inet_addr(argv[++argoff]);
            if(netmask == INADDR_NONE)
                errx(13, "%s: malformed netmask address", argv[argoff]);
            DEBUG("netmask: %s", inet_ntoa(*(struct in_addr*)&netmask));
        }else if(!strcmp(argv[argoff], "--randomize-ip")){
            srand(time(NULL)+devname[3]); /* we want our ip address to depend on time, and on last
                             symbol in device name. dev name is always a three-letter 'tap'
                             + number, and let's just presume it's a single digit num */
            uint32_t *ip_int = (uint32_t*)&ip;
            uint32_t *netmask_int = (uint32_t*)&netmask;
            uint32_t local = (uint32_t)rand() & ~*netmask_int;
            if(local == 0)
                local = 1;
            *ip_int |= local;
            DEBUG("randomized ip address: %s", inet_ntoa(*(struct in_addr*)&ip));
        }
        else
            break;
    }
    VERBOSE("verbosity: %d", enable_verbose);
    if(enable_tuntap_headers) VERBOSE("permitting tuntap headers");
    if(enable_tapper_headers) VERBOSE("using tapper headers");
    if(argc - argoff >= 2)
    {
        /* we can receive two arguments:
           - file we'll use for reading in place of stdin
           - file we'll use for writing in place of stdout */
        close(0);
        close(1);
        VERBOSE("using %s for input and %s for output", argv[argoff], argv[argoff+1]);
        if(!fopen(argv[argoff], "r"))
            err(10, "fopen(%s, r)", argv[argoff]);
        if(!fopen(argv[argoff+1], "w"))
            err(11, "fopen(%s, w)", argv[argoff+1]);
    }
    /* get ip address and netmask as strings */
    inet_ntop(AF_INET, &ip, ip_s, INET_ADDRSTRLEN);
    inet_ntop(AF_INET, &netmask, netmask_s, INET_ADDRSTRLEN);
    ip_s[INET_ADDRSTRLEN-1] = '\0';
    netmask_s[INET_ADDRSTRLEN-1] = '\0';
    /* let's create a tap device */
    primary_fd=createTap(devname, DEVNAMESIZE);
    /* configure ip address and netmask */
    snprintf(buf, sizeof(buf), "ifconfig %s inet %s netmask %s up", devname,
             ip_s, netmask_s);
    VERBOSE("configuring ip and netmask: %s", buf);
    system(buf);
    fd=primary_fd; /* store primary_fd into a shorthand */
    if (fd<0) /* error with creating tap? tough luck, let's bail out */
        err(ERR_OPEN_ERR, "open()");
    atexit(atex); /* when the loop is aborted, cleanup */
    while(1){
        int readies, i;
        /*
        since we're trying to create a twoway tunnel between stdio and the tap device
        we need to do monitoring via select(). we simply don't know which one will
        send us data first.
        */
        fd_set fds;
        FD_ZERO(&fds); /* init set of file descriptors */
        FD_SET(fd,&fds); /* add tap device to set */
        FD_SET(0,&fds); /* add stdin to set */

        readies=select(fd+1, &fds, NULL, NULL, NULL); /* monitor the set. the first param is
                            max fd we monitor +1 (as usual with select()).
                            here that's fd. */
        if(readies<=0) err(readies, "Not ready"); /* we passed a timeoutless select() with 0
                            active fds? ouch. */
        for(i=0;i<2;i++){
            /* some arcane magic to make the loop simple. i was lazy to cut paste code.
            basically first the fd_int is stdin (0) and fd_oth is our tap device (fd).
            then the fd_int is tap device (fd) and fd_oth is the stdout (1). */
            int fd_int=i*fd;
            int fd_oth=abs(fd-i*fd);
            if(!fd_oth) fd_oth=1;

            /* is the currently monitored fd_int (first stdin, then tap) actually
               the one causing select() to unblock? */
            if(FD_ISSET(fd_int, &fds)){
                if(!enable_tapper_headers || fd_int != 0){
                    /* yay! that one has something to say. let's read as much as
                       possible for our buffer. num of actually read bytes is
                       stored in ret, unless it's -1 which is error */
                    ssize_t ret = read(fd_int, buf, BUFFERSIZE);
                    if (!ret)
                    {
                        errx(100, "read(): nothing to read expecting data");
                        continue;
                    }
                    if (ret < 0) err(ERR_READ_ERR, "read(%d) for data", fd_int);
                    /* using headers? then the fd_oth is the stdout. first,
                       send the number of bytes we'll dispatch */
                    if(enable_tapper_headers){
                        uint16_t size = (uint16_t)htons(ret);

                        /* copying because we want to do one write, not two */
                        char * with_headers = malloc(sizeof(size) + ret);
                        memcpy(with_headers, &size, sizeof(size));
                        memcpy(with_headers + sizeof(size), buf, ret);
                        if(write(fd_oth, with_headers, sizeof(size) + ret)<0)
                            err(ERR_WRITE_ERR, "write(%d)", fd_oth);
                        DEBUG("wrote %lu bytes", sizeof(size) + ret);
                        free(with_headers);
                    }else{
                        /* write ret bytes into fd_oth; that's all the bytes we read */
                        if(write(fd_oth, buf, ret)<0)
                            err(ERR_WRITE_ERR, "write(%d)", fd_oth);
                    }
                }else{
                    /* new codepath: buffer stdin until filled with enough data */
                    /* only executed for stdin, and if tapper headers are enabled */
                    static uint16_t expected_size = 0;
                    static size_t current_buffer_content_size = 0;
                    if(!expected_size){
                        ssize_t ret = read(fd_int, &expected_size, sizeof(uint16_t));
                        if(!ret)
                        {
                            errx(101, "read(): nothing to read expecting message size");
                            continue;
                        }
                        if (ret < 0) err(ERR_READ_ERR, "read(%d) for message size", fd_int);

                        expected_size = ntohs(expected_size);
                        DEBUG("now expecting %d bytes", expected_size);
                    }else{
                        size_t bytes_left = expected_size - current_buffer_content_size;
                        ssize_t ret = read(fd_int, buf + current_buffer_content_size, bytes_left);
                        if(!ret){
                            errx(102, "read(): nothing to read expecting buffer content");
                            continue;
                        }
                        if (ret < 0) err(ERR_READ_ERR, "read(%d) for buffer content", fd_int);
                        current_buffer_content_size += ret;
                        DEBUG("received %lu bytes; buffer now %lu/%hu", ret, current_buffer_content_size, expected_size);
                        if(current_buffer_content_size == expected_size){
                            DEBUG("got all content");
                            /* write ret bytes into fd_oth; that's all the bytes we read */
                            if(write(fd_oth, buf, ret)<0)
                                err(ERR_WRITE_ERR, "write(%d)", fd_oth);
                            current_buffer_content_size = 0;
                            expected_size = 0;
                        }
                    }
                }
            }
        }
    }
    /* never happens */
    return 0;
}
分享到:
评论

相关推荐

    c# 基于任务的异步编程模式(TAP)

    异步编程是C#5.0的一个重要改进,...编译器最终会用Task类创建代码。 1、创建任务 建立一个同步方法Greeting,该方法在等待一段时间后,返回一个字符串。 private string Greeting(int delay, string name) { Sys

    Verilog SOPC高级实验教程 -夏宇闻-带书签完美清晰版PDF_2/4

    为了使阐述的内容更加具体,本教程中的每个实验均选用Altera FPGA (型号为Cyclone Ⅱ EP2C35F672C8)实现,并在革新科技公司专业级实验平台GXSOC/SOPC运行通过。 本书可作为电子信息、自动控制、计算机工程类大学...

    matlab的egde源代码-jenkins-matlab-plugin:该插件使您可以在Jenkins:trade_mark:构建中运行MATLAB:registered:和Simul

    用于MATLAB:registered:的Jenkins:trade_mark:插件使您能够运行MATLAB和Simulink:registered:测试并生成工件,例如PDF测试报告,JUnit和TAP测试结果以及Cobertura代码或模型覆盖率报告。 您也可以使用该插件导出...

    woke::raised_fist:在源代码中检测非包容性语言

    我保持醒着状态-Erykah Badu建立包容性的工作环境对于健康,支持和富有生产力的文化以及每个人都感到受欢迎和包容的环境势在必行。 woke是一个文本文件分析工具,可以在源代码中查找包含非包容性语言的位置,并建议...

    圆顶:一种轻量级的游戏开发环境,可以在其中用Wren编写游戏

    DOME-面向设计的极简... &gt; brew tap domeengine/tap &gt; brew install dome 建立 最后,如果您想自己构建DOME,进行修改或其他原因,请遵循以下说明。 确保首先在系统上安装了共享的SDL2库,然后进行构建,运行: &gt; m

    Verilog SOPC高级实验教程 -夏宇闻-带书签完美清晰版PDF_4/4

    为了使阐述的内容更加具体,本教程中的每个实验均选用Altera FPGA (型号为Cyclone Ⅱ EP2C35F672C8)实现,并在革新科技公司专业级实验平台GXSOC/SOPC运行通过。 本书可作为电子信息、自动控制、计算机工程类大学...

    Verilog SOPC高级实验教程 -夏宇闻-带书签完美清晰版PDF_3/4

    为了使阐述的内容更加具体,本教程中的每个实验均选用Altera FPGA (型号为Cyclone Ⅱ EP2C35F672C8)实现,并在革新科技公司专业级实验平台GXSOC/SOPC运行通过。 本书可作为电子信息、自动控制、计算机工程类大学...

    Verilog SOPC高级实验教程 -夏宇闻-带书签完美清晰版PDF_1/4

    为了使阐述的内容更加具体,本教程中的每个实验均选用Altera FPGA (型号为Cyclone Ⅱ EP2C35F672C8)实现,并在革新科技公司专业级实验平台GXSOC/SOPC运行通过。 本书可作为电子信息、自动控制、计算机工程类大学...

    TCP-IP详解卷2:实现.part1

    书中给出了约500个图例,15 000行实际操作的C代码,采用举例教学的方法帮助你掌握TCP/IP实现。本书不仅说明了插口API和协议族的关系以及主机实现与路由器实现的差别。还介绍了4.4BSD-Lite版的新的特点,如多播、长肥...

    TCP-IP详解卷2:实现.part2

    书中给出了约500个图例,15 000行实际操作的C代码,采用举例教学的方法帮助你掌握TCP/IP实现。本书不仅说明了插口API和协议族的关系以及主机实现与路由器实现的差别。还介绍了4.4BSD-Lite版的新的特点,如多播、长肥...

    本资源分为两个压缩包,请注意:TCP-IP详解卷2:实现(2)

    书中给出了约500个图例,15 000行实际操作的C代码,采用举例教学的方法帮助你掌握TCP/IP实现。本书不仅说明了插口API和协议族的关系以及主机实现与路由器实现的差别。还介绍了4.4BSD-Lite版的新的特点,如多播、长肥...

    TCP_IP详解卷1

    该文件共分12个压缩包,必须下载到同一个文件夹后解压才可以用哦~~ 简介: 《TCP/IP详解,卷1:协议》是一本完整而详细的...附录C sock程序 378 附录D 部分习题的解答 381 附录E 配置选项 395 附录F 可以免费获得...

    adb1.0.26包含fastboot.exe

    adb 的运行原理是 PC 端的 adb server 与手机端的守护进程 adbd 建立连接,然后 PC 端的 adb client 通过 adb server 转发命令,adbd 接收命令后解析运行。 所以如果 adbd 以普通权限执行,有些需要 root 权限才能...

    TCP-IP详解卷二:实现part2

    1.2 源代码表示 1 1.2.1 将拥塞窗口设置为1 1 1.2.2 印刷约定 2 1.3 历史 2 1.4 应用编程接口 3 1.5 程序示例 4 1.6 系统调用和库函数 6 1.7 网络实现概述 6 1.8 描述符 7 1.9 mbuf与输出处理 11 1.9.1 包含插口地址...

    TCP-IP详解卷2:实现.rar

    1.2 源代码表示 1 1.2.1 将拥塞窗口设置为1 1 1.2.2 印刷约定 2 1.3 历史 2 1.4 应用编程接口 3 1.5 程序示例 4 1.6 系统调用和库函数 6 1.7 网络实现概述 6 1.8 描述符 7 1.9 mbuf与输出处理 11 1.9.1 包含插口地址...

    TCP-IP详解-卷2实现分两部分-part2

    1.2 源代码表示 1 1.2.1 将拥塞窗口设置为1 1 1.2.2 印刷约定 2 1.3 历史 2 1.4 应用编程接口 3 1.5 程序示例 4 1.6 系统调用和库函数 6 1.7 网络实现概述 6 1.8 描述符 7 1.9 mbuf与输出处理 11 1.9.1 包含插口地址...

    TCP-IP详解卷2_1.rar

    1.2 源代码表示 1 1.2.1 将拥塞窗口设置为1 1 1.2.2 印刷约定 2 1.3 历史 2 1.4 应用编程接口 3 1.5 程序示例 4 1.6 系统调用和库函数 6 1.7 网络实现概述 6 1.8 描述符 7 1.9 mbuf与输出处理 11 1.9.1 包含插口地址...

    TCP-IP详解卷2:实现——2

    1.2 源代码表示 1 1.2.1 将拥塞窗口设置为1 1 1.2.2 印刷约定 2 1.3 历史 2 1.4 应用编程接口 3 1.5 程序示例 4 1.6 系统调用和库函数 6 1.7 网络实现概述 6 1.8 描述符 7 1.9 mbuf与输出处理 11 1.9.1 包含插口地址...

    TCP-IP详解卷2

    1.2 源代码表示 1 1.2.1 将拥塞窗口设置为1 1 1.2.2 印刷约定 2 1.3 历史 2 1.4 应用编程接口 3 1.5 程序示例 4 1.6 系统调用和库函数 6 1.7 网络实现概述 6 1.8 描述符 7 1.9 mbuf与输出处理 11 1.9.1 包含插口地址...

Global site tag (gtag.js) - Google Analytics