Camel
Peter
Peter Campbell Smith

Lies and lies within

Weekly challenge 363 — 2 March 2026

Week 363: 2 Mar 2026

Task 2

Task — Subnet sheriff

You are given an IPv4 address and an IPv4 network (in CIDR format). Write a script to determine whether both are valid and the address falls within the network.

For more information see this Wikipedia article.

Examples


Example 1
Input: $ip_addr = '192.168.1.45'
       $domain  = '192.168.1.0/24'
Output: true

Example 2
Input: $ip_addr = '10.0.0.256'
       $domain  = '10.0.0.0/24'
Output: false

Example 3
Input: $ip_addr = '172.16.8.9'
       $domain  = '172.16.8.9/32'
Output: true

Example 4
Input: $ip_addr = '172.16.4.5'
       $domain  = '172.16.0.0/14'
Output: true

Example 5
Input: $ip_addr = '192.0.2.0'
       $domain  = '192.0.2.0/25'
Output: true

Analysis

Confession: I submitted this challenge which arose from a need to filter IP addresses with permission to access a website.

An IPv4 address (ip) is a 32-bit integer. The usual dotted representation comprises the 32 bits divided into 4 octets, with each of these represented as the decimal equivalent (a.b.c.d):

ip = a × 224 + b × 216 + c × 28 + d

There are three steps to this challenge:

Step 1 is to check the validity of the supplied IPv4 address. A valid address comprises 4 integers in the range 0-255 separated by dots (.) and one line of code suffices to check that.

Step 2 is to validate the supplied network (or domain). It must be a valid address (as above) followed by a slash (/) and an integer (n) in the range 0-32.

To validate the domain, a mask (m) can be created which comprises n one bits followed by (32 - n) zero bits.

A valid domain (d) is then one where d ∧ m = d, that is, where the low order 32 - n bits of the domain are all zero.

The domain address is the lowest numbered address within the domain, and the domain contains 2(32 - n) addresses.

Step 3 is to check that the address falls within the domain which it does if ip ∧ m = d.

Fortunately, Perl supports all the operators needed to perform the needed bitwise operations.

Try it 

Try running the script with any input:



example: 172.16.4.5



example: 172.16.0.0/14

Script


#!/usr/bin/perl

# Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use v5.26;    # The Weekly Challenge - 2026-03-02
use utf8;     # Week 363 - task 2 - Subnet sheriff
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';
use Encode;

# test limits of subnet
my $subnet = '192.168.1.0/24';
subnet_sheriff('192.168.1.45', $subnet);   # typical
subnet_sheriff('192.168.1.0', $subnet);    # first
subnet_sheriff('192.168.1.255', $subnet);  # last
subnet_sheriff('192.168.2.0', $subnet);    # outside
subnet_sheriff('1.1.1.1', '1.1.255.1/24'); # invalid

# examples from challenge
subnet_sheriff('192.168.1.45', '192.168.1.0/24'); # true
subnet_sheriff('10.0.0.256', '10.0.0.0/24');    # invalid
subnet_sheriff('172.16.4.5', '172.16.0.0/14');  # true
subnet_sheriff('192.0.2.0', '192.0.2.0/25');    # true

# smallest and largest subnets
subnet_sheriff('1.2.3.4', '1.2.3.4/32'); # true
subnet_sheriff('1.2.3.4', '0.0.0.0/0');  # true

sub subnet_sheriff {
    
    my ($address, $domain, $good, $domain2, $mask, $within, $address2);
    
    # initialise
    ($address, $domain) = @_;
    say qq[\nInput:  \$address = '$address', \$domain = '$domain'];
    
    # validate address
    unless ($address =~ m|([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})|
        and $1 <= 255 and $2 <= 255 and $3 <= 255 and $4 <= 255) {
        say qq[Output: false - invalid address];
        return;
    }
    $address2 = ($1 * 2**24) + ($2 * 2**16) + ($3 * 2**8) + $4;
    
    # validate domain
    $good = $domain =~ m|([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/([0-9]{1,2})| ? 1 : 0;
    $good = ($good and $5 <= 32);
    if ($good) {
        $domain2 = $1 * (2 ** 24) + $2 * (2 ** 16) + $3 * (2 ** 8) + $4;
        $mask = (2 ** $5 - 1) << (32 - $5);
        $good = ($domain2 & $mask) == $domain2;
    }
    unless ($good) {        
        say qq[Output: false - invalid subnet];
        return;
    }
    
    # check that address falls within subnet
    $within = ($address2 & $mask) == $domain2 ? 'true' : 'false - address outside subnet';
    
    say qq[Output: $within];
}


Output


Input:  $address = '192.168.1.45',
   $domain = '192.168.1.0/24'
Output: true

Input:  $address = '192.168.1.0',
   $domain = '192.168.1.0/24'
Output: true

Input:  $address = '192.168.1.255',
   $domain = '192.168.1.0/24'
Output: true

Input:  $address = '192.168.2.0',
   $domain = '192.168.1.0/24'
Output: false - address outside subnet

Input:  $address = '1.1.1.1', $domain = '1.1.255.1/24'
Output: false - invalid subnet

Input:  $address = '192.168.1.45',
   $domain = '192.168.1.0/24'
Output: true

Input:  $address = '10.0.0.256', $domain = '10.0.0.0/24'
Output: false - invalid address

Input:  $address = '172.16.4.5', $domain = '172.16.0.0/14'
Output: true

Input:  $address = '192.0.2.0', $domain = '192.0.2.0/25'
Output: true

Input:  $address = '1.2.3.4', $domain = '1.2.3.4/32'
Output: true

Input:  $address = '1.2.3.4', $domain = '0.0.0.0/0'
Output: true

 

Any content of this website which has been created by Peter Campbell Smith is in the public domain