domainsniff.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. package domainsniff
  2. /*
  3. Domainsniff
  4. This package contain codes that perform project / domain specific behavior in Zoraxy
  5. If you want Zoraxy to handle a particular domain or open source project in a special way,
  6. you can add the checking logic here.
  7. */
  8. import (
  9. "crypto/tls"
  10. "encoding/json"
  11. "fmt"
  12. "net"
  13. "net/http"
  14. "strings"
  15. "time"
  16. "imuslab.com/zoraxy/mod/utils"
  17. )
  18. // Check if the domain is reachable and return err if not reachable
  19. func DomainReachableWithError(domain string) error {
  20. timeout := 1 * time.Second
  21. conn, err := net.DialTimeout("tcp", domain, timeout)
  22. if err != nil {
  23. return err
  24. }
  25. conn.Close()
  26. return nil
  27. }
  28. // Check if a domain have TLS but it is self-signed or expired
  29. // Return false if sniff error
  30. func DomainIsSelfSigned(domain string) bool {
  31. //Extract the domain from URl in case the user input the full URL
  32. host, port, err := net.SplitHostPort(domain)
  33. if err != nil {
  34. host = domain
  35. } else {
  36. domain = host + ":" + port
  37. }
  38. if !strings.Contains(domain, ":") {
  39. domain = domain + ":443"
  40. }
  41. //Get the certificate
  42. conn, err := net.Dial("tcp", domain)
  43. if err != nil {
  44. return false
  45. }
  46. defer conn.Close()
  47. //Connect with TLS using secure verify
  48. tlsConn := tls.Client(conn, nil)
  49. err = tlsConn.Handshake()
  50. if err == nil {
  51. //This is a valid certificate
  52. fmt.Println()
  53. return false
  54. }
  55. //Connect with TLS using insecure skip verify
  56. config := &tls.Config{
  57. InsecureSkipVerify: true,
  58. }
  59. tlsConn = tls.Client(conn, config)
  60. err = tlsConn.Handshake()
  61. //If the handshake is successful, this is a self-signed certificate
  62. return err == nil
  63. }
  64. // Check if domain reachable
  65. func DomainReachable(domain string) bool {
  66. return DomainReachableWithError(domain) == nil
  67. }
  68. // Check if domain is served by a web server using HTTPS
  69. func DomainUsesTLS(targetURL string) bool {
  70. //Check if the site support https
  71. httpsUrl := fmt.Sprintf("https://%s", targetURL)
  72. httpUrl := fmt.Sprintf("http://%s", targetURL)
  73. client := http.Client{Timeout: 5 * time.Second}
  74. resp, err := client.Head(httpsUrl)
  75. if err == nil && resp.StatusCode == http.StatusOK {
  76. return true
  77. }
  78. resp, err = client.Head(httpUrl)
  79. if err == nil && resp.StatusCode == http.StatusOK {
  80. return false
  81. }
  82. //If the site is not reachable, return false
  83. return false
  84. }
  85. /*
  86. WebSocket Header Sniff
  87. */
  88. // Check if the requst is a special case where
  89. // user defined header shall not be passed over
  90. func RequireWebsocketHeaderCopy(r *http.Request) bool {
  91. //Return false for proxmox
  92. if IsProxmox(r) {
  93. return false
  94. }
  95. //Add more edge cases here
  96. return true
  97. }
  98. /*
  99. Request Handlers
  100. */
  101. //Check if site support TLS
  102. //Pass in ?selfsignchk=true to also check for self-signed certificate
  103. func HandleCheckSiteSupportTLS(w http.ResponseWriter, r *http.Request) {
  104. targetURL, err := utils.PostPara(r, "url")
  105. if err != nil {
  106. utils.SendErrorResponse(w, "invalid url given")
  107. return
  108. }
  109. //If the selfsign flag is set, also chec for self-signed certificate
  110. _, err = utils.PostBool(r, "selfsignchk")
  111. if err == nil {
  112. //Return the https and selfsign status
  113. type result struct {
  114. Protocol string `json:"protocol"`
  115. SelfSign bool `json:"selfsign"`
  116. }
  117. scanResult := result{Protocol: "http", SelfSign: false}
  118. if DomainUsesTLS(targetURL) {
  119. scanResult.Protocol = "https"
  120. if DomainIsSelfSigned(targetURL) {
  121. scanResult.SelfSign = true
  122. }
  123. }
  124. js, _ := json.Marshal(scanResult)
  125. utils.SendJSONResponse(w, string(js))
  126. return
  127. }
  128. if DomainUsesTLS(targetURL) {
  129. js, _ := json.Marshal("https")
  130. utils.SendJSONResponse(w, string(js))
  131. return
  132. } else {
  133. js, _ := json.Marshal("http")
  134. utils.SendJSONResponse(w, string(js))
  135. return
  136. }
  137. }