package config import ( "fmt" "os" "path" "strings" ) const ( leaseFileKey = "dhcp-leasefile" rangeKey = "dhcp-range" confFileKey = "conf-file" confDirKey = "conf-dir" ) func tryParseLineOption(line, key string) (string, bool) { if !strings.HasPrefix(line, key) { return "", false } _, val, found := strings.Cut(line, "=") return val, found } type dnsmasqConfOptions struct { leaseFile string rangeStart string rangeEnd string } func defaultDNSMasqOptions() map[string]string { return map[string]string{ confDirKey: "/etc/dnsmasq.d", confFileKey: "", leaseFileKey: "/var/lib/misc/dnsmasq.leases", rangeKey: "", } } func parseDNSMasqConfFile(content string, options map[string]string) { for _, l := range strings.Split(content, "\n") { for key := range options { newVal, found := tryParseLineOption(l, key) if found { options[key] = newVal } } } } func parseDNSMasqOptions(rootFileContent string) (dnsmasqConfOptions, error) { rawOptions := defaultDNSMasqOptions() // start with parsing the root file parseDNSMasqConfFile(rootFileContent, rawOptions) // get all additional conf files in the provided directory confDir := rawOptions[confDirKey] if confDir != "" { entries, err := os.ReadDir(confDir) if err != nil { return dnsmasqConfOptions{}, fmt.Errorf("failed to get list of additional config files: %w", err) } for _, e := range entries { if e.IsDir() || !strings.HasSuffix(e.Name(), ".conf") { continue } fileContent, err := os.ReadFile(path.Join(confDir, e.Name())) if err != nil { return dnsmasqConfOptions{}, fmt.Errorf("failed to read sub config file: %w", err) } parseDNSMasqConfFile(string(fileContent), rawOptions) } } // get any additional config file if additionalFile := rawOptions[confFileKey]; additionalFile != "" { filecontent, err := os.ReadFile(additionalFile) if err != nil { return dnsmasqConfOptions{}, fmt.Errorf("failed to read additional config file: %w", err) } parseDNSMasqConfFile(string(filecontent), rawOptions) } dhcpRange := strings.Split(rawOptions[rangeKey], ",") if len(dhcpRange) < 2 { return dnsmasqConfOptions{}, fmt.Errorf("invalid value for DHCP range: %s", rawOptions[rangeKey]) } return dnsmasqConfOptions{ leaseFile: rawOptions[leaseFileKey], rangeStart: dhcpRange[0], rangeEnd: dhcpRange[1], }, nil }