mirror of
https://github.com/qdm12/ddns-updater.git
synced 2026-04-22 09:02:44 -04:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4e1cca222 | ||
|
|
79efca2bf4 | ||
|
|
f17be83112 | ||
|
|
2a9e41c646 | ||
|
|
8664aa0e5c | ||
|
|
4c840f4bb6 | ||
|
|
7230fea962 | ||
|
|
8aa6aba8b7 | ||
|
|
1d8690fb14 | ||
|
|
2922d441d2 | ||
|
|
607ca8f0b8 |
3
.github/workflows/configs/mlc-config.json
vendored
3
.github/workflows/configs/mlc-config.json
vendored
@@ -26,6 +26,9 @@
|
||||
},
|
||||
{
|
||||
"pattern": "https://github.com/qdm12/ddns-updater/pkgs/container/ddns-updater"
|
||||
},
|
||||
{
|
||||
"pattern": "^https://www.duckdns.org/$"
|
||||
}
|
||||
],
|
||||
"timeout": "20s",
|
||||
|
||||
12
README.md
12
README.md
@@ -30,6 +30,17 @@ Program to keep DNS A and/or AAAA records updated for multiple DNS providers
|
||||
[](LICENSE)
|
||||

|
||||
|
||||
## Versioned documentation
|
||||
|
||||
This readme and the [docs/](docs/) directory are **versioned** to match the program version:
|
||||
|
||||
| Version | Readme link | Docs link |
|
||||
| --- | --- | --- |
|
||||
| Latest | [README](https://github.com/qdm12/ddns-updater/blob/master/README.md) | [docs/](https://github.com/qdm12/ddns-updater/tree/master/docs) |
|
||||
| `v2.7` | [README](https://github.com/qdm12/ddns-updater/blob/v2.7.1/README.md) | [docs/](https://github.com/qdm12/ddns-updater/blob/v2.7.1/docs) |
|
||||
| `v2.6` | [README](https://github.com/qdm12/ddns-updater/blob/v2.6.1/README.md) | [docs/](https://github.com/qdm12/ddns-updater/blob/v2.6.1/docs) |
|
||||
| `v2.5` | [README](https://github.com/qdm12/ddns-updater/blob/v2.5/README.md) | [docs/](https://github.com/qdm12/ddns-updater/blob/v2.5/docs) |
|
||||
|
||||
## Features
|
||||
|
||||
- Available as a Docker image [`qmcgaw/ddns-updater`](https://hub.docker.com/r/qmcgaw/ddns-updater) and [`ghcr.io/qdm12/ddns-updater`]((https://github.com/qdm12/ddns-updater/pkgs/container/ddns-updater))
|
||||
@@ -294,7 +305,6 @@ You can otherwise customize it with the following:
|
||||
- `ipify` using [https://api64.ipify.org](https://api64.ipify.org)
|
||||
- `ifconfig` using [https://ifconfig.io/ip](https://ifconfig.io/ip)
|
||||
- `ipinfo` using [https://ipinfo.io/ip](https://ipinfo.io/ip)
|
||||
- `google` using [https://domains.google.com/checkip](https://domains.google.com/checkip)
|
||||
- `spdyn` using [https://checkip.spdyn.de](https://checkip.spdyn.de/)
|
||||
- `ipleak` using [https://ipleak.net/json](https://ipleak.net/json)
|
||||
- `icanhazip` using [https://icanhazip.com](https://icanhazip.com)
|
||||
|
||||
@@ -262,7 +262,7 @@ func _main(ctx context.Context, reader *reader.Reader, args []string, logger log
|
||||
}
|
||||
|
||||
func printSplash(buildInfo models.BuildInformation) {
|
||||
announcementExp, err := time.Parse(time.RFC3339, "2023-07-15T00:00:00Z")
|
||||
announcementExp, err := time.Parse(time.RFC3339, "2024-10-15T00:00:00Z")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -273,7 +273,7 @@ func printSplash(buildInfo models.BuildInformation) {
|
||||
Version: buildInfo.Version,
|
||||
Commit: buildInfo.Commit,
|
||||
BuildDate: buildInfo.Date,
|
||||
Announcement: "Public IP dns provider GOOGLE, see https://github.com/qdm12/ddns-updater/issues/492",
|
||||
Announcement: "Public IP http provider GOOGLE is no longer working",
|
||||
AnnounceExp: announcementExp,
|
||||
// Sponsor information
|
||||
PaypalUser: "qmcgaw",
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
"provider": "dondominio",
|
||||
"domain": "domain.com",
|
||||
"host": "@",
|
||||
"name": "something",
|
||||
"username": "username",
|
||||
"key": "key",
|
||||
"ip_version": "ipv4",
|
||||
@@ -25,7 +24,6 @@
|
||||
|
||||
- `"domain"`
|
||||
- `"host"` is the subdomain to update which can be `@`, `*` or a subdomain
|
||||
- `"name"` is the name of the service/hosting
|
||||
- `"username"`
|
||||
- `"password"`
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
### Compulsory parameters
|
||||
|
||||
- `"host"` is the full FQDN of your ddns address. sample.goip.de or something.goip.it
|
||||
- `"host"` is the host of your domain, for example `"example"` for `example.goip.de`.
|
||||
- `"username"` is your goip.de username listed under "Routers"
|
||||
- `"password"` is your router account password
|
||||
|
||||
|
||||
4
go.mod
4
go.mod
@@ -3,14 +3,14 @@ module github.com/qdm12/ddns-updater
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/breml/rootcerts v0.2.17
|
||||
github.com/breml/rootcerts v0.2.18
|
||||
github.com/chmike/domain v1.0.1
|
||||
github.com/containrrr/shoutrrr v0.8.0
|
||||
github.com/go-chi/chi/v5 v5.0.12
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/miekg/dns v1.1.61
|
||||
github.com/qdm12/goservices v0.1.0
|
||||
github.com/qdm12/gosettings v0.4.1
|
||||
github.com/qdm12/gosettings v0.4.4-rc1
|
||||
github.com/qdm12/gosplash v0.1.0
|
||||
github.com/qdm12/gotree v0.2.0
|
||||
github.com/qdm12/log v0.1.0
|
||||
|
||||
8
go.sum
8
go.sum
@@ -1,7 +1,7 @@
|
||||
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
||||
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
github.com/breml/rootcerts v0.2.17 h1:0/M2BE2Apw0qEJCXDOkaiu7d5Sx5ObNfe1BkImJ4u1I=
|
||||
github.com/breml/rootcerts v0.2.17/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/breml/rootcerts v0.2.18 h1:KjZaNT7AX/akUjzpStuwTMQs42YHlPyc6NmdwShVba0=
|
||||
github.com/breml/rootcerts v0.2.18/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/chmike/domain v1.0.1 h1:ug6h3a7LLAfAecBAysbCXWxP1Jo8iBKWNVDxcs1BNzA=
|
||||
github.com/chmike/domain v1.0.1/go.mod h1:h558M2qGKpYRUxHHNyey6puvXkZBjvjmseOla/d1VGQ=
|
||||
github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec=
|
||||
@@ -42,8 +42,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/qdm12/goservices v0.1.0 h1:9sODefm/yuIGS7ynCkEnNlMTAYn9GzPhtcK4F69JWvc=
|
||||
github.com/qdm12/goservices v0.1.0/go.mod h1:/JOFsAnHFiSjyoXxa5FlfX903h20K5u/3rLzCjYVMck=
|
||||
github.com/qdm12/gosettings v0.4.1 h1:c7+14jO1Y2kFXBCUfS2+QE2NgwTKfzcdJzGEFRItCI8=
|
||||
github.com/qdm12/gosettings v0.4.1/go.mod h1:uItKwGXibJp2pQ0am6MBKilpjfvYTGiH+zXHd10jFj8=
|
||||
github.com/qdm12/gosettings v0.4.4-rc1 h1:VT+6O6ww3Cn5v5/LgY2zlXoiCkZzbaLDWaA8ufQoOLY=
|
||||
github.com/qdm12/gosettings v0.4.4-rc1/go.mod h1:CPrt2YC4UsURTrslmhxocVhMCW03lIrqdH2hzIf5prg=
|
||||
github.com/qdm12/gosplash v0.1.0 h1:Sfl+zIjFZFP7b0iqf2l5UkmEY97XBnaKkH3FNY6Gf7g=
|
||||
github.com/qdm12/gosplash v0.1.0/go.mod h1:+A3fWW4/rUeDXhY3ieBzwghKdnIPFJgD8K3qQkenJlw=
|
||||
github.com/qdm12/gotree v0.2.0 h1:+58ltxkNLUyHtATFereAcOjBVfY6ETqRex8XK90Fb/c=
|
||||
|
||||
@@ -263,7 +263,12 @@ func (p *PubIP) read(r *reader.Reader, warner Warner) (err error) {
|
||||
copy(httpIPProvidersTemp, p.HTTPIPProviders)
|
||||
p.HTTPIPProviders = make([]string, 0, len(p.HTTPIPProviders))
|
||||
for _, provider := range httpIPProvidersTemp {
|
||||
if provider != "opendns" {
|
||||
switch provider {
|
||||
case "opendns": // no longer available, for a long time
|
||||
case "google": // found no longer working on 2024.09.17
|
||||
warner.Warnf("http provider google will be ignored " +
|
||||
"since it is no longer supported by Google")
|
||||
default:
|
||||
p.HTTPIPProviders = append(p.HTTPIPProviders, provider)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ var (
|
||||
ErrIPv6KeyNotSet = errors.New("IPv6 key is not set")
|
||||
ErrKeyNotSet = errors.New("key is not set")
|
||||
ErrKeyNotValid = errors.New("key is not valid")
|
||||
ErrNameNotSet = errors.New("name is not set")
|
||||
ErrPasswordNotSet = errors.New("password is not set")
|
||||
ErrPasswordNotValid = errors.New("password is not valid")
|
||||
ErrSecretKeyNotSet = errors.New("secret key is not set")
|
||||
|
||||
@@ -24,7 +24,6 @@ type Provider struct {
|
||||
ipv6Suffix netip.Prefix
|
||||
username string
|
||||
key string
|
||||
name string
|
||||
}
|
||||
|
||||
func New(data json.RawMessage, domain, host string,
|
||||
@@ -34,7 +33,6 @@ func New(data json.RawMessage, domain, host string,
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"` // retro-compatibility
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
}{}
|
||||
err = json.Unmarshal(data, &extraSettings)
|
||||
if err != nil {
|
||||
@@ -54,7 +52,6 @@ func New(data json.RawMessage, domain, host string,
|
||||
ipv6Suffix: ipv6Suffix,
|
||||
username: extraSettings.Username,
|
||||
key: extraSettings.Key,
|
||||
name: extraSettings.Name,
|
||||
}
|
||||
err = p.isValid()
|
||||
if err != nil {
|
||||
@@ -69,8 +66,6 @@ func (p *Provider) isValid() error {
|
||||
return fmt.Errorf("%w", errors.ErrUsernameNotSet)
|
||||
case p.key == "":
|
||||
return fmt.Errorf("%w", errors.ErrKeyNotSet)
|
||||
case p.name == "":
|
||||
return fmt.Errorf("%w", errors.ErrNameNotSet)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -41,6 +41,13 @@ func New(data json.RawMessage, domain, host string,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ipVersion == ipversion.IP6 {
|
||||
// Thanks to @NightFurySL2001
|
||||
// See https://github.com/qdm12/ddns-updater/discussions/750
|
||||
extraSettings.UseProviderIP = false
|
||||
}
|
||||
|
||||
p = &Provider{
|
||||
domain: domain,
|
||||
host: host,
|
||||
|
||||
@@ -20,9 +20,6 @@ func (p *Provider) getRecordIDs(ctx context.Context, client *http.Client, record
|
||||
Host: "porkbun.com",
|
||||
Path: "/api/json/v3/dns/retrieveByNameType/" + p.domain + "/" + recordType + "/",
|
||||
}
|
||||
if p.host != "@" && p.host != "*" {
|
||||
u.Path += p.host
|
||||
}
|
||||
|
||||
postRecordsParams := struct {
|
||||
SecretAPIKey string `json:"secretapikey"`
|
||||
@@ -38,7 +35,14 @@ func (p *Provider) getRecordIDs(ctx context.Context, client *http.Client, record
|
||||
return nil, fmt.Errorf("json encoding request data: %w", err)
|
||||
}
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), buffer)
|
||||
encodedRequestURL := u.String()
|
||||
if p.host != "@" {
|
||||
// add host after string-ing the URL to avoid encoding the '*' character,
|
||||
// since Porkbun requires we send the unencoded '*' character.
|
||||
encodedRequestURL += p.host
|
||||
}
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodPost, encodedRequestURL, buffer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating http request: %w", err)
|
||||
}
|
||||
@@ -173,14 +177,11 @@ func (p *Provider) updateRecord(ctx context.Context, client *http.Client,
|
||||
|
||||
// See https://porkbun.com/api/json/v3/documentation#DNS%20Delete%20Records%20by%20Domain,%20Subdomain%20and%20Type
|
||||
func (p *Provider) deleteAliasRecord(ctx context.Context, client *http.Client) (err error) {
|
||||
var subdomain string
|
||||
if p.host != "@" {
|
||||
subdomain = p.host + "."
|
||||
}
|
||||
u := url.URL{
|
||||
Scheme: "https",
|
||||
Host: "porkbun.com",
|
||||
Path: "/api/json/v3/dns/deleteByNameType/" + p.domain + "/ALIAS/" + subdomain,
|
||||
// host is added below after string-ing the URL
|
||||
Path: "/api/json/v3/dns/deleteByNameType/" + p.domain + "/ALIAS/",
|
||||
}
|
||||
postRecordsParams := struct {
|
||||
SecretAPIKey string `json:"secretapikey"`
|
||||
@@ -196,7 +197,14 @@ func (p *Provider) deleteAliasRecord(ctx context.Context, client *http.Client) (
|
||||
return fmt.Errorf("json encoding request data: %w", err)
|
||||
}
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), buffer)
|
||||
encodedRequestURL := u.String()
|
||||
if p.host != "@" {
|
||||
// add host after string-ing the URL to avoid encoding the '*' character,
|
||||
// since Porkbun requires we send the unencoded '*' character.
|
||||
encodedRequestURL += p.host
|
||||
}
|
||||
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodPost, encodedRequestURL, buffer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating http request: %w", err)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func Test_SetProviders(t *testing.T) {
|
||||
expectedSettings settings
|
||||
err error
|
||||
}{
|
||||
"Google": {
|
||||
"OpenDNS": {
|
||||
initialSettings: settings{
|
||||
providers: []Provider{Cloudflare},
|
||||
},
|
||||
|
||||
@@ -25,7 +25,7 @@ func Test_New(t *testing.T) {
|
||||
timeout: 5 * time.Second,
|
||||
ip4or6: &urlsRing{
|
||||
banned: map[int]string{},
|
||||
urls: []string{"https://domains.google.com/checkip"},
|
||||
urls: []string{"https://api64.ipify.org"},
|
||||
},
|
||||
ip4: &urlsRing{
|
||||
banned: map[int]string{},
|
||||
@@ -39,7 +39,7 @@ func Test_New(t *testing.T) {
|
||||
},
|
||||
"with options": {
|
||||
options: []Option{
|
||||
SetProvidersIP(Google),
|
||||
SetProvidersIP(Ifconfig),
|
||||
SetProvidersIP4(Ipify),
|
||||
SetProvidersIP6(Ipify),
|
||||
SetTimeout(time.Second),
|
||||
@@ -49,7 +49,7 @@ func Test_New(t *testing.T) {
|
||||
timeout: time.Second,
|
||||
ip4or6: &urlsRing{
|
||||
banned: map[int]string{},
|
||||
urls: []string{"https://domains.google.com/checkip"},
|
||||
urls: []string{"https://ifconfig.io/ip"},
|
||||
},
|
||||
ip4: &urlsRing{
|
||||
banned: map[int]string{},
|
||||
|
||||
@@ -17,7 +17,7 @@ func Test_integration(t *testing.T) {
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
fetcher, err := New(client, SetProvidersIP(Google))
|
||||
fetcher, err := New(client, SetProvidersIP(Ipify))
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -16,7 +16,7 @@ type settings struct {
|
||||
func newDefaultSettings() settings {
|
||||
const defaultTimeout = 5 * time.Second
|
||||
return settings{
|
||||
providersIP: []Provider{Google},
|
||||
providersIP: []Provider{Ipify},
|
||||
providersIP4: []Provider{Ipify},
|
||||
providersIP6: []Provider{Ipify},
|
||||
timeout: defaultTimeout,
|
||||
|
||||
@@ -29,13 +29,13 @@ func Test_SetProvidersIP(t *testing.T) {
|
||||
expectedSettings settings
|
||||
err error
|
||||
}{
|
||||
"Google": {
|
||||
"Ipify": {
|
||||
initialSettings: settings{
|
||||
providersIP: []Provider{Ifconfig},
|
||||
},
|
||||
providers: []Provider{Google},
|
||||
providers: []Provider{Ipify},
|
||||
expectedSettings: settings{
|
||||
providersIP: []Provider{Google},
|
||||
providersIP: []Provider{Ipify},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
type Provider string
|
||||
|
||||
const (
|
||||
Google Provider = "google"
|
||||
Ifconfig Provider = "ifconfig"
|
||||
Ipify Provider = "ipify"
|
||||
Ipinfo Provider = "ipinfo"
|
||||
@@ -28,7 +27,6 @@ const (
|
||||
|
||||
func ListProviders() []Provider {
|
||||
return []Provider{
|
||||
Google,
|
||||
Ifconfig,
|
||||
Ipify,
|
||||
Ipinfo,
|
||||
@@ -118,8 +116,6 @@ func (provider Provider) url(version ipversion.IPVersion) (url string, ok bool)
|
||||
switch provider {
|
||||
case Ipify:
|
||||
url = "https://api64.ipify.org"
|
||||
case Google:
|
||||
url = "https://domains.google.com/checkip"
|
||||
case Ifconfig:
|
||||
url = "https://ifconfig.io/ip"
|
||||
case Ipinfo:
|
||||
|
||||
@@ -19,7 +19,7 @@ func Test_ListProvidersForVersion(t *testing.T) {
|
||||
}{
|
||||
"ip4or6": {
|
||||
version: ipversion.IP4or6,
|
||||
providers: []Provider{Google, Ifconfig, Ipify, Ipinfo, Spdyn, Ipleak,
|
||||
providers: []Provider{Ifconfig, Ipify, Ipinfo, Spdyn, Ipleak,
|
||||
Icanhazip, Ident, Nnev, Wtfismyip, Seeip, Changeip},
|
||||
},
|
||||
"ip4": {
|
||||
@@ -51,7 +51,7 @@ func Test_ValidateProvider(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
"valid": {
|
||||
provider: Google,
|
||||
provider: Ifconfig,
|
||||
version: ipversion.IP4or6,
|
||||
},
|
||||
"custom url": {
|
||||
@@ -59,9 +59,9 @@ func Test_ValidateProvider(t *testing.T) {
|
||||
version: ipversion.IP4or6,
|
||||
},
|
||||
"invalid for ip version": {
|
||||
provider: Google,
|
||||
provider: Ifconfig,
|
||||
version: ipversion.IP4,
|
||||
err: errors.New(`provider does not support IP version: "google" for version ipv4`),
|
||||
err: errors.New(`provider does not support IP version: "ifconfig" for version ipv4`),
|
||||
},
|
||||
"unknown": {
|
||||
provider: Provider("unknown"),
|
||||
|
||||
Reference in New Issue
Block a user