host: deal with host/peer null pointers in debug messages
[project/unetd.git] / ubus.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
4 */
5 #include <arpa/inet.h>
6 #include <libubus.h>
7 #include "unetd.h"
8
9 static struct ubus_auto_conn conn;
10 static struct blob_buf b;
11
12 static int
13 ubus_network_add(struct ubus_context *ctx, struct ubus_object *obj,
14 struct ubus_request_data *req, const char *method,
15 struct blob_attr *msg)
16 {
17 struct blob_attr *name;
18
19 blobmsg_parse(&network_policy[NETWORK_ATTR_NAME], 1, &name,
20 blobmsg_data(msg), blobmsg_len(msg));
21
22 if (!name)
23 return UBUS_STATUS_INVALID_ARGUMENT;
24
25 if (unetd_network_add(blobmsg_get_string(name), msg))
26 return UBUS_STATUS_INVALID_ARGUMENT;
27
28 return 0;
29 }
30
31
32 static int
33 ubus_network_del(struct ubus_context *ctx, struct ubus_object *obj,
34 struct ubus_request_data *req, const char *method,
35 struct blob_attr *msg)
36 {
37 struct blob_attr *name;
38
39 blobmsg_parse(&network_policy[NETWORK_ATTR_NAME], 1, &name,
40 blobmsg_data(msg), blobmsg_len(msg));
41
42 if (!name)
43 return UBUS_STATUS_INVALID_ARGUMENT;
44
45 if (unetd_network_remove(blobmsg_get_string(name)))
46 return UBUS_STATUS_NOT_FOUND;
47
48 return 0;
49 }
50
51 enum {
52 SERVICE_ATTR_NETWORK,
53 SERVICE_ATTR_NAME,
54 __SERVICE_ATTR_MAX
55 };
56
57 static const struct blobmsg_policy service_policy[__SERVICE_ATTR_MAX] = {
58 [SERVICE_ATTR_NETWORK] = { "network", BLOBMSG_TYPE_STRING },
59 [SERVICE_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
60 };
61
62
63 static void
64 ubus_service_get_network_members(struct blob_buf *b, struct network *n,
65 const char *name)
66 {
67 struct network_service *s;
68 int i;
69
70 s = vlist_find(&n->services, name, s, node);
71 if (!s)
72 return;
73
74 for (i = 0; i < s->n_members; i++) {
75 struct network_host *host = s->members[i];
76 char *name;
77
78 name = blobmsg_alloc_string_buffer(b, NULL, INET6_ADDRSTRLEN);
79 inet_ntop(AF_INET6, &host->peer.local_addr.in6, name, INET6_ADDRSTRLEN);
80 blobmsg_add_string_buffer(b);
81 }
82 }
83
84
85 static int
86 ubus_service_get(struct ubus_context *ctx, struct ubus_object *obj,
87 struct ubus_request_data *req, const char *method,
88 struct blob_attr *msg)
89 {
90 struct blob_attr *tb[__SERVICE_ATTR_MAX];
91 struct blob_attr *cur;
92 struct network *n = NULL;
93 const char *name;
94 void *c;
95
96 blobmsg_parse(service_policy, __SERVICE_ATTR_MAX, tb,
97 blobmsg_data(msg), blobmsg_len(msg));
98
99 if ((cur = tb[SERVICE_ATTR_NAME]) != NULL)
100 name = blobmsg_get_string(cur);
101 else
102 return UBUS_STATUS_INVALID_ARGUMENT;
103
104 if ((cur = tb[SERVICE_ATTR_NETWORK]) != NULL) {
105 n = avl_find_element(&networks, blobmsg_get_string(cur), n, node);
106 if (!n)
107 return UBUS_STATUS_INVALID_ARGUMENT;
108 }
109
110 blob_buf_init(&b, 0);
111
112 c = blobmsg_open_array(&b, "hosts");
113 if (n) {
114 ubus_service_get_network_members(&b, n, name);
115 } else {
116 avl_for_each_element(&networks, n, node)
117 ubus_service_get_network_members(&b, n, name);
118 }
119 blobmsg_close_array(&b, c);
120 ubus_send_reply(ctx, req, b.head);
121
122 return 0;
123 }
124
125 static const struct ubus_method unetd_methods[] = {
126 UBUS_METHOD("network_add", ubus_network_add, network_policy),
127 UBUS_METHOD_MASK("network_del", ubus_network_del, network_policy,
128 (1 << NETWORK_ATTR_NAME)),
129 UBUS_METHOD("service_get", ubus_service_get, service_policy),
130 };
131
132 static struct ubus_object_type unetd_object_type =
133 UBUS_OBJECT_TYPE("unetd", unetd_methods);
134
135 static struct ubus_object unetd_object = {
136 .name = "unetd",
137 .type = &unetd_object_type,
138 .methods = unetd_methods,
139 .n_methods = ARRAY_SIZE(unetd_methods),
140 };
141
142 static void
143 ubus_connect_handler(struct ubus_context *ctx)
144 {
145 int ret;
146
147 ret = ubus_add_object(ctx, &unetd_object);
148 if (ret)
149 fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));
150 }
151
152 void unetd_ubus_netifd_update(struct blob_attr *data)
153 {
154 uint32_t id;
155
156 if (ubus_lookup_id(&conn.ctx, "network.interface", &id))
157 return;
158
159 ubus_invoke(&conn.ctx, id, "notify_proto", data, NULL, NULL, 5000);
160 }
161
162 void unetd_ubus_netifd_add_route(struct network *net, union network_endpoint *ep)
163 {
164 uint32_t id;
165 void *addr;
166 char *buf;
167
168 if (!net->config.interface)
169 return;
170
171 if (ubus_lookup_id(&conn.ctx, "network", &id))
172 return;
173
174 blob_buf_init(&b, 0);
175
176 if (ep->in.sin_family == AF_INET6)
177 addr = &ep->in6.sin6_addr;
178 else
179 addr = &ep->in.sin_addr;
180
181 blobmsg_add_u8(&b, "v6", ep->in.sin_family == AF_INET6);
182 buf = blobmsg_alloc_string_buffer(&b, "target", INET6_ADDRSTRLEN);
183 inet_ntop(ep->in.sin_family, addr, buf, INET6_ADDRSTRLEN);
184 blobmsg_add_string_buffer(&b);
185 blobmsg_add_string(&b, "interface", net->config.interface);
186 blobmsg_add_u8(&b, "exclude", true);
187
188 ubus_invoke(&conn.ctx, id, "add_host_route", b.head, NULL, NULL, -1);
189 }
190
191 void unetd_ubus_init(void)
192 {
193 conn.cb = ubus_connect_handler;
194 ubus_auto_connect(&conn);
195 }