1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
|
/*
* tun-linux.c
*
* Universal TUN/TAP driver, in Linux 2.4+
* /usr/src/linux/Documentation/networking/tuntap.txt
*
* Copyright (c) 2001 Dug Song <dugsong@monkey.org>
*
* $Id$
*/
#include "config.h"
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "dumbnet.h"
struct tun {
int fd;
intf_t *intf;
struct ifreq ifr;
};
tun_t *
tun_open(struct addr *src, struct addr *dst, int mtu)
{
tun_t *tun;
struct intf_entry ifent;
if ((tun = calloc(1, sizeof(*tun))) == NULL)
return (NULL);
if ((tun->fd = open("/dev/net/tun", O_RDWR, 0)) < 0 ||
(tun->intf = intf_open()) == NULL)
return (tun_close(tun));
tun->ifr.ifr_flags = IFF_TUN;
if (ioctl(tun->fd, TUNSETIFF, (void *) &tun->ifr) < 0)
return (tun_close(tun));
memset(&ifent, 0, sizeof(ifent));
strlcpy(ifent.intf_name, tun->ifr.ifr_name, sizeof(ifent.intf_name));
ifent.intf_flags = INTF_FLAG_UP|INTF_FLAG_POINTOPOINT;
ifent.intf_addr = *src;
ifent.intf_dst_addr = *dst;
ifent.intf_mtu = mtu;
if (intf_set(tun->intf, &ifent) < 0)
return (tun_close(tun));
return (tun);
}
const char *
tun_name(tun_t *tun)
{
return (tun->ifr.ifr_name);
}
int
tun_fileno(tun_t *tun)
{
return (tun->fd);
}
ssize_t
tun_send(tun_t *tun, const void *buf, size_t size)
{
struct iovec iov[2];
uint32_t etype = htonl(ETH_TYPE_IP);
iov[0].iov_base = &etype;
iov[0].iov_len = sizeof(etype);
iov[1].iov_base = (void *)buf;
iov[1].iov_len = size;
return (writev(tun->fd, iov, 2));
}
ssize_t
tun_recv(tun_t *tun, void *buf, size_t size)
{
struct iovec iov[2];
uint32_t type;
iov[0].iov_base = &type;
iov[0].iov_len = sizeof(type);
iov[1].iov_base = (void *)buf;
iov[1].iov_len = size;
return (readv(tun->fd, iov, 2) - sizeof(type));
}
tun_t *
tun_close(tun_t *tun)
{
if (tun->fd > 0)
close(tun->fd);
if (tun->intf != NULL)
intf_close(tun->intf);
free(tun);
return (NULL);
}
|