# Network/range syntax and semantics handling.
#
# Copyright (C) 1999 Ian Jackson <ijackson@chiark.greenend.org.uk>
#
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2,
# or (at your option) any later version.
#
# This is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this file; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

sub parse_netrange ($) {
    my ($net) = @_;
    my ($prefix,$network,@b,$b,$val,$mask);

    length $net or finish_error('nonet');
print DEBUG "got $net\n";
    $net =~ s,/(\d+)$,, or finish_error("badnet");
print DEBUG "prefix $1\n";
    $prefix= $1+0;  ($prefix >= 0 && $prefix <= 32) or finish_error("badnet");
print DEBUG "prefix $1 $net\n";
    $network= ''; @b= split(/\./,$net);
    @b<=4 or finish_error("badnet");
print DEBUG "big enough\n";
    @b*8 >= $prefix or finish_error("badnet");
    while (@b<4) { push @b,0; }
print DEBUG "@b\n";
    foreach $b (@b) {
	$b>=0 && $b<=255 or finish_error("badnet");
	$network .= sprintf("%02x",$b);
    }
    ($val,$mask) = net_valuemask($network,$prefix);
printf DEBUG "%08x %08x %08x\n", $val,$mask,~$mask;
    !($val & ~$mask) or finish_error("badnet");
print DEBUG "ok\n";
    return ($network,$prefix,$val,$mask);
}

sub net_subset ($$$$) {
    my ($smln,$smlp, $bign,$bigp) = @_;
    return 0 unless $smlp >= $bigp;
    ($bigv,$bigm) = net_valuemask($bign,$bigp);
    ($smlv,$smlm) = net_valuemask($bign,$bigp);
    return 0 unless ($smlv & $bigm) == $bigv;
    return 1;
}

sub net_overlap ($$$$) {
    my ($an,$ap, $bn,$bp) = @_;
    my ($av,$am,$bv,$bm, $tm,$r);
    ($av,$am) = net_valuemask($an,$ap);
    ($bv,$bm) = net_valuemask($bn,$bp);
    $tm= $am & $bm;
    $r= (($av & $tm) == ($bv & $tm)) ? 1 : 0;
printf DEBUG "overlap %s/%s %s/%s %d\n", $an,$ap, $bn,$bp, $r;
    return $r;
}    

sub get_mask ($) {
    my ($prefix) = @_;
    my ($m, $sh);
    $m= 0xffffffff;
    $sh= 32-$prefix;
    $sh2= 0;
    if ($sh>=16) { $sh2 += 16; $sh -= 16; }
    $m <<= $sh;
    $m <<= $sh2;
    return $m;
};

sub net_valuemask ($$) {
    my ($network,$prefix) = @_;
    return (hex($network), get_mask($prefix));
}

sub display_net ($$) {
    my ($network,$prefix) = @_;
    return join('.', unpack("C4",pack("H8",$network)))."/".$prefix;
}

1;
