Public Internet facing gateway (TCP reverse tunnel) for greenhouse 🏔️⛰️🛤️⛰️🏔️
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

897 lines
29 KiB

3 weeks ago
  1. package main
  2. import (
  3. "bufio"
  4. "bytes"
  5. "crypto/rand"
  6. "crypto/rsa"
  7. "crypto/tls"
  8. "crypto/x509"
  9. "crypto/x509/pkix"
  10. "encoding/binary"
  11. "encoding/json"
  12. "fmt"
  13. "io/ioutil"
  14. "log"
  15. "math/big"
  16. "net"
  17. "net/http"
  18. "net/url"
  19. "os"
  20. "path"
  21. "path/filepath"
  22. "regexp"
  23. "runtime"
  24. "strconv"
  25. "strings"
  26. "time"
  27. errors "git.sequentialread.com/forest/pkg-errors"
  28. tunnel "git.sequentialread.com/forest/threshold/tunnel-lib"
  29. "git.sequentialread.com/forest/threshold/tunnel-lib/proto"
  30. proxyprotocol "github.com/armon/go-proxyproto"
  31. "golang.org/x/net/proxy"
  32. )
  33. type ClientConfig struct {
  34. DebugLog bool
  35. ClientId string
  36. GreenhouseDomain string
  37. GreenhouseAPIToken string
  38. GreenhouseThresholdPort int
  39. // Theshold client will listen for SOCKS5 connections on the specified port (for example, "127.0.0.1:1080")
  40. // and tunnel them to the threshold server, where the server will handle the SOCKS5 CONNECT requests
  41. // and proxy the connections. Use this for hosting email servers or any other server where Outbound
  42. // connections have to come from the same IP address which is used for Inbound connections
  43. TunneledOutboundSOCKS5ListenAddress string
  44. MaximumConnectionRetrySeconds int
  45. ServerAddr string
  46. Servers []string
  47. DefaultTunnels *LiveConfigUpdate
  48. CaCertificateFilesGlob string
  49. ClientTlsKeyFile string
  50. ClientTlsCertificateFile string
  51. CaCertificate string
  52. ClientTlsKey string
  53. ClientTlsCertificate string
  54. // Use this when a local proxy is required for threshold client (this app) to talk to the threshold server.
  55. // For example, if a firewall or other hostile network environment might otherwise prevent you from connecting.
  56. // This would be the address of an external 3rd party SOCKS5 proxy server that is reachable from your computer.
  57. // If you set the hostname to "gateway", like "HostileNetworkEnvironmentEvasionSOCKS5Address": "gateway:1080"
  58. // then it will try to SOCKS5 connect to any/all default gateways (routers) on the given port (1080 in this case).
  59. HostileNetworkEnvironmentEvasionSOCKS5Address string
  60. AdminUnixSocket string
  61. AdminAPIPort int
  62. AdminAPICACertificateFile string
  63. AdminAPITlsKeyFile string
  64. AdminAPITlsCertificateFile string
  65. Metrics MetricsConfig
  66. }
  67. type ClientServer struct {
  68. Client *tunnel.Client
  69. ServerUrl *url.URL
  70. ServerHostPort string
  71. }
  72. type LiveConfigUpdate struct {
  73. Listeners []ListenerConfig
  74. ServiceToLocalAddrMap map[string]string
  75. }
  76. type ThresholdTenantInfo struct {
  77. ThresholdServers []string
  78. }
  79. type maximumBackoff struct {
  80. Maximum time.Duration
  81. Base tunnel.Backoff
  82. }
  83. func (bo *maximumBackoff) NextBackOff() time.Duration {
  84. result := bo.Base.NextBackOff()
  85. if result > bo.Maximum {
  86. return bo.Maximum
  87. }
  88. return result
  89. }
  90. func (bo *maximumBackoff) Reset() {
  91. bo.Base.Reset()
  92. }
  93. type clientAdminAPI struct{}
  94. // Client State
  95. var clientServers []ClientServer
  96. var tlsClientConfig *tls.Config
  97. var serviceToLocalAddrMap *map[string]string
  98. var isTestMode bool
  99. var testModeListeners map[string]ListenerConfig
  100. var testModeTLSConfig *tls.Config
  101. var testTokens []string
  102. func runClient(configFileName *string) {
  103. configBytes := getConfigBytes(configFileName)
  104. var config ClientConfig
  105. err := json.Unmarshal(configBytes, &config)
  106. if err != nil {
  107. log.Fatalf("runClient(): can't json.Unmarshal(configBytes, &config) because %s \n", err)
  108. }
  109. if config.GreenhouseThresholdPort == 0 {
  110. config.GreenhouseThresholdPort = 9056
  111. }
  112. var forwardProxyListener *net.TCPListener
  113. if config.TunneledOutboundSOCKS5ListenAddress != "" {
  114. tunneledOutboundSOCKS5ListenAddress, err := net.ResolveTCPAddr("tcp", config.TunneledOutboundSOCKS5ListenAddress)
  115. if err != nil {
  116. log.Fatalf("runClient(): can't net.ResolveTCPAddr(TunneledOutboundSOCKS5ListenAddress) because %s \n", err)
  117. }
  118. forwardProxyListener, err = net.ListenTCP("tcp", tunneledOutboundSOCKS5ListenAddress)
  119. if err != nil {
  120. log.Fatalf("runClient(): can't net.ListenTCP(\"tcp\", TunneledOutboundSOCKS5ListenAddress) because %s \n", err)
  121. }
  122. }
  123. clientServers = []ClientServer{}
  124. makeServer := func(hostPort string) ClientServer {
  125. serverURLString := fmt.Sprintf("https://%s", hostPort)
  126. serverURL, err := url.Parse(serverURLString)
  127. if err != nil {
  128. log.Fatal(fmt.Errorf("failed to parse the ServerAddr (prefixed with https://) '%s' as a url", serverURLString))
  129. }
  130. return ClientServer{
  131. ServerHostPort: hostPort,
  132. ServerUrl: serverURL,
  133. }
  134. }
  135. serverListToLog := ""
  136. if config.GreenhouseDomain != "" {
  137. if config.ServerAddr != "" {
  138. log.Fatal("config contains both GreenhouseDomain and ServerAddr, only use one or the other")
  139. }
  140. if config.Servers != nil && len(config.Servers) > 0 {
  141. log.Fatal("config contains both GreenhouseDomain and Servers, only use one or the other")
  142. }
  143. if config.GreenhouseAPIToken == "" {
  144. log.Fatal("config contains GreenhouseDomain but does not contain GreenhouseAPIToken, use both or niether")
  145. }
  146. greenhouseClient := http.Client{Timeout: time.Second * 10}
  147. greenhouseURL := fmt.Sprintf("https://%s/api/tenant_info", config.GreenhouseDomain)
  148. request, err := http.NewRequest("GET", greenhouseURL, nil)
  149. if err != nil {
  150. log.Fatal("invalid GreenhouseDomain '%s', can't create http request for %s", config.GreenhouseDomain, greenhouseURL)
  151. }
  152. request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", config.GreenhouseAPIToken))
  153. hostPortStringsToLog := []string{}
  154. response, err := greenhouseClient.Do(request)
  155. if err != nil || response.StatusCode != 200 {
  156. if err == nil {
  157. if response.StatusCode == 401 {
  158. log.Printf("bad or expired GreenhouseAPIToken, recieved HTTP 401 Unauthorized from Greenhouse server %s", greenhouseURL)
  159. } else {
  160. log.Printf("recieved HTTP %d from Greenhouse server %s", response.StatusCode, greenhouseURL)
  161. }
  162. } else {
  163. log.Printf("Greenhouse server %s could not be reached: %s", greenhouseURL, err)
  164. }
  165. log.Printf("falling back to DNS lookup on '%s'...\n", greenhouseURL)
  166. // TODO for _, tunnel := range config.DefaultTunnels
  167. ips, err := net.LookupIP(config.GreenhouseDomain)
  168. if err != nil {
  169. log.Fatalf("Failed to lookup GreenhouseDomain '%s'", config.GreenhouseDomain)
  170. }
  171. for _, ip := range ips {
  172. serverHostPort := fmt.Sprintf("%s:%d", ip, config.GreenhouseThresholdPort)
  173. clientServers = append(clientServers, makeServer(serverHostPort))
  174. hostPortStringsToLog = append(hostPortStringsToLog, serverHostPort)
  175. }
  176. } else {
  177. responseBytes, err := ioutil.ReadAll(response.Body)
  178. if err != nil {
  179. log.Fatal("http read error GET '%s'", greenhouseURL)
  180. }
  181. var tenantInfo ThresholdTenantInfo
  182. err = json.Unmarshal(responseBytes, &tenantInfo)
  183. if err != nil {
  184. log.Fatal("http read error GET '%s'", greenhouseURL)
  185. }
  186. for _, serverHostPort := range tenantInfo.ThresholdServers {
  187. ip := strings.Split(serverHostPort, ":")[0]
  188. serverHostPort = fmt.Sprintf("%s:%d", ip, config.GreenhouseThresholdPort)
  189. clientServers = append(clientServers, makeServer(serverHostPort))
  190. hostPortStringsToLog = append(hostPortStringsToLog, serverHostPort)
  191. }
  192. }
  193. serverListToLog = fmt.Sprintf("%s (%s)", config.GreenhouseDomain, strings.Join(hostPortStringsToLog, ", "))
  194. } else if config.Servers != nil && len(config.Servers) > 0 {
  195. if config.ServerAddr != "" {
  196. log.Fatal("config contains both Servers and ServerAddr, only use one or the other")
  197. }
  198. for _, serverHostPort := range config.Servers {
  199. clientServers = append(clientServers, makeServer(serverHostPort))
  200. }
  201. serverListToLog = fmt.Sprintf("[%s]", strings.Join(config.Servers, ", "))
  202. } else {
  203. clientServers = []ClientServer{makeServer(config.ServerAddr)}
  204. serverListToLog = config.ServerAddr
  205. }
  206. if config.DefaultTunnels != nil {
  207. serviceToLocalAddrMap = &config.DefaultTunnels.ServiceToLocalAddrMap
  208. } else {
  209. serviceToLocalAddrMap = &(map[string]string{})
  210. }
  211. configToLog, _ := json.MarshalIndent(config, "", " ")
  212. configToLogString := string(configToLog)
  213. configToLogString = regexp.MustCompile(
  214. `("GreenhouseAPIToken": ")[^"]+(",)`,
  215. ).ReplaceAllString(
  216. configToLogString,
  217. "$1******$2",
  218. )
  219. configToLogString = regexp.MustCompile(
  220. `("(CaCertificate|ClientTlsKey|ClientTlsCertificate)": "[^"]{27})[^"]+([^"]{27}")`,
  221. ).ReplaceAllString(
  222. configToLogString,
  223. "$1 blahblahPEMblahblah $3",
  224. )
  225. log.Printf("theshold client is starting up using config:\n%s\n", configToLogString)
  226. var proxyDialer proxy.Dialer = nil
  227. dialFunction := net.Dial
  228. if config.HostileNetworkEnvironmentEvasionSOCKS5Address != "" {
  229. proxyDialer, err = getProxyDialer(config.HostileNetworkEnvironmentEvasionSOCKS5Address)
  230. if err != nil {
  231. log.Fatalf("can't start because can't getProxyDialer(): %+v", err)
  232. }
  233. dialFunction = func(network, address string) (net.Conn, error) {
  234. var err error
  235. if proxyDialer == nil {
  236. proxyDialer, err = getProxyDialer(config.HostileNetworkEnvironmentEvasionSOCKS5Address)
  237. if err != nil {
  238. return nil, errors.Wrap(err, "dialFunction failed to recreate proxyDialer: ")
  239. }
  240. }
  241. // if it fails, set it to null so it will be re-created // TODO test this and verify it actually works 0__0
  242. conn, err := proxyDialer.Dial(network, address)
  243. if err != nil {
  244. proxyDialer = nil
  245. }
  246. return conn, err
  247. }
  248. }
  249. var cert tls.Certificate
  250. hasFiles := config.ClientTlsCertificateFile != "" && config.ClientTlsKeyFile != ""
  251. hasLiterals := config.ClientTlsCertificate != "" && config.ClientTlsKey != ""
  252. if hasFiles && !hasLiterals {
  253. cert, err = tls.LoadX509KeyPair(config.ClientTlsCertificateFile, config.ClientTlsKeyFile)
  254. if err != nil {
  255. log.Fatalf("can't start because tls.LoadX509KeyPair returned: \n%+v\n", err)
  256. }
  257. } else if !hasFiles && hasLiterals {
  258. cert, err = tls.X509KeyPair([]byte(config.ClientTlsCertificate), []byte(config.ClientTlsKey))
  259. if err != nil {
  260. log.Fatalf("can't start because tls.X509KeyPair returned: \n%+v\n", err)
  261. }
  262. } else {
  263. log.Fatal("one or the other (not both) of ClientTlsCertificateFile+ClientTlsKeyFile or ClientTlsCertificate+ClientTlsKey is required\n")
  264. }
  265. parsedCert, err := x509.ParseCertificate(cert.Certificate[0])
  266. if err != nil {
  267. log.Fatal(err)
  268. }
  269. if parsedCert == nil {
  270. log.Fatalf("parsedCert is nil (%s)", config.ClientTlsCertificateFile)
  271. }
  272. commonName := parsedCert.Subject.CommonName
  273. clientIdDomain := strings.Split(commonName, "@")
  274. if len(clientIdDomain) != 2 {
  275. log.Fatal(fmt.Errorf(
  276. "expected TLS client certificate common name '%s' to match format '<clientId>@<domain>'", commonName,
  277. ))
  278. }
  279. // This is enforced by the server anyways, so no need to enforce it here.
  280. // This allows server URLs to use IP addresses, don't require DNS.
  281. // if clientIdDomain[1] != serverURL.Hostname() {
  282. // log.Fatal(fmt.Errorf(
  283. // "expected TLS client certificate common name domain '%s' to match ServerAddr domain '%s'",
  284. // clientIdDomain[1], serverURL.Hostname(),
  285. // ))
  286. // }
  287. if clientIdDomain[0] != config.ClientId {
  288. log.Fatal(fmt.Errorf(
  289. "expected TLS client certificate common name clientId '%s' to match ClientId '%s'",
  290. clientIdDomain[0], config.ClientId,
  291. ))
  292. }
  293. caCertPool := x509.NewCertPool()
  294. if config.CaCertificateFilesGlob != "" && config.CaCertificate == "" {
  295. certificates, err := filepath.Glob(config.CaCertificateFilesGlob)
  296. if err != nil {
  297. log.Fatal(err)
  298. }
  299. for _, filename := range certificates {
  300. caCert, err := ioutil.ReadFile(filename)
  301. if err != nil {
  302. log.Fatal(err)
  303. }
  304. ok := caCertPool.AppendCertsFromPEM(caCert)
  305. if !ok {
  306. log.Fatalf("Failed to add CA certificate '%s' to cert pool\n", filename)
  307. }
  308. }
  309. } else if config.CaCertificateFilesGlob == "" && config.CaCertificate != "" {
  310. ok := caCertPool.AppendCertsFromPEM([]byte(config.CaCertificate))
  311. if !ok {
  312. log.Fatal("Failed to add config.CaCertificate to cert pool\n")
  313. }
  314. } else {
  315. log.Fatal("one or the other (not both) of CaCertificateFilesGlob or CaCertificate is required\n")
  316. }
  317. tlsClientConfig = &tls.Config{
  318. Certificates: []tls.Certificate{cert},
  319. RootCAs: caCertPool,
  320. }
  321. tlsClientConfig.BuildNameToCertificate()
  322. // wrap whatever dial function we have right now with TLS.
  323. existingDialFunction := dialFunction
  324. dialFunction = func(network, address string) (net.Conn, error) {
  325. conn, err := existingDialFunction(network, address)
  326. if err != nil {
  327. return nil, err
  328. }
  329. addressSplit := strings.Split(address, ":")
  330. // log.Printf("ASD!! LEN: %d\n", len(tlsClientConfig.Certificates))
  331. // if len(tlsClientConfig.Certificates) > 0 {
  332. // for i, cert := range tlsClientConfig.Certificates {
  333. // log.Printf("cert[%d]\n", i)
  334. // if cert.Leaf != nil {
  335. // bytez := pem.EncodeToMemory(&pem.Block{
  336. // Bytes: cert.Leaf.Raw,
  337. // Type: "CERTIFICATE",
  338. // })
  339. // log.Printf("cert[%d].Leaf.Raw:\n%s\n\n", i, bytez)
  340. // }
  341. // if cert.Certificate != nil {
  342. // for j, bytez := range cert.Certificate {
  343. // bytez2 := pem.EncodeToMemory(&pem.Block{
  344. // Bytes: bytez,
  345. // Type: "CERTIFICATE",
  346. // })
  347. // log.Printf("cert[%d][%d].Raw:\n%s\n\n", i, j, bytez2)
  348. // }
  349. // }
  350. // }
  351. // }
  352. tlsConn := tls.Client(conn, &tls.Config{
  353. ServerName: addressSplit[0],
  354. Certificates: tlsClientConfig.Certificates,
  355. RootCAs: tlsClientConfig.RootCAs,
  356. })
  357. err = tlsConn.Handshake()
  358. if err != nil {
  359. log.Printf("tlsConn.Handshake() ERROR %+v\n", err)
  360. return nil, err
  361. }
  362. return tlsConn, nil
  363. }
  364. go runClientAdminApi(config)
  365. fetchLocalAddr := func(service string) (string, error) {
  366. //log.Printf("(*serviceToLocalAddrMap): %+v\n\n", (*serviceToLocalAddrMap))
  367. localAddr, hasLocalAddr := (*serviceToLocalAddrMap)[service]
  368. if !hasLocalAddr {
  369. return "", fmt.Errorf("service '%s' not configured. Set ServiceToLocalAddrMap in client config file or HTTP PUT /liveconfig over the admin api.", service)
  370. }
  371. return localAddr, nil
  372. }
  373. productionProxyFunc := (&tunnel.TCPProxy{
  374. FetchLocalAddr: fetchLocalAddr,
  375. DebugLog: config.DebugLog,
  376. }).Proxy
  377. proxyFunc := func(remote net.Conn, msg *proto.ControlMessage) {
  378. if isTestMode {
  379. handleTestConnection(remote, msg)
  380. } else {
  381. productionProxyFunc(remote, msg)
  382. }
  383. }
  384. maximumConnectionRetrySeconds := 60
  385. if config.MaximumConnectionRetrySeconds != 0 {
  386. maximumConnectionRetrySeconds = config.MaximumConnectionRetrySeconds
  387. }
  388. for i, server := range clientServers {
  389. // make a separate backoff instance for each server.
  390. myBackoff := maximumBackoff{
  391. Maximum: time.Second * time.Duration(maximumConnectionRetrySeconds),
  392. Base: tunnel.NewExponentialBackoff(),
  393. }
  394. clientStateChanges := make(chan *tunnel.ClientStateChange)
  395. tunnelClientConfig := &tunnel.ClientConfig{
  396. DebugLog: config.DebugLog,
  397. Identifier: config.ClientId,
  398. ServerAddr: server.ServerHostPort,
  399. FetchLocalAddr: fetchLocalAddr,
  400. Proxy: proxyFunc,
  401. Dial: dialFunction,
  402. StateChanges: clientStateChanges,
  403. Backoff: &myBackoff,
  404. }
  405. client, err := tunnel.NewClient(tunnelClientConfig)
  406. if err != nil {
  407. log.Fatalf("runClient(): can't create tunnel client for %s because %v \n", server.ServerHostPort, err)
  408. }
  409. go (func() {
  410. for {
  411. stateChange := <-clientStateChanges
  412. log.Printf("%s clientStateChange: %s\n", server.ServerHostPort, stateChange.String())
  413. if config.DefaultTunnels != nil && stateChange.Current == tunnel.ClientConnected {
  414. go (func() {
  415. failed := true
  416. for failed {
  417. err := updateListenersOnServer(config.DefaultTunnels.Listeners)
  418. if err != nil {
  419. log.Printf("DefaultTunnels: failed to updateListenersOnServer(): %+v\nRetrying in 5 seconds...\n", err)
  420. time.Sleep(time.Second * 5)
  421. } else {
  422. failed = false
  423. }
  424. }
  425. })()
  426. }
  427. }
  428. })()
  429. server.Client = client
  430. clientServers[i] = server
  431. go server.Client.Start()
  432. }
  433. log.Printf(
  434. "runClient(): the threshold client should be running now 🏔️⛰️🛤️⛰️🏔️ \n connecting to %s... \n",
  435. serverListToLog,
  436. )
  437. if forwardProxyListener != nil {
  438. log.Printf(
  439. "runClient(): I am listening on %s for SOCKS5 forward proxy \n",
  440. config.TunneledOutboundSOCKS5ListenAddress,
  441. )
  442. for {
  443. conn, err := forwardProxyListener.Accept()
  444. if err != nil {
  445. log.Printf("Can't accept incoming connection: forwardProxyListener.Accept() returned %s\n", err)
  446. }
  447. // TODO better way of determining which one to use for forward proxy.
  448. // log.Printf("clientServers: %+v, clientServers[0]: %+v\n", clientServers, clientServers[0])
  449. err = clientServers[0].Client.HandleForwardProxy(conn)
  450. if err != nil {
  451. log.Printf("Can't accept incoming connection %s -> %s because %s\n", conn.RemoteAddr, conn.LocalAddr, err)
  452. }
  453. }
  454. } else {
  455. waitForever := make(chan bool)
  456. <-waitForever
  457. }
  458. }
  459. func runClientAdminApi(config ClientConfig) {
  460. var listener net.Listener
  461. if config.AdminUnixSocket != "" && config.AdminAPIPort == 0 {
  462. os.Remove(config.AdminUnixSocket)
  463. listenAddress, err := net.ResolveUnixAddr("unix", config.AdminUnixSocket)
  464. if err != nil {
  465. panic(fmt.Sprintf("runClient(): can't start because net.ResolveUnixAddr() returned %+v", err))
  466. }
  467. listener, err = net.ListenUnix("unix", listenAddress)
  468. if err != nil {
  469. panic(fmt.Sprintf("can't start because net.ListenUnix() returned %+v", err))
  470. }
  471. log.Printf("AdminUnixSocket Listening: %v\n\n", config.AdminUnixSocket)
  472. defer listener.Close()
  473. } else if config.AdminUnixSocket == "" && config.AdminAPIPort != 0 {
  474. addrString := fmt.Sprintf("127.0.0.1:%d", config.AdminAPIPort)
  475. addr, err := net.ResolveTCPAddr("tcp", addrString)
  476. if err != nil {
  477. panic(fmt.Sprintf("runClient(): can't start because net.ResolveTCPAddr(%s) returned %+v", addrString, err))
  478. }
  479. tcpListener, err := net.ListenTCP("tcp", addr)
  480. if err != nil {
  481. panic(fmt.Sprintf("runClient(): can't start because net.ListenTCP(%s) returned %+v", addrString, err))
  482. }
  483. caCertPool := x509.NewCertPool()
  484. caCertBytes, err := ioutil.ReadFile(config.AdminAPICACertificateFile)
  485. if err != nil {
  486. panic(fmt.Sprintf("runClient(): can't start because ioutil.ReadFile(%s) returned %+v", config.AdminAPICACertificateFile, err))
  487. }
  488. caCertPool.AppendCertsFromPEM(caCertBytes)
  489. tlsCert, err := tls.LoadX509KeyPair(config.AdminAPITlsCertificateFile, config.AdminAPITlsKeyFile)
  490. if err != nil {
  491. panic(fmt.Sprintf(
  492. "runClient(): can't start because tls.LoadX509KeyPair(%s,%s) returned %+v",
  493. config.AdminAPITlsCertificateFile, config.AdminAPITlsKeyFile, err,
  494. ))
  495. }
  496. tlsConfig := &tls.Config{
  497. Certificates: []tls.Certificate{tlsCert},
  498. ClientCAs: caCertPool,
  499. ClientAuth: tls.RequireAndVerifyClientCert,
  500. }
  501. tlsConfig.BuildNameToCertificate()
  502. listener = tls.NewListener(tcpListener, tlsConfig)
  503. } else if config.AdminUnixSocket != "" && config.AdminAPIPort != 0 {
  504. log.Fatal("One or the other (and not both) of AdminUnixSocket or AdminAPIPort is required")
  505. return
  506. } else if config.AdminUnixSocket == "" && config.AdminAPIPort == 0 {
  507. return
  508. }
  509. server := http.Server{
  510. Handler: clientAdminAPI{},
  511. ReadTimeout: 10 * time.Second,
  512. WriteTimeout: 10 * time.Second,
  513. }
  514. err := server.Serve(listener)
  515. if err != nil {
  516. panic(fmt.Sprintf("Admin API server returned %+v", err))
  517. }
  518. }
  519. // client admin api handler for /liveconfig over unix socket
  520. func (handler clientAdminAPI) ServeHTTP(response http.ResponseWriter, request *http.Request) {
  521. switch path.Clean(request.URL.Path) {
  522. case "/start_test":
  523. isTestMode = true
  524. testTokens = []string{}
  525. if testModeTLSConfig == nil {
  526. certificate, err := GenerateTestX509Cert()
  527. if err != nil {
  528. log.Printf("clientAdminAPI: GenerateTestX509Cert failed: %+v\n\n", err)
  529. http.Error(response, "500 GenerateTestX509Cert failed", http.StatusInternalServerError)
  530. return
  531. }
  532. testModeTLSConfig = &tls.Config{
  533. Certificates: []tls.Certificate{certificate},
  534. }
  535. testModeTLSConfig.BuildNameToCertificate()
  536. }
  537. response.Write([]byte("OK"))
  538. case "/end_test":
  539. isTestMode = false
  540. response.Header().Set("Content-Type", "text/plain")
  541. for _, testToken := range testTokens {
  542. response.Write([]byte(fmt.Sprintln(testToken)))
  543. }
  544. case "/liveconfig":
  545. if request.Method == "PUT" {
  546. requestBytes, err := ioutil.ReadAll(request.Body)
  547. if err != nil {
  548. log.Printf("clientAdminAPI: request read error: %+v\n\n", err)
  549. http.Error(response, "500 request read error", http.StatusInternalServerError)
  550. return
  551. }
  552. var configUpdate LiveConfigUpdate
  553. err = json.Unmarshal(requestBytes, &configUpdate)
  554. if err != nil {
  555. log.Printf("clientAdminAPI: can't parse JSON: %+v\n\n", err)
  556. http.Error(response, "400 bad request: can't parse JSON", http.StatusBadRequest)
  557. return
  558. }
  559. err = updateListenersOnServer(configUpdate.Listeners)
  560. if err != nil {
  561. log.Printf("clientAdminAPI: can't updateListenersOnServer(): %+v\n\n", err)
  562. http.Error(response, "500 internal server error", http.StatusInternalServerError)
  563. return
  564. }
  565. if &configUpdate.ServiceToLocalAddrMap != nil {
  566. serviceToLocalAddrMap = &configUpdate.ServiceToLocalAddrMap
  567. }
  568. response.Header().Add("content-type", "application/json")
  569. response.WriteHeader(http.StatusOK)
  570. response.Write(requestBytes)
  571. } else {
  572. response.Header().Set("Allow", "PUT")
  573. http.Error(response, "405 method not allowed, try PUT", http.StatusMethodNotAllowed)
  574. }
  575. default:
  576. http.Error(response, "404 not found, try PUT /liveconfig or PUT/GET /testmode", http.StatusNotFound)
  577. }
  578. }
  579. func updateListenersOnServer(listeners []ListenerConfig) error {
  580. sendBytes, err := json.Marshal(listeners)
  581. if err != nil {
  582. return errors.Wrap(err, "Listeners json serialization failed")
  583. }
  584. client := &http.Client{
  585. Transport: &http.Transport{
  586. TLSClientConfig: tlsClientConfig,
  587. },
  588. Timeout: 10 * time.Second,
  589. }
  590. // TODO make this concurrent requests, not one by one.
  591. for _, server := range clientServers {
  592. apiURL := fmt.Sprintf("https://%s/tunnels", server.ServerHostPort)
  593. tunnelsRequest, err := http.NewRequest("PUT", apiURL, bytes.NewReader(sendBytes))
  594. if err != nil {
  595. return errors.Wrap(err, "error creating tunnels request")
  596. }
  597. tunnelsRequest.Header.Add("content-type", "application/json")
  598. tunnelsResponse, err := client.Do(tunnelsRequest)
  599. if err != nil {
  600. return errors.Wrap(err, "tunnels request failed")
  601. }
  602. tunnelsResponseBytes, err := ioutil.ReadAll(tunnelsResponse.Body)
  603. if err != nil {
  604. return errors.Wrap(err, "tunnels request response read error")
  605. }
  606. if tunnelsResponse.StatusCode != http.StatusOK {
  607. return errors.Errorf("tunnelsRequest returned HTTP %d: %s", tunnelsResponse.StatusCode, string(tunnelsResponseBytes))
  608. }
  609. }
  610. // cache the listeners locally for use in test mode.
  611. testModeListeners = map[string]ListenerConfig{}
  612. for _, listener := range listeners {
  613. testModeListeners[listener.BackEndService] = listener
  614. }
  615. return nil
  616. }
  617. func handleTestConnection(remote net.Conn, msg *proto.ControlMessage) {
  618. listenerInfo, hasListenerInfo := testModeListeners[msg.Service]
  619. log.Printf("handleTestConnection: %s (%s, %d)", msg.Service, listenerInfo.ListenHostnameGlob, listenerInfo.ListenPort)
  620. if !hasListenerInfo {
  621. remote.Close()
  622. return
  623. }
  624. if listenerInfo.HaProxyProxyProtocol {
  625. remote = proxyprotocol.NewConn(remote, time.Second*5)
  626. }
  627. if listenerInfo.ListenHostnameGlob != "" && listenerInfo.ListenHostnameGlob != "*" {
  628. // TODO make greenhouse-desktop always use HAPROXY proxy protocol with Caddy
  629. // so caddy can get the real remote IP
  630. if listenerInfo.ListenPort == 80 {
  631. requestBuffer := make([]byte, 1024)
  632. bytesRead, err := remote.Read(requestBuffer)
  633. if err != nil {
  634. remote.Close()
  635. } else {
  636. result := regexp.MustCompile("GET /([^ ]+) HTTP/1.1").FindStringSubmatch(string(requestBuffer[:bytesRead]))
  637. if result != nil && len(result) == 2 {
  638. testToken := result[1]
  639. testTokens = append(testTokens, testToken)
  640. remote.Write([]byte(fmt.Sprintf(`HTTP/1.1 200 OK
  641. Content-Type: text/plain
  642. %s`, testToken)))
  643. // TODO add remote.RemoteAddr().String()
  644. remote.Close()
  645. }
  646. }
  647. } else {
  648. remote_tls := tls.Server(remote, testModeTLSConfig)
  649. err := remote_tls.Handshake()
  650. if err != nil {
  651. remote_tls.Close()
  652. return
  653. }
  654. requestBuffer := make([]byte, 1024)
  655. bytesRead, err := remote_tls.Read(requestBuffer)
  656. if err != nil {
  657. remote_tls.Close()
  658. return
  659. }
  660. testToken := string(requestBuffer[:bytesRead])
  661. testTokens = append(testTokens, testToken)
  662. remote_tls.Write([]byte(testToken))
  663. remote_tls.Close()
  664. }
  665. } else {
  666. requestBuffer := make([]byte, 1024)
  667. bytesRead, err := remote.Read(requestBuffer)
  668. if err != nil {
  669. remote.Close()
  670. return
  671. }
  672. testToken := string(requestBuffer[:bytesRead])
  673. testTokens = append(testTokens, testToken)
  674. remote.Write([]byte(testToken))
  675. remote.Close()
  676. }
  677. }
  678. // https://gist.github.com/shivakar/cd52b5594d4912fbeb46
  679. // create a bogus TLS key pair for the test server to use -- the test client will use InsecureSkipVerify
  680. func GenerateTestX509Cert() (tls.Certificate, error) {
  681. now := time.Now()
  682. subjectKeyIDByteSlice := make([]byte, 10)
  683. rand.Read(subjectKeyIDByteSlice)
  684. template := &x509.Certificate{
  685. SerialNumber: big.NewInt(now.Unix()),
  686. Subject: pkix.Name{
  687. CommonName: "threshold-test-certificate.example.com",
  688. Country: []string{"USA"},
  689. Organization: []string{"example.com"},
  690. OrganizationalUnit: []string{"threshold-test-certificate"},
  691. },
  692. NotBefore: now,
  693. NotAfter: now.AddDate(99, 0, 0), // Valid for long time (99 years)
  694. SubjectKeyId: subjectKeyIDByteSlice,
  695. BasicConstraintsValid: true,
  696. IsCA: true,
  697. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  698. KeyUsage: x509.KeyUsageKeyEncipherment |
  699. x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
  700. }
  701. priv, err := rsa.GenerateKey(rand.Reader, 2048)
  702. if err != nil {
  703. return tls.Certificate{}, err
  704. }
  705. cert, err := x509.CreateCertificate(rand.Reader, template, template,
  706. priv.Public(), priv)
  707. if err != nil {
  708. return tls.Certificate{}, err
  709. }
  710. var outCert tls.Certificate
  711. outCert.Certificate = append(outCert.Certificate, cert)
  712. outCert.PrivateKey = priv
  713. return outCert, nil
  714. }
  715. func getProxyDialer(socks5Address string) (proxy.Dialer, error) {
  716. if strings.HasPrefix(strings.ToLower(socks5Address), "gateway") {
  717. splitAddress := strings.Split(socks5Address, ":")
  718. if len(splitAddress) != 2 {
  719. return nil, errors.Errorf("can't getProxyDialer() because HostileNetworkEnvironmentEvasionSOCKS5Address '%s' was invalid. should be of the form host:port")
  720. }
  721. port := splitAddress[1]
  722. defaultGateways, err := getDefaultGatewaysFromRoutingTable()
  723. if err != nil {
  724. return nil, errors.Errorf("can't getProxyDialer() because HostileNetworkEnvironmentEvasionSOCKS5Address was set to '%s' but: \n%+v\n", socks5Address, err)
  725. }
  726. if len(defaultGateways) == 0 {
  727. return nil, errors.Errorf(
  728. "can't getProxyDialer() because HostileNetworkEnvironmentEvasionSOCKS5Address was set to '%s' but no default gateways were found in routing table",
  729. socks5Address,
  730. )
  731. }
  732. failures := make([]string, len(defaultGateways))
  733. for i := 0; i < len(defaultGateways); i++ {
  734. address := fmt.Sprintf("%s:%s", defaultGateways[i], port)
  735. conn, err := net.Dial("tcp", address)
  736. if err == nil {
  737. conn.Close()
  738. return proxy.SOCKS5("tcp", address, nil, proxy.Direct)
  739. }
  740. failures = append(failures, fmt.Sprintf("can't connect to %s", address))
  741. }
  742. // if we got this far it means we tried them all and none of them worked.
  743. return nil, errors.Errorf("can't connect to HostileNetworkEnvironmentEvasionSOCKS5Address '%s': %s", socks5Address, strings.Join(failures, ", "))
  744. } else {
  745. conn, err := net.Dial("tcp", socks5Address)
  746. if err != nil {
  747. return nil, errors.Errorf("can't connect to HostileNetworkEnvironmentEvasionSOCKS5Address '%s': %s", socks5Address, err)
  748. }
  749. conn.Close()
  750. return proxy.SOCKS5("tcp", socks5Address, nil, proxy.Direct)
  751. }
  752. }
  753. // https://stackoverflow.com/questions/40682760/what-syscall-method-could-i-use-to-get-the-default-network-gateway
  754. func getDefaultGatewaysFromRoutingTable() ([]string, error) {
  755. if runtime.GOOS != "linux" {
  756. return nil, errors.Errorf("getDefaultGatewaysFromRoutingTable() does not support %s operating system yet.", runtime.GOOS)
  757. }
  758. toReturn := []string{}
  759. file, err := os.Open("/proc/net/route")
  760. if err != nil {
  761. return nil, err
  762. }
  763. defer file.Close()
  764. scanner := bufio.NewScanner(file)
  765. if scanner.Scan() { // skip the first line (header)
  766. for scanner.Scan() {
  767. tokens := strings.Split(scanner.Text(), "\t")
  768. destinationHex := "0x" + tokens[1]
  769. gatewayHex := "0x" + tokens[2]
  770. destinationInt, err := strconv.ParseInt(destinationHex, 0, 64)
  771. if err != nil {
  772. return nil, err
  773. }
  774. gatewayInt, err := strconv.ParseInt(gatewayHex, 0, 64)
  775. if err != nil {
  776. return nil, err
  777. }
  778. // 0 means 0.0.0.0 -- we are looking for default routes, routes that have universal destination 0.0.0.0
  779. if destinationInt == 0 && gatewayInt != 0 {
  780. gatewayUint32 := uint32(gatewayInt)
  781. // make net.IP address from uint32
  782. ip := make(net.IP, 4)
  783. binary.LittleEndian.PutUint32(ip, gatewayUint32)
  784. toReturn = append(toReturn, ip.String())
  785. //fmt.Printf("%T --> %[1]v\n", ipBytes)
  786. }
  787. }
  788. }
  789. return toReturn, nil
  790. }