carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package geoip
2
3import (
4 "archive/tar"
5 "compress/gzip"
6 "errors"
7 "fmt"
8 "io"
9 "path"
10 "strings"
11)
12
13// ErrTooLarge is a capped reader refusing to read past its cap (spec §10.3).
14var ErrTooLarge = errors.New("geoip archive: larger than its cap")
15
16type cappedReader struct {
17 r io.Reader
18 left int64
19}
20
21func (c *cappedReader) Read(p []byte) (int, error) {
22 if c.left < 0 {
23 return 0, ErrTooLarge
24 }
25 if int64(len(p)) > c.left+1 {
26 p = p[:c.left+1]
27 }
28 n, err := c.r.Read(p)
29 c.left -= int64(n)
30 if c.left < 0 {
31 return n, ErrTooLarge
32 }
33 return n, err
34}
35
36// CappedReader reads r until more than max bytes have come through, then
37// fails with ErrTooLarge. Exactly max bytes read cleanly.
38func CappedReader(r io.Reader, max int64) io.Reader { return &cappedReader{r: r, left: max} }
39
40// GunzipReader expands a gzip stream, refusing to expand past maxExpanded:
41// a decompression bomb stops at the cap, never at the end of its expansion.
42func GunzipReader(r io.Reader, maxExpanded int64) (io.Reader, error) {
43 zr, err := gzip.NewReader(r)
44 if err != nil {
45 return nil, fmt.Errorf("geoip archive: not gzip: %w", err)
46 }
47 return CappedReader(zr, maxExpanded), nil
48}
49
50// TarGzMMDB returns the first regular *.mmdb member of a .tar.gz (MaxMind's
51// download format). Every expanded byte counts toward maxExpanded,
52// including the members walked past, so junk padding cannot fill a disk.
53func TarGzMMDB(r io.Reader, maxExpanded int64) (io.Reader, error) {
54 expanded, err := GunzipReader(r, maxExpanded)
55 if err != nil {
56 return nil, err
57 }
58 tr := tar.NewReader(expanded)
59 for {
60 h, err := tr.Next()
61 if err == io.EOF {
62 return nil, errors.New("geoip archive: no .mmdb member")
63 }
64 if err != nil {
65 return nil, err
66 }
67 if h.Typeflag == tar.TypeReg && strings.HasSuffix(path.Base(h.Name), ".mmdb") {
68 return tr, nil
69 }
70 }
71}
72