real_ip.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. package features
  2. import (
  3. "bufio"
  4. "crypto/tls"
  5. "fmt"
  6. "net"
  7. "net/http"
  8. "github.com/onsi/ginkgo/v2"
  9. pp "github.com/pires/go-proxyproto"
  10. "github.com/fatedier/frp/pkg/transport"
  11. "github.com/fatedier/frp/pkg/util/log"
  12. "github.com/fatedier/frp/test/e2e/framework"
  13. "github.com/fatedier/frp/test/e2e/framework/consts"
  14. "github.com/fatedier/frp/test/e2e/mock/server/httpserver"
  15. "github.com/fatedier/frp/test/e2e/mock/server/streamserver"
  16. "github.com/fatedier/frp/test/e2e/pkg/request"
  17. "github.com/fatedier/frp/test/e2e/pkg/rpc"
  18. )
  19. var _ = ginkgo.Describe("[Feature: Real IP]", func() {
  20. f := framework.NewDefaultFramework()
  21. ginkgo.Describe("HTTP X-forwarded-For", func() {
  22. ginkgo.It("Client Without Header", func() {
  23. vhostHTTPPort := f.AllocPort()
  24. serverConf := consts.DefaultServerConfig + fmt.Sprintf(`
  25. vhostHTTPPort = %d
  26. `, vhostHTTPPort)
  27. localPort := f.AllocPort()
  28. localServer := httpserver.New(
  29. httpserver.WithBindPort(localPort),
  30. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  31. _, _ = w.Write([]byte(req.Header.Get("X-Forwarded-For")))
  32. })),
  33. )
  34. f.RunServer("", localServer)
  35. clientConf := consts.DefaultClientConfig
  36. clientConf += fmt.Sprintf(`
  37. [[proxies]]
  38. name = "test"
  39. type = "http"
  40. localPort = %d
  41. customDomains = ["normal.example.com"]
  42. `, localPort)
  43. f.RunProcesses([]string{serverConf}, []string{clientConf})
  44. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  45. RequestModify(func(r *request.Request) {
  46. r.HTTP().HTTPHost("normal.example.com")
  47. }).
  48. ExpectResp([]byte("127.0.0.1")).
  49. Ensure()
  50. })
  51. ginkgo.It("Client With Header", func() {
  52. vhostHTTPPort := f.AllocPort()
  53. serverConf := consts.DefaultServerConfig + fmt.Sprintf(`
  54. vhostHTTPPort = %d
  55. `, vhostHTTPPort)
  56. localPort := f.AllocPort()
  57. localServer := httpserver.New(
  58. httpserver.WithBindPort(localPort),
  59. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  60. _, _ = w.Write([]byte(req.Header.Get("X-Forwarded-For")))
  61. })),
  62. )
  63. f.RunServer("", localServer)
  64. clientConf := consts.DefaultClientConfig
  65. clientConf += fmt.Sprintf(`
  66. [[proxies]]
  67. name = "test"
  68. type = "http"
  69. localPort = %d
  70. customDomains = ["normal.example.com"]
  71. `, localPort)
  72. f.RunProcesses([]string{serverConf}, []string{clientConf})
  73. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  74. RequestModify(func(r *request.Request) {
  75. r.HTTP().HTTPHost("normal.example.com")
  76. r.HTTP().HTTPHeaders(map[string]string{"x-forwarded-for": "2.2.2.2"})
  77. }).
  78. ExpectResp([]byte("2.2.2.2, 127.0.0.1")).
  79. Ensure()
  80. })
  81. ginkgo.It("http2https plugin", func() {
  82. vhostHTTPPort := f.AllocPort()
  83. serverConf := consts.DefaultServerConfig + fmt.Sprintf(`
  84. vhostHTTPPort = %d
  85. `, vhostHTTPPort)
  86. localPort := f.AllocPort()
  87. clientConf := consts.DefaultClientConfig
  88. clientConf += fmt.Sprintf(`
  89. [[proxies]]
  90. name = "test"
  91. type = "http"
  92. customDomains = ["normal.example.com"]
  93. [proxies.plugin]
  94. type = "http2https"
  95. localAddr = "127.0.0.1:%d"
  96. `, localPort)
  97. f.RunProcesses([]string{serverConf}, []string{clientConf})
  98. tlsConfig, err := transport.NewServerTLSConfig("", "", "")
  99. framework.ExpectNoError(err)
  100. localServer := httpserver.New(
  101. httpserver.WithBindPort(localPort),
  102. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  103. _, _ = w.Write([]byte(req.Header.Get("X-Forwarded-For")))
  104. })),
  105. httpserver.WithTLSConfig(tlsConfig),
  106. )
  107. f.RunServer("", localServer)
  108. framework.NewRequestExpect(f).Port(vhostHTTPPort).
  109. RequestModify(func(r *request.Request) {
  110. r.HTTP().HTTPHost("normal.example.com")
  111. r.HTTP().HTTPHeaders(map[string]string{"x-forwarded-for": "2.2.2.2, 3.3.3.3"})
  112. }).
  113. ExpectResp([]byte("2.2.2.2, 3.3.3.3, 127.0.0.1")).
  114. Ensure()
  115. })
  116. ginkgo.It("https2http plugin", func() {
  117. vhostHTTPSPort := f.AllocPort()
  118. serverConf := consts.DefaultServerConfig + fmt.Sprintf(`
  119. vhostHTTPSPort = %d
  120. `, vhostHTTPSPort)
  121. localPort := f.AllocPort()
  122. clientConf := consts.DefaultClientConfig
  123. clientConf += fmt.Sprintf(`
  124. [[proxies]]
  125. name = "test"
  126. type = "https"
  127. customDomains = ["normal.example.com"]
  128. [proxies.plugin]
  129. type = "https2http"
  130. localAddr = "127.0.0.1:%d"
  131. `, localPort)
  132. f.RunProcesses([]string{serverConf}, []string{clientConf})
  133. localServer := httpserver.New(
  134. httpserver.WithBindPort(localPort),
  135. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  136. _, _ = w.Write([]byte(req.Header.Get("X-Forwarded-For")))
  137. })),
  138. )
  139. f.RunServer("", localServer)
  140. framework.NewRequestExpect(f).Port(vhostHTTPSPort).
  141. RequestModify(func(r *request.Request) {
  142. r.HTTPS().HTTPHost("normal.example.com").
  143. HTTPHeaders(map[string]string{"x-forwarded-for": "2.2.2.2"}).
  144. TLSConfig(&tls.Config{ServerName: "normal.example.com", InsecureSkipVerify: true})
  145. }).
  146. ExpectResp([]byte("2.2.2.2, 127.0.0.1")).
  147. Ensure()
  148. })
  149. })
  150. ginkgo.Describe("Proxy Protocol", func() {
  151. ginkgo.It("TCP", func() {
  152. serverConf := consts.DefaultServerConfig
  153. clientConf := consts.DefaultClientConfig
  154. localPort := f.AllocPort()
  155. localServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(localPort),
  156. streamserver.WithCustomHandler(func(c net.Conn) {
  157. defer c.Close()
  158. rd := bufio.NewReader(c)
  159. ppHeader, err := pp.Read(rd)
  160. if err != nil {
  161. log.Errorf("read proxy protocol error: %v", err)
  162. return
  163. }
  164. for {
  165. if _, err := rpc.ReadBytes(rd); err != nil {
  166. return
  167. }
  168. buf := []byte(ppHeader.SourceAddr.String())
  169. _, _ = rpc.WriteBytes(c, buf)
  170. }
  171. }))
  172. f.RunServer("", localServer)
  173. remotePort := f.AllocPort()
  174. clientConf += fmt.Sprintf(`
  175. [[proxies]]
  176. name = "tcp"
  177. type = "tcp"
  178. localPort = %d
  179. remotePort = %d
  180. transport.proxyProtocolVersion = "v2"
  181. `, localPort, remotePort)
  182. f.RunProcesses([]string{serverConf}, []string{clientConf})
  183. framework.NewRequestExpect(f).Port(remotePort).Ensure(func(resp *request.Response) bool {
  184. log.Tracef("proxy protocol get SourceAddr: %s", string(resp.Content))
  185. addr, err := net.ResolveTCPAddr("tcp", string(resp.Content))
  186. if err != nil {
  187. return false
  188. }
  189. if addr.IP.String() != "127.0.0.1" {
  190. return false
  191. }
  192. return true
  193. })
  194. })
  195. ginkgo.It("UDP", func() {
  196. serverConf := consts.DefaultServerConfig
  197. clientConf := consts.DefaultClientConfig
  198. localPort := f.AllocPort()
  199. localServer := streamserver.New(streamserver.UDP, streamserver.WithBindPort(localPort),
  200. streamserver.WithCustomHandler(func(c net.Conn) {
  201. defer c.Close()
  202. rd := bufio.NewReader(c)
  203. ppHeader, err := pp.Read(rd)
  204. if err != nil {
  205. log.Errorf("read proxy protocol error: %v", err)
  206. return
  207. }
  208. // Read the actual UDP content after proxy protocol header
  209. if _, err := rpc.ReadBytes(rd); err != nil {
  210. return
  211. }
  212. buf := []byte(ppHeader.SourceAddr.String())
  213. _, _ = rpc.WriteBytes(c, buf)
  214. }))
  215. f.RunServer("", localServer)
  216. remotePort := f.AllocPort()
  217. clientConf += fmt.Sprintf(`
  218. [[proxies]]
  219. name = "udp"
  220. type = "udp"
  221. localPort = %d
  222. remotePort = %d
  223. transport.proxyProtocolVersion = "v2"
  224. `, localPort, remotePort)
  225. f.RunProcesses([]string{serverConf}, []string{clientConf})
  226. framework.NewRequestExpect(f).Protocol("udp").Port(remotePort).Ensure(func(resp *request.Response) bool {
  227. log.Tracef("udp proxy protocol get SourceAddr: %s", string(resp.Content))
  228. addr, err := net.ResolveUDPAddr("udp", string(resp.Content))
  229. if err != nil {
  230. return false
  231. }
  232. if addr.IP.String() != "127.0.0.1" {
  233. return false
  234. }
  235. return true
  236. })
  237. })
  238. ginkgo.It("HTTP", func() {
  239. vhostHTTPPort := f.AllocPort()
  240. serverConf := consts.DefaultServerConfig + fmt.Sprintf(`
  241. vhostHTTPPort = %d
  242. `, vhostHTTPPort)
  243. clientConf := consts.DefaultClientConfig
  244. localPort := f.AllocPort()
  245. var srcAddrRecord string
  246. localServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(localPort),
  247. streamserver.WithCustomHandler(func(c net.Conn) {
  248. defer c.Close()
  249. rd := bufio.NewReader(c)
  250. ppHeader, err := pp.Read(rd)
  251. if err != nil {
  252. log.Errorf("read proxy protocol error: %v", err)
  253. return
  254. }
  255. srcAddrRecord = ppHeader.SourceAddr.String()
  256. }))
  257. f.RunServer("", localServer)
  258. clientConf += fmt.Sprintf(`
  259. [[proxies]]
  260. name = "test"
  261. type = "http"
  262. localPort = %d
  263. customDomains = ["normal.example.com"]
  264. transport.proxyProtocolVersion = "v2"
  265. `, localPort)
  266. f.RunProcesses([]string{serverConf}, []string{clientConf})
  267. framework.NewRequestExpect(f).Port(vhostHTTPPort).RequestModify(func(r *request.Request) {
  268. r.HTTP().HTTPHost("normal.example.com")
  269. }).Ensure(framework.ExpectResponseCode(404))
  270. log.Tracef("proxy protocol get SourceAddr: %s", srcAddrRecord)
  271. addr, err := net.ResolveTCPAddr("tcp", srcAddrRecord)
  272. framework.ExpectNoError(err, srcAddrRecord)
  273. framework.ExpectEqualValues("127.0.0.1", addr.IP.String())
  274. })
  275. })
  276. })