Re: Ebtables NFQUEUE Support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thank you JieYue Ma!

This is excellent.  Out of curiousity which kernel version and ebtables
version were you working against?

Benny

> I forgot the ebtables command patch, here it is..
>
> diff -upNr old/extensions/ebt_nfqueue.c new/extensions/ebt_nfqueue.c
> --- old/extensions/ebt_nfqueue.c    1970-01-01 08:00:00.000000000 +0800
> +++ new/extensions/ebt_nfqueue.c    2012-10-24 14:35:40.000000000 +0800
> @@ -0,0 +1,127 @@
> +/*
> + * Shared library add-on to ebtables for NFQ
> + *
> + * (C) 2012 by Ma Jie Yue <jieyue.majy@xxxxxxxxxxxxxx>
> + *
> + * This program is distributed under the terms of GNU GPLv2, 1991
> + */
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <getopt.h>
> +#include <errno.h>
> +
> +#include "../include/ebtables_u.h"
> +#include <linux/netfilter/x_tables.h>
> +#include <linux/netfilter_bridge/ebt_nfqueue.h>
> +
> +#define NFQUEUE_QUEUENUM 0x1
> +#define NFQUEUE_QUEUEBALANCE 0x2
> +
> +static int string_to_number(const char *s, unsigned int min, unsigned
> int max, unsigned int *ret)
> +{
> +   long number;
> +   char *end;
> +   errno = 0;
> +   number = strtol(s, &end, 0);
> +
> +   if (*end == '\0' && end != s) {
> +       if (errno != ERANGE && min <= number && number <= max) {
> +           *ret = number;
> +           return 0;
> +       }
> +   }
> +   return -1;
> +}
> +
> +static void nfqueue_help(void)
> +{
> +   printf("NFQUEUE target options\n"
> +           "  --queue-num value       Send packet to QUEUE number
> <value>.\n"
> +           "                          Valid queue numbers are
> 0-65535\n");
> +}
> +
> +static void nfqueue_init(struct ebt_entry_target* target) {
> +   struct xt_NFQ_info* info = (struct xt_NFQ_info *)target->data;
> +
> +   info->queuenum = 0;
> +}
> +
> +static const struct option nfqueue_opts[] = {
> +   { "queue-num", 1, NULL, 'F' },
> +   { "queue-balance", 1, NULL, 'B' },
> +   { .name = NULL }
> +};
> +
> +static void parse_num(const char *s, struct xt_NFQ_info *tinfo)
> +{
> +   unsigned int num = 0;
> +   if (string_to_number(s, 0, 65535, &num) < 0) {
> +       ebt_print_error("Invalid queue number %s\n", s);
> +   }
> +
> +   tinfo->queuenum = num;
> +}
> +
> +static int nfqueue_parse(int c, char **argv, int argc,
> +       const struct ebt_u_entry *entry, unsigned int *flags,
> +       struct ebt_entry_target **target)
> +{
> +   struct xt_NFQ_info *tinfo = (struct xt_NFQ_info *)(*target)->data;
> +   tinfo->queuenum = 0;
> +
> +   switch (c) {
> +       case 'F':
> +           if (*flags)
> +               ebt_print_error2("NFQUEUE target: "
> +                               "Only use --queue-num ONCE!");
> +           *flags |= NFQUEUE_QUEUENUM;
> +           parse_num(optarg, tinfo);
> +           break;
> +
> +       case 'B':
> +           ebt_print_error2("NFQUEUE target: "
> +                           "--queue-balance not supported (kernel too
> old?)");
> +
> +       default:
> +           break;
> +   }
> +   return 1;
> +}
> +
> +static void nfqueue_print(const struct ebt_u_entry* entry, const
> struct ebt_entry_target *target) {
> +   struct xt_NFQ_info *tinfo = (struct xt_NFQ_info *)target->data;
> +
> +   printf("--queue-num %u ", tinfo->queuenum);
> +}
> +
> +static void nfqueue_check(const struct ebt_u_entry *entry,
> +               const struct ebt_entry_target *target, const char *name,
> +               unsigned int hookmask, unsigned int time) {
> +
> +}
> +
> +static int nfqueue_compare(const struct ebt_entry_target *t1, const
> struct ebt_entry_target *t2) {
> +   struct xt_NFQ_info *info1 = (struct xt_NFQ_info *)t1->data;
> +   struct xt_NFQ_info *info2 = (struct xt_NFQ_info *)t2->data;
> +
> +   return (info1->queuenum == info2->queuenum);
> +}
> +
> +static struct ebt_u_target nfqueue_target = {
> +   .name       = "nfqueue",
> +   .init       = nfqueue_init,
> +   .size       = sizeof(struct xt_NFQ_info),
> +   .help       = nfqueue_help,
> +   .parse      = nfqueue_parse,
> +   .print      = nfqueue_print,
> +   .final_check    = nfqueue_check,
> +   .compare    = nfqueue_compare,
> +   .extra_ops  = nfqueue_opts,
> +};
> +
> +void _init(void) {
> +   ebt_register_target(&nfqueue_target);
> +}
> +
> diff -upNr old/extensions/Makefile new/extensions/Makefile
> --- old/extensions/Makefile 2011-12-16 04:02:47.000000000 +0800
> +++ new/extensions/Makefile 2012-10-24 14:18:50.000000000 +0800
> @@ -1,7 +1,7 @@
>  #! /usr/bin/make
>
>  EXT_FUNC+=802_3 nat arp arpreply ip ip6 standard log redirect vlan
> mark_m mark \
> -          pkttype stp among limit ulog nflog
> +          pkttype stp among limit ulog nflog nfqueue
>  EXT_TABLES+=filter nat broute
>  EXT_OBJS+=$(foreach T,$(EXT_FUNC), extensions/ebt_$(T).o)
>  EXT_OBJS+=$(foreach T,$(EXT_TABLES), extensions/ebtable_$(T).o)
> diff -upNr old/include/linux/netfilter_bridge/ebt_nfqueue.h
> new/include/linux/netfilter_bridge/ebt_nfqueue.h
> --- old/include/linux/netfilter_bridge/ebt_nfqueue.h    1970-01-01
> 08:00:00.000000000 +0800
> +++ new/include/linux/netfilter_bridge/ebt_nfqueue.h    2012-10-24
> 14:17:02.000000000 +0800
> @@ -0,0 +1,11 @@
> +#ifndef __LINUX_BRIDGE_EBT_NFQUEUE_H
> +#define __LINUX_BRIDGE_EBT_NFQUEUE_H
> +
> +#include <linux/types.h>
> +
> +struct xt_NFQ_info {
> +   __u16 queuenum;
> +   int target;
> +};
> +
> +#endif
>
>
> On Wed, Oct 24, 2012 at 1:16 PM, JieYue Ma <xiaoma80.dev@xxxxxxxxx> wrote:
>> Well, I wrote the nfqueue patch for both ebtables and arptables a few
>> months ago, it did work well, so I think it is appropriate to release
>> these patches. Hope it will help you.
>>
>> I am not sure if I understand the problem you raised correctly. I
>> guess it might be the netfilter sus-subsystem currently not supporting
>> queue verdict for bridge very well. As you can see, you need a
>> nf_afinfo structure to be registered before using netfilter queue
>> verdict for this protocol. Unfortunately, during initialization of
>> netfilter, it did register such nf_afinfo for ipv4, ipv6, maybe arp as
>> well.. but not for bridge. So in order to enable queue verdict to work
>> under bridge, you need to register it by yourself, maybe during
>> initialization of ebtables nfqueue target module
>>
>> here is my patch for ebtables:
>>
>>
>> diff -upNr old/include/linux/netfilter_bridge/ebt_nfqueue.h
>> new/include/linux/netfilter_bridge/ebt_nfqueue.h
>> --- old/include/linux/netfilter_bridge/ebt_nfqueue.h    1969-12-31
>> 19:00:00.000000000 -0500
>> +++ new/include/linux/netfilter_bridge/ebt_nfqueue.h    2012-05-29
>> 23:59:06.940194206 -0400
>> @@ -0,0 +1,10 @@
>> +#ifndef __LINUX_BRIDGE_EBT_NFQUEUE_H
>> +#define __LINUX_BRIDGE_EBT_NFQUEUE_H
>> +#include <linux/types.h>
>> +
>> +struct xt_NFQ_info {
>> +        __u16 queuenum;
>> +        int target;
>> +};
>> +
>> +#endif
>> diff -upNr old/net/bridge/netfilter/ebtables.c
>> new/net/bridge/netfilter/ebtables.c
>> --- old/net/bridge/netfilter/ebtables.c 2012-05-27 08:48:00.095617214
>> -0400
>> +++ new/net/bridge/netfilter/ebtables.c 2012-05-27 08:57:27.644193954
>> -0400
>> @@ -252,6 +252,17 @@ letsreturn:
>>             return NF_DROP;
>>         }
>>  #endif
>> +       /*
>> +        * We add NFQUEUE support in ebtables here:
>> +        *
>> +        * If verdict is NF_QUEUE type, pass it to Netfilter. Netfilter
>> will
>> +        * call nf_queue to handle this.
>> +        */
>> +       if (verdict > 0 && (verdict & NF_VERDICT_MASK) == NF_QUEUE) {
>> +           read_unlock_bh(&table->lock);
>> +           return verdict;
>> +       }
>> +
>>         /* jump to a udc */
>>         cs[sp].n = i + 1;
>>         cs[sp].chaininfo = chaininfo;
>>
>> diff -upNr old/net/bridge/netfilter/ebt_nfqueue.c
>> new/net/bridge/netfilter/ebt_nfqueue.c
>> --- old/net/bridge/netfilter/ebt_nfqueue.c  1969-12-31
>> 19:00:00.000000000 -0500
>> +++ new/net/bridge/netfilter/ebt_nfqueue.c  2012-05-27
>> 08:58:58.511193378 -0400
>> @@ -0,0 +1,117 @@
>> +/*
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/kernel.h>
>> +#include <linux/types.h>
>> +#include <linux/netfilter.h>
>> +#include <linux/netfilter/x_tables.h>
>> +#include <linux/netfilter_bridge/ebtables.h>
>> +#include <linux/netfilter_bridge/ebt_nfqueue.h>
>> +
>> +MODULE_AUTHOR("alibaba");
>> +MODULE_DESCRIPTION("ebtables: forwarding to netlink");
>> +MODULE_LICENSE("GPL");
>> +
>> +static unsigned int ebt_nfqueue_tg(struct sk_buff *skb, const struct
>> xt_target_param *par) {
>> +   const struct xt_NFQ_info *info = par->targinfo;
>> +
>> +   return NF_QUEUE_NR(info->queuenum);
>> +}
>> +
>> +static bool ebt_nfqueue_tg_check(const struct xt_tgchk_param* par) {
>> +   const struct xt_NFQ_info *info = par->targinfo;
>> +
>> +   if (BASE_CHAIN && info->target == EBT_RETURN) {
>> +       printk(KERN_INFO"ebt_nfqueue: ebt_nfqueue_tg_check failed\n");
>> +       return false;
>> +   }
>> +
>> +   return true;
>> +}
>> +
>> +void dummy_from_user(void *dst, void *src) {
>> +}
>> +
>> +int dummy_to_user(void __user *dst, void *src) {
>> +   return 0;
>> +}
>> +
>> +static struct xt_target nfqueue_tg_reg __read_mostly = {
>> +   .name           = "nfqueue",
>> +   .revision   = 0,
>> +   .family     = NFPROTO_BRIDGE,
>> +   .table      = "filter",
>> +   .hooks      = (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_LOCAL_IN) | (1
>> << NF_BR_LOCAL_OUT) | (1 << NF_BR_FORWARD),
>> +        .target         = ebt_nfqueue_tg,
>> +        .checkentry     = ebt_nfqueue_tg_check,
>> +        .targetsize     = XT_ALIGN(sizeof(struct xt_NFQ_info)),
>> +   .compat_from_user = dummy_from_user,
>> +   .compat_to_user = dummy_to_user,
>> +        .me             = THIS_MODULE,
>> +};
>> +
>> +
>> +__sum16 nf_br_checksum(struct sk_buff* skb, unsigned int hook,
>> unsigned int dataoff, u_int8_t protocol) {
>> +   return 0;
>> +}
>> +
>> +static __sum16 nf_br_checksum_partial(struct sk_buff* skb, unsigned int
>> hook,
>> +       unsigned int dataoff, unsigned int len,
>> +       u_int8_t protocol) {
>> +   return 0;
>> +}
>> +
>> +static int nf_br_route(struct dst_entry **dst, struct flowi *fl) {
>> +   return 0;
>> +}
>> +
>> +static void nf_br_saveroute(const struct sk_buff *skb, struct
>> nf_queue_entry *entry) {
>> +
>> +}
>> +
>> +static int nf_br_reroute(struct sk_buff *skb, const struct
>> nf_queue_entry *entry) {
>> +   return 0;
>> +}
>> +
>> +static const struct nf_afinfo nf_br_afinfo = {
>> +   .family     = NFPROTO_BRIDGE,
>> +   .checksum   = nf_br_checksum,
>> +   .checksum_partial = nf_br_checksum_partial,
>> +   .route      = nf_br_route,
>> +   .saveroute  = nf_br_saveroute,
>> +   .reroute    = nf_br_reroute,
>> +   .route_key_size = 0,
>> +};
>> +
>> +
>> +static int __init nfqueue_tg_init(void)
>> +{
>> +   int ret;
>> +   /*
>> +    * a tricky hack here, we forge a bridge nf_afinfo struct and
>> register it
>> +    *
>> +    * We have to do this, coz currently netfilter subsystem doesn't
>> support bridge in nf_queue
>> +    */
>> +   ret = nf_register_afinfo(&nf_br_afinfo);
>> +   if (ret < 0) {
>> +       printk("[ebt_nfqueue] nf_register_afinfo failed, cannot
>> install ebt_nfqueue.ko\n");
>> +       return ret;
>> +   }
>> +
>> +   return xt_register_target(&nfqueue_tg_reg);
>> +}
>> +
>> +static void __exit nfqueue_tg_exit(void)
>> +{
>> +   nf_unregister_afinfo(&nf_br_afinfo);
>> +   xt_unregister_target(&nfqueue_tg_reg);
>> +}
>> +
>> +module_init(nfqueue_tg_init);
>> +module_exit(nfqueue_tg_exit);
>>
>>
>>
>>
>> On Sat, Oct 20, 2012 at 2:32 AM, Benjamin Beckmeyer
>> <B.Beckmeyer@xxxxxxxxxxxxxxxxxxxx> wrote:
>>> Hi all,
>>>
>>> I am trying to build an Ebtables NFQUEUE module to also move layer 2
>>> traffic to the NFQUEUE system provided by IPtables.  A few years ago a
>>> Pierre Chifflier provided 3 patches to Ebtables that appear to try and
>>> utilize the NFQUEUE xt_tables target within Ebtables to pass the layer
>>> 2
>>> data via nfnetlink_queue.
>>>
>>> Some background, I am trying to get this working on 2.6.26.5 kernel
>>> version and have applied the patches listed here:
>>>
>>> http://permalink.gmane.org/gmane.comp.security.firewalls.netfilter.devel/37859
>>> http://permalink.gmane.org/gmane.comp.security.firewalls.netfilter.devel/37862
>>>
>>> I have also patched the Ebtables (2.0.8) userspace utility to produce
>>> the
>>> shared object ebt_NFQUEUE.so with code also from Pierre, which can be
>>> found here:
>>>
>>> https://www.wzdftpd.net/downloads/ebt_NFQUEUE.c
>>>
>>> To get the patches to work for the ebt_nfqueue kernel object, due to an
>>> older kernel, I had to modify the target and check function arguments
>>> as
>>> the "const struct xt_action_param" does not exist in my kernel version:
>>>
>>> static int ebt_nfqueue_tg(const struct sk_buff *skb, const struct
>>> net_device *in,
>>>                                    const struct net_device *out, const
>>> void *data, unsigned int datalen)
>>> {
>>>     const struct ebt_nfqueue_info *info = data;
>>>     struct nf_loginfo li;
>>>     unsigned int verdict = NF_ACCEPT;
>>>
>>>     printk(KERN_NOTICE "ebt_NFQUEUE: returning EBT_QUEUE\n");
>>>     return EBT_QUEUE; // return -5
>>> }
>>>
>>> static struct ebt_target ebt_nfqueue __read_mostly = {
>>>     .name               = "NFQUEUE",
>>>     .target     = ebt_nfqueue_tg,
>>>     .check = ebt_nfqueue_check,
>>>     .me                 = THIS_MODULE,
>>> };
>>>
>>> +++++ VERSUS +++++
>>>
>>> static struct xt_target ebt_xt_nfqueue __read_mostly = {
>>>     .name               = "NFQUEUE",
>>>     .revision   = 0,
>>>     .family     = 7, // NFPROTO_BRIDGE
>>>     .target     = ebt_nfqueue_tg,
>>>     .checkentry = ebt_nfqueue_check,
>>>     .targetsize = sizeof(struct ebt_nfqueue_info),
>>>     .me                 = THIS_MODULE,
>>> };
>>>
>>> Nevertheless, the return value from this target is just the EBT_QUEUE
>>> (-5)
>>> to inform the Netfilter system of the queue number.  If I use the
>>> ebt_target rather than xt_target the kernel module will build and can
>>> be
>>> inserted into ebtables with no errors - the problem is that queuing
>>> does
>>> not work.  If I use the xt_target rather than the ebt_target then
>>> Ebtables
>>> userspace complains that it is not supported from this kernel version
>>> (error in communication.c in userspace and appears to fail on the
>>> "setsockopt" calls).
>>>
>>> I have printed out the entire contents of using the xt_target vs
>>> ebt_target and all data going into this call is identical, which
>>> boggles
>>> my mind as to why xt_target will trigger the error in the ebtables
>>> userspace program and ebt_target will not.
>>>
>>> I think that I MUST use the xt_target within ebtables to properly pass
>>> this data to the NFQUEUE system.  This comes from an earlier
>>> discussion:
>>>
>>> +++
>>>
>>> On 04.02.2011 14:40, Pierre Chifflier wrote:
>>>> On 02/04/2011 02:25 PM, Patrick McHardy wrote:
>>>>> On 03.02.2011 15:32, Pierre Chifflier wrote:
>>>>>> This adds support for sending bridge packets to userspace using
>>>>>> the NFQUEUE target with ebtables.
>>>>>
>>>>> I don't think we need a new target for this (and the EBT_QUEUE
>>>>> definition), just using xt_NFQUEUE should work fine.
>>>>
>>>> I thought ebtables did not support sending packet to xtables ? (that's
>>>> on the TODO list for ebtables).
>>>
>>> It can use xtables targets and matches if I'm not completely
>>> mistaken.
>>>
>>> +++
>>>
>>> It appears I can 'use' xtables targets, it will compile correctly, but
>>> ebtables will not actually allow me to insert the rules to jump to the
>>> NFQUEUE target, so I am unable to actually verify if packets would be
>>> queue'd by the system.
>>>
>>> When using the ebt_target I can insert my NFQUEUE rules into the nat
>>> PREROUTING table, and the packet counter will actually increment on
>>> layer
>>> 2 traffic, but the packets do not appear to actually hit any of the
>>> nfnetlink_queue functions (I have added a printk to every function). I
>>> even see that my target has been hit via a printk:
>>>
>>> user.notice kernel: ebt_NFQUEUE: returning EBT_QUEUE
>>>
>>> But then it appears that is as far as the packet goes.
>>>
>>> When queueing a packet from IPtables I see a huge amount of output:
>>>
>>> user.notice kernel: BB: File: nfnetlink_queue.c        Function:
>>> __enqueue_entry
>>> user.notice kernel: BB: File: nfnetlink.c      Function: nfnetlink_rcv
>>> user.notice kernel: BB: File: nfnetlink.c      Function: nfnl_lock
>>> user.notice kernel: BB: File: nfnetlink.c      Function:
>>> nfnetlink_rcv_msg
>>> user.notice kernel: BB: File: nfnetlink.c      Function:
>>> nfnetlink_get_subsys
>>> user.notice kernel: BB: File: nfnetlink.c      Function:
>>> nfnetlink_find_client
>>> user.notice kernel: BB: File: nfnetlink_queue.c        Function:
>>> nfqnl_recv_verdict
>>> user.notice kernel: BB: File: nfnetlink_queue.c        Function:
>>> instance_lookup
>>> user.notice kernel: BB: File: nfnetlink_queue.c        Function:
>>> find_dequeue_entry
>>> user.notice kernel: BB: File: nfnetlink.c      Function: nfnl_unlock
>>> user.notice kernel: BB: File: nfnetlink_queue.c        Function:
>>> nfqnl_enqueue_packet
>>> user.notice kernel: BB: File: nfnetlink_queue.c        Function:
>>> instance_lookup
>>> user.notice kernel: BB: File: nfnetlink_queue.c        Function:
>>> nfqnl_build_packet_message
>>> user.notice kernel: BB: File: nfnetlink.c      Function:
>>> nfnetlink_unicast
>>>
>>> But from my ebtables -j NFQUEUE there are no calls to the nfnetlink.c
>>> or
>>> nfnetlink_queue.c functions.  It is almost like the target is hit then
>>> the
>>> packet is just mysteriously gone...or hits other functions unrelated to
>>> the queueing system.
>>>
>>> In summation, the problem is if using the ebt_target struct in the
>>> kernel
>>> module for ebtables, it will be inserted and can be utilized by the
>>> userspace Ebtables - but it doesnt appear to pass the packet to the
>>> IPtables nfqueue correctly.  If using the xt_target struct in the
>>> kernel
>>> module for ebtables, it will compile, but fails to be utilized by
>>> Ebtables
>>> userspace due to a "setsockopt error mentioned above.
>>>
>>> Any help or suggestions are greatly appreciated!
>>>
>>> Thank you, Benny
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe netfilter" in
>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

--
To unsubscribe from this list: send the line "unsubscribe netfilter" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux