Syed Jahanzaib Personal Blog to Share Knowledge !

December 19, 2016

Tik: 9 wan pcc with vpn server

Filed under: Mikrotik Related — Syed Jahanzaib / Pinochio~:) @ 10:12 AM

~ There are no absolute answers in this universe, only assumptions, guesses, Jeopardies
Syed Jahanzaib !


9 wan pcc.png


 

Following is just a reference post. This configuration contains PCC and PPtP server. (to provide net access to local users via dialer) , You may need to tweak in order to make it work.

Disclaimer: 
The script in this post is made for reference purposes only. This is no way a COPY PASTE material which you can use it as a whole. every network is different and should be build accordingly. Modify the config as per local requirements and then implement it. You may need to play a bit or tweak it in order to make it Workable config.


Scenario:

Hardware Used : Mikrotik – Rb1100ahx2

  • 9 DSL (ptcl) routers are connected with the RB1100ahx2.
  • Each DSL modem is in router mode, so the gateway ip are in series like 192.168.1,1 or 192.168.2.1 and so on …
  • Ports name have been renamed to friendlier label for easy marking.
    Example Port 1-9 are renamed as WANx , and Port 10 is marked as Local
  • VPN Server is configured on same RB, and users dials in to this server in order to access internet.
  • No DHCP is being used on this setup as OP prefers to use static ips due to some specific circumstances.

the scriptO!

# 9 wan PCC load balancing script along with PPtP config
# Make sure to adjust it as per your setup
# Syed Jahanzaib / aacable at hotmail dot com
# http:// aacable . wordpress . com
# Made in 2016 / Pakistan

# Local Interface connected with the Users Switch
/ip address
add address=10.0.0.1/24 interface=Local network=10.0.0.0

# WAN interfaces IP addresses, which are connected with ptcl dsl routers
/ip address
add address=192.168.1.2/24 interface=WAN1 network=192.168.1.0
add address=192.168.2.2/24 interface=WAN2 network=192.168.2.0
add address=192.168.3.2/24 interface=WAN3 network=192.168.3.0
add address=192.168.4.2/24 interface=WAN4 network=192.168.4.0
add address=192.168.5.2/24 interface=WAN5 network=192.168.5.0
add address=192.168.6.2/24 interface=WAN6 network=192.168.6.0
add address=192.168.7.2/24 interface=WAN7 network=192.168.7.0
add address=192.168.8.2/24 interface=WAN8 network=192.168.8.0
add address=192.168.9.2/24 interface=WAN9 network=192.168.9.0

# Add IP pool for VPN dialer users, which will be allowed to use internet
/ip pool
add name=vpn-pool ranges=172.16.0.1-172.16.0.255

# Add VPN Profile for users , example 1mb per user profile
/ppp profile
add change-tcp-mss=yes dns-server=110.0.0.1,8.8.8.8 local-address=10.0.0.1 name=vpn-1mb only-one=yes rate-limit=1024k/1024k remote-address=vpn-pool use-encryption=yes

/interface pptp-server server set authentication=pap,chap,mschap1,mschap2 default-profile=vpn-1mb enabled=yes

# Enable DNS server
/ip dns
set allow-remote-requests=yes servers=8.8.8.8

/ip firewall address-list
add address=172.16.0.1-172.16.0.255 list=local_vpn_users_internet_allowed_list

# This is a local sharing server
add address=192.168.10.1 list=local_sharing_server

/ip firewall mangle

# Bypass Local Media Sharing server from PCC, so user can access it / Adjust it according to your need/ Jz
add action=accept chain=prerouting comment="Allow access to local sharing server / bypass them from the PCC" dst-address-list=local_sharing_server

# Accept traffic going to DSL Routers / Adjust it according to your need/ Jz
add action=accept chain=prerouting dst-address=192.168.1.0/24
add action=accept chain=prerouting dst-address=192.168.1.0/24
add action=accept chain=prerouting dst-address=192.168.2.0/24
add action=accept chain=prerouting dst-address=192.168.3.0/24
add action=accept chain=prerouting dst-address=192.168.4.0/24
add action=accept chain=prerouting dst-address=192.168.5.0/24
add action=accept chain=prerouting dst-address=192.168.6.0/24
add action=accept chain=prerouting dst-address=192.168.7.0/24
add action=accept chain=prerouting dst-address=192.168.8.0/24
add action=accept chain=prerouting dst-address=192.168.9.0/24

# Mark connections using PCC for 9 WAN / Adjust it according to your need / Jz
add action=mark-connection chain=prerouting dst-address-type=!local new-connection-mark=WAN1_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:9/0 src-address-list=local_vpn_users_internet_allowed_list
add action=mark-connection chain=prerouting dst-address-type=!local new-connection-mark=WAN2_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:9/1 src-address-list=local_vpn_users_internet_allowed_list
add action=mark-connection chain=prerouting dst-address-type=!local new-connection-mark=WAN3_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:9/2 src-address-list=local_vpn_users_internet_allowed_list
add action=mark-connection chain=prerouting dst-address-type=!local new-connection-mark=WAN4_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:9/3 src-address-list=local_vpn_users_internet_allowed_list
add action=mark-connection chain=prerouting dst-address-type=!local new-connection-mark=WAN5_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:9/4 src-address-list=local_vpn_users_internet_allowed_list
add action=mark-connection chain=prerouting dst-address-type=!local new-connection-mark=WAN6_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:9/5 src-address-list=local_vpn_users_internet_allowed_list
add action=mark-connection chain=prerouting dst-address-type=!local new-connection-mark=WAN7_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:9/6 src-address-list=local_vpn_users_internet_allowed_list
add action=mark-connection chain=prerouting dst-address-type=!local new-connection-mark=WAN8_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:9/7 src-address-list=local_vpn_users_internet_allowed_list
add action=mark-connection chain=prerouting dst-address-type=!local new-connection-mark=WAN9_conn passthrough=yes per-connection-classifier=both-addresses-and-ports:9/8 src-address-list=local_vpn_users_internet_allowed_list

# Mark routing for above marked connections, so that it can be used in ROUTE section / Adjust it according to your need/ Jz
add action=mark-routing chain=prerouting connection-mark=WAN1_conn new-routing-mark=to_WAN1 passthrough=yes
add action=mark-routing chain=prerouting connection-mark=WAN2_conn new-routing-mark=to_WAN2 passthrough=yes
add action=mark-routing chain=prerouting connection-mark=WAN3_conn new-routing-mark=to_WAN3 passthrough=yes
add action=mark-routing chain=prerouting connection-mark=WAN4_conn new-routing-mark=to_WAN4 passthrough=yes
add action=mark-routing chain=prerouting connection-mark=WAN5_conn new-routing-mark=to_WAN5 passthrough=yes
add action=mark-routing chain=prerouting connection-mark=WAN6_conn new-routing-mark=to_WAN6 passthrough=yes
add action=mark-routing chain=prerouting connection-mark=WAN7_conn new-routing-mark=to_WAN7 passthrough=yes
add action=mark-routing chain=prerouting connection-mark=WAN8_conn new-routing-mark=to_WAN8 passthrough=yes
add action=mark-routing chain=prerouting connection-mark=WAN9_conn new-routing-mark=to_WAN9 passthrough=yes

# Add NAT/MASQUERADE rule allowing only allowed users, restricted to allowed users only
add action=masquerade chain=srcnat comment="Allow Local Sharing Servers / NATING" dst-address-list=local_sharing_server
add action=masquerade chain=srcnat comment="WAN-1 / Allow Internet Access - For VPN Users only" out-interface=WAN1 src-address-list=local_vpn_users_internet_allowed_list
add action=masquerade chain=srcnat comment="WAN-2 / Allow Internet Access - For VPN Users only" out-interface=WAN2 src-address-list=local_vpn_users_internet_allowed_list
add action=masquerade chain=srcnat comment="WAN-3 / Allow Internet Access - For VPN Users only" out-interface=WAN3 src-address-list=local_vpn_users_internet_allowed_list
add action=masquerade chain=srcnat comment="WAN-4 / Allow Internet Access - For VPN Users only" out-interface=WAN4 src-address-list=local_vpn_users_internet_allowed_list
add action=masquerade chain=srcnat comment="WAN-5 / Allow Internet Access - For VPN Users only" out-interface=WAN5 src-address-list=local_vpn_users_internet_allowed_list
add action=masquerade chain=srcnat comment="WAN-6 / Allow Internet Access - For VPN Users only" out-interface=WAN6 src-address-list=local_vpn_users_internet_allowed_list
add action=masquerade chain=srcnat comment="WAN-7 / Allow Internet Access - For VPN Users only" out-interface=WAN7 src-address-list=local_vpn_users_internet_allowed_list
add action=masquerade chain=srcnat comment="WAN-8 / Allow Internet Access - For VPN Users only" out-interface=WAN8 src-address-list=local_vpn_users_internet_allowed_list
add action=masquerade chain=srcnat comment="WAN-9 / Allow Internet Access - For VPN Users only" out-interface=WAN9 src-address-list=local_vpn_users_internet_allowed_list

# Adding routes for marked traffic
# Each DSL router ip is in series like 192.168.1.1 / 2.1 / 3.1 and so on

/ip route
add check-gateway=ping distance=1 gateway=192.168.1.1 routing-mark=to_WAN1
add check-gateway=ping distance=1 gateway=192.168.2.1 routing-mark=to_WAN2
add check-gateway=ping distance=1 gateway=192.168.3.1 routing-mark=to_WAN3
add check-gateway=ping distance=1 gateway=192.168.4.1 routing-mark=to_WAN4
add check-gateway=ping distance=1 gateway=192.168.5.1 routing-mark=to_WAN5
add check-gateway=ping distance=1 gateway=192.168.6.1 routing-mark=to_WAN6
add check-gateway=ping distance=1 gateway=192.168.7.1 routing-mark=to_WAN7
add check-gateway=ping distance=1 gateway=192.168.8.1 routing-mark=to_WAN8
add check-gateway=ping distance=1 gateway=192.168.9.1 routing-mark=to_WAN9

# Adding routes for default routes, so that if any WAN goes down, those packets should go via MAIN table : ) kind of fail over/ Jz
add check-gateway=ping comment="WAN-1 / DEFAULT ROUTE" distance=1 gateway=192.168.1.1
add check-gateway=ping comment="WAN-2 / DEFAULT ROUTE" distance=2 gateway=192.168.2.1
add check-gateway=ping comment="WAN-3 / DEFAULT ROUTE" distance=3 gateway=192.168.3.1
add check-gateway=ping comment="WAN-4 / DEFAULT ROUTE" distance=4 gateway=192.168.4.1
add check-gateway=ping comment="WAN-5 / DEFAULT ROUTE" distance=5 gateway=192.168.5.1
add check-gateway=ping comment="WAN-6 / DEFAULT ROUTE" distance=6 gateway=192.168.6.1
add check-gateway=ping comment="WAN-7 / DEFAULT ROUTE" distance=7 gateway=192.168.7.1
add check-gateway=ping comment="WAN-8 / DEFAULT ROUTE" distance=8 gateway=192.168.8.1
add check-gateway=ping comment="WAN-9 / DEFAULT ROUTE" distance=9 gateway=192.168.9.1

W/Salam

December 1, 2016

rrdtool: MRTG next level graphing

Filed under: Linux Related, Mikrotik Related — Tags: , , , , , , , — Syed Jahanzaib / Pinochio~:) @ 10:56 AM

DRAFT VERSION: This is incomplete Post ! Some points may be missing, I will update them later ..

rrdtool

We all know what is MRTG. You can graph so many information including temperature humidity, speed, voltage, uptime, routers, active numbers of users,  number of printouts and sometimes out of the box graphing/zaib.

In this post, I am just posting reference material on how to move plain mrtg graphs to RRD. The advantage of RRD over MRTG is that using RRD you can generate the graphs on the fly, as opposed as MRTG that generates the graphs all the time, no matter that nobody sees the generated HTML pages or not. we can use RRD to make graphs with one minute interval, whereas in plain MRTG, we have to use 5 minutes interval which is not good to monitor jerks or sensitive devices.

For initial / basic level of MRTG installation on Ubuntu Server , refer to the inernet or my previous post at

https://aacable.wordpress.com/tag/mrtg-installation-on-ubuntu/


Sample CFG Files:

main MRTG.CFG file

cat /etc/mrtg.cfg


#########################
# START OF /etc/mrtg.cfg#
#########################
# Author: Syed Jahanzaib
# Email : aacable@hotmail.com
# Web : https://aacable.wordpress.com

WorkDir: /var/www/mrtg
Options[_]: growright,nobanner,pngdate,noinfo,nobanner

XSize[_]: 600
YSize[_]: 200
EnableIPv6: no
RunAsDaemon: no
Interval: 1
Logformat: rrdtool
#Use MIBS as per your local config, make sure you download the mibs as mentioned here
# https://aacable.wordpress.com/tag/mrtg-installation-on-ubuntu/
LoadMIBs: /cfg/mibs/HOST-RESOURCES-MIB /cfg/mibs/IF-MIB /cfg/mibs/UCD-SNMP-MIB
PageFoot[^]: Page managed by SYED JAHANZAIB
AddHead[_]:
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cstyle%20type%3D%22text%2Fcss%22%3E%20%3C!.%20a%20%7B%20color%3A%20%23263F66%3B%20text-decoration%3A%20none%3B%20%7D%20a%3Ahover%20%7B%20color%3A%20%23785B41%3B%20text-decoration%3A%20none%3B%20%7D%20body%20%7B%20color%3A%20black%3B%20font%3A%208pt%20Verdana%2C%20Geneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3B%20%7D%20h1%20%7B%20font%3A%20bold%2016pt%20Verdana%2C%20Geneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3B%20color%3A%20%23342A21%3B%20%7D%20h2%20%7B%20color%3A%20%23666666%3B%20font%3A%20bold%2012pt%20Verdana%2C%20Geneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3B%20%7D%20h3%20%7B%20color%3A%20black%3B%20font%3A%20bold%209pt%20Verdana%2C%20Geneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3B%20%7D%20table%20%7B%20border%3A%200%3B%20%7D%20td%20%7B%20background-color%3A%20%23E7DDD3%3B%20border%3A%200px%20solid%20%23FFFFFF%3B%20color%3A%20Black%3B%20font%3A%208pt%20Verdana%2C%20Geneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3B%20vertical-align%3A%20top%3B%20%7D%20th%20%7B%20background-color%3A%20%23735A4A%3B%20color%3A%20White%3B%20font%3A%2011px%20Verdana%2C%20arial%2C%20geneva%2C%20helvetica%2C%20sans-serif%3B%20border%3A%200%3B%20font-weight%3A%20bold%3B%20text-align%3A%20left%3B%20%7D%20.%3E%20%3C%2Fstyle%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;style&gt;" title="&lt;style&gt;" />

Background[_]: #F6F1EE

# Change it as required , it means mrtg will read following file and will create graphs based on its contents
# ADD remove them as required, they are added for reference purposes only
#Include: /cfg/temp.cfg
Include: /cfg/kesc.cfg
Include: /cfg/lanwan.cfg
Include: /cfg/radius.cfg
Include: /cfg/mt.cfg
Include: /cfg/ping.cfg
#Include: /cfg/vlan.cfg

##################
# END OF /etc/mrtg.cfg #
##################


radius.cfg


# Created by
# /usr/bin/cfgmaker public@10.0.0.1

# or for NT
WorkDir: /var/www/mrtg

### Interface 2 >> Descr: 'eth0' | Name: 'eth0' | Ip: '1' | Eth: '00' ###

Target[10.0.0.1_eth0]: #eth0:public@10.0.0.1:
SetEnv[10.0.0.1_eth0]: MRTG_INT_IP="10.0.0.1" MRTG_INT_DESCR="eth0"
MaxBytes[10.0.0.1_eth0]: 125000000
Title[10.0.0.1_eth0]: Traffic Analysis for eth0 -- BILLING
PageTop[10.0.0.1_eth0]:
<h1>Traffic Analysis for eth0 -- BILLING</h1>
<div id="sysdetails">
<table>
<tr>
<td>System:</td>
<td>in "BILLING"</td>
</tr>
<tr>
<td>Maintainer:</td>
<td>aacable at hotmail dot com</td>
</tr>
<tr>
<td>Description:</td>
<td>eth0</td>
</tr>
<tr>
<td>ifType:</td>
<td>ethernetCsmacd (6)</td>
</tr>
<tr>
<td>ifName:</td>
<td>eth0</td>
</tr>
<tr>
<td>Max Speed:</td>
<td>125.0 MBytes/s</td>
</tr>
<tr>
<td>Ip:</td>
<td>10.0.0.1 (click.onmypc.net)</td>
</tr>
</table>
</div>
#Percent of memory used
Target[radius_server_mem_ram]: ( hrStorageUsed.1&hrStorageUsed.1:public@10.0.0.1) * 100 / ( hrStorageSize.1&hrStorageSize.1:public@10.0.0.1 ) / 10
Title[radius_server_mem_ram]: Memory usage for Radius Server
PageTop[radius_server_mem_ram]:
<H1> Memory usage for Radius Server </H1>

MaxBytes[radius_server_mem_ram]: 100
AbsMax[radius_server_mem_ram]: 100
ShortLegend[radius_server_mem_ram]: %
YLegend[radius_server_mem_ram]: % of Memory
Legend1[radius_server_mem_ram]: Used Memory
LegendI[radius_server_mem_ram]: Used :
LegendO[radius_server_mem_ram]:
Options[radius_server_mem_ram]: growright,nopercent,gauge,integer,nobanner,printrouter,pngdate,noo
#Unscaled[radius_server_mem_ram]: ymwd

Target[linux_server_dis_usage]: ( hrStorageUsed.31&hrStorageUsed.31:public@10.0.0.1 ) * 100 / ( hrStorageSize.31&hrStorageSize.31:public@10.0.0.1 ) / 8
Title[linux_server_dis_usage]: Disk usage for Linux Server
PageTop[linux_server_dis_usage]:
<H1> Disk usage for Linux Server </H1>

MaxBytes[linux_server_dis_usage]: 100
AbsMax[linux_server_dis_usage]: 100
ShortLegend[linux_server_dis_usage]: %
YLegend[linux_server_dis_usage]: % of RM_DISK
Legend1[linux_server_dis_usage]: Used RM_DISK
LegendI[linux_server_dis_usage]: Used :
LegendO[linux_server_dis_usage]:
Options[linux_server_dis_usage]: growright,gauge,integer,nobanner,printrouter,pngdate,noo,nopercent,logscale
#Unscaled[linux_server_dis_usage]: ymwd


Mikrotik Sample CFG File


workdir: /var/www/mrtg/
#Options[_]: growright,nopercent

# Z_CCR_MIKROTIK CCR_1036 PPPoE ACTIVE Users
Target[mtPPPoEusers]: 1.3.6.1.4.1.9.9.150.1.1.1.0&1.3.6.1.4.1.9.9.150.1.1.1.0:public@10.0.0.1 / 8
Title[mtPPPoEusers]: Active PPPoE Users on Z_CCR_MIKROTIK CCR_1036
PageTop[mtPPPoEusers]:
<H1>Active PPPoE Users on Z_CCR_MIKROTIK CCR_1036</H1>

MaxBytes[mtPPPoEusers]: 2000
Colours[mtPPPoEusers]: B#8888ff,B#8888ff,B#5398ff,B#5398ff
Options[mtPPPoEusers]: growright,nopercent,gauge,integer,nobanner,printrouter,pngdate,noo
LegendI[mtPPPoEusers]: Active PPPoE Users on MT
LegendO[mtPPPoEusers]:
YLegend[mtPPPoEusers]: Active PPPoE Users on MT
Legend1[mtPPPoEusers]: Active PPPoE Users on MT
Legend2[mtPPPoEusers]:
#Unscaled[mtPPPoEusers]: dwmy

### Z_CCR_MIKROTIK CCR_1036 192.168.100.2 CPU load ###
Target[192.168.100.2_cpu]: 1.3.6.1.2.1.25.3.3.1.2.1&1.3.6.1.2.1.25.3.3.1.2.1:public@10.0.0.1 / 8
AbsMax[192.168.100.2_cpu]: 100
MaxBytes[192.168.100.2_cpu]: 100
Title[192.168.100.2_cpu]: Z_CCR_MIKROTIK CCR_1036 CPU load
PageTop[192.168.100.2_cpu]:
<H1>Z_CCR_MIKROTIK CCR_1036 CPU load</H1>

Options[192.168.100.2_cpu]: growright,gauge,integer,nobanner,printrouter,pngdate,noo,nopercent
Legend1[192.168.100.2_cpu]: CPU load
YLegend[192.168.100.2_cpu]: CPU load
ShortLegend[192.168.100.2_cpu]: %
LegendI[192.168.100.2_cpu]: CPU load (percentage)
#Unscaled[192.168.100.2_cpu]: y

### MONITORING Z_CCR_MIKROTIK CCR_1036 CPU TEMP ###
Target[mt.cpu.temp]: 1.3.6.1.4.1.14988.1.1.3.11.0&1.3.6.1.4.1.14988.1.1.3.11.0:public@10.0.0.1 / 100
Options[mt.cpu.temp]: gauge, growright, nopercent, noinfo
MaxBytes[mt.cpu.temp]: 100
Colours[mt.cpu.temp]: RED#ff4f27,Y#fffb15,RED#ff4f27,RED#fffb15
#Unscaled[mt.cpu.temp]: dwmy
YLegend[mt.cpu.temp]: CPU Temprature
Title[mt.cpu.temp]: Z_CCR_MIKROTIK CCR_1036 RB CPU Temprature
PageTop[mt.cpu.temp]:
<H1>Z_CCR_MIKROTIK CCR_1036 RB CPU Temprature</H1>

ShortLegend[mt.cpu.temp]: c
LegendI[mt.cpu.temp]:
LegendO[mt.cpu.temp]: CPU Temp
Legend1[mt.cpu.temp]: CPU Temprature
Legend2[mt.cpu.temp]: CPU Temprature

### MONITORING Z_CCR_MIKROTIK CCR_1036 RB TEMP ###
Target[mt.rb.temp]: 1.3.6.1.4.1.14988.1.1.3.10.0&1.3.6.1.4.1.14988.1.1.3.10.0:public@10.0.0.1 / 100
Options[mt.rb.temp]: gauge, growright, nopercent, noinfo
MaxBytes[mt.rb.temp]: 100
Colours[mt.rb.temp]: RED#ff4f27,Y#fffb15,RED#ff4f27,RED#fffb15
#Unscaled[mt.rb.temp]: dwmy
YLegend[mt.rb.temp]: RB Temprature
Title[mt.rb.temp]: Z_CCR_MIKROTIK CCR_1036 Router Board Temprature
PageTop[mt.rb.temp]:
<H1>Z_CCR_MIKROTIK CCR_1036 Router Board Temprature</H1>

ShortLegend[mt.rb.temp]: c
LegendI[mt.rb.temp]:
LegendO[mt.rb.temp]: RB Temp
Legend1[mt.rb.temp]: RB Temprature
Legend2[mt.rb.temp]: RB Temprature

### MONITORING Z_CCR_MIKROTIK CCR_1036 VOLTAGE Monitor ###
Target[mt-voltage]: 1.3.6.1.4.1.14988.1.1.3.8.0&1.3.6.1.4.1.14988.1.1.3.8.0:public@10.0.0.1 / 8
Options[mt-voltage]: growright,nopercent,gauge,integer,nobanner,printrouter,pngdate
MaxBytes[mt-voltage]: 30
Colours[mt-voltage]: RED#ff4f27,Y#fffb15,RED#ff4f27,RED#fffb15
Unscaled[mt-voltage]: dwmy
YLegend[mt-voltage]: Voltaeg Monitor
Title[mt-voltage]: Z_CCR_MIKROTIK CCR_1036 Cloudcore RB VOLTAGE Monitor
PageTop[mt-voltage]:
<H1>Z_CCR_MIKROTIK CCR_1036 Cloudcore RB VOLTAGE Monitor</H1>

ShortLegend[mt-voltage]: v
LegendI[mt-voltage]:
LegendO[mt-voltage]: Voltage
Legend1[mt-voltage]: Voltage
Legend2[mt-voltage]: Voltage

### MONITORING Z_CCR_MIKROTIK CCR_1036 power.consumption Watt Usage Monitor ###
Target[mt-powerconsumption]: .1.3.6.1.4.1.14988.1.1.3.12.0&.1.3.6.1.4.1.14988.1.1.3.12.0:public@10.0.0.1 / 100
Options[mt-powerconsumption]: gauge, growright, nopercent, noinfo
MaxBytes[mt-powerconsumption]: 1000
Colours[mt-powerconsumption]: RED#ff4f27,Y#fffb15,RED#ff4f27,RED#fffb15
#Unscaled[mt-powerconsumption]: dwmy
YLegend[mt-powerconsumption]: Watts USAGE Monitor
Title[mt-powerconsumption]: Z_CCR_MIKROTIK CCR_1036 Cloudcore RB Watts Usage Monitor
PageTop[mt-powerconsumption]:
<H1>Z_CCR_MIKROTIK CCR_1036 Cloudcore RB Watts Usage Monitor</H1>

ShortLegend[mt-powerconsumption]: W
LegendI[mt-powerconsumption]:
LegendO[mt-powerconsumption]: power.consumption.wts
Legend1[mt-powerconsumption]: power.consumption.wts
Legend2[mt-powerconsumption]: power.consumption.wts

### MONITORING Z_CCR_MIKROTIK CCR_1036 FAN-2 Speed Monitor ###
Target[mt-FAN2-speed]: 1.3.6.1.4.1.14988.1.1.3.18.0&1.3.6.1.4.1.14988.1.1.3.18.0:public@10.0.0.1 / 8
Options[mt-FAN2-speed]: growright,nopercent,gauge,integer,nobanner,printrouter,pngdate,logscale,noi
MaxBytes[mt-FAN2-speed]: 10000
Colours[mt-FAN2-speed]: RED#ff4f27,Y#fffb15,RED#ff4f27,RED#fffb15
#Unscaled[mt-FAN2-speed]: dwmy
YLegend[mt-FAN2-speed]: FAN-2 RPM
Title[mt-FAN2-speed]: Z_CCR_MIKROTIK CCR_1036 Cloudcore RB FAN-2 Speed Monitor
PageTop[mt-FAN2-speed]:
<H1>Z_CCR_MIKROTIK CCR_1036 Cloudcore RB FAN-2 Speed Monitor</H1>

ShortLegend[mt-FAN2-speed]: RPM
LegendI[mt-FAN2-speed]:
LegendO[mt-FAN2-speed]: fan-2.rpm.speed
Legend1[mt-FAN2-speed]: fan-2.rpm.speed
Legend2[mt-FAN2-speed]: fan-2.rpm.speed

### MONITORING Z_CCR_MIKROTIK CCR_1036 AMP Monitor ###
Target[mt-amp-mon]: 1.3.6.1.4.1.14988.1.1.3.13.0&1.3.6.1.4.1.14988.1.1.3.13.0:public@10.0.0.1 / 10000
Options[mt-amp-mon]: gauge,growright,nopercent,pngdate,nobanner
MaxBytes[mt-amp-mon]: 30
Colours[mt-amp-mon]: RED#ff4f27,Y#fffb15,RED#ff4f27,RED#fffb15
#Unscaled[mt-amp-mon]: dwmy
YLegend[mt-amp-mon]: AMP USAGE Monitor
Title[mt-amp-mon]: Z_CCR_MIKROTIK CCR_1036 Cloudcore RB AMP Monitor
PageTop[mt-amp-mon]:
<H1>Z_CCR_MIKROTIK CCR_1036 Cloudcore RB AMP Monitor</H1>

ShortLegend[mt-amp-mon]: amp
LegendI[mt-amp-mon]:
LegendO[mt-amp-mon]: amps
Legend1[mt-amp-mon]: amps
Legend2[mt-amp-mon]: amps


ping.cfg


WorkDir: /var/www/mrtg
### ping.cfg
# 10.0.0.1 MIKROTIK NAS SERVERPING GRAPH
Title[mikrotik.ping]: MIKROTIK NAS SERVER PING RTT / Pkt LOSS Report
PageTop[mikrotik.ping]:
<H1>MIKROTIK NAS SERVER PING RTT / Pkt LOSS Report</H1>

Target[mikrotik.ping]: `/cfg/norping.sh 10.0.0.1`
Colours[mikrotik.ping]: R#f75712,G#04bf27,G#70ff53,R#70ff53
MaxBytes[mikrotik.ping]: 100
AbsMax[mikrotik.ping]: 100
Options[mikrotik.ping]: growright,gauge,pngdate,printrouter,nopercent,noinfo,logscale
#growright,nopercent,gauge
LegendI[mikrotik.ping]: Pkt LOSS
LegendO[mikrotik.ping]: Active Round Trip Time
YLegend[mikrotik.ping]: RTT
Legend1[mikrotik.ping]: Pkt LOSS
Legend2[mikrotik.ping]: Active RTT

# 8.8.8.8 GOOGLE SERVERPING GRAPH
Title[8.8.8.8.ping]: GOOGLE DNS PING RTT / Pkt LOSS Report
PageTop[8.8.8.8.ping]:
<H1>GOOGLE DNS PING RTT / Pkt LOSS Report</H1>

Target[8.8.8.8.ping]: `/cfg/norping.sh 8.8.8.8`
Colours[8.8.8.8.ping]: R#f75712,G#04bf27,G#70ff53,R#70ff53
MaxBytes[8.8.8.8.ping]: 100
AbsMax[8.8.8.8.ping]: 100
Options[8.8.8.8.ping]: growright,gauge,pngdate,printrouter,nopercent,noinfo,logscale
#growright,nopercent,gauge
LegendI[8.8.8.8.ping]: Pkt LOSS
LegendO[8.8.8.8.ping]: Active Round Trip Time
YLegend[8.8.8.8.ping]: RTT
Legend1[8.8.8.8.ping]: Pkt LOSS
Legend2[8.8.8.8.ping]: Active RTT


kesc.cfg


WorkDir: /var/www/mrtg

# 10.0.0.2 MIKROTIK AP FOR KESC RPING GRAPH
Title[kesc.ping]: K.E.S.C LIGHT FAILURE GRAPH / MRTG GRAPH
PageTop[kesc.ping]:
<H1>K.E.S.C LIGHT FAILURE / MRTG GRAPH Report ! z@iB</H1>

Target[kesc.ping]: `/cfg/kping.sh 10.0.0.2`
Colours[kesc.ping]: RED#ff4f27,GREEN#00eb0c,RED#ff4f27,RED#fffb15
MaxBytes[kesc.ping]: 100
AbsMax[kesc.ping]: 100
Options[kesc.ping]: growright,gauge,pngdate,printrouter,nopercent,noinfo,logscale
ShortLegend[kesc.ping]: %
LegendI[kesc.ping]: K.E Light Loss
LegendO[kesc.ping]: K.E Availability
YLegend[kesc.ping]: Red Bar Shows Failure (:)


norping.sh


#!/bin/bash
HOST=$1
ping -c 3 $HOST > /dev/null
DATA=`ping -c 3 $1 -q `
if [ $? -eq 0 ]
then
echo "0"
echo $DATA | awk -F/ '{print $6 }'

else
echo "100
0"
fi


APACHE / WEB SERVER Section

To enable cgi execution in /var/www/mrtg folder, edit the apache config file, and

nano /etc/apache2/sites-enabled/000-default

and paste following so that the last section of file should be like below …


<Directory /var/www/mrtg>
AddHandler cgi-script .cgi
Options +ExecCGI +Indexes
DirectoryIndex index.cgi
</Directory>
</VirtualHost>


mrtg-rrd.cgi or index.cgi to graph creation

Following CGI file will create MRTG graph on the fly (on demand)


#!/usr/bin/perl -w
# $Id: mrtg-rrd.cgi,v 1.35 2003/08/18 15:58:57 kas Exp $
# mrtg-rrd.cgi: The script for generating graphs for MRTG statistics.
# Loosely modelled after the Rainer.Bawidamann@informatik.uni-ulm.de's
# 14all.cgi
use strict;
use POSIX qw(strftime);
use Time::Local;
# The %.1f should work on 5.005+. There may be other problems, though.
# I've tested this on 5.8.0 only, so mind the gap!
require 5.005;
# Location of RRDs.pm, if it is not in @INC
# use lib '/usr/lib/perl5/5.00503/i386-linux';
use RRDs;
use vars qw(@config_files @all_config_files %targets $config_time
%directories $version $imagetype);

# EDIT THIS to reflect all your MRTG config files
BEGIN { @config_files = qw(/etc/mrtg.cfg); }

$version = '0.7';
# This depends on what image format your libgd (and rrdtool) uses
$imagetype = 'png'; # or make this 'gif';
# strftime(3) compatibility test
my $percent_h = '%-H';
$percent_h = '%H' if (strftime('%-H', gmtime(0)) !~ /^\d+$/);
sub handler ($)
{
my ($q) = @_;
try_read_config($q->url());
my $path = $q->path_info();
$path =~ s/^\///;
$path =~ s/\/$//;
if (defined $directories{$path}) {
if ($q->path_info() =~ /\/$/) {
print_dir($path);
} else {
print "Location: ", $q->url(-path_info=>1), "/\n\n";
}
return;
}

my ($dir, $stat, $ext) = ($q->path_info() =~
/^(.*)\/([^\/]+)(\.html|-(day|week|month|year)\.$imagetype)$/);

$dir =~ s/^\///;

print_error("Undefined statistics")
unless defined $targets{$stat};

print_error("Incorrect directory")
unless defined $targets{$stat}{directory} || $targets{$stat}{directory} eq $dir;

my $tgt = $targets{$stat};

common_args($stat, $tgt, $q);

# We may be running under mod_perl or something. Do not destroy
# the original settings of timezone.
my $oldtz;
if (defined $tgt->{timezone}) {
$oldtz = $ENV{TZ};
$ENV{TZ} = $tgt->{timezone};
}

if ($ext eq '.html') {
do_html($tgt);
} elsif ($ext eq '-day.' . $imagetype) {
do_image($tgt, 'day');
} elsif ($ext eq '-week.' . $imagetype) {
do_image($tgt, 'week');
} elsif ($ext eq '-month.' . $imagetype) {
do_image($tgt, 'month');
} elsif ($ext eq '-year.' . $imagetype) {
do_image($tgt, 'year');
} else {
print_error("Unknown extension");
}
$ENV{TZ} = $oldtz
if defined $oldtz;
}

sub do_html($)
{
my ($tgt) = @_;

my @day = do_image($tgt, 'day');
my @week = do_image($tgt, 'week');
my @month = do_image($tgt, 'month');
my @year = do_image($tgt, 'year');

http_headers('text/html', $tgt->{config});
print <<'EOF';
<HTML>
<HEAD>
<TITLE>
EOF
print $tgt->{title} if defined $tgt->{title};
print "</TITLE>\n";

html_comments($tgt, 'd', @{$day[0]}) if $#day != -1;
html_comments($tgt, 'w', @{$week[0]}) if $#week != -1;
html_comments($tgt, 'm', @{$month[0]}) if $#month != -1;
html_comments($tgt, 'y', @{$year[0]}) if $#year != -1;

print $tgt->{addhead} if defined $tgt->{addhead};

print "</HEAD>\n", $tgt->{bodytag}, "\n";

print $tgt->{pagetop} if defined $tgt->{pagetop};

unless (defined $tgt->{options}{noinfo}) {
my @st = stat $tgt->{rrd};

print "

<hr>

\nThe statistics were last updated ",
strftime("<B>%A, %d %B, %H:%M:%S %Z</B>\n",
localtime($st[9]));
}

my $dayavg = $tgt->{config}->{interval};

html_graph($tgt, 'day', 'Daily', $dayavg . ' Minute', \@day);
html_graph($tgt, 'week', 'Weekly', '30 Minute', \@week);
html_graph($tgt, 'month', 'Monthly', '2 Hour', \@month);
html_graph($tgt, 'year', 'Yearly', '1 Day', \@year);

unless (defined $tgt->{options}{nolegend}) {
print <<EOF;

<hr>

<table WIDTH=500 BORDER=0 CELLPADDING=4 CELLSPACING=0>
EOF
print <<EOF unless ($tgt->{options}{noi});
<tr>
<td ALIGN=RIGHT><font SIZE=-1 COLOR="$tgt->{col1}">
<b>$tgt->{colname1} ###</b></font></td>
<td><font SIZE=-1>$tgt->{legend1}</font></td>
</tr>
EOF
print <<EOF unless ($tgt->{options}{noo});
<tr>
<td ALIGN=RIGHT><font SIZE=-1 COLOR="$tgt->{col2}">
<b>$tgt->{colname2} ###</b></font></td>
<td><font SIZE=-1>$tgt->{legend2}</font></td>
</tr>
EOF
if ($tgt->{withpeak} ne '') {
print <<EOF unless ($tgt->{options}{noi});
<tr>
<td ALIGN=RIGHT><font SIZE=-1 COLOR="$tgt->{col3}">
<b>$tgt->{colname3} ###</b></font></td>
<td><font SIZE=-1>$tgt->{legend3}</font></td>
</tr>
EOF
print <<EOF unless ($tgt->{options}{noo});
<tr>
<td ALIGN=RIGHT><font SIZE=-1 COLOR="$tgt->{col4}">
<b>$tgt->{colname4} ###</b></font></td>
<td><font SIZE=-1>$tgt->{legend4}</font></td>
</tr>
EOF
}
print <<EOF;</table>
EOF
}

print_banner($tgt->{config})
unless defined $tgt->{options}{nobanner};

print $tgt->{pagefoot} if defined $tgt->{pagefoot};
print "\n", <<'EOF';
</body>
</html>
EOF

}

sub html_comments($$@)
{
my ($tgt, $letter, @val) = @_;

return if $#val == -1;

unless ($tgt->{options}{noi}) {
print "<!-- maxin $letter ", $val[1], " -->\n";
print "<!-- avin $letter ", $val[3], " -->\n";
print "<!-- cuin $letter ", $val[5], " -->\n";
}
unless ($tgt->{options}{noo}) {
print "<!-- maxout $letter ", $val[0], " -->\n";
print "<!-- avout $letter ", $val[2], " -->\n";
print "<!-- cuout $letter ", $val[4], " -->\n";
}
}
sub html_graph($$$$$)
{
my ($tgt, $ext, $freq, $period, $params) = @_;

return unless defined $tgt->{$ext};

my @values = @{$params->[0]};
my $x = $params->[1];
my $y = $params->[2];

$x *= $tgt->{xzoom} if defined $tgt->{xzoom};
$y *= $tgt->{yzoom} if defined $tgt->{yzoom};

my $kilo = $tgt->{kilo};
my @kmg = split(',', $tgt->{kmg});

my $fmt;
if (defined $tgt->{options}{integer}) {
$fmt = '%d';
} else {
$fmt = '%.1f';
}

my @percent = do_percent($tgt, \@values);
my @relpercent = do_relpercent($tgt, \@values);

my @nv;
for my $val (@values) {
if (@kmg == 0) { # kMG[target]: <empty>
push @nv, sprintf($fmt, $val);
next;
}
for my $si (@kmg) {
if ($val < 10000) {
push @nv, sprintf($fmt, $val) . " $si";
last;
}
$val /= $kilo;
}
}
@values = @nv;

print "

<hr>

\n<B>\`$freq\' Graph ($period Average)</B>
\n";

print '<IMG SRC="', $tgt->{url}, '-', $ext, '.' . $imagetype .
'" WIDTH=', $x, ' HEIGHT=', $y, ' ALT="', $freq,
' Graph" VSPACE=10 ALIGN=TOP>
', "\n";
print '
<TABLE CELLPADDING=0 CELLSPACING=0>';
print <<EOF if $tgt->{legendi} ne '' && !$tgt->{options}{noi};
<TR>
<TD ALIGN=RIGHT><SMALL>Max <FONT COLOR="$tgt->{col1}">$tgt->{legendi}</FONT></SMALL></TD>
<TD ALIGN=RIGHT><SMALL>&nbsp;$values[1]$tgt->{shortlegend}$percent[1]</SMALL></TD>
<TD WIDTH=5></TD>
<TD ALIGN=RIGHT><SMALL>Average <FONT COLOR="$tgt->{col1}">$tgt->{legendi}</FONT></SMALL></TD>
<TD ALIGN=RIGHT><SMALL>&nbsp;$values[3]$tgt->{shortlegend}$percent[3]</SMALL></TD>
<TD WIDTH=5></TD>
<TD ALIGN=RIGHT><SMALL>Current <FONT COLOR="$tgt->{col1}">$tgt->{legendi}</FONT></SMALL></TD>
<TD ALIGN=RIGHT><SMALL>&nbsp;$values[5]$tgt->{shortlegend}$percent[5]</SMALL></TD>
</TR>

EOF
print <<EOF if $tgt->{legendo} ne '' && !$tgt->{options}{noo};
<TR>
<TD ALIGN=RIGHT><SMALL>Max <FONT COLOR="$tgt->{col2}">$tgt->{legendo}</FONT></SMALL></TD>
<TD ALIGN=RIGHT><SMALL>&nbsp;$values[0]$tgt->{shortlegend}$percent[0]</SMALL></TD>
<TD WIDTH=5></TD>
<TD ALIGN=RIGHT><SMALL>Average <FONT COLOR="$tgt->{col2}">$tgt->{legendo}</FONT></SMALL></TD>
<TD ALIGN=RIGHT><SMALL>&nbsp;$values[2]$tgt->{shortlegend}$percent[2]</SMALL></TD>
<TD WIDTH=5></TD>
<TD ALIGN=RIGHT><SMALL>Current <FONT COLOR="$tgt->{col2}">$tgt->{legendo}</FONT></SMALL></TD>
<TD ALIGN=RIGHT><SMALL>&nbsp;$values[4]$tgt->{shortlegend}$percent[4]</SMALL></TD>

EOF
if (defined $tgt->{options}{dorelpercent}) {
print <<"EOF";
</TR>
<TR>
<TD ALIGN=RIGHT><SMALL>Max <FONT COLOR="$tgt->{col5}">&nbsp;Percentage:</FONT></SMALL></TD>
<TD ALIGN=RIGHT><SMALL>&nbsp;$relpercent[0]</SMALL></TD>
<TD WIDTH=5></TD>
<TD ALIGN=RIGHT><SMALL>Average <FONT COLOR="$tgt->{col5}">&nbsp;Percentage:</FONT></SMALL></TD>
<TD ALIGN=RIGHT><SMALL>&nbsp;$relpercent[1]</SMALL></TD>
<TD WIDTH=5></TD>
<TD ALIGN=RIGHT><SMALL>Current <FONT COLOR="$tgt->{col5}">&nbsp;Percentage:</FONT></SMALL></TD>
<TD ALIGN=RIGHT><SMALL>&nbsp;$relpercent[2]</SMALL></TD>

EOF
}
print <<'EOF';
</TR>
</TABLE>

EOF
}

sub do_percent($$)
{
my ($tgt, $values) = @_;

my @percent = ('', '', '', '', '', '');

return @percent if defined $tgt->{options}{nopercent};

for my $val (0..$#$values) {
my $mx = ($val % 2 == 1) ? $tgt->{maxbytes1} : $tgt->{maxbytes2};
next unless defined $mx;
my $p = sprintf("%.1f", $values->[$val]*100/$mx);
$percent[$val] = ' (' . $p . '%)';
}

@percent;
}

sub do_relpercent($$)
{
my ($tgt, $values) = @_;

my @percent = ('', '', '');

return @percent unless defined $tgt->{options}{dorelpercent};

for my $val (0..2) {
$percent[$val] = sprintf("%.1f",
$values->[2*$val+1] * 100 / $values->[2*$val])
if $values->[2*$val] > 0;
$percent[$val] ||= 0;
$percent[$val] .= ' %';
}

@percent;
}

sub http_headers($$)
{
my ($content_type, $cfg) = @_;

print <<"EOF"; Content-Type: $content_type Refresh: $cfg->{refresh}
Pragma: no-cache
EOF
# Expires header calculation stolen from CGI.pm
print strftime("Expires: %a, %d %b %Y %H:%M:%S GMT\n",
gmtime(time+60*$cfg->{interval}));

print "\n";
}

sub do_image($$)
{
my ($target, $ext) = @_;

my $file = $target->{$ext};

return unless defined $file;

# Now the vertical rule at the end of the day
my @t = localtime(time);
$t[0] = $t[1] = $t[2] = 0;

my $seconds;
my $oldsec;
my $back;
my $xgrid;

my $unscaled;
my $withpeak;

my $noi = 1 if $target->{options}{noi};
my $noo = 1 if $target->{options}{noo};

if ($ext eq 'day') {
$seconds = timelocal(@t);
$back = 30*3600; # 30 hours
$oldsec = $seconds - 86400;
$unscaled = 1 if $target->{unscaled} =~ /d/;
$withpeak = 1 if $target->{withpeak} =~ /d/;
# We need this only for day graph. The other ones
# are magically correct.
$xgrid = 'HOUR:1:HOUR:6:HOUR:2:0:' . $percent_h;
} elsif ($ext eq 'week') {
$seconds = timelocal(@t);
$t[6] = ($t[6]+6) % 7;
$seconds -= $t[6]*86400;
$back = 8*86400; # 8 days
$oldsec = $seconds - 7*86400;
$unscaled = 1 if $target->{unscaled} =~ /w/;
$withpeak = 1 if $target->{withpeak} =~ /w/;
} elsif ($ext eq 'month') {
$t[3] = 1;
$seconds = timelocal(@t);
$back = 36*86400; # 36 days
$oldsec = $seconds - 30*86400; # FIXME (the right # of days!!)
$unscaled = 1 if $target->{unscaled} =~ /m/;
$withpeak = 1 if $target->{withpeak} =~ /m/;
} elsif ($ext eq 'year') {
$t[3] = 1;
$t[4] = 0;
$seconds = timelocal(@t);
$back = 396*86400; # 365 + 31 days
$oldsec = $seconds - 365*86400; # FIXME (the right # of days!!)
$unscaled = 1 if $target->{unscaled} =~ /y/;
$withpeak = 1 if $target->{withpeak} =~ /y/;
} else {
print_error("Unknown file extension: $ext");
}

my @local_args;

if ($unscaled) {
@local_args = ('-u', $target->{maxbytes1});
push @local_args, '--rigid' unless defined $target->{absmax};
}

if ($xgrid) {
push @local_args, '-x', $xgrid;
}

my @local_args_end;

if ($withpeak) {
push @local_args_end, 'LINE1:maxin'.$target->{col3}.':MaxIn'
unless $noi;
push @local_args_end, 'LINE1:maxout'.$target->{col4}.':MaxOut'
unless $noo;
}

my @rv = RRDs::graph($file, '-s', "-$back", @local_args,
@{$target->{args}}, "VRULE:$oldsec#ff0000",
"VRULE:$seconds#ff0000", @local_args_end);

my $rrd_error = RRDs::error;
print_error("RRDs::graph failed, $rrd_error") if defined $rrd_error;

# In array context just return the values
if (wantarray) {
if (defined $target->{factor}) {
@{$rv[0]} = map { $_ * $target->{factor} } @{$rv[0]};
}
if ($noi) {
return ([$rv[0][0], 0, $rv[0][1], 0, $rv[0][2], 0],
$rv[1], $rv[2]);
} elsif ($noo) {
return ([0, $rv[0][0], 0, $rv[0][1], 0, $rv[0][2]],
$rv[1], $rv[2]);
} else {
return @rv;
}
}

# Not in array context ==> print out the PNG file.
open PNG, "<$file" or print_error("Can't open $file: $!"); binmode PNG; http_headers("image/$imagetype", $target->{config});

my $buf;
# could be sendfile in Linux 😉
while(sysread PNG, $buf, 8192) {
print $buf;
}
close PNG;
}

sub common_args($$$)
{
my ($name, $target, $q) = @_;

return @{$target->{args}} if defined @{$target->{args}};

my $noi = 1 if $target->{options}{noi};
my $noo = 1 if $target->{options}{noo};

$target->{name} = $name;

$target->{directory} = ''
unless defined $target->{directory};

my $tdir = $target->{directory};
$tdir .= '/'
unless $tdir eq '' || $tdir =~ /\/$/;

$target->{url} = $q->url . '/' . $tdir . $name;

my $cfg = $target->{config};

my $dir = $cfg->{workdir};
$dir = $cfg->{logdir}
if defined $cfg->{logdir};

$target->{rrd} = $dir . '/' . $tdir . $name . '.rrd';

%{$target->{options}} = ()
unless defined %{$target->{options}};

$dir = $cfg->{workdir};
$dir = $cfg->{imagedir}
if defined $cfg->{imagedir};

$target->{suppress} ||= '';

$target->{day} = $dir . '/' . $tdir . $name
. '-day.' . $imagetype unless $target->{suppress} =~ /d/;
$target->{week} = $dir . '/' . $tdir . $name
. '-week.' . $imagetype unless $target->{suppress} =~ /w/;
$target->{month} = $dir . '/' . $tdir . $name
. '-month.' . $imagetype unless $target->{suppress} =~ /m/;
$target->{year} = $dir . '/' . $tdir . $name
. '-year.' . $imagetype unless $target->{suppress} =~ /y/;

$target->{maxbytes1} = $target->{maxbytes}
if defined $target->{maxbytes} && !defined $target->{maxbytes1};

$target->{maxbytes2} = $target->{maxbytes1}
if defined $target->{maxbytes1} && !defined $target->{maxbytes2};

my @args = ();

push @args, '--lazy', '-c', 'FONT#000000', '-c',
'MGRID#000000', '-c', 'FRAME#000000',
'-g', '-l', '0';

$target->{background} = '#f5f5f5'
unless defined $target->{background};

push @args, '-c', 'BACK'. $target->{background};

push @args, '-c', 'SHADEA' . $target->{background},
'-c', 'SHADEB' . $target->{background}
if defined $target->{options}{noborder};

if (defined $target->{options}{noarrow}) {
push @args, '-c', 'ARROW' . $target->{background};
} else {
push @args, '-c', 'ARROW#000000';
}

push @args, '-b', $target->{kilo}
if defined $target->{kilo};

if (defined $target->{xsize}) {
if (defined $target->{xscale}) {
push @args, '-w', $target->{xsize}*$target->{xscale};
} else {
push @args, '-w', $target->{xsize};
}
}

if (defined $target->{ysize}) {
if (defined $target->{yscale}) {
push @args, '-h', $target->{ysize}*$target->{yscale};
} else {
push @args, '-h', $target->{ysize};
}
}

my $scale = 1;

if (defined $target->{options}->{perminute}) {
$scale *= 60;
} elsif (defined $target->{options}->{perhour}) {
$scale *= 3600;
}

if (defined $target->{options}->{bits}) {
$scale *= 8;
$target->{ylegend} = 'Bits per second'
unless defined $target->{ylegend};
$target->{legend1} = 'Incoming Traffic in Bits per Second'
unless defined $target->{legend1};
$target->{legend2} = 'Outgoing Traffic in Bits per Second'
unless defined $target->{legend2};
$target->{legend3} = 'Peak Incoming Traffic in Bits per Second'
unless defined $target->{legend3};
$target->{legend4} = 'Peak Outgoing Traffic in Bits per Second'
unless defined $target->{legend4};
$target->{shortlegend} = 'b/s'
unless defined $target->{shortlegend};
} else {
$target->{ylegend} = 'Bytes per second'
unless defined $target->{ylegend};
$target->{legend1} = 'Incoming Traffic in Bytes per Second'
unless defined $target->{legend1};
$target->{legend2} = 'Outgoing Traffic in Bytes per Second'
unless defined $target->{legend2};
$target->{legend3} = 'Peak Incoming Traffic in Bytes per Second'
unless defined $target->{legend3};
$target->{legend4} = 'Peak Outgoing Traffic in Bytes per Second'
unless defined $target->{legend4};
$target->{shortlegend} = 'B/s'
unless defined $target->{shortlegend};
}

if ($scale > 1) {
push @args, "DEF:in0=$target->{rrd}:ds0:AVERAGE",
"CDEF:in=in0,$scale,*",
"DEF:maxin0=$target->{rrd}:ds0:MAX",
"CDEF:maxin=maxin0,$scale,*"
unless $noi;
push @args, "DEF:out0=$target->{rrd}:ds1:AVERAGE",
"CDEF:out=out0,$scale,*",
"DEF:maxout0=$target->{rrd}:ds1:MAX",
"CDEF:maxout=maxout0,$scale,*"
unless $noo;
} else {
push @args, "DEF:in=$target->{rrd}:ds0:AVERAGE",
"DEF:maxin=$target->{rrd}:ds0:MAX"
unless $noi;
push @args, "DEF:out=$target->{rrd}:ds1:AVERAGE",
"DEF:maxout=$target->{rrd}:ds1:MAX"
unless $noo;
}

my $i=1;
for my $coltext (split(/,/, $target->{colours})) {
my ($text, $rgb) = ($coltext =~ /^([^#]+)(#[0-9a-fA-F]{6})$/);
$target->{'col'.$i} = $rgb;
$target->{'colname'.$i} = $text;
$i++;
}

push @args, '-v', $target->{ylegend};

push @args, 'AREA:in' . $target->{col1} . ':In',
unless $noi;
push @args, 'LINE2:out' . $target->{col2} . ':Out'
unless $noo;

push @args, 'PRINT:out:MAX:%.1lf' unless $noo;
push @args, 'PRINT:in:MAX:%.1lf' unless $noi;
push @args, 'PRINT:out:AVERAGE:%.1lf' unless $noo;
push @args, 'PRINT:in:AVERAGE:%.1lf' unless $noi;
push @args, 'PRINT:out:LAST:%.1lf' unless $noo;
push @args, 'PRINT:in:LAST:%.1lf' unless $noi;

if (defined $target->{maxbytes1}) {
$target->{maxbytes1} *= $scale;
push @args, 'HRULE:' . $target->{maxbytes1} . '#cc0000';
}

if (defined $target->{maxbytes2}) {
$target->{maxbytes2} *= $scale;
push @args, 'HRULE:' . $target->{maxbytes2} . '#cccc00'
if $target->{maxbytes2} != $target->{maxbytes1};
}

@{$target->{args}} = @args;

@args;
}

sub try_read_config($)
{
my ($prefix) = (@_);
$prefix =~ s/\/[^\/]*$//;

# Verify the version of RRDtool:
if (!defined $RRDs::VERSION || $RRDs::VERSION < 1.000331) {
print_error("Please install more up-to date RRDtool - need at least 1.000331");
}

my $read_cfg;
if (!defined $config_time) {
$read_cfg = 1;
} else {
for my $file (@all_config_files) {
my @stat = stat $file;
if ($config_time < $stat[9]) { $read_cfg = 1; last; } } } return unless $read_cfg; my %defaults = ( xsize => 400,
ysize => 100,
kmg => ',k,M,G,T,P',
kilo => 1000,
bodytag => "<BODY BGCOLOR=#ffffff>\n",
colours => 'GREEN#00cc00,BLUE#0000ff,DARK GREEN#006600,MAGENTA#ff00ff,AMBER#ef9f4f',
legendi => '&nbsp;In:',
legendo => '&nbsp;Out:',
unscaled => '',
withpeak => '',
directory => '',
);

%targets = ();

@all_config_files = @config_files;

my $order = 0;
for my $cfgfile (@config_files) {
%{$targets{_}} = %defaults;
%{$targets{'^'}} = ();
%{$targets{'$'}} = ();

my $cfgref = {
refresh => 300,
interval => 5,
icondir => $prefix
};

read_mrtg_config($cfgfile, \%defaults, $cfgref, \$order);
}

delete $targets{'^'};
delete $targets{_};
delete $targets{'$'};

parse_directories();

$config_time = time;
}

sub read_mrtg_config($$$$);

sub read_mrtg_config($$$$)
{
my ($file, $def, $cfgref, $order) = @_;

my %defaults = %$def;

my @lines;

open(CFG, "<$file") || print_error("Cannot open config file: $!");
while (<CFG>) {
chomp; # remove newline
s/\s+$//; # remove trailing space
s/\s+/ /g; # collapse white spaces to ' '
next if /^ *\#/; # skip comment lines
next if /^\s*$/; # skip empty lines
if (/^ \S/) { # multiline options
$lines[$#lines] .= $_;
} else {
push @lines, $_;
}
}
close CFG;

foreach (@lines) {
if (/^\s*([\w\d]+)\[(\S+)\]\s*:\s*(.*)$/) {
my ($tgt, $opt, $val) = (lc($2), lc($1), $3);
unless (exists $targets{$tgt}) {
# pre-set defaults constructed on all of ^, _, and $
for my $key (%{$targets{'^'}}) {
$targets{$tgt}{$key} = $targets{'^'}{$key};
}
for my $key (%{$targets{'$'}}) {
$targets{$tgt}{$key} .= $targets{'$'}{$key};
}
# WARNING: Tobi explicitly said that when all ^, _, and $
# options are set, the result should be just the value
# of the _ option (when the option itself is not explicitly
# defined. I do not agree with him here but I respect this
# and will try to be compatible with MRTG.
for my $key (%{$targets{'_'}}) {
$targets{$tgt}{$key} = $targets{'_'}{$key};
}

# anonymous hash ref - need copy, not ref
delete $targets{$tgt}{options};
# The same as above - we need to create this
# based on [^], [_], and [$] values
%{$targets{$tgt}{options}} = ();
%{$targets{$tgt}{options}} = %{$targets{'^'}{options}}
if defined $targets{'^'}{options};
%{$targets{$tgt}{options}} = (%{$targets{$tgt}{options}},
%{$targets{'_'}{options}})
if defined $targets{'_'}{options};
%{$targets{$tgt}{options}} = (%{$targets{$tgt}{options}},
%{$targets{'$'}{options}})
if defined $targets{'$'}{options};

$targets{$tgt}{order} = ++$$order;
$targets{$tgt}{config} = $cfgref;
}
if ($tgt eq '_' && $val eq '') {
if (defined $defaults{$opt}) {
$targets{_}{$opt} = $defaults{$opt};
} else {
delete $targets{_}{$opt};
}
} elsif (($tgt eq '^' || $tgt eq '$') && $val eq '') {
delete $targets{$tgt}{$opt};
} elsif ($opt eq 'options') {
# Do not forget defaults [^] and [$]
delete $targets{$tgt}{options};
%{$targets{$tgt}{options}} = %{$targets{'^'}{options}}
if defined $targets{'^'}{options};
$val = lc($val);
map { $targets{$tgt}{options}{$_} = 1 } ($val =~ m/([a-z]+)/g);
%{$targets{$tgt}{options}} = (%{$targets{$tgt}{options}},
%{$targets{'$'}{options}})
if defined $targets{'$'}{options};
} else {
my $pre = $targets{'^'}{$opt}
if defined $targets{'^'}{$opt};
$pre ||= '';
$targets{$tgt}{$opt} = $pre.$val;
$targets{$tgt}{$opt} .= $targets{'$'}{$opt}
if defined $targets{'$'}{$opt};
}
next;
} elsif (/^Include\s*:\s*(\S*)$/) {
push @all_config_files, $1;
read_mrtg_config($1, $def, $cfgref, $order);
next;
} elsif (/^([\w\d]+)\s*:\s*(\S.*)$/) {
my ($opt, $val) = (lc($1), $2);
$cfgref->{$opt} = $val;
next;
}
print_error("Parse error in $file near $_");
}

if (defined $cfgref->{pathadd}) {
$ENV{PATH} .= ':'.$cfgref->{pathadd};
}

# if (defined $cfgref->{libadd}) {
# use lib $cfgref->{libadd}
# }
}

sub parse_directories {
%directories = ();

# FIXME: the sort is expensive
for my $name (sort { $targets{$a}{order} <=> $targets{$b}{order} } keys %targets) {
my $dir = $targets{$name}{directory}
if defined $targets{$name}{directory};
$dir = '' unless defined $dir;

my $prefix = '';
for my $component (split /\/+/, $dir) {
unless (defined $directories{$prefix.$component}) {
push (@{$directories{$prefix}{subdir}},
$component);

# For the directory, get the global parameters
# from the # config of the first item of the
# directory:
$directories{$prefix}{config} =
$targets{$name}{config};
$directories{$prefix}{bodytag} =
$targets{$name}{bodytag};
}
$prefix .= $component . '/';
}
unless (defined $directories{$dir}) {
$directories{$dir}{config} =
$targets{$name}{config};
$directories{$dir}{bodytag} =
$targets{$name}{bodytag};
}

push (@{$directories{$dir}{target}}, $name);
}
}

sub print_dir($) {
my ($dir) = @_;

my $dir1 = $dir . '/';

http_headers('text/html', $directories{$dir}{config});

print <<EOF;
<HTML>
<HEAD>
<TITLE>MRTG: Directory $dir1</TITLE>
</HEAD>
EOF
print $directories{$dir}{bodytag};

my $subdirs_printed;
if (defined @{$directories{$dir}{subdir}}) {
$subdirs_printed = 1;
print <<EOF;
<H1>MRTG subdirectories in the directory $dir1</H1>
<UL>
EOF
for my $item (@{$directories{$dir}{subdir}}) {
print "
<LI><A HREF=\"$item/\">$item/</A>\n";
}

print "</UL>

\n";
}
if (defined @{$directories{$dir}{target}}) {
print "

<hr>

\n" if defined $subdirs_printed;
print <<EOF;
<H1>MRTG graphs in the directory $dir1</H1>
<TABLE BORDER=0 WIDTH=100%>
EOF
my $odd;
for my $item (@{$directories{$dir}{target}}) {
my $itemname = $item;
$itemname = $targets{$item}{title}
if defined $targets{$item}{title};
print "
<TR>\n" unless $odd;
print <<EOF;
<TD><A HREF="$item.html">$itemname
<IMG SRC="$item-day.$imagetype" BORDER=0 ALIGN=TOP VSPACE=10 ALT="$item">
</A><BR CLEAR=ALL>
</TD>

EOF
print " </TR>

\n" if $odd;
$odd = !$odd;
}
print " </TR>

\n</TABLE>

\n";
}

print_banner($directories{$dir}{config});
print "</BODY>\n</HTML>\n";
}

sub print_banner($) {
my $cfg = shift;

print <<EOF;

<hr>

<table BORDER=0 CELLSPACING=0 CELLPADDING=0>
<tr>
<td WIDTH=63><a ALT="MRTG" HREF="http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html"><img BORDER=0 SRC="$cfg->{icondir}/mrtg-l.$imagetype"></a></td>
<td WIDTH=25><a ALT="" HREF="http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html"><img BORDER=0 SRC="$cfg->{icondir}/mrtg-m.$imagetype"></a></td>
<td WIDTH=388><a ALT="" HREF="http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html"><img BORDER=0 SRC="$cfg->{icondir}/mrtg-r.$imagetype"></a></td>
</tr>
</table>
<spacer TYPE=VERTICAL SIZE=4>
<table BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=476>
<tr VALIGN=top>
<td ALIGN=LEFT><font FACE="Arial,Helvetica" SIZE=2>
version 2.9.17</font></td>
<td ALIGN=RIGHT><font FACE="Arial,Helvetica" SIZE=2>
<a HREF="http://ee-staff.ethz.ch/~oetiker/">Tobias Oetiker</a>
<a HREF="mailto:oetiker\@ee.ethz.ch">&lt;oetiker\@ee.ethz.ch&gt;</a>
</font></td>
</tr>
<tr>
<td></td>
<td ALIGN=RIGHT><font FACE="Arial,Helvetica" SIZE=2>
and&nbsp;<a HREF="http://www.bungi.com">Dave&nbsp;Rand</a>&nbsp;<a HREF="mailto:dlr\@bungi.com">&lt;dlr\@bungi.com&gt;</a></font></td>
<tr VALIGN=top>
<td ALIGN=LEFT><font FACE="Arial,Helvetica" SIZE=2>
<A HREF=http://www.fi.muni.cz/~kas/mrtg-rrd/>mrtg-rrd.cgi version $version</A>
</font></td>
<td ALIGN=RIGHT><font FACE="Arial,Helvetica" SIZE=2>
<A HREF="http://www.fi.muni.cz/~kas/">Jan "Yenya" Kasprzak</A>
<A HREF="mailto:kas\@fi.muni.cz">&lt;kas\@fi.muni.cz&gt;</A>
</font></td>
</tr>
</table>
EOF
print '<!--$Id: mrtg-rrd.cgi,v 1.35 2003/08/18 15:58:57 kas Exp $-->', "\n";
}

sub dump_targets() {
for my $tgt (keys %targets) {
print "Target $tgt:\n";
for my $opt (keys %{$targets{$tgt}}) {
if ($opt eq 'options') {
print "\toptions: ";
for my $o1 (keys %{$targets{$tgt}{options}}) {
print $o1, ",";
}
print "\n";
next;
}
print "\t$opt: ", $targets{$tgt}{$opt}, "\n";
}
}
}

sub dump_directories {
print "Directories:\n";

for my $dir (keys %directories) {
print "Directory $dir:\n";
for my $item (@{$directories{$dir}}) {
print "\t$item\n";
}
}
}

sub print_error(@)
{
print "Content-Type: text/plain\n\nError: ", join(' ', @_), "\n";
exit 0;
}

#--BEGIN CGI--
#For CGI, use this:

use CGI;
my $q = new CGI;

# thttpd fix up by Akihiro Sagawa
if ($q->server_software() =~ m|^thttpd/|) {
my $path = $q->path_info();
$path .= '/' if ($q->script_name=~ m|/$|);
$q->path_info($path);
}

handler($q);

#--END CGI--
#--BEGIN FCGI--
# For FastCGI, uncomment this and comment out the above:
#-# use FCGI;
#-# use CGI;
#-#
#-# my $req = FCGI::Request();
#-#
#-# while ($req->Accept >= 0) {
#-# my $q = new CGI;
#-#
#-# # thttpd fix up by Akihiro Sagawa
#-# if ($q->server_software() =~ m|^thttpd/|) {
#-# my $path = $q->path_info();
#-# $path .= '/' if ($q->script_name=~ m|/$|);
#-# $q->path_info($path);
#-# }
#-#
#-# handler($q);
#-# }
#--END FCGI--

1;


Few Tips

Make sure you install rrdtool before using it 🙂

apt-get -y install rrdtool

To execute MRTG with command manually

env LANG=C mrtg /etc/mrtg.cfg

To assign apache www-data users full rights to /var/www/mrtg folder

chown -R www-data /var/www/mrtg/

SNMPWALK sample command to query any OID from snmp enabled target machine

snmpwalk -v1 -c gt 10.0.0.1  .1.3.6.1.2.1.25.2.3.1.6.65536

CFGMAKER command to create interface commands (this will support acquiring data larget then 120 M limit) as explained here. ( https://aacable.wordpress.com/tag/mrtg-120m-limit/ )

cfgmaker public@10.0.0.1:::::2 > temp.cfg

MRTG crontab sample (1 minute interval when using RRD)

*/1 * * * * env LANG=C mrtg /etc/mrtg.cfg –logging /var/log/mrtg.log

Enable CGI

sudo a2enmod cgi

Can’t locate RRDs.pm in @INC

SOLUTION:

sudo apt-get install librrds-perl


Some Sample Outputs !

WAN Usage: [Below …]

1-wan

Noc Room Temperature

1- noc room temp.PNG

Disk Space Used in Percent %

2- disk space of mail.PNG

Active PPP Users on CCR_1036

2-active-pppoe

CPU Usage of CCR_1036

3-mt-cpu-load

PING to Google DNS via CCR_1036

4-ping

Memory Usage of CCR_1036

5-memory

RB Temperature of CCR_1036

6-ccr-1036-rb-board-temperature

RB Voltage history of CCR_1036

7-rb-ccr-1036-voltage

SERVER UPTIME

3- server uptime.PNG

Memory Usage of Linux System

8-radius-memory


Regard’s
~ Syed Jahanza!B ~

November 25, 2016

Mikrotik: Switching between interface

Filed under: Mikrotik Related — Tags: , , , — Syed Jahanzaib / Pinochio~:) @ 2:18 PM

f

NOT FOR GENERAL PUBLIC

SHARING IT FOR PERSONAL REFERENCE


Following is an script that switches connectivity between two interfaces (usually wan).

Example: ISP x have provided internet connectivity via fiber link . as a backup / redundancy link ISP have provided second fiber line. Both link have same ip address with same gateway. There are other ways too , this is just one way of achieving task. it can be customized in many ways like forcing specific hosts to be monitored by ping and act accordingly , or by having bridge etc.

IP address example:

in /ip address >>>

sfp1 = 10.0.0.1 (with comments “PRIMARY-SFP1”)
[remains enabled until next status changed]

sfp2 = 10.0.0.1 (with comments “SECONDARY-SFP2”)
[remains enabled until next status changed]

The script will do following.

Check the SFP1 Status, if it does not found “linkok” reply, it will log event, send email/sms alert to admin, and switch to SFP2 port by enabling IP of SFP2 [and Disable ip on SFP1]

On next run, if it found SFP1 link ok, then it will log event, send email/sms alert to admin, and switch back to SFP1 port by enabling IP of SFP1 and disable ip on SFP2.


# Mikrotik SPF Link monitoring SCRIPT with optional Email and SMS Alert,
# We are using local KANNEL as SMS gateway and GMAIL as email sender
# by Syed Jahanzaib
# https://aacable.wordpress.com
# Email : aacable at hotmail dot com
# Script Last Modified : 25-NOV-2016 / 1400 hours

# PRIMARY FIBER LINK
:local INT "sfp1"
# SECONDARY BACKUP FIBER LINK
:local INT2 "sfp2"
:local i 0;
:local F 0;
:local date;
:local time;
:global sub1 ([/system identity get name])
:global sub2 ([/system clock get time])
:global sub3 ([/system clock get date])
:set date [/system clock get date];
:set time [/system clock get time];
:local cell1 "03333021909"
:global FIBERnetstatus;
:global FIBERnetlastchange;
:global FIBERIP;

# Company Name, do not use spaces in it
:local COMPANY "ZZZ"

# Setting GMAIL config
:local sub1 ([/system identity get name])
:local sub2 ([/system clock get date])
:local sub3 ([/system clock get time])
:local TO1 "RECIPIENT-1@hotmail.com"
:local gmailid "YOUR-GMAIL-ID@gmail.com"

#If you dont have kannel sms gateway ignore this.
:local KURL "http://10.0.0.1:13013/cgi-bin/sendsms"
:local KID "kannel"
:local KPASS "KANNEL-PASS"

# SMS DOWN status Msg format for Kannel SMS gateway (donot use spaces in it)
:local MSGDOWNSMS "$COMPANY+FIBER+ALERT:%0A$INT+fiber+is+now+DOWN.%0ASwitching+to+$INT2+backup+fiber+link"
# SMS UP status Msg format for Kannel SMS gateway (donot use spaces in it)
:local MSGUPSMS "$COMPANY+FIBER+INFO:%0A$INT+fiber+is+now+UP.%0ASwitching+back+to+$INT"

# EMAIL Msg format for FIBER DOWN
:local MSGDOWNEMAIL "$COMPANY FIBER ALERT: $INT fiber is now DOWN at $sub1 $sub2 $sub3 . Switching to $INT2 backup link. Please Verify it."
# EMAIL Msg format for FIBER UP
:local MSGUPEMAIL "$COMPANY FIBER INFO: $INT fiber is now UP at $sub1 $sub2 $sub3 . Switching back to $INT primary link. Please Verify it."
# LOG error
:local DOWNLOG1 "$COMPANY FIBER ALERT: $INT fiber is now DOWN at $sub1 $sub2 $sub3 . Switching to $INT2 backup link. Please Verify it."
:local UPLOG1 "$COMPANY FIBER INFO: $INT fiber is now UP at $sub1 $sub2 $sub3 . Switching back to $INT primary link. Please Verify it"

######################################
########## Start the SCRIPT ###############
########## DONOT EDIT BELOW ############
######################################

local link;
/interface ethernet cable-test $INT once do={
:set link $"status";
};

:if ($link != "link-ok") do={
:log error "$INT SFP DOWN"

:if (($FIBERnetstatus="UP")) do={
:set FIBERnetstatus "DOWN";

# Also add status in global variables to be used as tracking
:set date [/system clock get date];
:set time [/system clock get time];
:set FIBERnetlastchange ($time . " " . $date);
##################################################
####### FOR DOWN STATUS, CHANGE THE RULES ########
##################################################

# If the link is down, then LOG info and warning in Mikrotik LOG window [Zaib]
:log error "$DOWNLOG1"

# DOWN ACTION , shifting to SFP2 , backup link
/ip address set disabled=yes [find comment="PRIMARY-SFP1"]
/ip address set disabled=no [find comment="BACKUP-SFP2"]

# Adding delay so gateway should be reachable properly
:delay 5s;

:global gmailsmtp
:set gmailsmtp [:resolve "smtp.gmail.com"];

# "Emailing the DOWN status. . . "
/tool e-mail send to=$TO1 subject="$MSGDOWNEMAIL" start-tls=yes body="$MSGDOWNEMAIL"

# Send SMS the DOWN status via KANNEL
/tool fetch url="$KURL\?username=$KID&password=$KPASS&to=$cell1&text=$MSGDOWNSMS"

##################################################
####### FOR UP STATUS, CHANGE THE RULES ########
##################################################

} else={:set FIBERnetstatus "DOWN";}
} else={
:if (($FIBERnetstatus="DOWN")) do={

:set FIBERnetstatus "UP";

# If link is UP, then LOG info and warning in Mikrotik LOG window [Zaib]
:log warning "$UPLOG1"

# UP ACTION , shifting back to SFP1
/ip address set disabled=no [find comment="PRIMARY-SFP1"]
/ip address set disabled=yes [find comment="BACKUP-SFP2"]

# Adding delay so gateway should be reachable properly
:delay 5s;
:global gmailsmtp
:set gmailsmtp [:resolve "smtp.gmail.com"];

# "Emailing the UP status. . . "
/tool e-mail send to=$TO1 subject="$MSGUPEMAIL" start-tls=yes body="$MSGUPEMAIL"

# Send SMS via KANNEL Gateway
/tool fetch url="$KURL\?username=$KID&password=$KPASS&to=$cell1&text=$MSGUPSMS"

:set date [/system clock get date];
:set time [/system clock get time];
:set FIBERnetlastchange ($time . " " . $date);

} else={:set FIBERnetstatus "UP";}
}

September 30, 2016

Linux pppoe client disconnects after x minutes issue

Filed under: Linux Related, Mikrotik Related — Tags: , , — Syed Jahanzaib / Pinochio~:) @ 9:02 PM

dc


Scenario:

Mikrotik is acting as PPPoE server.

We have one Linux (Ubuntu) base client and wants to connect it to pppoe server using pppoe client. We have created the pppoe dialer using ‘pppoeconfig‘ CLI tool. Its connecting fine using pon dsl-rpovider command.


Problem:

PPPoE Dialer is regularly disconnecting after x minutes and ` /var/log/syslog ` is showing following error

Sep 30 20:40:44 ubuntu pppd[4375]: No response to 4 echo-requests
Sep 30 20:40:44 ubuntu pppd[4375]: Serial link appears to be disconnected.
Sep 30 20:40:44 ubuntu pppd[4375]: Connect time 5.5 minutes.
Sep 30 20:40:44 ubuntu pppd[4375]: Sent 6536 bytes, received 2983 bytes.
Sep 30 20:40:44 ubuntu pppd[4375]: restoring old default route to eth0 [192.168.1.1]
Sep 30 20:40:50 ubuntu pppd[4375]: Connection terminated.
Sep 30 20:40:50 ubuntu pppd[4375]: Modem hangup

Possible Reason:

The other side of the PPP link probably doesn’t support LCP echo. I have seen this with Mikrotik base pppoe server. [zaib]


Solution:

Oddly it was a rear issue i guess and internet is a bit silent about it.

Any way put this line in the relevant ppp options file and try again.

[ Example: /etc/ppp/peers/dsl-provider ]

echo-requests

lcp-echo-interval 0

Save and redial connection by

poff dsl-provider

pon dsl-provider


Complete DSL-PROVIDER file for pppoe client config.


# pppoe dialer config sample, by
# syed jahanzaib

noipdefault
defaultroute
replacedefaultroute
hide-password
lcp-echo-interval 0
noauth
persist
#mtu 1492
#persist
#maxfail 0
#holdoff 20
plugin rp-pppoe.so eth0
usepeerdns
maxfail 0
persist
user "PPPOE-USER-ID"

Regard’s
Syed Jahanzaib

August 24, 2016

Radius Manager Connection Tracking System for Mikrotik

Filed under: Mikrotik Related, Radius Manager — Tags: , , — Syed Jahanzaib / Pinochio~:) @ 10:35 AM

trackme

As requested by few OP, following is a short technical reference guide on how you can enable TCP/UDP connections in Mikrotik to be stored in Radius manager connection tracking database so that you can view user base connection tracking report. In my personal view, it’s not much useful and at low end hardware it creates bottleneck, but if you have good resources with some fast storage (like SSD or RAID-10) it is better to set it up.

CTS is best described in the manual by dmasoftlab manual as mentioned below

Radius Manager has a special feature: the Connection Tracking System. It is available only in Radius Manager CTS version or higher. With the help of it the system can track and log all the TCP and UDP connections for all registered (online) users.

By default when You install the CTS enabled version of Radius Manager, it will use the default CTS database (CONNTRACK). It is strongly recommended to use a separate database host for the CONNTRACK database, due to the enormous amount of data stored daily. It can be even a 100-500 MegaBytes (and in my personal experience it can grow as much as 3-5 GB on busy network, ZAIB) per day. Fast disks (like SSD in RAID 10 mode,  zaib) are also recommended to be able to seek and store the data in real time. Radius Manager periodically stores the traffic data to CONNTRACK database (typically in
every 5–60 seconds).


Mikrotik (6.x) Configuration to enable Firewall Logging to remote server (RM)

If you have already configured the radius manager, then the conntrack database also get configured via the installation script. Next step is to enable the firewall logging in the mikrotik router so that mikrotik can send the categorized TCP/UDP data to radius manager conntrack database.

In mikrotik, open terminal and issue following commands …

In below example, we have following IP scheme.

PPPoE users ip pool = 172.16.0.1-172.16.0.255
Radius Manager IP  = 101.11.11.254

/ip firewall filter add chain=forward src-address=172.16.0.1-172.16.0.255 protocol=tcp connection-state=new action=log

/ip firewall filter add chain=forward src-address=172.16.0.1-172.16.0.255 protocol=udp connection-state=new action=log

/system logging action add name=rmctszaib remote=101.11.11.254 target=remote remote-port=4950

/system logging add topics=firewall action=rmctszaib

If you don’t see any errors , you are good to Go.


RADIUS MANAGER SECTION:

1. Radius Manager should be licensed with CTS level. Basic license wont gonna work ..

2. Make sure that  RMCONNTRACK service is UP and running.To make sure it’s running , get its process by

ps aux |grep rmconntrack

and you should get result something like following

root@radius:/# ps aux |grep rmconntrack
root xxxx 0.0 0.0 xxxxxx xxx ? Ssl 13:22 0:00 /usr/local/bin/rmconntrack

if you see its running, proceed further , otherwise you may start it manually by

rmconntrack –x

Now login to RM ACP  >  Reports  >  Connection Report

Here you can get report for all or individual user.

As showed in the image below …

c1

 

c2

 


Regard’s
Syed Jahanzaib

 

 

1

July 20, 2016

Mikrotik reboot alert with false detection checks

Filed under: Mikrotik Related — Tags: , — Syed Jahanzaib / Pinochio~:) @ 12:05 PM

reboot

Scenario:

We have a routerboard which have 2 wan pppoe-outX dialers. Gmail account is configured to send alerts. On the same LAN we have KANNEL sms gateway server which acts as a central sms gateway for sending receiving sms.

Disclaimer:
The script is designed for some specific network, it may not fit general public requirements, but still its a good idea to collect various scripting ideas for learning purposes and it may help in other tasks as well.


Requirements:

  • If the Router is rebooted , it should send us Email and SMS with the new WAN ip addresses.
  • It should check for both WAN connections status before acquiring IP addresses, if it won’t check for interface status and the dialer aren’t connected, the script will terminate, therefore this check must be added
  • It should check for UPTIME , if the UPTIME is less than X Minutes, then it should consider the RB is actually rebooted, this check was required to prevent false detection of reboot. In some ROS, it was a bug that the RB doesn’t gets rebooted but reload the OS and the scripts consider that the RB got rebooted while it actually dont. so this check need to be added.
  • Make sure you have already configured the /tools/emails section in RB to make email alerts work.

the SCRIPT !

use the following script, modify it as required. schedule it to run on system reboot only,

# Mikrotik reboot alert / UPTIME CHECK SCRIPT, with prevention of sending FALSE ALARM with optional Email and SMS Alert
# We are using local KANNEL as SMS gateway and GMAIL as mail relay server
# By Syed Jahanzaib
# https://aacable.wordpress.com
# Email : aacable at hotmail dot com
# Script Last Modified : 20th-JUL-2016 / 1100 Hours

# Get Uptime
:local UPTIME [/system resource get uptime]

# Set UPTIME Limit
:local UPTIMELIMIT "00:05:00"

# SET DATE TIME
:local date;
:local time;
:set date [/system clock get date];
:set time [/system clock get time];

# if uptime is less then uptime limit threshold value, then consider router is actually rebooted, and take action / zaib
:if ($UPTIME<$UPTIMELIMIT) do={
:log error "ALERT: Router was rebooted just before $UPTIMELIMIT Minutes therefore sending Reboot SMS / Email Alert";

# Sleep , this is added so that RB and the KANNEL services may start properly / zaib
:delay 180s

# GMAIL Setup
:local gmailid "YOUR-GMAIL-ID@gmail.com"
:local GMAILPASS "YOUR-GMAIL-PAS"
:global gmailsmtp
:set gmailsmtp [:resolve "smtp.gmail.com"];
:local COMPANY "ZAIB"

# KANNEL SMS Configuration
#If you dont have kannel sms gateway ignore this.
:local KURL "192.168.100.1"
:local KID "kannel"
:local KPASS "kannelpassword"

#Mobile numbers of Admin
:local cell1 "03333021909"
:local cell2 "0333xxxxxxx"

:global WAN1IP
:global WAN2IP

# in this RB,we have two pppoe-outx wan dialers, Check if dialer is present and connected,
# this check is added because if dialer is not connected script was terminating, so this check is added now

if ([/interface get pppoe-out1 disabled] = yes) do={ :log error "pppoe-out1 Interface disabled" }\
else={[:global WAN1IP [/ip address get [find where interface=pppoe-out1] address];]}

if ([/interface get pppoe-out2 disabled] = yes) do={ :log error "pppoe-out2 Interface disabled" }\
else={[:global WAN2IP [/ip address get [find where interface=pppoe-out2] address];]}

# email recipients, Set your email where you want to receive the alert
:local mailsendto
:set mailsendto aacableAThotmailDOTcom

:local mailsendto2
:set mailsendto2 secondadmin@gmailDOTcom
# Set Email Subject
:local es "$[/system identity get name] $[/system clock get date] $[/system clock get time] $COMPANY MIKROTIK got rebooted ! new ips $WAN1IP $WAN2IP and Uptime is $UPTIME"

# Set Email Body
:local eb "$[/system identity get name] $[/system clock get date] $[/system clock get time] $COMPANY MIKROTIK got rebooted ! \nNew ip address are \n WAN1IP = $WAN1IP \n WAN2IP = $WAN2IP \n\n Current Uptime is $UPTIME \n\n This script is powered by SYED JAHANZAIB !"

# Finally send email to both amind email addresses
/tool e-mail send to=$mailsendto subject=$es start-tls=yes body=$eb password=$GMAILPASS
/tool e-mail send to=$mailsendto2 subject=$es body=$eb start-tls=yes password=$GMAILPASS

:log warning "Email Done! for REBOOT ..."

:log warning "SENDING SMS FOR REBOOT ALERT VIA KANNEL RADIUS GATEWAY ."

# Send SMS using local KANNEL sms gateway
/tool fetch url="http://$KHOST:13013/cgi-bin/sendsms\?username=$KID&password=$KPASS&to=$cell1+$cell2&text=$COMPANY+MIKROTIK+Router+was+rebooted+and+now+restored+at+$date+$time+and+new+ips+are+$WAN1IP+$WAN2IP+++++++[$COMPANY+Pvt+Ltd]"

# if uptime is above then uptime limit threshold value, then no need to send SMS, this is to prevent false alarm.
} else={
:log error "System is above then $UPTIMELIMIT, so no need to send reboot sms/email alert!"
}

# Script , Ends Here
# Syed Jahanzaib
# aacable [at] hotmail.com


Results~

Screenshot_2016-07-20-11-52-17

 

rebootmail

 


Regard’s
Syed Jahanzaib~

June 20, 2016

Routing & Natting with Failover ! Brothers in Arms

Filed under: Mikrotik Related — Tags: — Syed Jahanzaib / Pinochio~:) @ 1:39 PM

natro

~ Mikrotik CCR.1036 Performance Statistics ~

4vdsl-1fiber

 

 

mrtg


Reference Notes:

Mikrotik is a very powerful router that can perform variety of functions in one box. Sometimes It’s fun to do complex configuration with customized scripting to achieve our desired results. I just wanted to share some thoughts on one scenario where I configured multiple WAN links with PCC config plus public ips routing for users in single CCR RB. Routing+Natting+Fire-walling+QOS+Scripting and much more all together. Later we added failover so that if pcc wan links fails it should switch to fiber link, and if fiber link fails, it should failover to dsl by blending public ips into PCC.

  • Mikrotik have 4 DSL links which are configured in PCC (Load balancing) and serving local pppoe clients.
  • We have added another WAN Link via Fiber which is 1 STM (155mbps) and have acquire another large public pool for users which is routed to our /29 ip on mikrotik.
  • We have configured services in such a way that normal users gets private ip upon pppoe connectivity, and goes via PCC/Natting. and few services are configured in such a way that user gets public ip and goes to internet via public ip Routing, (bypass natting, preserving his public ip)
  • We have configured VLANs to isolate the different areas/networks to minimize the broadcast and for better network management. Also some corporate clients are connected to separate vlans to provide them public ip pool to be used in there routers.
  • We connected some corporate clients, which of course should not be connected via pppoe method, they wanted direct public ip so they can configure it in there own router/system. So we did it by connecting that client on our vlan switch,TAG there port traffic, and on mikrotik we added new vlan interface (accordingly ) and assign public ip (as required like /30) and assigned it to this new vlan interface, and gave appropriate ip to the client.
  • We have configured FAILOVER by using following techniques
  • 4 vdsl links (100mb each) are configured as PCC. For fail over we are using script that monitor 2 internet hosts for each wan link. we have also created forced route for those hosts with black holes as well to make sure the hosts goes via specific wan link only. once the script failed to ping those 2 hosts, it will simply enable rule in (ip/route/rules) TABLE to lookup the speciifc wan marked packets via main table where fiber link have distance value of 1 which will be default rule. thus traffic for that failed dsl link will start natting via fiber link. of course there are various other measurements need to be done, like proper natting rules, etc.
  • For fiber fail over (public ips) to dsl, we have script that checks for 2 hosts, if it fails, it will simply add the public ip pool to pcc pool as well, so the public pool also starts mixing with the pcc quern 😀
  • CCR performed amazingly good with complex configuration , lots of dynamic queues, and CPU usage usually remains under 10%. We can use PCQ base queues to lower the cpu usage in specific circumstances.
  • QOS is dynamically Done by the radius billing system. In this case DMASOFTLAB Radius Manager.
  • FTP are in DMZ, controlled by Mikrotik Firewall and separate QOS are setup to provide each user with 4 MB of downloads from local media server. This is done to prevent over utilization by each user. I used Queue type and then tag it with the simple queue for FTP. I also marked packets in mangle going to FTP, then later used in queues.
  • There are few other scripts configured like daily backup script, wan monitoring scripts, etc.
  • DDNS is also configured to access mikrotik and other servers/devices behind the MT, to pass through via PCC. port forwarding with the PCC is a bit tricky, and it requires additional rules in mangle and routes. I wrote about it in details in other posts.
  • Lot of port forwarding 🙂
  • Filter rules to block DDOSER, Block PING access ,Port Scanning etc…

 


TIPS for running NATING and ROUTING TOGETHER ~

Updated: 21-Sep-2016

As few asked how to run both natting and routing together in one router, here are few tips, (as I cannot post whole configuration because every network is different so rather then getting the code, try to understand the logic and apply it on your network if required)

Example:

We have Mikrotik RouterOS with 4 DLS(100mb x 4) links plus 1 Fiber Link (1 STM bandwidth) on /30 pool and two separate /24 pools (routed to /30 pool via ISP) for user end. We also have freeradius billing system where all users account / billing is managed. Mikrotik is acting as NAS / PPPoE Server as well.

Now we want that default normal group of clients should use these 4 dsl via PCC (using src-address approach as its more stable and have no ip changing issue) and selected group of users should get public ip and go directly via routing (while preserving their own public ip). here how I did this.

on Mikrotik I have defined two pools. One for the normal clients that will be natted using PCC. and other pool with public IP’s for users that will be routed.

1- pppoe_private_pool / 172.16.0.1-172.16.10.255
2- pppoe_public_pool / 123.0.0.1-123.0.1.255

In Mikrotik pppoe server, default pool for users is pppoe_private_pool (172.16.0.1-172.16.10.255) so any client connects to pppoe server will get ip from 172.16.x.x series. in PCC Mangle rules I defined 172.16.0.1-172.16.10.255 in src-address , this way only clients with these ip series will be processed via PCC and will go via dsl links. Same I did for default NAT rules, I defined this private pool in NAT src-address as well, This is must other wise all users will be natted (private or public). So make sure you pay attention to this portion.

Now to route public ips, I add the route of Fiber link ISP Gateway as Default route with distance value of 1 (all other routes of PCC have values of 2,3,4,5 (default routes for pcc / dsl is not required because they already have routes with marked traffic, but I still created default routes on dsl with different distance values to avail failover if one dsl fail , other should take over auto using MAIN TABLE) .

Then in radius panel, I created new services with pool defined “pppoe_public_pool”. and assign this profile to users whom I wanted to get public ip. this way when these particular users connects, they gets public IP, and they don’t processed by NAT rules and straightforward goes via routing table 🙂

Z@ib

 


Regard’s

Syed Jahanzaib

June 8, 2016

Mikrotik: Script to re-connect wan pppoe-outx after X hours

Filed under: Mikrotik Related — Tags: , — Syed Jahanzaib / Pinochio~:) @ 12:36 PM

link

Example of Mikrotik Script to execute customized function IF condition matches !


Requirements:

  • Mikrotik should disconnect wan client pppoe-out1 , only if its uptime is above 8 hours for that single session. There should be several checks like the script should check for following (to avoid errors)
  • Check for valid interface name , if interface not found, print error
  • Check for Running Status, if the pppoe-out interface is not connected to ppp server, print error
  • If the pppoe-out client uptime is above then the defined maximum uptime limit, it should disable interface, wait for 5 seconds, and then re-connect
  • Check if interface is in running status, print its IP address an strip its subnet

Solution:

the Script !

 

# Mikrotik Script to monitor UPTIME of the PPPOE-OUT(x) WAN interface, and act accordingly
# Useful when you want to disconnect your wan interface for any reason if it uptime crosses max up time limit defined. 
# Maybe to hide router form Remote PPP Servers uptime Monitoring System

# Syed Jahanzaib / aacable @ hotmail . com / https://aacable.wordpress.com
# Tested with Mikrotik 6.35.2 / on RB3011UiAS (arm)
# Created: 8-JUN-2016

# Define which interface uptime you want to monitor, in this example, i used pppoe-out1, you may change it as required
:local PPPINT pppoe-out1;

# Define the UPTIME Limit that will be matched with uptime, Example is 8 hours
:local MAXUPTIMELIMIT 08:00:00;

# Define how long it should wait before re-connecting / re-enable wan interface, example 5 seconds
:local DELAY 5s;

###############################
# SCRIPT FUNCTIONS STARTS HERE ...
###############################

# Check if interface is available or not, IF NOT THEN EXIT
:if ([:len [/interface find name=$PPPINT]] = 0 ) do={ :log error "WARNING: No interface named $PPPTINT, please check configuration." }

# Check for Interface Running Status, if its not connected then give error
:global PPPINTSTATUS;
/interface pppoe-client monitor $PPPINT once do={ :set PPPINTSTATUS $status}
:if ($PPPINTSTATUS != "connected") do={
:log error "$PPPINT NOT CONNECTED TO THE REMOTE SERVER YET, NOT READY";
}

# Define variable to hold current uptime value of the interface
:local wanuptime;
/interface pppoe-client monitor $PPPINT once do={
:set $wanuptime $uptime;

# Print Uptime , just for testing
#:log warning "$PPPINT UP Time is > $uptime";
}

# Match interface current uptime with maximum uptime limit defined in MAXUPTIMELIMIT variable
# Greater then forumla / zaib
:if ($wanuptime>$MAXUPTIMELIMIT) do={
:log error "ALERT: $PPPINT UP Time have crossed $MAXUPTIMELIMIT Hours Limit ... Disconnecting it and will Re-Connect after 5 Seconds";

# Disable $PPPINT interface
/interface disable $PPPINT
delay $DELAY;
/interface enable $PPPINT
:log warning "$PPPINT have been enabled , check if its connected properly."
:delay $DELAY
:local PPPINTIP [ /ip address get [/ip address find interface=$PPPINT] address ]
:for i from=( [:len $PPPINTIP] - 1) to=0 step=-1 do={ 
:if ( [:pick $PPPINTIP $i] = "/") do={ 
:set PPPINTIP [:pick $PPPINTIP 0 $i]
:log warning "$PPPINT ip address is > $PPPINTIP / Script ENDS here ..."
}
}

# Show under limit message. if all ok

:if ([/interface get $PPPINT value-name=running]) do={
:if ($wanuptime<$MAXUPTIMELIMIT) do={
:log warning "$PPPINT UP-Time $wanuptime is under $MAXUPTIMELIMIT Hours Limit / Script ENDS here ...";

:local PPPINTIP [ /ip address get [/ip address find interface=$PPPINT] address ]
:for i from=( [:len $PPPINTIP] - 1) to=0 step=-1 do={ 
:if ( [:pick $PPPINTIP $i] = "/") do={ 
:set PPPINTIP [:pick $PPPINTIP 0 $i]
:log warning "$PPPINT ip address is > $PPPINTIP"
} 
}
}
}
}

Regard’s
Syed Jahanzaib

June 2, 2016

Getting ‘Out of the Box’ solution with Mikrotik , BASH & mySQL

Filed under: Linux Related, Mikrotik Related, Radius Manager — Tags: , , — Syed Jahanzaib / Pinochio~:) @ 4:52 PM

codes


DISCLAIMER:

JUST AN EXAMPLE SAMPLE !

Following post is an example of fun coding. Just to learn and explore new ways of howto get ‘out of the box’ solution. In this example I have used Mikrotik Script, Bash Script, mySQL, and sendEmail tool all together. I made this solution, and surely I know that it’s not very elegant, not professional but I learned few things from it . This is just my own idea and sharing it , maybe someone will find it useful for some other project. Just to share my two cents …

Most of tasks described in this lengthy post can be achieved using mikrotik scripting alone, But

I just wanted to explore the possibilities on how multi platform systems , scripts, functions can be used all together to get our desired results with twisted, molded and formatted results in a way we want it to be !!! Simple is this !!!

BASH is Fun !

Regard's
Syed Jahanzaib

Scenario:

The OP have several dhcp pools in Mikrotik for users. In peak time , the dhcp assigned all or most available ips from the specific pool and error starts appearing in LOG.

Jun 1 14:46:51 X.X.X.X dhcp,error dhcp12: failed to give out IP address: pool <dhcp_pool12> is empty

mikrotik log error full pool

 


Requirements

The OP wanted to receive email alert when any pool configured in pool section of mikrotik crosses xx %.
and all pool statistics should be stored in mySQL as well, so that it can be used for various purposes. The script should also email the admin about the pool usage alert if it crosses XX %.


Solution

At mikrotik forum, dssmiktik posted an script which can query all pools and display there statistics.
Example of this script result on mikrotik terminal is as follows.

mtdhcplog

We will use this script on the mikrotik, and configure scheduler on Ubuntu/Lilnux to execute this script remotely and fetch the results in a local file, Format it, Store it in mySQL custom table, Do Comparison and ACT accordingly.

Example if any pool  crosses specific % limit, the bash script will update table accordingly, Send email and it will also prevent repeated email for the same.

 


Mikrotik Section #

Add following script in mikrotik script section …


# List stats for IP -> Pool
#
# criticalthreshold = output pool display in red if pool used is above this %
# warnthreshold = output pool display in gold if pool used is above this %

:local criticalthreshold 85
:local warnthreshold 50

# Internal processing below...
# ----------------------------------
/ip pool {
:local poolname
:local pooladdresses
:local poolused
:local poolpercent
:local minaddress
:local maxaddress
:local findindex
:local tmpint
:local maxindex
:local line

# :put ("IP Pool Statistics")
# :put ("------------------")

# Iterate through IP Pools
:foreach p in=[find] do={

:set poolname [get $p name]
:set pooladdresses 0
:set poolused 0
:set line ""

:set line (" " . $poolname)

# Iterate through current pool's IP ranges
:foreach r in=[:toarray [get $p range]] do={

# Get min and max addresses
:set findindex [:find [:tostr $r] "-"]
:if ([:len $findindex] > 0) do={
:set minaddress [:pick [:tostr $r] 0 $findindex]
:set maxaddress [:pick [:tostr $r] ($findindex + 1) [:len [:tostr $r]]]
} else={
:set minaddress [:tostr $r]
:set maxaddress [:tostr $r]
}

# Convert to array of octets (replace '.' with ',')
:for x from=0 to=([:len [:tostr $minaddress]] - 1) do={
:if ([:pick [:tostr $minaddress] $x ($x + 1)] = ".") do={
:set minaddress ([:pick [:tostr $minaddress] 0 $x] . "," . \
[:pick [:tostr $minaddress] ($x + 1) [:len [:tostr $minaddress]]]) }
}
:for x from=0 to=([:len [:tostr $maxaddress]] - 1) do={
:if ([:pick [:tostr $maxaddress] $x ($x + 1)] = ".") do={
:set maxaddress ([:pick [:tostr $maxaddress] 0 $x] . "," . \
[:pick [:tostr $maxaddress] ($x + 1) [:len [:tostr $maxaddress]]]) }
}

# Calculate available addresses for current range
:if ([:len [:toarray $minaddress]] = [:len [:toarray $maxaddress]]) do={
:set maxindex ([:len [:toarray $minaddress]] - 1)
:for x from=$maxindex to=0 step=-1 do={
# Calculate 256^($maxindex - $x)
:set tmpint 1
:if (($maxindex - $x) > 0) do={
:for y from=1 to=($maxindex - $x) do={ :set tmpint (256 * $tmpint) }
}
:set tmpint ($tmpint * ([:tonum [:pick [:toarray $maxaddress] $x]] - \
[:tonum [:pick [:toarray $minaddress] $x]]) )
:set pooladdresses ($pooladdresses + $tmpint)
# for x
}

# if len array $minaddress = $maxaddress
}

# Add current range to total pool's available addresses
:set pooladdresses ($pooladdresses + 1)

# foreach r
}

# Now, we have the available address for all ranges in this pool
# Get the number of used addresses for this pool
:set poolused [:len [used find pool=[:tostr $poolname]]]
:set poolpercent (($poolused * 100) / $pooladdresses)

# Output information
:set line ([:tostr $line] . " [" . $poolused . "/" . $pooladdresses . "]")
:set line ([:tostr $line] . " " . $poolpercent . " % used")

# Set colored display for used thresholds
:if ( [:tonum $poolpercent] > $criticalthreshold ) do={
:log error ("IP Pool " . $poolname . " is " . $poolpercent . "% full")
:put ([:terminal style varname] . $line)
} else={
:if ( [:tonum $poolpercent] > $warnthreshold ) do={
:log warning ("IP Pool " . $poolname . " is " . $poolpercent . "% full")
:put ([:terminal style syntax-meta] . $line)
} else={
:put ([:terminal style none] . $line)
}
}

# foreach p
}
# /ip pool
}


Create Tables in DB first !

Following is mysql table mikrodhcp.sql dump. Save it in file, and restore it using mysql command.

Example: [restore mikrodhcp table in mysql radius database, change it as per your own configuration]

mysql -u root -prootpassword radius < mikrodhcp.sql 


-- MySQL dump 10.13 Distrib 5.5.49, for debian-linux-gnu (i686)
--
-- Host: localhost Database: radius
-- ------------------------------------------------------
-- Server version 5.5.49-0ubuntu0.12.04.1

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `mikrodhcp`
--

DROP TABLE IF EXISTS `mikrodhcp`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `mikrodhcp` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`mikrotikip` varchar(16) CHARACTER SET utf32 NOT NULL,
`poolname` text NOT NULL,
`poolipusedno` int(11) NOT NULL,
`pooliptotal` int(11) NOT NULL,
`percentage` int(11) NOT NULL,
`mailsent` tinyint(1) NOT NULL,
`status` tinyint(1) NOT NULL,
`lastupdate` datetime NOT NULL,
`autodateupdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=727 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `mikrodhcp`
--

LOCK TABLES `mikrodhcp` WRITE;
/*!40000 ALTER TABLE `mikrodhcp` DISABLE KEYS */;
/*!40000 ALTER TABLE `mikrodhcp` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2016-06-02 15:58:13

IMPORTANT ! TEST THE TABLE !

One the table is imported without any error. Check it with following command

mysql -uroot -pROOTPASSWORD -e "use radius; describe mikrodhcp;"

 

and you may get following result if ALL is OK !

+----------------+------------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+-------------------+-----------------------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| mikrotikip | varchar(16) | NO | | NULL | |
| poolname | text | NO | | NULL | |
| poolipusedno | int(11) | NO | | NULL | |
| pooliptotal | int(11) | NO | | NULL | |
| percentage | int(11) | NO | | NULL | |
| mailsent | tinyint(1) | NO | | NULL | |
| status | tinyint(1) | NO | | NULL | |
| lastupdate | datetime | NO | | NULL | |
| autodateupdate | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+----------------+------------------+------+-----+-------------------+-----------------------------+

Now you can use following bash script …

the BASH SCRIPT !


#!/bin/bash
#set -x
# Script to fetch dhcp ip pool results from the mikrotik
# then update these results in mysql table, and email accordingly
# No portion of this script is copied from the internet.
# You are free to copy, modify, distribute it as you like
# Make sure you change all the variables as required like mysql id, tables etc.
# Created by : Syed Jahanzaib / aacable @ hotmail dot com
# https://aacable.wordpress.com
# Created: 2nd-MAY-2016

clear

# Colors Config . . . [[ JZ . . . ]]
ESC_SEQ="\x1b["
COL_RESET=$ESC_SEQ"39;49;00m"
COL_RED=$ESC_SEQ"31;01m"
COL_GREEN=$ESC_SEQ"32;01m"

#Temporary Holder for DHCP Status from Mikrotik
RESULT="/tmp/dhcpstatus.txt"
> $RESULT

#Mikrotik Details
MIKROTIK="1.2.3.4"
MTPORT="8291"
MTDHCPSCRIPT="dhcpstatus"

# DATE TIME
DATE=`date`
TODAYTIME=$(date +"%Y-%m-%d %T")

#MYSQL INFO
SQLUSER="MYSQL-ROOT"
SQLPASS="MYSQL-PASSWPORD"
DB="radius"
TABLE="mikrodhcp"
MAINTABLE="rm_users"
ALERTPERCENTAGE="50"

#EMAIL SECTION
GMAILID="YOURGMAILID@gmail.com"
GMAILPASS="GMAILPASS"
ADMINMAIL1="YOURADMINMAIL@hotmail.com"
COMPANY="YOUR COMPANY (Pvt) LTD"
FOOTER="Powered by Syed Jahanzaib"
# Create mikrodhcp table if not exists
DBCHECK=`mysql -u$SQLUSER -p$SQLPASS -e " SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '$DB';"`
if [ ! -z "$DBCHECK" ];
then
echo -e "Step-1# Checking $DB DB ... $DB database Found OK, proceeding further ... $COL_GREEN OK $COL_RESET"
#sleep 3
else
echo -e "$COL_RED ERROR: $DB database does NOT exists in mysql. it is required to store dhcp pool status data ...$COL_RESET"
exit 0
fi
# Create mikrodhcp table if not exists
TABLECHECK=`mysql -u$SQLUSER -p$SQLPASS -e " SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '$DB' AND TABLE_NAME = '$TABLE';"`
if [ ! -z "$TABLECHECK" ];
then
echo -e "Step-2# Checking $TABLE table ... $TABLE TABLE Found OK, proceeding further ... $COL_GREEN OK $COL_RESET"
#sleep 3
else
echo -e "$COL_RED ERROR: $TABLE does NOT exists in $MAINTABLE. it is required to store mikroptik dhcp pool status data ...$COL_RESET"
exit 0
fi
# Check if Mikrotik is accessibel or not, if not then EXIT immediately with error / zaib
if [[ $(ping -q -c 1 $MIKROTIK) == @(*100% packet loss*) ]]; then
echo -e "$COL_RED ALERT ..... MIKROTIK $MIKROTIK is DOWN$COL_RESET"
exit
else
echo -e "Step-3# Mikroik is Accessible, now proceeding further ... $COL_GREEN OK $COL_RESET"
fi

# Execute script on mikrotik which will get the required results liek dhcp ip pool status
ssh -q -p $MTPORT admin@$MIKROTIK /sys script run $MTDHCPSCRIPT > $RESULT

# VERIFY $RESULT FILE
A=`cat $RESULT`
B="no such item"
if [ "$A" == "$B" ];
then
echo -e "$COL_RED Mikrotik Script name '$MTDHCPSCRIPT' not found on Mikrotik. Please verify script name, test it on mikrotik first .... $COL_RESET"
exit 0
fi
echo -e "Step-4# Mikroik script fetched is Accessible, now proceeding further ... $COL_GREEN OK $COL_RESET"

# Verify if file is downloaded from mikrotik or not, if not dueo to ssh delay bug or other , then print error and exit 🙂 Security Check by zaib
{
if [ ! -f $RESULT ]; then
echo -e "$COL_RED ERROR: Mikrotik $MIKROTIK is live but it's SSH not accessible !!! $COL_RESET"
exit 0
fi
}
echo -e "Step-5# Mikroik $MIKROTIK SSH is accessible, now proceeding further ... $COL_GREEN OK $COL_RESET"

echo -e "Showing Results fetched from Mikrotik script ... $COL_GREEN OK $COL_RESET
"

echo -e "[POOL-NAME] [IP-USED-IN-POOL] [TOTAL-IP-IN-POOL] [POOL-USED-PERCENTAGE-%]" | awk '{printf "%-30s %-40s %-40s %-40s\n",$1,$2,$3,$4}'
echo ""
# Run Loop Formula
# Apply Formula to read the file in which dismissed users list and act accordingly.
num=0
cat $RESULT | while read data
do
num=$[$num+1]
POOLNAME=`echo $data | awk '{print $1}'`
POOLSTATUS=`echo $data | awk '{print $2}'`
POOLUSEDPERC=`echo $data | awk '{print $3}'`
POOLIPTOTAL=`echo $data | awk '{print $2}' | sed 's/\(\[\|\]\)//g' | sed 's#/#\ #g' | awk '{print $2}'`
POOLIPUSEDNO=`echo $data | awk '{print $2}' | sed 's/\(\[\|\]\)//g' | sed 's#/#\ #g' | awk '{print $1}'`

# Adding POOL names in table, so they can be updated according to teh usage in later stage ... zaib
mysql -u$SQLUSER -p$SQLPASS -e "use $DB; INSERT INTO $TABLE (mikrotikip, poolname) SELECT * FROM (SELECT '$MIKROTIK', '$POOLNAME') AS tmp WHERE NOT EXISTS (
SELECT poolname FROM $TABLE WHERE poolname = '$POOLNAME') LIMIT 1;"
# If percentage is high, ALERT in RED
if [ "$POOLUSEDPERC" -gt $ALERTPERCENTAGE ]
then
#echo -e "$COL_RED ALERT: $POOLNAME have consumed $POOLIPUSEDNO ips from $POOLIPTOTAL Total IPs / Percetnage Used = $POOLUSEDPERC % $COL_RESET"
echo -e "$COL_RED$POOLNAME $POOLIPUSEDNO $POOLIPTOTAL $POOLUSEDPERC Crossed $ALERTPERCENTAGE% $COL_RESET" | awk '{printf "%-40s %-40s %-40s %-5s %-5s %-5s *** ALERT ***\n",$1,$2,$3,$4,$5,$6}'

# UPDATE pool status with ALERT Status and other info
mysql -u$SQLUSER -p$SQLPASS -e "use $DB; UPDATE $TABLE SET mikrotikip = '$MIKROTIK' , poolipusedno = '$POOLIPUSEDNO' , pooliptotal = '$POOLIPTOTAL' , percentage = '$POOLUSEDPERC' , status = '1' , lastupdate = '$TODAYTIME' WHERE poolname = '$POOLNAME';"

else

# If percentage is low, Show result and update mysql table as well
#echo -e "$COL_GREEN NORMAL USAGE: $POOLNAME have consumed $POOLIPUSEDNO ips from $POOLIPTOTAL Total IPs / Percentage Used = $POOLUSEDPERC % $COL_RESET"
echo -e "$COL_GREEN$POOLNAME $POOLIPUSEDNO $POOLIPTOTAL $POOLUSEDPERC $COL_RESET" | awk '{printf "%-40s %-40s %-40s %-40s\n",$1,$2,$3,$4}'

# UPDATE pool status with normal values
mysql -u$SQLUSER -p$SQLPASS -e "use $DB; UPDATE $TABLE SET mikrotikip = '$MIKROTIK' , poolipusedno = '$POOLIPUSEDNO' , pooliptotal = '$POOLIPTOTAL' , percentage = '$POOLUSEDPERC' , status = '0' , mailsent = '0' , lastupdate = '$TODAYTIME' WHERE poolname = '$POOLNAME';"
fi

# Testing if email is required to be sent, if not alreasy sent
MAILSENT=`mysql -uroot -pView*pak --skip-column-names -e "use radius; select mailsent from mikrodhcp where poolname = '$POOLNAME';"`
if [[ $POOLUSEDPERC -gt $ALERTPERCENTAGE && $MAILSENT -eq 0 ]]
then
echo "Sending email for $POOLNAME ..."
mysql -u$SQLUSER -p$SQLPASS -e "use $DB; UPDATE $TABLE SET mailsent = '1' where poolname = '$POOLNAME';"

##################### START SENDING EMAIL
# create temporary holder where EMAIL will be stored
EMAILFILE="/tmp/$POOLNAME.dhcp.email"
> $EMAILFILE

echo "$COMPANY DHCP ALERT:

$POOLNAME pool in Mikrotik DHCP have crossed $ALERTPERCENTAGE % Limit

$POOLNAME have consumed $POOLIPUSEDNO ips from $POOLIPTOTAL Total IPs
$POOLNAME Percetnage Used = $POOLUSEDPERC %

Regard's

$COMPANY
$FOOTER" > $EMAILFILE

# Make sure you install sendEMAIL tool and test it properly before using email section.
# SEND EMAIL Alert As well using sendEMAIL tool using GMAIL ADDRESS.
# If you want to send email , use below ...

echo "Sending EMAIL ALERT to $ADMINMAIL1  ..."
/temp/sendEmail-v1.56/sendEmail -u "$COMPANY DHCP ALERT: $POOLNAME have consumed $POOLUSEDPERC %." -o tls=yes -s smtp.gmail.com:587 -t $ADMINMAIL1 -xu $GMAILID -xp $GMAILPASS -f $GMAILID -o message-file=$EMAILFILE -o message-content-type=text
fi
##################### EMAIL SENT DONE

fi

if [[ $POOLUSEDPERC -gt $ALERTPERCENTAGE && $MAILSENT -eq 1 ]]
then
echo "Email alert already sent for $POOLNAME to $ADMINMAIL1..."
#mysql -u$SQLUSER -p$SQLPASS -e "use $DB; UPDATE $TABLE SET mailsent = '1' where poolname = '$POOLNAME';"
fi
done

###### LOOP DONE ########
#Reset Terminal Color to Default
tput sgr0

POOLIPTOTAL=`cat $RESULT | awk '{print $2}' | sed 's/\(\[\|\]\)//g' | sed 's#/#\ #g' | awk '{print $2}'`
POOLIPUSEDNO=`cat $RESULT | awk '{print $2}' | sed 's/\(\[\|\]\)//g' | sed 's#/#\ #g' | awk '{print $1}'`

TOTALIP=`echo "$POOLIPTOTAL" | awk '{ sum+=$1} END {print sum}'`
USEDIP=`echo "$POOLIPUSEDNO" | awk '{ sum+=$1} END {print sum}'`

echo "
Total USED IPs = $USEDIP
Total IPs in POOL = $TOTALIP"
echo -e "Updating MYSQL Table on Billing @ $DATE ... $COL_GREEN OK $COL_RESET"
echo "Powered by Syed Jahanzaib"


END RESULTS ! with FANCY COLORED OUTPUT : ) We all love COLORS don’t we ?

 

SCRIPT EXECUTION RESULT #1

1-dhcp-alert-on-bash-screen

 

SCRIPT EXECUTION RESULT #2

 

2-dhcp-alert-on-bash-screen-and-show-already-sent email

 

TABLE RESULTS AFTER SCRIPT UPDATE !

5- table result


EMAIL ALERT SAMPLE #1

 

2- dhcp alert amil sub

EMAIL ALERT SAMPLE #2


3- dhcp billing alert full mail

 


Next Tasks:  To be continued …

Create MRTG graph for each pool, so that OP can have idea on which pool is most used in what timings exactly.

 

May 24, 2016

Mikrotik: Using Firewall Filters to Acquire Wan Data Usage via Email

Filed under: Mikrotik Related — Tags: , , , — Syed Jahanzaib / Pinochio~:) @ 11:32 AM

monitoring_report


Requirements:

An Operator [from Amsterdam] wanted to receive email on daily basis for the Daily usage of WAN link on the Mikrotik. Something like Mikrotik should send simple reporting email on daily basis like ‘XXX MB were downloaded Yesterday via WAN link’.

Solution:

Use following Script. All sections are well defined in it. Make sure you read it carefully line by line, and modify items required.

In this example I used FILTER rules approach to collect the bytes. Surely there are more elegant ways to fetch the data like … Linux base MRTG, NMS like DUDE, above all SNMP  and many others. I just used this method. You may select other as it suites you. This one worked neatly for me 🙂

You can customize it as per your requirements, like multi wan report, monthly report etc.


Requirements:

Mikrotik 6.x

  1. Schedule this script to run after 5 (or xx) minutes. When DATE change occurs, it will reset the counter file and filter rules counters.
  2. Create two FILTER rules in Mikrotik as following. SFP1 is the wan interface, so do change it accordingly.
/ip firewall filter
add action=passthrough chain=forward comment=WAN_1_IN in-interface=sfp1
add action=passthrough chain=forward comment=WAN_1_OUT out-interface=sfp1

the Script !


# Script to collect WAN DATA USAGE by FILTER rules, and send data to admin by Email Daily.
# And reset the counters on daily basis in night. it will preserve the data in a file even if the router reboots.
# Syed Jahanzaib / aacable @ hotmail . com
# https://aacable.wordpress.com
# 23-MAY-2016

# Make sure you add two firewall rules as showed below so that script can take bytes from it and reset it when date changes.
# Change the interface name accordingly, and make sure to enter the matching comments too.
# /ip firewall filter
#add action=passthrough chain=forward comment=WAN_1_IN in-interface=sfp1
#add action=passthrough chain=forward comment=WAN_1_OUT out-interface=sfp1

# Set comments for firewall filter rules, change them as required
:local WAN1INCOMMENT
:local WAN1OUTCOMMENT
:local WAN1INCOMMENT "WAN_1_IN"
:local WAN1OUTCOMMENT "WAN_1_OUT"

:local BYTESOUT [/ip firewall filter get [/ip firewall filter find comment="$WAN1INCOMMENT"] bytes]
:local BYTESIN [/ip firewall filter get [/ip firewall filter find comment="$WAN1OUTCOMMENT"] bytes]

# SET GMAIL for sending email, make sure you have configured /TOOLS,EMAIL option of mikrotik. and test it before using following.
:global gmailsmtp
:set gmailsmtp [:resolve "smtp.gmail.com"];
# Set your GMAIL Account Password
:local gmailpass
:set gmailpass GMAIL-PASSWORD
# Set your email where you want to receive the alert
:local mailsendto
:set mailsendto YOUR-ADMIN-EMAIL@xxxx.com

# set DATE TIME
:local date
:local time
:set date [/system clock get date];
:set time [/system clock get time];

# Create file (if file is not already there.) to update date time of last update
:if ([:len [/file find where name=counterslastupdate.txt ]] < 1 ) do={
/file print file=counterslastupdate.txt where name=counterslastupdate.txt
/file set counterslastupdate.txt contents="0";
};

# Create file (if file is not already there.) to store last update date time in normal format to be showed in email.
:if ([:len [/file find where name=counterslastupdatenormalformat.txt ]] < 1 ) do={
/file print file=counterslastupdatenormalformat where name=counterslastupdatenormalformat.txt
/file set counterslastupdatenormalformat contents="0";
};

# Setting variables
:local curDate [/system clock get date]
:local curYear [:pick $curDate 7 13]
:local curMon [ :pick $curDate 0 3 ]
:local curDay [:pick $curDate 4 6]
:local COMPANY "JZ"
:local CURRENTDATE "$curDay$curYear"
:local LASTUPDATEDATE value=[/file get counterslastupdate.txt contents]
:local LASTUPDATEDATENORMAL value=[/file get counterslastupdatenormalformat.txt contents]

# Update counters last update with current date time
/file set counterslastupdate.txt contents=$CURRENTDATE

# Calculate data in MB to be displayed in LOG and email
:local TOTAL
:set $TOTAL ($BYTESOUT+$BYTESIN)
:local TOTALMB
:set $TOTALMB ($TOTAL / 1024 / 1024)
#:log info ( "Traffic out = " . $BYTESOUT . " bytes" )
#:log info ( "Traffic in = " . $BYTESIN . " bytes" )
#:log warning ( "TOTAL TRAFFIC = " . $TOTAL. " bytes" )
:log warning "$TOTALMB MB Downloaded iva WAN link on $curDate"

# If date is changed (usually in night) , then send email using GMAIL , with the Data
:if ($CURRENTDATE = $LASTUPDATEDATE) do={
:log warning "No need to send email."
} else {
:log warning "DATE changed, sending email for last day data usage and also reset the Firewall Counters ..."
# Reset the firewall counters and counter files if date change is detected / zaib
/ip firewall filter reset-counters [find comment=$WAN1INCOMMENT ]
/ip firewall filter reset-counters [find comment=$WAN1OUTCOMMENT ]
/file set counter.txt contents="0";

# Set Email Subject
:local es "$[/system identity get name] $[/system clock get date] $[/system clock get time] $COMPANY MIKROTIK / $TOTALMB MB were downloaded via WAN link on $LASTUPDATEDATENORMAL"
# Set Email Body
:local eb "$[/system identity get name] $[/system clock get date] $[/system clock get time] $COMPANY MIKROTIK / $TOTALMB MB were downloaded via WAN link on $LASTUPDATEDATENORMAL"
# Finally send email
/tool e-mail send to=$mailsendto subject=$es body=$eb start-tls=yes
};

# Create file (if file is not already there.) to update download bytes
:if ([:len [/file find where name=counter.txt]] < 1 ) do={
/file print file=counter.txt where name=counter.txt;
/delay delay-time=1;
/file set counter.txt contents="0";
};

# If current value is bigger then older, then update the counters,
# Helpfule to save counters, when router reboots.

# Get value from stored data for matching
:local before value=[/file get counter.txt contents]

:if ($TOTAL > $before) do={
/file set counter.txt contents=$TOTAL
} else= {
# Else update both values in the file
:set $TOTAL ($TOTAL+$before)
/file set counter.txt contents=$TOTAL
};

# Update Date time stamp in both files / zaib
/file set counterslastupdate.txt contents=$CURRENTDATE
/file set counterslastupdatenormalformat.txt contents=$curDate

# Regard's
# Syed Jahanzaib


End Results !

downlaoded

 

 

Older Posts »

%d bloggers like this: