Estoy usando libnetfilter_queue e iptables con el objetivo NFQUEUE para almacenar paquetes entrantes en tres colas diferentes con --queue-num x .
Creo con éxito las tres colas con funciones libnetfilter_queue , las vinculo, las escucho y las leo de la siguiente manera:
/* given 'h' as a handler of one of my three queues */ fd = nfq_fd(h); while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) { nfq_handle_packet(h, buf, rv); } La función de devolución de llamada, activada con nfq_handle_packet , tiene nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); comando donde envía el paquete tan pronto como ha sido procesado. El problema es que no quiero que todos los paquetes se envíen de inmediato, ya que necesito almacenarlos en una estructura personalizada (escrita a continuación).
Así que me encontré con una solución potencial: puedo llamar al veredicto NF_DROP en lugar de NF_ACCEPT en cada paquete que quiero poner en cola (para que no se envíe inmediatamente), almacenarlo en mi estructura personalizada y luego (tarde o temprano) re- inyectarlo a mi necesidad.
Suena muy bien, pero la situación es la siguiente: no sé cómo reinyectar mis paquetes en cola a mi gusto desde mi aplicación de espacio de usuario . ¿Es correcto usar nfq_set_verdict nuevamente en el mismo punto de mi código, pero con el veredicto NF_ACCEPT ? ¿O debería abrir un zócalo (tal vez uno sin procesar)?
Esta es mi estructura personalizada
struct List { int queue; int pktsize; unsigned char *buffer; struct nfq_q_handle *qh; struct nfqnl_msg_packet_hdr *hdr; struct List *next; };representando un paquete capturado con la regla anterior.
Estas son mis colas donde almacenar paquetes.
struct List *List0 = NULL; // low priority struct List *List1 = NULL; // medium priority struct List *List2 = NULL; // high priority Tengo Ubuntu 14.04 3.13.0-57-generic .
Cualquier sugerencia sera apreciada.
Tu idea tiene sentido. De hecho, he visto un esquema muy similar implementado en un producto comercial en el que trabajé. Tenía que procesar paquetes individuales a altas velocidades, por lo que siempre copiaba el paquete entrante e inmediatamente establecía un veredicto NF_DROP . Luego realizaría el procesamiento y, si decidiera que el paquete debe reenviarse, enviaría la copia a la interfaz de salida. Así que no estás solo.
Hasta donde yo sé, nfq_set_verdict solo se puede llamar una vez por paquete. Una vez que se establece el veredicto, NFQUEUE envía el paquete al destino (que es el paraíso de los paquetes en su caso). No conserva una copia adicional del paquete en caso de que cambie de opinión. Entonces, para enviar el paquete de regreso a la red, deberá almacenar una copia y enviarla usando su propio socket. Y sí, si desea enviar el paquete recibido tal cual (incluidos los encabezados), el socket de salida tendría que ser raw .
No sé si esto encajará con su modelo de aplicación, pero Frottle simplemente mantiene los paquetes en el limbo hasta que decide si aceptarlos o descartarlos. La "novedad" de este enfoque se basa en el hecho de que no es necesario llamar a nfq_set_verdict durante la función de devolución de llamada NFQUEUE; puede llamarlo más tarde y fuera del bucle de netfilter propiamente dicho. Usará más memoria del kernel, pero la alternativa sería simplemente usar más memoria de modo de usuario para que no sea una gran pérdida.
¡Espero que esto ayude!