-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement initial login for ROS v6.43+ #37
Comments
Thanks for the heads up. I hadn't seen the latest RC... I probably would've started implementing this shortly after the release of 6.43. From a test with 6.42, it appears it's possible to make the login agnostic to RouterOS version - the new method (PAP) will be attempted first, and if there is no error and a challenge, then the client can fallback to the pre-6.43 login (CHAP), which is what I will do. |
Hi, i already updated script to login with version 6.43.
|
If new version of ROS require unsecured password challenge, It look like that RouterOS in some newer versions deprecate or remove unsecured API. |
@RAD-X Newer PHP versions (everything 7.2 and above, plus some higher earlier ones) are better, in that if you keep the payload under around 512KBs per request/response cycle, it should work fine. It's still not exactly stable for all intents and purposes. Notable use cases that are likely to spontaneously cause errors are anything that involves long running continuous commands like "torch". Both before and now, if you want an encrypted API connection with PHP, it's better to set up the web server and router so that they are both clients in an encrypted VPN, and connect with an unencrypted connection inside the encrypted VPN. |
i am really curious why mikrotik opted for a pap-like login, kind of forcing us to go SSL soon. i did actually mail mikrotik about this. while they are generally VERY nice and helpful, on this particular request i basically got a "dont worry, in the future, passwords will be encrypted!" (?) reply. sad :x |
Version 6.43 has been released. |
Where would one implement this? Also will it slow down the request at all considering its checking the version in order to set |
@sieberlukas To be perfectly honest, I find your solution somewhat duct-tape-ish, but at the same time, I keep finding myself with not enough time to make a more robust and future proof implementation, so if you make a pull request, I'll merge it. @borsn |
@boenrobot I edited the script so that it was not so duck-tape-ish? private static function _login(
Communicator $com,
$username,
$password = '',
$timeout = null
) {
$request = new Request('/login');
$request->setArgument('name', $username);
$request->setArgument('password', $password);
$request->verify($com)->send($com);
$response = new Response($com, false, $timeout);
if ($response->getType() === Response::TYPE_FINAL && null === $response->getProperty('ret')) {
// version >= 6.43
return null === $response->getProperty('message');
} elseif ($response->getType() === Response::TYPE_FINAL) {
// version < 6.43
$request->setArgument('password', '');
$request->setArgument(
'response',
'00' . md5(
chr(0) . $password
. pack('H*', $response->getProperty('ret'))
)
);
$request->verify($com)->send($com);
$response = new Response($com, false, $timeout);
if ($response->getType() === Response::TYPE_FINAL) {
return null === $response->getProperty('ret');
}
}
while ($response->getType() !== Response::TYPE_FINAL
&& $response->getType() !== Response::TYPE_FATAL
) {
$response = new Response($com, false, $timeout);
}
return false;
} |
@sieberlukas When I say duct-tape-ish, I'm not talking about the method itself, but the whole login process... The method itself is fine (which is why I'll accept a PR). But I'm thinking it will be best to somehow have a dedicated static method for each login method (i.e. allow users to call only a specified method), and have "login" be a version agnostic way that will try all methods before giving up. The hard part (due to which I haven't done this already) is to design the architecture in such a way that, if a 3rd login method appears, one can define it in their own class or callback, and register it with "login" to be performed before falling back to the previously registered methods... And all of that in a way that lets each method work regardless of whether it's in or not in a persistent connection. Furthermore, this new method has error replies, while the old one didn't. It would be good if error replies (in full, not just their messages) are exposed to the caller in some fashion, but at the same time, there should be a way to indicate general failure for the old method, where you know there's an error, but no message to go along with it. |
Merged. Thank you. |
I've switched to the develop branch but now, after crawling a list of mikrotik devices, I get this as reply: Any way this is related to this change request and what might be causing it? Could it be version related? |
The most typical reason for the "This is not a compatible RouterOS service" error is that the API port isn't actually used by the API, but by something else, be it the router's HTTP server, SSH server... Also, if you're using the api-ssl port but haven't declared so in the constructor or vice-versa. |
The API port is not used for anything else, even devices with an out of the box default config do not work on this beta version. I've switched back to the master branch and all these devices work fine again. Only devices on 6.45beta54 no longer want to connect (invalid user/password). Any idea what changed during this beta that impacts this? |
I haven't looked into it at all yet. If you could run "roscon" over the router without login, and attempt to actually do the login via the new method, we might get some idea of what's going on, since roscon will display the raw data, including possibly the unrecognized control byte that made it trip up. |
@Yentel I set up a new VM with 6.45.1, and ran my whole unit tests, and something interesting popped up with regards to the "incompatible service error"... It seems MikroTik's new password method causes problems when the password contains non-ASCII characters and you're using charset conversion. PHP's iconv() fails to convert the password, causing an exception to be thrown, which is then caught, and because the error is during the login, and is not a recognized one (like "wrong password"), the conclusion is that this is not a compatible API service. Since the new method is always tried first, before a fallback to the old one, this problem exists even if your router is older than 6.43. What matters only is that your password needs charset conversion. If that's your issue, then the solution for now is to change the password to one limited to only ASCII characters, and remove calls to setDefaultCharset in favor of setCharset after the login. |
According to the new Router OS version, the login parameters changed. Now we need to send the password with the name of the password instead of response and the encryption is not needed. |
Is a phar file including the fix available for download ? |
Work for me. Thanks!
|
Who helps me I am using PEAR2 which does not work for Mikrotik version 6.46.3 here the code that I must change private static function _login( |
Thanks , i replaced all this code in PEAR2_Net_RouterOS-1.0.0b6/src/PEAR2/Net/RouterOSClient.php and now i can login to my rb: private static function _login(
} |
tnx @ubntomar |
just logged in to say: you saved my ass. thank you. you know the story: some guy in my company implemented a raspi with this interface and then some other guy updated the mikrotiks and then... BOOM. No more wifi for guests. The first guy is not available some months and i am the one left to fix this with absolutely no glue. i copied this into my client.php and bazinga! it works! Cheers! |
See https://wiki.mikrotik.com/wiki/Manual:API#Initial_login
But I'm not sure if it is possible to get ROS version before login. But without this change it won't be possible to use Net_RouterOS with v6.43+
The text was updated successfully, but these errors were encountered: