Назад | Перейти на главную страницу

Восстановление счетчиков iptables при использовании квот не работает должным образом

Я установил квоту для определенного компьютера:

iptables -A FORWARD -d 192.168.1.10 -m quota --quota 500000000 -j ACCEPT
iptables -A FORWARD -d 192.168.1.10 -j DROP

Это работает, как ожидалось. По достижении предела (500 МБ) все пакеты для этого компьютера отбрасываются.

Но если я сохраню счетчики (iptables-save -c> /home/iptables.counters), перезапущу iptables и восстановлю счетчики (iptables-restore -c /home/iptables.counters), то независимо от того, какие сохраненные счетчики при этом этот компьютер все еще сможет загрузить 500 МБ, поэтому общий размер счетчика до того, как этот компьютер потеряет доступ в Интернет, будет X + 500 МБ, где X - размер сохраненного счетчика.

Я, должно быть, делаю что-то не так, поскольку в этом весь смысл сохранения / восстановления счетчиков: возобновление с этого счетчика байтов до тех пор, пока не будет достигнут предел. Мы будем очень благодарны за любые подсказки ...

Эта проблема является ошибка ядра.

В 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(&quota_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(&quota_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.