Consolidate the various add_option() functions
authorDavid Woodhouse <dwmw2@infradead.org>
Tue, 13 Apr 2021 12:14:01 +0000 (13:14 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Fri, 16 Apr 2021 15:06:36 +0000 (16:06 +0100)
We have duplicates of these littered all over the place. Make two simple
"strndup" vs. "steal" variants and put them in library.c.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
f5.c
fortinet.c
gpst.c
library.c
oncp.c
openconnect-internal.h
pulse.c

diff --git a/f5.c b/f5.c
index d7c0332af83410abf565779fb87d5743819f60bc..c294d51adefecebefd666d933fd043c645f63407 100644 (file)
--- a/f5.c
+++ b/f5.c
@@ -302,31 +302,6 @@ static int xmlnode_bool_or_int_value(struct openconnect_info *vpninfo, xmlNode *
        return ret;
 }
 
-/* We behave like CSTP — create a linked list in vpninfo->cstp_options
- * with the strings containing the information we got from the server,
- * and oc_ip_info contains const copies of those pointers.
- *
- * (unlike version in oncp.c, val is stolen rather than strdup'ed) */
-
-static const char *add_option(struct openconnect_info *vpninfo, const char *opt, char **val)
-{
-       struct oc_vpn_option *new = malloc(sizeof(*new));
-       if (!new)
-               return NULL;
-
-       new->option = strdup(opt);
-       if (!new->option) {
-               free(new);
-               return NULL;
-       }
-       new->value = *val;
-       *val = NULL;
-       new->next = vpninfo->cstp_options;
-       vpninfo->cstp_options = new;
-
-       return new->value;
-}
-
 static int parse_options(struct openconnect_info *vpninfo, char *buf, int len,
                         char **session_id, char **ur_z, int *ipv4, int *ipv6, int *hdlc)
 {
@@ -403,14 +378,14 @@ static int parse_options(struct openconnect_info *vpninfo, char *buf, int len,
                        if (s && *s) {
                                vpn_progress(vpninfo, PRG_INFO, _("Got IPv%d DNS server %s\n"),
                                             xml_node->name[4]=='_' ? 6 : 4, s);
-                               if (n_dns < 3) vpninfo->ip_info.dns[n_dns++] = add_option(vpninfo, "DNS", &s);
+                               if (n_dns < 3) vpninfo->ip_info.dns[n_dns++] = add_option_steal(vpninfo, "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(vpninfo, "WINS", &s);
+                               if (n_nbns < 3) vpninfo->ip_info.dns[n_nbns++] = add_option_steal(vpninfo, "WINS", &s);
                        }
                } else if (!strncmp((char *)xml_node->name, "DNSSuffix", 9) && isdigit(xml_node->name[9])) {
                        free(s);
@@ -427,7 +402,7 @@ static int parse_options(struct openconnect_info *vpninfo, char *buf, int len,
                                char *word, *next;
                                struct oc_split_include *inc;
 
-                               for (word = (char *)add_option(vpninfo, "route-list", &s);
+                               for (word = (char *)add_option_steal(vpninfo, "route-list", &s);
                                     *word; word = next) {
                                        for (next = word; *next && !isspace(*next); next++);
                                        if (*next)
@@ -452,7 +427,7 @@ static int parse_options(struct openconnect_info *vpninfo, char *buf, int len,
                vpninfo->ip_info.netmask6 = strdup("::/0");
        if (buf_error(domains) == 0 && domains->pos > 0) {
                domains->data[domains->pos-1] = '\0';
-               vpninfo->ip_info.domain = add_option(vpninfo, "search", &domains->data);
+               vpninfo->ip_info.domain = add_option_steal(vpninfo, "search", &domains->data);
        }
        buf_free(domains);
 
@@ -470,21 +445,19 @@ static int parse_options(struct openconnect_info *vpninfo, char *buf, int len,
 }
 
 static int get_ip_address(struct openconnect_info *vpninfo, char *header, char *val) {
-       char *s = strdup(val);
        if (!strcasecmp(header, "X-VPN-client-IP")) {
                vpn_progress(vpninfo, PRG_INFO,
                             _("Got legacy IP address %s\n"), val);
-               vpninfo->ip_info.addr = add_option(vpninfo, "ipaddr", &s);
+               vpninfo->ip_info.addr = add_option_dup(vpninfo, "ipaddr", val, -1);
        } else if (!strcasecmp(header, "X-VPN-client-IPv6")) {
                vpn_progress(vpninfo, PRG_INFO,
                             _("Got IPv6 address %s\n"), val);
                /* XX: Should we treat this as a /64 netmask? Or an /128 address? */
-               vpninfo->ip_info.addr6 = add_option(vpninfo, "ipaddr6", &s);
+               vpninfo->ip_info.addr6 = add_option_dup(vpninfo, "ipaddr6", val, -1);
        }
         /* XX: The server's IP address(es) X-VPN-server-{IP,IPv6} are also
          * sent, but the utility of these is unclear. As remarked in oncp.c,
         * "this is a tunnel; having a gateway is meaningless." */
-       free(s);
        return 0;
 }
 
index 9718230d332e1b6002d19b681d1d014b5f2bb051..c081e8855ef238a4998a3c60e51b126553641e8b 100644 (file)
@@ -249,31 +249,6 @@ int fortinet_obtain_cookie(struct openconnect_info *vpninfo)
        return ret;
 }
 
-/* We behave like CSTP — create a linked list in vpninfo->cstp_options
- * with the strings containing the information we got from the server,
- * and oc_ip_info contains const copies of those pointers.
- *
- * (unlike version in oncp.c, val is stolen rather than strdup'ed) */
-
-static const char *add_option(struct openconnect_info *vpninfo, const char *opt, char **val)
-{
-       struct oc_vpn_option *new = malloc(sizeof(*new));
-       if (!new)
-               return NULL;
-
-       new->option = strdup(opt);
-       if (!new->option) {
-               free(new);
-               return NULL;
-       }
-       new->value = *val;
-       *val = NULL;
-       new->next = vpninfo->cstp_options;
-       vpninfo->cstp_options = new;
-
-       return new->value;
-}
-
 /* Parse this:
 <?xml version="1.0" encoding="utf-8"?>
 <sslvpn-tunnel ver="2" dtls="1" patch="1">
@@ -364,7 +339,7 @@ static int parse_fortinet_xml_config(struct openconnect_info *vpninfo, char *buf
                        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(vpninfo, "ipaddr", &s);
+                                       vpninfo->ip_info.addr = add_option_steal(vpninfo, "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);
@@ -372,7 +347,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(vpninfo, "DNS", &s);
+                                               if (n_dns < 3) vpninfo->ip_info.dns[n_dns++] = add_option_steal(vpninfo, "DNS", &s);
                                        }
                                } else if (xmlnode_is_named(x, "split-dns")) {
                                        int ii;
@@ -403,10 +378,10 @@ static int parse_fortinet_xml_config(struct openconnect_info *vpninfo, char *buf
                                                                }
                                                                snprintf(route, 32, "%s/%s", s, s2);
                                                                vpn_progress(vpninfo, PRG_INFO, _("Got IPv%d route %s\n"), 4, route);
-                                                               inc->route = add_option(vpninfo, "split-include", &route);
+                                                               inc->route = add_option_steal(vpninfo, "split-include", &route);
                                                                inc->next = vpninfo->ip_info.split_includes;
                                                                vpninfo->ip_info.split_includes = inc;
-                                                               /* XX: static analyzer doesn't realize that add_option will steal route's reference, so... */
+                                                               /* XX: static analyzer doesn't realize that add_option_steal will steal route's reference, so... */
                                                                free(route);
                                                        }
                                                }
@@ -422,7 +397,7 @@ static int parse_fortinet_xml_config(struct openconnect_info *vpninfo, char *buf
                vpninfo->ip_info.netmask6 = strdup("::/0");
        if (buf_error(domains) == 0 && domains->pos > 0) {
                domains->data[domains->pos-1] = '\0';
-               vpninfo->ip_info.domain = add_option(vpninfo, "search", &domains->data);
+               vpninfo->ip_info.domain = add_option_steal(vpninfo, "search", &domains->data);
        }
        buf_free(domains);
 
diff --git a/gpst.c b/gpst.c
index 64b24c0406017349140ec2e550ea7217bc9a6088..08e9a0d5a7e90feebfeffc925583c5c650a0cf65 100644 (file)
--- a/gpst.c
+++ b/gpst.c
@@ -74,31 +74,6 @@ static const struct pkt dpd_pkt = {
        { .gpst.hdr = { 0x1a, 0x2b, 0x3c, 0x4d } }
 };
 
-/* We behave like CSTP — create a linked list in vpninfo->cstp_options
- * with the strings containing the information we got from the server,
- * and oc_ip_info contains const copies of those pointers.
- *
- * (unlike version in oncp.c, val is stolen rather than strdup'ed) */
-
-static const char *add_option(struct openconnect_info *vpninfo, const char *opt, char **val)
-{
-       struct oc_vpn_option *new = malloc(sizeof(*new));
-       if (!new)
-               return NULL;
-
-       new->option = strdup(opt);
-       if (!new->option) {
-               free(new);
-               return NULL;
-       }
-       new->value = *val;
-       *val = NULL;
-       new->next = vpninfo->cstp_options;
-       vpninfo->cstp_options = new;
-
-       return new->value;
-}
-
 static int filter_opts(struct oc_text_buf *buf, const char *query, const char *incexc, int include)
 {
        const char *f, *endf, *eq;
@@ -395,7 +370,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
        /* 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(vpninfo, "ipaddr", &s);
+                       vpninfo->ip_info.addr = add_option_steal(vpninfo, "ipaddr", &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)
@@ -448,13 +423,13 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
                                                if (!strcmp(s, vpninfo->ip_info.dns[ii]))
                                                        break;
                                        if (ii==n_dns)
-                                               vpninfo->ip_info.dns[n_dns++] = add_option(vpninfo, "DNS", &s);
+                                               vpninfo->ip_info.dns[n_dns++] = add_option_steal(vpninfo, "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(vpninfo, "WINS", &s);
+                                       vpninfo->ip_info.nbns[ii++] = add_option_steal(vpninfo, "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)
@@ -462,7 +437,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(vpninfo, "search", &domains->data);
+                               vpninfo->ip_info.domain = add_option_steal(vpninfo, "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")) {
@@ -485,11 +460,11 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
                                        if ((inc = malloc(sizeof(*inc))) == NULL)
                                                return -ENOMEM;
                                        if (is_inc) {
-                                               inc->route = add_option(vpninfo, "split-include", &s);
+                                               inc->route = add_option_steal(vpninfo, "split-include", &s);
                                                inc->next = vpninfo->ip_info.split_includes;
                                                vpninfo->ip_info.split_includes = inc;
                                        } else {
-                                               inc->route = add_option(vpninfo, "split-exclude", &s);
+                                               inc->route = add_option_steal(vpninfo, "split-exclude", &s);
                                                inc->next = vpninfo->ip_info.split_excludes;
                                                vpninfo->ip_info.split_excludes = inc;
                                        }
@@ -569,7 +544,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
                                if ((inc = malloc(sizeof(*inc))) == NULL ||
                                    asprintf(&s, "%s/%s", inet_ntoa(net_addr), original_netmask) <= 0)
                                        return -ENOMEM;
-                               inc->route = add_option(vpninfo, "split-include", &s);
+                               inc->route = add_option_steal(vpninfo, "split-include", &s);
                                inc->next = vpninfo->ip_info.split_includes;
                                vpninfo->ip_info.split_includes = inc;
                        }
@@ -577,7 +552,7 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
                free(original_netmask);
        }
        if (deferred_netmask)
-               vpninfo->ip_info.netmask = add_option(vpninfo, "netmask", &deferred_netmask);
+               vpninfo->ip_info.netmask = add_option_steal(vpninfo, "netmask", &deferred_netmask);
 
        /* Set 10-second DPD/keepalive (same as Windows client) unless
         * overridden with --force-dpd */
index e7cf199120aada7a05764ff4d2e76f33d9508555..2d1c58c48c16e81821fad483159909a0317b001e 100644 (file)
--- a/library.c
+++ b/library.c
@@ -389,6 +389,42 @@ 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 *val, int val_len)
+{
+       const char *ret;
+       char *new_val;
+
+       if (val_len >= 0)
+               new_val = strndup(val, val_len);
+       else
+               new_val = strdup(val);
+
+       ret = add_option_steal(vpninfo, opt, &new_val);
+       free(new_val);
+       return ret;
+}
+
+const char *add_option_steal(struct openconnect_info *vpninfo, const char *opt, char **val)
+{
+       struct oc_vpn_option *new = malloc(sizeof(*new));
+       if (!new)
+               return NULL;
+
+       new->option = strdup(opt);
+       if (!new->option) {
+               free(new);
+               return NULL;
+       }
+       new->value = *val;
+       *val = NULL;
+       new->next = vpninfo->cstp_options;
+       vpninfo->cstp_options = new;
+
+       return new->value;
+}
+
+
 void free_optlist(struct oc_vpn_option *opt)
 {
        struct oc_vpn_option *next;
diff --git a/oncp.c b/oncp.c
index 32798fa5aa5b4216459e3d58b370bdedf5e3e01f..759327d2c49cce22340e00bfbeb63d81b83993ee 100644 (file)
--- a/oncp.c
+++ b/oncp.c
@@ -61,37 +61,6 @@ static const char authpkt_tail[] = { 0xbb, 0x01, 0x00, 0x00, 0x00, 0x00 };
 
 #define GRP_ATTR(g, a) (((g) << 16) | (a))
 
-/* We behave like CSTP — create a linked list in vpninfo->cstp_options
- * with the strings containing the information we got from the server,
- * and oc_ip_info contains const copies of those pointers. */
-
-static const char *add_option(struct openconnect_info *vpninfo, const char *opt,
-                             const char *val, int val_len)
-{
-       struct oc_vpn_option *new = malloc(sizeof(*new));
-       if (!new)
-               return NULL;
-
-       new->option = strdup(opt);
-       if (!new->option) {
-               free(new);
-               return NULL;
-       }
-       if (val_len >= 0)
-               new->value = strndup(val, val_len);
-       else
-               new->value = strdup(val);
-       if (!new->value) {
-               free(new->option);
-               free(new);
-               return NULL;
-       }
-       new->next = vpninfo->cstp_options;
-       vpninfo->cstp_options = new;
-
-       return new->value;
-}
-
 static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                        unsigned char *data, int attrlen)
 {
@@ -122,7 +91,7 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
 
                for (i = 0; i < 3; i++) {
                        if (!vpninfo->ip_info.dns[i]) {
-                               vpninfo->ip_info.dns[i] = add_option(vpninfo, "DNS", buf, -1);
+                               vpninfo->ip_info.dns[i] = add_option_dup(vpninfo, "DNS", buf, -1);
                                break;
                        }
                }
@@ -131,7 +100,7 @@ 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(vpninfo, "search", (char *)data, attrlen);
+               vpninfo->ip_info.domain = add_option_dup(vpninfo, "search", (char *)data, attrlen);
                if (vpninfo->ip_info.domain) {
                        char *p = (char *)vpninfo->ip_info.domain;
                        while ((p = strchr(p, ',')))
@@ -145,7 +114,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(vpninfo, "ipaddr", buf, -1);
+               vpninfo->ip_info.addr = add_option_dup(vpninfo, "ipaddr", buf, -1);
                break;
 
        case GRP_ATTR(1, 2):
@@ -154,7 +123,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(vpninfo, "netmask", buf, -1);
+               vpninfo->ip_info.netmask = add_option_dup(vpninfo, "netmask", buf, -1);
                break;
 
        case GRP_ATTR(1, 3):
@@ -165,7 +134,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(vpninfo, "ipaddr", buf, -1);
+               add_option_dup(vpninfo, "ipaddr", buf, -1);
                break;
 
        case GRP_ATTR(3, 3): {
@@ -180,7 +149,7 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                        break;
                inc = malloc(sizeof(*inc));
                if (inc) {
-                       inc->route = add_option(vpninfo, "split-include", buf, -1);
+                       inc->route = add_option_dup(vpninfo, "split-include", buf, -1);
                        if (inc->route) {
                                inc->next = vpninfo->ip_info.split_includes;
                                vpninfo->ip_info.split_includes = inc;
@@ -202,7 +171,7 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
                        break;
                exc = malloc(sizeof(*exc));
                if (exc) {
-                       exc->route = add_option(vpninfo, "split-exclude", buf, -1);
+                       exc->route = add_option_dup(vpninfo, "split-exclude", buf, -1);
                        if (exc->route) {
                                exc->next = vpninfo->ip_info.split_excludes;
                                vpninfo->ip_info.split_excludes = exc;
@@ -221,7 +190,7 @@ static int process_attr(struct openconnect_info *vpninfo, int group, int attr,
 
                for (i = 0; i < 3; i++) {
                        if (!vpninfo->ip_info.nbns[i]) {
-                               vpninfo->ip_info.nbns[i] = add_option(vpninfo, "WINS", buf, -1);
+                               vpninfo->ip_info.nbns[i] = add_option_dup(vpninfo, "WINS", buf, -1);
                                break;
                        }
                }
index e3a8a758be1e5d74e7b32bb2701669f2b5243425..3ee725f2d0008a99a2a27178cfcc22d78f1eeec0 100644 (file)
@@ -1280,6 +1280,8 @@ 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);
 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 */
diff --git a/pulse.c b/pulse.c
index c07b21b5e7962fca6690e5e3a5fef16b598012a9..4181896cf86abd34c55c2d3d6ee2b10ba451afe2 100644 (file)
--- a/pulse.c
+++ b/pulse.c
@@ -217,37 +217,6 @@ static int valid_ift_auth_eap_exj1(unsigned char *bytes, int len)
        return 1;
 }
 
-/* We behave like CSTP — create a linked list in vpninfo->cstp_options
- * with the strings containing the information we got from the server,
- * and oc_ip_info contains const copies of those pointers. */
-
-static const char *add_option(struct openconnect_info *vpninfo, const char *opt,
-                             const char *val, int val_len)
-{
-       struct oc_vpn_option *new = malloc(sizeof(*new));
-       if (!new)
-               return NULL;
-
-       new->option = strdup(opt);
-       if (!new->option) {
-               free(new);
-               return NULL;
-       }
-       if (val_len >= 0)
-               new->value = strndup(val, val_len);
-       else
-               new->value = strdup(val);
-       if (!new->value) {
-               free(new->option);
-               free(new);
-               return NULL;
-       }
-       new->next = vpninfo->cstp_options;
-       vpninfo->cstp_options = new;
-
-       return new->value;
-}
-
 static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
                        unsigned char *data, int attrlen)
 {
@@ -263,7 +232,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(vpninfo, "ipaddr", buf, -1);
+               vpninfo->ip_info.addr = add_option_dup(vpninfo, "ipaddr", buf, -1);
                break;
 
        case 0x0002:
@@ -272,7 +241,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(vpninfo, "netmask", buf, -1);
+               vpninfo->ip_info.netmask = add_option_dup(vpninfo, "netmask", buf, -1);
                break;
 
        case 0x0003:
@@ -284,7 +253,7 @@ 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(vpninfo, "DNS", buf, -1);
+                               vpninfo->ip_info.dns[i] = add_option_dup(vpninfo, "DNS", buf, -1);
                                break;
                        }
                }
@@ -299,7 +268,7 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
 
                for (i = 0; i < 3; i++) {
                        if (!vpninfo->ip_info.nbns[i]) {
-                               vpninfo->ip_info.nbns[i] = add_option(vpninfo, "WINS", buf, -1);
+                               vpninfo->ip_info.nbns[i] = add_option_dup(vpninfo, "WINS", buf, -1);
                                break;
                        }
                }
@@ -313,11 +282,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(vpninfo, "ip6addr", buf, -1);
+               vpninfo->ip_info.addr6 = add_option_dup(vpninfo, "ip6addr", buf, -1);
 
                i = strlen(buf);
                snprintf(buf + i, sizeof(buf) - i, "/%d", data[16]);
-               vpninfo->ip_info.netmask6 = add_option(vpninfo, "ip6netmask", buf, -1);
+               vpninfo->ip_info.netmask6 = add_option_dup(vpninfo, "ip6netmask", buf, -1);
 
                vpn_progress(vpninfo, PRG_DEBUG, _("Received internal IPv6 address %s\n"), buf);
                break;
@@ -333,7 +302,7 @@ 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(vpninfo, "DNS", buf, -1);
+                               vpninfo->ip_info.dns[i] = add_option_dup(vpninfo, "DNS", buf, -1);
                                break;
                        }
                }
@@ -354,7 +323,7 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
 
                xc = malloc(sizeof(*xc));
                if (xc) {
-                       xc->route =  add_option(vpninfo, "split-include6", buf, -1);
+                       xc->route =  add_option_dup(vpninfo, "split-include6", buf, -1);
                        if (xc->route) {
                                xc->next = vpninfo->ip_info.split_includes;
                                vpninfo->ip_info.split_includes = xc;
@@ -377,7 +346,7 @@ static int process_attr(struct openconnect_info *vpninfo, uint16_t type,
 
                xc = malloc(sizeof(*xc));
                if (xc) {
-                       xc->route =  add_option(vpninfo, "split-exclude6", buf, -1);
+                       xc->route =  add_option_dup(vpninfo, "split-exclude6", buf, -1);
                        if (xc->route) {
                                xc->next = vpninfo->ip_info.split_excludes;
                                vpninfo->ip_info.split_excludes = xc;
@@ -408,7 +377,7 @@ 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(vpninfo, "search", (char *)data, attrlen);
+               vpninfo->ip_info.domain = add_option_dup(vpninfo, "search", (char *)data, attrlen);
                if (vpninfo->ip_info.domain) {
                        char *p = (char *)vpninfo->ip_info.domain;
                        while ((p = strchr(p, ',')))
@@ -424,7 +393,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(vpninfo, "ipaddr", buf, -1);
+               add_option_dup(vpninfo, "ipaddr", buf, -1);
                break;
 
        case 0x4010: {
@@ -2334,7 +2303,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(vpninfo, "split-include", buf, -1);
+                               inc->route = add_option_dup(vpninfo, "split-include", buf, -1);
                                if (inc->route) {
                                        inc->next = vpninfo->ip_info.split_includes;
                                        vpninfo->ip_info.split_includes = inc;
@@ -2347,7 +2316,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(vpninfo, "split-exclude", buf, -1);
+                               exc->route = add_option_dup(vpninfo, "split-exclude", buf, -1);
                                if (exc->route) {
                                        exc->next = vpninfo->ip_info.split_excludes;
                                        vpninfo->ip_info.split_excludes = exc;