This commit is contained in:
DataHearth 2021-03-15 08:31:47 +01:00
parent 0ed762638a
commit 05c98a9adb
No known key found for this signature in database
GPG Key ID: E88FD356ACC5F3C4
7 changed files with 170 additions and 167 deletions

View File

@ -1,5 +1,17 @@
# DDNS Client
## How to install DDNS-CLIENT
Simply run the command `go get github.com/datahearth/ddnsclient`
## Run the client
You have 2 options to run the DDNS client.
You can either run it as a docker container:
`PENDING...`
Or as binary executable:
`PENDING...`
## Supported providers
- OVH (list of available [regions](https://github.com/ovh/php-ovh/#supported-apis))
- OVH (list of available [regions](https://github.com/ovh/php-ovh/#supported-apis). TO BE CHECKED HOW TO SHIT WORKS)

25
main.go
View File

@ -1,31 +1,30 @@
package ddnsclient
import (
"github.com/datahearth/ddnsclient/pkg/http"
"time"
"github.com/datahearth/ddnsclient/pkg/providers/ovh"
"github.com/datahearth/ddnsclient/pkg/watcher"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
// Start create a new instance of ddns-client
func Start(logger logrus.FieldLogger) error {
ddnsHTTP, err := http.NewHTTP(logger)
if err != nil {
return err
}
ovh, err := ovh.NewOVH(logger)
if err != nil {
return err
}
check := make(chan bool)
w, err := watcher.NewWatcher(logger, ovh, viper.GetString("web-ip"))
if err != nil {
return err
}
c := make(chan bool)
go w.Run(c)
for {
select {
case <-check:
case <-c:
break
}
}
return nil

View File

@ -1,132 +0,0 @@
package http
import (
"io/ioutil"
"net"
h "net/http"
"github.com/datahearth/ddnsclient/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
// HTTP is the base interface to interact with websites
type HTTP interface {
CheckIPAddr(addr string) (bool, error)
GetServerIP() (string, error)
GetSubdomainIP(addr string) (string, error)
RetrieveSubdomainIP(addr string) error
RetrieveServerIP() error
}
type http struct {
logger logrus.FieldLogger
serverIP string
subdomainIP string
webIP string
}
// NewHTTP instanciate a new http implementation
func NewHTTP(logger logrus.FieldLogger) (HTTP, error) {
if logger == nil {
return nil, utils.ErrNilLogger
}
logger = logger.WithField("package", "http")
webIP := viper.GetString("web-ip")
if webIP == "" {
logger.Infoln("web-ip field not set in config. Using default")
webIP = "http://dynamicdns.park-your-domain.com/getip"
}
return &http{
logger: logger,
webIP: webIP,
}, nil
}
// RetrieveServerIP will use the defined web-ip service to get the server public address and save it to the struct
func (http *http) RetrieveServerIP() error {
resp, err := h.Get(http.webIP)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return utils.ErrWrongStatusCode
}
d, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
http.serverIP = string(d)
return nil
}
// GetServerIP will return the IP addr of the server.
// If you haven't triggered the function before manually or with CheckIPAddr,
// it'll trigger the RetrieveServerIP function and save it. Then, it'll return the IP
func (http *http) GetServerIP() (string, error) {
if http.serverIP == "" {
if err := http.RetrieveServerIP(); err != nil {
return "", err
}
}
return http.serverIP, nil
}
// RetrieveSubdomainIP will retrieve the subdomain IP with a HEAD request then save it to the struct
func (http *http) RetrieveSubdomainIP(addr string) error {
resp, err := h.Head(addr)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return utils.ErrWrongStatusCode
}
h, _, err := net.SplitHostPort(resp.Request.RemoteAddr)
if err != nil {
return err
}
http.subdomainIP = h
return nil
}
// GetSubdomainIP will return the IP addr of the subdomain.
// If you haven't triggered the function before manually or with CheckIPAddr,
// it'll trigger the RetrieveSubdomainIP function and save it. Then, it'll return the IP
func (http *http) GetSubdomainIP(addr string) (string, error) {
if http.subdomainIP == "" {
if err := http.RetrieveSubdomainIP(addr); err != nil {
return "", err
}
}
return http.subdomainIP, nil
}
// CheckIPAddr will get both ip addr (subdomain from addr and server) and compare it.
// If one of them is missing, it'll retrieve it and then save it
func (http *http) CheckIPAddr(addr string) (bool, error) {
srvIP, err := http.GetServerIP()
if err != nil {
return false, err
}
subIP, err := http.GetSubdomainIP(addr)
if err != nil {
return false, err
}
if srvIP != subIP {
return false, nil
}
return true, nil
}

73
pkg/subdomain/main.go Normal file
View File

@ -0,0 +1,73 @@
package subdomain
import (
"net"
h "net/http"
"github.com/datahearth/ddnsclient/pkg/utils"
"github.com/sirupsen/logrus"
)
// HTTP is the base interface to interact with websites
type Subdomain interface {
CheckIPAddr(srvIP string) (bool, error)
GetSubdomainIP() string
retrieveSubdomainIP() error
}
type subdomain struct {
logger logrus.FieldLogger
subdomainAddr string
ip string
}
// NewSubdomain instanciate a new http implementation
func NewSubdomain(logger logrus.FieldLogger, subdomainAddr string) (Subdomain, error) {
if logger == nil {
return nil, utils.ErrNilLogger
}
logger = logger.WithField("package", "http")
return &subdomain{
logger: logger,
subdomainAddr: subdomainAddr,
}, nil
}
// RetrieveSubdomainIP will retrieve the subdomain IP with a HEAD request
func (sd *subdomain) retrieveSubdomainIP() error {
resp, err := h.Head(sd.subdomainAddr)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return utils.ErrWrongStatusCode
}
h, _, err := net.SplitHostPort(resp.Request.RemoteAddr)
if err != nil {
return err
}
sd.ip = h
return nil
}
// CheckIPAddr will compare the srvIP passed in parameter and the subIP retrieved from the head request
func (sd *subdomain) CheckIPAddr(srvIP string) (bool, error) {
if err := sd.retrieveSubdomainIP(); err != nil {
return false, err
}
if srvIP != sd.ip {
return false, nil
}
return true, nil
}
func (sd *subdomain) GetSubdomainIP() string {
return sd.ip
}

View File

@ -1,10 +0,0 @@
package utils
func AggregateSubdomains(subdomains []string, domain string) []string {
agdSub := make([]string, len(subdomains))
for _, sd := range subdomains {
agdSub = append(agdSub, sd+"."+domain)
}
return agdSub
}

View File

@ -1,6 +1,9 @@
package utils
import (
"io/ioutil"
"net/http"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
@ -50,3 +53,32 @@ func SetupLogger(logger *logrus.Logger) {
DisableTimestamp: timestamp,
})
}
func AggregateSubdomains(subdomains []string, domain string) []string {
agdSub := make([]string, len(subdomains))
for _, sd := range subdomains {
agdSub = append(agdSub, sd+"."+domain)
}
return agdSub
}
// RetrieveServerIP will use the defined web-ip service to get the server public address and save it to the struct
func RetrieveServerIP(webIP) (string, error) {
// * retrieve client's server IP
resp, err := http.Get(webIP)
if err != nil {
return "", err
}
if resp.StatusCode != 200 {
return "", ErrWrongStatusCode
}
// * get ip from body
d, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(d), nil
}

View File

@ -1,47 +1,76 @@
package watcher
import (
"github.com/datahearth/ddnsclient/pkg/http"
"github.com/datahearth/ddnsclient/pkg/providers"
"github.com/datahearth/ddnsclient/pkg/subdomain"
"github.com/datahearth/ddnsclient/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
type Watcher interface {
Run() error
Run(chan bool) error
}
type watcher struct {
logger logrus.FieldLogger
provider providers.Provider
http http.HTTP
subdomains []string
subdomains []subdomain.Subdomain
domain string
webIP string
}
func NewWatcher(logger logrus.FieldLogger, provider providers.Provider, http http.HTTP) (Watcher, error) {
func NewWatcher(logger logrus.FieldLogger, provider providers.Provider, webIP string) (Watcher, error) {
if logger == nil {
return nil, utils.ErrNilLogger
}
if provider == nil {
return nil, ErrNilProvider
}
if http == nil {
return nil, ErrNilHTTP
if webIP == "" {
webIP = "http://dynamicdns.park-your-domain.com/getip"
}
domain := viper.GetStringMap("watcher")["domain"].(string)
subdomains := utils.AggregateSubdomains(viper.GetStringMap("watcher")["subdomains"].([]string), domain)
sbs := utils.AggregateSubdomains(viper.GetStringMap("watcher")["subdomains"].([]string), domain)
subdomains := make([]subdomain.Subdomain, len(sbs))
for _, sd := range sbs {
sub, err := subdomain.NewSubdomain(logger, sd)
if err != nil {
return nil, err
}
subdomains = append(subdomains, sub)
}
return &watcher{
logger: logger,
provider: provider,
http: http,
domain: domain,
subdomains: subdomains,
webIP: webIP,
}, nil
}
func (w *watcher) Run() error {
return nil
func (w *watcher) Run(close chan bool) error {
for {
select {
case <-close:
return nil
default:
srvIP, err := utils.RetrieveServerIP(w.webIP)
if err != nil {
return err
}
for _, sd := range w.subdomains {
ok, err := sd.CheckIPAddr(srvIP)
if err != nil {
return err
}
if !ok {
w.provider.UpdateIP(sd.GetSubdomainIP(), srvIP)
}
}
}
}
}