我的代码
https://github.com/liuqun/demo-linux-tun-virtual-netcard/blob/master/demo-1-ioctl/src/main.c

代码片段1

以下代码节选自"openV屁N"的源码tun.c文件:

openV屁N封装了一组读写函数如下:

  • open_tun(dev_name, dev_type, dev_node, tuntap上下文)打开Tun虚拟网卡
  • close_tun(tuntap上下文)
  • n_bytes = write_tun(tuntap上下文, buf, len)
  • n_bytes = read_tun(tuntap上下文, buf, len)
int write_tun(struct tuntap *tt, uint8_t *buf, int len)
{return write(tt->fd, buf, len);
}
int read_tun(struct tuntap *tt, uint8_t *buf, int len)
{return read(tt->fd, buf, len);
}
void open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{struct ifreq ifr;/** We handle --dev null specially, we do not open /dev/null for this.*/if (tt->type == DEV_TYPE_NULL){open_null(tt);}else{/** Process --dev-node*/const char *node = dev_node;if (!node){node = "/dev/net/tun";}/** Open the interface*/if ((tt->fd = open(node, O_RDWR)) < 0){msg(M_ERR, "ERROR: Cannot open TUN/TAP dev %s", node);}/** Process --tun-ipv6*/CLEAR(ifr);ifr.ifr_flags = IFF_NO_PI;#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN)ifr.ifr_flags |= IFF_ONE_QUEUE;
#endif/** Figure out if tun or tap device*/if (tt->type == DEV_TYPE_TUN){ifr.ifr_flags |= IFF_TUN;}else if (tt->type == DEV_TYPE_TAP){ifr.ifr_flags |= IFF_TAP;}else{msg(M_FATAL, "I don't recognize device %s as a tun or tap device",dev);}/** Set an explicit name, if --dev is not tun or tap*/if (strcmp(dev, "tun") && strcmp(dev, "tap")){strncpynt(ifr.ifr_name, dev, IFNAMSIZ);}/** Use special ioctl that configures tun/tap device with the parms* we set in ifr*/if (ioctl(tt->fd, TUNSETIFF, (void *) &ifr) < 0){msg(M_ERR, "ERROR: Cannot ioctl TUNSETIFF %s", dev);}msg(M_INFO, "TUN/TAP device %s opened", ifr.ifr_name);/** Try making the TX send queue bigger*/
#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN)if (tt->options.txqueuelen){struct ifreq netifr;int ctl_fd;if ((ctl_fd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0){CLEAR(netifr);strncpynt(netifr.ifr_name, ifr.ifr_name, IFNAMSIZ);netifr.ifr_qlen = tt->options.txqueuelen;if (ioctl(ctl_fd, SIOCSIFTXQLEN, (void *) &netifr) >= 0){msg(D_OSBUF, "TUN/TAP TX queue length set to %d", tt->options.txqueuelen);}else{msg(M_WARN | M_ERRNO, "Note: Cannot set tx queue length on %s", ifr.ifr_name);}close(ctl_fd);}else{msg(M_WARN | M_ERRNO, "Note: Cannot open control socket on %s", ifr.ifr_name);}}
#endif /* if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) */set_nonblock(tt->fd);set_cloexec(tt->fd);tt->actual_name = string_alloc(ifr.ifr_name, NULL);}return;
}
void close_tun(struct tuntap *tt)
{if (tt){if (tt->type != DEV_TYPE_NULL && tt->did_ifconfig){struct argv argv = argv_new();struct gc_arena gc = gc_new();#ifdef ENABLE_IPROUTEif (is_tun_p2p(tt)){argv_printf(&argv,"%s addr del dev %s local %s peer %s",iproute_path,tt->actual_name,print_in_addr_t(tt->local, 0, &gc),print_in_addr_t(tt->remote_netmask, 0, &gc));}else{argv_printf(&argv,"%s addr del dev %s %s/%d",iproute_path,tt->actual_name,print_in_addr_t(tt->local, 0, &gc),netmask_to_netbits2(tt->remote_netmask));}
#else  /* ifdef ENABLE_IPROUTE */argv_printf(&argv,"%s %s 0.0.0.0",IFCONFIG_PATH,tt->actual_name);
#endif /* ifdef ENABLE_IPROUTE */argv_msg(M_INFO, &argv);openvpn_execve_check(&argv, NULL, 0, "Linux ip addr del failed");if (tt->did_ifconfig_ipv6_setup){const char *ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, &gc);#ifdef ENABLE_IPROUTEargv_printf(&argv, "%s -6 addr del %s/%d dev %s",iproute_path,ifconfig_ipv6_local,tt->netbits_ipv6,tt->actual_name);argv_msg(M_INFO, &argv);openvpn_execve_check(&argv, NULL, 0, "Linux ip -6 addr del failed");
#else  /* ifdef ENABLE_IPROUTE */argv_printf(&argv,"%s %s del %s/%d",IFCONFIG_PATH,tt->actual_name,ifconfig_ipv6_local,tt->netbits_ipv6);argv_msg(M_INFO, &argv);openvpn_execve_check(&argv, NULL, 0, "Linux ifconfig inet6 del failed");
#endif}argv_reset(&argv);gc_free(&gc);}close_tun_generic(tt);free(tt);}
}
#define TUNNEL_TYPE(tt) ((tt) ? ((tt)->type) : DEV_TYPE_UNDEF)
#define TUNNEL_TOPOLOGY(tt) ((tt) ? ((tt)->topology) : TOP_UNDEF)/** Define a TUN/TAP dev.*/
struct tuntap
{int type; /* DEV_TYPE_x as defined in proto.h */int topology; /* one of the TOP_x values */bool did_ifconfig_setup;bool did_ifconfig_ipv6_setup;bool did_ifconfig;bool persistent_if;         /* if existed before, keep on program end */struct tuntap_options options; /* options set on command line */char *actual_name; /* actual name of TUN/TAP dev, usually including unit number *//* number of TX buffers */int txqueuelen;/* ifconfig parameters */in_addr_t local;in_addr_t remote_netmask;in_addr_t broadcast;struct in6_addr local_ipv6;struct in6_addr remote_ipv6;int netbits_ipv6;#ifdef _WIN32HANDLE hand;struct overlapped_io reads;struct overlapped_io writes;struct rw_handle rw_handle;/* used for setting interface address via IP Helper API* or DHCP masquerade */bool ipapi_context_defined;ULONG ipapi_context;ULONG ipapi_instance;in_addr_t adapter_netmask;/* Windows adapter index for TAP-Windows adapter,* ~0 if undefined */DWORD adapter_index;int standby_iter;
#else  /* ifdef _WIN32 */int fd; /* file descriptor for TUN/TAP dev */
#endif#ifdef TARGET_SOLARISint ip_fd;
#endif#ifdef HAVE_NET_IF_UTUN_Hbool is_utun;
#endif/* used for printing status info only */unsigned int rwflags_debug;/* Some TUN/TAP drivers like to be ioctled for mtu* after open */int post_open_mtu;
};

代码片段2

节选自Linux内核文档提供的一段Tun/Tap用户层样例代码(多处细节已经调整)
https://www.kernel.org/doc/Documentation/networking/tuntap.txt

// 样例代码
#include <linux/if.h>
#include <linux/if_tun.h>int open_tun_and_select_type(char devName[IFNAMSIZ], int devType)//devName字符串指针不能为NULL,但可以是全0x00即'\0'{struct ifreq ifr;int fd;int err;if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )return old_style__open_tun_and_select_type(devName, devType);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 = (short) devType; if( *devName ) {memcpy(ifr.ifr_name, devName, IFNAMSIZ);ifr.ifr_name[IFNAMSIZ-1] = '\0';}if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){close(fd);return err;}memcpy(devName, ifr.ifr_name, IFNAMSIZ);return fd;}
  • Linux标准struct ifreq结构体的定义位于<linux/if.h>, 细节如下:
    http://man7.org/linux/man-pages/man7/netdevice.7.html
    https://github.com/torvalds/linux/blob/master/include/uapi/linux/if.h
#define IFNAMSIZ    16
// 该结构体用于修改网卡的各种参数, 包括MAC地址/IP地址/MTU最大值/Metric跃点数等
// 之前的程序我们仅仅用到 ifr.ifr_flags=IFF_TUN切换Tun/Tap网卡的类型struct ifreq {char ifr_name[IFNAMSIZ]; /* Interface name */union {struct sockaddr ifr_addr;struct sockaddr ifr_dstaddr;struct sockaddr ifr_broadaddr;struct sockaddr ifr_netmask;struct sockaddr ifr_hwaddr;short           ifr_flags;int             ifr_ifindex;int             ifr_metric;int             ifr_mtu;struct ifmap    ifr_map;char            ifr_slave[IFNAMSIZ];char            ifr_newname[IFNAMSIZ];char           *ifr_data;};};

数据格式

tun_read() / tun_write()读写操作的数据包结构如下(摘自Linux内核文档):

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

https://www.kernel.org/doc/Documentation/networking/tuntap.txt

Linux Tun/Tap网口(/dev/net/tun)的读写方法相关推荐

  1. linux tun 读取数据,Linux Tun/Tap网口(/dev/net/tun)的读写方法

    我的代码 https://github.com/liuqun/demo-linux-tun-virtual-netcard/blob/master/demo-1-ioctl/src/main.c 代码 ...

  2. TUN/TAP设备浅析(三) -- TUN/TAP设备的应用

    上一篇文章主要讲述了TUN/TAP设备的一些原理,你可能会好奇,TUN/TAP设备究竟有什么用处呢?所以这篇文章,我想用一些实际的例子来回答这个问题. 例子源自陈硕老师的博客,博文中关于TUN/TAP ...

  3. TUN/TAP设备浅析(二) -- TUN/TAP的编程

    这篇文章想详细阐述一下有关于 TUN/TAP 设备的编程. 其实关于这两种设备的编程,基本上属于八股文,大家一般都这么干. 启动设备之前 有的linux 并没有将tun 模块编译到内核之中,所以,我们 ...

  4. linux应用对I2C设备驱动4种读写方法

    From 一:读写/dev/i2c-x设备结点 /dev/i2c-x设备结点对应的驱动文件为内核目录drivers/i2c下自带的i2c-dev.c文件,通读此文件可以发现它的工作流程.1.通过reg ...

  5. linux下使用tun/tap虚拟网卡

    tun/tap虚拟网卡介绍 tun是一种虚拟网络设备,tun设备一端连接着用户程序,一端连接着内核协议栈,任何时候从协议栈发到tun网卡的数据都能从用户程序中读到,而从用户程序写入/dev/net/t ...

  6. Linux tun:tap 详解

    在计算机网络中,tun与tap是操作系统内核中的虚拟网络设备.不同于普通靠硬件网络适配器实现的设备,这些虚拟的网络设备全部用软件实现,并向运行于操作系统上的软件提供与硬件的网络设备完全相同的功能. t ...

  7. 介绍Linux下的 Tun/Tap

    在计算机网络中,TUN与TAP是操作系统内核中的虚拟网络设备.不同于普通靠硬件网路板卡实现的设备,这些虚拟的网络设备全部用软件实现,并向运行于操作系统上的软件提供与硬件的网络设备完全相同的功能. 什么 ...

  8. Tun/Tap接口指导

    转载来源: 本文来自博客园,作者:charlieroro,转载请注明原文链接:https://www.cnblogs.com/charlieroro/p/13497340.html ========= ...

  9. linux虚拟网络设备之tun/tap驱动程序设计原理(五)

    简介 虚拟网卡Tun/tap驱动是一个开源项目,支持很多的类UNIX平台,OpenVPN和Vtun都是基于它实现隧道包封装.本文将介绍tun/tap驱动的使用并分析虚拟网卡tun/tap驱动程序在li ...

最新文章

  1. 好久没有看到这么有建设性德文章,由衷地赞叹《知其所以然地学习(以算法学习为例)》-By 刘未鹏(pongba)
  2. OpenCASCADE:Mac OS X平台使用Code::Blocks构建OCCT
  3. 谷歌guava_Google Guava –期货
  4. vue前后分离session实现_vue2 前后端分离项目ajax跨域session问题解决
  5. WSARecv参数lpNumberOfBytesRecvd的一个变态问题
  6. 开源十问, 社区新人快速上手指南
  7. php的具体配置学习笔记
  8. 小红书公司注册老红书商标上热搜 网友:过两年变老了改名吗?
  9. distinct group by一起用_用ggplot2来画带有对角线的热图。
  10. mysql设计学习_Mysql数据库设计学习
  11. 多尺度:传统高斯金字塔,拉普拉斯金字塔及SIFT算法多尺度金字塔
  12. 学生HTML个人网页作业作品:基于web在线汽车网站的设计与实现 (宝马轿车介绍)
  13. (转)Windows gcc(MinGW32)配置-慢!!!
  14. sealos4.1部署Kubernetes单机
  15. DHU Python Curriculumly Learning【5】——大作业_key_by_TA
  16. 第8天 鼠标控制与32位模式切换
  17. 撤销博士学位!取消硕导资格!科技部最新通报一批科研不端案件...
  18. 【紫书】第一章实验+问题
  19. 三分法 three-way partitioning
  20. 关于el-upload上传图片的一些坑clearFiles()的使用

热门文章

  1. 10A 的GROUP和CUI使用
  2. 判断输入几位数的正则_判断是几位数,并逆向输出此数的程序算法和说明
  3. php variables,浅析PHP原理之变量(Variables inside PHP)
  4. input 限制只能输入数字,且保留小数后两位
  5. JavaScript 自定义年月日选择下拉框select选择的日期方法vue实现
  6. Angular 启动项目时 port 4200 is already in use 解决方法
  7. Open3d之文件IO
  8. git的一些简单用法
  9. token的作用_说一说Coin和Token有什么不同
  10. 理解BERT Transformer:Attention is not all you need!