From bbf81dd0e493a6829c7b4955f6aede6b497ff125 Mon Sep 17 00:00:00 2001
From: noreply <users.noreply@github.com>
Date: Wed, 15 Jan 2025 16:38:31 +0530
Subject: [PATCH 1/2] Added option to mention custom LDAP server IP

---
 bloodhound/__init__.py  |  7 ++++++-
 bloodhound/ad/domain.py | 22 ++++++++++++++++------
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/bloodhound/__init__.py b/bloodhound/__init__.py
index df3cb19..95c6036 100644
--- a/bloodhound/__init__.py
+++ b/bloodhound/__init__.py
@@ -228,6 +228,10 @@ def main():
                         metavar='HOST',
                         action='store',
                         help='Override which DC to query (hostname)')
+    coopts.add_argument('-dc-ip',
+                        '--domain-ip',
+                        action='store',
+                        help='Override which DC/LDAP server to query (IP)')         
     coopts.add_argument('-gc',
                         '--global-catalog',
                         metavar='HOST',
@@ -303,7 +307,7 @@ def main():
             args.auth_method = 'kerberos'
             auth = ADAuthentication(username=args.username, password=args.password, domain=args.domain, auth_method=args.auth_method, ldap_channel_binding=args.ldap_channel_binding)
 
-    ad = AD(auth=auth, domain=args.domain, nameserver=args.nameserver, dns_tcp=args.dns_tcp, dns_timeout=args.dns_timeout, use_ldaps=args.use_ldaps)
+    ad = AD(auth=auth, domain=args.domain, nameserver=args.nameserver, dns_tcp=args.dns_tcp, dns_timeout=args.dns_timeout, use_ldaps=args.use_ldaps, dc_ip=args.domain_ip)
     # Resolve collection methods
     collect = resolve_collection_methods(args.collectionmethod)
     if not collect:
@@ -311,6 +315,7 @@ def main():
     logging.debug('Resolved collection methods: %s', ', '.join(list(collect)))
 
     logging.debug('Using DNS to retrieve domain information')
+    print(args)
     ad.dns_resolve(domain=args.domain, options=args)
 
     # Override the detected DC / GC if specified
diff --git a/bloodhound/ad/domain.py b/bloodhound/ad/domain.py
index 46f76fb..562f119 100644
--- a/bloodhound/ad/domain.py
+++ b/bloodhound/ad/domain.py
@@ -61,11 +61,19 @@ def ldap_connect(self, protocol=None, resolver=False):
         logging.info('Connecting to LDAP server: %s' % self.hostname)
         logging.debug('Using protocol %s' % protocol)
 
-        # Convert the hostname to an IP, this prevents ldap3 from doing it
-        # which doesn't use our custom nameservers
-        q = self.ad.dnsresolver.query(self.hostname, tcp=self.ad.dns_tcp)
-        for r in q:
-            ip = r.address
+
+        if (self.ad.dc_ip):
+            logging.info('LDAP server IP provied')
+            logging.info('LDAP server IP: %s' % self.ad.dc_ip)
+            ip = self.ad.dc_ip
+        else:
+            # Convert the hostname to an IP, this prevents ldap3 from doing it
+            # which doesn't use our custom nameservers
+            logging.info('Resolving LDAP ip from nameserver')
+            q = self.ad.dnsresolver.query(self.hostname, tcp=self.ad.dns_tcp)
+            for r in q:
+                ip = r.address
+            logging.info('LDAP server IP: %s' % ip)
 
         ldap = self.ad.auth.getLDAPConnection(hostname=self.hostname, ip=ip,
                                               baseDN=self.ad.baseDN, protocol=protocol)
@@ -588,7 +596,7 @@ def get_root_domain(self):
 """
 class AD(object):
 
-    def __init__(self, domain=None, auth=None, nameserver=None, dns_tcp=False, dns_timeout=3.0, use_ldaps=False):
+    def __init__(self, domain=None, auth=None, nameserver=None, dns_tcp=False, dns_timeout=3.0, use_ldaps=False,dc_ip=None):
         self.domain = domain
         # Object of type ADDomain, added later
         self.domain_object = None
@@ -614,6 +622,8 @@ def __init__(self, domain=None, auth=None, nameserver=None, dns_tcp=False, dns_t
             self.dnsresolver.nameservers = [nameserver]
         # Resolve DNS over TCP?
         self.dns_tcp = dns_tcp
+        # ldap ip to query
+        self.dc_ip = dc_ip
         # Give it a cache to prevent duplicate lookups
         self.dnsresolver.cache = resolver.Cache()
         # Default timeout after 3 seconds if the DNS servers

From a20cd4cd8c131bd79b0fed72a120acc50b5d5f28 Mon Sep 17 00:00:00 2001
From: noreply <users.noreply@github.com>
Date: Wed, 15 Jan 2025 16:42:51 +0530
Subject: [PATCH 2/2] remove some debug logs

---
 bloodhound/__init__.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/bloodhound/__init__.py b/bloodhound/__init__.py
index 95c6036..298b62d 100644
--- a/bloodhound/__init__.py
+++ b/bloodhound/__init__.py
@@ -315,7 +315,6 @@ def main():
     logging.debug('Resolved collection methods: %s', ', '.join(list(collect)))
 
     logging.debug('Using DNS to retrieve domain information')
-    print(args)
     ad.dns_resolve(domain=args.domain, options=args)
 
     # Override the detected DC / GC if specified