Use libmnl and libnetfilter_conntrack mnl helpers to update the conntrack table entries. Signed-off-by: Mikhail Sennikovsky <mikhail.sennikovskii@xxxxxxxxx> --- src/conntrack.c | 268 +++++++++++++++++++++++++++++------------------- 1 file changed, 163 insertions(+), 105 deletions(-) diff --git a/src/conntrack.c b/src/conntrack.c index fe5574d..161e6a5 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -68,10 +68,13 @@ #include <linux/netfilter/nf_conntrack_common.h> #include <libnetfilter_conntrack/libnetfilter_conntrack.h> -static struct nfct_mnl_socket { +struct nfct_mnl_socket { struct mnl_socket *mnl; uint32_t portid; -} _sock; +}; + +static struct nfct_mnl_socket _sock; +static struct nfct_mnl_socket _modifier_sock; struct u32_mask { uint32_t value; @@ -2073,33 +2076,6 @@ done: return NFCT_CB_CONTINUE; } -static int print_cb(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) -{ - char buf[1024]; - unsigned int op_type = NFCT_O_DEFAULT; - unsigned int op_flags = 0; - - if (output_mask & _O_SAVE) { - ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_NEW); - goto done; - } - - if (output_mask & _O_XML) - op_type = NFCT_O_XML; - if (output_mask & _O_EXT) - op_flags = NFCT_OF_SHOW_LAYER3; - if (output_mask & _O_ID) - op_flags |= NFCT_OF_ID; - - nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap); -done: - printf("%s\n", buf); - - return NFCT_CB_CONTINUE; -} - static void copy_mark(const struct ct_cmd *cmd, struct nf_conntrack *tmp, const struct nf_conntrack *ct, const struct u32_mask *m) @@ -2190,73 +2166,6 @@ static void copy_label(const struct ct_cmd *cmd, struct nf_conntrack *tmp, } } -static int update_cb(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) -{ - struct ct_cmd *cmd = data; - struct nf_conntrack *obj = cmd->tmpl.ct, *tmp; - int res; - - if (filter_nat(cmd, ct) || - filter_label(ct, cur_tmpl) || - filter_network(cmd, ct)) - return NFCT_CB_CONTINUE; - - if (nfct_attr_is_set(obj, ATTR_ID) && nfct_attr_is_set(ct, ATTR_ID) && - nfct_get_attr_u32(obj, ATTR_ID) != nfct_get_attr_u32(ct, ATTR_ID)) - return NFCT_CB_CONTINUE; - - if (cmd->options & CT_OPT_TUPLE_ORIG && - !nfct_cmp(obj, ct, NFCT_CMP_ORIG)) - return NFCT_CB_CONTINUE; - if (cmd->options & CT_OPT_TUPLE_REPL && - !nfct_cmp(obj, ct, NFCT_CMP_REPL)) - return NFCT_CB_CONTINUE; - - tmp = nfct_new(); - if (tmp == NULL) - exit_error(OTHER_PROBLEM, "out of memory"); - - nfct_copy(tmp, ct, NFCT_CP_ORIG); - nfct_copy(tmp, obj, NFCT_CP_META); - copy_mark(cmd, tmp, ct, &cur_tmpl->mark); - copy_status(cmd, tmp, ct); - copy_label(cmd, tmp, ct, cur_tmpl); - - /* do not send NFCT_Q_UPDATE if ct appears unchanged */ - if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) { - nfct_destroy(tmp); - return NFCT_CB_CONTINUE; - } - - res = nfct_query(ith, NFCT_Q_UPDATE, tmp); - if (res < 0) - fprintf(stderr, - "Operation failed: %s\n", - err2str(errno, CT_UPDATE)); - nfct_callback_register(ith, NFCT_T_ALL, print_cb, NULL); - - res = nfct_query(ith, NFCT_Q_GET, tmp); - if (res < 0) { - nfct_destroy(tmp); - /* the entry has vanish in middle of the update */ - if (errno == ENOENT) { - nfct_callback_unregister(ith); - return NFCT_CB_CONTINUE; - } - exit_error(OTHER_PROBLEM, - "Operation failed: %s", - err2str(errno, CT_UPDATE)); - } - nfct_destroy(tmp); - nfct_callback_unregister(ith); - - counter++; - - return NFCT_CB_CONTINUE; -} - static int dump_exp_cb(enum nf_conntrack_msg_type type, struct nf_expect *exp, void *data) @@ -2529,6 +2438,45 @@ nfct_mnl_create(struct nfct_mnl_socket *sock, uint16_t subsys, uint16_t type, return nfct_mnl_talk(sock, nlh, NULL); } +static int +nfct_mnl_set_ct(struct nfct_mnl_socket *sock, + uint16_t subsys, uint16_t type, const struct nf_conntrack *ct) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + int res; + + nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, + NLM_F_ACK, + nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)); + + res = nfct_nlmsg_build(nlh, ct); + if (res < 0) + return res; + + return nfct_mnl_talk(sock, nlh, NULL); +} + +static int +nfct_mnl_request(struct nfct_mnl_socket *sock, + uint16_t subsys, uint16_t type, const struct nf_conntrack *ct, + mnl_cb_t cb) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + int res; + + nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, + NLM_F_ACK, + nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)); + + res = nfct_nlmsg_build(nlh, ct); + if (res < 0) + return res; + + return nfct_mnl_recv(sock, nlh, cb, NULL); +} + #define UNKNOWN_STATS_NUM 4 static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) @@ -2717,6 +2665,116 @@ done: return MNL_CB_OK; } +static int mnl_nfct_print_cb(const struct nlmsghdr *nlh, void *data) +{ + char buf[1024]; + unsigned int op_type = NFCT_O_DEFAULT; + unsigned int op_flags = 0; + struct nf_conntrack *ct; + + ct = nfct_new(); + if (ct == NULL) + return MNL_CB_OK; + + nfct_nlmsg_parse(nlh, ct); + + if (output_mask & _O_SAVE) { + ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_NEW); + goto done; + } + + if (output_mask & _O_XML) + op_type = NFCT_O_XML; + if (output_mask & _O_EXT) + op_flags = NFCT_OF_SHOW_LAYER3; + if (output_mask & _O_ID) + op_flags |= NFCT_OF_ID; + + nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap); +done: + printf("%s\n", buf); + + nfct_destroy(ct); + + return MNL_CB_OK; +} + +static int mnl_nfct_update_cb(const struct nlmsghdr *nlh, void *data) +{ + struct ct_cmd *cmd = data; + struct nfct_mnl_socket *modifier_sock = &_modifier_sock; + struct nf_conntrack *ct, *obj = cmd->tmpl.ct, *tmp = NULL; + int res; + + ct = nfct_new(); + if (ct == NULL) + return MNL_CB_OK; + + nfct_nlmsg_parse(nlh, ct); + + if (filter_nat(cmd, ct) || + filter_label(ct, cur_tmpl) || + filter_network(cmd, ct)) + goto destroy_ok; + + if (nfct_attr_is_set(obj, ATTR_ID) && nfct_attr_is_set(ct, ATTR_ID) && + nfct_get_attr_u32(obj, ATTR_ID) != nfct_get_attr_u32(ct, ATTR_ID)) + goto destroy_ok; + + if (cmd->options & CT_OPT_TUPLE_ORIG && + !nfct_cmp(obj, ct, NFCT_CMP_ORIG)) + goto destroy_ok; + if (cmd->options & CT_OPT_TUPLE_REPL && + !nfct_cmp(obj, ct, NFCT_CMP_REPL)) + goto destroy_ok; + + tmp = nfct_new(); + if (tmp == NULL) + exit_error(OTHER_PROBLEM, "out of memory"); + + nfct_copy(tmp, ct, NFCT_CP_ORIG); + nfct_copy(tmp, obj, NFCT_CP_META); + copy_mark(cmd, tmp, ct, &cur_tmpl->mark); + copy_status(cmd, tmp, ct); + copy_label(cmd, tmp, ct, cur_tmpl); + + /* do not send NFCT_Q_UPDATE if ct appears unchanged */ + if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) + goto destroy_ok; + + res = nfct_mnl_set_ct(modifier_sock, + NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_CT_NEW, + tmp); + if (res < 0) + fprintf(stderr, + "Operation failed: %s\n", + err2str(errno, CT_UPDATE)); + + res = nfct_mnl_request(modifier_sock, + NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_CT_GET, + tmp, + mnl_nfct_print_cb); + if (res < 0) { + /* the entry has vanish in middle of the update */ + if (errno == ENOENT) + goto destroy_ok; + exit_error(OTHER_PROBLEM, + "Operation failed: %s", + err2str(errno, CT_UPDATE)); + } + + counter++; + +destroy_ok: + if (tmp) + nfct_destroy(tmp); + nfct_destroy(ct); + + return MNL_CB_OK; +} + static struct ctproto_handler *h; static void labelmap_init(void) @@ -3253,6 +3311,7 @@ static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[]) static int do_command_ct(const char *progname, struct ct_cmd *cmd) { struct nfct_mnl_socket *sock = &_sock; + struct nfct_mnl_socket *modifier_sock = &_modifier_sock; struct nfct_filter_dump *filter_dump; int res = 0; @@ -3373,19 +3432,18 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) break; case CT_UPDATE: - cth = nfct_open(CONNTRACK, 0); - /* internal handler for delete_cb, otherwise we hit EILSEQ */ - ith = nfct_open(CONNTRACK, 0); - if (!cth || !ith) + if (nfct_mnl_socket_open(sock, 0) < 0 + || nfct_mnl_socket_open(modifier_sock, 0) < 0) exit_error(OTHER_PROBLEM, "Can't open handler"); nfct_filter_init(cmd); - nfct_callback_register(cth, NFCT_T_ALL, update_cb, cmd); - - res = nfct_query(cth, NFCT_Q_DUMP, &cmd->family); - nfct_close(ith); - nfct_close(cth); + res = nfct_mnl_dump(sock, + NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_CT_GET, + mnl_nfct_update_cb, cmd, NULL); + nfct_mnl_socket_close(modifier_sock); + nfct_mnl_socket_close(sock); break; case CT_DELETE: -- 2.25.1