cidrexpand revision 266692
1178580Simp#!/usr/bin/perl -w
2178580Simp
3178580Simp# $Id: cidrexpand,v 8.8 2006-08-07 17:18:37 ca Exp $
4178580Simp#
5178580Simp# v 0.4
6178580Simp#
7178580Simp# 17 July 2000 Derek J. Balling (dredd@megacity.org)
8178580Simp# 
9178580Simp# Acts as a preparser on /etc/mail/access_db to allow you to use address/bit
10178580Simp# notation. 
11178580Simp#
12178580Simp# If you have two overlapping CIDR blocks with conflicting actions
13178580Simp# e.g.   10.2.3.128/25 REJECT and 10.2.3.143 ACCEPT
14178580Simp# make sure that the exceptions to the more general block are specified
15178580Simp# later in the access_db.
16178580Simp#
17178580Simp# the -r flag to makemap will make it "do the right thing"
18178580Simp#
19178580Simp# Modifications
20178580Simp# -------------
21178580Simp# 26 Jul 2001 Derek Balling (dredd@megacity.org)
22178580Simp#     Now uses Net::CIDR because it makes life a lot easier.
23178580Simp#
24178580Simp#  5 Nov 2002 Richard Rognlie (richard@sendmail.com)
25178580Simp#     Added code to deal with the prefix tags that may now be included in
26178580Simp#     the access_db
27178580Simp#
28178580Simp#     Added clarification in the notes for what to do if you have 
29178580Simp#     exceptions to a larger CIDR block.
30178580Simp#
31178580Simp#  26 Jul 2006 Richard Rognlie (richard@sendmail.com>
32178580Simp#     Added code to strip "comments" (anything after a non-escaped #)
33178580Simp#     # characters after a \ or within quotes (single and double) are
34178580Simp#     left intact. 
35178580Simp#
36178580Simp#     e.g.
37178580Simp#	From:1.2.3.4	550 Die spammer # spammed us 2006.07.26
38178580Simp#     becomes
39178580Simp#	From:1.2.3.4	550 Die spammer 
40178580Simp#
41178580Simp#  3 August 2006
42178580Simp#
43178580Simp#     Corrected a bug to have it handle the special case of "0.0.0.0/0"
44178580Simp#     since Net::CIDR doesn't handle it properly.
45178580Simp#
46178580Simp# usage: 
47178580Simp#  cidrexpand < /etc/mail/access | makemap -r hash /etc/mail/access
48178580Simp#
49178580Simp#
50178580Simp# Report bugs to: <dredd@megacity.org>
51178580Simp#
52178580Simp
53178580Simp
54178580Simpuse strict;
55178580Simpuse Net::CIDR;
56178580Simpuse Getopt::Std;
57
58our ($opt_c,$opt_t);
59getopts('ct:');
60
61my $spaceregex = '\s+';
62if ($opt_t)
63{
64    $spaceregex = $opt_t;
65}
66
67while (<>)
68{
69    chomp;
70    my ($prefix,$left,$right,$space);
71
72    if ( (/\#/) && $opt_c )
73    {
74	# print "checking...\n";
75	my $i;
76	my $qtype='';
77	for ($i=0 ; $i<length($_) ; $i++) 
78	{
79	    my $ch = substr($_,$i,1);
80	    if ($ch eq '\\') 
81	    {
82		$i++;
83		next;
84	    }
85	    elsif ($qtype eq '' && $ch eq '#') 
86	    {
87		substr($_,$i) = '';
88		last;
89	    }
90	    elsif ($qtype ne '' && $ch eq $qtype) 
91	    {
92		$qtype = '';
93	    }
94	    elsif ($qtype eq '' && $ch =~ /[\'\"]/) 
95	    {
96		$qtype = $ch;
97	    }
98	}
99    } 
100    
101    if (! /^(|\S\S*:)(\d+\.){3}\d+\/\d\d?$spaceregex.*/ )
102    {
103	print "$_\n";
104    }
105    else
106    {
107	($prefix,$left,$space,$right) = 
108	    /^(|\S\S*:)((?:\d+\.){3}\d+\/\d\d?)($spaceregex)(.*)$/;
109	
110	my @new_lefts = expand_network($left);
111	foreach my $nl (@new_lefts)
112	{
113	    print "$prefix$nl$space$right\n";
114	}
115    }
116}
117    
118sub expand_network
119{
120    my $left_input = shift;
121    my @rc = ($left_input);
122    my ($network,$mask) = split /\//, $left_input;
123    if (defined $mask)
124    {
125	return (0..255)	if $mask == 0;
126
127	my @parts = split /\./, $network;
128	while ($#parts < 3)
129	{
130	    push @parts, "0";
131	}
132	my $clean_input = join '.', @parts;
133	$clean_input .= "/$mask";
134	my @octets = Net::CIDR::cidr2octets($clean_input);
135	@rc = @octets;
136    }
137    return @rc;
138}
139