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 rule_delete(struct firewall_handle *handle) { struct nftnl_rule *rule; struct mnl_socket *nl; int err; DBG(""); rule = nftnl_rule_alloc(); if (!rule) return -ENOMEM; nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE); nftnl_rule_set(rule, NFTNL_RULE_CHAIN, handle->chain); nftnl_rule_set_u64(rule, NFTNL_RULE_HANDLE, handle->handle); err = socket_open_and_bind(&nl); if (err < 0) { nftnl_rule_free(rule); return err; } err = rule_cmd(nl, rule, NFT_MSG_DELRULE, NFPROTO_IPV4, NLM_F_ACK, 0, NULL); nftnl_rule_free(rule); mnl_socket_close(nl); return err; }
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; }
static struct nftnl_rule *setup_rule(uint8_t family, const char *table, const char *chain, const char *handle) { struct nftnl_rule *r = NULL; uint8_t proto; uint16_t dport; uint64_t handle_num; r = nftnl_rule_alloc(); if (r == NULL) { perror("OOM"); exit(EXIT_FAILURE); } nftnl_rule_set(r, NFTNL_RULE_TABLE, table); nftnl_rule_set(r, NFTNL_RULE_CHAIN, chain); nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); if (handle != NULL) { handle_num = atoll(handle); nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle_num); } proto = IPPROTO_TCP; add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, offsetof(struct iphdr, protocol), sizeof(uint8_t)); add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); dport = htons(22); add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, offsetof(struct tcphdr, dest), sizeof(uint16_t)); add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); add_counter(r); return r; }
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; }