peersarray.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. package drblpeer
  2. import (
  3. // "../watcher"
  4. "fmt"
  5. "sync/atomic"
  6. "github.com/asaskevich/govalidator"
  7. //"github.com/bogdanovich/dns_resolver"
  8. "github.com/elico/dns_resolver"
  9. "gopkg.in/yaml.v2"
  10. "io/ioutil"
  11. "net/http"
  12. "regexp"
  13. "strconv"
  14. "strings"
  15. //"time"
  16. )
  17. var spacesAndTabs = regexp.MustCompile(`[\s\t]+`)
  18. type DrblPeers struct {
  19. Peers []DrblClient
  20. HitWeight int64
  21. Timeout int
  22. Debug bool
  23. /*
  24. ReverseOrderDomLookup bool
  25. ReverseOrderIpv4Lookup bool
  26. Ipv6Lookup bool
  27. */
  28. }
  29. type YamlPeerDrblName struct {
  30. Peer string `name`
  31. Type string `type`
  32. Host string `host`
  33. Port int `port`
  34. Weight int `weight`
  35. Path string `path`
  36. Expected []string `expected`
  37. }
  38. type YamlDrblPeers struct {
  39. Clients []YamlPeerDrblName `peers`
  40. }
  41. func NewPeerListFromFile(filename string, hitWeight int64, timeout int, debug bool) (*DrblPeers, error) {
  42. //peerName, protocol, path string, port int, weight int64, bladdr []string ) *DrblClient
  43. // mainDrbPeer := drblpeer.New("199.85.126.20", "dns", "", 53, int64(128), []string{"156.154.175.216", "156.154.176.216"})
  44. // drblPeers := *drblpeer.DrblPeers{[]DrblClient{}, int64(128), 30, true}
  45. //var drblPeers drblpeer.DrblPeers{[]drblpeer.DrblClient{*mainDrbPeer}, int64(128), 30, true}
  46. // Read whole file
  47. // Split lines
  48. // Walk on the lines
  49. // If the line syntax is fine add it else move on
  50. // Swap the drbl peers list
  51. content, err := ioutil.ReadFile(filename)
  52. if err != nil {
  53. //fmt.Println(err)
  54. return &DrblPeers{}, err
  55. }
  56. peersClient := make([]DrblClient, 0)
  57. newlist := &DrblPeers{peersClient, hitWeight, timeout, debug}
  58. lines := strings.Split(string(content), "\n")
  59. for _, peerline := range lines {
  60. if len(peerline) > 10 {
  61. peer, err := NewPeerFromLine(peerline)
  62. if err != nil {
  63. if debug {
  64. fmt.Println(err)
  65. }
  66. continue
  67. } else {
  68. newlist.Peers = append(newlist.Peers, *peer)
  69. }
  70. }
  71. }
  72. if newlist.Debug {
  73. fmt.Println("Peers number", int64(len(newlist.Peers)))
  74. }
  75. return newlist, nil
  76. }
  77. func NewPeerListFromYamlFile(filename string, hitWeight int64, timeout int, debug bool) (*DrblPeers, error) {
  78. //peerName, protocol, path string, port int, weight int64, bladdr []string ) *DrblClient
  79. // mainDrbPeer := drblpeer.New("199.85.126.20", "dns", "", 53, int64(128), []string{"156.154.175.216", "156.154.176.216"})
  80. // drblPeers := *drblpeer.DrblPeers{[]DrblClient{}, int64(128), 30, true}
  81. //var drblPeers drblpeer.DrblPeers{[]drblpeer.DrblClient{*mainDrbPeer}, int64(128), 30, true}
  82. // Read whole file
  83. // Split lines
  84. // Walk on the lines
  85. // If the line syntax is fine add it else move on
  86. // Swap the drbl peers list
  87. var peers YamlDrblPeers
  88. content, err := ioutil.ReadFile(filename)
  89. if err != nil {
  90. return &DrblPeers{}, err
  91. }
  92. err = yaml.Unmarshal(content, &peers)
  93. if err != nil {
  94. return &DrblPeers{}, err
  95. }
  96. if debug {
  97. fmt.Println(string(content))
  98. fmt.Println(peers.Clients)
  99. }
  100. peersClient := make([]DrblClient, 0)
  101. newlist := &DrblPeers{peersClient, hitWeight, timeout, debug}
  102. for _, client := range peers.Clients {
  103. peer, err := NewPeerFromYaml(client)
  104. if err != nil {
  105. if debug {
  106. fmt.Println(err)
  107. }
  108. continue
  109. } else {
  110. newlist.Peers = append(newlist.Peers, *peer)
  111. }
  112. if newlist.Debug {
  113. fmt.Println("Peers number", int64(len(newlist.Peers)))
  114. }
  115. }
  116. return newlist, nil
  117. }
  118. func NewPeerFromYaml(peer YamlPeerDrblName) (*DrblClient, error) {
  119. port := uint(peer.Port) //port
  120. weight := uint(peer.Weight) //weight
  121. /*
  122. switch {
  123. case govalidator.IsIP(lparts[1]):
  124. ;;
  125. case govalidator.IsDNSName(lparts[1]):
  126. if lparts[0] != "http" {
  127. addr, err := net.LookupHost(lparts[1])
  128. if err != nil {
  129. return &DrblClient{}, fmt.Errorf("%s hostname cannot be resolved", lparts[1])
  130. }
  131. // Choosing a static IP address
  132. lparts[1] = addr[0]
  133. }
  134. default:
  135. return &DrblClient{}, fmt.Errorf("%s is not a valid hostname or ip address", lparts[1])
  136. }
  137. */
  138. if !govalidator.IsHost(peer.Host) {
  139. return &DrblClient{}, fmt.Errorf("%s is not a valid hostname or ip address", peer.Host)
  140. }
  141. // http\dns\dnsrbl ip\domain /path/vote/ port weigth bl ip's
  142. // 0 1 2 3 4 5
  143. switch {
  144. case peer.Type == "http" || peer.Type == "https":
  145. return &DrblClient{peer.Host,
  146. peer.Path,
  147. int(port),
  148. int64(weight),
  149. peer.Type,
  150. []string{},
  151. dns_resolver.New([]string{peer.Host}),
  152. &http.Client{},
  153. }, nil
  154. case peer.Type == "dns":
  155. blIpAddr := make([]string, 1)
  156. for _, addr := range peer.Expected {
  157. if govalidator.IsIPv4(addr) {
  158. blIpAddr = append(blIpAddr, addr)
  159. }
  160. }
  161. return &DrblClient{peer.Host,
  162. peer.Path,
  163. int(port),
  164. int64(weight),
  165. peer.Type,
  166. blIpAddr,
  167. dns_resolver.NewWithPort([]string{peer.Host}, strconv.Itoa(int(port))),
  168. &http.Client{},
  169. }, nil
  170. case peer.Type == "dnsrbl":
  171. blIpAddr := make([]string, 1)
  172. for _, addr := range peer.Expected {
  173. if govalidator.IsIPv4(addr) {
  174. blIpAddr = append(blIpAddr, addr)
  175. }
  176. }
  177. return &DrblClient{peer.Host,
  178. peer.Path,
  179. int(port),
  180. int64(weight),
  181. peer.Type,
  182. blIpAddr,
  183. dns_resolver.NewWithPort([]string{peer.Host}, strconv.Itoa(int(port))),
  184. &http.Client{},
  185. }, nil
  186. }
  187. return &DrblClient{}, fmt.Errorf("drblpeer: malformed peerYaml %s", peer)
  188. }
  189. func NewPeerFromLine(peerline string) (*DrblClient, error) {
  190. // Cleanup
  191. peerline = spacesAndTabs.ReplaceAllString(peerline, " ")
  192. /*
  193. if strings.Contains(peerline,"\t") {
  194. return &DrblClient{}, fmt.Errorf("tabs are not allowed in peerline +> %s", peerline)
  195. }
  196. */
  197. if len(peerline) > 10 {
  198. lparts := strings.Split(peerline, " ")
  199. if len(lparts) > 5 {
  200. port, err := strconv.ParseUint(lparts[3], 10, 64) //port
  201. if err != nil {
  202. return &DrblClient{}, err
  203. }
  204. weight, err := strconv.ParseUint(lparts[4], 10, 64) //weight
  205. if err != nil {
  206. return &DrblClient{}, err
  207. }
  208. /*
  209. switch {
  210. case govalidator.IsIP(lparts[1]):
  211. ;;
  212. case govalidator.IsDNSName(lparts[1]):
  213. if lparts[0] != "http" {
  214. addr, err := net.LookupHost(lparts[1])
  215. if err != nil {
  216. return &DrblClient{}, fmt.Errorf("%s hostname cannot be resolved", lparts[1])
  217. }
  218. // Choosing a static IP address
  219. lparts[1] = addr[0]
  220. }
  221. default:
  222. return &DrblClient{}, fmt.Errorf("%s is not a valid hostname or ip address", lparts[1])
  223. }
  224. */
  225. if !govalidator.IsHost(lparts[1]) {
  226. return &DrblClient{}, fmt.Errorf("%s is not a valid hostname or ip address", lparts[1])
  227. }
  228. // http\dns\dnsrbl ip\domain /path/vote/ port weigth bl ip's
  229. // 0 1 2 3 4 5
  230. switch {
  231. case lparts[0] == "http" || lparts[0] == "https":
  232. return &DrblClient{lparts[1],
  233. lparts[2],
  234. int(port),
  235. int64(weight),
  236. lparts[0],
  237. []string{},
  238. dns_resolver.New([]string{lparts[1]}),
  239. &http.Client{},
  240. }, nil
  241. case lparts[0] == "dns":
  242. blIpAddr := make([]string, 1)
  243. for _, addr := range lparts[5:] {
  244. if govalidator.IsIPv4(addr) {
  245. blIpAddr = append(blIpAddr, addr)
  246. }
  247. }
  248. return &DrblClient{lparts[1],
  249. lparts[2],
  250. int(port),
  251. int64(weight),
  252. lparts[0],
  253. blIpAddr,
  254. dns_resolver.NewWithPort([]string{lparts[1]}, strconv.Itoa(int(port))),
  255. &http.Client{},
  256. }, nil
  257. case lparts[0] == "dnsrbl":
  258. blIpAddr := make([]string, 1)
  259. for _, addr := range lparts[5:] {
  260. if govalidator.IsIPv4(addr) {
  261. blIpAddr = append(blIpAddr, addr)
  262. }
  263. }
  264. return &DrblClient{lparts[1],
  265. lparts[2],
  266. int(port),
  267. int64(weight),
  268. lparts[0],
  269. blIpAddr,
  270. dns_resolver.NewWithPort([]string{lparts[1]}, strconv.Itoa(int(port))),
  271. &http.Client{},
  272. }, nil
  273. }
  274. }
  275. return &DrblClient{}, fmt.Errorf("drblpeer: malformed peerline %s", peerline)
  276. } else {
  277. return &DrblClient{}, fmt.Errorf("drblpeer: malformed peerline %s", peerline)
  278. }
  279. }
  280. /*
  281. func PeerListWatcher(filename string, peersList *DrblPeers, debug bool) {
  282. doneChan := make(chan bool)
  283. newlist, err := NewPeerListFromFile(filename, peersList.HitWeight, peersList.Timeout, peersList.Debug)
  284. if err != nil {
  285. fmt.Println(err)
  286. //DENY all unfortunate case
  287. } else {
  288. fmt.Println("no error on first parsing config file =>", filename)
  289. peersList = newlist
  290. }
  291. for {
  292. go func(doneChan chan bool) {
  293. defer func() {
  294. doneChan <- true
  295. }()
  296. err := watcher.WatchFile(filename)
  297. if err != nil && debug {
  298. fmt.Println("Error Watching config file =>", filename, "Error =>", err)
  299. }
  300. if debug {
  301. fmt.Println("File", filename, "has been changed")
  302. }
  303. }(doneChan)
  304. select {
  305. case <-doneChan:
  306. newlist, err := NewPeerListFromFile(filename, peersList.HitWeight, peersList.Timeout, peersList.Debug)
  307. if err != nil {
  308. //DENY all unfortunate case
  309. fmt.Println("Error parsing config file =>", filename, "Error =>", err)
  310. } else {
  311. peersList = newlist
  312. }
  313. }
  314. }
  315. }
  316. */
  317. //Block and weight
  318. func (peersList *DrblPeers) Check(hostname string) (bool, int64) {
  319. block := false
  320. localWeight := peersList.HitWeight
  321. if len(peersList.Peers) < 1 {
  322. localWeight = 100 * 1024
  323. }
  324. if peersList.Debug {
  325. fmt.Println("Peerlist size", peersList.Peers, "while checking:", hostname, "Local weigth:", localWeight)
  326. }
  327. if len(peersList.Peers) < 1 {
  328. return block, localWeight
  329. }
  330. for _, peer := range peersList.Peers {
  331. if localWeight <= int64(0) {
  332. block = true
  333. return block, localWeight
  334. }
  335. found, allowaccess, admin, key, err := peer.Check(hostname, peersList.Debug)
  336. if err != nil {
  337. if peersList.Debug {
  338. fmt.Println("peer", peer.Peername, "had an error", err, "while checking:", hostname, "Allow acces:", allowaccess)
  339. }
  340. continue
  341. }
  342. if peersList.Debug {
  343. fmt.Println("peer", peer.Peername, ", results: found =>", found, "allow-access =>", allowaccess, "admin =>", admin, "key =>", key, "hostname =>", hostname)
  344. }
  345. if found {
  346. atomic.AddInt64(&localWeight, -peer.Weight)
  347. }
  348. if found && !allowaccess {
  349. if peersList.Debug {
  350. fmt.Println("Peer", peer.Peername, "weigth =>", peer.Weight, "hostname =>,", hostname, "!allowaccess", "found =>", found)
  351. }
  352. } else {
  353. if peersList.Debug {
  354. fmt.Println("Peer", peer.Peername, "weigth =>", peer.Weight, "hostname =>,", hostname, "allowaccess", "found =>", found)
  355. }
  356. }
  357. }
  358. if localWeight <= int64(0) {
  359. block = true
  360. }
  361. return block, localWeight
  362. }
  363. func (peersList *DrblPeers) CheckUrlWithSrc(requestUrl, src string) (bool, int64) {
  364. block := false
  365. localWeight := peersList.HitWeight
  366. if len(peersList.Peers) < 1 {
  367. localWeight = 100 * 1024
  368. }
  369. if peersList.Debug {
  370. fmt.Println("Peerlist size", peersList.Peers, "while checking:", requestUrl, "For Source", src, "Local weigth:", localWeight)
  371. }
  372. if len(peersList.Peers) < 1 {
  373. return block, localWeight
  374. }
  375. for _, peer := range peersList.Peers {
  376. if localWeight <= int64(0) {
  377. block = true
  378. return block, localWeight
  379. }
  380. found, allowaccess, admin, key, err := peer.HttpCheckUrlWithSrc(requestUrl, src, peersList.Debug)
  381. if peer.Protocol == "http" || peer.Protocol == "https" {
  382. // OK+ if peersList.Debug {
  383. if peersList.Debug {
  384. fmt.Println("peer", peer.Peername, "peer-protocol", peer.Protocol, ", results: found =>", found, "allow-access =>", allowaccess, "admin =>", admin, "url =>", requestUrl, "src =>", src)
  385. }
  386. } else {
  387. continue
  388. }
  389. if err != nil {
  390. if peersList.Debug {
  391. fmt.Println("peer", peer.Peername, "had an error", err, "while checking:", requestUrl, "Allow acces:", allowaccess)
  392. }
  393. continue
  394. }
  395. if peersList.Debug {
  396. fmt.Println("peer", peer.Peername, ", results: found =>", found, "allow-access =>", allowaccess, "admin =>", admin, "key =>", key, "url =>", requestUrl, "src =>", src)
  397. }
  398. if found {
  399. atomic.AddInt64(&localWeight, -peer.Weight)
  400. }
  401. if found && !allowaccess {
  402. if peersList.Debug {
  403. fmt.Println("Peer", peer.Peername, "weigth =>", peer.Weight, "url =>,", requestUrl, "!allowaccess", "src =>", src, "found =>", found)
  404. }
  405. } else {
  406. if peersList.Debug {
  407. fmt.Println("Peer", peer.Peername, "weigth =>", peer.Weight, "url =>,", requestUrl, "allowaccess", "src =>", src, "found =>", found)
  408. }
  409. }
  410. }
  411. if localWeight <= int64(0) {
  412. block = true
  413. }
  414. return block, localWeight
  415. }