Un programa que se conecta al enlace XDP del kernel de Linux a través de (e)BPF para un procesamiento rápido de paquetes y realiza un reenvío básico de capa 3/4. Este programa realiza un mapeo de puertos de origen similar a IPTables y NFTables para manejar conexiones. Las conexiones existentes se priorizan en función de los paquetes de conexión por nanosegundo. Esto significa que, cuando se agote el puerto, se reemplazarán las conexiones con la menor cantidad de paquetes por nanosegundo. Creo que esto es mejor ya que las conexiones con más paquetes por nanosegundo serán más sensibles.
Además, si la configuración de red del host o la tarjeta de interfaz de red (NIC) no admite el enlace XDP DRV (también conocido como nativo; ocurre antes de la creación de SKB), el programa intentará conectarse al enlace XDP SKB (también conocido como genérico; ocurre después de SKB creación, que es donde se procesan IPTables y NFTables a través del módulo del kernel netfilter
). Puede utilizar anulaciones a través de la línea de comandos para forzar los modos SKB o de descarga.
Dicho esto, las razones por las que la configuración de red de un host no admite el enlace DRV de XDP pueden ser las siguientes.
Espero que este proyecto ayude a los ingenieros/programadores de redes existentes interesados en utilizar XDP o a cualquiera interesado en ingresar a esos campos. Los enrutadores/reenvío de paquetes de alto rendimiento y la mitigación/prevención (D)DoS son partes muy importantes de la seguridad cibernética y comprender el concepto de redes y flujo de paquetes en un nivel bajo-medio sin duda ayudaría a quienes siguen una carrera en este campo.
ADVERTENCIA : todavía quedan muchas cosas por hacer en este proyecto y, por el momento, solo es compatible con IPv4. Se agregará compatibilidad con IPv6 antes del lanzamiento oficial. A partir de ahora, el programa puede incluir errores y las funciones de reenvío aún no están disponibles.
El valor máximo predeterminado de puertos de origen que se pueden utilizar por dirección de enlace es 21 y se establece aquí (puede ajustarlos si lo desea). Usamos el rango de puertos 500 - 520 de forma predeterminada, pero esto se puede configurar.
Al principio, intentaba utilizar la mayoría de los puertos disponibles (1 - 65534). Sin embargo, debido a las limitaciones del verificador BPF, tuve que generar un par de constantes dentro del kernel de Linux y recompilar el kernel. Hice parches para estos y tengo todo documentado aquí. Puedo ejecutar el programa con 65534 puertos máximos por dirección de enlace sin ningún problema con el kernel personalizado que construí usando los parches que hice. Sin embargo, tenga en cuenta que cuantos más puertos de origen haya disponibles, más procesamiento tendrá que realizar el programa XDP al comprobar los puertos disponibles.
Si planea usar esto para producción, le sugiero compilar su propio kernel con las constantes mencionadas anteriormente. 21 puertos de origen máximo por dirección de enlace no es mucho, pero desafortunadamente, las restricciones predeterminadas del verificador BPF no nos permiten ir más lejos actualmente.
El código principal que causa estas limitaciones se encuentra aquí y ocurre cuando intentamos encontrar el mejor puerto de origen para usar en una nueva conexión. Realmente no hay otra manera de verificar el mejor puerto de origen disponible con la cantidad de flexibilidad que tenemos, según tengo entendido, ya que debemos recorrer todos los puertos de origen y verificar los paquetes por valor de nanosegundo (búsqueda de mapas BPF por clave).
Necesitará make
, clang
, libelf
y llvm
ya que usamos estos paquetes para construir el proyecto. Además, también necesitará libconfig
( libconfig-dev
es el paquete en los sistemas Ubuntu/Debian) para analizar el archivo de configuración.
Para Ubuntu/Debian, lo siguiente debería funcionar.
apt install build-essential make clang libelf-dev llvm libconfig-dev
Supongo que los nombres de los paquetes son similares en otras distribuciones de Linux.
Para utilizar xdpfwd-add
y xdpfwd-del
, debe montar el sistema de archivos BPF ya que el programa XDP fija los mapas BPF en /sys/fs/bpf/xdpfwd
. Existe una alta probabilidad de que esto ya esté hecho a través de iproute2
o algo similar, pero si no es así, puede usar el siguiente comando.
mount -t bpf bpf /sys/fs/bpf/
El uso básico de la línea de comandos incluye lo siguiente.
-o --offload => Attempt to load XDP program with HW/offload mode. If fails, will try DRV and SKB mode in that order.
-s --skb => Force program to load in SKB/generic mode.
-t --time => The amount of time in seconds to run the program for. Unset or 0 = infinite.
-c --config => Location to XDP Forward config (default is /etc/xdpfwd/xdpfwd.conf).
-l --list => List all forwarding rules.
-h --help => Print out command line usage.
La descarga de su programa XDP/BPF a la NIC de su sistema permite el procesamiento de paquetes más rápido que puede lograr debido al procesamiento/reenvío de los paquetes por parte de la NIC con su hardware. Sin embargo, no hay muchos fabricantes de NIC que admitan esta característica y usted está limitado a la memoria/procesamiento de la NIC (por ejemplo, los tamaños de sus mapas BPF serán extremadamente limitados). Además, generalmente existen limitaciones más estrictas del verificador BPF para los programas BPF descargados, pero puede intentar comunicarse con el fabricante de la NIC para ver si le brindarán una versión especial de su controlador de NIC que aumente estas limitaciones (esto es lo que hice con un fabricante). Yo usé).
Hasta este momento, no conozco ningún fabricante de NIC que pueda descargar esta herramienta completamente a la NIC debido a su complejidad BPF y requisitos de bucle. Para ser honesto, en la era actual de las redes, creo que es mejor dejar los programas descargados para las búsquedas de mapas BPF y la inspección mínima de paquetes. Por ejemplo, una simple búsqueda de mapa de tabla de rutas de capa 2 BPF y luego transmitir los paquetes fuera de la NIC. Sin embargo, XDP todavía es muy nuevo y me imagino que veremos estas limitaciones aflojadas o eliminadas en los próximos años. Es por eso que agregué soporte para el modo de descarga en este programa.
El ejecutable xdpfwd-add
que se agrega a $PATH
mediante /usr/bin
durante la instalación acepta los siguientes argumentos.
-b --baddr => The address to bind/look for.
-B --bport => The port to bind/look for.
-d --daddr => The destination address.
-D --dport => The destination port.
-p --protocol => The protocol (either "tcp", "udp", "icmp", or unset for all).
-a --save => Save rule to config file.
Esto agregará una regla de reenvío mientras se ejecuta el programa XDP.
El ejecutable xdpfwd-del
que se agrega a $PATH
a través de /usr/bin
durante la instalación acepta los siguientes argumentos.
-b --baddr => The address to bind/look for.
-B --bport => The port to bind/look for.
-p --protocol => The protocol (either "tcp", "udp", "icmp", or unset for all).
-a --save => Remove rule from config file.
Esto eliminará una regla de reenvío mientras se ejecuta el programa XDP.
El archivo de configuración predeterminado se encuentra en /etc/xdpfwd/xdpfwd.conf
y utiliza la sintaxis libconfig
. Aquí hay una configuración de ejemplo que utiliza todas sus funciones actuales.
interface = "ens18"; // The interface the XDP program attaches to.
// Forwarding rules array.
forwarding = (
{
bind = "10.50.0.3", // The bind address which incoming packets must match.
bindport = 80, // The bind port which incoming packets must match.
protocol = "tcp", // The protocol (as of right now "udp", "tcp", and "icmp" are supported). Right now, you must specify a protocol. However, in the future I will be implementing functionality so you don't have to and it'll do full layer-3 forwarding.
dest = "10.50.0.4", // The address we're forwarding to.
destport = 8080 // The port we're forwarding to (if not set, will use the bind port).
},
...
);
Suponiendo que haya descargado todos los paquetes necesarios, construir este proyecto debería ser sencillo. ¡Puedes usar los siguientes comandos de shell y Bash!
# Clone respository and its sub-modules such as LibBPF.
git clone --recursive https://github.com/gamemann/XDP-Forwarding
# Change directory.
cd XDP-Forwarding
# Make project using all cores.
make -j $( nproc )
# Install binaries to PATH as root so you may use 'xdpfwd', 'xdpfwd-add', 'xdpfwd-del'.
sudo make install