#!/usr/bin/perl
#
# Copyright (C) 2003 - 2004 Josip Deanovic <djosip@linuxpages.org>
# This program is copyrighted under GPL licence. See COPYING file
# for details.


# We are using strict mode.
use strict;

# Variables defined by user
####
# This is the errorcode which will be used in case you want to use sendmail
# access compatible output.
my $ERRORCODE_DEFAULT = "571";

# This is the message which will be used in case you want to sendmail access
# compatible output.
my $MESSAGE_DEFAULT = "Because of previous SPAM activity from your domain, we reject your mail.";


# You should not change anything under this line unles you know what
# are you doing.
################################################################################


# Main body of the script
####

# Variables
my $parameter_h;
my $parameter_V;
my $parameter_v;
my $parameter_d;
my $parameter_e;
my $parameter_e_value;
my $parameter_m;
my $parameter_m_value;
my @splited_common_ip;
my @splited_common_ip_start;
my $nonsplited_common_ip_start;
my $numeric_ip_start;
my $numeric_ip_end;
my $common_ip_start;
my $common_ip_end;


# Parsing command line parameters.
f_params();


# Converting IP from common notation to numeric notation.
$numeric_ip_start = new NetAddr::IP ($common_ip_start)->numeric ();
$numeric_ip_end = new NetAddr::IP ($common_ip_end)->numeric ();

# First IP in range cannot be smaller then the last IP in the range.
if ($numeric_ip_end < $numeric_ip_start)
   {
   f_help();
   exit (2);
   }


# If output should be verbose, script will prepend "#<range>" to normal output.
if ($parameter_v == 1)
   {
   print "#<$common_ip_start-$common_ip_end>\n"
   }


# This part of code is doing the most important job.
my $counter = $numeric_ip_start;
while ($counter <= $numeric_ip_end)
      {
      $nonsplited_common_ip_start = new NetAddr::IP ($counter)->addr ();
      @splited_common_ip_start = split(/\./, $nonsplited_common_ip_start);
      if ($splited_common_ip_start[1] == 0 && ($numeric_ip_end - $counter) >= 16777215)
         {
         $counter = ($counter+16777215);
         print "$splited_common_ip_start[0]";
         if ($parameter_d == 1)
            {
            if ($parameter_e == 1)
               {
               print " $parameter_e_value";
               }
            else
               {
               print " $ERRORCODE_DEFAULT";
               }
            if ($parameter_m == 1)
               {
               print " $parameter_m_value";
               }
            else
               {
               print " $MESSAGE_DEFAULT";
               }
            }
         print "\n";
         }
      elsif ($splited_common_ip_start[2] == 0 && ($numeric_ip_end - $counter) >= 65535)
            {
            $counter = ($counter+65535);
            print "$splited_common_ip_start[0].$splited_common_ip_start[1]";
            if ($parameter_d == 1)
               {
               if ($parameter_e == 1)
                  {
                  print " $parameter_e_value";
                  }
               else
                  {
                  print " $ERRORCODE_DEFAULT";
                  }
               if ($parameter_m == 1)
                  {
                  print " $parameter_m_value";
                  }
               else
                  {
                  print " $MESSAGE_DEFAULT";
                  }
               }
            print "\n";
            }
      elsif ($splited_common_ip_start[3] == 0 && ($numeric_ip_end - $counter) >= 255)
            {
            $counter = ($counter+255);
            print "$splited_common_ip_start[0].$splited_common_ip_start[1].$splited_common_ip_start[2]";
            if ($parameter_d == 1)
               {
               if ($parameter_e == 1)
                  {
                  print " $parameter_e_value";
                  }
               else
                  {
                  print " $ERRORCODE_DEFAULT";
                  }
               if ($parameter_m == 1)
                  {
                  print " $parameter_m_value";
                  }
               else
                  {
                  print " $MESSAGE_DEFAULT";
                  }
               }
            print "\n";
            }
      else
         {
         print new NetAddr::IP ($counter)->addr ();
         if ($parameter_d == 1)
            {
            if ($parameter_e == 1)
               {
               print " $parameter_e_value";
               }
            else
               {
               print " $ERRORCODE_DEFAULT";
               }
            if ($parameter_m == 1)
               {
               print " $parameter_m_value";
               }
            else
               {
               print " $MESSAGE_DEFAULT";
               }
            }
         print "\n";
         }
      $counter++;
      }


# If output should be verbose, script will append "#</range>" to normal output.
if ($parameter_v == 1)
   {
   print "#</$common_ip_start-$common_ip_end>\n"
   }


# Functions
####

# Help function
sub f_help {
           print STDERR "$0: Perl script for generating records for /etc/mail/access.\n".
                        "Usage: $0 first_ip [-] last_ip [options]\n".
                        "	-d	deny mode (will output line useful for sendmail access file)\n".
                        "	-v	verbose (will prepend and append lines with curent range to\n".
                        "		output). It could only be used with -d option\n".
                        "	-e errorcode	If you don't like default errorcode (571), you can\n".
                        "			change it with this option. It could only be used with\n".
                        "			-d option\n".
                        "	-m message	If you don't like default message, you can change it\n".
                        "			with this option. It could only be used with -d option\n".
                        "	-V	Output version and exit.\n".
                        "	-h	Show this help screen and exit\n".
                        "Examples:\n".
                        "	$0 first_ip - last_ip -d\n".
                        "	$0 first_ip-last_ip -d -v -e 571 -m \"No spam here!\"\n";
           }


# Function for parsing command line parameters
sub f_params {
             my $nparam = $#ARGV;
             my $param_counter = 0;
             while ($param_counter <= $nparam)
                   {
                   if ($ARGV[$param_counter] eq "-h")
                      {
                      $parameter_h = 1;
                      $param_counter++;
                      next;
                      }
                   if ($ARGV[$param_counter] eq "-V")
                      {
                      $parameter_V = 1;
                      $param_counter++;
                      next;
                      }
                   if ($ARGV[$param_counter] eq "-v")
                      {
                      $parameter_v = 1;
                      $param_counter++;
                      next;
                      }
                   if ($ARGV[$param_counter] eq "-d")
                      {
                      $parameter_d = 1;
                      $param_counter++;
                      next;
                      }
                   if ($ARGV[$param_counter] eq "-e")
                      {
                      $parameter_e = 1;
                      if ($ARGV[$param_counter+1] ne "")
                         {
                         $parameter_e_value = $ARGV[++$param_counter];
                         }
                      else
                         {
                         f_help();
                         exit (3);
                         }
                      $param_counter++;
                      next;
                      }
                   if ($ARGV[$param_counter] eq "-m")
                      {
                      $parameter_m = 1;
                      if ($ARGV[$param_counter+1] ne "")
                         {
                         $parameter_m_value = $ARGV[++$param_counter];
                         }
                      else
                         {
                         f_help();
                         exit (4);
                         }
                      $param_counter++;
                      next;
                      }
                   if ($ARGV[$param_counter] =~ /^([0-9]{1,3}\.){3,3}[0-9]{1,3}$/ && $ARGV[$param_counter+1] eq "-" && $ARGV[$param_counter+2] =~ /^([0-9]{1,3}\.){3,3}[0-9]{1,3}$/)
                      {
                      $common_ip_start = $ARGV[$param_counter];
                      $common_ip_end = $ARGV[$param_counter+2];
                      $param_counter = ($param_counter+2);
                      }
                   elsif ($ARGV[$param_counter] =~ /^([0-9]{1,3}\.){3,3}[0-9]{1,3}$/ && $ARGV[$param_counter+1] =~ /^([0-9]{1,3}\.){3,3}[0-9]{1,3}$/)
                         {
                         $common_ip_start = $ARGV[$param_counter];
                         $common_ip_end = $ARGV[$param_counter+1];
                         $param_counter++;
                         }
                   elsif ($ARGV[$param_counter] =~ /^([0-9]{1,3}\.){3,3}[0-9]{1,3}-([0-9]{1,3}\.){3,3}[0-9]{1,3}$/)
                         {
                         @splited_common_ip = split(/-/, $ARGV[$param_counter]);
                         $common_ip_start = @splited_common_ip[0];
                         $common_ip_end = @splited_common_ip[1];
                         }
                   else
                         {
                         f_help();
                         exit (5);
                         }

                   $param_counter++;
                   }

             if ($parameter_h == 1)
                {
                f_help ();
                exit (0);
                }
             if ($parameter_V == 1)
                {
                print STDERR "$0: iprange2access V1.0\tJosip Deanovic <djosip\@linuxpages.org>\n";
                exit (0);
                }
             if ($parameter_d != 1)
                {
                if ($parameter_v == 1)
                   {
                   f_help();
                   exit (6);
                   }
                if ($parameter_e == 1)
                   {
                   f_help();
                   exit (7);
                   }
                if ($parameter_m == 1)
                   {
                   f_help();
                   exit (8);
                   }
                }
             if ($common_ip_start !~ /^([0-9]{1,3}\.){3,3}[0-9]{1,3}$/)
                {
                f_help();
                exit (9);
                }
             if ($common_ip_end !~ /^([0-9]{1,3}\.){3,3}[0-9]{1,3}$/)
                {
                f_help ();
                exit (10);
                }
             }


# Class for converting IP from common notation to numeric and vice versa.
# Class have two objects, "addr" if IP should be converted from numeric to
# common notation and "numeric" if IP should be converted from common to numeric
# notation.
package NetAddr::IP;
sub new {
        my $class = shift;
        my $self = {};
        bless $self;
        if (defined $_[0])
           {
           $self->{'ip'} = shift;
           }
        return $self;
        }

sub addr {
         my $self = shift;

         $splited_common_ip[0] = int($self->{ip}/256/256/256);
         $splited_common_ip[1] = int(($self->{ip}-($splited_common_ip[0]*256*256*256))/256/256);
         $splited_common_ip[2] = int((($self->{ip}-($splited_common_ip[0]*256*256*256))-($splited_common_ip[1]*256*256))/256);
         $splited_common_ip[3] = int((($self->{ip}-($splited_common_ip[0]*256*256*256))-($splited_common_ip[1]*256*256))-($splited_common_ip[2]*256));
         my $converted_ip = "$splited_common_ip[0].$splited_common_ip[1].$splited_common_ip[2].$splited_common_ip[3]";
         return ($converted_ip);
         }

sub numeric {
            my $self = shift;

            @splited_common_ip = split(/\./, $self->{ip});
            my $converted_ip = ((@splited_common_ip[0] * 16777216) + (@splited_common_ip[1] * 65536) + (@splited_common_ip[2] * 256) + @splited_common_ip[3]);
            return ($converted_ip);
            }

