利用 Linux tap/tun 虛擬設備寫一個 ICMP echo 程序

利用 Linux tap/tun 虛擬設備寫一個 ICMP echo 程序

前面兩篇文章已經介紹過 tap/tun 的原理和配置工具。這篇文章通過一個編程示例來深入了解 tap/tun 的程序結構。

01 準備工作

首先通過?modinfo tun?查看系統內核是否支持 tap/tun 設備驅動。

 
Copy
[root@by ~]# modinfo tun filename: /lib/modules/3.10.0-862.14.4.el7.x86_64/kernel/drivers/net/tun.ko.xz alias: devname:net/tun alias: char-major-10-200 license: GPL author: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com> description: Universal TUN/TAP device driver retpoline: Y rhelversion: 7.5 srcversion: 50878D5D5A0138445B25AA8 depends: intree: Y vermagic: 3.10.0-862.14.4.el7.x86_64 SMP mod_unload modversions signer: CentOS Linux kernel signing key sig_key: E4:A1:B6:8F:46:8A:CA:5C:22:84:50:53:18:FD:9D:AD:72:4B:13:03 sig_hashalgo: sha256

在 linux 2.4 及之后的內核版本中,tun/tap 驅動是默認編譯進內核中的。

如果你的系統不支持,請先選擇手動編譯內核或者升級內核。編譯時開啟下面的選項即可:

 
Copy
Device Drivers => Network device support => Universal TUN/TAP device driver support

tap/tun 也支持編譯成模塊,如果編譯成模塊,需要手動加載它:

 
Copy
[root@localhost ~]# modprobe tun [root@localhost ~]# lsmod | grep tun tun 31665 0

關于以上的詳細步驟,網上有很多教程,這里就不再贅述了。

https://blog.csdn.net/lishuhuakai/article/details/70305543

上面只是加載了 tap/tun 模塊,要完成 tap/tun 的編碼,還需要有設備文件,運行命令:

 
Copy
mknod /dev/net/tun c 10 200 # c表示為字符設備,10和200分別是主設備號和次設備號

這樣在?/dev/net?下就創建了一個名為 tun 的文件。

02 編程示例

2.1 啟動設備

使用 tap/tun 設備,需要先進行一些初始化工作,如下代碼所示:

 
Copy
int tun_alloc(char *dev, int flags) { assert(dev != NULL); struct ifreq ifr; int fd, err; char *clonedev = "/dev/net/tun"; if ((fd = open(clonedev, O_RDWR)) < 0) { return fd; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = flags; if (*dev != '\0') { strncpy(ifr.ifr_name, dev, IFNAMSIZ); } if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) { close(fd); return err; } // 一旦設備開啟成功,系統會給設備分配一個名稱,對于tun設備,一般為tunX,X為從0開始的編號; // 對于tap設備,一般為tapX strcpy(dev, ifr.ifr_name); return fd; }

首先打開字符設備文件?/dev/net/tun,然后用?ioctl?注冊設備的工作模式,是 tap 還是 tun。這個模式由結構體?struct ifreq?的屬性?ifr_flags?來定義,它有以下表示:

  • IFF_TUN: 表示創建一個 tun 設備。
  • IFF_TAP: 表示創建一個 tap 設備。
  • IFF_NO_PI: 表示不包含包頭信息,默認的,每個數據包傳到用戶空間時,都會包含一個附加的包頭來保存包信息,這個表示不加包頭。
  • IFF_ONE_QUEUE:表示采用單一隊列模式。

還是有一個屬性是?ifr_name,表示設備的名字,它可以由用戶自己指定,也可以由系統自動分配,比如?tapXtunX,X 從 0 開始編號。

ioctl?完了之后,文件描述符 fd 就和設備建立起了關聯,之后就可以根據 fd 進行 read 和 write 操作了。

2.2 寫一個 ICMP 的調用函數

為了測試上面的程序,我們寫一個簡單的 ICMP echo 程序。我們會使用 tun 設備,然后給?tunX?接口發送一個 ping 包,程序簡單響應這個包,完成 ICMP 的 request 和 reply 的功能。

如下代碼所示:

 
Copy
int main() { int tun_fd, nread; char buffer[4096]; char tun_name[IFNAMSIZ]; tun_name[0] = '\0'; /* Flags: IFF_TUN - TUN device (no Ethernet headers) * IFF_TAP - TAP device * IFF_NO_PI - Do not provide packet information */ tun_fd = tun_alloc(tun_name, IFF_TUN | IFF_NO_PI); if (tun_fd < 0) { perror("Allocating interface"); exit(1); } printf("Open tun/tap device: %s for reading...\n", tun_name); while (1) { unsigned char ip[4]; // 收包 nread = read(tun_fd, buffer, sizeof(buffer)); if (nread < 0) { perror("Reading from interface"); close(tun_fd); exit(1); } printf("Read %d bytes from tun/tap device\n", nread); // 簡單對收到的包調換一下順序 memcpy(ip, &buffer[12], 4); memcpy(&buffer[12], &buffer[16], 4); memcpy(&buffer[16], ip, 4); buffer[20] = 0; *((unsigned short *)&buffer[22]) += 8; // 發包 nread = write(tun_fd, buffer, nread); printf("Write %d bytes to tun/tap device, that's %s\n", nread, buffer); } return 0; }

下面測試一下。

2.3 給 tap/tun 設備配置 IP 地址

編譯:

 
Copy
[root@localhost coding]# gcc -o taptun taptun.c [root@localhost coding]# ./taptun Open tun/tap device: tun0 for reading...

開另一個終端,查看生成了?tun0?接口:

 
Copy
[root@localhost coding]# ip a 6: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN qlen 500 link/none

給?tun0?接口配置 IP 并啟用,比如?10.1.1.2/24

 
Copy
[root@localhost ~]# ip a a 10.1.1.2/24 dev tun0 [root@localhost ~]# ip l s tun0 up

再開一個終端,用?tcpdump?抓?tun0?的包。

 
Copy
[root@localhost ~]# tcpdump -nnt -i tun0

然后在第二個終端?ping?一下?10.1.1.0/24?網段的 IP,比如?10.1.1.3,看到:

 
Copy
[root@localhost ~]# ping -c 4 10.1.1.3 PING 10.1.1.3 (10.1.1.3) 56(84) bytes of data. 64 bytes from 10.1.1.3: icmp_seq=1 ttl=64 time=0.133 ms 64 bytes from 10.1.1.3: icmp_seq=2 ttl=64 time=0.188 ms 64 bytes from 10.1.1.3: icmp_seq=3 ttl=64 time=0.092 ms 64 bytes from 10.1.1.3: icmp_seq=4 ttl=64 time=0.110 ms --- 10.1.1.3 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3290ms rtt min/avg/max/mdev = 0.092/0.130/0.188/0.038 ms

由于?tun0?接口建好之后,會生成一條到本網段?10.1.1.0/24?的默認路由,根據默認路由,數據包會走?tun0?口,所以能 ping 通,可以用?route -n?查看。

再看 tcpdump 抓包終端,成功顯示 ICMP 的 request 包和 reply 包。

 
Copy
[root@localhost ~]# tcpdump -nnt -i tun0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 3250, seq 1, length 64 IP 10.1.1.3 > 10.1.1.2: ICMP echo reply, id 3250, seq 1, length 64 IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 3250, seq 2, length 64 IP 10.1.1.3 > 10.1.1.2: ICMP echo reply, id 3250, seq 2, length 64

再看程序?taptun.c?的輸出:

 
Copy
[root@localhost coding]# ./taptun Open tun/tap device: tun0 for reading... Read 48 bytes from tun/tap device Write 48 bytes to tun/tap device Read 48 bytes from tun/tap device Write 48 bytes to tun/tap device

ok,以上便驗證了程序的正確性。

03 總結

通過這個小例子,讓我們知道了基于 tap/tun 編程的流程,對 tap/tun 又加深了一層理解。

使用 tap/tun 設備需要包含頭文件?#include <linux/if_tun.h>,以下是完整代碼。

 
Copy
/****************************************************************************** * File Name: taptun.c * Author: 公眾號: CloudDeveloper * Created Time: 2019年02月23日 星期六 21時28分24秒 *****************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <net/if.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <linux/if_tun.h> int tun_alloc(char *dev, int flags) { assert(dev != NULL); struct ifreq ifr; int fd, err; char *clonedev = "/dev/net/tun"; if ((fd = open(clonedev, O_RDWR)) < 0) { return fd; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = flags; if (*dev != '\0') { strncpy(ifr.ifr_name, dev, IFNAMSIZ); } if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) { close(fd); return err; } // 一旦設備開啟成功,系統會給設備分配一個名稱,對于tun設備,一般為tunX,X為從0開始的編號; // 對于tap設備,一般為tapX strcpy(dev, ifr.ifr_name); return fd; } int main() { int tun_fd, nread; char buffer[4096]; char tun_name[IFNAMSIZ]; tun_name[0] = '\0'; /* Flags: IFF_TUN - TUN device (no Ethernet headers) * IFF_TAP - TAP device * IFF_NO_PI - Do not provide packet information */ tun_fd = tun_alloc(tun_name, IFF_TUN | IFF_NO_PI); if (tun_fd < 0) { perror("Allocating interface"); exit(1); } printf("Open tun/tap device: %s for reading...\n", tun_name); while (1) { unsigned char ip[4]; // 收包 nread = read(tun_fd, buffer, sizeof(buffer)); if (nread < 0) { perror("Reading from interface"); close(tun_fd); exit(1); } printf("Read %d bytes from tun/tap device\n", nread); // 簡單對收到的包調換一下順序 memcpy(ip, &buffer[12], 4); memcpy(&buffer[12], &buffer[16], 4); memcpy(&buffer[16], ip, 4); buffer[20] = 0; *((unsigned short *)&buffer[22]) += 8; // 發包 nread = write(tun_fd, buffer, nread); printf("Write %d bytes to tun/tap device, that's %s\n", nread, buffer); } return 0; } 原文地址https://www.cnblogs.com/bakari/p/10474600.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/449254.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/449254.shtml
英文地址,請注明出處:http://en.pswp.cn/news/449254.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2020-3-21

題目一&#xff1a; JavaScript 獲取月份最后一天日期 月份最后一天日期可能是不同的&#xff0c;比如有的是30、有的是31還有的是28。 <!DOCTYPE html><html> <head> <meta charset" utf-8"> <script type"text/javascript"&…

正方形矩陣求對角線之和

nint(input()) a[] for i in range(n): #循環體里面加入input&#xff08;&#xff09;可以實現一共執行n次input&#xff08;&#xff09; lst[int(x) for x in input().split()]a.append(lst) #用列表解析&#xff0c;兩層列表代表行列&#xff0c;很巧妙的方法 w0 bl…

解決: Unable to connect to zookeeper server within timeout: 5000

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 一個項目啟動不起來了&#xff0c;報錯如題&#xff1a; Caused by: org.I0Itec.zkclient.exception.ZkTimeoutException: Unable to c…

閑錢請看如何處理

買一點基金定投。基金是專家幫你理財。基金的起始資金最低單筆是1000元,定投200元起投 買基金到銀行或者基金公司都行。銀行能代理很多基金公司的業務&#xff0c;具體開戶找銀行理財專柜辦理。現在有些證券公司也有代理基金買賣的。在銀行開通網上銀行后網上購買一般收費上有優…

JAVA 數組元素的反轉

package Code411;/*數組元素的反轉本來[1,2,3,4]反轉后[4,3,2,1]1.對稱位置的元素交換2.對稱位子需要兩個索引3.int temp a&#xff1b;ab;btemp;4.什么時候停止交換&#xff08;1&#xff09;minmax (2)min>max */public class CodeArrayReverse { public static void m…

requests模塊相關用法

requests模塊 -1. 什么是requests模塊- python原生的一個基于網絡請求的模塊&#xff0c;模擬瀏覽器發起請求。 -2. 為什么使用requests模塊-1. 自動處理url編碼-2. 自動處理post請求參數-3. 簡化cookie和代理的操作-3. requests模塊如何被使用安裝&#xff1a; pip install re…

2020-3-22

題目一&#xff1a; JavaScript 天小時分鐘和秒倒計時 代碼與解析&#xff1a; <!DOCTYPE html> <html> <head> <meta charset" utf-8"> <style type"text/css"> *{margin:0;padding:0;list-style:none; } body{font-size:…

TeamViewer13 -- 安裝、使用說明

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 Teamviewer13是一款強大的遠程桌面控制工具&#xff0c;同時也是一款非常實用的共享文件傳輸工具&#xff0c;它擁有簡潔的界面以及方便快…

論程序員的自我修煉

摘要&#xff1a;軟件開發是個挑戰&#xff0c;尤其是對于那些完美主義的程序員。為了想要成為更好的程序員&#xff0c;總會開發出一些特別的功能&#xff0c;在軟件設計上想要做到零瑕疵&#xff0c;但事實上&#xff0c;完美的軟件設計是根本不存在的&#xff0c;試著讓你的…

利用 Charles Proxy 下載舊版本 iOS App

一、軟件準備 1、舊版本 iTunes1.IPSW Downloads&#xff1a;https://ipsw.me/2.百度網盤鏈接&#xff1a;https://pan.baidu.com/s/1PO9Z12o-rqZ_JG68zRqEnA 提取碼&#xff1a;fe1v 2、抓包工具 Charles Proxy1.Charles官網鏈接&#xff1a;https://www.charlesproxy.com/2.百…

禪道8.2-9.2.1注入GetShell

漏洞分析附上某老哥的漏洞分析&#xff0c;來了解下原理。 漏洞利用查看版本&#xff1a;訪問Url&#xff1a;http://127.0.0.1/zentao/index.php?modegetconfig即可獲取禪道的版本號以及一些其他的信息&#xff0c;目前漏洞存在于v8.2~v9.2確定版本號之后&#xff0c;我們就…

2020-3-23

題目一&#xff1a; JavaScript 復選框全選和全不選 <!DOCTYPE html> <html> <head> <meta charset" utf-8"> <style type"text/css"> body{font-size:12px;} ul{list-style:none} </style> <script type"te…

Maven 依賴-鏡像倉庫替換為 -- 阿里云鏡像倉庫(飛快實現 pom 引入)

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 在本地 maven 的 setting 配置文件中加上阿里云鏡像地址就行了&#xff1a; 新增配置內容&#xff1a; <!-- 阿里鏡像倉庫 --><…

cmake 常用命令

1. 使用日期 # 獲取時間 string(TIMESTAMP DATE_TIME "%y-%m-%d %H:%M")# 獲取日期 string(TIMESTAMP DATE_VERSION "%m%d") 轉載于:https://www.cnblogs.com/ziyu-trip/p/10697309.html

愛屋吉屋病死后,鏈家、中原、我愛我家們卻哭不得笑不得

作為互聯網房產中介最快成長為行業獨角獸的愛屋吉屋&#xff0c;還是沒能迎來開春之暖&#xff0c;于2019年2月19日便停止了運營。對于這個享有創造中國房市273天四輪融資的奇跡、估值超過10億美元的速成獨角獸、一代“革命者”、創造世界紀錄的互聯網房產神話等多個美譽企業的…

2020-3-24

題目一&#xff1a; JavaScript 頁面跳轉效果 實現在10秒之后跳轉到指定頁面。 代碼與解析&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <script type"text/javascript"> function countDown(secs,…

清洗腎臟的絕好秘方(圖)

清洗腎臟的絕好秘方&#xff1a;只用香菜&#xff0c;可以在家里嘗試。不用花多少錢就可清洗你的腎臟。經過多年來&#xff0c;我們的腎臟過濾血液&#xff0c;排除鹽&#xff0c;毒素及所有不需要的物質進入我們的身體。隨著時日&#xff0c;鹽毒積累&#xff0c;這需要進行清…

列表 字典

一、列表 1.定義&#xff1a; stus ["s1","s2","s3","s4","s5","s6","s7"] #List 列表 數組用中括號定義&#xff0c;逗號隔開 stus2 [] #空的列表stus3 list() #空的列表 【定義空的列表便于往里…

MySQL執行外部sql腳本文件的命令( source命令執行sql )

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 sql腳本是包含一到多個sql命令的sql語句&#xff0c;我們可以將這些sql腳本放在一個文本文件中&#xff08;我們稱之為“sql腳本文件”&…

【案例】數據量猛增,BI分析效率太低怎么破?

2019獨角獸企業重金招聘Python工程師標準>>> 近日&#xff0c;Apache Kylin Innovation Meetup 在上海成功舉辦&#xff0c;有近200位小伙伴來到了現場。此次會議特別邀請到了金融、互聯網等行業的技術伙伴分享了 Kylin 在行業中的實操應用 。今天將首先與大家分享演…