Permalink
Browse files

refactored TUNInterface/TUNConverter

  • Loading branch information...
1 parent 829f93e commit 4acf90837d9c7943c416716e0a74732b68fe9873 Caleb James DeLisle committed Jun 17, 2012
View
@@ -315,12 +315,17 @@ static void registerRouter(Dict* config, struct Address* addr, struct Context* c
{
Dict* iface = Dict_getDict(config, String_CONST("interface"));
if (String_equals(Dict_getString(iface, String_CONST("type")), String_CONST("TUNInterface"))) {
- String* tunPath = Dict_getString(iface, String_CONST("tunDevice"));
- struct TUNInterface* tun = TUNInterface_new(tunPath, context->base, context->allocator);
- if (TUNConfigurator_configure(tun, addr->ip6.bytes, 8) != 0) {
- fprintf(stderr, "Couldn't configure TUN interface\n");
- }
+ String* ifName = Dict_getString(iface, String_CONST("tunDevice"));
+
+ void* tunDesc = TUNConfigurator_configure(((ifName) ? ifName->bytes : NULL),
+ addr->ip6.bytes,
+ 8,
+ context->logger,
+ AbortHandler_INSTANCE);
+
+ struct TUNInterface* tun = TUNInterface_new(tunDesc, context->base, context->allocator);
context->tunInterface = TUNInterface_asGeneric(tun);
+
}
context->routerModule = RouterModule_register(context->registry,
context->allocator,
View
@@ -0,0 +1,41 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef Except_H
+#define Except_H
+
+#include "exception/ExceptionHandler.h"
+#include "util/Gcc.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#define Except ExceptionHandler
+
+Gcc_NORETURN
+Gcc_PRINTF(3, 4)
+static inline void Except_raise(struct Except* eh, int code, char* format, ...)
+{
+ #define Except_BUFFER_SZ 1024
+ char buff[Except_BUFFER_SZ];
+
+ va_list args;
+ va_start(args, format);
+ vsnprintf(buff, Except_BUFFER_SZ, format, args);
+
+ eh->exception(buff, code, eh);
+ abort();
+}
+
+#endif
View
@@ -16,7 +16,9 @@ if(WIN32)
set(tunconf W32TUNConfigurator.c)
else()
set(tunif TUNInterface.c)
- set(tunconf TUNConfigurator.c)
+ if(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
+ set(tunconf TUNConfigurator_Linux.c)
+ endif()
endif()
add_library(interface
@@ -15,18 +15,29 @@
#ifndef TUNConfigurator_H
#define TUNConfigurator_H
-#include "interface/TUNInterface.h"
+#include "exception/Except.h"
+#include "util/Log.h"
/**
* Configure a TUNInterface.
*
* @param interface to configure.
* @param address the ipv6 address in binary form.
* @param prefixLen the number of bits in the network mask.
- * @return 0 if successful, non-zero otherwise.
+ * @param logger
+ * @param eh if this function fails, it will raise one of the following.
+ * TUNConfigurator_configure_BAD_TUNNEL interfaceName was an invalid tun device name.
+ * TUNConfigurator_configure_MALFORMED_ADDRESS myIp was an invalid ipv6 address.
+ * TUNConfigurator_configure_INTERNAL Something went wrong internally.
+ * @return an opaque pointer which represents the file descriptor for the newly configured tunnel.
*/
-int TUNConfigurator_configure(struct TUNInterface* iface,
- uint8_t address[16],
- int prefixLen);
+#define TUNConfigurator_configure_BAD_TUNNEL -1
+#define TUNConfigurator_configure_MALFORMED_ADDRESS -2
+#define TUNConfigurator_configure_INTERNAL -3
+void* TUNConfigurator_configure(const char* interfaceName,
+ const uint8_t myIp[40],
+ int prefixLen,
+ struct Log* logger,
+ struct Except* eh);
#endif
@@ -0,0 +1,124 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "interface/Interface.h"
+#include "interface/TUNConfigurator.h"
+#include "util/AddrTools.h"
+
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <net/if.h>
+
+#include <net/if_tun.h>
+#include <sys/stropts.h>
+#include <sys/sockio.h>
+
+
+
+/**
+ * Open the tun device.
+ *
+ * @param interfaceName the interface name you *want* to use or NULL to let the kernel decide.
+ * @param assignedInterfaceName the interface name you get.
+ * @param log
+ * @param eh
+ * @return a file descriptor for the tunnel.
+ */
+static int openTunnel(const char* interfaceName,
+ char assignedInterfaceName[IFNAMSIZ],
+ struct Log* logger,
+ struct Except* eh)
+{
+ Log_info(logger, "Initializing tun device [%s]", ((interfaceName) ? interfaceName : "auto"));
+
+ struct ifreq ifRequest = { .ifr_flags = IFF_TUN };
+ if (interfaceName) {
+ strncpy(ifRequest.ifr_name, interfaceName, IFNAMSIZ);
+ }
+ int tunFileDescriptor = open("/dev/net/tun", O_RDWR);
+
+ if (tunFileDescriptor < 0) {
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "open(\"/dev/net/tun\") [%s]", strerror(errno));
+ }
+
+ if (ioctl(tunFileDescriptor, TUNSETIFF, &ifRequest) < 0) {
+ int err = errno;
+ close(tunFileDescriptor);
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "ioctl(TUNSETIFF) [%s]", strerror(err));
+ }
+ strncpy(assignedInterfaceName, ifRequest.ifr_name, IFNAMSIZ);
+
+ return tunFileDescriptor;
+}
+
+static void setupIpv6(const char* interfaceName,
+ const char myIp[40],
+ int prefixLen
+ struct Log* logger,
+ struct Except* eh)
+{
+ int s;
+ struct ifreq ifRequest;
+ struct in6_ifreq ifr6;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "socket() failed: [%s]", strerror(errno));
+ }
+
+ strncpy(ifRequest.ifr_name, interfaceName, IFNAMSIZ);
+
+ if (ioctl(s, SIOCGIFINDEX, &ifRequest) < 0) {
+ int err = errno;
+ close(s);
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "ioctl(SIOCGIFINDEX) failed: [%s]", strerror(errno));
+ }
+
+ ifr6.ifr6_ifindex = ifRequest.ifr_ifindex;
+ ifr6.ifr6_prefixlen = prefixLen;
+ inet_pton(AF_INET6, myIp, &ifr6.ifr6_addr);
+
+ ifRequest.ifr_flags |= IFF_UP | IFF_RUNNING;
+ if (ioctl(s, SIOCSIFFLAGS, &ifRequest) < 0) {
+ int err = errno;
+ close(s);
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "ioctl(SIOCSIFFLAGS) failed: [%s]", strerror(errno));
+ }
+
+ if (ioctl(s, SIOCSIFADDR, &ifr6) < 0) {
+ int err = errno;
+ close(s);
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "ioctl(SIOCSIFADDR) failed: [%s]", strerror(errno));
+ }
+}
+
+void* TUNConfigurator_configure(const char* interfaceName,
+ const uint8_t address[16],
+ int prefixLen,
+ struct Log* logger,
+ struct Except* eh)
+{
+ return NULL;
+}
@@ -0,0 +1,146 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "interface/Interface.h"
+#include "interface/TUNConfigurator.h"
+#include "util/AddrTools.h"
+
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <net/if.h>
+
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/if_ether.h>
+
+/**
+ * This hack exists because linux/in.h and linux/in6.h define
+ * the same structures, leading to redefinition errors.
+ */
+#ifndef _LINUX_IN6_H
+ struct in6_ifreq
+ {
+ struct in6_addr ifr6_addr;
+ uint32_t ifr6_prefixlen;
+ int ifr6_ifindex;
+ };
+#endif
+
+
+/**
+ * Open the tun device.
+ *
+ * @param interfaceName the interface name you *want* to use or NULL to let the kernel decide.
+ * @param assignedInterfaceName the interface name you get.
+ * @param log
+ * @param eh
+ * @return a file descriptor for the tunnel.
+ */
+static int openTunnel(const char* interfaceName,
+ char assignedInterfaceName[IFNAMSIZ],
+ struct Log* logger,
+ struct Except* eh)
+{
+ Log_info(logger, "Initializing tun device [%s]", ((interfaceName) ? interfaceName : "auto"));
+
+ struct ifreq ifRequest = { .ifr_flags = IFF_TUN };
+ if (interfaceName) {
+ strncpy(ifRequest.ifr_name, interfaceName, IFNAMSIZ);
+ }
+ int tunFileDescriptor = open("/dev/net/tun", O_RDWR);
+
+ if (tunFileDescriptor < 0) {
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "open(\"/dev/net/tun\") [%s]", strerror(errno));
+ }
+
+ if (ioctl(tunFileDescriptor, TUNSETIFF, &ifRequest) < 0) {
+ int err = errno;
+ close(tunFileDescriptor);
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "ioctl(TUNSETIFF) [%s]", strerror(err));
+ }
+ strncpy(assignedInterfaceName, ifRequest.ifr_name, IFNAMSIZ);
+
+ return tunFileDescriptor;
+}
+
+static void setupIpv6(const char* interfaceName,
+ const uint8_t myIp[40],
+ int prefixLen,
+ struct Log* logger,
+ struct Except* eh)
+{
+ int s;
+ struct ifreq ifRequest;
+ struct in6_ifreq ifr6;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "socket() failed: [%s]", strerror(errno));
+ }
+
+ strncpy(ifRequest.ifr_name, interfaceName, IFNAMSIZ);
+
+ if (ioctl(s, SIOCGIFINDEX, &ifRequest) < 0) {
+ int err = errno;
+ close(s);
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "ioctl(SIOCGIFINDEX) failed: [%s]", strerror(err));
+ }
+
+ ifr6.ifr6_ifindex = ifRequest.ifr_ifindex;
+ ifr6.ifr6_prefixlen = prefixLen;
+ inet_pton(AF_INET6, (char*) myIp, &ifr6.ifr6_addr);
+
+ ifRequest.ifr_flags |= IFF_UP | IFF_RUNNING;
+ if (ioctl(s, SIOCSIFFLAGS, &ifRequest) < 0) {
+ int err = errno;
+ close(s);
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "ioctl(SIOCSIFFLAGS) failed: [%s]", strerror(err));
+ }
+
+ if (ioctl(s, SIOCSIFADDR, &ifr6) < 0) {
+ int err = errno;
+ close(s);
+ Except_raise(eh, TUNConfigurator_configure_INTERNAL,
+ "ioctl(SIOCSIFADDR) failed: [%s]", strerror(err));
+ }
+}
+
+void* TUNConfigurator_configure(const char* interfaceName,
+ const uint8_t address[16],
+ int prefixLen,
+ struct Log* logger,
+ struct Except* eh)
+{
+ /* stringify our IP address */
+ uint8_t myIp[40];
+ AddrTools_printIp(myIp, address);
+
+ char assignedInterfaceName[IFNAMSIZ];
+ intptr_t tunFd = (intptr_t) openTunnel(interfaceName, assignedInterfaceName, logger, eh);
+ if (address) {
+ setupIpv6(assignedInterfaceName, myIp, prefixLen, logger, eh);
+ }
+ return (void*) tunFd;
+}
Oops, something went wrong.

0 comments on commit 4acf908

Please sign in to comment.