mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-02-16 10:22:45 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a23feaf4b | ||
|
|
b82ad3720c | ||
|
|
8d2cb6091e | ||
|
|
3023f33dff | ||
|
|
22e97e981a | ||
|
|
44484e1231 | ||
|
|
eac60b87c7 | ||
|
|
8db28cb76e | ||
|
|
8dbe828b99 | ||
|
|
5c24acd952 |
@@ -146,6 +146,7 @@ func initCLI() {
|
|||||||
_ = runCmd.Flags().MarkHidden("iface")
|
_ = runCmd.Flags().MarkHidden("iface")
|
||||||
runCmd.Flags().StringVarP(&cdUpstreamProto, "proto", "", ctrld.ResolverTypeDOH, `Control D upstream type, either "doh" or "doh3"`)
|
runCmd.Flags().StringVarP(&cdUpstreamProto, "proto", "", ctrld.ResolverTypeDOH, `Control D upstream type, either "doh" or "doh3"`)
|
||||||
|
|
||||||
|
runCmd.FParseErrWhitelist = cobra.FParseErrWhitelist{UnknownFlags: true}
|
||||||
rootCmd.AddCommand(runCmd)
|
rootCmd.AddCommand(runCmd)
|
||||||
|
|
||||||
startCmd := &cobra.Command{
|
startCmd := &cobra.Command{
|
||||||
@@ -206,7 +207,11 @@ func initCLI() {
|
|||||||
defaultConfigFile = filepath.Join(dir, defaultConfigFile)
|
defaultConfigFile = filepath.Join(dir, defaultConfigFile)
|
||||||
}
|
}
|
||||||
sc.Arguments = append(sc.Arguments, "--homedir="+dir)
|
sc.Arguments = append(sc.Arguments, "--homedir="+dir)
|
||||||
sockPath := filepath.Join(dir, ctrldLogUnixSock)
|
sockDir := dir
|
||||||
|
if d, err := socketDir(); err == nil {
|
||||||
|
sockDir = d
|
||||||
|
}
|
||||||
|
sockPath := filepath.Join(sockDir, ctrldLogUnixSock)
|
||||||
_ = os.Remove(sockPath)
|
_ = os.Remove(sockPath)
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -393,7 +398,7 @@ func initCLI() {
|
|||||||
{s.Start, true},
|
{s.Start, true},
|
||||||
}
|
}
|
||||||
if doTasks(tasks) {
|
if doTasks(tasks) {
|
||||||
dir, err := userHomeDir()
|
dir, err := socketDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mainLog.Load().Warn().Err(err).Msg("Service was restarted, but could not ping the control server")
|
mainLog.Load().Warn().Err(err).Msg("Service was restarted, but could not ping the control server")
|
||||||
return
|
return
|
||||||
@@ -416,7 +421,7 @@ func initCLI() {
|
|||||||
Short: "Reload the ctrld service",
|
Short: "Reload the ctrld service",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
dir, err := userHomeDir()
|
dir, err := socketDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mainLog.Load().Fatal().Err(err).Msg("failed to find ctrld home dir")
|
mainLog.Load().Fatal().Err(err).Msg("failed to find ctrld home dir")
|
||||||
}
|
}
|
||||||
@@ -688,7 +693,7 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`,
|
|||||||
checkHasElevatedPrivilege()
|
checkHasElevatedPrivilege()
|
||||||
},
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
dir, err := userHomeDir()
|
dir, err := socketDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mainLog.Load().Fatal().Err(err).Msg("failed to find ctrld home dir")
|
mainLog.Load().Fatal().Err(err).Msg("failed to find ctrld home dir")
|
||||||
}
|
}
|
||||||
@@ -790,7 +795,11 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
|
|||||||
homedir = dir
|
homedir = dir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sockPath := filepath.Join(homedir, ctrldLogUnixSock)
|
sockDir := homedir
|
||||||
|
if d, err := socketDir(); err == nil {
|
||||||
|
sockDir = d
|
||||||
|
}
|
||||||
|
sockPath := filepath.Join(sockDir, ctrldLogUnixSock)
|
||||||
if addr, err := net.ResolveUnixAddr("unix", sockPath); err == nil {
|
if addr, err := net.ResolveUnixAddr("unix", sockPath); err == nil {
|
||||||
if conn, err := net.Dial(addr.Network(), addr.String()); err == nil {
|
if conn, err := net.Dial(addr.Network(), addr.String()); err == nil {
|
||||||
lc := &logConn{conn: conn}
|
lc := &logConn{conn: conn}
|
||||||
@@ -842,7 +851,7 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.router = router.New(&cfg, cdUID != "")
|
p.router = router.New(&cfg, cdUID != "")
|
||||||
cs, err := newControlServer(filepath.Join(homedir, ctrldControlUnixSock))
|
cs, err := newControlServer(filepath.Join(sockDir, ctrldControlUnixSock))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mainLog.Load().Warn().Err(err).Msg("could not create control server")
|
mainLog.Load().Warn().Err(err).Msg("could not create control server")
|
||||||
}
|
}
|
||||||
@@ -1295,7 +1304,7 @@ func selfCheckStatus(s service.Service) service.Status {
|
|||||||
if status != service.StatusRunning {
|
if status != service.StatusRunning {
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
dir, err := userHomeDir()
|
dir, err := socketDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mainLog.Load().Error().Err(err).Msg("failed to check ctrld listener status: could not get home directory")
|
mainLog.Load().Error().Err(err).Msg("failed to check ctrld listener status: could not get home directory")
|
||||||
return service.StatusUnknown
|
return service.StatusUnknown
|
||||||
@@ -1447,6 +1456,19 @@ func userHomeDir() (string, error) {
|
|||||||
return dir, nil
|
return dir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// socketDir returns directory that ctrld will create socket file for running controlServer.
|
||||||
|
func socketDir() (string, error) {
|
||||||
|
switch {
|
||||||
|
case runtime.GOOS == "windows", isMobile():
|
||||||
|
return userHomeDir()
|
||||||
|
}
|
||||||
|
dir := "/var/run"
|
||||||
|
if ok, _ := dirWritable(dir); !ok {
|
||||||
|
return userHomeDir()
|
||||||
|
}
|
||||||
|
return dir, nil
|
||||||
|
}
|
||||||
|
|
||||||
// tryReadingConfig is like tryReadingConfigWithNotice, with notice set to false.
|
// tryReadingConfig is like tryReadingConfigWithNotice, with notice set to false.
|
||||||
func tryReadingConfig(writeDefaultConfig bool) {
|
func tryReadingConfig(writeDefaultConfig bool) {
|
||||||
tryReadingConfigWithNotice(writeDefaultConfig, false)
|
tryReadingConfigWithNotice(writeDefaultConfig, false)
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ type upstreamForResult struct {
|
|||||||
matchedNetwork string
|
matchedNetwork string
|
||||||
matchedRule string
|
matchedRule string
|
||||||
matched bool
|
matched bool
|
||||||
|
srcAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prog) serveDNS(listenerNum string) error {
|
func (p *prog) serveDNS(listenerNum string) error {
|
||||||
@@ -97,9 +98,9 @@ func (p *prog) serveDNS(listenerNum string) error {
|
|||||||
ci.ClientIDPref = p.cfg.Service.ClientIDPref
|
ci.ClientIDPref = p.cfg.Service.ClientIDPref
|
||||||
stripClientSubnet(m)
|
stripClientSubnet(m)
|
||||||
remoteAddr := spoofRemoteAddr(w.RemoteAddr(), ci)
|
remoteAddr := spoofRemoteAddr(w.RemoteAddr(), ci)
|
||||||
fmtSrcToDest := fmtRemoteToLocal(listenerNum, remoteAddr.String(), w.LocalAddr().String())
|
fmtSrcToDest := fmtRemoteToLocal(listenerNum, ci.Hostname, remoteAddr.String())
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
ctrld.Log(ctx, mainLog.Load().Debug(), "%s received query: %s %s", fmtSrcToDest, dns.TypeToString[q.Qtype], domain)
|
ctrld.Log(ctx, mainLog.Load().Info(), "QUERY: %s: %s %s", fmtSrcToDest, dns.TypeToString[q.Qtype], domain)
|
||||||
res := p.upstreamFor(ctx, listenerNum, listenerConfig, remoteAddr, ci.Mac, domain)
|
res := p.upstreamFor(ctx, listenerNum, listenerConfig, remoteAddr, ci.Mac, domain)
|
||||||
var answer *dns.Msg
|
var answer *dns.Msg
|
||||||
if !res.matched && listenerConfig.Restricted {
|
if !res.matched && listenerConfig.Restricted {
|
||||||
@@ -200,7 +201,7 @@ func (p *prog) upstreamFor(ctx context.Context, defaultUpstreamNum string, lc *c
|
|||||||
matchedNetwork := "no network"
|
matchedNetwork := "no network"
|
||||||
matchedRule := "no rule"
|
matchedRule := "no rule"
|
||||||
matched := false
|
matched := false
|
||||||
res = &upstreamForResult{}
|
res = &upstreamForResult{srcAddr: addr.String()}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
res.upstreams = upstreams
|
res.upstreams = upstreams
|
||||||
@@ -377,7 +378,7 @@ func (p *prog) proxy(ctx context.Context, req *proxyRequest) *dns.Msg {
|
|||||||
// 4. Try remote upstream.
|
// 4. Try remote upstream.
|
||||||
isLanOrPtrQuery := false
|
isLanOrPtrQuery := false
|
||||||
if req.ufr.matched {
|
if req.ufr.matched {
|
||||||
ctrld.Log(ctx, mainLog.Load().Info(), "%s, %s, %s -> %v", req.ufr.matchedPolicy, req.ufr.matchedNetwork, req.ufr.matchedRule, upstreams)
|
ctrld.Log(ctx, mainLog.Load().Debug(), "%s, %s, %s -> %v", req.ufr.matchedPolicy, req.ufr.matchedNetwork, req.ufr.matchedRule, upstreams)
|
||||||
} else {
|
} else {
|
||||||
switch {
|
switch {
|
||||||
case isPrivatePtrLookup(req.msg):
|
case isPrivatePtrLookup(req.msg):
|
||||||
@@ -386,16 +387,16 @@ func (p *prog) proxy(ctx context.Context, req *proxyRequest) *dns.Msg {
|
|||||||
return answer
|
return answer
|
||||||
}
|
}
|
||||||
upstreams, upstreamConfigs = p.upstreamsAndUpstreamConfigForLanAndPtr(upstreams, upstreamConfigs)
|
upstreams, upstreamConfigs = p.upstreamsAndUpstreamConfigForLanAndPtr(upstreams, upstreamConfigs)
|
||||||
ctrld.Log(ctx, mainLog.Load().Info(), "private PTR lookup, using upstreams: %v", upstreams)
|
ctrld.Log(ctx, mainLog.Load().Debug(), "private PTR lookup, using upstreams: %v", upstreams)
|
||||||
case isLanHostnameQuery(req.msg):
|
case isLanHostnameQuery(req.msg):
|
||||||
isLanOrPtrQuery = true
|
isLanOrPtrQuery = true
|
||||||
if answer := p.proxyLanHostnameQuery(ctx, req.msg); answer != nil {
|
if answer := p.proxyLanHostnameQuery(ctx, req.msg); answer != nil {
|
||||||
return answer
|
return answer
|
||||||
}
|
}
|
||||||
upstreams, upstreamConfigs = p.upstreamsAndUpstreamConfigForLanAndPtr(upstreams, upstreamConfigs)
|
upstreams, upstreamConfigs = p.upstreamsAndUpstreamConfigForLanAndPtr(upstreams, upstreamConfigs)
|
||||||
ctrld.Log(ctx, mainLog.Load().Info(), "lan hostname lookup, using upstreams: %v", upstreams)
|
ctrld.Log(ctx, mainLog.Load().Debug(), "lan hostname lookup, using upstreams: %v", upstreams)
|
||||||
default:
|
default:
|
||||||
ctrld.Log(ctx, mainLog.Load().Info(), "no explicit policy matched, using default routing -> %v", upstreams)
|
ctrld.Log(ctx, mainLog.Load().Debug(), "no explicit policy matched, using default routing -> %v", upstreams)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,6 +504,11 @@ func (p *prog) proxy(ctx context.Context, req *proxyRequest) *dns.Msg {
|
|||||||
p.cache.Add(dnscache.NewKey(req.msg, upstreams[n]), dnscache.NewValue(answer, expired))
|
p.cache.Add(dnscache.NewKey(req.msg, upstreams[n]), dnscache.NewValue(answer, expired))
|
||||||
ctrld.Log(ctx, mainLog.Load().Debug(), "add cached response")
|
ctrld.Log(ctx, mainLog.Load().Debug(), "add cached response")
|
||||||
}
|
}
|
||||||
|
hostname := ""
|
||||||
|
if req.ci != nil {
|
||||||
|
hostname = req.ci.Hostname
|
||||||
|
}
|
||||||
|
ctrld.Log(ctx, mainLog.Load().Info(), "REPLY: %s -> %s (%s): %s", upstreams[n], req.ufr.srcAddr, hostname, dns.RcodeToString[answer.Rcode])
|
||||||
return answer
|
return answer
|
||||||
}
|
}
|
||||||
ctrld.Log(ctx, mainLog.Load().Error(), "all %v endpoints failed", upstreams)
|
ctrld.Log(ctx, mainLog.Load().Error(), "all %v endpoints failed", upstreams)
|
||||||
@@ -564,8 +570,8 @@ func wildcardMatches(wildcard, domain string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func fmtRemoteToLocal(listenerNum, remote, local string) string {
|
func fmtRemoteToLocal(listenerNum, hostname, remote string) string {
|
||||||
return fmt.Sprintf("%s -> listener.%s: %s:", remote, listenerNum, local)
|
return fmt.Sprintf("%s (%s) -> listener.%s", remote, hostname, listenerNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestID() string {
|
func requestID() string {
|
||||||
|
|||||||
@@ -525,6 +525,7 @@ var (
|
|||||||
windowsENETUNREACH = syscall.Errno(10051)
|
windowsENETUNREACH = syscall.Errno(10051)
|
||||||
windowsEINVAL = syscall.Errno(10022)
|
windowsEINVAL = syscall.Errno(10022)
|
||||||
windowsEADDRINUSE = syscall.Errno(10048)
|
windowsEADDRINUSE = syscall.Errno(10048)
|
||||||
|
windowsEHOSTUNREACH = syscall.Errno(10065)
|
||||||
)
|
)
|
||||||
|
|
||||||
func errUrlNetworkError(err error) bool {
|
func errUrlNetworkError(err error) bool {
|
||||||
@@ -547,7 +548,8 @@ func errNetworkError(err error) bool {
|
|||||||
errors.Is(opErr.Err, syscall.ENETUNREACH),
|
errors.Is(opErr.Err, syscall.ENETUNREACH),
|
||||||
errors.Is(opErr.Err, windowsENETUNREACH),
|
errors.Is(opErr.Err, windowsENETUNREACH),
|
||||||
errors.Is(opErr.Err, windowsEINVAL),
|
errors.Is(opErr.Err, windowsEINVAL),
|
||||||
errors.Is(opErr.Err, windowsECONNREFUSED):
|
errors.Is(opErr.Err, windowsECONNREFUSED),
|
||||||
|
errors.Is(opErr.Err, windowsEHOSTUNREACH):
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
@@ -22,45 +21,52 @@ const (
|
|||||||
type upstreamMonitor struct {
|
type upstreamMonitor struct {
|
||||||
cfg *ctrld.Config
|
cfg *ctrld.Config
|
||||||
|
|
||||||
down map[string]*atomic.Bool
|
mu sync.Mutex
|
||||||
failureReq map[string]*atomic.Uint64
|
checking map[string]bool
|
||||||
|
down map[string]bool
|
||||||
mu sync.Mutex
|
failureReq map[string]uint64
|
||||||
checking map[string]bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUpstreamMonitor(cfg *ctrld.Config) *upstreamMonitor {
|
func newUpstreamMonitor(cfg *ctrld.Config) *upstreamMonitor {
|
||||||
um := &upstreamMonitor{
|
um := &upstreamMonitor{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
down: make(map[string]*atomic.Bool),
|
|
||||||
failureReq: make(map[string]*atomic.Uint64),
|
|
||||||
checking: make(map[string]bool),
|
checking: make(map[string]bool),
|
||||||
|
down: make(map[string]bool),
|
||||||
|
failureReq: make(map[string]uint64),
|
||||||
}
|
}
|
||||||
for n := range cfg.Upstream {
|
for n := range cfg.Upstream {
|
||||||
upstream := upstreamPrefix + n
|
upstream := upstreamPrefix + n
|
||||||
um.down[upstream] = new(atomic.Bool)
|
um.reset(upstream)
|
||||||
um.failureReq[upstream] = new(atomic.Uint64)
|
|
||||||
}
|
}
|
||||||
um.down[upstreamOS] = new(atomic.Bool)
|
um.reset(upstreamOS)
|
||||||
um.failureReq[upstreamOS] = new(atomic.Uint64)
|
|
||||||
return um
|
return um
|
||||||
}
|
}
|
||||||
|
|
||||||
// increaseFailureCount increase failed queries count for an upstream by 1.
|
// increaseFailureCount increase failed queries count for an upstream by 1.
|
||||||
func (um *upstreamMonitor) increaseFailureCount(upstream string) {
|
func (um *upstreamMonitor) increaseFailureCount(upstream string) {
|
||||||
failedCount := um.failureReq[upstream].Add(1)
|
um.mu.Lock()
|
||||||
um.down[upstream].Store(failedCount >= maxFailureRequest)
|
defer um.mu.Unlock()
|
||||||
|
|
||||||
|
um.failureReq[upstream] += 1
|
||||||
|
failedCount := um.failureReq[upstream]
|
||||||
|
um.down[upstream] = failedCount >= maxFailureRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// isDown reports whether the given upstream is being marked as down.
|
// isDown reports whether the given upstream is being marked as down.
|
||||||
func (um *upstreamMonitor) isDown(upstream string) bool {
|
func (um *upstreamMonitor) isDown(upstream string) bool {
|
||||||
return um.down[upstream].Load()
|
um.mu.Lock()
|
||||||
|
defer um.mu.Unlock()
|
||||||
|
|
||||||
|
return um.down[upstream]
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset marks an upstream as up and set failed queries counter to zero.
|
// reset marks an upstream as up and set failed queries counter to zero.
|
||||||
func (um *upstreamMonitor) reset(upstream string) {
|
func (um *upstreamMonitor) reset(upstream string) {
|
||||||
um.failureReq[upstream].Store(0)
|
um.mu.Lock()
|
||||||
um.down[upstream].Store(false)
|
defer um.mu.Unlock()
|
||||||
|
|
||||||
|
um.failureReq[upstream] = 0
|
||||||
|
um.down[upstream] = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkUpstream checks the given upstream status, periodically sending query to upstream
|
// checkUpstream checks the given upstream status, periodically sending query to upstream
|
||||||
@@ -74,6 +80,11 @@ func (um *upstreamMonitor) checkUpstream(upstream string, uc *ctrld.UpstreamConf
|
|||||||
}
|
}
|
||||||
um.checking[upstream] = true
|
um.checking[upstream] = true
|
||||||
um.mu.Unlock()
|
um.mu.Unlock()
|
||||||
|
defer func() {
|
||||||
|
um.mu.Lock()
|
||||||
|
um.checking[upstream] = false
|
||||||
|
um.mu.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
resolver, err := ctrld.NewResolver(uc)
|
resolver, err := ctrld.NewResolver(uc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -412,7 +412,7 @@ If set to `true`, makes the listener `REFUSED` DNS queries from all source IP ad
|
|||||||
- Default: false
|
- Default: false
|
||||||
|
|
||||||
### allow_wan_clients
|
### allow_wan_clients
|
||||||
The listener `REFUSED` DNS queries from WAN clients by default. If set to `true`, makes the listener replies to them.
|
The listener will refuse DNS queries from WAN IPs using `REFUSED` RCODE by default. Set to `true` to disable this behavior, but this is not recommended.
|
||||||
|
|
||||||
- Type: bool
|
- Type: bool
|
||||||
- Required: no
|
- Required: no
|
||||||
|
|||||||
46
doh.go
46
doh.go
@@ -146,61 +146,67 @@ func (r *dohResolver) Resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, erro
|
|||||||
return answer, nil
|
return answer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addHeader adds necessary HTTP header to request based on upstream config.
|
||||||
func addHeader(ctx context.Context, req *http.Request, uc *UpstreamConfig) {
|
func addHeader(ctx context.Context, req *http.Request, uc *UpstreamConfig) {
|
||||||
req.Header.Set("Content-Type", headerApplicationDNS)
|
|
||||||
req.Header.Set("Accept", headerApplicationDNS)
|
|
||||||
|
|
||||||
printed := false
|
printed := false
|
||||||
|
dohHeader := make(http.Header)
|
||||||
if uc.UpstreamSendClientInfo() {
|
if uc.UpstreamSendClientInfo() {
|
||||||
if ci, ok := ctx.Value(ClientInfoCtxKey{}).(*ClientInfo); ok && ci != nil {
|
if ci, ok := ctx.Value(ClientInfoCtxKey{}).(*ClientInfo); ok && ci != nil {
|
||||||
printed = ci.Mac != "" || ci.IP != "" || ci.Hostname != ""
|
printed = ci.Mac != "" || ci.IP != "" || ci.Hostname != ""
|
||||||
switch {
|
switch {
|
||||||
case uc.isControlD():
|
case uc.isControlD():
|
||||||
addControlDHeaders(req, ci)
|
dohHeader = newControlDHeaders(ci)
|
||||||
case uc.isNextDNS():
|
case uc.isNextDNS():
|
||||||
addNextDNSHeaders(req, ci)
|
dohHeader = newNextDNSHeaders(ci)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if printed {
|
if printed {
|
||||||
Log(ctx, ProxyLogger.Load().Debug().Interface("header", req.Header), "sending request header")
|
Log(ctx, ProxyLogger.Load().Debug(), "sending request header: %v", dohHeader)
|
||||||
}
|
}
|
||||||
|
dohHeader.Set("Content-Type", headerApplicationDNS)
|
||||||
|
dohHeader.Set("Accept", headerApplicationDNS)
|
||||||
|
req.Header = dohHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// addControlDHeaders set DoH/Doh3 HTTP request headers for ControlD upstream.
|
// newControlDHeaders returns DoH/Doh3 HTTP request headers for ControlD upstream.
|
||||||
func addControlDHeaders(req *http.Request, ci *ClientInfo) {
|
func newControlDHeaders(ci *ClientInfo) http.Header {
|
||||||
req.Header.Set(dohOsHeader, dohOsHeaderValue())
|
header := make(http.Header)
|
||||||
|
header.Set(dohOsHeader, dohOsHeaderValue())
|
||||||
if ci.Mac != "" {
|
if ci.Mac != "" {
|
||||||
req.Header.Set(dohMacHeader, ci.Mac)
|
header.Set(dohMacHeader, ci.Mac)
|
||||||
}
|
}
|
||||||
if ci.IP != "" {
|
if ci.IP != "" {
|
||||||
req.Header.Set(dohIPHeader, ci.IP)
|
header.Set(dohIPHeader, ci.IP)
|
||||||
}
|
}
|
||||||
if ci.Hostname != "" {
|
if ci.Hostname != "" {
|
||||||
req.Header.Set(dohHostHeader, ci.Hostname)
|
header.Set(dohHostHeader, ci.Hostname)
|
||||||
}
|
}
|
||||||
if ci.Self {
|
if ci.Self {
|
||||||
req.Header.Set(dohOsHeader, dohOsHeaderValue())
|
header.Set(dohOsHeader, dohOsHeaderValue())
|
||||||
}
|
}
|
||||||
switch ci.ClientIDPref {
|
switch ci.ClientIDPref {
|
||||||
case "mac":
|
case "mac":
|
||||||
req.Header.Set(dohClientIDPrefHeader, "1")
|
header.Set(dohClientIDPrefHeader, "1")
|
||||||
case "host":
|
case "host":
|
||||||
req.Header.Set(dohClientIDPrefHeader, "2")
|
header.Set(dohClientIDPrefHeader, "2")
|
||||||
}
|
}
|
||||||
|
return header
|
||||||
}
|
}
|
||||||
|
|
||||||
// addNextDNSHeaders set DoH/Doh3 HTTP request headers for nextdns upstream.
|
// newNextDNSHeaders returns DoH/Doh3 HTTP request headers for nextdns upstream.
|
||||||
// https://github.com/nextdns/nextdns/blob/v1.41.0/resolver/doh.go#L100
|
// https://github.com/nextdns/nextdns/blob/v1.41.0/resolver/doh.go#L100
|
||||||
func addNextDNSHeaders(req *http.Request, ci *ClientInfo) {
|
func newNextDNSHeaders(ci *ClientInfo) http.Header {
|
||||||
|
header := make(http.Header)
|
||||||
if ci.Mac != "" {
|
if ci.Mac != "" {
|
||||||
// https: //github.com/nextdns/nextdns/blob/v1.41.0/run.go#L543
|
// https: //github.com/nextdns/nextdns/blob/v1.41.0/run.go#L543
|
||||||
req.Header.Set("X-Device-Model", "mac:"+ci.Mac[:8])
|
header.Set("X-Device-Model", "mac:"+ci.Mac[:8])
|
||||||
}
|
}
|
||||||
if ci.IP != "" {
|
if ci.IP != "" {
|
||||||
req.Header.Set("X-Device-Ip", ci.IP)
|
header.Set("X-Device-Ip", ci.IP)
|
||||||
}
|
}
|
||||||
if ci.Hostname != "" {
|
if ci.Hostname != "" {
|
||||||
req.Header.Set("X-Device-Name", ci.Hostname)
|
header.Set("X-Device-Name", ci.Hostname)
|
||||||
}
|
}
|
||||||
|
return header
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user