Reputation: 3814
I have been trying to work out the correct way of blocking access to our Rails 3 application except for a small number of IP addresses and a couple of IP subnets.
While looking for ways to do this I found this question/answer. The suggested code is as follows:
Application Controller
before_filter :protect
def protect
@ips = ['127.0.0.1', '203.123.10.1'] #And so on ...]
if not @ips.include? request.remote_ip
# Check for your subnet stuff here, for example
# if not request.remote_ip.include?('127.0,0')
render :text => "You are unauthorized"
return
end
end
This works, so I've altered it to redirect to a static page rather than just the text message.
What I would like to do though, is allow access from local IP's on the same subnet as the Rails application server. The subnet is simply 192.168.1.0/24
.
What is the easiest/cleanest way to add the subnet to the accepted IP's?
Upvotes: 2
Views: 1965
Reputation:
To test if a given IP address foo
is within a network specified by address net
and mask mask
, you would apply the mask to both the network address and the tested address, and see if the results are equal: foo & mask == net & mask
. You have to first convert the IP address and the mask to integers. A mask of /24
is 24 bits set to 1
followed by 8 bits set to 0
- 0xFFFFFF00
or 255.255.255.0
in dotted quad notation.
before_filter :protect
def protect
@ips = ['127.0.0.1', '192.168.1.0/24'] #And so on ...]
allowed = false
# Convert remote IP to an integer.
bremote_ip = request.remote_ip.split('.').map(&:to_i).pack('C*').unpack('N').first
@ips.each do |ipstring|
ip, mask = ipstring.split '/'
# Convert tested IP to an integer.
bip = ip.split('.').map(&:to_i).pack('C*').unpack('N').first
# Convert mask to an integer, and assume /32 if not specified.
mask = mask ? mask.to_i : 32
bmask = ((1 << mask) - 1) << (32 - mask)
if bip & bmask == bremote_ip & bmask
allowed = true
break
end
end
if not allowed
render :text => "You are unauthorized"
return
end
end
Upvotes: 6