diff options
Diffstat (limited to 'src/libstrongswan')
-rw-r--r-- | src/libstrongswan/eap/eap.c | 80 | ||||
-rw-r--r-- | src/libstrongswan/eap/eap.h | 35 | ||||
-rw-r--r-- | src/libstrongswan/utils/tun_device.c | 148 |
3 files changed, 229 insertions, 34 deletions
diff --git a/src/libstrongswan/eap/eap.c b/src/libstrongswan/eap/eap.c index efd3ee981..1e4cf11bf 100644 --- a/src/libstrongswan/eap/eap.c +++ b/src/libstrongswan/eap/eap.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -13,8 +14,13 @@ * for more details. */ +#include <stdlib.h> +#include <errno.h> + #include "eap.h" +#include <debug.h> + ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE, "EAP_REQUEST", "EAP_RESPONSE", @@ -51,12 +57,12 @@ ENUM_NEXT(eap_type_names, EAP_MSTLV, EAP_MSTLV, EAP_MSCHAPV2, "EAP_MSTLV"); ENUM_NEXT(eap_type_names, EAP_TNC, EAP_TNC, EAP_MSTLV, "EAP_TNC"); -ENUM_NEXT(eap_type_names, EAP_DYNAMIC, EAP_EXPERIMENTAL, EAP_TNC, - "EAP_DYNAMIC", - "EAP_RADIUS", +ENUM_NEXT(eap_type_names, EAP_EXPANDED, EAP_DYNAMIC, EAP_TNC, "EAP_EXPANDED", - "EAP_EXPERIMENTAL"); -ENUM_END(eap_type_names, EAP_EXPERIMENTAL); + "EAP_EXPERIMENTAL", + "EAP_RADIUS", + "EAP_DYNAMIC"); +ENUM_END(eap_type_names, EAP_DYNAMIC); ENUM_BEGIN(eap_type_short_names, EAP_IDENTITY, EAP_GTC, "ID", @@ -80,12 +86,12 @@ ENUM_NEXT(eap_type_short_names, EAP_MSTLV, EAP_MSTLV, EAP_MSCHAPV2, "MSTLV"); ENUM_NEXT(eap_type_short_names, EAP_TNC, EAP_TNC, EAP_MSTLV, "TNC"); -ENUM_NEXT(eap_type_short_names, EAP_DYNAMIC, EAP_EXPERIMENTAL, EAP_TNC, - "DYN", - "RAD", +ENUM_NEXT(eap_type_short_names, EAP_EXPANDED, EAP_DYNAMIC, EAP_TNC, "EXP", - "XP"); -ENUM_END(eap_type_short_names, EAP_EXPERIMENTAL); + "XP", + "RAD", + "DYN"); +ENUM_END(eap_type_short_names, EAP_DYNAMIC); /* * See header @@ -108,6 +114,7 @@ eap_type_t eap_type_from_string(char *name) {"peap", EAP_PEAP}, {"mschapv2", EAP_MSCHAPV2}, {"tnc", EAP_TNC}, + {"dynamic", EAP_DYNAMIC}, {"radius", EAP_RADIUS}, }; @@ -120,3 +127,56 @@ eap_type_t eap_type_from_string(char *name) } return 0; } + +/* + * See header + */ +eap_vendor_type_t *eap_vendor_type_from_string(char *str) +{ + enumerator_t *enumerator; + eap_vendor_type_t *result = NULL; + eap_type_t type = 0; + u_int32_t vendor = 0; + char *part, *end; + + /* parse EAP method string of the form: [eap-]type[-vendor] */ + enumerator = enumerator_create_token(str, "-", " "); + while (enumerator->enumerate(enumerator, &part)) + { + if (!type) + { + if (streq(part, "eap")) + { /* skip 'eap' at the beginning */ + continue; + } + type = eap_type_from_string(part); + if (!type) + { + type = strtoul(part, &end, 0); + if (*end != '\0' || errno) + { + DBG1(DBG_LIB, "unknown or invalid EAP method: %s", part); + break; + } + } + continue; + } + vendor = strtoul(part, &end, 0); + if (*end != '\0' || errno) + { + DBG1(DBG_LIB, "invalid EAP vendor: %s", part); + type = 0; + } + break; + } + enumerator->destroy(enumerator); + + if (type) + { + INIT(result, + .type = type, + .vendor = vendor, + ); + } + return result; +} diff --git a/src/libstrongswan/eap/eap.h b/src/libstrongswan/eap/eap.h index 143232e4b..0e144b123 100644 --- a/src/libstrongswan/eap/eap.h +++ b/src/libstrongswan/eap/eap.h @@ -1,6 +1,8 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG + * Hochschule fuer Technik Rapperswil * * 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 @@ -23,6 +25,7 @@ typedef enum eap_code_t eap_code_t; typedef enum eap_type_t eap_type_t; +typedef struct eap_vendor_type_t eap_vendor_type_t; #include <library.h> @@ -64,12 +67,12 @@ enum eap_type_t { EAP_MSCHAPV2 = 26, EAP_MSTLV = 33, EAP_TNC = 38, - /** select EAP method dynamically based on i.e. EAP-Identity */ - EAP_DYNAMIC = 252, - /** not a method, but an implementation providing different methods */ - EAP_RADIUS = 253, EAP_EXPANDED = 254, EAP_EXPERIMENTAL = 255, + /** not a method, but an implementation providing different methods */ + EAP_RADIUS = 256, + /** not a method, select method dynamically based on client selection */ + EAP_DYNAMIC = 257, }; /** @@ -83,6 +86,22 @@ extern enum_name_t *eap_type_names; extern enum_name_t *eap_type_short_names; /** + * Struct that stores EAP type and vendor ID + */ +struct eap_vendor_type_t { + + /** + * EAP type + */ + eap_type_t type; + + /** + * Vendor Id + */ + u_int32_t vendor; +}; + +/** * EAP packet format */ typedef struct __attribute__((packed)) { @@ -101,4 +120,12 @@ typedef struct __attribute__((packed)) { */ eap_type_t eap_type_from_string(char *name); +/** + * Parse a string of the form [eap-]type[-vendor]. + * + * @param str EAP method string + * @return parsed type (gets allocated), NULL if unknown or failed + */ +eap_vendor_type_t *eap_vendor_type_from_string(char *str); + #endif /** EAP_H_ @}*/ diff --git a/src/libstrongswan/utils/tun_device.c b/src/libstrongswan/utils/tun_device.c index 889fe6247..36f3359c0 100644 --- a/src/libstrongswan/utils/tun_device.c +++ b/src/libstrongswan/utils/tun_device.c @@ -3,6 +3,7 @@ * Copyright (C) 2012 Giuliano Grassi * Copyright (C) 2012 Ralf Sager * Hochschule fuer Technik Rapperswil + * Copyright (C) 2012 Martin Willi * * 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 @@ -24,8 +25,17 @@ #include <sys/socket.h> #include <sys/stat.h> #include <unistd.h> -#include <linux/if.h> +#include <net/if.h> + +#ifdef __APPLE__ +#include <net/if_utun.h> +#include <netinet/in_var.h> +#include <sys/kern_control.h> +#elif defined(__linux__) #include <linux/if_tun.h> +#else +#include <net/if_tun.h> +#endif #include "tun_device.h" @@ -127,6 +137,14 @@ METHOD(tun_device_t, set_address, bool, this->if_name, strerror(errno)); return FALSE; } +#ifdef __APPLE__ + if (ioctl(this->sock, SIOCSIFDSTADDR, &ifr) < 0) + { + DBG1(DBG_LIB, "failed to set dest address on %s: %s", + this->if_name, strerror(errno)); + return FALSE; + } +#endif /* __APPLE__ */ set_netmask(&ifr, family, netmask); @@ -176,6 +194,8 @@ METHOD(tun_device_t, set_mtu, bool, if (ioctl(this->sock, SIOCSIFMTU, &ifr) < 0) { + DBG1(DBG_LIB, "failed to set MTU on %s: %s", this->if_name, + strerror(errno)); return FALSE; } this->mtu = mtu; @@ -269,6 +289,20 @@ METHOD(tun_device_t, destroy, void, if (this->tunfd > 0) { close(this->tunfd); +#ifdef __FreeBSD__ + /* tun(4) says the following: "These network interfaces persist until + * the if_tun.ko module is unloaded, or until removed with the + * ifconfig(8) command." So simply closing the FD is not enough. */ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); + if (ioctl(this->sock, SIOCIFDESTROY, &ifr) < 0) + { + DBG1(DBG_LIB, "failed to destroy %s: %s", this->if_name, + strerror(errno)); + } +#endif /* __FreeBSD__ */ } if (this->sock > 0) { @@ -278,18 +312,70 @@ METHOD(tun_device_t, destroy, void, } /** - * Allocate a TUN device + * Initialize the tun device */ -static int tun_alloc(char dev[IFNAMSIZ]) +static bool init_tun(private_tun_device_t *this, const char *name_tmpl) { +#ifdef __APPLE__ + + struct ctl_info info; + struct sockaddr_ctl addr; + socklen_t size = IFNAMSIZ; + + memset(&info, 0, sizeof(info)); + memset(&addr, 0, sizeof(addr)); + + this->tunfd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + if (this->tunfd < 0) + { + DBG1(DBG_LIB, "failed to open tundevice PF_SYSTEM socket: %s", + strerror(errno)); + return FALSE; + } + + /* get a control identifier for the utun kernel extension */ + strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME)); + if (ioctl(this->tunfd, CTLIOCGINFO, &info) < 0) + { + DBG1(DBG_LIB, "failed to ioctl tundevice: %s", strerror(errno)); + close(this->tunfd); + return FALSE; + } + + addr.sc_id = info.ctl_id; + addr.sc_len = sizeof(addr); + addr.sc_family = AF_SYSTEM; + addr.ss_sysaddr = AF_SYS_CONTROL; + /* allocate identifier dynamically */ + addr.sc_unit = 0; + + if (connect(this->tunfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { + DBG1(DBG_LIB, "failed to connect tundevice: %s", strerror(errno)); + close(this->tunfd); + return FALSE; + } + if (getsockopt(this->tunfd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, + this->if_name, &size) < 0) + { + DBG1(DBG_LIB, "getting tundevice name failed: %s", strerror(errno)); + close(this->tunfd); + return FALSE; + } + return TRUE; + +#elif defined(IFF_TUN) + struct ifreq ifr; - int fd; - fd = open("/dev/net/tun", O_RDWR); - if (fd < 0) + strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ); + this->if_name[IFNAMSIZ-1] = '\0'; + + this->tunfd = open("/dev/net/tun", O_RDWR); + if (this->tunfd < 0) { DBG1(DBG_LIB, "failed to open /dev/net/tun: %s", strerror(errno)); - return fd; + return FALSE; } memset(&ifr, 0, sizeof(ifr)); @@ -297,16 +383,42 @@ static int tun_alloc(char dev[IFNAMSIZ]) /* TUN device, no packet info */ ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - strncpy(ifr.ifr_name, dev, IFNAMSIZ); - - if (ioctl(fd, TUNSETIFF, (void*)&ifr) < 0) + strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); + if (ioctl(this->tunfd, TUNSETIFF, (void*)&ifr) < 0) { DBG1(DBG_LIB, "failed to configure TUN device: %s", strerror(errno)); - close(fd); - return -1; + close(this->tunfd); + return FALSE; + } + strncpy(this->if_name, ifr.ifr_name, IFNAMSIZ); + return TRUE; + +#else /* !IFF_TUN */ + + /* this works on FreeBSD and might also work on Linux with older TUN + * driver versions (no IFF_TUN) */ + char devname[IFNAMSIZ]; + int i; + + if (name_tmpl) + { + DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported"); } - strncpy(dev, ifr.ifr_name, IFNAMSIZ); - return fd; + + for (i = 0; i < 256; i++) + { + snprintf(devname, IFNAMSIZ, "/dev/tun%d", i); + this->tunfd = open(devname, O_RDWR); + if (this->tunfd > 0) + { /* for ioctl(2) calls only the interface name is used */ + snprintf(this->if_name, IFNAMSIZ, "tun%d", i); + break; + } + DBG1(DBG_LIB, "failed to open %s: %s", this->if_name, strerror(errno)); + } + return this->tunfd > 0; + +#endif /* !__APPLE__ */ } /* @@ -331,13 +443,9 @@ tun_device_t *tun_device_create(const char *name_tmpl) .sock = -1, ); - strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ); - this->if_name[IFNAMSIZ-1] = '\0'; - - this->tunfd = tun_alloc(this->if_name); - if (this->tunfd < 0) + if (!init_tun(this, name_tmpl)) { - destroy(this); + free(this); return NULL; } DBG1(DBG_LIB, "created TUN device: %s", this->if_name); |