#!/usr/bin/perl
#
# genmask : Generate NETMASK and NETWORK from IPADDR
# Author: Shun-ichi TAHARA <jado@flowernet.gr.jp>
# Time-stamp: <04/10/14 10:55:41 jado@sheira>
#
# Copyright (c) 2001 Shun-ichi TAHARA
#
# This program 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 of the License, or
# (at your option) any later version.
#

					$genmask = $0; $genmask =~ s|^.*/||;
					$USAGE = <<END
Usage: $genmask [-b{1|0|-}] IPADDR/MASK
  IPADDR: Valid IPv4 address of the interface.
    MASK: Bit length of the network address;
          0 for P2P connection (without route to the local network).
     -bn: Broadcast address with the host address bits n (default 1).
     -b-: Without broadcast address.
END
					;

sub usage
{
    print STDERR $USAGE;
    exit 1;
}

sub err
{
    local($msg) = @_;

    print STDERR $genmask . ": " . $msg . ".\n";
    exit 1;
}

$bcbit = 1;

$i = 0;
if(@ARGV > $i) {
    $_ = $ARGV[$i];
    if(/-b([10-])/) {
	$bcbit = ($1 eq '-') ? -1 : $1;
	$i++;
    }
}
&usage unless $#ARGV == $i;
$_ = $ARGV[$i];

&usage unless m|^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/([0-9]+)$|;

@addrs = ($1, $2, $3, $4);
&chkaddrs(@addrs);

$mask = $5;
&chkmask($mask);
@masks = &mkmasks($mask);

$iaddr = &mkaddr(@addrs);
$nmask = &mkaddr(@masks);
if($mask != 0) {
    $naddr = &mknaddr(@addrs, @masks);
    &chkiaddr($iaddr, $naddr);
    if($bcbit != -1) {
	$bcast = &mkbcast(@addrs, @masks, $bcbit);
	&chkiaddr($iaddr, $bcast);
    }
}

print   "IPADDR=" . $iaddr . "; NETMASK=" . $nmask;
if($mask != 0) {
    print "; NETWORK=" . $naddr;
    if($bcbit != -1) {
	print "; BROADCAST=" . $bcast;
    }
}
print "\n";

exit 0;

sub chkaddrs
{
    local(@addrs[0..3]) = @_;
    local($i);

    $_ = $addrs[0];
    # 224-.*.*.* is multicast or reserved.
    goto errend if($_ >= 224);
    for($i = 1; $i < 4; $i++) {
	$_ = $addrs[$i];
	goto errend if($_ > 255);
    }
    return 0;

  errend:
    err("Illegal ip address: " . &mkaddr(@addrs));
}

sub chkmask
{
    local($mask) = @_;

    err("Illegal mask: " . $mask) unless $mask <= 31;
}

sub chkiaddr
{
    local($iaddr, $nonvalid) = @_;

    err("Non-valid ip address: " . $iaddr) if $iaddr eq $nonvalid;
}

sub mkaddr
{
    local(@addrs[0..3]) = @_;

    $addrs[0] . '.' . $addrs[1] . '.' . $addrs[2] . '.' . $addrs[3];
}

sub mkmasks
{
    local($mask) = @_;
    local($i, @masks[0..3]);

    for($i = 0; $i < 4; $i++) {
	$masks[$i] = &mkpartmask($mask, $i);
    }
    return @masks;
}

sub mkpartmask
{
    local($mask, $part) = @_;
    local($div, $mod) = (int $mask / 8, $mask % 8);

    return 0x00 if $part > $div;
    return 0xff if $part < $div;
    return 0x100 - (1 << (8 - $mod));
}

sub mknaddr
{
    local(@addrs[0..3], @masks[0..3]) = @_;
    local($i, @naddrs[0..3]);

    for($i = 0; $i < 4; $i++) {
	$naddrs[$i] = $addrs[$i] & $masks[$i];
    }
    return &mkaddr(@naddrs);
}

sub mkbcast
{
    local(@addrs[0..3], @masks[0..3], $bcbit) = @_;
    local($i, @bcasts[0..3]);

    for($i = 0; $i < 4; $i++) {
	$bcasts[$i] = $addrs[$i] & $masks[$i];
	$bcasts[$i] |= (($masks[$i] ^ 0xff) * $bcbit);
    }
    return &mkaddr(@bcasts);
}
