X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/e6b06b6b61b4b877937d4a56ba704d3f18154dc2..786989941b7b4504f0234c4a318f929802e981ad:/server/tun-linux.c diff --git a/server/tun-linux.c b/server/tun-linux.c new file mode 100644 index 00000000..3cfa5d72 --- /dev/null +++ b/server/tun-linux.c @@ -0,0 +1,192 @@ +/* -*-c-*- + * + * $Id$ + * + * Tunnel interface based on Linux TUN/TAP driver + * + * (c) 2003 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Trivial IP Encryption (TrIPE). + * + * TrIPE 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. + * + * TrIPE 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 TrIPE; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#define TUN_INTERNALS + +#include "tripe.h" + +#ifdef TUN_LINUX +# include +# include +# include +#endif + +/*----- Main code ---------------------------------------------------------*/ + +#ifdef TUN_LINUX + +struct tunnel { + const tunnel_ops *ops; /* Pointer to operations */ + sel_file f; /* Selector for TUN/TAP device */ + struct peer *p; /* Pointer to my peer */ + char ifn[IFNAMSIZ]; /* Interface name buffer */ +}; + +/* --- @t_read@ --- * + * + * Arguments: @int fd@ = file descriptor to read + * @unsigned mode@ = what's happened + * @void *v@ = pointer to tunnel block + * + * Returns: --- + * + * Use: Reads data from the tunnel. + */ + +static void t_read(int fd, unsigned mode, void *v) +{ + tunnel *t = v; + ssize_t n; + buf b; + + n = read(fd, buf_i, sizeof(buf_i)); + if (n < 0) { + a_warn("TUN", "%s", t->ifn, "read-error", "?ERRNO", A_END); + return; + } + IF_TRACING(T_TUNNEL, { + trace(T_TUNNEL, "tun-linux: packet arrived"); + trace_block(T_PACKET, "tun-linux: packet contents", buf_i, n); + }) + buf_init(&b, buf_i, n); + p_tun(t->p, &b); +} + +/* --- @t_init@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Initializes the tunneling system. Maybe this will require + * opening file descriptors or something. + */ + +static void t_init(void) { return; } + +/* --- @t_create@ --- * + * + * Arguments: @peer *p@ = pointer to peer block + * + * Returns: A tunnel block if it worked, or null on failure. + * + * Use: Initializes a new tunnel. + */ + +static tunnel *t_create(peer *p) +{ + int fd; + int f; + struct ifreq iff; + tunnel *t; + + if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { + a_warn("TUN", "-", "linux", + "open-error", "/dev/net/tun", "?ERRNO", + A_END); + return (0); + } + fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); + memset(&iff, 0, sizeof(iff)); + iff.ifr_name[0] = 0; + iff.ifr_flags = IFF_TUN | IFF_NO_PI; + if ((f = ioctl(fd, TUNSETIFF, &iff)) < 0) { + a_warn("TUN", "-", "linux", "config-error", "?ERRNO", A_END); + close(fd); + return (0); + } + t = CREATE(tunnel); + t->ops = &tun_linux; + t->p = p; + sel_initfile(&sel, &t->f, fd, SEL_READ, t_read, t); + sel_addfile(&t->f); + iff.ifr_name[IFNAMSIZ - 1] = 0; + strcpy(t->ifn, iff.ifr_name); + T( trace(T_TUNNEL, "tun-linux: attached interface %s to peer `%s'", + t->ifn, p_name(p)); ) + return (t); +} + +/* --- @t_ifname@ --- * + * + * Arguments: @tunnel *t@ = pointer to tunnel block + * + * Returns: A pointer to the tunnel's interface name. + */ + +static const char *t_ifname(tunnel *t) { return (t->ifn); } + +/* --- @t_inject@ --- * + * + * Arguments: @tunnel *t@ = pointer to tunnel block + * @buf *b@ = buffer to send + * + * Returns: --- + * + * Use: Injects a packet into the local network stack. + */ + +static void t_inject(tunnel *t, buf *b) +{ + IF_TRACING(T_TUNNEL, { + trace(T_TUNNEL, "tun-linux: inject decrypted packet"); + trace_block(T_PACKET, "tunnel: packet contents", BBASE(b), BLEN(b)); + }) + write(t->f.fd, BBASE(b), BLEN(b)); +} + +/* --- @t_destroy@ --- * + * + * Arguments: @tunnel *t@ = pointer to tunnel block + * + * Returns: --- + * + * Use: Destroys a tunnel. + */ + +static void t_destroy(tunnel *t) +{ + sel_rmfile(&t->f); + close(t->f.fd); + DESTROY(t); +} + +const tunnel_ops tun_linux = { + "linux", + t_init, + t_create, + t_ifname, + t_inject, + t_destroy +}; + +#endif + +/*----- That's all, folks -------------------------------------------------*/