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}