#!/usr/bin/perl

# Copyright (C) 2000-2004 NEC Corporation
# All Rights Reserved.

# RCS: $Id: ipchconf,v 1.2 2004/09/19 13:19:10 snavi Exp $

##20001009 4.1 RPMへ追加
##001116 v5.1 ipchains,ip_forward対応(wbmc03-046) haramoto
##040919 v6.0.1 iptables に変更 oyama

require "/opt/nec/wbmc/lib/wbmc.pl";

chdir("/opt/nec/wbmc/adm/system/security");
require "./ipchconf.pl";
&readIpchConfFile($M_SECFN_IPCHAINS_CUR_CONF);
&readFltSrvFile();
chdir("../../bin");

# logging option
$alog = "";
$dlog = "";

# ZZZ for debug
if ($ARGV[0] eq "-d") {
    $alog = "-l";
    $dlog = "-l";
}

@ipchopt = ();
&clearAll();
&denyAll("on");
&setForward();
&setInput();
&denyAll("off");

#&writeIpForward();		##001116
&callIpch();

########################################################################

#
# clearAll()
#

sub clearAll {
    push(@ipchopt, "-P INPUT ACCEPT");
    push(@ipchopt, "-P OUTPUT ACCEPT");
    push(@ipchopt, "-P FORWARD ACCEPT");

    push(@ipchopt, "-F");
    push(@ipchopt, "-X");

    return ;
}

#
# denyAll($flag)
#     $flag  (i) : "on" add all INPUT deny / "off" remove all INPUT deny
#

sub denyAll {
    my($flag) = @_;

    if ($flag eq "on") {
        push(@ipchopt, "-A INPUT -i ! lo -j DROP");
    } else {
        push(@ipchopt, "-D INPUT -i ! lo -j DROP");
    }
}

#
# setForward()
#

sub setForward {
    my($i);

    if ($g_secfw eq $M_SECFW_OFF) {
        return ;
    }

    for ($i = 0; $i < $g_secifcnt; $i++) {
        if ($g_secif[$i]->{MASQ} eq $M_SECIF_MASQ_ON) {
            push(@ipchopt, "-A forward -i $g_secif[$i]->{NAME} -j MASQ");
        }
    }

    return ;
}

#
# setInput()
#

sub setInput {
    my($i, $if, $chain, @chainlist);

    @chainlist = ();

    for ($i = 0; $i < $g_secifcnt; $i++) {
        if ($g_secif[$i]->{FILTERING} eq $M_SECIF_FLT_OFF) {
            next;
        }

        $if = $g_secif[$i]->{NAME};
        $chain = $if . "_in";
        push(@ipchopt, "-N $chain");
        &setIfInput($g_secif[$i]->{FILTER}, $chain); 
        push(@ipchopt, "-A INPUT -i $if -j $chain");
        push(@chainlist, $chain);
    }

    if (@chainlist) {
        push(@ipchopt, "-N default");
        &createDefaultInput("default");
        foreach (@chainlist) {
            push(@ipchopt, "-A $_ -j default");
        }
    }

    return ;
}

#
# createDefaultInput
#

sub createDefaultInput {
    my($chain) = @_;
    my(@type);

    @type = ("echo-reply", "destination-unreachable","source-quench",
             "redirect","router-advertisement","time-exceeded",
             "parameter-problem", "timestamp-reply", "address-mask-reply");

    push(@ipchopt, "-A $chain -m state --state ESTABLISHED,RELATED -j ACCEPT $alog");
    foreach (@type) {
        push(@ipchopt, "-A $chain -p icmp --icmp-type $_ -j ACCEPT $alog");
    }

    push(@ipchopt, "-A $chain -p udp -j DROP $dlog");
    push(@ipchopt, "-A $chain -p icmp -j DROP $dlog");

    return ;
}

#
# setIfInput($filter, $chain)
#     $filter :  filter name (eg. "1,2,3")
#     $chain  :  chain name  (eg. "eth0_in")
# 

sub setIfInput {
    my($filter, $chain) = @_;
    my($i, $buf);
    local(@protocol, @dstport, @srcaddr);
    @protocol = ();
    @dstport = ();
    @srcaddr = ();

    &getIfRuleList($filter, *protocol, *dstport, *srcaddr);

    for ($i = 0; $i <= $#protocol; $i++) {
        $buf = "";
        if ($protocol[$i] ne "") {
            $buf .= " -p $protocol[$i]";
        }
        if ($dstport[$i] ne "") {
            if ($protocol[$i] eq "icmp") {
                $buf .= " --icmp-type $dstport[$i]";
            } else {
                $buf .= " --dport $dstport[$i]";
            } 
        }
        if ($srcaddr[$i] ne "") {
            $buf .= " -s $srcaddr[$i]";
        }
        push(@ipchopt, "-A $chain $buf -j ACCEPT $alog");
    }

    return ;
}

#
# getIfRuleList($filter, *protocol, *dstport, *srcaddr)
#     $filter  (i) : filter string (eg. "1,2,3")
#     @protocol(o) : protocol list
#     @dstport (o) : dstport list
#     @srcaddr (o) : srcaddr list
#

sub getIfRuleList {
    local($filter, *protocol, *dstport, *srcaddr) = @_;
    my($i, $idx, $j, $addr, $portstr, $num);

    if ($filter eq $M_SECIF_FLT_NONE) {
        return ;
    }

    @fltent = split(/,/, $filter);

    for ($i = 0; $i <= $#fltent; $i++) {
        $idx = &searchIpchConfDataFlt($fltent[$i]);
        if ($idx == -1 ) {
            next;
        }
        if ($g_secflt[$idx]->{SRCADDR} eq $M_SECFLT_SRCADDR_ALL) {
            $addr = "";
        } else {
            $addr = $g_secflt[$idx]->{SRCADDR};
        }
        $portstr = &makeCompletePort($g_secflt[$idx]->{DSTPORT});
        $num = &getPortList($portstr, *protocol, *dstport);
        for ($j = 0; $j < $num; $j++) {
            push(@srcaddr, $addr);
        }
    }

    return ;
}

# 
# makeCompletePort  (make uncomplete port strings to complete port strings)
# makeCompletePort($port)
#   $port     port strings (eg. "http icmp/8 udp/137,138 udp/100-200 ...")
# return      port strings (eg. "tcp/80 icmp/8 udp/137,138 udp/100-200 ...")
#
sub makeCompletePort {
    my($port) = @_;
    my(@ent);
    my($i, $idx, $ret);

    if ($port eq $M_SECFLT_DSTPORT_ALL) {
        return ("");
    }

    $ret = "";
    @ent = split(/\s+/, $port);

    for ($i = 0; $i <= $#ent; $i++) {
        if ($ent[$i] =~ /([^\/]+)\/(.+)$/) {
            $ret .= " $ent[$i]";
        } else {
            $idx = &searchFltSrvData($ent[$i]);
            if ($idx != -1) {
                $ret .= " $g_secsrv[$idx]->{'PORT'}";
            } else {
                next;
            }
        }
    }

    $ret =~ s/^\s//;

    return ($ret);
}

# 
# getPortList  (make uncomplete port strings to complete protocol & port list)
# getPortList($port, *protolist, *portlist)
#   $port       port strings (eg. "tcp/80 icmp/8 udp/137,138 udp/100-200 ...")
#   @protolist  protocol list
#   @portlist   port list
# return     num
#
sub getPortList
{
    local($port, *protolist, *portlist) = @_;
    my($num);

    if ($port eq "") {
        push(@protolist, "");
        push(@portlist, "");
        return (1);
    }

    $num = 0;

    @ent = split(/\s+/, $port);

    for ($i = 0; $i <= $#ent; $i++) {
        $buf = $ent[$i];
        $buf =~ /([^\/]+)\/(.+)$/;
	$protocol = $1;
	$portbuf = $2;
        @ent1 = split(/,/, $portbuf);
        for ($j = 0; $j <= $#ent1; $j++) {
            push(@protolist, $protocol);
            push(@portlist, $ent1[$j]);
            $num++;
        }
    }

    return ($num);
}

#
# writeIpForward()
#

sub writeIpForward {
    my($value);

    if ($g_secfw eq $M_SECFW_OFF) {
        $value = "0" ;
    } else {
        $value = "1" ;
    }

    system("/bin/echo $value > /proc/sys/net/ipv4/ip_forward");

    return;
}

#
# callIpch()
#

sub callIpch {

    foreach (@ipchopt) {
        system ("/sbin/iptables $_");
    }

    return ;
}
