blob: 0c502ad522fb65369ecbef11e5d4f97b1056d267 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* dnsmasq is Copyright (c) 2000-2021 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
23static struct blob_buf b;
24static int error_logged = 0;
25
26static 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
31enum {
32 SET_CONNMARK_ALLOWLIST_MARK,
33 SET_CONNMARK_ALLOWLIST_MASK,
34 SET_CONNMARK_ALLOWLIST_PATTERNS
35};
36static 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};
50static 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
55static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj);
56
57static 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
64static struct ubus_object_type ubus_object_type =
65 UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods);
66
67static 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
75static 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
82static 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
92static 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
105char *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
128void 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
148void 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
184static 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
204static 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
299fail:
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
331void 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
352void 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
366void 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 */