carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package geo
2
3import (
4 "bytes"
5 "context"
6 "encoding/binary"
7 "errors"
8 "os"
9 "path/filepath"
10 "testing"
11 "time"
12)
13
14// pathologicalMMDB builds a structurally valid IPv4 database of 32 nodes
15// whose two children are both the next node: 2^32 network paths through 32
16// nodes (code review R8-1).
17func pathologicalMMDB(t *testing.T) string {
18 t.Helper()
19 const nodes = 32
20 var buf bytes.Buffer
21 rec := func(v uint32) { buf.Write([]byte{byte(v >> 16), byte(v >> 8), byte(v)}) } // 24-bit records
22 for i := 0; i < nodes; i++ {
23 next := uint32(i + 1)
24 if i == nodes-1 {
25 next = nodes + 16 // data section offset 0
26 }
27 rec(next)
28 rec(next)
29 }
30 buf.Write(make([]byte, 16)) // data section separator
31 buf.WriteByte(0xE0) // the one record: an empty map
32 str := func(s string) { buf.WriteByte(0x40 | byte(len(s))); buf.WriteString(s) }
33 u16 := func(v uint16) { buf.WriteByte(0xA2); binary.Write(&buf, binary.BigEndian, v) }
34 u32 := func(v uint32) { buf.WriteByte(0xC4); binary.Write(&buf, binary.BigEndian, v) }
35 buf.WriteString("\xAB\xCD\xEFMaxMind.com")
36 buf.WriteByte(0xE0 | 9) // metadata map, 9 keys
37 str("node_count")
38 u32(nodes)
39 str("record_size")
40 u16(24)
41 str("ip_version")
42 u16(4)
43 str("database_type")
44 str("Pathological")
45 str("languages")
46 buf.Write([]byte{0x00, 0x04}) // array of 0
47 str("binary_format_major_version")
48 u16(2)
49 str("binary_format_minor_version")
50 u16(0)
51 str("build_epoch")
52 buf.Write([]byte{0x08, 0x02}) // uint64, 8 bytes
53 binary.Write(&buf, binary.BigEndian, uint64(time.Now().Unix()))
54 str("description")
55 buf.WriteByte(0xE0) // empty map
56 p := filepath.Join(t.TempDir(), "dag.mmdb")
57 if err := os.WriteFile(p, buf.Bytes(), 0o644); err != nil {
58 t.Fatal(err)
59 }
60 return p
61}
62
63func TestOpenMMDBRefusesAPathologicalTreeInTime(t *testing.T) {
64 p := pathologicalMMDB(t)
65 start := time.Now()
66 _, err := OpenMMDBVerified(context.Background(), p)
67 if !errors.Is(err, ErrSearchTreeTooLarge) {
68 t.Fatalf("err = %v, want ErrSearchTreeTooLarge", err)
69 }
70 if d := time.Since(start); d > 5*time.Second {
71 t.Fatalf("took %s", d)
72 }
73 // The real fixtures still open.
74 for _, f := range []string{"GeoIP2-City-Test.mmdb", "GeoIP2-Country-Test.mmdb", "MaxMind-DB-test-ipv4-24.mmdb"} {
75 m, err := OpenMMDBVerified(context.Background(), "testdata/"+f)
76 if err != nil {
77 t.Fatalf("%s: %v", f, err)
78 }
79 m.Close()
80 }
81}
82
83// TestRealDatabaseOpensVerified runs only with GEOIP_REAL_MMDB set to a real
84// database (DB-IP Lite, GeoLite2): the bounded walk must accept it.
85func TestRealDatabaseOpensVerified(t *testing.T) {
86 p := os.Getenv("GEOIP_REAL_MMDB")
87 if p == "" {
88 t.Skip("set GEOIP_REAL_MMDB to a real .mmdb")
89 }
90 start := time.Now()
91 m, err := OpenMMDBVerified(context.Background(), p)
92 if err != nil {
93 t.Fatal(err)
94 }
95 m.Close()
96 t.Logf("%s verified in %s", m.Source(), time.Since(start))
97}
98