1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
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:
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:
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),
59: #ifdef HAVE_CONNTRACK
60: UBUS_METHOD("set_connmark_allowlist", ubus_handle_set_connmark_allowlist, set_connmark_allowlist_policy),
61: #endif
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;
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;
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:
105: char *ubus_init()
106: {
107: struct ubus_context *ubus = NULL;
108: int ret = 0;
109:
110: if (!(ubus = ubus_connect(NULL)))
111: return NULL;
112:
113: ubus_object.name = daemon->ubus_name;
114: ret = ubus_add_object(ubus, &ubus_object);
115: if (ret)
116: {
117: ubus_destroy(ubus);
118: return (char *)ubus_strerror(ret);
119: }
120:
121: ubus->connection_lost = ubus_disconnect_cb;
122: daemon->ubus = ubus;
123: error_logged = 0;
124:
125: return NULL;
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:
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:
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:
194: CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
195:
196: for (i=0; i < __METRIC_MAX; i++)
197: CHECK(blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]));
198:
199: CHECK(ubus_send_reply(ctx, req, b.head));
200: return UBUS_STATUS_OK;
201: }
202:
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:
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:
335: if (!ubus || !ubus_object.has_subscribers)
336: return;
337:
338: CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
339: if (mac)
340: CHECK(blobmsg_add_string(&b, "mac", mac));
341: if (ip)
342: CHECK(blobmsg_add_string(&b, "ip", ip));
343: if (name)
344: CHECK(blobmsg_add_string(&b, "name", name));
345: if (interface)
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));
378:
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));
381: }
382: #endif
383:
384: #undef CHECK
385:
386: #endif /* HAVE_UBUS */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>