Files
cloudflare-dns-updater/dns.go
2025-10-03 01:01:07 -04:00

185 lines
4.0 KiB
Go

package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
)
type IpResponse struct {
Ip string `json:"ip"`
}
type DnsRecord struct {
Id string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Content string `json:"content"`
Ttl int `json:"ttl"`
Proxied bool `json:"proxied"`
}
type DnsRecords struct {
Result []DnsRecord `json:"result"`
}
func getIp() (string, error) {
// Get IP from ipify and return it as a IpResponse
ipUrl := "https://api.ipify.org?format=json"
resp, err := http.Get(ipUrl)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
var ipResponse IpResponse
if err := json.Unmarshal(body, &ipResponse); err != nil {
return "", err
}
return ipResponse.Ip, nil
}
type DnsUpdater struct {
config *Config
}
func (d *DnsUpdater) CheckIfRecordsExist(recordName string) (DnsRecord, error) {
cloudFlareUrl := "https://api.cloudflare.com/client/v4/zones/" + d.config.ZoneID + "/dns_records?name=" + recordName + "&type=A"
log.Printf("CloudFlare URL: %s", cloudFlareUrl)
req, err := http.NewRequest("GET", cloudFlareUrl, nil)
if err != nil {
return DnsRecord{}, err
}
req.Header.Set("X-Auth-Email", d.config.Email)
req.Header.Set("Authorization", "Bearer "+d.config.AuthKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return DnsRecord{}, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return DnsRecord{}, err
}
log.Printf("Body: %s", string(body))
var dnsRecords DnsRecords
if err := json.Unmarshal(body, &dnsRecords); err != nil {
return DnsRecord{}, err
}
log.Printf("DNS Records: %+v", dnsRecords)
// Check if the record exists
for _, record := range dnsRecords.Result {
if record.Name == recordName && record.Type == "A" {
return record, nil
}
}
return DnsRecord{}, nil
}
func (d *DnsUpdater) Update(record DnsRecord) error {
ip, err := getIp()
if err != nil {
return err
}
if d.config.ForceIP != "" {
ip = d.config.ForceIP
}
if record.Content == ip {
return nil
}
record.Content = ip
record.Ttl = 3600
cloudFlareUrl := "https://api.cloudflare.com/client/v4/zones/" + d.config.ZoneID + "/dns_records/" + record.Id
body, err := json.Marshal(record)
if err != nil {
return err
}
req, err := http.NewRequest("PATCH", cloudFlareUrl, bytes.NewBuffer(body))
if err != nil {
return err
}
req.Header.Set("X-Auth-Email", d.config.Email)
req.Header.Set("Authorization", "Bearer "+d.config.AuthKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err = io.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return fmt.Errorf("failed to update DNS: %s", string(body))
}
log.Printf("Updated DNS: %s", string(body))
return nil
}
func (d *DnsUpdater) Create(recordName string) error {
ip, err := getIp()
if err != nil {
return err
}
if d.config.ForceIP != "" {
ip = d.config.ForceIP
}
record := DnsRecord{
Name: recordName,
Type: "A",
Content: ip,
Ttl: 3600,
Proxied: false,
}
cloudFlareUrl := "https://api.cloudflare.com/client/v4/zones/" + d.config.ZoneID + "/dns_records"
body, err := json.Marshal(record)
if err != nil {
return err
}
req, err := http.NewRequest("POST", cloudFlareUrl, bytes.NewBuffer(body))
if err != nil {
return err
}
req.Header.Set("X-Auth-Email", d.config.Email)
req.Header.Set("Authorization", "Bearer "+d.config.AuthKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err = io.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return fmt.Errorf("failed to create DNS: %s", string(body))
}
log.Printf("Created DNS: %s", string(body))
return nil
}