152 lines
3.3 KiB
Go
152 lines
3.3 KiB
Go
package nsupdate
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"os/exec"
|
|
|
|
"istheinternetonfire.app/internal/config"
|
|
)
|
|
|
|
func New(keyLabel, keyAlgorithm, keySecret, server string, port int, zone string) NsUpdateStruct {
|
|
return NsUpdateStruct{
|
|
Key: KeyStruct{
|
|
Label: keyLabel,
|
|
Algorithm: keyAlgorithm,
|
|
Secret: keySecret,
|
|
},
|
|
Server: server,
|
|
Port: port,
|
|
Zone: zone,
|
|
}
|
|
}
|
|
|
|
var (
|
|
// escape characters
|
|
specialChars = []string{
|
|
`"`,
|
|
}
|
|
)
|
|
|
|
func (c NsUpdateStruct) UpdateTXT(record, recordType, value string) error {
|
|
var (
|
|
stdout bytes.Buffer
|
|
stderr bytes.Buffer
|
|
)
|
|
|
|
for _, v := range specialChars {
|
|
value = strings.ReplaceAll(value, v, fmt.Sprintf("\\%s", v))
|
|
}
|
|
|
|
value = sanitizeTXT(value)
|
|
|
|
command := fmt.Sprintf("dig +short TXT %s", record)
|
|
cmd := exec.Command("/usr/bin/env", "sh", "-c", command)
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
if err := cmd.Run(); err != nil {
|
|
config.Cfg.Log.Error("error adding record", "error", err, "stderr", stderr.String(), "stdout", stdout.String())
|
|
return err
|
|
}
|
|
|
|
oldTXT := stdout.String()
|
|
|
|
if strings.ReplaceAll(oldTXT, `" "`, ``) != strings.ReplaceAll(value, `" "`, ``) {
|
|
config.Cfg.Log.Debug("deleting record", "record", record)
|
|
if err := c.Delete(record, recordType); err != nil {
|
|
return err
|
|
}
|
|
config.Cfg.Log.Debug("creating record", "record", record)
|
|
if err := c.Create(record, recordType, value); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
config.Cfg.Log.Debug("no update necessary")
|
|
return nil
|
|
}
|
|
|
|
func (c NsUpdateStruct) Delete(record, recordType string) error {
|
|
var (
|
|
stdout bytes.Buffer
|
|
stderr bytes.Buffer
|
|
)
|
|
|
|
command := fmt.Sprintf(`#/usr/bin/env sh
|
|
read -r -d '' DDNS_KEY <<- EOF
|
|
key "%s" {
|
|
algorithm "%s";
|
|
secret "%s";
|
|
};
|
|
EOF
|
|
read -r -d '' COMMAND <<- EOF
|
|
server %s
|
|
update delete %s. 30 IN %s
|
|
send
|
|
EOF
|
|
|
|
nsupdate -v -k <(printf '%%s' "${DDNS_KEY}") <(printf '%%s\n\n' "${COMMAND}")
|
|
`, c.Key.Label, c.Key.Algorithm, c.Key.Secret, c.Server, record, strings.ToUpper(recordType))
|
|
cmd := exec.Command("/usr/bin/env", "sh", "-c", command)
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
if err := cmd.Run(); err != nil {
|
|
config.Cfg.Log.Error("error deleting record", "error", err, "stderr", stderr.String(), "stdout", stdout.String())
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c NsUpdateStruct) Create(record, recordType, value string) error {
|
|
var (
|
|
stdout bytes.Buffer
|
|
stderr bytes.Buffer
|
|
)
|
|
|
|
command := fmt.Sprintf(`#/usr/bin/env sh
|
|
read -r -d '' DDNS_KEY <<- EOF
|
|
key "%s" {
|
|
algorithm "%s";
|
|
secret "%s";
|
|
};
|
|
EOF
|
|
read -r -d '' COMMAND <<- EOF
|
|
server %s
|
|
update add %s. 30 IN %s "%s"
|
|
send
|
|
EOF
|
|
|
|
nsupdate -v -k <(printf '%%s' "${DDNS_KEY}") <(printf '%%s\n\n' "${COMMAND}")
|
|
`, c.Key.Label, c.Key.Algorithm, c.Key.Secret, c.Server, record, strings.ToUpper(recordType), value)
|
|
cmd := exec.Command("/usr/bin/env", "sh", "-c", command)
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
if err := cmd.Run(); err != nil {
|
|
config.Cfg.Log.Error("error adding record", "error", err, "stderr", stderr.String(), "stdout", stdout.String())
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func sanitizeTXT(s string) string {
|
|
// convert to rune
|
|
a := []rune(s)
|
|
// split into 255 character blocks
|
|
s = ""
|
|
for i, r := range a {
|
|
s += string(r)
|
|
if i > 0 && (i+1)%200 == 0 {
|
|
s += string(`" "`)
|
|
}
|
|
}
|
|
// convert new lines into safe string
|
|
s = strings.ReplaceAll(s, "\n", "%n")
|
|
|
|
return s
|
|
}
|