blacklist.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. package blacklist
  2. import (
  3. "bytes"
  4. "errors"
  5. "log"
  6. "net"
  7. "strconv"
  8. "strings"
  9. db "imuslab.com/arozos/mod/database"
  10. )
  11. /*
  12. ArozOS Blacklist Module
  13. Author: tobychui
  14. This module record the IP blacklist of users trying to enter the
  15. system without permission
  16. */
  17. type BlackList struct {
  18. Enabled bool
  19. database *db.Database
  20. }
  21. func NewBlacklistManager(sysdb *db.Database) *BlackList {
  22. sysdb.NewTable("ipblacklist")
  23. blacklistEnabled := false
  24. if sysdb.KeyExists("ipblacklist", "enable") {
  25. err := sysdb.Read("ipblacklist", "enable", &blacklistEnabled)
  26. if err != nil {
  27. log.Println("[Auth/Blacklist] Unable to load previous enable state from database. Using default.")
  28. }
  29. }
  30. return &BlackList{
  31. Enabled: blacklistEnabled,
  32. database: sysdb,
  33. }
  34. }
  35. //Check if a given IP is banned
  36. func (bl *BlackList) IsBanned(ip string) bool {
  37. if bl.Enabled == false {
  38. return false
  39. }
  40. if bl.database.KeyExists("ipblacklist", ip) {
  41. return true
  42. }
  43. //The ip might be inside as a range. Do a range search.
  44. //Need optimization, current implementation is O(N)
  45. for _, thisIpRange := range bl.ListBannedIpRanges() {
  46. if ipInRange(ip, thisIpRange) {
  47. return true
  48. }
  49. }
  50. return false
  51. }
  52. func (bl *BlackList) ListBannedIpRanges() []string {
  53. entries, err := bl.database.ListTable("ipblacklist")
  54. if err != nil {
  55. return []string{}
  56. }
  57. results := []string{}
  58. for _, keypairs := range entries {
  59. thisIpRange := keypairs[0]
  60. if string(thisIpRange) == "enable" || validateIpRange(string(thisIpRange)) != nil {
  61. //Reserved key field
  62. continue
  63. }
  64. results = append(results, string(thisIpRange))
  65. }
  66. return results
  67. }
  68. //Set the ban state of a ip or ip range
  69. func (bl *BlackList) Ban(ipRange string) error {
  70. //Check if the IP range is correct
  71. err := validateIpRange(ipRange)
  72. if err != nil {
  73. return err
  74. }
  75. //Push it to the ban list
  76. ipRange = strings.TrimSpace(ipRange)
  77. ipRange = strings.ReplaceAll(ipRange, " ", "")
  78. return bl.database.Write("ipblacklist", ipRange, true)
  79. }
  80. //Unban an IP or IP range
  81. func (bl *BlackList) UnBan(ipRange string) error {
  82. //Check if the IP range is correct
  83. err := validateIpRange(ipRange)
  84. if err != nil {
  85. return err
  86. }
  87. //Check if the ip range is banned
  88. if !bl.database.KeyExists("ipblacklist", ipRange) {
  89. return errors.New("invalid IP range given")
  90. }
  91. //Ip range exists, remove it from database
  92. return bl.database.Delete("ipblacklist", ipRange)
  93. }
  94. //Break an ip range text into independent ip strings
  95. func breakdownIpRange(ipRange string) []string {
  96. ipRange = strings.ReplaceAll(ipRange, " ", "")
  97. err := validateIpRange(ipRange)
  98. if err != nil {
  99. return []string{}
  100. }
  101. if !strings.Contains(ipRange, "-") {
  102. //This is not an ip range but a single ip
  103. return []string{ipRange}
  104. }
  105. //Break down the IP range
  106. results := []string{}
  107. ips := strings.Split(ipRange, "-")
  108. subnet := ips[0][:strings.LastIndex(ips[0], ".")]
  109. startD := ips[0][strings.LastIndex(ips[0], ".")+1:]
  110. if err != nil {
  111. return []string{}
  112. }
  113. endD := ips[1][strings.LastIndex(ips[0], ".")+1:]
  114. if err != nil {
  115. return []string{}
  116. }
  117. startDInt, err := strconv.Atoi(startD)
  118. endDInt, err := strconv.Atoi(endD)
  119. currentDInt := startDInt
  120. for currentDInt < endDInt+1 {
  121. results = append(results, subnet+"."+strconv.Itoa(currentDInt))
  122. currentDInt++
  123. }
  124. return results
  125. }
  126. //Check if an given ip in the given range
  127. func ipInRange(ip string, ipRange string) bool {
  128. ip = strings.TrimSpace(ip)
  129. ipRange = strings.ReplaceAll(ipRange, " ", "")
  130. if ip == ipRange {
  131. //For fields that the ipRange is the ip itself
  132. return true
  133. }
  134. //Try matching range
  135. if strings.Contains(ipRange, "-") {
  136. //Parse the source IP
  137. trial := net.ParseIP(ip)
  138. //Parse the IP range
  139. ips := strings.Split(ipRange, "-")
  140. ip1 := net.ParseIP(ips[0])
  141. if ip1 == nil {
  142. return false
  143. }
  144. ip2 := net.ParseIP(ips[1])
  145. if ip2 == nil {
  146. return false
  147. }
  148. if trial.To4() == nil {
  149. return false
  150. }
  151. if bytes.Compare(trial, ip1) >= 0 && bytes.Compare(trial, ip2) <= 0 {
  152. return true
  153. }
  154. return false
  155. }
  156. return false
  157. }
  158. //Check if the given IP Range string is actually an IP range
  159. func validateIpRange(ipRange string) error {
  160. ipRange = strings.TrimSpace(ipRange)
  161. ipRange = strings.ReplaceAll(ipRange, " ", "")
  162. if strings.Contains(ipRange, "-") {
  163. //This is a range
  164. if strings.Count(ipRange, "-") != 1 {
  165. //Invalid range defination
  166. return errors.New("Invalid ip range defination")
  167. }
  168. ips := strings.Split(ipRange, "-")
  169. //Check if the starting IP and ending IP are both valid
  170. if net.ParseIP(ips[0]) == nil {
  171. return errors.New("Starting ip is invalid")
  172. }
  173. if net.ParseIP(ips[1]) == nil {
  174. return errors.New("Ending ip is invalid")
  175. }
  176. //Check if the ending IP is larger than the starting IP
  177. startingIpInt, _ := strconv.Atoi(strings.ReplaceAll(ips[0], ".", ""))
  178. endingIpInt, _ := strconv.Atoi(strings.ReplaceAll(ips[1], ".", ""))
  179. if startingIpInt >= endingIpInt {
  180. return errors.New("Invalid ip range: Starting IP is larger or equal to ending ip")
  181. }
  182. //Check if they are in the same subnet
  183. startSubnet := ips[0][:strings.LastIndex(ips[0], ".")]
  184. endSubnet := ips[1][:strings.LastIndex(ips[1], ".")]
  185. if startSubnet != endSubnet {
  186. //They are not in the same subnet
  187. return errors.New("IP range subnet mismatch")
  188. }
  189. } else {
  190. //This is a single IP instead of range. Check if it is a valid IP addr
  191. if net.ParseIP(ipRange) != nil {
  192. //Ok
  193. return nil
  194. } else {
  195. return errors.New("Invalid ip given")
  196. }
  197. }
  198. return nil
  199. }