Skip to content

Commit

Permalink
use generic KA stuff for dtls
Browse files Browse the repository at this point in the history
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Oct 2, 2008
1 parent c5a17b7 commit cea4b05
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 94 deletions.
1 change: 1 addition & 0 deletions anyconnect.h
Expand Up @@ -159,6 +159,7 @@ int vpn_add_pollfd(struct anyconnect_info *vpninfo, int fd, short events);
int vpn_mainloop(struct anyconnect_info *vpninfo);
int queue_new_packet(struct pkt **q, int type, void *buf, int len);
void queue_packet(struct pkt **q, struct pkt *new);
int keepalive_action(struct keepalive_info *ka, int *timeout);

/* xml.c */
int config_lookup_host(struct anyconnect_info *vpninfo, const char *host);
Expand Down
151 changes: 58 additions & 93 deletions dtls.c
Expand Up @@ -253,6 +253,7 @@ int dtls_mainloop(struct anyconnect_info *vpninfo, int *timeout)
unsigned char buf[2000];
int len;
int work_done = 0;
char magic_pkt;

while ( (len = SSL_read(vpninfo->dtls_ssl, buf, sizeof(buf))) > 0 ) {
if (verbose)
Expand All @@ -278,42 +279,13 @@ int dtls_mainloop(struct anyconnect_info *vpninfo, int *timeout)
return 1;
}
}
while (vpninfo->outgoing_queue) {
struct pkt *this = vpninfo->outgoing_queue;
int ret;

vpninfo->outgoing_queue = this->next;

/* One byte of header */
this->hdr[7] = AC_PKT_DATA;

ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
/* There's not a lot we can do if the write fails. If the link is
really dead, DPD will kick in and we should fall back to SSL,
if that's still working */
vpninfo->dtls_times.last_tx = time(NULL);
if (verbose) {
printf("Sent DTLS packet of %d bytes; SSL_write() returned %d\n",
this->len, ret);
}
}

/* DPD is bidirectional -- PKT 3 out, PKT 4 back */
if (vpninfo->dtls_times.dpd) {
time_t now = time(NULL);
time_t due = vpninfo->dtls_times.last_rx + vpninfo->dtls_times.dpd;
time_t overdue = vpninfo->dtls_times.last_rx + (2 * vpninfo->dtls_times.dpd);

/* If we already have DPD outstanding, don't flood */
if (vpninfo->dtls_times.last_dpd > vpninfo->dtls_times.last_rx) {
if (verbose) {
printf("DTLS DPD outstanding. Will kill in %ld seconds\n",
overdue - now);
}
due = vpninfo->dtls_times.last_dpd + vpninfo->dtls_times.dpd;
}
if (now > overdue) {
fprintf(stderr, "DTLS Dead Peer Detection detected dead peer!\n");
switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
case KA_REKEY:
if (verbose)
printf("DTLS rekey due\n");
if (dtls_rekey(vpninfo)) {
fprintf(stderr, "DTLS rekey failed\n");
/* Fall back to SSL */
SSL_free(vpninfo->dtls_ssl);
close(vpninfo->dtls_fd);
Expand All @@ -322,73 +294,66 @@ int dtls_mainloop(struct anyconnect_info *vpninfo, int *timeout)
vpninfo->dtls_fd = -1;
return 1;
}
if (now >= due) {
static unsigned char dtls_dpd_pkt[1] = { 3 };
/* Haven't heard anything from the other end for a while.
Check if it's still there */
/* FIXME: If isn't, we should act on that */
SSL_write(vpninfo->dtls_ssl, dtls_dpd_pkt, 1);
vpninfo->dtls_times.last_dpd = vpninfo->dtls_times.last_tx = now;

due = now + vpninfo->dtls_times.dpd;
if (verbose)
printf("Sent DTLS DPD\n");
}

if (verbose && due < overdue)
printf("Next DTLS DPD due in %ld seconds\n", (due - now));
if (*timeout > (due - now) * 1000)
*timeout = (due - now) * 1000;
}
time(&vpninfo->dtls_times.last_rekey);
work_done = 1;
break;


case KA_DPD_DEAD:
fprintf(stderr, "DTLS Dead Peer Detection detected dead peer!\n");
/* Fall back to SSL */
SSL_free(vpninfo->dtls_ssl);
close(vpninfo->dtls_fd);
vpninfo->pfds[vpninfo->dtls_pfd].fd = -1;
vpninfo->dtls_ssl = NULL;
vpninfo->dtls_fd = -1;
return 1;

case KA_DPD:
if (verbose)
printf("Send DTLS DPD\n");

/* Keepalive is just client -> server */
if (vpninfo->dtls_times.keepalive) {
time_t now = time(NULL);
time_t due = vpninfo->dtls_times.last_tx + vpninfo->dtls_times.keepalive;
magic_pkt = AC_PKT_DPD_OUT;
SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
/* last_dpd will just have been set */
vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
work_done = 1;
break;

if (now >= due) {
static unsigned char dtls_keepalive_pkt[1] = { 7 };
case KA_KEEPALIVE:
if (verbose)
printf("Send DTLS Keepalive\n");

/* Send something (which is discarded), to keep
the connection alive. */
SSL_write(vpninfo->dtls_ssl, dtls_keepalive_pkt, 1);
vpninfo->dtls_times.last_tx = now;
/* No need to send an explicit keepalive
if we have real data to send */
if (vpninfo->outgoing_queue)
break;

due = now + vpninfo->dtls_times.keepalive;
if (verbose)
printf("Sent DTLS Keepalive\n");
}
magic_pkt = AC_PKT_KEEPALIVE;
SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
time(&vpninfo->dtls_times.last_tx);
work_done = 1;
break;

if (verbose)
printf("Next DTLS Keepalive due in %ld seconds\n", (due - now));
if (*timeout > (due - now) * 1000)
*timeout = (due - now) * 1000;
case KA_NONE:
;
}

if (vpninfo->dtls_times.rekey) {
time_t now = time(NULL);
time_t due = vpninfo->dtls_times.last_rekey + vpninfo->dtls_times.rekey;
while (vpninfo->outgoing_queue) {
struct pkt *this = vpninfo->outgoing_queue;
int ret;

if (now >= due) {
if (verbose)
printf("DTLS rekey due\n");
if (dtls_rekey(vpninfo)) {
fprintf(stderr, "DTLS rekey failed\n");
/* Fall back to SSL */
SSL_free(vpninfo->dtls_ssl);
close(vpninfo->dtls_fd);
vpninfo->pfds[vpninfo->dtls_pfd].fd = -1;
vpninfo->dtls_ssl = NULL;
vpninfo->dtls_fd = -1;
return 1;
}
vpninfo->dtls_times.last_rekey = time(NULL);
due = vpninfo->dtls_times.last_rekey + vpninfo->dtls_times.rekey;
vpninfo->outgoing_queue = this->next;

/* One byte of header */
this->hdr[7] = AC_PKT_DATA;

ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
time(&vpninfo->dtls_times.last_tx);
if (verbose) {
printf("Sent DTLS packet of %d bytes; SSL_write() returned %d\n",
this->len, ret);
}
if (verbose)
printf("Next DTLS rekey due in %ld seconds\n", (due - now));
if (*timeout > (due - now) * 1000)
*timeout = (due - now) * 1000;
}

return work_done;
Expand Down
8 changes: 7 additions & 1 deletion mainloop.c
Expand Up @@ -134,7 +134,7 @@ int vpn_mainloop(struct anyconnect_info *vpninfo)
return 0;
}

int keepalive_action(struct keepalive_info *ka, time_t *timeout)
int keepalive_action(struct keepalive_info *ka, int *timeout)
{
time_t now = time(NULL);

Expand All @@ -144,6 +144,8 @@ int keepalive_action(struct keepalive_info *ka, time_t *timeout)
if (now >= due)
return KA_REKEY;

if (verbose)
printf("Rekey in %d seconds\n", (int)(due - now));
if (*timeout > (due - now) * 1000)
*timeout = (due - now) * 1000;
}
Expand All @@ -169,6 +171,8 @@ int keepalive_action(struct keepalive_info *ka, time_t *timeout)
return KA_DPD;
}

if (verbose)
printf("DPD in %d seconds\n", (int)(due - now));
if (*timeout > (due - now) * 1000)
*timeout = (due - now) * 1000;
}
Expand All @@ -182,6 +186,8 @@ int keepalive_action(struct keepalive_info *ka, time_t *timeout)
if (now >= due)
return KA_KEEPALIVE;

if (verbose)
printf("KA in %d seconds\n", (int)(due - now));
if (*timeout > (due - now) * 1000)
*timeout = (due - now) * 1000;
}
Expand Down

0 comments on commit cea4b05

Please sign in to comment.