origin_service.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. package ingress
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "fmt"
  6. "io"
  7. "net"
  8. "net/http"
  9. "net/url"
  10. "sync"
  11. "time"
  12. "github.com/pkg/errors"
  13. "github.com/rs/zerolog"
  14. "github.com/cloudflare/cloudflared/hello"
  15. "github.com/cloudflare/cloudflared/ipaccess"
  16. "github.com/cloudflare/cloudflared/socks"
  17. "github.com/cloudflare/cloudflared/tlsconfig"
  18. )
  19. // originService is something a tunnel can proxy traffic to.
  20. type originService interface {
  21. String() string
  22. // Start the origin service if it's managed by cloudflared, e.g. proxy servers or Hello World.
  23. // If it's not managed by cloudflared, this is a no-op because the user is responsible for
  24. // starting the origin service.
  25. start(wg *sync.WaitGroup, log *zerolog.Logger, shutdownC <-chan struct{}, errC chan error, cfg OriginRequestConfig) error
  26. }
  27. // unixSocketPath is an OriginService representing a unix socket (which accepts HTTP)
  28. type unixSocketPath struct {
  29. path string
  30. transport *http.Transport
  31. }
  32. func (o *unixSocketPath) String() string {
  33. return "unix socket: " + o.path
  34. }
  35. func (o *unixSocketPath) start(wg *sync.WaitGroup, log *zerolog.Logger, shutdownC <-chan struct{}, errC chan error, cfg OriginRequestConfig) error {
  36. transport, err := newHTTPTransport(o, cfg, log)
  37. if err != nil {
  38. return err
  39. }
  40. o.transport = transport
  41. return nil
  42. }
  43. type httpService struct {
  44. url *url.URL
  45. hostHeader string
  46. transport *http.Transport
  47. }
  48. func (o *httpService) start(wg *sync.WaitGroup, log *zerolog.Logger, shutdownC <-chan struct{}, errC chan error, cfg OriginRequestConfig) error {
  49. transport, err := newHTTPTransport(o, cfg, log)
  50. if err != nil {
  51. return err
  52. }
  53. o.hostHeader = cfg.HTTPHostHeader
  54. o.transport = transport
  55. return nil
  56. }
  57. func (o *httpService) String() string {
  58. return o.url.String()
  59. }
  60. // rawTCPService dials TCP to the destination specified by the client
  61. // It's used by warp routing
  62. type rawTCPService struct {
  63. name string
  64. }
  65. func (o *rawTCPService) String() string {
  66. return o.name
  67. }
  68. func (o *rawTCPService) start(wg *sync.WaitGroup, log *zerolog.Logger, shutdownC <-chan struct{}, errC chan error, cfg OriginRequestConfig) error {
  69. return nil
  70. }
  71. // tcpOverWSService models TCP origins serving eyeballs connecting over websocket, such as
  72. // cloudflared access commands.
  73. type tcpOverWSService struct {
  74. dest string
  75. isBastion bool
  76. streamHandler streamHandlerFunc
  77. }
  78. type socksProxyOverWSService struct {
  79. conn *socksProxyOverWSConnection
  80. }
  81. func newTCPOverWSService(url *url.URL) *tcpOverWSService {
  82. switch url.Scheme {
  83. case "ssh":
  84. addPortIfMissing(url, 22)
  85. case "rdp":
  86. addPortIfMissing(url, 3389)
  87. case "smb":
  88. addPortIfMissing(url, 445)
  89. case "tcp":
  90. addPortIfMissing(url, 7864) // just a random port since there isn't a default in this case
  91. }
  92. return &tcpOverWSService{
  93. dest: url.Host,
  94. }
  95. }
  96. func newBastionService() *tcpOverWSService {
  97. return &tcpOverWSService{
  98. isBastion: true,
  99. }
  100. }
  101. func newSocksProxyOverWSService(accessPolicy *ipaccess.Policy) *socksProxyOverWSService {
  102. proxy := socksProxyOverWSService{
  103. conn: &socksProxyOverWSConnection{
  104. accessPolicy: accessPolicy,
  105. },
  106. }
  107. return &proxy
  108. }
  109. func addPortIfMissing(uri *url.URL, port int) {
  110. if uri.Port() == "" {
  111. uri.Host = fmt.Sprintf("%s:%d", uri.Hostname(), port)
  112. }
  113. }
  114. func (o *tcpOverWSService) String() string {
  115. if o.isBastion {
  116. return ServiceBastion
  117. }
  118. return o.dest
  119. }
  120. func (o *tcpOverWSService) start(wg *sync.WaitGroup, log *zerolog.Logger, shutdownC <-chan struct{}, errC chan error, cfg OriginRequestConfig) error {
  121. if cfg.ProxyType == socksProxy {
  122. o.streamHandler = socks.StreamHandler
  123. } else {
  124. o.streamHandler = DefaultStreamHandler
  125. }
  126. return nil
  127. }
  128. func (o *socksProxyOverWSService) start(wg *sync.WaitGroup, log *zerolog.Logger, shutdownC <-chan struct{}, errC chan error, cfg OriginRequestConfig) error {
  129. return nil
  130. }
  131. func (o *socksProxyOverWSService) String() string {
  132. return ServiceSocksProxy
  133. }
  134. // HelloWorld is an OriginService for the built-in Hello World server.
  135. // Users only use this for testing and experimenting with cloudflared.
  136. type helloWorld struct {
  137. httpService
  138. server net.Listener
  139. }
  140. func (o *helloWorld) String() string {
  141. return "Hello World test origin"
  142. }
  143. // Start starts a HelloWorld server and stores its address in the Service receiver.
  144. func (o *helloWorld) start(
  145. wg *sync.WaitGroup,
  146. log *zerolog.Logger,
  147. shutdownC <-chan struct{},
  148. errC chan error,
  149. cfg OriginRequestConfig,
  150. ) error {
  151. if err := o.httpService.start(wg, log, shutdownC, errC, cfg); err != nil {
  152. return err
  153. }
  154. helloListener, err := hello.CreateTLSListener("127.0.0.1:")
  155. if err != nil {
  156. return errors.Wrap(err, "Cannot start Hello World Server")
  157. }
  158. wg.Add(1)
  159. go func() {
  160. defer wg.Done()
  161. _ = hello.StartHelloWorldServer(log, helloListener, shutdownC)
  162. }()
  163. o.server = helloListener
  164. o.httpService.url = &url.URL{
  165. Scheme: "https",
  166. Host: o.server.Addr().String(),
  167. }
  168. return nil
  169. }
  170. // statusCode is an OriginService that just responds with a given HTTP status.
  171. // Typical use-case is "user wants the catch-all rule to just respond 404".
  172. type statusCode struct {
  173. resp *http.Response
  174. }
  175. func newStatusCode(status int) statusCode {
  176. resp := &http.Response{
  177. StatusCode: status,
  178. Status: fmt.Sprintf("%d %s", status, http.StatusText(status)),
  179. Body: new(NopReadCloser),
  180. }
  181. return statusCode{resp: resp}
  182. }
  183. func (o *statusCode) String() string {
  184. return fmt.Sprintf("HTTP %d", o.resp.StatusCode)
  185. }
  186. func (o *statusCode) start(
  187. wg *sync.WaitGroup,
  188. log *zerolog.Logger,
  189. shutdownC <-chan struct{},
  190. errC chan error,
  191. cfg OriginRequestConfig,
  192. ) error {
  193. return nil
  194. }
  195. type NopReadCloser struct{}
  196. // Read always returns EOF to signal end of input
  197. func (nrc *NopReadCloser) Read(buf []byte) (int, error) {
  198. return 0, io.EOF
  199. }
  200. func (nrc *NopReadCloser) Close() error {
  201. return nil
  202. }
  203. func newHTTPTransport(service originService, cfg OriginRequestConfig, log *zerolog.Logger) (*http.Transport, error) {
  204. originCertPool, err := tlsconfig.LoadOriginCA(cfg.CAPool, log)
  205. if err != nil {
  206. return nil, errors.Wrap(err, "Error loading cert pool")
  207. }
  208. httpTransport := http.Transport{
  209. Proxy: http.ProxyFromEnvironment,
  210. MaxIdleConns: cfg.KeepAliveConnections,
  211. MaxIdleConnsPerHost: cfg.KeepAliveConnections,
  212. IdleConnTimeout: cfg.KeepAliveTimeout,
  213. TLSHandshakeTimeout: cfg.TLSTimeout,
  214. ExpectContinueTimeout: 1 * time.Second,
  215. TLSClientConfig: &tls.Config{RootCAs: originCertPool, InsecureSkipVerify: cfg.NoTLSVerify},
  216. }
  217. if _, isHelloWorld := service.(*helloWorld); !isHelloWorld && cfg.OriginServerName != "" {
  218. httpTransport.TLSClientConfig.ServerName = cfg.OriginServerName
  219. }
  220. dialer := &net.Dialer{
  221. Timeout: cfg.ConnectTimeout,
  222. KeepAlive: cfg.TCPKeepAlive,
  223. }
  224. if cfg.NoHappyEyeballs {
  225. dialer.FallbackDelay = -1 // As of Golang 1.12, a negative delay disables "happy eyeballs"
  226. }
  227. // DialContext depends on which kind of origin is being used.
  228. dialContext := dialer.DialContext
  229. switch service := service.(type) {
  230. // If this origin is a unix socket, enforce network type "unix".
  231. case *unixSocketPath:
  232. httpTransport.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
  233. return dialContext(ctx, "unix", service.path)
  234. }
  235. // Otherwise, use the regular network config.
  236. default:
  237. httpTransport.DialContext = dialContext
  238. }
  239. return &httpTransport, nil
  240. }
  241. // MockOriginHTTPService should only be used by other packages to mock OriginService. Set Transport to configure desired RoundTripper behavior.
  242. type MockOriginHTTPService struct {
  243. Transport http.RoundTripper
  244. }
  245. func (mos MockOriginHTTPService) RoundTrip(req *http.Request) (*http.Response, error) {
  246. return mos.Transport.RoundTrip(req)
  247. }
  248. func (mos MockOriginHTTPService) String() string {
  249. return "MockOriginService"
  250. }
  251. func (mos MockOriginHTTPService) start(wg *sync.WaitGroup, log *zerolog.Logger, shutdownC <-chan struct{}, errC chan error, cfg OriginRequestConfig) error {
  252. return nil
  253. }