From b78729d516a632bbafdd819e828135832b8584ad Mon Sep 17 00:00:00 2001 From: Lakshman Peethani Date: Mon, 30 May 2022 11:55:28 +0530 Subject: [PATCH 1/4] added vscode settings --- .github/workflows/build.yml | 4 ++-- .vscode/settings.json | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 87fe3b6..732d191 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,5 +21,5 @@ jobs: - name: Build run: go build -v ./... - - name: Test - run: go test -v ./... + # - name: Test + # run: go test -v ./... diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..61ff975 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "yaml.schemas": { + "https://json.schemastore.org/github-workflow.json": "file:///home/lakshman/projects/gddns/.github/workflows/build.yml" + } +} \ No newline at end of file From e31c3c6f652e849221863aeef3165dc4a592d8eb Mon Sep 17 00:00:00 2001 From: Lakshman Peethani Date: Thu, 2 Jun 2022 00:13:09 +0530 Subject: [PATCH 2/4] Service/Daemon implementation wip --- go.mod | 7 ++- go.sum | 5 ++ main.go | 142 +++++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 126 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 32e5f9b..38a889a 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,9 @@ module github.com/plkumar/gddns go 1.18 -require gopkg.in/yaml.v2 v2.4.0 +require ( + github.com/takama/daemon v1.0.0 + gopkg.in/yaml.v2 v2.4.0 +) + +require golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6 // indirect diff --git a/go.sum b/go.sum index 7534661..7928dce 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,8 @@ +github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/takama/daemon v1.0.0 h1:XS3VLnFKmqw2Z7fQ/dHRarrVjdir9G3z7BEP8osjizQ= +github.com/takama/daemon v1.0.0/go.mod h1:gKlhcjbqtBODg5v9H1nj5dU1a2j2GemtuWSNLD5rxOE= +golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6 h1:X9xIZ1YU8bLZA3l6gqDUHSFiD0GFI9S548h6C8nDtOY= +golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/main.go b/main.go index dd6ca23..99ab8ea 100644 --- a/main.go +++ b/main.go @@ -3,47 +3,135 @@ package main import ( "flag" "fmt" + "log" + "os" + "os/signal" "strings" + "syscall" + "time" common "github.com/plkumar/gddns/common" config "github.com/plkumar/gddns/config" "github.com/plkumar/gddns/ddns" + "github.com/takama/daemon" + _ "github.com/takama/daemon" ) +const ( + name = "gddns" + description = "Google Dynamic DNS Client Daemon" +) + +// dependencies that are NOT required by the service, but might be used +var dependencies = []string{"dummy.service"} + +var stdlog, errlog *log.Logger + +// Service has embedded daemon +type Service struct { + daemon.Daemon +} + +func (service *Service) Manage(configFile *string) (string, error) { + + usage := "Usage: myservice install | remove | start | stop | status" + + if len(os.Args) > 1 { + command := os.Args[1] + switch command { + case "install": + return service.Install() + case "remove": + return service.Remove() + case "start": + return service.Start() + case "stop": + return service.Stop() + case "status": + return service.Status() + default: + return usage, nil + } + } + + interrupt := make(chan os.Signal, 1) + signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM) + timer1 := time.NewTimer(5 * time.Minute) + for { + select { + case <-timer1.C: + updateIP(configFile) + case killSignal := <-interrupt: + stdlog.Println("Got signal:", killSignal) + + if killSignal == os.Interrupt { + return "Daemon was interrupted by system signal", nil + } + return "Daemon was killed", nil + } + } +} + +func init() { + stdlog = log.New(os.Stdout, "", 0) + errlog = log.New(os.Stderr, "", 0) +} + +func updateIP(configFile *string) { + + y, err := config.GetConfig(*configFile) + if err == nil { + gd := ddns.GoogleDDNS{} + for key, host := range y.Gddns { + fmt.Println("Updating for: ", key) + hostParams := host["params"] + gd.SetHost(&hostParams) + + status, err := gd.UpdateDDNSIp() + if err != nil { + fmt.Println(err.Error()) + } else { + + if strings.Contains(status, "success") { + fmt.Println("DNS Updated successfully.") + } else if strings.Contains(status, "nochg") { + fmt.Println("No Change") + } else { + // DNS Update failed, log and stop processing current host + // TODO: Stop further DNS update attempts to ensure google is not blocking the client + fmt.Println(status, common.DDNSStatusMap[status]) + } + } + } + } else { + fmt.Println("Error reading configuration :: ", err) + } + +} + func main() { - fmt.Println("Google Dynamic DNS Client") - standalone := flag.Bool("standalone", true, "Run in standalone mode.") + //fmt.Println("Google Dynamic DNS Client") + + standalone := flag.Bool("standalone", false, "Run in standalone mode.") configFile := flag.String("config", "gddns.yml", "configuration file path.") flag.Parse() if *standalone { - y, err := config.GetConfig(*configFile) - if err == nil { - gd := ddns.GoogleDDNS{} - for key, host := range y.Gddns { - fmt.Println("Updating for: ", key) - hostParams := host["params"] - gd.SetHost(&hostParams) - - status, err := gd.UpdateDDNSIp() - if err != nil { - fmt.Println(err.Error()) - } else { + updateIP(configFile) + } else { - if strings.Contains(status, "success") { - fmt.Println("DNS Updated successfully.") - } else if strings.Contains(status, "nochg") { - fmt.Println("No Change") - } else { - // DNS Update failed, log and stop processing current host - // TODO: Stop further DNS update attempts to ensure google is not blocking the client - fmt.Println(status, common.DDNSStatusMap[status]) - } - } - } - } else { - fmt.Println("Error reading configuration :: ", err) + srv, err := daemon.New(name, description, daemon.SystemDaemon, dependencies...) + if err != nil { + errlog.Println("Error: ", err) + os.Exit(1) + } + service := &Service{srv} + status, err := service.Manage(configFile) + if err != nil { + errlog.Println(status, "\nError: ", err) + os.Exit(1) } + fmt.Println(status) } } From ace6a6d603858c0f9acde42cf5ab7bf0a0f294ee Mon Sep 17 00:00:00 2001 From: Lakshman Peethani Date: Thu, 2 Jun 2022 22:57:23 +0530 Subject: [PATCH 3/4] daemon implementation wip --- .github/workflows/build.yml | 12 ++++++++++-- common/constants.go | 3 ++- ddns/gddns.go | 37 +++++++++++++++++++++++++++++++++++-- main.go | 20 ++++++++------------ 4 files changed, 55 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 732d191..f91b5a2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,8 +18,16 @@ jobs: with: go-version: 1.18 - - name: Build - run: go build -v ./... + - name: Generate build files + uses: thatisuday/go-cross-build@v1 + with: + platforms: 'linux/amd64, darwin/amd64, darwin/arm64, windows/amd64' + package: 'demo' + name: 'program' + compress: 'true' + dest: 'dist' + # - name: Build + # run: go build -v ./... # - name: Test # run: go test -v ./... diff --git a/common/constants.go b/common/constants.go index b1a3e1f..d82d81b 100644 --- a/common/constants.go +++ b/common/constants.go @@ -1,3 +1,4 @@ package common -const GoogleDDNSUrl = "https://domains.google.com/nic/update" +const GOOGLE_URL_DDNS_UPDATE = "https://domains.google.com/nic/update" +const GOOGLE_URL_IP_CHECK = "https://domains.google.com/checkip" diff --git a/ddns/gddns.go b/ddns/gddns.go index 428b188..ae5a4c4 100644 --- a/ddns/gddns.go +++ b/ddns/gddns.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net/http" + "os" "time" "github.com/plkumar/gddns/common" @@ -13,15 +14,47 @@ import ( type GoogleDDNS struct { HostConfig config.Params + tempFile string } func (g *GoogleDDNS) SetHost(cfg *config.Params) { g.HostConfig = *cfg } +func (g *GoogleDDNS) writeCurrentIP(tmpFile string, ip string) error { + f, err := os.CreateTemp("", tmpFile) + if err == nil { + defer f.Close() + f.WriteString(ip) + g.tempFile = f.Name() + return nil + } else { + return err + } +} + +func (g *GoogleDDNS) readIPFromTmpFile() (string, error) { + data, err := os.ReadFile(g.tempFile) + if err == nil { + return string(data), nil + } else { + return "", err + } +} + +func (g *GoogleDDNS) checkIPChanged(tmpFile string, ip string) bool { + lastIPAddress, err := g.readIPFromTmpFile() + if err == nil { + if lastIPAddress == ip { + return false + } + } + return true +} + func (g *GoogleDDNS) GetIP() (string, error) { - resp, err := http.Get("https://domains.google.com/checkip") + resp, err := http.Get(common.GOOGLE_URL_IP_CHECK) if err == nil { scanner := bufio.NewScanner(resp.Body) if scanner.Scan() { @@ -44,7 +77,7 @@ func (g *GoogleDDNS) UpdateDDNSIp() (string, error) { Timeout: time.Second * 10, } - req, err := http.NewRequest("GET", common.GoogleDDNSUrl, nil) + req, err := http.NewRequest("GET", common.GOOGLE_URL_DDNS_UPDATE, nil) if err != nil { //fmt.Print("Got error %s", err.Error()) return "", err diff --git a/main.go b/main.go index 99ab8ea..8bbe174 100644 --- a/main.go +++ b/main.go @@ -2,7 +2,6 @@ package main import ( "flag" - "fmt" "log" "os" "os/signal" @@ -14,7 +13,6 @@ import ( config "github.com/plkumar/gddns/config" "github.com/plkumar/gddns/ddns" "github.com/takama/daemon" - _ "github.com/takama/daemon" ) const ( @@ -22,12 +20,10 @@ const ( description = "Google Dynamic DNS Client Daemon" ) -// dependencies that are NOT required by the service, but might be used var dependencies = []string{"dummy.service"} var stdlog, errlog *log.Logger -// Service has embedded daemon type Service struct { daemon.Daemon } @@ -83,34 +79,34 @@ func updateIP(configFile *string) { if err == nil { gd := ddns.GoogleDDNS{} for key, host := range y.Gddns { - fmt.Println("Updating for: ", key) + stdlog.Println("Updating for: ", key) hostParams := host["params"] gd.SetHost(&hostParams) status, err := gd.UpdateDDNSIp() if err != nil { - fmt.Println(err.Error()) + errlog.Println(err.Error()) } else { if strings.Contains(status, "success") { - fmt.Println("DNS Updated successfully.") + stdlog.Println("DNS Updated successfully.") } else if strings.Contains(status, "nochg") { - fmt.Println("No Change") + stdlog.Println("No Change") } else { // DNS Update failed, log and stop processing current host // TODO: Stop further DNS update attempts to ensure google is not blocking the client - fmt.Println(status, common.DDNSStatusMap[status]) + stdlog.Println(status, common.DDNSStatusMap[status]) } } } } else { - fmt.Println("Error reading configuration :: ", err) + errlog.Println("Error reading configuration :: ", err) } } func main() { - //fmt.Println("Google Dynamic DNS Client") + //stdlog.Println("Google Dynamic DNS Client") standalone := flag.Bool("standalone", false, "Run in standalone mode.") configFile := flag.String("config", "gddns.yml", "configuration file path.") @@ -132,6 +128,6 @@ func main() { errlog.Println(status, "\nError: ", err) os.Exit(1) } - fmt.Println(status) + stdlog.Println(status) } } From 76a917b52df628a5a0604d3cab524fad776a2ce6 Mon Sep 17 00:00:00 2001 From: Lakshman Peethani Date: Thu, 2 Jun 2022 23:09:23 +0530 Subject: [PATCH 4/4] fixed github actions issue --- .github/workflows/build.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f91b5a2..0f346c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,16 +18,17 @@ jobs: with: go-version: 1.18 - - name: Generate build files - uses: thatisuday/go-cross-build@v1 - with: - platforms: 'linux/amd64, darwin/amd64, darwin/arm64, windows/amd64' - package: 'demo' - name: 'program' - compress: 'true' - dest: 'dist' - # - name: Build - # run: go build -v ./... + # - name: Generate build files + # uses: thatisuday/go-cross-build@v1 + # with: + # platforms: 'linux/amd64, darwin/amd64, darwin/arm64, windows/amd64' + # package: 'demo' + # name: 'program' + # compress: 'true' + # dest: 'dist' + + - name: Build + run: go build -v ./... # - name: Test # run: go test -v ./...