向目标服务器发送 tun/tap 个数据包

sending tun/tap packets to destination server

如何将tun读取的数据包发送到服务器?我通过 Wireshark 检查数据包,发现它们都是 DNS 请求,并将我系统的默认网关更改为我的 VM 的 IP,所有数据包都到达那里。 tun 运行良好,我可以打印有关数据包的所有内容,但问题是我不知道如何将它们转发到目标服务器。 (我知道套接字编程)
代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <fcntl.h>
#include <signal.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/ip.h>
#include <arpa/inet.h>
#include <netinet/in.h>

struct sockaddr_in Packet, dest;

#define Tun_Device "tun0"

static int max(int a, int b){
    return a > b ? a : b;
    }

int read_tun(char *name, int type){
    struct ifreq ifr;
    int tun_fd;
    tun_fd = open("/dev/net/tun", O_RDWR)
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = type;
    strncpy(ifr.ifr_name, name, IFNAMSIZ);
    ioctl(tun_fd, TUNSETIFF, (void *)&ifr);
    return tun_fd;
    }

int main(){ 
    int tun_fd, packet_length, tcpfd;
    struct sockaddr_in cliaddr, servaddr;
    char buffer[2048];
    char destination[16];
    int i = 0;
    struct iphdr *iph = (struct iphdr*) buffer;
    tun_fd = read_tun(Tun_Device, IFF_TUN | IFF_NO_PI);
    while (1) {
        fd_set readset;
        FD_ZERO(&readset);
        FD_SET(tun_fd, &readset);
        FD_SET( , &readset);
        int max_fd = max(tun_fd, udp_fd) + 1;
        select(max_fd, &readset, NULL, NULL, NULL)
        if (FD_ISSET( , &readset)) {
            }

        if (FD_ISSET( , &readset)) {
            }
        }
    }

您的默认网关必须开启IP转发,您需要设置相应的iptables规则。

从网关机器,您需要:

# Turn on IPv4 forward
sudo sysctl net.ipv4.ip_forward=1

# Add MASQUERADE rule
iptables -t nat -I POSTROUTING -s x.x.x.x/y ! -o tun0 -j MASQUERADE

# Allow forwarding
iptables -t filter -I FORWARD -d x.x.x.x/y -j ACCEPT
iptables -t filter -I FORWARD -s x.x.x.x/y -j ACCEPT
iptables -t filter -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT

备注

  • 使用您的 TUN/TAP 网络子网调整 x.x.x.x/y
  • 使用您使用的虚拟网络接口名称调整tun0

客户端的默认网关设置

当您覆盖到虚拟网络接口的任何流量时,您仍然需要与您的互联网路由器通信,因为您需要将封装的数据包发送到 VPN 服务器。

为此,您不应删除通过物理路由器的默认路由。

规则很简单:

  • 其 destination/source 为 VPN 服务器 IP 地址 的数据包必须 sent/received 通过物理路由器。
  • 其他数据包必须sent/received通过虚拟网络接口。
  • 此外,如果有的话,您可能希望为本地网络设置一些例外。

配置示例

VPN_IFACE=tun0
VPN_PRIVATE_IP=10.8.8.2
VPN_GATEWAY_IP=10.8.8.1
VPN_BROADCAST_IP=10.8.8.25
VPN_PUBLIC_IP=123.123.123.123
REAL_DEFAULT_IP=192.168.1.1

# Raise up virtual network interface
sudo ip link set dev $VPN_IFACE up mtu 1480
sudo ip addr add dev $VPN_IFACE $VPN_PRIVATE_IP/24 broadcast $VPN_BROADCAST_IP

# Encapsulated packet must be routed via your real router.
sudo ip route add $VPN_PUBLIC_IP/32 via $REAL_DEFAULT_IP

# Override any traffic, except for encapsulated packet
# Make them routed via virtual network interface gateway
sudo ip route add 0.0.0.0/1 dev $VPN_IFACE via $VPN_GATEWAY_IP
sudo ip route add 128.0.0.0/1 dev $VPN_IFACE via $VPN_GATEWAY_IP

# Don't delete default route to your real physical router!