Information Technology Grimoire

Version .0.0.1

IT Notes from various projects because I forget, and hopefully they help you too.

Sort IP Addresses Using Perl

When dealing with lists of IP addresses, it was common for the numbers to merge together and lose track of duplicates, bad IP addresses etc. This Perl script helps you extract valid IPs from a block of text.

Sort IP Addresses Using Perl

This program gives you a Tk Box to paste some IPv4 looking text. After you have a block of text with IP addresses in it, you click “sort” and here is what happens:

  • Duplicates IP Are Removed (Deduplication)

  • Invalid IP/Text is skipped

  • IP Addresses are sorted

  • Valid IP printed out

  • Count/statistics of lines, ip addresses, etc

What to Learn from this Perl Code:

We try to follow the Perl style guide by Damon Conway, but we have our preferences too. This is more of a lesson in how to solve simple problems. This would not be a great way to sort through records that have millions of entries - for that you’d want to optimize certain aspects and verify you are not soaking up too much memory. For the purpose of a few hundred IP addresses though, this script works great.

  • Tk (message boxes, entry boxes, buttons, basic form setup)

  • IPv4 Extraction

  • Operating System Detection

  • Win32 Console Management

  • Sorting and Working with Perl Hashes

Typical Use

When working for a client, we processed many firewall requests (sometimes up to 50 changes per day). They often provided us with spreadsheets that were manually typed up and contained duplicates, errors, and sometimes missing ip addresses. It was maddening to try and review a list and not make mistakes. Perl is great for automation tasks like this, even if Tk is an outdated interface - it works!

Known Issues

Valid IP addresses come in many forms. Perhaps you don’t want anything except the x.x.x.x format? We are only looking at the x.x.x.x format! So if you need a different type of input, you will have to rewrite your error checking!

Source Code for Sorting IP Addresses:

(Don’t forget that this removes duplicates and matches valid IP only too!)

#!/usr/bin/perl

# Sorter helps to process firewall requests, especially for a large change
# or especially where the request has a random order to the IP addresses
# it's often very difficult to mentally sort the list and remove duplicates
# this program assists by doing the sort/unique for you for a side by side stare
# and compare in whatever program you are building a firewall.

# note that this is not a valid IP checker!
# IPs can be in the form of a, a.b, a.b.c, or a.b.c.d
# IPs are 32 bit binary numbers!
# this is just for sorting strings that look like IPs
# there is NO error checking

# KNOWN ISSUE:
# 1.1.1.1-1.1.1.10 only gets 2 ip addresses
# 1.1.1.1/16 shows as ip 1.1.1.1, not the actual network

# INPUT: block of text that contains ipv4 addresses in x.x.x.x format
# OUTPUT: sorts ipv4 for a side by side comparison (like comparing spreadsheet cells

use warnings;
use strict;
use Tk;
use Regexp::Common qw /net/;
use constant VERSION => ' v2.2';

# hide the console, if windows
BEGIN {
	if ($^O eq 'MSWin32') {
		require Win32::Console;
		Win32::Console::Free( );
	}
}

my $instructions1 = qq~1. Paste Text Containing IPs~;
my $instructions2 = qq~2. Sort Output ~;
my $h             = 45; # rows
my $w             = 22; # cols

my  $g = MainWindow->new;
	# title bar of main window
	$g->title('IP Sorter ' . VERSION);
	# pixels window size (resizable later via mouse, w x h)
	$g->geometry("320x659");

# setup some frames in the main window
	# the main frame
	my $mF		= $g->Frame(
		-background => "red")->pack(
		-side => 'top',
		-fill => 'x');
	# Frame 1
	my $f1		= $mF->Frame(
		-background => "grey")->pack(
		-side => 'left',
		-fill => 'y');
	# Frame 2
	my $f2		= $mF->Frame(
		-background => "grey")->pack(
		-side => 'right',
		-fill => 'y');

	# fill f1 Frame
	my $inLabel  	= $f1->Label(
		-text => $instructions1)->pack(
		-side => "top");
	my $input		= $f1->Text(
		-background => 'white',
		-foreground => 'black',
		-height		=> $h,
		-width		=> $w)->pack(
		-side 		=> "bottom");

	# fill f2 Frame and Command Button + Options
	my $outCommand  = $f2->Button(
		-text => $instructions2,
		-command =>\&process)->pack(
		-side=>"top");
	my $output		= $f2->Text(
		-background => 'white',
		-foreground => 'black',
		-height		=> $h,
		-width		=> $w)->pack(
		-side 		=> "bottom");

# stop building TK widgets, the rest is subroutines
MainLoop;

sub process {

	my %data;
	my $found 	= 0;
	my $unique 	= 0;
	my $lines 	= 0;

	# delete the output to prepare for use
	$output->delete('0.0', 'end');

	# get text block from input
	my $text = $input->get('1.0','end');

	# process the text field into an array of lines
	my @data = split /\n/,$text;

	# count how many elements are in raw data
	$lines = @data;

	while (<@data>) {
		# TODO: add the case for x.x.x.x-x.x.x.y to at least warn.
		if (m/($RE{net}{IPv4})/) {

			my $ip = $1;

			# so I'm replacing the / with  a -
			$ip =~ s#\/#-#;

			# load the index of the hash
			$data{$ip} = 1;

			# count it as a found IP
			$found++;
		}
	}

	# keys are always unique in a hash,
	# print them out in the text box
	foreach my $u (sort keys %data) {
		$output->insert('end',"$u\n");

		# count how many were unique
		$unique++;
	}

	# status of what was found
	$g->messageBox(
		-message => "LINES: $lines\nFOUND: $found\nUNIQUE: $unique",
		-type => "OK");

}

# sample data for cut and paste while testing
__DATA__
1.19.247.12-1.19.247.14 range
1.19.247.17
1.1.1.1 2.2.2.2 (2)
1.15.8.134 post
pre 1.15.8.139
1.2.199.96
1.2.199.96 duplicate
1.2.212.84
empty
555.55.5.5 (wrong)
Last updated on 12 Jul 2019
Published on 12 Jul 2019