mirror of
https://github.com/qdm12/ddns-updater.git
synced 2026-07-02 20:12:05 -04:00
feat(provider): add support for all-inkl.com (#309)
This commit is contained in:
28
docs/allinkl.md
Normal file
28
docs/allinkl.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# All-Inkl
|
||||
|
||||
## Configuration
|
||||
|
||||
### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"settings": [
|
||||
{
|
||||
"provider": "allinkl",
|
||||
"domain": "domain.com",
|
||||
"host": "host",
|
||||
"username": "dynXXXXXXX",
|
||||
"password": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Compulsory parameters
|
||||
|
||||
- `"domain"`
|
||||
- `"host"` is your host (subdomain)
|
||||
- `"username"` username (usually starts with dyn followed by numbers)
|
||||
- `"password"` password in plain text
|
||||
|
||||
## Domain setup
|
||||
@@ -5,6 +5,7 @@ import "github.com/qdm12/ddns-updater/internal/models"
|
||||
// All possible provider values.
|
||||
const (
|
||||
Aliyun models.Provider = "aliyun"
|
||||
AllInkl models.Provider = "allinkl"
|
||||
Cloudflare models.Provider = "cloudflare"
|
||||
Dd24 models.Provider = "dd24"
|
||||
DdnssDe models.Provider = "ddnss"
|
||||
@@ -41,6 +42,7 @@ const (
|
||||
func ProviderChoices() []models.Provider {
|
||||
return []models.Provider{
|
||||
Aliyun,
|
||||
AllInkl,
|
||||
Cloudflare,
|
||||
Dd24,
|
||||
DdnssDe,
|
||||
|
||||
179
internal/settings/providers/allinkl/provider.go
Normal file
179
internal/settings/providers/allinkl/provider.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package allinkl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/models"
|
||||
"github.com/qdm12/ddns-updater/internal/settings/constants"
|
||||
"github.com/qdm12/ddns-updater/internal/settings/errors"
|
||||
"github.com/qdm12/ddns-updater/internal/settings/headers"
|
||||
"github.com/qdm12/ddns-updater/internal/settings/utils"
|
||||
"github.com/qdm12/ddns-updater/pkg/publicip/ipversion"
|
||||
"github.com/qdm12/golibs/verification"
|
||||
)
|
||||
|
||||
type provider struct {
|
||||
domain string
|
||||
host string
|
||||
ipVersion ipversion.IPVersion
|
||||
username string
|
||||
password string
|
||||
useProviderIP bool
|
||||
}
|
||||
|
||||
func New(data json.RawMessage, domain, host string,
|
||||
ipVersion ipversion.IPVersion) (p *provider, err error) {
|
||||
extraSettings := struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
UseProviderIP bool `json:"provider_ip"`
|
||||
}{}
|
||||
if err := json.Unmarshal(data, &extraSettings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p = &provider{
|
||||
domain: domain,
|
||||
host: host,
|
||||
ipVersion: ipVersion,
|
||||
username: extraSettings.Username,
|
||||
password: extraSettings.Password,
|
||||
useProviderIP: extraSettings.UseProviderIP,
|
||||
}
|
||||
if err := p.isValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *provider) isValid() error {
|
||||
switch {
|
||||
case p.username == "":
|
||||
return errors.ErrEmptyUsername
|
||||
case p.password == "":
|
||||
return errors.ErrEmptyPassword
|
||||
case p.host == "*":
|
||||
return errors.ErrHostWildcard
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *provider) String() string {
|
||||
return utils.ToString(p.domain, p.host, constants.AllInkl, p.ipVersion)
|
||||
}
|
||||
|
||||
func (p *provider) Domain() string {
|
||||
return p.domain
|
||||
}
|
||||
|
||||
func (p *provider) Host() string {
|
||||
return p.host
|
||||
}
|
||||
|
||||
func (p *provider) IPVersion() ipversion.IPVersion {
|
||||
return p.ipVersion
|
||||
}
|
||||
|
||||
func (p *provider) Proxied() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *provider) BuildDomainName() string {
|
||||
return utils.BuildDomainName(p.host, p.domain)
|
||||
}
|
||||
|
||||
func (p *provider) HTML() models.HTMLRow {
|
||||
return models.HTMLRow{
|
||||
Domain: models.HTML(fmt.Sprintf("<a href=\"http://%s\">%s</a>", p.BuildDomainName(), p.BuildDomainName())),
|
||||
Host: models.HTML(p.Host()),
|
||||
Provider: "<a href=\"https://all-inkl.com/\">ALL-INKL.com</a>",
|
||||
IPVersion: models.HTML(p.ipVersion.String()),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *provider) Update(ctx context.Context, client *http.Client, ip net.IP) (newIP net.IP, err error) {
|
||||
u := url.URL{
|
||||
Scheme: "https",
|
||||
Host: "dyndns.kasserver.com",
|
||||
Path: "/",
|
||||
User: url.UserPassword(p.username, p.password),
|
||||
}
|
||||
values := url.Values{}
|
||||
values.Set("host", utils.BuildURLQueryHostname(p.host, p.domain))
|
||||
if !p.useProviderIP {
|
||||
if ip.To4() == nil { // ipv6
|
||||
values.Set("myip6", ip.String())
|
||||
} else {
|
||||
values.Set("myip", ip.String())
|
||||
}
|
||||
}
|
||||
u.RawQuery = values.Encode()
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", errors.ErrBadRequest, err)
|
||||
}
|
||||
headers.SetUserAgent(request)
|
||||
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", errors.ErrUnsuccessfulResponse, err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
b, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", errors.ErrUnmarshalResponse, err)
|
||||
}
|
||||
s := string(b)
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("%w: %d: %s", errors.ErrBadHTTPStatus, response.StatusCode, utils.ToSingleLine(s))
|
||||
}
|
||||
|
||||
switch s {
|
||||
case "":
|
||||
return nil, errors.ErrNoResultReceived
|
||||
case constants.Nineoneone:
|
||||
return nil, errors.ErrDNSServerSide
|
||||
case constants.Abuse:
|
||||
return nil, errors.ErrAbuse
|
||||
case "!donator":
|
||||
return nil, errors.ErrFeatureUnavailable
|
||||
case constants.Badagent:
|
||||
return nil, errors.ErrBannedUserAgent
|
||||
case constants.Badauth:
|
||||
return nil, errors.ErrAuth
|
||||
case constants.Nohost:
|
||||
return nil, errors.ErrHostnameNotExists
|
||||
}
|
||||
if !strings.Contains(s, "nochg") && !strings.Contains(s, "good") {
|
||||
return nil, fmt.Errorf("%w: %s", errors.ErrUnknownResponse, s)
|
||||
}
|
||||
var ips []string
|
||||
verifier := verification.NewVerifier()
|
||||
if ip.To4() != nil {
|
||||
ips = verifier.SearchIPv4(s)
|
||||
} else {
|
||||
ips = verifier.SearchIPv6(s)
|
||||
}
|
||||
|
||||
if len(ips) == 0 {
|
||||
return nil, errors.ErrNoIPInResponse
|
||||
}
|
||||
|
||||
newIP = net.ParseIP(ips[0])
|
||||
if newIP == nil {
|
||||
return nil, fmt.Errorf("%w: %s", errors.ErrIPReceivedMalformed, ips[0])
|
||||
}
|
||||
if !p.useProviderIP && !ip.Equal(newIP) {
|
||||
return nil, fmt.Errorf("%w: %s", errors.ErrIPReceivedMismatch, newIP.String())
|
||||
}
|
||||
return newIP, nil
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/qdm12/ddns-updater/internal/regex"
|
||||
"github.com/qdm12/ddns-updater/internal/settings/constants"
|
||||
"github.com/qdm12/ddns-updater/internal/settings/providers/aliyun"
|
||||
"github.com/qdm12/ddns-updater/internal/settings/providers/allinkl"
|
||||
"github.com/qdm12/ddns-updater/internal/settings/providers/cloudflare"
|
||||
"github.com/qdm12/ddns-updater/internal/settings/providers/dd24"
|
||||
"github.com/qdm12/ddns-updater/internal/settings/providers/ddnss"
|
||||
@@ -66,6 +67,8 @@ func New(provider models.Provider, data json.RawMessage, domain, host string,
|
||||
switch provider {
|
||||
case constants.Aliyun:
|
||||
return aliyun.New(data, domain, host, ipVersion)
|
||||
case constants.AllInkl:
|
||||
return allinkl.New(data, domain, host, ipVersion)
|
||||
case constants.Cloudflare:
|
||||
return cloudflare.New(data, domain, host, ipVersion, matcher)
|
||||
case constants.Dd24:
|
||||
|
||||
Reference in New Issue
Block a user