Nice idea and thanks for putting me on the right track, this is just what I was trying to do. I guess I could host the site on one of the many free web hosting services out there, this way I would be able to offer the functionality to several hotspots on different networks.Well, in MikroTik's defense, a forgotten password feature isn't hard to implement if you have an external web server.
You just place that server into a "walled garden", so that it can be accessed without a login, and link to it from the login page. The external server itself can do whatever check ups are needed (e.g. ask for an email, phone or other verifiable personal data) and set a new password, all using the API protocol, which can also connect to RouerBoard devices.
I understand what you mean, but my purpose here is to keep things as simple and cheap as I can, because I am not doing this professionally. I benevolently administrate (and police!) the internet access at a remote location where we have to share a very limited satellite connection between multiple users. For this purpose, the RouterBoard 450G has been a terrific and cost effective tool, so much so that other similar locations have asked me to implement the same system at their site. I work at these locations, but my job is completely unrelated to this. I just do it on the side, time allowing.Developing your own features on top of mikrotik is what gives your business value, otherwise you are no different from everyone else. Setting up a simple free radius lamp server takes less than 60 minutes, even less if you use a cloud server.
Get the business logic off the mt and onto your own system and you,ll be amazed at what you can do with the platform.
You're welcome.Awesome, thanks for that.
That's not the problem with having an email leading to a password changer.My first thought for the lost password was that users would just enter their user name, and the script would have the router either email a new temporary password to their registered address, or email them a link to the form allowing them to change their password. However I guess this would require some sort of security measure to prevent potential attackers to flood the inbox of the users.
That's what we thought at my work (a computer repair shop) when we first started... now, this is our 2nd greatest revenue stream, without which we'll have a very hard time. You said it yourself... you already have other clients who want the same. So - welcome to the club .my job is completely unrelated to this. I just do it on the side, time allowing.
I understand that it would not be a viable option in lots of cases, but in my particular case, people who lost their password can simply go to one of their colleagues and borrow their computer/laptop for the sake of checking their email and retrieving the password. So I might build it that way by modifying your code when I get to that point. Or I may decide to do it your way. I still have to think about what will be easier for me and more convenient for them.The problem is your users need to login in order to have internet. And they need internet to access their email => Without login, how could they access their email?
<?php phpinfo(); ?>
$file = realpath($path);
$file = $path;
<?php
namespace PEAR2\Net\RouterOS;
require_once 'PEAR2/Net/RouterOS/Autoload.php';
echo 'OK1';
$client = new Client('192.168.0.1', 'admin');
echo 'OK2';
?>
<?php
namespace PEAR2\Net\RouterOS;
class Time {
function GenerateCurrentTime(){
$sTime = gmdate("d-m-Y H:i:s");
return $sTime;
}
}
?>
<?php
namespace PEAR2\Net\RouterOS;
require_once 'PEAR2/Net/RouterOS/classTime.php';
$oTime = new Time;
$sTime = $oTime->GenerateCurrentTime();
print 'The time is: ' . $sTime;
?>
<?php
namespace PEAR2\Net\RouterOS;
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'On');
require_once 'PEAR2/Net/RouterOS/Autoload.php';
echo 'Autoload.php is loaded...';
try {
$client = new Client('192.168.0.1', 'admin');
echo 'Client is created...';
} catch(\Exception $e) {
echo 'Client not created because of the following exception: ', $e;
}
Client not created because of the following exception: exception 'PEAR2\Net\Transmitter\SocketException' with message 'Failed to initialize socket.' in /srv/disk8/xxxxxxx/www/mysubdomain.myhost.net/PEAR2/Net/Transmitter/TcpClient.php:109 Stack trace: #0 /srv/disk8/xxxxxxx/www/mysubdomain.myhost.net/PEAR2/Net/Transmitter/TcpClient.php(93): PEAR2\Net\Transmitter\TcpClient->createException('Failed to initi...', 7) #1 /srv/disk8/xxxxxxx/www/mysubdomain.myhost.net/PEAR2/Net/RouterOS/Communicator.php(110): PEAR2\Net\Transmitter\TcpClient->__construct('myexternalIP', 8728, false, NULL, 'api_user', NULL) #2 /srv/disk8/xxxxxxx/www/mysubdomain.myhost.net/PEAR2/Net/RouterOS/Client.php(105): PEAR2\Net\RouterOS\Communicator->__construct('myexternalIP', 8728, false, NULL, 'api_user', NULL) #3 /srv/disk8/xxxxxxx/www/mysubdomain.myhost.net/test11.php(11): PEAR2\Net\RouterOS\Client->__construct('myexternalIP', 'api_user', 'api_user_password') #4 {main} Socket error number:111 Socket error message:Connection refused
I verified that the router is accessible and the API service is enabled and listening on port 8728 and I opened the port in the firewall. Do you think this happens because of limitations from my hosting site? Should I try another one?The following PHP functions are disabled on free accounts due to system/security reasons: allow_url_fopen, fsockopen, pfsockpen, getrusage, get_current_user, set_time_limit, getmyuid, getmypid, dl, leak, listen, chown, chgrp, realpath, link, exec, passthru, curl_init.
Socket error message:Connection refused
OK. Sorry for doubting that. I had to check, as I've now had two instances of people either forgetting to enable the API or forgetting to give sufficient permissions to the user.To answer the question in your previous post: yes I do know that I have to use the external IP of the router, and I created a user with limited privileges and a strong password for the purpose. I just used the example of your code to avoid posting my IP and user names all over the forum.
<?php
namespace PEAR2\Net\RouterOS;
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'On');
require_once 'PEAR2/Net/RouterOS/Autoload.php';
echo 'Autoload.php is loaded...';
try {
$client = new Client('myexternalIP', 'api_user', 'api_user_password', 21);
echo 'Client is created...';
} catch(\Exception $e) {
echo 'Client not created because of the following exception: ', $e;
}
$responses = $client->sendSync(new Request('/ip/arp/print'));
foreach($responses as $response) {
if ($response->getType() === Response::TYPE_DATA) {
echo 'IP: ', $response->getArgument('address'),
' MAC: ', $response->getArgument('mac-address'),
"\n";
}
}
?>
$globalRequest = new Request('/global');
$globalRequest->setArgument('name', 'hsusername');
$globalRequest->setArgument('value', 'ActualHSUserName');
$client->sendSync($globalRequest);
$client->sendSync(new Request('/global name="hsuname" value="ActualHSUserName"'));
$mailRequest = new Request('/system script run');
$mailRequest->setArgument('number', 'mailing_script');
$client->sendSync($mailRequest);
function safeForScripting($value) {
$result = '';
for ($i=0, $l=strlen($value); $i<$l; ++$i) {
$result .= '\\' . str_pad(strtoupper(dechex(ord($value[$i]))), 2, '0', STR_PAD_LEFT);
}
return $result;
}
$scriptName = 'mailer_' . $username;
$scriptingSafeUsername = safeForScripting($username);
$scriptingSafeEmail = safeForScripting($email);
$addRequest = new Request('/system script add');
$addRequest
->setArgument('name', $scriptName)
->setArgument('source', ':local p [/ip hotspot user get "' . $scriptingSafeUsername . '" password]
/tool e-mail send subject="Forgotten hotspot password" to="' . $scriptingSafeEmail . '" body="Your hotspot password is: $p"');
$client->sendSync($addRequest);
$runRequest = new Request('/system script run');
$client->sendSync($runRequest->setArgument('number', $scriptName));
$removeRequest = new Request('/system script remove');
$client->sendSync($removeRequest->setArgument('numbers', $scriptName));
$removeRequest = new Request('/system script remove');
$client->sendSync($removeRequest->setArgument('numbers', $scriptName));
Almost . I sort of dream in algos, which may or may not be implemented in PHP (I mean silly and unrealistic algos... like "where do packets go when they die because their time to live is up?" or "how do you find if a bite of a kilo of bytes would be delicious?"... no fancy stuff like graphics, crypthography or things like that).Thanks for your code, man you're fast, you must be dreaming in php!
Any error messages by the router are part of the returned result set, just like any other response. You can inspect the different responses by looping over them, like:How can I see the error message output by the router upon the failed deletion, if any?
foreach ($client->sendSync(new Request('/system script run number="TEST"')) as $response) {
if ($response->getType() === Response::TYPE_ERROR) {
echo "Error occured:\n";
foreach ($response->getAllArguments() as $name => $value) {
echo $name, ': ', $value, "\n";
}
echo "====\n";
} else {
echo "A response which is not an error\n=====\n";
}
}
foreach ($client->sendSync(new Request('/system script run number="TEST"'))->getAllOfType(Response::TYPE_ERROR) as $response) {
foreach ($response->getAllArguments() as $name => $value) {
echo $name, ': ', $value, "\n";
}
echo "====\n";
}
Sounds like a bug, and I can confirm it happens on my RouterOS too ( 5.8 ). If you have 5.17 and it still occurs, you may want to contact support.Also wanted to ask: how does script policy work on RouterOS? I unset the "sensitive" policy of a script that reads the passwords of hotspot users, but the script was still reading the passwords!? Is it because it is a user who has the "sensitive" policy switched on who runs the script??
Fair enough. I suppose anyone hacker enough to guess a username/email combo is also hacker enough to guess an email/password(for email) combo and/or snoop around long enough to see a user change it.Concerning security and confidence, you are probably right, but with the link (which would necessarily have to be to an external website without SSL because I don't want to pay for a certificate), the hotspot passwords themselves would have to travel to and from the web server in clear text, so how is that more secure? (unless I implement chap encryption?) And at the end of the day, I am not really trying to protect sensitive information, these passwords only give internet access to a bunch of guys in a remote location and they're only useful to them. But it's true there is always the off chance that one of them will try sniffing clear text passwords off the air though.
Hello Sir,Everything but the password is in clear text. It's a CHAP challenge, just like in Hotspot - before login you get a random string, you encrypt your password with MD5, using the provided random string as a salt, and send the result (with all this being done automatically by the client, of course).
MD5 is nowadays easy to be "decrypted" to a string that would produce the same hash, but making it be decrypted to a specific string that would match a specified pattern (the pattern in this case being a null byte, followed by the password, followed by the random string) is fortunatly still relatively hard.
$printRequest = new Request('/system/script/run');
$printRequest->setArgument('number',$scriptnum);
foreach ($client->sendSync($printRequest) as $response) {
foreach ($response->getAllArguments() as $name => $value) {
echo $name, ': ', $value, "\n";
}
}
:global scanresult [int wir scan number=wlan1 duration=2]; :put $scanresult