2010-08-19 33 views
29

Đây là một khó khăn ...Rails: tìm hiểu xem một IP nằm trong một dãy IP

Làm thế nào bạn có thể cho biết nếu một ip, nói 62.156.244.13 nằm trong phạm vi của 62.0.0.062.255.255.255

Có một cách Ruby đơn giản để làm điều này, hoặc làm thế nào tôi có thể giải quyết điều này?

Trả lời

75
>> require "ipaddr" 
=> true 
>> low = IPAddr.new("62.0.0.0").to_i 
=> 1040187392 
>> high = IPAddr.new("62.255.255.255").to_i 
=> 1056964607 
>> ip = IPAddr.new("62.156.244.13").to_i 
=> 1050473485 
>> (low..high)===ip 
=> true 

Nếu bạn đang cho mạng thay vì các địa chỉ bắt đầu và kết thúc, nó thậm chí còn đơn giản hơn

>> net = IPAddr.new("62.0.0.0/8") 
=> #<IPAddr: IPv4:62.0.0.0/255.0.0.0> 
>> net===IPAddr.new("62.156.244.13") 
=> true 

IPAddr cũng sẽ hoạt động với địa chỉ IPv6

>> low = IPAddr.new('1::') 
=> #<IPAddr: IPv6:0001:0000:0000:0000:0000:0000:0000:0000/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff> 
>> high = IPAddr.new('2::') 
=> #<IPAddr: IPv6:0002:0000:0000:0000:0000:0000:0000:0000/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff> 
>> (low..high)===IPAddr.new('1::1') 
=> true 
+6

Trong khi bài đăng của jdl thật tuyệt vời, đây là giải pháp tốt nhất. Đừng sáng tạo lại bánh xe. –

+0

Vâng, tôi thích cái này. Tôi không biết rằng thư viện đã tồn tại. – jdl

+0

đây là điểm trên! cảm ơn bạn! – r2b2

11

Tôi sẽ sử dụng this killer little function để chuyển đổi địa chỉ IP thành số nguyên và sau đó so sánh các địa chỉ đó.

def ip_addr_in_range?(low, high, addr) 
    int_addr = numeric_ip(addr) 
    int_addr <= numeric_ip(high) && int_addr >= numeric_ip(low) 
end 

def numeric_ip(ip_str) 
    ip_str.split('.').inject(0) { |ip_num, part| (ip_num << 8) + part.to_i } 
end 

def test_ip_addr_in_range(low, high, addr, expected) 
    result = ip_addr_in_range?(low, high, addr) 
    puts "#{addr} #{(expected ? 'should' : 'should not')} be within #{low} and #{high}: #{(expected == result ? 'PASS' : 'FAIL')}" 
end 


test_ip_addr_in_range("192.168.0.0", "192.168.0.255", "192.168.0.200", true) 
test_ip_addr_in_range("192.168.0.0", "192.168.0.155", "192.168.0.200", false) 
test_ip_addr_in_range("192.168.0.0", "192.168.255.255", "192.168.100.200", true) 
test_ip_addr_in_range("192.168.0.0", "192.168.100.255", "192.168.150.200", false) 
test_ip_addr_in_range("192.168.255.255", "192.255.255.255", "192.200.100.100", true) 
test_ip_addr_in_range("192.168.255.255", "192.255.255.255", "192.100.100.100", false) 
test_ip_addr_in_range("192.168.255.255", "255.255.255.255", "200.200.100.100", true) 
test_ip_addr_in_range("192.168.255.255", "255.255.255.255", "180.100.100.100", false) 

$ ruby ip_range.rb 
192.168.0.200 should be within 192.168.0.0 and 192.168.0.255: PASS 
192.168.0.200 should not be within 192.168.0.0 and 192.168.0.155: PASS 
192.168.100.200 should be within 192.168.0.0 and 192.168.255.255: PASS 
192.168.150.200 should not be within 192.168.0.0 and 192.168.100.255: PASS 
192.200.100.100 should be within 192.168.255.255 and 192.255.255.255: PASS 
192.100.100.100 should not be within 192.168.255.255 and 192.255.255.255: PASS 
200.200.100.100 should be within 192.168.255.255 and 255.255.255.255: PASS 
180.100.100.100 should not be within 192.168.255.255 and 255.255.255.255: PASS 
+0

+1 cho câu trả lời bao gồm rộng rãi. kiểm tra – jhwist

+0

Câu trả lời hay, hoàn chỉnh với bộ thử nghiệm đầy đủ, +1 –

-7

Đừng làm cho việc này khó hơn.

def check_ip(ip) 
    '62.0.0.0' < ip and ip < '62.255.255.255' 
end 

check_ip '62.156.244.13' #=> true 

Chỉnh sửa: Hoặc, nếu bạn đang sử dụng Rails/ActiveSupport:

def check_ip(ip) 
    ip.starts_with? '62' 
end 

check_ip '62.156.244.13' #=> true 
+0

Điều này có nghĩa là Ruby tự động nhận ra địa chỉ IP trong chuỗi không? – deceze

+2

Phương pháp của bạn không thành công khi kiểm tra "10.0.0.2" nằm trong khoảng "10.0.0.1" và "10.0.0.10". – jdl

+2

@deceze No. Anh ấy dựa vào thứ tự chữ cái, chỉ ngẫu nhiên làm việc với những con số anh ấy chọn. – jdl

-1

JDL của answer là tốt. Tôi sẽ làm cho in_range? hoạt một lớp lót:

def ip_addr_in_range?(low, high, addr) 
    (numeric_ip(low) .. numeric_ip(high)) === numeric_ip(addr) 
end 
0

tôi thích phương pháp này để chuyển đổi địa chỉ IP để một số nguyên cho phạm vi so sánh:

# n_ip("192.1.1.23") will return the number 192001001023 
def n_ip(input) 
    input.split(".").collect{|p| p.rjust(3, "0")}.join.to_i 
end 

def ip_in_range?(from, to, given) 
    (n_ip(from)..n_ip(to).include?(n_ip(given)) 
end 

Bây giờ bạn có thể kiểm tra giá trị như sau:

>> ip_in_range?("192.168.0.0", "192.168.0.255","192.168.0.200") 
ip_in_range?("192.168.0.0", "192.168.0.255","192.168.0.200") 
=> true 
>> ip_in_range?("192.168.0.0", "192.168.0.255", "192.168.1.200") 
ip_in_range?("192.168.0.0", "192.168.0.255", "192.168.1.200") 
=> false 

Số nguyên được trả về không phải là biểu diễn 32 bit của địa chỉ IP. Logic sẽ làm việc cho tất cả các địa chỉ IP hợp lệ.

3

Lấy cảm hứng từ câu trả lời JDL, nhưng với chiếc Range:

class String 
    def to_ip 
    split(".").inject(0) { |s, p| (s << 8) + p.to_i } 
    end 
end 

("62.0.0.0".to_ip.."62.255.255.255".to_ip).include?("62.156.244.13".to_ip) 
+0

Cách tiếp cận tuyệt vời. – ylluminate

Các vấn đề liên quan