github.com/status-im/status-go@v1.1.0/server/pairing/preflight/preflight.go (about) 1 package preflight 2 3 import ( 4 "crypto/tls" 5 "crypto/x509" 6 "fmt" 7 "net" 8 "net/http" 9 "net/url" 10 "strconv" 11 "sync" 12 "time" 13 14 "github.com/ethereum/go-ethereum/log" 15 16 "github.com/status-im/status-go/server/pairing" 17 "github.com/status-im/status-go/timesource" 18 19 "go.uber.org/zap" 20 21 "github.com/status-im/status-go/logutils" 22 "github.com/status-im/status-go/protocol/common" 23 "github.com/status-im/status-go/server" 24 ) 25 26 const ( 27 outboundCheck = "/outbound_check" 28 headerPing = "ping" 29 headerPong = "pong" 30 ) 31 32 func preflightHandler(w http.ResponseWriter, r *http.Request) { 33 ping := r.Header.Get(headerPing) 34 if ping == "" { 35 http.Error(w, "no value in 'ping' header", http.StatusBadRequest) 36 } 37 38 w.Header().Set(headerPong, ping) 39 } 40 41 func makeCert(address net.IP) (*tls.Certificate, []byte, error) { 42 now := timesource.GetCurrentTime() 43 log.Debug("makeCert", "system time", time.Now().String(), "timesource time", now.String()) 44 notBefore := now.Add(-pairing.CertificateMaxClockDrift) 45 notAfter := now.Add(pairing.CertificateMaxClockDrift) 46 return server.GenerateTLSCert(notBefore, notAfter, []net.IP{address}, []string{}) 47 } 48 49 func makeAndStartServer(cert *tls.Certificate, address net.IP) (string, func() error, error) { 50 wg := sync.WaitGroup{} 51 wg.Add(1) 52 waitForPortSet := func(int) { 53 wg.Done() 54 } 55 56 s := server.NewServer( 57 cert, 58 address.String(), 59 waitForPortSet, 60 logutils.ZapLogger().Named("Preflight Server"), 61 ) 62 63 s.SetHandlers(server.HandlerPatternMap{outboundCheck: preflightHandler}) 64 err := s.Start() 65 if err != nil { 66 return "", nil, err 67 } 68 69 wg.Wait() 70 return s.GetHostname() + ":" + strconv.Itoa(s.GetPort()), s.Stop, nil 71 } 72 73 func makeClient(certPem []byte) (*http.Client, error) { 74 rootCAs, err := x509.SystemCertPool() 75 if err != nil { 76 return nil, err 77 } 78 if ok := rootCAs.AppendCertsFromPEM(certPem); !ok { 79 return nil, fmt.Errorf("failed to append certPem to rootCAs") 80 } 81 82 tr := &http.Transport{ 83 TLSClientConfig: &tls.Config{ 84 MinVersion: tls.VersionTLS12, 85 InsecureSkipVerify: false, // MUST BE FALSE 86 RootCAs: rootCAs, 87 Time: timesource.GetCurrentTime, 88 }, 89 } 90 91 return &http.Client{Transport: tr}, nil 92 } 93 94 func makeOutboundCheck(c *http.Client, host string) error { 95 u := url.URL{ 96 Scheme: "https", 97 Host: host, 98 Path: outboundCheck, 99 } 100 101 req, err := http.NewRequest("GET", u.String(), nil) 102 if err != nil { 103 return err 104 } 105 106 ping, err := common.RandomAlphanumericString(64) 107 if err != nil { 108 return err 109 } 110 111 req.Header.Set(headerPing, ping) 112 113 resp, err := c.Do(req) 114 if err != nil { 115 return err 116 } 117 118 if resp.StatusCode != http.StatusOK { 119 return fmt.Errorf("response status not ok, received '%d' : '%s'", resp.StatusCode, resp.Status) 120 } 121 122 pong := resp.Header.Get(headerPong) 123 if pong != ping { 124 return fmt.Errorf("ping should match pong: ping '%s', pong '%s'", ping, pong) 125 } 126 return nil 127 } 128 129 func CheckOutbound() error { 130 // cert stuff 131 outboundIP, err := server.GetOutboundIP() 132 if err != nil { 133 return err 134 } 135 136 cert, certPem, err := makeCert(outboundIP) 137 if err != nil { 138 return err 139 } 140 141 // server stuff 142 host, stop, err := makeAndStartServer(cert, outboundIP) 143 if err != nil { 144 return err 145 } 146 defer func() { 147 err := stop() 148 if err != nil { 149 logutils.ZapLogger().Error("error while stopping preflight serve", zap.Error(err)) 150 } 151 }() 152 153 // Client stuff 154 c, err := makeClient(certPem) 155 if err != nil { 156 return err 157 } 158 159 return makeOutboundCheck(c, host) 160 }