mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-07-29 01:18:48 +02:00
@@ -2,7 +2,6 @@ package ctrld
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -13,8 +12,6 @@ import (
|
|||||||
"github.com/Control-D-Inc/ctrld/internal/dnsrcode"
|
"github.com/Control-D-Inc/ctrld/internal/dnsrcode"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
"github.com/quic-go/quic-go"
|
|
||||||
"github.com/quic-go/quic-go/http3"
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -95,14 +92,14 @@ type NetworkConfig struct {
|
|||||||
|
|
||||||
// UpstreamConfig specifies configuration for upstreams that ctrld will forward requests to.
|
// UpstreamConfig specifies configuration for upstreams that ctrld will forward requests to.
|
||||||
type UpstreamConfig struct {
|
type UpstreamConfig struct {
|
||||||
Name string `mapstructure:"name" toml:"name,omitempty"`
|
Name string `mapstructure:"name" toml:"name,omitempty"`
|
||||||
Type string `mapstructure:"type" toml:"type,omitempty" validate:"oneof=doh doh3 dot doq os legacy"`
|
Type string `mapstructure:"type" toml:"type,omitempty" validate:"oneof=doh doh3 dot doq os legacy"`
|
||||||
Endpoint string `mapstructure:"endpoint" toml:"endpoint,omitempty" validate:"required_unless=Type os"`
|
Endpoint string `mapstructure:"endpoint" toml:"endpoint,omitempty" validate:"required_unless=Type os"`
|
||||||
BootstrapIP string `mapstructure:"bootstrap_ip" toml:"bootstrap_ip,omitempty"`
|
BootstrapIP string `mapstructure:"bootstrap_ip" toml:"bootstrap_ip,omitempty"`
|
||||||
Domain string `mapstructure:"-" toml:"-"`
|
Domain string `mapstructure:"-" toml:"-"`
|
||||||
Timeout int `mapstructure:"timeout" toml:"timeout,omitempty" validate:"gte=0"`
|
Timeout int `mapstructure:"timeout" toml:"timeout,omitempty" validate:"gte=0"`
|
||||||
transport *http.Transport `mapstructure:"-" toml:"-"`
|
transport *http.Transport `mapstructure:"-" toml:"-"`
|
||||||
http3RoundTripper *http3.RoundTripper `mapstructure:"-" toml:"-"`
|
http3RoundTripper http.RoundTripper `mapstructure:"-" toml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenerConfig specifies the networks configuration that ctrld will run on.
|
// ListenerConfig specifies the networks configuration that ctrld will run on.
|
||||||
@@ -179,33 +176,6 @@ func (uc *UpstreamConfig) setupDOHTransport() {
|
|||||||
uc.pingUpstream()
|
uc.pingUpstream()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uc *UpstreamConfig) setupDOH3Transport() {
|
|
||||||
uc.http3RoundTripper = &http3.RoundTripper{}
|
|
||||||
uc.http3RoundTripper.Dial = func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
|
||||||
host := addr
|
|
||||||
ProxyLog.Debug().Msgf("debug dial context D0H3 %s - %s", addr, bootstrapDNS)
|
|
||||||
// if we have a bootstrap ip set, use it to avoid DNS lookup
|
|
||||||
if uc.BootstrapIP != "" {
|
|
||||||
if _, port, _ := net.SplitHostPort(addr); port != "" {
|
|
||||||
addr = net.JoinHostPort(uc.BootstrapIP, port)
|
|
||||||
}
|
|
||||||
ProxyLog.Debug().Msgf("sending doh3 request to: %s", addr)
|
|
||||||
}
|
|
||||||
remoteAddr, err := net.ResolveUDPAddr("udp", addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
udpConn, err := net.ListenUDP("udp", nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return quic.DialEarlyContext(ctx, udpConn, remoteAddr, host, tlsCfg, cfg)
|
|
||||||
}
|
|
||||||
|
|
||||||
uc.pingUpstream()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (uc *UpstreamConfig) pingUpstream() {
|
func (uc *UpstreamConfig) pingUpstream() {
|
||||||
// Warming up the transport by querying a test packet.
|
// Warming up the transport by querying a test packet.
|
||||||
dnsResolver, err := NewResolver(uc)
|
dnsResolver, err := NewResolver(uc)
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
//go:build !qf
|
||||||
|
|
||||||
|
package ctrld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/quic-go/quic-go"
|
||||||
|
"github.com/quic-go/quic-go/http3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (uc *UpstreamConfig) setupDOH3Transport() {
|
||||||
|
rt := &http3.RoundTripper{}
|
||||||
|
rt.Dial = func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
||||||
|
host := addr
|
||||||
|
ProxyLog.Debug().Msgf("debug dial context D0H3 %s - %s", addr, bootstrapDNS)
|
||||||
|
// if we have a bootstrap ip set, use it to avoid DNS lookup
|
||||||
|
if uc.BootstrapIP != "" {
|
||||||
|
if _, port, _ := net.SplitHostPort(addr); port != "" {
|
||||||
|
addr = net.JoinHostPort(uc.BootstrapIP, port)
|
||||||
|
}
|
||||||
|
ProxyLog.Debug().Msgf("sending doh3 request to: %s", addr)
|
||||||
|
}
|
||||||
|
remoteAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
udpConn, err := net.ListenUDP("udp", nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return quic.DialEarlyContext(ctx, udpConn, remoteAddr, host, tlsCfg, cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
uc.http3RoundTripper = rt
|
||||||
|
uc.pingUpstream()
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build qf
|
||||||
|
|
||||||
|
package ctrld
|
||||||
|
|
||||||
|
func (uc *UpstreamConfig) setupDOH3Transport() {}
|
||||||
@@ -3,12 +3,12 @@ package ctrld
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
"github.com/quic-go/quic-go/http3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func newDohResolver(uc *UpstreamConfig) *dohResolver {
|
func newDohResolver(uc *UpstreamConfig) *dohResolver {
|
||||||
@@ -25,7 +25,7 @@ type dohResolver struct {
|
|||||||
endpoint string
|
endpoint string
|
||||||
isDoH3 bool
|
isDoH3 bool
|
||||||
transport *http.Transport
|
transport *http.Transport
|
||||||
http3RoundTripper *http3.RoundTripper
|
http3RoundTripper http.RoundTripper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *dohResolver) Resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, error) {
|
func (r *dohResolver) Resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, error) {
|
||||||
@@ -44,12 +44,17 @@ func (r *dohResolver) Resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, erro
|
|||||||
|
|
||||||
c := http.Client{Transport: r.transport}
|
c := http.Client{Transport: r.transport}
|
||||||
if r.isDoH3 {
|
if r.isDoH3 {
|
||||||
|
if r.http3RoundTripper == nil {
|
||||||
|
return nil, errors.New("DoH3 is not supported")
|
||||||
|
}
|
||||||
c.Transport = r.http3RoundTripper
|
c.Transport = r.http3RoundTripper
|
||||||
}
|
}
|
||||||
resp, err := c.Do(req)
|
resp, err := c.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if r.isDoH3 {
|
if r.isDoH3 {
|
||||||
r.http3RoundTripper.Close()
|
if closer, ok := r.http3RoundTripper.(io.Closer); ok {
|
||||||
|
closer.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("could not perform request: %w", err)
|
return nil, fmt.Errorf("could not perform request: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
//go:build qf
|
||||||
|
|
||||||
|
package ctrld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type doqResolver struct {
|
||||||
|
uc *UpstreamConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *doqResolver) Resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, error) {
|
||||||
|
return nil, errors.New("DoQ is not supported")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user