server_test.go 22 KB

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