[PATCH 2/2] add --request-ip option to explicitly request a specific IPv4 addresses

Daniel Lenski dlenski at gmail.com
Wed Dec 20 22:56:59 PST 2017


This behavior is supported by AnyConnect (CONNECT with X-CSTP-Address header)
and by GlobalProtect (POST /ssl-vpn/getconfig.esp with preferred-ip form field).

Currently, this option is only a request. OpenConnect will print an error
message, but will not abort, if the server assigns a different IPv4 address.

I did not implement the corresponding behavior for IPv6 because I do not
have a way to test it right now.

Signed-off-by: Daniel Lenski <dlenski at gmail.com>
---
 auth-globalprotect.c |  2 ++
 cstp.c               | 23 +++++++++++++++++------
 gpst.c               | 19 ++++++++++++++-----
 main.c               |  6 ++++++
 openconnect.8.in     |  6 ++++++
 5 files changed, 45 insertions(+), 11 deletions(-)

diff --git a/auth-globalprotect.c b/auth-globalprotect.c
index 1449d8c..dd3cb0d 100644
--- a/auth-globalprotect.c
+++ b/auth-globalprotect.c
@@ -295,6 +295,8 @@ static int gpst_login(struct openconnect_info *vpninfo, int portal)
 		buf_append(request_body, "jnlpReady=jnlpReady&ok=Login&direct=yes&clientVer=4100&prot=https:");
 		append_opt(request_body, "server", vpninfo->hostname);
 		append_opt(request_body, "computer", vpninfo->localname);
+		if (vpninfo->ip_info.addr)
+			append_opt(request_body, "preferred-ip", vpninfo->ip_info.addr);
 		if (form->auth_id && form->auth_id[0]!='_')
 			append_opt(request_body, "inputStr", form->auth_id);
 		append_form_opts(vpninfo, form, request_body);
diff --git a/cstp.c b/cstp.c
index a22c66e..3c35d05 100644
--- a/cstp.c
+++ b/cstp.c
@@ -262,7 +262,9 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
 		buf_append(reqbuf, "X-CSTP-MTU: %d\r\n", mtu);
 	buf_append(reqbuf, "X-CSTP-Address-Type: %s\r\n",
 			       vpninfo->disable_ipv6 ? "IPv4" : "IPv6,IPv4");
-       /* Explicitly request the same IPv4 address on reconnect */
+	/* Explicitly request the same IPv4 address on reconnect (or on
+	 * initial connection if specified with the --request-ip option)
+	 */
 	if (old_addr)
 		buf_append(reqbuf, "X-CSTP-Address: %s\r\n", old_addr);
 	if (!vpninfo->disable_ipv6)
@@ -580,11 +582,20 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
 			     mtu);
 	}
 	if (old_addr) {
-		if (strcmp(old_addr, vpninfo->ip_info.addr)) {
-			vpn_progress(vpninfo, PRG_ERR,
-				     _("Reconnect gave different Legacy IP address (%s != %s)\n"),
-				     vpninfo->ip_info.addr, old_addr);
-			return -EINVAL;
+		/* XXX: if --request-ip option is used, we'll have old_addr!=NULL even on the
+		   first connection attempt, but if old_netmask is also non-NULL then we know
+		   it's a reconnect. */
+		if (vpninfo->ip_info.addr==NULL || strcmp(old_addr, vpninfo->ip_info.addr)) {
+			if (!old_netmask)
+				vpn_progress(vpninfo, PRG_ERR,
+							 _("Legacy IP address %s was requested, but server provided %s\n"),
+							 old_addr, vpninfo->ip_info.addr);
+			else {
+				vpn_progress(vpninfo, PRG_ERR,
+							 _("Reconnect gave different Legacy IP address (%s != %s)\n"),
+							 vpninfo->ip_info.addr, old_addr);
+				return -EINVAL;
+			}
 		}
 	}
 	if (old_netmask) {
diff --git a/gpst.c b/gpst.c
index 9b8b3c6..3665261 100644
--- a/gpst.c
+++ b/gpst.c
@@ -532,12 +532,21 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
 		goto out;
 	}
 	if (old_addr) {
+		/* XXX: if --request-ip option is used, we'll have old_addr!=NULL even on the
+		   first connection attempt, but if old_netmask is also non-NULL then we know
+		   it's a reconnect. */
 		if (strcmp(old_addr, vpninfo->ip_info.addr)) {
-			vpn_progress(vpninfo, PRG_ERR,
-				     _("Reconnect gave different Legacy IP address (%s != %s)\n"),
-				     vpninfo->ip_info.addr, old_addr);
-			result = -EINVAL;
-			goto out;
+			if (!old_netmask)
+				vpn_progress(vpninfo, PRG_ERR,
+							 _("Legacy IP address %s was requested, but server provided %s\n"),
+							 old_addr, vpninfo->ip_info.addr);
+			else {
+				vpn_progress(vpninfo, PRG_ERR,
+							 _("Reconnect gave different Legacy IP address (%s != %s)\n"),
+							 vpninfo->ip_info.addr, old_addr);
+				result = -EINVAL;
+				goto out;
+			}
 		}
 	}
 	if (old_netmask) {
diff --git a/main.c b/main.c
index 815c220..b2fb10a 100644
--- a/main.c
+++ b/main.c
@@ -188,6 +188,7 @@ enum {
 	OPT_LOCAL_HOSTNAME,
 	OPT_PROTOCOL,
 	OPT_PASSTOS,
+	OPT_REQUEST_IP,
 };
 
 #ifdef __sun__
@@ -269,6 +270,7 @@ static const struct option long_options[] = {
 	OPTION("dump-http-traffic", 0, OPT_DUMP_HTTP),
 	OPTION("no-system-trust", 0, OPT_NO_SYSTEM_TRUST),
 	OPTION("protocol", 1, OPT_PROTOCOL),
+	OPTION("request-ip", 1, OPT_REQUEST_IP),
 #ifdef OPENCONNECT_GNUTLS
 	OPTION("gnutls-debug", 1, OPT_GNUTLS_DEBUG),
 #endif
@@ -860,6 +862,7 @@ static void usage(void)
 	printf("      --resolve=HOST:IP           %s\n", _("Use IP when connecting to HOST"));
 	printf("      --os=STRING                 %s\n", _("OS type (linux,linux-64,win,...) to report"));
 	printf("      --dtls-local-port=PORT      %s\n", _("Set local port for DTLS datagrams"));
+	printf("      --request-ip=IP             %s\n", _("Request a specific IPv4 address"));
 	print_supported_protocols_usage();
 
 	printf("\n");
@@ -1270,6 +1273,9 @@ int main(int argc, char **argv)
 		case OPT_AUTHGROUP:
 			authgroup = keep_config_arg();
 			break;
+		case OPT_REQUEST_IP:
+			vpninfo->ip_info.addr = keep_config_arg();
+			break;
 		case 'C':
 			vpninfo->cookie = dup_config_arg();
 			break;
diff --git a/openconnect.8.in b/openconnect.8.in
index 9f46b30..65b26f3 100644
--- a/openconnect.8.in
+++ b/openconnect.8.in
@@ -66,6 +66,7 @@ openconnect \- Multi-protocol VPN client, for Cisco AnyConnect VPNs and others
 .OP \-\-useragent string
 .OP \-\-local-hostname string
 .OP \-\-os string
+.OP \-\-request-ip ip
 .B [https://]\fIserver\fB[:\fIport\fB][/\fIgroup\fB]
 .YS
 
@@ -523,6 +524,11 @@ applied to the VPN session.  If the gateway requires CSD, it will also cause
 the corresponding CSD trojan binary to be downloaded, so you may need to use
 .B \-\-csd\-wrapper
 if this code is not executable on the local machine.
+.TP
+.B \-\-request-ip=IP
+Request a specific IPv4 address from the gateway.  Currently, OpenConnect
+will print a warning but will not abort if the gateway provides a different
+IPv4 address.
 .SH SIGNALS
 In the data phase of the connection, the following signals are handled:
 .TP
-- 
2.7.4




More information about the openconnect-devel mailing list