peers.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. package drblpeer
  2. import (
  3. "fmt"
  4. "os"
  5. "github.com/asaskevich/govalidator"
  6. //"github.com/bogdanovich/dns_resolver"
  7. "net/http"
  8. "net/url"
  9. "strconv"
  10. "strings"
  11. "github.com/elico/dns_resolver"
  12. )
  13. // DrblClient ---
  14. type DrblClient struct {
  15. Peername string
  16. Path string
  17. Port int
  18. Weight int64
  19. Protocol string
  20. BlResponses []string
  21. Resolver *dns_resolver.DnsResolver
  22. Client *http.Client
  23. }
  24. // DRBLClientUA ---
  25. var DRBLClientUA = "DRBL-Peer Client V1"
  26. func New(peerName, protocol, path string, port int, weight int64, bladdr []string) *DrblClient {
  27. return &DrblClient{peerName,
  28. path,
  29. port,
  30. weight,
  31. protocol,
  32. bladdr,
  33. dns_resolver.NewWithPort([]string{peerName}, strconv.Itoa(port)),
  34. &http.Client{},
  35. }
  36. }
  37. // In case of i/o timeout the resolver should be set to retry 3 times
  38. /*
  39. instance.Resolver.RetryTimes = 0
  40. */
  41. // return: found, allow\deny, admin\nonadmin, error)
  42. func (instance *DrblClient) Check(hostname string, debug bool) (bool, bool, bool, string, error) {
  43. found := false
  44. admin := false
  45. allow := true
  46. key := ""
  47. switch {
  48. case instance.Protocol == "http" || instance.Protocol == "https":
  49. testurl, _ := url.Parse(instance.Protocol + "://" + instance.Peername + ":" + strconv.Itoa(instance.Port) + instance.Path)
  50. testurlVals := url.Values{}
  51. testurlVals.Set("host", hostname)
  52. testurlVals.Set("port", "0")
  53. testurl.RawQuery = testurlVals.Encode()
  54. request, err := http.NewRequest("HEAD", testurl.String(), nil)
  55. //request.SetBasicAuth(*user, *pass)
  56. request.Header.Set("User-Agent", DRBLClientUA)
  57. resp, err := instance.Client.Do(request)
  58. if err != nil {
  59. return found, allow, admin, key, err
  60. }
  61. if resp.Header.Get("X-Admin-Vote") == "YES" {
  62. admin = true
  63. found = true
  64. }
  65. if resp.Header.Get("X-Vote") == "BLOCK" {
  66. found = true
  67. allow = false
  68. }
  69. // For cases which debug is required you can use this key to see the BL VALUE
  70. //resp.Header.Get("X-Rate")
  71. key = resp.Header.Get("X-Rate-Key")
  72. case instance.Protocol == "dns":
  73. if len(hostname) > 1 {
  74. if debug {
  75. fmt.Fprintln(os.Stderr, "trying to match hostname =>", hostname, "to dns hostname =>", hostname)
  76. }
  77. ip, err := instance.Resolver.LookupHost(hostname)
  78. if err != nil {
  79. //SHould not always be on.. dpends on the err For now it's on
  80. switch {
  81. case strings.Contains(err.Error(), "NXDOMAIN"):
  82. //it's fine and possible
  83. default:
  84. fmt.Fprintln(os.Stderr, instance, "Got error on lookup for", hostname, "ERROR:", err)
  85. }
  86. return found, true, admin, key, err
  87. }
  88. // I could have added a loop over loop to verify that each host from the results
  89. // is not from the blacklisting results but it's not that important
  90. if err == nil && len(ip) > 0 {
  91. for _, block := range instance.BlResponses {
  92. if debug {
  93. fmt.Fprintln(os.Stderr, "trying to match resposne =>", ip[0].String(), "to blacklisting response =>", block)
  94. }
  95. if ip[0].String() == block {
  96. found = true
  97. allow = false
  98. break
  99. }
  100. }
  101. }
  102. }
  103. case instance.Protocol == "dnsquad":
  104. if len(hostname) > 1 {
  105. if debug {
  106. fmt.Fprintln(os.Stderr, "trying to match hostname =>", hostname, "to dns hostname =>", hostname)
  107. }
  108. _, err := instance.Resolver.LookupHost(hostname)
  109. if err != nil {
  110. //SHould not always be on.. dpends on the err For now it's on
  111. switch {
  112. case strings.Contains(err.Error(), "NXDOMAIN"):
  113. //it's fine and possible but gets a HIT and needs to be reduced from the score compared to the domain NS rating or another way to analyse it
  114. default:
  115. fmt.Fprintln(os.Stderr, instance, "Got error on lookup for", hostname, "ERROR:", err)
  116. }
  117. return found, true, admin, key, err
  118. }
  119. }
  120. case instance.Protocol == "dnsrbl":
  121. if govalidator.IsIPv4(hostname) {
  122. hostname = ReverseTheDomain(hostname)
  123. }
  124. if len(hostname) > 1 {
  125. // in a RBL compared to BL the request domains is being tested as a prefix to the domain of the RBL
  126. if debug {
  127. fmt.Fprintln(os.Stderr, "trying to match hostname =>", hostname, "to dnsrbl hostname =>", hostname+"."+instance.Peername)
  128. }
  129. ip, err := instance.Resolver.LookupHost(hostname + "." + instance.Peername)
  130. if err != nil {
  131. return found, false, admin, key, err
  132. }
  133. if err == nil && len(ip) > 0 {
  134. for _, block := range instance.BlResponses {
  135. if debug {
  136. fmt.Fprintln(os.Stderr, "tryiing to match resposne =>", ip[0].String(), "to blacklisting response =>", block)
  137. }
  138. if ip[0].String() == block {
  139. found = true
  140. allow = false
  141. break
  142. }
  143. }
  144. }
  145. }
  146. }
  147. return found, allow, admin, key, nil
  148. }
  149. func (instance *DrblClient) HttpCheckUrlWithSrc(requestUrl, src string, debug bool) (bool, bool, bool, string, error) {
  150. found := false
  151. admin := false
  152. allow := true
  153. key := ""
  154. // parse url
  155. _, err := url.Parse(requestUrl)
  156. if err != nil {
  157. if debug {
  158. fmt.Fprintln(os.Stderr, "testing =>", requestUrl, "src =>", src, "error =>", err)
  159. }
  160. return found, allow, admin, key, err
  161. }
  162. switch {
  163. case instance.Protocol == "http" || instance.Protocol == "https":
  164. if debug {
  165. fmt.Fprintln(os.Stderr, "testing =>", requestUrl, "src =>", src, "to blacklisting type =>", instance.Protocol)
  166. }
  167. testurl, _ := url.Parse(instance.Protocol + "://" + instance.Peername + ":" + strconv.Itoa(instance.Port) + instance.Path)
  168. testurlVals := url.Values{}
  169. testurlVals.Set("url", requestUrl)
  170. if govalidator.IsIP(src) {
  171. testurlVals.Set("src", src)
  172. }
  173. testurl.RawQuery = testurlVals.Encode()
  174. request, err := http.NewRequest("HEAD", testurl.String(), nil)
  175. //request.SetBasicAuth(*user, *pass)
  176. testurl.String()
  177. resp, err := instance.Client.Do(request)
  178. if err != nil {
  179. if debug {
  180. fmt.Fprintln(os.Stderr, "testing =>", requestUrl, "testurl =>", testurl.String(), "src =>", src, "error =>", err)
  181. fmt.Fprintln(os.Stderr, "RESPOSE =>", resp)
  182. }
  183. return found, allow, admin, key, err
  184. }
  185. if resp.Header.Get("X-Admin-Vote") == "YES" {
  186. admin = true
  187. found = true
  188. }
  189. if resp.Header.Get("X-Vote") == "BLOCK" {
  190. found = true
  191. allow = false
  192. }
  193. // For cases which debug is required you can use this key to see the BL VALUE
  194. //resp.Header.Get("X-Rate")
  195. key = resp.Header.Get("X-Rate-Key")
  196. }
  197. return found, allow, admin, key, nil
  198. }
  199. // We need to implement a peer object which can be either DNS or HTTP,
  200. // the url of the host can be:
  201. // - host\ip:port
  202. // - type: dns, dnsrbl, http
  203. // Should have an interace\function: checkBl(host)(found, allowed, key)
  204. func ReverseTheDomain(orig string) string {
  205. var c []string = strings.Split(orig, ".")
  206. for i, j := 0, len(c)-1; i < j; i, j = i+1, j-1 {
  207. c[i], c[j] = c[j], c[i]
  208. }
  209. return strings.Join(c, ".")
  210. }