From 11843972ec6ac3c772967f436a61adc6a4c72ad8 Mon Sep 17 00:00:00 2001 From: Tomas Halman Date: Fri, 18 Oct 2024 15:49:40 +0200 Subject: [PATCH 1/4] tests: Check failover to secondary IP family Test that IPA server is still reachable when primary address family is blocked but secondary is working. --- src/tests/system/tests/test_failover.py | 28 ++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/tests/system/tests/test_failover.py b/src/tests/system/tests/test_failover.py index 49f1720db63..7486662861c 100644 --- a/src/tests/system/tests/test_failover.py +++ b/src/tests/system/tests/test_failover.py @@ -13,7 +13,7 @@ from sssd_test_framework.roles.ipa import IPA from sssd_test_framework.roles.ldap import LDAP from sssd_test_framework.roles.samba import Samba -from sssd_test_framework.topology import KnownTopologyGroup +from sssd_test_framework.topology import KnownTopologyGroup, KnownTopology @pytest.mark.parametrize("value, expected", [(None, 31), (15, 31), (60, 60)]) @@ -80,3 +80,29 @@ def test_failover__reactivation_timeout_is_honored( assert ( f"Primary server reactivation timeout set to {expected} seconds" in log ), f"'Primary server reactivation timeout set to {expected} seconds' not found in logs!" + + +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.IPA) +def test_failover__connect_second_family(client: Client, ipa: IPA): + """ + :title: Make sure that we can connect using secondary protocol + :setup: + 1. Create user in IPA + 2. Set family_order to "ipv6_first" + 3. Set IPv6 address in /etc/hosts so it resolves but it + points to non-exesting machine + :steps: + 1. Restart SSSD + 2. Resolve user + :expectedresults: + 1. SSSD goes online, user is resolved + :customerscenario: False + """ + user = "testuser" + ipa.user(user).add() + client.sssd.domain["lookup_family_order"] = "ipv6_first" + client.fs.append("%s cafe:cafe::3" % ipa.host.hostname) + client.sssd.start() + result = client.tools.id(user) + assert result is not None From cfb8d918780645eddf97a1092532d7ae398c81a7 Mon Sep 17 00:00:00 2001 From: Tomas Halman Date: Fri, 18 Oct 2024 15:53:28 +0200 Subject: [PATCH 2/4] failover: Make failover work over IP families Originally the option ipv4_first and ipv6_first was taken into account when resolving IP address. When both families are resolvable but the primary is blocked on firewall, the SSSD must switch to the socondary family. --- src/providers/fail_over.c | 39 ++++++++++++++++++++++++++++++++++- src/providers/fail_over.h | 1 + src/providers/fail_over_srv.c | 1 + 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c index 7f94407c538..6d3deef1f9c 100644 --- a/src/providers/fail_over.c +++ b/src/providers/fail_over.c @@ -268,6 +268,8 @@ str_server_status(enum server_status status) return "working"; case SERVER_NOT_WORKING: return "not working"; + case SERVER_SECOND_FAMILY: + return "second family"; } return "unknown server status"; @@ -481,6 +483,23 @@ service_destructor(struct fo_service *service) return 0; } +static int +try_another_family(struct fo_server *server, enum restrict_family family_order) { + if (server == NULL || server->common == NULL || server->common->rhostent == NULL) { + return 0; + } + + if (server->common->rhostent->family == AF_INET && family_order == IPV4_FIRST) { + return 1; + } + + if (server->common->rhostent->family == AF_INET6 && family_order == IPV6_FIRST) { + return 1; + } + + return 0; +} + int fo_new_service(struct fo_ctx *ctx, const char *name, datacmp_fn user_data_cmp, @@ -937,6 +956,11 @@ get_first_server_entity(struct fo_service *service, struct fo_server **_server) if (service_works(server) && fo_is_server_primary(server)) { goto done; } + if (fo_is_server_primary(server) && try_another_family(server, service->ctx->opts->family_order) ) { + /* set server state shomehow ? */ + fo_set_server_status(server, SERVER_SECOND_FAMILY); + goto done; + } service->active_server = NULL; } @@ -1193,13 +1217,26 @@ fo_resolve_service_server(struct tevent_req *req) struct resolve_service_state); struct tevent_req *subreq; int ret; + enum restrict_family family_restriction; + family_restriction = state->fo_ctx->opts->family_order; switch (get_server_status(state->server)) { + case SERVER_SECOND_FAMILY: + switch (family_restriction) { + case IPV4_FIRST: + family_restriction = IPV6_ONLY; + break; + case IPV6_FIRST: + family_restriction = IPV4_ONLY; + break; + default: + break; + } case SERVER_NAME_NOT_RESOLVED: /* Request name resolution. */ subreq = resolv_gethostbyname_send(state->server->common, state->ev, state->resolv, state->server->common->name, - state->fo_ctx->opts->family_order, + family_restriction, default_host_dbs); if (subreq == NULL) { tevent_req_error(req, ENOMEM); diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h index 924a09970b1..642965bbe69 100644 --- a/src/providers/fail_over.h +++ b/src/providers/fail_over.h @@ -49,6 +49,7 @@ enum server_status { SERVER_NAME_NOT_RESOLVED, /* We didn't yet resolved the host name. */ SERVER_RESOLVING_NAME, /* Name resolving is in progress. */ SERVER_NAME_RESOLVED, /* We resolved the host name but didn't try to connect. */ + SERVER_SECOND_FAMILY, /* We should try second protocol */ SERVER_WORKING, /* We successfully connected to the server. */ SERVER_NOT_WORKING /* We tried and failed to connect to the server. */ }; diff --git a/src/providers/fail_over_srv.c b/src/providers/fail_over_srv.c index 5f474eaee4f..be68761a1de 100644 --- a/src/providers/fail_over_srv.c +++ b/src/providers/fail_over_srv.c @@ -440,6 +440,7 @@ struct fo_resolve_srv_dns_ctx { char *hostname; char *sssd_domain; char *detected_domain; + bool last_family_tried; }; struct fo_resolve_srv_dns_state { From 0e4cc78e674d347615afab59a2d8ebb55babd4c8 Mon Sep 17 00:00:00 2001 From: Tomas Halman Date: Wed, 23 Oct 2024 15:50:37 +0200 Subject: [PATCH 3/4] fix-part-test --- src/tests/fail_over-tests.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tests/fail_over-tests.c b/src/tests/fail_over-tests.c index ccb896c29d8..9b1c611e9cb 100644 --- a/src/tests/fail_over-tests.c +++ b/src/tests/fail_over-tests.c @@ -275,6 +275,8 @@ START_TEST(test_fo_resolve_service) get_request(ctx, service[0], EOK, 20, PORT_WORKING, -1); get_request(ctx, service[0], EOK, 20, PORT_WORKING, SERVER_WORKING); get_request(ctx, service[0], EOK, 20, -1, SERVER_NOT_WORKING); + get_request(ctx, service[0], EOK, 20, PORT_WORKING, SERVER_WORKING); + get_request(ctx, service[0], EOK, 20, -1, SERVER_NOT_WORKING); get_request(ctx, service[0], EOK, 80, PORT_WORKING, -1); get_request(ctx, service[0], EOK, 80, PORT_NOT_WORKING, -1); get_request(ctx, service[0], ENOENT, 0, -1, -1); From cb925e5336e443519b2daf242fb374d3d399e3fe Mon Sep 17 00:00:00 2001 From: Tomas Halman Date: Fri, 8 Nov 2024 14:58:59 +0100 Subject: [PATCH 4/4] Fix test --- src/tests/system/tests/test_failover.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tests/system/tests/test_failover.py b/src/tests/system/tests/test_failover.py index 7486662861c..bc183b61078 100644 --- a/src/tests/system/tests/test_failover.py +++ b/src/tests/system/tests/test_failover.py @@ -102,7 +102,10 @@ def test_failover__connect_second_family(client: Client, ipa: IPA): user = "testuser" ipa.user(user).add() client.sssd.domain["lookup_family_order"] = "ipv6_first" - client.fs.append("%s cafe:cafe::3" % ipa.host.hostname) + client.sssd.domain["debug_level"] = "9" + client.fs.append("/etc/hosts", "cafe:cafe::3 %s" % ipa.host.hostname) + import time + time.sleep(2) client.sssd.start() result = client.tools.id(user) assert result is not None