summaryrefslogtreecommitdiff
path: root/src/ubus.c
diff options
context:
space:
mode:
authorSeonah Moon <seonah1.moon@samsung.com>2022-01-12 16:43:03 +0900
committerSeonah Moon <seonah1.moon@samsung.com>2022-01-12 16:49:46 +0900
commitaff4fe95c96ee39f595d743b29245b5813bdece1 (patch)
tree424758e17c91dfd12845449a2061cf5cf2627b65 /src/ubus.c
parent9a9940fac7c8116d02571a84692e25396a4cfcfc (diff)
parentd08de9e4ac117490e1bc53b587ee68681ef0fbe9 (diff)
downloaddnsmasq-aff4fe95c96ee39f595d743b29245b5813bdece1.tar.gz
dnsmasq-aff4fe95c96ee39f595d743b29245b5813bdece1.tar.bz2
dnsmasq-aff4fe95c96ee39f595d743b29245b5813bdece1.zip
Change-Id: I8c4bbd0b37b8789579fb2e3ac4cdfb7472a9a114
Diffstat (limited to 'src/ubus.c')
-rw-r--r--src/ubus.c267
1 files changed, 224 insertions, 43 deletions
diff --git a/src/ubus.c b/src/ubus.c
index 5f81287..0c502ad 100644
--- a/src/ubus.c
+++ b/src/ubus.c
@@ -1,4 +1,4 @@
-/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
+/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,17 +21,44 @@
#include <libubus.h>
static struct blob_buf b;
-static int notify;
static int error_logged = 0;
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg);
+#ifdef HAVE_CONNTRACK
+enum {
+ SET_CONNMARK_ALLOWLIST_MARK,
+ SET_CONNMARK_ALLOWLIST_MASK,
+ SET_CONNMARK_ALLOWLIST_PATTERNS
+};
+static const struct blobmsg_policy set_connmark_allowlist_policy[] = {
+ [SET_CONNMARK_ALLOWLIST_MARK] = {
+ .name = "mark",
+ .type = BLOBMSG_TYPE_INT32
+ },
+ [SET_CONNMARK_ALLOWLIST_MASK] = {
+ .name = "mask",
+ .type = BLOBMSG_TYPE_INT32
+ },
+ [SET_CONNMARK_ALLOWLIST_PATTERNS] = {
+ .name = "patterns",
+ .type = BLOBMSG_TYPE_ARRAY
+ }
+};
+static int ubus_handle_set_connmark_allowlist(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg);
+#endif
+
static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj);
static const struct ubus_method ubus_object_methods[] = {
UBUS_METHOD_NOARG("metrics", ubus_handle_metrics),
+#ifdef HAVE_CONNTRACK
+ UBUS_METHOD("set_connmark_allowlist", ubus_handle_set_connmark_allowlist, set_connmark_allowlist_policy),
+#endif
};
static struct ubus_object_type ubus_object_type =
@@ -50,17 +77,16 @@ static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
(void)ctx;
my_syslog(LOG_DEBUG, _("UBus subscription callback: %s subscriber(s)"), obj->has_subscribers ? "1" : "0");
- notify = obj->has_subscribers;
}
static void ubus_destroy(struct ubus_context *ubus)
{
- // Forces re-initialization when we're reusing the same definitions later on.
- ubus_object.id = 0;
- ubus_object_type.id = 0;
-
ubus_free(ubus);
daemon->ubus = NULL;
+
+ /* Forces re-initialization when we're reusing the same definitions later on. */
+ ubus_object.id = 0;
+ ubus_object_type.id = 0;
}
static void ubus_disconnect_cb(struct ubus_context *ubus)
@@ -76,42 +102,27 @@ static void ubus_disconnect_cb(struct ubus_context *ubus)
}
}
-void ubus_init()
+char *ubus_init()
{
struct ubus_context *ubus = NULL;
int ret = 0;
- ubus = ubus_connect(NULL);
- if (!ubus)
- {
- if (!error_logged)
- {
- my_syslog(LOG_ERR, _("Cannot initialize UBus: connection failed"));
- error_logged = 1;
- }
-
- ubus_destroy(ubus);
- return;
- }
-
+ if (!(ubus = ubus_connect(NULL)))
+ return NULL;
+
ubus_object.name = daemon->ubus_name;
ret = ubus_add_object(ubus, &ubus_object);
if (ret)
{
- if (!error_logged)
- {
- my_syslog(LOG_ERR, _("Cannot add object to UBus: %s"), ubus_strerror(ret));
- error_logged = 1;
- }
ubus_destroy(ubus);
- return;
- }
-
+ return (char *)ubus_strerror(ret);
+ }
+
ubus->connection_lost = ubus_disconnect_cb;
daemon->ubus = ubus;
error_logged = 0;
- my_syslog(LOG_INFO, _("Connected to system UBus"));
+ return NULL;
}
void set_ubus_listeners()
@@ -160,6 +171,16 @@ void check_ubus_listeners()
}
}
+#define CHECK(stmt) \
+ do { \
+ int e = (stmt); \
+ if (e) \
+ { \
+ my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
+ return (UBUS_STATUS_UNKNOWN_ERROR); \
+ } \
+ } while (0)
+
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
@@ -170,36 +191,196 @@ static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj
(void)method;
(void)msg;
- blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
+ CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
for (i=0; i < __METRIC_MAX; i++)
- blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]);
+ CHECK(blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]));
- return ubus_send_reply(ctx, req, b.head);
+ CHECK(ubus_send_reply(ctx, req, b.head));
+ return UBUS_STATUS_OK;
}
+#ifdef HAVE_CONNTRACK
+static int ubus_handle_set_connmark_allowlist(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ const struct blobmsg_policy *policy = set_connmark_allowlist_policy;
+ size_t policy_len = countof(set_connmark_allowlist_policy);
+ struct allowlist *allowlists = NULL, **allowlists_pos;
+ char **patterns = NULL, **patterns_pos;
+ u32 mark, mask = UINT32_MAX;
+ size_t num_patterns = 0;
+ struct blob_attr *tb[policy_len];
+ struct blob_attr *attr;
+
+ if (blobmsg_parse(policy, policy_len, tb, blob_data(msg), blob_len(msg)))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (!tb[SET_CONNMARK_ALLOWLIST_MARK])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ mark = blobmsg_get_u32(tb[SET_CONNMARK_ALLOWLIST_MARK]);
+ if (!mark)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ if (tb[SET_CONNMARK_ALLOWLIST_MASK])
+ {
+ mask = blobmsg_get_u32(tb[SET_CONNMARK_ALLOWLIST_MASK]);
+ if (!mask || (mark & ~mask))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ }
+
+ if (tb[SET_CONNMARK_ALLOWLIST_PATTERNS])
+ {
+ struct blob_attr *head = blobmsg_data(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
+ size_t len = blobmsg_data_len(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
+ __blob_for_each_attr(attr, head, len)
+ {
+ char *pattern;
+ if (blob_id(attr) != BLOBMSG_TYPE_STRING)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ if (!(pattern = blobmsg_get_string(attr)))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ if (strcmp(pattern, "*") && !is_valid_dns_name_pattern(pattern))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ num_patterns++;
+ }
+ }
+
+ for (allowlists_pos = &daemon->allowlists; *allowlists_pos; allowlists_pos = &(*allowlists_pos)->next)
+ if ((*allowlists_pos)->mark == mark && (*allowlists_pos)->mask == mask)
+ {
+ struct allowlist *allowlists_next = (*allowlists_pos)->next;
+ for (patterns_pos = (*allowlists_pos)->patterns; *patterns_pos; patterns_pos++)
+ {
+ free(*patterns_pos);
+ *patterns_pos = NULL;
+ }
+ free((*allowlists_pos)->patterns);
+ (*allowlists_pos)->patterns = NULL;
+ free(*allowlists_pos);
+ *allowlists_pos = allowlists_next;
+ break;
+ }
+
+ if (!num_patterns)
+ return UBUS_STATUS_OK;
+
+ patterns = whine_malloc((num_patterns + 1) * sizeof(char *));
+ if (!patterns)
+ goto fail;
+ patterns_pos = patterns;
+ if (tb[SET_CONNMARK_ALLOWLIST_PATTERNS])
+ {
+ struct blob_attr *head = blobmsg_data(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
+ size_t len = blobmsg_data_len(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
+ __blob_for_each_attr(attr, head, len)
+ {
+ char *pattern;
+ if (!(pattern = blobmsg_get_string(attr)))
+ goto fail;
+ if (!(*patterns_pos = whine_malloc(strlen(pattern) + 1)))
+ goto fail;
+ strcpy(*patterns_pos++, pattern);
+ }
+ }
+
+ allowlists = whine_malloc(sizeof(struct allowlist));
+ if (!allowlists)
+ goto fail;
+ memset(allowlists, 0, sizeof(struct allowlist));
+ allowlists->mark = mark;
+ allowlists->mask = mask;
+ allowlists->patterns = patterns;
+ allowlists->next = daemon->allowlists;
+ daemon->allowlists = allowlists;
+ return UBUS_STATUS_OK;
+
+fail:
+ if (patterns)
+ {
+ for (patterns_pos = patterns; *patterns_pos; patterns_pos++)
+ {
+ free(*patterns_pos);
+ *patterns_pos = NULL;
+ }
+ free(patterns);
+ patterns = NULL;
+ }
+ if (allowlists)
+ {
+ free(allowlists);
+ allowlists = NULL;
+ }
+ return UBUS_STATUS_UNKNOWN_ERROR;
+}
+#endif
+
+#undef CHECK
+
+#define CHECK(stmt) \
+ do { \
+ int e = (stmt); \
+ if (e) \
+ { \
+ my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
+ return; \
+ } \
+ } while (0)
+
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
{
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
- int ret;
- if (!ubus || !notify)
+ if (!ubus || !ubus_object.has_subscribers)
return;
- blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
+ CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
if (mac)
- blobmsg_add_string(&b, "mac", mac);
+ CHECK(blobmsg_add_string(&b, "mac", mac));
if (ip)
- blobmsg_add_string(&b, "ip", ip);
+ CHECK(blobmsg_add_string(&b, "ip", ip));
if (name)
- blobmsg_add_string(&b, "name", name);
+ CHECK(blobmsg_add_string(&b, "name", name));
if (interface)
- blobmsg_add_string(&b, "interface", interface);
+ CHECK(blobmsg_add_string(&b, "interface", interface));
+
+ CHECK(ubus_notify(ubus, &ubus_object, type, b.head, -1));
+}
+
+#ifdef HAVE_CONNTRACK
+void ubus_event_bcast_connmark_allowlist_refused(u32 mark, const char *name)
+{
+ struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
+
+ if (!ubus || !ubus_object.has_subscribers)
+ return;
+
+ CHECK(blob_buf_init(&b, 0));
+ CHECK(blobmsg_add_u32(&b, "mark", mark));
+ CHECK(blobmsg_add_string(&b, "name", name));
+
+ CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.refused", b.head, -1));
+}
+
+void ubus_event_bcast_connmark_allowlist_resolved(u32 mark, const char *name, const char *value, u32 ttl)
+{
+ struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
+
+ if (!ubus || !ubus_object.has_subscribers)
+ return;
+
+ CHECK(blob_buf_init(&b, 0));
+ CHECK(blobmsg_add_u32(&b, "mark", mark));
+ CHECK(blobmsg_add_string(&b, "name", name));
+ CHECK(blobmsg_add_string(&b, "value", value));
+ CHECK(blobmsg_add_u32(&b, "ttl", ttl));
- ret = ubus_notify(ubus, &ubus_object, type, b.head, -1);
- if (!ret)
- my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
+ /* Set timeout to allow UBus subscriber to configure firewall rules before returning. */
+ CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.resolved", b.head, /* timeout: */ 1000));
}
+#endif
+#undef CHECK
#endif /* HAVE_UBUS */