mirror of
https://github.com/qdm12/ddns-updater.git
synced 2026-04-05 08:53:52 -04:00
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:
@@ -73,7 +73,6 @@ ENV \
|
||||
# Core
|
||||
CONFIG= \
|
||||
PERIOD=5m \
|
||||
IPV6_PREFIX=/128 \
|
||||
UPDATE_COOLDOWN_PERIOD=5m \
|
||||
PUBLICIP_FETCHERS=all \
|
||||
PUBLICIP_HTTP_PROVIDERS=all \
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"`
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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: /
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 == "*" {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
27
internal/update/ipv6.go
Normal 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
|
||||
}
|
||||
57
internal/update/ipv6_test.go
Normal file
57
internal/update/ipv6_test.go
Normal 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())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user