#!/usr/local/bin/perl -- -*-Perl-*-
#
# $Id$
# $Source$
# Paul Traina (Feburary 1994)
#
# Common data and subrouines to help in generating network access
# control lists.
#
#--------------------------------------------------------------------

#
# All cisco networks (whether advertized or not).
#
# This list is used to generate "network" statements and ACL entries.
# It absolutely MUST be kept up to date.
#
@cisco_networks = (
        "131.108.0.0",
	"160.90.0.0"
);

@cisco_insecure_networks = (
	"131.108.85.0 0.0.0.255"
);

@anyone = ( "0.0.0.0 255.255.255.255",);

%protocols = (
	"igmp",  2,			# internet gateway management protocol
	"ipip",  4,			# IP over IP (multicast encaps)
	"gre",  47,			# GRE multiprotocol over IP tunneling
	"eon",  80,			# EON CLNP over IP tunneling
	"rsrb", 90,			# FST RSRB
	"nos",  94,			# NOS IP over IP tunneling
);

%ports = (
	"ftp-data",		"eq 20",
	"ftp-cmd",		"eq 21",
	"telnet",		"eq 23",
	"smtp",			"eq 25",
	"tacacs",		"eq 49",
	"dns",			"eq 53",
	"tftp",			"eq 69",
	"finger",		"eq 79",
	"pop2",			"eq 109",
	"pop3",			"eq 110",
	"sunrpc",		"eq 111",
	"nntp",			"eq 119",
	"ntp",			"eq 123",
	"NeWS",			"eq 144",
	"snmp",			"eq 161",
	"snmp-trap",		"eq 162",
	"bgp",			"eq 179",
	"aurp",			"eq 387",
	"rexec",		"eq 512",
	"rlogin",		"eq 513",
	"rsh",			"eq 514",
	"talk",			"eq 517",
	"ntalk",		"eq 518",
	"klogin",		"eq 543",	# tcp (kerberos)
	"kshell",		"eq 544",	# tcp (kerberos)
	"kerberos",		"eq 750",	# tcp and udp (kerberos)
	"kerberos_master",	"eq 751",	# tcp and udp (kerberos)
	"passwd_server",	"eq 752",	# udp (kerberos)
	"userreg_server",	"eq 753",	# udp (kerberos)
	"krb_prop",		"eq 754",	# tcp (kerberos)
	"erlogin",		"eq 888",	# tcp (kerberos)
	"kpop",			"eq 1109",	# tcp (kerberos)
	"knetd",		"eq 2053",	# tcp (kerberos)
	"openwin",		"eq 2000",	# actually 2000-2015
	"openwin:1",		"eq 2001",
	"openwin:2",		"eq 2002",
	"nfs",			"eq 2049",	# rpc service but usually fixed
	"x11",			"eq 6000",	# acutally 6000-6015
	"x11:1",		"eq 6001",
	"x11:2",		"eq 6002",
);

########################################################################
#####
#####	Subroutines
#####
########################################################################

#
# header_prelude (public)
#
# print record keeping verbage
#

sub header_prelude {
     local($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
	localtime(time);
     local($today) = sprintf("%d-%-2.2d-%-2.2d %-2.2d:%-2.2d",
			     1900 + $year, $mon+1, $mday, $min, $hour);
     local($user) = $ENV{'USER'};

     print "! this file is automaticly generated by $0\n";
     print "! do not edit by hand\n";
     print "! generated $today by $user\n";
     print "!\n";
}

#
# start_list (public)
#
# do housekeeping necessary at the start of list generation
#

sub start_list {
    $_ = @_[0];

    $_alnum = $_;
    print "no access-list $_alnum\n";
}

#
# entry (public)
#
# create an extended access list entry (or entries) based upon
# passed parameters
#

sub entry {
    local($grant, $proto, $mod, @nets) = @_;
    local($net, @sources, @dests);
    local($dodest) = 0;

    $proto = $protocols{$proto} unless $protocols{$proto} eq "";
    $mod = $ports{$mod} unless $ports{$mod} eq "";

    foreach $net (@nets) {
	if ($net eq "*") {
	    $dodest++;
	    next;
	}
	if ($dodest > 0) {
	    push(@dests, $net);
	} else {
	    push(@sources, $net);
	}
    }

    foreach $source_id (@sources) {
	foreach $source (&_mung_addr($source_id)) {
	    foreach $dest_id (@dests) {
		foreach $dest (&_mung_addr($dest_id)) {
		    print "access-list $_alnum $grant $proto $source $dest $mod\n";
		}
	    }
	}
    }
}

#
# fast_entry (public)
#
# Create a fast access list entry (or entries)
#

sub fast_entry {
    local($grant, @nets) = @_;
    local($net);

    foreach $net_id (@nets) {
	foreach $net (&_mung_addr($net_id)) {
	    print "access-list $_alnum $grant $net\n";
	}
    }
}

########################################################################
#####
#####	Private subroutines
#####
########################################################################

#
# _mung_addr (private)
#
# convert a text entry into a group of dotted decimal addresses
#
# Addresses can be of the form:
#  net mask
#  hostname
#  host address
#
#
sub _mung_addr {
    local (@retval);
    $_ = @_[0];

    # if we have whitespace, it must be a network & mask
    if (/\s+/) {
	s/\s+/ /;

	@retval[0] = $_;

    } elsif (/^\d+\.\d+.\d+.\d+$/) {
	local ($a, $b, $c, $d ) = split(/\./);
	if ($d != 0) {		# if it's a host
	    $mask = " 0.0.0.0";
	} elsif ($a < 128) {	# class A net
	    $mask = " 0.255.255.255";
	} elsif ($a < 192) {	# class B net
	    $mask = " 0.0.255.255";
	} elsif ($a < 224) {	# class C net
	    $mask = " 0.0.0.255";
	} else {
	    die "Invalid address: $_";
	}
		
	@retval[0] = $_ . $mask;

    } else {
	local ($name, $aliases, $type, $len, @addrs) = gethostbyname($_);
	local ($a, $b, $c, $d);
	local ($addr);

	if ($#addrs < 0) {
	    print STDERR "ERROR: cannot resolve hostname $_\n";
	}

	foreach $addr (@addrs) {
	   ($a, $b, $c, $d) = unpack('C4', $addr);
	   push(retval, "$a.$b.$c.$d 0.0.0.0");
	}
    }
    @retval;
}

# -------------------------------------------------------------------------
# $Log$
#
# -------------------------------------------------------------------------
