utils.go 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package dpcore
  2. import (
  3. "net"
  4. "net/url"
  5. "strings"
  6. )
  7. // replaceLocationHost rewrite the backend server's location header to a new URL based on the given proxy rules
  8. // If you have issues with tailing slash, you can try to fix them here (and remember to PR :D )
  9. func replaceLocationHost(urlString string, rrr *ResponseRewriteRuleSet, useTLS bool) (string, error) {
  10. u, err := url.Parse(urlString)
  11. if err != nil {
  12. return "", err
  13. }
  14. //Update the schemetic if the proxying target is http
  15. //but exposed as https to the internet via Zoraxy
  16. if useTLS {
  17. u.Scheme = "https"
  18. } else {
  19. u.Scheme = "http"
  20. }
  21. //Issue #39: Check if it is location target match the proxying domain
  22. //E.g. Proxy config: blog.example.com -> example.com/blog
  23. //Check if it is actually redirecting to example.com instead of a new domain
  24. //like news.example.com.
  25. // The later check bypass apache screw up method of redirection header
  26. // e.g. https://imuslab.com -> http://imuslab.com:443
  27. if rrr.ProxyDomain != u.Host && !strings.Contains(u.Host, rrr.OriginalHost+":") {
  28. //New location domain not matching proxy target domain.
  29. //Do not modify location header
  30. return urlString, nil
  31. }
  32. u.Host = rrr.OriginalHost
  33. if strings.Contains(rrr.ProxyDomain, "/") {
  34. //The proxy domain itself seems contain subpath.
  35. //Trim it off from Location header to prevent URL segment duplicate
  36. //E.g. Proxy config: blog.example.com -> example.com/blog
  37. //Location Header: /blog/post?id=1
  38. //Expected Location Header send to client:
  39. // blog.example.com/post?id=1 instead of blog.example.com/blog/post?id=1
  40. ProxyDomainURL := "http://" + rrr.ProxyDomain
  41. if rrr.UseTLS {
  42. ProxyDomainURL = "https://" + rrr.ProxyDomain
  43. }
  44. ru, err := url.Parse(ProxyDomainURL)
  45. if err == nil {
  46. //Trim off the subpath
  47. u.Path = strings.TrimPrefix(u.Path, ru.Path)
  48. }
  49. }
  50. return u.String(), nil
  51. }
  52. // Debug functions
  53. func ReplaceLocationHost(urlString string, rrr *ResponseRewriteRuleSet, useTLS bool) (string, error) {
  54. return replaceLocationHost(urlString, rrr, useTLS)
  55. }
  56. // isExternalDomainName check and return if the hostname is external domain name (e.g. github.com)
  57. // instead of internal (like 192.168.1.202:8443 (ip address) or domains end with .local or .internal)
  58. func isExternalDomainName(hostname string) bool {
  59. host, _, err := net.SplitHostPort(hostname)
  60. if err != nil {
  61. //hostname doesnt contain port
  62. ip := net.ParseIP(hostname)
  63. if ip != nil {
  64. //IP address, not a domain name
  65. return false
  66. }
  67. } else {
  68. //Hostname contain port, use hostname without port to check if it is ip
  69. ip := net.ParseIP(host)
  70. if ip != nil {
  71. //IP address, not a domain name
  72. return false
  73. }
  74. }
  75. //Check if it is internal DNS assigned domains
  76. internalDNSTLD := []string{".local", ".internal", ".localhost", ".home.arpa"}
  77. for _, tld := range internalDNSTLD {
  78. if strings.HasSuffix(strings.ToLower(hostname), tld) {
  79. return false
  80. }
  81. }
  82. return true
  83. }