API in C Sharp
From MikroTik Wiki
This is C# class for connecting and working with v3.x API
Contents
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