1717
1818struct options {
1919 bool count_packets ;
20+ bool gso_enabled ;
2021 int verbose ;
2122 unsigned int queue_num ;
2223 unsigned int timeout ;
24+ uint32_t verdict ;
25+ uint32_t delay_ms ;
2326};
2427
2528static unsigned int queue_stats [5 ];
2629static struct options opts ;
2730
2831static void help (const char * p )
2932{
30- printf ("Usage: %s [-c|-v [-vv] ] [-t timeout] [-q queue_num]\n" , p );
33+ printf ("Usage: %s [-c|-v [-vv] ] [-t timeout] [-q queue_num] [-Qdst_queue ] [ -d ms_delay ] [-G] \n" , p );
3134}
3235
3336static int parse_attr_cb (const struct nlattr * attr , void * data )
@@ -162,7 +165,7 @@ nfq_build_cfg_params(char *buf, uint8_t mode, int range, int queue_num)
162165}
163166
164167static struct nlmsghdr *
165- nfq_build_verdict (char * buf , int id , int queue_num , int verd )
168+ nfq_build_verdict (char * buf , int id , int queue_num , uint32_t verd )
166169{
167170 struct nfqnl_msg_verdict_hdr vh = {
168171 .verdict = htonl (verd ),
@@ -189,9 +192,6 @@ static void print_stats(void)
189192 unsigned int last , total ;
190193 int i ;
191194
192- if (!opts .count_packets )
193- return ;
194-
195195 total = 0 ;
196196 last = queue_stats [0 ];
197197
@@ -234,7 +234,8 @@ struct mnl_socket *open_queue(void)
234234
235235 nlh = nfq_build_cfg_params (buf , NFQNL_COPY_PACKET , 0xFFFF , queue_num );
236236
237- flags = NFQA_CFG_F_GSO | NFQA_CFG_F_UID_GID ;
237+ flags = opts .gso_enabled ? NFQA_CFG_F_GSO : 0 ;
238+ flags |= NFQA_CFG_F_UID_GID ;
238239 mnl_attr_put_u32 (nlh , NFQA_CFG_FLAGS , htonl (flags ));
239240 mnl_attr_put_u32 (nlh , NFQA_CFG_MASK , htonl (flags ));
240241
@@ -255,6 +256,17 @@ struct mnl_socket *open_queue(void)
255256 return nl ;
256257}
257258
259+ static void sleep_ms (uint32_t delay )
260+ {
261+ struct timespec ts = { .tv_sec = delay / 1000 };
262+
263+ delay %= 1000 ;
264+
265+ ts .tv_nsec = delay * 1000llu * 1000llu ;
266+
267+ nanosleep (& ts , NULL );
268+ }
269+
258270static int mainloop (void )
259271{
260272 unsigned int buflen = 64 * 1024 + MNL_SOCKET_BUFFER_SIZE ;
@@ -278,7 +290,7 @@ static int mainloop(void)
278290
279291 ret = mnl_socket_recvfrom (nl , buf , buflen );
280292 if (ret == -1 ) {
281- if (errno == ENOBUFS )
293+ if (errno == ENOBUFS || errno == EINTR )
282294 continue ;
283295
284296 if (errno == EAGAIN ) {
@@ -298,7 +310,10 @@ static int mainloop(void)
298310 }
299311
300312 id = ret - MNL_CB_OK ;
301- nlh = nfq_build_verdict (buf , id , opts .queue_num , NF_ACCEPT );
313+ if (opts .delay_ms )
314+ sleep_ms (opts .delay_ms );
315+
316+ nlh = nfq_build_verdict (buf , id , opts .queue_num , opts .verdict );
302317 if (mnl_socket_sendto (nl , nlh , nlh -> nlmsg_len ) < 0 ) {
303318 perror ("mnl_socket_sendto" );
304319 exit (EXIT_FAILURE );
@@ -314,7 +329,7 @@ static void parse_opts(int argc, char **argv)
314329{
315330 int c ;
316331
317- while ((c = getopt (argc , argv , "chvt:q:" )) != -1 ) {
332+ while ((c = getopt (argc , argv , "chvt:q:Q:d:G " )) != -1 ) {
318333 switch (c ) {
319334 case 'c' :
320335 opts .count_packets = true;
@@ -328,20 +343,48 @@ static void parse_opts(int argc, char **argv)
328343 if (opts .queue_num > 0xffff )
329344 opts .queue_num = 0 ;
330345 break ;
346+ case 'Q' :
347+ opts .verdict = atoi (optarg );
348+ if (opts .verdict > 0xffff ) {
349+ fprintf (stderr , "Expected destination queue number\n" );
350+ exit (1 );
351+ }
352+
353+ opts .verdict <<= 16 ;
354+ opts .verdict |= NF_QUEUE ;
355+ break ;
356+ case 'd' :
357+ opts .delay_ms = atoi (optarg );
358+ if (opts .delay_ms == 0 ) {
359+ fprintf (stderr , "Expected nonzero delay (in milliseconds)\n" );
360+ exit (1 );
361+ }
362+ break ;
331363 case 't' :
332364 opts .timeout = atoi (optarg );
333365 break ;
366+ case 'G' :
367+ opts .gso_enabled = false;
368+ break ;
334369 case 'v' :
335370 opts .verbose ++ ;
336371 break ;
337372 }
338373 }
374+
375+ if (opts .verdict != NF_ACCEPT && (opts .verdict >> 16 == opts .queue_num )) {
376+ fprintf (stderr , "Cannot use same destination and source queue\n" );
377+ exit (1 );
378+ }
339379}
340380
341381int main (int argc , char * argv [])
342382{
343383 int ret ;
344384
385+ opts .verdict = NF_ACCEPT ;
386+ opts .gso_enabled = true;
387+
345388 parse_opts (argc , argv );
346389
347390 ret = mainloop ();
0 commit comments