diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 0fbf90d..0000000 --- a/.drone.yml +++ /dev/null @@ -1,51 +0,0 @@ -kind: pipeline -type: docker -name: staging - -trigger: - branches: - - master - event: - - push - -steps: - - name: test - image: golang:1.13.5 - commands: - - go test ./... - - - name: build - image: plugins/docker - settings: - username: - from_secret: dockerlogin - password: - from_secret: dockerpassword - repo: llehouerou/dnsupdater - tags: latest - ---- -kind: pipeline -type: ssh -name: deploy - -server: - host: - from_secret: host - user: - from_secret: username - ssh_key: - from_secret: ssh_key - -clone: - disable: true - -steps: - - name: deploy - commands: - - cd /home/laurent/docker/ - - docker-compose pull dnsupdater - - docker-compose up -d dnsupdater - -depends_on: - - staging \ No newline at end of file diff --git a/main.go b/cmd/dnsupdater/main.go similarity index 67% rename from main.go rename to cmd/dnsupdater/main.go index ea40017..d239e15 100644 --- a/main.go +++ b/cmd/dnsupdater/main.go @@ -4,13 +4,18 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" "net/http" "os" "path" - "regexp" "time" + "gitlab.lehouerou.net/laurent/dnsupdater/internal/outboundip/ddwrt" + + "gitlab.lehouerou.net/laurent/dnsupdater/internal/outboundip" + + "gitlab.lehouerou.net/laurent/dnsupdater/internal/config" + "gitlab.lehouerou.net/laurent/dnsupdater/internal/dns/gandi" + "golang.org/x/xerrors" "cdr.dev/slog" @@ -22,34 +27,8 @@ import ( "gopkg.in/gomail.v2" ) -type Configuration struct { - Username string `json:"name"` - Email string `json:"email"` - GandiKey string `json:"gandikey"` - Domains []string `json:"domains"` - RouterLogin string `json:"router_login"` - RouterPassword string `json:"router_password"` - RouterStatusUrl string `json:"router_status_url"` - WanIPRegex string `json:"wan_ip_regex"` - MailSettings *struct { - Sender string `json:"sender"` - To []string `json:"to"` - SmtpHost string `json:"smtp_host"` - SmtpLogin string `json:"smtp_login"` - SmtpPassword string `json:"smtp_password"` - SmtpPort int `json:"smtp_port"` - } `json:"mail_settings"` -} - -type DnsResponse struct { - RecordType string `json:"rrset_type"` - Ttl int `json:"rrset_ttl"` - Name string `json:"rrset_name"` - Values []string `json:"rrset_values"` -} - var ( - configuration Configuration + configuration config.Configuration configPath string base *sling.Sling ) @@ -91,7 +70,7 @@ func before(c *cli.Context) error { } defer file.Close() decoder := json.NewDecoder(file) - configuration = Configuration{} + configuration = config.Configuration{} err = decoder.Decode(&configuration) if err != nil { return err @@ -107,18 +86,23 @@ func before(c *cli.Context) error { func start(*cli.Context) error { ctx := context.Background() - if err := update(ctx); err != nil { + outboundIpRequester := ddwrt.NewIpRequester(configuration.RouterStatusUrl, + configuration.RouterLogin, + configuration.RouterPassword) + if err := update(ctx, outboundIpRequester); err != nil { SendStatusMail(ctx, fmt.Sprintf("Error during update process : %s", err)) return err } return nil } -func update(ctx context.Context) error { - newIp, err := GetOutboundIP() - if err != nil { - return fmt.Errorf("getting outbound ip: %v", err) +func update(ctx context.Context, requester outboundip.IpRequester) error { + newIpResult := <-requester.GetOutboundIp() + + if newIpResult.Error != nil { + return fmt.Errorf("getting outbound ip: %v", newIpResult.Error) } + newIp := newIpResult.Ip updatedDomains := "" for _, domain := range configuration.Domains { @@ -181,7 +165,7 @@ func GetCurrentIp(ctx context.Context, domain string) (string, error) { err := try.Do(func(attempt int) (bool, error) { var err error value, err = func(domain string) (string, error) { - dnsresponse := DnsResponse{} + dnsresponse := gandi.DnsResponse{} resp, err := base.New().Get(fmt.Sprintf(GandiARecordUrl, domain)). ReceiveSuccess(&dnsresponse) if err != nil { @@ -224,37 +208,3 @@ func SetCurrentIp(newip string, domain string) error { } return nil } - -func GetOutboundIP() (string, error) { - url := configuration.RouterStatusUrl - if url == "" { - url = "http://192.168.1.1/Status_Internet.live.asp" - } - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return "", fmt.Errorf("creating http request: %v", err) - } - if configuration.RouterLogin != "" && configuration.RouterPassword != "" { - req.SetBasicAuth(configuration.RouterLogin, configuration.RouterPassword) - } - res, err := http.DefaultClient.Do(req) - if err != nil { - return "", fmt.Errorf("executing http request: %v", err) - } - defer res.Body.Close() - body, err := ioutil.ReadAll(res.Body) - if err != nil { - return "", fmt.Errorf("reading response body: %v", err) - } - - wanipregex := configuration.WanIPRegex - if wanipregex == "" { - wanipregex = "wan_ipaddr::([0-9.]*)}" - } - r := regexp.MustCompile(wanipregex) - matches := r.FindStringSubmatch(string(body)) - if len(matches) < 2 { - return "", fmt.Errorf("unable to find WAN IP with regex %s in %s", wanipregex, string(body)) - } - return matches[1], nil -} diff --git a/entry.sh b/entry.sh index 40a5c3f..795e273 100644 --- a/entry.sh +++ b/entry.sh @@ -1,4 +1,4 @@ -#!bin/sh +#!/usr/bin/env sh echo "Starting container ..." echo "Setup check cron job with cron expression CHECK_CRON: ${CHECK_CRON}" diff --git a/go.mod b/go.mod index 67c3b48..1b332c4 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module gogs.lehouerou.net/Laurent/dnsupdater +module gitlab.lehouerou.net/laurent/dnsupdater go 1.13 @@ -7,6 +7,7 @@ require ( github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 // indirect github.com/dghubble/sling v1.3.0 github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 + github.com/pkg/errors v0.8.1 github.com/urfave/cli v1.20.0 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect diff --git a/go.sum b/go.sum index 6b68420..32ceb86 100644 --- a/go.sum +++ b/go.sum @@ -103,6 +103,7 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..3de5da5 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,20 @@ +package config + +type Configuration struct { + Username string `json:"name"` + Email string `json:"email"` + GandiKey string `json:"gandikey"` + Domains []string `json:"domains"` + RouterLogin string `json:"router_login"` + RouterPassword string `json:"router_password"` + RouterStatusUrl string `json:"router_status_url"` + WanIPRegex string `json:"wan_ip_regex"` + MailSettings *struct { + Sender string `json:"sender"` + To []string `json:"to"` + SmtpHost string `json:"smtp_host"` + SmtpLogin string `json:"smtp_login"` + SmtpPassword string `json:"smtp_password"` + SmtpPort int `json:"smtp_port"` + } `json:"mail_settings"` +} diff --git a/internal/dns/gandi/dnsresponse.go b/internal/dns/gandi/dnsresponse.go new file mode 100644 index 0000000..91d9d4e --- /dev/null +++ b/internal/dns/gandi/dnsresponse.go @@ -0,0 +1,8 @@ +package gandi + +type DnsResponse struct { + RecordType string `json:"rrset_type"` + Ttl int `json:"rrset_ttl"` + Name string `json:"rrset_name"` + Values []string `json:"rrset_values"` +} diff --git a/internal/outboundip/ddwrt/iprequester.go b/internal/outboundip/ddwrt/iprequester.go new file mode 100644 index 0000000..8b79a6b --- /dev/null +++ b/internal/outboundip/ddwrt/iprequester.go @@ -0,0 +1,74 @@ +package ddwrt + +import ( + "io/ioutil" + "net/http" + "regexp" + + "github.com/pkg/errors" + "gitlab.lehouerou.net/laurent/dnsupdater/internal/outboundip" +) + +const ( + DefaultUrl = "http://192.168.1.1/Status_Internet.live.asp" + WanIpRegex = "wan_ipaddr::([0-9.]*)}" +) + +type IpRequester struct { + statusUrl string + login string + password string +} + +func NewIpRequester(statusUrl string, login string, password string) *IpRequester { + return &IpRequester{statusUrl: statusUrl, login: login, password: password} +} + +func (r IpRequester) GetOutboundIp() <-chan outboundip.IpRequestResult { + result := make(chan outboundip.IpRequestResult) + go func() { + defer close(result) + url := r.statusUrl + if url == "" { + url = DefaultUrl + } + req, err := http.NewRequest("GET", url, nil) + if err != nil { + result <- outboundip.IpRequestResult{ + Error: errors.Wrap(err, "creating http request"), + } + return + } + + if r.login != "" && r.password != "" { + req.SetBasicAuth(r.login, r.password) + } + + res, err := http.DefaultClient.Do(req) + if err != nil { + result <- outboundip.IpRequestResult{ + Error: errors.Wrap(err, "executing http request"), + } + return + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + result <- outboundip.IpRequestResult{ + Error: errors.Wrap(err, "reading response body"), + } + return + } + + matches := regexp.MustCompile(WanIpRegex).FindStringSubmatch(string(body)) + if len(matches) < 2 { + result <- outboundip.IpRequestResult{ + Error: errors.Errorf("unable to find WAN IP with regex %s in %s", WanIpRegex, string(body)), + } + return + } + result <- outboundip.IpRequestResult{Ip: matches[1]} + }() + return result +} diff --git a/internal/outboundip/ddwrt/iprequester_test.go b/internal/outboundip/ddwrt/iprequester_test.go new file mode 100644 index 0000000..834b6d8 --- /dev/null +++ b/internal/outboundip/ddwrt/iprequester_test.go @@ -0,0 +1,15 @@ +package ddwrt + +import ( + "fmt" + "testing" +) + +func TestRequester_GetOutboundIp(t *testing.T) { + requester := NewIpRequester("", "laurent", "&951753seiko38613861") + result := <-requester.GetOutboundIp() + fmt.Printf("%+v\n", result) + if result.Error != nil { + t.Error(result.Error) + } +} diff --git a/internal/outboundip/iprequester.go b/internal/outboundip/iprequester.go new file mode 100644 index 0000000..25c6a6f --- /dev/null +++ b/internal/outboundip/iprequester.go @@ -0,0 +1,10 @@ +package outboundip + +type IpRequestResult struct { + Ip string + Error error +} + +type IpRequester interface { + GetOutboundIp() <-chan IpRequestResult +}