5 * Copyright (C) 2016 BMW Car IT GmbH.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 * This file is based on the libnftnl examples:
24 * https://git.netfilter.org/libnftnl/tree/examples
25 * by Pablo Neira Ayuso. and inspiration from systemd nft implemention
26 * https://github.com/zonque/systemd/blob/rfc-nftnl/src/shared/firewall-util.c
40 #include <netinet/in.h>
41 #include <netinet/ip.h>
43 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
50 #include <linux/netfilter.h>
51 #include <linux/netfilter/nfnetlink.h>
52 #include <linux/netfilter/nf_nat.h>
53 #include <linux/netfilter/nf_tables.h>
55 #include <libmnl/libmnl.h>
56 #include <libnftnl/table.h>
57 #include <libnftnl/chain.h>
58 #include <libnftnl/rule.h>
59 #include <libnftnl/expr.h>
65 #define CONNMAN_TABLE "connman"
66 #define CONNMAN_CHAIN_NAT_PRE "nat-prerouting"
67 #define CONNMAN_CHAIN_NAT_POST "nat-postrouting"
68 #define CONNMAN_CHAIN_ROUTE_OUTPUT "route-output"
70 static bool debug_enabled = true;
72 struct firewall_handle {
77 struct firewall_context {
78 struct firewall_handle rule;
81 struct nftables_info {
82 struct firewall_handle ct;
85 static struct nftables_info *nft_info;
87 enum callback_return_type {
88 CALLBACK_RETURN_NONE = 0,
89 CALLBACK_RETURN_HANDLE,
90 CALLBACK_RETURN_BYTE_COUNTER,
94 struct callback_data {
95 enum callback_return_type type;
100 static void debug_netlink_dump_rule(struct nftnl_rule *nlr)
107 nftnl_rule_snprintf(buf, sizeof(buf), nlr, 0, 0);
108 fprintf(stdout, "%s\n", buf);
111 static void debug_mnl_dump_rule(const void *req, size_t req_size)
116 mnl_nlmsg_fprintf(stdout, req, req_size, 0);
120 static int rule_expr_cb(struct nftnl_expr *expr, void *data) {
122 struct callback_data *cb = data;
125 name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
127 if (strcmp(name, "counter")) {
128 cb->value = nftnl_expr_get_u64(expr, NFTNL_EXPR_CTR_BYTES);
135 static int rule_cb(const struct nlmsghdr *nlh, int event,
136 struct callback_data *cb)
138 struct nftnl_rule *rule;
140 rule = nftnl_rule_alloc();
144 if (nftnl_rule_nlmsg_parse(nlh, rule) < 0)
148 case CALLBACK_RETURN_HANDLE:
149 cb->value = nftnl_rule_get_u64(rule, NFTNL_RULE_HANDLE);
153 case CALLBACK_RETURN_BYTE_COUNTER:
154 nftnl_expr_foreach(rule, rule_expr_cb, cb);
158 DBG("unhandled callback type %d\n", cb->type);
163 nftnl_rule_free(rule);
167 static int chain_cb(const struct nlmsghdr *nlh, int event,
168 struct callback_data *cb)
170 struct nftnl_chain *chain;
172 chain = nftnl_chain_alloc();
176 if (nftnl_chain_nlmsg_parse(nlh, chain) < 0)
180 case CALLBACK_RETURN_HANDLE:
181 cb->value = nftnl_chain_get_u64(chain, NFTNL_CHAIN_HANDLE);
186 DBG("unhandled callback type %d\n", cb->type);
191 nftnl_chain_free(chain);
195 static const char *event_to_str(enum nf_tables_msg_types type)
197 const char *table[] = {
210 "NFT_MSG_NEWSETELEM",
211 "NFT_MSG_GETSETELEM",
212 "NFT_MSG_DELSETELEM",
218 if (type < sizeof(table)/sizeof(table[0]))
224 static int events_cb(const struct nlmsghdr *nlh, void *data)
226 int event = NFNL_MSG_TYPE(nlh->nlmsg_type);
227 struct callback_data *cb = data;
230 if (!cb || cb->type == CALLBACK_RETURN_NONE)
233 DBG("handle event %s", event_to_str(event));
236 case NFT_MSG_NEWCHAIN:
237 err = chain_cb(nlh, event, cb);
240 case NFT_MSG_NEWRULE:
241 err = rule_cb(nlh, event, cb);
244 DBG("unhandled event type %s", event_to_str(event));
251 static int socket_open_and_bind(struct mnl_socket **n)
254 struct mnl_socket *nl = NULL;
257 nl = mnl_socket_open(NETLINK_NETFILTER);
261 err = mnl_socket_bind(nl, 1 << (NFNLGRP_NFTABLES-1),
265 mnl_socket_close(nl);
273 static int send_and_dispatch(struct mnl_socket *nl, const void *req,
274 size_t req_size, enum callback_return_type callback_type,
275 uint64_t *callback_value)
277 struct callback_data cb = {};
281 debug_mnl_dump_rule(req, req_size);
283 err = mnl_socket_sendto(nl, req, req_size);
287 portid = mnl_socket_get_portid(nl);
288 cb.type = callback_type;
291 char buf[MNL_SOCKET_BUFFER_SIZE];
293 err = mnl_socket_recvfrom(nl, buf, sizeof(buf));
297 err = mnl_cb_run(buf, err, 0, portid, events_cb, &cb);
305 if (callback_type == CALLBACK_RETURN_NONE)
310 *callback_value = cb.value;
318 static void put_batch_headers(char *buf, uint16_t type, uint32_t seq)
321 struct nlmsghdr *nlh;
322 struct nfgenmsg *nfg;
324 nlh = mnl_nlmsg_put_header(buf);
325 nlh->nlmsg_type = type;
326 nlh->nlmsg_flags = NLM_F_REQUEST;
327 nlh->nlmsg_seq = seq;
329 nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
330 nfg->nfgen_family = AF_INET;
331 nfg->version = NFNETLINK_V0;
332 nfg->res_id = NFNL_SUBSYS_NFTABLES;
335 static int add_payload(struct nftnl_rule *rule, uint32_t base,
336 uint32_t dreg, uint32_t offset, uint32_t len)
338 struct nftnl_expr *expr;
340 expr = nftnl_expr_alloc("payload");
344 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base);
345 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, dreg);
346 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
347 nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_LEN, len);
349 nftnl_rule_add_expr(rule, expr);
354 static int add_bitwise(struct nftnl_rule *rule, int reg, const void *mask,
357 struct nftnl_expr *expr;
360 expr = nftnl_expr_alloc("bitwise");
367 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, reg);
368 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg);
369 nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, len);
370 nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, mask, len);
371 nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, xor, len);
373 nftnl_rule_add_expr(rule, expr);
378 static int add_cmp(struct nftnl_rule *rule, uint32_t sreg, uint32_t op,
379 const void *data, uint32_t data_len)
381 struct nftnl_expr *expr;
383 expr = nftnl_expr_alloc("cmp");
387 nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, sreg);
388 nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op);
389 nftnl_expr_set(expr, NFTNL_EXPR_CMP_DATA, data, data_len);
391 nftnl_rule_add_expr(rule, expr);
396 static int table_cmd(struct mnl_socket *nl, struct nftnl_table *t,
397 uint16_t cmd, uint16_t family, uint16_t type)
399 char buf[MNL_SOCKET_BUFFER_SIZE];
400 struct mnl_nlmsg_batch *batch;
401 struct nlmsghdr *nlh;
405 batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
406 nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
407 mnl_nlmsg_batch_next(batch);
409 nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
410 cmd, family, type, seq++);
411 nftnl_table_nlmsg_build_payload(nlh, t);
413 mnl_nlmsg_batch_next(batch);
415 nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
416 mnl_nlmsg_batch_next(batch);
418 /* The current table commands do not support any callback returns. */
419 err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
420 mnl_nlmsg_batch_size(batch), 0, NULL);
422 mnl_nlmsg_batch_stop(batch);
426 static int chain_cmd(struct mnl_socket *nl, struct nftnl_chain *chain,
427 uint16_t cmd, int family, uint16_t type,
428 enum callback_return_type cb_type, uint64_t *cb_val)
430 char buf[MNL_SOCKET_BUFFER_SIZE];
431 struct mnl_nlmsg_batch *batch;
432 struct nlmsghdr *nlh;
436 batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
437 nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
438 mnl_nlmsg_batch_next(batch);
440 nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
441 cmd, family, type, seq++);
442 nftnl_chain_nlmsg_build_payload(nlh, chain);
443 nftnl_chain_free(chain);
444 mnl_nlmsg_batch_next(batch);
446 nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
447 mnl_nlmsg_batch_next(batch);
449 err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
450 mnl_nlmsg_batch_size(batch), cb_type, cb_val);
452 mnl_nlmsg_batch_stop(batch);
456 static int rule_cmd(struct mnl_socket *nl, struct nftnl_rule *rule,
457 uint16_t cmd, uint16_t family, uint16_t type,
458 enum callback_return_type callback_type,
459 uint64_t *callback_value)
462 char buf[MNL_SOCKET_BUFFER_SIZE];
463 struct mnl_nlmsg_batch *batch;
464 struct nlmsghdr *nlh;
468 debug_netlink_dump_rule(rule);
470 batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
471 put_batch_headers(mnl_nlmsg_batch_current(batch),
472 NFNL_MSG_BATCH_BEGIN, seq++);
473 mnl_nlmsg_batch_next(batch);
475 nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
476 cmd, family, type, seq++);
477 nftnl_rule_nlmsg_build_payload(nlh, rule);
478 mnl_nlmsg_batch_next(batch);
480 put_batch_headers(mnl_nlmsg_batch_current(batch),
481 NFNL_MSG_BATCH_END, seq++);
482 mnl_nlmsg_batch_next(batch);
484 err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
485 mnl_nlmsg_batch_size(batch),
486 callback_type, callback_value);
487 mnl_nlmsg_batch_stop(batch);
492 static int rule_delete(struct firewall_handle *handle)
494 struct nftnl_rule *rule;
495 struct mnl_socket *nl;
500 rule = nftnl_rule_alloc();
504 nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
505 nftnl_rule_set(rule, NFTNL_RULE_CHAIN, handle->chain);
506 nftnl_rule_set_u64(rule, NFTNL_RULE_HANDLE, handle->handle);
508 err = socket_open_and_bind(&nl);
510 nftnl_rule_free(rule);
514 err = rule_cmd(nl, rule, NFT_MSG_DELRULE, NFPROTO_IPV4,
516 nftnl_rule_free(rule);
517 mnl_socket_close(nl);
522 struct firewall_context *__connman_firewall_create(void)
524 struct firewall_context *ctx;
528 ctx = g_new0(struct firewall_context, 1);
533 void __connman_firewall_destroy(struct firewall_context *ctx)
540 static int build_rule_nat(const char *address, unsigned char prefixlen,
541 const char *interface, struct nftnl_rule **res)
543 struct nftnl_rule *rule;
544 struct in_addr ipv4_addr, ipv4_mask;
545 struct nftnl_expr *expr;
549 * # nft --debug netlink add rule connman nat-postrouting \
550 * oifname eth0 ip saddr 10.10.0.0/24 masquerade
552 * ip connman nat-postrouting
553 * [ meta load oifname => reg 1 ]
554 * [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
555 * [ payload load 4b @ network header + 12 => reg 1 ]
556 * [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
557 * [ cmp eq reg 1 0x00000a0a ]
561 rule = nftnl_rule_alloc();
565 nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
566 nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
569 nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
572 expr = nftnl_expr_alloc("meta");
575 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_OIFNAME);
576 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
577 nftnl_rule_add_expr(rule, expr);
578 err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, interface,
579 strlen(interface) + 1);
584 ipv4_mask.s_addr = htonl((0xffffffff << (32 - prefixlen)) & 0xffffffff);
585 ipv4_addr.s_addr = inet_addr(address);
586 ipv4_addr.s_addr &= ipv4_mask.s_addr;
588 err = add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
589 offsetof(struct iphdr, saddr), sizeof(struct in_addr));
592 err = add_bitwise(rule, NFT_REG_1, &ipv4_mask.s_addr,
593 sizeof(struct in_addr));
596 err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &ipv4_addr.s_addr,
597 sizeof(struct in_addr));
602 expr = nftnl_expr_alloc("masq");
605 nftnl_rule_add_expr(rule, expr);
611 nftnl_rule_free(rule);
615 int __connman_firewall_enable_nat(struct firewall_context *ctx,
616 char *address, unsigned char prefixlen,
619 struct mnl_socket *nl;
620 struct nftnl_rule *rule;
623 DBG("address %s/%d interface %s", address, (int)prefixlen, interface);
625 err = socket_open_and_bind(&nl);
629 err = build_rule_nat(address, prefixlen, interface, &rule);
633 ctx->rule.chain = CONNMAN_CHAIN_NAT_POST;
634 err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
635 NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
636 CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
637 nftnl_rule_free(rule);
639 mnl_socket_close(nl);
643 int __connman_firewall_disable_nat(struct firewall_context *ctx)
645 return rule_delete(&ctx->rule);
648 static int build_rule_snat(int index, const char *address,
649 struct nftnl_rule **res)
651 struct nftnl_rule *rule;
652 struct nftnl_expr *expr;
657 * # nft --debug netlink add rule connman nat-postrouting \
658 * oif eth0 snat 1.2.3.4
659 * ip connman nat-postrouting
660 * [ meta load oif => reg 1 ]
661 * [ cmp eq reg 1 0x0000000b ]
662 * [ immediate reg 1 0x04030201 ]
663 * [ nat snat ip addr_min reg 1 addr_max reg 0 ]
666 rule = nftnl_rule_alloc();
670 nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
671 nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
674 expr = nftnl_expr_alloc("meta");
677 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_OIF);
678 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
679 nftnl_rule_add_expr(rule, expr);
680 err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &index, sizeof(index));
685 expr = nftnl_expr_alloc("immediate");
688 snat = inet_addr(address);
689 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1);
690 nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &snat, sizeof(snat));
691 nftnl_rule_add_expr(rule, expr);
693 expr = nftnl_expr_alloc("nat");
696 nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_TYPE, NFT_NAT_SNAT);
697 nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_FAMILY, NFPROTO_IPV4);
698 nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1);
699 nftnl_rule_add_expr(rule, expr);
705 nftnl_rule_free(rule);
709 int __connman_firewall_enable_snat(struct firewall_context *ctx,
710 int index, const char *ifname, const char *addr)
712 struct nftnl_rule *rule;
713 struct mnl_socket *nl;
718 err = socket_open_and_bind(&nl);
722 err = build_rule_snat(index, addr, &rule);
726 ctx->rule.chain = CONNMAN_CHAIN_NAT_POST;
727 err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
728 NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
729 CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
730 nftnl_rule_free(rule);
732 mnl_socket_close(nl);
736 int __connman_firewall_disable_snat(struct firewall_context *ctx)
740 return rule_delete(&ctx->rule);
743 static int build_rule_marking(uid_t uid, uint32_t mark, struct nftnl_rule **res)
745 struct nftnl_rule *rule;
746 struct nftnl_expr *expr;
750 * http://wiki.nftables.org/wiki-nftables/index.php/Setting_packet_metainformation
751 * http://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_metainformation
753 * # nft --debug netlink add rule connman route-output \
754 * meta skuid wagi mark set 1234
756 * ip connman route-output
757 * [ meta load skuid => reg 1 ]
758 * [ cmp eq reg 1 0x000003e8 ]
759 * [ immediate reg 1 0x000004d2 ]
760 * [ meta set mark with reg 1 ]
763 rule = nftnl_rule_alloc();
767 nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
768 nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
770 expr = nftnl_expr_alloc("meta");
773 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_SKUID);
774 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
775 nftnl_rule_add_expr(rule, expr);
776 err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &uid, sizeof(uid));
780 expr = nftnl_expr_alloc("immediate");
783 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1);
784 nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &mark, sizeof(mark));
785 nftnl_rule_add_expr(rule, expr);
787 expr = nftnl_expr_alloc("meta");
790 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_MARK);
791 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG_1);
792 nftnl_rule_add_expr(rule, expr);
801 static int build_rule_src_ip(const char *src_ip, uint32_t mark, struct nftnl_rule **res)
803 struct nftnl_rule *rule;
804 struct nftnl_expr *expr;
809 * # nft --debug netlink add rule connman route-output \
810 * ip saddr 192.168.10.31 mark set 1234
812 * ip connman route-output
813 * [ payload load 4b @ network header + 12 => reg 1 ]
814 * [ cmp eq reg 1 0x1f0aa8c0 ]
815 * [ immediate reg 1 0x000004d2 ]
816 * [ meta set mark with reg 1 ]
819 rule = nftnl_rule_alloc();
823 nftnl_rule_set(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
824 nftnl_rule_set(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
827 nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
830 err = add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
831 offsetof(struct iphdr, saddr), sizeof(struct in_addr));
835 s_addr = inet_addr(src_ip);
836 err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &s_addr, sizeof(s_addr));
840 expr = nftnl_expr_alloc("immediate");
843 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1);
844 nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &mark, sizeof(mark));
845 nftnl_rule_add_expr(rule, expr);
847 expr = nftnl_expr_alloc("meta");
850 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_MARK);
851 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG_1);
852 nftnl_rule_add_expr(rule, expr);
861 int __connman_firewall_enable_marking(struct firewall_context *ctx,
862 enum connman_session_id_type id_type,
863 char *id, const char *src_ip,
866 struct nftnl_rule *rule;
867 struct mnl_socket *nl;
874 if (id_type == CONNMAN_SESSION_ID_TYPE_UID) {
883 err = socket_open_and_bind(&nl);
887 if (id_type == CONNMAN_SESSION_ID_TYPE_UID) {
888 err = build_rule_marking(uid, mark, &rule);
892 ctx->rule.chain = CONNMAN_CHAIN_ROUTE_OUTPUT;
893 err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
894 NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
895 CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
897 nftnl_rule_free(rule);
901 err = build_rule_src_ip(src_ip, mark, &rule);
905 ctx->rule.chain = CONNMAN_CHAIN_ROUTE_OUTPUT;
906 err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
907 NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
908 CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
910 nftnl_rule_free(rule);
913 mnl_socket_close(nl);
917 int __connman_firewall_disable_marking(struct firewall_context *ctx)
923 err = rule_delete(&ctx->rule);
927 static struct nftnl_table *build_table(const char *name, uint16_t family)
929 struct nftnl_table *table;
931 table = nftnl_table_alloc();
935 nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family);
936 nftnl_table_set_str(table, NFTNL_TABLE_NAME, name);
942 static struct nftnl_chain *build_chain(const char *name, const char *table,
943 const char *type, int hooknum, int prio)
945 struct nftnl_chain *chain;
947 chain = nftnl_chain_alloc();
951 nftnl_chain_set(chain, NFTNL_CHAIN_TABLE, table);
952 nftnl_chain_set(chain, NFTNL_CHAIN_NAME, name);
955 nftnl_chain_set_str(chain, NFTNL_CHAIN_TYPE, type);
958 nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM, hooknum);
961 nftnl_chain_set_u32(chain, NFTNL_CHAIN_PRIO, prio);
966 static int create_table_and_chains(struct nftables_info *nft_info)
968 struct mnl_socket *nl;
969 struct nftnl_table *table;
970 struct nftnl_chain *chain;
976 err = socket_open_and_bind(&nl);
982 * http://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables
986 * # nft add table connman
988 table = build_table(CONNMAN_TABLE, NFPROTO_IPV4);
994 err = table_cmd(nl, table, NFT_MSG_NEWTABLE, NFPROTO_IPV4,
995 NLM_F_CREATE|NLM_F_ACK);
1001 * http://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
1005 * # nft add chain connman nat-prerouting \
1006 * { type nat hook prerouting priortiy 0 ; }
1008 chain = build_chain(CONNMAN_CHAIN_NAT_PRE, CONNMAN_TABLE,
1009 "nat", NF_INET_PRE_ROUTING, 0);
1015 err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN,
1016 NFPROTO_IPV4, NLM_F_CREATE | NLM_F_ACK,
1017 CALLBACK_RETURN_NONE, NULL);
1022 * # nft add chain connman nat-postrouting \
1023 * { type nat hook postrouting priortiy 0 ; }
1025 chain = build_chain(CONNMAN_CHAIN_NAT_POST, CONNMAN_TABLE,
1026 "nat", NF_INET_POST_ROUTING, 0);
1032 err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN,
1033 NFPROTO_IPV4, NLM_F_CREATE | NLM_F_ACK,
1034 CALLBACK_RETURN_NONE, NULL);
1039 * # nft add chain connman route-output \
1040 * { type route hook output priority 0 ; }
1042 chain = build_chain(CONNMAN_CHAIN_ROUTE_OUTPUT, CONNMAN_TABLE,
1043 "route", NF_INET_LOCAL_OUT, 0);
1049 err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN,
1050 NFPROTO_IPV4, NLM_F_CREATE | NLM_F_ACK,
1051 CALLBACK_RETURN_NONE, NULL);
1057 connman_warn("Failed to create basic chains: %s",
1059 mnl_socket_close(nl);
1063 static int cleanup_table_and_chains(void)
1065 struct nftnl_table *table;
1066 struct mnl_socket *nl;
1071 err = socket_open_and_bind(&nl);
1076 * Cleanup everythying in one go. There is little point in
1077 * step-by-step removal of rules and chains if you can get it
1078 * as simple as this.
1081 * # nft delete table connman
1083 table = build_table(CONNMAN_TABLE, NFPROTO_IPV4);
1084 err = table_cmd(nl, table, NFT_MSG_DELTABLE, NFPROTO_IPV4, NLM_F_ACK);
1086 mnl_socket_close(nl);
1090 int __connman_firewall_init(void)
1096 if (getenv("CONNMAN_NFTABLES_DEBUG"))
1097 debug_enabled = true;
1100 * EAFNOSUPPORT is return whenever the nf_tables_ipv4 hasn't been
1101 * loaded yet. ENOENT is return in case the table is missing.
1103 err = cleanup_table_and_chains();
1104 if (err < 0 && (err != EAFNOSUPPORT && err != -ENOENT)) {
1105 connman_warn("initializing nftable failed with '%s' %d. Check if kernel module nf_tables_ipv4 is missing\n",
1106 strerror(-err), err);
1110 nft_info = g_new0(struct nftables_info, 1);
1111 err = create_table_and_chains(nft_info);
1120 void __connman_firewall_cleanup(void)
1126 err = cleanup_table_and_chains();
1128 connman_warn("cleanup table and chains failed with '%s' %d\n",
1129 strerror(-err), err);