forked from RedTeamPentesting/adauth
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresolver.go
113 lines (90 loc) · 2.95 KB
/
resolver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package adauth
import (
"context"
"fmt"
"net"
"strings"
)
type Resolver interface {
LookupAddr(ctx context.Context, addr string) ([]string, error)
LookupIP(ctx context.Context, network string, host string) ([]net.IP, error)
LookupSRV(ctx context.Context, service string, proto string, name string) (string, []*net.SRV, error)
}
var _ Resolver = net.DefaultResolver
type resolver struct {
Resolver
debugFn func(string, ...any)
}
func ensureResolver(r Resolver, debug func(string, ...any)) *resolver {
if r == nil {
return &resolver{Resolver: net.DefaultResolver, debugFn: debug}
}
return &resolver{Resolver: r, debugFn: debug}
}
func (r *resolver) debug(format string, a ...any) {
if r.debugFn == nil {
return
}
r.debugFn(format, a...)
}
func (r *resolver) LookupFirstService(ctx context.Context, protocol string, domain string) (string, int, error) {
_, addrs, err := r.Resolver.LookupSRV(ctx, protocol, "tcp", domain)
if err != nil {
if strings.EqualFold(protocol, "ldaps") {
host, _, srvLDAPErr := r.LookupFirstService(ctx, "ldap", domain)
if srvLDAPErr == nil {
return host, 636, nil
}
}
return "", 0, fmt.Errorf("lookup %q service of domain %q: %w", protocol, domain, err)
}
if len(addrs) == 0 {
return "", 0, fmt.Errorf("no %q services were discovered for domain %q", protocol, domain)
}
return strings.TrimRight(addrs[0].Target, "."), int(addrs[0].Port), nil
}
func (r *resolver) LookupDCByDomain(ctx context.Context, domain string) (string, error) {
// Unfortunately, Go does not implement SOA lookups, so we lookup the domain
// for DC IPs and reverse lookup their hostnames instead.
dcAddrs, err := r.Resolver.LookupIP(context.Background(), "ip", domain)
if err != nil {
return "", fmt.Errorf("lookup domain itself: %w", err)
}
if len(dcAddrs) == 0 {
return "", fmt.Errorf("looking up domain itself returned no results")
}
dcAddr := dcAddrs[0].String()
names, err := r.Resolver.LookupAddr(context.Background(), dcAddr)
if err == nil {
domain, names = splitResultsInDomainAndHostname(names, domain)
switch {
case len(names) > 0:
dcAddr = strings.TrimRight(names[0], ".")
case domain != "":
dcAddr = domain
r.debug("Warning: reverse lookup of DC only returned domain name, using domain name %q as DC hostname",
domain)
default:
r.debug("Warning: reverse lookup of DC did not contain a hostname")
}
} else {
r.debug("Warning: could not reverse lookup DC IP: %v", err)
}
return dcAddr, nil
}
// A reverse lookup of the DC IP returns both the DCs hostname and the name of
// the domain. This function splits the results in these categories.
func splitResultsInDomainAndHostname(
hostnames []string, domain string,
) (domainFromHostnames string, filtered []string) {
var d string
for _, hostname := range hostnames {
hostname = strings.TrimRight(hostname, ".")
if strings.EqualFold(hostname, domain) {
d = hostname
} else {
filtered = append(filtered, hostname)
}
}
return d, filtered
}