Você pode atingir sua meta usando (abusando) iptables
, para ser mais específico: connbytes
match e NFQUEUE
target. connbytes
permite que você corresponda ao N-ésimo pacote na conexão e NFQUEUE
é um mecanismo para passar pacotes correspondentes a uma regra iptables para o programa userspace. Além disso: você terá que usar algum programa que esteja recebendo pacotes relevantes do kernel e processando-os.
iptables
Estou assumindo aqui que você está interessado em capturar o lado do servidor de pacotes (que pode ser alterado se você estiver interessado na captura do lado do cliente). Nesse caso, precisaremos capturar o pacote 3-incoming para cada conexão (ou seja, o primeiro pacote de entrada após o handshake de três vias) e colocar o pacote em uma fila do netfilter (fila # 1 neste caso).
iptables -I INPUT -p tcp -m tcp --dport 12345 -m connbytes --connbytes-mode packets --connbytes-dir original --connbytes 3:3 -j NFQUEUE --queue-num 1
Assim que um pacote corresponder a essa regra, ele será transmitido para o programa userspace ligado à fila # 1. O programa pode então examinar o pacote e depois decidir aceitá-lo ou soltá-lo.
O programa
Você precisará de um programa que receberá os pacotes no espaço do usuário usando a libnetfilter_queue
library . As ligações para a biblioteca estão disponíveis em diferentes idiomas. A seguir, um exemplo de programa escrito em python:
import struct
from netfilterqueue import NetfilterQueue
def ip_to_string(ip):
return ".".join(map(lambda n: str(ip>>n & 0xff), [24,16,8,0]))
def print_and_accept(pkt):
pl = pkt.get_payload()
src_ip = struct.unpack('>I', pl[12:16])[0]
tcp_offset = (struct.unpack('>B', pl[0:1])[0] & 0xf) * 4
tmp = struct.unpack('>B', pl[tcp_offset+12:tcp_offset+13])[0]
data_offset = ((tmp & 0xf0) >> 4) * 4
src_port = struct.unpack('>H', pl[tcp_offset+0:tcp_offset+2])[0]
data = pl[tcp_offset + data_offset:]
print 'from {}:{}, "{}"'.format(ip_to_string(src_ip), src_port, data)
pkt.accept()
nfqueue = NetfilterQueue()
nfqueue.bind(1, print_and_accept)
try:
nfqueue.run()
except KeyboardInterrupt:
print
O programa assume que os pacotes enfileirados serão pacotes TCP IPv4 e imprime o par de origem ip: porta e a carga TCP do pacote.
Advertências
- Você nunca pode ter certeza de que o primeiro pacote de dados terá o cliente TLS completo como hello - o TCP pode fragmentar o fluxo da forma que desejar e não é impossível receber um único byte no primeiro pacote de dados.
- O TCP Fast Open irá quebrar a lógica desta abordagem. Se estiver habilitado, o handshake triplo inicial pode já transferir dados. Mas o TFO está desativado por padrão em quase todos os dispositivos por enquanto.
- Deve-se tomar cuidado ao usar
NFQUEUE
target: se o programa userspace ligado à fila travar, travar ou for lento para processar pacotes, eles serão descartados / travados e o serviço ligado à porta especificada ficará inacessível. Você pode passar a opção--queue-bypass
para oNFQUEUE
target paraACCEPT
dos pacotes correspondentes se nenhum programa de espaço do usuário estiver ligado à fila especificada: isso deve ajudar com o problema do travamento do programa, mas não ajudará com um travamento ou programa lento.