Imported Upstream version 2.88
[platform/upstream/dnsmasq.git] / src / ubus.c
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 */