-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
srv.go
123 lines (108 loc) · 3.37 KB
/
srv.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
package paymail
import (
"context"
"fmt"
"net"
"strings"
)
// defaultResolver will return a custom dns resolver
//
// This uses client options to set the network and port
func (c *Client) defaultResolver() net.Resolver {
return net.Resolver{
PreferGo: true,
StrictErrors: false,
Dial: func(ctx context.Context, _, _ string) (net.Conn, error) {
d := net.Dialer{
Timeout: c.options.dnsTimeout,
}
return d.DialContext(
ctx, c.options.nameServerNetwork, c.options.nameServer+":"+c.options.dnsPort,
)
},
}
}
// GetSRVRecord will get the SRV record for a given domain name
//
// Specs: http://bsvalias.org/02-01-host-discovery.html
func (c *Client) GetSRVRecord(service, protocol, domainName string) (srv *net.SRV, err error) {
// Invalid parameters?
if len(service) == 0 { // Use the default from paymail specs
service = DefaultServiceName
}
if len(protocol) == 0 { // Use the default from paymail specs
protocol = DefaultProtocol
}
if len(domainName) == 0 || len(domainName) > 255 {
err = fmt.Errorf("invalid parameter: domainName")
return
}
// Force the case
protocol = strings.TrimSpace(strings.ToLower(protocol))
// The computed cname to check against
cnameCheck := fmt.Sprintf("_%s._%s.%s.", service, protocol, domainName)
// Lookup the SRV record
var cname string
var records []*net.SRV
if cname, records, err = c.resolver.LookupSRV(
context.Background(), service, protocol, domainName,
); err != nil || len(records) == 0 {
// @rohenaz: Paymail spec says if SRV record doesn't exist, assume it is <domain>.<tld> and port of 443
err = nil // Hack
cname = cnameCheck // Hack
records = append(records, &net.SRV{
Port: DefaultPort,
Priority: DefaultPriority,
Target: domainName,
Weight: DefaultWeight,
})
}
// Basic CNAME check (sanity check!)
if cname != cnameCheck {
err = fmt.Errorf(
"srv cname was invalid or not found using: %s and expected: %s",
cnameCheck, cname,
)
return
}
// Only return the first record (in case multiple are returned)
srv = records[0]
// Remove any period on the end
srv.Target = strings.TrimSuffix(srv.Target, ".")
return
}
// ValidateSRVRecord will check for a valid SRV record for paymail following specifications
//
// Specs: http://bsvalias.org/02-01-host-discovery.html
func (c *Client) ValidateSRVRecord(ctx context.Context, srv *net.SRV, port, priority, weight uint16) error {
// Check the parameters
if srv == nil {
return fmt.Errorf("invalid parameter: srv is missing or nil")
}
if port <= 0 { // Use the default(s) from paymail specs
port = uint16(DefaultPort)
}
if priority <= 0 {
priority = uint16(DefaultPriority)
}
if weight <= 0 {
weight = uint16(DefaultWeight)
}
// Check the basics of the SRV record
if len(srv.Target) == 0 {
return fmt.Errorf("srv target is invalid or empty")
} else if srv.Port != port {
return fmt.Errorf("srv port %d does not match %d", srv.Port, port)
} else if srv.Priority != priority {
return fmt.Errorf("srv priority %d does not match %d", srv.Priority, priority)
} else if srv.Weight != weight {
return fmt.Errorf("srv weight %d does not match %d", srv.Weight, weight)
}
// Test resolving the target
if addresses, err := c.resolver.LookupHost(ctx, srv.Target); err != nil {
return err
} else if len(addresses) == 0 {
return fmt.Errorf("srv target %s could not resolve a host", srv.Target)
}
return nil
}