diff options
Diffstat (limited to 'src/providers/fail_over.c')
-rw-r--r-- | src/providers/fail_over.c | 198 |
1 files changed, 176 insertions, 22 deletions
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c index 4fb05c1f..c965c0e3 100644 --- a/src/providers/fail_over.c +++ b/src/providers/fail_over.c @@ -97,7 +97,7 @@ struct server_common { }; struct srv_data { - char *domain; + char *dns_domain; char *proto; char *srv; @@ -212,7 +212,7 @@ get_srv_query(TALLOC_CTX *mem_ctx, struct fo_server *server) query = talloc_asprintf(mem_ctx, "_%s._%s.%s", server->srv_data->srv, server->srv_data->proto, - server->srv_data->domain); + server->srv_data->dns_domain); return query; } @@ -222,7 +222,7 @@ collapse_srv_lookup(struct fo_server *server) struct fo_server *tmp, *meta; meta = server->srv_data->meta; - DEBUG(4, ("Need to refresh SRV lookup for domain %s\n", meta->srv_data->domain)) + DEBUG(4, ("Need to refresh SRV lookup for domain %s\n", meta->srv_data->dns_domain)) if (server != meta) { while (server->prev && server->prev->srv_data == meta->srv_data) { @@ -498,19 +498,20 @@ create_server_common(TALLOC_CTX *mem_ctx, struct fo_ctx *ctx, const char *name) int fo_add_srv_server(struct fo_service *service, const char *srv, - const char *domain, const char *proto, void *user_data) + const char *dns_domain, const char *proto, void *user_data) { struct fo_server *server; DEBUG(3, ("Adding new SRV server in domain '%s', to service '%s'\n", - domain, service->name)); + dns_domain ? dns_domain : "unknown", service->name)); DLIST_FOR_EACH(server, service->server_list) { if (server->user_data != user_data) continue; if (fo_is_srv_lookup(server)) { - if (strcasecmp(server->srv_data->domain, domain) == 0 && + if (((dns_domain == NULL && server->srv_data->dns_domain == NULL) || + strcasecmp(server->srv_data->dns_domain, dns_domain) == 0) && strcasecmp(server->srv_data->proto, proto) == 0) { return EEXIST; } @@ -530,14 +531,18 @@ fo_add_srv_server(struct fo_service *service, const char *srv, if (server->srv_data == NULL) return ENOMEM; - server->srv_data->domain = talloc_strdup(server->srv_data, domain); server->srv_data->proto = talloc_strdup(server->srv_data, proto); server->srv_data->srv = talloc_strdup(server->srv_data, srv); - if (server->srv_data->domain == NULL || - server->srv_data->proto == NULL || + if (server->srv_data->proto == NULL || server->srv_data->srv == NULL) return ENOMEM; + if (dns_domain) { + server->srv_data->dns_domain = talloc_strdup(server->srv_data, dns_domain); + if (server->srv_data->dns_domain == NULL) + return ENOMEM; + } + server->srv_data->meta = server; server->srv_data->srv_lookup_status = DEFAULT_SRV_STATUS; server->srv_data->last_status_change.tv_sec = 0; @@ -895,6 +900,17 @@ fo_resolve_service_recv(struct tevent_req *req, struct fo_server **server) *******************************************************************/ static void resolve_srv_done(struct tevent_req *subreq); +static void resolve_srv_cont(struct tevent_req *req); + +struct tevent_req *resolve_get_domain_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct fo_ctx *foctx, + struct resolv_ctx *resolv); + +static void resolve_getsrv_domain_done(struct tevent_req *req); +int resolve_get_domain_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + char **dns_domain); struct resolve_srv_state { struct fo_server *meta; @@ -913,7 +929,6 @@ resolve_srv_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct fo_server *server) { int ret; - char *query; struct tevent_req *req; struct tevent_req *subreq; struct resolve_srv_state *state; @@ -937,19 +952,18 @@ resolve_srv_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->meta = collapse_srv_lookup(server); /* FALLTHROUGH */ case SRV_NEUTRAL: /* Request SRV lookup */ - query = get_srv_query(state, state->meta); - if (!query) { - ret = ENOMEM; - goto done; - } - DEBUG(4, ("Searching for servers via SRV query '%s'\n", query)); - - subreq = resolv_getsrv_send(state, ev, resolv, query); - if (subreq == NULL) { - ret = ENOMEM; - goto done; + if (server->srv_data->dns_domain == NULL) { + /* we need to look up our DNS domain first */ + subreq = resolve_get_domain_send(state, ev, ctx, resolv); + if (subreq == NULL) { + ret = ENOMEM; + goto done; + } + tevent_req_set_callback(subreq, resolve_getsrv_domain_done, req); + break; } - tevent_req_set_callback(subreq, resolve_srv_done, req); + /* we know the DNS domain, just do the lookup */ + resolve_srv_cont(req); break; case SRV_NOT_RESOLVED: /* query could not be resolved but don't retry yet */ ret = EIO; @@ -975,6 +989,49 @@ done: } static void +resolve_getsrv_domain_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct resolve_srv_state *state = tevent_req_data(req, + struct resolve_srv_state); + int ret; + + ret = resolve_get_domain_recv(subreq, state->meta->srv_data, + &state->meta->srv_data->dns_domain); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + resolve_srv_cont(req); +} + +static void +resolve_srv_cont(struct tevent_req *req) +{ + struct resolve_srv_state *state = tevent_req_data(req, + struct resolve_srv_state); + char *query; + struct tevent_req *subreq; + + query = get_srv_query(state, state->meta); + if (!query) { + tevent_req_error(req, ENOMEM); + return; + } + DEBUG(4, ("Searching for servers via SRV query '%s'\n", query)); + + subreq = resolv_getsrv_send(state, state->ev, state->resolv, query); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, resolve_srv_done, req); +} + +static void resolve_srv_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, @@ -1072,6 +1129,103 @@ resolve_srv_recv(struct tevent_req *req, struct fo_server **server) return EOK; } +/******************************************************************* + * Get Fully Qualified Domain Name of the host machine * + *******************************************************************/ +struct resolve_get_domain_state { + char *fqdn; + char hostname[HOST_NAME_MAX]; +}; + +static void resolve_get_domain_done(struct tevent_req *subreq); + +struct tevent_req * +resolve_get_domain_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct fo_ctx *foctx, + struct resolv_ctx *resolv) +{ + int ret; + struct resolve_get_domain_state *state; + struct tevent_req *req, *subreq; + + req = tevent_req_create(mem_ctx, &state, struct resolve_get_domain_state); + if (!req) { + return NULL; + } + + ret = gethostname(state->hostname, HOST_NAME_MAX); + if (ret) { + DEBUG(2, ("gethostname() failed: [%d]: %s\n",ret, strerror(ret))); + return NULL; + } + state->hostname[HOST_NAME_MAX-1] = '\0'; + DEBUG(7, ("Host name is: %s\n", state->hostname)); + + subreq = resolv_gethostbyname_send(mem_ctx, ev, resolv, + state->hostname, + foctx->opts->family_order); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + tevent_req_set_callback(subreq, resolve_get_domain_done, req); + + return req; +} + +static void resolve_get_domain_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct resolve_get_domain_state *state = tevent_req_data(req, + struct resolve_get_domain_state); + struct hostent *hostent; + int ret; + + ret = resolv_gethostbyname_recv(subreq, req, NULL, NULL, &hostent); + talloc_zfree(subreq); + if (ret) { + DEBUG(2, ("Could not get fully qualified name for host name %s " + "resolver returned: [%d]: %s\n", + state->hostname, ret, strerror(ret))); + /* We'll proceed with hostname in this case */ + } else { + DEBUG(7, ("The full FQDN is: %s\n", hostent->h_name)); + state->fqdn = hostent->h_name; + } + tevent_req_done(req); +} + +int resolve_get_domain_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + char **dns_domain) +{ + struct resolve_get_domain_state *state = tevent_req_data(req, + struct resolve_get_domain_state); + char *fqdn; + char *domptr; + + TEVENT_REQ_RETURN_ON_ERROR(req); + + fqdn = state->fqdn ? state->fqdn : state->hostname; + domptr = strchr(fqdn, '.'); + + if (!domptr || (*(domptr+1) == '\0')) { + /* If the FQDN did not contain a dot or the dot was the last character + * (broken DNS server perhaps */ + *dns_domain = talloc_strdup(mem_ctx, fqdn); + } else { + domptr++; + *dns_domain = talloc_strdup(mem_ctx, domptr); + } + + if (*dns_domain == NULL) { + return ENOMEM; + } + + return EOK; +} + static void set_server_common_status(struct server_common *common, enum server_status status) |