Linux虚拟网络之tun(一)基本使用
来源:互联网 发布:edius mac 编辑:程序博客网 时间:2024/05/20 04:14
TUN/TAP 设备是一种让用户态程序向内核协议栈注入数据的设备,一个工作在三层,一个工作在二层。理论知识可以看:
- 虚拟网卡 TUN/TAP 驱动程序设计原理。
- TAP/TUN摘要
- TAP/TUN浅析(一)
- TAP/TUN(二)
本文只讲怎么用,直接上代码:
#include <fcntl.h>#include <sys/socket.h>#include <linux/ip.h>#include <linux/if.h>#include <linux/if_tun.h>#include <arpa/inet.h>#include <string.h>#include <sys/ioctl.h>#include <unistd.h>#include <iostream>#include <errno.h>#include <linux/if_ether.h>#include <linux/if_packet.h>#include <thread>using namespace std;void task(char* dev, int net_addr){ int tun_fd; struct ifreq ifr; tun_fd = open("/dev/net/tun", O_RDWR); if(0 > tun_fd) { cout<<"open tun file error!" << endl; return; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ); if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) { string err_str = strerror(errno); cout << "Failed to set TUN device name: " << err_str << endl; close(tun_fd); return; } // Bring up the interface int sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) { string err_str = strerror(errno); cout << "Failed to bring up socket: " << err_str << endl; close(tun_fd); return; } ifr.ifr_flags |= IFF_UP | IFF_RUNNING | IFF_PROMISC; if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) { string err_str = strerror(errno); cout << "Failed to set socket flags: " << err_str << endl; close(tun_fd); return; } ifr.ifr_addr.sa_family = AF_INET; ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = net_addr; if(0 > ioctl(sock, SIOCSIFADDR, &ifr)) { string err_str = strerror(errno); cout << "Failed to set socket address: " << err_str << endl; close(tun_fd); return; } ifr.ifr_netmask.sa_family = AF_INET; ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0"); if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) { string err_str = strerror(errno); cout << "Failed to set socket netmask: " << err_str << endl; close(tun_fd); return; } if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) { string err_str = strerror(errno); cout << "Failed to get socket index: " << err_str << endl; close (tun_fd); return; } struct sockaddr_ll addr; memset (&addr, 0, sizeof (addr)); addr.sll_family = AF_PACKET; addr.sll_ifindex = ifr.ifr_ifindex; addr.sll_protocol = htons(ETH_P_ALL); printf("addr.sll_ifindex %d" ,addr.sll_ifindex); if (-1 == bind(sock, (struct sockaddr *)&addr, sizeof(addr))) { string err_str = strerror(errno); printf("binding socket %d with if %s error: %s", sock, dev, strerror(errno)); close (tun_fd); return; } int N_bytes; unsigned char msg[8000]; in_addr ip_addr; ip_addr.s_addr = net_addr; int j = 500; while(j-- > 0) { N_bytes = read(tun_fd, msg, 8000); if (N_bytes > 0) { printf("%s recv msg len: %3d, msg: ", inet_ntoa(ip_addr), N_bytes); for (int i = 0; i < 20 && i < N_bytes; i++) printf("%2x ", msg[i]); cout << endl; } } while(true) { N_bytes = recv (sock, msg, 8000, 0); if (N_bytes > 0) { printf("%s sock recv msg len: %3d, msg: ", inet_ntoa(ip_addr), N_bytes); for (int i = 0; i < 20 && i < N_bytes; i++) printf("%2x ", msg[i]); cout << endl; } }}int main(){ char dev[IFNAMSIZ] = "tun0"; char dev2[IFNAMSIZ] = "tun1"; thread t(task, dev, inet_addr("172.23.1.25")); thread t2(task, dev2, inet_addr("172.23.1.24")); t.join(); t2.join();}
1、上面代码建立了两个tun设备(tun0和tun1),每个设备有自己的地址。
2、task中演示了两种访问tun设备的方式 – 文件方式和socket方式(为了让socket能收发所有的包,用了SOCK_RAW,这里可以根据自己的需要建立其他协议类型的socket)。
3、假设有个目标地址是 10.0.0.10,执行下面的命令,程序就可以打印所接收到的包了。
ping 10.0.0.10 -I tun0
curl可以如下使用:
sudo curl --interface tun_srsue -O target_url
4、如果使用tun方式,收到的包都是ip包;如果使用tap方式,收到的是以太网帧。
5、跟netlink其实有点像,很多场景下可以互换。不过从使用方便程度看,tun占很大优势,因为不用编写内核驱动。跟netlink的性能没有对比测试,有空了测测。
说到使用方便性,在go语言中体现更明显。目前为止还没有哪个netlink库能很方便的使用,但是tun库是有的,代码如下:
package mainimport ( "log" "github.com/songgao/water")func main() { ifce, err := water.New(water.Config{ DeviceType: water.TUN, }) if err != nil { log.Fatal(err) } log.Printf("Interface Name: %s\n", ifce.Name()) packet := make([]byte, 2000) for { n, err := ifce.Read(packet) if err != nil { log.Fatal(err) } log.Printf("Packet Received: % x\n", packet[:n]) }}
0 0
- Linux虚拟网络之tun(一)基本使用
- Linux虚拟网络之tun(四)虚拟VPN
- Linux虚拟网络之tun(二)Raw包转发
- Linux虚拟网络之tun(三)隔离网络下的Raw转发
- linux下TUN/TAP虚拟网卡的使用
- linux下TUN或TAP虚拟网卡的使用
- linux下TUN/TAP虚拟网卡的使用 - heidsoft
- 在linux下使用tun/tap创建虚拟假网卡
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP
- LINUX 虚拟网卡tun例子
- Linux虚拟网卡TUN/TAP
- Linux虚拟网卡TUN/TAP
- LINUX 虚拟网卡tun例子
- PRML读书笔记——概率分布
- 多线程(2)- 线程同步
- STM32学习笔记
- vue-cli的使用
- 301、404、200、304等HTTP状态
- Linux虚拟网络之tun(一)基本使用
- poj 2241 The Tower of Babylon lis
- openconnect 编译
- 欢迎使用CSDN-markdown编辑器
- 网络安全监控 NSM 笔记
- window.onload和body的onload的区别
- 倒数求和
- C语言之动态数组
- MyBatis-入门、动态代理、配置