API question

I’ve been managing my MT’s through software I wrote using Telnet & FTP, but would like to start to use the ROS3 API as telnet doesn’t always return consistent result with ROS3 and it would give me more functionality.

Just a question on the send/receive of commands.
To send ‘/login’, I’d have to send (hex):
07 2F 6C 6F 67 69 6E 00
length / l o g i n

Is this correct?
I use Delphi and do not understand the Python example so well…

In hex you should send:
06 2F 6C 6F 67 69 6E 00

because length of ‘/login’ = 6

Thanks for that. Got that part working.
Two more questions:

/login
!done
=ret=8d3a824d2f706e0685f0ceccf6ab86c4
/login
=name=admin
=response=73A3FBF0034B26B3D033759C84775A9E
!trap
=message=cannot log in

1)Should I do something with the =ret=string?
2)Is the =response=string I must send a MD5 hash of the password?

If I send this to a RB133C with ROS3.2, the cPU stays on 100% until I power-cycle or reboot if I can get into it(slow).

Thanks
Ekkas

no,response should be
/login
=name=user
=response=00 + md5hash

where md5hash is calculated from:
“00” + convertToHex(“password”) + response

Please read wiki
http://wiki.mikrotik.com/wiki/API

Thanks for that, I read the WIKI, but only found this:
Reply contains =ret=challenge argument.
Client sends second /login command, with =name=username and =response=response.
In case of error, reply contains =ret=error message.

I do this:
S:=‘=response=00’+GetMD5(‘00’+lowercase(MyToHex(password))+ChallengeStr);


which results in:
/login
=name=admin
=response=00633d8f7e95ae168e28032f626c9757b4

But it still doesn’t work.

Thanks for the help so far.
Ekkas

You get string of hex values from this “00”+lowercase(MyToHex(password))+ChallengeStr
but md5 should be generated from array of bytes, so
*) you must convert hex string to bytes
*) generate md5 from bytes you get from previous operation
*) convert bytes you got from md5 to hex string


Just look at python example in wiki, everything you need is written there.

Here is another discussion:
http://forum.mikrotik.com/t/api-login-and-md5/18926/1

Thanks a lot, I got it working with:

S:=HexToAscii(ChallengeStr);
S:=‘=response=00’+GetMD5(#0+password+S);

(For what its’ worth.)
Ekkas

Hello

Somebody could send me example in Delphi 7 ?

Thanks

You need to use Indy 10, paste the stuff below as a unit. At the bottom is an example to show packages on the RB. This should be enough to get you going. If you refine/improve it, please report back here so all can share in the ‘fun’. Maybe I’ll post this in the WIKI but if you feel like it, go ahead, just mention me there.

unit MikrotikAPI;

interface

uses Classes,IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, StdCtrls,
Buttons, IdAntiFreezeBase, IdAntiFreeze, IdIOHandlerStream;

type TMikrotikAPI = class(TComponent)
Client : TidTCPClient;
Log,
Response:TStringList;
constructor Create;
destructor Destroy;
function Connect(TCPClient:TidTCPClient;Host:String;Port:Integer):Boolean;
procedure Disconnect;
function LogOn(Username,Password:String):Boolean;
procedure Write(S:String);
function Read:String;
function ReadStr: String;
procedure WriteStr(S: String);
private
end;


implementation

{ TMikrotikAPI }

uses IdOTPCalculator,idHashMessageDigest,SysUtils;

function StrToHex(O:String):String;
var i : Integer;
begin
Result:=‘’;
for i:=1 to Length(O) do
begin
Result:=Result+lowercase(IntToHex(Integer(O_),2));
end;
end;

Function GetMD5(Source:String):String;
var MD5:TIdHashMessageDigest5;
begin
MD5:=TIdHashMessageDigest5.Create;
try
Result:=MD5.AsHex(MD5.HashValue(Source));

finally
MD5.Free;
end;
end;

function TMikrotikAPI.Connect(TCPClient:TidTCPClient;Host:String;Port:Integer): Boolean;
begin
try
Response.Clear;
Log .Clear;
Client:=TCPClient;
Client.Host:=Host;
Client.Port:=Port;
Client.Connect;
Result:=True
except
Result:=False;
end;
end;

procedure TMikrotikAPI.Disconnect;
begin
Client.Disconnect;
end;

function TMikrotikAPI.LogOn(Username,Password:String): Boolean;
var S : String;
IC: TIdOTPCalculator;
begin
Write(‘/login’);
S:=ReadStr; (!done)
S:=ReadStr; (=ret)
ReadStr; (0)

S:=Copy(S,6,Length(S));
S:=HexToAscii(S);
S:=‘=response=00’+GetMD5(#0+password+S);
Write(‘/login’#13#10’=name=‘+username+#13#10+S);

{ chal=MessageDigestHelper.myHexStrToStr(“00”) + password + MessageDigestHelper.myHexStrToStr(transition);
chal = MessageDigestHelper.myMD5Helper(chal); }


Read;
Result:=Response[0]=’!done’;
end;

function TMikrotikAPI.ReadStr:String;
var LN1 : Byte;
LN,I : Integer;
TS : String;
begin
Result:=‘’;
LN1:=Ord(Client.IOHandler.ReadChar);
LN :=LN1;
if LN1=0
then exit;
if LN1>128
then begin
LN1:=Ord(Client.IOHandler.ReadChar);
if LN1>128
then begin
LN:=LN+LN1 shl 8;
LN1:=Ord(Client.IOHandler.ReadChar);
if LN1>128
then begin
LN:=LN+LN1 shl 16;
end;
end;
end;
SetLength(TS,LN);
for I:=0 to LN-1 do
TS[i+1]:=Client.IOHandler.ReadChar;
Result:=TS;
Log.Add(TS);
end;

procedure TMikrotikAPI.WriteStr(S:String);
var I : Integer;
begin
if Length(S)>128
then Log.Add(‘< String to long.’);
Client.IOHandler.Write(Char(Length(S)));
for i:=1 to Length(S) do
Client.IOHandler.Write(S);
Log.Add(‘>’+S);
end;

function TMikrotikAPI.Read: String;
var TS : String;
begin
Response.Clear;
repeat
TS:=ReadStr;
if TS<>‘’
then Response.Add(TS);
until TS=‘!done’;
Result:=Response.Text;
end;

procedure TMikrotikAPI.Write(S: String);
var SL : TStringList;
i : Integer;
begin
if Pos(#13#10,S)>0
then begin
SL:=TStringList.Create;
SL.Text:=S;
for i:=0 to SL.Count-1 do
begin
WriteStr(SL);
end;
SL.Free;
end
else begin
WriteStr(S);
end;
Client.IOHandler.Write(#0);
end;

constructor TMikrotikAPI.Create;
begin
Response:=TStringList.Create;
Log :=TStringList.Create;
end;

destructor TMikrotikAPI.Destroy;
begin
Response.Free;
Log .Free;
inherited;
end;

end.

{

IP:=‘192.168.0.1’;
Password:=‘password’;
SL:=TStringList.Create;

TCP:=TidTCPClient.Create;
MT :=TMikrotikAPI.Create;
if not MT.Connect(TCP,IP,8728)
then begin
ShowMessage(‘WARNING : ‘+IP+’ : API inactive?’);
MT.Free;
TCP.Free;
end
else begin
MT.Logon(‘admin’,Password);
MT.Write(‘/sys/pack/pr’);
S1:=MT.Read;
SL.Text:=S1;
i:=0;
while i<SL.Count do
begin
if Copy(SL,1,6)=‘=name=’
then begin
S1:=SL;
Delete(S1,1,6);
SL:=S1;
if SL=‘routeros-mipsle’
then SL.Delete(i)
else Inc(i);
end
else begin
SL.Delete(i);
end;
end;
MT.Disconnect;
MT.Free;
TCP.Free;
end;
ShowMessage(SL.Text);
}_

Thak you Ekkas !

I not found HexToAscii function. Where found it ?

That is in the JvCSVParse.pas file that comes if you use the JEDI library, but here it is :

function HexToAscii(const S: string): string;
var
I, Y, L: Integer;
C: array [0..256] of Char;
begin
L := Length(S) div 2;
for I := 0 to L - 1 do
begin
Y := (I * 2) + 1;
C := Char(HexDigitVal(S[Y]) * 16 + HexDigitVal(S[Y + 1]));
end;
C[L] := Chr(0);
Result := C;
end;

and…

const
HexadecimalUppercaseLetters = [‘A’..‘F’];
HexadecimalLowercaseLetters = [‘a’..‘f’];


function HexDigitVal(C: Char): Integer;
begin
if C in DigitSymbols then
Result := Ord(C) - Ord(‘0’)
else
if C in HexadecimalLowercaseLetters then
Result := Ord(C) - Ord(‘a’) + 10
else
if C in HexadecimalUppercaseLetters then
Result := Ord(C) - Ord(‘A’) + 10
else
Result := 0;
end;

and yet again…

const
DigitSymbols = [‘0’..‘9’];

Thank you agaon Ekkas ! :slight_smile:

It’s work.

please consider that you can send different line length over using api, and depending the length there are different possibilities of what you can receive back.

1 char in front showing the len of command or return string is for string that are less then 255 symbols in API example you can see what value you will receive or have to send if you want to send longer commands.

for example, if you send and receive scripts you will need this.