#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_tun.h>
#include <err.h>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "main.h"
#define TUN0 "tun98"
#define TUN1 "tun99"
#define TUN0_ADDR "192.0.2.1"
#define TUN1_ADDR "192.0.2.2"
#define TUN_MAXWAIT 5
#define TUN_PINGDEL 1
struct buffer {
u_char *buf;
size_t len;
size_t a;
};
int state;
int tunfd[2];
struct buffer tpkt;
u_char pktbuf[TUNMTU];
struct event tunwev[2];
struct timeval exittv = {TUN_MAXWAIT, 0};
void
tunnel_write(int fd, short which, void *arg)
{
uint32_t type = htonl(AF_INET);
struct iovec iv[2];
int rlen;
int fdkey = (fd == tunfd[0]) ? 0 : 1;
iv[0].iov_base = &type;
iv[0].iov_len = sizeof(type);
iv[1].iov_base = tpkt.buf;
iv[1].iov_len = tpkt.len;
state++;
if ((rlen = writev(fd, iv, 2)) > 0)
fprintf(stderr, "Tunnel %d wrote %ld bytes\n",
fdkey, (long)(rlen - sizeof(type)));
else
errx(1, "Write to tunnel %d failed", fdkey);
}
void
tunnel_read(int fd, short which, void *arg)
{
struct iovec iv[2];
uint32_t type;
int rlen;
int fdkey = (fd == tunfd[0]) ? 0 : 1;
int oppfdkey = (fd == tunfd[0]) ? 1 : 0;
iv[0].iov_base = &type;
iv[0].iov_len = sizeof(type);
iv[1].iov_base = tpkt.buf;
iv[1].iov_len = tpkt.a;
state++;
if ((rlen = readv(fd, iv, 2)) > 0) {
fprintf(stderr, "Tunnel %d read %ld bytes\n",
fdkey, (long)(rlen - sizeof(type)));
tpkt.len = rlen - sizeof(type);
event_add(&tunwev[oppfdkey], &exittv);
} else
errx(1, "Read from tunnel %d failed", fdkey);
}
void
tunnel_ping(int fd, short which, void *arg)
{
system("ping -c 1 -I " TUN0_ADDR " " TUN1_ADDR " >/dev/null &");
}
int
do_tun(void)
{
struct event tunrev[2];
struct event pingev;
struct timeval pingtv = {TUN_PINGDEL, 0};
tpkt.buf = (u_char *)&pktbuf;
tpkt.len = 0;
tpkt.a = sizeof(pktbuf);
event_init();
if ((tunfd[0] = open("/dev/" TUN0, O_RDWR)) < 0)
errx(1, "Cannot open /dev/" TUN0);
event_set(&tunrev[0], tunfd[0], EV_READ, tunnel_read, NULL);
event_set(&tunwev[0], tunfd[0], EV_WRITE, tunnel_write, NULL);
event_add(&tunrev[0], &exittv);
if ((tunfd[1] = open("/dev/" TUN1, O_RDWR)) < 0)
errx(1, "Cannot open /dev/" TUN1);
event_set(&tunrev[1], tunfd[1], EV_READ, tunnel_read, NULL);
event_set(&tunwev[1], tunfd[1], EV_WRITE, tunnel_write, NULL);
event_add(&tunrev[1], &exittv);
evtimer_set(&pingev, tunnel_ping, NULL);
event_add(&pingev, &pingtv);
system("ifconfig " TUN0 " " TUN0_ADDR
" netmask 255.255.255.255 " TUN1_ADDR);
system("ifconfig " TUN1 " " TUN1_ADDR
" netmask 255.255.255.255 " TUN0_ADDR);
state = 0;
if (event_dispatch() < 0)
errx(errno, "Event handler failed");
return (state != 4);
}