#include "./helpers.h" batch batch_init(size_t size) { void *buf = malloc(size); batch b = mnl_nlmsg_batch_start(buf, size); nftnl_batch_begin(mnl_nlmsg_batch_current(b), seq++); mnl_nlmsg_batch_next(b); rseq = seq; return b; } void batch_end(batch b) { nftnl_batch_end(mnl_nlmsg_batch_current(b), seq); mnl_nlmsg_batch_next(b); } ssize_t batch_send(batch b, sock s) { return mnl_socket_sendto(s, mnl_nlmsg_batch_head(b), mnl_nlmsg_batch_size(b)); } void batch_free(batch b) { void *buf = mnl_nlmsg_batch_head(b); mnl_nlmsg_batch_stop(b); free(buf); } int batch_send_and_run_callbacks(batch b, sock s, void *cb) { batch_end(b); if (batch_send(b, s) == -1) { ERROR("batch_send"); return -1; } batch_free(b); if (run_callbacks(s, cb, NULL) < 0) { ERROR("run_callbacks"); return -1; } return 0; } table make_table(const char *name, uint32_t family, const void *udata, uint32_t udlen) { table t = nftnl_table_alloc(); if (t == NULL) { ERROR("Couldn't allocate a table"); exit(EXIT_FAILURE); } nftnl_table_set_str(t, NFTNL_TABLE_NAME, name); if (udata != NULL && udlen > 0) nftnl_table_set_data(t, NFTNL_TABLE_USERDATA, udata, udlen); return t; } void batch_new_table(batch b, table t, uint32_t family) { nlmsghdr hdr = nftnl_nlmsg_build_hdr((char *)mnl_nlmsg_batch_current(b), NFT_MSG_NEWTABLE, family, NLM_F_ACK | NLM_F_CREATE | NLM_F_APPEND, seq++); nftnl_table_nlmsg_build_payload(hdr, t); mnl_nlmsg_batch_next(b); } chain make_chain(const char *table, const char *name, uint32_t flags, uint32_t hooknum, uint32_t prio, char *type) { chain c = nftnl_chain_alloc(); if (c == NULL) { ERROR("Couldn't allocate a chain"); exit(EXIT_FAILURE); } nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, name); nftnl_chain_set_u32(c, NFTNL_CHAIN_FLAGS, flags); if (type) nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, type); if (hooknum != -1) { nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, hooknum); nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, prio); } return c; } void batch_new_chain(batch b, chain c, uint32_t family) { nlmsghdr hdr = nftnl_nlmsg_build_hdr((char *)mnl_nlmsg_batch_current(b), NFT_MSG_NEWCHAIN, family, NLM_F_ACK | NLM_F_CREATE | NLM_F_APPEND, seq++); nftnl_chain_nlmsg_build_payload(hdr, c); mnl_nlmsg_batch_next(b); } rule make_rule(const char *table, const char *chain, expr *exprs, size_t num_exprs, const void *udata, uint32_t udlen, uint64_t handle) { rule r = nftnl_rule_alloc(); if (r == NULL) { ERROR("Couldn't allocate a rule"); return NULL; } nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table); nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain); for (int i = 0; i < num_exprs; ++i) nftnl_rule_add_expr(r, exprs[i]); if (udlen) nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, udata, udlen); if (handle) nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, handle); return r; } void batch_new_rule(batch b, rule r, uint32_t family) { nlmsghdr hdr = nftnl_nlmsg_build_hdr((char *)mnl_nlmsg_batch_current(b), NFT_MSG_NEWRULE, family, NLM_F_ACK | NLM_F_CREATE | NLM_F_APPEND, seq++); nftnl_rule_nlmsg_build_payload(hdr, r); mnl_nlmsg_batch_next(b); } void batch_del_rule(batch b, rule r, uint32_t family) { nlmsghdr hdr = nftnl_nlmsg_build_hdr((char *)mnl_nlmsg_batch_current(b), NFT_MSG_DELRULE, family, NLM_F_ACK, seq++); nftnl_rule_nlmsg_build_payload(hdr, r); mnl_nlmsg_batch_next(b); } expr make_notrack_expr() { return nftnl_expr_alloc("notrack"); } expr make_ct_set_zone_expr(uint32_t sreg) { expr e = nftnl_expr_alloc("ct"); if (e == NULL) return NULL; nftnl_expr_set_u32(e, NFTNL_EXPR_CT_KEY, NFT_CT_ZONE); nftnl_expr_set_u32(e, NFTNL_EXPR_CT_SREG, sreg); return e; } expr make_queue_expr(uint16_t num, uint16_t total, uint16_t flags) { expr e = nftnl_expr_alloc("queue"); if (e == NULL) return NULL; nftnl_expr_set_u16(e, NFTNL_EXPR_QUEUE_NUM, num); if (total) nftnl_expr_set_u16(e, NFTNL_EXPR_QUEUE_TOTAL, total); if (flags) nftnl_expr_set_u16(e, NFTNL_EXPR_QUEUE_FLAGS, flags); return e; } expr make_cmp_expr(uint32_t sreg, uint32_t cmp_op, uint8_t data) { expr e = nftnl_expr_alloc("cmp"); if (e == NULL) return NULL; nftnl_expr_set_u32(e, NFTNL_EXPR_CMP_SREG, sreg); nftnl_expr_set_u32(e, NFTNL_EXPR_CMP_OP, cmp_op); nftnl_expr_set_u8(e, NFTNL_EXPR_CMP_DATA, data); return e; } expr make_log_expr(char *prefix) { expr e = nftnl_expr_alloc("log"); if (e == NULL) return NULL; if (prefix) { nftnl_expr_set_str(e, NFTNL_EXPR_LOG_PREFIX, prefix); } nftnl_expr_set_u32(e, NFTNL_EXPR_LOG_LEVEL, NFT_LOGLEVEL_AUDIT); return e; } expr make_payload_expr(uint32_t base, uint32_t offset, uint32_t len, uint32_t dreg) { expr e = nftnl_expr_alloc("payload"); if (e == NULL) return NULL; nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg); return e; } int run_callbacks(sock s, mnl_cb_t cb, void *data) { char buf[MNL_SOCKET_BUFFER_SIZE]; int ret = 0; while (rseq < seq) { ret = mnl_socket_recvfrom(s, buf, sizeof(buf)); if (ret <= 0) break; ret = mnl_cb_run(buf, ret, rseq, mnl_socket_get_portid(s), cb, data); if (ret < 0) break; rseq += ret == 0; } return ret; } nlmsghdr dump_rule(rule r, char *buf, uint32_t family) { nlmsghdr hdr = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, NLM_F_ACK, seq++); nftnl_rule_nlmsg_build_payload(hdr, r); return hdr; }