[PATCH 6/9] hs20: Bind curl, including dns, to wlan interface.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Ben Greear <greearb@xxxxxxxxxxxxxxx>

This lets things work better on multi-homed networks.

Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
---
 hs20/client/est.c           |  15 ++++--
 hs20/client/oma_dm_client.c |   7 ++-
 hs20/client/osu_client.c    |  43 +++++++++++++--
 hs20/client/osu_client.h    |   4 ++
 hs20/client/spp_client.c    |  18 +++++--
 src/utils/http-utils.h      |  12 +++--
 src/utils/http_curl.c       | 103 ++++++++++++++++++++++++++++++++----
 7 files changed, 179 insertions(+), 23 deletions(-)

diff --git a/hs20/client/est.c b/hs20/client/est.c
index 97f913210..f93a15696 100644
--- a/hs20/client/est.c
+++ b/hs20/client/est.c
@@ -137,7 +137,10 @@ int est_load_cacerts(struct hs20_osu_client *ctx, const char *url)
 	ctx->no_osu_cert_validation = 1;
 	http_ocsp_set(ctx->http, 1);
 	res = http_download_file(ctx->http, buf, "Cert/est-cacerts.txt",
-				 ctx->ca_fname);
+				 ctx->ca_fname,
+				 ctx->do_bind_iface ? ctx->ifname : NULL,
+				 ctx->dns);
+
 	http_ocsp_set(ctx->http,
 		      (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
 	ctx->no_osu_cert_validation = 0;
@@ -619,7 +622,10 @@ int est_build_csr(struct hs20_osu_client *ctx, const char *url)
 	ctx->no_osu_cert_validation = 1;
 	http_ocsp_set(ctx->http, 1);
 	res = http_download_file(ctx->http, buf, "Cert/est-csrattrs.txt",
-				 ctx->ca_fname);
+				 ctx->ca_fname,
+				 ctx->do_bind_iface ? ctx->ifname : NULL,
+				 ctx->dns);
+
 	http_ocsp_set(ctx->http,
 		      (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
 	ctx->no_osu_cert_validation = 0;
@@ -721,7 +727,10 @@ int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
 	resp = http_post(ctx->http, buf, req, "application/pkcs10",
 			 "Content-Transfer-Encoding: base64",
 			 ctx->ca_fname, user, pw, client_cert, client_key,
-			 &resp_len);
+			 &resp_len,
+			 ctx->do_bind_iface ? ctx->ifname : NULL,
+			 ctx->dns);
+
 	http_ocsp_set(ctx->http,
 		      (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
 	ctx->no_osu_cert_validation = 0;
diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c
index d75c84562..78b46341a 100644
--- a/hs20/client/oma_dm_client.c
+++ b/hs20/client/oma_dm_client.c
@@ -957,7 +957,10 @@ static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx,
 	ctx->server_url = os_strdup(url);
 	res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml",
 			ext_hdr, ctx->ca_fname, username, password,
-			client_cert, client_key, NULL);
+			client_cert, client_key, NULL,
+			ctx->do_bind_iface ? ctx->ifname : NULL,
+			ctx->dns);
+
 	os_free(str);
 	os_free(resp_uri);
 	resp_uri = NULL;
@@ -1210,6 +1213,8 @@ int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url)
 	}
 	write_summary(ctx, "OMA-DM SIM provisioning");
 
+	check_dns_file(ctx);
+
 	msgid++;
 	syncml = build_oma_dm_1_sub_prov(ctx, url, msgid);
 	if (syncml == NULL)
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 9f9c307b6..ff6e5b1c0 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -339,7 +339,10 @@ static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params,
 	write_summary(ctx, "Download certificate from %s", url);
 	ctx->no_osu_cert_validation = 1;
 	http_ocsp_set(ctx->http, 1);
-	res = http_download_file(ctx->http, url, TMP_CERT_DL_FILE, NULL);
+	res = http_download_file(ctx->http, url, TMP_CERT_DL_FILE, NULL,
+				 ctx->do_bind_iface ? ctx->ifname : NULL,
+				 ctx->dns);
+
 	http_ocsp_set(ctx->http,
 		      (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
 	ctx->no_osu_cert_validation = 0;
@@ -2151,6 +2154,33 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
 	return osu;
 }
 
+void check_dns_file(struct hs20_osu_client* ctx)
+{
+	/* Look for DNS servers in case user specified a place to look. */
+	if (ctx->dns_file) {
+		FILE *f;
+		char buf[100];
+
+		f = fopen(ctx->dns_file, "r");
+		if (f) {
+			if (fgets(buf, sizeof(buf), f)) {
+				wpa_printf(MSG_DEBUG, "Checking DNS file: %s contents: %s",
+					   ctx->dns_file, buf);
+				if (strncmp(buf, "DNS:", 4) == 0) {
+					/* remove ending whitespace */
+					int len = strlen(buf);
+					if ((buf[len - 2] == '\n') || (buf[len - 2] == '\r'))
+						buf[len - 2] = 0;
+					else if ((buf[len - 1] == '\n') || (buf[len - 1] == '\r'))
+						buf[len - 1] = 0;
+					http_bind_dns(ctx->http, NULL, buf + 4);
+					ctx->dns = strdup(buf + 4);
+				}
+			}
+			fclose(f);
+		}
+	}
+}
 
 static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
 		       const char *ssid, const char *ssid2, const char *url,
@@ -2255,6 +2285,8 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
 		wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
 	}
 
+	check_dns_file(ctx);
+
 	if (no_prod_assoc) {
 		if (res < 0)
 			return -1;
@@ -2698,6 +2730,7 @@ static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
 	if (wait_ip_addr(ctx->ifname, 15) < 0) {
 		wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
 	}
+	check_dns_file(ctx);
 
 	if (spp)
 		spp_sub_rem(ctx, address, pps_fname,
@@ -3162,7 +3195,7 @@ static void check_workarounds(struct hs20_osu_client *ctx)
 static void usage(void)
 {
 	printf("usage: hs20-osu-client [-dddqqKt] [-S<station ifname>] \\\n"
-	       "    [-w<wpa_supplicant ctrl_iface dir>] "
+	       "    [-w<wpa_supplicant ctrl_iface dir>] [-D<dns-file-name>] "
 	       "[-r<result file>] [-f<debug file>] \\\n"
 	       "    [-s<summary file>] \\\n"
 	       "    [-x<spp.xsd file name>] \\\n"
@@ -3207,7 +3240,7 @@ int main(int argc, char *argv[])
 		return -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
+		c = getopt(argc, argv, "dD:f:hKNo:O:qr:s:S:tw:x:");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -3215,6 +3248,9 @@ int main(int argc, char *argv[])
 			if (wpa_debug_level > 0)
 				wpa_debug_level--;
 			break;
+		case 'D':
+			ctx.dns_file = optarg;
+			break;
 		case 'f':
 			wpa_debug_file_path = optarg;
 			break;
@@ -3241,6 +3277,7 @@ int main(int argc, char *argv[])
 			break;
 		case 'S':
 			ctx.ifname = optarg;
+			ctx.do_bind_iface = 1;
 			break;
 		case 't':
 			wpa_debug_timestamp++;
diff --git a/hs20/client/osu_client.h b/hs20/client/osu_client.h
index 5c8e6d00b..9b1082278 100644
--- a/hs20/client/osu_client.h
+++ b/hs20/client/osu_client.h
@@ -34,6 +34,9 @@ struct hs20_osu_client {
 	const char *summary_file;
 	const char *ifname;
 	const char *ca_fname;
+	const char *dns_file;
+	const char* dns;
+	int do_bind_iface;
 	int no_osu_cert_validation; /* for EST operations */
 	char *fqdn;
 	char *server_url;
@@ -71,6 +74,7 @@ int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname,
 		    xml_node_t *pps);
 void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname);
 
+void check_dns_file(struct hs20_osu_client* ctx);
 
 /* spp_client.c */
 
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
index c619541ae..4144189b0 100644
--- a/hs20/client/spp_client.c
+++ b/hs20/client/spp_client.c
@@ -796,7 +796,9 @@ void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
 
 	if (soap_init_client(ctx->http, address, ctx->ca_fname,
 			     cred_username, cred_password, client_cert,
-			     client_key) == 0) {
+			     client_key,
+			     ctx->do_bind_iface ? ctx->ifname : NULL,
+			     ctx->dns) == 0) {
 		spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION,
 				  "Subscription remediation", pps_fname, pps);
 	}
@@ -942,7 +944,9 @@ void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
 	ctx->server_url = os_strdup(address);
 
 	if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username,
-			     cred_password, client_cert, client_key) == 0) {
+			     cred_password, client_cert, client_key,
+			     ctx->do_bind_iface ? ctx->ifname : NULL,
+			     ctx->dns) == 0) {
 		spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update",
 				  pps_fname, pps);
 	}
@@ -967,7 +971,9 @@ int cmd_prov(struct hs20_osu_client *ctx, const char *url)
 	ctx->server_url = os_strdup(url);
 
 	if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
-			     NULL) < 0)
+			     NULL,
+			     ctx->do_bind_iface ? ctx->ifname : NULL,
+			     ctx->dns) < 0)
 		return -1;
 	spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
 			  "Subscription registration", NULL, NULL);
@@ -994,8 +1000,12 @@ int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url)
 		wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
 	}
 
+	check_dns_file(ctx);
+
 	if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
-			     NULL) < 0)
+			     NULL,
+			     ctx->do_bind_iface ? ctx->ifname : NULL,
+			     ctx->dns) < 0)
 		return -1;
 	spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
 			  "Subscription provisioning", NULL, NULL);
diff --git a/src/utils/http-utils.h b/src/utils/http-utils.h
index 8d4399a37..277ac3485 100644
--- a/src/utils/http-utils.h
+++ b/src/utils/http-utils.h
@@ -38,22 +38,28 @@ struct http_cert {
 int soap_init_client(struct http_ctx *ctx, const char *address,
 		     const char *ca_fname, const char *username,
 		     const char *password, const char *client_cert,
-		     const char *client_key);
+		     const char *client_key, const char* ifname, const char* dns);
 int soap_reinit_client(struct http_ctx *ctx);
 xml_node_t * soap_send_receive(struct http_ctx *ctx, xml_node_t *node);
 
+/* Bind curl to an interface. */
+int http_bind_iface(struct http_ctx *ctx, void* curl, const char* ifname);
+/* Tell curl's resolver (in case it is using one) to use a specific DNS server. */
+int http_bind_dns(struct http_ctx *ctx, void* curl, const char* dns);
+
 struct http_ctx * http_init_ctx(void *upper_ctx, struct xml_node_ctx *xml_ctx);
 void http_ocsp_set(struct http_ctx *ctx, int val);
 void http_deinit_ctx(struct http_ctx *ctx);
 
 int http_download_file(struct http_ctx *ctx, const char *url,
-		       const char *fname, const char *ca_fname);
+		       const char *fname, const char *ca_fname,
+		       const char* ifname, const char* dns);
 char * http_post(struct http_ctx *ctx, const char *url, const char *data,
 		 const char *content_type, const char *ext_hdr,
 		 const char *ca_fname,
 		 const char *username, const char *password,
 		 const char *client_cert, const char *client_key,
-		 size_t *resp_len);
+		 size_t *resp_len, const char* ifname, const char* dns);
 void http_set_cert_cb(struct http_ctx *ctx,
 		      int (*cb)(void *ctx, struct http_cert *cert),
 		      void *cb_ctx);
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index e62fbf96b..967eace09 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -50,8 +50,11 @@ struct http_ctx {
 	char *svc_password;
 	char *svc_client_cert;
 	char *svc_client_key;
+	char *ifname;
+	char *dns;
 	char *curl_buf;
 	size_t curl_buf_len;
+	char curl_err_buffer[CURL_ERROR_SIZE + 1];
 
 	int (*cert_cb)(void *ctx, struct http_cert *cert);
 	void *cert_cb_ctx;
@@ -1348,7 +1351,7 @@ static CURLcode curl_cb_ssl(CURL *curl, void *sslctx, void *parm)
 static CURL * setup_curl_post(struct http_ctx *ctx, const char *address,
 			      const char *ca_fname, const char *username,
 			      const char *password, const char *client_cert,
-			      const char *client_key)
+			      const char *client_key, const char* ifname, const char* dns)
 {
 	CURL *curl;
 #ifdef EAP_TLS_OPENSSL
@@ -1364,6 +1367,15 @@ static CURL * setup_curl_post(struct http_ctx *ctx, const char *address,
 	if (curl == NULL)
 		return NULL;
 
+	ctx->curl_err_buffer[0] = 0;
+	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, ctx->curl_err_buffer);
+
+	if (ifname)
+		http_bind_iface(ctx, curl, ifname);
+
+	if (dns)
+		http_bind_dns(ctx, curl, dns);
+
 	curl_easy_setopt(curl, CURLOPT_URL, address);
 	curl_easy_setopt(curl, CURLOPT_POST, 1L);
 	if (ca_fname) {
@@ -1398,6 +1410,7 @@ static CURL * setup_curl_post(struct http_ctx *ctx, const char *address,
 	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_cb_write);
 	curl_easy_setopt(curl, CURLOPT_WRITEDATA, ctx);
 	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
 	if (username) {
 		curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
 		curl_easy_setopt(curl, CURLOPT_USERNAME, username);
@@ -1407,11 +1420,67 @@ static CURL * setup_curl_post(struct http_ctx *ctx, const char *address,
 	return curl;
 }
 
+int http_bind_iface(struct http_ctx *ctx, void* _curl, const char* ifname)
+{
+	int rv;
+	CURL* curl = _curl;
+
+	if (!curl)
+		curl = ctx->curl;
+
+	if (ctx->ifname)
+		os_free(ctx->ifname);
+	ctx->ifname = NULL;
+	clone_str(&ctx->ifname, ifname);
+
+	/* Bind DNS resolver to the local interface, if curl is using such. */
+	rv = curl_easy_setopt(curl, CURLOPT_DNS_INTERFACE, ifname);
+	if (rv != CURLE_OK) {
+		wpa_printf(MSG_ERROR, "Failed CURLOPT_DNS_INTERFACE, curl: %p ifname: %s  error: %s rv: %d (%s)\n",
+			   curl, ifname, ctx->curl_err_buffer, rv, curl_easy_strerror(rv));
+	}
+	else {
+		wpa_printf(MSG_DEBUG, "Bound curl DNS to interface: %s\n", ifname);
+	}
+	rv = curl_easy_setopt(curl, CURLOPT_INTERFACE, ifname);
+	if (rv != CURLE_OK) {
+		wpa_printf(MSG_ERROR, "Failed CURLOPT_INTERFACE, curl: %p ifname: %s  error: %s, rv: %d(%s)\n",
+			   curl, ifname, ctx->curl_err_buffer, rv, curl_easy_strerror(rv));
+	}
+	else {
+		wpa_printf(MSG_DEBUG, "Bound curl to interface: %s\n", ifname);
+	}
+	return rv;
+}
+
+int http_bind_dns(struct http_ctx *ctx, void* _curl, const char* dns)
+{
+	CURL* curl = _curl;
+	int rv;
+
+	if (!curl)
+		curl = ctx->curl;
+
+	if (ctx->dns)
+		os_free(ctx->dns);
+	ctx->dns = NULL;
+	clone_str(&ctx->dns, dns);
+
+	rv = curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, dns);
+	if (rv != CURLE_OK) {
+		wpa_printf(MSG_ERROR, "Failed CURLOPT_DNS_SERVERS, curl: %p dns: %s  error: %s rv: %d(%s)\n",
+			   curl, dns, ctx->curl_err_buffer, rv, curl_easy_strerror(rv));
+	}
+	else {
+		wpa_printf(MSG_DEBUG, "Bound curl DNS servers: %s\n", dns);
+	}
+	return rv;
+}
 
 static int post_init_client(struct http_ctx *ctx, const char *address,
 			    const char *ca_fname, const char *username,
 			    const char *password, const char *client_cert,
-			    const char *client_key)
+			    const char *client_key, const char* ifname, const char* dns)
 {
 	char *pos;
 	int count;
@@ -1422,6 +1491,8 @@ static int post_init_client(struct http_ctx *ctx, const char *address,
 	clone_str(&ctx->svc_password, password);
 	clone_str(&ctx->svc_client_cert, client_cert);
 	clone_str(&ctx->svc_client_key, client_key);
+	clone_str(&ctx->ifname, ifname);
+	clone_str(&ctx->dns, dns);
 
 	/*
 	 * Workaround for Apache "Hostname 'FOO' provided via SNI and hostname
@@ -1435,7 +1506,7 @@ static int post_init_client(struct http_ctx *ctx, const char *address,
 	}
 
 	ctx->curl = setup_curl_post(ctx, ctx->svc_address, ca_fname, username,
-				    password, client_cert, client_key);
+				    password, client_cert, client_key, ifname, dns);
 	if (ctx->curl == NULL)
 		return -1;
 
@@ -1446,10 +1517,10 @@ static int post_init_client(struct http_ctx *ctx, const char *address,
 int soap_init_client(struct http_ctx *ctx, const char *address,
 		     const char *ca_fname, const char *username,
 		     const char *password, const char *client_cert,
-		     const char *client_key)
+		     const char *client_key, const char* ifname, const char* dns)
 {
 	if (post_init_client(ctx, address, ca_fname, username, password,
-			     client_cert, client_key) < 0)
+			     client_cert, client_key, ifname, dns) < 0)
 		return -1;
 
 	ctx->curl_hdr = curl_slist_append(ctx->curl_hdr,
@@ -1470,6 +1541,8 @@ int soap_reinit_client(struct http_ctx *ctx)
 	char *password = NULL;
 	char *client_cert = NULL;
 	char *client_key = NULL;
+	char *ifname = NULL;
+	char *dns = NULL;
 	int ret;
 
 	clear_curl(ctx);
@@ -1480,9 +1553,11 @@ int soap_reinit_client(struct http_ctx *ctx)
 	clone_str(&password, ctx->svc_password);
 	clone_str(&client_cert, ctx->svc_client_cert);
 	clone_str(&client_key, ctx->svc_client_key);
+	clone_str(&ifname, ctx->ifname);
+	clone_str(&dns, ctx->dns);
 
 	ret = soap_init_client(ctx, address, ca_fname, username, password,
-			       client_cert, client_key);
+			       client_cert, client_key, ifname, dns);
 	os_free(address);
 	os_free(ca_fname);
 	str_clear_free(username);
@@ -1614,7 +1689,8 @@ void http_deinit_ctx(struct http_ctx *ctx)
 
 
 int http_download_file(struct http_ctx *ctx, const char *url,
-		       const char *fname, const char *ca_fname)
+		       const char *fname, const char *ca_fname,
+		       const char* ifname, const char* dns)
 {
 	CURL *curl;
 	FILE *f;
@@ -1629,6 +1705,15 @@ int http_download_file(struct http_ctx *ctx, const char *url,
 	if (curl == NULL)
 		return -1;
 
+	ctx->curl_err_buffer[0] = 0;
+	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, ctx->curl_err_buffer);
+
+	if (ifname)
+		http_bind_iface(ctx, curl, ifname);
+
+	if (dns)
+		http_bind_dns(ctx, curl, dns);
+
 	f = fopen(fname, "wb");
 	if (f == NULL) {
 		curl_easy_cleanup(curl);
@@ -1682,7 +1767,7 @@ char * http_post(struct http_ctx *ctx, const char *url, const char *data,
 		 const char *ca_fname,
 		 const char *username, const char *password,
 		 const char *client_cert, const char *client_key,
-		 size_t *resp_len)
+		 size_t *resp_len, const char* ifname, const char* dns)
 {
 	long http = 0;
 	CURLcode res;
@@ -1693,7 +1778,7 @@ char * http_post(struct http_ctx *ctx, const char *url, const char *data,
 	ctx->last_err = NULL;
 	wpa_printf(MSG_DEBUG, "curl: HTTP POST to %s", url);
 	curl = setup_curl_post(ctx, url, ca_fname, username, password,
-			       client_cert, client_key);
+			       client_cert, client_key, ifname, dns);
 	if (curl == NULL)
 		return NULL;
 
-- 
2.20.1


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux