package main import ( "encoding/json" "flag" "fmt" "io" "log" "net/http" "os" "os/exec" "strings" ) type IPAddress struct { Address string `json:"address"` DNSName string `json:"dns_name"` } type NetBoxResponse struct { Results []IPAddress `json:"results"` } func FetchNetboxIPAddresses(apiURL, token string) ([]IPAddress, error) { req, err := http.NewRequest("GET", apiURL, nil) if err != nil { return nil, err } req.Header.Set("Accept", "application/json; indent=2") req.Header.Set("Authorization", "Token "+token) resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) return nil, fmt.Errorf("unexpected status: %s, body: %s", resp.Status, string(body)) } var nbResp NetBoxResponse decoder := json.NewDecoder(resp.Body) if err := decoder.Decode(&nbResp); err != nil { return nil, err } // Filter out entries with empty DNSName and strip CIDR from Address var filtered []IPAddress for _, ip := range nbResp.Results { if ip.DNSName != "" { ip.Address = strings.Split(ip.Address, "/")[0] filtered = append(filtered, ip) } } return filtered, nil } func CreateDnsMasqConfig() { token := os.Getenv("NETBOX_TOKEN") if token == "" { home := os.Getenv("HOME") paths := []string{ home + "/.netbox/token", "/etc/netbox/token", } for _, path := range paths { data, err := os.ReadFile(path) if err == nil { token = strings.TrimSpace(string(data)) break } } if token == "" { log.Fatal("NETBOX_TOKEN not set and no token file found") } } apiURL := "https://netbox.koszewscy.waw.pl/api/ipam/ip-addresses/" ips, err := FetchNetboxIPAddresses(apiURL, token) if err != nil { log.Fatalf("Error fetching IP addresses: %v", err) } dir := "/etc/dnsmasq.d" if stat, err := os.Stat(dir); err == nil && stat.IsDir() { file, err := os.Create(dir + "/netbox.conf") if err != nil { log.Fatalf("Failed to create netbox.conf: %v", err) } defer file.Close() for _, ip := range ips { fmt.Fprintf(file, "address=/%s/%s\n", ip.DNSName, ip.Address) } } else { for _, ip := range ips { fmt.Printf("address=/%s/%s\n", ip.DNSName, ip.Address) } } } func main() { listenAddr := flag.String("listen", ":8080", "address and port to listen on (e.g. :8080 or 127.0.0.1:8080)") flag.Parse() http.HandleFunc("/update-dnsmasq", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { w.WriteHeader(http.StatusMethodNotAllowed) w.Write([]byte("Method not allowed")) return } CreateDnsMasqConfig() cmd := exec.Command("systemctl", "restart", "dnsmasq.service") if err := cmd.Run(); err != nil { log.Printf("Failed to restart dnsmasq.service: %v", err) w.Write([]byte("\nWarning: Failed to restart dnsmasq.service.\n")) } w.Write([]byte("DNSMasq config updated.")) }) log.Printf("Starting web service on %s...", *listenAddr) if err := http.ListenAndServe(*listenAddr, nil); err != nil { log.Fatalf("Failed to start server: %v", err) } }