Skip to content

Commit

Permalink
First attempt at a mainloop
Browse files Browse the repository at this point in the history
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Sep 22, 2008
1 parent 8125385 commit 051c4d4
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 107 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -8,7 +8,7 @@ endif
CFLAGS += -I/usr/include/openssl #-I/usr/include/libxml2
LDFLAGS += -lssl

OBJECTS := main.o tun.o dtls.o ssl.o
OBJECTS := main.o tun.o dtls.o ssl.o mainloop.o

anyconnect: $(OBJECTS)
$(CC) -o $@ $(LDFLAGS) $^
Expand Down
6 changes: 6 additions & 0 deletions dtls.c
Expand Up @@ -34,3 +34,9 @@ int setup_dtls(struct anyconnect_info *vpninfo)
return -EINVAL;
}

int dtls_mainloop(struct anyconnect_info *vpninfo, int *timeout)
{
return 0;
}


50 changes: 4 additions & 46 deletions main.c
Expand Up @@ -66,7 +66,9 @@ int main(int argc, char **argv)
exit(1);
}
memset(vpninfo, 0, sizeof(*vpninfo));

/* Set up some defaults */
vpninfo->tun_fd = vpninfo->ssl_fd = vpninfo->dtls_fd = -1;
vpninfo->useragent = "Open AnyConnect VPN Agent v0.01";
vpninfo->mtu = 1406;
if (RAND_bytes(vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)) != 1) {
Expand Down Expand Up @@ -133,53 +135,9 @@ int main(int argc, char **argv)
}

if (setup_dtls(vpninfo))
fprintf(stderr, "Set up DTLS failed\n");
fprintf(stderr, "Set up DTLS failedd; using SSL instead\n");

printf("Connected\n");
vpn_mainloop(vpninfo);
exit(1);

#if 0

if (fork()) {
while (1) {
size_t len;

buf[0] = 'S';
buf[1] = 'T';
buf[2] = 'F';
buf[3] = 1;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;

len = read(tun_fd, &buf[8], 65536);
if (len >= 0) {
buf[4] = len >> 8;
buf[5] = len & 0xff;
}
SSL_write(https_info->https_ssl, buf, len + 8);
}
} else {
while (1) {
int len;
SSL_read(https_info->https_ssl, buf, 8);

len = (buf[4] << 8) + buf [5];
SSL_read(https_info->https_ssl, buf + 8, len);
if (buf[0] != 'S' ||
buf[1] != 'T' ||
buf[2] != 'F' ||
buf[3] != 1 ||
buf[6] != 0 ||
buf[7] != 0) {
printf("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7]);
} else {
write(tun_fd, buf + 8, len);
}
}
}
#endif
}
188 changes: 128 additions & 60 deletions ssl.c
Expand Up @@ -20,13 +20,66 @@
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

#include "anyconnect.h"

SSL *open_https(struct anyconnect_info *vpninfo)
/* Helper functions for reading/writing lines over SSL.
We could use cURL for the HTTP stuff, but it's overkill */

static 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));

}

static 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 open_https(struct anyconnect_info *vpninfo)
{
SSL_METHOD *ssl3_method;
SSL_CTX *https_ctx;
Expand All @@ -37,18 +90,18 @@ SSL *open_https(struct anyconnect_info *vpninfo)
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_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
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;
return -EINVAL;
}

for (rp = result; rp ; rp = rp->ai_next) {
Expand All @@ -57,16 +110,25 @@ SSL *open_https(struct anyconnect_info *vpninfo)
if (ssl_sock < 0)
continue;

if (connect(ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0)
if (connect(ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
/* Store the peer address we actually used, so that DTLS can
use it again later */
vpninfo->peer_addr = malloc(rp->ai_addrlen);
if (!vpninfo->peer_addr) {
fprintf(stderr, "Failed to allocate sockaddr storage\n");
close(ssl_sock);
return -ENOMEM;
}
memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen);
break;

}
close(ssl_sock);
}
freeaddrinfo(result);

if (!rp) {
fprintf(stderr, "Failed to connect to host %s\n", vpninfo->hostname);
return NULL;
return -EINVAL;
}

ssl3_method = SSLv23_client_method();
Expand All @@ -81,59 +143,15 @@ SSL *open_https(struct anyconnect_info *vpninfo)
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;
vpninfo->ssl_fd = ssl_sock;
vpninfo->https_ssl = https_ssl;
return 0;
}


int start_ssl_connection(struct anyconnect_info *vpninfo)
{
char buf[65536];
Expand Down Expand Up @@ -214,18 +232,25 @@ int start_ssl_connection(struct anyconnect_info *vpninfo)

if (verbose)
printf("Connected!\n");

BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl),1);
BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl),1);

fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);

vpninfo->ssl_pfd = vpn_add_pollfd(vpninfo, vpninfo->ssl_fd, POLLIN);

return 0;
}

int make_ssl_connection(struct anyconnect_info *vpninfo)
{
SSL *https_ssl = open_https(vpninfo);
if (!https_ssl)
if (open_https(vpninfo))
exit(1);

vpninfo->https_ssl = https_ssl;
if (start_ssl_connection(vpninfo))
exit(1);

return 0;
}

Expand All @@ -237,3 +262,46 @@ void vpn_init_openssl(void)
SSL_load_error_strings ();
OpenSSL_add_all_algorithms ();
}

static char data_hdr[8] = {'S', 'T', 'F', 1, 0, 0, 0, 0};

int ssl_mainloop(struct anyconnect_info *vpninfo, int *timeout)
{
unsigned char buf[16384];
int len;
int work_done = 0;

while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {

if (buf[0] != 'S' || buf[1] != 'T' ||
buf[2] != 'F' || buf[3] != 1 ||
buf[6] != 0 || buf[7] != 0) {
printf("Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7]);
continue;
}
if (len != 8 + (buf[4] << 8) + buf[5]) {
printf("Unexpected packet length. SSL_read returned %d but packet is\n",
len);
printf("%02x %02x %02x %02x %02x %02x %02x %02x\n",
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7]);
}
queue_new_packet(&vpninfo->incoming_queue, AF_INET, buf + 8,
(buf[4] << 8) + buf[5]);
work_done = 1;
}

while (vpninfo->outgoing_queue) {
struct pkt *this = vpninfo->outgoing_queue;
vpninfo->outgoing_queue = this->next;
memcpy(this->hdr, data_hdr, 8);
this->hdr[4] = this->len >> 8;
this->hdr[5] = this->len & 0xff;

SSL_write(vpninfo->https_ssl, this->hdr, this->len + 8);
}
/* Work is not done if we just got rid of packets off the queue */
return work_done;
}
25 changes: 25 additions & 0 deletions tun.c
Expand Up @@ -25,6 +25,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include "anyconnect.h"

Expand All @@ -34,6 +35,7 @@ int setup_tun(struct anyconnect_info *vpninfo)
struct vpn_option *cstp_opt = vpninfo->cstp_options;
struct ifreq ifr;
int tun_fd;
int pfd;

tun_fd = open("/dev/net/tun", O_RDWR);
if (tun_fd == -1) {
Expand All @@ -57,6 +59,29 @@ int setup_tun(struct anyconnect_info *vpninfo)
/* Better still, use lwip and just provide a SOCKS server rather than
telling the kernel about it at all */
vpninfo->tun_fd = tun_fd;
pfd = vpn_add_pollfd(vpninfo, vpninfo->tun_fd, POLLIN);

fcntl(vpninfo->tun_fd, F_SETFL, fcntl(vpninfo->tun_fd, F_GETFL) | O_NONBLOCK);

return 0;
}

int tun_mainloop(struct anyconnect_info *vpninfo, int *timeout)
{
char buf[2000];
int len;
int work_done = 0;

while ( (len = read(vpninfo->tun_fd, buf, sizeof(buf))) > 0) {
queue_new_packet(&vpninfo->outgoing_queue, AF_INET, buf, len);
work_done = 1;
}

while (vpninfo->incoming_queue) {
struct pkt *this = vpninfo->incoming_queue;
vpninfo->incoming_queue = this->next;
write(vpninfo->tun_fd, this->data, this->len);
}
/* Work is not done if we just got rid of packets off the queue */
return work_done;
}

0 comments on commit 051c4d4

Please sign in to comment.