1
0

check_client_ip_job.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. package job
  2. import (
  3. "encoding/json"
  4. "os"
  5. "regexp"
  6. "x-ui/database"
  7. "x-ui/database/model"
  8. "x-ui/logger"
  9. "x-ui/web/service"
  10. "x-ui/xray"
  11. "sort"
  12. "strings"
  13. "time"
  14. )
  15. type CheckClientIpJob struct {
  16. xrayService service.XrayService
  17. }
  18. var job *CheckClientIpJob
  19. var disAllowedIps []string
  20. func NewCheckClientIpJob() *CheckClientIpJob {
  21. job = new(CheckClientIpJob)
  22. return job
  23. }
  24. func (j *CheckClientIpJob) Run() {
  25. logger.Debug("Check Client IP Job...")
  26. processLogFile()
  27. blockedIps := []byte(strings.Join(disAllowedIps, ","))
  28. // check if file exists, if not create one
  29. _, err := os.Stat(xray.GetBlockedIPsPath())
  30. if os.IsNotExist(err) {
  31. _, err = os.OpenFile(xray.GetBlockedIPsPath(), os.O_RDWR|os.O_CREATE, 0755)
  32. checkError(err)
  33. }
  34. err = os.WriteFile(xray.GetBlockedIPsPath(), blockedIps, 0755)
  35. checkError(err)
  36. }
  37. func processLogFile() {
  38. accessLogPath := GetAccessLogPath()
  39. if accessLogPath == "" {
  40. logger.Warning("access.log doesn't exist in your config.json")
  41. return
  42. }
  43. data, err := os.ReadFile(accessLogPath)
  44. InboundClientIps := make(map[string][]string)
  45. checkError(err)
  46. lines := strings.Split(string(data), "\n")
  47. for _, line := range lines {
  48. ipRegx, _ := regexp.Compile(`[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+`)
  49. emailRegx, _ := regexp.Compile(`email:.+`)
  50. matchesIp := ipRegx.FindString(line)
  51. if len(matchesIp) > 0 {
  52. ip := string(matchesIp)
  53. if ip == "127.0.0.1" || ip == "1.1.1.1" {
  54. continue
  55. }
  56. matchesEmail := emailRegx.FindString(line)
  57. if matchesEmail == "" {
  58. continue
  59. }
  60. matchesEmail = strings.TrimSpace(strings.Split(matchesEmail, "email: ")[1])
  61. if InboundClientIps[matchesEmail] != nil {
  62. if contains(InboundClientIps[matchesEmail], ip) {
  63. continue
  64. }
  65. InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
  66. } else {
  67. InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
  68. }
  69. }
  70. }
  71. disAllowedIps = []string{}
  72. shouldCleanLog := false
  73. for clientEmail, ips := range InboundClientIps {
  74. inboundClientIps, err := GetInboundClientIps(clientEmail)
  75. sort.Strings(ips)
  76. if err != nil {
  77. addInboundClientIps(clientEmail, ips)
  78. } else {
  79. shouldCleanLog = updateInboundClientIps(inboundClientIps, clientEmail, ips)
  80. }
  81. }
  82. time.Sleep(time.Second * 5)
  83. //added 5 seconds delay before cleaning logs to reduce chance of logging IP that already has been banned
  84. if shouldCleanLog {
  85. // clean log
  86. if err := os.Truncate(GetAccessLogPath(), 0); err != nil {
  87. checkError(err)
  88. }
  89. }
  90. }
  91. func GetAccessLogPath() string {
  92. config, err := os.ReadFile(xray.GetConfigPath())
  93. checkError(err)
  94. jsonConfig := map[string]interface{}{}
  95. err = json.Unmarshal([]byte(config), &jsonConfig)
  96. checkError(err)
  97. if jsonConfig["log"] != nil {
  98. jsonLog := jsonConfig["log"].(map[string]interface{})
  99. if jsonLog["access"] != nil {
  100. accessLogPath := jsonLog["access"].(string)
  101. return accessLogPath
  102. }
  103. }
  104. return ""
  105. }
  106. func checkError(e error) {
  107. if e != nil {
  108. logger.Warning("client ip job err:", e)
  109. }
  110. }
  111. func contains(s []string, str string) bool {
  112. for _, v := range s {
  113. if v == str {
  114. return true
  115. }
  116. }
  117. return false
  118. }
  119. func GetInboundClientIps(clientEmail string) (*model.InboundClientIps, error) {
  120. db := database.GetDB()
  121. InboundClientIps := &model.InboundClientIps{}
  122. err := db.Model(model.InboundClientIps{}).Where("client_email = ?", clientEmail).First(InboundClientIps).Error
  123. if err != nil {
  124. return nil, err
  125. }
  126. return InboundClientIps, nil
  127. }
  128. func addInboundClientIps(clientEmail string, ips []string) error {
  129. inboundClientIps := &model.InboundClientIps{}
  130. jsonIps, err := json.Marshal(ips)
  131. checkError(err)
  132. inboundClientIps.ClientEmail = clientEmail
  133. inboundClientIps.Ips = string(jsonIps)
  134. db := database.GetDB()
  135. tx := db.Begin()
  136. defer func() {
  137. if err == nil {
  138. tx.Commit()
  139. } else {
  140. tx.Rollback()
  141. }
  142. }()
  143. err = tx.Save(inboundClientIps).Error
  144. if err != nil {
  145. return err
  146. }
  147. return nil
  148. }
  149. func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmail string, ips []string) bool {
  150. jsonIps, err := json.Marshal(ips)
  151. checkError(err)
  152. inboundClientIps.ClientEmail = clientEmail
  153. inboundClientIps.Ips = string(jsonIps)
  154. // check inbound limitation
  155. inbound, err := GetInboundByEmail(clientEmail)
  156. checkError(err)
  157. if inbound.Settings == "" {
  158. logger.Debug("wrong data ", inbound)
  159. return false
  160. }
  161. settings := map[string][]model.Client{}
  162. json.Unmarshal([]byte(inbound.Settings), &settings)
  163. clients := settings["clients"]
  164. shouldCleanLog := false
  165. for _, client := range clients {
  166. if client.Email == clientEmail {
  167. limitIp := client.LimitIP
  168. if limitIp != 0 {
  169. shouldCleanLog = true
  170. if limitIp < len(ips) && inbound.Enable {
  171. disAllowedIps = append(disAllowedIps, ips[limitIp:]...)
  172. for i:=limitIp; i < len(ips); i++ {
  173. logger.Info("[LIMIT_IP] Email=", clientEmail, " SRC=", ips[i])
  174. }
  175. }
  176. }
  177. }
  178. }
  179. logger.Debug("disAllowedIps ", disAllowedIps)
  180. sort.Strings(disAllowedIps)
  181. db := database.GetDB()
  182. err = db.Save(inboundClientIps).Error
  183. if err != nil {
  184. return shouldCleanLog
  185. }
  186. return shouldCleanLog
  187. }
  188. func DisableInbound(id int) error {
  189. db := database.GetDB()
  190. result := db.Model(model.Inbound{}).
  191. Where("id = ? and enable = ?", id, true).
  192. Update("enable", false)
  193. err := result.Error
  194. logger.Warning("disable inbound with id:", id)
  195. if err == nil {
  196. job.xrayService.SetToNeedRestart()
  197. }
  198. return err
  199. }
  200. func GetInboundByEmail(clientEmail string) (*model.Inbound, error) {
  201. db := database.GetDB()
  202. var inbounds *model.Inbound
  203. err := db.Model(model.Inbound{}).Where("settings LIKE ?", "%"+clientEmail+"%").Find(&inbounds).Error
  204. if err != nil {
  205. return nil, err
  206. }
  207. return inbounds, nil
  208. }