return p;
}
-static int connect_dtls_socket(struct openconnect_info *vpninfo)
+static int connect_dtls_socket(struct openconnect_info *vpninfo, int *timeout)
{
int dtls_fd, ret;
time(&vpninfo->new_dtls_started);
- return dtls_try_handshake(vpninfo);
+ return dtls_try_handshake(vpninfo, timeout);
}
void dtls_close(struct openconnect_info *vpninfo)
vpninfo->dtls_state = DTLS_SLEEPING;
}
-static int dtls_reconnect(struct openconnect_info *vpninfo)
+int dtls_reconnect(struct openconnect_info *vpninfo, int *timeout)
{
dtls_close(vpninfo);
return -EINVAL;
vpninfo->dtls_state = DTLS_SLEEPING;
- return connect_dtls_socket(vpninfo);
+ return connect_dtls_socket(vpninfo, timeout);
}
int dtls_setup(struct openconnect_info *vpninfo)
if (vpninfo->dtls_times.rekey <= 0)
vpninfo->dtls_times.rekey_method = REKEY_NONE;
- if (connect_dtls_socket(vpninfo))
+ if (connect_dtls_socket(vpninfo, NULL))
return -EINVAL;
vpn_progress(vpninfo, PRG_DEBUG,
if (vpninfo->dtls_need_reconnect) {
vpninfo->dtls_need_reconnect = 0;
- dtls_reconnect(vpninfo);
+ dtls_reconnect(vpninfo, timeout);
return 1;
}
if (vpninfo->dtls_state == DTLS_CONNECTING) {
- dtls_try_handshake(vpninfo);
+ dtls_try_handshake(vpninfo, timeout);
vpninfo->delay_tunnel_reason = "DTLS MTU detection";
return 0;
}
if (when <= 0) {
vpn_progress(vpninfo, PRG_DEBUG, _("Attempt new DTLS connection\n"));
- if (connect_dtls_socket(vpninfo) < 0)
+ if (connect_dtls_socket(vpninfo, timeout) < 0)
*timeout = 1000;
} else if ((when * 1000) < *timeout) {
*timeout = when * 1000;
if (vpninfo->dtls_times.rekey_method == REKEY_SSL) {
time(&vpninfo->new_dtls_started);
vpninfo->dtls_state = DTLS_CONNECTING;
- ret = dtls_try_handshake(vpninfo);
+ ret = dtls_try_handshake(vpninfo, timeout);
if (ret) {
vpn_progress(vpninfo, PRG_ERR, _("DTLS Rehandshake failed; reconnecting.\n"));
- return connect_dtls_socket(vpninfo);
+ return connect_dtls_socket(vpninfo, timeout);
}
}
case KA_DPD_DEAD:
vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
/* Fall back to SSL, and start a new DTLS connection */
- dtls_reconnect(vpninfo);
+ dtls_reconnect(vpninfo, timeout);
return 1;
case KA_DPD:
if (ret < 0) {
/* If it's a real error, kill the DTLS connection so
the requeued packet will be sent over SSL */
- dtls_reconnect(vpninfo);
+ dtls_reconnect(vpninfo, timeout);
work_done = 1;
}
return work_done;
return 0;
}
-int dtls_try_handshake(struct openconnect_info *vpninfo)
+int dtls_try_handshake(struct openconnect_info *vpninfo, int *timeout)
{
int err = gnutls_handshake(vpninfo->dtls_ssl);
char *str;
}
if (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED) {
- if (time(NULL) < vpninfo->new_dtls_started + 12)
+ int quit_time = vpninfo->new_dtls_started + 12 - time(NULL);
+ if (quit_time > 0) {
+ if (timeout) {
+ unsigned next_resend = gnutls_dtls_get_timeout(vpninfo->dtls_ssl);
+ if (next_resend && *timeout > next_resend)
+ *timeout = next_resend;
+
+ if (*timeout > quit_time * 1000)
+ *timeout = quit_time * 1000;
+ }
return 0;
+ }
vpn_progress(vpninfo, PRG_DEBUG, _("DTLS handshake timed out\n"));
}
vpninfo->dtls_state = DTLS_SLEEPING;
time(&vpninfo->new_dtls_started);
+ if (timeout && *timeout > vpninfo->dtls_attempt_period * 1000)
+ *timeout = vpninfo->dtls_attempt_period * 1000;
return -EINVAL;
}
/* {gnutls,openssl}-dtls.c */
int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd);
-int dtls_try_handshake(struct openconnect_info *vpninfo);
+int dtls_try_handshake(struct openconnect_info *vpninfo, int *timeout);
unsigned dtls_set_mtu(struct openconnect_info *vpninfo, unsigned mtu);
void dtls_ssl_free(struct openconnect_info *vpninfo);
/* dtls.c */
int dtls_setup(struct openconnect_info *vpninfo);
+int dtls_reconnect(struct openconnect_info *vpninfo, int *timeout);
int udp_tos_update(struct openconnect_info *vpninfo, struct pkt *pkt);
int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable);
void dtls_close(struct openconnect_info *vpninfo);
return 0;
}
-int dtls_try_handshake(struct openconnect_info *vpninfo)
+int dtls_try_handshake(struct openconnect_info *vpninfo, int *timeout)
{
int ret = SSL_do_handshake(vpninfo->dtls_ssl);
ret = SSL_get_error(vpninfo->dtls_ssl, ret);
if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
- static int badossl_bitched = 0;
- if (time(NULL) < vpninfo->new_dtls_started + 12)
+ int quit_time = vpninfo->new_dtls_started + 12 - time(NULL);
+
+ if (quit_time > 0) {
+ if (timeout) {
+ struct timeval tv;
+ if (SSL_ctrl(vpninfo->dtls_ssl, DTLS_CTRL_GET_TIMEOUT, 0, &tv)) {
+ unsigned timeout_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ if (*timeout > timeout_ms)
+ *timeout = timeout_ms;
+ }
+
+ if (*timeout > quit_time * 1000)
+ *timeout = quit_time * 1000;
+ }
return 0;
+ }
+
+ static int badossl_bitched = 0;
if (((OPENSSL_VERSION_NUMBER >= 0x100000b0L && OPENSSL_VERSION_NUMBER <= 0x100000c0L) || \
(OPENSSL_VERSION_NUMBER >= 0x10001040L && OPENSSL_VERSION_NUMBER <= 0x10001060L) || \
OPENSSL_VERSION_NUMBER == 0x10002000L) && !badossl_bitched) {
vpninfo->dtls_state = DTLS_SLEEPING;
time(&vpninfo->new_dtls_started);
+ if (timeout && *timeout > vpninfo->dtls_attempt_period * 1000)
+ *timeout = vpninfo->dtls_attempt_period * 1000;
return -EINVAL;
}