[SSSD] Design Discussion: SSSD should support DNS sites

Simo Sorce simo at redhat.com
Thu Jan 31 14:43:09 UTC 2013


On Thu, 2013-01-31 at 10:49 +0100, Sumit Bose wrote:
> Hi,
> 
> I have created a design page for
> https://fedorahosted.org/sssd/ticket/1032 "[RFE] sssd should support DNS
> sites" at
> https://fedorahosted.org/sssd/wiki/DesignDocs/ActiveDirectoryDNSSites .
> It can be found below as well.
> 
> Corrections, comments and enhancements are welcome.

Good start, comments inline!

> bye,
> Sumit
> 
> == Use Active Directory's DNS sites ==
> Related ticket(s):
> * [https://fedorahosted.org/sssd/ticket/1032 RFE sssd should support DNS sites]
> 
> === Problem Statement ===
> In larger Active Directory environments there is typically more than one domain controller. Some of them are used for redundancy, others to build different administrative domains. But in environments with multiple physical locations each location often has at least one local domain controller to reduce latency and network load between the locations.
> 
> Now clients have to find the local or nearest domain controller. For this the concept of sites was introduce where each physical location can be seen as an individual site with a unique name. The naming scheme for DNS service records was extended (see e.g. http://technet.microsoft.com/en-us/library/cc759550(v=ws.10).aspx) so that clients can first try to find the needed service in the local site and can fall back to look in the whole domain if there is no local service available.
> 
> Additionally clients have to find out about which site they belong to. This must be done dynamically because clients might move from one location to a different one on regular basis (roaming users). For this a special LDAP request, the (C)LDAP ping (http://msdn.microsoft.com/en-us/library/cc223811.aspx), was introduced.
> 
> === Overview view of the solution ===
> A new request should be added to the sssd resolver code which can do site aware lookups of DNS service records. This request will do the following steps:
> 1. do a DNS lookup to find any DC
> 1. send a CLDAP ping to the returned DC to get the client's site
> 1. lookup the requested service in the client's site
> 1. if this fails, lookup the requested service in the next nearest site if available (only available in domains with functional level 2008 or higher)
> 1. if this fails, lookup the requested service in the 'Default-First-Site-Name' site if it wasn't one of the previously used sites
> 1. if this fails, lookup the requested service without any site extension
> 1. if this fails the request will ultimately fail
> 
> The results of the different step should be available with one of the debug levels reserved for tracing to make debugging easier and to allow acceptance tests to validate the behavior with the help of the debug logs.
> 
> === Implementation details ===
> Currently the request to look up service records if defined by
> 
> {{{
> struct tevent_req *resolv_getsrv_send(TALLOC_CTX *mem_ctx,
>                                       struct tevent_context *ev,
>                                       struct resolv_ctx *ctx,
>                                       const char *query);
> 
> int resolv_getsrv_recv(TALLOC_CTX *mem_ctx,
>                        struct tevent_req *req,
>                        int *status,
>                        int *timeouts,
>                        struct ares_srv_reply **reply_list);
> }}}
> from async_resolv.h.
> 
> The new request might have the following interface:
> {{{
> /**
>  * @brief Create an async request to lookup DNS service records and respect the AD DNS sites
>  * 
>  * @param[in] mem_ctx Talloc memory context for the returned tevent_req structure
>  * @param[in] ev Tevent context
>  * @param[in] ctx Resolver context
>  * @param[in] site_ctx Site related context, may be NULL. If site_ctx is NULL resolv_getsrv_site_send() tries to resolve the site the client belongs to first and then tries to find the nearest server for the requested service.
>  * @param[in] service the service which should be found, e.g. _ldap._tcp
>  * @param[in] domain the domain where the service should be found
>  *
>  * @return
>  *  - tevent_req structure for the new request
>  *  - NULL if a new request could not be allocated
>  */ 
> struct tevent_req *resolv_getsrv_site_send(TALLOC_CTX *mem_ctx,
>                                            struct tevent_context *ev,
>                                            struct resolv_ctx *ctx,
>                                            struct site_ctx *site_ctx,
>                                            const char *service,
>                                            const char *domain);

I do not think you should have a site_ctx and a resolv_ctx, one or the
other.
If you added site_ctx with the idea of calling this function recursively
then I would object to that, you should have a higher level internal
public function that does the whole processing and an internal private
one that is called multiple times and conceal internal requirements.

Also I do not know that we really need to specify the service.

The site is independent from the service you want to get. So we should
probably have a call that returns the site and a separate call that gets
the site name as input to get a specific service.

So I would have something like this:

struct tevent_req *resolv_get_site_send(TALLOC_CTX *mem_ctx,
                                        struct tevent_context *ev,
                                        struct resolv_ctx *ctx,
                                        const char *domain);

And separately:
struct tevent_req *resolv_srv_by_site_send(TALLOC_CTX *mem_ctx,
                                           struct tevent_context *ev,
                                           struct resolv_ctx *ctx,
                                           const char *site,
                                           const char *domain);


> /**
>  * @brief Return the results of the given resolv_getsrv_site request
>  *
>  * @param[in] mem_ctx Talloc memory context for the returned results
>  * @param[in] req resolv_getsrv_site request which should be checked
>  * @param[out] status the returned status of the underlying c-ares request, see area_query(3) for details
>  * @param[out] timeouts the number of timeout occured during the underlying c-ares request, see area_query(3) for details
>  * @param[out] site_ctx an opaque struct with site information which can be used in later requests to skip the site lookup
>  * @param[out] reply_list list of replies
>  *
>  * @return
>  *  - 0 (EOK) on success
>  *  - !=0 in case of an error
>  */
> int resolv_getsrv_site_recv(TALLOC_CTX *mem_ctx,
>                             struct tevent_req *req,
>                             int *status,
>                             int *timeouts,
>                             struct site_ctx **site_ctx,
>                             struct ares_srv_reply **reply_list);
> }}}

As above 
int resolv_get_site_recv(TALLOC_CTX *mem_ctx,
                         struct tevent_req *req,
                         int *status,
                         int *timeouts,
                         const char **site);

In site we can return something like 'Foo Site', or
'Default-First-site-name' (possibly localized) or NULL if no site was
found.

And another _recv() to return srv by site.

> ==== Finding a DC for the CLDAP ping ====
> To find any DC in the domain a Windows client, and samba as well, look
> for a _ldap._tcp service record. The only difference is that samba
> uses a plain _ldap._tcp.domain.name while a Windows client
> _ldap._tcp.Default-First-Site-Name._sites.dc._msdcs.domain.name. I
> guess it will fall back to _ldap._tcp.domain.name if the other name
> cannot be resolved. I would suggest to use _ldap._tcp.domain.name for
> the SSSD implementation.

Why ? Using the Default-First-Site-Name one is technically more correct
when multiple sites are in use.

> ==== Sending the CLDAP ping ====
> The CLDAP ping is a LDAP search request with a filter like
> {{{
> (&(&(DnsDomain=ad.domain)(DomainSid=S-1-5-21-1111-2222-3333))(NtVer=0x01000016))
> }}}
> and the attribute "!NetLogon".
> The flags given with the !NtVer component of the search filter will be
> different for a domain member (AD provider) and an IPA server in an
> environment with trusts (IPA provider).
> 
> A domain member will belong to a site and the following flags
> from /usr/include/samba-4.0/gen_ndr/nbt.h should be used
> 'NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX |
> NETLOGON_NT_VERSION_IP'. A trusted server does not belong to one of
> the sites of trusting domain so it can only ask for the closest site
> with 'NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX |
> NETLOGON_NT_VERSION_WITH_CLOSEST_SITE'. Maybe
> NETLOGON_NT_VERSION_WITH_CLOSEST_SITE is useful for a domain member as
> well if e.g. the services on the local site are not available.
> 
> ==== Parsing the server response ====
> The server response is a single attribute "!NetLogon" which is a
> binary blob containing multiple NDR encoded values. This value can be
> decoded with ndr_pull_netlogon_samlogon_response() from the Samba
> library libndr-nbt.

Ack, we already use ndr libs for the PAC, we need to make sure though
that libndr-nbt doesn't drag in too many dependencies.

> === How to test ===
> If this feature is tested the following scenarios can be considered:
> ==== AD domain does not have any sites other than the default 'Default-First-Site-Name' ====
> * SSSD should be able to discover the default site 'Default-First-Site-Name' 
> * SSSD should connect to any DC.
> 
> ==== AD domain has sites but the local site of the SSSD client has no domain controller ====
> * SSSD should be able to discover the local site
> * SSSD should connect to a DC from 'Default-First-Site-Name'
> 
> ==== AD domain has sites and the local site of the SSSD client has a domain controller ====
> * SSSD should be able to discover the local site
> * SSSD should connect to a DC from the local site
> 
> Besides inspection the log files with a high debug level to connection
> to the domain controller can also be verified with the netstat or ss
> utilities.

we should probably have a sssdctl command in the future that can query
this kind of info.

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York




More information about the sssd-devel mailing list