API in C Sharp
This is C# class for connecting and working with v3.x API
Class
class MK { Stream connection; TcpClient con; public MK(string ip) { con = new TcpClient(); con.Connect(ip, 8728); connection = (Stream)con.GetStream(); } public void Close() { connection.Close(); con.Close(); } public bool Login(string username, string password) { Send("/login", true); string hash = Read()[0].Split(new string[] { "ret=" }, StringSplitOptions.None)[1]; Send("/login"); Send("=name=" + username); Send("=response=00" + EncodePassword(password, hash), true); if (Read()[0] == "!done") { return true; } else { return false; } } public void Send(string co) { Send(co, false); } public void Send(string co, bool endsentence) { byte[] bajty = Encoding.ASCII.GetBytes(co.ToCharArray()); byte[] velikost = EncodeLength(bajty.Length); connection.Write(velikost, 0, velikost.Length); connection.Write(bajty, 0, bajty.Length); if (endsentence) { connection.WriteByte(0); } } public List<string> Read() { List<string> output = new List<string>(); string o = ""; byte[] tmp = new byte[4]; long count; while (true) { tmp[3] = (byte)connection.ReadByte(); //if(tmp[3] == 220) tmp[3] = (byte)connection.ReadByte(); it sometimes happend to me that //mikrotik send 220 as some kind of "bonus" between words, this fixed things, not sure about it though if (tmp[3] == 0) { output.Add(o); if (o.Substring(0, 5) == "!done") { break; } else { o = ""; continue; } } else { if (tmp[3] < 0x80) { count = tmp[3]; } else { if (tmp[3] < 0xC0) { int tmpi = BitConverter.ToInt32(new byte[] { (byte)connection.ReadByte(), tmp[3],0,0 }, 0); count = tmpi ^ 0x8000; } else { if (tmp[3] < 0xE0) { tmp[2] = (byte)connection.ReadByte(); int tmpi = BitConverter.ToInt32(new byte[] { (byte)connection.ReadByte(), tmp[2], tmp[3],0 }, 0); count = tmpi ^ 0xC00000; } else { if (tmp[3] < 0xF0) { tmp[2] = (byte)connection.ReadByte(); tmp[1] = (byte)connection.ReadByte(); int tmpi = BitConverter.ToInt32(new byte[] { (byte)connection.ReadByte(), tmp[1], tmp[2], tmp[3] }, 0); count = tmpi ^ 0xE0000000; } else { if (tmp[3] == 0xF0) { tmp[3] = (byte)connection.ReadByte(); tmp[2] = (byte)connection.ReadByte(); tmp[1] = (byte)connection.ReadByte(); tmp[0] = (byte)connection.ReadByte(); count = BitConverter.ToInt32(tmp, 0); } else { //Error in packet reception, unknown length break; } } } } } } for (int i = 0; i < count; i++) { o += (Char)connection.ReadByte(); } } return output; } byte[] EncodeLength(int delka) { if (delka < 0x80) { byte[] tmp = BitConverter.GetBytes(delka); return new byte[1] { tmp[0] }; } if (delka < 0x4000) { byte[] tmp = BitConverter.GetBytes(delka | 0x8000); return new byte[2] { tmp[1], tmp[0] }; } if (delka < 0x200000) { byte[] tmp = BitConverter.GetBytes(delka | 0xC00000); return new byte[3] { tmp[2], tmp[1], tmp[0] }; } if (delka < 0x10000000) { byte[] tmp = BitConverter.GetBytes(delka | 0xE0000000); return new byte[4] { tmp[3], tmp[2], tmp[1], tmp[0] }; } else { byte[] tmp = BitConverter.GetBytes(delka); return new byte[5] { 0xF0, tmp[3], tmp[2], tmp[1], tmp[0] }; } } public string EncodePassword(string Password, string hash) { byte[] hash_byte = new byte[hash.Length / 2]; for (int i = 0; i <= hash.Length - 2; i += 2) { hash_byte[i / 2] = Byte.Parse(hash.Substring(i, 2), System.Globalization.NumberStyles.HexNumber); } byte[] heslo = new byte[1 + Password.Length + hash_byte.Length]; heslo[0] = 0; Encoding.ASCII.GetBytes(Password.ToCharArray()).CopyTo(heslo, 1); hash_byte.CopyTo(heslo, 1 + Password.Length); Byte[] hotovo; System.Security.Cryptography.MD5 md5; md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); hotovo = md5.ComputeHash(heslo); //Convert encoded bytes back to a 'readable' string string navrat = ""; foreach (byte h in hotovo) { navrat += h.ToString("x2"); } return navrat; } }
Class with SSL support
using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Web; using System.Web.UI.WebControls.WebParts; namespace BitWorker.Classes { public class MikrotikAPI { string _IPAddress; int _APIPort; bool _UseSSL; Stream _Stream; SslStream _SslStream; TcpClient _TcpClient; public MikrotikAPI(string IPAddress,bool UseSSL = false, int APIPort = 8728) { _IPAddress = IPAddress; _APIPort = APIPort; _UseSSL = UseSSL; } public static bool ValidateServerCertificate( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; } public void Connect() { if (_UseSSL && _APIPort == 8728) _APIPort = 8729; _TcpClient = new TcpClient(); _TcpClient.Connect(_IPAddress, _APIPort); if (_UseSSL) { _SslStream = new SslStream(_TcpClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); _SslStream.AuthenticateAsClient(_IPAddress); } else _Stream = (Stream)_TcpClient.GetStream(); } public void Disconnect() { if (_UseSSL) _Stream.Close(); else _SslStream.Close(); _TcpClient.Close(); } public bool LoginDeprecated(string Username, string Password) { Send("/login", true); string hash = Receive()[0].Split(new string[] { "ret=" }, StringSplitOptions.None)[1]; Send("/login"); Send("=name=" + Username); Send("=response=00" + EncodePassword(Password, hash), true); List<string> ReceiveResult = Receive(); if (ReceiveResult[0] == "!done") { return true; } else { return false; } } public bool Login(string Username, string Password, out string OutMessageDesc) { OutMessageDesc = ""; Send("/login"); Send("=name=" + Username); Send("=password=" + Password, true); List<string> ReceiveResult = Receive(); if (ReceiveResult[0] == "!done") { return true; } else { OutMessageDesc = ReceiveResult[1]; return false; } } public void Send(string DataToSend, bool EndofPacket = false) { if (_UseSSL) DoSendSSL(DataToSend, EndofPacket); else DoSend(DataToSend, EndofPacket); } private void DoSend(string DataToSend, bool EndofPacket = false) { byte[] DataToSendasByte = Encoding.ASCII.GetBytes(DataToSend.ToCharArray()); byte[] SendSize = EncodeLength(DataToSendasByte.Length); _Stream.Write(SendSize, 0, SendSize.Length); _Stream.Write(DataToSendasByte, 0, DataToSendasByte.Length); if (EndofPacket) _Stream.WriteByte(0); } private void DoSendSSL(string DataToSend, bool EndofPacket = false) { byte[] DataToSendasByte = Encoding.ASCII.GetBytes(DataToSend.ToCharArray()); byte[] SendSize = EncodeLength(DataToSendasByte.Length); _SslStream.Write(SendSize, 0, SendSize.Length); _SslStream.Write(DataToSendasByte, 0, DataToSendasByte.Length); if (EndofPacket) _SslStream.WriteByte(0); } public ArrayList ReceiveList() { List<string> ReceivedDataList; if (_UseSSL) ReceivedDataList = DoReceiveSSL(); else ReceivedDataList = DoReceive(); ArrayList DataList = new ArrayList(); List<string> ReceivedData = new List<string>(); foreach (string DataLine in ReceivedDataList) { if (DataLine == "!re" || DataLine == "!done" || DataLine == "!trap") { DataList.Add(ReceivedData); ReceivedData = new List<string>(); } else ReceivedData.Add(DataLine); } if (DataList.Count > 1) DataList.RemoveAt(0); return DataList; } public List<string> Receive() { if (_UseSSL) return DoReceiveSSL(); else return DoReceive(); } private List<string> DoReceive() { List<string> OutputList = new List<string>(); long TempReceiveSize; string TempString = ""; long ReceiveSize = 0; while (true) { TempReceiveSize = (byte)_Stream.ReadByte(); if (TempReceiveSize > 0) { if ((TempReceiveSize & 0x80) == 0) { ReceiveSize = TempReceiveSize; } else if ((TempReceiveSize & 0xC0) == 0x80) { TempReceiveSize &= ~0xC0; TempReceiveSize <<= 8; TempReceiveSize += (byte)_Stream.ReadByte(); ReceiveSize = TempReceiveSize; } else if ((TempReceiveSize & 0xE0) == 0xC0) { TempReceiveSize &= ~0xE0; TempReceiveSize <<= 8; TempReceiveSize += (byte)_Stream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_Stream.ReadByte(); ReceiveSize = TempReceiveSize; } else if ((TempReceiveSize & 0xF0) == 0xE0) { TempReceiveSize &= ~0xF0; TempReceiveSize <<= 8; TempReceiveSize += (byte)_Stream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_Stream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_Stream.ReadByte(); ReceiveSize = TempReceiveSize; } else if ((TempReceiveSize & 0xF8) == 0xF0) { TempReceiveSize += (byte)_Stream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_Stream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_Stream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_Stream.ReadByte(); ReceiveSize = TempReceiveSize; } } else ReceiveSize = TempReceiveSize; for (int i = 0; i < ReceiveSize; i++) { Char TempChar = (Char)_Stream.ReadByte(); TempString += TempChar; } if (ReceiveSize > 0) { OutputList.Add(TempString); if (TempString == "!done") break; TempString = ""; } } return OutputList; } private List<string> DoReceiveSSL() { List<string> OutputList = new List<string>(); long TempReceiveSize; string TempString = ""; long ReceiveSize = 0; while (true) { TempReceiveSize = (byte)_SslStream.ReadByte(); if (TempReceiveSize > 0) { if ((TempReceiveSize & 0x80) == 0) { ReceiveSize = TempReceiveSize; } else if ((TempReceiveSize & 0xC0) == 0x80) { TempReceiveSize &= ~0xC0; TempReceiveSize <<= 8; TempReceiveSize += (byte)_SslStream.ReadByte(); ReceiveSize = TempReceiveSize; } else if ((TempReceiveSize & 0xE0) == 0xC0) { TempReceiveSize &= ~0xE0; TempReceiveSize <<= 8; TempReceiveSize += (byte)_SslStream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_SslStream.ReadByte(); ReceiveSize = TempReceiveSize; } else if ((TempReceiveSize & 0xF0) == 0xE0) { TempReceiveSize &= ~0xF0; TempReceiveSize <<= 8; TempReceiveSize += (byte)_SslStream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_SslStream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_SslStream.ReadByte(); ReceiveSize = TempReceiveSize; } else if ((TempReceiveSize & 0xF8) == 0xF0) { TempReceiveSize += (byte)_SslStream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_SslStream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_SslStream.ReadByte(); TempReceiveSize <<= 8; TempReceiveSize += (byte)_SslStream.ReadByte(); ReceiveSize = TempReceiveSize; } } else ReceiveSize = TempReceiveSize; for (int i = 0; i < ReceiveSize; i++) { Char TempChar = (Char)_SslStream.ReadByte(); TempString += TempChar; } if (ReceiveSize > 0) { OutputList.Add(TempString); if (TempString == "!done") break; TempString = ""; } } return OutputList; } private byte[] EncodeLength(int delka) { if (delka < 0x80) { byte[] tmp = BitConverter.GetBytes(delka); return new byte[1] { tmp[0] }; } if (delka < 0x4000) { byte[] tmp = BitConverter.GetBytes(delka | 0x8000); return new byte[2] { tmp[1], tmp[0] }; } if (delka < 0x200000) { byte[] tmp = BitConverter.GetBytes(delka | 0xC00000); return new byte[3] { tmp[2], tmp[1], tmp[0] }; } if (delka < 0x10000000) { byte[] tmp = BitConverter.GetBytes(delka | 0xE0000000); return new byte[4] { tmp[3], tmp[2], tmp[1], tmp[0] }; } else { byte[] tmp = BitConverter.GetBytes(delka); return new byte[5] { 0xF0, tmp[3], tmp[2], tmp[1], tmp[0] }; } } private string EncodePassword(string Password, string hash) { byte[] hash_byte = new byte[hash.Length / 2]; for (int i = 0; i <= hash.Length - 2; i += 2) { hash_byte[i / 2] = Byte.Parse(hash.Substring(i, 2), System.Globalization.NumberStyles.HexNumber); } byte[] heslo = new byte[1 + Password.Length + hash_byte.Length]; heslo[0] = 0; Encoding.ASCII.GetBytes(Password.ToCharArray()).CopyTo(heslo, 1); hash_byte.CopyTo(heslo, 1 + Password.Length); Byte[] hotovo; System.Security.Cryptography.MD5 md5; md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); hotovo = md5.ComputeHash(heslo); //Convert encoded bytes back to a 'readable' string string navrat = ""; foreach (byte h in hotovo) { navrat += h.ToString("x2"); } return navrat; } } }
Example
using System.IO; using System.Net.Sockets; class Program { static void Main(string[] args) { MK mikrotik = new MK("your ip here"); if (!mikrotik.Login("username", "password")) { Console.WriteLine("Could not log in"); mikrotik.Close(); return; } mikrotik.Send("/system/identity/getall"); mikrotik.Send(".tag=sss", true); foreach (string h in mikrotik.Read()) { Console.WriteLine(h); } Console.ReadKey(); } }
Example 2
Block SMTP port and specific Ip rule by Oguzhan
using System.IO; using System.Net.Sockets; class Program { static void Main(string[] args) { string ip = args[0]; MK mikrotik = new MK("your ip here"); if (mikrotik.Login("admin", "P@ssW0rd")) { mikrotik.Send("/ip/firewall/filter/add"); mikrotik.Send("=action=drop"); mikrotik.Send("=chain=forward"); mikrotik.Send("=dst-port=25"); mikrotik.Send("=protocol=tcp"); mikrotik.Send("=protocol=tcp"); mikrotik.Send(String.Format("=src-address={0}",ip)); mikrotik.Send(".tag=firewall", true); foreach (string h in mikrotik.Read()) { Console.WriteLine(h); } } } }
Notes
- I have not tested it thorougly (especialy length encoding with longer words)
- You have to have using System.IO; and using System.Net.Sockets;
- Exceptions are not handled