自研VPN解决方案
服务端:
服务端执行的linux 命令:
ip tuntap add tun0 mode tun
ip link set dev tun0 up
ifconfig tun0 192.168.194.224 netmask 255.255.255.0 promisc
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
服务端代码为:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> //read() write()
#include <net/if.h> //struct ifreq, IFNAMSIZ
#include <sys/ioctl.h> //TUNSETIFF
#include <sys/epoll.h> //epoll
#include <fcntl.h> //O_RDWR
#include <linux/if_tun.h> //IFF_TAP
#include <linux/ip.h> //struct iphdr
#include <arpa/inet.h> //struct in_addr
#include <netinet/tcp.h> //struct tcphdr
#include <netinet/udp.h> //struct udphdr
#define DEBUG
#define MAX_PKG_LEN 65535
typedef struct iphdr* piphdr;
typedef struct tcphdr* ptcphdr;
typedef struct udphdr* pudphdr;
typedef unsigned char u_char;
int HEAD_IP = 20;
int OPEN_MAX = 500;
int LISTENQ = 5;
void ProcessShark(struct sockaddr_in* clent_addr, u_char* user_data, int data_size);
void ProcessBack(u_char* buffer, int nread);
int udp_fd;
int tun_fd;
struct sockaddr_in* clent_addrs[256] = { 0 };
int main(int argc, char* argv[])
{
if (argc != 2) {
printf("Usage: ./shark $port\n");
return 2;
}
int listen_port = atoi(argv[1]);
if (listen_port == 0) {
printf("listen_port[%d] error!\n", listen_port);
return 2;
}
printf("sharking...\n");
udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_fd < 0) {
printf("create socket fail!\n");
return -1;
}
struct sockaddr_in ser_addr;
memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ser_addr.sin_port = htons(listen_port);
//struct sockaddr* ser_addr = (struct sockaddr*)&ser_addr;
int ret = bind(udp_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
if (ret < 0) {
printf("socket bind[%d] fail!\n", listen_port);
return -1;
}
char *clonedev = "/dev/net/tun";
if ((tun_fd = open(clonedev, O_RDWR)) < 0) {
printf("error1\n");
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_name, "tun0", IFNAMSIZ);
int err;
if ((err = ioctl(tun_fd, TUNSETIFF, (void *) &ifr)) < 0) {
close(tun_fd);
printf("error2 err[%d]\n", err);
return err;
}
printf("tun/tap[%s]\n", ifr.ifr_name);
int epollfd = epoll_create(OPEN_MAX);
if (epollfd <= 0) {
printf("epollfd[%d]\n", epollfd);
return epollfd;
}
struct epoll_event epev;
epev.events = EPOLLIN;
epev.data.fd = udp_fd;
ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, udp_fd, &epev);
if (ret != 0) {
printf("ret1[%d]\n", ret);
return ret;
}
listen(udp_fd, LISTENQ);
struct epoll_event epev2;
epev2.events = EPOLLIN;
epev2.data.fd = tun_fd;
ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, tun_fd, &epev2);
if (ret != 0) {
printf("ret2[%d]\n", ret);
return ret;
}
listen(tun_fd, LISTENQ);
struct epoll_event events_in[OPEN_MAX];
uint8_t buf[MAX_PKG_LEN] = { 0 };
socklen_t len = sizeof(struct sockaddr_in);
while (1) {
int event_count = epoll_wait(epollfd, events_in, OPEN_MAX, -1);
//超时返回 0 , 出错返回 -1 , timeout 设置为 -1 表示无限等待.
if (event_count == -1) {
printf("epoll_wait error\n");
exit(1);
}
for (int i = 0; i < event_count; i++) {
if (events_in[i].data.fd == tun_fd && events_in[i].events & EPOLLIN) {
int n = read(tun_fd, buf, MAX_PKG_LEN);
if (n <= 0) continue;
ProcessBack(buf, n);
} else if (events_in[i].data.fd == udp_fd && events_in[i].events & EPOLLIN) {
struct sockaddr_in* clent_addr = (struct sockaddr_in*)malloc(len);
int n = recvfrom(udp_fd, buf, MAX_PKG_LEN, 0, (struct sockaddr*)clent_addr, &len);
if (n <= 0) continue;
ProcessShark(clent_addr, buf, n);
}
}
}
return 0;
}
void ProcessShark(struct sockaddr_in* clent_addr, u_char* user_data, int data_size)
{
int cip = user_data[15]; //源地址,子网ip最后
if (!clent_addrs[cip]) free(clent_addrs[cip]);
clent_addrs[cip] = clent_addr;
#ifdef DEBUG
piphdr user_data_ip = (piphdr)user_data;
char ip1[16] = { 0 };
char ip2[16] = { 0 };
sprintf(ip1, "%s", inet_ntoa(*(struct in_addr*)(&user_data_ip->saddr)));
sprintf(ip2, "%s", inet_ntoa(*(struct in_addr*)(&user_data_ip->daddr)));
unsigned ack = -1;
u_short port_src, port_dst;
if (user_data_ip->protocol == IPPROTO_TCP) {
ptcphdr tcp = (ptcphdr)(user_data + HEAD_IP);
port_src = ntohs(tcp->source);
port_dst = ntohs(tcp->dest);
} else if (user_data_ip->protocol == IPPROTO_UDP) {
pudphdr udp = (pudphdr)(user_data + HEAD_IP);
port_src = ntohs(udp->source);
port_dst = ntohs(udp->dest);
} else {
printf("protocol[%d] return\n", user_data_ip->protocol);
return;
}
printf("send %s:%d -> %s:%d data_size:%d ip_p:%d tot_len[%d]\n",
ip1, port_src, ip2, port_dst, data_size, user_data_ip->protocol,
ntohs(user_data_ip->tot_len));
#endif
write(tun_fd, user_data, data_size);
}
void ProcessBack(u_char* buffer, int nread)
{
piphdr pip = (piphdr)buffer;
if (nread < 4 || nread != ntohs(pip->tot_len)) {
printf("read err[%d][%d]\n", nread, ntohs(pip->tot_len));
// 打印 buffer 的前 20 个字节,检查是否是有效的 IP 头部
for (int i = 0; i < 20; i++) {
printf("%02x ", buffer[i]);
}
printf("\n");
return;
}
#ifdef DEBUG
char ip1[16] = { 0 };
char ip2[16] = { 0 };
sprintf(ip1, "%s", inet_ntoa(*(struct in_addr*)(&pip->saddr)));
sprintf(ip2, "%s", inet_ntoa(*(struct in_addr*)(&pip->daddr)));
printf("nread[%d] tot_len[%d] protocol[%d] saddr[%s] daddr[%s]\n",
nread, ntohs(pip->tot_len), pip->protocol, ip1, ip2);
#endif
int cip = buffer[19]; //目的地址,子网ip最后
struct sockaddr* clent_addr = (struct sockaddr*)clent_addrs[cip];
if (!clent_addr) return;
//发包
sendto(udp_fd, buffer, nread, 0, clent_addr, sizeof(struct sockaddr_in));
}
客户端执行的命令为:
ip tuntap add tun0 mode tun
ip link set dev tun0 up
ifconfig tun0 192.168.194.225 netmask 255.255.255.0 promisc
客户端代码是:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/if_tun.h>
#include <sys/epoll.h>
#define MAX_PKG_LEN 65535
#define SERVER_IP "137.184.44.85" // 替换为服务端的 IP 地址
#define SERVER_PORT 7194 // 替换为服务端的端口号
int tun_fd;
int udp_fd;
// 创建 TUN 设备
int create_tun_device() {
char *clonedev = "/dev/net/tun";
int fd;
if ((fd = open(clonedev, O_RDWR)) < 0) {
perror("open tun device failed");
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_name, "tun0", IFNAMSIZ);
if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
perror("ioctl TUNSETIFF failed");
close(fd);
return -1;
}
printf("TUN device %s created\n", ifr.ifr_name);
return fd;
}
// 初始化 UDP 套接字
int init_udp_socket() {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
perror("create UDP socket failed");
return -1;
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
server_addr.sin_port = htons(SERVER_PORT);
if (connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("connect to server failed");
close(fd);
return -1;
}
printf("UDP socket connected to server %s:%d\n", SERVER_IP, SERVER_PORT);
return fd;
}
// 主逻辑
int main() {
// 创建 TUN 设备
tun_fd = create_tun_device();
if (tun_fd < 0) {
return -1;
}
// 初始化 UDP 套接字
udp_fd = init_udp_socket();
if (udp_fd < 0) {
close(tun_fd);
return -1;
}
// 创建 epoll 实例
int epoll_fd = epoll_create1(0);
if (epoll_fd < 0) {
perror("epoll_create1 failed");
close(tun_fd);
close(udp_fd);
return -1;
}
// 添加 TUN 设备到 epoll
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = tun_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, tun_fd, &ev) < 0) {
perror("epoll_ctl add tun_fd failed");
close(tun_fd);
close(udp_fd);
close(epoll_fd);
return -1;
}
// 添加 UDP 套接字到 epoll
ev.events = EPOLLIN;
ev.data.fd = udp_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, udp_fd, &ev) < 0) {
perror("epoll_ctl add udp_fd failed");
close(tun_fd);
close(udp_fd);
close(epoll_fd);
return -1;
}
// 事件循环
struct epoll_event events[2];
uint8_t buffer[MAX_PKG_LEN];
while (1) {
int nfds = epoll_wait(epoll_fd, events, 2, -1);
if (nfds < 0) {
perror("epoll_wait failed");
break;
}
for (int i = 0; i < nfds; i++) {
if (events[i].data.fd == tun_fd) {
// 从 TUN 设备读取数据并发送到 UDP 套接字
int nread = read(tun_fd, buffer, MAX_PKG_LEN);
if (nread < 0) {
perror("read from tun_fd failed");
continue;
}
send(udp_fd, buffer, nread, 0);
printf("Sent %d bytes from TUN to UDP\n", nread);
} else if (events[i].data.fd == udp_fd) {
// 从 UDP 套接字读取数据并写入 TUN 设备
int nread = recv(udp_fd, buffer, MAX_PKG_LEN, 0);
if (nread < 0) {
perror("recv from udp_fd failed");
continue;
}
write(tun_fd, buffer, nread);
printf("Received %d bytes from UDP to TUN\n", nread);
}
}
}
// 关闭资源
close(tun_fd);
close(udp_fd);
close(epoll_fd);
return 0;
}