Diff for /embedaddon/dnsmasq/src/ubus.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2021/03/17 00:56:46 version 1.1.1.2, 2023/09/27 11:02:07
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
Line 21 Line 21
 #include <libubus.h>  #include <libubus.h>
   
 static struct blob_buf b;  static struct blob_buf b;
 static int notify;  
 static int error_logged = 0;  static int error_logged = 0;
   
 static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,  static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
                                struct ubus_request_data *req, const char *method,                                 struct ubus_request_data *req, const char *method,
                                struct blob_attr *msg);                                 struct blob_attr *msg);
   
   #ifdef HAVE_CONNTRACK
   enum {
     SET_CONNMARK_ALLOWLIST_MARK,
     SET_CONNMARK_ALLOWLIST_MASK,
     SET_CONNMARK_ALLOWLIST_PATTERNS
   };
   static const struct blobmsg_policy set_connmark_allowlist_policy[] = {
     [SET_CONNMARK_ALLOWLIST_MARK] = {
       .name = "mark",
       .type = BLOBMSG_TYPE_INT32
     },
     [SET_CONNMARK_ALLOWLIST_MASK] = {
       .name = "mask",
       .type = BLOBMSG_TYPE_INT32
     },
     [SET_CONNMARK_ALLOWLIST_PATTERNS] = {
       .name = "patterns",
       .type = BLOBMSG_TYPE_ARRAY
     }
   };
   static int ubus_handle_set_connmark_allowlist(struct ubus_context *ctx, struct ubus_object *obj,
                                                 struct ubus_request_data *req, const char *method,
                                                 struct blob_attr *msg);
   #endif
   
 static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj);  static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj);
   
 static const struct ubus_method ubus_object_methods[] = {  static const struct ubus_method ubus_object_methods[] = {
   UBUS_METHOD_NOARG("metrics", ubus_handle_metrics),    UBUS_METHOD_NOARG("metrics", ubus_handle_metrics),
   #ifdef HAVE_CONNTRACK
     UBUS_METHOD("set_connmark_allowlist", ubus_handle_set_connmark_allowlist, set_connmark_allowlist_policy),
   #endif
 };  };
   
 static struct ubus_object_type ubus_object_type =  static struct ubus_object_type ubus_object_type =
Line 50  static void ubus_subscribe_cb(struct ubus_context *ctx Line 77  static void ubus_subscribe_cb(struct ubus_context *ctx
   (void)ctx;    (void)ctx;
   
   my_syslog(LOG_DEBUG, _("UBus subscription callback: %s subscriber(s)"), obj->has_subscribers ? "1" : "0");    my_syslog(LOG_DEBUG, _("UBus subscription callback: %s subscriber(s)"), obj->has_subscribers ? "1" : "0");
   notify = obj->has_subscribers;  
 }  }
   
 static void ubus_destroy(struct ubus_context *ubus)  static void ubus_destroy(struct ubus_context *ubus)
 {  {
   // Forces re-initialization when we're reusing the same definitions later on.  
   ubus_object.id = 0;  
   ubus_object_type.id = 0;  
   
   ubus_free(ubus);    ubus_free(ubus);
   daemon->ubus = NULL;    daemon->ubus = NULL;
     
     /* Forces re-initialization when we're reusing the same definitions later on. */
     ubus_object.id = 0;
     ubus_object_type.id = 0;
 }  }
   
 static void ubus_disconnect_cb(struct ubus_context *ubus)  static void ubus_disconnect_cb(struct ubus_context *ubus)
Line 76  static void ubus_disconnect_cb(struct ubus_context *ub Line 102  static void ubus_disconnect_cb(struct ubus_context *ub
     }      }
 }  }
   
void ubus_init()char *ubus_init()
 {  {
   struct ubus_context *ubus = NULL;    struct ubus_context *ubus = NULL;
   int ret = 0;    int ret = 0;
   
  ubus = ubus_connect(NULL);  if (!(ubus = ubus_connect(NULL)))
  if (!ubus)    return NULL;
    {  
      if (!error_logged) 
        { 
          my_syslog(LOG_ERR, _("Cannot initialize UBus: connection failed")); 
          error_logged = 1; 
        } 
 
      ubus_destroy(ubus); 
      return; 
    } 
 
   ubus_object.name = daemon->ubus_name;    ubus_object.name = daemon->ubus_name;
   ret = ubus_add_object(ubus, &ubus_object);    ret = ubus_add_object(ubus, &ubus_object);
   if (ret)    if (ret)
     {      {
       if (!error_logged)  
         {  
           my_syslog(LOG_ERR, _("Cannot add object to UBus: %s"), ubus_strerror(ret));  
           error_logged = 1;  
         }  
       ubus_destroy(ubus);        ubus_destroy(ubus);
      return;      return (char *)ubus_strerror(ret);
    }    }    
  
   ubus->connection_lost = ubus_disconnect_cb;    ubus->connection_lost = ubus_disconnect_cb;
   daemon->ubus = ubus;    daemon->ubus = ubus;
   error_logged = 0;    error_logged = 0;
   
  my_syslog(LOG_INFO, _("Connected to system UBus"));  return NULL;
 }  }
   
 void set_ubus_listeners()  void set_ubus_listeners()
Line 160  void check_ubus_listeners() Line 171  void check_ubus_listeners()
     }      }
 }  }
   
   #define CHECK(stmt) \
     do { \
       int e = (stmt); \
       if (e) \
         { \
           my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
           return (UBUS_STATUS_UNKNOWN_ERROR); \
         } \
     } while (0)
   
 static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,  static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
                                struct ubus_request_data *req, const char *method,                                 struct ubus_request_data *req, const char *method,
                                struct blob_attr *msg)                                 struct blob_attr *msg)
Line 170  static int ubus_handle_metrics(struct ubus_context *ct Line 191  static int ubus_handle_metrics(struct ubus_context *ct
   (void)method;    (void)method;
   (void)msg;    (void)msg;
   
  blob_buf_init(&b, BLOBMSG_TYPE_TABLE);  CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
   
   for (i=0; i < __METRIC_MAX; i++)    for (i=0; i < __METRIC_MAX; i++)
    blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]);    CHECK(blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]));
       
  return ubus_send_reply(ctx, req, b.head);  CHECK(ubus_send_reply(ctx, req, b.head));
   return UBUS_STATUS_OK;
 }  }
   
   #ifdef HAVE_CONNTRACK
   static int ubus_handle_set_connmark_allowlist(struct ubus_context *ctx, struct ubus_object *obj,
                                                 struct ubus_request_data *req, const char *method,
                                                 struct blob_attr *msg)
   {
     const struct blobmsg_policy *policy = set_connmark_allowlist_policy;
     size_t policy_len = countof(set_connmark_allowlist_policy);
     struct allowlist *allowlists = NULL, **allowlists_pos;
     char **patterns = NULL, **patterns_pos;
     u32 mark, mask = UINT32_MAX;
     size_t num_patterns = 0;
     struct blob_attr *tb[policy_len];
     struct blob_attr *attr;
     
     if (blobmsg_parse(policy, policy_len, tb, blob_data(msg), blob_len(msg)))
       return UBUS_STATUS_INVALID_ARGUMENT;
     
     if (!tb[SET_CONNMARK_ALLOWLIST_MARK])
       return UBUS_STATUS_INVALID_ARGUMENT;
     mark = blobmsg_get_u32(tb[SET_CONNMARK_ALLOWLIST_MARK]);
     if (!mark)
       return UBUS_STATUS_INVALID_ARGUMENT;
     
     if (tb[SET_CONNMARK_ALLOWLIST_MASK])
       {
         mask = blobmsg_get_u32(tb[SET_CONNMARK_ALLOWLIST_MASK]);
         if (!mask || (mark & ~mask))
           return UBUS_STATUS_INVALID_ARGUMENT;
       }
     
     if (tb[SET_CONNMARK_ALLOWLIST_PATTERNS])
       {
         struct blob_attr *head = blobmsg_data(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
         size_t len = blobmsg_data_len(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
         __blob_for_each_attr(attr, head, len)
           {
             char *pattern;
             if (blob_id(attr) != BLOBMSG_TYPE_STRING)
               return UBUS_STATUS_INVALID_ARGUMENT;
             if (!(pattern = blobmsg_get_string(attr)))
               return UBUS_STATUS_INVALID_ARGUMENT;
             if (strcmp(pattern, "*") && !is_valid_dns_name_pattern(pattern))
               return UBUS_STATUS_INVALID_ARGUMENT;
             num_patterns++;
           }
       }
     
     for (allowlists_pos = &daemon->allowlists; *allowlists_pos; allowlists_pos = &(*allowlists_pos)->next)
       if ((*allowlists_pos)->mark == mark && (*allowlists_pos)->mask == mask)
         {
           struct allowlist *allowlists_next = (*allowlists_pos)->next;
           for (patterns_pos = (*allowlists_pos)->patterns; *patterns_pos; patterns_pos++)
             {
               free(*patterns_pos);
               *patterns_pos = NULL;
             }
           free((*allowlists_pos)->patterns);
           (*allowlists_pos)->patterns = NULL;
           free(*allowlists_pos);
           *allowlists_pos = allowlists_next;
           break;
         }
     
     if (!num_patterns)
       return UBUS_STATUS_OK;
     
     patterns = whine_malloc((num_patterns + 1) * sizeof(char *));
     if (!patterns)
       goto fail;
     patterns_pos = patterns;
     if (tb[SET_CONNMARK_ALLOWLIST_PATTERNS])
       {
         struct blob_attr *head = blobmsg_data(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
         size_t len = blobmsg_data_len(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
         __blob_for_each_attr(attr, head, len)
           {
             char *pattern;
             if (!(pattern = blobmsg_get_string(attr)))
               goto fail;
             if (!(*patterns_pos = whine_malloc(strlen(pattern) + 1)))
               goto fail;
             strcpy(*patterns_pos++, pattern);
           }
       }
     
     allowlists = whine_malloc(sizeof(struct allowlist));
     if (!allowlists)
       goto fail;
     memset(allowlists, 0, sizeof(struct allowlist));
     allowlists->mark = mark;
     allowlists->mask = mask;
     allowlists->patterns = patterns;
     allowlists->next = daemon->allowlists;
     daemon->allowlists = allowlists;
     return UBUS_STATUS_OK;
     
   fail:
     if (patterns)
       {
         for (patterns_pos = patterns; *patterns_pos; patterns_pos++)
           {
             free(*patterns_pos);
             *patterns_pos = NULL;
           }
         free(patterns);
         patterns = NULL;
       }
     if (allowlists)
       {
         free(allowlists);
         allowlists = NULL;
       }
     return UBUS_STATUS_UNKNOWN_ERROR;
   }
   #endif
   
   #undef CHECK
   
   #define CHECK(stmt) \
     do { \
       int e = (stmt); \
       if (e) \
         { \
           my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
           return; \
         } \
     } while (0)
   
 void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)  void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
 {  {
   struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;    struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
   int ret;  
   
  if (!ubus || !notify)  if (!ubus || !ubus_object.has_subscribers)
     return;      return;
   
  blob_buf_init(&b, BLOBMSG_TYPE_TABLE);  CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
   if (mac)    if (mac)
    blobmsg_add_string(&b, "mac", mac);    CHECK(blobmsg_add_string(&b, "mac", mac));
   if (ip)    if (ip)
    blobmsg_add_string(&b, "ip", ip);    CHECK(blobmsg_add_string(&b, "ip", ip));
   if (name)    if (name)
    blobmsg_add_string(&b, "name", name);    CHECK(blobmsg_add_string(&b, "name", name));
   if (interface)    if (interface)
    blobmsg_add_string(&b, "interface", interface);    CHECK(blobmsg_add_string(&b, "interface", interface));
       
  ret = ubus_notify(ubus, &ubus_object, type, b.head, -1);  CHECK(ubus_notify(ubus, &ubus_object, type, b.head, -1));
  if (!ret) 
    my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret)); 
 }  }
   
   #ifdef HAVE_CONNTRACK
   void ubus_event_bcast_connmark_allowlist_refused(u32 mark, const char *name)
   {
     struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
   
     if (!ubus || !ubus_object.has_subscribers)
       return;
   
     CHECK(blob_buf_init(&b, 0));
     CHECK(blobmsg_add_u32(&b, "mark", mark));
     CHECK(blobmsg_add_string(&b, "name", name));
     
     CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.refused", b.head, -1));
   }
   
   void ubus_event_bcast_connmark_allowlist_resolved(u32 mark, const char *name, const char *value, u32 ttl)
   {
     struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
   
     if (!ubus || !ubus_object.has_subscribers)
       return;
   
     CHECK(blob_buf_init(&b, 0));
     CHECK(blobmsg_add_u32(&b, "mark", mark));
     CHECK(blobmsg_add_string(&b, "name", name));
     CHECK(blobmsg_add_string(&b, "value", value));
     CHECK(blobmsg_add_u32(&b, "ttl", ttl));
     
     /* Set timeout to allow UBus subscriber to configure firewall rules before returning. */
     CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.resolved", b.head, /* timeout: */ 1000));
   }
   #endif
   
   #undef CHECK
   
 #endif /* HAVE_UBUS */  #endif /* HAVE_UBUS */

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>