All of lore.kernel.org
 help / color / mirror / Atom feed
* libnfnetlink_conntrack encapsulation issues
@ 2006-07-27 10:53 Amin Azez
  2006-07-27 11:04 ` aggg " Amin Azez
  2006-07-28 15:38 ` Pablo Neira Ayuso
  0 siblings, 2 replies; 11+ messages in thread
From: Amin Azez @ 2006-07-27 10:53 UTC (permalink / raw)
  To: netfilter-devel

I'm reworking some patches from conntrack 0.4.2 to the latest conntrack
and I am getting badly bitten by a few problems of encapsulation and
over seperation between user and kernel space.

Problem 1:

One of my requirements is to combine CT_DUMP with CT_EVENT, so that I
get regular events but also an inline dump based on a signal (blah blah
blah). Inline (over the same socket) is important as it makes
synchronzing the dump with events a little easier.

Of course most of this won't belong in libnetlink_conntrack but in some
conntrack derivative, but the encapsulation of nfct_handle spoils this.

Specifically, I need such behaviours as requesting the conntrack table
dump but without the nfnl_listen tacked on the end, for example
(simplified fragment):

int nfct_dump_conntrack_table_request(struct nfct_handle *cth, int
flags, int family)
{
        int err, msg;
        struct nfnlhdr req;

        memset(&req, 0, sizeof(req));
        /* This is not important until nfnl_listen we will set it again
by then
        cth->handler = nfct_conntrack_netlink_handler;
        */

        msg = flags;

        nfnl_fill_hdr(cth->nfnlssh_ct, &req.nlh, 0, family, 0,
                        msg,
NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_DUMP);

        err = nfnl_send(cth->nfnlh, &req.nlh);
        return err;
}

int nfct_dump_event_conntrack(struct nfct_handle *cth, int family)
{
        struct sigaction sa;
        struct sigaction oldint;
        sa.sa_handler = signal_handler;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;

        setlinebuf(stdout);

        sigaction(SIGUSR1, &sa, &oldint);

        if
(nfct_dump_conntrack_table_requestl(cth,IPCTNL_MSG_CT_GET_CTRZERO_EXTRA,family)<0)
{
                exit_error(OTHER_PROBLEM, "Can't request initial dump");
                break;
        }

        /* Break this open later to do our own handler and own callback */
        return nfct_event_conntrack(nfct_handle);
}

Of course I'd rather do this duplicating as little of
libnetlink_conntrack as possible, but this means libnetlink_conntrack
needs to open up its primatives a lttle more. The reason I need my own
handler too is because I'm sending back extra tuples including layer7
information (I've submitted patches for this to the layer7 mailing list)

Also, as well as IPCTNL_MSG_CT_GET_CTRZERO in
libnetfilter_conntrack/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h
 I have IPCTNL_MSG_CT_GET_CTRZERO_EXTRA, which is an alternate message
to pass to the kernel to zero another class of counters.  Again, the
libnetlink_conntrack library calls don't permit passing individual
messages, making libnetlink_conntrack tightly coupled to a specific
kernel and requiring that the kernel capabilities be known to
libnetlink_conntrack - for example, do we need to change
libnetlink_conntrack every time a new type of data can be dumped? (e.g.
layer7?)

Problem 2

autogen.sh

(mild issue first, not your fault anyway)

Of course my message is defined in my kernel headers which autogen.sh
tries to copy accross - except that I am now using the make -o option
for the kernel which means that build header files like autoconf.h,
compile.h and version.h are linked to from /lib/modules/`uname -r`/build
but none of the source header files are. For now I can copy the header
file by hand but I wonder if anyone has a more general solution to this.
I guess that the make process ought to write symlinks to any include
dirs to the source.

However (big problems), when I make autogen copy my version of
nfnetlink_conntrack.h, compiles fail on lack of: CTA_EXPECT_QUEUENR
which I don't find available in any of the kernel sources I have; so
which kernel is being tracked for libnetfilter_conntrack? The only
useful reference google can find is a February chat session which
indicates that linux_nfnetlink_conntrack.h is being kept in SVN so where
does the idea of CTA_EXPECT_QUEUENR come from?

In fact I find that despite the assurances in autogen,sh,
linux_nfnetlink_conntrack.h IS being kept in CVN and that the only
solution the chatlogs recommend is to revert linux_nfnetlink_conntrack.h
to the supplied one? What?


I sometimes wonder if it is time to stop sharing enums like this between
kernel and user space and make text labels out of them which
applications can resolve into numbers by asking the kernel as they are
executed.

Sam

^ permalink raw reply	[flat|nested] 11+ messages in thread

* aggg Re: libnfnetlink_conntrack encapsulation issues
  2006-07-27 10:53 libnfnetlink_conntrack encapsulation issues Amin Azez
@ 2006-07-27 11:04 ` Amin Azez
  2006-07-27 14:00   ` Patrick McHardy
  2006-07-28 15:38 ` Pablo Neira Ayuso
  1 sibling, 1 reply; 11+ messages in thread
From: Amin Azez @ 2006-07-27 11:04 UTC (permalink / raw)
  To: netfilter-devel

Not only is linux_nfnetlink_conntrack.h from SVN and not any kernel, it
even ignores the kernel config so such ifdef's as:

enum ctattr_type {
        CTA_UNSPEC,
        CTA_TUPLE_ORIG,
        CTA_TUPLE_REPLY,
        CTA_STATUS,
        CTA_PROTOINFO,
        CTA_HELP,
        CTA_NAT_SRC,
#define CTA_NAT       CTA_NAT_SRC     /* backwards compatibility */
        CTA_TIMEOUT,
        CTA_MARK,
        CTA_COUNTERS_ORIG,
        CTA_COUNTERS_REPLY,
        CTA_USE,
        CTA_ID,
        CTA_NAT_DST,
#if defined(CONFIG_IP_NF_MATCH_LAYER7) ||
defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
        CTA_L7,
#endif /* LAYER7 */
#ifdef CONFIG_IP_NF_CT_LINKLAYER
        CTA_LINKLAYER,
#endif /* LINKLAYER */
...
...
...

are ignored, resulting in a totally different enum anyway.

I see now that obviously these extra enum members should not be defined
with ifdef, and it fact it makes a lot of sense, otherwise rebuilding
with a new match enabled as a module would change the enum definition
for that module but for nothing else.

BUT if libnetlink_conntrack is going to be reading kernel files, ought
it not to read in the kernel config too?

oy oy oy. Sorry to be so dumb, but I don't think we've hit the right
kernel/userspace solution yet.

I'm reminded of the windows make_atom call which allows you or anyone to
 supply a string and get the same number back every time, I wonder if we
need that instead of enums.

Sam

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: aggg Re: libnfnetlink_conntrack encapsulation issues
  2006-07-27 11:04 ` aggg " Amin Azez
@ 2006-07-27 14:00   ` Patrick McHardy
       [not found]     ` <44C8CC58.1080909@ufomechanic.net>
  0 siblings, 1 reply; 11+ messages in thread
From: Patrick McHardy @ 2006-07-27 14:00 UTC (permalink / raw)
  To: Amin Azez; +Cc: netfilter-devel

Amin Azez wrote:
> Not only is linux_nfnetlink_conntrack.h from SVN and not any kernel, it
> even ignores the kernel config so such ifdef's as:
> 
> enum ctattr_type {
>         CTA_UNSPEC,
>         CTA_TUPLE_ORIG,
>         CTA_TUPLE_REPLY,
>         CTA_STATUS,
>         CTA_PROTOINFO,
>         CTA_HELP,
>         CTA_NAT_SRC,
> #define CTA_NAT       CTA_NAT_SRC     /* backwards compatibility */
>         CTA_TIMEOUT,
>         CTA_MARK,
>         CTA_COUNTERS_ORIG,
>         CTA_COUNTERS_REPLY,
>         CTA_USE,
>         CTA_ID,
>         CTA_NAT_DST,
> #if defined(CONFIG_IP_NF_MATCH_LAYER7) ||
> defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
>         CTA_L7,
> #endif /* LAYER7 */
> #ifdef CONFIG_IP_NF_CT_LINKLAYER
>         CTA_LINKLAYER,
> #endif /* LINKLAYER */
> ...
> ...
> ...

WTF is this? Its not from SVN, it appears the layer7 match does some
bad hacks here. It looks like a really dumb idea, this will break
once we add new attributes. Not sure why a match would need ctnetlink
attributes.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: aggg Re: libnfnetlink_conntrack encapsulation issues
       [not found]     ` <44C8CC58.1080909@ufomechanic.net>
@ 2006-07-27 14:32       ` Patrick McHardy
  2006-07-27 14:43         ` Amin Azez
  0 siblings, 1 reply; 11+ messages in thread
From: Patrick McHardy @ 2006-07-27 14:32 UTC (permalink / raw)
  To: Amin Azez; +Cc: netfilter-devel

Amin Azez wrote:
> * Patrick McHardy wrote, On 27/07/06 15:00:
> 
>>it appears the layer7 match does some
>>bad hacks here. 
> 
> Thats my layer7 stuff.
> I recognize that ifdef's here are no good because the file is used for
> userspace, which doesn't solve the general problem of adding conntrack
> attributes generally (which I've been doing for the last 15 months). The
> current mechanism effectively ensures that this cannot happen (sadly)

One way to add new stuff is to get your patch into the kernel. Other
than that its hard, I agree. ifdefs are not a good idea because
following members don't have a constant value anymore.

>>It looks like a really dumb idea, this will break
>>once we add new attributes. Not sure why a match would need ctnetlink
>>attributes.
>>  
> 
> Some matches (like layer7) store state which is output via
> /proc/net/ip_conntrack, I also need it as part of conntrack updates.
> I like receiving a conntrack update when the layer7 is detected, for
> instance.

A match shouldn't do that - what kind of state does it store? Can't
you just use your match and combine it with CONNMARK?

> I also output the link layer mac addresses as part of conntrack dumps/

The LL address is not part of the conntrack entry and can change at any
time, so it doesn't belong in ctnetlink.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: aggg Re: libnfnetlink_conntrack encapsulation issues
  2006-07-27 14:32       ` Patrick McHardy
@ 2006-07-27 14:43         ` Amin Azez
  2006-07-27 14:59           ` Patrick McHardy
  0 siblings, 1 reply; 11+ messages in thread
From: Amin Azez @ 2006-07-27 14:43 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netfilter-devel

* Patrick McHardy wrote, On 27/07/06 15:32:
> Amin Azez wrote:
>> * Patrick McHardy wrote, On 27/07/06 15:00:
>>
>>> it appears the layer7 match does some
>>> bad hacks here. 
>> Thats my layer7 stuff.
>> I recognize that ifdef's here are no good because the file is used for
>> userspace, which doesn't solve the general problem of adding conntrack
>> attributes generally (which I've been doing for the last 15 months). The
>> current mechanism effectively ensures that this cannot happen (sadly)
> 
> One way to add new stuff is to get your patch into the kernel. Other
> than that its hard, I agree. ifdefs are not a good idea because
> following members don't have a constant value anymore.

Indeed. Layer7 has been around some time, I guess I will attempt to get
CTA_L7 into that file in the official kernel so that those who use the
L7 match can get L7 info via contrack /if they want/.

> 
>> Some matches (like layer7) store state which is output via
>> /proc/net/ip_conntrack, I also need it as part of conntrack updates.
>> I like receiving a conntrack update when the layer7 is detected, for
>> instance.
> 
> A match shouldn't do that - what kind of state does it store? Can't
> you just use your match and combine it with CONNMARK?

Err... it stores the layer7 pattern that was matched against the
packets. So you can recognize a flow as being HTTP or SMTP or DNS etc,
by regexing the packets. It only checks the first few packets in each
direction of the flow, but having matched, the name of the matching
pattern becomes part of the conntrack, and the iptables module can then
test this - so you could set a certain connmark based on the ip
addresses in combination with some layer7 type; so that HTTP - no matter
what the port - could all have a higher priority. This is visible from
/proc/net/ip_conntrack

>> I also output the link layer mac addresses as part of conntrack dumps/
> 
> The LL address is not part of the conntrack entry and can change at any
> time, so it doesn't belong in ctnetlink.

I won't argue on this one, it's merely one of my uses, with the option
to perform a ctnetlink update when the mac addresses change.

The bigger problem which I guess you answered is, how "new" ctnetlink
attributes should be registered and used; how near an extensible
framework (which is what I *thought* libnetlink_conntrack was for) and
how much is just abstraction from the kernel (which it seems *is* what
libnetlink_conntrack is for).


This other problem was how much of libnetlink_conntrack I am rewriting
so that I can vary ever so slightly the conntrack user space tool. I'll
send my patches on this early next week when I'm through testing on 2.6.17

thanks

Sam

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: aggg Re: libnfnetlink_conntrack encapsulation issues
  2006-07-27 14:43         ` Amin Azez
@ 2006-07-27 14:59           ` Patrick McHardy
  2006-07-27 15:16             ` Amin Azez
  0 siblings, 1 reply; 11+ messages in thread
From: Patrick McHardy @ 2006-07-27 14:59 UTC (permalink / raw)
  To: Amin Azez; +Cc: netfilter-devel

Amin Azez wrote:
> * Patrick McHardy wrote, On 27/07/06 15:32:
> 
>>One way to add new stuff is to get your patch into the kernel. Other
>>than that its hard, I agree. ifdefs are not a good idea because
>>following members don't have a constant value anymore.
> 
> 
> Indeed. Layer7 has been around some time, I guess I will attempt to get
> CTA_L7 into that file in the official kernel so that those who use the
> L7 match can get L7 info via contrack /if they want/.

Its not a big deal, but I lean towards not taking such a patch as it
is a) only used by an external match and b) wrong anyway in my opinion.

>>>Some matches (like layer7) store state which is output via
>>>/proc/net/ip_conntrack, I also need it as part of conntrack updates.
>>>I like receiving a conntrack update when the layer7 is detected, for
>>>instance.
>>
>>A match shouldn't do that - what kind of state does it store? Can't
>>you just use your match and combine it with CONNMARK?
> 
> 
> Err... it stores the layer7 pattern that was matched against the
> packets. So you can recognize a flow as being HTTP or SMTP or DNS etc,
> by regexing the packets. It only checks the first few packets in each
> direction of the flow, but having matched, the name of the matching
> pattern becomes part of the conntrack, and the iptables module can then
> test this - so you could set a certain connmark based on the ip
> addresses in combination with some layer7 type; so that HTTP - no matter
> what the port - could all have a higher priority. This is visible from
> /proc/net/ip_conntrack

I actually don't understand the need for the layer7 match at all.
The string match with the fsm textsearch algorithm and some clever
CONNMARK use should be able to do the same.

> The bigger problem which I guess you answered is, how "new" ctnetlink
> attributes should be registered and used; how near an extensible
> framework (which is what I *thought* libnetlink_conntrack was for) and
> how much is just abstraction from the kernel (which it seems *is* what
> libnetlink_conntrack is for).

Its meant for a single purpose - access to the conntrack database.
It is extensible enough for this purpose, we can add new attributes
in the kernel any time.

> This other problem was how much of libnetlink_conntrack I am rewriting
> so that I can vary ever so slightly the conntrack user space tool. I'll
> send my patches on this early next week when I'm through testing on 2.6.17

I'm also not too happy with the current library. I'm doing some work
adding nfnetlink support to libnl, but its far from complete.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: aggg Re: libnfnetlink_conntrack encapsulation issues
  2006-07-27 14:59           ` Patrick McHardy
@ 2006-07-27 15:16             ` Amin Azez
  2006-07-29  2:11               ` Patrick McHardy
  0 siblings, 1 reply; 11+ messages in thread
From: Amin Azez @ 2006-07-27 15:16 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netfilter-devel

* Patrick McHardy wrote, On 27/07/06 15:59:
> Amin Azez wrote:
>> * Patrick McHardy wrote, On 27/07/06 15:32:
>>
>>> One way to add new stuff is to get your patch into the kernel. Other
>>> than that its hard, I agree. ifdefs are not a good idea because
>>> following members don't have a constant value anymore.
>>
>> Indeed. Layer7 has been around some time, I guess I will attempt to get
>> CTA_L7 into that file in the official kernel so that those who use the
>> L7 match can get L7 info via contrack /if they want/.
> 
> Its not a big deal, but I lean towards not taking such a patch as it
> is a) only used by an external match and b) wrong anyway in my opinion.

I would lean towards not taking it too, but how else to get
libnetlink_conntrack to work with arbitrary conntrack attributes?
And taking the general case of ct_extend? make_atom is my favoured
solution but it might spoil the _XXX_MSG_MAX idea, or we would need
multiple atom pools.

> I actually don't understand the need for the layer7 match at all.
> The string match with the fsm textsearch algorithm and some clever
> CONNMARK use should be able to do the same.

I heard a layer7 guy saying a similar thing about the string match. I
think. :-) It's not like I'm trying to match a particular layer7
protocol, I'm trying to match about a hundred, and managing regex's is
easy. Anyway.... I'm not for making everyone like each-others favourite
modules; I'm already overusing the mark (IMHO) although some use it
more, it really is a boon to have the odd extra conntrack attribute
/that I need/

> Its meant for a single purpose - access to the conntrack database.
> It is extensible enough for this purpose, we can add new attributes
> in the kernel any time.

thats the bit I'm also trying to do..

I've also extended connmark so that each flow can have its own mark -
which sort of helps traffic shaping each direction differently.
Naturally of course, I need to get the extra marks from the conntrack
database to userspace, along with the original mark. (For compatability
there are now 3 marks, the traditional mark, and one set for each direction)

Sam

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: libnfnetlink_conntrack encapsulation issues
  2006-07-27 10:53 libnfnetlink_conntrack encapsulation issues Amin Azez
  2006-07-27 11:04 ` aggg " Amin Azez
@ 2006-07-28 15:38 ` Pablo Neira Ayuso
  2006-07-28 21:13   ` Amin Azez
  2006-07-29 10:51   ` Pablo Neira Ayuso
  1 sibling, 2 replies; 11+ messages in thread
From: Pablo Neira Ayuso @ 2006-07-28 15:38 UTC (permalink / raw)
  To: Amin Azez
  Cc: Harald Welte, Netfilter Development Mailinglist, Patrick McHardy

Amin Azez wrote:
> I'm reworking some patches from conntrack 0.4.2 to the latest conntrack
> and I am getting badly bitten by a few problems of encapsulation and
> over seperation between user and kernel space.
>
> Problem 1:
> 
> One of my requirements is to combine CT_DUMP with CT_EVENT, so that I
> get regular events but also an inline dump based on a signal (blah blah
> blah). Inline (over the same socket) is important as it makes
> synchronzing the dump with events a little easier.
> 
> Of course most of this won't belong in libnetlink_conntrack but in some
> conntrack derivative, but the encapsulation of nfct_handle spoils this.
> 
> Specifically, I need such behaviours as requesting the conntrack table
> dump but without the nfnl_listen tacked on the end, for example
> (simplified fragment):
> 
> int nfct_dump_conntrack_table_request(struct nfct_handle *cth, int
> flags, int family)
> {
>         int err, msg;
>         struct nfnlhdr req;
> 
>         memset(&req, 0, sizeof(req));
>         /* This is not important until nfnl_listen we will set it again
> by then
>         cth->handler = nfct_conntrack_netlink_handler;
>         */
> 
>         msg = flags;
> 
>         nfnl_fill_hdr(cth->nfnlssh_ct, &req.nlh, 0, family, 0,
>                         msg,
> NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_DUMP);
> 
>         err = nfnl_send(cth->nfnlh, &req.nlh);
>         return err;
> }
> 
> int nfct_dump_event_conntrack(struct nfct_handle *cth, int family)
> {
>         struct sigaction sa;
>         struct sigaction oldint;
>         sa.sa_handler = signal_handler;
>         sigemptyset(&sa.sa_mask);
>         sa.sa_flags = 0;
> 
>         setlinebuf(stdout);
> 
>         sigaction(SIGUSR1, &sa, &oldint);
> 
>         if
> (nfct_dump_conntrack_table_requestl(cth,IPCTNL_MSG_CT_GET_CTRZERO_EXTRA,family)<0)
> {
>                 exit_error(OTHER_PROBLEM, "Can't request initial dump");
>                 break;
>         }
> 
>         /* Break this open later to do our own handler and own callback */
>         return nfct_event_conntrack(nfct_handle);
> }

The right thing here is not adding more crap API like this that makes 
very specific things. The problem with libnetfilter_conntrack is that at 
the time that I designed it I tried to hide as much netlink details as 
possible at that was an error.

I just send the patch attached to Patrick, since I can't commit to SVN 
anymore since my certificate expired. It provides low-level functions 
for those that want to work with libnfnetlink (or someday libnl) that is 
what I'm currently doing with conntrackd.

So libnetfilter_conntrack provides the set of specific functions to 
build netlink messages/attributes and you can use the low level 
communication layer that you prefer.

> Of course I'd rather do this duplicating as little of
> libnetlink_conntrack as possible, but this means libnetlink_conntrack
> needs to open up its primatives a lttle more. The reason I need my own
> handler too is because I'm sending back extra tuples including layer7
> information (I've submitted patches for this to the layer7 mailing list)
> 
> Also, as well as IPCTNL_MSG_CT_GET_CTRZERO in
> libnetfilter_conntrack/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h
>  I have IPCTNL_MSG_CT_GET_CTRZERO_EXTRA, which is an alternate message
> to pass to the kernel to zero another class of counters.  Again, the
> libnetlink_conntrack library calls don't permit passing individual
> messages, making libnetlink_conntrack tightly coupled to a specific
> kernel and requiring that the kernel capabilities be known to
> libnetlink_conntrack - for example, do we need to change
> libnetlink_conntrack every time a new type of data can be dumped? (e.g.
> layer7?)
>
> Problem 2
> 
> autogen.sh
> 
> (mild issue first, not your fault anyway)
> 
> Of course my message is defined in my kernel headers which autogen.sh
> tries to copy accross - except that I am now using the make -o option
> for the kernel which means that build header files like autoconf.h,
> compile.h and version.h are linked to from /lib/modules/`uname -r`/build
> but none of the source header files are. For now I can copy the header
> file by hand but I wonder if anyone has a more general solution to this.
> I guess that the make process ought to write symlinks to any include
> dirs to the source.
> 
> However (big problems), when I make autogen copy my version of
> nfnetlink_conntrack.h, compiles fail on lack of: CTA_EXPECT_QUEUENR
> which I don't find available in any of the kernel sources I have; so
> which kernel is being tracked for libnetfilter_conntrack? The only
> useful reference google can find is a February chat session which
> indicates that linux_nfnetlink_conntrack.h is being kept in SVN so where
> does the idea of CTA_EXPECT_QUEUENR come from?

This is Harald's userspace helper stuff that is pending to be commited, 
since he's overloaded with work, I propose to remove it temporarily from 
SVN to avoid breaking things and take it back later once it gets commited.

> In fact I find that despite the assurances in autogen,sh,
> linux_nfnetlink_conntrack.h IS being kept in CVN and that the only
> solution the chatlogs recommend is to revert linux_nfnetlink_conntrack.h
> to the supplied one? What?
> 
> 
> I sometimes wonder if it is time to stop sharing enums like this between
> kernel and user space and make text labels out of them which
> applications can resolve into numbers by asking the kernel as they are
> executed.

enums are OK, the problem is out-of-tree scary things like this layer 7 
stuff that makes an insane use of libnetfilter_conntrack.

-- 
The dawn of the fourth age of Linux firewalling is coming; a time of 
great struggle and heroic deeds -- J.Kadlecsik got inspired by J.Morris

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: libnfnetlink_conntrack encapsulation issues
  2006-07-28 15:38 ` Pablo Neira Ayuso
@ 2006-07-28 21:13   ` Amin Azez
  2006-07-29 10:51   ` Pablo Neira Ayuso
  1 sibling, 0 replies; 11+ messages in thread
From: Amin Azez @ 2006-07-28 21:13 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: Harald Welte, Netfilter Development Mailinglist, Patrick McHardy


Thanks for your help Pablo.

Pablo Neira Ayuso wrote:
>
> enums are OK, the problem is out-of-tree scary things like this layer 
> 7 stuff that makes an insane use of libnetfilter_conntrack.
>

ummmm it seems quite normal use, such as any iptables extension that 
stores per-conntrack information might want to use. I already mentioned 
the per-flow mark, so that each flow of a conntrack can have its own 
mark; just like it suseful to get one mark via conntrack, its useful to 
get the rest too.

I agree, out-of-tree is where it gets scary. I send myself to sleep at 
night thinking up alternative methods.

Sam

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: aggg Re: libnfnetlink_conntrack encapsulation issues
  2006-07-27 15:16             ` Amin Azez
@ 2006-07-29  2:11               ` Patrick McHardy
  0 siblings, 0 replies; 11+ messages in thread
From: Patrick McHardy @ 2006-07-29  2:11 UTC (permalink / raw)
  To: Amin Azez; +Cc: netfilter-devel

Amin Azez wrote:
> * Patrick McHardy wrote, On 27/07/06 15:59:
> 
>>Its not a big deal, but I lean towards not taking such a patch as it
>>is a) only used by an external match and b) wrong anyway in my opinion.
> 
> 
> I would lean towards not taking it too, but how else to get
> libnetlink_conntrack to work with arbitrary conntrack attributes?
> And taking the general case of ct_extend? make_atom is my favoured
> solution but it might spoil the _XXX_MSG_MAX idea, or we would need
> multiple atom pools.

I guess the first question we need to answer is if it has too.

>>I actually don't understand the need for the layer7 match at all.
>>The string match with the fsm textsearch algorithm and some clever
>>CONNMARK use should be able to do the same.
> 
> 
> I heard a layer7 guy saying a similar thing about the string match. I
> think. :-) It's not like I'm trying to match a particular layer7
> protocol, I'm trying to match about a hundred, and managing regex's is
> easy. Anyway.... I'm not for making everyone like each-others favourite
> modules; I'm already overusing the mark (IMHO) although some use it
> more, it really is a boon to have the odd extra conntrack attribute
> /that I need/

Last time I looked at the layer7 match (long time ago though), it
didn't do any optimizations for matching multiple patterns, so I think
the string match will perform at least comparable and you will need
log2(n) CONNMARK bits. I really hate this idea that every high-level
function needs an equivalent in the kernel, just because its harder
to use without (with low-level tools).

> I've also extended connmark so that each flow can have its own mark -
> which sort of helps traffic shaping each direction differently.
> Naturally of course, I need to get the extra marks from the conntrack
> database to userspace, along with the original mark. (For compatability
> there are now 3 marks, the traditional mark, and one set for each direction)

I have been using a patch for a long time that extends the conntrack
match by a match on direction, just never made an effort to merge it.
You can encode the direction of each packet in the mark independant
of connmark. I think this approach is a lot more flexible. I'll take
care of adding this (and port matches) sometime if nobody beats me
to it.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: libnfnetlink_conntrack encapsulation issues
  2006-07-28 15:38 ` Pablo Neira Ayuso
  2006-07-28 21:13   ` Amin Azez
@ 2006-07-29 10:51   ` Pablo Neira Ayuso
  1 sibling, 0 replies; 11+ messages in thread
From: Pablo Neira Ayuso @ 2006-07-29 10:51 UTC (permalink / raw)
  To: Amin Azez
  Cc: Harald Welte, Netfilter Development Mailinglist, Patrick McHardy

[-- Attachment #1: Type: text/plain, Size: 707 bytes --]

Pablo Neira Ayuso wrote:
> I just send the patch attached to Patrick, since I can't commit to SVN 
> anymore since my certificate expired. It provides low-level functions 
> for those that want to work with libnfnetlink (or someday libnl) that is 
> what I'm currently doing with conntrackd.

Uh, I forgot to attach the patch that I sent to Patrick. It implements a 
set of functions to build/parse netlink messages for ctnetlink, so you 
can implement your own functions that do specific things with 
libnfnetlink and them, I think this is way more flexible.

-- 
The dawn of the fourth age of Linux firewalling is coming; a time of 
great struggle and heroic deeds -- J.Kadlecsik got inspired by J.Morris

[-- Attachment #2: libnetfilter_conntrack.patch --]
[-- Type: text/plain, Size: 23459 bytes --]

Index: include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h
===================================================================
--- include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h	(revisión: 6652)
+++ include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h	(copia de trabajo)
@@ -27,13 +27,15 @@
 	CTA_STATUS,
 	CTA_PROTOINFO,
 	CTA_HELP,
-	CTA_NAT,
+	CTA_NAT_SRC,
+#define CTA_NAT	CTA_NAT_SRC	/* backwards compatibility */
 	CTA_TIMEOUT,
 	CTA_MARK,
 	CTA_COUNTERS_ORIG,
 	CTA_COUNTERS_REPLY,
 	CTA_USE,
 	CTA_ID,
+	CTA_NAT_DST,
 	__CTA_MAX
 };
 #define CTA_MAX (__CTA_MAX - 1)
Index: include/libnetfilter_conntrack/libnetfilter_conntrack.h
===================================================================
--- include/libnetfilter_conntrack/libnetfilter_conntrack.h	(revisión: 6652)
+++ include/libnetfilter_conntrack/libnetfilter_conntrack.h	(copia de trabajo)
@@ -96,7 +96,8 @@
 
 	union nfct_protoinfo protoinfo;
 	struct nfct_counters counters[NFCT_DIR_MAX];
-	struct nfct_nat nat;
+	struct nfct_nat snat;
+	struct nfct_nat dnat;
 };
 
 struct nfct_expect {
@@ -211,6 +212,8 @@
 /*
  * [Allocate|free] a conntrack
  */
+extern struct nfct_conntrack *nfct_conntrack_new(void);
+
 extern struct nfct_conntrack *
 nfct_conntrack_alloc(struct nfct_tuple *orig, struct nfct_tuple *reply,
 		     u_int32_t timeout, union nfct_protoinfo *proto,
@@ -281,6 +284,30 @@
 extern int nfct_event_conntrack(struct nfct_handle *cth); 
 
 /*
+ * NAT facilities 
+ */
+
+enum {
+	NFCT_NAT_SRC,
+	NFCT_NAT_DST,
+	NFCT_NAT_PORT_SRC,
+	NFCT_NAT_PORT_DST
+};
+
+extern int nfct_nat_setup(unsigned int type,
+			  struct nfct_conntrack *ct,
+			  const char *data);
+
+/*
+ * strip NAT handlings
+ */ 
+extern void nfct_conntrack_strip_nat(const struct nfct_conntrack *ct,
+				     struct nfct_conntrack *strip_ct);
+extern int nfct_conntrack_is_snatted(const struct nfct_conntrack *ct);
+extern int nfct_conntrack_is_dnatted(const struct nfct_conntrack *ct);
+extern int nfct_conntrack_is_redirected(const struct nfct_conntrack *ct);
+
+/*
  * Conntrack printing functions
  */
 extern int nfct_sprintf_conntrack(char *buf, struct nfct_conntrack *ct, 
@@ -305,6 +332,17 @@
 extern int nfct_conntrack_compare(struct nfct_conntrack *ct1, 
 				  struct nfct_conntrack *ct2,
 				  struct nfct_conntrack_compare *cmp);
+/*
+ * Tuple comparison
+ */
+extern int nfct_tuple_src_equal(const struct nfct_tuple *t1,
+				const struct nfct_tuple *t2);
+extern int nfct_tuple_dst_equal(const struct nfct_tuple *t1,
+				const struct nfct_tuple *t2);
+extern int nfct_tuple_proto_equal(const struct nfct_tuple *t1,
+				  const struct nfct_tuple *t2);
+extern int nfct_tuple_equal(const struct nfct_tuple *t1,
+			    const struct nfct_tuple *t2);
 
 /* 
  * Expectations
@@ -327,11 +365,38 @@
 extern int nfct_sprintf_expect_id(char *buf, struct nfct_expect *exp);
 
 /*
- * low-level functions for libnetfilter_cthelper
+ * low-level netlink functions 
  */
 extern void nfct_build_tuple(struct nfnlhdr *req, int size, 
 			     struct nfct_tuple *t, int type);
 
+extern void nfct_build_snat(struct nfnlhdr *req, int size,
+			    struct nfct_conntrack *ct);
 
+extern void nfct_build_dnat(struct nfnlhdr *req, int size,
+			    struct nfct_conntrack *ct); 
 
+extern void nfct_build_protoinfo(struct nfnlhdr *req, int size,
+				 struct nfct_conntrack *ct);
+
+extern void nfct_build_status(struct nfnlhdr *req, int size,
+			      struct nfct_conntrack *ct);
+
+extern void nfct_build_timeout(struct nfnlhdr *req, int size,
+			       struct nfct_conntrack *ct);
+
+extern void nfct_build_mark(struct nfnlhdr *req, int size,
+			    struct nfct_conntrack *ct);
+
+extern int nfct_build_netlink_message(const int msg_type,
+				      struct nfnl_subsys_handle *ssh, 
+				      struct nfct_conntrack *ct,
+				      void *buffer,
+				      unsigned int size);
+
+extern int nfct_parse_netlink_message(struct nfct_conntrack *ct,
+				      struct nlmsghdr *nlh,
+				      unsigned int *type,
+				      unsigned int *flags);
+
 #endif	/* _LIBNETFILTER_CONNTRACK_H_ */
Index: configure.in
===================================================================
--- configure.in	(revisión: 6652)
+++ configure.in	(copia de trabajo)
@@ -4,7 +4,7 @@
 
 AC_CANONICAL_SYSTEM
 
-AM_INIT_AUTOMAKE(libnetfilter_conntrack, 0.0.31)
+AM_INIT_AUTOMAKE(libnetfilter_conntrack, 0.0.40)
 
 AC_PROG_CC
 AM_PROG_LIBTOOL
Index: src/libnetfilter_conntrack.c
===================================================================
--- src/libnetfilter_conntrack.c	(revisión: 6652)
+++ src/libnetfilter_conntrack.c	(copia de trabajo)
@@ -222,8 +222,8 @@
 	nfnl_nest_end(&req->nlh, nest);
 }
 
-static void nfct_build_protoinfo(struct nfnlhdr *req, int size,
-				 struct nfct_conntrack *ct)
+void nfct_build_protoinfo(struct nfnlhdr *req, int size,
+			  struct nfct_conntrack *ct)
 {
 	struct nfattr *nest;
 	struct nfct_proto *h;
@@ -237,7 +237,8 @@
 }
 
 static void nfct_build_protonat(struct nfnlhdr *req, int size,
-				struct nfct_conntrack *ct)
+				struct nfct_conntrack *ct,
+				struct nfct_nat *nat)
 {
 	struct nfattr *nest;
 
@@ -262,26 +263,95 @@
 	nfnl_nest_end(&req->nlh, nest);
 }
 
-static void nfct_build_nat(struct nfnlhdr *req, int size,
-			   struct nfct_conntrack *ct)
+static void __nfct_build_nat(struct nfnlhdr *req,
+			     int size,
+			     struct nfct_nat *nat)
 {
-	struct nfattr *nest;
-
-	nest = nfnl_nest(&req->nlh, size, CTA_NAT);
-
 	nfnl_addattr_l(&req->nlh, size, CTA_NAT_MINIP,
-		       &ct->nat.min_ip, sizeof(u_int32_t));
+		       &nat->min_ip, sizeof(u_int32_t));
 	
-	if (ct->nat.min_ip != ct->nat.max_ip)
+	if (nat->min_ip != nat->max_ip)
 		nfnl_addattr_l(&req->nlh, size, CTA_NAT_MAXIP,
-			       &ct->nat.max_ip, sizeof(u_int32_t));
+			       &nat->max_ip, sizeof(u_int32_t));
+}
 
-	if (ct->nat.l4min.all != ct->nat.l4max.all)
-		nfct_build_protonat(req, size, ct);
+void nfct_build_snat(struct nfnlhdr *req, int size, struct nfct_conntrack *ct)
+{
+	struct nfattr *nest;
 
+	/* no NAT handling, skip */
+	if (ct->snat.min_ip == 0 || ct->snat.l4min.all == 0)
+		return;
+
+	nest = nfnl_nest(&req->nlh, size, CTA_NAT_SRC);
+
+	__nfct_build_nat(req, size, &ct->snat);
+
+	if (ct->snat.l4min.all != ct->snat.l4max.all)
+		nfct_build_protonat(req, size, ct, &ct->snat);
+
 	nfnl_nest_end(&req->nlh, nest);
 }
 
+void nfct_build_dnat(struct nfnlhdr *req, int size, struct nfct_conntrack *ct)
+{
+	struct nfattr *nest;
+
+	/* no NAT handling, skip */
+	if (ct->dnat.min_ip == 0 || ct->dnat.l4min.all == 0)
+		return;
+
+	nest = nfnl_nest(&req->nlh, size, CTA_NAT_SRC);
+
+	__nfct_build_nat(req, size, &ct->dnat);
+
+	if (ct->dnat.l4min.all != ct->dnat.l4max.all)
+		nfct_build_protonat(req, size, ct, &ct->dnat);
+
+	nfnl_nest_end(&req->nlh, nest);
+}
+
+void nfct_build_status(struct nfnlhdr *req,
+		       int size,
+		       struct nfct_conntrack *ct)
+{
+	if (ct->status == 0)
+		return;
+
+	nfnl_addattr32(&req->nlh, size, CTA_STATUS,
+		       htonl(ct->status | IPS_CONFIRMED));
+}
+
+void nfct_build_timeout(struct nfnlhdr *req,
+			int size,
+			struct nfct_conntrack *ct)
+{
+	if (ct->timeout == 0)
+		return;
+
+	nfnl_addattr32(&req->nlh, size, CTA_TIMEOUT, htonl(ct->timeout));
+}
+
+void nfct_build_mark(struct nfnlhdr *req,
+		     int size,
+		     struct nfct_conntrack *ct)
+{
+	if (ct->mark == 0)
+		return;
+	
+	nfnl_addattr32(&req->nlh, size, CTA_MARK, htonl(ct->mark));
+}
+
+void nfct_build_id(struct nfnlhdr *req,
+		   int size,
+		   struct nfct_conntrack *ct)
+{
+	if (ct->id == 0)
+		return;
+
+	nfnl_addattr32(&req->nlh, size, CTA_ID, htonl(ct->id));
+}
+
 void nfct_dump_tuple(struct nfct_tuple *tp)
 {
 	struct in_addr src = { .s_addr = tp->src.v4 };
@@ -489,8 +559,10 @@
 
 static char *msgtype[] = {"[UNKNOWN]", "[NEW]", "[UPDATE]", "[DESTROY]"};
 
-static int typemsg2enum(u_int16_t type, u_int16_t flags)
+static int typemsg2enum(struct nlmsghdr *nlh)
 {
+	u_int16_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
+	u_int16_t flags = nlh->nlmsg_flags;
 	int ret = NFCT_MSG_UNKNOWN;
 
 	if (type == IPCTNL_MSG_CT_NEW) {
@@ -504,13 +576,64 @@
 	return ret;
 }
 
-static int nfct_conntrack_netlink_handler(struct nfct_handle *cth, 
-					  struct nlmsghdr *nlh, void *arg)
+int nfct_conntrack_is_snatted(const struct nfct_conntrack *ct)
 {
-	struct nfct_conntrack ct;
-	unsigned int flags = 0;
+	return (ct->status & IPS_SRC_NAT_DONE) &&
+	       (ct->tuple[NFCT_DIR_REPLY].dst.v4 !=
+		ct->tuple[NFCT_DIR_ORIGINAL].src.v4);
+}
+
+int nfct_conntrack_is_dnatted(const struct nfct_conntrack *ct)
+{
+	return (ct->status & IPS_DST_NAT_DONE) &&
+	       (ct->tuple[NFCT_DIR_REPLY].src.v4 !=
+		ct->tuple[NFCT_DIR_ORIGINAL].dst.v4);
+}
+
+int nfct_conntrack_is_redirected(const struct nfct_conntrack *ct)
+{
+	return (ct->status & IPS_DST_NAT_DONE) &&
+	       (ct->tuple[NFCT_DIR_ORIGINAL].l4dst.tcp.port !=
+	        ct->tuple[NFCT_DIR_REPLY].l4src.tcp.port);
+}
+
+void nfct_conntrack_strip_nat(const struct nfct_conntrack *ct,
+			      struct nfct_conntrack *strip_ct)
+{
+	memcpy(strip_ct, ct, sizeof(struct nfct_conntrack));
+	memset(&strip_ct->snat, 0, sizeof(struct nfct_nat));
+	memset(&strip_ct->dnat, 0, sizeof(struct nfct_nat));
+
+	if (nfct_conntrack_is_snatted(ct)) {
+		strip_ct->snat.min_ip = strip_ct->tuple[NFCT_DIR_REPLY].dst.v4;
+		strip_ct->snat.max_ip = strip_ct->snat.min_ip;
+		strip_ct->tuple[NFCT_DIR_REPLY].dst.v4 =
+			strip_ct->tuple[NFCT_DIR_ORIGINAL].src.v4;
+	} else if (nfct_conntrack_is_dnatted(ct)) {
+		/* This connection has been DNAT'ed */
+		strip_ct->dnat.min_ip = ct->tuple[NFCT_DIR_REPLY].src.v4;
+		strip_ct->dnat.max_ip = strip_ct->dnat.min_ip;
+		strip_ct->tuple[NFCT_DIR_REPLY].src.v4 =
+			ct->tuple[NFCT_DIR_ORIGINAL].dst.v4;
+		strip_ct->tuple[NFCT_DIR_REPLY].dst.v4 =
+			ct->tuple[NFCT_DIR_REPLY].src.v4;
+	} else if (nfct_conntrack_is_redirected(ct)) {
+		/* This connection has been DNAT'ed: Port redirection */
+		strip_ct->dnat.l4min.tcp.port =
+			ct->tuple[NFCT_DIR_REPLY].l4src.tcp.port;
+		strip_ct->dnat.l4max.tcp.port =
+			strip_ct->dnat.l4min.tcp.port;
+		strip_ct->tuple[NFCT_DIR_REPLY].l4src.tcp.port =
+			ct->tuple[NFCT_DIR_ORIGINAL].l4dst.tcp.port;
+	}
+}
+
+int nfct_parse_netlink_message(struct nfct_conntrack *ct,
+			       struct nlmsghdr *nlh,
+			       unsigned int *type,
+			       unsigned int *flags)
+{
 	struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
-	int type = NFNL_MSG_TYPE(nlh->nlmsg_type), ret = 0;
 	int len = nlh->nlmsg_len;
 	struct nfattr *cda[CTA_MAX];
 
@@ -518,66 +641,83 @@
 	if (len < 0)
 		return -EINVAL;
 
-	memset(&ct, 0, sizeof(struct nfct_conntrack));
+	*type = typemsg2enum(nlh);
+	*flags = 0;
 
-	ct.tuple[NFCT_DIR_ORIGINAL].l3protonum = nfhdr->nfgen_family;
-	ct.tuple[NFCT_DIR_REPLY].l3protonum = nfhdr->nfgen_family;
+	memset(ct, 0, sizeof(struct nfct_conntrack));
 
+	ct->tuple[NFCT_DIR_ORIGINAL].l3protonum = nfhdr->nfgen_family;
+	ct->tuple[NFCT_DIR_REPLY].l3protonum = nfhdr->nfgen_family;
+
 	nfnl_parse_attr(cda, CTA_MAX, NFA_DATA(nfhdr), len);
 
 	if (cda[CTA_TUPLE_ORIG-1])
 		parse_tuple(cda[CTA_TUPLE_ORIG-1], 
-			    &ct.tuple[NFCT_DIR_ORIGINAL]);
+			    &ct->tuple[NFCT_DIR_ORIGINAL]);
 	
 	if (cda[CTA_TUPLE_REPLY-1])
 		parse_tuple(cda[CTA_TUPLE_REPLY-1], 
-			    &ct.tuple[NFCT_DIR_REPLY]);
+			    &ct->tuple[NFCT_DIR_REPLY]);
 	
 	if (cda[CTA_STATUS-1]) {
-		ct.status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
-		flags |= NFCT_STATUS;
+		ct->status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
+		*flags |= NFCT_STATUS;
 	}
 
 	if (cda[CTA_PROTOINFO-1]) {
-		parse_protoinfo(cda[CTA_PROTOINFO-1], &ct);
-		flags |= NFCT_PROTOINFO;
+		parse_protoinfo(cda[CTA_PROTOINFO-1], ct);
+		*flags |= NFCT_PROTOINFO;
 	}
 
 	if (cda[CTA_TIMEOUT-1]) {
-		ct.timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
-		flags |= NFCT_TIMEOUT;
+		ct->timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
+		*flags |= NFCT_TIMEOUT;
 	}
 	
 	if (cda[CTA_MARK-1]) {
-		ct.mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
-		flags |= NFCT_MARK;
+		ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+		*flags |= NFCT_MARK;
 	}
 	
 	if (cda[CTA_COUNTERS_ORIG-1]) {
-		nfct_parse_counters(cda[CTA_COUNTERS_ORIG-1], &ct, 
+		nfct_parse_counters(cda[CTA_COUNTERS_ORIG-1], ct, 
 				    NFA_TYPE(cda[CTA_COUNTERS_ORIG-1])-1);
-		flags |= NFCT_COUNTERS_ORIG;
+		*flags |= NFCT_COUNTERS_ORIG;
 	}
 
 	if (cda[CTA_COUNTERS_REPLY-1]) {
-		nfct_parse_counters(cda[CTA_COUNTERS_REPLY-1], &ct, 
+		nfct_parse_counters(cda[CTA_COUNTERS_REPLY-1], ct, 
 				    NFA_TYPE(cda[CTA_COUNTERS_REPLY-1])-1);
-		flags |= NFCT_COUNTERS_RPLY;
+		*flags |= NFCT_COUNTERS_RPLY;
 	}
 
 	if (cda[CTA_USE-1]) {
-		ct.use = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_USE-1]));
-		flags |= NFCT_USE;
+		ct->use = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_USE-1]));
+		*flags |= NFCT_USE;
 	}
 
 	if (cda[CTA_ID-1]) {
-		ct.id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));
-		flags |= NFCT_ID;
+		ct->id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));
+		*flags |= NFCT_ID;
 	}
 
+	return 0;
+}
+
+static int nfct_conntrack_netlink_handler(struct nfct_handle *cth, 
+					  struct nlmsghdr *nlh, void *arg)
+{
+	struct nfct_conntrack ct;
+	unsigned int flags, type;
+	int ret = 0;
+
+	if (nfct_parse_netlink_message(&ct, nlh, &type, &flags) < 0)
+		return -EINVAL;
+
 	if (cth->callback)
-		ret = cth->callback((void *) &ct, flags,
-				    typemsg2enum(type, nlh->nlmsg_flags),
+		ret = cth->callback((void *) &ct,
+				    flags,
+				    type,
 				    cth->callback_data);
 
 	return ret;
@@ -829,7 +969,7 @@
 {
 	struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
 	struct nfct_expect exp;
-	int type = NFNL_MSG_TYPE(nlh->nlmsg_type), ret = 0;
+	int ret = 0;
 	int len = nlh->nlmsg_len;
 	struct nfattr *cda[CTA_EXPECT_MAX];
 
@@ -859,12 +999,50 @@
 
 	if (cth->callback)
 		ret = cth->callback((void *)&exp, 0, 
-				    typemsg2enum(type, nlh->nlmsg_flags),
+				    typemsg2enum(nlh),
 				    cth->callback_data);
 
 	return 0;
 }
 
+struct nfct_conntrack *nfct_conntrack_new()
+{
+	struct nfct_conntrack *ct;
+
+	ct = malloc(sizeof(struct nfct_conntrack));
+	if (!ct)
+		return NULL;
+	memset(ct, 0, sizeof(struct nfct_conntrack));
+
+	return ct;
+}
+
+int nfct_nat_setup(unsigned int type,
+		   struct nfct_conntrack *ct,
+		   const char *data)
+{
+	int ret = 0;
+
+	switch(type) {
+	case NFCT_NAT_SRC:
+		ret = inet_aton(data, (struct in_addr *) &ct->snat.min_ip);
+		break;
+	case NFCT_NAT_DST:
+		ret = inet_aton(data, (struct in_addr *) &ct->dnat.min_ip);
+		break;
+	case NFCT_NAT_PORT_SRC:
+		ct->snat.l4min.all = htons(atoi(data));
+		break;
+	case NFCT_NAT_PORT_DST:
+		ct->dnat.l4min.all = htons(atoi(data));
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+	return ret;
+}
+
 struct nfct_conntrack *
 nfct_conntrack_alloc(struct nfct_tuple *orig, struct nfct_tuple *reply,
 		     u_int32_t timeout, union nfct_protoinfo *proto,
@@ -873,10 +1051,9 @@
 {
 	struct nfct_conntrack *ct;
 
-	ct = malloc(sizeof(struct nfct_conntrack));
+	ct = nfct_conntrack_new();
 	if (!ct)
 		return NULL;
-	memset(ct, 0, sizeof(struct nfct_conntrack));
 
 	ct->tuple[NFCT_DIR_ORIGINAL] = *orig;
 	ct->tuple[NFCT_DIR_REPLY] = *reply;
@@ -886,8 +1063,15 @@
 	ct->mark = mark;
 	if (id != NFCT_ANY_ID)
 		ct->id = id;
-	if (range)
-		ct->nat = *range;
+	if (range) {
+		/*
+		 * This is hack <SIGH>, just to keep backward compatibility
+		 */
+		if (status & IPS_SRC_NAT || status & IPS_SRC_NAT_DONE)
+			ct->snat = *range;
+		else if (status & IPS_DST_NAT_DONE || status & IPS_DST_NAT_DONE)
+			ct->dnat = *range;
+	}
 
 	return ct;
 }
@@ -897,6 +1081,40 @@
 	free(ct);
 }
 
+int nfct_tuple_src_equal(const struct nfct_tuple *t1,
+			 const struct nfct_tuple *t2)
+{
+	return (t1->src.v6[0] == t2->src.v6[0] &&
+		t1->src.v6[1] == t2->src.v6[1] &&
+		t1->src.v6[2] == t2->src.v6[2] &&
+		t1->src.v6[3] == t2->src.v6[3]);
+}
+
+int nfct_tuple_dst_equal(const struct nfct_tuple *t1,
+			 const struct nfct_tuple *t2)
+{
+	return (t1->dst.v6[0] == t2->dst.v6[0] &&
+		t1->src.v6[1] == t2->dst.v6[1] &&
+		t1->dst.v6[2] == t2->dst.v6[2] &&
+		t1->dst.v6[3] == t2->dst.v6[3]);
+}
+
+int nfct_tuple_proto_equal(const struct nfct_tuple *t1,
+			   const struct nfct_tuple *t2)
+{
+	return (t1->l3protonum == t2->l3protonum &&
+		t1->protonum == t2->protonum &&
+		t1->l4src.all == t2->l4src.all &&
+		t1->l4dst.all == t2->l4dst.all);
+}
+
+int nfct_tuple_equal(const struct nfct_tuple *t1,
+		     const struct nfct_tuple *t2)
+{
+	return (nfct_tuple_src_equal(t1, t2) && nfct_tuple_dst_equal(t1, t2)
+		&& nfct_tuple_proto_equal(t1, t2));
+}
+
 #define L3PROTONUM(ct) ct->tuple[NFCT_DIR_ORIGINAL].l3protonum
 #define L4PROTONUM(ct) ct->tuple[NFCT_DIR_ORIGINAL].protonum
 
@@ -948,110 +1166,120 @@
 	return 1;
 }
 
-int nfct_create_conntrack(struct nfct_handle *cth, struct nfct_conntrack *ct)
+static void __build_create_conntrack(struct nfnl_subsys_handle *ssh,
+				     struct nfnlhdr *req,
+				     int size,
+				     struct nfct_conntrack *ct)
 {
-	struct nfnlhdr *req;
-	char buf[NFCT_BUFSIZE];
-	u_int32_t status = htonl(ct->status | IPS_CONFIRMED);
-	u_int32_t timeout = htonl(ct->timeout);
-	u_int32_t mark = htonl(ct->mark);
 	u_int8_t l3num = ct->tuple[NFCT_DIR_ORIGINAL].l3protonum;
 
-	req = (void *) buf;
+	memset(req, 0, size);
 
-	memset(buf, 0, sizeof(buf));
-	
-	nfnl_fill_hdr(cth->nfnlssh_ct, &req->nlh, 0, l3num, 0, 
+	nfnl_fill_hdr(ssh, &req->nlh, 0, l3num, 0, 
 		      IPCTNL_MSG_CT_NEW,
 		      NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|NLM_F_EXCL);
 
-	nfct_build_tuple(req, sizeof(buf), &ct->tuple[NFCT_DIR_ORIGINAL], 
+	nfct_build_tuple(req, size, &ct->tuple[NFCT_DIR_ORIGINAL], 
 				 CTA_TUPLE_ORIG);
-	nfct_build_tuple(req, sizeof(buf), &ct->tuple[NFCT_DIR_REPLY],
+	nfct_build_tuple(req, size, &ct->tuple[NFCT_DIR_REPLY],
 				 CTA_TUPLE_REPLY);
 
-	nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_STATUS, &status, 
-		       sizeof(u_int32_t));
+	nfct_build_status(req, size, ct);
+	nfct_build_timeout(req, size, ct);
+	nfct_build_mark(req, size, ct);
+	nfct_build_protoinfo(req, size, ct);
+	nfct_build_snat(req, size, ct);
+	nfct_build_dnat(req, size, ct);
+}
 
-	nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_TIMEOUT, &timeout, 
-		       sizeof(u_int32_t));
-	
-	if (ct->mark != 0)
-		nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_MARK, &mark,
-			       sizeof(u_int32_t));
+int nfct_create_conntrack(struct nfct_handle *cth, struct nfct_conntrack *ct)
+{
+	char buf[NFCT_BUFSIZE];
+	struct nfnlhdr *req = (void *) buf;
 
-	nfct_build_protoinfo(req, sizeof(buf), ct);
-	if (ct->nat.min_ip != 0)
-		nfct_build_nat(req, sizeof(buf), ct);
+	__build_create_conntrack(cth->nfnlssh_ct, req, sizeof(buf), ct);
 
 	return nfnl_talk(cth->nfnlh, &req->nlh, 0, 0, NULL, NULL, NULL);
 }
 
-int nfct_update_conntrack(struct nfct_handle *cth, struct nfct_conntrack *ct)
+static void __build_update_conntrack(struct nfnl_subsys_handle *ssh,
+				     struct nfnlhdr *req,
+				     int size,
+				     struct nfct_conntrack *ct)
 {
-	struct nfnlhdr *req;
-	char buf[NFCT_BUFSIZE];
-	u_int32_t status = htonl(ct->status | IPS_CONFIRMED);
-	u_int32_t timeout = htonl(ct->timeout);
-	u_int32_t id = htonl(ct->id);
-	u_int32_t mark = htonl(ct->mark);
 	u_int8_t l3num = ct->tuple[NFCT_DIR_ORIGINAL].l3protonum;
 
-	req = (void *) &buf;
-	memset(&buf, 0, sizeof(buf));
+	memset(req, 0, size);
 
-	nfnl_fill_hdr(cth->nfnlssh_ct, &req->nlh, 0, l3num, 0, 
+	nfnl_fill_hdr(ssh, &req->nlh, 0, l3num, 0, 
 		      IPCTNL_MSG_CT_NEW, NLM_F_REQUEST|NLM_F_ACK);	
 
-	nfct_build_tuple(req, sizeof(buf), &ct->tuple[NFCT_DIR_ORIGINAL], 
-				 CTA_TUPLE_ORIG);
-	nfct_build_tuple(req, sizeof(buf), &ct->tuple[NFCT_DIR_REPLY],
-				 CTA_TUPLE_REPLY);
+	nfct_build_tuple(req, size, &ct->tuple[NFCT_DIR_ORIGINAL], 
+			 CTA_TUPLE_ORIG);
+	nfct_build_tuple(req, size, &ct->tuple[NFCT_DIR_REPLY],
+			 CTA_TUPLE_REPLY);
 
-	if (ct->status != 0)
-		nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_STATUS, &status, 
-			       sizeof(u_int32_t));
+	nfct_build_status(req, size, ct);
+	nfct_build_timeout(req, size, ct);
+	nfct_build_mark(req, size, ct);
+	nfct_build_id(req, size, ct);
+	nfct_build_protoinfo(req, size, ct);
+}
 
-	if (ct->timeout != 0)
-		nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_TIMEOUT, &timeout, 
-			       sizeof(u_int32_t));
-	
-	if (ct->mark != 0)
-		nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_MARK, &mark,
-			       sizeof(u_int32_t));
+int nfct_update_conntrack(struct nfct_handle *cth, struct nfct_conntrack *ct)
+{
+	char buf[NFCT_BUFSIZE];
+	struct nfnlhdr *req = (void *) buf;
 
-	if (ct->id != NFCT_ANY_ID)
-		nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_ID, &id, 
-			       sizeof(u_int32_t));
+	__build_update_conntrack(cth->nfnlssh_ct, req, sizeof(buf), ct);
 
-	nfct_build_protoinfo(req, sizeof(buf), ct);
-
 	return nfnl_talk(cth->nfnlh, &req->nlh, 0, 0, NULL, NULL, NULL);
 }
 
-int nfct_delete_conntrack(struct nfct_handle *cth, struct nfct_tuple *tuple, 
-			  int dir, u_int32_t id)
+static void __build_delete_conntrack(struct nfnl_subsys_handle *ssh,
+				     struct nfnlhdr *req,
+				     int size,
+				     struct nfct_conntrack *ct)
 {
-	struct nfnlhdr *req;
-	char buf[NFCT_BUFSIZE];
-	int type = dir ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG;
-	 u_int8_t l3num = tuple->l3protonum;
+	u_int8_t l3num = ct->tuple[NFCT_DIR_ORIGINAL].l3protonum;
+	struct nfct_tuple zero;
 
-	req = (void *) &buf;
-	memset(&buf, 0, sizeof(buf));
+	memset(req, 0, size);
+	memset(&zero, 0, sizeof(struct nfct_tuple));
 
-	nfnl_fill_hdr(cth->nfnlssh_ct, &req->nlh, 0, 
+	nfnl_fill_hdr(ssh, &req->nlh, 0, 
 		      l3num, 0, IPCTNL_MSG_CT_DELETE, 
 		      NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK);
 
-	nfct_build_tuple(req, sizeof(buf), tuple, type);
-
-	if (id != NFCT_ANY_ID) {
-		id = htonl(id); /* to network byte order */
-		nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_ID, &id, 
-			       sizeof(u_int32_t));
+	if (!nfct_tuple_equal(&zero, &ct->tuple[NFCT_DIR_ORIGINAL])) {
+		nfct_build_tuple(req,
+				 size,
+				 &ct->tuple[NFCT_DIR_ORIGINAL],
+				 CTA_TUPLE_ORIG);
+	} else if (!nfct_tuple_equal(&zero, &ct->tuple[NFCT_DIR_REPLY])) {
+		nfct_build_tuple(req,
+				 size,
+				 &ct->tuple[NFCT_DIR_REPLY],
+				 CTA_TUPLE_REPLY);
 	}
 
+	if (ct->id != NFCT_ANY_ID)
+		nfnl_addattr32(&req->nlh, size, CTA_ID, htonl(ct->id));
+}
+
+int nfct_delete_conntrack(struct nfct_handle *cth, struct nfct_tuple *tuple, 
+			  int dir, u_int32_t id)
+{
+	char buf[NFCT_BUFSIZE];
+	struct nfnlhdr *req = (void *) buf;
+	struct nfct_conntrack ct;
+
+	memset(&ct, 0, sizeof(struct nfct_conntrack));
+	ct.tuple[dir] = *tuple;
+	ct.id = id;
+
+	__build_delete_conntrack(cth->nfnlssh_ct, req, sizeof(buf), &ct);
+
 	return nfnl_talk(cth->nfnlh, &req->nlh, 0, 0, NULL, NULL, NULL);
 }
 
@@ -1123,6 +1351,33 @@
 	return(__nfct_dump_conntrack_table(cth, 1, family));
 }
 
+int nfct_build_netlink_message(const int msg_type,
+			       struct nfnl_subsys_handle *ssh,
+			       struct nfct_conntrack *ct,
+			       void *buffer,
+			       unsigned int size)
+{
+	struct nfnlhdr *req = buffer;
+
+	memset(req, 0, size);
+
+	switch(msg_type) {
+	case NFCT_MSG_NEW:
+		__build_create_conntrack(ssh, req, size, ct);
+		break;
+	case NFCT_MSG_UPDATE:
+		__build_update_conntrack(ssh, req, size, ct);
+		break;
+	case NFCT_MSG_DESTROY:
+		__build_delete_conntrack(ssh, req, size, ct);
+		break;
+	default:
+		return -1;
+	}
+
+	return req->nlh.nlmsg_len;
+}
+
 int nfct_event_conntrack(struct nfct_handle *cth)
 {
 	/*

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2006-07-29 10:51 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-27 10:53 libnfnetlink_conntrack encapsulation issues Amin Azez
2006-07-27 11:04 ` aggg " Amin Azez
2006-07-27 14:00   ` Patrick McHardy
     [not found]     ` <44C8CC58.1080909@ufomechanic.net>
2006-07-27 14:32       ` Patrick McHardy
2006-07-27 14:43         ` Amin Azez
2006-07-27 14:59           ` Patrick McHardy
2006-07-27 15:16             ` Amin Azez
2006-07-29  2:11               ` Patrick McHardy
2006-07-28 15:38 ` Pablo Neira Ayuso
2006-07-28 21:13   ` Amin Azez
2006-07-29 10:51   ` Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.