X-Git-Url: https://www.tinc-vpn.org/git/browse?a=blobdiff_plain;f=src%2Fvnd.c;fp=src%2Fvnd.c;h=7eba993a280e63947246fa99ae94a1486175d43d;hb=ff03bb9b0a744530e1145fef656644987a10d62d;hp=0000000000000000000000000000000000000000;hpb=56c51e94a620dd91eeb510176b9c970af9a9a372;p=tinc diff --git a/src/vnd.c b/src/vnd.c new file mode 100644 index 00000000..7eba993a --- /dev/null +++ b/src/vnd.c @@ -0,0 +1,150 @@ +/* + vnd.c -- virtual network device management + + Copyright (C) 2003-2004 Guus Sliepen , + 2003-2004 Ivo Timmermans + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include "system.h" + +#include + +#include "fd/fd.h" +#include "logger/logger.h" +#include "support/xalloc.h" + +#include "vnd/vnd.h" + +vnd_t *vnd_new(void) { + vnd_t *vnd; + + return clear(new(vnd)); +} + +void vnd_free(vnd_t *vnd) { + replace(vnd->device, NULL); + replace(vnd->interface, NULL); + replace(vnd->description, NULL); + free(vnd); +} + +void vnd_set(vnd_t *vnd, char *device, char *interface, vnd_mode_t mode, vnd_handler_t recv) { + replace(vnd->device, device); + replace(vnd->interface, interface); + vnd->mode = mode; + vnd->recv = recv; +} + +static bool vnd_send(vnd_t *vnd, const void *buf, int len) { + int result; + + result = write(vnd->fd.fd, buf, len); + + if(result == len || result < 0 && (errno == EINTR || errno == EAGAIN)) { + logger(LOG_INFO, _("vnd: wrote packet of %d bytes to %s"), len, vnd->description); + return true; + } + + logger(LOG_INFO, _("vnd: error writing packet of %d bytes to %s: %s"), len, vnd->description, strerror(errno)); + + return false; +} + +static bool vnd_recv_handler(fd_t *fd) { + vnd_t *vnd = fd->data; + char buf[vnd->mtu]; + int len; + + vnd = fd->data; + + len = read(fd->fd, buf, sizeof buf); + + if(len > 0) { + logger(LOG_INFO, _("vnd: read packet of %d bytes from %s"), len, vnd->description); + return vnd->recv(vnd, buf, len); + } + + if(len < 0 && (errno == EINTR || errno == EAGAIN)) + return true; + + logger(LOG_ERR, _("vnd: error reading packet from %s: %s"), vnd->description, strerror(errno)); + + return false; +} + +bool vnd_open(vnd_t *vnd) { + struct ifreq ifr = {0}; + + if(!vnd->device) + vnd->device = xstrdup("/dev/net/tun"); + + vnd->fd.fd = open(vnd->device, O_RDWR | O_NONBLOCK); + + if(vnd->fd.fd < 0) { + logger(LOG_ERR, _("vnd: could not open %s: %s"), vnd->device, strerror(errno)); + return false; + } + + if(vnd->mode == VND_MODE_TUN) + ifr.ifr_flags = IFF_TUN; + else + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + + if(vnd->interface) + strncpy(ifr.ifr_name, vnd->interface, IFNAMSIZ); + + if(!ioctl(vnd->fd.fd, TUNSETIFF, &ifr)) { + if(vnd->interface) + free(vnd->interface); + vnd->interface = xstrdup(ifr.ifr_name); + } else { + logger(LOG_ERR, _("vnd: %s is not a Linux tun/tap device"), vnd->device); + return false; + } + + if(!vnd->mtu) + vnd->mtu = 1514; + + vnd->send = vnd_send; + vnd->fd.read = vnd_recv_handler; + vnd->fd.data = vnd; + + if(vnd->description) + free(vnd->description); + + asprintf(&vnd->description, "Linux tun/tap device %s (interface %s)", vnd->device, vnd->interface); + + if(!fd_add(&vnd->fd)) + return false; + + logger(LOG_INFO, _("vnd: opened %s"), vnd->description); + + return true; +} + +bool vnd_close(vnd_t *vnd) { + fd_del(&vnd->fd); + + close(vnd->fd.fd); + + logger(LOG_INFO, _("vnd: closed %s"), vnd->description); + + return true; +} +