-CFLAGS += -Lssl -I/usr/include/openssl
+CFLAGS += -I/usr/include/openssl -g -I/usr/include/libxml2 -Wall
-cisco: cisco.o
- $(CC) -o $@ $<
+cisco: cisco.o tun.o dtls.o ssl.o
+ $(CC) -o $@ -lssl $^
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <linux/if_tun.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
#include <sys/utsname.h>
#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
+#include <openssl/rand.h>
#define _GNU_SOURCE
#include <getopt.h>
session, bypassing all the initial setup of a normal DTLS connection.
Or you can just send traffic over the HTTPS connection... */
-char *cookie;
-char *hostname;
-unsigned char dtls_secret[48];
-int mtu = 1406;
-int deflate;
-const char *useragent = "Open AnyConnect VPN Agent v0.01";
-int verbose;
-
-/* Set up a tuntap device. */
-int setup_tun(struct cstp_option *options)
-{
- struct ifreq ifr;
- int tun_fd;
-
- tun_fd = open("/dev/net/tun", O_RDWR);
- if (tun_fd == -1) {
- perror("open tun");
- exit(1);
- }
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
- strncpy(ifr.ifr_name, "cisco0", sizeof(ifr.ifr_name) - 1);
- if (ioctl(tun_fd, TUNSETIFF, (void *) &ifr) < 0){
- perror("TUNSETIFF");
- exit(1);
- }
- /* FIXME: Configure it... */
- /* Better still, use lwip and just provide a SOCKS server rather than
- telling the kernel at all */
- return tun_fd;
-}
-
-
-SSL *open_https(const char *host)
-{
- SSL_METHOD *ssl3_method;
- SSL_CTX *https_ctx;
- SSL *https_ssl;
- BIO *https_bio;
- int ssl_sock;
- int err;
- struct addrinfo hints, *result, *rp;
-
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
- hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
- hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
- hints.ai_protocol = 0; /* Any protocol */
- hints.ai_canonname = NULL;
- hints.ai_addr = NULL;
- hints.ai_next = NULL;
-
- err = getaddrinfo(host, "https", &hints, &result);
- if (err) {
- fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(err));
- return NULL;
- }
-
- for (rp = result; rp ; rp = rp->ai_next) {
- ssl_sock = socket(rp->ai_family, rp->ai_socktype,
- rp->ai_protocol);
- if (ssl_sock < 0)
- continue;
-
- if (connect(ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0)
- break;
-
- close(ssl_sock);
- }
- freeaddrinfo(result);
-
- if (!rp) {
- fprintf(stderr, "Failed to connect to host %s\n", host);
- return NULL;
- }
-
- ssl3_method = SSLv23_client_method();
- https_ctx = SSL_CTX_new(ssl3_method);
- https_ssl = SSL_new(https_ctx);
-
- https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
- SSL_set_bio(https_ssl, https_bio, https_bio);
-
- if (SSL_connect(https_ssl) <= 0) {
- fprintf(stderr, "SSL connection failure\n");
- ERR_print_errors_fp(stderr);
- SSL_free(https_ssl);
- SSL_CTX_free(https_ctx);
- return NULL;
- }
-
- return https_ssl;
-}
-
-
-int __attribute__ ((format (printf, 2, 3))) my_SSL_printf(SSL *ssl, const char *fmt, ...)
-{
- char buf[1024];
- va_list args;
-
-
- buf[1023] = 0;
-
- va_start(args, fmt);
- vsnprintf(buf, 1023, fmt, args);
- va_end(args);
- if (verbose)
- printf("%s", buf);
- return SSL_write(ssl, buf, strlen(buf));
-
-}
-
-int my_SSL_gets(SSL *ssl, char *buf, size_t len)
-{
- int i = 0;
- int ret;
-
- if (len < 2)
- return -EINVAL;
-
- while ( (ret = SSL_read(ssl, buf + i, 1)) == 1) {
- if (buf[i] == '\n') {
- buf[i] = 0;
- if (i && buf[i-1] == '\r') {
- buf[i-1] = 0;
- i--;
- }
- return i;
- }
- i++;
-
- if (i >= len - 1) {
- buf[i] = 0;
- return i;
- }
- }
-
- buf[i] = 0;
- return i?:ret;
-}
-
-struct cstp_option *start_ssl_connection(SSL *ssl)
-{
- char buf[65536];
- int i;
- struct utsname utsbuf;
- struct cstp_option *options = NULL, **next_option = &options;
-
- if (uname(&utsbuf))
- printf(utsbuf.nodename, "localhost");
-
- if (verbose)
- printf("Connected to HTTPS on %s\n", hostname);
-
- my_SSL_printf(ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
- my_SSL_printf(ssl, "Host: %s\r\n", hostname);
- my_SSL_printf(ssl, "User-Agent: %s\r\n", useragent);
- my_SSL_printf(ssl, "Cookie: webvpn=%s\r\n", cookie);
- my_SSL_printf(ssl, "X-CSTP-Version: 1\r\n");
- my_SSL_printf(ssl, "X-CSTP-Hostname: %s\r\n", utsbuf.nodename);
- if (deflate)
- my_SSL_printf(ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
- my_SSL_printf(ssl, "X-CSTP-MTU: %d\r\n", mtu);
- my_SSL_printf(ssl, "X-CSTP-Address-Type: IPv6,IPv4\r\n");
- my_SSL_printf(ssl, "X-DTLS-Master-Secret: ");
- for (i = 0; i < sizeof(dtls_secret); i++)
- my_SSL_printf(ssl, "%02X", dtls_secret[i]);
- my_SSL_printf(ssl, "\r\nX-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n");
-
- if (my_SSL_gets(ssl, buf, 65536) < 0) {
- fprintf(stderr, "Error fetching HTTPS response\n");
- return NULL;
- }
-
- if (verbose)
- printf("Got CONNECT response: %s\n", buf);
-
- if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
- fprintf(stderr, "Got inappropriate HTTP CONNECT response: %s\n",
- buf);
- return NULL;
- }
-
-
- while ((i=my_SSL_gets(ssl, buf, sizeof(buf)))) {
- char *colon = strchr(buf, ':');
- if (!colon)
- continue;
-
- *colon = 0;
- colon++;
- if (*colon == ' ')
- colon++;
-
- *next_option = malloc(sizeof(*options));
- (*next_option)->option = strdup(buf);
- (*next_option)->value = strdup(colon);
- (*next_option)->next = NULL;
- next_option = &(*next_option)->next;
- }
-
- if (verbose)
- printf("Connected!\n");
- return options;
-}
+int verbose = 0;
static struct option long_options[] = {
{"cookie", 1, 0, 'c'},
{"host", 1, 0, 'h'},
{"mtu", 1, 0, 'm'},
{"verbose", 1, 0, 'v'},
- {"deflate", 1, 0, 'd'},
+ {"deflate", 0, 0, 'd'},
+ {"useragent", 1, 0, 'u'},
};
int main(int argc, char **argv)
{
- SSL *https_ssl;
- struct cstp_option *opts;
- int tun_fd;
+ struct anyconnect_info *vpninfo;
+ struct utsname utsbuf;
int optind;
int opt;
- char buf[65536 + 8];
- SSL_library_init ();
- ERR_clear_error ();
- SSL_load_error_strings ();
- OpenSSL_add_all_algorithms ();
+ vpn_init_openssl();
+
+ vpninfo = malloc(sizeof(*vpninfo));
+ if (!vpninfo) {
+ fprintf(stderr, "Failed to allocate vpninfo structure\n");
+ exit(1);
+ }
+ memset(vpninfo, 0, sizeof(*vpninfo));
+ /* Set up some defaults */
+ vpninfo->useragent = "Open AnyConnect VPN Agent v0.01";
+ vpninfo->mtu = 1406;
+ if (RAND_bytes(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)) != 1) {
+ fprintf(stderr, "Failed to initialise DTLS secret\n");
+ exit(1);
+ }
+ if (!uname(&utsbuf))
+ vpninfo->localname = utsbuf.nodename;
+ else
+ vpninfo->localname = "localhost";
+
+ /* While we get it working, make it slightly easier... and don't forget */
+ fprintf(stderr, "HACKING DTLS SECRET TO 0x5A5A5A...\n");
+ memset(vpninfo->dtls_secret, 0x5a, sizeof(vpninfo->dtls_secret));
- while ((opt = getopt_long(argc, argv, "c:h:vd", long_options, &optind))) {
+ while ((opt = getopt_long(argc, argv, "c:h:vdu:", long_options, &optind))) {
if (opt < 0)
break;
switch (opt) {
case 'c':
- cookie = optarg;
+ vpninfo->cookie = optarg;
break;
case 'h':
- hostname = optarg;
+ vpninfo->hostname = optarg;
break;
case 'm':
- mtu = atol(optarg);
- if (mtu < 576) {
- fprintf(stderr, "MTU %d too small\n", mtu);
- exit(1);
+ vpninfo->mtu = atol(optarg);
+ if (vpninfo->mtu < 576) {
+ fprintf(stderr, "MTU %d too small\n", vpninfo->mtu);
+ vpninfo->mtu = 576;
}
break;
+ case 'u':
+ vpninfo->useragent = optarg;
+ break;
+
case 'v':
verbose = 1;
break;
case 'd':
fprintf(stderr, "Deflate not yet supported\n");
- //deflate = 1;
+ //vpninfo->deflate = 1;
break;
}
}
- if (!hostname || !cookie) {
+ if (!vpninfo->hostname || !vpninfo->cookie) {
fprintf(stderr, "Need -h hostname, -c cookie\n");
exit(1);
}
- https_ssl = open_https(hostname);
- if (!https_ssl)
+ if (make_ssl_connection(vpninfo)) {
+ fprintf(stderr, "Creating SSL connection failed\n");
+ exit(1);
+ }
+
+ if (setup_tun(vpninfo)) {
+ fprintf(stderr, "Set up tun device failed\n");
exit(1);
- int i;
- for (i=0; i<48; i++)
- dtls_secret[i] = i;
-
- opts = start_ssl_connection(https_ssl);
-
- while (opts) {
- printf ("Got opt %s, val %s\n", opts->option, opts->value);
- opts = opts->next;
}
- exit(1);
+
+ if (setup_dtls(vpninfo))
+ fprintf(stderr, "Set up DTLS failed\n");
printf("Connected\n");
+ exit(1);
- tun_fd = setup_tun(NULL);
+#if 0
if (fork()) {
while (1) {
buf[4] = len >> 8;
buf[5] = len & 0xff;
}
- SSL_write(https_ssl, buf, len + 8);
+ SSL_write(https_info->https_ssl, buf, len + 8);
}
} else {
while (1) {
int len;
- SSL_read(https_ssl, buf, 8);
+ SSL_read(https_info->https_ssl, buf, 8);
len = (buf[4] << 8) + buf [5];
- SSL_read(https_ssl, buf + 8, len);
+ SSL_read(https_info->https_ssl, buf + 8, len);
if (buf[0] != 'S' ||
buf[1] != 'T' ||
buf[2] != 'F' ||
}
}
}
+#endif
}
--- /dev/null
+/*
+ * Open AnyConnect (SSL + DTLS) client
+ *
+ * © 2008 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+
+#include "anyconnect.h"
+
+int setup_dtls(struct anyconnect_info *vpninfo)
+{
+ struct vpn_option *dtls_opt = vpninfo->dtls_options;
+
+ while (dtls_opt) {
+ printf("DTLS option %s : %s\n", dtls_opt->option, dtls_opt->value);
+ dtls_opt = dtls_opt->next;
+ }
+ /* No idea how to do this yet */
+ return -EINVAL;
+}
+
--- /dev/null
+/*
+ * Open AnyConnect (SSL + DTLS) client
+ *
+ * © 2008 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/socket.h>
+#include <netdb.h>
+#include <unistd.h>
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "anyconnect.h"
+
+SSL *open_https(struct anyconnect_info *vpninfo)
+{
+ SSL_METHOD *ssl3_method;
+ SSL_CTX *https_ctx;
+ SSL *https_ssl;
+ BIO *https_bio;
+ int ssl_sock;
+ int err;
+ struct addrinfo hints, *result, *rp;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
+ hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
+ hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
+ hints.ai_protocol = 0; /* Any protocol */
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+
+ err = getaddrinfo(vpninfo->hostname, "https", &hints, &result);
+ if (err) {
+ fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(err));
+ return NULL;
+ }
+
+ for (rp = result; rp ; rp = rp->ai_next) {
+ ssl_sock = socket(rp->ai_family, rp->ai_socktype,
+ rp->ai_protocol);
+ if (ssl_sock < 0)
+ continue;
+
+ if (connect(ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0)
+ break;
+
+ close(ssl_sock);
+ }
+ freeaddrinfo(result);
+
+ if (!rp) {
+ fprintf(stderr, "Failed to connect to host %s\n", vpninfo->hostname);
+ return NULL;
+ }
+
+ ssl3_method = SSLv23_client_method();
+ https_ctx = SSL_CTX_new(ssl3_method);
+ https_ssl = SSL_new(https_ctx);
+
+ https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
+ SSL_set_bio(https_ssl, https_bio, https_bio);
+
+ if (SSL_connect(https_ssl) <= 0) {
+ fprintf(stderr, "SSL connection failure\n");
+ ERR_print_errors_fp(stderr);
+ SSL_free(https_ssl);
+ SSL_CTX_free(https_ctx);
+ return NULL;
+ }
+
+ return https_ssl;
+}
+
+
+int __attribute__ ((format (printf, 2, 3))) my_SSL_printf(SSL *ssl, const char *fmt, ...)
+{
+ char buf[1024];
+ va_list args;
+
+
+ buf[1023] = 0;
+
+ va_start(args, fmt);
+ vsnprintf(buf, 1023, fmt, args);
+ va_end(args);
+ if (verbose)
+ printf("%s", buf);
+ return SSL_write(ssl, buf, strlen(buf));
+
+}
+
+int my_SSL_gets(SSL *ssl, char *buf, size_t len)
+{
+ int i = 0;
+ int ret;
+
+ if (len < 2)
+ return -EINVAL;
+
+ while ( (ret = SSL_read(ssl, buf + i, 1)) == 1) {
+ if (buf[i] == '\n') {
+ buf[i] = 0;
+ if (i && buf[i-1] == '\r') {
+ buf[i-1] = 0;
+ i--;
+ }
+ return i;
+ }
+ i++;
+
+ if (i >= len - 1) {
+ buf[i] = 0;
+ return i;
+ }
+ }
+
+ buf[i] = 0;
+ return i?:ret;
+}
+
+int start_ssl_connection(struct anyconnect_info *vpninfo)
+{
+ char buf[65536];
+ int i;
+ struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
+ struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
+
+ if (verbose)
+ printf("Connected to HTTPS on %s\n", vpninfo->hostname);
+
+ my_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
+ my_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
+ my_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
+ my_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
+ my_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
+ my_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
+ if (vpninfo->deflate)
+ my_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
+ my_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
+ my_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: IPv6,IPv4\r\n");
+ my_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
+ for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
+ my_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
+ my_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n");
+
+ if (my_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
+ fprintf(stderr, "Error fetching HTTPS response\n");
+ return -EINVAL;
+ }
+
+ if (verbose)
+ printf("Got CONNECT response: %s\n", buf);
+
+ if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
+ fprintf(stderr, "Got inappropriate HTTP CONNECT response: %s\n",
+ buf);
+ return -EINVAL;
+ }
+
+
+ while ((i=my_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
+ struct vpn_option *new_option;
+ char *colon = strchr(buf, ':');
+ if (!colon)
+ continue;
+
+ *colon = 0;
+ colon++;
+ if (*colon == ' ')
+ colon++;
+
+ if (strncmp(buf, "X-DTLS-", 7) &&
+ strncmp(buf, "X-CSTP-", 7))
+ continue;
+
+ new_option = malloc(sizeof(*new_option));
+ if (!new_option) {
+ fprintf(stderr, "No memory for allocation options\n");
+ return -ENOMEM;
+ }
+ new_option->option = strdup(buf);
+ new_option->value = strdup(colon);
+ new_option->next = NULL;
+
+ if (!new_option->option || !new_option->value) {
+ fprintf(stderr, "No memory for allocation options\n");
+ return -ENOMEM;
+ }
+
+ if (!strncmp(buf, "X-DTLS-", 7)) {
+ *next_dtls_option = new_option;
+ next_dtls_option = &new_option->next;
+ } else {
+ *next_cstp_option = new_option;
+ next_cstp_option = &new_option->next;
+ }
+ }
+
+ if (verbose)
+ printf("Connected!\n");
+ return 0;
+}
+
+int make_ssl_connection(struct anyconnect_info *vpninfo)
+{
+ SSL *https_ssl = open_https(vpninfo);
+ if (!https_ssl)
+ exit(1);
+
+ vpninfo->https_ssl = https_ssl;
+ if (start_ssl_connection(vpninfo))
+ exit(1);
+ return 0;
+}
+
+
+void vpn_init_openssl(void)
+{
+ SSL_library_init ();
+ ERR_clear_error ();
+ SSL_load_error_strings ();
+ OpenSSL_add_all_algorithms ();
+}
--- /dev/null
+/*
+ * Open AnyConnect (SSL + DTLS) client
+ *
+ * © 2008 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <linux/if_tun.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "anyconnect.h"
+
+/* Set up a tuntap device. */
+int setup_tun(struct anyconnect_info *vpninfo)
+{
+ struct vpn_option *cstp_opt = vpninfo->cstp_options;
+ struct ifreq ifr;
+ int tun_fd;
+
+ tun_fd = open("/dev/net/tun", O_RDWR);
+ if (tun_fd == -1) {
+ perror("open tun");
+ exit(1);
+ }
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+ strncpy(ifr.ifr_name, "cisco0", sizeof(ifr.ifr_name) - 1);
+ if (ioctl(tun_fd, TUNSETIFF, (void *) &ifr) < 0){
+ perror("TUNSETIFF");
+ exit(1);
+ }
+
+ /* FIXME: Configure it... */
+ while (cstp_opt) {
+ printf("CSTP option %s : %s\n", cstp_opt->option, cstp_opt->value);
+ cstp_opt = cstp_opt->next;
+ }
+
+ /* Better still, use lwip and just provide a SOCKS server rather than
+ telling the kernel about it at all */
+ vpninfo->tun_fd = tun_fd;
+ return 0;
+}
+