diff --git a/cstp.c b/cstp.c index 4225760b..5f806cf7 100644 --- a/cstp.c +++ b/cstp.c @@ -529,6 +529,18 @@ static int start_cstp_connection(struct openconnect_info *vpninfo) if (!strcmp(buf + 7, "Keepalive")) { vpninfo->ssl_times.keepalive = atol(colon); + } else if (!strcmp(buf + 7, "Lease-Duration") || + !strcmp(buf + 7, "Session-Timeout") || + !strcmp(buf + 7, "Session-Timeout-Remaining")) { + + /* XX: Distinction between Lease-Duration and Session-Timeout is rather unclear. Cisco doc: + * https://www.cisco.com/assets/sol/sb/RV345P_Emulators/RV345P_Emulator_v1-0-01-17/help/help/t_SSL_VPN.html + * Empirically, it appears that the best behavior is to accept whichever of these headers has the + * lowest non-zero value. + */ + long j = atol(colon); + if (j && (!vpninfo->auth_expiration || j < vpninfo->auth_expiration)) + vpninfo->auth_expiration = time(NULL) + j; } else if (!strcmp(buf + 7, "Idle-Timeout")) { vpninfo->idle_timeout = atol(colon); } else if (!strcmp(buf + 7, "DPD")) { diff --git a/gpst.c b/gpst.c index 761a9142..f8143a68 100644 --- a/gpst.c +++ b/gpst.c @@ -491,7 +491,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_ } else if (!xmlnode_get_val(xml_node, "mtu", &s)) vpninfo->ip_info.mtu = atoi(s); else if (!xmlnode_get_val(xml_node, "lifetime", &s)) - vpn_progress(vpninfo, PRG_INFO, _("Session will expire after %d minutes.\n"), atoi(s)/60); + vpninfo->auth_expiration = time(NULL) + atol(s); else if (!xmlnode_get_val(xml_node, "disconnect-on-idle", &s)) { int sec = atoi(s); vpn_progress(vpninfo, PRG_INFO, _("Idle timeout is %d minutes.\n"), sec/60); diff --git a/java/src/com/example/LibTest.java b/java/src/com/example/LibTest.java index 280ea1d2..d2097ca2 100644 --- a/java/src/com/example/LibTest.java +++ b/java/src/com/example/LibTest.java @@ -17,6 +17,7 @@ import java.io.*; import java.util.*; +import java.time.Instant; import org.infradead.libopenconnect.LibOpenConnect; public final class LibTest { @@ -279,6 +280,8 @@ else if (ret > 0) int idleTimeout = lib.getIdleTimeout(); System.out.println("Idle Timeout: " + idleTimeout + " seconds"); + Instant authExpiration = lib.getAuthExpiration(); + System.out.println("Auth Expiration: " + authExpiration.toString()); printIPInfo(lib.getIPInfo()); if (lib.setupDTLS(60) != 0) diff --git a/java/src/org/infradead/libopenconnect/LibOpenConnect.java b/java/src/org/infradead/libopenconnect/LibOpenConnect.java index 2f60e107..e9606ba0 100644 --- a/java/src/org/infradead/libopenconnect/LibOpenConnect.java +++ b/java/src/org/infradead/libopenconnect/LibOpenConnect.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.time.Instant; public abstract class LibOpenConnect { @@ -166,6 +167,7 @@ public synchronized native void setMobileInfo(String mobilePlatformVersion, public synchronized native String getDTLSCompression(); public synchronized native String getProtocol(); public synchronized native int getIdleTimeout(); + public synchronized native Instant getAuthExpiration(); /* certificate info */ diff --git a/jni.c b/jni.c index 8f5b982a..9ef7959e 100644 --- a/jni.c +++ b/jni.c @@ -1164,6 +1164,36 @@ JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getIdleT return openconnect_get_idle_timeout(ctx->vpninfo); } +JNIEXPORT jobject JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getAuthExpiration( + JNIEnv *jenv, jobject jobj) +{ + struct libctx *ctx = getctx(jenv, jobj); + jmethodID mid; + jobject result; + jclass jcls; + time_t auth_expiration; + + if (!ctx) + return NULL; + + auth_expiration = openconnect_get_auth_expiration(ctx->vpninfo); + jcls = (*ctx->jenv)->FindClass(ctx->jenv, "java/time/Instant"); + if (jcls == NULL) + goto err; + mid = (*jenv)->GetStaticMethodID(jenv, jcls, "ofEpochSecond", "(J)Ljava/time/Instant;"); + if (!mid) + goto err; + result = (*jenv)->CallStaticObjectMethod(jenv, jcls, mid, auth_expiration); + if (result == NULL) + goto err; + + return result; + +err: + return NULL; +} + + /* simple cases: return a const string (no need to free it) */ #define RETURN_STRING_START \ diff --git a/libopenconnect.map.in b/libopenconnect.map.in index a45b25fd..9c5171fb 100644 --- a/libopenconnect.map.in +++ b/libopenconnect.map.in @@ -112,6 +112,7 @@ OPENCONNECT_5_7 { global: openconnect_set_cookie; openconnect_set_allow_insecure_crypto; + openconnect_get_auth_expiration; } OPENCONNECT_5_6; OPENCONNECT_PRIVATE { diff --git a/library.c b/library.c index 4146e8f1..3a8d6cd6 100644 --- a/library.c +++ b/library.c @@ -611,6 +611,11 @@ int openconnect_get_idle_timeout(struct openconnect_info *vpninfo) return vpninfo->idle_timeout; } +time_t openconnect_get_auth_expiration(struct openconnect_info *vpninfo) +{ + return vpninfo->auth_expiration; +} + int openconnect_get_ip_info(struct openconnect_info *vpninfo, const struct oc_ip_info **info, const struct oc_vpn_option **cstp_options, diff --git a/main.c b/main.c index 7978af22..58a7fc0f 100644 --- a/main.c +++ b/main.c @@ -1420,6 +1420,9 @@ static void print_connection_info(struct openconnect_info *vpninfo) ssl_compr ? " + " : "", ssl_compr ? : "", vpninfo->proto->udp_protocol ? : "UDP", udp_compr ? " + " : "", udp_compr ? : "", dtls_state); + if (vpninfo->auth_expiration != 0) + vpn_progress(vpninfo, PRG_INFO, _("Session authentication will expire at %s"), + ctime(&vpninfo->auth_expiration)); } #ifndef _WIN32 diff --git a/openconnect-internal.h b/openconnect-internal.h index 0db75b27..af11c366 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -567,6 +567,7 @@ struct openconnect_info { int reconnect_timeout; int reconnect_interval; int dtls_attempt_period; + time_t auth_expiration; time_t new_dtls_started; #if defined(OPENCONNECT_OPENSSL) SSL_CTX *dtls_ctx; diff --git a/openconnect.h b/openconnect.h index b89f2a69..8fba0ddf 100644 --- a/openconnect.h +++ b/openconnect.h @@ -39,6 +39,7 @@ extern "C" { * API version 5.7: * - Add openconnect_set_cookie() * - Add openconnect_set_allow_insecure_crypto() + * - Add openconnect_get_auth_expiration() * * API version 5.6 (v8.06; 2020-03-31): * - Add openconnect_set_trojan_interval() @@ -532,6 +533,7 @@ void openconnect_set_reqmtu(struct openconnect_info *, int reqmtu); void openconnect_set_dpd(struct openconnect_info *, int min_seconds); void openconnect_set_trojan_interval(struct openconnect_info *, int seconds); int openconnect_get_idle_timeout(struct openconnect_info *); +time_t openconnect_get_auth_expiration(struct openconnect_info *); /* The returned structures are owned by the library and may be freed/replaced due to rekey or reconnect. Assume that once the mainloop starts, the