File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / ubus.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:02:07 2023 UTC (9 months, 2 weeks ago) by misho
Branches: dnsmasq, MAIN
CVS tags: v8_2p1, HEAD
Version 8.2p1

    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>