DEV Community

Daily Challenge #31 - Count IPv4 Addresses

dev.to staff on August 03, 2019

Your challenge is to write a function that accepts starting and ending IPv4 addresses and returns the number of IP addresses from start to end, exc...
Collapse
 
phallstrom profile image
Philip Hallstrom

Ruby, and totally cheating by using it's IPAddr class :)

def ips_between(from, to)
  IPAddr.new(to).to_i - IPAddr.new(from).to_i
end
Collapse
 
maxart2501 profile image
Massimo Artizzu

This actually made me chuckle... lol cheating indeed 😁

Collapse
 
andreasjakof profile image
Andreas Jakof

And it was my first idea as well... IPv4 Addresses are 4byte integers... so the easiest way is to subtract them. 😎

Collapse
 
tanguyandreani profile image
Tanguy Andreani • Edited
def ip2int ip
  ip.split(".").map(&:to_i).pack('CCCC').unpack('N')[0]
end

def ipsBetween start, end_
  ip2int(end_) - ip2int(start)
end

p ipsBetween("10.0.0.0", "10.0.0.50") # => 50
p ipsBetween("10.0.0.0", "10.0.1.0")  # => 256
p ipsBetween("20.0.0.10", "20.0.1.0") # => 246

ip2int() is from Stack Overflow.

Collapse
 
kerrishotts profile image
Kerri Shotts

Here's mine! I extended it a little to work if the start and end were reversed.

const convertIPStringToNumber = ipString => ipString.split(".")
    .reduce((acc, part) => (acc << 8) | Number(part), 0);

const ipsBetween = (start, finish) => 
    Math.abs(convertIPStringToNumber(finish) - convertIPStringToNumber(start));

Gist: gist.github.com/kerrishotts/797450...

Collapse
 
choroba profile image
E. Choroba

Perl, using recursion. Tests included. It throws an exception if the end address precedes the start one.

#!/usr/bin/perl
use warnings;
use strict;

sub _ips_between {
    my ($list1, $list2, $sum) = @_;
    return $sum unless @$list1;

    my ($e1, $e2) = (shift @$list1, shift @$list2);
    die "End before start.\n" if $e2 < $e1 && $sum == 0;

    return _ips_between($list1, $list2, $sum + ($e2 - $e1) * 256 ** @$list1)
}

sub ips_between {
    _ips_between([split /\./, shift],
                 [split /\./, shift],
                 0)
}

use Test::More tests => 6;
use Test::Exception;

is ips_between('10.0.0.0', '10.0.0.50'), 50;
is ips_between('10.0.0.0', '10.0.1.0'), 256;
is ips_between('20.0.0.10', '20.0.1.0'), 246;
is ips_between('0.255.127.12', '1.2.3.4'), 164_856;
is ips_between('1.1.1.1', '1.1.1.1'), 0;
throws_ok { ips_between('1.1.1.1', '1.1.0.1') } qr/End before start/;
Collapse
 
peter279k profile image
peter279k

Here is the simple solution with Python:

def ips_between(start, end):
    start_ip_array = start.split('.')
    end_ip_array = end.split('.')

    first_part = int(end_ip_array[3]) - int(start_ip_array[3])
    second_part = (int(end_ip_array[2]) - int(start_ip_array[2])) * 256
    third_part = (int(end_ip_array[1]) - int(start_ip_array[1])) * pow(256, 2)
    end_part = (int(end_ip_array[0]) - int(start_ip_array[0])) * pow(256, 3)

    return sum([first_part, second_part, third_part, end_part])
Collapse
 
jasman7799 profile image
Jarod Smith • Edited
// sectionSum :: (Number -> Number) -> Number
const sectionSum = value => section => value * 256 ** section;
// ipSum :: [Number] -> Number
const ipSum = ipArray => ipArray.reduceRight((sum, value, section) => sum += sectionSum(value)(3-section));
// ipDifference :: Number -> Number -> Number
const ipDifference = ipSum1 => ipSum2 => Math.abs(ipSum1 - ipSum2);
// ipSections :: String -> [Number]
const ipSections = address => address.split('.').map(section => parseInt(section));
// ipVal :: String -> Number 
const ipVal = ip => ipSum(ipSections(ip))

// ipsBetween :: (String -> String) -> Number 
const ipsBetweenCount = startIp => endIp => ipDifference(ipVal(startIp))(ipVal(endIp))
Collapse
 
matrossuch profile image
Mat-R-Such

Python IPv4 and IPv6:

def ipsBetween(s,e): #Ipv4
    if s == e : return 0
    s,e,n=s.split('.'),e.split('.'),0
    for i in range(len(s)):
        if s[i]  < e[i]:    n+=int(e[i])
        elif s[i] == e[i] and n>0:  n+=255
        elif s[i]>e[i]: n+=255-int(s[i])
    return n
def ipsBetweenIPv6(s,e): #Ipv6
    s= [int(i,16) for i in s.split(':')]
    e= [int(i,16) for i in e.split(':')]
    return sum(map(int,e))- sum(map(int,s))

print(ipsBetween("10.0.0.0", "10.0.0.50"))
print(ipsBetween("10.0.0.0", "10.0.1.0"))
print(ipsBetween("20.0.0.10", "20.0.1.0"))  
print(ipsBetweenIPv6('2001:db8:85a3:8d3:1319:8a2e:370:7348','2001:db8:85a3:8d3:1319:8a2e:3a0:7348')) #48
Collapse
 
brightone profile image
Oleksii Filonenko

Elixir:

defmodule IP do
  import Bitwise

  def between(from, to),
    do: abs(to_integer(to) - to_integer(from))

  defp to_integer(ip) do
    ip
    |> String.split(".")
    |> Enum.reduce(0, fn part, acc -> acc <<< 8 ||| String.to_integer(part) end)
  end
end
Collapse
 
alvaromontoro profile image
Alvaro Montoro • Edited

JavaScript

const ipsBetween = (ip1, ip2) => {
  let diff = 0;
  const aIp1 = ip1.split(".");
  const aIp2 = ip2.split(".");

  // check that the IPs are well formed
  if (aIp1.length !== 4 || aIp2.length !== 4) {
    return "Invalid IPs: incorrect format";
  }

  for (x = 0; x < 4; x++) {
    // check that all the parts are valid (numeric and 0-255)
    if (
      isNaN(aIp1[x]) || isNaN(aIp2[x]) 
      || aIp1[x] < 0 || aIp1[x] > 255
      || aIp2[x] < 0 || aIp2[x] > 255
    ) {
      return "Invalid IPs: incorrect values"
    }
    diff += (aIp1[x] - aIp2[x]) * (256 ** (3-x));
  }
  return Math.abs(diff);
}

A bit verbose, but it seems to work fine. Live demo on CodePen.

Collapse
 
andreasjakof profile image
Andreas Jakof • Edited

in C#

public long IPAddressesBetween(string start, string end) => 
    IPAddress.Parse(end).Address - IPAddress.Parse(start).Address;
Collapse
 
dev0x0 profile image
Mohamed El Bahja

PHP :D

function ipsBetween($from, $to)
{
    return ip2long($to) - ip2long($from);    
}

demo: 3v4l.org/8NiWc