aboutsummaryrefslogtreecommitdiffstats
path: root/src/libstrongswan
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan')
-rw-r--r--src/libstrongswan/eap/eap.c80
-rw-r--r--src/libstrongswan/eap/eap.h35
-rw-r--r--src/libstrongswan/utils/tun_device.c148
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);