mirror of
https://github.com/qdm12/ddns-updater.git
synced 2026-04-05 08:54:09 -04:00
@@ -41,6 +41,7 @@
|
||||
- OpenDNS
|
||||
- OVH
|
||||
- Selfhost.de
|
||||
- [Spdyn](spdyn.de)
|
||||
- Strato.de
|
||||
- **Want more?** [Create an issue for it](https://github.com/qdm12/ddns-updater/issues/new/choose)!
|
||||
- Web User interface
|
||||
@@ -152,6 +153,7 @@ Check the documentation for your DNS provider:
|
||||
- [OpenDNS](https://github.com/qdm12/ddns-updater/blob/master/docs/opendns.md)
|
||||
- [OVH](https://github.com/qdm12/ddns-updater/blob/master/docs/ovh.md)
|
||||
- [Selfhost.de](https://github.com/qdm12/ddns-updater/blob/master/docs/selfhost.de.md)
|
||||
- [Spdyn](https://github.com/qdm12/ddns-updater/blob/master/docs/spdyn.md)
|
||||
- [Strato.de](https://github.com/qdm12/ddns-updater/blob/master/docs/strato.md)
|
||||
|
||||
Note that:
|
||||
|
||||
39
docs/spdyn.md
Normal file
39
docs/spdyn.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Spdyn.de
|
||||
|
||||
## Configuration
|
||||
|
||||
### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"settings": [
|
||||
{
|
||||
"provider": "spdyn",
|
||||
"domain": "domain.com",
|
||||
"host": "@",
|
||||
"user": "user",
|
||||
"password": "password",
|
||||
"token": "token",
|
||||
"ip_version": "ipv4"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Compulsory parameters
|
||||
|
||||
- `"domain"`
|
||||
- `"host"` is your host and can be a subdomain or `"@"`
|
||||
|
||||
#### Using user and password
|
||||
|
||||
- `"user"` is the name of a user who can update this host
|
||||
- `"password"` is the password of a user who can update this host
|
||||
|
||||
#### Using update tokens
|
||||
|
||||
- `"token"` is your update token
|
||||
|
||||
### Optional parameters
|
||||
|
||||
- `"ip_version"` can be `ipv4` (A records) or `ipv6` (AAAA records), defaults to `ipv4 or ipv6`
|
||||
@@ -28,6 +28,7 @@ const (
|
||||
OPENDNS models.Provider = "opendns"
|
||||
OVH models.Provider = "ovh"
|
||||
SELFHOSTDE models.Provider = "selfhost.de"
|
||||
SPDYN models.Provider = "spdyn"
|
||||
STRATO models.Provider = "strato"
|
||||
)
|
||||
|
||||
@@ -57,6 +58,7 @@ func ProviderChoices() []models.Provider {
|
||||
OVH,
|
||||
OPENDNS,
|
||||
SELFHOSTDE,
|
||||
SPDYN,
|
||||
STRATO,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +156,8 @@ func makeSettingsFromObject(common commonSettings, rawSettings json.RawMessage,
|
||||
settingsConstructor = settings.NewDyn
|
||||
case constants.SELFHOSTDE:
|
||||
settingsConstructor = settings.NewSelfhostde
|
||||
case constants.SPDYN:
|
||||
settingsConstructor = settings.NewSpdyn
|
||||
case constants.STRATO:
|
||||
settingsConstructor = settings.NewStrato
|
||||
case constants.OVH:
|
||||
|
||||
159
internal/settings/spdyn.go
Normal file
159
internal/settings/spdyn.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/models"
|
||||
"github.com/qdm12/ddns-updater/internal/regex"
|
||||
"github.com/qdm12/ddns-updater/pkg/publicip/ipversion"
|
||||
)
|
||||
|
||||
type spdyn struct {
|
||||
domain string
|
||||
host string
|
||||
ipVersion ipversion.IPVersion
|
||||
user string
|
||||
password string
|
||||
token string
|
||||
// useProviderIP bool
|
||||
}
|
||||
|
||||
func NewSpdyn(data json.RawMessage, domain, host string, ipVersion ipversion.IPVersion,
|
||||
_ regex.Matcher) (s Settings, err error) {
|
||||
extraSettings := struct {
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
Token string `json:"token"`
|
||||
// UseProviderIP bool `json:"provider_ip"`
|
||||
}{}
|
||||
if err := json.Unmarshal(data, &extraSettings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spdyn := &spdyn{
|
||||
domain: domain,
|
||||
host: host,
|
||||
ipVersion: ipVersion,
|
||||
user: extraSettings.User,
|
||||
password: extraSettings.Password,
|
||||
token: extraSettings.Token,
|
||||
// useProviderIP: extraSettings.UseProviderIP,
|
||||
}
|
||||
if err := spdyn.isValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return spdyn, nil
|
||||
}
|
||||
|
||||
func (s *spdyn) isValid() error {
|
||||
if len(s.token) > 0 {
|
||||
return nil
|
||||
}
|
||||
switch {
|
||||
case len(s.user) == 0:
|
||||
return ErrEmptyUsername
|
||||
case len(s.password) == 0:
|
||||
return ErrEmptyPassword
|
||||
case s.host == "*":
|
||||
return ErrHostWildcard
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *spdyn) String() string {
|
||||
return fmt.Sprintf("[domain: %s | host: %s | provider: Spdyn]", s.domain, s.host)
|
||||
}
|
||||
|
||||
func (s *spdyn) Domain() string {
|
||||
return s.domain
|
||||
}
|
||||
|
||||
func (s *spdyn) Host() string {
|
||||
return s.host
|
||||
}
|
||||
|
||||
func (s *spdyn) IPVersion() ipversion.IPVersion {
|
||||
return s.ipVersion
|
||||
}
|
||||
|
||||
func (s *spdyn) Proxied() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *spdyn) BuildDomainName() string {
|
||||
return buildDomainName(s.host, s.domain)
|
||||
}
|
||||
|
||||
func (s *spdyn) HTML() models.HTMLRow {
|
||||
return models.HTMLRow{
|
||||
Domain: models.HTML(fmt.Sprintf("<a href=\"http://%s\">%s</a>", s.BuildDomainName(), s.BuildDomainName())),
|
||||
Host: models.HTML(s.Host()),
|
||||
Provider: "<a href=\"https://spdyn.com/\">Spdyn DNS</a>",
|
||||
IPVersion: models.HTML(s.ipVersion),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *spdyn) Update(ctx context.Context, client *http.Client, ip net.IP) (newIP net.IP, err error) {
|
||||
// see https://wiki.securepoint.de/SPDyn/Variablen
|
||||
u := url.URL{
|
||||
Scheme: "https",
|
||||
Host: "update.spdyn.de",
|
||||
Path: "/nic/update",
|
||||
}
|
||||
values := url.Values{}
|
||||
values.Set("hostname", s.BuildDomainName())
|
||||
values.Set("myip", ip.String())
|
||||
if len(s.token) > 0 {
|
||||
values.Set("user", s.BuildDomainName())
|
||||
values.Set("passport", s.token)
|
||||
} else {
|
||||
values.Set("user", s.user)
|
||||
values.Set("passport", s.password)
|
||||
}
|
||||
u.RawQuery = values.Encode()
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
setUserAgent(request)
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
b, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrUnmarshalResponse, err)
|
||||
}
|
||||
bodyString := string(b)
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("%w: %d: %s",
|
||||
ErrBadHTTPStatus, response.StatusCode, bodyDataToSingleLine(bodyString))
|
||||
}
|
||||
|
||||
switch bodyString {
|
||||
case abuse, "numhost":
|
||||
return nil, ErrAbuse
|
||||
case badauth, "!yours":
|
||||
return nil, ErrAuth
|
||||
case "good":
|
||||
return ip, nil
|
||||
case notfqdn:
|
||||
return nil, fmt.Errorf("%w: not fqdn", ErrBadRequest)
|
||||
case "nochg":
|
||||
return ip, nil
|
||||
case "nohost", "fatal":
|
||||
return nil, ErrHostnameNotExists
|
||||
default:
|
||||
return nil, fmt.Errorf("%w: %s", ErrUnknownResponse, s)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user