defender_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. // Copyright (C) 2019-2023 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package common
  15. import (
  16. "crypto/rand"
  17. "encoding/hex"
  18. "encoding/json"
  19. "fmt"
  20. "net"
  21. "os"
  22. "path/filepath"
  23. "runtime"
  24. "testing"
  25. "time"
  26. "github.com/stretchr/testify/assert"
  27. "github.com/stretchr/testify/require"
  28. "github.com/yl2chen/cidranger"
  29. )
  30. func TestBasicDefender(t *testing.T) {
  31. bl := HostListFile{
  32. IPAddresses: []string{"172.16.1.1", "172.16.1.2"},
  33. CIDRNetworks: []string{"10.8.0.0/24"},
  34. }
  35. sl := HostListFile{
  36. IPAddresses: []string{"172.16.1.3", "172.16.1.4"},
  37. CIDRNetworks: []string{"192.168.8.0/24"},
  38. }
  39. blFile := filepath.Join(os.TempDir(), "bl.json")
  40. slFile := filepath.Join(os.TempDir(), "sl.json")
  41. data, err := json.Marshal(bl)
  42. assert.NoError(t, err)
  43. err = os.WriteFile(blFile, data, os.ModePerm)
  44. assert.NoError(t, err)
  45. data, err = json.Marshal(sl)
  46. assert.NoError(t, err)
  47. err = os.WriteFile(slFile, data, os.ModePerm)
  48. assert.NoError(t, err)
  49. config := &DefenderConfig{
  50. Enabled: true,
  51. BanTime: 10,
  52. BanTimeIncrement: 2,
  53. Threshold: 5,
  54. ScoreInvalid: 2,
  55. ScoreValid: 1,
  56. ScoreLimitExceeded: 3,
  57. ObservationTime: 15,
  58. EntriesSoftLimit: 1,
  59. EntriesHardLimit: 2,
  60. SafeListFile: "slFile",
  61. BlockListFile: "blFile",
  62. SafeList: []string{"192.168.1.3", "192.168.1.4", "192.168.9.0/24"},
  63. BlockList: []string{"192.168.1.1", "192.168.1.2", "10.8.9.0/24"},
  64. }
  65. _, err = newInMemoryDefender(config)
  66. assert.Error(t, err)
  67. config.BlockListFile = blFile
  68. _, err = newInMemoryDefender(config)
  69. assert.Error(t, err)
  70. config.SafeListFile = slFile
  71. d, err := newInMemoryDefender(config)
  72. assert.NoError(t, err)
  73. defender := d.(*memoryDefender)
  74. assert.True(t, defender.IsBanned("172.16.1.1"))
  75. assert.True(t, defender.IsBanned("192.168.1.1"))
  76. assert.False(t, defender.IsBanned("172.16.1.10"))
  77. assert.False(t, defender.IsBanned("192.168.1.10"))
  78. assert.False(t, defender.IsBanned("10.8.2.3"))
  79. assert.False(t, defender.IsBanned("10.9.2.3"))
  80. assert.True(t, defender.IsBanned("10.8.0.3"))
  81. assert.True(t, defender.IsBanned("10.8.9.3"))
  82. assert.False(t, defender.IsBanned("invalid ip"))
  83. assert.Equal(t, 0, defender.countBanned())
  84. assert.Equal(t, 0, defender.countHosts())
  85. hosts, err := defender.GetHosts()
  86. assert.NoError(t, err)
  87. assert.Len(t, hosts, 0)
  88. _, err = defender.GetHost("10.8.0.4")
  89. assert.Error(t, err)
  90. defender.AddEvent("172.16.1.4", HostEventLoginFailed)
  91. defender.AddEvent("192.168.1.4", HostEventLoginFailed)
  92. defender.AddEvent("192.168.8.4", HostEventUserNotFound)
  93. defender.AddEvent("172.16.1.3", HostEventLimitExceeded)
  94. defender.AddEvent("192.168.1.3", HostEventLimitExceeded)
  95. assert.Equal(t, 0, defender.countHosts())
  96. testIP := "12.34.56.78"
  97. defender.AddEvent(testIP, HostEventLoginFailed)
  98. assert.Equal(t, 1, defender.countHosts())
  99. assert.Equal(t, 0, defender.countBanned())
  100. score, err := defender.GetScore(testIP)
  101. assert.NoError(t, err)
  102. assert.Equal(t, 1, score)
  103. hosts, err = defender.GetHosts()
  104. assert.NoError(t, err)
  105. if assert.Len(t, hosts, 1) {
  106. assert.Equal(t, 1, hosts[0].Score)
  107. assert.True(t, hosts[0].BanTime.IsZero())
  108. assert.Empty(t, hosts[0].GetBanTime())
  109. }
  110. host, err := defender.GetHost(testIP)
  111. assert.NoError(t, err)
  112. assert.Equal(t, 1, host.Score)
  113. assert.Empty(t, host.GetBanTime())
  114. banTime, err := defender.GetBanTime(testIP)
  115. assert.NoError(t, err)
  116. assert.Nil(t, banTime)
  117. defender.AddEvent(testIP, HostEventLimitExceeded)
  118. assert.Equal(t, 1, defender.countHosts())
  119. assert.Equal(t, 0, defender.countBanned())
  120. score, err = defender.GetScore(testIP)
  121. assert.NoError(t, err)
  122. assert.Equal(t, 4, score)
  123. hosts, err = defender.GetHosts()
  124. assert.NoError(t, err)
  125. if assert.Len(t, hosts, 1) {
  126. assert.Equal(t, 4, hosts[0].Score)
  127. assert.True(t, hosts[0].BanTime.IsZero())
  128. assert.Empty(t, hosts[0].GetBanTime())
  129. }
  130. defender.AddEvent(testIP, HostEventNoLoginTried)
  131. defender.AddEvent(testIP, HostEventNoLoginTried)
  132. assert.Equal(t, 0, defender.countHosts())
  133. assert.Equal(t, 1, defender.countBanned())
  134. score, err = defender.GetScore(testIP)
  135. assert.NoError(t, err)
  136. assert.Equal(t, 0, score)
  137. banTime, err = defender.GetBanTime(testIP)
  138. assert.NoError(t, err)
  139. assert.NotNil(t, banTime)
  140. hosts, err = defender.GetHosts()
  141. assert.NoError(t, err)
  142. if assert.Len(t, hosts, 1) {
  143. assert.Equal(t, 0, hosts[0].Score)
  144. assert.False(t, hosts[0].BanTime.IsZero())
  145. assert.NotEmpty(t, hosts[0].GetBanTime())
  146. assert.Equal(t, hex.EncodeToString([]byte(testIP)), hosts[0].GetID())
  147. }
  148. host, err = defender.GetHost(testIP)
  149. assert.NoError(t, err)
  150. assert.Equal(t, 0, host.Score)
  151. assert.NotEmpty(t, host.GetBanTime())
  152. // now test cleanup, testIP is already banned
  153. testIP1 := "12.34.56.79"
  154. testIP2 := "12.34.56.80"
  155. testIP3 := "12.34.56.81"
  156. defender.AddEvent(testIP1, HostEventNoLoginTried)
  157. defender.AddEvent(testIP2, HostEventNoLoginTried)
  158. assert.Equal(t, 2, defender.countHosts())
  159. time.Sleep(20 * time.Millisecond)
  160. defender.AddEvent(testIP3, HostEventNoLoginTried)
  161. assert.Equal(t, defender.config.EntriesSoftLimit, defender.countHosts())
  162. // testIP1 and testIP2 should be removed
  163. assert.Equal(t, defender.config.EntriesSoftLimit, defender.countHosts())
  164. score, err = defender.GetScore(testIP1)
  165. assert.NoError(t, err)
  166. assert.Equal(t, 0, score)
  167. score, err = defender.GetScore(testIP2)
  168. assert.NoError(t, err)
  169. assert.Equal(t, 0, score)
  170. score, err = defender.GetScore(testIP3)
  171. assert.NoError(t, err)
  172. assert.Equal(t, 2, score)
  173. defender.AddEvent(testIP3, HostEventNoLoginTried)
  174. defender.AddEvent(testIP3, HostEventNoLoginTried)
  175. // IP3 is now banned
  176. banTime, err = defender.GetBanTime(testIP3)
  177. assert.NoError(t, err)
  178. assert.NotNil(t, banTime)
  179. assert.Equal(t, 0, defender.countHosts())
  180. time.Sleep(20 * time.Millisecond)
  181. for i := 0; i < 3; i++ {
  182. defender.AddEvent(testIP1, HostEventNoLoginTried)
  183. }
  184. assert.Equal(t, 0, defender.countHosts())
  185. assert.Equal(t, config.EntriesSoftLimit, defender.countBanned())
  186. banTime, err = defender.GetBanTime(testIP)
  187. assert.NoError(t, err)
  188. assert.Nil(t, banTime)
  189. banTime, err = defender.GetBanTime(testIP3)
  190. assert.NoError(t, err)
  191. assert.Nil(t, banTime)
  192. banTime, err = defender.GetBanTime(testIP1)
  193. assert.NoError(t, err)
  194. assert.NotNil(t, banTime)
  195. for i := 0; i < 3; i++ {
  196. defender.AddEvent(testIP, HostEventNoLoginTried)
  197. time.Sleep(10 * time.Millisecond)
  198. defender.AddEvent(testIP3, HostEventNoLoginTried)
  199. }
  200. assert.Equal(t, 0, defender.countHosts())
  201. assert.Equal(t, defender.config.EntriesSoftLimit, defender.countBanned())
  202. banTime, err = defender.GetBanTime(testIP3)
  203. assert.NoError(t, err)
  204. if assert.NotNil(t, banTime) {
  205. assert.True(t, defender.IsBanned(testIP3))
  206. // ban time should increase
  207. newBanTime, err := defender.GetBanTime(testIP3)
  208. assert.NoError(t, err)
  209. assert.True(t, newBanTime.After(*banTime))
  210. }
  211. assert.True(t, defender.DeleteHost(testIP3))
  212. assert.False(t, defender.DeleteHost(testIP3))
  213. err = os.Remove(slFile)
  214. assert.NoError(t, err)
  215. err = os.Remove(blFile)
  216. assert.NoError(t, err)
  217. }
  218. func TestExpiredHostBans(t *testing.T) {
  219. config := &DefenderConfig{
  220. Enabled: true,
  221. BanTime: 10,
  222. BanTimeIncrement: 2,
  223. Threshold: 5,
  224. ScoreInvalid: 2,
  225. ScoreValid: 1,
  226. ScoreLimitExceeded: 3,
  227. ObservationTime: 15,
  228. EntriesSoftLimit: 1,
  229. EntriesHardLimit: 2,
  230. }
  231. d, err := newInMemoryDefender(config)
  232. assert.NoError(t, err)
  233. defender := d.(*memoryDefender)
  234. testIP := "1.2.3.4"
  235. defender.banned[testIP] = time.Now().Add(-24 * time.Hour)
  236. // the ban is expired testIP should not be listed
  237. res, err := defender.GetHosts()
  238. assert.NoError(t, err)
  239. assert.Len(t, res, 0)
  240. assert.False(t, defender.IsBanned(testIP))
  241. _, err = defender.GetHost(testIP)
  242. assert.Error(t, err)
  243. _, ok := defender.banned[testIP]
  244. assert.True(t, ok)
  245. // now add an event for an expired banned ip, it should be removed
  246. defender.AddEvent(testIP, HostEventLoginFailed)
  247. assert.False(t, defender.IsBanned(testIP))
  248. entry, err := defender.GetHost(testIP)
  249. assert.NoError(t, err)
  250. assert.Equal(t, testIP, entry.IP)
  251. assert.Empty(t, entry.GetBanTime())
  252. assert.Equal(t, 1, entry.Score)
  253. res, err = defender.GetHosts()
  254. assert.NoError(t, err)
  255. if assert.Len(t, res, 1) {
  256. assert.Equal(t, testIP, res[0].IP)
  257. assert.Empty(t, res[0].GetBanTime())
  258. assert.Equal(t, 1, res[0].Score)
  259. }
  260. events := []hostEvent{
  261. {
  262. dateTime: time.Now().Add(-24 * time.Hour),
  263. score: 2,
  264. },
  265. {
  266. dateTime: time.Now().Add(-24 * time.Hour),
  267. score: 3,
  268. },
  269. }
  270. hs := hostScore{
  271. Events: events,
  272. TotalScore: 5,
  273. }
  274. defender.hosts[testIP] = hs
  275. // the recorded scored are too old
  276. res, err = defender.GetHosts()
  277. assert.NoError(t, err)
  278. assert.Len(t, res, 0)
  279. _, err = defender.GetHost(testIP)
  280. assert.Error(t, err)
  281. _, ok = defender.hosts[testIP]
  282. assert.True(t, ok)
  283. }
  284. func TestLoadHostListFromFile(t *testing.T) {
  285. _, err := loadHostListFromFile(".")
  286. assert.Error(t, err)
  287. hostsFilePath := filepath.Join(os.TempDir(), "hostfile")
  288. content := make([]byte, 1048576*6)
  289. _, err = rand.Read(content)
  290. assert.NoError(t, err)
  291. err = os.WriteFile(hostsFilePath, content, os.ModePerm)
  292. assert.NoError(t, err)
  293. _, err = loadHostListFromFile(hostsFilePath)
  294. assert.Error(t, err)
  295. hl := HostListFile{
  296. IPAddresses: []string{},
  297. CIDRNetworks: []string{},
  298. }
  299. asJSON, err := json.Marshal(hl)
  300. assert.NoError(t, err)
  301. err = os.WriteFile(hostsFilePath, asJSON, os.ModePerm)
  302. assert.NoError(t, err)
  303. hostList, err := loadHostListFromFile(hostsFilePath)
  304. assert.NoError(t, err)
  305. assert.Nil(t, hostList)
  306. hl.IPAddresses = append(hl.IPAddresses, "invalidip")
  307. asJSON, err = json.Marshal(hl)
  308. assert.NoError(t, err)
  309. err = os.WriteFile(hostsFilePath, asJSON, os.ModePerm)
  310. assert.NoError(t, err)
  311. hostList, err = loadHostListFromFile(hostsFilePath)
  312. assert.NoError(t, err)
  313. assert.Len(t, hostList.IPAddresses, 0)
  314. hl.IPAddresses = nil
  315. hl.CIDRNetworks = append(hl.CIDRNetworks, "invalid net")
  316. asJSON, err = json.Marshal(hl)
  317. assert.NoError(t, err)
  318. err = os.WriteFile(hostsFilePath, asJSON, os.ModePerm)
  319. assert.NoError(t, err)
  320. hostList, err = loadHostListFromFile(hostsFilePath)
  321. assert.NoError(t, err)
  322. assert.NotNil(t, hostList)
  323. assert.Len(t, hostList.IPAddresses, 0)
  324. assert.Equal(t, 0, hostList.Ranges.Len())
  325. if runtime.GOOS != osWindows {
  326. err = os.Chmod(hostsFilePath, 0111)
  327. assert.NoError(t, err)
  328. _, err = loadHostListFromFile(hostsFilePath)
  329. assert.Error(t, err)
  330. err = os.Chmod(hostsFilePath, 0644)
  331. assert.NoError(t, err)
  332. }
  333. err = os.WriteFile(hostsFilePath, []byte("non json content"), os.ModePerm)
  334. assert.NoError(t, err)
  335. _, err = loadHostListFromFile(hostsFilePath)
  336. assert.Error(t, err)
  337. err = os.Remove(hostsFilePath)
  338. assert.NoError(t, err)
  339. }
  340. func TestAddEntriesToHostList(t *testing.T) {
  341. name := "testList"
  342. hostlist := addEntriesToList([]string{"192.168.6.1", "10.7.0.0/25"}, nil, name)
  343. require.NotNil(t, hostlist)
  344. assert.True(t, hostlist.isListed("192.168.6.1"))
  345. assert.False(t, hostlist.isListed("192.168.6.2"))
  346. assert.True(t, hostlist.isListed("10.7.0.28"))
  347. assert.False(t, hostlist.isListed("10.7.0.129"))
  348. // load invalid values
  349. hostlist = addEntriesToList([]string{"invalidip", "invalidnet/24"}, nil, name)
  350. require.NotNil(t, hostlist)
  351. assert.Len(t, hostlist.IPAddresses, 0)
  352. assert.Equal(t, 0, hostlist.Ranges.Len())
  353. }
  354. func TestDefenderCleanup(t *testing.T) {
  355. d := memoryDefender{
  356. baseDefender: baseDefender{
  357. config: &DefenderConfig{
  358. ObservationTime: 1,
  359. EntriesSoftLimit: 2,
  360. EntriesHardLimit: 3,
  361. },
  362. },
  363. banned: make(map[string]time.Time),
  364. hosts: make(map[string]hostScore),
  365. }
  366. d.banned["1.1.1.1"] = time.Now().Add(-24 * time.Hour)
  367. d.banned["1.1.1.2"] = time.Now().Add(-24 * time.Hour)
  368. d.banned["1.1.1.3"] = time.Now().Add(-24 * time.Hour)
  369. d.banned["1.1.1.4"] = time.Now().Add(-24 * time.Hour)
  370. d.cleanupBanned()
  371. assert.Equal(t, 0, d.countBanned())
  372. d.banned["2.2.2.2"] = time.Now().Add(2 * time.Minute)
  373. d.banned["2.2.2.3"] = time.Now().Add(1 * time.Minute)
  374. d.banned["2.2.2.4"] = time.Now().Add(3 * time.Minute)
  375. d.banned["2.2.2.5"] = time.Now().Add(4 * time.Minute)
  376. d.cleanupBanned()
  377. assert.Equal(t, d.config.EntriesSoftLimit, d.countBanned())
  378. banTime, err := d.GetBanTime("2.2.2.3")
  379. assert.NoError(t, err)
  380. assert.Nil(t, banTime)
  381. d.hosts["3.3.3.3"] = hostScore{
  382. TotalScore: 0,
  383. Events: []hostEvent{
  384. {
  385. dateTime: time.Now().Add(-5 * time.Minute),
  386. score: 1,
  387. },
  388. {
  389. dateTime: time.Now().Add(-3 * time.Minute),
  390. score: 1,
  391. },
  392. {
  393. dateTime: time.Now(),
  394. score: 1,
  395. },
  396. },
  397. }
  398. d.hosts["3.3.3.4"] = hostScore{
  399. TotalScore: 1,
  400. Events: []hostEvent{
  401. {
  402. dateTime: time.Now().Add(-3 * time.Minute),
  403. score: 1,
  404. },
  405. },
  406. }
  407. d.hosts["3.3.3.5"] = hostScore{
  408. TotalScore: 1,
  409. Events: []hostEvent{
  410. {
  411. dateTime: time.Now().Add(-2 * time.Minute),
  412. score: 1,
  413. },
  414. },
  415. }
  416. d.hosts["3.3.3.6"] = hostScore{
  417. TotalScore: 1,
  418. Events: []hostEvent{
  419. {
  420. dateTime: time.Now().Add(-1 * time.Minute),
  421. score: 1,
  422. },
  423. },
  424. }
  425. score, err := d.GetScore("3.3.3.3")
  426. assert.NoError(t, err)
  427. assert.Equal(t, 1, score)
  428. d.cleanupHosts()
  429. assert.Equal(t, d.config.EntriesSoftLimit, d.countHosts())
  430. score, err = d.GetScore("3.3.3.4")
  431. assert.NoError(t, err)
  432. assert.Equal(t, 0, score)
  433. }
  434. func TestDefenderConfig(t *testing.T) {
  435. c := DefenderConfig{}
  436. err := c.validate()
  437. require.NoError(t, err)
  438. c.Enabled = true
  439. c.Threshold = 10
  440. c.ScoreInvalid = 10
  441. err = c.validate()
  442. require.Error(t, err)
  443. c.ScoreInvalid = 2
  444. c.ScoreLimitExceeded = 10
  445. err = c.validate()
  446. require.Error(t, err)
  447. c.ScoreLimitExceeded = 2
  448. c.ScoreValid = 10
  449. err = c.validate()
  450. require.Error(t, err)
  451. c.ScoreValid = 1
  452. c.BanTime = 0
  453. err = c.validate()
  454. require.Error(t, err)
  455. c.BanTime = 30
  456. c.BanTimeIncrement = 0
  457. err = c.validate()
  458. require.Error(t, err)
  459. c.BanTimeIncrement = 50
  460. c.ObservationTime = 0
  461. err = c.validate()
  462. require.Error(t, err)
  463. c.ObservationTime = 30
  464. err = c.validate()
  465. require.Error(t, err)
  466. c.EntriesSoftLimit = 10
  467. err = c.validate()
  468. require.Error(t, err)
  469. c.EntriesHardLimit = 10
  470. err = c.validate()
  471. require.Error(t, err)
  472. c.EntriesHardLimit = 20
  473. err = c.validate()
  474. require.NoError(t, err)
  475. }
  476. func BenchmarkDefenderBannedSearch(b *testing.B) {
  477. d := getDefenderForBench()
  478. ip, ipnet, err := net.ParseCIDR("10.8.0.0/12") // 1048574 ip addresses
  479. if err != nil {
  480. panic(err)
  481. }
  482. for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
  483. d.banned[ip.String()] = time.Now().Add(10 * time.Minute)
  484. }
  485. b.ResetTimer()
  486. for i := 0; i < b.N; i++ {
  487. d.IsBanned("192.168.1.1")
  488. }
  489. }
  490. func BenchmarkCleanup(b *testing.B) {
  491. d := getDefenderForBench()
  492. ip, ipnet, err := net.ParseCIDR("192.168.4.0/24")
  493. if err != nil {
  494. panic(err)
  495. }
  496. b.ResetTimer()
  497. for i := 0; i < b.N; i++ {
  498. for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
  499. d.AddEvent(ip.String(), HostEventLoginFailed)
  500. if d.countHosts() > d.config.EntriesHardLimit {
  501. panic("too many hosts")
  502. }
  503. if d.countBanned() > d.config.EntriesSoftLimit {
  504. panic("too many ip banned")
  505. }
  506. }
  507. }
  508. }
  509. func BenchmarkDefenderBannedSearchWithBlockList(b *testing.B) {
  510. d := getDefenderForBench()
  511. d.blockList = &HostList{
  512. IPAddresses: make(map[string]bool),
  513. Ranges: cidranger.NewPCTrieRanger(),
  514. }
  515. ip, ipnet, err := net.ParseCIDR("129.8.0.0/12") // 1048574 ip addresses
  516. if err != nil {
  517. panic(err)
  518. }
  519. for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
  520. d.banned[ip.String()] = time.Now().Add(10 * time.Minute)
  521. d.blockList.IPAddresses[ip.String()] = true
  522. }
  523. for i := 0; i < 255; i++ {
  524. cidr := fmt.Sprintf("10.8.%v.1/24", i)
  525. _, network, _ := net.ParseCIDR(cidr)
  526. if err := d.blockList.Ranges.Insert(cidranger.NewBasicRangerEntry(*network)); err != nil {
  527. panic(err)
  528. }
  529. }
  530. b.ResetTimer()
  531. for i := 0; i < b.N; i++ {
  532. d.IsBanned("192.168.1.1")
  533. }
  534. }
  535. func BenchmarkHostListSearch(b *testing.B) {
  536. hostlist := &HostList{
  537. IPAddresses: make(map[string]bool),
  538. Ranges: cidranger.NewPCTrieRanger(),
  539. }
  540. ip, ipnet, _ := net.ParseCIDR("172.16.0.0/16")
  541. for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
  542. hostlist.IPAddresses[ip.String()] = true
  543. }
  544. for i := 0; i < 255; i++ {
  545. cidr := fmt.Sprintf("10.8.%v.1/24", i)
  546. _, network, _ := net.ParseCIDR(cidr)
  547. if err := hostlist.Ranges.Insert(cidranger.NewBasicRangerEntry(*network)); err != nil {
  548. panic(err)
  549. }
  550. }
  551. b.ResetTimer()
  552. for i := 0; i < b.N; i++ {
  553. if hostlist.isListed("192.167.1.2") {
  554. panic("should not be listed")
  555. }
  556. }
  557. }
  558. func BenchmarkCIDRanger(b *testing.B) {
  559. ranger := cidranger.NewPCTrieRanger()
  560. for i := 0; i < 255; i++ {
  561. cidr := fmt.Sprintf("192.168.%v.1/24", i)
  562. _, network, _ := net.ParseCIDR(cidr)
  563. if err := ranger.Insert(cidranger.NewBasicRangerEntry(*network)); err != nil {
  564. panic(err)
  565. }
  566. }
  567. ipToMatch := net.ParseIP("192.167.1.2")
  568. b.ResetTimer()
  569. for i := 0; i < b.N; i++ {
  570. if _, err := ranger.Contains(ipToMatch); err != nil {
  571. panic(err)
  572. }
  573. }
  574. }
  575. func BenchmarkNetContains(b *testing.B) {
  576. var nets []*net.IPNet
  577. for i := 0; i < 255; i++ {
  578. cidr := fmt.Sprintf("192.168.%v.1/24", i)
  579. _, network, _ := net.ParseCIDR(cidr)
  580. nets = append(nets, network)
  581. }
  582. ipToMatch := net.ParseIP("192.167.1.1")
  583. b.ResetTimer()
  584. for i := 0; i < b.N; i++ {
  585. for _, n := range nets {
  586. n.Contains(ipToMatch)
  587. }
  588. }
  589. }
  590. func getDefenderForBench() *memoryDefender {
  591. config := &DefenderConfig{
  592. Enabled: true,
  593. BanTime: 30,
  594. BanTimeIncrement: 50,
  595. Threshold: 10,
  596. ScoreInvalid: 2,
  597. ScoreValid: 2,
  598. ObservationTime: 30,
  599. EntriesSoftLimit: 50,
  600. EntriesHardLimit: 100,
  601. }
  602. return &memoryDefender{
  603. baseDefender: baseDefender{
  604. config: config,
  605. },
  606. hosts: make(map[string]hostScore),
  607. banned: make(map[string]time.Time),
  608. }
  609. }
  610. func inc(ip net.IP) {
  611. for j := len(ip) - 1; j >= 0; j-- {
  612. ip[j]++
  613. if ip[j] > 0 {
  614. break
  615. }
  616. }
  617. }