-
Notifications
You must be signed in to change notification settings - Fork 4
/
main.go
145 lines (129 loc) · 3.64 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// This script is meant to help verify 'bulk correction' files for submission
// to MaxMind. The files are expected to (mostly) follow the format provided by the RFC at
// https://datatracker.ietf.org/doc/rfc8805/
// Region codes without the country prefix are accepted. eg, 'NY' is allowed, along with
// 'US-NY' for the state of New York in the United States.
// Beyond verifying that the format of the data is correct, the script will also compare
// the corrections against a given MMDB, reporting on how many corrections differ from
// the contents in the database.
package main
import (
"bytes"
"errors"
"flag"
"fmt"
"log"
"os"
"sort" //nolint:depguard // preexisting
"strings"
"github.com/maxmind/mm-geofeed-verifier/v3/verify"
)
// This value is set by build scripts. Changing the name of
// the variable should be considered a breaking change.
var version = "unknown"
type config struct {
gf string
db string
isp string
laxMode bool
emptyOK bool
}
func main() {
err := run()
if err != nil {
log.Fatal(err)
}
}
func run() error {
conf, output, err := parseFlags(os.Args[0], os.Args[1:])
if err != nil {
fmt.Println(output)
return err
}
c, diffLines, asnCounts, err := verify.ProcessGeofeed(
conf.gf,
conf.db,
conf.isp,
verify.Options{LaxMode: conf.laxMode, EmptyOK: conf.emptyOK},
)
if err != nil {
if errors.Is(err, verify.ErrInvalidGeofeed) {
log.Printf("Found %d invalid rows out of %d rows in total, examples by type:", c.Invalid, c.Total)
for invType, invMessage := range c.SampleInvalidRows {
log.Printf("%s: '%s'", invType, invMessage)
}
}
return fmt.Errorf("unable to process geofeed %s: %w", conf.gf, err)
}
fmt.Printf(
strings.Join(diffLines, "\n\n")+
"\n\nOut of %d potential corrections, %d may be different than our current mappings\n\n",
c.Total,
c.Differences,
)
// https://stackoverflow.com/a/56706305
asNumbers := make([]uint, 0, len(asnCounts))
for asNumber := range asnCounts {
asNumbers = append(asNumbers, asNumber)
}
sort.Slice(
asNumbers,
func(i, j int) bool {
return asnCounts[asNumbers[i]] > asnCounts[asNumbers[j]]
},
)
for _, asNumber := range asNumbers {
fmt.Printf("ASN: %d, count: %d\n", asNumber, asnCounts[asNumber])
}
return nil
}
func parseFlags(program string, args []string) (c *config, output string, err error) {
flags := flag.NewFlagSet(program, flag.ContinueOnError)
var buf bytes.Buffer
flags.SetOutput(&buf)
var conf config
flags.StringVar(&conf.gf, "gf", "", "Path to local geofeed file to verify")
flags.StringVar(&conf.isp, "isp", "", "Path to ISP MMDB file (optional)")
flags.StringVar(
&conf.db,
"db",
"/usr/local/share/GeoIP/GeoIP2-City.mmdb",
"Path to MMDB file to compare geofeed file against",
)
displayVersion := false
flags.BoolVar(&displayVersion, "V", false, "Display version")
flags.BoolVar(
&conf.laxMode,
"lax",
false,
"Enable lax mode: geofeed's region code may be provided without country code prefix")
flags.BoolVar(
&conf.emptyOK,
"empty-ok",
false,
"Allow empty geofeeds to be considered valid")
err = flags.Parse(args)
if err != nil {
return nil, buf.String(), err
}
if displayVersion {
log.Printf("mm-geofeed-verifier %s", version)
//nolint:revive // preexisting
os.Exit(0)
}
if conf.gf == "" && conf.db == "" {
flags.PrintDefaults()
return nil, buf.String(), errors.New(
"-gf is required and -db can not be an empty string",
)
}
if conf.gf == "" {
flags.PrintDefaults()
return nil, buf.String(), errors.New("-gf is required")
}
if conf.db == "" {
flags.PrintDefaults()
return nil, buf.String(), errors.New("-db is required")
}
return &conf, buf.String(), nil
}