ZBLOG

linux c tun/tap 发送udp包,指定ip地址的udpserver 实现代码案例

下面是一个使用TUN/TAP设备发送UDP数据包的示例代码。该示例创建了一个TUN设备,并将接收到的数据封装为UDP数据包,通过指定的IP地址和端口发送到UDP服务器。

TUN/TAP 发送 UDP 数据包示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/if_tun.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/udp.h>

#define BUFFER_SIZE 2048
#define TUN_DEVICE "/dev/net/tun"
#define UDP_SERVER_IP "192.168.1.100" // 替换为目标UDP服务器的IP地址
#define UDP_SERVER_PORT 12345 // 替换为目标UDP服务器的端口

int create_tun_device() {
    struct ifreq ifr;
    int fd;

    fd = open(TUN_DEVICE, O_RDWR);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    memset(&ifr, 0, sizeof(ifr));
    
    ifr.ifr_flags = IFF_TUN | IFF_NO_PI; // 使用IFF_TAP可以获取数据链路层帧
    strncpy(ifr.ifr_name, "tun0", IFNAMSIZ); 

    if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
        perror("ioctl");
        close(fd);
        return -1;
    }

    printf("TUN device %s created\n", ifr.ifr_name);
    
    return fd;
}

// 计算校验和
unsigned short checksum(void *b, int len) {    
    unsigned short *buf = b;
    unsigned int sum = 0;
    unsigned short result;

    for (sum = 0; len > 1; len -= 2)
        sum += *buf++;
    
    if (len == 1)
        sum += *(unsigned char *)buf;

    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    
    result = ~sum;
    
    return result;
}

int main() {
    char buffer[BUFFER_SIZE];
    
	// 创建TUN设备并获取文件描述符
	int tun_fd = create_tun_device();
	if (tun_fd < 0) {
		exit(EXIT_FAILURE);
	}

	// UDP Socket
	int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sockfd < 0) {
		perror("socket");
		close(tun_fd);
		exit(EXIT_FAILURE);
	}

	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(UDP_SERVER_PORT);
	if (inet_aton(UDP_SERVER_IP, &server_addr.sin_addr) == 0) {
	    perror("inet_aton");
	    close(sockfd);
	    close(tun_fd);
	    exit(EXIT_FAILURE);
	}

	while (1) {
		int nread = read(tun_fd, buffer, BUFFER_SIZE);

		if (nread < 0) {
			perror("read from tun device");
			break;
		}
		
        printf("Read %d bytes from TUN device\n", nread);

        // 构建IP头部(IPv4)
        struct iphdr *ip_header = (struct iphdr *)buffer;
        ip_header->version = IPVERSION; // IPv4
        ip_header->ihl = sizeof(struct iphdr) / 4; 
        ip_header->tot_len = htons(nread + sizeof(struct iphdr)); 
        ip_header->protocol = IPPROTO_UDP; 
       
       // 设置源IP和目的IP,替换为你的实际源IP地址
       ip_header->saddr = inet_addr("192.168.1.101"); // 源IP,替换为你的源IP地址
       ip_header->daddr = server_addr.sin_addr.s_addr;

       // 构建UDP头部(简化版,不考虑选项)
       struct udphdr *udp_header = (struct udphdr *)(buffer + sizeof(struct iphdr));
       udp_header->source = htons(12345); // 源端口,替换为你的实际源端口
       udp_header->dest = htons(UDP_SERVER_PORT); 
       udp_header->len = htons(nread + sizeof(struct udphdr)); 
       
       // 校验和(这里简单处理,没有填充伪头部,通常需要更完整实现)
       udp_header->check=checksum((unsigned short *)udp_header,nread+sizeof(struct udphdr));

       int send_len=nread+sizeof(struct udphdr)+sizeof(struct iphdr);

	   // 将数据通过socket发送到指定的 UDP 服务端
	   ssize_t sent_bytes=sendto(sockfd, buffer, send_len , MSG_CONFIRM,
                              (const struct sockaddr *)&server_addr,
                              sizeof(server_addr));

	   if(sent_bytes<0){
	        perror("sendto failed");
            break;
	   }
       
	   printf("Sent %ld bytes to UDP server\n", sent_bytes);      
   }

   close(sockfd);
   close(tun_fd);

   return EXIT_SUCCESS;   
}

编译与运行

将上述代码保存为 tun_udp_client.c,然后通过以下命令编译:

gcc tun_udp_client.c -o tun_udp_client
sudo ./tun_udp_client

注意事项

  1. 权限: 因为需要操作 /dev/net/tun 和创建Socket,所以通常需要以超级用户权限运行程序。
  2. 网络配置: 请确保目标服务器(指定的 UDP_SERVER_IP)可以从你执行这个程序的机器访问。
  3. 源地址: 示例中的源 IP 地址是硬编码的,可以根据需要修改。
  4. 错误处理: 示例中的错误处理较简单,可根据实际情况进行改进。

此程序读取从TUN设备接收的数据,将其封装成一个包含IPv4头和UDP头的数据包,并通过指定的目标主机发送。这是一个基础示例,用于学习如何结合使用TUN/TAP接口与套接字编程。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:http://sdn.0voice.com/?id=7860

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?