Skip to content

Commit

Permalink
Merge pull request #194 from Control-D-Inc/release-branch-v1.3.11
Browse files Browse the repository at this point in the history
Release branch v1.3.11
  • Loading branch information
cuonglm authored Nov 20, 2024
2 parents 5b9ccc5 + 484643e commit 09495f2
Show file tree
Hide file tree
Showing 16 changed files with 93 additions and 133 deletions.
2 changes: 1 addition & 1 deletion cmd/cli/ad_others.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ import (
)

// addExtraSplitDnsRule adds split DNS rule if present.
func addExtraSplitDnsRule(_ *ctrld.Config) {}
func addExtraSplitDnsRule(_ *ctrld.Config) bool { return false }
12 changes: 8 additions & 4 deletions cmd/cli/ad_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ import (
)

// addExtraSplitDnsRule adds split DNS rule for domain if it's part of active directory.
func addExtraSplitDnsRule(cfg *ctrld.Config) {
func addExtraSplitDnsRule(cfg *ctrld.Config) bool {
domain, err := getActiveDirectoryDomain()
if err != nil {
mainLog.Load().Debug().Msgf("unable to get active directory domain: %v", err)
return
return false
}
if domain == "" {
mainLog.Load().Debug().Msg("no active directory domain found")
return
return false
}
// Network rules are lowercase during toml config marshaling,
// lowercase the domain here too for consistency.
domain = strings.ToLower(domain)
for n, lc := range cfg.Listener {
if lc.Policy == nil {
lc.Policy = &ctrld.ListenerPolicyConfig{}
Expand All @@ -26,12 +29,13 @@ func addExtraSplitDnsRule(cfg *ctrld.Config) {
for _, rule := range lc.Policy.Rules {
if _, ok := rule[domainRule]; ok {
mainLog.Load().Debug().Msgf("domain rule already exist for listener.%s", n)
return
return false
}
}
mainLog.Load().Debug().Msgf("adding active directory domain for listener.%s", n)
lc.Policy.Rules = append(lc.Policy.Rules, ctrld.Rule{domainRule: []string{}})
}
return true
}

// getActiveDirectoryDomain returns AD domain name of this computer.
Expand Down
31 changes: 20 additions & 11 deletions cmd/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"sort"
"strconv"
"strings"
"sync/atomic"
"time"

"github.com/Masterminds/semver"
Expand Down Expand Up @@ -685,13 +686,14 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`,
var files []string
// Config file.
files = append(files, v.ConfigFileUsed())
// Log file.
logFile := normalizeLogFilePath(cfg.Service.LogPath)
files = append(files, logFile)
// Backup log file.
oldLogFile := logFile + oldLogSuffix
if _, err := os.Stat(oldLogFile); err == nil {
files = append(files, oldLogFile)
// Log file and backup log file.
// For safety, only process if log file path is absolute.
if logFile := normalizeLogFilePath(cfg.Service.LogPath); filepath.IsAbs(logFile) {
files = append(files, logFile)
oldLogFile := logFile + oldLogSuffix
if _, err := os.Stat(oldLogFile); err == nil {
files = append(files, oldLogFile)
}
}
// Socket files.
if dir, _ := socketDir(); dir != "" {
Expand Down Expand Up @@ -1385,7 +1387,6 @@ func run(appCallback *AppCallback, stopCh chan struct{}) {
}

func writeConfigFile(cfg *ctrld.Config) error {
addExtraSplitDnsRule(cfg)
if cfu := v.ConfigFileUsed(); cfu != "" {
defaultConfigFile = cfu
} else if configPath != "" {
Expand Down Expand Up @@ -1438,6 +1439,7 @@ func readConfigFile(writeDefaultConfig, notice bool) bool {
}
nop := zerolog.Nop()
_, _ = tryUpdateListenerConfig(&cfg, &nop, true)
addExtraSplitDnsRule(&cfg)
if err := writeConfigFile(&cfg); err != nil {
mainLog.Load().Fatal().Msgf("failed to write default config file: %v", err)
} else {
Expand Down Expand Up @@ -1551,11 +1553,15 @@ func processNoConfigFlags(noConfigStart bool) {
const defaultDeactivationPin = -1

// cdDeactivationPin is used in cd mode to decide whether stop and uninstall commands can be run.
var cdDeactivationPin int64 = defaultDeactivationPin
var cdDeactivationPin atomic.Int64

func init() {
cdDeactivationPin.Store(defaultDeactivationPin)
}

// deactivationPinNotSet reports whether cdDeactivationPin was not set by processCDFlags.
func deactivationPinNotSet() bool {
return cdDeactivationPin == defaultDeactivationPin
return cdDeactivationPin.Load() == defaultDeactivationPin
}

func processCDFlags(cfg *ctrld.Config) error {
Expand Down Expand Up @@ -1584,7 +1590,7 @@ func processCDFlags(cfg *ctrld.Config) error {

if resolverConfig.DeactivationPin != nil {
logger.Debug().Msg("saving deactivation pin")
cdDeactivationPin = *resolverConfig.DeactivationPin
cdDeactivationPin.Store(*resolverConfig.DeactivationPin)
}

logger.Info().Msg("generating ctrld config from Control-D configuration")
Expand Down Expand Up @@ -2086,6 +2092,9 @@ func mobileListenerIp() string {
// than 127.0.0.1 with systemd-resolved.
func updateListenerConfig(cfg *ctrld.Config) bool {
updated, _ := tryUpdateListenerConfig(cfg, nil, true)
if addExtraSplitDnsRule(cfg) {
updated = true
}
return updated
}

Expand Down
25 changes: 21 additions & 4 deletions cmd/cli/control_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (
"time"

"github.com/kardianos/service"

dto "github.com/prometheus/client_model/go"

"github.com/Control-D-Inc/ctrld"
"github.com/Control-D-Inc/ctrld/internal/controld"
)

const (
Expand Down Expand Up @@ -152,8 +152,25 @@ func (p *prog) registerControlServerHandler() {
w.WriteHeader(http.StatusOK)
}))
p.cs.register(deactivationPath, http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
// Non-cd mode or pin code not set, always allowing deactivation.
if cdUID == "" || deactivationPinNotSet() {
// Non-cd mode always allowing deactivation.
if cdUID == "" {
w.WriteHeader(http.StatusOK)
return
}

// Re-fetch pin code from API.
if rc, err := controld.FetchResolverConfig(cdUID, rootCmd.Version, cdDev); rc != nil {
if rc.DeactivationPin != nil {
cdDeactivationPin.Store(*rc.DeactivationPin)
} else {
cdDeactivationPin.Store(defaultDeactivationPin)
}
} else {
mainLog.Load().Warn().Err(err).Msg("could not re-fetch deactivation pin code")
}

// If pin code not set, allowing deactivation.
if deactivationPinNotSet() {
w.WriteHeader(http.StatusOK)
return
}
Expand All @@ -167,7 +184,7 @@ func (p *prog) registerControlServerHandler() {

code := http.StatusForbidden
switch req.Pin {
case cdDeactivationPin:
case cdDeactivationPin.Load():
code = http.StatusOK
case defaultDeactivationPin:
// If the pin code was set, but users do not provide --pin, return proper code to client.
Expand Down
5 changes: 3 additions & 2 deletions cmd/cli/dns_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -630,14 +630,15 @@ func canonicalName(fqdn string) string {
return q
}

// wildcardMatches reports whether string str matches the wildcard pattern.
// wildcardMatches reports whether string str matches the wildcard pattern in case-insensitive manner.
func wildcardMatches(wildcard, str string) bool {
// Wildcard match.
wildCardParts := strings.Split(wildcard, "*")
wildCardParts := strings.Split(strings.ToLower(wildcard), "*")
if len(wildCardParts) != 2 {
return false
}

str = strings.ToLower(str)
switch {
case len(wildCardParts[0]) > 0 && len(wildCardParts[1]) > 0:
// Domain must match both prefix and suffix.
Expand Down
1 change: 1 addition & 0 deletions cmd/cli/dns_proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func Test_wildcardMatches(t *testing.T) {
{"domain - suffix not match other", "suffix.*", "suffix1.windscribe.com", false},
{"domain - both", "suffix.*.windscribe.com", "suffix.anything.windscribe.com", true},
{"domain - both not match", "suffix.*.windscribe.com", "suffix1.suffix.windscribe.com", false},
{"domain - case-insensitive", "*.WINDSCRIBE.com", "anything.windscribe.com", true},
{"mac - prefix", "*:98:05:b4:2b", "d4:67:98:05:b4:2b", true},
{"mac - prefix not match other s", "*:98:05:b4:2b", "0d:ba:54:09:94:2c", false},
{"mac - prefix not match s in name", "*:98:05:b4:2b", "e4:67:97:05:b4:2b", false},
Expand Down
7 changes: 2 additions & 5 deletions cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,8 @@ func Main() {
}

func normalizeLogFilePath(logFilePath string) string {
// In cleanup mode, we always want the full log file path.
if !cleanup {
if logFilePath == "" || filepath.IsAbs(logFilePath) || service.Interactive() {
return logFilePath
}
if logFilePath == "" || filepath.IsAbs(logFilePath) || service.Interactive() {
return logFilePath
}
if homedir != "" {
return filepath.Join(homedir, logFilePath)
Expand Down
9 changes: 4 additions & 5 deletions cmd/cli/os_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import (
"net/netip"
"os/exec"

"tailscale.com/tsd"
"tailscale.com/control/controlknobs"
"tailscale.com/health"

"github.com/Control-D-Inc/ctrld/internal/dns"
"github.com/Control-D-Inc/ctrld/internal/resolvconffile"
Expand Down Expand Up @@ -38,8 +39,7 @@ func setDnsIgnoreUnusableInterface(iface *net.Interface, nameservers []string) e

// set the dns server for the provided network interface
func setDNS(iface *net.Interface, nameservers []string) error {
sys := new(tsd.System)
r, err := dns.NewOSConfigurator(logf, sys.HealthTracker(), sys.ControlKnobs(), iface.Name)
r, err := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name)
if err != nil {
mainLog.Load().Error().Err(err).Msg("failed to create DNS OS configurator")
return err
Expand All @@ -63,8 +63,7 @@ func resetDnsIgnoreUnusableInterface(iface *net.Interface) error {
}

func resetDNS(iface *net.Interface) error {
sys := new(tsd.System)
r, err := dns.NewOSConfigurator(logf, sys.HealthTracker(), sys.ControlKnobs(), iface.Name)
r, err := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name)
if err != nil {
mainLog.Load().Error().Err(err).Msg("failed to create DNS OS configurator")
return err
Expand Down
10 changes: 4 additions & 6 deletions cmd/cli/os_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import (
"syscall"
"time"

"tailscale.com/tsd"

"github.com/insomniacslk/dhcp/dhcpv4/nclient4"
"github.com/insomniacslk/dhcp/dhcpv6"
"github.com/insomniacslk/dhcp/dhcpv6/client6"
"tailscale.com/control/controlknobs"
"tailscale.com/health"
"tailscale.com/util/dnsname"

"github.com/Control-D-Inc/ctrld/internal/dns"
Expand Down Expand Up @@ -56,8 +56,7 @@ func setDnsIgnoreUnusableInterface(iface *net.Interface, nameservers []string) e
}

func setDNS(iface *net.Interface, nameservers []string) error {
sys := new(tsd.System)
r, err := dns.NewOSConfigurator(logf, sys.HealthTracker(), sys.ControlKnobs(), iface.Name)
r, err := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name)
if err != nil {
mainLog.Load().Error().Err(err).Msg("failed to create DNS OS configurator")
return err
Expand Down Expand Up @@ -139,8 +138,7 @@ func resetDNS(iface *net.Interface) (err error) {
if exe, _ := exec.LookPath("/lib/systemd/systemd-networkd"); exe != "" {
_ = exec.Command("systemctl", "start", "systemd-networkd").Run()
}
sys := new(tsd.System)
if r, oerr := dns.NewOSConfigurator(logf, sys.HealthTracker(), sys.ControlKnobs(), iface.Name); oerr == nil {
if r, oerr := dns.NewOSConfigurator(logf, &health.Tracker{}, &controlknobs.Knobs{}, iface.Name); oerr == nil {
_ = r.SetDNS(dns.OSConfig{})
if err := r.Close(); err != nil {
mainLog.Load().Error().Err(err).Msg("failed to rollback DNS setting")
Expand Down
15 changes: 15 additions & 0 deletions cmd/cli/prog.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ func (p *prog) runWait() {
continue
}

addExtraSplitDnsRule(newCfg)
if err := writeConfigFile(newCfg); err != nil {
logger.Err(err).Msg("could not write new config")
}
Expand Down Expand Up @@ -273,6 +274,20 @@ func (p *prog) apiConfigReload() {
return
}

if resolverConfig.DeactivationPin != nil {
newDeactivationPin := *resolverConfig.DeactivationPin
curDeactivationPin := cdDeactivationPin.Load()
switch {
case curDeactivationPin != defaultDeactivationPin:
logger.Debug().Msg("saving deactivation pin")
case curDeactivationPin != newDeactivationPin:
logger.Debug().Msg("update deactivation pin")
}
cdDeactivationPin.Store(newDeactivationPin)
} else {
cdDeactivationPin.Store(defaultDeactivationPin)
}

if resolverConfig.Ctrld.CustomConfig == "" {
return
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/cli/prog_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import (
"os"
"os/exec"
"strings"
"tailscale.com/tsd"

"github.com/kardianos/service"
"tailscale.com/control/controlknobs"
"tailscale.com/health"

"github.com/Control-D-Inc/ctrld/internal/dns"
)

func init() {
sys := new(tsd.System)
if r, err := dns.NewOSConfigurator(func(format string, args ...any) {}, sys.HealthTracker(), sys.ControlKnobs(), "lo"); err == nil {
if r, err := dns.NewOSConfigurator(func(format string, args ...any) {}, &health.Tracker{}, &controlknobs.Knobs{}, "lo"); err == nil {
useSystemdResolved = r.Mode() == "systemd-resolved"
}
// Disable quic-go's ECN support by default, see https://github.com/quic-go/quic-go/issues/3911
Expand Down
9 changes: 4 additions & 5 deletions cmd/cli/resolvconf_not_darwin_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import (
"net"
"net/netip"

"tailscale.com/tsd"
"tailscale.com/control/controlknobs"
"tailscale.com/health"
"tailscale.com/util/dnsname"

"github.com/Control-D-Inc/ctrld/internal/dns"
)

// setResolvConf sets the content of resolv.conf file using the given nameservers list.
func setResolvConf(iface *net.Interface, ns []netip.Addr) error {
sys := new(tsd.System)
r, err := dns.NewOSConfigurator(func(format string, args ...any) {}, sys.HealthTracker(), sys.ControlKnobs(), "lo") // interface name does not matter.
r, err := dns.NewOSConfigurator(func(format string, args ...any) {}, &health.Tracker{}, &controlknobs.Knobs{}, "lo") // interface name does not matter.
if err != nil {
return err
}
Expand All @@ -29,8 +29,7 @@ func setResolvConf(iface *net.Interface, ns []netip.Addr) error {

// shouldWatchResolvconf reports whether ctrld should watch changes to resolv.conf file with given OS configurator.
func shouldWatchResolvconf() bool {
sys := new(tsd.System)
r, err := dns.NewOSConfigurator(func(format string, args ...any) {}, sys.HealthTracker(), sys.ControlKnobs(), "lo") // interface name does not matter.
r, err := dns.NewOSConfigurator(func(format string, args ...any) {}, &health.Tracker{}, &controlknobs.Knobs{}, "lo") // interface name does not matter.
if err != nil {
return false
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/cli/self_kill_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func selfUninstall(p *prog, logger zerolog.Logger) {
}
args := []string{"uninstall"}
if !deactivationPinNotSet() {
args = append(args, fmt.Sprintf("--pin=%d", cdDeactivationPin))
args = append(args, fmt.Sprintf("--pin=%d", cdDeactivationPin.Load()))
}
cmd := exec.Command(bin, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
Expand Down
6 changes: 6 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,12 @@ And within each policy, the rules are processed from top to bottom.
- Required: no
- Default: []

---

Note that the domain comparisons are done in case in-sensitive manner following [RFC 1034](https://datatracker.ietf.org/doc/html/rfc1034#section-3.1)

---

### macs:
`macs` is the list of mac rules within the policy. Mac address value is case-insensitive.

Expand Down
Loading

0 comments on commit 09495f2

Please sign in to comment.