wafris 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05707fe625f71f24a02f26585d89356156b1dc83887195f1042a47856d3c86cf
4
- data.tar.gz: 05e798e3298518a0310f1cdf6a68426b2b12f9c066acc74e78833987e26f2e31
3
+ metadata.gz: 2da3a1b92fba96e01f65433a9388d7dbeb8f24225b352e1958f392cd82fc8522
4
+ data.tar.gz: c8a72dcb1459454890d11d5ba0190f2b4a7f0d13cc63ce9d7038e87cb8ca7af7
5
5
  SHA512:
6
- metadata.gz: b41d4ee2190f5a88e263ef6905ffe43e6727923df4f3f1a600f203d10ea2010409e95c02c965cc2161fce47d5d541aaa1217beeb05097134fcaecdcfcd4305f1
7
- data.tar.gz: dd940d846b7892a4607c78767f2ca364c62ab33782deb76b863d8b393f1a5c82134f0b3f6c76a438f9993e7d7702df67899d9e6485bc5491e03fcc3e02a38c1e
6
+ metadata.gz: ef4e1b43b6ae8f9060e8ba936ebffed084288e3a0df798c487141dd608f9f136e4cde74babc9ed9ab9c908f96a558fd674dcc9b579f94cc0bc95da581a973a20
7
+ data.tar.gz: a252ddc02c510c14c011c23d3127a5f17d7dc97dc6b44a46e889b85b4130e9897c4d9623fb6ad144e6cc32f21524ad5d58f008d9d1b6376c47884c2f42c94008
@@ -60,28 +60,42 @@ local function add_to_HLL_request_count(timebucket, request_id)
60
60
  end
61
61
 
62
62
  -- For: Leaderboard of IPs with Request count as score
63
- local function increment_timebucket_for_ip(timebucket, ip)
64
- redis.call("ZINCRBY", "ip-leader-sset:" .. timebucket, 1, ip)
63
+ local function increment_timebucket_for(type, timebucket, property)
64
+ -- TODO: breaking change will to switch to client_ip: prefix
65
+ type = type or "ip-"
66
+ redis.call("ZINCRBY", type .. "leader-sset:" .. timebucket, 1, property)
65
67
  end
66
68
 
67
69
  -- Configuration
68
70
  local max_requests = 100000
69
71
  local max_requests_per_ip = 10000
70
72
 
71
- local ip = ARGV[1]
73
+ local client_ip = ARGV[1]
72
74
  local ip_to_decimal = ARGV[2]
73
75
  local unix_time_milliseconds = ARGV[3]
74
76
  local unix_time = ARGV[3] / 1000
77
+ local proxy_ip = ARGV[4]
78
+ local user_agent = ARGV[5]
79
+ local request_path = ARGV[6]
80
+ local host = ARGV[7]
75
81
 
76
82
  -- Initialize local variables
77
- local request_id = get_request_id(nil, ip, max_requests)
83
+ local request_id = get_request_id(nil, client_ip, max_requests)
78
84
  local current_timebucket = get_time_bucket_from_timestamp(unix_time_milliseconds)
79
85
 
80
86
  -- GRAPH DATA COLLECTION
81
87
  add_to_HLL_request_count(current_timebucket, request_id)
82
88
 
83
89
  -- LEADERBOARD DATA COLLECTION
84
- increment_timebucket_for_ip(current_timebucket, ip)
90
+ -- TODO: breaking change will to switch to client_ip: prefix
91
+ increment_timebucket_for(nil, current_timebucket, client_ip)
92
+ if proxy_ip ~= nil then
93
+ increment_timebucket_for(nil, current_timebucket, proxy_ip)
94
+ end
95
+ increment_timebucket_for("proxy_ip:", current_timebucket, proxy_ip)
96
+ increment_timebucket_for("user_agent:", current_timebucket, user_agent)
97
+ increment_timebucket_for("request_path:", current_timebucket, request_path)
98
+ increment_timebucket_for("host:", current_timebucket, host)
85
99
 
86
100
  -- BLOCKING LOGIC
87
101
  -- Safelist Range Check
@@ -36,14 +36,6 @@ module Wafris
36
36
  read_lua_dist("wafris_core")
37
37
  end
38
38
 
39
- def graph_sha
40
- @graph_sha ||= redis.script(:load, wafris_graph)
41
- end
42
-
43
- def wafris_graph
44
- read_lua_dist("get_graph_data")
45
- end
46
-
47
39
  private
48
40
 
49
41
  def read_lua_dist(filename)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wafris
4
- VERSION = "0.1.2"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/wafris.rb CHANGED
@@ -32,12 +32,18 @@ module Wafris
32
32
  def allow_request?(request)
33
33
  configuration.connection_pool.with do |conn|
34
34
  time = Time.now.to_f * 1000
35
+ puts "WAF LOG: Client IP #{client_ip(request)}"
36
+ puts "WAF LOG: Proxy IP #{proxy_ip(request)}"
35
37
  status = conn.evalsha(
36
38
  configuration.core_sha,
37
39
  argv: [
38
- request.ip,
40
+ client_ip(request),
39
41
  IPAddr.new(request.ip).to_i,
40
- time.to_i
42
+ time.to_i,
43
+ proxy_ip(request),
44
+ request.user_agent,
45
+ request.path,
46
+ request.host
41
47
  ]
42
48
  )
43
49
 
@@ -49,60 +55,18 @@ module Wafris
49
55
  end
50
56
  end
51
57
 
52
- def add_block(ip)
53
- configuration.connection_pool.with do |conn|
54
- conn.zadd(
55
- 'blocked_ranges',
56
- IPAddr.new(ip).to_i,
57
- ip
58
- )
59
- end
60
- end
61
-
62
- def remove_block(ip)
63
- configuration.connection_pool.with do |conn|
64
- conn.zrem(
65
- 'blocked_ranges',
66
- ip
67
- )
68
- end
69
- end
70
-
71
- def request_buckets(_now)
72
- graph_data = []
73
- configuration.connection_pool.with do |conn|
74
- time = Time.now.to_f * 1000
75
- graph_data = conn.evalsha(
76
- configuration.graph_sha,
77
- argv: [
78
- time.to_i
79
- ]
80
- )
81
- end
58
+ private
82
59
 
83
- return graph_data
84
- end
60
+ def client_ip(request)
61
+ return request.ip if request.headers['x-forwarded-for'].nil?
85
62
 
86
- def ips_with_num_requests
87
- configuration.connection_pool.with do |conn|
88
- return conn.zunion(
89
- *leader_timebuckets,
90
- 0, -1, with_scores: true
91
- )
92
- end
63
+ request.headers['x-forwarded-for'].split(',').first
93
64
  end
94
65
 
95
- private
96
-
97
- def leader_timebuckets
98
- timebuckets = []
99
-
100
- time = Time.now.utc
101
- 24.times do |hours|
102
- timebuckets << "ip-leader-sset:#{(time - 60 * 60 * hours).strftime("%Y-%m-%d-%H")}"
103
- end
66
+ def proxy_ip(request)
67
+ return nil if request.headers['x-forwarded-for'].nil?
104
68
 
105
- return timebuckets
69
+ request.headers['x-forwarded-for'].split(',').last
106
70
  end
107
71
  end
108
72
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wafris
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micahel Buckbee
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-04-23 00:00:00.000000000 Z
12
+ date: 2023-05-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: connection_pool
@@ -185,7 +185,6 @@ executables: []
185
185
  extensions: []
186
186
  extra_rdoc_files: []
187
187
  files:
188
- - lib/lua/dist/get_graph_data.lua
189
188
  - lib/lua/dist/wafris_core.lua
190
189
  - lib/lua/src/get_time_buckets.lua
191
190
  - lib/lua/src/queries.lua
@@ -1,81 +0,0 @@
1
- -- Compiled from:
2
- -- src/get_time_buckets.lua
3
-
4
- -- Code was pulled from https://otland.net/threads/how-convert-timestamp-to-date-type.251657/
5
- -- An alternate solution is https://gist.github.com/markuman/e96d04139cd8acc33604
6
- local function get_time_bucket_from_timestamp(unix_time_milliseconds)
7
- local function calculate_years_number_of_days(yr)
8
- return (yr % 4 == 0 and (yr % 100 ~= 0 or yr % 400 == 0)) and 366 or 365
9
- end
10
-
11
- local function get_year_and_day_number(year, days)
12
- while days >= calculate_years_number_of_days(year) do
13
- days = days - calculate_years_number_of_days(year)
14
- year = year + 1
15
- end
16
- return year, days
17
- end
18
-
19
- local function get_month_and_month_day(days, year)
20
- local days_in_each_month = {
21
- 31,
22
- (calculate_years_number_of_days(year) == 366 and 29 or 28),
23
- 31,
24
- 30,
25
- 31,
26
- 30,
27
- 31,
28
- 31,
29
- 30,
30
- 31,
31
- 30,
32
- 31,
33
- }
34
-
35
- for month = 1, #days_in_each_month do
36
- if days - days_in_each_month[month] <= 0 then
37
- return month, days
38
- end
39
- days = days - days_in_each_month[month]
40
- end
41
- end
42
-
43
- local unix_time = unix_time_milliseconds / 1000
44
- local year = 1970
45
- local days = math.ceil(unix_time / 86400)
46
- local month = nil
47
-
48
- year, days = get_year_and_day_number(year, days)
49
- month, days = get_month_and_month_day(days, year)
50
- local hours = math.floor(unix_time / 3600 % 24)
51
- -- local minutes, seconds = math.floor(unix_time / 60 % 60), math.floor(unix_time % 60)
52
- -- hours = hours > 12 and hours - 12 or hours == 0 and 12 or hours
53
- return string.format("%04d-%02d-%02d-%02d", year, month, days, hours)
54
- end
55
-
56
- local function get_time_buckets(unix_time_milliseconds)
57
- local time_buckets = {}
58
-
59
- for i = 23, 0, -1 do
60
- table.insert(time_buckets, get_time_bucket_from_timestamp(unix_time_milliseconds - (1000 * 60 * 60 * i)))
61
- end
62
- return time_buckets
63
- end
64
-
65
- local function num_requests(time_bucket)
66
- local request_keys = redis.call("KEYS", "unique-requests:" .. time_bucket)
67
- redis.call("PFMERGE", "merged_unique-requests", unpack(request_keys))
68
- return redis.call("PFCOUNT", "merged_unique-requests")
69
- end
70
-
71
- local graph_data = {}
72
- local unix_time_milliseconds = ARGV[1]
73
- local time_buckets = get_time_buckets(unix_time_milliseconds)
74
- -- use the get_time_buckets method to get each time bucket and
75
- -- the associated count for that bucket
76
- for bucket in pairs(time_buckets) do
77
- table.insert(graph_data, time_buckets[bucket])
78
- table.insert(graph_data, num_requests(time_buckets[bucket]))
79
- end
80
-
81
- return graph_data