blob: 49697711c1645610aaca86da295a84ec2323cc9b [file] [log] [blame]
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +04001package controllers
2
3import (
4 "fmt"
5 "io"
Giorgi Lekveishvili109a5672023-12-07 16:05:42 +04006 "net"
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +04007 "strings"
Giorgi Lekveishvili109a5672023-12-07 16:05:42 +04008 "sync"
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +04009 "time"
10
11 "github.com/miekg/dns"
12)
13
14type ZoneFile struct {
Giorgi Lekveishvili109a5672023-12-07 16:05:42 +040015 lock sync.Locker
16 rrs []dns.RR
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +040017}
18
19func NewZoneFile(r io.Reader) (*ZoneFile, error) {
20 rrs := make([]dns.RR, 0)
21 p := dns.NewZoneParser(r, "", "")
22 p.SetIncludeAllowed(false)
23 for {
24 if rr, ok := p.Next(); ok {
25 rrs = append(rrs, rr)
26 } else {
27 if err := p.Err(); err != nil {
28 return nil, err
29 }
30 break
31 }
32 }
Giorgi Lekveishvili109a5672023-12-07 16:05:42 +040033 return &ZoneFile{&sync.Mutex{}, rrs}, nil
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +040034}
35
36func (z *ZoneFile) DeleteTxtRecord(name, value string) {
Giorgi Lekveishvili109a5672023-12-07 16:05:42 +040037 z.lock.Lock()
38 defer z.lock.Unlock()
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +040039 for i, rr := range z.rrs {
40 if txt, ok := rr.(*dns.TXT); ok {
41 if txt.Hdr.Name == name && strings.Join(txt.Txt, "") == value {
42 z.rrs = append(z.rrs[:i], z.rrs[i+1:]...)
43 }
44 }
45 }
46}
47
Giorgi Lekveishvili109a5672023-12-07 16:05:42 +040048func (z *ZoneFile) DeleteRecordsFor(name string) {
49 z.lock.Lock()
50 defer z.lock.Unlock()
51 rrs := make([]dns.RR, 0)
52 for _, rr := range z.rrs {
53 if rr.Header().Name != name {
54 rrs = append(rrs, rr)
55 }
56 }
57 z.rrs = rrs
58}
59
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +040060func (z *ZoneFile) CreateOrReplaceTxtRecord(name, value string) {
Giorgi Lekveishvili109a5672023-12-07 16:05:42 +040061 z.lock.Lock()
62 defer z.lock.Unlock()
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +040063 for i, rr := range z.rrs {
64 if txt, ok := rr.(*dns.TXT); ok {
65 if txt.Hdr.Name == name && strings.Join(txt.Txt, "") == value {
66 txt.Txt = []string{value}
67 z.rrs = append(z.rrs[:i], z.rrs[i+1:]...)
68 z.rrs = append(z.rrs, txt)
69 return
70 }
71 }
72 }
73 z.rrs = append(z.rrs, &dns.TXT{
74 Hdr: dns.RR_Header{
75 Name: name,
76 Rrtype: dns.TypeTXT,
77 Class: dns.ClassINET,
78 Ttl: 300,
79 },
80 Txt: []string{value},
81 })
82}
83
Giorgi Lekveishvili109a5672023-12-07 16:05:42 +040084func (z *ZoneFile) CreateARecord(name, value string) {
85 z.lock.Lock()
86 defer z.lock.Unlock()
87 z.rrs = append(z.rrs, &dns.A{
88 Hdr: dns.RR_Header{
89 Name: name,
90 Rrtype: dns.TypeA,
91 Class: dns.ClassINET,
92 Ttl: 300,
93 },
94 A: net.ParseIP(value),
95 })
96}
97
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +040098func (z *ZoneFile) Write(w io.Writer) error {
Giorgi Lekveishvili109a5672023-12-07 16:05:42 +040099 z.lock.Lock()
100 defer z.lock.Unlock()
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +0400101 for _, rr := range z.rrs {
102 if soa, ok := rr.(*dns.SOA); ok {
103 soa.Serial = NowUnix()
104 }
105 if _, err := fmt.Fprintf(w, "%s\n", rr.String()); err != nil {
106 return err
107 }
108 }
109 return nil
110}
111
112// TODO(gio): not going to work in 15 years?
113// TODO(gio): remove 10 *
114func NowUnix() uint32 {
115 return 10 * uint32(time.Now().Unix())
116}