237 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			237 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
<?php
 | 
						|
/*
 | 
						|
  ----------------------------------------------------------------------
 | 
						|
  AlternC - Web Hosting System
 | 
						|
  Copyright (C) 2000-2012 by the AlternC Development Team.
 | 
						|
  https://alternc.org/
 | 
						|
  ----------------------------------------------------------------------
 | 
						|
  LICENSE
 | 
						|
  
 | 
						|
  This program is free software; you can redistribute it and/or
 | 
						|
  modify it under the terms of the GNU General Public License (GPL)
 | 
						|
  as published by the Free Software Foundation; either version 2
 | 
						|
  of the License, or (at your option) any later version.
 | 
						|
  
 | 
						|
  This program 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.
 | 
						|
  
 | 
						|
  To read the license please visit http://www.gnu.org/copyleft/gpl.html
 | 
						|
  ----------------------------------------------------------------------
 | 
						|
  Purpose of file: Manage UPnP ports forwarding from router
 | 
						|
  ----------------------------------------------------------------------
 | 
						|
*/
 | 
						|
 | 
						|
/**
 | 
						|
* This class handle UPnP forwarding from a IGD/UPnP compliant router
 | 
						|
* you need this only when you are behind a IGD-compliant router
 | 
						|
* each class may exports a hook that defined named port/protocol to
 | 
						|
* forward to the local IP address of the server.
 | 
						|
* this class manage the upnp table 
 | 
						|
* and its configuration from admin control panel
 | 
						|
*/
 | 
						|
class m_upnp {
 | 
						|
 | 
						|
 | 
						|
  /* ----------------------------------------------------------------- */
 | 
						|
  /** get the list of current upnp forwards and their status
 | 
						|
   * @return array the attributes of all port-forwards
 | 
						|
   */
 | 
						|
  function get_forward_list() {
 | 
						|
    global $db,$err;
 | 
						|
    $err->log("upnp","get_forward_list");
 | 
						|
    $db->query("SELECT * FROM upnp");
 | 
						|
    $res=array();
 | 
						|
    while ($db->next_record()) {
 | 
						|
      $res[]=$db->Record;
 | 
						|
    }
 | 
						|
    return $res;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /* ----------------------------------------------------------------- */
 | 
						|
  /** enable a upnp port in the upnp table
 | 
						|
   * @param integer the id of the port to enable
 | 
						|
   * @return boolean TRUE if the port has been properly forwarded
 | 
						|
   * FALSE if an error occurred
 | 
						|
   */
 | 
						|
  function enable_port($id) {
 | 
						|
    global $db,$err;
 | 
						|
    $id=intval($id);
 | 
						|
    $err->log("upnp","enable_port($id)");
 | 
						|
    $db->query("SELECT enabled FROM upnp WHERE id=$id;");
 | 
						|
    if (!$db->next_record()) {
 | 
						|
      $err->raise("upnp",_("The required port is not currently defined"));
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    if (!$db->f("enabled")) {
 | 
						|
      $db->query("UPDATE upnp SET enabled=1 WHERE id=$id;");
 | 
						|
      $err->raise("upnp",_("The specified upnp port is now enabled"));
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    $err->raise("upnp",_("The specified upnp port is already enabled"));
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /* ----------------------------------------------------------------- */
 | 
						|
  /** disable a upnp port in the upnp table
 | 
						|
   * @param integer the id of the port to disable
 | 
						|
   * @return boolean TRUE if the port has been properly forwarded
 | 
						|
   * FALSE if an error occurred
 | 
						|
   */
 | 
						|
  function disable_port($id) {
 | 
						|
    global $db,$err;
 | 
						|
    $id=intval($id);
 | 
						|
    $err->log("upnp","disable_port($id)");
 | 
						|
    $db->query("SELECT enabled,mandatory FROM upnp WHERE id=$id;");
 | 
						|
    if (!$db->next_record()) {
 | 
						|
      $err->raise("upnp",_("The required port is not currently defined"));
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    if ($db->f("mandatory")) {
 | 
						|
      $err->raise("upnp",_("You can't disable that mandatory port forward"));
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    if ($db->f("enabled")) {
 | 
						|
      $db->query("UPDATE upnp SET enabled=0 WHERE id=$id;");
 | 
						|
      $err->raise("upnp",_("The specified upnp port is now disabled"));
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    $err->raise("upnp",_("The specified upnp port is already disabled"));
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /* ----------------------------------------------------------------- */
 | 
						|
  /** cron launched every minute to check the status of UPnP forwarding
 | 
						|
   */
 | 
						|
  function cron() {
 | 
						|
    global $hooks,$L_INTERNAL_IP,$PUBLIC_IP;
 | 
						|
    // if we check anything less than 5 minutes ago, or if the upnp table is empty, let's make a check...
 | 
						|
    $db->query("SELECT UNIX_TIMESTAMP(lastcheck) AS lc, * FROM upnp ORDER BY lastcheck ASC;");
 | 
						|
    $forwards=array();
 | 
						|
    $bigcheck=false;
 | 
						|
    if (!$db->next_record()) {
 | 
						|
      $bigcheck=true;
 | 
						|
    } else {
 | 
						|
      if ($db->f("lc")+600<time()) { 
 | 
						|
	$bigcheck=true;
 | 
						|
      }
 | 
						|
      do {
 | 
						|
	$db->Record["found"]=false;
 | 
						|
	$forwards[]=$db->Record;
 | 
						|
      } while ($db->next_record());
 | 
						|
    }
 | 
						|
    
 | 
						|
    if ($bigcheck) {
 | 
						|
      // Do the check first by calling the hooks & comparing the arrays
 | 
						|
      $res=$hooks->invoke("hooks_upnp_list");
 | 
						|
      foreach($res as $c=>$tmp) {
 | 
						|
	if (is_array($tmp) && count($tmp)) {
 | 
						|
	  foreach($tmp as $name=>$v) {
 | 
						|
	    
 | 
						|
	    // We compare the hook array with the forwards array
 | 
						|
	    $found=false;
 | 
						|
	    for($i=0;$i<count($forwards);$i++) {
 | 
						|
	      if ($forwards[$i]["class"]==$c && 
 | 
						|
		  $forwards[$i]["name"]==$name && 
 | 
						|
		  $forwards[$i]["protocol"]==$v["protocol"] && 
 | 
						|
		  $forwards[$i]["port"]==$v["port"] && 
 | 
						|
		  $forwards[$i]["mandatory"]==$v["mandatory"]) {
 | 
						|
		// Found it and unchanged
 | 
						|
		$forwards[$i]["found"]=true;
 | 
						|
		$found=true;
 | 
						|
	      }
 | 
						|
	    } // compare with forwards class.
 | 
						|
	    if (!$found) {
 | 
						|
	      // Mark it for creation
 | 
						|
	      $db->query("INSERT INTO upnp SET mandatory='".addslashes($v["mandatory"])."', protocol='".addslashes($v["protocol"])."', port='".addslashes($v["port"])."', name='".addslashes($name)."', action='CREATE'");
 | 
						|
	      $id=$db->last_id();
 | 
						|
	      $forwards[]=array("id"=>$id, "mandatory" => intval($v["mandatory"]), "protocol" => $v["protocol"], "port" => intval($v["port"]), "name" => $name, "action" => "CREATE");
 | 
						|
	    }
 | 
						|
	  } // for each port forward in that class
 | 
						|
	} 
 | 
						|
      } // for each hooked class
 | 
						|
      // Now We search the "not found" and remove them from the array
 | 
						|
      for($i=0;$i<count($forwards);$i++) {
 | 
						|
	if (!$forwards[$i]["found"]) {
 | 
						|
	  $forwards[$i]["action"]="DELETING";
 | 
						|
	  $db->query("UPDATE upnp SET action='DELETING' WHERE id=".$forwards[$i]["id"].";");
 | 
						|
	}
 | 
						|
      }
 | 
						|
      
 | 
						|
    } // bigcheck ?
 | 
						|
    
 | 
						|
    // Ask for the current upnp status of forwarded ports
 | 
						|
    $status=array(); $statusout=array(); $bad=false;
 | 
						|
    unset($out);
 | 
						|
    exec("upnpc -l 2>&1",$res,$out);
 | 
						|
    foreach($out as $line) {
 | 
						|
      // example line:  1 TCP   222->192.168.0.5:22   'libminiupnpc' ''
 | 
						|
      if (preg_match("#^ *([0-9]+) (TCP|UDP) *([0-9]+)\-\>([0-9\.]+):([0-9]+) *#",$line,$mat)) {
 | 
						|
	if ($mat[4]==$L_INTERNAL_IP) {
 | 
						|
	  $status[]=array("protocol" => $mat[2], "port" => $mat[3]);
 | 
						|
	} else {
 | 
						|
	  $statusout[]=array("protocol" => $mat[2], "port" => $mat[3], "ip" => $mat[4]);
 | 
						|
	}
 | 
						|
      }
 | 
						|
      if (preg_match("#No IGD UPnP Device found on the network#",$line)) {
 | 
						|
	$bad=true;
 | 
						|
      }
 | 
						|
    } // For each line in upnpc -l (check list)
 | 
						|
 | 
						|
    // No UPnP peripheral !! maybe you should not have installed AlternC-upnp altogether ? 
 | 
						|
    if ($bad) {
 | 
						|
      foreach($forwards as $f) {
 | 
						|
	if ($f["action"]!="OK") {
 | 
						|
	  $db->query("UPDATE upnp SET lastupdate=NOW(), lastcheck=NOW(), result='No UPnP device detected in your network !' WHERE id=".$f["id"].";");
 | 
						|
	} else {
 | 
						|
	  $db->query("UPDATE upnp SET lastupdate=NOW(), lastcheck=NOW(), WHERE id=".$f["id"].";");
 | 
						|
	}
 | 
						|
      }
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    // Now, for each forward, we either 
 | 
						|
    // * check it (via upnpc -l parsing)
 | 
						|
    // * add it (via upnpc -a)
 | 
						|
    // * remove it (via upnpc -d)
 | 
						|
    foreach($forwards as $f) {
 | 
						|
      switch ($f["action"]) {
 | 
						|
      case "OK": // check
 | 
						|
	$found=false;
 | 
						|
	foreach($status as $s) {
 | 
						|
	  if ($s["port"]==$f["port"] && $s["protocol"]==$s["protocol"]) {
 | 
						|
	    $found=true;
 | 
						|
	    $db->query("UPDATE upnp SET lastcheck=NOW() WHERE id=".$f["id"].";");
 | 
						|
	  }
 | 
						|
	}
 | 
						|
	if (!$found) {
 | 
						|
	  // Search this protocol+port in the OTHER list ... if found, tell it ...
 | 
						|
	}
 | 
						|
	break;
 | 
						|
      case "CREATE": 
 | 
						|
	break;
 | 
						|
      case "DELETE":
 | 
						|
      case "DELETING":
 | 
						|
	break;
 | 
						|
      case "DISABLE":
 | 
						|
	break;
 | 
						|
      case "ENABLE":
 | 
						|
	break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
  } // CRON function
 | 
						|
  
 | 
						|
 | 
						|
 | 
						|
 | 
						|
  
 | 
						|
 | 
						|
} /* Class UPnP */
 | 
						|
 |