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 implementation
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 = false;
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 bzero(buf, sizeof(buf));
407 batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
408 nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
409 mnl_nlmsg_batch_next(batch);
411 nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
412 cmd, family, type, seq++);
413 nftnl_table_nlmsg_build_payload(nlh, t);
415 mnl_nlmsg_batch_next(batch);
417 nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
418 mnl_nlmsg_batch_next(batch);
420 /* The current table commands do not support any callback returns. */
421 err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
422 mnl_nlmsg_batch_size(batch), 0, NULL);
424 mnl_nlmsg_batch_stop(batch);
428 static int chain_cmd(struct mnl_socket *nl, struct nftnl_chain *chain,
429 uint16_t cmd, int family, uint16_t type,
430 enum callback_return_type cb_type, uint64_t *cb_val)
432 char buf[MNL_SOCKET_BUFFER_SIZE];
433 struct mnl_nlmsg_batch *batch;
434 struct nlmsghdr *nlh;
438 bzero(buf, sizeof(buf));
440 batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
441 nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
442 mnl_nlmsg_batch_next(batch);
444 nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
445 cmd, family, type, seq++);
446 nftnl_chain_nlmsg_build_payload(nlh, chain);
447 nftnl_chain_free(chain);
448 mnl_nlmsg_batch_next(batch);
450 nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
451 mnl_nlmsg_batch_next(batch);
453 err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
454 mnl_nlmsg_batch_size(batch), cb_type, cb_val);
456 mnl_nlmsg_batch_stop(batch);
460 static int rule_cmd(struct mnl_socket *nl, struct nftnl_rule *rule,
461 uint16_t cmd, uint16_t family, uint16_t type,
462 enum callback_return_type callback_type,
463 uint64_t *callback_value)
466 char buf[MNL_SOCKET_BUFFER_SIZE];
467 struct mnl_nlmsg_batch *batch;
468 struct nlmsghdr *nlh;
472 bzero(buf, sizeof(buf));
474 debug_netlink_dump_rule(rule);
476 batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
477 put_batch_headers(mnl_nlmsg_batch_current(batch),
478 NFNL_MSG_BATCH_BEGIN, seq++);
479 mnl_nlmsg_batch_next(batch);
481 nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
482 cmd, family, type, seq++);
483 nftnl_rule_nlmsg_build_payload(nlh, rule);
484 mnl_nlmsg_batch_next(batch);
486 put_batch_headers(mnl_nlmsg_batch_current(batch),
487 NFNL_MSG_BATCH_END, seq++);
488 mnl_nlmsg_batch_next(batch);
490 err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
491 mnl_nlmsg_batch_size(batch),
492 callback_type, callback_value);
493 mnl_nlmsg_batch_stop(batch);
498 static int rule_delete(struct firewall_handle *handle)
500 struct nftnl_rule *rule;
501 struct mnl_socket *nl;
506 rule = nftnl_rule_alloc();
510 nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
511 nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, handle->chain);
512 nftnl_rule_set_u64(rule, NFTNL_RULE_HANDLE, handle->handle);
514 err = socket_open_and_bind(&nl);
516 nftnl_rule_free(rule);
520 err = rule_cmd(nl, rule, NFT_MSG_DELRULE, NFPROTO_IPV4,
522 nftnl_rule_free(rule);
523 mnl_socket_close(nl);
528 struct firewall_context *__connman_firewall_create(void)
530 struct firewall_context *ctx;
534 ctx = g_new0(struct firewall_context, 1);
539 void __connman_firewall_destroy(struct firewall_context *ctx)
546 static int build_rule_nat(const char *address, unsigned char prefixlen,
547 const char *interface, struct nftnl_rule **res)
549 struct nftnl_rule *rule;
550 struct in_addr ipv4_addr, ipv4_mask;
551 struct nftnl_expr *expr;
555 * # nft --debug netlink add rule connman nat-postrouting \
556 * oifname eth0 ip saddr 10.10.0.0/24 masquerade
558 * ip connman nat-postrouting
559 * [ meta load oifname => reg 1 ]
560 * [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
561 * [ payload load 4b @ network header + 12 => reg 1 ]
562 * [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
563 * [ cmp eq reg 1 0x00000a0a ]
567 rule = nftnl_rule_alloc();
571 nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
572 nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
575 nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
578 expr = nftnl_expr_alloc("meta");
581 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_OIFNAME);
582 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
583 nftnl_rule_add_expr(rule, expr);
584 err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, interface,
585 strlen(interface) + 1);
590 ipv4_mask.s_addr = htonl((0xffffffff << (32 - prefixlen)) & 0xffffffff);
591 ipv4_addr.s_addr = inet_addr(address);
592 ipv4_addr.s_addr &= ipv4_mask.s_addr;
594 err = add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
595 offsetof(struct iphdr, saddr), sizeof(struct in_addr));
598 err = add_bitwise(rule, NFT_REG_1, &ipv4_mask.s_addr,
599 sizeof(struct in_addr));
602 err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &ipv4_addr.s_addr,
603 sizeof(struct in_addr));
608 expr = nftnl_expr_alloc("masq");
611 nftnl_rule_add_expr(rule, expr);
617 nftnl_rule_free(rule);
621 int __connman_firewall_enable_nat(struct firewall_context *ctx,
622 char *address, unsigned char prefixlen,
625 struct mnl_socket *nl;
626 struct nftnl_rule *rule;
629 DBG("address %s/%d interface %s", address, (int)prefixlen, interface);
631 err = socket_open_and_bind(&nl);
635 err = build_rule_nat(address, prefixlen, interface, &rule);
639 ctx->rule.chain = CONNMAN_CHAIN_NAT_POST;
640 err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
641 NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
642 CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
643 nftnl_rule_free(rule);
645 mnl_socket_close(nl);
649 int __connman_firewall_disable_nat(struct firewall_context *ctx)
651 return rule_delete(&ctx->rule);
654 static int build_rule_snat(int index, const char *address,
655 struct nftnl_rule **res)
657 struct nftnl_rule *rule;
658 struct nftnl_expr *expr;
663 * # nft --debug netlink add rule connman nat-postrouting \
664 * oif eth0 snat 1.2.3.4
665 * ip connman nat-postrouting
666 * [ meta load oif => reg 1 ]
667 * [ cmp eq reg 1 0x0000000b ]
668 * [ immediate reg 1 0x04030201 ]
669 * [ nat snat ip addr_min reg 1 addr_max reg 0 ]
672 rule = nftnl_rule_alloc();
676 nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
677 nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_NAT_POST);
680 expr = nftnl_expr_alloc("meta");
683 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_OIF);
684 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
685 nftnl_rule_add_expr(rule, expr);
686 err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &index, sizeof(index));
691 expr = nftnl_expr_alloc("immediate");
694 snat = inet_addr(address);
695 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1);
696 nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &snat, sizeof(snat));
697 nftnl_rule_add_expr(rule, expr);
699 expr = nftnl_expr_alloc("nat");
702 nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_TYPE, NFT_NAT_SNAT);
703 nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_FAMILY, NFPROTO_IPV4);
704 nftnl_expr_set_u32(expr, NFTNL_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1);
705 nftnl_rule_add_expr(rule, expr);
711 nftnl_rule_free(rule);
715 int __connman_firewall_enable_snat(struct firewall_context *ctx,
716 int index, const char *ifname, const char *addr)
718 struct nftnl_rule *rule;
719 struct mnl_socket *nl;
724 err = socket_open_and_bind(&nl);
728 err = build_rule_snat(index, addr, &rule);
732 ctx->rule.chain = CONNMAN_CHAIN_NAT_POST;
733 err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
734 NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
735 CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
736 nftnl_rule_free(rule);
738 mnl_socket_close(nl);
742 int __connman_firewall_disable_snat(struct firewall_context *ctx)
746 return rule_delete(&ctx->rule);
749 static int build_rule_marking(uid_t uid, uint32_t mark, struct nftnl_rule **res)
751 struct nftnl_rule *rule;
752 struct nftnl_expr *expr;
756 * http://wiki.nftables.org/wiki-nftables/index.php/Setting_packet_metainformation
757 * http://wiki.nftables.org/wiki-nftables/index.php/Matching_packet_metainformation
759 * # nft --debug netlink add rule connman route-output \
760 * meta skuid wagi mark set 1234
762 * ip connman route-output
763 * [ meta load skuid => reg 1 ]
764 * [ cmp eq reg 1 0x000003e8 ]
765 * [ immediate reg 1 0x000004d2 ]
766 * [ meta set mark with reg 1 ]
769 rule = nftnl_rule_alloc();
773 nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
774 nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
776 expr = nftnl_expr_alloc("meta");
779 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_SKUID);
780 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1);
781 nftnl_rule_add_expr(rule, expr);
782 err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &uid, sizeof(uid));
786 expr = nftnl_expr_alloc("immediate");
789 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1);
790 nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &mark, sizeof(mark));
791 nftnl_rule_add_expr(rule, expr);
793 expr = nftnl_expr_alloc("meta");
796 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_MARK);
797 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG_1);
798 nftnl_rule_add_expr(rule, expr);
807 static int build_rule_src_ip(const char *src_ip, uint32_t mark, struct nftnl_rule **res)
809 struct nftnl_rule *rule;
810 struct nftnl_expr *expr;
815 * # nft --debug netlink add rule connman route-output \
816 * ip saddr 192.168.10.31 mark set 1234
818 * ip connman route-output
819 * [ payload load 4b @ network header + 12 => reg 1 ]
820 * [ cmp eq reg 1 0x1f0aa8c0 ]
821 * [ immediate reg 1 0x000004d2 ]
822 * [ meta set mark with reg 1 ]
825 rule = nftnl_rule_alloc();
829 nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, CONNMAN_TABLE);
830 nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, CONNMAN_CHAIN_ROUTE_OUTPUT);
833 nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_IPV4);
836 err = add_payload(rule, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1,
837 offsetof(struct iphdr, saddr), sizeof(struct in_addr));
841 s_addr = inet_addr(src_ip);
842 err = add_cmp(rule, NFT_REG_1, NFT_CMP_EQ, &s_addr, sizeof(s_addr));
846 expr = nftnl_expr_alloc("immediate");
849 nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG_1);
850 nftnl_expr_set(expr, NFTNL_EXPR_IMM_DATA, &mark, sizeof(mark));
851 nftnl_rule_add_expr(rule, expr);
853 expr = nftnl_expr_alloc("meta");
856 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_MARK);
857 nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG_1);
858 nftnl_rule_add_expr(rule, expr);
867 int __connman_firewall_enable_marking(struct firewall_context *ctx,
868 enum connman_session_id_type id_type,
869 char *id, const char *src_ip,
872 struct nftnl_rule *rule;
873 struct mnl_socket *nl;
880 if (id_type == CONNMAN_SESSION_ID_TYPE_UID) {
889 err = socket_open_and_bind(&nl);
893 if (id_type == CONNMAN_SESSION_ID_TYPE_UID) {
894 err = build_rule_marking(uid, mark, &rule);
898 ctx->rule.chain = CONNMAN_CHAIN_ROUTE_OUTPUT;
899 err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
900 NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
901 CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
903 nftnl_rule_free(rule);
907 err = build_rule_src_ip(src_ip, mark, &rule);
911 ctx->rule.chain = CONNMAN_CHAIN_ROUTE_OUTPUT;
912 err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
913 NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
914 CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
916 nftnl_rule_free(rule);
919 mnl_socket_close(nl);
923 int __connman_firewall_disable_marking(struct firewall_context *ctx)
929 err = rule_delete(&ctx->rule);
933 static struct nftnl_table *build_table(const char *name, uint16_t family)
935 struct nftnl_table *table;
937 table = nftnl_table_alloc();
941 nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family);
942 nftnl_table_set_str(table, NFTNL_TABLE_NAME, name);
948 static struct nftnl_chain *build_chain(const char *name, const char *table,
949 const char *type, int hooknum, int prio)
951 struct nftnl_chain *chain;
953 chain = nftnl_chain_alloc();
957 nftnl_chain_set_str(chain, NFTNL_CHAIN_TABLE, table);
958 nftnl_chain_set_str(chain, NFTNL_CHAIN_NAME, name);
961 nftnl_chain_set_str(chain, NFTNL_CHAIN_TYPE, type);
964 nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM, hooknum);
967 nftnl_chain_set_u32(chain, NFTNL_CHAIN_PRIO, prio);
972 static int create_table_and_chains(struct nftables_info *nft_info)
974 struct mnl_socket *nl;
975 struct nftnl_table *table;
976 struct nftnl_chain *chain;
982 err = socket_open_and_bind(&nl);
988 * http://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables
992 * # nft add table connman
994 table = build_table(CONNMAN_TABLE, NFPROTO_IPV4);
1000 err = table_cmd(nl, table, NFT_MSG_NEWTABLE, NFPROTO_IPV4,
1001 NLM_F_CREATE|NLM_F_ACK);
1007 * http://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
1011 * # nft add chain connman nat-prerouting \
1012 * { type nat hook prerouting priority 0 ; }
1014 chain = build_chain(CONNMAN_CHAIN_NAT_PRE, CONNMAN_TABLE,
1015 "nat", NF_INET_PRE_ROUTING, 0);
1021 err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN,
1022 NFPROTO_IPV4, NLM_F_CREATE | NLM_F_ACK,
1023 CALLBACK_RETURN_NONE, NULL);
1028 * # nft add chain connman nat-postrouting \
1029 * { type nat hook postrouting priority 0 ; }
1031 chain = build_chain(CONNMAN_CHAIN_NAT_POST, CONNMAN_TABLE,
1032 "nat", NF_INET_POST_ROUTING, 0);
1038 err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN,
1039 NFPROTO_IPV4, NLM_F_CREATE | NLM_F_ACK,
1040 CALLBACK_RETURN_NONE, NULL);
1045 * # nft add chain connman route-output \
1046 * { type route hook output priority 0 ; }
1048 chain = build_chain(CONNMAN_CHAIN_ROUTE_OUTPUT, CONNMAN_TABLE,
1049 "route", NF_INET_LOCAL_OUT, 0);
1055 err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN,
1056 NFPROTO_IPV4, NLM_F_CREATE | NLM_F_ACK,
1057 CALLBACK_RETURN_NONE, NULL);
1063 connman_warn("Failed to create basic chains: %s",
1065 mnl_socket_close(nl);
1069 static int cleanup_table_and_chains(void)
1071 struct nftnl_table *table;
1072 struct mnl_socket *nl;
1077 err = socket_open_and_bind(&nl);
1082 * Cleanup everythying in one go. There is little point in
1083 * step-by-step removal of rules and chains if you can get it
1084 * as simple as this.
1087 * # nft delete table connman
1089 table = build_table(CONNMAN_TABLE, NFPROTO_IPV4);
1090 err = table_cmd(nl, table, NFT_MSG_DELTABLE, NFPROTO_IPV4, NLM_F_ACK);
1092 mnl_socket_close(nl);
1096 int __connman_firewall_init(void)
1102 if (getenv("CONNMAN_NFTABLES_DEBUG"))
1103 debug_enabled = true;
1106 * EAFNOSUPPORT is return whenever the nf_tables_ipv4 hasn't been
1107 * loaded yet. ENOENT is return in case the table is missing.
1109 err = cleanup_table_and_chains();
1110 if (err < 0 && (err != EAFNOSUPPORT && err != -ENOENT)) {
1111 connman_warn("initializing nftable failed with '%s' %d. Check if kernel module nf_tables_ipv4 is missing\n",
1112 strerror(-err), err);
1116 nft_info = g_new0(struct nftables_info, 1);
1117 err = create_table_and_chains(nft_info);
1126 void __connman_firewall_cleanup(void)
1132 err = cleanup_table_and_chains();
1134 connman_warn("cleanup table and chains failed with '%s' %d\n",
1135 strerror(-err), err);