server_test.go 18 KB

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