Annotation of embedaddon/dnsmasq/src/ubus.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1 misho 2:
3: This program is free software; you can redistribute it and/or modify
4: it under the terms of the GNU General Public License as published by
5: the Free Software Foundation; version 2 dated June, 1991, or
6: (at your option) version 3 dated 29 June, 2007.
7:
8: This program is distributed in the hope that it will be useful,
9: but WITHOUT ANY WARRANTY; without even the implied warranty of
10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11: GNU General Public License for more details.
12:
13: You should have received a copy of the GNU General Public License
14: along with this program. If not, see <http://www.gnu.org/licenses/>.
15: */
16:
17: #include "dnsmasq.h"
18:
19: #ifdef HAVE_UBUS
20:
21: #include <libubus.h>
22:
23: static struct blob_buf b;
24: static int error_logged = 0;
25:
26: static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
27: struct ubus_request_data *req, const char *method,
28: struct blob_attr *msg);
29:
1.1.1.2 ! misho 30: #ifdef HAVE_CONNTRACK
! 31: enum {
! 32: SET_CONNMARK_ALLOWLIST_MARK,
! 33: SET_CONNMARK_ALLOWLIST_MASK,
! 34: SET_CONNMARK_ALLOWLIST_PATTERNS
! 35: };
! 36: static const struct blobmsg_policy set_connmark_allowlist_policy[] = {
! 37: [SET_CONNMARK_ALLOWLIST_MARK] = {
! 38: .name = "mark",
! 39: .type = BLOBMSG_TYPE_INT32
! 40: },
! 41: [SET_CONNMARK_ALLOWLIST_MASK] = {
! 42: .name = "mask",
! 43: .type = BLOBMSG_TYPE_INT32
! 44: },
! 45: [SET_CONNMARK_ALLOWLIST_PATTERNS] = {
! 46: .name = "patterns",
! 47: .type = BLOBMSG_TYPE_ARRAY
! 48: }
! 49: };
! 50: static int ubus_handle_set_connmark_allowlist(struct ubus_context *ctx, struct ubus_object *obj,
! 51: struct ubus_request_data *req, const char *method,
! 52: struct blob_attr *msg);
! 53: #endif
! 54:
1.1 misho 55: static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj);
56:
57: static const struct ubus_method ubus_object_methods[] = {
58: UBUS_METHOD_NOARG("metrics", ubus_handle_metrics),
1.1.1.2 ! misho 59: #ifdef HAVE_CONNTRACK
! 60: UBUS_METHOD("set_connmark_allowlist", ubus_handle_set_connmark_allowlist, set_connmark_allowlist_policy),
! 61: #endif
1.1 misho 62: };
63:
64: static struct ubus_object_type ubus_object_type =
65: UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods);
66:
67: static struct ubus_object ubus_object = {
68: .name = NULL,
69: .type = &ubus_object_type,
70: .methods = ubus_object_methods,
71: .n_methods = ARRAY_SIZE(ubus_object_methods),
72: .subscribe_cb = ubus_subscribe_cb,
73: };
74:
75: static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
76: {
77: (void)ctx;
78:
79: my_syslog(LOG_DEBUG, _("UBus subscription callback: %s subscriber(s)"), obj->has_subscribers ? "1" : "0");
80: }
81:
82: static void ubus_destroy(struct ubus_context *ubus)
83: {
84: ubus_free(ubus);
85: daemon->ubus = NULL;
1.1.1.2 ! misho 86:
! 87: /* Forces re-initialization when we're reusing the same definitions later on. */
! 88: ubus_object.id = 0;
! 89: ubus_object_type.id = 0;
1.1 misho 90: }
91:
92: static void ubus_disconnect_cb(struct ubus_context *ubus)
93: {
94: int ret;
95:
96: ret = ubus_reconnect(ubus, NULL);
97: if (ret)
98: {
99: my_syslog(LOG_ERR, _("Cannot reconnect to UBus: %s"), ubus_strerror(ret));
100:
101: ubus_destroy(ubus);
102: }
103: }
104:
1.1.1.2 ! misho 105: char *ubus_init()
1.1 misho 106: {
107: struct ubus_context *ubus = NULL;
108: int ret = 0;
109:
1.1.1.2 ! misho 110: if (!(ubus = ubus_connect(NULL)))
! 111: return NULL;
! 112:
1.1 misho 113: ubus_object.name = daemon->ubus_name;
114: ret = ubus_add_object(ubus, &ubus_object);
115: if (ret)
116: {
117: ubus_destroy(ubus);
1.1.1.2 ! misho 118: return (char *)ubus_strerror(ret);
! 119: }
! 120:
1.1 misho 121: ubus->connection_lost = ubus_disconnect_cb;
122: daemon->ubus = ubus;
123: error_logged = 0;
124:
1.1.1.2 ! misho 125: return NULL;
1.1 misho 126: }
127:
128: void set_ubus_listeners()
129: {
130: struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
131: if (!ubus)
132: {
133: if (!error_logged)
134: {
135: my_syslog(LOG_ERR, _("Cannot set UBus listeners: no connection"));
136: error_logged = 1;
137: }
138: return;
139: }
140:
141: error_logged = 0;
142:
143: poll_listen(ubus->sock.fd, POLLIN);
144: poll_listen(ubus->sock.fd, POLLERR);
145: poll_listen(ubus->sock.fd, POLLHUP);
146: }
147:
148: void check_ubus_listeners()
149: {
150: struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
151: if (!ubus)
152: {
153: if (!error_logged)
154: {
155: my_syslog(LOG_ERR, _("Cannot poll UBus listeners: no connection"));
156: error_logged = 1;
157: }
158: return;
159: }
160:
161: error_logged = 0;
162:
163: if (poll_check(ubus->sock.fd, POLLIN))
164: ubus_handle_event(ubus);
165:
166: if (poll_check(ubus->sock.fd, POLLHUP | POLLERR))
167: {
168: my_syslog(LOG_INFO, _("Disconnecting from UBus"));
169:
170: ubus_destroy(ubus);
171: }
172: }
173:
1.1.1.2 ! misho 174: #define CHECK(stmt) \
! 175: do { \
! 176: int e = (stmt); \
! 177: if (e) \
! 178: { \
! 179: my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
! 180: return (UBUS_STATUS_UNKNOWN_ERROR); \
! 181: } \
! 182: } while (0)
! 183:
1.1 misho 184: static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
185: struct ubus_request_data *req, const char *method,
186: struct blob_attr *msg)
187: {
188: int i;
189:
190: (void)obj;
191: (void)method;
192: (void)msg;
193:
1.1.1.2 ! misho 194: CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
1.1 misho 195:
196: for (i=0; i < __METRIC_MAX; i++)
1.1.1.2 ! misho 197: CHECK(blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]));
1.1 misho 198:
1.1.1.2 ! misho 199: CHECK(ubus_send_reply(ctx, req, b.head));
! 200: return UBUS_STATUS_OK;
1.1 misho 201: }
202:
1.1.1.2 ! misho 203: #ifdef HAVE_CONNTRACK
! 204: static int ubus_handle_set_connmark_allowlist(struct ubus_context *ctx, struct ubus_object *obj,
! 205: struct ubus_request_data *req, const char *method,
! 206: struct blob_attr *msg)
! 207: {
! 208: const struct blobmsg_policy *policy = set_connmark_allowlist_policy;
! 209: size_t policy_len = countof(set_connmark_allowlist_policy);
! 210: struct allowlist *allowlists = NULL, **allowlists_pos;
! 211: char **patterns = NULL, **patterns_pos;
! 212: u32 mark, mask = UINT32_MAX;
! 213: size_t num_patterns = 0;
! 214: struct blob_attr *tb[policy_len];
! 215: struct blob_attr *attr;
! 216:
! 217: if (blobmsg_parse(policy, policy_len, tb, blob_data(msg), blob_len(msg)))
! 218: return UBUS_STATUS_INVALID_ARGUMENT;
! 219:
! 220: if (!tb[SET_CONNMARK_ALLOWLIST_MARK])
! 221: return UBUS_STATUS_INVALID_ARGUMENT;
! 222: mark = blobmsg_get_u32(tb[SET_CONNMARK_ALLOWLIST_MARK]);
! 223: if (!mark)
! 224: return UBUS_STATUS_INVALID_ARGUMENT;
! 225:
! 226: if (tb[SET_CONNMARK_ALLOWLIST_MASK])
! 227: {
! 228: mask = blobmsg_get_u32(tb[SET_CONNMARK_ALLOWLIST_MASK]);
! 229: if (!mask || (mark & ~mask))
! 230: return UBUS_STATUS_INVALID_ARGUMENT;
! 231: }
! 232:
! 233: if (tb[SET_CONNMARK_ALLOWLIST_PATTERNS])
! 234: {
! 235: struct blob_attr *head = blobmsg_data(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
! 236: size_t len = blobmsg_data_len(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
! 237: __blob_for_each_attr(attr, head, len)
! 238: {
! 239: char *pattern;
! 240: if (blob_id(attr) != BLOBMSG_TYPE_STRING)
! 241: return UBUS_STATUS_INVALID_ARGUMENT;
! 242: if (!(pattern = blobmsg_get_string(attr)))
! 243: return UBUS_STATUS_INVALID_ARGUMENT;
! 244: if (strcmp(pattern, "*") && !is_valid_dns_name_pattern(pattern))
! 245: return UBUS_STATUS_INVALID_ARGUMENT;
! 246: num_patterns++;
! 247: }
! 248: }
! 249:
! 250: for (allowlists_pos = &daemon->allowlists; *allowlists_pos; allowlists_pos = &(*allowlists_pos)->next)
! 251: if ((*allowlists_pos)->mark == mark && (*allowlists_pos)->mask == mask)
! 252: {
! 253: struct allowlist *allowlists_next = (*allowlists_pos)->next;
! 254: for (patterns_pos = (*allowlists_pos)->patterns; *patterns_pos; patterns_pos++)
! 255: {
! 256: free(*patterns_pos);
! 257: *patterns_pos = NULL;
! 258: }
! 259: free((*allowlists_pos)->patterns);
! 260: (*allowlists_pos)->patterns = NULL;
! 261: free(*allowlists_pos);
! 262: *allowlists_pos = allowlists_next;
! 263: break;
! 264: }
! 265:
! 266: if (!num_patterns)
! 267: return UBUS_STATUS_OK;
! 268:
! 269: patterns = whine_malloc((num_patterns + 1) * sizeof(char *));
! 270: if (!patterns)
! 271: goto fail;
! 272: patterns_pos = patterns;
! 273: if (tb[SET_CONNMARK_ALLOWLIST_PATTERNS])
! 274: {
! 275: struct blob_attr *head = blobmsg_data(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
! 276: size_t len = blobmsg_data_len(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
! 277: __blob_for_each_attr(attr, head, len)
! 278: {
! 279: char *pattern;
! 280: if (!(pattern = blobmsg_get_string(attr)))
! 281: goto fail;
! 282: if (!(*patterns_pos = whine_malloc(strlen(pattern) + 1)))
! 283: goto fail;
! 284: strcpy(*patterns_pos++, pattern);
! 285: }
! 286: }
! 287:
! 288: allowlists = whine_malloc(sizeof(struct allowlist));
! 289: if (!allowlists)
! 290: goto fail;
! 291: memset(allowlists, 0, sizeof(struct allowlist));
! 292: allowlists->mark = mark;
! 293: allowlists->mask = mask;
! 294: allowlists->patterns = patterns;
! 295: allowlists->next = daemon->allowlists;
! 296: daemon->allowlists = allowlists;
! 297: return UBUS_STATUS_OK;
! 298:
! 299: fail:
! 300: if (patterns)
! 301: {
! 302: for (patterns_pos = patterns; *patterns_pos; patterns_pos++)
! 303: {
! 304: free(*patterns_pos);
! 305: *patterns_pos = NULL;
! 306: }
! 307: free(patterns);
! 308: patterns = NULL;
! 309: }
! 310: if (allowlists)
! 311: {
! 312: free(allowlists);
! 313: allowlists = NULL;
! 314: }
! 315: return UBUS_STATUS_UNKNOWN_ERROR;
! 316: }
! 317: #endif
! 318:
! 319: #undef CHECK
! 320:
! 321: #define CHECK(stmt) \
! 322: do { \
! 323: int e = (stmt); \
! 324: if (e) \
! 325: { \
! 326: my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
! 327: return; \
! 328: } \
! 329: } while (0)
! 330:
1.1 misho 331: void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
332: {
333: struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
334:
1.1.1.2 ! misho 335: if (!ubus || !ubus_object.has_subscribers)
1.1 misho 336: return;
337:
1.1.1.2 ! misho 338: CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
1.1 misho 339: if (mac)
1.1.1.2 ! misho 340: CHECK(blobmsg_add_string(&b, "mac", mac));
1.1 misho 341: if (ip)
1.1.1.2 ! misho 342: CHECK(blobmsg_add_string(&b, "ip", ip));
1.1 misho 343: if (name)
1.1.1.2 ! misho 344: CHECK(blobmsg_add_string(&b, "name", name));
1.1 misho 345: if (interface)
1.1.1.2 ! misho 346: CHECK(blobmsg_add_string(&b, "interface", interface));
! 347:
! 348: CHECK(ubus_notify(ubus, &ubus_object, type, b.head, -1));
! 349: }
! 350:
! 351: #ifdef HAVE_CONNTRACK
! 352: void ubus_event_bcast_connmark_allowlist_refused(u32 mark, const char *name)
! 353: {
! 354: struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
! 355:
! 356: if (!ubus || !ubus_object.has_subscribers)
! 357: return;
! 358:
! 359: CHECK(blob_buf_init(&b, 0));
! 360: CHECK(blobmsg_add_u32(&b, "mark", mark));
! 361: CHECK(blobmsg_add_string(&b, "name", name));
! 362:
! 363: CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.refused", b.head, -1));
! 364: }
! 365:
! 366: void ubus_event_bcast_connmark_allowlist_resolved(u32 mark, const char *name, const char *value, u32 ttl)
! 367: {
! 368: struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
! 369:
! 370: if (!ubus || !ubus_object.has_subscribers)
! 371: return;
! 372:
! 373: CHECK(blob_buf_init(&b, 0));
! 374: CHECK(blobmsg_add_u32(&b, "mark", mark));
! 375: CHECK(blobmsg_add_string(&b, "name", name));
! 376: CHECK(blobmsg_add_string(&b, "value", value));
! 377: CHECK(blobmsg_add_u32(&b, "ttl", ttl));
1.1 misho 378:
1.1.1.2 ! misho 379: /* Set timeout to allow UBus subscriber to configure firewall rules before returning. */
! 380: CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.resolved", b.head, /* timeout: */ 1000));
1.1 misho 381: }
1.1.1.2 ! misho 382: #endif
1.1 misho 383:
1.1.1.2 ! misho 384: #undef CHECK
1.1 misho 385:
386: #endif /* HAVE_UBUS */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>