server_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. /*
  2. * Copyright (c) 2016, 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. "errors"
  23. "flag"
  24. "fmt"
  25. "io/ioutil"
  26. "net"
  27. "net/http"
  28. "net/url"
  29. "os"
  30. "strconv"
  31. "sync"
  32. "syscall"
  33. "testing"
  34. "time"
  35. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
  36. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  37. "golang.org/x/net/proxy"
  38. )
  39. func TestMain(m *testing.M) {
  40. flag.Parse()
  41. os.Remove(psiphon.DATA_STORE_FILENAME)
  42. psiphon.SetEmitDiagnosticNotices(true)
  43. CLIENT_VERIFICATION_REQUIRED = true
  44. os.Exit(m.Run())
  45. }
  46. // Note: not testing fronting meek protocols, which client is
  47. // hard-wired to except running on privileged ports 80 and 443.
  48. func TestSSH(t *testing.T) {
  49. runServer(t,
  50. &runServerConfig{
  51. tunnelProtocol: "SSH",
  52. enableSSHAPIRequests: true,
  53. doHotReload: false,
  54. denyTrafficRules: false,
  55. })
  56. }
  57. func TestOSSH(t *testing.T) {
  58. runServer(t,
  59. &runServerConfig{
  60. tunnelProtocol: "OSSH",
  61. enableSSHAPIRequests: true,
  62. doHotReload: false,
  63. denyTrafficRules: false,
  64. })
  65. }
  66. func TestUnfrontedMeek(t *testing.T) {
  67. runServer(t,
  68. &runServerConfig{
  69. tunnelProtocol: "UNFRONTED-MEEK-OSSH",
  70. enableSSHAPIRequests: true,
  71. doHotReload: false,
  72. denyTrafficRules: false,
  73. })
  74. }
  75. func TestUnfrontedMeekHTTPS(t *testing.T) {
  76. runServer(t,
  77. &runServerConfig{
  78. tunnelProtocol: "UNFRONTED-MEEK-HTTPS-OSSH",
  79. enableSSHAPIRequests: true,
  80. doHotReload: false,
  81. denyTrafficRules: false,
  82. })
  83. }
  84. func TestWebTransportAPIRequests(t *testing.T) {
  85. runServer(t,
  86. &runServerConfig{
  87. tunnelProtocol: "OSSH",
  88. enableSSHAPIRequests: false,
  89. doHotReload: false,
  90. denyTrafficRules: false,
  91. })
  92. }
  93. func TestHotReload(t *testing.T) {
  94. runServer(t,
  95. &runServerConfig{
  96. tunnelProtocol: "OSSH",
  97. enableSSHAPIRequests: true,
  98. doHotReload: true,
  99. denyTrafficRules: false,
  100. })
  101. }
  102. func TestDenyTrafficRules(t *testing.T) {
  103. runServer(t,
  104. &runServerConfig{
  105. tunnelProtocol: "OSSH",
  106. enableSSHAPIRequests: true,
  107. doHotReload: true,
  108. denyTrafficRules: true,
  109. })
  110. }
  111. type runServerConfig struct {
  112. tunnelProtocol string
  113. enableSSHAPIRequests bool
  114. doHotReload bool
  115. denyTrafficRules bool
  116. }
  117. func sendNotificationReceived(c chan<- struct{}) {
  118. select {
  119. case c <- *new(struct{}):
  120. default:
  121. }
  122. }
  123. func waitOnNotification(t *testing.T, c, timeoutSignal <-chan struct{}, timeoutMessage string) {
  124. select {
  125. case <-c:
  126. case <-timeoutSignal:
  127. t.Fatalf(timeoutMessage)
  128. }
  129. }
  130. const dummyClientVerificationPayload = `
  131. {
  132. "status": 0,
  133. "payload": ""
  134. }`
  135. func runServer(t *testing.T, runConfig *runServerConfig) {
  136. // create a server
  137. var err error
  138. serverIPaddress := ""
  139. for _, interfaceName := range []string{"eth0", "en0"} {
  140. serverIPaddress, err = psiphon.GetInterfaceIPAddress(interfaceName)
  141. if err == nil {
  142. break
  143. }
  144. }
  145. if err != nil {
  146. t.Fatalf("error getting server IP address: %s", err)
  147. }
  148. serverConfigJSON, _, encodedServerEntry, err := GenerateConfig(
  149. &GenerateConfigParams{
  150. ServerIPAddress: serverIPaddress,
  151. EnableSSHAPIRequests: runConfig.enableSSHAPIRequests,
  152. WebServerPort: 8000,
  153. TunnelProtocolPorts: map[string]int{runConfig.tunnelProtocol: 4000},
  154. })
  155. if err != nil {
  156. t.Fatalf("error generating server config: %s", err)
  157. }
  158. // customize server config
  159. // Pave psinet with random values to test handshake homepages.
  160. psinetFilename := "psinet.json"
  161. sponsorID, expectedHomepageURL := pavePsinetDatabaseFile(t, psinetFilename)
  162. // Pave traffic rules file which exercises handshake parameter filtering. Client
  163. // must handshake with specified sponsor ID in order to allow ports for tunneled
  164. // requests.
  165. trafficRulesFilename := "traffic_rules.json"
  166. paveTrafficRulesFile(t, trafficRulesFilename, sponsorID, runConfig.denyTrafficRules)
  167. var serverConfig interface{}
  168. json.Unmarshal(serverConfigJSON, &serverConfig)
  169. serverConfig.(map[string]interface{})["GeoIPDatabaseFilename"] = ""
  170. serverConfig.(map[string]interface{})["PsinetDatabaseFilename"] = psinetFilename
  171. serverConfig.(map[string]interface{})["TrafficRulesFilename"] = trafficRulesFilename
  172. serverConfig.(map[string]interface{})["LogLevel"] = "debug"
  173. // 1 second is the minimum period; should be small enough to emit a log during the
  174. // test run, but not guaranteed
  175. serverConfig.(map[string]interface{})["LoadMonitorPeriodSeconds"] = 1
  176. serverConfigJSON, _ = json.Marshal(serverConfig)
  177. // run server
  178. serverWaitGroup := new(sync.WaitGroup)
  179. serverWaitGroup.Add(1)
  180. go func() {
  181. defer serverWaitGroup.Done()
  182. err := RunServices(serverConfigJSON)
  183. if err != nil {
  184. // TODO: wrong goroutine for t.FatalNow()
  185. t.Fatalf("error running server: %s", err)
  186. }
  187. }()
  188. defer func() {
  189. // Test: orderly server shutdown
  190. p, _ := os.FindProcess(os.Getpid())
  191. p.Signal(os.Interrupt)
  192. shutdownTimeout := time.NewTimer(5 * time.Second)
  193. shutdownOk := make(chan struct{}, 1)
  194. go func() {
  195. serverWaitGroup.Wait()
  196. shutdownOk <- *new(struct{})
  197. }()
  198. select {
  199. case <-shutdownOk:
  200. case <-shutdownTimeout.C:
  201. t.Fatalf("server shutdown timeout exceeded")
  202. }
  203. }()
  204. // Test: hot reload (of psinet and traffic rules)
  205. if runConfig.doHotReload {
  206. // TODO: monitor logs for more robust wait-until-loaded
  207. time.Sleep(1 * time.Second)
  208. // Pave a new psinet and traffic rules with different random values.
  209. sponsorID, expectedHomepageURL = pavePsinetDatabaseFile(t, psinetFilename)
  210. paveTrafficRulesFile(t, trafficRulesFilename, sponsorID, runConfig.denyTrafficRules)
  211. p, _ := os.FindProcess(os.Getpid())
  212. p.Signal(syscall.SIGUSR1)
  213. // TODO: monitor logs for more robust wait-until-reloaded
  214. time.Sleep(1 * time.Second)
  215. // After reloading psinet, the new sponsorID/expectedHomepageURL
  216. // should be active, as tested in the client "Homepage" notice
  217. // handler below.
  218. }
  219. // connect to server with client
  220. // TODO: currently, TargetServerEntry only works with one tunnel
  221. numTunnels := 1
  222. localSOCKSProxyPort := 1081
  223. localHTTPProxyPort := 8081
  224. establishTunnelPausePeriodSeconds := 1
  225. // Note: calling LoadConfig ensures all *int config fields are initialized
  226. clientConfigJSON := `
  227. {
  228. "ClientPlatform" : "Android",
  229. "ClientVersion" : "0",
  230. "SponsorId" : "0",
  231. "PropagationChannelId" : "0"
  232. }`
  233. clientConfig, _ := psiphon.LoadConfig([]byte(clientConfigJSON))
  234. clientConfig.SponsorId = sponsorID
  235. clientConfig.ConnectionWorkerPoolSize = numTunnels
  236. clientConfig.TunnelPoolSize = numTunnels
  237. clientConfig.DisableRemoteServerListFetcher = true
  238. clientConfig.EstablishTunnelPausePeriodSeconds = &establishTunnelPausePeriodSeconds
  239. clientConfig.TargetServerEntry = string(encodedServerEntry)
  240. clientConfig.TunnelProtocol = runConfig.tunnelProtocol
  241. clientConfig.LocalSocksProxyPort = localSOCKSProxyPort
  242. clientConfig.LocalHttpProxyPort = localHTTPProxyPort
  243. err = psiphon.InitDataStore(clientConfig)
  244. if err != nil {
  245. t.Fatalf("error initializing client datastore: %s", err)
  246. }
  247. controller, err := psiphon.NewController(clientConfig)
  248. if err != nil {
  249. t.Fatalf("error creating client controller: %s", err)
  250. }
  251. tunnelsEstablished := make(chan struct{}, 1)
  252. homepageReceived := make(chan struct{}, 1)
  253. verificationRequired := make(chan struct{}, 1)
  254. verificationCompleted := make(chan struct{}, 1)
  255. psiphon.SetNoticeOutput(psiphon.NewNoticeReceiver(
  256. func(notice []byte) {
  257. //fmt.Printf("%s\n", string(notice))
  258. noticeType, payload, err := psiphon.GetNotice(notice)
  259. if err != nil {
  260. return
  261. }
  262. switch noticeType {
  263. case "Tunnels":
  264. // Do not set verification payload until tunnel is
  265. // established. Otherwise will silently take no action.
  266. controller.SetClientVerificationPayloadForActiveTunnels("")
  267. count := int(payload["count"].(float64))
  268. if count >= numTunnels {
  269. sendNotificationReceived(tunnelsEstablished)
  270. }
  271. case "Homepage":
  272. homepageURL := payload["url"].(string)
  273. if homepageURL != expectedHomepageURL {
  274. // TODO: wrong goroutine for t.FatalNow()
  275. t.Fatalf("unexpected homepage: %s", homepageURL)
  276. }
  277. sendNotificationReceived(homepageReceived)
  278. case "ClientVerificationRequired":
  279. sendNotificationReceived(verificationRequired)
  280. controller.SetClientVerificationPayloadForActiveTunnels(dummyClientVerificationPayload)
  281. case "NoticeClientVerificationRequestCompleted":
  282. sendNotificationReceived(verificationCompleted)
  283. }
  284. }))
  285. controllerShutdownBroadcast := make(chan struct{})
  286. controllerWaitGroup := new(sync.WaitGroup)
  287. controllerWaitGroup.Add(1)
  288. go func() {
  289. defer controllerWaitGroup.Done()
  290. controller.Run(controllerShutdownBroadcast)
  291. }()
  292. defer func() {
  293. close(controllerShutdownBroadcast)
  294. shutdownTimeout := time.NewTimer(20 * time.Second)
  295. shutdownOk := make(chan struct{}, 1)
  296. go func() {
  297. controllerWaitGroup.Wait()
  298. shutdownOk <- *new(struct{})
  299. }()
  300. select {
  301. case <-shutdownOk:
  302. case <-shutdownTimeout.C:
  303. t.Fatalf("controller shutdown timeout exceeded")
  304. }
  305. }()
  306. // Test: tunnels must be established, and correct homepage
  307. // must be received, within 30 seconds
  308. timeoutSignal := make(chan struct{})
  309. go func() {
  310. timer := time.NewTimer(30 * time.Second)
  311. <-timer.C
  312. close(timeoutSignal)
  313. }()
  314. waitOnNotification(t, tunnelsEstablished, timeoutSignal, "tunnel establish timeout exceeded")
  315. waitOnNotification(t, homepageReceived, timeoutSignal, "homepage received timeout exceeded")
  316. waitOnNotification(t, verificationRequired, timeoutSignal, "verification required timeout exceeded")
  317. waitOnNotification(t, verificationCompleted, timeoutSignal, "verification completed timeout exceeded")
  318. // Test: tunneled web site fetch
  319. err = makeTunneledWebRequest(t, localHTTPProxyPort)
  320. if err == nil {
  321. if runConfig.denyTrafficRules {
  322. t.Fatalf("unexpected tunneled web request success")
  323. }
  324. } else {
  325. if !runConfig.denyTrafficRules {
  326. t.Fatalf("tunneled web request failed: %s", err)
  327. }
  328. }
  329. // Test: tunneled UDP packets
  330. udpgwServerAddress := serverConfig.(map[string]interface{})["UDPInterceptUdpgwServerAddress"].(string)
  331. err = makeTunneledNTPRequest(t, localSOCKSProxyPort, udpgwServerAddress)
  332. if err == nil {
  333. if runConfig.denyTrafficRules {
  334. t.Fatalf("unexpected tunneled NTP request success")
  335. }
  336. } else {
  337. if !runConfig.denyTrafficRules {
  338. t.Fatalf("tunneled NTP request failed: %s", err)
  339. }
  340. }
  341. }
  342. func makeTunneledWebRequest(t *testing.T, localHTTPProxyPort int) error {
  343. testUrl := "https://psiphon.ca"
  344. roundTripTimeout := 30 * time.Second
  345. proxyUrl, err := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", localHTTPProxyPort))
  346. if err != nil {
  347. return fmt.Errorf("error initializing proxied HTTP request: %s", err)
  348. }
  349. httpClient := &http.Client{
  350. Transport: &http.Transport{
  351. Proxy: http.ProxyURL(proxyUrl),
  352. },
  353. Timeout: roundTripTimeout,
  354. }
  355. response, err := httpClient.Get(testUrl)
  356. if err != nil {
  357. return fmt.Errorf("error sending proxied HTTP request: %s", err)
  358. }
  359. _, err = ioutil.ReadAll(response.Body)
  360. if err != nil {
  361. return fmt.Errorf("error reading proxied HTTP response: %s", err)
  362. }
  363. response.Body.Close()
  364. return nil
  365. }
  366. func makeTunneledNTPRequest(t *testing.T, localSOCKSProxyPort int, udpgwServerAddress string) error {
  367. testHostname := "pool.ntp.org"
  368. timeout := 10 * time.Second
  369. localUDPProxyAddress, err := net.ResolveUDPAddr("udp", "127.0.0.1:7301")
  370. if err != nil {
  371. t.Fatalf("ResolveUDPAddr failed: %s", err)
  372. }
  373. // Note: this proxy is intended for this test only -- it only accepts a single connection,
  374. // handles it, and then terminates.
  375. localUDPProxy := func(destinationIP net.IP, destinationPort uint16, waitGroup *sync.WaitGroup) {
  376. if waitGroup != nil {
  377. defer waitGroup.Done()
  378. }
  379. destination := net.JoinHostPort(destinationIP.String(), strconv.Itoa(int(destinationPort)))
  380. serverUDPConn, err := net.ListenUDP("udp", localUDPProxyAddress)
  381. if err != nil {
  382. t.Logf("ListenUDP for %s failed: %s", destination, err)
  383. return
  384. }
  385. defer serverUDPConn.Close()
  386. udpgwPreambleSize := 11 // see writeUdpgwPreamble
  387. buffer := make([]byte, udpgwProtocolMaxMessageSize)
  388. packetSize, clientAddr, err := serverUDPConn.ReadFromUDP(
  389. buffer[udpgwPreambleSize:len(buffer)])
  390. if err != nil {
  391. t.Logf("serverUDPConn.Read for %s failed: %s", destination, err)
  392. return
  393. }
  394. socksProxyAddress := fmt.Sprintf("127.0.0.1:%d", localSOCKSProxyPort)
  395. dialer, err := proxy.SOCKS5("tcp", socksProxyAddress, nil, proxy.Direct)
  396. if err != nil {
  397. t.Logf("proxy.SOCKS5 for %s failed: %s", destination, err)
  398. return
  399. }
  400. socksTCPConn, err := dialer.Dial("tcp", udpgwServerAddress)
  401. if err != nil {
  402. t.Logf("dialer.Dial for %s failed: %s", destination, err)
  403. return
  404. }
  405. defer socksTCPConn.Close()
  406. flags := uint8(0)
  407. if destinationPort == 53 {
  408. flags = udpgwProtocolFlagDNS
  409. }
  410. err = writeUdpgwPreamble(
  411. udpgwPreambleSize,
  412. flags,
  413. 0,
  414. destinationIP,
  415. destinationPort,
  416. uint16(packetSize),
  417. buffer)
  418. if err != nil {
  419. t.Logf("writeUdpgwPreamble for %s failed: %s", destination, err)
  420. return
  421. }
  422. _, err = socksTCPConn.Write(buffer[0 : udpgwPreambleSize+packetSize])
  423. if err != nil {
  424. t.Logf("socksTCPConn.Write for %s failed: %s", destination, err)
  425. return
  426. }
  427. updgwProtocolMessage, err := readUdpgwMessage(socksTCPConn, buffer)
  428. if err != nil {
  429. t.Logf("readUdpgwMessage for %s failed: %s", destination, err)
  430. return
  431. }
  432. _, err = serverUDPConn.WriteToUDP(updgwProtocolMessage.packet, clientAddr)
  433. if err != nil {
  434. t.Logf("serverUDPConn.Write for %s failed: %s", destination, err)
  435. return
  436. }
  437. }
  438. // Tunneled DNS request
  439. waitGroup := new(sync.WaitGroup)
  440. waitGroup.Add(1)
  441. go localUDPProxy(
  442. net.IP(make([]byte, 4)), // ignored due to transparent DNS forwarding
  443. 53,
  444. waitGroup)
  445. // TODO: properly synchronize with local UDP proxy startup
  446. time.Sleep(1 * time.Second)
  447. clientUDPConn, err := net.DialUDP("udp", nil, localUDPProxyAddress)
  448. if err != nil {
  449. return fmt.Errorf("DialUDP failed: %s", err)
  450. }
  451. clientUDPConn.SetReadDeadline(time.Now().Add(timeout))
  452. clientUDPConn.SetWriteDeadline(time.Now().Add(timeout))
  453. addrs, _, err := psiphon.ResolveIP(testHostname, clientUDPConn)
  454. clientUDPConn.Close()
  455. if err == nil && (len(addrs) == 0 || len(addrs[0]) < 4) {
  456. err = errors.New("no address")
  457. }
  458. if err != nil {
  459. return fmt.Errorf("ResolveIP failed: %s", err)
  460. }
  461. waitGroup.Wait()
  462. // Tunneled NTP request
  463. go localUDPProxy(addrs[0][len(addrs[0])-4:], 123, nil)
  464. // TODO: properly synchronize with local UDP proxy startup
  465. time.Sleep(1 * time.Second)
  466. clientUDPConn, err = net.DialUDP("udp", nil, localUDPProxyAddress)
  467. if err != nil {
  468. return fmt.Errorf("DialUDP failed: %s", err)
  469. }
  470. clientUDPConn.SetReadDeadline(time.Now().Add(timeout))
  471. clientUDPConn.SetWriteDeadline(time.Now().Add(timeout))
  472. // NTP protocol code from: https://groups.google.com/d/msg/golang-nuts/FlcdMU5fkLQ/CAeoD9eqm-IJ
  473. ntpData := make([]byte, 48)
  474. ntpData[0] = 3<<3 | 3
  475. _, err = clientUDPConn.Write(ntpData)
  476. if err != nil {
  477. clientUDPConn.Close()
  478. return fmt.Errorf("NTP Write failed: %s", err)
  479. }
  480. _, err = clientUDPConn.Read(ntpData)
  481. if err != nil {
  482. clientUDPConn.Close()
  483. return fmt.Errorf("NTP Read failed: %s", err)
  484. }
  485. clientUDPConn.Close()
  486. var sec, frac uint64
  487. sec = uint64(ntpData[43]) | uint64(ntpData[42])<<8 | uint64(ntpData[41])<<16 | uint64(ntpData[40])<<24
  488. frac = uint64(ntpData[47]) | uint64(ntpData[46])<<8 | uint64(ntpData[45])<<16 | uint64(ntpData[44])<<24
  489. nsec := sec * 1e9
  490. nsec += (frac * 1e9) >> 32
  491. ntpNow := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(nsec)).Local()
  492. now := time.Now()
  493. diff := ntpNow.Sub(now)
  494. if diff < 0 {
  495. diff = -diff
  496. }
  497. if diff > 1*time.Minute {
  498. return fmt.Errorf("Unexpected NTP time: %s; local time: %s", ntpNow, now)
  499. }
  500. return nil
  501. }
  502. func pavePsinetDatabaseFile(t *testing.T, psinetFilename string) (string, string) {
  503. sponsorID, _ := common.MakeRandomStringHex(8)
  504. fakeDomain, _ := common.MakeRandomStringHex(4)
  505. fakePath, _ := common.MakeRandomStringHex(4)
  506. expectedHomepageURL := fmt.Sprintf("https://%s.com/%s", fakeDomain, fakePath)
  507. psinetJSONFormat := `
  508. {
  509. "sponsors": {
  510. "%s": {
  511. "home_pages": {
  512. "None": [
  513. {
  514. "region": null,
  515. "url": "%s"
  516. }
  517. ]
  518. }
  519. }
  520. }
  521. }
  522. `
  523. psinetJSON := fmt.Sprintf(psinetJSONFormat, sponsorID, expectedHomepageURL)
  524. err := ioutil.WriteFile(psinetFilename, []byte(psinetJSON), 0600)
  525. if err != nil {
  526. t.Fatalf("error paving psinet database file: %s", err)
  527. }
  528. return sponsorID, expectedHomepageURL
  529. }
  530. func paveTrafficRulesFile(t *testing.T, trafficRulesFilename, sponsorID string, deny bool) {
  531. allowTCPPorts := "443"
  532. allowUDPPorts := "53, 123"
  533. if deny {
  534. allowTCPPorts = "0"
  535. allowUDPPorts = "0"
  536. }
  537. trafficRulesJSONFormat := `
  538. {
  539. "DefaultRules" : {
  540. "RateLimits" : {
  541. "ReadBytesPerSecond": 16384,
  542. "WriteBytesPerSecond": 16384
  543. },
  544. "AllowTCPPorts" : [0],
  545. "AllowUDPPorts" : [0]
  546. },
  547. "FilteredRules" : [
  548. {
  549. "Filter" : {
  550. "HandshakeParameters" : {
  551. "sponsor_id" : ["%s"]
  552. }
  553. },
  554. "Rules" : {
  555. "RateLimits" : {
  556. "ReadUnthrottledBytes": 132352,
  557. "WriteUnthrottledBytes": 132352
  558. },
  559. "AllowTCPPorts" : [%s],
  560. "AllowUDPPorts" : [%s]
  561. }
  562. }
  563. ]
  564. }
  565. `
  566. trafficRulesJSON := fmt.Sprintf(
  567. trafficRulesJSONFormat, sponsorID, allowTCPPorts, allowUDPPorts)
  568. err := ioutil.WriteFile(trafficRulesFilename, []byte(trafficRulesJSON), 0600)
  569. if err != nil {
  570. t.Fatalf("error paving traffic rules file: %s", err)
  571. }
  572. }