最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux tun虛擬網(wǎng)卡通信的使用解讀

 更新時(shí)間:2025年05月28日 09:52:16   作者:wifi chicken  
這篇文章主要介紹了Linux tun虛擬網(wǎng)卡通信的使用,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

什么是linux tun設(shè)備

Linux TUN 設(shè)備是一種虛擬網(wǎng)絡(luò)設(shè)備,用于在用戶空間和內(nèi)核空間之間建立數(shù)據(jù)通道,使用戶空間程序可以通過這個(gè)設(shè)備與內(nèi)核網(wǎng)絡(luò)棧進(jìn)行交互。TUN 設(shè)備是一種通用的網(wǎng)絡(luò)隧道設(shè)備,常用于實(shí)現(xiàn)虛擬專用網(wǎng)絡(luò)(VPN)和其他網(wǎng)絡(luò)隧道技術(shù)。

TUN 設(shè)備的工作原理

將網(wǎng)絡(luò)數(shù)據(jù)包從用戶空間發(fā)送到內(nèi)核空間,或者從內(nèi)核空間發(fā)送到用戶空間。可以收發(fā)第三層數(shù)據(jù)報(bào)文包,如IP封包,這使得用戶空間的應(yīng)用程序可以讀取和處理傳入的數(shù)據(jù)包,然后將數(shù)據(jù)包發(fā)送回TUN 設(shè)備,再由內(nèi)核負(fù)責(zé)將數(shù)據(jù)包發(fā)送到目標(biāo)地址。

在使用 TUN 設(shè)備時(shí),用戶空間程序通常會打開 TUN 設(shè)備文件,并像讀寫普通文件一樣對其進(jìn)行讀寫操作。這樣,用戶空間程序就可以將網(wǎng)絡(luò)數(shù)據(jù)包發(fā)送到 TUN 設(shè)備或者從 TUN 設(shè)備讀取接收到的數(shù)據(jù)包。TUN 設(shè)備通常具有一個(gè)虛擬的 IP 地址,作為與內(nèi)核網(wǎng)絡(luò)棧進(jìn)行交互的入口和出口

基本處理框架

  • 創(chuàng)建 TUN 設(shè)備: 在 Linux 系統(tǒng)中,可以使用 ip 命令或者其他網(wǎng)絡(luò)管理工具來創(chuàng)建 TUN 設(shè)備。
  • 用戶空間應(yīng)用程序與 TUN 設(shè)備交互: 用戶空間的應(yīng)用程序通常會打開 TUN 設(shè)備文件,這類似于打開普通文件。例如,應(yīng)用程序可以打開 /dev/net/tun 設(shè)備文件。
  • 數(shù)據(jù)包傳輸: 當(dāng)用戶空間的應(yīng)用程序向 TUN 設(shè)備文件寫入數(shù)據(jù)包時(shí),數(shù)據(jù)包將被發(fā)送到內(nèi)核空間的 TUN 設(shè)備驅(qū)動程序。這個(gè)過程是由內(nèi)核的 TUN/TAP 驅(qū)動來完成的。
  • 內(nèi)核處理: 內(nèi)核中的 TUN/TAP 驅(qū)動程序接收從用戶空間傳入的數(shù)據(jù)包。對于 TUN 設(shè)備,它會將數(shù)據(jù)包解析為 IP 數(shù)據(jù)包,并將其發(fā)送到內(nèi)核網(wǎng)絡(luò)棧進(jìn)行進(jìn)一步處理。
  • 數(shù)據(jù)包處理: 在內(nèi)核網(wǎng)絡(luò)棧中,數(shù)據(jù)包將按照路由表和網(wǎng)絡(luò)配置進(jìn)行處理。如果數(shù)據(jù)包的目標(biāo)地址與本地網(wǎng)絡(luò)或者路由表匹配,那么數(shù)據(jù)包將被內(nèi)核轉(zhuǎn)發(fā)到目標(biāo)地址。
  • 接收數(shù)據(jù)包: 當(dāng)內(nèi)核收到其他網(wǎng)絡(luò)設(shè)備傳入的數(shù)據(jù)包(如網(wǎng)絡(luò)接口收到的數(shù)據(jù)包),如果目標(biāo)地址是 TUN 設(shè)備的 IP 地址,那么數(shù)據(jù)包將被傳遞給 TUN 設(shè)備驅(qū)動程序。
  • 用戶空間讀取: 數(shù)據(jù)包通過 TUN 設(shè)備驅(qū)動程序傳遞到用戶空間的應(yīng)用程序打開的 TUN 設(shè)備文件。應(yīng)用程序可以讀取這些數(shù)據(jù)包并進(jìn)行處理。

如下是框架流程圖:

linux tun設(shè)備可以用作什么技術(shù)

  • VPN(Virtual Private Network): TUN 設(shè)備可用于構(gòu)建 VPN。通過將數(shù)據(jù)包從用戶空間發(fā)送到內(nèi)核空間,再通過TUN 設(shè)備進(jìn)行加密、隧道封裝和傳輸,可以實(shí)現(xiàn)安全的遠(yuǎn)程訪問和數(shù)據(jù)傳輸。
  • 隧道技術(shù): TUN 設(shè)備也可用于其他隧道技術(shù),如隧道模式下的 IPv6-over-IPv4 和 IPv4-over-IPv6 隧道。它允許不同網(wǎng)絡(luò)之間通過隧道進(jìn)行通信。
  • 加密通信: TUN 設(shè)備可以用于實(shí)現(xiàn)端到端的加密通信,保護(hù)數(shù)據(jù)的安全性和隱私。
  • 虛擬專用網(wǎng)絡(luò): 使用 TUN 設(shè)備,可以創(chuàng)建虛擬專用網(wǎng)絡(luò)(VPN)或虛擬局域網(wǎng)(VLAN),將不同的網(wǎng)絡(luò)或子網(wǎng)連接在一起。
  • 網(wǎng)絡(luò)隔離: TUN 設(shè)備可以用于實(shí)現(xiàn)網(wǎng)絡(luò)隔離,將不同的應(yīng)用程序或服務(wù)隔離在不同的虛擬網(wǎng)絡(luò)中,增強(qiáng)網(wǎng)絡(luò)的安全性。
  • 協(xié)議代理: TUN 設(shè)備還可以用作協(xié)議代理,允許用戶空間應(yīng)用程序處理特定的網(wǎng)絡(luò)協(xié)議,例如將 UDP 或 TCP 流量進(jìn)行自定義處理。
  • 網(wǎng)絡(luò)測試和仿真: 利用 TUN 設(shè)備,可以在用戶空間中模擬網(wǎng)絡(luò)環(huán)境,用于測試和仿真網(wǎng)絡(luò)應(yīng)用程序的性能和穩(wěn)定性。

本文今天要完成什么?

使用虛擬機(jī)ubuntu 自帶tun驅(qū)動完成:

  • 虛擬驅(qū)動的啟動
  • 應(yīng)用層發(fā)包給虛擬網(wǎng)卡驅(qū)動tun并寫入設(shè)備節(jié)點(diǎn)文件,應(yīng)用層完成讀取,加密,寫入設(shè)備節(jié)點(diǎn)并發(fā)送給協(xié)議棧
  • 使用tcpdump工具抓取包驗(yàn)證是否正確發(fā)送與接收

完成框架

  • 利用已有的tun設(shè)備驅(qū)動,打開并配置ip,添加靜態(tài)路由表
  • 寫兩個(gè)應(yīng)用層進(jìn)程,分別完成數(shù)據(jù)發(fā)送到tun和數(shù)據(jù)接收處理加密并發(fā)回tun驅(qū)動

linux已經(jīng)自帶驅(qū)動:

ubuntu:/dev/net$ ls 
tun

應(yīng)用層代碼1:

基本邏輯:

  • 打開虛擬設(shè)備網(wǎng)卡
  • 添加靜態(tài)路由
  • 阻塞等待數(shù)據(jù)的到來
  • read后,再進(jìn)行wirite操作
#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>
#include<stdlib.h>
#include<stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define IP_VERSION 4
#define IP_HEADER_LENGTH 20 // IPv4頭部長度,單位為字節(jié)
#define DEST_IP "10.0.0.2"

struct iphdr {
    unsigned char  ihl_version;
    unsigned char  tos;
    unsigned short total_length;
    unsigned short id;
    unsigned short frag_off;
    unsigned char  ttl;
    unsigned char  protocol;
    unsigned short checksum;
    unsigned int   saddr;
    unsigned int   daddr;
};
int tun_alloc(int flags)
{
    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 ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
        close(fd);
        return err;
    }
    system("sudo ifconfig tun0 10.0.0.1 up");//啟動tun虛擬網(wǎng)卡
    system("sudo route add -net 10.0.0.2 netmask 255.255.255.255 dev tun0");//將所有發(fā)送到 10.0.0.2 的數(shù)據(jù)包,通過網(wǎng)絡(luò)接口 "tun0" 進(jìn)行傳輸,而且這個(gè)目標(biāo)地址被視為一個(gè)單獨(dú)的主機(jī),而不是一個(gè)整個(gè)網(wǎng)絡(luò)。
    system("sudo route add -net 192.168.6.1 netmask 255.255.255.255 dev tun0");
    printf("Open tun/tap device: %s for reading...\n", ifr.ifr_name);

    return fd;
}

int main()
{

            int tun_fd, nread;
            char buffer[1500];
            char buffer1[IP_HEADER_LENGTH + 100]; // IP頭部長度 + 應(yīng)用層數(shù)據(jù)長度        
            tun_fd = tun_alloc(IFF_TUN | IFF_NO_PI);
            if (tun_fd < 0) 
            {
            perror("Allocating interface");
            exit(1);
            }
while (1) {
            //發(fā)送數(shù)據(jù)包到TUN/TAP設(shè)備
            memset(buffer,0,sizeof(buffer));
            //讀取協(xié)議棧發(fā)送來的信息
            nread = read(tun_fd, buffer, sizeof(buffer));
            if (nread < 0) {
            close(tun_fd);
            exit(1);
            }
            printf("Read %zd bytes from tun/tap device\n", nread);
            // 以十六進(jìn)制格式輸出IP數(shù)據(jù)包
            for (int i = 0; i < nread; i++) {
            printf("%02X ", buffer[i]);
            if ((i + 1) % 16 == 0) {
            printf("\n");
            }
            }
            printf("\n");
            // 構(gòu)造 IP 數(shù)據(jù)包頭部,此處就可以進(jìn)行數(shù)據(jù)加密,具體的功能未完成,可自行加密處理
            struct iphdr *ip_header = (struct iphdr *)buffer1;
            ip_header->ihl_version = (IP_VERSION << 4) | (IP_HEADER_LENGTH / 4);
            ip_header->tos = 0;
            ip_header->total_length = htons(IP_HEADER_LENGTH + 8); // IP 頭部長度 + ICMP 數(shù)據(jù)長度
            ip_header->id = 0;
            ip_header->frag_off = 0;
            ip_header->ttl = 64;
            ip_header->protocol = 1;//IPPROTO_ICMPCMP 協(xié)議
            ip_header->checksum = 0; // 留空,內(nèi)核會自動計(jì)算校驗(yàn)和
            ip_header->saddr = inet_addr("10.0.0.1"); // 源 IP 地址
            ip_header->daddr = inet_addr("14.0.0.2"); // 目標(biāo) IP 地址

            // 添加 ICMP 數(shù)據(jù)
            char *icmp_data = buffer1 + IP_HEADER_LENGTH;
            icmp_data[0] = 8; // ICMP 類型為 8(Echo Request)
            icmp_data[1] = 0; // ICMP 代碼為 0
            icmp_data[2] = 0; // 校驗(yàn)和高位字節(jié)
            icmp_data[3] = 0; // 校驗(yàn)和低位字節(jié)
            icmp_data[4] = 0x12; // 標(biāo)識符高位字節(jié)
            icmp_data[5] = 0x34; // 標(biāo)識符低位字節(jié)
            icmp_data[6] = 0; // 序列號高位字節(jié)
            icmp_data[7] = 0; // 序列號低位字節(jié)

            // 計(jì)算 ICMP 校驗(yàn)和
            unsigned short checksum = 0;
            for (int i = 0; i < 8; i += 2) {
            checksum += (icmp_data[i] << 8) | icmp_data[i + 1];
            }
            checksum = (checksum >> 16) + (checksum & 0xFFFF);
            checksum = ~checksum;
            icmp_data[2] = (checksum >> 8) & 0xFF;
            icmp_data[3] = checksum & 0xFF;
            // 將數(shù)據(jù)包寫入TUN設(shè)備的設(shè)備節(jié)點(diǎn)
            ssize_t num_bytes_sent = write(tun_fd, buffer1, IP_HEADER_LENGTH + 8);

            if (num_bytes_sent < 0) {
            perror("write");
            close(tun_fd);
            return -1;
            }
            printf("Sent %zd bytes to TUN device.\n", num_bytes_sent);
            }
            close(tun_fd);
            return 0;
}

應(yīng)用層2代碼

基本邏輯:

負(fù)責(zé)給虛擬網(wǎng)卡驅(qū)動發(fā)送應(yīng)用層數(shù)據(jù)包

#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>
#include<stdlib.h>
#include<stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define DEST_IP "10.0.0.2"
#define DEST_IP1 "192.168.6.1"


int main()
{

// 創(chuàng)建套接字
            int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if (sockfd < 0) {
            perror("Error creating socket");
            //close(tun_fd);
            exit(1);
            }
            sleep(5);
            // 設(shè)置目標(biāo) IP 地址和端口
            printf("------------start-------------------\n");
            struct sockaddr_in dest_addr;
            memset(&dest_addr, 0, sizeof(dest_addr));
            dest_addr.sin_family = AF_INET;
            dest_addr.sin_port = htons(12345);
            inet_pton(AF_INET, DEST_IP, &(dest_addr.sin_addr));

            // 模擬發(fā)送數(shù)據(jù)到 TUN 設(shè)備
            const char* message = "Hello, TUN device!!!!!";

            int sockfd1 = socket(AF_INET, SOCK_DGRAM, 0);
            if (sockfd1 < 0) {
            perror("Error creating socket");
            //close(tun_fd);
            exit(1);
            }
            sleep(5);
            // 設(shè)置目標(biāo) IP 地址和端口
            printf("------------start-------------------\n");
            struct sockaddr_in dest_addr1;
            memset(&dest_addr1, 0, sizeof(dest_addr1));
            dest_addr1.sin_family = AF_INET;
            dest_addr1.sin_port = htons(1234);
            inet_pton(AF_INET, DEST_IP1, &(dest_addr1.sin_addr));

            // 模擬發(fā)送數(shù)據(jù)到 TUN 設(shè)備
            const char* message1 = "tun tunt tunt!!!!!!";

            while(1)
            {
            sendto(sockfd1, message1, strlen(message1), 0, (struct sockaddr*)&dest_addr1, sizeof(dest_addr1));        
               sleep(5);
               sendto(sockfd, message, strlen(message), 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));
            }
            close(sockfd);
            close(sockfd1);
  
}

應(yīng)用層如何編譯

如果您經(jīng)常閱讀我的文章,就不應(yīng)該問出這樣的問題,以前的文章都有提及!

驗(yàn)證

root權(quán)限執(zhí)行應(yīng)用層代碼1結(jié)果(有刪減):

sudo ./net_device_user1
RTNETLINK answers: File exists
Open tun/tap device: tun0 for reading...

Read 50 bytes from tun/tap device
45 00 00 32 03 FFFFFF9E 40 00 40 11 23 1B 0A 00 00 01 
0A 00 00 02 FFFFFF86 0D 30 39 00 1E 05 27 48 65 6C 6C 
6F 2C 20 54 55 4E 20 64 65 76 69 63 65 21 21 21 
21 21 
Sent 28 bytes to TUN device.
Read 47 bytes from tun/tap device
45 00 00 2F 03 FFFFFF9F 40 00 40 11 23 1D 0A 00 00 01 
0A 00 00 02 FFFFFFC0 3E 04 FFFFFFD2 00 1B FFFFFFF3 FFFFFFDE 74 75 6E 20 
74 75 6E 74 20 74 75 6E 74 21 21 21 21 21 21 
Sent 28 bytes to TUN device.

root權(quán)限執(zhí)行應(yīng)用層代碼2結(jié)果

sudo ./net_device.o
------------start-------------------

抓取tupdump包

sudo tcpdump -i tun0 -w tcpdump_30.pcap
tcpdump: listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
tcpdump: pcap_loop: The interface went down
16 packets captured
16 packets received by filter
0 packets dropped by kernel

分別抓到了應(yīng)用層發(fā)來的數(shù)據(jù)包(兩個(gè)包),讀取完后完成數(shù)據(jù)包的發(fā)送

利用十六進(jìn)制轉(zhuǎn)字符串驗(yàn)證應(yīng)用代碼2發(fā)送給應(yīng)用代碼1的數(shù)據(jù)是否發(fā)送成功:

  • 第一個(gè)包
Read 50 bytes from tun/tap device
45 00 00 32 03 FFFFFF9E 40 00 40 11 23 1B 0A 00 00 01 
0A 00 00 02 FFFFFF86 0D 30 39 00 1E 05 27 48 65 6C 6C 
6F 2C 20 54 55 4E 20 64 65 76 69 63 65 21 21 21 
21 21

其中的data數(shù)據(jù)轉(zhuǎn)化結(jié)果:

  • 第二個(gè)包
Read 47 bytes from tun/tap device
45 00 00 2F 03 FFFFFF9F 40 00 40 11 23 1D 0A 00 00 01 
0A 00 00 02 FFFFFFC0 3E 04 FFFFFFD2 00 1B FFFFFFF3 FFFFFFDE 74 75 6E 20 
74 75 6E 74 20 74 75 6E 74 21 21 21 21 21 21 

結(jié)果

驗(yàn)證成功

ps:

  • 完成的功能很少,希望這能拋磚引玉
  • 代碼解釋不是特別詳細(xì),代碼行中有很多注釋,希望能幫助到你

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • centos7搭建hadoop2.10高可用(HA)

    centos7搭建hadoop2.10高可用(HA)

    這篇文章主要介紹了centos7搭建hadoop2.10高可用(HA),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • linux連接不上服務(wù)器卻能ping通的解決

    linux連接不上服務(wù)器卻能ping通的解決

    這篇文章主要介紹了linux連接不上服務(wù)器卻能ping通的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Linux進(jìn)程池實(shí)現(xiàn)的詳細(xì)指南

    Linux進(jìn)程池實(shí)現(xiàn)的詳細(xì)指南

    如果你了解過STL的底層設(shè)計(jì),你會發(fā)現(xiàn)在其中會有一個(gè)叫做內(nèi)存池的設(shè)計(jì),其作用就是先申請出一片空間,如果后續(xù)你需要對你的容器進(jìn)行擴(kuò)容,所擴(kuò)展的空間就從內(nèi)存池里取的,本文給大家介紹了Linux進(jìn)程池實(shí)現(xiàn)的詳細(xì)指南,需要的朋友可以參考下
    2024-11-11
  • linux的CPU、內(nèi)存查看命令方式

    linux的CPU、內(nèi)存查看命令方式

    這篇文章主要介紹了linux的CPU、內(nèi)存查看命令方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-07-07
  • linux之如何查找包含指定關(guān)鍵字的文件

    linux之如何查找包含指定關(guān)鍵字的文件

    這篇文章主要介紹了linux之如何查找包含指定關(guān)鍵字的文件問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • ubuntu如何開啟ssh遠(yuǎn)程登錄

    ubuntu如何開啟ssh遠(yuǎn)程登錄

    在Ubuntu上開啟SSH遠(yuǎn)程登錄的步驟如下:檢查SSH安裝情況、啟動SSH服務(wù)、設(shè)置開機(jī)啟動、檢查SSH狀態(tài)、配置防火墻、并使用SSH客戶端進(jìn)行遠(yuǎn)程登錄
    2025-03-03
  • Linux下進(jìn)程數(shù)量的限制pid_max的配置方法

    Linux下進(jìn)程數(shù)量的限制pid_max的配置方法

    這篇文章主要介紹了Linux下進(jìn)程數(shù)量的限制pid_max的方法,非常不錯,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-07-07
  • Linux進(jìn)程使用文件進(jìn)行通信的常用方法

    Linux進(jìn)程使用文件進(jìn)行通信的常用方法

    在Linux系統(tǒng)中,進(jìn)程間通信(IPC)是構(gòu)建復(fù)雜應(yīng)用的關(guān)鍵技術(shù),使用文件進(jìn)行通信是一種簡單而有效的方法,特別適合需要持久化數(shù)據(jù)或跨系統(tǒng)邊界的場景,本文將介紹幾種主要的文件通信技術(shù)及其應(yīng)用場景,需要的朋友可以參考下
    2025-11-11
  • Linux的/etc/hosts文件的基礎(chǔ)知識和在實(shí)用指南

    Linux的/etc/hosts文件的基礎(chǔ)知識和在實(shí)用指南

    在 Linux 和 Unix 系統(tǒng)中,/etc/hosts 文件扮演著一個(gè)至關(guān)重要的角色,在網(wǎng)絡(luò)和系統(tǒng)管理中,了解如何正確使用這個(gè)文件能夠大大提升效率和靈活性,本文將深入探討 /etc/hosts 文件的用途、結(jié)構(gòu)和實(shí)際應(yīng)用,需要的朋友可以參考下
    2026-02-02
  • CentOS6.5安裝glibc-2.14后locale出現(xiàn)No?such?file?or?directory解決辦法

    CentOS6.5安裝glibc-2.14后locale出現(xiàn)No?such?file?or?directory解

    大家好,本篇文章主要講了CentOS6.5安裝glibc-2.14后locale出現(xiàn)No?such?file?or?directory解決辦法,感興趣的同學(xué)趕快來看看吧,希望對你有幫助
    2021-11-11

最新評論

彩票| 陆川县| 田东县| 双柏县| 茌平县| 鸡西市| 大荔县| 新津县| 桦南县| 民勤县| 定安县| 正定县| 江川县| 临江市| 湘阴县| 阳泉市| 垦利县| 崇明县| 得荣县| 永州市| 扎赉特旗| 沧州市| 文登市| 璧山县| 武乡县| 东兰县| 衡阳县| 万宁市| 桃江县| 旬阳县| 沙雅县| 灌阳县| 汕头市| 惠来县| 南汇区| 象州县| 襄城县| 丰城市| 廉江市| 沭阳县| 徐水县|