jpmikkers / DHCPServer

Managed DHCP server implementation, written in C#
MIT License
66 stars 24 forks source link

Option to Update a windows DNS Server. #19

Closed ruicaramalho closed 1 year ago

ruicaramalho commented 1 year ago

How about every time the DHCP server gives a lease, also updates the DNS Server with the value?

Do you thing it can be done?

I know how to update an DNS server using WMI.

    /// <summary>
    /// DNS class for Windows DNS Server, uses WMI 
    /// </summary>
    public class DnsProvider
    {
        #region Members
        private ManagementScope Session = null;

        /// <summary>
        /// DNS Server
        /// </summary>
        public string Server
        {
            get; set;
        }

        /// <summary>
        /// User to connect to Dns Server
        /// </summary>
        public string User
        {
            get; set;
        }

        /// <summary>
        /// User Password to connect to Dns Server
        /// </summary>
        public string Password
        {
            get; set;
        }

        /// <summary>
        /// DNS Domain
        /// </summary>
        public string UserDomain
        {
            get; set;
        }

        /// <summary>
        /// Current Domain
        /// </summary>
        public string Domain
        {
            get; set;
        }
        #endregion

        /// <summary>
        /// Get values from SQL Parameter table
        /// </summary>
        private void GetValuesFromSQL()
        {
            SqlInterface sqli = new SqlInterface();

            LanUser lanUser = LanUser.Get();

            this.User = lanUser.UserName; 
            this.Password = lanUser.Password; 
            this.UserDomain = lanUser.DomainOrComputerName;

            if (string.IsNullOrEmpty(Domain))
                this.Domain = UserDomain;

            if (string.IsNullOrEmpty(Server))
                this.Server = Parameter.GetString("DNSserver", sqli, true);

            if (string.IsNullOrEmpty(User)
                || string.IsNullOrEmpty(Password)
                || string.IsNullOrEmpty(UserDomain)
                || string.IsNullOrEmpty(Server)
                )
            {
                throw new Exception("'LANUser','LANpassword','LANdomain','DNSServer' must be configured.");
            }

        }

        /// <summary>
        /// DNS class for Windows DNS Server, uses WMI. Constructor
        /// </summary>
        public DnsProvider()
        {
            this.GetValuesFromSQL();
            this.Logon();
            this.Initialize();
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="serverName"></param>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        public DnsProvider(string serverName, string userName, string password)
        {
            this.Server = serverName;
            this.User = userName;
            this.Password = password;
            this.Logon();
            this.Initialize();
        }

        // Error 800703fa Illegal operation attempted on a registry key that has been marked for deletion
        // Just restart App Pool and be sure in advanced settings that `Load User Profile` is true

        /// <summary>
        /// Logon to DNS Server
        /// </summary>
        private void Logon()
        {
            if (String.IsNullOrEmpty(this.Server))
                throw new Exception("'Server' must be configured.");

            this.NameSpace = "\\\\" + this.Server + "\\root\\microsoftdns";
            ConnectionOptions con = new ConnectionOptions();
            con.Username = this.User + "@" + this.UserDomain;
            con.Password = this.Password;
            con.Impersonation = ImpersonationLevel.Impersonate;
            this.Session = new ManagementScope(this.NameSpace);
            this.Session.Options = con;
            this.Session.Connect();
        }

        private void Initialize()
        {
        }

        #region Methods

        /// <summary>
        /// Check if A Record Exists
        /// </summary>
        /// <param name="domainName"></param>
        /// <returns></returns>
        public bool ARecordExists(string domainName = null)
        {
            if (String.IsNullOrEmpty(domainName))
            {
                domainName = this.Domain;
            }
            bool retval = false;
            string wql = "";
            wql = "SELECT *";
            wql += " FROM MicrosoftDNS_ATYPE";
            wql += " WHERE OwnerName = '" + domainName + "'";
            ObjectQuery q = new ObjectQuery(wql);
            ManagementObjectSearcher s = new ManagementObjectSearcher(this.Session, q);
            ManagementObjectCollection col = s.Get();
            int total = col.Count;
            foreach (ManagementObject o in col)
            {
                retval = true;
            }
            s.Dispose();
            return retval;
        }

        /// <summary>
        /// Get DNS Server Domains
        /// </summary>
        /// <returns></returns>
        public List<string> GetDomains()
        {

            List<string> ret = new List<string>();

            ObjectQuery q = new ObjectQuery("SELECT ContainerName from MicrosoftDNS_Zone where ForwarderTimeout=0 and ZoneType=1 and ( NOT ContainerName LIKE '%.arpa') and ContainerName<>'TrustAnchors'");
            ManagementObjectSearcher s = new ManagementObjectSearcher(this.Session, q);
            ManagementObjectCollection col = s.Get();
            foreach (ManagementObject mo in col.Cast<ManagementObject>())
            {
                ret.Add(Convert.ToString(mo["ContainerName"]));
            }
            s.Dispose();
            return ret;
        }

        /// <summary>
        /// Add Domain
        /// </summary>
        /// <param name="domainName"></param>
        /// <param name="ipDestination"></param>
        public void AddDomain(string domainName, string ipDestination)
        {

            //check if domain already exists
            if (this.ARecordExists(domainName))
            {
                throw new Exception("The domain you are trying to add already exists on this server!");
            }

            //generate zone
            using (ManagementClass man = this.Manage("MicrosoftDNS_Zone"))
            {
                //ManagementBaseObject ret = null;
                using (ManagementBaseObject obj = man.GetMethodParameters("CreateZone"))
                {
                    obj["ZoneName"] = domainName;
                    obj["ZoneType"] = 0;
                    //invoke method, dispose unneccesary vars
                    man.InvokeMethod("CreateZone", obj, null);
                    //this.Dispose(ref obj);
                    //this.Dispose(ref ret);

                    //add rr containing the ip destination
                    this.AddARecord(null, ipDestination, domainName);
                }
                //this.Dispose(ref man);
            }

        }

        /// <summary>
        /// Remove Domain
        /// </summary>
        /// <param name="domainName"></param>
        public void RemoveDomain(string domainName)
        {

            string wql = "";
            wql = "SELECT *";
            wql += " FROM MicrosoftDNS_Zone";
            wql += " WHERE Name = '" + domainName + "'";
            ObjectQuery q = new ObjectQuery(wql);
            ManagementObjectSearcher s = new ManagementObjectSearcher(this.Session, q);
            ManagementObjectCollection col = s.Get();
            int total = col.Count;
            foreach (ManagementObject o in col)
            {
                o.Delete();
            }
            s.Dispose();
        }

        /// <summary>
        /// Add an 'A' type Record
        /// </summary>
        /// <param name="aRecord"></param>
        /// <param name="ipDestination"></param>
        /// <param name="domainName"></param>
        public void AddARecord(string aRecord, string ipDestination, string domainName = null)
        {
            if (String.IsNullOrEmpty(domainName))
            {
                domainName = this.Domain;
            }
            if (this.ARecordExists(aRecord + "." + domainName))
            {
                throw new Exception("The record '" + aRecord + "." + domainName + "' already exists!");
            }

            ManagementPath manpt = new ManagementPath("MicrosoftDNS_ATYPE");
            using (ManagementClass man = new ManagementClass(this.Session, manpt, null))
            {
                using (ManagementBaseObject vars = man.GetMethodParameters("CreateInstanceFromPropertyData"))
                {
                    vars["DnsServerName"] = this.Server;
                    vars["ContainerName"] = domainName;
                    vars["TTL"] = 300;
                    if (aRecord == null)
                    {
                        vars["OwnerName"] = domainName;
                    }
                    else
                    {
                        vars["OwnerName"] = aRecord + "." + domainName;
                    }
                    vars["IPAddress"] = ipDestination;
                    man.InvokeMethod("CreateInstanceFromPropertyData", vars, null);
                }

            }
        }

        /// <summary>
        /// Remove an 'A' type Record
        /// </summary>
        /// <param name="aRecord"></param>
        /// <param name="domainName"></param>
        public void RemoveARecord(string aRecord, string domainName = null)
        {
            if (String.IsNullOrEmpty(domainName))
            {
                domainName = this.Domain;
            }
            string wql = "";
            wql = "SELECT *";
            wql += " FROM MicrosoftDNS_ATYPE";
            wql += " WHERE OwnerName = '" + aRecord + "." + domainName + "'";
            ObjectQuery q = new ObjectQuery(wql);
            ManagementObjectSearcher s = new ManagementObjectSearcher(this.Session, q);
            ManagementObjectCollection col = s.Get();
            int total = col.Count;

            foreach (ManagementObject o in col)
            {
                o.Delete();
            }
            s.Dispose();
        }
        #endregion

        #region Properties

        /// <summary>
        /// WMI Management Namespace 
        /// </summary>
        private string NameSpace { get; set; } = null;

        private ManagementClass Manage(string path)
        {
            //ManagementClass retval=new ManagementClass(path);
            ManagementClass retval = new ManagementClass(this.Session, new ManagementPath(path), null);
            return retval;
        }
        #endregion
    }

Tech URL

Thanks

jpmikkers commented 1 year ago

Hi, I looked at that link, DNS is an interesting rabbit hole! Can you describe your use-case for this a bit? I mean, if you're using a windows DNS server, wouldn't you also have that running as the DHCP server?

ruicaramalho commented 1 year ago

"if you're using a windows DNS server, wouldn't you also have that running as the DHCP server?" I have a lot of locations. One is the main location and there I have a Windows DNS Server, all the other locations use this DNS.

I could use DHCP relay, but I'm building a software to change DHCP options if the tunnel is down.

This way on the other locations can still work if:

But don't worry close this. I've already found a solution..

Thanks