Dag Wieers
2007-Aug-01 14:34 UTC
[Samba] Hostname DNS update (using nsupdate-gss) to Active Directory DNS using Sites
Hi, We were unable to use nsupdate-gss to a Windows 2003 Active Directory. I modified the nsupdate-gss script to use the local Domain Controller to do the DNS update and then it works (albeit giving a TKEY integrity error). The patch attached adds a 5th argument to the command line to specify the local Domain Controller to send the DNS update to. Usage: nsupdate-gss.pl HOST DOMAIN IP TTL [NS] Here is the example output when it fails: ---- [root@rhun root]# nsupdate-gss rhun REALM.DOM 1.2.3.4 3600 Found 93 nameserver(s) Using DNS server name somedc.REALM.DOM creds acquired init done calling RR new init_sec_context step 2: Unspecified GSS failure. Minor code may provide more information Message stream modified Failed to negotiate a TKEY ---- And this is shown when it works (using the extra argument): ---- [root@rhun redhat]# nsupdate-gss rhun REALM.DOM 1.2.3.4 3600 localdc.REALM.DOM Found 1 nameserver(s) Using DNS server name localdc.REALM.DOM creds acquired init done calling RR new verifying calling sig_data Use of uninitialized value in pack at /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi/Net/DNS/RR/TKEY.pm line 104. sig_data_done Failed to verify TKEY reply: A token had an invalid Message Integrity Check (MIC) No error verifying done Negotiated TKEY 9019541380429 Update gave rcode NOERROR ---- (Beware IANAADE: I Am Not an Active Directory Expert) Apparently with Active Directory and Sites and Services enabled you can not just update using any Domain Controller but instead you need to use the local one. Apparently there is a mapping between routes and "Sites" that contain local DCs and only these allow to updates the DNS. As a result the normal nsupdate-gss fails. I've tested with Samba 3.0.25b as well and that fails too, most likely because it tries one out of the 93 Domain Controllers we have. I've tried to look into finding who my local DCs are from DNS information, but as far as I can see there is no query to link the local route with a "Site". I was wondering of someone knows exactly how this is supposed to work ? How can we register the hostname with Active Directory DNS ? And how can we make this information persistent ? (ie. if DHCP provides a new IP, update the DNS accordingly) I also fail to see how the Kerberos credentials can be persistent for this functionality to work without someone providing a user password. Even an ADS join requires a password every time again. Is there anyone with a clue ? Or is there any documentation I failed to Google for ? Thanks in advance :) -- dag wieers, dag@wieers.com, http://dag.wieers.com/ -- [Any errors in spelling, tact or fact are transmission errors] -------------- next part -------------- --- /usr/src/redhat/SOURCES/nsupdate-gss 2006-01-23 06:35:10.000000000 +0100 +++ /usr/bin/nsupdate-gss 2007-08-01 13:28:39.000000000 +0200 @@ -5,6 +5,9 @@ # jmruiz@animatika.net # updated, 2004-Enero +# dag@wieers.com +# updated, 2007-EMC + # See draft-ietf-dnsext-gss-tsig-02, RFC2845 and RFC2930 @@ -20,9 +23,9 @@ # Integrity of the arguments -if ($#ARGV != 3) { +if ($#ARGV < 3) { print " -Usage: nsupdate-gss.pl HOST DOMAIN IP TTL +Usage: nsupdate-gss.pl HOST DOMAIN IP TTL [NS] "; exit 1; } @@ -35,6 +38,7 @@ my $ip = $ARGV[2]; my $ttl = $ARGV[3]; my $alg = "gss.microsoft.com"; +my $ns = $ARGV[4] if ($#ARGV >= 4); @@ -229,7 +233,11 @@ # find the nameservers my $nameserver = find_nameservers("$domain."); -print "Found nameserver $nameserver\n"; +$nameserver->nameservers("$ns") if (defined($ns)); +#print $nameserver->print; + +#print "Found nameserver $nameserver\n"; +print "Found ".$nameserver->nameservers." nameserver(s)\n"; if (!defined($nameserver) || $nameserver->{'errorstring'} ne 'NOERROR') { print "Failed to find a nameserver for domain $domain\n"; @@ -238,6 +246,8 @@ # find the name of the DNS server my $server_name = find_server_name($domain); +$server_name = $ns if (defined($ns)); + if (!defined($server_name)) { print "Failed to find a DNS server name for $domain\n"; exit 1;