1 /* 2 * Copyright (C) 2014 John Crispin <blogic@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License version 2.1 6 * as published by the Free Software Foundation 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 14 #include <sys/types.h> 15 #include <arpa/nameser.h> 16 #include <sys/socket.h> 17 18 #include <resolv.h> 19 #include <glob.h> 20 #include <inttypes.h> 21 #include <stdio.h> 22 #include <time.h> 23 24 #include <libubus.h> 25 #include <libubox/vlist.h> 26 #include <libubox/uloop.h> 27 #include <libubox/avl-cmp.h> 28 #include <libubox/blobmsg_json.h> 29 30 #include "ubus.h" 31 #include "dns.h" 32 #include "service.h" 33 #include "util.h" 34 #include "interface.h" 35 #include "announce.h" 36 37 enum { 38 SERVICE_INSTANCE, 39 SERVICE_SERVICE, 40 SERVICE_PORT, 41 SERVICE_TXT, 42 SERVICE_HOSTNAME, 43 __SERVICE_MAX, 44 }; 45 46 struct service { 47 struct vlist_node node; 48 49 time_t t; 50 51 const char *id; 52 const char *instance; 53 const char *service; 54 const uint8_t *txt; 55 int txt_len; 56 int port; 57 int active; 58 }; 59 60 static const struct blobmsg_policy service_policy[__SERVICE_MAX] = { 61 [SERVICE_INSTANCE] = { .name = "instance", .type = BLOBMSG_TYPE_STRING }, 62 [SERVICE_SERVICE] = { .name = "service", .type = BLOBMSG_TYPE_STRING }, 63 [SERVICE_PORT] = { .name = "port", .type = BLOBMSG_TYPE_INT32 }, 64 [SERVICE_TXT] = { .name = "txt", .type = BLOBMSG_TYPE_ARRAY }, 65 [SERVICE_HOSTNAME] = { .name = "hostname", .type = BLOBMSG_TYPE_STRING }, 66 }; 67 68 static void 69 service_update(struct vlist_tree *tree, struct vlist_node *node_new, 70 struct vlist_node *node_old); 71 72 static void 73 hostname_update(struct vlist_tree *tree, struct vlist_node *node_new, 74 struct vlist_node *node_old); 75 76 static struct blob_buf b; 77 static VLIST_TREE(services, avl_strcmp, service_update, false, false); 78 VLIST_TREE(hostnames, avl_strcmp, hostname_update, false, false); 79 static int service_init_announce; 80 81 /** 82 * service_instance_name - construct Service Instance Name as in RFC 6763 83 * 84 * RFC 6763 specifies Service Instance Names in the following way: 85 * 86 * Service Instance Name = <Instance> . <Service> . <Domain> 87 * 88 * @s: service to generate service instance name for 89 */ 90 static const char * 91 service_instance_name(struct service *s) 92 { 93 static char buffer[256]; 94 95 snprintf(buffer, sizeof(buffer), "%s.%s", s->instance, s->service); 96 97 return buffer; 98 } 99 100 static void 101 service_add_ptr(const char *host, int ttl) 102 { 103 int len = dn_comp(host, mdns_buf, sizeof(mdns_buf), NULL, NULL); 104 105 if (len < 1) 106 return; 107 108 dns_add_answer(TYPE_PTR, mdns_buf, len, ttl); 109 } 110 111 static void 112 service_add_srv(struct service *s, int ttl) 113 { 114 struct dns_srv_data *sd = (struct dns_srv_data *) mdns_buf; 115 int len = sizeof(*sd); 116 117 len += dn_comp(mdns_hostname_local, mdns_buf + len, sizeof(mdns_buf) - len, NULL, NULL); 118 if (len <= sizeof(*sd)) 119 return; 120 121 sd->port = cpu_to_be16(s->port); 122 dns_add_answer(TYPE_SRV, mdns_buf, len, ttl); 123 } 124 125 #define TOUT_LOOKUP 60 126 127 static time_t 128 service_timeout(struct service *s) 129 { 130 time_t t = monotonic_time(); 131 132 if (t - s->t <= TOUT_LOOKUP) { 133 DBG(2, "t=%" PRId64 ", s->t=%" PRId64 ", t - s->t = %" PRId64 "\n", (int64_t)t, (int64_t)s->t, (int64_t)(t - s->t)); 134 return 0; 135 } 136 137 return t; 138 } 139 140 static void 141 service_reply_single(struct interface *iface, struct sockaddr *to, struct service *s, int ttl, int force) 142 { 143 const char *host = service_instance_name(s); 144 char *service = strstr(host, "._"); 145 time_t t = service_timeout(s); 146 147 148 if (!force && (!s->active || !service || !t)) 149 return; 150 151 service++; 152 153 s->t = t; 154 155 dns_init_answer(); 156 service_add_ptr(service_instance_name(s), ttl); 157 dns_send_answer(iface, to, service); 158 159 dns_init_answer(); 160 service_add_srv(s, ttl); 161 if (s->txt && s->txt_len) 162 dns_add_answer(TYPE_TXT, (uint8_t *) s->txt, s->txt_len, ttl); 163 dns_send_answer(iface, to, host); 164 } 165 166 void 167 service_reply(struct interface *iface, struct sockaddr *to, const char *instance, const char *service_domain, int ttl) 168 { 169 struct service *s; 170 171 vlist_for_each_element(&services, s, node) { 172 if (instance && strcmp(s->instance, instance)) 173 continue; 174 if (service_domain && strcmp(s->service, service_domain)) 175 continue; 176 service_reply_single(iface, to, s, ttl, 0); 177 } 178 } 179 180 void 181 service_announce_services(struct interface *iface, struct sockaddr *to, int ttl) 182 { 183 struct service *s; 184 185 vlist_for_each_element(&services, s, node) { 186 s->t = 0; 187 if (ttl) { 188 dns_init_answer(); 189 service_add_ptr(s->service, ttl); 190 dns_send_answer(iface, to, C_DNS_SD); 191 } 192 service_reply_single(iface, to, s, ttl, 0); 193 } 194 } 195 196 static void 197 service_update(struct vlist_tree *tree, struct vlist_node *node_new, 198 struct vlist_node *node_old) 199 { 200 struct interface *iface; 201 struct service *s; 202 203 if (!node_old) { 204 s = container_of(node_new, struct service, node); 205 if (service_init_announce) 206 vlist_for_each_element(&interfaces, iface, node) { 207 s->t = 0; 208 service_reply_single(iface, NULL, s, announce_ttl, 1); 209 } 210 return; 211 } 212 213 s = container_of(node_old, struct service, node); 214 if (!node_new && service_init_announce) 215 vlist_for_each_element(&interfaces, iface, node) 216 service_reply_single(iface, NULL, s, 0, 1); 217 free(s); 218 } 219 220 static void 221 hostname_update(struct vlist_tree *tree, struct vlist_node *node_new, 222 struct vlist_node *node_old) 223 { 224 struct interface *iface; 225 struct hostname *h; 226 227 if (!node_old) { 228 h = container_of(node_new, struct hostname, node); 229 vlist_for_each_element(&interfaces, iface, node) 230 dns_reply_a(iface, NULL, announce_ttl, h->hostname); 231 return; 232 } 233 234 h = container_of(node_old, struct hostname, node); 235 if (!node_new) 236 vlist_for_each_element(&interfaces, iface, node) 237 dns_reply_a(iface, NULL, 0, h->hostname); 238 239 free(h); 240 } 241 242 static void 243 service_load_hostname(struct blob_attr *b) 244 { 245 struct hostname *h; 246 char *hostname, *d_hostname; 247 248 hostname = blobmsg_get_string(b); 249 h = calloc_a(sizeof(*h), &d_hostname, strlen(hostname) + 1); 250 if (!h) 251 return; 252 253 h->hostname = strcpy(d_hostname, hostname); 254 255 vlist_add(&hostnames, &h->node, h->hostname); 256 } 257 258 static void 259 service_load_blob(struct blob_attr *b) 260 { 261 struct blob_attr *txt, *_tb[__SERVICE_MAX]; 262 struct service *s; 263 char *d_instance, *d_service, *d_id; 264 uint8_t *d_txt; 265 int rem2; 266 int txt_len = 0; 267 unsigned int n; 268 269 blobmsg_parse(service_policy, ARRAY_SIZE(service_policy), 270 _tb, blobmsg_data(b), blobmsg_data_len(b)); 271 272 if (_tb[SERVICE_HOSTNAME]) { 273 service_load_hostname(_tb[SERVICE_HOSTNAME]); 274 return; 275 } 276 277 if (!_tb[SERVICE_PORT] || !_tb[SERVICE_SERVICE]) 278 return; 279 280 if (_tb[SERVICE_TXT]) 281 blobmsg_for_each_attr(txt, _tb[SERVICE_TXT], rem2) 282 txt_len += 1 + strlen(blobmsg_get_string(txt)); 283 284 n = strlen(blobmsg_name(b)); 285 s = calloc_a(sizeof(*s), 286 &d_id, n + 1, 287 &d_instance, _tb[SERVICE_INSTANCE] ? strlen(blobmsg_get_string(_tb[SERVICE_INSTANCE])) + 1 : 0, 288 &d_service, strlen(blobmsg_get_string(_tb[SERVICE_SERVICE])) + 1, 289 &d_txt, txt_len); 290 if (!s) 291 return; 292 293 s->port = blobmsg_get_u32(_tb[SERVICE_PORT]); 294 s->id = strncpy(d_id, blobmsg_name(b), n); 295 if (_tb[SERVICE_INSTANCE]) 296 s->instance = strcpy(d_instance, blobmsg_get_string(_tb[SERVICE_INSTANCE])); 297 else 298 s->instance = umdns_host_label; 299 s->service = strcpy(d_service, blobmsg_get_string(_tb[SERVICE_SERVICE])); 300 s->active = 1; 301 s->t = 0; 302 s->txt_len = txt_len; 303 s->txt = d_txt; 304 305 if (_tb[SERVICE_TXT]) 306 blobmsg_for_each_attr(txt, _tb[SERVICE_TXT], rem2) { 307 int len = strlen(blobmsg_get_string(txt)); 308 if (!len) 309 return; 310 if (len > 0xff) 311 len = 0xff; 312 *d_txt = len; 313 d_txt++; 314 memcpy(d_txt, blobmsg_get_string(txt), len); 315 d_txt += len; 316 } 317 318 vlist_add(&services, &s->node, s->id); 319 } 320 321 static void 322 service_load(char *path) 323 { 324 struct blob_attr *cur; 325 glob_t gl; 326 int i, rem; 327 328 if (glob(path, GLOB_NOESCAPE | GLOB_MARK, NULL, &gl)) 329 return; 330 331 for (i = 0; i < gl.gl_pathc; i++) { 332 blob_buf_init(&b, 0); 333 if (blobmsg_add_json_from_file(&b, gl.gl_pathv[i])) { 334 blob_for_each_attr(cur, b.head, rem) 335 service_load_blob(cur); 336 } else { 337 fprintf(stderr, "Error reading %s JSON\n", gl.gl_pathv[i]); 338 } 339 } 340 globfree(&gl); 341 } 342 343 static void 344 service_init_cb(struct ubus_request *req, int type, struct blob_attr *msg) 345 { 346 struct blob_attr *cur; 347 int rem; 348 349 get_hostname(); 350 351 vlist_update(&services); 352 vlist_update(&hostnames); 353 service_load("/etc/umdns/*"); 354 355 blob_for_each_attr(cur, msg, rem) { 356 struct blob_attr *cur2; 357 int rem2; 358 359 blobmsg_for_each_attr(cur2, cur, rem2) { 360 struct blob_attr *cur3; 361 int rem3; 362 363 if (strcmp(blobmsg_name(cur2), "instances")) 364 continue; 365 366 blobmsg_for_each_attr(cur3, cur2, rem3) { 367 struct blob_attr *cur4; 368 int rem4; 369 int running = 0; 370 371 blobmsg_for_each_attr(cur4, cur3, rem4) { 372 const char *name = blobmsg_name(cur4); 373 374 if (!strcmp(name, "running")) { 375 running = blobmsg_get_bool(cur4); 376 } else if (running && !strcmp(name, "data")) { 377 struct blob_attr *cur5; 378 int rem5; 379 380 blobmsg_for_each_attr(cur5, cur4, rem5) { 381 struct blob_attr *cur6; 382 int rem6; 383 384 if (strcmp(blobmsg_name(cur5), "mdns")) 385 continue; 386 387 blobmsg_for_each_attr(cur6, cur5, rem6) 388 service_load_blob(cur6); 389 } 390 break; 391 } 392 } 393 } 394 } 395 } 396 vlist_flush(&services); 397 vlist_flush(&hostnames); 398 } 399 400 void 401 service_init(int announce) 402 { 403 get_hostname(); 404 405 service_init_announce = announce; 406 ubus_service_list(service_init_cb); 407 } 408 409 void 410 service_cleanup(void) 411 { 412 vlist_flush(&services); 413 blob_buf_free(&b); 414 } 415
This page was automatically generated by LXR 0.3.1. • OpenWrt