欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

什么是linux tun設(shè)備

Linux TUN 設(shè)備是一種虛擬網(wǎng)絡(luò)設(shè)備,用于在用戶空間和內(nèi)核空間之間建立數(shù)據(jù)通道,使用戶空間程序可以通過(guò)這個(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ā)送到用戶空間??梢允瞻l(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í),用戶空間程序通常會(huì)打開(kāi) TUN 設(shè)備文件,并像讀寫(xiě)普通文件一樣對(duì)其進(jìn)行讀寫(xiě)操作。這樣,用戶空間程序就可以將網(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ò)管理工具來(lái)創(chuàng)建 TUN 設(shè)備。
  • 用戶空間應(yīng)用程序與 TUN 設(shè)備交互: 用戶空間的應(yīng)用程序通常會(huì)打開(kāi) TUN 設(shè)備文件,這類(lèi)似于打開(kāi)普通文件。例如,應(yīng)用程序可以打開(kāi) /dev/net/tun 設(shè)備文件。
  • 數(shù)據(jù)包傳輸: 當(dāng)用戶空間的應(yīng)用程序向 TUN 設(shè)備文件寫(xiě)入數(shù)據(jù)包時(shí),數(shù)據(jù)包將被發(fā)送到內(nèi)核空間的 TUN 設(shè)備驅(qū)動(dòng)程序。這個(gè)過(guò)程是由內(nèi)核的 TUN/TAP 驅(qū)動(dòng)來(lái)完成的。
  • 內(nèi)核處理: 內(nèi)核中的 TUN/TAP 驅(qū)動(dòng)程序接收從用戶空間傳入的數(shù)據(jù)包。對(duì)于 TUN 設(shè)備,它會(huì)將數(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ū)動(dòng)程序。
  • 用戶空間讀取: 數(shù)據(jù)包通過(guò) TUN 設(shè)備驅(qū)動(dòng)程序傳遞到用戶空間的應(yīng)用程序打開(kāi)的 TUN 設(shè)備文件。應(yīng)用程序可以讀取這些數(shù)據(jù)包并進(jìn)行處理。

如下是框架流程圖:

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

  • VPN(Virtual Private Network): TUN 設(shè)備可用于構(gòu)建 VPN。通過(guò)將數(shù)據(jù)包從用戶空間發(fā)送到內(nèi)核空間,再通過(guò)TUN 設(shè)備進(jìn)行加密、隧道封裝和傳輸,可以實(shí)現(xiàn)安全的遠(yuǎn)程訪問(wèn)和數(shù)據(jù)傳輸。
  • 隧道技術(shù): TUN 設(shè)備也可用于其他隧道技術(shù),如隧道模式下的 IPv6-over-IPv4 和 IPv4-over-IPv6 隧道。它允許不同網(wǎng)絡(luò)之間通過(guò)隧道進(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ò)測(cè)試和仿真: 利用 TUN 設(shè)備,可以在用戶空間中模擬網(wǎng)絡(luò)環(huán)境,用于測(cè)試和仿真網(wǎng)絡(luò)應(yīng)用程序的性能和穩(wěn)定性。

本文今天要完成什么?

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

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

完成框架

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

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

ubuntu:/dev/net$ ls 
tun

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

基本邏輯:

  • 打開(kāi)虛擬設(shè)備網(wǎng)卡
  • 添加靜態(tài)路由
  • 阻塞等待數(shù)據(jù)的到來(lái)
  • 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頭部長(zhǎng)度,單位為字節(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");//啟動(dòng)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ù)包,通過(guò)網(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頭部長(zhǎng)度 + 應(yīng)用層數(shù)據(jù)長(zhǎng)度        
            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ā)送來(lái)的信息
            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 頭部長(zhǎng)度 + ICMP 數(shù)據(jù)長(zhǎng)度
            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)核會(huì)自動(dòng)計(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 類(lèi)型為 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)識(shí)符高位字節(jié)
            icmp_data[5] = 0x34; // 標(biāo)識(shí)符低位字節(jié)
            icmp_data[6] = 0; // 序列號(hào)高位字節(jié)
            icmp_data[7] = 0; // 序列號(hào)低位字節(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ù)包寫(xiě)入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ū)動(dòng)發(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)該問(wèn)出這樣的問(wèn)題,以前的文章都有提及!

驗(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ā)來(lái)的數(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)文章

  • centos中yum命令刪除還原的補(bǔ)救方法介紹

    centos中yum命令刪除還原的補(bǔ)救方法介紹

    Yum: 即Yellowdog Update Modifier,是一種基于rpm的包管理工具,這篇文章主要給大家介紹了關(guān)于在centos中yum命令刪除還原的補(bǔ)救方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • CentOS 7安裝Mysql并設(shè)置開(kāi)機(jī)自啟動(dòng)的方法

    CentOS 7安裝Mysql并設(shè)置開(kāi)機(jī)自啟動(dòng)的方法

    本篇文章主要介紹了CentOS 7安裝Mysql并設(shè)置開(kāi)機(jī)自啟動(dòng)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • centos7下安裝oracle11gR2的詳細(xì)步驟

    centos7下安裝oracle11gR2的詳細(xì)步驟

    本篇文章主要介紹了centos7下安裝oracle11gR2的詳細(xì)步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • 深入理解apahce的工作模式perfork、worker

    深入理解apahce的工作模式perfork、worker

    本文介紹下,apache的兩種工作模式perfork與worker,就它們的區(qū)別進(jìn)行深入分析,供大家學(xué)習(xí)參考
    2013-06-06
  • telnet?Connection?refused端口不通如何處理

    telnet?Connection?refused端口不通如何處理

    本文介紹了telnet命令的基本用途及排查telnet連接拒絕的處理思路,telnet主要用于測(cè)試網(wǎng)絡(luò)連接,如遇到連接問(wèn)題,可能是由于防火墻未開(kāi)放或目的主機(jī)服務(wù)未啟動(dòng),文章通過(guò)實(shí)際例子解釋了telnet命令的作用,并提供了解決網(wǎng)絡(luò)連接問(wèn)題的方法
    2024-10-10
  • 詳解Linux(Centos)之安裝Nginx及注意事項(xiàng)

    詳解Linux(Centos)之安裝Nginx及注意事項(xiàng)

    Nginx是一個(gè)高性能的HTTP和反向代理服務(wù)器,這篇文章主要介紹了詳解Linux(Centos)之安裝Nginx及注意事項(xiàng),有興趣的可以了解一下。
    2017-03-03
  • CentOS7升級(jí)內(nèi)核kernel5.0版本

    CentOS7升級(jí)內(nèi)核kernel5.0版本

    這篇文章主要介紹了CentOS7升級(jí)內(nèi)核kernel5.0版本,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Apache中的Order Allow,Deny用法詳解

    Apache中的Order Allow,Deny用法詳解

    這篇文章主要介紹了Apache中的Order Allow,Deny用法,結(jié)合實(shí)例較為詳細(xì)的分析了Apache中Order Allow,Deny的具體作用及使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-12-12
  • linux下如何安裝nginx

    linux下如何安裝nginx

    這篇文章主要介紹了linux下如何安裝nginx問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Apache 開(kāi)通子站點(diǎn)配置方法

    Apache 開(kāi)通子站點(diǎn)配置方法

    前一段時(shí)間突發(fā)奇想,想自己給自己做個(gè)記錄系統(tǒng),暫且就叫他記錄系統(tǒng)吧。其實(shí)木的就是記錄一些亂七八糟的事情,譬如,賬簿,記事本之類(lèi)的
    2012-06-06

最新評(píng)論