diff options
author | Mike Crute <mike@crute.us> | 2020-01-02 03:05:21 +0000 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2020-01-02 03:05:21 +0000 |
commit | 473ec1c19bb9d8cad259481f5cd2096a47dfb40f (patch) | |
tree | b319656f708795e34fdecce45cb6aed28e7b4972 /bind | |
parent | b2e062c5de3fb233d34bf0c67c7e43cfd9969706 (diff) | |
download | go_ddns_manager-473ec1c19bb9d8cad259481f5cd2096a47dfb40f.tar.bz2 go_ddns_manager-473ec1c19bb9d8cad259481f5cd2096a47dfb40f.tar.xz go_ddns_manager-473ec1c19bb9d8cad259481f5cd2096a47dfb40f.zip |
Create updated service
Diffstat (limited to 'bind')
-rw-r--r-- | bind/config.go | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/bind/config.go b/bind/config.go new file mode 100644 index 0000000..584b1ee --- /dev/null +++ b/bind/config.go | |||
@@ -0,0 +1,227 @@ | |||
1 | package bind | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "io/ioutil" | ||
6 | "strings" | ||
7 | "time" | ||
8 | |||
9 | "github.com/miekg/dns" | ||
10 | ) | ||
11 | |||
12 | type Signable interface { | ||
13 | SetTsig(string, string, uint16, int64) *dns.Msg | ||
14 | } | ||
15 | |||
16 | func NewBINDConfig() *BINDConfig { | ||
17 | return &BINDConfig{ | ||
18 | zones: map[string]map[string]*Zone{}, | ||
19 | keys: map[string]*Key{}, | ||
20 | } | ||
21 | } | ||
22 | |||
23 | type BINDConfig struct { | ||
24 | zones map[string]map[string]*Zone | ||
25 | keys map[string]*Key | ||
26 | } | ||
27 | |||
28 | func (c *BINDConfig) Views() []string { | ||
29 | v := []string{} | ||
30 | for vn, _ := range c.zones { | ||
31 | v = append(v, vn) | ||
32 | } | ||
33 | return v | ||
34 | } | ||
35 | |||
36 | func (c *BINDConfig) Zone(view, name string) *Zone { | ||
37 | if !strings.HasSuffix(name, ".") { | ||
38 | name = fmt.Sprintf("%s.", name) | ||
39 | } | ||
40 | |||
41 | if _, ok := c.zones[view]; !ok { | ||
42 | return nil | ||
43 | } | ||
44 | |||
45 | z, ok := c.zones[view][name] | ||
46 | if !ok { | ||
47 | return nil | ||
48 | } | ||
49 | |||
50 | if z.InView != "" { | ||
51 | return c.zones[z.InView][name] | ||
52 | } | ||
53 | |||
54 | return z | ||
55 | } | ||
56 | |||
57 | func (c *BINDConfig) AddKey(k *Key) { | ||
58 | c.keys[k.Name] = k | ||
59 | } | ||
60 | |||
61 | func (c *BINDConfig) AddZone(z *Zone, view string) { | ||
62 | if c.zones[view] == nil { | ||
63 | c.zones[view] = map[string]*Zone{} | ||
64 | } | ||
65 | c.zones[view][z.Name] = z | ||
66 | z.config = c | ||
67 | } | ||
68 | |||
69 | func NewZone(name string) *Zone { | ||
70 | // Canonicalize name | ||
71 | if !strings.HasSuffix(name, ".") { | ||
72 | name = fmt.Sprintf("%s.", name) | ||
73 | } | ||
74 | |||
75 | return &Zone{ | ||
76 | Name: name, | ||
77 | keys: []string{}, | ||
78 | } | ||
79 | } | ||
80 | |||
81 | type Zone struct { | ||
82 | Name string | ||
83 | Type string | ||
84 | InView string | ||
85 | keys []string | ||
86 | config *BINDConfig | ||
87 | } | ||
88 | |||
89 | func (z *Zone) AddKey(key string) { | ||
90 | z.keys = append(z.keys, key) | ||
91 | } | ||
92 | |||
93 | func (z *Zone) Keys() []*Key { | ||
94 | k := []*Key{} | ||
95 | for _, kn := range z.keys { | ||
96 | k = append(k, z.config.keys[kn]) | ||
97 | } | ||
98 | return k | ||
99 | } | ||
100 | |||
101 | type Key struct { | ||
102 | Name string | ||
103 | Algorithm string | ||
104 | Secret string | ||
105 | } | ||
106 | |||
107 | func (k *Key) CanonicalName() string { | ||
108 | if !strings.HasSuffix(k.Name, ".") { | ||
109 | return fmt.Sprintf("%s.", k.Name) | ||
110 | } | ||
111 | return k.Name | ||
112 | } | ||
113 | |||
114 | func (k *Key) CanonicalAlgorithm() string { | ||
115 | if !strings.HasSuffix(k.Algorithm, ".") { | ||
116 | return fmt.Sprintf("%s.", k.Algorithm) | ||
117 | } | ||
118 | return k.Name | ||
119 | } | ||
120 | |||
121 | func (k *Key) Sign(r Signable) { | ||
122 | r.SetTsig(k.CanonicalName(), k.CanonicalAlgorithm(), 300, time.Now().Unix()) | ||
123 | } | ||
124 | |||
125 | func (k *Key) AsMap() map[string]string { | ||
126 | return map[string]string{k.CanonicalName(): k.Secret} | ||
127 | } | ||
128 | |||
129 | func NewStringStack() *StringStack { | ||
130 | return &StringStack{[]string{}} | ||
131 | } | ||
132 | |||
133 | type StringStack struct { | ||
134 | items []string | ||
135 | } | ||
136 | |||
137 | func (s *StringStack) isEmpty() bool { | ||
138 | return len(s.items) == 0 | ||
139 | } | ||
140 | |||
141 | func (s *StringStack) Peek() string { | ||
142 | return s.items[len(s.items)-1] | ||
143 | } | ||
144 | |||
145 | func (s *StringStack) Pop() string { | ||
146 | if s.isEmpty() { | ||
147 | return "" | ||
148 | } | ||
149 | v := s.items[len(s.items)-1] | ||
150 | s.items = s.items[:len(s.items)-1] | ||
151 | return v | ||
152 | } | ||
153 | |||
154 | func (s *StringStack) Push(v string) { | ||
155 | s.items = append(s.items, v) | ||
156 | } | ||
157 | |||
158 | func cleanValue(s string) string { | ||
159 | return strings.Trim(strings.Trim(s, ";"), "\"") | ||
160 | } | ||
161 | |||
162 | func isContainerStart(line []string) bool { | ||
163 | return line[len(line)-1] == "{" | ||
164 | } | ||
165 | |||
166 | func ParseBINDConfig(filename string) (*BINDConfig, error) { | ||
167 | data, err := ioutil.ReadFile(filename) | ||
168 | if err != nil { | ||
169 | return nil, err | ||
170 | } | ||
171 | |||
172 | var view string | ||
173 | var zone *Zone | ||
174 | var key *Key | ||
175 | |||
176 | config := NewBINDConfig() | ||
177 | stack := NewStringStack() | ||
178 | |||
179 | for _, line := range strings.Split(string(data), "\n") { | ||
180 | line := strings.Split(strings.TrimSpace(line), " ") | ||
181 | |||
182 | switch line[0] { | ||
183 | case "};": | ||
184 | t := stack.Pop() | ||
185 | switch t { | ||
186 | case "view": | ||
187 | view = "" | ||
188 | case "key": | ||
189 | key = nil | ||
190 | case "zone": | ||
191 | zone = nil | ||
192 | } | ||
193 | case "view": | ||
194 | view = cleanValue(line[1]) | ||
195 | stack.Push("view") | ||
196 | case "zone": | ||
197 | zone = NewZone(cleanValue(line[1])) | ||
198 | config.AddZone(zone, view) | ||
199 | stack.Push("zone") | ||
200 | case "in-view": | ||
201 | zone.Type = "reference" | ||
202 | zone.InView = cleanValue(line[1]) | ||
203 | case "type": | ||
204 | zone.Type = cleanValue(line[1]) | ||
205 | case "grant": | ||
206 | zone.AddKey(cleanValue(line[1])) | ||
207 | case "key": | ||
208 | if !isContainerStart(line) { | ||
209 | continue | ||
210 | } | ||
211 | |||
212 | key = &Key{Name: cleanValue(line[1])} | ||
213 | config.AddKey(key) | ||
214 | stack.Push("key") | ||
215 | case "algorithm": | ||
216 | key.Algorithm = cleanValue(line[1]) | ||
217 | case "secret": | ||
218 | key.Secret = cleanValue(line[1]) | ||
219 | default: | ||
220 | if isContainerStart(line) { | ||
221 | stack.Push(line[0]) | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | |||
226 | return config, nil | ||
227 | } | ||