La mitigación de ataques de denegación de servicio distribuido (DDoS) para protocolos de capa de transporte sin conexión como UDP presenta un desafío fundamental en la seguridad de redes a escala. A diferencia de TCP, UDP carece de un handshake inicial y de mecanismos de estado inherentes, lo que dificulta la distinción entre tráfico legítimo y malicioso cuando el contenido del payload es desconocido. Los sistemas de mitigación tradicionales se basan en el conocimiento de protocolos estándar (DNS, NTP, RDP) para aplicar reglas de filtrado o desafíos.
Sin embargo, la proliferación de aplicaciones que utilizan protocolos UDP personalizados o propietarios (ej. juegos en línea, VoIP, streaming de video) expone una brecha crítica: cuando la infraestructura de mitigación no comprende la semántica del protocolo de aplicación, sus opciones se limitan a bloqueos o rate limiting genéricos, que impactan negativamente al tráfico legítimo. La tesis central de Programmable Flow Protection es que la lógica de mitigación más efectiva reside en el conocimiento específico del protocolo de aplicación, y que esta lógica puede ser inyectada y ejecutada de forma segura y eficiente en el borde de la red global mediante eBPF, delegando la inteligencia de filtrado al propietario del protocolo.
Arquitectura del Sistema
Programmable Flow Protection se integra con la infraestructura existente de mitigación DDoS de Cloudflare, incluyendo 'flowtrackd' para mitigación de capa de red y el uso de tecnologías Linux como XDP y eBPF. La arquitectura permite a los clientes escribir programas eBPF que definen la validez de los paquetes, los cuales son compilados a bytecode BPF y ejecutados en una máquina virtual ligera y aislada. A diferencia de los programas eBPF tradicionales que se cargan en el kernel de Linux, estos programas se ejecutan en userspace, lo que proporciona flexibilidad y seguridad sin comprometer el aislamiento.
El sistema proporciona un API de 'helper functions' adaptado específicamente para la mitigación DDoS, que incluye funcionalidades para almacenar estado por cliente entre ejecuciones del programa, realizar validación criptográfica y emitir paquetes de desafío. Estos programas se ejecutan después de las mitigaciones DDoS estándar de Cloudflare, actuando como una capa de filtrado de granularidad fina. La capacidad de mantener estado permite implementar lógicas de desafío-respuesta para verificar la legitimidad de los clientes, mitigando ataques de replay o spoofing que no serían detectables por firewalls estáticos. La decisión final del programa eBPF puede ser 'pass', 'drop' o 'challenge' el paquete.
Flujo de Mitigación de Tráfico UDP con Programmable Flow Protection
- 1 Ingress Edge Paquete UDP llega al borde de la red global de Cloudflare.
- 2 Mitigación Estándar El paquete pasa por las mitigaciones DDoS estándar de Cloudflare (ej. Advance...
- 3 Ejecución eBPF Si el paquete no es dropeado, se ejecuta el programa eBPF personalizado del c...
- 4 Lógica Personalizada El programa eBPF inspecciona el payload, consulta estado, y aplica lógica de ...
- 5 Decisión El programa decide 'PASS', 'DROP' o 'CHALLENGE' el paquete.
- 6 Acción Si 'PASS', el paquete se envía al origen. Si 'DROP', se descarta. Si 'CHALLEN...
| Capa | Tecnología | Justificación |
|---|---|---|
| networking | eBPF | Permite la ejecución de lógica de filtrado de paquetes personalizada y segura en el borde de la red, adaptada a protocolos propietarios. vs Netfilter/iptables (menos programable, estático), OpenFlow (controlador centralizado, mayor latencia), Custom kernel modules (riesgo de estabilidad, complejidad) Ejecución en userspace con API de helper functions para mitigación DDoS. |
| networking | UDP | Protocolo de transporte objetivo para la mitigación, debido a su naturaleza sin conexión y la dificultad de inspección para protocolos desconocidos. |
| security | flowtrackd | Sistema de mitigación DDoS de capa de red con estado, complementado por la lógica eBPF para casos específicos. |
#include <linux/ip.h>
#include <linux/udp.h>
#include <arpa/inet.h>
#include "cf_ebpf_defs.h"
#include "cf_ebpf_helper.h"
// Custom application header
struct apphdr {
uint8_t version;
uint16_t length; // Length of the variable-length token
uint8_t token[0]; // Variable-length token
} __attribute__((packed));
uint64_t
cf_ebpf_main(void *state)
{
struct cf_ebpf_generic_ctx *ctx = state;
struct cf_ebpf_parsed_headers headers;
struct cf_ebpf_packet_data *p;
// Parse the packet headers with provided helper function
if (parse_packet_data(ctx, &p, &headers) != 0) {
return CF_EBPF_DROP;
}
// Drop packets not destined to port 207
struct udphdr *udp_hdr = (struct udphdr *)headers.udp;
if (ntohs(udp_hdr->dest) != 207) {
return CF_EBPF_DROP;
}
// Get application header from UDP payload
struct apphdr *app = (struct apphdr *)(udp_hdr + 1);
if ((uint8_t *)(app + 1) > headers.data_end) {
return CF_EBPF_DROP;
}
// Perform memory checks to satisfy the verifier
// and access the token safely
uint16_t token_len = ntohs(app->length);
if ((uint8_t *)(app->token + token_len) > headers.data_end) {
return CF_EBPF_DROP;
}
// Check the last byte of the token against expected value
uint8_t *last_byte = app->token + token_len - 1;
if (*last_byte != 0xCF) {
return CF_EBPF_DROP;
}
return CF_EBPF_PASS;
}#include <linux/ip.h>
#include <linux/udp.h>
#include <arpa/inet.h>
#include "cf_ebpf_defs.h"
#include "cf_ebpf_helper.h"
uint64_t
cf_ebpf_main(void *state)
{
// ... (packet parsing and initial checks omitted for brevity)
// Get the status of this source IP (statefully tracked)
uint8_t status;
if (cf_ebpf_get_source_ip_status(&status) != 0) {
return CF_EBPF_DROP;
}
switch (status) {
case NONE:
// Issue a custom challenge to this source IP
issue_challenge(); // Placeholder for actual challenge logic
cf_ebpf_set_source_ip_status(CHALLENGED);
return CF_EBPF_DROP;
case CHALLENGED:
// Check if this packet passes the challenge
// with custom logic
if (verify_challenge()) { // Placeholder for actual verification logic
cf_ebpf_set_source_ip_status(VERIFIED);
return CF_EBPF_PASS;
} else {
cf_ebpf_set_source_ip_status(BLOCKED);
return CF_EBPF_DROP;
}
case VERIFIED:
// This source IP has passed the challenge
return CF_EBPF_PASS;
case BLOCKED:
// This source IP has been blocked
return CF_EBPF_DROP;
default:
return CF_EBPF_PASS;
}
return CF_EBPF_PASS;
}Fundamentos Teóricos
El problema de distinguir tráfico legítimo de malicioso en redes de alta velocidad, especialmente para protocolos no estandarizados, se relaciona con los desafíos de inspección profunda de paquetes (DPI) y clasificación de tráfico. Conceptos como los filtros de Bloom o el hashing consistente son fundamentales para la gestión eficiente de grandes volúmenes de datos y la distribución de carga en sistemas de seguridad de red. La capacidad de programar la red en tiempo de ejecución, como lo permite eBPF, tiene raíces en la investigación sobre redes programables y 'active networks' de los años 90, donde la idea era inyectar lógica de procesamiento en los nodos de la red para una mayor flexibilidad y personalización. eBPF, en particular, extiende el concepto de máquinas virtuales de paquetes (como el original BPF de Steven McCanne y Van Jacobson en 1992) para permitir la ejecución de lógica arbitraria y segura en el kernel, o en este caso, en un entorno de userspace controlado, sin comprometer la estabilidad del sistema subyacente. La verificación de seguridad y terminación de los programas eBPF se basa en principios de análisis estático de código y pruebas de seguridad de sistemas operativos.