Send connman mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
https://lists.01.org/mailman/listinfo/connman
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of connman digest..."
Today's Topics:
1. [PATCH] Remove old ip/gateway address if different addresses
are assigned during DHCP renewal to avoid two ip addresses added
to the interface. (Feng Wang)
2. Re: [PATCH v2 6/6] firewall-nftables: Add nftable support for
firewall (Dragos Tatulea)
----------------------------------------------------------------------
Message: 1
Date: Mon, 25 Apr 2016 16:34:00 -0700
From: Feng Wang <[email protected]>
To: [email protected]
Subject: [PATCH] Remove old ip/gateway address if different addresses
are assigned during DHCP renewal to avoid two ip addresses added to
the interface.
Message-ID: <[email protected]>
---
src/dhcp.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/src/dhcp.c b/src/dhcp.c
index 1d2cd48..54d98db 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -435,7 +435,7 @@ static void lease_available_cb(GDHCPClient *dhcp_client,
gpointer user_data)
char *address, *netmask = NULL, *gateway = NULL;
const char *c_address, *c_gateway;
unsigned char prefixlen, c_prefixlen;
- bool ip_change;
+ bool ip_change = false;
DBG("Lease available");
@@ -467,14 +467,21 @@ static void lease_available_cb(GDHCPClient *dhcp_client,
gpointer user_data)
DBG("c_address %s", c_address);
- if (g_strcmp0(address, c_address))
+ if (g_strcmp0(address, c_address)) {
ip_change = true;
- else if (g_strcmp0(gateway, c_gateway))
+ if (c_address) {
+ /* Remove old ip address */
+ __connman_ipconfig_address_remove(dhcp->ipconfig);
+ }
+ }
+ if (g_strcmp0(gateway, c_gateway)) {
ip_change = true;
- else if (prefixlen != c_prefixlen)
+ if (c_gateway) {
+ /* Remove gateway ip address */
+ __connman_ipconfig_gateway_remove(dhcp->ipconfig);
+ }
+ } else if (prefixlen != c_prefixlen)
ip_change = true;
- else
- ip_change = false;
__connman_ipconfig_set_method(dhcp->ipconfig,
CONNMAN_IPCONFIG_METHOD_DHCP);
--
2.8.0.rc3.226.g39d4020
------------------------------
Message: 2
Date: Tue, 26 Apr 2016 10:37:04 +0200
From: Dragos Tatulea <[email protected]>
To: Daniel Wagner <[email protected]>, [email protected]
Subject: Re: [PATCH v2 6/6] firewall-nftables: Add nftable support for
firewall
Message-ID: <[email protected]>
Content-Type: text/plain; charset=windows-1252
Hi Daniel,
On 04/22/2016 02:34 PM, Daniel Wagner wrote:
> From: Daniel Wagner <[email protected]>
>
> A straight forward implementation for the firewall API. It is based
> on the libntfnl examples and Daniel Macks' systemd implementation.
>
> There are some comment how to use/extend this code, that is
> 'nft --debug' your friend. Also check the libnftnl examples for more
> details.
> ---
> src/firewall-nftables.c | 1089
> ++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 1081 insertions(+), 8 deletions(-)
>
> diff --git a/src/firewall-nftables.c b/src/firewall-nftables.c
> index df578fa..cedfc28 100644
> --- a/src/firewall-nftables.c
> +++ b/src/firewall-nftables.c
> @@ -19,63 +19,1136 @@
> *
> */
>
> +/*
> + * This file is based on the libnftnl examples:
> + * https://git.netfilter.org/libnftnl/tree/examples
> + * by Pablo Neira Ayuso. and inspiration from systemd nft implemention
> + *
> https://github.com/zonque/systemd/blob/rfc-nftnl/src/shared/firewall-util.c
> + * by Daniel Mack.
> + */
> +
> #ifdef HAVE_CONFIG_H
> #include <config.h>
> #endif
>
> +#include <stdlib.h>
> +#include <time.h>
> +#include <string.h>
> #include <errno.h>
> +#include <stdint.h>
> +#include <alloca.h>
> +#include <netinet/in.h>
> +#include <netinet/ip.h>
> +
> +#include <sys/types.h>
> +#include <pwd.h>
> +
> +#include <sys/socket.h>
> +#include <netinet/in.h>
> +#include <arpa/inet.h>
> +
> +#include <linux/netfilter.h>
> +#include <linux/netfilter/nfnetlink.h>
> +#include <linux/netfilter/nf_nat.h>
> +#include <linux/netfilter/nf_tables.h>
> +
> +#include <libmnl/libmnl.h>
> +#include <libnftnl/table.h>
> +#include <libnftnl/chain.h>
> +#include <libnftnl/rule.h>
> +#include <libnftnl/expr.h>
> +
> +#include <glib.h>
>
> #include "connman.h"
>
> +#define CONNMAN_TABLE "connman"
> +#define CONNMAN_CHAIN_NAT_PRE "nat-prerouting"
> +#define CONNMAN_CHAIN_NAT_POST "nat-postrouting"
> +#define CONNMAN_CHAIN_FILTER_OUTPUT "filter-output"
> +
> +static bool debug_enabled = true;
> +
> +struct firewall_handle {
> + uint64_t handle;
> + const char *chain;
> +};
> +
> +struct firewall_context {
> + struct firewall_handle rule;
> +};
> +
> +struct nftables_info {
> + struct firewall_handle filter;
> + struct firewall_handle nat;
> +
> + struct firewall_handle ct;
> + unsigned int mark_ref;
> +};
> +static struct nftables_info *nft_info;
> +
> +enum callback_return_type {
> + CALLBACK_RETURN_UNDEF,
> + CALLBACK_RETURN_HANDLE,
> + CALLBACK_RETURN_BYTE_COUNTER,
> + _CALLBACK_RETURN_MAX,
> +};
> +
> +struct callback_data {
> + enum callback_return_type type;
> + uint64_t value;
> + bool success;
> +};
> +
> +static void debug_netlink_dump_rule(struct nftnl_rule *nlr)
> +{
> + char buf[4096];
> +
> + if (!debug_enabled)
> + return;
> +
> + nftnl_rule_snprintf(buf, sizeof(buf), nlr, 0, 0);
> + fprintf(stdout, "%s\n", buf);
> +}
> +
> +static void debug_mnl_dump_rule(const void *req, size_t req_size)
> +{
> + if (!debug_enabled)
> + return;
> +
> + mnl_nlmsg_fprintf(stdout, req, req_size, 0);
> + printf("\n");
> +}
> +
> +static int rule_expr_cb(struct nftnl_expr *expr, void *data) {
> +
> + struct callback_data *cb = data;
> + const char *name;
> +
> + name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
> +
> + if (strcmp(name, "counter")) {
> + cb->value = nftnl_expr_get_u64(expr, NFTNL_EXPR_CTR_BYTES);
> + cb->success = true;
> + }
> +
> + return 0;
> +}
> +
> +static int rule_cb(const struct nlmsghdr *nlh, int event,
> + struct callback_data *cb)
> +{
> + struct nftnl_rule *rule;
> +
> + rule = nftnl_rule_alloc();
> + if (!rule)
> + return MNL_CB_OK;
> +
> + if (nftnl_rule_nlmsg_parse(nlh, rule) < 0)
> + goto out;
> +
> + switch (cb->type) {
> + case CALLBACK_RETURN_HANDLE:
> + cb->value = nftnl_rule_get_u64(rule, NFTNL_RULE_HANDLE);
> + cb->success = true;
> + break;
> +
> + case CALLBACK_RETURN_BYTE_COUNTER:
> + nftnl_expr_foreach(rule, rule_expr_cb, cb);
> + break;
> +
> + default:
> + DBG("unhandled callback type %d\n", cb->type);
> + break;
> + }
> +
> +out:
> + nftnl_rule_free(rule);
> + return MNL_CB_STOP;
> +}
> +
> +static int chain_cb(const struct nlmsghdr *nlh, int event,
> + struct callback_data *cb)
> +{
> + struct nftnl_chain *chain;
> +
> + chain = nftnl_chain_alloc();
> + if (!chain)
> + return MNL_CB_OK;
> +
> + if (nftnl_chain_nlmsg_parse(nlh, chain) < 0)
> + goto out;
> +
> + switch (cb->type) {
> + case CALLBACK_RETURN_HANDLE:
> + cb->value = nftnl_chain_get_u64(chain, NFTNL_CHAIN_HANDLE);
> + cb->success = true;
> + break;
> +
> + default:
> + DBG("unhandled callback type %d\n", cb->type);
> + break;
> + }
> +
> +out:
> + nftnl_chain_free(chain);
> + return MNL_CB_OK;
> +}
> +
> +static const char *event_to_str(enum nf_tables_msg_types type)
> +{
> + const char *table[] = {
> + "NFT_MSG_NEWTABLE",
> + "NFT_MSG_GETTABLE",
> + "NFT_MSG_DELTABLE",
> + "NFT_MSG_NEWCHAIN",
> + "NFT_MSG_GETCHAIN",
> + "NFT_MSG_DELCHAIN",
> + "NFT_MSG_NEWRULE",
> + "NFT_MSG_GETRULE",
> + "NFT_MSG_DELRULE",
> + "NFT_MSG_NEWSET",
> + "NFT_MSG_GETSET",
> + "NFT_MSG_DELSET",
> + "NFT_MSG_NEWSETELEM",
> + "NFT_MSG_GETSETELEM",
> + "NFT_MSG_DELSETELEM",
> + "NFT_MSG_NEWGEN",
> + "NFT_MSG_GETGEN",
> + "NFT_MSG_TRACE"
> + };
> +
> + if (type < sizeof(table)/sizeof(table[0]))
> + return table[type];
> +
> + return "unknown";
> +}
> +
> +static int events_cb(const struct nlmsghdr *nlh, void *data)
> +{
> + int event = NFNL_MSG_TYPE(nlh->nlmsg_type);
> + struct callback_data *cb = data;
> + int err = MNL_CB_OK;
> +
> + if (!cb || cb->type == CALLBACK_RETURN_UNDEF)
> + return err;
> +
> + DBG("handle event %s", event_to_str(event));
> +
> + switch(event) {
> + case NFT_MSG_NEWCHAIN:
> + err = chain_cb(nlh, event, cb);
> + break;
> +
> + case NFT_MSG_NEWRULE:
> + err = rule_cb(nlh, event, cb);
> + break;
> + default:
> + DBG("unhandled event type %s", event_to_str(event));
> + break;
> + }
> +
> + return err;
> +}
> +
> +static int socket_open_and_bind(struct mnl_socket **n)
> +{
> +
> + struct mnl_socket *nl = NULL;
> + int err;
> +
> + nl = mnl_socket_open(NETLINK_NETFILTER);
> + if (!nl)
> + return -errno;
> +
> + err = mnl_socket_bind(nl, 1 << (NFNLGRP_NFTABLES-1),
> + MNL_SOCKET_AUTOPID);
> + if (err < 0) {
> + mnl_socket_close(nl);
> + return -errno;
> + }
> +
> + *n = nl;
> + return 0;
> +}
> +
> +static int send_and_dispatch(struct mnl_socket *nl, const void *req,
> + size_t req_size, enum callback_return_type callback_type,
> + uint64_t *callback_value)
> +{
> + struct callback_data cb = {};
> + uint32_t portid;
> + int err;
> +
> + debug_mnl_dump_rule(req, req_size);
> +
> + err = mnl_socket_sendto(nl, req, req_size);
> + if (err < 0)
> + return -errno;
> +
> + portid = mnl_socket_get_portid(nl);
> + cb.type = callback_type;
> +
> + for (;;) {
> + char buf[MNL_SOCKET_BUFFER_SIZE];
> +
> + err = mnl_socket_recvfrom(nl, buf, sizeof(buf));
> + if (err <= 0)
> + break;
> +
> + err = mnl_cb_run(buf, err, 0, portid, events_cb, &cb);
> + if (err <= 0)
> + break;
> + }
> +
> + if (err < 0)
> + return -errno;
> +
> + if (callback_type == CALLBACK_RETURN_UNDEF)
> + return 0;
> +
> + if (cb.success) {
> + if (callback_value)
> + *callback_value = cb.value;
> +
> + return 0;
> + }
> +
> + return -ENOENT;
> +}
> +
> +static void put_batch_headers(char *buf, uint16_t type, uint32_t seq)
> +{
> +
> + struct nlmsghdr *nlh;
> + struct nfgenmsg *nfg;
> +
> + nlh = mnl_nlmsg_put_header(buf);
> + nlh->nlmsg_type = type;
> + nlh->nlmsg_flags = NLM_F_REQUEST;
> + nlh->nlmsg_seq = seq;
> +
> + nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
> + nfg->nfgen_family = AF_INET;
> + nfg->version = NFNETLINK_V0;
> + nfg->res_id = NFNL_SUBSYS_NFTABLES;
> +}
> +
> +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 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 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, NFT_EXPR_CMP_SREG, sreg);
> + nftnl_expr_set_u32(expr, NFT_EXPR_CMP_OP, op);
> + nftnl_expr_set(expr, NFT_EXPR_CMP_DATA, data, data_len);
> +
> + nftnl_rule_add_expr(rule, expr);
> +
> + return 0;
> +}
> +
> +static int table_cmd(struct mnl_socket *nl, struct nftnl_table *t,
> + uint16_t cmd, uint16_t family, uint16_t type)
> +{
> + char buf[MNL_SOCKET_BUFFER_SIZE];
> + struct mnl_nlmsg_batch *batch;
> + struct nlmsghdr *nlh;
> + uint32_t seq = 0;
> + int err;
> +
> + batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
> + nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
> + mnl_nlmsg_batch_next(batch);
> +
> + nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
> + cmd, family, type, seq++);
> + nftnl_table_nlmsg_build_payload(nlh, t);
> + nftnl_table_free(t);
> + mnl_nlmsg_batch_next(batch);
> +
> + nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
> + mnl_nlmsg_batch_next(batch);
> +
> + /* The current table commands do not support any callback returns. */
> + err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
> + mnl_nlmsg_batch_size(batch), 0, NULL);
> + if (err < 0)
> + return err;
> +
> + mnl_nlmsg_batch_stop(batch);
> +
> + return 0;
> +}
> +
> +static int chain_cmd(struct mnl_socket *nl, struct nftnl_chain *chain,
> + uint16_t cmd, int family, uint16_t type,
> + enum callback_return_type cb_type, uint64_t *cb_val)
> +{
> + char buf[MNL_SOCKET_BUFFER_SIZE];
> + struct mnl_nlmsg_batch *batch;
> + struct nlmsghdr *nlh;
> + uint32_t seq = 0;
> + int err;
> +
> + batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
> + nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
> + mnl_nlmsg_batch_next(batch);
> +
> + nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
> + cmd, family, type, seq++);
> + nftnl_chain_nlmsg_build_payload(nlh, chain);
> + nftnl_chain_free(chain);
> + mnl_nlmsg_batch_next(batch);
> +
> + nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
> + mnl_nlmsg_batch_next(batch);
> +
> + err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
> + mnl_nlmsg_batch_size(batch), cb_type, cb_val);
> + if (err < 0)
> + return err;
> +
> + mnl_nlmsg_batch_stop(batch);
> +
> + return 0;
> +}
> +
> +static int rule_cmd(struct mnl_socket *nl, struct nftnl_rule *rule,
> + uint16_t cmd, uint16_t family, uint16_t type,
> + enum callback_return_type callback_type,
> + uint64_t *callback_value)
> +{
> +
> + char buf[MNL_SOCKET_BUFFER_SIZE];
> + struct mnl_nlmsg_batch *batch;
> + struct nlmsghdr *nlh;
> + uint32_t seq = 0;
> + int err;
> +
> + debug_netlink_dump_rule(rule);
> +
> + batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
> + put_batch_headers(mnl_nlmsg_batch_current(batch),
> + NFNL_MSG_BATCH_BEGIN, seq++);
> + mnl_nlmsg_batch_next(batch);
> +
> + nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
> + cmd, family, type, seq++);
> + nftnl_rule_nlmsg_build_payload(nlh, rule);
> + mnl_nlmsg_batch_next(batch);
> +
> + put_batch_headers(mnl_nlmsg_batch_current(batch),
> + NFNL_MSG_BATCH_END, seq++);
> + mnl_nlmsg_batch_next(batch);
> +
> + err = send_and_dispatch(nl, mnl_nlmsg_batch_head(batch),
> + mnl_nlmsg_batch_size(batch),
> + callback_type, callback_value);
> + mnl_nlmsg_batch_stop(batch);
> +
> + return err;
> +}
> +
> +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;
> +}
> +
> struct firewall_context *__connman_firewall_create(void)
> {
> - return NULL;
> + struct firewall_context *ctx;
> +
> + DBG("");
> +
> + ctx = g_new0(struct firewall_context, 1);
> +
> + return ctx;
> }
>
> void __connman_firewall_destroy(struct firewall_context *ctx)
> {
> + DBG("");
> +
> + g_free(ctx);
> +}
> +
> +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, NFT_EXPR_META_KEY, NFT_META_OIFNAME);
> + nftnl_expr_set_u32(expr, NFT_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);
> +
> + 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;
> }
>
> int __connman_firewall_enable_nat(struct firewall_context *ctx,
> char *address, unsigned char prefixlen,
> char *interface)
> {
> - return -EPROTONOSUPPORT;
> + struct mnl_socket *nl;
> + struct nftnl_rule *rule;
> + int err;
> +
> + DBG("address %s/%d interface %s", address, (int)prefixlen, interface);
> +
> + err = socket_open_and_bind(&nl);
> + if (err < 0)
> + return err;
> +
> + err = build_rule_nat(address, prefixlen, interface, &rule);
> + if (err)
> + goto out;
> +
> + ctx->rule.chain = CONNMAN_CHAIN_NAT_POST;
> + err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
> + NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
> + CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
> + nftnl_rule_free(rule);
> +out:
> + mnl_socket_close(nl);
> + return err;
> }
>
> int __connman_firewall_disable_nat(struct firewall_context *ctx)
> {
> - return -EPROTONOSUPPORT;
> + return rule_delete(&ctx->rule);
> +}
> +
> +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);
> +
> + /* IOF */
> + expr = nftnl_expr_alloc("meta");
> + if (!expr)
> + goto err;
> + nftnl_expr_set_u32(expr, NFT_EXPR_META_KEY, NFT_META_OIF);
> + nftnl_expr_set_u32(expr, NFT_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;
> }
>
> int __connman_firewall_enable_snat(struct firewall_context *ctx,
> int index, const char *ifname, const char *addr)
> {
> - return -EPROTONOSUPPORT;
> + struct nftnl_rule *rule;
> + struct mnl_socket *nl;
> + int err;
> +
> + DBG("");
> +
> + err = socket_open_and_bind(&nl);
> + if (err < 0)
> + return err;
> +
> + err = build_rule_snat(index, addr, &rule);
> + if (err)
> + goto out;
> +
> + ctx->rule.chain = CONNMAN_CHAIN_NAT_POST;
> + err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
> + NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
> + CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
> + nftnl_rule_free(rule);
> +out:
> + mnl_socket_close(nl);
> + return err;
> }
>
> int __connman_firewall_disable_snat(struct firewall_context *ctx)
> {
> - return -EPROTONOSUPPORT;
> + DBG("");
> +
> + return rule_delete(&ctx->rule);
> +}
> +
> +static int build_rule_ct(struct nftnl_rule **res)
> +{
> + struct nftnl_rule *rule;
> + struct nftnl_expr *expr;
> +
> + /*
> + *
> 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 filter-output \
> + * ct mark set mark
> + *
> + * ip connman filter-output
> + * [ meta load mark => reg 1 ]
> + * [ ct 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_FILTER_OUTPUT);
> +
> + 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_DREG, NFT_REG_1);
> + nftnl_rule_add_expr(rule, expr);
> +
> + expr = nftnl_expr_alloc("ct");
> + if (!expr)
> + goto err;
> + nftnl_expr_set_u32(expr, NFTNL_EXPR_CT_KEY, NFT_CT_MARK);
> + nftnl_expr_set_u32(expr, NFTNL_EXPR_CT_SREG, NFT_REG_1);
> + nftnl_rule_add_expr(rule, expr);
> +
> + *res = rule;
> + return 0;
> +
> +err:
> + nftnl_rule_free(rule);
> + return -ENOMEM;
> +}
> +
> +static int ct_enable(void)
> +{
> + struct nftnl_rule *rule;
> + struct mnl_socket *nl;
> + int err;
> +
> + DBG("");
> +
> + if (nft_info->mark_ref > 0)
> + return 0;
> +
> + err = socket_open_and_bind(&nl);
> + if (err < 0)
> + return err;
> +
> + err = build_rule_ct(&rule);
> + if (err < 0)
> + goto out;
> +
> + nft_info->ct.chain = CONNMAN_CHAIN_FILTER_OUTPUT;
> + err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
> + NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
> + CALLBACK_RETURN_HANDLE, &nft_info->ct.handle);
> + nftnl_rule_free(rule);
> +
> + if (!err)
> + nft_info->mark_ref++;
> +out:
> + mnl_socket_close(nl);
> + return err;
> +}
> +
> +static int ct_disable(void)
> +{
> + nft_info->mark_ref--;
> + if (nft_info->mark_ref > 0)
> + return 0;
> +
> + return rule_delete(&nft_info->ct);
> +}
> +
> +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 filter-output \
> + * meta skuid wagi mark set 1234
> + *
> + * ip connman filter-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_FILTER_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 __connman_firewall_enable_marking(struct firewall_context *ctx,
> enum connman_session_id_type id_type,
> char *id, uint32_t mark)
> {
> - return -EPROTONOSUPPORT;
> + struct nftnl_rule *rule;
> + struct mnl_socket *nl;
> + struct passwd *pw;
> + uid_t uid;
> + int err;
> +
> + DBG("");
> +
> +
> + if (id_type != CONNMAN_SESSION_ID_TYPE_UID)
> + return -ENOTSUP;
> +
> + pw = getpwnam(id);
> + if (!pw)
> + return -EINVAL;
> + uid = pw->pw_uid;
> +
> + err = ct_enable();
> + if (err)
> + return err;
> +
> + err = socket_open_and_bind(&nl);
> + if (err < 0)
> + return err;
> +
> + err = build_rule_marking(uid, mark, &rule);
> + if (err < 0)
> + goto out;
> +
> + ctx->rule.chain = CONNMAN_CHAIN_FILTER_OUTPUT;
> + err = rule_cmd(nl, rule, NFT_MSG_NEWRULE, NFPROTO_IPV4,
> + NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK,
> + CALLBACK_RETURN_HANDLE, &ctx->rule.handle);
> +
> + nftnl_rule_free(rule);
> +out:
> + if (err)
> + ct_disable();
> + mnl_socket_close(nl);
> + return err;
> }
>
> int __connman_firewall_disable_marking(struct firewall_context *ctx)
> {
> - return -EPROTONOSUPPORT;
> + int err;
> +
> + DBG("");
> +
> + err = rule_delete(&ctx->rule);
> + ct_disable();
> + return err;
> +}
> +
> +static struct nftnl_table *build_table(const char *name, uint16_t family)
> +{
> + struct nftnl_table *table;
> +
> + table = nftnl_table_alloc();
> + if (!table)
> + return NULL;
> +
> + nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family);
> + nftnl_table_set_str(table, NFTNL_TABLE_NAME, name);
> +
> + return table;
> +}
> +
> +
> +static struct nftnl_chain *build_chain(const char *name, const char *table,
> + const char *type, int hooknum, int prio)
> +{
> + struct nftnl_chain *chain;
> +
> + chain = nftnl_chain_alloc();
> + if (!chain)
> + return NULL;
> +
> + nftnl_chain_set(chain, NFTNL_CHAIN_TABLE, table);
> + nftnl_chain_set(chain, NFTNL_CHAIN_NAME, name);
> +
> + if (type)
> + nftnl_chain_set_str(chain, NFTNL_CHAIN_TYPE, type);
> +
> + if (hooknum >= 0)
> + nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM, hooknum);
> +
> + if (prio >= 0)
> + nftnl_chain_set_u32(chain, NFTNL_CHAIN_PRIO, prio);
> +
> + return chain;
> +}
> +
> +static int create_table_and_chains(struct nftables_info *nft_info)
> +{
> + struct mnl_socket *nl;
> + struct nftnl_table *table;
> + struct nftnl_chain *chain;
> + int err;
> +
> +
> + DBG("");
> +
> + err = socket_open_and_bind(&nl);
> + if (err < 0)
> + return err;
> +
> + /*
> + * Add table
> + * http://wiki.nftables.org/wiki-nftables/index.php/Configuring_tables
> + */
> +
> + /*
> + * # nft add table connman
> + */
> + table = build_table(CONNMAN_TABLE, NFPROTO_IPV4);
> + if (!table) {
> + err = -ENOMEM;
> + goto out;
> + }
> +
> + err = table_cmd(nl, table, NFT_MSG_NEWTABLE, NFPROTO_IPV4,
> NLM_F_ACK);
> + if (err < 0)
> + goto out;
> +
> + /*
> + * Add basic chains
> + * http://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
> + */
> +
> + /*
> + * # nft add chain connman nat-prerouting \
> + * { type nat hook prerouting priortiy 0 ; }
> + */
> + chain = build_chain(CONNMAN_CHAIN_NAT_PRE, CONNMAN_TABLE,
> + "nat", NF_INET_PRE_ROUTING, 0);
> + if (!chain) {
> + err = -ENOMEM;
> + goto out;
> + }
> +
> + nft_info->nat.chain = CONNMAN_CHAIN_NAT_PRE;
> + err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN, NFPROTO_IPV4, NLM_F_ACK,
> + CALLBACK_RETURN_HANDLE, &nft_info->nat.handle);
> + if (err < 0)
> + goto out;
> +
> + /*
> + * # nft add chain connman nat-postrouting \
> + * { type nat hook postrouting priortiy 0 ; }
> + */
> + chain = build_chain(CONNMAN_CHAIN_NAT_POST, CONNMAN_TABLE,
> + "nat", NF_INET_POST_ROUTING, 0);
> + if (!chain) {
> + err = -ENOMEM;
> + goto out;
> + }
> +
> + nft_info->nat.chain = CONNMAN_CHAIN_NAT_POST;
> + err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN, NFPROTO_IPV4, NLM_F_ACK,
> + CALLBACK_RETURN_HANDLE, &nft_info->nat.handle);
This returns ENOENT for me (4.4.6 kernel, libnftnl-1.0.5).
> + if (err < 0)
> + goto out;
> +
> + /*
> + * # nft add chain connman filter-output \
> + * { type filter hook output priority 0 ; }
> + */
> + chain = build_chain(CONNMAN_CHAIN_FILTER_OUTPUT, CONNMAN_TABLE,
> + "filter", NF_INET_LOCAL_OUT, 0);
> + if (!chain) {
> + err = -ENOMEM;
> + goto out;
> + }
> +
> + nft_info->filter.chain = CONNMAN_CHAIN_FILTER_OUTPUT;
> + err = chain_cmd(nl, chain, NFT_MSG_NEWCHAIN, NFPROTO_IPV4, NLM_F_ACK,
> + CALLBACK_RETURN_HANDLE, &nft_info->filter.handle);
> + if (err < 0)
> + goto out;
> +
> +out:
> + if (err)
> + connman_warn("Failed to create basic chains: %s",
> + strerror(-err));
> + mnl_socket_close(nl);
> + return err;
> +}
> +
> +static int cleanup_table_and_chains(void)
> +{
> + struct nftnl_table *table;
> + struct mnl_socket *nl;
> + int err;
> +
> + DBG("");
> +
> + err = socket_open_and_bind(&nl);
> + if (err < 0)
> + return -ENOMEM;
> +
> + /*
> + * Cleanup everythying in one go. There is little point in
> + * step-by-step removal of rules and chains if you can get it
> + * as simple as this.
> + */
> + /*
> + * # nft delete table connman
> + */
> + table = build_table(CONNMAN_TABLE, NFPROTO_IPV4);
> + err = table_cmd(nl, table, NFT_MSG_DELTABLE, NFPROTO_IPV4, NLM_F_ACK);
> +
> + mnl_socket_close(nl);
> + return err;
> }
>
> int __connman_firewall_init(void)
> {
> - return 0;
> + int err;
> +
> + DBG("");
> +
> + if (getenv("CONNMAN_NFTABLES_DEBUG"))
> + debug_enabled = true;
> +
> + /*
> + * EAFNOSUPPORT is return whenever the nf_tables_ipv4 hasn't been
> + * loaded yet. ENOENT is return in case the table is missing.
> + */
> + err = cleanup_table_and_chains();
> + if (err < 0 && (err != EAFNOSUPPORT || err != -ENOENT))
This doesn't work. Changed it to:
if (err < 0 && (err != -EAFNOSUPPORT && err != -ENOENT)
> + return err;
> +
> + nft_info = g_new0(struct nftables_info, 1);
> + err = create_table_and_chains(nft_info);
> + if (err) {
> + g_free(nft_info);
> + nft_info = NULL;
> + }
> +
> + return err;
> }
>
> void __connman_firewall_cleanup(void)
> {
> + int err;
> +
> + DBG("");
> +
> + err = cleanup_table_and_chains();
> + if (err < 0)
> + printf("cleanup table and chains failed with '%s' %d\n",
> + strerror(-err), err);
> +
> + g_free(nft_info);
> + nft_info = NULL;
> }
>
Thanks
--
Dragos Tatulea
Software Developer @ Endocode AG
[email protected]
Endocode AG, Br?ckenstra?e 5A, 10179 Berlin
+49 30 1206 4472 | [email protected] | www.endocode.com
Vorstandsvorsitzender: Mirko Boehm
Vorst?nde: Dr. Thomas Fricke, Sebastian Sucker
Aufsichtsratsvorsitzende: Alexandra Boehm
Registergericht: Amtsgericht Charlottenburg - HRB 150748 B
------------------------------
Subject: Digest Footer
_______________________________________________
connman mailing list
[email protected]
https://lists.01.org/mailman/listinfo/connman
------------------------------
End of connman Digest, Vol 6, Issue 19
**************************************