minor tweaks for multi-line nsupdate

This commit is contained in:
Hyatt 2024-01-15 15:02:37 -06:00
parent a4430227e3
commit c1739856ce
Signed by: nhyatt
GPG Key ID: C50D0BBB5BC40BEA
5 changed files with 97 additions and 16 deletions

View File

@ -19,7 +19,7 @@
</head>
<body style="text-align:center;">
<small>
[<a href="./status.txt">txt</a>]&nbsp;<tt>dig +short txt istheinternetonfire.app</tt>&nbsp;[<a href="./status.json">json</a>]
[<a href="./status.txt">txt</a>]&nbsp;<tt>dig +short txt istheinternetonfire.app | sed 's/" "//g' |sed 's/%n/\n/g'</tt>&nbsp;[<a href="./status.json">json</a>]
</small>
<hr align="CENTER" noshade="noshade" size="2" width="100%">
{{- if gt (len .CVEs) 0 }}

View File

@ -32,10 +32,12 @@ type Config struct {
RefreshSeconds int `default:"14400" env:"refresh_seconds"`
// nsupdate
NSUKey string `env:"nsupdate-key" secret:"true"`
NSUPort int `default:"53" env:"nsupdate-port"`
NSUServer string `default:"ns1.example.com" env:"nsupdate-server"`
NSUZone string `default:"example.com" env:"nsupdate-zone"`
NSUKeyLabel string `env:"nsupdate-key-label"`
NSUKey string `env:"nsupdate-key" secret:"true"`
NSUKeyAlgorithm string `default:"hmac-sha512" env:"nsupdate-key-algorithm"`
NSUPort int `default:"53" env:"nsupdate-port"`
NSUServer string `default:"ns1.example.com" env:"nsupdate-server"`
NSUZone string `default:"example.com" env:"nsupdate-zone"`
}
// New initializes the config variable for use with a prepared set of defaults.

View File

@ -13,15 +13,49 @@ import (
"istheinternetonfire.app/internal/config"
)
func New() NsUpdateStruct {
return NsUpdateStruct{}
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) Update(record, recordType, value string) error {
if strings.ToUpper(recordType) == "TXT" {
// sanitize TXT value
for _, v := range specialChars {
value = strings.ReplaceAll(value, v, fmt.Sprintf("\\%s", v))
}
// convert to rune
a := []rune(value)
// split into 255 character blocks
value = ""
for i, r := range a {
value += string(r)
if i > 0 && (i+1)%254 == 0 {
value += string(`" "`)
}
}
// convert new lines into safe string
value = strings.ReplaceAll(value, "\n", "%n")
}
r, err := getRecord(c.Server, c.Port, recordType, record)
if err != nil {
config.Cfg.Log.Debug("creating record", "record", record)
return c.Create(record, recordType, value)
config.Cfg.Log.Info("unable to get existing record", "record", record, "error", err)
}
if r != value {
@ -48,7 +82,7 @@ func (c NsUpdateStruct) Delete(record, recordType string) error {
command := fmt.Sprintf(`#/bin/env/sh
read -r -d '' DDNS_KEY <<- EOF
key "update" {
key "%s" {
algorithm "%s";
secret "%s";
};
@ -60,7 +94,7 @@ send
EOF
nsupdate -v -k <(printf '%%s' "${DDNS_KEY}") <(printf '%%s\n\n' "${COMMAND}")
`, c.Key.Algorithm, c.Key.Secret, c.Server, record, strings.ToUpper(recordType))
`, c.Key.Label, c.Key.Algorithm, c.Key.Secret, c.Server, record, strings.ToUpper(recordType))
cmd := exec.Command("/usr/bin/sh", "-c", command)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
@ -80,19 +114,19 @@ func (c NsUpdateStruct) Create(record, recordType, value string) error {
command := fmt.Sprintf(`#/bin/env/sh
read -r -d '' DDNS_KEY <<- EOF
key "update" {
key "%s" {
algorithm "%s";
secret "%s";
};
EOF
read -r -d '' COMMAND <<- EOF
server %s
update add %s. 30 IN %s %s
update add %s. 30 IN %s "%s"
send
EOF
nsupdate -v -k <(printf '%%s' "${DDNS_KEY}") <(printf '%%s\n\n' "${COMMAND}")
`, c.Key.Algorithm, c.Key.Secret, c.Server, record, strings.ToUpper(recordType), value)
`, c.Key.Label, c.Key.Algorithm, c.Key.Secret, c.Server, record, strings.ToUpper(recordType), value)
cmd := exec.Command("/usr/bin/sh", "-c", command)
cmd.Stdout = &stdout
cmd.Stderr = &stderr

View File

@ -1,13 +1,14 @@
package nsupdate
type NsUpdateStruct struct {
Key KeyStruct `json:"key" yaml:"key"`
Key KeyStruct `json:"key" yaml:"key"`
Server string `json:"server" yaml:"server"`
Port int `json:"port" yaml:"port"`
Zone string `json:"zone" yaml:"zone"`
}
type KeyStruct struct {
Label string `json:"key-label" yaml:"key-label"`
Algorithm string `json:"algorithm" yaml:"algorithm"`
Secret string `json:"Secret" yaml:"secret"`
Secret string `json:"secret" yaml:"secret"`
}

44
main.go
View File

@ -1,13 +1,16 @@
package main
import (
"fmt"
"log"
"os"
"os/signal"
"syscall"
"time"
"istheinternetonfire.app/internal/cisa"
"istheinternetonfire.app/internal/config"
"istheinternetonfire.app/internal/nsupdate"
"istheinternetonfire.app/internal/webserver"
)
@ -34,5 +37,46 @@ func main() {
// get remote data
go cisa.Start()
// update DNS records
go func() {
dns := nsupdate.New(config.Cfg.NSUKeyLabel, config.Cfg.NSUKeyAlgorithm, config.Cfg.NSUKey, config.Cfg.NSUServer, config.Cfg.NSUPort, config.Cfg.NSUZone)
time.Sleep(time.Second * time.Duration(15))
for {
var (
cves []cisa.VulStruct
num int = 3
)
c := cisa.Read()
for _, i := range c.Vulnerabilities {
t, _ := time.Parse("2006-01-02", i.DateAdded)
if t.After(time.Now().Add(-time.Hour * 720)) {
cves = append(cves, i)
}
}
if len(cves) == 0 {
if err := dns.Delete("istheinternetonfire.app", "TXT"); err != nil {
config.Cfg.Log.Error("unable to delete dns record", "error", err)
time.Sleep(time.Second * time.Duration(config.Cfg.RefreshSeconds))
continue
}
} else if len(cves) < 3 {
num = len(cves)
}
var txtData string
for _, v := range cves[len(cves)-num:] {
txtData += fmt.Sprintf("%s - %s - %s\n", v.CveID, v.Product, v.ShortDescription)
}
if err := dns.Update("istheinternetonfire.app", "TXT", txtData); err != nil {
config.Cfg.Log.Error("unable to add dns record", "error", err)
time.Sleep(time.Second * time.Duration(config.Cfg.RefreshSeconds))
continue
}
time.Sleep(time.Second * time.Duration(config.Cfg.RefreshSeconds))
}
}()
forever()
}