a recursive dns resolver
1package main 2 3import ( 4 "flag" 5 "log" 6 "log/slog" 7 "os" 8 "time" 9 10 "code.kiri.systems/kiri/alky/pkg/config" 11 "code.kiri.systems/kiri/alky/pkg/dns" 12 "code.kiri.systems/kiri/alky/pkg/rootservers" 13) 14 15var configFlag string 16 17func init() { 18 flag.StringVar(&configFlag, "config", "/etc/alky/alky.toml", "config file path for alky") 19 20 flag.Parse() 21} 22 23func main() { 24 cfg, err := config.LoadConfig(configFlag) 25 if err != nil { 26 log.Fatal(err) 27 } 28 29 rootServers, err := rootservers.DecodeRootHints(cfg.Server.RootHintsFile) 30 if err != nil { 31 log.Fatal(err) 32 } 33 34 var logger *slog.Logger 35 switch cfg.Logging.Output { 36 case "file": 37 f, err := os.OpenFile(cfg.Logging.FilePath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644) 38 if err != nil { 39 log.Fatal(err) 40 } 41 42 logger = slog.New(slog.NewJSONHandler(f, nil)) 43 case "stdout": 44 fallthrough 45 default: 46 logger = slog.New(slog.NewJSONHandler(os.Stdout, nil)) 47 } 48 49 memCache := dns.NewMemoryCache() 50 var cache dns.Cache = memCache 51 52 handler := &dns.QueryHandler{ 53 RootServers: rootServers, 54 Timeout: time.Duration(cfg.Advanced.QueryTimeout) * time.Second, 55 Cache: &cache, 56 } 57 58 logConfig := &dns.LogConfig{Logger: logger} 59 60 rateLimitHandler := dns.RateLimitMiddleware(&dns.RateLimitConfig{ 61 Rate: float64(cfg.Ratelimit.Rate), 62 Burst: cfg.Ratelimit.Burst, 63 WindowLength: time.Duration(cfg.Ratelimit.Window) * time.Second, 64 ExpirationTime: time.Duration(cfg.Ratelimit.ExpirationTime) * time.Second, 65 })(handler) 66 loggingHandler := dns.LoggingMiddleware(logConfig)(rateLimitHandler) 67 68 s := dns.Server{ 69 Address: cfg.Server.Address, 70 Port: cfg.Server.Port, 71 Handler: loggingHandler, 72 UDPSize: 512, 73 ReadTimeout: 2 * time.Second, 74 WriteTimeout: 2 * time.Second, 75 76 Logger: logger, 77 } 78 79 if err := s.ListenAndServe(); err != nil { 80 slog.Error("Failed to start server", "error", err) 81 } 82}