Score:0

Match specific user's traffic both in OUTPUT and in INPUT to use quota on it

mr flag

How can I convert:

iptables -t mangle -A OUTPUT -m owner --uid-owner root -j MARK --set-mark 1

iptables -A OUTPUT -m owner --uid-owner root -m quota2 --name 10mb_quota --quota 10240000 -j MARK --set-mark 1

for use in INPUT?

I tried it like this:

iptables -t mangle -A INPUT -m owner --uid-owner root -j MARK --set-mark 1

iptables -A INPUT -m owner --uid-owner root -m quota2 --name 10mb_quota --quota 10240000 -j MARK --set-mark 1

but I didn't succeed.

Luana avatar
mr flag
so there's no way to convert to INPUT?
Luana avatar
mr flag
could you help me with this solution? I will be very grateful
Score:1
cl flag
A.B

The problem

The man page tells:

owner

This module attempts to match various characteristics of the packet creator, for locally generated packets. This match is only valid in the OUTPUT and POSTROUTING chains. Forwarded packets do not have any socket associated with them. Packets from kernel threads do have a socket, but usually no owner.

So there's no direct equivalent for INPUT. The reason is simple: an incoming packet doesn't come from a process, so it's not possible to check the socket owner of the process that will (very soon but has not yet) receive(d) this packet (despite the existence of a socket match which can do such advance lookup but doesn't have any owner-related feature).

connmark

What can be done instead, is to associate a conntrack mark to the (first) time an outgoing packet of this flow is associated with an user, and mark subsequent packets, including incoming packets, from the conntrack mark. It's then possible to use other features like quota.

  1. Blindly restores a mark from the conntrack flow to the packet: the mark if any (0 means there was none) is now available on the incoming packet.

    This could have been done in mangle/INPUT instead, since the overall feature makes sense only to local traffic (so not to traffic passing through FORWARD chains), but this is easier to not care about rule ordering later and do it in mangle/PREROUTING (one can choose to optimize and move it to mangle/INPUT).

    iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
    

    (add more related rules here or in mangle/INPUT or filter/INPUT as needed that should start with -m mark --mark 1).

  2. Also restore the mark from the conntrack flow to the outgoing packet. Then if there's no mark, do the owner test to add a firewall mark to the packet

    Chronologically that's the place where the mark will be initially set, since testing the owner of a packet can be done only in the output path.

    The mark test before setting the mark is there to possibly allow with later rules to change again this mark (and ultimately the conntrack mark) without then getting it overwritten again on next output packet.

    iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
    iptables -t mangle -A OUTPUT -m mark --mark 0 -m owner --uid-owner root -j MARK --set-mark 1
    

    (add more related rules here or in filter/OUTPUT as needed that should start with -m mark --mark 1).

  3. Save back the firewall mark on the packet to the conntrack flow mark (it will also save a mark that was changed)

    This is done in POSTROUTING so there's no rule ordering to care about (it could also have been done in mangle/OUTPUT).

    iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark
    

Depending on the problem some optimization is probably possible, but this gives the idea.

With this setup, as soon as a packet in a flow gets for the first time a mark (either the first packet of an originally outgoing flow from a root process, or the first reply packet of an originally incoming flow to a root process), the flow will inherit the mark and any further packets of this flow will also inherit this mark, both ways.

Caveat: this method won't allow to account the the first packet in an incoming flow. For quota accounting that means the first payload size won't be accounted (eg: received UDP query, or of the first TCP incoming (SYN) packet (not that important, unless it's a TCP Fast Open with initial payload)).


Addressing OP's specific question

Once above framework is in place one can now check the mark in INPUT or OUTPUT to know it's about a packet to or from the root user.

  1. INPUT

    The quota2 match in (default) count down mode returns true as long as there is quota remaining: the test must be inverted with a !, as documented:

    When counting down from the initial quota, the counter will stop at 0 and the match will return false [...]

    [!] --quota iq

    Specify the initial quota for this counter. If the counter al‐ ready exists, it is not reset. An "!" may be used to invert the result of the match. The negation has no effect when --grow is used.

    to return false and not execute the target DROP until there is no quota left anymore (reaches 0). An other way (not done here) would be to invert the logic of the actions (-j ACCEPT followed by a single -j DROP rule).

    For OP's quota2 match to then apply in INPUT:

    iptables -A INPUT -m mark --mark 1 -m quota2 --name 10mb_quota ! --quota 10000000 -j DROP
    

    Note that it didn't make sense to reapply the same mark as in OP's example: this was already done with the previous command in mangle/PREROUTING (just as it was already done with OP's initial command iptables -t mangle -A OUTPUT -m owner --uid-owner root -j MARK --set-mark 1, thus for no additional effect). Instead of -j DROP one could jump to a new user chain that will handle basic traffic policing with rate limit. I think applying quota to root wouldn't be a good idea, but could make sense for an other user. Anyway that's what OP asked.

  2. revised OUTPUT

    Revised OP's quota2 to apply in OUTPUT like was done in INPUT.

    iptables -A OUTPUT -m mark --mark 1 -m quota2 --name 10mb_quota ! --quota 10000000 -j DROP
    

    As before one could instead choose rate limit once the global quota has been consumed.

Luana avatar
mr flag
how can i add this new rule to be accept with **iptables -A OUTPUT -m owner --uid-owner root -m quota2 --name 10mbps --quota 10000000 -j MARK --set-mark 1**
Luana avatar
mr flag
worked as expected yes more when the quota reaches its 10mb spent the traffic still continue, I would like this connection to be stopped immediately when it reaches its given quota both input and output .
Luana avatar
mr flag
@AB yes I read every part of what you wrote and thank you very much for the help but still did not understand this part to reject when the quota zeroes with -j DROP What I tried was iptables -A INPUT -m mark --mark 1 -m quota2 --name 10mb_quota --quota 10000000 -j DROP iptables -A OUTPUT -m mark --mark 1 -m quota2 --name 10mb_quota --quota 10000000 -j DROP plus the traffic is frozen when added -j DROP before ending the quota I'm confused I apologize for not understanding much I'm a bit of a beginner in the world of iptables.
A.B avatar
cl flag
A.B
I changed the rules to do what you wanted (mind the `!`).
Luana avatar
mr flag
@AB sensational!!!! I was surprised by the result and it worked as expected now stopping user traffic!!Thank you very much!!!
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.