1
0

https.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package proxy
  2. import (
  3. "net"
  4. "net/http"
  5. "net/url"
  6. "sync"
  7. "ehang.io/nps/lib/cache"
  8. "ehang.io/nps/lib/common"
  9. "ehang.io/nps/lib/conn"
  10. "ehang.io/nps/lib/crypt"
  11. "ehang.io/nps/lib/file"
  12. "github.com/astaxie/beego"
  13. "github.com/astaxie/beego/logs"
  14. "github.com/pkg/errors"
  15. )
  16. type HttpsServer struct {
  17. httpServer
  18. listener net.Listener
  19. httpsListenerMap sync.Map
  20. }
  21. func NewHttpsServer(l net.Listener, bridge NetBridge, useCache bool, cacheLen int) *HttpsServer {
  22. https := &HttpsServer{listener: l}
  23. https.bridge = bridge
  24. https.useCache = useCache
  25. if useCache {
  26. https.cache = cache.New(cacheLen)
  27. }
  28. return https
  29. }
  30. //start https server
  31. func (https *HttpsServer) Start() error {
  32. if b, err := beego.AppConfig.Bool("https_just_proxy"); err == nil && b {
  33. conn.Accept(https.listener, func(c net.Conn) {
  34. https.handleHttps(c)
  35. })
  36. } else {
  37. //start the default listener
  38. certFile := beego.AppConfig.String("https_default_cert_file")
  39. keyFile := beego.AppConfig.String("https_default_key_file")
  40. if common.FileExists(certFile) && common.FileExists(keyFile) {
  41. l := NewHttpsListener(https.listener)
  42. https.NewHttps(l, certFile, keyFile)
  43. https.httpsListenerMap.Store("default", l)
  44. }
  45. conn.Accept(https.listener, func(c net.Conn) {
  46. serverName, rb := GetServerNameFromClientHello(c)
  47. //if the clientHello does not contains sni ,use the default ssl certificate
  48. if serverName == "" {
  49. serverName = "default"
  50. }
  51. var l *HttpsListener
  52. if v, ok := https.httpsListenerMap.Load(serverName); ok {
  53. l = v.(*HttpsListener)
  54. } else {
  55. r := buildHttpsRequest(serverName)
  56. if host, err := file.GetDb().GetInfoByHost(serverName, r); err != nil {
  57. c.Close()
  58. logs.Notice("the url %s can't be parsed!,remote addr %s", serverName, c.RemoteAddr().String())
  59. return
  60. } else {
  61. if !common.FileExists(host.CertFilePath) || !common.FileExists(host.KeyFilePath) {
  62. //if the host cert file or key file is not set ,use the default file
  63. if v, ok := https.httpsListenerMap.Load("default"); ok {
  64. l = v.(*HttpsListener)
  65. } else {
  66. c.Close()
  67. logs.Error("the key %s cert %s file is not exist", host.KeyFilePath, host.CertFilePath)
  68. return
  69. }
  70. } else {
  71. l = NewHttpsListener(https.listener)
  72. https.NewHttps(l, host.CertFilePath, host.KeyFilePath)
  73. https.httpsListenerMap.Store(serverName, l)
  74. }
  75. }
  76. }
  77. acceptConn := conn.NewConn(c)
  78. acceptConn.Rb = rb
  79. l.acceptConn <- acceptConn
  80. })
  81. }
  82. return nil
  83. }
  84. // close
  85. func (https *HttpsServer) Close() error {
  86. return https.listener.Close()
  87. }
  88. // new https server by cert and key file
  89. func (https *HttpsServer) NewHttps(l net.Listener, certFile string, keyFile string) {
  90. go func() {
  91. logs.Error(https.NewServer(0, "https").ServeTLS(l, certFile, keyFile))
  92. }()
  93. }
  94. //handle the https which is just proxy to other client
  95. func (https *HttpsServer) handleHttps(c net.Conn) {
  96. hostName, rb := GetServerNameFromClientHello(c)
  97. var targetAddr string
  98. r := buildHttpsRequest(hostName)
  99. var host *file.Host
  100. var err error
  101. if host, err = file.GetDb().GetInfoByHost(hostName, r); err != nil {
  102. c.Close()
  103. logs.Notice("the url %s can't be parsed!", hostName)
  104. return
  105. }
  106. if err := https.CheckFlowAndConnNum(host.Client); err != nil {
  107. logs.Warn("client id %d, host id %d, error %s, when https connection", host.Client.Id, host.Id, err.Error())
  108. c.Close()
  109. return
  110. }
  111. defer host.Client.AddConn()
  112. if err = https.auth(r, conn.NewConn(c), host.Client.Cnf.U, host.Client.Cnf.P); err != nil {
  113. logs.Warn("auth error", err, r.RemoteAddr)
  114. return
  115. }
  116. if targetAddr, err = host.Target.GetRandomTarget(); err != nil {
  117. logs.Warn(err.Error())
  118. }
  119. logs.Trace("new https connection,clientId %d,host %s,remote address %s", host.Client.Id, r.Host, c.RemoteAddr().String())
  120. https.DealClient(conn.NewConn(c), host.Client, targetAddr, rb, common.CONN_TCP, nil, host.Flow, host.Target.LocalProxy)
  121. }
  122. type HttpsListener struct {
  123. acceptConn chan *conn.Conn
  124. parentListener net.Listener
  125. }
  126. // https listener
  127. func NewHttpsListener(l net.Listener) *HttpsListener {
  128. return &HttpsListener{parentListener: l, acceptConn: make(chan *conn.Conn)}
  129. }
  130. // accept
  131. func (httpsListener *HttpsListener) Accept() (net.Conn, error) {
  132. httpsConn := <-httpsListener.acceptConn
  133. if httpsConn == nil {
  134. return nil, errors.New("get connection error")
  135. }
  136. return httpsConn, nil
  137. }
  138. // close
  139. func (httpsListener *HttpsListener) Close() error {
  140. return nil
  141. }
  142. // addr
  143. func (httpsListener *HttpsListener) Addr() net.Addr {
  144. return httpsListener.parentListener.Addr()
  145. }
  146. // get server name from connection by read client hello bytes
  147. func GetServerNameFromClientHello(c net.Conn) (string, []byte) {
  148. buf := make([]byte, 4096)
  149. data := make([]byte, 4096)
  150. n, err := c.Read(buf)
  151. if err != nil {
  152. return "", nil
  153. }
  154. if n < 42 {
  155. return "", nil
  156. }
  157. copy(data, buf[:n])
  158. clientHello := new(crypt.ClientHelloMsg)
  159. clientHello.Unmarshal(data[5:n])
  160. return clientHello.GetServerName(), buf[:n]
  161. }
  162. // build https request
  163. func buildHttpsRequest(hostName string) *http.Request {
  164. r := new(http.Request)
  165. r.RequestURI = "/"
  166. r.URL = new(url.URL)
  167. r.URL.Scheme = "https"
  168. r.Host = hostName
  169. return r
  170. }