Skip to content

Commit

Permalink
Revert "Revert "Supports multiple CloudFlare DNS records in config.ya…
Browse files Browse the repository at this point in the history
…ml (#26)" (#27)" (#28)

This reverts commit eea2c13.
  • Loading branch information
boris1993 authored Mar 29, 2019
1 parent eea2c13 commit bc857e3
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go:
- "1.12.x"
install: true
env:
- GO111MODULE=on
- GO111MODULE=on
script:
- make
notifications:
Expand Down
49 changes: 29 additions & 20 deletions utils/cfutil.go → cfutil/cfutil.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Package utils provides utilities about IP addresses, DNS records, and config files.
package utils
// Package cfutil provides utilities about manipulating a CloudFlare DNS record.
package cfutil

import (
"bytes"
Expand All @@ -14,25 +14,27 @@ import (
"github.com/boris1993/dnsupdater/model"
)

// GetDnsRecordIpAddress gets the IP address in the specified DNS record,
// GetDnsRecordIpAddress gets the IP address associated with the specified DNS record,
// which is identified by the combination of the record type(hard coded as A type for now) and the domain name.
//
// cloudFlareRecord contains the information which this process needed, and it is coming from the config.yaml.
//
// It returns the ID of this DNS record, the IP address of this record,
// or the error message if any error occurs.
func GetDnsRecordIpAddress() (recordID string, address string, err error) {
var config = conf.Get()
func GetDnsRecordIpAddress(cloudFlareRecord conf.CloudFlare) (recordID string, address string, err error) {
APIEndpoint := conf.Get().System.CloudFlareAPIEndpoint

client := &http.Client{}

req, err := http.NewRequest(http.MethodGet,
config.CloudFlare.APIEndpoint+"/zones/"+config.CloudFlare.ZoneID+"/dns_records?type=A&name="+config.CloudFlare.DomainName,
APIEndpoint+"/zones/"+cloudFlareRecord.ZoneID+"/dns_records?type=A&name="+cloudFlareRecord.DomainName,
nil)

req.Header.Add("X-Auth-Email", config.CloudFlare.AuthEmail)
req.Header.Add("X-Auth-Key", config.CloudFlare.APIKey)
req.Header.Add("X-Auth-Email", cloudFlareRecord.AuthEmail)
req.Header.Add("X-Auth-Key", cloudFlareRecord.APIKey)
req.Header.Add("Content-Type", "application/json")

log.Println(constants.MsgHeaderFetchingIPOfDomain, config.CloudFlare.DomainName)
log.Println(constants.MsgHeaderFetchingIPOfDomain, cloudFlareRecord.DomainName)

resp, err := client.Do(req)

Expand All @@ -44,7 +46,13 @@ func GetDnsRecordIpAddress() (recordID string, address string, err error) {
return "", "", errors.New(resp.Status)
}

defer resp.Body.Close()
defer func() {
err = resp.Body.Close()

if err != nil {
log.Errorln(constants.ErrCloseHTTPConnectionFail, err)
}
}()

body, err := ioutil.ReadAll(resp.Body)

Expand All @@ -63,7 +71,7 @@ func GetDnsRecordIpAddress() (recordID string, address string, err error) {
}

if !dnsRecord.Success {
return "", "", errors.New(constants.ErrMsgHeaderFetchDomainInfoFailed + config.CloudFlare.DomainName)
return "", "", errors.New(constants.ErrMsgHeaderFetchDomainInfoFailed + cloudFlareRecord.DomainName)
}

if len(dnsRecord.Result) == 0 {
Expand All @@ -73,42 +81,43 @@ func GetDnsRecordIpAddress() (recordID string, address string, err error) {
id := dnsRecord.Result[0].ID
ipAddrInDns := dnsRecord.Result[0].Content

log.Printf(constants.MsgFormatDNSFetchResult, config.CloudFlare.DomainName, ipAddrInDns)
log.Printf(constants.MsgFormatDNSFetchResult, cloudFlareRecord.DomainName, ipAddrInDns)

return id, ipAddrInDns, nil
}

// UpdateDnsRecord updates the specified DNS record identified by the record ID.
//
// id is the record ID, address is the IP address to be written.
// id is the record ID, address is the IP address to be written,
// and cloudFlareRecord contains the information corresponding to the DNS record to be updated.
//
// It returns the status of the update process, or the error if any error occurs.
func UpdateDnsRecord(id string, address string) (status bool, err error) {
var config = conf.Get()
func UpdateDnsRecord(id string, address string, cloudFlareRecord conf.CloudFlare) (status bool, err error) {
APIEndpoint := conf.Get().System.CloudFlareAPIEndpoint

client := &http.Client{}

updateRecordData := model.UpdateRecordData{}
updateRecordData.RecordType = "A"
updateRecordData.Name = config.CloudFlare.DomainName
updateRecordData.Name = cloudFlareRecord.DomainName
updateRecordData.Content = address

updateRecordDataByte, _ := json.Marshal(updateRecordData)
requestBodyReader := bytes.NewReader(updateRecordDataByte)

req, err := http.NewRequest(http.MethodPut,
config.CloudFlare.APIEndpoint+"/zones/"+config.CloudFlare.ZoneID+"/dns_records/"+id,
APIEndpoint+"/zones/"+cloudFlareRecord.ZoneID+"/dns_records/"+id,
requestBodyReader)

if err != nil {
return false, err
}

req.Header.Add("X-Auth-Email", config.CloudFlare.AuthEmail)
req.Header.Add("X-Auth-Key", config.CloudFlare.APIKey)
req.Header.Add("X-Auth-Email", cloudFlareRecord.AuthEmail)
req.Header.Add("X-Auth-Key", cloudFlareRecord.APIKey)
req.Header.Add("Content-Type", "application/json")

log.Printf(constants.MsgFormatUpdatingDNS, config.CloudFlare.DomainName, address)
log.Printf(constants.MsgFormatUpdatingDNS, cloudFlareRecord.DomainName, address)

resp, err := client.Do(req)

Expand Down
47 changes: 27 additions & 20 deletions conf/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,25 @@ var Debug bool
var Path string
var conf *config

// system describes the system properties in config.yaml
type system struct {
IPAddrAPI string `yaml:"IPAddrAPI"`
// config describes the top-level properties in config.yaml
type config struct {
System System `yaml:"System"`
CloudFlareRecords []CloudFlare `yaml:"CloudFlareRecords"`
}

// cloudFlare describes the CloudFlare specialised properties in config.yaml
type cloudFlare struct {
APIEndpoint string `yaml:"APIEndpoint"`
APIKey string `yaml:"APIKey"`
ZoneID string `yaml:"ZoneID"`
AuthEmail string `yaml:"AuthEmail"`
DomainName string `yaml:"DomainName"`
// System describes the System properties in config.yaml
type System struct {
IPAddrAPI string `yaml:"IPAddrAPI"`
CloudFlareAPIEndpoint string `yaml:"CloudFlareAPIEndpoint"`
}

// config describes the top-level properties in config.yaml
type config struct {
System system `yaml:"System"`
CloudFlare cloudFlare `yaml:"CloudFlare"`
// CloudFlare describes the CloudFlare specialised properties in config.yaml
type CloudFlare struct {
//APIEndpoint string `yaml:"APIEndpoint"`
APIKey string `yaml:"APIKey"`
ZoneID string `yaml:"ZoneID"`
AuthEmail string `yaml:"AuthEmail"`
DomainName string `yaml:"DomainName"`
}

func Get() *config {
Expand Down Expand Up @@ -84,10 +85,16 @@ func initConfig() error {

// printDebugInfo prints the configurations loaded from the file.
func printDebugInfo() {
log.Debugf("%15v: %s", "IPAddrAPI", conf.System.IPAddrAPI)
log.Debugf("%15v: %s", "APIEndpoint", conf.CloudFlare.APIEndpoint)
log.Debugf("%15v: %s", "APIKey", conf.CloudFlare.APIKey)
log.Debugf("%15v: %s", "ZoneID", conf.CloudFlare.ZoneID)
log.Debugf("%15v: %s", "AuthEmail", conf.CloudFlare.AuthEmail)
log.Debugf("%15v: %s", "DomainName", conf.CloudFlare.DomainName)
log.Debugf("%21v: %s", "IPAddrAPI", conf.System.IPAddrAPI)
log.Debugf("%21v: %s", "CloudFlareAPIEndpoint", conf.System.CloudFlareAPIEndpoint)
log.Debugln()

for _, item := range conf.CloudFlareRecords {
log.Debugln("========== CloudFlare DNS Record ==========")
log.Debugf("%10v: %s", "APIKey", item.APIKey)
log.Debugf("%10v: %s", "ZoneID", item.ZoneID)
log.Debugf("%10v: %s", "AuthEmail", item.AuthEmail)
log.Debugf("%10v: %s", "DomainName", item.DomainName)
log.Debugln()
}
}
16 changes: 10 additions & 6 deletions config.yaml.template
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
---
System:
IPAddrAPI: "https://api.ipify.org/"
CloudFlare:
APIEndpoint: "https://api.cloudflare.com/client/v4"
APIKey: "YOUR_CLOUDFLARE_API_KEY"
ZoneID: "ZONE_ID_OF_YOUR_DOMAIN"
AuthEmail: "EMAIL_FOR_LOGGING_INTO_CLOUDFLARE"
DomainName: "FULL_DOMAIN_YOU_WANT_TO_UPDATE. e.g.:test.example.com"
CloudFlareAPIEndpoint: "https://api.cloudflare.com/client/v4"
CloudFlareRecords:
- APIKey: "YOUR_CLOUDFLARE_API_KEY"
ZoneID: "ZONE_ID_OF_YOUR_DOMAIN"
AuthEmail: "EMAIL_FOR_LOGGING_INTO_CLOUDFLARE"
DomainName: "FULL_DOMAIN_YOU_WANT_TO_UPDATE. e.g.:test1.example.com"
- APIKey: "YOUR_CLOUDFLARE_API_KEY"
ZoneID: "ZONE_ID_OF_YOUR_DOMAIN"
AuthEmail: "EMAIL_FOR_LOGGING_INTO_CLOUDFLARE"
DomainName: "FULL_DOMAIN_YOU_WANT_TO_UPDATE. e.g.:test2.example.com"
2 changes: 2 additions & 0 deletions constants/errormsg.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const MsgHeaderDNSRecordUpdateSuccessful = "Successfully updated the DNS record"
const MsgHeaderCurrentIPAddr = "Current IP address is:"
const MsgHeaderFetchingIPOfDomain = "Fetching the IP address of domain"
const MsgHeaderLoadingConfig = "Loading configuration from"
const MsgHeaderDomainProcessing = "Processing"
const MsgCloudFlareRecordsFoundSuffix = "CloudFlare DNS record(s) found."

const MsgFormatDNSFetchResult = "The IP address of %s is %s."
const MsgFormatUpdatingDNS = "Updating the IP address of domain %s to %s."
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
Expand Down
51 changes: 31 additions & 20 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package main

import (
"flag"
"github.com/boris1993/dnsupdater/cfutil"
"github.com/boris1993/dnsupdater/conf"
"github.com/boris1993/dnsupdater/constants"
"github.com/boris1993/dnsupdater/utils"
log "github.com/sirupsen/logrus"
"io/ioutil"
"net/http"
Expand All @@ -17,34 +17,44 @@ func main() {
// Fetch the current external IP address.
ipAddress := getIPAddr()

// Then fetch the IP address of the specified DNS record.
id, recordAddress, err := utils.GetDnsRecordIpAddress()
log.Println(len(config.CloudFlareRecords), constants.MsgCloudFlareRecordsFoundSuffix)

if err != nil {
log.Fatalln(err)
}
// Process each CloudFlare DNS record
for _, cloudFlareRecord := range config.CloudFlareRecords {

// Do nothing when the IP address didn't change.
if ipAddress == recordAddress {
log.Println(constants.MsgIPAddrNotChanged)
os.Exit(0)
} else {
// Update the IP address when changed.
status, err := utils.UpdateDnsRecord(id, ipAddress)
// Prints which record is being processed
log.Println(constants.MsgHeaderDomainProcessing, cloudFlareRecord.DomainName)

// Then fetch the IP address of the specified DNS record.
id, recordAddress, err := cfutil.GetDnsRecordIpAddress(cloudFlareRecord)

if err != nil {
log.Fatalln(err)
log.Errorln(err)
}

if !status {
log.Errorln(constants.ErrMsgHeaderUpdateDNSRecordFailed, config.CloudFlare.DomainName)
os.Exit(1)
// Do nothing when the IP address didn't change.
if ipAddress == recordAddress {
log.Println(constants.MsgIPAddrNotChanged)
continue
} else {
log.Println(constants.MsgHeaderDNSRecordUpdateSuccessful, config.CloudFlare.DomainName)
// Update the IP address when changed.
status, err := cfutil.UpdateDnsRecord(id, ipAddress, cloudFlareRecord)

if err != nil {
log.Errorln(err)
continue
}

if !status {
log.Errorln(constants.ErrMsgHeaderUpdateDNSRecordFailed, cloudFlareRecord.DomainName)
continue
} else {
log.Println(constants.MsgHeaderDNSRecordUpdateSuccessful, cloudFlareRecord.DomainName)
}
}

os.Exit(0)
}

os.Exit(0)
}

func init() {
Expand All @@ -62,6 +72,7 @@ func init() {
}
}

// getIPAddr returns the external IP address for your network
func getIPAddr() string {
var config = conf.Get()

Expand Down

0 comments on commit bc857e3

Please sign in to comment.