1 /*
2 * Copyright (c) 2010, 2011 Christiano F. Haesbaert <haesbaert@haesbaert.org>
3 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <arpa/nameser.h>
27
28 #include <err.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34
35 #include "mdnsd.h"
36 #include "mdns.h"
37 #include "log.h"
38 #include "control.h"
39
40 #define CONTROL_BACKLOG 5
41
42 struct ctl_conn *control_connbyfd(int);
43 struct ctl_conn *control_connbypid(pid_t);
44 void control_close(int);
45 void control_lookup(struct ctl_conn *, struct imsg *);
46 void control_browse_add(struct ctl_conn *, struct imsg *);
47 void control_browse_del(struct ctl_conn *, struct imsg *);
48 void control_resolve(struct ctl_conn *, struct imsg *);
49 void control_group_add(struct ctl_conn *, struct imsg *);
50 void control_group_reset(struct ctl_conn *, struct imsg *);
51 void control_group_commit(struct ctl_conn *, struct imsg *);
52 void control_group_add_service(struct ctl_conn *, struct imsg *);
53
54 extern struct mdnsd_conf *conf;
55
56 struct control_state control_state;
57
58 void
control_lookup(struct ctl_conn * c,struct imsg * imsg)59 control_lookup(struct ctl_conn *c, struct imsg *imsg)
60 {
61 struct rrset mlkup, *rrs;
62 struct rr *rr;
63 struct query *q;
64 struct timeval tv;
65 if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(mlkup))
66 return;
67
68 memcpy(&mlkup, imsg->data, sizeof(mlkup));
69 mlkup.dname[MAXHOSTNAMELEN - 1] = '\0'; /* assure clients are nice */
70
71 switch (mlkup.type) {
72 case T_A: /* FALLTHROUGH */
73 case T_HINFO: /* FALLTHROUGH */
74 case T_PTR: /* FALLTHROUGH */
75 case T_SRV: /* FALLTHROUGH */
76 case T_TXT: /* FALLTHROUGH */
77 break;
78 default:
79 log_warnx("Lookup type %d not supported/implemented",
80 mlkup.type);
81 return;
82 }
83
84 if (mlkup.class != C_IN) {
85 log_warnx("Lookup class %d not supported/implemented",
86 mlkup.class);
87 return;
88 }
89
90 /* Check if control has this query already, if so don't do anything */
91 LIST_FOREACH(q, &c->qlist, entry) {
92 if (q->style != QUERY_LOOKUP)
93 continue;
94 LIST_FOREACH(rrs, &q->rrslist, entry)
95 if (rrset_cmp(rrs, &mlkup) == 0) {
96 log_debug("control already querying for %s",
97 rrs_str(rrs));
98 return;
99 }
100 }
101
102 log_debug("looking up %s (%s %d)", mlkup.dname, rr_type_name(mlkup.type),
103 mlkup.class);
104
105 /*
106 * Look for answers in our cache
107 */
108 rr = cache_lookup(&mlkup);
109 /* cache hit */
110 if (rr != NULL) {
111 if (control_send_rr(c, rr, IMSG_CTL_LOOKUP) == -1)
112 log_warnx("query_answer error");
113 return;
114 }
115
116 if (question_add(&mlkup) == NULL) {
117 log_warnx("Can't add question for %s (%s)", rrs_str(&mlkup));
118 return;
119 }
120
121 /* cache miss */
122 if ((q = calloc(1, sizeof(*q))) == NULL)
123 fatal("calloc");
124 if ((rrs = calloc(1, sizeof(*rrs))) == NULL)
125 fatal("calloc");
126 LIST_INIT(&q->rrslist);
127 q->style = QUERY_LOOKUP;
128 q->ctl = c;
129 *rrs = mlkup;
130 LIST_INSERT_HEAD(&q->rrslist, rrs, entry);
131 LIST_INSERT_HEAD(&c->qlist, q, entry);
132 timerclear(&tv);
133 tv.tv_usec = FIRST_QUERYTIME;
134 evtimer_set(&q->timer, query_fsm, q);
135 evtimer_add(&q->timer, &tv);
136 }
137
138 void
control_browse_add(struct ctl_conn * c,struct imsg * imsg)139 control_browse_add(struct ctl_conn *c, struct imsg *imsg)
140 {
141 struct rrset mlkup, *rrs;
142 struct rr *rr;
143 struct query *q;
144 struct timeval tv;
145
146 if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(mlkup))
147 return;
148
149 memcpy(&mlkup, imsg->data, sizeof(mlkup));
150 mlkup.dname[MAXHOSTNAMELEN - 1] = '\0'; /* assure clients were nice */
151
152 if (mlkup.type != T_PTR) {
153 log_warnx("Browse type %d not supported/implemented",
154 mlkup.type);
155 return;
156 }
157
158 if (mlkup.class != C_IN) {
159 log_warnx("Browse class %d not supported/implemented",
160 mlkup.class);
161 return;
162 }
163
164 /* Check if control has this query already, if so don't do anything */
165 LIST_FOREACH(q, &c->qlist, entry) {
166 if (q->style != QUERY_BROWSE)
167 continue;
168 if (rrset_cmp(q->br_ptr, &mlkup) == 0) {
169 log_warnx("control already querying for %s",
170 rrs_str(q->br_ptr));
171 return;
172 }
173 }
174
175 log_debug("Browse add %s (%s %d)", mlkup.dname, rr_type_name(mlkup.type),
176 mlkup.class);
177
178 /*
179 * Look for answers in our cache
180 */
181 CACHE_FOREACH_RRS(rr, &mlkup) {
182 if ((rr->flags & RR_FLAG_PUBLISHED) == 0)
183 continue;
184 if (control_send_rr(c, rr, IMSG_CTL_BROWSE_ADD) == -1)
185 log_warnx("control_send_rr error 2");
186 }
187
188 if (question_add(&mlkup) == NULL) {
189 log_warnx("Can't add question for %s", rrs_str(&mlkup));
190 return;
191 }
192
193 if ((q = calloc(1, sizeof(*q))) == NULL)
194 fatal("calloc");
195 if ((rrs = calloc(1, sizeof(*rrs))) == NULL)
196 fatal("calloc");
197 *rrs = mlkup;
198 LIST_INIT(&q->rrslist);
199 q->style = QUERY_BROWSE;
200 q->ctl = c;
201 q->br_ptr = rrs;
202 LIST_INSERT_HEAD(&q->rrslist, rrs, entry);
203 LIST_INSERT_HEAD(&c->qlist, q, entry);
204 timerclear(&tv);
205 tv.tv_usec = FIRST_QUERYTIME;
206 evtimer_set(&q->timer, query_fsm, q);
207 evtimer_add(&q->timer, &tv);
208 }
209
210 void
control_browse_del(struct ctl_conn * c,struct imsg * imsg)211 control_browse_del(struct ctl_conn *c, struct imsg *imsg)
212 {
213 struct rrset mlkup;
214 struct query *q;
215
216 if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(mlkup))
217 return;
218
219 memcpy(&mlkup, imsg->data, sizeof(mlkup));
220 mlkup.dname[MAXHOSTNAMELEN - 1] = '\0'; /* assure clients were nice */
221
222 if (mlkup.type != T_PTR) {
223 log_warnx("Browse type %d not supported/implemented",
224 mlkup.type);
225 return;
226 }
227
228 if (mlkup.class != C_IN) {
229 log_warnx("Browse class %d not supported/implemented",
230 mlkup.class);
231 return;
232 }
233
234 LIST_FOREACH(q, &c->qlist, entry) {
235 if (q->style != QUERY_BROWSE)
236 continue;
237 if (rrset_cmp(q->br_ptr, &mlkup) != 0)
238 continue;
239 query_remove(q);
240 return;
241 }
242
243 log_warnx("Trying to remove non existant query");
244 }
245
246 void
control_resolve(struct ctl_conn * c,struct imsg * imsg)247 control_resolve(struct ctl_conn *c, struct imsg *imsg)
248 {
249 char msg[MAXHOSTNAMELEN];
250 struct rrset *rrs_srv, *rrs_txt, *rrs_a, *rrs_aux;
251 struct rr *srv_cache;
252 struct query *q;
253 struct timeval tv;
254
255 if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) {
256 log_warnx("control_resolve: Invalid msg len");
257 return;
258 }
259
260 memcpy(msg, imsg->data, sizeof(msg));
261 msg[sizeof(msg) - 1] = '\0';
262
263 /* Check if control has this query already, if so don't do anything */
264 LIST_FOREACH(q, &c->qlist, entry) {
265 if (q->style != QUERY_RESOLVE)
266 continue;
267 if (strcmp(msg, q->ms_srv->dname) == 0) {
268 log_debug("control already resolving %s",
269 q->ms_srv->dname);
270 return;
271 }
272 }
273
274 log_debug("Resolve %s", msg);
275
276 /*
277 * Try getting answer withing our cache entries
278 */
279 if (control_try_answer_ms(c, msg) == 1) {
280 log_debug("Resolve for %s all in cache", msg);
281 return;
282 }
283
284 /*
285 * If we got here we need to make a query.
286 */
287 if ((q = calloc(1, sizeof(*q))) == NULL)
288 fatal("calloc");
289 LIST_INSERT_HEAD(&c->qlist, q, entry);
290 LIST_INIT(&q->rrslist);
291 q->style = QUERY_RESOLVE;
292 q->ctl = c;
293 timerclear(&tv);
294 tv.tv_usec = FIRST_QUERYTIME;
295 evtimer_set(&q->timer, query_fsm, q);
296 evtimer_add(&q->timer, &tv);
297
298 if ((rrs_srv = calloc(1, sizeof(*rrs_srv))) == NULL)
299 err(1, "calloc");
300 if ((rrs_txt = calloc(1, sizeof(*rrs_txt))) == NULL)
301 err(1, "calloc");
302
303 if (strlcpy(rrs_srv->dname, msg, sizeof(rrs_srv->dname)) >=
304 sizeof(rrs_srv->dname)) {
305 log_warnx("control_resolve: msg too long, dropping");
306 free(rrs_srv);
307 free(rrs_txt);
308 return;
309 }
310 rrs_srv->class = C_IN;
311 rrs_srv->type = T_SRV;
312 strlcpy(rrs_txt->dname, msg, sizeof(rrs_txt->dname));
313 rrs_txt->class = C_IN;
314 rrs_txt->type = T_TXT;
315 q->ms_srv = rrs_srv;
316 LIST_INSERT_HEAD(&q->rrslist, rrs_srv, entry);
317 LIST_INSERT_HEAD(&q->rrslist, rrs_txt, entry);
318 if ((srv_cache = cache_lookup(rrs_srv)) != NULL) {
319 if ((rrs_a = calloc(1, sizeof(*rrs_a))) == NULL)
320 err(1, "calloc");
321 strlcpy(rrs_a->dname, srv_cache->rdata.SRV.target,
322 sizeof(rrs_a->dname));
323 rrs_a->class = C_IN;
324 rrs_a->type = T_A;
325 q->ms_a = rrs_a;
326 LIST_INSERT_HEAD(&q->rrslist, rrs_a, entry);
327 }
328
329 LIST_FOREACH(rrs_aux, &q->rrslist, entry) {
330 if (question_add(rrs_aux) == NULL) {
331 log_warnx("control_resolve: question_add error");
332 query_remove(q);
333 return;
334 }
335 }
336 }
337
338 void
control_group_add(struct ctl_conn * c,struct imsg * imsg)339 control_group_add(struct ctl_conn *c, struct imsg *imsg)
340 {
341 char msg[MAXHOSTNAMELEN];
342
343 if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) {
344 log_warnx("control_group_add: Invalid group len");
345 return;
346 }
347
348 memcpy(msg, imsg->data, sizeof(msg));
349 msg[sizeof(msg) - 1] = '\0';
350 /*
351 * Check if the user hasn't already added this group, we'll issue an
352 * error when he commits.
353 */
354 if (pg_get(0, msg, c) != NULL)
355 return;
356 /*
357 * Initialize group in temporary list, when user commits the group, we
358 * will process it all.
359 */
360 (void)pg_get(1, msg, c);
361 }
362
363 void
control_group_add_service(struct ctl_conn * c,struct imsg * imsg)364 control_group_add_service(struct ctl_conn *c, struct imsg *imsg)
365 {
366 struct pg *pg;
367 struct pge *pge;
368 struct mdns_service msg, *ms;
369
370 if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) {
371 log_warnx("control_group_add_service: Invalid group len");
372 return;
373 }
374 memcpy(&msg, imsg->data, sizeof(msg));
375 msg.name[sizeof(msg.name) - 1] = '\0';
376 ms = &msg;
377 /* Default to ourself if target hostname not provided */
378 if (strlen(ms->target) == 0)
379 (void)strlcpy(ms->target, conf->myname, sizeof(ms->target));
380
381 /* Group not found, or not newgroup commited */
382 pg = pg_get(0, ms->name, c);
383 if (pg == NULL ||
384 (pg != NULL && pg->state != PG_STA_NEW)) {
385 log_warnx("Controller trying to add service to invalid group");
386 return;
387 }
388
389 if ((pge = pge_from_ms(pg, ms, ALL_IFACE)) == NULL) {
390 /* XXX assume collision */
391 pg->state = PG_STA_COLLISION;
392 return;
393 }
394 }
395
396 void
control_group_reset(struct ctl_conn * c,struct imsg * imsg)397 control_group_reset(struct ctl_conn *c, struct imsg *imsg)
398 {
399 char msg[MAXHOSTNAMELEN];
400 struct pg *pg;
401
402 if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) {
403 log_warnx("control_group_reset: Invalid group len");
404 return;
405 }
406
407 memcpy(msg, imsg->data, sizeof(msg));
408 msg[sizeof(msg) - 1] = '\0';
409
410 if ((pg = pg_get(0, msg, NULL)) == NULL) {
411 log_debug("control_group_reset: group %s not found",
412 msg);
413 return;
414 }
415
416 pg_kill(pg);
417
418 log_debug("group %s reseted", msg);
419 }
420
421 /*
422 * XXX revise all this, we must have a flag in group if we had a collision when
423 * adding an entry.
424 */
425 void
control_group_commit(struct ctl_conn * c,struct imsg * imsg)426 control_group_commit(struct ctl_conn *c, struct imsg *imsg)
427 {
428 char msg[MAXHOSTNAMELEN];
429 struct pg *pg;
430 struct pge *pge;
431 struct timeval tv;
432
433 if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) {
434 log_warnx("control_group_commit: Invalid group len");
435 return;
436 }
437 memcpy(msg, imsg->data, sizeof(msg));
438 msg[sizeof(msg) - 1] = '\0';
439
440 /* Check if we have the group under our control. */
441 pg = pg_get(0, msg, c);
442 if (pg == NULL) {
443 /*
444 * If we don't, check if someone else does, if yes, we
445 * probabably failed adding some service due to a collision, so
446 * guess this is a collision :-), yes this is disgusting, will
447 * fix it someday.
448 */
449 TAILQ_FOREACH(pg, &pg_queue, entry) {
450 if (strcmp(pg->name, msg) != 0)
451 continue;
452 control_notify_pg(c, pg,
453 IMSG_CTL_GROUP_ERR_COLLISION);
454 return;
455 }
456
457 control_notify_pg(c, pg,
458 IMSG_CTL_GROUP_ERR_NOT_FOUND);
459 return;
460 }
461
462 /* Check if we got a collision */
463 if (pg->state == PG_STA_COLLISION) {
464 control_notify_pg(pg->c, pg,
465 IMSG_CTL_GROUP_ERR_COLLISION);
466 pg_kill(pg);
467 return;
468 }
469
470 /* Mark we got a commit */
471 pg->state = PG_STA_COMMITED;
472
473 timerclear(&tv);
474 tv.tv_usec = RANDOM_PROBETIME;
475 LIST_FOREACH(pge, &pg->pge_list, pge_entry) {
476 pge_fsm_restart(pge, &tv);
477 }
478 }
479
480 int
control_init(void)481 control_init(void)
482 {
483 struct sockaddr_un sun;
484 int fd;
485 mode_t old_umask;
486
487 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
488 log_warn("control_init: socket");
489 return (-1);
490 }
491
492 bzero(&sun, sizeof(sun));
493 sun.sun_family = AF_UNIX;
494 strlcpy(sun.sun_path, MDNSD_SOCKET, sizeof(sun.sun_path));
495
496 if (unlink(MDNSD_SOCKET) == -1)
497 if (errno != ENOENT) {
498 log_warn("control_init: unlink %s", MDNSD_SOCKET);
499 close(fd);
500 return (-1);
501 }
502
503 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
504 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
505 log_warn("control_init: bind: %s", MDNSD_SOCKET);
506 close(fd);
507 umask(old_umask);
508 return (-1);
509 }
510 umask(old_umask);
511
512 if (chmod(MDNSD_SOCKET, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
513 log_warn("control_init: chmod");
514 close(fd);
515 (void)unlink(MDNSD_SOCKET);
516 return (-1);
517 }
518
519 session_socket_blockmode(fd, BM_NONBLOCK);
520 control_state.fd = fd;
521
522 return (0);
523 }
524
525 int
control_listen(void)526 control_listen(void)
527 {
528
529 if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
530 log_warn("control_listen: listen");
531 return (-1);
532 }
533
534 event_set(&control_state.ev, control_state.fd, EV_READ | EV_PERSIST,
535 control_accept, NULL);
536 event_add(&control_state.ev, NULL);
537
538 return (0);
539 }
540
541 void
control_cleanup(void)542 control_cleanup(void)
543 {
544 unlink(MDNSD_SOCKET);
545 }
546
547 void
control_accept(int listenfd,short event,void * bula)548 control_accept(int listenfd, short event, void *bula)
549 {
550 int connfd;
551 socklen_t len;
552 struct sockaddr_un sun;
553 struct ctl_conn *c;
554
555 len = sizeof(sun);
556 if ((connfd = accept(listenfd,
557 (struct sockaddr *)&sun, &len)) == -1) {
558 if (errno != EWOULDBLOCK && errno != EINTR)
559 log_warn("control_accept: accept");
560 return;
561 }
562
563 session_socket_blockmode(connfd, BM_NONBLOCK);
564
565 if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
566 log_warn("control_accept");
567 close(connfd);
568 return;
569 }
570
571 LIST_INIT(&c->qlist);
572 imsg_init(&c->iev.ibuf, connfd);
573 c->iev.handler = control_dispatch_imsg;
574 c->iev.events = EV_READ;
575 event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
576 c->iev.handler, &c->iev);
577 event_add(&c->iev.ev, NULL);
578
579 TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
580 }
581
582 struct ctl_conn *
control_connbyfd(int fd)583 control_connbyfd(int fd)
584 {
585 struct ctl_conn *c;
586
587 for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd;
588 c = TAILQ_NEXT(c, entry))
589 ; /* nothing */
590
591 return (c);
592 }
593
594 struct ctl_conn *
control_connbypid(pid_t pid)595 control_connbypid(pid_t pid)
596 {
597 struct ctl_conn *c;
598
599 for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.pid != pid;
600 c = TAILQ_NEXT(c, entry))
601 ; /* nothing */
602
603 return (c);
604 }
605
606 void
control_close(int fd)607 control_close(int fd)
608 {
609 struct ctl_conn *c;
610 struct query *q;
611 struct pg *pg, *pg_next;
612
613 if ((c = control_connbyfd(fd)) == NULL) {
614 log_warn("control_close: fd %d: not found", fd);
615 return;
616 }
617 msgbuf_clear(&c->iev.ibuf.w);
618 TAILQ_REMOVE(&ctl_conns, c, entry);
619
620 event_del(&c->iev.ev);
621 close(c->iev.ibuf.fd);
622 while ((q = LIST_FIRST(&c->qlist)) != NULL)
623 query_remove(q);
624 /*
625 * Clean up all groups belonging to this controller
626 */
627 for (pg = TAILQ_FIRST(&pg_queue); pg != NULL;
628 pg = pg_next) {
629 pg_next = TAILQ_NEXT(pg, entry);
630 if (pg->c == c)
631 pg_kill(pg);
632 }
633 free(c);
634 }
635
636 void
control_dispatch_imsg(int fd,short event,void * bula)637 control_dispatch_imsg(int fd, short event, void *bula)
638 {
639 struct ctl_conn *c;
640 struct imsg imsg;
641 ssize_t n;
642
643 if ((c = control_connbyfd(fd)) == NULL) {
644 log_warn("control_dispatch_imsg: fd %d: not found", fd);
645 return;
646 }
647
648 if (event & EV_READ) {
649 if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) {
650 control_close(fd);
651 return;
652 }
653 }
654 if (event & EV_WRITE) {
655 if (msgbuf_write(&c->iev.ibuf.w) == -1) {
656 control_close(fd);
657 return;
658 }
659 }
660
661 for (;;) {
662 if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
663 control_close(fd);
664 return;
665 }
666
667 if (n == 0)
668 break;
669
670 switch (imsg.hdr.type) {
671 case IMSG_CTL_LOOKUP:
672 control_lookup(c, &imsg);
673 break;
674 case IMSG_CTL_BROWSE_ADD:
675 control_browse_add(c, &imsg);
676 break;
677 case IMSG_CTL_BROWSE_DEL:
678 control_browse_del(c, &imsg);
679 break;
680 case IMSG_CTL_RESOLVE:
681 control_resolve(c, &imsg);
682 break;
683 case IMSG_CTL_GROUP_ADD:
684 control_group_add(c, &imsg);
685 break;
686 case IMSG_CTL_GROUP_RESET:
687 control_group_reset(c, &imsg);
688 break;
689 case IMSG_CTL_GROUP_COMMIT:
690 control_group_commit(c, &imsg);
691 break;
692 case IMSG_CTL_GROUP_ADD_SERVICE:
693 control_group_add_service(c, &imsg);
694 break;
695 default:
696 log_debug("control_dispatch_imsg: "
697 "error handling imsg %d", imsg.hdr.type);
698 break;
699 }
700 imsg_free(&imsg);
701 }
702
703 imsg_event_add(&c->iev);
704 }
705
706 void
session_socket_blockmode(int fd,enum blockmodes bm)707 session_socket_blockmode(int fd, enum blockmodes bm)
708 {
709 int flags;
710
711 if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
712 fatal("fcntl F_GETFL");
713
714 if (bm == BM_NONBLOCK)
715 flags |= O_NONBLOCK;
716 else
717 flags &= ~O_NONBLOCK;
718
719 if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
720 fatal("fcntl F_SETFL");
721 }
722
723 int
control_send_rr(struct ctl_conn * c,struct rr * rr,int msgtype)724 control_send_rr(struct ctl_conn *c, struct rr *rr, int msgtype)
725 {
726 int r;
727 int inaddrany = RR_INADDRANY(rr);
728
729 log_debug("control_send_rr (%s) %s", rr_type_name(rr->rrs.type),
730 rr->rrs.dname);
731
732 /* Patch up T_A with the first interface address */
733 if (inaddrany)
734 rr->rdata.A.s_addr = LIST_FIRST(&conf->iface_list)->addr.s_addr;
735 r = mdnsd_imsg_compose_ctl(c, msgtype, rr, sizeof(*rr));
736 if (inaddrany)
737 rr->rdata.A.s_addr = INADDR_ANY;
738
739 return (r);
740 }
741
742 int
control_send_ms(struct ctl_conn * c,struct mdns_service * ms,int msgtype)743 control_send_ms(struct ctl_conn *c, struct mdns_service *ms, int msgtype)
744 {
745 log_debug("control_send_ms %s", ms->name);
746
747 return (mdnsd_imsg_compose_ctl(c, msgtype, ms, sizeof(*ms)));
748 }
749
750 /*
751 * 1 = Success, 0 = Fail
752 */
753 int
control_try_answer_ms(struct ctl_conn * c,char dname[MAXHOSTNAMELEN])754 control_try_answer_ms(struct ctl_conn *c, char dname[MAXHOSTNAMELEN])
755 {
756 struct rr *srv, *txt, *a;
757 struct rrset rrs;
758 struct mdns_service ms;
759
760 srv = txt = a = NULL;
761
762 /*
763 * Look for answers in our cache
764 */
765 log_debug("control_try_answer_ms %s", dname);
766 strlcpy(rrs.dname, dname, sizeof(rrs.dname));
767 rrs.class = C_IN;
768 rrs.type = T_SRV;
769 if ((srv = cache_lookup(&rrs)) == NULL)
770 return (0);
771 rrs.type = T_TXT;
772 if ((txt = cache_lookup(&rrs)) == NULL)
773 return (0);
774 strlcpy(rrs.dname, srv->rdata.SRV.target, sizeof(rrs.dname));
775 rrs.type = T_A;
776 if ((a = cache_lookup(&rrs)) == NULL)
777 return (0);
778
779 bzero(&ms, sizeof(ms));
780 strlcpy(ms.name, srv->rrs.dname, sizeof(ms.name));
781 strlcpy(ms.target, rrs.dname, sizeof(ms.target));
782 strlcpy(ms.txt, txt->rdata.TXT, sizeof(ms.txt));
783 ms.priority = srv->rdata.SRV.priority;
784 ms.weight = srv->rdata.SRV.weight;
785 ms.port = srv->rdata.SRV.port;
786 /* Patch up T_A with the first interface address */
787 if (RR_INADDRANY(a))
788 ms.addr = LIST_FIRST(&conf->iface_list)->addr;
789 else
790 ms.addr = a->rdata.A;
791 if (control_send_ms(c, &ms, IMSG_CTL_RESOLVE) == -1)
792 log_warnx("control_send_ms error");
793
794 return (1);
795 }
796
797 int
control_notify_pg(struct ctl_conn * c,struct pg * pg,int msgtype)798 control_notify_pg(struct ctl_conn *c, struct pg *pg, int msgtype)
799 {
800 log_debug("control_notify_pg %s msg %d", pg->name, msgtype);
801
802 if (c == NULL) {
803 log_warnx("Calling control_notify_pg() with NULL !");
804 return (-1);
805 }
806
807 return (mdnsd_imsg_compose_ctl(c, msgtype, pg->name,
808 sizeof(pg->name)));
809 }
810