tlsdate: randomize IP address selection
Select random addresses for a host.
tlsdate may not have time to try all the addresses, so
randomizing helps when the first ones are not accessible.
Bug: 1057485
Test: manual on eve
Change-Id: Ib1d3d98bb944cbc7f5d0d5285584ab481c318f3d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/tlsdate/+/2767318
Tested-by: Michael Ershov <miersh@google.com>
Commit-Queue: Michael Ershov <miersh@google.com>
Reviewed-by: Pavol Marko <pmarko@chromium.org>
Reviewed-by: Mattias Nissler <mnissler@chromium.org>
diff --git a/src/tlsdate-helper.c b/src/tlsdate-helper.c
index 476f301..7db5e3c 100644
--- a/src/tlsdate-helper.c
+++ b/src/tlsdate-helper.c
@@ -196,14 +196,35 @@
verb ("V: unknown sa_family %hu\n", addr->sa_family);
}
+static int
+get_addrinfo_length (struct addrinfo *addr_infos) {
+ int result = 0;
+ for (struct addrinfo *iter = addr_infos; iter; iter = iter->ai_next) {
+ ++result;
+ }
+ return result;
+}
+
+static struct addrinfo *
+get_addrinfo_element (struct addrinfo *addr_infos, int index) {
+ int current_index = 0;
+ for (struct addrinfo *iter = addr_infos; iter; iter = iter->ai_next) {
+ if (current_index == index) {
+ return iter;
+ }
+ ++current_index;
+ }
+ return NULL;
+}
+
/* Connects to |host| on port |port|.
* Returns the socket file descriptor if successful, otherwise exits with
* failure.
*/
-static int create_connection (const char *host, const char *port)
+static int
+create_connection (const char *host, const char *port)
{
- int err, sock = -1;
- struct addrinfo *ai = NULL, *cai = NULL;
+ int sock = -1;
struct addrinfo hints = {
.ai_flags = AI_ADDRCONFIG,
.ai_family = AF_UNSPEC,
@@ -214,23 +235,35 @@
char addr_str_buf[INET6_ADDRSTRLEN];
memset (addr_str_buf, '\0', INET6_ADDRSTRLEN);
- err = getaddrinfo (host, port, &hints, &ai);
-
- if (err != 0 || !ai)
+ struct addrinfo *addr_infos = NULL;
+ int err = getaddrinfo (host, port, &hints, &addr_infos);
+ if (err != 0 || !addr_infos)
die ("getaddrinfo (%s): %s\n", host, gai_strerror (err));
- for (cai = ai; cai; cai = cai->ai_next)
+ int list_length = get_addrinfo_length (addr_infos);
+ for (int i = 0; i < list_length; ++i)
{
- addr_to_str (cai->ai_addr, addr_str_buf, INET6_ADDRSTRLEN);
+ // tlsdate is killed by a supervisor if it takes too long to finish. So it
+ // may not have time to try all the addresses. Selecting randomly makes
+ // it try different addresses during different attempts, that is usefull
+ // when some addresses are not accessible (e.g. first ones).
+ struct addrinfo *current_addr_info =
+ get_addrinfo_element (addr_infos, random () % list_length);
+ if (!current_addr_info) {
+ die ("attempted to use NULL addrinfo");
+ }
+
+ addr_to_str (current_addr_info->ai_addr, addr_str_buf, INET6_ADDRSTRLEN);
verb ("V: attempting to connect to %s\n", addr_str_buf);
- sock = socket (cai->ai_family, SOCK_STREAM, 0);
+ sock = socket (current_addr_info->ai_family, SOCK_STREAM, 0);
if (sock < 0)
{
perror ("socket");
continue;
}
- if (connect (sock, cai->ai_addr, cai->ai_addrlen) != 0)
+ if (connect (sock, current_addr_info->ai_addr,
+ current_addr_info->ai_addrlen) != 0)
{
perror ("connect");
close (sock);
@@ -239,7 +272,7 @@
}
break;
}
- freeaddrinfo (ai);
+ freeaddrinfo (addr_infos);
if (sock < 0)
die ("failed to find any remote addresses for %s:%s\n", host, port);
@@ -947,6 +980,7 @@
timewarp = (0 == strcmp ("timewarp", argv[9]));
leap = (0 == strcmp ("leapaway", argv[10]));
g_proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
+ srandom(time(NULL));
clock_init_time (&warp_time, RECENT_COMPILE_DATE, 0);
if (timewarp)
{