基于ubuntu tun虚拟网卡设备完成ping的发送与模拟接收

前言

前面我们初步认识了什么是tun设备及基础的工作原理与接收文件的设备文件(节点)、虚拟网卡的启动、添加路由表等操作,为什么进一步理解tun设备与协议栈的通信理解,这次我们将应用层控制tun设备发送ping,通过read读取到,后经过手动组装icmp网络包write到协议栈,模拟远程主机回复给我们的 icmp reply,顺便熟悉下icmp 网络包的协议。

模拟ping发送与接收有什么作用

网络测试和调试:TUN设备可以用于模拟网络环境,以测试和调试网络应用程序和协议。通过模拟Ping发送和接收,您可以检查网络连接是否正常工作,诊断延迟问题,以及测试网络拓扑。

完成事项

在ubuntu 设中使用ping指定网卡命令使得tun设备发送ping包,tun read到后,定义组装icmp reply、调用系统调用write到协议栈,通过tcpdump抓包,验证是否模拟成功

作用

  1. 提高tun 设备的发送、接收与read与write的理解。
  2. 了解ping的协议,ip header、icmp header、icmp date的定义,赋值,校验和等,协议字段的不同,导致的无法被识别为目标request 的reply,为的ping外网做技术储备。

操作列表

  1. 用于读取tun设备节点并处理数据的应用层程序,再模拟发送icmp reply包
  2. 通过ping命令使得tun设备发送icmp包
  3. tcpdump工具抓取流经tun网卡的包

验证与代码流程

  • 用于读取tun设备节点并处理数据的应用层程序,再模拟发送icmp reply包
#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>
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ip_icmp.h>


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");
    printf("Open tun/tap device: %s for reading...\n", ifr.ifr_name);

    return fd;
}
			int tun_fd, nread;
            char buffer[1500];
            char buffer7[1000];
tun_fd = tun_alloc(IFF_TUN | IFF_NO_PI);

            if (tun_fd < 0) 
            {
            perror("Allocating interface");
            exit(1);
            }
while (1) {

            //发送数据包到TUN/TAP设备
            memset(buffer,0,sizeof(buffer));
            //读取协议栈发送来的信息
            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);
            // 以十六进制格式输出IP数据包
            for (int i = 0; i < nread; i++) {
            printf("%02X ", buffer[i]);
            if ((i + 1) % 16 == 0) {
            printf("\n");
            }
            }
            printf("\n");
uint16_t calculate_checksum(uint16_t *data, int length) {
    uint32_t sum = 0;
    while (length > 1) 
    {
        sum += *data++;
        length -= 2;
    }
    if (length > 0)
    {
        sum += *((uint8_t *)data);
    }
    while (sum >> 16) 
    {
        sum = (sum & 0xFFFF) + (sum >> 16);
    }
    return (uint16_t)(~sum);
}

                memset(buffer7,0,sizeof(buffer7));
                    // 检查数据包是否为 ICMP Echo 请求
                struct iphdr *ip_header = (struct iphdr *)buffer7;
                if( buffer[20]==0x08)
    {
                struct icmphdr *icmp_header = (struct icmphdr *)(buffer7 + sizeof(struct iphdr));
                printf("--------是icmp request包-----------\n");
                printf("--------ID:%02X,%02X,seq num:%02X,%02X-----------\n",buffer[24],buffer[25],buffer[26],buffer[27]);
                unsigned char id = buffer[24];
                unsigned char se = buffer[26];
                unsigned char id1 = buffer[25];
                unsigned char se1 = buffer[27];
                unsigned short ID = ((unsigned short)id << 8 )|id1;
                unsigned short seq = ((unsigned short)se << 8 )|se1;
                printf("----------ID:%04X,seq:%04X--------------\n",ID,seq);

                // Manually construct IP header
                ip_header->version = 4;
                ip_header->ihl = 5; // Header length in 32-bit words (5 for no options)
                ip_header->tot_len = htons(sizeof(struct iphdr) + sizeof(struct icmphdr) + 56);
                ip_header->id = htons(12345); // Customize the ID if needed
                ip_header->ttl = 64; // Time to Live
                ip_header->protocol = IPPROTO_ICMP;
                ip_header->saddr = inet_addr("192.168.100.137"); // Source IP address
                ip_header->daddr = inet_addr("10.0.0.1"); // Destination IP address
                ip_header->check = 0; // Checksum (set to 0 for now, will be calculated later)
                
                // Create ICMP header for Echo Reply
                icmp_header->type = ICMP_ECHOREPLY;
                icmp_header->code = 0;
                icmp_header->checksum = 0;
                icmp_header->un.echo.id = htons(ID); // Customize the ID if needed
                icmp_header->un.echo.sequence = htons(seq);// Customize the sequence number if needed

                char *data = buffer7 + sizeof(struct iphdr) + sizeof(struct icmphdr);
                memcpy(data,&(buffer[28]),8);
                memcpy(data+8,&(buffer[36]),48);
                icmp_header->checksum = calculate_checksum((uint16_t *)icmp_header, sizeof(struct icmphdr) + 56);
                printf("------------sizeof(struct icmphdr) + sizeof(reply_data):%d--------------------\n",(sizeof(struct icmphdr) + 56));

                // 发送 ICMP Echo Reply 数据包到 TUN 设备
                ssize_t bytes_written=write(tun_fd, buffer7, (sizeof(struct icmphdr) + 56+sizeof(struct iphdr)));
                if (bytes_written < 0) {
                perror("Failed to write to TUN device");
                break;
                }
                printf("---------ICMP Echo Request sent :%d Bytes-------------\n",bytes_written);
        }
}
            close(tun_fd);
            return 0;
}

编译并执行结果
编译:

$ gcc net_device_user1.c -o net_device_user1
net_device_user1.c: In function ‘main’:
net_device_user1.c:143:28: warning: format ‘%zd’ expects argument of type ‘signed size_t’, but argument 2 has type ‘int’ [-Wformat=]
             printf("Read %zd bytes from tun/tap device\n", nread);
                          ~~^
                          %d
net_device_user1.c:401:82: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
                 printf("------------sizeof(struct icmphdr) + sizeof(reply_data):%d--------------------\n",(sizeof(struct icmphdr) + 56));
                                                                                 ~^
                                                                                 %ld
net_device_user1.c:409:59: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘ssize_t {aka long int}[-Wformat=]
                 printf("---------ICMP Echo Request sent :%d Bytes-------------\n",bytes_written);

执行结果:

$ sudo ./net_device_user1
SIOCADDRT: File exists
Open tun/tap device: tun0 for reading...
  • 通过ping命令使得tun设备发送icmp包
$ ping -I tun0 192.168.100.137
PING 192.168.100.137 (192.168.100.137) from 10.0.0.1 tun0: 56(84) bytes of data.

ping后,应用程序会有新的日志log

$ sudo ./net_device_user1
SIOCADDRT: File exists
Open tun/tap device: tun0 for reading...
Read 84 bytes from tun/tap device
45 00 00 54 2B FFFFFF8B 40 00 40 01 FFFFFFDF FFFFFFEB 0A 00 00 01 
FFFFFFC0 FFFFFFA8 64 FFFFFF89 08 00 21 FFFFFF9D 53 46 00 01 FFFFFFC2 2D FFFFFFF8 64 
00 00 00 00 FFFFFFFC FFFFFFB5 0D 00 00 00 00 00 10 11 12 13 
14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 
24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 
34 35 36 37 
--------是icmp request包-----------
--------ID:53,46,seq num:00,01-----------
----------ID:5346,seq:0001--------------
------------sizeof(struct icmphdr) + sizeof(reply_data):64--------------------
---------ICMP Echo Request sent :84 Bytes-------------
  • tcpdump工具抓取流经tun网卡的包
sudo tcpdump -i tun0 -w tcpdump.pcap
tcpdump: listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
tcpdump: pcap_loop: The interface went down
16 packets captured
18 packets received by filter
0 packets dropped by kernel

打开tcpdump包:
在这里插入图片描述
正常被协议栈识别

PS

处理icmp网络包的应用层有很多细节问题,在代码中也打印了出来,我们可以利用wireshark的二进制来确定协议与打印出来的二进制之间的关系
在这里插入图片描述

<think>好的,我现在需要帮助用户在没有外网连接的飞腾处理器主机上安装和配置TAP虚拟网卡。首先,我得确认用户的操作系统是银河麒麟V10服务器版,架构应该是ARM64的,飞腾属于ARM架构。 用户的主机没有外网,这意味着不能直接通过apt-get在线安装软件包。这种情况下,可能需要用户提前下载好所需的依赖包,或者使用安装镜像作为本地源。不过,用户可能没有配置本地源的经验,可能需要指导他们如何操作,或者是否有其他方式获取所需的包。 接下来,安装TAP虚拟网卡通常需要tun/tap驱动,这部分内核一般已经包含,但需要检查是否加载。用户可能需要加载内核模块,使用modprobe命令,比如modprobe tun。如果模块不存在,可能需要编译内核模块,但这在没有外网的情况下会比较麻烦,特别是用户可能没有编译环境所需的工具链。 然后,安装uml-utilities或类似的软件包,这些包提供了创建和管理TAP设备的工具,比如tunctl。但银河麒麟的软件源可能名称不同,或者需要特定的版本。用户需要找到对应的安装包,可能需要从其他途径获取,比如从另一台有网的机器下载,然后拷贝过来。 配置虚拟网卡部分,可能需要使用ip tuntap命令创建TAP设备,设置IP地址,启动设备。这部分步骤相对固定,但需要确保命令正确,比如ip tuntap add mode tap user [username]等。另外,配置持久化的问题,用户可能希望在重启后自动创建,这需要将命令写入/etc/rc.local或者网络配置文件中,但需要注意权限和系统服务是否启用。 权限问题也是一个关键点,用户可能需要将当前用户加入特定的组,比如允许访问TAP设备的组,或者使用sudo执行相关命令。如果权限设置不正确,可能会导致无法创建或访问TAP设备。 考虑到用户的环境没有外网,可能需要详细说明如何手动下载和传输所需的deb包,以及处理依赖关系。例如,uml-utilities可能有依赖的其他包,需要一并下载。如果用户没有这些包,可能需要寻找银河麒麟的安装镜像,里面可能包含这些软件包,然后配置本地源。 另外,银河麒麟基于Ubuntu还是CentOS?这会影响包管理器的使用。银河麒麟V10服务器版通常基于Ubuntu,所以使用apt-get,但如果是基于CentOS,则使用yum。需要确认这一点,但用户提到的是银河麒麟,可能属于Debian系,所以用apt。 总结步骤可能包括:检查内核模块,加载tun模块,安装uml-utilities,创建TAP设备,配置IP和路由,设置开机自启。但每一步都可能遇到问题,比如模块不存在,软件包缺失,权限不足等,需要给出解决方案,比如如何手动安装软件包,如何处理依赖,如何设置权限等。 需要提醒用户,如果遇到模块加载失败,可能需要检查内核版本,或者重新编译模块,但这在没有外网的情况下可能困难。如果软件包无法安装,建议用户联系系统提供商获取所需的依赖包,或者从其他来源获取兼容ARM64架构的deb包。 最后,确保命令的准确性,使用正确的语法,比如ip命令的正确参数,以及配置文件的正确位置。同时,测试步骤,比如使用ip a查看TAP设备是否出现,ping测试等,确保用户能够验证配置是否成功。</think>在银河麒麟V10服务器版(飞腾ARM64架构)离线环境下安装配置TAP虚拟网卡,可按以下步骤操作: 1. **检查内核支持** ```bash lsmod | grep tun # 查看是否加载tun模块 sudo modprobe tun # 手动加载模块(若未加载) ``` 2. **准备离线安装包** 需提前在有网络环境的主机下载: ```bash apt-get download uml-utilities libpam0g:arm64 libselinux1:arm64 ``` (将下载的*.deb包拷贝到目标主机) 3. **安装软件包** ```bash sudo dpkg -i *.deb # 在存放deb包的目录执行 ``` 4. **创建TAP设备** ```bash sudo ip tuntap add mode tap user $(whoami) # 创建设备 sudo ip link set tap0 up # 启用设备 sudo ip addr add 192.168.100.1/24 dev tap0 # 配置IP地址 ``` 5. **设置开机自启** 新建脚本文件 `/etc/network/tap-setup`: ```bash #!/bin/bash ip tuntap add mode tap user your_username ip link set tap0 up ip addr add 192.168.100.1/24 dev tap0 ``` 执行: ```bash sudo chmod +x /etc/network/tap-setup sudo echo "/etc/network/tap-setup" >> /etc/rc.local sudo chmod +x /etc/rc.local ``` **注意事项**: 1. 若提示依赖缺失,需补全下载所有依赖包的*.deb文件 2. 用户`your_username`需替换为实际用户名 3. IP地址段可根据需要调整 4. 查看设备是否生效: ```bash ip addr show tap0 # 应显示配置的IP地址 ping 192.168.100.1 # 测试连通性 ``` 如需卸载: ```bash sudo ip link del tap0 sudo apt purge uml-utilities ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值