Просмотр исходного кода

Add firehol blocklist

tags/v2.0.0-rc1
9seconds 5 лет назад
Родитель
Сommit
f52b3391d1

+ 2
- 0
go.mod Просмотреть файл

9
 	github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
9
 	github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
10
 	github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6
10
 	github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6
11
 	github.com/jarcoal/httpmock v1.0.8
11
 	github.com/jarcoal/httpmock v1.0.8
12
+	github.com/kentik/patricia v0.0.0-20201202224819-f9447a6e25f1 // indirect
12
 	github.com/kr/pretty v0.1.0 // indirect
13
 	github.com/kr/pretty v0.1.0 // indirect
13
 	github.com/libp2p/go-reuseport v0.0.2
14
 	github.com/libp2p/go-reuseport v0.0.2
14
 	github.com/mccutchen/go-httpbin v1.1.1
15
 	github.com/mccutchen/go-httpbin v1.1.1
16
+	github.com/panjf2000/ants v1.3.0 // indirect
15
 	github.com/pelletier/go-toml v1.8.1
17
 	github.com/pelletier/go-toml v1.8.1
16
 	github.com/rs/zerolog v1.20.0 // indirect
18
 	github.com/rs/zerolog v1.20.0 // indirect
17
 	github.com/stretchr/objx v0.3.0 // indirect
19
 	github.com/stretchr/objx v0.3.0 // indirect

+ 5
- 0
go.sum Просмотреть файл

14
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
14
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
15
 github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k=
15
 github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k=
16
 github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
16
 github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
17
+github.com/kentik/patricia v0.0.0-20201202224819-f9447a6e25f1 h1:D7qhJP3R49ZjUzpzKQ6B2H3lgejPs6DTO5gRomhhOpE=
18
+github.com/kentik/patricia v0.0.0-20201202224819-f9447a6e25f1/go.mod h1:2OfLA+0esiUJpwMjrH39pEk79cb8MvGTBS9YlZpejJ4=
17
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
19
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
18
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
20
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
19
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
21
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
23
 github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=
25
 github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=
24
 github.com/mccutchen/go-httpbin v1.1.1 h1:aEws49HEJEyXHLDnshQVswfUlCVoS8g6h9YaDyaW7RE=
26
 github.com/mccutchen/go-httpbin v1.1.1 h1:aEws49HEJEyXHLDnshQVswfUlCVoS8g6h9YaDyaW7RE=
25
 github.com/mccutchen/go-httpbin v1.1.1/go.mod h1:fhpOYavp5g2K74XDl/ao2y4KvhqVtKlkg1e+0UaQv7I=
27
 github.com/mccutchen/go-httpbin v1.1.1/go.mod h1:fhpOYavp5g2K74XDl/ao2y4KvhqVtKlkg1e+0UaQv7I=
28
+github.com/panjf2000/ants v1.3.0 h1:8pQ+8leaLc9lys2viEEr8md0U4RN6uOSUCE9bOYjQ9M=
29
+github.com/panjf2000/ants v1.3.0/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY=
26
 github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
30
 github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
27
 github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
31
 github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
28
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
32
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
36
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
40
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
37
 github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
41
 github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
38
 github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
42
 github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
43
+github.com/stretchr/testify v1.1.5-0.20170809224252-890a5c3458b4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
39
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
44
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
40
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
45
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
41
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
46
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=

+ 327
- 0
ipblocklist/firehol.go Просмотреть файл

1
+package ipblocklist
2
+
3
+import (
4
+	"bufio"
5
+	"context"
6
+	"fmt"
7
+	"io"
8
+	"io/ioutil"
9
+	"net"
10
+	"net/http"
11
+	"net/url"
12
+	"os"
13
+	"regexp"
14
+	"strings"
15
+	"sync"
16
+	"time"
17
+
18
+	"github.com/9seconds/mtg/v2/mtglib"
19
+	"github.com/kentik/patricia"
20
+	"github.com/kentik/patricia/bool_tree"
21
+	"github.com/panjf2000/ants"
22
+)
23
+
24
+const (
25
+	fireholIPv4DefaultCIDR = 32
26
+	fireholIPv6DefaultCIDR = 128
27
+)
28
+
29
+var fireholRegexpComment = regexp.MustCompile(`\s*#.*?$`)
30
+
31
+type Firehol struct {
32
+	logger     mtglib.Logger
33
+	rwMutex    sync.RWMutex
34
+	remoteURLs []string
35
+	localFiles []string
36
+	httpClient *http.Client
37
+	workerPool *ants.Pool
38
+	treeV4     *bool_tree.TreeV4
39
+	treeV6     *bool_tree.TreeV6
40
+}
41
+
42
+func (f *Firehol) Contains(ip net.IP) bool {
43
+	if ip == nil {
44
+		return true
45
+	}
46
+
47
+	ip4 := ip.To4()
48
+
49
+	f.rwMutex.RLock()
50
+	defer f.rwMutex.RUnlock()
51
+
52
+	if ip4 != nil {
53
+		return f.containsIPv4(ip4)
54
+	}
55
+
56
+	return f.containsIPv6(ip.To16())
57
+}
58
+
59
+func (f *Firehol) containsIPv4(addr net.IP) bool {
60
+	ip := patricia.NewIPv4AddressFromBytes(addr, 32)
61
+
62
+	if ok, _, err := f.treeV4.FindDeepestTag(ip); ok && err == nil {
63
+		return true
64
+	}
65
+
66
+	return false
67
+}
68
+
69
+func (f *Firehol) containsIPv6(addr net.IP) bool {
70
+	ip := patricia.NewIPv6Address(addr, 128)
71
+
72
+	if ok, _, err := f.treeV6.FindDeepestTag(ip); ok && err == nil {
73
+		return true
74
+	}
75
+
76
+	return false
77
+}
78
+
79
+func (f *Firehol) Run(ctx context.Context, updateEach time.Duration) {
80
+	ticker := time.NewTicker(updateEach)
81
+
82
+	defer func() {
83
+		ticker.Stop()
84
+
85
+		select {
86
+		case <-ticker.C:
87
+		default:
88
+		}
89
+	}()
90
+
91
+	if err := f.update(ctx); err != nil {
92
+		f.logger.WarningError("cannot update blocklist", err)
93
+	}
94
+
95
+	for {
96
+		select {
97
+		case <-ctx.Done():
98
+			return
99
+		case <-ticker.C:
100
+			if err := f.update(ctx); err != nil {
101
+				f.logger.WarningError("cannot update blocklist", err)
102
+			}
103
+		}
104
+	}
105
+}
106
+
107
+func (f *Firehol) update(ctx context.Context) error { // nolint: funlen, cyclop
108
+	ctx, cancel := context.WithCancel(ctx)
109
+	defer cancel()
110
+
111
+	wg := &sync.WaitGroup{}
112
+	wg.Add(len(f.remoteURLs) + len(f.localFiles))
113
+
114
+	treeMutex := &sync.Mutex{}
115
+	v4tree := bool_tree.NewTreeV4()
116
+	v6tree := bool_tree.NewTreeV6()
117
+
118
+	errorChan := make(chan error, 1)
119
+	defer close(errorChan)
120
+
121
+	for _, v := range f.localFiles {
122
+		go func(filename string) {
123
+			defer wg.Done()
124
+
125
+			if err := f.updateLocalFile(ctx, filename, treeMutex, v4tree, v6tree); err != nil {
126
+				cancel()
127
+				f.logger.BindStr("filename", filename).WarningError("cannot update", err)
128
+
129
+				select {
130
+				case errorChan <- err:
131
+				default:
132
+				}
133
+			}
134
+		}(v)
135
+	}
136
+
137
+	for _, v := range f.remoteURLs {
138
+		value := v
139
+
140
+		f.workerPool.Submit(func() { // nolint: errcheck
141
+			defer wg.Done()
142
+
143
+			if err := f.updateRemoteURL(ctx, value, treeMutex, v4tree, v6tree); err != nil {
144
+				cancel()
145
+				f.logger.BindStr("url", value).WarningError("cannot update", err)
146
+
147
+				select {
148
+				case errorChan <- err:
149
+				default:
150
+				}
151
+			}
152
+		})
153
+	}
154
+
155
+	wg.Wait()
156
+
157
+	select {
158
+	case err := <-errorChan:
159
+		return fmt.Errorf("cannot update trees: %w", err)
160
+	default:
161
+	}
162
+
163
+	f.rwMutex.Lock()
164
+	defer f.rwMutex.Unlock()
165
+
166
+	f.treeV4 = v4tree
167
+	f.treeV6 = v6tree
168
+
169
+	return nil
170
+}
171
+
172
+func (f *Firehol) updateLocalFile(ctx context.Context, filename string,
173
+	mutex sync.Locker,
174
+	v4tree *bool_tree.TreeV4, v6tree *bool_tree.TreeV6) error {
175
+	filefp, err := os.Open(filename)
176
+	if err != nil {
177
+		return fmt.Errorf("cannot open file: %w", err)
178
+	}
179
+
180
+	defer filefp.Close()
181
+
182
+	return f.updateTrees(ctx, mutex, filefp, v4tree, v6tree)
183
+}
184
+
185
+func (f *Firehol) updateRemoteURL(ctx context.Context, url string,
186
+	mutex sync.Locker,
187
+	v4tree *bool_tree.TreeV4, v6tree *bool_tree.TreeV6) error {
188
+	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
189
+	if err != nil {
190
+		return fmt.Errorf("cannot build a request: %w", err)
191
+	}
192
+
193
+	resp, err := f.httpClient.Do(req)
194
+	if err != nil {
195
+		return fmt.Errorf("cannot request a remote URL %s: %w", url, err)
196
+	}
197
+
198
+	defer func() {
199
+		io.Copy(ioutil.Discard, resp.Body) // nolint: errcheck
200
+		resp.Body.Close()
201
+	}()
202
+
203
+	return f.updateTrees(ctx, mutex, resp.Body, v4tree, v6tree)
204
+}
205
+
206
+func (f *Firehol) updateTrees(ctx context.Context,
207
+	mutex sync.Locker,
208
+	reader io.Reader,
209
+	v4tree *bool_tree.TreeV4,
210
+	v6tree *bool_tree.TreeV6) error {
211
+	scanner := bufio.NewScanner(reader)
212
+
213
+	for scanner.Scan() {
214
+		select {
215
+		case <-ctx.Done():
216
+			return ctx.Err()
217
+		default:
218
+		}
219
+
220
+		text := scanner.Text()
221
+		text = fireholRegexpComment.ReplaceAllLiteralString(text, "")
222
+		text = strings.TrimSpace(text)
223
+
224
+		if text == "" {
225
+			continue
226
+		}
227
+
228
+		ip, cidr, err := f.updateParseLine(text)
229
+		if err != nil {
230
+			return fmt.Errorf("cannot parse a line: %w", err)
231
+		}
232
+
233
+		if err := f.updateAddToTrees(ip, cidr, mutex, v4tree, v6tree); err != nil {
234
+			return fmt.Errorf("cannot add a node to the tree: %w", err)
235
+		}
236
+	}
237
+
238
+	if scanner.Err() != nil {
239
+		return fmt.Errorf("cannot parse a response: %w", scanner.Err())
240
+	}
241
+
242
+	return nil
243
+}
244
+
245
+func (f *Firehol) updateParseLine(text string) (net.IP, uint, error) {
246
+	_, ipnet, err := net.ParseCIDR(text)
247
+	if err != nil {
248
+		ipaddr := net.ParseIP(text)
249
+		if ipaddr == nil {
250
+			return nil, 0, fmt.Errorf("incorrect ip address %s", text)
251
+		}
252
+
253
+		ip4 := ipaddr.To4()
254
+		if ip4 != nil {
255
+			return ip4, fireholIPv4DefaultCIDR, nil
256
+		}
257
+
258
+		return ipaddr.To16(), fireholIPv6DefaultCIDR, nil
259
+	}
260
+
261
+	ones, _ := ipnet.Mask.Size()
262
+
263
+	return ipnet.IP, uint(ones), nil
264
+}
265
+
266
+func (f *Firehol) updateAddToTrees(ip net.IP, cidr uint,
267
+	mutex sync.Locker,
268
+	v4tree *bool_tree.TreeV4, v6tree *bool_tree.TreeV6) error {
269
+	mutex.Lock()
270
+	defer mutex.Unlock()
271
+
272
+	if ip.To4() != nil {
273
+		addr := patricia.NewIPv4AddressFromBytes(ip, cidr)
274
+
275
+		if _, _, err := v4tree.Set(addr, true); err != nil {
276
+			return err // nolint: wrapcheck
277
+		}
278
+	} else {
279
+		addr := patricia.NewIPv6Address(ip, cidr)
280
+
281
+		if _, _, err := v6tree.Set(addr, true); err != nil {
282
+			return err // nolint: wrapcheck
283
+		}
284
+	}
285
+
286
+	return nil
287
+}
288
+
289
+func NewFirehol(logger mtglib.Logger, network mtglib.Network,
290
+	downloadConcurrency uint,
291
+	remoteURLs []string,
292
+	localFiles []string) (*Firehol, error) {
293
+	for _, v := range remoteURLs {
294
+		parsed, err := url.Parse(v)
295
+		if err != nil {
296
+			return nil, fmt.Errorf("incorrect url %s: %w", v, err)
297
+		}
298
+
299
+		switch parsed.Scheme {
300
+		case "http", "https":
301
+		default:
302
+			return nil, fmt.Errorf("unsupported url %s", v)
303
+		}
304
+	}
305
+
306
+	for _, v := range localFiles {
307
+		if stat, err := os.Stat(v); os.IsNotExist(err) || stat.IsDir() || stat.Mode().Perm()&0o400 == 0 {
308
+			return nil, fmt.Errorf("%s is not a readable file", v)
309
+		}
310
+	}
311
+
312
+	if downloadConcurrency == 0 {
313
+		downloadConcurrency = 1
314
+	}
315
+
316
+	workerPool, _ := ants.NewPool(int(downloadConcurrency))
317
+
318
+	return &Firehol{
319
+		logger:     logger.Named("firehol"),
320
+		httpClient: network.MakeHTTPClient(nil),
321
+		treeV4:     bool_tree.NewTreeV4(),
322
+		treeV6:     bool_tree.NewTreeV6(),
323
+		workerPool: workerPool,
324
+		remoteURLs: remoteURLs,
325
+		localFiles: localFiles,
326
+	}, nil
327
+}

+ 137
- 0
ipblocklist/firehol_test.go Просмотреть файл

1
+package ipblocklist_test
2
+
3
+import (
4
+	"context"
5
+	"io"
6
+	"net"
7
+	"net/http"
8
+	"net/http/httptest"
9
+	"os"
10
+	"path/filepath"
11
+	"testing"
12
+	"time"
13
+
14
+	"github.com/9seconds/mtg/v2/ipblocklist"
15
+	"github.com/9seconds/mtg/v2/logger"
16
+	"github.com/9seconds/mtg/v2/network"
17
+	"github.com/9seconds/mtg/v2/testlib"
18
+	"github.com/jarcoal/httpmock"
19
+	"github.com/stretchr/testify/mock"
20
+	"github.com/stretchr/testify/suite"
21
+)
22
+
23
+type FireholTestSuite struct {
24
+	suite.Suite
25
+
26
+	networkMock *testlib.MtglibNetworkMock
27
+	httpServer  *httptest.Server
28
+}
29
+
30
+func (suite *FireholTestSuite) SetupSuite() {
31
+	mux := http.NewServeMux()
32
+
33
+	mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
34
+		filefp, err := os.Open(filepath.Join("testdata", "remote_ipset.ipset"))
35
+		if err != nil {
36
+			panic(err)
37
+		}
38
+
39
+		defer filefp.Close()
40
+
41
+		io.Copy(w, filefp) // nolint: errcheck
42
+	})
43
+
44
+	suite.httpServer = httptest.NewServer(mux)
45
+}
46
+
47
+func (suite *FireholTestSuite) SetupTest() {
48
+	httpClient := &http.Client{}
49
+	suite.networkMock = &testlib.MtglibNetworkMock{}
50
+
51
+	httpmock.ActivateNonDefault(httpClient)
52
+
53
+	suite.networkMock.
54
+		On("MakeHTTPClient", mock.Anything).
55
+		Maybe().
56
+		Return(httpClient)
57
+}
58
+
59
+func (suite *FireholTestSuite) TearDownTest() {
60
+	suite.networkMock.AssertExpectations(suite.T())
61
+	httpmock.DeactivateAndReset()
62
+}
63
+
64
+func (suite *FireholTestSuite) TearDownSuite() {
65
+	suite.httpServer.Close()
66
+}
67
+
68
+func (suite *FireholTestSuite) TestLocalFail() {
69
+	blocklist, err := ipblocklist.NewFirehol(logger.NewNoopLogger(),
70
+		suite.networkMock, 2,
71
+		nil, []string{filepath.Join("testdata", "broken_ipset.ipset")})
72
+
73
+	suite.NoError(err)
74
+
75
+	go blocklist.Run(context.Background(), time.Hour)
76
+
77
+	time.Sleep(500 * time.Millisecond)
78
+
79
+	suite.False(blocklist.Contains(net.ParseIP("10.0.0.10")))
80
+	suite.False(blocklist.Contains(net.ParseIP("127.0.0.1")))
81
+}
82
+
83
+func (suite *FireholTestSuite) TestLocalOk() {
84
+	blocklist, err := ipblocklist.NewFirehol(logger.NewNoopLogger(),
85
+		suite.networkMock, 2,
86
+		nil, []string{filepath.Join("testdata", "good_ipset.ipset")})
87
+
88
+	suite.NoError(err)
89
+
90
+	go blocklist.Run(context.Background(), time.Hour)
91
+
92
+	time.Sleep(500 * time.Millisecond)
93
+
94
+	suite.True(blocklist.Contains(net.ParseIP("10.0.0.10")))
95
+	suite.False(blocklist.Contains(net.ParseIP("127.0.0.1")))
96
+}
97
+
98
+func (suite *FireholTestSuite) TestRemoteFail() {
99
+	blocklist, err := ipblocklist.NewFirehol(logger.NewNoopLogger(),
100
+		suite.networkMock, 2,
101
+		[]string{"https://google.com"}, nil)
102
+
103
+	suite.NoError(err)
104
+
105
+	go blocklist.Run(context.Background(), time.Hour)
106
+
107
+	time.Sleep(500 * time.Millisecond)
108
+
109
+	suite.False(blocklist.Contains(net.ParseIP("10.2.2.2")))
110
+}
111
+
112
+func (suite *FireholTestSuite) TestMixed() {
113
+	dialer, _ := network.NewDefaultDialer(0, 0)
114
+	ntw, _ := network.NewNetwork(dialer, "mtg", "1.1.1.1", 0, 0)
115
+
116
+	blocklist, err := ipblocklist.NewFirehol(logger.NewNoopLogger(),
117
+		ntw, 2,
118
+		[]string{
119
+			suite.httpServer.URL,
120
+		}, []string{
121
+			filepath.Join("testdata", "good_ipset.ipset"),
122
+		})
123
+
124
+	suite.NoError(err)
125
+
126
+	go blocklist.Run(context.Background(), time.Hour)
127
+
128
+	time.Sleep(500 * time.Millisecond)
129
+
130
+	suite.True(blocklist.Contains(net.ParseIP("10.2.2.2")))
131
+	suite.True(blocklist.Contains(net.ParseIP("10.1.0.100")))
132
+}
133
+
134
+func TestFirehol(t *testing.T) {
135
+	t.Parallel()
136
+	suite.Run(t, &FireholTestSuite{})
137
+}

+ 15
- 0
ipblocklist/noop.go Просмотреть файл

1
+package ipblocklist
2
+
3
+import (
4
+	"net"
5
+
6
+	"github.com/9seconds/mtg/v2/mtglib"
7
+)
8
+
9
+type noop struct{}
10
+
11
+func (n noop) Contains(ip net.IP) bool { return false }
12
+
13
+func NewNoop() mtglib.IPBlocklist {
14
+	return noop{}
15
+}

+ 23
- 0
ipblocklist/noop_test.go Просмотреть файл

1
+package ipblocklist_test
2
+
3
+import (
4
+	"net"
5
+	"testing"
6
+
7
+	"github.com/9seconds/mtg/v2/ipblocklist"
8
+	"github.com/stretchr/testify/suite"
9
+)
10
+
11
+type NoopTestSuite struct {
12
+	suite.Suite
13
+}
14
+
15
+func (suite *NoopTestSuite) TestOp() {
16
+	suite.False(ipblocklist.NewNoop().Contains(net.ParseIP("10.0.0.10")))
17
+	suite.False(ipblocklist.NewNoop().Contains(net.ParseIP("10.0.0.10")))
18
+}
19
+
20
+func TestNoop(t *testing.T) {
21
+	t.Parallel()
22
+	suite.Run(t, &NoopTestSuite{})
23
+}

+ 5
- 0
ipblocklist/testdata/broken_ipset.ipset Просмотреть файл

1
+#
2
+# This is an intentionally broken ipset.
3
+#
4
+
5
+ajsdkfbd

+ 7
- 0
ipblocklist/testdata/good_ipset.ipset Просмотреть файл

1
+#
2
+# This is very good ipset
3
+#
4
+
5
+10.0.0.10  # just an example
6
+10.1.0.0/24
7
+2001:0db8:85a3:0000:0000:8a2e:0370:7334

+ 1
- 0
ipblocklist/testdata/remote_ipset.ipset Просмотреть файл

1
+10.2.2.2

+ 4
- 0
mtglib/init.go Просмотреть файл

21
 	SeenBefore(data []byte) bool
21
 	SeenBefore(data []byte) bool
22
 }
22
 }
23
 
23
 
24
+type IPBlocklist interface {
25
+	Contains(net.IP) bool
26
+}
27
+
24
 type Logger interface {
28
 type Logger interface {
25
 	Named(name string) Logger
29
 	Named(name string) Logger
26
 
30
 

+ 7
- 0
network/network.go Просмотреть файл

132
 func NewNetwork(dialer Dialer,
132
 func NewNetwork(dialer Dialer,
133
 	userAgent, dohHostname string,
133
 	userAgent, dohHostname string,
134
 	httpTimeout, idleTimeout time.Duration) (mtglib.Network, error) {
134
 	httpTimeout, idleTimeout time.Duration) (mtglib.Network, error) {
135
+	switch {
136
+	case httpTimeout < 0:
137
+		return nil, fmt.Errorf("timeout should be positive number %s", httpTimeout)
138
+	case httpTimeout == 0:
139
+		httpTimeout = DefaultHTTPTimeout
140
+	}
141
+
135
 	switch {
142
 	switch {
136
 	case idleTimeout < 0:
143
 	case idleTimeout < 0:
137
 		return nil, fmt.Errorf("timeout should be positive number %s", idleTimeout)
144
 		return nil, fmt.Errorf("timeout should be positive number %s", idleTimeout)

Загрузка…
Отмена
Сохранить