-
-
Notifications
You must be signed in to change notification settings - Fork 216
/
handler.go
148 lines (123 loc) · 3.94 KB
/
handler.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package handler
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/TimothyYe/godns/internal/provider"
log "github.com/sirupsen/logrus"
"github.com/TimothyYe/godns/internal/settings"
"github.com/TimothyYe/godns/internal/utils"
"github.com/TimothyYe/godns/pkg/lib"
"github.com/TimothyYe/godns/pkg/notification"
)
var (
errEmptyResult = errors.New("empty result")
errEmptyDomain = errors.New("NXDOMAIN")
)
type Handler struct {
ctx context.Context
Configuration *settings.Settings
dnsProvider provider.IDNSProvider
notificationManager notification.INotificationManager
ipManager *lib.IPHelper
cachedIP string
}
func (handler *Handler) SetContext(ctx context.Context) {
handler.ctx = ctx
}
func (handler *Handler) SetConfiguration(conf *settings.Settings) {
handler.Configuration = conf
handler.notificationManager = notification.GetNotificationManager(handler.Configuration)
handler.ipManager = lib.GetIPHelperInstance(handler.Configuration)
}
func (handler *Handler) Init() {
handler.ipManager.UpdateConfiguration(handler.Configuration)
}
func (handler *Handler) SetProvider(provider provider.IDNSProvider) {
handler.dnsProvider = provider
}
func (handler *Handler) LoopUpdateIP(ctx context.Context, domain *settings.Domain) error {
ticker := time.NewTicker(time.Second * time.Duration(handler.Configuration.Interval))
// run once at the beginning
err := handler.UpdateIP(domain)
if err != nil {
log.WithError(err).Debug("Update IP failed during the DNS Update loop")
}
log.Debugf("DNS update loop finished, will run again in %d seconds", handler.Configuration.Interval)
for {
select {
case <-ticker.C:
err := handler.UpdateIP(domain)
if err != nil {
log.WithError(err).Debug("Update IP failed during the DNS Update loop")
}
log.Debugf("DNS update loop finished, will run again in %d seconds", handler.Configuration.Interval)
case <-ctx.Done():
log.Info("DNS update loop cancelled")
ticker.Stop()
return nil
}
}
}
func (handler *Handler) UpdateIP(domain *settings.Domain) error {
ip := handler.ipManager.GetCurrentIP()
if ip == "" {
if handler.Configuration.RunOnce {
return fmt.Errorf("fail to get current IP")
}
return nil
}
if ip == handler.cachedIP {
log.Debugf("IP (%s) matches cached IP (%s), skipping", ip, handler.cachedIP)
return nil
}
err := handler.updateDNS(domain, ip)
if err != nil {
if handler.Configuration.RunOnce {
return fmt.Errorf("%v: fail to update DNS", err)
}
log.Error(err)
return nil
}
handler.cachedIP = ip
log.Debugf("Cached IP address: %s", ip)
return nil
}
func (handler *Handler) updateDNS(domain *settings.Domain, ip string) error {
var updatedDomains []string
for _, subdomainName := range domain.SubDomains {
var hostname string
if subdomainName != utils.RootDomain {
hostname = subdomainName + "." + domain.DomainName
} else {
hostname = domain.DomainName
}
lastIP, err := utils.ResolveDNS(hostname, handler.Configuration.Resolver, handler.Configuration.IPType)
if err != nil && (errors.Is(err, errEmptyResult) || errors.Is(err, errEmptyDomain)) {
log.Errorf("Failed to resolve DNS for domain: %s, error: %s", hostname, err)
continue
}
//check against the current known IP, if no change, skip update
if ip == lastIP {
log.Infof("IP is the same as cached one (%s). Skip update.", ip)
} else {
if err := handler.dnsProvider.UpdateIP(domain.DomainName, subdomainName, ip); err != nil {
return err
}
updatedDomains = append(updatedDomains, subdomainName)
// execute webhook when it is enabled
if handler.Configuration.Webhook.Enabled {
if err := lib.GetWebhook(handler.Configuration).Execute(hostname, ip); err != nil {
return err
}
}
}
}
if len(updatedDomains) > 0 {
successMessage := fmt.Sprintf("[ %s ] of %s", strings.Join(updatedDomains, ", "), domain.DomainName)
handler.notificationManager.Send(successMessage, ip)
}
return nil
}