Re: Ebtables NFQUEUE Support

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

 



kernel is 2.6.32, while ebtables is 2.0.10-4

On Thu, Oct 25, 2012 at 7:39 AM, Benjamin Beckmeyer
<B.Beckmeyer@xxxxxxxxxxxxxxxxxxxx> wrote:
> 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