<?php
## this file name is 'class.network.tcpwrap.php'
##
## simple check ipaddress math of tcpwrapper /etc/hosts.allow or /etc/hosts.deny
## such as PECL/tcpwrap
##
## - support php4.2.x(J5K/admin UI), php5.x
##
## - san2@2009.06.26: support case-insensitive in daemon_list
## - san2@2009.06.23: daemon match bug fixed
## - san2@2009.06.22: new build
##
## - example
##   tcpwrap::match(NULL,$_SERVER['REMOTE_ADDR']);
##   or
##   tcpwrap::match('sshd',$_SERVER['REMOTE_ADDR']);
##
## - return value
##    0: no match, FALSE
##    1: match, TRUE
##

class tcpwrap
{
  
## public, check to allow
  ##
  
function &match($daemon$client)
  {
    
$denyrule tcpwrap::_match('/etc/hosts.deny',$daemon,$client);

    if(!
$denyrule || $denyrule=='allow') return TRUE;

    
$allowrule tcpwrap::_match('/etc/hosts.allow',$daemon,$client);

    return (
$allowrule=='allow') ? TRUE FALSE;
  }

  
## private, core
  ## hosts_access(5)  daemon_list : client_list [ : shell_command ]
  ## hosts_options(5) daemon_list : client_list : option : option ...
  ##
  
function &_match($file$daemon$client)
  {
    if(!
file_exists($file)) return -1;
    if(!
$fp fopen($file,'r')) return -1;

    
$baserule preg_match('/\.allow$/',$file) ? 'allow' 'deny';
    
$daemon strtoupper(trim($daemon)); // rewrite
    
$client trim($client); // rewrite

    
while($line fgets($fp,1024))
    {
        list(
$line) = explode('#',trim($line));
        if(!
$line trim($line)) continue;
        if(
preg_match('/(.+)\\\$/',$line,$m))
        {
            
$pline .= $m[1].' ';
            continue;
        }

        
$tmp explode(':',$pline.$line);
        
$size sizeof($tmp);
        
$dlists trim($tmp[0]);
        
$clists trim($tmp[1]);

        
## match rlue
        
if($size 2)
        {
            
$rule strtolower(trim($tmp[$size-1]));
            
$rule preg_match("/^(allow|deny)$/",$rule) ? $rule $baserule;
        }
        else 
$rule $baserule;

        
## check daemon list
        ##
        
if($daemon && $daemon!='ALL')
        {
            list(
$dmatch,$dexcept) = tcpwrap::__get_matchlist(strtoupper($dlists));
            if(
$dexcept && in_array($daemon,$dexcept)) continue;
            if(!
in_array('ALL',$dmatch) && !in_array($daemon,$dmatch)) continue;
        }

        list(
$match,$except) = tcpwrap::__get_matchlist($clists);
        if(
$except && tcpwrap::__ipmatch($client,$except)) continue;
        if(
tcpwrap::__ipmatch($client,$match))
        {
            
$r $rule;
            break;
        }

        
$pline '';
    }
    @
fclose($fp);

    return 
$r $r FALSE;
  }

  
## private, get daemon list
  ##
  
function &__get_matchlist($str)
  {
    
$rr $ee = array();
    
$arr explode(',',preg_replace('/[\s]+/',' ',$str));
    foreach(
$arr AS $v)
    {
        list(
$u,$e) = explode('EXCEPT',trim($v));
        
$rr array_merge($rrexplode(' ',trim($u)));
        if(
$e$ee array_merge($eeexplode(' ',trim($e)));
    }

    return array(
$rr,$ee);
  }

  function &
__ipmatch($ip$arr)
  {
    if(!
is_array($arr)) $arr = array($arr);
    if(
in_array($ip,$arr)) return TRUE;

    
$ipbit tcpwrap::inet_atob($ip);
    foreach(
$arr AS $v)
    {
        if(
$v == 'ALL')
        {
            return 
TRUE;
            break;
        }
        else if(
preg_match(';/;',$v)) // network/netmask
        
{
            list(
$net,$mask) = explode('/',$v);
            
$mbit tcpwrap::inet_atob($mask);
            
$unet = ($ipbit $mbit);
            
$unet tcpwrap::inet_btoa("$unet"); // required double quota "
            
if($unet == $net)
            {
                return 
TRUE;
                break;
            }
        }
        else if(
preg_match(';\.$;',$v))
        {
            if(
preg_match("/^$v/",$ip)) // $v = str_replace('.','\.',$v);
            
{
                return 
TRUE;
                break;
            }
        }
    }

    return; 
// false
  
}

  
## check /etc/hosts hosts
  ## such as getent
  ##
  
function &__getent_hosts($ipaddr)
  {
    return;
  }

  function &
inet_atob($ipaddr)
  {
    return 
sprintf('%032b',ip2long($ipaddr));
  }

  function &
inet_btoa($bits)
  {
    return 
long2ip(bindec("$bits"));
  }
// eof clss
## EOF
?>