server_test.go 22 KB

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