From b4c3a23c884c24f4e5d941fb928cf49561a9cdf9 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org" Date: Tue, 19 Dec 2006 17:41:53 +0000 Subject: Introduce the new libnetfilter_conntrack API, features: - object oriented infrastructure - extensible and configurable output (XML) - low level functions to interact with netlink details - fairly documented Still backward compatible. --- src/conntrack/build.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 src/conntrack/build.c (limited to 'src/conntrack/build.c') diff --git a/src/conntrack/build.c b/src/conntrack/build.c new file mode 100644 index 0000000..e8d5276 --- /dev/null +++ b/src/conntrack/build.c @@ -0,0 +1,284 @@ +/* + * (C) 2006 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" + +void __build_tuple_ip(struct nfnlhdr *req, + size_t size, + const struct __nfct_tuple *t) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_IP); + + switch(t->l3protonum) { + case AF_INET: + nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_SRC, &t->src.v4, + sizeof(u_int32_t)); + nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_DST, &t->dst.v4, + sizeof(u_int32_t)); + break; + case AF_INET6: + nfnl_addattr_l(&req->nlh, size, CTA_IP_V6_SRC, &t->src.v6, + sizeof(struct in6_addr)); + nfnl_addattr_l(&req->nlh, size, CTA_IP_V6_DST, &t->dst.v6, + sizeof(struct in6_addr)); + break; + default: + break; + } + + nfnl_nest_end(&req->nlh, nest); +} + +void __build_tuple_proto(struct nfnlhdr *req, + size_t size, + const struct __nfct_tuple *t) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_PROTO); + + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_NUM, &t->protonum, + sizeof(u_int8_t)); + + switch(t->protonum) { + case IPPROTO_UDP: + case IPPROTO_TCP: + case IPPROTO_SCTP: + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_SRC_PORT, + &t->l4src.tcp.port, sizeof(u_int16_t)); + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_DST_PORT, + &t->l4dst.tcp.port, sizeof(u_int16_t)); + break; + case IPPROTO_ICMP: + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_CODE, + &t->l4dst.icmp.code, sizeof(u_int8_t)); + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_TYPE, + &t->l4dst.icmp.type, sizeof(u_int8_t)); + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_ID, + &t->l4src.icmp.id, sizeof(u_int16_t)); + break; + default: + break; + } + + nfnl_nest_end(&req->nlh, nest); +} + +void __build_tuple(struct nfnlhdr *req, + size_t size, + const struct __nfct_tuple *t, + const int type) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, type); + + __build_tuple_ip(req, size, t); + __build_tuple_proto(req, size, t); + + nfnl_nest_end(&req->nlh, nest); +} + +void __build_protoinfo(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + struct nfattr *nest, *nest_proto; + + switch(ct->tuple[__DIR_ORIG].protonum) { + case IPPROTO_TCP: + nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); + nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_TCP); + nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_STATE, + &ct->protoinfo.tcp.state, sizeof(u_int8_t)); + nfnl_nest_end(&req->nlh, nest_proto); + nfnl_nest_end(&req->nlh, nest); + break; + default: + break; + } +} + +void __build_protonat(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct, + const struct __nfct_nat *nat) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_PROTO); + + switch (ct->tuple[NFCT_DIR_ORIGINAL].protonum) { + case IPPROTO_TCP: + case IPPROTO_UDP: + nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_PORT_MIN, + &nat->l4min.tcp.port, sizeof(u_int16_t)); + nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_PORT_MAX, + &nat->l4max.tcp.port, sizeof(u_int16_t)); + break; + } + nfnl_nest_end(&req->nlh, nest); +} + +void __build_nat(struct nfnlhdr *req, + size_t size, + const struct __nfct_nat *nat) +{ + nfnl_addattr_l(&req->nlh, size, CTA_NAT_MINIP, + &nat->min_ip, sizeof(u_int32_t)); +} + +void __build_snat(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_SRC); + __build_nat(req, size, &ct->snat); + __build_protonat(req, size, ct, &ct->snat); + nfnl_nest_end(&req->nlh, nest); +} + +void __build_snat_ipv4(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_SRC); + __build_nat(req, size, &ct->snat); + nfnl_nest_end(&req->nlh, nest); +} + +void __build_snat_port(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_SRC); + __build_protonat(req, size, ct, &ct->snat); + nfnl_nest_end(&req->nlh, nest); +} + +void __build_dnat(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_DST); + __build_nat(req, size, &ct->dnat); + __build_protonat(req, size, ct, &ct->dnat); + nfnl_nest_end(&req->nlh, nest); +} + +void __build_dnat_ipv4(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_DST); + __build_nat(req, size, &ct->dnat); + nfnl_nest_end(&req->nlh, nest); +} + +void __build_dnat_port(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_DST); + __build_protonat(req, size, ct, &ct->dnat); + nfnl_nest_end(&req->nlh, nest); +} + +void __build_status(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + nfnl_addattr32(&req->nlh, size, CTA_STATUS, + htonl(ct->status | IPS_CONFIRMED)); +} + +void __build_timeout(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + nfnl_addattr32(&req->nlh, size, CTA_TIMEOUT, htonl(ct->timeout)); +} + +void __build_mark(struct nfnlhdr *req, + size_t size, + const struct nf_conntrack *ct) +{ + nfnl_addattr32(&req->nlh, size, CTA_MARK, htonl(ct->mark)); +} + +void __build_id(struct nfnlhdr *req, + size_t size, + const const struct nf_conntrack *ct) +{ + nfnl_addattr32(&req->nlh, size, CTA_ID, htonl(ct->id)); +} + +int __build_conntrack(struct nfnl_subsys_handle *ssh, + struct nfnlhdr *req, + size_t size, + u_int16_t type, + u_int16_t flags, + const struct nf_conntrack *ct) +{ + u_int8_t l3num = ct->tuple[NFCT_DIR_ORIGINAL].l3protonum; + + if (!test_bit(ATTR_ORIG_L3PROTO, ct->set)) { + errno = EINVAL; + return -1; + } + + memset(req, 0, size); + + 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); + + /* always build IPS_CONFIRMED */ + __build_status(req, size, ct); + + if (test_bit(ATTR_TIMEOUT, ct->set)) + __build_timeout(req, size, ct); + + if (test_bit(ATTR_MARK, ct->set)) + __build_mark(req, size, ct); + + if (test_bit(ATTR_TCP_STATE, ct->set)) + __build_protoinfo(req, size, ct); + + if (test_bit(ATTR_SNAT_IPV4, ct->set) && + test_bit(ATTR_SNAT_PORT, ct->set)) + __build_snat(req, size, ct); + else if (test_bit(ATTR_SNAT_IPV4, ct->set)) + __build_snat_ipv4(req, size, ct); + else if (test_bit(ATTR_SNAT_PORT, ct->set)) + __build_snat_port(req, size, ct); + + if (test_bit(ATTR_DNAT_IPV4, ct->set) && + test_bit(ATTR_DNAT_PORT, ct->set)) + __build_dnat(req, size, ct); + else if (test_bit(ATTR_DNAT_IPV4, ct->set)) + __build_dnat_ipv4(req, size, ct); + else if (test_bit(ATTR_DNAT_PORT, ct->set)) + __build_dnat_port(req, size, ct); + + return 0; +} -- cgit v1.2.3