The Samba-Bugzilla – Attachment 8682 Details for
Bug 9742
DNS updater does not find primary nameserver from SOA RRs.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch to fix DNS update using SOA query
fix_dns_update_with_soa.patch (text/plain), 17.04 KB, created by
Kyle Strickland
on 2013-03-25 17:28:23 UTC
(
hide
)
Description:
Patch to fix DNS update using SOA query
Filename:
MIME Type:
Creator:
Kyle Strickland
Created:
2013-03-25 17:28:23 UTC
Size:
17.04 KB
patch
obsolete
>From c18bbe1f3a5855d5462a97d3583cc8ba668950ab Mon Sep 17 00:00:00 2001 >From: Kyle Strickland <kyle@kyle.strickland.name> >Date: Thu, 21 Mar 2013 15:24:20 -0400 >Subject: [PATCH 1/2] > lib/addns/dnsquery.c,lib/addns/dnsquery.h,libcli/dns/dns.h, > source3/utils/net_ads.c: > >Since the realm may be different from the DNS domain: > Query for SOA records to know where to update DNS. > Fall back to checking for NS records if no SOA records found. >--- > lib/addns/dnsquery.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++- > lib/addns/dnsquery.h | 5 + > libcli/dns/dns.h | 14 +++ > source3/utils/net_ads.c | 115 +++++++++++++--------- > 4 files changed, 337 insertions(+), 48 deletions(-) > >diff --git a/lib/addns/dnsquery.c b/lib/addns/dnsquery.c >index 57ef8d9..33e8bd8 100644 >--- a/lib/addns/dnsquery.c >+++ b/lib/addns/dnsquery.c >@@ -221,6 +221,67 @@ static bool ads_dns_parse_rr_srv( TALLOC_CTX *ctx, uint8_t *start, uint8_t *end, > /********************************************************************* > *********************************************************************/ > >+static bool ads_dns_parse_rr_soa( TALLOC_CTX *ctx, uint8_t *start, uint8_t *end, >+ uint8_t **ptr, struct dns_rr_soa *soarec ) >+{ >+ struct dns_rr rr; >+ uint8_t *p; >+ char soaname[MAX_DNS_NAME_LENGTH]; >+ int namelen; >+ >+ if ( !start || !end || !soarec || !*ptr) >+ return -1; >+ >+ /* Parse the RR entry. Coming out of the this, ptr is at the beginning >+ of the next record */ >+ >+ if ( !ads_dns_parse_rr( ctx, start, end, ptr, &rr ) ) { >+ DEBUG(1,("ads_dns_parse_rr_soa: Failed to parse RR record\n")); >+ return false; >+ } >+ >+ if ( rr.type != T_SOA ) { >+ DEBUG(1,("ads_dns_parse_rr_soa: Bad answer type (%d)\n", >+ rr.type)); >+ return false; >+ } >+ >+ soarec->zone = talloc_strdup( ctx, rr.hostname); >+ >+ p = rr.rdata; >+ >+ /* parse SOA data */ >+ >+ namelen = dn_expand( start, end, p, soaname, sizeof(soaname) ); >+ if ( namelen < 0 ) { >+ DEBUG(1,("ads_dns_parse_rr_soa: Failed to uncompress SOA mname!\n")); >+ return false; >+ } >+ soarec->mname = talloc_strdup( ctx, soaname ); >+ >+ p += namelen; >+ >+ namelen = dn_expand( start, end, p, soaname, sizeof(soaname) ); >+ if ( namelen < 0 ) { >+ DEBUG(1,("ads_dns_parse_rr_soa: Failed to uncompress SOA rname!\n")); >+ return false; >+ } >+ soarec->rname = talloc_strdup( ctx, soaname ); >+ >+ p += namelen; >+ >+ soarec->serial = RIVAL(p, 0); >+ soarec->refresh = RIVAL(p, 4); >+ soarec->retry = RIVAL(p, 8); >+ soarec->expiration = RIVAL(p, 12); >+ soarec->min_ttl = RIVAL(p, 16); >+ >+ return true; >+} >+ >+/********************************************************************* >+*********************************************************************/ >+ > static bool ads_dns_parse_rr_ns( TALLOC_CTX *ctx, uint8_t *start, uint8_t *end, > uint8_t **ptr, struct dns_rr_ns *nsrec ) > { >@@ -296,6 +357,8 @@ static NTSTATUS dns_send_req( TALLOC_CTX *ctx, const char *name, int q_type, > { > uint8_t *buffer = NULL; > size_t buf_len = 0; >+ uint8_t *msg = NULL; >+ size_t msg_len = 0; > int resp_len = NS_PACKETSZ; > static time_t last_dns_check = 0; > static NTSTATUS last_dns_status = NT_STATUS_OK; >@@ -339,8 +402,31 @@ static NTSTATUS dns_send_req( TALLOC_CTX *ctx, const char *name, int q_type, > } > } > >- if ((resp_len = res_query(name, C_IN, q_type, buffer, buf_len)) >- < 0 ) { >+ if (q_type != T_SOA) { >+ resp_len = res_query(name, C_IN, q_type, buffer, buf_len); >+ } else { >+ if ( msg ) >+ TALLOC_FREE( msg ); >+ >+ msg_len = resp_len * sizeof(uint8_t); >+ >+ if (msg_len) { >+ if ((msg = talloc_array(ctx, uint8_t, buf_len)) >+ == NULL ) { >+ DEBUG(0,("dns_send_req: " >+ "talloc() failed!\n")); >+ last_dns_status = NT_STATUS_NO_MEMORY; >+ last_dns_check = time_mono(NULL); >+ return last_dns_status; >+ } >+ } >+ >+ res_mkquery(ns_o_query, name, C_IN, q_type, NULL, 0, NULL, >+ msg, msg_len); >+ resp_len = res_send(msg, msg_len, buffer, buf_len); >+ } >+ >+ if (resp_len < 0 ) { > DEBUG(3,("dns_send_req: " > "Failed to resolve %s (%s)\n", > name, strerror(errno))); >@@ -582,6 +668,167 @@ NTSTATUS ads_dns_lookup_srv(TALLOC_CTX *ctx, > } > > /********************************************************************* >+ Simple wrapper for a DNS SOA query >+*********************************************************************/ >+ >+NTSTATUS ads_dns_lookup_soa(TALLOC_CTX *ctx, >+ const char *dns_hosts_file, >+ const char *dnsdomain, >+ struct dns_rr_soa **soalist, >+ int *numsoa) >+{ >+ uint8_t *buffer = NULL; >+ int resp_len = 0; >+ struct dns_rr_soa *soaarray = NULL; >+ int query_count, answer_count, auth_count, additional_count; >+ uint8_t *p; >+ int rrnum; >+ int idx = 0; >+ NTSTATUS status; >+ >+ if ( !ctx || !dnsdomain || !soalist ) { >+ return NT_STATUS_INVALID_PARAMETER; >+ } >+ >+ if (dns_hosts_file) { >+ DEBUG(1, ("NO 'SOA' lookup available when using resolv:host file")); >+ return NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ } >+ >+ /* Send the request. May have to loop several times in case >+ of large replies */ >+ >+ status = dns_send_req( ctx, dnsdomain, T_SOA, &buffer, &resp_len ); >+ if ( !NT_STATUS_IS_OK(status) ) { >+ DEBUG(3,("ads_dns_lookup_soa: Failed to send DNS query (%s)\n", >+ nt_errstr(status))); >+ return status; >+ } >+ p = buffer; >+ >+ /* For some insane reason, the ns_initparse() et. al. routines are only >+ available in libresolv.a, and not the shared lib. Who knows why.... >+ So we have to parse the DNS reply ourselves */ >+ >+ /* Pull the answer RR's count from the header. >+ * Use the NMB ordering macros */ >+ >+ query_count = RSVAL( p, 4 ); >+ answer_count = RSVAL( p, 6 ); >+ auth_count = RSVAL( p, 8 ); >+ additional_count = RSVAL( p, 10 ); >+ >+ DEBUG(4,("ads_dns_lookup_soa: " >+ "%d records returned in the answer section.\n", >+ answer_count)); >+ DEBUG(4,("ads_dns_lookup_soa: " >+ "%d records returned in the authority section.\n", >+ auth_count)); >+ >+ if (answer_count + auth_count > 0) { >+ if ((soaarray = talloc_array(ctx, struct dns_rr_soa, >+ answer_count + auth_count)) == NULL ) { >+ DEBUG(0,("ads_dns_lookup_soa: " >+ "talloc() failure for %d char*'s\n", >+ answer_count + auth_count)); >+ return NT_STATUS_NO_MEMORY; >+ } >+ } else { >+ soaarray = NULL; >+ } >+ >+ /* now skip the header */ >+ >+ p += NS_HFIXEDSZ; >+ >+ /* parse the query section */ >+ >+ for ( rrnum=0; rrnum<query_count; rrnum++ ) { >+ struct dns_query q; >+ >+ if (!ads_dns_parse_query(ctx, buffer, buffer+resp_len, >+ &p, &q)) { >+ DEBUG(1,("ads_dns_lookup_soa: " >+ " Failed to parse query record!\n")); >+ return NT_STATUS_UNSUCCESSFUL; >+ } >+ } >+ >+ /* now we are at the answer section */ >+ >+ for ( rrnum=0; rrnum<answer_count; rrnum++ ) { >+ if (!ads_dns_parse_rr_soa(ctx, buffer, buffer+resp_len, >+ &p, &soaarray[rrnum])) { >+ DEBUG(1,("ads_dns_lookup_soa: " >+ "Failed to parse answer record!\n")); >+ return NT_STATUS_UNSUCCESSFUL; >+ } >+ } >+ >+ /* Parse the authority section */ >+ >+ for ( rrnum=answer_count; rrnum<answer_count + auth_count; rrnum++ ) { >+ if (!ads_dns_parse_rr_soa(ctx, buffer, buffer+resp_len, >+ &p, &soaarray[rrnum])) { >+ DEBUG(1,("ads_dns_lookup_soa: " >+ "Failed to parse authority record!\n")); >+ return NT_STATUS_UNSUCCESSFUL; >+ } >+ } >+ idx = rrnum; >+ >+ /* Parse the additional records section */ >+ >+ for ( rrnum=0; rrnum<additional_count; rrnum++ ) { >+ struct dns_rr rr; >+ int i; >+ >+ if (!ads_dns_parse_rr(ctx, buffer, buffer+resp_len, >+ &p, &rr)) { >+ DEBUG(1,("ads_dns_lookup_soa: Failed " >+ "to parse additional records section!\n")); >+ return NT_STATUS_UNSUCCESSFUL; >+ } >+ >+ /* only interested in A records as a shortcut for having to come >+ back later and lookup the name */ >+ >+ if (rr.type != T_A || rr.rdatalen != 4) { >+#if defined(HAVE_IPV6) >+ if (rr.type != T_AAAA || rr.rdatalen != 16) >+#endif >+ continue; >+ } >+ >+ for ( i=0; i<idx; i++ ) { >+ if (strcmp(rr.hostname, soaarray[i].mname) == 0) { >+ if (rr.type == T_A) { >+ struct in_addr ip; >+ memcpy(&ip, rr.rdata, 4); >+ in_addr_to_sockaddr_storage( >+ &soaarray[i].ss, >+ ip); >+ } >+#if defined(HAVE_IPV6) >+ if (rr.type == T_AAAA) { >+ struct in6_addr ip6; >+ memcpy(&ip6, rr.rdata, rr.rdatalen); >+ in6_addr_to_sockaddr_storage( >+ &soaarray[i].ss, >+ ip6); >+ } >+#endif >+ } >+ } >+ } >+ >+ *soalist = soaarray; >+ *numsoa = idx; >+ >+ return NT_STATUS_OK; >+} >+ >+/********************************************************************* > Simple wrapper for a DNS NS query > *********************************************************************/ > >diff --git a/lib/addns/dnsquery.h b/lib/addns/dnsquery.h >index 1491b69..33ac3c2 100644 >--- a/lib/addns/dnsquery.h >+++ b/lib/addns/dnsquery.h >@@ -29,6 +29,11 @@ NTSTATUS ads_dns_lookup_srv(TALLOC_CTX *ctx, > const char *name, > struct dns_rr_srv **dclist, > int *numdcs); >+NTSTATUS ads_dns_lookup_soa(TALLOC_CTX *ctx, >+ const char *dns_hosts_file, >+ const char *dnsdomain, >+ struct dns_rr_soa **soalist, >+ int *numsoa); > NTSTATUS ads_dns_lookup_ns(TALLOC_CTX *ctx, > const char *dns_hosts_file, > const char *dnsdomain, >diff --git a/libcli/dns/dns.h b/libcli/dns/dns.h >index 01aa6c4..f9ff14e 100644 >--- a/libcli/dns/dns.h >+++ b/libcli/dns/dns.h >@@ -48,6 +48,20 @@ struct dns_rr_srv { > struct sockaddr_storage *ss_s; /* support multi-homed hosts */ > }; > >+/* SOA records */ >+ >+struct dns_rr_soa { >+ const char *zone; >+ const char *mname; >+ const char *rname; >+ uint32_t serial; >+ uint32_t refresh; >+ uint32_t retry; >+ uint32_t expiration; >+ uint32_t min_ttl; >+ struct sockaddr_storage ss; >+}; >+ > /* NS records */ > > struct dns_rr_ns { >diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c >index 5699943..11b2a14 100644 >--- a/source3/utils/net_ads.c >+++ b/source3/utils/net_ads.c >@@ -1134,8 +1134,11 @@ static NTSTATUS net_update_dns_internal(struct net_context *c, > const struct sockaddr_storage *addrs, > int num_addrs) > { >+ struct dns_rr_soa *soaservers = NULL; >+ int soa_count = 0; > struct dns_rr_ns *nameservers = NULL; >- int ns_count = 0, i; >+ int ns_count = 0; >+ int i; > NTSTATUS status = NT_STATUS_UNSUCCESSFUL; > DNS_ERROR dns_err; > fstring dns_server; >@@ -1152,59 +1155,70 @@ static NTSTATUS net_update_dns_internal(struct net_context *c, > dnsdomain++; > > dns_hosts_file = lp_parm_const_string(-1, "resolv", "host file", NULL); >- status = ads_dns_lookup_ns(ctx, dns_hosts_file, >- dnsdomain, &nameservers, &ns_count); >- if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) { >- /* Child domains often do not have NS records. Look >- for the NS record for the forest root domain >- (rootDomainNamingContext in therootDSE) */ >- >- const char *rootname_attrs[] = { "rootDomainNamingContext", NULL }; >- LDAPMessage *msg = NULL; >- char *root_dn; >- ADS_STATUS ads_status; >- >- if ( !ads->ldap.ld ) { >- ads_status = ads_connect( ads ); >- if ( !ADS_ERR_OK(ads_status) ) { >- DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n")); >+ >+ status = ads_dns_lookup_soa(ctx, dns_hosts_file, >+ dnsdomain, &soaservers, &soa_count); >+ if ( !NT_STATUS_IS_OK(status) || (soa_count == 0)) { >+ >+ status = ads_dns_lookup_ns(ctx, dns_hosts_file, >+ dnsdomain, &nameservers, &ns_count); >+ if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) { >+ /* Child domains often do not have NS records. Look >+ for the NS record for the forest root domain >+ (rootDomainNamingContext in therootDSE) */ >+ >+ const char *rootname_attrs[] = { "rootDomainNamingContext", NULL }; >+ LDAPMessage *msg = NULL; >+ char *root_dn; >+ ADS_STATUS ads_status; >+ >+ if ( !ads->ldap.ld ) { >+ ads_status = ads_connect( ads ); >+ if ( !ADS_ERR_OK(ads_status) ) { >+ DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n")); >+ goto done; >+ } >+ } >+ >+ ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE, >+ "(objectclass=*)", >+ rootname_attrs, &msg); >+ if (!ADS_ERR_OK(ads_status)) { > goto done; > } >- } > >- ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE, >- "(objectclass=*)", rootname_attrs, &msg); >- if (!ADS_ERR_OK(ads_status)) { >- goto done; >- } >+ root_dn = ads_pull_string(ads, ctx, msg, >+ "rootDomainNamingContext"); >+ if ( !root_dn ) { >+ ads_msgfree( ads, msg ); >+ goto done; >+ } >+ >+ root_domain = ads_build_domain( root_dn ); > >- root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext"); >- if ( !root_dn ) { >+ /* cleanup */ > ads_msgfree( ads, msg ); >- goto done; >- } > >- root_domain = ads_build_domain( root_dn ); >+ /* try again for NS servers */ > >- /* cleanup */ >- ads_msgfree( ads, msg ); >+ status = ads_dns_lookup_ns(ctx, dns_hosts_file, >+ root_domain, &nameservers, >+ &ns_count); > >- /* try again for NS servers */ >+ if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) { >+ DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s " >+ "realm\n", ads->config.realm)); >+ goto done; >+ } > >- status = ads_dns_lookup_ns(ctx, dns_hosts_file, root_domain, >- &nameservers, &ns_count); >+ dnsdomain = root_domain; > >- if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) { >- DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s " >- "realm\n", ads->config.realm)); >- goto done; > } >- >- dnsdomain = root_domain; >- > } > >- for (i=0; i < ns_count; i++) { >+ /* Only SOA or NS queries will have been successfully performed, >+ so we use whichever one has information. */ >+ for (i=0; i < soa_count || i < ns_count; i++) { > > uint32_t flags = DNS_UPDATE_SIGNED | > DNS_UPDATE_UNSIGNED | >@@ -1219,12 +1233,21 @@ static NTSTATUS net_update_dns_internal(struct net_context *c, > > status = NT_STATUS_UNSUCCESSFUL; > >- /* Now perform the dns update - we'll try non-secure and if we fail, >- we'll follow it up with a secure update */ >- >- fstrcpy( dns_server, nameservers[i].hostname ); >+ /* Now perform the dns update - we'll try non-secure and if we >+ * fail, we'll follow it up with a secure update */ >+ >+ if(soa_count > 0) { >+ fstrcpy( dns_server, soaservers[i].mname ); >+ dns_err = DoDNSUpdate(dns_server, >+ soaservers[i].zone, machine_name, >+ addrs, num_addrs, flags); >+ } else { >+ fstrcpy( dns_server, nameservers[i].hostname ); >+ dns_err = DoDNSUpdate(dns_server, >+ dnsdomain, machine_name, addrs, >+ num_addrs, flags); >+ } > >- dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs, flags); > if (ERR_DNS_IS_OK(dns_err)) { > status = NT_STATUS_OK; > goto done; >-- >1.8.1.4 > > >From 49010b4f168561ad6b1a8e462f1af1b9fbfd4b82 Mon Sep 17 00:00:00 2001 >From: Kyle Strickland <kyle@kyle.strickland.name> >Date: Mon, 25 Mar 2013 13:17:51 -0400 >Subject: [PATCH 2/2] source3/utils/net_ads.c, source3/utils/net_dns.c, > source3/utils/net_dns.h: > > Do not assume that the realm is the same as the DNS domain > when creating the GSS security context for updating DNS. >--- > source3/utils/net_ads.c | 4 ++-- > source3/utils/net_dns.c | 6 +++--- > source3/utils/net_dns.h | 2 +- > 3 files changed, 6 insertions(+), 6 deletions(-) > >diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c >index 11b2a14..6830245 100644 >--- a/source3/utils/net_ads.c >+++ b/source3/utils/net_ads.c >@@ -1238,12 +1238,12 @@ static NTSTATUS net_update_dns_internal(struct net_context *c, > > if(soa_count > 0) { > fstrcpy( dns_server, soaservers[i].mname ); >- dns_err = DoDNSUpdate(dns_server, >+ dns_err = DoDNSUpdate(ads->config.realm, dns_server, > soaservers[i].zone, machine_name, > addrs, num_addrs, flags); > } else { > fstrcpy( dns_server, nameservers[i].hostname ); >- dns_err = DoDNSUpdate(dns_server, >+ dns_err = DoDNSUpdate(ads->config.realm, dns_server, > dnsdomain, machine_name, addrs, > num_addrs, flags); > } >diff --git a/source3/utils/net_dns.c b/source3/utils/net_dns.c >index 9bbefdb..a8566bc 100644 >--- a/source3/utils/net_dns.c >+++ b/source3/utils/net_dns.c >@@ -29,7 +29,7 @@ > /********************************************************************* > *********************************************************************/ > >-DNS_ERROR DoDNSUpdate(char *pszServerName, >+DNS_ERROR DoDNSUpdate(char *realm, char *pszServerName, > const char *pszDomainName, const char *pszHostName, > const struct sockaddr_storage *sslist, size_t num_addrs, > uint32_t flags) >@@ -125,12 +125,12 @@ DNS_ERROR DoDNSUpdate(char *pszServerName, > goto error; > } > >- err = dns_negotiate_sec_ctx( pszDomainName, pszServerName, >+ err = dns_negotiate_sec_ctx( realm, pszServerName, > keyname, &gss_context, DNS_SRV_ANY ); > > /* retry using the Windows 2000 DNS hack */ > if (!ERR_DNS_IS_OK(err)) { >- err = dns_negotiate_sec_ctx( pszDomainName, pszServerName, >+ err = dns_negotiate_sec_ctx( realm, pszServerName, > keyname, &gss_context, > DNS_SRV_WIN2000 ); > } >diff --git a/source3/utils/net_dns.h b/source3/utils/net_dns.h >index 31e541b..28c995a 100644 >--- a/source3/utils/net_dns.h >+++ b/source3/utils/net_dns.h >@@ -32,7 +32,7 @@ > > #include "../lib/addns/dns.h" > >-DNS_ERROR DoDNSUpdate(char *pszServerName, >+DNS_ERROR DoDNSUpdate(char *realm, char *pszServerName, > const char *pszDomainName, const char *pszHostName, > const struct sockaddr_storage *sslist, > size_t num_addrs, >-- >1.8.1.4 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 9742
: 8682