Repository: favonia/cloudflare-ddns
Pull request #997 (2024-12-11 19:27:39)

refactor: remove useless code
This is part of the fix for #985.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/997?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) Report
Attention: Patch coverage is `95.00000%` with `2 lines` in your changes missing coverage. Please review.
> Project coverage is 94.58%. Comparing base [(`6f486e1`)](https://app.codecov.io/gh/favonia/cloudflare-ddns/commit/6f486e1aa31372f37709be36a0872d35c93d4549?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) to head [(`04c5e68`)](https://app.codecov.io/gh/favonia/cloudflare-ddns/commit/04c5e686a2c10f1275bc80271a2d594524461665?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).

| [Files with missing lines](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/997?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) | Patch % | Lines |
|---|---|---|
| [internal/provider/protocol/local\_auto.go](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/997?src=pr&el=tree&filepath=internal%2Fprovider%2Fprotocol%2Flocal_auto.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia#diff-aW50ZXJuYWwvcHJvdmlkZXIvcHJvdG9jb2wvbG9jYWxfYXV0by5nbw==) | 75.00% | [1 Missing :warning: ](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/997?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) |
| [internal/provider/protocol/local\_iface.go](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/997?src=pr&el=tree&filepath=internal%2Fprovider%2Fprotocol%2Flocal_iface.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia#diff-aW50ZXJuYWwvcHJvdmlkZXIvcHJvdG9jb2wvbG9jYWxfaWZhY2UuZ28=) | 87.50% | [1 Missing :warning: ](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/997?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #997      +/-   ##
==========================================
- Coverage   94.74%   94.58%   -0.16%     
==========================================
  Files          64       62       -2     
  Lines        3465     3364     -101     
==========================================
- Hits         3283     3182     -101     
  Misses        170      170              
  Partials       12       12              
```

| [Flag](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/997/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/997/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia) | `94.58% <95.00%> (-0.16%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/favonia/cloudflare-ddns/pull/997?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=favonia).


Patch:
diff --git a/README.markdown b/README.markdown
index 53d74d2..584f973 100644
--- a/README.markdown
+++ b/README.markdown
@@ -308,14 +308,14 @@ The emoji “🧪” indicates experimental features and the emoji “🤖” in
 
 > 👉 The option `IP4_PROVIDER` governs `A`-type DNS records and IPv4 addresses in WAF lists, while the option `IP6_PROVIDER` governs `AAAA`-type DNS records and IPv6 addresses in WAF lists. The two options act independently of each other. You can specify different address providers for IPv4 and IPv6.
 
-| Provider Name                                                                            | Explanation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
-| ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `cloudflare.doh`                                                                         | Get the IP address by querying `whoami.cloudflare.` against [Cloudflare via DNS-over-HTTPS](https://developers.cloudflare.com/1.1.1.1/dns-over-https). 🤖 The updater will connect `1.1.1.1` for IPv4 and `2606:4700:4700::1111` for IPv6. Since version 1.9.3, the updater will switch to `1.0.0.1` for IPv4 if `1.1.1.1` appears to be blocked or intercepted by your ISP or your router (which is still not uncommon). Since version 1.14.0, the blockage detection uses a variant of [the Happy Eyeballs algorithm](https://en.wikipedia.org/wiki/Happy_Eyeballs) to reduce delay. |
-| `cloudflare.trace`                                                                       | Get the IP address by parsing the [Cloudflare debugging page](https://one.one.one.one/cdn-cgi/trace). **This is the default provider.** 🤖 The updater will connect `1.1.1.1` for IPv4 and `2606:4700:4700::1111` for IPv6. Since version 1.9.3, the updater will switch to `1.0.0.1` for IPv4 if `1.1.1.1` appears to be blocked or intercepted by your ISP or your router (which is still not uncommon). Since version 1.14.0, the blockage detection uses a variant of [the Happy Eyeballs algorithm](https://en.wikipedia.org/wiki/Happy_Eyeballs) to reduce delay.                |
-| `local`                                                                                  | <p>Get the IP address via local network interfaces and routing tables. The updater will use the local address that _would have_ been used for outbound UDP connections to Cloudflare servers. (No data will be transmitted.)</p><p>⚠️ The updater needs access to the host network (such as `network_mode: host` in Docker Compose) for this provider, for otherwise the updater will detect the addresses inside [the default bridge network in Docker](https://docs.docker.com/network/bridge/) instead of those in the host network.</p>                                            |
-| 🧪 `local.iface:<iface>` (available since version 1.15.0 but not finalized until 1.16.0) | <p>🧪 Get the IP address via the specific local network interface `iface`. The updater will choose the first global unicast IP address of the matching IP family (IPv4 or IPv6).</p><p>⚠️ The updater needs access to the host network (such as `network_mode: host` in Docker Compose) for this provider, for otherwise the updater cannot access host network interfaces.</p>                                                                                                                                                                                                        |
-| `url:<URL>`                                                                              | Fetch the IP address from a URL. The provider format is `url:` followed by the URL itself. For example, `IP4_PROVIDER=url:https://api4.ipify.org` will fetch the IPv4 address from <https://api4.ipify.org>. Since version 1.15.0, the updater will enforce the matching protocol (IPv4 or IPv6) when connecting to the provided URL. Currently, only HTTP(S) is supported.                                                                                                                                                                                                            |
-| `none`                                                                                   | <p>Stop the DNS updating for the specified IP version completely. For example `IP4_PROVIDER=none` will disable IPv4 completely. Existing DNS records will not be removed.</p><p>🧪 The IP addresses of the disabled IP version will be removed from WAF lists; so `IP4_PROVIDER=none` will remove all IPv4 addresses from all managed WAF lists. As the support of WAF lists is still experimental, this behavior is subject to changes and please [provide feedback](https://github.com/favonia/cloudflare-ddns/issues/new).</p>                                                      |
+| Provider Name                                                                            | Explanation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
+| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `cloudflare.doh`                                                                         | Get the IP address by querying `whoami.cloudflare.` against [Cloudflare via DNS-over-HTTPS](https://developers.cloudflare.com/1.1.1.1/dns-over-https).                                                                                                                                                                                                                                                                                                                                                                                      |
+| `cloudflare.trace`                                                                       | Get the IP address by parsing the [Cloudflare debugging page](https://api.cloudflare.com/cdn-cgi/trace). **This is the default provider.**                                                                                                                                                                                                                                                                                                                                                                                                  |
+| `local`                                                                                  | <p>Get the IP address via local network interfaces and routing tables. The updater will use the local address that _would have_ been used for outbound UDP connections to Cloudflare servers. (No data will be transmitted.)</p><p>⚠️ The updater needs access to the host network (such as `network_mode: host` in Docker Compose) for this provider, for otherwise the updater will detect the addresses inside [the default bridge network in Docker](https://docs.docker.com/network/bridge/) instead of those in the host network.</p> |
+| 🧪 `local.iface:<iface>` (available since version 1.15.0 but not finalized until 1.16.0) | <p>🧪 Get the IP address via the specific local network interface `iface`. The updater will choose the first global unicast IP address of the matching IP family (IPv4 or IPv6).</p><p>⚠️ The updater needs access to the host network (such as `network_mode: host` in Docker Compose) for this provider, for otherwise the updater cannot access host network interfaces.</p>                                                                                                                                                             |
+| `url:<URL>`                                                                              | Fetch the IP address from a URL. The provider format is `url:` followed by the URL itself. For example, `IP4_PROVIDER=url:https://api4.ipify.org` will fetch the IPv4 address from <https://api4.ipify.org>. Since version 1.15.0, the updater will enforce the matching protocol (IPv4 or IPv6) when connecting to the provided URL. Currently, only HTTP(S) is supported.                                                                                                                                                                 |
+| `none`                                                                                   | <p>Stop the DNS updating for the specified IP version completely. For example `IP4_PROVIDER=none` will disable IPv4 completely. Existing DNS records will not be removed.</p><p>🧪 The IP addresses of the disabled IP version will be removed from WAF lists; so `IP4_PROVIDER=none` will remove all IPv4 addresses from all managed WAF lists. As the support of WAF lists is still experimental, this behavior is subject to changes and please [provide feedback](https://github.com/favonia/cloudflare-ddns/issues/new).</p>           |
 
 </details>
 
diff --git a/internal/config/config_read.go b/internal/config/config_read.go
index 0aa2e73..3f9a3c1 100644
--- a/internal/config/config_read.go
+++ b/internal/config/config_read.go
@@ -153,13 +153,6 @@ func (c *Config) Normalize(ppfmt pp.PP) bool {
 		}
 	}
 
-	// Part 7: Warn about short DetectionTimeout
-	if c.DetectionTimeout <= provider.HappyEyeballsAlternativeDelay {
-		ppfmt.Noticef(pp.EmojiUserWarning,
-			"DETECTION_TIMEOUT=%s may be too short for trying 1.0.0.1 when 1.1.1.1 does not work", c.DetectionTimeout)
-		provider.Hint1111Blockage(ppfmt)
-	}
-
 	// Final Part: override the old values
 	c.Provider = providerMap
 	c.Proxied = proxiedMap
diff --git a/internal/mocks/mock_provider.go b/internal/mocks/mock_provider.go
index a8c3c19..0601196 100644
--- a/internal/mocks/mock_provider.go
+++ b/internal/mocks/mock_provider.go
@@ -1,9 +1,9 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/favonia/cloudflare-ddns/internal/provider (interfaces: Provider,SplitProvider)
+// Source: github.com/favonia/cloudflare-ddns/internal/provider (interfaces: Provider)
 //
 // Generated by this command:
 //
-//	mockgen -typed -destination=../mocks/mock_provider.go -package=mocks . Provider,SplitProvider
+//	mockgen -typed -destination=../mocks/mock_provider.go -package=mocks . Provider
 //
 // Package mocks is a generated GoMock package.
 package mocks
@@ -15,7 +15,6 @@ import (
 
 	ipnet "github.com/favonia/cloudflare-ddns/internal/ipnet"
 	pp "github.com/favonia/cloudflare-ddns/internal/pp"
-	protocol "github.com/favonia/cloudflare-ddns/internal/provider/protocol"
 	gomock "go.uber.org/mock/gomock"
 )
 
@@ -43,13 +42,12 @@ func (m *MockProvider) EXPECT() *MockProviderMockRecorder {
 }
 
 // GetIP mocks base method.
-func (m *MockProvider) GetIP(arg0 context.Context, arg1 pp.PP, arg2 ipnet.Type) (netip.Addr, protocol.Method, bool) {
+func (m *MockProvider) GetIP(arg0 context.Context, arg1 pp.PP, arg2 ipnet.Type) (netip.Addr, bool) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GetIP", arg0, arg1, arg2)
 	ret0, _ := ret[0].(netip.Addr)
-	ret1, _ := ret[1].(protocol.Method)
-	ret2, _ := ret[2].(bool)
-	return ret0, ret1, ret2
+	ret1, _ := ret[1].(bool)
+	return ret0, ret1
 }
 
 // GetIP indicates an expected call of GetIP.
@@ -65,19 +63,19 @@ type ProviderGetIPCall struct {
 }
 
 // Return rewrite *gomock.Call.Return
-func (c *ProviderGetIPCall) Return(arg0 netip.Addr, arg1 protocol.Method, arg2 bool) *ProviderGetIPCall {
-	c.Call = c.Call.Return(arg0, arg1, arg2)
+func (c *ProviderGetIPCall) Return(arg0 netip.Addr, arg1 bool) *ProviderGetIPCall {
+	c.Call = c.Call.Return(arg0, arg1)
 	return c
 }
 
 // Do rewrite *gomock.Call.Do
-func (c *ProviderGetIPCall) Do(f func(context.Context, pp.PP, ipnet.Type) (netip.Addr, protocol.Method, bool)) *ProviderGetIPCall {
+func (c *ProviderGetIPCall) Do(f func(context.Context, pp.PP, ipnet.Type) (netip.Addr, bool)) *ProviderGetIPCall {
 	c.Call = c.Call.Do(f)
 	return c
 }
 
 // DoAndReturn rewrite *gomock.Call.DoAndReturn
-func (c *ProviderGetIPCall) DoAndReturn(f func(context.Context, pp.PP, ipnet.Type) (netip.Addr, protocol.Method, bool)) *ProviderGetIPCall {
+func (c *ProviderGetIPCall) DoAndReturn(f func(context.Context, pp.PP, ipnet.Type) (netip.Addr, bool)) *ProviderGetIPCall {
 	c.Call = c.Call.DoAndReturn(f)
 	return c
 }
@@ -119,141 +117,3 @@ func (c *ProviderNameCall) DoAndReturn(f func() string) *ProviderNameCall {
 	c.Call = c.Call.DoAndReturn(f)
 	return c
 }
-
-// MockSplitProvider is a mock of SplitProvider interface.
-type MockSplitProvider struct {
-	ctrl     *gomock.Controller
-	recorder *MockSplitProviderMockRecorder
-}
-
-// MockSplitProviderMockRecorder is the mock recorder for MockSplitProvider.
-type MockSplitProviderMockRecorder struct {
-	mock *MockSplitProvider
-}
-
-// NewMockSplitProvider creates a new mock instance.
-func NewMockSplitProvider(ctrl *gomock.Controller) *MockSplitProvider {
-	mock := &MockSplitProvider{ctrl: ctrl}
-	mock.recorder = &MockSplitProviderMockRecorder{mock}
-	return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use.
-func (m *MockSplitProvider) EXPECT() *MockSplitProviderMockRecorder {
-	return m.recorder
-}
-
-// GetIP mocks base method.
-func (m *MockSplitProvider) GetIP(arg0 context.Context, arg1 pp.PP, arg2 ipnet.Type, arg3 protocol.Method) (netip.Addr, bool) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "GetIP", arg0, arg1, arg2, arg3)
-	ret0, _ := ret[0].(netip.Addr)
-	ret1, _ := ret[1].(bool)
-	return ret0, ret1
-}
-
-// GetIP indicates an expected call of GetIP.
-func (mr *MockSplitProviderMockRecorder) GetIP(arg0, arg1, arg2, arg3 any) *SplitProviderGetIPCall {
-	mr.mock.ctrl.T.Helper()
-	call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIP", reflect.TypeOf((*MockSplitProvider)(nil).GetIP), arg0, arg1, arg2, arg3)
-	return &SplitProviderGetIPCall{Call: call}
-}
-
-// SplitProviderGetIPCall wrap *gomock.Call
-type SplitProviderGetIPCall struct {
-	*gomock.Call
-}
-
-// Return rewrite *gomock.Call.Return
-func (c *SplitProviderGetIPCall) Return(arg0 netip.Addr, arg1 bool) *SplitProviderGetIPCall {
-	c.Call = c.Call.Return(arg0, arg1)
-	return c
-}
-
-// Do rewrite *gomock.Call.Do
-func (c *SplitProviderGetIPCall) Do(f func(context.Context, pp.PP, ipnet.Type, protocol.Method) (netip.Addr, bool)) *SplitProviderGetIPCall {
-	c.Call = c.Call.Do(f)
-	return c
-}
-
-// DoAndReturn rewrite *gomock.Call.DoAndReturn
-func (c *SplitProviderGetIPCall) DoAndReturn(f func(context.Context, pp.PP, ipnet.Type, protocol.Method) (netip.Addr, bool)) *SplitProviderGetIPCall {
-	c.Call = c.Call.DoAndReturn(f)
-	return c
-}
-
-// HasAlternative mocks base method.
-func (m *MockSplitProvider) HasAlternative(arg0 ipnet.Type) bool {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "HasAlternative", arg0)
-	ret0, _ := ret[0].(bool)
-	return ret0
-}
-
-// HasAlternative indicates an expected call of HasAlternative.
-func (mr *MockSplitProviderMockRecorder) HasAlternative(arg0 any) *SplitProviderHasAlternativeCall {
-	mr.mock.ctrl.T.Helper()
-	call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasAlternative", reflect.TypeOf((*MockSplitProvider)(nil).HasAlternative), arg0)
-	return &SplitProviderHasAlternativeCall{Call: call}
-}
-
-// SplitProviderHasAlternativeCall wrap *gomock.Call
-type SplitProviderHasAlternativeCall struct {
-	*gomock.Call
-}
-
-// Return rewrite *gomock.Call.Return
-func (c *SplitProviderHasAlternativeCall) Return(arg0 bool) *SplitProviderHasAlternativeCall {
-	c.Call = c.Call.Return(arg0)
-	return c
-}
-
-// Do rewrite *gomock.Call.Do
-func (c *SplitProviderHasAlternativeCall) Do(f func(ipnet.Type) bool) *SplitProviderHasAlternativeCall {
-	c.Call = c.Call.Do(f)
-	return c
-}
-
-// DoAndReturn rewrite *gomock.Call.DoAndReturn
-func (c *SplitProviderHasAlternativeCall) DoAndReturn(f func(ipnet.Type) bool) *SplitProviderHasAlternativeCall {
-	c.Call = c.Call.DoAndReturn(f)
-	return c
-}
-
-// Name mocks base method.
-func (m *MockSplitProvider) Name() string {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Name")
-	ret0, _ := ret[0].(string)
-	return ret0
-}
-
-// Name indicates an expected call of Name.
-func (mr *MockSplitProviderMockRecorder) Name() *SplitProviderNameCall {
-	mr.mock.ctrl.T.Helper()
-	call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockSplitProvider)(nil).Name))
-	return &SplitProviderNameCall{Call: call}
-}
-
-// SplitProviderNameCall wrap *gomock.Call
-type SplitProviderNameCall struct {
-	*gomock.Call
-}
-
-// Return rewrite *gomock.Call.Return
-func (c *SplitProviderNameCall) Return(arg0 string) *SplitProviderNameCall {
-	c.Call = c.Call.Return(arg0)
-	return c
-}
-
-// Do rewrite *gomock.Call.Do
-func (c *SplitProviderNameCall) Do(f func() string) *SplitProviderNameCall {
-	c.Call = c.Call.Do(f)
-	return c
-}
-
-// DoAndReturn rewrite *gomock.Call.DoAndReturn
-func (c *SplitProviderNameCall) DoAndReturn(f func() string) *SplitProviderNameCall {
-	c.Call = c.Call.DoAndReturn(f)
-	return c
-}
diff --git a/internal/pp/hint.go b/internal/pp/hint.go
index 7ccc367..60a26ad 100644
--- a/internal/pp/hint.go
+++ b/internal/pp/hint.go
@@ -16,7 +16,6 @@ const (
 	HintWAFListPermission                          // Permissions to update WAF lists
 	HintMismatchedRecordAttributes                 // Attributes of DNS records have been changed
 	HintMismatchedWAFListAttributes                // Attributes of WAF lists have been changed
-	Hint1111Blockage                               // 1.1.1.1 is blocked
 	HintExperimentalShoutrrr                       // New feature introduced in 1.12.0 on 2024/6/28
 	HintExperimentalWAF                            // New feature introduced in 1.14.0 on 2024/8/25
 	HintExperimentalLocalWithInterface             // New feature introduced in 1.15.0
diff --git a/internal/provider/base.go b/internal/provider/base.go
index 99fc039..88dcc3b 100644
--- a/internal/provider/base.go
+++ b/internal/provider/base.go
@@ -10,39 +10,14 @@ import (
 	"github.com/favonia/cloudflare-ddns/internal/provider/protocol"
 )
 
-//go:generate mockgen -typed -destination=../mocks/mock_provider.go -package=mocks . Provider,SplitProvider
-
-// Method reexports [protocol.Method].
-type Method = protocol.Method
-
-// Re-exporting constants from protocol.
-const (
-	MethodPrimary     = protocol.MethodPrimary
-	MethodAlternative = protocol.MethodAlternative
-	MethodUnspecified = protocol.MethodUnspecified
-)
+//go:generate mockgen -typed -destination=../mocks/mock_provider.go -package=mocks . Provider
 
 // Provider is the abstraction of a protocol to detect public IP addresses.
 type Provider interface {
 	Name() string
 	// Name gives the name of the protocol.
 
-	GetIP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, Method, bool)
-	// GetIP gets the IP.
-}
-
-// SplitProvider is the abstraction of a protocol to detect public IP addresses
-// in potentially two ways. GetIP is taking an extra argument to change the method.
-// So far, all alternative methods are to connect to 1.0.0.1 instead of 1.1.1.1
-// to work around bad ISPs or bad routers.
-type SplitProvider interface {
-	Name() string
-	// Name gives the name of the protocol.
-
-	HasAlternative(ipNet ipnet.Type) bool
-	// HasAlternative checks whether there is a different alternative method.
-
-	GetIP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type, method Method) (netip.Addr, bool)
+	GetIP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, bool)
 	// GetIP gets the IP.
 }
 
diff --git a/internal/provider/cloudflare_doh.go b/internal/provider/cloudflare_doh.go
index dd83ef4..c52f0ed 100644
--- a/internal/provider/cloudflare_doh.go
+++ b/internal/provider/cloudflare_doh.go
@@ -10,17 +10,17 @@ import (
 // NewCloudflareDOH creates a new provider that queries whoami.cloudflare. via Cloudflare DNS over HTTPS.
 // If use1001 is true, 1.0.0.1 is used instead of 1.1.1.1.
 func NewCloudflareDOH() Provider {
-	return NewHappyEyeballs(protocol.DNSOverHTTPS{
+	return protocol.DNSOverHTTPS{
 		ProviderName: "cloudflare.doh",
 		Param: map[ipnet.Type]protocol.DNSOverHTTPSParam{
 			ipnet.IP4: {
-				protocol.Constant("https://cloudflare-dns.com/dns-query"),
+				"https://cloudflare-dns.com/dns-query",
 				"whoami.cloudflare.", dnsmessage.ClassCHAOS,
 			},
 			ipnet.IP6: {
-				protocol.Constant("https://cloudflare-dns.com/dns-query"),
+				"https://cloudflare-dns.com/dns-query",
 				"whoami.cloudflare.", dnsmessage.ClassCHAOS,
 			},
 		},
-	})
+	}
 }
diff --git a/internal/provider/cloudflare_trace.go b/internal/provider/cloudflare_trace.go
index 9cc0f6c..0670f27 100644
--- a/internal/provider/cloudflare_trace.go
+++ b/internal/provider/cloudflare_trace.go
@@ -18,17 +18,11 @@ func NewCloudflareTrace() Provider {
 // NewCloudflareTraceCustom creates a specialized CloudflareTrace provider
 // with a specific URL.
 func NewCloudflareTraceCustom(url string) Provider {
-	return NewHappyEyeballs(protocol.Regexp{
+	return protocol.Regexp{
 		ProviderName: "cloudflare.trace",
 		Param: map[ipnet.Type]protocol.RegexpParam{
-			ipnet.IP4: {
-				protocol.Constant(url),
-				fieldIP,
-			},
-			ipnet.IP6: {
-				protocol.Constant(url),
-				fieldIP,
-			},
+			ipnet.IP4: {url, fieldIP},
+			ipnet.IP6: {url, fieldIP},
 		},
-	})
+	}
 }
diff --git a/internal/provider/custom.go b/internal/provider/custom.go
index f8ff80f..52c93c7 100644
--- a/internal/provider/custom.go
+++ b/internal/provider/custom.go
@@ -34,13 +34,13 @@ func NewCustomURL(ppfmt pp.PP, rawURL string) (Provider, bool) {
 		return nil, false
 	}
 
-	return NewHappyEyeballs(protocol.HTTP{
+	return protocol.HTTP{
 		ProviderName: "url:(redacted)",
-		URL: map[ipnet.Type]protocol.Switch{
-			ipnet.IP4: protocol.Constant(rawURL),
-			ipnet.IP6: protocol.Constant(rawURL),
+		URL: map[ipnet.Type]string{
+			ipnet.IP4: rawURL,
+			ipnet.IP6: rawURL,
 		},
-	}), true
+	}, true
 }
 
 // MustNewCustomURL creates a HTTP provider and panics if it fails.
diff --git a/internal/provider/happy_eyeballs.go b/internal/provider/happy_eyeballs.go
deleted file mode 100644
index df75d85..0000000
--- a/internal/provider/happy_eyeballs.go
+++ /dev/null
@@ -1,133 +0,0 @@
-package provider
-
-import (
-	"context"
-	"net/netip"
-	"time"
-
-	"github.com/favonia/cloudflare-ddns/internal/ipnet"
-	"github.com/favonia/cloudflare-ddns/internal/pp"
-)
-
-// HappyEyeballsAlternativeDelay is the delay to start the alternative
-// detection method.
-const HappyEyeballsAlternativeDelay = time.Second / 2
-
-// Hint1111BlocakageText is the explanation of why we want the parallel detection algorithm.
-const Hint1111BlocakageText string = "Your IPv4 provider is using 1.1.1.1 to get your public IP. Sometimes, your ISP or router might block this. If that happens, we'll try 1.0.0.1 instead. Whichever works first will be used from then on." //nolint:lll
-
-// Hint1111Blockage prints out a message that explains the parallel connection to 1.0.0.1.
-func Hint1111Blockage(ppfmt pp.PP) { ppfmt.Hintf(pp.Hint1111Blockage, "%s", Hint1111BlocakageText) }
-
-type splitResult struct {
-	method Method
-	ip     netip.Addr
-	ok     bool
-}
-
-type happyEyeballs struct {
-	provider SplitProvider
-	chosen   map[ipnet.Type]Method
-}
-
-// NewHappyEyeballs creates a new [Provider] by applying the Happy Eyeballs algorithm to [SplitProvider].
-func NewHappyEyeballs(provider SplitProvider) Provider {
-	return happyEyeballs{
-		provider: provider,
-		chosen:   map[ipnet.Type]Method{},
-	}
-}
-
-// Name calls the [SplitProvider.Name].
-func (p happyEyeballs) Name() string {
-	return p.provider.Name()
-}
-
-// GetIP initiates both methods simultaneously.
-//
-// This is basically the Happy Eyeballs, with two major changes:
-//  1. The delay to initiate the alternative method is controlled
-//     by [HappyEyeballsAlternativeDelay], which is longer than
-//     what's recommended in RFC 6555.
-//  2. The state will not be flushed because 1.1.1.1 is not
-func (p happyEyeballs) GetIP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, Method, bool) {
-	if !p.provider.HasAlternative(ipNet) {
-		p.chosen[ipNet] = MethodPrimary
-	}
-
-	if method := p.chosen[ipNet]; method != MethodUnspecified {
-		ip, ok := p.provider.GetIP(ctx, ppfmt, ipNet, method)
-		return ip, method, ok
-	}
-
-	finished := make(chan struct{})
-	defer close(finished)
-
-	splitResults := make(chan splitResult)
-	failed := map[Method]bool{}
-	queuedPP := map[Method]pp.QueuedPP{}
-
-	start := func(ctx context.Context, ppfmt pp.PP, method Method) {
-		ip, ok := p.provider.GetIP(ctx, ppfmt, ipNet, method)
-
-		select {
-		case <-finished: // done
-		case splitResults <- splitResult{method: method, ip: ip, ok: ok}:
-		}
-	}
-
-	fork := func(method Method) func() {
-		ctx, cancel := context.WithCancel(ctx)
-		queuedPP[method] = pp.NewQueued(ppfmt)
-		go start(ctx, queuedPP[method], method)
-
-		return cancel
-	}
-
-	primaryCancel := fork(MethodPrimary)
-	defer primaryCancel()
-
-	// Some delay for the alternative method so that
-	// 1. We prefer the primary method, and
-	// 2. We are not making lots of requests at the same time.
-	alternativeDelayTimer := time.NewTimer(HappyEyeballsAlternativeDelay)
-
-	for {
-		select {
-		case <-alternativeDelayTimer.C:
-			alternativeCancel := fork(MethodAlternative)
-			defer alternativeCancel()
-
-		case r := <-splitResults:
-			if r.ok {
-				// remember this successful IP detection
-				p.chosen[ipNet] = r.method
-				queuedPP[r.method].Flush()
-
-				if r.method == MethodAlternative {
-					ppfmt.Infof(pp.EmojiNow, "The server 1.0.0.1 responded before 1.1.1.1 does and will be used from now on")
-				}
-
-				return r.ip, r.method, r.ok
-			}
-
-			// Record the failure.
-			failed[r.method] = true
-
-			// If both methods fail, then the detection fails.
-			if failed[MethodPrimary] && failed[MethodAlternative] {
-				// Flush out the messages from the primary method.
-				queuedPP[MethodPrimary].Flush()
-
-				return netip.Addr{}, MethodUnspecified, false
-			}
-
-			// If the primary method fails, start the alternative method immediately.
-			if r.method == MethodPrimary {
-				if alternativeDelayTimer.Stop() {
-					alternativeDelayTimer.Reset(0)
-				}
-			}
-		}
-	}
-}
diff --git a/internal/provider/ipify.go b/internal/provider/ipify.go
index 90d56d5..6f0d9de 100644
--- a/internal/provider/ipify.go
+++ b/internal/provider/ipify.go
@@ -7,11 +7,11 @@ import (
 
 // NewIpify creates a specialized HTTP provider that uses the ipify service.
 func NewIpify() Provider {
-	return NewHappyEyeballs(protocol.HTTP{
+	return protocol.HTTP{
 		ProviderName: "ipify",
-		URL: map[ipnet.Type]protocol.Switch{
-			ipnet.IP4: protocol.Constant("https://api4.ipify.org"),
-			ipnet.IP6: protocol.Constant("https://api6.ipify.org"),
+		URL: map[ipnet.Type]string{
+			ipnet.IP4: "https://api4.ipify.org",
+			ipnet.IP6: "https://api6.ipify.org",
 		},
-	})
+	}
 }
diff --git a/internal/provider/protocol/const.go b/internal/provider/protocol/const.go
index 295f3ba..3256896 100644
--- a/internal/provider/protocol/const.go
+++ b/internal/provider/protocol/const.go
@@ -23,7 +23,7 @@ func (p Const) Name() string {
 }
 
 // GetIP returns the IP.
-func (p Const) GetIP(_ context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, Method, bool) {
+func (p Const) GetIP(_ context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, bool) {
 	normalizedIP, ok := ipNet.NormalizeDetectedIP(ppfmt, p.IP)
-	return normalizedIP, MethodPrimary, ok
+	return normalizedIP, ok
 }
diff --git a/internal/provider/protocol/doh.go b/internal/provider/protocol/doh.go
index 4d64d31..7264383 100644
--- a/internal/provider/protocol/doh.go
+++ b/internal/provider/protocol/doh.go
@@ -167,7 +167,7 @@ func getIPFromDNS(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type, url string
 
 // DNSOverHTTPSParam is the parameter of a DNS-based IP provider.
 type DNSOverHTTPSParam = struct {
-	URL   Switch           // the DoH server
+	URL   string           // the DoH server
 	Name  string           // domain name to query
 	Class dnsmessage.Class // DNS class to query
 }
@@ -184,22 +184,17 @@ func (p DNSOverHTTPS) Name() string {
 }
 
 // GetIP detects the IP address by DNS over HTTPS.
-func (p DNSOverHTTPS) GetIP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type, method Method) (netip.Addr, bool) {
+func (p DNSOverHTTPS) GetIP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, bool) {
 	param, found := p.Param[ipNet]
 	if !found {
 		ppfmt.Noticef(pp.EmojiImpossible, "Unhandled IP network: %s", ipNet.Describe())
 		return netip.Addr{}, false
 	}
 
-	ip, ok := getIPFromDNS(ctx, ppfmt, ipNet, param.URL.Switch(method), param.Name, param.Class)
+	ip, ok := getIPFromDNS(ctx, ppfmt, ipNet, param.URL, param.Name, param.Class)
 	if !ok {
 		return netip.Addr{}, false
 	}
 
 	return ipNet.NormalizeDetectedIP(ppfmt, ip)
 }
-
-// HasAlternative calls [Switch.HasAlternative].
-func (p DNSOverHTTPS) HasAlternative(ipNet ipnet.Type) bool {
-	return p.Param[ipNet].URL.HasAlternative()
-}
diff --git a/internal/provider/protocol/http.go b/internal/provider/protocol/http.go
index 79b9f32..cfd20a5 100644
--- a/internal/provider/protocol/http.go
+++ b/internal/provider/protocol/http.go
@@ -34,7 +34,7 @@ func getIPFromHTTP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type, url strin
 // HTTP represents a generic detection protocol to use an HTTP response directly.
 type HTTP struct {
 	ProviderName string                // name of the protocol
-	URL          map[ipnet.Type]Switch // URL of the page for detection
+	URL          map[ipnet.Type]string // URL of the page for detection
 }
 
 // Name of the detection protocol.
@@ -43,20 +43,17 @@ func (p HTTP) Name() string {
 }
 
 // GetIP detects the IP address by using the HTTP response directly.
-func (p HTTP) GetIP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type, method Method) (netip.Addr, bool) {
+func (p HTTP) GetIP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, bool) {
 	url, found := p.URL[ipNet]
 	if !found {
 		ppfmt.Noticef(pp.EmojiImpossible, "Unhandled IP network: %s", ipNet.Describe())
 		return netip.Addr{}, false
 	}
 
-	ip, ok := getIPFromHTTP(ctx, ppfmt, ipNet, url.Switch(method))
+	ip, ok := getIPFromHTTP(ctx, ppfmt, ipNet, url)
 	if !ok {
 		return netip.Addr{}, false
 	}
 
 	return ipNet.NormalizeDetectedIP(ppfmt, ip)
 }
-
-// HasAlternative calls [Switch.HasAlternative].
-func (p HTTP) HasAlternative(ipNet ipnet.Type) bool { return p.URL[ipNet].HasAlternative() }
diff --git a/internal/provider/protocol/local_auto.go b/internal/provider/protocol/local_auto.go
index 2235a51..0bb0b92 100644
--- a/internal/provider/protocol/local_auto.go
+++ b/internal/provider/protocol/local_auto.go
@@ -45,19 +45,19 @@ func ExtractUDPAddr(ppfmt pp.PP, addr net.Addr) (netip.Addr, bool) {
 
 // GetIP detects the IP address by pretending to send an UDP packet.
 // (No actual UDP packets will be sent out.)
-func (p LocalAuto) GetIP(_ context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, Method, bool) {
+func (p LocalAuto) GetIP(_ context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, bool) {
 	conn, err := net.Dial(ipNet.UDPNetwork(), p.RemoteUDPAddr)
 	if err != nil {
 		ppfmt.Noticef(pp.EmojiError, "Failed to detect a local %s address: %v", ipNet.Describe(), err)
-		return netip.Addr{}, MethodUnspecified, false
+		return netip.Addr{}, false
 	}
 	defer conn.Close()
 
 	ip, ok := ExtractUDPAddr(ppfmt, conn.LocalAddr())
 	if !ok {
-		return netip.Addr{}, MethodUnspecified, false
+		return netip.Addr{}, false
 	}
 
 	normalizedIP, ok := ipNet.NormalizeDetectedIP(ppfmt, ip)
-	return normalizedIP, MethodPrimary, ok
+	return normalizedIP, ok
 }
diff --git a/internal/provider/protocol/local_iface.go b/internal/provider/protocol/local_iface.go
index 7b75dea..94f5fcc 100644
--- a/internal/provider/protocol/local_iface.go
+++ b/internal/provider/protocol/local_iface.go
@@ -52,12 +52,12 @@ func ExtractInterfaceAddr(ppfmt pp.PP, iface string, addr net.Addr) (netip.Addr,
 }
 
 // SelectInterfaceIP takes a list of [net.Addr] and choose the first reasonable IP (if any).
-func SelectInterfaceIP(ppfmt pp.PP, iface string, ipNet ipnet.Type, addrs []net.Addr) (netip.Addr, Method, bool) {
+func SelectInterfaceIP(ppfmt pp.PP, iface string, ipNet ipnet.Type, addrs []net.Addr) (netip.Addr, bool) {
 	ips := make([]netip.Addr, 0, len(addrs))
 	for _, addr := range addrs {
 		ip, ok := ExtractInterfaceAddr(ppfmt, iface, addr)
 		if !ok {
-			return ip, MethodUnspecified, false
+			return ip, false
 		}
 		ips = append(ips, ip)
 	}
@@ -66,7 +66,7 @@ func SelectInterfaceIP(ppfmt pp.PP, iface string, ipNet ipnet.Type, addrs []net.
 		return ipNet.Matches(ip) && ip.IsGlobalUnicast()
 	})
 	if i >= 0 {
-		return ips[i], MethodPrimary, true
+		return ips[i], true
 	}
 
 	// Choose an IP that is above the link-local scope
@@ -82,28 +82,28 @@ func SelectInterfaceIP(ppfmt pp.PP, iface string, ipNet ipnet.Type, addrs []net.
 			"Failed to find any global unicast %s address assigned to interface %s, "+
 				"but found an address %s with a scope larger than the link-local scope",
 			ipNet.Describe(), iface, ips[i].String())
-		return ips[i], MethodPrimary, true
+		return ips[i], true
 	}
 
 	ppfmt.Noticef(pp.EmojiError,
 		"Failed to find any global unicast %s address assigned to interface %s",
 		ipNet.Describe(), iface)
-	return netip.Addr{}, MethodUnspecified, false
+	return netip.Addr{}, false
 }
 
 // GetIP detects the IP address by pretending to send an UDP packet.
 // (No actual UDP packets will be sent out.)
-func (p LocalWithInterface) GetIP(_ context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, Method, bool) {
+func (p LocalWithInterface) GetIP(_ context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, bool) {
 	iface, err := net.InterfaceByName(p.InterfaceName)
 	if err != nil {
 		ppfmt.Noticef(pp.EmojiUserError, "Failed to find an interface named %q: %v", p.InterfaceName, err)
-		return netip.Addr{}, MethodUnspecified, false
+		return netip.Addr{}, false
 	}
 
 	addrs, err := iface.Addrs()
 	if err != nil {
 		ppfmt.Noticef(pp.EmojiImpossible, "Failed to list addresses of interface %s: %v", p.InterfaceName, err)
-		return netip.Addr{}, MethodUnspecified, false
+		return netip.Addr{}, false
 	}
 
 	return SelectInterfaceIP(ppfmt, p.InterfaceName, ipNet, addrs)
diff --git a/internal/provider/protocol/regexp.go b/internal/provider/protocol/regexp.go
index 94afc78..1b74b73 100644
--- a/internal/provider/protocol/regexp.go
+++ b/internal/provider/protocol/regexp.go
@@ -41,7 +41,7 @@ func getIPFromRegexp(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type, url str
 
 // RegexpParam is the type of parameters for the Regexp provider for a specific IP network.
 type RegexpParam = struct {
-	URL    Switch         // URL of the detection page
+	URL    string         // URL of the detection page
 	Regexp *regexp.Regexp // regular expression to match the IP address
 }
 
@@ -55,20 +55,17 @@ type Regexp struct {
 func (p Regexp) Name() string { return p.ProviderName }
 
 // GetIP detects the IP address by parsing the HTTP response.
-func (p Regexp) GetIP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type, method Method) (netip.Addr, bool) {
+func (p Regexp) GetIP(ctx context.Context, ppfmt pp.PP, ipNet ipnet.Type) (netip.Addr, bool) {
 	param, found := p.Param[ipNet]
 	if !found {
 		ppfmt.Noticef(pp.EmojiImpossible, "Unhandled IP network: %s", ipNet.Describe())
 		return netip.Addr{}, false
 	}
 
-	ip, ok := getIPFromRegexp(ctx, ppfmt, ipNet, param.URL.Switch(method), param.Regexp)
+	ip, ok := getIPFromRegexp(ctx, ppfmt, ipNet, param.URL, param.Regexp)
 	if !ok {
 		return netip.Addr{}, false
 	}
 
 	return ipNet.NormalizeDetectedIP(ppfmt, ip)
 }
-
-// HasAlternative calls [Switch.HasAlternative].
-func (p Regexp) HasAlternative(ipNet ipnet.Type) bool { return p.Param[ipNet].URL.HasAlternative() }
diff --git a/internal/provider/protocol/switch.go b/internal/provider/protocol/switch.go
deleted file mode 100644
index eaf9a3a..0000000
--- a/internal/provider/protocol/switch.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package protocol
-
-// Method denotes the choice between the primary and alternative methods.
-type Method int
-
-// The tags for the primary and alternative methods.
-const (
-	MethodUnspecified Method = iota
-	MethodPrimary
-	MethodAlternative
-)
-
-// Switch represents a string depending on the method.
-type Switch interface {
-	Switch(method Method) string
-	HasAlternative() bool
-}
-
-// Constant is a [Switch] that ignores whether 1.1.1.1 or 1.0.0.1 is used.
-type Constant string
-
-// Switch always returns the same string.
-func (c Constant) Switch(Method) string { return string(c) }
-
-// HasAlternative always returns false.
-func (Constant) HasAlternative() bool { return false }
-
-// Switchable is a [Switch] that returns one of the given strings.
-type Switchable struct {
-	Primary     string
-	Alternative string
-}
-
-// Switch returns one of the given strings depending on the boolean value.
-func (s Switchable) Switch(method Method) string {
-	switch method {
-	default:
-		return s.Primary
-	case MethodAlternative:
-		return s.Alternative
-	}
-}
-
-// HasAlternative always returns true.
-func (Switchable) HasAlternative() bool { return true }
diff --git a/internal/updater/updater.go b/internal/updater/updater.go
index e055e02..b7deffd 100644
--- a/internal/updater/updater.go
+++ b/internal/updater/updater.go
@@ -25,16 +25,10 @@ func detectIP(ctx context.Context, ppfmt pp.PP, c *config.Config, ipNet ipnet.Ty
 	ctx, cancel := context.WithTimeoutCause(ctx, c.DetectionTimeout, errTimeout)
 	defer cancel()
 
-	ip, method, ok := c.Provider[ipNet].GetIP(ctx, ppfmt, ipNet)
+	ip, ok := c.Provider[ipNet].GetIP(ctx, ppfmt, ipNet)
 
 	if ok {
-		switch method {
-		case provider.MethodAlternative:
-			ppfmt.Infof(pp.EmojiInternet, "Detected the %s address %v (using 1.0.0.1)", ipNet.Describe(), ip)
-			provider.Hint1111Blockage(ppfmt)
-		default:
-			ppfmt.Infof(pp.EmojiInternet, "Detected the %s address %v", ipNet.Describe(), ip)
-		}
+		ppfmt.Infof(pp.EmojiInternet, "Detected the %s address %v", ipNet.Describe(), ip)
 		ppfmt.SuppressHint(getHintIDForDetection(ipNet))
 	} else {
 		ppfmt.Noticef(pp.EmojiError, "Failed to detect the %s address", ipNet.Describe())


Test patch:
diff --git a/internal/config/config_read_test.go b/internal/config/config_read_test.go
index 56cdd78..ce0d090 100644
--- a/internal/config/config_read_test.go
+++ b/internal/config/config_read_test.go
@@ -453,41 +453,6 @@ func TestNormalize(t *testing.T) {
 				)
 			},
 		},
-		"dectioctn-time-too-short": {
-			input: &config.Config{ //nolint:exhaustruct
-				UpdateOnStart: true,
-				Provider: map[ipnet.Type]provider.Provider{
-					ipnet.IP6: provider.NewCloudflareTrace(),
-				},
-				Domains: map[ipnet.Type][]domain.Domain{
-					ipnet.IP6: {domain.FQDN("a.b.c")},
-				},
-				ProxiedTemplate:  "true",
-				DetectionTimeout: time.Nanosecond,
-			},
-			ok: true,
-			expected: &config.Config{ //nolint:exhaustruct
-				UpdateOnStart: true,
-				Provider: map[ipnet.Type]provider.Provider{
-					ipnet.IP6: provider.NewCloudflareTrace(),
-				},
-				Domains: map[ipnet.Type][]domain.Domain{
-					ipnet.IP6: {domain.FQDN("a.b.c")},
-				},
-				ProxiedTemplate:  "true",
-				Proxied:          map[domain.Domain]bool{domain.FQDN("a.b.c"): true},
-				DetectionTimeout: time.Nanosecond,
-			},
-			prepareMockPP: func(m *mocks.MockPP) {
-				gomock.InOrder(
-					m.EXPECT().IsShowing(pp.Info).Return(true),
-					m.EXPECT().Infof(pp.EmojiEnvVars, "Checking settings . . ."),
-					m.EXPECT().Indent().Return(m),
-					m.EXPECT().Noticef(pp.EmojiUserWarning, "DETECTION_TIMEOUT=%s may be too short for trying 1.0.0.1 when 1.1.1.1 does not work", time.Nanosecond),
-					m.EXPECT().Hintf(pp.Hint1111Blockage, "%s", provider.Hint1111BlocakageText),
-				)
-			},
-		},
 	} {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
diff --git a/internal/provider/happy_eyeballs_test.go b/internal/provider/happy_eyeballs_test.go
deleted file mode 100644
index 4212212..0000000
--- a/internal/provider/happy_eyeballs_test.go
+++ /dev/null
@@ -1,251 +0,0 @@
-package provider_test
-
-import (
-	"context"
-	"net/netip"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/require"
-	"go.uber.org/mock/gomock"
-
-	"github.com/favonia/cloudflare-ddns/internal/ipnet"
-	"github.com/favonia/cloudflare-ddns/internal/mocks"
-	"github.com/favonia/cloudflare-ddns/internal/pp"
-	"github.com/favonia/cloudflare-ddns/internal/provider"
-)
-
-func sleepCtx(ctx context.Context, d time.Duration) {
-	timer := time.NewTimer(d)
-	select {
-	case <-timer.C:
-	case <-ctx.Done():
-	}
-}
-
-func TestHappyEyeballs(t *testing.T) {
-	t.Parallel()
-
-	ipNet := ipnet.IP4
-	forever := time.Hour
-	ip1111 := netip.MustParseAddr("1.1.1.1")
-	ip1001 := netip.MustParseAddr("1.0.0.1")
-
-	for name, tc := range map[string]struct {
-		ip           netip.Addr
-		method       provider.Method
-		ok           bool
-		timeout      time.Duration
-		elapsed      time.Duration
-		prepareMocks func(ppfmt *mocks.MockPP, p *mocks.MockSplitProvider)
-	}{
-		"no-alternative": {
-			ip1111, provider.MethodPrimary, true,
-			3 * time.Second, 0,
-			func(ppfmt *mocks.MockPP, p *mocks.MockSplitProvider) {
-				p.EXPECT().HasAlternative(ipNet).Return(false)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodPrimary).DoAndReturn(
-					func(_ context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Infof(pp.EmojiGood, "Got 1.1.1.1!")
-						return ip1111, true
-					}).Times(2)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.1.1.1!")
-				p.EXPECT().HasAlternative(ipNet).Return(false)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.1.1.1!")
-			},
-		},
-		"primary-instant": {
-			ip1111, provider.MethodPrimary, true,
-			3 * time.Second, 0,
-			func(ppfmt *mocks.MockPP, p *mocks.MockSplitProvider) {
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodPrimary).DoAndReturn(
-					func(_ context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Infof(pp.EmojiGood, "Got 1.1.1.1!")
-						return ip1111, true
-					}).Times(2)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.1.1.1!")
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.1.1.1!")
-			},
-		},
-		"primary-delayed/alternative-instant": {
-			ip1001, provider.MethodAlternative, true,
-			3 * time.Second, provider.HappyEyeballsAlternativeDelay,
-			func(ppfmt *mocks.MockPP, p *mocks.MockSplitProvider) {
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodPrimary).DoAndReturn(
-					func(ctx context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Infof(pp.EmojiGood, "Got 1.1.1.1!")
-						sleepCtx(ctx, time.Second)
-						return ip1111, true
-					}).Times(1)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodAlternative).DoAndReturn(
-					func(_ context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Infof(pp.EmojiGood, "Got 1.0.0.1!")
-						return ip1001, true
-					}).Times(2)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.0.0.1!")
-				ppfmt.EXPECT().Infof(pp.EmojiNow, "The server 1.0.0.1 responded before 1.1.1.1 does and will be used from now on")
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.0.0.1!")
-			},
-		},
-		"primary-delayed/alternative-instant-fails": {
-			ip1111, provider.MethodPrimary, true,
-			3 * time.Second, time.Second,
-			func(ppfmt *mocks.MockPP, p *mocks.MockSplitProvider) {
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodPrimary).DoAndReturn(
-					func(ctx context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Infof(pp.EmojiGood, "Got 1.1.1.1!")
-						sleepCtx(ctx, time.Second)
-						return ip1111, true
-					}).Times(2)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodAlternative).DoAndReturn(
-					func(_ context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Noticef(pp.EmojiError, "Can't get 1.0.0.1")
-						return netip.Addr{}, false
-					}).Times(1)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.1.1.1!")
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.1.1.1!")
-			},
-		},
-		"primary-delayed/alternative-timeout": {
-			ip1111, provider.MethodPrimary, true,
-			3 * time.Second, time.Second,
-			func(ppfmt *mocks.MockPP, p *mocks.MockSplitProvider) {
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodPrimary).DoAndReturn(
-					func(ctx context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Infof(pp.EmojiGood, "Got 1.1.1.1!")
-						sleepCtx(ctx, time.Second)
-						return ip1111, true
-					}).Times(2)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodAlternative).DoAndReturn(
-					func(ctx context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Infof(pp.EmojiGood, "Got 1.0.0.1!")
-						sleepCtx(ctx, forever)
-						return ip1001, true
-					}).Times(1)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.1.1.1!")
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.1.1.1!")
-			},
-		},
-		"primary-instant-fails/alternative-instant": {
-			ip1001, provider.MethodAlternative, true,
-			3 * time.Second, 0,
-			func(ppfmt *mocks.MockPP, p *mocks.MockSplitProvider) {
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodPrimary).DoAndReturn(
-					func(_ context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Noticef(pp.EmojiError, "Can't get 1.1.1.1")
-						return netip.Addr{}, false
-					}).Times(1)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodAlternative).DoAndReturn(
-					func(_ context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Infof(pp.EmojiGood, "Got 1.0.0.1!")
-						return ip1001, true
-					}).Times(2)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.0.0.1!")
-				ppfmt.EXPECT().Infof(pp.EmojiNow, "The server 1.0.0.1 responded before 1.1.1.1 does and will be used from now on")
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.0.0.1!")
-			},
-		},
-		"primary-instant-fails/alternative-instant-fails": {
-			netip.Addr{},
-			provider.MethodUnspecified, false,
-			3 * time.Second, 0,
-			func(ppfmt *mocks.MockPP, p *mocks.MockSplitProvider) {
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodPrimary).DoAndReturn(
-					func(_ context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Noticef(pp.EmojiError, "Can't get 1.1.1.1")
-						return netip.Addr{}, false
-					}).Times(1)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodAlternative).DoAndReturn(
-					func(_ context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Noticef(pp.EmojiError, "Can't get 1.0.0.1")
-						return netip.Addr{}, false
-					}).Times(1)
-				ppfmt.EXPECT().Noticef(pp.EmojiError, "Can't get 1.1.1.1")
-			},
-		},
-		"primary-timeout/alternative-delayed": {
-			ip1001, provider.MethodAlternative, true,
-			3 * time.Second, provider.HappyEyeballsAlternativeDelay + time.Second,
-			func(ppfmt *mocks.MockPP, p *mocks.MockSplitProvider) {
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodPrimary).DoAndReturn(
-					func(ctx context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Noticef(pp.EmojiError, "Can't get 1.1.1.1")
-						sleepCtx(ctx, forever)
-						return netip.Addr{}, false
-					}).Times(1)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodAlternative).DoAndReturn(
-					func(ctx context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Infof(pp.EmojiGood, "Got 1.0.0.1!")
-						sleepCtx(ctx, time.Second)
-						return ip1001, true
-					}).Times(2)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.0.0.1!")
-				ppfmt.EXPECT().Infof(pp.EmojiNow, "The server 1.0.0.1 responded before 1.1.1.1 does and will be used from now on")
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				ppfmt.EXPECT().Infof(pp.EmojiGood, "Got 1.0.0.1!")
-			},
-		},
-		"primary-timeout/alternative-timeout": {
-			netip.Addr{},
-			provider.MethodUnspecified, false,
-			3 * time.Second, 3 * time.Second,
-			func(ppfmt *mocks.MockPP, p *mocks.MockSplitProvider) {
-				p.EXPECT().HasAlternative(ipNet).Return(true)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodPrimary).DoAndReturn(
-					func(ctx context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Noticef(pp.EmojiError, "Can't get 1.1.1.1")
-						sleepCtx(ctx, forever)
-						return netip.Addr{}, false
-					}).Times(1)
-				p.EXPECT().GetIP(gomock.Any(), gomock.Any(), ipNet, provider.MethodAlternative).DoAndReturn(
-					func(ctx context.Context, ppfmt pp.PP, _ ipnet.Type, _ provider.Method) (netip.Addr, bool) {
-						ppfmt.Noticef(pp.EmojiError, "Can't get 1.0.0.1")
-						sleepCtx(ctx, forever)
-						return netip.Addr{}, false
-					}).Times(1)
-				ppfmt.EXPECT().Noticef(pp.EmojiError, "Can't get 1.1.1.1")
-			},
-		},
-	} {
-		t.Run(name, func(t *testing.T) {
-			t.Parallel()
-
-			mockCtrl := gomock.NewController(t)
-			mockPP := mocks.NewMockPP(mockCtrl)
-			mockSP := mocks.NewMockSplitProvider(mockCtrl)
-			if tc.prepareMocks != nil {
-				tc.prepareMocks(mockPP, mockSP)
-			}
-
-			ctx, cancel := context.WithTimeout(context.Background(), tc.timeout)
-			defer cancel()
-
-			startTime := time.Now()
-			p := provider.NewHappyEyeballs(mockSP)
-			ip, method, ok := p.GetIP(ctx, mockPP, ipNet)
-			require.Equal(t, tc.ip, ip)
-			require.Equal(t, tc.method, method)
-			require.Equal(t, tc.ok, ok)
-			require.WithinDuration(t, startTime.Add(tc.elapsed), time.Now(), 100*time.Millisecond)
-
-			if tc.ok {
-				ip, method, ok = p.GetIP(ctx, mockPP, ipNet)
-				require.Equal(t, tc.ip, ip)
-				require.Equal(t, tc.method, method)
-				require.Equal(t, tc.ok, ok)
-			}
-		})
-	}
-}
diff --git a/internal/provider/protocol/const_test.go b/internal/provider/protocol/const_test.go
index 048f491..f9074a0 100644
--- a/internal/provider/protocol/const_test.go
+++ b/internal/provider/protocol/const_test.go
@@ -76,9 +76,8 @@ func TestConstGetIP(t *testing.T) {
 				ProviderName: "",
 				IP:           tc.savedIP,
 			}
-			ip, method, ok := provider.GetIP(context.Background(), mockPP, tc.ipNet)
+			ip, ok := provider.GetIP(context.Background(), mockPP, tc.ipNet)
 			require.Equal(t, tc.ok, ok)
-			require.NotEqual(t, protocol.MethodAlternative, method)
 			require.Equal(t, tc.expected, ip)
 		})
 	}
diff --git a/internal/provider/protocol/doh_test.go b/internal/provider/protocol/doh_test.go
index 617738e..299e995 100644
--- a/internal/provider/protocol/doh_test.go
+++ b/internal/provider/protocol/doh_test.go
@@ -544,7 +544,7 @@ func TestDNSOverHTTPSGetIP(t *testing.T) {
 			provider := &protocol.DNSOverHTTPS{
 				ProviderName: "",
 				Param: map[ipnet.Type]protocol.DNSOverHTTPSParam{
-					tc.urlKey: {protocol.Constant(server.URL), tc.name, tc.class},
+					tc.urlKey: {server.URL, tc.name, tc.class},
 				},
 			}
 
@@ -552,24 +552,9 @@ func TestDNSOverHTTPSGetIP(t *testing.T) {
 			if tc.prepareMockPP != nil {
 				tc.prepareMockPP(mockPP)
 			}
-			ip, ok := provider.GetIP(context.Background(), mockPP, tc.ipNet, protocol.MethodPrimary)
+			ip, ok := provider.GetIP(context.Background(), mockPP, tc.ipNet)
 			require.Equal(t, tc.expected, ip)
 			require.Equal(t, tc.expected.IsValid(), ok)
 		})
 	}
 }
-
-func TestDOHHasAlternative(t *testing.T) {
-	t.Parallel()
-
-	require.True(t, (&protocol.DNSOverHTTPS{
-		ProviderName: "",
-		Param: map[ipnet.Type]protocol.DNSOverHTTPSParam{
-			ipnet.IP4: {
-				Name:  "whoami.",
-				Class: dnsmessage.ClassANY,
-				URL:   protocol.Switchable{}, //nolint:exhaustruct
-			},
-		},
-	}).HasAlternative(ipnet.IP4))
-}
diff --git a/internal/provider/protocol/http_test.go b/internal/provider/protocol/http_test.go
index 3f2f4d1..af8ce42 100644
--- a/internal/provider/protocol/http_test.go
+++ b/internal/provider/protocol/http_test.go
@@ -138,8 +138,8 @@ func TestHTTPGetIP(t *testing.T) {
 
 			provider := &protocol.HTTP{
 				ProviderName: "secret name",
-				URL: map[ipnet.Type]protocol.Switch{
-					tc.urlKey: protocol.Constant(tc.url),
+				URL: map[ipnet.Type]string{
+					tc.urlKey: tc.url,
 				},
 			}
 
@@ -155,20 +155,9 @@ func TestHTTPGetIP(t *testing.T) {
 				tc.prepareMockPP(mockPP)
 			}
 
-			ip, ok := provider.GetIP(ctx, mockPP, tc.ipNet, protocol.MethodPrimary)
+			ip, ok := provider.GetIP(ctx, mockPP, tc.ipNet)
 			require.Equal(t, tc.expected, ip)
 			require.Equal(t, tc.expected.IsValid(), ok)
 		})
 	}
 }
-
-func TestHTTPHasAlternative(t *testing.T) {
-	t.Parallel()
-
-	require.True(t, (&protocol.HTTP{
-		ProviderName: "",
-		URL: map[ipnet.Type]protocol.Switch{
-			ipnet.IP4: protocol.Switchable{}, //nolint:exhaustruct
-		},
-	}).HasAlternative(ipnet.IP4))
-}
diff --git a/internal/provider/protocol/local_auto_test.go b/internal/provider/protocol/local_auto_test.go
index 86fc9c6..365ee2a 100644
--- a/internal/provider/protocol/local_auto_test.go
+++ b/internal/provider/protocol/local_auto_test.go
@@ -131,9 +131,8 @@ func TestLocalAuteGetIP(t *testing.T) {
 				ProviderName:  "",
 				RemoteUDPAddr: tc.addr,
 			}
-			ip, method, ok := provider.GetIP(context.Background(), mockPP, tc.ipNet)
+			ip, ok := provider.GetIP(context.Background(), mockPP, tc.ipNet)
 			require.Equal(t, tc.expected, ip)
-			require.NotEqual(t, protocol.MethodAlternative, method)
 			require.Equal(t, tc.ok, ok)
 		})
 	}
diff --git a/internal/provider/protocol/local_iface_test.go b/internal/provider/protocol/local_iface_test.go
index ced2f39..1b44344 100644
--- a/internal/provider/protocol/local_iface_test.go
+++ b/internal/provider/protocol/local_iface_test.go
@@ -107,7 +107,6 @@ func TestSelectInterfaceIP(t *testing.T) {
 		ipNet         ipnet.Type
 		input         []net.Addr
 		ok            bool
-		method        protocol.Method
 		output        netip.Addr
 		prepareMockPP func(*mocks.MockPP)
 	}{
@@ -119,13 +118,13 @@ func TestSelectInterfaceIP(t *testing.T) {
 				&net.IPAddr{IP: net.ParseIP("4.3.2.1"), Zone: ""},
 				&net.IPAddr{IP: net.ParseIP("2::2"), Zone: ""},
 			},
-			true, protocol.MethodPrimary, netip.MustParseAddr("1.2.3.4"),
+			true, netip.MustParseAddr("1.2.3.4"),
 			nil,
 		},
 		"ipaddr/4/none": {
 			ipnet.IP4,
 			[]net.Addr{&net.IPAddr{IP: net.ParseIP("1::1"), Zone: ""}, &net.IPAddr{IP: net.ParseIP("2::2"), Zone: ""}},
-			false, protocol.MethodUnspecified, invalidIP,
+			false, invalidIP,
 			func(ppfmt *mocks.MockPP) {
 				ppfmt.EXPECT().Noticef(pp.EmojiError, "Failed to find any global unicast %s address assigned to interface %s", "IPv4", "iface")
 			},
@@ -133,7 +132,7 @@ func TestSelectInterfaceIP(t *testing.T) {
 		"ipaddr/4/loopback": {
 			ipnet.IP4,
 			[]net.Addr{&net.IPAddr{IP: net.ParseIP("127.0.0.1"), Zone: ""}},
-			false, protocol.MethodUnspecified, invalidIP,
+			false, invalidIP,
 			func(ppfmt *mocks.MockPP) {
 				ppfmt.EXPECT().Noticef(pp.EmojiError, "Failed to find any global unicast %s address assigned to interface %s", "IPv4", "iface")
 			},
@@ -141,7 +140,7 @@ func TestSelectInterfaceIP(t *testing.T) {
 		"ipaddr/6/ff05::2": {
 			ipnet.IP6,
 			[]net.Addr{&net.IPAddr{IP: net.ParseIP("ff05::2"), Zone: "site"}},
-			true, protocol.MethodPrimary, netip.MustParseAddr("ff05::2%site"),
+			true, netip.MustParseAddr("ff05::2%site"),
 			func(ppfmt *mocks.MockPP) {
 				ppfmt.EXPECT().Noticef(pp.EmojiWarning, "Failed to find any global unicast %s address assigned to interface %s, but found an address %s with a scope larger than the link-local scope", "IPv6", "iface", "ff05::2%site")
 			},
@@ -149,7 +148,7 @@ func TestSelectInterfaceIP(t *testing.T) {
 		"ipaddr/4/dummy": {
 			ipnet.IP6,
 			[]net.Addr{&Dummy{}},
-			false, protocol.MethodUnspecified, invalidIP,
+			false, invalidIP,
 			func(ppfmt *mocks.MockPP) {
 				ppfmt.EXPECT().Noticef(pp.EmojiImpossible, "Unexpected address data %q of type %T found in interface %s", "dummy/string", &Dummy{}, "iface")
 			},
@@ -164,9 +163,8 @@ func TestSelectInterfaceIP(t *testing.T) {
 				tc.prepareMockPP(mockPP)
 			}
 
-			output, method, ok := protocol.SelectInterfaceIP(mockPP, "iface", tc.ipNet, tc.input)
+			output, ok := protocol.SelectInterfaceIP(mockPP, "iface", tc.ipNet, tc.input)
 			require.Equal(t, tc.ok, ok)
-			require.Equal(t, tc.method, method)
 			require.Equal(t, tc.output, output)
 		})
 	}
@@ -217,9 +215,8 @@ func TestLocalWithInterfaceGetIP(t *testing.T) {
 				ProviderName:  "",
 				InterfaceName: tc.interfaceName,
 			}
-			ip, method, ok := provider.GetIP(context.Background(), mockPP, tc.ipNet)
+			ip, ok := provider.GetIP(context.Background(), mockPP, tc.ipNet)
 			require.Equal(t, tc.ok, ok)
-			require.NotEqual(t, protocol.MethodAlternative, method)
 			require.Equal(t, tc.expected, ip)
 		})
 	}
diff --git a/internal/provider/protocol/regexp_test.go b/internal/provider/protocol/regexp_test.go
index 6565dd1..d158e56 100644
--- a/internal/provider/protocol/regexp_test.go
+++ b/internal/provider/protocol/regexp_test.go
@@ -139,7 +139,7 @@ func TestRegexpGetIP(t *testing.T) {
 				ProviderName: "secret name",
 				Param: map[ipnet.Type]protocol.RegexpParam{
 					tc.urlKey: {
-						URL:    protocol.Constant(tc.url),
+						URL:    tc.url,
 						Regexp: tc.regexp,
 					},
 				},
@@ -153,23 +153,9 @@ func TestRegexpGetIP(t *testing.T) {
 			ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
 			defer cancel()
 
-			ip, ok := provider.GetIP(ctx, mockPP, tc.ipNet, protocol.MethodPrimary)
+			ip, ok := provider.GetIP(ctx, mockPP, tc.ipNet)
 			require.Equal(t, tc.expected, ip)
 			require.Equal(t, tc.expected.IsValid(), ok)
 		})
 	}
 }
-
-func TestRegexpHasAlternative(t *testing.T) {
-	t.Parallel()
-
-	require.True(t, (&protocol.Regexp{
-		ProviderName: "",
-		Param: map[ipnet.Type]protocol.RegexpParam{
-			ipnet.IP4: {
-				URL:    protocol.Switchable{}, //nolint:exhaustruct
-				Regexp: regexp.MustCompile(``),
-			},
-		},
-	}).HasAlternative(ipnet.IP4))
-}
diff --git a/internal/provider/protocol/switch_test.go b/internal/provider/protocol/switch_test.go
deleted file mode 100644
index 5d870a8..0000000
--- a/internal/provider/protocol/switch_test.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package protocol_test
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/require"
-
-	"github.com/favonia/cloudflare-ddns/internal/provider/protocol"
-)
-
-func TestConstant(t *testing.T) {
-	t.Parallel()
-	s := protocol.Constant("very secret string")
-	require.Equal(t, "very secret string", s.Switch(protocol.MethodPrimary))
-	require.Equal(t, "very secret string", s.Switch(protocol.MethodAlternative))
-	require.False(t, s.HasAlternative())
-}
-
-func TestSwitchable(t *testing.T) {
-	t.Parallel()
-	s := protocol.Switchable{Primary: "very secret string 1", Alternative: "very secret string 2"}
-	require.Equal(t, "very secret string 1", s.Switch(protocol.MethodPrimary))
-	require.Equal(t, "very secret string 2", s.Switch(protocol.MethodAlternative))
-	require.True(t, s.HasAlternative())
-}
diff --git a/internal/updater/updater_test.go b/internal/updater/updater_test.go
index bed1ddd..f131391 100644
--- a/internal/updater/updater_test.go
+++ b/internal/updater/updater_test.go
@@ -18,7 +18,6 @@ import (
 	"github.com/favonia/cloudflare-ddns/internal/monitor"
 	"github.com/favonia/cloudflare-ddns/internal/notifier"
 	"github.com/favonia/cloudflare-ddns/internal/pp"
-	"github.com/favonia/cloudflare-ddns/internal/provider"
 	"github.com/favonia/cloudflare-ddns/internal/setter"
 	"github.com/favonia/cloudflare-ddns/internal/updater"
 )
@@ -102,7 +101,7 @@ func TestUpdateIPsMultiple(t *testing.T) {
 			providerEnablers{ipnet.IP4: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodPrimary, true),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello1"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseUpdating),
@@ -130,7 +129,7 @@ func TestUpdateIPsMultiple(t *testing.T) {
 			providerEnablers{ipnet.IP4: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodPrimary, true),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello1"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseUpdated),
@@ -275,10 +274,6 @@ func TestFinalDeleteIPsMultiple(t *testing.T) {
 	}
 }
 
-func expectHint1111Blockage(p *mocks.MockPP) *mocks.PPHintfCall {
-	return p.EXPECT().Hintf(pp.Hint1111Blockage, "%s", provider.Hint1111BlocakageText)
-}
-
 func TestUpdateIPs(t *testing.T) {
 	t.Parallel()
 
@@ -304,7 +299,7 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodPrimary, true),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseNoop),
@@ -319,7 +314,7 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodPrimary, true),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseFailed),
@@ -334,7 +329,7 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodPrimary, true),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseUpdating),
@@ -349,7 +344,7 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP6: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, provider.MethodPrimary, true),
+					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv6", ip6),
 					p.EXPECT().SuppressHint(pp.HintIP6DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP6, domain.FQDN("ip6.hello"), ip6, api.TTLAuto, false, recordComment).Return(setter.ResponseUpdated),
@@ -364,7 +359,7 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP6: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, provider.MethodPrimary, true),
+					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv6", ip6),
 					p.EXPECT().SuppressHint(pp.HintIP6DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP6, domain.FQDN("ip6.hello"), ip6, api.TTLAuto, false, recordComment).Return(setter.ResponseFailed),
@@ -377,12 +372,11 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true, ipnet.IP6: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodAlternative, true),
-					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v (using 1.0.0.1)", "IPv4", ip4),
-					expectHint1111Blockage(p),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
+					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseNoop),
-					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, provider.MethodPrimary, true),
+					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv6", ip6),
 					p.EXPECT().SuppressHint(pp.HintIP6DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP6, domain.FQDN("ip6.hello"), ip6, api.TTLAuto, false, recordComment).Return(setter.ResponseNoop),
@@ -397,12 +391,11 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true, ipnet.IP6: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodAlternative, true),
-					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v (using 1.0.0.1)", "IPv4", ip4),
-					expectHint1111Blockage(p),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
+					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseFailed),
-					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, provider.MethodPrimary, true),
+					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv6", ip6),
 					p.EXPECT().SuppressHint(pp.HintIP6DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP6, domain.FQDN("ip6.hello"), ip6, api.TTLAuto, false, recordComment).Return(setter.ResponseNoop),
@@ -417,12 +410,11 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true, ipnet.IP6: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodAlternative, true),
-					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v (using 1.0.0.1)", "IPv4", ip4),
-					expectHint1111Blockage(p),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
+					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseNoop),
-					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, provider.MethodPrimary, true),
+					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv6", ip6),
 					p.EXPECT().SuppressHint(pp.HintIP6DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP6, domain.FQDN("ip6.hello"), ip6, api.TTLAuto, false, recordComment).Return(setter.ResponseFailed),
@@ -437,12 +429,11 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true, ipnet.IP6: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodAlternative, true),
-					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v (using 1.0.0.1)", "IPv4", ip4),
-					expectHint1111Blockage(p),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
+					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseNoop),
-					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, provider.MethodPrimary, true),
+					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv6", ip6),
 					p.EXPECT().SuppressHint(pp.HintIP6DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP6, domain.FQDN("ip6.hello"), ip6, api.TTLAuto, false, recordComment).Return(setter.ResponseNoop),
@@ -457,10 +448,10 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true, ipnet.IP6: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(netip.Addr{}, provider.MethodUnspecified, false),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(netip.Addr{}, false),
 					p.EXPECT().Noticef(pp.EmojiError, "Failed to detect the %s address", "IPv4"),
 					p.EXPECT().Hintf(pp.HintIP4DetectionFails, "If your network does not support IPv4, you can disable it with IP4_PROVIDER=none"),
-					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, provider.MethodPrimary, true),
+					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(ip6, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv6", ip6),
 					p.EXPECT().SuppressHint(pp.HintIP6DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP6, domain.FQDN("ip6.hello"), ip6, api.TTLAuto, false, recordComment).Return(setter.ResponseNoop),
@@ -475,12 +466,11 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true, ipnet.IP6: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodAlternative, true),
-					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v (using 1.0.0.1)", "IPv4", ip4),
-					expectHint1111Blockage(p),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
+					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseNoop),
-					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(netip.Addr{}, provider.MethodUnspecified, false),
+					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(netip.Addr{}, false),
 					p.EXPECT().Noticef(pp.EmojiError, "Failed to detect the %s address", "IPv6"),
 					hintIP6DetectionFails(p),
 					s.EXPECT().SetWAFList(gomock.Any(), p, list, wafListDescription, detectedIPs{ipnet.IP4: ip4, ipnet.IP6: netip.Addr{}}, ""),
@@ -494,10 +484,10 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true, ipnet.IP6: true},
 			func(p *mocks.MockPP, pv mockProviders, _ *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(netip.Addr{}, provider.MethodUnspecified, false),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(netip.Addr{}, false),
 					p.EXPECT().Noticef(pp.EmojiError, "Failed to detect the %s address", "IPv4"),
 					p.EXPECT().Hintf(pp.HintIP4DetectionFails, "If your network does not support IPv4, you can disable it with IP4_PROVIDER=none"),
-					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(netip.Addr{}, provider.MethodUnspecified, false),
+					pv[ipnet.IP6].EXPECT().GetIP(gomock.Any(), p, ipnet.IP6).Return(netip.Addr{}, false),
 					p.EXPECT().Noticef(pp.EmojiError, "Failed to detect the %s address", "IPv6"),
 					hintIP6DetectionFails(p),
 				)
@@ -511,9 +501,9 @@ func TestUpdateIPs(t *testing.T) {
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
 					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).DoAndReturn(
-						func(context.Context, pp.PP, ipnet.Type) (netip.Addr, provider.Method, bool) {
+						func(context.Context, pp.PP, ipnet.Type) (netip.Addr, bool) {
 							time.Sleep(2 * time.Second)
-							return netip.Addr{}, provider.MethodUnspecified, false
+							return netip.Addr{}, false
 						},
 					),
 					p.EXPECT().Noticef(pp.EmojiError, "Failed to detect the %s address", "IPv4"),
@@ -530,7 +520,7 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodPrimary, true),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello"), ip4, api.TTLAuto, false, recordComment).DoAndReturn(
@@ -550,7 +540,7 @@ func TestUpdateIPs(t *testing.T) {
 			providerEnablers{ipnet.IP4: true},
 			func(p *mocks.MockPP, pv mockProviders, s *mocks.MockSetter) {
 				gomock.InOrder(
-					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, provider.MethodPrimary, true),
+					pv[ipnet.IP4].EXPECT().GetIP(gomock.Any(), p, ipnet.IP4).Return(ip4, true),
 					p.EXPECT().Infof(pp.EmojiInternet, "Detected the %s address %v", "IPv4", ip4),
 					p.EXPECT().SuppressHint(pp.HintIP4DetectionFails),
 					s.EXPECT().Set(gomock.Any(), p, ipnet.IP4, domain.FQDN("ip4.hello"), ip4, api.TTLAuto, false, recordComment).Return(setter.ResponseNoop),