From c3704c0e73d0dda9d9d5919af22831a439fbc611 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 13 Apr 2008 00:38:09 +0000 Subject: - add nfct_cmp (replacement for nfct_compare a bit more flexible) - add nfct_copy - conditional build of original and reply tuples - fix secmark parsing --- configure.in | 2 +- include/internal.h | 2 +- .../libnetfilter_conntrack.h | 22 ++++ src/conntrack/Makefile.am | 3 +- src/conntrack/api.c | 67 +++++++++- src/conntrack/build.c | 31 ++++- src/conntrack/compare.c | 146 +++++++++++++-------- src/conntrack/copy.c | 57 ++++++++ src/conntrack/parse.c | 2 +- 9 files changed, 267 insertions(+), 65 deletions(-) create mode 100644 src/conntrack/copy.c diff --git a/configure.in b/configure.in index 481b6b0..64f2dc9 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(libnetfilter_conntrack, 0.0.90) +AM_INIT_AUTOMAKE(libnetfilter_conntrack, 0.0.91) AC_PROG_CC AM_PROG_LIBTOOL diff --git a/include/internal.h b/include/internal.h index 0c369aa..f38b7d3 100644 --- a/include/internal.h +++ b/include/internal.h @@ -199,7 +199,7 @@ int __callback(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data); int __setobjopt(struct nf_conntrack *ct, unsigned int option); int __getobjopt(const struct nf_conntrack *ct, unsigned int option); -int __compare(const struct nf_conntrack *ct1, const struct nf_conntrack *ct2); +int __compare(const struct nf_conntrack *ct1, const struct nf_conntrack *ct2, unsigned int flags); typedef void (*set_exp_attr)(struct nf_expect *exp, const void *value); typedef const void *(*get_exp_attr)(const struct nf_expect *exp); diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h index 644806d..e366061 100644 --- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h +++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h @@ -260,9 +260,21 @@ extern int nfct_snprintf(char *buf, const unsigned int out_type, const unsigned int out_flags); +/* comparison */ extern int nfct_compare(const struct nf_conntrack *ct1, const struct nf_conntrack *ct2); +enum { + NFCT_CMP_ALL = 0, + NFCT_CMP_ORIG = (1 << 0), + NFCT_CMP_REPL = (1 << 1), +}; + +extern int nfct_cmp(const struct nf_conntrack *ct1, + const struct nf_conntrack *ct2, + unsigned int flags); + + /* query */ enum nf_conntrack_query { NFCT_Q_CREATE, @@ -285,6 +297,16 @@ extern int nfct_send(struct nfct_handle *h, extern int nfct_catch(struct nfct_handle *h); +/* copy */ +enum { + NFCT_CP_ORIG = (1 << 0), + NFCT_CP_REPL = (1 << 1) +}; + +extern void nfct_copy(struct nf_conntrack *dest, + const struct nf_conntrack *source, + unsigned int flags); + /* low level API: netlink functions */ extern int nfct_build_conntrack(struct nfnl_subsys_handle *ssh, diff --git a/src/conntrack/Makefile.am b/src/conntrack/Makefile.am index e37c3eb..6440dd7 100644 --- a/src/conntrack/Makefile.am +++ b/src/conntrack/Makefile.am @@ -11,4 +11,5 @@ libnfconntrack_la_SOURCES = api.c callback.c \ snprintf.c \ snprintf_default.c snprintf_xml.c \ objopt.c \ - compare.c + compare.c \ + copy.c diff --git a/src/conntrack/api.c b/src/conntrack/api.c index 04f78ed..bd6a154 100644 --- a/src/conntrack/api.c +++ b/src/conntrack/api.c @@ -671,6 +671,8 @@ int nfct_snprintf(char *buf, * * If both conntrack object are equal, this function returns 1, otherwise * 0 is returned. + * + * NOTICE: The use nfct_cmp is preferred. */ int nfct_compare(const struct nf_conntrack *ct1, const struct nf_conntrack *ct2) @@ -678,5 +680,68 @@ int nfct_compare(const struct nf_conntrack *ct1, assert(ct1 != NULL); assert(ct2 != NULL); - return __compare(ct1, ct2); + return __compare(ct1, ct2, NFCT_CMP_ALL); +} + +/** + * nfct_cmp - compare two conntrack objects + * @ct1: pointer to a valid conntrack object + * @ct2: pointer to a valid conntrack object + * @flags: flags + * + * This function only compare attribute set in both objects, ie. if a certain + * attribute is not set in ct1 but it is in ct2, then the value of such + * attribute is not used in the comparison. + * + * The available flags are: + * + * - NFCT_CMP_ALL: full comparison of both objects + * - NFCT_CMP_ORIG: it only compares the source and destination address; + * source and destination ports; and the layer 3 and 4 protocol numbers + * of the original direction. + * - NFCT_CMP_REPL: like NFCT_CMP_REPL but it compares the flow + * information that goes in the reply direction. + * + * If both conntrack object are equal, this function returns 1, otherwise + * 0 is returned. + */ +int nfct_cmp(const struct nf_conntrack *ct1, + const struct nf_conntrack *ct2, + unsigned int flags) +{ + assert(ct1 != NULL); + assert(ct2 != NULL); + + return __compare(ct1, ct2, flags); +} + +/** + * nfct_copy - copy part of one source object to another + * @ct1: destination object + * @ct2: source object + * @flags: flags + * + * This function copies one part of the source object to the target. + * It behaves like clone but: + * + * 1) You have to pass an already allocated space for the target object + * 2) You can copy only a part of the source object to the target + * + * The current supported flags are NFCT_CP_ORIG and NFCT_CP_REPL that + * can be used to copy the information that identifies a flow in the + * original and the reply direction. This information is usually composed + * of: source and destination IP address; source and destination ports; + * layer 3 and 4 protocol number. + */ +void nfct_copy(struct nf_conntrack *ct1, + const struct nf_conntrack *ct2, + unsigned int flags) +{ + assert(ct1 != NULL); + assert(ct2 != NULL); + + if (flags & NFCT_CP_ORIG) + __copy_tuple(ct1, ct2, __DIR_ORIG); + if (flags & NFCT_CP_REPL) + __copy_tuple(ct1, ct2, __DIR_REPL); } diff --git a/src/conntrack/build.c b/src/conntrack/build.c index cf65ef3..638fbe2 100644 --- a/src/conntrack/build.c +++ b/src/conntrack/build.c @@ -307,8 +307,35 @@ int __build_conntrack(struct nfnl_subsys_handle *ssh, nfnl_fill_hdr(ssh, &req->nlh, 0, l3num, 0, type, flags); - __build_tuple(req, size, &ct->tuple[__DIR_ORIG], CTA_TUPLE_ORIG); - __build_tuple(req, size, &ct->tuple[__DIR_REPL], CTA_TUPLE_REPLY); + if (test_bit(ATTR_ORIG_IPV4_SRC, ct->set) || + test_bit(ATTR_ORIG_IPV4_DST, ct->set) || + test_bit(ATTR_ORIG_IPV6_SRC, ct->set) || + test_bit(ATTR_ORIG_IPV6_DST, ct->set) || + test_bit(ATTR_ORIG_PORT_SRC, ct->set) || + test_bit(ATTR_ORIG_PORT_DST, ct->set) || + test_bit(ATTR_ORIG_L3PROTO, ct->set) || + test_bit(ATTR_ORIG_L4PROTO, ct->set) || + test_bit(ATTR_ICMP_TYPE, ct->set) || + test_bit(ATTR_ICMP_CODE, ct->set) || + test_bit(ATTR_ICMP_ID, ct->set)) + __build_tuple(req, size, + &ct->tuple[__DIR_ORIG], + CTA_TUPLE_ORIG); + + if (test_bit(ATTR_REPL_IPV4_SRC, ct->set) || + test_bit(ATTR_REPL_IPV4_DST, ct->set) || + test_bit(ATTR_REPL_IPV6_SRC, ct->set) || + test_bit(ATTR_REPL_IPV6_DST, ct->set) || + test_bit(ATTR_REPL_PORT_SRC, ct->set) || + test_bit(ATTR_REPL_PORT_DST, ct->set) || + test_bit(ATTR_REPL_L3PROTO, ct->set) || + test_bit(ATTR_REPL_L4PROTO, ct->set) || + test_bit(ATTR_ICMP_TYPE, ct->set) || + test_bit(ATTR_ICMP_CODE, ct->set) || + test_bit(ATTR_ICMP_ID, ct->set)) + __build_tuple(req, size, + &ct->tuple[__DIR_REPL], + CTA_TUPLE_REPLY); if (test_bit(ATTR_MASTER_IPV4_SRC, ct->set) || test_bit(ATTR_MASTER_IPV4_DST, ct->set) || diff --git a/src/conntrack/compare.c b/src/conntrack/compare.c index a5c66e2..0280638 100644 --- a/src/conntrack/compare.c +++ b/src/conntrack/compare.c @@ -7,28 +7,34 @@ #include "internal.h" -int __compare(const struct nf_conntrack *ct1, - const struct nf_conntrack *ct2) +static int cmp_orig(const struct nf_conntrack *ct1, + const struct nf_conntrack *ct2) { - if (test_bit(ATTR_MARK, ct1->set) && - test_bit(ATTR_MARK, ct2->set) && - ct1->mark != ct2->mark) - return 0; + if (test_bit(ATTR_ORIG_IPV4_SRC, ct1->set) && + test_bit(ATTR_ORIG_IPV4_SRC, ct2->set) && + ct1->tuple[__DIR_ORIG].src.v4 != + ct2->tuple[__DIR_ORIG].src.v4) + return 0; - if (test_bit(ATTR_TIMEOUT, ct1->set) && - test_bit(ATTR_TIMEOUT, ct2->set) && - ct1->timeout != ct2->timeout) - return 0; + if (test_bit(ATTR_ORIG_IPV4_DST, ct1->set) && + test_bit(ATTR_ORIG_IPV4_DST, ct2->set) && + ct1->tuple[__DIR_ORIG].dst.v4 != + ct2->tuple[__DIR_ORIG].dst.v4) + return 0; - if (test_bit(ATTR_STATUS, ct1->set) && - test_bit(ATTR_STATUS, ct2->set) && - ct1->status == ct2->status) - return 0; + if (test_bit(ATTR_ORIG_IPV6_SRC, ct1->set) && + test_bit(ATTR_ORIG_IPV6_SRC, ct2->set) && + memcmp(&ct1->tuple[__DIR_ORIG].src.v6, + &ct2->tuple[__DIR_ORIG].src.v6, + sizeof(u_int32_t)*4) == 0) + return 0; - if (test_bit(ATTR_TCP_STATE, ct1->set) && - test_bit(ATTR_TCP_STATE, ct2->set) && - ct1->protoinfo.tcp.state != ct2->protoinfo.tcp.state) - return 0; + if (test_bit(ATTR_ORIG_IPV6_DST, ct1->set) && + test_bit(ATTR_ORIG_IPV6_DST, ct2->set) && + memcmp(&ct1->tuple[__DIR_ORIG].dst.v6, + &ct2->tuple[__DIR_ORIG].dst.v6, + sizeof(u_int32_t)*4) == 0) + return 0; if (test_bit(ATTR_ORIG_L3PROTO, ct1->set) && test_bit(ATTR_ORIG_L3PROTO, ct2->set) && @@ -36,15 +42,7 @@ int __compare(const struct nf_conntrack *ct1, ct2->tuple[__DIR_ORIG].l3protonum != AF_UNSPEC && ct1->tuple[__DIR_ORIG].l3protonum != ct2->tuple[__DIR_ORIG].l3protonum) - return 0; - - if (test_bit(ATTR_REPL_L3PROTO, ct1->set) && - test_bit(ATTR_REPL_L3PROTO, ct2->set) && - ct1->tuple[__DIR_REPL].l3protonum != AF_UNSPEC && - ct2->tuple[__DIR_REPL].l3protonum != AF_UNSPEC && - ct1->tuple[__DIR_REPL].l3protonum != - ct2->tuple[__DIR_REPL].l3protonum) - return 0; + return 0; if (test_bit(ATTR_ORIG_L4PROTO, ct1->set) && test_bit(ATTR_ORIG_L4PROTO, ct2->set) && @@ -52,24 +50,12 @@ int __compare(const struct nf_conntrack *ct1, ct2->tuple[__DIR_ORIG].protonum) return 0; - if (test_bit(ATTR_REPL_L4PROTO, ct1->set) && - test_bit(ATTR_REPL_L4PROTO, ct2->set) && - ct1->tuple[__DIR_REPL].protonum != - ct2->tuple[__DIR_REPL].protonum) - return 0; - - if (test_bit(ATTR_ORIG_IPV4_SRC, ct1->set) && - test_bit(ATTR_ORIG_IPV4_SRC, ct2->set) && - ct1->tuple[__DIR_ORIG].src.v4 != - ct2->tuple[__DIR_ORIG].src.v4) - return 0; - - if (test_bit(ATTR_ORIG_IPV4_DST, ct1->set) && - test_bit(ATTR_ORIG_IPV4_DST, ct2->set) && - ct1->tuple[__DIR_ORIG].dst.v4 != - ct2->tuple[__DIR_ORIG].dst.v4) - return 0; + return 1; +} +static int cmp_repl(const struct nf_conntrack *ct1, + const struct nf_conntrack *ct2) +{ if (test_bit(ATTR_REPL_IPV4_SRC, ct1->set) && test_bit(ATTR_REPL_IPV4_SRC, ct2->set) && ct1->tuple[__DIR_REPL].src.v4 != @@ -82,20 +68,6 @@ int __compare(const struct nf_conntrack *ct1, ct2->tuple[__DIR_REPL].dst.v4) return 0; - if (test_bit(ATTR_ORIG_IPV6_SRC, ct1->set) && - test_bit(ATTR_ORIG_IPV6_SRC, ct2->set) && - memcmp(&ct1->tuple[__DIR_ORIG].src.v6, - &ct2->tuple[__DIR_ORIG].src.v6, - sizeof(u_int32_t)*4) == 0) - return 0; - - if (test_bit(ATTR_ORIG_IPV6_DST, ct1->set) && - test_bit(ATTR_ORIG_IPV6_DST, ct2->set) && - memcmp(&ct1->tuple[__DIR_ORIG].dst.v6, - &ct2->tuple[__DIR_ORIG].dst.v6, - sizeof(u_int32_t)*4) == 0) - return 0; - if (test_bit(ATTR_REPL_IPV6_SRC, ct1->set) && test_bit(ATTR_REPL_IPV6_SRC, ct2->set) && memcmp(&ct1->tuple[__DIR_REPL].src.v6, @@ -110,5 +82,63 @@ int __compare(const struct nf_conntrack *ct1, sizeof(u_int32_t)*4) == 0) return 0; + if (test_bit(ATTR_REPL_L3PROTO, ct1->set) && + test_bit(ATTR_REPL_L3PROTO, ct2->set) && + ct1->tuple[__DIR_REPL].l3protonum != AF_UNSPEC && + ct2->tuple[__DIR_REPL].l3protonum != AF_UNSPEC && + ct1->tuple[__DIR_REPL].l3protonum != + ct2->tuple[__DIR_REPL].l3protonum) + return 0; + + if (test_bit(ATTR_REPL_L4PROTO, ct1->set) && + test_bit(ATTR_REPL_L4PROTO, ct2->set) && + ct1->tuple[__DIR_REPL].protonum != + ct2->tuple[__DIR_REPL].protonum) + return 0; + + return 1; +} + +static int cmp_meta(const struct nf_conntrack *ct1, + const struct nf_conntrack *ct2) +{ + if (test_bit(ATTR_MARK, ct1->set) && + test_bit(ATTR_MARK, ct2->set) && + ct1->mark != ct2->mark) + return 0; + + if (test_bit(ATTR_TIMEOUT, ct1->set) && + test_bit(ATTR_TIMEOUT, ct2->set) && + ct1->timeout != ct2->timeout) + return 0; + + if (test_bit(ATTR_STATUS, ct1->set) && + test_bit(ATTR_STATUS, ct2->set) && + ct1->status == ct2->status) + return 0; + + if (test_bit(ATTR_TCP_STATE, ct1->set) && + test_bit(ATTR_TCP_STATE, ct2->set) && + ct1->protoinfo.tcp.state != ct2->protoinfo.tcp.state) + return 0; + + return 1; +} + +int __compare(const struct nf_conntrack *ct1, + const struct nf_conntrack *ct2, + unsigned int flags) +{ + if (flags == NFCT_CMP_ALL) + return cmp_orig(ct1, ct2) && + cmp_repl(ct1, ct2) && + cmp_meta(ct1, ct2); + + if (flags & NFCT_CMP_ORIG && !cmp_orig(ct1, ct2)) + return 0; + + if (flags & NFCT_CMP_REPL && !cmp_repl(ct1, ct2)) + return 0; + return 1; } diff --git a/src/conntrack/copy.c b/src/conntrack/copy.c new file mode 100644 index 0000000..e03abc8 --- /dev/null +++ b/src/conntrack/copy.c @@ -0,0 +1,57 @@ +/* + * (C) 2008 by Pablo Neira Ayuso + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + */ + +#include "internal.h" + +#define TS_ORIG \ +({ \ + ((1 << ATTR_ORIG_IPV4_SRC) | (1 << ATTR_ORIG_IPV4_DST) | \ + (1 << ATTR_ORIG_IPV6_SRC) | (1 << ATTR_ORIG_IPV6_DST) | \ + (1 << ATTR_ORIG_PORT_SRC) | (1 << ATTR_ORIG_PORT_DST) | \ + (1 << ATTR_ORIG_L3PROTO) | (1 << ATTR_ORIG_L4PROTO) | \ + (1 << ATTR_ICMP_TYPE) | (1 << ATTR_ICMP_CODE) | \ + (1 << ATTR_ICMP_ID)); \ +}) + +#define TS_REPL \ +({ \ + ((1 << ATTR_REPL_IPV4_SRC) | (1 << ATTR_REPL_IPV4_DST) | \ + (1 << ATTR_REPL_IPV6_SRC) | (1 << ATTR_REPL_IPV6_DST) | \ + (1 << ATTR_REPL_PORT_SRC) | (1 << ATTR_REPL_PORT_DST) | \ + (1 << ATTR_REPL_L3PROTO) | (1 << ATTR_REPL_L4PROTO) | \ + (1 << ATTR_ICMP_TYPE) | (1 << ATTR_ICMP_CODE) | \ + (1 << ATTR_ICMP_ID)); \ +}) + +#define TUPLE_SET(dir) (dir == __DIR_ORIG ? TS_ORIG : TS_REPL) + +void __copy_tuple(struct nf_conntrack *ct2, + const struct nf_conntrack *ct1, + int dir) +{ + memcpy(&ct2->tuple[dir].src, + &ct1->tuple[dir].src, + sizeof(union __nfct_address)); + + memcpy(&ct2->tuple[dir].dst, + &ct1->tuple[dir].dst, + sizeof(union __nfct_address)); + + ct2->tuple[dir].l3protonum = ct1->tuple[dir].l3protonum; + ct2->tuple[dir].protonum = ct1->tuple[dir].protonum; + + memcpy(&ct2->tuple[dir].l4src, + &ct1->tuple[dir].l4src, + sizeof(union __nfct_l4)); + + memcpy(&ct2->tuple[dir].l4dst, + &ct1->tuple[dir].l4dst, + sizeof(union __nfct_l4)); + + /* XXX: this is safe but better convert bitset to uint64_t */ + ct2->set[0] |= ct1->set[0] & TUPLE_SET(__DIR_ORIG); +} diff --git a/src/conntrack/parse.c b/src/conntrack/parse.c index e5e62c8..c21f304 100644 --- a/src/conntrack/parse.c +++ b/src/conntrack/parse.c @@ -394,7 +394,7 @@ void __parse_conntrack(const struct nlmsghdr *nlh, } if (cda[CTA_SECMARK-1]) { - ct->secmark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); + ct->secmark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_SECMARK-1])); set_bit(ATTR_SECMARK, ct->set); } -- cgit v1.2.3