/
resolver-env.go
127 lines (108 loc) Β· 3.31 KB
/
resolver-env.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package resolver
import (
"context"
"fmt"
"net"
"github.com/miekg/dns"
"github.com/safing/portbase/log"
"github.com/safing/portmaster/netenv"
"github.com/safing/portmaster/network/netutils"
)
const (
internalSpecialUseDomain = "17.home.arpa."
routerDomain = "router.local." + internalSpecialUseDomain
captivePortalDomain = "captiveportal.local." + internalSpecialUseDomain
)
var (
envResolver = &Resolver{
Server: ServerSourceEnv,
ServerType: ServerTypeEnv,
ServerIPScope: netutils.SiteLocal,
ServerInfo: "Portmaster environment",
Source: ServerSourceEnv,
Conn: &envResolverConn{},
}
envResolvers = []*Resolver{envResolver}
internalSpecialUseSOA dns.RR
internalSpecialUseComment dns.RR
)
func prepEnvResolver() (err error) {
netenv.SpecialCaptivePortalDomain = captivePortalDomain
internalSpecialUseSOA, err = dns.NewRR(fmt.Sprintf(
"%s 17 IN SOA localhost. none.localhost. 0 0 0 0 0",
internalSpecialUseDomain,
))
if err != nil {
return err
}
internalSpecialUseComment, err = dns.NewRR(fmt.Sprintf(
`%s 17 IN TXT "This is a special use TLD of the Portmaster."`,
internalSpecialUseDomain,
))
return err
}
type envResolverConn struct{}
func (er *envResolverConn) Query(ctx context.Context, q *Query) (*RRCache, error) {
switch uint16(q.QType) {
case dns.TypeA, dns.TypeAAAA: // We respond with all IPv4/6 addresses we can find.
switch q.FQDN {
case captivePortalDomain:
// Get IP address of the captive portal.
portal := netenv.GetCaptivePortal()
portalIP := portal.IP
if portalIP == nil {
portalIP = netenv.PortalTestIP
}
// Convert IP to record and respond.
records, err := netutils.IPsToRRs(q.FQDN, []net.IP{portalIP})
if err != nil {
log.Warningf("nameserver: failed to create captive portal response to %s: %s", q.FQDN, err)
return er.nxDomain(q), nil
}
return er.makeRRCache(q, records), nil
case routerDomain:
// Get gateways from netenv system.
routers := netenv.Gateways()
if len(routers) == 0 {
return er.nxDomain(q), nil
}
// Convert IP to record and respond.
records, err := netutils.IPsToRRs(q.FQDN, routers)
if err != nil {
log.Warningf("nameserver: failed to create gateway response to %s: %s", q.FQDN, err)
return er.nxDomain(q), nil
}
return er.makeRRCache(q, records), nil
}
case dns.TypeSOA:
// Direct query for the SOA record.
if q.FQDN == internalSpecialUseDomain {
return er.makeRRCache(q, []dns.RR{internalSpecialUseSOA}), nil
}
}
// No match, reply with NXDOMAIN and SOA record
reply := er.nxDomain(q)
reply.Ns = []dns.RR{internalSpecialUseSOA}
return reply, nil
}
func (er *envResolverConn) nxDomain(q *Query) *RRCache {
return er.makeRRCache(q, nil)
}
func (er *envResolverConn) makeRRCache(q *Query, answers []dns.RR) *RRCache {
// Disable caching, as the env always has the raw data available.
q.NoCaching = true
return &RRCache{
Domain: q.FQDN,
Question: q.QType,
RCode: dns.RcodeSuccess,
Answer: answers,
Extra: []dns.RR{internalSpecialUseComment}, // Always add comment about this TLD.
Server: envResolver.Server,
ServerScope: envResolver.ServerIPScope,
ServerInfo: envResolver.ServerInfo,
}
}
func (er *envResolverConn) ReportFailure() {}
func (er *envResolverConn) IsFailing() bool {
return false
}