clinuxsocketsnetwork-programmingtun

sending tun/tap packets to destination server


how can I send the read packet from tun to the server? I checked the packets by Wireshark and all of them was DNS request and changed the default gateway of my system to the IP of my VM and all packets goes there. the tun works good and I can print everything about packets but the problem is I don't know how to forward them to the destination server. (i know socket programming)
the code:

#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)) {
            }
        }
    }

Solution

  • Your default gateway must activate IP forwarding and you need to set corresponding iptables rules.

    From gateway machine, you need to:

    # 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
    

    Note


    Default Gateway setting for client

    You still need to communicate with your internet router when you override any traffic to virtual network interface, because you need to send encapsulated packet to VPN server.

    In order to do that, you should not delete your default route that is going via your physical router.

    The rule is simple:

    Config example

    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!