Bind-dyndb-ldap keeps PTR record synchronized with coresponding A/AAAA record.
https://fedorahosted.org/bind-dyndb-ldap/ticket/33
From d2c0fa61bf87727e13abff17436a49d067071df9 Mon Sep 17 00:00:00 2001 From: Jiri Kuncar <jkun...@redhat.com> Date: Wed, 23 Nov 2011 09:57:12 -0500 Subject: [PATCH] Update PTR records when A/AAAA records are updated. - Enable by new runtime option: sync_ptr (boolean). - Added section in README file about PTR synchronization. Signed-off-by: Jiri Kuncar <jkuncar redhat com> --- README | 9 +++- src/ldap_convert.c | 3 +- src/ldap_convert.h | 2 + src/ldap_helper.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 129 insertions(+), 15 deletions(-) diff --git a/README b/README index 1509068..9df2ac4 100644 --- a/README +++ b/README @@ -180,8 +180,9 @@ psearch (default no) your zones will be automatically update when they change in LDAP. reconnect_interval (default 60) - Time (in seconds) after that the plugin should try to connect to LDAP server - again in case connection is lost and immediate reconnection fails. + Time (in seconds) after that the plugin should try to connect to LDAP + server again in case connection is lost and immediate reconnection + fails. ldap_hostname (default "") Sets hostname of the LDAP server. When it is set to "", actual @@ -190,6 +191,10 @@ ldap_hostname (default "") is used and named service has Kerberos principal different from /bin/hostname output. +sync_ptr (default no) + Keeps PTR record synchronized with coresponding A/AAAA record. + When an A/AAAA record is deleted the PTR record is also deleted + however it can point to different hostname. 5.2 Sample configuration ------------------------ diff --git a/src/ldap_convert.c b/src/ldap_convert.c index 2cbc058..85b572e 100644 --- a/src/ldap_convert.c +++ b/src/ldap_convert.c @@ -61,7 +61,6 @@ const char *dns_records[] = { "RRSIG", "NSEC", NULL }; -static isc_result_t dn_to_text(const char *dn, ld_string_t *target); static isc_result_t explode_dn(const char *dn, char ***explodedp, int notypes); static isc_result_t explode_rdn(const char *rdn, char ***explodedp, int notypes); @@ -105,7 +104,7 @@ cleanup: * * The resulting string will be "foo.bar.example.org." */ -static isc_result_t +isc_result_t dn_to_text(const char *dn, ld_string_t *target) { isc_result_t result; diff --git a/src/ldap_convert.h b/src/ldap_convert.h index 052eafa..4443855 100644 --- a/src/ldap_convert.h +++ b/src/ldap_convert.h @@ -43,4 +43,6 @@ isc_result_t ldap_attribute_to_rdatatype(const char *ldap_record, isc_result_t rdatatype_to_ldap_attribute(dns_rdatatype_t rdtype, const char **target); +isc_result_t dn_to_text(const char *dn, ld_string_t *target); + #endif /* !_LD_LDAP_CONVERT_H_ */ diff --git a/src/ldap_helper.c b/src/ldap_helper.c index ed0f6bc..8115f73 100644 --- a/src/ldap_helper.c +++ b/src/ldap_helper.c @@ -30,6 +30,7 @@ #include <dns/view.h> #include <dns/zone.h> #include <dns/zt.h> +#include <dns/byaddr.h> #include <isc/buffer.h> #include <isc/lex.h> @@ -41,6 +42,7 @@ #include <isc/thread.h> #include <isc/time.h> #include <isc/util.h> +#include <isc/netaddr.h> #include <alloca.h> #define LDAP_DEPRECATED 1 @@ -159,6 +161,7 @@ struct ldap_instance { isc_task_t *task; isc_thread_t watcher; isc_boolean_t exiting; + isc_boolean_t sync_ptr; }; struct ldap_pool { @@ -323,6 +326,7 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, { "fake_mname", default_string("") }, { "psearch", default_boolean(ISC_FALSE) }, { "ldap_hostname", default_string("") }, + { "sync_ptr", default_boolean(ISC_FALSE) }, end_of_settings }; @@ -380,6 +384,7 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name, ldap_settings[i++].target = ldap_inst->fake_mname; ldap_settings[i++].target = &ldap_inst->psearch; ldap_settings[i++].target = ldap_inst->ldap_hostname; + ldap_settings[i++].target = &ldap_inst->sync_ptr; CHECK(set_settings(ldap_settings, argv)); /* Validate and check settings. */ @@ -663,7 +668,7 @@ configure_zone_ssutable(dns_zone_t *zone, const char *update_str) * This is meant only for debugging. * DANGEROUS: Do not leave uncommented! */ -#if 0 +#if 0 { dns_acl_t *any; dns_acl_any(dns_zone_getmctx(zone), &any); @@ -1078,13 +1083,13 @@ ldapdb_rdatalist_get(isc_mem_t *mctx, ldap_instance_t *ldap_inst, dns_name_t *na } for (entry = HEAD(ldap_conn->ldap_entries); - entry != NULL; - entry = NEXT(entry, link)) { - if (ldap_parse_rrentry(mctx, entry, ldap_conn, - origin, ldap_inst->fake_mname, - string, rdatalist) != ISC_R_SUCCESS ) { - log_error("Failed to parse RR entry (%s)", str_buf(string)); - } + entry != NULL; + entry = NEXT(entry, link)) { + if (ldap_parse_rrentry(mctx, entry, ldap_conn, + origin, ldap_inst->fake_mname, + string, rdatalist) != ISC_R_SUCCESS ) { + log_error("Failed to parse RR entry (%s)", str_buf(string)); + } } /* Cache RRs */ @@ -1096,6 +1101,7 @@ cleanup: str_destroy(&string); if (result != ISC_R_SUCCESS) + ldapdb_rdatalist_destroy(mctx, rdatalist); return result; @@ -1646,7 +1652,7 @@ ldap_rdata_to_char_array(isc_mem_t *mctx, dns_rdata_t *rdata_head, CHECKED_MEM_ALLOCATE(mctx, vals[i], region.length + 1); memcpy(vals[i], region.base, region.length); vals[i][region.length] = '\0'; - + rdata = NEXT(rdata, link); } @@ -1762,6 +1768,7 @@ modify_ldap_common(dns_name_t *owner, ldap_instance_t *ldap_inst, ldap_connection_t *ldap_conn = NULL; ld_string_t *owner_dn = NULL; LDAPMod *change[3] = { NULL }; + LDAPMod *change_ptr = NULL; ldap_cache_t *cache; /* Flush modified record from the cache */ @@ -1787,14 +1794,115 @@ modify_ldap_common(dns_name_t *owner, ldap_instance_t *ldap_inst, /* for now always replace the ttl on add */ CHECK(ldap_rdttl_to_ldapmod(mctx, rdlist, &change[1])); } - + CHECK(ldap_modify_do(ldap_conn, str_buf(owner_dn), change, delete_node)); + /* Keep the PTR of corresponding A/AAAA record synchronized. */ + if (ldap_inst->sync_ptr == ISC_TRUE && + (rdlist->type == dns_rdatatype_a || rdlist->type == dns_rdatatype_aaaa)) { + + /* Get string with IP address from change request + * and convert it to in_addr structure. */ + in_addr_t ip; + if ((ip = inet_addr(change[0]->mod_values[0])) == 0) { + log_bug("Could not convert IP address from string '%s'.", change[0]->mod_values[0]); + } + + /* Use internal net address representation. */ + isc_netaddr_t isc_ip; + isc_netaddr_fromin(&isc_ip,(struct in_addr *) &ip); /* Only copy data to isc_ip stucture. */ + + /* + * Convert IP address to PTR record. + * + * @example + * 192.168.0.1 -> 1.0.168.192.in-addr.arpa + * + * @todo Check if it works for IPv6 correctly. + */ + struct dns_fixedname name; + dns_fixedname_init(&name); + CHECK(dns_byaddr_createptrname2(&isc_ip, 0, dns_fixedname_name(&name))); + + /* Find PTR entry in LDAP. */ + ldapdb_rdatalist_t rdlist_ptr; + result = ldapdb_rdatalist_get(mctx, ldap_inst, dns_fixedname_name(&name), + NULL, &rdlist_ptr); + + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { + log_error("Can not synchronize PTR record, ldapdb_rdatalist_get = %d", + result); + result = ISC_R_SUCCESS; /* Problem only with PTR synchronization. */ + goto cleanup; + } + + /* + * Do not overwrite old record and delete only existing record. + * + * @todo Check if PTR value == dns name. + */ + if ((result == ISC_R_SUCCESS && mod_op == LDAP_MOD_ADD) || + (result == ISC_R_NOTFOUND && mod_op == LDAP_MOD_DELETE)) { + log_bug("Can not synchronize PTR record for A/AAAA one (%s) - %s.", + str_buf(owner_dn), + ((mod_op == LDAP_MOD_ADD)?"already exists":"not found")); + result = ISC_R_SUCCESS; + goto cleanup; + } + + /* Get LDAP entry indentifier. */ + ld_string_t *owner_dn_ptr = NULL; + CHECK(str_new(mctx, &owner_dn_ptr)); + CHECK(dnsname_to_dn(ldap_inst->zone_register, dns_fixedname_name(&name), + owner_dn_ptr)); + + /* + * Get string representation of PTR record value. + * + * @example str_ptr = "host.example.com." + */ + ld_string_t *str_ptr = NULL; + CHECK(str_new(mctx, &str_ptr)); + CHECK(dn_to_text(str_buf(owner_dn), str_ptr)); + + + /* Fill the LDAPMod change structure up. */ + char **vals = NULL; + CHECKED_MEM_GET_PTR(mctx, change_ptr); + ZERO_PTR(change_ptr); + + /* Do the same action what has been done with A/AAAA record. */ + change_ptr->mod_op = mod_op; + char *attr_name; + const char *attr_name_c; + CHECK(rdatatype_to_ldap_attribute(dns_rdatatype_ptr, &attr_name_c)); + + DE_CONST(attr_name_c, attr_name); + change_ptr->mod_type = attr_name; + + CHECKED_MEM_ALLOCATE(mctx, vals, 2 * sizeof(char *)); + memset(vals, 0, 2 * sizeof(char *)); + change_ptr->mod_values = vals; + + CHECKED_MEM_ALLOCATE(mctx, vals[0], str_len(str_ptr) + 1); + memcpy(vals[0], str_buf(str_ptr), str_len(str_ptr) + 1); + + /* Switch pointers and free the old memory. */ + free_ldapmod(mctx, &change[0]); + change[0] = change_ptr; + change_ptr = NULL; + + /* Modify PTR record. */ + CHECK(ldap_modify_do(ldap_conn, str_buf(owner_dn_ptr), change, delete_node)); + (void) discard_from_cache(ldap_instance_getcache(ldap_inst), dns_fixedname_name(&name)); + } + cleanup: ldap_pool_putconnection(ldap_inst->pool, ldap_conn); str_destroy(&owner_dn); free_ldapmod(mctx, &change[0]); free_ldapmod(mctx, &change[1]); + if (change_ptr != NULL) free_ldapmod(mctx, &change_ptr); return result; } @@ -1874,7 +1982,7 @@ ldap_pool_destroy(ldap_pool_t **poolp) static ldap_connection_t * ldap_pool_getconnection(ldap_pool_t *pool) { - ldap_connection_t *ldap_conn; + ldap_connection_t *ldap_conn = NULL; unsigned int i; REQUIRE(pool != NULL); -- 1.7.7.1
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel