10 Commits
azure ... v2.6

Author SHA1 Message Date
Quentin McGaw
6cc0b9b2a1 fix(namecom): update record using "" when the host is @ 2024-06-26 14:22:51 +00:00
Quentin McGaw
d3ec047483 fix(ui): list IPs in reverse chronological order
- Fix #730
2024-06-26 14:22:12 +00:00
Quentin McGaw
08c95618cb fix(ionos): wildcard handling 2024-06-26 14:22:00 +00:00
Quentin McGaw
1130a58b60 fix(namecom): detect existing root host domains 2024-06-26 14:21:46 +00:00
Quentin McGaw
4635d8e4d6 fix(porkbun): do not add * to URL path 2024-06-26 14:19:13 +00:00
Quentin McGaw
7f74bc8e40 fix(noip): useproviderip and no ip returned case 2024-06-26 14:16:18 +00:00
Quentin McGaw
1f82cb1f54 fix(custom): keep url values and only set ip 2024-06-26 14:15:23 +00:00
Quentin McGaw
81aaeeebf6 fix(config): allow custom urls for http ip providers 2024-06-26 14:08:07 +00:00
Quentin McGaw
2ac822a871 fix(inwx): allow wildcard hosts 2024-06-26 14:07:55 +00:00
Quentin McGaw
cd5aae240e fix(noip): IPv6 query parameter fixed 2024-06-26 14:07:29 +00:00
11 changed files with 83 additions and 22 deletions

View File

@@ -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
}

View File

@@ -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).

View File

@@ -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 {

View File

@@ -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

View File

@@ -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
}

View File

@@ -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,

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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,

View File

@@ -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)
}

View File

@@ -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
}