]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Rework cstp_options and ip_info handling
authorDavid Woodhouse <dwmw2@infradead.org>
Thu, 22 Apr 2021 15:46:17 +0000 (16:46 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Fri, 23 Apr 2021 15:47:34 +0000 (16:47 +0100)
Build up the new opt list and ip_info first, then have a function to
"install" them into the vpninfo, doing the sanity check at that point.
Should make the whole thing a little bit less vile.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
12 files changed:
.gitlab-ci.yml
cstp.c
f5.c
fortinet.c
gpst.c
library.c
oncp.c
openconnect-internal.h
openconnect.h
ppp.c
pulse.c
script.c

index f3f981ddf9b4bf088815349959ba1cc5e75aa4fd..22d8ab24eb2cac9cfd2920a0d4af9a701667169a 100644 (file)
@@ -507,8 +507,7 @@ static-analyzer/GnuTLS/Fedora:
     expire_in: 1 week
     when: always
     paths:
-      - tests/*.log
-      - openconnect-installer.exe
+      - scan-build-src/*
 
 static-analyzer/OpenSSL/Fedora:
   image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:buildenv-fedora
diff --git a/cstp.c b/cstp.c
index 17d0f91444bf2d4e617991762f00f8f8dae36fd3..7e7916a651a950b82c585d712eb6a8ba14f9dd7f 100644 (file)
--- a/cstp.c
+++ b/cstp.c
@@ -208,44 +208,6 @@ static int parse_hex_val(const char *str, unsigned char *storage, unsigned int m
        return len/2;
 }
 
-int check_address_sanity(struct openconnect_info *vpninfo, const char *old_addr, const char *old_netmask, const char *old_addr6, const char *old_netmask6)
-{
-       if (old_addr) {
-               if (!vpninfo->ip_info.addr || 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);
-                       /* EPERM means that the retry loop will abort and won't keep trying. */
-                       return -EPERM;
-               }
-       }
-       if (old_netmask) {
-               if (!vpninfo->ip_info.netmask || strcmp(old_netmask, vpninfo->ip_info.netmask)) {
-                       vpn_progress(vpninfo, PRG_ERR,
-                                    _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
-                                    vpninfo->ip_info.netmask, old_netmask);
-                       return -EPERM;
-               }
-       }
-       if (old_addr6) {
-               if (!vpninfo->ip_info.addr6 || strcmp(old_addr6, vpninfo->ip_info.addr6)) {
-                       vpn_progress(vpninfo, PRG_ERR,
-                                                _("Reconnect gave different IPv6 address (%s != %s)\n"),
-                                                vpninfo->ip_info.addr6, old_addr6);
-                       return -EPERM;
-               }
-       }
-       if (old_netmask6) {
-               if (!vpninfo->ip_info.netmask6 || strcmp(old_netmask6, vpninfo->ip_info.netmask6)) {
-                       vpn_progress(vpninfo, PRG_ERR,
-                                    _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
-                                    vpninfo->ip_info.netmask6, old_netmask6);
-                       return -EPERM;
-               }
-       }
-       return 0;
-}
-
 static int start_cstp_connection(struct openconnect_info *vpninfo)
 {
        struct oc_text_buf *reqbuf;
@@ -253,27 +215,11 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
        int i;
        int dtls_secret_set = 0;
        int retried = 0, sessid_found = 0;
-       struct oc_vpn_option **next_dtls_option = &vpninfo->dtls_options;
-       struct oc_vpn_option **next_cstp_option = &vpninfo->cstp_options;
-       struct oc_vpn_option *old_cstp_opts = vpninfo->cstp_options;
-       struct oc_vpn_option *old_dtls_opts = vpninfo->dtls_options;
        const char *old_addr = vpninfo->ip_info.addr;
-       const char *old_netmask = vpninfo->ip_info.netmask;
        const char *old_addr6 = vpninfo->ip_info.addr6;
-       const char *old_netmask6 = vpninfo->ip_info.netmask6;
+       const char *banner = NULL;
        int base_mtu = 0, mtu = 0;
 
-       /* Clear old options which will be overwritten */
-       vpninfo->ip_info.addr = vpninfo->ip_info.netmask = NULL;
-       vpninfo->ip_info.addr6 = vpninfo->ip_info.netmask6 = NULL;
-       vpninfo->cstp_options = vpninfo->dtls_options = NULL;
-       vpninfo->ip_info.domain = vpninfo->ip_info.proxy_pac = NULL;
-       vpninfo->banner = NULL;
-
-       for (i = 0; i < 3; i++)
-               vpninfo->ip_info.dns[i] = vpninfo->ip_info.nbns[i] = NULL;
-       free_split_routes(vpninfo);
-
  retry:
        calculate_dtls_mtu(vpninfo, &base_mtu, &mtu);
        vpninfo->cstp_basemtu = base_mtu;
@@ -417,12 +363,19 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
        vpninfo->cstp_compr = vpninfo->dtls_compr = 0;
        mtu = 0;
 
-       while ((i = vpninfo->ssl_gets(vpninfo, buf, sizeof(buf)))) {
+       struct oc_vpn_option *new_cstp_opts = NULL;
+       struct oc_vpn_option *new_dtls_opts = NULL;
+       struct oc_vpn_option **next_dtls_option = &new_dtls_opts;
+       struct oc_vpn_option **next_cstp_option = &new_cstp_opts;
+       struct oc_ip_info new_ip_info = {};
+       int ret = 0;
+
+       while ((ret = vpninfo->ssl_gets(vpninfo, buf, sizeof(buf)))) {
                struct oc_vpn_option *new_option;
                char *colon;
 
-               if (i < 0)
-                       return i;
+               if (ret < 0)
+                       goto err;
 
                colon = strchr(buf, ':');
                if (!colon)
@@ -441,7 +394,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
                new_option = malloc(sizeof(*new_option));
                if (!new_option) {
                        vpn_progress(vpninfo, PRG_ERR, _("No memory for options\n"));
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto err;
                }
                new_option->option = strdup(buf);
                new_option->value = strdup(colon);
@@ -452,7 +406,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
                        free(new_option->option);
                        free(new_option->value);
                        free(new_option);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto err;
                }
 
                /* This contains the whole document, including the webvpn cookie. */
@@ -479,7 +434,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
                                             _("X-DTLS-Session-ID not 64 characters; is: \"%s\"\n"),
                                                colon);
                                        vpninfo->dtls_attempt_period = 0;
-                                       return -EINVAL;
+                                       ret = -EINVAL;
+                                       goto err;
                                }
 
                                sessid_found = 1;
@@ -496,7 +452,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
                                             _("X-DTLS-Session-ID is invalid; is: \"%s\"\n"),
                                                colon);
                                        vpninfo->dtls_attempt_period = 0;
-                                       return -EINVAL;
+                                       ret = -EINVAL;
+                                       goto err;
                                }
 
                                vpninfo->dtls_app_id_size = vsize;
@@ -513,7 +470,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
                                        vpn_progress(vpninfo, PRG_ERR,
                                                     _("Unknown DTLS-Content-Encoding %s\n"),
                                                     colon);
-                                       return -EINVAL;
+                                       ret = -EINVAL;
+                                       goto err;
                                }
                        } else if (!strcmp(buf + i, "CipherSuite")) {
                                /* Remember if it came from a 'X-DTLS12-CipherSuite:' header */
@@ -587,7 +545,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
                                vpn_progress(vpninfo, PRG_ERR,
                                             _("Unknown CSTP-Content-Encoding %s\n"),
                                             colon);
-                               return -EINVAL;
+                               ret= -EINVAL;
+                               goto err;
                        }
                } else if (!strcmp(buf + 7, "Base-MTU")) {
                        vpninfo->cstp_basemtu = atol(colon);
@@ -599,92 +558,89 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
                        if (!strcmp(colon, "true"))
                                vpninfo->is_dyndns = 1;
                } else if (!strcmp(buf + 7, "Address-IP6")) {
-                       vpninfo->ip_info.netmask6 = new_option->value;
+                       new_ip_info.netmask6 = new_option->value;
                } else if (!strcmp(buf + 7, "Address")) {
                        if (strchr(new_option->value, ':')) {
                                if (!vpninfo->disable_ipv6)
-                                       vpninfo->ip_info.addr6 = new_option->value;
+                                       new_ip_info.addr6 = new_option->value;
                        } else
-                               vpninfo->ip_info.addr = new_option->value;
+                               new_ip_info.addr = new_option->value;
                } else if (!strcmp(buf + 7, "Netmask")) {
                        if (strchr(new_option->value, ':')) {
                                if (!vpninfo->disable_ipv6)
-                                       vpninfo->ip_info.netmask6 = new_option->value;
+                                       new_ip_info.netmask6 = new_option->value;
                        } else
-                               vpninfo->ip_info.netmask = new_option->value;
+                               new_ip_info.netmask = new_option->value;
                } else if (!strcmp(buf + 7, "DNS") ||
                           !strcmp(buf + 7, "DNS-IP6")) {
                        int j;
                        for (j = 0; j < 3; j++) {
-                               if (!vpninfo->ip_info.dns[j]) {
-                                       vpninfo->ip_info.dns[j] = new_option->value;
+                               if (!new_ip_info.dns[j]) {
+                                       new_ip_info.dns[j] = new_option->value;
                                        break;
                                }
                        }
                } else if (!strcmp(buf + 7, "NBNS")) {
                        int j;
                        for (j = 0; j < 3; j++) {
-                               if (!vpninfo->ip_info.nbns[j]) {
-                                       vpninfo->ip_info.nbns[j] = new_option->value;
+                               if (!new_ip_info.nbns[j]) {
+                                       new_ip_info.nbns[j] = new_option->value;
                                        break;
                                }
                        }
                } else if (!strcmp(buf + 7, "Default-Domain")) {
-                       vpninfo->ip_info.domain = new_option->value;
+                       new_ip_info.domain = new_option->value;
                } else if (!strcmp(buf + 7, "MSIE-Proxy-PAC-URL")) {
-                       vpninfo->ip_info.proxy_pac = new_option->value;
+                       new_ip_info.proxy_pac = new_option->value;
                } else if (!strcmp(buf + 7, "Banner")) {
-                       vpninfo->banner = new_option->value;
+                       banner = new_option->value;
                } else if (!strcmp(buf + 7, "Split-DNS")) {
                        struct oc_split_include *dns = malloc(sizeof(*dns));
                        if (!dns)
                                continue;
                        dns->route = new_option->value;
-                       dns->next = vpninfo->ip_info.split_dns;
-                       vpninfo->ip_info.split_dns = dns;
+                       dns->next = new_ip_info.split_dns;
+                       new_ip_info.split_dns = dns;
                } else if (!strcmp(buf + 7, "Split-Include") || !strcmp(buf + 7, "Split-Include-IP6")) {
                        struct oc_split_include *inc = malloc(sizeof(*inc));
                        if (!inc)
                                continue;
                        inc->route = new_option->value;
-                       inc->next = vpninfo->ip_info.split_includes;
-                       vpninfo->ip_info.split_includes = inc;
+                       inc->next = new_ip_info.split_includes;
+                       new_ip_info.split_includes = inc;
                } else if (!strcmp(buf + 7, "Split-Exclude") || !strcmp(buf + 7, "Split-Exclude-IP6")) {
                        struct oc_split_include *exc = malloc(sizeof(*exc));
                        if (!exc)
                                continue;
                        exc->route = new_option->value;
-                       exc->next = vpninfo->ip_info.split_excludes;
-                       vpninfo->ip_info.split_excludes = exc;
+                       exc->next = new_ip_info.split_excludes;
+                       new_ip_info.split_excludes = exc;
                }
        }
 
        if (!mtu) {
                vpn_progress(vpninfo, PRG_ERR,
                             _("No MTU received. Aborting\n"));
-               return -EINVAL;
-       }
-       vpninfo->ip_info.mtu = mtu;
-
-       if (!vpninfo->ip_info.addr && !vpninfo->ip_info.addr6 &&
-           !vpninfo->ip_info.netmask6) {
-               vpn_progress(vpninfo, PRG_ERR,
-                            _("No IP address received. Aborting\n"));
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err;
        }
-       if (mtu < 1280 &&
-           (vpninfo->ip_info.addr6 || vpninfo->ip_info.netmask6)) {
-               vpn_progress(vpninfo, PRG_ERR,
-                            _("IPv6 configuration received but MTU %d is too small.\n"),
-                            mtu);
+       new_ip_info.mtu = mtu;
+
+       ret = install_vpn_opts(vpninfo, new_cstp_opts, &new_ip_info);
+       if (ret) {
+       err:
+               free_optlist(new_cstp_opts);
+               free_optlist(new_dtls_opts);
+               free_split_routes(&new_ip_info);
+               return ret;
        }
 
-       i = check_address_sanity(vpninfo, old_addr, old_netmask, old_addr6, old_netmask6);
-       if (i)
-               return i;
+       /* DTLS opts are a special case. Perhaps should have been in the
+        * CSTP opts list anyway. This all very Cisco-specific. */
+       free_optlist(vpninfo->dtls_options);
+       vpninfo->dtls_options = new_dtls_opts;
+       vpninfo->banner = banner;
 
-       free_optlist(old_dtls_opts);
-       free_optlist(old_cstp_opts);
        vpn_progress(vpninfo, PRG_INFO, _("CSTP connected. DPD %d, Keepalive %d\n"),
                     vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
 
diff --git a/f5.c b/f5.c
index 4035f4baf1810315ef115800900aeebbecd97968..dda53d7c7cf30bfe521d4e49fa943e81456466cf 100644 (file)
--- a/f5.c
+++ b/f5.c
@@ -308,7 +308,7 @@ static int parse_options(struct openconnect_info *vpninfo, char *buf, int len,
 {
        xmlNode *fav_node, *obj_node, *xml_node;
        xmlDocPtr xml_doc;
-       int ret = 0, ii, n_dns = 0, n_nbns = 0, default_route = 0, dtls = 0, dtls_port = 0;
+       int ret = 0, n_dns = 0, n_nbns = 0, default_route = 0, dtls = 0, dtls_port = 0;
        char *s = NULL;
        struct oc_text_buf *domains = NULL;
 
@@ -332,14 +332,8 @@ static int parse_options(struct openconnect_info *vpninfo, char *buf, int len,
        if (!xmlnode_is_named(obj_node, "object"))
                goto err;
 
-       /* Clear old options which will be overwritten */
-       vpninfo->ip_info.addr = vpninfo->ip_info.netmask = NULL;
-       vpninfo->ip_info.addr6 = vpninfo->ip_info.netmask6 = NULL;
-       vpninfo->ip_info.domain = NULL;
-       vpninfo->cstp_options = NULL;
-       for (ii = 0; ii < 3; ii++)
-               vpninfo->ip_info.dns[ii] = vpninfo->ip_info.nbns[ii] = NULL;
-       free_split_routes(vpninfo);
+       struct oc_vpn_option *new_opts = NULL;
+       struct oc_ip_info new_ip_info = {};
 
        domains = buf_alloc();
 
@@ -382,14 +376,14 @@ static int parse_options(struct openconnect_info *vpninfo, char *buf, int len,
                        s = (char *)xmlNodeGetContent(xml_node);
                        if (s && *s) {
                                vpn_progress(vpninfo, PRG_INFO, _("Got DNS server %s\n"), s);
-                               if (n_dns < 3) vpninfo->ip_info.dns[n_dns++] = add_option_steal(vpninfo, "DNS", &s);
+                               if (n_dns < 3) new_ip_info.dns[n_dns++] = add_option_steal(&new_opts, "DNS", &s);
                        }
                } else if (!strncmp((char *)xml_node->name, "WINS", 4) && isdigit(xml_node->name[4])) {
                        free(s);
                        s = (char *)xmlNodeGetContent(xml_node);
                        if (s && *s) {
                                vpn_progress(vpninfo, PRG_INFO, _("Got WINS/NBNS server %s\n"), s);
-                               if (n_nbns < 3) vpninfo->ip_info.dns[n_nbns++] = add_option_steal(vpninfo, "WINS", &s);
+                               if (n_nbns < 3) new_ip_info.dns[n_nbns++] = add_option_steal(&new_opts, "WINS", &s);
                        }
                } else if (!strncmp((char *)xml_node->name, "DNSSuffix", 9) && isdigit(xml_node->name[9])) {
                        free(s);
@@ -421,14 +415,14 @@ static int parse_options(struct openconnect_info *vpninfo, char *buf, int len,
                                        struct oc_split_include *inc = malloc(sizeof(*inc));
                                        if (!inc)
                                                continue;
-                                       inc->route = add_option_dup(vpninfo, option, word, -1);
+                                       inc->route = add_option_dup(&new_opts, option, word, -1);
                                        if (is_exclude) {
-                                               inc->next = vpninfo->ip_info.split_excludes;
-                                               vpninfo->ip_info.split_excludes = inc;
+                                               inc->next = new_ip_info.split_excludes;
+                                               new_ip_info.split_excludes = inc;
                                                vpn_progress(vpninfo, PRG_INFO, _("Got split exclude route %s\n"), word);
                                        } else {
-                                               inc->next = vpninfo->ip_info.split_includes;
-                                               vpninfo->ip_info.split_includes = inc;
+                                               inc->next = new_ip_info.split_includes;
+                                               new_ip_info.split_includes = inc;
                                                vpn_progress(vpninfo, PRG_INFO, _("Got split include route %s\n"), word);
                                        }
                                }
@@ -454,16 +448,20 @@ static int parse_options(struct openconnect_info *vpninfo, char *buf, int len,
                }
        }
        if (default_route && *ipv4)
-               vpninfo->ip_info.netmask = add_option_dup(vpninfo, "netmask", "0.0.0.0", -1);
+               new_ip_info.netmask = add_option_dup(&new_opts, "netmask", "0.0.0.0", -1);
        if (default_route && *ipv6)
-               vpninfo->ip_info.netmask6 = add_option_dup(vpninfo, "netmask6", "::/0", -1);
+               new_ip_info.netmask6 = add_option_dup(&new_opts, "netmask6", "::/0", -1);
        if (buf_error(domains) == 0 && domains->pos > 0) {
                domains->data[domains->pos-1] = '\0';
-               vpninfo->ip_info.domain = add_option_steal(vpninfo, "search", &domains->data);
+               new_ip_info.domain = add_option_steal(&new_opts, "search", &domains->data);
        }
        buf_free(domains);
 
-       if ( (*ipv4 < 1 && *ipv6 < 1) || !*ur_z || !*session_id) {
+       ret = install_vpn_opts(vpninfo, new_opts, &new_ip_info);
+
+       if (ret || (*ipv4 < 1 && *ipv6 < 1) || !*ur_z || !*session_id) {
+               free_optlist(new_opts);
+                free_split_routes(&new_ip_info);
        err:
                vpn_progress(vpninfo, PRG_ERR,
                             _("Failed to find VPN options\n"));
@@ -513,11 +511,6 @@ static int f5_configure(struct openconnect_info *vpninfo)
        char *sid = NULL, *ur_z = NULL;
        int ipv4 = -1, ipv6 = -1, hdlc = 0;
        char *res_buf = NULL;
-       struct oc_vpn_option *old_cstp_opts = vpninfo->cstp_options;
-       const char *old_addr = vpninfo->ip_info.addr;
-       const char *old_netmask = vpninfo->ip_info.netmask;
-       const char *old_addr6 = vpninfo->ip_info.addr6;
-       const char *old_netmask6 = vpninfo->ip_info.netmask6;
 
        if (!vpninfo->cookies) {
                /* XX: This will happen if authentication was separate/external */
@@ -576,17 +569,6 @@ static int f5_configure(struct openconnect_info *vpninfo)
        if (ipv6 == -1)
                ipv6 = 0;
 
-       /* The addresses set in ip_info only after they're negotiated in PPP.
-        * If they were there before a reconnect, preserve them. */
-       if (old_addr)
-               vpninfo->ip_info.addr = add_option_dup(vpninfo, "ppp_addr", old_addr, -1);
-       if (old_addr6)
-               vpninfo->ip_info.addr6 = add_option_dup(vpninfo, "ppp_addr6", old_addr6, -1);
-
-       ret = check_address_sanity(vpninfo, old_addr, old_netmask, old_addr6, old_netmask6);
-       if (ret < 0)
-               goto out;
-
        /* XX: This buffer is used to initiate the connection over either TLS or DTLS.
         * Cookies are not needed for it to succeed, and can potentially grow without bound,
         * which would make it too big to fit in a single DTLS packet (ick, HTTP over DTLS).
@@ -619,8 +601,6 @@ static int f5_configure(struct openconnect_info *vpninfo)
        ret = openconnect_ppp_new(vpninfo, hdlc ? PPP_ENCAP_F5_HDLC : PPP_ENCAP_F5, ipv4, ipv6);
 
  out:
-       if (old_cstp_opts != vpninfo->cstp_options)
-               free_optlist(old_cstp_opts);
        free(res_buf);
        free(profile_params);
        free(sid);
index e51994decd0718af484a4c6f75f2f0b974d1bf6c..bc5ef8ab03b0fc4e933f0fd08b6e52cb6027c96d 100644 (file)
@@ -278,12 +278,11 @@ int fortinet_obtain_cookie(struct openconnect_info *vpninfo)
   <auth-timeout val="18000"/>
 </sslvpn-tunnel>
 */
-static int parse_fortinet_xml_config(struct openconnect_info *vpninfo, char *buf, int len,
-                                    int *ipv4, int *ipv6)
+static int parse_fortinet_xml_config(struct openconnect_info *vpninfo, char *buf, int len)
 {
        xmlNode *xml_node, *x, *x2;
        xmlDocPtr xml_doc;
-       int ret = 0, ii, n_dns = 0, default_route = 1;
+       int ret = 0, n_dns = 0, default_route = 1;
        char *s = NULL, *s2 = NULL;
        struct oc_text_buf *domains = NULL;
 
@@ -304,14 +303,8 @@ static int parse_fortinet_xml_config(struct openconnect_info *vpninfo, char *buf
        if (!xml_node || !xmlnode_is_named(xml_node, "sslvpn-tunnel"))
                return -EINVAL;
 
-       /* Clear old options which will be overwritten */
-       vpninfo->ip_info.addr = vpninfo->ip_info.netmask = NULL;
-       vpninfo->ip_info.addr6 = vpninfo->ip_info.netmask6 = NULL;
-       vpninfo->ip_info.domain = NULL;
-       vpninfo->cstp_options = NULL;
-       for (ii = 0; ii < 3; ii++)
-               vpninfo->ip_info.dns[ii] = vpninfo->ip_info.nbns[ii] = NULL;
-       free_split_routes(vpninfo);
+       struct oc_vpn_option *new_opts = NULL;
+       struct oc_ip_info new_ip_info = {};
 
        domains = buf_alloc();
 
@@ -347,11 +340,10 @@ static int parse_fortinet_xml_config(struct openconnect_info *vpninfo, char *buf
                                         _("Reported platform is %s\n"), platform);
                        }
                } else if (xmlnode_is_named(xml_node, "ipv4")) {
-                       *ipv4 = 1;
                        for (x = xml_node->children; x; x=x->next) {
                                if (xmlnode_is_named(x, "assigned-addr") && !xmlnode_get_prop(x, "ipv4", &s)) {
                                        vpn_progress(vpninfo, PRG_INFO, _("Got legacy IP address %s\n"), s);
-                                       vpninfo->ip_info.addr = add_option_steal(vpninfo, "ipaddr", &s);
+                                       new_ip_info.addr = add_option_steal(&new_opts, "ipaddr", &s);
                                } else if (xmlnode_is_named(x, "dns")) {
                                        if (!xmlnode_get_prop(x, "domain", &s) && s && *s) {
                                                vpn_progress(vpninfo, PRG_INFO, _("Got search domain %s\n"), s);
@@ -359,7 +351,7 @@ static int parse_fortinet_xml_config(struct openconnect_info *vpninfo, char *buf
                                        }
                                        if (!xmlnode_get_prop(x, "ip", &s) && s && *s) {
                                                vpn_progress(vpninfo, PRG_INFO, _("Got IPv%d DNS server %s\n"), 4, s);
-                                               if (n_dns < 3) vpninfo->ip_info.dns[n_dns++] = add_option_steal(vpninfo, "DNS", &s);
+                                               if (n_dns < 3) new_ip_info.dns[n_dns++] = add_option_steal(&new_opts, "DNS", &s);
                                        }
                                } else if (xmlnode_is_named(x, "split-dns")) {
                                        int ii;
@@ -385,14 +377,16 @@ static int parse_fortinet_xml_config(struct openconnect_info *vpninfo, char *buf
                                                                if (!route || !inc) {
                                                                        free(route);
                                                                        free(inc);
+                                                                       free_optlist(new_opts);
+                                                                       free_split_routes(&new_ip_info);
                                                                        ret = -ENOMEM;
                                                                        goto out;
                                                                }
                                                                snprintf(route, 32, "%s/%s", s, s2);
                                                                vpn_progress(vpninfo, PRG_INFO, _("Got IPv%d route %s\n"), 4, route);
-                                                               inc->route = add_option_steal(vpninfo, "split-include", &route);
-                                                               inc->next = vpninfo->ip_info.split_includes;
-                                                               vpninfo->ip_info.split_includes = inc;
+                                                               inc->route = add_option_steal(&new_opts, "split-include", &route);
+                                                               inc->next = new_ip_info.split_includes;
+                                                               new_ip_info.split_includes = inc;
                                                                /* XX: static analyzer doesn't realize that add_option_steal will steal route's reference, so... */
                                                                free(route);
                                                        }
@@ -403,17 +397,19 @@ static int parse_fortinet_xml_config(struct openconnect_info *vpninfo, char *buf
                }
        }
 
-       if (default_route && *ipv4)
-               vpninfo->ip_info.netmask = strdup("0.0.0.0");
-       if (default_route && *ipv6)
-               vpninfo->ip_info.netmask6 = strdup("::/0");
+       if (default_route && new_ip_info.addr)
+               new_ip_info.netmask = add_option_dup(&new_opts, "full-netmask", "0.0.0.0", -1);
        if (buf_error(domains) == 0 && domains->pos > 0) {
                domains->data[domains->pos-1] = '\0';
-               vpninfo->ip_info.domain = add_option_steal(vpninfo, "search", &domains->data);
+               new_ip_info.domain = add_option_steal(&new_opts, "search", &domains->data);
        }
        buf_free(domains);
 
-       if (*ipv4 < 1 && *ipv6 < 1) {
+       ret = install_vpn_opts(vpninfo, new_opts, &new_ip_info);
+       if (ret) {
+               free_optlist(new_opts);
+                free_split_routes(&new_ip_info);
+
                vpn_progress(vpninfo, PRG_ERR,
                             _("Failed to find VPN options\n"));
                vpn_progress(vpninfo, PRG_DEBUG,
@@ -432,7 +428,7 @@ static int fortinet_configure(struct openconnect_info *vpninfo)
        char *res_buf = NULL;
        struct oc_text_buf *reqbuf = NULL;
        struct oc_vpn_option *svpncookie = NULL;
-       int ret, ipv4 = -1, ipv6 = -1;
+       int ret;
 
        /* XXX: We should use check_address_sanity to verify that addresses haven't
           changed on a reconnect, except that:
@@ -497,15 +493,10 @@ static int fortinet_configure(struct openconnect_info *vpninfo)
        } else if (ret == 0)
                goto invalid_cookie;
 
-       ret = parse_fortinet_xml_config(vpninfo, res_buf, ret, &ipv4, &ipv6);
+       ret = parse_fortinet_xml_config(vpninfo, res_buf, ret);
        if (ret)
                goto out;
 
-       if (ipv4 == -1)
-               ipv4 = 0;
-       if (ipv6 == -1)
-               ipv6 = 0;
-
        reqbuf = vpninfo->ppp_tls_connect_req;
        if (!reqbuf)
                reqbuf = buf_alloc();
@@ -534,6 +525,8 @@ static int fortinet_configure(struct openconnect_info *vpninfo)
        vpninfo->ppp_dtls_connect_req = reqbuf;
        reqbuf = NULL;
 
+       int ipv4 = !!vpninfo->ip_info.addr;
+       int ipv6 = !!(vpninfo->ip_info.addr6 || vpninfo->ip_info.netmask6);
        ret = openconnect_ppp_new(vpninfo, PPP_ENCAP_FORTINET, ipv4, ipv6);
 
  out:
diff --git a/gpst.c b/gpst.c
index 39b6daa36def4e481953c207b84e70022a861361..c3d0b5ede850a5c0178f33ff2906d259d7389b4b 100644 (file)
--- a/gpst.c
+++ b/gpst.c
@@ -348,39 +348,35 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
        struct oc_split_include *inc;
        int split_route_is_default_route = 0;
        int n_dns = 0, got_esp = 0;
+       int ret = 0;
        int ii;
 
        if (!xml_node || !xmlnode_is_named(xml_node, "response"))
                return -EINVAL;
 
-       /* Clear old options which will be overwritten */
-       vpninfo->ip_info.addr = vpninfo->ip_info.netmask = NULL;
-       vpninfo->ip_info.addr6 = vpninfo->ip_info.netmask6 = NULL;
-       vpninfo->ip_info.domain = NULL;
-       vpninfo->ip_info.mtu = 0;
-       vpninfo->esp_magic = inet_addr(vpninfo->ip_info.gateway_addr);
+
+       struct oc_vpn_option *new_opts = NULL;
+       struct oc_ip_info new_ip_info = {};
+
+       if (vpninfo->ip_info.gateway_addr)
+               vpninfo->esp_magic = inet_addr(vpninfo->ip_info.gateway_addr);
        vpninfo->esp_replay_protect = 1;
        vpninfo->ssl_times.rekey_method = REKEY_NONE;
-       vpninfo->cstp_options = NULL;
-
-       for (ii = 0; ii < 3; ii++)
-               vpninfo->ip_info.dns[ii] = vpninfo->ip_info.nbns[ii] = NULL;
-       free_split_routes(vpninfo);
 
        /* Parse config */
        for (xml_node = xml_node->children; xml_node; xml_node=xml_node->next) {
                if (!xmlnode_get_val(xml_node, "ip-address", &s))
-                       vpninfo->ip_info.addr = add_option_steal(vpninfo, "ipaddr", &s);
+                       new_ip_info.addr = add_option_steal(&new_opts, "ipaddr", &s);
                else if (!xmlnode_get_val(xml_node, "ip-address-v6", &s)) {
                        if (!vpninfo->disable_ipv6)
-                               vpninfo->ip_info.addr6 = add_option_steal(vpninfo, "ipaddr6", &s);
+                               new_ip_info.addr6 = add_option_steal(&new_opts, "ipaddr6", &s);
                } else if (!xmlnode_get_val(xml_node, "netmask", &deferred_netmask)) {
                        /* XX: GlobalProtect servers always (almost always?) send 255.255.255.255 as their netmask
                         * (a /32 host route), and if they want to include an actual default route (0.0.0.0/0)
                         * they instead put it under <access-routes/>. We defer saving the netmask until later.
                         */
                } else if (!xmlnode_get_val(xml_node, "mtu", &s))
-                       vpninfo->ip_info.mtu = atoi(s);
+                       new_ip_info.mtu = atoi(s);
                else if (!xmlnode_get_val(xml_node, "lifetime", &s))
                        vpninfo->auth_expiration = time(NULL) + atol(s);
                else if (!xmlnode_get_val(xml_node, "quarantine", &s) && strcmp(s, "no"))
@@ -408,9 +404,9 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
                         * gateway is meaningless." See esp_send_probes_gp for the
                         * gory details of what this field actually means.
                         */
-                       if (strcmp(s, vpninfo->ip_info.gateway_addr))
+                       if (vpninfo->ip_info.gateway_addr && strcmp(s, vpninfo->ip_info.gateway_addr))
                                vpn_progress(vpninfo, PRG_DEBUG,
-                                                        _("Gateway address in config XML (%s) differs from external gateway address (%s).\n"), s, vpninfo->ip_info.gateway_addr);
+                                                        _("Gateway address in config XML (%s) differs from external gateway address (%s).\n"), s, new_ip_info.gateway_addr);
                        vpninfo->esp_magic = inet_addr(s);
                } else if (!xmlnode_get_val(xml_node, "gw-address-v6", &s)) {
                        /* This is probably used analogously to <gw-address>, but
@@ -419,27 +415,28 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
                        vpn_progress(vpninfo, PRG_ERR,
                                     _("WARNING: IPv6 gateway address set in config XML (%s). IPv6 ESP may not yet be functional.\n"), s);
                } else if (!xmlnode_get_val(xml_node, "connected-gw-ip", &s)) {
-                       if (strcmp(s, vpninfo->ip_info.gateway_addr))
+                       if (vpninfo->ip_info.gateway_addr && strcmp(s, vpninfo->ip_info.gateway_addr))
                                vpn_progress(vpninfo, PRG_DEBUG, _("Config XML <connected-gw-ip> address (%s) differs from external\n"
                                                                   "gateway address (%s). Please report any this to\n"
                                                                   "<openconnect-devel@lists.infradead.org>, including any problems\n"
-                                                                  "with ESP or other apparent loss of connectivity or performance.\n"), s, vpninfo->ip_info.gateway_addr);
+                                                                  "with ESP or other apparent loss of connectivity or performance.\n"),
+                                            s, vpninfo->ip_info.gateway_addr);
                } else if (xmlnode_is_named(xml_node, "dns-v6") ||
                           xmlnode_is_named(xml_node, "dns")) {
                        for (member = xml_node->children; member && n_dns<3; member=member->next) {
                                if (!xmlnode_get_val(member, "member", &s)) {
                                        for (ii=0; ii<n_dns; ii++)
                                                /* XX: frequent duplicates between <dns> and <dns-v6> */
-                                               if (!strcmp(s, vpninfo->ip_info.dns[ii]))
+                                               if (!strcmp(s, new_ip_info.dns[ii]))
                                                        break;
                                        if (ii==n_dns)
-                                               vpninfo->ip_info.dns[n_dns++] = add_option_steal(vpninfo, "DNS", &s);
+                                               new_ip_info.dns[n_dns++] = add_option_steal(&new_opts, "DNS", &s);
                                }
                        }
                } else if (xmlnode_is_named(xml_node, "wins")) {
                        for (ii=0, member = xml_node->children; member && ii<3; member=member->next)
                                if (!xmlnode_get_val(member, "member", &s))
-                                       vpninfo->ip_info.nbns[ii++] = add_option_steal(vpninfo, "WINS", &s);
+                                       new_ip_info.nbns[ii++] = add_option_steal(&new_opts, "WINS", &s);
                } else if (xmlnode_is_named(xml_node, "dns-suffix")) {
                        struct oc_text_buf *domains = buf_alloc();
                        for (member = xml_node->children; member; member=member->next)
@@ -447,7 +444,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
                                        buf_append(domains, "%s ", s);
                        if (buf_error(domains) == 0 && domains->pos > 0) {
                                domains->data[domains->pos-1] = '\0';
-                               vpninfo->ip_info.domain = add_option_steal(vpninfo, "search", &domains->data);
+                               new_ip_info.domain = add_option_steal(&new_opts, "search", &domains->data);
                        }
                        buf_free(domains);
                } else if (xmlnode_is_named(xml_node, "access-routes-v6") || xmlnode_is_named(xml_node, "exclude-access-routes-v6") ||
@@ -464,16 +461,19 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
                                                continue;
                                        }
 
-                                       if ((inc = malloc(sizeof(*inc))) == NULL)
-                                               return -ENOMEM;
+                                       inc = malloc(sizeof(*inc));
+                                       if (!inc) {
+                                               ret = -ENOMEM;
+                                               goto err;
+                                       }
                                        if (is_inc) {
-                                               inc->route = add_option_steal(vpninfo, "split-include", &s);
-                                               inc->next = vpninfo->ip_info.split_includes;
-                                               vpninfo->ip_info.split_includes = inc;
+                                               inc->route = add_option_steal(&new_opts, "split-include", &s);
+                                               inc->next = new_ip_info.split_includes;
+                                               new_ip_info.split_includes = inc;
                                        } else {
-                                               inc->route = add_option_steal(vpninfo, "split-exclude", &s);
-                                               inc->next = vpninfo->ip_info.split_excludes;
-                                               vpninfo->ip_info.split_excludes = inc;
+                                               inc->route = add_option_steal(&new_opts, "split-exclude", &s);
+                                               inc->next = new_ip_info.split_excludes;
+                                               new_ip_info.split_excludes = inc;
                                        }
                                }
                        }
@@ -540,25 +540,25 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
                        return -ENOMEM;
 
                /* If the original netmask wasn't /32, add it as a split route */
-               if (vpninfo->ip_info.addr && original_netmask) {
+               if (new_ip_info.addr && original_netmask) {
                        uint32_t nm_bits = inet_addr(original_netmask);
                        if (nm_bits != 0xffffffff) { /* 255.255.255.255 */
                                struct in_addr net_addr;
-                               inet_aton(vpninfo->ip_info.addr, &net_addr);
+                               inet_aton(new_ip_info.addr, &net_addr);
                                net_addr.s_addr &= nm_bits; /* clear host bits */
 
                                if ((inc = malloc(sizeof(*inc))) == NULL ||
                                    asprintf(&s, "%s/%s", inet_ntoa(net_addr), original_netmask) <= 0)
                                        return -ENOMEM;
-                               inc->route = add_option_steal(vpninfo, "split-include", &s);
-                               inc->next = vpninfo->ip_info.split_includes;
-                               vpninfo->ip_info.split_includes = inc;
+                               inc->route = add_option_steal(&new_opts, "split-include", &s);
+                               inc->next = new_ip_info.split_includes;
+                               new_ip_info.split_includes = inc;
                        }
                }
                free(original_netmask);
        }
        if (deferred_netmask)
-               vpninfo->ip_info.netmask = add_option_steal(vpninfo, "netmask", &deferred_netmask);
+               new_ip_info.netmask = add_option_steal(&new_opts, "netmask", &deferred_netmask);
 
        /* Set 10-second DPD/keepalive (same as Windows client) unless
         * overridden with --force-dpd */
@@ -567,7 +567,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
        vpninfo->ssl_times.keepalive = vpninfo->esp_ssl_fallback = vpninfo->ssl_times.dpd;
 
        /* Warn about IPv6 config, if present, and ESP config, if absent */
-       if (vpninfo->ip_info.addr6)
+       if (new_ip_info.addr6)
                vpn_progress(vpninfo, PRG_ERR,
                             _("GlobalProtect IPv6 support is experimental. Please report results to <openconnect-devel@lists.infradead.org>.\n"));
 #ifdef HAVE_ESP
@@ -577,7 +577,15 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
 #endif
 
        free(s);
-       return 0;
+
+       ret = install_vpn_opts(vpninfo, new_opts, &new_ip_info);
+       if (ret) {
+       err:
+               free_optlist(new_opts);
+               free_split_routes(&new_ip_info);
+       }
+
+       return ret;
 }
 
 static int gpst_get_config(struct openconnect_info *vpninfo)
@@ -585,13 +593,12 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
        char *orig_path;
        int result;
        struct oc_text_buf *request_body = buf_alloc();
-       struct oc_vpn_option *old_cstp_opts = vpninfo->cstp_options;
-       const char *old_addr = vpninfo->ip_info.addr, *old_netmask = vpninfo->ip_info.netmask;
-       const char *old_addr6 = vpninfo->ip_info.addr6, *old_netmask6 = vpninfo->ip_info.netmask6;
+       const char *old_addr = vpninfo->ip_info.addr;
+       const char *old_addr6 = vpninfo->ip_info.addr6;
        const char *request_body_type = "application/x-www-form-urlencoded";
        const char *method = "POST";
-       char *xml_buf=NULL;
-       vpninfo->cstp_options = NULL;
+       char *xml_buf = NULL;
+
 
        /* submit getconfig request */
        buf_append(request_body, "client-type=1&protocol-version=p1&app-version=5.1.5-8");
@@ -653,18 +660,8 @@ static int gpst_get_config(struct openconnect_info *vpninfo)
                             no_esp_reason ? "SSL tunnel. " : "ESP tunnel", no_esp_reason ? : "");
                /* return -EINVAL; */
        }
-       if (!vpninfo->ip_info.addr && !vpninfo->ip_info.addr6 &&
-           !vpninfo->ip_info.netmask6) {
-               vpn_progress(vpninfo, PRG_ERR,
-                            _("No IP address received. Aborting\n"));
-               result = -EINVAL;
-               goto out;
-       }
-
-       result = check_address_sanity(vpninfo, old_addr, old_netmask, old_addr6, old_netmask6);
 
 out:
-       free_optlist(old_cstp_opts);
        buf_free(request_body);
        free(xml_buf);
        return result;
index b0655ba7b5e585f0bf741a9ade762822614c8e00..0aa0bd4da1921c4db7491f61dafc3b94ae2fc9ed 100644 (file)
--- a/library.c
+++ b/library.c
@@ -387,7 +387,8 @@ int openconnect_set_version_string(struct openconnect_info *vpninfo,
        return 0;
 }
 
-const char *add_option_dup(struct openconnect_info *vpninfo, const char *opt,
+const char *add_option_dup(struct oc_vpn_option **list,
+                          const char *opt,
                           const char *val, int val_len)
 {
        const char *ret;
@@ -398,12 +399,13 @@ const char *add_option_dup(struct openconnect_info *vpninfo, const char *opt,
        else
                new_val = strdup(val);
 
-       ret = add_option_steal(vpninfo, opt, &new_val);
+       ret = add_option_steal(list, opt, &new_val);
        free(new_val);
        return ret;
 }
 
-const char *add_option_steal(struct openconnect_info *vpninfo, const char *opt, char **val)
+const char *add_option_steal(struct oc_vpn_option **list,
+                            const char *opt, char **val)
 {
        struct oc_vpn_option *new = malloc(sizeof(*new));
        if (!new)
@@ -416,21 +418,21 @@ const char *add_option_steal(struct openconnect_info *vpninfo, const char *opt,
        }
        new->value = *val;
        *val = NULL;
-       new->next = vpninfo->cstp_options;
-       vpninfo->cstp_options = new;
+       new->next = *list;
+       *list = new;
 
        return new->value;
 }
 
-const char *add_option_ipaddr(struct openconnect_info *vpninfo, const char *opt,
-                             int af, void *addr)
+const char *add_option_ipaddr(struct oc_vpn_option **list,
+                             const char *opt, int af, void *addr)
 {
        char buf[40];
 
        if (!inet_ntop(af, addr, buf, sizeof(buf)))
                return NULL;
 
-       return add_option_dup(vpninfo, opt, buf, -1);
+       return add_option_dup(list, opt, buf, -1);
 }
 
 
@@ -446,6 +448,75 @@ void free_optlist(struct oc_vpn_option *opt)
        }
 }
 
+int install_vpn_opts(struct openconnect_info *vpninfo, struct oc_vpn_option *opt,
+                    struct oc_ip_info *ip_info)
+{
+       /* F5 doesn't get its IP address until it actually establishes the
+        * PPP connection. */
+       if (vpninfo->proto->proto != PROTO_F5 && !ip_info->addr &&
+           !ip_info->addr6 && !ip_info->netmask6) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("No IP address received. Aborting\n"));
+               return -EINVAL;
+       }
+
+       if (vpninfo->ip_info.addr) {
+               if (!ip_info->addr || strcmp(ip_info->addr, vpninfo->ip_info.addr)) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("Reconnect gave different Legacy IP address (%s != %s)\n"),
+                                    ip_info->addr, vpninfo->ip_info.addr);
+                       /* EPERM means that the retry loop will abort and won't keep trying. */
+                       return -EPERM;
+               }
+       }
+       if (vpninfo->ip_info.netmask) {
+               if (!ip_info->netmask || strcmp(ip_info->netmask, vpninfo->ip_info.netmask)) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("Reconnect gave different Legacy IP netmask (%s != %s)\n"),
+                                    ip_info->netmask, vpninfo->ip_info.netmask);
+                       return -EPERM;
+               }
+       }
+       if (vpninfo->ip_info.addr6) {
+               if (!ip_info->addr6 || strcmp(ip_info->addr6, vpninfo->ip_info.addr6)) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("Reconnect gave different IPv6 address (%s != %s)\n"),
+                                    ip_info->addr6, vpninfo->ip_info.addr6);
+                       return -EPERM;
+               }
+       }
+       if (vpninfo->ip_info.netmask6) {
+               if (!ip_info->netmask6 || strcmp(ip_info->netmask6, vpninfo->ip_info.netmask6)) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("Reconnect gave different IPv6 netmask (%s != %s)\n"),
+                                    ip_info->netmask6, vpninfo->ip_info.netmask6);
+                       return -EPERM;
+               }
+       }
+
+       /* Preserve gateway_addr and MTU if they were set */
+       ip_info->gateway_addr = vpninfo->ip_info.gateway_addr;
+       if (!ip_info->mtu)
+               ip_info->mtu = vpninfo->ip_info.mtu;
+
+       if (ip_info->mtu && ip_info->mtu < 1280 &&
+           (ip_info->addr6 || ip_info->netmask6)) {
+               vpn_progress(vpninfo, PRG_ERR,
+                            _("IPv6 configuration received but MTU %d is too small.\n"),
+                            ip_info->mtu);
+       }
+
+       /* Free the original options */
+       free_split_routes(&vpninfo->ip_info);
+       free_optlist(vpninfo->cstp_options);
+
+       /* Install the new options */
+       vpninfo->cstp_options = opt;
+       vpninfo->ip_info = *ip_info;
+
+       return 0;
+}
+
 void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
 {
        openconnect_close_https(vpninfo, 1);
@@ -485,7 +556,7 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
        free_optlist(vpninfo->cookies);
        free_optlist(vpninfo->cstp_options);
        free_optlist(vpninfo->dtls_options);
-       free_split_routes(vpninfo);
+       free_split_routes(&vpninfo->ip_info);
        free(vpninfo->hostname);
        free(vpninfo->unique_hostname);
        free(vpninfo->urlpath);
diff --git a/oncp.c b/oncp.c
index c297ba0c438c42a67375f1eec39064d7a884882b..f1fc0b5f6fd883c00d34389e801f9b9f30daa23e 100644 (file)
--- a/oncp.c
+++ b/oncp.c
@@ -61,8 +61,9 @@ static const char authpkt_tail[] = { 0xbb, 0x01, 0x00, 0x00, 0x00, 0x00 };
 
 #define GRP_ATTR(g, a) (((g) << 16) | (a))
 
-static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
-                       unsigned char *data, int attrlen)
+static int process_attr(struct openconnect_info *vpninfo,
+                       struct oc_vpn_option **new_opts, struct oc_ip_info *new_ip_info,
+                       int group, int attr, unsigned char *data, int attrlen)
 {
        char buf[80];
        int i;
@@ -76,10 +77,10 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                                     attrlen, group, attr);
                        return -EINVAL;
                }
-               vpninfo->ip_info.mtu = load_be32(data);
+               new_ip_info->mtu = load_be32(data);
                vpn_progress(vpninfo, PRG_DEBUG,
                             _("Received MTU %d from server\n"),
-                            vpninfo->ip_info.mtu);
+                            new_ip_info->mtu);
                break;
 
        case GRP_ATTR(2, 1):
@@ -90,8 +91,8 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                vpn_progress(vpninfo, PRG_DEBUG, _("Received DNS server %s\n"), buf);
 
                for (i = 0; i < 3; i++) {
-                       if (!vpninfo->ip_info.dns[i]) {
-                               vpninfo->ip_info.dns[i] = add_option_dup(vpninfo, "DNS", buf, -1);
+                       if (!new_ip_info->dns[i]) {
+                               new_ip_info->dns[i] = add_option_dup(new_opts, "DNS", buf, -1);
                                break;
                        }
                }
@@ -100,9 +101,9 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
        case GRP_ATTR(2, 2):
                vpn_progress(vpninfo, PRG_DEBUG, _("Received DNS search domain %.*s\n"),
                             attrlen, (char *)data);
-               vpninfo->ip_info.domain = add_option_dup(vpninfo, "search", (char *)data, attrlen);
-               if (vpninfo->ip_info.domain) {
-                       char *p = (char *)vpninfo->ip_info.domain;
+               new_ip_info->domain = add_option_dup(new_opts, "search", (char *)data, attrlen);
+               if (new_ip_info->domain) {
+                       char *p = (char *)new_ip_info->domain;
                        while ((p = strchr(p, ',')))
                                *p = ' ';
                }
@@ -114,7 +115,7 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                snprintf(buf, sizeof(buf), "%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
 
                vpn_progress(vpninfo, PRG_DEBUG, _("Received internal IP address %s\n"), buf);
-               vpninfo->ip_info.addr = add_option_dup(vpninfo, "ipaddr", buf, -1);
+               new_ip_info->addr = add_option_dup(new_opts, "ipaddr", buf, -1);
                break;
 
        case GRP_ATTR(1, 2):
@@ -123,7 +124,7 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                snprintf(buf, sizeof(buf), "%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
 
                vpn_progress(vpninfo, PRG_DEBUG, _("Received netmask %s\n"), buf);
-               vpninfo->ip_info.netmask = add_option_dup(vpninfo, "netmask", buf, -1);
+               new_ip_info->netmask = add_option_dup(new_opts, "netmask", buf, -1);
                break;
 
        case GRP_ATTR(1, 3):
@@ -134,7 +135,7 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                vpn_progress(vpninfo, PRG_DEBUG, _("Received internal gateway address %s\n"), buf);
                /* Hm, what are we supposed to do with this? It's a tunnel;
                   having a gateway is meaningless. */
-               add_option_dup(vpninfo, "ipaddr", buf, -1);
+               add_option_dup(new_opts, "ipaddr", buf, -1);
                break;
 
        case GRP_ATTR(3, 3): {
@@ -149,10 +150,10 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                        break;
                inc = malloc(sizeof(*inc));
                if (inc) {
-                       inc->route = add_option_dup(vpninfo, "split-include", buf, -1);
+                       inc->route = add_option_dup(new_opts, "split-include", buf, -1);
                        if (inc->route) {
-                               inc->next = vpninfo->ip_info.split_includes;
-                               vpninfo->ip_info.split_includes = inc;
+                               inc->next = new_ip_info->split_includes;
+                               new_ip_info->split_includes = inc;
                        } else
                                free(inc);
                }
@@ -171,10 +172,10 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                        break;
                exc = malloc(sizeof(*exc));
                if (exc) {
-                       exc->route = add_option_dup(vpninfo, "split-exclude", buf, -1);
+                       exc->route = add_option_dup(new_opts, "split-exclude", buf, -1);
                        if (exc->route) {
-                               exc->next = vpninfo->ip_info.split_excludes;
-                               vpninfo->ip_info.split_excludes = exc;
+                               exc->next = new_ip_info->split_excludes;
+                               new_ip_info->split_excludes = exc;
                        } else
                                free(exc);
                }
@@ -189,8 +190,8 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                vpn_progress(vpninfo, PRG_DEBUG, _("Received WINS server %s\n"), buf);
 
                for (i = 0; i < 3; i++) {
-                       if (!vpninfo->ip_info.nbns[i]) {
-                               vpninfo->ip_info.nbns[i] = add_option_dup(vpninfo, "WINS", buf, -1);
+                       if (!new_ip_info->nbns[i]) {
+                               new_ip_info->nbns[i] = add_option_dup(new_opts, "WINS", buf, -1);
                                break;
                        }
                }
@@ -396,6 +397,8 @@ static int parse_conf_pkt(struct openconnect_info *vpninfo, unsigned char *bytes
        int kmplen, kmpend, grouplen, groupend, group, attr, attrlen;
        int ofs = 0;
        int split_enc_hmac_keys = 0;
+       struct oc_vpn_option *new_opts = NULL;
+       struct oc_ip_info new_ip_info = {};
 
        kmplen = load_be16(bytes + ofs + 18);
        kmpend = ofs + kmplen;
@@ -404,6 +407,9 @@ static int parse_conf_pkt(struct openconnect_info *vpninfo, unsigned char *bytes
                vpn_progress(vpninfo, PRG_ERR,
                             _("Failed to parse KMP message\n"));
                dump_buf_hex(vpninfo, PRG_ERR, '<', bytes, pktlen);
+       einval:
+               free_optlist(new_opts);
+               free_split_routes(&new_ip_info);
                return -EINVAL;
        }
 
@@ -426,7 +432,7 @@ static int parse_conf_pkt(struct openconnect_info *vpninfo, unsigned char *bytes
                        vpn_progress(vpninfo, PRG_ERR,
                                     _("Received non-ESP TLVs (group %d) in ESP negotiation KMP\n"),
                                     group);
-                       return -EINVAL;
+                       goto einval;
                }
 
                while (ofs < groupend) {
@@ -437,7 +443,8 @@ static int parse_conf_pkt(struct openconnect_info *vpninfo, unsigned char *bytes
                        ofs += 6;
                        if (attrlen + ofs > groupend)
                                goto eparse;
-                       if (process_attr(vpninfo, group, attr, bytes + ofs, attrlen))
+                       if (process_attr(vpninfo, &new_opts, &new_ip_info,
+                                        group, attr, bytes + ofs, attrlen))
                                goto eparse;
                        if (GRP_ATTR(group, attr)==GRP_ATTR(7, 2))
                                split_enc_hmac_keys = 1;
@@ -450,6 +457,13 @@ static int parse_conf_pkt(struct openconnect_info *vpninfo, unsigned char *bytes
        if (split_enc_hmac_keys)
                memcpy(vpninfo->esp_out.hmac_key, vpninfo->esp_out.enc_key + vpninfo->enc_key_len, vpninfo->hmac_key_len);
 
+       int ret = install_vpn_opts(vpninfo, new_opts, &new_ip_info);
+       if (ret) {
+               free_optlist(new_opts);
+               free_split_routes(&new_ip_info);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -459,7 +473,6 @@ int oncp_connect(struct openconnect_info *vpninfo)
        int ret, len, kmp, kmplen, group, check_len;
        struct oc_text_buf *reqbuf;
        unsigned char bytes[65536];
-       const char *old_addr = vpninfo->ip_info.addr, *old_netmask = vpninfo->ip_info.netmask;
 
        if (!vpninfo->cookies) {
                /* XX: This will happen if authentication was separate/external */
@@ -704,8 +717,7 @@ int oncp_connect(struct openconnect_info *vpninfo)
                }
                goto out;
        }
-
-       ret = check_address_sanity(vpninfo, old_addr, old_netmask, NULL, NULL);
+       ret = 0;
 
  out:
        if (ret)
index 233835060636bee8892710664b8310c9f1dcf4e2..a6bffae830960c0266f1a7c9d7b448345da1650a 100644 (file)
@@ -936,7 +936,9 @@ int script_setenv_int(struct openconnect_info *vpninfo, const char *opt, int val
 void prepare_script_env(struct openconnect_info *vpninfo);
 int script_config_tun(struct openconnect_info *vpninfo, const char *reason);
 int apply_script_env(struct oc_vpn_option *envs);
-void free_split_routes(struct openconnect_info *vpninfo);
+void free_split_routes(struct oc_ip_info *ip_info);
+int install_vpn_opts(struct openconnect_info *vpninfo, struct oc_vpn_option *opt,
+                    struct oc_ip_info *ip_info);
 
 /* tun.c / tun-win32.c */
 void os_shutdown_tun(struct openconnect_info *vpninfo);
@@ -986,7 +988,6 @@ char *openconnect_bin2base64(const char *prefix, const uint8_t *data, unsigned l
 int calculate_mtu(struct openconnect_info *vpninfo, int is_udp, int unpadded_overhead, int padded_overhead, int block_size);
 
 /* cstp.c */
-int check_address_sanity(struct openconnect_info *vpninfo, const char *old_addr, const char *old_netmask, const char *old_addr6, const char *old_netmask6);
 void cstp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
 int cstp_connect(struct openconnect_info *vpninfo);
 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable);
@@ -1304,9 +1305,9 @@ int digest_authorization(struct openconnect_info *vpninfo, int proxy, struct htt
 
 /* library.c */
 void nuke_opt_values(struct oc_form_opt *opt);
-const char *add_option_dup(struct openconnect_info *vpninfo, const char *opt, const char *val, int val_len);
-const char *add_option_steal(struct openconnect_info *vpninfo, const char *opt, char **val);
-const char *add_option_ipaddr(struct openconnect_info *vpninfo, const char *opt, int af, void *addr);
+const char *add_option_dup(struct oc_vpn_option **list, const char *opt, const char *val, int val_len);
+const char *add_option_steal(struct oc_vpn_option **list, const char *opt, char **val);
+const char *add_option_ipaddr(struct oc_vpn_option **list, const char *opt, int af, void *addr);
 void free_optlist(struct oc_vpn_option *opt);
 int process_auth_form(struct openconnect_info *vpninfo, struct oc_auth_form *form);
 /* This is private for now since we haven't yet worked out what the API will be */
index 9cc142fa278a590832c33817eb42de87e5835ce4..389d5a871af6a5655e4508d02ce4d24c21b83192 100644 (file)
@@ -284,9 +284,10 @@ struct oc_split_include {
 
 struct oc_ip_info {
        const char *addr;
-       const char *netmask;
+       const char *netmask; /* Just the netmask, in dotted-quad form. */
        const char *addr6;
-       const char *netmask6;
+       const char *netmask6; /* This is the IPv6 address *and* netmask
+                              * e.g. "2001::dead:beef/128". */
        const char *dns[3];
        const char *nbns[3];
        const char *domain;
diff --git a/ppp.c b/ppp.c
index 6b6096c69f00273bb82ccfdf97cadb310a55f210..672ff17788aa152c6ed082916d03f9319dca27c2 100644 (file)
--- a/ppp.c
+++ b/ppp.c
@@ -937,32 +937,32 @@ static int handle_state_transition(struct openconnect_info *vpninfo, int dtls,
 
                /* Ensure that we use the addresses we configured on PPP */
                if (ppp->want_ipv4) {
-                       vpninfo->ip_info.addr = add_option_ipaddr(vpninfo, "ppp_ipv4", AF_INET,
-                                                                 &ppp->out_ipv4_addr);
+                       vpninfo->ip_info.addr = add_option_ipaddr(&vpninfo->cstp_options, "ppp_ipv4",
+                                                                 AF_INET, &ppp->out_ipv4_addr);
                } else {
                        vpninfo->ip_info.addr = NULL;
                }
 
                /* Ensure that we use the addresses we configured on PPP */
                if (ppp->want_ipv6) {
-                       vpninfo->ip_info.addr6 = add_option_ipaddr(vpninfo, "ppp_ipv6", AF_INET6,
-                                                                  &ppp->out_ipv6_addr);
+                       vpninfo->ip_info.addr6 = add_option_ipaddr(&vpninfo->cstp_options, "ppp_ipv6",
+                                                                  AF_INET6, &ppp->out_ipv6_addr);
                } else {
                        vpninfo->ip_info.addr6 = NULL;
                }
 
                if (ppp->got_peerns & IPCP_NBNS0)
-                       vpninfo->ip_info.nbns[0] = add_option_ipaddr(vpninfo, "ppp_nbns0", AF_INET,
-                                                                    &ppp->nameservers[0]);
+                       vpninfo->ip_info.nbns[0] = add_option_ipaddr(&vpninfo->cstp_options, "ppp_nbns0",
+                                                                    AF_INET, &ppp->nameservers[0]);
                if (ppp->got_peerns & IPCP_DNS0)
-                       vpninfo->ip_info.dns[0] = add_option_ipaddr(vpninfo, "ppp_dns0", AF_INET,
-                                                                   &ppp->nameservers[1]);
+                       vpninfo->ip_info.dns[0] = add_option_ipaddr(&vpninfo->cstp_options, "ppp_dns0",
+                                                                   AF_INET, &ppp->nameservers[1]);
                if (ppp->got_peerns & IPCP_NBNS1)
-                       vpninfo->ip_info.nbns[1] = add_option_ipaddr(vpninfo, "ppp_nbns1", AF_INET,
-                                                                    &ppp->nameservers[2]);
+                       vpninfo->ip_info.nbns[1] = add_option_ipaddr(&vpninfo->cstp_options, "ppp_nbns1",
+                                                                    AF_INET, &ppp->nameservers[2]);
                if (ppp->got_peerns & IPCP_DNS1)
-                       vpninfo->ip_info.dns[1] = add_option_ipaddr(vpninfo, "ppp_dns1", AF_INET,
-                                                                   &ppp->nameservers[3]);
+                       vpninfo->ip_info.dns[1] = add_option_ipaddr(&vpninfo->cstp_options, "ppp_dns1",
+                                                                   AF_INET, &ppp->nameservers[3]);
 
                /* on close, we will need to send TERMREQ, then receive TERMACK */
                vpninfo->delay_close = DELAY_CLOSE_IMMEDIATE_CALLBACK;
diff --git a/pulse.c b/pulse.c
index a7ad0ad1c2b1f9f80b22b87fd3549bebe3b7d513..2e18c7d2df75d38a21de6fb0fe7f8275b65a0fd2 100644 (file)
--- a/pulse.c
+++ b/pulse.c
@@ -217,7 +217,8 @@ static int valid_ift_auth_eap_exj1(unsigned char *bytes, int len)
        return 1;
 }
 
-static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
+static int process_attr(struct openconnect_info *vpninfo, struct oc_vpn_option **new_opts,
+                       struct oc_ip_info *new_ip_info, uint16_t type,
                        unsigned char *data, int attrlen)
 {
        struct oc_split_include *xc;
@@ -232,7 +233,7 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
                snprintf(buf, sizeof(buf), "%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
 
                vpn_progress(vpninfo, PRG_DEBUG, _("Received internal Legacy IP address %s\n"), buf);
-               vpninfo->ip_info.addr = add_option_dup(vpninfo, "ipaddr", buf, -1);
+               new_ip_info->addr = add_option_dup(new_opts, "ipaddr", buf, -1);
                break;
 
        case 0x0002:
@@ -241,7 +242,7 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
                snprintf(buf, sizeof(buf), "%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
 
                vpn_progress(vpninfo, PRG_DEBUG, _("Received netmask %s\n"), buf);
-               vpninfo->ip_info.netmask = add_option_dup(vpninfo, "netmask", buf, -1);
+               new_ip_info->netmask = add_option_dup(new_opts, "netmask", buf, -1);
                break;
 
        case 0x0003:
@@ -252,8 +253,8 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
                vpn_progress(vpninfo, PRG_DEBUG, _("Received DNS server %s\n"), buf);
 
                for (i = 0; i < 3; i++) {
-                       if (!vpninfo->ip_info.dns[i]) {
-                               vpninfo->ip_info.dns[i] = add_option_dup(vpninfo, "DNS", buf, -1);
+                       if (!new_ip_info->dns[i]) {
+                               new_ip_info->dns[i] = add_option_dup(new_opts, "DNS", buf, -1);
                                break;
                        }
                }
@@ -267,8 +268,8 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
                vpn_progress(vpninfo, PRG_DEBUG, _("Received WINS server %s\n"), buf);
 
                for (i = 0; i < 3; i++) {
-                       if (!vpninfo->ip_info.nbns[i]) {
-                               vpninfo->ip_info.nbns[i] = add_option_dup(vpninfo, "WINS", buf, -1);
+                       if (!new_ip_info->nbns[i]) {
+                               new_ip_info->nbns[i] = add_option_dup(new_opts, "WINS", buf, -1);
                                break;
                        }
                }
@@ -282,11 +283,11 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
                                     _("Failed to handle IPv6 address\n"));
                        return -EINVAL;
                }
-               vpninfo->ip_info.addr6 = add_option_dup(vpninfo, "ip6addr", buf, -1);
+               new_ip_info->addr6 = add_option_dup(new_opts, "ip6addr", buf, -1);
 
                i = strlen(buf);
                snprintf(buf + i, sizeof(buf) - i, "/%d", data[16]);
-               vpninfo->ip_info.netmask6 = add_option_dup(vpninfo, "ip6netmask", buf, -1);
+               new_ip_info->netmask6 = add_option_dup(new_opts, "ip6netmask", buf, -1);
 
                vpn_progress(vpninfo, PRG_DEBUG, _("Received internal IPv6 address %s\n"), buf);
                break;
@@ -301,8 +302,8 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
                }
 
                for (i = 0; i < 3; i++) {
-                       if (!vpninfo->ip_info.dns[i]) {
-                               vpninfo->ip_info.dns[i] = add_option_dup(vpninfo, "DNS", buf, -1);
+                       if (!new_ip_info->dns[i]) {
+                               new_ip_info->dns[i] = add_option_dup(new_opts, "DNS", buf, -1);
                                break;
                        }
                }
@@ -323,10 +324,10 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
 
                xc = malloc(sizeof(*xc));
                if (xc) {
-                       xc->route =  add_option_dup(vpninfo, "split-include6", buf, -1);
+                       xc->route =  add_option_dup(new_opts, "split-include6", buf, -1);
                        if (xc->route) {
-                               xc->next = vpninfo->ip_info.split_includes;
-                               vpninfo->ip_info.split_includes = xc;
+                               xc->next = new_ip_info->split_includes;
+                               new_ip_info->split_includes = xc;
                        } else
                                free(xc);
                }
@@ -346,10 +347,10 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
 
                xc = malloc(sizeof(*xc));
                if (xc) {
-                       xc->route =  add_option_dup(vpninfo, "split-exclude6", buf, -1);
+                       xc->route =  add_option_dup(new_opts, "split-exclude6", buf, -1);
                        if (xc->route) {
-                               xc->next = vpninfo->ip_info.split_excludes;
-                               vpninfo->ip_info.split_excludes = xc;
+                               xc->next = new_ip_info->split_excludes;
+                               new_ip_info->split_excludes = xc;
                        } else
                                free(xc);
                }
@@ -364,10 +365,10 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
                                     attrlen, type);
                        return -EINVAL;
                }
-               vpninfo->ip_info.mtu = load_be32(data);
+               new_ip_info->mtu = load_be32(data);
                vpn_progress(vpninfo, PRG_DEBUG,
                             _("Received MTU %d from server\n"),
-                            vpninfo->ip_info.mtu);
+                            new_ip_info->mtu);
                break;
 
        case 0x4006:
@@ -377,9 +378,9 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
                    attrlen--;
                vpn_progress(vpninfo, PRG_DEBUG, _("Received DNS search domain %.*s\n"),
                             attrlen, (char *)data);
-               vpninfo->ip_info.domain = add_option_dup(vpninfo, "search", (char *)data, attrlen);
-               if (vpninfo->ip_info.domain) {
-                       char *p = (char *)vpninfo->ip_info.domain;
+               new_ip_info->domain = add_option_dup(new_opts, "search", (char *)data, attrlen);
+               if (new_ip_info->domain) {
+                       char *p = (char *)new_ip_info->domain;
                        while ((p = strchr(p, ',')))
                                *p = ' ';
                }
@@ -393,7 +394,7 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
                vpn_progress(vpninfo, PRG_DEBUG, _("Received internal gateway address %s\n"), buf);
                /* Hm, what are we supposed to do with this? It's a tunnel;
                   having a gateway is meaningless. */
-               add_option_dup(vpninfo, "ipaddr", buf, -1);
+               add_option_dup(new_opts, "ipaddr", buf, -1);
                break;
 
        case 0x4010: {
@@ -2257,10 +2258,6 @@ static int handle_main_config_packet(struct openconnect_info *vpninfo,
        int routes_len = 0;
        int l;
        unsigned char *p;
-       const char *old_addr = vpninfo->ip_info.addr;
-       const char *old_netmask = vpninfo->ip_info.netmask;
-       const char *old_addr6 = vpninfo->ip_info.addr6;
-       const char *old_netmask6 = vpninfo->ip_info.netmask6;
 
        /* First part of header, similar to ESP, has already been checked */
        if (len < 0x31 ||
@@ -2281,6 +2278,9 @@ static int handle_main_config_packet(struct openconnect_info *vpninfo,
        p = bytes + 0x34;
        routes_len -= 8; /* The header including length and number of routes */
 
+       struct oc_vpn_option *new_opts = NULL;
+       struct oc_ip_info new_ip_info = {};
+
        /* We know it's a multiple of 0x10 now. We checked. */
        while (routes_len) {
                char buf[80];
@@ -2310,7 +2310,7 @@ static int handle_main_config_packet(struct openconnect_info *vpninfo,
                        vpn_progress(vpninfo, PRG_DEBUG, _("Received split include route %s\n"), buf);
                        inc = malloc(sizeof(*inc));
                        if (inc) {
-                               inc->route = add_option_dup(vpninfo, "split-include", buf, -1);
+                               inc->route = add_option_dup(&new_opts, "split-include", buf, -1);
                                if (inc->route) {
                                        inc->next = vpninfo->ip_info.split_includes;
                                        vpninfo->ip_info.split_includes = inc;
@@ -2323,7 +2323,7 @@ static int handle_main_config_packet(struct openconnect_info *vpninfo,
                        vpn_progress(vpninfo, PRG_DEBUG, _("Received split exclude route %s\n"), buf);
                        exc = malloc(sizeof(*exc));
                        if (exc) {
-                               exc->route = add_option_dup(vpninfo, "split-exclude", buf, -1);
+                               exc->route = add_option_dup(&new_opts, "split-exclude", buf, -1);
                                if (exc->route) {
                                        exc->next = vpninfo->ip_info.split_excludes;
                                        vpninfo->ip_info.split_excludes = exc;
@@ -2358,14 +2358,19 @@ static int handle_main_config_packet(struct openconnect_info *vpninfo,
 
                p += 4;
                l -= 4;
-               process_attr(vpninfo, type, p, attrlen);
+               process_attr(vpninfo, &new_opts, &new_ip_info, type, p, attrlen);
                p += attrlen;
                l -= attrlen;
                if (l && l < 4)
                        goto bad_config;
        }
 
-       return check_address_sanity(vpninfo, old_addr, old_netmask, old_addr6, old_netmask6);
+       int ret = install_vpn_opts(vpninfo, new_opts, &new_ip_info);
+       if (ret) {
+               free_optlist(new_opts);
+               free_split_routes(&new_ip_info);
+       }
+       return ret;
 }
 
 /* Example ESP config packet:
index 17cda887d5f3325004694e0902f40464b730ed29..2ab66735351856997ccb2be4ca39638fd04a8ed5 100644 (file)
--- a/script.c
+++ b/script.c
@@ -336,13 +336,16 @@ void prepare_script_env(struct openconnect_info *vpninfo)
                        }
                }
        }
-       if (vpninfo->ip_info.addr6) {
+
+       if (vpninfo->ip_info.addr6)
                script_setenv(vpninfo, "INTERNAL_IP6_ADDRESS", vpninfo->ip_info.addr6, 0, 0);
+       if (vpninfo->ip_info.netmask6)
                script_setenv(vpninfo, "INTERNAL_IP6_NETMASK", vpninfo->ip_info.netmask6, 0, 0);
-       } else if (vpninfo->ip_info.netmask6) {
-               char *slash = strchr(vpninfo->ip_info.netmask6, '/');
-               script_setenv(vpninfo, "INTERNAL_IP6_NETMASK", vpninfo->ip_info.netmask6, 0, 0);
-               if (slash)
+       /* The 'netmask6' is actually the address *and* netmask. From which we
+        * obtain just the address on its own, if we don't have it separately */
+       if (vpninfo->ip_info.netmask6 && !vpninfo->ip_info.addr6) {
+               char *slash = strchr(vpninfo->ip_info.netmask6, '/');
+               if (slash)
                        script_setenv(vpninfo, "INTERNAL_IP6_ADDRESS", vpninfo->ip_info.netmask6,
                                     slash - vpninfo->ip_info.netmask6, 0);
        }
@@ -436,27 +439,27 @@ void prepare_script_env(struct openconnect_info *vpninfo)
        setenv_cstp_opts(vpninfo);
 }
 
-void free_split_routes(struct openconnect_info *vpninfo)
+void free_split_routes(struct oc_ip_info *ip_info)
 {
        struct oc_split_include *inc;
 
-       for (inc = vpninfo->ip_info.split_includes; inc; ) {
+       for (inc = ip_info->split_includes; inc; ) {
                struct oc_split_include *next = inc->next;
                free(inc);
                inc = next;
        }
-       for (inc = vpninfo->ip_info.split_excludes; inc; ) {
+       for (inc = ip_info->split_excludes; inc; ) {
                struct oc_split_include *next = inc->next;
                free(inc);
                inc = next;
        }
-       for (inc = vpninfo->ip_info.split_dns; inc; ) {
+       for (inc = ip_info->split_dns; inc; ) {
                struct oc_split_include *next = inc->next;
                free(inc);
                inc = next;
        }
-       vpninfo->ip_info.split_dns = vpninfo->ip_info.split_includes =
-               vpninfo->ip_info.split_excludes = NULL;
+       ip_info->split_dns = ip_info->split_includes =
+               ip_info->split_excludes = NULL;
 }