我的代码

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_IPROUTE

if (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);

open_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_IPROUTE

argv_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);

open_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);

open_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 _WIN32

HANDLE 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_SOLARIS

int ip_fd;

#endif

#ifdef HAVE_NET_IF_UTUN_H

bool 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 #include 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结构体的定义位于, 细节如下:

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 读取数据,Linux Tun/Tap网口(/dev/net/tun)的读写方法相关推荐

  1. Linux Tun/Tap网口(/dev/net/tun)的读写方法

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

  2. linux文件读取程序,Linux系统编程:文件的读取写入

    一.read系统调用 一旦有了与一个打开文件描述相关连的文件描述符,只要该文件是用O_RDONLY或O_RDWR标志打开的,就可以用read()系统调用从该文件中读取字节 函数原型: ssize_t ...

  3. linux 汇编 读取软盘,Linux下如何格式化软盘和读取软盘?

    我用fdformat /dev/fd0H1440命令格式化了软盘,然后照课本说的: mkfs -f ext2 -c /dev/fd0H1440结果系统说bad fragment size - ext2 ...

  4. linux 汇编 读取软盘,[Linux]dd 读写软盘:在软盘主引导扇区写入显示hello world的二进制代码数据...

    代码效果 在软盘主引导扇区写入显示 hello world 的二进制代码数据 命令行操作 第一步,格式化软盘,/dev/fd0是软盘的名字 $ sudo fdformat /dev/fd0 $ sud ...

  5. linux 内核 发送数据,linux 内核tcp数据发送的实现

    在分析之前先来看下SO_RCVTIMEO和SO_SNDTIMEO套接口吧,前面分析代码时没太注意这两个.这里算是个补充. SO_RCVTIMEO和SO_SNDTIMEO套接口选项可以给套接口的读和写, ...

  6. linux c 读取摄像头,Linux下onvif客户端获取ipc摄像头 获取能力:GetCapabilities

    getcapabilities:获取能力,主要目的获取设备能力信息(获取媒体服务地址) 鉴权:但是在调用获取设备能力之前是需要鉴权的.onvif协议规定,部分接口需要鉴权,部分接口不需要鉴权,在调用需 ...

  7. linux历史性能数据,Linux平台下如何看OS历史的性能数据

    同事电话询问Linux下一个集群内2个主机前后2天相继无响应,表现状况为ping都没响应. 因为没任何监控或其他性能数据,故需要获取历史OS性能数据. 我们知道rhel5,6下默认可以通过sar命令查 ...

  8. linux 文件读取 监控,linux 文件系统的监控

    完整性检查是HIDS的重要组成部分之一,linux下做完整性检查的思路有3个 1.哈希对比 2.签名校验 3.inotify 方法有2个: A.定期检测,例如通过cron或程序内置计时器 B.实时检测 ...

  9. linux备份磁盘数据,linux下vmstat输出数据分析-linux下dd命令备份磁盘的节点(...-linux watch命令用法简介(图文)_169IT.COM...

    Linux下vmstat命令的输出,对应着很多选项,有的朋友不是很明白. 下面为大家作详细的分析,如下: Vmstat procs -----------memory---------- ---swa ...

最新文章

  1. php文件上传代码_PHP实现文件分片上传的实例代码
  2. 使用ANY和ALL条件
  3. mysql函数封装_Mysql对文件操作的封装
  4. java 解析二进制_Java二进制Class文件格式解析
  5. 【Python】字符串反转
  6. 关于Excel的查询,可以通过格式查询(比如查找指定颜色的单元格)。
  7. python怎么读取中文文件-Python3 中文文件读写方法
  8. subsring 截取
  9. 王道机考系列——数学问题
  10. 张一鸣宣布卸任字节跳动CEO,去学习承担社会责任
  11. 长尾效应--Long Tail Effect
  12. python实现中国象棋
  13. 修改导航栏的背景色和字体颜色
  14. 2016-7-20 奶奶走了
  15. 宁波市第23届中小学生计算机程序设计竞赛初赛,宁波市第24届中小学生计算机程序设计竞赛初赛试题(小学组)...
  16. composer详解
  17. Linux内核分析 笔记二 操作系统是如何工作的 ——by王玥
  18. kotlin sealed 中_Kotlin的密封(Sealed)类:超强的枚举(KAD 28)
  19. 风靡整个DOS时代的Pctools,现已不再,饱受争议的它,又能走多远
  20. 使用server版的哈工大LTP进行NLP任务(Java实现)

热门文章

  1. oracle 查叶子节点,oracle 层次查询判断叶子和根节点
  2. Raid卡(阵列卡)
  3. python datetime timezone_Python中timezone的部分常用操作
  4. Django ——Timezone 处理
  5. PCB 模拟Windows管理员域帐号安装软件
  6. mysql decimal 类型_MySQL数据类型DECIMAL用法详解
  7. 智能车学习(六)——OLED屏幕使用
  8. java的cloneable_Java中的克隆Cloneable
  9. 科技向善:用OpenVINO减少食物浪费
  10. 庆典活动全面展开,网工系列全面预订