mirror of
https://github.com/qdm12/ddns-updater.git
synced 2026-04-22 17:12:14 -04:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cc0b9b2a1 | ||
|
|
d3ec047483 | ||
|
|
08c95618cb | ||
|
|
1130a58b60 | ||
|
|
4635d8e4d6 | ||
|
|
7f74bc8e40 | ||
|
|
1f82cb1f54 | ||
|
|
81aaeeebf6 | ||
|
|
2ac822a871 | ||
|
|
cd5aae240e |
@@ -190,6 +190,7 @@ func (p PubIP) validateHTTPIPv6Providers() (err error) {
|
||||
|
||||
var (
|
||||
ErrNoPublicIPHTTPProvider = errors.New("no public IP HTTP provider specified")
|
||||
ErrURLIsNotValidHTTPS = errors.New("URL is not valid or not HTTPS")
|
||||
)
|
||||
|
||||
func validateHTTPIPProviders(providerStrings []string,
|
||||
@@ -215,8 +216,11 @@ func validateHTTPIPProviders(providerStrings []string,
|
||||
}
|
||||
|
||||
// Custom URL check
|
||||
url, err := url.Parse(providerString)
|
||||
if err == nil && url != nil && url.Scheme == "https" {
|
||||
if strings.HasPrefix(providerString, "url:") {
|
||||
url, err := url.Parse(providerString[4:])
|
||||
if err != nil || url.Scheme != "https" {
|
||||
return fmt.Errorf("%w: %s", ErrURLIsNotValidHTTPS, providerString)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -18,16 +18,16 @@ type HistoryEvent struct { // current and previous ips
|
||||
|
||||
// GetPreviousIPs returns an antichronological list of previous
|
||||
// IP addresses if there is any.
|
||||
func (h History) GetPreviousIPs() []netip.Addr {
|
||||
func (h History) GetPreviousIPs() (previousIPs []netip.Addr) {
|
||||
if len(h) <= 1 {
|
||||
return nil
|
||||
}
|
||||
IPs := make([]netip.Addr, len(h)-1)
|
||||
const two = 2
|
||||
for i := len(h) - two; i >= 0; i-- {
|
||||
IPs[i] = h[i].IP
|
||||
previousIPs = make([]netip.Addr, len(h)-1)
|
||||
mostRecentPreviousIPIndex := len(h) - 2 //nolint:gomnd
|
||||
for i := range previousIPs {
|
||||
previousIPs[i] = h[mostRecentPreviousIPIndex-i].IP
|
||||
}
|
||||
return IPs
|
||||
return previousIPs
|
||||
}
|
||||
|
||||
// GetCurrentIP returns the current IP address (latest in history).
|
||||
|
||||
@@ -1,12 +1,58 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_GetPreviousIPs(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := map[string]struct {
|
||||
h History
|
||||
previousIPs []netip.Addr
|
||||
}{
|
||||
"empty_history": {
|
||||
h: History{},
|
||||
},
|
||||
"single_event": {
|
||||
h: History{
|
||||
{IP: netip.MustParseAddr("1.2.3.4")},
|
||||
},
|
||||
},
|
||||
"two_events": {
|
||||
h: History{
|
||||
{IP: netip.MustParseAddr("1.2.3.4")},
|
||||
{IP: netip.MustParseAddr("5.6.7.8")}, // last one
|
||||
},
|
||||
previousIPs: []netip.Addr{
|
||||
netip.MustParseAddr("1.2.3.4"),
|
||||
},
|
||||
},
|
||||
"three_events": {
|
||||
h: History{
|
||||
{IP: netip.MustParseAddr("1.2.3.4")},
|
||||
{IP: netip.MustParseAddr("5.6.7.8")},
|
||||
{IP: netip.MustParseAddr("9.6.7.8")}, // last one
|
||||
},
|
||||
previousIPs: []netip.Addr{
|
||||
netip.MustParseAddr("5.6.7.8"),
|
||||
netip.MustParseAddr("1.2.3.4"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
previousIPs := testCase.h.GetPreviousIPs()
|
||||
assert.Equal(t, testCase.previousIPs, previousIPs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetDurationSinceSuccess(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := map[string]struct {
|
||||
|
||||
@@ -122,8 +122,10 @@ func (p *Provider) HTML() models.HTMLRow {
|
||||
}
|
||||
|
||||
func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Addr) (newIP netip.Addr, err error) {
|
||||
values := url.Values{}
|
||||
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
|
||||
values, err := url.ParseQuery(p.url.RawQuery)
|
||||
if err != nil {
|
||||
return netip.Addr{}, fmt.Errorf("parsing URL query: %w", err)
|
||||
}
|
||||
ipKey := p.ipv4Key
|
||||
if ip.Is6() {
|
||||
ipKey = p.ipv6Key
|
||||
|
||||
@@ -59,8 +59,6 @@ func (p *Provider) isValid() error {
|
||||
return fmt.Errorf("%w", errors.ErrUsernameNotSet)
|
||||
case p.password == "":
|
||||
return fmt.Errorf("%w", errors.ErrPasswordNotSet)
|
||||
case p.host == "*":
|
||||
return fmt.Errorf("%w", errors.ErrHostWildcard)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/qdm12/ddns-updater/internal/provider/constants"
|
||||
"github.com/qdm12/ddns-updater/internal/provider/errors"
|
||||
"github.com/qdm12/ddns-updater/internal/provider/utils"
|
||||
)
|
||||
|
||||
func (p *Provider) createRecord(ctx context.Context, client *http.Client,
|
||||
@@ -30,7 +31,7 @@ func (p *Provider) createRecord(ctx context.Context, client *http.Client,
|
||||
const defaultPrio = 0
|
||||
recordsList := []apiRecord{
|
||||
{
|
||||
Name: p.BuildDomainName(),
|
||||
Name: utils.BuildURLQueryHostname(p.host, p.domain),
|
||||
Type: recordType,
|
||||
Content: ip.String(),
|
||||
TTL: defaultTTL,
|
||||
|
||||
@@ -121,7 +121,7 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
|
||||
|
||||
const usualRecordsCount = 1
|
||||
matchingRecords := make([]apiRecord, 0, usualRecordsCount)
|
||||
fullDomainName := p.BuildDomainName()
|
||||
fullDomainName := utils.BuildURLQueryHostname(p.host, p.domain)
|
||||
for _, record := range records {
|
||||
if record.Name == fullDomainName {
|
||||
matchingRecords = append(matchingRecords, record)
|
||||
|
||||
@@ -54,6 +54,9 @@ func (p *Provider) getRecordID(ctx context.Context, client *http.Client,
|
||||
}
|
||||
|
||||
for _, record := range data.Records {
|
||||
if record.Host == "" {
|
||||
record.Host = "@"
|
||||
}
|
||||
if record.Host == p.host && record.Type == recordType {
|
||||
return record.RecordID, nil
|
||||
}
|
||||
|
||||
@@ -27,13 +27,17 @@ func (p *Provider) updateRecord(ctx context.Context, client *http.Client,
|
||||
User: url.UserPassword(p.username, p.token),
|
||||
}
|
||||
|
||||
host := ""
|
||||
if p.host != "@" {
|
||||
host = p.host
|
||||
}
|
||||
postRecordsParams := struct {
|
||||
Host string `json:"host"`
|
||||
Type string `json:"type"`
|
||||
Answer string `json:"answer"`
|
||||
TTL *uint32 `json:"ttl,omitempty"`
|
||||
}{
|
||||
Host: p.host,
|
||||
Host: host,
|
||||
Type: recordType,
|
||||
Answer: ip.String(),
|
||||
TTL: p.ttl,
|
||||
|
||||
@@ -120,11 +120,10 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
|
||||
values.Set("hostname", utils.BuildURLQueryHostname(p.host, p.domain))
|
||||
useProviderIP := p.useProviderIP && (ip.Is4() || !p.ipv6Suffix.IsValid())
|
||||
if !useProviderIP {
|
||||
if ip.Is6() {
|
||||
values.Set("myipv6", ip.String())
|
||||
} else {
|
||||
values.Set("myip", ip.String())
|
||||
}
|
||||
// See https://help.dyn.com/remote-access-api/perform-update/ stating:
|
||||
// This authentication method supports both IPv6 and IPv4 addresses.
|
||||
// Use commas to separate multiple IP addresses in the myip field.
|
||||
values.Set("myip", ip.String())
|
||||
}
|
||||
u.RawQuery = values.Encode()
|
||||
|
||||
@@ -178,7 +177,11 @@ func (p *Provider) Update(ctx context.Context, client *http.Client, ip netip.Add
|
||||
ips = ipextract.IPv6(s)
|
||||
}
|
||||
|
||||
if !useProviderIP && len(ips) == 0 {
|
||||
if len(ips) == 0 {
|
||||
if useProviderIP {
|
||||
// No returned ip address from noip server
|
||||
return ip, nil
|
||||
}
|
||||
return netip.Addr{}, fmt.Errorf("%w", errors.ErrReceivedNoIP)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ func (p *Provider) getRecordIDs(ctx context.Context, client *http.Client, record
|
||||
Host: "porkbun.com",
|
||||
Path: "/api/json/v3/dns/retrieveByNameType/" + p.domain + "/" + recordType + "/",
|
||||
}
|
||||
if p.host != "@" {
|
||||
if p.host != "@" && p.host != "*" {
|
||||
u.Path += p.host
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user