Created
April 14, 2019 10:54
-
-
Save magicdude4eva/5a8d14fe7c08262408e0356953a617cb to your computer and use it in GitHub Desktop.
Huawei B618s-22d - reboot script and retrieval of other info
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Config | |
$routerAddress = '192.168.8.1'; | |
$username="admin"; | |
$password="password"; | |
// Code | |
$router = new HuaweiB618($routerAddress); | |
if ($router->login($username, $password)==FALSE) { echo $router->LastError. "!\n"; die(); } | |
// activate one, or more, functions that you want to try | |
if ($router->reboot()==FALSE) echo $router->LastError. "!\n"; die(); | |
//if ($ret=$router->DeviceInformation()) echo $ret."\n"; else { echo $router->LastError. "!\n"; die(); } | |
//if ($ret=$router->CurrentPlmn()) echo $ret."\n"; else { echo $router->LastError. "!\n"; die(); } | |
//if ($ret=$router->TrafficStatistics()) echo $ret."\n"; else { echo $router->LastError. "!\n"; die(); } | |
//if ($ret=$router->Status()) echo $ret."\n"; else { echo $router->LastError. "!\n"; die(); } | |
//if ($router->SendSms("+43670XXXXXX", "SMS sent via php class")==FALSE) { echo $router->LastError. "!\n"; die(); } | |
if ($router->logout() == FALSE) { echo $router->LastError. "!\n"; die(); } | |
echo 'OK'; | |
/* | |
Done on 14th April 2019 for the Huawei B618s-22d | |
DeviceName: B618s-22d | |
HardwareVersion: WL1B610FM | |
SoftwareVersion: 11.196.01.00.965 | |
To run on PI you need to install: sudo apt-get install php-curl php-xml | |
*/ | |
class HuaweiB618 | |
{ | |
public $url = ""; | |
public $LastError = ""; | |
private $ch = NULL; | |
private $SessionID = ""; | |
private $TokInfo = array (""); | |
private $ContLen = 0; | |
private $options = array( | |
CURLOPT_RETURNTRANSFER => true, // return web page | |
CURLOPT_HEADER => false, // NO return headers in addition to content | |
CURLOPT_FOLLOWLOCATION => true, // follow redirects | |
CURLOPT_CONNECTTIMEOUT => 5, // timeout on connect | |
CURLOPT_TIMEOUT => 5, // timeout on response | |
CURLOPT_MAXREDIRS => 1, // stop after 1 redirect | |
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, | |
); | |
private $firstNonce = ""; // example: "f0ce57a3413f75627f2fb0748f6c0edfd7ca88f6f9538fe2a3dc0e03bb01f5c0" // MUST change at every login ! | |
public function __destruct ( ) { if ($this->ch) curl_close( $this->ch ); } | |
public function __construct($URL="192.168.8.1") { $this->url=$URL; } | |
/******************************************** | |
* Generic POST * | |
********************************************/ | |
private function POST($post, $Url, $tok="") | |
{ | |
if ($tok=="") $tok=$this->TokInfo[0]; | |
curl_setopt($this->ch, CURLOPT_URL, $this->url . $Url); | |
curl_setopt($this->ch, CURLOPT_POST, 1); | |
curl_setopt($this->ch, CURLOPT_POSTFIELDS,$post); | |
curl_setopt($this->ch, CURLOPT_COOKIE, $this->SessionID); | |
curl_setopt($this->ch, CURLOPT_HTTPHEADER, array( "__RequestVerificationToken: ".$tok, | |
"Connection: keep-alive")); | |
return curl_exec( $this->ch ); | |
} | |
/******************************************** | |
* Generic GET * | |
********************************************/ | |
private function GET($fun) | |
{ | |
curl_setopt($this->ch, CURLOPT_URL, $this->url . $fun); | |
curl_setopt($this->ch, CURLOPT_COOKIE, $this->SessionID); | |
curl_setopt($this->ch, CURLOPT_POST, 0); | |
if (!($body = curl_exec( $this->ch ))) return FALSE; | |
return substr($body, -$this->ContLen); | |
} | |
/******************************************** | |
* Error Error Error Error Error * | |
********************************************/ | |
private function ERROR($f) | |
{ | |
$this->LastError = $f ." error - ". curl_error($this->ch) . " ( ". curl_errno($this->ch)." )"; | |
return FALSE; | |
} | |
/******************************************** | |
* GET /api/webserver/SesTokInfo * | |
* Recovery <TokInfo> and <SessionID> * | |
********************************************/ | |
private function SesTokInfo() | |
{ | |
if (!($body = $this->GET("/api/webserver/SesTokInfo"))) return $this->ERROR(__METHOD__); | |
$xmlP=simplexml_load_string($body); | |
$this->SessionID =$xmlP->SesInfo; | |
$this->TokInfo[0] =$xmlP->TokInfo; | |
if (!$this->SessionID || !$this->TokInfo[0]) return $this->ERROR (__METHOD__ ."->NAK"); | |
return TRUE; | |
} | |
/******************************************** | |
* GET /api/user/state-login * | |
********************************************/ | |
private function StateLogin() | |
{ | |
if (!($ret=$this->GET("/api/user/state-login"))) return $this->ERROR(__METHOD__); | |
return $ret; | |
} | |
/******************************************** | |
* GET /api/monitoring/status * | |
********************************************/ | |
public function Status() | |
{ | |
if (!($ret=$this->GET("/api/monitoring/status"))) return $this->ERROR(__METHOD__); | |
return $ret; | |
} | |
/******************************************************************************** | |
* login with SCRAM ( Salted Challenge Response Authentication Mechanism ) * | |
* * | |
* Warning: the session expires after 5 minutes from login * | |
********************************************************************************/ | |
public function login($user, $password) | |
{ | |
$this->ch = curl_init(); | |
$ch=$this->ch; | |
curl_setopt_array( $ch, $this->options ); | |
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($CH,$header) { | |
if (substr($header,0,27) == '__RequestVerificationToken:') $this->TokInfo = explode("#", trim(substr($header,27))); else | |
if (substr($header,0,11) == 'Set-Cookie:') $this->SessionID= trim(substr($header,11)); else | |
if (substr($header,0,15) == 'Content-Length:') $this->ContLen =(int)trim(substr($header,15)); | |
return strlen($header); | |
}); | |
if (!$this->SesTokInfo()) return FALSE; | |
/*------------------------------------------+ | |
| Now I create a new firstNonce | | |
+------------------------------------------*/ | |
$ctx = hash_init('sha256'); | |
hash_update($ctx, time().date("-m-d H:i:s")); $this->firstNonce=hash_final($ctx); | |
/*------------------------------------------+ | |
| POST /api/user/challenge_login | | |
| This POST changes the TokInfo ! | | |
+------------------------------------------*/ | |
$post="<?xml version='1.0' encoding='UTF-8'?>". | |
"<request>". | |
"<username>".$user."</username>". | |
"<firstnonce>".$this->firstNonce."</firstnonce>". | |
"<mode>1</mode>". | |
"</request>"; | |
if (!($body = $this->POST($post, "/api/user/challenge_login"))) return $this->ERROR(__METHOD__ . "->challenge_login"); | |
$body_content = substr($body, -$this->ContLen); | |
$xmlP = simplexml_load_string($body_content); | |
$salt = $xmlP->salt; | |
$servernonce = $xmlP->servernonce; | |
$iter = (int) $xmlP->iterations; // always = 100 | |
/*------------------------------------------+ | |
| Calculating the clientproof | | |
+------------------------------------------*/ | |
$authMsg = $this->firstNonce . "," . $servernonce . "," . $servernonce; | |
$ctx = hash_init('sha256'); | |
$saltPassword = hash_pbkdf2('sha256', $password, hex2bin($salt), $iter, 0, TRUE); | |
$clientKey = hash_hmac ('sha256', $saltPassword, "Client Key", TRUE); | |
hash_update($ctx, $clientKey); | |
$storedkey = hash_final ($ctx, TRUE); | |
$signature = hash_hmac ('sha256', $storedkey, $authMsg, TRUE); | |
for($i = 0; $i < strlen($clientKey); $i++) $clientKey[$i] = $clientKey[$i] ^ $signature[$i]; | |
$clientproof=bin2hex($clientKey); | |
/*------------------------------------------+ | |
| POST api/user/authentication_login | | |
| This POST changes the SessionID cookie | | |
+------------------------------------------*/ | |
$post="<?xml version='1.0' encoding='UTF-8'?>". | |
"<request>". | |
"<clientproof>" . $clientproof . "</clientproof>". | |
"<finalnonce>" . $servernonce . "</finalnonce>". | |
"</request>"; | |
if (!($body = $this->POST($post, "/api/user/authentication_login"))) return $this->ERROR(__METHOD__ . "->authentication_login"); | |
/*------------------------------------------+ | |
| GET /api/user/state-login | | |
+------------------------------------------*/ | |
if (($body = $this->StateLogin())==FALSE) return FALSE; | |
$xmlP=simplexml_load_string($body); | |
if ($xmlP->State != "0" || $xmlP->Username != $user) return $this->ERROR(__METHOD__ ."->StateLogin NAK"); | |
return TRUE; | |
} | |
/******************************************** | |
* GET /api/device/information * | |
********************************************/ | |
public function DeviceInformation () | |
{ | |
if (!($ret=$this->GET("/api/device/information"))) return $this->ERROR(__METHOD__); | |
return $ret; | |
} | |
/******************************************** | |
* GET /api/net/current-plmn * | |
********************************************/ | |
public function CurrentPlmn () | |
{ | |
if (!($ret=$this->GET("/api/net/current-plmn"))) return $this->ERROR(__METHOD__); | |
return $ret; | |
} | |
/******************************************** | |
* GET /api/monitoring/traffic-statistics * | |
********************************************/ | |
public function TrafficStatistics () | |
{ | |
if (!($ret=$this->GET("/api/monitoring/traffic-statistics"))) return $this->ERROR(__METHOD__); | |
return $ret; | |
} | |
/******************************************** | |
* POST /api/sms/send-sms * | |
********************************************/ | |
public function SendSms ($to, $testo) | |
{ | |
$post= "<?xml version='1.0' encoding='UTF-8'?>\n". | |
"<request>\n". | |
"<Index>-1</Index>\n". | |
"<Phones>\n". | |
"<Phone>".$to."</Phone>\n". | |
"</Phones>\n". | |
"<Sca></Sca>\n". | |
"<Content>".$testo."</Content>\n". | |
"<Length>".strlen($testo)."</Length>\n". | |
"<Reserved>1</Reserved>\n". | |
"<Date>".date("Y-m-d H:i:s")."</Date>\n". | |
"</request>\n"; | |
if (!($body = $this->POST($post, "/api/sms/send-sms"))) return $this->ERROR(__METHOD__); | |
if (!strpos($body, "<response>OK</response>")) return $this->ERROR(__METHOD__ ."->NAK"); | |
return substr($body, -$this->ContLen); | |
} | |
/******************************************** | |
* POST /api/device/control reboot * | |
********************************************/ | |
public function reboot ($rr="1") | |
{ | |
$post= "<?xml version='1.0' encoding='UTF-8'?>\n". | |
"<request>\n". | |
"<Control>".$rr."</Control>\n". // 1=Reboot | 2=Reset | |
"</request>\n"; | |
if (!($body = $this->POST($post, "/api/device/control"))) return $this->ERROR(__METHOD__); | |
if (!strpos($body, "<response>OK</response>")) return $this->ERROR(__METHOD__ ."->NAK"); | |
curl_close( $this->ch ); $this->ch=NULL; | |
return substr($body, -$this->ContLen); | |
} | |
/******************************************** | |
* POST /api/user/logout * | |
********************************************/ | |
public function logout () | |
{ | |
$post= "<?xml version='1.0' encoding='UTF-8'?>\n". | |
"<request>\n". | |
"<Logout>1</Logout>\n". | |
"</request>\n"; | |
if (!($body = $this->POST($post, "/api/user/logout"))) return $this->ERROR(__METHOD__); | |
if (!strpos($body, "<response>OK</response>")) return $this->ERROR(__METHOD__ .":NAK"); | |
curl_close( $this->ch ); $this->ch=NULL; | |
return TRUE; | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi magicdude4eva,
thanks for providing this nice and straightforward example of making use of the Huawei ajax api.
Alas I don't have coins nor do I socialize via "social" media. I prefer personal contact face to face. So, alas, I can not pay you in the currency of your desire, but I can light a candle for you in a church of your preference ;-)
While I still strive to keep much of my tinkering in bash scripting, I learned quite a lot about PHP from you, I even installed a LAMP server on my Pi for that end.
I found, that PHP can, and probably should be used for commandline scripting more often.
I added a shebang to your script (#!/usr/bin/php) and set the file executable, so I can now simply invoke the script by typing ./Huawei.php.
or use it for piping by adding "$input = stream_get_contents(STDIN);" and evaluating the data for use in the script. (As pointed out at https://stackoverflow.com/questions/5891888/piping-data-into-command-line-php).
This enables me to use PHP functions in bash scripting, which may sound weird but I somehow like the odd solutions, just for the heck oft them.
For instance, adding "$message=stream_get_contents(STDIN);" to the script and replacing the message part of the send sms function with $message, I can then do "./huawei.php <<< 'hello world' to send an sms to the given phone number. Nifty, isn't it ?
Presently I am using a Huawei B818-263 (4G) as well as a Huawei H138-380 (5G) router, both can be controlled perfectly with the script.
MulMic