启用tun设备开启tap虚拟网卡功能

2023-11-16

注意:该文章中的arp应答部分是有问题的,由于作者现在已经没有实验环境无法再进行修正了,望看该文章的人注意一下

关于tun设备启用tap网卡,就是启用一个字符设备,使用open函数得到一个tun设备的文件描述符,可以使用write和read,或者pcap接口读写网卡,以下的部分为tun设备的控制代码,包括了网卡mac ip mask设置等,主要就是ioctl函数的使用

#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/if_tun.h>
#include <linux/if.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>

#include <linux/if_ether.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/route.h>

static char * interface_name_cut (char *buf, char **name)  
{  
    char *stat; 

    while (*buf == ' ')                                                                                                                                                                                                                     
        buf++;  
    *name = buf;  
    
    stat = strrchr (buf, ':');  
    *stat = '\0';  
    
    return *name;  
}

//check whether the network card exists.
int check_phy_name(char *interface)  
{  
    FILE *fp;  
    char buf[PROCBUFSIZ];  
    char *name;  

    fp = fopen (_PATH_PROC_NET_DEV, "r");  
    if (fp == NULL) {     
        printf("open proc file error\n");  
        goto EXIT1;
    }     

    fgets (buf, PROCBUFSIZ, fp);  
    fgets (buf, PROCBUFSIZ, fp);  

    while (fgets (buf, PROCBUFSIZ, fp) != NULL) {     
        interface_name_cut(buf, &name);  
        if(strcmp(interface,name)==0) {
            fclose(fp);
            return 1;  
        }
    } 

EXIT1:
    fclose(fp);  
    return -1;  
} 

//设置ip和mask
static int set_addr(char *dev_name, char *ip, int flag)
{
    struct ifreq ifr;
    struct sockaddr_in sin;
    int sockfd;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd == -1) {
        perror("tap");
        goto EXIT2;
    }

    snprintf(ifr.ifr_name, sizeof(dev_name), "%s", dev_name);

    /* Read interface flags */
    if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
        perror(ifr.ifr_name);
        goto EXIT2;
    }

    memset(&sin, 0, sizeof(struct sockaddr));
    sin.sin_family = AF_INET;
    inet_aton(ip, &sin.sin_addr);
    memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
   
    if (ioctl(sockfd, flag, &ifr) < 0) {
        perror(ifr.ifr_name);
        goto EXIT2;
    }
    
    close(sockfd);
    return 1;

EXIT2:
    close(sockfd);
    exit(-1);
}

static int get_tun_mac(char *dev_name, uint8_t *tun_mac)
{
    struct ifreq ifr;
    int sockfd, ret;
    uint8_t *mac;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd == -1) {
        perror("tap");
        goto EXIT1;
    }

    snprintf(ifr.ifr_name, sizeof(dev_name), "%s", dev_name);

    ret = ioctl(sockfd, SIOCGIFHWADDR, &ifr);
    if (ret == -1) {
        printf("get tun mac error\n");
        goto EXIT1;
    }   

    mac = (uint8_t *)ifr.ifr_hwaddr.sa_data;
    memcpy(tun_mac, mac, 6);
    
    close(sockfd);
    return 1;

EXIT1:
    close(sockfd);
    exit(-1);
}

static int set_tun_mac(char *dev_name, uint8_t *tun_mac)
{
    struct ifreq ifr;
    int sockfd, ret;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd == -1) {
        perror("tap");
        goto EXIT;
    }

    snprintf(ifr.ifr_name, sizeof(dev_name), "%s", dev_name);
    
    /* Read interface flags */
    if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
        perror(ifr.ifr_name);
        goto EXIT;
    }
    
    ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
    memcpy(&ifr.ifr_hwaddr.sa_data, tun_mac, 6);

    ret = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
    if (ret == -1) {
        printf("set tun mac error\n");
        goto EXIT;
    } 

    close(sockfd);
    return 1;

EXIT:
    close(sockfd);
    return -1;
}

static int set_routing(char *dst, char *gw, char *genmask, char *dev)
{
    int sockfd;
    struct rtentry route;
    struct sockaddr_in *addr;
    int err = 0;

    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("set routing");
        close(sockfd);
        return -1;
    }

    memset(&route, 0, sizeof(route));
    
    route.rt_dev = dev;
    
    addr = (struct sockaddr_in*)&route.rt_gateway;
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = inet_addr(gw);

    addr = (struct sockaddr_in*) &route.rt_dst;
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = inet_addr(dst);

    addr = (struct sockaddr_in*) &route.rt_genmask;
    addr->sin_family = AF_INET;
    inet_aton(genmask, &addr->sin_addr);

    route.rt_flags = RTF_UP | RTF_GATEWAY;
    route.rt_metric = 0;
    if ((err = ioctl(sockfd, SIOCADDRT, &route)) != 0) 
    {
        perror("ioctl routing");
        close(sockfd);
        return -1;
    }
    
    close(sockfd);
    return 1;
}

static int set_gateway(char ip[16])
{
    int sockfd;
    struct sockaddr_in sockaddr;
    struct rtentry rt;
    
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("set gateway");
        close(sockfd);
        exit(-1);
    } 

    memset(&rt, 0, sizeof(struct rtentry));
    memset(&sockaddr, 0, sizeof(struct sockaddr_in));
    sockaddr.sin_family = AF_INET;
    sockaddr.sin_port = 0;
    inet_aton(ip, &sockaddr.sin_addr);

    memcpy (&rt.rt_gateway, &sockaddr, sizeof(struct sockaddr_in));
    ((struct sockaddr_in *)&rt.rt_dst)->sin_family = AF_INET;
    ((struct sockaddr_in *)&rt.rt_genmask)->sin_family = AF_INET;
    rt.rt_flags = RTF_GATEWAY;

    if (ioctl(sockfd, SIOCADDRT, &rt) < 0)
    {
        perror("ioctl(SIOCADDRT) error in set_default_route\n");
        close(sockfd);
        exit(-1);
    }
    
    close(sockfd);
    return 1;
}

int interface_up(char *name)
{
    int fd;
    struct ifreq ifr;
    
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0)
    {
        fprintf(stderr, "tun : interface sokcet open failed!\n");
        return -1;
    }

    strcpy(ifr.ifr_name, name);
    
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        exit(-1);
    }

    ifr.ifr_flags |= IFF_UP;

    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        exit(-1);
    }

    return 1;
}

int interface_down(char *name)
{
    int fd;
    struct ifreq ifr;
    
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0)
    {
        fprintf(stderr, "tun : interface sokcet open failed!\n");
        return -1;
    }

    strcpy(ifr.ifr_name, name);
    
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        return -1;
    }

    ifr.ifr_flags &= ~IFF_UP;

    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
    {
        perror("ioctl");
        return -1;
    }

    return 1;
}

//arp应答就是填充一个mac地址然后对换mac,将数据包发出
static int build_arp_response(int tunfd, char *origin_pkts,int pkts_len)
{
    char buf[128]={0};
    unsigned char mymac[6] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
    struct ethhdr *eth_request = (struct ethhdr *)origin_pkts;
    struct ethhdr *eth_reply = (struct ethhdr *)buf;

    //原本的代码部分存在问题,所以删除了,如果有需要的自行添加,
    //arp的应答只需要修改下行流量的目标mac即可,将ff:ff:ff:ff:ff:ff换成mymac
    //调换ip和mac然后write写数据到tunfd即可
    return 0;
}

int main(int argc, char *argv[])
{
    struct ifreq ifr;
	int tunfd;

    //检测主网卡是否存在 -1 no exist
    if (check_phy_name("tap") == -1)  
    {
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_flags |= (IFF_TAP | IFF_NO_PI);
        strncpy(ifr.ifr_name, "tap", IFNAMSIZ);

        tunfd = open("/dev/net/tun", O_RDWR|O_NONBLOCK);
        if (tunfd == -1)
        {
            fprintf(stderr, "tun : /dev/net/tun open failed\n");
            return -1;
        }

        int ior;
        ior = ioctl(tunfd, TUNSETIFF, (void *)&ifr);
        if (ior < 0)
        {
            fprintf(stderr, "tun : virtual network create failed\n");
            return -1;
        }
    }

	unsigned char mac[6] = {0x43, 0x42, 0x15, 0x57, 0x45, 0x65};
	char ip[] = "192.168.0.1"
	char mask[] = "255.255.255.0";
    set_tap_mac("tap", mac);

    if (set_addr("tap", ip, SIOCSIFADDR) == -1)                       //set ip
        return -1;
    if (set_addr("tap", mask, SIOCSIFNETMASK) == -1)  //set netmask
        return -1;

    if (interface_up("tap") == -1)
    {
        fprintf(stderr, "virtual network up failed!\n");
        return -1;
    }

    if (set_routing("0.0.0.0", ip, "0.0.0.0", "tap") == -1)
    {
        fprintf(stderr, "virtual network set routing failed!\n");
        return -1;
    }
  
    get_tap_mac("tap", mac);
    printf("tun mac : %x:%x:%x:%x:%x:%x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
 
    return 1;
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

启用tun设备开启tap虚拟网卡功能 的相关文章

  • C语言pcre库的使用及验证IP地址的合法性

    PCRE是一个用C语言编写的正则表达式函数库 它十分易用 同时功能也很强大 性能超过了POSIX正则表达式库和一些经典的正则表达式库 在使用PCRE库时 首先肯定是需要安装pcre的 不过一般的系统都会有自带的PCRE库 不过如果想使用最新
  • 编写程序模拟完成动态分区存储管理方式的内存分配和回收。

    usr bin python coding utf 8 class Table object 空闲分区表 0 开始地址 1 长度 freeTable 占用分区表 0 程序名 1 开始地址 2 长度 useTable def init sel
  • 写时拷贝技术(copy-on-write)

    传统的fork 系统调用直接把所有的资源复制给新创建的进程 这种实现过于简单并且效率低下 因为它拷贝的数据也许并不共享 更糟的情况是 如果新进程打算立即执行一个新的映像 那么所有的拷贝都将前功尽弃 Linux的fork 使用写时拷贝 cop
  • Lua和C++交互总结(很详细)

    出处 http blog csdn net shun fzll article details 39120965 一 lua堆栈 要理解lua和c 交互 首先要理解lua堆栈 简单来说 Lua和C c 语言通信的主要方法是一个无处不在的虚拟
  • 为何在新建STM工程中全局声明两个宏

    在uVision中新建STM32工程后 需要从STM32标准库中拷贝标准外设驱动到自己的工程目录中 此时需要在工程设置 gt C C 选项卡下的Define文本框中键入这两个全局宏定义 STM32F40 41xxx USE STDPERIP
  • lua和测试(一)

    lua做为一门高级语言 在游戏产业运用到机会越来越多了 测试掌握几门脚本语言也有一定的重要性 以下对于lua组合输入做出一些引导 测试需要掌握的关于返回数值 主要用到布尔类 前言的指引 lua的语法比较简单和清晰 学过c语言的可以很好的掌握
  • Dev-C++之开启装逼效果

    Dev C 是个不错的C IDE 在10年前 它是很不错 在现在 它是个以界面丑陋和调试像吃粑粑这两点著称 如下图 实在是丑到离谱 丑到无法忍受 可是没办法呀 人家CCF规定比赛用这个 你个小蒟蒻吵什么 我现在就来讲讲怎么把你的Dev C
  • 手把手教你如何写一个三子棋/N子棋的小游戏

    这里写目录标题 第一步 游戏进入界面 第二步 初始化棋盘 第三步 打印棋盘 第四步 玩家和电脑下棋 第五步 判断输赢 三子棋或者N子棋怎么写 让我们先来玩一把 再来看看怎么写 程序运行界面 1为玩游戏 2为清屏 0为退出游戏 我们选1 然后
  • C++:指向类的成员的指针

    引 想必接触过C的朋友们对C语言中指针的概念已经有了深入的了解 如果初步进行了解的朋友可以看一下 C语言基础学习笔记 指针展开来讲的基本知识点包括 指针的概念 指针的定义和初始化及简单使用 指针函数和函数指针 有关指针函数和函数指针的内容上
  • 【C/C++】 - Linux下查找函数头文件 以及 man命令拓展

    背景 比如现在需要找C语言 sleep函数的头文件 使用man来查找 可以先man sleep 可以发现出来的默认是sleep 1 是一个User Commands 明显不是我们需要的 这里提示了 看sleep 3 那我们查看下sleep
  • 如何在 OSX 中点击/挂钩键盘事件并记录哪个键盘触发每个事件

    我现在已经发现了如何在 OS X 上低级别挂接 点击键盘事件 如何在 MacBook 键盘上点击 钩住 F7 到 F12 以及电源 弹出 打印出该答案的代码 compile and run from the commandline with
  • 当被测试者在 Perl 中使用 TAP 失败退出时,是否可以测试预期的错误?

    假设您正在运行一些单元测试 并且您想查看正在测试的方法 或脚本或函数或其他内容 是否失败 如何设置这样的测试 我希望有这样的事情 ok obj gt method my bad params DEATH method dies as exp
  • 虚函数不能声明为static

    虚函数申明为static报错 class Foo public Foo default static virtual Foo int main Foo foo return 0 main cpp 10 25 error member Foo
  • C++中的并发多线程网络通讯

    C 中的并发多线程网络通讯 一 引言 C 作为一种高效且功能强大的编程语言 为开发者提供了多种工具来处理多线程和网络通信 多线程编程允许多个任务同时执行 而网络通信则是现代应用程序的基石 本文将深入探讨如何使用C 实现并发多线程网络通信 并
  • C/C++编程中的算法实现技巧与案例分析

    C C 编程语言因其高效 灵活和底层的特性 被广大开发者用于实现各种复杂算法 本文将通过10个具体的算法案例 详细探讨C C 在算法实现中的技巧和应用 一 冒泡排序 Bubble Sort 冒泡排序 Bubble Sort 是一种简单的排序
  • 非阻塞 tun/tap 文件描述符上的 read() 收到 EAGAIN 错误

    我想从非阻塞 tun tap 文件描述符读取 IP 数据包tunfd我设置了tunfd作为非阻塞并在 libevent 中为其注册 READ EV 事件 当事件触发时 我先读取前20个字节来获取IP头 然后 阅读其余部分 nr bytes
  • C++实现函数重载的原理

    一 函数重载的概念 C 中允许存在同名函数 但要求函数参数的类型 个数不同 这些同名函数就称为函数的重载 void func int a int b cout lt lt func int a int b lt lt endl void f
  • 在 Solaris 上,使用 gcc 编译的库与使用 cc 生成的库的使用方式是否相同?

    我目前正在尝试编译 libxml2在 Solaris 上 当我运行源代码提供的 configure 脚本时 会自动使用 gcc 和 g 编译器 但是 我想使用 cc 和 CC 编译器 所以我跑 configure CC cc CXX CC
  • MKMapView 未在平移上调用 RegionDidChangeAnimated

    我有一个带有 MKMapView 的应用程序和每次地图更改位置 在 RegionDidChangeAnimated 中 时调用的代码 当应用程序最初加载时 在显式更新地图坐标的平移 滑动 捏合 点击和按钮上调用regionDidChange
  • Pipe 和 Tap VS 使用 ngxs 订阅

    我正在玩管道并订阅 如果我使用带有水龙头的管道 则控制台中不会登录任何内容 如果我使用订阅 它就可以工作 那么我做错了什么 import Observable from rxjs import tap take from rxjs oper

随机推荐

  • 人工智能的数学基石:揭秘人工智能十大数学基础

    人工智能 Artificial Intelligence 简称AI 正以惊人的速度改变着我们的生活 然而 要实现智能的机器 离不开数学的支持 本文将带你深入探索人工智能的数学基础 揭示AI背后的数学奥秘 一 线性代数 Linear Alge
  • 函数对象(重载括号运算符)

    函数对象 重载括号运算符 函数对象超出普通函数的概念 函数对象可以有自己的状态 在使用stl中 经常需要将函数对象作为算法的输入参数 或实例子化一个容器的输入参数
  • NodeJs之邮件(email)发送

    NodeJs之邮件 email 发送 一 介绍与需求 1 1 介绍 1 Nodemailer简介 Nodemailer是一个简单易用的Node js邮件发送插件 github地址 Nodemailer的主要特点包括 支持Unicode编码
  • SpringBoot+Shiro+LayUI权限管理系统项目-9.核心知识点总结

    1 说明 本篇讲一下本项目几个重要的知识点 详细看源码 文章下方捐赠或QQ联系捐赠获取 2 Shiro如何设置密码加密算法 1 在shiro配置文件中添加 Bean public HashedCredentialsMatcher hashe
  • 协方差矩阵的几何解释

    A geometric interpretation of the covariance matrix http www visiondummy com 2014 04 geometric interpretation covariance
  • Java线程:新特征-阻塞栈

    本文转载至 http lavasoft blog 51cto com 62575 222530 对于阻塞栈 与阻塞队列相似 不同点在于栈是 后入先出 的结构 每次操作的是栈顶 而队列是 先进先出 的结构 每次操作的是队列头 这里要特别说明一
  • 构建OpenCV和Raspberry Pi物体视觉追踪

    平移和倾斜伺服设备可帮助摄像机使用视觉自动跟踪颜色对象 OpenCV是免费的 可用于学术和商业用途 它具有C C Python和Java接口 并支持Windows Linux Mac OS iOS和Android 在我的系列OpenCV教程
  • scanf("%d\n",&num)中的\n是很特别的

    这是上篇博文 http blog csdn net u010412719 article details 48324799 中遇到的问题 详细原因明天再总结 总之 因为自己这样写了 花了很长时间才把这个bug调通 在scanf里 n 很特别
  • 小程序margin-bottom在IOS里面不起作用的解决方法

    margin bottom 是页面标签底部的元素属性 例如view中的定义按钮 如果想要距离底部有20rpx 按照常规写法margin bottom 20rpx 但是小程序用margin bottom在IOS手机出现失效问题 如何解决这个问
  • appuim+python常遇到的问题

    appuim python常遇到的问题 appuim使用过程中常见的问题 import time 一 内嵌H5定位 1 在web自动化中我们会遇见frame的问题 在遇见这些内嵌的标签后我们需要做的就是切换窗口 那么在app自动化测试也有类
  • Kotlin和Java混合开发必读:基本的互操作

    在使用Kotlin和Java混合开发的时候 涉及到一些基本的互操作 一 属性的读写 1 Kotlin自动识别Java的属性的Getter和Setter 2 Java操作kotlin属性可以通过Getter和Setter的方式 二 空安全类型
  • 面试官问:微服务的4种部署策略有哪些,什么区别?

    在项目迭代的过程中 不可避免需要 上线 上线对应着部署 或者重新部署 部署对应着修改 修改则意味着风险 目前有很多部署发布的技术 这儿将常见的做一个总结 上面所说难免有些抽象 举一个情景例子 加入你是微博项目负责人员 现在新版本较原来的老版
  • VScode解压版升级

    按照提示 下载最新的解压版 下载后解压文件夹 然后将旧的的解压版删除 不要替换 是删除之前的解压版 然后将新的解压后的文件粘贴到原来的位置 当然 如果你要换位置也是可以的 解压版很随意 很绿色的 之前的插件也是会完全保留的 包括登录信息
  • C# 中 Console.WriteLine 常见的几种形式及其用法差异

    在 C 的 Console WriteLine 方法中 有多种重载形式可以用于不同的输出需求 下面是常见的几种形式及其用法差异 输出字符串 Copy code Console WriteLine Hello World 这是最简单的用法 直
  • Unity --- 基本键鼠操作

    1 我们对于键盘和鼠标的点击操作相当于在输入数据 这些输入的数据都会被存储到对应的数据缓存区中供程序读取和调用 而我们所谓的游戏程序中的键鼠操作其实就是当我们通过键盘输入了特定数据之后 游戏程序马上从缓存区中读取到这个数据 并通过这个输入的
  • axure怎么存html文件怎么打开,axure 保存html文件怎么打开

    2 回答 2020 08 18 浏览 71 分类 绘图建模 回答 1 谷歌内核的浏览器需要安装Axure的插件才能访问 2 火狐浏览器 好像可以 与IE浏览器 3 可以用本机搭建一个服务器 让人家访问你的IP 任何浏览器都可以 1 回答 2
  • cobalt strike木马免杀

    0x001 针对powershell免杀 工具 Invoke Obfuscation 操作实例 1 利用CS生成powershell木马 2 进入invoke Obsfuscation文件 使用powershell命令执行 3 利用powe
  • CUDA Samples:Vector Add

    以下CUDA sample是分别用C 和CUDA实现的两向量相加操作 参考CUDA 8 0中的sample C ProgramData NVIDIA Corporation CUDA Samples v8 0 0 Simple 并对其中使用
  • 《深度学习入门》鱼书学习笔记(代码可运行)

    X 前言 X 1环境配置 x 1 1安装Anaconda 直接官网下载Anaconda 安装完成后 conda V查看是否安装成功 activate gt 进入base环境 conda create n py37 python 3 7 创建
  • 启用tun设备开启tap虚拟网卡功能

    注意 该文章中的arp应答部分是有问题的 由于作者现在已经没有实验环境无法再进行修正了 望看该文章的人注意一下 关于tun设备启用tap网卡 就是启用一个字符设备 使用open函数得到一个tun设备的文件描述符 可以使用write和read