diff --git a/esp.c b/esp.c index bb64b512..045a14bb 100644 --- a/esp.c +++ b/esp.c @@ -156,12 +156,35 @@ int print_esp_keys(struct openconnect_info *vpninfo, const char *name, struct es return 0; } -int esp_setup(struct openconnect_info *vpninfo, int dtls_attempt_period) +static int esp_send_probes(struct openconnect_info *vpninfo) { - int fd; struct pkt *pkt; int pktlen; + pkt = malloc(sizeof(*pkt) + 1 + vpninfo->pkt_trailer); + if (!pkt) + return -ENOMEM; + + pkt->len = 1; + pkt->data[0] = 0; + pktlen = encrypt_esp_packet(vpninfo, pkt); + send(vpninfo->dtls_fd, &pkt->esp, pktlen, 0); + + pkt->len = 1; + pkt->data[0] = 0; + pktlen = encrypt_esp_packet(vpninfo, pkt); + send(vpninfo->dtls_fd, &pkt->esp, pktlen, 0); + + free(pkt); + time(&vpninfo->new_dtls_started); + + return 0; +}; + +int esp_setup(struct openconnect_info *vpninfo, int dtls_attempt_period) +{ + int fd; + if (vpninfo->dtls_state == DTLS_DISABLED || vpninfo->dtls_state == DTLS_NOSECRET) return -EINVAL; @@ -170,34 +193,17 @@ int esp_setup(struct openconnect_info *vpninfo, int dtls_attempt_period) if (fd < 0) return fd; - pkt = malloc(sizeof(*pkt) + 1 + vpninfo->pkt_trailer); - if (!pkt) { - closesocket(fd); - return -ENOMEM; - } - print_esp_keys(vpninfo, _("incoming"), &vpninfo->esp_in); print_esp_keys(vpninfo, _("outgoing"), &vpninfo->esp_out); /* We are not connected until we get an ESP packet back */ - vpninfo->dtls_state = DTLS_CONNECTING; + vpninfo->dtls_state = DTLS_SLEEPING; vpninfo->dtls_fd = fd; monitor_fd_new(vpninfo, dtls); monitor_read_fd(vpninfo, dtls); monitor_except_fd(vpninfo, dtls); - pkt->len = 1; - pkt->data[0] = 0; - pktlen = encrypt_esp_packet(vpninfo, pkt); - send(fd, &pkt->esp, pktlen, 0); - - pkt->len = 1; - pkt->data[0] = 0; - pktlen = encrypt_esp_packet(vpninfo, pkt); - send(fd, &pkt->esp, pktlen, 0); - - free(pkt); - time(&vpninfo->new_dtls_started); + esp_send_probes(vpninfo); return 0; } @@ -254,9 +260,11 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout) pkt->len = len - 2 - pkt->data[len - 2]; if (pkt->len == 1 && pkt->data[0] == 0) { - vpn_progress(vpninfo, PRG_INFO, - _("ESP session established with server\n")); - vpninfo->dtls_state = DTLS_CONNECTED; + if (vpninfo->dtls_state == DTLS_SLEEPING) { + vpn_progress(vpninfo, PRG_INFO, + _("ESP session established with server\n")); + vpninfo->dtls_state = DTLS_CONNECTING; + } continue; } queue_packet(&vpninfo->incoming_queue, pkt); diff --git a/oncp.c b/oncp.c index c800e748..ae3e6cc4 100644 --- a/oncp.c +++ b/oncp.c @@ -908,6 +908,20 @@ static const unsigned char esp_kmp_part2[] = { /* And now 0x40 bytes of random secret for encryption and HMAC key */ +static const struct pkt esp_enable_pkt = { + .oncp_hdr = { + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x2f, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d + }, + .data = { + 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, /* Group 6, len 7 */ + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, /* Attr 1, len 1 */ + 0x01 + }, + .len = 13 +}; + int oncp_connect(struct openconnect_info *vpninfo) { int ret, ofs, kmp, kmpend, kmplen, attr, attrlen, group, grouplen, groupend; @@ -1447,13 +1461,14 @@ int oncp_mainloop(struct openconnect_info *vpninfo, int *timeout) /* Don't free the 'special' packets */ if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt) free(vpninfo->pending_deflated_pkt); - else -#if 0 /* No DPD or keepalive for Juniper yet */ - if (vpninfo->current_ssl_pkt != &dpd_pkt && - vpninfo->current_ssl_pkt != &dpd_resp_pkt && - vpninfo->current_ssl_pkt != &keepalive_pkt) -#endif + else if (vpninfo->current_ssl_pkt == &esp_enable_pkt) { + /* If we sent the special ESP enable packet, ESP + * is now enabled. And we don't need to free it. */ + if (vpninfo->dtls_state == DTLS_CONNECTING) + vpninfo->dtls_state = DTLS_CONNECTED; + } else { free(vpninfo->current_ssl_pkt); + } vpninfo->current_ssl_pkt = NULL; } @@ -1528,6 +1543,10 @@ int oncp_mainloop(struct openconnect_info *vpninfo, int *timeout) } #endif + if (vpninfo->dtls_state == DTLS_CONNECTING) { + vpninfo->current_ssl_pkt = (struct pkt *)&esp_enable_pkt; + goto handle_outgoing; + } /* Service outgoing packet queue, if no DTLS */ while (vpninfo->dtls_state != DTLS_CONNECTED && vpninfo->outgoing_queue) { struct pkt *this = vpninfo->outgoing_queue; diff --git a/openconnect-internal.h b/openconnect-internal.h index f978000f..c887a943 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -155,9 +155,9 @@ struct pkt { #define DTLS_NOSECRET 0 #define DTLS_SECRET 1 #define DTLS_DISABLED 2 -#define DTLS_SLEEPING 3 -#define DTLS_CONNECTING 4 -#define DTLS_CONNECTED 5 +#define DTLS_SLEEPING 3 /* For ESP, sometimes sending probes */ +#define DTLS_CONNECTING 4 /* ESP probe received; must tell server */ +#define DTLS_CONNECTED 5 /* Server informed and should be sending ESP */ #define COMPR_DEFLATE (1<<0) #define COMPR_LZS (1<<1)