dnscrypt-proxy/dnscrypt-proxy/main.go

158 lines
4.1 KiB
Go

package main
import (
crypto_rand "crypto/rand"
"encoding/binary"
"flag"
"fmt"
"math/rand"
"os"
"runtime"
"sync"
"github.com/jedisct1/dlog"
"github.com/kardianos/service"
)
const (
AppVersion = "2.1.5"
DefaultConfigFileName = "dnscrypt-proxy.toml"
)
type App struct {
wg sync.WaitGroup
quit chan struct{}
proxy *Proxy
flags *ConfigFlags
}
func main() {
tzErr := TimezoneSetup()
dlog.Init("dnscrypt-proxy", dlog.SeverityNotice, "DAEMON")
if tzErr != nil {
dlog.Warnf("Timezone setup failed: [%v]", tzErr)
}
runtime.MemProfileRate = 0
seed := make([]byte, 8)
if _, err := crypto_rand.Read(seed); err != nil {
dlog.Fatal(err)
}
rand.Seed(int64(binary.LittleEndian.Uint64(seed)))
pwd, err := os.Getwd()
if err != nil {
dlog.Fatal("Unable to find the path to the current directory")
}
svcFlag := flag.String("service", "", fmt.Sprintf("Control the system service: %q", service.ControlAction))
version := flag.Bool("version", false, "print current proxy version")
flags := ConfigFlags{}
flags.Resolve = flag.String("resolve", "", "resolve a DNS name (string can be <name> or <name>,<resolver address>)")
flags.List = flag.Bool("list", false, "print the list of available resolvers for the enabled filters")
flags.ListAll = flag.Bool("list-all", false, "print the complete list of available resolvers, ignoring filters")
flags.IncludeRelays = flag.Bool("include-relays", false, "include the list of available relays in the output of -list and -list-all")
flags.JSONOutput = flag.Bool("json", false, "output list as JSON")
flags.Check = flag.Bool("check", false, "check the configuration file and exit")
flags.ConfigFile = flag.String("config", DefaultConfigFileName, "Path to the configuration file")
flags.Child = flag.Bool("child", false, "Invokes program as a child process")
flags.NetprobeTimeoutOverride = flag.Int("netprobe-timeout", 60, "Override the netprobe timeout")
flags.ShowCerts = flag.Bool("show-certs", false, "print DoH certificate chain hashes")
flag.Parse()
if *version {
fmt.Println(AppVersion)
os.Exit(0)
}
if fullexecpath, err := os.Executable(); err == nil {
WarnIfMaybeWritableByOtherUsers(fullexecpath)
}
app := &App{
flags: &flags,
}
svcConfig := &service.Config{
Name: "dnscrypt-proxy",
DisplayName: "DNSCrypt client proxy",
Description: "Encrypted/authenticated DNS proxy",
WorkingDirectory: pwd,
Arguments: []string{"-config", *flags.ConfigFile},
}
svc, err := service.New(app, svcConfig)
if err != nil {
svc = nil
dlog.Debug(err)
}
app.proxy = NewProxy()
_ = ServiceManagerStartNotify()
if len(*svcFlag) != 0 {
if svc == nil {
dlog.Fatal("Built-in service installation is not supported on this platform")
}
if err := service.Control(svc, *svcFlag); err != nil {
dlog.Fatal(err)
}
if *svcFlag == "install" {
dlog.Notice("Installed as a service. Use `-service start` to start")
} else if *svcFlag == "uninstall" {
dlog.Notice("Service uninstalled")
} else if *svcFlag == "start" {
dlog.Notice("Service started")
} else if *svcFlag == "stop" {
dlog.Notice("Service stopped")
} else if *svcFlag == "restart" {
dlog.Notice("Service restarted")
}
return
}
if svc != nil {
if err := svc.Run(); err != nil {
dlog.Fatal(err)
}
} else {
app.Start(nil)
}
}
func (app *App) Start(service service.Service) error {
if service != nil {
go func() {
app.AppMain()
}()
} else {
app.AppMain()
}
return nil
}
func (app *App) AppMain() {
if err := ConfigLoad(app.proxy, app.flags); err != nil {
dlog.Fatal(err)
}
if err := PidFileCreate(); err != nil {
dlog.Errorf("Unable to create the PID file: [%v]", err)
}
if err := app.proxy.InitPluginsGlobals(); err != nil {
dlog.Fatal(err)
}
app.quit = make(chan struct{})
app.wg.Add(1)
app.proxy.StartProxy()
runtime.GC()
<-app.quit
dlog.Notice("Quit signal received...")
app.wg.Done()
}
func (app *App) Stop(service service.Service) error {
if err := PidFileRemove(); err != nil {
dlog.Warnf("Failed to remove the PID file: [%v]", err)
}
dlog.Notice("Stopped.")
return nil
}