Active Directory mit DNS und DHCP Failover auf Debian

Vorbereitungen

Ich betreibe zu Hause ein reines IPv4 Netzwerk, weshalb ich im ersten Schritt IPv6 deaktiviere, in dem ich in der Datei…

nano /etc/sysctl.conf

…am Ende folgende Zeile hinzufüge:

net.ipv6.conf.all.disable_ipv6 = 1

Bevor es an die Einrichtung geht, kommt das obligatorische Aktualisieren des Systems, was ich eigentlich immer mit diesem Befehl ausführe:

apt update -y && apt upgrade -y && apt clean -y && apt autoremove -y && reboot

Bevor es gleich an das eigentlich Installieren geht, prüfe ich vorab, ob der Server seinen Namen und seine IP Adresse richtig kennt.

nano /etc/hosts

Das sollte jetzt so aussehen.

127.0.0.1 localhost 192.168.178.11 dc1.intern.domain.tld dc1
Code-Sprache: CSS (css)

Samba installieren

apt-get install acl attr samba samba-dsdb-modules samba-vfs-modules smbclient winbind libpam-winbind libnss-winbind libpam-krb5 krb5-config krb5-user dnsutils
Code-Sprache: JavaScript (javascript)

Möglicherweise wird bei der Installation folgendes abgefragt:

  • WINS Server: nein
  • Default Kerberos Realm: INTERN.DOMAIN.TLD
  • Kerberos Server: dc1.intern.domain.tld
  • Admin Server: dc1.intern.domain.tld

Bind (DNS) installieren

apt install bind9

Samba für Erstellung der Domäne vorbereiten

Zu aller erst sicherstellen, dass keine Samba oder DNS Dienste laufen.

ps ax | egrep "samba|smbd|nmbd|winbindd"
Code-Sprache: JavaScript (javascript)

Die Ausgabe könnte wie folgt aussehen…

root@dc1:~# ps ax | egrep "samba|smbd|nmbd|winbindd" 158 ? Ss 0:00 /usr/sbin/smbd -D --option=server role check:inhibit=yes --foreground 162 ? Ss 0:03 /usr/sbin/winbindd -D --option=server role check:inhibit=yes --foreground 219 ? S 0:00 /usr/sbin/smbd -D --option=server role check:inhibit=yes --foreground 220 ? S 0:00 /usr/sbin/smbd -D --option=server role check:inhibit=yes --foreground 232 ? S 0:00 /usr/sbin/smbd -D --option=server role check:inhibit=yes --foreground 30976 pts/2 S+ 0:00 grep -E samba|smbd|nmbd|winbindd
Code-Sprache: PHP (php)

Die letzte Zeile zeigt unseren soeben gestarteten Suchprozess und alle anderen gehören zu Samba und DNS. Die Nummern der ersten Spalte sind die Prozess IDs (kurz PID), welche allesamt beendet werden müssen (PID durch die jeweilige Nummer ersetzen). Bei o.g. Beispiel:

kill -9 158 162 219 220 232

Desweiteren muss die vorhandene Konfigurationsdatei von Samba entfernt werden. Mit smbd -b | grep "CONFIGFILE" zeigt das System an, wo sich diese befindet.

rm /etc/samba/smb.conf

Auch müssen eventuell bereits bestehende Datenbanken von Samba entfernt werden. Mit smbd -b | egrep "LOCKDIR|STATEDIR|CACHEDIR|PRIVATE_DIR" werden die entsprechenden Pfade angezeigt.

root@dc1:~# smbd -b | egrep "LOCKDIR|STATEDIR|CACHEDIR|PRIVATE_DIR" LOCKDIR: /var/run/samba STATEDIR: /var/lib/samba CACHEDIR: /var/cache/samba PRIVATE_DIR: /var/lib/samba/private
Code-Sprache: PHP (php)

Mit diesen Befehlen habe ich alle Datenbanken bei mir entfernt:

rm /var/run/samba/*.tdb rm /var/run/samba/*.ldb rm /var/lib/samba/*.tdb rm /var/lib/samba/*.ldb rm /var/cache/samba/*.tdb rm /var/cache/samba/*.ldb rm /var/lib/samba/private/*.tdb rm /var/lib/samba/private/*.ldb
Code-Sprache: JavaScript (javascript)

Und da wir gerade so schön mit Löschen beschäftigt sind, entfernen wir auch die Konfiguration von Kerberos.

rm /etc/krb5.conf

Domäne erstellen

Um den Server zum Domaincontroller zu provisionieren, gibt es bei Samba den Befehl samba-tool domain provision, welcher während der Ausführung einige Parameter abfragt, aber nicht alle, um eine Windows taugliche Active Directory Domäne erstellen zu können.

samba-tool domain provision --use-rfc2307 --interactive --option="interfaces=lo eth0" --option="bind interfaces only=yes"
Code-Sprache: JavaScript (javascript)

Bei den Abfragen müssen die ersten beiden Angaben in Großbuchstaben erfolgen. Die Abfrage „Domain“ entspricht dem NetBIOS Domänennamen. Bei einer Benutzeranmeldung kommt dieser Name vor den User (DOMAIN\user) und kann beliebig benannt werden (max. 15 Zeichen). Realm entspricht übrigens in diesem Beispiel „user@intern.domain.tld“.

Wichtig ist die Eingabe „BIND9_DLZ“ anstelle dem vorausgewählten „SAMBA INTERNAL“.
Das Administrator Kennwort entspricht dem späteren gleichnamigen Domänen-Admin.

Abfrage Realm: INTERN.DOMAIN.TLD
Abfrage Domain: DOMAIN
Abfrage Rolle: dc
Abfrage DNS Backend: BIND9_DLZ
Abfrage Admin Kennwort: *******

Samba hat bei der Erstellung der Domäne eine Konfigurationsdatei erstellt, welche wir noch an die richtige Stelle kopieren müssen.

cp /var/lib/samba/private/krb5.conf /etc/krb5.conf
Code-Sprache: PHP (php)

BIND9_DLZ aktivieren und anpassen

In der Regel sollte der folgende Schritt bei einer Neuinstallation überflüssig sein, wird jedoch in vielen anderen Beiträgen im Internet immer wieder erwähnt. Hier wird festgelegt, welches Shared Object für Bind verwendet werden soll.
Wir müssen hierfür die Version von Bind ermitteln…

named -v

Die Ausgabe beinhaltet hinter dem Wort BIND die Versionsnummer. In der Datei…

nano /var/lib/samba/bind-dns/named.conf
Code-Sprache: JavaScript (javascript)

…muss nun entsprechend der Pfad unkommentiert sein, welcher der BIND Version entspricht.

Beispiel:

# For BIND 9.11.x database "dlopen /usr/lib/x86_64-linux-gnu/samba/bind9/dlz_bind9_11.so";
Code-Sprache: PHP (php)

Wir sagen BIND, dass es nur auf IPv4 hören darf…

nano /etc/default/bind9
Code-Sprache: JavaScript (javascript)

…und ändern die Zeile OPTIONS= wie folgt:

OPTIONS="-u bind"
Code-Sprache: JavaScript (javascript)

…ändern in…

OPTIONS="-4 -u bind"
Code-Sprache: JavaScript (javascript)

In der eigentlichen Konfigurationsdatei legen wir fest, aus welchen Netzen DNS Abfragen erfolgen dürfen und wohin unbekannte Anfragen weitergeleitet werden sollen. Entweder die bestehende Datei abändern oder zuvor mit rm /etc/bind/named.conf.options löschen oder mit mv /etc/bind/named.conf.options /etc/bind/named.conf.options.org umbenennen.

nano /etc/bind/named.conf.options
// Netze, aus denen zugegriffen werden darf - die erste ist der Server selbst acl internals { 127.0.0.0/8; 192.168.178.0/24; }; options { directory "/var/cache/bind"; version "Go Away 0.0.7"; notify no; empty-zones-enable no; auth-nxdomain yes; // Weiterleitungen (hier Router und die bekannten DNS Server) forwarders { 192.168.178.1; 1.1.1.1; 8.8.8.8; }; // Hier kommt die IP des 2. Domaincontrollers rein allow-transfer { 192.168.178.12; }; dnssec-validation no; dnssec-enable no; dnssec-lookaside no; // Nur IPv4 listen-on-v6 { none; }; // Adressen, auf denen der DNS hört und arbeitet. listen-on port 53 { 192.168.178.11; 127.0.0.1; ::1; }; minimal-responses yes; // Hier wird auf die o.g. Netze verwiesen allow-query { "internals"; }; allow-query-cache { "internals"; }; recursion yes; allow-recursion { "internals"; }; tkey-gssapi-keytab "/var/lib/samba/bind-dns/dns.keytab"; };
Code-Sprache: PHP (php)

In die Datei…

nano /etc/bind/named.conf.local

…muss jetzt noch auf die Samba BIND Konfiguration verwiesen werden, in dem folgende Zeile am Ende eingefügt wird:

include "/var/lib/samba/bind-dns/named.conf";
Code-Sprache: PHP (php)

Jetzt starten wir den DNS bzw. BIND Dienst mit…

systemctl start bind9

…und testen seine Funktion mit den Zeilen:

host -t A localhost 127.0.0.1 host -t PTR 127.0.0.1 127.0.0.1
Code-Sprache: CSS (css)

Die Ausgabe sollte wie folgt aussehen:

root@dc1:~# host -t A localhost 127.0.0.1 Using domain server: Name: 127.0.0.1 Address: 127.0.0.1#53 Aliases: localhost has address 127.0.0.1 root@dc1:~# host -t PTR 127.0.0.1 127.0.0.1 Using domain server: Name: 127.0.0.1 Address: 127.0.0.1#53 Aliases: 1.0.0.127.in-addr.arpa domain name pointer localhost.
Code-Sprache: PHP (php)

Sollte das nicht der Fall sein, es gegebenenfalls nach einem Neustart (reboot) noch einmal versuchen.

Nun die Namensauflösung des Server so ändern, dass er sich zuerst selbst fragt und nicht den Router. Bei einem PVE Container geht das über die PVE GUI unter dem Menüpunkt „DNS“ und einem nachfolgenden Neustart.

nano /etc/resolv.conf

So sieht das bei PVE aus…

# --- BEGIN PVE --- search intern.domain.tld nameserver 192.168.178.11 # --- END PVE ---
Code-Sprache: CSS (css)

Neustarten (reboot) und mit nslookup beoceka.de prüfen, ob der lokale Server ordnungsgemäß über die oben eingegebenen Forwarder den Namen auflösen kann. Das sollte jetzt so aussehen:

root@dc1:~# nslookup beoceka.de Server: 192.168.178.11 Address: 192.168.178.11#53 Non-authoritative answer: Name: beoceka.de Address: 85.13.151.105
Code-Sprache: PHP (php)

Sollte ein connection timed out kommen, mit service bind9 status den Status prüfen und korrigieren.
In der Regel sollte es ein Fehler in der /etc/bind/named.conf.options sein.

Jetzt müssen wir Samba starten – ja, Samba startet im Domänen Modus nicht automatisch. Befehle wie systemctl start smbd.service oder samba-ad-dc funktionierten bei keinem meiner Tests. Zum automatischen Starten kommen wir gegen Ende des Artikels.

samba

Mit Samba können wir jetzt eine Reverse Lookup Zone erstellen.

samba-tool dns zonecreate -U Administrator dc1.intern.domain.tld 178.168.192.in-addr.arpa
Code-Sprache: CSS (css)

Freigaben und DNS testen

Jetzt können wir die Freigaben testen, die zur Nutzung des Domänencontrollers notwendig sind.

Einmal anonym mit smbclient -L localhost -N sollte es so aussehen:

Anonymous login successful Sharename Type Comment --------- ---- ------- netlogon Disk sysvol Disk IPC$ IPC IPC Service (Samba 4.9.5-Debian) Reconnecting with SMB1 for workgroup listing. Anonymous login successful Server Comment --------- ------- Workgroup Master --------- ------- WORKGROUP DC1
Code-Sprache: JavaScript (javascript)

…und als Domänen-Admin sollte der Netlogon-Ordner mit smbclient //localhost/netlogon -UAdministrator -c 'ls' sollte es so aussehen:

Enter INTERN\Administrator's password: . D 0 Tue May 4 10:45:52 2021 .. D 0 Tue May 4 10:45:54 2021

Die DNS Einträge für Active Directory testen wir mit folgenden Befehlen:

host -t SRV _ldap._tcp.intern.domain.tld.
Code-Sprache: CSS (css)
host -t SRV _kerberos._udp.intern.domain.tld.
Code-Sprache: CSS (css)
host -t A dc1.intern.domain.tld.
Code-Sprache: CSS (css)

Die Ausgaben sollten wie folgt aussehen:

_ldap._tcp.intern.domain.tld has SRV record 0 100 389 dc1.intern.domain.tld. _kerberos._udp.intern.domain.tld has SRV record 0 100 88 dc1.intern.domain.tld. root@dc1:~# host -t A dc1.intern.domain.tld. dc1.intern.domain.tld has address 192.168.178.11
Code-Sprache: PHP (php)

Nun testen wir Kerberos mit kinit Administrator. Hierbei sollte keine Fehlermeldung erscheinen, außer der Hinweis, dass das Kennwort in einigen Tagen ablaufen wird.
Mit klist wird das Ticket angezeit:

Ticket cache: FILE:/tmp/krb5cc_0 Default principal: Administrator@INTERN.DOMAIN.TLD Valid starting Expires Service principal 05/04/21 12:37:38 05/04/21 22:37:38 krbtgt/INTERN.DOMAIN.TLD@INTERN.DOMAIN.TLD renew until 05/05/21 12:37:35
Code-Sprache: JavaScript (javascript)

Damit das Kennwort vom Administrator nicht mehr ablaufen kann, setzen wir einen entsprechenden Wert mit samba-tool user setexpiry Administrator --noexpiry.

Samba automatisch bei Reboot starten

Sobald Samba als Domaincontroller arbeitet, heißen die Dienste anders. Mit folgenden Zeilen wird das System dafür vorbereitet:

systemctl stop smbd nmbd winbind systemctl disable smbd nmbd winbind systemctl unmask samba-ad-dc systemctl start samba-ad-dc systemctl status samba-ad-dc

Um sicher zu gehen, dass bisher alles richtig funktioniert, einfach neustarten und die Tests von oben noch einmal durchführen.

DHCP installieren

apt install isc-dhcp-server

Damit der DHCP Server dem DNS Server neu vergebene IP Adressen mit Client Name und Client MAC Adresse mitteilen darf, benötigt dieser entsprechende Rechte. Da es sich bei diesem DNS um einen Active Directory Dienst handelt, brauchen wir einen AD-User mit entsprechenden Rechten.

samba-tool user create dhcpduser --description="Benutzer für TSIG-GSSAPI DNS Updates via ISC DHCP Server" --random-password samba-tool user setexpiry dhcpduser --noexpiry samba-tool group addmembers DnsAdmins dhcpduser
Code-Sprache: JavaScript (javascript)

Wir exportieren den Benutzerschlüssel für die spätere Verwendung.

samba-tool domain exportkeytab --principal=dhcpduser@INTERN.DOMAIN.TLD /etc/dhcpduser.keytab chown root:root /etc/dhcpduser.keytab chmod 400 /etc/dhcpduser.keytab

Für die Aktualisierung der DNS Einträge brauchen wir ein Skript, welches bei neuen DHCP Einträgen automatisch ausgeführt wird:

nano /usr/local/bin/dhcp-dyndns.sh
#!/bin/bash # On FreeBSD change the above line to #!/usr/local/bin/bash # # /usr/local/bin/dhcp-dyndns.sh # # This script is for secure DDNS updates on Samba, # it can also add the 'macAddress' to the Computers object. # # Version: 0.9.3 # # Copyright (C) Rowland Penny 2020-2021 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # Make sure we have a useful path export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin ########################################################################## # # # You can optionally add the 'macAddress' to the Computers object. # # Add 'dhcpduser' to the 'Domain Admins' group if used # # Change the next line to 'yes' to make this happen # Add_macAddress='yes' # # ########################################################################## # On FreeBSD change this to /usr/local/etc/dhcpduser.keytab keytab=/etc/dhcpduser.keytab usage() { echo "USAGE:" echo " $(basename $0) add ip-address dhcid|mac-address hostname" echo " $(basename $0) delete ip-address dhcid|mac-address" } _KERBEROS () { # get current time as a number test=$(date +%d'-'%m'-'%y' '%H':'%M':'%S) # Note: there have been problems with this # check that 'date' returns something like # Check for valid kerberos ticket #logger "${test} [dyndns] : Running check for valid kerberos ticket" klist -c "${KRB5CCNAME}" -s if [ "$?" != "0" ]; then logger "${test} [dyndns] : Getting new ticket, old one has expired" kinit -F -k -t $keytab "${SETPRINCIPAL}" # On FreeBSD change the -F to --no-forwardable if [ "$?" != "0" ]; then logger "${test} [dyndns] : dhcpd kinit for dynamic DNS failed" exit 1 fi fi } rev_zone_info () { local RevZone="$1" local IP="$2" local rzoneip rzoneip=$(echo "$RevZone" | sed 's/\.in-addr.arpa//') local rzonenum rzonenum=$(echo "$rzoneip" | tr '.' '\n') declare -a words for n in $rzonenum do words+=("$n") done local numwords="${#words[@]}" unset ZoneIP unset RZIP unset IP2add case "$numwords" in 1) # single ip rev zone '192' ZoneIP=$(echo "${IP}" | awk -F '.' '{print $1}') RZIP="${rzoneip}" IP2add=$(echo "${IP}" | awk -F '.' '{print $4"."$3"."$2}') ;; 2) # double ip rev zone '168.192' ZoneIP=$(echo "${IP}" | awk -F '.' '{print $1"."$2}') RZIP=$(echo "${rzoneip}" | awk -F '.' '{print $2"."$1}') IP2add=$(echo "${IP}" | awk -F '.' '{print $4"."$3}') ;; 3) # triple ip rev zone '0.168.192' ZoneIP=$(echo "${IP}" | awk -F '.' '{print $1"."$2"."$3}') RZIP=$(echo "${rzoneip}" | awk -F '.' '{print $3"."$2"."$1}') IP2add=$(echo "${IP}" | awk -F '.' '{print $4}') ;; *) # should never happen exit 1 ;; esac } BINDIR=$(samba -b | grep 'BINDIR' | grep -v 'SBINDIR' | awk '{print $NF}') WBINFO="$BINDIR/wbinfo" # DHCP Server hostname Server=$(hostname -s) # DNS domain domain=$(hostname -d) if [ -z ${domain} ]; then logger "Cannot obtain domain name, is DNS set up correctly?" logger "Cannot continue... Exiting." exit 1 fi # Samba realm REALM=$(echo ${domain^^}) # krbcc ticket cache export KRB5CCNAME="/tmp/dhcp-dyndns.cc" # Kerberos principal SETPRINCIPAL="dhcpduser@${REALM}" # Kerberos keytab as above # krbcc ticket cache : /tmp/dhcp-dyndns.cc TESTUSER="$($WBINFO -u | grep 'dhcpduser')" if [ -z "${TESTUSER}" ]; then logger "No AD dhcp user exists, need to create it first.. exiting." logger "you can do this by typing the following commands" logger "kinit Administrator@${REALM}" logger "samba-tool user create dhcpduser --random-password --description='Unprivileged user for DNS updates via ISC DHCP server'" logger "samba-tool user setexpiry dhcpduser --noexpiry" logger "samba-tool group addmembers DnsAdmins dhcpduser" exit 1 fi # Check for Kerberos keytab if [ ! -f /etc/dhcpduser.keytab ]; then logger "Required keytab $keytab not found, it needs to be created." logger "Use the following commands as root" logger "samba-tool domain exportkeytab --principal=${SETPRINCIPAL} $keytab" logger "chown XXXX:XXXX $keytab" logger "Replace 'XXXX:XXXX' with the user & group that dhcpd runs as on your distro" logger "chmod 400 $keytab" exit 1 fi # Variables supplied by dhcpd.conf action="$1" ip="$2" DHCID="$3" name="${4%%.*}" # Exit if no ip address or mac-address if [ -z "${ip}" ]; then usage exit 1 fi # Exit if no computer name supplied, unless the action is 'delete' if [ -z "${name}" ]; then if [ "${action}" = "delete" ]; then name=$(host -t PTR "${ip}" | awk '{print $NF}' | awk -F '.' '{print $1}') else usage exit 1 fi fi # exit if name contains a space case ${name} in *\ * ) logger "Invalid hostname '${name}' ...Exiting" exit ;; esac # exit if $name starts with 'dhcp' # if you do not want computers without a hostname in AD # uncomment the following block of code. #if [[ $name == dhcp* ]]; then # logger "not updating DNS record in AD, invalid name" # exit 0 #fi ## update ## case "${action}" in add) _KERBEROS count=0 # does host have an existing 'A' record ? A_REC=$(samba-tool dns query ${Server} ${domain} ${name} A -k yes 2>/dev/null | grep 'A:' | awk '{print $2}') if [[ -z $A_REC ]]; then # no A record to delete result1=0 samba-tool dns add ${Server} ${domain} "${name}" A ${ip} -k yes result2="$?" elif [ "$A_REC" = "${ip}" ]; then # Correct A record exists, do nothing logger "Correct 'A' record exists, not updating." result1=0 result2=0 count=$((count+1)) elif [ "$A_REC" != "${ip}" ]; then # Wrong A record exists logger "'A' record changed, updating record." samba-tool dns delete ${Server} ${domain} "${name}" A ${A_REC} -k yes result1="$?" samba-tool dns add ${Server} ${domain} "${name}" A ${ip} -k yes result2="$?" fi # get existing reverse zones (if any) ReverseZones=$(samba-tool dns zonelist ${Server} -k yes --reverse | grep 'pszZoneName' | awk '{print $NF}') if [ -z "$ReverseZones" ]; then logger "No reverse zone found, not updating" result3='0' result4='0' count=$((count+1)) else for revzone in $ReverseZones do rev_zone_info "$revzone" "${ip}" if [[ ${ip} = $ZoneIP* ]] && [ "$ZoneIP" = "$RZIP" ]; then # does host have an existing 'PTR' record ? PTR_REC=$(samba-tool dns query ${Server} ${revzone} ${IP2add} PTR -k yes 2>/dev/null | grep 'PTR:' | awk '{print $2}' | awk -F '.' '{print $1}') if [[ -z $PTR_REC ]]; then # no PTR record to delete result3=0 samba-tool dns add ${Server} ${revzone} ${IP2add} PTR "${name}".${domain} -k yes result4="$?" break elif [ "$PTR_REC" = "${name}" ]; then # Correct PTR record exists, do nothing logger "Correct 'PTR' record exists, not updating." result3=0 result4=0 count=$((count+1)) break elif [ "$PTR_REC" != "${name}" ]; then # Wrong PTR record exists # points to wrong host logger "'PTR' record changed, updating record." samba-tool dns delete ${Server} ${revzone} ${IP2add} PTR "${PTR_REC}".${domain} -k yes result3="$?" samba-tool dns add ${Server} ${revzone} ${IP2add} PTR "${name}".${domain} -k yes result4="$?" break fi else continue fi done fi ;; delete) _KERBEROS count=0 samba-tool dns delete ${Server} ${domain} "${name}" A ${ip} -k yes result1="$?" # get existing reverse zones (if any) ReverseZones=$(samba-tool dns zonelist ${Server} --reverse -k yes | grep 'pszZoneName' | awk '{print $NF}') if [ -z "$ReverseZones" ]; then logger "No reverse zone found, not updating" result2='0' count=$((count+1)) else for revzone in $ReverseZones do rev_zone_info "$revzone" "${ip}" if [[ ${ip} = $ZoneIP* ]] && [ "$ZoneIP" = "$RZIP" ]; then host -t PTR ${ip} > /dev/null 2>&1 if [ "$?" -eq 0 ]; then samba-tool dns delete ${Server} ${revzone} ${IP2add} PTR "${name}".${domain} -k yes result2="$?" else result2='0' count=$((count+1)) fi break else continue fi done fi result3='0' result4='0' ;; *) logger "Invalid action specified" exit 103 ;; esac result="${result1}:${result2}:${result3}:${result4}" if [ "$count" -eq 0 ]; then if [ "${result}" != "0:0:0:0" ]; then logger "DHCP-DNS $action failed: ${result}" exit 1 else logger "DHCP-DNS $action succeeded" fi fi if [ "$Add_macAddress" != 'no' ]; then if [ -n "$DHCID" ]; then Computer_Object=$(ldbsearch -k yes -H ldap://"$Server" "(&(objectclass=computer)(objectclass=ieee802Device)(cn=$name))" | grep -v '#' | grep -v 'ref:') if [ -z "$Computer_Object" ]; then # Computer object not found with the 'ieee802Device' objectclass, does the computer actually exist, it should. Computer_Object=$(ldbsearch -k yes -H ldap://"$Server" "(&(objectclass=computer)(cn=$name))" | grep -v '#' | grep -v 'ref:') if [ -z "$Computer_Object" ]; then logger "Computer '$name' not found. Exiting." exit 68 else DN=$(echo "$Computer_Object" | grep 'dn:') objldif="$DN changetype: modify add: objectclass objectclass: ieee802Device" attrldif="$DN changetype: modify add: macAddress macAddress: $DHCID" # add the ldif echo "$objldif" | ldbmodify -k yes -H ldap://"$Server" ret="$?" if [ "$ret" -ne 0 ]; then logger "Error modifying Computer objectclass $name in AD." exit "${ret}" fi sleep 2 echo "$attrldif" | ldbmodify -k yes -H ldap://"$Server" ret="$?" if [ "$ret" -ne 0 ]; then logger "Error modifying Computer attribute $name in AD." exit "${ret}" fi unset objldif unset attrldif logger "Successfully modified Computer $name in AD" fi else DN=$(echo "$Computer_Object" | grep 'dn:') attrldif="$DN changetype: modify replace: macAddress macAddress: $DHCID" echo "$attrldif" | ldbmodify -k yes -H ldap://"$Server" ret="$?" if [ "$ret" -ne 0 ]; then logger "Error modifying Computer attribute $name in AD." exit "${ret}" fi unset attrldif logger "Successfully modified Computer $name in AD" fi fi fi exit 0
Code-Sprache: PHP (php)

Mit chmod 755 /usr/local/bin/dhcp-dyndns.sh machen wir das Skript ausführbar.

Damit der DHCP Server nur auf IPv4 und nur auf dem Interface eth0 antwortet, brauchen wir mit nano /etc/default/isc-dhcp-server folgende Änderung:

INTERFACESv4="eth0" #INTERFACESv6=""
Code-Sprache: PHP (php)

Die originale Konfigurationsdatei des DHCP Servers sichern wir mit mv /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.orig weg und erstellen mit nano /etc/dhcp/dhcpd.conf eine neue mit folgendem Inhalt:

authoritative; ddns-update-style none; subnet 192.168.178.0 netmask 255.255.255.0 { option subnet-mask 255.255.255.0; option broadcast-address 192.168.178.255; option time-offset 0; option routers 192.168.178.1; option domain-name "intern.domain.tld"; option domain-search "intern.domain.tld"; option domain-name-servers 192.168.178.11, 192.168.178.12; option ntp-servers 192.168.178.11, 192.168.178.12; pool { max-lease-time 1800; # 30 minutes range 192.168.178.50 192.168.178.199; } } on commit { set noname = concat("dhcp-", binary-to-ascii(10, 8, "-", leased-address)); set ClientIP = binary-to-ascii(10, 8, ".", leased-address); set ClientDHCID = concat ( suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2) ); set ClientName = pick-first-value(option host-name, config-option-host-name, client-name, noname); log(concat("Commit: IP: ", ClientIP, " DHCID: ", ClientDHCID, " Name: ", ClientName)); execute("/usr/local/bin/dhcp-dyndns.sh", "add", ClientIP, ClientDHCID, ClientName); } on release { set ClientIP = binary-to-ascii(10, 8, ".", leased-address); set ClientDHCID = concat ( suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2) ); log(concat("Release: IP: ", ClientIP)); execute("/usr/local/bin/dhcp-dyndns.sh", "delete", ClientIP, ClientDHCID); } on expiry { set ClientIP = binary-to-ascii(10, 8, ".", leased-address); # cannot get a ClientMac here, apparently this only works when actually receiving a packet log(concat("Expired: IP: ", ClientIP)); # cannot get a ClientName here, for some reason that always fails # however the dhcp update script will obtain the short hostname. execute("/usr/local/bin/dhcp-dyndns.sh", "delete", ClientIP, "", "0"); }
Code-Sprache: PHP (php)

Jetzt starten wir den DHCP Server mit /etc/init.d/isc-dhcp-server restart und schauen, ob er startet oder Fehler auswirft. Bei meinen Tests kam es nur zu Fehlern, wenn ich ein Zeichen vergessen habe. Das wird mit journalctl -xe aber angezeigt.

Fehler wie: „May 05 10:33:05 dc1 dhcpd[3272]: execute: /usr/local/bin/dhcp-dyndns.sh exit status 17408“ bedeuten, dass sich ein Windows Client bereits selbst im DNS eingetragen hat. Dieser Fehler kann ignoriert werden.

Dienste automatisch starten

DHCP und BIND

systemctl enable bind9 systemctl enable isc-dhcp-server

Einen lauffähigen Domaincontroller mit DHCP und DNS haben wir jetzt. Zum Testen habe ich in meiner Proxmox Umgebung eine Debian- und eine Windows 10 Maschine angelegt.
Auf der nächsten Seite geht des mit dem zweiten DC weiter…

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert