http.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. package proxy
  2. import (
  3. "bufio"
  4. "bytes"
  5. "crypto/tls"
  6. "github.com/cnlh/nps/bridge"
  7. "github.com/cnlh/nps/lib/common"
  8. "github.com/cnlh/nps/lib/conn"
  9. "github.com/cnlh/nps/lib/file"
  10. "github.com/cnlh/nps/server/connection"
  11. "github.com/cnlh/nps/vender/github.com/astaxie/beego"
  12. "github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
  13. "io"
  14. "net"
  15. "net/http"
  16. "net/http/httputil"
  17. "net/url"
  18. "os"
  19. "path/filepath"
  20. "strconv"
  21. "sync"
  22. )
  23. type httpServer struct {
  24. BaseServer
  25. httpPort int //http端口
  26. httpsPort int //https监听端口
  27. pemPath string
  28. keyPath string
  29. httpServer *http.Server
  30. httpsServer *http.Server
  31. httpsListener net.Listener
  32. }
  33. func NewHttp(bridge *bridge.Bridge, c *file.Tunnel) *httpServer {
  34. httpPort, _ := beego.AppConfig.Int("http_proxy_port")
  35. httpsPort, _ := beego.AppConfig.Int("https_proxy_port")
  36. pemPath := beego.AppConfig.String("pem_path")
  37. keyPath := beego.AppConfig.String("key_path")
  38. return &httpServer{
  39. BaseServer: BaseServer{
  40. task: c,
  41. bridge: bridge,
  42. Mutex: sync.Mutex{},
  43. },
  44. httpPort: httpPort,
  45. httpsPort: httpsPort,
  46. pemPath: pemPath,
  47. keyPath: keyPath,
  48. }
  49. }
  50. func (s *httpServer) processHttps(c net.Conn) {
  51. buf := make([]byte, 2048)
  52. n, err := c.Read(buf)
  53. if err != nil {
  54. return
  55. }
  56. var host *file.Host
  57. file.GetCsvDb().Hosts.Range(func(key, value interface{}) bool {
  58. v := value.(*file.Host)
  59. if v.Scheme != "https" && v.Scheme != "all" {
  60. return true
  61. }
  62. if bytes.Index(buf[:n], []byte(v.Host)) >= 0 && (host == nil || len(host.Host) < len(v.Host)) {
  63. host = v
  64. return false
  65. }
  66. return true
  67. })
  68. if host == nil {
  69. logs.Error("new https connection can't be parsed!", c.RemoteAddr().String())
  70. c.Close()
  71. return
  72. }
  73. var targetAddr string
  74. r := new(http.Request)
  75. r.RequestURI = "/"
  76. r.URL = new(url.URL)
  77. r.URL.Scheme = "https"
  78. r.Host = host.Host
  79. if err := s.CheckFlowAndConnNum(host.Client); err != nil {
  80. logs.Warn("client id %d, host id %d, error %s, when https connection", host.Client.Id, host.Id, err.Error())
  81. c.Close()
  82. return
  83. }
  84. if err = s.auth(r, conn.NewConn(c), host.Client.Cnf.U, host.Client.Cnf.P); err != nil {
  85. logs.Warn("auth error", err, r.RemoteAddr)
  86. return
  87. }
  88. if targetAddr, err = host.GetRandomTarget(); err != nil {
  89. logs.Warn(err.Error())
  90. }
  91. logs.Trace("new https connection,clientId %d,host %s,remote address %s", host.Client.Id, r.Host, c.RemoteAddr().String())
  92. s.DealClient(conn.NewConn(c), host.Client, targetAddr, buf[:n], common.CONN_TCP, nil, host.Flow)
  93. }
  94. func (s *httpServer) Start() error {
  95. var err error
  96. if s.errorContent, err = common.ReadAllFromFile(filepath.Join(common.GetRunPath(), "web", "static", "page", "error.html")); err != nil {
  97. s.errorContent = []byte("easyProxy 404")
  98. }
  99. if s.httpPort > 0 {
  100. s.httpServer = s.NewServer(s.httpPort, "http")
  101. go func() {
  102. l, err := connection.GetHttpListener()
  103. if err != nil {
  104. logs.Error(err)
  105. os.Exit(0)
  106. }
  107. err = s.httpServer.Serve(l)
  108. if err != nil {
  109. logs.Error(err)
  110. os.Exit(0)
  111. }
  112. }()
  113. }
  114. if s.httpsPort > 0 {
  115. s.httpsServer = s.NewServer(s.httpsPort, "https")
  116. go func() {
  117. s.httpsListener, err = connection.GetHttpsListener()
  118. if err != nil {
  119. logs.Error(err)
  120. os.Exit(0)
  121. }
  122. if b, err := beego.AppConfig.Bool("https_just_proxy"); err == nil && b {
  123. for {
  124. c, err := s.httpsListener.Accept()
  125. if err != nil {
  126. logs.Error(err)
  127. break
  128. }
  129. go s.processHttps(c)
  130. }
  131. } else {
  132. if !common.FileExists(s.pemPath) {
  133. logs.Error("ssl certFile %s exist", s.keyPath)
  134. os.Exit(0)
  135. }
  136. if !common.FileExists(s.keyPath) {
  137. logs.Error("ssl keyFile %s exist", s.keyPath)
  138. os.Exit(0)
  139. }
  140. err = s.httpsServer.ServeTLS(s.httpsListener, s.pemPath, s.keyPath)
  141. if err != nil {
  142. logs.Error(err)
  143. os.Exit(0)
  144. }
  145. }
  146. }()
  147. }
  148. return nil
  149. }
  150. func (s *httpServer) Close() error {
  151. if s.httpsListener != nil {
  152. s.httpsListener.Close()
  153. }
  154. if s.httpsServer != nil {
  155. s.httpsServer.Close()
  156. }
  157. if s.httpServer != nil {
  158. s.httpServer.Close()
  159. }
  160. return nil
  161. }
  162. func (s *httpServer) handleTunneling(w http.ResponseWriter, r *http.Request) {
  163. hijacker, ok := w.(http.Hijacker)
  164. if !ok {
  165. http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
  166. return
  167. }
  168. c, _, err := hijacker.Hijack()
  169. if err != nil {
  170. http.Error(w, err.Error(), http.StatusServiceUnavailable)
  171. }
  172. s.process(conn.NewConn(c), r)
  173. }
  174. func (s *httpServer) process(c *conn.Conn, r *http.Request) {
  175. //多客户端域名代理
  176. var (
  177. isConn = true
  178. host *file.Host
  179. target net.Conn
  180. lastHost *file.Host
  181. err error
  182. connClient io.ReadWriteCloser
  183. scheme = r.URL.Scheme
  184. lk *conn.Link
  185. targetAddr string
  186. wg sync.WaitGroup
  187. )
  188. if host, err = file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil {
  189. logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI)
  190. goto end
  191. }
  192. if err := s.CheckFlowAndConnNum(host.Client); err != nil {
  193. logs.Warn("client id %d, host id %d, error %s, when https connection", host.Client.Id, host.Id, err.Error())
  194. c.Close()
  195. return
  196. }
  197. logs.Trace("new %s connection,clientId %d,host %s,url %s,remote address %s", r.URL.Scheme, host.Client.Id, r.Host, r.URL, r.RemoteAddr)
  198. lastHost = host
  199. for {
  200. start:
  201. if isConn {
  202. if err = s.auth(r, c, host.Client.Cnf.U, host.Client.Cnf.P); err != nil {
  203. logs.Warn("auth error", err, r.RemoteAddr)
  204. break
  205. }
  206. if targetAddr, err = host.GetRandomTarget(); err != nil {
  207. logs.Warn(err.Error())
  208. break
  209. }
  210. lk = conn.NewLink(common.CONN_TCP, targetAddr, host.Client.Cnf.Crypt, host.Client.Cnf.Compress, r.RemoteAddr)
  211. if target, err = s.bridge.SendLinkInfo(host.Client.Id, lk, c.Conn.RemoteAddr().String(), nil); err != nil {
  212. logs.Notice("connect to target %s error %s", lk.Host, err)
  213. break
  214. }
  215. connClient = conn.GetConn(target, lk.Crypt, lk.Compress, host.Client.Rate, true)
  216. isConn = false
  217. go func() {
  218. wg.Add(1)
  219. w, _ := common.CopyBuffer(c, connClient)
  220. host.Flow.Add(0, w)
  221. c.Close()
  222. target.Close()
  223. wg.Done()
  224. }()
  225. } else {
  226. r, err = http.ReadRequest(bufio.NewReader(c))
  227. if err != nil {
  228. break
  229. }
  230. r.URL.Scheme = scheme
  231. //What happened ,Why one character less???
  232. if r.Method == "ET" {
  233. r.Method = "GET"
  234. }
  235. if r.Method == "OST" {
  236. r.Method = "POST"
  237. }
  238. logs.Trace("new %s connection,clientId %d,host %s,url %s,remote address %s", r.URL.Scheme, host.Client.Id, r.Host, r.URL, r.RemoteAddr)
  239. if hostTmp, err := file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil {
  240. logs.Notice("the url %s %s %s can't be parsed!", r.URL.Scheme, r.Host, r.RequestURI)
  241. break
  242. } else if host != lastHost {
  243. host.Client.AddConn()
  244. if !hostTmp.Client.GetConn() {
  245. break
  246. }
  247. host = hostTmp
  248. lastHost = host
  249. isConn = true
  250. goto start
  251. }
  252. }
  253. //根据设定,修改header和host
  254. common.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String())
  255. b, err := httputil.DumpRequest(r, false)
  256. if err != nil {
  257. break
  258. }
  259. logs.Trace("%s request, method %s, host %s, url %s, remote address %s, target %s", r.URL.Scheme, r.Method, r.Host, r.RequestURI, r.RemoteAddr, lk.Host)
  260. //write
  261. connClient.Write(b)
  262. if bodyLen, err := common.CopyBuffer(connClient, r.Body); err != nil {
  263. break
  264. } else {
  265. host.Flow.Add(int64(len(b))+bodyLen, 0)
  266. }
  267. }
  268. end:
  269. if isConn {
  270. s.writeConnFail(c.Conn)
  271. }
  272. c.Close()
  273. if target != nil {
  274. target.Close()
  275. }
  276. wg.Wait()
  277. if host != nil {
  278. host.Client.AddConn()
  279. }
  280. }
  281. func (s *httpServer) NewServer(port int, scheme string) *http.Server {
  282. return &http.Server{
  283. Addr: ":" + strconv.Itoa(port),
  284. Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  285. r.URL.Scheme = scheme
  286. s.handleTunneling(w, r)
  287. }),
  288. // Disable HTTP/2.
  289. TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
  290. }
  291. }