mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-04-07 12:32:04 +02:00
Compare commits
3 Commits
fix-missin
...
add-missin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f39512b4c0 | ||
|
|
7ce62ccaec | ||
|
|
f7d3db06c6 |
@@ -76,8 +76,8 @@ $ go install github.com/Control-D-Inc/ctrld/cmd/ctrld@latest
|
|||||||
or
|
or
|
||||||
|
|
||||||
```
|
```
|
||||||
$ docker build -t controld/ctrld .
|
$ docker build -t controldns/ctrld .
|
||||||
$ docker run -d --name=ctrld -p 53:53/tcp -p 53:53/udp controld/ctrld --cd=RESOLVER_ID_GOES_HERE -vv
|
$ docker run -d --name=ctrld -p 53:53/tcp -p 53:53/udp controldns/ctrld --cd=RESOLVER_ID_GOES_HERE -vv
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -208,16 +208,18 @@ func initCLI() {
|
|||||||
processCDFlags()
|
processCDFlags()
|
||||||
}
|
}
|
||||||
|
|
||||||
updateListenerConfig()
|
updated := updateListenerConfig()
|
||||||
|
|
||||||
if cdUID != "" {
|
if cdUID != "" {
|
||||||
processLogAndCacheFlags()
|
processLogAndCacheFlags()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := writeConfigFile(); err != nil {
|
if updated {
|
||||||
mainLog.Load().Fatal().Err(err).Msg("failed to write config file")
|
if err := writeConfigFile(); err != nil {
|
||||||
} else {
|
mainLog.Load().Fatal().Err(err).Msg("failed to write config file")
|
||||||
mainLog.Load().Info().Msg("writing config file to: " + defaultConfigFile)
|
} else {
|
||||||
|
mainLog.Load().Info().Msg("writing config file to: " + defaultConfigFile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if newLogPath := cfg.Service.LogPath; newLogPath != "" && oldLogPath != newLogPath {
|
if newLogPath := cfg.Service.LogPath; newLogPath != "" && oldLogPath != newLogPath {
|
||||||
@@ -1383,6 +1385,8 @@ func fieldErrorMsg(fe validator.FieldError) string {
|
|||||||
return fmt.Sprintf("invalid IP format: %s", fe.Value())
|
return fmt.Sprintf("invalid IP format: %s", fe.Value())
|
||||||
case "file":
|
case "file":
|
||||||
return fmt.Sprintf("filed does not exist: %s", fe.Value())
|
return fmt.Sprintf("filed does not exist: %s", fe.Value())
|
||||||
|
case "http_url":
|
||||||
|
return fmt.Sprintf("invalid http/https url: %s", fe.Value())
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -1410,8 +1414,8 @@ type listenerConfigCheck struct {
|
|||||||
|
|
||||||
// updateListenerConfig updates the config for listeners if not defined,
|
// updateListenerConfig updates the config for listeners if not defined,
|
||||||
// or defined but invalid to be used, e.g: using loopback address other
|
// or defined but invalid to be used, e.g: using loopback address other
|
||||||
// than 127.0.0.1 with sytemd-resolved.
|
// than 127.0.0.1 with systemd-resolved.
|
||||||
func updateListenerConfig() {
|
func updateListenerConfig() (updated bool) {
|
||||||
lcc := make(map[string]*listenerConfigCheck)
|
lcc := make(map[string]*listenerConfigCheck)
|
||||||
cdMode := cdUID != ""
|
cdMode := cdUID != ""
|
||||||
for n, listener := range cfg.Listener {
|
for n, listener := range cfg.Listener {
|
||||||
@@ -1429,6 +1433,7 @@ func updateListenerConfig() {
|
|||||||
lcc[n].IP = true
|
lcc[n].IP = true
|
||||||
lcc[n].Port = true
|
lcc[n].Port = true
|
||||||
}
|
}
|
||||||
|
updated = updated || lcc[n].IP || lcc[n].Port
|
||||||
}
|
}
|
||||||
|
|
||||||
var closers []io.Closer
|
var closers []io.Closer
|
||||||
@@ -1601,6 +1606,7 @@ func updateListenerConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func dirWritable(dir string) (bool, error) {
|
func dirWritable(dir string) (bool, error) {
|
||||||
|
|||||||
29
config.go
29
config.go
@@ -193,7 +193,7 @@ type NetworkConfig struct {
|
|||||||
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"`
|
||||||
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:"-"`
|
||||||
IPStack string `mapstructure:"ip_stack" toml:"ip_stack,omitempty" validate:"ipstack"`
|
IPStack string `mapstructure:"ip_stack" toml:"ip_stack,omitempty" validate:"ipstack"`
|
||||||
@@ -589,6 +589,7 @@ func ValidateConfig(validate *validator.Validate, cfg *Config) error {
|
|||||||
_ = validate.RegisterValidation("dnsrcode", validateDnsRcode)
|
_ = validate.RegisterValidation("dnsrcode", validateDnsRcode)
|
||||||
_ = validate.RegisterValidation("ipstack", validateIpStack)
|
_ = validate.RegisterValidation("ipstack", validateIpStack)
|
||||||
_ = validate.RegisterValidation("iporempty", validateIpOrEmpty)
|
_ = validate.RegisterValidation("iporempty", validateIpOrEmpty)
|
||||||
|
validate.RegisterStructValidation(upstreamConfigStructLevelValidation, UpstreamConfig{})
|
||||||
return validate.Struct(cfg)
|
return validate.Struct(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,6 +614,32 @@ func validateIpOrEmpty(fl validator.FieldLevel) bool {
|
|||||||
return net.ParseIP(val) != nil
|
return net.ParseIP(val) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func upstreamConfigStructLevelValidation(sl validator.StructLevel) {
|
||||||
|
uc := sl.Current().Addr().Interface().(*UpstreamConfig)
|
||||||
|
if uc.Type == ResolverTypeOS {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Endpoint is required for non os resolver.
|
||||||
|
if uc.Endpoint == "" {
|
||||||
|
sl.ReportError(uc.Endpoint, "endpoint", "Endpoint", "required_unless", "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoH/DoH3 requires endpoint is an HTTP url.
|
||||||
|
if uc.Type == ResolverTypeDOH || uc.Type == ResolverTypeDOH3 {
|
||||||
|
u, err := url.Parse(uc.Endpoint)
|
||||||
|
if err != nil || u.Host == "" {
|
||||||
|
sl.ReportError(uc.Endpoint, "endpoint", "Endpoint", "http_url", "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if u.Scheme != "http" && u.Scheme != "https" {
|
||||||
|
sl.ReportError(uc.Endpoint, "endpoint", "Endpoint", "http_url", "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func defaultPortFor(typ string) string {
|
func defaultPortFor(typ string) string {
|
||||||
switch typ {
|
switch typ {
|
||||||
case ResolverTypeDOH, ResolverTypeDOH3:
|
case ResolverTypeDOH, ResolverTypeDOH3:
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ func TestConfigValidation(t *testing.T) {
|
|||||||
{"non-existed lease file", configWithNonExistedLeaseFile(t), true},
|
{"non-existed lease file", configWithNonExistedLeaseFile(t), true},
|
||||||
{"lease file format required if lease file exist", configWithExistedLeaseFile(t), true},
|
{"lease file format required if lease file exist", configWithExistedLeaseFile(t), true},
|
||||||
{"invalid lease file format", configWithInvalidLeaseFileFormat(t), true},
|
{"invalid lease file format", configWithInvalidLeaseFileFormat(t), true},
|
||||||
|
{"invalid doh/doh3 endpoint", configWithInvalidDoHEndpoint(t), true},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
@@ -225,3 +226,10 @@ func configWithInvalidLeaseFileFormat(t *testing.T) *ctrld.Config {
|
|||||||
cfg.Service.DHCPLeaseFileFormat = "invalid"
|
cfg.Service.DHCPLeaseFileFormat = "invalid"
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func configWithInvalidDoHEndpoint(t *testing.T) *ctrld.Config {
|
||||||
|
cfg := defaultConfig(t)
|
||||||
|
cfg.Upstream["0"].Endpoint = "1.1.1.1"
|
||||||
|
cfg.Upstream["0"].Type = ctrld.ResolverTypeDOH
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|||||||
179
scripts/build.sh
179
scripts/build.sh
@@ -1,179 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
go=${GOBIN:-go}
|
|
||||||
executable_name="ctrld"
|
|
||||||
os_archs=(
|
|
||||||
darwin/arm64
|
|
||||||
darwin/amd64
|
|
||||||
windows/386
|
|
||||||
windows/amd64
|
|
||||||
windows/arm64
|
|
||||||
windows/arm
|
|
||||||
linux/amd64
|
|
||||||
linux/386
|
|
||||||
linux/mips
|
|
||||||
linux/mipsle
|
|
||||||
linux/mips64
|
|
||||||
linux/arm
|
|
||||||
linux/arm64
|
|
||||||
freebsd/amd64
|
|
||||||
freebsd/386
|
|
||||||
freebsd/arm
|
|
||||||
freebsd/arm64
|
|
||||||
)
|
|
||||||
|
|
||||||
compress() {
|
|
||||||
binary=$1
|
|
||||||
|
|
||||||
if [ -z "$binary" ]; then
|
|
||||||
echo >&2 "missing binary"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$binary" in
|
|
||||||
*-freebsd-*)
|
|
||||||
echo >&2 "upx does not work with freebsd binary yet"
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
*-windows-arm*)
|
|
||||||
echo >&2 "upx does not work with windows arm/arm64 binary yet"
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
*-darwin-*)
|
|
||||||
echo >&2 "upx claims to work with darwin binary, but testing show that it is broken"
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
*-linux-armv*)
|
|
||||||
echo >&2 "upx does not work on arm routers"
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
*-linux-mips*)
|
|
||||||
echo >&2 "upx does not work on mips routers"
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
upx -- "$binary"
|
|
||||||
}
|
|
||||||
|
|
||||||
build() {
|
|
||||||
goos=$1
|
|
||||||
goarch=$2
|
|
||||||
ldflags="-s -w -X github.com/Windscribe/ctrld/cmd/cli.version="${CI_COMMIT_TAG:-dev}" -X github.com/Windscribe/ctrld/cmd/cli.commit=$(git rev-parse HEAD)"
|
|
||||||
|
|
||||||
case $3 in
|
|
||||||
5 | 6 | 7)
|
|
||||||
goarm=$3
|
|
||||||
if [ "${goos}${goarm}" = "freebsd5" ]; then
|
|
||||||
# freebsd/arm require ARMv6K or above: https://github.com/golang/go/wiki/GoArm#supported-operating-systems
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
binary=${executable_name}-${goos}-${goarch}v${3}
|
|
||||||
if [ "$CGO_ENABLED" = "0" ]; then
|
|
||||||
binary=${binary}-nocgo
|
|
||||||
fi
|
|
||||||
GOOS=${goos} GOARCH=${goarch} GOARM=${3} "$go" build -ldflags="$ldflags" -o "$binary" ./cmd/ctrld
|
|
||||||
compress "$binary"
|
|
||||||
|
|
||||||
if [ -z "${CTRLD_NO_QF}" ]; then
|
|
||||||
binary_qf=${executable_name}-qf-${goos}-${goarch}v${3}
|
|
||||||
if [ "$CGO_ENABLED" = "0" ]; then
|
|
||||||
binary_qf=${binary_qf}-nocgo
|
|
||||||
fi
|
|
||||||
GOOS=${goos} GOARCH=${goarch} GOARM=${3} "$go" build -ldflags="$ldflags" -tags=qf -o "$binary_qf" ./cmd/ctrld
|
|
||||||
compress "$binary_qf"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# GOMIPS is required for linux/mips: https://nileshgr.com/2020/02/16/golang-on-openwrt-mips/
|
|
||||||
binary=${executable_name}-${goos}-${goarch}
|
|
||||||
if [ "$CGO_ENABLED" = "0" ]; then
|
|
||||||
binary=${binary}-nocgo
|
|
||||||
fi
|
|
||||||
GOOS=${goos} GOARCH=${goarch} GOMIPS=softfloat "$go" build -ldflags="$ldflags" -o "$binary" ./cmd/ctrld
|
|
||||||
compress "$binary"
|
|
||||||
|
|
||||||
if [ -z "${CTRLD_NO_QF}" ]; then
|
|
||||||
binary_qf=${executable_name}-qf-${goos}-${goarch}
|
|
||||||
if [ "$CGO_ENABLED" = "0" ]; then
|
|
||||||
binary_qf=${binary_qf}-nocgo
|
|
||||||
fi
|
|
||||||
GOOS=${goos} GOARCH=${goarch} GOMIPS=softfloat "$go" build -ldflags="$ldflags" -tags=qf -o "$binary_qf" ./cmd/ctrld
|
|
||||||
compress "$binary_qf"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
echo "Building binaries..."
|
|
||||||
|
|
||||||
case $1 in
|
|
||||||
all)
|
|
||||||
for os_arch in "${os_archs[@]}"; do
|
|
||||||
goos=${os_arch%/*}
|
|
||||||
goarch=${os_arch#*/}
|
|
||||||
|
|
||||||
case goarch in
|
|
||||||
arm)
|
|
||||||
|
|
||||||
echo "Building $goos/$goarch ARM5..."
|
|
||||||
build "$goos" "$goarch" "5"
|
|
||||||
|
|
||||||
echo "Building $goos/$goarch ARM6..."
|
|
||||||
build "$goos" "$goarch" "6"
|
|
||||||
|
|
||||||
echo "Building $goos/$goarch ARM7..."
|
|
||||||
build "$goos" "$goarch" "7"
|
|
||||||
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Building $goos/$goarch..."
|
|
||||||
build "$goos" "$goarch"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
linux/armv5)
|
|
||||||
goos=${1%/*}
|
|
||||||
goarch=${1#*/}
|
|
||||||
echo "Building $goos/$goarch..."
|
|
||||||
build "$goos" arm "5"
|
|
||||||
;;
|
|
||||||
linux/armv6)
|
|
||||||
goos=${1%/*}
|
|
||||||
goarch=${1#*/}
|
|
||||||
echo "Building $goos/$goarch..."
|
|
||||||
build "$goos" arm "6"
|
|
||||||
;;
|
|
||||||
linux/armv7)
|
|
||||||
goos=${1%/*}
|
|
||||||
goarch=${1#*/}
|
|
||||||
echo "Building $goos/$goarch..."
|
|
||||||
build "$goos" arm "7"
|
|
||||||
;;
|
|
||||||
freebsd/armv6)
|
|
||||||
goos=${1%/*}
|
|
||||||
goarch=${1#*/}
|
|
||||||
echo "Building $goos/$goarch..."
|
|
||||||
build "$goos" arm "6"
|
|
||||||
;;
|
|
||||||
freebsd/armv7)
|
|
||||||
goos=${1%/*}
|
|
||||||
goarch=${1#*/}
|
|
||||||
echo "Building $goos/$goarch..."
|
|
||||||
build "$goos" arm "7"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
goos=${1%/*}
|
|
||||||
goarch=${1#*/}
|
|
||||||
if [ -z "$goos" ]; then
|
|
||||||
goos=$(go env GOOS)
|
|
||||||
fi
|
|
||||||
if [ -z "$goarch" ]; then
|
|
||||||
goarch=$(go env GOARCH)
|
|
||||||
fi
|
|
||||||
echo "Building $goos/$goarch..."
|
|
||||||
build "$goos" "$goarch"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
printf 'Done \360\237\221\214\n'
|
|
||||||
Reference in New Issue
Block a user