decisions.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. package database
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. "strconv"
  7. "github.com/crowdsecurity/crowdsec/pkg/database/ent"
  8. "github.com/crowdsecurity/crowdsec/pkg/database/ent/decision"
  9. "github.com/crowdsecurity/crowdsec/pkg/types"
  10. "github.com/pkg/errors"
  11. )
  12. func BuildDecisionRequestWithFilter(query *ent.DecisionQuery, filter map[string][]string) (*ent.DecisionQuery, error) {
  13. var err error
  14. var start_ip, start_sfx, end_ip, end_sfx int64
  15. var ip_sz int
  16. var contains bool = true
  17. /*if contains is true, return bans that *contains* the given value (value is the inner)
  18. else, return bans that are *contained* by the given value (value is the outer)*/
  19. /*the simulated filter is a bit different : if it's not present *or* set to false, specifically exclude records with simulated to true */
  20. if v, ok := filter["simulated"]; ok {
  21. if v[0] == "false" {
  22. query = query.Where(decision.SimulatedEQ(false))
  23. }
  24. delete(filter, "simulated")
  25. } else {
  26. query = query.Where(decision.SimulatedEQ(false))
  27. }
  28. for param, value := range filter {
  29. switch param {
  30. case "contains":
  31. contains, err = strconv.ParseBool(value[0])
  32. if err != nil {
  33. return nil, errors.Wrapf(InvalidFilter, "invalid contains value : %s", err)
  34. }
  35. case "scope":
  36. for i, scope := range value {
  37. switch strings.ToLower(scope) {
  38. case "ip":
  39. value[i] = types.Ip
  40. case "range":
  41. value[i] = types.Range
  42. case "country":
  43. value[i] = types.Country
  44. case "as":
  45. value[i] = types.AS
  46. }
  47. }
  48. query = query.Where(decision.ScopeIn(value...))
  49. case "value":
  50. query = query.Where(decision.ValueEQ(value[0]))
  51. case "type":
  52. query = query.Where(decision.TypeEQ(value[0]))
  53. case "ip", "range":
  54. ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(value[0])
  55. if err != nil {
  56. return nil, errors.Wrapf(InvalidIPOrRange, "unable to convert '%s' to int: %s", value[0], err)
  57. }
  58. default:
  59. return query, errors.Wrapf(InvalidFilter, "'%s' doesn't exist", param)
  60. }
  61. }
  62. if ip_sz == 4 {
  63. if contains { /*decision contains {start_ip,end_ip}*/
  64. query = query.Where(decision.And(
  65. decision.StartIPLTE(start_ip),
  66. decision.EndIPGTE(end_ip),
  67. decision.IPSizeEQ(int64(ip_sz)),
  68. ))
  69. } else { /*decision is contained within {start_ip,end_ip}*/
  70. query = query.Where(decision.And(
  71. decision.StartIPGTE(start_ip),
  72. decision.EndIPLTE(end_ip),
  73. decision.IPSizeEQ(int64(ip_sz)),
  74. ))
  75. }
  76. } else if ip_sz == 16 {
  77. if contains { /*decision contains {start_ip,end_ip}*/
  78. query = query.Where(decision.And(
  79. //matching addr size
  80. decision.IPSizeEQ(int64(ip_sz)),
  81. decision.Or(
  82. //decision.start_ip < query.start_ip
  83. decision.StartIPLT(start_ip),
  84. decision.And(
  85. //decision.start_ip == query.start_ip
  86. decision.StartIPEQ(start_ip),
  87. //decision.start_suffix <= query.start_suffix
  88. decision.StartSuffixLTE(start_sfx),
  89. )),
  90. decision.Or(
  91. //decision.end_ip > query.end_ip
  92. decision.EndIPGT(end_ip),
  93. decision.And(
  94. //decision.end_ip == query.end_ip
  95. decision.EndIPEQ(end_ip),
  96. //decision.end_suffix >= query.end_suffix
  97. decision.EndSuffixGTE(end_sfx),
  98. ),
  99. ),
  100. ))
  101. } else { /*decision is contained {start_ip,end_ip}*/
  102. query = query.Where(decision.And(
  103. //matching addr size
  104. decision.IPSizeEQ(int64(ip_sz)),
  105. decision.Or(
  106. //decision.start_ip > query.start_ip
  107. decision.StartIPGT(start_ip),
  108. decision.And(
  109. //decision.start_ip == query.start_ip
  110. decision.StartIPEQ(start_ip),
  111. //decision.start_suffix >= query.start_suffix
  112. decision.StartSuffixGTE(start_sfx),
  113. )),
  114. decision.Or(
  115. //decision.end_ip < query.end_ip
  116. decision.EndIPLT(end_ip),
  117. decision.And(
  118. //decision.end_ip == query.end_ip
  119. decision.EndIPEQ(end_ip),
  120. //decision.end_suffix <= query.end_suffix
  121. decision.EndSuffixLTE(end_sfx),
  122. ),
  123. ),
  124. ))
  125. }
  126. } else if ip_sz != 0 {
  127. return nil, errors.Wrapf(InvalidFilter, "Unknown ip size %d", ip_sz)
  128. }
  129. return query, nil
  130. }
  131. func (c *Client) QueryDecisionWithFilter(filter map[string][]string) ([]*ent.Decision, error) {
  132. var data []*ent.Decision
  133. var err error
  134. decisions := c.Ent.Decision.Query().
  135. Where(decision.UntilGTE(time.Now().UTC()))
  136. decisions, err = BuildDecisionRequestWithFilter(decisions, filter)
  137. if err != nil {
  138. return []*ent.Decision{}, err
  139. }
  140. err = decisions.Select(
  141. decision.FieldID,
  142. decision.FieldUntil,
  143. decision.FieldScenario,
  144. decision.FieldType,
  145. decision.FieldStartIP,
  146. decision.FieldEndIP,
  147. decision.FieldValue,
  148. decision.FieldScope,
  149. decision.FieldOrigin,
  150. ).Scan(c.CTX, &data)
  151. if err != nil {
  152. c.Log.Warningf("QueryDecisionWithFilter : %s", err)
  153. return []*ent.Decision{}, errors.Wrap(QueryFail, "query decision failed")
  154. }
  155. return data, nil
  156. }
  157. func (c *Client) QueryAllDecisionsWithFilters(filters map[string][]string) ([]*ent.Decision, error) {
  158. query := c.Ent.Decision.Query().Where(decision.UntilGT(time.Now().UTC()))
  159. query, err := BuildDecisionRequestWithFilter(query, filters)
  160. if err != nil {
  161. c.Log.Warningf("QueryAllDecisionsWithFilters : %s", err)
  162. return []*ent.Decision{}, errors.Wrap(QueryFail, "get all decisions with filters")
  163. }
  164. data, err := query.All(c.CTX)
  165. if err != nil {
  166. c.Log.Warningf("QueryAllDecisionsWithFilters : %s", err)
  167. return []*ent.Decision{}, errors.Wrap(QueryFail, "get all decisions with filters")
  168. }
  169. return data, nil
  170. }
  171. func (c *Client) QueryExpiredDecisionsWithFilters(filters map[string][]string) ([]*ent.Decision, error) {
  172. query := c.Ent.Decision.Query().Where(decision.UntilLT(time.Now().UTC()))
  173. query, err := BuildDecisionRequestWithFilter(query, filters)
  174. if err != nil {
  175. c.Log.Warningf("QueryExpiredDecisionsWithFilters : %s", err)
  176. return []*ent.Decision{}, errors.Wrap(QueryFail, "get expired decisions with filters")
  177. }
  178. data, err := query.All(c.CTX)
  179. if err != nil {
  180. c.Log.Warningf("QueryExpiredDecisionsWithFilters : %s", err)
  181. return []*ent.Decision{}, errors.Wrap(QueryFail, "expired decisions")
  182. }
  183. return data, nil
  184. }
  185. func (c *Client) QueryExpiredDecisionsSinceWithFilters(since time.Time, filters map[string][]string) ([]*ent.Decision, error) {
  186. query := c.Ent.Decision.Query().Where(decision.UntilLT(time.Now().UTC())).Where(decision.UntilGT(since))
  187. query, err := BuildDecisionRequestWithFilter(query, filters)
  188. if err != nil {
  189. c.Log.Warningf("QueryExpiredDecisionsSinceWithFilters : %s", err)
  190. return []*ent.Decision{}, errors.Wrap(QueryFail, "expired decisions with filters")
  191. }
  192. data, err := query.All(c.CTX)
  193. if err != nil {
  194. c.Log.Warningf("QueryExpiredDecisionsSinceWithFilters : %s", err)
  195. return []*ent.Decision{}, errors.Wrap(QueryFail, "expired decisions with filters")
  196. }
  197. return data, nil
  198. }
  199. func (c *Client) QueryNewDecisionsSinceWithFilters(since time.Time, filters map[string][]string) ([]*ent.Decision, error) {
  200. query := c.Ent.Decision.Query().Where(decision.CreatedAtGT(since)).Where(decision.UntilGT(time.Now().UTC()))
  201. query, err := BuildDecisionRequestWithFilter(query, filters)
  202. if err != nil {
  203. c.Log.Warningf("QueryNewDecisionsSinceWithFilters : %s", err)
  204. return []*ent.Decision{}, errors.Wrapf(QueryFail, "new decisions since '%s'", since.String())
  205. }
  206. data, err := query.All(c.CTX)
  207. if err != nil {
  208. c.Log.Warningf("QueryNewDecisionsSinceWithFilters : %s", err)
  209. return []*ent.Decision{}, errors.Wrapf(QueryFail, "new decisions since '%s'", since.String())
  210. }
  211. return data, nil
  212. }
  213. func (c *Client) DeleteDecisionById(decisionId int) error {
  214. err := c.Ent.Decision.DeleteOneID(decisionId).Exec(c.CTX)
  215. if err != nil {
  216. c.Log.Warningf("DeleteDecisionById : %s", err)
  217. return errors.Wrapf(DeleteFail, "decision with id '%d' doesn't exist", decisionId)
  218. }
  219. return nil
  220. }
  221. func (c *Client) DeleteDecisionsWithFilter(filter map[string][]string) (string, error) {
  222. var err error
  223. var start_ip, start_sfx, end_ip, end_sfx int64
  224. var ip_sz int
  225. var contains bool = true
  226. /*if contains is true, return bans that *contains* the given value (value is the inner)
  227. else, return bans that are *contained* by the given value (value is the outer) */
  228. decisions := c.Ent.Decision.Delete()
  229. for param, value := range filter {
  230. switch param {
  231. case "contains":
  232. contains, err = strconv.ParseBool(value[0])
  233. if err != nil {
  234. return "0", errors.Wrapf(InvalidFilter, "invalid contains value : %s", err)
  235. }
  236. case "scope":
  237. decisions = decisions.Where(decision.ScopeEQ(value[0]))
  238. case "value":
  239. decisions = decisions.Where(decision.ValueEQ(value[0]))
  240. case "type":
  241. decisions = decisions.Where(decision.TypeEQ(value[0]))
  242. case "ip", "range":
  243. ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(value[0])
  244. if err != nil {
  245. return "0", errors.Wrapf(InvalidIPOrRange, "unable to convert '%s' to int: %s", value[0], err)
  246. }
  247. default:
  248. return "0", errors.Wrap(InvalidFilter, fmt.Sprintf("'%s' doesn't exist", param))
  249. }
  250. }
  251. if ip_sz == 4 {
  252. if contains { /*decision contains {start_ip,end_ip}*/
  253. decisions = decisions.Where(decision.And(
  254. decision.StartIPLTE(start_ip),
  255. decision.EndIPGTE(end_ip),
  256. decision.IPSizeEQ(int64(ip_sz)),
  257. ))
  258. } else { /*decision is contained within {start_ip,end_ip}*/
  259. decisions = decisions.Where(decision.And(
  260. decision.StartIPGTE(start_ip),
  261. decision.EndIPLTE(end_ip),
  262. decision.IPSizeEQ(int64(ip_sz)),
  263. ))
  264. }
  265. } else if ip_sz == 16 {
  266. if contains { /*decision contains {start_ip,end_ip}*/
  267. decisions = decisions.Where(decision.And(
  268. //matching addr size
  269. decision.IPSizeEQ(int64(ip_sz)),
  270. decision.Or(
  271. //decision.start_ip < query.start_ip
  272. decision.StartIPLT(start_ip),
  273. decision.And(
  274. //decision.start_ip == query.start_ip
  275. decision.StartIPEQ(start_ip),
  276. //decision.start_suffix <= query.start_suffix
  277. decision.StartSuffixLTE(start_sfx),
  278. )),
  279. decision.Or(
  280. //decision.end_ip > query.end_ip
  281. decision.EndIPGT(end_ip),
  282. decision.And(
  283. //decision.end_ip == query.end_ip
  284. decision.EndIPEQ(end_ip),
  285. //decision.end_suffix >= query.end_suffix
  286. decision.EndSuffixGTE(end_sfx),
  287. ),
  288. ),
  289. ))
  290. } else {
  291. decisions = decisions.Where(decision.And(
  292. //matching addr size
  293. decision.IPSizeEQ(int64(ip_sz)),
  294. decision.Or(
  295. //decision.start_ip > query.start_ip
  296. decision.StartIPGT(start_ip),
  297. decision.And(
  298. //decision.start_ip == query.start_ip
  299. decision.StartIPEQ(start_ip),
  300. //decision.start_suffix >= query.start_suffix
  301. decision.StartSuffixGTE(start_sfx),
  302. )),
  303. decision.Or(
  304. //decision.end_ip < query.end_ip
  305. decision.EndIPLT(end_ip),
  306. decision.And(
  307. //decision.end_ip == query.end_ip
  308. decision.EndIPEQ(end_ip),
  309. //decision.end_suffix <= query.end_suffix
  310. decision.EndSuffixLTE(end_sfx),
  311. ),
  312. ),
  313. ))
  314. }
  315. } else if ip_sz != 0 {
  316. return "0", errors.Wrapf(InvalidFilter, "Unknown ip size %d", ip_sz)
  317. }
  318. nbDeleted, err := decisions.Exec(c.CTX)
  319. if err != nil {
  320. c.Log.Warningf("DeleteDecisionsWithFilter : %s", err)
  321. return "0", errors.Wrap(DeleteFail, "decisions with provided filter")
  322. }
  323. return strconv.Itoa(nbDeleted), nil
  324. }
  325. // SoftDeleteDecisionsWithFilter udpate the expiration time to now() for the decisions matching the filter
  326. func (c *Client) SoftDeleteDecisionsWithFilter(filter map[string][]string) (string, error) {
  327. var err error
  328. var start_ip, start_sfx, end_ip, end_sfx int64
  329. var ip_sz int
  330. var contains bool = true
  331. /*if contains is true, return bans that *contains* the given value (value is the inner)
  332. else, return bans that are *contained* by the given value (value is the outer)*/
  333. decisions := c.Ent.Decision.Update().Where(decision.UntilGT(time.Now().UTC()))
  334. for param, value := range filter {
  335. switch param {
  336. case "contains":
  337. contains, err = strconv.ParseBool(value[0])
  338. if err != nil {
  339. return "0", errors.Wrapf(InvalidFilter, "invalid contains value : %s", err)
  340. }
  341. case "scope":
  342. decisions = decisions.Where(decision.ScopeEQ(value[0]))
  343. case "value":
  344. decisions = decisions.Where(decision.ValueEQ(value[0]))
  345. case "type":
  346. decisions = decisions.Where(decision.TypeEQ(value[0]))
  347. case "ip", "range":
  348. ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(value[0])
  349. if err != nil {
  350. return "0", errors.Wrapf(InvalidIPOrRange, "unable to convert '%s' to int: %s", value[0], err)
  351. }
  352. default:
  353. return "0", errors.Wrapf(InvalidFilter, "'%s' doesn't exist", param)
  354. }
  355. }
  356. if ip_sz == 4 {
  357. if contains {
  358. /*Decision contains {start_ip,end_ip}*/
  359. decisions = decisions.Where(decision.And(
  360. decision.StartIPLTE(start_ip),
  361. decision.EndIPGTE(end_ip),
  362. decision.IPSizeEQ(int64(ip_sz)),
  363. ))
  364. } else {
  365. /*Decision is contained within {start_ip,end_ip}*/
  366. decisions = decisions.Where(decision.And(
  367. decision.StartIPGTE(start_ip),
  368. decision.EndIPLTE(end_ip),
  369. decision.IPSizeEQ(int64(ip_sz)),
  370. ))
  371. }
  372. } else if ip_sz == 16 {
  373. /*decision contains {start_ip,end_ip}*/
  374. if contains {
  375. decisions = decisions.Where(decision.And(
  376. //matching addr size
  377. decision.IPSizeEQ(int64(ip_sz)),
  378. decision.Or(
  379. //decision.start_ip < query.start_ip
  380. decision.StartIPLT(start_ip),
  381. decision.And(
  382. //decision.start_ip == query.start_ip
  383. decision.StartIPEQ(start_ip),
  384. //decision.start_suffix <= query.start_suffix
  385. decision.StartSuffixLTE(start_sfx),
  386. )),
  387. decision.Or(
  388. //decision.end_ip > query.end_ip
  389. decision.EndIPGT(end_ip),
  390. decision.And(
  391. //decision.end_ip == query.end_ip
  392. decision.EndIPEQ(end_ip),
  393. //decision.end_suffix >= query.end_suffix
  394. decision.EndSuffixGTE(end_sfx),
  395. ),
  396. ),
  397. ))
  398. } else {
  399. /*decision is contained within {start_ip,end_ip}*/
  400. decisions = decisions.Where(decision.And(
  401. //matching addr size
  402. decision.IPSizeEQ(int64(ip_sz)),
  403. decision.Or(
  404. //decision.start_ip > query.start_ip
  405. decision.StartIPGT(start_ip),
  406. decision.And(
  407. //decision.start_ip == query.start_ip
  408. decision.StartIPEQ(start_ip),
  409. //decision.start_suffix >= query.start_suffix
  410. decision.StartSuffixGTE(start_sfx),
  411. )),
  412. decision.Or(
  413. //decision.end_ip < query.end_ip
  414. decision.EndIPLT(end_ip),
  415. decision.And(
  416. //decision.end_ip == query.end_ip
  417. decision.EndIPEQ(end_ip),
  418. //decision.end_suffix <= query.end_suffix
  419. decision.EndSuffixLTE(end_sfx),
  420. ),
  421. ),
  422. ))
  423. }
  424. } else if ip_sz != 0 {
  425. return "0", errors.Wrapf(InvalidFilter, "Unknown ip size %d", ip_sz)
  426. }
  427. nbDeleted, err := decisions.SetUntil(time.Now().UTC()).Save(c.CTX)
  428. if err != nil {
  429. c.Log.Warningf("SoftDeleteDecisionsWithFilter : %s", err)
  430. return "0", errors.Wrap(DeleteFail, "soft delete decisions with provided filter")
  431. }
  432. return strconv.Itoa(nbDeleted), nil
  433. }
  434. //SoftDeleteDecisionByID set the expiration of a decision to now()
  435. func (c *Client) SoftDeleteDecisionByID(decisionID int) error {
  436. nbUpdated, err := c.Ent.Decision.Update().Where(decision.IDEQ(decisionID)).SetUntil(time.Now().UTC()).Save(c.CTX)
  437. if err != nil || nbUpdated == 0 {
  438. c.Log.Warningf("SoftDeleteDecisionByID : %v (nb soft deleted: %d)", err, nbUpdated)
  439. return errors.Wrapf(DeleteFail, "decision with id '%d' doesn't exist", decisionID)
  440. }
  441. if nbUpdated == 0 {
  442. return ItemNotFound
  443. }
  444. return nil
  445. }