@cmd = ("/category/command", "keyword1=value1", "keyword2=value2");
($rc, @response) = Mtik::talk(\@cmd);
my @cmd = ("/ip/firewall/filter/remove", "$rowno");
my($retval,@results) = Mtik::talk(\@cmd);
# Remove a camera/IPA pair from the firewall list.
# Returns 0 if it was removed, or a negative number if it wasn't.
# Inputs:
# The camera resource name (which is also used as the name of
# its chain in the firewall)
# The source (i.e., user's) IP address
sub mtik_access_remove
{
my($chain) = shift;
my($ipa) = shift;
# First see whether it's already in the list
my($rc, @firewall) = mtik_get_firewall;
if ($rc) {
return $rc;
}
my($rowno) = mtik_find_entry_in_firewall(\@firewall, $chain, $ipa);
if ($rowno < 0) {
print "IPA $ipa not found in chain $chain\n";
return -1;
}
# It's there, so try to remove it
# my @cmd = ("/ip", "firewall", "filter", "remove", "$rowno");
my %operands;
$operands{'numbers'} = $firewall[$rowno]{".id"};
my($retval,@results) = Mtik::mtik_cmd("/ip/firewall/filter/remove", \%operands);
if ($retval != 1) {
print "removal of IPA $ipa from $chain failed. RC = $retval\n$Mtik::error_msg\n";
return $retval;
}
return 0;
}
[code]
Note the way I test $retval for a value of 1 (instead of 0) for "success". I translate it to 0 for code calling my functions, since I'm used to the convention of "0 for success, non-zero for failure".
Thanks again for sharing. I hope others find this record of my mistakes useful in avoiding repeating them.
Ran
use .id to remove entries, in this case, do print and get a list of rules with .id numbers, then parse the result and get what rules you want to remove.
also when you add a rule, you get the .id number of the rule, so if in the same session you want to remove the rule you can use returned .id number of the rule to remove it in the end
Thanks for the code - but I would like to write that the read_len() function in mtapi.pl is completely wrong. For one byte lengths it works (but only by accident - the initial IF statement is not correct).[New version uploaded 3/26/2008. Fixed a bug which caused command output to hang sometimes, and added simple command line client]
Attached should be a ZIP with three files:
Mtik.pm - a simple perl client for the Mtik API. Pretty much a perl port of the python client from the Wiki, with an extra routine or two for formatting the returned data.
mtik_api_example.pl - an example of how to use the API. Provides some useful wireless ACL control routines. I've included enough comments so you should be able to work out how it all hangs together.
mtik_tty.pl - a simple command line client for testing API commands with. Use -h switch for usage info.
This code is very much a first cut. I intend to make the Mtik.pm stuff object oriented, so it can support more than one open Mtik connection at a time, but for now it is purely function driven. I needed it in a hurry!
Please feel free to feed back comments, suggestions, bug reports or light bulb jokes. Also feel free to modify, redistribute and generally do what you will with the code.
Share And Enjoy.
-- hugh
print $sock chr(($len >> 8) & 0xFF);
print $sock chr(($len >> 8) & 0xFF);
print $sock chr(($len >> 8) & 0xFF);
print $sock chr(($len >> 24) & 0xFF);
print $sock chr(($len >> 16) & 0xFF);
print $sock chr(($len >> 8) & 0xFF);
so your code islen >= 0x10000000
0xF0 and len as four bytes
elsif ($len < 0x10000000)
{
$len |= 0xE0000000;
$bytes=$len < 0x80? 1 : $len < 0x4000? 2 : $len < 0x200000? 3 : $len < 0x10000000? 4 : 5;
$len|=(0x0F >> (5-$bytes)) << ($bytes*8-$bytes+1);
while ($bytes--)
{
$str.=chr($len & 0xFF);
$len>>=8;
}
elsif ($len < 0x10000000)
...
elsif ($len < 0x10000000)
sub read_len
{
my ($len,$c,$bytes);
$sock->recv($c,1);
$c=ord($c);
$bytes=$c<0x80? 0 : $c<0xC0? 1 : $c<0xE0? 2 : $c<0xF0? 3 : 4;
$len=$c & (0xFF >> $bytes);
$bytes or return $len;
while ($bytes--)
{
$sock->recv($c,1);
$len=($len << 8) + ord($c);
}
return $len;
}
if ($word =~ /!done/)
{
$retval = 1;
}
if ($word =~ /^!done/)
{
$retval = 1;
}
=name=system!done
What's new in 3.25:
*) api - do not accept truncated property names;
sub read_sentence {
my ($word);
my ($i) = 0;
my (@reply);
my($retval) = 0;
my($done) = 0;
# tu trzeba dopisać obsluga trap
while ($word = &read_word())
{
if ($word =~ /^!done/)
{
$retval = 1;
$done=1;
}
elsif ($word =~ /^!trap/)
{
$retval = 2;
}
elsif ($word =~ /^!fatal/)
{
$retval = 3;
}
$reply[$i++] = $word;
if ($debug > 2)
{
print STDERR "MT: $word\n"
}
}
return ($done,$retval,@reply);
}
######## PUBLIC FUNCTIONS ############
sub talk
{
#my(@sentence) = shift;
my($sentence_ref) = shift;
my(@sentence) = @$sentence_ref;
&write_sentence(\@sentence);
my(@reply);
my(@attrs);
my($i) = 0;
my($retval) = 0;
my($done) = 0;
while (($done,$retval,@reply) = &read_sentence())
{
foreach my $line (@reply)
{
if ($line =~ /^=(\S+)=(.*)/)
{
$attrs[$i]{$1} = $2;
}
}
if ($retval > 0 && $done>0)
{
last;
}
$i++;
}
return ($retval, @attrs);
}
How many client stations is connected to this mikrotik?
There is a bug which losts data when you try to get more then 1KB data.
Try to change first doanloaded perl api and apply all canges on forum site in this thread.
#!/usr/bin/perl
use strict;
use warnings;
use Mtik;
use Data::Dumper;
my $mt = Mtik->new( host => 'host', user => 'admin', pass => 'pass');
if ($mt->login()) {
my $regtable_api = $mt->get_by_key('/interface/wireless/registration-table/print','=stats', 'mac-address');
print Dumper $regtable_api;
}
localhost sbin # perl dupa.pl
$VAR1 = {
'00:15:6D:D0:0F:F5' => {
'rx-ccq' => '17',
'hw-frame-bytes' => '42100172,7240063',
'packets' => '49461,38274',
'nstreme' => 'false',
'ack-timeout' => '28',
'uptime' => '08:03:54',
'interface' => 'wlan3',
'last-activity' => '00:00:03.350',
'frame-bytes' => '40615897,6306238',
'mac-address' => '00:15:6D:D0:0F:F5',
'framing-mode' => 'none',
'802.1x-port-enabled' => 'true',
'routeros-version' => '3.2',
'ap' => 'false',
'bytes' => '40910305,6535882',
'signal-to-noise' => '34',
'tx-ccq' => '97',
'radio-name' => 'Motozbyt',
'frames' => '49461,38274',
'hw-frames' => '49738,38665',
'tx-frames-timed-out' => '0',
'compression' => 'false',
'wmm-enabled' => 'false',
'p-throughput' => '18146',
'tx-signal-strength' => '-67',
'wds' => 'false',
'signal-strength' => '-70dBm@6Mbps',
'comment' => '',
'.id' => '*4',
'rx-rate' => '12Mbps',
'strength-at-rates' => '-70dBm@6Mbps 1s350ms,-70dBm@9Mbps 18s380ms,-71dBm@12Mbps 3s350ms,-71dBm@18Mbps 3m39s750ms,-72dBm@24Mbps 3m43s620ms',
'tx-rate' => '24Mbps'
},
/queue/simple-table/print
#lists queues
>>> !re
>>> =.id=*2
>>> =name=limit-vlan3-tc
>>> =target-addresses=192.168.192.0/22
>>> =dst-address=0.0.0.0/0
>>> =interface=vlan3-192.168.192.0/22 VM TC
>>> =parent=none
>>> =direction=both
>>> =priority=8
>>> =queue=default-small/default-small
>>> =limit-at=0/0
>>> =max-limit=2M/2M
>>> =burst-limit=0/0
>>> =burst-threshold=0/0
>>> =burst-time=0s/0s
>>> =total-queue=default-small
>>> =bytes=0/0
>>> =total-bytes=0
>>> =packets=0/0
>>> =total-packets=0
>>> =dropped=0/0
>>> =total-dropped=0
>>> =rate=0/0
>>> =total-rate=0
>>> =packet-rate=0/0
>>> =total-packet-rate=0
>>> =queued-packets=0/0
>>> =total-queued-packets=0
>>> =queued-bytes=0/0
>>> =total-queued-bytes=0
>>> =lends=0/0
>>> =total-lends=0
>>> =borrows=0/0
>>> =total-borrows=0
>>> =pcq-queues=0/0
>>> =total-pcq-queues=0
>>> =disabled=true
>>> =invalid=false
>>> =dynamic=false
>>> !done
I have a list of simple queue's that I wish to be able to disable and enable from a perl script using the API,/queue/simple-table ?..
what exact command do you try to set 'disabled' to false?..
no such command prefix
/queue/simple/set
=.id=*2
=disabled=false
Cool Thanks, works now, however can I address the queue differently as in;at first, '/queue/simple-table/print' getstrap =) you should use '/queue/simple/print'Code: Select allno such command prefix
for enabling, useCode: Select all/queue/simple/set =.id=*2 =disabled=false
<<< /queue/simple/set
<<< =name=limit-vlan3-tc
<<< =disable=false
<<<
>>> !done
no, you should first find necessary item, then disable it by id. like this:Cool Thanks, works now, however can I address the queue differently as in;Code: Select all<<< /queue/simple/set <<< =name=limit-vlan3-tc <<< =disable=false <<< >>> !done
/queue/simple/print
=.proplist=.id
?name=limit-vlan3-tc
/queue/simple/set
=.id=*here's_your_id
=disabled=false
basically, API can do anything you can do with CLI =) all exceptions you can get to know only after you try to do something unusual =)Is the API able to control the BW server settings as well?
<<< /queue/simple/print
<<< =.proplist=.id
<<< ?name=limit-vlan3=tc
<<<
>>> !done
!re=
=.id=*1
Got itchecked with 3.28: when that name exists, the request returns the following:Code: Select all!re= =.id=*1
Will try now to implement this in a perl script<<< /queue/simple/print
<<< =.proplist=.id
<<< ?name=limit-vlan3-tc
<<<
>>> !re
>>> =.id=*2
>>> !done
<<<
/ip/address/print
=interval=1
my $ret = $mt->get_by_key('/system/ups/print');
print Dumper($ret);
$VAR1 = {
'*3' => {
'nominal-battery-voltage' => '24',
'disabled' => 'false',
'manufacture-date' => '08/06/99',
'serial' => '************',
'version' => '50.11.I',
'model' => 'SMART-UPS 700',
'name' => 'ups1',
'alarm-setting' => 'immediate',
'port' => 'serial0',
'min-runtime' => '5m',
'on-line' => 'true',
'.id' => '*3',
'offline-time' => '00:05:00',
'load' => '5',
'invalid' => 'false'
}
};
my $ret = $mt->get_by_key('/system/ups/monitor','=0','=once');
print Dumper($ret);
$VAR1 = {};
my $ret = $mt->get_by_key('/system/ups/monitor','=.id=*3','=once=');
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
Use of uninitialized value in hash element at /usr/local/lib/perl5/site_perl/5.10.1/Mtik.pm line 414.
$VAR1 = {
'' => {
'rtc-running' => 'false',
'battery-voltage' => '2760',
'smart-boost' => 'false',
'on-battery' => 'false',
'overload' => 'false',
'runtime-left' => '02:31:00',
'transfer-cause' => 'Line voltage notch or spike',
'smart-trim' => 'false',
'replace-battery' => 'false',
'frequency' => '50',
'line-voltage' => '24050',
'on-line' => 'true',
'low-battery' => 'false',
'load' => '5',
'output-voltage' => '24050',
'temperature' => '5620',
'battery-charge' => '100'
}
};
foreach (@results) {
my $item = $_;
foreach my $result_key (keys (%$item)) {
if (exists($item->{$key})) {
if ($key eq $result_key) {
$result_hash->{ $item->{$key} } = $item
}
}
else {
$result_hash->{ $item->{'.id'} } = $item <--- HERE
}
}
}
>>> /login
start read_len
read_len got 5
recv 5
<<< !done
start read_len
read_len got 37
recv 37
<<< =ret=5d6f57de5c78f9305a19e17e11ff47cf
start read_len
read_len got 0
Use of uninitialized value in pack at Mtik.pm line 292.
>>> /login
>>> =name=admin
>>> =response=0088d75a26cd50e9304521a8b0bba09a85
start read_len
read_len got 5
recv 5
<<< !trap
start read_len
read_len got 22
recv 22
<<< =message=cannot log in
start read_len
read_len got 0
is API service enabled?Hello!
Download this module, but it's don't connect to my RB:
seems like it is:is API service enabled?
=ret=5d6f57de5c78f9305a19e17e11ff47cf
it worksmy $sock = new IO::Socket::INET(
PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp',
Timeout => 3);
my (%attrs); $attrs{'.proplist'} = ".id,name,source"; my (%queries); $queries{'name'} = "MyScript"; my($retval,@results) = Mtik::mtik_query('/system/script/print',\%attrs,\%queries); print Dumper(\@results);This Doesn't:
my (%attrs); $attrs{'.proplist'} = ".id,name"; my (%queries); $queries{'name'} = "MyScript"; my($retval,@results) = Mtik::mtik_query('/system/script/print',\%attrs,\%queries); print Dumper(\@results);
sub mtik_query { my($cmd) = shift; my(%attrs) = %{(shift)}; my(%queries) = %{(shift)}; $error_msg = ''; my(@command); push(@command,$cmd); foreach my $attr (keys (%attrs)) { push(@command,'=' . $attr . '=' . $attrs{$attr}); } foreach my $query (keys (%queries)) { push(@command,'?' . $query . '=' . $queries{$query}); } my($retval,@results) = talk(\@command); if ($retval > 1) { $error_msg = $results[0]{'message'}; } return ($retval,@results); }
/system/script/print
<<< /system/script/print
<<<
>>> !re
>>> =.id=*1
>>> =name=script1
>>> =owner=admin
>>> =policy=ftp,reboot,read,write,policy,test,winbox,password,sniff,sensitive,api
>>> =run-count=0
>>> =source=asdfasdfasdfsadf
>>> =invalid=false
>>>
>>> !done
>>>
using python (3) client:source is just fast example of error:Code: Select all/system/script/print <<< /system/script/print <<< >>> !re >>> =.id=*1 >>> =name=script1 >>> =owner=admin >>> =policy=ftp,reboot,read,write,policy,test,winbox,password,sniff,sensitive,api >>> =run-count=0 >>> =source=asdfasdfasdfsadf >>> =invalid=false >>> >>> !done >>>
asdfasdfasdfsadf
so this is language specific.
Given that most words are read fine, and only the last one is the problem, length decoding is probably not the issue.Yeah... I think I narrowed it down. I am pretty sure there is an error in the reading of the line length somewhere.... So yes.. it is library specific. Now if I could find the bug.
Interesting.... I wonder the best way to fix it. It is getting to the last word... reading part of it... reading "!do" then reads the length of the next word as "ne" and is trying to read 111 bytes... only finds 2 and fails.Given that most words are read fine, and only the last one is the problem, length decoding is probably not the issue.Yeah... I think I narrowed it down. I am pretty sure there is an error in the reading of the line length somewhere.... So yes.. it is library specific. Now if I could find the bug.
It appers the real culprit may be the lack of socket buffering, which most API clients don't do. In the vast majority of cases, this is a problem only when you have large words, but if the speed of your connection to the router is low enough, you can experience it even with just a few bytes, as the case here. I think other than my client, there was only one other which did such buffering, but I don't remember which one it was... I think maybe Ruby, or ActionScript.
It is theoretically doing that....It needs to be fixed in a generic fashion - the procedure that reads words needs to try read some data, then check out how much data it ACTUALLY received, and substract THAT from the length, and retry the remaining bytes.
What most clients do instead is that they read the length as, say "5 bytes", then they ask for 5 bytes, and assume they got what they asked for, when in fact, they got just 3 bytes.
It's not about "runinng out" per se, but about not addressing how OS socket functions work - i.e. them being unreliable in terms of fetching what you ask for. People look at receivers like "give me N bytes", when in fact, they work as "give me all you've got, even if it's just 1 byte... just don't give me more than N bytes".i really doubt that he is running out of TCP buffers set by OS. Unless perl uses something different. And usually TCP buffer is enough.
I saw the source for the brief time you posted it - do the "<<= 8" first, and THEN "+=" the new byte, not the other way around.There was a bug in read_len... I thought I fixed it, but there is still a bug. Fixing it... or trying to.
Can you add $sock->autoflush(0) ?Updated a few things....
Added the timeout parameter, fixed write_len for lengths > 0x80, fixed read_len for lengths > 0x80, and fixed allowing of newlines in the read_sentence.
I am now able to read and write scripts... woot!
I think I got all of my debugging out of the pm file. Let me know if you see anything else.
-Eric
Feel free to add it. I don't actually maintain the thing. I just went to use it and found a bunch of errors in it, so I fixed them.Can you add $sock->autoflush(0) ?Updated a few things....
Added the timeout parameter, fixed write_len for lengths > 0x80, fixed read_len for lengths > 0x80, and fixed allowing of newlines in the read_sentence.
I am now able to read and write scripts... woot!
I think I got all of my debugging out of the pm file. Let me know if you see anything else.
-Eric
I wrote test program (it add 250 ips to address-list "using Mtik::mtik_cmd('/ip/firewall/address-list/add',\%attr);")
with $sock->autoflush(1) it takes ~60 sec .
with $sock->autoflush(0) it takes ~27 sec .
==== some changes
sub mtik_connect
{
my($host) = shift;
my($port) = shift || 8728;
if (!($host))
{
print "no host!\n";
return 0;
}
my($sock) = new IO::Socket::INET(
PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp');
if (!($sock))
{
print "no socket :$!\n";
return 0;
}
$sock->autoflush(0); #<---- ADD THIS LINE
return $sock;
}
sub write_sentence {
my($sentence_ref) = shift;
my(@sentence) = @$sentence_ref;
foreach my $word (@sentence)
{
write_word($word);
if ($debug > 2)
{
print ">>> $word\n";
}
}
write_word('');
$sock->flush(); #<---- ADD THIS LINE
}
How to add ips to address list at once (like "enable/disable/remove" do )?
To cheesegrits: If you will add this info to the wiki, I will give you a free RouterOS license!
To normis: Dear friend i am looking some one who able to make perl or php basic gui for few commands for me i will pay works! my email : atilla.o.ersoz [at] gmail.com please get in touch with me
in API, you can use shortened value names, like in CLI; e.g.
/ip/route/print
=n=*1
=val=routing-mark
instead of
/ip/route/print
=numbers=*1
=value-name=routing-mark
isn't it a bit dangerous? maybe it should be forbidden, to avoid possible future problems? API is not CLI for humans...
To forum guru i am looking some one who are able to do it perl or php little gui for me only few commands please recomend me some one my email is atilla.o.erso [at] gmail.com i am sorry for this message hire
Really? Since which version? Last I checked (right now, with 6.5), that's not the case, protocol wise at least.in API, you can use shortened value names, like in CLI; e.g.
The next version of my client (in PHP, from my signature) will provide an interactive command line utility that you can type raw commands in. You can get the current state from its develop branch on GitHub if you can't wait for a tagged release (which is held up for a few reasons, one of which is that for the console, you need to also get the current untagged PEAR2_Console_CommandLine for it to work...).To forum guru i am looking some one who are able to do it perl or php little gui for me only few commands please recomend me some one my email is atilla.o.erso [at] gmail.com i am sorry for this message hire
it was 4,5 years ago read the next message: "Shortened names will not be allowed in 3.25+ versions"Really? Since which version? Last I checked (right now, with 6.5), that's not the case, protocol wise at least.in API, you can use shortened value names, like in CLI; e.g.
Thanks! This fixed a problem I've been having with perl API for years.Updated a few things....
As camlost said above, there is a repo on GitHub, but without your modifications.Let's set up a repository somewhere... Then make sure we get the latest code on there (that I fixed)... then I can start to work on it again.
I modified it because some things were missing. Also, I added ssl. This can be done simply by reviewing client @akschu.I think the code that Efaden put on github is probably the best bet since it fixes the length issue, as well as gives us a place to track change, but it didn't have port or ssl support. I forked his code and added those featuers:
https://github.com/akschu/MikroTikPerl
Efaden, please consider merging my pull request.
Total Elapsed Time = 2.998272 Seconds
User+System Time = 0.508272 Seconds
Total Elapsed Time = 0.077465 Seconds
User+System Time = 0.077465 Seconds
--- /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_old.pl 2017-04-04 05:53:43.547467546 +0200
+++ /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status.pl 2018-01-28 08:50:56.437834735 +0200
@@ -1,10 +1,11 @@
#!/usr/bin/perl
use strict;
use warnings;
-use MikroTik::API; # http://search.cpan.org/~martingo/MikroTik-API/lib/MikroTik/API/Examples.pm
+use MikroTik::API2; # https://github.com/efaden/MikroTikPerl/blob/master/MikroTik.pm
use Fcntl qw(:flock);
use Storable qw(lock_store lock_nstore lock_retrieve);
+my $use_ssl = 1;
my ($router, $api_user, $api_passwd, $command, $peer, $key) = @ARGV;
if (not defined $router) { print STDERR "Need router FQDN or IP, as first parameter.\n"; exit 3 };
if (not defined $api_user) { print STDERR "Need MikroTik API username, as second parameter.\n"; exit 4 };
@@ -25,16 +26,6 @@
return ($years*31536000)+($weeks*604800)+($days*86400)+($hours*3600)+($minutes*60)+$seconds;
}
-my $api = MikroTik::API->new (
- {
- host => $router,
- username => $api_user,
- password => $api_passwd,
- use_ssl => 1,
- autoconnect => 0,
- }
-);
-
my %bgp_peer;
my $cached = 0;
my $modified = (stat($cachefile))[9];
@@ -46,10 +37,9 @@
}
if ($cached == 0) {
if (!flock $lockfile, LOCK_EX | LOCK_NB) { print STDERR "Another process is already using MikroTik API.\n"; exit 6 };
- $api->connect();
- $api->login();
- %bgp_peer = $api->get_by_key('/routing/bgp/peer/print', 'name');
- $api->logout();
+ MikroTik::login($router, $api_user, $api_passwd, $use_ssl);
+ %bgp_peer = MikroTik::get_by_key('/routing/bgp/peer/print', 'name');
+ MikroTik::logout;
lock_nstore \%bgp_peer, $cachefile;
chmod 0660, $cachefile;
flock $lockfile, LOCK_UN;
real 0m0.003s
user 0m0.003s
sys 0m0.001s
[root@zabbix ~]# /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_client.sh 10.0.0.1 syrexnms 'FakeP@ssw0rd' -d; echo $?
{
"data": [
{ "{#BGPPEER}": "iOnline" }
]
}
0
[root@zabbix ~]# cat /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_client.sh
#!/bin/sh
echo "'$1'" "'$2'" "'$3'" "'$4'" "'$5'" "'$6'" | /usr/bin/nc -w 3 127.0.0.1 7890;
exit $?;
-print STDERR "Another ...
+print $client "Another ...
-printf ("%-25.25s ...
+printf $client ("%-25.25s ...
sub handle_client {
my $client = shift;
my $msg;
$client->recv($msg, 250);
my ($router, $api_user, $api_passwd, $command, $peer, $key) = quotewords('\s+', 0, $msg);
#my ($router, $api_user, $api_passwd, $command, $peer, $key) = @ARGV;
use IO::Socket::INET;
use Text::ParseWords;
$SIG{CHLD} = 'IGNORE';
STDOUT->autoflush(1);
my $server = IO::Socket::INET->new(
LocalAddr => '127.0.0.1',
LocalPort => '7890',
Listen => SOMAXCONN,
Type => SOCK_STREAM,
Reuse => 1) or die "could not open port: $!";
while (my $client = $server->accept) {
next if my $pid = fork;
die "fork: $!" unless defined $pid;
$client->autoflush(1);
close $server;
handle_client($client);
} continue {
close $client;
}
[root@zabbix ~]# /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_client.sh 10.0.0.1 syrexnms 'FakeP@ssw0rd'
Missing or invalid command. Usage /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_client.sh <router> <api username> <api password> <command> [<peer>] :
-d|--discover Zabbix LLD (low level discovery). In JSON format.
-c|--croak Dumps all available data. Usable as $bgp_peer{'$peer'}->{'key'}
-t|--table Displays tabled overview
-g|--get <peer> <key> example: -g "Syrex - Primary" state
Examples:
Discovery : /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_client.sh 10.0.0.1 syrexnms "FakeP@ssw0rd" -d
Sample : {
"data": [
{ "{#BGPPEER}": "Syrex - Primary" },
{ "{#BGPPEER}": "Syrex - Secondary" }
]
}
Get item : /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_client.sh 10.0.0.1 syrexnms "FakeP@ssw0rd" "Syrex - Primary" state
Sample : established
[root@zabbix ~]# /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_client.sh 10.0.0.1 syrexnms 'FakeP@ssw0rd' -d
{
"data": [
{ "{#BGPPEER}": "iOnline" }
]
}
[root@zabbix ~]# /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_client.sh 10.0.0.1 syrexnms 'FakeP@ssw0rd' -t
Peer Active Prefixes Remote IP Remote AS Uptime State
iOnline yes 2 172.18.0.17 327909 4w1d12h20m3s established
[root@zabbix ~]# /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_client.sh 10.0.0.1 syrexnms 'FakeP@ssw0rd' -c
peer: iOnline
=
.id=*0
address-families=ip
as-override=false
as4-capability=true
default-originate=if-installed
disabled=false
established=true
hold-time=3m
in-filter=ionline-in
instance=mpls
local-address=172.18.0.20
multihop=false
name=iOnline
nexthop-choice=default
out-filter=ionline-out
passive=false
prefix-count=2
refresh-capability=true
remote-address=172.18.0.17
remote-as=329709
remote-hold-time=3m
remote-id=145.23.110.26
remove-private-as=false
route-reflect=false
state=established
tcp-md5-key=secret123
ttl=default
updates-received=6
updates-sent=1
uptime=4w1d12h21m3s
use-bfd=false
used-hold-time=3m
used-keepalive-time=1m
withdrawn-received=0
withdrawn-sent=0
[root@zabbix ~]# /usr/lib/zabbix/externalscripts/mikrotik-api-bgp_status_client.sh 10.0.0.1 syrexnms 'FakeP@ssw0rd' -g iOnline uptime
2550183
The legacy challenge-response authentication is not a measure of good protection. You can set the router to encrypt the connection.According to the docs, the challenge/response login mechanism is no longer available after 6.45.1, however, 6.45.8 returns a challenge after sending the new username/password style parameters, and sending the md5 response results in "invalid username or password". Given that the connection is not encrypted, deprecating the challenge/response login is unfortunate.
[admin@zabbix ~]# openssl s_client -host router1.domain.com -port 8729
CONNECTED(00000003)
140139476116800:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1543:SSL alert number 40
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 317 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
[admin@zabbix ~]# openssl s_client -host router1.domain.com -port 8729 -cipher HIGH:@SECLEVEL=0
CONNECTED(00000003)
---
no peer certificate available
---
No client certificate CA names sent
Server Temp Key: DH, 2048 bits
---
SSL handshake has read 853 bytes and written 753 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ADH-AES256-GCM-SHA384
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ADH-AES256-GCM-SHA384
Session-ID: 935F72E228A4CEA71F519C4F3B9A55F75E027483F0992538D2ACB0CB64038438
Session-ID-ctx:
Master-Key: 273B26E476DDA0E4ADCD85816518118256EC129D742640433553F92C0F6D867AD362BACC90625284A1B6181CE0C737F0
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 37 d0 be 7a e1 80 57 0f-bb 39 35 a4 88 ad c9 1a 7..z..W..95.....
0010 - 96 4c 04 98 44 23 11 92-28 53 56 47 a5 69 d4 d7 .L..D#..(SVG.i..
0020 - b3 e4 f5 c7 f8 e4 9b 4f-2b 0b 30 c0 83 0a e5 75 .......O+.0....u
0030 - dc aa 74 7a 2c d3 c9 dd-57 67 47 3c 8b a9 09 86 ..tz,...WgG<....
0040 - 41 b3 56 50 33 25 51 fa-a9 a8 97 b8 e5 1c 4c 42 A.VP3%Q.......LB
0050 - 30 fb 7b 9b 09 5b 52 4c-53 a8 9f 45 9b 55 32 ea 0.{..[RLS..E.U2.
0060 - da 4a 51 d6 02 bb d0 b8-9e d2 45 b5 b1 e8 28 07 .JQ.......E...(.
0070 - ac 77 e3 65 cb af c9 67-57 a8 57 db 07 55 5c 8e .w.e...gW.W..U\.
0080 - 17 5a e2 76 b7 7a a4 b6-b4 97 03 e9 d1 69 83 e4 .Z.v.z.......i..
0090 - c2 64 87 54 86 e7 d2 b7-fc 97 56 3d 3d 40 8d 65 .d.T......V==@.e
00a0 - 35 19 9a da a1 10 94 dd-e6 8a 25 42 cb 7c 02 95 5.........%B.|..
00b0 - 7b d3 fb d0 a6 21 3b 74-5c 01 3b 9c ae 1a e6 60 {....!;t\.;....`
Start Time: 1665492017
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no
---
[admin@zabbix ~]# diff -uNr /usr/share/perl5/MikroTik/API.pm_v2.0.1.orig /usr/share/perl5/MikroTik/API.pm
--- /usr/share/perl5/MikroTik/API.pm_v2.0.1.orig 2022-10-10 21:35:36.261712950 +0200
+++ /usr/share/perl5/MikroTik/API.pm 2022-10-10 23:09:32.948755784 +0200
@@ -110,7 +110,7 @@
PeerHost => $self->get_host,
PeerPort => $self->get_port,
Proto => 'tcp',
- SSL_cipher_list => 'HIGH',
+ SSL_cipher_list => 'HIGH:@SECLEVEL=0',
SSL_verify_mode => $self->get_ssl_verify(),
Timeout => $self->get_timeout,
);