about summary refs log tree commit diff
path: root/src/nm-connectivity.c
diff options
context:
space:
mode:
authorSebastien Bacher <seb128@ubuntu.com>2019-03-12 15:16:42 +0100
committerSebastien Bacher <seb128@ubuntu.com>2019-03-12 15:16:42 +0100
commitcc4ab276f923ded9f415c1c2bf192994367ab0bb (patch)
treeac3a7775665992b27d07eb44186d38ff961a8cd7 /src/nm-connectivity.c
parentbb1cf58350bb34463e9ffc5f96ac4f9b6bf46d28 (diff)
parentdd428301eb6f02542015121d7b08d9997f137e50 (diff)
Update upstream source from tag 'upstream/1.15.91'
Update to upstream version '1.15.91'
with Debian dir 74de38245314cab529c6c94cd9d0b874ce0c2994
Diffstat (limited to 'src/nm-connectivity.c')
-rw-r--r--src/nm-connectivity.c138
1 files changed, 99 insertions, 39 deletions
diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c
index 5f0567e9..b72413d2 100644
--- a/src/nm-connectivity.c
+++ b/src/nm-connectivity.c
@@ -24,8 +24,6 @@
 
 #include "nm-connectivity.h"
 
-#include <string.h>
-
 #if WITH_CONCHECK
 #include <curl/curl.h>
 #endif
@@ -92,7 +90,7 @@ struct _NMConnectivityCheckHandle {
 		struct curl_slist *request_headers;
 		struct curl_slist *hosts;
 
-		GString *recv_msg;
+		gsize response_good_cnt;
 
 		guint curl_timer;
 		int ch_ifindex;
@@ -271,8 +269,6 @@ cb_data_complete (NMConnectivityCheckHandle *cb_data,
 
 #if WITH_CONCHECK
 	_con_config_unref (cb_data->concheck.con_config);
-	if (cb_data->concheck.recv_msg)
-		g_string_free (cb_data->concheck.recv_msg, TRUE);
 #endif
 	g_free (cb_data->ifspec);
 	if (cb_data->completed_log_message_free)
@@ -342,6 +338,7 @@ _con_curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask)
 	}
 
 	while ((msg = curl_multi_info_read (mhandle, &m_left))) {
+		const char *response;
 
 		if (msg->msg != CURLMSG_DONE)
 			continue;
@@ -370,25 +367,44 @@ _con_curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask)
 			                         g_strdup_printf ("check failed: (%d) %s",
 			                                          msg->data.result,
 			                                          curl_easy_strerror (msg->data.result)));
-		} else if (   !((_con_config_get_response (cb_data->concheck.con_config))[0])
-		           && (curl_easy_getinfo (msg->easy_handle, CURLINFO_RESPONSE_CODE, &response_code) == CURLE_OK)
-		           && response_code == 204) {
-			/* If we got a 204 response code (no content) and we actually
-			 * requested no content, report full connectivity. */
-			cb_data_queue_completed (cb_data,
-			                         NM_CONNECTIVITY_FULL,
-			                         "no content, as expected",
-			                         NULL);
-		} else {
-			/* If we get here, it means that easy_write_cb() didn't read enough
-			 * bytes to be able to do a match, or that we were asking for no content
-			 * (204 response code) and we actually got some. Either way, that is
-			 * an indication of a captive portal */
-			cb_data_queue_completed (cb_data,
-			                         NM_CONNECTIVITY_PORTAL,
-			                         "unexpected short response",
-			                         NULL);
+			continue;
+		}
+
+		response = _con_config_get_response (cb_data->concheck.con_config);
+
+		if (   response[0] == '\0'
+		    && (curl_easy_getinfo (msg->easy_handle, CURLINFO_RESPONSE_CODE, &response_code) == CURLE_OK)) {
+
+			if (response_code == 204) {
+				/* We expected an empty response, and we got a 204 response code (no content).
+				 * We may or may not have received any content (we would ignore it).
+				 * Anyway, the response_code 204 means we are good. */
+				cb_data_queue_completed (cb_data,
+				                         NM_CONNECTIVITY_FULL,
+				                         "no content, as expected",
+				                         NULL);
+				continue;
+			}
+
+			if (   response_code == 200
+			    && cb_data->concheck.response_good_cnt == 0) {
+				/* we expected no response, and indeed we got an empty reply (with status code 200) */
+				cb_data_queue_completed (cb_data,
+				                         NM_CONNECTIVITY_FULL,
+				                         "empty response, as expected",
+				                         NULL);
+				continue;
+			}
 		}
+
+		/* If we get here, it means that easy_write_cb() didn't read enough
+		 * bytes to be able to do a match, or that we were asking for no content
+		 * (204 response code) and we actually got some. Either way, that is
+		 * an indication of a captive portal */
+		cb_data_queue_completed (cb_data,
+		                         NM_CONNECTIVITY_PORTAL,
+		                         "unexpected short response",
+		                         NULL);
 	}
 
 	/* if we return a failure, we don't know what went wrong. It's likely serious, because
@@ -540,6 +556,8 @@ easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata)
 {
 	NMConnectivityCheckHandle *cb_data = userdata;
 	size_t len = size * nmemb;
+	size_t response_len;
+	size_t check_len;
 	const char *response;
 
 	if (cb_data->completed_state != NM_CONNECTIVITY_UNKNOWN) {
@@ -547,26 +565,68 @@ easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata)
 		return 0;
 	}
 
-	if (!cb_data->concheck.recv_msg)
-		cb_data->concheck.recv_msg = g_string_sized_new (len + 10);
-
-	g_string_append_len (cb_data->concheck.recv_msg, buffer, len);
+	if (len == 0) {
+		/* no data. That can happen, it's fine. */
+		return len;
+	}
 
 	response = _con_config_get_response (cb_data->concheck.con_config);;
-	if (   response
-	    && cb_data->concheck.recv_msg->len >= strlen (response)) {
-		/* We already have enough data -- check response */
-		if (g_str_has_prefix (cb_data->concheck.recv_msg->str, response)) {
-			cb_data_queue_completed (cb_data,
-			                         NM_CONNECTIVITY_FULL,
-			                         "expected response",
-			                         NULL);
-		} else {
+
+	if (response[0] == '\0') {
+		/* no response expected. We are however graceful and accept any
+		 * extra response that we might receive. We determine the empty
+		 * response based on the status code 204.
+		 *
+		 * Continue receiving... */
+		cb_data->concheck.response_good_cnt += len;
+
+		if (cb_data->concheck.response_good_cnt > (gsize) (100 * 1024)) {
+			/* we expect an empty response. We accept either
+			 * 1) status code 204 and any response
+			 * 2) status code 200 and an empty response.
+			 *
+			 * Here, we want to continue receiving data, to see whether we have
+			 * case 1). Arguably, the server shouldn't send us 204 with a non-empty
+			 * response, but we accept that also with a non-empty response, so
+			 * keep receiving.
+			 *
+			 * However, if we get an excessive amount of data, we put a stop on it
+			 * and fail. */
 			cb_data_queue_completed (cb_data,
 			                         NM_CONNECTIVITY_PORTAL,
-			                         "unexpected response",
+			                         "unexpected non-empty response",
 			                         NULL);
+			return 0;
 		}
+
+		return len;
+	}
+
+	nm_assert (cb_data->concheck.response_good_cnt < strlen (response));
+
+	response_len = strlen (response);
+
+	check_len = NM_MIN (len,
+	                    response_len - cb_data->concheck.response_good_cnt);
+
+	if (strncmp (&response[cb_data->concheck.response_good_cnt],
+	             buffer,
+	             check_len) != 0) {
+		cb_data_queue_completed (cb_data,
+		                         NM_CONNECTIVITY_PORTAL,
+		                         "unexpected response",
+		                         NULL);
+		return 0;
+	}
+
+	cb_data->concheck.response_good_cnt += len;
+
+	if (cb_data->concheck.response_good_cnt >= response_len) {
+		/* We already have enough data, and it matched. */
+		cb_data_queue_completed (cb_data,
+		                         NM_CONNECTIVITY_FULL,
+		                         "expected response",
+		                         NULL);
 		return 0;
 	}
 
@@ -1041,8 +1101,8 @@ nm_connectivity_init (NMConnectivity *self)
 #if WITH_CONCHECK
 	ret = curl_global_init (CURL_GLOBAL_ALL);
 	if (ret != CURLE_OK) {
-		 _LOGE ("unable to init cURL, connectivity check will not work: (%d) %s",
-		        ret, curl_easy_strerror (ret));
+		_LOGE ("unable to init cURL, connectivity check will not work: (%d) %s",
+		       ret, curl_easy_strerror (ret));
 	}
 #endif