static int build_rule_snat(int index, const char *address, struct nftnl_rule **res) { struct nftnl_rule *rule; struct nftnl_expr *expr; uint32_t snat; int err; /* * # nft --debug netlink add rule connman nat-postrouting \ * oif eth0 snat 1.2.3.4 * ip connman nat-postrouting * [ meta load oif => reg 1 ] * [ cmp eq reg 1 0x0000000b ] * [ immediate reg 1 0x04030201 ] * [ nat snat ip addr_min reg 1 addr_max reg 0 ] */ rule = nftnl_rule_alloc(); if (!rule) return -ENOMEM; nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE); nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST); /* OIF */ expr = nftnl_expr_alloc("meta"); if (!expr) goto err; nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_OIF); nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1); nftnl_rule_add_expr(rule, expr); err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &index, sizeof(index)); if (err < 0) goto err; /* snat */ expr = nftnl_expr_alloc("immediate"); if (!expr) goto err; snat = inet_addr(address); nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1); nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &snat, sizeof(snat)); nftnl_rule_add_expr(rule, expr); expr = nftnl_expr_alloc("nat"); if (!expr) goto err; nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_TYPE, NFT_NAT_SNAT); nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_FAMILY, NFPROTO_IPV4); nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1); nftnl_rule_add_expr(rule, expr); *res = rule; return 0; err: nftnl_rule_free(rule); return -ENOMEM; }
static int build_rule_src_ip(const char *src_ip, uint32_t mark, struct nftnl_rule **res) { struct nftnl_rule *rule; struct nftnl_expr *expr; int err; in_addr_t s_addr; /* * # nft --debug netlink add rule connman route-output \ * ip saddr 192.168.10.31 mark set 1234 * * ip connman route-output * [ payload load 4b @ network header + 12 => reg 1 ] * [ cmp eq reg 1 0x1f0aa8c0 ] * [ immediate reg 1 0x000004d2 ] * [ meta set mark with reg 1 ] */ rule = nftnl_rule_alloc(); if (!rule) return -ENOMEM; nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE); nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT); /* family ipv4 */ nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4); /* source IP */ err = add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, offsetof(struct iphdr, saddr), sizeof(struct in_addr)); if (err < 0) goto err; s_addr = inet_addr(src_ip); err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &s_addr, sizeof(s_addr)); if (err < 0) goto err; expr = nftnl_expr_alloc("immediate"); if (!expr) goto err; nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1); nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &mark, sizeof(mark)); nftnl_rule_add_expr(rule, expr); expr = nftnl_expr_alloc("meta"); if (!expr) goto err; nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_MARK); nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG_1); nftnl_rule_add_expr(rule, expr); *res = rule; return 0; err: return -ENOMEM; }
static int build_rule_marking(uid_t uid, uint32_t mark, struct nftnl_rule **res) { struct nftnl_rule *rule; struct nftnl_expr *expr; int err; /* * http://wiki.nftables.org/wiki-nftables/index.php/Setting_packet_metainformation * http://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_metainformation * * # nft --debug netlink add rule connman route-output \ * meta skuid wagi mark set 1234 * * ip connman route-output * [ meta load skuid => reg 1 ] * [ cmp eq reg 1 0x000003e8 ] * [ immediate reg 1 0x000004d2 ] * [ meta set mark with reg 1 ] */ rule = nftnl_rule_alloc(); if (!rule) return -ENOMEM; nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE); nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT); expr = nftnl_expr_alloc("meta"); if (!expr) goto err; nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_SKUID); nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1); nftnl_rule_add_expr(rule, expr); err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &uid, sizeof(uid)); if (err < 0) goto err; expr = nftnl_expr_alloc("immediate"); if (!expr) goto err; nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1); nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &mark, sizeof(mark)); nftnl_rule_add_expr(rule, expr); expr = nftnl_expr_alloc("meta"); if (!expr) goto err; nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_MARK); nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG_1); nftnl_rule_add_expr(rule, expr); *res = rule; return 0; err: return -ENOMEM; }
int main(int argc, char *argv[]) { struct nftnl_rule *a, *b; struct nftnl_expr *ex; struct nlmsghdr *nlh; char buf[4096]; struct nftnl_expr_iter *iter_a, *iter_b; struct nftnl_expr *rule_a, *rule_b; uint32_t chain_t = 0x12345678; uint32_t data_t = 0x12345678; a = nftnl_rule_alloc(); b = nftnl_rule_alloc(); if (a == NULL || b == NULL) print_err("OOM"); ex = nftnl_expr_alloc("immediate"); if (ex == NULL) print_err("OOM"); nftnl_expr_set_u32(ex, NFTNL_EXPR_IMM_DREG, 0x1234568); nftnl_expr_set(ex, NFTNL_EXPR_IMM_DATA, &chain_t, sizeof(chain_t)); nftnl_expr_set_u32(ex, NFTNL_EXPR_IMM_VERDICT, 0x12345678); nftnl_expr_set(ex, NFTNL_EXPR_IMM_CHAIN, &data_t, sizeof(data_t)); nftnl_rule_add_expr(a, ex); nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE, AF_INET, 0, 1234); nftnl_rule_nlmsg_build_payload(nlh, a); if (nftnl_rule_nlmsg_parse(nlh, b) < 0) print_err("parsing problems"); iter_a = nftnl_expr_iter_create(a); iter_b = nftnl_expr_iter_create(b); if (iter_a == NULL || iter_b == NULL) print_err("OOM"); rule_a = nftnl_expr_iter_next(iter_a); rule_b = nftnl_expr_iter_next(iter_b); if (rule_a == NULL || rule_b == NULL) print_err("OOM"); cmp_nftnl_expr(rule_a, rule_b); if (nftnl_expr_iter_next(iter_a) != NULL || nftnl_expr_iter_next(iter_b) != NULL) print_err("More 1 expr."); nftnl_expr_iter_destroy(iter_a); nftnl_expr_iter_destroy(iter_b); nftnl_rule_free(a); nftnl_rule_free(b); if (!test_ok) exit(EXIT_FAILURE); printf("%s: \033[32mOK\e[0m\n", argv[0]); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { struct nftnl_rule *a, *b; struct nftnl_expr *ex; struct nlmsghdr *nlh; char buf[4096]; struct nftnl_expr_iter *iter_a, *iter_b; struct nftnl_expr *rule_a, *rule_b; a = nftnl_rule_alloc(); b = nftnl_rule_alloc(); if (a == NULL || b == NULL) print_err("OOM"); ex = nftnl_expr_alloc("byteorder"); if (ex == NULL) print_err("OOM"); nftnl_expr_set_u32(ex, NFTNL_EXPR_BYTEORDER_SREG, 0x12345678); nftnl_expr_set_u32(ex, NFTNL_EXPR_BYTEORDER_DREG, 0x12345678); nftnl_expr_set_u32(ex, NFTNL_EXPR_BYTEORDER_OP, 0x12345678); nftnl_expr_set_u32(ex, NFTNL_EXPR_BYTEORDER_LEN, 0x12345678); nftnl_expr_set_u32(ex, NFTNL_EXPR_BYTEORDER_SIZE, 0x12345678); nftnl_rule_add_expr(a, ex); nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE, AF_INET, 0, 1234); nftnl_rule_nlmsg_build_payload(nlh, a); if (nftnl_rule_nlmsg_parse(nlh, b) < 0) print_err("parsing problems"); iter_a = nftnl_expr_iter_create(a); iter_b = nftnl_expr_iter_create(b); if (iter_a == NULL || iter_b == NULL) print_err("OOM"); rule_a = nftnl_expr_iter_next(iter_a); rule_b = nftnl_expr_iter_next(iter_b); if (rule_a == NULL || rule_b == NULL) print_err("OOM"); cmp_nftnl_expr(rule_a,rule_b); if (nftnl_expr_iter_next(iter_a) != NULL || nftnl_expr_iter_next(iter_b) != NULL) print_err("More 1 expr."); nftnl_expr_iter_destroy(iter_a); nftnl_expr_iter_destroy(iter_b); nftnl_rule_free(a); nftnl_rule_free(b); if (!test_ok) exit(EXIT_FAILURE); printf("%s: \033[32mOK\e[0m\n", argv[0]); return EXIT_SUCCESS; }
static void add_counter(struct nftnl_rule *r) { struct nftnl_expr *e; e = nftnl_expr_alloc("counter"); if (e == NULL) { perror("expr counter oom"); exit(EXIT_FAILURE); } nftnl_rule_add_expr(r, e); }
void add_meta(struct nftnl_rule *r, uint32_t key) { struct nftnl_expr *expr; expr = nftnl_expr_alloc("meta"); if (expr == NULL) return; nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, key); nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1); nftnl_rule_add_expr(r, expr); }
void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len) { struct nftnl_expr *expr; expr = nftnl_expr_alloc("cmp"); if (expr == NULL) return; nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, NFT_REG_1); nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op); nftnl_expr_set(expr, NFTNL_EXPR_CMP_DATA, data, len); nftnl_rule_add_expr(r, expr); }
void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base) { struct nftnl_expr *expr; expr = nftnl_expr_alloc("payload"); if (expr == NULL) return; nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base); nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, NFT_REG_1); nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_OFFSET, offset); nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_LEN, len); nftnl_rule_add_expr(r, expr); }
struct nftnl_expr *nftnl_mxml_expr_parse(mxml_node_t *node, struct nftnl_parse_err *err, struct nftnl_set_list *set_list) { mxml_node_t *tree; struct nftnl_expr *e; const char *expr_name; char *xml_text; uint32_t set_id; int ret; expr_name = mxmlElementGetAttr(node, "type"); if (expr_name == NULL) { err->node_name = "type"; err->error = NFTNL_PARSE_EMISSINGNODE; goto err; } e = nftnl_expr_alloc(expr_name); if (e == NULL) goto err; xml_text = mxmlSaveAllocString(node, MXML_NO_CALLBACK); if (xml_text == NULL) goto err_expr; tree = mxmlLoadString(NULL, xml_text, MXML_OPAQUE_CALLBACK); xfree(xml_text); if (tree == NULL) goto err_expr; ret = e->ops->xml_parse(e, tree, err); mxmlDelete(tree); if (set_list != NULL && strcmp(expr_name, "lookup") == 0 && nftnl_set_lookup_id(e, set_list, &set_id)) nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SET_ID, set_id); return ret < 0 ? NULL : e; err_expr: nftnl_expr_free(e); err: mxmlDelete(tree); errno = EINVAL; return NULL; }
/* bitwise operation is = sreg & mask ^ xor */ void add_bitwise_u16(struct nftnl_rule *r, int mask, int xor) { struct nftnl_expr *expr; expr = nftnl_expr_alloc("bitwise"); if (expr == NULL) return; nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, sizeof(uint16_t)); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, &mask, sizeof(uint16_t)); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, sizeof(uint16_t)); nftnl_rule_add_expr(r, expr); }
static int add_cmp(struct nftnl_rule *rule, uint32_t sreg, uint32_t op, const void *data, uint32_t data_len) { struct nftnl_expr *expr; expr = nftnl_expr_alloc("cmp"); if (!expr) return -ENOMEM; nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, sreg); nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op); nftnl_expr_set(expr, NFTNL_EXPR_CMP_DATA, data, data_len); nftnl_rule_add_expr(rule, expr); return 0; }
static void add_cmp(struct nftnl_rule *r, uint32_t sreg, uint32_t op, const void *data, uint32_t data_len) { struct nftnl_expr *e; e = nftnl_expr_alloc("cmp"); if (e == NULL) { perror("expr cmp oom"); exit(EXIT_FAILURE); } nftnl_expr_set_u32(e, NFTNL_EXPR_CMP_SREG, sreg); nftnl_expr_set_u32(e, NFTNL_EXPR_CMP_OP, op); nftnl_expr_set(e, NFTNL_EXPR_CMP_DATA, data, data_len); nftnl_rule_add_expr(r, e); }
static void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len) { struct nftnl_expr *expr; uint32_t xor[4] = { 0 }; expr = nftnl_expr_alloc("bitwise"); if (expr == NULL) return; nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, len); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, mask, len); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, len); nftnl_rule_add_expr(r, expr); }
static int add_payload(struct nftnl_rule *rule, uint32_t base, uint32_t dreg, uint32_t offset, uint32_t len) { struct nftnl_expr *expr; expr = nftnl_expr_alloc("payload"); if (!expr) return -ENOMEM; nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base); nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, dreg); nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_OFFSET, offset); nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_LEN, len); nftnl_rule_add_expr(rule, expr); return 0; }
static void add_payload(struct nftnl_rule *r, uint32_t base, uint32_t dreg, uint32_t offset, uint32_t len) { struct nftnl_expr *e; e = nftnl_expr_alloc("payload"); if (e == NULL) { perror("expr payload oom"); exit(EXIT_FAILURE); } nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset); nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len); nftnl_rule_add_expr(r, e); }
static int add_bitwise(struct nftnl_rule *rule, int reg, const void *mask, size_t len) { struct nftnl_expr *expr; uint8_t *xor; expr = nftnl_expr_alloc("bitwise"); if (!expr) return -ENOMEM; xor = alloca(len); memset(xor, 0, len); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, reg); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, len); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, mask, len); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, xor, len); nftnl_rule_add_expr(rule, expr); return 0; }
static int build_rule_nat(const char *address, unsigned char prefixlen, const char *interface, struct nftnl_rule **res) { struct nftnl_rule *rule; struct in_addr ipv4_addr, ipv4_mask; struct nftnl_expr *expr; int err; /* * # nft --debug netlink add rule connman nat-postrouting \ * oifname eth0 ip saddr 10.10.0.0/24 masquerade * * ip connman nat-postrouting * [ meta load oifname => reg 1 ] * [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ] * [ payload load 4b @ network header + 12 => reg 1 ] * [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ] * [ cmp eq reg 1 0x00000a0a ] * [ masq ] */ rule = nftnl_rule_alloc(); if (!rule) return -ENOMEM; nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE); nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST); /* family ipv4 */ nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4); /* oifname */ expr = nftnl_expr_alloc("meta"); if (!expr) goto err; nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_OIFNAME); nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1); nftnl_rule_add_expr(rule, expr); err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, interface, strlen(interface) + 1); if (err < 0) goto err; /* source */ ipv4_mask.s_addr = htonl((0xffffffff << (32 - prefixlen)) & 0xffffffff); ipv4_addr.s_addr = inet_addr(address); ipv4_addr.s_addr &= ipv4_mask.s_addr; err = add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, offsetof(struct iphdr, saddr), sizeof(struct in_addr)); if (err < 0) goto err; err = add_bitwise(rule, NFT_REG_1, &ipv4_mask.s_addr, sizeof(struct in_addr)); if (err < 0) goto err; err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &ipv4_addr.s_addr, sizeof(struct in_addr)); if (err < 0) goto err; /* masquerade */ expr = nftnl_expr_alloc("masq"); if (!expr) goto err; nftnl_rule_add_expr(rule, expr); *res = rule; return 0; err: nftnl_rule_free(rule); return -ENOMEM; }