//go:build ignore // Parses Wireshark's packet-e212.c and generates utils/mccmnc_data.go. // Run: go generate ./utils/... package main import ( "fmt" "go/format" "io" "log" "net/http" "os" "regexp" "sort" "strconv" "strings" ) const wiresharkURL = "https://raw.githubusercontent.com/wireshark/wireshark/master/epan/dissectors/packet-e212.c" // matches entries like { 123, "Some Name" } in C value_string arrays var entryRe = regexp.MustCompile(`\{\s*(\d+),\s*"([^"]+)"\s*\}`) func main() { log.SetFlags(0) src := fetchSource() countries := parseTable(src, "E212_codes[]", func(code int) string { return fmt.Sprintf("%03d", code) }) networks := parseTable(src, "mcc_mnc_2digits_codes[]", func(code int) string { return fmt.Sprintf("%03d-%02d", code/100, code%100) }) // 3-digit MNC: only add if no 2-digit entry exists for the same key for k, v := range parseTable(src, "mcc_mnc_3digits_codes[]", func(code int) string { return fmt.Sprintf("%03d-%03d", code/1000, code%1000) }) { if _, ok := networks[k]; !ok { networks[k] = v } } var buf strings.Builder buf.WriteString("// Code generated by gen_mccmnc from Wireshark's packet-e212.c; DO NOT EDIT.\n\npackage utils\n\n") writeMap(&buf, "mccCountry", "MCC to country name (ITU-T E.212)", countries) writeMap(&buf, "mccmncNetwork", "MCC-MNC to network/operator name (ITU-T E.212)", networks) formatted, err := format.Source([]byte(buf.String())) if err != nil { log.Fatalf("gofmt: %v", err) } if err := os.WriteFile("mccmnc_data.go", formatted, 0644); err != nil { log.Fatal(err) } fmt.Printf("generated mccmnc_data.go: %d countries, %d networks\n", len(countries), len(networks)) } func fetchSource() string { resp, err := http.Get(wiresharkURL) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } return string(body) } func parseTable(src, name string, formatKey func(int) string) map[string]string { block := extractBlock(src, name) if block == "" { log.Fatalf("table %s not found", name) } result := make(map[string]string) for _, m := range entryRe.FindAllStringSubmatch(block, -1) { if m[2] == "Unassigned" || m[2] == "Unset" { continue } code, _ := strconv.Atoi(m[1]) result[formatKey(code)] = m[2] } return result } // extractBlock returns the body of a C value_string array, up to its { 0, NULL } terminator. func extractBlock(src, name string) string { marker := "value_string " + name + " = {" start := strings.Index(src, marker) if start < 0 { return "" } end := strings.Index(src[start:], "{ 0, NULL }") if end < 0 { return "" } return src[start : start+end] } func writeMap(buf *strings.Builder, varName, comment string, m map[string]string) { keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } sort.Strings(keys) fmt.Fprintf(buf, "// %s maps %s.\nvar %s = map[string]string{\n", varName, comment, varName) for _, k := range keys { fmt.Fprintf(buf, "\t%q: %q,\n", k, m[k]) } buf.WriteString("}\n\n") }