3

I'm trying to create an array of IP addresses so that when the application is ran Rack-Attack can identify from the set of IP addresses that are allowed to access the application. So what I have done is as followed:

  a = "127.0.0.1"
  Rack::Attack.blacklist('allow from localhost') do |req|
    p "#{'127.0.0.1' == req.ip} "
   a != req.ip 
  end

The above works, so localhost can access the application but I have tried the following below which seems to not work what so ever:

a = "127.0.0.1", "1.2.3.4"
  Rack::Attack.blacklist('allow from localhost') do |req|
    a.select{|x| x != req.ip}.join("")
  end

Can someone explain what the correct way would be to do this. You can see that I create an array. I want Rack::Attack to detect whether the IP address in the array has access or not.

ekremkaraca
  • 1,453
  • 2
  • 18
  • 37
user532339
  • 179
  • 9

3 Answers3

2

First off it would be nice if you were more explicit about creating an array and write

a = ["127.0.0.1", "1.2.3.4"]

but it's even better to use Set

allowed = Set.new['127.0.0.1', '1.2.3.4']

(also using single-quotes should save time as Ruby treats such string as literal, opposed to double-quotes)

To check if element is a member of an array you should use Array#include? so the code becomes

Rack::Attack.blacklist('allow from localhost') do |req|
  !a.include? req.ip
end
Mike Szyndel
  • 10,461
  • 10
  • 47
  • 63
  • Prior to your answer I tried this momentarily ago. I was following https://github.com/kickstarter/rack-attack#blacklists. However this only specifies one particular IP address. I want to specify an array of IP address's. Thank you for acknowledging the question. – user532339 May 28 '14 at 15:18
2

An efficient way to do this would be to use a Set, a container that's like an array but provides fast lookup on individual, unique elements.

So, rewritten with that in mind:

allowed = %w[ 127.0.0.1 1.2.3.4 ].to_set

Rack::Attack.blacklist('allow from localhost') do |req|
  !allowed.include?(req.ip)
end

In your original declaration:

a = "x", "y"

In this case a is assigned to the first thing in that list, "x", and the rest is ignored.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • You mentioning `to_set` triggered one of the key points the guy mentioned in the rails conf 2014 video: https://www.youtube.com/watch?feature=player_detailpage&v=m1UwxsZD6sw#t=1437 but he does `BANNED_IPS = Set.new['1.2.3.4', '5.6.7.8']` But thank you – user532339 May 28 '14 at 15:26
  • 1
    `Set.new([...])` and `[...].to_set` are two ways to get the same result. – tadman May 28 '14 at 15:35
1

I know it's too late but I didn't like the Array#include? solution so I went ahead and added 2 new methods for safelist and blocklist each to have support for the same. Sharing it here as it will help other users too. It can be found in forked rack_attack branch.

Usage:

Safelisting:

# config/initializers/rack_attack.rb (for rails app)

ALLOWED_IPS = %w[127.0.0.1 ::1 5.6.7.8 123.456.789.0/24]

Rack::Attack.safelist_ips(ALLOWED_IPS)

Blocklisting:

# config/initializers/rack_attack.rb (for rails apps)

BLOCKED_IPS = %w[1.2.3.4 123.456.789.0/24]

Rack::Attack.blocklist_ips(BLOCKED_IPS)
Md. Farhan Memon
  • 6,055
  • 2
  • 11
  • 36