Peter’s blog ✴ Week 363 ✴ 2 March 2026

THE WEEKLY CHALLENGE
Lies and lies within

The Perl Camel

Task 2

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.

Perl Weekly’s review

from PW issue 763

The write-up presents a clear and methodical approach to solving the Perl Weekly Challenge, with well-structured code and helpful explanations of the reasoning behind the solution. The implementation is clean and idiomatic Perl, making the logic easy to follow and reproduce. Overall, it's a thoughtful and technically solid exploration of the problem.

This review may cover either or both challenges for this week.

I am sorry that the 'Try it' feature is currently working very slowly or not at all owing to some issue with my web hosting provider.

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];
}


31 lines of code

Output from script


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