Python/ iptables: захват всех UDP-пакетов и их исходного назначения
я пытаюсь написать iptables
правило, которое перенаправит все исходящие UDP-пакеты в локальный сокет, но мне также нужна информация о назначении. Я начал с
sudo iptables -t nat -A sshuttle-12300 -j RETURN --dest 127.0.0.0/8 -p udp
sudo iptables -t nat -A sshuttle-12300 -j REDIRECT --dest 0.0.0.0/0 -p udp --to-ports 15000
и это здорово, теперь я могу получить все исходящие UDP пакеты, используя сокет на порту 15000.
теперь мне нужна информация о назначении (целевой хост и номер порта), поэтому простого сокета UDP недостаточно; нужен необработанный сокет, чтобы он получил полный IP заголовок.
однако, как оказалось, полученные пакеты, похоже, адресованы для localhost:15000
. Это имеет смысл, потому что это где сокет, но это не то, что я хочу; я хочу хост/порт до того, как пакет был перенаправлен iptables
.
гуглить привело к этот вопрос, С ответом, предлагающим два подхода:TPROXY
и SO_ORIGINAL_DST
, рекомендуя первое, так что это то, с чем я пытался пойти.
добавил iptables
правила для TPROXY
:
sudo iptables -t mangle -A PREROUTING -j TPROXY --dest 0.0.0.0/0 -p udp --on-port 15000
чтение tproxy.txt, нам нужно создать гнездо прослушивания с IP_TRANSPARENT
опция (это делается как root):
from socket import *
s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)
# The IP_TRANSPARENT option isn't defined in the socket module.
# Took the value (19) from the patch in http://bugs.python.org/issue12809
s.setsockopt(SOL_IP, 19, 1)
s.bind(('0.0.0.0', 15000))
s.recv(4096) # Will hang until it receives a packet
хорошо, теперь давайте напишем другой сценарий для создания тестового пакета, чтобы увидеть, если что-нибудь произойдет:
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.connect(('192.168.1.1', 9001))
s.send('hello')
но потом ничего не происходит на принимающей стороне. The recv
вызов, кажется, зависает, не получая никаких данных.
Итак, общий вопрос либо:
- есть ли что-то неправильное в коде для получения данных от
TPROXY
правило?
или
- есть ли другой способ достичь этого (перенаправить все исходящие UDP-пакеты в локальный сокет, чтобы получить информацию о цели)?
редактировать: я должен настаивать, что я хотел бы редирект (поэтому перехватывайте) пакеты, а не просто проверяйте их по мере их прохождения через.
3 ответов
Я нашел ваш вопрос интересным.
следующее решение основано на маркировке UDP-трафика, генерируемого хостом, и его повторной маршрутизации обратно в локальное хост-приложение. В приложении сокет UDP должен использоваться для чтения данных, даже тот, который не предназначен для самого хоста (см. ниже, как).
настройки сети:
- отметьте трафик UDP, который выходит из хоста
- трафик, который отмечен 1, переход к маршрутизации таблица 100 для обработка
- маршрут движения приложения
iptables -A OUTPUT -t mangle -p udp -j MARK --set-mark 1 ip rule add fwmark 1 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100
розетка параметры:
- создать UDP сокет (обычный)
- включить привязку/чтение для локальных адресов
#ifndef IP_TRANSPARENT #define IP_TRANSPARENT 19 #endif int val = 1; setsockopt(sockfd, SOL_IP, IP_TRANSPARENT, &val, sizeof(val));
теперь вы должны иметь возможность читать из сокета. Совет форма Этьен перо: для принятия всего UDP-трафика, привязка к 0.0.0.0.
то, что я нашел здесь очень интересно, является ли локально генерируемый трафик (а не маршрутизируемый) может быть классифицирован и перенаправлен с использованием iptables и правил маршрута.
надеюсь, что это помогает.
вы можете использовать устройство tun / tap, можете просто прочитать его с python, например:
tunnel.py
import os
from fcntl import ioctl
from select import select
import struct
import subprocess
TUNSETIFF = 0x400454ca
TUNMODE = 0x0001
tunFile = os.open("/dev/net/tun", os.O_RDWR)
ifs = ioctl(f, TUNSETIFF, struct.pack("16sH", "tun%d", TUNMODE))
ifname = ifs[:16].strip("\x00")
print "Allocated interface %s. Configure it and use it" % ifname
subprocess.call("ifconfig %s 192.168.13.1" % ifname,shell=True)
# Reading
def read():
r = select([tunFile], [], [])[0][0]
if r == tunFile:
return os.read(tunFile, 1600)
return None
# Writing
def write(buf):
os.write(tunFile, buf)
полный пример можно найти здесь
и направьте свои пакеты на интерфейс "tun0" или напечатанное имя inetrface.
дистрибутивы linux не требуют установки ничего, но если вы находитесь в windows, используйте этой, а для mac os используйте этой
изменить 1 Примечание здесь:
разницу между активным интерфейсом и tun-интерфейс это интерфейс крана выходы (и должны) полный Ethernet-кадры, а tun-интерфейс выходы (и должны) сырые IP пакеты (и нет Ethernet заголовки добавляются к ядру). Ли интерфейс функционирует как интерфейс tun или как интерфейс tap указывается с флагом при создании интерфейса.
для поиска в заголовках пакетов информация(например, src, dst и т. д...) вы можете использовать dpkt
from dpkt import ip
from tunnel import read,write # tunnel.py
while 1:
data = read()
if data:
ipObj = ip.IP(data[4:])
print ipObj.src, ipObj.dst
вы контролируете хозяин? Если это так, вы можете использовать открыть vSwitch чтобы написать правило, которое охватывает только рассматриваемый поток, сохраняя всю информацию IP в порту крана (а затем просто привязать прослушиватель к порту крана).
(ОВС может делать всевозможные гораздо более сложные вещи, но это относительно простая задача)