Annotation of embedaddon/dnsmasq/src/ubus.c, revision 1.1.1.2

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

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