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 <dlen...@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


_______________________________________________
openconnect-devel mailing list
openconnect-devel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/openconnect-devel

Reply via email to