version 1.1.1.1, 2021/03/17 00:56:46
|
version 1.1.1.2, 2023/09/27 11:02:07
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
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 |
it under the terms of the GNU General Public License as published by |
Line 21
|
Line 21
|
#include <libubus.h> |
#include <libubus.h> |
|
|
static struct blob_buf b; |
static struct blob_buf b; |
static int notify; |
|
static int error_logged = 0; |
static int error_logged = 0; |
|
|
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj, |
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj, |
struct ubus_request_data *req, const char *method, |
struct ubus_request_data *req, const char *method, |
struct blob_attr *msg); |
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 void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj); |
|
|
static const struct ubus_method ubus_object_methods[] = { |
static const struct ubus_method ubus_object_methods[] = { |
UBUS_METHOD_NOARG("metrics", ubus_handle_metrics), |
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 = |
static struct ubus_object_type ubus_object_type = |
Line 50 static void ubus_subscribe_cb(struct ubus_context *ctx
|
Line 77 static void ubus_subscribe_cb(struct ubus_context *ctx
|
(void)ctx; |
(void)ctx; |
|
|
my_syslog(LOG_DEBUG, _("UBus subscription callback: %s subscriber(s)"), obj->has_subscribers ? "1" : "0"); |
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) |
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); |
ubus_free(ubus); |
daemon->ubus = NULL; |
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) |
static void ubus_disconnect_cb(struct ubus_context *ubus) |
Line 76 static void ubus_disconnect_cb(struct ubus_context *ub
|
Line 102 static void ubus_disconnect_cb(struct ubus_context *ub
|
} |
} |
} |
} |
|
|
void ubus_init() | char *ubus_init() |
{ |
{ |
struct ubus_context *ubus = NULL; |
struct ubus_context *ubus = NULL; |
int ret = 0; |
int ret = 0; |
|
|
ubus = ubus_connect(NULL); | if (!(ubus = ubus_connect(NULL))) |
if (!ubus) | return NULL; |
{ | |
if (!error_logged) | |
{ | |
my_syslog(LOG_ERR, _("Cannot initialize UBus: connection failed")); | |
error_logged = 1; | |
} | |
| |
ubus_destroy(ubus); | |
return; | |
} | |
| |
ubus_object.name = daemon->ubus_name; |
ubus_object.name = daemon->ubus_name; |
ret = ubus_add_object(ubus, &ubus_object); |
ret = ubus_add_object(ubus, &ubus_object); |
if (ret) |
if (ret) |
{ |
{ |
if (!error_logged) |
|
{ |
|
my_syslog(LOG_ERR, _("Cannot add object to UBus: %s"), ubus_strerror(ret)); |
|
error_logged = 1; |
|
} |
|
ubus_destroy(ubus); |
ubus_destroy(ubus); |
return; | return (char *)ubus_strerror(ret); |
} | } |
| |
ubus->connection_lost = ubus_disconnect_cb; |
ubus->connection_lost = ubus_disconnect_cb; |
daemon->ubus = ubus; |
daemon->ubus = ubus; |
error_logged = 0; |
error_logged = 0; |
|
|
my_syslog(LOG_INFO, _("Connected to system UBus")); | return NULL; |
} |
} |
|
|
void set_ubus_listeners() |
void set_ubus_listeners() |
Line 160 void check_ubus_listeners()
|
Line 171 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, |
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj, |
struct ubus_request_data *req, const char *method, |
struct ubus_request_data *req, const char *method, |
struct blob_attr *msg) |
struct blob_attr *msg) |
Line 170 static int ubus_handle_metrics(struct ubus_context *ct
|
Line 191 static int ubus_handle_metrics(struct ubus_context *ct
|
(void)method; |
(void)method; |
(void)msg; |
(void)msg; |
|
|
blob_buf_init(&b, BLOBMSG_TYPE_TABLE); | CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE)); |
|
|
for (i=0; i < __METRIC_MAX; i++) |
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) |
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; |
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus; |
int ret; |
|
|
|
if (!ubus || !notify) | if (!ubus || !ubus_object.has_subscribers) |
return; |
return; |
|
|
blob_buf_init(&b, BLOBMSG_TYPE_TABLE); | CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE)); |
if (mac) |
if (mac) |
blobmsg_add_string(&b, "mac", mac); | CHECK(blobmsg_add_string(&b, "mac", mac)); |
if (ip) |
if (ip) |
blobmsg_add_string(&b, "ip", ip); | CHECK(blobmsg_add_string(&b, "ip", ip)); |
if (name) |
if (name) |
blobmsg_add_string(&b, "name", name); | CHECK(blobmsg_add_string(&b, "name", name)); |
if (interface) |
if (interface) |
blobmsg_add_string(&b, "interface", interface); | CHECK(blobmsg_add_string(&b, "interface", interface)); |
|
|
ret = ubus_notify(ubus, &ubus_object, type, b.head, -1); | CHECK(ubus_notify(ubus, &ubus_object, type, b.head, -1)); |
if (!ret) | |
my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret)); | |
} |
} |
|
|
|
#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)); |
|
|
|
/* 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 */ |
#endif /* HAVE_UBUS */ |