Skip to content

Commit 27707bc

Browse files
author
Inbal Tako
committed
Support ipv6 extraction
1 parent 1094882 commit 27707bc

File tree

7 files changed

+81
-16
lines changed

7 files changed

+81
-16
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
securenative (0.1.36)
4+
securenative (0.1.37)
55

66
GEM
77
remote: https://rubygems.org/

lib/securenative/utils/request_utils.rb

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# frozen_string_literal: true
22

3+
require 'ipaddr'
4+
35
module SecureNative
46
module Utils
57
class RequestUtils
@@ -24,14 +26,20 @@ def self.get_client_ip_from_request(request, options)
2426
if h.nil?
2527
h = request.env[self.parse_ip(header)]
2628
end
27-
return h.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless h.nil?
29+
parsed = self.parse_proxy_header(h, header)
30+
if self.validate_ip(parsed)
31+
return parsed
32+
end
2833
rescue NoMethodError
2934
begin
3035
h = request[header]
3136
if h.nil?
3237
h = request.env[self.parse_ip(header)]
3338
end
34-
return h.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless h.nil?
39+
parsed = self.parse_proxy_header(h, header)
40+
if self.validate_ip(parsed)
41+
return parsed
42+
end
3543
rescue NoMethodError
3644
# Ignored
3745
end
@@ -41,35 +49,47 @@ def self.get_client_ip_from_request(request, options)
4149

4250
begin
4351
x_forwarded_for = request.env['HTTP_X_FORWARDED_FOR']
44-
return x_forwarded_for.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless x_forwarded_for.nil?
52+
if self.validate_ip(x_forwarded_for)
53+
return x_forwarded_for
54+
end
4555
rescue NoMethodError
4656
begin
4757
x_forwarded_for = request['HTTP_X_FORWARDED_FOR']
48-
return x_forwarded_for.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless x_forwarded_for.nil?
58+
if self.validate_ip(x_forwarded_for)
59+
return x_forwarded_for
60+
end
4961
rescue NoMethodError
5062
# Ignored
5163
end
5264
end
5365

5466
begin
5567
x_forwarded_for = request.env['HTTP_X_REAL_IP']
56-
return x_forwarded_for.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless x_forwarded_for.nil?
68+
if self.validate_ip(x_forwarded_for)
69+
return x_forwarded_for
70+
end
5771
rescue NoMethodError
5872
begin
5973
x_forwarded_for = request['HTTP_X_REAL_IP']
60-
return x_forwarded_for.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless x_forwarded_for.nil?
74+
if self.validate_ip(x_forwarded_for)
75+
return x_forwarded_for
76+
end
6177
rescue NoMethodError
6278
# Ignored
6379
end
6480
end
6581

6682
begin
6783
x_forwarded_for = request.env['REMOTE_ADDR']
68-
return x_forwarded_for.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless x_forwarded_for.nil?
84+
if self.validate_ip(x_forwarded_for)
85+
return x_forwarded_for
86+
end
6987
rescue NoMethodError
7088
begin
7189
x_forwarded_for = request['REMOTE_ADDR']
72-
return x_forwarded_for.scan(/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/)[0] unless x_forwarded_for.nil?
90+
if self.validate_ip(x_forwarded_for)
91+
return x_forwarded_for
92+
end
7393
rescue NoMethodError
7494
# Ignored
7595
end
@@ -96,6 +116,32 @@ def self.parse_ip(headers)
96116
h = headers.gsub('-', '_')
97117
return PREFIX + h.upcase
98118
end
119+
120+
def self.parse_proxy_header(headers, header_key)
121+
h = headers.gsub(header_key + ': ', '')
122+
return h
123+
end
124+
125+
def self.validate_ip(ip)
126+
if ip.nil?
127+
return false
128+
end
129+
130+
begin
131+
ipaddr = IPAddr.new(ip)
132+
if ipaddr.ipv4?
133+
return true
134+
end
135+
136+
if ipaddr.ipv6?
137+
return true
138+
end
139+
rescue Exception
140+
# Ignored
141+
end
142+
143+
return false
144+
end
99145
end
100146
end
101147
end

lib/securenative/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module SecureNative
4-
VERSION = '0.1.36'
4+
VERSION = '0.1.37'
55
end

spec/securenative/spec_api_manager.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
5656
'Authorization' => 'YOUR_API_KEY',
5757
'Content-Type' => 'application/json',
58-
'Sn-Version' => '0.1.36',
58+
'Sn-Version' => '0.1.37',
5959
'User-Agent' => 'SecureNative-ruby'
6060
}
6161
).to_return(status: 200, body: '', headers: {})

spec/securenative/spec_event_manager.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def initialize
2929
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
3030
'Authorization' => 'YOUR_API_KEY',
3131
'Content-Type' => 'application/json',
32-
'Sn-Version' => '0.1.36',
32+
'Sn-Version' => '0.1.37',
3333
'User-Agent' => 'SecureNative-ruby'
3434
})
3535
.to_return(status: 200, body: '', headers: {})
@@ -53,7 +53,7 @@ def initialize
5353
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
5454
'Authorization' => 'YOUR_API_KEY',
5555
'Content-Type' => 'application/json',
56-
'Sn-Version' => '0.1.36',
56+
'Sn-Version' => '0.1.37',
5757
'User-Agent' => 'SecureNative-ruby'
5858
})
5959
.to_return(status: 401, body: '', headers: {})
@@ -74,7 +74,7 @@ def initialize
7474
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
7575
'Authorization' => 'YOUR_API_KEY',
7676
'Content-Type' => 'application/json',
77-
'Sn-Version' => '0.1.36',
77+
'Sn-Version' => '0.1.37',
7878
'User-Agent' => 'SecureNative-ruby'
7979
})
8080
.to_return(status: 500, body: '', headers: {})

spec/securenative/spec_http_client.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
1616
'Authorization' => 'YOUR_API_KEY',
1717
'Content-Type' => 'application/json',
18-
'Sn-Version' => '0.1.36',
18+
'Sn-Version' => '0.1.37',
1919
'User-Agent' => 'SecureNative-ruby'
2020
}).to_return(status: 200, body: '', headers: {})
2121

spec/securenative/utils/spec_request_utils.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
require 'rspec'
66

77
RSpec.describe SecureNative::Utils::RequestUtils do
8-
it 'extract a request with proxy headers' do
8+
it 'extract a request with proxy headers ipv4' do
99
options = SecureNative::Options.new
1010
options.proxy_headers = [
1111
'CF-Connecting-IP'
@@ -23,4 +23,23 @@
2323

2424
expect(client_ip).to eq('203.0.113.1')
2525
end
26+
27+
it 'extract a request with proxy headers ipv6' do
28+
options = SecureNative::Options.new
29+
options.proxy_headers = [
30+
'CF-Connecting-IP'
31+
]
32+
33+
stub_request(:get, 'http://www.example.com/')
34+
.with(headers: {
35+
'Accept' => '*/*',
36+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
37+
'User-Agent' => 'Ruby'
38+
}).to_return(status: 200, body: '', headers: { 'CF-Connecting-IP' => 'CF-Connecting-IP: f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d' })
39+
40+
request = Net::HTTP.get_response('www.example.com', '/')
41+
client_ip = SecureNative::Utils::RequestUtils.get_client_ip_from_request(request, options)
42+
43+
expect(client_ip).to eq('f71f:5bf9:25ff:1883:a8c4:eeff:7b80:aa2d')
44+
end
2645
end

0 commit comments

Comments
 (0)