petspanda D
petspanda D

Reputation: 171

Elixir : verify IP present in particular range

Need to check whether the given IP present in these multiple range or not

Given IP: 49.14.1.2
Ranges: 49.14.0.0 - 49.14.63.255, 106.76.96.0 - 106.76.127.255, and so on

I have tried by converting to integer and verifying the ranges. Is there any other way to do in IP itself without converting to integer

Upvotes: 2

Views: 1226

Answers (4)

Spacez
Spacez

Reputation: 81

In addition to what other people suggest, net_address also offers a simple and lightweight way to work with IPs and ranges.

In the OP's case, you can do something like:

iex(9)> import IP
IP
iex(10)> ip_ranges = [~i"49.14.0.0..49.14.63.255", ~i"106.76.96.0..106.76.127.255"]
[~i"49.14.0.0..49.14.63.255", ~i"106.76.96.0..106.76.127.255"]
iex(11)> {:ok, ip} = from_string("49.14.1.2")
{:ok, {49, 14, 1, 2}}
iex(12)> ip
{49, 14, 1, 2}
iex(13)> Enum.any?(ip_ranges, fn ip_range -> ip in ip_range end)
true
iex(14)> {:ok, ip} = from_string("49.14.64.1")
{:ok, {49, 14, 64, 1}}
iex(15)> Enum.any?(ip_ranges, fn ip_range -> ip in ip_range end)
false

For more info, check out this documentation.

Upvotes: 0

Ben Yee
Ben Yee

Reputation: 1595

If you know CIDR IP notation, then you can check to see if a particular IP Address is with in the IP range using:

> cidr = InetCidr.parse("49.14.0.0/16")
{{49, 14, 0, 0}, {49, 14, 255, 255}, 16}

> address = InetCidr.parse_address!("49.14.1.2") 
{49, 14, 1, 2}

> InetCidr.contains?(cidr, address)
true

https://github.com/Cobenian/inet_cidr

Upvotes: 3

Máté
Máté

Reputation: 2345

You could use a tail recursive function to deal with the large list, and check each. Something along the lines of:

# First parameter: ip
# Second parameter the list of ranges in a tuple
# Third parameter the passed list, i.e. the ranges it does match
# It return the list of range(s) that the ip matched.
def ip_in_range(ip, [], match_list) do: match_list
def ip_in_range(ip, [{from_ip, to_ip} | rest], match_list) when ip > from_ip and ip < to_ip do: ip_in_range(ip, rest, [{from_ip, to_ip} | match_list])
def ip_in_range(ip, [{from_ip, to_ip} | rest], match_list) when ip < from_ip or ip > to_ip do: ip_in_range(ip, rest, match_list)

Then you could kick it off with the inet:parse_address/1 results, for example:

ranges = [{{49, 14, 0, 0}, {49, 14, 63, 255}}, ...]
ip_in_range({49, 14, 1, 2}, ranges, [])

You could mold this as much as you like, i.e. check how many ranges it belongs to. Or even exit on the first range check success.

Upvotes: 2

evnu
evnu

Reputation: 6690

Convert addresses into a tuple form using :inet.parse_address/1 and compare using simple tuple comparison.

iex(33)> a_ip = :inet.parse_address(a)
{:ok, {49, 14, 1, 2}}
iex(34)> low_ip = :inet.parse_address(low)
{:ok, {49, 14, 0, 0}}
iex(35)> high_ip = :inet.parse_address(high)
{:ok, {49, 14, 63, 255}}
iex(36)> a_ip < low_ip
false
iex(37)> a_ip > low_ip
true
iex(38)> a_ip < high_ip
true
iex(39)> a_ip > high_ip
false

Upvotes: 2

Related Questions