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
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;
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;
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)
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);
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. */
_("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;
_("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;
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 */
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);
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);
{
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;
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();
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);
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);
}
}
}
}
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"));
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 */
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).
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);
<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;
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();
_("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);
}
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;
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);
}
}
}
- 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,
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:
} 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();
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:
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"))
* 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
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)
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") ||
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;
}
}
}
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 */
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
#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)
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");
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;
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;
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)
}
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);
}
}
}
+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);
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);
#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;
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):
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;
}
}
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 = ' ';
}
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):
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):
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): {
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);
}
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);
}
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;
}
}
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;
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;
}
vpn_progress(vpninfo, PRG_ERR,
_("Received non-ESP TLVs (group %d) in ESP negotiation KMP\n"),
group);
- return -EINVAL;
+ goto einval;
}
while (ofs < groupend) {
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;
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;
}
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 */
}
goto out;
}
-
- ret = check_address_sanity(vpninfo, old_addr, old_netmask, NULL, NULL);
+ ret = 0;
out:
if (ret)
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);
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);
/* 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 */
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;
/* 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;
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;
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:
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:
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;
}
}
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;
}
}
_("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;
}
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;
}
}
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);
}
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);
}
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:
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 = ' ';
}
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: {
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 ||
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];
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;
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;
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:
}
}
}
- 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);
}
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;
}