Commit f5b09229 authored by David Woodhouse's avatar David Woodhouse

Merge branch 'master' of gitlab.com:dlenski/openconnect

parents 6eb0a6e3 37fbeedd
......@@ -173,6 +173,7 @@ static int parse_login_xml(struct openconnect_info *vpninfo, xmlNode *xml_node)
free(value);
value = NULL;
}
append_opt(cookie, "computer", vpninfo->localname);
if (!buf_error(cookie)) {
vpninfo->cookie = cookie->data;
......@@ -294,7 +295,7 @@ gateways:
buf_append(buf, " </ServerList>\n</GPPortal>\n");
if ((result = buf_error(buf)))
goto out;
if ((result = vpninfo->write_new_config(vpninfo, buf->data, buf->pos)))
if ((result = vpninfo->write_new_config(vpninfo->cbdata, buf->data, buf->pos)))
goto out;
}
......@@ -475,8 +476,7 @@ int gpst_bye(struct openconnect_info *vpninfo, const char *reason)
*
* Don't blame me. I didn't design this.
*/
append_opt(request_body, "computer", vpninfo->localname);
buf_append(request_body, "&%s", vpninfo->cookie);
buf_append(request_body, "%s", vpninfo->cookie);
if ((result = buf_error(request_body)))
goto out;
......
......@@ -47,7 +47,6 @@ void oncp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b
{
http_common_headers(vpninfo, buf);
buf_append(buf, "Connection: close\r\n");
// buf_append(buf, "Content-Length: 256\r\n");
buf_append(buf, "NCP-Version: 3\r\n");
// buf_append(buf, "Accept-Encoding: gzip\r\n");
......
......@@ -462,6 +462,8 @@ 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, "Idle-Timeout")) {
vpninfo->idle_timeout = atol(colon);
} else if (!strcmp(buf + 7, "DPD")) {
int j = atol(colon);
if (j && (!vpninfo->ssl_times.dpd || j < vpninfo->ssl_times.dpd))
......@@ -729,7 +731,11 @@ static int cstp_reconnect(struct openconnect_info *vpninfo)
int decompress_and_queue_packet(struct openconnect_info *vpninfo, int compr_type,
unsigned char *buf, int len)
{
struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->ip_info.mtu);
/* Some servers send us packets that are larger than
negotiated MTU after decompression. We reserve some extra
space to handle that */
int receive_mtu = MAX(16384, vpninfo->ip_info.mtu);
struct pkt *new = malloc(sizeof(struct pkt) + receive_mtu);
const char *comprname = "";
if (!new)
......@@ -746,7 +752,7 @@ int decompress_and_queue_packet(struct openconnect_info *vpninfo, int compr_type
vpninfo->inflate_strm.avail_in = len - 4;
vpninfo->inflate_strm.next_out = new->data;
vpninfo->inflate_strm.avail_out = vpninfo->ip_info.mtu;
vpninfo->inflate_strm.avail_out = receive_mtu;
vpninfo->inflate_strm.total_out = 0;
if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
......@@ -768,7 +774,7 @@ int decompress_and_queue_packet(struct openconnect_info *vpninfo, int compr_type
} else if (compr_type == COMPR_LZS) {
comprname = "LZS";
new->len = lzs_decompress(new->data, vpninfo->ip_info.mtu, buf, len);
new->len = lzs_decompress(new->data, receive_mtu, buf, len);
if (new->len < 0) {
len = new->len;
if (len == 0)
......@@ -781,7 +787,7 @@ int decompress_and_queue_packet(struct openconnect_info *vpninfo, int compr_type
#ifdef HAVE_LZ4
} else if (compr_type == COMPR_LZ4) {
comprname = "LZ4";
new->len = LZ4_decompress_safe((void *)buf, (void *)new->data, len, vpninfo->ip_info.mtu);
new->len = LZ4_decompress_safe((void *)buf, (void *)new->data, len, receive_mtu);
if (new->len <= 0) {
len = new->len;
if (len == 0)
......@@ -882,18 +888,21 @@ int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
and add POLLOUT. As it is, though, it'll just chew CPU time in that
fairly unlikely situation, until the write backlog clears. */
while (1) {
int len = MAX(16384, vpninfo->deflate_pkt_size ? : vpninfo->ip_info.mtu);
int payload_len;
/* Some servers send us packets that are larger than
negotiated MTU. We reserve some extra space to
handle that */
int receive_mtu = MAX(16384, vpninfo->deflate_pkt_size ? : vpninfo->ip_info.mtu);
int len, payload_len;
if (!vpninfo->cstp_pkt) {
vpninfo->cstp_pkt = malloc(sizeof(struct pkt) + len);
vpninfo->cstp_pkt = malloc(sizeof(struct pkt) + receive_mtu);
if (!vpninfo->cstp_pkt) {
vpn_progress(vpninfo, PRG_ERR, _("Allocation failed\n"));
break;
}
}
len = ssl_nonblock_read(vpninfo, vpninfo->cstp_pkt->cstp.hdr, len + 8);
len = ssl_nonblock_read(vpninfo, vpninfo->cstp_pkt->cstp.hdr, receive_mtu + 8);
if (!len)
break;
if (len < 0)
......
......@@ -106,10 +106,14 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
struct esp *esp = &vpninfo->esp_in[vpninfo->current_esp_in];
struct esp *old_esp = &vpninfo->esp_in[vpninfo->current_esp_in ^ 1];
struct pkt *this;
int receive_mtu = MAX(2048, vpninfo->ip_info.mtu + 256);
int work_done = 0;
int ret;
/* Some servers send us packets that are larger than negotiated
MTU, or lack the ability to negotiate MTU (see gpst.c). We
reserve some extra space to handle that */
int receive_mtu = MAX(2048, vpninfo->ip_info.mtu + 256);
if (vpninfo->dtls_state == DTLS_SLEEPING) {
if (ka_check_deadline(timeout, time(NULL), vpninfo->new_dtls_started + vpninfo->dtls_attempt_period)
|| vpninfo->dtls_need_reconnect) {
......@@ -142,6 +146,7 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
len);
work_done = 1;
/* both supported algos (SHA1 and MD5) have 12-byte MAC lengths (RFC2403 and RFC2404) */
if (len <= sizeof(pkt->esp) + 12)
continue;
......@@ -165,6 +170,11 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout)
continue;
}
/* Possible values of the Next Header field are:
0x04: IP[v4]-in-IP
0x05: supposed to mean Internet Stream Protocol
(XXX: but used for LZO compressed packets by Juniper)
0x29: IPv6 encapsulation */
if (pkt->data[len - 1] != 0x04 && pkt->data[len - 1] != 0x29 &&
pkt->data[len - 1] != 0x05) {
vpn_progress(vpninfo, PRG_ERR,
......
......@@ -481,6 +481,11 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
else if (!xmlnode_get_text(xml_node, "mtu", &s)) {
vpninfo->ip_info.mtu = atoi(s);
free(s);
} else if (!xmlnode_get_text(xml_node, "disconnect-on-idle", &s)) {
int sec = atoi(s);
vpn_progress(vpninfo, PRG_INFO, _("Idle timeout is %d minutes.\n"), sec/60);
vpninfo->idle_timeout = sec;
free(s);
} else if (!xmlnode_get_text(xml_node, "ssl-tunnel-url", &s)) {
free(vpninfo->urlpath);
vpninfo->urlpath = s;
......@@ -630,7 +635,7 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
vpninfo->ip_info.mtu = calculate_mtu(vpninfo, !no_esp_reason);
vpn_progress(vpninfo, PRG_ERR,
_("No MTU received. Calculated %d for %s%s\n"), vpninfo->ip_info.mtu,
no_esp_reason ? "TLS tunnel. " : "ESP tunnel", no_esp_reason ? : "");
no_esp_reason ? "SSL tunnel. " : "ESP tunnel", no_esp_reason ? : "");
/* return -EINVAL; */
}
if (!vpninfo->ip_info.addr) {
......@@ -789,9 +794,8 @@ static int build_csd_token(struct openconnect_info *vpninfo)
if (!vpninfo->csd_token)
return -ENOMEM;
/* use localname and cookie (excluding volatile authcookie and preferred-ip) to build md5sum */
/* use cookie (excluding volatile authcookie and preferred-ip) to build md5sum */
buf = buf_alloc();
append_opt(buf, "computer", vpninfo->localname);
filter_opts(buf, vpninfo->cookie, "authcookie,preferred-ip", 0);
if (buf_error(buf))
goto out;
......@@ -815,9 +819,8 @@ static int check_or_submit_hip_report(struct openconnect_info *vpninfo, const ch
const char *method = "POST";
char *xml_buf=NULL, *orig_path;
/* cookie gives us these fields: authcookie, portal, user, domain, and (maybe the unnecessary) preferred-ip */
/* cookie gives us these fields: authcookie, portal, user, domain, computer, and (maybe the unnecessary) preferred-ip */
buf_append(request_body, "client-role=global-protect-full&%s", vpninfo->cookie);
append_opt(request_body, "computer", vpninfo->localname);
append_opt(request_body, "client-ip", vpninfo->ip_info.addr);
if (report) {
/* XML report contains many characters requiring URL-encoding (%xx) */
......@@ -887,9 +890,15 @@ static int run_hip_script(struct openconnect_info *vpninfo)
buf_append_bytes(report_buf, b, i);
waitpid(child, &status, 0);
if (status != 0) {
if (!WIFEXITED(status)) {
vpn_progress(vpninfo, PRG_ERR,
_("HIP script '%s' exited abnormally\n"),
vpninfo->csd_wrapper);
ret = -EINVAL;
} else if (WEXITSTATUS(status) != 0) {
vpn_progress(vpninfo, PRG_ERR,
_("HIP script returned non-zero status: %d\n"), status);
_("HIP script '%s' returned non-zero status: %d\n"),
vpninfo->csd_wrapper, WEXITSTATUS(status));
ret = -EINVAL;
} else {
ret = check_or_submit_hip_report(vpninfo, report_buf->data);
......@@ -912,8 +921,6 @@ static int run_hip_script(struct openconnect_info *vpninfo)
hip_argv[i++] = openconnect_utf8_to_legacy(vpninfo, vpninfo->csd_wrapper);
hip_argv[i++] = (char *)"--cookie";
hip_argv[i++] = vpninfo->cookie;
hip_argv[i++] = (char *)"--computer";
hip_argv[i++] = vpninfo->localname;
hip_argv[i++] = (char *)"--client-ip";
hip_argv[i++] = (char *)vpninfo->ip_info.addr;
hip_argv[i++] = (char *)"--md5";
......@@ -1014,7 +1021,10 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout)
goto do_reconnect;
while (1) {
int receive_mtu = MAX(2048, vpninfo->ip_info.mtu + 256);
/* Some servers send us packets that are larger than
negotiated MTU. We reserve some extra space to
handle that */
int receive_mtu = MAX(16384, vpninfo->ip_info.mtu);
int len, payload_len;
if (!vpninfo->cstp_pkt) {
......
......@@ -6,10 +6,7 @@
#
# --cookie: a URL-encoded string, as output by openconnect
# --authenticate --protocol=gp, which includes parameters
# --from the /ssl-vpn/login.esp response
#
# --computer: local hostname, which can be overriden with
# --openconnect local-hostname=HOSTNAME
# from the /ssl-vpn/login.esp response
#
# --client-ip: IPv4 address allocated by the GlobalProtect VPN for
# this client (included in /ssl-vpn/getconfig.esp
......@@ -22,26 +19,25 @@
# Read command line arguments into variables
COOKIE=
COMPUTER=
IP=
MD5=
while [ "$1" ]; do
if [ "$1" = "--cookie" ]; then shift; COOKIE="$1"; fi
if [ "$1" = "--computer" ]; then shift; COMPUTER="$1"; fi
if [ "$1" = "--client-ip" ]; then shift; IP="$1"; fi
if [ "$1" = "--md5" ]; then shift; MD5="$1"; fi
shift
done
if [ -z "$COOKIE" -o -z "$COMPUTER" -o -z "$IP" -o -z "$MD5" ]; then
if [ -z "$COOKIE" -o -z "$IP" -o -z "$MD5" ]; then
echo "Parameters --cookie, --computer, --client-ip, and --md5 are required" >&2
exit 1;
fi
# Extract username and domain from cookie
# Extract username and domain and computer from cookie
USER=$(echo "$COOKIE" | sed -rn 's/(.+&|^)user=([^&]+)(&.+|$)/\2/p')
DOMAIN=$(echo "$COOKIE" | sed -rn 's/(.+&|^)domain=([^&]+)(&.+|$)/\2/p')
COMPUTER=$(echo "$COOKIE" | sed -rn 's/(.+&|^)computer=([^&]+)(&.+|$)/\2/p')
# Timestamp in the format expected by GlobalProtect server
NOW=$(date +'%m/%d/%Y %H:%M:%S')
......
......@@ -11,7 +11,7 @@ From the top level, run:
make
cd java
ant
sudo java -Djava.library.path=../.libs -jar dist/example.jar <server_ip>
sudo java -Djava.library.path=../.libs -jar dist/example.jar <server_name> [protocol]
If ocproxy[1] is installed somewhere in your $PATH, this can be run as a
non-root user and it should be pingable from across the VPN.
......
......@@ -204,12 +204,30 @@ public final class LibTest {
System.out.println("");
}
private static void describeProtocol(LibOpenConnect.VPNProto vp) {
ArrayList<String> flags = new ArrayList<String>();
if ((vp.flags & LibOpenConnect.OC_PROTO_PROXY) != 0) flags.add("proxy");
if ((vp.flags & LibOpenConnect.OC_PROTO_CSD) != 0) flags.add("CSD");
if ((vp.flags & LibOpenConnect.OC_PROTO_AUTH_CERT) != 0) flags.add("auth-cert");
if ((vp.flags & LibOpenConnect.OC_PROTO_AUTH_OTP) != 0) flags.add("auth-otp");
if ((vp.flags & LibOpenConnect.OC_PROTO_AUTH_OTP) != 0) flags.add("auth-stoken");
System.out.println(" " + vp.name +
") PRETTY_NAME=" + vp.prettyName +
", DESCRIPTION=" + vp.description +
", FLAGS=" + String.join("+", flags));
}
public static void main(String argv[]) {
System.loadLibrary("openconnect-wrapper");
LibOpenConnect lib = new TestLib();
String server_name, protocol;
if (argv.length != 1)
die("usage: LibTest <server_name>");
if (argv.length != 1 && argv.length != 2)
die("usage: LibTest <server_name> [protocol]");
server_name = argv[0];
protocol = argv.length == 2 ? argv[1] : null;
System.out.println("OpenConnect version: " + lib.getVersion());
System.out.println(" PKCS=" + lib.hasPKCS11Support() +
......@@ -217,13 +235,29 @@ public final class LibTest {
", STOKEN=" + lib.hasStokenSupport() +
", OATH=" + lib.hasOATHSupport() +
", YUBIOATH=" + lib.hasYubiOATHSupport());
System.out.println("Supported protocols:");
for (LibOpenConnect.VPNProto vp : lib.getSupportedProtocols())
describeProtocol(vp);
if (protocol == null) {
System.out.println("Using default VPN protocol of " + lib.getProtocol());
} else {
System.out.println("Setting VPN protocol to " + protocol);
if (lib.setProtocol(protocol) != 0)
die("Error setting VPN protocol");
}
lib.setReportedOS("win");
lib.setLogLevel(lib.PRG_DEBUG);
//lib.setTokenMode(LibOpenConnect.OC_TOKEN_MODE_STOKEN, null);
if (new File("csd.sh").exists()) {
lib.setCSDWrapper("csd.sh", null, null);
String csd_wrapper = "./csd-" + lib.getProtocol() + ".sh";
if (new File(csd_wrapper).exists()) {
System.out.println("Using CSD wrapper script " + csd_wrapper);
lib.setCSDWrapper(csd_wrapper, null, null);
} else {
System.out.println("Skipping CSD wrapper (script " + csd_wrapper + " doesn't exist)");
}
lib.parseURL(argv[0]);
lib.parseURL(server_name);
lib.setSystemTrust(true);
int ret = lib.obtainCookie();
if (ret < 0)
......@@ -241,6 +275,8 @@ public final class LibTest {
if (lib.makeCSTPConnection() != 0)
die("Error establishing VPN link");
int idleTimeout = lib.getIdleTimeout();
System.out.println("Idle Timeout: " + idleTimeout + " seconds");
printIPInfo(lib.getIPInfo());
if (lib.setupDTLS(60) != 0)
......
......@@ -22,6 +22,12 @@ public abstract class LibOpenConnect {
/* constants */
public static final int OC_PROTO_PROXY = 1;
public static final int OC_PROTO_CSD = 2;
public static final int OC_PROTO_AUTH_CERT = 4;
public static final int OC_PROTO_AUTH_OTP = 8;
public static final int OC_PROTO_AUTH_STOKEN = 16;
public static final int OC_FORM_OPT_TEXT = 1;
public static final int OC_FORM_OPT_PASSWORD = 2;
public static final int OC_FORM_OPT_SELECT = 3;
......@@ -135,6 +141,7 @@ public abstract class LibOpenConnect {
public synchronized native void setReqMTU(int mtu);
public synchronized native void setPFS(boolean isEnabled);
public synchronized native void setSystemTrust(boolean isEnabled);
public synchronized native int setProtocol(String protocol);
/* connection info */
......@@ -149,6 +156,8 @@ public abstract class LibOpenConnect {
public synchronized native String getDTLSCipher();
public synchronized native String getCSTPCompression();
public synchronized native String getDTLSCompression();
public synchronized native String getProtocol();
public synchronized native int getIdleTimeout();
/* certificate info */
......@@ -166,6 +175,7 @@ public abstract class LibOpenConnect {
public static native boolean hasStokenSupport();
public static native boolean hasOATHSupport();
public static native boolean hasYubiOATHSupport();
public static native VPNProto[] getSupportedProtocols();
/* public data structures */
......@@ -238,6 +248,7 @@ public abstract class LibOpenConnect {
public String proxyPac;
public String gatewayAddr;
public int MTU;
public int idleTimeoutSec;
public ArrayList<String> splitDNS = new ArrayList<String>();
public ArrayList<String> splitIncludes = new ArrayList<String>();
......@@ -265,6 +276,13 @@ public abstract class LibOpenConnect {
public Object userData;
};
public static class VPNProto {
public String name;
public String prettyName;
public String description;
public int flags;
};
/* Optional storage for caller's data */
public Object userData;
......
......@@ -879,8 +879,8 @@ JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setCSDWr
!get_cstring(ctx->jenv, jarg2, &arg2)) {
openconnect_setup_csd(ctx->vpninfo, getuid(), 1, arg0);
openconnect_set_csd_environ(ctx->vpninfo, "TMPDIR", arg1);
openconnect_set_csd_environ(ctx->vpninfo, "PATH", arg2);
if (arg1) openconnect_set_csd_environ(ctx->vpninfo, "TMPDIR", arg1);
if (arg2) openconnect_set_csd_environ(ctx->vpninfo, "PATH", arg2);
}
release_cstring(ctx->jenv, jarg0, arg0);
......@@ -1108,6 +1108,16 @@ JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setXMLPo
openconnect_set_xmlpost(ctx->vpninfo, arg);
}
JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getIdleTimeout(
JNIEnv *jenv, jobject jobj)
{
struct libctx *ctx = getctx(jenv, jobj);
if (!ctx)
return -EINVAL;
return openconnect_get_idle_timeout(ctx->vpninfo);
}
/* simple cases: return a const string (no need to free it) */
#define RETURN_STRING_START \
......@@ -1197,6 +1207,14 @@ JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getCS
RETURN_STRING_END
}
JNIEXPORT jstring JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getProtocol(
JNIEnv *jenv, jobject jobj)
{
RETURN_STRING_START
buf = openconnect_get_protocol(ctx->vpninfo);
RETURN_STRING_END
}
#define SET_STRING_START(ret) \
struct libctx *ctx = getctx(jenv, jobj); \
const char *arg = NULL; \
......@@ -1247,6 +1265,16 @@ JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setHTTPP
return ret;
}
JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setProtocol(
JNIEnv *jenv, jobject jobj, jstring jarg)
{
int ret;
SET_STRING_START(-ENOMEM)
ret = openconnect_set_protocol(ctx->vpninfo, arg);
SET_STRING_END();
return ret;
}
JNIEXPORT void JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setXMLSHA1(
JNIEnv *jenv, jobject jobj, jstring jarg)
{
......@@ -1381,3 +1409,53 @@ JNIEXPORT jobject JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getIP
return jobj;
}
JNIEXPORT jobjectArray JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_getSupportedProtocols(
JNIEnv *jenv, jclass jcls)
{
jmethodID mid;
jobjectArray result;
struct libctx ctx = { .jenv = jenv, .jobj = NULL, .async_lock = NULL, .vpninfo = NULL, .cmd_fd = -1, .loglevel = -1 };
/* call C library */
struct oc_vpn_proto *protos;
int np, ii;
np = openconnect_get_supported_protocols(&protos);
if (np < 0)
return NULL;
/* get VPNProto class, its init method, and create array */
jcls = (*jenv)->FindClass(jenv,
"org/infradead/libopenconnect/LibOpenConnect$VPNProto");
if (jcls == NULL)
goto err;
mid = (*jenv)->GetMethodID(jenv, jcls, "<init>", "()V");
if (!mid)
goto err;
result = (*jenv)->NewObjectArray(jenv, np, jcls, NULL);
if (result == NULL)
goto nomem;
for (ii=0; ii<np; ii++) {
jobject jobj = (*jenv)->NewObject(jenv, jcls, mid);
if (!jobj)
goto nomem;
if (set_string(&ctx, jobj, "name", protos[ii].name) ||
set_string(&ctx, jobj, "prettyName", protos[ii].pretty_name) ||
set_string(&ctx, jobj, "description", protos[ii].description) ||
set_int (&ctx, jobj, "flags", protos[ii].flags))
goto nomem;
(*jenv)->SetObjectArrayElement(jenv, result, ii, jobj);
}
openconnect_free_supported_protocols(protos);
return result;
nomem:
OOM(jenv);
err:
openconnect_free_supported_protocols(protos);
return NULL;
}
......@@ -94,6 +94,8 @@ OPENCONNECT_5_4 {
OPENCONNECT_5_5 {
global:
openconnect_get_idle_timeout;
openconnect_get_protocol;
openconnect_get_supported_protocols;
openconnect_free_supported_protocols;
} OPENCONNECT_5_4;
......
......@@ -117,6 +117,7 @@ const struct vpn_proto openconnect_protos[] = {
.tcp_mainloop = cstp_mainloop,
.add_http_headers = cstp_common_headers,
.obtain_cookie = cstp_obtain_cookie,
.udp_protocol = "DTLS",
#ifdef HAVE_DTLS
.udp_setup = dtls_setup,
.udp_mainloop = dtls_mainloop,
......@@ -133,6 +134,7 @@ const struct vpn_proto openconnect_protos[] = {
.tcp_mainloop = oncp_mainloop,
.add_http_headers = oncp_common_headers,
.obtain_cookie = oncp_obtain_cookie,
.udp_protocol = "ESP",
#ifdef HAVE_ESP
.udp_setup = esp_setup,
.udp_mainloop = esp_mainloop,
......@@ -145,12 +147,13 @@ const struct vpn_proto openconnect_protos[] = {
.name = "gp",
.pretty_name = N_("Palo Alto Networks GlobalProtect"),
.description = N_("Compatible with Palo Alto Networks (PAN) GlobalProtect SSL VPN"),
.flags = OC_PROTO_PROXY | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN,
.flags = OC_PROTO_PROXY | OC_PROTO_CSD | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN,
.vpn_close_session = gpst_bye,
.tcp_connect = gpst_setup,
.tcp_mainloop = gpst_mainloop,
.add_http_headers = gpst_common_headers,
.obtain_cookie = gpst_obtain_cookie,
.udp_protocol = "ESP",
#ifdef HAVE_ESP
.udp_setup = esp_setup,
.udp_mainloop = esp_mainloop,
......@@ -186,6 +189,11 @@ void openconnect_free_supported_protocols(struct oc_vpn_proto *protos)
free((void *)protos);
}
const char *openconnect_get_protocol(struct openconnect_info *vpninfo)
{
return vpninfo->proto->name;
}
int openconnect_set_protocol(struct openconnect_info *vpninfo, const char *protocol)
{
const struct vpn_proto *p;
......@@ -530,6 +538,11 @@ void openconnect_set_dpd(struct openconnect_info *vpninfo, int min_seconds)
vpninfo->dtls_times.dpd = vpninfo->ssl_times.dpd = 2;
}
int openconnect_get_idle_timeout(struct openconnect_info *vpninfo)
{
return vpninfo->idle_timeout;
}
int openconnect_get_ip_info(struct openconnect_info *vpninfo,
const struct oc_ip_info **info,
const struct oc_vpn_option **cstp_options,
......@@ -904,7 +917,8 @@ int openconnect_setup_tun_device(struct openconnect_info *vpninfo,
static const char *compr_name_map[] = {
[COMPR_DEFLATE] = "Deflate",
[COMPR_LZS] = "LZS",
[COMPR_LZ4] = "LZ4"
[COMPR_LZ4] = "LZ4",
[COMPR_LZO] = "LZO",
};
const char *openconnect_get_cstp_compression(struct openconnect_info * vpninfo)
......
......@@ -863,8 +863,8 @@ static void usage(void)
printf(" -x, --xmlconfig=CONFIG %s\n", _("XML config file"));
printf(" -m, --mtu=MTU %s\n", _("Request MTU from server (legacy servers only)"));
printf(" --base-mtu=MTU %s\n", _("Indicate path MTU to/from server"));
printf(" -d, --deflate %s\n", _("Enable compression (default)"));
printf(" -D, --no-deflate %s\n", _("Disable compression"));
printf(" -d, --deflate %s\n", _("Enable stateful compression (default is stateless only)"));
printf(" -D, --no-deflate %s\n", _("Disable all compression"));
printf(" --force-dpd=INTERVAL %s\n", _("Set minimum Dead Peer Detection interval"));
printf(" --pfs %s\n", _("Require perfect forward secrecy"));
printf(" --no-dtls %s\n", _("Disable DTLS and ESP"));
......@@ -1083,7 +1083,7 @@ int main(int argc, char **argv)
char *urlpath = NULL;
struct oc_vpn_option *gai;
char *ip;
const char *compr = "";
const char *ssl_compr, *udp_compr;
char *proxy = getenv("https_proxy");
char *vpnc_script = NULL;
const struct oc_ip_info *ip_info;
......@@ -1596,33 +1596,21 @@ int main(int argc, char **argv)
* reconnects end up in infinite loop trying to connect
* to non existing DTLS */
vpninfo->dtls_state = DTLS_DISABLED;
fprintf(stderr, _("Set up DTLS failed; using SSL instead\n"));
fprintf(stderr, _("Set up UDP failed; using SSL instead\n"));
}
openconnect_get_ip_info(vpninfo, &ip_info, NULL, NULL);
if (vpninfo->dtls_state != DTLS_CONNECTED) {
if (vpninfo->cstp_compr == COMPR_DEFLATE)
compr = " + deflate";
else if (vpninfo->cstp_compr == COMPR_LZS)
compr = " + lzs";
else if (vpninfo->cstp_compr == COMPR_LZ4)
compr = " + lz4";
} else {
if (vpninfo->dtls_compr == COMPR_DEFLATE)
compr = " + deflate";
else if (vpninfo->dtls_compr == COMPR_LZS)
compr = " + lzs";
else if (vpninfo->dtls_compr == COMPR_LZ4)
compr = " + lz4";
}
ssl_compr = openconnect_get_cstp_compression(vpninfo);
udp_compr = openconnect_get_dtls_compression(vpninfo);
vpn_progress(vpninfo, PRG_INFO,
_("Connected as %s%s%s, using %s%s\n"),
_("Connected as %s%s%s, using SSL%s%s, with %s%s%s %s\n"),
ip_info->addr?:"",
(ip_info->netmask6 && ip_info->addr) ? " + " : "",
ip_info->netmask6 ? : "",
(vpninfo->dtls_state != DTLS_CONNECTED) ? "SSL"
: "DTLS", compr);
ssl_compr ? " + " : "", ssl_compr ? : "",
vpninfo->proto->udp_protocol ? : "UDP", udp_compr ? " + " : "", udp_compr ? : "",
(vpninfo->dtls_state == DTLS_DISABLED || vpninfo->dtls_state == DTLS_NOSECRET ? _("disabled") : _("in progress")));
if (!vpninfo->vpnc_script) {
vpn_progress(vpninfo, PRG_INFO,
......
......@@ -323,6 +323,7 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
if (attrlen != 1)
goto badlen;
vpninfo->esp_compr = data[0];
vpninfo->dtls_compr = data[0] ? COMPR_LZO : 0;
vpn_progress(vpninfo, PRG_DEBUG, _("ESP compression: %d\n"), data[0]);
break;
......@@ -559,52 +560,14 @@ int oncp_connect(struct openconnect_info *vpninfo)
reqbuf = buf_alloc();
buf_append(reqbuf, "POST /dana/js?prot=1&svc=1 HTTP/1.1\r\n");
oncp_common_headers(vpninfo, reqbuf);
buf_append(reqbuf, "Content-Length: 256\r\n");
buf_append(reqbuf, "\r\n");
if (buf_error(reqbuf)) {
vpn_progress(vpninfo, PRG_ERR,
_("Error creating oNCP negotiation request\n"));
ret = buf_error(reqbuf);
goto out;
}
ret = vpninfo->ssl_write(vpninfo, reqbuf->data, reqbuf->pos);
if (ret < 0)
goto out;
/* The server is fairly weird. It sends Connection: close which would
* indicate an HTTP 1.0-style body, but doesn't seem to actually close
* the connection. So tell process_http_response() it was a CONNECT
* request, since we don't care about the body anyway, and then close
* the connection for ourselves. */
ret = process_http_response(vpninfo, 1, NULL, reqbuf);
openconnect_close_https(vpninfo, 0);
if (ret < 0) {
/* We'll already have complained about whatever offended us */
goto out;
}
if (ret != 200) {
vpn_progress(vpninfo, PRG_ERR,
_("Unexpected %d result from server\n"),
ret);
ret = -EINVAL;
goto out;
}
/* Now the second request. We should reduce the duplication
here but let's not overthink it for now; we should see what
the authentication requests are going to look like, and make
do_https_request() or a new helper function work for those
too. */
ret = openconnect_open_https(vpninfo);
if (ret)
goto out;
buf_truncate(reqbuf);
buf_append(reqbuf, "POST /dana/js?prot=1&svc=4 HTTP/1.1\r\n");
/* The TLS socket actually remains open for use by the oNCP
tunnel, but the "Connection: close" header is nevertheless
required here. It appears to signal to the server to stop
treating this as an HTTP connection and to start treating
it as an oNCP connection.
*/
buf_append(reqbuf, "Connection: close\r\n");
oncp_common_headers(vpninfo, reqbuf);
buf_append(reqbuf, "Content-Length: 256\r\n");
buf_append(reqbuf, "\r\n");
......
......@@ -174,10 +174,11 @@ struct pkt {
#define COMPR_DEFLATE (1<<0)
#define COMPR_LZS (1<<1)
#define COMPR_LZ4 (1<<2)
#define COMPR_MAX COMPR_LZ4
#define COMPR_LZO (1<<3)
#define COMPR_MAX COMPR_LZO