github.com/Psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/server/blocklist_test.go (about) 1 /* 2 * Copyright (c) 2019, Psiphon Inc. 3 * All rights reserved. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package server 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "net" 26 "os" 27 "path/filepath" 28 "testing" 29 "time" 30 31 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common" 32 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng" 33 ) 34 35 func TestBlocklist(t *testing.T) { 36 37 testDataDirName, err := ioutil.TempDir("", "psiphon-blocklist-test") 38 if err != nil { 39 t.Fatalf("TempDir failed: %s", err) 40 } 41 defer os.RemoveAll(testDataDirName) 42 43 filename := filepath.Join(testDataDirName, "blocklist") 44 45 hitIPv4 := net.ParseIP("0.0.0.0") 46 hitIPv6 := net.ParseIP("2001:db8:f75c::0951:58bc:ef22") 47 hitDomain := "example.org" 48 missIPv4 := net.ParseIP("255.255.255.255") 49 sources := []string{"source1", "source2", "source3", "source4", "source4"} 50 subjects := []string{"subject1", "subject2", "subject3", "subject4", "subject4"} 51 hitPresent := []int{0, 1} 52 entriesPerSource := 100000 53 54 file, err := os.Create(filename) 55 if err != nil { 56 t.Fatalf("Open failed: %s", err) 57 } 58 defer file.Close() 59 60 for i := 0; i < len(sources); i++ { 61 _, err := fmt.Fprintf(file, "# comment\n# comment\n# comment\n") 62 if err != nil { 63 t.Fatalf("Fprintf failed: %s", err) 64 } 65 hitIPv4Index := -1 66 hitIPv6Index := -1 67 hitDomainIndex := -1 68 if common.ContainsInt(hitPresent, i) { 69 indices := prng.Perm(entriesPerSource) 70 hitIPv4Index = indices[0] - 1 71 hitIPv6Index = indices[1] - 1 72 hitDomainIndex = indices[2] - 1 73 } 74 for j := 0; j < entriesPerSource; j++ { 75 var address string 76 if j == hitIPv4Index { 77 address = hitIPv4.String() 78 } else if j == hitIPv6Index { 79 address = hitIPv6.String() 80 } else if j == hitDomainIndex { 81 address = hitDomain 82 } else { 83 address = fmt.Sprintf( 84 "%d.%d.%d.%d", 85 prng.Range(1, 254), prng.Range(1, 254), 86 prng.Range(1, 254), prng.Range(1, 254)) 87 } 88 _, err := fmt.Fprintf(file, "%s,%s,%s\n", 89 address, sources[i], subjects[i]) 90 if err != nil { 91 t.Fatalf("Fprintf failed: %s", err) 92 } 93 } 94 } 95 96 file.Close() 97 98 b, err := NewBlocklist(filename) 99 if err != nil { 100 t.Fatalf("NewBlocklist failed: %s", err) 101 } 102 103 for _, hitIP := range []net.IP{hitIPv4, hitIPv6} { 104 105 tags := b.LookupIP(hitIP) 106 107 if tags == nil { 108 t.Fatalf("unexpected miss") 109 } 110 111 if len(tags) != len(hitPresent) { 112 t.Fatalf("unexpected hit tag count") 113 } 114 115 for _, tag := range tags { 116 sourceFound := false 117 subjectFound := false 118 for _, i := range hitPresent { 119 if tag.Source == sources[i] { 120 sourceFound = true 121 } 122 if tag.Subject == subjects[i] { 123 subjectFound = true 124 } 125 } 126 if !sourceFound || !subjectFound { 127 t.Fatalf("unexpected hit tag") 128 } 129 } 130 } 131 132 tags := b.LookupDomain(hitDomain) 133 134 if tags == nil { 135 t.Fatalf("unexpected miss") 136 } 137 138 if len(tags) != len(hitPresent) { 139 t.Fatalf("unexpected hit tag count") 140 } 141 142 if b.LookupIP(missIPv4) != nil { 143 t.Fatalf("unexpected hit") 144 } 145 146 numLookups := 10 147 numIterations := 1000000 148 149 lookups := make([]net.IP, numLookups) 150 151 for i := 0; i < numLookups; i++ { 152 lookups[i] = net.ParseIP( 153 fmt.Sprintf( 154 "%d.%d.%d.%d", 155 prng.Range(1, 254), prng.Range(1, 254), 156 prng.Range(1, 254), prng.Range(1, 254))) 157 } 158 159 start := time.Now() 160 161 for i := 0; i < numIterations; i++ { 162 _ = b.LookupIP(lookups[i%numLookups]) 163 } 164 165 t.Logf( 166 "average time per lookup in %d entries: %s", 167 len(sources)*entriesPerSource, 168 time.Since(start)/time.Duration(numIterations)) 169 }