Hey zusammen.

Weil ich nach Jahren einen neuen Router bekommen habe, musste ich mein Router-Parsing-Script überarbeiten.

Damit ist es möglich die am Router angemeldeten Geräte samt IP & MAC Adresse abzurufen.
Darüber lässt sich dann z.B. abgleichen ob Personen (bzw. deren SmartPhones) anwesend sind.

Da es bei der weißen Connect Box etwas komplizierter war an die Liste zu kommen, möchte ich das Script / die PHP Klasse mit euch teilen, vielleicht bringts ja jemandem was...
Spart auf jedenfall Strom / Energie (Wenn das Haus automatisch merkt das keiner mehr da ist und alle vergessenen Lampen ausschaltet / Heizungen runter regelt.)

PHP-Code:
<?php 

class UnitimediaRouter 
    
/// you can do your setup here, or pass the configs on the go (as done in the example) 
    
var $ip '';  
    var 
$psw ''
    var 
$debug false
     
    var 
$lastToken false
    var 
$sid false
    var 
$userAgent 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'

    
// Construct: Pass ID and perform StartAction 
    
function __construct($ip false){ 
        if (
$ip){ 
            
$this->ip $ip
        } 
    } 

    
// Helper for performing CURL requests 
    
function httpRequest($url$post false$header false){ 
        
$ch curl_init('http://' $this->ip.$url); 
        
curl_setopt($chCURLOPT_RETURNTRANSFER1); 
        
curl_setopt($chCURLOPT_VERBOSEtrue); 
        
curl_setopt($chCURLOPT_HEADER1); 
        
curl_setopt($chCURLINFO_HEADER_OUTtrue); 

        
// Header 
        
if ($header){ 
            
curl_setopt($chCURLOPT_HTTPHEADER$header); 
        } 

        
// Post 
        
if ($post){ 
            
curl_setopt($chCURLOPT_POST1);     
            
curl_setopt($ch,CURLOPT_POSTFIELDShttp_build_query($post));     
        } 

        
$result curl_exec($ch);     
        
$info curl_getinfo($ch); 

        
// get Response Header & Body 
        
$responseHeader substr($result0$info['header_size']-1); 
        
$body substr($result$info['header_size']); 

        
// Get Cookies from Response Header 
        
preg_match_all('/^Set-Cookie:\s*([^;]*)/mi'$responseHeader$matches); 
        
$cookies = array(); 
        foreach(
$matches[1] as $item) { 
            
parse_str($item$cookie); 
            
$cookies array_merge($cookies$cookie); 
        } 

        
$resultFull = array( 
            
'info' => $info
            
'header' => $responseHeader
            
'body' => $body
            
'cookies' => $cookies
            
'result' => $result 
        
); 

        if (
$this->debug){ 
            
print_r($resultFull); 
        } 
        return 
$resultFull
    } 

    
// helper to transform a XML String to an assoc array 
    
static function xmlToArray($sXML){ 
        
$oXml simplexml_load_string($sXML); 
        
$json json_encode($oXml); 
        return 
json_decode($json,TRUE);         
    } 

    
// helper to prepare an AJAX Call 
    
function headerForAjaxCall(){ 
        return array( 
            
'Accept: application/xml, text/xml, */*; q=0.01'
            
'Content-Type: application/x-www-form-urlencoded; charset=UTF-8'
            
'Cookie: ' . ($this->sid $this->sid.';' '') . 'sessionToken=' $this->lastToken// Add SID (if available - after login) AND Token 
            
'User-Agent: '.$this->userAgent
            
'X-Requested-With: XMLHttpRequest' 
        
); 
    } 

    
// every call changes the "sessionToken" which is needed for the next call 
    
function updateToken($result){ 
        if (isset(
$result['cookies']['sessionToken'])){ 
            
$token $result['cookies']['sessionToken']; 
            if (
$token){ 
                
$this->lastToken $token
                return 
true
            }             
        } 
        return 
false
    } 

    
// ACTIONS 
     
    // First thing to do:  
    // Call login page to get a token to start with 
    
function start(){         
        
// header 
         
        
$header = array( 
            
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'
            
'User-Agent: '.$this->userAgent
        ); 

        
// perform request 
        
$result $this->httpRequest('/common_page/login.html'false $header); 

        
// Update Token (changes every time) 
        
return $this->updateToken($result); 
    } 

    
// Second: 
    // Login with password to get a SID aswell 
    
function login($psw false){ 
        if (
$psw === false){ 
            
$psw $this->psw// use default settings 
        

        
// Post Data 
        
$post = array( 
            
'token' => $this->lastToken
            
'fun' => 15// function 15 => login 
            
'Username' => 'NULL'
            
'Password' => $psw 
        
); 
        
// header 
        
$header $this->headerForAjaxCall(); 

        
// perform request 
        
$result $this->httpRequest('/xml/setter.xml'$post$header); 

        
// Update Token (changes every time) 
        
if (!$this->updateToken($result)){ 
            return 
false
        } 

        
// Valid response? 
        
if ($result['info']['http_code'] != 200 || !$result['body'] ){ 
            return 
false
        } 
   
        
// Get Information (SID!) from response body 
        
$responseData explode(';',$result['body']); 
        if (
$responseData[0] != 'successful'){ // Is either "successful" or "useridwrong" (or something like that) 
            
return false
        } 
   
        
$this->sid $responseData[1]; // save SID 
        
return true
    } 

    
// last action: Logout (optional - but without it the router's webconsole is locked for other IPs (e.g. your browser) for some time) 
    
function logout(){ 
        
// Post Data 
        
$post = array( 
            
'token' => $this->lastToken
            
'fun' => 16 // function 16 => logout 
        
); 
        
// header 
        
$header $this->headerForAjaxCall(); 

        
// perform request 
        
$result $this->httpRequest('/xml/setter.xml'$post$header);         

        
// Update Token (changes every time) 
        
if (!$this->updateToken($result)){ 
            return 
false
        } 

        return 
true
    } 
     
    
// Get Connection Table as XML String (Login needed!) 
    
function getConnectionTableXML(){ 
        
// Post Data 
        
$post = array( 
            
'token' => $this->lastToken
            
'fun' => 123 // function 123 => get IP Table 
        
); 
        
// header 
        
$header $this->headerForAjaxCall(); 

        
// perform request 
        
$result $this->httpRequest('/xml/getter.xml'$post$header); 

        
// Update Token (changes every time) 
        
if (!$this->updateToken($result)){ 
            return 
false
        } 

        
// Valid response? 
        
if ($result['info']['http_code'] != 200 || !$result['body']){ 
            return 
false
        } 

        
// get XML from responseBody 
        
$xml trim($result['body']); 
        return 
$xml
    } 



// Usage Example 

$oRouter = new UnitimediaRouter('192.168.0.1'); 
// $oRouter->debug = true; 
if ($oRouter->start() == false){ 
    die(
'Error Start'); // e.g. Console is locked by an other user 

if (
$oRouter->login('MyPassword')){
    
// get the table 
    
$sXML $oRouter->getConnectionTableXML(); 
    if (
$sXML){ 
        
// use the helper to get an array from XML String (you could also work with SimpleXML / DomXML ;) 
        
$myConnections UnitimediaRouter::xmlToArray($sXML); 
        
print_r($myConnections); 
    } 
    
// you should log out to free the web-console 
    
$oRouter->logout();     
} else { 
    die(
'Error Login'); // e.g. Password is wrong 
}
Das funktioniert viel schneller und zuverlässiger als beispielsweise nmap/pings da wirklich alle angemeldeten Geräte aufgelistet werden. Beim Pingen war das anders: Android im Standby z.B. antwortet (bei mir) nicht auf Pings.

Viel Spaß damit.

Grüße,

Huelke