diff --git a/CHANGELOG b/CHANGELOG index a811ec1..2778c87 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,38 @@ -Version 0.2.7 (next) +Version ?.?.? (next) + Make ldap2dns behave like a secondary nameserver by storing the serial number, expire, refresh, retry and minimum values in a record. -Version 0.2.6 (latest) +Version 0.3.3 (latest) +- Removed a bug which caused ldap2dns to etablish more than one connections + to the LDAP server. + +Version 0.3.2 ++ Only patches from Martin Lesser + applied. Nothing from myself. ++ connecting to a ldap-server where the server is given as URI works + (both ldap:// [with TLS] and ldaps://) ++ we use location-codes here, so ldap2dns.c was extended to make use of + them, this also requires an extension of dns.schema. + +Version 0.3.1 ++ ldap2dns now can work together with tinydns. This means that + all DNS queries are passed through tinydns directly onto the + LDAP backend. This avoids generating a data-file and calling + tinydns-data (or restarting BIND). + Drawback: Queries are much slower now. I am not sure if this + is acceptable on the long run. This is caused by the LDAP-schema + used here, were many objects with strict attribute-value-pair mapping + is used. Other schemas, such as the core- and cosine-schema need + less LDAP-objects, since they code multiple values into one attribute. + Nameservers based on this schema (such as ldapdns + http://nimh.org/code/ldapdns/) can therefore answer much faster. + +Version 0.3.0 ++ A new interface for web-administration written compleatly in PHP. + Much easier to install that the old mod_perl interface. + +Version 0.2.6 + Password passed with option -w now is invisible to 'ps'. + ldap2tinydns-conf now takes a parameter to specify to user under which ldap2dns will be running. diff --git a/FAQ b/FAQ new file mode 100644 index 0000000..0945ca8 --- /dev/null +++ b/FAQ @@ -0,0 +1,19 @@ +From: Steven Dossett +Right after I mailed you, I patched the schema :) +I moved from IA5 Strings to Numeric Strings in that section of the schema: + +attributetype ( 1.3.6.1.4.1.7222.1.4.12 + NAME 'dnsipaddr' + EQUALITY numericStringMatch + SUBSTR numericStringSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.13 + NAME 'dnscipaddr' + EQUALITY numericStringMatch + SUBSTR numericStringSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} ) + +Thanks for the quick reply. Take care. + + diff --git a/Makefile b/Makefile index 459624b..05e29d5 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ -# $Id: Makefile,v 1.27 2001/08/09 10:35:49 jrief Exp $ -VERSION=0.2.6 +# $Id: Makefile,v 1.30 2003/01/20 14:33:25 jrief Exp $ +VERSION=0.3.4 RELEASE=1 CC=gcc -O2 +CCDEBUG=gcc -g CFLAGS=$(INC) -DVERSION='"$(VERSION)"' -OBJS=ldap2dns.o LIBS=-lldap -llber LD=gcc LDFLAGS= @@ -13,30 +13,37 @@ LDAPCONFDIR=$(INSTALL_PREFIX)/etc/openldap TARFILE=/usr/src/redhat/SOURCES/ldap2dns-$(VERSION).tar.gz SPECFILE=ldap2dns.spec -all: ldap2dns +all: ldap2dns ldap2dnsd ldap2dns-dbg -ldap2dns: $(OBJS) $(LIBS) - $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) +ldap2dns: ldap2dns.o $(LIBS) + $(LD) $(LDFLAGS) -o $@ $+ + +ldap2dnsd: ldap2dns ln -f ldap2dns ldap2dnsd +ldap2dns-dbg: ldap2dns.o-dbg $(LIBS) + $(LD) $(LDFLAGS) -o $@ $+ + ldap2dns.o: ldap2dns.c - $(CC) $(CFLAGS) -c $< + $(CC) $(CFLAGS) -c $< -o $@ + +ldap2dns.o-dbg: ldap2dns.c + $(CCDEBUG) $(CFLAGS) -c $< -o $@ install: all mkdir -p $(PREFIXDIR)/bin - mkdir -p $(LDAPCONFDIR) + mkdir -p $(LDAPCONFDIR)/schema install -s -o root -g root -m 755 ldap2dns $(PREFIXDIR)/bin/ ln -f $(PREFIXDIR)/bin/ldap2dns $(PREFIXDIR)/bin/ldap2dnsd install -o root -g root -m 755 ldap2tinydns-conf $(PREFIXDIR)/bin/ - install -o root -g root -m 644 dns.at.conf $(LDAPCONFDIR)/ - install -o root -g root -m 644 dns.oc.conf $(LDAPCONFDIR)/ + install -o root -g root -m 644 dns.schema $(LDAPCONFDIR)/schema/ clean: - rm -f $(OBJS) ldap2dns ldap2dnsd data* *.db core $(SPECFILE) + rm -f *.o *.o-dbg ldap2dns ldap2dnsd data* *.db core $(SPECFILE) tar: clean cd ..; \ - tar czf $(TARFILE) ldap2dns-$(VERSION) --exclude CVS --exclude DNSadmin + tar czf $(TARFILE) ldap2dns-$(VERSION) --exclude CVS $(SPECFILE): Specfile sed -e 's#%VERSION%#$(VERSION)#g' \ diff --git a/README.html b/README.html index 2eb03b6..161a655 100644 --- a/README.html +++ b/README.html @@ -195,8 +195,12 @@ include /etc/openldap/dns.at.conf include /etc/openldap/dns.oc.conf or, if You are using openldap-2.0.x:
-copy the file dns.schema into the directory /etc/openldap/schema or -appropriate and add the following line to Your slapd.conf file:
+copy the file dns.schema-2.0 into the directory /etc/openldap/schema +and rename it to dns.schema. +If You are using openldap-2.2.x:
+copy the file dns.schema-2.2 into the directory /etc/openldap/schema +and rename it to dns.schema. +Add the following line to Your slapd.conf file:
 include         /etc/openldap/schema/dns.schema
 
diff --git a/TODO.schema b/TODO.schema new file mode 100644 index 0000000..668aa32 --- /dev/null +++ b/TODO.schema @@ -0,0 +1 @@ +# schema for DNS data# include this file into Your slapd.conf for openldap-2.0.x# $Id: dns.schema,v 1.9 2001/11/06 08:01:51 config Exp $attributetype ( 1.3.6.1.4.1.7222.1.4.1 NAME 'dnszonename' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.2 NAME 'dnsserial' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.3 NAME 'dnsrefresh' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.4 NAME 'dnsretry' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.5 NAME 'dnsexpire' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.6 NAME 'dnsminimum' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.7 NAME 'dnsadminmailbox' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.8 NAME 'dnszonemaster' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.9 NAME 'dnstype' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.10 NAME 'dnsclass' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.11 NAME 'dnsdomainname' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.12 NAME 'dnsipaddr' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} ) SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.13 NAME 'dnscipaddr' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} )attributetype ( 1.3.6.1.4.1.7222.1.4.14 NAME 'dnscname' SUP name )attributetype ( 1.3.6.1.4.1.7222.1.4.15 NAME 'dnspreference' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.16 NAME 'dnsrr' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.17 NAME 'dnsttl' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.18 NAME 'dnstimestamp' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )attributetype ( 1.3.6.1.4.1.7222.1.4.21 NAME 'NIChandle' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} )attributetype ( 1.3.6.1.4.1.7222.1.4.22 NAME 'TIShandle' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} )objectclass ( 1.3.6.1.4.1.7222.1.4.19 NAME 'dnszone' MUST ( objectclass $ cn ) MAY ( dnszonename $ dnsserial $ dnsrefresh $ dnsretry $ dnsexpire $ dnsminimum $ dnsadminmailbox $ dnszonemaster $ dnstype $ dnsclass $ dnsttl $ dnstimestamp $ owner $ NIChandle $ TIShandle ) )objectclass ( 1.3.6.1.4.1.7222.1.4.20 NAME 'dnsrrset' SUP dnszone MUST ( objectclass $ cn ) MAY ( dnsdomainname $ dnsrr $ dnsclass $ dnstype $ dnsipaddr $ dnscipaddr $ dnscname $ dnspreference $ dnsttl $ dnstimestamp $ owner ) ) diff --git a/askldap.c b/askldap.c new file mode 100644 index 0000000..5d9f2da --- /dev/null +++ b/askldap.c @@ -0,0 +1,743 @@ +/* Patch for tinydns to pass DNS-query to LDAP in favour of a cdb lookup. + * $Id: askldap.c,v 1.8 2002/08/12 16:41:25 jrief Exp $ + * Copyright 2002 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "alloc.h" +#include "byte.h" +#include "response.h" +#include "askldap.h" +#include "dns.h" + +static LDAP* ldap_con; +static sigjmp_buf stack_context; + +static struct { + char ldaphosts[256]; + const char* basedn; + char binddn[256]; + char bindpwd[16]; + struct timeval timeout; + int verbose; + int initialized; +} options; + +struct zonerecord { + char zonedn[256]; + char zonename[64]; + char class[16]; + char type[16]; + char adminmailbox[64]; + char zonemaster[64]; + unsigned long serial, refresh, retry, expire, minimum; + int ttl; + int timestamp; +}; + +struct resourcerecord { + char qualifieddomainname[256]; + char class[16]; + char type[16]; + char ipaddr[8][4]; + int numipaddrs; + char cname[256]; + unsigned int preference; + int ttl; + int timestamp; + int additionalinfo; + struct resourcerecord* next; +}; + +enum { ASKLDAP_RETRY = 1, ASKLDAP_RETURN = 2, ASKLDAP_RECONNECT = 3 }; + +static +void assert_ldap(int err) +{ + static int retries; + switch (err) { + case LDAP_SUCCESS: + return; + case LDAP_TIMELIMIT_EXCEEDED: + fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); + retries++; + if (retries<3) + siglongjmp(stack_context, ASKLDAP_RETRY); + retries = 0; + siglongjmp(stack_context, ASKLDAP_RETURN); + case LDAP_TIMEOUT: + case LDAP_NO_SUCH_OBJECT: + fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); + siglongjmp(stack_context, ASKLDAP_RETURN); + case LDAP_BUSY: + case LDAP_UNAVAILABLE: + case LDAP_UNWILLING_TO_PERFORM: + case LDAP_SERVER_DOWN: + fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); + siglongjmp(stack_context, ASKLDAP_RECONNECT); + default: + fprintf(stderr, "Fatal error: %s\n", ldap_err2string(err)); +#ifdef _DEBUG + abort(); +#else + exit(1); +#endif + } +} + +void free_domainrecords(struct resourcerecord* anchor) +{ + struct resourcerecord* ptr; + for (ptr = anchor; ptr; ptr = anchor) { + anchor = anchor->next; + alloc_free(ptr); + } +} + +static +void fill_resourcerecord(struct resourcerecord* rr, LDAPMessage* m, const char* zonename) +{ + BerElement* ber = NULL; + char* attr; + + byte_zero(rr, sizeof(struct resourcerecord)); + strcpy(rr->class, "IN"); + for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { + struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); + if (bvals && bvals[0] && bvals[0]->bv_len>0) { + if (strcasecmp(attr, "dnsdomainname")==0) { + char tmp[64]; + if (sscanf(bvals[0]->bv_val, "%64s", tmp)==1) { + if (zonename[0]!='\0') + snprintf(rr->qualifieddomainname, 256, "%s.%s", tmp, zonename); + else + strncpy(rr->qualifieddomainname, tmp, 256); + } + } else if (strcasecmp(attr, "dnstype")==0) { + if (sscanf(bvals[0]->bv_val, "%16s", rr->type)!=1) { + rr->type[0] = '\0'; + } + } else if (strcasecmp(attr, "dnsipaddr")==0) { + int k, ip[4]; + for (k = 0; bvals[k] && k < 8-rr->numipaddrs; k++) { + if (sscanf(bvals[k]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { + rr->ipaddr[rr->numipaddrs][0] = (char)ip[0]; + rr->ipaddr[rr->numipaddrs][1] = (char)ip[1]; + rr->ipaddr[rr->numipaddrs][2] = (char)ip[2]; + rr->ipaddr[rr->numipaddrs][3] = (char)ip[3]; + rr->numipaddrs++; + } + } + } else if (rr->numipaddrs<8 && strcasecmp(attr, "dnscipaddr")==0) { + int ip[4]; + if (sscanf(bvals[0]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { + rr->ipaddr[rr->numipaddrs][0] = (char)ip[0]; + rr->ipaddr[rr->numipaddrs][1] = (char)ip[1]; + rr->ipaddr[rr->numipaddrs][2] = (char)ip[2]; + rr->ipaddr[rr->numipaddrs][3] = (char)ip[3]; + rr->numipaddrs++; + } + } else if (strcasecmp(attr, "dnscname")==0) { + if (sscanf(bvals[0]->bv_val, "%256s", rr->cname)==1) { + int len = strlen(rr->cname); + if (rr->cname[len-1]!='.' && zonename[0]!='\0') { + strcat(rr->cname, "."); + strncat(rr->cname, zonename, 252-len); + strcat(rr->cname, "."); + } + } else { + rr->cname[0] = '\0'; + } + } else if (strcasecmp(attr, "dnsttl")==0) { + if (sscanf(bvals[0]->bv_val, "%d", &rr->ttl)!=1) + rr->ttl = 0; + } else if (strcasecmp(attr, "dnstimestamp")==0) { + if (sscanf(bvals[0]->bv_val, "%d", &rr->timestamp)!=1) + rr->timestamp = 0; + } else if (strcasecmp(attr, "dnspreference")==0) { + if (sscanf(bvals[0]->bv_val, "%u", &rr->preference)!=1) + rr->preference = 1; + } + } + ldap_value_free_len(bvals); + } + if (rr->qualifieddomainname[0]=='\0') + strncpy(rr->qualifieddomainname, zonename, 256); +} + +static +void fill_zonerecord(struct zonerecord* zone, LDAPMessage* m) +{ + BerElement* ber = NULL; + char* attr; + + byte_zero(zone, sizeof(struct zonerecord)); + strcpy(zone->class, "IN"); + for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { + struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); + if (bvals && bvals[0] && bvals[0]->bv_len>0) { + if (strcasecmp(attr, "dnstype")==0) { + if (sscanf(bvals[0]->bv_val, "%16s", zone->type)!=1) + zone->type[0] = '\0'; + } else if (strcasecmp(attr, "dnsserial")==0) { + if (sscanf(bvals[0]->bv_val, "%lu", &zone->serial)!=1) + zone->serial = 0; + } else if (strcasecmp(attr, "dnsrefresh")==0) { + if (sscanf(bvals[0]->bv_val, "%lu", &zone->refresh)!=1) + zone->refresh = 0; + } else if (strcasecmp(attr, "dnsretry")==0) { + if (sscanf(bvals[0]->bv_val, "%lu", &zone->retry)!=1) + zone->retry = 0; + } else if (strcasecmp(attr, "dnsexpire")==0) { + if (sscanf(bvals[0]->bv_val, "%lu", &zone->expire)!=1) + zone->expire = 0; + } else if (strcasecmp(attr, "dnsminimum")==0) { + if (sscanf(bvals[0]->bv_val, "%lu", &zone->minimum)!=1) + zone->minimum = 0; + } else if (strcasecmp(attr, "dnsadminmailbox")==0) { + if (sscanf(bvals[0]->bv_val, "%64s", zone->adminmailbox)!=1) + zone->adminmailbox[0] = '\0'; + } else if (strcasecmp(attr, "dnszonemaster")==0) { + if (sscanf(bvals[0]->bv_val, "%64s", zone->zonemaster)!=1) + zone->zonemaster[0] = '\0'; + } else if (strcasecmp(attr, "dnsttl")==0) { + if (sscanf(bvals[0]->bv_val, "%d", &zone->ttl)!=1) + zone->ttl = 0; + } else if (strcasecmp(attr, "dnstimestamp")==0) { + if (sscanf(bvals[0]->bv_val, "%d", &zone->timestamp)!=1) + zone->timestamp = 0; + } else if (strcasecmp(attr, "dnszonename")==0) { + if (sscanf(bvals[0]->bv_val, "%s", zone->zonename)!=1) + zone->zonename[0] = '\0'; + } + } + ldap_value_free_len(bvals); + } +} + +static +int find_ipaddr(const char* queryname, char ip[4]) +{ + static char *rrattrs[] = { "dnsipaddr", "dnscipaddr", 0 }; + LDAPMessage* res = NULL; + LDAPMessage* m; + int ret = 0; + char filter[256], domainname[64]; + const char *zonename = queryname; + domainname[0] = '\0'; + while (*zonename) { + int len = snprintf(filter, 256, "(&(dnszonename=%s", zonename); + if (filter[len-1]=='.') + filter[len-1] = '\0'; + strncat(filter, ")(objectclass=dnszone)(dnsclass=IN))", 256-len); + assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + if (m = ldap_first_entry(ldap_con, res)) { + char* zonedn = ldap_get_dn(ldap_con, m); + if (ldap_next_entry(ldap_con, m)) + printf("Warning: ambigous zonename for %s in %s\n", zonename, zonedn); + if (domainname[0]!='\0') { + len = strlen(domainname); + if (domainname[len-1]=='.') + domainname[len-1] = '\0'; + snprintf(filter, 256, "(&(|(dnsdomainname=%s)(dnscname=%s))(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))", domainname, domainname); + } else { + strcpy(filter, "(&(!(dnsdomainname=*))(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))"); + } + ldap_msgfree(res); + assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + if (m = ldap_first_entry(ldap_con, res)) { + struct resourcerecord rr; + fill_resourcerecord(&rr, m, ""); + if (rr.numipaddrs>0) { + rr.numipaddrs = rand()%rr.numipaddrs; + ip[0] = rr.ipaddr[rr.numipaddrs][0]; + ip[1] = rr.ipaddr[rr.numipaddrs][1]; + ip[2] = rr.ipaddr[rr.numipaddrs][2]; + ip[3] = rr.ipaddr[rr.numipaddrs][3]; + ret = 1; + } + } + ldap_memfree(zonedn); + ldap_msgfree(res); res = NULL; + if (ret) + return 1; + break; + } + while (*zonename && *zonename!='.') { + domainname[zonename-queryname] = *zonename; + zonename++; + } + domainname[zonename-queryname] = *zonename; + if (*zonename=='.') { + zonename++; + domainname[zonename-queryname] = '\0'; + } + } + /* sometimes the queryname resolves directly as cname in some other records */ + snprintf(filter, 256, "(&(dnscname=%s)(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))", queryname); + assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + if (m = ldap_first_entry(ldap_con, res)) { + struct resourcerecord rr; + fill_resourcerecord(&rr, m, ""); + if (rr.numipaddrs>0) { + rr.numipaddrs = rand()%rr.numipaddrs; + ip[0] = rr.ipaddr[rr.numipaddrs][0]; + ip[1] = rr.ipaddr[rr.numipaddrs][1]; + ip[2] = rr.ipaddr[rr.numipaddrs][2]; + ip[3] = rr.ipaddr[rr.numipaddrs][3]; + ret = 1; + } + } + ldap_msgfree(res); + return ret; +} + +static +struct resourcerecord* find_reverserecord(const char* queryname, int ip[4]) +{ + static char *rrattrs[] = { "dnstype", "dnsdomainname", "dnscname", "dnsttl", 0 }; + LDAPMessage* res = NULL; + struct resourcerecord* rr = NULL; + LDAPMessage* m; + char filter[256]; + snprintf(filter, 256, "(&(dnscipaddr=%u.%u.%u.%u)(objectclass=dnsrrset)(dnsclass=IN))", ip[0], ip[1], ip[2], ip[3]); + assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + if (m = ldap_first_entry(ldap_con, res)) { + char* rrsetdn = ldap_get_dn(ldap_con, m); + char** explodedn = NULL; + + rr = (void*)alloc(sizeof(struct resourcerecord)); + fill_resourcerecord(rr, m, ""); + if (ldap_next_entry(ldap_con, m)) + printf("Warning: ambigous IP-address for %u.%u.%u.%u in dn: %s\n", ip[0], ip[1], ip[2], ip[3], rrsetdn); + explodedn = ldap_explode_dn(rrsetdn, 0); + if (explodedn[0]) { + static char *zoneattrs[] = { "dnszonename", 0 }; + char zonedn[256]; + int i, len = 0; + struct zonerecord zone; + + zonedn[0] = '\0'; + for (i = 1; explodedn[i]; i++) + len += snprintf(zonedn+len, 256-len, "%s,", explodedn[i]); + zonedn[len-1] = '\0'; + ldap_msgfree(res); + assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, "(objectclass=dnszone)", zoneattrs, 0, &options.timeout, &res)); + m = ldap_first_entry(ldap_con, res); + if (m==NULL) + printf("Error: parent dn: %s not found for %s\n", zonedn, rrsetdn); + fill_zonerecord(&zone, m); + len = strlen(rr->qualifieddomainname); + if (len==0) { + len = strlen(rr->cname); + if (rr->cname[len-1]!='.') { + strcat(rr->cname, "."); + strncat(rr->cname, zone.zonename, 252-len); + } + } else { + /* in those situations where a dnsrrset + * defines something like MX or NS for a zone + * and also sets a canonical name for the + * service. */ + snprintf(rr->cname, 256, "%s.%s", rr->qualifieddomainname, zone.zonename); + } + strcpy(rr->type, "PTR"); + strncpy(rr->qualifieddomainname, queryname, 256); + } + ldap_memfree(rrsetdn); + ldap_value_free(explodedn); + } + ldap_msgfree(res); + return rr; +} + +static +struct resourcerecord* read_domainrecords(const char* zonedn, const char* domainname, const char* zonename) +{ + static char *rrattrs[] = { "dnsdomainname", "dnstype", "dnsttl", "dnscname", "dnsipaddr", "dnscipaddr", "dnstimestamp", "dnspreference", 0 }; + LDAPMessage* res = NULL; + LDAPMessage* m; + char filter[256]; + struct resourcerecord *prev, *anchor = NULL; + + if (domainname[0]) { + if (strstr(zonename, "in-addr.arpa")) { + unsigned int ip[4]; + char queryname[256]; + snprintf(queryname, 256, "%s.%s", domainname, zonename); + if (sscanf(queryname, "%3u.%3u.%3u.%3u", &ip[3], &ip[2], &ip[1], &ip[0])!=4) + return NULL; + snprintf(filter, 256, "(&(dnsipaddr=%u.%u.%u.%u)(objectclass=dnsrrset)(dnsclass=IN))", ip[0], ip[1], ip[2], ip[3]); + assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + if (m = ldap_first_entry(ldap_con, res)) { + struct resourcerecord* rr; + rr = (void*)alloc(sizeof(struct resourcerecord)); + fill_resourcerecord(rr, m, zonename); + strncpy(rr->qualifieddomainname, queryname, 256); + ldap_msgfree(res); + return rr; + } else { + /* ipaddr not in our baliwick, search the whole tree for canonical ipaddr */ + ldap_msgfree(res); + return find_reverserecord(queryname, ip); + } + } else { + snprintf(filter, 256, "(&(dnsdomainname=%s)(objectclass=dnsrrset)(dnsclass=IN))", domainname); + assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + } + } else { + snprintf(filter, 256, "(&(!(dnsdomainname=*))(objectclass=dnsrrset)(dnsclass=IN))"); + assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); + } + for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { + struct resourcerecord* rr; + rr = (void*)alloc(sizeof(struct resourcerecord)); + fill_resourcerecord(rr, m, zonename); + if (anchor==NULL) { + prev = anchor = rr; + } else { + prev->next = rr; + prev = rr; + } + if (options.verbose&1) + printf("\trr: %s %s\n", domainname, rr->type); + } + ldap_msgfree(res); + return anchor; +} + +static +int read_dnszone(struct zonerecord* zone, const char* zonename) +{ + static char *zoneattrs[] = { "dnszonename", "dnstype", "dnsserial", "dnsrefresh", "dnsretry", "dnsexpire", "dnsminimum", "dnszonemaster", "dnsadminmailbox", "dnsttl", "dnstimestamp", 0 }; + LDAPMessage* res = NULL; + LDAPMessage* m; + char* dn; + char filter[256]; + + snprintf(filter, 256, "(&(dnszonename=%s)(objectclass=dnszone)(dnsclass=IN))", zonename); + assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, zoneattrs, 0, &options.timeout, &res)); + m = ldap_first_entry(ldap_con, res); + if (m==NULL) { + ldap_msgfree(res); + return 0; + } + dn = ldap_get_dn(ldap_con, m); + fill_zonerecord(zone, m); + m = ldap_next_entry(ldap_con, m); + if (m) { + char* otherdn = ldap_get_dn(ldap_con, m); + printf("Warning: ambigous zonename found in dn: %s and dn: %s\n", dn, otherdn); + ldap_memfree(otherdn); + } + strncpy(zone->zonedn, dn, 256); + ldap_memfree(dn); + ldap_msgfree(res); + return 1; +} + +static +void djb_name(const char* dotname, char* djbname) +{ + const char* c = dotname; + int i, k; + for (i = 0; *c; c++) { + k = i; + while (*c!='.') { + k++; + djbname[k] = *c; + if (*c=='\0') { + djbname[i] = k-i-1; + return; + } + c++; + } + djbname[i] = k-i; + i = k+1; + } + djbname[i] = '\0'; +} + +static +void djb_type(const char* dottype, char djbtype[2]) +{ + djbtype[0] = '\0'; + if (strcasecmp(dottype, "A")==0) + djbtype[1] = 001; + else if (strcasecmp(dottype, "NS")==0) + djbtype[1] = 002; + else if (strcasecmp(dottype, "CNAME")==0) + djbtype[1] = 005; + else if (strcasecmp(dottype, "SOA")==0) + djbtype[1] = 006; + else if (strcasecmp(dottype, "PTR")==0) + djbtype[1] = 014; + else if (strcasecmp(dottype, "MX")==0) + djbtype[1] = 017; + else if (strcasecmp(dottype, "TXT")==0) + djbtype[1] = 020; +} + +static +void split_djbstyle(const char* djbname, char* domainname, char* zonename, int offset) +{ + int i, k, m = 0, n = 0; + for (i = *djbname; i; i = *++djbname) { + if (offset>0) { + offset--; + for (k = m; k0 ? m-1 : 0] = '\0'; + zonename[n>0 ? n-1 : 0] = '\0'; +} + +static +void build_response_section(struct resourcerecord *rr, char qtype[2], int section) +{ + char djbname[256], djbtype[2]; + djb_name(rr->qualifieddomainname, djbname); + djb_type(rr->type, djbtype); + if (byte_equal(djbtype, 2, DNS_T_A)) { + if (byte_equal(qtype, 2, DNS_T_A) || byte_equal(qtype, 2, DNS_T_ANY)) { + response_rstart(djbname, djbtype, rr->ttl); + response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); + response_rfinish(section); + } + } else if (byte_equal(djbtype, 2, DNS_T_CNAME)) { + response_rstart(djbname, djbtype, rr->ttl); + djb_name(rr->cname, djbname); + response_addname(djbname); + response_rfinish(section); + } else if (byte_equal(djbtype, 2, DNS_T_NS)) { + if (byte_equal(qtype, 2, DNS_T_NS) || byte_equal(qtype, 2, DNS_T_ANY)) { + response_rstart(djbname, djbtype, rr->ttl); + if (rr->cname[0]) { + djb_name(rr->cname, djbname); + response_addname(djbname); + rr->additionalinfo = 1; + } else { + response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); + } + response_rfinish(section); + } + } else if (byte_equal(djbtype, 2, DNS_T_PTR)) { + response_rstart(djbname, djbtype, rr->ttl); + djb_name(rr->cname, djbname); + response_addname(djbname); + response_rfinish(section); + } else if (byte_equal(djbtype, 2, DNS_T_MX)) { + if (byte_equal(qtype, 2, DNS_T_MX) || byte_equal(qtype, 2, DNS_T_ANY)) { + char tmp[2]; + response_rstart(djbname, djbtype, rr->ttl); + tmp[0] = rr->preference/0x100; + tmp[1] = rr->preference%0x100; + response_addbytes(tmp, 2); + if (rr->cname[0]) { + djb_name(rr->cname, djbname); + response_addname(djbname); + rr->additionalinfo = 1; + } else { + response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); + } + response_rfinish(section); + } + } +} + +static +void build_soa_section(struct zonerecord *zone, int section) +{ + time_t now; + char defaultsoa[20]; + char djbname[256]; + char zonesoa[20]; + unsigned long tmp; + time(&now); + djb_name(zone->zonename, djbname); + response_rstart(djbname, DNS_T_SOA, zone->ttl); + djb_name(zone->zonemaster, djbname); + response_addname(djbname); + djb_name(zone->adminmailbox, djbname); + response_addname(djbname); + uint32_pack_big(defaultsoa, now); + if (byte_equal(defaultsoa,4,"\0\0\0\0")) + defaultsoa[3] = 1; + byte_copy(defaultsoa + 4, 16, "\0\0\100\000\0\0\010\000\0\020\000\000\0\0\012\000"); + if (zone->serial==0) + uint32_unpack_big(defaultsoa, &tmp); + else + tmp = zone->serial; + uint32_pack_big(zonesoa, tmp); + if (zone->refresh==0) + uint32_unpack_big(defaultsoa+4, &tmp); + else + tmp = zone->refresh; + uint32_pack_big(zonesoa+4, tmp); + if (zone->retry==0) + uint32_unpack_big(defaultsoa+8, &tmp); + else + tmp = zone->retry; + uint32_pack_big(zonesoa+8, tmp); + if (zone->expire==0) + uint32_unpack_big(defaultsoa+12, &tmp); + else + tmp = zone->expire; + uint32_pack_big(zonesoa+12, tmp); + if (zone->minimum==0) + uint32_unpack_big(defaultsoa+16, &tmp); + else + tmp = zone->minimum; + uint32_pack_big(zonesoa+16, tmp); + response_addbytes(zonesoa, 20); + response_rfinish(section); +} + +static +void build_additional_section(struct resourcerecord *rr) +{ + char djbname[256], ip[4]; + if (rr->additionalinfo && find_ipaddr(rr->cname, ip)) { + djb_name(rr->cname, djbname); + response_rstart(djbname, DNS_T_A, rr->ttl); + response_addbytes(ip, 4); + response_rfinish(RESPONSE_ADDITIONAL); + } +} + +static +int connect_and_bind() +{ + ldap_con = ldap_init(options.ldaphosts, LDAP_PORT); + if (ldap_simple_bind_s(ldap_con, options.binddn, options.bindpwd)==LDAP_SUCCESS) { + printf("Connected to %s as \"%s\"\n", options.ldaphosts, options.binddn); + return 1; + } + ldap_con = NULL; + return 0; +} + +int askldap_query(const char* djbdomainname, char qtype[2]) +{ + int offset; + char domainname[64], zonename[64]; + struct zonerecord zoneinfo; + int answer_ok = 0, flagsoa = 0, flagns = 0; + if (!options.initialized) + return 0; + switch (sigsetjmp(stack_context, 1)) { + default: + if (ldap_con==NULL && !connect_and_bind()) + return answer_ok; + break; + case ASKLDAP_RECONNECT: + if (connect_and_bind()) + break; + return answer_ok; + case ASKLDAP_RETURN: + return answer_ok; + } + for (offset = 0; offset<32; offset++) { + struct resourcerecord *rransw, *rrauth, *rr; + + split_djbstyle(djbdomainname, domainname, zonename, offset); + if (zonename[0]=='\0') return 0; + if (!read_dnszone(&zoneinfo, zonename)) + continue; + rransw = read_domainrecords(zoneinfo.zonedn, domainname, zonename); + rrauth = NULL; + if (offset==0) { + /* query is in our bailiwick */ + if (byte_equal(qtype, 2, DNS_T_ANY) || byte_equal(qtype, 2, DNS_T_SOA)) { + build_soa_section(&zoneinfo, RESPONSE_ANSWER); + flagsoa = 1; + } + for (rr = rransw; rr; rr = rr->next) { + build_response_section(rr, qtype, RESPONSE_ANSWER); + answer_ok = 1; + } + if (!flagsoa) { + build_soa_section(&zoneinfo, RESPONSE_AUTHORITY); + flagsoa = 1; + } + if (!byte_equal(qtype, 2, DNS_T_ANY) && !byte_equal(qtype, 2, DNS_T_NS)) { + for (rr = rransw; rr; rr = rr->next) + if (strcmp(rr->type, "NS")==0) { + build_response_section(rr, DNS_T_NS, RESPONSE_AUTHORITY); + flagns = 1; + } + } + } else { + for (rr = rransw; rr; rr = rr->next) { + if (strcmp(rr->type, "NS")==0) { + build_response_section(rr, qtype, RESPONSE_AUTHORITY); + flagns = 1; + } + } + if (!flagns) { + for (rr = rransw; rr; rr = rr->next) { + build_response_section(rr, qtype, RESPONSE_ANSWER); + answer_ok = 1; + } + if (answer_ok) { + rrauth = read_domainrecords(zoneinfo.zonedn, "", zonename); + } else { + build_soa_section(&zoneinfo, RESPONSE_AUTHORITY); + flagsoa = 1; + } + } + for (rr = rrauth; rr; rr = rr->next) { + if (strcmp(rr->type, "NS")==0) { + build_response_section(rr, DNS_T_NS, RESPONSE_AUTHORITY); + flagns = 1; + } + } + } + for (rr = rransw; rr; rr = rr->next) + build_additional_section(rr); + for (rr = rrauth; rr; rr = rr->next) + build_additional_section(rr); + free_domainrecords(rransw); + free_domainrecords(rrauth); + break; + } + return answer_ok || flagsoa || flagns; +} + +void askldap_init(const char* ldaphost, const char* basedn, const char* binddn, const char* passwd) +{ + strncpy(options.ldaphosts, ldaphost, 256); + options.basedn = basedn; + if (binddn) strncpy(options.binddn, binddn, 256); + if (passwd) strncpy(options.bindpwd, passwd, 16); + /* LDAP timeout is hardcoded to 2/10 second. + * This must be enough because bindoperations usually + * timeout after one second and here we usually have to + * send five queries to the LDAP-server */ + options.timeout.tv_sec = 1; + options.timeout.tv_usec = 200000; + options.verbose = 0; + options.initialized = 1; + connect_and_bind(); +} + diff --git a/askldap.h b/askldap.h new file mode 100644 index 0000000..1338808 --- /dev/null +++ b/askldap.h @@ -0,0 +1,10 @@ +/* Patch for tinydns to pass DNS-query to LDAP in favour of a cdb lookup. + * $Id: askldap.h,v 1.8 2002/08/12 16:41:25 jrief Exp $ + * Copyright 2002 + */ + +extern +int askldap_query(const char* djbdomainname, char qtype[2]); + +extern +void askldap_init(const char* ldaphost, const char* basedn, const char* binddn, const char* passwd); diff --git a/djbdns-1.0.5.patch b/djbdns-1.0.5.patch new file mode 100644 index 0000000..ad6cb2f --- /dev/null +++ b/djbdns-1.0.5.patch @@ -0,0 +1,972 @@ +diff -Naur djbdns-1.05.orig/Makefile djbdns-1.05/Makefile +--- djbdns-1.05.orig/Makefile Sun Feb 11 22:11:45 2001 ++++ djbdns-1.05/Makefile Tue Aug 13 14:28:52 2002 +@@ -1,9 +1,6 @@ +-# Don't edit Makefile! Use conf-* for configuration. +- +-SHELL=/bin/sh +- + default: it + ++ + alloc.a: \ + makelib alloc.o alloc_re.o getln.o getln2.o stralloc_cat.o \ + stralloc_catb.o stralloc_cats.o stralloc_copy.o stralloc_eady.o \ +@@ -55,8 +52,8 @@ + prot.o timeoutread.o timeoutwrite.o dns.a libtai.a alloc.a env.a \ + cdb.a buffer.a unix.a byte.a + ./load axfrdns iopause.o droproot.o tdlookup.o response.o \ +- qlog.o prot.o timeoutread.o timeoutwrite.o dns.a libtai.a \ +- alloc.a env.a cdb.a buffer.a unix.a byte.a ++ qlog.o prot.o timeoutread.o timeoutwrite.o askldap.o dns.a libtai.a \ ++ alloc.a env.a cdb.a buffer.a unix.a byte.a `cat ldap.lib` + + axfrdns-conf: \ + load axfrdns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a +@@ -626,11 +623,11 @@ + ./compile parsetype.c + + pickdns: \ +-load pickdns.o server.o response.o droproot.o qlog.o prot.o dns.a \ ++load pickdns.o server.o response.o droproot.o qlog.o prot.o askldap.o dns.a \ + env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib + ./load pickdns server.o response.o droproot.o qlog.o \ +- prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \ +- byte.a `cat socket.lib` ++ prot.o askldap.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \ ++ byte.a `cat socket.lib` `cat ldap.lib` + + pickdns-conf: \ + load pickdns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a +@@ -704,11 +701,11 @@ + ./compile random-ip.c + + rbldns: \ +-load rbldns.o server.o response.o dd.o droproot.o qlog.o prot.o dns.a \ ++load rbldns.o server.o response.o dd.o droproot.o qlog.o prot.o askldap.o dns.a \ + env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib + ./load rbldns server.o response.o dd.o droproot.o qlog.o \ +- prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \ +- byte.a `cat socket.lib` ++ prot.o askldap.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \ ++ byte.a `cat socket.lib` `cat ldap.lib` + + rbldns-conf: \ + load rbldns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a +@@ -792,6 +789,9 @@ + && echo -lsocket -lnsl || exit 0 ) > socket.lib + rm -f trylsock.o trylsock + ++ldap.lib: ++ echo -lldap -llber > ldap.lib ++ + socket_accept.o: \ + compile socket_accept.c byte.h socket.h uint16.h + ./compile socket_accept.c +@@ -978,13 +978,17 @@ + timeoutwrite.h + ./compile timeoutwrite.c + ++askldap.o: \ ++compile askldap.c askldap.h ++ ./compile askldap.c ++ + tinydns: \ + load tinydns.o server.o droproot.o tdlookup.o response.o qlog.o \ +-prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a byte.a \ +-socket.lib ++prot.o askldap.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a byte.a \ ++socket.lib ldap.lib + ./load tinydns server.o droproot.o tdlookup.o response.o \ +- qlog.o prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a \ +- unix.a byte.a `cat socket.lib` ++ qlog.o prot.o askldap.o dns.a libtai.a env.a cdb.a alloc.a buffer.a \ ++ unix.a byte.a `cat socket.lib` `cat ldap.lib` + + tinydns-conf: \ + load tinydns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a +@@ -1015,26 +1019,26 @@ + tinydns-edit.o: \ + compile tinydns-edit.c stralloc.h gen_alloc.h buffer.h exit.h open.h \ + getln.h buffer.h stralloc.h strerr.h scan.h byte.h str.h fmt.h ip4.h \ +-dns.h stralloc.h iopause.h taia.h tai.h uint64.h taia.h ++dns.h stralloc.h iopause.h taia.h tai.h uint64.h taia.h askldap.h + ./compile tinydns-edit.c + + tinydns-get: \ + load tinydns-get.o tdlookup.o response.o printpacket.o printrecord.o \ + parsetype.o dns.a libtai.a cdb.a buffer.a alloc.a unix.a byte.a + ./load tinydns-get tdlookup.o response.o printpacket.o \ +- printrecord.o parsetype.o dns.a libtai.a cdb.a buffer.a \ +- alloc.a unix.a byte.a ++ printrecord.o parsetype.o askldap.o dns.a libtai.a cdb.a buffer.a \ ++ alloc.a unix.a byte.a `cat ldap.lib` + + tinydns-get.o: \ + compile tinydns-get.c str.h byte.h scan.h exit.h stralloc.h \ + gen_alloc.h buffer.h strerr.h uint16.h response.h uint32.h case.h \ + printpacket.h stralloc.h parsetype.h ip4.h dns.h stralloc.h iopause.h \ +-taia.h tai.h uint64.h taia.h ++taia.h tai.h uint64.h taia.h askldap.h + ./compile tinydns-get.c + + tinydns.o: \ + compile tinydns.c dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h \ +-uint64.h taia.h ++uint64.h taia.h askldap.h + ./compile tinydns.c + + uint16_pack.o: \ +@@ -1084,11 +1088,11 @@ + ./compile utime.c + + walldns: \ +-load walldns.o server.o response.o droproot.o qlog.o prot.o dd.o \ ++load walldns.o server.o response.o droproot.o qlog.o prot.o dd.o askldap.o \ + dns.a env.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib + ./load walldns server.o response.o droproot.o qlog.o \ +- prot.o dd.o dns.a env.a cdb.a alloc.a buffer.a unix.a \ +- byte.a `cat socket.lib` ++ prot.o dd.o askldap.o dns.a env.a cdb.a alloc.a buffer.a unix.a \ ++ byte.a `cat socket.lib` `cat ldap.lib` + + walldns-conf: \ + load walldns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a +diff -Naur djbdns-1.05.orig/askldap.c djbdns-1.05/askldap.c +--- djbdns-1.05.orig/askldap.c Thu Jan 1 01:00:00 1970 ++++ djbdns-1.05/askldap.c Tue Aug 13 14:30:18 2002 +@@ -0,0 +1,750 @@ ++/* Patch for tinydns to pass DNS-query to LDAP in favour of a cdb lookup. ++ * $Id$ ++ * Copyright 2002 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "alloc.h" ++#include "byte.h" ++#include "response.h" ++#include "askldap.h" ++#include "dns.h" ++ ++static LDAP* ldap_con; ++static sigjmp_buf stack_context; ++ ++static struct { ++ char ldaphosts[256]; ++ const char* basedn; ++ char binddn[256]; ++ char bindpwd[16]; ++ struct timeval timeout; ++ int verbose; ++ int initialized; ++} options; ++ ++struct zonerecord { ++ char zonedn[256]; ++ char zonename[64]; ++ char class[16]; ++ char type[16]; ++ char adminmailbox[64]; ++ char zonemaster[64]; ++ unsigned long serial, refresh, retry, expire, minimum; ++ int ttl; ++ int timestamp; ++}; ++ ++struct resourcerecord { ++ char qualifieddomainname[256]; ++ char class[16]; ++ char type[16]; ++ char ipaddr[8][4]; ++ int numipaddrs; ++ char cname[256]; ++ unsigned int preference; ++ int ttl; ++ int timestamp; ++ int additionalinfo; ++ struct resourcerecord* next; ++}; ++ ++enum { ASKLDAP_RETRY = 1, ASKLDAP_RETURN = 2, ASKLDAP_RECONNECT = 3 }; ++ ++static ++void assert_ldap(int err) ++{ ++ static int retries; ++ switch (err) { ++ case LDAP_SUCCESS: ++ return; ++ case LDAP_TIMELIMIT_EXCEEDED: ++ fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); ++ retries++; ++ if (retries<3) ++ siglongjmp(stack_context, ASKLDAP_RETRY); ++ retries = 0; ++ siglongjmp(stack_context, ASKLDAP_RETURN); ++ case LDAP_TIMEOUT: ++ case LDAP_NO_SUCH_OBJECT: ++ fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); ++ siglongjmp(stack_context, ASKLDAP_RETURN); ++ case LDAP_BUSY: ++ case LDAP_UNAVAILABLE: ++ case LDAP_UNWILLING_TO_PERFORM: ++ case LDAP_SERVER_DOWN: ++ fprintf(stderr, "Warning: %s\n", ldap_err2string(err)); ++ siglongjmp(stack_context, ASKLDAP_RECONNECT); ++ default: ++ fprintf(stderr, "Fatal error: %s\n", ldap_err2string(err)); ++#ifdef _DEBUG ++ abort(); ++#else ++ exit(1); ++#endif ++ } ++} ++ ++void free_domainrecords(struct resourcerecord* anchor) ++{ ++ struct resourcerecord* ptr; ++ for (ptr = anchor; ptr; ptr = anchor) { ++ anchor = anchor->next; ++ alloc_free(ptr); ++ } ++} ++ ++static ++void fill_resourcerecord(struct resourcerecord* rr, LDAPMessage* m, const char* zonename) ++{ ++ BerElement* ber = NULL; ++ char* attr; ++ ++ byte_zero(rr, sizeof(struct resourcerecord)); ++ strcpy(rr->class, "IN"); ++ for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { ++ struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); ++ if (bvals && bvals[0] && bvals[0]->bv_len>0) { ++ if (strcasecmp(attr, "dnsdomainname")==0) { ++ char tmp[64]; ++ if (sscanf(bvals[0]->bv_val, "%64s", tmp)==1) { ++ if (zonename[0]!='\0') ++ snprintf(rr->qualifieddomainname, 256, "%s.%s", tmp, zonename); ++ else ++ strncpy(rr->qualifieddomainname, tmp, 256); ++ } ++ } else if (strcasecmp(attr, "dnstype")==0) { ++ if (sscanf(bvals[0]->bv_val, "%16s", rr->type)!=1) { ++ rr->type[0] = '\0'; ++ } ++ } else if (strcasecmp(attr, "dnsipaddr")==0) { ++ int k, ip[4]; ++ for (k = 0; bvals[k] && k < 8-rr->numipaddrs; k++) { ++ if (sscanf(bvals[k]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { ++ rr->ipaddr[rr->numipaddrs][0] = (char)ip[0]; ++ rr->ipaddr[rr->numipaddrs][1] = (char)ip[1]; ++ rr->ipaddr[rr->numipaddrs][2] = (char)ip[2]; ++ rr->ipaddr[rr->numipaddrs][3] = (char)ip[3]; ++ rr->numipaddrs++; ++ } ++ } ++ } else if (rr->numipaddrs<8 && strcasecmp(attr, "dnscipaddr")==0) { ++ int ip[4]; ++ if (sscanf(bvals[0]->bv_val, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3])==4) { ++ rr->ipaddr[rr->numipaddrs][0] = (char)ip[0]; ++ rr->ipaddr[rr->numipaddrs][1] = (char)ip[1]; ++ rr->ipaddr[rr->numipaddrs][2] = (char)ip[2]; ++ rr->ipaddr[rr->numipaddrs][3] = (char)ip[3]; ++ rr->numipaddrs++; ++ } ++ } else if (strcasecmp(attr, "dnscname")==0) { ++ if (sscanf(bvals[0]->bv_val, "%256s", rr->cname)==1) { ++ int len = strlen(rr->cname); ++ if (rr->cname[len-1]!='.' && zonename[0]!='\0') { ++ strcat(rr->cname, "."); ++ strncat(rr->cname, zonename, 252-len); ++ strcat(rr->cname, "."); ++ } ++ } else { ++ rr->cname[0] = '\0'; ++ } ++ } else if (strcasecmp(attr, "dnsttl")==0) { ++ if (sscanf(bvals[0]->bv_val, "%d", &rr->ttl)!=1) ++ rr->ttl = 0; ++ } else if (strcasecmp(attr, "dnstimestamp")==0) { ++ if (sscanf(bvals[0]->bv_val, "%d", &rr->timestamp)!=1) ++ rr->timestamp = 0; ++ } else if (strcasecmp(attr, "dnspreference")==0) { ++ if (sscanf(bvals[0]->bv_val, "%u", &rr->preference)!=1) ++ rr->preference = 1; ++ } ++ } ++ ldap_value_free_len(bvals); ++ } ++} ++ ++static ++void fill_zonerecord(struct zonerecord* zone, LDAPMessage* m) ++{ ++ BerElement* ber = NULL; ++ char* attr; ++ ++ byte_zero(zone, sizeof(struct zonerecord)); ++ strcpy(zone->class, "IN"); ++ for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { ++ struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); ++ if (bvals && bvals[0] && bvals[0]->bv_len>0) { ++ if (strcasecmp(attr, "dnstype")==0) { ++ if (sscanf(bvals[0]->bv_val, "%16s", zone->type)!=1) ++ zone->type[0] = '\0'; ++ } else if (strcasecmp(attr, "dnsserial")==0) { ++ if (sscanf(bvals[0]->bv_val, "%lu", &zone->serial)!=1) ++ zone->serial = 0; ++ } else if (strcasecmp(attr, "dnsrefresh")==0) { ++ if (sscanf(bvals[0]->bv_val, "%lu", &zone->refresh)!=1) ++ zone->refresh = 0; ++ } else if (strcasecmp(attr, "dnsretry")==0) { ++ if (sscanf(bvals[0]->bv_val, "%lu", &zone->retry)!=1) ++ zone->retry = 0; ++ } else if (strcasecmp(attr, "dnsexpire")==0) { ++ if (sscanf(bvals[0]->bv_val, "%lu", &zone->expire)!=1) ++ zone->expire = 0; ++ } else if (strcasecmp(attr, "dnsminimum")==0) { ++ if (sscanf(bvals[0]->bv_val, "%lu", &zone->minimum)!=1) ++ zone->minimum = 0; ++ } else if (strcasecmp(attr, "dnsadminmailbox")==0) { ++ if (sscanf(bvals[0]->bv_val, "%64s", zone->adminmailbox)!=1) ++ zone->adminmailbox[0] = '\0'; ++ } else if (strcasecmp(attr, "dnszonemaster")==0) { ++ if (sscanf(bvals[0]->bv_val, "%64s", zone->zonemaster)!=1) ++ zone->zonemaster[0] = '\0'; ++ } else if (strcasecmp(attr, "dnsttl")==0) { ++ if (sscanf(bvals[0]->bv_val, "%d", &zone->ttl)!=1) ++ zone->ttl = 0; ++ } else if (strcasecmp(attr, "dnstimestamp")==0) { ++ if (sscanf(bvals[0]->bv_val, "%d", &zone->timestamp)!=1) ++ zone->timestamp = 0; ++ } else if (strcasecmp(attr, "dnszonename")==0) { ++ if (sscanf(bvals[0]->bv_val, "%s", zone->zonename)!=1) ++ zone->zonename[0] = '\0'; ++ } ++ } ++ ldap_value_free_len(bvals); ++ } ++} ++ ++static ++int find_ipaddr(const char* queryname, char ip[4]) ++{ ++ static char *rrattrs[] = { "dnsipaddr", "dnscipaddr", 0 }; ++ LDAPMessage* res = NULL; ++ LDAPMessage* m; ++ int ret = 0; ++ char filter[256], domainname[64]; ++ const char *zonename = queryname; ++ domainname[0] = '\0'; ++ while (*zonename) { ++ int len = snprintf(filter, 256, "(&(dnszonename=%s", zonename); ++ if (filter[len-1]=='.') ++ filter[len-1] = '\0'; ++ strncat(filter, ")(objectclass=dnszone)(dnsclass=IN))", 256-len); ++ assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (m = ldap_first_entry(ldap_con, res)) { ++ char* zonedn = ldap_get_dn(ldap_con, m); ++ if (ldap_next_entry(ldap_con, m)) ++ printf("Warning: ambigous zonename for %s in %s\n", zonename, zonedn); ++ if (domainname[0]!='\0') { ++ len = strlen(domainname); ++ if (domainname[len-1]=='.') ++ domainname[len-1] = '\0'; ++ snprintf(filter, 256, "(&(|(dnsdomainname=%s)(dnscname=%s))(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))", domainname, domainname); ++ } else { ++ strcpy(filter, "(&(!(dnsdomainname=*))(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))"); ++ } ++ ldap_msgfree(res); ++ assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (m = ldap_first_entry(ldap_con, res)) { ++ struct resourcerecord rr; ++ fill_resourcerecord(&rr, m, ""); ++ if (rr.numipaddrs>0) { ++ rr.numipaddrs = rand()%rr.numipaddrs; ++ ip[0] = rr.ipaddr[rr.numipaddrs][0]; ++ ip[1] = rr.ipaddr[rr.numipaddrs][1]; ++ ip[2] = rr.ipaddr[rr.numipaddrs][2]; ++ ip[3] = rr.ipaddr[rr.numipaddrs][3]; ++ ret = 1; ++ } ++ } ++ ldap_memfree(zonedn); ++ ldap_msgfree(res); res = NULL; ++ if (ret) ++ return 1; ++ break; ++ } ++ while (*zonename && *zonename!='.') { ++ domainname[zonename-queryname] = *zonename; ++ zonename++; ++ } ++ domainname[zonename-queryname] = *zonename; ++ if (*zonename=='.') { ++ zonename++; ++ domainname[zonename-queryname] = '\0'; ++ } ++ } ++ /* sometimes the queryname resolves directly as cname in some other records */ ++ snprintf(filter, 256, "(&(dnscname=%s)(objectclass=dnsrrset)(dnsclass=IN)(|(dnsipaddr=*)(dnscipaddr=*)))", queryname); ++ assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (m = ldap_first_entry(ldap_con, res)) { ++ struct resourcerecord rr; ++ fill_resourcerecord(&rr, m, ""); ++ if (rr.numipaddrs>0) { ++ rr.numipaddrs = rand()%rr.numipaddrs; ++ ip[0] = rr.ipaddr[rr.numipaddrs][0]; ++ ip[1] = rr.ipaddr[rr.numipaddrs][1]; ++ ip[2] = rr.ipaddr[rr.numipaddrs][2]; ++ ip[3] = rr.ipaddr[rr.numipaddrs][3]; ++ ret = 1; ++ } ++ } ++ ldap_msgfree(res); ++ return ret; ++} ++ ++static ++struct resourcerecord* find_reverserecord(const char* queryname, int ip[4]) ++{ ++ static char *rrattrs[] = { "dnstype", "dnsdomainname", "dnscname", "dnsttl", 0 }; ++ LDAPMessage* res = NULL; ++ struct resourcerecord* rr = NULL; ++ LDAPMessage* m; ++ char filter[256]; ++ snprintf(filter, 256, "(&(dnscipaddr=%u.%u.%u.%u)(objectclass=dnsrrset)(dnsclass=IN))", ip[0], ip[1], ip[2], ip[3]); ++ assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (m = ldap_first_entry(ldap_con, res)) { ++ char* rrsetdn = ldap_get_dn(ldap_con, m); ++ char** explodedn = NULL; ++ ++ rr = (void*)alloc(sizeof(struct resourcerecord)); ++ fill_resourcerecord(rr, m, ""); ++ if (ldap_next_entry(ldap_con, m)) ++ printf("Warning: ambigous IP-address for %u.%u.%u.%u in dn: %s\n", ip[0], ip[1], ip[2], ip[3], rrsetdn); ++ explodedn = ldap_explode_dn(rrsetdn, 0); ++ if (explodedn[0]) { ++ static char *zoneattrs[] = { "dnszonename", 0 }; ++ char zonedn[256]; ++ int i, len = 0; ++ struct zonerecord zone; ++ ++ zonedn[0] = '\0'; ++ for (i = 1; explodedn[i]; i++) ++ len += snprintf(zonedn+len, 256-len, "%s,", explodedn[i]); ++ zonedn[len-1] = '\0'; ++ ldap_msgfree(res); ++ assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, "(objectclass=dnszone)", zoneattrs, 0, &options.timeout, &res)); ++ m = ldap_first_entry(ldap_con, res); ++ if (m==NULL) ++ printf("Error: parent dn: %s not found for %s\n", zonedn, rrsetdn); ++ fill_zonerecord(&zone, m); ++ len = strlen(rr->qualifieddomainname); ++ if (len==0) { ++ len = strlen(rr->cname); ++ if (rr->cname[len-1]!='.') { ++ strcat(rr->cname, "."); ++ strncat(rr->cname, zone.zonename, 252-len); ++ } ++ } else { ++ /* in those situations where a dnsrrset ++ * defines something like MX or NS for a zone ++ * and also sets a canonical name for the ++ * service. */ ++ snprintf(rr->cname, 256, "%s.%s", rr->qualifieddomainname, zone.zonename); ++ } ++ strcpy(rr->type, "PTR"); ++ strncpy(rr->qualifieddomainname, queryname, 256); ++ } ++ ldap_memfree(rrsetdn); ++ ldap_value_free(explodedn); ++ } ++ ldap_msgfree(res); ++ return rr; ++} ++ ++static ++struct resourcerecord* read_domainrecords(const char* zonedn, const char* domainname, const char* zonename) ++{ ++ static char *rrattrs[] = { "dnsdomainname", "dnstype", "dnsttl", "dnscname", "dnsipaddr", "dnscipaddr", "dnstimestamp", "dnspreference", 0 }; ++ LDAPMessage* res = NULL; ++ LDAPMessage* m; ++ char filter[256]; ++ struct resourcerecord *prev, *anchor = NULL; ++ ++ if (domainname[0]) { ++ if (strstr(zonename, "in-addr.arpa")) { ++ unsigned int ip[4]; ++ char queryname[256]; ++ snprintf(queryname, 256, "%s.%s", domainname, zonename); ++ if (sscanf(queryname, "%3u.%3u.%3u.%3u", &ip[3], &ip[2], &ip[1], &ip[0])!=4) ++ return NULL; ++ snprintf(filter, 256, "(&(dnsipaddr=%u.%u.%u.%u)(objectclass=dnsrrset)(dnsclass=IN))", ip[0], ip[1], ip[2], ip[3]); ++ assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (m = ldap_first_entry(ldap_con, res)) { ++ struct resourcerecord* rr; ++ rr = (void*)alloc(sizeof(struct resourcerecord)); ++ fill_resourcerecord(rr, m, zonename); ++ strncpy(rr->qualifieddomainname, queryname, 256); ++ ldap_msgfree(res); ++ return rr; ++ } else { ++ /* ipaddr not in our baliwick, search the whole tree for canonical ipaddr */ ++ ldap_msgfree(res); ++ return find_reverserecord(queryname, ip); ++ } ++ } else { ++ int i; ++ for (i = 0; domainname[i]; i++) { ++ snprintf(filter, 256, (i==0 ? "(&(dnsdomainname=%s)(objectclass=dnsrrset)(dnsclass=IN))" : ++ "(&(dnsdomainname=\\*.%s)(objectclass=dnsrrset)(dnsclass=IN))"), &domainname[i]); ++ assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ if (ldap_count_entries(ldap_con, res)>0) ++ break; ++ while (domainname[i] && domainname[i]!='.') ++ i++; ++ } ++ } ++ } else { ++ snprintf(filter, 256, "(&(!(dnsdomainname=*))(objectclass=dnsrrset)(dnsclass=IN))"); ++ assert_ldap(ldap_search_st(ldap_con, zonedn, LDAP_SCOPE_SUBTREE, filter, rrattrs, 0, &options.timeout, &res)); ++ } ++ for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { ++ struct resourcerecord* rr; ++ rr = (void*)alloc(sizeof(struct resourcerecord)); ++ fill_resourcerecord(rr, m, zonename); ++ snprintf(rr->qualifieddomainname, 256, "%s%s%s", domainname, domainname[0] ? "." : "", zonename); ++ if (anchor==NULL) { ++ prev = anchor = rr; ++ } else { ++ prev->next = rr; ++ prev = rr; ++ } ++ if (options.verbose&1) ++ printf("\trr: %s %s\n", domainname, rr->type); ++ } ++ ldap_msgfree(res); ++ return anchor; ++} ++ ++static ++int read_dnszone(struct zonerecord* zone, const char* zonename) ++{ ++ static char *zoneattrs[] = { "dnszonename", "dnstype", "dnsserial", "dnsrefresh", "dnsretry", "dnsexpire", "dnsminimum", "dnszonemaster", "dnsadminmailbox", "dnsttl", "dnstimestamp", 0 }; ++ LDAPMessage* res = NULL; ++ LDAPMessage* m; ++ char* dn; ++ char filter[256]; ++ ++ snprintf(filter, 256, "(&(dnszonename=%s)(objectclass=dnszone)(dnsclass=IN))", zonename); ++ assert_ldap(ldap_search_st(ldap_con, options.basedn, LDAP_SCOPE_SUBTREE, filter, zoneattrs, 0, &options.timeout, &res)); ++ m = ldap_first_entry(ldap_con, res); ++ if (m==NULL) { ++ ldap_msgfree(res); ++ return 0; ++ } ++ dn = ldap_get_dn(ldap_con, m); ++ fill_zonerecord(zone, m); ++ m = ldap_next_entry(ldap_con, m); ++ if (m) { ++ char* otherdn = ldap_get_dn(ldap_con, m); ++ printf("Warning: ambigous zonename found in dn: %s and dn: %s\n", dn, otherdn); ++ ldap_memfree(otherdn); ++ } ++ strncpy(zone->zonedn, dn, 256); ++ ldap_memfree(dn); ++ ldap_msgfree(res); ++ return 1; ++} ++ ++static ++void djb_name(const char* dotname, char* djbname) ++{ ++ const char* c = dotname; ++ int i, k; ++ for (i = 0; *c; c++) { ++ k = i; ++ while (*c!='.') { ++ k++; ++ djbname[k] = *c; ++ if (*c=='\0') { ++ djbname[i] = k-i-1; ++ return; ++ } ++ c++; ++ } ++ djbname[i] = k-i; ++ i = k+1; ++ } ++ djbname[i] = '\0'; ++} ++ ++static ++void djb_type(const char* dottype, char djbtype[2]) ++{ ++ djbtype[0] = '\0'; ++ if (strcasecmp(dottype, "A")==0) ++ djbtype[1] = 001; ++ else if (strcasecmp(dottype, "NS")==0) ++ djbtype[1] = 002; ++ else if (strcasecmp(dottype, "CNAME")==0) ++ djbtype[1] = 005; ++ else if (strcasecmp(dottype, "SOA")==0) ++ djbtype[1] = 006; ++ else if (strcasecmp(dottype, "PTR")==0) ++ djbtype[1] = 014; ++ else if (strcasecmp(dottype, "MX")==0) ++ djbtype[1] = 017; ++ else if (strcasecmp(dottype, "TXT")==0) ++ djbtype[1] = 020; ++} ++ ++static ++void split_djbstyle(const char* djbname, char* domainname, char* zonename, int offset) ++{ ++ int i, k, m = 0, n = 0; ++ for (i = *djbname; i; i = *++djbname) { ++ if (offset>0) { ++ offset--; ++ for (k = m; k0 ? m-1 : 0] = '\0'; ++ zonename[n>0 ? n-1 : 0] = '\0'; ++} ++ ++static ++void build_response_section(struct resourcerecord *rr, char qtype[2], int section) ++{ ++ char djbname[256], djbtype[2]; ++ djb_name(rr->qualifieddomainname, djbname); ++ djb_type(rr->type, djbtype); ++ if (byte_equal(djbtype, 2, DNS_T_A)) { ++ if (byte_equal(qtype, 2, DNS_T_A) || byte_equal(qtype, 2, DNS_T_ANY)) { ++ response_rstart(djbname, djbtype, rr->ttl); ++ response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); ++ response_rfinish(section); ++ } ++ } else if (byte_equal(djbtype, 2, DNS_T_CNAME)) { ++ response_rstart(djbname, djbtype, rr->ttl); ++ djb_name(rr->cname, djbname); ++ response_addname(djbname); ++ response_rfinish(section); ++ } else if (byte_equal(djbtype, 2, DNS_T_NS)) { ++ if (byte_equal(qtype, 2, DNS_T_NS) || byte_equal(qtype, 2, DNS_T_ANY)) { ++ response_rstart(djbname, djbtype, rr->ttl); ++ if (rr->cname[0]) { ++ djb_name(rr->cname, djbname); ++ response_addname(djbname); ++ rr->additionalinfo = 1; ++ } else { ++ response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); ++ } ++ response_rfinish(section); ++ } ++ } else if (byte_equal(djbtype, 2, DNS_T_PTR)) { ++ response_rstart(djbname, djbtype, rr->ttl); ++ djb_name(rr->cname, djbname); ++ response_addname(djbname); ++ response_rfinish(section); ++ } else if (byte_equal(djbtype, 2, DNS_T_MX)) { ++ if (byte_equal(qtype, 2, DNS_T_MX) || byte_equal(qtype, 2, DNS_T_ANY)) { ++ char tmp[2]; ++ response_rstart(djbname, djbtype, rr->ttl); ++ tmp[0] = rr->preference/0x100; ++ tmp[1] = rr->preference%0x100; ++ response_addbytes(tmp, 2); ++ if (rr->cname[0]) { ++ djb_name(rr->cname, djbname); ++ response_addname(djbname); ++ rr->additionalinfo = 1; ++ } else { ++ response_addbytes(rr->ipaddr[rand()%rr->numipaddrs], 4); ++ } ++ response_rfinish(section); ++ } ++ } ++} ++ ++static ++void build_soa_section(struct zonerecord *zone, int section) ++{ ++ time_t now; ++ char defaultsoa[20]; ++ char djbname[256]; ++ char zonesoa[20]; ++ unsigned long tmp; ++ time(&now); ++ djb_name(zone->zonename, djbname); ++ response_rstart(djbname, DNS_T_SOA, zone->ttl); ++ djb_name(zone->zonemaster, djbname); ++ response_addname(djbname); ++ djb_name(zone->adminmailbox, djbname); ++ response_addname(djbname); ++ uint32_pack_big(defaultsoa, now); ++ if (byte_equal(defaultsoa,4,"\0\0\0\0")) ++ defaultsoa[3] = 1; ++ byte_copy(defaultsoa + 4, 16, "\0\0\100\000\0\0\010\000\0\020\000\000\0\0\012\000"); ++ if (zone->serial==0) ++ uint32_unpack_big(defaultsoa, &tmp); ++ else ++ tmp = zone->serial; ++ uint32_pack_big(zonesoa, tmp); ++ if (zone->refresh==0) ++ uint32_unpack_big(defaultsoa+4, &tmp); ++ else ++ tmp = zone->refresh; ++ uint32_pack_big(zonesoa+4, tmp); ++ if (zone->retry==0) ++ uint32_unpack_big(defaultsoa+8, &tmp); ++ else ++ tmp = zone->retry; ++ uint32_pack_big(zonesoa+8, tmp); ++ if (zone->expire==0) ++ uint32_unpack_big(defaultsoa+12, &tmp); ++ else ++ tmp = zone->expire; ++ uint32_pack_big(zonesoa+12, tmp); ++ if (zone->minimum==0) ++ uint32_unpack_big(defaultsoa+16, &tmp); ++ else ++ tmp = zone->minimum; ++ uint32_pack_big(zonesoa+16, tmp); ++ response_addbytes(zonesoa, 20); ++ response_rfinish(section); ++} ++ ++static ++void build_additional_section(struct resourcerecord *rr) ++{ ++ char djbname[256], ip[4]; ++ if (rr->additionalinfo && find_ipaddr(rr->cname, ip)) { ++ djb_name(rr->cname, djbname); ++ response_rstart(djbname, DNS_T_A, rr->ttl); ++ response_addbytes(ip, 4); ++ response_rfinish(RESPONSE_ADDITIONAL); ++ } ++} ++ ++static ++int connect_and_bind() ++{ ++ ldap_con = ldap_init(options.ldaphosts, LDAP_PORT); ++ if (ldap_simple_bind_s(ldap_con, options.binddn, options.bindpwd)==LDAP_SUCCESS) { ++ printf("Connected to %s as \"%s\"\n", options.ldaphosts, options.binddn); ++ return 1; ++ } ++ ldap_con = NULL; ++ return 0; ++} ++ ++int askldap_query(const char* djbdomainname, char qtype[2]) ++{ ++ int offset; ++ char domainname[64], zonename[64]; ++ struct zonerecord zoneinfo; ++ int answer_ok = 0, flagsoa = 0, flagns = 0; ++ if (!options.initialized) ++ return 0; ++ switch (sigsetjmp(stack_context, 1)) { ++ default: ++ if (ldap_con==NULL && !connect_and_bind()) ++ return answer_ok; ++ break; ++ case ASKLDAP_RECONNECT: ++ if (connect_and_bind()) ++ break; ++ return answer_ok; ++ case ASKLDAP_RETURN: ++ return answer_ok; ++ } ++ for (offset = 0; offset<32; offset++) { ++ struct resourcerecord *rransw, *rrauth, *rr; ++ ++ split_djbstyle(djbdomainname, domainname, zonename, offset); ++ if (zonename[0]=='\0') return 0; ++ if (!read_dnszone(&zoneinfo, zonename)) ++ continue; ++ rransw = read_domainrecords(zoneinfo.zonedn, domainname, zonename); ++ rrauth = NULL; ++ if (offset==0) { ++ /* query is in our bailiwick */ ++ if (byte_equal(qtype, 2, DNS_T_ANY) || byte_equal(qtype, 2, DNS_T_SOA)) { ++ build_soa_section(&zoneinfo, RESPONSE_ANSWER); ++ flagsoa = 1; ++ } ++ for (rr = rransw; rr; rr = rr->next) { ++ build_response_section(rr, qtype, RESPONSE_ANSWER); ++ answer_ok = 1; ++ } ++ if (!flagsoa) { ++ build_soa_section(&zoneinfo, RESPONSE_AUTHORITY); ++ flagsoa = 1; ++ } ++ if (!byte_equal(qtype, 2, DNS_T_ANY) && !byte_equal(qtype, 2, DNS_T_NS)) { ++ for (rr = rransw; rr; rr = rr->next) ++ if (strcmp(rr->type, "NS")==0) { ++ build_response_section(rr, DNS_T_NS, RESPONSE_AUTHORITY); ++ flagns = 1; ++ } ++ } ++ } else { ++ for (rr = rransw; rr; rr = rr->next) { ++ if (strcmp(rr->type, "NS")==0) { ++ build_response_section(rr, qtype, RESPONSE_AUTHORITY); ++ flagns = 1; ++ } ++ } ++ if (!flagns) { ++ for (rr = rransw; rr; rr = rr->next) { ++ build_response_section(rr, qtype, RESPONSE_ANSWER); ++ answer_ok = 1; ++ } ++ if (answer_ok) { ++ rrauth = read_domainrecords(zoneinfo.zonedn, "", zonename); ++ } else { ++ build_soa_section(&zoneinfo, RESPONSE_AUTHORITY); ++ flagsoa = 1; ++ } ++ } ++ for (rr = rrauth; rr; rr = rr->next) { ++ if (strcmp(rr->type, "NS")==0) { ++ build_response_section(rr, DNS_T_NS, RESPONSE_AUTHORITY); ++ flagns = 1; ++ } ++ } ++ } ++ for (rr = rransw; rr; rr = rr->next) ++ build_additional_section(rr); ++ for (rr = rrauth; rr; rr = rr->next) ++ build_additional_section(rr); ++ free_domainrecords(rransw); ++ free_domainrecords(rrauth); ++ break; ++ } ++ return answer_ok || flagsoa || flagns; ++} ++ ++void askldap_init(const char* ldaphost, const char* basedn, const char* binddn, const char* passwd) ++{ ++ strncpy(options.ldaphosts, ldaphost, 256); ++ options.basedn = basedn; ++ if (binddn) strncpy(options.binddn, binddn, 256); ++ if (passwd) strncpy(options.bindpwd, passwd, 16); ++ /* LDAP timeout is hardcoded to 2/10 second. ++ * This must be enough because bindoperations usually ++ * timeout after one second and here we usually have to ++ * send five queries to the LDAP-server */ ++ options.timeout.tv_sec = 1; ++ options.timeout.tv_usec = 200000; ++ options.verbose = 0; ++ options.initialized = 1; ++ connect_and_bind(); ++} ++ +diff -Naur djbdns-1.05.orig/askldap.h djbdns-1.05/askldap.h +--- djbdns-1.05.orig/askldap.h Thu Jan 1 01:00:00 1970 ++++ djbdns-1.05/askldap.h Tue Aug 13 14:30:22 2002 +@@ -0,0 +1,10 @@ ++/* Patch for tinydns to pass DNS-query to LDAP in favour of a cdb lookup. ++ * $Id$ ++ * Copyright 2002 ++ */ ++ ++extern ++int askldap_query(const char* djbdomainname, char qtype[2]); ++ ++extern ++void askldap_init(const char* ldaphost, const char* basedn, const char* binddn, const char* passwd); +diff -Naur djbdns-1.05.orig/ldap.lib djbdns-1.05/ldap.lib +--- djbdns-1.05.orig/ldap.lib Thu Jan 1 01:00:00 1970 ++++ djbdns-1.05/ldap.lib Tue Aug 13 14:29:53 2002 +@@ -0,0 +1 @@ ++-lldap -llber +diff -Naur djbdns-1.05.orig/server.c djbdns-1.05/server.c +--- djbdns-1.05.orig/server.c Sun Feb 11 22:11:45 2001 ++++ djbdns-1.05/server.c Tue Aug 13 14:29:15 2002 +@@ -11,6 +11,7 @@ + #include "qlog.h" + #include "response.h" + #include "dns.h" ++#include "askldap.h" + + extern char *fatal; + extern char *starting; +@@ -79,6 +80,7 @@ + return 0; + } + ++ + int main() + { + char *x; +@@ -90,6 +92,19 @@ + if (!ip4_scan(x,ip)) + strerr_die3x(111,fatal,"unable to parse IP address ",x); + ++ x = env_get("LDAPHOSTS"); ++ if (x) { ++ char *basedn = env_get("LDAPBASEDN"); ++ char *binddn = env_get("LDAPBINDDN"); ++ char *bindpwd = env_get("LDAPPASSWD"); ++ if (basedn) ++ askldap_init(x, basedn, binddn, bindpwd); ++ if (bindpwd) { ++ int len = str_len(bindpwd); ++ while (len) bindpwd[--len] = 'x'; ++ } ++ } ++ + udp53 = socket_udp(); + if (udp53 == -1) + strerr_die2sys(111,fatal,"unable to create UDP socket: "); +diff -Naur djbdns-1.05.orig/tdlookup.c djbdns-1.05/tdlookup.c +--- djbdns-1.05.orig/tdlookup.c Sun Feb 11 22:11:45 2001 ++++ djbdns-1.05/tdlookup.c Tue Aug 13 14:29:29 2002 +@@ -8,6 +8,7 @@ + #include "dns.h" + #include "seek.h" + #include "response.h" ++#include "askldap.h" + + static int want(const char *owner,const char type[2]) + { +@@ -285,10 +286,13 @@ + char key[6]; + + tai_now(&now); ++ if (askldap_query(q, qtype)) ++ return 1; ++ + fd = open_read("data.cdb"); + if (fd == -1) return 0; + cdb_init(&c,fd); +- ++ + byte_zero(clientloc,2); + key[0] = 0; + key[1] = '%'; diff --git a/dns.at.conf b/dns.at.conf deleted file mode 100644 index 30e42d0..0000000 --- a/dns.at.conf +++ /dev/null @@ -1,24 +0,0 @@ -# include this file into Your slapd.conf for openldap-1.2.x -# $Id: dns.at.conf,v 1.5 2000/12/04 12:59:57 jrief Exp $ -attribute DNSzonename cis -attribute DNSserial cis -attribute DNSrefresh cis -attribute DNSretry cis -attribute DNSexpire cis -attribute DNSminimum cis -attribute DNSadminmailbox cis -attribute DNSzonemaster cis -attribute DNStype cis -attribute DNSclass cis -attribute DNSdomainname cis -attribute DNSipaddr cis -attribute DNScname cis -attribute DNSpreference cis -attribute DNSttl cis -attribute DNStimestamp cis - -#attribute DNSaliasedobjectname cis -#attribute DNSrr cis -#attribute DNSrrcount cis -#attribute DNSmacaddress cis - diff --git a/dns.oc.conf b/dns.oc.conf deleted file mode 100644 index 6a6359c..0000000 --- a/dns.oc.conf +++ /dev/null @@ -1,45 +0,0 @@ -# include this file into Your slapd.conf for openldap-1.2.x -# $Id: dns.oc.conf,v 1.4 2000/12/01 14:48:25 jrief Exp $ - -# child of anybody -# information to setup a DNS zone -objectclass DNSzone - requires - objectclass, - cn - allows - DNSzonename, - DNSserial, - DNSrefresh, - DNSretry, - DNSexpire, - DNSminimum, - DNSadminmailbox, - DNSzonemaster, - DNStype, - DNSclass, - DNSttl, - DNStimestamp - - #DNSrrcount, - -# child of a DNSzone -# information to setup a resource record -objectclass DNSrrset - requires - objectclass, - cn - allows - DNSdomainname, - DNSclass, - DNStype, - DNSipaddr, - DNScname, - DNSpreference, - DNSttl, - DNStimestamp - - #DNSaliasedobjectname, - #DNSrr, - #DNSmacaddress, - diff --git a/dns.schema b/dns.schema-2.0 similarity index 56% rename from dns.schema rename to dns.schema-2.0 index 81044c4..6bcabbb 100644 --- a/dns.schema +++ b/dns.schema-2.0 @@ -1,103 +1,125 @@ # schema for DNS data # include this file into Your slapd.conf for openldap-2.0.x -# $Id: dns.schema,v 1.8 2001/08/09 10:35:49 jrief Exp $ +# $Id: dns.schema,v 1.9 2003/01/20 14:33:25 jrief Exp $ attributetype ( 1.3.6.1.4.1.7222.1.4.1 - NAME 'DNSzonename' + NAME 'dnszonename' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.2 - NAME 'DNSserial' + NAME 'dnsserial' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.3 - NAME 'DNSrefresh' + NAME 'dnsrefresh' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.4 - NAME 'DNSretry' + NAME 'dnsretry' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.5 - NAME 'DNSexpire' + NAME 'dnsexpire' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.6 - NAME 'DNSminimum' + NAME 'dnsminimum' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.7 - NAME 'DNSadminmailbox' + NAME 'dnsadminmailbox' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.8 - NAME 'DNSzonemaster' + NAME 'dnszonemaster' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.9 - NAME 'DNStype' + NAME 'dnstype' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.10 - NAME 'DNSclass' + NAME 'dnsclass' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.11 - NAME 'DNSdomainname' + NAME 'dnsdomainname' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.12 - NAME 'DNSipaddr' + NAME 'dnsipaddr' EQUALITY numericStringMatch SUBSTR numericStringSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} ) attributetype ( 1.3.6.1.4.1.7222.1.4.13 - NAME 'DNScipaddr' + NAME 'dnscipaddr' EQUALITY numericStringMatch SUBSTR numericStringSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} ) attributetype ( 1.3.6.1.4.1.7222.1.4.14 - NAME 'DNScname' + NAME 'dnscname' SUP name ) attributetype ( 1.3.6.1.4.1.7222.1.4.15 - NAME 'DNSpreference' + NAME 'dnspreference' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.16 - NAME 'DNSrr' + NAME 'dnsrr' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.17 - NAME 'DNSttl' + NAME 'dnsttl' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 1.3.6.1.4.1.7222.1.4.18 - NAME 'DNStimestamp' + NAME 'dnstimestamp' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +attributetype ( 1.3.6.1.4.1.7222.1.4.21 + NAME 'NIChandle' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.22 + NAME 'TIShandle' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.23 + NAME 'dnslocation' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{2} + SINGLE-VALUE ) + objectclass ( 1.3.6.1.4.1.7222.1.4.19 - NAME 'DNSzone' + NAME 'dnszone' MUST ( objectclass $ cn ) - MAY ( DNSzonename $ DNSserial $ DNSrefresh $ DNSretry $ DNSexpire - $ DNSminimum $ DNSadminmailbox $ DNSzonemaster $ DNStype $ DNSclass - $ DNSttl $ DNStimestamp $ owner ) ) + MAY ( dnszonename $ dnsserial $ dnsrefresh $ dnsretry $ dnsexpire + $ dnsminimum $ dnsadminmailbox $ dnszonemaster $ dnstype $ dnsclass + $ dnsttl $ dnstimestamp $ owner $ NIChandle $ TIShandle $ dnslocation ) ) objectclass ( 1.3.6.1.4.1.7222.1.4.20 - NAME 'DNSrrset' - SUP DNSzone + NAME 'dnsrrset' + SUP dnszone MUST ( objectclass $ cn ) - MAY ( DNSdomainname $ DNSrr $ DNSclass $ DNStype $ DNSipaddr $ DNScipaddr - $ DNScname $ DNSpreference $ DNSttl $ DNStimestamp $ owner ) ) + MAY ( dnsdomainname $ dnsrr $ dnsclass $ dnstype $ dnsipaddr $ dnscipaddr + $ dnscname $ dnspreference $ dnsttl $ dnstimestamp $ owner ) ) +objectclass ( 1.3.6.1.4.1.7222.1.4.24 + NAME 'dnsloccodes' + MUST ( objectclass $ dnslocation ) + MAY ( dnsipaddr $ uid $ description ) ) diff --git a/dns.schema-2.2 b/dns.schema-2.2 new file mode 100644 index 0000000..1be6a2e --- /dev/null +++ b/dns.schema-2.2 @@ -0,0 +1,126 @@ +# schema for DNS data +# include this file into Your slapd.conf for openldap-2.0.x +# $Id: dns.schema,v 1.9 2001/11/06 08:01:51 config Exp $ + +attributetype ( 1.3.6.1.4.1.7222.1.4.1 + NAME 'dnszonename' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.2 + NAME 'dnsserial' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.3 + NAME 'dnsrefresh' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.4 + NAME 'dnsretry' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.5 + NAME 'dnsexpire' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.6 + NAME 'dnsminimum' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.7 + NAME 'dnsadminmailbox' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.8 + NAME 'dnszonemaster' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.9 + NAME 'dnstype' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.10 + NAME 'dnsclass' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.11 + NAME 'dnsdomainname' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.12 + NAME 'dnsipaddr' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} ) + SINGLE-VALUE ) + + +attributetype ( 1.3.6.1.4.1.7222.1.4.13 + NAME 'dnscipaddr' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.14 + NAME 'dnscname' + SUP name ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.15 + NAME 'dnspreference' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.16 + NAME 'dnsrr' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.17 + NAME 'dnsttl' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.18 + NAME 'dnstimestamp' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.21 + NAME 'NIChandle' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} ) + +attributetype ( 1.3.6.1.4.1.7222.1.4.22 + NAME 'TIShandle' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} ) + +objectclass ( 1.3.6.1.4.1.7222.1.4.19 + NAME 'dnszone' + MUST ( objectclass $ cn ) + MAY ( dnszonename $ dnsserial $ dnsrefresh $ dnsretry $ dnsexpire + $ dnsminimum $ dnsadminmailbox $ dnszonemaster $ dnstype $ dnsclass + $ dnsttl $ dnstimestamp $ owner $ NIChandle $ TIShandle ) ) + +objectclass ( 1.3.6.1.4.1.7222.1.4.20 + NAME 'dnsrrset' + SUP dnszone + MUST ( objectclass $ cn ) + MAY ( dnsdomainname $ dnsrr $ dnsclass $ dnstype $ dnsipaddr $ dnscipaddr + $ dnscname $ dnspreference $ dnsttl $ dnstimestamp $ owner ) ) + + + diff --git a/export-ldap2dns.pl b/export-ldap2dns.pl new file mode 100755 index 0000000..5119189 --- /dev/null +++ b/export-ldap2dns.pl @@ -0,0 +1,190 @@ +#!/usr/bin/perl +# Script to import data from DNS into LDAP +# Copyright 2000, Jacob Rief +# $Id: export-ldap2dns.pl,v 1.1 2002/09/03 10:43:40 jrief Exp $ + +###### configure this ###### +# remember to allow zone transfers from Your nameserver +my $LDAPHOST = "localhost"; +my $LDAPBINDDN = "uid=root,o=tiscover"; +my $LDAPPASSWD = "1Fnegu!"; +my $BASEDN = "ou=dns,o=tiscover"; + +###### don't edit below this line ###### +use strict; +use Net::LDAP qw(LDAP_NO_SUCH_OBJECT LDAP_ALREADY_EXISTS); + +my $ldap; +initialize(); +migrate_zones(); + +sub initialize +{ + $ldap = Net::LDAP->new($LDAPHOST) or die "Can't connect to LDAP server"; + my $mesg = $ldap->bind( dn => $LDAPBINDDN, password => $LDAPPASSWD ); + die "Unable to bind to LDAP ", $mesg->error if ($mesg->code); +} + +sub migrate_zones +{ + my $mesg = $ldap->search(base=>$BASEDN, scope=>'sub', filter=>"(objectclass=dnszone)"); + my @oldzones = $mesg->entries(); + foreach my $oldzone (@oldzones) { + my @zonename = $oldzone->get_value('dnszonename'); + my $masterdn = dn_domain($zonename[0]) if ($#zonename>=0); + foreach my $zn (@zonename) { + my $newdn = dn_domain($zn); + next unless ($newdn =~ /^dc=\s*([^,]+).*/); + my $dc = $1; + my $soarecord = $oldzone->get_value('dnsserial')." " + .$oldzone->get_value('dnsrefresh')." " + .$oldzone->get_value('dnsretry')." " + .$oldzone->get_value('dnsexpire')." " + .$oldzone->get_value('dnsminimum'); + my %attrs = ( 'objectclass' => [ qw(dNSDomain dcObject) ], 'dc' => $dc, 'sOARecord' => [ $soarecord ] ); + $mesg = $ldap->modify($newdn, 'replace' => \%attrs); + while ($mesg->code()==LDAP_NO_SUCH_OBJECT) { + repeat: + $mesg = $ldap->add($newdn, 'attrs' => list_attrs(\%attrs)); + last unless ($mesg->code()==LDAP_NO_SUCH_OBJECT); + my $filldn = $newdn; + do { + die("Invalid dn: $filldn") unless ($filldn =~ /[^,]+,((dc=[^,]+),.+)/); + $filldn = $1; + $mesg = $ldap->add($filldn, 'attrs' => [ 'objectclass'=>'dcObject', 'dc'=>$2) ]); + } until ($mesg->code()==0 || $mesg->code()==LDAP_ALREADY_EXISTS); + goto repeat; + } + die("Error from LDAP: \"".$mesg->error()."\" on $newdn (".$mesg->code().")") if ($mesg->code()); + if ($masterdn ne $newdn) { + $mesg = $ldap->modify($masterdn, 'replace' => [ 'objectclass' => 'alias' ]); + $mesg = $ldap->modify($masterdn, 'add' => [ 'alias' => $newdn ]); + $mesg = $ldap->modify($newdn, 'replace' => [ 'objectclass' => 'alias', 'alias' => $masterdn ]); + } + migrate_rrrecords($zn, $newdn, $oldzone->dn()); + } + } +} + +sub migrate_rrrecords +{ + my ($zonename, $newzonedn, $oldzonedn) = (@_); + my @objectclass = qw(dNSDomain dcObject); + my $mesg = $ldap->search(base=>$oldzonedn, scope=>'sub', filter=>"(objectclass=dnsrrset)"); + my @rrsets = $mesg->entries(); + foreach my $rr (@rrsets) { + my $domainname = $rr->get_value('dnsdomainname'); + my $dn = dn_domain(length($domainname)>0 ? "$domainname.$zonename" : "$zonename"); + my $type = $rr->get_value('dnstype'); + print "dn: $dn (type: $type)\n"; + next unless ($dn =~ /^dc=\s*([^,]+).*/); + my %attrs = read_ldapobject($dn); + $attrs{'objectclass'} = \@objectclass; + $attrs{'dc'} = $1; + my @cname = $rr->get_value('dnscname'); + my @ipaddr = $rr->get_value('dnsipaddr'); + my $cipaddr = $rr->get_value('dnscipaddr'); + if ($type eq "A") { + push(@ipaddr, $cipaddr) if (length($cipaddr)>5); + my $ta = $attrs{'aRecord'}; + push(@$ta, @ipaddr) if ($#ipaddr>=0); + } elsif ($type eq "NS") { + my $ta = $attrs{'NSRecord'}; + foreach my $cn (@cname) { + if ($cn =~ /\.$/) { + push(@$ta, $cn); + } else { + push(@$ta, "$cn.$zonename"); + } + } + } elsif ($type eq "MX") { + my $ta = $attrs{'MXRecord'}; + my $pref = $rr->get_value('dnspreference'); + foreach my $cn (@cname) { + if ($cn =~ /\.$/) { + push(@$ta, "$pref $cn"); + } else { + push(@$ta, "$pref $cn.$zonename"); + } + } + } elsif ($type eq "CNAME") { + my $ta = $attrs{'cNAMERecord'}; + die("no CNAME") unless($#cname>=0); + foreach my $cn (@cname) { + if ($cn =~ /\.$/) { + push(@$ta, $cn); + } else { + push(@$ta, "$cn.$zonename"); + } + } + } + remove_unused(\%attrs); + $mesg = $ldap->modify($dn, 'replace' => \%attrs); + while ($mesg->code()==LDAP_NO_SUCH_OBJECT) { + repeat: + $mesg = $ldap->add($dn, 'attrs' => list_attrs(\%attrs)); + last unless ($mesg->code()==LDAP_NO_SUCH_OBJECT); + my $filldn = $dn; + do { + die("Invalid dn: $filldn") unless ($filldn =~ /[^,]+,((dc=[^,]+),.+)/); + $filldn = $1; + $mesg = $ldap->add($filldn, 'attrs' => [ qw(objectclass dcObject dc $2) ]); + } until ($mesg->code()==0 || $mesg->code()==LDAP_ALREADY_EXISTS); + goto repeat; + } + die("Error from LDAP: \"".$mesg->error()."\" on $dn") if ($mesg->code()); + } +} + +sub dn_domain +{ + my ($domain)=(@_); + my @p = split /\./, lc($domain); + my $dc = 'dc='.join(',dc=', @p); + $dc .= ','.$BASEDN; + return $dc; +} + +sub list_attrs +{ + my $attr = shift; + my (@list, $key, $value); + while (($key, $value) = each %$attr) { + push(@list, $key => $value); + } + return \@list; +} + +sub read_ldapobject +{ + my $dn = shift; + my %attrs = (); + $attrs{'aRecord'} = []; + $attrs{'cNAMERecord'} = []; + $attrs{'MXRecord'} = []; + $attrs{'NSRecord'} = []; + my $mesg = $ldap->search(base => $dn, scope => 'base', filter => "(objectclass=dcObject)"); + return %attrs if ($mesg->code()==LDAP_NO_SUCH_OBJECT); + return %attrs if ($mesg->count()==0); + my $obj = $mesg->entry(0); + my @tempa = $obj->get_value('aRecord'); + $attrs{'aRecord'} = \@tempa if ($#tempa>=0); + my @tempcname = $obj->get_value('cNAMERecord'); + $attrs{'cNAMERecord'} = \@tempcname if ($#tempcname>=0); + my @tempmx = $obj->get_value('MXRecord'); + $attrs{'MXRecord'} = \@tempmx if ($#tempmx>=0); + my @tempns = $obj->get_value('NSRecord'); + $attrs{'NSRecord'} = \@tempns if ($#tempns>=0); + return %attrs; +} + +sub remove_unused +{ + my $hash = shift; + foreach my $key (keys %$hash) { + my $ta = $$hash{$key}; + next if ($key eq "dc"); + delete $$hash{$key} if ($#$ta<0); + } +} + diff --git a/ldap2dns-dbg b/ldap2dns-dbg new file mode 100755 index 0000000..0427d18 Binary files /dev/null and b/ldap2dns-dbg differ diff --git a/ldap2dns-ldapuri.patch b/ldap2dns-ldapuri.patch new file mode 100644 index 0000000..40c15a1 --- /dev/null +++ b/ldap2dns-ldapuri.patch @@ -0,0 +1,134 @@ +--- ldap2dns-0.3.1-orig/ldap2dns.c 2002-08-02 17:19:36.000000000 +0200 ++++ ldap2dns-0.3.1/ldap2dns.c 2002-09-01 13:31:52.000000000 +0200 +@@ -14,7 +14,7 @@ + #include + + #define UPDATE_INTERVALL 59 +-#define LDAP_CONF "/etc/ldap.conf" ++#define LDAP_CONF "/etc/ldap/ldap.conf" + #define OUTPUT_DATA 1 + #define OUTPUT_DB 2 + #define MAXHOSTS 10 +@@ -85,6 +85,7 @@ + char searchbase[128]; + char binddn[128]; + char hostname[MAXHOSTS][128]; ++ char urildap[MAXHOSTS][128]; + int port[MAXHOSTS]; + char password[128]; + int usedhosts; +@@ -94,6 +95,7 @@ + int verbose; + char ldifname[128]; + char exec_command[128]; ++ int use_tls[MAXHOSTS]; + } options; + + +@@ -130,7 +132,8 @@ + static void print_usage(void) + { + print_version(); +- printf("usage: ldap2dns[d] [-D binddn] [-b searchbase] [-o data|db] [-h host] [-p port] [-w password] [-L[filename]] [-u numsecs] [-v[v]] [-V]\n\n"); ++ printf("usage: ldap2dns[d] [-D binddn] [-b searchbase] [-o data|db] [-h host] [-p port] [-H hostURI] " ++ "[-w password] [-L[filename]] [-u numsecs] [-v[v]] [-V]\n\n"); + printf("ldap2dns connects to an LDAP server reads the DNS information stored in objectclasses\n" + "\t\tDNSzone and DNSrrset and writes a file to be used by tinydns or named.\n" + "\t\tldap2dnsd starts as background-job and continouesly updates DNS information.\n"); +@@ -143,6 +146,7 @@ + printf(" -L[filename] Print output in LDIF format for reimport\n"); + printf(" -h host\tHostname of LDAP server, defaults to localhost\n"); + printf(" -p port\tPortnumber to connect to LDAP server, defaults to %d\n", LDAP_PORT); ++ printf(" -H hostURI\tURI (ldap://hostname or ldaps://hostname of LDAP server\n"); + printf(" -u numsecs\tUpdate DNS data after numsecs. Defaults to %d if started as daemon.\n\t\t" + "Important notice: data.cdb is rewritten only after DNSserial in DNSzone is increased.\n", + UPDATE_INTERVALL); +@@ -159,7 +163,18 @@ + + options.usedhosts = 0; + for (i = 0; i=2) { ++ if (!strncasecmp(buf, "ldaps://", 8) || !strncasecmp(buf, "ldap://", 7)) { ++ // LDAP-URI is given/found, at the moment only the standard-ports 389 and 636 are supported ++ if (!strncasecmp(buf, "ldap://", 7)) ++ options.use_tls[i] = 1; ++ if ((k = sscanf(buf, "%128s %512[A-Za-z0-9 .:/_+-]", value, rest))>=1) { ++ strcpy(options.urildap[i], value); ++ options.usedhosts++; ++ if (k==1) ++ break; ++ buf = rest; ++ } else break; ++ } else if ((k = sscanf(buf, "%128s:%d %512[A-Za-z0-9 .:_+-]", value, &port, rest))>=2) { + strcpy(options.hostname[i], value); + options.port[i] = port; + options.usedhosts++; +@@ -194,6 +209,8 @@ + int i; + if (sscanf(buf, "BASE %128s", value)==1) + strcpy(options.searchbase, value); ++ if (sscanf(buf, "URI %512[A-Za-z0-9 .:/_+-]", value)==1) ++ parse_hosts(value); + if (sscanf(buf, "HOST %512[A-Za-z0-9 .:_+-]", value)==1) + parse_hosts(value); + if (sscanf(buf, "PORT %d", &len)==1) +@@ -239,7 +256,7 @@ + options.ldifname[0] = '\0'; + strcpy(options.password, ""); + strcpy(options.exec_command, ""); +- while ( (len = getopt(main_argc, main_argv, "b:D:e:h:o:p:u:V:v::w:L::"))>0 ) { ++ while ( (len = getopt(main_argc, main_argv, "b:D:e:h:H:o:p:u:V:v::w:L::"))>0 ) { + if (optarg && strlen(optarg)>127) { + fprintf(stderr, "argument %s too long\n", optarg); + continue; +@@ -260,6 +277,10 @@ + strcpy(options.hostname[0], optarg); + options.usedhosts = 1; + break; ++ case 'H': ++ strcpy(options.urildap[0], optarg); ++ options.usedhosts = 1; ++ break; + case 'L': + if (optarg==NULL) + strcpy(options.ldifname, "-"); +@@ -796,12 +817,37 @@ + + static int connect() + { +- int i; ++ int i, rc, version; + for (i = 0; i 0) { ++ rc = ldap_initialize(&ldap_con, options.urildap[i]); ++ if (options.verbose&1 && rc == LDAP_SUCCESS) { ++ printf("ldap_initialization successful (%s)\n", options.urildap[i]); ++ } else if ( rc != LDAP_SUCCESS ) { ++ printf("ldap_initialization to %s failed %d\n", options.urildap[i], ldap_err2string(rc)); ++ ldap_con = NULL; ++ return 0; ++ } ++ version = LDAP_VERSION3; ++ if ( (rc=ldap_set_option(ldap_con, LDAP_OPT_PROTOCOL_VERSION, &version)) != LDAP_SUCCESS ) { ++ printf("ldap_set_option to %s failed with err %s!\n", options.urildap[i], ldap_err2string(rc)); ++ ldap_con = NULL; ++ return 0; ++ } ++ if ( options.use_tls[i] && (rc=ldap_start_tls_s( ldap_con, NULL, NULL )) != LDAP_SUCCESS ) { ++ printf("ldap_start_tls_s to %s failed with err %s!\n", options.urildap[i], ldap_err2string(rc)); ++ ldap_con = NULL; ++ return 0; ++ } ++ } else { + ldap_con = ldap_init(options.hostname[i], options.port[i]); ++ } + if (ldap_simple_bind_s(ldap_con, options.binddn, options.password)==LDAP_SUCCESS) { +- if (options.verbose&1) ++ if (options.verbose&1 && strlen(options.urildap[i]) > 0) { ++ printf("Connected to %s as \"%s\"\n", options.urildap[i], options.binddn); ++ } else if (options.verbose&1) { + printf("Connected to %s:%d as \"%s\"\n", options.hostname[i], options.port[i], options.binddn); ++ } + return 1; + } + } diff --git a/ldap2dns-loccode.patch b/ldap2dns-loccode.patch new file mode 100644 index 0000000..f177354 --- /dev/null +++ b/ldap2dns-loccode.patch @@ -0,0 +1,299 @@ +diff -bu ldap2dns-0.3.1-p1/dns.schema ldap2dns-0.3.1/dns.schema +--- ldap2dns-0.3.1-p1/dns.schema 2002-08-13 14:23:53.000000000 +0200 ++++ ldap2dns-0.3.1/dns.schema 2002-09-02 10:10:32.000000000 +0200 +@@ -99,12 +99,18 @@ + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} ) + ++attributetype ( 1.3.6.1.4.1.7222.1.4.23 ++ NAME 'dnslocation' ++ EQUALITY caseExactIA5Match ++ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{2} ++ SINGLE-VALUE ) ++ + objectclass ( 1.3.6.1.4.1.7222.1.4.19 + NAME 'dnszone' + MUST ( objectclass $ cn ) + MAY ( dnszonename $ dnsserial $ dnsrefresh $ dnsretry $ dnsexpire + $ dnsminimum $ dnsadminmailbox $ dnszonemaster $ dnstype $ dnsclass +- $ dnsttl $ dnstimestamp $ owner $ NIChandle $ TIShandle ) ) ++ $ dnsttl $ dnstimestamp $ owner $ NIChandle $ TIShandle $ dnslocation ) ) + + objectclass ( 1.3.6.1.4.1.7222.1.4.20 + NAME 'dnsrrset' +@@ -113,3 +119,7 @@ + MAY ( dnsdomainname $ dnsrr $ dnsclass $ dnstype $ dnsipaddr $ dnscipaddr + $ dnscname $ dnspreference $ dnsttl $ dnstimestamp $ owner ) ) + ++objectclass ( 1.3.6.1.4.1.7222.1.4.24 ++ NAME 'dnsloccodes' ++ MUST ( objectclass $ dnslocation ) ++ MAY ( dnsipaddr $ uid $ description ) ) +diff -bu ldap2dns-0.3.1-p1/ldap2dns.c ldap2dns-0.3.1/ldap2dns.c +--- ldap2dns-0.3.1-p1/ldap2dns.c 2002-09-02 10:45:43.000000000 +0200 ++++ ldap2dns-0.3.1/ldap2dns.c 2002-09-02 10:04:50.000000000 +0200 +@@ -58,8 +58,15 @@ + char minimum[12]; + char ttl[12]; + char timestamp[20]; ++ char location[2]; + } zone; + ++static struct ++{ ++ char locname[3]; ++ char member[256][16]; ++} loc_rec; ++ + struct resourcerecord + { + char cn[64]; +@@ -72,6 +79,7 @@ + char ttl[12]; + char timestamp[20]; + char preference[12]; ++ char location[2]; + #if defined DRAFT_RFC + char rr[1024]; + char aliasedobjectname[256]; +@@ -360,19 +368,19 @@ + if (tinyfile) { + if (znix==0) { + if (ipdx<=0 && rr->cipaddr[0]) { +- fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); + if (rr->cname[0]) +- fprintf(tinyfile, "=%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "=%s:%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); + if (ipdx==0) +- fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp, rr->location); + } else if (ipdx<0) +- fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); + else if (ipdx==0) +- fprintf(tinyfile, "&%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "&%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->ttl, rr->timestamp, rr->location); + else if (ipdx>0 && rr->cname[0]) +- fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); + } else if (ipdx<=0) { +- fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); + } + } + if (namedzone) { +@@ -384,19 +392,19 @@ + if (tinyfile) { + if (znix==0) { + if (ipdx<=0 && rr->cipaddr[0]) { +- fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); + if (rr->cname[0]) +- fprintf(tinyfile, "=%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "=%s:%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); + if (ipdx==0) +- fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp, rr->location); + } else if (ipdx<0) +- fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); + else if (ipdx==0) +- fprintf(tinyfile, "@%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->preference, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "@%s:%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); + else if (ipdx>0 && rr->cname[0]) +- fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); + } else if (ipdx<=0) { +- fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); + } + } + if (namedzone) { +@@ -407,9 +415,9 @@ + } else if ( strcasecmp(rr->type, "A")==0) { + if (tinyfile) { + if (ipdx<=0 && rr->cipaddr[0]) +- fprintf(tinyfile, "%s%s:%s:%s:%s\n", (znix==0 ? "=" : "+"), rr->dnsdomainname, rr->cipaddr, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "%s%s:%s:%s:%s:%s\n", (znix==0 ? "=" : "+"), rr->dnsdomainname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); + if (ipdx>=0) +- fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); + } + if (namedzone) { + if (ipdx<=0 && rr->cipaddr[0]) +@@ -431,17 +439,17 @@ + strcpy(buf, rr->dnsdomainname); + } + if (tinyfile) +- fprintf(tinyfile, "^%s:%s:%s:%s\n", buf, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "^%s:%s:%s:%s:%s\n", buf, rr->cname, rr->ttl, rr->timestamp, rr->location); + if (namedzone) + fprintf(namedzone, "%s.\tIN PTR\t%s.\n", buf, rr->cname); + } else if (strcasecmp(rr->type, "CNAME")==0) { + if (tinyfile) +- fprintf(tinyfile, "C%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "C%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); + if (namedzone) + fprintf(namedzone, "%s.\tIN CNAME\t%s.\n", rr->dnsdomainname, rr->cname); + } else if (strcasecmp(rr->type, "TXT")==0) { + if (tinyfile) +- fprintf(tinyfile, "'%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); ++ fprintf(tinyfile, "'%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); + if (namedzone) + fprintf(namedzone, "%s.\tIN TXT\t%s.\n", rr->dnsdomainname, rr->cname); + } +@@ -515,6 +523,7 @@ + rr.ttl[0] = '\0'; + rr.timestamp[0] = '\0'; + rr.preference[0] = '\0'; ++ rr.location[0] = '\0'; + #if defined DRAFT_RFC + rr.aliasedobjectname[0] = '\0'; + rr.rr[0] = '\0'; +@@ -585,6 +594,11 @@ + rr.preference[0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); ++ } else if (strcasecmp(attr, "DNSlocation")==0) { ++ if (sscanf(bvals[0]->bv_val, "%s", rr.location)!=1) ++ rr.location[0] = '\0'; ++ else if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); + } + #if defined DRAFT_RFC + else if (strcasecmp(attr, "DNSrr")==0) { +@@ -632,10 +646,10 @@ + char soa[20]; + + if (tinyfile) { +- fprintf(tinyfile, "Z%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", ++ fprintf(tinyfile, "Z%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", + zone.domainname, zone.zonemaster, zone.adminmailbox, + zone.serial, zone.refresh, zone.retry, zone.expire, +- zone.minimum, zone.ttl, zone.timestamp); ++ zone.minimum, zone.ttl, zone.timestamp, zone.location); + } + if (namedmaster) { + fprintf(namedmaster, "zone \"%s\" %s {\n\ttype master;\n\tfile \"%s.db\";\n};\n", +@@ -717,6 +731,7 @@ + zone.minimum[0] = '\0'; + zone.ttl[0] = '\0'; + zone.timestamp[0] = '\0'; ++ zone.location[0] = '\0'; + dn = ldap_get_dn(ldap_con, m); + if (options.ldifname[0]) + fprintf(ldifout, "dn: %s\n", dn); +@@ -782,6 +797,11 @@ + zone.timestamp[0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, zone.timestamp); ++ } else if (strcasecmp(attr, "DNSlocation")==0) { ++ if (sscanf(bvals[0]->bv_val, "%2s", zone.location)!=1) ++ zone.location[0] = '\0'; ++ else if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, zone.location); + } + } + ldap_value_free_len(bvals); +@@ -815,6 +835,91 @@ + ldap_msgfree(res); + } + ++static void write_loccode(int lidx) ++{ ++ if (tinyfile) { ++ fprintf(tinyfile, "%%%s:%s\n", loc_rec.locname, loc_rec.member[lidx]); ++ } ++ if (options.ldifname[0]) ++ fprintf(ldifout, "\n"); ++} ++ ++ ++static void read_loccodes(void) ++{ ++ LDAPMessage* res = NULL; ++ LDAPMessage* m; ++ int ldaperr; ++ ++ if (tinyfile) ++ fprintf(tinyfile, "# Location Codes (if any) - generated by ldap2dns - DO NOT EDIT!\n"); ++ ++ if ( (ldaperr = ldap_search_s(ldap_con, options.searchbase[0] ? options.searchbase : NULL, ++ LDAP_SCOPE_SUBTREE, ++ "objectclass=DNSloccodes", ++ NULL, ++ 0, ++ &res) ++ )!=LDAP_SUCCESS ) ++ die_ldap(ldaperr); ++ for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { ++ BerElement* ber = NULL; ++ char* attr; ++ char* dn = ldap_get_dn(ldap_con, m); ++ int i, locmembers = 0; ++ char l_members[256][15]; ++ //char loc[256][64]; ++ char loc[2]; ++ char ldif0; ++ ++ loc_rec.locname[0] = '\0'; ++ if (options.ldifname[0]) ++ fprintf(ldifout, "dn: %s\n", dn); ++ for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { ++ struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); ++ if (bvals!=NULL) { ++ if (bvals[0] && bvals[0]->bv_len>0) { ++ if (strcasecmp(attr, "objectclass")==0 ++ || strcasecmp(attr, "cn")==0) { ++ if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); ++ } else if (strcasecmp(attr, "DNSlocation")==0) { ++ if (sscanf(bvals[0]->bv_val, "%2s", loc_rec.locname)!=1) ++ loc_rec.locname[0] = '\0'; ++ else if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, loc_rec.locname); ++ } else if (strcasecmp(attr, "DNSipaddr")==0) { ++ for (locmembers = 0; bvals[locmembers] && locmembers<256; locmembers++) { ++ if (sscanf(bvals[locmembers]->bv_val, "%15s", loc_rec.member[locmembers])!=1) ++ loc_rec.member[locmembers][0] = '\0'; ++ else if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, loc_rec.member[locmembers]); ++ } ++ } else { ++ if (options.ldifname[0]) ++ fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); ++ } ++ } ++ ldap_value_free_len(bvals); ++ } ++ } ++ ldif0 = options.ldifname[0]; ++ if (options.verbose&1) ++ printf("locationcodename: %s (%d members)\n", loc_rec.locname, locmembers); ++ for (i = 0; i0) ++ options.ldifname[0] = '\0'; ++ write_loccode(i); ++ if (options.ldifname[0]) ++ fprintf(ldifout, "\n"); ++ } ++ options.ldifname[0] = ldif0; ++ free(dn); ++ } ++ ldap_msgfree(res); ++} ++ ++ + static int connect() + { + int i, rc, version; +@@ -906,6 +1011,7 @@ + die_exit("Unable to open file 'data.temp' for writing"); + if ( options.output&OUTPUT_DB && !(namedmaster = fopen("named.zones", "w")) ) + die_exit("Unable to open file 'named.zones' for writing"); ++ read_loccodes(); + read_dnszones(); + if (namedmaster) + fclose(namedmaster); +Gemeinsame Unterverzeichnisse: ldap2dns-0.3.1-p1/webadmin und ldap2dns-0.3.1/webadmin. diff --git a/ldap2dns.c b/ldap2dns.c index a54dc3d..d70d8bd 100644 --- a/ldap2dns.c +++ b/ldap2dns.c @@ -1,6 +1,6 @@ /* * Create data from an LDAP directory service to be used for tinydns - * $Id: ldap2dns.c,v 1.30 2001/08/09 10:35:49 jrief Exp $ + * $Id: ldap2dns.c,v 1.33 2003/01/20 14:33:25 jrief Exp $ * Copyright 2000 by Jacob Rief * License: GPL version 2 or later. See http://www.fsf.org for details */ @@ -14,7 +14,7 @@ #include #define UPDATE_INTERVALL 59 -#define LDAP_CONF "/etc/ldap.conf" +#define LDAP_CONF "/etc/ldap/ldap.conf" #define OUTPUT_DATA 1 #define OUTPUT_DB 2 #define MAXHOSTS 10 @@ -58,8 +58,15 @@ static struct char minimum[12]; char ttl[12]; char timestamp[20]; + char location[2]; } zone; +static struct +{ + char locname[3]; + char member[256][16]; +} loc_rec; + struct resourcerecord { char cn[64]; @@ -72,6 +79,7 @@ struct resourcerecord char ttl[12]; char timestamp[20]; char preference[12]; + char location[2]; #if defined DRAFT_RFC char rr[1024]; char aliasedobjectname[256]; @@ -85,6 +93,7 @@ static struct char searchbase[128]; char binddn[128]; char hostname[MAXHOSTS][128]; + char urildap[MAXHOSTS][128]; int port[MAXHOSTS]; char password[128]; int usedhosts; @@ -94,6 +103,7 @@ static struct int verbose; char ldifname[128]; char exec_command[128]; + int use_tls[MAXHOSTS]; } options; @@ -130,7 +140,8 @@ static void set_datadir(void) static void print_usage(void) { print_version(); - printf("usage: ldap2dns[d] [-D binddn] [-b searchbase] [-o data|db] [-h host] [-p port] [-w password] [-L[filename]] [-u numsecs] [-v[v]] [-V]\n\n"); + printf("usage: ldap2dns[d] [-D binddn] [-b searchbase] [-o data|db] [-h host] [-p port] [-H hostURI] " + "[-w password] [-L[filename]] [-u numsecs] [-v[v]] [-V]\n\n"); printf("ldap2dns connects to an LDAP server reads the DNS information stored in objectclasses\n" "\t\tDNSzone and DNSrrset and writes a file to be used by tinydns or named.\n" "\t\tldap2dnsd starts as background-job and continouesly updates DNS information.\n"); @@ -143,6 +154,7 @@ static void print_usage(void) printf(" -L[filename] Print output in LDIF format for reimport\n"); printf(" -h host\tHostname of LDAP server, defaults to localhost\n"); printf(" -p port\tPortnumber to connect to LDAP server, defaults to %d\n", LDAP_PORT); + printf(" -H hostURI\tURI (ldap://hostname or ldaps://hostname of LDAP server\n"); printf(" -u numsecs\tUpdate DNS data after numsecs. Defaults to %d if started as daemon.\n\t\t" "Important notice: data.cdb is rewritten only after DNSserial in DNSzone is increased.\n", UPDATE_INTERVALL); @@ -159,7 +171,18 @@ static void parse_hosts(char* buf) options.usedhosts = 0; for (i = 0; i=2) { + if (!strncasecmp(buf, "ldaps://", 8) || !strncasecmp(buf, "ldap://", 7)) { + // LDAP-URI is given/found, at the moment only the standard-ports 389 and 636 are supported + if (!strncasecmp(buf, "ldap://", 7)) + options.use_tls[i] = 1; + if ((k = sscanf(buf, "%128s %512[A-Za-z0-9 .:/_+-]", value, rest))>=1) { + strcpy(options.urildap[i], value); + options.usedhosts++; + if (k==1) + break; + buf = rest; + } else break; + } else if ((k = sscanf(buf, "%128s:%d %512[A-Za-z0-9 .:_+-]", value, &port, rest))>=2) { strcpy(options.hostname[i], value); options.port[i] = port; options.usedhosts++; @@ -194,6 +217,8 @@ static int parse_options() int i; if (sscanf(buf, "BASE %128s", value)==1) strcpy(options.searchbase, value); + if (sscanf(buf, "URI %512[A-Za-z0-9 .:/_+-]", value)==1) + parse_hosts(value); if (sscanf(buf, "HOST %512[A-Za-z0-9 .:_+-]", value)==1) parse_hosts(value); if (sscanf(buf, "PORT %d", &len)==1) @@ -239,7 +264,7 @@ static int parse_options() options.ldifname[0] = '\0'; strcpy(options.password, ""); strcpy(options.exec_command, ""); - while ( (len = getopt(main_argc, main_argv, "b:D:e:h:o:p:u:V:v::w:L::"))>0 ) { + while ( (len = getopt(main_argc, main_argv, "b:D:e:h:H:o:p:u:V:v::w:L::"))>0 ) { if (optarg && strlen(optarg)>127) { fprintf(stderr, "argument %s too long\n", optarg); continue; @@ -260,6 +285,10 @@ static int parse_options() strcpy(options.hostname[0], optarg); options.usedhosts = 1; break; + case 'H': + strcpy(options.urildap[0], optarg); + options.usedhosts = 1; + break; case 'L': if (optarg==NULL) strcpy(options.ldifname, "-"); @@ -339,19 +368,19 @@ static void write_rr(struct resourcerecord* rr, int ipdx, int znix) if (tinyfile) { if (znix==0) { if (ipdx<=0 && rr->cipaddr[0]) { - fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); if (rr->cname[0]) - fprintf(tinyfile, "=%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp); + fprintf(tinyfile, "=%s:%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); if (ipdx==0) - fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp); + fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp, rr->location); } else if (ipdx<0) - fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); else if (ipdx==0) - fprintf(tinyfile, "&%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "&%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->ttl, rr->timestamp, rr->location); else if (ipdx>0 && rr->cname[0]) - fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); + fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); } else if (ipdx<=0) { - fprintf(tinyfile, "&%s::%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "&%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); } } if (namedzone) { @@ -363,19 +392,19 @@ static void write_rr(struct resourcerecord* rr, int ipdx, int znix) if (tinyfile) { if (znix==0) { if (ipdx<=0 && rr->cipaddr[0]) { - fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); + fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); if (rr->cname[0]) - fprintf(tinyfile, "=%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp); + fprintf(tinyfile, "=%s:%s:%s:%s:%s\n", rr->cname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); if (ipdx==0) - fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp); + fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[0], rr->ttl, rr->timestamp, rr->location); } else if (ipdx<0) - fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); + fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); else if (ipdx==0) - fprintf(tinyfile, "@%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->preference, rr->ttl, rr->timestamp); + fprintf(tinyfile, "@%s:%s:%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[0], rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); else if (ipdx>0 && rr->cname[0]) - fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); + fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->cname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); } else if (ipdx<=0) { - fprintf(tinyfile, "@%s::%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp); + fprintf(tinyfile, "@%s::%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->preference, rr->ttl, rr->timestamp, rr->location); } } if (namedzone) { @@ -386,9 +415,9 @@ static void write_rr(struct resourcerecord* rr, int ipdx, int znix) } else if ( strcasecmp(rr->type, "A")==0) { if (tinyfile) { if (ipdx<=0 && rr->cipaddr[0]) - fprintf(tinyfile, "%s%s:%s:%s:%s\n", (znix==0 ? "=" : "+"), rr->dnsdomainname, rr->cipaddr, rr->ttl, rr->timestamp); + fprintf(tinyfile, "%s%s:%s:%s:%s:%s\n", (znix==0 ? "=" : "+"), rr->dnsdomainname, rr->cipaddr, rr->ttl, rr->timestamp, rr->location); if (ipdx>=0) - fprintf(tinyfile, "+%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp); + fprintf(tinyfile, "+%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->ipaddr[ipdx], rr->ttl, rr->timestamp, rr->location); } if (namedzone) { if (ipdx<=0 && rr->cipaddr[0]) @@ -410,17 +439,17 @@ static void write_rr(struct resourcerecord* rr, int ipdx, int znix) strcpy(buf, rr->dnsdomainname); } if (tinyfile) - fprintf(tinyfile, "^%s:%s:%s:%s\n", buf, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "^%s:%s:%s:%s:%s\n", buf, rr->cname, rr->ttl, rr->timestamp, rr->location); if (namedzone) fprintf(namedzone, "%s.\tIN PTR\t%s.\n", buf, rr->cname); } else if (strcasecmp(rr->type, "CNAME")==0) { if (tinyfile) - fprintf(tinyfile, "C%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "C%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); if (namedzone) fprintf(namedzone, "%s.\tIN CNAME\t%s.\n", rr->dnsdomainname, rr->cname); } else if (strcasecmp(rr->type, "TXT")==0) { if (tinyfile) - fprintf(tinyfile, "'%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp); + fprintf(tinyfile, "'%s:%s:%s:%s:%s\n", rr->dnsdomainname, rr->cname, rr->ttl, rr->timestamp, rr->location); if (namedzone) fprintf(namedzone, "%s.\tIN TXT\t%s.\n", rr->dnsdomainname, rr->cname); } @@ -474,7 +503,7 @@ static void read_resourcerecords(char* dn, int znix) LDAPMessage* m; int ldaperr; - if ( (ldaperr = ldap_search_s(ldap_con, dn, LDAP_SCOPE_ONELEVEL, "objectclass=DNSrrset", NULL, 0, &res))!=LDAP_SUCCESS ) + if ( (ldaperr = ldap_search_s(ldap_con, dn, LDAP_SCOPE_SUBTREE, "objectclass=DNSrrset", NULL, 0, &res))!=LDAP_SUCCESS ) die_ldap(ldaperr); for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { BerElement* ber = NULL; @@ -494,6 +523,7 @@ static void read_resourcerecords(char* dn, int znix) rr.ttl[0] = '\0'; rr.timestamp[0] = '\0'; rr.preference[0] = '\0'; + rr.location[0] = '\0'; #if defined DRAFT_RFC rr.aliasedobjectname[0] = '\0'; rr.rr[0] = '\0'; @@ -564,6 +594,11 @@ static void read_resourcerecords(char* dn, int znix) rr.preference[0] = '\0'; else if (options.ldifname[0]) fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); + } else if (strcasecmp(attr, "DNSlocation")==0) { + if (sscanf(bvals[0]->bv_val, "%s", rr.location)!=1) + rr.location[0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); } #if defined DRAFT_RFC else if (strcasecmp(attr, "DNSrr")==0) { @@ -611,17 +646,17 @@ static void write_zone(void) char soa[20]; if (tinyfile) { - fprintf(tinyfile, "Z%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", + fprintf(tinyfile, "Z%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", zone.domainname, zone.zonemaster, zone.adminmailbox, zone.serial, zone.refresh, zone.retry, zone.expire, - zone.minimum, zone.ttl, zone.timestamp); + zone.minimum, zone.ttl, zone.timestamp, zone.location); } if (namedmaster) { fprintf(namedmaster, "zone \"%s\" %s {\n\ttype master;\n\tfile \"%s.db\";\n};\n", zone.domainname, zone.class, zone.domainname); } if (namedzone) { - fprintf(namedzone, "# Automatically generated by ldap2dns - DO NOT EDIT!\n"); + fprintf(namedzone, "; Automatically generated by ldap2dns - DO NOT EDIT!\n"); if (zone.ttl[0]) fprintf(namedzone, "$TTL %s\n", zone.ttl); else @@ -677,7 +712,7 @@ static void read_dnszones(void) if (tinyfile) fprintf(tinyfile, "# Automatically generated by ldap2dns - DO NOT EDIT!\n"); if (namedmaster) - fprintf(namedmaster, "# Automatically generated by ldap2dns - DO NOT EDIT!\n"); + fprintf(namedmaster, "; Automatically generated by ldap2dns - DO NOT EDIT!\n"); if ( (ldaperr = ldap_search_s(ldap_con, options.searchbase[0] ? options.searchbase : NULL, LDAP_SCOPE_SUBTREE, "objectclass=DNSzone", NULL, 0, &res))!=LDAP_SUCCESS ) die_ldap(ldaperr); for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { @@ -696,6 +731,7 @@ static void read_dnszones(void) zone.minimum[0] = '\0'; zone.ttl[0] = '\0'; zone.timestamp[0] = '\0'; + zone.location[0] = '\0'; dn = ldap_get_dn(ldap_con, m); if (options.ldifname[0]) fprintf(ldifout, "dn: %s\n", dn); @@ -761,6 +797,11 @@ static void read_dnszones(void) zone.timestamp[0] = '\0'; else if (options.ldifname[0]) fprintf(ldifout, "%s: %s\n", attr, zone.timestamp); + } else if (strcasecmp(attr, "DNSlocation")==0) { + if (sscanf(bvals[0]->bv_val, "%2s", zone.location)!=1) + zone.location[0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, zone.location); } } ldap_value_free_len(bvals); @@ -794,14 +835,124 @@ static void read_dnszones(void) ldap_msgfree(res); } +static void write_loccode(int lidx) +{ + if (tinyfile) { + fprintf(tinyfile, "%%%s:%s\n", loc_rec.locname, loc_rec.member[lidx]); + } + if (options.ldifname[0]) + fprintf(ldifout, "\n"); +} + + +static void read_loccodes(void) +{ + LDAPMessage* res = NULL; + LDAPMessage* m; + int ldaperr; + + if (tinyfile) + fprintf(tinyfile, "# Location Codes (if any) - generated by ldap2dns - DO NOT EDIT!\n"); + + if ( (ldaperr = ldap_search_s(ldap_con, options.searchbase[0] ? options.searchbase : NULL, + LDAP_SCOPE_SUBTREE, + "objectclass=DNSloccodes", + NULL, + 0, + &res) + )!=LDAP_SUCCESS ) + die_ldap(ldaperr); + for (m = ldap_first_entry(ldap_con, res); m; m = ldap_next_entry(ldap_con, m)) { + BerElement* ber = NULL; + char* attr; + char* dn = ldap_get_dn(ldap_con, m); + int i, locmembers = 0; + char l_members[256][15]; + //char loc[256][64]; + char loc[2]; + char ldif0; + + loc_rec.locname[0] = '\0'; + if (options.ldifname[0]) + fprintf(ldifout, "dn: %s\n", dn); + for (attr = ldap_first_attribute(ldap_con, m, &ber); attr; attr = ldap_next_attribute(ldap_con, m, ber)) { + struct berval** bvals = ldap_get_values_len(ldap_con, m, attr); + if (bvals!=NULL) { + if (bvals[0] && bvals[0]->bv_len>0) { + if (strcasecmp(attr, "objectclass")==0 + || strcasecmp(attr, "cn")==0) { + if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); + } else if (strcasecmp(attr, "DNSlocation")==0) { + if (sscanf(bvals[0]->bv_val, "%2s", loc_rec.locname)!=1) + loc_rec.locname[0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, loc_rec.locname); + } else if (strcasecmp(attr, "DNSipaddr")==0) { + for (locmembers = 0; bvals[locmembers] && locmembers<256; locmembers++) { + if (sscanf(bvals[locmembers]->bv_val, "%15s", loc_rec.member[locmembers])!=1) + loc_rec.member[locmembers][0] = '\0'; + else if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, loc_rec.member[locmembers]); + } + } else { + if (options.ldifname[0]) + fprintf(ldifout, "%s: %s\n", attr, bvals[0]->bv_val); + } + } + ldap_value_free_len(bvals); + } + } + ldif0 = options.ldifname[0]; + if (options.verbose&1) + printf("locationcodename: %s (%d members)\n", loc_rec.locname, locmembers); + for (i = 0; i0) + options.ldifname[0] = '\0'; + write_loccode(i); + if (options.ldifname[0]) + fprintf(ldifout, "\n"); + } + options.ldifname[0] = ldif0; + free(dn); + } + ldap_msgfree(res); +} + + static int connect() { - int i; + int i, rc, version; for (i = 0; i 0) { + rc = ldap_initialize(&ldap_con, options.urildap[i]); + if (options.verbose&1 && rc == LDAP_SUCCESS) { + printf("ldap_initialization successful (%s)\n", options.urildap[i]); + } else if ( rc != LDAP_SUCCESS ) { + printf("ldap_initialization to %s failed %d\n", options.urildap[i], ldap_err2string(rc)); + ldap_con = NULL; + return 0; + } + version = LDAP_VERSION3; + if ( (rc=ldap_set_option(ldap_con, LDAP_OPT_PROTOCOL_VERSION, &version)) != LDAP_SUCCESS ) { + printf("ldap_set_option to %s failed with err %s!\n", options.urildap[i], ldap_err2string(rc)); + ldap_con = NULL; + return 0; + } + if ( options.use_tls[i] && (rc=ldap_start_tls_s( ldap_con, NULL, NULL )) != LDAP_SUCCESS ) { + printf("ldap_start_tls_s to %s failed with err %s!\n", options.urildap[i], ldap_err2string(rc)); + ldap_con = NULL; + return 0; + } + } else { + ldap_con = ldap_init(options.hostname[i], options.port[i]); + } if (ldap_simple_bind_s(ldap_con, options.binddn, options.password)==LDAP_SUCCESS) { - if (options.verbose&1) + if (options.verbose&1 && strlen(options.urildap[i]) > 0) { + printf("Connected to %s as \"%s\"\n", options.urildap[i], options.binddn); + } else if (options.verbose&1) { printf("Connected to %s:%d as \"%s\"\n", options.hostname[i], options.port[i], options.binddn); + } return 1; } } @@ -860,6 +1011,7 @@ int main(int argc, char** argv) die_exit("Unable to open file 'data.temp' for writing"); if ( options.output&OUTPUT_DB && !(namedmaster = fopen("named.zones", "w")) ) die_exit("Unable to open file 'named.zones' for writing"); + read_loccodes(); read_dnszones(); if (namedmaster) fclose(namedmaster); diff --git a/webadmin/.htaccess b/webadmin/.htaccess new file mode 100644 index 0000000..070e8fc --- /dev/null +++ b/webadmin/.htaccess @@ -0,0 +1,2 @@ +AddType application/x-httpd-php .php +DirectoryIndex index.php diff --git a/webadmin/common.inc b/webadmin/common.inc new file mode 100644 index 0000000..f07931e --- /dev/null +++ b/webadmin/common.inc @@ -0,0 +1,81 @@ +

$errmsg


\n"; + log_action("error: ".$errmsg); +} + +function log_action($errmsg) +{ + global $LOGFILE, $REMOTE_ADDR, $PHP_AUTH_USER; + $fd = fopen("$LOGFILE", "a"); + fwrite($fd, "[".date("H:i:s d/M/Y")."] $PHP_AUTH_USER@$REMOTE_ADDR $errmsg\n"); + fclose($fd); +} + +# Use this function to determine contraints on objects and returns a set +# of characters with the following meaning: +# o: binddn owns the object +# a: binddn is administrator +# m: binddn is member +function check_constraint($dn = "") +{ + global $ldap, $binddn, $BASEDN; + $result = ""; + $num_owners = 0; + if (strlen($dn)>0) { + // get owners for this object + $query = ldap_read($ldap, $dn, "(objectclass=*)", array("owner")); + $entries = ldap_get_entries($ldap, $query); + ldap_free_result($query); + $num_owners = $entries[0][owner][count]; + for ($i = 0; $i<$num_owners; $i++) { + if ($entries[0][owner][$i]==$binddn) { + $result .= "o"; + $num_owners = 0; + } + } + } + // get administrators for BASEDN + $query = ldap_read($ldap, $BASEDN, "(objectclass=*)", array("administrator", "member")); + $entries = ldap_get_entries($ldap, $query); + ldap_free_result($query); + for ($i = 0; $i<$entries[0][administrator][count]; $i++) { + if ($entries[0][administrator][$i]==$binddn) { + $result .= "a"; + break; + } + } + if ($num_owners==0) { + // only objects owned by nobody except binddn are granted to members + for ($i = 0; $i<$entries[0][member][count]; $i++) { + if ($entries[0][member][$i]==$binddn) { + $result .= "m"; + break; + } + } + } + print ""; + return $result; +} + +?> diff --git a/webadmin/config.inc b/webadmin/config.inc new file mode 100644 index 0000000..5ee0603 --- /dev/null +++ b/webadmin/config.inc @@ -0,0 +1,44 @@ + "", + "dnsserial" => "", + "dnsclass" => "IN", + "dnstype" => "SOA", + "dnsexpire" => "604800", + "dnsretry" => "3600", + "dnsminimum" => "86400", + "dnsrefresh" => "10800", + "dnsttl" => "3600", + "dnszonemaster" => "ns1.company.com.", + "dnsadminmailbox" => "hostmaster.company.com.", +); +$ZONE_ENTRY = array( + array("cn"=>"NS1:", "objectclass"=>"dnsrrset", "dnstype"=>"NS", "dnsclass"=>"IN", "dnsttl"=>"3600", "dnscname"=>"ns1.company.com."), + array("cn"=>"NS2:", "objectclass"=>"dnsrrset", "dnstype"=>"NS", "dnsclass"=>"IN", "dnsttl"=>"3600", "dnscname"=>"ns2.company.com."), +); + +#################### whois configuration #################### +$WHOISSERVERS = array( "at"=>"whois.nic.at", "de"=>"whois.denic.de", "ch"=>"whois.nic.ch", + "com"=>"whois.networksolutions.com", "net"=>"whois.networksolutions.com", + "org"=>"whois.networksolutions.com", "be"=>"whois.dns.be", "cz"=>"whois.nic.cz", + "fr"=>"whois.nic.fr", "hu"=>"whois.nic.hu", "it"=>"whois.nic.it", "dk"=>"whois.dk-hostmaster.dk", + "li"=>"whois.nic.li", "lu"=>"whois.dns.lu", "cc"=>"whois.nic.cc", "uk"=>"whois.nic.uk" ); +?> diff --git a/webadmin/footer.inc b/webadmin/footer.inc new file mode 100644 index 0000000..8d4ef1e --- /dev/null +++ b/webadmin/footer.inc @@ -0,0 +1,3 @@ +
+ + diff --git a/webadmin/framesets.inc b/webadmin/framesets.inc new file mode 100644 index 0000000..29186c3 --- /dev/null +++ b/webadmin/framesets.inc @@ -0,0 +1,8 @@ +DNS Zone Admin + + + + + You need a frame capable browser + + diff --git a/webadmin/icons/branch-cont.gif b/webadmin/icons/branch-cont.gif new file mode 100644 index 0000000..29a4e9b Binary files /dev/null and b/webadmin/icons/branch-cont.gif differ diff --git a/webadmin/icons/branch-end.gif b/webadmin/icons/branch-end.gif new file mode 100644 index 0000000..b3d5b2f Binary files /dev/null and b/webadmin/icons/branch-end.gif differ diff --git a/webadmin/icons/folder-closed.gif b/webadmin/icons/folder-closed.gif new file mode 100644 index 0000000..b785fc4 Binary files /dev/null and b/webadmin/icons/folder-closed.gif differ diff --git a/webadmin/icons/folder-open.gif b/webadmin/icons/folder-open.gif new file mode 100644 index 0000000..ff82c95 Binary files /dev/null and b/webadmin/icons/folder-open.gif differ diff --git a/webadmin/icons/img-blank.gif b/webadmin/icons/img-blank.gif new file mode 100644 index 0000000..449af00 Binary files /dev/null and b/webadmin/icons/img-blank.gif differ diff --git a/webadmin/icons/img-vert-line.gif b/webadmin/icons/img-vert-line.gif new file mode 100644 index 0000000..648e755 Binary files /dev/null and b/webadmin/icons/img-vert-line.gif differ diff --git a/webadmin/icons/minus-cont.gif b/webadmin/icons/minus-cont.gif new file mode 100644 index 0000000..a86b6b6 Binary files /dev/null and b/webadmin/icons/minus-cont.gif differ diff --git a/webadmin/icons/minus-end.gif b/webadmin/icons/minus-end.gif new file mode 100644 index 0000000..dc3b247 Binary files /dev/null and b/webadmin/icons/minus-end.gif differ diff --git a/webadmin/icons/plus-cont.gif b/webadmin/icons/plus-cont.gif new file mode 100644 index 0000000..b05c448 Binary files /dev/null and b/webadmin/icons/plus-cont.gif differ diff --git a/webadmin/icons/plus-end.gif b/webadmin/icons/plus-end.gif new file mode 100644 index 0000000..b617d61 Binary files /dev/null and b/webadmin/icons/plus-end.gif differ diff --git a/webadmin/icons/zone_forb.gif b/webadmin/icons/zone_forb.gif new file mode 100644 index 0000000..94c250c Binary files /dev/null and b/webadmin/icons/zone_forb.gif differ diff --git a/webadmin/icons/zone_new.gif b/webadmin/icons/zone_new.gif new file mode 100644 index 0000000..192039b Binary files /dev/null and b/webadmin/icons/zone_new.gif differ diff --git a/webadmin/icons/zone_unkn.gif b/webadmin/icons/zone_unkn.gif new file mode 100644 index 0000000..c35cd9e Binary files /dev/null and b/webadmin/icons/zone_unkn.gif differ diff --git a/webadmin/icons/zone_unre.gif b/webadmin/icons/zone_unre.gif new file mode 100644 index 0000000..3abcd86 Binary files /dev/null and b/webadmin/icons/zone_unre.gif differ diff --git a/webadmin/icons/zone_val.gif b/webadmin/icons/zone_val.gif new file mode 100644 index 0000000..54433f3 Binary files /dev/null and b/webadmin/icons/zone_val.gif differ diff --git a/webadmin/index.php b/webadmin/index.php new file mode 100644 index 0000000..902c5ca --- /dev/null +++ b/webadmin/index.php @@ -0,0 +1,725 @@ +0) { + zone_edit_plus($zonedn); + } else { + new_zone($HTTP_GET_VARS[zonename]); + } + } + include("footer.inc"); + break; + case "editzone": + connect_ldap(); + include("mainheader.inc"); + if (isset($HTTP_POST_VARS[modifysoa])) { + modify_zone_soa($HTTP_POST_VARS[zonedn]); + log_action("modify_zone_soa: $HTTP_POST_VARS[zonedn]"); + } elseif (isset($HTTP_POST_VARS[addrrset])) { + add_rrset($HTTP_POST_VARS[zonedn]); + log_action("add_rrset: $HTTP_POST_VARS[zonedn]"); + } elseif (isset($HTTP_POST_VARS[modifyrrset])) { + if (isset($HTTP_POST_VARS[deleterrset])) { + delete_rrset($HTTP_POST_VARS[zonedn], $HTTP_POST_VARS[setdn]); + log_action("delete_rrset: $HTTP_POST_VARS[setdn]"); + } else { + modify_rrset($HTTP_POST_VARS[zonedn], $HTTP_POST_VARS[setdn]); + log_action("modify_rrset: ".$HTTP_POST_VARS[setdn]); + } + } + if (isset($HTTP_GET_VARS[zonedn])) + zone_edit_plus($HTTP_GET_VARS[zonedn]); + elseif (isset($HTTP_POST_VARS[zonedn])) + edit_zone_attrs($HTTP_POST_VARS[zonedn]); + include("footer.inc"); + break; + case "newzone": + connect_ldap(); + include("mainheader.inc"); + new_zone(); + include("footer.inc"); + break; + case "addzone": + connect_ldap(); + include("mainheader.inc"); + zone_edit_plus(add_zone()); + include("footer.inc"); + break; + case "removezone": + connect_ldap(); + if (isset($HTTP_GET_VARS[zonedn]) && remove_zone($HTTP_GET_VARS[zonedn])) { + include("xearthheader.inc"); + include("footer.inc"); + } + break; + } +} + + +function full_dns_list() +{ + global $ldap, $BASEDN, $ZONEEDIT, $HTTP_GET_VARS; + $letters = array( "0-9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q-R","S","T","U","V","W","X-Z" ); + if (isset($HTTP_GET_VARS[wait])) sleep($HTTP_GET_VARS[wait]); + if (isset($HTTP_GET_VARS[selet])) $selet = $HTTP_GET_VARS[selet]; +?> +
+ + Find  +
+" TARGET="main"> +  Add new Zone
+". + "". + "...$let
\n"; + } else { + $newselet = $selet.$let; + print "". + "". + "...$let
\n"; + continue; + } + $filter = "(&(objectclass=dnszone)"; + if (ereg("([0-9A-Z])-([0-9A-Z])", $let, $regs)) { + $filter .= "(|"; + for ($i = ord($regs[1]); $i<=ord($regs[2]); $i++) { + $filter .= "(cn=".chr($i)."*)"; + } + $filter .= "))"; + } else { + $filter .= "(cn=$let*))"; + } + $query = ldap_search($ldap, $BASEDN, $filter); + //ldap_sort($ldap, $query, "cn"); + $entries = ldap_get_entries($ldap, $query); + ldap_free_result($query); + for ($i = 0; $i<$entries[count]; $i++) { + $zonedn = $entries[$i]["dn"]; + $zonename = $entries[$i]["dnszonename"][0]; + $tree2 = ($i==$entries[count]-1 ? "end" : "cont"); + print "". + "". + " $zonename
\n"; + } + print "\n"; + } + #print "Without DNS-lookup
\n"; + } else { + print "With DNS-lookup
\n"; + } +} + +function individual_dns_list() +{ + global $ldap, $binddn, $BASEDN, $ZONEEDIT, $HTTP_GET_VARS; + $query = ldap_search($ldap, $BASEDN, "(&(objectclass=DNSzone)(owner=$binddn))"); + $entries = ldap_get_entries($ldap, $query); + for ($i = 0; $i<$entries[count]; $i++) { + $zonedn = $entries[$i][dn]; + $zonename = $entries[$i][dnszonename][0]; + $tree = ($i==$entries[count]-1 ? "end" : "cont"); + print "". + "". + " $zonename
\n"; + } +} + +function search_zone($zonename) +{ + global $ldap, $BASEDN; + $filter = "(&(objectclass=dnszone)(dnszonename=$zonename))"; + $query = ldap_search($ldap, $BASEDN, $filter); + $entries = ldap_get_entries($ldap, $query); + if ($entries[count]>1) { + $mesg = "Ambigous zonenames $zonename in
"; + for ($i = 0; $i<$entries[count]; $i++) { + $mesg .= "dn: ". + $entries[$i]["dn"]."
"; + } + print "

Warning: $mesg

"; + exit; + } + if ($entries[count]==1) { + return $entries[0][dn]; + } else switch (authorized($zonename)) { + case -2: + error_confirm("The zone does not belong to a valid top level domain"); + exit; + case -1: + error_confirm("The zone is owned by someone else"); + print_whois($zonename); + exit; + default: + return; + } +} + +function print_zone_soa($zonedata, $constr) +{ + print "Serial: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsserial"]." "; + } + print "Refresh: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsrefresh"]." "; + } + print "\nRetry: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsretry"]." "; + } + print "\nExpire: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsexpire"]." "; + } + print "\nMinimum: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsminimum"]." "; + } + print "\nAdminmailbox: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsadminmailbox"]." "; + } + print "\nZonemaster: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnszonemaster"]." "; + } + print "\nTime to live: "; + if (ereg("[amo]", $constr)) { + print ""; + } else { + print " ".$zonedata["dnsttl"]." "; + } + print "\n"; +} + +function get_zone_name($zonedn) +{ + global $ldap; + $query = ldap_read($ldap, $zonedn, "(objectclass=dnszone)", array("dnszonename")); + $entries = ldap_get_entries($ldap, $query); + $zonename = $entries[0][dnszonename][0]; + ldap_free_result($query); + return $zonename; +} + +function modify_zone_soa($zonedn) +{ + global $ldap, $ZONE_INFO, $HTTP_POST_VARS; + $zonename = get_zone_name($zonedn); + $entry = array(); + foreach ($ZONE_INFO as $za) { + if (strlen($HTTP_POST_VARS["$za"])>0) + $entry["$za"] = $HTTP_POST_VARS["$za"]; + } + if (ereg("[a]", check_constraint($zonedn))) { + $entry[dnszonename] = array("$zonename"); + for ($i = 0; isset($HTTP_POST_VARS["dnszonename$i"]); $i++) { + if (strlen($HTTP_POST_VARS["dnszonename$i"])>3) + array_push($entry[dnszonename], $HTTP_POST_VARS["dnszonename$i"]); + } + } + ldap_modify($ldap, $zonedn, $entry) or die("ldap_modify failed to update SOA for $zonedn"); +} + +function authorized($zonename) +{ + return 1; +} + +function zone_edit_plus($zonedn) +{ + $zonename = get_zone_name($zonedn); + $auth = authorized($zonename); + if ($auth==1) { + print "

The nameserver is active and authorized to handle this zone

\n"; + edit_zone_attrs($zonedn); + print_whois($zonename); + } elseif ($auth==0) { + print "

The nameserver is not active for this zone

\n"; + edit_zone_attrs($zonedn); + print_whois($zonename); + } elseif ($auth==-1) { + print "

The nameserver is not authorized to handle this zone

\n"; + edit_zone_attrs($zonedn); + print_whois($zonename); + } else { + print "

Zone $zonename does not not belong to a valid TLD

\n"; + delete_zone(); + } +} + +function edit_zone_attrs($zonedn) +{ + global $ldap, $ZONE_INFO, $ZONEEDIT, $HTTP_GET_VARS, $HTTP_POST_VARS; + if (isset($HTTP_GET_VARS[selet])) $selet = $HTTP_GET_VARS[selet]; elseif (isset($HTTP_POST_VARS[selet])) $selet = $HTTP_POST_VARS[selet]; + $query = ldap_read($ldap, $zonedn, "(objectclass=dnszone)"); + $entries = ldap_get_entries($ldap, $query); + $zonename = $entries[0][dnszonename][0]; + ldap_free_result($query); + $zonedn = $entries[0][dn]; + $zonename0 = $entries[0][dnszonename][0]; + $zonenames = array(); + for ($i = 1; $i<$entries[0][dnszonename][count]; $i++) { + array_push($zonenames, $entries[0][dnszonename][$i]); + } + $zonedata = array(); + foreach ($ZONE_INFO as $za) { + $zonedata[$za] = $entries[0][$za][0]; + } + + print "

Edit DNS zone $zonename0

"; + $zoneconstr = check_constraint($zonedn); + if (ereg("[a]", $zoneconstr)) { + # Print modifiable table for SOA + if (ereg("[f]", $selet)) { + print "
". + "". + ""; + } else { + print "". + "". + "". + ""; + } + print "\n"; + $zc = 0; + foreach ($zonenames as $zn) { + print "\n"; + $zc++; + } + if (ereg("[a]", $zoneconstr)) { + print "\n"; + } + print_zone_soa($zonedata, $zoneconstr); + print "
Aliasing Zonename: "; + if (ereg("[a]", $zoneconstr)) + print ""; + else + print "$zn"; + print "
Add aliasing Zonename: ". + "
". + "

"; + } else { + # Print non-modifiable table for SOA + print "\n"; + foreach ($zonenames as $zn) { + print "\n"; + } + print_zone_soa($zonedata, $zoneconstr); + print "
Aliasing Zonename: $zn

\n"; + } + + # Tables for RRsets + $query = ldap_list($ldap, $zonedn, "(objectclass=dnsrrset)"); + $rrsets = ldap_get_entries($ldap, $query); + ldap_free_result($query); + print "\n". + "". + "\n"; + for ($i = 0; $i<$rrsets[count]; $i++) { + $setdn = $rrsets[$i][dn]; + $setconstr = $zoneconstr.check_constraint($setdn); + $domainname = $rrsets[$i][dnsdomainname][0]; + $ipaddr = $rrsets[$i][dnsipaddr]; + $cipaddr = $rrsets[$i][dnscipaddr][0]; + $cname = $rrsets[$i][dnscname][0]; + $type = $rrsets[$i][dnstype][0]; + $ttl = $rrsets[$i][dnsttl][0]; + $preference = $rrsets[$i][dnspreference][0]; + if (ereg("[amo]", $setconstr)) { + if (ereg("[f]", $selet)) { + print "". + "". + "". + "". + ""; + } else { + print "". + "". + "". + ""; + } + } + if (ereg("[amo]", $setconstr)) { + print "
Delete"; + } + print ""; + if (ereg("[amo]", $setconstr)) { + print "\n"; + } else { + print "\n"; + } + } + if (ereg("[amo]", $setconstr)) { + if (ereg("[f]", $selet)) { + print "\n". + "". + "". + "". + "". + "". + "". + "". + ""; + } + print "
DNS NameTypeMappingTTL/Pref 
$type"; + if ($type=="CNAME" || $type=="MX" || $type=="NS") { + print ""; + if (ereg("[amo]", $setconstr)) + print "\n"; + else + print "\n"; + } + if ($type=="A" || $type=="MX" || $type=="NS") { + if (ereg("[a]", $setconstr)) { + print "". + "\n"; + } else if (isset($cipaddr)) { + print "\n"; + } + for ($k = 0; $k<$rrsets[$i][dnsipaddr][count]; $k++) { + print ""; + $ipaddr = $rrsets[$i][dnsipaddr][$k]; + if (ereg("[amo]", $setconstr)) + print "\n"; + else + print "\n"; + } + if (ereg("[amo]", $setconstr)) { + print "\n"; + } + } + print "
CName:
$cname
Canonical IP:
Canonical IP:$cipaddr
Modify IP:
$ipaddr
Add IP:
TTL: "; + if ($type=="MX") + print "
Pref: "; + print "
TTL: $ttl"; + if ($type=="MX") + print "
Pref: $preference"; + print "
 

\n"; + + print ""; + // 'Delete' form + $onclick = "if(confirm('Do you really want to remove zone: $zonename0 and all its resource records?'))"; + if (ereg("[f]", $selet)) { + $onclick .= "{ parent.frames.menu.location='$ZONEEDIT?call=dnslist&selet=$selet&wait=1';". + "parent.frames.main.location='$ZONEEDIT?call=removezone&zonedn=$zonedn&selet=$selet'; }"; + } else { + $onclick .= "{ parent.window.location='$ZONEEDIT?call=removezone&zonedn=$zonedn'; }"; + } + if (ereg("[am]", $setconstr)) { + print "\n"; + } + + // form for reset/refresh button + if (ereg("[f]", $selet)) { + print "". + "". + "". + ""; + } else { + print "". + "". + ""; + } + print "". + "
\n"; +} + +function new_zone($new_zonename = "") +{ + global $HTTP_GET_VARS, $ZONE_SOA, $ZONEEDIT, $BASEDN; + if (isset($HTTP_GET_VARS[selet])) $selet = $HTTP_GET_VARS[selet]; + $zonedata = $ZONE_SOA; + $zonedata[dnsserial] = new_serial(); + $onsubmit = "{ parent.frames.menu.location='$ZONEEDIT?call=dnslist&selet=$selet&wait=1'; }"; + print "

Add new DNS zone

"; + print "
". + "". + "". + "\n". + "\n"; + print_zone_soa($zonedata, check_constraint()); + print "
New Zonename: ". + "". + "
". + "". + "". + "". + "
\n". + "
"; +} + +function add_zone() +{ + global $ldap, $HTTP_POST_VARS, $BASEDN, $ZONE_SOA, $ZONE_ENTRY, $ZONE_INFO; + $zonedata = array(); + foreach ($ZONE_INFO as $za) { + if (strlen($HTTP_POST_VARS[$za])>0) { + $zonedata[$za] = $HTTP_POST_VARS[$za]; + } + } + $zonedata["cn"] = $zonedata["dnszonename"]; + $zonedata["objectclass"] = "dnszone"; + $zonedn = "cn=$zonedata[cn],$BASEDN"; + ldap_add($ldap, $zonedn, $zonedata) or die("Failed to add zonedn: $zonedn"); + + foreach ($ZONE_ENTRY as $ze) { + $dnch = "cn=$ze[cn],$zonedn"; + ldap_add($ldap, $dnch, $ze) or die("Failed to add rrset dn: $dnch"); + } + return $zonedn; +} + +function remove_zone($zonedn) +{ + global $ldap; + $query = ldap_list($ldap, $zonedn, "(objectclass=DNSrrset)"); + $entries = ldap_get_entries($ldap, $query); + ldap_free_result($query); + for ($i = 0; $i<$entries[count]; $i++) { + ldap_delete($ldap, $entries[$i][dn]) or die("Failed to delete dn: $entries[$i][dn]"); + } + ldap_delete($ldap, $zonedn) or die("Failed to delete dn: $zonedn"); + return 1; +} + +function new_serial($zonedn = 0) +{ + global $ldap; + $newserial = date("Ymd")."00"; + if ($zonedn) { + $query = ldap_read($ldap, $zonedn, "(objectclass=DNSzone)"); + $entries = ldap_get_entries($ldap, $query); + $oldserial = $entries[0][dnsserial][0]; + } + return ($newserial>$oldserial) ? $newserial : $oldserial+1; +} + +function add_rrset($zonedn) +{ + global $ldap, $binddn, $HTTP_POST_VARS, $DEFAULT_TTL, $DEFAULT_PREFERENCE; + if (!isset($HTTP_POST_VARS[dnsdomainname])) die("No domainname specified"); + if (strlen($HTTP_POST_VARS[dnsdomainname])>0) + $entry[dnsdomainname] = $HTTP_POST_VARS[dnsdomainname]; + if (!isset($HTTP_POST_VARS[dnstype])) die("No type specified"); + $entry[dnstype] = $HTTP_POST_VARS[dnstype]; + $entry[dnsclass] = "IN"; // INternet is hardcoded + $entry[dnsttl] = $DEFAULT_TTL; + // $entry[owner] = $binddn; + if ($entry[dnstype]=="MX" || $entry[dnstype]=="NS") { + for ($i = 1;; $i++) { + $setcn = "$entry[dnstype]$i:$entry[dnsdomainname]"; + $query = ldap_list($ldap, $zonedn, "(&(objectclass=dnsrrset)(cn=$setcn))"); + $rrset = ldap_get_entries($ldap, $query); + ldap_free_result($query); + if ($rrset[count]==0) + break; + } + if ($entry[dnstype]=="MX") + $entry[dnspreference] = $DEFAULT_PREFERENCE; + } else { + $setcn = "$entry[dnstype]:$entry[dnsdomainname]"; + $query = ldap_list($ldap, $zonedn, "(&(objectclass=dnsrrset)(cn=$setcn))"); + $rrset = ldap_get_entries($ldap, $query); + ldap_free_result($query); + if ($rrset[count]>0) { + error_confirm("$entry[dnsdomainname] has already been added to this zone"); + return; + } + } + $entry[objectclass] = "dnsrrset"; + $entry[cn] = $setcn; + $setdn = "cn=$setcn,$zonedn"; + ldap_add($ldap, $setdn, $entry) or die("Faild to add DNSrrset $setdn to DNSzone $zonedn"); +} + +function modify_rrset($zonedn, $setdn) +{ + global $ldap, $HTTP_POST_VARS; + $zonename = get_zone_name($zonedn); + $entry = array(); + if (isset($HTTP_POST_VARS[dnscname])) { + if ($HTTP_POST_VARS[dnscname]=="") { + $entry[dnscname] = array(); + } elseif (ereg("\.$", $HTTP_POST_VARS[dnscname])) { + if (checkdnsrr($HTTP_POST_VARS[dnscname], "A")) { + $entry[dnscname] = $HTTP_POST_VARS[dnscname]; + } else { + error_confirm("Error: $HTTP_POST_VARS[dnscname] does not resolve to a valid IP-address"); + return; + } + } elseif (isset($HTTP_POST_VARS[dnsipaddr0]) || isset($HTTP_POST_VARS[dnscipaddr])) { + // records with their own address settings are not checked against DNS + $entry[dnscname] = $HTTP_POST_VARS[dnscname]; + } else { + if (!checkdnsrr("$HTTP_POST_VARS[dnscname].$zonename", "A")) { + print "

Warning: $HTTP_POST_VARS[dnscname].$zonename". + " does not resolve to a valid IP-address

\n"; + } + $entry[dnscname] = $HTTP_POST_VARS[dnscname]; + } + } + if (isset($HTTP_POST_VARS[dnscipaddr])) { + if (ereg("^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$", $HTTP_POST_VARS[dnscipaddr], $reg)) { + $regip = "$reg[1].$reg[2].$reg[3].$reg[4]"; + if (check_unique_cipaddr($setdn, $regip)) + $entry[dnscipaddr] = $regip; + else + return; + } elseif ($HTTP_POST_VARS[dnscipaddr]=="") { + $entry[dnscipaddr] = array(); + } else { + error_confirm("$HTTP_POST_VARS[dnscipaddr] is not a valid IP-address"); + return; + } + } + if (isset($HTTP_POST_VARS[dnsttl])) { + if (ereg("([0-9]+)", $HTTP_POST_VARS[dnsttl], $reg)) { + $entry[dnsttl] = $reg[1]; + } else { + error_confirm("$HTTP_POST_VARS[dnsttl] is not a valid Time To Live"); + return; + } + } + if (isset($HTTP_POST_VARS[dnspreference])) { + if (ereg("([0-9]+)", $HTTP_POST_VARS[dnspreference], $reg)) { + $entry[dnspreference] = $reg[1]; + } else { + error_confirm("$HTTP_POST_VARS[dnspreference] is not a valid MX-prefrence"); + return; + } + } + $entry[dnsipaddr] = array(); + for ($i = 0; isset($HTTP_POST_VARS["dnsipaddr$i"]); $i++) { + $ipaddr = $HTTP_POST_VARS["dnsipaddr$i"]; + if (ereg("^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$", $ipaddr, $reg)) { + array_push($entry[dnsipaddr], "$reg[1].$reg[2].$reg[3].$reg[4]"); + } elseif ($ipaddr!="") { + error_confirm("$ipaddr is not a valid IP-address"); + return; + } + } + ldap_modify($ldap, $setdn, $entry) or die("Faild to modify DNSrrest $setdn in DNSzone $zonedn"); + ldap_mod_replace($ldap, $zonedn, array("dnsserial"=>new_serial($zonedn))); +} + +function delete_rrset($zonedn, $setdn) +{ + global $ldap; + ldap_delete($ldap, $setdn) or die("Failed to delete $setdn from LDAP");; + ldap_mod_replace($ldap, $zonedn, array("dnsserial"=>new_serial($zonedn))); +} + +function check_unique_cipaddr($setdn, $cipaddr) +{ + global $ldap, $BASEDN; + $query = ldap_search($ldap, $BASEDN, "(&(objectclass=dnsrrset)(dnscipaddr=$cipaddr))"); + $entries = ldap_get_entries($ldap, $query); + ldap_free_result($query); + for ($i = 0; $i<$entries[count]; $i++) { + $dn = $entries[$i][dn]; + if ($dn!=$setdn) { + error_confirm("Canonical IP-address $cipaddr is already used by $dn"); + return 0; + } + } + return 1; +} + +function print_whois($zonename) +{ + global $WHOISSERVERS; + return; // weil unser FW-Gschaftler den Port 43 von innen nach aussen zugedreht hat + + if (ereg("\.([a-zA-Z]+)$", $zonename, $regex)) { + $whoissrv = $WHOISSERVERS["$regex[1]"]; + if (isset($whoissrv)) { + $whoisrecord = system("whois -h $whoissrv $zonename"); + print "

Whois-record for zone $zonename

\n". + "as serverd by $whoissrv
\n". + "". + "
$whoisrecord
\n"; + } else { + print "

No WHOIS-Server found for \"$regex[1]\"

\n"; + } + } +} + +?> diff --git a/webadmin/main.css b/webadmin/main.css new file mode 100644 index 0000000..a78a6d6 --- /dev/null +++ b/webadmin/main.css @@ -0,0 +1,17 @@ +BODY, TD { + font-family: Verdana,Arial,Helvetica; + font-size: 11pt; + background-color: white; + color: black; +} + +SMALL { + font-family: Verdana,Arial,Helvetica; + font-size: 8pt; +} + +BIG { + font-family: Verdana,Arial,Helvetica; + font-size: 14pt; +} + diff --git a/webadmin/mainheader.inc b/webadmin/mainheader.inc new file mode 100644 index 0000000..a29cca2 --- /dev/null +++ b/webadmin/mainheader.inc @@ -0,0 +1,8 @@ + + + Zone-Editor + + + + + diff --git a/webadmin/menu.css b/webadmin/menu.css new file mode 100644 index 0000000..5f17597 --- /dev/null +++ b/webadmin/menu.css @@ -0,0 +1,37 @@ +A { + text-decoration: none; +} + +A:link { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 10px; + color: black; +} + +A:visited { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 10px; + color: #222222; +} + +A:hover { + text-decoration: underline; +} + +BODY, TD { + font-family: Verdana,Arial,Helvetica; + font-size: 10pt; + background-color: lightgrey; + color: black; +} + +SMALL { + font-family: Verdana,Arial,Helvetica; + font-size: 8pt; +} + +BIG { + font-family: Verdana,Arial,Helvetica; + font-size: 14pt; +} + diff --git a/webadmin/menuheader.inc b/webadmin/menuheader.inc new file mode 100644 index 0000000..2ae4a1b --- /dev/null +++ b/webadmin/menuheader.inc @@ -0,0 +1,8 @@ + + + + Zone-Selector + + + +
diff --git a/webadmin/xearth.css b/webadmin/xearth.css new file mode 100644 index 0000000..cc181e3 --- /dev/null +++ b/webadmin/xearth.css @@ -0,0 +1,21 @@ +A { + text-decoration: none; +} + +BODY, TD { + font-family: Verdana,Arial,Helvetica; + font-size: 10pt; + background-color: black; + color: white; +} + +SMALL { + font-family: Verdana,Arial,Helvetica; + font-size: 8pt; +} + +BIG { + font-family: Verdana,Arial,Helvetica; + font-size: 12pt; +} + diff --git a/webadmin/xearth.php b/webadmin/xearth.php new file mode 100644 index 0000000..8c9b9cb --- /dev/null +++ b/webadmin/xearth.php @@ -0,0 +1,16 @@ + + + + XEarth + + + +



+ + + +
+
+ + + diff --git a/webadmin/xearthimage.php b/webadmin/xearthimage.php new file mode 100644 index 0000000..2f07167 --- /dev/null +++ b/webadmin/xearthimage.php @@ -0,0 +1,4 @@ +