DHCP-Tabelle aus Lancom-Router

Gibt ein Array heraus ($DhcpArray), welches die DHCP-Tabelle eines Lancom-Routers enthält.

Es müssen folgende Parameters gesetzt werden:
$router_ip = ‚string‘;
$username = ‚string‘;
$password = ‚string‘;


<?php

$port = 23;
$timeout = 10;
$router_ip = '';
$username = '';
$password = '';

$connection = fsockopen($router_ip, $port, $errno, $errstr, $timeout);

if(!$connection){
 echo "Connection failed
";
 exit();
} else {
 echo "Connected
";
 fputs($connection, "$username
");
 fputs($connection, "$password
");
 fputs($connection, "cd setup/dhcp/dhcp-table 
");
 fputs($connection, "dir 
");
 fputs($connection, " ");

 $j = 0;
 while ($j < 16) {
  fgets($connection);
  $j++;
 }
 stream_set_timeout($connection, 2);
 $timeoutCount = 0;
 $content ='';
 $DhcpArray = '';
 (int) $index =0;

$DhcpFile = "C:\IP-Symcon\webfront\user\images\LancomDhcp.txt";
$fh = fopen($DhcpFile, 'w') or die("can't open file");



 while (!feof($connection)){
  
  $content = fgets($connection);
  $content = str_replace("\r", '', $content);
  $content = str_replace("
", "", $content);
  if (isValidIp(explode(' ', $content)[0]))
  	{ $index +=1;
	  $DhcpArray[$index]['WholeString']= $content;
$DhcpArray[$index]['IP-Address'] = substr ($content, 0,17);
$DhcpArray[$index]['MAC-Address'] = substr ($content, 17,32-18);
$DhcpArray[$index]['Timeout'] = substr ($content, 31,41-32);
$DhcpArray[$index]['Hostname'] = substr ($content, 40,108-41);
$DhcpArray[$index]['Type'] = substr ($content, 107,125-108);
$DhcpArray[$index]['LAN-Ifc'] = substr ($content, 124,137-125);
$DhcpArray[$index]['Ethernet-Port'] = substr ($content, 136,152-137);
$DhcpArray[$index]['VLAN-ID'] = substr ($content, 151,161-152);
$DhcpArray[$index]['Network-Name'] = substr ($content, 160);
fwrite($fh, $content);
	  //$DhcpArray[$index]= preg_split('/ +/', $content);} // each element is an array
	  }

  # If the router say "press space for more", send space char:
  if (preg_match('/MORE/', $content) ){ // IF current line contain --More-- expression,
   fputs ($connection, " "); // sending space char for next part of output.
  } # The "more" controlling part complated.

  $info = stream_get_meta_data($connection);
  if ($info['timed_out']) { // If timeout of connection info has got a value, the router not returning a output.
   $timeoutCount++; // We want to count, how many times repeating.
  }
  if ($timeoutCount >2){ // If repeating more than 2 times,
   break;   // the connection terminating..
  }
 }
 $content = substr($content,410);
  print "content: ".chr(13).$content."
";
  print_r ($DhcpArray);
  



fclose($fh);

}
echo "End.
";

function isValidIp($ip)
{/* PCRE Pattern written by Junaid Atari */
    return !preg_match ( '/^([1-9]\d|1\d{0,2}|2[0-5]{2})\.('.
                         '(0|1?\d{0,2}|2[0-5]{2})\.){2}(0|1?'.
                         '\d{0,2}|2[0-5]{2})(\:\d{2,4})?$/',
                         (string) $ip )
            ? false
            : true;
}

?>

hier kommt noch ein kleines Goodie dazu. Die Funktion BetterTable() akzeptiert ein beliebiges 2-dimensionales array und macht daraus eine schön formatierte Tabelle, welche als HTML-Element eingesetzt werden kann. Funktioniert prima in Kombination mit dem obigen Script - kann aber auch woanders eingesetzt werden.



function BetterTable($twoDimArray)
{
$i = 0;
echo "<table>
		<table class='BetterTable' border='1'>";

echo "<tr>";
echo '<td>Line #
</td>';
foreach ($twoDimArray[0] as  $fieldName => $fieldValue)
	{
		echo '<td>'.$fieldName. '</td>';
	}echo '</tr>';
$i = 0;

foreach ($twoDimArray as $rowName => $rowValue) 
{
		if ($i%2 == 0) 
  			Echo "<tr bgcolor=\"#d0d0d0\" >";
		else 
			Echo "<tr bgcolor=\"#eeeeee\">";
	$fields = count($twoDimArray[$i]);
	$y = 0;
	echo '<td>'.$i. '</td>';
	foreach ($rowValue as  $fieldName => $fieldValue)
	{
		echo '<td>'.$fieldValue. '</td>';
		$y = $y + 1;
	}
	echo '</tr>';
	$i = $i + 1;
}


echo '</table>';
}


…und hier kommt eine erweiterte Variante, welche allerlei Tabellen aus dem Lancom-Router holen kann. Eingerichtet wurde sie für DHCP, port forwarding, und 1-N-NAT. Die allfällige Herausgabe anderer Tabellen ist relativ einfach einzurichten, indem man ein weiteres „case xyz:“ angibt.

Die Funktion BetterTable() ist nun integriert. Die Funktion isValidIP() validiert die Zeilen, welche eine korrekt formatierte IP-Addresse enthalten.

Das Aufrufen der Funktion mit dem Parameter „DHCP“||„Masquerade“||„1-N-NAT“ gibt die jeweilige HTML-Tabelle aus, welche z.B. in eine Webseite integriert werden kann.


<?php
function LancomTelnet($Table)
{
$port = 23;
$timeout = 10;
$router_ip = 'x.x.x.x'; //valid IP address of router
$username = 'user';
$password = 'pwd';

$connection = fsockopen($router_ip, $port, $errno, $errstr, $timeout);

Switch ($Table)
 {case "DHCP":
	  $TelnetRequest1 = "dir setup/dhcp/dhcp-table 
";
	  $TableStructure = Array ('IP-Address' => 16, //number is length of each field
	  							'MAC-Address' => 13,
								'Timeout' => 10,
								'Hostname' => 67,
								'Type' => 17,
								'LAN-Ifc' => 12,
								'Ethernet-Port' => 15,
								'VLAN-ID' => 10,
								'Network-Name' => 16);
 break;
 
 case "Masquerade":
	  $TelnetRequest1 = "dir /Setup/IP-Router/1-N-NAT/Service-Table 
";
	  $TableStructure = Array ('D-port-from' => 13,
							  'D-port-to' => 13 , 
							  'Protocol' => 11 ,
							  'Peer' => 18 ,
							  'WAN-Address' => 17 ,
							  'Intranet-Address' => 18 ,
							  'Map-Port' => 13 ,
							  'Active' => 9 ,
							  'Comment' => 25
							  );
 break;
  
 
 case "1-N-NAT":
   	  $TelnetRequest1 = "dir /Setup/IP-Router/1-N-NAT/Table-1-N-NAT 
"; 
	  $TableStructure = Array ('Intranet-Address' => 17,
	  						   'Source-Port' => 13,
							   'Protocol' => 11,
							   'Timeout' => 9,
	  						   'Handler' => 12,
							   'remote-Address' => 17);
 break;
}

if(!$connection){echo "Connection failed
"; exit();} 
else 
{
 fputs($connection, "$username
");
 fputs($connection, "$password
");
 fputs($connection, $TelnetRequest1);
 fputs($connection, " ");
 $j = 0;
 while ($j < 16) 
 	{
  	fgets($connection);
	$j++;
 	}
 
stream_set_timeout($connection, 2);
$timeoutCount = 0;
$content ='';
$LancomArray = '';
(int)$index =0;

$LancomFile = "C:\IP-Symcon\webfront\user\images\LancomDhcp.txt";
$fh = fopen($LancomFile, 'w') or die("can't open file");



while (!feof($connection)){
  // pull the table from the router via telnet
  $content = fgets($connection);
  $content = str_replace("\r", '', $content);
  $content = str_replace("
", "", $content);
  if (isValidIp(substr($content,0,16)) || isValidIp(substr($content,72,16)))
      { 
	  $LancomArray[$index] = ParseIrregularString($content, $TableStructure);
	  fwrite($fh, $content);
	  $index +=1;
	  }

  # If the router say "press space for more", send space char:
  if (preg_match('/MORE/', $content) ){ // IF current line contain --More-- expression,
   fputs ($connection, " "); // sending space char for next part of output.
  } # The "more" controlling part complated.

  $info = stream_get_meta_data($connection);
  if ($info['timed_out']) { // If timeout of connection info has got a value, the router not returning a output.
   $timeoutCount++; // Count how many times it is repeating.
  }
  if ($timeoutCount >2){ // If repeating more than 2 times,
   break;   // then terminating connection..
  }
 }
 $content = substr($content,410);

BetterTable($LancomArray);
 
  
fclose($fh);

}


}

//--------------------------------------------------------------------

function ParseIrregularString  ($string, $lengths)
	{ 
    $parts = array(); 
 
    foreach ($lengths as $StringKey => $position)
		{ 

        $parts[$StringKey] = substr($string, 0, $position); 
        $string = substr($string, $position); 
    	} 
 
    return $parts; 
} 

//--------------------------------------------------------------------

function isValidIp($ip)
{/* PCRE Pattern written by Junaid Atari */
    return !preg_match ( '/^([1-9]\d|1\d{0,2}|2[0-5]{2})\.('.
                         '(0|1?\d{0,2}|2[0-5]{2})\.){2}(0|1?'.
                         '\d{0,2}|2[0-5]{2})(\:\d{2,4})?$/',
                         (string) trim($ip) )
            ? false
            : true;
}

//--------------------------------------------------------------

function BetterTable($twoDimArray)
{
$i = 0;
echo "<table>
		<table class='BetterTable' border='1'>";

echo "<tr>";
echo '<td>Line #
</td>';
foreach ($twoDimArray[0] as  $fieldName => $fieldValue)
	{
		echo '<td>'.$fieldName. '</td>';
	}echo '</tr>';
$i = 0;

foreach ($twoDimArray as $rowName => $rowValue) 
{
		if ($i%2 == 0) 
  			Echo "<tr bgcolor=\"#d0d0d0\" >";
		else 
			Echo "<tr bgcolor=\"#eeeeee\">";
	$fields = count($twoDimArray[$i]);
	$y = 0;
	echo '<td>'.$i. '</td>';
	foreach ($rowValue as  $fieldName => $fieldValue)
	{
		echo '<td>'.$fieldValue. '</td>';
		$y = $y + 1;
	}
	echo '</tr>';
	$i = $i + 1;
}


echo '</table>';
}


?>

Hi,

habe das Script (wieder)gefunden. Leider wirft das Grundscript Fehler in Zeile 52 aus:

Connected


Fatal error:  Uncaught Error: Cannot use string offset as an array in C:\ProgramData\Symcon\scripts\41057.ips.php:52
Stack trace:
#0 {main}
  thrown in C:\ProgramData\Symcon\scripts\41057.ips.php on line 52
Abort Processing during Fatal-Error: Uncaught Error: Cannot use string offset as an array in C:\ProgramData\Symcon\scripts\41057.ips.php:52
Stack trace:
#0 {main}
  thrown
   Error in Script C:\ProgramData\Symcon\scripts\41057.ips.php on Line 52

Zugang und Tabelle auf dem LC sind ok…

Solltest Du das Script nicht mehr „pflegen“ reicht eine kurze Nachricht.

Vielen Dank und schöne Grüße

kea

leider habe ich das Lancom-Ding vor einigen Jahren entsorgt. Mein Gateway ist eine pfSense Box, DHCP und DNS laufen auf einem Windows Server. Das ganze ist viel flexibler und einfacher zu pflegen. Sorry…

Du könntest ja mal die Ausgabe deiner Lancom Tabelle 1:1 ins Forum kopieren. Dann kann jeder das Script darüber laufen lassen und sich das Ergebnis anzeigen lassen.

Falls da nochmal jemand drüber stolpert, das geht auch mit SNMP ohne viel herumbasteln mit der String-Formatierung oder nur halben Listen.

SNMP User im Lancom anlegen: SNMP-Einstellungen

Die SNMP Bibliothek GitHub - FreeDSx/SNMP: A Pure PHP SNMP Library. muss entsprechend im scripts/snmp Ordner liegen.

Zwei Beiträge weiter unten ist die lauffähige SNMP-Bibliothek inkl. autoload.php hochgeladen.

$HTMLBOXID = 12345; // HTML Box mit Ausgabe
require_once('.\snmp\autoload.php');
use FreeDSx\Snmp\SnmpClient;
$snmp = new SnmpClient([
   'host' => '192.168.123.1',
   'version' => 3,
   'user' => 'SYMCON',
   'use_auth' => true,
   'auth_mech' => 'sha1',
   'auth_pwd' => "SymconPWD",
   'use_priv' => true,
   'priv_mech' => 'aes128',
   'priv_pwd' => 'SymconPWD',
]);
$dhcptable = array();
$start = "1.3.6.1.4.1.2356.11.1.9.6.16";  
try {
  $walk= $snmp->walk($start,$start);
  while($walk->hasOids()) {
    try {
        $oid = $walk->next();
        //$ident = "_".str_replace(".","_",$oid->getOid());
        //$id = IPS_GetObjectIDByIdent($ident, $parent);
        $value = $oid->getValue()->getValue();
        $shortoid = str_replace(array('1.3.6.1.4.1.2356.11.1.9.6.16.1.' /*prefix*/, '.8.73.78.84.82.65.78.69.84' /*Suffix*/) ,'',$oid->getOid());
        $pos =  strpos($shortoid, '.');
        $type = substr($shortoid, 0, $pos);
        $ip = substr($shortoid, $pos+1);
        $dhcptable[$ip][$type]=$oid->getValue()->getValue();

    } catch (\Exception $e) {
        echo "Unable to retrieve OID. ".$e->getMessage().PHP_EOL;
    }
  } // ende while
} catch (\Exception $e) { /* catchblock zu ->walk*/ echo "Unable to walk. ".$e->getMessage().PHP_EOL;}
array_multisort (array_column($dhcptable, '11'), SORT_DESC, $dhcptable);
//print_r($dhcptable);

$out='<table class="wwx">';
foreach($dhcptable as $k => $v){
    $macad = (strlen($v[2])>12) ? $v[2] : join(':', str_split($v[2], 2));
    $macad = strtolower($macad);
    $out.='<tr><td><a target="_blank" href="https://'.$v[1].'">secure</a> - <a target="_blank" href="http://'.$v[1].'">'.$v[1].'</a></td><td>'.$macad.'</td><td>'.$v[4].'</td><td>'.$v[11].'</td></tr>';
 }
$out.='</table>';
SetValue($HTMLBOXID, $out);

Moin,

danke für das Update. Musste ich natürlich sofort ausprobieren :slight_smile: .
Allerdings mein meint IPS (6.1 auf Win2016), das noch eine autoload.php fehlt?
In GIT finde ich das Ding aber nicht?

Mit der Bitte um Erleuchtung und schönen Grüßen

kea

Warning: require_once(.\snmp\autoload.php): failed to open stream: No such file or directory in C:\ProgramData\Symcon\scripts\50060.ips.php on line 4

Fatal error: require_once(): Failed opening required '.\snmp\autoload.php' (include_path='.;C:\ProgramData\Symcon\scripts') in C:\ProgramData\Symcon\scripts\50060.ips.php on line 4
Abort Processing during Fatal-Error: require_once(): Failed opening required '.\snmp\autoload.php' (include_path='.;C:\ProgramData\Symcon\scripts')
   Error in Script C:\ProgramData\Symcon\scripts\50060.ips.php on Line 4

Hab mal meine lauffähige Version angehangen.
snmp-autoload.7z (97,6 KB)