Skip to content

Instantly share code, notes, and snippets.

@magicdude4eva
Created April 14, 2019 10:54
Show Gist options
  • Save magicdude4eva/5a8d14fe7c08262408e0356953a617cb to your computer and use it in GitHub Desktop.
Save magicdude4eva/5a8d14fe7c08262408e0356953a617cb to your computer and use it in GitHub Desktop.
Huawei B618s-22d - reboot script and retrieval of other info
<?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;
}
}
?>
@magicdude4eva
Copy link
Author

magicdude4eva commented Dec 29, 2019

Donations are always welcome

🍺 Please support me: Although all my software is free, it is always appreciated if you can support my efforts on Github with a contribution via Paypal - this allows me to write cool projects like this in my personal time and hopefully help you or your business.

(CRO)    0xBAdB43af444055c4031B79a76F74895469BA0CD7 (Cronos)
(USDC)   0xBAdB43af444055c4031B79a76F74895469BA0CD7
(ETH)    0xfc316ba7d8dc325250f1adfafafc320ad75d87c0
(BTC)    1Mhq9SY6DzPhs7PNDx7idXFDWsGtyn7GWM
(BNB)    0xfc316ba7d8dc325250f1adfafafc320ad75d87c0
Crypto.com PayString: magicdude$paystring.crypto.com    

Go to Curve.com to add your Crypto.com card to ApplePay and signup to Crypto.com for a staking and free Crypto debit card.

Use Binance Exchange to trade #altcoins. I also accept old-school PayPal.

visitors

@vihatsoft
Copy link

thank you so much.
work fine with Huawei B311As-853
Hardware versionWL2B311M
Software version10.0.1.1(H187SP11C00)

@vihatsoft
Copy link

when will expire SessionID and firstNonce after set?

@MadMakz
Copy link

MadMakz commented Feb 13, 2022

Great script! Thank you very much!

Stupid question but what does "2=Reset" instead of 1 in function reboot do? Is that a factory reset?
I'm looking for a way to (re)connect LTE without a hardware reboot on a B528.

@cod-xio
Copy link

cod-xio commented Feb 16, 2022

Hello, I don't know how to use the script?

How can it be done?

@sstrix
Copy link

sstrix commented Aug 10, 2022

thanks, work fine on B818-263

@MulMic
Copy link

MulMic commented Nov 13, 2023

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment