How to limit a user to a given amount of traffic?

Many times people have asked how to shape traffic based on the amount the user has already downloaded.
Here is a small script which makes the job:

:local sum; :local traf;
:set sum 0
/ip firewall rule forward {
:foreach i in [find] do={:incr sum}
:for i from=1 to=$sum do={
:set traf [get [find comment=(“user” . $i)]
bytes]
:set traf ($traf/1073741824)
:if ($traf>1) do={:log facility=System-Info message=(“user” . $i .
" exceeded 1Gb limit!")}
}
}

Comments:
1)Make your own chain for accounting purposes (just don’t forget to add jumps from forward chain.) In the end of this chain add return rule.

2)Make a custom action when the user reaches the limit. By default the scripts writes message to logs (use /log print without-paging command to view logs)

The original can be found in MT docs:
http://www.mikrotik.com/docs/ros/2.8/appex/scripting1.content#11.2.5.8

Can this script work with PPPoE?? Like the OS provides a Traffic limit for HotSpot Users can this be adapted in similar fashion for PPPoE users??

With pppoe, I think you can set this based on a radius attribute. See the radius attributes that are supported for AAA in the AAA section of the manual.

John

Yes, of course this script can work with PPPoE. Just make correct firewall rules that count traffic for particular PPPoE client.

Eugene, could you please be a bit more specific on it.

I have 50 customers woth pppoe. With 3 profiles (so that I have 3 fw rules, one each profile below ppp fw rule).

where should I put the rules for counting bytes?

I imagine that to put an identifier on each rule, I have to base the rule on the IP address of the customer. This means I have to fix the IP address of teh customer to his username on the pppoe secrets.

Am i correct?

thanks

just one more thing. my pppoe customers take the ip from a pool.

can anybody answer on how check amount of upload/dwonload traffic with radius and pppoe users?

afaik ‘Alive’ packets are sent back to the radius server with the updates. These are usually sent every 5min, but you can change that using either the MT Router or the Radius server. Otherwise the total session data will be sent with the Stop packet.

The difficult thing is enforcing the quota. Ie, a user is connected, exceeds their limit - how do you disconnect them? Currently I just disable and enable the PPPoE service every 24hrs, which is pretty dodgy. I’d like to know a more elegant solution that only affects the users in question.

thank for the help.

About enforcing a rule when they reach a quote, I probably run a script with a forward rule doing what you want to do, i.e. stop p2p … or what else

can you expand a little more on this im attempting to set transfer limits so userx gets 1 GB transfer/month / week whatever. if they exceed it they get throttled to 64 K. This is my first run with mikrotik ect… so im still trying to figure out the firewall ect …


Thanks

So let me see if I understand this at all or if im on the right track.

first thing to do is add a chain

/ip firewall add name=accounting

then set a comment for it called userN atm i have 2 users so

/ip firewall rule accounting add comment=user2

add passthrough action to the chain accounting

/ip firewall rule accounting add action=passthrough

add a jump rule in forward to accountin

/ip firewall rule forward add jump-target=accounting

change the refferences of forward to accounting in the script provided
and add

:local sum; :local traf;
:set sum 0
/ip firewall rule accounting{
:foreach i in [find] do={:incr sum}
:for i from=1 to=$sum do={
:set traf [get [find comment=("user" . $i)]
bytes]
:set traf ($traf/1073741824)
:if ($traf>1) do={:log facility=System-Info message=("user" . $i .
" exceeded 1Gb limit!")}
}
/ip firewall rule accounting return
}

does that look right?
Help is greatly appriciated

when i do

/ip firewall rule accounting add action=passthrough comment=user1 dst-address=192.168.0.199/24

I get ERROR: destination bad

192.168.0.199/24 is not a valid notation. If you want to describe the single host, you have to use a /32 netmask:

192.168.0.199/32

If you meant to filter the whole class C network, you must use the network address together with the /24 subnet mask:

192.168.0.0/24

ahh thanks now this is how i have it setup


forward chain

[admin@MikroTik] system script> /ip firewall rule forward print
Flags: X - disabled, I - invalid, D - dynamic
 0   action=jump jump-target=accounting

 1   ;;; limit access for unauthorized hotspot clients
     in-interface=ether2 action=jump jump-target=hotspot-temp

 2   ;;; account traffic for authorized hotspot clients
     action=jump jump-target=hotspot

 3   action=accept

accounting chain

[admin@MikroTik] system script> /ip firewall rule accounting print
Flags: X - disabled, I - invalid, D - dynamic
 0   ;;; user1
     dst-address=192.168.0.195/32 action=passthrough

 1   action=return

script

[admin@MikroTik] system script> print
 0 name="account_user_traffic"
   source=":local sum; :local traf;\r\n:set sum 0\r\n/ip firewall rule
          accounting{\r\n:foreach i in [find] do={:incr sum}\r\n:for i from=1
          to=$sum do={\r\n:set traf [get [find comment=("user" . $i)]
          bytes]\r\n:set traf ($traf/1073741824)\r\n:if ($traf>1) do={:log
          facility=System-Info message=("user" . $i . " exceeded 1Gb
          limit!")}\r\n}\r\n}"
   owner="admin" policy=ftp,reboot,read,write,policy,test
   last-started=feb/16/2005 13:58:27 run-count=5

I get feb/16/2005 13:58:27 script error: no such chain when i try to run it.

well figured out what the deal with not seeing the chain is. DONT PUT A SCRIPT IN VIA WINBOX. :slight_smile: found the pico clone and entered it via cli script starts working except now it spits an error to the log script error: empty string value where some kind of specific value expected


here is my current script

:local sum; :local traf;
:set sum 0 
/ip firewall rule accounting {
  :foreach i in [find] do={:incr sum}
  :for i from=1 to=$sum do={
    :set traf [get [find comment=("user" . $i)] bytes]
    :set traf ($raf/1073741824)
    :if ($traf>1) do={:log facility=System-Info message=("Limit-exceeded")}
  }
}

It’s your script:

There is one corrected string:

:set traf ($traf/1073741824)

So far everyone has addressed the issue of throttling using local user accounts.

Our network is in the situation where users authenticate via PPPOE, and are assigned an IP address either statically or from the routers dynamic pool, no matter where they enter the network.

The PPPOE server then talks to a freeradius server to get the appropriate attributes (static / dynamic IP, any queues that need to be applied, routes that need to be added etc). The PPPOE server is also set to send interim accounting updates every 5 minutes to let the radius server know how much data a user has used.

To make this work with a radius server either a script would need to run on the mikrotik PPPOE server (where the queue is applied) to check the value of the data usage on the radius server and set the queue appropriately, or a script would have to run on the radius server and somehow tell the mikrotik router to alter the queue if the user had gone over their allocated data cap.

We can not check the amount of data on the local mikrotik box, as users may come into the network from different entry points through different PPPOE servers. The mikrotik router would also loose all accounting information if it was rebooted.

I notice in 2.9 there is a feature where you can specify an incoming raidus server. Does anyone have any information on how this works? What it does?

Alternatively does anyone have a working solution for this?

The “radius incoming” features is to let a RADIUS server actively disconnect PPP(oE) sessions without using SSH scripts on the RADIUS server or the like. See here for example: http://forum.mikrotik.com/t/how-to-disconnect-user/1016/1

Regarding your question of changing queues: I suppose the only way will be to run a script on the RADIUS server that connects to the appropriate PPPoE server (MikroTik) via SSH and then switches queues for the active user. Have never tried this, though…

I try stop traffic and inform user buy mail:

my script:

:local sum; :local traf;
:set sum 0
/ip firewall rule example {
:foreach i in [find] do={:incr sum}
:for i from=1 to=$sum do={
:set traf [get [find comment=(“user” . $i)] bytes]
:set traf ($traf/1073741824)
:if ($traf>0) do={ /ip firewall rule forward add src-address=1.1.1.1/32 action=reject
/tool e-mail send to=example@example.com subject=“Limit-exceeded”}
}
}

but, I run this script from scheduler , interval is 5s , and when user reach traffic limit , scheduler make rule and send mail on 5s , nonstop.

Is there any way to stop scheduler when user reach traffic limit , something like /system scheduler disable 0 ?

and is there way to put “ip firewall forward rule” on ie. position 10 , something like… put-on=10 or put-position=10 …

any idea ?

Thanks