LINUX.ORG.RU
решено ФорумAdmin

Неправильная маршрутизация ack-пакетов отправляемых при закрытии tcp-соединения

 , ,


0

3

Привет, ЛОР. У меня два сетевых интерфейса, eth0 и eth1 с ip-адресами ip0 и ip1 соответсвтеннно. Я хочу, чтобы в основном использовался ip1, а для пользователя user ip0.

В iptables в таблице mangle я с помощью -m owner --uid-owner user я помечаю пакеты меткой:

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

Командой ip rule я отправляю пакеты с меткой в соответствующую таблицу. Кроме того, есть правила чтобы пакеты с каждого ip-адресу уходили в соответствующие таблицы:

ip rule add fwmark 1 table table0
ip rule add from ip0 table table0 priority 300
ip rule add from ip1 table table1 priority 300

Наконец, на пакеты, уходящие с интерфейса eth0, я ставлю его ip-адрес:

iptalbes -t nat -A POSTROUTING -o eth0 -j SNAT ip0

Прописал 2 в rp_filter, и всё почти заработало. Теперь начинается самое интересное.

Я пробую подключиться к Яндексу от пользователя user, например, с помощью такого кода:

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
(socket.AF_INET, socket.SOCK_STREAM)

С помощью tcpdump я вижу, что пока всё сработало правильно: пакеты для инициации tcp-соединения ушли с интерфейса eth0 с обратным ip-адресом ip0, функция выполнилась прваильно, всё пока работает. При этом сам сокет считает, что его ip-адрес ip1, так и дожно быть:

s.getsockname
(ip1, 36286)

Но вот я закрываю соединение

s.close()
И я вижу в tcpdump, что пакеты уходят с интефейса eth1, хотя и с правильным адресом ip0, почему так?
18:17:12.419048 IP ip0.36286 > www.yandex.ru.http: Flags [F.], seq 2604533824, ack 3747075092, win 229, length 0
18:17:12.625721 IP ip0.36286 > www.yandex.ru.http: Flags [F.], seq 0, ack 1, win 229, length 0
18:17:13.039056 IP ip0.36286 > www.yandex.ru.http: Flags [F.], seq 0, ack 1, win 229, length 0
18:17:13.865720 IP ip0.36286 > www.yandex.ru.http: Flags [F.], seq 0, ack 1, win 229, length 0
18:17:15.522390 IP ip0.36286 > www.yandex.ru.http: Flags [F.], seq 0, ack 1, win 229, length 0
18:17:18.839054 IP ip0.36286 > www.yandex.ru.http: Flags [F.], seq 0, ack 1, win 229, length 0
18:17:25.465724 IP ip0.36286 > www.yandex.ru.http: Flags [F.], seq 0, ack 1, win 229, length 0

Почему так может происходить? Ведь есть явное правильно, что пакеты from ip0 должны проходить через table0, где указан им путь вперед.

★★★★★

попробуй вставить в начало OUTPUT

-I OUTPUT 1 -p tcp -m state --state INVALID -j DROP

А вообще TRACE в помощь.

vel ★★★★★
()
Последнее исправление: vel (всего исправлений: 1)
Ответ на: комментарий от vel

Эм, я не хочу, чтобы эти пакеты дропались, я так понимаю, это нужные пакеты, только почему-то не с того интерфейса уходяи.

Про TRACE посмотрю, спасибо.

anarquista ★★★★★
() автор топика
Ответ на: комментарий от anarquista

это fin-пакет, который никому уже ничем не поможет.

Есть подозрение, что uid у этого пакета отсутствует, т.к. он генериться системой (обычно из-за незакрытого до конца соединения). Вообще перед закрытием соединения не плохо бы shutdown() сделать. Правильное закрытие соединений со стороны клиента позволяет избавиться от некоторых прблем.

vel ★★★★★
()
Ответ на: комментарий от vel

Да ладно, close тут принципиально ничем не хуже, ядро само закроет соединение правильно.

anarquista ★★★★★
() автор топика

Всё это я делал в Arch с ядро 4.0.5.

Попробовал воспроизвести в Debian Jessie 8.1 с ядром 3.16 — а вот не воспроизводится пока что. А уж не баг ли это?..

anarquista ★★★★★
() автор топика
Ответ на: комментарий от anarquista

Если задача завершается до полного завершения закрытия соединения, то от какого uid будет fin ? Сделай TRACE на fin - будет более понятно с какой проблемой боремся.

Возможно включенныей SO_LINGER даст нужный результат с shutdown()/close().

vel ★★★★★
()
Ответ на: комментарий от vel

Посмотрел TRACE всех пакетов, да, действительно на эти последние пакеты метка не устанавливается, соответсвенно, и интерфейс не меняется.

Хорошо. Но остаётся не понятным, почему тогда адрес меняется на ip0. У всех пакетов, которые видны в логе, SRC=ip1. Пока сокет не закрыт, в логе видно, как выполняется правило, в nat POSTROUTING, заменяющее адрес. Но для пакетов, уходящих с интерфейс eth1, такого правила нет.

anarquista ★★★★★
() автор топика
Ответ на: комментарий от vel

Да, понятно.

Прежде всего, я не учел, что таблица nat просматривается только для первого пакета в соединении, поэтому-то у всех остальных пакетов и меняется адрес, вне зависимости от того, с какого интерфейса этот пакет уходит.

anarquista ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.