http.go 7.9 KB

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