From 3388d7df304f26617c4487418c05734ae4fce5b8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 28 Dec 2011 20:16:46 +0100 Subject: src: major API redesign This patch reworks the initial API. Now it provides functions to: - allocate/release accounting objects. - set/unset/get attributes of accounting objects. - build one netlink message from one accounting object. - parse one netlink message to one accounting object. - print one accounting object into a buffer. Binary layout of nfacct objects are opaque. This is good for extensibility without breaking backward compatibility. Signed-off-by: Pablo Neira Ayuso --- src/libnetfilter_acct.c | 257 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 179 insertions(+), 78 deletions(-) (limited to 'src/libnetfilter_acct.c') diff --git a/src/libnetfilter_acct.c b/src/libnetfilter_acct.c index 777c960..86d7b96 100644 --- a/src/libnetfilter_acct.c +++ b/src/libnetfilter_acct.c @@ -11,48 +11,159 @@ #include #include +#include +#include + #include #include #include #include -struct nlmsghdr *nfacct_add(char *buf, struct nfacct *nfacct) +struct nfacct { + char name[NFACCT_NAME_MAX]; + uint64_t pkts; + uint64_t bytes; + uint32_t bitset; +}; + +struct nfacct *nfacct_alloc(void) { - struct nlmsghdr *nlh; - struct nfgenmsg *nfh; + return calloc(1, sizeof(struct nfacct)); +} +EXPORT_SYMBOL(nfacct_alloc); - nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_NEW; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK; - nlh->nlmsg_seq = time(NULL); +void nfacct_free(struct nfacct *nfacct) +{ + free(nfacct); +} +EXPORT_SYMBOL(nfacct_free); - nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); - nfh->nfgen_family = AF_UNSPEC; - nfh->version = NFNETLINK_V0; - nfh->res_id = 0; +void +nfacct_attr_set(struct nfacct *nfacct, enum nfacct_attr_type type, + const void *data) +{ + switch(type) { + case NFACCT_ATTR_NAME: + strncpy(nfacct->name, data, NFACCT_NAME_MAX); + nfacct->name[NFACCT_NAME_MAX-1] = '\0'; + nfacct->bitset |= (1 << NFACCT_ATTR_NAME); + break; + case NFACCT_ATTR_PKTS: + nfacct->bytes = *((uint64_t *) data); + nfacct->bitset |= (1 << NFACCT_ATTR_PKTS); + break; + case NFACCT_ATTR_BYTES: + nfacct->pkts = *((uint64_t *) data); + nfacct->bitset |= (1 << NFACCT_ATTR_BYTES); + break; + } +} +EXPORT_SYMBOL(nfacct_attr_set); - mnl_attr_put_strz(nlh, NFACCT_NAME, nfacct->name); - mnl_attr_put_u64(nlh, NFACCT_PKTS, htobe64(nfacct->pkts)); - mnl_attr_put_u64(nlh, NFACCT_PKTS, htobe64(nfacct->bytes)); +void +nfacct_attr_set_str(struct nfacct *nfacct, enum nfacct_attr_type type, + const char *name) +{ + nfacct_attr_set(nfacct, type, name); +} +EXPORT_SYMBOL(nfacct_attr_set_str); - return nlh; +void +nfacct_attr_set_u64(struct nfacct *nfacct, enum nfacct_attr_type type, + uint64_t value) +{ + nfacct_attr_set(nfacct, type, &value); } -EXPORT_SYMBOL(nfacct_add); +EXPORT_SYMBOL(nfacct_attr_set_u64); -struct nlmsghdr *nfacct_list(char *buf, bool ctrzero) +void +nfacct_attr_unset(struct nfacct *nfacct, enum nfacct_attr_type type) +{ + switch(type) { + case NFACCT_ATTR_NAME: + nfacct->bitset &= ~(1 << NFACCT_ATTR_NAME); + break; + case NFACCT_ATTR_PKTS: + nfacct->bitset &= ~(1 << NFACCT_ATTR_PKTS); + break; + case NFACCT_ATTR_BYTES: + nfacct->bitset &= ~(1 << NFACCT_ATTR_BYTES); + break; + } +} +EXPORT_SYMBOL(nfacct_attr_unset); + +const void *nfacct_attr_get(struct nfacct *nfacct, enum nfacct_attr_type type) +{ + const void *ret = NULL; + + switch(type) { + case NFACCT_ATTR_NAME: + ret = nfacct->name; + break; + case NFACCT_ATTR_PKTS: + ret = &nfacct->pkts; + break; + case NFACCT_ATTR_BYTES: + ret = &nfacct->bytes; + break; + } + return ret; +} +EXPORT_SYMBOL(nfacct_attr_get); + +const char * +nfacct_attr_get_str(struct nfacct *nfacct, enum nfacct_attr_type type) +{ + return (char *)nfacct_attr_get(nfacct, type); +} +EXPORT_SYMBOL(nfacct_attr_get_str); + +uint64_t nfacct_attr_get_u64(struct nfacct *nfacct, enum nfacct_attr_type type) +{ + return *((uint64_t *)nfacct_attr_get(nfacct, type)); +} +EXPORT_SYMBOL(nfacct_attr_get_u64); + +/** + * nfacct_nlmsg_build_hdr - build netlink message header for nfacct subsystem + * @buf: buffer where this function outputs the netlink message. + * @cmd: nfacct nfnetlink command. + * @flags: netlink flags. + * @seq: sequence number for this message. + * + * Possible commands: + * - NFNL_MSG_ACCT_NEW: new accounting object. + * - NFNL_MSG_ACCT_GET: get accounting object. + * - NFNL_MSG_ACCT_GET_CTRZERO: get accounting object and atomically reset. + * + * Examples: + * - Command NFNL_MSG_ACCT_NEW + flags NLM_F_CREATE | NLM_F_ACK, to create + * one new accounting object (if it does not already exists). You receive + * one acknoledgment in any case with the result of the operation. + * + * - Command NFNL_MSG_ACCT_GET + flags NLM_F_DUMP, to obtain all the + * existing accounting objects. + * + * - Command NFNL_MSG_ACCT_GET_CTRZERO + flags NLM_F_DUMP, to atomically + * obtain all the existing accounting objects and reset them. + * + * - Command NFNL_MSG_ACCT_DEL, to delete all existing unused objects. + * + * - Command NFNL_MSG_ACCT_DEL, to delete one specific nfacct object (if + * unused, otherwise you hit EBUSY). + */ +struct nlmsghdr * +nfacct_nlmsg_build_hdr(char *buf, uint8_t cmd, uint16_t flags, uint32_t seq) { struct nlmsghdr *nlh; struct nfgenmsg *nfh; - uint32_t msg_type = NFNL_MSG_ACCT_GET; - - if (ctrzero) - msg_type = NFNL_MSG_ACCT_GET_CTRZERO; nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | msg_type; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - nlh->nlmsg_seq = time(NULL); + nlh->nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | cmd; + nlh->nlmsg_flags = NLM_F_REQUEST | flags; + nlh->nlmsg_seq = seq; nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); nfh->nfgen_family = AF_UNSPEC; @@ -61,9 +172,22 @@ struct nlmsghdr *nfacct_list(char *buf, bool ctrzero) return nlh; } -EXPORT_SYMBOL(nfacct_list); +EXPORT_SYMBOL(nfacct_nlmsg_build_hdr); + +void nfacct_nlmsg_build_payload(struct nlmsghdr *nlh, struct nfacct *nfacct) +{ + if (nfacct->name) + mnl_attr_put_strz(nlh, NFACCT_NAME, nfacct->name); + + if (nfacct->pkts) + mnl_attr_put_u64(nlh, NFACCT_PKTS, htobe64(nfacct->pkts)); + + if (nfacct->bytes) + mnl_attr_put_u64(nlh, NFACCT_PKTS, htobe64(nfacct->bytes)); +} +EXPORT_SYMBOL(nfacct_nlmsg_build_payload); -static int nfacct_list_attr_cb(const struct nlattr *attr, void *data) +static int nfacct_nlmsg_parse_attr_cb(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; int type = mnl_attr_get_type(attr); @@ -95,67 +219,44 @@ static int nfacct_list_attr_cb(const struct nlattr *attr, void *data) return MNL_CB_OK; } -int nfacct_list_cb(const struct nlmsghdr *nlh, void *data) +int +nfacct_nlmsg_parse_payload(const struct nlmsghdr *nlh, struct nfacct *nfacct) { struct nlattr *tb[NFACCT_MAX+1] = {}; struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); - bool *full = data; - mnl_attr_parse(nlh, sizeof(*nfg), nfacct_list_attr_cb, tb); + mnl_attr_parse(nlh, sizeof(*nfg), nfacct_nlmsg_parse_attr_cb, tb); if (!tb[NFACCT_NAME] && !tb[NFACCT_PKTS] && !tb[NFACCT_BYTES]) - return MNL_CB_OK; + return -1; - if (full) { - printf("%s = { pkts = %.12llu,\tbytes = %.12llu }; \n", - mnl_attr_get_str(tb[NFACCT_NAME]), - (unsigned long long) - be64toh(mnl_attr_get_u64(tb[NFACCT_PKTS])), - (unsigned long long) - be64toh(mnl_attr_get_u64(tb[NFACCT_BYTES]))); - } else { - printf("%s\n", mnl_attr_get_str(tb[NFACCT_NAME])); - } + nfacct_attr_set_str(nfacct, NFACCT_ATTR_NAME, + mnl_attr_get_str(tb[NFACCT_NAME])); + nfacct_attr_set_u64(nfacct, NFACCT_ATTR_PKTS, + be64toh(mnl_attr_get_u64(tb[NFACCT_PKTS]))); + nfacct_attr_set_u64(nfacct, NFACCT_ATTR_BYTES, + be64toh(mnl_attr_get_u64(tb[NFACCT_BYTES]))); - return MNL_CB_OK; + return 0; } -EXPORT_SYMBOL(nfacct_list_cb); +EXPORT_SYMBOL(nfacct_nlmsg_parse_payload); -struct nlmsghdr *nfacct_flush(char *buf) +int nfacct_snprintf(char *buf, size_t size, struct nfacct *nfacct, + unsigned int flags) { - struct nlmsghdr *nlh; - struct nfgenmsg *nfh; - - nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_DEL; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK; - nlh->nlmsg_seq = time(NULL); + int ret; - nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); - nfh->nfgen_family = AF_UNSPEC; - nfh->version = NFNETLINK_V0; - nfh->res_id = 0; - - return nlh; -} -EXPORT_SYMBOL(nfacct_flush); - -struct nlmsghdr *nfacct_delete(char *buf, const char *filter_name) -{ - struct nlmsghdr *nlh; - struct nfgenmsg *nfh; - - nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | NFNL_MSG_ACCT_DEL; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - nlh->nlmsg_seq = time(NULL); - - nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); - nfh->nfgen_family = AF_UNSPEC; - nfh->version = NFNETLINK_V0; - nfh->res_id = 0; - - mnl_attr_put_strz(nlh, NFACCT_NAME, filter_name); - - return nlh; + if (flags & NFACCT_SNPRINTF_F_FULL) { + ret = snprintf(buf, size, + "%s = { pkts = %.12llu,\tbytes = %.12llu };", + nfacct_attr_get_str(nfacct, NFACCT_ATTR_NAME), + (unsigned long long) + nfacct_attr_get_u64(nfacct, NFACCT_ATTR_BYTES), + (unsigned long long) + nfacct_attr_get_u64(nfacct, NFACCT_ATTR_PKTS)); + } else { + ret = snprintf(buf, size, "%s\n", + nfacct_attr_get_str(nfacct, NFACCT_ATTR_NAME)); + } + return ret; } -EXPORT_SYMBOL(nfacct_delete); +EXPORT_SYMBOL(nfacct_snprintf); -- cgit v1.2.3