我为某台计算机设置了配额:
iptables -A FORWARD -d 192.168.1.10 -m quota --quota 500000000 -j ACCEPT
iptables -A FORWARD -d 192.168.1.10 -j DROP
这按预期工作。当达到限制(500MB)时,这台特定计算机的所有数据包都将被丢弃。
但是,如果我保存计数器(iptables-save -c > /home/iptables.counters),重新启动 iptables,并恢复计数器(iptables-restore -c /home/iptables.counters),那么无论保存的计数器是什么,该计算机仍然能够下载 500 MB,因此在该计算机失去互联网访问之前,计数器的总大小将为 X + 500MB,其中 X 是保存的计数器大小。
我肯定做错了什么,因为这是保存/恢复计数器的重点:从该字节数恢复,直到达到限制。任何提示都将不胜感激...
答案1
问题是一个内核错误。
在 EL6 中,执行匹配的配额代码显示如下:
quota_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
struct xt_quota_info *q = (void *)par->matchinfo;
struct xt_quota_priv *priv = q->master;
bool ret = q->flags & XT_QUOTA_INVERT;
spin_lock_bh("a_lock);
if (priv->quota >= skb->len) {
priv->quota -= skb->len;
ret = !ret;
} else {
/* we do not allow even small packets from now on */
priv->quota = 0;
}
/* Copy quota back to matchinfo so that iptables can display it */
q->quota = priv->quota;
spin_unlock_bh("a_lock);
return ret;
在 F20 中显示如下内容:
static bool
quota_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
struct xt_quota_info *q = (void *)par->matchinfo;
struct xt_quota_priv *priv = q->master;
bool ret = q->flags & XT_QUOTA_INVERT;
spin_lock_bh(&priv->lock);
if (priv->quota >= skb->len) {
priv->quota -= skb->len;
ret = !ret;
} else {
/* we do not allow even small packets from now on */
priv->quota = 0;
}
spin_unlock_bh(&priv->lock);
return ret;
}
基本相同(减去间距变化)分开从一行;
/* Copy quota back to matchinfo so that iptables can display it */
q->quota = priv->quota;
这是一个显示参数。
因此,在 EL6 中,如果您设置了配额,并传递了一些数据包,那么iptables -vnL SOMECHAIN
您会注意到配额值会减少。
在 F20 中,做同样的事情时,值不会减少。我猜设计师认为确保人们知道设置了什么配额而不是配额实际上是多少可能更好(因为数据包计数清楚地表明了剩余的配额)。
但是,这会产生意想不到的效果。运行时,iptables-save
您会将配额值保存为通过 读取iptables
。在 EL6 中,如果此值达到 0,则会将 0 显示为iptables
。因此,当您恢复时,您会将 0 恢复回 iptables 链中。
随着他们将其删除,这个值永远不会减少,因此您实际上永远不会节省配额。
真正需要做的是重新设计模块。应该有一个quota
条目和一个remaining
条目。剩余应该像在 EL6 中一样减少,并且用于强制执行配额,而“配额”应该是实际设置的值,就像在 F20 中一样。这样您就可以两全其美。配额的保存状态和设置配额的实际描述。
您可能应该将此事报告给 netfilter 团队。