-
Notifications
You must be signed in to change notification settings - Fork 2
/
acme.go
107 lines (88 loc) · 2.66 KB
/
acme.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
package dns
import (
"errors"
"io"
"io/ioutil"
"log"
"os"
"path"
"strings"
"github.com/miekg/dns"
)
// domains for the acme challenge are like this:
// _acme-challenge.$callbackdomain.
// the first label may not be _acme-challenge though
// on disk, they are stored in $acmedir/$record/,
// which is a directory of files to return.
// example: /acme/response/_acme-challenge.hotlinecallback.net/
// this function checks if such a dir exists, and if it has files
func doesAcmeChalRespExist(domain string) bool {
// check if an acme response directory has been configured
if acmeChallengePath == "" {
// no acme response, user doens't care about SSL
// bail
return false
}
// get the path for the acme challenge response, if it exists
chalPath := getPathForAcmeChallenge(domain)
// check if the directory exists
_, err := os.Stat(chalPath)
if errors.Is(err, os.ErrNotExist) {
// dir doesn't exist, so no responses available
return false
}
// the directory exists, check if there are any TXT responses available
files, err := ioutil.ReadDir(chalPath)
if err != nil {
log.Println("error while looking for ACME chal responses")
log.Println(err)
return false
}
// if there are any files in the dir, there are responses available
return len(files) > 0
}
// this function builds the directory path for looking for ACME
// challenge response files. each file is a TXT record for the domain
func getPathForAcmeChallenge(domain string) string {
// strip off the trailing period
domainWithoutTrailingPeriod := strings.TrimSuffix(domain, ".")
// build the path
p := path.Join(acmeChallengePath, domainWithoutTrailingPeriod)
return p
}
// add the TXT record responses to the DNS message for an acme challenge
// this assumes the directory exists and has files
func setAcmeChalRRs(domain string, msg *dns.Msg) error {
chalPath := getPathForAcmeChallenge(domain)
files, err := ioutil.ReadDir(chalPath)
if err != nil {
return err
}
for _, f := range files {
fp := path.Join(chalPath, f.Name())
file, err := os.Open(fp)
if err != nil {
return err
}
defer file.Close()
responseBytes, err := io.ReadAll(file)
if err != nil {
return err
}
// set the TXT response
msg.Answer = append(msg.Answer, &dns.TXT{
Hdr: dns.RR_Header{Name: msg.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 60},
Txt: []string{string(responseBytes)},
})
}
return nil
}
func setAcmeCAAResp(domain string, msg *dns.Msg) error {
msg.Answer = append(msg.Answer, &dns.CAA{
Hdr: dns.RR_Header{Name: msg.Question[0].Name, Rrtype: dns.TypeCAA, Class: dns.ClassINET, Ttl: 60},
Flag: 0,
Tag: "issue",
Value: "letsencrypt.org",
})
return nil
}