loading...

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... [Read Full]
markdown guide
 

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
 

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

 

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

 
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.

 

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...

 

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/;
 

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
 
// 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))
 

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.

 

PHP :D

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

demo: 3v4l.org/8NiWc

 

in C#

public long IPAddressesBetween(string start, string end) => 
    IPAddress.Parse(end).Address - IPAddress.Parse(start).Address;
code of conduct - report abuse