mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-08-10 13:20:33 +02:00
Support query param in upstream value
This commit is contained in:
@@ -110,6 +110,7 @@ type UpstreamConfig struct {
|
|||||||
transport *http.Transport `mapstructure:"-" toml:"-"`
|
transport *http.Transport `mapstructure:"-" toml:"-"`
|
||||||
http3RoundTripper http.RoundTripper `mapstructure:"-" toml:"-"`
|
http3RoundTripper http.RoundTripper `mapstructure:"-" toml:"-"`
|
||||||
certPool *x509.CertPool `mapstructure:"-" toml:"-"`
|
certPool *x509.CertPool `mapstructure:"-" toml:"-"`
|
||||||
|
u *url.URL `mapstructure:"-" toml:"-"`
|
||||||
|
|
||||||
g singleflight.Group
|
g singleflight.Group
|
||||||
bootstrapIPs []string
|
bootstrapIPs []string
|
||||||
@@ -142,6 +143,10 @@ type Rule map[string][]string
|
|||||||
func (uc *UpstreamConfig) Init() {
|
func (uc *UpstreamConfig) Init() {
|
||||||
if u, err := url.Parse(uc.Endpoint); err == nil {
|
if u, err := url.Parse(uc.Endpoint); err == nil {
|
||||||
uc.Domain = u.Host
|
uc.Domain = u.Host
|
||||||
|
switch uc.Type {
|
||||||
|
case ResolverTypeDOH, ResolverTypeDOH3:
|
||||||
|
uc.u = u
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if uc.Domain != "" {
|
if uc.Domain != "" {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package ctrld
|
package ctrld
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUpstreamConfig_SetupBootstrapIP(t *testing.T) {
|
func TestUpstreamConfig_SetupBootstrapIP(t *testing.T) {
|
||||||
@@ -19,3 +22,139 @@ func TestUpstreamConfig_SetupBootstrapIP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log(uc)
|
t.Log(uc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpstreamConfig_Init(t *testing.T) {
|
||||||
|
u1, _ := url.Parse("https://example.com")
|
||||||
|
u2, _ := url.Parse("https://example.com?k=v")
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
uc *UpstreamConfig
|
||||||
|
expected *UpstreamConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"doh+doh3",
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "doh",
|
||||||
|
Type: "doh",
|
||||||
|
Endpoint: "https://example.com",
|
||||||
|
BootstrapIP: "",
|
||||||
|
Domain: "",
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "doh",
|
||||||
|
Type: "doh",
|
||||||
|
Endpoint: "https://example.com",
|
||||||
|
BootstrapIP: "",
|
||||||
|
Domain: "example.com",
|
||||||
|
Timeout: 0,
|
||||||
|
u: u1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doh+doh3 with query param",
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "doh",
|
||||||
|
Type: "doh",
|
||||||
|
Endpoint: "https://example.com?k=v",
|
||||||
|
BootstrapIP: "",
|
||||||
|
Domain: "",
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "doh",
|
||||||
|
Type: "doh",
|
||||||
|
Endpoint: "https://example.com?k=v",
|
||||||
|
BootstrapIP: "",
|
||||||
|
Domain: "example.com",
|
||||||
|
Timeout: 0,
|
||||||
|
u: u2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dot+doq",
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "dot",
|
||||||
|
Type: "dot",
|
||||||
|
Endpoint: "freedns.controld.com:8853",
|
||||||
|
BootstrapIP: "",
|
||||||
|
Domain: "",
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "dot",
|
||||||
|
Type: "dot",
|
||||||
|
Endpoint: "freedns.controld.com:8853",
|
||||||
|
BootstrapIP: "",
|
||||||
|
Domain: "freedns.controld.com",
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dot+doq without port",
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "dot",
|
||||||
|
Type: "dot",
|
||||||
|
Endpoint: "freedns.controld.com",
|
||||||
|
BootstrapIP: "",
|
||||||
|
Domain: "",
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "dot",
|
||||||
|
Type: "dot",
|
||||||
|
Endpoint: "freedns.controld.com:853",
|
||||||
|
BootstrapIP: "",
|
||||||
|
Domain: "freedns.controld.com",
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"legacy",
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "legacy",
|
||||||
|
Type: "legacy",
|
||||||
|
Endpoint: "1.2.3.4:53",
|
||||||
|
BootstrapIP: "",
|
||||||
|
Domain: "",
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "legacy",
|
||||||
|
Type: "legacy",
|
||||||
|
Endpoint: "1.2.3.4:53",
|
||||||
|
BootstrapIP: "1.2.3.4",
|
||||||
|
Domain: "1.2.3.4",
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"legacy without port",
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "legacy",
|
||||||
|
Type: "legacy",
|
||||||
|
Endpoint: "1.2.3.4",
|
||||||
|
BootstrapIP: "",
|
||||||
|
Domain: "",
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
&UpstreamConfig{
|
||||||
|
Name: "legacy",
|
||||||
|
Type: "legacy",
|
||||||
|
Endpoint: "1.2.3.4:53",
|
||||||
|
BootstrapIP: "1.2.3.4",
|
||||||
|
Domain: "1.2.3.4",
|
||||||
|
Timeout: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
tc := tc
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
tc.uc.Init()
|
||||||
|
assert.Equal(t, tc.expected, tc.uc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
-113
@@ -165,116 +165,3 @@ func configWithInvalidRcodes(t *testing.T) *ctrld.Config {
|
|||||||
}
|
}
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpstreamConfig_Init(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
uc *ctrld.UpstreamConfig
|
|
||||||
expected *ctrld.UpstreamConfig
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"doh+doh3",
|
|
||||||
&ctrld.UpstreamConfig{
|
|
||||||
Name: "doh",
|
|
||||||
Type: "doh",
|
|
||||||
Endpoint: "https://example.com",
|
|
||||||
BootstrapIP: "",
|
|
||||||
Domain: "",
|
|
||||||
Timeout: 0,
|
|
||||||
},
|
|
||||||
&ctrld.UpstreamConfig{
|
|
||||||
Name: "doh",
|
|
||||||
Type: "doh",
|
|
||||||
Endpoint: "https://example.com",
|
|
||||||
BootstrapIP: "",
|
|
||||||
Domain: "example.com",
|
|
||||||
Timeout: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dot+doq",
|
|
||||||
&ctrld.UpstreamConfig{
|
|
||||||
Name: "dot",
|
|
||||||
Type: "dot",
|
|
||||||
Endpoint: "freedns.controld.com:8853",
|
|
||||||
BootstrapIP: "",
|
|
||||||
Domain: "",
|
|
||||||
Timeout: 0,
|
|
||||||
},
|
|
||||||
&ctrld.UpstreamConfig{
|
|
||||||
Name: "dot",
|
|
||||||
Type: "dot",
|
|
||||||
Endpoint: "freedns.controld.com:8853",
|
|
||||||
BootstrapIP: "",
|
|
||||||
Domain: "freedns.controld.com",
|
|
||||||
Timeout: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dot+doq without port",
|
|
||||||
&ctrld.UpstreamConfig{
|
|
||||||
Name: "dot",
|
|
||||||
Type: "dot",
|
|
||||||
Endpoint: "freedns.controld.com",
|
|
||||||
BootstrapIP: "",
|
|
||||||
Domain: "",
|
|
||||||
Timeout: 0,
|
|
||||||
},
|
|
||||||
&ctrld.UpstreamConfig{
|
|
||||||
Name: "dot",
|
|
||||||
Type: "dot",
|
|
||||||
Endpoint: "freedns.controld.com:853",
|
|
||||||
BootstrapIP: "",
|
|
||||||
Domain: "freedns.controld.com",
|
|
||||||
Timeout: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"legacy",
|
|
||||||
&ctrld.UpstreamConfig{
|
|
||||||
Name: "legacy",
|
|
||||||
Type: "legacy",
|
|
||||||
Endpoint: "1.2.3.4:53",
|
|
||||||
BootstrapIP: "",
|
|
||||||
Domain: "",
|
|
||||||
Timeout: 0,
|
|
||||||
},
|
|
||||||
&ctrld.UpstreamConfig{
|
|
||||||
Name: "legacy",
|
|
||||||
Type: "legacy",
|
|
||||||
Endpoint: "1.2.3.4:53",
|
|
||||||
BootstrapIP: "1.2.3.4",
|
|
||||||
Domain: "1.2.3.4",
|
|
||||||
Timeout: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"legacy without port",
|
|
||||||
&ctrld.UpstreamConfig{
|
|
||||||
Name: "legacy",
|
|
||||||
Type: "legacy",
|
|
||||||
Endpoint: "1.2.3.4",
|
|
||||||
BootstrapIP: "",
|
|
||||||
Domain: "",
|
|
||||||
Timeout: 0,
|
|
||||||
},
|
|
||||||
&ctrld.UpstreamConfig{
|
|
||||||
Name: "legacy",
|
|
||||||
Type: "legacy",
|
|
||||||
Endpoint: "1.2.3.4:53",
|
|
||||||
BootstrapIP: "1.2.3.4",
|
|
||||||
Domain: "1.2.3.4",
|
|
||||||
Timeout: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
tc := tc
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
tc.uc.Init()
|
|
||||||
assert.Equal(t, tc.expected, tc.uc)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newDohResolver(uc *UpstreamConfig) *dohResolver {
|
func newDohResolver(uc *UpstreamConfig) *dohResolver {
|
||||||
r := &dohResolver{
|
r := &dohResolver{
|
||||||
endpoint: uc.Endpoint,
|
endpoint: uc.u,
|
||||||
isDoH3: uc.Type == ResolverTypeDOH3,
|
isDoH3: uc.Type == ResolverTypeDOH3,
|
||||||
transport: uc.transport,
|
transport: uc.transport,
|
||||||
http3RoundTripper: uc.http3RoundTripper,
|
http3RoundTripper: uc.http3RoundTripper,
|
||||||
@@ -22,7 +23,7 @@ func newDohResolver(uc *UpstreamConfig) *dohResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type dohResolver struct {
|
type dohResolver struct {
|
||||||
endpoint string
|
endpoint *url.URL
|
||||||
isDoH3 bool
|
isDoH3 bool
|
||||||
transport *http.Transport
|
transport *http.Transport
|
||||||
http3RoundTripper http.RoundTripper
|
http3RoundTripper http.RoundTripper
|
||||||
@@ -33,9 +34,14 @@ func (r *dohResolver) Resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
enc := base64.RawURLEncoding.EncodeToString(data)
|
enc := base64.RawURLEncoding.EncodeToString(data)
|
||||||
url := fmt.Sprintf("%s?dns=%s", r.endpoint, enc)
|
query := r.endpoint.Query()
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
query.Add("dns", enc)
|
||||||
|
|
||||||
|
endpoint := *r.endpoint
|
||||||
|
endpoint.RawQuery = query.Encode()
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not create request: %w", err)
|
return nil, fmt.Errorf("could not create request: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user