`
haoningabc
  • 浏览: 1481845 次
  • 性别: 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;
}
分享到:
评论

相关推荐

    TAP

    3. **持续集成(CI)**:在持续集成服务器如Jenkins、Travis CI或CircleCI中,TAP格式的测试报告可以被轻松地解析和展示,使得团队成员能够快速了解测试状态。 4. **第三方库**:如Jython(Python的Java实现)和...

    FT2232C JTAG函数库 C

    FT2232C JTAG函数库是针对FT2232C芯片设计的一个用于进行JTAG(Joint Test Action Group)通信的C语言程序库。FT2232C是一款多协议USB到串行接口集成电路,它支持多种不同的通信协议,如UART、SPI、I²C、JTAG等。这...

    TAPA:ELEC 4700中用于PA 6的回购

    在ELEC 4700这门课程中,学生可能被要求研究和应用TAPA技术,特别是在PA 6的设计上下文中。 标题中的“TAPA:ELEC 4700中用于PA 6的回购”可能指的是一个项目或课程作业,其中学生需要分析或重新设计PA 6,利用TAPA...

    iphone开发基础教程(源代码)

    《iPhone开发基础教程》是一本面向初学者的iOS开发...总之,《iPhone开发基础教程》的源代码涵盖了iOS开发的多个重要方面,通过学习和实践这些代码,初学者能够逐步建立起扎实的iOS开发基础,从而迈向专业开发者之路。

    在Windows系统中建立基于Linux的嵌入式开发平台.pdf

    嵌入式开发是现代电子设备设计的核心部分,尤其是在物联网和智能设备领域。由于大多数开发者习惯于Windows操作系统,并且Windows提供了丰富的开发工具,因此在Windows环境下建立Linux嵌入式开发平台具有显著的优势。...

    Controle Fuzzy p/ tap de Transformadores-开源

    C代码部分通常用于实现模糊控制器的实时运行,与电力系统硬件设备交互,调整变压器的分接开关,以达到期望的电压调节效果。而Matlab部分则用于设计和测试模糊控制算法,通过仿真验证控制策略的性能,便于快速迭代和...

    No Cortex-M Device found in JTAG chain.的解决

    错误的连接可能导致JTAG链路无法建立,从而无法识别到Cortex-M设备。 2. **BOOT引脚配置**:STM32的BOOT引脚用于设置启动模式,当BOOT1和BOOT0处于特定状态时,会进入不同的启动模式。在某些情况下,如果BOOT1被拉...

    NFC流程概要

    - **建立蓝牙连接**:接收端设备通过NFC与发送端建立蓝牙连接。 - **数据接收**:接收端设备通过蓝牙接收发送端设备传输过来的大数据。 #### 结论 本文总结了NFC的基本概念、硬件结构、Android系统中的总体框架...

    C#连接安卓手机安装软件和发送信息

    接下来,通过以下C#代码片段创建一个进程来检查设备或模拟器是否已连接: ```csharp ProcessStartInfo startInfo = new ProcessStartInfo("adb", "devices"); startInfo.CreateNoWindow = true; startInfo....

    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是一个文本文件分析工具,可以在源代码中查找包含非包容性语言的位置,并建议...

    fpga 开发板

    DE2-70是一款由台湾友晶公司生产的FPGA开发板,它采用了Altera公司的EP2C70F896C6 FPGA芯片作为核心处理器。这款开发板主要面向FPGA/SOPC(System-On-a-Programmable-Chip)领域的初学者,提供了丰富的实验指导和...

    学习IOS实例(2)

    在本节的学习IOS实例(2)中,我们将深入...通过实际操作和代码分析,你可以逐步建立自己的iOS开发技能,为成为专业的iOS开发者打下坚实基础。在实践中不断探索,你会发现iOS开发不仅有趣,而且充满了创造的可能性。

    jtag 调试2440的程序

    JTAG最初是为了电路板级测试而设计的,它通过一个四线接口(TMS、TCK、TDI和TDO)连接到目标设备,形成一个TAP(Test Access Port)控制器。这些线分别代表测试模式选择(TMS)、时钟(TCK)、数据输入(TDI)和数据...

    QuartusII基本操作流程.pptx

    ### 一、建立工作库文件夹和编辑设计文件 在开始任何设计之前,首先需要创建一个用于存放设计文件的工作库文件夹。这个文件夹将是项目的基础,其中将包含所有的设计文件、工程文件以及其他辅助文件等。接下来,使用...

    产品测试课程学习复盘测试题 个人学习材料,仅供学习参考

    ()是实际的执行被测对象的程序代码,输入实现设计好的测试用例,检查程序代码运行得到的结果与测试用力中设计的预期结果之间是否有差异,判定实际结果与预测结果是否一致。** - **选项解析:** - **A. 集成测试...

    matlab计算光栅衍射效率

    根据光栅衍射理论,可以通过建立矩阵方程来解决该问题。这里我们定义了几个关键矩阵: - **A**: 零矩阵 - **B**: 单位矩阵 - **C**: 用于存储方程组中的系数 - **D**: 存储方程组中的另一组系数 接下来,通过循环...

    TCP客户端+服务器 异步编程

    客户端同样采用异步连接,这意味着在尝试建立与服务器的连接时,程序不会被阻塞,用户界面仍能保持交互性。此外,异步接收和发送数据让客户端能在等待数据传输的同时执行其他任务,提高了用户体验。 在VS2008中,C#...

Global site tag (gtag.js) - Google Analytics