WIP
This commit is contained in:
parent
0ed762638a
commit
05c98a9adb
14
README.md
14
README.md
|
@ -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
25
main.go
|
@ -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
|
||||
|
|
132
pkg/http/main.go
132
pkg/http/main.go
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue