fix(ipv6): add JSON IPv6 suffix parameter (#611)

- Remove `IPV6_PREFIX` environment variable (unneeded) and remove associated code
- Update all documentation for each provider supporting IPv6
- Build IPv6 as prefix:suffix when getting it from a public IP source for each record IPv6 suffix parameter
- Automatically disable provider_ip if public ip is IPv6 and IPv6 suffix is set (they are not compatible with each other)
This commit is contained in:
Quentin McGaw
2024-01-29 17:31:07 +01:00
committed by GitHub
parent 25b8e02acc
commit bad0d3aeda
98 changed files with 806 additions and 498 deletions

View File

@@ -73,7 +73,6 @@ ENV \
# Core
CONFIG= \
PERIOD=5m \
IPV6_PREFIX=/128 \
UPDATE_COOLDOWN_PERIOD=5m \
PUBLICIP_FETCHERS=all \
PUBLICIP_HTTP_PROVIDERS=all \

View File

@@ -127,7 +127,6 @@ The program reads the configuration from a JSON object, either from a file or fr
docker run -d -p 8000:8000/tcp -v "$(pwd)"/data:/updater/data qmcgaw/ddns-updater
```
1. ⚠️ If you use IPv6, you might need to set `-e IPV6_PREFIX=/64` (`/64` is your prefix, depending on your ISP)
1. (Optional) You can also set your JSON configuration as a single environment variable line (i.e. `{"settings": [{"provider": "namecheap", ...}]}`), which takes precedence over config.json. Note however that if you don't bind mount the `/updater/data` directory, there won't be a persistent database file `/updater/updates.json` but it will still work.
### Next steps
@@ -224,7 +223,6 @@ Note that:
| --- | --- | --- |
| `CONFIG` | | One line JSON object containing the entire config (takes precedence over config.json file) if specified |
| `PERIOD` | `5m` | Default period of IP address check, following [this format](https://golang.org/pkg/time/#ParseDuration) |
| `IPV6_PREFIX` | `/128` | IPv6 prefix used to mask your public IPv6 address and your record IPv6 address. Ranges from `/0` to `/128` depending on your ISP. |
| `PUBLICIP_FETCHERS` | `all` | Comma separated fetcher types to obtain the public IP address from `http` and `dns` |
| `PUBLICIP_HTTP_PROVIDERS` | `all` | Comma separated providers to obtain the public IP address (ipv4 or ipv6). See the [Public IP section](#public-ip) |
| `PUBLICIPV4_HTTP_PROVIDERS` | `all` | Comma separated providers to obtain the public IPv4 address only. See the [Public IP section](#public-ip) |

View File

@@ -8,7 +8,6 @@ import (
"os/signal"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
_ "time/tzdata"
@@ -248,8 +247,7 @@ func _main(ctx context.Context, reader *reader.Reader, args []string, logger log
updater := update.NewUpdater(db, client, shoutrrrClient, logger)
runner := update.NewRunner(db, updater, ipGetter, config.Update.Period,
ipv6PrefixToBits(config.IPv6.Prefix), config.Update.Cooldown, logger,
resolver, timeNow, hioClient)
config.Update.Cooldown, logger, resolver, timeNow, hioClient)
runnerHandler, runnerCtx, runnerDone := goshutdown.NewGoRoutineHandler("runner")
go runner.Run(runnerCtx, runnerDone)
@@ -326,12 +324,3 @@ func backupRunLoop(ctx context.Context, done chan<- struct{}, backupPeriod time.
}
}
}
func ipv6PrefixToBits(prefix string) (maskBits uint8) {
prefix = strings.TrimPrefix(prefix, "/")
n, err := strconv.Atoi(prefix)
if err != nil {
panic(err) // prefix already validated before
}
return uint8(n)
}

View File

@@ -13,7 +13,8 @@
"host": "@",
"access_key_id": "your access_key_id",
"access_secret": "your access_secret",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -29,5 +30,6 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -13,7 +13,8 @@
"host": "host",
"username": "dynXXXXXXX",
"password": "password",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -29,5 +30,6 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -14,7 +14,8 @@
"host": "@",
"ttl": 600,
"token": "yourtoken",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -36,5 +37,6 @@ See [this issue comment for context](https://github.com/qdm12/ddns-updater/issue
- `"proxied"` can be set to `true` to use the proxy services of Cloudflare
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
Special thanks to @Starttoaster for helping out with the [documentation](https://gist.github.com/Starttoaster/07d568c2a99ad7631dd776688c988326) and testing.

View File

@@ -20,7 +20,8 @@ Feel free to open issues to extend its configuration options.
"ipv4key": "ipv4",
"ipv6key": "ipv6",
"success_regex": "good",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -38,3 +39,4 @@ Feel free to open issues to extend its configuration options.
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.

View File

@@ -12,7 +12,8 @@
"domain": "domain.com",
"host": "@",
"password": "password",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -27,3 +28,4 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.

View File

@@ -15,7 +15,8 @@
"username": "user",
"password": "password",
"dual_stack": false,
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -34,5 +35,6 @@
- if it is `false`, the updates are done using the `ip` parameter and only one IP address can be set (ipv4 or ipv6, whichever is last sent).
- if it is `true`, the updates are done using the `ip` and `ip6` parameters, for IPv4 and IPv6 respectively, and both can be set on the same record
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -13,6 +13,7 @@
"host": "host",
"token": "token",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": false
}
]
@@ -28,6 +29,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -12,7 +12,8 @@
"domain": "domain.com",
"host": "@",
"token": "yourtoken",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -27,5 +28,6 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -14,7 +14,8 @@
"username": "username",
"password": "password",
"provider_ip": true,
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -31,5 +32,6 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -12,7 +12,8 @@
"domain": "domain.com",
"host": "@",
"token": "yourtoken",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -27,5 +28,6 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -14,7 +14,8 @@
"name": "something",
"username": "username",
"key": "key",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -31,6 +32,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -12,7 +12,8 @@
"domain": "domain.com",
"host": "@",
"key": "key",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -27,5 +28,6 @@
- `"host"` is your host and can be a subdomain or `"@"`. It defaults to `"@"`.
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -12,6 +12,7 @@
"host": "host",
"token": "token",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -26,6 +27,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (**NOT** your IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -13,7 +13,8 @@
"host": "@",
"username": "username",
"client_key": "client_key",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -29,5 +30,6 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -15,6 +15,7 @@
"username": "username",
"password": "password",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -31,6 +32,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
- `"group"` specify the Group for which you want to set the IP (will update any domains and subdomains in the same group)

View File

@@ -13,6 +13,7 @@
"host": "@",
"token": "token",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -28,6 +29,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -14,6 +14,7 @@
"username": "username",
"token": "token",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -30,6 +31,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -12,7 +12,8 @@
"domain": "domain.com",
"host": "host",
"token": "token",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -27,6 +28,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -15,7 +15,8 @@ This provider uses Gandi v5 API
"host": "@",
"personal_access_token": "token",
"ttl": 3600,
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -30,6 +31,7 @@ This provider uses Gandi v5 API
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"ttl"` default is `3600`
## Domain setup

View File

@@ -18,7 +18,8 @@
},
"domain": "domain.com",
"host": "@",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -35,3 +36,4 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.

View File

@@ -13,7 +13,8 @@
"host": "@",
"key": "key",
"secret": "secret",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -29,6 +30,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -13,7 +13,8 @@
"host": "@",
"password": "password",
"provider_ip": true,
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -28,6 +29,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -14,7 +14,8 @@
"host": "@",
"ttl": 600,
"token": "yourtoken",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -32,3 +33,4 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.

View File

@@ -14,6 +14,7 @@
"username": "username",
"password": "password",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -30,6 +31,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -13,7 +13,8 @@
"host": "@",
"username": "username",
"password": "password",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -29,5 +30,6 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -12,7 +12,8 @@
"domain": "domain.com",
"host": "@",
"api_key": "api_key",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -27,3 +28,4 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.

View File

@@ -12,7 +12,8 @@
"domain": "domain.com",
"host": "@",
"token": "token",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -27,6 +28,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -13,7 +13,8 @@
"host": "@",
"email": "email",
"token": "token",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -29,6 +30,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -16,7 +16,8 @@
"username": "username",
"token": "token",
"ttl": 300,
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -33,3 +34,4 @@
- `"ttl"` is the time this record can be cached for in seconds. Name.com allows a minimum TTL of 300, or 5 minutes. Name.com defaults to 300 if not provided.
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.

View File

@@ -18,7 +18,8 @@ Also keep in mind, that TTL, Expire, Retry and Refresh values of the given Domai
"api_key": "xxxxx",
"password": "yyyyy",
"customer_number": "111111",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -35,3 +36,4 @@ Also keep in mind, that TTL, Expire, Retry and Refresh values of the given Domai
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.

View File

@@ -13,6 +13,7 @@
"host": "@",
"key": "key",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -28,6 +29,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -14,6 +14,7 @@
"username": "username",
"password": "password",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -30,6 +31,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -12,7 +12,8 @@
"domain": "domain.com",
"username": "username",
"password": "password",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -27,3 +28,4 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.

View File

@@ -14,6 +14,7 @@
"username": "username",
"password": "password",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -30,6 +31,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -14,6 +14,7 @@
"username": "username",
"password": "password",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -42,6 +43,7 @@ The ZoneDNS implementation allows you to update any record name including *.your
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
- `"mode"` select between two modes, OVH's dynamic hosting service (`"dynamic"`) or OVH's API (`"api"`). Default is `"dynamic"`

View File

@@ -13,7 +13,8 @@
"host": "@",
"api_key": "sk1_7d119e3f656b00ae042980302e1425a04163c476efec1833q3cb0w54fc6f5022",
"secret_api_key": "pk1_5299b57125c8f3cdf347d2fe0e713311ee3a1e11f11a14942b26472593e35368",
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -30,6 +31,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
## Domain setup

View File

@@ -14,7 +14,8 @@
"username": "username",
"password": "password",
"provider_ip": true,
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -30,6 +31,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -15,7 +15,8 @@
"password": "servercow_password",
"ttl": 600,
"provider_ip": true,
"ip_version": "ipv4"
"ip_version": "ipv4",
"ipv6_suffix": ""
}
]
}
@@ -32,6 +33,7 @@
- `"ttl"` can be set to an integer value for record TTL in seconds (if not set the default is 120)
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -15,6 +15,7 @@
"password": "password",
"token": "token",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -38,4 +39,5 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (**not IPv6**)automatically when you send an update request, without sending the new IP address detected by the program in the request.

View File

@@ -13,6 +13,7 @@
"host": "@",
"password": "password",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -28,6 +29,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -14,6 +14,7 @@
"email": "email@domain.com",
"password": "password",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -30,6 +31,7 @@
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -20,6 +20,7 @@ set the environment variable as `PERIOD=11m` to check your public IP address and
"username": "username",
"token": "token",
"ip_version": "ipv4",
"ipv6_suffix": "",
"provider_ip": true
}
]
@@ -36,6 +37,7 @@ set the environment variable as `PERIOD=11m` to check your public IP address and
### Optional parameters
- `"ip_version"` can be `ipv4` (A records), or `ipv6` (AAAA records) or `ipv4 or ipv6` (update one of the two, depending on the public ip found). It defaults to `ipv4 or ipv6`.
- `"ipv6_suffix"` is the IPv6 interface indentifier suffix to use. It can be for example `0:0:0:0:72ad:8fbb:a54e:bedd/64`. If left empty, it defaults to no suffix and the raw public IPv6 address obtained is used in the record updating.
- `"provider_ip"` can be set to `true` to let your DNS provider determine your IPv4 address (and/or IPv6 address) automatically when you send an update request, without sending the new IP address detected by the program in the request.
## Domain setup

View File

@@ -1,66 +0,0 @@
package config
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/qdm12/gosettings"
"github.com/qdm12/gosettings/reader"
"github.com/qdm12/gotree"
)
type IPv6 struct {
// Prefix is the IPv6 mask, for example /128
Prefix string
}
func (i *IPv6) setDefaults() {
i.Prefix = gosettings.DefaultComparable(i.Prefix, "/128")
}
func (i IPv6) Validate() (err error) {
err = validateIPv6Prefix(i.Prefix)
if err != nil {
return err
}
return nil
}
var (
ErrIPv6PrefixFormat = errors.New("IPv6 prefix format is incorrect")
)
func validateIPv6Prefix(prefix string) (err error) {
prefix = strings.TrimPrefix(prefix, "/")
const base, bits = 10, 8
_, err = strconv.ParseUint(prefix, base, bits)
if err != nil {
return fmt.Errorf("%w: cannot parse %q as uint8", ErrIPv6PrefixFormat, prefix)
}
const maxBits = 128
if bits > maxBits {
return fmt.Errorf("%w: %d bits cannot be larger than %d",
ErrIPv6PrefixFormat, bits, maxBits)
}
return nil
}
func (i IPv6) String() string {
return i.toLinesNode().String()
}
func (i IPv6) toLinesNode() *gotree.Node {
node := gotree.New("IPv6")
node.Appendf("Prefix: %s", i.Prefix)
return node
}
func (i *IPv6) read(reader *reader.Reader) {
i.Prefix = reader.String("IPV6_PREFIX")
}

View File

@@ -1,56 +0,0 @@
package config
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_validateIPv6Prefix(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
prefixDecimal string
err error
}{
"empty": {
err: fmt.Errorf(`IPv6 prefix format is incorrect: ` +
`cannot parse "" as uint8`),
},
"malformed": {
prefixDecimal: "malformed",
err: fmt.Errorf(`IPv6 prefix format is incorrect: ` +
`cannot parse "malformed" as uint8`),
},
"with leading slash": {
prefixDecimal: "/78",
},
"without leading slash": {
prefixDecimal: "78",
},
"full IPv6 mask": {
prefixDecimal: "/128",
},
"zero IPv6 mask": {
prefixDecimal: "/0",
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
err := validateIPv6Prefix(testCase.prefixDecimal)
if testCase.err != nil {
require.Error(t, err)
assert.Equal(t, testCase.err.Error(), err.Error())
} else {
assert.NoError(t, err)
}
})
}
}

View File

@@ -12,7 +12,6 @@ type Config struct {
Update Update
PubIP PubIP
Resolver Resolver
IPv6 IPv6
Server Server
Health Health
Paths Paths
@@ -26,7 +25,6 @@ func (c *Config) SetDefaults() {
c.Update.setDefaults()
c.PubIP.setDefaults()
c.Resolver.setDefaults()
c.IPv6.setDefaults()
c.Server.setDefaults()
c.Health.SetDefaults()
c.Paths.setDefaults()
@@ -44,7 +42,6 @@ func (c Config) Validate() (err error) {
"update": &c.Update,
"public ip": &c.PubIP,
"resolver": &c.Resolver,
"ipv6": &c.IPv6,
"server": &c.Server,
"health": &c.Health,
"paths": &c.Paths,
@@ -73,7 +70,6 @@ func (c Config) toLinesNode() *gotree.Node {
node.AppendNode(c.Update.toLinesNode())
node.AppendNode(c.PubIP.toLinesNode())
node.AppendNode(c.Resolver.ToLinesNode())
node.AppendNode(c.IPv6.toLinesNode())
node.AppendNode(c.Server.toLinesNode())
node.AppendNode(c.Health.toLinesNode())
node.AppendNode(c.Paths.toLinesNode())
@@ -105,8 +101,6 @@ func (c *Config) Read(reader *reader.Reader,
return fmt.Errorf("reading resolver settings: %w", err)
}
c.IPv6.read(reader)
err = c.Server.read(reader, warner)
if err != nil {
return fmt.Errorf("reading server settings: %w", err)

View File

@@ -33,8 +33,6 @@ func Test_Settings_String(t *testing.T) {
| └── DNS over TLS providers
| └── all
├── Resolver: use Go default resolver
├── IPv6
| └── Prefix: /128
├── Server
| ├── Listening address: :8000
| └── Root URL: /

View File

@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io/fs"
"net/netip"
"os"
"strings"
@@ -20,6 +21,7 @@ type commonSettings struct {
Domain string `json:"domain"`
Host string `json:"host"`
IPVersion string `json:"ip_version"`
IPv6Suffix netip.Prefix `json:"ipv6_suffix,omitempty"`
// Retro values for warnings
IPMethod *string `json:"ip_method,omitempty"`
Delay *uint64 `json:"delay,omitempty"`
@@ -165,10 +167,16 @@ func makeSettingsFromObject(common commonSettings, rawSettings json.RawMessage)
return nil, nil, err
}
if ipVersion != ipversion.IP6 && common.IPv6Suffix.IsValid() {
warnings = append(warnings,
fmt.Sprintf("IPv6 suffix specified as %s but IP version is %s",
common.IPv6Suffix, ipVersion))
}
providers = make([]provider.Provider, len(hosts))
for i, host := range hosts {
providers[i], err = provider.New(providerName, rawSettings, common.Domain,
host, ipVersion)
host, ipVersion, common.IPv6Suffix)
if err != nil {
return nil, warnings, err
}

View File

@@ -64,6 +64,7 @@ type Provider interface {
HTML() models.HTMLRow
Proxied() bool
IPVersion() ipversion.IPVersion
IPv6Suffix() netip.Prefix
Update(ctx context.Context, client *http.Client, ip netip.Addr) (newIP netip.Addr, err error)
}
@@ -71,94 +72,94 @@ var ErrProviderUnknown = errors.New("unknown provider")
//nolint:gocyclo
func New(providerName models.Provider, data json.RawMessage, domain, host string, //nolint:ireturn
ipVersion ipversion.IPVersion) (provider Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (provider Provider, err error) {
switch providerName {
case constants.Aliyun:
return aliyun.New(data, domain, host, ipVersion)
return aliyun.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.AllInkl:
return allinkl.New(data, domain, host, ipVersion)
return allinkl.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Cloudflare:
return cloudflare.New(data, domain, host, ipVersion)
return cloudflare.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Custom:
return custom.New(data, domain, host, ipVersion)
return custom.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Dd24:
return dd24.New(data, domain, host, ipVersion)
return dd24.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.DdnssDe:
return ddnss.New(data, domain, host, ipVersion)
return ddnss.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.DeSEC:
return desec.New(data, domain, host, ipVersion)
return desec.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.DigitalOcean:
return digitalocean.New(data, domain, host, ipVersion)
return digitalocean.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.DNSOMatic:
return dnsomatic.New(data, domain, host, ipVersion)
return dnsomatic.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.DNSPod:
return dnspod.New(data, domain, host, ipVersion)
return dnspod.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.DonDominio:
return dondominio.New(data, domain, host, ipVersion)
return dondominio.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Dreamhost:
return dreamhost.New(data, domain, host, ipVersion)
return dreamhost.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.DuckDNS:
return duckdns.New(data, domain, host, ipVersion)
return duckdns.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Dyn:
return dyn.New(data, domain, host, ipVersion)
return dyn.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Dynu:
return dynu.New(data, domain, host, ipVersion)
return dynu.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.DynV6:
return dynv6.New(data, domain, host, ipVersion)
return dynv6.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.EasyDNS:
return easydns.New(data, domain, host, ipVersion)
return easydns.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.FreeDNS:
return freedns.New(data, domain, host, ipVersion)
return freedns.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Gandi:
return gandi.New(data, domain, host, ipVersion)
return gandi.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.GCP:
return gcp.New(data, domain, host, ipVersion)
return gcp.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.GoDaddy:
return godaddy.New(data, domain, host, ipVersion)
return godaddy.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.HE:
return he.New(data, domain, host, ipVersion)
return he.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Hetzner:
return hetzner.New(data, domain, host, ipVersion)
return hetzner.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Infomaniak:
return infomaniak.New(data, domain, host, ipVersion)
return infomaniak.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.INWX:
return inwx.New(data, domain, host, ipVersion)
return inwx.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Ionos:
return ionos.New(data, domain, host, ipVersion)
return ionos.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Linode:
return linode.New(data, domain, host, ipVersion)
return linode.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.LuaDNS:
return luadns.New(data, domain, host, ipVersion)
return luadns.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Namecheap:
return namecheap.New(data, domain, host)
case constants.NameCom:
return namecom.New(data, domain, host, ipVersion)
return namecom.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Netcup:
return netcup.New(data, domain, host, ipVersion)
return netcup.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Njalla:
return njalla.New(data, domain, host, ipVersion)
return njalla.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.NoIP:
return noip.New(data, domain, host, ipVersion)
return noip.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.NowDNS:
return nowdns.New(data, domain, ipVersion)
return nowdns.New(data, domain, ipVersion, ipv6Suffix)
case constants.OpenDNS:
return opendns.New(data, domain, host, ipVersion)
return opendns.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.OVH:
return ovh.New(data, domain, host, ipVersion)
return ovh.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Porkbun:
return porkbun.New(data, domain, host, ipVersion)
return porkbun.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.SelfhostDe:
return selfhostde.New(data, domain, host, ipVersion)
return selfhostde.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Servercow:
return servercow.New(data, domain, host, ipVersion)
return servercow.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Spdyn:
return spdyn.New(data, domain, host, ipVersion)
return spdyn.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Strato:
return strato.New(data, domain, host, ipVersion)
return strato.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Variomedia:
return variomedia.New(data, domain, host, ipVersion)
return variomedia.New(data, domain, host, ipVersion, ipv6Suffix)
case constants.Zoneedit:
return zoneedit.New(data, domain, host, ipVersion)
return zoneedit.New(data, domain, host, ipVersion, ipv6Suffix)
default:
return nil, fmt.Errorf("%w: %s", ErrProviderUnknown, providerName)
}

View File

@@ -19,13 +19,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
accessKeyID string
accessSecret string
region string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
AccessKeyID string `json:"access_key_id"`
AccessSecret string `json:"access_secret"`
@@ -39,6 +41,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
accessKeyID: extraSettings.AccessKeyID,
accessSecret: extraSettings.AccessSecret,
region: "cn-hangzhou",
@@ -79,6 +82,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -23,13 +23,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -43,6 +45,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
@@ -82,6 +85,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -108,8 +115,9 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("host", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
if ip.Is6() { // ipv6
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
if ip.Is6() {
values.Set("myip6", ip.String())
} else {
values.Set("myip", ip.String())
@@ -171,7 +179,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
newIP = ips[0]
if !p.useProviderIP && ip.Compare(newIP) != 0 {
if !useProviderIP && ip.Compare(newIP) != 0 {
return netip.Addr{}, fmt.Errorf("%w: sent ip %s to update but received %s",
errors.ErrIPReceivedMismatch, ip, newIP)
}

View File

@@ -24,6 +24,7 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
key string
token string
email string
@@ -34,7 +35,8 @@ type Provider struct {
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Key string `json:"key"`
Token string `json:"token"`
@@ -52,6 +54,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
key: extraSettings.Key,
token: extraSettings.Token,
email: extraSettings.Email,
@@ -116,6 +119,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return p.proxied
}

View File

@@ -22,6 +22,7 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
url *url.URL
ipv4Key string
ipv6Key string
@@ -29,7 +30,8 @@ type Provider struct {
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
URL string `json:"url"`
IPv4Key string `json:"ipv4key"`
@@ -50,6 +52,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
url: parsedURL,
ipv4Key: extraSettings.IPv4Key,
ipv6Key: extraSettings.IPv6Key,
@@ -95,6 +98,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -22,12 +22,13 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
password string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Password string `json:"password"`
@@ -41,6 +42,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
}
@@ -74,6 +76,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -101,7 +107,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
values := url.Values{}
values.Set("hostname", p.BuildDomainName())
values.Set("password", p.password)
if p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if useProviderIP {
values.Set("ip", "auto")
} else {
values.Set("ip", ip.String())

View File

@@ -22,6 +22,7 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
dualStack bool
@@ -29,7 +30,8 @@ type Provider struct {
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -44,6 +46,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
dualStack: extraSettings.DualStack,
@@ -84,6 +87,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -111,7 +118,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
values.Set("user", p.username)
values.Set("pwd", p.password)
values.Set("host", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
ipKey := "ip"
if p.dualStack && ip.Is6() { // ipv6 update for dual stack
ipKey = "ip6"

View File

@@ -22,12 +22,14 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
token string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Token string `json:"token"`
UseProviderIP bool `json:"provider_ip"`
@@ -43,6 +45,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
token: extraSettings.Token,
useProviderIP: extraSettings.UseProviderIP,
}
@@ -76,6 +79,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -102,7 +109,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if useProviderIP {
values.Set("myip", ip.String())
}
u.RawQuery = values.Encode()

View File

@@ -21,11 +21,13 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
token string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Token string `json:"token"`
}{}
@@ -37,6 +39,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
token: extraSettings.Token,
}
err = p.isValid()
@@ -69,6 +72,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -23,13 +23,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -43,6 +45,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
@@ -80,6 +83,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return p.host == "all"
}
@@ -106,7 +113,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
User: url.UserPassword(p.username, p.password),
}
values := url.Values{}
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if useProviderIP {
values.Set("myip", ip.String())
}
values.Set("wildcard", "NOCHG")
@@ -172,7 +180,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
newIP = ips[0]
if !p.useProviderIP && ip.Compare(newIP) != 0 {
if !useProviderIP && ip.Compare(newIP) != 0 {
return netip.Addr{}, fmt.Errorf("%w: sent ip %s to update but received %s",
errors.ErrIPReceivedMismatch, ip, newIP)
}

View File

@@ -22,11 +22,13 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
token string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Token string `json:"token"`
}{}
@@ -38,6 +40,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
token: extraSettings.Token,
}
err = p.isValid()
@@ -70,6 +73,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -21,13 +21,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
key string
name string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"` // retro-compatibility
@@ -49,6 +51,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
key: extraSettings.Key,
name: extraSettings.Name,
@@ -88,6 +91,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -22,11 +22,13 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
key string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Key string `json:"key"`
}{}
@@ -41,6 +43,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
key: extraSettings.Key,
}
err = p.isValid()
@@ -76,6 +79,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -22,12 +22,14 @@ import (
type Provider struct {
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
token string
useProviderIP bool
}
func New(data json.RawMessage, _, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Token string `json:"token"`
UseProviderIP bool `json:"provider_ip"`
@@ -39,6 +41,7 @@ func New(data json.RawMessage, _, host string,
p = &Provider{
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
token: extraSettings.Token,
useProviderIP: extraSettings.UseProviderIP,
}
@@ -52,12 +55,11 @@ func New(data json.RawMessage, _, host string,
var tokenRegex = regexp.MustCompile(`^[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}$`)
func (p *Provider) isValid() error {
if !tokenRegex.MatchString(p.token) {
switch {
case !tokenRegex.MatchString(p.token):
return fmt.Errorf("%w: token %q does not match regex %q",
errors.ErrTokenNotValid, p.token, tokenRegex)
}
switch p.host {
case "@", "*":
case p.host == "@", p.host == "*":
return fmt.Errorf("%w: %q is not valid",
errors.ErrHostOnlySubdomain, p.host)
}
@@ -80,6 +82,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -107,7 +113,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
values.Set("verbose", "true")
values.Set("domains", p.host)
values.Set("token", p.token)
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
if ip.Is6() {
values.Set("ipv6", ip.String())
} else {
@@ -156,7 +163,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
return netip.Addr{}, fmt.Errorf("%w", errors.ErrReceivedNoIP)
}
newIP = ips[0]
if !p.useProviderIP && newIP.Compare(ip) != 0 {
if !useProviderIP && newIP.Compare(ip) != 0 {
return netip.Addr{}, fmt.Errorf("%w: sent ip %s to update but received %s",
errors.ErrIPReceivedMismatch, ip, newIP)
}

View File

@@ -22,12 +22,14 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
clientKey string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"` // Retro-compatibility
@@ -47,6 +49,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
clientKey: clientKey,
}
@@ -83,6 +86,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -21,15 +21,17 @@ import (
type Provider struct {
domain string
host string
group string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
useProviderIP bool
group string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -49,6 +51,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
group: extraSettings.Group,
username: extraSettings.Username,
password: extraSettings.Password,
@@ -89,6 +92,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -118,7 +125,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
values.Set("location", p.group)
hostname := utils.BuildDomainName(p.host, p.domain)
values.Set("hostname", hostname)
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
if ip.Is6() {
values.Set("myipv6", ip.String())
} else {

View File

@@ -20,12 +20,14 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
token string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Token string `json:"token"`
UseProviderIP bool `json:"provider_ip"`
@@ -38,6 +40,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
token: extraSettings.Token,
useProviderIP: extraSettings.UseProviderIP,
}
@@ -74,6 +77,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -108,7 +115,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
values.Set("token", p.token)
values.Set("zone", utils.BuildURLQueryHostname(p.host, p.domain))
ipValue := ip.String()
if p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if useProviderIP {
ipValue = "auto"
}
if isIPv4 {

View File

@@ -22,13 +22,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
token string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Token string `json:"token"`
@@ -42,6 +44,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
token: extraSettings.Token,
useProviderIP: extraSettings.UseProviderIP,
@@ -79,6 +82,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -106,7 +113,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
values.Set("myip", ip.String())
}
if p.host == "*" {

View File

@@ -22,11 +22,13 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
token string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Token string `json:"token"`
}{}
@@ -38,6 +40,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
token: extraSettings.Token,
}
err = p.isValid()
@@ -74,6 +77,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) BuildDomainName() string {
return utils.BuildDomainName(p.host, p.domain)
}

View File

@@ -20,8 +20,9 @@ import (
type Provider struct {
domain string
host string
ttl int
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
ttl int
// Authentication, either use the personal access token
// or the deprecated API key.
// See https://api.gandi.net/docs/authentication/
@@ -32,7 +33,8 @@ type Provider struct {
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
PersonalAccessToken string `json:"personal_access_token"`
APIKey string `json:"key"`
@@ -46,6 +48,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
personalAccessToken: extraSettings.PersonalAccessToken,
apiKey: extraSettings.APIKey,
ttl: extraSettings.TTL,
@@ -80,6 +83,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -3,6 +3,7 @@ package gcp
import (
"encoding/json"
"fmt"
"net/netip"
"github.com/qdm12/ddns-updater/internal/models"
"github.com/qdm12/ddns-updater/internal/provider/constants"
@@ -14,14 +15,16 @@ import (
type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
project string
zone string
credentials json.RawMessage
ipVersion ipversion.IPVersion
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
var extraSettings struct {
Project string `json:"project"`
Zone string `json:"zone"`
@@ -37,6 +40,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
project: extraSettings.Project,
zone: extraSettings.Zone,
credentials: extraSettings.Credentials,
@@ -82,6 +86,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -23,12 +23,14 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
key string
secret string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Key string `json:"key"`
Secret string `json:"secret"`
@@ -41,6 +43,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
key: extraSettings.Key,
secret: extraSettings.Secret,
}
@@ -80,6 +83,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -23,12 +23,14 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
password string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Password string `json:"password"`
UseProviderIP bool `json:"provider_ip"`
@@ -41,6 +43,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
}
@@ -74,6 +77,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -101,7 +108,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("hostname", fqdn)
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
values.Set("myip", ip.String())
}
u.RawQuery = values.Encode()
@@ -147,7 +155,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
newIP = ips[0]
if !p.useProviderIP && ip.Compare(newIP) != 0 {
if !useProviderIP && ip.Compare(newIP) != 0 {
return netip.Addr{}, fmt.Errorf("%w: sent ip %s to update but received %s",
errors.ErrIPReceivedMismatch, ip, newIP)
}

View File

@@ -19,13 +19,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
token string
zoneIdentifier string
ttl uint
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Token string `json:"token"`
ZoneIdentifier string `json:"zone_identifier"`
@@ -39,6 +41,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
token: extraSettings.Token,
zoneIdentifier: extraSettings.ZoneIdentifier,
ttl: extraSettings.TTL,
@@ -79,6 +82,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -22,13 +22,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -42,6 +44,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
@@ -81,6 +84,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -107,7 +114,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
values.Set("myip", ip.String())
}
u.RawQuery = values.Encode()
@@ -152,7 +160,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
if err != nil {
return netip.Addr{}, fmt.Errorf("%w: for response %q: %w",
errors.ErrIPReceivedMalformed, ipString, err)
} else if !p.useProviderIP && ip.Compare(newIP) != 0 {
} else if !useProviderIP && ip.Compare(newIP) != 0 {
return netip.Addr{}, fmt.Errorf("%w: sent ip %s to update but received %s",
errors.ErrIPReceivedMismatch, ip, newIP)
}

View File

@@ -22,12 +22,14 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -40,6 +42,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
}
@@ -78,6 +81,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -18,11 +18,13 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
apiKey string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
APIKey string `json:"api_key"`
}{}
@@ -33,6 +35,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
apiKey: extraSettings.APIKey,
}
if err := p.isValid(); err != nil {
@@ -64,6 +67,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -23,11 +23,13 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
token string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Token string `json:"token"`
}{}
@@ -39,6 +41,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
token: extraSettings.Token,
}
err = p.isValid()
@@ -71,6 +74,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -23,12 +23,14 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
email string
token string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Email string `json:"email"`
Token string `json:"token"`
@@ -41,6 +43,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
email: extraSettings.Email,
token: extraSettings.Token,
}
@@ -82,6 +85,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -19,13 +19,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
token string
ttl *uint32
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Token string `json:"token"`
@@ -51,6 +53,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
token: extraSettings.Token,
ttl: extraSettings.TTL,
@@ -73,6 +76,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -15,16 +15,18 @@ import (
)
type Provider struct {
customerNumber string
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
customerNumber string
apiKey string
password string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
var extraSettings struct {
CustomerNumber string `json:"customer_number"`
APIKey string `json:"api_key"`
@@ -39,6 +41,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
customerNumber: extraSettings.CustomerNumber,
apiKey: extraSettings.APIKey,
password: extraSettings.Password,
@@ -82,6 +85,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -20,12 +20,14 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
key string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Key string `json:"key"`
UseProviderIP bool `json:"provider_ip"`
@@ -38,6 +40,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
key: extraSettings.Key,
useProviderIP: extraSettings.UseProviderIP,
}
@@ -71,6 +74,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -98,7 +105,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
values.Set("h", utils.BuildURLQueryHostname(p.host, p.domain))
values.Set("k", p.key)
updatingIP6 := ip.Is6()
if p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if useProviderIP {
values.Set("auto", "")
} else {
if updatingIP6 {
@@ -147,7 +155,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
newIP, err = netip.ParseAddr(ipString)
if err != nil {
return netip.Addr{}, fmt.Errorf("%w: %w", errors.ErrIPReceivedMalformed, err)
} else if !p.useProviderIP && ip.Compare(newIP) != 0 {
} else if !useProviderIP && ip.Compare(newIP) != 0 {
return netip.Addr{}, fmt.Errorf("%w: sent ip %s to update but received %s",
errors.ErrIPReceivedMismatch, ip, newIP)
}

View File

@@ -23,13 +23,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -43,6 +45,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
@@ -85,6 +88,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -111,7 +118,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
if ip.Is6() {
values.Set("myipv6", ip.String())
} else {
@@ -170,12 +178,12 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
ips = ipextract.IPv6(s)
}
if !p.useProviderIP && len(ips) == 0 {
if !useProviderIP && len(ips) == 0 {
return netip.Addr{}, fmt.Errorf("%w", errors.ErrReceivedNoIP)
}
newIP = ips[0]
if !p.useProviderIP && ip.Compare(newIP) != 0 {
if !useProviderIP && ip.Compare(newIP) != 0 {
return netip.Addr{}, fmt.Errorf("%w: sent ip %s to update but received %s",
errors.ErrIPReceivedMismatch, ip, newIP)
}

View File

@@ -21,13 +21,15 @@ import (
type Provider struct {
domain string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
useProviderIP bool
}
func New(data json.RawMessage, domain string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -40,6 +42,7 @@ func New(data json.RawMessage, domain string,
p = &Provider{
domain: domain,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
@@ -77,6 +80,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -104,7 +111,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
values := url.Values{}
values.Set("hostname", p.domain)
if !p.useProviderIP {
if !p.useProviderIP || (ip.Is6() && p.ipv6Suffix.IsValid()) {
values.Set("myip", ip.String())
}
u.RawQuery = values.Encode()

View File

@@ -22,13 +22,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -42,6 +44,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
@@ -81,6 +84,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -107,7 +114,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
values.Set("myip", ip.String())
}
u.RawQuery = values.Encode()
@@ -141,7 +149,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
newIP, err = netip.ParseAddr(responseIPString)
if err != nil {
return netip.Addr{}, fmt.Errorf("%w: %w", errors.ErrIPReceivedMalformed, err)
} else if !p.useProviderIP && newIP.Compare(ip) != 0 {
} else if !useProviderIP && newIP.Compare(ip) != 0 {
return netip.Addr{}, fmt.Errorf("%w: sent ip %s to update but received %s",
errors.ErrIPReceivedMismatch, ip, newIP)
}

View File

@@ -23,6 +23,7 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
useProviderIP bool
@@ -36,7 +37,8 @@ type Provider struct {
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -61,6 +63,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
@@ -117,6 +120,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -145,7 +152,8 @@ func (p *Provider) updateWithDynHost(ctx context.Context, client *http.Client,
values := url.Values{}
values.Set("system", "dyndns")
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
values.Set("myip", ip.String())
}
u.RawQuery = values.Encode()

View File

@@ -18,14 +18,16 @@ import (
type Provider struct {
domain string
host string
ttl uint
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
ttl uint
apiKey string
secretAPIKey string
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
SecretAPIKey string `json:"secret_api_key"`
APIKey string `json:"api_key"`
@@ -39,6 +41,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
secretAPIKey: extraSettings.SecretAPIKey,
apiKey: extraSettings.APIKey,
ttl: extraSettings.TTL,
@@ -76,6 +79,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -22,13 +22,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -42,6 +44,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
@@ -81,6 +84,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -107,7 +114,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
values.Set("myip", ip.String())
}
u.RawQuery = values.Encode()

View File

@@ -22,13 +22,14 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
password string
useProviderIP bool
ttl uint
}
func New(data json.RawMessage, domain, host string, ipVersion ipversion.IPVersion) (
func New(data json.RawMessage, domain, host string, ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
@@ -45,6 +46,7 @@ func New(data json.RawMessage, domain, host string, ipVersion ipversion.IPVersio
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
@@ -85,6 +87,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -22,6 +22,7 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
user string
password string
token string
@@ -29,7 +30,8 @@ type Provider struct {
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
User string `json:"user"`
Password string `json:"password"`
@@ -44,6 +46,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
user: extraSettings.User,
password: extraSettings.Password,
token: extraSettings.Token,
@@ -88,6 +91,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}

View File

@@ -22,12 +22,14 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
password string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Password string `json:"password"`
UseProviderIP bool `json:"provider_ip"`
@@ -40,6 +42,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
}
@@ -76,6 +79,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -102,7 +109,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
values.Set("myip", ip.String())
}
u.RawQuery = values.Encode()

View File

@@ -22,13 +22,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
email string
password string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Email string `json:"email"`
Password string `json:"password"`
@@ -42,6 +44,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
email: extraSettings.Email,
password: extraSettings.Password,
useProviderIP: extraSettings.UseProviderIP,
@@ -81,6 +84,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -100,7 +107,8 @@ func (p *Provider) HTML() models.HTMLRow {
func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Addr) (newIP netip.Addr, err error) {
host := "dyndns.variomedia.de"
if p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if useProviderIP {
if ip.Is6() {
host = "dyndns6.variomedia.de"
} else {

View File

@@ -23,13 +23,15 @@ type Provider struct {
domain string
host string
ipVersion ipversion.IPVersion
ipv6Suffix netip.Prefix
username string
token string
useProviderIP bool
}
func New(data json.RawMessage, domain, host string,
ipVersion ipversion.IPVersion) (p *Provider, err error) {
ipVersion ipversion.IPVersion, ipv6Suffix netip.Prefix) (
p *Provider, err error) {
extraSettings := struct {
Username string `json:"username"`
Token string `json:"token"`
@@ -43,6 +45,7 @@ func New(data json.RawMessage, domain, host string,
domain: domain,
host: host,
ipVersion: ipVersion,
ipv6Suffix: ipv6Suffix,
username: extraSettings.Username,
token: extraSettings.Token,
useProviderIP: extraSettings.UseProviderIP,
@@ -80,6 +83,10 @@ func (p *Provider) IPVersion() ipversion.IPVersion {
return p.ipVersion
}
func (p *Provider) IPv6Suffix() netip.Prefix {
return p.ipv6Suffix
}
func (p *Provider) Proxied() bool {
return false
}
@@ -107,7 +114,8 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
}
values := url.Values{}
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
if !p.useProviderIP {
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
if !useProviderIP {
values.Set("myip", ip.String())
}
if p.host == "*" {

27
internal/update/ipv6.go Normal file
View File

@@ -0,0 +1,27 @@
package update
import (
"fmt"
"net/netip"
)
func ipv6WithSuffix(publicIP netip.Addr, ipv6Suffix netip.Prefix) (
updateIP netip.Addr) {
if !publicIP.IsValid() || !publicIP.Is6() || !ipv6Suffix.IsValid() {
return publicIP
}
const ipv6Bits = 128
const bitsInByte = 8
prefixLength := (ipv6Bits - ipv6Suffix.Bits()) / bitsInByte
ispPrefix := publicIP.AsSlice()[:prefixLength]
localSuffix := ipv6Suffix.Addr().AsSlice()[prefixLength:]
ipv6Bytes := ispPrefix // ispPrefix has already 16 bytes of capacity
ipv6Bytes = append(ipv6Bytes, localSuffix...)
updateIP, ok := netip.AddrFromSlice(ipv6Bytes)
if !ok {
panic(fmt.Sprintf("failed to create IPv6 address from merged bytes %v", ipv6Bytes))
}
return updateIP
}

View File

@@ -0,0 +1,57 @@
package update
import (
"net/netip"
"testing"
"github.com/stretchr/testify/assert"
)
func Test_ipv6WithSuffix(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
publicIP netip.Addr
ipv6Suffix netip.Prefix
updateIP netip.Addr
}{
"blank_inputs": {},
"ipv4_publicip": {
publicIP: netip.MustParseAddr("1.2.3.4"),
updateIP: netip.MustParseAddr("1.2.3.4"),
},
"invalid_suffix": {
publicIP: netip.MustParseAddr("2001:db8::1"),
updateIP: netip.MustParseAddr("2001:db8::1"),
},
"zero_suffix": {
publicIP: netip.MustParseAddr("e4db:af36:82e:1221:1b7f:2f54:6e9e:5e5f"),
ipv6Suffix: netip.MustParsePrefix("0:0:0:0:0:0:0:0/0"),
updateIP: netip.MustParseAddr("e4db:af36:82e:1221:1b7f:2f54:6e9e:5e5f"),
},
"suffix_64": {
publicIP: netip.MustParseAddr("e4db:af36:82e:1221:1b7f:2f54:6e9e:5e5f"),
ipv6Suffix: netip.MustParsePrefix("0:0:0:0:72ad:8fbb:a54e:bedd/64"),
updateIP: netip.MustParseAddr("e4db:af36:82e:1221:" + "72ad:8fbb:a54e:bedd"),
},
"suffix_56": {
publicIP: netip.MustParseAddr("e4db:af36:82e:1221:1b7f:2f54:6e9e:5e5f"),
ipv6Suffix: netip.MustParsePrefix("bbff:8199:4e2f:b4ba:72ad:8fbb:a54e:bedd/56"),
updateIP: netip.MustParseAddr("e4db:af36:82e:1221:1b" + "ad:8fbb:a54e:bedd"),
},
"suffix_48": {
publicIP: netip.MustParseAddr("e4db:af36:82e:1221:1b7f:2f54:6e9e:5e5f"),
ipv6Suffix: netip.MustParsePrefix("bbff:8199:4e2f:b4ba:72ad:8fbb:a54e:bedd/48"),
updateIP: netip.MustParseAddr("e4db:af36:82e:1221:1b7f:" + "8fbb:a54e:bedd"),
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
updateIP := ipv6WithSuffix(testCase.publicIP, testCase.ipv6Suffix)
assert.Equal(t, testCase.updateIP.String(), updateIP.String())
})
}
}

View File

@@ -1,15 +0,0 @@
package update
import (
"fmt"
"net/netip"
)
func mustMaskIPv6(ipv6 netip.Addr, ipv6MaskBits uint8) (maskedIPv6 netip.Addr) {
prefix, err := ipv6.Prefix(int(ipv6MaskBits))
if err != nil {
panic(fmt.Sprintf("getting masked IPv6 prefix: %s", err))
}
maskedIPv6 = prefix.Addr()
return maskedIPv6
}

View File

@@ -1,19 +0,0 @@
package update
import (
"net/netip"
"testing"
"github.com/stretchr/testify/assert"
)
func Test_mustMaskIPv6(t *testing.T) {
t.Parallel()
const maskBits = 24
ip := netip.AddrFrom4([4]byte{1, 2, 3, 4})
maskedIP := mustMaskIPv6(ip, maskBits)
expected := netip.AddrFrom4([4]byte{1, 2, 3, 0})
assert.Equal(t, expected, maskedIP)
}

View File

@@ -19,7 +19,6 @@ type Runner struct {
updater UpdaterInterface
force chan struct{}
forceResult chan []error
ipv6MaskBits uint8
cooldown time.Duration
resolver LookupIPer
ipGetter PublicIPFetcher
@@ -29,16 +28,14 @@ type Runner struct {
}
func NewRunner(db Database, updater UpdaterInterface, ipGetter PublicIPFetcher,
period time.Duration, ipv6MaskBits uint8, cooldown time.Duration,
logger Logger, resolver LookupIPer, timeNow func() time.Time,
hioClient HealthchecksIOClient) *Runner {
period time.Duration, cooldown time.Duration, logger Logger, resolver LookupIPer,
timeNow func() time.Time, hioClient HealthchecksIOClient) *Runner {
return &Runner{
period: period,
db: db,
updater: updater,
force: make(chan struct{}),
forceResult: make(chan []error),
ipv6MaskBits: ipv6MaskBits,
cooldown: cooldown,
resolver: resolver,
ipGetter: ipGetter,
@@ -103,15 +100,13 @@ func doIPVersion(records []librecords.Record) (doIP, doIPv4, doIPv6 bool) {
return doIP, doIPv4, doIPv6
}
func (r *Runner) getNewIPs(ctx context.Context, doIP, doIPv4, doIPv6 bool, ipv6MaskBits uint8) (
func (r *Runner) getNewIPs(ctx context.Context, doIP, doIPv4, doIPv6 bool) (
ip, ipv4, ipv6 netip.Addr, errors []error) {
var err error
if doIP {
ip, err = tryAndRepeatGettingIP(ctx, r.ipGetter.IP, r.logger, ipversion.IP4or6)
if err != nil {
errors = append(errors, err)
} else if ip.Is6() {
ip = mustMaskIPv6(ip, ipv6MaskBits)
}
}
if doIPv4 {
@@ -124,18 +119,17 @@ func (r *Runner) getNewIPs(ctx context.Context, doIP, doIPv4, doIPv6 bool, ipv6M
ipv6, err = tryAndRepeatGettingIP(ctx, r.ipGetter.IP6, r.logger, ipversion.IP6)
if err != nil {
errors = append(errors, err)
} else {
ipv6 = mustMaskIPv6(ipv6, ipv6MaskBits)
}
}
return ip, ipv4, ipv6, errors
}
func (r *Runner) getRecordIDsToUpdate(ctx context.Context, records []librecords.Record,
ip, ipv4, ipv6 netip.Addr, now time.Time, ipv6MaskBits uint8) (recordIDs map[uint]struct{}) {
ip, ipv4, ipv6 netip.Addr, now time.Time) (recordIDs map[uint]struct{}) {
recordIDs = make(map[uint]struct{})
for i, record := range records {
if shouldUpdate := r.shouldUpdateRecord(ctx, record, ip, ipv4, ipv6, now, ipv6MaskBits); shouldUpdate {
shouldUpdate := r.shouldUpdateRecord(ctx, record, ip, ipv4, ipv6, now)
if shouldUpdate {
id := uint(i)
recordIDs[id] = struct{}{}
}
@@ -144,7 +138,7 @@ func (r *Runner) getRecordIDsToUpdate(ctx context.Context, records []librecords.
}
func (r *Runner) shouldUpdateRecord(ctx context.Context, record librecords.Record,
ip, ipv4, ipv6 netip.Addr, now time.Time, ipv6MaskBits uint8) (update bool) {
ip, ipv4, ipv6 netip.Addr, now time.Time) (update bool) {
isWithinBanPeriod := record.LastBan != nil && now.Sub(*record.LastBan) < time.Hour
isWithinCooldown := now.Sub(record.History.GetSuccessTime()) < r.cooldown
if isWithinBanPeriod || isWithinCooldown {
@@ -161,13 +155,15 @@ func (r *Runner) shouldUpdateRecord(ctx context.Context, record librecords.Recor
r.logger.Warn(fmt.Sprintf("Skipping update for %s because %s address was not found",
hostname, ipVersionToIPKind(ipVersion)))
return false
} else if publicIP.Is6() {
publicIP = ipv6WithSuffix(publicIP, record.Provider.IPv6Suffix())
}
if record.Provider.Proxied() {
lastIP := record.History.GetCurrentIP() // can be nil
return r.shouldUpdateRecordNoLookup(hostname, ipVersion, lastIP, publicIP)
}
return r.shouldUpdateRecordWithLookup(ctx, hostname, ipVersion, publicIP, ipv6MaskBits)
return r.shouldUpdateRecordWithLookup(ctx, hostname, ipVersion, publicIP)
}
func (r *Runner) shouldUpdateRecordNoLookup(hostname string, ipVersion ipversion.IPVersion,
@@ -181,8 +177,8 @@ func (r *Runner) shouldUpdateRecordNoLookup(hostname string, ipVersion ipversion
return false
}
func (r *Runner) shouldUpdateRecordWithLookup(ctx context.Context, hostname string, ipVersion ipversion.IPVersion,
publicIP netip.Addr, ipv6MaskBits uint8) (update bool) {
func (r *Runner) shouldUpdateRecordWithLookup(ctx context.Context, hostname string,
ipVersion ipversion.IPVersion, publicIP netip.Addr) (update bool) {
const tries = 5
recordIPv4, recordIPv6, err := r.lookupIPsResilient(ctx, hostname, tries)
if err != nil {
@@ -195,10 +191,6 @@ func (r *Runner) shouldUpdateRecordWithLookup(ctx context.Context, hostname stri
fmt.Sprint(tries) + " tries: " + err.Error()) // update anyway
}
if recordIPv6.IsValid() {
recordIPv6 = mustMaskIPv6(recordIPv6, ipv6MaskBits)
}
ipKind := ipVersionToIPKind(ipVersion)
recordIP := recordIPv4
if publicIP.Is6() {
@@ -249,18 +241,18 @@ func setInitialUpToDateStatus(db Database, id uint, updateIP netip.Addr, now tim
return db.Update(id, record)
}
func (r *Runner) updateNecessary(ctx context.Context, ipv6MaskBits uint8) (errors []error) {
func (r *Runner) updateNecessary(ctx context.Context) (errors []error) {
records := r.db.SelectAll()
doIP, doIPv4, doIPv6 := doIPVersion(records)
r.logger.Debug(fmt.Sprintf("configured to fetch IP: v4 or v6: %t, v4: %t, v6: %t", doIP, doIPv4, doIPv6))
ip, ipv4, ipv6, errors := r.getNewIPs(ctx, doIP, doIPv4, doIPv6, ipv6MaskBits)
ip, ipv4, ipv6, errors := r.getNewIPs(ctx, doIP, doIPv4, doIPv6)
r.logger.Debug(fmt.Sprintf("your public IP address are: v4 or v6: %s, v4: %s, v6: %s", ip, ipv4, ipv6))
for _, err := range errors {
r.logger.Error(err.Error())
}
now := r.timeNow()
recordIDs := r.getRecordIDsToUpdate(ctx, records, ip, ipv4, ipv6, now, ipv6MaskBits)
recordIDs := r.getRecordIDsToUpdate(ctx, records, ip, ipv4, ipv6, now)
for i, record := range records {
id := uint(i)
@@ -269,6 +261,10 @@ func (r *Runner) updateNecessary(ctx context.Context, ipv6MaskBits uint8) (error
continue
}
updateIP := getIPMatchingVersion(ip, ipv4, ipv6, record.Provider.IPVersion())
if updateIP.Is6() {
updateIP = ipv6WithSuffix(updateIP, record.Provider.IPv6Suffix())
}
err := setInitialUpToDateStatus(r.db, id, updateIP, now)
if err != nil {
err = fmt.Errorf("setting initial up to date status: %w", err)
@@ -284,6 +280,8 @@ func (r *Runner) updateNecessary(ctx context.Context, ipv6MaskBits uint8) (error
errors = append(errors, err)
r.logger.Error(err.Error())
continue
} else if updateIP.Is6() {
updateIP = ipv6WithSuffix(updateIP, record.Provider.IPv6Suffix())
}
r.logger.Info("Updating record " + record.Provider.String() + " to use " + updateIP.String())
err := r.updater.Update(ctx, id, updateIP, r.timeNow())
@@ -307,9 +305,9 @@ func (r *Runner) Run(ctx context.Context, done chan<- struct{}) {
for {
select {
case <-ticker.C:
r.updateNecessary(ctx, r.ipv6MaskBits)
r.updateNecessary(ctx)
case <-r.force:
r.forceResult <- r.updateNecessary(ctx, r.ipv6MaskBits)
r.forceResult <- r.updateNecessary(ctx)
case <-ctx.Done():
ticker.Stop()
return