package main import ( "bufio" "encoding/json" "fmt" "log" "net" "net/http" "os" ) type Country struct { Name string `json:"name"` Url string `json:"url"` v4Addresses []string } type JsonListFile struct { Countries []Country `json:"countries"` } func main() { // Validate arguments if len(os.Args) < 3 { log.Fatalf("usage: %s ", os.Args[0]) } blockListName := os.Args[1] jsonListFile := os.Args[2] fmt.Printf("generating blocklist %s\n", blockListName) // Load blocklist config file countries, err := readJsonListFile(jsonListFile) if err != nil { log.Fatalf("failed to read jsonlistfile '%s': %v", jsonListFile, err) } // Download up to date geoip CIDR data for i := range countries { countries[i].v4Addresses, err = downloadAddressList(countries[i].Url) if err != nil { log.Fatalf("failed to download address list for county'%s': %v", countries[i].Name, err) } } // Generate mikrotik block list err = generateOutput(countries, blockListName) if err != nil { log.Fatalf("failed to generate output file: %v", err) } } func generateOutput(countries []Country, blockListName string) error { output := "/ip firewall address-list\n" for _, country := range countries { for _, v4Address := range country.v4Addresses { output += fmt.Sprintf("add address=%s comment=\"%s\" list=%s\n", v4Address, country.Name, blockListName) } } err := os.WriteFile(fmt.Sprintf("%s.rsc", blockListName), []byte(output), os.ModePerm) if err != nil { return fmt.Errorf("failed to write file '%s.rsc': %v", blockListName, err) } return nil } func downloadAddressList(url string) ([]string, error) { resp, err := http.Get(url) if err != nil { return nil, fmt.Errorf("http get error on url '%s': %v", url, err) } if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("unexpected http status - expected '%d' but got '%d'", http.StatusOK, resp.StatusCode) } scanner := bufio.NewScanner(resp.Body) scanner.Split(bufio.ScanLines) v4Addresses := make([]string, 0) for scanner.Scan() { line := scanner.Text() _, ipnet, err := net.ParseCIDR(line) if err != nil { log.Printf("skippine line: failed to parse line '%s' to cidr: %v", line, err) continue } v4Addresses = append(v4Addresses, ipnet.String()) } return v4Addresses, nil } // reads the json config file containing the lists of countries you want to block func readJsonListFile(filename string) ([]Country, error) { b, err := os.ReadFile(filename) if err != nil { return nil, fmt.Errorf("failed to open file %s: %v", filename, err) } jsonListFile := JsonListFile{} err = json.Unmarshal(b, &jsonListFile) if err != nil { return nil, fmt.Errorf("failed to unmarshal json file to jsonListFile struct: %v", err) } return jsonListFile.Countries, nil }