Как получить исходный порт назначения перенаправленного сообщения UDP? - PullRequest
10 голосов
/ 11 апреля 2011

Используя эту вещь Я могу получить исходный IP-адрес назначения сокета socket(PF_INET, SOCK_DGRAM, 0).

Как получить оригинальный порт назначения?

Ответы [ 2 ]

10 голосов
/ 28 апреля 2011

Зависит от механизма перенаправления. Если вы используете REDIRECT (который является NAT под капотом), то вам нужно использовать SO_ORIGINAL_DST или libnetfilter_conntrack, чтобы запросить исходное назначение соединения до применения NAT. Однако, поскольку вы можете обслуживать несколько соединений с одним и тем же сокетом слушателя, этот поиск должен быть выполнен для каждого пакета.

Вы можете поэкспериментировать с libnetfilter_conntrack и сервисами, которые он предоставляет, используя инструмент командной строки conntrack.

Альтернативой является использование TPROXY для перенаправления, которое предназначалось для использования в подобных случаях. Там вы можете получить исходный пункт назначения пакета, используя вспомогательное сообщение, используя recvmsg (). Ключ, который нужно искать, это IP_RECVORIGDST setsockopt.

Дополнительную информацию о TPROXY можно найти в каталоге документации ядра, в файле с именем tproxy.txt. Его немного сложно использовать, но он работает более надежно, так как он реализован стеком, а не подсистемой фильтрации пакетов.

Отредактировано: , чтобы добавить способ запроса адресов назначения UDP с помощью TProxy.

  1. открыть сокет UDP, привязать его к 0.0.0.0 или к более конкретному IP
  2. вы включаете IP_RECVORIGDST через setsockopt (fd, SOL_IP, IP_RECVORIGDSTADDR, ...)
  3. вы используете recvmsg () вместо recvfrom () / recv () для получения кадров
  4. recvmsg () вернет пакет и серию вспомогательных сообщений,
  5. переберите вспомогательные сообщения и найдите блок CMSG с уровнем SOL_IP, индекс IP_ORIGDSTADDR
  6. этот блок CMSG будет содержать struct sockaddr_in с информацией об IP и порте.

Отредактировано: SO_ORIGINAL_DST против udp

SO_ORIGINAL_DST должен работать с сокетами udp, однако ядро ​​не позволяет указывать конечные точки подключения, оно будет использовать сокет, для которого вы вызываете SO_ORIGINAL_DST, для получения этой информации об адресе.

Это означает, что он будет работать, только если UDP-сокет правильно связан (с перенаправленным адресом / портом) и подключен (к рассматриваемому клиенту). Ваш сокет слушателя, вероятно, связан с 0.0.0.0 и обслуживает не один, а несколько клиентов.

Однако вам не нужно использовать фактический сокет прослушивателя для запроса адреса назначения. Поскольку UDP не передает дейтаграммы при установлении соединения, вы можете создать новый сокет UDP, связать его с адресом перенаправления и подключить его к клиенту (чей адрес вы знаете с тех пор, как он отправил первый пакет вашему слушателю в любом случае). Затем вы можете использовать этот сокет для запуска SO_ORIGINAL_DST, однако есть и недостатки:

  1. как только вы откроете такой сокет, ядро ​​предпочтет, что если клиент отправит дополнительные пакеты после первого, а не ваш сокет слушателя
  2. это по своей сути очень неестественно, поскольку к тому времени, когда у вашего приложения появится возможность вызвать SO_ORIGINAL_DST, срок действия записи conntrack может истечь.
  3. это медленно и много накладных расходов

Метод на основе TProxy явно лучше.

1 голос
/ 11 апреля 2011

Попробуйте разобрать /proc/net/nf_conntrack

...