trafficRules_test.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Copyright (c) 2022, 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. package server
  20. import (
  21. "encoding/json"
  22. "io/ioutil"
  23. "os"
  24. "reflect"
  25. "testing"
  26. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  27. )
  28. func TestTrafficRulesFilters(t *testing.T) {
  29. trafficRulesJSON := `
  30. {
  31. "DefaultRules" : {
  32. "RateLimits" : {
  33. "WriteUnthrottledBytes": 1,
  34. "WriteBytesPerSecond": 2,
  35. "ReadUnthrottledBytes": 3,
  36. "ReadBytesPerSecond": 4,
  37. "UnthrottleFirstTunnelOnly": true
  38. },
  39. "AllowTCPPorts" : [5],
  40. "AllowUDPPorts" : [6]
  41. },
  42. "FilteredRules" : [
  43. {
  44. "Filter" : {
  45. "Regions" : ["R2"],
  46. "HandshakeParameters" : {
  47. "client_version" : ["1"]
  48. }
  49. },
  50. "Rules" : {
  51. "RateLimits" : {
  52. "WriteBytesPerSecond": 7,
  53. "ReadBytesPerSecond": 8
  54. },
  55. "AllowTCPPorts" : [5,9],
  56. "AllowUDPPorts" : [6,10]
  57. }
  58. },
  59. {
  60. "Filter" : {
  61. "TunnelProtocols" : ["P2"],
  62. "Regions" : ["R3", "R4"],
  63. "HandshakeParameters" : {
  64. "client_version" : ["1", "2"]
  65. }
  66. },
  67. "ExceptFilter" : {
  68. "ISPs" : ["I2", "I3"],
  69. "HandshakeParameters" : {
  70. "client_version" : ["1"]
  71. }
  72. },
  73. "Rules" : {
  74. "RateLimits" : {
  75. "WriteBytesPerSecond": 11,
  76. "ReadBytesPerSecond": 12
  77. },
  78. "AllowTCPPorts" : [5,13],
  79. "AllowUDPPorts" : [6,14]
  80. }
  81. },
  82. {
  83. "Filter" : {
  84. "Regions" : ["R3", "R4"],
  85. "HandshakeParameters" : {
  86. "client_version" : ["1", "2"]
  87. }
  88. },
  89. "ExceptFilter" : {
  90. "ISPs" : ["I2", "I3"],
  91. "HandshakeParameters" : {
  92. "client_version" : ["1"]
  93. }
  94. },
  95. "Rules" : {
  96. "RateLimits" : {
  97. "WriteBytesPerSecond": 15,
  98. "ReadBytesPerSecond": 16
  99. },
  100. "AllowTCPPorts" : [5,17],
  101. "AllowUDPPorts" : [6,18]
  102. }
  103. }
  104. ]
  105. }
  106. `
  107. file, err := ioutil.TempFile("", "trafficRules.config")
  108. if err != nil {
  109. t.Fatalf("TempFile create failed: %s", err)
  110. }
  111. _, err = file.Write([]byte(trafficRulesJSON))
  112. if err != nil {
  113. t.Fatalf("TempFile write failed: %s", err)
  114. }
  115. file.Close()
  116. configFileName := file.Name()
  117. defer os.Remove(configFileName)
  118. trafficRules, err := NewTrafficRulesSet(configFileName)
  119. if err != nil {
  120. t.Fatalf("NewTrafficRulesSet failed: %s", err)
  121. }
  122. err = trafficRules.Validate()
  123. if err != nil {
  124. t.Fatalf("TrafficRulesSet.Validate failed: %s", err)
  125. }
  126. makePortList := func(portsJSON string) common.PortList {
  127. var p common.PortList
  128. _ = json.Unmarshal([]byte(portsJSON), &p)
  129. return p
  130. }
  131. testCases := []struct {
  132. description string
  133. isFirstTunnelInSession bool
  134. tunnelProtocol string
  135. geoIPData GeoIPData
  136. state handshakeState
  137. expectedWriteUnthrottledBytes int64
  138. expectedWriteBytesPerSecond int64
  139. expectedReadUnthrottledBytes int64
  140. expectedReadBytesPerSecond int64
  141. expectedAllowTCPPorts common.PortList
  142. expectedAllowUDPPorts common.PortList
  143. }{
  144. {
  145. "get defaults",
  146. true,
  147. "P1",
  148. GeoIPData{Country: "R1", ISP: "I1"},
  149. handshakeState{apiParams: map[string]interface{}{"client_version": "1"}, completed: true},
  150. 1, 2, 3, 4, makePortList("[5]"), makePortList("[6]"),
  151. },
  152. {
  153. "get defaults for not first tunnel in session",
  154. false,
  155. "P1",
  156. GeoIPData{Country: "R1", ISP: "I1"},
  157. handshakeState{apiParams: map[string]interface{}{"client_version": "1"}, completed: true},
  158. 0, 2, 0, 4, makePortList("[5]"), makePortList("[6]"),
  159. },
  160. {
  161. "get first filtered rule",
  162. true,
  163. "P1",
  164. GeoIPData{Country: "R2", ISP: "I1"},
  165. handshakeState{apiParams: map[string]interface{}{"client_version": "1"}, completed: true},
  166. 1, 7, 3, 8, makePortList("[5,9]"), makePortList("[6,10]"),
  167. },
  168. {
  169. "don't get first filtered rule with incomplete match",
  170. true,
  171. "P1",
  172. GeoIPData{Country: "R2", ISP: "I1"},
  173. handshakeState{apiParams: map[string]interface{}{"client_version": "2"}, completed: true},
  174. 1, 2, 3, 4, makePortList("[5]"), makePortList("[6]"),
  175. },
  176. {
  177. "get second filtered rule",
  178. true,
  179. "P2",
  180. GeoIPData{Country: "R3", ISP: "I1"},
  181. handshakeState{apiParams: map[string]interface{}{"client_version": "2"}, completed: true},
  182. 1, 11, 3, 12, makePortList("[5,13]"), makePortList("[6,14]"),
  183. },
  184. {
  185. "get second filtered rule with incomplete exception",
  186. true,
  187. "P2",
  188. GeoIPData{Country: "R3", ISP: "I2"},
  189. handshakeState{apiParams: map[string]interface{}{"client_version": "2"}, completed: true},
  190. 1, 11, 3, 12, makePortList("[5,13]"), makePortList("[6,14]"),
  191. },
  192. {
  193. "don't get second filtered rule due to exception",
  194. true,
  195. "P2",
  196. GeoIPData{Country: "R3", ISP: "I2"},
  197. handshakeState{apiParams: map[string]interface{}{"client_version": "1"}, completed: true},
  198. 1, 2, 3, 4, makePortList("[5]"), makePortList("[6]"),
  199. },
  200. {
  201. "get third filtered rule",
  202. true,
  203. "P1",
  204. GeoIPData{Country: "R3", ISP: "I1"},
  205. handshakeState{apiParams: map[string]interface{}{"client_version": "1"}, completed: true},
  206. 1, 15, 3, 16, makePortList("[5,17]"), makePortList("[6,18]"),
  207. },
  208. {
  209. "don't get third filtered rule due to exception",
  210. true,
  211. "P1",
  212. GeoIPData{Country: "R3", ISP: "I2"},
  213. handshakeState{apiParams: map[string]interface{}{"client_version": "1"}, completed: true},
  214. 1, 2, 3, 4, makePortList("[5]"), makePortList("[6]"),
  215. },
  216. }
  217. for _, testCase := range testCases {
  218. t.Run(testCase.description, func(t *testing.T) {
  219. rules := trafficRules.GetTrafficRules(
  220. testCase.isFirstTunnelInSession,
  221. testCase.tunnelProtocol,
  222. testCase.geoIPData,
  223. testCase.state)
  224. if *rules.RateLimits.WriteUnthrottledBytes != testCase.expectedWriteUnthrottledBytes {
  225. t.Errorf("unexpected rules.RateLimits.WriteUnthrottledBytes: %v != %v",
  226. *rules.RateLimits.WriteUnthrottledBytes, testCase.expectedWriteUnthrottledBytes)
  227. }
  228. if *rules.RateLimits.WriteBytesPerSecond != testCase.expectedWriteBytesPerSecond {
  229. t.Errorf("unexpected rules.RateLimits.WriteBytesPerSecond: %v != %v",
  230. *rules.RateLimits.WriteBytesPerSecond, testCase.expectedWriteBytesPerSecond)
  231. }
  232. if *rules.RateLimits.ReadUnthrottledBytes != testCase.expectedReadUnthrottledBytes {
  233. t.Errorf("unexpected rules.RateLimits.ReadUnthrottledBytes: %v != %v",
  234. *rules.RateLimits.ReadUnthrottledBytes, testCase.expectedReadUnthrottledBytes)
  235. }
  236. if *rules.RateLimits.ReadBytesPerSecond != testCase.expectedReadBytesPerSecond {
  237. t.Errorf("unexpected rules.RateLimits.ReadBytesPerSecond: %v != %v",
  238. *rules.RateLimits.ReadBytesPerSecond, testCase.expectedReadBytesPerSecond)
  239. }
  240. if !reflect.DeepEqual(*rules.AllowTCPPorts, testCase.expectedAllowTCPPorts) {
  241. t.Errorf("unexpected rules.RateLimits.AllowTCPPorts: %v != %v",
  242. *rules.AllowTCPPorts, testCase.expectedAllowTCPPorts)
  243. }
  244. if !reflect.DeepEqual(*rules.AllowUDPPorts, testCase.expectedAllowUDPPorts) {
  245. t.Errorf("unexpected rules.RateLimits.AllowUDPPorts: %v != %v",
  246. *rules.AllowUDPPorts, testCase.expectedAllowUDPPorts)
  247. }
  248. })
  249. }
  250. }