You've already forked ddns-updater
Add 1.1.1.1 resolver
This commit is contained in:
@@ -17,7 +17,7 @@ Before run, you need configure this environment variables.
|
||||
- `CLOUDFLARE_ZONE` - (required) zone name with domain you want to check. See: [https://developers.cloudflare.com/fundamentals/get-started/concepts/accounts-and-zones/#zones](https://developers.cloudflare.com/fundamentals/get-started/concepts/accounts-and-zones/#zones)
|
||||
- `ON_CHANGE_COMMENT` - (optional) in the event that the ip address of the dns record changes, this comment will be added to the record
|
||||
- `CHECK_INTERVAL_SECONDS` - (optional) how often will the ip address of the records be checked (default: `300`)
|
||||
- `PUBLIC_IP_RESOLVER` - (optional) public ip address resolver. (default: `ifconfig.me`) Available: `ifconfig.me`, `v4.ident.me`
|
||||
- `PUBLIC_IP_RESOLVER` - (optional) public ip address resolver. (default: `ifconfig.me`) Available: `ifconfig.me`, `v4.ident.me`, `1.1.1.1`
|
||||
|
||||
### Building from source
|
||||
|
||||
|
||||
4
main.go
4
main.go
@@ -20,6 +20,8 @@ type PublicIpResolver interface {
|
||||
func getResolver(resolverName string) (PublicIpResolver, string) {
|
||||
switch resolverName {
|
||||
// HERE add another resolver if needed
|
||||
case public_resolvers.CloudflareTraceTag:
|
||||
return public_resolvers.NewDefaultCloudflareTrace(), public_resolvers.CloudflareTraceTag
|
||||
case public_resolvers.V4IdentMeTag:
|
||||
return public_resolvers.NewV4IdentMeDefault(), public_resolvers.V4IdentMeTag
|
||||
case public_resolvers.IfConfigMeTag:
|
||||
@@ -57,7 +59,7 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("Current public ip `%s` (%s)", currentPublicIP, resolverTag)
|
||||
log.Printf("Current public ip `%s` (resolver: %s)", currentPublicIP, resolverTag)
|
||||
|
||||
dns, err := allDNSRecords(ctx, api, cloudflare.ZoneIdentifier(zoneID))
|
||||
if err != nil {
|
||||
|
||||
@@ -2,19 +2,30 @@ package public_resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var NoIPInResponseError = errors.New("no ip found in response")
|
||||
|
||||
type Doer interface {
|
||||
Do(*http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
type ipParserFunc func(reader io.Reader) (string, error)
|
||||
|
||||
func defaultIpParser(reader io.Reader) (string, error) {
|
||||
out, err := io.ReadAll(reader)
|
||||
return string(out), err
|
||||
}
|
||||
|
||||
type baseResolver struct {
|
||||
client Doer
|
||||
url string
|
||||
client Doer
|
||||
url string
|
||||
ipParser ipParserFunc
|
||||
}
|
||||
|
||||
func (i baseResolver) ResolvePublicIp(ctx context.Context) (net.IP, error) {
|
||||
@@ -35,10 +46,10 @@ func (i baseResolver) ResolvePublicIp(ctx context.Context) (net.IP, error) {
|
||||
return net.IP{}, fmt.Errorf("unexpected response code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
ipText, err := io.ReadAll(resp.Body)
|
||||
ipText, err := i.ipParser(resp.Body)
|
||||
if err != nil {
|
||||
return net.IP{}, fmt.Errorf("error reading body: %w", err)
|
||||
}
|
||||
|
||||
return net.ParseIP(string(ipText)), nil
|
||||
return net.ParseIP(ipText), nil
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// NewTestClient returns *http.Client with Transport replaced to avoid making real calls
|
||||
func NewTestClient(fn RoundTripFunc) *http.Client {
|
||||
return &http.Client{
|
||||
Transport: RoundTripFunc(fn),
|
||||
Transport: fn,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ func Test_baseResolver_ResolvePublicIp(t *testing.T) {
|
||||
type fields struct {
|
||||
client Doer
|
||||
url string
|
||||
fn ipParserFunc
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -70,6 +71,7 @@ func Test_baseResolver_ResolvePublicIp(t *testing.T) {
|
||||
fields: fields{
|
||||
client: client,
|
||||
url: testUrl,
|
||||
fn: defaultIpParser,
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -81,8 +83,9 @@ func Test_baseResolver_ResolvePublicIp(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
i := baseResolver{
|
||||
client: tt.fields.client,
|
||||
url: tt.fields.url,
|
||||
client: tt.fields.client,
|
||||
url: tt.fields.url,
|
||||
ipParser: tt.fields.fn,
|
||||
}
|
||||
got, err := i.ResolvePublicIp(tt.args.ctx)
|
||||
if (err != nil) != tt.wantErr {
|
||||
|
||||
49
public_resolvers/cloudflare_trace.go
Normal file
49
public_resolvers/cloudflare_trace.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package public_resolvers
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
CloudflareTraceTag = "1.1.1.1"
|
||||
CloudflareTraceUrl = "https://1.1.1.1/cdn-cgi/trace"
|
||||
|
||||
ipPrefix = "ip="
|
||||
)
|
||||
|
||||
type CloudflareTrace struct {
|
||||
baseResolver
|
||||
}
|
||||
|
||||
func NewDefaultCloudflareTrace() *CloudflareTrace {
|
||||
return NewCloudflareTrace(&http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
})
|
||||
}
|
||||
|
||||
func cloudflareTraceResponseParser(reader io.Reader) (string, error) {
|
||||
data, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, row := range strings.Split(string(data), "\n") {
|
||||
if strings.Index(row, ipPrefix) == 0 {
|
||||
return strings.TrimSpace(strings.ReplaceAll(row, ipPrefix, "")), nil
|
||||
}
|
||||
}
|
||||
return "", NoIPInResponseError
|
||||
}
|
||||
|
||||
func NewCloudflareTrace(client Doer) *CloudflareTrace {
|
||||
return &CloudflareTrace{
|
||||
baseResolver: baseResolver{
|
||||
client: client,
|
||||
url: CloudflareTraceUrl,
|
||||
ipParser: cloudflareTraceResponseParser,
|
||||
},
|
||||
}
|
||||
}
|
||||
78
public_resolvers/cloudflare_trace_test.go
Normal file
78
public_resolvers/cloudflare_trace_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package public_resolvers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_cloudflareTraceResponseParser(t *testing.T) {
|
||||
|
||||
type args struct {
|
||||
reader io.Reader
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "ok",
|
||||
args: args{
|
||||
reader: bytes.NewBuffer([]byte(`fl=31f118
|
||||
h=1.1.1.1
|
||||
ip=94.113.142.206
|
||||
ts=1683145336.383
|
||||
visit_scheme=https
|
||||
uag=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
|
||||
colo=PRG
|
||||
sliver=none
|
||||
http=http/2
|
||||
loc=CZ
|
||||
tls=TLSv1.3
|
||||
sni=off
|
||||
warp=off
|
||||
gateway=off
|
||||
rbi=off
|
||||
kex=X25519`)),
|
||||
},
|
||||
want: "94.113.142.206",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "no ip in response",
|
||||
args: args{
|
||||
reader: bytes.NewBuffer([]byte(`fl=31f118
|
||||
h=1.1.1.1
|
||||
ts=1683145336.383
|
||||
visit_scheme=https
|
||||
uag=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
|
||||
colo=PRG
|
||||
sliver=none
|
||||
http=http/2
|
||||
loc=CZ
|
||||
tls=TLSv1.3
|
||||
sni=off
|
||||
warp=off
|
||||
gateway=off
|
||||
rbi=off
|
||||
kex=X25519`)),
|
||||
},
|
||||
want: "",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := cloudflareTraceResponseParser(tt.args.reader)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("cloudflareTraceResponseParser() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("cloudflareTraceResponseParser() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -23,8 +23,9 @@ func NewDefaultIfConfigMe() *IfConfigMe {
|
||||
func NewIfConfigMe(client Doer) *IfConfigMe {
|
||||
return &IfConfigMe{
|
||||
baseResolver: baseResolver{
|
||||
client: client,
|
||||
url: ifConfigMeUrl,
|
||||
client: client,
|
||||
url: ifConfigMeUrl,
|
||||
ipParser: defaultIpParser,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,9 @@ func NewV4IdentMeDefault() *V4IdentMe {
|
||||
func NewV4IdentMe(client Doer) *V4IdentMe {
|
||||
return &V4IdentMe{
|
||||
baseResolver: baseResolver{
|
||||
client: client,
|
||||
url: v4IdentMeUrl,
|
||||
client: client,
|
||||
url: v4IdentMeUrl,
|
||||
ipParser: defaultIpParser,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user