; Version 1.0.2 ;=============================================================================== ; REQUIREMENTS: ; ; TCPStartup() - have to be used befor using any of these functions!!! ; TCPShutdown() - should be used at the end!!! ;=============================================================================== ;======================= ; Include ;======================= #include #include #include ;=============================================================================== ; ; Function Name: _mkt_connect() ; Description: Creates a new connection to a mikrotik device ; Parameter(s): $IPaddr - IP address of the mikrotik device ; $port - API port to mikrotik ; - optional - using the default port if not provided ; Requirement(s): AutoIt ; Return Value(s): On Success - Returns socket ID for further communication ; On Failure - Returns 0 and sets @ERROR ; @ERROR = 1 - IP Address is incorrect ; @ERROR = 2 - Port is incorrect ; @ERROR = number returned by windows API WSAGetError - see http://msdn.microsoft.com/en-us/library/ms740668.aspx for details ; Author(s): UncleFester ; ;=============================================================================== Func _mkt_connect($IPaddr, $port = 8728) Local $socket = TCPConnect($IPaddr, $port) If @error = 1 Then SetError(1) Return 0 ElseIf @error = 2 Then SetError(2) Return 0 ElseIf @error > 2 Then SetError(@error) Return 0 Else Return $socket EndIf EndFunc ;==>_mkt_connect ;=============================================================================== ; ; Function Name: _mkt_login() ; Description: Login to a mikrotik device using given credentials ; Parameter(s): $socket - socket identifier given by _mkt_connect() ; $user - username to mikrotik device ; - optional - using the default user "admin" if not provided ; $pass - password to mikrotik device ; - optional - using the default password (none) if not provided ; Requirement(s): AutoIt ; Return Value(s): On Success - Returns 1 ; On Failure - Returns 0 and sets @ERROR ; @ERROR = 1 - Unable to send command ; @ERROR = 2 - Unable to send finish line ; @ERROR = 3 - Problem while receiving data from connected socket ; @ERROR = 4 - Login wasn`t successful, challenge invalid/not received ; @ERROR = 5 - Counldn`t log in, wrong username or password ; @ERROR = 6 - Counldn`t log in, unknown error ; @ERROR = 7 - Decimal To Binary - Wrong input, or something went wrong in there ; @ERROR = 8 - Binary to Decimal - Wrong input, or something went wrong in there ; Author(s): UncleFester ; ;=============================================================================== Func _mkt_login($socket, $user = "admin", $pass = "") Local $recv Local $number = 9999 ;gotta be different from 0 Local $challenge Local $hashed_data _mk_SendCommand($socket, "/login") _mk_SendFinish($socket) If @error = 2 Then SetError(1) Return 0 ElseIf @error = 3 Then SetError(2) Return 0 ElseIf @error = 7 Then SetError(7) Return 0 ElseIf @error = 8 Then SetError(5) Return 0 EndIf While True $recv = TCPRecv($socket, 1400, 1) If @error Then SetError(3) Return 0 EndIf $recv = BinaryToString($recv, 4) If $recv <> "" Then ;~ ConsoleWrite("Data from login: " & $recv & @CRLF) ;for error checking $number = Asc(StringLeft($recv, 1)) ;number of characters in next line $recv = StringTrimLeft($recv, $number + 1) ;delete that line $number = Asc(StringLeft($recv, 1)) ;number of characters in next line $recv = StringTrimLeft($recv, 1) ;delets number char ;~ ConsoleWrite(StringLen($recv) - 1 & "=" & $number) ;for error checking If StringLen($recv) - 1 = $number Then If StringInStr($recv, "=ret=") Then $challenge = StringSplit($recv, "=ret=", 1) $challenge[2] = StringTrimRight($challenge[2], 1) ExitLoop Else SetError(4) Return 0 EndIf Else SetError(4) Return 0 EndIf EndIf WEnd _Crypt_Startup() $hashed_data = _HexToString("00") & String($pass) & _HexToString($challenge[2]) $hashed_data = _Crypt_HashData($hashed_data, $CALG_MD5) $hashed_data = StringLower(StringTrimLeft($hashed_data, 2)) _mk_SendCommand($socket, "/login") _mk_SendCommand($socket, "=name=" & $user) _mk_SendCommand($socket, "=response=00" & $hashed_data) _mk_SendFinish($socket) If @error = 2 Then SetError(1) Return 0 ElseIf @error = 3 Then SetError(2) Return 0 ElseIf @error = 7 Then SetError(7) Return 0 ElseIf @error = 8 Then SetError(5) Return 0 EndIf _Crypt_Shutdown() While True $recv = TCPRecv($socket, 1400, 1) If @error Then SetError(3) Return 0 EndIf $recv = BinaryToString($recv, 4) If $recv <> "" Then ;~ ConsoleWrite("Login response: " & $recv & @CRLF) ;for error checking If StringInStr($recv, "!trap") Then SetError(5) Return 0 ElseIf StringInStr($recv, "!done") Then Return 1 Else SetError(6) Return 0 EndIf EndIf WEnd EndFunc ;==>_mkt_login ;=============================================================================== ; ; Function Name: _mkt_command() ; Description: Sends command to a mikrotik device ; Parameter(s): $socket - socket identifier given by _mkt_connect() ; $command - command to send ; Requirement(s): AutoIt ; Return Value(s): On Success - Returns array containing lines returned by mikrotik ; On Failure - Returns 0 and sets @ERROR ; @ERROR = 1 - Unable to send command ; @ERROR = 2 - Unable to send finish line ; @ERROR = 3 - Problem while receiving data from connected socket ; @ERROR = 4 - Decimal To Binary - Wrong input, or something went wrong in there ; @ERROR = 5 - Binary to Decimal - Wrong input, or something went wrong in there ; @ERROR = 5 - BinaryToString function returned an error ; Author(s): UncleFester ; ;=============================================================================== Func _mkt_command($socket, $command) Local $recv Local $number = 9999 ;gotta be different from 0 Local $linecount Local $array_size = 0 Local $data Local $tString Local $tString2 _mk_SendCommand($socket, $command) _mk_SendFinish($socket) If @error = 2 Then SetError(1) Return 0 ElseIf @error = 3 Then SetError(2) Return 0 ElseIf @error = 7 Then SetError(4) Return 0 ElseIf @error = 8 Then SetError(5) Return 0 EndIf While True $recv = TCPRecv($socket, 1400, 1) If @error Then ;~ ConsoleWrite("Win API error:" & @error & @CRLF) ;if you wanna know SetError(3) Return 0 EndIf ;~ ConsoleWrite("Pure binary data received:" & $recv & @CRLF) ;if you wanna know ; This whole segment fixes a problem with AutoIt's BinaryToString() considering ascii "00" (CR) as the ending string of a sentance. ; The problem is that the binary data consists of more than one string, and each string is terminated with "00". ; So first replace all the NULL characters (acsii "00" - CR), to see the all the data in the string. For $n = 1 To (BinaryLen($recv) * 8) Step 2 $tString = StringMid($recv, $n, 2) If $tString <> "00" Then $tString2 &= $tString Else $tString2 &= "" ; remove the CRs EndIf Next ;~ ConsoleWrite("Binary data after fix:" & $tString2 & @CRLF) ;if you wanna know $recv = BinaryToString($tString2, 4) If $recv = "" Then ;~ ConsoleWrite("BinaryToString error:" & @error & @CRLF) ;if you wanna know SetError(6) Return 0 EndIf If $recv <> "" Then ;~ ConsoleWrite("Data received:" & $recv & @CRLF) ;if you wanna know $linecount = $recv While $number <> 0 ;count number of lines returned by mikrotik $number = Asc(StringLeft($linecount, 1)) ;number of characters in next line $linecount = StringTrimLeft($linecount, $number + 1) ;delete that line $array_size += 1 WEnd Dim $data[$array_size + 1] ;creating an array with right size $data[0] = 0 $number = 9999 ;something different from 0, because previous While loop returns 0 While $number <> 0 ;filling the array with lines $data[0] += 1 $number = Asc(StringLeft($recv, 1)) ;number of characters in next line $recv = StringTrimLeft($recv, 1) ;delete number char $data[$data[0]] = StringLeft($recv, $number) ;read and save line $recv = StringTrimLeft($recv, $number) ;delete that line WEnd $data[0] -= 1 ;because last lines is 0 _ArrayDelete($data, $data[0] + 1) Return ($data) EndIf WEnd EndFunc ;==>_mkt_command ;=============================================================================== ; ; Function Name: _mkt_disconnect() ; Description: Terminates conection to mikrotik device ; Parameter(s): $socket - socket identifier given by _mkt_connect() ; $command - command to send ; Requirement(s): AutoIt ; Return Value(s): On Success - Returns 1 ; On Failure - Returns 0 and sets @ERROR = 1 ; Author(s): UncleFester ; ;=============================================================================== Func _mkt_disconnect($socket) TCPCloseSocket($socket) If @error Then SetError(1) Return 0 EndIf Return 1 EndFunc ;==>_mkt_disconnect #region Support functions ;do description at some point!!! Func _mk_SendCommand($socket, $command) ;translates commands into the right format Local $cLen = BinaryLen(Binary($command)) ;calculate the length of the command Local $eLen Local $rawPacket Select ;selecting the way Case $cLen < 0x80 $eLen = Chr(StringLen($command)) $rawPacket = $eLen & $command Case $cLen < 0x4B0 Local $temp = _DecToBinary(BitOR($cLen, 0x8000)) If @error = 1 Then SetError(7) Return 0 EndIf $eLen = _StringChop($temp, 8) For $i = 1 To $eLen[0] $rawPacket &= Chr(_BinaryToDec($eLen[$i])) If @error = 1 Then SetError(8) Return 0 EndIf Next $rawPacket &= $command Case Else ;won`t work for commands longer then 0x4B0 now, at some point should be finished SetError(1) Exit EndSelect TCPSend($socket, Binary($rawPacket)) If @error Then SetError(2) Return 0 EndIf EndFunc ;==>_mk_SendCommand Func _mk_SendFinish($socket) TCPSend($socket, Binary(Chr(0))) ;sending the finishing socket of zeros If @error Then SetError(3) Return 0 EndIf EndFunc ;==>_mk_SendFinish Func _StringChop($String, $size) Local $count $count = Ceiling(StringLen($String) / $size) Dim $array[$count + 1], $start = 1 For $i = 1 To $count $array[$i] = StringMid($String, $start, $size) $start += $size Next $array[0] = $count Return $array EndFunc ;==>_StringChop ; Decimal To Binary Func _DecToBinary($iDec) Local $i, $x, $sBinChar = "" If StringRegExp($iDec, '[[:digit:]]') Then $i = 1 Do $x = 16 ^ $i $i += 1 ; Determine the Octets Until $iDec < $x For $n = 4 * ($i - 1) To 1 Step -1 If BitAND(2 ^ ($n - 1), $iDec) Then $sBinChar &= "1" Else $sBinChar &= "0" EndIf Next Return $sBinChar Else SetError(1) Return 0 EndIf EndFunc ;==>_DecToBinary ; Binary to Decimal Func _BinaryToDec($strBin) Local $Return Local $lngResult Local $intIndex Local $strDigit If StringRegExp($strBin, '[0-1]') Then $lngResult = 0 For $intIndex = StringLen($strBin) To 1 Step -1 $strDigit = StringMid($strBin, $intIndex, 1) Select Case $strDigit = "0" ; do nothing Case $strDigit = "1" $lngResult = $lngResult + (2 ^ (StringLen($strBin) - $intIndex)) Case Else ; invalid binary digit, so the whole thing is invalid $lngResult = 0 $intIndex = 0 ; stop the loop EndSelect Next $Return = $lngResult Return $Return Else SetError(2) Return 0 EndIf EndFunc ;==>_BinaryToDec #endregion Support functions